@rjsf/core 6.0.0-beta.9 → 6.0.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 (160) hide show
  1. package/README.md +2 -0
  2. package/dist/core.umd.js +2042 -1987
  3. package/dist/index.cjs +4909 -0
  4. package/dist/index.cjs.map +7 -0
  5. package/dist/index.esm.js +2509 -2389
  6. package/dist/index.esm.js.map +4 -4
  7. package/lib/components/Form.d.ts +137 -34
  8. package/lib/components/Form.d.ts.map +1 -1
  9. package/lib/components/Form.js +318 -173
  10. package/lib/components/fields/ArrayField.d.ts +2 -187
  11. package/lib/components/fields/ArrayField.d.ts.map +1 -1
  12. package/lib/components/fields/ArrayField.js +526 -492
  13. package/lib/components/fields/BooleanField.d.ts.map +1 -1
  14. package/lib/components/fields/BooleanField.js +8 -3
  15. package/lib/components/fields/FallbackField.d.ts +7 -0
  16. package/lib/components/fields/FallbackField.d.ts.map +1 -0
  17. package/lib/components/fields/FallbackField.js +72 -0
  18. package/lib/components/fields/LayoutGridField.d.ts +109 -186
  19. package/lib/components/fields/LayoutGridField.d.ts.map +1 -1
  20. package/lib/components/fields/LayoutGridField.js +426 -426
  21. package/lib/components/fields/LayoutHeaderField.d.ts +1 -1
  22. package/lib/components/fields/LayoutHeaderField.js +3 -3
  23. package/lib/components/fields/LayoutMultiSchemaField.d.ts.map +1 -1
  24. package/lib/components/fields/LayoutMultiSchemaField.js +6 -6
  25. package/lib/components/fields/MultiSchemaField.d.ts.map +1 -1
  26. package/lib/components/fields/MultiSchemaField.js +16 -10
  27. package/lib/components/fields/NullField.js +3 -3
  28. package/lib/components/fields/NumberField.d.ts.map +1 -1
  29. package/lib/components/fields/NumberField.js +3 -3
  30. package/lib/components/fields/ObjectField.d.ts +2 -68
  31. package/lib/components/fields/ObjectField.d.ts.map +1 -1
  32. package/lib/components/fields/ObjectField.js +163 -163
  33. package/lib/components/fields/OptionalDataControlsField.d.ts +8 -0
  34. package/lib/components/fields/OptionalDataControlsField.d.ts.map +1 -0
  35. package/lib/components/fields/OptionalDataControlsField.js +43 -0
  36. package/lib/components/fields/SchemaField.d.ts.map +1 -1
  37. package/lib/components/fields/SchemaField.js +52 -30
  38. package/lib/components/fields/StringField.d.ts.map +1 -1
  39. package/lib/components/fields/StringField.js +8 -3
  40. package/lib/components/fields/index.d.ts.map +1 -1
  41. package/lib/components/fields/index.js +4 -0
  42. package/lib/components/templates/ArrayFieldDescriptionTemplate.d.ts +1 -1
  43. package/lib/components/templates/ArrayFieldDescriptionTemplate.js +3 -3
  44. package/lib/components/templates/ArrayFieldItemButtonsTemplate.d.ts +3 -3
  45. package/lib/components/templates/ArrayFieldItemButtonsTemplate.d.ts.map +1 -1
  46. package/lib/components/templates/ArrayFieldItemButtonsTemplate.js +3 -8
  47. package/lib/components/templates/ArrayFieldItemTemplate.d.ts +3 -3
  48. package/lib/components/templates/ArrayFieldItemTemplate.d.ts.map +1 -1
  49. package/lib/components/templates/ArrayFieldItemTemplate.js +1 -1
  50. package/lib/components/templates/ArrayFieldTemplate.d.ts +1 -1
  51. package/lib/components/templates/ArrayFieldTemplate.d.ts.map +1 -1
  52. package/lib/components/templates/ArrayFieldTemplate.js +4 -5
  53. package/lib/components/templates/ArrayFieldTitleTemplate.d.ts +1 -1
  54. package/lib/components/templates/ArrayFieldTitleTemplate.d.ts.map +1 -1
  55. package/lib/components/templates/ArrayFieldTitleTemplate.js +3 -3
  56. package/lib/components/templates/BaseInputTemplate.js +2 -2
  57. package/lib/components/templates/ButtonTemplates/AddButton.d.ts +1 -1
  58. package/lib/components/templates/ButtonTemplates/AddButton.d.ts.map +1 -1
  59. package/lib/components/templates/ButtonTemplates/AddButton.js +2 -2
  60. package/lib/components/templates/FallbackFieldTemplate.d.ts +7 -0
  61. package/lib/components/templates/FallbackFieldTemplate.d.ts.map +1 -0
  62. package/lib/components/templates/FallbackFieldTemplate.js +12 -0
  63. package/lib/components/templates/FieldErrorTemplate.js +2 -2
  64. package/lib/components/templates/FieldHelpTemplate.js +2 -2
  65. package/lib/components/templates/MultiSchemaFieldTemplate.d.ts +8 -0
  66. package/lib/components/templates/MultiSchemaFieldTemplate.d.ts.map +1 -0
  67. package/lib/components/templates/MultiSchemaFieldTemplate.js +10 -0
  68. package/lib/components/templates/ObjectFieldTemplate.d.ts.map +1 -1
  69. package/lib/components/templates/ObjectFieldTemplate.js +3 -2
  70. package/lib/components/templates/OptionalDataControlsTemplate.d.ts +11 -0
  71. package/lib/components/templates/OptionalDataControlsTemplate.d.ts.map +1 -0
  72. package/lib/components/templates/OptionalDataControlsTemplate.js +20 -0
  73. package/lib/components/templates/TitleField.d.ts.map +1 -1
  74. package/lib/components/templates/TitleField.js +2 -2
  75. package/lib/components/templates/UnsupportedField.js +3 -3
  76. package/lib/components/templates/WrapIfAdditionalTemplate.js +2 -2
  77. package/lib/components/templates/index.d.ts.map +1 -1
  78. package/lib/components/templates/index.js +6 -0
  79. package/lib/components/widgets/AltDateWidget.d.ts +1 -1
  80. package/lib/components/widgets/AltDateWidget.d.ts.map +1 -1
  81. package/lib/components/widgets/AltDateWidget.js +5 -46
  82. package/lib/components/widgets/CheckboxWidget.d.ts +1 -1
  83. package/lib/components/widgets/CheckboxWidget.d.ts.map +1 -1
  84. package/lib/components/widgets/CheckboxWidget.js +2 -2
  85. package/lib/components/widgets/CheckboxesWidget.d.ts +1 -1
  86. package/lib/components/widgets/CheckboxesWidget.d.ts.map +1 -1
  87. package/lib/components/widgets/CheckboxesWidget.js +4 -4
  88. package/lib/components/widgets/FileWidget.d.ts.map +1 -1
  89. package/lib/components/widgets/FileWidget.js +7 -87
  90. package/lib/components/widgets/HiddenWidget.d.ts +1 -1
  91. package/lib/components/widgets/HiddenWidget.d.ts.map +1 -1
  92. package/lib/components/widgets/HiddenWidget.js +2 -2
  93. package/lib/components/widgets/RadioWidget.d.ts +1 -1
  94. package/lib/components/widgets/RadioWidget.d.ts.map +1 -1
  95. package/lib/components/widgets/RadioWidget.js +2 -2
  96. package/lib/components/widgets/RatingWidget.d.ts +1 -1
  97. package/lib/components/widgets/RatingWidget.d.ts.map +1 -1
  98. package/lib/components/widgets/RatingWidget.js +2 -2
  99. package/lib/components/widgets/SelectWidget.d.ts +1 -1
  100. package/lib/components/widgets/SelectWidget.d.ts.map +1 -1
  101. package/lib/components/widgets/SelectWidget.js +2 -2
  102. package/lib/components/widgets/TextareaWidget.d.ts +1 -1
  103. package/lib/components/widgets/TextareaWidget.d.ts.map +1 -1
  104. package/lib/components/widgets/TextareaWidget.js +2 -2
  105. package/lib/getDefaultRegistry.d.ts.map +1 -1
  106. package/lib/getDefaultRegistry.js +6 -1
  107. package/lib/getTestRegistry.d.ts +5 -0
  108. package/lib/getTestRegistry.d.ts.map +1 -0
  109. package/lib/getTestRegistry.js +23 -0
  110. package/lib/index.d.ts +2 -1
  111. package/lib/index.d.ts.map +1 -1
  112. package/lib/index.js +2 -1
  113. package/lib/tsconfig.tsbuildinfo +1 -1
  114. package/package.json +35 -20
  115. package/src/components/Form.tsx +468 -206
  116. package/src/components/fields/ArrayField.tsx +871 -723
  117. package/src/components/fields/BooleanField.tsx +14 -5
  118. package/src/components/fields/FallbackField.tsx +157 -0
  119. package/src/components/fields/LayoutGridField.tsx +626 -603
  120. package/src/components/fields/LayoutHeaderField.tsx +3 -3
  121. package/src/components/fields/LayoutMultiSchemaField.tsx +9 -10
  122. package/src/components/fields/MultiSchemaField.tsx +57 -36
  123. package/src/components/fields/NullField.tsx +3 -3
  124. package/src/components/fields/NumberField.tsx +11 -3
  125. package/src/components/fields/ObjectField.tsx +308 -239
  126. package/src/components/fields/OptionalDataControlsField.tsx +84 -0
  127. package/src/components/fields/SchemaField.tsx +75 -94
  128. package/src/components/fields/StringField.tsx +14 -5
  129. package/src/components/fields/index.ts +4 -0
  130. package/src/components/templates/ArrayFieldDescriptionTemplate.tsx +3 -3
  131. package/src/components/templates/ArrayFieldItemButtonsTemplate.tsx +16 -21
  132. package/src/components/templates/ArrayFieldItemTemplate.tsx +3 -3
  133. package/src/components/templates/ArrayFieldTemplate.tsx +11 -18
  134. package/src/components/templates/ArrayFieldTitleTemplate.tsx +4 -3
  135. package/src/components/templates/BaseInputTemplate.tsx +5 -5
  136. package/src/components/templates/ButtonTemplates/AddButton.tsx +2 -0
  137. package/src/components/templates/FallbackFieldTemplate.tsx +28 -0
  138. package/src/components/templates/FieldErrorTemplate.tsx +2 -2
  139. package/src/components/templates/FieldHelpTemplate.tsx +2 -2
  140. package/src/components/templates/MultiSchemaFieldTemplate.tsx +20 -0
  141. package/src/components/templates/ObjectFieldTemplate.tsx +12 -7
  142. package/src/components/templates/OptionalDataControlsTemplate.tsx +43 -0
  143. package/src/components/templates/TitleField.tsx +6 -1
  144. package/src/components/templates/UnsupportedField.tsx +3 -3
  145. package/src/components/templates/WrapIfAdditionalTemplate.tsx +5 -5
  146. package/src/components/templates/index.ts +6 -0
  147. package/src/components/widgets/AltDateWidget.tsx +8 -126
  148. package/src/components/widgets/CheckboxWidget.tsx +4 -3
  149. package/src/components/widgets/CheckboxesWidget.tsx +5 -4
  150. package/src/components/widgets/FileWidget.tsx +11 -102
  151. package/src/components/widgets/HiddenWidget.tsx +2 -1
  152. package/src/components/widgets/RadioWidget.tsx +3 -2
  153. package/src/components/widgets/RatingWidget.tsx +2 -1
  154. package/src/components/widgets/SelectWidget.tsx +3 -2
  155. package/src/components/widgets/TextareaWidget.tsx +3 -2
  156. package/src/getDefaultRegistry.ts +14 -1
  157. package/src/getTestRegistry.tsx +38 -0
  158. package/src/index.ts +2 -1
  159. package/dist/index.js +0 -4834
  160. package/dist/index.js.map +0 -7
