@limetech/lime-elements 39.20.0 → 39.22.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 (48) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/limel-chip_2.cjs.entry.js +2 -2
  3. package/dist/cjs/limel-form.cjs.entry.js +1111 -263
  4. package/dist/collection/components/chip-set/chip-set.js +3 -2
  5. package/dist/esm/{_baseEach-CL_-rBMy.js → _baseEach-C4UJIc96.js} +1 -1
  6. package/dist/esm/{_baseIsEqual-BfXMsuGh.js → _baseIsEqual-DCZXUzsZ.js} +1 -1
  7. package/dist/esm/{_baseIteratee-kS1-0_xD.js → _baseIteratee-CI-QZdpx.js} +1 -1
  8. package/dist/esm/{_getAllKeysIn-BKpeslPJ.js → _getAllKeysIn-v-KlW5r_.js} +1 -1
  9. package/dist/esm/{cloneDeep-BXAw5H-1.js → cloneDeep-V4fB8wfG.js} +2 -2
  10. package/dist/esm/{difference-DMAjHh-t.js → difference-CWrdq-hd.js} +1 -1
  11. package/dist/esm/{isEmpty-DrFXbHWO.js → isEmpty-BFxMjh_H.js} +1 -1
  12. package/dist/esm/{isEqual-CpaoJ_AF.js → isEqual-CsrptmTU.js} +1 -1
  13. package/dist/esm/limel-chip_2.entry.js +5 -5
  14. package/dist/esm/limel-dialog.entry.js +2 -2
  15. package/dist/esm/limel-file-dropzone_2.entry.js +3 -3
  16. package/dist/esm/limel-form.entry.js +1127 -279
  17. package/dist/esm/limel-prosemirror-adapter.entry.js +4 -4
  18. package/dist/esm/limel-tab-bar.entry.js +3 -3
  19. package/dist/esm/limel-table.entry.js +5 -5
  20. package/dist/esm/{pickBy-BEA90LIZ.js → pickBy-D8CUtxE4.js} +2 -2
  21. package/dist/lime-elements/lime-elements.esm.js +1 -1
  22. package/dist/lime-elements/p-29a59535.entry.js +13 -0
  23. package/dist/lime-elements/p-34d1d00a.entry.js +1 -0
  24. package/dist/lime-elements/{p-4ca67b17.entry.js → p-48db87d3.entry.js} +1 -1
  25. package/dist/lime-elements/{p-757896f5.entry.js → p-4e9baf08.entry.js} +1 -1
  26. package/dist/lime-elements/{p-BbU4FGNT.js → p-7uuv3HUP.js} +1 -1
  27. package/dist/lime-elements/{p-4ce682cf.entry.js → p-8139d26a.entry.js} +1 -1
  28. package/dist/lime-elements/{p-CMjGNANG.js → p-BTHqaZIi.js} +1 -1
  29. package/dist/lime-elements/p-Bj622DVt.js +1 -0
  30. package/dist/lime-elements/p-C3Myy3mA.js +1 -0
  31. package/dist/lime-elements/{p-xQsJdKrq.js → p-CXgJVvTe.js} +1 -1
  32. package/dist/lime-elements/p-CxfAgSVd.js +1 -0
  33. package/dist/lime-elements/{p-DFWcgJ_i.js → p-DNIqLXTL.js} +1 -1
  34. package/dist/lime-elements/p-DbC-smVQ.js +1 -0
  35. package/dist/lime-elements/p-SvuA3Boo.js +1 -0
  36. package/dist/lime-elements/{p-cffc137e.entry.js → p-e720f65c.entry.js} +3 -3
  37. package/dist/lime-elements/{p-8065425a.entry.js → p-fd4a4f87.entry.js} +1 -1
  38. package/dist/types/components/chip-set/chip-set.d.ts +1 -0
  39. package/dist/types/components/chip-set/chip.types.d.ts +4 -0
  40. package/dist/types/components.d.ts +4 -0
  41. package/package.json +4 -4
  42. package/dist/lime-elements/p-B3zCFNAw.js +0 -1
  43. package/dist/lime-elements/p-B6bNnxRu.js +0 -1
  44. package/dist/lime-elements/p-BCMRfUKp.js +0 -1
  45. package/dist/lime-elements/p-DTXIk0fN.js +0 -1
  46. package/dist/lime-elements/p-UGKt6Ywx.js +0 -1
  47. package/dist/lime-elements/p-cae35eb0.entry.js +0 -1
  48. package/dist/lime-elements/p-e60ffc0a.entry.js +0 -13
@@ -2,10 +2,9 @@
2
2
 
3
3
  var index$1 = require('./index-BjHIBY-I.js');
4
4
  var _commonjsHelpers = require('./_commonjsHelpers-CFO10eej.js');
5
- var _baseIsEqual = require('./_baseIsEqual-aOPReRWl.js');
6
5
  var _baseIteratee = require('./_baseIteratee-DggA4e7a.js');
7
6
  var pickBy = require('./pickBy-kLjYLoam.js');
8
- var isEqual = require('./isEqual-bXyw7kXo.js');
7
+ var _baseIsEqual = require('./_baseIsEqual-aOPReRWl.js');
9
8
  var identity$1 = require('./identity-Dz5mxHaJ.js');
10
9
  var _isIterateeCall = require('./_isIterateeCall-CPWXFS_s.js');
11
10
  var cloneDeep = require('./cloneDeep-CxFNKF1Y.js');
@@ -20,6 +19,7 @@ var isObjectLike = require('./isObjectLike-Dlpn-j-1.js');
20
19
  var isEmpty = require('./isEmpty-EBCFxX1S.js');
21
20
  var isSymbol = require('./isSymbol-DxAVNJfH.js');
22
21
  var isArrayLike = require('./isArrayLike-_dR1U5-Y.js');
22
+ var isEqual = require('./isEqual-bXyw7kXo.js');
23
23
  var moment = require('./moment-CqRdiK10.js');
24
24
  var multiple = require('./multiple-DYfiga7l.js');
25
25
  require('./_getNative-B4n5HX2B.js');
@@ -149,7 +149,7 @@ var funcProto = Function.prototype,
149
149
  var funcToString = funcProto.toString;
150
150
 
151
151
  /** Used to check objects for own properties. */
152
- var hasOwnProperty$1 = objectProto$1.hasOwnProperty;
152
+ var hasOwnProperty$2 = objectProto$1.hasOwnProperty;
153
153
 
154
154
  /** Used to infer the `Object` constructor. */
155
155
  var objectCtorString = funcToString.call(Object);
@@ -190,7 +190,7 @@ function isPlainObject(value) {
190
190
  if (proto === null) {
191
191
  return true;
192
192
  }
193
- var Ctor = hasOwnProperty$1.call(proto, 'constructor') && proto.constructor;
193
+ var Ctor = hasOwnProperty$2.call(proto, 'constructor') && proto.constructor;
194
194
  return typeof Ctor == 'function' && Ctor instanceof Ctor &&
195
195
  funcToString.call(Ctor) == objectCtorString;
196
196
  }
@@ -906,44 +906,6 @@ function parent(object, path) {
906
906
  return path.length < 2 ? object : _baseIteratee.baseGet(object, baseSlice(path, 0, -1));
907
907
  }
908
908
 
909
- /**
910
- * This method is like `_.isEqual` except that it accepts `customizer` which
911
- * is invoked to compare values. If `customizer` returns `undefined`, comparisons
912
- * are handled by the method instead. The `customizer` is invoked with up to
913
- * six arguments: (objValue, othValue [, index|key, object, other, stack]).
914
- *
915
- * @static
916
- * @memberOf _
917
- * @since 4.0.0
918
- * @category Lang
919
- * @param {*} value The value to compare.
920
- * @param {*} other The other value to compare.
921
- * @param {Function} [customizer] The function to customize comparisons.
922
- * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
923
- * @example
924
- *
925
- * function isGreeting(value) {
926
- * return /^h(?:i|ello)$/.test(value);
927
- * }
928
- *
929
- * function customizer(objValue, othValue) {
930
- * if (isGreeting(objValue) && isGreeting(othValue)) {
931
- * return true;
932
- * }
933
- * }
934
- *
935
- * var array = ['hello', 'goodbye'];
936
- * var other = ['hi', 'goodbye'];
937
- *
938
- * _.isEqualWith(array, other, customizer);
939
- * // => true
940
- */
941
- function isEqualWith(value, other, customizer) {
942
- customizer = typeof customizer == 'function' ? customizer : undefined;
943
- var result = customizer ? customizer(value, other) : undefined;
944
- return result === undefined ? _baseIsEqual.baseIsEqual(value, other, undefined, customizer) : !!result;
945
- }
946
-
947
909
  /** `Object#toString` result references. */
948
910
  var numberTag = '[object Number]';
949
911
 
