@rjsf/core 6.1.2 → 6.2.4

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 (35) hide show
  1. package/dist/core.umd.js +65 -44
  2. package/dist/index.cjs +65 -44
  3. package/dist/index.cjs.map +3 -3
  4. package/dist/index.esm.js +68 -47
  5. package/dist/index.esm.js.map +3 -3
  6. package/lib/components/Form.d.ts +9 -1
  7. package/lib/components/Form.d.ts.map +1 -1
  8. package/lib/components/Form.js +35 -49
  9. package/lib/components/fields/LayoutMultiSchemaField.d.ts.map +1 -1
  10. package/lib/components/fields/LayoutMultiSchemaField.js +1 -1
  11. package/lib/components/fields/SchemaField.d.ts.map +1 -1
  12. package/lib/components/fields/SchemaField.js +1 -0
  13. package/lib/components/templates/BaseInputTemplate.d.ts.map +1 -1
  14. package/lib/components/templates/BaseInputTemplate.js +7 -1
  15. package/lib/components/templates/ButtonTemplates/IconButton.d.ts +1 -0
  16. package/lib/components/templates/ButtonTemplates/IconButton.d.ts.map +1 -1
  17. package/lib/components/templates/ButtonTemplates/IconButton.js +4 -0
  18. package/lib/components/templates/ButtonTemplates/index.d.ts.map +1 -1
  19. package/lib/components/templates/ButtonTemplates/index.js +2 -1
  20. package/lib/components/templates/ObjectFieldTemplate.d.ts +1 -1
  21. package/lib/components/templates/ObjectFieldTemplate.d.ts.map +1 -1
  22. package/lib/components/templates/ObjectFieldTemplate.js +6 -0
  23. package/lib/components/widgets/TextareaWidget.d.ts +0 -6
  24. package/lib/components/widgets/TextareaWidget.d.ts.map +1 -1
  25. package/lib/components/widgets/TextareaWidget.js +0 -4
  26. package/lib/tsconfig.tsbuildinfo +1 -1
  27. package/package.json +7 -10
  28. package/src/components/Form.tsx +44 -58
  29. package/src/components/fields/LayoutMultiSchemaField.tsx +1 -0
  30. package/src/components/fields/SchemaField.tsx +1 -0
  31. package/src/components/templates/BaseInputTemplate.tsx +13 -1
  32. package/src/components/templates/ButtonTemplates/IconButton.tsx +24 -0
  33. package/src/components/templates/ButtonTemplates/index.ts +2 -1
  34. package/src/components/templates/ObjectFieldTemplate.tsx +9 -0
  35. package/src/components/widgets/TextareaWidget.tsx +0 -5
package/dist/core.umd.js CHANGED
@@ -1462,6 +1462,7 @@
1462
1462
  return /* @__PURE__ */ jsxRuntime.jsx(
1463
1463
  FieldTemplate2,
1464
1464
  {
1465
+ fieldPathId,
1465
1466
  id,
1466
1467
  schema,
1467
1468
  label: (title || schema.title) ?? "",
@@ -2236,6 +2237,7 @@
2236
2237
  rawHelp: typeof help === "string" ? help : void 0,
2237
2238
  errors: errorsComponent,
2238
2239
  rawErrors: hideError ? void 0 : __errors,
2240
+ fieldPathId,
2239
2241
  id,
2240
2242
  label,
2241
2243
  hidden,
@@ -2616,6 +2618,7 @@
2616
2618
  // remove this from ...rest
2617
2619
  ...rest
2618
2620
  } = props;
2621
+ const { ClearButton: ClearButton2 } = registry.templates.ButtonTemplates;
2619
2622
  if (!id) {
2620
2623
  console.log("No id for", props);
2621
2624
  throw new Error(`no id for props ${JSON.stringify(props)}`);
@@ -2642,6 +2645,14 @@
2642
2645
  ({ target }) => onFocus(id, target && target.value),
2643
2646
  [onFocus, id]
2644
2647
  );
2648
+ const _onClear = react.useCallback(
2649
+ (e) => {
2650
+ e.preventDefault();
2651
+ e.stopPropagation();
2652
+ onChange(options.emptyValue ?? "");
2653
+ },
2654
+ [onChange, options.emptyValue]
2655
+ );
2645
2656
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2646
2657
  /* @__PURE__ */ jsxRuntime.jsx(
2647
2658
  "input",
@@ -2661,6 +2672,7 @@
2661
2672
  "aria-describedby": utils.ariaDescribedByIds(id, !!schema.examples)
2662
2673
  }
2663
2674
  ),
