/** * SMA MA1~11 기간 입력 — 프리셋 드롭다운 없이 직접 숫자 편집 (포커스 유지) */ import React, { useState, useEffect, useRef, useCallback } from 'react'; const MIN = 1; const MAX = 500; interface SmaPeriodInputProps { value: number; disabled?: boolean; onCommit: (v: number) => void; } const SmaPeriodInput: React.FC = ({ value, disabled = false, onCommit, }) => { const [text, setText] = useState(() => String(value)); const editingRef = useRef(false); const committedRef = useRef(value); useEffect(() => { if (editingRef.current) return; if (value !== committedRef.current) { committedRef.current = value; setText(String(value)); } }, [value]); const commit = useCallback((raw: string) => { const trimmed = raw.trim(); if (trimmed === '') { setText(String(committedRef.current)); return; } const n = parseInt(trimmed, 10); if (isNaN(n)) { setText(String(committedRef.current)); return; } const clamped = Math.max(MIN, Math.min(MAX, n)); committedRef.current = clamped; setText(String(clamped)); onCommit(clamped); }, [onCommit]); return ( { e.stopPropagation(); }} onPointerDown={e => { e.stopPropagation(); }} onClick={e => e.stopPropagation()} onFocus={e => { e.stopPropagation(); editingRef.current = true; }} onChange={e => { const s = e.target.value.replace(/[^\d]/g, ''); setText(s); }} onBlur={e => { editingRef.current = false; commit(e.target.value); }} onKeyDown={e => { if (e.key === 'Enter') { (e.target as HTMLInputElement).blur(); } }} /> ); }; export default SmaPeriodInput;