client/src/components/forms/input/component.tsx
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;