68 lines
1.9 KiB
TypeScript
68 lines
1.9 KiB
TypeScript
import React, { FC, InputHTMLAttributes } from "react";
|
|
import classNames from "classnames";
|
|
|
|
interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
|
|
label?: string;
|
|
error?: string;
|
|
helperText?: string;
|
|
fullWidth?: boolean;
|
|
}
|
|
|
|
const Input: FC<InputProps> = ({
|
|
label,
|
|
error,
|
|
helperText,
|
|
fullWidth = true,
|
|
className,
|
|
id,
|
|
required,
|
|
...props
|
|
}) => {
|
|
const inputId = id || label?.toLowerCase().replace(/\s+/g, '-');
|
|
|
|
const inputStyles = classNames(
|
|
"px-3 py-2 rounded border-2 transition-colors",
|
|
"bg-gray-600 text-secondary",
|
|
"focus:outline-none focus:ring-2 focus:ring-offset-1",
|
|
{
|
|
"border-secondary focus:border-primary focus:ring-primary-500": !error,
|
|
"border-danger focus:border-danger focus:ring-danger-500": error,
|
|
"w-full": fullWidth,
|
|
"opacity-50 cursor-not-allowed": props.disabled,
|
|
},
|
|
className
|
|
);
|
|
|
|
const labelStyles = classNames(
|
|
"block text-sm font-medium mb-1",
|
|
{
|
|
"text-secondary": !error,
|
|
"text-danger": error,
|
|
}
|
|
);
|
|
|
|
return (
|
|
<div className={fullWidth ? "w-full" : ""}>
|
|
{label && (
|
|
<label htmlFor={inputId} className={labelStyles}>
|
|
{label}
|
|
{required && <span className="text-danger ml-1">*</span>}
|
|
</label>
|
|
)}
|
|
<input
|
|
id={inputId}
|
|
className={inputStyles}
|
|
required={required}
|
|
{...props}
|
|
/>
|
|
{error && (
|
|
<p className="mt-1 text-sm text-danger">{error}</p>
|
|
)}
|
|
{helperText && !error && (
|
|
<p className="mt-1 text-sm text-gray-400">{helperText}</p>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Input;
|