@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,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,20 +13,19 @@ 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
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
28
29
|
import each from 'lodash/each';
|
|
29
30
|
import flatten from 'lodash/flatten';
|
|
30
31
|
import get from 'lodash/get';
|
|
@@ -38,6 +39,7 @@ import isObject from 'lodash/isObject';
|
|
|
38
39
|
import isPlainObject from 'lodash/isPlainObject';
|
|
39
40
|
import isString from 'lodash/isString';
|
|
40
41
|
import isUndefined from 'lodash/isUndefined';
|
|
42
|
+
import last from 'lodash/last';
|
|
41
43
|
import set from 'lodash/set';
|
|
42
44
|
|
|
43
45
|
/** The enumeration of the three different Layout GridTemplate type values
|
|
@@ -101,10 +103,6 @@ export const LAYOUT_GRID_UI_OPTION = 'layoutGrid';
|
|
|
101
103
|
*/
|
|
102
104
|
export const LAYOUT_GRID_OPTION = `ui:${LAYOUT_GRID_UI_OPTION}`;
|
|
103
105
|
|
|
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
106
|
/** Type used to return options list and whether it has a discriminator */
|
|
109
107
|
type OneOfOptionsInfoType<S extends StrictRJSFSchema = RJSFSchema> = { options: S[]; hasDiscriminator: boolean };
|
|
110
108
|
|
|
@@ -133,6 +131,15 @@ function getNonNullishValue<T = unknown>(value?: T, fallback?: T): T | undefined
|
|
|
133
131
|
return value ?? fallback;
|
|
134
132
|
}
|
|
135
133
|
|
|
134
|
+
/** Detects if a `str` is made up entirely of numeric characters
|
|
135
|
+
*
|
|
136
|
+
* @param str - The string to check to see if it is a numeric index
|
|
137
|
+
* @return - True if the string consists entirely of numeric characters
|
|
138
|
+
*/
|
|
139
|
+
function isNumericIndex(str: string) {
|
|
140
|
+
return /^\d+?$/.test(str); // Matches positive integers
|
|
141
|
+
}
|
|
142
|
+
|
|
136
143
|
/** The `LayoutGridField` will render a schema, uiSchema and formData combination out into a GridTemplate in the shape
|
|
137
144
|
* described in the uiSchema. To define the grid to use to render the elements within a field in the schema, provide in
|
|
138
145
|
* the uiSchema for that field the object contained under a `ui:layoutGrid` element. E.g. (as a JSON object):
|
|
@@ -386,7 +393,7 @@ export default class LayoutGridField<
|
|
|
386
393
|
schemaReadonly?: boolean,
|
|
387
394
|
forceReadonly?: boolean,
|
|
388
395
|
) {
|
|
389
|
-
const globalUiOptions = get(uiSchema, [
|
|
396
|
+
const globalUiOptions = get(uiSchema, [UI_GLOBAL_OPTIONS_KEY], {});
|
|
390
397
|
const localUiSchema = get(uiSchema, field);
|
|
391
398
|
const localUiOptions = { ...get(localUiSchema, [UI_OPTIONS_KEY], {}), ...uiProps, ...globalUiOptions };
|
|
392
399
|
const fieldUiSchema = { ...localUiSchema };
|
|
@@ -395,7 +402,7 @@ export default class LayoutGridField<
|
|
|
395
402
|
}
|
|
396
403
|
if (!isEmpty(globalUiOptions)) {
|
|
397
404
|
// pass the global uiOptions down to the field uiSchema so that they can be applied to all nested fields
|
|
398
|
-
set(fieldUiSchema, [
|
|
405
|
+
set(fieldUiSchema, [UI_GLOBAL_OPTIONS_KEY], globalUiOptions);
|
|
399
406
|
}
|
|
400
407
|
let { readonly: uiReadonly } = getUiOptions<T, S, F>(fieldUiSchema);
|
|
401
408
|
if (forceReadonly === true || (isUndefined(uiReadonly) && schemaReadonly === true)) {
|
|
@@ -478,25 +485,46 @@ export default class LayoutGridField<
|
|
|
478
485
|
return { children: children as LayoutGridSchemaType[], gridProps };
|
|
479
486
|
}
|
|
480
487
|
|
|
481
|
-
/**
|
|
482
|
-
*
|
|
488
|
+
/** Computes the `rawSchema` and `fieldPathId` for a `schema` and a `potentialIndex`. If the `schema` is of type array,
|
|
489
|
+
* has an `ITEMS_KEY` element and `potentialIndex` represents a numeric value, the element at `ITEMS_KEY` is checked
|
|
490
|
+
* to see if it is an array. If it is AND the `potentialIndex`th element is available, it is used as the `rawSchema`,
|
|
491
|
+
* otherwise the last value of the element is used. If it is not, then the element is used as the `rawSchema`. In
|
|
492
|
+
* either case, an `fieldPathId` is computed for the array index. If the `schema` does not represent an array or the
|
|
493
|
+
* `potentialIndex` is not a numeric value, then `rawSchema` is returned as undefined and given `fieldPathId` is returned
|
|
494
|
+
* as is.
|
|
483
495
|
*
|
|
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`
|
|
496
|
+
* @param schema - The schema to generate the fieldPathId for
|
|
497
|
+
* @param fieldPathId - The FieldPathId for the schema
|
|
498
|
+
* @param potentialIndex - A string containing a potential index
|
|
499
|
+
* @returns - An object containing the `rawSchema` and `fieldPathId` of an array item, otherwise an undefined `rawSchema`
|
|
490
500
|
*/
|
|
491
|
-
static
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
501
|
+
static computeArraySchemasIfPresent<S extends StrictRJSFSchema = RJSFSchema>(
|
|
502
|
+
schema: S | undefined,
|
|
503
|
+
fieldPathId: FieldPathId,
|
|
504
|
+
potentialIndex: string,
|
|
505
|
+
): {
|
|
506
|
+
rawSchema?: S;
|
|
507
|
+
fieldPathId: FieldPathId;
|
|
508
|
+
} {
|
|
509
|
+
let rawSchema: S | undefined;
|
|
510
|
+
if (isNumericIndex(potentialIndex) && schema && schema?.type === 'array' && has(schema, ITEMS_KEY)) {
|
|
511
|
+
const index = Number(potentialIndex);
|
|
512
|
+
const items = schema[ITEMS_KEY];
|
|
513
|
+
if (Array.isArray(items)) {
|
|
514
|
+
if (index > items.length) {
|
|
515
|
+
rawSchema = last(items) as S;
|
|
516
|
+
} else {
|
|
517
|
+
rawSchema = items[index] as S;
|
|
518
|
+
}
|
|
519
|
+
} else {
|
|
520
|
+
rawSchema = items as S;
|
|
521
|
+
}
|
|
522
|
+
fieldPathId = {
|
|
523
|
+
[ID_KEY]: fieldPathId[ID_KEY],
|
|
524
|
+
path: [...fieldPathId.path.slice(0, fieldPathId.path.length - 1), index],
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
return { rawSchema, fieldPathId };
|
|
500
528
|
}
|
|
501
529
|
|
|
502
530
|
/** Given a `dottedPath` to a field in the `initialSchema`, iterate through each individual path in the schema until
|
|
@@ -504,31 +532,30 @@ export default class LayoutGridField<
|
|
|
504
532
|
* element in the path. If the leaf schema element happens to be a oneOf/anyOf then also return the oneOf/anyOf as
|
|
505
533
|
* `options`.
|
|
506
534
|
*
|
|
507
|
-
* @param
|
|
535
|
+
* @param registry - The registry
|
|
508
536
|
* @param dottedPath - The dotted-path to the field for which to get the schema
|
|
509
537
|
* @param initialSchema - The initial schema to start the search from
|
|
510
538
|
* @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
|
|
539
|
+
* @param initialFieldIdPath - The initial fieldPathId to start the search from
|
|
513
540
|
* @returns - An object containing the destination schema, isRequired and isReadonly flags for the field and options
|
|
514
541
|
* info if a oneOf/anyOf
|
|
515
542
|
*/
|
|
516
543
|
static getSchemaDetailsForField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
|
|
517
|
-
|
|
544
|
+
registry: Registry<T, S, F>,
|
|
518
545
|
dottedPath: string,
|
|
519
546
|
initialSchema: S,
|
|
520
547
|
formData: FieldProps<T, S, F>['formData'],
|
|
521
|
-
|
|
522
|
-
idSeparator?: string,
|
|
548
|
+
initialFieldIdPath: FieldPathId,
|
|
523
549
|
): {
|
|
524
550
|
schema?: S;
|
|
525
551
|
isRequired: boolean;
|
|
526
552
|
isReadonly?: boolean;
|
|
527
553
|
optionsInfo?: OneOfOptionsInfoType<S>;
|
|
528
|
-
|
|
554
|
+
fieldPathId: FieldPathId;
|
|
529
555
|
} {
|
|
556
|
+
const { schemaUtils, globalFormOptions } = registry;
|
|
530
557
|
let rawSchema: S = initialSchema;
|
|
531
|
-
let
|
|
558
|
+
let fieldPathId = initialFieldIdPath;
|
|
532
559
|
const parts: string[] = dottedPath.split('.');
|
|
533
560
|
const leafPath: string | undefined = parts.pop(); // pop off the last element in the list as the leaf
|
|
534
561
|
let schema: S | undefined = schemaUtils.retrieveSchema(rawSchema, formData); // always returns an object
|
|
@@ -538,24 +565,18 @@ export default class LayoutGridField<
|
|
|
538
565
|
// For all the remaining path parts
|
|
539
566
|
parts.forEach((part) => {
|
|
540
567
|
// dive into the properties of the current schema (when it exists) and get the schema for the next part
|
|
568
|
+
fieldPathId = toFieldPathId(part, globalFormOptions, fieldPathId);
|
|
541
569
|
if (has(schema, PROPERTIES_KEY)) {
|
|
542
570
|
rawSchema = get(schema, [PROPERTIES_KEY, part], {}) as S;
|
|
543
|
-
idSchema = get(idSchema, part, {}) as IdSchema<T>;
|
|
544
571
|
} else if (schema && (has(schema, ONE_OF_KEY) || has(schema, ANY_OF_KEY))) {
|
|
545
572
|
const xxx = has(schema, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY;
|
|
546
573
|
// When the schema represents a oneOf/anyOf, find the selected schema for it and grab the inner part
|
|
547
574
|
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
575
|
rawSchema = get(selectedSchema, [PROPERTIES_KEY, part], {}) as S;
|
|
556
|
-
idSchema = get(selectedIdSchema, part, {}) as IdSchema<T>;
|
|
557
576
|
} else {
|
|
558
|
-
|
|
577
|
+
const result = LayoutGridField.computeArraySchemasIfPresent<S>(schema, fieldPathId, part);
|
|
578
|
+
rawSchema = result.rawSchema ?? ({} as S);
|
|
579
|
+
fieldPathId = result.fieldPathId;
|
|
559
580
|
}
|
|
560
581
|
// Now drill into the innerData for the part, returning an empty object by default if it doesn't exist
|
|
561
582
|
innerData = get(innerData, part, {}) as T;
|
|
@@ -576,16 +597,19 @@ export default class LayoutGridField<
|
|
|
576
597
|
const xxx = has(schema, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY;
|
|
577
598
|
// Grab the selected schema for the oneOf/anyOf value for the leafPath using the innerData
|
|
578
599
|
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
600
|
}
|
|
601
|
+
fieldPathId = toFieldPathId(leafPath, globalFormOptions, fieldPathId);
|
|
583
602
|
isRequired = schema !== undefined && Array.isArray(schema.required) && includes(schema.required, leafPath);
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
603
|
+
const result = LayoutGridField.computeArraySchemasIfPresent<S>(schema, fieldPathId, leafPath);
|
|
604
|
+
if (result.rawSchema) {
|
|
605
|
+
schema = result.rawSchema;
|
|
606
|
+
fieldPathId = result.fieldPathId;
|
|
607
|
+
} else {
|
|
608
|
+
// Now grab the schema from the leafPath of the current schema properties
|
|
609
|
+
schema = get(schema, [PROPERTIES_KEY, leafPath]) as S | undefined;
|
|
610
|
+
// Resolve any `$ref`s for the current schema
|
|
611
|
+
schema = schema ? schemaUtils.retrieveSchema(schema) : schema;
|
|
612
|
+
}
|
|
589
613
|
isReadonly = getNonNullishValue(schema?.readOnly, isReadonly);
|
|
590
614
|
if (schema && (has(schema, ONE_OF_KEY) || has(schema, ANY_OF_KEY))) {
|
|
591
615
|
const xxx = has(schema, ONE_OF_KEY) ? ONE_OF_KEY : ANY_OF_KEY;
|
|
@@ -595,7 +619,7 @@ export default class LayoutGridField<
|
|
|
595
619
|
}
|
|
596
620
|
}
|
|
597
621
|
|
|
598
|
-
return { schema, isRequired, isReadonly, optionsInfo,
|
|
622
|
+
return { schema, isRequired, isReadonly, optionsInfo, fieldPathId };
|
|
599
623
|
}
|
|
600
624
|
|
|
601
625
|
/** Gets the custom render component from the `render`, by either determining that it is either already a function or
|
|
@@ -640,7 +664,7 @@ export default class LayoutGridField<
|
|
|
640
664
|
if (isString(gridSchema) || isUndefined(gridSchema)) {
|
|
641
665
|
name = gridSchema ?? '';
|
|
642
666
|
} else {
|
|
643
|
-
const { name: innerName, render, ...innerProps } = gridSchema;
|
|
667
|
+
const { name: innerName = '', render, ...innerProps } = gridSchema;
|
|
644
668
|
name = innerName;
|
|
645
669
|
uiProps = innerProps;
|
|
646
670
|
if (!isEmpty(uiProps)) {
|
|
@@ -676,19 +700,12 @@ export default class LayoutGridField<
|
|
|
676
700
|
* elements, they will then be passed on to the `onChange` handler of the `LayoutFieldGrid`.
|
|
677
701
|
*
|
|
678
702
|
* @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
|
|
703
|
+
* @returns - The `onChange` handling function for the `dottedPath` field of the `schemaType` type
|
|
680
704
|
*/
|
|
681
705
|
onFieldChange = (dottedPath: string) => {
|
|
682
|
-
return (value:
|
|
683
|
-
const { onChange
|
|
684
|
-
|
|
685
|
-
let newErrorSchema = errorSchema;
|
|
686
|
-
if (errSchema && errorSchema) {
|
|
687
|
-
newErrorSchema = cloneDeep(errorSchema);
|
|
688
|
-
set(newErrorSchema, dottedPath, errSchema);
|
|
689
|
-
}
|
|
690
|
-
set(newFormData as object, dottedPath, value);
|
|
691
|
-
onChange(newFormData, newErrorSchema, id);
|
|
706
|
+
return (value: T | undefined, path: FieldPathList, errSchema?: ErrorSchema<T>, id?: string) => {
|
|
707
|
+
const { onChange } = this.props;
|
|
708
|
+
onChange(value, path, errSchema, id);
|
|
692
709
|
};
|
|
693
710
|
};
|
|
694
711
|
|
|
@@ -792,21 +809,21 @@ export default class LayoutGridField<
|
|
|
792
809
|
);
|
|
793
810
|
}
|
|
794
811
|
|
|
795
|
-
/** Iterates through all the `
|
|
812
|
+
/** Iterates through all the `childrenLayoutGrfieldPathId`, rendering a nested `LayoutGridField` for each item in the
|
|
796
813
|
* list, passing all the props for the current `LayoutGridField` along, updating the `schema` by calling
|
|
797
814
|
* `retrieveSchema()` on it to resolve any `$ref`s. In addition to the updated `schema`, each item in
|
|
798
|
-
* `
|
|
815
|
+
* `childrenLayoutGrfieldPathId` is passed as `layoutGridSchema`.
|
|
799
816
|
*
|
|
800
|
-
* @param
|
|
817
|
+
* @param childrenLayoutGrfieldPathId - The list of strings or objects that represents the configurations for the
|
|
801
818
|
* children fields
|
|
802
819
|
* @returns - The nested `LayoutGridField`s
|
|
803
820
|
*/
|
|
804
|
-
renderChildren(
|
|
821
|
+
renderChildren(childrenLayoutGrfieldPathId: LayoutGridSchemaType[]) {
|
|
805
822
|
const { registry, schema: rawSchema, formData } = this.props;
|
|
806
823
|
const { schemaUtils } = registry;
|
|
807
824
|
const schema = schemaUtils.retrieveSchema(rawSchema, formData);
|
|
808
825
|
|
|
809
|
-
return
|
|
826
|
+
return childrenLayoutGrfieldPathId.map((layoutGridSchema) => (
|
|
810
827
|
<LayoutGridField<T, S, F>
|
|
811
828
|
{...this.props}
|
|
812
829
|
key={`layoutGrid-${hashObject(layoutGridSchema)}`}
|
|
@@ -822,7 +839,7 @@ export default class LayoutGridField<
|
|
|
822
839
|
* specified props for that component. If `name` exists, we take the name, the initial & root schemas and the formData
|
|
823
840
|
* and get the destination schema, is required state and optional oneOf/anyOf options for it. If the destination
|
|
824
841
|
* schema was located along with oneOf/anyOf options then a `LayoutMultiSchemaField` will be rendered with the
|
|
825
|
-
* `uiSchema`, `errorSchema`, `
|
|
842
|
+
* `uiSchema`, `errorSchema`, `fieldPathId` and `formData` drilled down to the dotted-path field, spreading any other
|
|
826
843
|
* props from `gridSchema` into the `ui:options`. If the destination schema located without any oneOf/anyOf options,
|
|
827
844
|
* then a `SchemaField` will be rendered with the same props as mentioned in the previous sentence. If no destination
|
|
828
845
|
* schema was located, but a custom render component was found, then it will be rendered with many of the non-event
|
|
@@ -836,17 +853,16 @@ export default class LayoutGridField<
|
|
|
836
853
|
schema: initialSchema,
|
|
837
854
|
uiSchema,
|
|
838
855
|
errorSchema,
|
|
839
|
-
|
|
856
|
+
fieldPathId,
|
|
840
857
|
onBlur,
|
|
841
858
|
onFocus,
|
|
842
859
|
formData,
|
|
843
860
|
readonly,
|
|
844
861
|
registry,
|
|
845
|
-
idSeparator,
|
|
846
862
|
layoutGridSchema, // Used to pull this out of otherProps since we don't want to pass it through
|
|
847
863
|
...otherProps
|
|
848
864
|
} = this.props;
|
|
849
|
-
const { fields
|
|
865
|
+
const { fields } = registry;
|
|
850
866
|
const { SchemaField, LayoutMultiSchemaField } = fields;
|
|
851
867
|
const uiComponentProps = LayoutGridField.computeUIComponentPropsFromGridSchema(registry, gridSchema);
|
|
852
868
|
if (uiComponentProps.rendered) {
|
|
@@ -858,15 +874,8 @@ export default class LayoutGridField<
|
|
|
858
874
|
isRequired,
|
|
859
875
|
isReadonly,
|
|
860
876
|
optionsInfo,
|
|
861
|
-
|
|
862
|
-
} = LayoutGridField.getSchemaDetailsForField<T, S, F>(
|
|
863
|
-
schemaUtils,
|
|
864
|
-
name,
|
|
865
|
-
initialSchema,
|
|
866
|
-
formData,
|
|
867
|
-
idSchema,
|
|
868
|
-
idSeparator,
|
|
869
|
-
);
|
|
877
|
+
fieldPathId: fieldIdSchema,
|
|
878
|
+
} = LayoutGridField.getSchemaDetailsForField<T, S, F>(registry, name, initialSchema, formData, fieldPathId);
|
|
870
879
|
|
|
871
880
|
if (schema) {
|
|
872
881
|
const Field = optionsInfo?.hasDiscriminator ? LayoutMultiSchemaField : SchemaField;
|
|
@@ -897,8 +906,7 @@ export default class LayoutGridField<
|
|
|
897
906
|
schema={schema}
|
|
898
907
|
uiSchema={fieldUiSchema}
|
|
899
908
|
errorSchema={get(errorSchema, name)}
|
|
900
|
-
|
|
901
|
-
idSeparator={idSeparator}
|
|
909
|
+
fieldPathId={fieldIdSchema}
|
|
902
910
|
formData={get(formData, name)}
|
|
903
911
|
onChange={this.onFieldChange(name)}
|
|
904
912
|
onBlur={onBlur}
|
|
@@ -921,8 +929,7 @@ export default class LayoutGridField<
|
|
|
921
929
|
errorSchema={errorSchema}
|
|
922
930
|
uiSchema={uiSchema}
|
|
923
931
|
schema={initialSchema}
|
|
924
|
-
|
|
925
|
-
idSeparator={idSeparator}
|
|
932
|
+
fieldPathId={fieldPathId}
|
|
926
933
|
onBlur={onBlur}
|
|
927
934
|
onFocus={onFocus}
|
|
928
935
|
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 { formData, onChange, fieldPathId } = props;
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
if (formData === undefined) {
|
|
15
|
-
onChange(null as unknown as T);
|
|
15
|
+
onChange(null as unknown as T, fieldPathId.path);
|
|
16
16
|
}
|
|
17
|
-
}, [formData, onChange]);
|
|
17
|
+
}, [fieldPathId, 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
|
);
|