@rjsf/core 6.0.0-beta.2 → 6.0.0-beta.21

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 (114) hide show
  1. package/dist/core.umd.js +705 -471
  2. package/dist/{index.js → index.cjs} +1094 -844
  3. package/dist/index.cjs.map +7 -0
  4. package/dist/index.esm.js +1053 -774
  5. package/dist/index.esm.js.map +4 -4
  6. package/lib/components/Form.d.ts +88 -23
  7. package/lib/components/Form.d.ts.map +1 -1
  8. package/lib/components/Form.js +213 -151
  9. package/lib/components/fields/ArrayField.d.ts +17 -7
  10. package/lib/components/fields/ArrayField.d.ts.map +1 -1
  11. package/lib/components/fields/ArrayField.js +116 -70
  12. package/lib/components/fields/BooleanField.d.ts.map +1 -1
  13. package/lib/components/fields/BooleanField.js +7 -2
  14. package/lib/components/fields/LayoutGridField.d.ts +27 -25
  15. package/lib/components/fields/LayoutGridField.d.ts.map +1 -1
  16. package/lib/components/fields/LayoutGridField.js +83 -59
  17. package/lib/components/fields/LayoutHeaderField.d.ts +1 -1
  18. package/lib/components/fields/LayoutHeaderField.js +3 -3
  19. package/lib/components/fields/LayoutMultiSchemaField.js +6 -5
  20. package/lib/components/fields/MultiSchemaField.d.ts.map +1 -1
  21. package/lib/components/fields/MultiSchemaField.js +13 -9
  22. package/lib/components/fields/NullField.js +3 -3
  23. package/lib/components/fields/NumberField.d.ts.map +1 -1
  24. package/lib/components/fields/NumberField.js +3 -3
  25. package/lib/components/fields/ObjectField.d.ts +3 -3
  26. package/lib/components/fields/ObjectField.d.ts.map +1 -1
  27. package/lib/components/fields/ObjectField.js +34 -34
  28. package/lib/components/fields/OptionalDataControlsField.d.ts +8 -0
  29. package/lib/components/fields/OptionalDataControlsField.d.ts.map +1 -0
  30. package/lib/components/fields/OptionalDataControlsField.js +43 -0
  31. package/lib/components/fields/SchemaField.d.ts.map +1 -1
  32. package/lib/components/fields/SchemaField.js +17 -17
  33. package/lib/components/fields/StringField.d.ts.map +1 -1
  34. package/lib/components/fields/StringField.js +7 -2
  35. package/lib/components/fields/index.d.ts.map +1 -1
  36. package/lib/components/fields/index.js +2 -0
  37. package/lib/components/templates/ArrayFieldDescriptionTemplate.d.ts +1 -1
  38. package/lib/components/templates/ArrayFieldDescriptionTemplate.js +3 -3
  39. package/lib/components/templates/ArrayFieldItemButtonsTemplate.js +2 -2
  40. package/lib/components/templates/ArrayFieldTemplate.d.ts.map +1 -1
  41. package/lib/components/templates/ArrayFieldTemplate.js +4 -3
  42. package/lib/components/templates/ArrayFieldTitleTemplate.d.ts +1 -1
  43. package/lib/components/templates/ArrayFieldTitleTemplate.d.ts.map +1 -1
  44. package/lib/components/templates/ArrayFieldTitleTemplate.js +3 -3
  45. package/lib/components/templates/ButtonTemplates/AddButton.d.ts +1 -1
  46. package/lib/components/templates/ButtonTemplates/AddButton.d.ts.map +1 -1
  47. package/lib/components/templates/ButtonTemplates/AddButton.js +2 -2
  48. package/lib/components/templates/FieldErrorTemplate.js +2 -2
  49. package/lib/components/templates/FieldHelpTemplate.js +2 -2
  50. package/lib/components/templates/MultiSchemaFieldTemplate.d.ts +8 -0
  51. package/lib/components/templates/MultiSchemaFieldTemplate.d.ts.map +1 -0
  52. package/lib/components/templates/MultiSchemaFieldTemplate.js +10 -0
  53. package/lib/components/templates/ObjectFieldTemplate.d.ts.map +1 -1
  54. package/lib/components/templates/ObjectFieldTemplate.js +3 -2
  55. package/lib/components/templates/OptionalDataControlsTemplate.d.ts +11 -0
  56. package/lib/components/templates/OptionalDataControlsTemplate.d.ts.map +1 -0
  57. package/lib/components/templates/OptionalDataControlsTemplate.js +20 -0
  58. package/lib/components/templates/TitleField.d.ts.map +1 -1
  59. package/lib/components/templates/TitleField.js +2 -2
  60. package/lib/components/templates/UnsupportedField.js +3 -3
  61. package/lib/components/templates/index.d.ts.map +1 -1
  62. package/lib/components/templates/index.js +4 -0
  63. package/lib/components/widgets/AltDateWidget.d.ts.map +1 -1
  64. package/lib/components/widgets/AltDateWidget.js +15 -18
  65. package/lib/components/widgets/CheckboxesWidget.js +2 -2
  66. package/lib/getDefaultRegistry.d.ts.map +1 -1
  67. package/lib/getDefaultRegistry.js +2 -1
  68. package/lib/getTestRegistry.d.ts +5 -0
  69. package/lib/getTestRegistry.d.ts.map +1 -0
  70. package/lib/getTestRegistry.js +19 -0
  71. package/lib/index.d.ts +2 -1
  72. package/lib/index.d.ts.map +1 -1
  73. package/lib/index.js +2 -1
  74. package/lib/tsconfig.tsbuildinfo +1 -1
  75. package/package.json +18 -19
  76. package/src/components/Form.tsx +306 -177
  77. package/src/components/fields/ArrayField.tsx +127 -80
  78. package/src/components/fields/BooleanField.tsx +12 -3
  79. package/src/components/fields/LayoutGridField.tsx +95 -88
  80. package/src/components/fields/LayoutHeaderField.tsx +3 -3
  81. package/src/components/fields/LayoutMultiSchemaField.tsx +5 -5
  82. package/src/components/fields/MultiSchemaField.tsx +51 -35
  83. package/src/components/fields/NullField.tsx +3 -3
  84. package/src/components/fields/NumberField.tsx +11 -3
  85. package/src/components/fields/ObjectField.tsx +47 -53
  86. package/src/components/fields/OptionalDataControlsField.tsx +84 -0
  87. package/src/components/fields/SchemaField.tsx +24 -30
  88. package/src/components/fields/StringField.tsx +12 -3
  89. package/src/components/fields/index.ts +2 -0
  90. package/src/components/templates/ArrayFieldDescriptionTemplate.tsx +3 -3
  91. package/src/components/templates/ArrayFieldItemButtonsTemplate.tsx +5 -5
  92. package/src/components/templates/ArrayFieldTemplate.tsx +9 -5
  93. package/src/components/templates/ArrayFieldTitleTemplate.tsx +4 -3
  94. package/src/components/templates/BaseInputTemplate.tsx +3 -3
  95. package/src/components/templates/ButtonTemplates/AddButton.tsx +2 -0
  96. package/src/components/templates/FieldErrorTemplate.tsx +2 -2
  97. package/src/components/templates/FieldHelpTemplate.tsx +2 -2
  98. package/src/components/templates/MultiSchemaFieldTemplate.tsx +20 -0
  99. package/src/components/templates/ObjectFieldTemplate.tsx +10 -5
  100. package/src/components/templates/OptionalDataControlsTemplate.tsx +43 -0
  101. package/src/components/templates/TitleField.tsx +6 -1
  102. package/src/components/templates/UnsupportedField.tsx +3 -3
  103. package/src/components/templates/WrapIfAdditionalTemplate.tsx +1 -1
  104. package/src/components/templates/index.ts +4 -0
  105. package/src/components/widgets/AltDateWidget.tsx +21 -23
  106. package/src/components/widgets/CheckboxWidget.tsx +2 -2
  107. package/src/components/widgets/CheckboxesWidget.tsx +3 -3
  108. package/src/components/widgets/RadioWidget.tsx +1 -1
  109. package/src/components/widgets/SelectWidget.tsx +1 -1
  110. package/src/components/widgets/TextareaWidget.tsx +1 -1
  111. package/src/getDefaultRegistry.ts +10 -1
  112. package/src/getTestRegistry.tsx +34 -0
  113. package/src/index.ts +2 -1
  114. package/dist/index.js.map +0 -7
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/get'), require('lodash/isEmpty'), 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'), require('@rjsf/validator-ajv8')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'react', '@rjsf/utils', 'lodash/cloneDeep', 'lodash/get', 'lodash/isEmpty', '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', '@rjsf/validator-ajv8'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.JSONSchemaForm = {}, global.react, global.utils, global.cloneDeep, global.get2, global.isEmpty, 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, global.validator));
5
+ })(this, (function (exports, react, utils, cloneDeep, get2, isEmpty, _pick, set, _toPath, isObject, uniqueId, jsxRuntime, each, flatten, has, includes, intersection, isFunction, isEqual, isPlainObject, isString, isUndefined, last, noop, omit3, Markdown, unset, validator) { '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) => {
@@ -29,7 +29,7 @@
29
29
  */
30
30
  constructor(props) {
31
31
  super(props);
32
- const { formData = [] } = props;
32
+ const { formData } = props;
33
33
  const keyedFormData = generateKeyedFormData(formData);
34
34
  this.state = {
35
35
  keyedFormData,
@@ -126,7 +126,7 @@
126
126
  if (event) {
127
127
  event.preventDefault();
128
128
  }
129
- const { onChange, errorSchema } = this.props;
129
+ const { onChange, errorSchema, fieldPathId } = this.props;
130
130
  const { keyedFormData } = this.state;
131
131
  let newErrorSchema;
132
132
  if (errorSchema) {
@@ -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), fieldPathId.path, 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
@@ -189,7 +190,7 @@
189
190
  if (event) {
190
191
  event.preventDefault();
191
192
  }
192
- const { onChange, errorSchema } = this.props;
193
+ const { onChange, errorSchema, fieldPathId } = this.props;
193
194
  const { keyedFormData } = this.state;
194
195
  let newErrorSchema;
195
196
  if (errorSchema) {
@@ -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,7 @@
218
219
  keyedFormData: newKeyedFormData,
219
220
  updatedKeyedFormData: true
220
221
  },
221
- () => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema)
222
+ () => onChange(keyedToPlainFormData(newKeyedFormData), fieldPathId.path, newErrorSchema)
222
223
  );
223
224
  };
224
225
  };
@@ -233,7 +234,7 @@
233
234
  if (event) {
234
235
  event.preventDefault();
235
236
  }
236
- const { onChange, errorSchema } = this.props;
237
+ const { onChange, errorSchema, fieldPathId } = this.props;
237
238
  const { keyedFormData } = this.state;
238
239
  let newErrorSchema;
239
240
  if (errorSchema) {
@@ -253,7 +254,7 @@
253
254
  keyedFormData: newKeyedFormData,
254
255
  updatedKeyedFormData: true
255
256
  },
256
- () => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema)
257
+ () => onChange(keyedToPlainFormData(newKeyedFormData), fieldPathId.path, newErrorSchema)
257
258
  );
258
259
  };
259
260
  };
@@ -270,7 +271,7 @@
270
271
  event.preventDefault();
271
272
  event.currentTarget.blur();
272
273
  }
273
- const { onChange, errorSchema } = this.props;
274
+ const { onChange, errorSchema, fieldPathId } = this.props;
274
275
  let newErrorSchema;
275
276
  if (errorSchema) {
276
277
  newErrorSchema = {};
@@ -297,7 +298,7 @@
297
298
  {
298
299
  keyedFormData: newKeyedFormData
299
300
  },
300
- () => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema)
301
+ () => onChange(keyedToPlainFormData(newKeyedFormData), fieldPathId.path, newErrorSchema)
301
302
  );
302
303
  };
303
304
  };
@@ -307,32 +308,49 @@
307
308
  * @param index - The index of the item being changed
308
309
  */
309
310
  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
- });
311
+ return (value, path, newErrorSchema, id) => {
312
+ const { onChange } = this.props;
317
313
  onChange(
318
- newFormData,
319
- errorSchema && errorSchema && {
320
- ...errorSchema,
321
- [index]: newErrorSchema
322
- },
314
+ // We need to treat undefined items as nulls to have validation.
315
+ // See https://github.com/tdegrunt/jsonschema/issues/206
316
+ value === void 0 ? null : value,
317
+ path,
318
+ newErrorSchema,
323
319
  id
324
320
  );
325
321
  };
326
322
  };
327
323
  /** Callback handler used to change the value for a checkbox */
328
324
  onSelectChange = (value) => {
329
- const { onChange, idSchema } = this.props;
330
- onChange(value, void 0, idSchema && idSchema.$id);
325
+ const { onChange, fieldPathId } = this.props;
326
+ onChange(value, fieldPathId.path, void 0, fieldPathId && fieldPathId.$id);
331
327
  };
328
+ /** Helper method to compute item UI schema for both normal and fixed arrays
329
+ * Handles both static object and dynamic function cases
330
+ *
331
+ * @param uiSchema - The parent UI schema containing items definition
332
+ * @param item - The item data
333
+ * @param index - The index of the item
334
+ * @param formContext - The form context
335
+ * @returns The computed UI schema for the item
336
+ */
337
+ computeItemUiSchema(uiSchema, item, index, formContext) {
338
+ if (typeof uiSchema.items === "function") {
339
+ try {
340
+ const result = uiSchema.items(item, index, formContext);
341
+ return result;
342
+ } catch (e) {
343
+ console.error(`Error executing dynamic uiSchema.items function for item at index ${index}:`, e);
344
+ return void 0;
345
+ }
346
+ } else {
347
+ return uiSchema.items;
348
+ }
349
+ }
332
350
  /** Renders the `ArrayField` depending on the specific needs of the schema and uischema elements
333
351
  */
