Files
aggios.app/front-end-agency/components/ui/Input.tsx
2025-12-29 17:23:59 -03:00

109 lines
4.1 KiB
TypeScript

"use client";
import { InputHTMLAttributes, forwardRef, useState, ReactNode } from "react";
import { EyeIcon, EyeSlashIcon, ExclamationCircleIcon } from "@heroicons/react/24/outline";
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
helperText?: string;
leftIcon?: ReactNode;
rightIcon?: 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-[#7D7D7D] dark:text-gray-400 w-5 h-5">
{leftIcon}
</div>
)}
<input
ref={ref}
type={inputType}
className={`
w-full px-4 py-2.5 text-sm font-normal
border rounded-lg bg-white dark:bg-gray-800 dark:text-white
placeholder:text-gray-400 dark:placeholder:text-gray-500
transition-all duration-200
${leftIcon ? "pl-11" : ""}
${isPassword || rightIcon ? "pr-11" : ""}
${error
? "border-red-500 focus:border-red-500 focus:ring-4 focus:ring-red-500/10"
: "border-zinc-200 dark:border-zinc-700 focus:border-zinc-400 dark:focus:border-zinc-500 focus:ring-0"
}
outline-none
disabled:bg-gray-50 disabled:text-gray-500 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 transition-colors cursor-pointer"
>
{showPassword ? (
<EyeSlashIcon className="w-5 h-5" />
) : (
<EyeIcon className="w-5 h-5" />
)}
</button>
)}
{!isPassword && rightIcon && (
<button
type="button"
onClick={onRightIconClick}
className="absolute right-3.5 top-1/2 -translate-y-1/2 text-zinc-500 hover:text-zinc-900 transition-colors cursor-pointer"
>
<div className="w-5 h-5">{rightIcon}</div>
</button>
)}
</div>
{error && (
<p className="mt-1 text-[13px] text-red-500 flex items-center gap-1">
<ExclamationCircleIcon className="w-4 h-4" />
{error}
</p>
)}
{helperText && !error && (
<p className="mt-1 text-[13px] text-zinc-500">{helperText}</p>
)}
</div>
);
}
);
Input.displayName = "Input";
export default Input;