@react-typed-forms/schemas 16.2.2 → 17.0.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/FORM_EXTENSIONS_GUIDE.md +781 -0
- package/lib/RenderForm.d.ts +22 -5
- package/lib/controlBuilder.d.ts +4 -47
- package/lib/controlRender.d.ts +49 -24
- package/lib/index.cjs +310 -332
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +270 -272
- package/lib/index.js.map +1 -1
- package/lib/renderer/elementSelected.d.ts +8 -0
- package/lib/renderers.d.ts +6 -2
- package/lib/types.d.ts +10 -5
- package/lib/util.d.ts +3 -2
- package/package.json +5 -5
- package/src/RenderForm.tsx +130 -64
- package/src/controlBuilder.ts +6 -193
- package/src/controlRender.tsx +127 -81
- package/src/createFormRenderer.tsx +52 -19
- package/src/index.ts +1 -0
- package/src/renderer/elementSelected.ts +48 -0
- package/src/renderers.tsx +8 -1
- package/src/types.ts +15 -5
- package/src/util.ts +13 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Control } from "@react-typed-forms/core";
|
|
2
|
+
import { RenderOptions } from "@astroapps/forms-core";
|
|
3
|
+
import { RunExpression } from "../types";
|
|
4
|
+
export declare function useElementSelectedRenderer({ runExpression, renderOptions, control, }: {
|
|
5
|
+
runExpression: RunExpression;
|
|
6
|
+
renderOptions: RenderOptions;
|
|
7
|
+
control: Control<any>;
|
|
8
|
+
}): Control<boolean>;
|
package/lib/renderers.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactElement, ReactNode } from "react";
|
|
2
2
|
import { AdornmentProps, AdornmentRenderer, ArrayRendererProps, ControlLayoutProps, DataRendererProps, DisplayRendererProps, FormRenderer, GroupRendererProps, HtmlComponents, LabelRendererProps, LabelType, RenderedControl, VisibilityRendererProps } from "./controlRender";
|
|
3
|
-
import { AccordionAdornment, ControlAdornment, IconAdornment, OptionalAdornment, RenderOptions, SetFieldAdornment } from "@astroapps/forms-core";
|
|
3
|
+
import { AccordionAdornment, ChildResolverFunc, ControlAdornment, FormStateNode, IconAdornment, OptionalAdornment, RenderOptions, SetFieldAdornment } from "@astroapps/forms-core";
|
|
4
4
|
import { ActionRendererProps } from "./types";
|
|
5
5
|
export interface DefaultRenderers {
|
|
6
6
|
data: DataRendererRegistration;
|
|
@@ -26,8 +26,9 @@ export interface DataRendererRegistration {
|
|
|
26
26
|
renderType?: string | string[];
|
|
27
27
|
options?: boolean;
|
|
28
28
|
collection?: boolean;
|
|
29
|
-
match?: (props:
|
|
29
|
+
match?: (props: FormStateNode, renderOptions: RenderOptions) => boolean;
|
|
30
30
|
render: (props: DataRendererProps, renderers: FormRenderer) => ReactNode | ((layout: ControlLayoutProps) => ControlLayoutProps);
|
|
31
|
+
resolveChildren?: ChildResolverFunc;
|
|
31
32
|
}
|
|
32
33
|
export interface LabelRendererRegistration {
|
|
33
34
|
type: "label";
|
|
@@ -38,6 +39,7 @@ export interface ActionRendererRegistration {
|
|
|
38
39
|
type: "action";
|
|
39
40
|
actionType?: string | string[];
|
|
40
41
|
render: (props: ActionRendererProps, renderers: FormRenderer) => ReactElement;
|
|
42
|
+
resolveChildren?: ChildResolverFunc;
|
|
41
43
|
}
|
|
42
44
|
export interface ArrayRendererRegistration {
|
|
43
45
|
type: "array";
|
|
@@ -47,11 +49,13 @@ export interface GroupRendererRegistration {
|
|
|
47
49
|
type: "group";
|
|
48
50
|
renderType?: string | string[];
|
|
49
51
|
render: (props: GroupRendererProps, renderers: FormRenderer) => ReactElement | ((layout: ControlLayoutProps) => ControlLayoutProps);
|
|
52
|
+
resolveChildren?: ChildResolverFunc;
|
|
50
53
|
}
|
|
51
54
|
export interface DisplayRendererRegistration {
|
|
52
55
|
type: "display";
|
|
53
56
|
renderType?: string | string[];
|
|
54
57
|
render: (props: DisplayRendererProps, renderers: FormRenderer) => ReactElement;
|
|
58
|
+
resolveChildren?: ChildResolverFunc;
|
|
55
59
|
}
|
|
56
60
|
export interface AdornmentRendererRegistration {
|
|
57
61
|
type: "adornment";
|
package/lib/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ActionStyle, EntityExpression,
|
|
1
|
+
import { ActionStyle, EntityExpression, IconPlacement, IconReference, SchemaDataNode, SchemaInterface, ControlDisableType } from "@astroapps/forms-core";
|
|
2
2
|
import React, { Key, ReactNode } from "react";
|
|
3
|
-
import { CleanupScope } from "@react-typed-forms/core";
|
|
3
|
+
import { ChangeListenerFunc, CleanupScope } from "@react-typed-forms/core";
|
|
4
4
|
/**
|
|
5
5
|
* Interface representing the control data context.
|
|
6
6
|
*/
|
|
@@ -8,9 +8,13 @@ export interface ControlDataContext {
|
|
|
8
8
|
schemaInterface: SchemaInterface;
|
|
9
9
|
dataNode: SchemaDataNode | undefined;
|
|
10
10
|
parentNode: SchemaDataNode;
|
|
11
|
-
variables: Record<string, any>;
|
|
12
11
|
}
|
|
13
|
-
export
|
|
12
|
+
export interface ControlActionContext {
|
|
13
|
+
disableForm(disable: ControlDisableType): void;
|
|
14
|
+
runAction(action: string, actionData?: any): void | Promise<any>;
|
|
15
|
+
}
|
|
16
|
+
export declare const NoOpControlActionContext: ControlActionContext;
|
|
17
|
+
export type ControlActionHandler = (actionId: string, actionData: any, dataContext: ControlDataContext) => ((actionContext: ControlActionContext) => void | Promise<any>) | undefined;
|
|
14
18
|
export interface ActionRendererProps {
|
|
15
19
|
key?: Key;
|
|
16
20
|
actionId: string;
|
|
@@ -27,5 +31,6 @@ export interface ActionRendererProps {
|
|
|
27
31
|
disabled?: boolean;
|
|
28
32
|
hidden?: boolean;
|
|
29
33
|
inline?: boolean;
|
|
34
|
+
busy?: boolean;
|
|
30
35
|
}
|
|
31
|
-
export type RunExpression = (scope: CleanupScope, expression: EntityExpression, returnResult: (v: unknown) => void,
|
|
36
|
+
export type RunExpression = (scope: CleanupScope, expression: EntityExpression, returnResult: (v: unknown) => void, variables?: (changes: ChangeListenerFunc<any>) => Record<string, any>) => void;
|
package/lib/util.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CompoundField, ControlDataVisitor, ControlDefinition, DataControlDefinition, EntityExpression, FieldOption, SchemaDataNode, SchemaField, SchemaNode } from "@astroapps/forms-core";
|
|
2
2
|
import { MutableRefObject } from "react";
|
|
3
|
-
import { Control } from "@react-typed-forms/core";
|
|
3
|
+
import { ChangeListenerFunc, Control } from "@react-typed-forms/core";
|
|
4
4
|
import { ActionRendererProps, ControlActionHandler, RunExpression } from "./types";
|
|
5
5
|
/**
|
|
6
6
|
* Interface representing the classes for a control.
|
|
@@ -229,4 +229,5 @@ export declare function collectDifferences(dataNode: SchemaDataNode, values: unk
|
|
|
229
229
|
editing: number;
|
|
230
230
|
};
|
|
231
231
|
export declare function validationVisitor(onInvalid: (data: Control<unknown>) => void): ControlDataVisitor<any>;
|
|
232
|
-
export declare function useExpression<T>(defaultValue: T, runExpression: RunExpression, expression: EntityExpression | null | undefined, coerce: (x: any) => T, bindings?: Record<string, any>): Control<T>;
|
|
232
|
+
export declare function useExpression<T>(defaultValue: T, runExpression: RunExpression, expression: EntityExpression | null | undefined, coerce: (x: any) => T, bindings?: (changes: ChangeListenerFunc<any>) => Record<string, any>): Control<T>;
|
|
233
|
+
export declare function setIncluded<A>(array: A[], elem: A, included: boolean): A[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-typed-forms/schemas",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "17.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.cjs",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"clsx": "^1 || ^2",
|
|
35
35
|
"uuid": "^10.0.0",
|
|
36
36
|
"jsonata": "^2.0.4",
|
|
37
|
-
"@astroapps/forms-core": "^
|
|
37
|
+
"@astroapps/forms-core": "^2.0.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"react": "^18.2.0 || ^19",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@jest/globals": "^29.7.0",
|
|
52
52
|
"typedoc": "^0.27.2",
|
|
53
53
|
"@types/uuid": "^10.0.0",
|
|
54
|
-
"@types/react": "^18.2.28",
|
|
54
|
+
"@types/react": "^18.2.28 || ^19",
|
|
55
55
|
"markdown-magic": "^2.6.1",
|
|
56
56
|
"microbundle": "^0.15.1",
|
|
57
57
|
"nswag": "^13.18.2",
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
},
|
|
62
62
|
"gitHead": "698e16cd3ab31b7dd0528fc76536f4d3205ce8c6",
|
|
63
63
|
"scripts": {
|
|
64
|
-
"build": "rimraf ./lib/ node_modules/.cache && microbundle -f modern,cjs --no-compress --jsxImportSource=react",
|
|
65
|
-
"watch": "microbundle -
|
|
64
|
+
"build": "rimraf ./lib/ node_modules/.cache && microbundle -f modern,cjs --no-compress --jsx React --jsxImportSource=react",
|
|
65
|
+
"watch": "microbundle -f modern,cjs --no-compress --jsx React --jsxImportSource=react",
|
|
66
66
|
"test": "jest --coverage",
|
|
67
67
|
"play": "tsx test/play.ts",
|
|
68
68
|
"update-readme": "md-magic --path README.md",
|
package/src/RenderForm.tsx
CHANGED
|
@@ -9,22 +9,24 @@ import {
|
|
|
9
9
|
} from "./controlRender";
|
|
10
10
|
import React, {
|
|
11
11
|
FC,
|
|
12
|
+
MutableRefObject,
|
|
12
13
|
useCallback,
|
|
13
14
|
useEffect,
|
|
14
15
|
useMemo,
|
|
15
|
-
useRef,
|
|
16
|
-
useState,
|
|
17
16
|
} from "react";
|
|
18
17
|
import {
|
|
19
18
|
ControlDefinition,
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
ControlDisableType,
|
|
20
|
+
createFormStateNode,
|
|
22
21
|
createSchemaDataNode,
|
|
23
22
|
createSchemaTree,
|
|
23
|
+
defaultEvaluators,
|
|
24
24
|
defaultSchemaInterface,
|
|
25
|
+
FormGlobalOptions,
|
|
25
26
|
FormNode,
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
FormNodeOptions,
|
|
28
|
+
FormNodeUi,
|
|
29
|
+
FormStateNode,
|
|
28
30
|
JsonPath,
|
|
29
31
|
legacyFormNode,
|
|
30
32
|
SchemaDataNode,
|
|
@@ -44,6 +46,7 @@ export interface RenderFormProps {
|
|
|
44
46
|
form: FormNode;
|
|
45
47
|
renderer: FormRenderer;
|
|
46
48
|
options?: ControlRenderOptions;
|
|
49
|
+
stateRef?: MutableRefObject<FormStateNode | null>;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
/* @trackControls */
|
|
@@ -52,28 +55,64 @@ export function RenderForm({
|
|
|
52
55
|
form,
|
|
53
56
|
renderer,
|
|
54
57
|
options = {},
|
|
58
|
+
stateRef,
|
|
55
59
|
}: RenderFormProps) {
|
|
60
|
+
const { readonly, disabled, displayOnly, hidden, variables, clearHidden } =
|
|
61
|
+
options;
|
|
56
62
|
const schemaInterface = options.schemaInterface ?? defaultSchemaInterface;
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
const { runAsync } = useAsyncRunner();
|
|
64
|
+
const globals: FormGlobalOptions = {
|
|
65
|
+
runAsync,
|
|
66
|
+
schemaInterface,
|
|
67
|
+
evalExpression: (e, ctx) => defaultEvaluators[e.type]?.(e, ctx),
|
|
68
|
+
resolveChildren: renderer.resolveChildren,
|
|
69
|
+
clearHidden: !!clearHidden,
|
|
64
70
|
};
|
|
65
|
-
const state =
|
|
66
|
-
|
|
71
|
+
const state = useMemo(
|
|
72
|
+
() =>
|
|
73
|
+
createFormStateNode(form, data, globals, {
|
|
74
|
+
forceReadonly: !!readonly,
|
|
75
|
+
forceDisabled: !!disabled,
|
|
76
|
+
variables,
|
|
77
|
+
forceHidden: !!hidden,
|
|
78
|
+
}),
|
|
79
|
+
[form.id],
|
|
80
|
+
);
|
|
81
|
+
state.globals.value = globals;
|
|
82
|
+
state.options.setValue((x) => ({
|
|
83
|
+
variables,
|
|
84
|
+
forceHidden: hidden ?? x.forceHidden,
|
|
85
|
+
forceDisabled: disabled ?? x.forceDisabled,
|
|
86
|
+
forceReadonly: readonly ?? x.forceReadonly,
|
|
87
|
+
}));
|
|
88
|
+
if (stateRef) stateRef.current = state;
|
|
67
89
|
useEffect(() => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
}, [
|
|
72
|
-
|
|
73
|
-
|
|
90
|
+
return () => {
|
|
91
|
+
state.cleanup();
|
|
92
|
+
};
|
|
93
|
+
}, [state]);
|
|
94
|
+
return <RenderFormNode node={state} renderer={renderer} options={options} />;
|
|
95
|
+
}
|
|
74
96
|
|
|
75
|
-
|
|
97
|
+
export interface RenderFormNodeProps {
|
|
98
|
+
node: FormStateNode;
|
|
99
|
+
renderer: FormRenderer;
|
|
100
|
+
options?: ControlRenderOptions;
|
|
101
|
+
}
|
|
76
102
|
|
|
103
|
+
/* @trackControls */
|
|
104
|
+
export function RenderFormNode({
|
|
105
|
+
node: state,
|
|
106
|
+
renderer,
|
|
107
|
+
options = {},
|
|
108
|
+
}: RenderFormNodeProps) {
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
state.attachUi(new DefaultFormNodeUi(state));
|
|
111
|
+
}, [state]);
|
|
112
|
+
const { runAsync } = useAsyncRunner();
|
|
113
|
+
const schemaInterface = state.schemaInterface;
|
|
114
|
+
const definition = state.definition;
|
|
115
|
+
const visible = state.visible;
|
|
77
116
|
const visibility = useControl<Visibility | undefined>(() =>
|
|
78
117
|
visible != null
|
|
79
118
|
? {
|
|
@@ -82,13 +121,14 @@ export function RenderForm({
|
|
|
82
121
|
}
|
|
83
122
|
: undefined,
|
|
84
123
|
);
|
|
85
|
-
|
|
124
|
+
if (visible != null) {
|
|
125
|
+
visibility.fields.visible.value = visible;
|
|
126
|
+
}
|
|
86
127
|
|
|
87
128
|
const dataContext: ControlDataContext = {
|
|
88
129
|
schemaInterface: state.schemaInterface,
|
|
89
130
|
dataNode: state.dataNode,
|
|
90
|
-
parentNode:
|
|
91
|
-
variables: state.variables,
|
|
131
|
+
parentNode: state.parent,
|
|
92
132
|
};
|
|
93
133
|
|
|
94
134
|
const adornments =
|
|
@@ -96,7 +136,7 @@ export function RenderForm({
|
|
|
96
136
|
renderer.renderAdornment({
|
|
97
137
|
adornment: x,
|
|
98
138
|
dataContext,
|
|
99
|
-
|
|
139
|
+
formNode: state,
|
|
100
140
|
}),
|
|
101
141
|
) ?? [];
|
|
102
142
|
|
|
@@ -108,41 +148,35 @@ export function RenderForm({
|
|
|
108
148
|
textClass,
|
|
109
149
|
...inheritableOptions
|
|
110
150
|
} = options;
|
|
111
|
-
const { readonly,
|
|
151
|
+
const { readonly, visible: vis, disabled, variables } = state;
|
|
112
152
|
const childOptions: ControlRenderOptions = {
|
|
113
153
|
...inheritableOptions,
|
|
114
154
|
readonly,
|
|
115
155
|
disabled,
|
|
116
156
|
variables,
|
|
117
|
-
|
|
118
|
-
hidden,
|
|
157
|
+
hidden: vis === false,
|
|
119
158
|
};
|
|
120
159
|
|
|
121
160
|
const labelAndChildren = renderControlLayout({
|
|
122
|
-
formNode:
|
|
161
|
+
formNode: state,
|
|
123
162
|
renderer,
|
|
124
|
-
|
|
125
|
-
renderChild: (k, child, options) => {
|
|
163
|
+
renderChild: (child, options) => {
|
|
126
164
|
const overrideClasses = getGroupClassOverrides(definition);
|
|
127
|
-
const {
|
|
128
|
-
options ?? {};
|
|
129
|
-
const dContext = parentDataNode ?? dataContext.dataNode ?? data;
|
|
165
|
+
const { actionOnClick, ...renderOptions } = options ?? {};
|
|
130
166
|
const allChildOptions = {
|
|
131
167
|
...childOptions,
|
|
132
168
|
...overrideClasses,
|
|
133
169
|
...renderOptions,
|
|
134
|
-
variables: { ...childOptions.variables, ...variables },
|
|
135
170
|
actionOnClick: actionHandlers(
|
|
136
171
|
actionOnClick,
|
|
137
172
|
childOptions.actionOnClick,
|
|
138
173
|
),
|
|
139
174
|
};
|
|
140
175
|
return (
|
|
141
|
-
<
|
|
142
|
-
key={
|
|
143
|
-
|
|
176
|
+
<RenderFormNode
|
|
177
|
+
key={child.childKey}
|
|
178
|
+
node={child}
|
|
144
179
|
renderer={renderer}
|
|
145
|
-
data={dContext}
|
|
146
180
|
options={allChildOptions}
|
|
147
181
|
/>
|
|
148
182
|
);
|
|
@@ -150,32 +184,22 @@ export function RenderForm({
|
|
|
150
184
|
inline: options?.inline,
|
|
151
185
|
displayOnly: options?.displayOnly,
|
|
152
186
|
createDataProps: defaultDataProps,
|
|
153
|
-
formOptions: state,
|
|
154
187
|
dataContext,
|
|
155
188
|
control: dataContext.dataNode?.control,
|
|
156
189
|
schemaInterface,
|
|
157
|
-
style: state.style,
|
|
158
|
-
allowedOptions: state.allowedOptions,
|
|
190
|
+
style: state.resolved.style,
|
|
159
191
|
customDisplay: options.customDisplay,
|
|
160
192
|
actionOnClick: options.actionOnClick,
|
|
161
193
|
styleClass: styleClass,
|
|
162
194
|
labelClass: labelClass,
|
|
163
195
|
labelTextClass: labelTextClass,
|
|
164
196
|
textClass: textClass,
|
|
165
|
-
getChildState(child: FormNode, parent?: SchemaDataNode): ControlState {
|
|
166
|
-
return formState.getControlState(
|
|
167
|
-
parent ?? state.dataNode ?? data,
|
|
168
|
-
child,
|
|
169
|
-
childOptions,
|
|
170
|
-
runAsync,
|
|
171
|
-
);
|
|
172
|
-
},
|
|
173
197
|
runExpression: (scope, expr, returnResult) => {
|
|
174
198
|
if (expr?.type) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
dataNode: data,
|
|
199
|
+
defaultEvaluators[expr.type](expr, {
|
|
200
|
+
dataNode: state.parent,
|
|
178
201
|
schemaInterface,
|
|
202
|
+
scope,
|
|
179
203
|
returnResult,
|
|
180
204
|
runAsync,
|
|
181
205
|
});
|
|
@@ -186,23 +210,15 @@ export function RenderForm({
|
|
|
186
210
|
...labelAndChildren,
|
|
187
211
|
adornments,
|
|
188
212
|
className: rendererClass(options.layoutClass, definition.layoutClass),
|
|
189
|
-
style: state.layoutStyle,
|
|
213
|
+
style: state.resolved.layoutStyle,
|
|
190
214
|
};
|
|
191
215
|
const renderedControl = renderer.renderLayout(
|
|
192
216
|
options.adjustLayout?.(dataContext, layoutProps) ?? layoutProps,
|
|
193
217
|
);
|
|
194
|
-
|
|
218
|
+
return renderer.renderVisibility({
|
|
195
219
|
visibility,
|
|
196
220
|
...renderedControl,
|
|
197
221
|
});
|
|
198
|
-
useEffect(() => {
|
|
199
|
-
if (effects) {
|
|
200
|
-
const toRun = effects;
|
|
201
|
-
effects = undefined;
|
|
202
|
-
toRun.forEach((cb) => cb());
|
|
203
|
-
}
|
|
204
|
-
}, [effects]);
|
|
205
|
-
return rendered;
|
|
206
222
|
}
|
|
207
223
|
|
|
208
224
|
/**
|
|
@@ -319,3 +335,53 @@ export function useControlRenderer(
|
|
|
319
335
|
[r],
|
|
320
336
|
);
|
|
321
337
|
}
|
|
338
|
+
|
|
339
|
+
export function useAsyncRunner(): {
|
|
340
|
+
runAsync: (cb: () => void) => void;
|
|
341
|
+
} {
|
|
342
|
+
let effects: (() => void)[] | undefined = [];
|
|
343
|
+
const runAsync = (cb: () => void) => {
|
|
344
|
+
if (effects) effects.push(cb);
|
|
345
|
+
else cb();
|
|
346
|
+
};
|
|
347
|
+
useEffect(() => {
|
|
348
|
+
if (effects) {
|
|
349
|
+
const toRun = effects;
|
|
350
|
+
effects = undefined;
|
|
351
|
+
toRun.forEach((cb) => cb());
|
|
352
|
+
}
|
|
353
|
+
}, [effects]);
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
runAsync,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export class DefaultFormNodeUi implements FormNodeUi {
|
|
361
|
+
constructor(protected node: FormStateNode) {}
|
|
362
|
+
ensureVisible() {
|
|
363
|
+
this.node.parentNode?.ui.ensureChildVisible(this.node.childIndex);
|
|
364
|
+
}
|
|
365
|
+
ensureChildVisible(childIndex: number) {
|
|
366
|
+
this.ensureVisible();
|
|
367
|
+
}
|
|
368
|
+
getDisabler(type: ControlDisableType): () => () => void {
|
|
369
|
+
if (type === ControlDisableType.Self) {
|
|
370
|
+
return () => {
|
|
371
|
+
const old = !!this.node.forceDisabled;
|
|
372
|
+
this.node.setForceDisabled(true);
|
|
373
|
+
return () => {
|
|
374
|
+
this.node.setForceDisabled(old);
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
if (type === ControlDisableType.Global) {
|
|
379
|
+
let topLevel = this.node;
|
|
380
|
+
while (topLevel.parentNode) {
|
|
381
|
+
topLevel = topLevel.parentNode;
|
|
382
|
+
}
|
|
383
|
+
return topLevel.ui.getDisabler(ControlDisableType.Self);
|
|
384
|
+
}
|
|
385
|
+
return () => () => {};
|
|
386
|
+
}
|
|
387
|
+
}
|
package/src/controlBuilder.ts
CHANGED
|
@@ -1,201 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
AccordionAdornment,
|
|
3
|
-
ActionControlDefinition,
|
|
4
|
-
AutocompleteRenderOptions,
|
|
5
|
-
CheckListRenderOptions,
|
|
6
|
-
ControlAdornmentType,
|
|
7
2
|
ControlDefinition,
|
|
8
|
-
|
|
9
|
-
DataControlDefinition,
|
|
10
|
-
DataExpression,
|
|
11
|
-
DataMatchExpression,
|
|
12
|
-
DataRenderType,
|
|
13
|
-
DateValidator,
|
|
14
|
-
DisplayControlDefinition,
|
|
15
|
-
DisplayDataType,
|
|
16
|
-
DisplayOnlyRenderOptions,
|
|
17
|
-
DynamicProperty,
|
|
18
|
-
DynamicPropertyType,
|
|
19
|
-
EntityExpression,
|
|
20
|
-
ExpressionType,
|
|
3
|
+
emptyGroupDefinition,
|
|
21
4
|
GroupedControlsDefinition,
|
|
22
|
-
|
|
23
|
-
HtmlDisplay,
|
|
24
|
-
JsonataExpression,
|
|
25
|
-
JsonataRenderOptions,
|
|
26
|
-
JsonataValidator,
|
|
27
|
-
LengthValidator,
|
|
5
|
+
mergeFields,
|
|
28
6
|
mergeOption,
|
|
29
|
-
|
|
30
|
-
RenderOptions,
|
|
7
|
+
resolveSchemas,
|
|
31
8
|
SchemaField,
|
|
32
9
|
SchemaMap,
|
|
33
10
|
SchemaNode,
|
|
34
|
-
TextDisplay,
|
|
35
|
-
TextfieldRenderOptions,
|
|
36
|
-
ValidatorType,
|
|
37
11
|
} from "@astroapps/forms-core";
|
|
38
12
|
import { useMemo } from "react";
|
|
39
13
|
import { addMissingControls } from "./util";
|
|
40
|
-
import { mergeFields, resolveSchemas } from "@astroapps/forms-core";
|
|
41
14
|
import { ActionRendererProps } from "./types";
|
|
42
15
|
|
|
43
|
-
export function dataControl(
|
|
44
|
-
field: string,
|
|
45
|
-
title?: string | null,
|
|
46
|
-
options?: Partial<DataControlDefinition>,
|
|
47
|
-
): DataControlDefinition {
|
|
48
|
-
return { type: ControlDefinitionType.Data, field, title, ...options };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function validatorOptions<A extends { type: string }>(
|
|
52
|
-
type: ValidatorType,
|
|
53
|
-
): (options: Omit<A, "type">) => A {
|
|
54
|
-
return (o) => ({ type, ...o }) as A;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function adornmentOptions<A extends { type: string }>(
|
|
58
|
-
type: ControlAdornmentType,
|
|
59
|
-
): (options: Omit<A, "type">) => A {
|
|
60
|
-
return (o) => ({ type, ...o }) as A;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function renderOptionsFor<A extends RenderOptions>(
|
|
64
|
-
type: DataRenderType,
|
|
65
|
-
): (options: Omit<A, "type">) => { renderOptions: A } {
|
|
66
|
-
return (o) => ({ renderOptions: { type, ...o } as A });
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const autocompleteOptions = renderOptionsFor<AutocompleteRenderOptions>(
|
|
70
|
-
DataRenderType.Autocomplete,
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
export const checkListOptions = renderOptionsFor<CheckListRenderOptions>(
|
|
74
|
-
DataRenderType.CheckList,
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
export const radioButtonOptions = renderOptionsFor<RadioButtonRenderOptions>(
|
|
78
|
-
DataRenderType.Radio,
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
export const lengthValidatorOptions = validatorOptions<LengthValidator>(
|
|
82
|
-
ValidatorType.Length,
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
export const jsonataValidatorOptions = validatorOptions<JsonataValidator>(
|
|
86
|
-
ValidatorType.Jsonata,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
export const dateValidatorOptions = validatorOptions<DateValidator>(
|
|
90
|
-
ValidatorType.Date,
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
export const accordionOptions = adornmentOptions<AccordionAdornment>(
|
|
94
|
-
ControlAdornmentType.Accordion,
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
export const textfieldOptions = renderOptionsFor<TextfieldRenderOptions>(
|
|
98
|
-
DataRenderType.Textfield,
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
export const displayOnlyOptions = renderOptionsFor<DisplayOnlyRenderOptions>(
|
|
102
|
-
DataRenderType.DisplayOnly,
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
export const jsonataOptions = renderOptionsFor<JsonataRenderOptions>(
|
|
106
|
-
DataRenderType.Jsonata,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
export function textDisplayControl(
|
|
110
|
-
text: string,
|
|
111
|
-
options?: Partial<DisplayControlDefinition>,
|
|
112
|
-
): DisplayControlDefinition {
|
|
113
|
-
return {
|
|
114
|
-
type: ControlDefinitionType.Display,
|
|
115
|
-
displayData: { type: DisplayDataType.Text, text } as TextDisplay,
|
|
116
|
-
...options,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function htmlDisplayControl(
|
|
121
|
-
html: string,
|
|
122
|
-
options?: Partial<DisplayControlDefinition>,
|
|
123
|
-
): DisplayControlDefinition {
|
|
124
|
-
return {
|
|
125
|
-
type: ControlDefinitionType.Display,
|
|
126
|
-
displayData: { type: DisplayDataType.Html, html } as HtmlDisplay,
|
|
127
|
-
...options,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export function dynamicDefaultValue(expr: EntityExpression): DynamicProperty {
|
|
132
|
-
return { type: DynamicPropertyType.DefaultValue, expr };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export function dynamicReadonly(expr: EntityExpression): DynamicProperty {
|
|
136
|
-
return { type: DynamicPropertyType.Readonly, expr };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export function dynamicVisibility(expr: EntityExpression): DynamicProperty {
|
|
140
|
-
return { type: DynamicPropertyType.Visible, expr };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export function dynamicDisabled(expr: EntityExpression): DynamicProperty {
|
|
144
|
-
return { type: DynamicPropertyType.Disabled, expr };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function fieldExpr(field: string): DataExpression {
|
|
148
|
-
return { type: ExpressionType.Data, field };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function fieldEqExpr(field: string, value: any): DataMatchExpression {
|
|
152
|
-
return { type: ExpressionType.DataMatch, field, value };
|
|
153
|
-
}
|
|
154
|
-
export function jsonataExpr(expression: string): JsonataExpression {
|
|
155
|
-
return { type: ExpressionType.Jsonata, expression };
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export function groupedControl(
|
|
159
|
-
children: ControlDefinition[],
|
|
160
|
-
title?: string,
|
|
161
|
-
options?: Partial<GroupedControlsDefinition>,
|
|
162
|
-
): GroupedControlsDefinition {
|
|
163
|
-
return {
|
|
164
|
-
type: ControlDefinitionType.Group,
|
|
165
|
-
children,
|
|
166
|
-
title,
|
|
167
|
-
groupOptions: { type: "Standard", hideTitle: !title },
|
|
168
|
-
...options,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
export function compoundControl(
|
|
172
|
-
field: string,
|
|
173
|
-
title: string | undefined,
|
|
174
|
-
children: ControlDefinition[],
|
|
175
|
-
options?: Partial<DataControlDefinition>,
|
|
176
|
-
): DataControlDefinition {
|
|
177
|
-
return {
|
|
178
|
-
type: ControlDefinitionType.Data,
|
|
179
|
-
field,
|
|
180
|
-
children,
|
|
181
|
-
title,
|
|
182
|
-
renderOptions: { type: "Standard" },
|
|
183
|
-
...options,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function actionControl(
|
|
188
|
-
actionText: string,
|
|
189
|
-
actionId: string,
|
|
190
|
-
options?: Partial<ActionControlDefinition>,
|
|
191
|
-
): ActionControlDefinition {
|
|
192
|
-
return {
|
|
193
|
-
type: ControlDefinitionType.Action,
|
|
194
|
-
title: actionText,
|
|
195
|
-
actionId,
|
|
196
|
-
...options,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
16
|
export function createAction(
|
|
200
17
|
actionId: string,
|
|
201
18
|
onClick: () => void,
|
|
@@ -210,12 +27,6 @@ export function createAction(
|
|
|
210
27
|
};
|
|
211
28
|
}
|
|
212
29
|
|
|
213
|
-
export const emptyGroupDefinition: GroupedControlsDefinition = {
|
|
214
|
-
type: ControlDefinitionType.Group,
|
|
215
|
-
children: [],
|
|
216
|
-
groupOptions: { type: GroupRenderType.Standard, hideTitle: true },
|
|
217
|
-
};
|
|
218
|
-
|
|
219
30
|
export function useControlDefinitionForSchema(
|
|
220
31
|
sf: SchemaField[],
|
|
221
32
|
definition: GroupedControlsDefinition = emptyGroupDefinition,
|
|
@@ -235,7 +46,7 @@ export interface EditorGroup {
|
|
|
235
46
|
}
|
|
236
47
|
|
|
237
48
|
export interface CustomRenderOptions {
|
|
238
|
-
value
|
|
49
|
+
value?: string;
|
|
239
50
|
name: string;
|
|
240
51
|
fields?: SchemaField[];
|
|
241
52
|
groups?: EditorGroup[];
|
|
@@ -250,6 +61,8 @@ export type ControlDefinitionExtension = {
|
|
|
250
61
|
SchemaValidator?: CustomRenderOptions | CustomRenderOptions[];
|
|
251
62
|
DisplayData?: CustomRenderOptions | CustomRenderOptions[];
|
|
252
63
|
IconReference?: CustomRenderOptions | CustomRenderOptions[];
|
|
64
|
+
ControlDefinition?: CustomRenderOptions | CustomRenderOptions[];
|
|
65
|
+
SchemaField?: CustomRenderOptions | CustomRenderOptions[];
|
|
253
66
|
};
|
|
254
67
|
|
|
255
68
|
export function applyExtensionToSchema<A extends SchemaMap>(
|