// Adapted from Untitled UI React (MIT). See THIRD_PARTY_NOTICES.md. import { useId, useState, type ComponentProps, type CSSProperties, } from "react"; export interface PinInputProps extends Omit< ComponentProps<"input">, "defaultValue" | "onChange" | "size" | "type" | "value" > { label: string; value?: string; defaultValue?: string; length?: number; numericOnly?: boolean; mask?: boolean; description?: string; error?: string; rootClassName?: string; onValueChange?: (value: string) => void; } export function PinInput({ label, value, defaultValue = "", length = 6, numericOnly = true, mask = false, description, error, rootClassName = "", className = "", id, onValueChange, style, "aria-describedby": describedBy, ...props }: PinInputProps) { const generatedId = useId(); const inputId = id ?? generatedId; const safeLength = Math.max(1, Math.floor(length)); const normalize = (next: string) => (numericOnly ? next.replace(/\D/g, "") : next).slice(0, safeLength); const [internalValue, setInternalValue] = useState(() => normalize(defaultValue), ); const currentValue = normalize(value ?? internalValue); const hint = error ?? description; const hintId = `${inputId}-hint`; const inputStyle = { ...style, "--pin-length": safeLength, } as CSSProperties; return (
{ const next = normalize(event.currentTarget.value); if (value === undefined) setInternalValue(next); onValueChange?.(next); }} /> {hint && (

{hint}

)}
); }