@@ -0,0 +1,84 @@
1
+ import {
2
+ FieldProps,
3
+ FormContextType,
4
+ getSchemaType,
5
+ getTemplate,
6
+ getUiOptions,
7
+ isFormDataAvailable,
8
+ optionalControlsId,
9
+ OptionalDataControlsTemplateProps,
10
+ RJSFSchema,
11
+ StrictRJSFSchema,
12
+ TranslatableString,
13
+ } from '@rjsf/utils';
14
+
15
+ /** The `OptionalDataControlsField` component is used to render the optional data controls for the field associated
16
+ * with the given props.
17
+ *
18
+ * @param props - The `FieldProps` for this template
19
+ */
20
+ export default function OptionalDataControlsField<
21
+ T = any,
22
+ S extends StrictRJSFSchema = RJSFSchema,
23
+ F extends FormContextType = any,
24
+ >(props: FieldProps<T, S, F>) {
25
+ const {
26
+ schema,
27
+ uiSchema = {},
28
+ formData,
29
+ disabled = false,
30
+ readonly = false,
31
+ onChange,
32
+ errorSchema,
33
+ fieldPathId,
34
+ registry,
35
+ } = props;
36
+
37
+ const { globalUiOptions = {}, schemaUtils, translateString } = registry;
38
+ const uiOptions = getUiOptions<T, S, F>(uiSchema, globalUiOptions);
39
+ const OptionalDataControlsTemplate = getTemplate<'OptionalDataControlsTemplate', T, S, F>(
40
+ 'OptionalDataControlsTemplate',
41
+ registry,
42
+ uiOptions,
43
+ );
44
+ const hasFormData = isFormDataAvailable<T>(formData);
45
+ let id: string;
46
+ let label: string | undefined;
47
+ let onAddClick: OptionalDataControlsTemplateProps['onAddClick'];
48
+ let onRemoveClick: OptionalDataControlsTemplateProps['onRemoveClick'];
49
+ if (disabled || readonly) {
50
+ id = optionalControlsId(fieldPathId, 'Msg');
51
+ label = hasFormData ? undefined : translateString(TranslatableString.OptionalObjectEmptyMsg);
52
+ } else {
53
+ const labelEnum = hasFormData ? TranslatableString.OptionalObjectRemove : TranslatableString.OptionalObjectAdd;
54
+ label = translateString(labelEnum);
55
+ if (hasFormData) {
56
+ id = optionalControlsId(fieldPathId, 'Remove');
57
+ onRemoveClick = () => onChange(undefined as T, fieldPathId.path, errorSchema);
58
+ } else {
59
+ id = optionalControlsId(fieldPathId, 'Add');
60
+ onAddClick = () => {
61
+ // If it has form data, store an empty object, otherwise get the default form state and use it
62
+ let newFormData: unknown = schemaUtils.getDefaultFormState(schema, formData, 'excludeObjectChildren');
63
+ if (newFormData === undefined) {
64
+ // If new form data ended up being undefined, and we have pushed the add button we need to actually add data
65
+ newFormData = getSchemaType<S>(schema) === 'array' ? [] : {};
66
+ }
67
+ onChange(newFormData as T, fieldPathId.path, errorSchema);
68
+ };
69
+ }
70
+ }
71
+ return (
72
+ label && (
73
+ <OptionalDataControlsTemplate
74
+ id={id}
75
+ registry={registry}
76
+ schema={schema}
77
+ uiSchema={uiSchema}
78
+ label={label}
79
+ onAddClick={onAddClick}
80
+ onRemoveClick={onRemoveClick}
81
+ />
82
+ )
83
+ );
84
+ }
@@ -1,9 +1,12 @@
1
1
  import { useCallback, Component, ComponentType } from 'react';
