@react-typed-forms/schemas 1.0.0-dev.18 → 1.0.0-dev.19

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/types.d.ts CHANGED
@@ -12,10 +12,6 @@ export interface SchemaField {
12
12
  searchable?: boolean | null;
13
13
  options?: FieldOption[] | null;
14
14
  validators?: SchemaValidator[] | null;
15
- /**
16
- * @deprecated Use options directly
17
- */
18
- restrictions?: SchemaRestrictions | undefined | null;
19
15
  }
20
16
  export declare enum FieldType {
21
17
  String = "String",
@@ -35,9 +31,6 @@ export interface EntityRefField extends SchemaField {
35
31
  entityRefType: string;
36
32
  parentField: string;
37
33
  }
38
- export interface SchemaRestrictions {
39
- options?: FieldOption[] | null;
40
- }
41
34
  export interface FieldOption {
42
35
  name: string;
43
36
  value: any;
package/lib/util.d.ts CHANGED
@@ -1,6 +1,22 @@
1
- import { FieldOption, SchemaField } from "./types";
1
+ import { CompoundField, ControlDefinition, DataControlDefinition, FieldOption, GroupedControlsDefinition, SchemaField } from "./types";
2
+ export declare function applyDefaultValues(v: {
3
+ [k: string]: any;
4
+ } | undefined, fields: SchemaField[]): any;
5
+ export declare function applyDefaultForField(v: any, field: SchemaField, parent: SchemaField[], notElement?: boolean): any;
6
+ export declare function defaultValueForFields(fields: SchemaField[]): any;
7
+ export declare function defaultValueForField(sf: SchemaField): any;
8
+ export declare function elementValueForField(sf: SchemaField): any;
9
+ export declare function findScalarField(fields: SchemaField[], field: string): SchemaField | undefined;
10
+ export declare function findCompoundField(fields: SchemaField[], field: string): CompoundField | undefined;
11
+ export declare function findField(fields: SchemaField[], field: string): SchemaField | undefined;
12
+ export declare function isScalarField(sf: SchemaField): sf is SchemaField;
13
+ export declare function isCompoundField(sf: SchemaField): sf is CompoundField;
14
+ export declare function isDataControl(c: ControlDefinition): c is DataControlDefinition;
15
+ export declare function isGroupControl(c: ControlDefinition): c is GroupedControlsDefinition;
2
16
  export declare function fieldHasTag(field: SchemaField, tag: string): boolean;
3
17
  export declare function fieldDisplayName(field: SchemaField): string;
4
18
  export declare function hasOptions(o: {
5
19
  options: FieldOption[] | undefined | null;
6
20
  }): boolean;
21
+ export declare function defaultControlForField(sf: SchemaField): DataControlDefinition | GroupedControlsDefinition;
22
+ export declare function addMissingControls(fields: SchemaField[], controls: ControlDefinition[]): ControlDefinition[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-typed-forms/schemas",
3
- "version": "1.0.0-dev.18",
3
+ "version": "1.0.0-dev.19",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -25,18 +25,18 @@
25
25
  ],
26
26
  "dependencies": {
27
27
  "@react-typed-forms/core": "^3.0.0-dev.116",
28
- "react": "^18.2.0",
28
+ "clsx": "^1 || ^2",
29
29
  "jsonata": "^2.0.3",
30
- "clsx": "^1 || ^2"
30
+ "react": "^18.2.0"
31
31
  },
32
32
  "devDependencies": {
33
- "typescript": "^5.2.2",
34
33
  "@react-typed-forms/transform": "^0.1.0",
35
34
  "@types/react": "^18.2.28",
36
35
  "microbundle": "^0.15.1",
37
36
  "nswag": "^13.18.2",
37
+ "prettier": "^3.0.3",
38
38
  "rimraf": "^3.0.2",
39
- "prettier": "^3.0.3"
39
+ "typescript": "^5.2.2"
40
40
  },
41
41
  "gitHead": "698e16cd3ab31b7dd0528fc76536f4d3205ce8c6",
42
42
  "scripts": {
@@ -9,23 +9,15 @@ import {
9
9
  DisplayControlDefinition,
10
10
  EntityExpression,
11
11
  FieldOption,
12
- FieldType,
13
12
  GroupedControlsDefinition,
14
13
  RenderOptions,
15
14
  SchemaField,
16
15
  SchemaValidator,
17
16
  visitControlDefinition,
18
17
  } from "./types";
19
- import React, {
20
- Context,
21
- createContext,
22
- Key,
23
- ReactElement,
24
- ReactNode,
25
- useContext,
26
- } from "react";
27
- import { Control, newControl } from "@react-typed-forms/core";
28
- import { fieldDisplayName } from "./util";
18
+ import React, {Context, createContext, Key, ReactElement, ReactNode, useContext,} from "react";
19
+ import {Control, newControl} from "@react-typed-forms/core";
20
+ import {fieldDisplayName, findCompoundField, findField, findScalarField, isDataControl, isGroupControl} from "./util";
29
21
 
30
22
  export interface SchemaHooks {
31
23
  useExpression(
@@ -190,100 +182,10 @@ export interface ActionRendererProps {
190
182
  onClick: () => void;
191
183
  }
192
184
 
193
- export function isScalarField(sf: SchemaField): sf is SchemaField {
194
- return !isCompoundField(sf);
195
- }
196
-
197
- export function isCompoundField(sf: SchemaField): sf is CompoundField {
198
- return sf.type === FieldType.Compound;
199
- }
200
-
201
185
  export type AnySchemaFields =
202
186
  | SchemaField
203
187
  | (Omit<CompoundField, "children"> & { children: AnySchemaFields[] });
204
188
 
205
- export function applyDefaultValues(
206
- v: { [k: string]: any } | undefined,
207
- fields: SchemaField[],
208
- ): any {
209
- if (!v) return defaultValueForFields(fields);
210
- const applyValue = fields.filter(
211
- (x) => isCompoundField(x) || !(x.field in v),
212
- );
213
- if (!applyValue.length) return v;
214
- const out = { ...v };
215
- applyValue.forEach((x) => {
216
- out[x.field] =
217
- x.field in v
218
- ? applyDefaultForField(v[x.field], x, fields)
219
- : defaultValueForField(x);
220
- });
221
- return out;
222
- }
223
-
224
- export function applyDefaultForField(
225
- v: any,
226
- field: SchemaField,
227
- parent: SchemaField[],
228
- notElement?: boolean,
229
- ): any {
230
- if (field.collection && !notElement) {
231
- return ((v as any[]) ?? []).map((x) =>
232
- applyDefaultForField(x, field, parent, true),
233
- );
234
- }
235
- if (isCompoundField(field)) {
236
- if (!v && !field.required) return v;
237
- return applyDefaultValues(v, field.treeChildren ? parent : field.children);
238
- }
239
- return defaultValueForField(field);
240
- }
241
-
242
- export function defaultValueForFields(fields: SchemaField[]): any {
243
- return Object.fromEntries(
244
- fields.map((x) => [x.field, defaultValueForField(x)]),
245
- );
246
- }
247
-
248
- export function defaultValueForField(sf: SchemaField): any {
249
- if (isCompoundField(sf)) {
250
- return sf.required
251
- ? sf.collection
252
- ? []
253
- : defaultValueForFields(sf.children)
254
- : undefined;
255
- }
256
- if (sf.collection) return [];
257
- return sf.defaultValue;
258
- }
259
-
260
- export function elementValueForField(sf: SchemaField): any {
261
- if (isCompoundField(sf)) {
262
- return defaultValueForFields(sf.children);
263
- }
264
- return sf.defaultValue;
265
- }
266
-
267
- export function findScalarField(
268
- fields: SchemaField[],
269
- field: string,
270
- ): SchemaField | undefined {
271
- return findField(fields, field);
272
- }
273
-
274
- export function findCompoundField(
275
- fields: SchemaField[],
276
- field: string,
277
- ): CompoundField | undefined {
278
- return findField(fields, field) as CompoundField | undefined;
279
- }
280
-
281
- export function findField(
282
- fields: SchemaField[],
283
- field: string,
284
- ): SchemaField | undefined {
285
- return fields.find((x) => x.field === field);
286
- }
287
189
  export function controlTitle(
288
190
  title: string | undefined | null,
289
191
  field: SchemaField,
@@ -437,18 +339,6 @@ export function fieldForControl(c: ControlDefinition) {
437
339
  : undefined;
438
340
  }
439
341
 
440
- export function isDataControl(
441
- c: ControlDefinition,
442
- ): c is DataControlDefinition {
443
- return c.type === ControlDefinitionType.Data;
444
- }
445
-
446
- export function isGroupControl(
447
- c: ControlDefinition,
448
- ): c is GroupedControlsDefinition {
449
- return c.type === ControlDefinitionType.Group;
450
- }
451
-
452
342
  export const AlwaysVisible: Visibility = { value: true, canChange: false };
453
343
 
454
344
  export function createAction(
package/src/hooks.tsx CHANGED
@@ -23,15 +23,10 @@ import {
23
23
  controlForField,
24
24
  controlTitle,
25
25
  DataRendererProps,
26
- elementValueForField,
27
26
  fieldForControl,
28
- findCompoundField,
29
- findField,
30
27
  FormEditHooks,
31
28
  FormEditState,
32
29
  GroupRendererProps,
33
- isGroupControl,
34
- isScalarField,
35
30
  renderControl,
36
31
  SchemaHooks,
37
32
  Visibility,
@@ -49,6 +44,14 @@ import {
49
44
  useValidator,
50
45
  } from "@react-typed-forms/core";
51
46
  import jsonata from "jsonata";
47
+ import {
48
+ addMissingControls,
49
+ elementValueForField,
50
+ findCompoundField,
51
+ findField,
52
+ isGroupControl,
53
+ isScalarField,
54
+ } from "./util";
52
55
 
53
56
  export function useDefaultValue(
54
57
  definition: DataControlDefinition,
@@ -140,7 +143,7 @@ export function getDefaultScalarControlProperties(
140
143
  export function getOptionsForScalarField(
141
144
  field: SchemaField,
142
145
  ): FieldOption[] | undefined | null {
143
- const opts = field.options ?? field.restrictions?.options;
146
+ const opts = field.options;
144
147
  if (opts?.length ?? 0 > 0) {
145
148
  return opts;
146
149
  }
@@ -423,3 +426,16 @@ function defaultArrayRendererProps(
423
426
  },
424
427
  };
425
428
  }
429
+
430
+ export function useControlsWithDefaults(
431
+ definition: GroupedControlsDefinition,
432
+ sf: SchemaField[],
433
+ ) {
434
+ return useMemo(
435
+ () =>
436
+ definition.children.length
437
+ ? definition
438
+ : { ...definition, children: addMissingControls(sf, []) },
439
+ [sf, definition],
440
+ );
441
+ }
package/src/types.ts CHANGED
@@ -12,10 +12,6 @@ export interface SchemaField {
12
12
  searchable?: boolean | null;
13
13
  options?: FieldOption[] | null;
14
14
  validators?: SchemaValidator[] | null;
15
- /**
16
- * @deprecated Use options directly
17
- */
18
- restrictions?: SchemaRestrictions | undefined | null;
19
15
  }
20
16
 
21
17
  export enum FieldType {
@@ -38,10 +34,6 @@ export interface EntityRefField extends SchemaField {
38
34
  parentField: string;
39
35
  }
40
36
 
41
- export interface SchemaRestrictions {
42
- options?: FieldOption[] | null;
43
- }
44
-
45
37
  export interface FieldOption {
46
38
  name: string;
47
39
  value: any;
package/src/util.ts CHANGED
@@ -1,4 +1,119 @@
1
- import { FieldOption, SchemaField } from "./types";
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
+ }
2
117
 
3
118
  export function fieldHasTag(field: SchemaField, tag: string) {
4
119
  return Boolean(field.tags?.includes(tag));
@@ -11,3 +126,87 @@ export function fieldDisplayName(field: SchemaField) {
11
126
  export function hasOptions(o: { options: FieldOption[] | undefined | null }) {
12
127
  return (o.options?.length ?? 0) > 0;
13
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
+ }