@usefillo/core 0.20.0 → 0.22.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 +21 -3
- package/dist/index.js +100 -9
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -131,9 +131,11 @@ interface HiddenField extends BaseField {
|
|
|
131
131
|
paramName?: string;
|
|
132
132
|
defaultValue?: string;
|
|
133
133
|
}
|
|
134
|
+
/** Maximum number of completed files in one upload-field answer. */
|
|
135
|
+
declare const MAX_FILES_PER_FIELD = 200;
|
|
134
136
|
interface FileUploadField extends BaseField {
|
|
135
137
|
kind: "file_upload";
|
|
136
|
-
/** Max files,
|
|
138
|
+
/** Max files, from 1 to 200. Default 1. */
|
|
137
139
|
maxFiles?: number;
|
|
138
140
|
/** Per-file size cap in MB. Default 500. */
|
|
139
141
|
maxFileSizeMb?: number;
|
|
@@ -589,7 +591,9 @@ declare function resolveNextPage(form: FormSchema, currentPageId: string, data:
|
|
|
589
591
|
* it reduces to today's linear behavior. {@link reachablePageIds} is the set of
|
|
590
592
|
* this exact walk (one walk, no divergence).
|
|
591
593
|
*/
|
|
592
|
-
declare function reachablePageSequence(form: FormSchema, data: ResponseData
|
|
594
|
+
declare function reachablePageSequence(form: FormSchema, data: ResponseData,
|
|
595
|
+
/** Optional starting page for inspecting a branch in a local form preview. */
|
|
596
|
+
startPageId?: string): string[];
|
|
593
597
|
/**
|
|
594
598
|
* The page ids reachable for the given data. The unordered set of
|
|
595
599
|
* {@link reachablePageSequence} — one shared walk keeps the ordered navigation
|
|
@@ -1322,6 +1326,8 @@ declare class FilloClient {
|
|
|
1322
1326
|
/** Server origin this client targets, normalized (no trailing slash). */
|
|
1323
1327
|
readonly baseUrl: string;
|
|
1324
1328
|
private fetch;
|
|
1329
|
+
private activeUploads;
|
|
1330
|
+
private uploadQueue;
|
|
1325
1331
|
/** Publishable project key, when configured. */
|
|
1326
1332
|
readonly key?: string;
|
|
1327
1333
|
constructor(options?: FilloClientOptions);
|
|
@@ -1405,6 +1411,8 @@ declare class FilloClient {
|
|
|
1405
1411
|
* form owner's Drive and never touch the Fillo server.
|
|
1406
1412
|
*/
|
|
1407
1413
|
uploadFile(formId: string, file: File | Blob, options: UploadFileOptions): Promise<FileValue>;
|
|
1414
|
+
private acquireUploadSlot;
|
|
1415
|
+
private performUpload;
|
|
1408
1416
|
/**
|
|
1409
1417
|
* Box direct upload with a folder-scoped token (Box UI Elements pattern).
|
|
1410
1418
|
* Small files go up in one multipart POST; large files run Box's chunked
|
|
@@ -1566,6 +1574,8 @@ declare function respondentErrorStringsFor(strings: Pick<FilloStrings, "submitFa
|
|
|
1566
1574
|
* an exhaustively-enumerated, closed set.
|
|
1567
1575
|
*/
|
|
1568
1576
|
interface FilloFieldStrings {
|
|
1577
|
+
/** Browse the next page in a render-only form preview without answering. */
|
|
1578
|
+
previewSkip: string;
|
|
1569
1579
|
/** Optional, backward-compatible overrides for respondent error states that
|
|
1570
1580
|
* do not already have a top-level renderer string. */
|
|
1571
1581
|
respondentErrors?: Partial<RespondentErrorOverrides>;
|
|
@@ -1676,6 +1686,12 @@ interface FormControllerOptions {
|
|
|
1676
1686
|
* option to change visitor-facing behavior such as branding.
|
|
1677
1687
|
*/
|
|
1678
1688
|
skipValidation?: boolean;
|
|
1689
|
+
/**
|
|
1690
|
+
* Enable explicit page skipping in a transportless preview. Requires
|
|
1691
|
+
* skipValidation and no client, formId, or resolver. Native next() still
|
|
1692
|
+
* validates; skipPreviewPage() alone bypasses validation and page routing.
|
|
1693
|
+
*/
|
|
1694
|
+
previewNavigation?: boolean;
|
|
1679
1695
|
/**
|
|
1680
1696
|
* Embedding surface, recorded per response for measurement. "headless" = a
|
|
1681
1697
|
* bare engine with no Fillo-rendered layout (createFormController /
|
|
@@ -1799,6 +1815,8 @@ interface FormController {
|
|
|
1799
1815
|
setUploading(fieldId: string, busy: boolean): void;
|
|
1800
1816
|
/** Validate the current page, then advance. No-op on the last page or with errors. */
|
|
1801
1817
|
next(): void;
|
|
1818
|
+
/** Browse the next physical page in an explicitly enabled local preview. */
|
|
1819
|
+
skipPreviewPage(): void;
|
|
1802
1820
|
back(): void;
|
|
1803
1821
|
submit(): Promise<void>;
|
|
1804
1822
|
/**
|
|
@@ -2234,4 +2252,4 @@ declare class Sha1 {
|
|
|
2234
2252
|
}
|
|
2235
2253
|
declare const sha1Base64: (bytes: Uint8Array) => string;
|
|
2236
2254
|
|
|
2237
|
-
export { type AutoSubmitContext, BLOCK_KIND_META, type BaseField, type Block, type BlockKind, CONTENT_KINDS, type CalcExpr, type CalculatedField, type ChallengeConfig, type ChallengeTheme, type CheckboxField, type ChoiceField, type CodeForm, type Condition, type ConditionOp, type ContentBlock, type ContentKind, type CreatedDraft, type CustomField, DEFAULT_FIELD_STRINGS, DEFAULT_RESPONDENT_ERROR_STRINGS, DEFAULT_STRINGS, DRAFT_KINDS, type DateField, type DividerBlock, FILLO_CALC_MIN_SDK_VERSION, FILLO_CHALLENGE_MIN_SDK_VERSION, FILLO_DATA_ATTRS, FILLO_GROUP_MIN_SDK_VERSION, FILLO_MIN_SDK_VERSION, FILLO_SCHEMA_VERSION, FILLO_SDK_VERSION, FILLO_SLOTS, FILLO_THEME_VARS, type Field, type FieldKind, type FieldSpec, type FieldValue, type FileUploadField, type FileValue, type FilloAppearance, FilloClient, type FilloClientOptions, FilloError, type FilloFieldStrings, FilloJsxError, type FilloRendererStrings, type FilloRespondent, type FilloSlot, type FilloStrings, type FormBranding, type FormController, type FormControllerOptions, type FormControllerState, type FormDraftSpec, type FormPage, type FormSchema, type FormSettings, type FormStatus, type FormTheme, type GroupInstanceValue, type HeadingBlock, type HiddenField, JSX_BLOCK_COMPONENTS, JSX_BLOCK_SPECS, type JsonValue, type JsxFormMeta, type JumpRule, type LinearScaleField, type MatrixField, type NextPage, type NumberField, PHONE_COUNTRIES, PHONE_PICKER_COUNTRIES, PHONE_POPOVER_VIEWPORT_GAP, type ParagraphBlock, type ParsePhoneOptions, type ParsedPhone, type PhoneCountry, type PhoneField, type PhonePopoverPlacement, type ProvisionWorkspaceResult, type PublishedForm, REQUIRED_FIELD_MESSAGE, type RankingField, type RatingField, type RepeatingGroupField, type RespondentErrorOverrides, type RespondentErrorStrings, type ResponseData, type ResponseDraft, type ResponseLimit, type SchemaValidationResult, type SelectOption, Sha1, type SignatureField, type SlotClass, type SlotState, type SubmitMeta, type SubmitResult, type SyncFormResult, type SyncedForm, type TextField, type TrustPolicy, type UploadFileOptions, type UploadProgress, type UploadSession, type UploadStatus, type UploadTransport, type ValidationResult, type WhenBuilder, allFields, assembleForm, codeFormFromJsx, computeCalculated, conditionsMet, contentHash, countryByDialCode, countryByIso, countryByTimeZone, createBlock, createClient, createEmptyForm, createFormController, createId, defineForm, digitsOnly, evaluateCalc, flagEmoji, formSchemasEqual, formatAnswer, formatGroupedNumber, formatNational, isAutoSubmitBlock, isBlockVisible, isBuildTimeDevEnv, isCodeForm, isField, isFilloError, isLikelyDevEnv, isPossiblePhone, isTerminalPage, isValidPartialNumberText, localeForNotation, needsExplicitSubmit, normalizeFormSchema, normalizeFormTheme, normalizeSettings, parseGroupedNumber, parsePhone, pipeBlock, positionPhonePopover, prefillFromParams, provisionWorkspace, radioGroupStep, reachableFieldIds, reachableFields, reachablePageIds, reachablePageSequence, requiredFieldMessage, resolveNextPage, resolveSlotClass, resolveStrings, resolveText, resolveThemeAppearance, respondentErrorStringsFor, responseScopeValue, schemaFromJsx, sha1Base64, shouldAutoSubmit, slotClass, syncCodeForm, toE164, validateField, validateFormSchema, validateResponse, visibleBlocks, visibleFields, visibleGroupChildren, visiblePageBlocks, when };
|
|
2255
|
+
export { type AutoSubmitContext, BLOCK_KIND_META, type BaseField, type Block, type BlockKind, CONTENT_KINDS, type CalcExpr, type CalculatedField, type ChallengeConfig, type ChallengeTheme, type CheckboxField, type ChoiceField, type CodeForm, type Condition, type ConditionOp, type ContentBlock, type ContentKind, type CreatedDraft, type CustomField, DEFAULT_FIELD_STRINGS, DEFAULT_RESPONDENT_ERROR_STRINGS, DEFAULT_STRINGS, DRAFT_KINDS, type DateField, type DividerBlock, FILLO_CALC_MIN_SDK_VERSION, FILLO_CHALLENGE_MIN_SDK_VERSION, FILLO_DATA_ATTRS, FILLO_GROUP_MIN_SDK_VERSION, FILLO_MIN_SDK_VERSION, FILLO_SCHEMA_VERSION, FILLO_SDK_VERSION, FILLO_SLOTS, FILLO_THEME_VARS, type Field, type FieldKind, type FieldSpec, type FieldValue, type FileUploadField, type FileValue, type FilloAppearance, FilloClient, type FilloClientOptions, FilloError, type FilloFieldStrings, FilloJsxError, type FilloRendererStrings, type FilloRespondent, type FilloSlot, type FilloStrings, type FormBranding, type FormController, type FormControllerOptions, type FormControllerState, type FormDraftSpec, type FormPage, type FormSchema, type FormSettings, type FormStatus, type FormTheme, type GroupInstanceValue, type HeadingBlock, type HiddenField, JSX_BLOCK_COMPONENTS, JSX_BLOCK_SPECS, type JsonValue, type JsxFormMeta, type JumpRule, type LinearScaleField, MAX_FILES_PER_FIELD, type MatrixField, type NextPage, type NumberField, PHONE_COUNTRIES, PHONE_PICKER_COUNTRIES, PHONE_POPOVER_VIEWPORT_GAP, type ParagraphBlock, type ParsePhoneOptions, type ParsedPhone, type PhoneCountry, type PhoneField, type PhonePopoverPlacement, type ProvisionWorkspaceResult, type PublishedForm, REQUIRED_FIELD_MESSAGE, type RankingField, type RatingField, type RepeatingGroupField, type RespondentErrorOverrides, type RespondentErrorStrings, type ResponseData, type ResponseDraft, type ResponseLimit, type SchemaValidationResult, type SelectOption, Sha1, type SignatureField, type SlotClass, type SlotState, type SubmitMeta, type SubmitResult, type SyncFormResult, type SyncedForm, type TextField, type TrustPolicy, type UploadFileOptions, type UploadProgress, type UploadSession, type UploadStatus, type UploadTransport, type ValidationResult, type WhenBuilder, allFields, assembleForm, codeFormFromJsx, computeCalculated, conditionsMet, contentHash, countryByDialCode, countryByIso, countryByTimeZone, createBlock, createClient, createEmptyForm, createFormController, createId, defineForm, digitsOnly, evaluateCalc, flagEmoji, formSchemasEqual, formatAnswer, formatGroupedNumber, formatNational, isAutoSubmitBlock, isBlockVisible, isBuildTimeDevEnv, isCodeForm, isField, isFilloError, isLikelyDevEnv, isPossiblePhone, isTerminalPage, isValidPartialNumberText, localeForNotation, needsExplicitSubmit, normalizeFormSchema, normalizeFormTheme, normalizeSettings, parseGroupedNumber, parsePhone, pipeBlock, positionPhonePopover, prefillFromParams, provisionWorkspace, radioGroupStep, reachableFieldIds, reachableFields, reachablePageIds, reachablePageSequence, requiredFieldMessage, resolveNextPage, resolveSlotClass, resolveStrings, resolveText, resolveThemeAppearance, respondentErrorStringsFor, responseScopeValue, schemaFromJsx, sha1Base64, shouldAutoSubmit, slotClass, syncCodeForm, toE164, validateField, validateFormSchema, validateResponse, visibleBlocks, visibleFields, visibleGroupChildren, visiblePageBlocks, when };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/types.ts
|
|
2
|
+
var MAX_FILES_PER_FIELD = 200;
|
|
2
3
|
var CONTENT_KINDS = ["heading", "paragraph", "divider"];
|
|
3
4
|
function isField(block) {
|
|
4
5
|
return !CONTENT_KINDS.includes(block.kind);
|
|
@@ -311,11 +312,11 @@ function resolveNextPage(form, currentPageId, data) {
|
|
|
311
312
|
}
|
|
312
313
|
return { linear: true };
|
|
313
314
|
}
|
|
314
|
-
function reachablePageSequence(form, data) {
|
|
315
|
+
function reachablePageSequence(form, data, startPageId) {
|
|
315
316
|
const seq = [];
|
|
316
317
|
if (form.pages.length === 0) return seq;
|
|
317
318
|
const seen = /* @__PURE__ */ new Set();
|
|
318
|
-
let index = 0;
|
|
319
|
+
let index = startPageId === void 0 ? 0 : form.pages.findIndex((p) => p.id === startPageId);
|
|
319
320
|
for (let steps = 0; steps <= form.pages.length; steps++) {
|
|
320
321
|
const page = form.pages[index];
|
|
321
322
|
if (!page || seen.has(page.id)) break;
|
|
@@ -793,6 +794,7 @@ function defaultRequiredForField(field2) {
|
|
|
793
794
|
return REQUIRED_BY_KIND[field2.kind] ?? REQUIRED_FIELD_MESSAGE;
|
|
794
795
|
}
|
|
795
796
|
var DEFAULT_FIELD_STRINGS = {
|
|
797
|
+
previewSkip: "Skip",
|
|
796
798
|
required: REQUIRED_FIELD_MESSAGE,
|
|
797
799
|
requiredForField: defaultRequiredForField,
|
|
798
800
|
resumeLinkExpired: "That saved-progress link expired or was already used \u2014 start again below.",
|
|
@@ -1112,7 +1114,7 @@ var schemaShape = z2.object({
|
|
|
1112
1114
|
});
|
|
1113
1115
|
var MAX_SCHEMA_VERSION = 1;
|
|
1114
1116
|
var FILLO_SCHEMA_VERSION = 1;
|
|
1115
|
-
var FILLO_SDK_VERSION = true ? "0.
|
|
1117
|
+
var FILLO_SDK_VERSION = true ? "0.22.0" : "0.0.0-dev";
|
|
1116
1118
|
var FILLO_MIN_SDK_VERSION = "0.4.0";
|
|
1117
1119
|
var FILLO_CHALLENGE_MIN_SDK_VERSION = "0.9.0";
|
|
1118
1120
|
var FILLO_CALC_MIN_SDK_VERSION = "0.11.0";
|
|
@@ -1734,7 +1736,7 @@ function normalizeBlock(input) {
|
|
|
1734
1736
|
case "file_upload":
|
|
1735
1737
|
return cleanObject({
|
|
1736
1738
|
...baseField(rec, kind),
|
|
1737
|
-
maxFiles: int(rec.maxFiles, 1,
|
|
1739
|
+
maxFiles: int(rec.maxFiles, 1, MAX_FILES_PER_FIELD, 1),
|
|
1738
1740
|
maxFileSizeMb: int(rec.maxFileSizeMb, 1, 5e3, 500),
|
|
1739
1741
|
accept: Array.isArray(rec.accept) ? rec.accept.flatMap((v) => {
|
|
1740
1742
|
const item = optionalStr(v, 100);
|
|
@@ -2471,6 +2473,7 @@ function retryAfterSec(res) {
|
|
|
2471
2473
|
return Number.isFinite(raw) && raw > 0 ? raw : void 0;
|
|
2472
2474
|
}
|
|
2473
2475
|
var MAX_CHUNK_RETRIES = 3;
|
|
2476
|
+
var MAX_CONCURRENT_UPLOADS = 4;
|
|
2474
2477
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
2475
2478
|
var S3_PART_TIMEOUT_MS = 5 * 6e4;
|
|
2476
2479
|
var UPLOAD_CONTROL_TIMEOUT_MS = 10 * 6e4;
|
|
@@ -2544,6 +2547,8 @@ var FilloClient = class {
|
|
|
2544
2547
|
/** Server origin this client targets, normalized (no trailing slash). */
|
|
2545
2548
|
baseUrl;
|
|
2546
2549
|
fetch;
|
|
2550
|
+
activeUploads = 0;
|
|
2551
|
+
uploadQueue = /* @__PURE__ */ new Set();
|
|
2547
2552
|
/** Publishable project key, when configured. */
|
|
2548
2553
|
key;
|
|
2549
2554
|
constructor(options2 = {}) {
|
|
@@ -2750,6 +2755,40 @@ var FilloClient = class {
|
|
|
2750
2755
|
* form owner's Drive and never touch the Fillo server.
|
|
2751
2756
|
*/
|
|
2752
2757
|
async uploadFile(formId, file, options2) {
|
|
2758
|
+
await this.acquireUploadSlot(options2.signal);
|
|
2759
|
+
try {
|
|
2760
|
+
options2.signal?.throwIfAborted();
|
|
2761
|
+
return await this.performUpload(formId, file, options2);
|
|
2762
|
+
} finally {
|
|
2763
|
+
this.activeUploads -= 1;
|
|
2764
|
+
const next = this.uploadQueue.values().next().value;
|
|
2765
|
+
if (next) {
|
|
2766
|
+
this.uploadQueue.delete(next);
|
|
2767
|
+
next();
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
async acquireUploadSlot(signal) {
|
|
2772
|
+
signal?.throwIfAborted();
|
|
2773
|
+
if (this.activeUploads < MAX_CONCURRENT_UPLOADS) {
|
|
2774
|
+
this.activeUploads += 1;
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
await new Promise((resolve, reject) => {
|
|
2778
|
+
const start = () => {
|
|
2779
|
+
signal?.removeEventListener("abort", aborted);
|
|
2780
|
+
this.activeUploads += 1;
|
|
2781
|
+
resolve();
|
|
2782
|
+
};
|
|
2783
|
+
const aborted = () => {
|
|
2784
|
+
this.uploadQueue.delete(start);
|
|
2785
|
+
reject(signal?.reason);
|
|
2786
|
+
};
|
|
2787
|
+
this.uploadQueue.add(start);
|
|
2788
|
+
signal?.addEventListener("abort", aborted, { once: true });
|
|
2789
|
+
});
|
|
2790
|
+
}
|
|
2791
|
+
async performUpload(formId, file, options2) {
|
|
2753
2792
|
const name = typeof File !== "undefined" && file instanceof File ? file.name : "upload.bin";
|
|
2754
2793
|
const mime = (file.type || "application/octet-stream").trim().toLowerCase();
|
|
2755
2794
|
let session;
|
|
@@ -3431,6 +3470,23 @@ function createFormController(options2) {
|
|
|
3431
3470
|
let data = computeCalculated(form, { ...options2.initialData ?? {} });
|
|
3432
3471
|
let errors = {};
|
|
3433
3472
|
let pageIndex = 0;
|
|
3473
|
+
let previewStartPageId;
|
|
3474
|
+
const previewHistory = [];
|
|
3475
|
+
function previewNavigationEnabled() {
|
|
3476
|
+
return options2.previewNavigation === true && options2.skipValidation === true && !client && !formId && !options2.resolveFormId;
|
|
3477
|
+
}
|
|
3478
|
+
function navigationSequence() {
|
|
3479
|
+
return reachablePageSequence(
|
|
3480
|
+
form,
|
|
3481
|
+
data,
|
|
3482
|
+
previewNavigationEnabled() ? previewStartPageId : void 0
|
|
3483
|
+
);
|
|
3484
|
+
}
|
|
3485
|
+
function rememberPreviewPage() {
|
|
3486
|
+
if (previewNavigationEnabled()) {
|
|
3487
|
+
previewHistory.push({ pageIndex, startPageId: previewStartPageId });
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3434
3490
|
let status = "idle";
|
|
3435
3491
|
let restoredSubmission = false;
|
|
3436
3492
|
let resumeLinkFailed = false;
|
|
@@ -3516,7 +3572,7 @@ function createFormController(options2) {
|
|
|
3516
3572
|
// Terminal-aware: true when the current page is the last reachable page OR
|
|
3517
3573
|
// a matched jump rule ends the form here — so the footer reads Submit and
|
|
3518
3574
|
// its handler submits. Same shared engine the validator reaches with.
|
|
3519
|
-
isLastPage: isTerminalPage(form, page.id, data),
|
|
3575
|
+
isLastPage: previewNavigationEnabled() && previewStartPageId !== void 0 ? navigationSequence().at(-1) === page.id : isTerminalPage(form, page.id, data),
|
|
3520
3576
|
uploading: uploadingFields.size > 0,
|
|
3521
3577
|
submitError,
|
|
3522
3578
|
restoredSubmission,
|
|
@@ -3545,6 +3601,7 @@ function createFormController(options2) {
|
|
|
3545
3601
|
const pageErrors = {};
|
|
3546
3602
|
for (const block of visiblePageBlocks(form, target, data)) {
|
|
3547
3603
|
if (!isField(block)) continue;
|
|
3604
|
+
if (previewNavigationEnabled() && block.kind === "file_upload") continue;
|
|
3548
3605
|
const error = validateField(block, data[block.id]);
|
|
3549
3606
|
if (error) pageErrors[block.id] = error;
|
|
3550
3607
|
}
|
|
@@ -3748,7 +3805,7 @@ function createFormController(options2) {
|
|
|
3748
3805
|
function next() {
|
|
3749
3806
|
const pageCount = form.pages.length;
|
|
3750
3807
|
const clamped = Math.min(pageIndex, Math.max(pageCount - 1, 0));
|
|
3751
|
-
if (!options2.skipValidation) {
|
|
3808
|
+
if (!options2.skipValidation || options2.previewNavigation === true) {
|
|
3752
3809
|
const pageErrors = validatePage(clamped);
|
|
3753
3810
|
errors = pageErrors;
|
|
3754
3811
|
if (Object.keys(pageErrors).length > 0) {
|
|
@@ -3757,14 +3814,15 @@ function createFormController(options2) {
|
|
|
3757
3814
|
}
|
|
3758
3815
|
}
|
|
3759
3816
|
const current = form.pages[clamped];
|
|
3760
|
-
const seq =
|
|
3817
|
+
const seq = navigationSequence();
|
|
3761
3818
|
const pos = currentSeqPosition(seq);
|
|
3762
|
-
const terminal = (current ? isTerminalPage(form, current.id, data) : true) || pos < 0 || pos + 1 >= seq.length;
|
|
3819
|
+
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
3820
|
if (terminal) {
|
|
3764
3821
|
void submit();
|
|
3765
3822
|
return;
|
|
3766
3823
|
}
|
|
3767
3824
|
const nextIndex = form.pages.findIndex((p) => p.id === seq[pos + 1]);
|
|
3825
|
+
rememberPreviewPage();
|
|
3768
3826
|
pageIndex = nextIndex >= 0 ? nextIndex : Math.min(clamped + 1, pageCount - 1);
|
|
3769
3827
|
if (sessionId && client) client.reportProgress(sessionId, { furthestPage: pageIndex });
|
|
3770
3828
|
notify();
|
|
@@ -3772,6 +3830,14 @@ function createFormController(options2) {
|
|
|
3772
3830
|
}
|
|
3773
3831
|
function back() {
|
|
3774
3832
|
errors = {};
|
|
3833
|
+
const previous = previewNavigationEnabled() ? previewHistory.pop() : void 0;
|
|
3834
|
+
if (previous) {
|
|
3835
|
+
pageIndex = Math.min(previous.pageIndex, form.pages.length - 1);
|
|
3836
|
+
previewStartPageId = previous.startPageId;
|
|
3837
|
+
submitError = void 0;
|
|
3838
|
+
notify();
|
|
3839
|
+
return;
|
|
3840
|
+
}
|
|
3775
3841
|
const seq = reachablePageSequence(form, data);
|
|
3776
3842
|
const pos = currentSeqPosition(seq);
|
|
3777
3843
|
if (pos > 0) {
|
|
@@ -3784,8 +3850,25 @@ function createFormController(options2) {
|
|
|
3784
3850
|
notify();
|
|
3785
3851
|
checkpointDraft();
|
|
3786
3852
|
}
|
|
3853
|
+
function skipPreviewPage() {
|
|
3854
|
+
if (!previewNavigationEnabled() || status === "submitting" || status === "submitted" || pageIndex >= form.pages.length - 1)
|
|
3855
|
+
return;
|
|
3856
|
+
rememberPreviewPage();
|
|
3857
|
+
pageIndex += 1;
|
|
3858
|
+
previewStartPageId = form.pages[pageIndex]?.id;
|
|
3859
|
+
errors = {};
|
|
3860
|
+
submitError = void 0;
|
|
3861
|
+
notify();
|
|
3862
|
+
}
|
|
3787
3863
|
async function submit() {
|
|
3788
3864
|
if (status === "submitting" || status === "submitted") return;
|
|
3865
|
+
if (previewNavigationEnabled()) {
|
|
3866
|
+
errors = validatePage(pageIndex);
|
|
3867
|
+
if (Object.keys(errors).length > 0) {
|
|
3868
|
+
notify();
|
|
3869
|
+
return;
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3789
3872
|
const result = validateResponse(form, data);
|
|
3790
3873
|
if (!result.ok) {
|
|
3791
3874
|
const transportlessPreview = options2.skipValidation && !(client && formId);
|
|
@@ -3809,7 +3892,11 @@ function createFormController(options2) {
|
|
|
3809
3892
|
const firstBad = form.pages.findIndex(
|
|
3810
3893
|
(p) => visiblePageBlocks(form, p, data).some((b) => b.id in previewErrors)
|
|
3811
3894
|
);
|
|
3812
|
-
if (firstBad >= 0)
|
|
3895
|
+
if (firstBad >= 0) {
|
|
3896
|
+
pageIndex = firstBad;
|
|
3897
|
+
previewStartPageId = void 0;
|
|
3898
|
+
previewHistory.length = 0;
|
|
3899
|
+
}
|
|
3813
3900
|
notify();
|
|
3814
3901
|
return;
|
|
3815
3902
|
}
|
|
@@ -3911,6 +3998,7 @@ function createFormController(options2) {
|
|
|
3911
3998
|
setValue,
|
|
3912
3999
|
setUploading,
|
|
3913
4000
|
next,
|
|
4001
|
+
skipPreviewPage,
|
|
3914
4002
|
back,
|
|
3915
4003
|
submit,
|
|
3916
4004
|
setContext(ctx) {
|
|
@@ -3955,6 +4043,8 @@ function createFormController(options2) {
|
|
|
3955
4043
|
data = computeCalculated(form, data);
|
|
3956
4044
|
errors = {};
|
|
3957
4045
|
pageIndex = 0;
|
|
4046
|
+
previewStartPageId = void 0;
|
|
4047
|
+
previewHistory.length = 0;
|
|
3958
4048
|
submitError = void 0;
|
|
3959
4049
|
resumedDraft = false;
|
|
3960
4050
|
editingPrevious = false;
|
|
@@ -4714,6 +4804,7 @@ export {
|
|
|
4714
4804
|
FilloJsxError,
|
|
4715
4805
|
JSX_BLOCK_COMPONENTS,
|
|
4716
4806
|
JSX_BLOCK_SPECS,
|
|
4807
|
+
MAX_FILES_PER_FIELD,
|
|
4717
4808
|
PHONE_COUNTRIES,
|
|
4718
4809
|
PHONE_PICKER_COUNTRIES,
|
|
4719
4810
|
PHONE_POPOVER_VIEWPORT_GAP,
|