@rjsf/core 6.4.2 → 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.
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,
@@ -1918,7 +1918,7 @@ function NumberField(props) {
1918
1918
  var NumberField_default = NumberField;
1919
1919
 
1920
1920
  // src/components/fields/ObjectField.tsx
1921
- import { useCallback as useCallback4, useState as useState5 } from "react";
1921
+ import { useCallback as useCallback4, useRef, useState as useState5 } from "react";
1922
1922
  import {
1923
1923
  ADDITIONAL_PROPERTY_FLAG,
1924
1924
  ANY_OF_KEY as ANY_OF_KEY4,
@@ -2066,10 +2066,13 @@ function ObjectField(props) {
2066
2066
  } = props;
2067
2067
  const { fields: fields2, schemaUtils, translateString, globalUiOptions } = registry;
2068
2068
  const { OptionalDataControlsField: OptionalDataControlsField2 } = fields2;
2069
+ const formDataRef = useRef(formData);
2070
+ formDataRef.current = formData;
2069
2071
  const schema = schemaUtils.retrieveSchema(rawSchema, formData, true);
2070
2072
  const uiOptions = getUiOptions8(uiSchema, globalUiOptions);
2071
2073
  const { properties: schemaProperties = {} } = schema;
2072
2074
  const childFieldPathId = props.childFieldPathId ?? fieldPathId;
2075
+ const lastRenamedProperty = useRef({ previousKey: "", currentKey: void 0 });
2073
2076
  const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
2074
2077
  const description = uiOptions.description ?? schema.description;
2075
2078
  const renderOptionalField = shouldRenderOptionalField3(registry, schema, required, uiSchema);
@@ -2119,14 +2122,19 @@ function ObjectField(props) {
2119
2122
  const newValue = constValue ?? defaultValue ?? getDefaultValue(translateString2, type);
2120
2123
  set4(newFormData, newKey, newValue);
2121
2124
  }
2125
+ if (lastRenamedProperty.current.previousKey === newKey) {
2126
+ lastRenamedProperty.current.currentKey = newKey;
2127
+ lastRenamedProperty.current.previousKey = getAvailableKey(newKey, newFormData);
2128
+ }
2122
2129
  onChange(newFormData, childFieldPathId.path);
2123
2130
  }, [formData, onChange, registry, childFieldPathId, getAvailableKey, schema]);
2124
2131
  const handleKeyRename = useCallback4(
2125
2132
  (oldKey, newKey) => {
2126
2133
  if (oldKey !== newKey) {
2127
- const actualNewKey = getAvailableKey(newKey, formData);
2134
+ const currentFormData = formDataRef.current;
2135
+ const actualNewKey = getAvailableKey(newKey, currentFormData);
2128
2136
  const newFormData = {
2129
- ...formData
2137
+ ...currentFormData
2130
2138
  };
2131
2139
  const newKeys = { [oldKey]: actualNewKey };
2132
2140
  const keyValues = Object.keys(newFormData).map((key) => {
@@ -2134,10 +2142,15 @@ function ObjectField(props) {
2134
2142
  return { [newKey2]: newFormData[key] };
2135
2143
  });
2136
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;
2137
2150
  onChange(renamedObj, childFieldPathId.path);
2138
2151
  }
2139
2152
  },
2140
- [formData, onChange, childFieldPathId, getAvailableKey]
2153
+ [onChange, childFieldPathId, getAvailableKey]
2141
2154
  );
2142
2155
  const handleRemoveProperty = useCallback4(
2143
2156
  (key) => {
@@ -2145,6 +2158,12 @@ function ObjectField(props) {
2145
2158
  },
2146
2159
  [onChange, childFieldPathId]
2147
2160
  );
2161
+ const getStableKey = useCallback4((property) => {
2162
+ if (lastRenamedProperty.current.currentKey === property) {
2163
+ return lastRenamedProperty.current.previousKey;
2164
+ }
2165
+ return property;
2166
+ }, []);
2148
2167
  if (!renderOptionalField || hasFormData) {
2149
2168
  try {
2150
2169
  const properties = Object.keys(schemaProperties);
@@ -2187,7 +2206,7 @@ function ObjectField(props) {
2187
2206
  readonly,
2188
2207
  hideError
2189
2208
  },
2190
- name2
2209
+ getStableKey(name2)
2191
2210
  );
2192
2211
  return {
2193
2212
  content,
@@ -3493,7 +3512,8 @@ function WrapIfAdditionalTemplate(props) {
3493
3512
  id: `${id}-key`,
3494
3513
  onBlur: onKeyRenameBlur,
3495
3514
  defaultValue: label
3496
- }
3515
+ },
3516
+ label
3497
3517
  )
3498
3518
  ] }) }),