2
2
  import {
3
3
  ADDITIONAL_PROPERTY_FLAG,
4
- deepEquals,
4
+ ANY_OF_KEY,
5
5
  descriptionId,
6
6
  ErrorSchema,
7
+ Field,
8
+ FieldPathId,
9
+ FieldPathList,
7
10
  FieldProps,
8
11
  FieldTemplateProps,
9
12
  FormContextType,
@@ -11,12 +14,14 @@ import {
11
14
  getTemplate,
12
15
  getUiOptions,
13
16
  ID_KEY,
14
- IdSchema,
15
- mergeObjects,
17
+ isFormDataAvailable,
18
+ ONE_OF_KEY,
16
19
  Registry,
17
20
  RJSFSchema,
21
+ shouldRender,
22
+ shouldRenderOptionalField,
18
23
  StrictRJSFSchema,
19
- TranslatableString,
24
+ toFieldPathId,
20
25
  UI_OPTIONS_KEY,
21
26
  UIOptionsType,
22
27
  } from '@rjsf/utils';
@@ -40,18 +45,16 @@ const COMPONENT_TYPES: { [key: string]: string } = {
40
45
  *
41
46
  * @param schema - The schema from which to obtain the type
42
47
  * @param uiOptions - The UI Options that may affect the component decision
43
- * @param idSchema - The id that is passed to the `UnsupportedFieldTemplate`
44
48
  * @param registry - The registry from which fields and templates are obtained
45
49
  * @returns - The `Field` component that is used to render the actual field data
46
50
  */
47
51
  function getFieldComponent<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
48
52
  schema: S,
49
53
  uiOptions: UIOptionsType<T, S, F>,
50
- idSchema: IdSchema<T>,
51
54
  registry: Registry<T, S, F>,
52
55
  ): ComponentType<FieldProps<T, S, F>> {
53
56
  const field = uiOptions.field;
54
- const { fields, translateString } = registry;
57
+ const { fields } = registry;
55
58
  if (typeof field === 'function') {
56
59
  return field;
57
60
  }
@@ -75,24 +78,7 @@ function getFieldComponent<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
75
78
  return () => null;
76
79
  }
77
80
 
78
- return componentName in fields
79
- ? fields[componentName]
80
- : () => {
81
- const UnsupportedFieldTemplate = getTemplate<'UnsupportedFieldTemplate', T, S, F>(
82
- 'UnsupportedFieldTemplate',
83
- registry,
84
- uiOptions,
85
- );
86
-
87
- return (
88
- <UnsupportedFieldTemplate
89
- schema={schema}
90
- idSchema={idSchema}
91
- reason={translateString(TranslatableString.UnknownFieldType, [String(schema.type)])}
92
- registry={registry}
93
- />
94
- );
95
- };
81
+ return componentName in fields ? fields[componentName] : fields['FallbackField'];
96
82
  }
