106 lines
3.9 KiB
TypeScript
106 lines
3.9 KiB
TypeScript
"use client";
|
|
|
|
import { InputHTMLAttributes, forwardRef, useState } from "react";
|
|
|
|
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
label?: string;
|
|
error?: string;
|
|
helperText?: string;
|
|
leftIcon?: string;
|
|
rightIcon?: string;
|
|
onRightIconClick?: () => void;
|
|
}
|
|
|
|
const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
(
|
|
{
|
|
label,
|
|
error,
|
|
helperText,
|
|
leftIcon,
|
|
rightIcon,
|
|
onRightIconClick,
|
|
className = "",
|
|
type,
|
|
...props
|
|
},
|
|
ref
|
|
) => {
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const isPassword = type === "password";
|
|
|
|
const inputType = isPassword ? (showPassword ? "text" : "password") : type;
|
|
|
|
return (
|
|
<div className="w-full">
|
|
{label && (
|
|
<label className="block text-[13px] font-semibold text-[#000000] dark:text-white mb-2">
|
|
{label}
|
|
{props.required && <span className="text-[#FF3A05] ml-1">*</span>}
|
|
</label>
|
|
)}
|
|
<div className="relative">
|
|
{leftIcon && (
|
|
<i
|
|
className={`${leftIcon} absolute left-3.5 top-1/2 -translate-y-1/2 text-[#7D7D7D] dark:text-gray-400 text-[20px]`}
|
|
/>
|
|
)}
|
|
<input
|
|
ref={ref}
|
|
type={inputType}
|
|
className={`
|
|
w-full px-3.5 py-3 text-[14px] font-normal
|
|
border rounded-md bg-white dark:bg-gray-700 dark:text-white
|
|
placeholder:text-[#7D7D7D] dark:placeholder:text-gray-400
|
|
transition-all
|
|
${leftIcon ? "pl-11" : ""}
|
|
${isPassword || rightIcon ? "pr-11" : ""}
|
|
${error
|
|
? "border-[#FF3A05]"
|
|
: "border-[#E5E5E5] dark:border-gray-600 focus:border-[#FF3A05]"
|
|
}
|
|
outline-none ring-0 focus:ring-0 shadow-none focus:shadow-none
|
|
disabled:bg-[#E5E5E5]/30 disabled:cursor-not-allowed
|
|
${className}
|
|
`}
|
|
{...props}
|
|
/>
|
|
{isPassword && (
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowPassword(!showPassword)}
|
|
className="absolute right-3.5 top-1/2 -translate-y-1/2 text-[#7D7D7D] hover:text-[#000000] transition-colors cursor-pointer"
|
|
>
|
|
<i
|
|
className={`${showPassword ? "ri-eye-off-line" : "ri-eye-line"} text-[20px]`}
|
|
/>
|
|
</button>
|
|
)}
|
|
{!isPassword && rightIcon && (
|
|
<button
|
|
type="button"
|
|
onClick={onRightIconClick}
|
|
className="absolute right-3.5 top-1/2 -translate-y-1/2 text-[#7D7D7D] hover:text-[#000000] transition-colors cursor-pointer"
|
|
>
|
|
<i className={`${rightIcon} text-[20px]`} />
|
|
</button>
|
|
)}
|
|
</div>
|
|
{error && (
|
|
<p className="mt-1 text-[13px] text-[#FF3A05] flex items-center gap-1">
|
|
<i className="ri-error-warning-line" />
|
|
{error}
|
|
</p>
|
|
)}
|
|
{helperText && !error && (
|
|
<p className="mt-1 text-[13px] text-[#7D7D7D]">{helperText}</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
|
|
Input.displayName = "Input";
|
|
|
|
export default Input;
|