@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 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, default 1. */
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): string[];
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.20.0" : "0.0.0-dev";
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, 20, 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 = reachablePageSequence(form, data);
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) pageIndex = firstBad;
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefillo/core",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "description": "Form schema, validation, logic engine and JS client for Fillo. Framework-agnostic.",
5
5
  "license": "MIT",
6
6
  "keywords": [