97
83
 
98
84
  /** The `SchemaFieldRender` component is the work-horse of react-jsonschema-form, determining what kind of real field to
@@ -106,21 +92,21 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
106
92
  ) {
107
93
  const {
108
94
  schema: _schema,
109
- idSchema: _idSchema,
95
+ fieldPathId,
110
96
  uiSchema,
111
97
  formData,
112
98
  errorSchema,
113
- idPrefix,
114
- idSeparator,
115
99
  name,
116
100
  onChange,
117
- onKeyChange,
118
- onDropPropertyClick,
119
- required,
101
+ onKeyRename,
102
+ onKeyRenameBlur,
103
+ onRemoveProperty,
104
+ required = false,
120
105
  registry,
121
106
  wasPropertyKeyModified = false,
122
107
  } = props;
123
- const { formContext, schemaUtils, globalUiOptions } = registry;
108
+ const { schemaUtils, globalFormOptions, globalUiOptions, fields } = registry;
109
+ const { AnyOfField: _AnyOfField, OneOfField: _OneOfField } = fields;
124
110
  const uiOptions = getUiOptions<T, S, F>(uiSchema, globalUiOptions);
125
111
  const FieldTemplate = getTemplate<'FieldTemplate', T, S, F>('FieldTemplate', registry, uiOptions);
126
112
  const DescriptionFieldTemplate = getTemplate<'DescriptionFieldTemplate', T, S, F>(
@@ -131,24 +117,20 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
131
117
  const FieldHelpTemplate = getTemplate<'FieldHelpTemplate', T, S, F>('FieldHelpTemplate', registry, uiOptions);
132
118
  const FieldErrorTemplate = getTemplate<'FieldErrorTemplate', T, S, F>('FieldErrorTemplate', registry, uiOptions);
133
119
  const schema = schemaUtils.retrieveSchema(_schema, formData);
134
- const fieldId = _idSchema[ID_KEY];
135
- const idSchema = mergeObjects(
136
- schemaUtils.toIdSchema(schema, fieldId, formData, idPrefix, idSeparator),
137
- _idSchema,
138
- ) as IdSchema<T>;
120
+ const fieldId = fieldPathId[ID_KEY];
139
121
 
140
122
  /** Intermediary `onChange` handler for field components that will inject the `id` of the current field into the
141
123
  * `onChange` chain if it is not already being provided from a deeper level in the hierarchy
142
124
  */
