import { useState, useEffect, useRef } from "react"; const NumberInput = ({ label, value, onChange, min = 1, max = 48, step = 1, allowDecimals = false, className = "", compact = false, disabled = false, }) => { const [inputValue, setInputValue] = useState(value?.toString() || ""); const prevDisabledRef = useRef(disabled); useEffect(() => { setInputValue(value?.toString() || ""); }, [value]); useEffect(() => { if (disabled && !prevDisabledRef.current && allowDecimals) { const numValue = parseFloat(inputValue); if ( inputValue === "" || inputValue === "." || isNaN(numValue) || numValue < min || numValue > max ) { const clampedValue = isNaN(numValue) ? min : Math.max(min, Math.min(max, numValue)); setInputValue(clampedValue.toString()); onChange(clampedValue); } } prevDisabledRef.current = disabled; }, [disabled, allowDecimals, inputValue, min, max, onChange]); const handleChange = (e) => { const inputVal = e.target.value; if (allowDecimals) { if (inputVal === ".") return; setInputValue(inputVal); if (inputVal !== "" && !inputVal.endsWith(".")) { const numValue = parseFloat(inputVal); if (!isNaN(numValue)) { onChange(numValue); } } } else { const cleanedInput = inputVal.includes(".") ? inputVal.split(".")[0] : inputVal; setInputValue(cleanedInput); if (cleanedInput === "") return; const numValue = parseInt(cleanedInput); if (!isNaN(numValue)) { const clampedValue = Math.max(min, Math.min(max, numValue)); onChange(clampedValue); if (clampedValue !== numValue) { setInputValue(clampedValue.toString()); } } } }; const handleBlur = () => { if ( inputValue === "" || isNaN(allowDecimals ? parseFloat(inputValue) : parseInt(inputValue)) ) { onChange(min); setInputValue(min.toString()); } else if (allowDecimals) { const numValue = parseFloat(inputValue); const clampedValue = Math.max(min, Math.min(max, numValue)); onChange(clampedValue); setInputValue(clampedValue.toString()); } }; return (