@rjsf/core 5.24.10 → 6.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/core.umd.js +982 -196
  2. package/dist/index.esm.js +1366 -490
  3. package/dist/index.esm.js.map +4 -4
  4. package/dist/index.js +1452 -616
  5. package/dist/index.js.map +4 -4
  6. package/lib/components/Form.d.ts +0 -7
  7. package/lib/components/Form.d.ts.map +1 -1
  8. package/lib/components/Form.js +2 -5
  9. package/lib/components/fields/ArrayField.d.ts +19 -9
  10. package/lib/components/fields/ArrayField.d.ts.map +1 -1
  11. package/lib/components/fields/ArrayField.js +22 -12
  12. package/lib/components/fields/BooleanField.d.ts.map +1 -1
  13. package/lib/components/fields/BooleanField.js +3 -9
  14. package/lib/components/fields/LayoutGridField.d.ts +480 -0
  15. package/lib/components/fields/LayoutGridField.d.ts.map +1 -0
  16. package/lib/components/fields/LayoutGridField.js +711 -0
  17. package/lib/components/fields/LayoutHeaderField.d.ts +12 -0
  18. package/lib/components/fields/LayoutHeaderField.d.ts.map +1 -0
  19. package/lib/components/fields/LayoutHeaderField.js +23 -0
  20. package/lib/components/fields/LayoutMultiSchemaField.d.ts +28 -0
  21. package/lib/components/fields/LayoutMultiSchemaField.d.ts.map +1 -0
  22. package/lib/components/fields/LayoutMultiSchemaField.js +114 -0
  23. package/lib/components/fields/MultiSchemaField.d.ts.map +1 -1
  24. package/lib/components/fields/ObjectField.d.ts.map +1 -1
  25. package/lib/components/fields/ObjectField.js +29 -23
  26. package/lib/components/fields/SchemaField.d.ts.map +1 -1
  27. package/lib/components/fields/SchemaField.js +2 -8
  28. package/lib/components/fields/index.d.ts.map +1 -1
  29. package/lib/components/fields/index.js +6 -0
  30. package/lib/components/templates/ArrayFieldItemButtonsTemplate.d.ts +8 -0
  31. package/lib/components/templates/ArrayFieldItemButtonsTemplate.d.ts.map +1 -0
  32. package/lib/components/templates/ArrayFieldItemButtonsTemplate.js +17 -0
  33. package/lib/components/templates/ArrayFieldItemTemplate.d.ts +3 -3
  34. package/lib/components/templates/ArrayFieldItemTemplate.d.ts.map +1 -1
  35. package/lib/components/templates/ArrayFieldItemTemplate.js +7 -5
  36. package/lib/components/templates/ArrayFieldTemplate.d.ts +1 -1
  37. package/lib/components/templates/ArrayFieldTemplate.d.ts.map +1 -1
  38. package/lib/components/templates/ArrayFieldTemplate.js +3 -3
  39. package/lib/components/templates/ButtonTemplates/IconButton.d.ts.map +1 -1
  40. package/lib/components/templates/ButtonTemplates/IconButton.js +4 -4
  41. package/lib/components/templates/GridTemplate.d.ts +8 -0
  42. package/lib/components/templates/GridTemplate.d.ts.map +1 -0
  43. package/lib/components/templates/GridTemplate.js +10 -0
  44. package/lib/components/templates/ObjectFieldTemplate.d.ts.map +1 -1
  45. package/lib/components/templates/ObjectFieldTemplate.js +2 -2
  46. package/lib/components/templates/WrapIfAdditionalTemplate.d.ts.map +1 -1
  47. package/lib/components/templates/WrapIfAdditionalTemplate.js +9 -4
  48. package/lib/components/templates/index.d.ts.map +1 -1
  49. package/lib/components/templates/index.js +4 -0
  50. package/lib/components/widgets/AltDateWidget.d.ts.map +1 -1
  51. package/lib/components/widgets/FileWidget.js +1 -1
  52. package/lib/components/widgets/RadioWidget.js +3 -3
  53. package/lib/components/widgets/RatingWidget.d.ts +15 -0
  54. package/lib/components/widgets/RatingWidget.d.ts.map +1 -0
  55. package/lib/components/widgets/RatingWidget.js +63 -0
  56. package/lib/components/widgets/SelectWidget.d.ts.map +1 -1
  57. package/lib/components/widgets/SelectWidget.js +4 -4
  58. package/lib/components/widgets/index.d.ts.map +1 -1
  59. package/lib/components/widgets/index.js +2 -0
  60. package/lib/tsconfig.tsbuildinfo +1 -1
  61. package/lib/withTheme.d.ts.map +1 -1
  62. package/lib/withTheme.js +1 -0
  63. package/package.json +44 -35
  64. package/src/components/Form.tsx +24 -30
  65. package/src/components/fields/ArrayField.tsx +34 -24
  66. package/src/components/fields/BooleanField.tsx +6 -14
  67. package/src/components/fields/LayoutGridField.tsx +967 -0
  68. package/src/components/fields/LayoutHeaderField.tsx +49 -0
  69. package/src/components/fields/LayoutMultiSchemaField.tsx +228 -0
  70. package/src/components/fields/NullField.tsx +1 -1
  71. package/src/components/fields/NumberField.tsx +2 -2
  72. package/src/components/fields/ObjectField.tsx +32 -28
  73. package/src/components/fields/SchemaField.tsx +14 -22
  74. package/src/components/fields/StringField.tsx +2 -2
  75. package/src/components/fields/index.ts +7 -1
  76. package/src/components/templates/ArrayFieldDescriptionTemplate.tsx +2 -2
  77. package/src/components/templates/ArrayFieldItemButtonsTemplate.tsx +85 -0
  78. package/src/components/templates/ArrayFieldItemTemplate.tsx +18 -57
  79. package/src/components/templates/ArrayFieldTemplate.tsx +10 -8
  80. package/src/components/templates/ArrayFieldTitleTemplate.tsx +2 -2
  81. package/src/components/templates/BaseInputTemplate.tsx +4 -4
  82. package/src/components/templates/ButtonTemplates/IconButton.tsx +9 -36
  83. package/src/components/templates/ButtonTemplates/SubmitButton.tsx +1 -1
  84. package/src/components/templates/ButtonTemplates/index.ts +1 -1
  85. package/src/components/templates/DescriptionField.tsx +1 -1
  86. package/src/components/templates/FieldErrorTemplate.tsx +1 -1
  87. package/src/components/templates/FieldHelpTemplate.tsx +1 -1
  88. package/src/components/templates/FieldTemplate/FieldTemplate.tsx +2 -2
  89. package/src/components/templates/GridTemplate.tsx +15 -0
  90. package/src/components/templates/ObjectFieldTemplate.tsx +5 -3
  91. package/src/components/templates/TitleField.tsx +1 -1
  92. package/src/components/templates/UnsupportedField.tsx +1 -1
  93. package/src/components/templates/WrapIfAdditionalTemplate.tsx +14 -4
  94. package/src/components/templates/index.ts +4 -0
  95. package/src/components/widgets/AltDateWidget.tsx +9 -6
  96. package/src/components/widgets/CheckboxWidget.tsx +4 -4
  97. package/src/components/widgets/CheckboxesWidget.tsx +2 -2
  98. package/src/components/widgets/ColorWidget.tsx +1 -1
  99. package/src/components/widgets/DateTimeWidget.tsx +1 -1
  100. package/src/components/widgets/DateWidget.tsx +1 -1
  101. package/src/components/widgets/EmailWidget.tsx +1 -1
  102. package/src/components/widgets/FileWidget.tsx +4 -4
  103. package/src/components/widgets/PasswordWidget.tsx +1 -1
  104. package/src/components/widgets/RadioWidget.tsx +3 -3
  105. package/src/components/widgets/RangeWidget.tsx +1 -1
  106. package/src/components/widgets/RatingWidget.tsx +129 -0
  107. package/src/components/widgets/SelectWidget.tsx +4 -3
  108. package/src/components/widgets/TextWidget.tsx +1 -1
  109. package/src/components/widgets/TextareaWidget.tsx +3 -3
  110. package/src/components/widgets/TimeWidget.tsx +1 -1
  111. package/src/components/widgets/URLWidget.tsx +1 -1
  112. package/src/components/widgets/UpDownWidget.tsx +1 -1
  113. package/src/components/widgets/index.ts +3 -1
  114. package/src/getDefaultRegistry.ts +1 -1
  115. package/src/tsconfig.json +0 -3
  116. package/src/withTheme.tsx +4 -3
  117. package/LICENSE.md +0 -201
