@usefillo/core 0.19.0 → 0.21.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/dist/index.d.ts +13 -1
- package/dist/index.js +60 -8
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -589,7 +589,9 @@ declare function resolveNextPage(form: FormSchema, currentPageId: string, data:
|
|
|
589
589
|
* it reduces to today's linear behavior. {@link reachablePageIds} is the set of
|
|
590
590
|
* this exact walk (one walk, no divergence).
|
|
591
591
|
*/
|
|
592
|
-
declare function reachablePageSequence(form: FormSchema, data: ResponseData
|
|
592
|
+
declare function reachablePageSequence(form: FormSchema, data: ResponseData,
|
|
593
|
+
/** Optional starting page for inspecting a branch in a local form preview. */
|
|
594
|
+
startPageId?: string): string[];
|
|
593
595
|
/**
|
|
594
596
|
* The page ids reachable for the given data. The unordered set of
|
|
595
597
|
* {@link reachablePageSequence} — one shared walk keeps the ordered navigation
|
|
@@ -1566,6 +1568,8 @@ declare function respondentErrorStringsFor(strings: Pick<FilloStrings, "submitFa
|
|
|
1566
1568
|
* an exhaustively-enumerated, closed set.
|
|
1567
1569
|
*/
|
|
1568
1570
|
interface FilloFieldStrings {
|
|
1571
|
+
/** Browse the next page in a render-only form preview without answering. */
|
|
1572
|
+
previewSkip: string;
|
|
1569
1573
|
/** Optional, backward-compatible overrides for respondent error states that
|
|
1570
1574
|
* do not already have a top-level renderer string. */
|
|
1571
1575
|
respondentErrors?: Partial<RespondentErrorOverrides>;
|
|
@@ -1676,6 +1680,12 @@ interface FormControllerOptions {
|
|
|
1676
1680
|
* option to change visitor-facing behavior such as branding.
|
|
1677
1681
|
*/
|
|
1678
1682
|
skipValidation?: boolean;
|
|
1683
|
+
/**
|
|
1684
|
+
* Enable explicit page skipping in a transportless preview. Requires
|
|
1685
|
+
* skipValidation and no client, formId, or resolver. Native next() still
|
|
1686
|
+
* validates; skipPreviewPage() alone bypasses validation and page routing.
|
|
1687
|
+
*/
|
|
1688
|
+
previewNavigation?: boolean;
|
|
1679
1689
|
/**
|
|
1680
1690
|
* Embedding surface, recorded per response for measurement. "headless" = a
|
|
1681
1691
|
* bare engine with no Fillo-rendered layout (createFormController /
|
|
@@ -1799,6 +1809,8 @@ interface FormController {
|
|
|
1799
1809
|
setUploading(fieldId: string, busy: boolean): void;
|
|
1800
1810
|
/** Validate the current page, then advance. No-op on the last page or with errors. */
|
|
1801
1811
|
next(): void;
|
|
1812
|
+
/** Browse the next physical page in an explicitly enabled local preview. */
|
|
1813
|
+
skipPreviewPage(): void;
|
|
1802
1814
|
back(): void;
|
|
1803
1815
|
submit(): Promise<void>;
|
|
1804
1816
|
/**
|
package/dist/index.js
CHANGED
|
@@ -311,11 +311,11 @@ function resolveNextPage(form, currentPageId, data) {
|
|
|
311
311
|
}
|
|
312
312
|
return { linear: true };
|
|
313
313
|
}
|
|
314
|
-
function reachablePageSequence(form, data) {
|
|
314
|
+
function reachablePageSequence(form, data, startPageId) {
|
|
315
315
|
const seq = [];
|
|
316
316
|
if (form.pages.length === 0) return seq;
|
|
317
317
|
const seen = /* @__PURE__ */ new Set();
|
|
318
|
-
let index = 0;
|
|
318
|
+
let index = startPageId === void 0 ? 0 : form.pages.findIndex((p) => p.id === startPageId);
|
|
319
319
|
for (let steps = 0; steps <= form.pages.length; steps++) {
|
|
320
320
|
const page = form.pages[index];
|
|
321
321
|
if (!page || seen.has(page.id)) break;
|
|
@@ -793,6 +793,7 @@ function defaultRequiredForField(field2) {
|
|
|
793
793
|
return REQUIRED_BY_KIND[field2.kind] ?? REQUIRED_FIELD_MESSAGE;
|
|
794
794
|
}
|
|
795
795
|
var DEFAULT_FIELD_STRINGS = {
|
|
796
|
+
previewSkip: "Skip",
|
|
796
797
|
required: REQUIRED_FIELD_MESSAGE,
|
|
797
798
|
requiredForField: defaultRequiredForField,
|
|
798
799
|
resumeLinkExpired: "That saved-progress link expired or was already used \u2014 start again below.",
|
|
@@ -1112,7 +1113,7 @@ var schemaShape = z2.object({
|
|
|
1112
1113
|
});
|
|
1113
1114
|
var MAX_SCHEMA_VERSION = 1;
|
|
1114
1115
|
var FILLO_SCHEMA_VERSION = 1;
|
|
1115
|
-
var FILLO_SDK_VERSION = true ? "0.
|
|
1116
|
+
var FILLO_SDK_VERSION = true ? "0.21.0" : "0.0.0-dev";
|
|
1116
1117
|
var FILLO_MIN_SDK_VERSION = "0.4.0";
|
|
1117
1118
|
var FILLO_CHALLENGE_MIN_SDK_VERSION = "0.9.0";
|
|
1118
1119
|
var FILLO_CALC_MIN_SDK_VERSION = "0.11.0";
|
|
@@ -3431,6 +3432,23 @@ function createFormController(options2) {
|
|
|
3431
3432
|
let data = computeCalculated(form, { ...options2.initialData ?? {} });
|
|
3432
3433
|
let errors = {};
|
|
3433
3434
|
let pageIndex = 0;
|
|
3435
|
+
let previewStartPageId;
|
|
3436
|
+
const previewHistory = [];
|
|
3437
|
+
function previewNavigationEnabled() {
|
|
3438
|
+
return options2.previewNavigation === true && options2.skipValidation === true && !client && !formId && !options2.resolveFormId;
|
|
3439
|
+
}
|
|
3440
|
+
function navigationSequence() {
|
|
3441
|
+
return reachablePageSequence(
|
|
3442
|
+
form,
|
|
3443
|
+
data,
|
|
3444
|
+
previewNavigationEnabled() ? previewStartPageId : void 0
|
|
3445
|
+
);
|
|
3446
|
+
}
|
|
3447
|
+
function rememberPreviewPage() {
|
|
3448
|
+
if (previewNavigationEnabled()) {
|
|
3449
|
+
previewHistory.push({ pageIndex, startPageId: previewStartPageId });
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3434
3452
|
let status = "idle";
|
|
3435
3453
|
let restoredSubmission = false;
|
|
3436
3454
|
let resumeLinkFailed = false;
|
|
@@ -3516,7 +3534,7 @@ function createFormController(options2) {
|
|
|
3516
3534
|
// Terminal-aware: true when the current page is the last reachable page OR
|
|
3517
3535
|
// a matched jump rule ends the form here — so the footer reads Submit and
|
|
3518
3536
|
// its handler submits. Same shared engine the validator reaches with.
|
|
3519
|
-
isLastPage: isTerminalPage(form, page.id, data),
|
|
3537
|
+
isLastPage: previewNavigationEnabled() && previewStartPageId !== void 0 ? navigationSequence().at(-1) === page.id : isTerminalPage(form, page.id, data),
|
|
3520
3538
|
uploading: uploadingFields.size > 0,
|
|
3521
3539
|
submitError,
|
|
3522
3540
|
restoredSubmission,
|
|
@@ -3545,6 +3563,7 @@ function createFormController(options2) {
|
|
|
3545
3563
|
const pageErrors = {};
|
|
3546
3564
|
for (const block of visiblePageBlocks(form, target, data)) {
|
|
3547
3565
|
if (!isField(block)) continue;
|
|
3566
|
+
if (previewNavigationEnabled() && block.kind === "file_upload") continue;
|
|
3548
3567
|
const error = validateField(block, data[block.id]);
|
|
3549
3568
|
if (error) pageErrors[block.id] = error;
|
|
3550
3569
|
}
|
|
@@ -3748,7 +3767,7 @@ function createFormController(options2) {
|
|
|
3748
3767
|
function next() {
|
|
3749
3768
|
const pageCount = form.pages.length;
|
|
3750
3769
|
const clamped = Math.min(pageIndex, Math.max(pageCount - 1, 0));
|
|
3751
|
-
if (!options2.skipValidation) {
|
|
3770
|
+
if (!options2.skipValidation || options2.previewNavigation === true) {
|
|
3752
3771
|
const pageErrors = validatePage(clamped);
|
|
3753
3772
|
errors = pageErrors;
|
|
3754
3773
|
if (Object.keys(pageErrors).length > 0) {
|
|
@@ -3757,14 +3776,15 @@ function createFormController(options2) {
|
|
|
3757
3776
|
}
|
|
3758
3777
|
}
|
|
3759
3778
|
const current = form.pages[clamped];
|
|
3760
|
-
const seq =
|
|
3779
|
+
const seq = navigationSequence();
|
|
3761
3780
|
const pos = currentSeqPosition(seq);
|
|
3762
|
-
const terminal = (current ? isTerminalPage(form, current.id, data) : true) || pos < 0 || pos + 1 >= seq.length;
|
|
3781
|
+
const terminal = (previewNavigationEnabled() && previewStartPageId !== void 0 ? seq.at(-1) === current?.id : current ? isTerminalPage(form, current.id, data) : true) || pos < 0 || pos + 1 >= seq.length;
|
|
3763
3782
|
if (terminal) {
|
|
3764
3783
|
void submit();
|
|
3765
3784
|
return;
|
|
3766
3785
|
}
|
|
3767
3786
|
const nextIndex = form.pages.findIndex((p) => p.id === seq[pos + 1]);
|
|
3787
|
+
rememberPreviewPage();
|
|
3768
3788
|
pageIndex = nextIndex >= 0 ? nextIndex : Math.min(clamped + 1, pageCount - 1);
|
|
3769
3789
|
if (sessionId && client) client.reportProgress(sessionId, { furthestPage: pageIndex });
|
|
3770
3790
|
notify();
|
|
@@ -3772,6 +3792,14 @@ function createFormController(options2) {
|
|
|
3772
3792
|
}
|
|
3773
3793
|
function back() {
|
|
3774
3794
|
errors = {};
|
|
3795
|
+
const previous = previewNavigationEnabled() ? previewHistory.pop() : void 0;
|
|
3796
|
+
if (previous) {
|
|
3797
|
+
pageIndex = Math.min(previous.pageIndex, form.pages.length - 1);
|
|
3798
|
+
previewStartPageId = previous.startPageId;
|
|
3799
|
+
submitError = void 0;
|
|
3800
|
+
notify();
|
|
3801
|
+
return;
|
|
3802
|
+
}
|
|
3775
3803
|
const seq = reachablePageSequence(form, data);
|
|
3776
3804
|
const pos = currentSeqPosition(seq);
|
|
3777
3805
|
if (pos > 0) {
|
|
@@ -3784,8 +3812,25 @@ function createFormController(options2) {
|
|
|
3784
3812
|
notify();
|
|
3785
3813
|
checkpointDraft();
|
|
3786
3814
|
}
|
|
3815
|
+
function skipPreviewPage() {
|
|
3816
|
+
if (!previewNavigationEnabled() || status === "submitting" || status === "submitted" || pageIndex >= form.pages.length - 1)
|
|
3817
|
+
return;
|
|
3818
|
+
rememberPreviewPage();
|
|
3819
|
+
pageIndex += 1;
|
|
3820
|
+
previewStartPageId = form.pages[pageIndex]?.id;
|
|
3821
|
+
errors = {};
|
|
3822
|
+
submitError = void 0;
|
|
3823
|
+
notify();
|
|
3824
|
+
}
|
|
3787
3825
|
async function submit() {
|
|
3788
3826
|
if (status === "submitting" || status === "submitted") return;
|
|
3827
|
+
if (previewNavigationEnabled()) {
|
|
3828
|
+
errors = validatePage(pageIndex);
|
|
3829
|
+
if (Object.keys(errors).length > 0) {
|
|
3830
|
+
notify();
|
|
3831
|
+
return;
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3789
3834
|
const result = validateResponse(form, data);
|
|
3790
3835
|
if (!result.ok) {
|
|
3791
3836
|
const transportlessPreview = options2.skipValidation && !(client && formId);
|
|
@@ -3809,7 +3854,11 @@ function createFormController(options2) {
|
|
|
3809
3854
|
const firstBad = form.pages.findIndex(
|
|
3810
3855
|
(p) => visiblePageBlocks(form, p, data).some((b) => b.id in previewErrors)
|
|
3811
3856
|
);
|
|
3812
|
-
if (firstBad >= 0)
|
|
3857
|
+
if (firstBad >= 0) {
|
|
3858
|
+
pageIndex = firstBad;
|
|
3859
|
+
previewStartPageId = void 0;
|
|
3860
|
+
previewHistory.length = 0;
|
|
3861
|
+
}
|
|
3813
3862
|
notify();
|
|
3814
3863
|
return;
|
|
3815
3864
|
}
|
|
@@ -3911,6 +3960,7 @@ function createFormController(options2) {
|
|
|
3911
3960
|
setValue,
|
|
3912
3961
|
setUploading,
|
|
3913
3962
|
next,
|
|
3963
|
+
skipPreviewPage,
|
|
3914
3964
|
back,
|
|
3915
3965
|
submit,
|
|
3916
3966
|
setContext(ctx) {
|
|
@@ -3955,6 +4005,8 @@ function createFormController(options2) {
|
|
|
3955
4005
|
data = computeCalculated(form, data);
|
|
3956
4006
|
errors = {};
|
|
3957
4007
|
pageIndex = 0;
|
|
4008
|
+
previewStartPageId = void 0;
|
|
4009
|
+
previewHistory.length = 0;
|
|
3958
4010
|
submitError = void 0;
|
|
3959
4011
|
resumedDraft = false;
|
|
3960
4012
|
editingPrevious = false;
|