"use client"; import { useEffect, useId, useRef, useState, type ChangeEvent, type ComponentPropsWithRef, type FocusEvent, type FormEvent, type ReactNode, } from "react"; import { cx } from "../../utils"; import { FoxFormLabel, type FoxFormLabelRequirement } from "../fox-form-label"; import { foxValidationMessage, foxValidators, type FoxValidationErrors, type FoxValidationMessages, type FoxValidator, } from "../../validation"; export type FoxInputSize = "lg" | "md" | "sm"; export type FoxInputState = "default" | "focused" | "completed" | "error" | "disabled" | "view"; /** * 네이티브 ``이 받는 것을 그대로 넘겨받는다 — type·name·autoComplete·maxLength· * min·max·step·pattern·inputMode·required·readOnly·disabled 등. 이름이 겹치거나 의미가 * 다른 것만 걷어내고 아래에서 다시 정의한다. */ type NativeInputProps = Omit< ComponentPropsWithRef<"input">, "size" | "onChange" | "onInput" | "className" | "children" | "hidden" >; export interface FoxInputProps extends NativeInputProps { size?: FoxInputSize; /** 값이 첫 인자다. 지우기 버튼은 이벤트 없이 빈 문자열로 호출한다. */ onChange?: (value: string, event?: ChangeEvent) => void; onInput?: (value: string, event: FormEvent) => void; label?: string; requirement?: FoxFormLabelRequirement; /** 헬퍼 메시지. 색은 상태를 따라간다. */ message?: string; /** 헬퍼 메시지 앞 아이콘. `currentColor`로 그려야 상태 색을 따라간다. */ messageIcon?: ReactNode; /** 입력 오른쪽 아이콘. 아이콘 폰트를 넘긴다 — `