@rjsf/core 6.0.0-beta.2 → 6.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.umd.js +705 -471
- package/dist/{index.js → index.cjs} +1094 -844
- package/dist/index.cjs.map +7 -0
- package/dist/index.esm.js +1053 -774
- package/dist/index.esm.js.map +4 -4
- package/lib/components/Form.d.ts +88 -23
- package/lib/components/Form.d.ts.map +1 -1
- package/lib/components/Form.js +213 -151
- package/lib/components/fields/ArrayField.d.ts +17 -7
- package/lib/components/fields/ArrayField.d.ts.map +1 -1
- package/lib/components/fields/ArrayField.js +116 -70
- package/lib/components/fields/BooleanField.d.ts.map +1 -1
- package/lib/components/fields/BooleanField.js +7 -2
- package/lib/components/fields/LayoutGridField.d.ts +27 -25
- package/lib/components/fields/LayoutGridField.d.ts.map +1 -1
- package/lib/components/fields/LayoutGridField.js +83 -59
- package/lib/components/fields/LayoutHeaderField.d.ts +1 -1
- package/lib/components/fields/LayoutHeaderField.js +3 -3
- package/lib/components/fields/LayoutMultiSchemaField.js +6 -5
- package/lib/components/fields/MultiSchemaField.d.ts.map +1 -1
- package/lib/components/fields/MultiSchemaField.js +13 -9
- package/lib/components/fields/NullField.js +3 -3
- package/lib/components/fields/NumberField.d.ts.map +1 -1
- package/lib/components/fields/NumberField.js +3 -3
- package/lib/components/fields/ObjectField.d.ts +3 -3
- package/lib/components/fields/ObjectField.d.ts.map +1 -1
- package/lib/components/fields/ObjectField.js +34 -34
- package/lib/components/fields/OptionalDataControlsField.d.ts +8 -0
- package/lib/components/fields/OptionalDataControlsField.d.ts.map +1 -0
- package/lib/components/fields/OptionalDataControlsField.js +43 -0
- package/lib/components/fields/SchemaField.d.ts.map +1 -1
- package/lib/components/fields/SchemaField.js +17 -17
- package/lib/components/fields/StringField.d.ts.map +1 -1
- package/lib/components/fields/StringField.js +7 -2
- package/lib/components/fields/index.d.ts.map +1 -1
- package/lib/components/fields/index.js +2 -0
- package/lib/components/templates/ArrayFieldDescriptionTemplate.d.ts +1 -1
- package/lib/components/templates/ArrayFieldDescriptionTemplate.js +3 -3
- package/lib/components/templates/ArrayFieldItemButtonsTemplate.js +2 -2
- package/lib/components/templates/ArrayFieldTemplate.d.ts.map +1 -1
- package/lib/components/templates/ArrayFieldTemplate.js +4 -3
- package/lib/components/templates/ArrayFieldTitleTemplate.d.ts +1 -1
- package/lib/components/templates/ArrayFieldTitleTemplate.d.ts.map +1 -1
- package/lib/components/templates/ArrayFieldTitleTemplate.js +3 -3
- package/lib/components/templates/ButtonTemplates/AddButton.d.ts +1 -1
- package/lib/components/templates/ButtonTemplates/AddButton.d.ts.map +1 -1
- package/lib/components/templates/ButtonTemplates/AddButton.js +2 -2
- package/lib/components/templates/FieldErrorTemplate.js +2 -2
- package/lib/components/templates/FieldHelpTemplate.js +2 -2
- package/lib/components/templates/MultiSchemaFieldTemplate.d.ts +8 -0
- package/lib/components/templates/MultiSchemaFieldTemplate.d.ts.map +1 -0
- package/lib/components/templates/MultiSchemaFieldTemplate.js +10 -0
- package/lib/components/templates/ObjectFieldTemplate.d.ts.map +1 -1
- package/lib/components/templates/ObjectFieldTemplate.js +3 -2
- package/lib/components/templates/OptionalDataControlsTemplate.d.ts +11 -0
- package/lib/components/templates/OptionalDataControlsTemplate.d.ts.map +1 -0
- package/lib/components/templates/OptionalDataControlsTemplate.js +20 -0
- package/lib/components/templates/TitleField.d.ts.map +1 -1
- package/lib/components/templates/TitleField.js +2 -2
- package/lib/components/templates/UnsupportedField.js +3 -3
- package/lib/components/templates/index.d.ts.map +1 -1
- package/lib/components/templates/index.js +4 -0
- package/lib/components/widgets/AltDateWidget.d.ts.map +1 -1
- package/lib/components/widgets/AltDateWidget.js +15 -18
- package/lib/components/widgets/CheckboxesWidget.js +2 -2
- package/lib/getDefaultRegistry.d.ts.map +1 -1
- package/lib/getDefaultRegistry.js +2 -1
- package/lib/getTestRegistry.d.ts +5 -0
- package/lib/getTestRegistry.d.ts.map +1 -0
- package/lib/getTestRegistry.js +19 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +18 -19
- package/src/components/Form.tsx +306 -177
- package/src/components/fields/ArrayField.tsx +127 -80
- package/src/components/fields/BooleanField.tsx +12 -3
- package/src/components/fields/LayoutGridField.tsx +95 -88
- package/src/components/fields/LayoutHeaderField.tsx +3 -3
- package/src/components/fields/LayoutMultiSchemaField.tsx +5 -5
- package/src/components/fields/MultiSchemaField.tsx +51 -35
- package/src/components/fields/NullField.tsx +3 -3
- package/src/components/fields/NumberField.tsx +11 -3
- package/src/components/fields/ObjectField.tsx +47 -53
- package/src/components/fields/OptionalDataControlsField.tsx +84 -0
- package/src/components/fields/SchemaField.tsx +24 -30
- package/src/components/fields/StringField.tsx +12 -3
- package/src/components/fields/index.ts +2 -0
- package/src/components/templates/ArrayFieldDescriptionTemplate.tsx +3 -3
- package/src/components/templates/ArrayFieldItemButtonsTemplate.tsx +5 -5
- package/src/components/templates/ArrayFieldTemplate.tsx +9 -5
- package/src/components/templates/ArrayFieldTitleTemplate.tsx +4 -3
- package/src/components/templates/BaseInputTemplate.tsx +3 -3
- package/src/components/templates/ButtonTemplates/AddButton.tsx +2 -0
- package/src/components/templates/FieldErrorTemplate.tsx +2 -2
- package/src/components/templates/FieldHelpTemplate.tsx +2 -2
- package/src/components/templates/MultiSchemaFieldTemplate.tsx +20 -0
- package/src/components/templates/ObjectFieldTemplate.tsx +10 -5
- package/src/components/templates/OptionalDataControlsTemplate.tsx +43 -0
- package/src/components/templates/TitleField.tsx +6 -1
- package/src/components/templates/UnsupportedField.tsx +3 -3
- package/src/components/templates/WrapIfAdditionalTemplate.tsx +1 -1
- package/src/components/templates/index.ts +4 -0
- package/src/components/widgets/AltDateWidget.tsx +21 -23
- package/src/components/widgets/CheckboxWidget.tsx +2 -2
- package/src/components/widgets/CheckboxesWidget.tsx +3 -3
- package/src/components/widgets/RadioWidget.tsx +1 -1
- package/src/components/widgets/SelectWidget.tsx +1 -1
- package/src/components/widgets/TextareaWidget.tsx +1 -1
- package/src/getDefaultRegistry.ts +10 -1
- package/src/getTestRegistry.tsx +34 -0
- package/src/index.ts +2 -1
- package/dist/index.js.map +0 -7
|
@@ -3,11 +3,13 @@ import {
|
|
|
3
3
|
getTemplate,
|
|
4
4
|
getUiOptions,
|
|
5
5
|
orderProperties,
|
|
6
|
+
shouldRenderOptionalField,
|
|
7
|
+
toFieldPathId,
|
|
6
8
|
ErrorSchema,
|
|
9
|
+
FieldPathList,
|
|
7
10
|
FieldProps,
|
|
8
11
|
FormContextType,
|
|
9
12
|
GenericObjectType,
|
|
10
|
-
IdSchema,
|
|
11
13
|
RJSFSchema,
|
|
12
14
|
StrictRJSFSchema,
|
|
13
15
|
TranslatableString,
|
|
@@ -16,6 +18,7 @@ import {
|
|
|
16
18
|
REF_KEY,
|
|
17
19
|
ANY_OF_KEY,
|
|
18
20
|
ONE_OF_KEY,
|
|
21
|
+
isFormDataAvailable,
|
|
19
22
|
} from '@rjsf/utils';
|
|
20
23
|
import Markdown from 'markdown-to-jsx';
|
|
21
24
|
import get from 'lodash/get';
|
|
@@ -66,8 +69,8 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
66
69
|
* @returns - The onPropertyChange callback for the `name` property
|
|
67
70
|
*/
|
|
68
71
|
onPropertyChange = (name: string, addedByAdditionalProperties = false) => {
|
|
69
|
-
return (value: T | undefined, newErrorSchema?: ErrorSchema<T>, id?: string) => {
|
|
70
|
-
const {
|
|
72
|
+
return (value: T | undefined, path: FieldPathList, newErrorSchema?: ErrorSchema<T>, id?: string) => {
|
|
73
|
+
const { onChange } = this.props;
|
|
71
74
|
if (value === undefined && addedByAdditionalProperties) {
|
|
72
75
|
// Don't set value = undefined for fields added by
|
|
73
76
|
// additionalProperties. Doing so removes them from the
|
|
@@ -78,16 +81,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
78
81
|
// set empty values to the empty string.
|
|
79
82
|
value = '' as unknown as T;
|
|
80
83
|
}
|
|
81
|
-
|
|
82
|
-
onChange(
|
|
83
|
-
newFormData,
|
|
84
|
-
errorSchema &&
|
|
85
|
-
errorSchema && {
|
|
86
|
-
...errorSchema,
|
|
87
|
-
[name]: newErrorSchema,
|
|
88
|
-
},
|
|
89
|
-
id,
|
|
90
|
-
);
|
|
84
|
+
onChange(value, path, newErrorSchema, id);
|
|
91
85
|
};
|
|
92
86
|
};
|
|
93
87
|
|
|
@@ -100,10 +94,11 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
100
94
|
onDropPropertyClick = (key: string) => {
|
|
101
95
|
return (event: DragEvent) => {
|
|
102
96
|
event.preventDefault();
|
|
103
|
-
const { onChange, formData } = this.props;
|
|
97
|
+
const { onChange, formData, fieldPathId } = this.props;
|
|
104
98
|
const copiedFormData = { ...formData } as T;
|
|
105
99
|
unset(copiedFormData, key);
|
|
106
|
-
|
|
100
|
+
// drop property will pass the name in `path` array
|
|
101
|
+
onChange(copiedFormData, fieldPathId.path);
|
|
107
102
|
};
|
|
108
103
|
};
|
|
109
104
|
|
|
@@ -133,11 +128,11 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
133
128
|
* @returns - The key change callback function
|
|
134
129
|
*/
|
|
135
130
|
onKeyChange = (oldValue: any) => {
|
|
136
|
-
return (value: any
|
|
131
|
+
return (value: any) => {
|
|
137
132
|
if (oldValue === value) {
|
|
138
133
|
return;
|
|
139
134
|
}
|
|
140
|
-
const { formData, onChange,
|
|
135
|
+
const { formData, onChange, fieldPathId } = this.props;
|
|
141
136
|
|
|
142
137
|
value = this.getAvailableKey(value, formData);
|
|
143
138
|
const newFormData: GenericObjectType = {
|
|
@@ -152,14 +147,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
152
147
|
|
|
153
148
|
this.setState({ wasPropertyKeyModified: true });
|
|
154
149
|
|
|
155
|
-
onChange(
|
|
156
|
-
renamedObj,
|
|
157
|
-
errorSchema &&
|
|
158
|
-
errorSchema && {
|
|
159
|
-
...errorSchema,
|
|
160
|
-
[value]: newErrorSchema,
|
|
161
|
-
},
|
|
162
|
-
);
|
|
150
|
+
onChange(renamedObj, fieldPathId.path);
|
|
163
151
|
};
|
|
164
152
|
};
|
|
165
153
|
|
|
@@ -198,7 +186,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
198
186
|
if (!(schema.additionalProperties || schema.patternProperties)) {
|
|
199
187
|
return;
|
|
200
188
|
}
|
|
201
|
-
const { formData, onChange, registry } = this.props;
|
|
189
|
+
const { formData, onChange, registry, fieldPathId } = this.props;
|
|
202
190
|
const newFormData = { ...formData } as T;
|
|
203
191
|
const newKey = this.getAvailableKey('newKey', newFormData);
|
|
204
192
|
if (schema.patternProperties) {
|
|
@@ -230,7 +218,8 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
230
218
|
set(newFormData as GenericObjectType, newKey, newValue);
|
|
231
219
|
}
|
|
232
220
|
|
|
233
|
-
|
|
221
|
+
// add will pass the name in `path` array
|
|
222
|
+
onChange(newFormData, fieldPathId.path);
|
|
234
223
|
};
|
|
235
224
|
|
|
236
225
|
/** Renders the `ObjectField` from the given props
|
|
@@ -241,46 +230,51 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
241
230
|
uiSchema = {},
|
|
242
231
|
formData,
|
|
243
232
|
errorSchema,
|
|
244
|
-
|
|
233
|
+
fieldPathId,
|
|
245
234
|
name,
|
|
246
235
|
required = false,
|
|
247
236
|
disabled,
|
|
248
237
|
readonly,
|
|
249
238
|
hideError,
|
|
250
|
-
idPrefix,
|
|
251
|
-
idSeparator,
|
|
252
239
|
onBlur,
|
|
253
240
|
onFocus,
|
|
254
241
|
registry,
|
|
255
242
|
title,
|
|
256
243
|
} = this.props;
|
|
257
244
|
|
|
258
|
-
const { fields, formContext, schemaUtils, translateString, globalUiOptions } = registry;
|
|
259
|
-
const { SchemaField } = fields;
|
|
260
|
-
const schema: S = schemaUtils.retrieveSchema(rawSchema, formData);
|
|
245
|
+
const { fields, formContext, schemaUtils, translateString, globalFormOptions, globalUiOptions } = registry;
|
|
246
|
+
const { OptionalDataControlsField, SchemaField } = fields;
|
|
247
|
+
const schema: S = schemaUtils.retrieveSchema(rawSchema, formData, true);
|
|
261
248
|
const uiOptions = getUiOptions<T, S, F>(uiSchema, globalUiOptions);
|
|
262
249
|
const { properties: schemaProperties = {} } = schema;
|
|
263
250
|
|
|
264
251
|
const templateTitle = uiOptions.title ?? schema.title ?? title ?? name;
|
|
265
252
|
const description = uiOptions.description ?? schema.description;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
253
|
+
const renderOptionalField = shouldRenderOptionalField(registry, schema, required, uiSchema);
|
|
254
|
+
const hasFormData = isFormDataAvailable(formData);
|
|
255
|
+
let orderedProperties: string[] = [];
|
|
256
|
+
if (!renderOptionalField || hasFormData) {
|
|
257
|
+
try {
|
|
258
|
+
const properties = Object.keys(schemaProperties);
|
|
259
|
+
orderedProperties = orderProperties(properties, uiOptions.order);
|
|
260
|
+
} catch (err) {
|
|
261
|
+
return (
|
|
262
|
+
<div>
|
|
263
|
+
<p className='rjsf-config-error' style={{ color: 'red' }}>
|
|
264
|
+
<Markdown options={{ disableParsingRawHTML: true }}>
|
|
265
|
+
{translateString(TranslatableString.InvalidObjectField, [name || 'root', (err as Error).message])}
|
|
266
|
+
</Markdown>
|
|
267
|
+
</p>
|
|
268
|
+
<pre>{JSON.stringify(schema)}</pre>
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
281
272
|
}
|
|
282
273
|
|
|
283
274
|
const Template = getTemplate<'ObjectFieldTemplate', T, S, F>('ObjectFieldTemplate', registry, uiOptions);
|
|
275
|
+
const optionalDataControl = renderOptionalField ? (
|
|
276
|
+
<OptionalDataControlsField {...this.props} schema={schema} />
|
|
277
|
+
) : undefined;
|
|
284
278
|
|
|
285
279
|
const templateProps = {
|
|
286
280
|
// getDisplayLabel() always returns false for object types, so just check the `uiOptions.label`
|
|
@@ -290,7 +284,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
290
284
|
const addedByAdditionalProperties = has(schema, [PROPERTIES_KEY, name, ADDITIONAL_PROPERTY_FLAG]);
|
|
291
285
|
const fieldUiSchema = addedByAdditionalProperties ? uiSchema.additionalProperties : uiSchema[name];
|
|
292
286
|
const hidden = getUiOptions<T, S, F>(fieldUiSchema).widget === 'hidden';
|
|
293
|
-
const
|
|
287
|
+
const innerFieldIdPathId = toFieldPathId(name, globalFormOptions, fieldPathId);
|
|
294
288
|
|
|
295
289
|
return {
|
|
296
290
|
content: (
|
|
@@ -301,9 +295,7 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
301
295
|
schema={get(schema, [PROPERTIES_KEY, name], {}) as S}
|
|
302
296
|
uiSchema={fieldUiSchema}
|
|
303
297
|
errorSchema={get(errorSchema, name)}
|
|
304
|
-
|
|
305
|
-
idPrefix={idPrefix}
|
|
306
|
-
idSeparator={idSeparator}
|
|
298
|
+
fieldPathId={innerFieldIdPathId}
|
|
307
299
|
formData={get(formData, name)}
|
|
308
300
|
formContext={formContext}
|
|
309
301
|
wasPropertyKeyModified={this.state.wasPropertyKeyModified}
|
|
@@ -328,13 +320,15 @@ class ObjectField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
328
320
|
readonly,
|
|
329
321
|
disabled,
|
|
330
322
|
required,
|
|
331
|
-
|
|
323
|
+
fieldPathId,
|
|
332
324
|
uiSchema,
|
|
333
325
|
errorSchema,
|
|
334
326
|
schema,
|
|
335
327
|
formData,
|
|
336
328
|
formContext,
|
|
337
329
|
registry,
|
|
330
|
+
optionalDataControl,
|
|
331
|
+
className: renderOptionalField ? 'rjsf-optional-object-field' : undefined,
|
|
338
332
|
};
|
|
339
333
|
return <Template {...templateProps} onAddClick={this.handleAddClick} />;
|
|
340
334
|
}
|
|
@@ -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(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,10 @@
|
|
|
1
1
|
import { useCallback, Component, ComponentType } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
ADDITIONAL_PROPERTY_FLAG,
|
|
4
|
-
deepEquals,
|
|
5
4
|
descriptionId,
|
|
6
5
|
ErrorSchema,
|
|
6
|
+
FieldPathId,
|
|
7
|
+
FieldPathList,
|
|
7
8
|
FieldProps,
|
|
8
9
|
FieldTemplateProps,
|
|
9
10
|
FormContextType,
|
|
@@ -11,10 +12,9 @@ import {
|
|
|
11
12
|
getTemplate,
|
|
12
13
|
getUiOptions,
|
|
13
14
|
ID_KEY,
|
|
14
|
-
IdSchema,
|
|
15
|
-
mergeObjects,
|
|
16
15
|
Registry,
|
|
17
16
|
RJSFSchema,
|
|
17
|
+
shouldRender,
|
|
18
18
|
StrictRJSFSchema,
|
|
19
19
|
TranslatableString,
|
|
20
20
|
UI_OPTIONS_KEY,
|
|
@@ -40,14 +40,14 @@ const COMPONENT_TYPES: { [key: string]: string } = {
|
|
|
40
40
|
*
|
|
41
41
|
* @param schema - The schema from which to obtain the type
|
|
42
42
|
* @param uiOptions - The UI Options that may affect the component decision
|
|
43
|
-
* @param
|
|
43
|
+
* @param fieldPathId - The id that is passed to the `UnsupportedFieldTemplate`
|
|
44
44
|
* @param registry - The registry from which fields and templates are obtained
|
|
45
45
|
* @returns - The `Field` component that is used to render the actual field data
|
|
46
46
|
*/
|
|
47
47
|
function getFieldComponent<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
48
48
|
schema: S,
|
|
49
49
|
uiOptions: UIOptionsType<T, S, F>,
|
|
50
|
-
|
|
50
|
+
fieldPathId: FieldPathId,
|
|
51
51
|
registry: Registry<T, S, F>,
|
|
52
52
|
): ComponentType<FieldProps<T, S, F>> {
|
|
53
53
|
const field = uiOptions.field;
|
|
@@ -87,7 +87,7 @@ function getFieldComponent<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
87
87
|
return (
|
|
88
88
|
<UnsupportedFieldTemplate
|
|
89
89
|
schema={schema}
|
|
90
|
-
|
|
90
|
+
fieldPathId={fieldPathId}
|
|
91
91
|
reason={translateString(TranslatableString.UnknownFieldType, [String(schema.type)])}
|
|
92
92
|
registry={registry}
|
|
93
93
|
/>
|
|
@@ -106,12 +106,10 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
106
106
|
) {
|
|
107
107
|
const {
|
|
108
108
|
schema: _schema,
|
|
109
|
-
|
|
109
|
+
fieldPathId,
|
|
110
110
|
uiSchema,
|
|
111
111
|
formData,
|
|
112
112
|
errorSchema,
|
|
113
|
-
idPrefix,
|
|
114
|
-
idSeparator,
|
|
115
113
|
name,
|
|
116
114
|
onChange,
|
|
117
115
|
onKeyChange,
|
|
@@ -131,24 +129,20 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
131
129
|
const FieldHelpTemplate = getTemplate<'FieldHelpTemplate', T, S, F>('FieldHelpTemplate', registry, uiOptions);
|
|
132
130
|
const FieldErrorTemplate = getTemplate<'FieldErrorTemplate', T, S, F>('FieldErrorTemplate', registry, uiOptions);
|
|
133
131
|
const schema = schemaUtils.retrieveSchema(_schema, formData);
|
|
134
|
-
const fieldId =
|
|
135
|
-
const idSchema = mergeObjects(
|
|
136
|
-
schemaUtils.toIdSchema(schema, fieldId, formData, idPrefix, idSeparator),
|
|
137
|
-
_idSchema,
|
|
138
|
-
) as IdSchema<T>;
|
|
132
|
+
const fieldId = fieldPathId[ID_KEY];
|
|
139
133
|
|
|
140
134
|
/** Intermediary `onChange` handler for field components that will inject the `id` of the current field into the
|
|
141
135
|
* `onChange` chain if it is not already being provided from a deeper level in the hierarchy
|
|
142
136
|
*/
|
|
143
137
|
const handleFieldComponentChange = useCallback(
|
|
144
|
-
(formData: T | undefined, newErrorSchema?: ErrorSchema<T>, id?: string) => {
|
|
138
|
+
(formData: T | undefined, path: FieldPathList, newErrorSchema?: ErrorSchema<T>, id?: string) => {
|
|
145
139
|
const theId = id || fieldId;
|
|
146
|
-
return onChange(formData, newErrorSchema, theId);
|
|
140
|
+
return onChange(formData, path, newErrorSchema, theId);
|
|
147
141
|
},
|
|
148
142
|
[fieldId, onChange],
|
|
149
143
|
);
|
|
150
144
|
|
|
151
|
-
const FieldComponent = getFieldComponent<T, S, F>(schema, uiOptions,
|
|
145
|
+
const FieldComponent = getFieldComponent<T, S, F>(schema, uiOptions, fieldPathId, registry);
|
|
152
146
|
const disabled = Boolean(uiOptions.disabled ?? props.disabled);
|
|
153
147
|
const readonly = Boolean(uiOptions.readonly ?? (props.readonly || props.schema.readOnly || schema.readOnly));
|
|
154
148
|
const uiSchemaHideError = uiOptions.hideError;
|
|
@@ -172,7 +166,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
172
166
|
<FieldComponent
|
|
173
167
|
{...props}
|
|
174
168
|
onChange={handleFieldComponentChange}
|
|
175
|
-
|
|
169
|
+
fieldPathId={fieldPathId}
|
|
176
170
|
schema={schema}
|
|
177
171
|
uiSchema={fieldUiSchema}
|
|
178
172
|
disabled={disabled}
|
|
@@ -185,7 +179,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
185
179
|
/>
|
|
186
180
|
);
|
|
187
181
|
|
|
188
|
-
const id =
|
|
182
|
+
const id = fieldPathId[ID_KEY];
|
|
189
183
|
|
|
190
184
|
// If this schema has a title defined, but the user has set a new key/label, retain their input.
|
|
191
185
|
let label;
|
|
@@ -213,7 +207,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
213
207
|
const helpComponent = (
|
|
214
208
|
<FieldHelpTemplate
|
|
215
209
|
help={help}
|
|
216
|
-
|
|
210
|
+
fieldPathId={fieldPathId}
|
|
217
211
|
schema={schema}
|
|
218
212
|
uiSchema={uiSchema}
|
|
219
213
|
hasErrors={!hideError && __errors && __errors.length > 0}
|
|
@@ -229,7 +223,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
229
223
|
<FieldErrorTemplate
|
|
230
224
|
errors={__errors}
|
|
231
225
|
errorSchema={errorSchema}
|
|
232
|
-
|
|
226
|
+
fieldPathId={fieldPathId}
|
|
233
227
|
schema={schema}
|
|
234
228
|
uiSchema={uiSchema}
|
|
235
229
|
registry={registry}
|
|
@@ -238,7 +232,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
238
232
|
const fieldProps: Omit<FieldTemplateProps<T, S, F>, 'children'> = {
|
|
239
233
|
description: (
|
|
240
234
|
<DescriptionFieldTemplate
|
|
241
|
-
id={descriptionId
|
|
235
|
+
id={descriptionId(id)}
|
|
242
236
|
description={description}
|
|
243
237
|
schema={schema}
|
|
244
238
|
uiSchema={uiSchema}
|
|
@@ -263,7 +257,6 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
263
257
|
displayLabel,
|
|
264
258
|
classNames: classNames.join(' ').trim(),
|
|
265
259
|
style: uiOptions.style,
|
|
266
|
-
formContext,
|
|
267
260
|
formData,
|
|
268
261
|
schema,
|
|
269
262
|
uiSchema,
|
|
@@ -292,9 +285,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
292
285
|
errorSchema={errorSchema}
|
|
293
286
|
formData={formData}
|
|
294
287
|
formContext={formContext}
|
|
295
|
-
|
|
296
|
-
idSchema={idSchema}
|
|
297
|
-
idSeparator={idSeparator}
|
|
288
|
+
fieldPathId={fieldPathId}
|
|
298
289
|
onBlur={props.onBlur}
|
|
299
290
|
onChange={props.onChange}
|
|
300
291
|
onFocus={props.onFocus}
|
|
@@ -316,9 +307,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
|
|
|
316
307
|
errorSchema={errorSchema}
|
|
317
308
|
formData={formData}
|
|
318
309
|
formContext={formContext}
|
|
319
|
-
|
|
320
|
-
idSchema={idSchema}
|
|
321
|
-
idSeparator={idSeparator}
|
|
310
|
+
fieldPathId={fieldPathId}
|
|
322
311
|
onBlur={props.onBlur}
|
|
323
312
|
onChange={props.onChange}
|
|
324
313
|
onFocus={props.onFocus}
|
|
@@ -343,7 +332,12 @@ class SchemaField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
|
|
|
343
332
|
FieldProps<T, S, F>
|
|
344
333
|
> {
|
|
345
334
|
shouldComponentUpdate(nextProps: Readonly<FieldProps<T, S, F>>) {
|
|
346
|
-
|
|
335
|
+
const {
|
|
336
|
+
registry: { globalFormOptions },
|
|
337
|
+
} = this.props;
|
|
338
|
+
const { experimental_componentUpdateStrategy = 'customDeep' } = globalFormOptions;
|
|
339
|
+
|
|
340
|
+
return shouldRender(this, nextProps, this.state, experimental_componentUpdateStrategy);
|
|
347
341
|
}
|
|
348
342
|
|
|
349
343
|
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
|
-
|
|
25
|
+
fieldPathId,
|
|
24
26
|
formData,
|
|
25
27
|
required,
|
|
26
28
|
disabled = false,
|
|
@@ -44,18 +46,25 @@ 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={
|
|
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={
|
|
67
|
+
onChange={onWidgetChange}
|
|
59
68
|
onBlur={onBlur}
|
|
60
69
|
onFocus={onFocus}
|
|
61
70
|
required={required}
|
|
@@ -8,6 +8,7 @@ import LayoutMultiSchemaField from './LayoutMultiSchemaField';
|
|
|
8
8
|
import MultiSchemaField from './MultiSchemaField';
|
|
9
9
|
import NumberField from './NumberField';
|
|
10
10
|
import ObjectField from './ObjectField';
|
|
11
|
+
import OptionalDataControlsField from './OptionalDataControlsField';
|
|
11
12
|
import SchemaField from './SchemaField';
|
|
12
13
|
import StringField from './StringField';
|
|
13
14
|
import NullField from './NullField';
|
|
@@ -28,6 +29,7 @@ function fields<
|
|
|
28
29
|
NumberField,
|
|
29
30
|
ObjectField,
|
|
30
31
|
OneOfField: MultiSchemaField,
|
|
32
|
+
OptionalDataControlsField,
|
|
31
33
|
SchemaField,
|
|
32
34
|
StringField,
|
|
33
35
|
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 `
|
|
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 {
|
|
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
|
|
34
|
+
id={descriptionId(fieldPathId)}
|
|
35
35
|
description={description}
|
|
36
36
|
schema={schema}
|
|
37
37
|
uiSchema={uiSchema}
|
|
@@ -23,7 +23,7 @@ export default function ArrayFieldItemButtonsTemplate<
|
|
|
23
23
|
hasMoveDown,
|
|
24
24
|
hasMoveUp,
|
|
25
25
|
hasRemove,
|
|
26
|
-
|
|
26
|
+
fieldPathId,
|
|
27
27
|
index,
|
|
28
28
|
onCopyIndexClick,
|
|
29
29
|
onDropIndexClick,
|
|
@@ -42,7 +42,7 @@ export default function ArrayFieldItemButtonsTemplate<
|
|
|
42
42
|
<>
|
|
43
43
|
{(hasMoveUp || hasMoveDown) && (
|
|
44
44
|
<MoveUpButton
|
|
45
|
-
id={buttonId
|
|
45
|
+
id={buttonId(fieldPathId, 'moveUp')}
|
|
46
46
|
className='rjsf-array-item-move-up'
|
|
47
47
|
disabled={disabled || readonly || !hasMoveUp}
|
|
48
48
|
onClick={onArrowUpClick}
|
|
@@ -52,7 +52,7 @@ export default function ArrayFieldItemButtonsTemplate<
|
|
|
52
52
|
)}
|
|
53
53
|
{(hasMoveUp || hasMoveDown) && (
|
|
54
54
|
<MoveDownButton
|
|
55
|
-
id={buttonId
|
|
55
|
+
id={buttonId(fieldPathId, 'moveDown')}
|
|
56
56
|
className='rjsf-array-item-move-down'
|
|
57
57
|
disabled={disabled || readonly || !hasMoveDown}
|
|
58
58
|
onClick={onArrowDownClick}
|
|
@@ -62,7 +62,7 @@ export default function ArrayFieldItemButtonsTemplate<
|
|
|
62
62
|
)}
|
|
63
63
|
{hasCopy && (
|
|
64
64
|
<CopyButton
|
|
65
|
-
id={buttonId
|
|
65
|
+
id={buttonId(fieldPathId, 'copy')}
|
|
66
66
|
className='rjsf-array-item-copy'
|
|
67
67
|
disabled={disabled || readonly}
|
|
68
68
|
onClick={onCopyClick}
|
|
@@ -72,7 +72,7 @@ export default function ArrayFieldItemButtonsTemplate<
|
|
|
72
72
|
)}
|
|
73
73
|
{hasRemove && (
|
|
74
74
|
<RemoveButton
|
|
75
|
-
id={buttonId
|
|
75
|
+
id={buttonId(fieldPathId, 'remove')}
|
|
76
76
|
className='rjsf-array-item-remove'
|
|
77
77
|
disabled={disabled || readonly}
|
|
78
78
|
onClick={onRemoveClick}
|
|
@@ -22,9 +22,10 @@ export default function ArrayFieldTemplate<
|
|
|
22
22
|
canAdd,
|
|
23
23
|
className,
|
|
24
24
|
disabled,
|
|
25
|
-
|
|
25
|
+
fieldPathId,
|
|
26
26
|
uiSchema,
|
|
27
27
|
items,
|
|
28
|
+
optionalDataControl,
|
|
28
29
|
onAddClick,
|
|
29
30
|
readonly,
|
|
30
31
|
registry,
|
|
@@ -49,26 +50,29 @@ export default function ArrayFieldTemplate<
|
|
|
49
50
|
uiOptions,
|
|
50
51
|
);
|
|
51
52
|
// Button templates are not overridden in the uiSchema
|
|
53
|
+
const showOptionalDataControlInTitle = !readonly && !disabled;
|
|
52
54
|
const {
|
|
53
55
|
ButtonTemplates: { AddButton },
|
|
54
56
|
} = registry.templates;
|
|
55
57
|
return (
|
|
56
|
-
<fieldset className={className} id={
|
|
58
|
+
<fieldset className={className} id={fieldPathId.$id}>
|
|
57
59
|
<ArrayFieldTitleTemplate
|
|
58
|
-
|
|
60
|
+
fieldPathId={fieldPathId}
|
|
59
61
|
title={uiOptions.title || title}
|
|
60
62
|
required={required}
|
|
61
63
|
schema={schema}
|
|
62
64
|
uiSchema={uiSchema}
|
|
63
65
|
registry={registry}
|
|
66
|
+
optionalDataControl={showOptionalDataControlInTitle ? optionalDataControl : undefined}
|
|
64
67
|
/>
|
|
65
68
|
<ArrayFieldDescriptionTemplate
|
|
66
|
-
|
|
69
|
+
fieldPathId={fieldPathId}
|
|
67
70
|
description={uiOptions.description || schema.description}
|
|
68
71
|
schema={schema}
|
|
69
72
|
uiSchema={uiSchema}
|
|
70
73
|
registry={registry}
|
|
71
74
|
/>
|
|
75
|
+
{!showOptionalDataControlInTitle ? optionalDataControl : undefined}
|
|
72
76
|
<div className='row array-item-list'>
|
|
73
77
|
{items &&
|
|
74
78
|
items.map(({ key, ...itemProps }: ArrayFieldItemTemplateType<T, S, F>) => (
|
|
@@ -77,7 +81,7 @@ export default function ArrayFieldTemplate<
|
|
|
77
81
|
</div>
|
|
78
82
|
{canAdd && (
|
|
79
83
|
<AddButton
|
|
80
|
-
id={buttonId
|
|
84
|
+
id={buttonId(fieldPathId, 'add')}
|
|
81
85
|
className='rjsf-array-item-add'
|
|
82
86
|
onClick={onAddClick}
|
|
83
87
|
disabled={disabled || readonly}
|