@rjsf/core 6.0.0-beta.2 → 6.0.0-beta.20
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 +469 -360
- package/dist/{index.js → index.cjs} +640 -519
- package/dist/index.cjs.map +7 -0
- package/dist/index.esm.js +706 -566
- package/dist/index.esm.js.map +4 -4
- package/lib/components/Form.d.ts +66 -16
- package/lib/components/Form.d.ts.map +1 -1
- package/lib/components/Form.js +138 -59
- 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 +92 -59
- 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 -53
- 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 +18 -25
- 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/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.js +3 -3
- package/lib/components/templates/ArrayFieldTitleTemplate.d.ts +1 -1
- package/lib/components/templates/ArrayFieldTitleTemplate.js +3 -3
- 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.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 +2 -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 +183 -73
- package/src/components/fields/ArrayField.tsx +99 -67
- package/src/components/fields/BooleanField.tsx +12 -3
- package/src/components/fields/LayoutGridField.tsx +95 -82
- 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 +19 -36
- package/src/components/fields/SchemaField.tsx +24 -30
- package/src/components/fields/StringField.tsx +12 -3
- package/src/components/templates/ArrayFieldDescriptionTemplate.tsx +3 -3
- package/src/components/templates/ArrayFieldItemButtonsTemplate.tsx +5 -5
- package/src/components/templates/ArrayFieldTemplate.tsx +5 -5
- package/src/components/templates/ArrayFieldTitleTemplate.tsx +3 -3
- package/src/components/templates/BaseInputTemplate.tsx +3 -3
- 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 +5 -5
- package/src/components/templates/UnsupportedField.tsx +3 -3
- package/src/components/templates/WrapIfAdditionalTemplate.tsx +1 -1
- package/src/components/templates/index.ts +2 -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,6 +3,8 @@ import {
|
|
|
3
3
|
ANY_OF_KEY,
|
|
4
4
|
ErrorSchema,
|
|
5
5
|
FieldProps,
|
|
6
|
+
FieldPathId,
|
|
7
|
+
FieldPathList,
|
|
6
8
|
FormContextType,
|
|
7
9
|
GenericObjectType,
|
|
8
10
|
getDiscriminatorFieldFromSchema,
|
|
@@ -11,18 +13,18 @@ import {
|
|
|
11
13
|
getUiOptions,
|
|
12
14
|
hashObject,
|
|
13
15
|
ID_KEY,
|
|
14
|
-
IdSchema,
|
|
15
16
|
lookupFromFormContext,
|
|
16
|
-
mergeObjects,
|
|
17
17
|
ONE_OF_KEY,
|
|
18
18
|
PROPERTIES_KEY,
|
|
19
19
|
READONLY_KEY,
|
|
20
20
|
RJSFSchema,
|
|
21
21
|
Registry,
|
|
22
|
-
SchemaUtilsType,
|
|
23
22
|
StrictRJSFSchema,
|
|
23
|
+
toFieldPathId,
|
|
24
24
|
UI_OPTIONS_KEY,
|
|
25
|
+
UI_GLOBAL_OPTIONS_KEY,
|
|
25
26
|
UiSchema,
|
|
27
|
+
ITEMS_KEY,
|
|
26
28
|
} from '@rjsf/utils';
|
|
27
29
|
import cloneDeep from 'lodash/cloneDeep';
|
|
28
30
|
import each from 'lodash/each';
|
|
@@ -38,6 +40,7 @@ import isObject from 'lodash/isObject';
|
|
|
38
40
|
import isPlainObject from 'lodash/isPlainObject';
|
|
39
41
|
import isString from 'lodash/isString';
|
|
40
42
|
import isUndefined from 'lodash/isUndefined';
|
|
43
|
+
import last from 'lodash/last';
|
|
41
44
|
import set from 'lodash/set';
|
|
42
45
|
|
|
43
46
|
/** The enumeration of the three different Layout GridTemplate type values
|
|
@@ -101,10 +104,6 @@ export const LAYOUT_GRID_UI_OPTION = 'layoutGrid';
|
|
|
101
104
|
*/
|
|
102
105
|
export const LAYOUT_GRID_OPTION = `ui:${LAYOUT_GRID_UI_OPTION}`;
|
|
103
106
|
|
|
104
|
-
/** The constant representing the global UI Options object potentially contained within the `uiSchema`
|
|
105
|
-
*/
|
|
106
|
-
export const UI_GLOBAL_OPTIONS = 'ui:global_options';
|
|
107
|
-
|
|
108
107
|
/** Type used to return options list and whether it has a discriminator */
|
|
109
108
|
type OneOfOptionsInfoType<S extends StrictRJSFSchema = RJSFSchema> = { options: S[]; hasDiscriminator: boolean };
|
|
110
109
|
|
|
@@ -133,6 +132,15 @@ function getNonNullishValue<T = unknown>(value?: T, fallback?: T): T | undefined
|
|
|
133
132
|
return value ?? fallback;
|
|
134
133
|
}
|
|
135
134
|
|
|
135
|
+
/** Detects if a `str` is made up entirely of numeric characters
|
|
136
|
+
*
|
|
137
|
+
* @param str - The string to check to see if it is a numeric index
|
|
138
|
+
* @return - True if the string consists entirely of numeric characters
|
|
139
|
+
*/
|
|
140
|
+
function isNumericIndex(str: string) {
|
|
141
|
+
return /^\d+?$/.test(str); // Matches positive integers
|
|
142
|
+
}
|
|
143
|
+
|
|
136
144
|
/** The `LayoutGridField` will render a schema, uiSchema and formData combination out into a GridTemplate in the shape
|
|
137
145
|
* described in the uiSchema. To define the grid to use to render the elements within a field in the schema, provide in
|
|
138
146
|
* the uiSchema for that field the object contained under a `ui:layoutGrid` element. E.g. (as a JSON object):
|
|
@@ -386,7 +394,7 @@ export default class LayoutGridField<
|
|
|
386
394
|
schemaReadonly?: boolean,
|
|
387
395
|
forceReadonly?: boolean,
|
|
388
396
|
) {
|
|
389
|
-
const globalUiOptions = get(uiSchema, [
|
|
397
|
+
const globalUiOptions = get(uiSchema, [UI_GLOBAL_OPTIONS_KEY], {});
|
|
390
398
|
const localUiSchema = get(uiSchema, field);
|
|
391
399
|
const localUiOptions = { ...get(localUiSchema, [UI_OPTIONS_KEY], {}), ...uiProps, ...globalUiOptions };
|
|
392
400
|
const fieldUiSchema = { ...localUiSchema };
|
|
@@ -395,7 +403,7 @@ export default class LayoutGridField<
|
|
|
395
403
|
}
|
|
396
404
|
if (!isEmpty(globalUiOptions)) {
|
|
397
405
|
// pass the global uiOptions down to the field uiSchema so that they can be applied to all nested fields
|
|
398
|
-
set(fieldUiSchema, [
|
|
406
|
+
set(fieldUiSchema, [UI_GLOBAL_OPTIONS_KEY], globalUiOptions);
|
|
399
407
|
}
|
|
400
408
|
let { readonly: uiReadonly } = getUiOptions<T, S, F>(fieldUiSchema);
|
|
401
409
|
if (forceReadonly === true || (isUndefined(uiReadonly) && schemaReadonly === true)) {
|
|
@@ -478,25 +486,46 @@ export default class LayoutGridField<
|
|
|
478
486
|
return { children: children as LayoutGridSchemaType[], gridProps };
|
|
479
487
|
}
|
|
480
488
|
|
|
481
|
-
/**
|
|
482
|
-
*
|
|
489
|
+
/** Computes the `rawSchema` and `fieldPathId` for a `schema` and a `potentialIndex`. If the `schema` is of type array,
|
|
490
|
+
* has an `ITEMS_KEY` element and `potentialIndex` represents a numeric value, the element at `ITEMS_KEY` is checked
|
|
491
|
+
* to see if it is an array. If it is AND the `potentialIndex`th element is available, it is used as the `rawSchema`,
|
|
492
|
+
* otherwise the last value of the element is used. If it is not, then the element is used as the `rawSchema`. In
|
|
493
|
+
* either case, an `fieldPathId` is computed for the array index. If the `schema` does not represent an array or the
|
|
494
|
+
* `potentialIndex` is not a numeric value, then `rawSchema` is returned as undefined and given `fieldPathId` is returned
|
|
495
|
+
* as is.
|
|
483
496
|
*
|
|
484
|
-
* @param
|
|
485
|
-
* @param
|
|
486
|
-
* @param
|
|
487
|
-
* @
|
|
488
|
-
* @param [idSeparator] - The param to pass into the `toIdSchema` util which will use it to join the `idSchema` paths
|
|
489
|
-
* @returns - The generated `idSchema` for the `schema`
|
|
497
|
+
* @param schema - The schema to generate the fieldPathId for
|
|
498
|
+
* @param fieldPathId - The FieldPathId for the schema
|
|
499
|
+
* @param potentialIndex - A string containing a potential index
|
|
500
|
+
* @returns - An object containing the `rawSchema` and `fieldPathId` of an array item, otherwise an undefined `rawSchema`
|
|
490
501
|
*/
|
|
491
|
-
static
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
502
|
+
static computeArraySchemasIfPresent<S extends StrictRJSFSchema = RJSFSchema>(
|
|
503
|
+
schema: S | undefined,
|
|
504
|
+
fieldPathId: FieldPathId,
|
|
505
|
+
potentialIndex: string,
|
|
506
|
+
): {
|
|
507
|
+
rawSchema?: S;
|
|
508
|
+
fieldPathId: FieldPathId;
|
|
509
|
+
} {
|
|
510
|
+
let rawSchema: S | undefined;
|
|
511
|
+
if (isNumericIndex(potentialIndex) && schema && schema?.type === 'array' && has(schema, ITEMS_KEY)) {
|
|
512
|
+
const index = Number(potentialIndex);
|
|
513
|
+
const items = schema[ITEMS_KEY];
|
|
514
|
+
if (Array.isArray(items)) {
|
|
515
|
+
if (index > items.length) {
|
|
516
|
+
rawSchema = last(items) as S;
|
|
517
|
+
} else {
|
|
518
|
+
rawSchema = items[index] as S;
|
|
519
|
+
}
|
|
520
|
+
} else {
|
|
521
|
+
rawSchema = items as S;
|
|
522
|
+
}
|
|
523
|
+
fieldPathId = {
|
|
524
|
+
[ID_KEY]: fieldPathId[ID_KEY],
|
|
525
|
+
path: [...fieldPathId.path.slice(0, fieldPathId.path.length - 1), index],
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
return { rawSchema, fieldPathId };
|
|
500
529
|
}
|
|
501
530
|
|
|
502
531
|
/** Given a `dottedPath` to a field in the `initialSchema`, iterate through each individual path in the schema until
|
|
@@ -504,31 +533,30 @@ export default class LayoutGridField<
|
|
|
504
533
|
* element in the path. If the leaf schema element happens to be a oneOf/anyOf then also return the oneOf/anyOf as
|
|
505
534
|
* `options`.
|
|
506
535
|
*
|
|
507
|
-
* @param
|
|
536
|
+
* @param registry - The registry
|
|
508
537
|
* @param dottedPath - The dotted-path to the field for which to get the schema
|
|
509
538
|
* @param initialSchema - The initial schema to start the search from
|
|
510
539
|
* @param formData - The formData, useful for resolving a oneOf/anyOf selection in the path hierarchy
|
|
511
|
-
* @param
|
|
512
|
-
* @param [idSeparator] - The param to pass into the `toIdSchema` util which will use it to join the `idSchema` paths
|
|
540
|
+
* @param initialFieldIdPath - The initial fieldPathId to start the search from
|
|
513
541
|
* @returns - An object containing the destination schema, isRequired and isReadonly flags for the field and options
|
|
514
542
|
* info if a oneOf/anyOf
|
|
515
543
|
*/
|
|
516
544
|
static getSchemaDetailsForField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
517
|
-
|
|
545
|
+
registry: Registry<T, S, F>,
|
|
518
546
|
dottedPath: string,
|
|
519
547
|
initialSchema: S,
|
|
520
548
|
formData: FieldProps<T, S, F>['formData'],
|
|
521
|
-
|
|
522
|
-
idSeparator?: string,
|
|
549
|
+
initialFieldIdPath: FieldPathId,
|
|
523
550
|
): {
|
|
524
551
|
schema?: S;
|
|
525
552
|
isRequired: boolean;
|
|
526
553
|
isReadonly?: boolean;
|
|
527
554
|
optionsInfo?: OneOfOptionsInfoType<S>;
|
|
528
|
-
|
|
555
|
+
fieldPathId: FieldPathId;
|
|
529
556
|
} {
|
|
557
|
+
const { schemaUtils, globalFormOptions } = registry;
|
|
530
558
|
let rawSchema: S = initialSchema;
|
|
531
|
-
let
|
|
559
|
+
let fieldPathId = initialFieldIdPath;
|
|
532
560
|
const parts: string[] = dottedPath.split('.');
|
|
533
561
|
const leafPath: string | undefined = parts.pop(); // pop off the last element in the list as the leaf
|
|
534
562
|
let schema: S | undefined = schemaUtils.retrieveSchema(rawSchema, formData); // always returns an object
|
|
@@ -538,24 +566,18 @@ export default class LayoutGridField<
|
|
|
538
566
|
// For all the remaining path parts
|
|
539
567
|
parts.forEach((part) => {
|
|
540
568
|
// dive into the properties of the current schema (when it exists) and get the schema for the next part
|
|
569
|
+
fieldPathId = toFieldPathId(part, globalFormOptions, fieldPathId);
|
|
541
570
|
if (has(schema, PROPERTIES_KEY)) {
|
|
542
571
|
rawSchema = get(schema, [PROPERTIES_KEY, part], {}) as S;
|
|
543
|
-
idSchema = get(idSchema, part, {}) as IdSchema<T>;
|
|
544
572
|
} else if (schema && (has(schema, ONE_OF_KEY) || has(schema, ANY_OF_KEY))) {
|
|
545
573
|
const xxx = has(schema, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY;
|
|
546
574
|
// When the schema represents a oneOf/anyOf, find the selected schema for it and grab the inner part
|
|
547
575
|
const selectedSchema = schemaUtils.findSelectedOptionInXxxOf(schema, part, xxx, innerData);
|
|
548
|
-
const selectedIdSchema = LayoutGridField.getIdSchema<T, S, F>(
|
|
549
|
-
schemaUtils,
|
|
550
|
-
idSchema,
|
|
551
|
-
formData,
|
|
552
|
-
selectedSchema,
|
|
553
|
-
idSeparator,
|
|
554
|
-
);
|
|
555
576
|
rawSchema = get(selectedSchema, [PROPERTIES_KEY, part], {}) as S;
|
|
556
|
-
idSchema = get(selectedIdSchema, part, {}) as IdSchema<T>;
|
|
557
577
|
} else {
|
|
558
|
-
|
|
578
|
+
const result = LayoutGridField.computeArraySchemasIfPresent<S>(schema, fieldPathId, part);
|
|
579
|
+
rawSchema = result.rawSchema ?? ({} as S);
|
|
580
|
+
fieldPathId = result.fieldPathId;
|
|
559
581
|
}
|
|
560
582
|
// Now drill into the innerData for the part, returning an empty object by default if it doesn't exist
|
|
561
583
|
innerData = get(innerData, part, {}) as T;
|
|
@@ -576,16 +598,19 @@ export default class LayoutGridField<
|
|
|
576
598
|
const xxx = has(schema, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY;
|
|
577
599
|
// Grab the selected schema for the oneOf/anyOf value for the leafPath using the innerData
|
|
578
600
|
schema = schemaUtils.findSelectedOptionInXxxOf(schema, leafPath, xxx, innerData);
|
|
579
|
-
// Generate the idSchema for the oneOf/anyOf value then merge with the existing `idSchema`
|
|
580
|
-
const rawIdSchema = LayoutGridField.getIdSchema<T, S, F>(schemaUtils, idSchema, formData, schema, idSeparator);
|
|
581
|
-
idSchema = mergeObjects(rawIdSchema, idSchema) as IdSchema<T>;
|
|
582
601
|
}
|
|
602
|
+
fieldPathId = toFieldPathId(leafPath, globalFormOptions, fieldPathId);
|
|
583
603
|
isRequired = schema !== undefined && Array.isArray(schema.required) && includes(schema.required, leafPath);
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
604
|
+
const result = LayoutGridField.computeArraySchemasIfPresent<S>(schema, fieldPathId, leafPath);
|
|
605
|
+
if (result.rawSchema) {
|
|
606
|
+
schema = result.rawSchema;
|
|
607
|
+
fieldPathId = result.fieldPathId;
|
|
608
|
+
} else {
|
|
609
|
+
// Now grab the schema from the leafPath of the current schema properties
|
|
610
|
+
schema = get(schema, [PROPERTIES_KEY, leafPath]) as S | undefined;
|
|
611
|
+
// Resolve any `$ref`s for the current schema
|
|
612
|
+
schema = schema ? schemaUtils.retrieveSchema(schema) : schema;
|
|
613
|
+
}
|
|
589
614
|
isReadonly = getNonNullishValue(schema?.readOnly, isReadonly);
|
|
590
615
|
if (schema && (has(schema, ONE_OF_KEY) || has(schema, ANY_OF_KEY))) {
|
|
591
616
|
const xxx = has(schema, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY;
|
|
@@ -595,7 +620,7 @@ export default class LayoutGridField<
|
|
|
595
620
|
}
|
|
596
621
|
}
|
|
597
622
|
|
|
598
|
-
return { schema, isRequired, isReadonly, optionsInfo,
|
|
623
|
+
return { schema, isRequired, isReadonly, optionsInfo, fieldPathId };
|
|
599
624
|
}
|
|
600
625
|
|
|
601
626
|
/** Gets the custom render component from the `render`, by either determining that it is either already a function or
|
|
@@ -640,7 +665,7 @@ export default class LayoutGridField<
|
|
|
640
665
|
if (isString(gridSchema) || isUndefined(gridSchema)) {
|
|
641
666
|
name = gridSchema ?? '';
|
|
642
667
|
} else {
|
|
643
|
-
const { name: innerName, render, ...innerProps } = gridSchema;
|
|
668
|
+
const { name: innerName = '', render, ...innerProps } = gridSchema;
|
|
644
669
|
name = innerName;
|
|
645
670
|
uiProps = innerProps;
|
|
646
671
|
if (!isEmpty(uiProps)) {
|
|
@@ -676,19 +701,17 @@ export default class LayoutGridField<
|
|
|
676
701
|
* elements, they will then be passed on to the `onChange` handler of the `LayoutFieldGrid`.
|
|
677
702
|
*
|
|
678
703
|
* @param dottedPath - The dotted-path to the field for which to generate the onChange handler
|
|
679
|
-
* @returns - The `onChange` handling function for the `dottedPath` field
|
|
704
|
+
* @returns - The `onChange` handling function for the `dottedPath` field of the `schemaType` type
|
|
680
705
|
*/
|
|
681
706
|
onFieldChange = (dottedPath: string) => {
|
|
682
|
-
return (value:
|
|
683
|
-
const { onChange, errorSchema
|
|
684
|
-
const newFormData = cloneDeep(formData || ({} as T));
|
|
707
|
+
return (value: T | undefined, path: FieldPathList, errSchema?: ErrorSchema<T>, id?: string) => {
|
|
708
|
+
const { onChange, errorSchema } = this.props;
|
|
685
709
|
let newErrorSchema = errorSchema;
|
|
686
710
|
if (errSchema && errorSchema) {
|
|
687
711
|
newErrorSchema = cloneDeep(errorSchema);
|
|
688
712
|
set(newErrorSchema, dottedPath, errSchema);
|
|
689
713
|
}
|
|
690
|
-
|
|
691
|
-
onChange(newFormData, newErrorSchema, id);
|
|
714
|
+
onChange(value, path, newErrorSchema, id);
|
|
692
715
|
};
|
|
693
716
|
};
|
|
694
717
|
|
|
@@ -792,21 +815,21 @@ export default class LayoutGridField<
|
|
|
792
815
|
);
|
|
793
816
|
}
|
|
794
817
|
|
|
795
|
-
/** Iterates through all the `
|
|
818
|
+
/** Iterates through all the `childrenLayoutGrfieldPathId`, rendering a nested `LayoutGridField` for each item in the
|
|
796
819
|
* list, passing all the props for the current `LayoutGridField` along, updating the `schema` by calling
|
|
797
820
|
* `retrieveSchema()` on it to resolve any `$ref`s. In addition to the updated `schema`, each item in
|
|
798
|
-
* `
|
|
821
|
+
* `childrenLayoutGrfieldPathId` is passed as `layoutGridSchema`.
|
|
799
822
|
*
|
|
800
|
-
* @param
|
|
823
|
+
* @param childrenLayoutGrfieldPathId - The list of strings or objects that represents the configurations for the
|
|
801
824
|
* children fields
|
|
802
825
|
* @returns - The nested `LayoutGridField`s
|
|
803
826
|
*/
|
|
804
|
-
renderChildren(
|
|
827
|
+
renderChildren(childrenLayoutGrfieldPathId: LayoutGridSchemaType[]) {
|
|
805
828
|
const { registry, schema: rawSchema, formData } = this.props;
|
|
806
829
|
const { schemaUtils } = registry;
|
|
807
830
|
const schema = schemaUtils.retrieveSchema(rawSchema, formData);
|
|
808
831
|
|
|
809
|
-
return
|
|
832
|
+
return childrenLayoutGrfieldPathId.map((layoutGridSchema) => (
|
|
810
833
|
<LayoutGridField<T, S, F>
|
|
811
834
|
{...this.props}
|
|
812
835
|
key={`layoutGrid-${hashObject(layoutGridSchema)}`}
|
|
@@ -822,7 +845,7 @@ export default class LayoutGridField<
|
|
|
822
845
|
* specified props for that component. If `name` exists, we take the name, the initial & root schemas and the formData
|
|
823
846
|
* and get the destination schema, is required state and optional oneOf/anyOf options for it. If the destination
|
|
824
847
|
* schema was located along with oneOf/anyOf options then a `LayoutMultiSchemaField` will be rendered with the
|
|
825
|
-
* `uiSchema`, `errorSchema`, `
|
|
848
|
+
* `uiSchema`, `errorSchema`, `fieldPathId` and `formData` drilled down to the dotted-path field, spreading any other
|
|
826
849
|
* props from `gridSchema` into the `ui:options`. If the destination schema located without any oneOf/anyOf options,
|
|
827
850
|
* then a `SchemaField` will be rendered with the same props as mentioned in the previous sentence. If no destination
|
|
828
851
|
* schema was located, but a custom render component was found, then it will be rendered with many of the non-event
|
|
@@ -836,17 +859,16 @@ export default class LayoutGridField<
|
|
|
836
859
|
schema: initialSchema,
|
|
837
860
|
uiSchema,
|
|
838
861
|
errorSchema,
|
|
839
|
-
|
|
862
|
+
fieldPathId,
|
|
840
863
|
onBlur,
|
|
841
864
|
onFocus,
|
|
842
865
|
formData,
|
|
843
866
|
readonly,
|
|
844
867
|
registry,
|
|
845
|
-
idSeparator,
|
|
846
868
|
layoutGridSchema, // Used to pull this out of otherProps since we don't want to pass it through
|
|
847
869
|
...otherProps
|
|
848
870
|
} = this.props;
|
|
849
|
-
const { fields
|
|
871
|
+
const { fields } = registry;
|
|
850
872
|
const { SchemaField, LayoutMultiSchemaField } = fields;
|
|
851
873
|
const uiComponentProps = LayoutGridField.computeUIComponentPropsFromGridSchema(registry, gridSchema);
|
|
852
874
|
if (uiComponentProps.rendered) {
|
|
@@ -858,15 +880,8 @@ export default class LayoutGridField<
|
|
|
858
880
|
isRequired,
|
|
859
881
|
isReadonly,
|
|
860
882
|
optionsInfo,
|
|
861
|
-
|
|
862
|
-
} = LayoutGridField.getSchemaDetailsForField<T, S, F>(
|
|
863
|
-
schemaUtils,
|
|
864
|
-
name,
|
|
865
|
-
initialSchema,
|
|
866
|
-
formData,
|
|
867
|
-
idSchema,
|
|
868
|
-
idSeparator,
|
|
869
|
-
);
|
|
883
|
+
fieldPathId: fieldIdSchema,
|
|
884
|
+
} = LayoutGridField.getSchemaDetailsForField<T, S, F>(registry, name, initialSchema, formData, fieldPathId);
|
|
870
885
|
|
|
871
886
|
if (schema) {
|
|
872
887
|
const Field = optionsInfo?.hasDiscriminator ? LayoutMultiSchemaField : SchemaField;
|
|
@@ -897,8 +912,7 @@ export default class LayoutGridField<
|
|
|
897
912
|
schema={schema}
|
|
898
913
|
uiSchema={fieldUiSchema}
|
|
899
914
|
errorSchema={get(errorSchema, name)}
|
|
900
|
-
|
|
901
|
-
idSeparator={idSeparator}
|
|
915
|
+
fieldPathId={fieldIdSchema}
|
|
902
916
|
formData={get(formData, name)}
|
|
903
917
|
onChange={this.onFieldChange(name)}
|
|
904
918
|
onBlur={onBlur}
|
|
@@ -921,8 +935,7 @@ export default class LayoutGridField<
|
|
|
921
935
|
errorSchema={errorSchema}
|
|
922
936
|
uiSchema={uiSchema}
|
|
923
937
|
schema={initialSchema}
|
|
924
|
-
|
|
925
|
-
idSeparator={idSeparator}
|
|
938
|
+
fieldPathId={fieldPathId}
|
|
926
939
|
onBlur={onBlur}
|
|
927
940
|
onFocus={onFocus}
|
|
928
941
|
registry={registry}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
TemplatesType,
|
|
10
10
|
} from '@rjsf/utils';
|
|
11
11
|
|
|
12
|
-
/** The `LayoutHeaderField` component renders a `TitleFieldTemplate` with an `id` derived from the `
|
|
12
|
+
/** The `LayoutHeaderField` component renders a `TitleFieldTemplate` with an `id` derived from the `fieldPathId`
|
|
13
13
|
* and whether it is `required` from the props. The `title` is derived from the props as follows:
|
|
14
14
|
* - If there is a title in the `uiSchema`, it is displayed
|
|
15
15
|
* - Else, if there is an explicit `title` passed in the props, it is displayed
|
|
@@ -23,7 +23,7 @@ export default function LayoutHeaderField<
|
|
|
23
23
|
S extends StrictRJSFSchema = RJSFSchema,
|
|
24
24
|
F extends FormContextType = any,
|
|
25
25
|
>(props: FieldProps<T, S, F>) {
|
|
26
|
-
const {
|
|
26
|
+
const { fieldPathId, title, schema, uiSchema, required, registry, name } = props;
|
|
27
27
|
const options = getUiOptions<T, S, F>(uiSchema, registry.globalUiOptions);
|
|
28
28
|
const { title: uiTitle } = options;
|
|
29
29
|
const { title: schemaTitle } = schema;
|
|
@@ -38,7 +38,7 @@ export default function LayoutHeaderField<
|
|
|
38
38
|
);
|
|
39
39
|
return (
|
|
40
40
|
<TitleFieldTemplate
|
|
41
|
-
id={titleId
|
|
41
|
+
id={titleId(fieldPathId)}
|
|
42
42
|
title={fieldTitle}
|
|
43
43
|
required={required}
|
|
44
44
|
schema={schema}
|
|
@@ -96,7 +96,7 @@ export default function LayoutMultiSchemaField<
|
|
|
96
96
|
baseType,
|
|
97
97
|
disabled = false,
|
|
98
98
|
formData,
|
|
99
|
-
|
|
99
|
+
fieldPathId,
|
|
100
100
|
onBlur,
|
|
101
101
|
onChange,
|
|
102
102
|
options,
|
|
@@ -113,7 +113,7 @@ export default function LayoutMultiSchemaField<
|
|
|
113
113
|
} = props;
|
|
114
114
|
const { widgets, schemaUtils, globalUiOptions } = registry;
|
|
115
115
|
const [enumOptions, setEnumOptions] = useState(computeEnumOptions(schema, options, schemaUtils, uiSchema, formData)!);
|
|
116
|
-
const id = get(
|
|
116
|
+
const id = get(fieldPathId, ID_KEY);
|
|
117
117
|
const discriminator = getDiscriminatorFieldFromSchema(schema);
|
|
118
118
|
const FieldErrorTemplate = getTemplate<'FieldErrorTemplate', T, S, F>('FieldErrorTemplate', registry, options);
|
|
119
119
|
const FieldTemplate = getTemplate<'FieldTemplate', T, S, F>('FieldTemplate', registry, options);
|
|
@@ -171,14 +171,15 @@ export default function LayoutMultiSchemaField<
|
|
|
171
171
|
if (newFormData) {
|
|
172
172
|
set(newFormData, selectorField, opt);
|
|
173
173
|
}
|
|
174
|
-
|
|
174
|
+
// Pass the component name in the path
|
|
175
|
+
onChange(newFormData, fieldPathId.path, undefined, id);
|
|
175
176
|
};
|
|
176
177
|
|
|
177
178
|
// filtering the options based on the type of widget because `selectField` does not recognize the `convertOther` prop
|
|
178
179
|
const widgetOptions = { enumOptions, ...uiOptions };
|
|
179
180
|
const errors =
|
|
180
181
|
!hideFieldError && rawErrors.length > 0 ? (
|
|
181
|
-
<FieldErrorTemplate
|
|
182
|
+
<FieldErrorTemplate fieldPathId={fieldPathId} schema={schema} errors={rawErrors} registry={registry} />
|
|
182
183
|
) : undefined;
|
|
183
184
|
const ignored = (value: string) => noop;
|
|
184
185
|
|
|
@@ -189,7 +190,6 @@ export default function LayoutMultiSchemaField<
|
|
|
189
190
|
label={(title || schema.title) ?? ''}
|
|
190
191
|
disabled={disabled || (Array.isArray(enumOptions) && isEmpty(enumOptions))}
|
|
191
192
|
uiSchema={uiSchema}
|
|
192
|
-
formContext={formContext}
|
|
193
193
|
required={required}
|
|
194
194
|
readonly={!!readonly}
|
|
195
195
|
registry={registry}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
FieldProps,
|
|
10
10
|
FormContextType,
|
|
11
11
|
getDiscriminatorFieldFromSchema,
|
|
12
|
+
getTemplate,
|
|
12
13
|
getUiOptions,
|
|
13
14
|
getWidget,
|
|
14
15
|
mergeSchemas,
|
|
@@ -64,7 +65,7 @@ class AnyOfField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
64
65
|
* @param prevState - The previous `AnyOfFieldState` for this template
|
|
65
66
|
*/
|
|
66
67
|
componentDidUpdate(prevProps: Readonly<FieldProps<T, S, F>>, prevState: Readonly<AnyOfFieldState>) {
|
|
67
|
-
const { formData, options,
|
|
68
|
+
const { formData, options, fieldPathId } = this.props;
|
|
68
69
|
const { selectedOption } = this.state;
|
|
69
70
|
let newState = this.state;
|
|
70
71
|
if (!deepEquals(prevProps.options, options)) {
|
|
@@ -75,7 +76,7 @@ class AnyOfField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
75
76
|
const retrievedOptions = options.map((opt: S) => schemaUtils.retrieveSchema(opt, formData));
|
|
76
77
|
newState = { selectedOption, retrievedOptions };
|
|
77
78
|
}
|
|
78
|
-
if (!deepEquals(formData, prevProps.formData) &&
|
|
79
|
+
if (!deepEquals(formData, prevProps.formData) && fieldPathId.$id === prevProps.fieldPathId.$id) {
|
|
79
80
|
const { retrievedOptions } = newState;
|
|
80
81
|
const matchingOption = this.getMatchingOption(selectedOption, formData, retrievedOptions);
|
|
81
82
|
|
|
@@ -113,7 +114,7 @@ class AnyOfField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
113
114
|
*/
|
|
114
115
|
onOptionChange = (option?: string) => {
|
|
115
116
|
const { selectedOption, retrievedOptions } = this.state;
|
|
116
|
-
const { formData, onChange, registry } = this.props;
|
|
117
|
+
const { formData, onChange, registry, fieldPathId } = this.props;
|
|
117
118
|
const { schemaUtils } = registry;
|
|
118
119
|
const intOption = option !== undefined ? parseInt(option, 10) : -1;
|
|
119
120
|
if (intOption === selectedOption) {
|
|
@@ -130,13 +131,13 @@ class AnyOfField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
this.setState({ selectedOption: intOption }, () => {
|
|
133
|
-
onChange(newFormData, undefined, this.getFieldId());
|
|
134
|
+
onChange(newFormData, fieldPathId.path, undefined, this.getFieldId());
|
|
134
135
|
});
|
|
135
136
|
};
|
|
136
137
|
|
|
137
138
|
getFieldId() {
|
|
138
|
-
const {
|
|
139
|
-
return `${
|
|
139
|
+
const { fieldPathId, schema } = this.props;
|
|
140
|
+
return `${fieldPathId.$id}${schema.oneOf ? '__oneof_select' : '__anyof_select'}`;
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
/** Renders the `AnyOfField` selector along with a `SchemaField` for the value of the `formData`
|
|
@@ -157,6 +158,12 @@ class AnyOfField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
157
158
|
|
|
158
159
|
const { widgets, fields, translateString, globalUiOptions, schemaUtils } = registry;
|
|
159
160
|
const { SchemaField: _SchemaField } = fields;
|
|
161
|
+
const MultiSchemaFieldTemplate = getTemplate<'MultiSchemaFieldTemplate', T, S, F>(
|
|
162
|
+
'MultiSchemaFieldTemplate',
|
|
163
|
+
registry,
|
|
164
|
+
globalUiOptions,
|
|
165
|
+
);
|
|
166
|
+
|
|
160
167
|
const { selectedOption, retrievedOptions } = this.state;
|
|
161
168
|
const {
|
|
162
169
|
widget = 'select',
|
|
@@ -215,36 +222,45 @@ class AnyOfField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
|
|
|
215
222
|
};
|
|
216
223
|
});
|
|
217
224
|
|
|
225
|
+
const selector = (
|
|
226
|
+
<Widget
|
|
227
|
+
id={this.getFieldId()}
|
|
228
|
+
name={`${name}${schema.oneOf ? '__oneof_select' : '__anyof_select'}`}
|
|
229
|
+
schema={{ type: 'number', default: 0 } as S}
|
|
230
|
+
onChange={this.onOptionChange}
|
|
231
|
+
onBlur={onBlur}
|
|
232
|
+
onFocus={onFocus}
|
|
233
|
+
disabled={disabled || isEmpty(enumOptions)}
|
|
234
|
+
multiple={false}
|
|
235
|
+
rawErrors={rawErrors}
|
|
236
|
+
errorSchema={fieldErrorSchema}
|
|
237
|
+
value={selectedOption >= 0 ? selectedOption : undefined}
|
|
238
|
+
options={{ enumOptions, ...uiOptions }}
|
|
239
|
+
registry={registry}
|
|
240
|
+
formContext={formContext}
|
|
241
|
+
placeholder={placeholder}
|
|
242
|
+
autocomplete={autocomplete}
|
|
243
|
+
autofocus={autofocus}
|
|
244
|
+
label={title ?? name}
|
|
245
|
+
hideLabel={!displayLabel}
|
|
246
|
+
readonly={readonly}
|
|
247
|
+
/>
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
const optionsSchemaField =
|
|
251
|
+
(optionSchema && optionSchema.type !== 'null' && (
|
|
252
|
+
<_SchemaField {...this.props} schema={optionSchema} uiSchema={optionUiSchema} />
|
|
253
|
+
)) ||
|
|
254
|
+
null;
|
|
255
|
+
|
|
218
256
|
return (
|
|
219
|
-
<
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
onBlur={onBlur}
|
|
227
|
-
onFocus={onFocus}
|
|
228
|
-
disabled={disabled || isEmpty(enumOptions)}
|
|
229
|
-
multiple={false}
|
|
230
|
-
rawErrors={rawErrors}
|
|
231
|
-
errorSchema={fieldErrorSchema}
|
|
232
|
-
value={selectedOption >= 0 ? selectedOption : undefined}
|
|
233
|
-
options={{ enumOptions, ...uiOptions }}
|
|
234
|
-
registry={registry}
|
|
235
|
-
formContext={formContext}
|
|
236
|
-
placeholder={placeholder}
|
|
237
|
-
autocomplete={autocomplete}
|
|
238
|
-
autofocus={autofocus}
|
|
239
|
-
label={title ?? name}
|
|
240
|
-
hideLabel={!displayLabel}
|
|
241
|
-
readonly={readonly}
|
|
242
|
-
/>
|
|
243
|
-
</div>
|
|
244
|
-
{optionSchema && optionSchema.type !== 'null' && (
|
|
245
|
-
<_SchemaField {...this.props} schema={optionSchema} uiSchema={optionUiSchema} />
|
|
246
|
-
)}
|
|
247
|
-
</div>
|
|
257
|
+
<MultiSchemaFieldTemplate
|
|
258
|
+
schema={schema}
|
|
259
|
+
registry={registry}
|
|
260
|
+
uiSchema={uiSchema}
|
|
261
|
+
selector={selector}
|
|
262
|
+
optionSchemaField={optionsSchemaField}
|
|
263
|
+
/>
|
|
248
264
|
);
|
|
249
265
|
}
|
|
250
266
|
}
|
|
@@ -9,12 +9,12 @@ import { FieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf
|
|
|
9
9
|
function NullField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
10
10
|
props: FieldProps<T, S, F>,
|
|
11
11
|
) {
|
|
12
|
-
const { formData, onChange } = props;
|
|
12
|
+
const { name, formData, onChange } = props;
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
if (formData === undefined) {
|
|
15
|
-
onChange(null as unknown as T);
|
|
15
|
+
onChange(null as unknown as T, [name]);
|
|
16
16
|
}
|
|
17
|
-
}, [formData, onChange]);
|
|
17
|
+
}, [name, formData, onChange]);
|
|
18
18
|
|
|
19
19
|
return null;
|
|
20
20
|
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { useState, useCallback } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
asNumber,
|
|
4
|
+
ErrorSchema,
|
|
5
|
+
FieldPathList,
|
|
6
|
+
FieldProps,
|
|
7
|
+
FormContextType,
|
|
8
|
+
RJSFSchema,
|
|
9
|
+
StrictRJSFSchema,
|
|
10
|
+
} from '@rjsf/utils';
|
|
3
11
|
|
|
4
12
|
// Matches a string that ends in a . character, optionally followed by a sequence of
|
|
5
13
|
// digits followed by any number of 0 characters up until the end of the line.
|
|
@@ -44,7 +52,7 @@ function NumberField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
44
52
|
* @param value - The current value for the change occurring
|
|
45
53
|
*/
|
|
46
54
|
const handleChange = useCallback(
|
|
47
|
-
(value: FieldProps<T, S, F>['value'], errorSchema?: ErrorSchema<T>, id?: string) => {
|
|
55
|
+
(value: FieldProps<T, S, F>['value'], path: FieldPathList, errorSchema?: ErrorSchema<T>, id?: string) => {
|
|
48
56
|
// Cache the original value in component state
|
|
49
57
|
setLastValue(value);
|
|
50
58
|
|
|
@@ -62,7 +70,7 @@ function NumberField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
|
|
|
62
70
|
? asNumber(value.replace(trailingCharMatcher, ''))
|
|
63
71
|
: asNumber(value);
|
|
64
72
|
|
|
65
|
-
onChange(processed as unknown as T, errorSchema, id);
|
|
73
|
+
onChange(processed as unknown as T, path, errorSchema, id);
|
|
66
74
|
},
|
|
67
75
|
[onChange],
|
|
68
76
|
);
|