@rjsf/core 6.6.1 → 6.7.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 (262) hide show
  1. package/LICENSE.md +201 -0
  2. package/dist/core.umd.js +694 -584
  3. package/dist/index.cjs +1191 -1071
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.esm.js +1030 -984
  6. package/dist/index.esm.js.map +4 -4
  7. package/lib/components/Form.d.ts +16 -13
  8. package/lib/components/Form.d.ts.map +1 -1
  9. package/lib/components/Form.js +126 -76
  10. package/lib/components/RichDescription.d.ts +3 -3
  11. package/lib/components/RichDescription.d.ts.map +1 -1
  12. package/lib/components/RichDescription.js +1 -1
  13. package/lib/components/RichHelp.d.ts +3 -3
  14. package/lib/components/RichHelp.d.ts.map +1 -1
  15. package/lib/components/RichHelp.js +1 -1
  16. package/lib/components/SchemaExamples.d.ts +2 -2
  17. package/lib/components/SchemaExamples.d.ts.map +1 -1
  18. package/lib/components/SchemaExamples.js +1 -3
  19. package/lib/components/fields/ArrayField.d.ts +2 -2
  20. package/lib/components/fields/ArrayField.d.ts.map +1 -1
  21. package/lib/components/fields/ArrayField.js +87 -88
  22. package/lib/components/fields/BooleanField.d.ts +2 -2
  23. package/lib/components/fields/BooleanField.d.ts.map +1 -1
  24. package/lib/components/fields/BooleanField.js +2 -5
  25. package/lib/components/fields/CyclicSchemaField.d.ts +8 -0
  26. package/lib/components/fields/CyclicSchemaField.d.ts.map +1 -0
  27. package/lib/components/fields/CyclicSchemaField.js +21 -0
  28. package/lib/components/fields/FallbackField.d.ts +2 -2
  29. package/lib/components/fields/FallbackField.d.ts.map +1 -1
  30. package/lib/components/fields/FallbackField.js +2 -2
  31. package/lib/components/fields/LayoutGridField.d.ts +8 -10
  32. package/lib/components/fields/LayoutGridField.d.ts.map +1 -1
  33. package/lib/components/fields/LayoutGridField.js +5 -4
  34. package/lib/components/fields/LayoutHeaderField.d.ts +2 -2
  35. package/lib/components/fields/LayoutHeaderField.d.ts.map +1 -1
  36. package/lib/components/fields/LayoutHeaderField.js +1 -1
  37. package/lib/components/fields/LayoutMultiSchemaField.d.ts +2 -2
  38. package/lib/components/fields/LayoutMultiSchemaField.d.ts.map +1 -1
  39. package/lib/components/fields/LayoutMultiSchemaField.js +4 -1
  40. package/lib/components/fields/MultiSchemaField.d.ts +2 -41
  41. package/lib/components/fields/MultiSchemaField.d.ts.map +1 -1
  42. package/lib/components/fields/MultiSchemaField.js +116 -122
  43. package/lib/components/fields/NullField.d.ts +1 -1
  44. package/lib/components/fields/NullField.d.ts.map +1 -1
  45. package/lib/components/fields/NumberField.d.ts +2 -2
  46. package/lib/components/fields/NumberField.d.ts.map +1 -1
  47. package/lib/components/fields/NumberField.js +7 -9
  48. package/lib/components/fields/ObjectField.d.ts +2 -2
  49. package/lib/components/fields/ObjectField.d.ts.map +1 -1
  50. package/lib/components/fields/ObjectField.js +28 -26
  51. package/lib/components/fields/OptionalDataControlsField.d.ts +2 -2
  52. package/lib/components/fields/OptionalDataControlsField.d.ts.map +1 -1
  53. package/lib/components/fields/SchemaField.d.ts +14 -8
  54. package/lib/components/fields/SchemaField.d.ts.map +1 -1
  55. package/lib/components/fields/SchemaField.js +43 -30
  56. package/lib/components/fields/StringField.d.ts +2 -2
  57. package/lib/components/fields/StringField.d.ts.map +1 -1
  58. package/lib/components/fields/StringField.js +2 -5
  59. package/lib/components/fields/index.d.ts +1 -1
  60. package/lib/components/fields/index.d.ts.map +1 -1
  61. package/lib/components/fields/index.js +2 -0
  62. package/lib/components/templates/ArrayFieldDescriptionTemplate.d.ts +2 -2
  63. package/lib/components/templates/ArrayFieldDescriptionTemplate.d.ts.map +1 -1
  64. package/lib/components/templates/ArrayFieldDescriptionTemplate.js +1 -1
  65. package/lib/components/templates/ArrayFieldItemButtonsTemplate.d.ts +2 -2
  66. package/lib/components/templates/ArrayFieldItemButtonsTemplate.d.ts.map +1 -1
  67. package/lib/components/templates/ArrayFieldItemButtonsTemplate.js +1 -1
  68. package/lib/components/templates/ArrayFieldItemTemplate.d.ts +2 -2
  69. package/lib/components/templates/ArrayFieldItemTemplate.d.ts.map +1 -1
  70. package/lib/components/templates/ArrayFieldItemTemplate.js +1 -1
  71. package/lib/components/templates/ArrayFieldTemplate.d.ts +2 -2
  72. package/lib/components/templates/ArrayFieldTemplate.d.ts.map +1 -1
  73. package/lib/components/templates/ArrayFieldTemplate.js +1 -1
  74. package/lib/components/templates/ArrayFieldTitleTemplate.d.ts +2 -2
  75. package/lib/components/templates/ArrayFieldTitleTemplate.d.ts.map +1 -1
  76. package/lib/components/templates/ArrayFieldTitleTemplate.js +1 -1
  77. package/lib/components/templates/BaseInputTemplate.d.ts +2 -2
  78. package/lib/components/templates/BaseInputTemplate.d.ts.map +1 -1
  79. package/lib/components/templates/BaseInputTemplate.js +7 -6
  80. package/lib/components/templates/ButtonTemplates/AddButton.d.ts +2 -2
  81. package/lib/components/templates/ButtonTemplates/AddButton.d.ts.map +1 -1
  82. package/lib/components/templates/ButtonTemplates/IconButton.d.ts +14 -7
  83. package/lib/components/templates/ButtonTemplates/IconButton.d.ts.map +1 -1
  84. package/lib/components/templates/ButtonTemplates/IconButton.js +14 -6
  85. package/lib/components/templates/ButtonTemplates/SubmitButton.d.ts +2 -2
  86. package/lib/components/templates/ButtonTemplates/SubmitButton.d.ts.map +1 -1
  87. package/lib/components/templates/ButtonTemplates/index.d.ts +1 -1
  88. package/lib/components/templates/ButtonTemplates/index.d.ts.map +1 -1
  89. package/lib/components/templates/CyclicSchemaExpandTemplate.d.ts +7 -0
  90. package/lib/components/templates/CyclicSchemaExpandTemplate.d.ts.map +1 -0
  91. package/lib/components/templates/CyclicSchemaExpandTemplate.js +12 -0
  92. package/lib/components/templates/DescriptionField.d.ts +2 -2
  93. package/lib/components/templates/DescriptionField.d.ts.map +1 -1
  94. package/lib/components/templates/ErrorList.d.ts +2 -2
  95. package/lib/components/templates/ErrorList.d.ts.map +1 -1
  96. package/lib/components/templates/ErrorList.js +2 -4
  97. package/lib/components/templates/FallbackFieldTemplate.d.ts +2 -2
  98. package/lib/components/templates/FallbackFieldTemplate.d.ts.map +1 -1
  99. package/lib/components/templates/FieldErrorTemplate.d.ts +2 -2
  100. package/lib/components/templates/FieldErrorTemplate.d.ts.map +1 -1
  101. package/lib/components/templates/FieldErrorTemplate.js +1 -3
  102. package/lib/components/templates/FieldHelpTemplate.d.ts +2 -2
  103. package/lib/components/templates/FieldHelpTemplate.d.ts.map +1 -1
  104. package/lib/components/templates/FieldTemplate/FieldTemplate.d.ts +2 -2
  105. package/lib/components/templates/FieldTemplate/FieldTemplate.d.ts.map +1 -1
  106. package/lib/components/templates/FieldTemplate/FieldTemplate.js +1 -1
  107. package/lib/components/templates/FieldTemplate/Label.d.ts +3 -3
  108. package/lib/components/templates/FieldTemplate/Label.d.ts.map +1 -1
  109. package/lib/components/templates/GridTemplate.d.ts +2 -2
  110. package/lib/components/templates/GridTemplate.d.ts.map +1 -1
  111. package/lib/components/templates/MultiSchemaFieldTemplate.d.ts +2 -2
  112. package/lib/components/templates/MultiSchemaFieldTemplate.d.ts.map +1 -1
  113. package/lib/components/templates/ObjectFieldTemplate.d.ts +2 -2
  114. package/lib/components/templates/ObjectFieldTemplate.d.ts.map +1 -1
  115. package/lib/components/templates/ObjectFieldTemplate.js +1 -1
  116. package/lib/components/templates/OptionalDataControlsTemplate.d.ts +2 -2
  117. package/lib/components/templates/OptionalDataControlsTemplate.d.ts.map +1 -1
  118. package/lib/components/templates/OptionalDataControlsTemplate.js +1 -1
  119. package/lib/components/templates/TitleField.d.ts +2 -2
  120. package/lib/components/templates/TitleField.d.ts.map +1 -1
  121. package/lib/components/templates/UnsupportedField.d.ts +2 -2
  122. package/lib/components/templates/UnsupportedField.d.ts.map +1 -1
  123. package/lib/components/templates/UnsupportedField.js +2 -2
  124. package/lib/components/templates/WrapIfAdditionalTemplate.d.ts +2 -2
  125. package/lib/components/templates/WrapIfAdditionalTemplate.d.ts.map +1 -1
  126. package/lib/components/templates/WrapIfAdditionalTemplate.js +1 -1
  127. package/lib/components/templates/index.d.ts +1 -1
  128. package/lib/components/templates/index.d.ts.map +1 -1
  129. package/lib/components/templates/index.js +2 -0
  130. package/lib/components/widgets/AltDateTimeWidget.d.ts +2 -2
  131. package/lib/components/widgets/AltDateTimeWidget.d.ts.map +1 -1
  132. package/lib/components/widgets/AltDateWidget.d.ts +2 -2
  133. package/lib/components/widgets/AltDateWidget.d.ts.map +1 -1
  134. package/lib/components/widgets/AltDateWidget.js +2 -2
  135. package/lib/components/widgets/CheckboxWidget.d.ts +2 -2
  136. package/lib/components/widgets/CheckboxWidget.d.ts.map +1 -1
  137. package/lib/components/widgets/CheckboxesWidget.d.ts +2 -2
  138. package/lib/components/widgets/CheckboxesWidget.d.ts.map +1 -1
  139. package/lib/components/widgets/CheckboxesWidget.js +4 -4
  140. package/lib/components/widgets/ColorWidget.d.ts +2 -2
  141. package/lib/components/widgets/ColorWidget.d.ts.map +1 -1
  142. package/lib/components/widgets/DateTimeWidget.d.ts +2 -2
  143. package/lib/components/widgets/DateTimeWidget.d.ts.map +1 -1
  144. package/lib/components/widgets/DateTimeWidget.js +2 -2
  145. package/lib/components/widgets/DateWidget.d.ts +2 -2
  146. package/lib/components/widgets/DateWidget.d.ts.map +1 -1
  147. package/lib/components/widgets/EmailWidget.d.ts +2 -2
  148. package/lib/components/widgets/EmailWidget.d.ts.map +1 -1
  149. package/lib/components/widgets/FileWidget.d.ts +2 -2
  150. package/lib/components/widgets/FileWidget.d.ts.map +1 -1
  151. package/lib/components/widgets/FileWidget.js +6 -4
  152. package/lib/components/widgets/HiddenWidget.d.ts +2 -2
  153. package/lib/components/widgets/HiddenWidget.d.ts.map +1 -1
  154. package/lib/components/widgets/PasswordWidget.d.ts +2 -2
  155. package/lib/components/widgets/PasswordWidget.d.ts.map +1 -1
  156. package/lib/components/widgets/RadioWidget.d.ts +2 -2
  157. package/lib/components/widgets/RadioWidget.d.ts.map +1 -1
  158. package/lib/components/widgets/RadioWidget.js +4 -4
  159. package/lib/components/widgets/RangeWidget.d.ts +2 -2
  160. package/lib/components/widgets/RangeWidget.d.ts.map +1 -1
  161. package/lib/components/widgets/RatingWidget.d.ts +2 -2
  162. package/lib/components/widgets/RatingWidget.d.ts.map +1 -1
  163. package/lib/components/widgets/RatingWidget.js +15 -15
  164. package/lib/components/widgets/SelectWidget.d.ts +2 -2
  165. package/lib/components/widgets/SelectWidget.d.ts.map +1 -1
  166. package/lib/components/widgets/SelectWidget.js +9 -8
  167. package/lib/components/widgets/TextWidget.d.ts +2 -2
  168. package/lib/components/widgets/TextWidget.d.ts.map +1 -1
  169. package/lib/components/widgets/TextareaWidget.d.ts +2 -2
  170. package/lib/components/widgets/TextareaWidget.d.ts.map +1 -1
  171. package/lib/components/widgets/TextareaWidget.js +5 -5
  172. package/lib/components/widgets/TimeWidget.d.ts +2 -2
  173. package/lib/components/widgets/TimeWidget.d.ts.map +1 -1
  174. package/lib/components/widgets/URLWidget.d.ts +2 -2
  175. package/lib/components/widgets/URLWidget.d.ts.map +1 -1
  176. package/lib/components/widgets/UpDownWidget.d.ts +2 -2
  177. package/lib/components/widgets/UpDownWidget.d.ts.map +1 -1
  178. package/lib/components/widgets/index.d.ts +1 -1
  179. package/lib/components/widgets/index.d.ts.map +1 -1
  180. package/lib/getDefaultRegistry.d.ts +1 -1
  181. package/lib/getDefaultRegistry.d.ts.map +1 -1
  182. package/lib/getDefaultRegistry.js +1 -1
  183. package/lib/getTestRegistry.d.ts +1 -1
  184. package/lib/getTestRegistry.d.ts.map +1 -1
  185. package/lib/getTestRegistry.js +1 -1
  186. package/lib/index.d.ts +10 -5
  187. package/lib/index.d.ts.map +1 -1
  188. package/lib/tsconfig.tsbuildinfo +1 -1
  189. package/lib/withTheme.d.ts +3 -3
  190. package/lib/withTheme.d.ts.map +1 -1
  191. package/lib/withTheme.js +6 -6
  192. package/package.json +28 -28
  193. package/src/components/Form.tsx +197 -111
  194. package/src/components/RichDescription.tsx +3 -10
  195. package/src/components/RichHelp.tsx +3 -10
  196. package/src/components/SchemaExamples.tsx +6 -4
  197. package/src/components/fields/ArrayField.tsx +122 -108
  198. package/src/components/fields/BooleanField.tsx +4 -9
  199. package/src/components/fields/CyclicSchemaField.tsx +40 -0
  200. package/src/components/fields/FallbackField.tsx +4 -8
  201. package/src/components/fields/LayoutGridField.tsx +21 -19
  202. package/src/components/fields/LayoutHeaderField.tsx +2 -10
  203. package/src/components/fields/LayoutMultiSchemaField.tsx +15 -10
  204. package/src/components/fields/MultiSchemaField.tsx +202 -218
  205. package/src/components/fields/NullField.tsx +1 -1
  206. package/src/components/fields/NumberField.tsx +8 -10
  207. package/src/components/fields/ObjectField.tsx +52 -40
  208. package/src/components/fields/OptionalDataControlsField.tsx +6 -4
  209. package/src/components/fields/SchemaField.tsx +66 -51
  210. package/src/components/fields/StringField.tsx +4 -15
  211. package/src/components/fields/index.ts +3 -1
  212. package/src/components/templates/ArrayFieldDescriptionTemplate.tsx +2 -9
  213. package/src/components/templates/ArrayFieldItemButtonsTemplate.tsx +2 -7
  214. package/src/components/templates/ArrayFieldItemTemplate.tsx +3 -9
  215. package/src/components/templates/ArrayFieldTemplate.tsx +2 -9
  216. package/src/components/templates/ArrayFieldTitleTemplate.tsx +2 -10
  217. package/src/components/templates/BaseInputTemplate.tsx +16 -23
  218. package/src/components/templates/ButtonTemplates/AddButton.tsx +2 -1
  219. package/src/components/templates/ButtonTemplates/IconButton.tsx +16 -7
  220. package/src/components/templates/ButtonTemplates/SubmitButton.tsx +2 -1
  221. package/src/components/templates/ButtonTemplates/index.ts +1 -1
  222. package/src/components/templates/CyclicSchemaExpandTemplate.tsx +31 -0
  223. package/src/components/templates/DescriptionField.tsx +1 -1
  224. package/src/components/templates/ErrorList.tsx +8 -15
  225. package/src/components/templates/FallbackFieldTemplate.tsx +2 -1
  226. package/src/components/templates/FieldErrorTemplate.tsx +8 -8
  227. package/src/components/templates/FieldHelpTemplate.tsx +2 -1
  228. package/src/components/templates/FieldTemplate/FieldTemplate.tsx +2 -8
  229. package/src/components/templates/FieldTemplate/Label.tsx +2 -2
  230. package/src/components/templates/GridTemplate.tsx +1 -1
  231. package/src/components/templates/MultiSchemaFieldTemplate.tsx +1 -1
  232. package/src/components/templates/ObjectFieldTemplate.tsx +2 -7
  233. package/src/components/templates/OptionalDataControlsTemplate.tsx +3 -2
  234. package/src/components/templates/TitleField.tsx +1 -1
  235. package/src/components/templates/UnsupportedField.tsx +4 -3
  236. package/src/components/templates/WrapIfAdditionalTemplate.tsx +2 -9
  237. package/src/components/templates/index.ts +3 -1
  238. package/src/components/widgets/AltDateTimeWidget.tsx +1 -1
  239. package/src/components/widgets/AltDateWidget.tsx +7 -13
  240. package/src/components/widgets/CheckboxWidget.tsx +3 -5
  241. package/src/components/widgets/CheckboxesWidget.tsx +8 -10
  242. package/src/components/widgets/ColorWidget.tsx +2 -1
  243. package/src/components/widgets/DateTimeWidget.tsx +3 -10
  244. package/src/components/widgets/DateWidget.tsx +2 -1
  245. package/src/components/widgets/EmailWidget.tsx +2 -1
  246. package/src/components/widgets/FileWidget.tsx +9 -8
  247. package/src/components/widgets/HiddenWidget.tsx +1 -1
  248. package/src/components/widgets/PasswordWidget.tsx +2 -1
  249. package/src/components/widgets/RadioWidget.tsx +8 -10
  250. package/src/components/widgets/RangeWidget.tsx +1 -1
  251. package/src/components/widgets/RatingWidget.tsx +48 -47
  252. package/src/components/widgets/SelectWidget.tsx +48 -31
  253. package/src/components/widgets/TextWidget.tsx +2 -1
  254. package/src/components/widgets/TextareaWidget.tsx +10 -7
  255. package/src/components/widgets/TimeWidget.tsx +2 -1
  256. package/src/components/widgets/URLWidget.tsx +2 -1
  257. package/src/components/widgets/UpDownWidget.tsx +2 -1
  258. package/src/components/widgets/index.ts +1 -1
  259. package/src/getDefaultRegistry.ts +2 -9
  260. package/src/getTestRegistry.tsx +2 -7
  261. package/src/index.ts +10 -5
  262. package/src/withTheme.tsx +14 -9
