"use client"; import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useRef, } from "react"; import type { FormEvent } from "react"; export type ActiveAnswerInput = 0 | 1; export interface AnswerFormHandle { focusInput: () => void; } interface AnswerFormProps { answerA: string; answerB: string; activeInput: ActiveAnswerInput; disabled: boolean; error: string; focusOnMount?: boolean; onAnswerAChange: (value: string) => void; onAnswerBChange: (value: string) => void; onActiveInputChange: (input: ActiveAnswerInput) => void; onInputBlur?: () => void; onInputFocus?: () => void; onSubmit: (event: FormEvent) => void; } const AnswerForm = forwardRef(function AnswerForm( { answerA, answerB, activeInput, disabled, error, focusOnMount = false, onAnswerAChange, onAnswerBChange, onActiveInputChange, onInputBlur, onInputFocus, onSubmit, }, ref, ) { const inputId = useId(); const formRef = useRef(null); const inputRef = useRef(null); const activeAnswer = activeInput === 0 ? answerA : answerB; const activeLabel = activeInput === 0 ? "첫째 항" : "둘째 항"; const activeEnterKeyHint = activeInput === 0 ? "next" : "done"; const activeAnswerChange = activeInput === 0 ? onAnswerAChange : onAnswerBChange; const focusInput = useCallback(() => { inputRef.current?.focus({ preventScroll: true }); onInputFocus?.(); }, [onInputFocus]); useImperativeHandle(ref, () => ({ focusInput }), [focusInput]); useEffect(() => { if (!disabled && focusOnMount) { window.requestAnimationFrame(() => { focusInput(); }); } }, [disabled, focusInput, focusOnMount]); function setAnswer(input: ActiveAnswerInput, value: string) { if (input === 0) { onAnswerAChange(value); } else { onAnswerBChange(value); } } function toggleMinus() { activeAnswerChange( activeAnswer.startsWith("-") ? activeAnswer.slice(1) : `-${activeAnswer}`, ); focusInput(); } function moveToInput(input: ActiveAnswerInput, reset = false) { onActiveInputChange(input); if (reset) { setAnswer(input, ""); } focusInput(); } function handleEnter() { if (activeInput === 0) { moveToInput(1); return; } formRef.current?.requestSubmit(); } const answerButtons = [ { index: 0 as const, label: "첫째 항", value: answerA, }, { index: 1 as const, label: "둘째 항", value: answerB, }, ]; return (
{ onInputFocus?.(); }} onBlur={() => { onInputBlur?.(); }} onChange={(event) => activeAnswerChange(event.target.value)} onKeyDown={(event) => { if (event.key === "Enter") { event.preventDefault(); handleEnter(); } }} disabled={disabled} autoComplete="off" enterKeyHint={activeEnterKeyHint} inputMode="numeric" pattern="-?[0-9]*" className="h-full min-w-0 flex-1 px-3 text-lg font-semibold text-slate-950 outline-none disabled:bg-slate-100 sm:rounded-md sm:border sm:border-slate-300 sm:px-4 sm:transition sm:focus:border-emerald-600 sm:focus:ring-2 sm:focus:ring-emerald-200" />
{answerButtons.map((button) => { const selected = activeInput === button.index; return ( ); })}
{error ? (

{error}

) : null}
); }); export default AnswerForm;