@@ -1100,7 +1062,7 @@ var merge = createAssigner(function(object, source, srcIndex) {
1100
1062
  var objectProto = Object.prototype;
1101
1063
 
1102
1064
  /** Used to check objects for own properties. */
1103
- var hasOwnProperty = objectProto.hasOwnProperty;
1065
+ var hasOwnProperty$1 = objectProto.hasOwnProperty;
1104
1066
 
1105
1067
  /**
1106
1068
  * The base implementation of `_.unset`.
@@ -1127,7 +1089,7 @@ function baseUnset(object, path) {
1127
1089
  var key = _baseIteratee.toKey(path[index]);
1128
1090
 
1129
1091
  // Always block "__proto__" anywhere in the path if it's not expected
1130
- if (key === '__proto__' && !hasOwnProperty.call(object, '__proto__')) {
1092
+ if (key === '__proto__' && !hasOwnProperty$1.call(object, '__proto__')) {
1131
1093
  return false;
1132
1094
  }
1133
1095
 
@@ -18535,24 +18497,634 @@ function createErrorHandler(formData) {
18535
18497
  return handler;
18536
18498
  }
18537
18499
 
18538
- /** Implements a deep equals using the `lodash.isEqualWith` function, that provides a customized comparator that
18539
- * assumes all functions are equivalent.
18500
+ const { getOwnPropertyNames, getOwnPropertySymbols } = Object;
18501
+ // eslint-disable-next-line @typescript-eslint/unbound-method
18502
+ const { hasOwnProperty } = Object.prototype;
18503
+ /**
18504
+ * Combine two comparators into a single comparators.
18505
+ */
18506
+ function combineComparators(comparatorA, comparatorB) {
18507
+ return function isEqual(a, b, state) {
18508
+ return comparatorA(a, b, state) && comparatorB(a, b, state);
18509
+ };
18510
+ }
18511
+ /**
18512
+ * Wrap the provided `areItemsEqual` method to manage the circular state, allowing
18513
+ * for circular references to be safely included in the comparison without creating
18514
+ * stack overflows.
18515
+ */
18516
+ function createIsCircular(areItemsEqual) {
18517
+ return function isCircular(a, b, state) {
18518
+ if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {
18519
+ return areItemsEqual(a, b, state);
18520
+ }
18521
+ const { cache } = state;
18522
+ const cachedA = cache.get(a);
18523
+ const cachedB = cache.get(b);
18524
+ if (cachedA && cachedB) {
18525
+ return cachedA === b && cachedB === a;
18526
+ }
18527
+ cache.set(a, b);
18528
+ cache.set(b, a);
18529
+ const result = areItemsEqual(a, b, state);
18530
+ cache.delete(a);
18531
+ cache.delete(b);
18532
+ return result;
18533
+ };
18534
+ }
18535
+ /**
18536
+ * Get the properties to strictly examine, which include both own properties that are
18537
+ * not enumerable and symbol properties.
18538
+ */
18539
+ function getStrictProperties(object) {
18540
+ return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
18541
+ }
18542
+ /**
18543
+ * Whether the object contains the property passed as an own property.
18544
+ */
18545
+ const hasOwn =
18546
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
18547
+ Object.hasOwn || ((object, property) => hasOwnProperty.call(object, property));
18548
+
18549
+ const PREACT_VNODE = '__v';
18550
+ const PREACT_OWNER = '__o';
18551
+ const REACT_OWNER = '_owner';
18552
+ const { getOwnPropertyDescriptor, keys } = Object;
18553
+ /**
18554
+ * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.
18555
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.
18556
+ *
18557
+ * @note
18558
+ * When available in the environment, this is just a re-export of the global
18559
+ * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.
18560
+ */
18561
+ const sameValueEqual =
18562
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
18563
+ Object.is
18564
+ || function sameValueEqual(a, b) {
18565
+ return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b;
18566
+ };
18567
+ /**
18568
+ * Whether the values passed are equal based on a
18569
+ * [Strict Equality Comparison](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) basis.
18570
+ * Simplified, this maps to if the two values are referentially equal to one another (`a === b`).
18540
18571
  *
18541
- * @param a - The first element to compare
18542
- * @param b - The second element to compare
18543
- * @returns - True if the `a` and `b` are deeply equal, false otherwise
18572
+ * @note
18573
+ * This is mainly available as a convenience function, such as being a default when a function to determine equality between
18574
+ * two objects is used.
18544
18575
  */
18545
- function deepEquals(a, b) {
18546
- return isEqualWith(a, b, (obj, other) => {
18547
- if (typeof obj === 'function' && typeof other === 'function') {
18548
- // Assume all functions are equivalent
18549
- // see https://github.com/rjsf-team/react-jsonschema-form/issues/255
18576
+ function strictEqual(a, b) {
18577
+ return a === b;
18578
+ }
18579
+ /**
18580
+ * Whether the array buffers are equal in value.
18581
+ */
18582
+ function areArrayBuffersEqual(a, b) {
18583
+ return a.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a), new Uint8Array(b));
18584
+ }
18585
+ /**
18586
+ * Whether the arrays are equal in value.
18587
+ */
18588
+ function areArraysEqual(a, b, state) {
18589
+ let index = a.length;
18590
+ if (b.length !== index) {
18591
+ return false;
18592
+ }
18593
+ while (index-- > 0) {
18594
+ if (!state.equals(a[index], b[index], index, index, a, b, state)) {
18595
+ return false;
18596
+ }
18597
+ }
18598
+ return true;
18599
+ }
18600
+ /**
18601
+ * Whether the dataviews are equal in value.
18602
+ */
18603
+ function areDataViewsEqual(a, b) {
18604
+ return (a.byteLength === b.byteLength
18605
+ && areTypedArraysEqual(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength)));
18606
+ }
18607
+ /**
18608
+ * Whether the dates passed are equal in value.
18609
+ */
18610
+ function areDatesEqual(a, b) {
18611
+ return sameValueEqual(a.getTime(), b.getTime());
18612
+ }
18613
+ /**
18614
+ * Whether the errors passed are equal in value.
18615
+ */
18616
+ function areErrorsEqual(a, b) {
18617
+ return a.name === b.name && a.message === b.message && a.cause === b.cause && a.stack === b.stack;
18618
+ }
18619
+ /**
18620
+ * Whether the `Map`s are equal in value.
18621
+ */
18622
+ function areMapsEqual(a, b, state) {
18623
+ const size = a.size;
18624
+ if (size !== b.size) {
18625
+ return false;
18626
+ }
18627
+ if (!size) {
18628
+ return true;
18629
+ }
18630
+ const matchedIndices = new Array(size);
18631
+ const aIterable = a.entries();
18632
+ let aResult;
18633
+ let bResult;
18634
+ let index = 0;
18635
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
18636
+ while ((aResult = aIterable.next())) {
18637
+ if (aResult.done) {
18638
+ break;
18639
+ }
18640
+ const bIterable = b.entries();
18641
+ let hasMatch = false;
18642
+ let matchIndex = 0;
18643
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
18644
+ while ((bResult = bIterable.next())) {
18645
+ if (bResult.done) {
18646
+ break;
18647
+ }
18648
+ if (matchedIndices[matchIndex]) {
18649
+ matchIndex++;
18650
+ continue;
18651
+ }
18652
+ const aEntry = aResult.value;
18653
+ const bEntry = bResult.value;
18654
+ if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a, b, state)
18655
+ && state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a, b, state)) {
18656
+ hasMatch = matchedIndices[matchIndex] = true;
18657
+ break;
18658
+ }
18659
+ matchIndex++;
18660
+ }
18661
+ if (!hasMatch) {
18662
+ return false;
18663
+ }
18664
+ index++;
18665
+ }
18666
+ return true;
18667
+ }
18668
+ /**
18669
+ * Whether the objects are equal in value.
18670
+ */
18671
+ function areObjectsEqual(a, b, state) {
18672
+ const properties = keys(a);
18673
+ let index = properties.length;
18674
+ if (keys(b).length !== index) {
18675
+ return false;
18676
+ }
18677
+ // Decrementing `while` showed faster results than either incrementing or
18678
+ // decrementing `for` loop and than an incrementing `while` loop. Declarative
18679
+ // methods like `some` / `every` were not used to avoid incurring the garbage
18680
+ // cost of anonymous callbacks.
18681
+ while (index-- > 0) {
18682
+ if (!isPropertyEqual(a, b, state, properties[index])) {
18683
+ return false;
18684
+ }
18685
+ }
18686
+ return true;
18687
+ }
18688
+ /**
18689
+ * Whether the objects are equal in value with strict property checking.
18690
+ */
18691
+ function areObjectsEqualStrict(a, b, state) {
18692
+ const properties = getStrictProperties(a);
18693
+ let index = properties.length;
18694
+ if (getStrictProperties(b).length !== index) {
18695
+ return false;
18696
+ }
18697
+ let property;
18698
+ let descriptorA;
18699
+ let descriptorB;
18700
+ // Decrementing `while` showed faster results than either incrementing or
18701
+ // decrementing `for` loop and than an incrementing `while` loop. Declarative
18702
+ // methods like `some` / `every` were not used to avoid incurring the garbage
18703
+ // cost of anonymous callbacks.
18704
+ while (index-- > 0) {
18705
+ property = properties[index];
18706
+ if (!isPropertyEqual(a, b, state, property)) {
18707
+ return false;
18708
+ }
18709
+ descriptorA = getOwnPropertyDescriptor(a, property);
18710
+ descriptorB = getOwnPropertyDescriptor(b, property);
18711
+ if ((descriptorA || descriptorB)
18712
+ && (!descriptorA
18713
+ || !descriptorB
18714
+ || descriptorA.configurable !== descriptorB.configurable
18715
+ || descriptorA.enumerable !== descriptorB.enumerable
18716
+ || descriptorA.writable !== descriptorB.writable)) {
18717
+ return false;
18718
+ }
18719
+ }
18720
+ return true;
18721
+ }
18722
+ /**
18723
+ * Whether the primitive wrappers passed are equal in value.
18724
+ */
18725
+ function arePrimitiveWrappersEqual(a, b) {
18726
+ return sameValueEqual(a.valueOf(), b.valueOf());
18727
+ }
18728
+ /**
18729
+ * Whether the regexps passed are equal in value.
18730
+ */
18731
+ function areRegExpsEqual(a, b) {
18732
+ return a.source === b.source && a.flags === b.flags;
18733
+ }
18734
+ /**
18735
+ * Whether the `Set`s are equal in value.
18736
+ */
18737
+ function areSetsEqual(a, b, state) {
18738
+ const size = a.size;
18739
+ if (size !== b.size) {
18740
+ return false;
18741
+ }
18742
+ if (!size) {
18743
+ return true;
18744
+ }
18745
+ const matchedIndices = new Array(size);
18746
+ const aIterable = a.values();
18747
+ let aResult;
18748
+ let bResult;
18749
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
18750
+ while ((aResult = aIterable.next())) {
18751
+ if (aResult.done) {
18752
+ break;
18753
+ }
18754
+ const bIterable = b.values();
18755
+ let hasMatch = false;
18756
+ let matchIndex = 0;
18757
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
18758
+ while ((bResult = bIterable.next())) {
18759
+ if (bResult.done) {
18760
+ break;
18761
+ }
18762
+ if (!matchedIndices[matchIndex]
18763
+ && state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state)) {
18764
+ hasMatch = matchedIndices[matchIndex] = true;
18765
+ break;
18766
+ }
18767
+ matchIndex++;
18768
+ }
18769
+ if (!hasMatch) {
18770
+ return false;
18771
+ }
18772
+ }
18773
+ return true;
18774
+ }
18775
+ /**
18776
+ * Whether the TypedArray instances are equal in value.
18777
+ */
18778
+ function areTypedArraysEqual(a, b) {
18779
+ let index = a.byteLength;
18780
+ if (b.byteLength !== index || a.byteOffset !== b.byteOffset) {
18781
+ return false;
18782
+ }
18783
+ while (index-- > 0) {
18784
+ if (a[index] !== b[index]) {
18785
+ return false;
18786
+ }
18787
+ }
18788
+ return true;
18789
+ }
18790
+ /**
18791
+ * Whether the URL instances are equal in value.
18792
+ */
18793
+ function areUrlsEqual(a, b) {
18794
+ return (a.hostname === b.hostname
18795
+ && a.pathname === b.pathname
18796
+ && a.protocol === b.protocol
18797
+ && a.port === b.port
18798
+ && a.hash === b.hash
18799
+ && a.username === b.username
18800
+ && a.password === b.password);
18801
+ }
18802
+ function isPropertyEqual(a, b, state, property) {
18803
+ if ((property === REACT_OWNER || property === PREACT_OWNER || property === PREACT_VNODE)
18804
+ && (a.$$typeof || b.$$typeof)) {
18805
+ return true;
18806
+ }
18807
+ return hasOwn(b, property) && state.equals(a[property], b[property], property, property, a, b, state);
18808
+ }
18809
+
18810
+ // eslint-disable-next-line @typescript-eslint/unbound-method
18811
+ const toString = Object.prototype.toString;
18812
+ /**
18813
+ * Create a comparator method based on the type-specific equality comparators passed.
18814
+ */
18815
+ function createEqualityComparator(config) {
18816
+ const supportedComparatorMap = createSupportedComparatorMap(config);
18817
+ const { areArraysEqual, areDatesEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, areRegExpsEqual, areSetsEqual, getUnsupportedCustomComparator, } = config;
18818
+ /**
18819
+ * compare the value of the two objects and return true if they are equivalent in values
18820
+ */
18821
+ return function comparator(a, b, state) {
18822
+ // If the items are strictly equal, no need to do a value comparison.
18823
+ if (a === b) {
18550
18824
  return true;
18551
18825
  }
18552
- return undefined; // fallback to default isEquals behavior
18553
- });
18826
+ // If either of the items are nullish and fail the strictly equal check
18827
+ // above, then they must be unequal.
18828
+ if (a == null || b == null) {
18829
+ return false;
18830
+ }
18831
+ const type = typeof a;
18832
+ if (type !== typeof b) {
18833
+ return false;
18834
+ }
18835
+ if (type !== 'object') {
18836
+ if (type === 'number' || type === 'bigint') {
18837
+ return areNumbersEqual(a, b, state);
18838
+ }
18839
+ if (type === 'function') {
18840
+ return areFunctionsEqual(a, b, state);
18841
+ }
18842
+ // If a primitive value that is not strictly equal, it must be unequal.
18843
+ return false;
18844
+ }
18845
+ const constructor = a.constructor;
18846
+ // Checks are listed in order of commonality of use-case:
18847
+ // 1. Common complex object types (plain object, array)
18848
+ // 2. Common data values (date, regexp)
18849
+ // 3. Less-common complex object types (map, set)
18850
+ // 4. Less-common data values (promise, primitive wrappers)
18851
+ // Inherently this is both subjective and assumptive, however
18852
+ // when reviewing comparable libraries in the wild this order
18853
+ // appears to be generally consistent.
18854
+ // Constructors should match, otherwise there is potential for false positives
18855
+ // between class and subclass or custom object and POJO.
18856
+ if (constructor !== b.constructor) {
18857
+ return false;
18858
+ }
18859
+ // Try to fast-path equality checks for other complex object types in the
18860
+ // same realm to avoid capturing the string tag. Strict equality is used
18861
+ // instead of `instanceof` because it is more performant for the common
18862
+ // use-case. If someone is creating a subclass from a native class, it will be
18863
+ // handled with the string tag comparison.
18864
+ if (constructor === Object) {
18865
+ return areObjectsEqual(a, b, state);
18866
+ }
18867
+ if (constructor === Array) {
18868
+ return areArraysEqual(a, b, state);
18869
+ }
18870
+ if (constructor === Date) {
18871
+ return areDatesEqual(a, b, state);
18872
+ }
18873
+ if (constructor === RegExp) {
18874
+ return areRegExpsEqual(a, b, state);
18875
+ }
18876
+ if (constructor === Map) {
18877
+ return areMapsEqual(a, b, state);
18878
+ }
18879
+ if (constructor === Set) {
18880
+ return areSetsEqual(a, b, state);
18881
+ }
18882
+ if (constructor === Promise) {
18883
+ // Avoid tag checks for promise values, since we know if they are not referentially equal
18884
+ // then they are not equal.
18885
+ return false;
18886
+ }
18887
+ // `isArray()` works on subclasses and is cross-realm, so we can avoid capturing
18888
+ // the string tag or doing an `instanceof` in edge cases.
18889
+ if (Array.isArray(a)) {
18890
+ return areArraysEqual(a, b, state);
18891
+ }
18892
+ // Since this is a custom object, capture the string tag to determining its type.
18893
+ // This is reasonably performant in modern environments like v8 and SpiderMonkey.
18894
+ const tag = toString.call(a);
18895
+ const supportedComparator = supportedComparatorMap[tag];
18896
+ if (supportedComparator) {
18897
+ return supportedComparator(a, b, state);
18898
+ }
18899
+ const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, state, tag);
18900
+ if (unsupportedCustomComparator) {
18901
+ return unsupportedCustomComparator(a, b, state);
18902
+ }
18903
+ // If not matching any tags that require a specific type of comparison, then we hard-code false because
18904
+ // the only thing remaining is strict equality, which has already been compared. This is for a few reasons:
18905
+ // - Certain types that cannot be introspected (e.g., `WeakMap`). For these types, this is the only
18906
+ // comparison that can be made.
18907
+ // - For types that can be introspected but do not have an objective definition of what
18908
+ // equality is (`Error`, etc.), the subjective decision is to be conservative and strictly compare.
18909
+ // In all cases, these decisions should be reevaluated based on changes to the language and
18910
+ // common development practices.
18911
+ return false;
18912
+ };
18913
+ }
18914
+ /**
18915
+ * Create the configuration object used for building comparators.
18916
+ */
18917
+ function createEqualityComparatorConfig({ circular, createCustomConfig, strict, }) {
18918
+ let config = {
18919
+ areArrayBuffersEqual,
18920
+ areArraysEqual: strict ? areObjectsEqualStrict : areArraysEqual,
18921
+ areDataViewsEqual,
18922
+ areDatesEqual: areDatesEqual,
18923
+ areErrorsEqual: areErrorsEqual,
18924
+ areFunctionsEqual: strictEqual,
18925
+ areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
18926
+ areNumbersEqual: sameValueEqual,
18927
+ areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
18928
+ arePrimitiveWrappersEqual: arePrimitiveWrappersEqual,
18929
+ areRegExpsEqual: areRegExpsEqual,
18930
+ areSetsEqual: strict ? combineComparators(areSetsEqual, areObjectsEqualStrict) : areSetsEqual,
18931
+ areTypedArraysEqual: strict
18932
+ ? combineComparators(areTypedArraysEqual, areObjectsEqualStrict)
18933
+ : areTypedArraysEqual,
18934
+ areUrlsEqual: areUrlsEqual,
18935
+ getUnsupportedCustomComparator: undefined,
18936
+ };
18937
+ if (createCustomConfig) {
18938
+ config = Object.assign({}, config, createCustomConfig(config));
18939
+ }
18940
+ if (circular) {
18941
+ const areArraysEqual = createIsCircular(config.areArraysEqual);
18942
+ const areMapsEqual = createIsCircular(config.areMapsEqual);
18943
+ const areObjectsEqual = createIsCircular(config.areObjectsEqual);
18944
+ const areSetsEqual = createIsCircular(config.areSetsEqual);
18945
+ config = Object.assign({}, config, {
18946
+ areArraysEqual,
18947
+ areMapsEqual,
18948
+ areObjectsEqual,
18949
+ areSetsEqual,
18950
+ });
18951
+ }
18952
+ return config;
18953
+ }
18954
+ /**
18955
+ * Default equality comparator pass-through, used as the standard `isEqual` creator for
18956
+ * use inside the built comparator.
18957
+ */
18958
+ function createInternalEqualityComparator(compare) {
18959
+ return function (a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, state) {
18960
+ return compare(a, b, state);
18961
+ };
18962
+ }
18963
+ /**
18964
+ * Create the `isEqual` function used by the consuming application.
18965
+ */
18966
+ function createIsEqual({ circular, comparator, createState, equals, strict }) {
18967
+ if (createState) {
18968
+ return function isEqual(a, b) {
18969
+ const { cache = circular ? new WeakMap() : undefined, meta } = createState();
18970
+ return comparator(a, b, {
18971
+ cache,
18972
+ equals,
18973
+ meta,
18974
+ strict,
18975
+ });
18976
+ };
18977
+ }
18978
+ if (circular) {
18979
+ return function isEqual(a, b) {
18980
+ return comparator(a, b, {
18981
+ cache: new WeakMap(),
18982
+ equals,
18983
+ meta: undefined,
18984
+ strict,
18985
+ });
18986
+ };
18987
+ }
18988
+ const state = {
18989
+ cache: undefined,
18990
+ equals,
18991
+ meta: undefined,
18992
+ strict,
18993
+ };
18994
+ return function isEqual(a, b) {
18995
+ return comparator(a, b, state);
18996
+ };
18997
+ }
18998
+ /**
18999
+ * Create a map of `toString()` values to their respective handlers for `tag`-based lookups.
19000
+ */
19001
+ function createSupportedComparatorMap({ areArrayBuffersEqual, areArraysEqual, areDataViewsEqual, areDatesEqual, areErrorsEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, arePrimitiveWrappersEqual, areRegExpsEqual, areSetsEqual, areTypedArraysEqual, areUrlsEqual, }) {
19002
+ return {
19003
+ '[object Arguments]': areObjectsEqual,
19004
+ '[object Array]': areArraysEqual,
19005
+ '[object ArrayBuffer]': areArrayBuffersEqual,
19006
+ '[object AsyncGeneratorFunction]': areFunctionsEqual,
19007
+ '[object BigInt]': areNumbersEqual,
19008
+ '[object BigInt64Array]': areTypedArraysEqual,
19009
+ '[object BigUint64Array]': areTypedArraysEqual,
19010
+ '[object Boolean]': arePrimitiveWrappersEqual,
19011
+ '[object DataView]': areDataViewsEqual,
19012
+ '[object Date]': areDatesEqual,
19013
+ // If an error tag, it should be tested explicitly. Like RegExp, the properties are not
19014
+ // enumerable, and therefore will give false positives if tested like a standard object.
19015
+ '[object Error]': areErrorsEqual,
19016
+ '[object Float16Array]': areTypedArraysEqual,
19017
+ '[object Float32Array]': areTypedArraysEqual,
19018
+ '[object Float64Array]': areTypedArraysEqual,
19019
+ '[object Function]': areFunctionsEqual,
19020
+ '[object GeneratorFunction]': areFunctionsEqual,
19021
+ '[object Int8Array]': areTypedArraysEqual,
19022
+ '[object Int16Array]': areTypedArraysEqual,
19023
+ '[object Int32Array]': areTypedArraysEqual,
19024
+ '[object Map]': areMapsEqual,
19025
+ '[object Number]': arePrimitiveWrappersEqual,
19026
+ '[object Object]': (a, b, state) =>
19027
+ // The exception for value comparison is custom `Promise`-like class instances. These should
19028
+ // be treated the same as standard `Promise` objects, which means strict equality, and if
19029
+ // it reaches this point then that strict equality comparison has already failed.
19030
+ typeof a.then !== 'function' && typeof b.then !== 'function' && areObjectsEqual(a, b, state),
19031
+ // For RegExp, the properties are not enumerable, and therefore will give false positives if
19032
+ // tested like a standard object.
19033
+ '[object RegExp]': areRegExpsEqual,
19034
+ '[object Set]': areSetsEqual,
19035
+ '[object String]': arePrimitiveWrappersEqual,
19036
+ '[object URL]': areUrlsEqual,
19037
+ '[object Uint8Array]': areTypedArraysEqual,
19038
+ '[object Uint8ClampedArray]': areTypedArraysEqual,
19039
+ '[object Uint16Array]': areTypedArraysEqual,
19040
+ '[object Uint32Array]': areTypedArraysEqual,
19041
+ };
18554
19042
  }
