(() =>
- value === null || value === undefined || value === '' ? '' : formatGrouped(value),
- );
- const focusedRef = React.useRef(false);
-
- // Re-sync the display when the controlled value changes externally (form
- // reset, parent-driven update). Skip while the input is focused so we
- // don't fight the user's keystrokes.
- React.useEffect(() => {
- if (focusedRef.current) return;
- if (value === null || value === undefined || value === '') {
- setDisplay('');
- } else {
- setDisplay(formatGrouped(value));
- }
- }, [value]);
+ // react-number-format wants undefined (not null) to render empty.
+ const formatValue =
+ value === null || value === undefined || value === '' ? undefined : Number(value);
return (
@@ -101,31 +45,19 @@ export const CurrencyInput = React.forwardRef
{symbol}
- {
- const { display: nextDisplay, numeric } = parseTyped(e.target.value);
- setDisplay(nextDisplay);
- onChange(numeric);
- }}
- onFocus={(e) => {
- focusedRef.current = true;
- onFocus?.(e);
- }}
- onBlur={(e) => {
- focusedRef.current = false;
- // On blur, canonicalize to a clean grouped representation so the
- // user sees the final value rather than any half-typed state.
- if (value === null || value === undefined || value === '') {
- setDisplay('');
- } else {
- setDisplay(formatGrouped(value));
- }
- onBlur?.(e);
+ onValueChange={(values) => {
+ // floatValue is undefined when input is empty.
+ onChange(values.floatValue ?? null);
}}
className={cn('pl-9 tabular-nums', className)}
{...props}