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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | 7x 101x 101x 101x 101x 32x 32x 32x 101x 7x 7x 47x 47x 7x | import type { InputHTMLAttributes, ReactNode } from 'react';
import { forwardRef, useId } from 'react';
import type { Control, FieldPath, FieldValues } from 'react-hook-form';
import { Controller } from 'react-hook-form';
import { cn } from '@/lib/utils';
export interface BaseInputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string | ReactNode;
error?: string;
}
// Enhanced Input props that can work with React Hook Form
export interface InputProps<T extends FieldValues = FieldValues>
extends BaseInputProps {
name?: FieldPath<T>;
control?: Control<T>;
}
const BaseInput = forwardRef<HTMLInputElement, BaseInputProps>(
({ className, type, label, required, error, id, ...props }, ref) => {
// Always call useId hook, then use provided id if available
const generatedId = useId();
const inputId = id || generatedId;
const baseStyles = [
// Layout & sizing - updated with specific dimensions
'flex w-full h-[50px]',
// Appearance - updated with radius and border
'rounded-[62px] border',
error ? 'border-red-500' : 'border-[#F0F0F0]',
'bg-background px-[34px] text-sm',
// Focus states
'ring-offset-background',
'focus-visible:outline-none',
error ? 'focus-visible:ring-red-500' : 'focus-visible:ring-blue-500',
// Placeholder styling
'placeholder:text-muted-foreground',
// File input styling
'file:border-0 file:bg-transparent file:text-sm file:font-medium',
// Disabled state
'disabled:cursor-not-allowed disabled:opacity-50',
];
const renderLabel = () => {
Iif (!label) return null;
Eif (typeof label === 'string') {
return (
<span className="text-sm font-medium text-foreground">
{label}
{required && <span className="text-red-500 ml-1">*</span>}
</span>
);
}
return label;
};
return (
<div className="flex flex-col space-y-2">
{label && (
<label
htmlFor={inputId}
className="text-sm font-medium text-foreground"
>
{renderLabel()}
</label>
)}
<input
id={inputId}
type={type}
className={cn(baseStyles.join(' '), className)}
ref={ref}
required={required}
{...props}
/>
{error && <span className="text-sm text-red-500">{error}</span>}
</div>
);
}
);
BaseInput.displayName = 'BaseInput';
// Smart Input component that works with or without React Hook Form
const Input = forwardRef<HTMLInputElement, InputProps>(
({ name, control, ...props }, ref) => {
// If control and name are provided, use Controller
Iif (control && name) {
return (
<Controller
name={name as any}
control={control as any}
render={({ field, fieldState: { error } }) => (
<BaseInput
{...field}
{...props}
error={error?.message || props.error}
ref={ref}
/>
)}
/>
);
}
// Otherwise, use as regular input and pass name prop
return <BaseInput {...props} name={name} ref={ref} />;
}
);
Input.displayName = 'Input';
export { Input, BaseInput };
|