@astroapps/forms-core 1.0.2 → 1.1.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astroapps/forms-core",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
package/src/formNode.ts CHANGED
@@ -247,3 +247,48 @@ export function visitFormDataInContext<A>(
247
247
  const dataNode = lookupDataNode(node.definition, parentContext);
248
248
  return visitFormData(node, dataNode ?? parentContext, cb, !dataNode);
249
249
  }
250
+
251
+ export interface FormDataNode {
252
+ parent?: FormDataNode;
253
+ formNode: FormNode;
254
+ parentData: SchemaDataNode;
255
+ childIndex?: number;
256
+ }
257
+
258
+ export function visitFormDataNode<A>(
259
+ node: FormDataNode,
260
+ visitFn: (node: FormDataNode, data?: SchemaDataNode) => A | undefined,
261
+ ): A | undefined {
262
+ const dataNode = lookupDataNode(node.formNode.definition, node.parentData);
263
+ const v = visitFn(node, dataNode);
264
+ if (v !== undefined) return v;
265
+
266
+ const parentData = dataNode ?? node.parentData;
267
+ if (parentData.schema.field.collection && parentData.elementIndex == null) {
268
+ const elemCount = parentData.control.elements.length;
269
+ for (let i = 0; i < elemCount; i++) {
270
+ const v = visitChildren(parentData.getChildElement(i));
271
+ if (v !== undefined) return v;
272
+ }
273
+ return undefined;
274
+ } else {
275
+ return visitChildren(parentData);
276
+ }
277
+
278
+ function visitChildren(parentData: SchemaDataNode) {
279
+ const children = node.formNode.getChildNodes();
280
+ for (let i = 0; i < children.length; i++) {
281
+ const child = children[i];
282
+ const res = visitFormDataNode(
283
+ {
284
+ formNode: child,
285
+ parent: node,
286
+ parentData,
287
+ childIndex: i,
288
+ },
289
+ visitFn,
290
+ );
291
+ if (res !== undefined) return res;
292
+ }
293
+ }
294
+ }
package/src/formState.ts CHANGED
@@ -24,15 +24,14 @@ import { SchemaInterface } from "./schemaInterface";
24
24
  import { FieldOption } from "./schemaField";
25
25
  import {
26
26
  CleanupScope,
27
- clearMetaValue,
28
27
  Control,
29
28
  createScopedEffect,
30
29
  createSyncEffect,
31
30
  ensureMetaValue,
32
31
  getControlPath,
33
32
  getCurrentFields,
33
+ getMetaValue,
34
34
  newControl,
35
- trackedValue,
36
35
  unsafeRestoreControl,
37
36
  updateComputedValue,
38
37
  } from "@astroapps/controls";
