@rjsf/core 6.4.1 → 6.5.0

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 (30) hide show
  1. package/dist/core.umd.js +102 -38
  2. package/dist/index.cjs +102 -38
  3. package/dist/index.cjs.map +3 -3
  4. package/dist/index.esm.js +114 -44
  5. package/dist/index.esm.js.map +3 -3
  6. package/lib/components/Form.d.ts +6 -0
  7. package/lib/components/Form.d.ts.map +1 -1
  8. package/lib/components/Form.js +30 -14
  9. package/lib/components/fields/ArrayField.d.ts.map +1 -1
  10. package/lib/components/fields/ArrayField.js +5 -1
  11. package/lib/components/fields/ObjectField.d.ts.map +1 -1
  12. package/lib/components/fields/ObjectField.js +29 -5
  13. package/lib/components/templates/WrapIfAdditionalTemplate.d.ts.map +1 -1
  14. package/lib/components/templates/WrapIfAdditionalTemplate.js +1 -1
  15. package/lib/components/widgets/CheckboxesWidget.d.ts +1 -1
  16. package/lib/components/widgets/CheckboxesWidget.d.ts.map +1 -1
  17. package/lib/components/widgets/CheckboxesWidget.js +7 -5
  18. package/lib/components/widgets/RadioWidget.d.ts.map +1 -1
  19. package/lib/components/widgets/RadioWidget.js +5 -4
  20. package/lib/components/widgets/SelectWidget.d.ts.map +1 -1
  21. package/lib/components/widgets/SelectWidget.js +11 -10
  22. package/lib/tsconfig.tsbuildinfo +1 -1
  23. package/package.json +7 -7
  24. package/src/components/Form.tsx +59 -15
  25. package/src/components/fields/ArrayField.tsx +6 -2
  26. package/src/components/fields/ObjectField.tsx +30 -5
  27. package/src/components/templates/WrapIfAdditionalTemplate.tsx +1 -0
  28. package/src/components/widgets/CheckboxesWidget.tsx +12 -7
  29. package/src/components/widgets/RadioWidget.tsx +9 -6
  30. package/src/components/widgets/SelectWidget.tsx +14 -11
