"use client"; import { useId, useState, type InputHTMLAttributes } from "react"; import "./etched-field.css"; /** * Etched Field * A text field with a floating label that rises into a notch cut in the top * border, like a name engraved on a plaque. An underline draws in on focus, and * validation state is carried by a small corner mark, not just colour. */ type Props = Omit, "id"> & { label: string; hint?: string; error?: string; }; export function EtchedField({ label, hint, error, className = "", onFocus, onBlur, onChange, ...rest }: Props) { const id = useId(); const [focused, setFocused] = useState(false); const [filled, setFilled] = useState(Boolean(rest.defaultValue ?? rest.value)); return (
{ setFocused(true); onFocus?.(e); }} onBlur={(e) => { setFocused(false); onBlur?.(e); }} onChange={(e) => { setFilled(e.target.value.length > 0); onChange?.(e); }} {...rest} />
{(error || hint) && (

{error ?? hint}

)}
); }