3499
3519
  /* @__PURE__ */ jsx38("div", { className: "form-additional form-group col-xs-5", children }),
@@ -3670,17 +3690,19 @@ var CheckboxWidget_default = CheckboxWidget;
3670
3690
  import { useCallback as useCallback9 } from "react";
3671
3691
  import {
3672
3692
  ariaDescribedByIds as ariaDescribedByIds3,
3693
+ enumOptionValueDecoder,
3694
+ enumOptionValueEncoder,
3673
3695
  enumOptionsDeselectValue,
3674
3696
  enumOptionsIsSelected,
3675
3697
  enumOptionsSelectValue,
3676
- enumOptionsValueForIndex,
3698
+ getOptionValueFormat,
3677
3699
  optionId
3678
3700
  } from "@rjsf/utils";
3679
3701
  import { jsx as jsx42, jsxs as jsxs17 } from "react/jsx-runtime";
3680
3702
  function CheckboxesWidget({
3681
3703
  id,
3682
3704
  disabled,
3683
- options: { inline = false, enumOptions, enumDisabled, emptyValue },
3705
+ options,
3684
3706
  value,
3685
3707
  autofocus = false,
3686
3708
  readonly,
@@ -3689,14 +3711,16 @@ function CheckboxesWidget({
3689
3711
  onFocus,
3690
3712
  htmlName
3691
3713
  }) {
3714
+ const { inline = false, enumOptions, enumDisabled, emptyValue } = options;
3715
+ const optionValueFormat = getOptionValueFormat(options);
3692
3716
  const checkboxesValues = Array.isArray(value) ? value : [value];
3693
3717
  const handleBlur = useCallback9(
3694
- ({ target }) => onBlur(id, enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3695
- [onBlur, id, enumOptions, emptyValue]
3718
+ ({ target }) => onBlur(id, enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3719
+ [onBlur, id, enumOptions, emptyValue, optionValueFormat]
3696
3720
  );
3697
3721
  const handleFocus = useCallback9(
3698
- ({ target }) => onFocus(id, enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)),
3699
- [onFocus, id, enumOptions, emptyValue]
3722
+ ({ target }) => onFocus(id, enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3723
+ [onFocus, id, enumOptions, emptyValue, optionValueFormat]
3700
3724
  );
3701
3725
  return /* @__PURE__ */ jsx42("div", { className: "checkboxes", id, children: Array.isArray(enumOptions) && enumOptions.map((option, index) => {
3702
3726
  const checked = enumOptionsIsSelected(option.value, checkboxesValues);
@@ -3717,7 +3741,7 @@ function CheckboxesWidget({
3717
3741
  id: optionId(id, index),
3718
3742
  name: htmlName || id,
3719
3743
  checked,
3720
- value: String(index),
3744
+ value: enumOptionValueEncoder(option.value, index, optionValueFormat),
3721
3745
  disabled: disabled || itemDisabled || readonly,
3722
3746
  autoFocus: autofocus && index === 0,
3723
3747
  onChange: handleChange,
@@ -3890,8 +3914,10 @@ function PasswordWidget(props) {
3890
3914
  import { useCallback as useCallback11 } from "react";
3891
3915
  import {
3892
3916
  ariaDescribedByIds as ariaDescribedByIds4,
3917
+ enumOptionValueDecoder as enumOptionValueDecoder2,
3918
+ enumOptionValueEncoder as enumOptionValueEncoder2,
3893
3919
  enumOptionsIsSelected as enumOptionsIsSelected2,
3894
- enumOptionsValueForIndex as enumOptionsValueForIndex2,
3920
+ getOptionValueFormat as getOptionValueFormat2,
3895
3921
  optionId as optionId2
3896
3922
  } from "@rjsf/utils";
3897
3923
  import { jsx as jsx50, jsxs as jsxs19 } from "react/jsx-runtime";
@@ -3909,13 +3935,14 @@ function RadioWidget({
3909
3935
  htmlName
3910
3936
  }) {
3911
3937
  const { enumOptions, enumDisabled, inline, emptyValue } = options;
3938
+ const optionValueFormat = getOptionValueFormat2(options);
3912
3939
  const handleBlur = useCallback11(
3913
- ({ target }) => onBlur(id, enumOptionsValueForIndex2(target && target.value, enumOptions, emptyValue)),
3914
- [onBlur, enumOptions, emptyValue, id]
3940
+ ({ target }) => onBlur(id, enumOptionValueDecoder2(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3941
+ [onBlur, enumOptions, emptyValue, id, optionValueFormat]
3915
3942
  );
3916
3943
  const handleFocus = useCallback11(
3917
- ({ target }) => onFocus(id, enumOptionsValueForIndex2(target && target.value, enumOptions, emptyValue)),
3918
- [onFocus, enumOptions, emptyValue, id]
3944
+ ({ target }) => onFocus(id, enumOptionValueDecoder2(target && target.value, enumOptions, optionValueFormat, emptyValue)),
3945
+ [onFocus, enumOptions, emptyValue, id, optionValueFormat]
3919
3946
  );
3920
3947
  return /* @__PURE__ */ jsx50("div", { className: "field-radio-group", id, role: "radiogroup", children: Array.isArray(enumOptions) && enumOptions.map((option, i) => {
3921
3948
  const checked = enumOptionsIsSelected2(option.value, value);
@@ -3931,7 +3958,7 @@ function RadioWidget({
3931
3958
  checked,
3932
3959
  name: htmlName || id,
3933
3960
  required,
3934
- value: String(i),
3961
+ value: enumOptionValueEncoder2(option.value, i, optionValueFormat),
3935
3962
  disabled: disabled || itemDisabled || readonly,
3936
3963
  autoFocus: autofocus && i === 0,
3937
3964
  onChange: handleChange,
@@ -4070,8 +4097,10 @@ function RatingWidget({
4070
4097
  import { useCallback as useCallback13 } from "react";
4071
4098
  import {
4072
4099
  ariaDescribedByIds as ariaDescribedByIds5,
4073
- enumOptionsIndexForValue,
4074
- enumOptionsValueForIndex as enumOptionsValueForIndex3
4100
+ enumOptionSelectedValue,
4101
+ enumOptionValueDecoder as enumOptionValueDecoder3,
4102
+ enumOptionValueEncoder as enumOptionValueEncoder3,
4103
+ getOptionValueFormat as getOptionValueFormat3
4075
4104
  } from "@rjsf/utils";
4076
4105
  import { jsx as jsx53, jsxs as jsxs22 } from "react/jsx-runtime";
4077
4106
  function getValue(event, multiple) {
@@ -4098,28 +4127,29 @@ function SelectWidget({
4098
4127
  }) {
4099
4128
  const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;
4100
4129
  const emptyValue = multiple ? [] : "";
4130
+ const optionValueFormat = getOptionValueFormat3(options);
4101
4131
  const handleFocus = useCallback13(
4102
4132
  (event) => {
4103
4133
  const newValue = getValue(event, multiple);
4104
- return onFocus(id, enumOptionsValueForIndex3(newValue, enumOptions, optEmptyVal));
4134
+ return onFocus(id, enumOptionValueDecoder3(newValue, enumOptions, optionValueFormat, optEmptyVal));
4105
4135
  },
4106
- [onFocus, id, multiple, enumOptions, optEmptyVal]
4136
+ [onFocus, id, multiple, enumOptions, optEmptyVal, optionValueFormat]
4107
4137
  );
4108
4138
  const handleBlur = useCallback13(
4109
4139
  (event) => {
4110
4140
  const newValue = getValue(event, multiple);
4111
- return onBlur(id, enumOptionsValueForIndex3(newValue, enumOptions, optEmptyVal));
4141
+ return onBlur(id, enumOptionValueDecoder3(newValue, enumOptions, optionValueFormat, optEmptyVal));
4112
4142
  },
4113
- [onBlur, id, multiple, enumOptions, optEmptyVal]
4143
+ [onBlur, id, multiple, enumOptions, optEmptyVal, optionValueFormat]
4114
4144
  );
4115
4145
  const handleChange = useCallback13(
4116
4146
  (event) => {
4117
4147
  const newValue = getValue(event, multiple);
4118
- return onChange(enumOptionsValueForIndex3(newValue, enumOptions, optEmptyVal));
4148
+ return onChange(enumOptionValueDecoder3(newValue, enumOptions, optionValueFormat, optEmptyVal));
4119
4149
  },
4120
- [onChange, multiple, enumOptions, optEmptyVal]
4150
+ [onChange, multiple, enumOptions, optEmptyVal, optionValueFormat]
4121
4151
  );
4122
- const selectedIndexes = enumOptionsIndexForValue(value, enumOptions, multiple);
4152
+ const selectValue = enumOptionSelectedValue(value, enumOptions, multiple, optionValueFormat, emptyValue);
4123
4153
  const showPlaceholderOption = !multiple && schema.default === void 0;
4124
4154
  return /* @__PURE__ */ jsxs22(
4125
4155
  "select",
@@ -4129,7 +4159,7 @@ function SelectWidget({
4129
4159
  multiple,
4130
4160
  role: "combobox",
4131
4161
  className: "form-control",
4132
- value: typeof selectedIndexes === "undefined" ? emptyValue : selectedIndexes,
4162
+ value: selectValue,
4133
4163
  required,
4134
4164
  disabled: disabled || readonly,
4135
4165
  autoFocus: autofocus,
@@ -4141,7 +4171,7 @@ function SelectWidget({
4141
4171
  showPlaceholderOption && /* @__PURE__ */ jsx53("option", { value: "", children: placeholder }),
4142
4172
  Array.isArray(enumOptions) && enumOptions.map(({ value: value2, label }, i) => {
4143
4173
  const disabled2 = enumDisabled && enumDisabled.indexOf(value2) !== -1;
4144
- 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);
4145
4175
  })
4146
4176
  ]
4147
4177
  }
@@ -4534,12 +4564,11 @@ var Form = class extends Component3 {
4534
4564
  }
4535
4565
  const newRegistry = this.getRegistry(props, rootSchema, schemaUtils);
4536
4566
  const registry = deepEquals2(state.registry, newRegistry) ? state.registry : newRegistry;
4537
- const expandedUiSchema = registry.uiSchemaDefinitions ? expandUiSchemaDefinitions(rootSchema, uiSchema, registry) : uiSchema;
4538
4567
  const fieldPathId = state.fieldPathId && state.fieldPathId?.[ID_KEY5] === registry.globalFormOptions.idPrefix ? state.fieldPathId : toFieldPathId6("", registry.globalFormOptions);
4539
4568
  const nextState = {
4540
4569
  schemaUtils,
4541
4570
  schema: rootSchema,
4542
- uiSchema: expandedUiSchema,
4571
+ uiSchema,
4543
4572
  fieldPathId,
4544
4573
  formData,
4545
4574
  edit,
@@ -4721,7 +4750,7 @@ var Form = class extends Component3 {
4721
4750
  this._isProcessingUserChange = true;
4722
4751
  const { newValue, path, id } = this.pendingChanges[0];
4723
4752
  const { newErrorSchema } = this.pendingChanges[0];
4724
- const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
4753
+ const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange, removeEmptyOptionalObjects } = this.props;
4725
4754
  const { formData: oldFormData, schemaUtils, schema, fieldPathId, schemaValidationErrorSchema, errors } = this.state;
4726
4755
  let { customErrors, errorSchema: originalErrorSchema } = this.state;
4727
4756
  const rootPathId = fieldPathId.path[0] || "";
@@ -4750,6 +4779,18 @@ var Form = class extends Component3 {
4750
4779
  formData: newFormData
4751
4780
  };
4752
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
+ }
4753
4794
  if (newErrorSchema) {
4754
4795
  const oldValidationError = !isRootPath ? _get(schemaValidationErrorSchema, path) : schemaValidationErrorSchema;
4755
4796
  if (!_isEmpty(oldValidationError)) {
@@ -4850,24 +4891,33 @@ var Form = class extends Component3 {
4850
4891
  * @param data - The data associated with the field that was blurred
4851
4892
  */
4852
4893
  onBlur = (id, data) => {
4853
- const { onBlur, omitExtraData, liveOmit, liveValidate } = this.props;
4894
+ const { onBlur, omitExtraData, liveOmit, liveValidate, removeEmptyOptionalObjects } = this.props;
4854
4895
  if (onBlur) {
4855
4896
  onBlur(id, data);
4856
4897
  }
4857
4898
  if (omitExtraData === true && liveOmit === "onBlur" || liveValidate === "onBlur") {
4858
4899
  const { onChange, extraErrors } = this.props;
4859
- const { formData } = this.state;
4900
+ const { formData, schemaUtils, schema } = this.state;
4860
4901
  let newFormData = formData;
4861
4902
  let state = { formData: newFormData };
4862
4903
  if (omitExtraData === true && liveOmit === "onBlur") {
4863
4904
  newFormData = this.omitExtraData(formData);
4864
4905
  state = { formData: newFormData };
4865
4906
  }
4907
+ if (removeEmptyOptionalObjects) {
4908
+ newFormData = removeOptionalEmptyObjects(
4909
+ schemaUtils.getValidator(),
4910
+ schema,
4911
+ schemaUtils.getRootSchema(),
4912
+ newFormData
4913
+ );
4914
+ state = { ...state, formData: newFormData };
4915
+ }
4866
4916
  if (liveValidate === "onBlur") {
4867
- const { schema, schemaUtils, errorSchema, customErrors, retrievedSchema } = this.state;
4917
+ const { schema: schema2, schemaUtils: schemaUtils2, errorSchema, customErrors, retrievedSchema } = this.state;
4868
4918
  const liveValidation = this.liveValidate(
4869
- schema,
4870
- schemaUtils,
4919
+ schema2,
4920
+ schemaUtils2,
4871
4921
  errorSchema,
4872
4922
  newFormData,
4873
4923
  extraErrors,
@@ -4914,11 +4964,20 @@ var Form = class extends Component3 {
4914
4964
  return;
4915
4965
  }
4916
4966
  event.persist();
4917
- const { omitExtraData, extraErrors, noValidate, onSubmit } = this.props;
4967
+ const { omitExtraData, extraErrors, noValidate, onSubmit, removeEmptyOptionalObjects } = this.props;
4918
4968
  let { formData: newFormData } = this.state;
4919
4969
  if (omitExtraData === true) {
4920
4970
  newFormData = this.omitExtraData(newFormData);
4921
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
+ }
4922
4981
  if (noValidate || this.validateFormWithFormData(newFormData)) {
4923
4982
  const errorSchema = extraErrors || {};
4924
4983
  const errors = extraErrors ? toErrorList(extraErrors) : [];
@@ -5015,7 +5074,7 @@ var Form = class extends Component3 {
5015
5074
  const elementId = path.join(idSeparator);
5016
5075
  let field = this.formElement.current.elements[elementId];
5017
5076
  if (!field) {
5018
- field = this.formElement.current.querySelector(`input[id^="${elementId}"`);
5077
+ field = this.formElement.current.querySelector(`input[id^="${elementId}"], button[id^="${elementId}"]`);
5019
5078
  }
5020
5079
  if (field && field.length) {
5021
5080
  field = field[0];
@@ -5083,11 +5142,20 @@ var Form = class extends Component3 {
5083
5142
  * @returns - True if the form is valid, false otherwise.
5084
5143
  */
5085
5144
  validateForm() {
5086
- const { omitExtraData } = this.props;
5145
+ const { omitExtraData, removeEmptyOptionalObjects } = this.props;
5087
5146
  let { formData: newFormData } = this.state;
5088
5147
  if (omitExtraData === true) {
5089
5148
  newFormData = this.omitExtraData(newFormData);
5090
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
+ }
5091
5159
  return this.validateFormWithFormData(newFormData);
5092
5160
  }
5093
5161
  /** Renders the `Form` fields inside the <form> | `tagName` or `_internalFormWrapper`, rendering any errors if