the-tip-top-frontend/components/ui/Input.tsx
2025-11-17 23:38:02 +01:00

59 lines
1.7 KiB
TypeScript

import React, { InputHTMLAttributes, forwardRef } from 'react';
import { cn } from '@/utils/helpers';
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
helperText?: string;
}
export const Input = forwardRef<HTMLInputElement, InputProps>(
({ label, error, helperText, className, ...props }, ref) => {
return (
<div className="w-full">
{label && (
<label
htmlFor={props.id}
className="block text-sm font-medium text-gray-700 mb-1"
>
{label}
{props.required && <span className="text-red-500 ml-1">*</span>}
</label>
)}
<input
ref={ref}
className={cn(
'w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition-colors',
error
? 'border-red-500 focus:ring-red-500'
: 'border-gray-300 focus:ring-blue-500 focus:border-blue-500',
props.disabled && 'bg-gray-100 cursor-not-allowed',
className
)}
aria-invalid={error ? 'true' : 'false'}
aria-describedby={
error ? `${props.id}-error` : helperText ? `${props.id}-helper` : undefined
}
{...props}
/>
{error && (
<p
id={`${props.id}-error`}
className="mt-1 text-sm text-red-600"
role="alert"
>
{error}
</p>
)}
{!error && helperText && (
<p id={`${props.id}-helper`} className="mt-1 text-sm text-gray-500">
{helperText}
</p>
)}
</div>
);
}
);
Input.displayName = 'Input';