18555
19043
 
19044
+ /**
19045
+ * Whether the items passed are deeply-equal in value.
19046
+ */
19047
+ createCustomEqual();
19048
+ /**
19049
+ * Whether the items passed are deeply-equal in value based on strict comparison.
19050
+ */
19051
+ createCustomEqual({ strict: true });
19052
+ /**
19053
+ * Whether the items passed are deeply-equal in value, including circular references.
19054
+ */
19055
+ createCustomEqual({ circular: true });
19056
+ /**
19057
+ * Whether the items passed are deeply-equal in value, including circular references,
19058
+ * based on strict comparison.
19059
+ */
19060
+ createCustomEqual({
19061
+ circular: true,
19062
+ strict: true,
19063
+ });
19064
+ /**
19065
+ * Whether the items passed are shallowly-equal in value.
19066
+ */
19067
+ createCustomEqual({
19068
+ createInternalComparator: () => sameValueEqual,
19069
+ });
19070
+ /**
19071
+ * Whether the items passed are shallowly-equal in value based on strict comparison
19072
+ */
19073
+ createCustomEqual({
19074
+ strict: true,
19075
+ createInternalComparator: () => sameValueEqual,
19076
+ });
19077
+ /**
19078
+ * Whether the items passed are shallowly-equal in value, including circular references.
19079
+ */
19080
+ createCustomEqual({
19081
+ circular: true,
19082
+ createInternalComparator: () => sameValueEqual,
19083
+ });
19084
+ /**
19085
+ * Whether the items passed are shallowly-equal in value, including circular references,
19086
+ * based on strict comparison.
19087
+ */
19088
+ createCustomEqual({
19089
+ circular: true,
19090
+ createInternalComparator: () => sameValueEqual,
19091
+ strict: true,
19092
+ });
19093
+ /**
19094
+ * Create a custom equality comparison method.
19095
+ *
19096
+ * This can be done to create very targeted comparisons in extreme hot-path scenarios
19097
+ * where the standard methods are not performant enough, but can also be used to provide
19098
+ * support for legacy environments that do not support expected features like
19099
+ * `RegExp.prototype.flags` out of the box.
19100
+ */
19101
+ function createCustomEqual(options = {}) {
19102
+ const { circular = false, createInternalComparator: createCustomInternalComparator, createState, strict = false, } = options;
19103
+ const config = createEqualityComparatorConfig(options);
19104
+ const comparator = createEqualityComparator(config);
19105
+ const equals = createCustomInternalComparator
19106
+ ? createCustomInternalComparator(comparator)
19107
+ : createInternalEqualityComparator(comparator);
19108
+ return createIsEqual({ circular, comparator, createState, equals, strict });
19109
+ }
19110
+
19111
+ /** Implements a deep equals using `fast-equals.createCustomEqual`. Functions
19112
+ * are always considered equal, and circular references are tracked to avoid
19113
+ * infinite recursion on self-referential inputs.
19114
+ *
19115
+ * @param a - The first element to compare
19116
+ * @param b - The second element to compare
19117
+ * @returns - True if the `a` and `b` are deeply equal, false otherwise
19118
+ */
19119
+ const deepEquals = createCustomEqual({
19120
+ circular: true,
19121
+ createCustomConfig: () => ({
19122
+ areFunctionsEqual(_a, b) {
19123
+ return typeof b === 'function';
19124
+ },
19125
+ }),
19126
+ });
19127
+
18556
19128
  const objProto = Object.prototype;
18557
19129
  function isRecordEmpty(rec) {
18558
19130
  for (const key in rec) {
@@ -21614,7 +22186,7 @@ function findSelectedOptionInXxxOf(validator, rootSchema, schema, fallbackField,
21614
22186
  const data = _baseIteratee.get(formData, selectorField);
21615
22187
  if (data !== undefined) {
21616
22188
  return xxxOfs.find((xxx) => {
21617
- return isEqual.isEqual(_baseIteratee.get(xxx, [PROPERTIES_KEY, selectorField, DEFAULT_KEY], _baseIteratee.get(xxx, [PROPERTIES_KEY, selectorField, CONST_KEY])), data);
22189
+ return deepEquals(_baseIteratee.get(xxx, [PROPERTIES_KEY, selectorField, DEFAULT_KEY], _baseIteratee.get(xxx, [PROPERTIES_KEY, selectorField, CONST_KEY])), data);
21618
22190
  });
21619
22191
  }
21620
22192
  }
@@ -22498,11 +23070,6 @@ function getObjectDefaults(validator, rawSchema, { rawFormData, rootSchema = {},
22498
23070
  ? retrievedSchema.additionalProperties
22499
23071
  : {};
22500
23072
  const keys = new Set();
22501
- if (isObject(defaults)) {
22502
- Object.keys(defaults)
22503
- .filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key])
22504
- .forEach((key) => keys.add(key));
22505
- }
22506
23073
  const formDataRequired = [];
22507
23074
  Object.keys(formData)
22508
23075
  .filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key])
@@ -22510,6 +23077,14 @@ function getObjectDefaults(validator, rawSchema, { rawFormData, rootSchema = {},
22510
23077
  keys.add(key);
22511
23078
  formDataRequired.push(key);
22512
23079
  });
