@usefillo/core 0.12.0 → 0.12.1

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
@@ -1696,8 +1696,8 @@ declare function resolveThemeAppearance(theme: FormTheme | null): FormTheme | nu
1696
1696
  /**
1697
1697
  * The default English validation message for a required field left empty.
1698
1698
  * `validateField` returns this exact sentinel (core has no strings context),
1699
- * and the React render layer swaps it for `strings.required` so a localized
1700
- * site can translate it. Keep it identical to `DEFAULT_FIELD_STRINGS.required`.
1699
+ * and renderer layers swap it for field-aware/localized copy. Keep it
1700
+ * identical to `DEFAULT_FIELD_STRINGS.required`.
1701
1701
  */
1702
1702
  declare const REQUIRED_FIELD_MESSAGE = "This field is required";
1703
1703
  /**
@@ -1763,8 +1763,12 @@ declare const DEFAULT_STRINGS: FilloStrings;
1763
1763
  * an exhaustively-enumerated, closed set.
1764
1764
  */
1765
1765
  interface FilloFieldStrings {
1766
- /** Validation: a required field was left empty. Mirrors REQUIRED_FIELD_MESSAGE. */
1766
+ /** Generic/legacy validation copy for a required field left empty. Mirrors
1767
+ * REQUIRED_FIELD_MESSAGE and remains the fallback for custom/hidden fields. */
1767
1768
  required: string;
1769
+ /** Optional field-aware required copy. Existing `required` overrides keep
1770
+ * their legacy generic behavior unless this function is also supplied. */
1771
+ requiredForField?: (field: Field) => string;
1768
1772
  /** Notice when a spent/expired resume link couldn't restore progress. */
1769
1773
  resumeLinkExpired: string;
1770
1774
  /** Success-screen message when a verified identity re-submits and the form
@@ -1772,6 +1776,14 @@ interface FilloFieldStrings {
1772
1776
  alreadyAnswered: string;
1773
1777
  /** Retry control on a failed upload row. */
1774
1778
  uploadRetry: string;
1779
+ /** Accessible action names for upload rows. The filename is appended by the renderer. */
1780
+ uploadCancel: string;
1781
+ uploadRemove: string;
1782
+ uploadDismiss: string;
1783
+ /** Visible secondary status for an upload in progress. */
1784
+ uploadingFile: (percent: number, size: string) => string;
1785
+ /** Visible secondary status for a completed upload. */
1786
+ uploadedFile: (size: string) => string;
1775
1787
  /** Dropzone copy when uploads can't run because the form isn't connected. */
1776
1788
  uploadsDisabled: string;
1777
1789
  /** Dropzone copy for an explicit render-only preview, which never has transport. */
@@ -1797,8 +1809,8 @@ interface FilloFieldStrings {
1797
1809
  /** Live-region announcement while a submit is in flight — for auto-submit
1798
1810
  * forms, which have no footer/button to show `submitting` on. */
1799
1811
  submittingAnnouncement: string;
1800
- /** Heading on the failed-submit error summary (one `role="alert"` summary
1801
- * linking to fields, GOV.UK pattern — replaces N competing per-field alerts). */
1812
+ /** @deprecated Retained for localization compatibility. Default renderers
1813
+ * now focus the first invalid control and show field-aware inline guidance. */
1802
1814
  errorSummaryTitle: string;
1803
1815
  /** Live-region announcement after a ranking move: "«label», position n of m". */
1804
1816
  rankingPosition: (label: string, position: number, count: number) => string;
@@ -1816,8 +1828,12 @@ interface FilloFieldStrings {
1816
1828
  declare const DEFAULT_FIELD_STRINGS: FilloFieldStrings;
1817
1829
  /** Everything the default renderers can localize — chrome + field/validation. */
1818
1830
  type FilloRendererStrings = FilloStrings & FilloFieldStrings;
1831
+ /** Resolve the renderer copy for core's stable required-field sentinel. */
1832
+ declare function requiredFieldMessage(field: Field, strings: Pick<FilloFieldStrings, "required" | "requiredForField">): string;
1819
1833
  /** Merge overrides over the built-in chrome + field defaults. Accepts a partial
1820
- * of the full renderer surface so the `strings` prop can override either set. */
1834
+ * of the full renderer surface so the `strings` prop can override either set.
1835
+ * A legacy generic `required` override disables the new field-aware default
1836
+ * unless the caller explicitly supplies `requiredForField` too. */
1821
1837
  declare function resolveStrings(overrides?: Partial<FilloRendererStrings>): FilloRendererStrings;
1822
1838
 
1823
1839
  /** Result of syncing a code-defined form: its canonical id, slug, and branding. */
@@ -2058,4 +2074,4 @@ declare class Sha1 {
2058
2074
  }
2059
2075
  declare const sha1Base64: (bytes: Uint8Array) => string;
2060
2076
 
2061
- export { type AutoSubmitContext, BLOCK_KIND_META, type BaseField, type Block, type BlockKind, CONTENT_KINDS, type CalcExpr, type CalculatedField, type ChallengeConfig, type CheckboxField, type ChoiceField, type CodeForm, type Condition, type ConditionOp, type ContentBlock, type ContentKind, type CreatedDraft, type CustomField, DEFAULT_FIELD_STRINGS, DEFAULT_STRINGS, DRAFT_KINDS, type DateField, type DividerBlock, FILLO_CALC_MIN_SDK_VERSION, FILLO_CHALLENGE_MIN_SDK_VERSION, FILLO_DATA_ATTRS, 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 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 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, resolveNextPage, resolveSlotClass, resolveStrings, resolveText, resolveThemeAppearance, responseScopeValue, schemaFromJsx, sha1Base64, shouldAutoSubmit, slotClass, syncCodeForm, toE164, validateField, validateFormSchema, validateResponse, visibleBlocks, visibleFields, visiblePageBlocks, when };
2077
+ export { type AutoSubmitContext, BLOCK_KIND_META, type BaseField, type Block, type BlockKind, CONTENT_KINDS, type CalcExpr, type CalculatedField, type ChallengeConfig, type CheckboxField, type ChoiceField, type CodeForm, type Condition, type ConditionOp, type ContentBlock, type ContentKind, type CreatedDraft, type CustomField, DEFAULT_FIELD_STRINGS, DEFAULT_STRINGS, DRAFT_KINDS, type DateField, type DividerBlock, FILLO_CALC_MIN_SDK_VERSION, FILLO_CHALLENGE_MIN_SDK_VERSION, FILLO_DATA_ATTRS, 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 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 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, responseScopeValue, schemaFromJsx, sha1Base64, shouldAutoSubmit, slotClass, syncCodeForm, toE164, validateField, validateFormSchema, validateResponse, visibleBlocks, visibleFields, visiblePageBlocks, when };
package/dist/index.js CHANGED
@@ -707,11 +707,39 @@ var DEFAULT_STRINGS = {
707
707
  resumeStartOver: "Start over",
708
708
  challengeUnavailable: "The verification check couldn't load. Refresh the page, or check that challenges.cloudflare.com isn't blocked."
709
709
  };
710
+ var REQUIRED_BY_KIND = {
711
+ short_text: "Enter your answer",
712
+ long_text: "Enter your answer",
713
+ email: "Enter an email address",
714
+ url: "Enter a URL",
715
+ phone: "Enter a phone number",
716
+ number: "Enter a number",
717
+ select: "Choose an option",
718
+ dropdown: "Choose an option",
719
+ multi_select: "Select at least one option",
720
+ checkbox: "Select this checkbox",
721
+ rating: "Choose a rating",
722
+ linear_scale: "Choose a value",
723
+ ranking: "Rank every option",
724
+ matrix: "Answer every row",
725
+ signature: "Add your signature",
726
+ date: "Enter a date",
727
+ file_upload: "Add a file"
728
+ };
729
+ function defaultRequiredForField(field2) {
730
+ return REQUIRED_BY_KIND[field2.kind] ?? REQUIRED_FIELD_MESSAGE;
731
+ }
710
732
  var DEFAULT_FIELD_STRINGS = {
711
733
  required: REQUIRED_FIELD_MESSAGE,
734
+ requiredForField: defaultRequiredForField,
712
735
  resumeLinkExpired: "That saved-progress link expired or was already used \u2014 start again below.",
713
736
  alreadyAnswered: "You've already answered this form.",
714
737
  uploadRetry: "Retry",
738
+ uploadCancel: "Cancel",
739
+ uploadRemove: "Remove",
740
+ uploadDismiss: "Dismiss",
741
+ uploadingFile: (percent, size) => `Uploading \xB7 ${percent}% \xB7 ${size}`,
742
+ uploadedFile: (size) => `Uploaded \xB7 ${size}`,
715
743
  uploadsDisabled: "Connect this form to Fillo to enable uploads",
716
744
  uploadsRenderOnly: "Uploads are unavailable in this render-only preview",
717
745
  uploadsUnavailable: "Uploads are temporarily unavailable",
@@ -724,15 +752,22 @@ var DEFAULT_FIELD_STRINGS = {
724
752
  uploadsFailed: (count) => `${count} ${count === 1 ? "upload" : "uploads"} failed.`,
725
753
  filesUploaded: (count) => `${count} ${count === 1 ? "file" : "files"} uploaded.`,
726
754
  submittingAnnouncement: "Submitting your response\u2026",
727
- errorSummaryTitle: "Please fix the following:",
755
+ errorSummaryTitle: "Check these fields",
728
756
  rankingPosition: (label, position, count) => `${label}, position ${position} of ${count}`,
729
757
  phoneCountrySelected: (name) => `${name} selected`,
730
758
  phoneResultsCount: (count) => `${count} ${count === 1 ? "result" : "results"}`,
731
759
  signatureEmpty: "No signature yet",
732
760
  signatureSigned: "Signature saved"
733
761
  };
762
+ function requiredFieldMessage(field2, strings) {
763
+ return strings.requiredForField?.(field2) ?? strings.required;
764
+ }
734
765
  function resolveStrings(overrides) {
735
- return overrides ? { ...DEFAULT_STRINGS, ...DEFAULT_FIELD_STRINGS, ...overrides } : { ...DEFAULT_STRINGS, ...DEFAULT_FIELD_STRINGS };
766
+ const resolved = overrides ? { ...DEFAULT_STRINGS, ...DEFAULT_FIELD_STRINGS, ...overrides } : { ...DEFAULT_STRINGS, ...DEFAULT_FIELD_STRINGS };
767
+ if (overrides && Object.prototype.hasOwnProperty.call(overrides, "required") && !Object.prototype.hasOwnProperty.call(overrides, "requiredForField")) {
768
+ delete resolved.requiredForField;
769
+ }
770
+ return resolved;
736
771
  }
737
772
 
738
773
  // src/validation.ts
@@ -962,7 +997,7 @@ var schemaShape = z2.object({
962
997
  });
963
998
  var MAX_SCHEMA_VERSION = 1;
964
999
  var FILLO_SCHEMA_VERSION = 1;
965
- var FILLO_SDK_VERSION = true ? "0.12.0" : "0.0.0-dev";
1000
+ var FILLO_SDK_VERSION = true ? "0.12.1" : "0.0.0-dev";
966
1001
  var FILLO_MIN_SDK_VERSION = "0.4.0";
967
1002
  var FILLO_CHALLENGE_MIN_SDK_VERSION = "0.9.0";
968
1003
  var FILLO_CALC_MIN_SDK_VERSION = "0.11.0";
@@ -3319,8 +3354,14 @@ function createFormController(options2) {
3319
3354
  scheduleDraftSave();
3320
3355
  }
3321
3356
  function setUploading(fieldId, busy) {
3322
- if (busy) uploadingFields.add(fieldId);
3323
- else uploadingFields.delete(fieldId);
3357
+ if (busy) {
3358
+ uploadingFields.add(fieldId);
3359
+ if (fieldId in errors) {
3360
+ errors = Object.fromEntries(Object.entries(errors).filter(([k]) => k !== fieldId));
3361
+ }
3362
+ } else {
3363
+ uploadingFields.delete(fieldId);
3364
+ }
3324
3365
  notify();
3325
3366
  }
3326
3367
  function currentSeqPosition(seq) {
@@ -3820,12 +3861,16 @@ function syncCodeForm(client, form, opts) {
3820
3861
  const content2 = JSON.stringify(form.schema) + JSON.stringify(form.theme ?? null);
3821
3862
  const hash = contentHash(content2);
3822
3863
  const key = `${client.baseUrl}:${client.key}:${form.id}:${hash}`;
3864
+ const revalidateUploadState = allFields(form.schema).some(
3865
+ (field2) => field2.kind === "file_upload"
3866
+ );
3823
3867
  const cached = syncCache.get(key);
3824
3868
  if (cached && !opts?.bypassCache) {
3825
- if (cached.expiresAt === null || cached.expiresAt > Date.now()) return cached.promise;
3869
+ if (cached.expiresAt === null || !revalidateUploadState && cached.expiresAt > Date.now())
3870
+ return cached.promise;
3826
3871
  syncCache.delete(key);
3827
3872
  }
3828
- if (!opts?.bypassCache) {
3873
+ if (!opts?.bypassCache && !revalidateUploadState) {
3829
3874
  const stored = readStoredSync(client, form.id, hash);
3830
3875
  if (stored) {
3831
3876
  const promise2 = Promise.resolve({
@@ -3847,7 +3892,7 @@ function syncCodeForm(client, form, opts) {
3847
3892
  promise.then(
3848
3893
  (result) => {
3849
3894
  if (syncCache.get(key) !== entry) return;
3850
- if (isVolatileSync(result)) {
3895
+ if (revalidateUploadState || isVolatileSync(result)) {
3851
3896
  syncCache.delete(key);
3852
3897
  return;
3853
3898
  }
@@ -4299,6 +4344,7 @@ export {
4299
4344
  reachableFields,
4300
4345
  reachablePageIds,
4301
4346
  reachablePageSequence,
4347
+ requiredFieldMessage,
4302
4348
  resolveNextPage,
4303
4349
  resolveSlotClass,
4304
4350
  resolveStrings,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefillo/core",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Form schema, validation, logic engine and JS client for Fillo. Framework-agnostic.",
5
5
  "license": "MIT",
6
6
  "keywords": [