@react-typed-forms/schemas 1.0.0-dev.2 → 1.0.0-dev.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +4 -0
- package/.rush/temp/operation/build/state.json +3 -0
- package/.rush/temp/package-deps_build.json +7 -7
- package/.rush/temp/shrinkwrap-deps.json +458 -7
- package/lib/controlRender.d.ts +81 -64
- package/lib/hooks.d.ts +11 -9
- package/lib/index.d.ts +3 -0
- package/lib/index.js +1621 -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 +13 -8
- package/src/controlRender.tsx +229 -321
- package/src/hooks.tsx +441 -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/schemaBuilder.ts
CHANGED
|
@@ -20,11 +20,14 @@ type AllowedSchema<T> = T extends string
|
|
|
20
20
|
? CompoundField & {
|
|
21
21
|
type: FieldType.Compound;
|
|
22
22
|
}
|
|
23
|
-
:
|
|
24
|
-
type AllowedField<T> = (name: string) => AllowedSchema<T>;
|
|
23
|
+
: SchemaField & { type: FieldType.Any };
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
type AllowedField<T, K> = (
|
|
26
|
+
name: string
|
|
27
|
+
) => (SchemaField & { type: K }) | AllowedSchema<T>;
|
|
28
|
+
|
|
29
|
+
export function buildSchema<T, Custom = "">(def: {
|
|
30
|
+
[K in keyof T]-?: AllowedField<T[K], Custom>;
|
|
28
31
|
}): SchemaField[] {
|
|
29
32
|
return Object.entries(def).map((x) =>
|
|
30
33
|
(x[1] as (n: string) => SchemaField)(x[0])
|
package/src/tailwind.tsx
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DefaultRendererOptions } from "./renderers";
|
|
3
|
+
|
|
4
|
+
export const defaultTailwindTheme: DefaultRendererOptions = {
|
|
5
|
+
label: {
|
|
6
|
+
className: "flex flex-col",
|
|
7
|
+
groupLabelClass: "font-bold",
|
|
8
|
+
requiredElement: <span className="text-red-500"> *</span>,
|
|
9
|
+
},
|
|
10
|
+
array: {
|
|
11
|
+
removableClass: "grid grid-cols-[1fr_auto] items-center gap-x-2",
|
|
12
|
+
childClass: "grow",
|
|
13
|
+
},
|
|
14
|
+
group: {
|
|
15
|
+
standardClassName: "space-y-4",
|
|
16
|
+
gridClassName: "gap-x-2 gap-y-4",
|
|
17
|
+
},
|
|
18
|
+
action: {
|
|
19
|
+
className: "bg-primary rounded-lg p-3 text-white",
|
|
20
|
+
},
|
|
21
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
export interface SchemaField {
|
|
2
2
|
type: string;
|
|
3
3
|
field: string;
|
|
4
|
-
displayName?: string;
|
|
5
|
-
tags?: string[];
|
|
6
|
-
system?: boolean;
|
|
7
|
-
collection?: boolean;
|
|
8
|
-
onlyForTypes?: string[];
|
|
9
|
-
required?: boolean;
|
|
4
|
+
displayName?: string | null;
|
|
5
|
+
tags?: string[] | null;
|
|
6
|
+
system?: boolean | null;
|
|
7
|
+
collection?: boolean | null;
|
|
8
|
+
onlyForTypes?: string[] | null;
|
|
9
|
+
required?: boolean | null;
|
|
10
10
|
defaultValue?: any;
|
|
11
|
-
isTypeField?: boolean;
|
|
12
|
-
searchable?: boolean;
|
|
13
|
-
options?: FieldOption[];
|
|
14
|
-
|
|
15
|
-
* @deprecated Use options directly
|
|
16
|
-
*/
|
|
17
|
-
restrictions?: SchemaRestrictions | undefined;
|
|
11
|
+
isTypeField?: boolean | null;
|
|
12
|
+
searchable?: boolean | null;
|
|
13
|
+
options?: FieldOption[] | null;
|
|
14
|
+
validators?: SchemaValidator[] | null;
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
export enum FieldType {
|
|
@@ -28,6 +25,7 @@ export enum FieldType {
|
|
|
28
25
|
Compound = "Compound",
|
|
29
26
|
AutoId = "AutoId",
|
|
30
27
|
Image = "Image",
|
|
28
|
+
Any = "Any",
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
export interface EntityRefField extends SchemaField {
|
|
@@ -36,10 +34,6 @@ export interface EntityRefField extends SchemaField {
|
|
|
36
34
|
parentField: string;
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
export interface SchemaRestrictions {
|
|
40
|
-
options: FieldOption[] | undefined;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
37
|
export interface FieldOption {
|
|
44
38
|
name: string;
|
|
45
39
|
value: any;
|
|
@@ -59,9 +53,9 @@ export type AnyControlDefinition =
|
|
|
59
53
|
|
|
60
54
|
export interface ControlDefinition {
|
|
61
55
|
type: string;
|
|
62
|
-
title?: string;
|
|
63
|
-
dynamic?: DynamicProperty[];
|
|
64
|
-
adornments?: ControlAdornment[];
|
|
56
|
+
title?: string | null;
|
|
57
|
+
dynamic?: DynamicProperty[] | null;
|
|
58
|
+
adornments?: ControlAdornment[] | null;
|
|
65
59
|
}
|
|
66
60
|
|
|
67
61
|
export enum ControlDefinitionType {
|
|
@@ -72,7 +66,7 @@ export enum ControlDefinitionType {
|
|
|
72
66
|
}
|
|
73
67
|
|
|
74
68
|
export interface DynamicProperty {
|
|
75
|
-
type:
|
|
69
|
+
type: string;
|
|
76
70
|
expr: EntityExpression;
|
|
77
71
|
}
|
|
78
72
|
|
|
@@ -82,7 +76,7 @@ export enum DynamicPropertyType {
|
|
|
82
76
|
}
|
|
83
77
|
|
|
84
78
|
export interface EntityExpression {
|
|
85
|
-
type:
|
|
79
|
+
type: string;
|
|
86
80
|
}
|
|
87
81
|
|
|
88
82
|
export enum ExpressionType {
|
|
@@ -92,43 +86,63 @@ export enum ExpressionType {
|
|
|
92
86
|
}
|
|
93
87
|
|
|
94
88
|
export interface JsonataExpression extends EntityExpression {
|
|
89
|
+
type: ExpressionType.Jsonata;
|
|
95
90
|
expression: string;
|
|
96
91
|
}
|
|
97
92
|
|
|
98
93
|
export interface FieldValueExpression extends EntityExpression {
|
|
94
|
+
type: ExpressionType.FieldValue;
|
|
99
95
|
field: string;
|
|
100
96
|
value: any;
|
|
101
97
|
}
|
|
102
98
|
|
|
103
99
|
export interface UserMatchExpression extends EntityExpression {
|
|
100
|
+
type: ExpressionType.UserMatch;
|
|
104
101
|
userMatch: string;
|
|
105
102
|
}
|
|
106
103
|
|
|
107
104
|
export interface ControlAdornment {
|
|
108
|
-
type:
|
|
105
|
+
type: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export enum AdornmentPlacement {
|
|
109
|
+
ControlStart = "ControlStart",
|
|
110
|
+
ControlEnd = "ControlEnd",
|
|
111
|
+
LabelStart = "LabelStart",
|
|
112
|
+
LabelEnd = "LabelEnd",
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
export enum ControlAdornmentType {
|
|
112
116
|
Tooltip = "Tooltip",
|
|
113
117
|
Accordion = "Accordion",
|
|
118
|
+
HelpText = "HelpText",
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
export interface TooltipAdornment extends ControlAdornment {
|
|
122
|
+
type: ControlAdornmentType.Tooltip;
|
|
117
123
|
tooltip: string;
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
export interface AccordionAdornment extends ControlAdornment {
|
|
127
|
+
type: ControlAdornmentType.Accordion;
|
|
121
128
|
title: string;
|
|
122
129
|
defaultExpanded: boolean;
|
|
123
130
|
}
|
|
124
131
|
|
|
132
|
+
export interface HelpTextAdornment extends ControlAdornment {
|
|
133
|
+
type: ControlAdornmentType.HelpText;
|
|
134
|
+
helpText: string;
|
|
135
|
+
placement: AdornmentPlacement;
|
|
136
|
+
}
|
|
137
|
+
|
|
125
138
|
export interface DataControlDefinition extends ControlDefinition {
|
|
126
139
|
type: ControlDefinitionType.Data;
|
|
127
140
|
field: string;
|
|
128
|
-
required?: boolean;
|
|
129
|
-
renderOptions?: RenderOptions;
|
|
141
|
+
required?: boolean | null;
|
|
142
|
+
renderOptions?: RenderOptions | null;
|
|
130
143
|
defaultValue?: any;
|
|
131
|
-
readonly?: boolean;
|
|
144
|
+
readonly?: boolean | null;
|
|
145
|
+
validators?: SchemaValidator[] | null;
|
|
132
146
|
}
|
|
133
147
|
|
|
134
148
|
export interface RenderOptions {
|
|
@@ -145,32 +159,44 @@ export enum DataRenderType {
|
|
|
145
159
|
Synchronised = "Synchronised",
|
|
146
160
|
IconSelector = "IconSelector",
|
|
147
161
|
DateTime = "DateTime",
|
|
162
|
+
Checkbox = "Checkbox",
|
|
163
|
+
Dropdown = "Dropdown",
|
|
148
164
|
}
|
|
149
165
|
|
|
150
|
-
export interface RadioButtonRenderOptions extends RenderOptions {
|
|
166
|
+
export interface RadioButtonRenderOptions extends RenderOptions {
|
|
167
|
+
type: DataRenderType.Radio;
|
|
168
|
+
}
|
|
151
169
|
|
|
152
|
-
export interface StandardRenderer extends RenderOptions {
|
|
170
|
+
export interface StandardRenderer extends RenderOptions {
|
|
171
|
+
type: DataRenderType.Standard;
|
|
172
|
+
}
|
|
153
173
|
|
|
154
174
|
export interface HtmlEditorRenderOptions extends RenderOptions {
|
|
175
|
+
type: DataRenderType.HtmlEditor;
|
|
155
176
|
allowImages: boolean;
|
|
156
177
|
}
|
|
157
178
|
|
|
158
179
|
export interface DateTimeRenderOptions extends RenderOptions {
|
|
159
|
-
|
|
180
|
+
type: DataRenderType.DateTime;
|
|
181
|
+
format?: string | null;
|
|
160
182
|
}
|
|
161
183
|
|
|
162
184
|
export interface IconListRenderOptions extends RenderOptions {
|
|
185
|
+
type: DataRenderType.IconList;
|
|
163
186
|
iconMappings: IconMapping[];
|
|
164
187
|
}
|
|
165
188
|
|
|
166
189
|
export interface IconMapping {
|
|
167
190
|
value: string;
|
|
168
|
-
materialIcon
|
|
191
|
+
materialIcon?: string | null;
|
|
169
192
|
}
|
|
170
193
|
|
|
171
|
-
export interface CheckListRenderOptions extends RenderOptions {
|
|
194
|
+
export interface CheckListRenderOptions extends RenderOptions {
|
|
195
|
+
type: DataRenderType.CheckList;
|
|
196
|
+
}
|
|
172
197
|
|
|
173
198
|
export interface SynchronisedRenderOptions extends RenderOptions {
|
|
199
|
+
type: DataRenderType.Synchronised;
|
|
174
200
|
fieldToSync: string;
|
|
175
201
|
syncType: SyncTextType;
|
|
176
202
|
}
|
|
@@ -182,22 +208,25 @@ export enum SyncTextType {
|
|
|
182
208
|
}
|
|
183
209
|
|
|
184
210
|
export interface UserSelectionRenderOptions extends RenderOptions {
|
|
211
|
+
type: DataRenderType.UserSelection;
|
|
185
212
|
noGroups: boolean;
|
|
186
213
|
noUsers: boolean;
|
|
187
214
|
}
|
|
188
215
|
|
|
189
|
-
export interface IconSelectionRenderOptions extends RenderOptions {
|
|
216
|
+
export interface IconSelectionRenderOptions extends RenderOptions {
|
|
217
|
+
type: DataRenderType.IconSelector;
|
|
218
|
+
}
|
|
190
219
|
|
|
191
220
|
export interface GroupedControlsDefinition extends ControlDefinition {
|
|
192
221
|
type: ControlDefinitionType.Group;
|
|
193
|
-
children:
|
|
194
|
-
compoundField?: string;
|
|
222
|
+
children: ControlDefinition[];
|
|
223
|
+
compoundField?: string | null;
|
|
195
224
|
groupOptions: GroupRenderOptions;
|
|
196
225
|
}
|
|
197
226
|
|
|
198
227
|
export interface GroupRenderOptions {
|
|
199
|
-
type:
|
|
200
|
-
hideTitle?: boolean;
|
|
228
|
+
type: string;
|
|
229
|
+
hideTitle?: boolean | null;
|
|
201
230
|
}
|
|
202
231
|
|
|
203
232
|
export enum GroupRenderType {
|
|
@@ -206,14 +235,18 @@ export enum GroupRenderType {
|
|
|
206
235
|
GroupElement = "GroupElement",
|
|
207
236
|
}
|
|
208
237
|
|
|
209
|
-
export interface StandardGroupRenderer extends GroupRenderOptions {
|
|
238
|
+
export interface StandardGroupRenderer extends GroupRenderOptions {
|
|
239
|
+
type: GroupRenderType.Standard;
|
|
240
|
+
}
|
|
210
241
|
|
|
211
242
|
export interface GroupElementRenderer extends GroupRenderOptions {
|
|
243
|
+
type: GroupRenderType.GroupElement;
|
|
212
244
|
value: any;
|
|
213
245
|
}
|
|
214
246
|
|
|
215
247
|
export interface GridRenderer extends GroupRenderOptions {
|
|
216
|
-
|
|
248
|
+
type: GroupRenderType.Grid;
|
|
249
|
+
columns?: number | null;
|
|
217
250
|
}
|
|
218
251
|
|
|
219
252
|
export interface DisplayControlDefinition extends ControlDefinition {
|
|
@@ -222,7 +255,7 @@ export interface DisplayControlDefinition extends ControlDefinition {
|
|
|
222
255
|
}
|
|
223
256
|
|
|
224
257
|
export interface DisplayData {
|
|
225
|
-
type:
|
|
258
|
+
type: string;
|
|
226
259
|
}
|
|
227
260
|
|
|
228
261
|
export enum DisplayDataType {
|
|
@@ -231,10 +264,12 @@ export enum DisplayDataType {
|
|
|
231
264
|
}
|
|
232
265
|
|
|
233
266
|
export interface TextDisplay extends DisplayData {
|
|
267
|
+
type: DisplayDataType.Text;
|
|
234
268
|
text: string;
|
|
235
269
|
}
|
|
236
270
|
|
|
237
271
|
export interface HtmlDisplay extends DisplayData {
|
|
272
|
+
type: DisplayDataType.Html;
|
|
238
273
|
html: string;
|
|
239
274
|
}
|
|
240
275
|
|
|
@@ -242,3 +277,102 @@ export interface ActionControlDefinition extends ControlDefinition {
|
|
|
242
277
|
type: ControlDefinitionType.Action;
|
|
243
278
|
actionId: string;
|
|
244
279
|
}
|
|
280
|
+
|
|
281
|
+
export enum ValidatorType {
|
|
282
|
+
Jsonata = "Jsonata",
|
|
283
|
+
Date = "Date",
|
|
284
|
+
}
|
|
285
|
+
export interface SchemaValidator {
|
|
286
|
+
type: string;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export interface JsonataValidator extends SchemaValidator {
|
|
290
|
+
type: ValidatorType.Jsonata;
|
|
291
|
+
expression: string;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export enum DateComparison {
|
|
295
|
+
NotBefore = "NotBefore",
|
|
296
|
+
NotAfter = "NotAfter",
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export interface DateValidator extends SchemaValidator {
|
|
300
|
+
type: ValidatorType.Date;
|
|
301
|
+
comparison: DateComparison;
|
|
302
|
+
fixedDate?: string | null;
|
|
303
|
+
daysFromCurrent?: number | null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export function isDataControlDefinition(
|
|
307
|
+
x: ControlDefinition,
|
|
308
|
+
): x is DataControlDefinition {
|
|
309
|
+
return x.type === ControlDefinitionType.Data;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export function isGroupControlsDefinition(
|
|
313
|
+
x: ControlDefinition,
|
|
314
|
+
): x is GroupedControlsDefinition {
|
|
315
|
+
return x.type === ControlDefinitionType.Group;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export function isDisplayControlsDefinition(
|
|
319
|
+
x: ControlDefinition,
|
|
320
|
+
): x is DisplayControlDefinition {
|
|
321
|
+
return x.type === ControlDefinitionType.Display;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export function isActionControlsDefinition(
|
|
325
|
+
x: ControlDefinition,
|
|
326
|
+
): x is ActionControlDefinition {
|
|
327
|
+
return x.type === ControlDefinitionType.Action;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export interface ControlVisitor<A> {
|
|
331
|
+
data(d: DataControlDefinition): A;
|
|
332
|
+
group(d: GroupedControlsDefinition): A;
|
|
333
|
+
display(d: DisplayControlDefinition): A;
|
|
334
|
+
action(d: ActionControlDefinition): A;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export function visitControlDefinition<A>(
|
|
338
|
+
x: ControlDefinition,
|
|
339
|
+
visitor: ControlVisitor<A>,
|
|
340
|
+
defaultValue: (c: ControlDefinition) => A,
|
|
341
|
+
): A {
|
|
342
|
+
switch (x.type) {
|
|
343
|
+
case ControlDefinitionType.Action:
|
|
344
|
+
return visitor.action(x as ActionControlDefinition);
|
|
345
|
+
case ControlDefinitionType.Data:
|
|
346
|
+
return visitor.data(x as DataControlDefinition);
|
|
347
|
+
case ControlDefinitionType.Display:
|
|
348
|
+
return visitor.display(x as DisplayControlDefinition);
|
|
349
|
+
case ControlDefinitionType.Group:
|
|
350
|
+
return visitor.group(x as GroupedControlsDefinition);
|
|
351
|
+
default:
|
|
352
|
+
return defaultValue(x);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export function dataControl(
|
|
357
|
+
field: string,
|
|
358
|
+
options?: Partial<DataControlDefinition>,
|
|
359
|
+
): DataControlDefinition {
|
|
360
|
+
return { type: ControlDefinitionType.Data, field, ...options };
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function fieldValueExpr(
|
|
364
|
+
field: string,
|
|
365
|
+
value: any,
|
|
366
|
+
): FieldValueExpression {
|
|
367
|
+
return { type: ExpressionType.FieldValue, field, value };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function visibility(expr: EntityExpression): DynamicProperty {
|
|
371
|
+
return { type: DynamicPropertyType.Visible, expr };
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function isGridRenderer(
|
|
375
|
+
options: GroupRenderOptions,
|
|
376
|
+
): options is GridRenderer {
|
|
377
|
+
return options.type === GroupRenderType.Grid;
|
|
378
|
+
}
|
package/src/util.ts
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CompoundField,
|
|
3
|
+
ControlDefinition,
|
|
4
|
+
ControlDefinitionType,
|
|
5
|
+
DataControlDefinition,
|
|
6
|
+
DataRenderType,
|
|
7
|
+
FieldOption,
|
|
8
|
+
FieldType,
|
|
9
|
+
GridRenderer,
|
|
10
|
+
GroupedControlsDefinition,
|
|
11
|
+
GroupRenderType,
|
|
12
|
+
SchemaField,
|
|
13
|
+
} from "./types";
|
|
14
|
+
|
|
15
|
+
export function applyDefaultValues(
|
|
16
|
+
v: { [k: string]: any } | undefined,
|
|
17
|
+
fields: SchemaField[],
|
|
18
|
+
): any {
|
|
19
|
+
if (!v) return defaultValueForFields(fields);
|
|
20
|
+
const applyValue = fields.filter(
|
|
21
|
+
(x) => isCompoundField(x) || !(x.field in v),
|
|
22
|
+
);
|
|
23
|
+
if (!applyValue.length) return v;
|
|
24
|
+
const out = { ...v };
|
|
25
|
+
applyValue.forEach((x) => {
|
|
26
|
+
out[x.field] =
|
|
27
|
+
x.field in v
|
|
28
|
+
? applyDefaultForField(v[x.field], x, fields)
|
|
29
|
+
: defaultValueForField(x);
|
|
30
|
+
});
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function applyDefaultForField(
|
|
35
|
+
v: any,
|
|
36
|
+
field: SchemaField,
|
|
37
|
+
parent: SchemaField[],
|
|
38
|
+
notElement?: boolean,
|
|
39
|
+
): any {
|
|
40
|
+
if (field.collection && !notElement) {
|
|
41
|
+
return ((v as any[]) ?? []).map((x) =>
|
|
42
|
+
applyDefaultForField(x, field, parent, true),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (isCompoundField(field)) {
|
|
46
|
+
if (!v && !field.required) return v;
|
|
47
|
+
return applyDefaultValues(v, field.treeChildren ? parent : field.children);
|
|
48
|
+
}
|
|
49
|
+
return defaultValueForField(field);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function defaultValueForFields(fields: SchemaField[]): any {
|
|
53
|
+
return Object.fromEntries(
|
|
54
|
+
fields.map((x) => [x.field, defaultValueForField(x)]),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function defaultValueForField(sf: SchemaField): any {
|
|
59
|
+
if (isCompoundField(sf)) {
|
|
60
|
+
return sf.required
|
|
61
|
+
? sf.collection
|
|
62
|
+
? []
|
|
63
|
+
: defaultValueForFields(sf.children)
|
|
64
|
+
: undefined;
|
|
65
|
+
}
|
|
66
|
+
if (sf.collection) return [];
|
|
67
|
+
return sf.defaultValue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function elementValueForField(sf: SchemaField): any {
|
|
71
|
+
if (isCompoundField(sf)) {
|
|
72
|
+
return defaultValueForFields(sf.children);
|
|
73
|
+
}
|
|
74
|
+
return sf.defaultValue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function findScalarField(
|
|
78
|
+
fields: SchemaField[],
|
|
79
|
+
field: string,
|
|
80
|
+
): SchemaField | undefined {
|
|
81
|
+
return findField(fields, field);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function findCompoundField(
|
|
85
|
+
fields: SchemaField[],
|
|
86
|
+
field: string,
|
|
87
|
+
): CompoundField | undefined {
|
|
88
|
+
return findField(fields, field) as CompoundField | undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function findField(
|
|
92
|
+
fields: SchemaField[],
|
|
93
|
+
field: string,
|
|
94
|
+
): SchemaField | undefined {
|
|
95
|
+
return fields.find((x) => x.field === field);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function isScalarField(sf: SchemaField): sf is SchemaField {
|
|
99
|
+
return !isCompoundField(sf);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function isCompoundField(sf: SchemaField): sf is CompoundField {
|
|
103
|
+
return sf.type === FieldType.Compound;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function isDataControl(
|
|
107
|
+
c: ControlDefinition,
|
|
108
|
+
): c is DataControlDefinition {
|
|
109
|
+
return c.type === ControlDefinitionType.Data;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function isGroupControl(
|
|
113
|
+
c: ControlDefinition,
|
|
114
|
+
): c is GroupedControlsDefinition {
|
|
115
|
+
return c.type === ControlDefinitionType.Group;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function fieldHasTag(field: SchemaField, tag: string) {
|
|
119
|
+
return Boolean(field.tags?.includes(tag));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function fieldDisplayName(field: SchemaField) {
|
|
123
|
+
return field.displayName ?? field.field;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function hasOptions(o: { options: FieldOption[] | undefined | null }) {
|
|
127
|
+
return (o.options?.length ?? 0) > 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function defaultControlForField(
|
|
131
|
+
sf: SchemaField,
|
|
132
|
+
): DataControlDefinition | GroupedControlsDefinition {
|
|
133
|
+
if (isCompoundField(sf)) {
|
|
134
|
+
return {
|
|
135
|
+
type: ControlDefinitionType.Group,
|
|
136
|
+
title: sf.displayName,
|
|
137
|
+
compoundField: sf.field,
|
|
138
|
+
groupOptions: {
|
|
139
|
+
type: GroupRenderType.Grid,
|
|
140
|
+
hideTitle: false,
|
|
141
|
+
} as GridRenderer,
|
|
142
|
+
children: sf.children.map(defaultControlForField),
|
|
143
|
+
} satisfies GroupedControlsDefinition;
|
|
144
|
+
} else if (isScalarField(sf)) {
|
|
145
|
+
const htmlEditor = sf.tags?.includes("_HtmlEditor");
|
|
146
|
+
return {
|
|
147
|
+
type: ControlDefinitionType.Data,
|
|
148
|
+
title: sf.displayName,
|
|
149
|
+
field: sf.field,
|
|
150
|
+
required: sf.required,
|
|
151
|
+
renderOptions: {
|
|
152
|
+
type: htmlEditor ? DataRenderType.HtmlEditor : DataRenderType.Standard,
|
|
153
|
+
},
|
|
154
|
+
} satisfies DataControlDefinition;
|
|
155
|
+
}
|
|
156
|
+
throw "Unknown schema field";
|
|
157
|
+
}
|
|
158
|
+
function findReferencedControl(
|
|
159
|
+
field: string,
|
|
160
|
+
control: ControlDefinition,
|
|
161
|
+
): ControlDefinition | undefined {
|
|
162
|
+
if (isDataControl(control) && field === control.field) return control;
|
|
163
|
+
if (isGroupControl(control)) {
|
|
164
|
+
if (control.compoundField)
|
|
165
|
+
return field === control.compoundField ? control : undefined;
|
|
166
|
+
return findReferencedControlInArray(field, control.children);
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function findReferencedControlInArray(
|
|
172
|
+
field: string,
|
|
173
|
+
controls: ControlDefinition[],
|
|
174
|
+
): ControlDefinition | undefined {
|
|
175
|
+
for (const c of controls) {
|
|
176
|
+
const ref = findReferencedControl(field, c);
|
|
177
|
+
if (ref) return ref;
|
|
178
|
+
}
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function addMissingControls(
|
|
183
|
+
fields: SchemaField[],
|
|
184
|
+
controls: ControlDefinition[],
|
|
185
|
+
): ControlDefinition[] {
|
|
186
|
+
const changes: {
|
|
187
|
+
field: SchemaField;
|
|
188
|
+
existing: ControlDefinition | undefined;
|
|
189
|
+
}[] = fields.flatMap((x) => {
|
|
190
|
+
if (fieldHasTag(x, "_NoControl")) return [];
|
|
191
|
+
const existing = findReferencedControlInArray(x.field, controls);
|
|
192
|
+
if (!existing || isCompoundField(x)) return { field: x, existing };
|
|
193
|
+
return [];
|
|
194
|
+
});
|
|
195
|
+
const changedCompounds = controls.map((x) => {
|
|
196
|
+
const ex = changes.find((c) => c.existing === x);
|
|
197
|
+
if (!ex) return x;
|
|
198
|
+
const cf = x as GroupedControlsDefinition;
|
|
199
|
+
return {
|
|
200
|
+
...cf,
|
|
201
|
+
children: addMissingControls(
|
|
202
|
+
(ex.field as CompoundField).children,
|
|
203
|
+
cf.children,
|
|
204
|
+
),
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
return changedCompounds.concat(
|
|
208
|
+
changes
|
|
209
|
+
.filter((x) => !x.existing)
|
|
210
|
+
.map((x) => defaultControlForField(x.field)),
|
|
211
|
+
);
|
|
212
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
3
|
+
"target": "ESNext",
|
|
4
4
|
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
5
|
"allowJs": true,
|
|
6
6
|
"skipLibCheck": true,
|
|
7
7
|
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
8
9
|
"forceConsistentCasingInFileNames": true,
|
|
9
10
|
"esModuleInterop": true,
|
|
10
11
|
"declaration": true,
|
|
11
|
-
"module": "
|
|
12
|
+
"module": "ESNext",
|
|
12
13
|
"moduleResolution": "node",
|
|
13
14
|
"resolveJsonModule": true,
|
|
14
15
|
"isolatedModules": true,
|
|
15
|
-
"jsx": "
|
|
16
|
+
"jsx": "preserve",
|
|
16
17
|
"outDir": "lib"
|
|
17
18
|
},
|
|
18
19
|
"include": ["src/**/*.ts", "src/**/*.tsx"],
|