143
125
  const handleFieldComponentChange = useCallback(
144
- (formData: T | undefined, newErrorSchema?: ErrorSchema<T>, id?: string) => {
126
+ (formData: T | undefined, path: FieldPathList, newErrorSchema?: ErrorSchema<T>, id?: string) => {
145
127
  const theId = id || fieldId;
146
- return onChange(formData, newErrorSchema, theId);
128
+ return onChange(formData, path, newErrorSchema, theId);
147
129
  },
148
130
  [fieldId, onChange],
149
131
  );
150
132
 
151
- const FieldComponent = getFieldComponent<T, S, F>(schema, uiOptions, idSchema, registry);
133
+ const FieldComponent = getFieldComponent<T, S, F>(schema, uiOptions, registry);
152
134
  const disabled = Boolean(uiOptions.disabled ?? props.disabled);
153
135
  const readonly = Boolean(uiOptions.readonly ?? (props.readonly || props.schema.readOnly || schema.readOnly));
154
136
  const uiSchemaHideError = uiOptions.hideError;
@@ -159,7 +141,40 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
159
141
  return null;
160
142
  }
161
143
 
162
- const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions);
144
+ let displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions);
145
+
146
+ /** If the schema `anyOf` or 'oneOf' can be rendered as a select control, don't render the selection and let
147
+ * `StringField` component handle rendering unless there is a field override and that field replaces the any or one of
148
+ */
149
+ const isReplacingAnyOrOneOf = uiOptions.field && uiOptions.fieldReplacesAnyOrOneOf === true;
150
+ let XxxOfField: Field<T, S, F> | undefined;
151
+ let XxxOfOptions: S[] | undefined;
152
+ // When rendering the `XxxOfField` we'll need to change the fieldPathId of the main component, remembering the
153
+ // fieldPathId of the children for the ObjectField and ArrayField
154
+ let fieldPathIdProps: { fieldPathId: FieldPathId; childFieldPathId?: FieldPathId } = { fieldPathId };
155
+ if ((ANY_OF_KEY in schema || ONE_OF_KEY in schema) && !isReplacingAnyOrOneOf && !schemaUtils.isSelect(schema)) {
156
+ if (schema[ANY_OF_KEY]) {
157
+ XxxOfField = _AnyOfField;
158
+ XxxOfOptions = schema[ANY_OF_KEY].map((_schema) =>
159
+ schemaUtils.retrieveSchema(isObject(_schema) ? (_schema as S) : ({} as S), formData),
160
+ );
161
+ } else if (schema[ONE_OF_KEY]) {
162
+ XxxOfField = _OneOfField;
163
+ XxxOfOptions = schema[ONE_OF_KEY].map((_schema) =>
164
+ schemaUtils.retrieveSchema(isObject(_schema) ? (_schema as S) : ({} as S), formData),
165
+ );
166
+ }
167
+ // When the anyOf/oneOf is an optional data control render AND it does not have form data, hide the label
168
+ const isOptionalRender = shouldRenderOptionalField<T, S, F>(registry, schema, required, uiSchema);
169
+ const hasFormData = isFormDataAvailable<T>(formData);
170
+ displayLabel = displayLabel && (!isOptionalRender || hasFormData);
171
+ fieldPathIdProps = {
172
+ childFieldPathId: fieldPathId,
173
+ // The main FieldComponent will add `XxxOf` onto the fieldPathId to avoid duplication with the rendering of the
174
+ // same FieldComponent by the `XxxOfField`
175
+ fieldPathId: toFieldPathId('XxxOf', globalFormOptions, fieldPathId),
176
+ };
177
+ }
163
178
 
164
179
  const { __errors, ...fieldErrorSchema } = errorSchema || {};
165
180
  // See #439: uiSchema: Don't pass consumed class names or style to child components
@@ -172,7 +187,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
172
187
  <FieldComponent
173
188
  {...props}
174
189
  onChange={handleFieldComponentChange}
175
- idSchema={idSchema}
190
+ {...fieldPathIdProps}
176
191
  schema={schema}
177
192
  uiSchema={fieldUiSchema}
178
193
  disabled={disabled}
@@ -180,12 +195,11 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
180
195
  hideError={hideError}
181
196
  autofocus={autofocus}
182
197
  errorSchema={fieldErrorSchema as ErrorSchema}
183
- formContext={formContext}
184
198
  rawErrors={__errors}
185
199
  />
186
200
  );
187
201
 
188
- const id = idSchema[ID_KEY];
202
+ const id = fieldPathId[ID_KEY];
189
203
 
190
204
  // If this schema has a title defined, but the user has set a new key/label, retain their input.
191
205
  let label;
