@react-typed-forms/schemas 14.3.0 → 14.4.0
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/lib/controlDefinition.d.ts +16 -12
- package/lib/controlRender.d.ts +3 -1
- package/lib/index.cjs +111 -79
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +98 -79
- package/lib/index.js.map +1 -1
- package/lib/renderers.d.ts +3 -1
- package/package.json +1 -1
- package/src/controlDefinition.ts +74 -57
- package/src/controlRender.tsx +6 -3
- package/src/createFormRenderer.tsx +25 -13
- package/src/renderers.tsx +5 -2
- package/tsconfig.json +1 -1
package/lib/renderers.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export interface DefaultRenderers {
|
|
|
11
11
|
adornment: AdornmentRendererRegistration;
|
|
12
12
|
renderLayout: LayoutRendererRegistration;
|
|
13
13
|
visibility: VisibilityRendererRegistration;
|
|
14
|
+
renderText: (props: ReactNode) => ReactNode;
|
|
15
|
+
h: (type: any, props: any, ...children: any[]) => ReactElement;
|
|
14
16
|
}
|
|
15
17
|
export interface LayoutRendererRegistration {
|
|
16
18
|
type: "layout";
|
|
@@ -57,7 +59,7 @@ export interface AdornmentRendererRegistration {
|
|
|
57
59
|
}
|
|
58
60
|
export interface VisibilityRendererRegistration {
|
|
59
61
|
type: "visibility";
|
|
60
|
-
render: (props: VisibilityRendererProps) => ReactNode;
|
|
62
|
+
render: (props: VisibilityRendererProps, renderer: FormRenderer) => ReactNode;
|
|
61
63
|
}
|
|
62
64
|
export type RendererRegistration = DataRendererRegistration | GroupRendererRegistration | DisplayRendererRegistration | ActionRendererRegistration | LabelRendererRegistration | ArrayRendererRegistration | AdornmentRendererRegistration | LayoutRendererRegistration | VisibilityRendererRegistration;
|
|
63
65
|
export declare function isIconAdornment(a: ControlAdornment): a is IconAdornment;
|
package/package.json
CHANGED
package/src/controlDefinition.ts
CHANGED
|
@@ -356,8 +356,9 @@ export interface GridRenderer extends GroupRenderOptions {
|
|
|
356
356
|
columns?: number | null;
|
|
357
357
|
}
|
|
358
358
|
|
|
359
|
-
export interface
|
|
359
|
+
export interface TabsRenderOptions extends GroupRenderOptions {
|
|
360
360
|
type: GroupRenderType.Tabs;
|
|
361
|
+
contentClass?: string;
|
|
361
362
|
}
|
|
362
363
|
|
|
363
364
|
export interface SelectChildRenderer extends GroupRenderOptions {
|
|
@@ -444,7 +445,7 @@ export function isSelectChildRenderer(
|
|
|
444
445
|
|
|
445
446
|
export function isTabsRenderer(
|
|
446
447
|
options: GroupRenderOptions,
|
|
447
|
-
): options is
|
|
448
|
+
): options is TabsRenderOptions {
|
|
448
449
|
return options.type === GroupRenderType.Tabs;
|
|
449
450
|
}
|
|
450
451
|
|
|
@@ -545,63 +546,59 @@ export function isCheckEntryClasses(
|
|
|
545
546
|
|
|
546
547
|
export type ControlMap = { [k: string]: ControlDefinition };
|
|
547
548
|
|
|
548
|
-
export
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
) {
|
|
556
|
-
this.id = id;
|
|
557
|
-
this.definition = definition;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
getChildNodes(): FormNode[] {
|
|
561
|
-
if (this.overrideChildren) return this.overrideChildren;
|
|
562
|
-
let children = this.definition.children;
|
|
563
|
-
if (this.definition.childRefId) {
|
|
564
|
-
const ref = this.tree.controlMap[this.definition.childRefId];
|
|
565
|
-
children = ref?.children;
|
|
566
|
-
}
|
|
567
|
-
return (
|
|
568
|
-
children?.map(
|
|
569
|
-
(x, i) => new FormNode(this.id + "/" + i, x, this.tree, this),
|
|
570
|
-
) ?? []
|
|
571
|
-
);
|
|
572
|
-
}
|
|
549
|
+
export interface FormNode {
|
|
550
|
+
id: string;
|
|
551
|
+
definition: ControlDefinition;
|
|
552
|
+
tree: FormTree;
|
|
553
|
+
parent?: FormNode;
|
|
554
|
+
getChildNodes(dontFollowRef?: boolean): FormNode[];
|
|
555
|
+
}
|
|
573
556
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
);
|
|
582
|
-
}
|
|
557
|
+
export function defaultGetChildNodes(
|
|
558
|
+
parent: FormNode,
|
|
559
|
+
children?: ControlDefinition[] | null,
|
|
560
|
+
) {
|
|
561
|
+
return (
|
|
562
|
+
children?.map((x, i) => nodeForControl(x, parent.tree, i, parent)) ?? []
|
|
563
|
+
);
|
|
583
564
|
}
|
|
584
565
|
|
|
585
|
-
export interface FormTreeLookup
|
|
586
|
-
getForm(formId:
|
|
566
|
+
export interface FormTreeLookup {
|
|
567
|
+
getForm(formId: string): FormTree | undefined;
|
|
587
568
|
}
|
|
588
569
|
export interface FormTree extends FormTreeLookup {
|
|
589
570
|
rootNode: FormNode;
|
|
590
|
-
|
|
571
|
+
getChildrenForId(id: string, parent: FormNode): FormNode[];
|
|
591
572
|
}
|
|
592
573
|
|
|
574
|
+
export function wrapFormNode(
|
|
575
|
+
node: FormNode,
|
|
576
|
+
getChildren?: (dontFollowRef?: boolean) => FormNode[],
|
|
577
|
+
): FormNode {
|
|
578
|
+
return {
|
|
579
|
+
...node,
|
|
580
|
+
getChildNodes: getChildren ?? ((dfr) => node.getChildNodes(dfr)),
|
|
581
|
+
};
|
|
582
|
+
}
|
|
593
583
|
export function nodeForControl(
|
|
594
584
|
definition: ControlDefinition,
|
|
595
585
|
tree: FormTree,
|
|
596
586
|
indexOrId?: number | string,
|
|
597
587
|
parent?: FormNode,
|
|
598
588
|
): FormNode {
|
|
599
|
-
return
|
|
600
|
-
parent ? parent.id + "/" + indexOrId : "",
|
|
589
|
+
return {
|
|
590
|
+
id: parent ? parent.id + "/" + indexOrId : "",
|
|
601
591
|
definition,
|
|
602
592
|
tree,
|
|
603
593
|
parent,
|
|
604
|
-
|
|
594
|
+
getChildNodes(dontFollowRef?: boolean): FormNode[] {
|
|
595
|
+
let children = this.definition.children;
|
|
596
|
+
if (!dontFollowRef && this.definition.childRefId) {
|
|
597
|
+
return this.tree.getChildrenForId(this.definition.childRefId, this);
|
|
598
|
+
}
|
|
599
|
+
return defaultGetChildNodes(this, children);
|
|
600
|
+
},
|
|
601
|
+
};
|
|
605
602
|
}
|
|
606
603
|
|
|
607
604
|
export function legacyFormNode(definition: ControlDefinition) {
|
|
@@ -619,36 +616,56 @@ function getControlIds(
|
|
|
619
616
|
: [[definition.id, definition], ...childEntries];
|
|
620
617
|
}
|
|
621
618
|
|
|
622
|
-
function
|
|
623
|
-
|
|
624
|
-
|
|
619
|
+
export function createFormTreeWithRoot(
|
|
620
|
+
createRootNode: (tree: FormTree) => FormNode,
|
|
621
|
+
getChildrenForId: (id: string, parent: FormNode) => FormNode[],
|
|
622
|
+
getForm: FormTreeLookup = { getForm: () => undefined },
|
|
625
623
|
): FormTree {
|
|
626
624
|
const tree = {
|
|
627
|
-
getForm,
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
625
|
+
...getForm,
|
|
626
|
+
getChildrenForId,
|
|
627
|
+
rootNode: undefined! as FormNode,
|
|
628
|
+
} satisfies FormTree;
|
|
629
|
+
tree.rootNode = createRootNode(tree);
|
|
630
|
+
return tree;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
export function createFormTree(
|
|
634
|
+
controls: ControlDefinition[],
|
|
635
|
+
getForm: FormTreeLookup = { getForm: () => undefined },
|
|
636
|
+
): FormTree {
|
|
637
|
+
const controlMap = Object.fromEntries(controls.flatMap(getControlIds));
|
|
638
|
+
return createFormTreeWithRoot(
|
|
639
|
+
(tree) =>
|
|
640
|
+
nodeForControl(
|
|
641
|
+
{ children: controls, type: ControlDefinitionType.Group },
|
|
642
|
+
tree,
|
|
643
|
+
),
|
|
644
|
+
(id: string, parent: FormNode) => {
|
|
645
|
+
return (
|
|
646
|
+
controlMap[id]?.children?.map((x, i) =>
|
|
647
|
+
nodeForControl(x, parent.tree, i, parent),
|
|
648
|
+
) ?? []
|
|
649
|
+
);
|
|
634
650
|
},
|
|
635
|
-
|
|
651
|
+
getForm,
|
|
636
652
|
);
|
|
637
|
-
return tree;
|
|
638
653
|
}
|
|
639
654
|
|
|
640
655
|
export function createFormLookup<A extends Record<string, ControlDefinition[]>>(
|
|
641
656
|
formMap: A,
|
|
642
|
-
):
|
|
657
|
+
): {
|
|
658
|
+
getForm(formId: keyof A): FormTree;
|
|
659
|
+
} {
|
|
643
660
|
const lookup = {
|
|
644
661
|
getForm,
|
|
645
662
|
};
|
|
646
663
|
const forms = Object.fromEntries(
|
|
647
|
-
Object.entries(formMap).map(([k, v]) => [k,
|
|
664
|
+
Object.entries(formMap).map(([k, v]) => [k, createFormTree(v, lookup)]),
|
|
648
665
|
);
|
|
649
666
|
return lookup;
|
|
650
667
|
|
|
651
|
-
function getForm(formId: keyof A): FormTree
|
|
668
|
+
function getForm(formId: keyof A): FormTree {
|
|
652
669
|
return forms[formId as string];
|
|
653
670
|
}
|
|
654
671
|
}
|
package/src/controlRender.tsx
CHANGED
|
@@ -148,8 +148,8 @@ export interface FormRenderer {
|
|
|
148
148
|
*/
|
|
149
149
|
renderLabel: (
|
|
150
150
|
props: LabelRendererProps,
|
|
151
|
-
labelStart
|
|
152
|
-
labelEnd
|
|
151
|
+
labelStart?: ReactNode,
|
|
152
|
+
labelEnd?: ReactNode,
|
|
153
153
|
) => ReactNode;
|
|
154
154
|
|
|
155
155
|
/**
|
|
@@ -172,6 +172,9 @@ export interface FormRenderer {
|
|
|
172
172
|
* @returns A React node.
|
|
173
173
|
*/
|
|
174
174
|
renderLabelText: (props: ReactNode) => ReactNode;
|
|
175
|
+
renderText: (props: ReactNode) => ReactNode;
|
|
176
|
+
|
|
177
|
+
h: (type: any, props: any, ...children: any[]) => ReactElement;
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
export interface AdornmentProps {
|
|
@@ -463,7 +466,7 @@ export function useControlRendererComponent(
|
|
|
463
466
|
parentDataNode: SchemaDataNode,
|
|
464
467
|
): FC<{}> {
|
|
465
468
|
const [definition, formNode] =
|
|
466
|
-
|
|
469
|
+
"definition" in controlOrFormNode
|
|
467
470
|
? [controlOrFormNode.definition, controlOrFormNode]
|
|
468
471
|
: [controlOrFormNode, legacyFormNode(controlOrFormNode)];
|
|
469
472
|
const dataProps = options.useDataHook?.(definition) ?? defaultDataProps;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
2
|
import {
|
|
3
3
|
ActionRendererProps,
|
|
4
4
|
AdornmentProps,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
GroupRendererProps,
|
|
12
12
|
LabelRendererProps,
|
|
13
13
|
LabelType,
|
|
14
|
+
VisibilityRendererProps,
|
|
14
15
|
} from "./controlRender";
|
|
15
16
|
import { hasOptions } from "./util";
|
|
16
17
|
import {
|
|
@@ -55,10 +56,16 @@ export function createFormRenderer(
|
|
|
55
56
|
renderArray,
|
|
56
57
|
renderAdornment,
|
|
57
58
|
renderLayout,
|
|
58
|
-
renderVisibility
|
|
59
|
+
renderVisibility,
|
|
59
60
|
renderLabelText,
|
|
61
|
+
renderText: defaultRenderers.renderText,
|
|
62
|
+
h: defaultRenderers.h,
|
|
60
63
|
};
|
|
61
64
|
|
|
65
|
+
function renderVisibility(props: VisibilityRendererProps) {
|
|
66
|
+
return visibilityRenderer.render(props, formRenderers);
|
|
67
|
+
}
|
|
68
|
+
|
|
62
69
|
function renderLabelText(label: ReactNode) {
|
|
63
70
|
return renderLabel({ label, type: LabelType.Text }, undefined, undefined);
|
|
64
71
|
}
|
|
@@ -103,28 +110,33 @@ export function createFormRenderer(
|
|
|
103
110
|
|
|
104
111
|
const options = hasOptions(props);
|
|
105
112
|
const renderType = renderOptions.type;
|
|
106
|
-
const renderer =
|
|
107
|
-
dataRegistrations.find(matchesRenderer) ?? defaultRenderers.data;
|
|
113
|
+
const renderer = dataRegistrations.find(matchesRenderer);
|
|
108
114
|
|
|
109
|
-
const result = renderer.render(
|
|
115
|
+
const result = (renderer ?? defaultRenderers.data).render(
|
|
116
|
+
props,
|
|
117
|
+
formRenderers,
|
|
118
|
+
);
|
|
110
119
|
if (typeof result === "function") return result;
|
|
111
120
|
return (l) => ({ ...l, children: result });
|
|
112
121
|
|
|
113
122
|
function matchesRenderer(x: DataRendererRegistration) {
|
|
123
|
+
const noMatch = x.match ? !x.match(props, renderOptions) : undefined;
|
|
124
|
+
if (noMatch === true) return false;
|
|
114
125
|
const matchCollection =
|
|
115
126
|
(x.collection ?? false) ===
|
|
116
127
|
(props.elementIndex == null && (field.collection ?? false));
|
|
117
|
-
const
|
|
118
|
-
x.schemaType &&
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
128
|
+
const isSchemaAllowed =
|
|
129
|
+
!!x.schemaType && renderType == DataRenderType.Standard
|
|
130
|
+
? isOneOf(x.schemaType, field.type)
|
|
131
|
+
: undefined;
|
|
132
|
+
const isRendererAllowed =
|
|
133
|
+
!!x.renderType && isOneOf(x.renderType, renderType);
|
|
123
134
|
return (
|
|
124
135
|
matchCollection &&
|
|
125
136
|
(x.options ?? false) === options &&
|
|
126
|
-
(
|
|
127
|
-
|
|
137
|
+
(isSchemaAllowed ||
|
|
138
|
+
isRendererAllowed ||
|
|
139
|
+
(!x.renderType && !x.schemaType && noMatch === false))
|
|
128
140
|
);
|
|
129
141
|
}
|
|
130
142
|
}
|
package/src/renderers.tsx
CHANGED
|
@@ -19,7 +19,8 @@ import {
|
|
|
19
19
|
ControlAdornment,
|
|
20
20
|
ControlAdornmentType,
|
|
21
21
|
IconAdornment,
|
|
22
|
-
OptionalAdornment,
|
|
22
|
+
OptionalAdornment,
|
|
23
|
+
RenderOptions,
|
|
23
24
|
SetFieldAdornment,
|
|
24
25
|
} from "./controlDefinition";
|
|
25
26
|
|
|
@@ -33,6 +34,8 @@ export interface DefaultRenderers {
|
|
|
33
34
|
adornment: AdornmentRendererRegistration;
|
|
34
35
|
renderLayout: LayoutRendererRegistration;
|
|
35
36
|
visibility: VisibilityRendererRegistration;
|
|
37
|
+
renderText: (props: ReactNode) => ReactNode;
|
|
38
|
+
h: (type: any, props: any, ...children: any[]) => ReactElement;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
export interface LayoutRendererRegistration {
|
|
@@ -104,7 +107,7 @@ export interface AdornmentRendererRegistration {
|
|
|
104
107
|
|
|
105
108
|
export interface VisibilityRendererRegistration {
|
|
106
109
|
type: "visibility";
|
|
107
|
-
render: (props: VisibilityRendererProps) => ReactNode;
|
|
110
|
+
render: (props: VisibilityRendererProps, renderer: FormRenderer) => ReactNode;
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
export type RendererRegistration =
|