70 lines
1.8 KiB
TypeScript
70 lines
1.8 KiB
TypeScript
import React, { InputHTMLAttributes } from 'react';
|
|
|
|
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
label?: string;
|
|
error?: string;
|
|
leftIcon?: React.ReactNode;
|
|
rightIcon?: React.ReactNode;
|
|
}
|
|
|
|
const Input: React.FC<InputProps> = ({
|
|
label,
|
|
error,
|
|
placeholder,
|
|
type = 'text',
|
|
leftIcon,
|
|
rightIcon,
|
|
disabled,
|
|
className = '',
|
|
...props
|
|
}) => {
|
|
return (
|
|
<div className="flex flex-col gap-1.5 w-full">
|
|
{label && (
|
|
<label className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
{label}
|
|
</label>
|
|
)}
|
|
|
|
<div className="relative flex items-center">
|
|
{leftIcon && (
|
|
<div className="absolute left-3 flex items-center pointer-events-none text-gray-400">
|
|
{leftIcon}
|
|
</div>
|
|
)}
|
|
|
|
<input
|
|
type={type}
|
|
placeholder={placeholder}
|
|
disabled={disabled}
|
|
className={`
|
|
w-full px-3 py-2 bg-white dark:bg-gray-900 border rounded-md outline-none transition-all
|
|
${leftIcon ? 'pl-10' : ''}
|
|
${rightIcon ? 'pr-10' : ''}
|
|
${error
|
|
? 'border-red-500 focus:ring-red-500'
|
|
: 'border-gray-300 dark:border-gray-700 focus:ring-2 focus:ring-blue-500 border-transparent focus:border-blue-500'
|
|
}
|
|
${disabled ? 'opacity-50 cursor-not-allowed bg-gray-100 dark:bg-gray-800' : ''}
|
|
${className}
|
|
`}
|
|
{...props}
|
|
/>
|
|
|
|
{rightIcon && (
|
|
<div className="absolute right-3 flex items-center pointer-events-none text-gray-400">
|
|
{rightIcon}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{error && (
|
|
<span className="text-xs text-red-500 font-medium">
|
|
{error}
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Input; |