@rjsf/core 6.0.0-beta.20 → 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 (52) hide show
  1. package/dist/core.umd.js +286 -161
  2. package/dist/index.cjs +635 -506
  3. package/dist/index.cjs.map +4 -4
  4. package/dist/index.esm.js +537 -398
  5. package/dist/index.esm.js.map +4 -4
  6. package/lib/components/Form.d.ts +30 -15
  7. package/lib/components/Form.d.ts.map +1 -1
  8. package/lib/components/Form.js +102 -119
  9. package/lib/components/fields/ArrayField.d.ts.map +1 -1
  10. package/lib/components/fields/ArrayField.js +28 -15
  11. package/lib/components/fields/LayoutGridField.d.ts.map +1 -1
  12. package/lib/components/fields/LayoutGridField.js +2 -8
  13. package/lib/components/fields/NullField.js +3 -3
  14. package/lib/components/fields/ObjectField.d.ts.map +1 -1
  15. package/lib/components/fields/ObjectField.js +17 -10
  16. package/lib/components/fields/OptionalDataControlsField.d.ts +8 -0
  17. package/lib/components/fields/OptionalDataControlsField.d.ts.map +1 -0
  18. package/lib/components/fields/OptionalDataControlsField.js +43 -0
  19. package/lib/components/fields/index.d.ts.map +1 -1
  20. package/lib/components/fields/index.js +2 -0
  21. package/lib/components/templates/ArrayFieldTemplate.d.ts.map +1 -1
  22. package/lib/components/templates/ArrayFieldTemplate.js +3 -2
  23. package/lib/components/templates/ArrayFieldTitleTemplate.d.ts.map +1 -1
  24. package/lib/components/templates/ArrayFieldTitleTemplate.js +2 -2
  25. package/lib/components/templates/ButtonTemplates/AddButton.d.ts +1 -1
  26. package/lib/components/templates/ButtonTemplates/AddButton.d.ts.map +1 -1
  27. package/lib/components/templates/ButtonTemplates/AddButton.js +2 -2
  28. package/lib/components/templates/ObjectFieldTemplate.d.ts.map +1 -1
  29. package/lib/components/templates/ObjectFieldTemplate.js +3 -2
  30. package/lib/components/templates/OptionalDataControlsTemplate.d.ts +11 -0
  31. package/lib/components/templates/OptionalDataControlsTemplate.d.ts.map +1 -0
  32. package/lib/components/templates/OptionalDataControlsTemplate.js +20 -0
  33. package/lib/components/templates/TitleField.d.ts.map +1 -1
  34. package/lib/components/templates/TitleField.js +2 -2
  35. package/lib/components/templates/index.d.ts.map +1 -1
  36. package/lib/components/templates/index.js +2 -0
  37. package/lib/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +5 -5
  39. package/src/components/Form.tsx +154 -135
  40. package/src/components/fields/ArrayField.tsx +30 -15
  41. package/src/components/fields/LayoutGridField.tsx +2 -8
  42. package/src/components/fields/NullField.tsx +3 -3
  43. package/src/components/fields/ObjectField.tsx +28 -17
  44. package/src/components/fields/OptionalDataControlsField.tsx +84 -0
  45. package/src/components/fields/index.ts +2 -0
  46. package/src/components/templates/ArrayFieldTemplate.tsx +4 -0
  47. package/src/components/templates/ArrayFieldTitleTemplate.tsx +2 -1
  48. package/src/components/templates/ButtonTemplates/AddButton.tsx +2 -0
  49. package/src/components/templates/ObjectFieldTemplate.tsx +6 -1
  50. package/src/components/templates/OptionalDataControlsTemplate.tsx +43 -0
  51. package/src/components/templates/TitleField.tsx +6 -1
  52. package/src/components/templates/index.ts +2 -0