@@ -0,0 +1,49 @@
1
+ import {
2
+ getTemplate,
3
+ getUiOptions,
4
+ titleId,
5
+ FieldProps,
6
+ FormContextType,
7
+ RJSFSchema,
8
+ StrictRJSFSchema,
9
+ TemplatesType,
10
+ } from '@rjsf/utils';
11
+
12
+ /** The `LayoutHeaderField` component renders a `TitleFieldTemplate` with an `id` derived from the `idSchema`
13
+ * and whether it is `required` from the props. The `title` is derived from the props as follows:
14
+ * - If there is a title in the `uiSchema`, it is displayed
15
+ * - Else, if there is an explicit `title` passed in the props, it is displayed
16
+ * - Otherwise, if there is a title in the `schema`, it is displayed
17
+ * - Finally, the `name` prop is displayed as the title
18
+ *
19
+ * @param props - The `LayoutHeaderField` for the component
20
+ */
21
+ export default function LayoutHeaderField<
22
+ T = any,
23
+ S extends StrictRJSFSchema = RJSFSchema,
24
+ F extends FormContextType = any,
25
+ >(props: FieldProps<T, S, F>) {
26
+ const { idSchema, title, schema, uiSchema, required, registry, name } = props;
27
+ const options = getUiOptions<T, S, F>(uiSchema, registry.globalUiOptions);
28
+ const { title: uiTitle } = options;
29
+ const { title: schemaTitle } = schema;
30
+ const fieldTitle = uiTitle || title || schemaTitle || name;
31
+ if (!fieldTitle) {
32
+ return null;
33
+ }
34
+ const TitleFieldTemplate: TemplatesType<T, S, F>['TitleFieldTemplate'] = getTemplate<'TitleFieldTemplate', T, S, F>(
35
+ 'TitleFieldTemplate',
36
+ registry,
37
+ options,
38
+ );
39
+ return (
40
+ <TitleFieldTemplate
41
+ id={titleId<T>(idSchema)}
42
+ title={fieldTitle}
43
+ required={required}
44
+ schema={schema}
45
+ uiSchema={uiSchema}
46
+ registry={registry}
47
+ />
48
+ );
49
+ }
@@ -0,0 +1,228 @@
1
+ import { useState, useEffect } from 'react';
2
+ import {
3
+ ANY_OF_KEY,
4
+ CONST_KEY,
5
+ DEFAULT_KEY,
6
+ EnumOptionsType,
7
+ ERRORS_KEY,
8
+ FieldProps,
9
+ FormContextType,
10
+ getDiscriminatorFieldFromSchema,
11
+ hashObject,
12
+ ID_KEY,
13
+ ONE_OF_KEY,
14
+ optionsList,
15
+ PROPERTIES_KEY,
16
+ RJSFSchema,
17
+ getTemplate,
18
+ getUiOptions,
19
+ getWidget,
20
+ SchemaUtilsType,
21
+ StrictRJSFSchema,
22
+ UiSchema,
23
+ } from '@rjsf/utils';
24
+ import get from 'lodash/get';
25
+ import has from 'lodash/has';
26
+ import isEmpty from 'lodash/isEmpty';
27
+ import noop from 'lodash/noop';
28
+ import omit from 'lodash/omit';
29
+ import set from 'lodash/set';
30
+
31
+ /** Gets the selected option from the list of `options`, using the `selectorField` to search inside each `option` for
32
+ * the `properties[selectorField].default(or const)` that matches the given `value`.
33
+ *
34
+ * @param options - The list of schemas each representing a choice in the `oneOf`
35
+ * @param selectorField - The name of the field that is common in all of the schemas that represents the selector field
36
+ * @param value - The current value of the selector field from the data
37
+ */
38
+ export function getSelectedOption<S extends StrictRJSFSchema = RJSFSchema>(
39
+ options: EnumOptionsType<S>[],
40
+ selectorField: string,
41
+ value: unknown,
42
+ ): S | undefined {
43
+ const defaultValue = '!@#!@$@#$!@$#';
44
+ const schemaOptions: S[] = options.map(({ schema }) => schema!);
45
+ return schemaOptions.find((option) => {
46
+ const selector = get(option, [PROPERTIES_KEY, selectorField]);
47
+ const result = get(selector, DEFAULT_KEY, get(selector, CONST_KEY, defaultValue));
48
+ return result === value;
49
+ });
50
+ }
51
+
52
+ /** Computes the `enumOptions` array from the schema and options.
53
+ *
54
+ * @param schema - The schema that contains the `options`
55
+ * @param options - The options from the `schema`
56
+ * @param schemaUtils - The SchemaUtilsType object used to call retrieveSchema,
57
+ * @param [uiSchema] - The optional uiSchema for the schema
58
+ * @param [formData] - The optional formData associated with the schema
59
+ * @returns - The list of enumOptions for the `schema` and `options`
60
+ * @throws - Error when no enum options were computed
61
+ */
62
+ export function computeEnumOptions<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
63
+ schema: S,
64
+ options: S[],
65
+ schemaUtils: SchemaUtilsType<T, S, F>,
66
+ uiSchema?: UiSchema<T, S, F>,
67
+ formData?: T,
68
+ ): EnumOptionsType<S>[] {
69
+ const realOptions = options.map((opt: S) => schemaUtils.retrieveSchema(opt, formData));
70
+ let tempSchema = schema;
71
+ if (has(schema, ONE_OF_KEY)) {
72
+ tempSchema = { ...schema, [ONE_OF_KEY]: realOptions };
73
+ } else if (has(schema, ANY_OF_KEY)) {
74
+ tempSchema = { ...schema, [ANY_OF_KEY]: realOptions };
75
+ }
76
+ const enumOptions = optionsList<T, S, F>(tempSchema, uiSchema);
77
+ if (!enumOptions) {
78
+ throw new Error(`No enumOptions were computed from the schema ${JSON.stringify(tempSchema)}`);
79
+ }
80
+ return enumOptions;
81
+ }
82
+
83
+ /** The `LayoutMultiSchemaField` is an adaptation of the `MultiSchemaField` but changed considerably to only
84
+ * support `anyOf`/`oneOf` fields that are being displayed in a `LayoutGridField` where the field selection is shown as
85
+ * a radio group by default. It expects that a `selectorField` is provided (either directly via the `discriminator`
86
+ * field or indirectly via `ui:optionsSchemaSelector` in the `uiSchema`) to help determine which `anyOf`/`oneOf` schema
87
+ * is active. If no `selectorField` is specified, then an error is thrown.
88
+ */
89
+ export default function LayoutMultiSchemaField<
90
+ T = any,
91
+ S extends StrictRJSFSchema = RJSFSchema,
92
+ F extends FormContextType = any,
93
+ >(props: FieldProps<T, S, F>) {
94
+ const {
95
+ name,
96
+ baseType,
97
+ disabled = false,
98
+ formData,
99
+ idSchema,
100
+ onBlur,
101
+ onChange,
102
+ options,
103
+ onFocus,
104
+ registry,
105
+ uiSchema,
106
+ schema,
107
+ formContext,
108
+ autofocus,
109
+ readonly,
110
+ required,
111
+ errorSchema,
112
+ hideError = false,
113
+ } = props;
114
+ const { widgets, schemaUtils, globalUiOptions } = registry;
115
+ const [enumOptions, setEnumOptions] = useState(computeEnumOptions(schema, options, schemaUtils, uiSchema, formData)!);
116
+ const id = get(idSchema, ID_KEY);
117
+ const discriminator = getDiscriminatorFieldFromSchema(schema);
118
+ const FieldErrorTemplate = getTemplate<'FieldErrorTemplate', T, S, F>('FieldErrorTemplate', registry, options);
119
+ const FieldTemplate = getTemplate<'FieldTemplate', T, S, F>('FieldTemplate', registry, options);
120
+ const schemaHash = hashObject(schema);
121
+ const optionsHash = hashObject(options);
122
+ const uiSchemaHash = uiSchema ? hashObject(uiSchema) : '';
123
+ const formDataHash = formData ? hashObject(formData) : '';
124
+
125
+ useEffect(() => {
126
+ setEnumOptions(computeEnumOptions(schema, options, schemaUtils, uiSchema, formData));
127
+ // We are using hashes in place of the dependencies
128
+ // eslint-disable-next-line react-hooks/exhaustive-deps
129
+ }, [schemaHash, optionsHash, schemaUtils, uiSchemaHash, formDataHash]);
130
+ const {
131
+ widget = discriminator ? 'radio' : 'select',
132
+ title = '',
133
+ placeholder = '',
134
+ optionsSchemaSelector: selectorField = discriminator,
135
+ hideError: uiSchemaHideError,
136
+ ...uiOptions
137
+ } = getUiOptions<T, S, F>(uiSchema);
138
+ if (!selectorField) {
139
+ throw new Error('No selector field provided for the LayoutMultiSchemaField');
140
+ }
141
+ const selectedOption = get(formData, selectorField);
142
+ let optionSchema: S = get(enumOptions[0]?.schema, [PROPERTIES_KEY, selectorField], {}) as S;
143
+ const option = getSelectedOption<S>(enumOptions, selectorField, selectedOption);
144
+ // If the subschema doesn't declare a type, infer the type from the parent schema
145
+ optionSchema = optionSchema?.type ? optionSchema : ({ ...optionSchema, type: option?.type || baseType } as S);
146
+ const Widget = getWidget<T, S, F>(optionSchema!, widget, widgets);
147
+
148
+ // The following code was copied from `@rjsf`'s `SchemaField`
149
+ // Set hideError to the value provided in the uiSchema, otherwise stick with the prop to propagate to children
150
+ const hideFieldError = uiSchemaHideError === undefined ? hideError : Boolean(uiSchemaHideError);
151
+
152
+ const rawErrors = get(errorSchema, [ERRORS_KEY], []) as string[];
153
+ const fieldErrorSchema = omit(errorSchema, [ERRORS_KEY]);
154
+ const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions);
155
+
156
+ /** Callback function that updates the selected option and adjusts the form data based on the structure of the new
157
+ * option, calling the `onChange` callback with the adjusted formData.
158
+ *
159
+ * @param opt - If the option is undefined, we are going to clear the selection otherwise we
160
+ * will use it as the index of the new option to select
161
+ */
162
+ const onOptionChange = (opt?: unknown) => {
163
+ const newOption = getSelectedOption<S>(enumOptions, selectorField, opt);
164
+ const oldOption = getSelectedOption<S>(enumOptions, selectorField, selectedOption);
165
+
166
+ let newFormData = schemaUtils.sanitizeDataForNewSchema(newOption, oldOption, formData);
167
+ if (newFormData && newOption) {
168
+ // Call getDefaultFormState to make sure defaults are populated on change.
169
+ newFormData = schemaUtils.getDefaultFormState(newOption, newFormData, 'excludeObjectChildren') as T;
170
+ }
171
+ if (newFormData) {
172
+ set(newFormData, selectorField, opt);
173
+ }
174
+ onChange(newFormData, undefined, id);
175
+ };
176
+
177
+ // filtering the options based on the type of widget because `selectField` does not recognize the `convertOther` prop
178
+ const widgetOptions = { enumOptions, ...uiOptions };
179
+ const errors =
180
+ !hideFieldError && rawErrors.length > 0 ? (
181
+ <FieldErrorTemplate idSchema={idSchema} schema={schema} errors={rawErrors} registry={registry} />
182
+ ) : undefined;
183
+ const ignored = (value: string) => noop;
184
+
185
+ return (
186
+ <FieldTemplate
187
+ id={id}
188
+ schema={schema}
189
+ label={(title || schema.title) ?? ''}
190
+ disabled={disabled || (Array.isArray(enumOptions) && isEmpty(enumOptions))}
191
+ uiSchema={uiSchema}
192
+ formContext={formContext}
193
+ required={required}
194
+ readonly={!!readonly}
195
+ registry={registry}
196
+ displayLabel={displayLabel}
197
+ errors={errors}
198
+ onChange={onChange}
199
+ onDropPropertyClick={ignored}
200
+ onKeyChange={ignored}
201
+ >
202
+ <Widget
203
+ id={id}
204
+ name={name}
205
+ schema={schema}
206
+ label={(title || schema.title) ?? ''}
207
+ disabled={disabled || (Array.isArray(enumOptions) && isEmpty(enumOptions))}
208
+ uiSchema={uiSchema}
209
+ formContext={formContext}
210
+ autofocus={autofocus}
211
+ readonly={readonly}
212
+ required={required}
213
+ registry={registry}
214
+ multiple={false}
215
+ rawErrors={rawErrors}
216
+ hideError={hideFieldError}
217
+ hideLabel={!displayLabel}
218
+ errorSchema={fieldErrorSchema}
219
+ placeholder={placeholder}
220
+ onChange={onOptionChange}
221
+ onBlur={onBlur}
222
+ onFocus={onFocus}
223
+ value={selectedOption}
224
+ options={widgetOptions}
225
+ />
226
+ </FieldTemplate>
227
+ );
228
+ }
@@ -7,7 +7,7 @@ import { FieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf
7
7
  * @param props - The `FieldProps` for this template
8
8
  */
9
9
  function NullField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
10
- props: FieldProps<T, S, F>
10
+ props: FieldProps<T, S, F>,
11
11
  ) {
12
12
  const { formData, onChange } = props;
13
13
  useEffect(() => {
@@ -31,7 +31,7 @@ const trailingCharMatcher = /[0.]0*$/;
31
31
  * value is passed to the input instead of the formData value
32
32
  */
33
33
  function NumberField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
34
- props: FieldProps<T, S, F>
34
+ props: FieldProps<T, S, F>,
35
35
  ) {
36
36
  const { registry, onChange, formData, value: initialValue } = props;
37
37
  const [lastValue, setLastValue] = useState(initialValue);
@@ -64,7 +64,7 @@ function NumberField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
64
64
 
65
65
  onChange(processed as unknown as T, errorSchema, id);
66
66
  },
67
- [onChange]
67
+ [onChange],
68
68
  );
69
69
 
70
70
  if (typeof lastValue === 'string' && typeof value === 'number') {
@@ -86,7 +86,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
86
86
  ...errorSchema,
87
87
  [name]: newErrorSchema,
88
88
  },
89
- id
89
+ id,
90
90
  );
