import { useState, useCallback } from 'react'; import { asNumber, ErrorSchema, FieldPathList, FieldProps, FormContextType, RJSFSchema, StrictRJSFSchema, } from '@rjsf/utils'; // Matches a string that ends in a . character, optionally followed by a sequence of // digits followed by any number of 0 characters up until the end of the line. // Ensuring that there is at least one prefixed character is important so that // you don't incorrectly match against "0". const trailingCharMatcherWithPrefix = /\.([0-9]*0)*$/; // This is used for trimming the trailing 0 and . characters without affecting // the rest of the string. Its possible to use one RegEx with groups for this // functionality, but it is fairly complex compared to simply defining two // different matchers. const trailingCharMatcher = /[0.]0*$/; /** * The NumberField class has some special handling for dealing with trailing * decimal points and/or zeroes. This logic is designed to allow trailing values * to be visible in the input element, but not be represented in the * corresponding form data. * * The algorithm is as follows: * * 1. When the input value changes the value is cached in the component state * * 2. The value is then normalized, removing trailing decimal points and zeros, * then passed to the "onChange" callback * * 3. When the component is rendered, the formData value is checked against the * value cached in the state. If it matches the cached value, the cached * value is passed to the input instead of the formData value */ function NumberField( props: FieldProps, ) { const { registry, onChange, formData, value: initialValue } = props; const [lastValue, setLastValue] = useState(initialValue); const { StringField } = registry.fields; let value = formData; /** Handle the change from the `StringField` to properly convert to a number * * @param value - The current value for the change occurring */ const handleChange = useCallback( (value: FieldProps['value'], path: FieldPathList, errorSchema?: ErrorSchema, id?: string) => { // Cache the original value in component state setLastValue(value); // Normalize decimals that don't start with a zero character in advance so // that the rest of the normalization logic is simpler if (`${value}`.charAt(0) === '.') { value = `0${value}`; } // Check that the value is a string (this can happen if the widget used is a //