@@ -1,19 +1,12 @@
1
- import { Component, ElementType, FormEvent, ReactNode, Ref, RefObject, createRef } from 'react';
2
- import {
3
- createSchemaUtils,
1
+ import type { ElementType, FormEvent, ReactNode, Ref, RefObject } from 'react';
2
+ import { Component, createRef } from 'react';
3
+ import type {
4
4
  CustomValidator,
5
- deepEquals,
6
5
  ErrorSchema,
7
- ErrorSchemaBuilder,
8
6
  ErrorTransformer,
9
7
  FieldPathId,
10
8
  FieldPathList,
11
9
  FormContextType,
12
- getChangedFields,
13
- getTemplate,
14
- getUiOptions,
15
- isObject,
16
- mergeObjects,
17
10
  PathSchema,
18
11
  StrictRJSFSchema,
19
12
  Registry,
@@ -22,26 +15,37 @@ import {
22
15
  RJSFSchema,
23
16
  RJSFValidationError,
24
17
  SchemaUtilsType,
18
+ TemplatesType,
19
+ UiSchema,
20
+ ValidationData,
21
+ ValidatorType,
22
+ Experimental_DefaultFormStateBehavior,
23
+ Experimental_CustomMergeAllOf,
24
+ GlobalFormOptions,
25
+ NameGeneratorFunction,
26
+ } from '@rjsf/utils';
27
+ import {
28
+ createSchemaUtils,
29
+ deepEquals,
30
+ ErrorSchemaBuilder,
31
+ getChangedFields,
32
+ getTemplate,
33
+ getUiOptions,
34
+ hashObject,
35
+ isObject,
36
+ mergeObjects,
25
37
  shouldRender,
26
38
  SUBMIT_BTN_OPTIONS_KEY,
27
- TemplatesType,
28
39
  toErrorList,
29
40
  toFieldPathId,
30
- UiSchema,
31
41
  UI_DEFINITIONS_KEY,
32
42
  UI_GLOBAL_OPTIONS_KEY,
33
43
  UI_OPTIONS_KEY,
34
- ValidationData,
35
44
  validationDataMerge,
36
- ValidatorType,
37
- Experimental_DefaultFormStateBehavior,
38
- Experimental_CustomMergeAllOf,
39
45
  DEFAULT_ID_SEPARATOR,
40
46
  DEFAULT_ID_PREFIX,
41
- GlobalFormOptions,
42
47
  ERRORS_KEY,
43
48
  ID_KEY,
44
- NameGeneratorFunction,
45
49
  getUsedFormData,
46
50
  getFieldNames,
47
51
  ANY_OF_KEY,
@@ -193,6 +197,7 @@ export interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
193
197
  *
194
198
  * NOTE: In a future major release, the `boolean` options for this flag will be removed
195
199
  */
200
+ // oxlint-disable-next-line typescript/no-deprecated
196
201
  liveValidate?: 'onChange' | 'onBlur' | DeprecatedBooleanOption;
197
202
  /** Flag that describes when live omit will be performed. Live omit happens only when `omitExtraData` is also set to
198
203
  * to `true` and the form's data is updated by the user.
@@ -204,6 +209,7 @@ export interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
204
209
  *
205
210
  * NOTE: In a future major release, the `boolean` options for this flag will be removed
206
211
  */
212
+ // oxlint-disable-next-line typescript/no-deprecated
207
213
  liveOmit?: 'onChange' | 'onBlur' | DeprecatedBooleanOption;
208
214
  /** If set to true, then extra form data values that are not in any form field will be removed whenever `onSubmit` is
209
215
  * called. Set to `false` by default.
@@ -315,7 +321,7 @@ export interface FormState<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
315
321
  /** The registry (re)computed only when props changed */
316
322
  registry: Registry<T, S, F>;
317
323
  /** Tracks the previous `extraErrors` prop reference so that `getDerivedStateFromProps` can detect changes */
318
- _prevExtraErrors?: ErrorSchema<T>;
324
+ prevExtraErrors?: ErrorSchema<T>;
319
325
  }
320
326
 
321
327
  /** The event data passed when changes have been made to the form, includes everything from the `FormState` except
@@ -380,7 +386,7 @@ export default class Form<
380
386
  /** Flag to track when we're processing a user-initiated field change.
381
387
  * This prevents componentDidUpdate from reverting oneOf/anyOf option switches.
382
388
  */
383
- private _isProcessingUserChange = false;
389
+ private isProcessingUserChange = false;
384
390
 
385
391
  /** When the `extraErrors` prop changes, re-merges `schemaValidationErrors` + `extraErrors` + `customErrors` into
386
392
  * state before render, ensuring the updated errors are visible immediately in a single render cycle.
@@ -393,10 +399,10 @@ export default class Form<
393
399
  props: FormProps<T, S, F>,
394
400
  state: FormState<T, S, F>,
395
401
  ): Partial<FormState<T, S, F>> | null {
396
- if (props.extraErrors !== state._prevExtraErrors) {
402
+ if (props.extraErrors !== state.prevExtraErrors) {
397
403
  const baseErrors: ValidationData<T> = {
398
404
  errors: state.schemaValidationErrors || [],
399
- errorSchema: (state.schemaValidationErrorSchema || {}) as ErrorSchema<T>,
405
+ errorSchema: state.schemaValidationErrorSchema || {},
400
406
  };
401
407
  let { errors, errorSchema } = baseErrors;
402
408
  if (props.extraErrors) {
@@ -409,7 +415,7 @@ export default class Form<
409
415
  true,
410
416
  ));
411
417
  }
412
- return { _prevExtraErrors: props.extraErrors, errors, errorSchema };
418
+ return { prevExtraErrors: props.extraErrors, errors, errorSchema };
413
419
  }
414
420
  return null;
415
421
  }
@@ -431,7 +437,7 @@ export default class Form<
431
437
  const formData = propsFormData ?? initialFormData;
432
438
  this.state = {
433
439
  ...this.getStateFromProps(props, formData, undefined, undefined, undefined, true),
434
- _prevExtraErrors: props.extraErrors,
440
+ prevExtraErrors: props.extraErrors,
435
441
  };
436
442
  if (onChange && !deepEquals(this.state.formData, formData)) {
437
443
  onChange(toIChangeEvent(this.state));
@@ -515,8 +521,8 @@ export default class Form<
515
521
  // Prevent oneOf/anyOf option switches from reverting when getStateFromProps
516
522
  // re-evaluates and produces stale formData.
517
523
  const nextStateDiffersFromProps = !deepEquals(nextState.formData, this.props.formData);
518
- const wasProcessingUserChange = this._isProcessingUserChange;
519
- this._isProcessingUserChange = false;
524
+ const wasProcessingUserChange = this.isProcessingUserChange;
525
+ this.isProcessingUserChange = false;
520
526
 
521
527
  if (wasProcessingUserChange && nextStateDiffersFromProps) {
522
528
  // Skip - the user's option switch is already applied via processPendingChange
@@ -526,6 +532,7 @@ export default class Form<
526
532
  if (nextStateDiffersFromProps && !deepEquals(nextState.formData, prevState.formData) && this.props.onChange) {
527
533
  this.props.onChange(toIChangeEvent(nextState));
528
534
  }
535
+ // oxlint-disable-next-line react/no-did-update-set-state -- guarded to prevent infinite loop
529
536
  this.setState(nextState);
530
537
  }
531
538
  }
@@ -537,9 +544,10 @@ export default class Form<
537
544
  * @param props - The props passed to the `Form`
538
545
  * @param inputFormData - The new or current data for the `Form`
539
546
  * @param retrievedSchema - An expanded schema, if not provided, it will be retrieved from the `schema` and `formData`.
540
- * @param isSchemaChanged - A flag indicating whether the schema has changed.
541
- * @param formDataChangedFields - The changed fields of `formData`
542
- * @param skipLiveValidate - Optional flag, if true, means that we are not running live validation
547
+ * @param [isSchemaChanged=false] - A flag indicating whether the schema has changed.
548
+ * @param [formDataChangedFields=[]] - The changed fields of `formData`
549
+ * @param [skipLiveValidate=false] - Optional flag, if true, means that we are not running live validation
550
+ * @param [shouldSanitize=false] - Optional flag, if true, means that we should attempt to sanitize formData
543
551
  * @returns - The new state for the `Form`
544
552
  */
545
553
  getStateFromProps(
@@ -549,6 +557,7 @@ export default class Form<
549
557
  isSchemaChanged = false,
550
558
  formDataChangedFields: string[] = [],
551
559
  skipLiveValidate = false,
560
+ shouldSanitize = false,
552
561
  ): FormState<T, S, F> {
553
562
  const state: FormState<T, S, F> = this.state || {};
554
563
  const schema = 'schema' in props ? props.schema : this.props.schema;
@@ -557,6 +566,7 @@ export default class Form<
557
566
  const isUncontrolled = props.formData === undefined && this.props.formData === undefined;
558
567
  const edit = typeof inputFormData !== 'undefined';
559
568
  const liveValidate = 'liveValidate' in props ? props.liveValidate : this.props.liveValidate;
569
+ // oxlint-disable-next-line typescript/no-deprecated
560
570
  const mustValidate = edit && !props.noValidate && liveValidate;
561
571
  const experimental_defaultFormStateBehavior =
562
572
  'experimental_defaultFormStateBehavior' in props
@@ -566,7 +576,7 @@ export default class Form<
566
576
  'experimental_customMergeAllOf' in props
567
577
  ? props.experimental_customMergeAllOf
568
578
  : this.props.experimental_customMergeAllOf;
569
- let schemaUtils: SchemaUtilsType<T, S, F> = state.schemaUtils;
579
+ let { schemaUtils } = state;
570
580
  if (
571
581
  !schemaUtils ||
572
582
  schemaUtils.doesSchemaUtilsDiffer(
@@ -593,21 +603,57 @@ export default class Form<
593
603
  } else if (inputFormData === undefined && isUncontrolled) {
594
604
  defaultsFormData = state.formData;
595
605
  }
596
- const formData: T = schemaUtils.getDefaultFormState(
597
- rootSchema,
598
- defaultsFormData,
599
- false,
600
- state.initialDefaultsGenerated,
601
- ) as T;
602
- const _retrievedSchema = this.updateRetrievedSchema(
603
- retrievedSchema ?? schemaUtils.retrieveSchema(rootSchema, formData),
604
- );
606
+ let formData: T;
607
+ let computedRetrievedSchema: S;
608
+ let wasSanitized = false;
609
+ const preventInfiniteSanitize: string[] = [];
610
+ do {
611
+ formData = schemaUtils.getDefaultFormState(
612
+ rootSchema,
613
+ defaultsFormData,
614
+ false,
615
+ state.initialDefaultsGenerated,
616
+ ) as T;
617
+ // Only hash when sanitizing, wrapping `formData` in an object to deal with a scalar/undefined value
618
+ const formHash = shouldSanitize ? hashObject({ formData }) : '';
619
+ computedRetrievedSchema = this.updateRetrievedSchema(
620
+ retrievedSchema ?? schemaUtils.retrieveSchema(rootSchema, formData),
621
+ );
622
+ if (
623
+ shouldSanitize &&
624
+ !preventInfiniteSanitize.includes(formHash) &&
625
+ !deepEquals(computedRetrievedSchema, state.retrievedSchema)
626
+ ) {
627
+ // Sanitize the form data if shouldSanitize is true, we haven't already processed this same formData AND
628
+ // we have a different retrieved schema from when we last ran the state
629
+ const sanitizedFormData = schemaUtils.sanitizeDataForNewSchema(
630
+ computedRetrievedSchema,
631
+ state.retrievedSchema,
632
+ formData,
633
+ );
634
+ wasSanitized = !deepEquals(sanitizedFormData, formData);
635
+ if (wasSanitized) {
636
+ // Update both the formData AND defaultsFormData due to the sanitize so the loop works with the new data
637
+ formData = sanitizedFormData;
638
+ defaultsFormData = sanitizedFormData;
639
+ const sanitizedFormHash = hashObject({ formData: sanitizedFormData });
640
+ // If we've seen the sanitized data before, we are done
641
+ wasSanitized = !preventInfiniteSanitize.includes(sanitizedFormHash);
642
+ preventInfiniteSanitize.push(sanitizedFormHash);
643
+ }
644
+ preventInfiniteSanitize.push(formHash);
645
+ } else {
646
+ wasSanitized = false;
647
+ }
648
+ } while (wasSanitized);
605
649
 
606
650
  const getCurrentErrors = (): ValidationData<T> => {
607
651
  // If the `props.noValidate` option is set or the schema has changed, we reset the error state.
652
+ // oxlint-disable-next-line typescript/no-deprecated
608
653
  if (props.noValidate || isSchemaChanged) {
609
654
  return { errors: [], errorSchema: {} };
610
- } else if (!props.liveValidate) {
655
+ }
656
+ if (!props.liveValidate) {
611
657
  return {
612
658
  errors: state.schemaValidationErrors || [],
613
659
  errorSchema: state.schemaValidationErrorSchema || {},
@@ -621,8 +667,7 @@ export default class Form<
621
667
 
622
668
  let errors: RJSFValidationError[];
623
669
  let errorSchema: ErrorSchema<T> | undefined;
624
- let schemaValidationErrors: RJSFValidationError[] = state.schemaValidationErrors;
625
- let schemaValidationErrorSchema: ErrorSchema<T> = state.schemaValidationErrorSchema;
670
+ let { schemaValidationErrors, schemaValidationErrorSchema } = state;
626
671
  // If we are skipping live validate, it means that the state has already been updated with live validation errors
627
672
  if (mustValidate && !skipLiveValidate) {
628
673
  const liveValidation = this.liveValidate(
@@ -647,26 +692,24 @@ export default class Form<
647
692
  errorSchema = currentErrors.errorSchema;
648
693
  // We only update the error schema for changed fields if mustValidate is false
649
694
  if (formDataChangedFields.length > 0 && !mustValidate) {
650
- const newErrorSchema = formDataChangedFields.reduce(
651
- (acc, key) => {
652
- acc[key] = undefined;
653
- return acc;
654
- },
655
- {} as Record<string, undefined>,
656
- );
657
- errorSchema = schemaValidationErrorSchema = mergeObjects(
695
+ const newErrorSchema = formDataChangedFields.reduce<Record<string, undefined>>((acc, key) => {
696
+ acc[key] = undefined;
697
+ return acc;
698
+ }, {});
699
+ schemaValidationErrorSchema = mergeObjects(
658
700
  currentErrors.errorSchema,
659
701
  newErrorSchema,
660
702
  'preventDuplicates',
661
703
  ) as ErrorSchema<T>;
704
+ errorSchema = schemaValidationErrorSchema;
662
705
  }
663
- const mergedErrors = this.mergeErrors({ errorSchema, errors }, props.extraErrors, state.customErrors);
706
+ const mergedErrors = Form.mergeErrors<T>({ errorSchema, errors }, props.extraErrors, state.customErrors);
664
707
  errors = mergedErrors.errors;
665
708
  errorSchema = mergedErrors.errorSchema;
666
709
  }
667
710
 
668
711
  // Only store a new registry when the props cause a different one to be created
669
- const newRegistry = this.getRegistry(props, rootSchema, schemaUtils);
712
+ const newRegistry = Form.getRegistry(props, rootSchema, schemaUtils);
670
713
  const registry = deepEquals(state.registry, newRegistry) ? state.registry : newRegistry;
671
714
 
672
715
  // Only compute a new `fieldPathId` when the `idPrefix` is different than the existing fieldPathId's ID_KEY
@@ -685,7 +728,7 @@ export default class Form<
685
728
  errorSchema,
686
729
  schemaValidationErrors,
687
730
  schemaValidationErrorSchema,
688
- retrievedSchema: _retrievedSchema,
731
+ retrievedSchema: computedRetrievedSchema,
689
732
  initialDefaultsGenerated: true,
690
733
  registry,
691
734
  };
@@ -717,12 +760,19 @@ export default class Form<
717
760
  altSchemaUtils?: SchemaUtilsType<T, S, F>,
718
761
  retrievedSchema?: S,
719
762
  ): ValidationData<T> {
720
- const schemaUtils = altSchemaUtils ? altSchemaUtils : this.state.schemaUtils;
763
+ const schemaUtils = altSchemaUtils || this.state.schemaUtils;
721
764
  const { customValidate, transformErrors, uiSchema } = this.props;
722
- const resolvedSchema = retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData);
765
+ // When a pre-resolved schema is provided (e.g., from live validation), use it directly.
766
+ // Otherwise validate against the original schema so AJV sees the full constraint set.
767
+ const validationSchema = retrievedSchema ?? schema;
768
+
769
+ // JSON.stringify drops keys with `undefined` values; JSON.parse on the result gives AJV a clean
770
+ // object that avoids spurious type errors for `type: "string"` fields that were cleared (#4518).
771
+ const validationFormData = formData ? JSON.parse(JSON.stringify(formData)) : undefined;
772
+
723
773
  return schemaUtils
724
774
  .getValidator()
725
- .validateFormData(formData, resolvedSchema, customValidate, transformErrors, uiSchema);
775
+ .validateFormData(validationFormData, validationSchema, customValidate, transformErrors, uiSchema);
726
776
  }
727
777
 
728
778
  /** Renders any errors contained in the `state` in using the `ErrorList`, if not disabled by `showErrorList`. */
@@ -731,7 +781,7 @@ export default class Form<
731
781
  const options = getUiOptions<T, S, F>(uiSchema);
732
782
  const ErrorListTemplate = getTemplate<'ErrorListTemplate', T, S, F>('ErrorListTemplate', registry, options);
733
783
 
734
- if (errors && errors.length) {
784
+ if (errors?.length) {
735
785
  return (
736
786
  <ErrorListTemplate
737
787
  errors={errors}
@@ -753,13 +803,12 @@ export default class Form<
753
803
  * @return - The `extraErrors` and `customErrors` merged into the `schemaValidation`
754
804
  * @private
755
805
  */
756
- private mergeErrors(
806
+ private static mergeErrors<T = any>(
757
807
  schemaValidation: ValidationData<T>,
758
808
  extraErrors?: FormProps['extraErrors'],
759
809
  customErrors?: ErrorSchemaBuilder,
760
810
  ): ValidationData<T> {
761
- let errorSchema: ErrorSchema<T> = schemaValidation.errorSchema;
762
- let errors: RJSFValidationError[] = schemaValidation.errors;
811
+ let { errorSchema, errors } = schemaValidation;
763
812
  if (extraErrors) {
764
813
  const merged = validationDataMerge(schemaValidation, extraErrors);
765
814
  errorSchema = merged.errorSchema;
@@ -798,8 +847,8 @@ export default class Form<
798
847
  mergeIntoOriginalErrorSchema = false,
799
848
  ) {
800
849
  const schemaValidation = this.validate(formData, rootSchema, schemaUtils, retrievedSchema);
801
- const errors = schemaValidation.errors;
802
- let errorSchema = schemaValidation.errorSchema;
850
+ const { errors } = schemaValidation;
851
+ let { errorSchema } = schemaValidation;
803
852
  // We merge 'originalErrorSchema' with 'schemaValidation.errorSchema.'; This done to display the raised field error.
804
853
  if (mergeIntoOriginalErrorSchema) {
805
854
  errorSchema = mergeObjects(
@@ -810,7 +859,7 @@ export default class Form<
810
859
  }
811
860
  const schemaValidationErrors = errors;
812
861
  const schemaValidationErrorSchema = errorSchema;
813
- const mergedErrors = this.mergeErrors({ errorSchema, errors }, extraErrors, customErrors);
862
+ const mergedErrors = Form.mergeErrors<T>({ errorSchema, errors }, extraErrors, customErrors);
814
863
  return { ...mergedErrors, schemaValidationErrors, schemaValidationErrorSchema };
815
864
  }
816
865
 
@@ -820,9 +869,8 @@ export default class Form<
820
869
  * @param fields - The fields to keep while filtering
821
870
  * @deprecated - To be removed as an exported `Form` function in a future release; there isn't a planned replacement
822
871
  */
823
- getUsedFormData = (formData: T | undefined, fields: string[]): T | undefined => {
824
- return getUsedFormData(formData, fields);
825
- };
872
+ // oxlint-disable-next-line class-methods-use-this, typescript/no-deprecated
873
+ getUsedFormData = (formData: T | undefined, fields: string[]): T | undefined => getUsedFormData(formData, fields);
826
874
 
827
875
  /** Returns the list of field names from inspecting the `pathSchema` as well as using the `formData`
828
876
  *
@@ -830,9 +878,8 @@ export default class Form<
830
878
  * @param [formData] - The form data to use while checking for empty objects/arrays
831
879
  * @deprecated - To be removed as an exported `Form` function in a future release; there isn't a planned replacement
832
880
  */
833
- getFieldNames = (pathSchema: PathSchema<T>, formData?: T): string[][] => {
834
- return getFieldNames(pathSchema, formData);
835
- };
881
+ // oxlint-disable-next-line class-methods-use-this, typescript/no-deprecated
882
+ getFieldNames = (pathSchema: PathSchema<T>, formData?: T): string[][] => getFieldNames(pathSchema, formData);
836
883
 
837
884
  /** Returns the `formData` after filtering to remove any extra data not in a form field
838
885
  *
@@ -890,20 +937,20 @@ export default class Form<
890
937
  }
891
938
  // Mark that we're processing a user-initiated change.
892
939
  // This prevents componentDidUpdate from reverting oneOf/anyOf option switches.
893
- this._isProcessingUserChange = true;
940
+ this.isProcessingUserChange = true;
894
941
  const { newValue, path, id } = this.pendingChanges[0];
895
942
  const { newErrorSchema } = this.pendingChanges[0];
896
- const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
943
+ // oxlint-disable-next-line typescript/no-deprecated
944
+ const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange, disabled, readonly } = this.props;
897
945
  const { formData: oldFormData, schemaUtils, schema, fieldPathId, schemaValidationErrorSchema, errors } = this.state;
898
- let { customErrors } = this.state;
946
+ let { customErrors, retrievedSchema } = this.state;
899
947
  // Use the un-merged AJV-only schema as the base for re-merging extraErrors. Mirrors the
900
948
  // pattern in getStateFromProps/getDerivedStateFromProps and avoids the duplication that
901
949
  // happened when state.errorSchema (already containing merged extraErrors) was passed in.
902
- let mergeBaseErrorSchema: ErrorSchema<T> = schemaValidationErrorSchema as ErrorSchema<T>;
950
+ let mergeBaseErrorSchema: ErrorSchema<T> = schemaValidationErrorSchema;
903
951
  const rootPathId = fieldPathId.path[0] || '';
904
952
 
905
953
  const isRootPath = !path || path.length === 0 || (path.length === 1 && path[0] === rootPathId);
906
- let retrievedSchema = this.state.retrievedSchema;
907
954
  let formData = isRootPath ? newValue : _cloneDeep(oldFormData);
908
955
 
909
956
  // When switching from null to an object option in oneOf, MultiSchemaField sends
@@ -918,12 +965,18 @@ export default class Form<
918
965
  const inputForDefaults = hasOnlyUndefinedValues && wasPreviouslyNull ? undefined : formData;
919
966
 
920
967
  if (isObject(formData) || Array.isArray(formData)) {
968
+ // Tracks if the user cleared a plain (non-oneOf/anyOf) leaf field.
969
+ // The key is removed twice: once before getStateFromProps so inputForDefaults
970
+ // reflects an empty field for conditional schema resolution, and once after so
971
+ // the user's clear overrides any schema default getStateFromProps re-applied (#5125)
972
+ // and AJV never receives { key: undefined } for type:"string" fields (#4518).
973
+ let plainLeafWasCleared = false;
974
+
921
975
  if (newValue === ADDITIONAL_PROPERTY_KEY_REMOVE) {
922
- // For additional properties, we were given the special remove this key value, so unset it
976
+ // For additional properties, this key was explicitly removed, so unset it
923
977
  _unset(formData, path);
924
978
  } else if (!isRootPath) {
925
- // If the newValue is not on the root path, then set it into the form data
926
- let unsetPath = false;
979
+ // Set the new value at its path in the form data.
927
980
  let valueForPath: T | null | undefined = newValue;
928
981
 
929
982
  if (newValue === undefined) {
@@ -935,37 +988,54 @@ export default class Form<
935
988
  const { field } = schemaUtils.findFieldInSchema(schema, path, oldFormData);
936
989
  const leaf = field as RJSFSchema | undefined;
937
990
  const isOneOfOrAnyOfLeaf = leaf && (ONE_OF_KEY in leaf || ANY_OF_KEY in leaf);
938
- // Plain leaves: omit the key instead of `{ key: undefined }`, which breaks `type: "string"` validation in
939
- // AJV after clearing a text input (https://github.com/rjsf-team/react-jsonschema-form/issues/4518).
940
- // oneOf/anyOf leaves and unresolved leaves: keep `valueForPath === newValue` (already `undefined`) so
941
- // mergeDefaults does not immediately re-apply a branch default when clearing those widgets.
991
+ // oneOf/anyOf and unresolved leaves keep `undefined` so mergeDefaults doesn't
992
+ // re-apply a branch default when the user clears the widget.
993
+ // Plain resolved leaves use plainLeafWasCleared instead (see below).
942
994
  if (!isOneOfOrAnyOfLeaf && leaf !== undefined) {
943
- unsetPath = true;
995
+ plainLeafWasCleared = true;
944
996
  }
945
997
  }
946
998
  }
947
999
 
948
- if (unsetPath) {
949
- _unset(formData, path);
1000
+ if (plainLeafWasCleared) {
1001
+ _set(formData, path, undefined);
950
1002
  } else {
951
1003
  _set(formData, path, valueForPath);
952
1004
  }
953
1005
  }
954
- // Pass true to skip live validation in `getStateFromProps()` since we will do it a bit later
955
- const newState = this.getStateFromProps(this.props, inputForDefaults, undefined, undefined, undefined, true);
1006
+ const shouldSanitize =
1007
+ retrievedSchema && !isRootPath && !isObject(newValue) && !Array.isArray(newValue) && !disabled && !readonly;
1008
+ // Skip live validation here; it runs later in this function.
1009
+ const newState = this.getStateFromProps(
1010
+ this.props,
1011
+ inputForDefaults,
1012
+ undefined,
1013
+ undefined,
1014
+ undefined,
1015
+ true,
1016
+ shouldSanitize,
1017
+ );
956
1018
  formData = newState.formData;
957
1019
  retrievedSchema = newState.retrievedSchema;
1020
+
1021
+ // Re-set to undefined after merging defaults so the user's clear is preserved in
1022
+ // state (#5125 regression: without this, clearing a second field re-applies the
1023
+ // default to previously-cleared fields). The undefined key is stripped from the
1024
+ // formData copy passed to AJV via JSON.parse(JSON.stringify(...)) so the validator never
1025
+ // sees { [key]: undefined } for type:"string" or patternProperties fields (#4518).
1026
+ if (plainLeafWasCleared && formData) {
1027
+ _set(formData, path, undefined);
1028
+ }
958
1029
  }
959
1030
 
960
1031
  const mustValidate = !noValidate && (liveValidate === true || liveValidate === 'onChange');
961
- let state: Partial<FormState<T, S, F>> = { formData, schema };
1032
+ let state: Partial<FormState<T, S, F>> = { formData, retrievedSchema };
962
1033
  let newFormData = formData;
963
1034
 
964
1035
  if (omitExtraData === true && (liveOmit === true || liveOmit === 'onChange')) {
1036
+ // oxlint-disable-next-line typescript/no-deprecated
965
1037
  newFormData = this.omitExtraData(formData);
966
- state = {
967
- formData: newFormData,
968
- };
1038
+ state = { ...state, formData: newFormData };
969
1039
  }
970
1040
 
971
1041
  if (newErrorSchema) {
@@ -977,20 +1047,20 @@ export default class Form<
977
1047
  // Apply the user-supplied newErrorSchema onto a clone of the AJV-only base, so that
978
1048
  // mergeErrors below sees the user's error at this path without mutating shared state.
979
1049
  if (!isRootPath) {
980
- mergeBaseErrorSchema = _cloneDeep(schemaValidationErrorSchema) as ErrorSchema<T>;
1050
+ mergeBaseErrorSchema = _cloneDeep(schemaValidationErrorSchema);
981
1051
  _set(mergeBaseErrorSchema, path, newErrorSchema);
982
1052
  } else {
983
- mergeBaseErrorSchema = newErrorSchema as ErrorSchema<T>;
1053
+ mergeBaseErrorSchema = newErrorSchema;
984
1054
  }
985
1055
  } else {
986
1056
  if (!customErrors) {
987
1057
  customErrors = new ErrorSchemaBuilder<T>();
988
1058
  }
989
1059
  if (isRootPath) {
990
- const errors = _get(newErrorSchema, ERRORS_KEY);
991
- if (errors) {
1060
+ const pathErrors = _get(newErrorSchema, ERRORS_KEY);
1061
+ if (pathErrors) {
992
1062
  // only set errors when there are some
993
- customErrors.setErrors(errors);
1063
+ customErrors.setErrors(pathErrors);
994
1064
  }
995
1065
  } else {
996
1066
  _set(customErrors.ErrorSchema, path, newErrorSchema);
@@ -1011,16 +1081,17 @@ export default class Form<
1011
1081
  customErrors,
1012
1082
  retrievedSchema,
1013
1083
  );
1014
- state = { formData: newFormData, ...liveValidation, customErrors };
1084
+ state = { ...state, formData: newFormData, ...liveValidation, customErrors };
1015
1085
  } else if (!noValidate && newErrorSchema) {
1016
1086
  // Merging 'newErrorSchema' into 'errorSchema' to display the custom raised errors.
1017
- const mergedErrors = this.mergeErrors({ errorSchema: mergeBaseErrorSchema, errors }, extraErrors, customErrors);
1018
- state = {
1019
- formData: newFormData,
1020
- ...mergedErrors,
1087
+ const mergedErrors = Form.mergeErrors<T>(
1088
+ { errorSchema: mergeBaseErrorSchema, errors },
1089
+ extraErrors,
1021
1090
  customErrors,
1022
- };
1091
+ );
1092
+ state = { ...state, formData: newFormData, ...mergedErrors, customErrors };
1023
1093
  }
1094
+
1024
1095
  this.setState(state as FormState<T, S, F>, () => {
1025
1096
  if (onChange) {
1026
1097
  onChange(toIChangeEvent({ ...this.state, ...state }), id);
@@ -1073,7 +1144,7 @@ export default class Form<
1073
1144
  customErrors: undefined,
1074
1145
  } as FormState<T, S, F>;
1075
1146
 
1076
- this.setState(state, () => onChange && onChange(toIChangeEvent({ ...this.state, ...state })));
1147
+ this.setState(state, () => onChange?.(toIChangeEvent({ ...this.state, ...state })));
1077
1148
  };
1078
1149
 
1079
1150
  /** Callback function to handle when a field on the form is blurred. Calls the `onBlur` callback for the `Form` if it
@@ -1094,6 +1165,7 @@ export default class Form<
1094
1165
  let newFormData: T | undefined = formData;
1095
1166
  let state: Partial<FormState<T, S, F>> = { formData: newFormData };
1096
1167
  if (omitExtraData === true && liveOmit === 'onBlur') {
1168
+ // oxlint-disable-next-line typescript/no-deprecated
1097
1169
  newFormData = this.omitExtraData(formData);
1098
1170
  state = { formData: newFormData };
1099
1171
  }
@@ -1154,10 +1226,12 @@ export default class Form<
1154
1226
  }
1155
1227
 
1156
1228
  event.persist();
1229
+ // oxlint-disable-next-line typescript/no-deprecated
1157
1230
  const { omitExtraData, extraErrors, noValidate, onSubmit } = this.props;
1158
1231
  let { formData: newFormData } = this.state;
1159
1232
 
1160
1233
  if (omitExtraData === true) {
1234
+ // oxlint-disable-next-line typescript/no-deprecated
1161
1235
  newFormData = this.omitExtraData(newFormData);
1162
1236
  }
1163
1237
 
@@ -1189,7 +1263,11 @@ export default class Form<
1189
1263
  * @returns - The `GlobalFormOptions` from the props
1190
1264
  * @private
1191
1265
  */
1192
- private getGlobalFormOptions(props: FormProps<T, S, F>): GlobalFormOptions {
1266
+ private static getGlobalFormOptions<
1267
+ T = any,
1268
+ S extends StrictRJSFSchema = RJSFSchema,
1269
+ F extends FormContextType = any,
1270
+ >(props: FormProps<T, S, F>): GlobalFormOptions {
1193
1271
  const {
1194
1272
  uiSchema = {},
1195
1273
  experimental_componentUpdateStrategy,
@@ -1198,6 +1276,7 @@ export default class Form<
1198
1276
  nameGenerator,
1199
1277
  useFallbackUiForUnsupportedType = false,
1200
1278
  } = props;
1279
+ // oxlint-disable-next-line typescript/no-deprecated
1201
1280
  const rootFieldId = uiSchema['ui:rootFieldId'];
1202
1281
  // Omit any options that are undefined or null
1203
1282
  return {
@@ -1210,7 +1289,11 @@ export default class Form<
1210
1289
  }
1211
1290
 
1212
1291
  /** Computed the registry for the form using the given `props`, `schema` and `schemaUtils` */
1213
- getRegistry(props: FormProps<T, S, F>, schema: S, schemaUtils: SchemaUtilsType<T, S, F>): Registry<T, S, F> {
1292
+ static getRegistry<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
1293
+ props: FormProps<T, S, F>,
1294
+ schema: S,
1295
+ schemaUtils: SchemaUtilsType<T, S, F>,
1296
+ ): Registry<T, S, F> {
1214
1297
  const { translateString: customTranslateString, uiSchema = {} } = props;
1215
1298
  const { fields, templates, widgets, formContext, translateString } = getDefaultRegistry<T, S, F>();
1216
1299
  return {
@@ -1229,7 +1312,7 @@ export default class Form<
1229
1312
  schemaUtils,
1230
1313
  translateString: customTranslateString || translateString,
1231
1314
  globalUiOptions: uiSchema[UI_GLOBAL_OPTIONS_KEY],
1232
- globalFormOptions: this.getGlobalFormOptions(props),
1315
+ globalFormOptions: Form.getGlobalFormOptions(props),
1233
1316
  uiSchemaDefinitions: uiSchema[UI_DEFINITIONS_KEY] ?? {},
1234
1317
  };
1235
1318
  }
@@ -1271,8 +1354,9 @@ export default class Form<
1271
1354
  // some themes (e.g. shadcn) use button elements instead of native inputs for radio groups
1272
1355
  field = this.formElement.current.querySelector(`input[id^="${elementId}"], button[id^="${elementId}"]`);
1273
1356
  }
1274
- if (field && field.length) {
1357
+ if (field?.length) {
1275
1358
  // If we got a list with length > 0
1359
+ // oxlint-disable-next-line prefer-destructuring
1276
1360
  field = field[0];
1277
1361
  }
1278
1362
  if (field) {
@@ -1291,7 +1375,7 @@ export default class Form<
1291
1375
  const { errors: prevErrors } = this.state;
1292
1376
  const schemaValidation = this.validate(formData);
1293
1377
  // Always merge extraErrors so they remain visible in state regardless of extraErrorsBlockSubmit.
1294
- const { errors, errorSchema } = extraErrors ? this.mergeErrors(schemaValidation, extraErrors) : schemaValidation;
1378
+ const { errors, errorSchema } = extraErrors ? Form.mergeErrors<T>(schemaValidation, extraErrors) : schemaValidation;
1295
1379
  // hasError gates submission: schema errors always block; extraErrors only block when
1296
1380
  // extraErrorsBlockSubmit is set (non-breaking default: extraErrors are informational only).
1297
1381
  const hasError = schemaValidation.errors.length > 0 || (extraErrors && extraErrorsBlockSubmit);
@@ -1314,6 +1398,7 @@ export default class Form<
1314
1398
  if (onError) {
1315
1399
  onError(errors);
1316
1400
  } else {
1401
+ // oxlint-disable-next-line no-console
1317
1402
  console.error('Form validation failed', errors);
1318
1403
  }
1319
1404
  },
@@ -1347,6 +1432,7 @@ export default class Form<
1347
1432
  const { omitExtraData } = this.props;
1348
1433
  let { formData: newFormData } = this.state;
1349
1434
  if (omitExtraData === true) {
1435
+ // oxlint-disable-next-line typescript/no-deprecated
1350
1436
  newFormData = this.omitExtraData(newFormData);
1351
1437
  }
1352
1438
  return this.validateFormWithFormData(newFormData);
@@ -1376,7 +1462,7 @@ export default class Form<
1376
1462
  } = this.props;
1377
1463
 
1378
1464
  const { schema, uiSchema, formData, errorSchema, fieldPathId, registry } = this.state;
1379
- const { SchemaField: _SchemaField } = registry.fields;
1465
+ const { SchemaField: SchemaFieldComponent } = registry.fields;
1380
1466
  const { SubmitButton } = registry.templates.ButtonTemplates;
1381
1467
  // The `semantic-ui` and `material-ui` themes have `_internalFormWrapper`s that take an `as` prop that is the
1382
1468
  // PropTypes.elementType to use for the inner tag, so we'll need to pass `tagName` along if it is provided.
@@ -1392,7 +1478,7 @@ export default class Form<
1392
1478
 
1393
1479
  return (
1394
1480
  <FormTag
1395
- className={className ? className : 'rjsf'}
1481
+ className={className || 'rjsf'}
1396
1482
  id={id}
1397
1483
  name={name}
1398
1484
  method={method}
@@ -1407,7 +1493,7 @@ export default class Form<
1407
1493
  ref={this.formElement}
1408
1494
  >
1409
1495
  {showErrorList === 'top' && this.renderErrors(registry)}
1410
- <_SchemaField
1496
+ <SchemaFieldComponent
1411
1497
  name=''
1412
1498
  schema={schema}
1413
1499
  uiSchema={uiSchema}
@@ -1422,7 +1508,7 @@ export default class Form<
1422
1508
  readonly={readonly}
1423
1509
  />
1424
1510
 
1425
- {children ? children : <SubmitButton uiSchema={submitUiSchema} registry={registry} />}
1511
+ {children || <SubmitButton uiSchema={submitUiSchema} registry={registry} />}
1426
1512
  {showErrorList === 'bottom' && this.renderErrors(registry)}
1427
1513
  </FormTag>
1428
1514
  );