import { useState } from "react"; import { AiOutlineEye, AiOutlineEyeInvisible } from "react-icons/ai"; /** * InputField * * Floating-label behaviour (Stripe / Vercel / Linear pattern): * Empty + not focused → label sits centred, acts as placeholder * Focused OR has value → label floats to top-left (small, uppercase) * Focused → label is teal * Has value, not focused → label stays floated but turns muted grey * * Props: * icon — React node for the left icon * hint — helper text shown below the field * error — error string; replaces hint when present */ export default function InputField({ label, name, type = "text", value, onChange, placeholder, autoComplete, error, onKeyDown, hint, icon, }) { const [focused, setFocused] = useState(false); const [showPass, setShowPass] = useState(false); const [autofilled, setAutofilled] = useState(false); const isPassword = type === "password"; const inputType = isPassword ? (showPass ? "text" : "password") : type; const hasValue = Boolean(value && value.length > 0); // Float the label if: focused, has a React-controlled value, OR browser autofilled const isFloated = focused || hasValue || autofilled; return (
{/* ── Left icon ── */} {icon && ( )} {/* ── Floating label ── */} {label && ( )} {/* ── Input ── */} setFocused(true)} onBlur={() => setFocused(false)} /* Detect browser autofill — Chrome fires a CSS animation on :-webkit-autofill which we can catch here to float the label before React's value state catches up. */ onAnimationStart={(e) => { if (e.animationName === "autofillStart") setAutofilled(true); if (e.animationName === "autofillEnd") setAutofilled(false); }} placeholder={focused ? placeholder : ""} autoComplete={autoComplete} className={[ "auth-input", icon ? "auth-input--with-icon" : "", isPassword ? "auth-input--with-toggle" : "", ].filter(Boolean).join(" ")} aria-invalid={!!error} aria-describedby={ error ? `${name}-error` : hint ? `${name}-hint` : undefined } /> {/* ── Password show / hide toggle ── */} {isPassword && ( )}
{/* Hint — only shown when there's no error */} {hint && !error && (
{hint}
)} {/* Error */} {error && ( )}
); }