"use client"; import { useId, useState, useCallback } from "react"; import { cn } from "@/shared/utils/cn"; interface InputProps extends Omit, "size"> { label?: React.ReactNode; error?: React.ReactNode; hint?: React.ReactNode; icon?: string; inputClassName?: string; } export default function Input({ label, type = "text", placeholder, value, onChange, error, hint, icon, disabled = false, required = false, className, inputClassName, id: externalId, onKeyDown: externalOnKeyDown, onKeyUp: externalOnKeyUp, ...props }: InputProps) { const generatedId = useId(); const inputId = externalId || generatedId; const errorId = error ? `${inputId}-error` : undefined; const hintId = hint && !error ? `${inputId}-hint` : undefined; const capsLockId = `${inputId}-capslock`; const isPassword = type === "password"; const [capsLockOn, setCapsLockOn] = useState(false); const [inputFocused, setInputFocused] = useState(false); const detectCapsLock = useCallback( (e: React.KeyboardEvent) => { if (isPassword) { setCapsLockOn(e.getModifierState("CapsLock")); } }, [isPassword] ); const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { detectCapsLock(e); externalOnKeyDown?.(e); }, [detectCapsLock, externalOnKeyDown] ); const handleKeyUp = useCallback( (e: React.KeyboardEvent) => { detectCapsLock(e); externalOnKeyUp?.(e); }, [detectCapsLock, externalOnKeyUp] ); const showCapsLock = isPassword && capsLockOn && inputFocused; const describedBy = [errorId, showCapsLock ? capsLockId : undefined, hintId].filter(Boolean).join(" ") || undefined; return (
{label && ( )}
{icon && (
)} { setInputFocused(true); props.onFocus?.(e); }} onBlur={(e) => { setInputFocused(false); setCapsLockOn(false); props.onBlur?.(e); }} className={cn( "w-full py-2 px-3 text-sm text-text-main", "bg-white dark:bg-white/5 border border-black/10 dark:border-white/10 rounded-md", "placeholder-text-muted/60", "focus:ring-1 focus:ring-primary/30 focus:border-primary/50 focus:outline-none", "transition-all shadow-inner disabled:opacity-50 disabled:cursor-not-allowed", // iOS zoom fix "text-[16px] sm:text-sm", icon && "pl-10", error ? "border-red-500 focus:border-red-500 focus:ring-red-500/20" : "", inputClassName )} {...props} />
{showCapsLock && (

Caps Lock is on

)} {error && ( )} {hint && !error && (

{hint}

)}
); }