@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
|
@@ -6,12 +6,16 @@ import {
|
|
|
6
6
|
isFixedItems,
|
|
7
7
|
allowAdditionalItems,
|
|
8
8
|
isCustomWidget,
|
|
9
|
+
isFormDataAvailable,
|
|
9
10
|
optionsList,
|
|
11
|
+
shouldRenderOptionalField,
|
|
12
|
+
toFieldPathId,
|
|
10
13
|
ArrayFieldTemplateProps,
|
|
11
14
|
ErrorSchema,
|
|
15
|
+
FieldPathId,
|
|
16
|
+
FieldPathList,
|
|
12
17
|
FieldProps,
|
|
13
18
|
FormContextType,
|
|
14
|
-
IdSchema,
|
|
15
19
|
RJSFSchema,
|
|
16
20
|
StrictRJSFSchema,
|
|
17
21
|
TranslatableString,
|
|
@@ -22,7 +26,7 @@ import cloneDeep from 'lodash/cloneDeep';
|
|
|
22
26
|
import get from 'lodash/get';
|
|
23
27
|
import isObject from 'lodash/isObject';
|
|
24
28
|
import set from 'lodash/set';
|
|
25
|
-
import
|
|
29
|
+
import uniqueId from 'lodash/uniqueId';
|
|
26
30
|
|
|
27
31
|
/** Type used to represent the keyed form data used in the state */
|
|
28
32
|
type KeyedFormDataType<T> = { key: string; item: T };
|
|
@@ -37,7 +41,7 @@ type ArrayFieldState<T> = {
|
|
|
37
41
|
|
|
38
42
|
/** Used to generate a unique ID for an element in a row */
|
|
39
43
|
function generateRowId() {
|
|
40
|
-
return
|
|
44
|
+
return uniqueId('rjsf-array-item-');
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
/** Converts the `formData` into `KeyedFormDataType` data, using the `generateRowId()` function to create the key
|
|
@@ -45,7 +49,7 @@ function generateRowId() {
|
|
|
45
49
|
* @param formData - The data for the form
|
|
46
50
|
* @returns - The `formData` converted into a `KeyedFormDataType` element
|
|
47
51
|
*/
|
|
48
|
-
function generateKeyedFormData<T>(formData
|
|
52
|
+
function generateKeyedFormData<T>(formData?: T[]): KeyedFormDataType<T>[] {
|
|
49
53
|
return !Array.isArray(formData)
|
|
50
54
|
? []
|
|
51
55
|
: formData.map((item) => {
|
|
@@ -81,7 +85,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
81
85
|
*/
|
|
82
86
|
constructor(props: FieldProps<T[], S, F>) {
|
|
83
87
|
super(props);
|
|
84
|
-
const { formData
|
|
88
|
+
const { formData } = props;
|
|
85
89
|
const keyedFormData = generateKeyedFormData<T>(formData);
|
|
86
90
|
this.state = {
|
|
87
91
|
keyedFormData,
|
|
@@ -198,7 +202,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
198
202
|
event.preventDefault();
|
|
199
203
|
}
|
|
200
204
|
|
|
201
|
-
const { onChange, errorSchema } = this.props;
|
|
205
|
+
const { onChange, errorSchema, fieldPathId } = this.props;
|
|
202
206
|
const { keyedFormData } = this.state;
|
|
203
207
|
// refs #195: revalidate to ensure properly reindexing errors
|
|
204
208
|
let newErrorSchema: ErrorSchema<T>;
|
|
@@ -229,7 +233,8 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
229
233
|
keyedFormData: newKeyedFormData,
|
|
230
234
|
updatedKeyedFormData: true,
|
|
231
235
|
},
|
|
232
|
-
|
|
236
|
+
// add click will pass the empty `path` array to the onChange which adds the appropriate path
|
|
237
|
+
() => onChange(keyedToPlainFormData(newKeyedFormData), fieldPathId.path, newErrorSchema as ErrorSchema<T[]>),
|
|
233
238
|
);
|
|
234
239
|
}
|
|
235
240
|
|
|
@@ -267,7 +272,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
267
272
|
event.preventDefault();
|
|
268
273
|
}
|
|
269
274
|
|
|
270
|
-
const { onChange, errorSchema } = this.props;
|
|
275
|
+
const { onChange, errorSchema, fieldPathId } = this.props;
|
|
271
276
|
const { keyedFormData } = this.state;
|
|
272
277
|
// refs #195: revalidate to ensure properly reindexing errors
|
|
273
278
|
let newErrorSchema: ErrorSchema<T>;
|
|
@@ -298,7 +303,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
298
303
|
keyedFormData: newKeyedFormData,
|
|
299
304
|
updatedKeyedFormData: true,
|
|
300
305
|
},
|
|
301
|
-
() => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema as ErrorSchema<T[]>),
|
|
306
|
+
() => onChange(keyedToPlainFormData(newKeyedFormData), fieldPathId.path, newErrorSchema as ErrorSchema<T[]>),
|
|
302
307
|
);
|
|
303
308
|
};
|
|
304
309
|
};
|
|
@@ -314,7 +319,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
314
319
|
if (event) {
|
|
315
320
|
event.preventDefault();
|
|
316
321
|
}
|
|
317
|
-
const { onChange, errorSchema } = this.props;
|
|
322
|
+
const { onChange, errorSchema, fieldPathId } = this.props;
|
|
318
323
|
const { keyedFormData } = this.state;
|
|
319
324
|
// refs #195: revalidate to ensure properly reindexing errors
|
|
320
325
|
let newErrorSchema: ErrorSchema<T>;
|
|
@@ -335,7 +340,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
335
340
|
keyedFormData: newKeyedFormData,
|
|
336
341
|
updatedKeyedFormData: true,
|
|
337
342
|
},
|
|
338
|
-
() => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema as ErrorSchema<T[]>),
|
|
343
|
+
() => onChange(keyedToPlainFormData(newKeyedFormData), fieldPathId.path, newErrorSchema as ErrorSchema<T[]>),
|
|
339
344
|
);
|
|
340
345
|
};
|
|
341
346
|
};
|
|
@@ -353,7 +358,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
353
358
|
event.preventDefault();
|
|
354
359
|
event.currentTarget.blur();
|
|
355
360
|
}
|
|
356
|
-
const { onChange, errorSchema } = this.props;
|
|
361
|
+
const { onChange, errorSchema, fieldPathId } = this.props;
|
|
357
362
|
let newErrorSchema: ErrorSchema<T>;
|
|
358
363
|
if (errorSchema) {
|
|
359
364
|
newErrorSchema = {};
|
|
@@ -385,7 +390,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
385
390
|
{
|
|
386
391
|
keyedFormData: newKeyedFormData,
|
|
387
392
|
},
|
|
388
|
-
() => onChange(keyedToPlainFormData(newKeyedFormData), newErrorSchema as ErrorSchema<T[]>),
|
|
393
|
+
() => onChange(keyedToPlainFormData(newKeyedFormData), fieldPathId.path, newErrorSchema as ErrorSchema<T[]>),
|
|
389
394
|
);
|
|
390
395
|
};
|
|
391
396
|
};
|
|
@@ -396,22 +401,14 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
396
401
|
* @param index - The index of the item being changed
|
|
397
402
|
*/
|
|
398
403
|
onChangeForIndex = (index: number) => {
|
|
399
|
-
return (value: any, newErrorSchema?: ErrorSchema<T>, id?: string) => {
|
|
400
|
-
const {
|
|
401
|
-
|
|
402
|
-
const newFormData = arrayData.map((item: T, i: number) => {
|
|
404
|
+
return (value: any, path: FieldPathList, newErrorSchema?: ErrorSchema<T>, id?: string) => {
|
|
405
|
+
const { onChange } = this.props;
|
|
406
|
+
onChange(
|
|
403
407
|
// We need to treat undefined items as nulls to have validation.
|
|
404
408
|
// See https://github.com/tdegrunt/jsonschema/issues/206
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
onChange(
|
|
409
|
-
newFormData,
|
|
410
|
-
errorSchema &&
|
|
411
|
-
errorSchema && {
|
|
412
|
-
...errorSchema,
|
|
413
|
-
[index]: newErrorSchema,
|
|
414
|
-
},
|
|
409
|
+
value === undefined ? null : value,
|
|
410
|
+
path,
|
|
411
|
+
newErrorSchema as ErrorSchema<T[]>,
|
|
415
412
|
id,
|
|
416
413
|
);
|
|
417
414
|
};
|
|
@@ -419,14 +416,48 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
419
416
|
|
|
420
417
|
/** Callback handler used to change the value for a checkbox */
|
|
421
418
|
onSelectChange = (value: any) => {
|
|
422
|
-
const { onChange,
|
|
423
|
-
|
|
419
|
+
const { onChange, fieldPathId } = this.props;
|
|
420
|
+
// select change will pass an empty `path` array since the `ObjectField` will add the path value automatically
|
|
421
|
+
onChange(value, fieldPathId.path, undefined, fieldPathId && fieldPathId.$id);
|
|
424
422
|
};
|
|
425
423
|
|
|
424
|
+
/** Helper method to compute item UI schema for both normal and fixed arrays
|
|
425
|
+
* Handles both static object and dynamic function cases
|
|
426
|
+
*
|
|
427
|
+
* @param uiSchema - The parent UI schema containing items definition
|
|
428
|
+
* @param item - The item data
|
|
429
|
+
* @param index - The index of the item
|
|
430
|
+
* @param formContext - The form context
|
|
431
|
+
* @returns The computed UI schema for the item
|
|
432
|
+
*/
|
|
433
|
+
private computeItemUiSchema(
|
|
434
|
+
uiSchema: UiSchema<T[], S, F>,
|
|
435
|
+
item: T,
|
|
436
|
+
index: number,
|
|
437
|
+
formContext: F,
|
|
438
|
+
): UiSchema<T[], S, F> | undefined {
|
|
439
|
+
if (typeof uiSchema.items === 'function') {
|
|
440
|
+
try {
|
|
441
|
+
// Call the function with item data, index, and form context
|
|
442
|
+
// TypeScript now correctly infers the types thanks to the ArrayElement type in UiSchema
|
|
443
|
+
const result = uiSchema.items(item, index, formContext);
|
|
444
|
+
// Only use the result if it's truthy
|
|
445
|
+
return result as UiSchema<T[], S, F>;
|
|
446
|
+
} catch (e) {
|
|
447
|
+
console.error(`Error executing dynamic uiSchema.items function for item at index ${index}:`, e);
|
|
448
|
+
// Fall back to undefined to allow the field to still render
|
|
449
|
+
return undefined;
|
|
450
|
+
}
|
|
451
|
+
} else {
|
|
452
|
+
// Static object case - preserve undefined to maintain backward compatibility
|
|
453
|
+
return uiSchema.items as UiSchema<T[], S, F> | undefined;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
426
457
|
/** Renders the `ArrayField` depending on the specific needs of the schema and uischema elements
|
|
427
458
|
*/
|
|
428
459
|
render() {
|
|
429
|
-
const { schema, uiSchema,
|
|
460
|
+
const { schema, uiSchema, fieldPathId, registry } = this.props;
|
|
430
461
|
const { schemaUtils, translateString } = registry;
|
|
431
462
|
if (!(ITEMS_KEY in schema)) {
|
|
432
463
|
const uiOptions = getUiOptions<T[], S, F>(uiSchema);
|
|
@@ -439,7 +470,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
439
470
|
return (
|
|
440
471
|
<UnsupportedFieldTemplate
|
|
441
472
|
schema={schema}
|
|
442
|
-
|
|
473
|
+
fieldPathId={fieldPathId}
|
|
443
474
|
reason={translateString(TranslatableString.MissingItems)}
|
|
444
475
|
registry={registry}
|
|
445
476
|
/>
|
|
@@ -468,7 +499,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
468
499
|
schema,
|
|
469
500
|
uiSchema = {},
|
|
470
501
|
errorSchema,
|
|
471
|
-
|
|
502
|
+
fieldPathId,
|
|
472
503
|
name,
|
|
473
504
|
title,
|
|
474
505
|
disabled = false,
|
|
@@ -478,28 +509,35 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
478
509
|
registry,
|
|
479
510
|
onBlur,
|
|
480
511
|
onFocus,
|
|
481
|
-
idPrefix,
|
|
482
|
-
idSeparator = '_',
|
|
483
512
|
rawErrors,
|
|
484
513
|
} = this.props;
|
|
485
514
|
const { keyedFormData } = this.state;
|
|
486
515
|
const fieldTitle = schema.title || title || name;
|
|
487
|
-
const { schemaUtils, formContext } = registry;
|
|
516
|
+
const { schemaUtils, fields, formContext, globalFormOptions } = registry;
|
|
517
|
+
const { OptionalDataControlsField } = fields;
|
|
488
518
|
const uiOptions = getUiOptions<T[], S, F>(uiSchema);
|
|
489
519
|
const _schemaItems: S = isObject(schema.items) ? (schema.items as S) : ({} as S);
|
|
490
520
|
const itemsSchema: S = schemaUtils.retrieveSchema(_schemaItems);
|
|
491
521
|
const formData = keyedToPlainFormData(this.state.keyedFormData);
|
|
492
|
-
const
|
|
522
|
+
const renderOptionalField = shouldRenderOptionalField(registry, schema, required, uiSchema);
|
|
523
|
+
const hasFormData = isFormDataAvailable(this.props.formData);
|
|
524
|
+
const canAdd = this.canAddItem(formData) && (!renderOptionalField || hasFormData);
|
|
525
|
+
const actualFormData = hasFormData ? keyedFormData : [];
|
|
526
|
+
const extraClass = renderOptionalField ? ' rjsf-optional-array-field' : '';
|
|
527
|
+
const optionalDataControl = renderOptionalField ? <OptionalDataControlsField {...this.props} /> : undefined;
|
|
493
528
|
const arrayProps: ArrayFieldTemplateProps<T[], S, F> = {
|
|
494
529
|
canAdd,
|
|
495
|
-
items:
|
|
530
|
+
items: actualFormData.map((keyedItem, index) => {
|
|
496
531
|
const { key, item } = keyedItem;
|
|
497
532
|
// While we are actually dealing with a single item of type T, the types require a T[], so cast
|
|
498
533
|
const itemCast = item as unknown as T[];
|
|
499
534
|
const itemSchema = schemaUtils.retrieveSchema(_schemaItems, itemCast);
|
|
500
535
|
const itemErrorSchema = errorSchema ? (errorSchema[index] as ErrorSchema<T[]>) : undefined;
|
|
501
|
-
const
|
|
502
|
-
|
|
536
|
+
const itemFieldPathId = toFieldPathId(index, globalFormOptions, fieldPathId);
|
|
537
|
+
|
|
538
|
+
// Compute the item UI schema using the helper method
|
|
539
|
+
const itemUiSchema = this.computeItemUiSchema(uiSchema, item, index, formContext);
|
|
540
|
+
|
|
503
541
|
return this.renderArrayFieldItem({
|
|
504
542
|
key,
|
|
505
543
|
index,
|
|
@@ -509,10 +547,10 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
509
547
|
canMoveUp: index > 0,
|
|
510
548
|
canMoveDown: index < formData.length - 1,
|
|
511
549
|
itemSchema,
|
|
512
|
-
|
|
550
|
+
itemFieldPathId,
|
|
513
551
|
itemErrorSchema,
|
|
514
552
|
itemData: itemCast,
|
|
515
|
-
itemUiSchema
|
|
553
|
+
itemUiSchema,
|
|
516
554
|
autofocus: autofocus && index === 0,
|
|
517
555
|
onBlur,
|
|
518
556
|
onFocus,
|
|
@@ -520,19 +558,19 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
520
558
|
totalItems: keyedFormData.length,
|
|
521
559
|
});
|
|
522
560
|
}),
|
|
523
|
-
className: `rjsf-field rjsf-field-array rjsf-field-array-of-${itemsSchema.type}`,
|
|
561
|
+
className: `rjsf-field rjsf-field-array rjsf-field-array-of-${itemsSchema.type}${extraClass}`,
|
|
524
562
|
disabled,
|
|
525
|
-
|
|
563
|
+
fieldPathId,
|
|
526
564
|
uiSchema,
|
|
527
565
|
onAddClick: this.onAddClick,
|
|
528
566
|
readonly,
|
|
529
567
|
required,
|
|
530
568
|
schema,
|
|
531
569
|
title: fieldTitle,
|
|
532
|
-
formContext,
|
|
533
570
|
formData,
|
|
534
571
|
rawErrors,
|
|
535
572
|
registry,
|
|
573
|
+
optionalDataControl,
|
|
536
574
|
};
|
|
537
575
|
|
|
538
576
|
const Template = getTemplate<'ArrayFieldTemplate', T[], S, F>('ArrayFieldTemplate', registry, uiOptions);
|
|
@@ -544,7 +582,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
544
582
|
renderCustomWidget() {
|
|
545
583
|
const {
|
|
546
584
|
schema,
|
|
547
|
-
|
|
585
|
+
fieldPathId,
|
|
548
586
|
uiSchema,
|
|
549
587
|
disabled = false,
|
|
550
588
|
readonly = false,
|
|
@@ -566,7 +604,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
566
604
|
const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions);
|
|
567
605
|
return (
|
|
568
606
|
<Widget
|
|
569
|
-
id={
|
|
607
|
+
id={fieldPathId.$id}
|
|
570
608
|
name={name}
|
|
571
609
|
multiple
|
|
572
610
|
onChange={this.onSelectChange}
|
|
@@ -596,7 +634,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
596
634
|
renderMultiSelect() {
|
|
597
635
|
const {
|
|
598
636
|
schema,
|
|
599
|
-
|
|
637
|
+
fieldPathId,
|
|
600
638
|
uiSchema,
|
|
601
639
|
formData: items = [],
|
|
602
640
|
disabled = false,
|
|
@@ -619,7 +657,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
619
657
|
const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema, globalUiOptions);
|
|
620
658
|
return (
|
|
621
659
|
<Widget
|
|
622
|
-
id={
|
|
660
|
+
id={fieldPathId.$id}
|
|
623
661
|
name={name}
|
|
624
662
|
multiple
|
|
625
663
|
onChange={this.onSelectChange}
|
|
@@ -649,7 +687,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
649
687
|
const {
|
|
650
688
|
schema,
|
|
651
689
|
uiSchema,
|
|
652
|
-
|
|
690
|
+
fieldPathId,
|
|
653
691
|
name,
|
|
654
692
|
disabled = false,
|
|
655
693
|
readonly = false,
|
|
@@ -669,7 +707,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
669
707
|
return (
|
|
670
708
|
<Widget
|
|
671
709
|
options={options}
|
|
672
|
-
id={
|
|
710
|
+
id={fieldPathId.$id}
|
|
673
711
|
name={name}
|
|
674
712
|
multiple
|
|
675
713
|
onChange={this.onSelectChange}
|
|
@@ -697,11 +735,9 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
697
735
|
const {
|
|
698
736
|
schema,
|
|
699
737
|
uiSchema = {},
|
|
700
|
-
formData
|
|
738
|
+
formData,
|
|
701
739
|
errorSchema,
|
|
702
|
-
|
|
703
|
-
idSeparator = '_',
|
|
704
|
-
idSchema,
|
|
740
|
+
fieldPathId,
|
|
705
741
|
name,
|
|
706
742
|
title,
|
|
707
743
|
disabled = false,
|
|
@@ -713,34 +749,39 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
713
749
|
onFocus,
|
|
714
750
|
rawErrors,
|
|
715
751
|
} = this.props;
|
|
716
|
-
const { keyedFormData } = this.state;
|
|
717
752
|
let { formData: items = [] } = this.props;
|
|
753
|
+
const { keyedFormData } = this.state;
|
|
718
754
|
const fieldTitle = schema.title || title || name;
|
|
719
755
|
const uiOptions = getUiOptions<T[], S, F>(uiSchema);
|
|
720
|
-
const { schemaUtils, formContext } = registry;
|
|
756
|
+
const { schemaUtils, fields, formContext, globalFormOptions } = registry;
|
|
757
|
+
const { OptionalDataControlsField } = fields;
|
|
758
|
+
const renderOptionalField = shouldRenderOptionalField(registry, schema, required, uiSchema);
|
|
759
|
+
const hasFormData = isFormDataAvailable(formData);
|
|
721
760
|
const _schemaItems: S[] = isObject(schema.items) ? (schema.items as S[]) : ([] as S[]);
|
|
722
761
|
const itemSchemas = _schemaItems.map((item: S, index: number) =>
|
|
723
|
-
schemaUtils.retrieveSchema(item,
|
|
762
|
+
schemaUtils.retrieveSchema(item, items[index] as unknown as T[]),
|
|
724
763
|
);
|
|
725
764
|
const additionalSchema = isObject(schema.additionalItems)
|
|
726
765
|
? schemaUtils.retrieveSchema(schema.additionalItems as S, formData)
|
|
727
766
|
: null;
|
|
728
767
|
|
|
729
|
-
if (
|
|
768
|
+
if (items.length < itemSchemas.length) {
|
|
730
769
|
// to make sure at least all fixed items are generated
|
|
731
|
-
items = items || [];
|
|
732
770
|
items = items.concat(new Array(itemSchemas.length - items.length));
|
|
733
771
|
}
|
|
772
|
+
const actualFormData = hasFormData ? keyedFormData : [];
|
|
773
|
+
const extraClass = renderOptionalField ? ' rjsf-optional-array-field' : '';
|
|
774
|
+
const optionalDataControl = renderOptionalField ? <OptionalDataControlsField {...this.props} /> : undefined;
|
|
734
775
|
|
|
735
776
|
// These are the props passed into the render function
|
|
736
|
-
const canAdd = this.canAddItem(items) && !!additionalSchema;
|
|
777
|
+
const canAdd = this.canAddItem(items) && !!additionalSchema && (!renderOptionalField || hasFormData);
|
|
737
778
|
const arrayProps: ArrayFieldTemplateProps<T[], S, F> = {
|
|
738
779
|
canAdd,
|
|
739
|
-
className:
|
|
780
|
+
className: `rjsf-field rjsf-field-array rjsf-field-array-fixed-items${extraClass}`,
|
|
740
781
|
disabled,
|
|
741
|
-
|
|
782
|
+
fieldPathId,
|
|
742
783
|
formData,
|
|
743
|
-
items:
|
|
784
|
+
items: actualFormData.map((keyedItem, index) => {
|
|
744
785
|
const { key, item } = keyedItem;
|
|
745
786
|
// While we are actually dealing with a single item of type T, the types require a T[], so cast
|
|
746
787
|
const itemCast = item as unknown as T[];
|
|
@@ -749,13 +790,21 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
749
790
|
(additional && isObject(schema.additionalItems)
|
|
750
791
|
? schemaUtils.retrieveSchema(schema.additionalItems as S, itemCast)
|
|
751
792
|
: itemSchemas[index]) || {};
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
793
|
+
const itemFieldPathId = toFieldPathId(index, globalFormOptions, fieldPathId);
|
|
794
|
+
// Compute the item UI schema - handle both static and dynamic cases
|
|
795
|
+
let itemUiSchema: UiSchema<T[], S, F> | undefined;
|
|
796
|
+
if (additional) {
|
|
797
|
+
// For additional items, use additionalItems uiSchema
|
|
798
|
+
itemUiSchema = uiSchema.additionalItems as UiSchema<T[], S, F>;
|
|
799
|
+
} else {
|
|
800
|
+
// For fixed items, uiSchema.items can be an array, a function, or a single object
|
|
801
|
+
if (Array.isArray(uiSchema.items)) {
|
|
802
|
+
itemUiSchema = uiSchema.items[index] as UiSchema<T[], S, F>;
|
|
803
|
+
} else {
|
|
804
|
+
// Use the helper method for function or static object cases
|
|
805
|
+
itemUiSchema = this.computeItemUiSchema(uiSchema, item, index, formContext);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
759
808
|
const itemErrorSchema = errorSchema ? (errorSchema[index] as ErrorSchema<T[]>) : undefined;
|
|
760
809
|
|
|
761
810
|
return this.renderArrayFieldItem({
|
|
@@ -770,7 +819,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
770
819
|
itemSchema,
|
|
771
820
|
itemData: itemCast,
|
|
772
821
|
itemUiSchema,
|
|
773
|
-
|
|
822
|
+
itemFieldPathId,
|
|
774
823
|
itemErrorSchema,
|
|
775
824
|
autofocus: autofocus && index === 0,
|
|
776
825
|
onBlur,
|
|
@@ -786,9 +835,9 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
786
835
|
schema,
|
|
787
836
|
uiSchema,
|
|
788
837
|
title: fieldTitle,
|
|
789
|
-
formContext,
|
|
790
838
|
errorSchema,
|
|
791
839
|
rawErrors,
|
|
840
|
+
optionalDataControl,
|
|
792
841
|
};
|
|
793
842
|
|
|
794
843
|
const Template = getTemplate<'ArrayFieldTemplate', T[], S, F>('ArrayFieldTemplate', registry, uiOptions);
|
|
@@ -811,8 +860,8 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
811
860
|
canMoveDown: boolean;
|
|
812
861
|
itemSchema: S;
|
|
813
862
|
itemData: T[];
|
|
814
|
-
itemUiSchema: UiSchema<T[], S, F
|
|
815
|
-
|
|
863
|
+
itemUiSchema: UiSchema<T[], S, F> | undefined;
|
|
864
|
+
itemFieldPathId: FieldPathId;
|
|
816
865
|
itemErrorSchema?: ErrorSchema<T[]>;
|
|
817
866
|
autofocus?: boolean;
|
|
818
867
|
onBlur: FieldProps<T[], S, F>['onBlur'];
|
|
@@ -831,7 +880,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
831
880
|
itemSchema,
|
|
832
881
|
itemData,
|
|
833
882
|
itemUiSchema,
|
|
834
|
-
|
|
883
|
+
itemFieldPathId,
|
|
835
884
|
itemErrorSchema,
|
|
836
885
|
autofocus,
|
|
837
886
|
onBlur,
|
|
@@ -840,7 +889,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
840
889
|
totalItems,
|
|
841
890
|
title,
|
|
842
891
|
} = props;
|
|
843
|
-
const { disabled, hideError,
|
|
892
|
+
const { disabled, hideError, readonly, uiSchema, registry, formContext } = this.props;
|
|
844
893
|
const {
|
|
845
894
|
fields: { ArraySchemaField, SchemaField },
|
|
846
895
|
globalUiOptions,
|
|
@@ -867,9 +916,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
867
916
|
formData={itemData}
|
|
868
917
|
formContext={formContext}
|
|
869
918
|
errorSchema={itemErrorSchema}
|
|
870
|
-
|
|
871
|
-
idSeparator={idSeparator}
|
|
872
|
-
idSchema={itemIdSchema}
|
|
919
|
+
fieldPathId={itemFieldPathId}
|
|
873
920
|
required={this.isItemRequired(itemSchema)}
|
|
874
921
|
onChange={this.onChangeForIndex(index)}
|
|
875
922
|
onBlur={onBlur}
|
|
@@ -883,7 +930,7 @@ class ArrayField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
883
930
|
/>
|
|
884
931
|
),
|
|
885
932
|
buttonsProps: {
|
|
886
|
-
|
|
933
|
+
fieldPathId: itemFieldPathId,
|
|
887
934
|
disabled: disabled,
|
|
888
935
|
readonly: readonly,
|
|
889
936
|
canAdd,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
1
2
|
import {
|
|
2
3
|
getWidget,
|
|
3
4
|
getUiOptions,
|
|
@@ -5,6 +6,7 @@ import {
|
|
|
5
6
|
FieldProps,
|
|
6
7
|
FormContextType,
|
|
7
8
|
EnumOptionsType,
|
|
9
|
+
ErrorSchema,
|
|
8
10
|
RJSFSchema,
|
|
9
11
|
StrictRJSFSchema,
|
|
10
12
|
TranslatableString,
|
|
@@ -23,7 +25,7 @@ function BooleanField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extend
|
|
|
23
25
|
schema,
|
|
24
26
|
name,
|
|
25
27
|
uiSchema,
|
|
26
|
-
|
|
28
|
+
fieldPathId,
|
|
27
29
|
formData,
|
|
28
30
|
registry,
|
|
29
31
|
required,
|
|
@@ -86,15 +88,22 @@ function BooleanField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extend
|
|
|
86
88
|
enumOptions = optionsList<T, S, F>({ enum: enums } as S, uiSchema);
|
|
87
89
|
}
|
|
88
90
|
}
|
|
91
|
+
const onWidgetChange = useCallback(
|
|
92
|
+
(value: T | undefined, errorSchema?: ErrorSchema, id?: string) => {
|
|
93
|
+
// Boolean field change passes an empty path array to the parent field which adds the appropriate path
|
|
94
|
+
return onChange(value, fieldPathId.path, errorSchema, id);
|
|
95
|
+
},
|
|
96
|
+
[onChange, fieldPathId],
|
|
97
|
+
);
|
|
89
98
|
|
|
90
99
|
return (
|
|
91
100
|
<Widget
|
|
92
101
|
options={{ ...options, enumOptions }}
|
|
93
102
|
schema={schema}
|
|
94
103
|
uiSchema={uiSchema}
|
|
95
|
-
id={
|
|
104
|
+
id={fieldPathId.$id}
|
|
96
105
|
name={name}
|
|
97
|
-
onChange={
|
|
106
|
+
onChange={onWidgetChange}
|
|
98
107
|
onFocus={onFocus}
|
|
99
108
|
onBlur={onBlur}
|
|
100
109
|
label={label}
|