@@ -49,6 +48,7 @@ export interface ControlState {
49
48
  definition: ControlDefinition;
50
49
  schemaInterface: SchemaInterface;
51
50
  dataNode?: SchemaDataNode | undefined;
51
+ display?: string;
52
52
  stateId?: string;
53
53
  style?: object;
54
54
  layoutStyle?: object;
@@ -58,6 +58,7 @@ export interface ControlState {
58
58
  disabled: boolean;
59
59
  clearHidden: boolean;
60
60
  variables: Record<string, any>;
61
+ meta: Control<Record<string, any>>;
61
62
  }
62
63
 
63
64
  export interface FormContextOptions {
@@ -88,10 +89,24 @@ export interface FormState {
88
89
  cleanup(): void;
89
90
 
90
91
  evalExpression(expr: EntityExpression, context: ExpressionEvalContext): void;
92
+
93
+ getExistingControlState(
94
+ parent: SchemaDataNode,
95
+ formNode: FormNode,
96
+ stateKey?: string,
97
+ ): ControlState | undefined;
91
98
  }
92
99
 
93
100
  const formStates: FormState[] = [];
94
101
 
102
+ export function getControlStateId(
103
+ parent: SchemaDataNode,
104
+ formNode: FormNode,
105
+ stateKey?: string,
106
+ ): string {
107
+ return parent.id + "$" + formNode.id + (stateKey ?? "");
108
+ }
109
+
95
110
  export function createFormState(
96
111
  schemaInterface: SchemaInterface,
97
112
  evaluators: Record<string, ExpressionEval<any>> = defaultEvaluators,
@@ -113,13 +128,25 @@ export function createFormState(
113
128
  // console.log("Cleanup form state");
114
129
  controlStates.cleanup();
115
130
  },
131
+ getExistingControlState(
132
+ parent: SchemaDataNode,
133
+ formNode: FormNode,
134
+ stateKey?: string,
135
+ ): ControlState | undefined {
136
+ const stateId = getControlStateId(parent, formNode, stateKey);
137
+ const control = getCurrentFields(controlStates)[stateId];
138
+ if (control) {
139
+ return getMetaValue<Control<ControlState>>(control, "impl")?.value;
140
+ }
141
+ return undefined;
142
+ },
116
143
  getControlState(
117
144
  parent: SchemaDataNode,
118
145
  formNode: FormNode,
119
146
  context: FormContextOptions,
120
147
  runAsync: (af: () => void) => void,
121
148
  ): ControlState {
122
- const stateId = parent.id + "$" + formNode.id + (context.stateKey ?? "");
149
+ const stateId = getControlStateId(parent, formNode, context.stateKey);
123
150
  const controlImpl = controlStates.fields[stateId];
124
151
  controlImpl.value = context;
125
152
  function evalExpr<A>(
@@ -173,34 +200,6 @@ export function createFormState(
173
200
  Control<any>
174
201
  >;
175
202
 
176
- createScopedEffect((c) => {
177
- const textDisplay =
178
- isDisplayControl(def) && isTextDisplay(def.displayData)
179
- ? def.displayData
180
- : undefined;
181
- evalExpr(
182
- c,
183
- textDisplay?.text,
184
- df.text,
185
- textDisplay && firstExpr(formNode, DynamicPropertyType.Display),
186
- coerceString,
187
- );
188
- }, displayOverrides);
189
-
190
- createScopedEffect((c) => {
191
- const htmlDisplay =
192
- isDisplayControl(def) && isHtmlDisplay(def.displayData)
193
- ? def.displayData
194
- : undefined;
195
- evalExpr(
196
- c,
197
- htmlDisplay?.html,
198
- df.html,
199
- htmlDisplay && firstExpr(formNode, DynamicPropertyType.Display),
200
- coerceString,
201
- );
202
- }, displayOverrides);
203
-
204
203
  updateComputedValue(of.displayData, () =>
205
204
  isDisplayControl(def)
206
205
  ? createOverrideProxy(def.displayData, displayOverrides)
@@ -281,6 +280,7 @@ export function createFormState(
281
280
  hidden: false,
282
281
  variables: controlImpl.fields.variables.current.value ?? {},
283
282
  stateId,
283
+ meta: newControl({}),
284
284
  });
285
285
 
286
286
  const {
@@ -292,6 +292,7 @@ export function createFormState(
292
292
  allowedOptions,
293
293
  disabled,
294
294
  variables,
295
+ display,
295
296
  } = control.fields;
296
297
 
297
298
  createScopedEffect(
@@ -330,6 +331,18 @@ export function createFormState(
330
331
  scope,
331
332
  );
332
333
 
334
+ createScopedEffect(
335
+ (c) =>
336
+ evalExpr(
337
+ c,
338
+ undefined,
339
+ display,
340
+ firstExpr(formNode, DynamicPropertyType.Display),
341
+ coerceString,
342
+ ),
343
+ scope,
344
+ );
345
+
333
346
  updateComputedValue(dataNode, () => lookupDataNode(definition, parent));
334
347
  updateComputedValue(
335
348
  hidden,
@@ -361,6 +374,14 @@ export function createFormState(
361
374
  }
362
375
  }, scope);
363
376
 
377
+ createSyncEffect(() => {
378
+ if (isDisplayControl(def)) {
379
+ if (isTextDisplay(def.displayData)) df.text.value = display.value;
380
+ else if (isHtmlDisplay(def.displayData))
381
+ df.html.value = display.value;
382
+ }
383
+ }, displayOverrides);
384
+
364
385
  setupValidation(
365
386
  controlImpl,
366
387
  definition,