NumericFormat is used with MUI TextField and prefix prop. When I start writing any number, I cannot write more than one number. If I write fast this time I can write all numbers but the prefix is gone. All numbers inserted from the keyboard should be shown, and shouldn't be any missing numbers at the start the prefix should be visible but this is not working.
import { Observer } from "mobx-react-lite";
import { TextField, TextFieldProps } from "@mui/material";
import { AllowedNames } from "../utils/utils";
import { useDialogState } from "../states/dialog-state";
import { NumericFormat, NumericFormatProps } from "react-number-format";
import React from "react";
interface NumericFormatCustomProps {
onChange: (event: { target: { name: string; value: string } }) => void;
name: string;
}
const NumericFormatCustom = React.forwardRef<
NumericFormatProps<HTMLInputElement>,
NumericFormatCustomProps & NumericFormatProps<HTMLInputElement>
>(function NumericFormatCustom(props, ref) {
const { onChange, prefix, suffix, ...other } = props;
return (
<NumericFormat
{...other}
getInputRef={ref}
onValueChange={(values) => {
onChange({
target: {
name: props.name,
value: values.value,
},
});
}}
prefix={prefix}
suffix={suffix}
/>
);
});
function getValue(value: any, coefficient: number) {
if (value === "" || value === null || value === undefined) {
return "";
}
return ((value ?? 0) / Math.pow(10, coefficient)).toString();
}
function setValue(value: any, coefficient: number, decimalPlaces: number) {
if (value === "" || value === null || value === undefined) {
return null;
}
return (
(Math.round(parseFloat(value) * Math.pow(10, decimalPlaces)) /
Math.pow(10, decimalPlaces)) *
Math.pow(10, coefficient)
);
}
export type FormNumberFieldProps<T extends object> = Omit<
TextFieldProps,
"defaultValue" | "type"
> & {
dataKey: AllowedNames<T, number>;
prefix?: string;
suffix?: string;
decimalPlaces?: number;
coefficient?: number;
thousandSeparator?: boolean;
min?: number;
max?: number;
};
export default function FormNumberField<T extends object>({
dataKey,
prefix = "$ ",
suffix = "",
decimalPlaces = 0,
coefficient = 0,
thousandSeparator = true,
min,
max,
...rest
}: FormNumberFieldProps<T>) {
const [internalError, setInternalError] = React.useState("");
const stateProvider = useDialogState<T>();
const state = stateProvider.state;
return (
<Observer>
{() => {
const value = getValue(state.getValue(dataKey) as any, coefficient);
const checkMinMax = () => {
const numberValue = parseInt(value, 10);
if (typeof min === "number") {
if (numberValue < min) {
setInternalError(`The value should be more than ${min}`);
return;
}
}
if (typeof max === "number") {
if (numberValue > max) {
setInternalError(`The value should be less than ${max}`);
return;
}
}
setInternalError("");
};
return (
<TextField
{...rest}
fullWidth
inputMode="numeric"
onBlur={checkMinMax}
value={value}
onChange={(e) => {
state.setValue(
dataKey,
setValue(e.target.value, coefficient, decimalPlaces) as any,
);
}}
error={!!internalError || !!state.errorOf(dataKey)}
helperText={internalError || state.errorOf(dataKey)}
InputLabelProps={{ shrink: true }}
InputProps={{
inputComponent: NumericFormatCustom as any,
inputProps: {
prefix,
suffix,
thousandSeparator,
},
}}
/>
);
}}
</Observer>
);
}