@@ -213,7 +227,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
213
227
  const helpComponent = (
214
228
  <FieldHelpTemplate
215
229
  help={help}
216
- idSchema={idSchema}
230
+ fieldPathId={fieldPathId}
217
231
  schema={schema}
218
232
  uiSchema={uiSchema}
219
233
  hasErrors={!hideError && __errors && __errors.length > 0}
@@ -225,11 +239,11 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
225
239
  * unless it can be rendered as select control
226
240
  */
227
241
  const errorsComponent =
228
- hideError || ((schema.anyOf || schema.oneOf) && !schemaUtils.isSelect(schema)) ? undefined : (
242
+ hideError || (XxxOfField && !schemaUtils.isSelect(schema)) ? undefined : (
229
243
  <FieldErrorTemplate
230
244
  errors={__errors}
231
245
  errorSchema={errorSchema}
232
- idSchema={idSchema}
246
+ fieldPathId={fieldPathId}
233
247
  schema={schema}
234
248
  uiSchema={uiSchema}
235
249
  registry={registry}
@@ -238,7 +252,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
238
252
  const fieldProps: Omit<FieldTemplateProps<T, S, F>, 'children'> = {
239
253
  description: (
240
254
  <DescriptionFieldTemplate
241
- id={descriptionId<T>(id)}
255
+ id={descriptionId(id)}
242
256
  description={description}
243
257
  schema={schema}
244
258
  uiSchema={uiSchema}
@@ -254,8 +268,9 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
254
268
  label,
255
269
  hidden,
256
270
  onChange,
257
- onKeyChange,
258
- onDropPropertyClick,
271
+ onKeyRename,
272
+ onKeyRenameBlur,
273
+ onRemoveProperty,
259
274
  required,
260
275
  disabled,
261
276
  readonly,
@@ -263,68 +278,29 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
263
278
  displayLabel,
264
279
  classNames: classNames.join(' ').trim(),
265
280
  style: uiOptions.style,
266
- formContext,
267
281
  formData,
268
282
  schema,
269
283
  uiSchema,
270
284
  registry,
271
285
  };
272
286
 
273
- const _AnyOfField = registry.fields.AnyOfField;
274
- const _OneOfField = registry.fields.OneOfField;
275
- const isReplacingAnyOrOneOf = uiSchema?.['ui:field'] && uiSchema?.['ui:fieldReplacesAnyOrOneOf'] === true;
276
-
277
287
  return (
278
288
  <FieldTemplate {...fieldProps}>
279
289
  <>
280
290
  {field}
281
- {/*
282
- If the schema `anyOf` or 'oneOf' can be rendered as a select control, don't
283
- render the selection and let `StringField` component handle
284
- rendering
285
- */}
286
- {schema.anyOf && !isReplacingAnyOrOneOf && !schemaUtils.isSelect(schema) && (
287
- <_AnyOfField
291
+ {XxxOfField && (
292
+ <XxxOfField
288
293
  name={name}
289
294
  disabled={disabled}
290
295
  readonly={readonly}
291
296
  hideError={hideError}
292
297
  errorSchema={errorSchema}
293
298
  formData={formData}
294
- formContext={formContext}
295
- idPrefix={idPrefix}
296
- idSchema={idSchema}
297
- idSeparator={idSeparator}
299
+ fieldPathId={fieldPathId}
298
300
  onBlur={props.onBlur}
299
301
  onChange={props.onChange}
300
302
  onFocus={props.onFocus}
301
- options={schema.anyOf.map((_schema) =>
302
- schemaUtils.retrieveSchema(isObject(_schema) ? (_schema as S) : ({} as S), formData),
303
- )}
304
- registry={registry}
305
- required={required}
306
- schema={schema}
307
- uiSchema={uiSchema}
308
- />
309
- )}
310
- {schema.oneOf && !isReplacingAnyOrOneOf && !schemaUtils.isSelect(schema) && (
311
- <_OneOfField
312
- name={name}
313
- disabled={disabled}
314
- readonly={readonly}
315
- hideError={hideError}
316
- errorSchema={errorSchema}
317
- formData={formData}
318
- formContext={formContext}
319
- idPrefix={idPrefix}
320
- idSchema={idSchema}
321
- idSeparator={idSeparator}
322
- onBlur={props.onBlur}
323
- onChange={props.onChange}
324
- onFocus={props.onFocus}
325
- options={schema.oneOf.map((_schema) =>
326
- schemaUtils.retrieveSchema(isObject(_schema) ? (_schema as S) : ({} as S), formData),
327
- )}
303
+ options={XxxOfOptions}
328
304
  registry={registry}
329
305
  required={required}
330
306
  schema={schema}
@@ -343,7 +319,12 @@ class SchemaField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
343
319
  FieldProps<T, S, F>
344
320
  > {
345
321
  shouldComponentUpdate(nextProps: Readonly<FieldProps<T, S, F>>) {
346
- return !deepEquals(this.props, nextProps);
322
+ const {
323
+ registry: { globalFormOptions },
324
+ } = this.props;
325
+ const { experimental_componentUpdateStrategy = 'customDeep' } = globalFormOptions;
326
+
327
+ return shouldRender(this, nextProps, this.state, experimental_componentUpdateStrategy);
347
328
  }
348
329
 
349
330
  render() {
@@ -1,3 +1,4 @@
1
+ import { useCallback } from 'react';
1
2
  import {
2
3
  getWidget,
3
4
  getUiOptions,
@@ -7,6 +8,7 @@ import {
7
8
  FormContextType,
8
9
  RJSFSchema,
9
10
  StrictRJSFSchema,
11
+ ErrorSchema,
10
12
  } from '@rjsf/utils';
11
13
 
12
14
  /** The `StringField` component is used to render a schema field that represents a string type
@@ -20,7 +22,7 @@ function StringField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
20
22
  schema,
21
23
  name,
22
24
  uiSchema,
23
- idSchema,
25
+ fieldPathId,
24
26
  formData,
25
27
  required,
26
28
  disabled = false,
@@ -34,7 +36,7 @@ function StringField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
34
36
  hideError,
35
37
  } = props;
36
38
  const { title, format } = schema;
37
- const { widgets, formContext, schemaUtils, globalUiOptions } = registry;
39
+ const { widgets, schemaUtils, globalUiOptions } = registry;
38
40
  const enumOptions = schemaUtils.isSelect(schema) ? optionsList<T, S, F>(schema, uiSchema) : undefined;
39
41
  let defaultWidget = enumOptions ? 'select' : 'text';
40
42
  if (format && hasWidget<T, S, F>(schema, format, widgets)) {
@@ -44,28 +46,35 @@ function StringField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
44
46
  const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions);
45
47
  const label = uiTitle ?? title ?? name;
46
48
  const Widget = getWidget<T, S, F>(schema, widget, widgets);
49
+ const onWidgetChange = useCallback(
50
+ (value: T | undefined, errorSchema?: ErrorSchema, id?: string) => {
51
+ // String field change passes an empty path array to the parent field which adds the appropriate path
52
+ return onChange(value, fieldPathId.path, errorSchema, id);
53
+ },
54
+ [onChange, fieldPathId],
55
+ );
47
56
  return (
48
57
  <Widget
49
58
  options={{ ...options, enumOptions }}
50
59
  schema={schema}
51
60
  uiSchema={uiSchema}
52
- id={idSchema.$id}
61
+ id={fieldPathId.$id}
53
62
  name={name}
54
63
  label={label}
55
64
  hideLabel={!displayLabel}
56
65
  hideError={hideError}
57
66
  value={formData}
58
- onChange={onChange}
67
+ onChange={onWidgetChange}
59
68
  onBlur={onBlur}
60
69
  onFocus={onFocus}
61
70
  required={required}
62
71
  disabled={disabled}
63
72
  readonly={readonly}
64
- formContext={formContext}
65
73
  autofocus={autofocus}
66
74
  registry={registry}
67
75
  placeholder={placeholder}
68
76
  rawErrors={rawErrors}
77
+ htmlName={fieldPathId.name}
69
78
  />
70
79
  );
71
80
  }
@@ -2,12 +2,14 @@ import { Field, FormContextType, RegistryFieldsType, RJSFSchema, StrictRJSFSchem
2
2
 
3
3
  import ArrayField from './ArrayField';
4
4
  import BooleanField from './BooleanField';
5
+ import FallbackField from './FallbackField';
5
6
  import LayoutGridField from './LayoutGridField';
6
7
  import LayoutHeaderField from './LayoutHeaderField';
7
8
  import LayoutMultiSchemaField from './LayoutMultiSchemaField';
8
9
  import MultiSchemaField from './MultiSchemaField';
9
10
  import NumberField from './NumberField';
10
11
  import ObjectField from './ObjectField';
12
+ import OptionalDataControlsField from './OptionalDataControlsField';
11
13
  import SchemaField from './SchemaField';
12
14
  import StringField from './StringField';
13
15
  import NullField from './NullField';
@@ -22,12 +24,14 @@ function fields<
22
24
  ArrayField: ArrayField as unknown as Field<T, S, F>,
23
25
  // ArrayField falls back to SchemaField if ArraySchemaField is not defined, which it isn't by default
24
26
  BooleanField,
27
+ FallbackField,
25
28
  LayoutGridField,
26
29
  LayoutHeaderField,
27
30
  LayoutMultiSchemaField,
28
31
  NumberField,
29
32
  ObjectField,
30
33
  OneOfField: MultiSchemaField,
34
+ OptionalDataControlsField,
31
35
  SchemaField,
32
36
  StringField,
33
37
  NullField,
@@ -9,7 +9,7 @@ import {
9
9
  } from '@rjsf/utils';
10
10
 
11
11
  /** The `ArrayFieldDescriptionTemplate` component renders a `DescriptionFieldTemplate` with an `id` derived from
12
- * the `idSchema`.
12
+ * the `fieldPathId`.
13
13
  *
14
14
  * @param props - The `ArrayFieldDescriptionProps` for the component
15
15
  */
@@ -18,7 +18,7 @@ export default function ArrayFieldDescriptionTemplate<
18
18
  S extends StrictRJSFSchema = RJSFSchema,
19
19
  F extends FormContextType = any,
20
20
  >(props: ArrayFieldDescriptionProps<T, S, F>) {
21
- const { idSchema, description, registry, schema, uiSchema } = props;
21
+ const { fieldPathId, description, registry, schema, uiSchema } = props;
22
22
  const options = getUiOptions<T, S, F>(uiSchema, registry.globalUiOptions);
23
23
  const { label: displayLabel = true } = options;
24
24
  if (!description || !displayLabel) {
@@ -31,7 +31,7 @@ export default function ArrayFieldDescriptionTemplate<
31
31
  );
32
32
  return (
33
33
  <DescriptionFieldTemplate
34
- id={descriptionId<T>(idSchema)}
34
+ id={descriptionId(fieldPathId)}
35
35
  description={description}
36
36
  schema={schema}
37
37
  uiSchema={uiSchema}
@@ -1,6 +1,5 @@
1
- import { useMemo } from 'react';
2
1
  import {
3
- ArrayFieldItemButtonsTemplateType,
2
+ ArrayFieldItemButtonsTemplateProps,
4
3
  buttonId,
5
4
  FormContextType,
6
5
  RJSFSchema,
@@ -10,72 +9,68 @@ import {
10
9
  /** The `ArrayFieldTemplateItemButtons` component is the template used to render the buttons associate3d with items of
11
10
  * an array.
12
11
  *
13
- * @param props - The `ArrayFieldItemButtonsTemplateType` props for the component
12
+ * @param props - The `ArrayFieldItemButtonsTemplateProps` props for the component
14
13
  */
15
14
  export default function ArrayFieldItemButtonsTemplate<
16
15
  T = any,
17
16
  S extends StrictRJSFSchema = RJSFSchema,
18
17
  F extends FormContextType = any,
19
- >(props: ArrayFieldItemButtonsTemplateType<T, S, F>) {
18
+ >(props: ArrayFieldItemButtonsTemplateProps<T, S, F>) {
20
19
  const {
21
20
  disabled,
22
21
  hasCopy,
23
22
  hasMoveDown,
24
23
  hasMoveUp,
25
24
  hasRemove,
26
- idSchema,
27
- index,
28
- onCopyIndexClick,
29
- onDropIndexClick,
30
- onReorderClick,
25
+ fieldPathId,
26
+ onCopyItem,
27
+ onRemoveItem,
28
+ onMoveDownItem,
29
+ onMoveUpItem,
31
30
  readonly,
32
31
  registry,
33
32
  uiSchema,
34
33
  } = props;
35
34
  const { CopyButton, MoveDownButton, MoveUpButton, RemoveButton } = registry.templates.ButtonTemplates;
36
- const onCopyClick = useMemo(() => onCopyIndexClick(index), [index, onCopyIndexClick]);
37
- const onRemoveClick = useMemo(() => onDropIndexClick(index), [index, onDropIndexClick]);
38
- const onArrowUpClick = useMemo(() => onReorderClick(index, index - 1), [index, onReorderClick]);
39
- const onArrowDownClick = useMemo(() => onReorderClick(index, index + 1), [index, onReorderClick]);
40
35
 
41
36
  return (
42
37
  <>
43
38
  {(hasMoveUp || hasMoveDown) && (
44
39
  <MoveUpButton
45
- id={buttonId<T>(idSchema, 'moveUp')}
40
+ id={buttonId(fieldPathId, 'moveUp')}
46
41
  className='rjsf-array-item-move-up'
47
42
  disabled={disabled || readonly || !hasMoveUp}
48
- onClick={onArrowUpClick}
43
+ onClick={onMoveUpItem}
49
44
  uiSchema={uiSchema}
50
45
  registry={registry}
51
46
  />
52
47
  )}
53
48
  {(hasMoveUp || hasMoveDown) && (
54
49
  <MoveDownButton
55
- id={buttonId<T>(idSchema, 'moveDown')}
50
+ id={buttonId(fieldPathId, 'moveDown')}
56
51
  className='rjsf-array-item-move-down'
57
52
  disabled={disabled || readonly || !hasMoveDown}
58
- onClick={onArrowDownClick}
53
+ onClick={onMoveDownItem}
59
54
  uiSchema={uiSchema}
60
55
  registry={registry}
61
56
  />
62
57
  )}
63
58
  {hasCopy && (
64
59
  <CopyButton
65
- id={buttonId<T>(idSchema, 'copy')}
60
+ id={buttonId(fieldPathId, 'copy')}
66
61
  className='rjsf-array-item-copy'
67
62
  disabled={disabled || readonly}
68
- onClick={onCopyClick}
63
+ onClick={onCopyItem}
69
64
  uiSchema={uiSchema}
70
65
  registry={registry}
71
66
  />
72
67
  )}
73
68
  {hasRemove && (
74
69
  <RemoveButton
75
- id={buttonId<T>(idSchema, 'remove')}
70
+ id={buttonId(fieldPathId, 'remove')}
76
71
  className='rjsf-array-item-remove'
77
72
  disabled={disabled || readonly}
78
- onClick={onRemoveClick}
73
+ onClick={onRemoveItem}
79
74
  uiSchema={uiSchema}
80
75
  registry={registry}
81
76
  />
@@ -1,6 +1,6 @@
1
1
  import { CSSProperties } from 'react';
2
2
  import {
3
- ArrayFieldItemTemplateType,
3
+ ArrayFieldItemTemplateProps,
4
4
  FormContextType,
5
5
  getTemplate,
6
6
  getUiOptions,
@@ -10,13 +10,13 @@ import {
10
10
 
11
11
  /** The `ArrayFieldItemTemplate` component is the template used to render an items of an array.
12
12
  *
13
- * @param props - The `ArrayFieldItemTemplateType` props for the component
13
+ * @param props - The `ArrayFieldItemTemplateProps` props for the component
14
14
  */
15
15
  export default function ArrayFieldItemTemplate<
16
16
  T = any,
17
17
  S extends StrictRJSFSchema = RJSFSchema,
18
18
  F extends FormContextType = any,
19
- >(props: ArrayFieldItemTemplateType<T, S, F>) {
19
+ >(props: ArrayFieldItemTemplateProps<T, S, F>) {
20
20
  const { children, className, buttonsProps, hasToolbar, registry, uiSchema } = props;
21
21
  const uiOptions = getUiOptions<T, S, F>(uiSchema);
22
22
  const ArrayFieldItemButtonsTemplate = getTemplate<'ArrayFieldItemButtonsTemplate', T, S, F>(