Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | 'use client';
import { InputHTMLAttributes, useId } from 'react';
import { Hint, Input, Label } from '@/components/ui';
import { cn } from '@/lib/utils';
type InputPropsWithIcon = InputHTMLAttributes<HTMLInputElement> & {
iconButton?: React.ReactNode;
};
interface FormInputProps {
className?: string;
labelName?: string;
hintMessage?: string;
availabilityHint?: string;
availabilityButtonDisabled?: boolean;
availabilityStatus?: AvailabilityState;
required?: boolean;
inputProps?: InputPropsWithIcon;
onClick?: () => void;
}
type AvailabilityState =
| { status: 'idle' }
| { status: 'checking' }
| { status: 'available' }
| { status: 'unavailable' }
| { status: 'error' };
export const FormInput = ({
className,
labelName,
hintMessage,
availabilityHint,
availabilityStatus,
required = true,
inputProps = {},
}: FormInputProps) => {
const { type, id, required: _, iconButton, ...restInputProps } = inputProps;
const generatedId = useId();
const inputId = id ?? generatedId;
let tone: 'default' | 'error' | 'success' = 'default';
if (hintMessage || availabilityStatus?.status === 'unavailable') {
tone = 'error';
}
if (availabilityStatus?.status === 'available') {
tone = 'success';
}
return (
<div className={cn('flex w-full flex-col gap-1', className)}>
<Label htmlFor={inputId} required={required}>
{labelName}
</Label>
<Input
aria-invalid={!!hintMessage}
id={inputId}
className={cn(
'bg-mono-white focus:border-mint-500 h-14 rounded-2xl border border-gray-300',
tone === 'error' && 'border-error-500',
tone === 'success' && 'border-gray-300',
availabilityStatus && 'pr-23',
)}
iconButton={iconButton}
required={required}
type={type}
{...restInputProps}
/>
{hintMessage && <Hint message={hintMessage} />}
{availabilityHint && (
<Hint
className={cn(
tone === 'error' && 'text-error-500',
tone === 'success' && 'text-mint-600',
)}
message={availabilityHint}
/>
)}
</div>
);
};
|