package/dist/core.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('@rjsf/utils'), require('lodash/cloneDeep'), require('lodash/forEach'), require('lodash/get'), require('lodash/isEmpty'), require('lodash/isNil'), require('lodash/pick'), require('lodash/set'), require('lodash/toPath'), require('lodash/isObject'), require('lodash/uniqueId'), require('react/jsx-runtime'), require('lodash/each'), require('lodash/flatten'), require('lodash/has'), require('lodash/includes'), require('lodash/intersection'), require('lodash/isFunction'), require('lodash/isEqual'), require('lodash/isPlainObject'), require('lodash/isString'), require('lodash/isUndefined'), require('lodash/last'), require('lodash/noop'), require('lodash/omit'), require('markdown-to-jsx'), require('lodash/unset'), require('@rjsf/validator-ajv8')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'react', '@rjsf/utils', 'lodash/cloneDeep', 'lodash/forEach', 'lodash/get', 'lodash/isEmpty', 'lodash/isNil', 'lodash/pick', 'lodash/set', 'lodash/toPath', 'lodash/isObject', 'lodash/uniqueId', 'react/jsx-runtime', 'lodash/each', 'lodash/flatten', 'lodash/has', 'lodash/includes', 'lodash/intersection', 'lodash/isFunction', 'lodash/isEqual', 'lodash/isPlainObject', 'lodash/isString', 'lodash/isUndefined', 'lodash/last', 'lodash/noop', 'lodash/omit', 'markdown-to-jsx', 'lodash/unset', '@rjsf/validator-ajv8'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.JSONSchemaForm = {}, global.react, global.utils, global._cloneDeep, global._forEach, global.get2, global.isEmpty, global._isNil, global._pick, global.set, global._toPath, global.isObject, global.uniqueId, global.jsxRuntime, global.each, global.flatten, global.has, global.includes, global.intersection, global.isFunction, global.isEqual, global.isPlainObject, global.isString, global.isUndefined, global.last, global.noop, global.omit3, global.Markdown, global.unset, global.validator));
5
- })(this, (function (exports, react, utils, _cloneDeep, _forEach, get2, isEmpty, _isNil, _pick, set, _toPath, isObject, uniqueId, jsxRuntime, each, flatten, has, includes, intersection, isFunction, isEqual, isPlainObject, isString, isUndefined, last, noop, omit3, Markdown, unset, validator) { '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() {
@@ -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,
@@ -206,7 +206,7 @@
206
206
  }
207
207
  const newKeyedFormDataRow = {
208
208
  key: generateRowId(),
209
- item: _cloneDeep(keyedFormData[index].item)
209
+ item: cloneDeep(keyedFormData[index].item)
210
210
  };
211
211
  const newKeyedFormData = [...keyedFormData];
212
212
  if (index !== void 0) {
@@ -404,15 +404,21 @@
404
404
  } = this.props;
405
405
  const { keyedFormData } = this.state;
406
406
  const fieldTitle = schema.title || title || name;
407
- const { schemaUtils, formContext, globalFormOptions } = registry;
407
+ const { schemaUtils, fields: fields2, formContext, globalFormOptions } = registry;
408
+ const { OptionalDataControlsField: OptionalDataControlsField2 } = fields2;
408
409
  const uiOptions = utils.getUiOptions(uiSchema);
409
410
  const _schemaItems = isObject(schema.items) ? schema.items : {};
410
411
  const itemsSchema = schemaUtils.retrieveSchema(_schemaItems);
411
412
  const formData = keyedToPlainFormData(this.state.keyedFormData);
412
- 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;
413
419
  const arrayProps = {
414
420
  canAdd,
415
- items: keyedFormData.map((keyedItem, index) => {
421
+ items: actualFormData.map((keyedItem, index) => {
416
422
  const { key, item } = keyedItem;
417
423
  const itemCast = item;
418
424
  const itemSchema = schemaUtils.retrieveSchema(_schemaItems, itemCast);
@@ -439,7 +445,7 @@
439
445
  totalItems: keyedFormData.length
440
446
  });
441
447
  }),
442
- 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}`,
443
449
  disabled,
444
450
  fieldPathId,
445
451
  uiSchema,
@@ -450,7 +456,8 @@
450
456
  title: fieldTitle,
451
457
  formData,
452
458
  rawErrors,
453
- registry
459
+ registry,
460
+ optionalDataControl
454
461
  };
455
462
  const Template = utils.getTemplate("ArrayFieldTemplate", registry, uiOptions);
456
463
  return /* @__PURE__ */ jsxRuntime.jsx(Template, { ...arrayProps });
@@ -613,7 +620,7 @@
613
620
  const {
614
621
  schema,
615
622
  uiSchema = {},
616
- formData = [],
623
+ formData,
617
624
  errorSchema,
618
625
  fieldPathId,
619
626
  name,
@@ -627,28 +634,33 @@
627
634
  onFocus,
628
635
  rawErrors
629
636
  } = this.props;
630
- const { keyedFormData } = this.state;
631
637
  let { formData: items = [] } = this.props;
638
+ const { keyedFormData } = this.state;
632
639
  const fieldTitle = schema.title || title || name;
633
640
  const uiOptions = utils.getUiOptions(uiSchema);
634
- const { schemaUtils, formContext, globalFormOptions } = 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);
635
645
  const _schemaItems = isObject(schema.items) ? schema.items : [];
636
646
  const itemSchemas = _schemaItems.map(
637
- (item, index) => schemaUtils.retrieveSchema(item, formData[index])
647
+ (item, index) => schemaUtils.retrieveSchema(item, items[index])
638
648
  );
639
649
  const additionalSchema = isObject(schema.additionalItems) ? schemaUtils.retrieveSchema(schema.additionalItems, formData) : null;
640
- if (!items || items.length < itemSchemas.length) {
641
- items = items || [];
650
+ if (items.length < itemSchemas.length) {
642
651
  items = items.concat(new Array(itemSchemas.length - items.length));
643
652
  }
644
- 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);
645
657
  const arrayProps = {
646
658
  canAdd,
647
- className: "rjsf-field rjsf-field-array rjsf-field-array-fixed-items",
659
+ className: `rjsf-field rjsf-field-array rjsf-field-array-fixed-items${extraClass}`,
648
660
  disabled,
649
661
  fieldPathId,
650
662
  formData,
651
- items: keyedFormData.map((keyedItem, index) => {
663
+ items: actualFormData.map((keyedItem, index) => {
652
664
  const { key, item } = keyedItem;
653
665
  const itemCast = item;
654
666
  const additional = index >= itemSchemas.length;
@@ -694,7 +706,8 @@
694
706
  uiSchema,
695
707
  title: fieldTitle,
696
708
  errorSchema,
697
- rawErrors
709
+ rawErrors,
710
+ optionalDataControl
698
711
  };
699
712
  const Template = utils.getTemplate("ArrayFieldTemplate", registry, uiOptions);
700
713
  return /* @__PURE__ */ jsxRuntime.jsx(Template, { ...arrayProps });
@@ -1177,13 +1190,8 @@
1177
1190
  */
1178
1191
  onFieldChange = (dottedPath) => {
1179
1192
  return (value, path, errSchema, id) => {
1180
- const { onChange, errorSchema } = this.props;
1181
- let newErrorSchema = errorSchema;
1182
- if (errSchema && errorSchema) {
1183
- newErrorSchema = _cloneDeep(errorSchema);
1184
- set(newErrorSchema, dottedPath, errSchema);
1185
- }
1186
- onChange(value, path, newErrorSchema, id);
1193
+ const { onChange } = this.props;
1194
+ onChange(value, path, errSchema, id);
1187
1195
  };
1188
1196
  };
1189
1197
  /** Renders the `children` of the `GridType.CONDITION` if it passes. The `layoutGridSchema` for the
@@ -1982,23 +1990,28 @@
1982
1990
  title
1983
1991
  } = this.props;
1984
1992
  const { fields: fields2, formContext, schemaUtils, translateString, globalFormOptions, globalUiOptions } = registry;
1985
- const { SchemaField: SchemaField2 } = fields2;
1986
- const schema = schemaUtils.retrieveSchema(rawSchema, formData);
1993
+ const { OptionalDataControlsField: OptionalDataControlsField2, SchemaField: SchemaField2 } = fields2;
1994
+ const schema = schemaUtils.retrieveSchema(rawSchema, formData, true);
1987
1995
  const uiOptions = utils.getUiOptions(uiSchema, globalUiOptions);
1988
1996
  const { properties: schemaProperties = {} } = schema;
1989
1997
  const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
1990
1998
  const description = uiOptions.description ?? schema.description;
1991
- let orderedProperties;
1992
- try {
1993
- const properties = Object.keys(schemaProperties);
1994
- orderedProperties = utils.orderProperties(properties, uiOptions.order);
1995
- } catch (err) {
1996
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1997
- /* @__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]) }) }),
1998
- /* @__PURE__ */ jsxRuntime.jsx("pre", { children: JSON.stringify(schema) })
1999
- ] });
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
+ }
2000
2012
  }
2001
2013
  const Template = utils.getTemplate("ObjectFieldTemplate", registry, uiOptions);
2014
+ const optionalDataControl = renderOptionalField ? /* @__PURE__ */ jsxRuntime.jsx(OptionalDataControlsField2, { ...this.props, schema }) : void 0;
2002
2015
  const templateProps = {
2003
2016
  // getDisplayLabel() always returns false for object types, so just check the `uiOptions.label`
2004
2017
  title: uiOptions.label === false ? "" : templateTitle,
@@ -2049,12 +2062,71 @@
2049
2062
  schema,
2050
2063
  formData,
2051
2064
  formContext,
2052
- registry
2065
+ registry,
2066
+ optionalDataControl,
2067
+ className: renderOptionalField ? "rjsf-optional-object-field" : void 0
2053
2068
  };
2054
2069
  return /* @__PURE__ */ jsxRuntime.jsx(Template, { ...templateProps, onAddClick: this.handleAddClick });
2055
2070
  }
2056
2071
  };
2057
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
+ }
2058
2130
  var COMPONENT_TYPES = {
2059
2131
  array: "ArrayField",
2060
2132
  boolean: "BooleanField",
@@ -2368,12 +2440,12 @@
2368
2440
  }
2369
2441
  var StringField_default = StringField;
2370
2442
  function NullField(props) {
2371
- const { name, formData, onChange } = props;
2443
+ const { formData, onChange, fieldPathId } = props;
2372
2444
  react.useEffect(() => {
2373
2445
  if (formData === void 0) {
2374
- onChange(null, [name]);
2446
+ onChange(null, fieldPathId.path);
2375
2447
  }
2376
- }, [name, formData, onChange]);
2448
+ }, [fieldPathId, formData, onChange]);
2377
2449
  return null;
2378
2450
  }
2379
2451
  var NullField_default = NullField;
@@ -2391,6 +2463,7 @@
2391
2463
  NumberField: NumberField_default,
2392
2464
  ObjectField: ObjectField_default,
2393
2465
  OneOfField: MultiSchemaField_default,
2466
+ OptionalDataControlsField,
2394
2467
  SchemaField: SchemaField_default,
2395
2468
  StringField: StringField_default,
2396
2469
  NullField: NullField_default
@@ -2525,6 +2598,7 @@
2525
2598
  fieldPathId,
2526
2599
  uiSchema,
2527
2600
  items,
2601
+ optionalDataControl,
2528
2602
  onAddClick,
2529
2603
  readonly,
2530
2604
  registry,
@@ -2548,6 +2622,7 @@
2548
2622
  registry,
2549
2623
  uiOptions
2550
2624
  );
2625
+ const showOptionalDataControlInTitle = !readonly && !disabled;
2551
2626
  const {
2552
2627
  ButtonTemplates: { AddButton: AddButton2 }
2553
2628
  } = registry.templates;
@@ -2560,7 +2635,8 @@
2560
2635
  required,
2561
2636
  schema,
2562
2637
  uiSchema,
2563
- registry
2638
+ registry,
2639
+ optionalDataControl: showOptionalDataControlInTitle ? optionalDataControl : void 0
2564
2640
  }
2565
2641
  ),
2566
2642
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2573,6 +2649,7 @@
2573
2649
  registry
2574
2650
  }
2575
2651
  ),
2652
+ !showOptionalDataControlInTitle ? optionalDataControl : void 0,
2576
2653
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "row array-item-list", children: items && items.map(({ key, ...itemProps }) => /* @__PURE__ */ jsxRuntime.jsx(ArrayFieldItemTemplate2, { ...itemProps }, key)) }),
2577
2654
  canAdd && /* @__PURE__ */ jsxRuntime.jsx(
2578
2655
  AddButton2,
@@ -2588,7 +2665,7 @@
2588
2665
  ] });
2589
2666
  }
2590
2667
  function ArrayFieldTitleTemplate(props) {
2591
- const { fieldPathId, title, schema, uiSchema, required, registry } = props;
2668
+ const { fieldPathId, title, schema, uiSchema, required, registry, optionalDataControl } = props;
2592
2669
  const options = utils.getUiOptions(uiSchema, registry.globalUiOptions);
2593
2670
  const { label: displayLabel = true } = options;
2594
2671
  if (!title || !displayLabel) {
@@ -2607,7 +2684,8 @@
2607
2684
  required,
2608
2685
  schema,
2609
2686
  uiSchema,
2610
- registry
2687
+ registry,
2688
+ optionalDataControl
2611
2689
  }
2612
2690
  );
2613
2691
  }
@@ -2723,6 +2801,7 @@
2723
2801
  return /* @__PURE__ */ jsxRuntime.jsx(IconButton, { title: translateString(utils.TranslatableString.RemoveButton), ...props, iconType: "danger", icon: "remove" });
2724
2802
  }
2725
2803
  function AddButton({
2804
+ id,
2726
2805
  className,
2727
2806
  onClick,
2728
2807
  disabled,
@@ -2732,6 +2811,7 @@
2732
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(
2733
2812
  IconButton,
2734
2813
  {
2814
+ id,
2735
2815
  iconType: "info",
2736
2816
  icon: "plus",
2737
2817
  className: "btn-add col-xs-12",
@@ -2851,11 +2931,13 @@
2851
2931
  }
2852
2932
  function ObjectFieldTemplate(props) {
2853
2933
  const {
2934
+ className,
2854
2935
  description,
2855
2936
  disabled,
2856
2937
  formData,
2857
2938
  fieldPathId,
2858
2939
  onAddClick,
2940
+ optionalDataControl,
2859
2941
  properties,
2860
2942
  readonly,
2861
2943
  registry,
@@ -2871,10 +2953,11 @@
2871
2953
  registry,
2872
2954
  options
2873
2955
  );
2956
+ const showOptionalDataControlInTitle = !readonly && !disabled;
2874
2957
  const {
2875
2958
  ButtonTemplates: { AddButton: AddButton2 }
2876
2959
  } = registry.templates;
2877
- return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { id: fieldPathId.$id, children: [
2960
+ return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className, id: fieldPathId.$id, children: [
2878
2961
  title && /* @__PURE__ */ jsxRuntime.jsx(
2879
2962
  TitleFieldTemplate,
2880
2963
  {
@@ -2883,7 +2966,8 @@
2883
2966
  required,
2884
2967
  schema,
2885
2968
  uiSchema,
2886
- registry
2969
+ registry,
2970
+ optionalDataControl: showOptionalDataControlInTitle ? optionalDataControl : void 0
2887
2971
  }
2888
2972
  ),
2889
2973
  description && /* @__PURE__ */ jsxRuntime.jsx(
@@ -2896,6 +2980,7 @@
2896
2980
  registry
2897
2981
  }
2898
2982
  ),
2983
+ !showOptionalDataControlInTitle ? optionalDataControl : void 0,
2899
2984
  properties.map((prop) => prop.content),
2900
2985
  utils.canExpand(schema, uiSchema, formData) && /* @__PURE__ */ jsxRuntime.jsx(
2901
2986
  AddButton2,
@@ -2910,12 +2995,42 @@
2910
2995
  )
2911
2996
  ] });
2912
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
+ }
2913
3027
  var REQUIRED_FIELD_SYMBOL2 = "*";
2914
3028
  function TitleField(props) {
2915
- const { id, title, required } = props;
3029
+ const { id, title, required, optionalDataControl } = props;
2916
3030
  return /* @__PURE__ */ jsxRuntime.jsxs("legend", { id, children: [
2917
3031
  title,
2918
- 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 })
2919
3034
  ] });
2920
3035
  }
2921
3036
  function UnsupportedField(props) {
@@ -3015,6 +3130,7 @@
3015
3130
  GridTemplate,
3016
3131
  MultiSchemaFieldTemplate,
3017
3132
  ObjectFieldTemplate,
3133
+ OptionalDataControlsTemplate,
3018
3134
  TitleFieldTemplate: TitleField,
3019
3135
  UnsupportedFieldTemplate: UnsupportedField_default,
3020
3136
  WrapIfAdditionalTemplate
@@ -3934,7 +4050,12 @@
3934
4050
  );
3935
4051
  }
3936
4052
  const rootSchema = schemaUtils.getRootSchema();
3937
- const formData = schemaUtils.getDefaultFormState(rootSchema, inputFormData);
4053
+ const formData = schemaUtils.getDefaultFormState(
4054
+ rootSchema,
4055
+ inputFormData,
4056
+ false,
4057
+ state.initialDefaultsGenerated
4058
+ );
3938
4059
  const _retrievedSchema = this.updateRetrievedSchema(
3939
4060
  retrievedSchema ?? schemaUtils.retrieveSchema(rootSchema, formData)
3940
4061
  );
@@ -3957,19 +4078,22 @@
3957
4078
  let schemaValidationErrors = state.schemaValidationErrors;
3958
4079
  let schemaValidationErrorSchema = state.schemaValidationErrorSchema;
3959
4080
  if (mustValidate && !skipLiveValidate) {
3960
- const schemaValidation = this.validate(formData, rootSchema, schemaUtils, _retrievedSchema);
3961
- errors = schemaValidation.errors;
3962
- if (retrievedSchema === void 0) {
3963
- errorSchema = schemaValidation.errorSchema;
3964
- } else {
3965
- errorSchema = utils.mergeObjects(
3966
- this.state?.errorSchema,
3967
- schemaValidation.errorSchema,
3968
- "preventDuplicates"
3969
- );
3970
- }
3971
- schemaValidationErrors = errors;
3972
- schemaValidationErrorSchema = errorSchema;
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;
3973
4097
  } else {
3974
4098
  const currentErrors = getCurrentErrors();
3975
4099
  errors = currentErrors.errors;
@@ -3988,11 +4112,9 @@
3988
4112
  "preventDuplicates"
3989
4113
  );
3990
4114
  }
3991
- }
3992
- if (props.extraErrors) {
3993
- const merged = utils.validationDataMerge({ errorSchema, errors }, props.extraErrors);
3994
- errorSchema = merged.errorSchema;
3995
- errors = merged.errors;
4115
+ const mergedErrors = this.mergeErrors({ errorSchema, errors }, props.extraErrors, state.customErrors);
4116
+ errors = mergedErrors.errors;
4117
+ errorSchema = mergedErrors.errorSchema;
3996
4118
  }
3997
4119
  const fieldPathId = utils.toFieldPathId("", this.getGlobalFormOptions(this.props));
3998
4120
  const nextState = {
@@ -4006,7 +4128,8 @@
4006
4128
  errorSchema,
4007
4129
  schemaValidationErrors,
4008
4130
  schemaValidationErrorSchema,
4009
- retrievedSchema: _retrievedSchema
4131
+ retrievedSchema: _retrievedSchema,
4132
+ initialDefaultsGenerated: true
4010
4133
  };
4011
4134
  return nextState;
4012
4135
  }
@@ -4020,20 +4143,6 @@
4020
4143
  const { experimental_componentUpdateStrategy = "customDeep" } = this.props;
4021
4144
  return utils.shouldRender(this, nextProps, nextState, experimental_componentUpdateStrategy);
4022
4145
  }
4023
- /** Gets the previously raised customValidate errors.
4024
- *
4025
- * @returns the previous customValidate errors
4026
- */
4027
- getPreviousCustomValidateErrors() {
4028
- const { customValidate, uiSchema } = this.props;
4029
- const prevFormData = this.state.formData;
4030
- let customValidateErrors = {};
4031
- if (typeof customValidate === "function") {
4032
- const errorHandler = customValidate(prevFormData, utils.createErrorHandler(prevFormData), uiSchema);
4033
- customValidateErrors = utils.unwrapErrorHandler(errorHandler);
4034
- }
4035
- return customValidateErrors;
4036
- }
4037
4146
  /** Validates the `formData` against the `schema` using the `altSchemaUtils` (if provided otherwise it uses the
4038
4147
  * `schemaUtils` in the state), returning the results.
4039
4148
  *
@@ -4067,6 +4176,59 @@
4067
4176
  }
4068
4177
  return null;
4069
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
+ }
4070
4232
  /** Returns the `formData` with only the elements specified in the `fields` list
4071
4233
  *
4072
4234
  * @param formData - The data for the `Form`
@@ -4126,51 +4288,6 @@
4126
4288
  const fieldNames = this.getFieldNames(pathSchema, formData);
4127
4289
  return this.getUsedFormData(formData, fieldNames);
4128
4290
  };
4129
- /** Filtering errors based on your retrieved schema to only show errors for properties in the selected branch.
4130
- *
4131
- * @param schemaErrors - The schema errors to filter
4132
- * @param [resolvedSchema] - An optionally resolved schema to use for performance reasons
4133
- * @param [formData] - The formData to help filter errors
4134
- * @private
4135
- */
4136
- filterErrorsBasedOnSchema(schemaErrors, resolvedSchema, formData) {
4137
- const { retrievedSchema, schemaUtils } = this.state;
4138
- const _retrievedSchema = resolvedSchema ?? retrievedSchema;
4139
- const pathSchema = schemaUtils.toPathSchema(_retrievedSchema, "", formData);
4140
- const fieldNames = this.getFieldNames(pathSchema, formData);
4141
- const filteredErrors = _pick(schemaErrors, fieldNames);
4142
- if (resolvedSchema?.type !== "object" && resolvedSchema?.type !== "array") {
4143
- filteredErrors[utils.ERRORS_KEY] = schemaErrors[utils.ERRORS_KEY];
4144
- }
4145
- const prevCustomValidateErrors = this.getPreviousCustomValidateErrors();
4146
- const filterPreviousCustomErrors = (errors = [], prevCustomErrors) => {
4147
- if (errors.length === 0) {
4148
- return errors;
4149
- }
4150
- return errors.filter((error) => {
4151
- return !prevCustomErrors.includes(error);
4152
- });
4153
- };
4154
- const filterNilOrEmptyErrors = (errors, previousCustomValidateErrors = {}) => {
4155
- _forEach(errors, (errorAtKey, errorKey) => {
4156
- const prevCustomValidateErrorAtKey = previousCustomValidateErrors[errorKey];
4157
- if (_isNil(errorAtKey) || Array.isArray(errorAtKey) && errorAtKey.length === 0) {
4158
- delete errors[errorKey];
4159
- } else if (utils.isObject(errorAtKey) && utils.isObject(prevCustomValidateErrorAtKey) && Array.isArray(prevCustomValidateErrorAtKey?.[utils.ERRORS_KEY])) {
4160
- errors[errorKey] = {
4161
- [utils.ERRORS_KEY]: filterPreviousCustomErrors(
4162
- errorAtKey[utils.ERRORS_KEY],
4163
- prevCustomValidateErrorAtKey?.[utils.ERRORS_KEY]
4164
- )
4165
- };
4166
- } else if (typeof errorAtKey === "object" && !Array.isArray(errorAtKey[utils.ERRORS_KEY])) {
4167
- filterNilOrEmptyErrors(errorAtKey, previousCustomValidateErrors[errorKey]);
4168
- }
4169
- });
4170
- return errors;
4171
- };
4172
- return filterNilOrEmptyErrors(filteredErrors, prevCustomValidateErrors);
4173
- }
4174
4291
  /** Pushes the given change information into the `pendingChanges` array and then calls `processPendingChanges()` if
4175
4292
  * the array only contains a single pending change.
4176
4293
  *
@@ -4199,13 +4316,14 @@
4199
4316
  return;
4200
4317
  }
4201
4318
  const { newValue, path, id } = this.pendingChanges[0];
4202
- let { newErrorSchema } = this.pendingChanges[0];
4319
+ const { newErrorSchema } = this.pendingChanges[0];
4203
4320
  const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
4204
- const { formData: oldFormData, schemaUtils, schema, errorSchema, fieldPathId } = this.state;
4321
+ const { formData: oldFormData, schemaUtils, schema, fieldPathId, schemaValidationErrorSchema, errors } = this.state;
4322
+ let { customErrors, errorSchema: originalErrorSchema } = this.state;
4205
4323
  const rootPathId = fieldPathId.path[0] || "";
4206
4324
  const isRootPath = !path || path.length === 0 || path.length === 1 && path[0] === rootPathId;
4207
4325
  let retrievedSchema = this.state.retrievedSchema;
4208
- let formData = isRootPath ? newValue : _cloneDeep(oldFormData);
4326
+ let formData = isRootPath ? newValue : cloneDeep(oldFormData);
4209
4327
  if (utils.isObject(formData) || Array.isArray(formData)) {
4210
4328
  if (!isRootPath) {
4211
4329
  set(formData, path, newValue);
@@ -4223,39 +4341,44 @@
4223
4341
  formData: newFormData
4224
4342
  };
4225
4343
  }
4226
- if (newErrorSchema && !isRootPath) {
4227
- const errorSchemaCopy = _cloneDeep(errorSchema);
4228
- set(errorSchemaCopy, path, newErrorSchema);
4229
- newErrorSchema = errorSchemaCopy;
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
+ }
4361
+ }
4362
+ } else if (customErrors && get2(customErrors.ErrorSchema, [...path, utils.ERRORS_KEY])) {
4363
+ customErrors.clearErrors(path);
4230
4364
  }
4231
4365
  if (mustValidate && this.pendingChanges.length === 1) {
4232
- const schemaValidation = this.validate(newFormData, schema, schemaUtils, retrievedSchema);
4233
- let errors = schemaValidation.errors;
4234
- let errorSchema2 = schemaValidation.errorSchema;
4235
- const schemaValidationErrors = errors;
4236
- const schemaValidationErrorSchema = errorSchema2;
4237
- if (extraErrors) {
4238
- const merged = utils.validationDataMerge(schemaValidation, extraErrors);
4239
- errorSchema2 = merged.errorSchema;
4240
- errors = merged.errors;
4241
- }
4242
- if (newErrorSchema) {
4243
- const filteredErrors = this.filterErrorsBasedOnSchema(newErrorSchema, retrievedSchema, newFormData);
4244
- errorSchema2 = utils.mergeObjects(errorSchema2, filteredErrors, "preventDuplicates");
4245
- }
4246
- state = {
4247
- formData: newFormData,
4248
- errors,
4249
- errorSchema: errorSchema2,
4250
- schemaValidationErrors,
4251
- schemaValidationErrorSchema
4252
- };
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 };
4253
4376
  } else if (!noValidate && newErrorSchema) {
4254
- const errorSchema2 = extraErrors ? utils.mergeObjects(newErrorSchema, extraErrors, "preventDuplicates") : newErrorSchema;
4377
+ const mergedErrors = this.mergeErrors({ errorSchema: originalErrorSchema, errors }, extraErrors, customErrors);
4255
4378
  state = {
4256
4379
  formData: newFormData,
4257
- errorSchema: errorSchema2,
4258
- errors: utils.toErrorList(errorSchema2)
4380
+ ...mergedErrors,
4381
+ customErrors
4259
4382
  };
4260
4383
  }
4261
4384
  this.setState(state, () => {
@@ -4294,7 +4417,9 @@
4294
4417
  errorSchema: {},
4295
4418
  errors: [],
4296
4419
  schemaValidationErrors: [],
4297
- schemaValidationErrorSchema: {}
4420
+ schemaValidationErrorSchema: {},
4421
+ initialDefaultsGenerated: false,
4422
+ customErrors: void 0
4298
4423
  };
4299
4424
  this.setState(state, () => onChange && onChange({ ...this.state, ...state }));
4300
4425
  };