package/dist/index.esm.js CHANGED
@@ -4,12 +4,12 @@ import {
4
4
  createSchemaUtils,
5
5
  deepEquals as deepEquals2,
6
6
  ErrorSchemaBuilder,
7
- expandUiSchemaDefinitions,
8
7
  getChangedFields,
9
8
  getTemplate as getTemplate28,
10
9
  getUiOptions as getUiOptions21,
11
10
  isObject as isObject6,
12
11
  mergeObjects,
12
+ removeOptionalEmptyObjects,
13
13
  shouldRender as shouldRender2,
14
14
  SUBMIT_BTN_OPTIONS_KEY,
15
15
  toErrorList,
@@ -141,7 +141,7 @@ function ArrayAsMultiSelect(props) {
141
141
  } = props;
142
142
  const { widgets: widgets2, schemaUtils, globalFormOptions, globalUiOptions } = registry;
143
143
  const itemsSchema = schemaUtils.retrieveSchema(schema.items, items);
144
- const itemsUiSchema = uiSchema?.items ?? {};
144
+ const itemsUiSchema = uiSchema?.items ?? uiSchema;
145
145
  const enumOptions = optionsList(itemsSchema, itemsUiSchema);
146
146
  const { widget = "select", title: uiTitle, ...options } = getUiOptions(uiSchema, globalUiOptions);
147
147
  const Widget = getWidget(schema, widget, widgets2);
@@ -474,6 +474,7 @@ function NormalArray(props) {
474
474
  name: name && `${name}-${index}`,
475
475
  registry,
476
476
  uiOptions,
477
+ parentUiSchema: uiSchema,
477
478
  hideError,
478
479
  readonly,
479
480
  disabled,
@@ -591,6 +592,7 @@ function FixedArray(props) {
591
592
  name: name && `${name}-${index}`,
592
593
  registry,
593
594
  uiOptions,
595
+ parentUiSchema: uiSchema,
594
596
  hideError,
595
597
  readonly,
596
598
  disabled,
@@ -1916,7 +1918,7 @@ function NumberField(props) {
1916
1918
  var NumberField_default = NumberField;
1917
1919
 
1918
1920
  // src/components/fields/ObjectField.tsx
1919
- import { useCallback as useCallback4, useState as useState5 } from "react";
1921
+ import { useCallback as useCallback4, useRef, useState as useState5 } from "react";
1920
1922
  import {
1921
1923
  ADDITIONAL_PROPERTY_FLAG,
1922
1924
  ANY_OF_KEY as ANY_OF_KEY4,
@@ -2064,10 +2066,13 @@ function ObjectField(props) {
2064
2066
  } = props;
2065
2067
  const { fields: fields2, schemaUtils, translateString, globalUiOptions } = registry;
2066
2068
  const { OptionalDataControlsField: OptionalDataControlsField2 } = fields2;
2069
+ const formDataRef = useRef(formData);
2070
+ formDataRef.current = formData;
2067
2071
  const schema = schemaUtils.retrieveSchema(rawSchema, formData, true);
2068
2072
  const uiOptions = getUiOptions8(uiSchema, globalUiOptions);
2069
2073
  const { properties: schemaProperties = {} } = schema;
2070
2074
  const childFieldPathId = props.childFieldPathId ?? fieldPathId;
2075
+ const lastRenamedProperty = useRef({ previousKey: "", currentKey: void 0 });
2071
2076
  const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
2072
2077
  const description = uiOptions.description ?? schema.description;
2073
2078
  const renderOptionalField = shouldRenderOptionalField3(registry, schema, required, uiSchema);
@@ -2117,14 +2122,19 @@ function ObjectField(props) {
2117
2122
  const newValue = constValue ?? defaultValue ?? getDefaultValue(translateString2, type);
2118
2123
  set4(newFormData, newKey, newValue);
2119
2124
  }
2125
+ if (lastRenamedProperty.current.previousKey === newKey) {
2126
+ lastRenamedProperty.current.currentKey = newKey;
2127
+ lastRenamedProperty.current.previousKey = getAvailableKey(newKey, newFormData);
2128
+ }
2120
2129
  onChange(newFormData, childFieldPathId.path);
2121
2130
  }, [formData, onChange, registry, childFieldPathId, getAvailableKey, schema]);
2122
2131
  const handleKeyRename = useCallback4(
2123
2132
  (oldKey, newKey) => {
2124
2133
  if (oldKey !== newKey) {
2125
- const actualNewKey = getAvailableKey(newKey, formData);
2134
+ const currentFormData = formDataRef.current;
2135
+ const actualNewKey = getAvailableKey(newKey, currentFormData);
2126
2136
  const newFormData = {
2127
- ...formData
2137
+ ...currentFormData
2128
2138
  };
2129
2139
  const newKeys = { [oldKey]: actualNewKey };
2130
2140
  const keyValues = Object.keys(newFormData).map((key) => {
@@ -2132,10 +2142,15 @@ function ObjectField(props) {
2132
2142
  return { [newKey2]: newFormData[key] };
2133
2143
  });
2134
2144
  const renamedObj = Object.assign({}, ...keyValues);
2145
+ formDataRef.current = renamedObj;
2146
+ if (oldKey !== lastRenamedProperty.current.currentKey) {
2147
+ lastRenamedProperty.current.previousKey = oldKey;
2148
+ }
2149
+ lastRenamedProperty.current.currentKey = actualNewKey;
2135
2150
  onChange(renamedObj, childFieldPathId.path);
2136
2151
  }
2137
2152
  },
2138
- [formData, onChange, childFieldPathId, getAvailableKey]
2153
+ [onChange, childFieldPathId, getAvailableKey]
2139
2154
  );
2140
2155
  const handleRemoveProperty = useCallback4(
2141
2156
  (key) => {
@@ -2143,6 +2158,12 @@ function ObjectField(props) {
2143
2158
  },
2144
2159
  [onChange, childFieldPathId]
2145
2160
  );
2161
+ const getStableKey = useCallback4((property) => {
2162
+ if (lastRenamedProperty.current.currentKey === property) {
2163
+ return lastRenamedProperty.current.previousKey;
2164
+ }
2165
+ return property;
2166
+ }, []);
2146
2167
  if (!renderOptionalField || hasFormData) {
2147
2168
  try {
2148
2169
  const properties = Object.keys(schemaProperties);
@@ -2185,7 +2206,7 @@ function ObjectField(props) {
2185
2206
  readonly,
2186
2207
  hideError
2187
2208
  },
2188
- name2
2209
+ getStableKey(name2)
2189
2210
  );
2190
2211
  return {
2191
2212
  content,
@@ -3491,7 +3512,8 @@ function WrapIfAdditionalTemplate(props) {
3491
3512
  id: `${id}-key`,
3492
3513
  onBlur: onKeyRenameBlur,
3493
3514
  defaultValue: label
3494
- }
3515
+ },
3516
+ label
3495
3517
  )
3496
3518
  ] }) }),