334
352
  render() {
335
- const { schema, uiSchema, idSchema, registry } = this.props;
353
+ const { schema, uiSchema, fieldPathId, registry } = this.props;
336
354
  const { schemaUtils, translateString } = registry;
337
355
  if (!(utils.ITEMS_KEY in schema)) {
338
356
  const uiOptions = utils.getUiOptions(uiSchema);
@@ -345,7 +363,7 @@
345
363
  UnsupportedFieldTemplate,
346
364
  {
347
365
  schema,
348
- idSchema,
366
+ fieldPathId,
349
367
  reason: translateString(utils.TranslatableString.MissingItems),
350
368
  registry
351
369
  }
@@ -372,7 +390,7 @@
372
390
  schema,
373
391
  uiSchema = {},
374
392
  errorSchema,
375
- idSchema,
393
+ fieldPathId,
376
394
  name,
377
395
  title,
378
396
  disabled = false,
@@ -382,27 +400,31 @@
382
400
  registry,
383
401
  onBlur,
384
402
  onFocus,
385
- idPrefix,
386
- idSeparator = "_",
387
403
  rawErrors
388
404
  } = this.props;
389
405
  const { keyedFormData } = this.state;
390
406
  const fieldTitle = schema.title || title || name;
391
- const { schemaUtils, formContext } = registry;
407
+ const { schemaUtils, fields: fields2, formContext, globalFormOptions } = registry;
408
+ const { OptionalDataControlsField: OptionalDataControlsField2 } = fields2;
392
409
  const uiOptions = utils.getUiOptions(uiSchema);
393
410
  const _schemaItems = isObject(schema.items) ? schema.items : {};
394
411
  const itemsSchema = schemaUtils.retrieveSchema(_schemaItems);
395
412
  const formData = keyedToPlainFormData(this.state.keyedFormData);
396
- const canAdd = this.canAddItem(formData);
413
+ const renderOptionalField = utils.shouldRenderOptionalField(registry, schema, required, uiSchema);
414
+ const hasFormData = utils.isFormDataAvailable(this.props.formData);
415
+ const canAdd = this.canAddItem(formData) && (!renderOptionalField || hasFormData);
416
+ const actualFormData = hasFormData ? keyedFormData : [];
417
+ const extraClass = renderOptionalField ? " rjsf-optional-array-field" : "";
418
+ const optionalDataControl = renderOptionalField ? /* @__PURE__ */ jsxRuntime.jsx(OptionalDataControlsField2, { ...this.props }) : void 0;
397
419
  const arrayProps = {
398
420
  canAdd,
399
- items: keyedFormData.map((keyedItem, index) => {
421
+ items: actualFormData.map((keyedItem, index) => {
400
422
  const { key, item } = keyedItem;
401
423
  const itemCast = item;
402
424
  const itemSchema = schemaUtils.retrieveSchema(_schemaItems, itemCast);
403
425
  const itemErrorSchema = errorSchema ? errorSchema[index] : void 0;
404
- const itemIdPrefix = idSchema.$id + idSeparator + index;
405
- const itemIdSchema = schemaUtils.toIdSchema(itemSchema, itemIdPrefix, itemCast, idPrefix, idSeparator);
426
+ const itemFieldPathId = utils.toFieldPathId(index, globalFormOptions, fieldPathId);
427
+ const itemUiSchema = this.computeItemUiSchema(uiSchema, item, index, formContext);
406
428
  return this.renderArrayFieldItem({
407
429
  key,
408
430
  index,
@@ -412,10 +434,10 @@
412
434
  canMoveUp: index > 0,
413
435
  canMoveDown: index < formData.length - 1,
414
436
  itemSchema,
415
- itemIdSchema,
437
+ itemFieldPathId,
416
438
  itemErrorSchema,
417
439
  itemData: itemCast,
418
- itemUiSchema: uiSchema.items,
440
+ itemUiSchema,
419
441
  autofocus: autofocus && index === 0,
420
442
  onBlur,
421
443
  onFocus,
@@ -423,19 +445,19 @@
423
445
  totalItems: keyedFormData.length
424
446
  });
425
447
  }),
426
- className: `rjsf-field rjsf-field-array rjsf-field-array-of-${itemsSchema.type}`,
448
+ className: `rjsf-field rjsf-field-array rjsf-field-array-of-${itemsSchema.type}${extraClass}`,
427
449
  disabled,
428
- idSchema,
450
+ fieldPathId,
429
451
  uiSchema,
430
452
  onAddClick: this.onAddClick,
431
453
  readonly,
432
454
  required,
433
455
  schema,
434
456
  title: fieldTitle,
435
- formContext,
436
457
  formData,
437
458
  rawErrors,
438
- registry
459
+ registry,
460
+ optionalDataControl
439
461
  };
440
462
  const Template = utils.getTemplate("ArrayFieldTemplate", registry, uiOptions);
441
463
  return /* @__PURE__ */ jsxRuntime.jsx(Template, { ...arrayProps });
@@ -445,7 +467,7 @@
445
467
  renderCustomWidget() {
446
468
  const {
447
469
  schema,
448
- idSchema,
470
+ fieldPathId,
449
471
  uiSchema,
450
472
  disabled = false,
451
473
  readonly = false,
@@ -468,7 +490,7 @@
468
490
  return /* @__PURE__ */ jsxRuntime.jsx(
469
491
  Widget,
470
492
  {
471
- id: idSchema.$id,
493
+ id: fieldPathId.$id,
472
494
  name,
473
495
  multiple: true,
474
496
  onChange: this.onSelectChange,
@@ -497,7 +519,7 @@
497
519
  renderMultiSelect() {
498
520
  const {
499
521
  schema,
500
- idSchema,
522
+ fieldPathId,
501
523
  uiSchema,
502
524
  formData: items = [],
503
525
  disabled = false,
@@ -521,7 +543,7 @@
521
543
  return /* @__PURE__ */ jsxRuntime.jsx(
522
544
  Widget,
523
545
  {
524
- id: idSchema.$id,
546
+ id: fieldPathId.$id,
525
547
  name,
526
548
  multiple: true,
527
549
  onChange: this.onSelectChange,
@@ -550,7 +572,7 @@
550
572
  const {
551
573
  schema,
552
574
  uiSchema,
553
- idSchema,
575
+ fieldPathId,
554
576
  name,
555
577
  disabled = false,
556
578
  readonly = false,
@@ -571,7 +593,7 @@
571
593
  Widget,
572
594
  {
573
595
  options,
574
- id: idSchema.$id,
596
+ id: fieldPathId.$id,
575
597
  name,
576
598
  multiple: true,
577
599
  onChange: this.onSelectChange,
@@ -598,11 +620,9 @@
598
620
  const {
599
621
  schema,
600
622
  uiSchema = {},
601
- formData = [],
623
+ formData,
602
624
  errorSchema,
603
- idPrefix,
604
- idSeparator = "_",
605
- idSchema,
625
+ fieldPathId,
606
626
  name,
607
627
  title,
608
628
  disabled = false,
@@ -614,35 +634,48 @@
614
634
  onFocus,
615
635
  rawErrors
616
636
  } = this.props;
617
- const { keyedFormData } = this.state;
618
637
  let { formData: items = [] } = this.props;
638
+ const { keyedFormData } = this.state;
619
639
  const fieldTitle = schema.title || title || name;
620
640
  const uiOptions = utils.getUiOptions(uiSchema);
621
- const { schemaUtils, formContext } = registry;
641
+ const { schemaUtils, fields: fields2, formContext, globalFormOptions } = registry;
642
+ const { OptionalDataControlsField: OptionalDataControlsField2 } = fields2;
643
+ const renderOptionalField = utils.shouldRenderOptionalField(registry, schema, required, uiSchema);
644
+ const hasFormData = utils.isFormDataAvailable(formData);
622
645
  const _schemaItems = isObject(schema.items) ? schema.items : [];
623
646
  const itemSchemas = _schemaItems.map(
624
- (item, index) => schemaUtils.retrieveSchema(item, formData[index])
647
+ (item, index) => schemaUtils.retrieveSchema(item, items[index])
625
648
  );
626
649
  const additionalSchema = isObject(schema.additionalItems) ? schemaUtils.retrieveSchema(schema.additionalItems, formData) : null;
627
- if (!items || items.length < itemSchemas.length) {
628
- items = items || [];
650
+ if (items.length < itemSchemas.length) {
629
651
  items = items.concat(new Array(itemSchemas.length - items.length));
630
652
  }
631
- const canAdd = this.canAddItem(items) && !!additionalSchema;
653
+ const actualFormData = hasFormData ? keyedFormData : [];
654
+ const extraClass = renderOptionalField ? " rjsf-optional-array-field" : "";
655
+ const optionalDataControl = renderOptionalField ? /* @__PURE__ */ jsxRuntime.jsx(OptionalDataControlsField2, { ...this.props }) : void 0;
656
+ const canAdd = this.canAddItem(items) && !!additionalSchema && (!renderOptionalField || hasFormData);
632
657
  const arrayProps = {
633
658
  canAdd,
634
- className: "rjsf-field rjsf-field-array rjsf-field-array-fixed-items",
659
+ className: `rjsf-field rjsf-field-array rjsf-field-array-fixed-items${extraClass}`,
635
660
  disabled,
636
- idSchema,
661
+ fieldPathId,
637
662
  formData,
638
- items: keyedFormData.map((keyedItem, index) => {
663
+ items: actualFormData.map((keyedItem, index) => {
639
664
  const { key, item } = keyedItem;
640
665
  const itemCast = item;
641
666
  const additional = index >= itemSchemas.length;
642
667
  const itemSchema = (additional && isObject(schema.additionalItems) ? schemaUtils.retrieveSchema(schema.additionalItems, itemCast) : itemSchemas[index]) || {};
643
- const itemIdPrefix = idSchema.$id + idSeparator + index;
644
- const itemIdSchema = schemaUtils.toIdSchema(itemSchema, itemIdPrefix, itemCast, idPrefix, idSeparator);
645
- const itemUiSchema = additional ? uiSchema.additionalItems || {} : Array.isArray(uiSchema.items) ? uiSchema.items[index] : uiSchema.items || {};
668
+ const itemFieldPathId = utils.toFieldPathId(index, globalFormOptions, fieldPathId);
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,
@@ -656,7 +689,7 @@
656
689
  itemSchema,
657
690
  itemData: itemCast,
658
691
  itemUiSchema,
659
- itemIdSchema,
692
+ itemFieldPathId,
660
693
  itemErrorSchema,
661
694
  autofocus: autofocus && index === 0,
662
695
  onBlur,
@@ -672,9 +705,9 @@
672
705
  schema,
673
706
  uiSchema,
674
707
  title: fieldTitle,
675
- formContext,
676
708
  errorSchema,
677
- rawErrors
709
+ rawErrors,
710
+ optionalDataControl
678
711
  };
679
712
  const Template = utils.getTemplate("ArrayFieldTemplate", registry, uiOptions);
680
713
  return /* @__PURE__ */ jsxRuntime.jsx(Template, { ...arrayProps });
@@ -696,7 +729,7 @@
696
729
  itemSchema,
697
730
  itemData,
698
731
  itemUiSchema,
699
- itemIdSchema,
732
+ itemFieldPathId,
700
733
  itemErrorSchema,
701
734
  autofocus,
702
735
  onBlur,
@@ -705,7 +738,7 @@
705
738
  totalItems,
706
739
  title
707
740
  } = props;
708
- const { disabled, hideError, idPrefix, idSeparator, readonly, uiSchema, registry, formContext } = this.props;
741
+ const { disabled, hideError, readonly, uiSchema, registry, formContext } = this.props;
709
742
  const {
710
743
  fields: { ArraySchemaField, SchemaField: SchemaField2 },
711
744
  globalUiOptions
@@ -732,9 +765,7 @@
732
765
  formData: itemData,
733
766
  formContext,
734
767
  errorSchema: itemErrorSchema,
735
- idPrefix,
736
- idSeparator,
737
- idSchema: itemIdSchema,
768
+ fieldPathId: itemFieldPathId,
738
769
  required: this.isItemRequired(itemSchema),
739
770
  onChange: this.onChangeForIndex(index),
740
771
  onBlur,
@@ -748,7 +779,7 @@
748
779
  }
749
780
  ),
750
781
  buttonsProps: {
751
- idSchema: itemIdSchema,
782
+ fieldPathId: itemFieldPathId,
752
783
  disabled,
753
784
  readonly,
754
785
  canAdd,
@@ -785,7 +816,7 @@
785
816
  schema,
786
817
  name,
787
818
  uiSchema,
788
- idSchema,
819
+ fieldPathId,
789
820
  formData,
790
821
  registry,
791
822
  required,
@@ -847,15 +878,21 @@
847
878
  enumOptions = utils.optionsList({ enum: enums }, uiSchema);
848
879
  }
849
880
  }
881
+ const onWidgetChange = react.useCallback(
882
+ (value, errorSchema, id) => {
883
+ return onChange(value, fieldPathId.path, errorSchema, id);
884
+ },
885
+ [onChange, fieldPathId]
886
+ );
850
887
  return /* @__PURE__ */ jsxRuntime.jsx(
851
888
  Widget,
852
889
  {
853
890
  options: { ...options, enumOptions },
854
891
  schema,
855
892
  uiSchema,
856
- id: idSchema.$id,
893
+ id: fieldPathId.$id,
857
894
  name,
858
- onChange,
895
+ onChange: onWidgetChange,
859
896
  onFocus,
860
897
  onBlur,
861
898
  label,
@@ -875,10 +912,12 @@
875
912
  var BooleanField_default = BooleanField;
876
913
  var LOOKUP_REGEX = /^\$lookup=(.+)/;
877
914
  var LAYOUT_GRID_UI_OPTION = "layoutGrid";
878
- var UI_GLOBAL_OPTIONS = "ui:global_options";
879
915
  function getNonNullishValue(value, fallback) {
880
916
  return value ?? fallback;
881
917
  }
918
+ function isNumericIndex(str) {
919
+ return /^\d+?$/.test(str);
920
+ }
882
921
  var LayoutGridField = class _LayoutGridField extends react.PureComponent {
883
922
  static defaultProps = {
884
923
  layoutGridSchema: void 0
@@ -898,7 +937,7 @@
898
937
  * @param [forceReadonly] - Optional flag indicating whether the Form itself is in readonly mode
899
938
  */
900
939
  static computeFieldUiSchema(field, uiProps, uiSchema, schemaReadonly, forceReadonly) {
901
- const globalUiOptions = get2(uiSchema, [UI_GLOBAL_OPTIONS], {});
940
+ const globalUiOptions = get2(uiSchema, [utils.UI_GLOBAL_OPTIONS_KEY], {});
902
941
  const localUiSchema = get2(uiSchema, field);
903
942
  const localUiOptions = { ...get2(localUiSchema, [utils.UI_OPTIONS_KEY], {}), ...uiProps, ...globalUiOptions };
904
943
  const fieldUiSchema = { ...localUiSchema };
@@ -906,7 +945,7 @@
906
945
  set(fieldUiSchema, [utils.UI_OPTIONS_KEY], localUiOptions);
907
946
  }
908
947
  if (!isEmpty(globalUiOptions)) {
909
- set(fieldUiSchema, [UI_GLOBAL_OPTIONS], globalUiOptions);
948
+ set(fieldUiSchema, [utils.UI_GLOBAL_OPTIONS_KEY], globalUiOptions);
910
949
  }
911
950
  let { readonly: uiReadonly } = utils.getUiOptions(fieldUiSchema);
912
951
  if (forceReadonly === true || isUndefined(uiReadonly) && schemaReadonly === true) {
@@ -978,60 +1017,74 @@
978
1017
  }
979
1018
  return { children, gridProps };
980
1019
  }
981
- /** Generates an idSchema for the `schema` using `@rjsf`'s `toIdSchema` util, passing the `baseIdSchema`'s `$id` value
982
- * as the id prefix.
1020
+ /** Computes the `rawSchema` and `fieldPathId` for a `schema` and a `potentialIndex`. If the `schema` is of type array,
1021
+ * has an `ITEMS_KEY` element and `potentialIndex` represents a numeric value, the element at `ITEMS_KEY` is checked
1022
+ * to see if it is an array. If it is AND the `potentialIndex`th element is available, it is used as the `rawSchema`,
1023
+ * otherwise the last value of the element is used. If it is not, then the element is used as the `rawSchema`. In
1024
+ * either case, an `fieldPathId` is computed for the array index. If the `schema` does not represent an array or the
1025
+ * `potentialIndex` is not a numeric value, then `rawSchema` is returned as undefined and given `fieldPathId` is returned
1026
+ * as is.
983
1027
  *
984
- * @param schemaUtils - The `SchemaUtilsType` used to call `toIdSchema`
985
- * @param schema - The schema to generate the idSchema for
986
- * @param baseIdSchema - The IdSchema for the base
987
- * @param formData - The formData to pass the `toIdSchema`
988
- * @param [idSeparator] - The param to pass into the `toIdSchema` util which will use it to join the `idSchema` paths
989
- * @returns - The generated `idSchema` for the `schema`
1028
+ * @param schema - The schema to generate the fieldPathId for
1029
+ * @param fieldPathId - The FieldPathId for the schema
1030
+ * @param potentialIndex - A string containing a potential index
1031
+ * @returns - An object containing the `rawSchema` and `fieldPathId` of an array item, otherwise an undefined `rawSchema`
990
1032
  */
991
- static getIdSchema(schemaUtils, baseIdSchema, formData, schema = {}, idSeparator) {
992
- const baseId = get2(baseIdSchema, utils.ID_KEY);
993
- return schemaUtils.toIdSchema(schema, baseId, formData, baseId, idSeparator);
1033
+ static computeArraySchemasIfPresent(schema, fieldPathId, potentialIndex) {
1034
+ let rawSchema;
1035
+ if (isNumericIndex(potentialIndex) && schema && schema?.type === "array" && has(schema, utils.ITEMS_KEY)) {
1036
+ const index = Number(potentialIndex);
1037
+ const items = schema[utils.ITEMS_KEY];
1038
+ if (Array.isArray(items)) {
1039
+ if (index > items.length) {
1040
+ rawSchema = last(items);
1041
+ } else {
1042
+ rawSchema = items[index];
1043
+ }
1044
+ } else {
1045
+ rawSchema = items;
1046
+ }
1047
+ fieldPathId = {
1048
+ [utils.ID_KEY]: fieldPathId[utils.ID_KEY],
1049
+ path: [...fieldPathId.path.slice(0, fieldPathId.path.length - 1), index]
1050
+ };
1051
+ }
1052
+ return { rawSchema, fieldPathId };
994
1053
  }
995
1054
  /** Given a `dottedPath` to a field in the `initialSchema`, iterate through each individual path in the schema until
996
1055
  * the leaf path is found and returned (along with whether that leaf path `isRequired`) OR no schema exists for an
997
1056
  * element in the path. If the leaf schema element happens to be a oneOf/anyOf then also return the oneOf/anyOf as
998
1057
  * `options`.
999
1058
  *
1000
- * @param schemaUtils - The `SchemaUtilsType` used to call `retrieveSchema`
1059
+ * @param registry - The registry
1001
1060
  * @param dottedPath - The dotted-path to the field for which to get the schema
1002
1061
  * @param initialSchema - The initial schema to start the search from
1003
1062
  * @param formData - The formData, useful for resolving a oneOf/anyOf selection in the path hierarchy
1004
- * @param initialIdSchema - The initial idSchema to start the search from
1005
- * @param [idSeparator] - The param to pass into the `toIdSchema` util which will use it to join the `idSchema` paths
1063
+ * @param initialFieldIdPath - The initial fieldPathId to start the search from
1006
1064
  * @returns - An object containing the destination schema, isRequired and isReadonly flags for the field and options
1007
1065
  * info if a oneOf/anyOf
1008
1066
  */
1009
- static getSchemaDetailsForField(schemaUtils, dottedPath, initialSchema, formData, initialIdSchema, idSeparator) {
1067
+ static getSchemaDetailsForField(registry, dottedPath, initialSchema, formData, initialFieldIdPath) {
1068
+ const { schemaUtils, globalFormOptions } = registry;
1010
1069
  let rawSchema = initialSchema;
1011
- let idSchema = initialIdSchema;
1070
+ let fieldPathId = initialFieldIdPath;
1012
1071
  const parts = dottedPath.split(".");
1013
1072
  const leafPath = parts.pop();
1014
1073
  let schema = schemaUtils.retrieveSchema(rawSchema, formData);
1015
1074
  let innerData = formData;
1016
1075
  let isReadonly = schema.readOnly;
1017
1076
  parts.forEach((part) => {
1077
+ fieldPathId = utils.toFieldPathId(part, globalFormOptions, fieldPathId);
1018
1078
  if (has(schema, utils.PROPERTIES_KEY)) {
1019
1079
  rawSchema = get2(schema, [utils.PROPERTIES_KEY, part], {});
1020
- idSchema = get2(idSchema, part, {});
1021
1080
  } else if (schema && (has(schema, utils.ONE_OF_KEY) || has(schema, utils.ANY_OF_KEY))) {
1022
1081
  const xxx = has(schema, utils.ONE_OF_KEY) ? utils.ONE_OF_KEY : utils.ANY_OF_KEY;
1023
1082
  const selectedSchema = schemaUtils.findSelectedOptionInXxxOf(schema, part, xxx, innerData);
1024
- const selectedIdSchema = _LayoutGridField.getIdSchema(
1025
- schemaUtils,
1026
- idSchema,
1027
- formData,
1028
- selectedSchema,
1029
- idSeparator
1030
- );
1031
1083
  rawSchema = get2(selectedSchema, [utils.PROPERTIES_KEY, part], {});
1032
- idSchema = get2(selectedIdSchema, part, {});
1033
1084
  } else {
1034
- rawSchema = {};
1085
+ const result = _LayoutGridField.computeArraySchemasIfPresent(schema, fieldPathId, part);
1086
+ rawSchema = result.rawSchema ?? {};
1087
+ fieldPathId = result.fieldPathId;
1035
1088
  }
1036
1089
  innerData = get2(innerData, part, {});
1037
1090
  schema = schemaUtils.retrieveSchema(rawSchema, innerData);
@@ -1046,13 +1099,17 @@
1046
1099
  if (schema && (has(schema, utils.ONE_OF_KEY) || has(schema, utils.ANY_OF_KEY))) {
1047
1100
  const xxx = has(schema, utils.ONE_OF_KEY) ? utils.ONE_OF_KEY : utils.ANY_OF_KEY;
1048
1101
  schema = schemaUtils.findSelectedOptionInXxxOf(schema, leafPath, xxx, innerData);
1049
- const rawIdSchema = _LayoutGridField.getIdSchema(schemaUtils, idSchema, formData, schema, idSeparator);
1050
- idSchema = utils.mergeObjects(rawIdSchema, idSchema);
1051
1102
  }
1103
+ fieldPathId = utils.toFieldPathId(leafPath, globalFormOptions, fieldPathId);
1052
1104
  isRequired = schema !== void 0 && Array.isArray(schema.required) && includes(schema.required, leafPath);
1053
- schema = get2(schema, [utils.PROPERTIES_KEY, leafPath]);
1054
- schema = schema ? schemaUtils.retrieveSchema(schema) : schema;
1055
- idSchema = get2(idSchema, leafPath, {});
1105
+ const result = _LayoutGridField.computeArraySchemasIfPresent(schema, fieldPathId, leafPath);
1106
+ if (result.rawSchema) {
1107
+ schema = result.rawSchema;
1108
+ fieldPathId = result.fieldPathId;
1109
+ } else {
1110
+ schema = get2(schema, [utils.PROPERTIES_KEY, leafPath]);
1111
+ schema = schema ? schemaUtils.retrieveSchema(schema) : schema;
1112
+ }
1056
1113
  isReadonly = getNonNullishValue(schema?.readOnly, isReadonly);
1057
1114
  if (schema && (has(schema, utils.ONE_OF_KEY) || has(schema, utils.ANY_OF_KEY))) {
1058
1115
  const xxx = has(schema, utils.ONE_OF_KEY) ? utils.ONE_OF_KEY : utils.ANY_OF_KEY;
@@ -1060,7 +1117,7 @@
1060
1117
  optionsInfo = { options: schema[xxx], hasDiscriminator: !!discriminator };
1061
1118
  }
1062
1119
  }
1063
- return { schema, isRequired, isReadonly, optionsInfo, idSchema };
1120
+ return { schema, isRequired, isReadonly, optionsInfo, fieldPathId };
1064
1121
  }
1065
1122
  /** Gets the custom render component from the `render`, by either determining that it is either already a function or
1066
1123
  * it is a non-function value that can be used to look up the function in the registry. If no function can be found,
@@ -1096,7 +1153,7 @@
1096
1153
  if (isString(gridSchema) || isUndefined(gridSchema)) {
1097
1154
  name = gridSchema ?? "";
1098
1155
  } else {
1099
- const { name: innerName, render, ...innerProps } = gridSchema;
1156
+ const { name: innerName = "", render, ...innerProps } = gridSchema;
1100
1157
  name = innerName;
1101
1158
  uiProps = innerProps;
1102
1159
  if (!isEmpty(uiProps)) {
@@ -1129,19 +1186,12 @@
1129
1186
  * elements, they will then be passed on to the `onChange` handler of the `LayoutFieldGrid`.
1130
1187
  *
1131
1188
  * @param dottedPath - The dotted-path to the field for which to generate the onChange handler
1132
- * @returns - The `onChange` handling function for the `dottedPath` field
1189
+ * @returns - The `onChange` handling function for the `dottedPath` field of the `schemaType` type
1133
1190
  */
1134
1191
  onFieldChange = (dottedPath) => {
1135
- return (value, errSchema, id) => {
1136
- const { onChange, errorSchema, formData } = this.props;
1137
- const newFormData = cloneDeep2(formData || {});
1138
- let newErrorSchema = errorSchema;
1139
- if (errSchema && errorSchema) {
1140
- newErrorSchema = cloneDeep2(errorSchema);
1141
- set(newErrorSchema, dottedPath, errSchema);
1142
- }
1143
- set(newFormData, dottedPath, value);
1144
- onChange(newFormData, newErrorSchema, id);
1192
+ return (value, path, errSchema, id) => {
1193
+ const { onChange } = this.props;
1194
+ onChange(value, path, errSchema, id);
1145
1195
  };
1146
1196
  };
1147
1197
  /** Renders the `children` of the `GridType.CONDITION` if it passes. The `layoutGridSchema` for the
@@ -1229,20 +1279,20 @@
1229
1279
  const GridTemplate2 = utils.getTemplate("GridTemplate", registry, uiOptions);
1230
1280
  return /* @__PURE__ */ jsxRuntime.jsx(GridTemplate2, { ...gridProps, "data-testid": _LayoutGridField.TEST_IDS.row, children: this.renderChildren(children) });
1231
1281
  }
1232
- /** Iterates through all the `childrenLayoutGridSchema`, rendering a nested `LayoutGridField` for each item in the
1282
+ /** Iterates through all the `childrenLayoutGrfieldPathId`, rendering a nested `LayoutGridField` for each item in the
1233
1283
  * list, passing all the props for the current `LayoutGridField` along, updating the `schema` by calling
1234
1284
  * `retrieveSchema()` on it to resolve any `$ref`s. In addition to the updated `schema`, each item in
1235
- * `childrenLayoutGridSchema` is passed as `layoutGridSchema`.
1285
+ * `childrenLayoutGrfieldPathId` is passed as `layoutGridSchema`.
1236
1286
  *
1237
- * @param childrenLayoutGridSchema - The list of strings or objects that represents the configurations for the
1287
+ * @param childrenLayoutGrfieldPathId - The list of strings or objects that represents the configurations for the
1238
1288
  * children fields
1239
1289
  * @returns - The nested `LayoutGridField`s
1240
1290
  */
1241
- renderChildren(childrenLayoutGridSchema) {
1291
+ renderChildren(childrenLayoutGrfieldPathId) {
1242
1292
  const { registry, schema: rawSchema, formData } = this.props;
1243
1293
  const { schemaUtils } = registry;
1244
1294
  const schema = schemaUtils.retrieveSchema(rawSchema, formData);
1245
- return childrenLayoutGridSchema.map((layoutGridSchema) => /* @__PURE__ */ react.createElement(
1295
+ return childrenLayoutGrfieldPathId.map((layoutGridSchema) => /* @__PURE__ */ react.createElement(
1246
1296
  _LayoutGridField,
1247
1297
  {
1248
1298
  ...this.props,
@@ -1258,7 +1308,7 @@
1258
1308
  * specified props for that component. If `name` exists, we take the name, the initial & root schemas and the formData
1259
1309
  * and get the destination schema, is required state and optional oneOf/anyOf options for it. If the destination
1260
1310
  * schema was located along with oneOf/anyOf options then a `LayoutMultiSchemaField` will be rendered with the
1261
- * `uiSchema`, `errorSchema`, `idSchema` and `formData` drilled down to the dotted-path field, spreading any other
1311
+ * `uiSchema`, `errorSchema`, `fieldPathId` and `formData` drilled down to the dotted-path field, spreading any other
1262
1312
  * props from `gridSchema` into the `ui:options`. If the destination schema located without any oneOf/anyOf options,
1263
1313
  * then a `SchemaField` will be rendered with the same props as mentioned in the previous sentence. If no destination
1264
1314
  * schema was located, but a custom render component was found, then it will be rendered with many of the non-event
@@ -1272,18 +1322,17 @@
1272
1322
  schema: initialSchema,
1273
1323
  uiSchema,
1274
1324
  errorSchema,
1275
- idSchema,
1325
+ fieldPathId,
1276
1326
  onBlur,
1277
1327
  onFocus,
1278
1328
  formData,
1279
1329
  readonly,
1280
1330
  registry,
1281
- idSeparator,
1282
1331
  layoutGridSchema,
1283
1332
  // Used to pull this out of otherProps since we don't want to pass it through
1284
1333
  ...otherProps
1285
1334
  } = this.props;
1286
- const { fields: fields2, schemaUtils } = registry;
1335
+ const { fields: fields2 } = registry;
1287
1336
  const { SchemaField: SchemaField2, LayoutMultiSchemaField: LayoutMultiSchemaField2 } = fields2;
1288
1337
  const uiComponentProps = _LayoutGridField.computeUIComponentPropsFromGridSchema(registry, gridSchema);
1289
1338
  if (uiComponentProps.rendered) {
@@ -1295,15 +1344,8 @@
1295
1344
  isRequired,
1296
1345
  isReadonly,
1297
1346
  optionsInfo,
1298
- idSchema: fieldIdSchema
1299
- } = _LayoutGridField.getSchemaDetailsForField(
1300
- schemaUtils,
1301
- name,
1302
- initialSchema,
1303
- formData,
1304
- idSchema,
1305
- idSeparator
1306
- );
1347
+ fieldPathId: fieldIdSchema
1348
+ } = _LayoutGridField.getSchemaDetailsForField(registry, name, initialSchema, formData, fieldPathId);
1307
1349
  if (schema) {
1308
1350
  const Field = optionsInfo?.hasDiscriminator ? LayoutMultiSchemaField2 : SchemaField2;
1309
1351
  const { fieldUiSchema, uiReadonly } = _LayoutGridField.computeFieldUiSchema(
@@ -1324,8 +1366,7 @@
1324
1366
  schema,
1325
1367
  uiSchema: fieldUiSchema,
1326
1368
  errorSchema: get2(errorSchema, name),
1327
- idSchema: fieldIdSchema,
1328
- idSeparator,
1369
+ fieldPathId: fieldIdSchema,
1329
1370
  formData: get2(formData, name),
1330
1371
  onChange: this.onFieldChange(name),
1331
1372
  onBlur,
@@ -1348,8 +1389,7 @@
1348
1389
  errorSchema,
1349
1390
  uiSchema,
1350
1391
  schema: initialSchema,
1351
- idSchema,
1352
- idSeparator,
1392
+ fieldPathId,
1353
1393
  onBlur,
1354
1394
  onFocus,
1355
1395
  registry,
@@ -1391,7 +1431,7 @@
1391
1431
  }
1392
1432
  };
1393
1433
  function LayoutHeaderField(props) {
1394
- const { idSchema, title, schema, uiSchema, required, registry, name } = props;
1434
+ const { fieldPathId, title, schema, uiSchema, required, registry, name } = props;
1395
1435
  const options = utils.getUiOptions(uiSchema, registry.globalUiOptions);
1396
1436
  const { title: uiTitle } = options;
1397
1437
  const { title: schemaTitle } = schema;
@@ -1407,7 +1447,7 @@
1407
1447
  return /* @__PURE__ */ jsxRuntime.jsx(
1408
1448
  TitleFieldTemplate,
1409
1449
  {
1410
- id: utils.titleId(idSchema),
1450
+ id: utils.titleId(fieldPathId),
1411
1451
  title: fieldTitle,
1412
1452
  required,
1413
1453
  schema,
@@ -1445,7 +1485,7 @@
1445
1485
  baseType,
1446
1486
  disabled = false,
1447
1487
  formData,
1448
- idSchema,
1488
+ fieldPathId,
1449
1489
  onBlur,
1450
1490
  onChange,
1451
1491
  options,
@@ -1462,7 +1502,7 @@
1462
1502
  } = props;
1463
1503
  const { widgets: widgets2, schemaUtils, globalUiOptions } = registry;
1464
1504
  const [enumOptions, setEnumOptions] = react.useState(computeEnumOptions(schema, options, schemaUtils, uiSchema, formData));
1465
- const id = get2(idSchema, utils.ID_KEY);
1505
+ const id = get2(fieldPathId, utils.ID_KEY);
1466
1506
  const discriminator = utils.getDiscriminatorFieldFromSchema(schema);
1467
1507
  const FieldErrorTemplate2 = utils.getTemplate("FieldErrorTemplate", registry, options);
1468
1508
  const FieldTemplate2 = utils.getTemplate("FieldTemplate", registry, options);
@@ -1503,10 +1543,10 @@
1503
1543
  if (newFormData) {
1504
1544
  set(newFormData, selectorField, opt);
1505
1545
  }
1506
- onChange(newFormData, void 0, id);
1546
+ onChange(newFormData, fieldPathId.path, void 0, id);
1507
1547
  };
1508
1548
  const widgetOptions = { enumOptions, ...uiOptions };
1509
- const errors = !hideFieldError && rawErrors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(FieldErrorTemplate2, { idSchema, schema, errors: rawErrors, registry }) : void 0;
1549
+ const errors = !hideFieldError && rawErrors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(FieldErrorTemplate2, { fieldPathId, schema, errors: rawErrors, registry }) : void 0;
1510
1550
  const ignored = (value) => noop;
1511
1551
  return /* @__PURE__ */ jsxRuntime.jsx(
1512
1552
  FieldTemplate2,
@@ -1516,7 +1556,6 @@
1516
1556
  label: (title || schema.title) ?? "",
1517
1557
  disabled: disabled || Array.isArray(enumOptions) && isEmpty(enumOptions),
1518
1558
  uiSchema,
1519
- formContext,
1520
1559
  required,
1521
1560
  readonly: !!readonly,
1522
1561
  registry,
@@ -1580,7 +1619,7 @@
1580
1619
  * @param prevState - The previous `AnyOfFieldState` for this template
1581
1620
  */
1582
1621
  componentDidUpdate(prevProps, prevState) {
1583
- const { formData, options, idSchema } = this.props;
1622
+ const { formData, options, fieldPathId } = this.props;
1584
1623
  const { selectedOption } = this.state;
1585
1624
  let newState = this.state;
1586
1625
  if (!utils.deepEquals(prevProps.options, options)) {
@@ -1590,7 +1629,7 @@
1590
1629
  const retrievedOptions = options.map((opt) => schemaUtils.retrieveSchema(opt, formData));
1591
1630
  newState = { selectedOption, retrievedOptions };
1592
1631
  }
1593
- if (!utils.deepEquals(formData, prevProps.formData) && idSchema.$id === prevProps.idSchema.$id) {
1632
+ if (!utils.deepEquals(formData, prevProps.formData) && fieldPathId.$id === prevProps.fieldPathId.$id) {
1594
1633
  const { retrievedOptions } = newState;
1595
1634
  const matchingOption = this.getMatchingOption(selectedOption, formData, retrievedOptions);
1596
1635
  if (prevState && matchingOption !== selectedOption) {
@@ -1624,7 +1663,7 @@
1624
1663
  */
1625
1664
  onOptionChange = (option) => {
1626
1665
  const { selectedOption, retrievedOptions } = this.state;
1627
- const { formData, onChange, registry } = this.props;
1666
+ const { formData, onChange, registry, fieldPathId } = this.props;
1628
1667
  const { schemaUtils } = registry;
1629
1668
  const intOption = option !== void 0 ? parseInt(option, 10) : -1;
1630
1669
  if (intOption === selectedOption) {
@@ -1637,12 +1676,12 @@
1637
1676
  newFormData = schemaUtils.getDefaultFormState(newOption, newFormData, "excludeObjectChildren");
1638
1677
  }
1639
1678
  this.setState({ selectedOption: intOption }, () => {
1640
- onChange(newFormData, void 0, this.getFieldId());
1679
+ onChange(newFormData, fieldPathId.path, void 0, this.getFieldId());
1641
1680
  });
1642
1681
  };
1643
1682
  getFieldId() {
1644
- const { idSchema, schema } = this.props;
1645
- return `${idSchema.$id}${schema.oneOf ? "__oneof_select" : "__anyof_select"}`;
1683
+ const { fieldPathId, schema } = this.props;
1684
+ return `${fieldPathId.$id}${schema.oneOf ? "__oneof_select" : "__anyof_select"}`;
1646
1685
  }
1647
1686
  /** Renders the `AnyOfField` selector along with a `SchemaField` for the value of the `formData`
1648
1687
  */
@@ -1661,6 +1700,11 @@
1661
1700
  } = this.props;
1662
1701
  const { widgets: widgets2, fields: fields2, translateString, globalUiOptions, schemaUtils } = registry;
1663
1702
  const { SchemaField: _SchemaField } = fields2;
1703
+ const MultiSchemaFieldTemplate2 = utils.getTemplate(
1704
+ "MultiSchemaFieldTemplate",
1705
+ registry,
1706
+ globalUiOptions
1707
+ );
1664
1708
  const { selectedOption, retrievedOptions } = this.state;
1665
1709
  const {
1666
1710
  widget = "select",
@@ -1707,34 +1751,42 @@
1707
1751
  value: index
1708
1752
  };
1709
1753
  });
1710
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel panel-default panel-body", children: [
1711
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "form-group", children: /* @__PURE__ */ jsxRuntime.jsx(
1712
- Widget,
1713
- {
1714
- id: this.getFieldId(),
1715
- name: `${name}${schema.oneOf ? "__oneof_select" : "__anyof_select"}`,
1716
- schema: { type: "number", default: 0 },
1717
- onChange: this.onOptionChange,
1718
- onBlur,
1719
- onFocus,
1720
- disabled: disabled || isEmpty(enumOptions),
1721
- multiple: false,
1722
- rawErrors,
1723
- errorSchema: fieldErrorSchema,
1724
- value: selectedOption >= 0 ? selectedOption : void 0,
1725
- options: { enumOptions, ...uiOptions },
1726
- registry,
1727
- formContext,
1728
- placeholder,
1729
- autocomplete,
1730
- autofocus,
1731
- label: title ?? name,
1732
- hideLabel: !displayLabel,
1733
- readonly
1734
- }
1735
- ) }),
1736
- optionSchema && optionSchema.type !== "null" && /* @__PURE__ */ jsxRuntime.jsx(_SchemaField, { ...this.props, schema: optionSchema, uiSchema: optionUiSchema })
1737
- ] });
1754
+ const selector = /* @__PURE__ */ jsxRuntime.jsx(
1755
+ Widget,
1756
+ {
1757
+ id: this.getFieldId(),
1758
+ name: `${name}${schema.oneOf ? "__oneof_select" : "__anyof_select"}`,
1759
+ schema: { type: "number", default: 0 },
1760
+ onChange: this.onOptionChange,
1761
+ onBlur,
1762
+ onFocus,
1763
+ disabled: disabled || isEmpty(enumOptions),
1764
+ multiple: false,
1765
+ rawErrors,
1766
+ errorSchema: fieldErrorSchema,
1767
+ value: selectedOption >= 0 ? selectedOption : void 0,
1768
+ options: { enumOptions, ...uiOptions },
1769
+ registry,
1770
+ formContext,
1771
+ placeholder,
1772
+ autocomplete,
1773
+ autofocus,
1774
+ label: title ?? name,
1775
+ hideLabel: !displayLabel,
1776
+ readonly
1777
+ }
1778
+ );
1779
+ const optionsSchemaField = optionSchema && optionSchema.type !== "null" && /* @__PURE__ */ jsxRuntime.jsx(_SchemaField, { ...this.props, schema: optionSchema, uiSchema: optionUiSchema }) || null;
1780
+ return /* @__PURE__ */ jsxRuntime.jsx(
1781
+ MultiSchemaFieldTemplate2,
1782
+ {
1783
+ schema,
1784
+ registry,
1785
+ uiSchema,
1786
+ selector,
1787
+ optionSchemaField: optionsSchemaField
1788
+ }
1789
+ );
1738
1790
  }
1739
1791
  };
1740
1792
  var MultiSchemaField_default = AnyOfField;
@@ -1746,13 +1798,13 @@
1746
1798
  const { StringField: StringField2 } = registry.fields;
1747
1799
  let value = formData;
1748
1800
  const handleChange = react.useCallback(
1749
- (value2, errorSchema, id) => {
1801
+ (value2, path, errorSchema, id) => {
1750
1802
  setLastValue(value2);
1751
1803
  if (`${value2}`.charAt(0) === ".") {
1752
1804
  value2 = `0${value2}`;
1753
1805
  }
1754
1806
  const processed = typeof value2 === "string" && value2.match(trailingCharMatcherWithPrefix) ? utils.asNumber(value2.replace(trailingCharMatcher, "")) : utils.asNumber(value2);
1755
- onChange(processed, errorSchema, id);
1807
+ onChange(processed, path, errorSchema, id);
1756
1808
  },
1757
1809
  [onChange]
1758
1810
  );
@@ -1789,20 +1841,12 @@
1789
1841
  * @returns - The onPropertyChange callback for the `name` property
1790
1842
  */
1791
1843
  onPropertyChange = (name, addedByAdditionalProperties = false) => {
1792
- return (value, newErrorSchema, id) => {
1793
- const { formData, onChange, errorSchema } = this.props;
1844
+ return (value, path, newErrorSchema, id) => {
1845
+ const { onChange } = this.props;
1794
1846
  if (value === void 0 && addedByAdditionalProperties) {
1795
1847
  value = "";
1796
1848
  }
1797
- const newFormData = { ...formData, [name]: value };
1798
- onChange(
1799
- newFormData,
1800
- errorSchema && errorSchema && {
1801
- ...errorSchema,
1802
- [name]: newErrorSchema
1803
- },
1804
- id
1805
- );
1849
+ onChange(value, path, newErrorSchema, id);
1806
1850
  };
1807
1851
  };
1808
1852
  /** Returns a callback to handle the onDropPropertyClick event for the given `key` which removes the old `key` data
@@ -1814,10 +1858,10 @@
1814
1858
  onDropPropertyClick = (key) => {
1815
1859
  return (event) => {
1816
1860
  event.preventDefault();
1817
- const { onChange, formData } = this.props;
1861
+ const { onChange, formData, fieldPathId } = this.props;
1818
1862
  const copiedFormData = { ...formData };
1819
1863
  unset(copiedFormData, key);
1820
- onChange(copiedFormData);
1864
+ onChange(copiedFormData, fieldPathId.path);
1821
1865
  };
1822
1866
  };
1823
1867
  /** Computes the next available key name from the `preferredKey`, indexing through the already existing keys until one
@@ -1844,11 +1888,11 @@
1844
1888
  * @returns - The key change callback function
1845
1889
  */
1846
1890
  onKeyChange = (oldValue) => {
1847
- return (value, newErrorSchema) => {
1891
+ return (value) => {
1848
1892
  if (oldValue === value) {
1849
1893
  return;
1850
1894
  }
1851
- const { formData, onChange, errorSchema } = this.props;
1895
+ const { formData, onChange, fieldPathId } = this.props;
1852
1896
  value = this.getAvailableKey(value, formData);
1853
1897
  const newFormData = {
1854
1898
  ...formData
@@ -1860,13 +1904,7 @@
1860
1904
  });
1861
1905
  const renamedObj = Object.assign({}, ...keyValues);
1862
1906
  this.setState({ wasPropertyKeyModified: true });
1863
- onChange(
1864
- renamedObj,
1865
- errorSchema && errorSchema && {
1866
- ...errorSchema,
1867
- [value]: newErrorSchema
1868
- }
1869
- );
1907
+ onChange(renamedObj, fieldPathId.path);
1870
1908
  };
1871
1909
  };
1872
1910
  /** Returns a default value to be used for a new additional schema property of the given `type`
@@ -1902,7 +1940,7 @@
1902
1940
  if (!(schema.additionalProperties || schema.patternProperties)) {
1903
1941
  return;
1904
1942
  }
1905
- const { formData, onChange, registry } = this.props;
1943
+ const { formData, onChange, registry, fieldPathId } = this.props;
1906
1944
  const newFormData = { ...formData };
1907
1945
  const newKey = this.getAvailableKey("newKey", newFormData);
1908
1946
  if (schema.patternProperties) {
@@ -1930,7 +1968,7 @@
1930
1968
  const newValue = constValue ?? defaultValue ?? this.getDefaultValue(type);
1931
1969
  set(newFormData, newKey, newValue);
1932
1970
  }
1933
- onChange(newFormData);
1971
+ onChange(newFormData, fieldPathId.path);
1934
1972
  };
1935
1973
  /** Renders the `ObjectField` from the given props
1936
1974
  */
@@ -1940,37 +1978,40 @@
1940
1978
  uiSchema = {},
1941
1979
  formData,
1942
1980
  errorSchema,
1943
- idSchema,
1981
+ fieldPathId,
1944
1982
  name,
1945
1983
  required = false,
1946
1984
  disabled,
1947
1985
  readonly,
1948
1986
  hideError,
1949
- idPrefix,
1950
- idSeparator,
1951
1987
  onBlur,
1952
1988
  onFocus,
1953
1989
  registry,
1954
1990
  title
1955
1991
  } = this.props;
1956
- const { fields: fields2, formContext, schemaUtils, translateString, globalUiOptions } = registry;
1957
- const { SchemaField: SchemaField2 } = fields2;
1958
- const schema = schemaUtils.retrieveSchema(rawSchema, formData);
1992
+ const { fields: fields2, formContext, schemaUtils, translateString, globalFormOptions, globalUiOptions } = registry;
1993
+ const { OptionalDataControlsField: OptionalDataControlsField2, SchemaField: SchemaField2 } = fields2;
1994
+ const schema = schemaUtils.retrieveSchema(rawSchema, formData, true);
1959
1995
  const uiOptions = utils.getUiOptions(uiSchema, globalUiOptions);
1960
1996
  const { properties: schemaProperties = {} } = schema;
1961
1997
  const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
1962
1998
  const description = uiOptions.description ?? schema.description;
1963
- let orderedProperties;
1964
- try {
1965
- const properties = Object.keys(schemaProperties);
1966
- orderedProperties = utils.orderProperties(properties, uiOptions.order);
1967
- } catch (err) {
1968
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1969
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "rjsf-config-error", style: { color: "red" }, children: /* @__PURE__ */ jsxRuntime.jsx(Markdown, { options: { disableParsingRawHTML: true }, children: translateString(utils.TranslatableString.InvalidObjectField, [name || "root", err.message]) }) }),
1970
- /* @__PURE__ */ jsxRuntime.jsx("pre", { children: JSON.stringify(schema) })
1971
- ] });
1999
+ const renderOptionalField = utils.shouldRenderOptionalField(registry, schema, required, uiSchema);
2000
+ const hasFormData = utils.isFormDataAvailable(formData);
2001
+ let orderedProperties = [];
2002
+ if (!renderOptionalField || hasFormData) {
2003
+ try {
2004
+ const properties = Object.keys(schemaProperties);
2005
+ orderedProperties = utils.orderProperties(properties, uiOptions.order);
2006
+ } catch (err) {
2007
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2008
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "rjsf-config-error", style: { color: "red" }, children: /* @__PURE__ */ jsxRuntime.jsx(Markdown, { options: { disableParsingRawHTML: true }, children: translateString(utils.TranslatableString.InvalidObjectField, [name || "root", err.message]) }) }),
2009
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { children: JSON.stringify(schema) })
2010
+ ] });
2011
+ }
1972
2012
  }
1973
2013
  const Template = utils.getTemplate("ObjectFieldTemplate", registry, uiOptions);
2014
+ const optionalDataControl = renderOptionalField ? /* @__PURE__ */ jsxRuntime.jsx(OptionalDataControlsField2, { ...this.props, schema }) : void 0;
1974
2015
  const templateProps = {
1975
2016
  // getDisplayLabel() always returns false for object types, so just check the `uiOptions.label`
1976
2017
  title: uiOptions.label === false ? "" : templateTitle,
@@ -1979,7 +2020,7 @@
1979
2020
  const addedByAdditionalProperties = has(schema, [utils.PROPERTIES_KEY, name2, utils.ADDITIONAL_PROPERTY_FLAG]);
1980
2021
  const fieldUiSchema = addedByAdditionalProperties ? uiSchema.additionalProperties : uiSchema[name2];
1981
2022
  const hidden = utils.getUiOptions(fieldUiSchema).widget === "hidden";
1982
- const fieldIdSchema = get2(idSchema, [name2], {});
2023
+ const innerFieldIdPathId = utils.toFieldPathId(name2, globalFormOptions, fieldPathId);
1983
2024
  return {
1984
2025
  content: /* @__PURE__ */ jsxRuntime.jsx(
1985
2026
  SchemaField2,
@@ -1989,9 +2030,7 @@
1989
2030
  schema: get2(schema, [utils.PROPERTIES_KEY, name2], {}),
1990
2031
  uiSchema: fieldUiSchema,
1991
2032
  errorSchema: get2(errorSchema, name2),
1992
- idSchema: fieldIdSchema,
1993
- idPrefix,
1994
- idSeparator,
2033
+ fieldPathId: innerFieldIdPathId,
1995
2034
  formData: get2(formData, name2),
1996
2035
  formContext,
1997
2036
  wasPropertyKeyModified: this.state.wasPropertyKeyModified,
@@ -2017,18 +2056,77 @@
2017
2056
  readonly,
2018
2057
  disabled,
2019
2058
  required,
2020
- idSchema,
2059
+ fieldPathId,
2021
2060
  uiSchema,
2022
2061
  errorSchema,
2023
2062
  schema,
2024
2063
  formData,
2025
2064
  formContext,
2026
- registry
2065
+ registry,
2066
+ optionalDataControl,
2067
+ className: renderOptionalField ? "rjsf-optional-object-field" : void 0
2027
2068
  };
2028
2069
  return /* @__PURE__ */ jsxRuntime.jsx(Template, { ...templateProps, onAddClick: this.handleAddClick });
2029
2070
  }
2030
2071
  };
2031
2072
  var ObjectField_default = ObjectField;
2073
+ function OptionalDataControlsField(props) {
2074
+ const {
2075
+ schema,
2076
+ uiSchema = {},
2077
+ formData,
2078
+ disabled = false,
2079
+ readonly = false,
2080
+ onChange,
2081
+ errorSchema,
2082
+ fieldPathId,
2083
+ registry
2084
+ } = props;
2085
+ const { globalUiOptions = {}, schemaUtils, translateString } = registry;
2086
+ const uiOptions = utils.getUiOptions(uiSchema, globalUiOptions);
2087
+ const OptionalDataControlsTemplate2 = utils.getTemplate(
2088
+ "OptionalDataControlsTemplate",
2089
+ registry,
2090
+ uiOptions
2091
+ );
2092
+ const hasFormData = utils.isFormDataAvailable(formData);
2093
+ let id;
2094
+ let label;
2095
+ let onAddClick;
2096
+ let onRemoveClick;
2097
+ if (disabled || readonly) {
2098
+ id = utils.optionalControlsId(fieldPathId, "Msg");
2099
+ label = hasFormData ? void 0 : translateString(utils.TranslatableString.OptionalObjectEmptyMsg);
2100
+ } else {
2101
+ const labelEnum = hasFormData ? utils.TranslatableString.OptionalObjectRemove : utils.TranslatableString.OptionalObjectAdd;
2102
+ label = translateString(labelEnum);
2103
+ if (hasFormData) {
2104
+ id = utils.optionalControlsId(fieldPathId, "Remove");
2105
+ onRemoveClick = () => onChange(void 0, fieldPathId.path, errorSchema);
2106
+ } else {
2107
+ id = utils.optionalControlsId(fieldPathId, "Add");
2108
+ onAddClick = () => {
2109
+ let newFormData = schemaUtils.getDefaultFormState(schema, formData, "excludeObjectChildren");
2110
+ if (newFormData === void 0) {
2111
+ newFormData = utils.getSchemaType(schema) === "array" ? [] : {};
2112
+ }
2113
+ onChange(newFormData, fieldPathId.path, errorSchema);
2114
+ };
2115
+ }
2116
+ }
2117
+ return label && /* @__PURE__ */ jsxRuntime.jsx(
2118
+ OptionalDataControlsTemplate2,
2119
+ {
2120
+ id,
2121
+ registry,
2122
+ schema,
2123
+ uiSchema,
2124
+ label,
2125
+ onAddClick,
2126
+ onRemoveClick
2127
+ }
2128
+ );
2129
+ }
2032
2130
  var COMPONENT_TYPES = {
2033
2131
  array: "ArrayField",
2034
2132
  boolean: "BooleanField",
@@ -2038,7 +2136,7 @@
2038
2136
  string: "StringField",
2039
2137
  null: "NullField"
2040
2138
  };
2041
- function getFieldComponent(schema, uiOptions, idSchema, registry) {
2139
+ function getFieldComponent(schema, uiOptions, fieldPathId, registry) {
2042
2140
  const field = uiOptions.field;
2043
2141
  const { fields: fields2, translateString } = registry;
2044
2142
  if (typeof field === "function") {
@@ -2067,7 +2165,7 @@
2067
2165
  UnsupportedFieldTemplate,
2068
2166
  {
2069
2167
  schema,
2070
- idSchema,
2168
+ fieldPathId,
2071
2169
  reason: translateString(utils.TranslatableString.UnknownFieldType, [String(schema.type)]),
2072
2170
  registry
2073
2171
  }
@@ -2077,12 +2175,10 @@
2077
2175
  function SchemaFieldRender(props) {
2078
2176
  const {
2079
2177
  schema: _schema,
2080
- idSchema: _idSchema,
2178
+ fieldPathId,
2081
2179
  uiSchema,
2082
2180
  formData,
2083
2181
  errorSchema,
2084
- idPrefix,
2085
- idSeparator,
2086
2182
  name,
2087
2183
  onChange,
2088
2184
  onKeyChange,
@@ -2102,19 +2198,15 @@
2102
2198
  const FieldHelpTemplate2 = utils.getTemplate("FieldHelpTemplate", registry, uiOptions);
2103
2199
  const FieldErrorTemplate2 = utils.getTemplate("FieldErrorTemplate", registry, uiOptions);
2104
2200
  const schema = schemaUtils.retrieveSchema(_schema, formData);
2105
- const fieldId = _idSchema[utils.ID_KEY];
2106
- const idSchema = utils.mergeObjects(
2107
- schemaUtils.toIdSchema(schema, fieldId, formData, idPrefix, idSeparator),
2108
- _idSchema
2109
- );
2201
+ const fieldId = fieldPathId[utils.ID_KEY];
2110
2202
  const handleFieldComponentChange = react.useCallback(
2111
- (formData2, newErrorSchema, id2) => {
2203
+ (formData2, path, newErrorSchema, id2) => {
2112
2204
  const theId = id2 || fieldId;
2113
- return onChange(formData2, newErrorSchema, theId);
2205
+ return onChange(formData2, path, newErrorSchema, theId);
2114
2206
  },
2115
2207
  [fieldId, onChange]
2116
2208
  );
2117
- const FieldComponent = getFieldComponent(schema, uiOptions, idSchema, registry);
2209
+ const FieldComponent = getFieldComponent(schema, uiOptions, fieldPathId, registry);
2118
2210
  const disabled = Boolean(uiOptions.disabled ?? props.disabled);
2119
2211
  const readonly = Boolean(uiOptions.readonly ?? (props.readonly || props.schema.readOnly || schema.readOnly));
2120
2212
  const uiSchemaHideError = uiOptions.hideError;
@@ -2134,7 +2226,7 @@
2134
2226
  {
2135
2227
  ...props,
2136
2228
  onChange: handleFieldComponentChange,
2137
- idSchema,
2229
+ fieldPathId,
2138
2230
  schema,
2139
2231
  uiSchema: fieldUiSchema,
2140
2232
  disabled,
@@ -2146,7 +2238,7 @@
2146
2238
  rawErrors: __errors
2147
2239
  }
2148
2240
  );
2149
- const id = idSchema[utils.ID_KEY];
2241
+ const id = fieldPathId[utils.ID_KEY];
2150
2242
  let label;
2151
2243
  if (wasPropertyKeyModified) {
2152
2244
  label = name;
@@ -2167,7 +2259,7 @@
2167
2259
  FieldHelpTemplate2,
2168
2260
  {
2169
2261
  help,
2170
- idSchema,
2262
+ fieldPathId,
2171
2263
  schema,
2172
2264
  uiSchema,
2173
2265
  hasErrors: !hideError && __errors && __errors.length > 0,
@@ -2179,7 +2271,7 @@
2179
2271
  {
2180
2272
  errors: __errors,
2181
2273
  errorSchema,
2182
- idSchema,
2274
+ fieldPathId,
2183
2275
  schema,
2184
2276
  uiSchema,
2185
2277
  registry
@@ -2214,7 +2306,6 @@
2214
2306
  displayLabel,
2215
2307
  classNames: classNames.join(" ").trim(),
2216
2308
  style: uiOptions.style,
2217
- formContext,
2218
2309
  formData,
2219
2310
  schema,
2220
2311
  uiSchema,
@@ -2235,9 +2326,7 @@
2235
2326
  errorSchema,
2236
2327
  formData,
2237
2328
  formContext,
2238
- idPrefix,
2239
- idSchema,
2240
- idSeparator,
2329
+ fieldPathId,
2241
2330
  onBlur: props.onBlur,
2242
2331
  onChange: props.onChange,
2243
2332
  onFocus: props.onFocus,
@@ -2260,9 +2349,7 @@
2260
2349
  errorSchema,
2261
2350
  formData,
2262
2351
  formContext,
2263
- idPrefix,
2264
- idSchema,
2265
- idSeparator,
2352
+ fieldPathId,
2266
2353
  onBlur: props.onBlur,
2267
2354
  onChange: props.onChange,
2268
2355
  onFocus: props.onFocus,
@@ -2279,7 +2366,11 @@
2279
2366
  }
2280
2367
  var SchemaField = class extends react.Component {
2281
2368
  shouldComponentUpdate(nextProps) {
2282
- return !utils.deepEquals(this.props, nextProps);
2369
+ const {
2370
+ registry: { globalFormOptions }
2371
+ } = this.props;
2372
+ const { experimental_componentUpdateStrategy = "customDeep" } = globalFormOptions;
2373
+ return utils.shouldRender(this, nextProps, this.state, experimental_componentUpdateStrategy);
2283
2374
  }
2284
2375
  render() {
2285
2376
  return /* @__PURE__ */ jsxRuntime.jsx(SchemaFieldRender, { ...this.props });
@@ -2291,7 +2382,7 @@
2291
2382
  schema,
2292
2383
  name,
2293
2384
  uiSchema,
2294
- idSchema,
2385
+ fieldPathId,
2295
2386
  formData,
2296
2387
  required,
2297
2388
  disabled = false,
@@ -2315,19 +2406,25 @@
2315
2406
  const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions);
2316
2407
  const label = uiTitle ?? title ?? name;
2317
2408
  const Widget = utils.getWidget(schema, widget, widgets2);
2409
+ const onWidgetChange = react.useCallback(
2410
+ (value, errorSchema, id) => {
2411
+ return onChange(value, fieldPathId.path, errorSchema, id);
2412
+ },
2413
+ [onChange, fieldPathId]
2414
+ );
2318
2415
  return /* @__PURE__ */ jsxRuntime.jsx(
2319
2416
  Widget,
2320
2417
  {
2321
2418
  options: { ...options, enumOptions },
2322
2419
  schema,
2323
2420
  uiSchema,
2324
- id: idSchema.$id,
2421
+ id: fieldPathId.$id,
2325
2422
  name,
2326
2423
  label,
2327
2424
  hideLabel: !displayLabel,
2328
2425
  hideError,
2329
2426
  value: formData,
2330
- onChange,
2427
+ onChange: onWidgetChange,
2331
2428
  onBlur,
2332
2429
  onFocus,
2333
2430
  required,
@@ -2343,12 +2440,12 @@
2343
2440
  }
2344
2441
  var StringField_default = StringField;
2345
2442
  function NullField(props) {
2346
- const { formData, onChange } = props;
2443
+ const { formData, onChange, fieldPathId } = props;
2347
2444
  react.useEffect(() => {
2348
2445
  if (formData === void 0) {
2349
- onChange(null);
2446
+ onChange(null, fieldPathId.path);
2350
2447
  }
2351
- }, [formData, onChange]);
2448
+ }, [fieldPathId, formData, onChange]);
2352
2449
  return null;
2353
2450
  }
2354
2451
  var NullField_default = NullField;
@@ -2366,6 +2463,7 @@
2366
2463
  NumberField: NumberField_default,
2367
2464
  ObjectField: ObjectField_default,
2368
2465
  OneOfField: MultiSchemaField_default,
2466
+ OptionalDataControlsField,
2369
2467
  SchemaField: SchemaField_default,
2370
2468
  StringField: StringField_default,
2371
2469
  NullField: NullField_default
@@ -2373,7 +2471,7 @@
2373
2471
  }
2374
2472
  var fields_default = fields;
2375
2473
  function ArrayFieldDescriptionTemplate(props) {
2376
- const { idSchema, description, registry, schema, uiSchema } = props;
2474
+ const { fieldPathId, description, registry, schema, uiSchema } = props;
2377
2475
  const options = utils.getUiOptions(uiSchema, registry.globalUiOptions);
2378
2476
  const { label: displayLabel = true } = options;
2379
2477
  if (!description || !displayLabel) {
@@ -2387,7 +2485,7 @@
2387
2485
  return /* @__PURE__ */ jsxRuntime.jsx(
2388
2486
  DescriptionFieldTemplate,
2389
2487
  {
2390
- id: utils.descriptionId(idSchema),
2488
+ id: utils.descriptionId(fieldPathId),
2391
2489
  description,
2392
2490
  schema,
2393
2491
  uiSchema,
@@ -2431,7 +2529,7 @@
2431
2529
  hasMoveDown,
2432
2530
  hasMoveUp,
2433
2531
  hasRemove,
2434
- idSchema,
2532
+ fieldPathId,
2435
2533
  index,
2436
2534
  onCopyIndexClick,
2437
2535
  onDropIndexClick,
@@ -2449,7 +2547,7 @@
2449
2547
  (hasMoveUp || hasMoveDown) && /* @__PURE__ */ jsxRuntime.jsx(
2450
2548
  MoveUpButton2,
2451
2549
  {
2452
- id: utils.buttonId(idSchema, "moveUp"),
2550
+ id: utils.buttonId(fieldPathId, "moveUp"),
2453
2551
  className: "rjsf-array-item-move-up",
2454
2552
  disabled: disabled || readonly || !hasMoveUp,
2455
2553
  onClick: onArrowUpClick,
@@ -2460,7 +2558,7 @@
2460
2558
  (hasMoveUp || hasMoveDown) && /* @__PURE__ */ jsxRuntime.jsx(
2461
2559
  MoveDownButton2,
2462
2560
  {
2463
- id: utils.buttonId(idSchema, "moveDown"),
2561
+ id: utils.buttonId(fieldPathId, "moveDown"),
2464
2562
  className: "rjsf-array-item-move-down",
2465
2563
  disabled: disabled || readonly || !hasMoveDown,
2466
2564
  onClick: onArrowDownClick,
@@ -2471,7 +2569,7 @@
2471
2569
  hasCopy && /* @__PURE__ */ jsxRuntime.jsx(
2472
2570
  CopyButton2,
2473
2571
  {
2474
- id: utils.buttonId(idSchema, "copy"),
2572
+ id: utils.buttonId(fieldPathId, "copy"),
2475
2573
  className: "rjsf-array-item-copy",
2476
2574
  disabled: disabled || readonly,
2477
2575
  onClick: onCopyClick,
@@ -2482,7 +2580,7 @@
2482
2580
  hasRemove && /* @__PURE__ */ jsxRuntime.jsx(
2483
2581
  RemoveButton2,
2484
2582
  {
2485
- id: utils.buttonId(idSchema, "remove"),
2583
+ id: utils.buttonId(fieldPathId, "remove"),
2486
2584
  className: "rjsf-array-item-remove",
2487
2585
  disabled: disabled || readonly,
2488
2586
  onClick: onRemoveClick,
@@ -2497,9 +2595,10 @@
2497
2595
  canAdd,
2498
2596
  className,
2499
2597
  disabled,
2500
- idSchema,
2598
+ fieldPathId,
2501
2599
  uiSchema,
2502
2600
  items,
2601
+ optionalDataControl,
2503
2602
  onAddClick,
2504
2603
  readonly,
2505
2604
  registry,
@@ -2523,36 +2622,39 @@
2523
2622
  registry,
2524
2623
  uiOptions
2525
2624
  );
2625
+ const showOptionalDataControlInTitle = !readonly && !disabled;
2526
2626
  const {
2527
2627
  ButtonTemplates: { AddButton: AddButton2 }
2528
2628
  } = registry.templates;
2529
- return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className, id: idSchema.$id, children: [
2629
+ return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className, id: fieldPathId.$id, children: [
2530
2630
  /* @__PURE__ */ jsxRuntime.jsx(
2531
2631
  ArrayFieldTitleTemplate2,
2532
2632
  {
2533
- idSchema,
2633
+ fieldPathId,
2534
2634
  title: uiOptions.title || title,
2535
2635
  required,
2536
2636
  schema,
2537
2637
  uiSchema,
2538
- registry
2638
+ registry,
2639
+ optionalDataControl: showOptionalDataControlInTitle ? optionalDataControl : void 0
2539
2640
  }
2540
2641
  ),
2541
2642
  /* @__PURE__ */ jsxRuntime.jsx(
2542
2643
  ArrayFieldDescriptionTemplate2,
2543
2644
  {
2544
- idSchema,
2645
+ fieldPathId,
2545
2646
  description: uiOptions.description || schema.description,
2546
2647
  schema,
2547
2648
  uiSchema,
2548
2649
  registry
2549
2650
  }
2550
2651
  ),
2652
+ !showOptionalDataControlInTitle ? optionalDataControl : void 0,
2551
2653
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "row array-item-list", children: items && items.map(({ key, ...itemProps }) => /* @__PURE__ */ jsxRuntime.jsx(ArrayFieldItemTemplate2, { ...itemProps }, key)) }),
2552
2654
  canAdd && /* @__PURE__ */ jsxRuntime.jsx(
2553
2655
  AddButton2,
2554
2656
  {
2555
- id: utils.buttonId(idSchema, "add"),
2657
+ id: utils.buttonId(fieldPathId, "add"),
2556
2658
  className: "rjsf-array-item-add",
2557
2659
  onClick: onAddClick,
2558
2660
  disabled: disabled || readonly,
@@ -2563,7 +2665,7 @@
2563
2665
  ] });
2564
2666
  }
2565
2667
  function ArrayFieldTitleTemplate(props) {
2566
- const { idSchema, title, schema, uiSchema, required, registry } = props;
2668
+ const { fieldPathId, title, schema, uiSchema, required, registry, optionalDataControl } = props;
2567
2669
  const options = utils.getUiOptions(uiSchema, registry.globalUiOptions);
2568
2670
  const { label: displayLabel = true } = options;
2569
2671
  if (!title || !displayLabel) {
@@ -2577,12 +2679,13 @@
2577
2679
  return /* @__PURE__ */ jsxRuntime.jsx(
2578
2680
  TitleFieldTemplate,
2579
2681
  {
2580
- id: utils.titleId(idSchema),
2682
+ id: utils.titleId(fieldPathId),
2581
2683
  title,
2582
2684
  required,
2583
2685
  schema,
2584
2686
  uiSchema,
2585
- registry
2687
+ registry,
2688
+ optionalDataControl
2586
2689
  }
2587
2690
  );
2588
2691
  }
@@ -2698,6 +2801,7 @@
2698
2801
  return /* @__PURE__ */ jsxRuntime.jsx(IconButton, { title: translateString(utils.TranslatableString.RemoveButton), ...props, iconType: "danger", icon: "remove" });
2699
2802
  }
2700
2803
  function AddButton({
2804
+ id,
2701
2805
  className,
2702
2806
  onClick,
2703
2807
  disabled,
@@ -2707,6 +2811,7 @@
2707
2811
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "row", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: `col-xs-3 col-xs-offset-9 text-right ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx(
2708
2812
  IconButton,
2709
2813
  {
2814
+ id,
2710
2815
  iconType: "info",
2711
2816
  icon: "plus",
2712
2817
  className: "btn-add col-xs-12",
@@ -2793,21 +2898,21 @@
2793
2898
  // src/components/templates/FieldTemplate/index.ts
2794
2899
  var FieldTemplate_default = FieldTemplate;
2795
2900
  function FieldErrorTemplate(props) {
2796
- const { errors = [], idSchema } = props;
2901
+ const { errors = [], fieldPathId } = props;
2797
2902
  if (errors.length === 0) {
2798
2903
  return null;
2799
2904
  }
2800
- const id = utils.errorId(idSchema);
2905
+ const id = utils.errorId(fieldPathId);
2801
2906
  return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("ul", { id, className: "error-detail bs-callout bs-callout-info", children: errors.filter((elem) => !!elem).map((error, index) => {
2802
2907
  return /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-danger", children: error }, index);
2803
2908
  }) }) });
2804
2909
  }
2805
2910
  function FieldHelpTemplate(props) {
2806
- const { idSchema, help } = props;
2911
+ const { fieldPathId, help } = props;
2807
2912
  if (!help) {
2808
2913
  return null;
2809
2914
  }
2810
- const id = utils.helpId(idSchema);
2915
+ const id = utils.helpId(fieldPathId);
2811
2916
  if (typeof help === "string") {
2812
2917
  return /* @__PURE__ */ jsxRuntime.jsx("p", { id, className: "help-block", children: help });
2813
2918
  }
@@ -2817,13 +2922,22 @@
2817
2922
  const { children, column, className, ...rest } = props;
2818
2923
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className, ...rest, children });
2819
2924
  }
2925
+ function MultiSchemaFieldTemplate(props) {
2926
+ const { selector, optionSchemaField } = props;
2927
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel panel-default panel-body", children: [
2928
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "form-group", children: selector }),
2929
+ optionSchemaField
2930
+ ] });
2931
+ }
2820
2932
  function ObjectFieldTemplate(props) {
2821
2933
  const {
2934
+ className,
2822
2935
  description,
2823
2936
  disabled,
2824
2937
  formData,
2825
- idSchema,
2938
+ fieldPathId,
2826
2939
  onAddClick,
2940
+ optionalDataControl,
2827
2941
  properties,
2828
2942
  readonly,
2829
2943
  registry,
@@ -2839,36 +2953,39 @@
2839
2953
  registry,
2840
2954
  options
2841
2955
  );
2956
+ const showOptionalDataControlInTitle = !readonly && !disabled;
2842
2957
  const {
2843
2958
  ButtonTemplates: { AddButton: AddButton2 }
2844
2959
  } = registry.templates;
2845
- return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { id: idSchema.$id, children: [
2960
+ return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className, id: fieldPathId.$id, children: [
2846
2961
  title && /* @__PURE__ */ jsxRuntime.jsx(
2847
2962
  TitleFieldTemplate,
2848
2963
  {
2849
- id: utils.titleId(idSchema),
2964
+ id: utils.titleId(fieldPathId),
2850
2965
  title,
2851
2966
  required,
2852
2967
  schema,
2853
2968
  uiSchema,
2854
- registry
2969
+ registry,
2970
+ optionalDataControl: showOptionalDataControlInTitle ? optionalDataControl : void 0
2855
2971
  }
2856
2972
  ),
2857
2973
  description && /* @__PURE__ */ jsxRuntime.jsx(
2858
2974
  DescriptionFieldTemplate,
2859
2975
  {
2860
- id: utils.descriptionId(idSchema),
2976
+ id: utils.descriptionId(fieldPathId),
2861
2977
  description,
2862
2978
  schema,
2863
2979
  uiSchema,
2864
2980
  registry
2865
2981
  }
2866
2982
  ),
2983
+ !showOptionalDataControlInTitle ? optionalDataControl : void 0,
2867
2984
  properties.map((prop) => prop.content),
2868
2985
  utils.canExpand(schema, uiSchema, formData) && /* @__PURE__ */ jsxRuntime.jsx(
2869
2986
  AddButton2,
2870
2987
  {
2871
- id: utils.buttonId(idSchema, "add"),
2988
+ id: utils.buttonId(fieldPathId, "add"),
2872
2989
  className: "rjsf-object-property-expand",
2873
2990
  onClick: onAddClick(schema),
2874
2991
  disabled: disabled || readonly,
@@ -2878,22 +2995,52 @@
2878
2995
  )
2879
2996
  ] });
2880
2997
  }
2998
+ function OptionalDataControlsTemplate(props) {
2999
+ const { id, registry, label, onAddClick, onRemoveClick } = props;
3000
+ if (onAddClick) {
3001
+ return /* @__PURE__ */ jsxRuntime.jsx(
3002
+ IconButton,
3003
+ {
3004
+ id,
3005
+ registry,
3006
+ icon: "plus",
3007
+ className: "rjsf-add-optional-data btn-sm",
3008
+ onClick: onAddClick,
3009
+ title: label
3010
+ }
3011
+ );
3012
+ } else if (onRemoveClick) {
3013
+ return /* @__PURE__ */ jsxRuntime.jsx(
3014
+ IconButton,
3015
+ {
3016
+ id,
3017
+ registry,
3018
+ icon: "remove",
3019
+ className: "rjsf-remove-optional-data btn-sm",
3020
+ onClick: onRemoveClick,
3021
+ title: label
3022
+ }
3023
+ );
3024
+ }
3025
+ return /* @__PURE__ */ jsxRuntime.jsx("em", { id, children: label });
3026
+ }
2881
3027
  var REQUIRED_FIELD_SYMBOL2 = "*";
2882
3028
  function TitleField(props) {
2883
- const { id, title, required } = props;
3029
+ const { id, title, required, optionalDataControl } = props;
2884
3030
  return /* @__PURE__ */ jsxRuntime.jsxs("legend", { id, children: [
2885
3031
  title,
2886
- required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "required", children: REQUIRED_FIELD_SYMBOL2 })
3032
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "required", children: REQUIRED_FIELD_SYMBOL2 }),
3033
+ optionalDataControl && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pull-right", style: { marginBottom: "2px" }, children: optionalDataControl })
2887
3034
  ] });
2888
3035
  }
2889
3036
  function UnsupportedField(props) {
2890
- const { schema, idSchema, reason, registry } = props;
3037
+ const { schema, fieldPathId, reason, registry } = props;
2891
3038
  const { translateString } = registry;
2892
3039
  let translateEnum = utils.TranslatableString.UnsupportedField;
2893
3040
  const translateParams = [];
2894
- if (idSchema && idSchema.$id) {
3041
+ if (fieldPathId && fieldPathId.$id) {
2895
3042
  translateEnum = utils.TranslatableString.UnsupportedFieldWithId;
2896
- translateParams.push(idSchema.$id);
3043
+ translateParams.push(fieldPathId.$id);
2897
3044
  }
2898
3045
  if (reason) {
2899
3046
  translateEnum = translateEnum === utils.TranslatableString.UnsupportedField ? utils.TranslatableString.UnsupportedFieldWithReason : utils.TranslatableString.UnsupportedFieldWithIdAndReason;
@@ -2981,7 +3128,9 @@
2981
3128
  FieldErrorTemplate,
2982
3129
  FieldHelpTemplate,
2983
3130
  GridTemplate,
3131
+ MultiSchemaFieldTemplate,
2984
3132
  ObjectFieldTemplate,
3133
+ OptionalDataControlsTemplate,
2985
3134
  TitleFieldTemplate: TitleField,
2986
3135
  UnsupportedFieldTemplate: UnsupportedField_default,
2987
3136
  WrapIfAdditionalTemplate
@@ -3044,25 +3193,24 @@
3044
3193
  value
3045
3194
  }) {
3046
3195
  const { translateString } = registry;
3047
- const [lastValue, setLastValue] = react.useState(value);
3048
- const [state, setState] = react.useReducer(
3049
- (state2, action) => {
3050
- return { ...state2, ...action };
3196
+ const [state, setState] = react.useState(utils.parseDateString(value, time));
3197
+ react.useEffect(() => {
3198
+ setState(utils.parseDateString(value, time));
3199
+ }, [time, value]);
3200
+ const handleChange = react.useCallback(
3201
+ (property, value2) => {
3202
+ const nextState = {
3203
+ ...state,
3204
+ [property]: typeof value2 === "undefined" ? -1 : value2
3205
+ };
3206
+ if (readyForChange(nextState)) {
3207
+ onChange(utils.toDateString(nextState, time));
3208
+ } else {
3209
+ setState(nextState);
3210
+ }
3051
3211
  },
3052
- utils.parseDateString(value, time)
3212
+ [state, onChange, time]
3053
3213
  );
3054
- react.useEffect(() => {
3055
- const stateValue = utils.toDateString(state, time);
3056
- if (readyForChange(state) && stateValue !== value) {
3057
- onChange(stateValue);
3058
- } else if (lastValue !== value) {
3059
- setLastValue(value);
3060
- setState(utils.parseDateString(value, time));
3061
- }
3062
- }, [time, value, onChange, state, lastValue]);
3063
- const handleChange = react.useCallback((property, value2) => {
3064
- setState({ [property]: value2 });
3065
- }, []);
3066
3214
  const handleSetNow = react.useCallback(
3067
3215
  (event) => {
3068
3216
  event.preventDefault();
@@ -3072,7 +3220,7 @@
3072
3220
  const nextState = utils.parseDateString((/* @__PURE__ */ new Date()).toJSON(), time);
3073
3221
  onChange(utils.toDateString(nextState, time));
3074
3222
  },
3075
- [disabled, readonly, time]
3223
+ [disabled, readonly, time, onChange]
3076
3224
  );
3077
3225
  const handleClear = react.useCallback(
3078
3226
  (event) => {
@@ -3200,11 +3348,11 @@
3200
3348
  const checkboxesValues = Array.isArray(value) ? value : [value];
3201
3349
  const handleBlur = react.useCallback(
3202
3350
  ({ target }) => onBlur(id, utils.enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3203
- [onBlur, id]
3351
+ [onBlur, id, enumOptions, emptyValue]
3204
3352
  );
3205
3353
  const handleFocus = react.useCallback(
3206
3354
  ({ target }) => onFocus(id, utils.enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3207
- [onFocus, id]
3355
+ [onFocus, id, enumOptions, emptyValue]
3208
3356
  );
3209
3357
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "checkboxes", id, children: Array.isArray(enumOptions) && enumOptions.map((option, index) => {
3210
3358
  const checked = utils.enumOptionsIsSelected(option.value, checkboxesValues);
@@ -3773,7 +3921,8 @@
3773
3921
  widgets: widgets_default(),
3774
3922
  rootSchema: {},
3775
3923
  formContext: {},
3776
- translateString: utils.englishStringTranslator
3924
+ translateString: utils.englishStringTranslator,
3925
+ globalFormOptions: { idPrefix: utils.DEFAULT_ID_PREFIX, idSeparator: utils.DEFAULT_ID_SEPARATOR }
3777
3926
  };
3778
3927
  }
3779
3928
  var Form = class extends react.Component {
@@ -3781,6 +3930,9 @@
3781
3930
  * provide any possible type here
3782
3931
  */
3783
3932
  formElement;
3933
+ /** The list of pending changes
3934
+ */
3935
+ pendingChanges = [];
3784
3936
  /** Constructs the `Form` from the `props`. Will setup the initial state from the props. It will also call the
3785
3937
  * `onChange` handler if the initially provided `formData` is modified to add missing default values as part of the
3786
3938
  * state construction.
@@ -3819,8 +3971,10 @@
3819
3971
  getSnapshotBeforeUpdate(prevProps, prevState) {
3820
3972
  if (!utils.deepEquals(this.props, prevProps)) {
3821
3973
  const formDataChangedFields = utils.getChangedFields(this.props.formData, prevProps.formData);
3974
+ const stateDataChangedFields = utils.getChangedFields(this.props.formData, this.state.formData);
3822
3975
  const isSchemaChanged = !utils.deepEquals(prevProps.schema, this.props.schema);
3823
3976
  const isFormDataChanged = formDataChangedFields.length > 0 || !utils.deepEquals(prevProps.formData, this.props.formData);
3977
+ const isStateDataChanged = stateDataChangedFields.length > 0 || !utils.deepEquals(this.state.formData, this.props.formData);
3824
3978
  const nextState = this.getStateFromProps(
3825
3979
  this.props,
3826
3980
  this.props.formData,
@@ -3829,7 +3983,9 @@
3829
3983
  // match one of the subSchemas, the retrieved schema must be updated.
3830
3984
  isSchemaChanged || isFormDataChanged ? void 0 : this.state.retrievedSchema,
3831
3985
  isSchemaChanged,
3832
- formDataChangedFields
3986
+ formDataChangedFields,
3987
+ // Skip live validation for this request if no form data has changed from the last state
3988
+ !isStateDataChanged
3833
3989
  );
3834
3990
  const shouldUpdate = !utils.deepEquals(nextState, prevState);
3835
3991
  return { nextState, shouldUpdate };
@@ -3866,35 +4022,42 @@
3866
4022
  * @param retrievedSchema - An expanded schema, if not provided, it will be retrieved from the `schema` and `formData`.
3867
4023
  * @param isSchemaChanged - A flag indicating whether the schema has changed.
3868
4024
  * @param formDataChangedFields - The changed fields of `formData`
4025
+ * @param skipLiveValidate - Optional flag, if true, means that we are not running live validation
3869
4026
  * @returns - The new state for the `Form`
3870
4027
  */
3871
- getStateFromProps(props, inputFormData, retrievedSchema, isSchemaChanged = false, formDataChangedFields = []) {
4028
+ getStateFromProps(props, inputFormData, retrievedSchema, isSchemaChanged = false, formDataChangedFields = [], skipLiveValidate = false) {
3872
4029
  const state = this.state || {};
3873
4030
  const schema = "schema" in props ? props.schema : this.props.schema;
4031
+ const validator2 = "validator" in props ? props.validator : this.props.validator;
3874
4032
  const uiSchema = ("uiSchema" in props ? props.uiSchema : this.props.uiSchema) || {};
3875
4033
  const edit = typeof inputFormData !== "undefined";
3876
4034
  const liveValidate = "liveValidate" in props ? props.liveValidate : this.props.liveValidate;
3877
4035
  const mustValidate = edit && !props.noValidate && liveValidate;
3878
- const rootSchema = schema;
3879
4036
  const experimental_defaultFormStateBehavior = "experimental_defaultFormStateBehavior" in props ? props.experimental_defaultFormStateBehavior : this.props.experimental_defaultFormStateBehavior;
3880
4037
  const experimental_customMergeAllOf = "experimental_customMergeAllOf" in props ? props.experimental_customMergeAllOf : this.props.experimental_customMergeAllOf;
3881
4038
  let schemaUtils = state.schemaUtils;
3882
4039
  if (!schemaUtils || schemaUtils.doesSchemaUtilsDiffer(
3883
- props.validator,
3884
- rootSchema,
4040
+ validator2,
4041
+ schema,
3885
4042
  experimental_defaultFormStateBehavior,
3886
4043
  experimental_customMergeAllOf
3887
4044
  )) {
3888
4045
  schemaUtils = utils.createSchemaUtils(
3889
- props.validator,
3890
- rootSchema,
4046
+ validator2,
4047
+ schema,
3891
4048
  experimental_defaultFormStateBehavior,
3892
4049
  experimental_customMergeAllOf
3893
4050
  );
3894
4051
  }
3895
- const formData = schemaUtils.getDefaultFormState(schema, inputFormData);
4052
+ const rootSchema = schemaUtils.getRootSchema();
4053
+ const formData = schemaUtils.getDefaultFormState(
4054
+ rootSchema,
4055
+ inputFormData,
4056
+ false,
4057
+ state.initialDefaultsGenerated
4058
+ );
3896
4059
  const _retrievedSchema = this.updateRetrievedSchema(
3897
- retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData)
4060
+ retrievedSchema ?? schemaUtils.retrieveSchema(rootSchema, formData)
3898
4061
  );
3899
4062
  const getCurrentErrors = () => {
3900
4063
  if (props.noValidate || isSchemaChanged) {
@@ -3914,25 +4077,28 @@
3914
4077
  let errorSchema;
3915
4078
  let schemaValidationErrors = state.schemaValidationErrors;
3916
4079
  let schemaValidationErrorSchema = state.schemaValidationErrorSchema;
3917
- if (mustValidate) {
3918
- const schemaValidation = this.validate(formData, schema, schemaUtils, _retrievedSchema);
3919
- errors = schemaValidation.errors;
3920
- if (retrievedSchema === void 0) {
3921
- errorSchema = schemaValidation.errorSchema;
3922
- } else {
3923
- errorSchema = utils.mergeObjects(
3924
- this.state?.errorSchema,
3925
- schemaValidation.errorSchema,
3926
- "preventDuplicates"
3927
- );
3928
- }
3929
- schemaValidationErrors = errors;
3930
- schemaValidationErrorSchema = errorSchema;
4080
+ if (mustValidate && !skipLiveValidate) {
4081
+ const liveValidation = this.liveValidate(
4082
+ rootSchema,
4083
+ schemaUtils,
4084
+ state.errorSchema,
4085
+ formData,
4086
+ void 0,
4087
+ state.customErrors,
4088
+ retrievedSchema,
4089
+ // If retrievedSchema is undefined which means the schema or formData has changed, we do not merge state.
4090
+ // Else in the case where it hasn't changed,
4091
+ retrievedSchema !== void 0
4092
+ );
4093
+ errors = liveValidation.errors;
4094
+ errorSchema = liveValidation.errorSchema;
4095
+ schemaValidationErrors = liveValidation.schemaValidationErrors;
4096
+ schemaValidationErrorSchema = liveValidation.schemaValidationErrorSchema;
3931
4097
  } else {
3932
4098
  const currentErrors = getCurrentErrors();
3933
4099
  errors = currentErrors.errors;
3934
4100
  errorSchema = currentErrors.errorSchema;
3935
- if (formDataChangedFields.length > 0) {
4101
+ if (formDataChangedFields.length > 0 && !mustValidate) {
3936
4102
  const newErrorSchema = formDataChangedFields.reduce(
3937
4103
  (acc, key) => {
3938
4104
  acc[key] = void 0;
@@ -3946,31 +4112,24 @@
3946
4112
  "preventDuplicates"
3947
4113
  );
3948
4114
  }
4115
+ const mergedErrors = this.mergeErrors({ errorSchema, errors }, props.extraErrors, state.customErrors);
4116
+ errors = mergedErrors.errors;
4117
+ errorSchema = mergedErrors.errorSchema;
3949
4118
  }
3950
- if (props.extraErrors) {
3951
- const merged = utils.validationDataMerge({ errorSchema, errors }, props.extraErrors);
3952
- errorSchema = merged.errorSchema;
3953
- errors = merged.errors;
3954
- }
3955
- const idSchema = schemaUtils.toIdSchema(
3956
- _retrievedSchema,
3957
- uiSchema["ui:rootFieldId"],
3958
- formData,
3959
- props.idPrefix,
3960
- props.idSeparator
3961
- );
4119
+ const fieldPathId = utils.toFieldPathId("", this.getGlobalFormOptions(this.props));
3962
4120
  const nextState = {
3963
4121
  schemaUtils,
3964
- schema,
4122
+ schema: rootSchema,
3965
4123
  uiSchema,
3966
- idSchema,
4124
+ fieldPathId,
3967
4125
  formData,
3968
4126
  edit,
3969
4127
  errors,
3970
4128
  errorSchema,
3971
4129
  schemaValidationErrors,
3972
4130
  schemaValidationErrorSchema,
3973
- retrievedSchema: _retrievedSchema
4131
+ retrievedSchema: _retrievedSchema,
4132
+ initialDefaultsGenerated: true
3974
4133
  };
3975
4134
  return nextState;
3976
4135
  }
@@ -3981,31 +4140,18 @@
3981
4140
  * @returns - True if the component should be updated, false otherwise
3982
4141
  */
3983
4142
  shouldComponentUpdate(nextProps, nextState) {
3984
- return utils.shouldRender(this, nextProps, nextState);
3985
- }
3986
- /** Gets the previously raised customValidate errors.
3987
- *
3988
- * @returns the previous customValidate errors
3989
- */
3990
- getPreviousCustomValidateErrors() {
3991
- const { customValidate, uiSchema } = this.props;
3992
- const prevFormData = this.state.formData;
3993
- let customValidateErrors = {};
3994
- if (typeof customValidate === "function") {
3995
- const errorHandler = customValidate(prevFormData, utils.createErrorHandler(prevFormData), uiSchema);
3996
- const userErrorSchema = utils.unwrapErrorHandler(errorHandler);
3997
- customValidateErrors = userErrorSchema;
3998
- }
3999
- return customValidateErrors;
4143
+ const { experimental_componentUpdateStrategy = "customDeep" } = this.props;
4144
+ return utils.shouldRender(this, nextProps, nextState, experimental_componentUpdateStrategy);
4000
4145
  }
4001
4146
  /** Validates the `formData` against the `schema` using the `altSchemaUtils` (if provided otherwise it uses the
4002
4147
  * `schemaUtils` in the state), returning the results.
4003
4148
  *
4004
4149
  * @param formData - The new form data to validate
4005
4150
  * @param schema - The schema used to validate against
4006
- * @param altSchemaUtils - The alternate schemaUtils to use for validation
4151
+ * @param [altSchemaUtils] - The alternate schemaUtils to use for validation
4152
+ * @param [retrievedSchema] - An optionally retrieved schema for per
4007
4153
  */
4008
- validate(formData, schema = this.props.schema, altSchemaUtils, retrievedSchema) {
4154
+ validate(formData, schema = this.state.schema, altSchemaUtils, retrievedSchema) {
4009
4155
  const schemaUtils = altSchemaUtils ? altSchemaUtils : this.state.schemaUtils;
4010
4156
  const { customValidate, transformErrors, uiSchema } = this.props;
4011
4157
  const resolvedSchema = retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData);
@@ -4014,7 +4160,6 @@
4014
4160
  /** Renders any errors contained in the `state` in using the `ErrorList`, if not disabled by `showErrorList`. */
4015
4161
  renderErrors(registry) {
4016
4162
  const { errors, errorSchema, schema, uiSchema } = this.state;
4017
- const { formContext } = this.props;
4018
4163
  const options = utils.getUiOptions(uiSchema);
4019
4164
  const ErrorListTemplate = utils.getTemplate("ErrorListTemplate", registry, options);
4020
4165
  if (errors && errors.length) {
@@ -4025,13 +4170,65 @@
4025
4170
  errorSchema: errorSchema || {},
4026
4171
  schema,
4027
4172
  uiSchema,
4028
- formContext,
4029
4173
  registry
4030
4174
  }
4031
4175
  );
4032
4176
  }
4033
4177
  return null;
4034
4178
  }
4179
+ /** Merges any `extraErrors` or `customErrors` into the given `schemaValidation` object, returning the result
4180
+ *
4181
+ * @param schemaValidation - The `ValidationData` object into which additional errors are merged
4182
+ * @param [extraErrors] - The extra errors from the props
4183
+ * @param [customErrors] - The customErrors from custom components
4184
+ * @return - The `extraErrors` and `customErrors` merged into the `schemaValidation`
4185
+ * @private
4186
+ */
4187
+ mergeErrors(schemaValidation, extraErrors, customErrors) {
4188
+ let errorSchema = schemaValidation.errorSchema;
4189
+ let errors = schemaValidation.errors;
4190
+ if (extraErrors) {
4191
+ const merged = utils.validationDataMerge(schemaValidation, extraErrors);
4192
+ errorSchema = merged.errorSchema;
4193
+ errors = merged.errors;
4194
+ }
4195
+ if (customErrors) {
4196
+ const merged = utils.validationDataMerge(schemaValidation, customErrors.ErrorSchema, true);
4197
+ errorSchema = merged.errorSchema;
4198
+ errors = merged.errors;
4199
+ }
4200
+ return { errors, errorSchema };
4201
+ }
4202
+ /** Performs live validation and then updates and returns the errors and error schemas by potentially merging in
4203
+ * `extraErrors` and `customErrors`.
4204
+ *
4205
+ * @param rootSchema - The `rootSchema` from the state
4206
+ * @param schemaUtils - The `SchemaUtilsType` from the state
4207
+ * @param originalErrorSchema - The original `ErrorSchema` from the state
4208
+ * @param [formData] - The new form data to validate
4209
+ * @param [extraErrors] - The extra errors from the props
4210
+ * @param [customErrors] - The customErrors from custom components
4211
+ * @param [retrievedSchema] - An expanded schema, if not provided, it will be retrieved from the `schema` and `formData`
4212
+ * @param [mergeIntoOriginalErrorSchema=false] - Optional flag indicating whether we merge into original schema
4213
+ * @returns - An object containing `errorSchema`, `errors`, `schemaValidationErrors` and `schemaValidationErrorSchema`
4214
+ * @private
4215
+ */
4216
+ liveValidate(rootSchema, schemaUtils, originalErrorSchema, formData, extraErrors, customErrors, retrievedSchema, mergeIntoOriginalErrorSchema = false) {
4217
+ const schemaValidation = this.validate(formData, rootSchema, schemaUtils, retrievedSchema);
4218
+ const errors = schemaValidation.errors;
4219
+ let errorSchema = schemaValidation.errorSchema;
4220
+ if (mergeIntoOriginalErrorSchema) {
4221
+ errorSchema = utils.mergeObjects(
4222
+ originalErrorSchema,
4223
+ schemaValidation.errorSchema,
4224
+ "preventDuplicates"
4225
+ );
4226
+ }
4227
+ const schemaValidationErrors = errors;
4228
+ const schemaValidationErrorSchema = errorSchema;
4229
+ const mergedErrors = this.mergeErrors({ errorSchema, errors }, extraErrors, customErrors);
4230
+ return { ...mergedErrors, schemaValidationErrors, schemaValidationErrorSchema };
4231
+ }
4035
4232
  /** Returns the `formData` with only the elements specified in the `fields` list
4036
4233
  *
4037
4234
  * @param formData - The data for the `Form`
@@ -4053,19 +4250,23 @@
4053
4250
  * @param [formData] - The form data to use while checking for empty objects/arrays
4054
4251
  */
4055
4252
  getFieldNames = (pathSchema, formData) => {
4253
+ const formValueHasData = (value, isLeaf) => typeof value !== "object" || isEmpty(value) || isLeaf && !isEmpty(value);
4056
4254
  const getAllPaths = (_obj, acc = [], paths = [[]]) => {
4057
- Object.keys(_obj).forEach((key) => {
4058
- if (typeof _obj[key] === "object") {
4255
+ const objKeys = Object.keys(_obj);
4256
+ objKeys.forEach((key) => {
4257
+ const data = _obj[key];
4258
+ if (typeof data === "object") {
4059
4259
  const newPaths = paths.map((path) => [...path, key]);
4060
- if (_obj[key][utils.RJSF_ADDITIONAL_PROPERTIES_FLAG] && _obj[key][utils.NAME_KEY] !== "") {
4061
- acc.push(_obj[key][utils.NAME_KEY]);
4260
+ if (data[utils.RJSF_ADDITIONAL_PROPERTIES_FLAG] && data[utils.NAME_KEY] !== "") {
4261
+ acc.push(data[utils.NAME_KEY]);
4062
4262
  } else {
4063
- getAllPaths(_obj[key], acc, newPaths);
4263
+ getAllPaths(data, acc, newPaths);
4064
4264
  }
4065
- } else if (key === utils.NAME_KEY && _obj[key] !== "") {
4265
+ } else if (key === utils.NAME_KEY && data !== "") {
4066
4266
  paths.forEach((path) => {
4067
4267
  const formValue = get2(formData, path);
4068
- if (typeof formValue !== "object" || isEmpty(formValue) || Array.isArray(formValue) && formValue.every((val) => typeof val !== "object")) {
4268
+ const isLeaf = objKeys.length === 1;
4269
+ if (formValueHasData(formValue, isLeaf) || Array.isArray(formValue) && formValue.every((val) => formValueHasData(val, isLeaf))) {
4069
4270
  acc.push(path);
4070
4271
  }
4071
4272
  });
@@ -4085,60 +4286,49 @@
4085
4286
  const retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
4086
4287
  const pathSchema = schemaUtils.toPathSchema(retrievedSchema, "", formData);
4087
4288
  const fieldNames = this.getFieldNames(pathSchema, formData);
4088
- const newFormData = this.getUsedFormData(formData, fieldNames);
4089
- return newFormData;
4289
+ return this.getUsedFormData(formData, fieldNames);
4090
4290
  };
4091
- // Filtering errors based on your retrieved schema to only show errors for properties in the selected branch.
4092
- filterErrorsBasedOnSchema(schemaErrors, resolvedSchema, formData) {
4093
- const { retrievedSchema, schemaUtils } = this.state;
4094
- const _retrievedSchema = resolvedSchema ?? retrievedSchema;
4095
- const pathSchema = schemaUtils.toPathSchema(_retrievedSchema, "", formData);
4096
- const fieldNames = this.getFieldNames(pathSchema, formData);
4097
- const filteredErrors = _pick(schemaErrors, fieldNames);
4098
- if (resolvedSchema?.type !== "object" && resolvedSchema?.type !== "array") {
4099
- filteredErrors.__errors = schemaErrors.__errors;
4100
- }
4101
- const prevCustomValidateErrors = this.getPreviousCustomValidateErrors();
4102
- const filterPreviousCustomErrors = (errors = [], prevCustomErrors) => {
4103
- if (errors.length === 0) {
4104
- return errors;
4105
- }
4106
- return errors.filter((error) => {
4107
- return !prevCustomErrors.includes(error);
4108
- });
4109
- };
4110
- const filterNilOrEmptyErrors = (errors, previousCustomValidateErrors = {}) => {
4111
- _forEach(errors, (errorAtKey, errorKey) => {
4112
- const prevCustomValidateErrorAtKey = previousCustomValidateErrors[errorKey];
4113
- if (_isNil(errorAtKey) || Array.isArray(errorAtKey) && errorAtKey.length === 0) {
4114
- delete errors[errorKey];
4115
- } else if (utils.isObject(errorAtKey) && utils.isObject(prevCustomValidateErrorAtKey) && Array.isArray(prevCustomValidateErrorAtKey?.__errors)) {
4116
- errors[errorKey] = filterPreviousCustomErrors(errorAtKey.__errors, prevCustomValidateErrorAtKey.__errors);
4117
- } else if (typeof errorAtKey === "object" && !Array.isArray(errorAtKey.__errors)) {
4118
- filterNilOrEmptyErrors(errorAtKey, previousCustomValidateErrors[errorKey]);
4119
- }
4120
- });
4121
- return errors;
4122
- };
4123
- return filterNilOrEmptyErrors(filteredErrors, prevCustomValidateErrors);
4124
- }
4125
- /** Function to handle changes made to a field in the `Form`. This handler receives an entirely new copy of the
4126
- * `formData` along with a new `ErrorSchema`. It will first update the `formData` with any missing default fields and
4127
- * then, if `omitExtraData` and `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not
4128
- * in a form field. Then, the resulting formData will be validated if required. The state will be updated with the new
4129
- * updated (potentially filtered) `formData`, any errors that resulted from validation. Finally the `onChange`
4130
- * callback will be called if specified with the updated state.
4291
+ /** Pushes the given change information into the `pendingChanges` array and then calls `processPendingChanges()` if
4292
+ * the array only contains a single pending change.
4131
4293
  *
4132
- * @param formData - The new form data from a change to a field
4133
- * @param newErrorSchema - The new `ErrorSchema` based on the field change
4134
- * @param id - The id of the field that caused the change
4294
+ * @param newValue - The new form data from a change to a field
4295
+ * @param path - The path to the change into which to set the formData
4296
+ * @param [newErrorSchema] - The new `ErrorSchema` based on the field change
4297
+ * @param [id] - The id of the field that caused the change
4298
+ */
4299
+ onChange = (newValue, path, newErrorSchema, id) => {
4300
+ this.pendingChanges.push({ newValue, path, newErrorSchema, id });
4301
+ if (this.pendingChanges.length === 1) {
4302
+ this.processPendingChange();
4303
+ }
4304
+ };
4305
+ /** Function to handle changes made to a field in the `Form`. This handler gets the first change from the
4306
+ * `pendingChanges` list, containing the `newValue` for the `formData` and the `path` at which the `newValue` is to be
4307
+ * updated, along with a new, optional `ErrorSchema` for that same `path` and potentially the `id` of the field being
4308
+ * changed. It will first update the `formData` with any missing default fields and then, if `omitExtraData` and
4309
+ * `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not in a form field. Then, the
4310
+ * resulting `formData` will be validated if required. The state will be updated with the new updated (potentially
4311
+ * filtered) `formData`, any errors that resulted from validation. Finally the `onChange` callback will be called, if
4312
+ * specified, with the updated state and the `processPendingChange()` function is called again.
4135
4313
  */
4136
- onChange = (formData, newErrorSchema, id) => {
4314
+ processPendingChange() {
4315
+ if (this.pendingChanges.length === 0) {
4316
+ return;
4317
+ }
4318
+ const { newValue, path, id } = this.pendingChanges[0];
4319
+ const { newErrorSchema } = this.pendingChanges[0];
4137
4320
  const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
4138
- const { schemaUtils, schema } = this.state;
4321
+ const { formData: oldFormData, schemaUtils, schema, fieldPathId, schemaValidationErrorSchema, errors } = this.state;
4322
+ let { customErrors, errorSchema: originalErrorSchema } = this.state;
4323
+ const rootPathId = fieldPathId.path[0] || "";
4324
+ const isRootPath = !path || path.length === 0 || path.length === 1 && path[0] === rootPathId;
4139
4325
  let retrievedSchema = this.state.retrievedSchema;
4326
+ let formData = isRootPath ? newValue : cloneDeep(oldFormData);
4140
4327
  if (utils.isObject(formData) || Array.isArray(formData)) {
4141
- const newState = this.getStateFromProps(this.props, formData);
4328
+ if (!isRootPath) {
4329
+ set(formData, path, newValue);
4330
+ }
4331
+ const newState = this.getStateFromProps(this.props, formData, void 0, void 0, void 0, true);
4142
4332
  formData = newState.formData;
4143
4333
  retrievedSchema = newState.retrievedSchema;
4144
4334
  }
@@ -4151,38 +4341,54 @@
4151
4341
  formData: newFormData
4152
4342
  };
4153
4343
  }
4154
- if (mustValidate) {
4155
- const schemaValidation = this.validate(newFormData, schema, schemaUtils, retrievedSchema);
4156
- let errors = schemaValidation.errors;
4157
- let errorSchema = schemaValidation.errorSchema;
4158
- const schemaValidationErrors = errors;
4159
- const schemaValidationErrorSchema = errorSchema;
4160
- if (extraErrors) {
4161
- const merged = utils.validationDataMerge(schemaValidation, extraErrors);
4162
- errorSchema = merged.errorSchema;
4163
- errors = merged.errors;
4164
- }
4165
- if (newErrorSchema) {
4166
- const filteredErrors = this.filterErrorsBasedOnSchema(newErrorSchema, retrievedSchema, newFormData);
4167
- errorSchema = utils.mergeObjects(errorSchema, filteredErrors, "preventDuplicates");
4344
+ if (newErrorSchema) {
4345
+ const oldValidationError = !isRootPath ? get2(schemaValidationErrorSchema, path) : schemaValidationErrorSchema;
4346
+ if (!isEmpty(oldValidationError)) {
4347
+ if (!isRootPath) {
4348
+ set(originalErrorSchema, path, newErrorSchema);
4349
+ } else {
4350
+ originalErrorSchema = newErrorSchema;
4351
+ }
4352
+ } else {
4353
+ if (!customErrors) {
4354
+ customErrors = new utils.ErrorSchemaBuilder();
4355
+ }
4356
+ if (isRootPath) {
4357
+ customErrors.setErrors(get2(newErrorSchema, utils.ERRORS_KEY, ""));
4358
+ } else {
4359
+ set(customErrors.ErrorSchema, path, newErrorSchema);
4360
+ }
4168
4361
  }
4169
- state = {
4170
- formData: newFormData,
4171
- errors,
4172
- errorSchema,
4173
- schemaValidationErrors,
4174
- schemaValidationErrorSchema
4175
- };
4362
+ } else if (customErrors && get2(customErrors.ErrorSchema, [...path, utils.ERRORS_KEY])) {
4363
+ customErrors.clearErrors(path);
4364
+ }
4365
+ if (mustValidate && this.pendingChanges.length === 1) {
4366
+ const liveValidation = this.liveValidate(
4367
+ schema,
4368
+ schemaUtils,
4369
+ originalErrorSchema,
4370
+ newFormData,
4371
+ extraErrors,
4372
+ customErrors,
4373
+ retrievedSchema
4374
+ );
4375
+ state = { formData: newFormData, ...liveValidation, customErrors };
4176
4376
  } else if (!noValidate && newErrorSchema) {
4177
- const errorSchema = extraErrors ? utils.mergeObjects(newErrorSchema, extraErrors, "preventDuplicates") : newErrorSchema;
4377
+ const mergedErrors = this.mergeErrors({ errorSchema: originalErrorSchema, errors }, extraErrors, customErrors);
4178
4378
  state = {
4179
4379
  formData: newFormData,
4180
- errorSchema,
4181
- errors: utils.toErrorList(errorSchema)
4380
+ ...mergedErrors,
4381
+ customErrors
4182
4382
  };
4183
4383
  }
4184
- this.setState(state, () => onChange && onChange({ ...this.state, ...state }, id));
4185
- };
4384
+ this.setState(state, () => {
4385
+ if (onChange) {
4386
+ onChange({ ...this.state, ...state }, id);
4387
+ }
4388
+ this.pendingChanges.shift();
4389
+ this.processPendingChange();
4390
+ });
4391
+ }
4186
4392
  /**
4187
4393
  * If the retrievedSchema has changed the new retrievedSchema is returned.
4188
4394
  * Otherwise, the old retrievedSchema is returned to persist reference.
@@ -4211,7 +4417,9 @@
4211
4417
  errorSchema: {},
4212
4418
  errors: [],
4213
4419
  schemaValidationErrors: [],
4214
- schemaValidationErrorSchema: {}
4420
+ schemaValidationErrorSchema: {},
4421
+ initialDefaultsGenerated: false,
4422
+ customErrors: void 0
4215
4423
  };
4216
4424
  this.setState(state, () => onChange && onChange({ ...this.state, ...state }));
4217
4425
  };
@@ -4277,10 +4485,26 @@
4277
4485
  );
4278
4486
  }
4279
4487
  };
4488
+ /** Extracts the `GlobalFormOptions` from the given Form `props`
4489
+ *
4490
+ * @param props - The form props to extract the global form options from
4491
+ * @returns - The `GlobalFormOptions` from the props
4492
+ * @private
4493
+ */
4494
+ getGlobalFormOptions(props) {
4495
+ const {
4496
+ uiSchema = {},
4497
+ experimental_componentUpdateStrategy,
4498
+ idSeparator = utils.DEFAULT_ID_SEPARATOR,
4499
+ idPrefix = utils.DEFAULT_ID_PREFIX
4500
+ } = props;
4501
+ const rootFieldId = uiSchema["ui:rootFieldId"];
4502
+ return { idPrefix: rootFieldId || idPrefix, idSeparator, experimental_componentUpdateStrategy };
4503
+ }
4280
4504
  /** Returns the registry for the form */
4281
4505
  getRegistry() {
4282
4506
  const { translateString: customTranslateString, uiSchema = {} } = this.props;
4283
- const { schemaUtils } = this.state;
4507
+ const { schema, schemaUtils } = this.state;
4284
4508
  const { fields: fields2, templates: templates2, widgets: widgets2, formContext, translateString } = getDefaultRegistry();
4285
4509
  return {
4286
4510
  fields: { ...fields2, ...this.props.fields },
@@ -4293,11 +4517,12 @@
4293
4517
  }
4294
4518
  },
4295
4519
  widgets: { ...widgets2, ...this.props.widgets },
4296
- rootSchema: this.props.schema,
4520
+ rootSchema: schema,
4297
4521
  formContext: this.props.formContext || formContext,
4298
4522
  schemaUtils,
4299
4523
  translateString: customTranslateString || translateString,
4300
- globalUiOptions: uiSchema[utils.UI_GLOBAL_OPTIONS_KEY]
4524
+ globalUiOptions: uiSchema[utils.UI_GLOBAL_OPTIONS_KEY],
4525
+ globalFormOptions: this.getGlobalFormOptions(this.props)
4301
4526
  };
4302
4527
  }
4303
4528
  /** Provides a function that can be used to programmatically submit the `Form` */
@@ -4412,8 +4637,6 @@
4412
4637
  const {
4413
4638
  children,
4414
4639
  id,
4415
- idPrefix,
4416
- idSeparator,
4417
4640
  className = "",
4418
4641
  tagName,
4419
4642
  name,
@@ -4426,11 +4649,10 @@
4426
4649
  noHtml5Validate = false,
4427
4650
  disabled,
4428
4651
  readonly,
4429
- formContext,
4430
4652
  showErrorList = "top",
4431
4653
  _internalFormWrapper
4432
4654
  } = this.props;
4433
- const { schema, uiSchema, formData, errorSchema, idSchema } = this.state;
4655
+ const { schema, uiSchema, formData, errorSchema, fieldPathId } = this.state;
4434
4656
  const registry = this.getRegistry();
4435
4657
  const { SchemaField: _SchemaField } = registry.fields;
4436
4658
  const { SubmitButton: SubmitButton2 } = registry.templates.ButtonTemplates;
@@ -4466,10 +4688,7 @@
4466
4688
  schema,
4467
4689
  uiSchema,
4468
4690
  errorSchema,
4469
- idSchema,
4470
- idPrefix,
4471
- idSeparator,
4472
- formContext,
4691
+ fieldPathId,
4473
4692
  formData,
4474
4693
  onChange: this.onChange,
4475
4694
  onBlur: this.onBlur,
@@ -4513,6 +4732,20 @@
4513
4732
  }
4514
4733
  );
4515
4734
  }
4735
+ function getTestRegistry(rootSchema, fields2 = {}, templates2 = {}, widgets2 = {}, formContext = {}, globalFormOptions = { idPrefix: utils.DEFAULT_ID_PREFIX, idSeparator: utils.DEFAULT_ID_SEPARATOR }) {
4736
+ const defaults = getDefaultRegistry();
4737
+ const schemaUtils = utils.createSchemaUtils(validator, rootSchema);
4738
+ return {
4739
+ fields: { ...defaults.fields, ...fields2 },
4740
+ templates: { ...defaults.templates, ...templates2 },
4741
+ widgets: { ...defaults.widgets, ...widgets2 },
4742
+ formContext,
4743
+ rootSchema,
4744
+ schemaUtils,
4745
+ translateString: utils.englishStringTranslator,
4746
+ globalFormOptions
4747
+ };
4748
+ }
4516
4749
 
4517
4750
  // src/index.ts
4518
4751
  var index_default = Form;
@@ -4520,6 +4753,7 @@
4520
4753
  exports.RichDescription = RichDescription;
4521
4754
  exports.default = index_default;
4522
4755
  exports.getDefaultRegistry = getDefaultRegistry;
4756
+ exports.getTestRegistry = getTestRegistry;
4523
4757
  exports.withTheme = withTheme;
4524
4758
 
4525
4759
  Object.defineProperty(exports, '__esModule', { value: true });