2675
+ options.allowClearTextInputs && !readonly && !disabled && inputValue && /* @__PURE__ */ jsxRuntime.jsx(ClearButton2, { registry, onClick: _onClear }),
2664
2676
  Array.isArray(schema.examples) && /* @__PURE__ */ jsxRuntime.jsx("datalist", { id: utils.examplesId(id), children: schema.examples.concat(schema.default && !schema.examples.includes(schema.default) ? [schema.default] : []).map((example) => {
2665
2677
  return /* @__PURE__ */ jsxRuntime.jsx("option", { value: example }, example);
2666
2678
  }) }, `datalist_${id}`)
@@ -2701,6 +2713,30 @@
2701
2713
  } = props;
2702
2714
  return /* @__PURE__ */ jsxRuntime.jsx(IconButton, { title: translateString(utils.TranslatableString.RemoveButton), ...props, iconType: "danger", icon: "remove" });
2703
2715
  }
2716
+ function ClearButton({
2717
+ id,
2718
+ className,
2719
+ onClick,
2720
+ disabled,
2721
+ registry,
2722
+ ...props
2723
+ }) {
2724
+ const { translateString } = registry;
2725
+ return /* @__PURE__ */ jsxRuntime.jsx(
2726
+ IconButton,
2727
+ {
2728
+ id,
2729
+ iconType: "default",
2730
+ icon: "remove",
2731
+ className: "btn-clear col-xs-12",
2732
+ title: translateString(utils.TranslatableString.ClearButton),
2733
+ onClick,
2734
+ disabled,
2735
+ registry,
2736
+ ...props
2737
+ }
2738
+ );
2739
+ }
2704
2740
  function AddButton({
2705
2741
  id,
2706
2742
  className,
@@ -2738,7 +2774,8 @@
2738
2774
  CopyButton,
2739
2775
  MoveDownButton,
2740
2776
  MoveUpButton,
2741
- RemoveButton
2777
+ RemoveButton,
2778
+ ClearButton
2742
2779
  };
2743
2780
  }
2744
2781
  var ButtonTemplates_default = buttonTemplates;
@@ -2887,6 +2924,10 @@
2887
2924
  registry,
2888
2925
  options
2889
2926
  );
2927
+ const isPureUnionSchema = (schema.oneOf || schema.anyOf) && !schema.properties && properties.length === 0;
2928
+ if (isPureUnionSchema) {
2929
+ return null;
2930
+ }
2890
2931
  const showOptionalDataControlInTitle = !readonly && !disabled;
2891
2932
  const {
2892
2933
  ButtonTemplates: { AddButton: AddButton2 }
@@ -3635,10 +3676,6 @@
3635
3676
  }
3636
3677
  );
3637
3678
  }
3638
- TextareaWidget.defaultProps = {
3639
- autofocus: false,
3640
- options: {}
3641
- };
3642
3679
  var TextareaWidget_default = TextareaWidget;
