@usefillo/react 0.7.0 → 0.9.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/README.md CHANGED
@@ -71,7 +71,8 @@ Every rendered part carries a named slot (`data-fillo`) and state attributes
71
71
  (`data-invalid`, `data-selected`, `data-checked`, …), and the default
72
72
  stylesheet is cascade-layered so your utilities always win. On Tailwind v3 or
73
73
  reset-heavy sites import `@usefillo/react/styles.unlayered.css` instead.
74
- Localize every built-in string with the `strings` prop. Styling contract:
74
+ Localize the shared form chrome (navigation, submit states, errors, and resume
75
+ notices) with the `strings` prop. Styling contract:
75
76
  [fillo.so/docs/styling](https://fillo.so/docs/styling).
76
77
 
77
78
  ## Go fully headless
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { ComponentType, ReactNode, ReactElement } from 'react';
3
3
  import * as _usefillo_core from '@usefillo/core';
4
- import { FormSchema, FilloClient, ResponseData, FieldValue, FormPage, Block, FormStatus, FieldKind, Field, CustomField, FormTheme, FilloAppearance, FilloStrings, FilloRespondent, FilloError, CodeForm, FormSettings, Condition, TextField, PhoneField, NumberField, ChoiceField, SelectOption, CheckboxField, RatingField, LinearScaleField, RankingField, SignatureField, DateField, FileUploadField as FileUploadField$1, HiddenField } from '@usefillo/core';
5
- export { CodeForm, Field, FieldValue, FileValue, FilloAppearance, FilloClient, FilloError, FilloJsxError, FilloSlot, FilloStrings, FormSchema, FormStatus, FormTheme, ProvisionWorkspaceResult, PublishedForm, ResponseData, SlotState, createClient, defineForm, provisionWorkspace, when } from '@usefillo/core';
4
+ import { FormSchema, FilloClient, ResponseData, FieldValue, FormPage, Block, FormStatus, FieldKind, Field, CustomField, FormTheme, FilloAppearance, FilloRendererStrings, FilloRespondent, ChallengeConfig, FilloError, CodeForm, FormSettings, Condition, TextField, PhoneField, NumberField, ChoiceField, SelectOption, CheckboxField, RatingField, LinearScaleField, RankingField, SignatureField, DateField, FileUploadField as FileUploadField$1, HiddenField } from '@usefillo/core';
5
+ export { CodeForm, Field, FieldValue, FileValue, FilloAppearance, FilloClient, FilloError, FilloJsxError, FilloRendererStrings, FilloSlot, FilloStrings, FormSchema, FormStatus, FormTheme, ProvisionWorkspaceResult, PublishedForm, ResponseData, SlotState, createClient, defineForm, provisionWorkspace, when } from '@usefillo/core';
6
6
 
7
7
  /**
8
8
  * Everything a custom renderer needs. Returned by useFillo() and provided
@@ -48,6 +48,23 @@ interface FilloApi {
48
48
  * previous answers — submitting updates that response in place.
49
49
  */
50
50
  editingPrevious: boolean;
51
+ /**
52
+ * True when the last submit was kept as an already-recorded response (a
53
+ * verified identify() repeat on a keep-mode form) rather than a fresh one.
54
+ * Renderers show an "already answered" note instead of implying a new save.
55
+ */
56
+ duplicateSubmission: boolean;
57
+ /**
58
+ * True when the last submit updated the person's existing response in place
59
+ * (responseLimit onRepeat "update") rather than creating a new one.
60
+ */
61
+ updatedSubmission: boolean;
62
+ /**
63
+ * True when a resume link (#fillo-draft=…) was expired, spent, or foreign, so
64
+ * no progress could be restored. Renderers explain the blank form instead of
65
+ * showing it with no context.
66
+ */
67
+ resumeLinkFailed: boolean;
51
68
  /**
52
69
  * Persist unsaved draft progress right now (settings.saveProgress forms).
53
70
  * The built-in renderers call it on pagehide/visibility-hidden; custom
@@ -105,7 +122,7 @@ interface FilloFormBaseProps {
105
122
  */
106
123
  appearance?: FilloAppearance;
107
124
  /** Override any visitor-facing renderer string (for localized sites). */
108
- strings?: Partial<FilloStrings>;
125
+ strings?: Partial<FilloRendererStrings>;
109
126
  /** Swap any built-in field kind for your own component. */
110
127
  components?: FieldComponents;
111
128
  /** Renderers for your own `custom` field kinds, keyed by `component`. */
@@ -119,6 +136,13 @@ interface FilloFormBaseProps {
119
136
  * loads).
120
137
  */
121
138
  respondent?: FilloRespondent;
139
+ /**
140
+ * Human-verification challenge config (public site key + provider). Normally
141
+ * the SDK reads this from the form fetch automatically; pass it explicitly
142
+ * only when you render an inline `form` schema and still want the widget (the
143
+ * hosted page does this). The SECRET key stays server-side — never passed here.
144
+ */
145
+ challenge?: ChallengeConfig;
122
146
  onChange?: (data: ResponseData) => void;
123
147
  onSubmitted?: (responseId: string | undefined, data: ResponseData) => void;
124
148
  /** Observe load and code-form sync failures (otherwise only logged). */
@@ -167,8 +191,8 @@ declare function FilloForm(props: FilloFormProps): react.JSX.Element;
167
191
  * The authoring namespace: `<Fillo.Form id="contact"><Fillo.Email id="email"
168
192
  * label="Work email"/></Fillo.Form>`. Field elements are inert descriptors
169
193
  * compiled (never rendered) into the exact CodeForm defineForm() emits, then
170
- * fed to the existing framed <FilloForm> — same sync, same draft-by-default,
171
- * same badge, same responses. Define forms in a client module ("use client");
194
+ * fed to the existing framed <FilloForm> — same policy-aware resolution and
195
+ * staging, same badge, same responses. Define forms in a client module ("use client");
172
196
  * pass the compiled VALUE across server/client boundaries, never the JSX.
173
197
  */
174
198
  type WithVisible<T> = Omit<T, "kind" | "visibleIf"> & {
@@ -261,7 +285,7 @@ interface ControllerOptions {
261
285
  * renderers pass "default" explicitly.
262
286
  */
263
287
  surface?: "default" | "headless";
264
- /** Resolve the submission target at submit time when formId is still unset. */
288
+ /** Resolve/verify the canonical submission target immediately before submit. */
265
289
  resolveFormId?: () => Promise<string>;
266
290
  /**
267
291
  * Host-app account context (identify()): who is filling this form, by your
@@ -269,6 +293,12 @@ interface ControllerOptions {
269
293
  * dashboard, webhooks, and integrations can say who answered.
270
294
  */
271
295
  respondent?: FilloRespondent;
296
+ /** True when the form requires a human-verification challenge (Turnstile). */
297
+ challengeRequired?: boolean;
298
+ /** Read the current challenge token from the rendered widget (lazy). */
299
+ getChallengeToken?: () => string | undefined;
300
+ /** The server rejected the challenge — reset the widget for a fresh token. */
301
+ onChallengeFailed?: () => void;
272
302
  }
273
303
  /**
274
304
  * React binding for the framework-agnostic engine in @usefillo/core
@@ -286,14 +316,19 @@ interface FilloProviderProps extends Omit<ControllerOptions, "form"> {
286
316
  /** Slot classes for FormField-rendered fields in your composed layout. */
287
317
  appearance?: FilloAppearance;
288
318
  /** Override any visitor-facing renderer string (for localized sites). */
289
- strings?: Partial<FilloStrings>;
319
+ strings?: Partial<FilloRendererStrings>;
320
+ /** Observe code-form sync/configuration failures. */
321
+ onError?: (error: FilloError) => void;
322
+ /** Custom unavailable state; receives the full actionable integration error. */
323
+ renderError?: (error: FilloError) => ReactNode;
290
324
  children: ReactNode;
291
325
  }
292
326
  /**
293
327
  * The headless escape hatch. Sets up the form engine (validation, conditional
294
- * logic, uploads, submit) and renders **no layout at all** — you compose the
295
- * entire form yourself with <FormField>, useField() and useFillo(),
296
- * interleaving any markup of your own between fields.
328
+ * logic, uploads, submit) and renders no resolved form layout — you compose it
329
+ * with <FormField>, useField() and useFillo(). In production, a code form
330
+ * withholds children (returns null) until its canonical schema is safe; pass
331
+ * renderError to own unavailable/not-published UI without adding SDK layout.
297
332
  *
298
333
  * <FilloProvider form={feedback} client={client}>
299
334
  * <YourErrorContext />
@@ -308,7 +343,7 @@ interface FilloProviderProps extends Omit<ControllerOptions, "form"> {
308
343
  * defineForm() form and a keyed client, the structure also syncs into your
309
344
  * workspace, exactly like <FilloForm>.
310
345
  */
311
- declare function FilloProvider({ children, form, formId, client, appearance, strings, ...options }: FilloProviderProps): react.JSX.Element;
346
+ declare function FilloProvider({ children, form, formId, client, appearance, strings, onError, renderError, ...options }: FilloProviderProps): react.JSX.Element | null;
312
347
 
313
348
  /**
314
349
  * The full form engine — data, errors, pages, submit, status. Use inside a
@@ -353,9 +388,9 @@ declare function FormField({ id, components, customComponents, }: {
353
388
  }): react.JSX.Element | null;
354
389
 
355
390
  /**
356
- * Default file upload field: drag & drop, resumable chunked uploads with live
357
- * progress, multiple files. Replace it entirely via the `components` prop if
358
- * you want your own — completed uploads are just FileValue[] in the data.
391
+ * Default file upload field: drag & drop, multiple files, live progress, and
392
+ * provider-aware browser-direct transfer (resumable where supported). Replace
393
+ * it via `components` if needed; completed uploads are FileValue[] in the data.
359
394
  */
360
395
  declare function FileUploadField({ field, value, error, setValue, api, ids: providedIds }: FieldComponentProps): react.JSX.Element;
361
396