Files
aggios.app/front-end-dash.aggios.app/components/ui/Input.tsx
2025-12-17 13:36:23 -03:00

113 lines
4.4 KiB
TypeScript

"use client";
import { InputHTMLAttributes, forwardRef, useState, ReactNode } from "react";
import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline';
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
helperText?: ReactNode;
leftIcon?: string | ReactNode;
rightIcon?: string | ReactNode;
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-zinc-900 dark:text-white mb-2">
{label}
{props.required && <span className="text-brand-500 ml-1">*</span>}
</label>
)}
<div className="relative">
{leftIcon && (
<div className="absolute left-3.5 top-1/2 -translate-y-1/2 text-zinc-400 dark:text-gray-400">
{typeof leftIcon === 'string' ? (
<i className={`${leftIcon} text-[20px]`} />
) : (
<div className="w-5 h-5">{leftIcon}</div>
)}
</div>
)}
<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-zinc-500 dark:placeholder:text-gray-400
transition-all
${leftIcon ? "pl-11" : ""}
${isPassword || rightIcon ? "pr-11" : ""}
${error
? "border-red-500 focus:border-red-500"
: "border-zinc-200 dark:border-gray-600 focus:border-brand-500"
}
outline-none ring-0 focus:ring-0 shadow-none focus:shadow-none
disabled:bg-zinc-100 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-zinc-500 hover:text-zinc-900 dark:text-gray-400 dark:hover:text-white transition-colors cursor-pointer"
>
{showPassword ? (
<EyeSlashIcon className="w-5 h-5" />
) : (
<EyeIcon className="w-5 h-5" />
)}
</button>
)}
{!isPassword && rightIcon && (
<div className="absolute right-3.5 top-1/2 -translate-y-1/2 text-zinc-400 dark:text-gray-400">
{typeof rightIcon === 'string' ? (
<i className={`${rightIcon} text-[20px]`} />
) : (
<div className="w-5 h-5">{rightIcon}</div>
)}
</div>
)}
</div>
{error && (
<p className="mt-1 text-[13px] text-red-500 flex items-center gap-1">
<i className="ri-error-warning-line" />
{error}
</p>
)}
{helperText && !error && (
<p className="mt-1 text-[13px] text-zinc-500">{helperText}</p>
)}
</div>
);
}
);
Input.displayName = "Input";
export default Input;