91
91
  };
92
92
  };
@@ -158,7 +158,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
158
158
  errorSchema && {
159
159
  ...errorSchema,
160
160
  [value]: newErrorSchema,
161
- }
161
+ },
162
162
  );
163
163
  };
164
164
  };
@@ -195,36 +195,40 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
195
195
  * @param schema - The schema element to which the new property is being added
196
196
  */
197
197
  handleAddClick = (schema: S) => () => {
198
- if (!schema.additionalProperties) {
198
+ if (!(schema.additionalProperties || schema.patternProperties)) {
199
199
  return;
200
200
  }
201
201
  const { formData, onChange, registry } = this.props;
202
202
  const newFormData = { ...formData } as T;
203
-
204
- let type: RJSFSchema['type'] = undefined;
205
- let constValue: RJSFSchema['const'] = undefined;
206
- let defaultValue: RJSFSchema['default'] = undefined;
207
- if (isObject(schema.additionalProperties)) {
208
- type = schema.additionalProperties.type;
209
- constValue = schema.additionalProperties.const;
210
- defaultValue = schema.additionalProperties.default;
211
- let apSchema = schema.additionalProperties;
212
- if (REF_KEY in apSchema) {
213
- const { schemaUtils } = registry;
214
- apSchema = schemaUtils.retrieveSchema({ $ref: apSchema[REF_KEY] } as S, formData);
215
- type = apSchema.type;
216
- constValue = apSchema.const;
217
- defaultValue = apSchema.default;
218
- }
219
- if (!type && (ANY_OF_KEY in apSchema || ONE_OF_KEY in apSchema)) {
220
- type = 'object';
203
+ const newKey = this.getAvailableKey('newKey', newFormData);
204
+ if (schema.patternProperties) {
205
+ // Cast this to make the `set` work properly
206
+ set(newFormData as GenericObjectType, newKey, null);
207
+ } else {
208
+ let type: RJSFSchema['type'] = undefined;
209
+ let constValue: RJSFSchema['const'] = undefined;
210
+ let defaultValue: RJSFSchema['default'] = undefined;
211
+ if (isObject(schema.additionalProperties)) {
212
+ type = schema.additionalProperties.type;
213
+ constValue = schema.additionalProperties.const;
214
+ defaultValue = schema.additionalProperties.default;
215
+ let apSchema = schema.additionalProperties;
216
+ if (REF_KEY in apSchema) {
217
+ const { schemaUtils } = registry;
218
+ apSchema = schemaUtils.retrieveSchema({ $ref: apSchema[REF_KEY] } as S, formData);
219
+ type = apSchema.type;
220
+ constValue = apSchema.const;
221
+ defaultValue = apSchema.default;
222
+ }
223
+ if (!type && (ANY_OF_KEY in apSchema || ONE_OF_KEY in apSchema)) {
224
+ type = 'object';
225
+ }
221
226
  }
222
- }
223
227
 
224
- const newKey = this.getAvailableKey('newKey', newFormData);
225
- const newValue = constValue ?? defaultValue ?? this.getDefaultValue(type);
226
- // Cast this to make the `set` work properly
227
- set(newFormData as GenericObjectType, newKey, newValue);
228
+ const newValue = constValue ?? defaultValue ?? this.getDefaultValue(type);
229
+ // Cast this to make the `set` work properly
230
+ set(newFormData as GenericObjectType, newKey, newValue);
231
+ }
228
232
 
229
233
  onChange(newFormData);
230
234
  };
@@ -266,7 +270,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
266
270
  } catch (err) {
267
271
  return (
268
272
  <div>
269
- <p className='config-error' style={{ color: 'red' }}>
273
+ <p className='rjsf-config-error' style={{ color: 'red' }}>
270
274
  <Markdown options={{ disableParsingRawHTML: true }}>
271
275
  {translateString(TranslatableString.InvalidObjectField, [name || 'root', (err as Error).message])}
272
276
  </Markdown>
@@ -294,7 +298,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
294
298
  key={name}
295
299
  name={name}
296
300
  required={this.isRequired(name)}
297
- schema={get(schema, [PROPERTIES_KEY, name], {})}
301
+ schema={get(schema, [PROPERTIES_KEY, name], {}) as S}
298
302
  uiSchema={fieldUiSchema}
299
303
  errorSchema={get(errorSchema, name)}
300
304
  idSchema={fieldIdSchema}
@@ -1,4 +1,4 @@
1
- import { useCallback, Component } from 'react';
1
+ import { useCallback, Component, ComponentType } from 'react';
2
2
  import {
3
3
  ADDITIONAL_PROPERTY_FLAG,
4
4
  deepEquals,
@@ -49,15 +49,15 @@ function getFieldComponent<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
49
49
  schema: S,
50
50
  uiOptions: UIOptionsType<T, S, F>,
51
51
  idSchema: IdSchema<T>,
52
- registry: Registry<T, S, F>
53
- ) {
52
+ registry: Registry<T, S, F>,
53
+ ): ComponentType<FieldProps<T, S, F>> {
54
54
  const field = uiOptions.field;
55
55
  const { fields, translateString } = registry;
56
56
  if (typeof field === 'function') {
57
57
  return field;
58
58
  }
59
59
  if (typeof field === 'string' && field in fields) {
60
- return fields[field];
60
+ return fields[field] as ComponentType<FieldProps<T, S, F>>;
61
61
  }
62
62
 
63
63
  const schemaType = getSchemaType(schema);
@@ -82,7 +82,7 @@ function getFieldComponent<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
82
82
  const UnsupportedFieldTemplate = getTemplate<'UnsupportedFieldTemplate', T, S, F>(
83
83
  'UnsupportedFieldTemplate',
84
84
  registry,
85
- uiOptions
85
+ uiOptions,
86
86
  );
87
87
 
88
88
  return (
@@ -103,7 +103,7 @@ function getFieldComponent<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
103
103
  * @param props - The `FieldProps` for this component
104
104
  */
105
105
  function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
106
- props: FieldProps<T, S, F>
106
+ props: FieldProps<T, S, F>,
107
107
  ) {
108
108
  const {
109
109
  schema: _schema,
@@ -127,7 +127,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
127
127
  const DescriptionFieldTemplate = getTemplate<'DescriptionFieldTemplate', T, S, F>(
128
128
  'DescriptionFieldTemplate',
129
129
  registry,
130
- uiOptions
130
+ uiOptions,
131
131
  );
132
132
  const FieldHelpTemplate = getTemplate<'FieldHelpTemplate', T, S, F>('FieldHelpTemplate', registry, uiOptions);
133
133
  const FieldErrorTemplate = getTemplate<'FieldErrorTemplate', T, S, F>('FieldErrorTemplate', registry, uiOptions);
@@ -135,7 +135,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
135
135
  const fieldId = _idSchema[ID_KEY];
136
136
  const idSchema = mergeObjects(
137
137
  schemaUtils.toIdSchema(schema, fieldId, formData, idPrefix, idSeparator),
138
- _idSchema
138
+ _idSchema,
139
139
  ) as IdSchema<T>;
140
140
 
141
141
  /** Intermediary `onChange` handler for field components that will inject the `id` of the current field into the
@@ -146,7 +146,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
146
146
  const theId = id || fieldId;
147
147
  return onChange(formData, newErrorSchema, theId);
148
148
  },
149
- [fieldId, onChange]
149
+ [fieldId, onChange],
150
150
  );
151
151
 
152
152
  const FieldComponent = getFieldComponent<T, S, F>(schema, uiOptions, idSchema, registry);
@@ -180,7 +180,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
180
180
  readonly={readonly}
181
181
  hideError={hideError}
182
182
  autofocus={autofocus}
183
- errorSchema={fieldErrorSchema}
183
+ errorSchema={fieldErrorSchema as ErrorSchema}
184
184
  formContext={formContext}
185
185
  rawErrors={__errors}
186
186
  />
@@ -209,17 +209,9 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
209
209
  const help = uiOptions.help;
210
210
  const hidden = uiOptions.widget === 'hidden';
211
211
 
212
- const classNames = ['form-group', 'field', `field-${getSchemaType(schema)}`];
212
+ const classNames = ['rjsf-field', `rjsf-field-${getSchemaType(schema)}`];
213
213
  if (!hideError && __errors && __errors.length > 0) {
214
- classNames.push('field-error has-error has-danger');
215
- }
216
- if (uiSchema?.classNames) {
217
- if (process.env.NODE_ENV !== 'production') {
218
- console.warn(
219
- "'uiSchema.classNames' is deprecated and may be removed in a major release; Use 'ui:classNames' instead."
220
- );
221
- }
222
- classNames.push(uiSchema.classNames);
214
+ classNames.push('rjsf-field-error');
223
215
  }
224
216
  if (uiOptions.classNames) {
225
217
  classNames.push(uiOptions.classNames);
@@ -314,7 +306,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
314
306
  onChange={props.onChange}
315
307
  onFocus={props.onFocus}
316
308
  options={schema.anyOf.map((_schema) =>
317
- schemaUtils.retrieveSchema(isObject(_schema) ? (_schema as S) : ({} as S), formData)
309
+ schemaUtils.retrieveSchema(isObject(_schema) ? (_schema as S) : ({} as S), formData),
318
310
  )}
319
311
  registry={registry}
320
312
  required={required}
@@ -338,7 +330,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
338
330
  onChange={props.onChange}
339
331
  onFocus={props.onFocus}
340
332
  options={schema.oneOf.map((_schema) =>
341
- schemaUtils.retrieveSchema(isObject(_schema) ? (_schema as S) : ({} as S), formData)
333
+ schemaUtils.retrieveSchema(isObject(_schema) ? (_schema as S) : ({} as S), formData),
342
334
  )}
343
335
  registry={registry}
344
336
  required={required}
@@ -14,7 +14,7 @@ import {
14
14
  * @param props - The `FieldProps` for this template
15
15
  */
16
16
  function StringField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
17
- props: FieldProps<T, S, F>
17
+ props: FieldProps<T, S, F>,
18
18
  ) {
19
19
  const {
20
20
  schema,
@@ -35,7 +35,7 @@ function StringField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
35
35
  } = props;
36
36
  const { title, format } = schema;
37
37
  const { widgets, formContext, schemaUtils, globalUiOptions } = registry;
38
- const enumOptions = schemaUtils.isSelect(schema) ? optionsList<S, T, F>(schema, uiSchema) : undefined;
38
+ const enumOptions = schemaUtils.isSelect(schema) ? optionsList<T, S, F>(schema, uiSchema) : undefined;
39
39
  let defaultWidget = enumOptions ? 'select' : 'text';
40
40
  if (format && hasWidget<T, S, F>(schema, format, widgets)) {
41
41
  defaultWidget = format;
@@ -2,6 +2,9 @@ import { Field, FormContextType, RegistryFieldsType, RJSFSchema, StrictRJSFSchem
2
2
 
3
3
  import ArrayField from './ArrayField';
4
4
  import BooleanField from './BooleanField';
5
+ import LayoutGridField from './LayoutGridField';
6
+ import LayoutHeaderField from './LayoutHeaderField';
7
+ import LayoutMultiSchemaField from './LayoutMultiSchemaField';
5
8
  import MultiSchemaField from './MultiSchemaField';
6
9
  import NumberField from './NumberField';
7
10
  import ObjectField from './ObjectField';
@@ -12,13 +15,16 @@ import NullField from './NullField';
12
15
  function fields<
13
16
  T = any,
14
17
  S extends StrictRJSFSchema = RJSFSchema,
15
- F extends FormContextType = any
18
+ F extends FormContextType = any,
16
19
  >(): RegistryFieldsType<T, S, F> {
17
20
  return {
18
21
  AnyOfField: MultiSchemaField,
19
22
  ArrayField: ArrayField as unknown as Field<T, S, F>,
20
23
  // ArrayField falls back to SchemaField if ArraySchemaField is not defined, which it isn't by default
21
24
  BooleanField,
25
+ LayoutGridField,
26
+ LayoutHeaderField,
27
+ LayoutMultiSchemaField,
22
28
  NumberField,
23
29
  ObjectField,
24
30
  OneOfField: MultiSchemaField,
@@ -16,7 +16,7 @@ import {
16
16
  export default function ArrayFieldDescriptionTemplate<
17
17
  T = any,
18
18
  S extends StrictRJSFSchema = RJSFSchema,
19
- F extends FormContextType = any
19
+ F extends FormContextType = any,
20
20
  >(props: ArrayFieldDescriptionProps<T, S, F>) {
21
21
  const { idSchema, description, registry, schema, uiSchema } = props;
22
22
  const options = getUiOptions<T, S, F>(uiSchema, registry.globalUiOptions);
@@ -27,7 +27,7 @@ export default function ArrayFieldDescriptionTemplate<
27
27
  const DescriptionFieldTemplate = getTemplate<'DescriptionFieldTemplate', T, S, F>(
28
28
  'DescriptionFieldTemplate',
29
29
  registry,
30
- options
30
+ options,
31
31
  );
32
32
  return (
33
33
  <DescriptionFieldTemplate
@@ -0,0 +1,85 @@
1
+ import { useMemo } from 'react';
2
+ import {
3
+ ArrayFieldItemButtonsTemplateType,
4
+ buttonId,
5
+ FormContextType,
6
+ RJSFSchema,
7
+ StrictRJSFSchema,
8
+ } from '@rjsf/utils';
9
+
10
+ /** The `ArrayFieldTemplateItemButtons` component is the template used to render the buttons associate3d with items of
11
+ * an array.
12
+ *
13
+ * @param props - The `ArrayFieldItemButtonsTemplateType` props for the component
14
+ */
15
+ export default function ArrayFieldItemButtonsTemplate<
16
+ T = any,
17
+ S extends StrictRJSFSchema = RJSFSchema,
18
+ F extends FormContextType = any,
19
+ >(props: ArrayFieldItemButtonsTemplateType<T, S, F>) {
20
+ const {
21
+ disabled,
22
+ hasCopy,
23
+ hasMoveDown,
24
+ hasMoveUp,
25
+ hasRemove,
26
+ idSchema,
27
+ index,
28
+ onCopyIndexClick,
29
+ onDropIndexClick,
30
+ onReorderClick,
31
+ readonly,
32
+ registry,
33
+ uiSchema,
34
+ } = props;
35
+ 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
+
41
+ return (
42
+ <>
43
+ {(hasMoveUp || hasMoveDown) && (
44
+ <MoveUpButton
45
+ id={buttonId<T>(idSchema, 'moveUp')}
46
+ className='rjsf-array-item-move-up'
47
+ disabled={disabled || readonly || !hasMoveUp}
48
+ onClick={onArrowUpClick}
49
+ uiSchema={uiSchema}
50
+ registry={registry}
51
+ />
52
+ )}
53
+ {(hasMoveUp || hasMoveDown) && (
54
+ <MoveDownButton
55
+ id={buttonId<T>(idSchema, 'moveDown')}
56
+ className='rjsf-array-item-move-down'
57
+ disabled={disabled || readonly || !hasMoveDown}
58
+ onClick={onArrowDownClick}
59
+ uiSchema={uiSchema}
60
+ registry={registry}
61
+ />
62
+ )}
63
+ {hasCopy && (
64
+ <CopyButton
65
+ id={buttonId<T>(idSchema, 'copy')}
66
+ className='rjsf-array-item-copy'
67
+ disabled={disabled || readonly}
68
+ onClick={onCopyClick}
69
+ uiSchema={uiSchema}
70
+ registry={registry}
71
+ />
72
+ )}
73
+ {hasRemove && (
74
+ <RemoveButton
75
+ id={buttonId<T>(idSchema, 'remove')}
76
+ className='rjsf-array-item-remove'
77
+ disabled={disabled || readonly}
78
+ onClick={onRemoveClick}
79
+ uiSchema={uiSchema}
80
+ registry={registry}
81
+ />
82
+ )}
83
+ </>
84
+ );
85
+ }