@react-typed-forms/schemas 1.0.0-dev.2 → 1.0.0-dev.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/.babelrc +4 -0
- package/.rush/temp/operation/build/state.json +3 -0
- package/.rush/temp/operation/update-readme/state.json +3 -0
- package/.rush/temp/package-deps_build.json +7 -7
- package/.rush/temp/shrinkwrap-deps.json +580 -7
- package/README.md +223 -0
- package/lib/controlRender.d.ts +82 -65
- package/lib/hooks.d.ts +11 -9
- package/lib/index.d.ts +3 -0
- package/lib/index.js +1588 -19
- package/lib/index.js.map +1 -0
- package/lib/renderers.d.ts +154 -0
- package/lib/schemaBuilder.d.ts +38 -34
- package/lib/tailwind.d.ts +2 -0
- package/lib/types.d.ts +101 -36
- package/lib/util.d.ts +22 -0
- package/package.json +15 -8
- package/src/controlRender.tsx +217 -360
- package/src/hooks.tsx +439 -0
- package/src/index.ts +3 -0
- package/src/renderers.tsx +870 -0
- package/src/schemaBuilder.ts +7 -4
- package/src/tailwind.tsx +21 -0
- package/src/types.ts +173 -39
- package/src/util.ts +212 -0
- package/tsconfig.json +4 -3
- package/lib/controlRender.js +0 -230
- package/lib/hooks.js +0 -93
- package/lib/schemaBuilder.js +0 -67
- package/lib/types.js +0 -68
- package/schemas.build.log +0 -2
- package/src/hooks.ts +0 -164
package/src/controlRender.tsx
CHANGED
|
@@ -1,468 +1,278 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ActionControlDefinition,
|
|
3
|
-
|
|
3
|
+
AdornmentPlacement,
|
|
4
4
|
CompoundField,
|
|
5
|
+
ControlAdornment,
|
|
5
6
|
ControlDefinition,
|
|
6
7
|
ControlDefinitionType,
|
|
7
8
|
DataControlDefinition,
|
|
8
9
|
DisplayControlDefinition,
|
|
10
|
+
EntityExpression,
|
|
9
11
|
FieldOption,
|
|
10
|
-
FieldType,
|
|
11
12
|
GroupedControlsDefinition,
|
|
13
|
+
RenderOptions,
|
|
12
14
|
SchemaField,
|
|
15
|
+
SchemaValidator,
|
|
16
|
+
visitControlDefinition,
|
|
13
17
|
} from "./types";
|
|
14
|
-
import React, {
|
|
15
|
-
import { Control, newControl
|
|
18
|
+
import React, { Key, ReactElement, ReactNode } from "react";
|
|
19
|
+
import { Control, newControl } from "@react-typed-forms/core";
|
|
20
|
+
import {
|
|
21
|
+
fieldDisplayName,
|
|
22
|
+
findCompoundField,
|
|
23
|
+
findField,
|
|
24
|
+
findScalarField,
|
|
25
|
+
isDataControl,
|
|
26
|
+
isGroupControl,
|
|
27
|
+
} from "./util";
|
|
28
|
+
|
|
29
|
+
export interface SchemaHooks {
|
|
30
|
+
useExpression(
|
|
31
|
+
expr: EntityExpression,
|
|
32
|
+
formState: FormEditState,
|
|
33
|
+
): Control<any | undefined>;
|
|
34
|
+
useValidators(
|
|
35
|
+
formState: FormEditState,
|
|
36
|
+
isVisible: boolean,
|
|
37
|
+
control: Control<any>,
|
|
38
|
+
required: boolean,
|
|
39
|
+
validations?: SchemaValidator[] | null,
|
|
40
|
+
): void;
|
|
41
|
+
}
|
|
16
42
|
|
|
17
43
|
export interface FormEditHooks {
|
|
18
44
|
useDataProperties(
|
|
19
45
|
formState: FormEditState,
|
|
20
46
|
definition: DataControlDefinition,
|
|
21
|
-
field: SchemaField
|
|
22
|
-
):
|
|
47
|
+
field: SchemaField,
|
|
48
|
+
): DataRendererProps;
|
|
23
49
|
useGroupProperties(
|
|
24
50
|
formState: FormEditState,
|
|
25
51
|
definition: GroupedControlsDefinition,
|
|
26
|
-
|
|
27
|
-
): GroupControlProperties;
|
|
52
|
+
): GroupRendererProps;
|
|
28
53
|
useDisplayProperties(
|
|
29
54
|
formState: FormEditState,
|
|
30
|
-
definition: DisplayControlDefinition
|
|
31
|
-
):
|
|
55
|
+
definition: DisplayControlDefinition,
|
|
56
|
+
): DisplayRendererProps;
|
|
32
57
|
useActionProperties(
|
|
33
58
|
formState: FormEditState,
|
|
34
|
-
definition: ActionControlDefinition
|
|
35
|
-
):
|
|
59
|
+
definition: ActionControlDefinition,
|
|
60
|
+
): ActionRendererProps;
|
|
61
|
+
schemaHooks: SchemaHooks;
|
|
36
62
|
}
|
|
37
63
|
|
|
38
|
-
export interface
|
|
64
|
+
export interface DataRendererProps {
|
|
65
|
+
definition: DataControlDefinition;
|
|
66
|
+
renderOptions: RenderOptions;
|
|
67
|
+
visible: Visibility;
|
|
68
|
+
control: Control<any>;
|
|
69
|
+
field: SchemaField;
|
|
70
|
+
array?: ArrayRendererProps;
|
|
39
71
|
readonly: boolean;
|
|
40
|
-
visible: boolean;
|
|
41
|
-
options: FieldOption[] | undefined;
|
|
42
72
|
defaultValue: any;
|
|
43
73
|
required: boolean;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
) => ReactElement;
|
|
74
|
+
options: FieldOption[] | undefined | null;
|
|
75
|
+
customRender?: (props: DataRendererProps) => ReactElement;
|
|
76
|
+
formState: FormEditState;
|
|
48
77
|
}
|
|
49
78
|
|
|
50
|
-
export interface
|
|
51
|
-
|
|
79
|
+
export interface GroupRendererProps {
|
|
80
|
+
definition: Omit<GroupedControlsDefinition, "children">;
|
|
81
|
+
visible: Visibility;
|
|
82
|
+
field?: CompoundField;
|
|
83
|
+
array?: ArrayRendererProps;
|
|
84
|
+
hideTitle: boolean;
|
|
52
85
|
hooks: FormEditHooks;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
export interface DisplayControlProperties {
|
|
56
|
-
visible: boolean;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface ActionControlProperties {
|
|
60
|
-
visible: boolean;
|
|
61
|
-
onClick: () => void;
|
|
86
|
+
childCount: number;
|
|
87
|
+
renderChild: (child: number) => ReactElement;
|
|
62
88
|
}
|
|
63
89
|
|
|
64
90
|
export interface ControlData {
|
|
65
91
|
[field: string]: any;
|
|
66
92
|
}
|
|
67
93
|
|
|
68
|
-
export interface
|
|
94
|
+
export interface FormDataContext {
|
|
69
95
|
fields: SchemaField[];
|
|
70
96
|
data: Control<ControlData>;
|
|
71
|
-
readonly?: boolean;
|
|
72
97
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
element: boolean,
|
|
79
|
-
renderers: FormRendererComponents
|
|
80
|
-
) => ReactElement;
|
|
81
|
-
renderCompound: (
|
|
82
|
-
props: CompoundGroupRendererProps,
|
|
83
|
-
control: Control<any>,
|
|
84
|
-
renderers: FormRendererComponents
|
|
85
|
-
) => ReactElement;
|
|
86
|
-
renderGroup: (props: GroupRendererProps) => ReactElement;
|
|
87
|
-
renderDisplay: (props: DisplayRendererProps) => ReactElement;
|
|
88
|
-
renderAction: (props: ActionRendererProps) => ReactElement;
|
|
98
|
+
export interface FormEditState extends FormDataContext {
|
|
99
|
+
hooks: FormEditHooks;
|
|
100
|
+
renderer: FormRenderer;
|
|
101
|
+
readonly?: boolean;
|
|
102
|
+
invisible?: boolean;
|
|
89
103
|
}
|
|
90
104
|
|
|
91
|
-
export
|
|
92
|
-
FormRendererComponents | undefined
|
|
93
|
-
>(undefined);
|
|
105
|
+
export type RenderControlOptions = Omit<FormEditState, "data">;
|
|
94
106
|
|
|
95
|
-
export
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
107
|
+
export interface ArrayRendererProps {
|
|
108
|
+
definition: DataControlDefinition | GroupedControlsDefinition;
|
|
109
|
+
control: Control<any[]>;
|
|
110
|
+
field: SchemaField;
|
|
111
|
+
addAction?: ActionRendererProps;
|
|
112
|
+
removeAction?: (childCount: number) => ActionRendererProps;
|
|
113
|
+
childCount: number;
|
|
114
|
+
renderChild: (childCount: number) => ReactElement;
|
|
115
|
+
childKey: (childCount: number) => Key;
|
|
101
116
|
}
|
|
102
117
|
|
|
103
|
-
export interface
|
|
104
|
-
|
|
105
|
-
|
|
118
|
+
export interface AdornmentProps {
|
|
119
|
+
key: Key;
|
|
120
|
+
definition: ControlAdornment;
|
|
106
121
|
}
|
|
107
122
|
|
|
108
|
-
export interface
|
|
109
|
-
|
|
110
|
-
|
|
123
|
+
export interface AdornmentRenderer {
|
|
124
|
+
wrap?: (children: ReactElement) => ReactElement;
|
|
125
|
+
child?: [AdornmentPlacement, ReactNode];
|
|
111
126
|
}
|
|
112
127
|
|
|
113
|
-
export interface
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
128
|
+
export interface FormRenderer {
|
|
129
|
+
renderData: (props: DataRendererProps) => ReactElement;
|
|
130
|
+
renderGroup: (props: GroupRendererProps) => ReactElement;
|
|
131
|
+
renderDisplay: (props: DisplayRendererProps) => ReactElement;
|
|
132
|
+
renderAction: (props: ActionRendererProps) => ReactElement;
|
|
133
|
+
renderArray: (props: ArrayRendererProps) => ReactElement;
|
|
134
|
+
renderLabel: (props: LabelRendererProps, elem: ReactElement) => ReactElement;
|
|
135
|
+
renderVisibility: (visible: Visibility, elem: ReactElement) => ReactElement;
|
|
136
|
+
renderAdornment: (props: AdornmentProps) => AdornmentRenderer;
|
|
118
137
|
}
|
|
119
138
|
|
|
120
|
-
export interface
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
childCount: number;
|
|
124
|
-
renderChild: (
|
|
125
|
-
child: number,
|
|
126
|
-
wrapChild: (key: Key, childElem: ReactElement) => ReactElement
|
|
127
|
-
) => ReactElement;
|
|
139
|
+
export interface Visibility {
|
|
140
|
+
value: boolean;
|
|
141
|
+
canChange: boolean;
|
|
128
142
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
data: Control<{
|
|
138
|
-
[field: string]: any;
|
|
139
|
-
}>,
|
|
140
|
-
wrapChild: (key: Key, childElem: ReactElement) => ReactElement
|
|
141
|
-
) => ReactElement;
|
|
143
|
+
export interface LabelRendererProps {
|
|
144
|
+
visible: Visibility;
|
|
145
|
+
title?: ReactNode;
|
|
146
|
+
forId?: string;
|
|
147
|
+
required: boolean;
|
|
148
|
+
control?: Control<any>;
|
|
149
|
+
group?: boolean;
|
|
150
|
+
renderAdornment: (placement: AdornmentPlacement) => ReactElement;
|
|
142
151
|
}
|
|
143
152
|
|
|
144
|
-
export
|
|
145
|
-
|
|
153
|
+
export interface DisplayRendererProps {
|
|
154
|
+
definition: DisplayControlDefinition;
|
|
155
|
+
visible: Visibility;
|
|
146
156
|
}
|
|
147
157
|
|
|
148
|
-
export
|
|
149
|
-
|
|
158
|
+
export interface ActionRendererProps {
|
|
159
|
+
definition: ActionControlDefinition;
|
|
160
|
+
visible: Visibility;
|
|
161
|
+
onClick: () => void;
|
|
150
162
|
}
|
|
151
163
|
|
|
152
164
|
export type AnySchemaFields =
|
|
153
165
|
| SchemaField
|
|
154
166
|
| (Omit<CompoundField, "children"> & { children: AnySchemaFields[] });
|
|
155
167
|
|
|
156
|
-
export function
|
|
157
|
-
|
|
158
|
-
fields: SchemaField[]
|
|
159
|
-
): any {
|
|
160
|
-
if (!v) return defaultValueForFields(fields);
|
|
161
|
-
const applyValue = fields.filter(
|
|
162
|
-
(x) => isCompoundField(x) || !(x.field in v)
|
|
163
|
-
);
|
|
164
|
-
if (!applyValue.length) return v;
|
|
165
|
-
const out = { ...v };
|
|
166
|
-
applyValue.forEach((x) => {
|
|
167
|
-
out[x.field] =
|
|
168
|
-
x.field in v
|
|
169
|
-
? applyDefaultForField(v[x.field], x, fields)
|
|
170
|
-
: defaultValueForField(x);
|
|
171
|
-
});
|
|
172
|
-
return out;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export function applyDefaultForField(
|
|
176
|
-
v: any,
|
|
168
|
+
export function controlTitle(
|
|
169
|
+
title: string | undefined | null,
|
|
177
170
|
field: SchemaField,
|
|
178
|
-
|
|
179
|
-
notElement?: boolean
|
|
180
|
-
): any {
|
|
181
|
-
if (field.collection && !notElement) {
|
|
182
|
-
return ((v as any[]) ?? []).map((x) =>
|
|
183
|
-
applyDefaultForField(x, field, parent, true)
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
if (isCompoundField(field)) {
|
|
187
|
-
if (!v && !field.required) return v;
|
|
188
|
-
return applyDefaultValues(v, field.treeChildren ? parent : field.children);
|
|
189
|
-
}
|
|
190
|
-
return defaultValueForField(field);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export function defaultValueForFields(fields: SchemaField[]): any {
|
|
194
|
-
return Object.fromEntries(
|
|
195
|
-
fields.map((x) => [x.field, defaultValueForField(x)])
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export function defaultValueForField(sf: SchemaField): any {
|
|
200
|
-
if (isCompoundField(sf)) {
|
|
201
|
-
return sf.required
|
|
202
|
-
? sf.collection
|
|
203
|
-
? []
|
|
204
|
-
: defaultValueForFields(sf.children)
|
|
205
|
-
: undefined;
|
|
206
|
-
}
|
|
207
|
-
if (sf.collection) return [];
|
|
208
|
-
return sf.defaultValue;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export function elementValueForField(sf: SchemaField): any {
|
|
212
|
-
if (isCompoundField(sf)) {
|
|
213
|
-
return defaultValueForFields(sf.children);
|
|
214
|
-
}
|
|
215
|
-
return sf.defaultValue;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
export function findScalarField(
|
|
219
|
-
fields: SchemaField[],
|
|
220
|
-
field: string
|
|
221
|
-
): SchemaField | undefined {
|
|
222
|
-
return findField(fields, field);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export function findCompoundField(
|
|
226
|
-
fields: SchemaField[],
|
|
227
|
-
field: string
|
|
228
|
-
): CompoundField | undefined {
|
|
229
|
-
return findField(fields, field) as CompoundField | undefined;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
export function findField(
|
|
233
|
-
fields: SchemaField[],
|
|
234
|
-
field: string
|
|
235
|
-
): SchemaField | undefined {
|
|
236
|
-
return fields.find((x) => x.field === field);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export function fieldDisplayName(sf: SchemaField): string {
|
|
240
|
-
return sf.displayName ? sf.displayName : sf.field;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export function controlTitle(title: string | undefined, field: SchemaField) {
|
|
171
|
+
) {
|
|
244
172
|
return title ? title : fieldDisplayName(field);
|
|
245
173
|
}
|
|
246
174
|
|
|
247
|
-
export function renderControl(
|
|
248
|
-
definition:
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
key
|
|
252
|
-
wrapChild?: (key: Key, db: ReactElement) => ReactElement
|
|
175
|
+
export function renderControl<S extends ControlDefinition>(
|
|
176
|
+
definition: S,
|
|
177
|
+
data: Control<any>,
|
|
178
|
+
options: RenderControlOptions,
|
|
179
|
+
key?: Key,
|
|
253
180
|
): ReactElement {
|
|
254
|
-
const { fields } =
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
key={key}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
hooks={hooks}
|
|
285
|
-
formState={formState}
|
|
286
|
-
wrapElem={wrapElem}
|
|
287
|
-
displayDef={definition as DisplayControlDefinition}
|
|
288
|
-
/>
|
|
289
|
-
);
|
|
290
|
-
case ControlDefinitionType.Action:
|
|
291
|
-
return (
|
|
292
|
-
<ActionRenderer
|
|
293
|
-
key={key}
|
|
294
|
-
hooks={hooks}
|
|
295
|
-
formState={formState}
|
|
296
|
-
wrapElem={wrapElem}
|
|
297
|
-
actionDef={definition as ActionControlDefinition}
|
|
298
|
-
/>
|
|
299
|
-
);
|
|
300
|
-
default:
|
|
301
|
-
return <h1>Unknown control: {(definition as any).type}</h1>;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function wrapElem(e: ReactElement): ReactElement {
|
|
305
|
-
return wrapChild?.(key, e) ?? e;
|
|
306
|
-
}
|
|
181
|
+
const { fields } = options;
|
|
182
|
+
const formState = { ...options, data };
|
|
183
|
+
return visitControlDefinition(
|
|
184
|
+
definition,
|
|
185
|
+
{
|
|
186
|
+
data: (def) => {
|
|
187
|
+
const fieldData = findScalarField(fields, def.field);
|
|
188
|
+
if (!fieldData)
|
|
189
|
+
return <h1 key={key}>No schema field for: {def.field}</h1>;
|
|
190
|
+
return (
|
|
191
|
+
<DataRenderer
|
|
192
|
+
key={key}
|
|
193
|
+
formState={formState}
|
|
194
|
+
controlDef={def}
|
|
195
|
+
fieldData={fieldData}
|
|
196
|
+
/>
|
|
197
|
+
);
|
|
198
|
+
},
|
|
199
|
+
group: (d: GroupedControlsDefinition) => (
|
|
200
|
+
<GroupRenderer key={key} groupDef={d} formState={formState} />
|
|
201
|
+
),
|
|
202
|
+
action: (d: ActionControlDefinition) => (
|
|
203
|
+
<ActionRenderer key={key} formState={formState} actionDef={d} />
|
|
204
|
+
),
|
|
205
|
+
display: (d: DisplayControlDefinition) => (
|
|
206
|
+
<DisplayRenderer key={key} formState={formState} displayDef={d} />
|
|
207
|
+
),
|
|
208
|
+
},
|
|
209
|
+
() => <h1>Unknown control: {(definition as any).type}</h1>,
|
|
210
|
+
);
|
|
307
211
|
}
|
|
308
212
|
|
|
213
|
+
/** @trackControls */
|
|
309
214
|
function DataRenderer({
|
|
310
|
-
hooks,
|
|
311
215
|
formState,
|
|
312
216
|
controlDef,
|
|
313
|
-
wrapElem,
|
|
314
217
|
fieldData,
|
|
315
218
|
}: {
|
|
316
|
-
hooks: FormEditHooks;
|
|
317
219
|
controlDef: DataControlDefinition;
|
|
318
220
|
formState: FormEditState;
|
|
319
221
|
fieldData: SchemaField;
|
|
320
|
-
wrapElem: (db: ReactElement) => ReactElement;
|
|
321
222
|
}) {
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
useControlEffect(
|
|
327
|
-
() => scalarControl.value,
|
|
328
|
-
(v) => {
|
|
329
|
-
if (props.defaultValue && !v) {
|
|
330
|
-
scalarControl.value = props.defaultValue;
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
true
|
|
334
|
-
);
|
|
335
|
-
if (!props.visible) {
|
|
336
|
-
return <></>;
|
|
337
|
-
}
|
|
338
|
-
const scalarProps: DataRendererProps = {
|
|
339
|
-
formEditState: formState,
|
|
340
|
-
field: fieldData,
|
|
341
|
-
definition: controlDef,
|
|
342
|
-
properties: props,
|
|
343
|
-
};
|
|
344
|
-
return wrapElem(
|
|
345
|
-
(props.customRender ?? renderer.renderData)(
|
|
346
|
-
scalarProps,
|
|
347
|
-
scalarControl,
|
|
348
|
-
false,
|
|
349
|
-
renderer
|
|
350
|
-
)
|
|
223
|
+
const props = formState.hooks.useDataProperties(
|
|
224
|
+
formState,
|
|
225
|
+
controlDef,
|
|
226
|
+
fieldData,
|
|
351
227
|
);
|
|
228
|
+
return (props.customRender ?? formState.renderer.renderData)(props);
|
|
352
229
|
}
|
|
353
230
|
|
|
231
|
+
/** @trackControls */
|
|
354
232
|
function ActionRenderer({
|
|
355
|
-
hooks,
|
|
356
233
|
formState,
|
|
357
|
-
wrapElem,
|
|
358
234
|
actionDef,
|
|
359
235
|
}: {
|
|
360
|
-
hooks: FormEditHooks;
|
|
361
236
|
actionDef: ActionControlDefinition;
|
|
362
237
|
formState: FormEditState;
|
|
363
|
-
wrapElem: (db: ReactElement) => ReactElement;
|
|
364
238
|
}) {
|
|
365
|
-
const
|
|
366
|
-
const actionControlProperties = hooks.useActionProperties(
|
|
239
|
+
const actionControlProperties = formState.hooks.useActionProperties(
|
|
367
240
|
formState,
|
|
368
|
-
actionDef
|
|
369
|
-
);
|
|
370
|
-
if (!actionControlProperties.visible) {
|
|
371
|
-
return <></>;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return wrapElem(
|
|
375
|
-
renderAction({ definition: actionDef, properties: actionControlProperties })
|
|
241
|
+
actionDef,
|
|
376
242
|
);
|
|
243
|
+
return formState.renderer.renderAction(actionControlProperties);
|
|
377
244
|
}
|
|
378
245
|
|
|
246
|
+
/** @trackControls */
|
|
379
247
|
function GroupRenderer({
|
|
380
|
-
hooks,
|
|
381
248
|
formState,
|
|
382
249
|
groupDef,
|
|
383
|
-
wrapElem,
|
|
384
250
|
}: {
|
|
385
|
-
hooks: FormEditHooks;
|
|
386
251
|
groupDef: GroupedControlsDefinition;
|
|
387
252
|
formState: FormEditState;
|
|
388
|
-
wrapElem: (db: ReactElement) => ReactElement;
|
|
389
253
|
}) {
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
const groupProps = hooks.useGroupProperties(formState, groupDef, hooks);
|
|
393
|
-
if (!groupProps.visible) {
|
|
394
|
-
return <></>;
|
|
395
|
-
}
|
|
396
|
-
const compoundField = groupDef.compoundField
|
|
397
|
-
? findCompoundField(formState.fields, groupDef.compoundField)
|
|
398
|
-
: undefined;
|
|
399
|
-
if (compoundField) {
|
|
400
|
-
return wrapElem(
|
|
401
|
-
renderers.renderCompound(
|
|
402
|
-
{
|
|
403
|
-
definition: groupDef,
|
|
404
|
-
field: compoundField,
|
|
405
|
-
properties: groupProps,
|
|
406
|
-
renderChild: (k, c, data, wrapChild) =>
|
|
407
|
-
renderControl(
|
|
408
|
-
c as AnyControlDefinition,
|
|
409
|
-
{
|
|
410
|
-
...formState,
|
|
411
|
-
fields: compoundField!.children,
|
|
412
|
-
data,
|
|
413
|
-
},
|
|
414
|
-
groupProps.hooks,
|
|
415
|
-
k,
|
|
416
|
-
wrapChild
|
|
417
|
-
),
|
|
418
|
-
},
|
|
419
|
-
formState.data.fields[compoundField.field],
|
|
420
|
-
renderers
|
|
421
|
-
)
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
return wrapElem(
|
|
425
|
-
renderers.renderGroup({
|
|
426
|
-
definition: groupDef,
|
|
427
|
-
childCount: groupDef.children.length,
|
|
428
|
-
properties: groupProps,
|
|
429
|
-
renderChild: (c, wrapChild) =>
|
|
430
|
-
renderControl(
|
|
431
|
-
groupDef.children[c],
|
|
432
|
-
formState,
|
|
433
|
-
groupProps.hooks,
|
|
434
|
-
c,
|
|
435
|
-
wrapChild
|
|
436
|
-
),
|
|
437
|
-
})
|
|
438
|
-
);
|
|
254
|
+
const groupProps = formState.hooks.useGroupProperties(formState, groupDef);
|
|
255
|
+
return formState.renderer.renderGroup(groupProps);
|
|
439
256
|
}
|
|
440
257
|
|
|
258
|
+
/** @trackControls */
|
|
441
259
|
function DisplayRenderer({
|
|
442
|
-
hooks,
|
|
443
|
-
wrapElem,
|
|
444
260
|
formState,
|
|
445
261
|
displayDef,
|
|
446
262
|
}: {
|
|
447
|
-
hooks: FormEditHooks;
|
|
448
263
|
displayDef: DisplayControlDefinition;
|
|
449
264
|
formState: FormEditState;
|
|
450
|
-
wrapElem: (db: ReactElement) => ReactElement;
|
|
451
265
|
}) {
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
if (!displayProps.visible) {
|
|
456
|
-
return <></>;
|
|
457
|
-
}
|
|
458
|
-
return wrapElem(
|
|
459
|
-
renderDisplay({ definition: displayDef, properties: displayProps })
|
|
266
|
+
const displayProps = formState.hooks.useDisplayProperties(
|
|
267
|
+
formState,
|
|
268
|
+
displayDef,
|
|
460
269
|
);
|
|
270
|
+
return formState.renderer.renderDisplay(displayProps);
|
|
461
271
|
}
|
|
462
272
|
|
|
463
273
|
export function controlForField(
|
|
464
274
|
field: string,
|
|
465
|
-
formState: FormEditState
|
|
275
|
+
formState: FormEditState,
|
|
466
276
|
): Control<any> {
|
|
467
277
|
const refField = findField(formState.fields, field);
|
|
468
278
|
return (
|
|
@@ -478,14 +288,61 @@ export function fieldForControl(c: ControlDefinition) {
|
|
|
478
288
|
: undefined;
|
|
479
289
|
}
|
|
480
290
|
|
|
481
|
-
export
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
291
|
+
export const AlwaysVisible: Visibility = { value: true, canChange: false };
|
|
292
|
+
|
|
293
|
+
export function createAction(
|
|
294
|
+
label: string,
|
|
295
|
+
onClick: () => void,
|
|
296
|
+
actionId?: string,
|
|
297
|
+
): ActionRendererProps {
|
|
298
|
+
return {
|
|
299
|
+
definition: {
|
|
300
|
+
type: ControlDefinitionType.Action,
|
|
301
|
+
actionId: actionId ?? label,
|
|
302
|
+
title: label,
|
|
303
|
+
},
|
|
304
|
+
visible: AlwaysVisible,
|
|
305
|
+
onClick,
|
|
306
|
+
};
|
|
485
307
|
}
|
|
486
308
|
|
|
487
|
-
export function
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
309
|
+
export function visitControlData<S extends ControlDefinition, A>(
|
|
310
|
+
definition: S,
|
|
311
|
+
{ fields, data }: FormDataContext,
|
|
312
|
+
cb: (
|
|
313
|
+
definition: DataControlDefinition,
|
|
314
|
+
control: Control<any>,
|
|
315
|
+
) => A | undefined,
|
|
316
|
+
): A | undefined {
|
|
317
|
+
return visitControlDefinition<A | undefined>(
|
|
318
|
+
definition,
|
|
319
|
+
{
|
|
320
|
+
data(def: DataControlDefinition) {
|
|
321
|
+
const fieldData = findScalarField(fields, def.field);
|
|
322
|
+
if (!fieldData) return undefined;
|
|
323
|
+
return cb(def, data.fields[fieldData.field]);
|
|
324
|
+
},
|
|
325
|
+
group(d: GroupedControlsDefinition) {
|
|
326
|
+
if (d.compoundField) {
|
|
327
|
+
const compound = findCompoundField(fields, d.compoundField);
|
|
328
|
+
if (!compound) return;
|
|
329
|
+
fields = compound.children;
|
|
330
|
+
data = data.fields[compound.field];
|
|
331
|
+
}
|
|
332
|
+
const childState = { fields, data };
|
|
333
|
+
for (let c of d.children) {
|
|
334
|
+
const res = visitControlData(c, childState, cb);
|
|
335
|
+
if (res !== undefined) return res;
|
|
336
|
+
}
|
|
337
|
+
return undefined;
|
|
338
|
+
},
|
|
339
|
+
action(d: ActionControlDefinition) {
|
|
340
|
+
return undefined;
|
|
341
|
+
},
|
|
342
|
+
display(d: DisplayControlDefinition) {
|
|
343
|
+
return undefined;
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
() => undefined,
|
|
347
|
+
);
|
|
491
348
|
}
|