Vizzuality/landgriffon

View on GitHub
client/src/components/forms/input/component.tsx

Summary

Maintainability
A
1 hr
Test Coverage
import { cloneElement, forwardRef } from 'react';
import classnames from 'classnames';
import { ExclamationCircleIcon } from '@heroicons/react/solid';

import Hint from '../hint';

import type { InputProps } from './types';

const Input = forwardRef<HTMLInputElement, InputProps>(
  ({ className, error, icon, type = 'text', unit, showHint = true, ...inputProps }, ref) => (
    <>
      <div className={classnames('relative rounded-md shadow-sm', className)}>
        {icon && (
          <div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
            {cloneElement(icon, {
              className: classnames(
                'w-4 h-4',
                inputProps.disabled ? 'text-gray-300' : 'text-gray-500',
                icon.props?.className,
              ),
            })}
          </div>
        )}
        <input
          className={classnames(
            'block w-full rounded-md border px-4 py-2.5 text-sm leading-5 placeholder:text-gray-500 focus:outline-none focus:ring-0',
            error ? 'border-red-400 focus:border-red-400' : 'border-gray-200 focus:border-navy-400',
            inputProps.disabled ? 'bg-gray-300/20 text-gray-300' : 'bg-white text-gray-900',
            {
              'pl-8': icon,
              'pr-10': unit && !error,
              'pr-20': unit && error,
            },
          )}
          type={type}
          {...inputProps}
          ref={ref}
        />
        {unit && (
          <div
            className={classnames(
              'pointer-events-none absolute inset-y-0 flex items-center pr-3',
              error ? 'right-6' : 'right-0',
            )}
          >
            <span className="text-gray-500 sm:text-sm">{unit}</span>
          </div>
        )}
        {error && (
          <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
            <ExclamationCircleIcon className="h-4 w-4 text-red-400" />
          </div>
        )}
      </div>
      {showHint && error && typeof error === 'string' && (
        <Hint data-testid={`hint-input-${inputProps.name}`}>{error}</Hint>
      )}
    </>
  ),
);

Input.displayName = 'Input';

export default Input;