import React, { useEffect, useRef, useState } from "react"; import { useDebouncedCallback } from "../../../hooks/useDebouncedCallback"; import { cls } from "../../../util"; import { focusedDisabled } from "../../../styles"; import { TextField } from "../../TextField"; export function VirtualTableNumberInput(props: { error?: Error; value: number; align?: "right" | "left" | "center"; updateValue: (newValue: (number | null)) => void; focused: boolean; disabled: boolean; }) { const { align = "left", value, updateValue, focused } = props; const propStringValue = (value && typeof value === "number") ? value.toString() : ""; const [internalValue, setInternalValue] = useState(propStringValue); const prevValue = useRef(value); useEffect(() => { if (prevValue.current !== value && String(value) !== internalValue) setInternalValue(value ? value.toString() : null); prevValue.current = value; }, [value]); const doUpdate = React.useCallback(() => { if (internalValue !== propStringValue) { if (internalValue !== undefined && internalValue !== null) { const numberValue = parseFloat(internalValue); if (isNaN(numberValue)) return; updateValue(numberValue); } else { updateValue(null); } } }, [internalValue, value]); useDebouncedCallback(internalValue, doUpdate, !focused, 400); useEffect(() => { if (!focused && propStringValue !== internalValue) setInternalValue(value !== undefined && value !== null ? value.toString() : null); }, [value, focused]); const inputRef = React.useRef(null); useEffect(() => { if (inputRef.current && focused) { inputRef.current.focus({ preventScroll: true }); } }, [focused, inputRef]); const regexp = /^-?[0-9]+[,.]?[0-9]*$/; return ( { const newValue = evt.target.value.replace(",", "."); if (newValue.length === 0) setInternalValue(null); if (regexp.test(newValue) || newValue.startsWith("-")) setInternalValue(newValue); }} /> ); }