@astroapps/forms-core 1.0.1 → 1.1.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/lib/evalExpression.d.ts +1 -0
- package/lib/formNode.d.ts +7 -0
- package/lib/formState.d.ts +4 -1
- package/lib/index.cjs +62 -12
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +60 -14
- package/lib/index.js.map +1 -1
- package/lib/validators.d.ts +2 -1
- package/package.json +1 -1
- package/src/evalExpression.ts +4 -2
- package/src/formNode.ts +45 -0
- package/src/formState.ts +34 -3
- package/src/validators.ts +5 -1
package/lib/validators.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface ValidationEvalContext {
|
|
|
13
13
|
data: SchemaDataNode;
|
|
14
14
|
schemaInterface: SchemaInterface;
|
|
15
15
|
formContext: Control<FormContextOptions>;
|
|
16
|
+
runAsync(af: () => void): void;
|
|
16
17
|
}
|
|
17
18
|
export type ValidatorEval<T extends SchemaValidator> = (validation: T, context: ValidationEvalContext) => void;
|
|
18
19
|
export declare const jsonataValidator: ValidatorEval<JsonataValidator>;
|
|
@@ -20,4 +21,4 @@ export declare const lengthValidator: ValidatorEval<LengthValidator>;
|
|
|
20
21
|
export declare const dateValidator: ValidatorEval<DateValidator>;
|
|
21
22
|
export declare const defaultValidators: Record<string, ValidatorEval<any>>;
|
|
22
23
|
export declare function createValidators(def: ControlDefinition, context: ValidationEvalContext): void;
|
|
23
|
-
export declare function setupValidation(controlImpl: Control<FormContextOptions>, definition: ControlDefinition, dataNode: Control<SchemaDataNode | undefined>, schemaInterface: SchemaInterface, parent: SchemaDataNode, formNode: FormNode): void;
|
|
24
|
+
export declare function setupValidation(controlImpl: Control<FormContextOptions>, definition: ControlDefinition, dataNode: Control<SchemaDataNode | undefined>, schemaInterface: SchemaInterface, parent: SchemaDataNode, formNode: FormNode, runAsync: (af: () => void) => void): void;
|
package/package.json
CHANGED
package/src/evalExpression.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface ExpressionEvalContext {
|
|
|
28
28
|
dataNode: SchemaDataNode;
|
|
29
29
|
schemaInterface: SchemaInterface;
|
|
30
30
|
variables?: Value<Record<string, any> | undefined>;
|
|
31
|
+
runAsync(effect: () => void): void;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export type ExpressionEval<T extends EntityExpression> = (
|
|
@@ -72,7 +73,7 @@ const notEmptyEval: ExpressionEval<NotEmptyExpression> = (
|
|
|
72
73
|
|
|
73
74
|
export const jsonataEval: ExpressionEval<JsonataExpression> = (
|
|
74
75
|
expr,
|
|
75
|
-
{ scope, returnResult, dataNode, variables },
|
|
76
|
+
{ scope, returnResult, dataNode, variables, runAsync },
|
|
76
77
|
) => {
|
|
77
78
|
const path = getJsonPath(dataNode);
|
|
78
79
|
const pathString = jsonPathString(path, (x) => `#$i[${x}]`);
|
|
@@ -102,7 +103,8 @@ export const jsonataEval: ExpressionEval<JsonataExpression> = (
|
|
|
102
103
|
collectChanges(effect.collectUsage, () => returnResult(evalResult));
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
createAsyncEffect(runJsonata, scope);
|
|
106
|
+
const asyncEffect = createAsyncEffect(runJsonata, scope);
|
|
107
|
+
runAsync(() => asyncEffect.start());
|
|
106
108
|
};
|
|
107
109
|
|
|
108
110
|
export const uuidEval: ExpressionEval<EntityExpression> = (_, ctx) => {
|
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";
|
|
@@ -58,6 +57,7 @@ export interface ControlState {
|
|
|
58
57
|
disabled: boolean;
|
|
59
58
|
clearHidden: boolean;
|
|
60
59
|
variables: Record<string, any>;
|
|
60
|
+
meta: Control<Record<string, any>>;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export interface FormContextOptions {
|
|
@@ -82,15 +82,30 @@ export interface FormState {
|
|
|
82
82
|
parent: SchemaDataNode,
|
|
83
83
|
formNode: FormNode,
|
|
84
84
|
context: FormContextOptions,
|
|
85
|
+
runAsync: (af: () => void) => void,
|
|
85
86
|
): ControlState;
|
|
86
87
|
|
|
87
88
|
cleanup(): void;
|
|
88
89
|
|
|
89
90
|
evalExpression(expr: EntityExpression, context: ExpressionEvalContext): void;
|
|
91
|
+
|
|
92
|
+
getExistingControlState(
|
|
93
|
+
parent: SchemaDataNode,
|
|
94
|
+
formNode: FormNode,
|
|
95
|
+
stateKey?: string,
|
|
96
|
+
): ControlState | undefined;
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
const formStates: FormState[] = [];
|
|
93
100
|
|
|
101
|
+
export function getControlStateId(
|
|
102
|
+
parent: SchemaDataNode,
|
|
103
|
+
formNode: FormNode,
|
|
104
|
+
stateKey?: string,
|
|
105
|
+
): string {
|
|
106
|
+
return parent.id + "$" + formNode.id + (stateKey ?? "");
|
|
107
|
+
}
|
|
108
|
+
|
|
94
109
|
export function createFormState(
|
|
95
110
|
schemaInterface: SchemaInterface,
|
|
96
111
|
evaluators: Record<string, ExpressionEval<any>> = defaultEvaluators,
|
|
@@ -112,12 +127,25 @@ export function createFormState(
|
|
|
112
127
|
// console.log("Cleanup form state");
|
|
113
128
|
controlStates.cleanup();
|
|
114
129
|
},
|
|
130
|
+
getExistingControlState(
|
|
131
|
+
parent: SchemaDataNode,
|
|
132
|
+
formNode: FormNode,
|
|
133
|
+
stateKey?: string,
|
|
134
|
+
): ControlState | undefined {
|
|
135
|
+
const stateId = getControlStateId(parent, formNode, stateKey);
|
|
136
|
+
const control = getCurrentFields(controlStates)[stateId];
|
|
137
|
+
if (control) {
|
|
138
|
+
return getMetaValue<Control<ControlState>>(control, "impl")?.value;
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
},
|
|
115
142
|
getControlState(
|
|
116
143
|
parent: SchemaDataNode,
|
|
117
144
|
formNode: FormNode,
|
|
118
145
|
context: FormContextOptions,
|
|
146
|
+
runAsync: (af: () => void) => void,
|
|
119
147
|
): ControlState {
|
|
120
|
-
const stateId = parent
|
|
148
|
+
const stateId = getControlStateId(parent, formNode, context.stateKey);
|
|
121
149
|
const controlImpl = controlStates.fields[stateId];
|
|
122
150
|
controlImpl.value = context;
|
|
123
151
|
function evalExpr<A>(
|
|
@@ -137,6 +165,7 @@ export function createFormState(
|
|
|
137
165
|
dataNode: parent,
|
|
138
166
|
variables: controlImpl.fields.variables,
|
|
139
167
|
schemaInterface,
|
|
168
|
+
runAsync,
|
|
140
169
|
});
|
|
141
170
|
return true;
|
|
142
171
|
}
|
|
@@ -278,6 +307,7 @@ export function createFormState(
|
|
|
278
307
|
hidden: false,
|
|
279
308
|
variables: controlImpl.fields.variables.current.value ?? {},
|
|
280
309
|
stateId,
|
|
310
|
+
meta: newControl({}),
|
|
281
311
|
});
|
|
282
312
|
|
|
283
313
|
const {
|
|
@@ -365,6 +395,7 @@ export function createFormState(
|
|
|
365
395
|
schemaInterface,
|
|
366
396
|
parent,
|
|
367
397
|
formNode,
|
|
398
|
+
runAsync,
|
|
368
399
|
);
|
|
369
400
|
|
|
370
401
|
createSyncEffect(() => {
|
package/src/validators.ts
CHANGED
|
@@ -32,6 +32,7 @@ export interface ValidationEvalContext {
|
|
|
32
32
|
data: SchemaDataNode;
|
|
33
33
|
schemaInterface: SchemaInterface;
|
|
34
34
|
formContext: Control<FormContextOptions>;
|
|
35
|
+
runAsync(af: () => void): void;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
export type ValidatorEval<T extends SchemaValidator> = (
|
|
@@ -51,11 +52,12 @@ export const jsonataValidator: ValidatorEval<JsonataValidator> = (
|
|
|
51
52
|
dataNode: context.parentData,
|
|
52
53
|
returnResult: (v) => {
|
|
53
54
|
trackControlChange(context.data.control, ControlChange.Validate);
|
|
54
|
-
console.log("Setting jsonata error", v);
|
|
55
|
+
// console.log("Setting jsonata error", v);
|
|
55
56
|
context.data.control.setError("jsonata", v?.toString());
|
|
56
57
|
},
|
|
57
58
|
schemaInterface: context.schemaInterface,
|
|
58
59
|
variables: context.formContext.fields.variables,
|
|
60
|
+
runAsync: context.runAsync,
|
|
59
61
|
},
|
|
60
62
|
);
|
|
61
63
|
};
|
|
@@ -169,6 +171,7 @@ export function setupValidation(
|
|
|
169
171
|
schemaInterface: SchemaInterface,
|
|
170
172
|
parent: SchemaDataNode,
|
|
171
173
|
formNode: FormNode,
|
|
174
|
+
runAsync: (af: () => void) => void,
|
|
172
175
|
) {
|
|
173
176
|
const validationEnabled = createScopedComputed(
|
|
174
177
|
controlImpl,
|
|
@@ -193,6 +196,7 @@ export function setupValidation(
|
|
|
193
196
|
validatorsScope.addCleanup(cleanup);
|
|
194
197
|
},
|
|
195
198
|
formContext: controlImpl,
|
|
199
|
+
runAsync,
|
|
196
200
|
});
|
|
197
201
|
|
|
198
202
|
createEffect(
|