@rjsf/core 6.0.0-beta.13 → 6.0.0-beta.14

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.
Files changed (46) hide show
  1. package/dist/core.umd.js +235 -121
  2. package/dist/index.esm.js +277 -157
  3. package/dist/index.esm.js.map +3 -3
  4. package/dist/index.js +301 -182
  5. package/dist/index.js.map +3 -3
  6. package/lib/components/Form.d.ts +43 -12
  7. package/lib/components/Form.d.ts.map +1 -1
  8. package/lib/components/Form.js +70 -22
  9. package/lib/components/fields/ArrayField.d.ts +14 -4
  10. package/lib/components/fields/ArrayField.d.ts.map +1 -1
  11. package/lib/components/fields/ArrayField.js +74 -28
  12. package/lib/components/fields/BooleanField.d.ts.map +1 -1
  13. package/lib/components/fields/BooleanField.js +6 -1
  14. package/lib/components/fields/LayoutGridField.d.ts +19 -1
  15. package/lib/components/fields/LayoutGridField.d.ts.map +1 -1
  16. package/lib/components/fields/LayoutGridField.js +62 -12
  17. package/lib/components/fields/LayoutMultiSchemaField.d.ts.map +1 -1
  18. package/lib/components/fields/LayoutMultiSchemaField.js +2 -1
  19. package/lib/components/fields/MultiSchemaField.d.ts.map +1 -1
  20. package/lib/components/fields/MultiSchemaField.js +2 -1
  21. package/lib/components/fields/NullField.js +3 -3
  22. package/lib/components/fields/NumberField.js +2 -2
  23. package/lib/components/fields/ObjectField.d.ts +2 -2
  24. package/lib/components/fields/ObjectField.d.ts.map +1 -1
  25. package/lib/components/fields/ObjectField.js +16 -19
  26. package/lib/components/fields/SchemaField.js +2 -2
  27. package/lib/components/fields/StringField.d.ts.map +1 -1
  28. package/lib/components/fields/StringField.js +6 -1
  29. package/lib/components/widgets/AltDateWidget.d.ts.map +1 -1
  30. package/lib/components/widgets/AltDateWidget.js +15 -18
  31. package/lib/components/widgets/CheckboxesWidget.js +2 -2
  32. package/lib/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +11 -11
  34. package/src/components/Form.tsx +85 -22
  35. package/src/components/fields/ArrayField.tsx +75 -29
  36. package/src/components/fields/BooleanField.tsx +10 -1
  37. package/src/components/fields/LayoutGridField.tsx +69 -11
  38. package/src/components/fields/LayoutMultiSchemaField.tsx +2 -1
  39. package/src/components/fields/MultiSchemaField.tsx +2 -1
  40. package/src/components/fields/NullField.tsx +3 -3
  41. package/src/components/fields/NumberField.tsx +2 -2
  42. package/src/components/fields/ObjectField.tsx +16 -26
  43. package/src/components/fields/SchemaField.tsx +2 -2
  44. package/src/components/fields/StringField.tsx +10 -1
  45. package/src/components/widgets/AltDateWidget.tsx +20 -22
  46. package/src/components/widgets/CheckboxesWidget.tsx +2 -2