3497
3519
  /* @__PURE__ */ jsx38("div", { className: "form-additional form-group col-xs-5", children }),
@@ -3668,17 +3690,19 @@ var CheckboxWidget_default = CheckboxWidget;
3668
3690
  import { useCallback as useCallback9 } from "react";
3669
3691
  import {
3670
3692
  ariaDescribedByIds as ariaDescribedByIds3,
3693
+ enumOptionValueDecoder,
3694
+ enumOptionValueEncoder,
3671
3695
  enumOptionsDeselectValue,
3672
3696
  enumOptionsIsSelected,
3673
3697
  enumOptionsSelectValue,
3674
- enumOptionsValueForIndex,
3698
+ getOptionValueFormat,
3675
3699
  optionId
3676
3700
  } from "@rjsf/utils";
3677
3701
  import { jsx as jsx42, jsxs as jsxs17 } from "react/jsx-runtime";
3678
3702
  function CheckboxesWidget({
3679
3703
  id,
3680
3704
  disabled,
3681
- options: { inline = false, enumOptions, enumDisabled, emptyValue },
3705
+ options,
3682
3706
  value,
3683
3707
  autofocus = false,
3684
3708
  readonly,
@@ -3687,14 +3711,16 @@ function CheckboxesWidget({
3687
3711
  onFocus,
3688
3712
  htmlName
3689
3713
  }) {
3714
+ const { inline = false, enumOptions, enumDisabled, emptyValue } = options;
3715
+ const optionValueFormat = getOptionValueFormat(options);
3690
3716
  const checkboxesValues = Array.isArray(value) ? value : [value];
3691
3717
  const handleBlur = useCallback9(
3692
- ({ target }) => onBlur(id, enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3693
- [onBlur, id, enumOptions, emptyValue]
3718
+ ({ target }) => onBlur(id, enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3719
+ [onBlur, id, enumOptions, emptyValue, optionValueFormat]
3694
3720
  );
3695
3721
  const handleFocus = useCallback9(
3696
- ({ target }) => onFocus(id, enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3697
- [onFocus, id, enumOptions, emptyValue]
3722
+ ({ target }) => onFocus(id, enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3723
+ [onFocus, id, enumOptions, emptyValue, optionValueFormat]
3698
3724
  );
3699
3725
  return /* @__PURE__ */ jsx42("div", { className: "checkboxes", id, children: Array.isArray(enumOptions) && enumOptions.map((option, index) => {
3700
3726
  const checked = enumOptionsIsSelected(option.value, checkboxesValues);
@@ -3715,7 +3741,7 @@ function CheckboxesWidget({
3715
3741
  id: optionId(id, index),
3716
3742
  name: htmlName || id,
3717
3743
  checked,
3718
- value: String(index),
3744
+ value: enumOptionValueEncoder(option.value, index, optionValueFormat),
3719
3745
  disabled: disabled || itemDisabled || readonly,
3720
3746
  autoFocus: autofocus && index === 0,
3721
3747
  onChange: handleChange,
@@ -3888,8 +3914,10 @@ function PasswordWidget(props) {
3888
3914
  import { useCallback as useCallback11 } from "react";
3889
3915
  import {
3890
3916
  ariaDescribedByIds as ariaDescribedByIds4,
3917
+ enumOptionValueDecoder as enumOptionValueDecoder2,
3918
+ enumOptionValueEncoder as enumOptionValueEncoder2,
3891
3919
  enumOptionsIsSelected as enumOptionsIsSelected2,
3892
- enumOptionsValueForIndex as enumOptionsValueForIndex2,
3920
+ getOptionValueFormat as getOptionValueFormat2,
3893
3921
  optionId as optionId2
3894
3922
  } from "@rjsf/utils";
3895
3923
  import { jsx as jsx50, jsxs as jsxs19 } from "react/jsx-runtime";
@@ -3907,13 +3935,14 @@ function RadioWidget({
3907
3935
  htmlName
3908
3936
  }) {
3909
3937
  const { enumOptions, enumDisabled, inline, emptyValue } = options;
3938
+ const optionValueFormat = getOptionValueFormat2(options);
3910
3939
  const handleBlur = useCallback11(
3911
- ({ target }) => onBlur(id, enumOptionsValueForIndex2(target && target.value, enumOptions, emptyValue)),
3912
- [onBlur, enumOptions, emptyValue, id]
3940
+ ({ target }) => onBlur(id, enumOptionValueDecoder2(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3941
+ [onBlur, enumOptions, emptyValue, id, optionValueFormat]
3913
3942
  );
3914
3943
  const handleFocus = useCallback11(
3915
- ({ target }) => onFocus(id, enumOptionsValueForIndex2(target && target.value, enumOptions, emptyValue)),
3916
- [onFocus, enumOptions, emptyValue, id]
3944
+ ({ target }) => onFocus(id, enumOptionValueDecoder2(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3945
+ [onFocus, enumOptions, emptyValue, id, optionValueFormat]
3917
3946
  );
3918
3947
  return /* @__PURE__ */ jsx50("div", { className: "field-radio-group", id, role: "radiogroup", children: Array.isArray(enumOptions) && enumOptions.map((option, i) => {
3919
3948
  const checked = enumOptionsIsSelected2(option.value, value);
@@ -3929,7 +3958,7 @@ function RadioWidget({
3929
3958
  checked,
3930
3959
  name: htmlName || id,
3931
3960
  required,
3932
- value: String(i),
3961
+ value: enumOptionValueEncoder2(option.value, i, optionValueFormat),
3933
3962
  disabled: disabled || itemDisabled || readonly,
3934
3963
  autoFocus: autofocus && i === 0,
3935
3964
  onChange: handleChange,
@@ -4068,8 +4097,10 @@ function RatingWidget({
4068
4097
  import { useCallback as useCallback13 } from "react";
4069
4098
  import {
4070
4099
  ariaDescribedByIds as ariaDescribedByIds5,
4071
- enumOptionsIndexForValue,
4072
- enumOptionsValueForIndex as enumOptionsValueForIndex3
4100
+ enumOptionSelectedValue,
4101
+ enumOptionValueDecoder as enumOptionValueDecoder3,
4102
+ enumOptionValueEncoder as enumOptionValueEncoder3,
4103
+ getOptionValueFormat as getOptionValueFormat3
4073
4104
  } from "@rjsf/utils";
4074
4105
  import { jsx as jsx53, jsxs as jsxs22 } from "react/jsx-runtime";
4075
4106
  function getValue(event, multiple) {
@@ -4096,28 +4127,29 @@ function SelectWidget({
4096
4127
  }) {
4097
4128
  const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;
4098
4129
  const emptyValue = multiple ? [] : "";
4130
+ const optionValueFormat = getOptionValueFormat3(options);
4099
4131
  const handleFocus = useCallback13(
4100
4132
  (event) => {
4101
4133
  const newValue = getValue(event, multiple);
4102
- return onFocus(id, enumOptionsValueForIndex3(newValue, enumOptions, optEmptyVal));
4134
+ return onFocus(id, enumOptionValueDecoder3(newValue, enumOptions, optionValueFormat, optEmptyVal));
4103
4135
  },
4104
- [onFocus, id, multiple, enumOptions, optEmptyVal]
4136
+ [onFocus, id, multiple, enumOptions, optEmptyVal, optionValueFormat]
4105
4137
  );
4106
4138
  const handleBlur = useCallback13(
4107
4139
  (event) => {
4108
4140
  const newValue = getValue(event, multiple);
4109
- return onBlur(id, enumOptionsValueForIndex3(newValue, enumOptions, optEmptyVal));
4141
+ return onBlur(id, enumOptionValueDecoder3(newValue, enumOptions, optionValueFormat, optEmptyVal));
4110
4142
  },
4111
- [onBlur, id, multiple, enumOptions, optEmptyVal]
4143
+ [onBlur, id, multiple, enumOptions, optEmptyVal, optionValueFormat]
4112
4144
  );
4113
4145
  const handleChange = useCallback13(
4114
4146
  (event) => {
4115
4147
  const newValue = getValue(event, multiple);
4116
- return onChange(enumOptionsValueForIndex3(newValue, enumOptions, optEmptyVal));
4148
+ return onChange(enumOptionValueDecoder3(newValue, enumOptions, optionValueFormat, optEmptyVal));
4117
4149
  },
4118
- [onChange, multiple, enumOptions, optEmptyVal]
4150
+ [onChange, multiple, enumOptions, optEmptyVal, optionValueFormat]
4119
4151
  );
4120
- const selectedIndexes = enumOptionsIndexForValue(value, enumOptions, multiple);
4152
+ const selectValue = enumOptionSelectedValue(value, enumOptions, multiple, optionValueFormat, emptyValue);
4121
4153
  const showPlaceholderOption = !multiple && schema.default === void 0;
4122
4154
  return /* @__PURE__ */ jsxs22(
4123
4155
  "select",
@@ -4127,7 +4159,7 @@ function SelectWidget({
4127
4159
  multiple,
4128
4160
  role: "combobox",
4129
4161
  className: "form-control",
4130
- value: typeof selectedIndexes === "undefined" ? emptyValue : selectedIndexes,
4162
+ value: selectValue,
4131
4163
  required,
4132
4164
  disabled: disabled || readonly,
4133
4165
  autoFocus: autofocus,
@@ -4139,7 +4171,7 @@ function SelectWidget({
4139
4171
  showPlaceholderOption && /* @__PURE__ */ jsx53("option", { value: "", children: placeholder }),
4140
4172
  Array.isArray(enumOptions) && enumOptions.map(({ value: value2, label }, i) => {
4141
4173
  const disabled2 = enumDisabled && enumDisabled.indexOf(value2) !== -1;
4142
- return /* @__PURE__ */ jsx53("option", { value: String(i), disabled: disabled2, children: label }, i);
4174
+ return /* @__PURE__ */ jsx53("option", { value: enumOptionValueEncoder3(value2, i, optionValueFormat), disabled: disabled2, children: label }, i);
4143
4175
  })
4144
4176
  ]
4145
4177
  }
@@ -4532,12 +4564,11 @@ var Form = class extends Component3 {
4532
4564
  }
4533
4565
  const newRegistry = this.getRegistry(props, rootSchema, schemaUtils);
4534
4566
  const registry = deepEquals2(state.registry, newRegistry) ? state.registry : newRegistry;
4535
- const expandedUiSchema = registry.uiSchemaDefinitions ? expandUiSchemaDefinitions(rootSchema, uiSchema, registry) : uiSchema;
4536
4567
  const fieldPathId = state.fieldPathId && state.fieldPathId?.[ID_KEY5] === registry.globalFormOptions.idPrefix ? state.fieldPathId : toFieldPathId6("", registry.globalFormOptions);
4537
4568
  const nextState = {
4538
4569
  schemaUtils,
4539
4570
  schema: rootSchema,
4540
- uiSchema: expandedUiSchema,
4571
+ uiSchema,
4541
4572
  fieldPathId,
4542
4573
  formData,
4543
4574
  edit,
@@ -4611,7 +4642,7 @@ var Form = class extends Component3 {
4611
4642
  errors = merged.errors;
4612
4643
  }
4613
4644
  if (customErrors) {
4614
- const merged = validationDataMerge(schemaValidation, customErrors.ErrorSchema, true);
4645
+ const merged = validationDataMerge({ errors, errorSchema }, customErrors.ErrorSchema, true);
4615
4646
  errorSchema = merged.errorSchema;
4616
4647
  errors = merged.errors;
4617
4648
  }
@@ -4719,7 +4750,7 @@ var Form = class extends Component3 {
4719
4750
  this._isProcessingUserChange = true;
4720
4751
  const { newValue, path, id } = this.pendingChanges[0];
4721
4752
  const { newErrorSchema } = this.pendingChanges[0];
4722
- const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
4753
+ const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange, removeEmptyOptionalObjects } = this.props;
4723
4754
  const { formData: oldFormData, schemaUtils, schema, fieldPathId, schemaValidationErrorSchema, errors } = this.state;
4724
4755
  let { customErrors, errorSchema: originalErrorSchema } = this.state;
4725
4756
  const rootPathId = fieldPathId.path[0] || "";
@@ -4748,6 +4779,18 @@ var Form = class extends Component3 {
4748
4779
  formData: newFormData
4749
4780
  };
4750
4781
  }
4782
+ if (removeEmptyOptionalObjects) {
4783
+ newFormData = removeOptionalEmptyObjects(
4784
+ schemaUtils.getValidator(),
4785
+ schema,
4786
+ schemaUtils.getRootSchema(),
4787
+ newFormData
4788
+ );
4789
+ state = {
4790
+ ...state,
4791
+ formData: newFormData
4792
+ };
4793
+ }
4751
4794
  if (newErrorSchema) {
4752
4795
  const oldValidationError = !isRootPath ? _get(schemaValidationErrorSchema, path) : schemaValidationErrorSchema;
4753
4796
  if (!_isEmpty(oldValidationError)) {
@@ -4848,24 +4891,33 @@ var Form = class extends Component3 {
4848
4891
  * @param data - The data associated with the field that was blurred
4849
4892
  */
4850
4893
  onBlur = (id, data) => {
4851
- const { onBlur, omitExtraData, liveOmit, liveValidate } = this.props;
4894
+ const { onBlur, omitExtraData, liveOmit, liveValidate, removeEmptyOptionalObjects } = this.props;
4852
4895
  if (onBlur) {
4853
4896
  onBlur(id, data);
4854
4897
  }
4855
4898
  if (omitExtraData === true && liveOmit === "onBlur" || liveValidate === "onBlur") {
4856
4899
  const { onChange, extraErrors } = this.props;
4857
- const { formData } = this.state;
4900
+ const { formData, schemaUtils, schema } = this.state;
4858
4901
  let newFormData = formData;
4859
4902
  let state = { formData: newFormData };
4860
4903
  if (omitExtraData === true && liveOmit === "onBlur") {
4861
4904
  newFormData = this.omitExtraData(formData);
4862
4905
  state = { formData: newFormData };
4863
4906
  }
4907
+ if (removeEmptyOptionalObjects) {
4908
+ newFormData = removeOptionalEmptyObjects(
4909
+ schemaUtils.getValidator(),
4910
+ schema,
4911
+ schemaUtils.getRootSchema(),
4912
+ newFormData
4913
+ );
4914
+ state = { ...state, formData: newFormData };
4915
+ }
4864
4916
  if (liveValidate === "onBlur") {
4865
- const { schema, schemaUtils, errorSchema, customErrors, retrievedSchema } = this.state;
4917
+ const { schema: schema2, schemaUtils: schemaUtils2, errorSchema, customErrors, retrievedSchema } = this.state;
4866
4918
  const liveValidation = this.liveValidate(
4867
- schema,
4868
- schemaUtils,
4919
+ schema2,
4920
+ schemaUtils2,
4869
4921
  errorSchema,
4870
4922
  newFormData,
4871
4923
  extraErrors,
@@ -4912,11 +4964,20 @@ var Form = class extends Component3 {
4912
4964
  return;
4913
4965
  }
4914
4966
  event.persist();
4915
- const { omitExtraData, extraErrors, noValidate, onSubmit } = this.props;
4967
+ const { omitExtraData, extraErrors, noValidate, onSubmit, removeEmptyOptionalObjects } = this.props;
4916
4968
  let { formData: newFormData } = this.state;
4917
4969
  if (omitExtraData === true) {
4918
4970
  newFormData = this.omitExtraData(newFormData);
4919
4971
  }
4972
+ if (removeEmptyOptionalObjects) {
4973
+ const { schemaUtils, schema } = this.state;
4974
+ newFormData = removeOptionalEmptyObjects(
4975
+ schemaUtils.getValidator(),
4976
+ schema,
4977
+ schemaUtils.getRootSchema(),
4978
+ newFormData
4979
+ );
4980
+ }
4920
4981
  if (noValidate || this.validateFormWithFormData(newFormData)) {
4921
4982
  const errorSchema = extraErrors || {};
4922
4983
  const errors = extraErrors ? toErrorList(extraErrors) : [];
@@ -5013,7 +5074,7 @@ var Form = class extends Component3 {
5013
5074
  const elementId = path.join(idSeparator);
5014
5075
  let field = this.formElement.current.elements[elementId];
5015
5076
  if (!field) {
5016
- field = this.formElement.current.querySelector(`input[id^="${elementId}"`);
5077
+ field = this.formElement.current.querySelector(`input[id^="${elementId}"], button[id^="${elementId}"]`);
5017
5078
  }
5018
5079
  if (field && field.length) {
5019
5080
  field = field[0];
@@ -5081,11 +5142,20 @@ var Form = class extends Component3 {
5081
5142
  * @returns - True if the form is valid, false otherwise.
5082
5143
  */
5083
5144
  validateForm() {
5084
- const { omitExtraData } = this.props;
5145
+ const { omitExtraData, removeEmptyOptionalObjects } = this.props;
5085
5146
  let { formData: newFormData } = this.state;
5086
5147
  if (omitExtraData === true) {
5087
5148
  newFormData = this.omitExtraData(newFormData);
5088
5149
  }
5150
+ if (removeEmptyOptionalObjects) {
5151
+ const { schemaUtils, schema } = this.state;
5152
+ newFormData = removeOptionalEmptyObjects(
5153
+ schemaUtils.getValidator(),
5154
+ schema,
5155
+ schemaUtils.getRootSchema(),
5156
+ newFormData
5157
+ );
5158
+ }
5089
5159
  return this.validateFormWithFormData(newFormData);
5090
5160
  }
5091
5161
  /** Renders the `Form` fields inside the <form> | `tagName` or `_internalFormWrapper`, rendering any errors if