@rjsf/core 6.4.2 → 6.5.1

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.
package/dist/core.umd.js CHANGED
@@ -1859,10 +1859,13 @@
1859
1859
  } = props;
1860
1860
  const { fields: fields2, schemaUtils, translateString, globalUiOptions } = registry;
1861
1861
  const { OptionalDataControlsField: OptionalDataControlsField2 } = fields2;
1862
+ const formDataRef = react.useRef(formData);
1863
+ formDataRef.current = formData;
1862
1864
  const schema = schemaUtils.retrieveSchema(rawSchema, formData, true);
1863
1865
  const uiOptions = utils.getUiOptions(uiSchema, globalUiOptions);
1864
1866
  const { properties: schemaProperties = {} } = schema;
1865
1867
  const childFieldPathId = props.childFieldPathId ?? fieldPathId;
1868
+ const lastRenamedProperty = react.useRef({ previousKey: "", currentKey: void 0 });
1866
1869
  const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
1867
1870
  const description = uiOptions.description ?? schema.description;
1868
1871
  const renderOptionalField = utils.shouldRenderOptionalField(registry, schema, required, uiSchema);
@@ -1912,14 +1915,19 @@
1912
1915
  const newValue = constValue ?? defaultValue ?? getDefaultValue(translateString2, type);
1913
1916
  set(newFormData, newKey, newValue);
1914
1917
  }
1918
+ if (lastRenamedProperty.current.previousKey === newKey) {
1919
+ lastRenamedProperty.current.currentKey = newKey;
1920
+ lastRenamedProperty.current.previousKey = getAvailableKey(newKey, newFormData);
1921
+ }
1915
1922
  onChange(newFormData, childFieldPathId.path);
1916
1923
  }, [formData, onChange, registry, childFieldPathId, getAvailableKey, schema]);
1917
1924
  const handleKeyRename = react.useCallback(
1918
1925
  (oldKey, newKey) => {
1919
1926
  if (oldKey !== newKey) {
1920
- const actualNewKey = getAvailableKey(newKey, formData);
1927
+ const currentFormData = formDataRef.current;
1928
+ const actualNewKey = getAvailableKey(newKey, currentFormData);
1921
1929
  const newFormData = {
1922
- ...formData
1930
+ ...currentFormData
1923
1931
  };
1924
1932
  const newKeys = { [oldKey]: actualNewKey };
1925
1933
  const keyValues = Object.keys(newFormData).map((key) => {
@@ -1927,10 +1935,15 @@
1927
1935
  return { [newKey2]: newFormData[key] };
1928
1936
  });
1929
1937
  const renamedObj = Object.assign({}, ...keyValues);
1938
+ formDataRef.current = renamedObj;
1939
+ if (oldKey !== lastRenamedProperty.current.currentKey) {
1940
+ lastRenamedProperty.current.previousKey = oldKey;
1941
+ }
1942
+ lastRenamedProperty.current.currentKey = actualNewKey;
1930
1943
  onChange(renamedObj, childFieldPathId.path);
1931
1944
  }
1932
1945
  },
1933
- [formData, onChange, childFieldPathId, getAvailableKey]
1946
+ [onChange, childFieldPathId, getAvailableKey]
1934
1947
  );
1935
1948
  const handleRemoveProperty = react.useCallback(
1936
1949
  (key) => {
@@ -1938,6 +1951,12 @@
1938
1951
  },
1939
1952
  [onChange, childFieldPathId]
1940
1953
  );
1954
+ const getStableKey = react.useCallback((property) => {
1955
+ if (lastRenamedProperty.current.currentKey === property) {
1956
+ return lastRenamedProperty.current.previousKey;
1957
+ }
1958
+ return property;
1959
+ }, []);
1941
1960
  if (!renderOptionalField || hasFormData) {
1942
1961
  try {
1943
1962
  const properties = Object.keys(schemaProperties);
@@ -1980,7 +1999,7 @@
1980
1999
  readonly,
1981
2000
  hideError
1982
2001
  },
1983
- name2
2002
+ getStableKey(name2)
1984
2003
  );
1985
2004
  return {
1986
2005
  content,
@@ -3087,7 +3106,8 @@
3087
3106
  id: `${id}-key`,
3088
3107
  onBlur: onKeyRenameBlur,
3089
3108
  defaultValue: label
3090
- }
3109
+ },
3110
+ label
3091
3111
  )
3092
3112
  ] }) }),
