@rjsf/core 6.7.0 → 6.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.umd.js +41 -10
- package/dist/index.cjs +41 -10
- package/dist/index.cjs.map +2 -2
- package/dist/index.esm.js +74 -43
- package/dist/index.esm.js.map +3 -3
- package/lib/components/fields/NumberField.d.ts.map +1 -1
- package/lib/components/fields/NumberField.js +25 -14
- package/lib/components/fields/ObjectField.d.ts.map +1 -1
- package/lib/components/fields/ObjectField.js +19 -4
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/components/fields/NumberField.tsx +29 -15
- package/src/components/fields/ObjectField.tsx +27 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rjsf/core",
|
|
3
|
-
"version": "6.7.
|
|
3
|
+
"version": "6.7.1",
|
|
4
4
|
"description": "A simple React component capable of building HTML forms out of a JSON schema.",
|
|
5
5
|
"lint-staged": {
|
|
6
6
|
"{src,test}/**/*.{ts,tsx,js,jsx}": [
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"react": ">=18",
|
|
53
|
-
"@rjsf/utils": "^6.7.
|
|
53
|
+
"@rjsf/utils": "^6.7.1"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"lodash": "^4.18.1",
|
|
@@ -67,9 +67,9 @@
|
|
|
67
67
|
"ajv": "^8.20.0",
|
|
68
68
|
"atob": "^2.1.2",
|
|
69
69
|
"react-portal": "^4.3.0",
|
|
70
|
-
"@rjsf/snapshot-tests": "^6.7.
|
|
71
|
-
"@rjsf/
|
|
72
|
-
"@rjsf/
|
|
70
|
+
"@rjsf/snapshot-tests": "^6.7.1",
|
|
71
|
+
"@rjsf/utils": "^6.7.1",
|
|
72
|
+
"@rjsf/validator-ajv8": "^6.7.1"
|
|
73
73
|
},
|
|
74
74
|
"directories": {
|
|
75
75
|
"test": "test"
|
|
@@ -7,18 +7,10 @@ import type {
|
|
|
7
7
|
RJSFSchema,
|
|
8
8
|
StrictRJSFSchema,
|
|
9
9
|
} from '@rjsf/utils';
|
|
10
|
-
import { asNumber } from '@rjsf/utils';
|
|
10
|
+
import { asNumber, getDecimalSeparator, getUiOptions, optionsList } from '@rjsf/utils';
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
// digits followed by any number of 0 characters up until the end of the line.
|
|
14
|
-
// Ensuring that there is at least one prefixed character is important so that
|
|
15
|
-
// you don't incorrectly match against "0".
|
|
12
|
+
// Static matchers for standard '.' separator used during normalization inside handleChange
|
|
16
13
|
const trailingCharMatcherWithPrefix = /\.([0-9]*0)*$/;
|
|
17
|
-
|
|
18
|
-
// This is used for trimming the trailing 0 and . characters without affecting
|
|
19
|
-
// the rest of the string. Its possible to use one RegEx with groups for this
|
|
20
|
-
// functionality, but it is fairly complex compared to simply defining two
|
|
21
|
-
// different matchers.
|
|
22
14
|
const trailingCharMatcher = /[0.]0*$/;
|
|
23
15
|
|
|
24
16
|
/**
|
|
@@ -45,6 +37,9 @@ function NumberField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
45
37
|
const [lastValue, setLastValue] = useState(initialValue);
|
|
46
38
|
const { StringField } = registry.fields;
|
|
47
39
|
|
|
40
|
+
const separator = getDecimalSeparator();
|
|
41
|
+
const escapedSeparator = separator === '.' ? '\\.' : separator;
|
|
42
|
+
|
|
48
43
|
let value = formData;
|
|
49
44
|
|
|
50
45
|
/** Handle the change from the `StringField` to properly convert to a number
|
|
@@ -56,9 +51,12 @@ function NumberField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
56
51
|
// Cache the original value in component state
|
|
57
52
|
setLastValue(newValue);
|
|
58
53
|
|
|
54
|
+
// Convert locale separator to standard '.' first
|
|
55
|
+
const standardValue = typeof newValue === 'string' ? newValue.replace(separator, '.') : newValue;
|
|
56
|
+
|
|
59
57
|
// Normalize decimals that don't start with a zero character in advance so
|
|
60
58
|
// that the rest of the normalization logic is simpler
|
|
61
|
-
const normalizedValue = `${
|
|
59
|
+
const normalizedValue = `${standardValue}`.startsWith('.') ? `0${standardValue}` : standardValue;
|
|
62
60
|
|
|
63
61
|
// Check that the value is a string (this can happen if the widget used is a
|
|
64
62
|
// <select>, due to an enum declaration etc) then, if the value ends in a
|
|
@@ -70,14 +68,14 @@ function NumberField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
70
68
|
|
|
71
69
|
onChange(processed as unknown as T, path, errorSchema, id);
|
|
72
70
|
},
|
|
73
|
-
[onChange],
|
|
71
|
+
[onChange, separator],
|
|
74
72
|
);
|
|
75
73
|
|
|
76
74
|
if (typeof lastValue === 'string' && typeof value === 'number') {
|
|
77
75
|
// Construct a regular expression that checks for a string that consists
|
|
78
|
-
// of the formData value suffixed with zero or one
|
|
76
|
+
// of the formData value suffixed with zero or one locale separator characters and zero
|
|
79
77
|
// or more '0' characters
|
|
80
|
-
const re = new RegExp(`^(${String(value).replace('.',
|
|
78
|
+
const re = new RegExp(`^(${String(value).replace('.', escapedSeparator)})?${escapedSeparator}?0*$`);
|
|
81
79
|
|
|
82
80
|
// If the cached "lastValue" is a match, use that instead of the formData
|
|
83
81
|
// value to prevent the input value from changing in the UI
|
|
@@ -86,7 +84,23 @@ function NumberField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
86
84
|
}
|
|
87
85
|
}
|
|
88
86
|
|
|
89
|
-
|
|
87
|
+
// Format value to use the locale separator for rendering if it is a number
|
|
88
|
+
let displayValue: T | undefined = value;
|
|
89
|
+
if (typeof value === 'number' && separator !== '.') {
|
|
90
|
+
const { schema, uiSchema } = props;
|
|
91
|
+
const { schemaUtils } = registry;
|
|
92
|
+
const enumOptions = schemaUtils.isSelect(schema) ? optionsList(schema, uiSchema) : undefined;
|
|
93
|
+
const defaultWidget = enumOptions ? 'select' : 'text';
|
|
94
|
+
const { widget = defaultWidget } = getUiOptions(uiSchema);
|
|
95
|
+
|
|
96
|
+
// Do not convert the value to a locale-specific string for radio, select,
|
|
97
|
+
// or hidden widgets because option matching relies on the original numeric value.
|
|
98
|
+
if (widget !== 'radio' && widget !== 'select' && widget !== 'hidden') {
|
|
99
|
+
displayValue = String(value).replace('.', separator) as unknown as T;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return <StringField {...props} formData={displayValue} onChange={handleChange} />;
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
export default NumberField;
|
|
@@ -72,6 +72,16 @@ function getDefaultValue<T = any, S extends StrictRJSFSchema = RJSFSchema, F ext
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
function isAdditionalPropertySchema(schema: unknown) {
|
|
76
|
+
return Boolean((schema as RJSFMarkedSchema)?.[ADDITIONAL_PROPERTY_FLAG]);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getAdditionalPropertyOrder<S extends StrictRJSFSchema = RJSFSchema>(
|
|
80
|
+
schemaProperties: NonNullable<S['properties']>,
|
|
81
|
+
) {
|
|
82
|
+
return Object.keys(schemaProperties).filter((property) => isAdditionalPropertySchema(schemaProperties[property]));
|
|
83
|
+
}
|
|
84
|
+
|
|
75
85
|
/** Props for the `ObjectFieldProperty` component */
|
|
76
86
|
interface ObjectFieldPropertyProps<
|
|
77
87
|
T = any,
|
|
@@ -234,10 +244,17 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
|
|
|
234
244
|
[schemaUtils, rawSchema, formData],
|
|
235
245
|
);
|
|
236
246
|
const uiOptions = useMemo(() => getUiOptions<T, S, F>(uiSchema, globalUiOptions), [uiSchema, globalUiOptions]);
|
|
237
|
-
const
|
|
247
|
+
const schemaProperties = useMemo(() => schema.properties ?? {}, [schema.properties]);
|
|
238
248
|
// All the children will use childFieldPathId if present in the props, falling back to the fieldPathId
|
|
239
249
|
const childFieldPathId = props.childFieldPathId ?? fieldPathId;
|
|
240
250
|
const lastRenamedProperty = useRef({ previousKey: '', currentKey: undefined as string | undefined });
|
|
251
|
+
const [additionalPropertyOrder, setAdditionalPropertyOrder] = useState(() =>
|
|
252
|
+
getAdditionalPropertyOrder<S>(schemaProperties),
|
|
253
|
+
);
|
|
254
|
+
const definedPropertyOrder = useMemo(() => {
|
|
255
|
+
const additionalPropertySet = new Set(getAdditionalPropertyOrder<S>(schemaProperties));
|
|
256
|
+
return Object.keys(schemaProperties).filter((property) => !additionalPropertySet.has(property));
|
|
257
|
+
}, [schemaProperties]);
|
|
241
258
|
|
|
242
259
|
const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
|
|
243
260
|
const description = uiOptions.description ?? schema.description;
|
|
@@ -308,6 +325,7 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
|
|
|
308
325
|
lastRenamedProperty.current.currentKey = newKey;
|
|
309
326
|
lastRenamedProperty.current.previousKey = getAvailableKey(newKey, newFormData);
|
|
310
327
|
}
|
|
328
|
+
setAdditionalPropertyOrder((order) => [...order, newKey]);
|
|
311
329
|
onChange(newFormData, childFieldPathId.path);
|
|
312
330
|
}, [formData, onChange, translateString, schemaUtils, childFieldPathId, getAvailableKey, schema]);
|
|
313
331
|
|
|
@@ -339,6 +357,7 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
|
|
|
339
357
|
lastRenamedProperty.current.previousKey = oldKey;
|
|
340
358
|
}
|
|
341
359
|
lastRenamedProperty.current.currentKey = actualNewKey;
|
|
360
|
+
setAdditionalPropertyOrder((order) => order.map((property) => (property === oldKey ? actualNewKey : property)));
|
|
342
361
|
onChange(renamedObj, childFieldPathId.path);
|
|
343
362
|
}
|
|
344
363
|
},
|
|
@@ -350,6 +369,7 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
|
|
|
350
369
|
*/
|
|
351
370
|
const handleRemoveProperty = useCallback(
|
|
352
371
|
(key: string) => {
|
|
372
|
+
setAdditionalPropertyOrder((order) => order.filter((property) => property !== key));
|
|
353
373
|
onChange(ADDITIONAL_PROPERTY_KEY_REMOVE as T, [...childFieldPathId.path, key]);
|
|
354
374
|
},
|
|
355
375
|
[onChange, childFieldPathId],
|
|
@@ -369,8 +389,11 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
|
|
|
369
389
|
|
|
370
390
|
if (!renderOptionalField || hasFormData) {
|
|
371
391
|
try {
|
|
372
|
-
const
|
|
373
|
-
|
|
392
|
+
const definedPropertySet = new Set(definedPropertyOrder);
|
|
393
|
+
const currentAdditionalProperties = additionalPropertyOrder.filter(
|
|
394
|
+
(property) => Object.hasOwn(schemaProperties, property) && !definedPropertySet.has(property),
|
|
395
|
+
);
|
|
396
|
+
orderedProperties = orderProperties([...definedPropertyOrder, ...currentAdditionalProperties], uiOptions.order);
|
|
374
397
|
} catch (err) {
|
|
375
398
|
return (
|
|
376
399
|
<div>
|
|
@@ -395,9 +418,7 @@ export default function ObjectField<T = any, S extends StrictRJSFSchema = RJSFSc
|
|
|
395
418
|
title: uiOptions.label === false ? '' : templateTitle,
|
|
396
419
|
description: uiOptions.label === false ? undefined : description,
|
|
397
420
|
properties: orderedProperties.map((propertyName) => {
|
|
398
|
-
const addedByAdditionalProperties =
|
|
399
|
-
(schema.properties?.[propertyName] as RJSFMarkedSchema)?.[ADDITIONAL_PROPERTY_FLAG],
|
|
400
|
-
);
|
|
421
|
+
const addedByAdditionalProperties = isAdditionalPropertySchema(schema.properties?.[propertyName]);
|
|
401
422
|
const fieldUiSchema = addedByAdditionalProperties ? uiSchema.additionalProperties : uiSchema[propertyName];
|
|
402
423
|
const hidden = getUiOptions<T, S, F>(fieldUiSchema).widget === 'hidden';
|
|
403
424
|
const content = (
|