3643
3680
  function TextWidget(props) {
3644
3681
  const { options, registry } = props;
@@ -3719,6 +3756,10 @@
3719
3756
  /** The list of pending changes
3720
3757
  */
3721
3758
  pendingChanges = [];
3759
+ /** Flag to track when we're processing a user-initiated field change.
3760
+ * This prevents componentDidUpdate from reverting oneOf/anyOf option switches.
3761
+ */
3762
+ _isProcessingUserChange = false;
3722
3763
  /** Constructs the `Form` from the `props`. Will setup the initial state from the props. It will also call the
3723
3764
  * `onChange` handler if the initially provided `formData` is modified to add missing default values as part of the
3724
3765
  * state construction.
@@ -3795,7 +3836,13 @@
3795
3836
  componentDidUpdate(_, prevState, snapshot) {
3796
3837
  if (snapshot.shouldUpdate) {
3797
3838
  const { nextState } = snapshot;
3798
- if (!utils.deepEquals(nextState.formData, this.props.formData) && !utils.deepEquals(nextState.formData, prevState.formData) && this.props.onChange) {
3839
+ const nextStateDiffersFromProps = !utils.deepEquals(nextState.formData, this.props.formData);
3840
+ const wasProcessingUserChange = this._isProcessingUserChange;
3841
+ this._isProcessingUserChange = false;
3842
+ if (wasProcessingUserChange && nextStateDiffersFromProps) {
3843
+ return;
3844
+ }
3845
+ if (nextStateDiffersFromProps && !utils.deepEquals(nextState.formData, prevState.formData) && this.props.onChange) {
3799
3846
  this.props.onChange(toIChangeEvent(nextState));
3800
3847
  }
3801
3848
  this.setState(nextState);
@@ -4031,60 +4078,30 @@
4031
4078
  *
4032
4079
  * @param formData - The data for the `Form`
4033
4080
  * @param fields - The fields to keep while filtering
4081
+ * @deprecated - To be removed as an exported `Form` function in a future release; there isn't a planned replacement
4034
4082
  */
4035
4083
  getUsedFormData = (formData, fields2) => {
4036
- if (fields2.length === 0 && typeof formData !== "object") {
4037
- return formData;
4038
- }
4039
- const data = _pick(formData, fields2);
4040
- if (Array.isArray(formData)) {
4041
- return Object.keys(data).map((key) => data[key]);
4042
- }
4043
- return data;
4084
+ return utils.getUsedFormData(formData, fields2);
4044
4085
  };
4045
4086
  /** Returns the list of field names from inspecting the `pathSchema` as well as using the `formData`
4046
4087
  *
4047
4088
  * @param pathSchema - The `PathSchema` object for the form
4048
4089
  * @param [formData] - The form data to use while checking for empty objects/arrays
4090
+ * @deprecated - To be removed as an exported `Form` function in a future release; there isn't a planned replacement
4049
4091
  */
4050
4092
  getFieldNames = (pathSchema, formData) => {
4051
- const formValueHasData = (value, isLeaf) => typeof value !== "object" || isEmpty(value) || isLeaf && !isEmpty(value);
4052
- const getAllPaths = (_obj, acc = [], paths = [[]]) => {
4053
- const objKeys = Object.keys(_obj);
4054
- objKeys.forEach((key) => {
4055
- const data = _obj[key];
4056
- if (typeof data === "object") {
4057
- const newPaths = paths.map((path) => [...path, key]);
4058
- if (data[utils.RJSF_ADDITIONAL_PROPERTIES_FLAG] && data[utils.NAME_KEY] !== "") {
4059
- acc.push(data[utils.NAME_KEY]);
4060
- } else {
4061
- getAllPaths(data, acc, newPaths);
4062
- }
4063
- } else if (key === utils.NAME_KEY && data !== "") {
4064
- paths.forEach((path) => {
4065
- const formValue = get(formData, path);
4066
- const isLeaf = objKeys.length === 1;
4067
- if (formValueHasData(formValue, isLeaf) || Array.isArray(formValue) && formValue.every((val) => formValueHasData(val, isLeaf))) {
4068
- acc.push(path);
4069
- }
4070
- });
4071
- }
4072
- });
4073
- return acc;
4074
- };
4075
- return getAllPaths(pathSchema);
4093
+ return utils.getFieldNames(pathSchema, formData);
4076
4094
  };
4077
4095
  /** Returns the `formData` after filtering to remove any extra data not in a form field
4078
4096
  *
4079
4097
  * @param formData - The data for the `Form`
4080
4098
  * @returns The `formData` after omitting extra data
4099
+ * @deprecated - To be removed as an exported `Form` function in a future release, use `SchemaUtils.omitExtraData`
4100
+ * instead.
4081
4101
  */
4082
4102
  omitExtraData = (formData) => {
4083
4103
  const { schema, schemaUtils } = this.state;
4084
- const retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
4085
- const pathSchema = schemaUtils.toPathSchema(retrievedSchema, "", formData);
4086
- const fieldNames = this.getFieldNames(pathSchema, formData);
4087
- return this.getUsedFormData(formData, fieldNames);
4104
+ return schemaUtils.omitExtraData(schema, formData);
4088
4105
  };
4089
4106
  /** Allows a user to set a value for the provided `fieldPath`, which must be either a dotted path to the field OR a
4090
4107
  * `FieldPathList`. To set the root element, used either `''` or `[]` for the path. Passing undefined will clear the
@@ -4126,6 +4143,7 @@
4126
4143
  if (this.pendingChanges.length === 0) {
4127
4144
  return;
4128
4145
  }
4146
+ this._isProcessingUserChange = true;
4129
4147
  const { newValue, path, id } = this.pendingChanges[0];
4130
4148
  const { newErrorSchema } = this.pendingChanges[0];
4131
4149
  const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
@@ -4135,13 +4153,16 @@
4135
4153
  const isRootPath = !path || path.length === 0 || path.length === 1 && path[0] === rootPathId;
4136
4154
  let retrievedSchema = this.state.retrievedSchema;
4137
4155
  let formData = isRootPath ? newValue : cloneDeep(oldFormData);
4156
+ const hasOnlyUndefinedValues = utils.isObject(formData) && Object.keys(formData).length > 0 && Object.values(formData).every((v) => v === void 0);
4157
+ const wasPreviouslyNull = oldFormData === null || oldFormData === void 0;
4158
+ const inputForDefaults = hasOnlyUndefinedValues && wasPreviouslyNull ? void 0 : formData;
4138
4159
  if (utils.isObject(formData) || Array.isArray(formData)) {
4139
4160
  if (newValue === ADDITIONAL_PROPERTY_KEY_REMOVE) {
4140
4161
  _unset(formData, path);
4141
4162
  } else if (!isRootPath) {
4142
4163
  set(formData, path, newValue);
4143
4164
  }
4144
- const newState = this.getStateFromProps(this.props, formData, void 0, void 0, void 0, true);
4165
+ const newState = this.getStateFromProps(this.props, inputForDefaults, void 0, void 0, void 0, true);
4145
4166
  formData = newState.formData;
4146
4167
  retrievedSchema = newState.retrievedSchema;
4147
4168
  }
package/dist/index.cjs CHANGED
@@ -1565,6 +1565,7 @@ function LayoutMultiSchemaField(props) {
1565
1565
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1566
1566
  FieldTemplate2,
1567
1567
  {
1568
+ fieldPathId,
1568
1569
  id,
1569
1570
  schema,
1570
1571
  label: (title || schema.title) ?? "",
@@ -2375,6 +2376,7 @@ function SchemaFieldRender(props) {
2375
2376
  rawHelp: typeof help === "string" ? help : void 0,
2376
2377
  errors: errorsComponent,
2377
2378
  rawErrors: hideError ? void 0 : __errors,
2379
+ fieldPathId,
2378
2380
  id,
2379
2381
  label,
2380
2382
  hidden,
@@ -2788,6 +2790,7 @@ function BaseInputTemplate(props) {
2788
2790
  // remove this from ...rest
2789
2791
  ...rest
2790
2792
  } = props;
2793
+ const { ClearButton: ClearButton2 } = registry.templates.ButtonTemplates;
2791
2794
  if (!id) {
2792
2795
  console.log("No id for", props);
2793
2796
  throw new Error(`no id for props ${JSON.stringify(props)}`);
@@ -2814,6 +2817,14 @@ function BaseInputTemplate(props) {
2814
2817
  ({ target }) => onFocus(id, target && target.value),
2815
2818
  [onFocus, id]
2816
2819
  );
2820
+ const _onClear = (0, import_react12.useCallback)(
2821
+ (e) => {
2822
+ e.preventDefault();
2823
+ e.stopPropagation();
2824
+ onChange(options.emptyValue ?? "");
2825
+ },
2826
+ [onChange, options.emptyValue]
2827
+ );
2817
2828
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2818
2829
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2819
2830
  "input",
@@ -2833,6 +2844,7 @@ function BaseInputTemplate(props) {
2833
2844
  "aria-describedby": (0, import_utils18.ariaDescribedByIds)(id, !!schema.examples)
2834
2845
  }
2835
2846
  ),
2847
+ options.allowClearTextInputs && !readonly && !disabled && inputValue && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ClearButton2, { registry, onClick: _onClear }),
2836
2848
  Array.isArray(schema.examples) && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("datalist", { id: (0, import_utils18.examplesId)(id), children: schema.examples.concat(schema.default && !schema.examples.includes(schema.default) ? [schema.default] : []).map((example) => {
2837
2849
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: example }, example);
2838
2850
  }) }, `datalist_${id}`)
@@ -2884,6 +2896,30 @@ function RemoveButton(props) {
2884
2896
  } = props;
2885
2897
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(IconButton, { title: translateString(import_utils20.TranslatableString.RemoveButton), ...props, iconType: "danger", icon: "remove" });
2886
2898
  }
2899
+ function ClearButton({
2900
+ id,
2901
+ className,
2902
+ onClick,
2903
+ disabled,
2904
+ registry,
2905
+ ...props
2906
+ }) {
2907
+ const { translateString } = registry;
2908
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2909
+ IconButton,
2910
+ {
2911
+ id,
2912
+ iconType: "default",
2913
+ icon: "remove",
2914
+ className: "btn-clear col-xs-12",
2915
+ title: translateString(import_utils20.TranslatableString.ClearButton),
2916
+ onClick,
2917
+ disabled,
2918
+ registry,
2919
+ ...props
2920
+ }
2921
+ );
2922
+ }
2887
2923
 
2888
2924
  // src/components/templates/ButtonTemplates/AddButton.tsx
2889
2925
  var import_jsx_runtime21 = require("react/jsx-runtime");
@@ -2924,7 +2960,8 @@ function buttonTemplates() {
2924
2960
  CopyButton,
2925
2961
  MoveDownButton,
2926
2962
  MoveUpButton,
2927
- RemoveButton
2963
+ RemoveButton,
2964
+ ClearButton
2928
2965
  };
2929
2966
  }
2930
2967
  var ButtonTemplates_default = buttonTemplates;
@@ -3123,6 +3160,10 @@ function ObjectFieldTemplate(props) {
3123
3160
  registry,
3124
3161
  options
3125
3162
  );
3163
+ const isPureUnionSchema = (schema.oneOf || schema.anyOf) && !schema.properties && properties.length === 0;
3164
+ if (isPureUnionSchema) {
3165
+ return null;
3166
+ }
3126
3167
  const showOptionalDataControlInTitle = !readonly && !disabled;
3127
3168
  const {
3128
3169
  ButtonTemplates: { AddButton: AddButton2 }
@@ -3954,10 +3995,6 @@ function TextareaWidget({
3954
3995
  }
3955
3996
  );
3956
3997
  }
3957
- TextareaWidget.defaultProps = {
3958
- autofocus: false,
3959
- options: {}
3960
- };
3961
3998
  var TextareaWidget_default = TextareaWidget;
3962
3999
 
3963
4000
  // src/components/widgets/TextWidget.tsx
@@ -4058,6 +4095,10 @@ var Form = class extends import_react21.Component {
4058
4095
  /** The list of pending changes
4059
4096
  */
4060
4097
  pendingChanges = [];
4098
+ /** Flag to track when we're processing a user-initiated field change.
4099
+ * This prevents componentDidUpdate from reverting oneOf/anyOf option switches.
4100
+ */
4101
+ _isProcessingUserChange = false;
4061
4102
  /** Constructs the `Form` from the `props`. Will setup the initial state from the props. It will also call the
4062
4103
  * `onChange` handler if the initially provided `formData` is modified to add missing default values as part of the
4063
4104
  * state construction.
@@ -4134,7 +4175,13 @@ var Form = class extends import_react21.Component {
4134
4175
  componentDidUpdate(_, prevState, snapshot) {
4135
4176
  if (snapshot.shouldUpdate) {
4136
4177
  const { nextState } = snapshot;
4137
- if (!(0, import_utils49.deepEquals)(nextState.formData, this.props.formData) && !(0, import_utils49.deepEquals)(nextState.formData, prevState.formData) && this.props.onChange) {
4178
+ const nextStateDiffersFromProps = !(0, import_utils49.deepEquals)(nextState.formData, this.props.formData);
4179
+ const wasProcessingUserChange = this._isProcessingUserChange;
4180
+ this._isProcessingUserChange = false;
4181
+ if (wasProcessingUserChange && nextStateDiffersFromProps) {
4182
+ return;
4183
+ }
4184
+ if (nextStateDiffersFromProps && !(0, import_utils49.deepEquals)(nextState.formData, prevState.formData) && this.props.onChange) {
4138
4185
  this.props.onChange(toIChangeEvent(nextState));
4139
4186
  }
4140
4187
  this.setState(nextState);
@@ -4370,60 +4417,30 @@ var Form = class extends import_react21.Component {
4370
4417
  *
4371
4418
  * @param formData - The data for the `Form`
4372
4419
  * @param fields - The fields to keep while filtering
4420
+ * @deprecated - To be removed as an exported `Form` function in a future release; there isn't a planned replacement
4373
4421
  */
4374
4422
  getUsedFormData = (formData, fields2) => {
4375
- if (fields2.length === 0 && typeof formData !== "object") {
4376
- return formData;
4377
- }
4378
- const data = (0, import_pick.default)(formData, fields2);
4379
- if (Array.isArray(formData)) {
4380
- return Object.keys(data).map((key) => data[key]);
4381
- }
4382
- return data;
4423
+ return (0, import_utils49.getUsedFormData)(formData, fields2);
4383
4424
  };
4384
4425
  /** Returns the list of field names from inspecting the `pathSchema` as well as using the `formData`
4385
4426
  *
4386
4427
  * @param pathSchema - The `PathSchema` object for the form
4387
4428
  * @param [formData] - The form data to use while checking for empty objects/arrays
4429
+ * @deprecated - To be removed as an exported `Form` function in a future release; there isn't a planned replacement
4388
4430
  */
4389
4431
  getFieldNames = (pathSchema, formData) => {
4390
- const formValueHasData = (value, isLeaf) => typeof value !== "object" || (0, import_isEmpty4.default)(value) || isLeaf && !(0, import_isEmpty4.default)(value);
4391
- const getAllPaths = (_obj, acc = [], paths = [[]]) => {
4392
- const objKeys = Object.keys(_obj);
4393
- objKeys.forEach((key) => {
4394
- const data = _obj[key];
4395
- if (typeof data === "object") {
4396
- const newPaths = paths.map((path) => [...path, key]);
4397
- if (data[import_utils49.RJSF_ADDITIONAL_PROPERTIES_FLAG] && data[import_utils49.NAME_KEY] !== "") {
4398
- acc.push(data[import_utils49.NAME_KEY]);
4399
- } else {
4400
- getAllPaths(data, acc, newPaths);
4401
- }
4402
- } else if (key === import_utils49.NAME_KEY && data !== "") {
4403
- paths.forEach((path) => {
4404
- const formValue = (0, import_get5.default)(formData, path);
4405
- const isLeaf = objKeys.length === 1;
4406
- if (formValueHasData(formValue, isLeaf) || Array.isArray(formValue) && formValue.every((val) => formValueHasData(val, isLeaf))) {
4407
- acc.push(path);
4408
- }
4409
- });
4410
- }
4411
- });
4412
- return acc;
4413
- };
4414
- return getAllPaths(pathSchema);
4432
+ return (0, import_utils49.getFieldNames)(pathSchema, formData);
4415
4433
  };
4416
4434
  /** Returns the `formData` after filtering to remove any extra data not in a form field
4417
4435
  *
4418
4436
  * @param formData - The data for the `Form`
4419
4437
  * @returns The `formData` after omitting extra data
4438
+ * @deprecated - To be removed as an exported `Form` function in a future release, use `SchemaUtils.omitExtraData`
4439
+ * instead.
4420
4440
  */
4421
4441
  omitExtraData = (formData) => {
4422
4442
  const { schema, schemaUtils } = this.state;
4423
- const retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
4424
- const pathSchema = schemaUtils.toPathSchema(retrievedSchema, "", formData);
4425
- const fieldNames = this.getFieldNames(pathSchema, formData);
4426
- return this.getUsedFormData(formData, fieldNames);
4443
+ return schemaUtils.omitExtraData(schema, formData);
4427
4444
  };
4428
4445
  /** Allows a user to set a value for the provided `fieldPath`, which must be either a dotted path to the field OR a
4429
4446
  * `FieldPathList`. To set the root element, used either `''` or `[]` for the path. Passing undefined will clear the
@@ -4465,6 +4482,7 @@ var Form = class extends import_react21.Component {
4465
4482
  if (this.pendingChanges.length === 0) {
4466
4483
  return;
4467
4484
  }
4485
+ this._isProcessingUserChange = true;
4468
4486
  const { newValue, path, id } = this.pendingChanges[0];
4469
4487
  const { newErrorSchema } = this.pendingChanges[0];
4470
4488
  const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
@@ -4474,13 +4492,16 @@ var Form = class extends import_react21.Component {
4474
4492
  const isRootPath = !path || path.length === 0 || path.length === 1 && path[0] === rootPathId;
4475
4493
  let retrievedSchema = this.state.retrievedSchema;
4476
4494
  let formData = isRootPath ? newValue : (0, import_cloneDeep2.default)(oldFormData);
4495
+ const hasOnlyUndefinedValues = (0, import_utils49.isObject)(formData) && Object.keys(formData).length > 0 && Object.values(formData).every((v) => v === void 0);
4496
+ const wasPreviouslyNull = oldFormData === null || oldFormData === void 0;
4497
+ const inputForDefaults = hasOnlyUndefinedValues && wasPreviouslyNull ? void 0 : formData;
4477
4498
  if ((0, import_utils49.isObject)(formData) || Array.isArray(formData)) {
4478
4499
  if (newValue === ADDITIONAL_PROPERTY_KEY_REMOVE) {
4479
4500
  (0, import_unset.default)(formData, path);
4480
4501
  } else if (!isRootPath) {
4481
4502
  (0, import_set5.default)(formData, path, newValue);
4482
4503
  }
4483
- const newState = this.getStateFromProps(this.props, formData, void 0, void 0, void 0, true);
4504
+ const newState = this.getStateFromProps(this.props, inputForDefaults, void 0, void 0, void 0, true);
4484
4505
  formData = newState.formData;
4485
4506
  retrievedSchema = newState.retrievedSchema;
4486
4507
  }