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

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.
@@ -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,5 +1,3 @@
1
- import { DataControlProperties } from "./controlRender";
2
-
3
1
  export interface SchemaField {
4
2
  type: string;
5
3
  field: string;
@@ -13,6 +11,7 @@ export interface SchemaField {
13
11
  isTypeField?: boolean | null;
14
12
  searchable?: boolean | null;
15
13
  options?: FieldOption[] | null;
14
+ validators?: SchemaValidator[] | null;
16
15
  /**
17
16
  * @deprecated Use options directly
18
17
  */
@@ -114,9 +113,17 @@ export interface ControlAdornment {
114
113
  type: string;
115
114
  }
116
115
 
116
+ export enum AdornmentPlacement {
117
+ ControlStart = "ControlStart",
118
+ ControlEnd = "ControlEnd",
119
+ LabelStart = "LabelStart",
120
+ LabelEnd = "LabelEnd",
121
+ }
122
+
117
123
  export enum ControlAdornmentType {
118
124
  Tooltip = "Tooltip",
119
125
  Accordion = "Accordion",
126
+ HelpText = "HelpText",
120
127
  }
121
128
 
122
129
  export interface TooltipAdornment extends ControlAdornment {
@@ -130,6 +137,12 @@ export interface AccordionAdornment extends ControlAdornment {
130
137
  defaultExpanded: boolean;
131
138
  }
132
139
 
140
+ export interface HelpTextAdornment extends ControlAdornment {
141
+ type: ControlAdornmentType.HelpText;
142
+ helpText: string;
143
+ placement: AdornmentPlacement;
144
+ }
145
+
133
146
  export interface DataControlDefinition extends ControlDefinition {
134
147
  type: ControlDefinitionType.Data;
135
148
  field: string;
@@ -137,6 +150,7 @@ export interface DataControlDefinition extends ControlDefinition {
137
150
  renderOptions?: RenderOptions | null;
138
151
  defaultValue?: any;
139
152
  readonly?: boolean | null;
153
+ validators?: SchemaValidator[] | null;
140
154
  }
141
155
 
142
156
  export interface RenderOptions {
@@ -153,6 +167,8 @@ export enum DataRenderType {
153
167
  Synchronised = "Synchronised",
154
168
  IconSelector = "IconSelector",
155
169
  DateTime = "DateTime",
170
+ Checkbox = "Checkbox",
171
+ Dropdown = "Dropdown",
156
172
  }
157
173
 
158
174
  export interface RadioButtonRenderOptions extends RenderOptions {
@@ -270,26 +286,51 @@ export interface ActionControlDefinition extends ControlDefinition {
270
286
  actionId: string;
271
287
  }
272
288
 
289
+ export enum ValidatorType {
290
+ Jsonata = "Jsonata",
291
+ Date = "Date",
292
+ }
293
+ export interface SchemaValidator {
294
+ type: string;
295
+ }
296
+
297
+ export interface JsonataValidator extends SchemaValidator {
298
+ type: ValidatorType.Jsonata;
299
+ expression: string;
300
+ }
301
+
302
+ export enum DateComparison {
303
+ NotBefore = "NotBefore",
304
+ NotAfter = "NotAfter",
305
+ }
306
+
307
+ export interface DateValidator extends SchemaValidator {
308
+ type: ValidatorType.Date;
309
+ comparison: DateComparison;
310
+ fixedDate?: string | null;
311
+ daysFromCurrent?: number | null;
312
+ }
313
+
273
314
  export function isDataControlDefinition(
274
- x: ControlDefinition
315
+ x: ControlDefinition,
275
316
  ): x is DataControlDefinition {
276
317
  return x.type === ControlDefinitionType.Data;
277
318
  }
278
319
 
279
320
  export function isGroupControlsDefinition(
280
- x: ControlDefinition
321
+ x: ControlDefinition,
281
322
  ): x is GroupedControlsDefinition {
282
323
  return x.type === ControlDefinitionType.Group;
283
324
  }
284
325
 
285
326
  export function isDisplayControlsDefinition(
286
- x: ControlDefinition
327
+ x: ControlDefinition,
287
328
  ): x is DisplayControlDefinition {
288
329
  return x.type === ControlDefinitionType.Display;
289
330
  }
290
331
 
291
332
  export function isActionControlsDefinition(
292
- x: ControlDefinition
333
+ x: ControlDefinition,
293
334
  ): x is ActionControlDefinition {
294
335
  return x.type === ControlDefinitionType.Action;
295
336
  }
@@ -304,7 +345,7 @@ export interface ControlVisitor<A> {
304
345
  export function visitControlDefinition<A>(
305
346
  x: ControlDefinition,
306
347
  visitor: ControlVisitor<A>,
307
- defaultValue: (c: ControlDefinition) => A
348
+ defaultValue: (c: ControlDefinition) => A,
308
349
  ): A {
309
350
  switch (x.type) {
310
351
  case ControlDefinitionType.Action:
@@ -322,14 +363,14 @@ export function visitControlDefinition<A>(
322
363
 
323
364
  export function dataControl(
324
365
  field: string,
325
- options?: Partial<DataControlDefinition>
366
+ options?: Partial<DataControlDefinition>,
326
367
  ): DataControlDefinition {
327
368
  return { type: ControlDefinitionType.Data, field, ...options };
328
369
  }
329
370
 
330
371
  export function fieldValueExpr(
331
372
  field: string,
332
- value: any
373
+ value: any,
333
374
  ): FieldValueExpression {
334
375
  return { type: ExpressionType.FieldValue, field, value };
335
376
  }
@@ -337,3 +378,9 @@ export function fieldValueExpr(
337
378
  export function visibility(expr: EntityExpression): DynamicProperty {
338
379
  return { type: DynamicPropertyType.Visible, expr };
339
380
  }
381
+
382
+ export function isGridRenderer(
383
+ options: GroupRenderOptions,
384
+ ): options is GridRenderer {
385
+ return options.type === GroupRenderType.Grid;
386
+ }
package/src/util.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { SchemaField } from "./types";
1
+ import { FieldOption, SchemaField } from "./types";
2
2
 
3
3
  export function fieldHasTag(field: SchemaField, tag: string) {
4
4
  return Boolean(field.tags?.includes(tag));
@@ -7,3 +7,7 @@ export function fieldHasTag(field: SchemaField, tag: string) {
7
7
  export function fieldDisplayName(field: SchemaField) {
8
8
  return field.displayName ?? field.field;
9
9
  }
10
+
11
+ export function hasOptions(o: { options: FieldOption[] | undefined | null }) {
12
+ return (o.options?.length ?? 0) > 0;
13
+ }
package/src/hooks.ts DELETED
@@ -1,173 +0,0 @@
1
- import {
2
- ActionControlDefinition,
3
- ControlDefinition,
4
- DataControlDefinition,
5
- DynamicPropertyType,
6
- EntityExpression,
7
- ExpressionType,
8
- FieldOption,
9
- FieldValueExpression,
10
- SchemaField,
11
- } from "./types";
12
- import {
13
- ActionControlProperties,
14
- controlForField,
15
- DataControlProperties,
16
- ExpressionHook,
17
- fieldForControl,
18
- findField,
19
- FormEditHooks,
20
- FormEditState,
21
- isGroupControl,
22
- isScalarField,
23
- } from "./controlRender";
24
- import { useEffect, useMemo } from "react";
25
- import { Control, newControl } from "@react-typed-forms/core";
26
-
27
- export function useDefaultValue(
28
- definition: DataControlDefinition,
29
- field: SchemaField,
30
- formState: FormEditState,
31
- useExpression: ExpressionHook
32
- ) {
33
- const valueExpression = definition.dynamic?.find(
34
- (x) => x.type === DynamicPropertyType.DefaultValue
35
- );
36
- if (valueExpression) {
37
- return useExpression(valueExpression.expr, formState);
38
- }
39
- return field.defaultValue;
40
- }
41
-
42
- export function useIsControlVisible(
43
- definition: ControlDefinition,
44
- formState: FormEditState,
45
- useExpression: ExpressionHook
46
- ) {
47
- const visibleExpression = definition.dynamic?.find(
48
- (x) => x.type === DynamicPropertyType.Visible
49
- );
50
- if (visibleExpression && visibleExpression.expr) {
51
- return Boolean(useExpression(visibleExpression.expr, formState));
52
- }
53
- const schemaFields = formState.fields;
54
-
55
- const { typeControl, compoundField } = useMemo(() => {
56
- const typeField = schemaFields.find(
57
- (x) => isScalarField(x) && x.isTypeField
58
- ) as SchemaField | undefined;
59
-
60
- const typeControl = ((typeField &&
61
- formState.data.fields?.[typeField.field]) ??
62
- newControl(undefined)) as Control<string | undefined>;
63
- const compoundField =
64
- isGroupControl(definition) && definition.compoundField
65
- ? formState.data.fields[definition.compoundField]
66
- : undefined;
67
- return { typeControl, compoundField };
68
- }, [schemaFields, formState.data]);
69
-
70
- const fieldName = fieldForControl(definition);
71
- const onlyForTypes = (
72
- fieldName ? findField(schemaFields, fieldName) : undefined
73
- )?.onlyForTypes;
74
-
75
- return (
76
- (!compoundField || compoundField.value != null) &&
77
- (!onlyForTypes ||
78
- onlyForTypes.length === 0 ||
79
- Boolean(typeControl.value && onlyForTypes.includes(typeControl.value)))
80
- );
81
- }
82
- export function getDefaultScalarControlProperties(
83
- definition: DataControlDefinition,
84
- field: SchemaField,
85
- visible: boolean,
86
- defaultValue: any,
87
- control: Control<any>,
88
- readonly?: boolean
89
- ): DataControlProperties {
90
- return {
91
- defaultValue,
92
- options: getOptionsForScalarField(field),
93
- required: definition.required ?? false,
94
- visible,
95
- readonly: readonly ?? definition.readonly ?? false,
96
- control,
97
- };
98
- }
99
-
100
- export function getOptionsForScalarField(
101
- field: SchemaField
102
- ): FieldOption[] | undefined | null {
103
- const opts = field.options ?? field.restrictions?.options;
104
- if (opts?.length ?? 0 > 0) {
105
- return opts;
106
- }
107
- return undefined;
108
- }
109
-
110
- export const defaultExpressionHook: ExpressionHook = (
111
- expr: EntityExpression,
112
- formState: FormEditState
113
- ) => {
114
- switch (expr.type) {
115
- case ExpressionType.FieldValue:
116
- const fvExpr = expr as FieldValueExpression;
117
- return controlForField(fvExpr.field, formState).value === fvExpr.value;
118
- default:
119
- return undefined;
120
- }
121
- };
122
-
123
- export function createFormEditHooks(
124
- useExpression: ExpressionHook
125
- ): FormEditHooks {
126
- return {
127
- useExpression,
128
- useDataProperties(
129
- formState: FormEditState,
130
- definition: DataControlDefinition,
131
- field: SchemaField
132
- ): DataControlProperties {
133
- const visible = useIsControlVisible(definition, formState, useExpression);
134
- const defaultValue = useDefaultValue(
135
- definition,
136
- field,
137
- formState,
138
- useExpression
139
- );
140
- const scalarControl = formState.data.fields[field.field];
141
-
142
- useEffect(() => {
143
- if (!visible) scalarControl.value = null;
144
- else if (scalarControl.current.value == null) {
145
- scalarControl.value = defaultValue;
146
- }
147
- }, [visible, defaultValue]);
148
- return getDefaultScalarControlProperties(
149
- definition,
150
- field,
151
- visible,
152
- defaultValue,
153
- scalarControl,
154
- formState.readonly
155
- );
156
- },
157
- useDisplayProperties: (fs, definition) => {
158
- const visible = useIsControlVisible(definition, fs, useExpression);
159
- return { visible };
160
- },
161
- useGroupProperties: (fs, definition, hooks) => {
162
- const visible = useIsControlVisible(definition, fs, useExpression);
163
- return { visible, hooks };
164
- },
165
- useActionProperties(
166
- formState: FormEditState,
167
- definition: ActionControlDefinition
168
- ): ActionControlProperties {
169
- const visible = useIsControlVisible(definition, formState, useExpression);
170
- return { visible, onClick: () => {} };
171
- },
172
- };
173
- }