package/dist/core.umd.js CHANGED
@@ -1,12 +1,12 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('@rjsf/utils'), require('lodash/forEach'), require('lodash/get'), require('lodash/isEmpty'), require('lodash/isNil'), require('lodash/pick'), require('lodash/toPath'), require('lodash/cloneDeep'), require('lodash/isObject'), require('lodash/set'), require('nanoid'), require('react/jsx-runtime'), require('lodash/each'), require('lodash/flatten'), require('lodash/has'), require('lodash/includes'), require('lodash/intersection'), require('lodash/isFunction'), require('lodash/isEqual'), require('lodash/isPlainObject'), require('lodash/isString'), require('lodash/isUndefined'), require('lodash/noop'), require('lodash/omit'), require('markdown-to-jsx'), require('lodash/unset')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'react', '@rjsf/utils', 'lodash/forEach', 'lodash/get', 'lodash/isEmpty', 'lodash/isNil', 'lodash/pick', 'lodash/toPath', 'lodash/cloneDeep', 'lodash/isObject', 'lodash/set', 'nanoid', 'react/jsx-runtime', 'lodash/each', 'lodash/flatten', 'lodash/has', 'lodash/includes', 'lodash/intersection', 'lodash/isFunction', 'lodash/isEqual', 'lodash/isPlainObject', 'lodash/isString', 'lodash/isUndefined', 'lodash/noop', 'lodash/omit', 'markdown-to-jsx', 'lodash/unset'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.JSONSchemaForm = {}, global.react, global.utils, global._forEach, global.get2, global.isEmpty, global._isNil, global._pick, global._toPath, global.cloneDeep2, global.isObject, global.set, global.nanoid, global.jsxRuntime, global.each, global.flatten, global.has, global.includes, global.intersection, global.isFunction, global.isEqual, global.isPlainObject, global.isString, global.isUndefined, global.noop, global.omit3, global.Markdown, global.unset));
5
- })(this, (function (exports, react, utils, _forEach, get2, isEmpty, _isNil, _pick, _toPath, cloneDeep2, isObject, set, nanoid, jsxRuntime, each, flatten, has, includes, intersection, isFunction, isEqual, isPlainObject, isString, isUndefined, noop, omit3, Markdown, unset) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('@rjsf/utils'), require('lodash/cloneDeep'), require('lodash/forEach'), require('lodash/get'), require('lodash/isEmpty'), require('lodash/isNil'), require('lodash/pick'), require('lodash/set'), require('lodash/toPath'), require('lodash/isObject'), require('lodash/uniqueId'), require('react/jsx-runtime'), require('lodash/each'), require('lodash/flatten'), require('lodash/has'), require('lodash/includes'), require('lodash/intersection'), require('lodash/isFunction'), require('lodash/isEqual'), require('lodash/isPlainObject'), require('lodash/isString'), require('lodash/isUndefined'), require('lodash/last'), require('lodash/noop'), require('lodash/omit'), require('markdown-to-jsx'), require('lodash/unset')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'react', '@rjsf/utils', 'lodash/cloneDeep', 'lodash/forEach', 'lodash/get', 'lodash/isEmpty', 'lodash/isNil', 'lodash/pick', 'lodash/set', 'lodash/toPath', 'lodash/isObject', 'lodash/uniqueId', 'react/jsx-runtime', 'lodash/each', 'lodash/flatten', 'lodash/has', 'lodash/includes', 'lodash/intersection', 'lodash/isFunction', 'lodash/isEqual', 'lodash/isPlainObject', 'lodash/isString', 'lodash/isUndefined', 'lodash/last', 'lodash/noop', 'lodash/omit', 'markdown-to-jsx', 'lodash/unset'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.JSONSchemaForm = {}, global.react, global.utils, global._cloneDeep, global._forEach, global.get2, global.isEmpty, global._isNil, global._pick, global.set, global._toPath, global.isObject, global.uniqueId, global.jsxRuntime, global.each, global.flatten, global.has, global.includes, global.intersection, global.isFunction, global.isEqual, global.isPlainObject, global.isString, global.isUndefined, global.last, global.noop, global.omit3, global.Markdown, global.unset));
5
+ })(this, (function (exports, react, utils, _cloneDeep, _forEach, get2, isEmpty, _isNil, _pick, set, _toPath, isObject, uniqueId, jsxRuntime, each, flatten, has, includes, intersection, isFunction, isEqual, isPlainObject, isString, isUndefined, last, noop, omit3, Markdown, unset) { 'use strict';
6
6
 
7
7
  // src/components/Form.tsx
8
8
  function generateRowId() {
9
- return nanoid.nanoid();
9
+ return uniqueId("rjsf-array-item-");
10
10
  }
11
11
  function generateKeyedFormData(formData) {
12
12
  return !Array.isArray(formData) ? [] : formData.map((item) => {
@@ -155,7 +155,8 @@
155
155
  keyedFormData: newKeyedFormData,
156
156
  updatedKeyedFormData: true
157
157
  },
158
- () => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema)
158
+ // add click will pass the empty `path` array to the onChange which adds the appropriate path
159
+ () => onChange(keyedToPlainFormData(newKeyedFormData), [], newErrorSchema)
159
160
  );
160
161
  }
161
162
  /** Callback handler for when the user clicks on the add button. Creates a new row of keyed form data at the end of
@@ -205,7 +206,7 @@
205
206
  }
206
207
  const newKeyedFormDataRow = {
207
208
  key: generateRowId(),
208
- item: cloneDeep2(keyedFormData[index].item)
209
+ item: _cloneDeep(keyedFormData[index].item)
209
210
  };
210
211
  const newKeyedFormData = [...keyedFormData];
211
212
  if (index !== void 0) {
@@ -218,7 +219,8 @@
218
219
  keyedFormData: newKeyedFormData,
219
220
  updatedKeyedFormData: true
220
221
  },
221
- () => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema)
222
+ // Copy index will pass the empty `path` array to the onChange which adds the appropriate path
223
+ () => onChange(keyedToPlainFormData(newKeyedFormData), [], newErrorSchema)
222
224
  );
223
225
  };
224
226
  };
@@ -253,7 +255,8 @@
253
255
  keyedFormData: newKeyedFormData,
254
256
  updatedKeyedFormData: true
255
257
  },
256
- () => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema)
258
+ // drop index will pass the empty `path` array to the onChange which adds the appropriate path
259
+ () => onChange(keyedToPlainFormData(newKeyedFormData), [], newErrorSchema)
257
260
  );
258
261
  };
259
262
  };
@@ -297,7 +300,8 @@
297
300
  {
298
301
  keyedFormData: newKeyedFormData
299
302
  },
300
- () => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema)
303
+ // reorder click will pass the empty `path` array to the onChange which adds the appropriate path
304
+ () => onChange(keyedToPlainFormData(newKeyedFormData), [], newErrorSchema)
301
305
  );
302
306
  };
303
307
  };
@@ -307,28 +311,47 @@
307
311
  * @param index - The index of the item being changed
308
312
  */
309
313
  onChangeForIndex = (index) => {
310
- return (value, newErrorSchema, id) => {
311
- const { formData, onChange, errorSchema } = this.props;
312
- const arrayData = Array.isArray(formData) ? formData : [];
313
- const newFormData = arrayData.map((item, i) => {
314
- const jsonValue = typeof value === "undefined" ? null : value;
315
- return index === i ? jsonValue : item;
316
- });
314
+ return (value, path, newErrorSchema, id) => {
315
+ const { onChange } = this.props;
316
+ const changePath = Array.isArray(path) ? path.slice() : [];
317
+ changePath.unshift(index);
317
318
  onChange(
318
- newFormData,
319
- errorSchema && errorSchema && {
320
- ...errorSchema,
321
- [index]: newErrorSchema
322
- },
319
+ // We need to treat undefined items as nulls to have validation.
320
+ // See https://github.com/tdegrunt/jsonschema/issues/206
321
+ value === void 0 ? null : value,
322
+ changePath,
323
+ newErrorSchema,
323
324
  id
324
325
  );
325
326
  };
326
327
  };
327
328
  /** Callback handler used to change the value for a checkbox */
328
329
  onSelectChange = (value) => {
329
- const { onChange, idSchema } = this.props;
330
- onChange(value, void 0, idSchema && idSchema.$id);
330
+ const { name, onChange, idSchema } = this.props;
331
+ onChange(value, [name], void 0, idSchema && idSchema.$id);
331
332
  };
333
+ /** Helper method to compute item UI schema for both normal and fixed arrays
334
+ * Handles both static object and dynamic function cases
335
+ *
336
+ * @param uiSchema - The parent UI schema containing items definition
337
+ * @param item - The item data
338
+ * @param index - The index of the item
339
+ * @param formContext - The form context
340
+ * @returns The computed UI schema for the item
341
+ */
342
+ computeItemUiSchema(uiSchema, item, index, formContext) {
343
+ if (typeof uiSchema.items === "function") {
344
+ try {
345
+ const result = uiSchema.items(item, index, formContext);
346
+ return result;
347
+ } catch (e) {
348
+ console.error(`Error executing dynamic uiSchema.items function for item at index ${index}:`, e);
349
+ return void 0;
350
+ }
351
+ } else {
352
+ return uiSchema.items;
353
+ }
354
+ }
332
355
  /** Renders the `ArrayField` depending on the specific needs of the schema and uischema elements
333
356
  */
334
357
  render() {
@@ -403,6 +426,7 @@
403
426
  const itemErrorSchema = errorSchema ? errorSchema[index] : void 0;
404
427
  const itemIdPrefix = idSchema.$id + idSeparator + index;
405
428
  const itemIdSchema = schemaUtils.toIdSchema(itemSchema, itemIdPrefix, itemCast, idPrefix, idSeparator);
429
+ const itemUiSchema = this.computeItemUiSchema(uiSchema, item, index, formContext);
406
430
  return this.renderArrayFieldItem({
407
431
  key,
408
432
  index,
@@ -415,7 +439,7 @@
415
439
  itemIdSchema,
416
440
  itemErrorSchema,
417
441
  itemData: itemCast,
418
- itemUiSchema: uiSchema.items,
442
+ itemUiSchema,
419
443
  autofocus: autofocus && index === 0,
420
444
  onBlur,
421
445
  onFocus,
@@ -642,7 +666,16 @@
642
666
  const itemSchema = (additional && isObject(schema.additionalItems) ? schemaUtils.retrieveSchema(schema.additionalItems, itemCast) : itemSchemas[index]) || {};
643
667
  const itemIdPrefix = idSchema.$id + idSeparator + index;
644
668
  const itemIdSchema = schemaUtils.toIdSchema(itemSchema, itemIdPrefix, itemCast, idPrefix, idSeparator);
645
- const itemUiSchema = additional ? uiSchema.additionalItems || {} : Array.isArray(uiSchema.items) ? uiSchema.items[index] : uiSchema.items || {};
669
+ let itemUiSchema;
670
+ if (additional) {
671
+ itemUiSchema = uiSchema.additionalItems;
672
+ } else {
673
+ if (Array.isArray(uiSchema.items)) {
674
+ itemUiSchema = uiSchema.items[index];
675
+ } else {
676
+ itemUiSchema = this.computeItemUiSchema(uiSchema, item, index, formContext);
677
+ }
678
+ }
646
679
  const itemErrorSchema = errorSchema ? errorSchema[index] : void 0;
647
680
  return this.renderArrayFieldItem({
648
681
  key,
@@ -847,6 +880,12 @@
847
880
  enumOptions = utils.optionsList({ enum: enums }, uiSchema);
848
881
  }
849
882
  }
883
+ const onWidgetChange = react.useCallback(
884
+ (value, errorSchema, id) => {
885
+ return onChange(value, [], errorSchema, id);
886
+ },
887
+ [onChange]
888
+ );
850
889
  return /* @__PURE__ */ jsxRuntime.jsx(
851
890
  Widget,
852
891
  {
@@ -855,7 +894,7 @@
855
894
  uiSchema,
856
895
  id: idSchema.$id,
857
896
  name,
858
- onChange,
897
+ onChange: onWidgetChange,
859
898
  onFocus,
860
899
  onBlur,
861
900
  label,
@@ -878,6 +917,9 @@
878
917
  function getNonNullishValue(value, fallback) {
879
918
  return value ?? fallback;
880
919
  }
920
+ function isNumericIndex(str) {
921
+ return /^\d+?$/.test(str);
922
+ }
881
923
  var LayoutGridField = class _LayoutGridField extends react.PureComponent {
882
924
  static defaultProps = {
883
925
  layoutGridSchema: void 0
@@ -991,6 +1033,38 @@
991
1033
  const baseId = get2(baseIdSchema, utils.ID_KEY);
992
1034
  return schemaUtils.toIdSchema(schema, baseId, formData, baseId, idSeparator);
993
1035
  }
1036
+ /** Computes the `rawSchema` and `idSchema` for a `schema` and a `potentialIndex`. If the `schema` is of type array,
1037
+ * has an `ITEMS_KEY` element and `potentialIndex` represents a numeric value, the element at `ITEMS_KEY` is checked
1038
+ * to see if it is an array. If it is AND the `potentialIndex`th element is available, it is used as the `rawSchema`,
1039
+ * otherwise the last value of the element is used. If it is not, then the element is used as the `rawSchema`. In
1040
+ * either case, an `idSchema` is computed for the array index. If the `schema` does not represent an array or the
1041
+ * `potentialIndex` is not a numeric value, then `rawSchema` is returned as undefined and given `idSchema` is returned
1042
+ * as is.
1043
+ *
1044
+ * @param schema - The schema to generate the idSchema for
1045
+ * @param idSchema - The IdSchema for the schema
1046
+ * @param potentialIndex - A string containing a potential index
1047
+ * @param [idSeparator] - The param to pass into the `toIdSchema` util which will use it to join the `idSchema` paths
1048
+ * @returns - An object containing the `rawSchema` and `idSchema` of an array item, otherwise an undefined `rawSchema`
1049
+ */
1050
+ static computeArraySchemasIfPresent(schema, idSchema, potentialIndex, idSeparator) {
1051
+ let rawSchema;
1052
+ if (isNumericIndex(potentialIndex) && schema && schema?.type === "array" && has(schema, utils.ITEMS_KEY)) {
1053
+ const index = Number(potentialIndex);
1054
+ const items = schema[utils.ITEMS_KEY];
1055
+ if (Array.isArray(items)) {
1056
+ if (index > items.length) {
1057
+ rawSchema = last(items);
1058
+ } else {
1059
+ rawSchema = items[index];
1060
+ }
1061
+ } else {
1062
+ rawSchema = items;
1063
+ }
1064
+ idSchema = { [utils.ID_KEY]: `${idSchema[utils.ID_KEY]}${idSeparator ?? "_"}${index}` };
1065
+ }
1066
+ return { rawSchema, idSchema };
1067
+ }
994
1068
  /** Given a `dottedPath` to a field in the `initialSchema`, iterate through each individual path in the schema until
995
1069
  * the leaf path is found and returned (along with whether that leaf path `isRequired`) OR no schema exists for an
996
1070
  * element in the path. If the leaf schema element happens to be a oneOf/anyOf then also return the oneOf/anyOf as
@@ -1030,7 +1104,9 @@
1030
1104
  rawSchema = get2(selectedSchema, [utils.PROPERTIES_KEY, part], {});
1031
1105
  idSchema = get2(selectedIdSchema, part, {});
1032
1106
  } else {
1033
- rawSchema = {};
1107
+ const result = _LayoutGridField.computeArraySchemasIfPresent(schema, idSchema, part, idSeparator);
1108
+ rawSchema = result.rawSchema ?? {};
1109
+ idSchema = result.idSchema;
1034
1110
  }
1035
1111
  innerData = get2(innerData, part, {});
1036
1112
  schema = schemaUtils.retrieveSchema(rawSchema, innerData);
@@ -1049,9 +1125,15 @@
1049
1125
  idSchema = utils.mergeObjects(rawIdSchema, idSchema);
1050
1126
  }
1051
1127
  isRequired = schema !== void 0 && Array.isArray(schema.required) && includes(schema.required, leafPath);
1052
- schema = get2(schema, [utils.PROPERTIES_KEY, leafPath]);
1053
- schema = schema ? schemaUtils.retrieveSchema(schema) : schema;
1054
- idSchema = get2(idSchema, leafPath, {});
1128
+ const result = _LayoutGridField.computeArraySchemasIfPresent(schema, idSchema, leafPath, idSeparator);
1129
+ if (result.rawSchema) {
1130
+ schema = result.rawSchema;
1131
+ idSchema = result.idSchema;
1132
+ } else {
1133
+ schema = get2(schema, [utils.PROPERTIES_KEY, leafPath]);
1134
+ schema = schema ? schemaUtils.retrieveSchema(schema) : schema;
1135
+ idSchema = get2(idSchema, leafPath, {});
1136
+ }
1055
1137
  isReadonly = getNonNullishValue(schema?.readOnly, isReadonly);
1056
1138
  if (schema && (has(schema, utils.ONE_OF_KEY) || has(schema, utils.ANY_OF_KEY))) {
1057
1139
  const xxx = has(schema, utils.ONE_OF_KEY) ? utils.ONE_OF_KEY : utils.ANY_OF_KEY;
@@ -1131,16 +1213,14 @@
1131
1213
  * @returns - The `onChange` handling function for the `dottedPath` field
1132
1214
  */
1133
1215
  onFieldChange = (dottedPath) => {
1134
- return (value, errSchema, id) => {
1135
- const { onChange, errorSchema, formData } = this.props;
1136
- const newFormData = cloneDeep2(formData || {});
1216
+ return (value, path, errSchema, id) => {
1217
+ const { onChange, errorSchema } = this.props;
1137
1218
  let newErrorSchema = errorSchema;
1138
1219
  if (errSchema && errorSchema) {
1139
- newErrorSchema = cloneDeep2(errorSchema);
1220
+ newErrorSchema = _cloneDeep(errorSchema);
1140
1221
  set(newErrorSchema, dottedPath, errSchema);
1141
1222
  }
1142
- set(newFormData, dottedPath, value);
1143
- onChange(newFormData, newErrorSchema, id);
1223
+ onChange(value, dottedPath.split("."), newErrorSchema, id);
1144
1224
  };
1145
1225
  };
1146
1226
  /** Renders the `children` of the `GridType.CONDITION` if it passes. The `layoutGridSchema` for the
@@ -1502,7 +1582,7 @@
1502
1582
  if (newFormData) {
1503
1583
  set(newFormData, selectorField, opt);
1504
1584
  }
1505
- onChange(newFormData, void 0, id);
1585
+ onChange(newFormData, [name], void 0, id);
1506
1586
  };
1507
1587
  const widgetOptions = { enumOptions, ...uiOptions };
1508
1588
  const errors = !hideFieldError && rawErrors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(FieldErrorTemplate2, { idSchema, schema, errors: rawErrors, registry }) : void 0;
@@ -1636,7 +1716,7 @@
1636
1716
  newFormData = schemaUtils.getDefaultFormState(newOption, newFormData, "excludeObjectChildren");
1637
1717
  }
1638
1718
  this.setState({ selectedOption: intOption }, () => {
1639
- onChange(newFormData, void 0, this.getFieldId());
1719
+ onChange(newFormData, [], void 0, this.getFieldId());
1640
1720
  });
1641
1721
  };
1642
1722
  getFieldId() {
@@ -1758,13 +1838,13 @@
1758
1838
  const { StringField: StringField2 } = registry.fields;
1759
1839
  let value = formData;
1760
1840
  const handleChange = react.useCallback(
1761
- (value2, errorSchema, id) => {
1841
+ (value2, path, errorSchema, id) => {
1762
1842
  setLastValue(value2);
1763
1843
  if (`${value2}`.charAt(0) === ".") {
1764
1844
  value2 = `0${value2}`;
1765
1845
  }
1766
1846
  const processed = typeof value2 === "string" && value2.match(trailingCharMatcherWithPrefix) ? utils.asNumber(value2.replace(trailingCharMatcher, "")) : utils.asNumber(value2);
1767
- onChange(processed, errorSchema, id);
1847
+ onChange(processed, path, errorSchema, id);
1768
1848
  },
1769
1849
  [onChange]
1770
1850
  );
@@ -1801,20 +1881,14 @@
1801
1881
  * @returns - The onPropertyChange callback for the `name` property
1802
1882
  */
1803
1883
  onPropertyChange = (name, addedByAdditionalProperties = false) => {
1804
- return (value, newErrorSchema, id) => {
1805
- const { formData, onChange, errorSchema } = this.props;
1884
+ return (value, path, newErrorSchema, id) => {
1885
+ const { onChange } = this.props;
1806
1886
  if (value === void 0 && addedByAdditionalProperties) {
1807
1887
  value = "";
1808
1888
  }
1809
- const newFormData = { ...formData, [name]: value };
1810
- onChange(
1811
- newFormData,
1812
- errorSchema && errorSchema && {
1813
- ...errorSchema,
1814
- [name]: newErrorSchema
1815
- },
1816
- id
1817
- );
1889
+ const changePath = Array.isArray(path) ? path.slice() : [];
1890
+ changePath.unshift(name);
1891
+ onChange(value, changePath, newErrorSchema, id);
1818
1892
  };
1819
1893
  };
1820
1894
  /** Returns a callback to handle the onDropPropertyClick event for the given `key` which removes the old `key` data
@@ -1826,10 +1900,10 @@
1826
1900
  onDropPropertyClick = (key) => {
1827
1901
  return (event) => {
1828
1902
  event.preventDefault();
1829
- const { onChange, formData } = this.props;
1903
+ const { onChange, formData, name } = this.props;
1830
1904
  const copiedFormData = { ...formData };
1831
1905
  unset(copiedFormData, key);
1832
- onChange(copiedFormData);
1906
+ onChange(copiedFormData, [name]);
1833
1907
  };
1834
1908
  };
1835
1909
  /** Computes the next available key name from the `preferredKey`, indexing through the already existing keys until one
@@ -1856,11 +1930,11 @@
1856
1930
  * @returns - The key change callback function
1857
1931
  */
1858
1932
  onKeyChange = (oldValue) => {
1859
- return (value, newErrorSchema) => {
1933
+ return (value) => {
1860
1934
  if (oldValue === value) {
1861
1935
  return;
1862
1936
  }
1863
- const { formData, onChange, errorSchema } = this.props;
1937
+ const { formData, onChange } = this.props;
1864
1938
  value = this.getAvailableKey(value, formData);
1865
1939
  const newFormData = {
1866
1940
  ...formData
@@ -1872,13 +1946,7 @@
1872
1946
  });
1873
1947
  const renamedObj = Object.assign({}, ...keyValues);
1874
1948
  this.setState({ wasPropertyKeyModified: true });
1875
- onChange(
1876
- renamedObj,
1877
- errorSchema && errorSchema && {
1878
- ...errorSchema,
1879
- [value]: newErrorSchema
1880
- }
1881
- );
1949
+ onChange(renamedObj, []);
1882
1950
  };
1883
1951
  };
1884
1952
  /** Returns a default value to be used for a new additional schema property of the given `type`
@@ -1914,7 +1982,7 @@
1914
1982
  if (!(schema.additionalProperties || schema.patternProperties)) {
1915
1983
  return;
1916
1984
  }
1917
- const { formData, onChange, registry } = this.props;
1985
+ const { formData, name, onChange, registry } = this.props;
1918
1986
  const newFormData = { ...formData };
1919
1987
  const newKey = this.getAvailableKey("newKey", newFormData);
1920
1988
  if (schema.patternProperties) {
@@ -1942,7 +2010,7 @@
1942
2010
  const newValue = constValue ?? defaultValue ?? this.getDefaultValue(type);
1943
2011
  set(newFormData, newKey, newValue);
1944
2012
  }
1945
- onChange(newFormData);
2013
+ onChange(newFormData, [name]);
1946
2014
  };
1947
2015
  /** Renders the `ObjectField` from the given props
1948
2016
  */
@@ -2120,9 +2188,9 @@
2120
2188
  _idSchema
2121
2189
  );
2122
2190
  const handleFieldComponentChange = react.useCallback(
2123
- (formData2, newErrorSchema, id2) => {
2191
+ (formData2, path, newErrorSchema, id2) => {
2124
2192
  const theId = id2 || fieldId;
2125
- return onChange(formData2, newErrorSchema, theId);
2193
+ return onChange(formData2, path, newErrorSchema, theId);
2126
2194
  },
2127
2195
  [fieldId, onChange]
2128
2196
  );
@@ -2328,6 +2396,12 @@
2328
2396
  const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions);
2329
2397
  const label = uiTitle ?? title ?? name;
2330
2398
  const Widget = utils.getWidget(schema, widget, widgets2);
2399
+ const onWidgetChange = react.useCallback(
2400
+ (value, errorSchema, id) => {
2401
+ return onChange(value, [], errorSchema, id);
2402
+ },
2403
+ [onChange]
2404
+ );
2331
2405
  return /* @__PURE__ */ jsxRuntime.jsx(
2332
2406
  Widget,
2333
2407
  {
@@ -2340,7 +2414,7 @@
2340
2414
  hideLabel: !displayLabel,
2341
2415
  hideError,
2342
2416
  value: formData,
2343
- onChange,
2417
+ onChange: onWidgetChange,
2344
2418
  onBlur,
2345
2419
  onFocus,
2346
2420
  required,
@@ -2356,12 +2430,12 @@
2356
2430
  }
2357
2431
  var StringField_default = StringField;
2358
2432
  function NullField(props) {
2359
- const { formData, onChange } = props;
2433
+ const { name, formData, onChange } = props;
2360
2434
  react.useEffect(() => {
2361
2435
  if (formData === void 0) {
2362
- onChange(null);
2436
+ onChange(null, [name]);
2363
2437
  }
2364
- }, [formData, onChange]);
2438
+ }, [name, formData, onChange]);
2365
2439
  return null;
2366
2440
  }
2367
2441
  var NullField_default = NullField;
@@ -3065,25 +3139,24 @@
3065
3139
  value
3066
3140
  }) {
3067
3141
  const { translateString } = registry;
3068
- const [lastValue, setLastValue] = react.useState(value);
3069
- const [state, setState] = react.useReducer(
3070
- (state2, action) => {
3071
- return { ...state2, ...action };
3142
+ const [state, setState] = react.useState(utils.parseDateString(value, time));
3143
+ react.useEffect(() => {
3144
+ setState(utils.parseDateString(value, time));
3145
+ }, [time, value]);
3146
+ const handleChange = react.useCallback(
3147
+ (property, value2) => {
3148
+ const nextState = {
3149
+ ...state,
3150
+ [property]: typeof value2 === "undefined" ? -1 : value2
3151
+ };
3152
+ if (readyForChange(nextState)) {
3153
+ onChange(utils.toDateString(nextState, time));
3154
+ } else {
3155
+ setState(nextState);
3156
+ }
3072
3157
  },
3073
- utils.parseDateString(value, time)
3158
+ [state, onChange, time]
3074
3159
  );
3075
- react.useEffect(() => {
3076
- const stateValue = utils.toDateString(state, time);
3077
- if (readyForChange(state) && stateValue !== value) {
3078
- onChange(stateValue);
3079
- } else if (lastValue !== value) {
3080
- setLastValue(value);
3081
- setState(utils.parseDateString(value, time));
3082
- }
3083
- }, [time, value, onChange, state, lastValue]);
3084
- const handleChange = react.useCallback((property, value2) => {
3085
- setState({ [property]: value2 });
3086
- }, []);
3087
3160
  const handleSetNow = react.useCallback(
3088
3161
  (event) => {
3089
3162
  event.preventDefault();
@@ -3093,7 +3166,7 @@
3093
3166
  const nextState = utils.parseDateString((/* @__PURE__ */ new Date()).toJSON(), time);
3094
3167
  onChange(utils.toDateString(nextState, time));
3095
3168
  },
3096
- [disabled, readonly, time]
3169
+ [disabled, readonly, time, onChange]
3097
3170
  );
3098
3171
  const handleClear = react.useCallback(
3099
3172
  (event) => {
@@ -3221,11 +3294,11 @@
3221
3294
  const checkboxesValues = Array.isArray(value) ? value : [value];
3222
3295
  const handleBlur = react.useCallback(
3223
3296
  ({ target }) => onBlur(id, utils.enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3224
- [onBlur, id]
3297
+ [onBlur, id, enumOptions, emptyValue]
3225
3298
  );
3226
3299
  const handleFocus = react.useCallback(
3227
3300
  ({ target }) => onFocus(id, utils.enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3228
- [onFocus, id]
3301
+ [onFocus, id, enumOptions, emptyValue]
3229
3302
  );
3230
3303
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "checkboxes", id, children: Array.isArray(enumOptions) && enumOptions.map((option, index) => {
3231
3304
  const checked = utils.enumOptionsIsSelected(option.value, checkboxesValues);
@@ -3802,6 +3875,9 @@
3802
3875
  * provide any possible type here
3803
3876
  */
3804
3877
  formElement;
3878
+ /** The list of pending changes
3879
+ */
3880
+ pendingChanges = [];
3805
3881
  /** Constructs the `Form` from the `props`. Will setup the initial state from the props. It will also call the
3806
3882
  * `onChange` handler if the initially provided `formData` is modified to add missing default values as part of the
3807
3883
  * state construction.
@@ -4016,8 +4092,7 @@
4016
4092
  let customValidateErrors = {};
4017
4093
  if (typeof customValidate === "function") {
4018
4094
  const errorHandler = customValidate(prevFormData, utils.createErrorHandler(prevFormData), uiSchema);
4019
- const userErrorSchema = utils.unwrapErrorHandler(errorHandler);
4020
- customValidateErrors = userErrorSchema;
4095
+ customValidateErrors = utils.unwrapErrorHandler(errorHandler);
4021
4096
  }
4022
4097
  return customValidateErrors;
4023
4098
  }
@@ -4026,7 +4101,8 @@
4026
4101
  *
4027
4102
  * @param formData - The new form data to validate
4028
4103
  * @param schema - The schema used to validate against
4029
- * @param altSchemaUtils - The alternate schemaUtils to use for validation
4104
+ * @param [altSchemaUtils] - The alternate schemaUtils to use for validation
4105
+ * @param [retrievedSchema] - An optionally retrieved schema for per
4030
4106
  */
4031
4107
  validate(formData, schema = this.state.schema, altSchemaUtils, retrievedSchema) {
4032
4108
  const schemaUtils = altSchemaUtils ? altSchemaUtils : this.state.schemaUtils;
@@ -4108,10 +4184,15 @@
4108
4184
  const retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
4109
4185
  const pathSchema = schemaUtils.toPathSchema(retrievedSchema, "", formData);
4110
4186
  const fieldNames = this.getFieldNames(pathSchema, formData);
4111
- const newFormData = this.getUsedFormData(formData, fieldNames);
4112
- return newFormData;
4187
+ return this.getUsedFormData(formData, fieldNames);
4113
4188
  };
4114
- // Filtering errors based on your retrieved schema to only show errors for properties in the selected branch.
4189
+ /** Filtering errors based on your retrieved schema to only show errors for properties in the selected branch.
4190
+ *
4191
+ * @param schemaErrors - The schema errors to filter
4192
+ * @param [resolvedSchema] - An optionally resolved schema to use for performance reasons
4193
+ * @param [formData] - The formData to help filter errors
4194
+ * @private
4195
+ */
4115
4196
  filterErrorsBasedOnSchema(schemaErrors, resolvedSchema, formData) {
4116
4197
  const { retrievedSchema, schemaUtils } = this.state;
4117
4198
  const _retrievedSchema = resolvedSchema ?? retrievedSchema;
@@ -4145,22 +4226,44 @@
4145
4226
  };
4146
4227
  return filterNilOrEmptyErrors(filteredErrors, prevCustomValidateErrors);
4147
4228
  }
4148
- /** Function to handle changes made to a field in the `Form`. This handler receives an entirely new copy of the
4149
- * `formData` along with a new `ErrorSchema`. It will first update the `formData` with any missing default fields and
4150
- * then, if `omitExtraData` and `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not
4151
- * in a form field. Then, the resulting formData will be validated if required. The state will be updated with the new
4152
- * updated (potentially filtered) `formData`, any errors that resulted from validation. Finally the `onChange`
4153
- * callback will be called if specified with the updated state.
4229
+ /** Pushes the given change information into the `pendingChanges` array and then calls `processPendingChanges()` if
4230
+ * the array only contains a single pending change.
4154
4231
  *
4155
- * @param formData - The new form data from a change to a field
4156
- * @param newErrorSchema - The new `ErrorSchema` based on the field change
4157
- * @param id - The id of the field that caused the change
4232
+ * @param newValue - The new form data from a change to a field
4233
+ * @param [path] - The path to the change into which to set the formData
4234
+ * @param [newErrorSchema] - The new `ErrorSchema` based on the field change
4235
+ * @param [id] - The id of the field that caused the change
4236
+ */
4237
+ onChange = (newValue, path, newErrorSchema, id) => {
4238
+ this.pendingChanges.push({ newValue, path, newErrorSchema, id });
4239
+ if (this.pendingChanges.length === 1) {
4240
+ this.processPendingChange();
4241
+ }
4242
+ };
4243
+ /** Function to handle changes made to a field in the `Form`. This handler gets the first change from the
4244
+ * `pendingChanges` list, containing the `newValue` for the `formData` and the `path` at which the `newValue` is to be
4245
+ * updated, along with a new, optional `ErrorSchema` for that same `path` and potentially the `id` of the field being
4246
+ * changed. It will first update the `formData` with any missing default fields and then, if `omitExtraData` and
4247
+ * `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not in a form field. Then, the
4248
+ * resulting `formData` will be validated if required. The state will be updated with the new updated (potentially
4249
+ * filtered) `formData`, any errors that resulted from validation. Finally the `onChange` callback will be called, if
4250
+ * specified, with the updated state and the `processPendingChange()` function is called again.
4158
4251
  */
4159
- onChange = (formData, newErrorSchema, id) => {
4160
- const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
4161
- const { schemaUtils, schema } = this.state;
4252
+ processPendingChange() {
4253
+ if (this.pendingChanges.length === 0) {
4254
+ return;
4255
+ }
4256
+ const { newValue, path, id } = this.pendingChanges[0];
4257
+ let { newErrorSchema } = this.pendingChanges[0];
4258
+ const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange, idPrefix = "" } = this.props;
4259
+ const { formData: oldFormData, schemaUtils, schema, errorSchema } = this.state;
4260
+ const isRootPath = !path || path.length === 0 || path.length === 1 && path[0] === idPrefix;
4162
4261
  let retrievedSchema = this.state.retrievedSchema;
4262
+ let formData = isRootPath ? newValue : _cloneDeep(oldFormData);
4163
4263
  if (utils.isObject(formData) || Array.isArray(formData)) {
4264
+ if (!isRootPath) {
4265
+ set(formData, path, newValue);
4266
+ }
4164
4267
  const newState = this.getStateFromProps(this.props, formData);
4165
4268
  formData = newState.formData;
4166
4269
  retrievedSchema = newState.retrievedSchema;
@@ -4174,38 +4277,49 @@
4174
4277
  formData: newFormData
4175
4278
  };
4176
4279
  }
4280
+ if (newErrorSchema && !isRootPath) {
4281
+ const errorSchemaCopy = _cloneDeep(errorSchema);
4282
+ set(errorSchemaCopy, path, newErrorSchema);
4283
+ newErrorSchema = errorSchemaCopy;
4284
+ }
4177
4285
  if (mustValidate) {
4178
4286
  const schemaValidation = this.validate(newFormData, schema, schemaUtils, retrievedSchema);
4179
4287
  let errors = schemaValidation.errors;
4180
- let errorSchema = schemaValidation.errorSchema;
4288
+ let errorSchema2 = schemaValidation.errorSchema;
4181
4289
  const schemaValidationErrors = errors;
4182
- const schemaValidationErrorSchema = errorSchema;
4290
+ const schemaValidationErrorSchema = errorSchema2;
4183
4291
  if (extraErrors) {
4184
4292
  const merged = utils.validationDataMerge(schemaValidation, extraErrors);
4185
- errorSchema = merged.errorSchema;
4293
+ errorSchema2 = merged.errorSchema;
4186
4294
  errors = merged.errors;
4187
4295
  }
4188
4296
  if (newErrorSchema) {
4189
4297
  const filteredErrors = this.filterErrorsBasedOnSchema(newErrorSchema, retrievedSchema, newFormData);
4190
- errorSchema = utils.mergeObjects(errorSchema, filteredErrors, "preventDuplicates");
4298
+ errorSchema2 = utils.mergeObjects(errorSchema2, filteredErrors, "preventDuplicates");
4191
4299
  }
4192
4300
  state = {
4193
4301
  formData: newFormData,
4194
4302
  errors,
4195
- errorSchema,
4303
+ errorSchema: errorSchema2,
4196
4304
  schemaValidationErrors,
4197
4305
  schemaValidationErrorSchema
4198
4306
  };
4199
4307
  } else if (!noValidate && newErrorSchema) {
4200
- const errorSchema = extraErrors ? utils.mergeObjects(newErrorSchema, extraErrors, "preventDuplicates") : newErrorSchema;
4308
+ const errorSchema2 = extraErrors ? utils.mergeObjects(newErrorSchema, extraErrors, "preventDuplicates") : newErrorSchema;
4201
4309
  state = {
4202
4310
  formData: newFormData,
4203
- errorSchema,
4204
- errors: utils.toErrorList(errorSchema)
4311
+ errorSchema: errorSchema2,
4312
+ errors: utils.toErrorList(errorSchema2)
4205
4313
  };
4206
4314
  }
4207
- this.setState(state, () => onChange && onChange({ ...this.state, ...state }, id));
4208
- };
4315
+ this.setState(state, () => {
4316
+ if (onChange) {
4317
+ onChange({ ...this.state, ...state }, id);
4318
+ }
4319
+ this.pendingChanges.shift();
4320
+ this.processPendingChange();
4321
+ });
4322
+ }
4209
4323
  /**
4210
4324
  * If the retrievedSchema has changed the new retrievedSchema is returned.
4211
4325
  * Otherwise, the old retrievedSchema is returned to persist reference.
@@ -4440,7 +4554,7 @@
4440
4554
  const {
4441
4555
  children,
4442
4556
  id,
4443
- idPrefix,
4557
+ idPrefix = "",
4444
4558
  idSeparator,
4445
4559
  className = "",
4446
4560
  tagName,
@@ -4490,7 +4604,7 @@
4490
4604
  /* @__PURE__ */ jsxRuntime.jsx(
4491
4605
  _SchemaField,
4492
4606
  {
4493
- name: "",
4607
+ name: idPrefix,
4494
4608
  schema,
4495
4609
  uiSchema,
4496
4610
  errorSchema,