@react-typed-forms/schemas 5.0.3 → 7.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/src/hooks.tsx CHANGED
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  ControlDefinition,
3
+ DataExpression,
4
+ DataMatchExpression,
3
5
  DynamicPropertyType,
4
6
  EntityExpression,
5
7
  ExpressionType,
6
- FieldValueExpression,
7
8
  isDataControlDefinition,
8
9
  JsonataExpression,
9
10
  SchemaField,
11
+ SchemaInterface,
10
12
  } from "./types";
11
13
  import { useCallback, useMemo } from "react";
12
14
  import {
@@ -17,9 +19,10 @@ import {
17
19
  } from "@react-typed-forms/core";
18
20
 
19
21
  import {
20
- ControlGroupContext,
22
+ ControlDataContext,
21
23
  defaultValueForField,
22
24
  findField,
25
+ getDisplayOnlyOptions,
23
26
  getTypeField,
24
27
  isControlReadonly,
25
28
  useUpdatedRef,
@@ -41,13 +44,23 @@ export function useEvalVisibilityHook(
41
44
  DynamicPropertyType.Visible,
42
45
  useEvalExpressionHook,
43
46
  );
44
- const r = useUpdatedRef(schemaField);
47
+ const r = useUpdatedRef({ schemaField, definition });
45
48
  return useCallback(
46
49
  (ctx) => {
47
- const schemaField = r.current;
50
+ const { schemaField, definition } = r.current;
48
51
  return (
49
52
  dynamicVisibility?.(ctx) ??
50
- useComputed(() => matchesType(ctx, schemaField?.onlyForTypes))
53
+ useComputed(
54
+ () =>
55
+ matchesType(ctx, schemaField?.onlyForTypes) &&
56
+ (!schemaField ||
57
+ !hideDisplayOnly(
58
+ ctx,
59
+ schemaField,
60
+ definition,
61
+ ctx.schemaInterface,
62
+ )),
63
+ )
51
64
  );
52
65
  },
53
66
  [dynamicVisibility, r],
@@ -73,6 +86,25 @@ export function useEvalReadonlyHook(
73
86
  );
74
87
  }
75
88
 
89
+ export function useEvalStyleHook(
90
+ useEvalExpressionHook: UseEvalExpressionHook,
91
+ property: DynamicPropertyType,
92
+ definition: ControlDefinition,
93
+ ): EvalExpressionHook<React.CSSProperties> {
94
+ const dynamicStyle = useEvalDynamicHook(
95
+ definition,
96
+ property,
97
+ useEvalExpressionHook,
98
+ );
99
+ return useCallback(
100
+ (ctx) => {
101
+ if (dynamicStyle) return dynamicStyle(ctx);
102
+ return useControl(undefined);
103
+ },
104
+ [dynamicStyle],
105
+ );
106
+ }
107
+
76
108
  export function useEvalDisabledHook(
77
109
  useEvalExpressionHook: UseEvalExpressionHook,
78
110
  definition: ControlDefinition,
@@ -91,6 +123,19 @@ export function useEvalDisabledHook(
91
123
  );
92
124
  }
93
125
 
126
+ export function useEvalDisplayHook(
127
+ useEvalExpressionHook: UseEvalExpressionHook,
128
+ definition: ControlDefinition,
129
+ ): (
130
+ groupContext: ControlDataContext,
131
+ ) => Control<string | undefined> | undefined {
132
+ const dynamicDisplay = useEvalDynamicHook(
133
+ definition,
134
+ DynamicPropertyType.Display,
135
+ useEvalExpressionHook,
136
+ );
137
+ return useCallback((ctx) => dynamicDisplay?.(ctx), [dynamicDisplay]);
138
+ }
94
139
  export function useEvalDefaultValueHook(
95
140
  useEvalExpressionHook: UseEvalExpressionHook,
96
141
  definition: ControlDefinition,
@@ -123,11 +168,21 @@ export function useEvalDefaultValueHook(
123
168
  }
124
169
 
125
170
  export type EvalExpressionHook<A = any> = (
126
- groupContext: ControlGroupContext,
171
+ groupContext: ControlDataContext,
127
172
  ) => Control<A | undefined>;
128
173
 
129
- function useFieldValueExpression(
130
- fvExpr: FieldValueExpression,
174
+ function useDataExpression(
175
+ fvExpr: DataExpression,
176
+ fields: SchemaField[],
177
+ data: Control<any>,
178
+ ) {
179
+ const refField = findField(fields, fvExpr.field);
180
+ const otherField = refField ? data.fields[refField.field] : undefined;
181
+ return useCalculatedControl(() => otherField?.value);
182
+ }
183
+
184
+ function useDataMatchExpression(
185
+ fvExpr: DataMatchExpression,
131
186
  fields: SchemaField[],
132
187
  data: Control<any>,
133
188
  ) {
@@ -141,7 +196,7 @@ function useFieldValueExpression(
141
196
 
142
197
  export function defaultEvalHooks(
143
198
  expr: EntityExpression,
144
- context: ControlGroupContext,
199
+ context: ControlDataContext,
145
200
  ) {
146
201
  switch (expr.type) {
147
202
  case ExpressionType.Jsonata:
@@ -149,9 +204,15 @@ export function defaultEvalHooks(
149
204
  (expr as JsonataExpression).expression,
150
205
  context.groupControl,
151
206
  );
152
- case ExpressionType.FieldValue:
153
- return useFieldValueExpression(
154
- expr as FieldValueExpression,
207
+ case ExpressionType.Data:
208
+ return useDataExpression(
209
+ expr as DataExpression,
210
+ context.fields,
211
+ context.groupControl,
212
+ );
213
+ case ExpressionType.DataMatch:
214
+ return useDataMatchExpression(
215
+ expr as DataMatchExpression,
155
216
  context.fields,
156
217
  context.groupControl,
157
218
  );
@@ -164,12 +225,12 @@ export const defaultUseEvalExpressionHook =
164
225
  makeEvalExpressionHook(defaultEvalHooks);
165
226
 
166
227
  export function makeEvalExpressionHook(
167
- f: (expr: EntityExpression, context: ControlGroupContext) => Control<any>,
228
+ f: (expr: EntityExpression, context: ControlDataContext) => Control<any>,
168
229
  ): (expr: EntityExpression | undefined) => EvalExpressionHook | undefined {
169
230
  return (expr) => {
170
231
  const r = useUpdatedRef(expr);
171
232
  const cb = useCallback(
172
- (ctx: ControlGroupContext) => {
233
+ (ctx: ControlDataContext) => {
173
234
  const expr = r.current!;
174
235
  return f(expr, ctx);
175
236
  },
@@ -191,7 +252,7 @@ export function useEvalDynamicHook(
191
252
  }
192
253
 
193
254
  export function matchesType(
194
- context: ControlGroupContext,
255
+ context: ControlDataContext,
195
256
  types?: string[] | null,
196
257
  ) {
197
258
  if (types == null || types.length === 0) return true;
@@ -199,11 +260,35 @@ export function matchesType(
199
260
  return typeField && types.includes(typeField.value);
200
261
  }
201
262
 
263
+ export function hideDisplayOnly(
264
+ context: ControlDataContext,
265
+ field: SchemaField,
266
+ definition: ControlDefinition,
267
+ schemaInterface: SchemaInterface,
268
+ ) {
269
+ const displayOptions = getDisplayOnlyOptions(definition);
270
+ return (
271
+ displayOptions &&
272
+ !displayOptions.emptyText &&
273
+ schemaInterface.isEmptyValue(
274
+ field,
275
+ context.groupControl.fields[field.field].value,
276
+ )
277
+ );
278
+ }
279
+
202
280
  export function useJsonataExpression(
203
281
  jExpr: string,
204
282
  data: Control<any>,
205
283
  ): Control<any> {
206
- const compiledExpr = useMemo(() => jsonata(jExpr), [jExpr]);
284
+ const compiledExpr = useMemo(() => {
285
+ try {
286
+ return jsonata(jExpr);
287
+ } catch (e) {
288
+ console.error(e);
289
+ return jsonata("");
290
+ }
291
+ }, [jExpr]);
207
292
  const control = useControl();
208
293
  useControlEffect(
209
294
  () => data.value,
package/src/index.ts CHANGED
@@ -7,3 +7,4 @@ export * from "./renderers";
7
7
  export * from "./tailwind";
8
8
  export * from "./validators";
9
9
  export * from "./hooks";
10
+ export * from "./schemaInterface";
package/src/internal.ts CHANGED
@@ -5,3 +5,7 @@ export function useCalculatedControl<V>(calculate: () => V): Control<V> {
5
5
  useControlEffect(calculate, (v) => (c.value = v));
6
6
  return c;
7
7
  }
8
+
9
+ export function cc(n: string | null | undefined): string | undefined {
10
+ return n ? n : undefined;
11
+ }