3093
3113
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "form-additional form-group col-xs-5", children }),
@@ -3239,7 +3259,7 @@
3239
3259
  function CheckboxesWidget({
3240
3260
  id,
3241
3261
  disabled,
3242
- options: { inline = false, enumOptions, enumDisabled, emptyValue },
3262
+ options,
3243
3263
  value,
3244
3264
  autofocus = false,
3245
3265
  readonly,
@@ -3248,14 +3268,16 @@
3248
3268
  onFocus,
3249
3269
  htmlName
3250
3270
  }) {
3271
+ const { inline = false, enumOptions, enumDisabled, emptyValue } = options;
3272
+ const optionValueFormat = utils.getOptionValueFormat(options);
3251
3273
  const checkboxesValues = Array.isArray(value) ? value : [value];
3252
3274
  const handleBlur = react.useCallback(
3253
- ({ target }) => onBlur(id, utils.enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3254
- [onBlur, id, enumOptions, emptyValue]
3275
+ ({ target }) => onBlur(id, utils.enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3276
+ [onBlur, id, enumOptions, emptyValue, optionValueFormat]
3255
3277
  );
3256
3278
  const handleFocus = react.useCallback(
3257
- ({ target }) => onFocus(id, utils.enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3258
- [onFocus, id, enumOptions, emptyValue]
3279
+ ({ target }) => onFocus(id, utils.enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3280
+ [onFocus, id, enumOptions, emptyValue, optionValueFormat]
3259
3281
  );
3260
3282
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "checkboxes", id, children: Array.isArray(enumOptions) && enumOptions.map((option, index) => {
3261
3283
  const checked = utils.enumOptionsIsSelected(option.value, checkboxesValues);
@@ -3276,7 +3298,7 @@
3276
3298
  id: utils.optionId(id, index),
3277
3299
  name: htmlName || id,
3278
3300
  checked,
3279
- value: String(index),
3301
+ value: utils.enumOptionValueEncoder(option.value, index, optionValueFormat),
3280
3302
  disabled: disabled || itemDisabled || readonly,
3281
3303
  autoFocus: autofocus && index === 0,
3282
3304
  onChange: handleChange,
@@ -3421,13 +3443,14 @@
3421
3443
  htmlName
3422
3444
  }) {
3423
3445
  const { enumOptions, enumDisabled, inline, emptyValue } = options;
3446
+ const optionValueFormat = utils.getOptionValueFormat(options);
3424
3447
  const handleBlur = react.useCallback(
3425
- ({ target }) => onBlur(id, utils.enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3426
- [onBlur, enumOptions, emptyValue, id]
3448
+ ({ target }) => onBlur(id, utils.enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3449
+ [onBlur, enumOptions, emptyValue, id, optionValueFormat]
3427
3450
  );
3428
3451
  const handleFocus = react.useCallback(
3429
- ({ target }) => onFocus(id, utils.enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3430
- [onFocus, enumOptions, emptyValue, id]
3452
+ ({ target }) => onFocus(id, utils.enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3453
+ [onFocus, enumOptions, emptyValue, id, optionValueFormat]
3431
3454
  );
3432
3455
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "field-radio-group", id, role: "radiogroup", children: Array.isArray(enumOptions) && enumOptions.map((option, i) => {
3433
3456
  const checked = utils.enumOptionsIsSelected(option.value, value);
@@ -3443,7 +3466,7 @@
3443
3466
  checked,
3444
3467
  name: htmlName || id,
3445
3468
  required,
3446
- value: String(i),
3469
+ value: utils.enumOptionValueEncoder(option.value, i, optionValueFormat),
3447
3470
  disabled: disabled || itemDisabled || readonly,
3448
3471
  autoFocus: autofocus && i === 0,
3449
3472
  onChange: handleChange,
@@ -3594,28 +3617,29 @@
3594
3617
  }) {
3595
3618
  const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;
3596
3619
  const emptyValue = multiple ? [] : "";
3620
+ const optionValueFormat = utils.getOptionValueFormat(options);
3597
3621
  const handleFocus = react.useCallback(
3598
3622
  (event) => {
3599
3623
  const newValue = getValue(event, multiple);
3600
- return onFocus(id, utils.enumOptionsValueForIndex(newValue, enumOptions, optEmptyVal));
3624
+ return onFocus(id, utils.enumOptionValueDecoder(newValue, enumOptions, optionValueFormat, optEmptyVal));
3601
3625
  },
3602
- [onFocus, id, multiple, enumOptions, optEmptyVal]
3626
+ [onFocus, id, multiple, enumOptions, optEmptyVal, optionValueFormat]
3603
3627
  );
3604
3628
  const handleBlur = react.useCallback(
3605
3629
  (event) => {
3606
3630
  const newValue = getValue(event, multiple);
3607
- return onBlur(id, utils.enumOptionsValueForIndex(newValue, enumOptions, optEmptyVal));
3631
+ return onBlur(id, utils.enumOptionValueDecoder(newValue, enumOptions, optionValueFormat, optEmptyVal));
3608
3632
  },
3609
- [onBlur, id, multiple, enumOptions, optEmptyVal]
3633
+ [onBlur, id, multiple, enumOptions, optEmptyVal, optionValueFormat]
3610
3634
  );
3611
3635
  const handleChange = react.useCallback(
3612
3636
  (event) => {
3613
3637
  const newValue = getValue(event, multiple);
3614
- return onChange(utils.enumOptionsValueForIndex(newValue, enumOptions, optEmptyVal));
3638
+ return onChange(utils.enumOptionValueDecoder(newValue, enumOptions, optionValueFormat, optEmptyVal));
3615
3639
  },
3616
- [onChange, multiple, enumOptions, optEmptyVal]
3640
+ [onChange, multiple, enumOptions, optEmptyVal, optionValueFormat]
3617
3641
  );
3618
- const selectedIndexes = utils.enumOptionsIndexForValue(value, enumOptions, multiple);
3642
+ const selectValue = utils.enumOptionSelectedValue(value, enumOptions, multiple, optionValueFormat, emptyValue);
3619
3643
  const showPlaceholderOption = !multiple && schema.default === void 0;
3620
3644
  return /* @__PURE__ */ jsxRuntime.jsxs(
3621
3645
  "select",
@@ -3625,7 +3649,7 @@
3625
3649
  multiple,
3626
3650
  role: "combobox",
3627
3651
  className: "form-control",
3628
- value: typeof selectedIndexes === "undefined" ? emptyValue : selectedIndexes,
3652
+ value: selectValue,
3629
3653
  required,
3630
3654
  disabled: disabled || readonly,
3631
3655
  autoFocus: autofocus,
@@ -3637,7 +3661,7 @@
3637
3661
  showPlaceholderOption && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: placeholder }),
3638
3662
  Array.isArray(enumOptions) && enumOptions.map(({ value: value2, label }, i) => {
3639
3663
  const disabled2 = enumDisabled && enumDisabled.indexOf(value2) !== -1;
3640
- return /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(i), disabled: disabled2, children: label }, i);
3664
+ return /* @__PURE__ */ jsxRuntime.jsx("option", { value: utils.enumOptionValueEncoder(value2, i, optionValueFormat), disabled: disabled2, children: label }, i);
3641
3665
  })
3642
3666
  ]
3643
3667
  }
@@ -4005,12 +4029,11 @@
4005
4029
  }
4006
4030
  const newRegistry = this.getRegistry(props, rootSchema, schemaUtils);
4007
4031
  const registry = utils.deepEquals(state.registry, newRegistry) ? state.registry : newRegistry;
4008
- const expandedUiSchema = registry.uiSchemaDefinitions ? utils.expandUiSchemaDefinitions(rootSchema, uiSchema, registry) : uiSchema;
4009
4032
  const fieldPathId = state.fieldPathId && state.fieldPathId?.[utils.ID_KEY] === registry.globalFormOptions.idPrefix ? state.fieldPathId : utils.toFieldPathId("", registry.globalFormOptions);
4010
4033
  const nextState = {
4011
4034
  schemaUtils,
4012
4035
  schema: rootSchema,
4013
- uiSchema: expandedUiSchema,
4036
+ uiSchema,
4014
4037
  fieldPathId,
4015
4038
  formData,
4016
4039
  edit,
@@ -4192,7 +4215,7 @@
4192
4215
  this._isProcessingUserChange = true;
4193
4216
  const { newValue, path, id } = this.pendingChanges[0];
4194
4217
  const { newErrorSchema } = this.pendingChanges[0];
4195
- const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
4218
+ const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange, removeEmptyOptionalObjects } = this.props;
4196
4219
  const { formData: oldFormData, schemaUtils, schema, fieldPathId, schemaValidationErrorSchema, errors } = this.state;
4197
4220
  let { customErrors, errorSchema: originalErrorSchema } = this.state;
4198
4221
  const rootPathId = fieldPathId.path[0] || "";
@@ -4221,6 +4244,18 @@
4221
4244
  formData: newFormData
4222
4245
  };
4223
4246
  }
4247
+ if (removeEmptyOptionalObjects) {
4248
+ newFormData = utils.removeOptionalEmptyObjects(
4249
+ schemaUtils.getValidator(),
4250
+ schema,
4251
+ schemaUtils.getRootSchema(),
4252
+ newFormData
4253
+ );
4254
+ state = {
4255
+ ...state,
4256
+ formData: newFormData
4257
+ };
4258
+ }
4224
4259
  if (newErrorSchema) {
4225
4260
  const oldValidationError = !isRootPath ? get(schemaValidationErrorSchema, path) : schemaValidationErrorSchema;
4226
4261
  if (!isEmpty(oldValidationError)) {
@@ -4321,24 +4356,33 @@
4321
4356
  * @param data - The data associated with the field that was blurred
4322
4357
  */
4323
4358
  onBlur = (id, data) => {
4324
- const { onBlur, omitExtraData, liveOmit, liveValidate } = this.props;
4359
+ const { onBlur, omitExtraData, liveOmit, liveValidate, removeEmptyOptionalObjects } = this.props;
4325
4360
  if (onBlur) {
4326
4361
  onBlur(id, data);
4327
4362
  }
4328
4363
  if (omitExtraData === true && liveOmit === "onBlur" || liveValidate === "onBlur") {
4329
4364
  const { onChange, extraErrors } = this.props;
4330
- const { formData } = this.state;
4365
+ const { formData, schemaUtils, schema } = this.state;
4331
4366
  let newFormData = formData;
4332
4367
  let state = { formData: newFormData };
4333
4368
  if (omitExtraData === true && liveOmit === "onBlur") {
4334
4369
  newFormData = this.omitExtraData(formData);
4335
4370
  state = { formData: newFormData };
4336
4371
  }
4372
+ if (removeEmptyOptionalObjects) {
4373
+ newFormData = utils.removeOptionalEmptyObjects(
4374
+ schemaUtils.getValidator(),
4375
+ schema,
4376
+ schemaUtils.getRootSchema(),
4377
+ newFormData
4378
+ );
4379
+ state = { ...state, formData: newFormData };
4380
+ }
4337
4381
  if (liveValidate === "onBlur") {
4338
- const { schema, schemaUtils, errorSchema, customErrors, retrievedSchema } = this.state;
4382
+ const { schema: schema2, schemaUtils: schemaUtils2, errorSchema, customErrors, retrievedSchema } = this.state;
4339
4383
  const liveValidation = this.liveValidate(
4340
- schema,
4341
- schemaUtils,
4384
+ schema2,
4385
+ schemaUtils2,
4342
4386
  errorSchema,
4343
4387
  newFormData,
4344
4388
  extraErrors,
@@ -4385,11 +4429,20 @@
4385
4429
  return;
4386
4430
  }
4387
4431
  event.persist();
4388
- const { omitExtraData, extraErrors, noValidate, onSubmit } = this.props;
4432
+ const { omitExtraData, extraErrors, noValidate, onSubmit, removeEmptyOptionalObjects } = this.props;
4389
4433
  let { formData: newFormData } = this.state;
4390
4434
  if (omitExtraData === true) {
4391
4435
  newFormData = this.omitExtraData(newFormData);
4392
4436
  }
4437
+ if (removeEmptyOptionalObjects) {
4438
+ const { schemaUtils, schema } = this.state;
4439
+ newFormData = utils.removeOptionalEmptyObjects(
4440
+ schemaUtils.getValidator(),
4441
+ schema,
4442
+ schemaUtils.getRootSchema(),
4443
+ newFormData
4444
+ );
4445
+ }
4393
4446
  if (noValidate || this.validateFormWithFormData(newFormData)) {
4394
4447
  const errorSchema = extraErrors || {};
4395
4448
  const errors = extraErrors ? utils.toErrorList(extraErrors) : [];
@@ -4486,7 +4539,7 @@
4486
4539
  const elementId = path.join(idSeparator);
4487
4540
  let field = this.formElement.current.elements[elementId];
4488
4541
  if (!field) {
4489
- field = this.formElement.current.querySelector(`input[id^="${elementId}"`);
4542
+ field = this.formElement.current.querySelector(`input[id^="${elementId}"], button[id^="${elementId}"]`);
4490
4543
  }
4491
4544
  if (field && field.length) {
4492
4545
  field = field[0];
@@ -4554,11 +4607,20 @@
4554
4607
  * @returns - True if the form is valid, false otherwise.
4555
4608
  */
4556
4609
  validateForm() {
4557
- const { omitExtraData } = this.props;
4610
+ const { omitExtraData, removeEmptyOptionalObjects } = this.props;
4558
4611
  let { formData: newFormData } = this.state;
4559
4612
  if (omitExtraData === true) {
4560
4613
  newFormData = this.omitExtraData(newFormData);
4561
4614
  }
4615
+ if (removeEmptyOptionalObjects) {
4616
+ const { schemaUtils, schema } = this.state;
4617
+ newFormData = utils.removeOptionalEmptyObjects(
4618
+ schemaUtils.getValidator(),
4619
+ schema,
4620
+ schemaUtils.getRootSchema(),
4621
+ newFormData
4622
+ );
4623
+ }
4562
4624
  return this.validateFormWithFormData(newFormData);
4563
4625
  }
4564
4626
  /** Renders the `Form` fields inside the <form> | `tagName` or `_internalFormWrapper`, rendering any errors if
package/dist/index.cjs CHANGED
@@ -1988,10 +1988,13 @@ function ObjectField(props) {
1988
1988
  } = props;
1989
1989
  const { fields: fields2, schemaUtils, translateString, globalUiOptions } = registry;
1990
1990
  const { OptionalDataControlsField: OptionalDataControlsField2 } = fields2;
1991
+ const formDataRef = (0, import_react8.useRef)(formData);
1992
+ formDataRef.current = formData;
1991
1993
  const schema = schemaUtils.retrieveSchema(rawSchema, formData, true);
1992
1994
  const uiOptions = (0, import_utils9.getUiOptions)(uiSchema, globalUiOptions);
1993
1995
  const { properties: schemaProperties = {} } = schema;
1994
1996
  const childFieldPathId = props.childFieldPathId ?? fieldPathId;
1997
+ const lastRenamedProperty = (0, import_react8.useRef)({ previousKey: "", currentKey: void 0 });
1995
1998
  const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
1996
1999
  const description = uiOptions.description ?? schema.description;
1997
2000
  const renderOptionalField = (0, import_utils9.shouldRenderOptionalField)(registry, schema, required, uiSchema);
@@ -2041,14 +2044,19 @@ function ObjectField(props) {
2041
2044
  const newValue = constValue ?? defaultValue ?? getDefaultValue(translateString2, type);
2042
2045
  (0, import_set4.default)(newFormData, newKey, newValue);
2043
2046
  }
2047
+ if (lastRenamedProperty.current.previousKey === newKey) {
2048
+ lastRenamedProperty.current.currentKey = newKey;
2049
+ lastRenamedProperty.current.previousKey = getAvailableKey(newKey, newFormData);
2050
+ }
2044
2051
  onChange(newFormData, childFieldPathId.path);
2045
2052
  }, [formData, onChange, registry, childFieldPathId, getAvailableKey, schema]);
2046
2053
  const handleKeyRename = (0, import_react8.useCallback)(
2047
2054
  (oldKey, newKey) => {
2048
2055
  if (oldKey !== newKey) {
2049
- const actualNewKey = getAvailableKey(newKey, formData);
2056
+ const currentFormData = formDataRef.current;
2057
+ const actualNewKey = getAvailableKey(newKey, currentFormData);
2050
2058
  const newFormData = {
2051
- ...formData
2059
+ ...currentFormData
2052
2060
  };
2053
2061
  const newKeys = { [oldKey]: actualNewKey };
2054
2062
  const keyValues = Object.keys(newFormData).map((key) => {
@@ -2056,10 +2064,15 @@ function ObjectField(props) {
2056
2064
  return { [newKey2]: newFormData[key] };
2057
2065
  });
2058
2066
  const renamedObj = Object.assign({}, ...keyValues);
2067
+ formDataRef.current = renamedObj;
2068
+ if (oldKey !== lastRenamedProperty.current.currentKey) {
2069
+ lastRenamedProperty.current.previousKey = oldKey;
2070
+ }
2071
+ lastRenamedProperty.current.currentKey = actualNewKey;
2059
2072
  onChange(renamedObj, childFieldPathId.path);
2060
2073
  }
2061
2074
  },
2062
- [formData, onChange, childFieldPathId, getAvailableKey]
2075
+ [onChange, childFieldPathId, getAvailableKey]
2063
2076
  );
2064
2077
  const handleRemoveProperty = (0, import_react8.useCallback)(
2065
2078
  (key) => {
@@ -2067,6 +2080,12 @@ function ObjectField(props) {
2067
2080
  },
2068
2081
  [onChange, childFieldPathId]
2069
2082
  );
2083
+ const getStableKey = (0, import_react8.useCallback)((property) => {
2084
+ if (lastRenamedProperty.current.currentKey === property) {
2085
+ return lastRenamedProperty.current.previousKey;
2086
+ }
2087
+ return property;
2088
+ }, []);
2070
2089
  if (!renderOptionalField || hasFormData) {
2071
2090
  try {
2072
2091
  const properties = Object.keys(schemaProperties);
@@ -2109,7 +2128,7 @@ function ObjectField(props) {
2109
2128
  readonly,
2110
2129
  hideError
2111
2130
  },
2112
- name2
2131
+ getStableKey(name2)
2113
2132
  );
2114
2133
  return {
2115
2134
  content,
@@ -3345,7 +3364,8 @@ function WrapIfAdditionalTemplate(props) {
3345
3364
  id: `${id}-key`,
3346
3365
  onBlur: onKeyRenameBlur,
3347
3366
  defaultValue: label
3348
- }
3367
+ },
3368
+ label
3349
3369
  )
3350
3370
  ] }) }),
3351
3371
  /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "form-additional form-group col-xs-5", children }),
@@ -3514,7 +3534,7 @@ var import_jsx_runtime42 = require("react/jsx-runtime");
3514
3534
  function CheckboxesWidget({
3515
3535
  id,
3516
3536
  disabled,
3517
- options: { inline = false, enumOptions, enumDisabled, emptyValue },
3537
+ options,
3518
3538
  value,
3519
3539
  autofocus = false,
3520
3540
  readonly,
@@ -3523,14 +3543,16 @@ function CheckboxesWidget({
3523
3543
  onFocus,
3524
3544
  htmlName
3525
3545
  }) {
3546
+ const { inline = false, enumOptions, enumDisabled, emptyValue } = options;
3547
+ const optionValueFormat = (0, import_utils35.getOptionValueFormat)(options);
3526
3548
  const checkboxesValues = Array.isArray(value) ? value : [value];
3527
3549
  const handleBlur = (0, import_react14.useCallback)(
3528
- ({ target }) => onBlur(id, (0, import_utils35.enumOptionsValueForIndex)(target && target.value, enumOptions, emptyValue)),
3529
- [onBlur, id, enumOptions, emptyValue]
3550
+ ({ target }) => onBlur(id, (0, import_utils35.enumOptionValueDecoder)(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3551
+ [onBlur, id, enumOptions, emptyValue, optionValueFormat]
3530
3552
  );
3531
3553
  const handleFocus = (0, import_react14.useCallback)(
3532
- ({ target }) => onFocus(id, (0, import_utils35.enumOptionsValueForIndex)(target && target.value, enumOptions, emptyValue)),
3533
- [onFocus, id, enumOptions, emptyValue]
3554
+ ({ target }) => onFocus(id, (0, import_utils35.enumOptionValueDecoder)(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3555
+ [onFocus, id, enumOptions, emptyValue, optionValueFormat]
3534
3556
  );
3535
3557
  return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "checkboxes", id, children: Array.isArray(enumOptions) && enumOptions.map((option, index) => {
3536
3558
  const checked = (0, import_utils35.enumOptionsIsSelected)(option.value, checkboxesValues);
@@ -3551,7 +3573,7 @@ function CheckboxesWidget({
3551
3573
  id: (0, import_utils35.optionId)(id, index),
3552
3574
  name: htmlName || id,
3553
3575
  checked,
3554
- value: String(index),
3576
+ value: (0, import_utils35.enumOptionValueEncoder)(option.value, index, optionValueFormat),
3555
3577
  disabled: disabled || itemDisabled || readonly,
3556
3578
  autoFocus: autofocus && index === 0,
3557
3579
  onChange: handleChange,
@@ -3730,13 +3752,14 @@ function RadioWidget({
3730
3752
  htmlName
3731
3753
  }) {
3732
3754
  const { enumOptions, enumDisabled, inline, emptyValue } = options;
3755
+ const optionValueFormat = (0, import_utils42.getOptionValueFormat)(options);
3733
3756
  const handleBlur = (0, import_react16.useCallback)(
3734
- ({ target }) => onBlur(id, (0, import_utils42.enumOptionsValueForIndex)(target && target.value, enumOptions, emptyValue)),
3735
- [onBlur, enumOptions, emptyValue, id]
3757
+ ({ target }) => onBlur(id, (0, import_utils42.enumOptionValueDecoder)(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3758
+ [onBlur, enumOptions, emptyValue, id, optionValueFormat]
3736
3759
  );
3737
3760
  const handleFocus = (0, import_react16.useCallback)(
3738
- ({ target }) => onFocus(id, (0, import_utils42.enumOptionsValueForIndex)(target && target.value, enumOptions, emptyValue)),
3739
- [onFocus, enumOptions, emptyValue, id]
3761
+ ({ target }) => onFocus(id, (0, import_utils42.enumOptionValueDecoder)(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3762
+ [onFocus, enumOptions, emptyValue, id, optionValueFormat]
3740
3763
  );
3741
3764
  return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "field-radio-group", id, role: "radiogroup", children: Array.isArray(enumOptions) && enumOptions.map((option, i) => {
3742
3765
  const checked = (0, import_utils42.enumOptionsIsSelected)(option.value, value);
@@ -3752,7 +3775,7 @@ function RadioWidget({
3752
3775
  checked,
3753
3776
  name: htmlName || id,
3754
3777
  required,
3755
- value: String(i),
3778
+ value: (0, import_utils42.enumOptionValueEncoder)(option.value, i, optionValueFormat),
3756
3779
  disabled: disabled || itemDisabled || readonly,
3757
3780
  autoFocus: autofocus && i === 0,
3758
3781
  onChange: handleChange,
@@ -3915,28 +3938,29 @@ function SelectWidget({
3915
3938
  }) {
3916
3939
  const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;
3917
3940
  const emptyValue = multiple ? [] : "";
3941
+ const optionValueFormat = (0, import_utils43.getOptionValueFormat)(options);
3918
3942
  const handleFocus = (0, import_react18.useCallback)(
3919
3943
  (event) => {
3920
3944
  const newValue = getValue(event, multiple);
3921
- return onFocus(id, (0, import_utils43.enumOptionsValueForIndex)(newValue, enumOptions, optEmptyVal));
3945
+ return onFocus(id, (0, import_utils43.enumOptionValueDecoder)(newValue, enumOptions, optionValueFormat, optEmptyVal));
3922
3946
  },
3923
- [onFocus, id, multiple, enumOptions, optEmptyVal]
3947
+ [onFocus, id, multiple, enumOptions, optEmptyVal, optionValueFormat]
3924
3948
  );
3925
3949
  const handleBlur = (0, import_react18.useCallback)(
3926
3950
  (event) => {
3927
3951
  const newValue = getValue(event, multiple);
3928
- return onBlur(id, (0, import_utils43.enumOptionsValueForIndex)(newValue, enumOptions, optEmptyVal));
3952
+ return onBlur(id, (0, import_utils43.enumOptionValueDecoder)(newValue, enumOptions, optionValueFormat, optEmptyVal));
3929
3953
  },
3930
- [onBlur, id, multiple, enumOptions, optEmptyVal]
3954
+ [onBlur, id, multiple, enumOptions, optEmptyVal, optionValueFormat]
3931
3955
  );
3932
3956
  const handleChange = (0, import_react18.useCallback)(
3933
3957
  (event) => {
3934
3958
  const newValue = getValue(event, multiple);
3935
- return onChange((0, import_utils43.enumOptionsValueForIndex)(newValue, enumOptions, optEmptyVal));
3959
+ return onChange((0, import_utils43.enumOptionValueDecoder)(newValue, enumOptions, optionValueFormat, optEmptyVal));
3936
3960
  },
3937
- [onChange, multiple, enumOptions, optEmptyVal]
3961
+ [onChange, multiple, enumOptions, optEmptyVal, optionValueFormat]
3938
3962
  );
3939
- const selectedIndexes = (0, import_utils43.enumOptionsIndexForValue)(value, enumOptions, multiple);
3963
+ const selectValue = (0, import_utils43.enumOptionSelectedValue)(value, enumOptions, multiple, optionValueFormat, emptyValue);
3940
3964
  const showPlaceholderOption = !multiple && schema.default === void 0;
3941
3965
  return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
3942
3966
  "select",
@@ -3946,7 +3970,7 @@ function SelectWidget({
3946
3970
  multiple,
3947
3971
  role: "combobox",
3948
3972
  className: "form-control",
3949
- value: typeof selectedIndexes === "undefined" ? emptyValue : selectedIndexes,
3973
+ value: selectValue,
3950
3974
  required,
3951
3975
  disabled: disabled || readonly,
3952
3976
  autoFocus: autofocus,
@@ -3958,7 +3982,7 @@ function SelectWidget({
3958
3982
  showPlaceholderOption && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("option", { value: "", children: placeholder }),
3959
3983
  Array.isArray(enumOptions) && enumOptions.map(({ value: value2, label }, i) => {
3960
3984
  const disabled2 = enumDisabled && enumDisabled.indexOf(value2) !== -1;
3961
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("option", { value: String(i), disabled: disabled2, children: label }, i);
3985
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("option", { value: (0, import_utils43.enumOptionValueEncoder)(value2, i, optionValueFormat), disabled: disabled2, children: label }, i);
3962
3986
  })
3963
3987
  ]
3964
3988
  }
@@ -4351,12 +4375,11 @@ var Form = class extends import_react21.Component {
4351
4375
  }
4352
4376
  const newRegistry = this.getRegistry(props, rootSchema, schemaUtils);
4353
4377
  const registry = (0, import_utils50.deepEquals)(state.registry, newRegistry) ? state.registry : newRegistry;
4354
- const expandedUiSchema = registry.uiSchemaDefinitions ? (0, import_utils50.expandUiSchemaDefinitions)(rootSchema, uiSchema, registry) : uiSchema;
4355
4378
  const fieldPathId = state.fieldPathId && state.fieldPathId?.[import_utils50.ID_KEY] === registry.globalFormOptions.idPrefix ? state.fieldPathId : (0, import_utils50.toFieldPathId)("", registry.globalFormOptions);
4356
4379
  const nextState = {
4357
4380
  schemaUtils,
4358
4381
  schema: rootSchema,
4359
- uiSchema: expandedUiSchema,
4382
+ uiSchema,
4360
4383
  fieldPathId,
4361
4384
  formData,
4362
4385
  edit,
@@ -4538,7 +4561,7 @@ var Form = class extends import_react21.Component {
4538
4561
  this._isProcessingUserChange = true;
4539
4562
  const { newValue, path, id } = this.pendingChanges[0];
4540
4563
  const { newErrorSchema } = this.pendingChanges[0];
4541
- const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
4564
+ const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange, removeEmptyOptionalObjects } = this.props;
4542
4565
  const { formData: oldFormData, schemaUtils, schema, fieldPathId, schemaValidationErrorSchema, errors } = this.state;
4543
4566
  let { customErrors, errorSchema: originalErrorSchema } = this.state;
4544
4567
  const rootPathId = fieldPathId.path[0] || "";
@@ -4567,6 +4590,18 @@ var Form = class extends import_react21.Component {
4567
4590
  formData: newFormData
4568
4591
  };
4569
4592
  }
4593
+ if (removeEmptyOptionalObjects) {
4594
+ newFormData = (0, import_utils50.removeOptionalEmptyObjects)(
4595
+ schemaUtils.getValidator(),
4596
+ schema,
4597
+ schemaUtils.getRootSchema(),
4598
+ newFormData
4599
+ );
4600
+ state = {
4601
+ ...state,
4602
+ formData: newFormData
4603
+ };
4604
+ }
4570
4605
  if (newErrorSchema) {
4571
4606
  const oldValidationError = !isRootPath ? (0, import_get5.default)(schemaValidationErrorSchema, path) : schemaValidationErrorSchema;
4572
4607
  if (!(0, import_isEmpty4.default)(oldValidationError)) {
@@ -4667,24 +4702,33 @@ var Form = class extends import_react21.Component {
4667
4702
  * @param data - The data associated with the field that was blurred
4668
4703
  */
4669
4704
  onBlur = (id, data) => {
4670
- const { onBlur, omitExtraData, liveOmit, liveValidate } = this.props;
4705
+ const { onBlur, omitExtraData, liveOmit, liveValidate, removeEmptyOptionalObjects } = this.props;
4671
4706
  if (onBlur) {
4672
4707
  onBlur(id, data);
4673
4708
  }
4674
4709
  if (omitExtraData === true && liveOmit === "onBlur" || liveValidate === "onBlur") {
4675
4710
  const { onChange, extraErrors } = this.props;
4676
- const { formData } = this.state;
4711
+ const { formData, schemaUtils, schema } = this.state;
4677
4712
  let newFormData = formData;
4678
4713
  let state = { formData: newFormData };
4679
4714
  if (omitExtraData === true && liveOmit === "onBlur") {
4680
4715
  newFormData = this.omitExtraData(formData);
4681
4716
  state = { formData: newFormData };
4682
4717
  }
4718
+ if (removeEmptyOptionalObjects) {
4719
+ newFormData = (0, import_utils50.removeOptionalEmptyObjects)(
4720
+ schemaUtils.getValidator(),
4721
+ schema,
4722
+ schemaUtils.getRootSchema(),
4723
+ newFormData
4724
+ );
4725
+ state = { ...state, formData: newFormData };
4726
+ }
4683
4727
  if (liveValidate === "onBlur") {
4684
- const { schema, schemaUtils, errorSchema, customErrors, retrievedSchema } = this.state;
4728
+ const { schema: schema2, schemaUtils: schemaUtils2, errorSchema, customErrors, retrievedSchema } = this.state;
4685
4729
  const liveValidation = this.liveValidate(
4686
- schema,
4687
- schemaUtils,
4730
+ schema2,
4731
+ schemaUtils2,
4688
4732
  errorSchema,
4689
4733
  newFormData,
4690
4734
  extraErrors,
@@ -4731,11 +4775,20 @@ var Form = class extends import_react21.Component {
4731
4775
  return;
4732
4776
  }
4733
4777
  event.persist();
4734
- const { omitExtraData, extraErrors, noValidate, onSubmit } = this.props;
4778
+ const { omitExtraData, extraErrors, noValidate, onSubmit, removeEmptyOptionalObjects } = this.props;
4735
4779
  let { formData: newFormData } = this.state;
4736
4780
  if (omitExtraData === true) {
4737
4781
  newFormData = this.omitExtraData(newFormData);
4738
4782
  }
4783
+ if (removeEmptyOptionalObjects) {
4784
+ const { schemaUtils, schema } = this.state;
4785
+ newFormData = (0, import_utils50.removeOptionalEmptyObjects)(
4786
+ schemaUtils.getValidator(),
4787
+ schema,
4788
+ schemaUtils.getRootSchema(),
4789
+ newFormData
4790
+ );
4791
+ }
4739
4792
  if (noValidate || this.validateFormWithFormData(newFormData)) {
4740
4793
  const errorSchema = extraErrors || {};
4741
4794
  const errors = extraErrors ? (0, import_utils50.toErrorList)(extraErrors) : [];
@@ -4832,7 +4885,7 @@ var Form = class extends import_react21.Component {
4832
4885
  const elementId = path.join(idSeparator);
4833
4886
  let field = this.formElement.current.elements[elementId];
4834
4887
  if (!field) {
4835
- field = this.formElement.current.querySelector(`input[id^="${elementId}"`);
4888
+ field = this.formElement.current.querySelector(`input[id^="${elementId}"], button[id^="${elementId}"]`);
4836
4889
  }
4837
4890
  if (field && field.length) {
4838
4891
  field = field[0];
@@ -4900,11 +4953,20 @@ var Form = class extends import_react21.Component {
4900
4953
  * @returns - True if the form is valid, false otherwise.
4901
4954
  */
4902
4955
  validateForm() {
4903
- const { omitExtraData } = this.props;
4956
+ const { omitExtraData, removeEmptyOptionalObjects } = this.props;
4904
4957
  let { formData: newFormData } = this.state;
4905
4958
  if (omitExtraData === true) {
4906
4959
  newFormData = this.omitExtraData(newFormData);
4907
4960
  }
4961
+ if (removeEmptyOptionalObjects) {
4962
+ const { schemaUtils, schema } = this.state;
4963
+ newFormData = (0, import_utils50.removeOptionalEmptyObjects)(
4964
+ schemaUtils.getValidator(),
4965
+ schema,
4966
+ schemaUtils.getRootSchema(),
4967
+ newFormData
4968
+ );
4969
+ }
4908
4970
  return this.validateFormWithFormData(newFormData);
4909
4971
  }
4910
4972
  /** Renders the `Form` fields inside the <form> | `tagName` or `_internalFormWrapper`, rendering any errors if