Spaces:
Sleeping
Sleeping
| 'use client'; | |
| import { forwardRef, type InputHTMLAttributes } from 'react'; | |
| interface FormFieldProps extends InputHTMLAttributes<HTMLInputElement> { | |
| label: string; | |
| hint?: string; | |
| error?: string; | |
| } | |
| export const FormField = forwardRef<HTMLInputElement, FormFieldProps>( | |
| function FormField({ label, hint, error, id, className = '', ...rest }, ref) { | |
| const inputId = id ?? rest.name ?? label.toLowerCase().replace(/\s+/g, '-'); | |
| return ( | |
| <div className="space-y-1.5"> | |
| <label | |
| htmlFor={inputId} | |
| className="block text-sm font-medium text-slate-800" | |
| > | |
| {label} | |
| </label> | |
| <input | |
| ref={ref} | |
| id={inputId} | |
| aria-invalid={!!error} | |
| aria-describedby={ | |
| error ? `${inputId}-error` : hint ? `${inputId}-hint` : undefined | |
| } | |
| className={`block w-full rounded-lg border px-3 py-2 text-sm text-slate-900 placeholder-slate-400 shadow-sm focus:border-brand-500 focus:outline-none focus:ring-1 focus:ring-brand-500 ${ | |
| error ? 'border-red-300 bg-red-50/30' : 'border-slate-300 bg-white' | |
| } ${className}`} | |
| {...rest} | |
| /> | |
| {error ? ( | |
| <p id={`${inputId}-error`} className="text-xs text-red-600"> | |
| {error} | |
| </p> | |
| ) : hint ? ( | |
| <p id={`${inputId}-hint`} className="text-xs text-slate-500"> | |
| {hint} | |
| </p> | |
| ) : null} | |
| </div> | |
| ); | |
| }, | |
| ); | |