@react-typed-forms/schemas 7.1.0 → 7.3.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/internal.ts CHANGED
@@ -1,4 +1,10 @@
1
- import { Control, useControl, useControlEffect } from "@react-typed-forms/core";
1
+ import {
2
+ ChangeListenerFunc,
3
+ Control,
4
+ ControlChange,
5
+ useControl,
6
+ useControlEffect,
7
+ } from "@react-typed-forms/core";
2
8
 
3
9
  export function useCalculatedControl<V>(calculate: () => V): Control<V> {
4
10
  const c = useControl(calculate);
@@ -9,3 +15,34 @@ export function useCalculatedControl<V>(calculate: () => V): Control<V> {
9
15
  export function cc(n: string | null | undefined): string | undefined {
10
16
  return n ? n : undefined;
11
17
  }
18
+
19
+ export function trackedStructure<A>(
20
+ c: Control<A>,
21
+ tracker: ChangeListenerFunc<any>,
22
+ ): A {
23
+ const cc = c.current;
24
+ const cv = cc.value;
25
+ if (cv == null) {
26
+ tracker(c, ControlChange.Structure);
27
+ return cv;
28
+ }
29
+ if (typeof cv !== "object") {
30
+ tracker(c, ControlChange.Value);
31
+ return cv;
32
+ }
33
+ return new Proxy(cv, {
34
+ get(target: object, p: string | symbol, receiver: any): any {
35
+ if (Array.isArray(cv)) {
36
+ tracker(c, ControlChange.Structure);
37
+ if (typeof p === "symbol" || p[0] >= "9" || p[0] < "0")
38
+ return Reflect.get(cv, p);
39
+ const nc = (cc.elements as any)[p];
40
+ if (typeof nc === "function") return nc;
41
+ if (nc == null) return null;
42
+ return trackedStructure(nc, tracker);
43
+ }
44
+ if (p in cv) return trackedStructure((cc.fields as any)[p], tracker);
45
+ return undefined;
46
+ },
47
+ }) as A;
48
+ }
package/src/renderers.tsx CHANGED
@@ -428,8 +428,8 @@ export function createDefaultGroupRenderer(
428
428
  const { style, className: gcn } = isGridRenderer(renderOptions)
429
429
  ? gridStyles(renderOptions)
430
430
  : isFlexRenderer(renderOptions)
431
- ? flexStyles(renderOptions)
432
- : ({ className: standardClassName } as StyleProps);
431
+ ? flexStyles(renderOptions)
432
+ : ({ className: standardClassName } as StyleProps);
433
433
 
434
434
  return (cp: ControlLayoutProps) => {
435
435
  return {
@@ -531,7 +531,11 @@ export function createDefaultDataRenderer(
531
531
  style: props.style,
532
532
  className: props.className,
533
533
  renderOptions: { type: "Standard", hideTitle: true },
534
- renderChild: (i) => props.renderChild(i, i, { control: props.control }),
534
+ renderChild: (i) =>
535
+ props.renderChild(i, i, {
536
+ control: props.dataContext.data,
537
+ parentPath: props.dataContext.path,
538
+ }),
535
539
  childCount: props.childCount,
536
540
  });
537
541
  }
@@ -5,22 +5,22 @@ type AllowedSchema<T> = T extends string
5
5
  type: FieldType.String | FieldType.Date | FieldType.DateTime;
6
6
  }
7
7
  : T extends number
8
- ? SchemaField & {
9
- type: FieldType.Int | FieldType.Double;
10
- }
11
- : T extends boolean
12
- ? SchemaField & {
13
- type: FieldType.Bool;
14
- }
15
- : T extends Array<infer E>
16
- ? AllowedSchema<E> & {
17
- collection: true;
18
- }
19
- : T extends { [key: string]: any }
20
- ? CompoundField & {
21
- type: FieldType.Compound;
22
- }
23
- : SchemaField & { type: FieldType.Any };
8
+ ? SchemaField & {
9
+ type: FieldType.Int | FieldType.Double;
10
+ }
11
+ : T extends boolean
12
+ ? SchemaField & {
13
+ type: FieldType.Bool;
14
+ }
15
+ : T extends Array<infer E>
16
+ ? AllowedSchema<E> & {
17
+ collection: true;
18
+ }
19
+ : T extends { [key: string]: any }
20
+ ? CompoundField & {
21
+ type: FieldType.Compound;
22
+ }
23
+ : SchemaField & { type: FieldType.Any };
24
24
 
25
25
  type AllowedField<T, K> = (
26
26
  name: string,
@@ -56,10 +56,10 @@ export function stringOptionsField(
56
56
  });
57
57
  }
58
58
 
59
- export function withScalarOptions<S extends SchemaField>(
60
- options: Partial<SchemaField>,
61
- v: (name: string) => S,
62
- ): (name: string) => S {
59
+ export function withScalarOptions<
60
+ S extends SchemaField,
61
+ S2 extends Partial<SchemaField>,
62
+ >(options: S2, v: (name: string) => S): (name: string) => S & S2 {
63
63
  return (n) => ({ ...v(n), ...options });
64
64
  }
65
65
 
package/src/util.ts CHANGED
@@ -19,9 +19,9 @@ import {
19
19
  import { MutableRefObject, useRef } from "react";
20
20
  import { Control } from "@react-typed-forms/core";
21
21
  import clsx from "clsx";
22
+ import { DataContext, JsonPath } from "./controlRender";
22
23
 
23
- export interface ControlDataContext {
24
- groupControl: Control<any>;
24
+ export interface ControlDataContext extends DataContext {
25
25
  fields: SchemaField[];
26
26
  schemaInterface: SchemaInterface;
27
27
  }
@@ -251,7 +251,7 @@ export function getTypeField(
251
251
  ): Control<string> | undefined {
252
252
  const typeSchemaField = context.fields.find((x) => x.isTypeField);
253
253
  return typeSchemaField
254
- ? context.groupControl.fields?.[typeSchemaField.field]
254
+ ? lookupChildControl(context, typeSchemaField.field)
255
255
  : undefined;
256
256
  }
257
257
 
@@ -307,30 +307,42 @@ export function visitControlData<A>(
307
307
  if (!fieldData)
308
308
  return !fieldName ? visitControlDataArray(children, ctx, cb) : undefined;
309
309
 
310
- const control = ctx.groupControl.fields[fieldData.field];
310
+ const thisPath = [...ctx.path, fieldData.field];
311
+ const control = ctx.data.lookupControl(thisPath);
312
+ if (!control) throw "No control for field";
311
313
  const result = def ? cb(def, fieldData, control, false) : undefined;
312
314
  if (result !== undefined) return result;
313
315
  if (fieldData.collection) {
314
- for (const c of control.elements ?? []) {
316
+ let cIndex = 0;
317
+ for (const c of control!.elements ?? []) {
315
318
  const elemResult = def ? cb(def, fieldData, c, true) : undefined;
316
319
  if (elemResult !== undefined) return elemResult;
317
320
  if (isCompoundField(fieldData)) {
318
321
  const cfResult = visitControlDataArray(
319
322
  children,
320
323
  {
324
+ ...ctx,
321
325
  fields: fieldData.children,
322
- groupControl: c,
323
- schemaInterface: ctx.schemaInterface,
326
+ path: [...thisPath, cIndex],
324
327
  },
325
328
  cb,
326
329
  );
327
330
  if (cfResult !== undefined) return cfResult;
328
331
  }
332
+ cIndex++;
329
333
  }
330
334
  }
331
335
  }
332
336
  }
333
337
 
338
+ export function lookupChildControl(
339
+ data: DataContext,
340
+ child: JsonPath,
341
+ ): Control<any> | undefined {
342
+ const childPath = [...data.path, child];
343
+ return data.data.lookupControl(childPath);
344
+ }
345
+
334
346
  export function cleanDataForSchema(
335
347
  v: { [k: string]: any } | undefined,
336
348
  fields: SchemaField[],
@@ -383,3 +395,16 @@ export function getAllReferencedClasses(c: ControlDefinition): string[] {
383
395
  if (childClasses) return [tc, ...childClasses];
384
396
  return [tc];
385
397
  }
398
+
399
+ export function jsonPathString(jsonPath: JsonPath[]) {
400
+ let out = "";
401
+ jsonPath.forEach((v, i) => {
402
+ if (typeof v === "number") {
403
+ out += "[" + v + "]";
404
+ } else {
405
+ if (i > 0) out += ".";
406
+ out += v;
407
+ }
408
+ });
409
+ return out;
410
+ }
package/src/validators.ts CHANGED
@@ -70,7 +70,7 @@ function useJsonataValidator(
70
70
  hidden: boolean,
71
71
  i: number,
72
72
  ) {
73
- const errorMsg = useJsonataExpression(expr.expression, context.groupControl);
73
+ const errorMsg = useJsonataExpression(expr.expression, context);
74
74
  useControlEffect(
75
75
  () => [hidden, errorMsg.value],
76
76
  ([hidden, msg]) => control.setError("jsonata" + i, !hidden ? msg : null),