import { useEffect, useState } from 'react'; interface NumberFieldProps { value: number; onChange: (value: number) => void; min?: number; max?: number; step?: number; width?: number | string; className?: string; title?: string; } export function NumberField({ value, onChange, min, max, step, width, className, title }: NumberFieldProps) { const [text, setText] = useState(String(value)); useEffect(() => { setText(String(value)); }, [value]); const clamp = (n: number) => { if (min !== undefined) n = Math.max(min, n); if (max !== undefined) n = Math.min(max, n); return n; }; return ( e.stopPropagation()} onMouseDown={(e) => e.stopPropagation()} onChange={(e) => { const raw = e.target.value; if (!/^-?\d*$/.test(raw)) return; setText(raw); if (raw === '' || raw === '-') return; const parsed = Number(raw); if (!Number.isNaN(parsed)) { const next = clamp(parsed); if (next !== value) onChange(next); } }} onBlur={() => { if (text === '' || text === '-') { const fallback = clamp(value); onChange(fallback); setText(String(fallback)); } else { setText(String(value)); } }} onKeyDown={(e) => { if (e.key === 'ArrowUp' && step) { e.preventDefault(); const next = clamp(value + step); onChange(next); setText(String(next)); } if (e.key === 'ArrowDown' && step) { e.preventDefault(); const next = clamp(value - step); onChange(next); setText(String(next)); } }} /> ); }