Fix decimal input handling in DynamicJsonForm number fields
This commit is contained in:
parent
db0827b246
commit
fdbf896a04
1 changed files with 88 additions and 3 deletions
|
|
@ -125,6 +125,9 @@ const DynamicJsonForm = forwardRef<DynamicJsonFormRef, DynamicJsonFormProps>(
|
|||
const [rawJsonValue, setRawJsonValue] = useState<string>(
|
||||
JSON.stringify(value ?? generateDefaultValue(schema), null, 2),
|
||||
);
|
||||
const [numericInputDrafts, setNumericInputDrafts] = useState<
|
||||
Record<string, string>
|
||||
>({});
|
||||
|
||||
// Use a ref to manage debouncing timeouts to avoid parsing JSON
|
||||
// on every keystroke which would be inefficient and error-prone
|
||||
|
|
@ -134,6 +137,37 @@ const DynamicJsonForm = forwardRef<DynamicJsonFormRef, DynamicJsonFormProps>(
|
|||
return !!jsonError;
|
||||
};
|
||||
|
||||
const getPathKey = (path: string[]) =>
|
||||
path.length === 0 ? "$root" : path.join(".");
|
||||
|
||||
const getNumericDisplayValue = (
|
||||
path: string[],
|
||||
currentValue: JsonValue,
|
||||
): string => {
|
||||
const pathKey = getPathKey(path);
|
||||
if (Object.prototype.hasOwnProperty.call(numericInputDrafts, pathKey)) {
|
||||
return numericInputDrafts[pathKey];
|
||||
}
|
||||
return typeof currentValue === "number" ? currentValue.toString() : "";
|
||||
};
|
||||
|
||||
const updateNumericDraft = (path: string[], draftValue: string) => {
|
||||
const pathKey = getPathKey(path);
|
||||
setNumericInputDrafts((prev) => ({ ...prev, [pathKey]: draftValue }));
|
||||
};
|
||||
|
||||
const clearNumericDraft = (path: string[]) => {
|
||||
const pathKey = getPathKey(path);
|
||||
setNumericInputDrafts((prev) => {
|
||||
if (!Object.prototype.hasOwnProperty.call(prev, pathKey)) {
|
||||
return prev;
|
||||
}
|
||||
const next = { ...prev };
|
||||
delete next[pathKey];
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
// Debounce JSON parsing and parent updates to handle typing gracefully
|
||||
const debouncedUpdateParent = useCallback(
|
||||
(jsonString: string) => {
|
||||
|
|
@ -429,9 +463,10 @@ const DynamicJsonForm = forwardRef<DynamicJsonFormRef, DynamicJsonFormProps>(
|
|||
return (
|
||||
<Input
|
||||
type="number"
|
||||
value={(currentValue as number)?.toString() ?? ""}
|
||||
value={getNumericDisplayValue(path, currentValue)}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
updateNumericDraft(path, val);
|
||||
if (!val && !isRequired) {
|
||||
handleFieldChange(path, undefined);
|
||||
} else {
|
||||
|
|
@ -441,6 +476,19 @@ const DynamicJsonForm = forwardRef<DynamicJsonFormRef, DynamicJsonFormProps>(
|
|||
}
|
||||
}
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
const val = e.target.value;
|
||||
if (!val) {
|
||||
clearNumericDraft(path);
|
||||
return;
|
||||
}
|
||||
|
||||
const num = Number(val);
|
||||
if (!isNaN(num)) {
|
||||
handleFieldChange(path, num);
|
||||
}
|
||||
clearNumericDraft(path);
|
||||
}}
|
||||
placeholder={propSchema.description}
|
||||
required={isRequired}
|
||||
min={propSchema.minimum}
|
||||
|
|
@ -453,9 +501,10 @@ const DynamicJsonForm = forwardRef<DynamicJsonFormRef, DynamicJsonFormProps>(
|
|||
<Input
|
||||
type="number"
|
||||
step="1"
|
||||
value={(currentValue as number)?.toString() ?? ""}
|
||||
value={getNumericDisplayValue(path, currentValue)}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
updateNumericDraft(path, val);
|
||||
if (!val && !isRequired) {
|
||||
handleFieldChange(path, undefined);
|
||||
} else {
|
||||
|
|
@ -465,6 +514,19 @@ const DynamicJsonForm = forwardRef<DynamicJsonFormRef, DynamicJsonFormProps>(
|
|||
}
|
||||
}
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
const val = e.target.value;
|
||||
if (!val) {
|
||||
clearNumericDraft(path);
|
||||
return;
|
||||
}
|
||||
|
||||
const num = Number(val);
|
||||
if (!isNaN(num) && Number.isInteger(num)) {
|
||||
handleFieldChange(path, num);
|
||||
}
|
||||
clearNumericDraft(path);
|
||||
}}
|
||||
placeholder={propSchema.description}
|
||||
required={isRequired}
|
||||
min={propSchema.minimum}
|
||||
|
|
|
|||
Loading…
Reference in a new issue