23080
+ // Only seed keys from schema defaults when formData has no additionalProperties of its own.
23081
+ // If the user already has data (e.g. after a key rename), injecting default keys would
23082
+ // re-add stale entries that no longer exist in formData.
23083
+ if (isObject(defaults) && formDataRequired.length === 0) {
23084
+ Object.keys(defaults)
23085
+ .filter((key) => !retrievedSchema.properties || !retrievedSchema.properties[key])
23086
+ .forEach((key) => keys.add(key));
23087
+ }
22513
23088
  keys.forEach((key) => {
22514
23089
  var _a;
22515
23090
  const computedDefault = computeDefaults(validator, additionalPropertiesSchema, {
@@ -23498,6 +24073,67 @@ function englishStringTranslator(stringToTranslate, params) {
23498
24073
  return replaceStringParameters(stringToTranslate, params);
23499
24074
  }
23500
24075
 
24076
+ /** Determines whether the given `value` is (one of) the `selected` value(s).
24077
+ *
24078
+ * @param value - The value being checked to see if it is selected
24079
+ * @param selected - The current selected value or list of values
24080
+ * @returns - true if the `value` is one of the `selected` ones, false otherwise
24081
+ */
24082
+ function enumOptionsIsSelected(value, selected) {
24083
+ if (Array.isArray(selected)) {
24084
+ return selected.some((sel) => deepEquals(sel, value));
24085
+ }
24086
+ return deepEquals(selected, value);
24087
+ }
24088
+
24089
+ /** Returns the index(es) of the options in `allEnumOptions` whose value(s) match the ones in `value`. All the
24090
+ * `enumOptions` are filtered based on whether they are a "selected" `value` and the index of each selected one is then
24091
+ * stored in an array. If `multiple` is true, that array is returned, otherwise the first element in the array is
24092
+ * returned.
24093
+ *
24094
+ * @param value - The single value or list of values for which indexes are desired
24095
+ * @param [allEnumOptions=[]] - The list of all the known enumOptions
24096
+ * @param [multiple=false] - Optional flag, if true will return a list of index, otherwise a single one
24097
+ * @returns - A single string index for the first `value` in `allEnumOptions`, if not `multiple`. Otherwise, the list
24098
+ * of indexes for (each of) the value(s) in `value`.
24099
+ */
24100
+ function enumOptionsIndexForValue(value, allEnumOptions = [], multiple = false) {
24101
+ const selectedIndexes = allEnumOptions
24102
+ .map((opt, index) => (enumOptionsIsSelected(opt.value, value) ? String(index) : undefined))
24103
+ .filter((opt) => typeof opt !== 'undefined');
24104
+ if (!multiple) {
24105
+ return selectedIndexes[0];
24106
+ }
24107
+ return selectedIndexes;
24108
+ }
24109
+
24110
+ /** Computes the value to pass to a select element's `value` attribute.
24111
+ *
24112
+ * When `format` is `'realValue'`, converts form data values to strings.
24113
+ * When `format` is `'indexed'` (the default), resolves to index-based values via
24114
+ * `enumOptionsIndexForValue`. Returns `emptyValue` when the current value is empty.
24115
+ *
24116
+ * @param value - The current form data value
24117
+ * @param enumOptions - The available enum options
24118
+ * @param multiple - Whether the select allows multiple selections
24119
+ * @param [format='indexed'] - How option values are encoded on the DOM
24120
+ * @param emptyValue - The value to return when the selection is empty
24121
+ * @returns The value to use for the select element's `value` attribute
24122
+ */
24123
+ function enumOptionSelectedValue(value, enumOptions, multiple, format = 'indexed', emptyValue) {
24124
+ const isEmpty = typeof value === 'undefined' ||
24125
+ (multiple && Array.isArray(value) && value.length < 1) ||
24126
+ (!multiple && value === emptyValue);
24127
+ if (isEmpty) {
24128
+ return emptyValue;
24129
+ }
24130
+ if (format === 'realValue') {
24131
+ return multiple ? value.map(String) : String(value);
24132
+ }
24133
+ const indexes = enumOptionsIndexForValue(value, enumOptions, multiple);
24134
+ return typeof indexes === 'undefined' ? emptyValue : indexes;
24135
+ }
24136
+
23501
24137
  /** Returns the value(s) from `allEnumOptions` at the index(es) provided by `valueIndex`. If `valueIndex` is not an
23502
24138
  * array AND the index is not valid for `allEnumOptions`, `emptyValue` is returned. If `valueIndex` is an array, AND it
23503
24139
  * contains an invalid index, the returned array will have the resulting undefined values filtered out, leaving only
@@ -23522,6 +24158,84 @@ function enumOptionsValueForIndex(valueIndex, allEnumOptions = [], emptyValue) {
23522
24158
  return option ? option.value : emptyValue;
23523
24159
  }
23524
24160
 
24161
+ /** Resolves a single DOM value string back to its typed enum value in `'realValue'` mode.
24162
+ *
24163
+ * First attempts a reverse lookup by matching `String(opt.value)` against the input.
24164
+ * If no option matches and the input parses as a valid index, falls back to the
24165
+ * option at that index — this is how object/array enum values round-trip, since
24166
+ * they are encoded as indices by the encoder.
24167
+ *
24168
+ * @param value - A single string value from a DOM attribute
24169
+ * @param enumOptions - The available enum options
24170
+ * @param emptyValue - The value to return when the input is empty, options are missing, or no match is found
24171
+ * @returns The original typed enum value, or `emptyValue`
24172
+ */
24173
+ function decodeSingle(value, enumOptions, emptyValue) {
24174
+ if (value === '' || !Array.isArray(enumOptions)) {
24175
+ return emptyValue;
24176
+ }
24177
+ const match = enumOptions.find((opt) => String(opt.value) === value);
24178
+ if (match) {
24179
+ return match.value;
24180
+ }
24181
+ // Fallback: value might be an index (for object/array enum values)
24182
+ const index = Number(value);
24183
+ if (!isNaN(index) && index >= 0 && index < enumOptions.length) {
24184
+ return enumOptions[index].value;
24185
+ }
24186
+ return emptyValue;
24187
+ }
24188
+ /** Decodes a string from a DOM value attribute back to a typed enum value.
24189
+ *
24190
+ * When `format` is `'realValue'`, does a reverse lookup: finds the enum option
24191
+ * whose `String(value)` matches the input string and returns the original typed value.
24192
+ * For object/array values that were encoded as indices, falls back to index resolution.
24193
+ *
24194
+ * When `format` is `'indexed'` (the default), uses index-based resolution via
24195
+ * `enumOptionsValueForIndex`.
24196
+ *
24197
+ * @param value - The string value(s) from the DOM
24198
+ * @param enumOptions - The available enum options
24199
+ * @param [format='indexed'] - How the values were encoded on the DOM
24200
+ * @param emptyValue - The value to return for empty/missing selections
24201
+ * @returns The original typed enum value(s)
24202
+ */
24203
+ function enumOptionValueDecoder(value, enumOptions, format = 'indexed', emptyValue) {
24204
+ if (format !== 'realValue') {
24205
+ return enumOptionsValueForIndex(value, enumOptions, emptyValue);
24206
+ }
24207
+ if (Array.isArray(value)) {
24208
+ return value.map((v) => decodeSingle(v, enumOptions, emptyValue));
24209
+ }
24210
+ return decodeSingle(value, enumOptions, emptyValue);
24211
+ }
24212
+
24213
+ /** Encodes an enum option value into a string for a DOM value attribute.
24214
+ *
24215
+ * When `format` is `'realValue'`, primitive values are converted via `String()`.
24216
+ * Non-primitive values (objects, arrays) fall back to the index since
24217
+ * `String()` would produce `"[object Object]"`.
24218
+ *
24219
+ * When `format` is `'indexed'` (the default), returns the index as a string.
24220
+ *
24221
+ * @param value - The typed enum value
24222
+ * @param index - The option's position in the enumOptions array
24223
+ * @param [format='indexed'] - How to encode the value for the DOM attribute
24224
+ * @returns The string to use as the DOM value attribute
24225
+ */
24226
+ function enumOptionValueEncoder(value, index, format = 'indexed') {
24227
+ if (format !== 'realValue') {
24228
+ return String(index);
24229
+ }
24230
+ if (isNil(value)) {
24231
+ return '';
24232
+ }
24233
+ if (typeof value === 'object') {
24234
+ return String(index);
24235
+ }
24236
+ return String(value);
24237
+ }
24238
+
23525
24239
  /** Removes the enum option value at the `valueIndex` from the currently `selected` (list of) value(s). If `selected` is
23526
24240
  * a list, then that list is updated to remove the enum option value with the `valueIndex` in `allEnumOptions`. If it is
23527
24241
  * a single value, then if the enum option value with the `valueIndex` in `allEnumOptions` matches `selected`, undefined
@@ -23542,40 +24256,6 @@ function enumOptionsDeselectValue(valueIndex, selected, allEnumOptions = []) {
23542
24256
  return deepEquals(value, selected) ? undefined : selected;
23543
24257
  }
23544
24258
 
23545
- /** Determines whether the given `value` is (one of) the `selected` value(s).
23546
- *
23547
- * @param value - The value being checked to see if it is selected
23548
- * @param selected - The current selected value or list of values
23549
- * @returns - true if the `value` is one of the `selected` ones, false otherwise
23550
- */
23551
- function enumOptionsIsSelected(value, selected) {
23552
- if (Array.isArray(selected)) {
23553
- return selected.some((sel) => deepEquals(sel, value));
23554
- }
23555
- return deepEquals(selected, value);
23556
- }
23557
-
23558
- /** Returns the index(es) of the options in `allEnumOptions` whose value(s) match the ones in `value`. All the
23559
- * `enumOptions` are filtered based on whether they are a "selected" `value` and the index of each selected one is then
23560
- * stored in an array. If `multiple` is true, that array is returned, otherwise the first element in the array is
23561
- * returned.
23562
- *
23563
- * @param value - The single value or list of values for which indexes are desired
23564
- * @param [allEnumOptions=[]] - The list of all the known enumOptions
23565
- * @param [multiple=false] - Optional flag, if true will return a list of index, otherwise a single one
23566
- * @returns - A single string index for the first `value` in `allEnumOptions`, if not `multiple`. Otherwise, the list
23567
- * of indexes for (each of) the value(s) in `value`.
23568
- */
23569
- function enumOptionsIndexForValue(value, allEnumOptions = [], multiple = false) {
23570
- const selectedIndexes = allEnumOptions
23571
- .map((opt, index) => (enumOptionsIsSelected(opt.value, value) ? String(index) : undefined))
23572
- .filter((opt) => typeof opt !== 'undefined');
23573
- if (!multiple) {
23574
- return selectedIndexes[0];
23575
- }
23576
- return selectedIndexes;
23577
- }
23578
-
23579
24259
  /** Add the enum option value at the `valueIndex` to the list of `selected` values in the proper order as defined by
23580
24260
  * `allEnumOptions`
23581
24261
  *
@@ -23821,6 +24501,15 @@ function getInputProps(schema, defaultType, options = {}, autoDefaultStepAny = t
23821
24501
  }
23822
24502
  }
23823
24503
  }
24504
+ // For date/time input types, propagate formatMinimum/formatMaximum to min/max
24505
+ if (['date', 'datetime-local', 'time', 'week', 'month'].includes(inputProps.type)) {
24506
+ if (schema.formatMinimum !== undefined) {
24507
+ inputProps.min = schema.formatMinimum;
24508
+ }
24509
+ if (schema.formatMaximum !== undefined) {
24510
+ inputProps.max = schema.formatMaximum;
24511
+ }
24512
+ }
23824
24513
  if (options.autocomplete) {
23825
24514
  inputProps.autoComplete = options.autocomplete;
23826
24515
  }
@@ -23830,6 +24519,23 @@ function getInputProps(schema, defaultType, options = {}, autoDefaultStepAny = t
23830
24519
  return inputProps;
23831
24520
  }
23832
24521
 
24522
+ /** Resolves the effective `optionValueFormat` for enum-backed widgets.
24523
+ *
24524
+ * Provides a single source of truth for the default DOM encoding format
24525
+ * (`'indexed'`) used by `SelectWidget`, `RadioWidget`, and `CheckboxesWidget`.
24526
+ * Widgets should call this helper once and pass the result to
24527
+ * `enumOptionValueEncoder`, `enumOptionValueDecoder`, and `enumOptionSelectedValue`
24528
+ * rather than reading `options.optionValueFormat` directly.
24529
+ *
24530
+ * @param options - The widget options (typically from the `options` prop, already
24531
+ * resolved from `ui:options` and `ui:globalOptions`)
24532
+ * @returns The resolved `OptionValueFormat`, defaulting to `'indexed'` when not set
24533
+ */
24534
+ function getOptionValueFormat(options) {
24535
+ var _a;
24536
+ return (_a = options === null || options === void 0 ? void 0 : options.optionValueFormat) !== null && _a !== void 0 ? _a : 'indexed';
24537
+ }
24538
+
23833
24539
  /** The default submit button options, exported for testing purposes
23834
24540
  */
23835
24541
  const DEFAULT_OPTIONS = {
@@ -24246,12 +24952,12 @@ function isFormDataAvailable(formData) {
24246
24952
  */
24247
24953
  function isRootSchema(registry, schemaToCompare) {
24248
24954
  const { rootSchema, schemaUtils } = registry;
24249
- if (isEqual.isEqual(schemaToCompare, rootSchema)) {
24955
+ if (deepEquals(schemaToCompare, rootSchema)) {
24250
24956
  return true;
24251
24957
  }
24252
24958
  if (REF_KEY in rootSchema) {
24253
24959
  const resolvedSchema = schemaUtils.retrieveSchema(rootSchema);
24254
- return isEqual.isEqual(schemaToCompare, omit(resolvedSchema, RJSF_REF_KEY));
24960
+ return deepEquals(schemaToCompare, omit(resolvedSchema, RJSF_REF_KEY));
24255
24961
  }
24256
24962
  return false;
24257
24963
  }
@@ -24286,6 +24992,111 @@ function lookupFromFormContext(regOrFc, toLookup, fallback) {
24286
24992
  return _baseIteratee.get(regOrFc, [...lookupPath, toLookup], fallback);
24287
24993
  }
24288
24994
 
24995
+ /** Determines whether a value is considered "empty" for the purposes of optional object pruning.
24996
+ * A value is empty if it is `undefined`, `null`, an empty string, or an object where all own
24997
+ * properties are themselves empty.
24998
+ *
24999
+ * @param value - The value to check
25000
+ * @returns True if the value is considered empty
25001
+ */
25002
+ function isValueEmpty(value) {
25003
+ if (isNil(value) || value === '') {
25004
+ return true;
25005
+ }
25006
+ if (Array.isArray(value)) {
25007
+ // An empty array is considered empty; a non-empty array is not
25008
+ return value.length === 0;
25009
+ }
25010
+ if (isObject(value)) {
25011
+ const obj = value;
25012
+ const keys = Object.keys(obj);
25013
+ return keys.every((key) => isValueEmpty(obj[key]));
25014
+ }
25015
+ return false;
25016
+ }
25017
+ /** Recursively removes optional objects from the `formData` that are empty (i.e., all their fields
25018
+ * are undefined, null, empty strings, or themselves empty optional objects). This solves the problem
25019
+ * where interacting with fields inside an optional object "activates" it permanently, making the
25020
+ * form unsubmittable when the optional object has required inner fields.
25021
+ *
25022
+ * An object property is considered "optional" when it is NOT listed in its parent schema's `required`
25023
+ * array.
25024
+ *
25025
+ * @param validator - An implementation of the `ValidatorType` interface that will be used when necessary
25026
+ * @param schema - The JSON schema describing the `formData`
25027
+ * @param [rootSchema] - The root schema, used primarily to look up `$ref`s
25028
+ * @param [formData] - The current form data to prune
25029
+ * @returns - A new copy of `formData` with empty optional objects removed, or `undefined` if the
25030
+ * entire formData was pruned
25031
+ */
25032
+ function removeOptionalEmptyObjects(validator, schema, rootSchema, formData) {
25033
+ if (!isObject(schema)) {
25034
+ return formData;
25035
+ }
25036
+ const resolvedSchema = retrieveSchema(validator, schema, rootSchema, formData);
25037
+ if (Array.isArray(formData)) {
25038
+ const itemsSchema = resolvedSchema.items;
25039
+ if (!itemsSchema) {
25040
+ return formData;
25041
+ }
25042
+ let hasChanges = false;
25043
+ const mapped = formData.map((item, index) => {
25044
+ let itemSchema = itemsSchema;
25045
+ if (Array.isArray(itemsSchema)) {
25046
+ itemSchema = itemsSchema[index] || resolvedSchema.additionalItems || {};
25047
+ }
25048
+ const cleaned = removeOptionalEmptyObjects(validator, itemSchema, rootSchema, item);
25049
+ if (cleaned !== item) {
25050
+ hasChanges = true;
25051
+ }
25052
+ return cleaned === undefined ? {} : cleaned;
25053
+ });
25054
+ // Although T is an array type here, we still need to cast it back to T since TS
25055
+ // doesn't narrow the generic T automatically
25056
+ return hasChanges ? mapped : formData;
25057
+ }
25058
+ const { properties, required: requiredFields = [] } = resolvedSchema;
25059
+ if (!isObject(formData) || !properties) {
25060
+ return formData;
25061
+ }
25062
+ const result = {};
25063
+ const data = formData;
25064
+ let hasAnyValue = false;
25065
+ for (const key of Object.keys(data)) {
25066
+ const value = data[key];
25067
+ const propertySchema = (properties[key] || {});
25068
+ const isRequired = requiredFields.includes(key);
25069
+ const isObj = isObject(value);
25070
+ const isArr = Array.isArray(value);
25071
+ if ((isObj || isArr) && properties[key]) {
25072
+ // Recursively process nested objects and arrays
25073
+ const cleaned = removeOptionalEmptyObjects(validator, propertySchema, rootSchema, value);
25074
+ if (!isRequired && isValueEmpty(cleaned)) {
25075
+ // This is an optional property and the cleaned result is empty — omit it
25076
+ continue;
25077
+ }
25078
+ result[key] = cleaned;
25079
+ hasAnyValue = true;
25080
+ }
25081
+ else if (!isRequired && isValueEmpty(value) && properties[key]) {
25082
+ // Optional scalar property that is empty — omit it
25083
+ continue;
25084
+ }
25085
+ else {
25086
+ result[key] = value;
25087
+ if (!isValueEmpty(value)) {
25088
+ hasAnyValue = true;
25089
+ }
25090
+ }
25091
+ }
25092
+ // If the entire object ended up empty after pruning, return undefined so that the
25093
+ // caller (which may itself be a recursive call) can decide whether to keep or drop it
25094
+ if (!hasAnyValue && Object.keys(result).length === 0) {
25095
+ return undefined;
25096
+ }
25097
+ return result;
25098
+ }
25099
+
24289
25100
  /** Given a list of `properties` and an `order` list, returns a list that contains the `properties` ordered correctly.
24290
25101
  * If `order` is not an array, then the untouched `properties` list is returned. Otherwise `properties` is ordered per
24291
25102
  * the `order` list. If `order` contains a '*' then any `properties` that are not mentioned explicity in `order` will be
@@ -24356,104 +25167,18 @@ function parseDateString(dateString, includeTime = true) {
24356
25167
  };
24357
25168
  }
24358
25169
 
24359
- // Keywords where child schemas map to uiSchema at the SAME key
24360
- const SAME_KEY_KEYWORDS = [ITEMS_KEY, ADDITIONAL_PROPERTIES_KEY];
24361
- // Keywords where child schemas are in an array, each mapping to uiSchema[keyword][i]
24362
- const ARRAY_KEYWORDS = [ONE_OF_KEY, ANY_OF_KEY, ALL_OF_KEY];
24363
- /** Expands `ui:definitions` into the uiSchema by walking the schema tree and finding all `$ref`s.
24364
- * Called once at form initialization to pre-expand definitions into the uiSchema structure.
24365
- *
24366
- * For recursive schemas, expansion stops at recursion points to avoid infinite loops.
24367
- * Runtime resolution via `resolveUiSchema` handles these cases using registry definitions.
24368
- *
24369
- * @param currentSchema - The current schema node being processed
24370
- * @param uiSchema - The uiSchema at the current path
24371
- * @param registry - The registry containing rootSchema and uiSchemaDefinitions
24372
- * @param visited - Set of $refs already visited (to detect recursion)
24373
- * @returns - The expanded uiSchema with definitions merged in
24374
- */
24375
- function expandUiSchemaDefinitions(currentSchema, uiSchema, registry, visited = new Set()) {
24376
- const { rootSchema, uiSchemaDefinitions: definitions } = registry;
24377
- let result = { ...uiSchema };
24378
- let resolvedSchema = currentSchema;
24379
- const ref = currentSchema[REF_KEY];
24380
- const isRecursive = ref && visited.has(ref);
24381
- if (ref) {
24382
- visited.add(ref);
24383
- if (definitions && ref in definitions) {
24384
- result = mergeObjects(definitions[ref], result);
24385
- }
24386
- if (isRecursive) {
24387
- return result;
24388
- }
24389
- try {
24390
- resolvedSchema = findSchemaDefinition(ref, rootSchema);
24391
- }
24392
- catch (_a) {
24393
- resolvedSchema = currentSchema;
24394
- }
24395
- }
24396
- // Process properties (each property maps to uiSchema[propName] - flattened)
24397
- const properties = resolvedSchema[PROPERTIES_KEY];
24398
- if (properties && isObject(properties)) {
24399
- for (const [propName, propSchema] of Object.entries(properties)) {
24400
- const propUiSchema = (result[propName] || {});
24401
- const expanded = expandUiSchemaDefinitions(propSchema, propUiSchema, registry, new Set(visited));
24402
- if (Object.keys(expanded).length > 0) {
24403
- result[propName] = expanded;
24404
- }
24405
- }
24406
- }
24407
- // Process keywords where child maps to same key in uiSchema (items, additionalProperties)
24408
- for (const keyword of SAME_KEY_KEYWORDS) {
24409
- const subSchema = resolvedSchema[keyword];
24410
- if (subSchema && isObject(subSchema) && !Array.isArray(subSchema)) {
24411
- const currentUiSchema = result[keyword];
24412
- if (typeof currentUiSchema !== 'function') {
24413
- const subUiSchema = (currentUiSchema || {});
24414
- const expanded = expandUiSchemaDefinitions(subSchema, subUiSchema, registry, new Set(visited));
24415
- if (Object.keys(expanded).length > 0) {
24416
- result[keyword] = expanded;
24417
- }
24418
- }
24419
- }
24420
- }
24421
- // Process array keywords (oneOf, anyOf, allOf) - each option maps to uiSchema[keyword][i]
24422
- for (const keyword of ARRAY_KEYWORDS) {
24423
- const schemaOptions = resolvedSchema[keyword];
24424
- if (Array.isArray(schemaOptions) && schemaOptions.length > 0) {
24425
- const currentUiSchemaArray = result[keyword];
24426
- const uiSchemaArray = Array.isArray(currentUiSchemaArray) ? [...currentUiSchemaArray] : [];
24427
- let hasExpanded = false;
24428
- for (let i = 0; i < schemaOptions.length; i++) {
24429
- const optionSchema = schemaOptions[i];
24430
- const optionUiSchema = (uiSchemaArray[i] || {});
24431
- const expanded = expandUiSchemaDefinitions(optionSchema, optionUiSchema, registry, new Set(visited));
24432
- if (Object.keys(expanded).length > 0) {
24433
- uiSchemaArray[i] = expanded;
24434
- hasExpanded = true;
24435
- }
24436
- }
24437
- if (hasExpanded) {
24438
- result[keyword] = uiSchemaArray;
24439
- }
24440
- }
24441
- }
24442
- return result;
24443
- }
24444
25170
  /** Resolves the uiSchema for a given schema, considering `ui:definitions` stored in the registry.
24445
25171
  *
24446
- * This function is called at runtime for each field. It handles recursive schemas where the
24447
- * pre-expansion in `expandUiSchemaDefinitions` couldn't go deeper.
24448
- *
24449
- * When the schema contains a `$ref`, this function looks up the corresponding uiSchema definition
24450
- * from `registry.uiSchemaDefinitions` and merges it with any local uiSchema overrides.
25172
+ * Called at runtime for each field. When the schema contains a `$ref`, looks up the corresponding
25173
+ * uiSchema definition from `registry.uiSchemaDefinitions` and merges it with local overrides.
25174
+ * For schemas with `oneOf`/`anyOf` branches, also populates `uiSchema[keyword][i]` for branches
25175
+ * whose `$ref` matches a definition, so `MultiSchemaField` can read dropdown option titles.
24451
25176
  *
24452
25177
  * Resolution order (later sources override earlier):
24453
25178
  * 1. `ui:definitions[$ref]` - base definition from registry
24454
25179
  * 2. `localUiSchema` - local overrides at current path
24455
25180
  *
24456
- * @param schema - The JSON schema (may still contain `$ref` for recursive schemas)
25181
+ * @param schema - The JSON schema (may contain `$ref` or `RJSF_REF_KEY`)
24457
25182
  * @param localUiSchema - The uiSchema at the current path (local overrides)
24458
25183
  * @param registry - The registry containing `uiSchemaDefinitions`
24459
25184
  * @returns - The resolved uiSchema with definitions merged in
@@ -24461,14 +25186,54 @@ function expandUiSchemaDefinitions(currentSchema, uiSchema, registry, visited =
24461
25186
  function resolveUiSchema(schema, localUiSchema, registry) {
24462
25187
  var _a, _b;
24463
25188
  const ref = ((_a = schema[RJSF_REF_KEY]) !== null && _a !== void 0 ? _a : schema[REF_KEY]);
24464
- const definitionUiSchema = ref ? (_b = registry.uiSchemaDefinitions) === null || _b === void 0 ? void 0 : _b[ref] : undefined;
25189
+ const definitions = registry.uiSchemaDefinitions;
25190
+ const definitionUiSchema = ref && definitions ? definitions[ref] : undefined;
25191
+ let result;
24465
25192
  if (!definitionUiSchema) {
24466
- return localUiSchema || {};
25193
+ result = localUiSchema || {};
24467
25194
  }
24468
- if (!localUiSchema || Object.keys(localUiSchema).length === 0) {
24469
- return { ...definitionUiSchema };
25195
+ else if (!localUiSchema || isEmpty.isEmpty(localUiSchema)) {
25196
+ result = { ...definitionUiSchema };
25197
+ }
25198
+ else {
25199
+ result = mergeObjects(definitionUiSchema, localUiSchema);
25200
+ }
25201
+ // Walk oneOf/anyOf branches to populate uiSchema[keyword][i] so MultiSchemaField
25202
+ // can read dropdown option titles at the parent level.
25203
+ if (definitions) {
25204
+ let resolvedSchema = schema;
25205
+ if (ref && schema[REF_KEY] && !schema[RJSF_REF_KEY]) {
25206
+ try {
25207
+ resolvedSchema = findSchemaDefinition(ref, registry.rootSchema);
25208
+ }
25209
+ catch (e) {
25210
+ console.warn('could not resolve $ref in resolveUiSchema:\n', e);
25211
+ return result;
25212
+ }
25213
+ }
25214
+ for (const keyword of [ONE_OF_KEY, ANY_OF_KEY]) {
25215
+ const schemaOptions = resolvedSchema[keyword];
25216
+ if (!Array.isArray(schemaOptions) || schemaOptions.length === 0) {
25217
+ continue;
25218
+ }
25219
+ const currentUiSchemaArray = result[keyword];
25220
+ const uiSchemaArray = Array.isArray(currentUiSchemaArray) ? [...currentUiSchemaArray] : [];
25221
+ let hasExpanded = false;
25222
+ for (let i = 0; i < schemaOptions.length; i++) {
25223
+ const option = schemaOptions[i];
25224
+ const optionRef = ((_b = option === null || option === void 0 ? void 0 : option[RJSF_REF_KEY]) !== null && _b !== void 0 ? _b : option === null || option === void 0 ? void 0 : option[REF_KEY]);
25225
+ if (optionRef && optionRef in definitions) {
25226
+ const optionUiSchema = (uiSchemaArray[i] || {});
25227
+ uiSchemaArray[i] = mergeObjects(definitions[optionRef], optionUiSchema);
25228
+ hasExpanded = true;
25229
+ }
25230
+ }
25231
+ if (hasExpanded) {
25232
+ result[keyword] = uiSchemaArray;
25233
+ }
25234
+ }
24470
25235
  }
24471
- return mergeObjects(definitionUiSchema, localUiSchema);
25236
+ return result;
24472
25237
  }
24473
25238
 
24474
25239
  /** Check to see if a `schema` specifies that a value must be true. This happens when:
@@ -24779,7 +25544,7 @@ function useAltDateWidgetProps(props) {
24779
25544
  */
24780
25545
  function useDeepCompareMemo(newValue) {
24781
25546
  const valueRef = reactExports.useRef(newValue);
24782
- if (!isEqual.isEqual(newValue, valueRef.current)) {
25547
+ if (!deepEquals(newValue, valueRef.current)) {
24783
25548
  valueRef.current = newValue;
24784
25549
  }
24785
25550
  return valueRef.current;
@@ -25704,10 +26469,12 @@ function ArrayField$1(props) {
25704
26469
  * @param index - The index of the item being changed
25705
26470
  */
25706
26471
  const handleChange = reactExports.useCallback((value, path, newErrorSchema, id) => {
26472
+ const lastPathIsItemIndex = typeof path.at(-1) === 'number';
25707
26473
  onChange(
25708
26474
  // We need to treat undefined items as nulls to have validation.
25709
26475
  // See https://github.com/tdegrunt/jsonschema/issues/206
25710
- value === undefined ? null : value, path, newErrorSchema, id);
26476
+ // Only set to null for array items, and not for object properties within array items
26477
+ lastPathIsItemIndex && value === undefined ? null : value, path, newErrorSchema, id);
25711
26478
  }, [onChange]);
25712
26479
  /** Callback handler used to change the value for a checkbox */
25713
26480
  const onSelectChange = reactExports.useCallback((value) => {
@@ -27023,11 +27790,14 @@ function ObjectField$1(props) {
27023
27790
  const { schema: rawSchema, uiSchema = {}, formData, errorSchema, fieldPathId, name, required = false, disabled, readonly, hideError, onBlur, onFocus, onChange, registry, title, } = props;
27024
27791
  const { fields, schemaUtils, translateString, globalUiOptions } = registry;
27025
27792
  const { OptionalDataControlsField } = fields;
27793
+ const formDataRef = reactExports.useRef(formData);
27794
+ formDataRef.current = formData;
27026
27795
  const schema = schemaUtils.retrieveSchema(rawSchema, formData, true);
27027
27796
  const uiOptions = getUiOptions(uiSchema, globalUiOptions);
27028
27797
  const { properties: schemaProperties = {} } = schema;
27029
27798
  // All the children will use childFieldPathId if present in the props, falling back to the fieldPathId
27030
27799
  const childFieldPathId = props.childFieldPathId ?? fieldPathId;
27800
+ const lastRenamedProperty = reactExports.useRef({ previousKey: '', currentKey: undefined });
27031
27801
  const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
27032
27802
  const description = uiOptions.description ?? schema.description;
27033
27803
  const renderOptionalField = shouldRenderOptionalField(registry, schema, required, uiSchema);
@@ -27087,6 +27857,10 @@ function ObjectField$1(props) {
27087
27857
  // Cast this to make the `set` work properly
27088
27858
  set(newFormData, newKey, newValue);
27089
27859
  }
27860
+ if (lastRenamedProperty.current.previousKey === newKey) {
27861
+ lastRenamedProperty.current.currentKey = newKey;
27862
+ lastRenamedProperty.current.previousKey = getAvailableKey(newKey, newFormData);
27863
+ }
27090
27864
  onChange(newFormData, childFieldPathId.path);
27091
27865
  }, [formData, onChange, registry, childFieldPathId, getAvailableKey, schema]);
27092
27866
  /** Returns a callback function that deals with the rename of a key for an additional property for a schema. That
@@ -27098,9 +27872,10 @@ function ObjectField$1(props) {
27098
27872
  */
27099
27873
  const handleKeyRename = reactExports.useCallback((oldKey, newKey) => {
27100
27874
  if (oldKey !== newKey) {
27101
- const actualNewKey = getAvailableKey(newKey, formData);
27875
+ const currentFormData = formDataRef.current;
27876
+ const actualNewKey = getAvailableKey(newKey, currentFormData);
27102
27877
  const newFormData = {
27103
- ...formData,
27878
+ ...currentFormData,
27104
27879
  };
27105
27880
  const newKeys = { [oldKey]: actualNewKey };
27106
27881
  const keyValues = Object.keys(newFormData).map((key) => {
@@ -27108,15 +27883,31 @@ function ObjectField$1(props) {
27108
27883
  return { [newKey]: newFormData[key] };
27109
27884
  });
27110
27885
  const renamedObj = Object.assign({}, ...keyValues);
27886
+ formDataRef.current = renamedObj;
27887
+ if (oldKey !== lastRenamedProperty.current.currentKey) {
27888
+ lastRenamedProperty.current.previousKey = oldKey;
27889
+ }
27890
+ lastRenamedProperty.current.currentKey = actualNewKey;
27111
27891
  onChange(renamedObj, childFieldPathId.path);
27112
27892
  }
27113
- }, [formData, onChange, childFieldPathId, getAvailableKey]);
27893
+ }, [onChange, childFieldPathId, getAvailableKey]);
27114
27894
  /** Handles the remove click which calls the `onChange` callback with the special ADDITIONAL_PROPERTY_FIELD_REMOVE
27115
27895
  * value for the path plus the key to be removed
27116
27896
  */
27117
27897
  const handleRemoveProperty = reactExports.useCallback((key) => {
27118
27898
  onChange(ADDITIONAL_PROPERTY_KEY_REMOVE, [...childFieldPathId.path, key]);
27119
27899
  }, [onChange, childFieldPathId]);
27900
+ /** Returns the stable React key for a property. For the most recently renamed
27901
+ * additional property, returns the previous key so that React reuses the
27902
+ * existing component instance instead of unmounting/remounting it. This
27903
+ * preserves DOM focus naturally without manual focus management.
27904
+ */
27905
+ const getStableKey = reactExports.useCallback((property) => {
27906
+ if (lastRenamedProperty.current.currentKey === property) {
27907
+ return lastRenamedProperty.current.previousKey;
27908
+ }
27909
+ return property;
27910
+ }, []);
27120
27911
  if (!renderOptionalField || hasFormData) {
27121
27912
  try {
27122
27913
  const properties = Object.keys(schemaProperties);
@@ -27136,7 +27927,7 @@ function ObjectField$1(props) {
27136
27927
  const addedByAdditionalProperties = pickBy.has(schema, [PROPERTIES_KEY, name, ADDITIONAL_PROPERTY_FLAG]);
27137
27928
  const fieldUiSchema = addedByAdditionalProperties ? uiSchema.additionalProperties : uiSchema[name];
27138
27929
  const hidden = getUiOptions(fieldUiSchema).widget === 'hidden';
27139
- const content = (jsxRuntimeExports.jsx(ObjectFieldProperty, { propertyName: name, required: isRequired(schema, name), schema: _baseIteratee.get(schema, [PROPERTIES_KEY, name], {}), uiSchema: fieldUiSchema, errorSchema: _baseIteratee.get(errorSchema, [name]), fieldPathId: childFieldPathId, formData: _baseIteratee.get(formData, [name]), handleKeyRename: handleKeyRename, handleRemoveProperty: handleRemoveProperty, addedByAdditionalProperties: addedByAdditionalProperties, onChange: onChange, onBlur: onBlur, onFocus: onFocus, registry: registry, disabled: disabled, readonly: readonly, hideError: hideError }, name));
27930
+ const content = (jsxRuntimeExports.jsx(ObjectFieldProperty, { propertyName: name, required: isRequired(schema, name), schema: _baseIteratee.get(schema, [PROPERTIES_KEY, name], {}), uiSchema: fieldUiSchema, errorSchema: _baseIteratee.get(errorSchema, [name]), fieldPathId: childFieldPathId, formData: _baseIteratee.get(formData, [name]), handleKeyRename: handleKeyRename, handleRemoveProperty: handleRemoveProperty, addedByAdditionalProperties: addedByAdditionalProperties, onChange: onChange, onBlur: onBlur, onFocus: onFocus, registry: registry, disabled: disabled, readonly: readonly, hideError: hideError }, getStableKey(name)));
27140
27931
  return {
27141
27932
  content,
27142
27933
  name,
@@ -27881,7 +28672,7 @@ function WrapIfAdditionalTemplate(props) {
27881
28672
  return (jsxRuntimeExports.jsx("div", { className: uiClassNames, style: style, children: children }));
27882
28673
  }
27883
28674
  const margin = hasDescription ? 46 : 26;
27884
- return (jsxRuntimeExports.jsx("div", { className: uiClassNames, style: style, children: jsxRuntimeExports.jsxs("div", { className: 'row', children: [jsxRuntimeExports.jsx("div", { className: 'col-xs-5 form-additional', children: jsxRuntimeExports.jsxs("div", { className: 'form-group', children: [displayLabel && jsxRuntimeExports.jsx(Label, { label: keyLabel, required: required, id: `${id}-key` }), displayLabel && rawDescription && jsxRuntimeExports.jsx("div", { children: "\u00A0" }), jsxRuntimeExports.jsx("input", { className: 'form-control', type: 'text', id: `${id}-key`, onBlur: onKeyRenameBlur, defaultValue: label })] }) }), jsxRuntimeExports.jsx("div", { className: 'form-additional form-group col-xs-5', children: children }), jsxRuntimeExports.jsx("div", { className: 'col-xs-2', style: { marginTop: displayLabel ? `${margin}px` : undefined }, children: jsxRuntimeExports.jsx(RemoveButton, { id: buttonId(id, 'remove'), className: 'rjsf-object-property-remove btn-block', style: { border: '0' }, disabled: disabled || readonly, onClick: onRemoveProperty, uiSchema: uiSchema, registry: registry }) })] }) }));
28675
+ return (jsxRuntimeExports.jsx("div", { className: uiClassNames, style: style, children: jsxRuntimeExports.jsxs("div", { className: 'row', children: [jsxRuntimeExports.jsx("div", { className: 'col-xs-5 form-additional', children: jsxRuntimeExports.jsxs("div", { className: 'form-group', children: [displayLabel && jsxRuntimeExports.jsx(Label, { label: keyLabel, required: required, id: `${id}-key` }), displayLabel && rawDescription && jsxRuntimeExports.jsx("div", { children: "\u00A0" }), jsxRuntimeExports.jsx("input", { className: 'form-control', type: 'text', id: `${id}-key`, onBlur: onKeyRenameBlur, defaultValue: label }, label)] }) }), jsxRuntimeExports.jsx("div", { className: 'form-additional form-group col-xs-5', children: children }), jsxRuntimeExports.jsx("div", { className: 'col-xs-2', style: { marginTop: displayLabel ? `${margin}px` : undefined }, children: jsxRuntimeExports.jsx(RemoveButton, { id: buttonId(id, 'remove'), className: 'rjsf-object-property-remove btn-block', style: { border: '0' }, disabled: disabled || readonly, onClick: onRemoveProperty, uiSchema: uiSchema, registry: registry }) })] }) }));
27885
28676
  }
27886
28677
 
27887
28678
  function templates() {
@@ -27954,10 +28745,12 @@ function CheckboxWidget({ schema, uiSchema, options, id, value, disabled, readon
27954
28745
  *
27955
28746
  * @param props - The `WidgetProps` for this component
27956
28747
  */
27957
- function CheckboxesWidget({ id, disabled, options: { inline = false, enumOptions, enumDisabled, emptyValue }, value, autofocus = false, readonly, onChange, onBlur, onFocus, htmlName, }) {
28748
+ function CheckboxesWidget({ id, disabled, options, value, autofocus = false, readonly, onChange, onBlur, onFocus, htmlName, }) {
28749
+ const { inline = false, enumOptions, enumDisabled, emptyValue } = options;
28750
+ const optionValueFormat = getOptionValueFormat(options);
27958
28751
  const checkboxesValues = Array.isArray(value) ? value : [value];
27959
- const handleBlur = reactExports.useCallback(({ target }) => onBlur(id, enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)), [onBlur, id, enumOptions, emptyValue]);
27960
- const handleFocus = reactExports.useCallback(({ target }) => onFocus(id, enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)), [onFocus, id, enumOptions, emptyValue]);
28752
+ const handleBlur = reactExports.useCallback(({ target }) => onBlur(id, enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)), [onBlur, id, enumOptions, emptyValue, optionValueFormat]);
28753
+ const handleFocus = reactExports.useCallback(({ target }) => onFocus(id, enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)), [onFocus, id, enumOptions, emptyValue, optionValueFormat]);
27961
28754
  return (jsxRuntimeExports.jsx("div", { className: 'checkboxes', id: id, children: Array.isArray(enumOptions) &&
27962
28755
  enumOptions.map((option, index) => {
27963
28756
  const checked = enumOptionsIsSelected(option.value, checkboxesValues);
@@ -27971,7 +28764,7 @@ function CheckboxesWidget({ id, disabled, options: { inline = false, enumOptions
27971
28764
  onChange(enumOptionsDeselectValue(index, checkboxesValues, enumOptions));
27972
28765
  }
27973
28766
  };
27974
- const checkbox = (jsxRuntimeExports.jsxs("span", { children: [jsxRuntimeExports.jsx("input", { type: 'checkbox', id: optionId(id, index), name: htmlName || id, checked: checked, value: String(index), disabled: disabled || itemDisabled || readonly, autoFocus: autofocus && index === 0, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, "aria-describedby": ariaDescribedByIds(id) }), jsxRuntimeExports.jsx("span", { children: option.label })] }));
28767
+ const checkbox = (jsxRuntimeExports.jsxs("span", { children: [jsxRuntimeExports.jsx("input", { type: 'checkbox', id: optionId(id, index), name: htmlName || id, checked: checked, value: enumOptionValueEncoder(option.value, index, optionValueFormat), disabled: disabled || itemDisabled || readonly, autoFocus: autofocus && index === 0, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, "aria-describedby": ariaDescribedByIds(id) }), jsxRuntimeExports.jsx("span", { children: option.label })] }));
27975
28768
  return inline ? (jsxRuntimeExports.jsx("label", { className: `checkbox-inline ${disabledCls}`, children: checkbox }, index)) : (jsxRuntimeExports.jsx("div", { className: `checkbox ${disabledCls}`, children: jsxRuntimeExports.jsx("label", { children: checkbox }) }, index));
27976
28769
  }) }));
27977
28770
  }
@@ -28089,15 +28882,16 @@ function PasswordWidget(props) {
28089
28882
  */
28090
28883
  function RadioWidget({ options, value, required, disabled, readonly, autofocus = false, onBlur, onFocus, onChange, id, htmlName, }) {
28091
28884
  const { enumOptions, enumDisabled, inline, emptyValue } = options;
28092
- const handleBlur = reactExports.useCallback(({ target }) => onBlur(id, enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)), [onBlur, enumOptions, emptyValue, id]);
28093
- const handleFocus = reactExports.useCallback(({ target }) => onFocus(id, enumOptionsValueForIndex(target && target.value, enumOptions, emptyValue)), [onFocus, enumOptions, emptyValue, id]);
28885
+ const optionValueFormat = getOptionValueFormat(options);
28886
+ const handleBlur = reactExports.useCallback(({ target }) => onBlur(id, enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)), [onBlur, enumOptions, emptyValue, id, optionValueFormat]);
28887
+ const handleFocus = reactExports.useCallback(({ target }) => onFocus(id, enumOptionValueDecoder(target && target.value, enumOptions, optionValueFormat, emptyValue)), [onFocus, enumOptions, emptyValue, id, optionValueFormat]);
28094
28888
  return (jsxRuntimeExports.jsx("div", { className: 'field-radio-group', id: id, role: 'radiogroup', children: Array.isArray(enumOptions) &&
28095
28889
  enumOptions.map((option, i) => {
28096
28890
  const checked = enumOptionsIsSelected(option.value, value);
28097
28891
  const itemDisabled = Array.isArray(enumDisabled) && enumDisabled.indexOf(option.value) !== -1;
28098
28892
  const disabledCls = disabled || itemDisabled || readonly ? 'disabled' : '';
28099
28893
  const handleChange = () => onChange(option.value);
28100
- const radio = (jsxRuntimeExports.jsxs("span", { children: [jsxRuntimeExports.jsx("input", { type: 'radio', id: optionId(id, i), checked: checked, name: htmlName || id, required: required, value: String(i), disabled: disabled || itemDisabled || readonly, autoFocus: autofocus && i === 0, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, "aria-describedby": ariaDescribedByIds(id) }), jsxRuntimeExports.jsx("span", { children: option.label })] }));
28894
+ const radio = (jsxRuntimeExports.jsxs("span", { children: [jsxRuntimeExports.jsx("input", { type: 'radio', id: optionId(id, i), checked: checked, name: htmlName || id, required: required, value: enumOptionValueEncoder(option.value, i, optionValueFormat), disabled: disabled || itemDisabled || readonly, autoFocus: autofocus && i === 0, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, "aria-describedby": ariaDescribedByIds(id) }), jsxRuntimeExports.jsx("span", { children: option.label })] }));
28101
28895
  return inline ? (jsxRuntimeExports.jsx("label", { className: `radio-inline ${disabledCls}`, children: radio }, i)) : (jsxRuntimeExports.jsx("div", { className: `radio ${disabledCls}`, children: jsxRuntimeExports.jsx("label", { children: radio }) }, i));
28102
28896
  }) }));
28103
28897
  }
@@ -28191,24 +28985,25 @@ function getValue(event, multiple) {
28191
28985
  function SelectWidget({ schema, id, options, value, required, disabled, readonly, multiple = false, autofocus = false, onChange, onBlur, onFocus, placeholder, htmlName, }) {
28192
28986
  const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;
28193
28987
  const emptyValue = multiple ? [] : '';
28988
+ const optionValueFormat = getOptionValueFormat(options);
28194
28989
  const handleFocus = reactExports.useCallback((event) => {
28195
28990
  const newValue = getValue(event, multiple);
28196
- return onFocus(id, enumOptionsValueForIndex(newValue, enumOptions, optEmptyVal));
28197
- }, [onFocus, id, multiple, enumOptions, optEmptyVal]);
28991
+ return onFocus(id, enumOptionValueDecoder(newValue, enumOptions, optionValueFormat, optEmptyVal));
28992
+ }, [onFocus, id, multiple, enumOptions, optEmptyVal, optionValueFormat]);
28198
28993
  const handleBlur = reactExports.useCallback((event) => {
28199
28994
  const newValue = getValue(event, multiple);
28200
- return onBlur(id, enumOptionsValueForIndex(newValue, enumOptions, optEmptyVal));
28201
- }, [onBlur, id, multiple, enumOptions, optEmptyVal]);
28995
+ return onBlur(id, enumOptionValueDecoder(newValue, enumOptions, optionValueFormat, optEmptyVal));
28996
+ }, [onBlur, id, multiple, enumOptions, optEmptyVal, optionValueFormat]);
28202
28997
  const handleChange = reactExports.useCallback((event) => {
28203
28998
  const newValue = getValue(event, multiple);
28204
- return onChange(enumOptionsValueForIndex(newValue, enumOptions, optEmptyVal));
28205
- }, [onChange, multiple, enumOptions, optEmptyVal]);
28206
- const selectedIndexes = enumOptionsIndexForValue(value, enumOptions, multiple);
28999
+ return onChange(enumOptionValueDecoder(newValue, enumOptions, optionValueFormat, optEmptyVal));
29000
+ }, [onChange, multiple, enumOptions, optEmptyVal, optionValueFormat]);
29001
+ const selectValue = enumOptionSelectedValue(value, enumOptions, multiple, optionValueFormat, emptyValue);
28207
29002
  const showPlaceholderOption = !multiple && schema.default === undefined;
28208
- return (jsxRuntimeExports.jsxs("select", { id: id, name: htmlName || id, multiple: multiple, role: 'combobox', className: 'form-control', value: typeof selectedIndexes === 'undefined' ? emptyValue : selectedIndexes, required: required, disabled: disabled || readonly, autoFocus: autofocus, onBlur: handleBlur, onFocus: handleFocus, onChange: handleChange, "aria-describedby": ariaDescribedByIds(id), children: [showPlaceholderOption && jsxRuntimeExports.jsx("option", { value: '', children: placeholder }), Array.isArray(enumOptions) &&
29003
+ return (jsxRuntimeExports.jsxs("select", { id: id, name: htmlName || id, multiple: multiple, role: 'combobox', className: 'form-control', value: selectValue, required: required, disabled: disabled || readonly, autoFocus: autofocus, onBlur: handleBlur, onFocus: handleFocus, onChange: handleChange, "aria-describedby": ariaDescribedByIds(id), children: [showPlaceholderOption && jsxRuntimeExports.jsx("option", { value: '', children: placeholder }), Array.isArray(enumOptions) &&
28209
29004
  enumOptions.map(({ value, label }, i) => {
28210
29005
  const disabled = enumDisabled && enumDisabled.indexOf(value) !== -1;
28211
- return (jsxRuntimeExports.jsx("option", { value: String(i), disabled: disabled, children: label }, i));
29006
+ return (jsxRuntimeExports.jsx("option", { value: enumOptionValueEncoder(value, i, optionValueFormat), disabled: disabled, children: label }, i));
28212
29007
  })] }));
28213
29008
  }
28214
29009
 
@@ -28546,10 +29341,6 @@ let Form$1 = class Form extends reactExports.Component {
28546
29341
  // Only store a new registry when the props cause a different one to be created
28547
29342
  const newRegistry = this.getRegistry(props, rootSchema, schemaUtils);
28548
29343
  const registry = deepEquals(state.registry, newRegistry) ? state.registry : newRegistry;
28549
- // Pre-expand ui:definitions into the uiSchema structure (must happen after registry is created)
28550
- const expandedUiSchema = registry.uiSchemaDefinitions
28551
- ? expandUiSchemaDefinitions(rootSchema, uiSchema, registry)
28552
- : uiSchema;
28553
29344
  // Only compute a new `fieldPathId` when the `idPrefix` is different than the existing fieldPathId's ID_KEY
28554
29345
  const fieldPathId = state.fieldPathId && state.fieldPathId?.[ID_KEY] === registry.globalFormOptions.idPrefix
28555
29346
  ? state.fieldPathId
@@ -28557,7 +29348,7 @@ let Form$1 = class Form extends reactExports.Component {
28557
29348
  const nextState = {
28558
29349
  schemaUtils,
28559
29350
  schema: rootSchema,
28560
- uiSchema: expandedUiSchema,
29351
+ uiSchema,
28561
29352
  fieldPathId,
28562
29353
  formData,
28563
29354
  edit,
@@ -28731,9 +29522,13 @@ let Form$1 = class Form extends reactExports.Component {
28731
29522
  this._isProcessingUserChange = true;
28732
29523
  const { newValue, path, id } = this.pendingChanges[0];
28733
29524
  const { newErrorSchema } = this.pendingChanges[0];
28734
- const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
29525
+ const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange, removeEmptyOptionalObjects } = this.props;
28735
29526
  const { formData: oldFormData, schemaUtils, schema, fieldPathId, schemaValidationErrorSchema, errors } = this.state;
28736
- let { customErrors, errorSchema: originalErrorSchema } = this.state;
29527
+ let { customErrors } = this.state;
29528
+ // Use the un-merged AJV-only schema as the base for re-merging extraErrors. Mirrors the
29529
+ // pattern in getStateFromProps/getDerivedStateFromProps and avoids the duplication that
29530
+ // happened when state.errorSchema (already containing merged extraErrors) was passed in.
29531
+ let mergeBaseErrorSchema = schemaValidationErrorSchema;
28737
29532
  const rootPathId = fieldPathId.path[0] || '';
28738
29533
  const isRootPath = !path || path.length === 0 || (path.length === 1 && path[0] === rootPathId);
28739
29534
  let retrievedSchema = this.state.retrievedSchema;
@@ -28770,18 +29565,27 @@ let Form$1 = class Form extends reactExports.Component {
28770
29565
  formData: newFormData,
28771
29566
  };
28772
29567
  }
29568
+ if (removeEmptyOptionalObjects) {
29569
+ newFormData = removeOptionalEmptyObjects(schemaUtils.getValidator(), schema, schemaUtils.getRootSchema(), newFormData);
29570
+ state = {
29571
+ ...state,
29572
+ formData: newFormData,
29573
+ };
29574
+ }
28773
29575
  if (newErrorSchema) {
28774
29576
  // First check to see if there is an existing validation error on this path...
28775
29577
  // @ts-expect-error TS2590, because getting from the error schema is confusing TS
28776
29578
  const oldValidationError = !isRootPath ? _baseIteratee.get(schemaValidationErrorSchema, path) : schemaValidationErrorSchema;
28777
29579
  // If there is an old validation error for this path, assume we are updating it directly
28778
29580
  if (!isEmpty.isEmpty(oldValidationError)) {
28779
- // Update the originalErrorSchema "in place" or replace it if it is the root
29581
+ // Apply the user-supplied newErrorSchema onto a clone of the AJV-only base, so that
29582
+ // mergeErrors below sees the user's error at this path without mutating shared state.
28780
29583
  if (!isRootPath) {
28781
- set(originalErrorSchema, path, newErrorSchema);
29584
+ mergeBaseErrorSchema = cloneDeep.cloneDeep(schemaValidationErrorSchema);
29585
+ set(mergeBaseErrorSchema, path, newErrorSchema);
28782
29586
  }
28783
29587
  else {
28784
- originalErrorSchema = newErrorSchema;
29588
+ mergeBaseErrorSchema = newErrorSchema;
28785
29589
  }
28786
29590
  }
28787
29591
  else {
@@ -28806,12 +29610,12 @@ let Form$1 = class Form extends reactExports.Component {
28806
29610
  }
28807
29611
  // If there are pending changes in the queue, skip live validation since it will happen with the last change
28808
29612
  if (mustValidate && this.pendingChanges.length === 1) {
28809
- const liveValidation = this.liveValidate(schema, schemaUtils, originalErrorSchema, newFormData, extraErrors, customErrors, retrievedSchema);
29613
+ const liveValidation = this.liveValidate(schema, schemaUtils, mergeBaseErrorSchema, newFormData, extraErrors, customErrors, retrievedSchema);
28810
29614
  state = { formData: newFormData, ...liveValidation, customErrors };
28811
29615
  }
28812
29616
  else if (!noValidate && newErrorSchema) {
28813
29617
  // Merging 'newErrorSchema' into 'errorSchema' to display the custom raised errors.
28814
- const mergedErrors = this.mergeErrors({ errorSchema: originalErrorSchema, errors }, extraErrors, customErrors);
29618
+ const mergedErrors = this.mergeErrors({ errorSchema: mergeBaseErrorSchema, errors }, extraErrors, customErrors);
28815
29619
  state = {
28816
29620
  formData: newFormData,
28817
29621
  ...mergedErrors,
@@ -28870,19 +29674,23 @@ let Form$1 = class Form extends reactExports.Component {
28870
29674
  * @param data - The data associated with the field that was blurred
28871
29675
  */
28872
29676
  onBlur = (id, data) => {
28873
- const { onBlur, omitExtraData, liveOmit, liveValidate } = this.props;
29677
+ const { onBlur, omitExtraData, liveOmit, liveValidate, removeEmptyOptionalObjects } = this.props;
28874
29678
  if (onBlur) {
28875
29679
  onBlur(id, data);
28876
29680
  }
28877
29681
  if ((omitExtraData === true && liveOmit === 'onBlur') || liveValidate === 'onBlur') {
28878
29682
  const { onChange, extraErrors } = this.props;
28879
- const { formData } = this.state;
29683
+ const { formData, schemaUtils, schema } = this.state;
28880
29684
  let newFormData = formData;
28881
29685
  let state = { formData: newFormData };
28882
29686
  if (omitExtraData === true && liveOmit === 'onBlur') {
28883
29687
  newFormData = this.omitExtraData(formData);
28884
29688
  state = { formData: newFormData };
28885
29689
  }
29690
+ if (removeEmptyOptionalObjects) {
29691
+ newFormData = removeOptionalEmptyObjects(schemaUtils.getValidator(), schema, schemaUtils.getRootSchema(), newFormData);
29692
+ state = { ...state, formData: newFormData };
29693
+ }
28886
29694
  if (liveValidate === 'onBlur') {
28887
29695
  const { schema, schemaUtils, errorSchema, customErrors, retrievedSchema } = this.state;
28888
29696
  const liveValidation = this.liveValidate(schema, schemaUtils, errorSchema, newFormData, extraErrors, customErrors, retrievedSchema);
@@ -28929,11 +29737,15 @@ let Form$1 = class Form extends reactExports.Component {
28929
29737
  return;
28930
29738
  }
28931
29739
  event.persist();
28932
- const { omitExtraData, extraErrors, noValidate, onSubmit } = this.props;
29740
+ const { omitExtraData, extraErrors, noValidate, onSubmit, removeEmptyOptionalObjects } = this.props;
28933
29741
  let { formData: newFormData } = this.state;
28934
29742
  if (omitExtraData === true) {
28935
29743
  newFormData = this.omitExtraData(newFormData);
28936
29744
  }
29745
+ if (removeEmptyOptionalObjects) {
29746
+ const { schemaUtils, schema } = this.state;
29747
+ newFormData = removeOptionalEmptyObjects(schemaUtils.getValidator(), schema, schemaUtils.getRootSchema(), newFormData);
29748
+ }
28937
29749
  if (noValidate || this.validateFormWithFormData(newFormData)) {
28938
29750
  // There are no errors generated through schema validation.
28939
29751
  // Check for user provided errors and update state accordingly.
@@ -29026,8 +29838,9 @@ let Form$1 = class Form extends reactExports.Component {
29026
29838
  const elementId = path.join(idSeparator);
29027
29839
  let field = this.formElement.current.elements[elementId];
29028
29840
  if (!field) {
29029
- // if not an exact match, try finding an input starting with the element id (like radio buttons or checkboxes)
29030
- field = this.formElement.current.querySelector(`input[id^="${elementId}"`);
29841
+ // if not an exact match, try finding a focusable element starting with the element id (like radio buttons or checkboxes)
29842
+ // some themes (e.g. shadcn) use button elements instead of native inputs for radio groups
29843
+ field = this.formElement.current.querySelector(`input[id^="${elementId}"], button[id^="${elementId}"]`);
29031
29844
  }
29032
29845
  if (field && field.length) {
29033
29846
  // If we got a list with length > 0
@@ -29101,11 +29914,15 @@ let Form$1 = class Form extends reactExports.Component {
29101
29914
  * @returns - True if the form is valid, false otherwise.
29102
29915
  */
29103
29916
  validateForm() {
29104
- const { omitExtraData } = this.props;
29917
+ const { omitExtraData, removeEmptyOptionalObjects } = this.props;
29105
29918
  let { formData: newFormData } = this.state;
29106
29919
  if (omitExtraData === true) {
29107
29920
  newFormData = this.omitExtraData(newFormData);
29108
29921
  }
29922
+ if (removeEmptyOptionalObjects) {
29923
+ const { schemaUtils, schema } = this.state;
29924
+ newFormData = removeOptionalEmptyObjects(schemaUtils.getValidator(), schema, schemaUtils.getRootSchema(), newFormData);
29925
+ }
29109
29926
  return this.validateFormWithFormData(newFormData);
29110
29927
  }
29111
29928
  /** Renders the `Form` fields inside the <form> | `tagName` or `_internalFormWrapper`, rendering any errors if
@@ -35784,13 +36601,50 @@ function createAjvInstance(additionalMetaSchemas, customFormats, ajvOptionsOverr
35784
36601
  return ajv;
35785
36602
  }
35786
36603
 
36604
+ /** Filters duplicate errors from `anyOf`/`oneOf` schema paths according to the `suppressDuplicateFiltering` flag.
36605
+ *
36606
+ * @param errorList - The list of `RJSFValidationError`s to filter
36607
+ * @param [suppressDuplicateFiltering='none'] - Controls which duplicate filtering is suppressed:
36608
+ * - `'none'` (default): filters duplicates for both `anyOf` and `oneOf`
36609
+ * - `'all'`: returns `errorList` unmodified
36610
+ * - `'anyOf'`: suppresses filtering for `anyOf` errors; `oneOf` duplicates are still filtered
36611
+ * - `'oneOf'`: suppresses filtering for `oneOf` errors; `anyOf` duplicates are still filtered
36612
+ */
36613
+ function filterDuplicateErrors(errorList, suppressDuplicateFiltering = 'none') {
36614
+ if (suppressDuplicateFiltering === 'all') {
36615
+ return errorList;
36616
+ }
36617
+ return errorList.reduce((acc, err) => {
36618
+ const { message, schemaPath } = err;
36619
+ // Compute the index only when filtering for that keyword is not suppressed.
36620
+ // 'all' is already handled above; within the reduce, only 'none', 'anyOf', and 'oneOf' are possible.
36621
+ const anyOfIndex = suppressDuplicateFiltering !== 'anyOf' ? schemaPath === null || schemaPath === void 0 ? void 0 : schemaPath.indexOf(`/${ANY_OF_KEY}/`) : undefined;
36622
+ const oneOfIndex = suppressDuplicateFiltering !== 'oneOf' ? schemaPath === null || schemaPath === void 0 ? void 0 : schemaPath.indexOf(`/${ONE_OF_KEY}/`) : undefined;
36623
+ let schemaPrefix;
36624
+ if (anyOfIndex && anyOfIndex >= 0) {
36625
+ schemaPrefix = schemaPath === null || schemaPath === void 0 ? void 0 : schemaPath.substring(0, anyOfIndex);
36626
+ }
36627
+ else if (oneOfIndex && oneOfIndex >= 0) {
36628
+ schemaPrefix = schemaPath === null || schemaPath === void 0 ? void 0 : schemaPath.substring(0, oneOfIndex);
36629
+ }
36630
+ // If there is a schemaPrefix, then search for a duplicate message with the same prefix, otherwise undefined
36631
+ const dup = schemaPrefix
36632
+ ? acc.find((e) => { var _a; return e.message === message && ((_a = e.schemaPath) === null || _a === void 0 ? void 0 : _a.startsWith(schemaPrefix)); })
36633
+ : undefined;
36634
+ if (!dup) {
36635
+ acc.push(err);
36636
+ }
36637
+ return acc;
36638
+ }, []);
36639
+ }
35787
36640
  /** Transforming the error output from ajv to format used by @rjsf/utils.
35788
36641
  * At some point, components should be updated to support ajv.
35789
36642
  *
35790
36643
  * @param errors - The list of AJV errors to convert to `RJSFValidationErrors`
35791
36644
  * @param [uiSchema] - An optional uiSchema that is passed to `transformErrors` and `customValidate`
36645
+ * @param [suppressDuplicateFiltering] - Controls which duplicate filtering is suppressed; see `filterDuplicateErrors`
35792
36646
  */
35793
- function transformRJSFValidationErrors(errors = [], uiSchema) {
36647
+ function transformRJSFValidationErrors(errors = [], uiSchema, suppressDuplicateFiltering) {
35794
36648
  const errorList = errors.map((e) => {
35795
36649
  var _a;
35796
36650
  const { instancePath, keyword, params, schemaPath, parentSchema, ...rest } = e;
@@ -35860,29 +36714,7 @@ function transformRJSFValidationErrors(errors = [], uiSchema) {
35860
36714
  title: uiTitle,
35861
36715
  };
35862
36716
  });
35863
- // Filter out duplicates around anyOf/oneOf messages
35864
- return errorList.reduce((acc, err) => {
35865
- const { message, schemaPath } = err;
35866
- const anyOfIndex = schemaPath === null || schemaPath === void 0 ? void 0 : schemaPath.indexOf(`/${ANY_OF_KEY}/`);
35867
- const oneOfIndex = schemaPath === null || schemaPath === void 0 ? void 0 : schemaPath.indexOf(`/${ONE_OF_KEY}/`);
35868
- let schemaPrefix;
35869
- // Look specifically for `/anyOr/` or `/oneOf/` within the schemaPath information
35870
- if (anyOfIndex && anyOfIndex >= 0) {
35871
- schemaPrefix = schemaPath === null || schemaPath === void 0 ? void 0 : schemaPath.substring(0, anyOfIndex);
35872
- }
35873
- else if (oneOfIndex && oneOfIndex >= 0) {
35874
- schemaPrefix = schemaPath === null || schemaPath === void 0 ? void 0 : schemaPath.substring(0, oneOfIndex);
35875
- }
35876
- // If there is a schemaPrefix, then search for a duplicate message with the same prefix, otherwise undefined
35877
- const dup = schemaPrefix
35878
- ? acc.find((e) => { var _a; return e.message === message && ((_a = e.schemaPath) === null || _a === void 0 ? void 0 : _a.startsWith(schemaPrefix)); })
35879
- : undefined;
35880
- if (!dup) {
35881
- // Only push an error that is not a duplicate
35882
- acc.push(err);
35883
- }
35884
- return acc;
35885
- }, []);
36717
+ return filterDuplicateErrors(errorList, suppressDuplicateFiltering);
35886
36718
  }
35887
36719
  /** This function processes the `formData` with an optional user contributed `customValidate` function, which receives
35888
36720
  * the form data and a `errorHandler` function that will be used to add custom validation errors for each field. Also
@@ -35896,10 +36728,11 @@ function transformRJSFValidationErrors(errors = [], uiSchema) {
35896
36728
  * @param [customValidate] - An optional function that is used to perform custom validation
35897
36729
  * @param [transformErrors] - An optional function that is used to transform errors after AJV validation
35898
36730
  * @param [uiSchema] - An optional uiSchema that is passed to `transformErrors` and `customValidate`
36731
+ * @param [suppressDuplicateFiltering] - Controls which duplicate filtering is suppressed; see `filterDuplicateErrors`
35899
36732
  */
35900
- function processRawValidationErrors(validator, rawErrors, formData, schema, customValidate, transformErrors, uiSchema) {
36733
+ function processRawValidationErrors(validator, rawErrors, formData, schema, customValidate, transformErrors, uiSchema, suppressDuplicateFiltering) {
35901
36734
  const { validationError: invalidSchemaError } = rawErrors;
35902
- let errors = transformRJSFValidationErrors(rawErrors.errors, uiSchema);
36735
+ let errors = transformRJSFValidationErrors(rawErrors.errors, uiSchema, suppressDuplicateFiltering);
35903
36736
  if (invalidSchemaError) {
35904
36737
  errors = [...errors, { stack: invalidSchemaError.message }];
35905
36738
  }
@@ -35934,14 +36767,22 @@ class AJV8Validator {
35934
36767
  * @param [localizer] - If provided, is used to localize a list of Ajv `ErrorObject`s
35935
36768
  */
35936
36769
  constructor(options, localizer) {
35937
- const { additionalMetaSchemas, customFormats, ajvOptionsOverrides, ajvFormatOptions, AjvClass, extenderFn } = options;
36770
+ /** True once a `rootSchema` has been registered with Ajv in this lifecycle.
36771
+ *
36772
+ * @private
36773
+ */
36774
+ this.hasRegisteredRootSchema = false;
36775
+ const { additionalMetaSchemas, customFormats, ajvOptionsOverrides, ajvFormatOptions, AjvClass, extenderFn, suppressDuplicateFiltering, } = options;
35938
36776
  this.ajv = createAjvInstance(additionalMetaSchemas, customFormats, ajvOptionsOverrides, ajvFormatOptions, AjvClass, extenderFn);
35939
36777
  this.localizer = localizer;
36778
+ this.suppressDuplicateFiltering = suppressDuplicateFiltering;
35940
36779
  }
35941
36780
  /** Resets the internal AJV validator to clear schemas from it. Can be helpful for resetting the validator for tests.
35942
36781
  */
35943
36782
  reset() {
35944
36783
  this.ajv.removeSchema();
36784
+ this.lastSeenRootSchema = undefined;
36785
+ this.hasRegisteredRootSchema = false;
35945
36786
  }
35946
36787
  /** Runs the pure validation of the `schema` and `formData` without any of the RJSF functionality. Provided for use
35947
36788
  * by the playground. Returns the `errors` from the validation
@@ -36029,14 +36870,19 @@ class AJV8Validator {
36029
36870
  */
36030
36871
  validateFormData(formData, schema, customValidate, transformErrors, uiSchema) {
36031
36872
  const rawErrors = this.rawValidation(schema, formData);
36032
- return processRawValidationErrors(this, rawErrors, formData, schema, customValidate, transformErrors, uiSchema);
36873
+ return processRawValidationErrors(this, rawErrors, formData, schema, customValidate, transformErrors, uiSchema, this.suppressDuplicateFiltering);
36033
36874
  }
36034
36875
  /**
36035
36876
  * This function checks if a schema needs to be added and if the root schemas don't match it removes the old root schema from the ajv instance and adds the new one.
36877
+ * When called repeatedly with the same `rootSchema` reference the deep-equality check is skipped.
36878
+ *
36036
36879
  * @param rootSchema - The root schema used to provide $ref resolutions
36037
36880
  */
36038
36881
  handleSchemaUpdate(rootSchema) {
36039
36882
  var _a, _b;
36883
+ if (this.lastSeenRootSchema === rootSchema && this.hasRegisteredRootSchema) {
36884
+ return;
36885
+ }
36040
36886
  const rootSchemaId = (_a = rootSchema[ID_KEY]) !== null && _a !== void 0 ? _a : ROOT_SCHEMA_PREFIX;
36041
36887
  // add the rootSchema ROOT_SCHEMA_PREFIX as id.
36042
36888
  // if schema validator instance doesn't exist, add it.
@@ -36048,6 +36894,8 @@ class AJV8Validator {
36048
36894
  this.ajv.removeSchema(rootSchemaId);
36049
36895
  this.ajv.addSchema(rootSchema, rootSchemaId);
36050
36896
  }
36897
+ this.lastSeenRootSchema = rootSchema;
36898
+ this.hasRegisteredRootSchema = true;
36051
36899
  }
36052
36900
  /** Validates data against a schema, returning true if the data is valid, or
36053
36901
  * false otherwise. If the schema is invalid, then this function will return