@formwright/core 0.2.0 → 0.2.2
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/dist/chunk-OWEG6VGP.js +3 -0
- package/dist/{chunk-O4DUMDBU.js.map → chunk-OWEG6VGP.js.map} +1 -1
- package/dist/index.cjs +163 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -11
- package/dist/index.d.ts +57 -11
- package/dist/index.js +163 -20
- package/dist/index.js.map +1 -1
- package/dist/reactive.cjs +1 -1
- package/dist/reactive.d.cts +1 -1
- package/dist/reactive.d.ts +1 -1
- package/dist/reactive.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-O4DUMDBU.js +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-OWEG6VGP.js","sourcesContent":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var reactive = require('@
|
|
3
|
+
var reactive = require('@formwright/reactive');
|
|
4
4
|
var schema = require('@formwright/schema');
|
|
5
5
|
|
|
6
6
|
// src/reactive.ts
|
|
@@ -187,9 +187,11 @@ var FieldState = class {
|
|
|
187
187
|
revision;
|
|
188
188
|
validator;
|
|
189
189
|
rev = reactive.signal(0);
|
|
190
|
-
|
|
190
|
+
stepActive;
|
|
191
|
+
constructor(schema, initial, getValue, stepActive) {
|
|
191
192
|
this.id = schema.id;
|
|
192
193
|
this.schema = schema;
|
|
194
|
+
this.stepActive = stepActive;
|
|
193
195
|
this.value = reactive.signal(initial);
|
|
194
196
|
this.error = reactive.signal(null);
|
|
195
197
|
this.touched = reactive.signal(false);
|
|
@@ -217,12 +219,16 @@ var FieldState = class {
|
|
|
217
219
|
this.validator = this.schema.validation ? compileValidator(this.schema.validation) : null;
|
|
218
220
|
this.rev.update((n) => n + 1);
|
|
219
221
|
}
|
|
220
|
-
/** Run validation, store and return the error (or null). Hidden fields never error. */
|
|
221
|
-
validate() {
|
|
222
|
+
/** Run validation, store and return the error (or null). Hidden / inactive-step fields never error. */
|
|
223
|
+
validate(options) {
|
|
222
224
|
if (!this.visible.peek()) {
|
|
223
225
|
this.error.set(null);
|
|
224
226
|
return null;
|
|
225
227
|
}
|
|
228
|
+
if (!options?.allSteps && this.stepActive && !this.stepActive.peek()) {
|
|
229
|
+
this.error.set(null);
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
226
232
|
let result = null;
|
|
227
233
|
if (this.required.peek() && isEmpty2(this.value.peek())) {
|
|
228
234
|
result = requiredMessage(this.schema.validation);
|
|
@@ -259,18 +265,24 @@ function collectValues(nodes) {
|
|
|
259
265
|
}
|
|
260
266
|
return out;
|
|
261
267
|
}
|
|
262
|
-
function buildNodes(schemas, scope, initial) {
|
|
268
|
+
function buildNodes(schemas, scope, initial, stepActive) {
|
|
263
269
|
const nodes = [];
|
|
264
270
|
const byName = /* @__PURE__ */ new Map();
|
|
265
271
|
for (const schema of schemas) {
|
|
266
272
|
let node;
|
|
267
273
|
if (schema.type === "group") {
|
|
268
|
-
node = new GroupNode(schema, scope, asDict(initial[schema.id]));
|
|
274
|
+
node = new GroupNode(schema, scope, asDict(initial[schema.id]), stepActive);
|
|
275
|
+
} else if (schema.type === "step") {
|
|
276
|
+
if (!stepActive)
|
|
277
|
+
throw new Error('Field type "step" must be nested inside a "steps" container');
|
|
278
|
+
node = new StepNode(schema, scope, asDict(initial[schema.id]), stepActive);
|
|
269
279
|
} else if (schema.type === "collection") {
|
|
270
280
|
node = new CollectionNode(schema, scope, asArray(initial[schema.id]));
|
|
281
|
+
} else if (schema.type === "steps") {
|
|
282
|
+
node = new StepsNode(schema, scope, asDict(initial[schema.id]));
|
|
271
283
|
} else {
|
|
272
284
|
const init = initial[schema.id] ?? schema.defaultValue ?? defaultValueFor(schema.type);
|
|
273
|
-
node = new FieldState(schema, init, scope);
|
|
285
|
+
node = new FieldState(schema, init, scope, stepActive);
|
|
274
286
|
}
|
|
275
287
|
nodes.push(node);
|
|
276
288
|
byName.set(schema.id, node);
|
|
@@ -288,7 +300,9 @@ function resetNodes(nodes, initial) {
|
|
|
288
300
|
if (node.kind === "field") {
|
|
289
301
|
const init = initial[node.id] ?? node.schema.defaultValue ?? defaultValueFor(node.schema.type);
|
|
290
302
|
node.reset(init);
|
|
291
|
-
} else if (node.kind === "group") {
|
|
303
|
+
} else if (node.kind === "group" || node.kind === "step") {
|
|
304
|
+
node.reset(asDict(initial[node.id]));
|
|
305
|
+
} else if (node.kind === "steps") {
|
|
292
306
|
node.reset(asDict(initial[node.id]));
|
|
293
307
|
} else {
|
|
294
308
|
node.reset(asArray(initial[node.id]));
|
|
@@ -306,14 +320,14 @@ var GroupNode = class {
|
|
|
306
320
|
enabled;
|
|
307
321
|
/** The scope a child uses: resolve a name among siblings, else delegate upward. */
|
|
308
322
|
scope;
|
|
309
|
-
constructor(schema, parentScope, initial) {
|
|
323
|
+
constructor(schema, parentScope, initial, stepActive) {
|
|
310
324
|
this.id = schema.id;
|
|
311
325
|
this.schema = schema;
|
|
312
326
|
this.scope = (name) => {
|
|
313
327
|
const child = this.byName.get(name);
|
|
314
328
|
return child ? nodeValue(child) : parentScope(name);
|
|
315
329
|
};
|
|
316
|
-
const built = buildNodes(schema.fields ?? [], this.scope, initial);
|
|
330
|
+
const built = buildNodes(schema.fields ?? [], this.scope, initial, stepActive);
|
|
317
331
|
this.children = built.nodes;
|
|
318
332
|
this.byName = built.byName;
|
|
319
333
|
this.value = reactive.computed(() => collectValues(this.children));
|
|
@@ -376,6 +390,109 @@ var CollectionNode = class {
|
|
|
376
390
|
this.rows.set(this.seedRows(initial));
|
|
377
391
|
}
|
|
378
392
|
};
|
|
393
|
+
var StepNode = class {
|
|
394
|
+
kind = "step";
|
|
395
|
+
id;
|
|
396
|
+
schema;
|
|
397
|
+
children;
|
|
398
|
+
byName;
|
|
399
|
+
value;
|
|
400
|
+
visible;
|
|
401
|
+
enabled;
|
|
402
|
+
scope;
|
|
403
|
+
/** True when this step is the active step in its parent wizard. */
|
|
404
|
+
active;
|
|
405
|
+
constructor(schema, parentScope, initial, active) {
|
|
406
|
+
this.id = schema.id;
|
|
407
|
+
this.schema = schema;
|
|
408
|
+
this.active = active;
|
|
409
|
+
this.scope = (name) => {
|
|
410
|
+
const child = this.byName.get(name);
|
|
411
|
+
return child ? nodeValue(child) : parentScope(name);
|
|
412
|
+
};
|
|
413
|
+
const built = buildNodes(schema.fields ?? [], this.scope, initial, active);
|
|
414
|
+
this.children = built.nodes;
|
|
415
|
+
this.byName = built.byName;
|
|
416
|
+
this.value = reactive.computed(() => collectValues(this.children));
|
|
417
|
+
this.visible = reactive.computed(() => evaluateCondition(schema.visibleWhen, parentScope, true));
|
|
418
|
+
this.enabled = reactive.computed(() => evaluateCondition(schema.enabledWhen, parentScope, true));
|
|
419
|
+
}
|
|
420
|
+
reset(initial) {
|
|
421
|
+
resetNodes(this.children, initial);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
var StepsNode = class {
|
|
425
|
+
kind = "steps";
|
|
426
|
+
id;
|
|
427
|
+
schema;
|
|
428
|
+
steps;
|
|
429
|
+
byName;
|
|
430
|
+
value;
|
|
431
|
+
visible;
|
|
432
|
+
enabled;
|
|
433
|
+
currentStep;
|
|
434
|
+
scope;
|
|
435
|
+
constructor(schema, parentScope, initial) {
|
|
436
|
+
this.id = schema.id;
|
|
437
|
+
this.schema = schema;
|
|
438
|
+
this.currentStep = reactive.signal(0);
|
|
439
|
+
this.byName = /* @__PURE__ */ new Map();
|
|
440
|
+
this.scope = (name) => {
|
|
441
|
+
const step = this.byName.get(name);
|
|
442
|
+
return step ? step.value.get() : parentScope(name);
|
|
443
|
+
};
|
|
444
|
+
const stepSchemas = schema.fields ?? [];
|
|
445
|
+
const steps = stepSchemas.map((stepSchema, index) => {
|
|
446
|
+
const active = reactive.computed(() => this.currentStep.get() === index);
|
|
447
|
+
const stepInitial = asDict(initial[stepSchema.id]);
|
|
448
|
+
const step = new StepNode(stepSchema, this.scope, stepInitial, active);
|
|
449
|
+
this.byName.set(stepSchema.id, step);
|
|
450
|
+
return step;
|
|
451
|
+
});
|
|
452
|
+
this.steps = steps;
|
|
453
|
+
this.value = reactive.computed(() => {
|
|
454
|
+
const out = {};
|
|
455
|
+
for (const step of this.steps) out[step.id] = step.value.get();
|
|
456
|
+
return out;
|
|
457
|
+
});
|
|
458
|
+
this.visible = reactive.computed(() => evaluateCondition(schema.visibleWhen, parentScope, true));
|
|
459
|
+
this.enabled = reactive.computed(() => evaluateCondition(schema.enabledWhen, parentScope, true));
|
|
460
|
+
}
|
|
461
|
+
/** Validate every leaf in the step at `index` (defaults to the current step). */
|
|
462
|
+
validateStep(index) {
|
|
463
|
+
const i = index ?? this.currentStep.peek();
|
|
464
|
+
const step = this.steps[i];
|
|
465
|
+
if (!step) return true;
|
|
466
|
+
let ok = true;
|
|
467
|
+
eachLeaf([step], (leaf) => {
|
|
468
|
+
if (leaf.validate() !== null) ok = false;
|
|
469
|
+
});
|
|
470
|
+
return ok;
|
|
471
|
+
}
|
|
472
|
+
/** Advance to the next step after optionally validating the current one. Returns false if blocked. */
|
|
473
|
+
next() {
|
|
474
|
+
const validate = this.schema.validateOnNext !== false;
|
|
475
|
+
if (validate && !this.validateStep()) return false;
|
|
476
|
+
const cur = this.currentStep.peek();
|
|
477
|
+
if (cur < this.steps.length - 1) {
|
|
478
|
+
this.currentStep.set(cur + 1);
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
/** Go back one step (no validation). */
|
|
484
|
+
prev() {
|
|
485
|
+
this.currentStep.update((i) => Math.max(0, i - 1));
|
|
486
|
+
}
|
|
487
|
+
/** Jump to a step by index (does not validate). */
|
|
488
|
+
goTo(index) {
|
|
489
|
+
if (index >= 0 && index < this.steps.length) this.currentStep.set(index);
|
|
490
|
+
}
|
|
491
|
+
reset(initial) {
|
|
492
|
+
this.currentStep.set(0);
|
|
493
|
+
for (const step of this.steps) step.reset(asDict(initial[step.id]));
|
|
494
|
+
}
|
|
495
|
+
};
|
|
379
496
|
function buildTree(schemas, initial) {
|
|
380
497
|
let byName;
|
|
381
498
|
const scope = (name) => {
|
|
@@ -389,8 +506,10 @@ function buildTree(schemas, initial) {
|
|
|
389
506
|
function eachLeaf(nodes, visit) {
|
|
390
507
|
for (const node of nodes) {
|
|
391
508
|
if (node.kind === "field") visit(node);
|
|
392
|
-
else if (node.kind === "group") eachLeaf(node.children, visit);
|
|
393
|
-
else
|
|
509
|
+
else if (node.kind === "group" || node.kind === "step") eachLeaf(node.children, visit);
|
|
510
|
+
else if (node.kind === "steps") {
|
|
511
|
+
for (const step of node.steps) eachLeaf(step.children, visit);
|
|
512
|
+
} else for (const row of node.items.peek()) eachLeaf(row.group.children, visit);
|
|
394
513
|
}
|
|
395
514
|
}
|
|
396
515
|
var defaultRenderer = null;
|
|
@@ -493,17 +612,22 @@ var Form = class {
|
|
|
493
612
|
}
|
|
494
613
|
// ---- lifecycle ----------------------------------------------------------
|
|
495
614
|
/** Validate every (visible) leaf field; returns true when the whole form is valid. */
|
|
496
|
-
validate() {
|
|
615
|
+
validate(options) {
|
|
616
|
+
const allSteps = options?.allSteps ?? false;
|
|
497
617
|
return reactive.untrack(() => {
|
|
498
618
|
let ok = true;
|
|
499
619
|
reactive.batch(() => {
|
|
500
620
|
eachLeaf(this.tree, (leaf) => {
|
|
501
|
-
if (leaf.validate() !== null) ok = false;
|
|
621
|
+
if (leaf.validate({ allSteps }) !== null) ok = false;
|
|
502
622
|
});
|
|
503
623
|
});
|
|
504
624
|
return ok;
|
|
505
625
|
});
|
|
506
626
|
}
|
|
627
|
+
/** Find the first `steps` container in the field tree (if any). */
|
|
628
|
+
findSteps() {
|
|
629
|
+
return findSteps(this.tree);
|
|
630
|
+
}
|
|
507
631
|
/**
|
|
508
632
|
* Run the submission pipeline: validate → transform → send → onSuccess/onError.
|
|
509
633
|
* Pass an inline `transform` to shape the final payload, e.g.
|
|
@@ -514,7 +638,7 @@ var Form = class {
|
|
|
514
638
|
* `const res = await form.submit(); res.ok ? res.data : res.error`.
|
|
515
639
|
*/
|
|
516
640
|
async submit(transform) {
|
|
517
|
-
if (!this.validate()) {
|
|
641
|
+
if (!this.validate({ allSteps: true })) {
|
|
518
642
|
const errors = this.collectErrors();
|
|
519
643
|
const error = new FormValidationError(errors);
|
|
520
644
|
this.runErrorHandler(error);
|
|
@@ -694,8 +818,10 @@ function collectLeaves(tree) {
|
|
|
694
818
|
for (const node of nodes) {
|
|
695
819
|
const path = prefix ? `${prefix}.${node.id}` : node.id;
|
|
696
820
|
if (node.kind === "field") out.set(path, node);
|
|
697
|
-
else if (node.kind === "group") walk(node.children, path);
|
|
698
|
-
else {
|
|
821
|
+
else if (node.kind === "group" || node.kind === "step") walk(node.children, path);
|
|
822
|
+
else if (node.kind === "steps") {
|
|
823
|
+
for (const step of node.steps) walk(step.children, `${path}.${step.id}`);
|
|
824
|
+
} else {
|
|
699
825
|
node.items.peek().forEach((row, i) => walk(row.group.children, `${path}.${i}`));
|
|
700
826
|
}
|
|
701
827
|
}
|
|
@@ -708,7 +834,9 @@ function resolveLeaf(tree, rootByName, path) {
|
|
|
708
834
|
let node = rootByName.get(parts[0]);
|
|
709
835
|
for (let i = 1; i < parts.length && node; i++) {
|
|
710
836
|
const part = parts[i];
|
|
711
|
-
if (node instanceof GroupNode) {
|
|
837
|
+
if (node instanceof GroupNode || node instanceof StepNode) {
|
|
838
|
+
node = node.byName.get(part);
|
|
839
|
+
} else if (node instanceof StepsNode) {
|
|
712
840
|
node = node.byName.get(part);
|
|
713
841
|
} else if (node instanceof CollectionNode) {
|
|
714
842
|
node = node.items.peek()[Number(part)]?.group;
|
|
@@ -718,6 +846,21 @@ function resolveLeaf(tree, rootByName, path) {
|
|
|
718
846
|
}
|
|
719
847
|
return node && node.kind === "field" ? node : void 0;
|
|
720
848
|
}
|
|
849
|
+
function findSteps(tree) {
|
|
850
|
+
for (const node of tree) {
|
|
851
|
+
if (node.kind === "steps") return node;
|
|
852
|
+
if (node.kind === "group" || node.kind === "step") {
|
|
853
|
+
const found = findSteps(node.children);
|
|
854
|
+
if (found) return found;
|
|
855
|
+
} else if (node.kind === "collection") {
|
|
856
|
+
for (const row of node.items.peek()) {
|
|
857
|
+
const found = findSteps(row.group.children);
|
|
858
|
+
if (found) return found;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
return void 0;
|
|
863
|
+
}
|
|
721
864
|
|
|
722
865
|
Object.defineProperty(exports, "batch", {
|
|
723
866
|
enumerable: true,
|
|
@@ -748,6 +891,8 @@ exports.FieldState = FieldState;
|
|
|
748
891
|
exports.Form = Form;
|
|
749
892
|
exports.FormValidationError = FormValidationError;
|
|
750
893
|
exports.GroupNode = GroupNode;
|
|
894
|
+
exports.StepNode = StepNode;
|
|
895
|
+
exports.StepsNode = StepsNode;
|
|
751
896
|
exports.buildTree = buildTree;
|
|
752
897
|
exports.compileValidator = compileValidator;
|
|
753
898
|
exports.defaultValueFor = defaultValueFor;
|