@usefillo/react 0.5.4 → 0.6.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/README.md +68 -14
- package/dist/index.d.ts +106 -6
- package/dist/index.js +475 -149
- package/dist/styles.css +15 -11
- package/dist/styles.unlayered.css +700 -0
- package/package.json +10 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @usefillo/react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React components and hooks for embedding [Fillo](https://fillo.so) forms **natively inside your product** — rendered in your own DOM, with your styles, on your route. No iframe.
|
|
4
4
|
|
|
5
5
|
### 📚 Full documentation → **[fillo.so/docs](https://fillo.so/docs)**
|
|
6
6
|
|
|
@@ -10,34 +10,88 @@ npm i @usefillo/react
|
|
|
10
10
|
|
|
11
11
|
`react` and `react-dom` (18 or 19) are peer dependencies.
|
|
12
12
|
|
|
13
|
+
## Write forms as components
|
|
14
|
+
|
|
13
15
|
```tsx
|
|
14
|
-
|
|
16
|
+
"use client";
|
|
17
|
+
import { Fillo, when, createClient } from "@usefillo/react";
|
|
15
18
|
import "@usefillo/react/styles.css"; // optional default theme — or bring your own
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
const client = createClient({ key: process.env.NEXT_PUBLIC_FILLO_KEY });
|
|
21
|
+
|
|
22
|
+
export function ContactForm() {
|
|
23
|
+
return (
|
|
24
|
+
<Fillo.Form id="contact" title="Talk to us" client={client}>
|
|
25
|
+
<Fillo.Text id="name" label="Your name" required />
|
|
26
|
+
<Fillo.Email id="email" label="Work email" required />
|
|
27
|
+
<Fillo.Select id="topic" label="Topic" required>
|
|
28
|
+
<Fillo.Option id="sales" label="Sales" />
|
|
29
|
+
<Fillo.Option id="support" label="Support" />
|
|
30
|
+
</Fillo.Select>
|
|
31
|
+
<Fillo.LongText id="message" label="How can we help?"
|
|
32
|
+
visibleIf={when("topic").eq("support")} />
|
|
33
|
+
</Fillo.Form>
|
|
34
|
+
);
|
|
19
35
|
}
|
|
20
36
|
```
|
|
21
37
|
|
|
22
|
-
|
|
38
|
+
The first time this runs, the form appears in your Fillo workspace as a draft —
|
|
39
|
+
publish it there and responses, logic, exports, webhooks, and integrations all
|
|
40
|
+
work. Field ids are permanent (they key your responses); conditional questions
|
|
41
|
+
are `visibleIf`, never conditional JSX. The equivalent config style,
|
|
42
|
+
`defineForm({ id, pages })`, remains first-class — JSX compiles to it exactly.
|
|
43
|
+
|
|
44
|
+
## Or embed a form built in the dashboard
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { FilloForm } from "@usefillo/react";
|
|
48
|
+
|
|
49
|
+
<FilloForm formId="cust-feedback" onSubmitted={(r) => confetti()} />
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Style it with your own classes
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
<Fillo.Form
|
|
56
|
+
id="contact"
|
|
57
|
+
client={client}
|
|
58
|
+
appearance={{
|
|
59
|
+
theme: { primary: "#4f46e5", radius: "12px" }, // also themes your hosted page
|
|
60
|
+
classNames: {
|
|
61
|
+
control: "rounded-xl border-zinc-200 data-[invalid]:border-red-400",
|
|
62
|
+
option: "rounded-lg border p-3 data-[selected]:border-indigo-600",
|
|
63
|
+
button: (s) => (s.variant === "primary" ? "bg-indigo-600 text-white" : ""),
|
|
64
|
+
},
|
|
65
|
+
fields: { nps: { control: "grid grid-cols-11 gap-1" } },
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
```
|
|
23
69
|
|
|
24
|
-
|
|
25
|
-
- `
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
|
|
70
|
+
Every rendered part carries a named slot (`data-fillo`) and state attributes
|
|
71
|
+
(`data-invalid`, `data-selected`, `data-checked`, …), and the default
|
|
72
|
+
stylesheet is cascade-layered so your utilities always win. On Tailwind v3 or
|
|
73
|
+
reset-heavy sites import `@usefillo/react/styles.unlayered.css` instead.
|
|
74
|
+
Localize every built-in string with the `strings` prop. Styling contract:
|
|
75
|
+
[fillo.so/docs/styling](https://fillo.so/docs/styling).
|
|
29
76
|
|
|
30
|
-
|
|
77
|
+
## Go fully headless
|
|
31
78
|
|
|
32
|
-
|
|
79
|
+
Every part is replaceable — and every embed method is free:
|
|
33
80
|
|
|
34
|
-
|
|
81
|
+
- `components` / `customComponents` — swap any field kind for your own
|
|
82
|
+
- `<FilloProvider>` + `<FormField>` / `useField()` — your layout, Fillo's engine
|
|
83
|
+
- `useFilloController()` — the bare engine for total control
|
|
35
84
|
|
|
36
|
-
|
|
85
|
+
URL prefill works in embeds (`?field=value`, hidden-field `paramName`),
|
|
86
|
+
submissions retry safely, and failed submits show a visible, answer-preserving
|
|
87
|
+
error. This package re-exports the embedding surface from
|
|
88
|
+
[`@usefillo/core`](https://www.npmjs.com/package/@usefillo/core) so a single
|
|
89
|
+
import is usually enough.
|
|
37
90
|
|
|
38
91
|
## Links
|
|
39
92
|
|
|
40
93
|
- **Docs:** [fillo.so/docs](https://fillo.so/docs)
|
|
94
|
+
- **Authoring guide:** [fillo.so/docs/authoring](https://fillo.so/docs/authoring)
|
|
41
95
|
- **Website:** [fillo.so](https://fillo.so)
|
|
42
96
|
|
|
43
97
|
MIT licensed.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ComponentType, ReactNode } from 'react';
|
|
3
|
-
import
|
|
4
|
-
|
|
2
|
+
import { ComponentType, ReactNode, ReactElement } from 'react';
|
|
3
|
+
import * as _usefillo_core from '@usefillo/core';
|
|
4
|
+
import { FormSchema, FilloClient, ResponseData, FieldValue, FormPage, Block, FormStatus, FieldKind, Field, CustomField, FormTheme, FilloAppearance, FilloStrings, 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';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Everything a custom renderer needs. Returned by useFillo() and provided
|
|
@@ -27,6 +28,8 @@ interface FilloApi {
|
|
|
27
28
|
status: FormStatus;
|
|
28
29
|
/** True while any file upload is in flight — submit is blocked. */
|
|
29
30
|
uploading: boolean;
|
|
31
|
+
/** Human-readable message for the last failed submit; cleared on edit/retry. */
|
|
32
|
+
submitError?: string;
|
|
30
33
|
/** Used by upload fields to gate submission. */
|
|
31
34
|
setUploading: (fieldId: string, busy: boolean) => void;
|
|
32
35
|
}
|
|
@@ -69,6 +72,14 @@ type CustomComponents = Record<string, ComponentType<FieldComponentProps<CustomF
|
|
|
69
72
|
|
|
70
73
|
interface FilloFormBaseProps {
|
|
71
74
|
theme?: FormTheme;
|
|
75
|
+
/**
|
|
76
|
+
* The styling contract: theme tokens plus per-slot class strings (Tailwind
|
|
77
|
+
* or your own), appended after the built-in fillo-* classes so they win by
|
|
78
|
+
* cascade order. `appearance.theme` outranks every other theme source.
|
|
79
|
+
*/
|
|
80
|
+
appearance?: FilloAppearance;
|
|
81
|
+
/** Override any visitor-facing renderer string (for localized sites). */
|
|
82
|
+
strings?: Partial<FilloStrings>;
|
|
72
83
|
/** Swap any built-in field kind for your own component. */
|
|
73
84
|
components?: FieldComponents;
|
|
74
85
|
/** Renderers for your own `custom` field kinds, keyed by `component`. */
|
|
@@ -118,6 +129,85 @@ type PreviewFormProps = FilloFormBaseProps & {
|
|
|
118
129
|
type FilloFormProps = HostedFormProps | CodeBackedFormProps | PreviewFormProps;
|
|
119
130
|
declare function FilloForm(props: FilloFormProps): react.JSX.Element;
|
|
120
131
|
|
|
132
|
+
/**
|
|
133
|
+
* The authoring namespace: `<Fillo.Form id="contact"><Fillo.Email id="email"
|
|
134
|
+
* label="Work email"/></Fillo.Form>`. Field elements are inert descriptors
|
|
135
|
+
* compiled (never rendered) into the exact CodeForm defineForm() emits, then
|
|
136
|
+
* fed to the existing framed <FilloForm> — same sync, same draft-by-default,
|
|
137
|
+
* same badge, same responses. Define forms in a client module ("use client");
|
|
138
|
+
* pass the compiled VALUE across server/client boundaries, never the JSX.
|
|
139
|
+
*/
|
|
140
|
+
type WithVisible<T> = Omit<T, "kind" | "visibleIf"> & {
|
|
141
|
+
visibleIf?: Condition | Condition[];
|
|
142
|
+
};
|
|
143
|
+
type ChoiceProps = Omit<WithVisible<ChoiceField>, "options"> & {
|
|
144
|
+
options?: SelectOption[];
|
|
145
|
+
children?: ReactNode;
|
|
146
|
+
};
|
|
147
|
+
type ContentProps = {
|
|
148
|
+
id: string;
|
|
149
|
+
children?: string;
|
|
150
|
+
text?: string;
|
|
151
|
+
};
|
|
152
|
+
/** Inert: rendering one throws; they exist to be read by the compiler. */
|
|
153
|
+
type Inert<P> = (props: P) => never;
|
|
154
|
+
interface FilloJsxFormProps extends Omit<FilloFormProps, "form" | "formId" | "client"> {
|
|
155
|
+
/** Workspace handle — the form's identity across syncs. */
|
|
156
|
+
id: string;
|
|
157
|
+
title?: string;
|
|
158
|
+
description?: string;
|
|
159
|
+
settings?: FormSettings;
|
|
160
|
+
theme?: FormTheme;
|
|
161
|
+
client?: FilloClient;
|
|
162
|
+
children?: ReactNode;
|
|
163
|
+
}
|
|
164
|
+
declare function JsxForm(props: FilloJsxFormProps): react.JSX.Element;
|
|
165
|
+
declare function defineFormFromJsx(element: ReactElement<FilloJsxFormProps>): CodeForm;
|
|
166
|
+
declare const Fillo: {
|
|
167
|
+
readonly Form: typeof JsxForm;
|
|
168
|
+
/** Compile a <Fillo.Form> element to a CodeForm at module scope — the same
|
|
169
|
+
* value FilloProvider (headless) and the CLI consume. */
|
|
170
|
+
readonly defineForm: typeof defineFormFromJsx;
|
|
171
|
+
readonly Text: Inert<WithVisible<TextField>>;
|
|
172
|
+
readonly LongText: Inert<WithVisible<TextField>>;
|
|
173
|
+
readonly Email: Inert<WithVisible<TextField>>;
|
|
174
|
+
readonly Url: Inert<WithVisible<TextField>>;
|
|
175
|
+
readonly Phone: Inert<WithVisible<PhoneField>>;
|
|
176
|
+
readonly Number: Inert<WithVisible<NumberField>>;
|
|
177
|
+
readonly Select: Inert<ChoiceProps>;
|
|
178
|
+
readonly MultiSelect: Inert<ChoiceProps>;
|
|
179
|
+
readonly Dropdown: Inert<ChoiceProps>;
|
|
180
|
+
readonly Checkbox: Inert<WithVisible<CheckboxField>>;
|
|
181
|
+
readonly Rating: Inert<WithVisible<RatingField>>;
|
|
182
|
+
readonly Scale: Inert<WithVisible<LinearScaleField>>;
|
|
183
|
+
readonly Ranking: Inert<Omit<WithVisible<RankingField>, "options"> & {
|
|
184
|
+
options?: SelectOption[];
|
|
185
|
+
children?: ReactNode;
|
|
186
|
+
}>;
|
|
187
|
+
readonly Matrix: Inert<WithVisible<_usefillo_core.MatrixField>>;
|
|
188
|
+
readonly Signature: Inert<WithVisible<SignatureField>>;
|
|
189
|
+
readonly Date: Inert<WithVisible<DateField>>;
|
|
190
|
+
readonly FileUpload: Inert<WithVisible<FileUploadField$1>>;
|
|
191
|
+
readonly Hidden: Inert<WithVisible<HiddenField>>;
|
|
192
|
+
readonly Custom: Inert<WithVisible<CustomField>>;
|
|
193
|
+
readonly Heading: Inert<ContentProps>;
|
|
194
|
+
readonly Paragraph: Inert<ContentProps>;
|
|
195
|
+
readonly Divider: Inert<{
|
|
196
|
+
id: string;
|
|
197
|
+
}>;
|
|
198
|
+
readonly Page: Inert<{
|
|
199
|
+
id: string;
|
|
200
|
+
title?: string;
|
|
201
|
+
children?: ReactNode;
|
|
202
|
+
}>;
|
|
203
|
+
readonly Option: Inert<Omit<SelectOption, "id"> & {
|
|
204
|
+
id: string;
|
|
205
|
+
}>;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/** The raw appearance object — for renderers that resolve slots inside loops. */
|
|
209
|
+
declare function useFilloAppearance(): FilloAppearance | undefined;
|
|
210
|
+
|
|
121
211
|
interface ControllerOptions {
|
|
122
212
|
form: FormSchema;
|
|
123
213
|
formId?: string;
|
|
@@ -129,8 +219,14 @@ interface ControllerOptions {
|
|
|
129
219
|
getHoneypot?: () => string;
|
|
130
220
|
/** @internal Preview-only page navigation escape hatch. Submission still validates. */
|
|
131
221
|
skipValidation?: boolean;
|
|
132
|
-
/**
|
|
222
|
+
/**
|
|
223
|
+
* Embedding surface, recorded per response for measurement. Defaults to
|
|
224
|
+
* "headless" (your own markup), matching @usefillo/core — the framed
|
|
225
|
+
* renderers pass "default" explicitly.
|
|
226
|
+
*/
|
|
133
227
|
surface?: "default" | "headless";
|
|
228
|
+
/** Resolve the submission target at submit time when formId is still unset. */
|
|
229
|
+
resolveFormId?: () => Promise<string>;
|
|
134
230
|
}
|
|
135
231
|
/**
|
|
136
232
|
* React binding for the framework-agnostic engine in @usefillo/core
|
|
@@ -145,6 +241,10 @@ declare function useFilloController(options: ControllerOptions): FilloApi;
|
|
|
145
241
|
interface FilloProviderProps extends Omit<ControllerOptions, "form"> {
|
|
146
242
|
/** A schema, or a code-defined form from defineForm() — which also syncs. */
|
|
147
243
|
form: FormSchema | CodeForm;
|
|
244
|
+
/** Slot classes for FormField-rendered fields in your composed layout. */
|
|
245
|
+
appearance?: FilloAppearance;
|
|
246
|
+
/** Override any visitor-facing renderer string (for localized sites). */
|
|
247
|
+
strings?: Partial<FilloStrings>;
|
|
148
248
|
children: ReactNode;
|
|
149
249
|
}
|
|
150
250
|
/**
|
|
@@ -166,7 +266,7 @@ interface FilloProviderProps extends Omit<ControllerOptions, "form"> {
|
|
|
166
266
|
* defineForm() form and a keyed client, the structure also syncs into your
|
|
167
267
|
* workspace, exactly like <FilloForm>.
|
|
168
268
|
*/
|
|
169
|
-
declare function FilloProvider({ children, form, formId, client, ...options }: FilloProviderProps): react.JSX.Element;
|
|
269
|
+
declare function FilloProvider({ children, form, formId, client, appearance, strings, ...options }: FilloProviderProps): react.JSX.Element;
|
|
170
270
|
|
|
171
271
|
/**
|
|
172
272
|
* The full form engine — data, errors, pages, submit, status. Use inside a
|
|
@@ -217,4 +317,4 @@ declare function FormField({ id, components, customComponents, }: {
|
|
|
217
317
|
*/
|
|
218
318
|
declare function FileUploadField({ field, value, error, setValue, api, ids: providedIds }: FieldComponentProps): react.JSX.Element;
|
|
219
319
|
|
|
220
|
-
export { BlockRenderer, type ControllerOptions, type CustomComponents, type FieldComponentProps, type FieldComponents, type FieldHandle, type FilloApi, type FilloFieldIds, FileUploadField as FilloFileUpload, FilloForm, type FilloFormProps, FilloProvider, type FilloProviderProps, FormField, useField, useFillo, useFilloController };
|
|
320
|
+
export { BlockRenderer, type ControllerOptions, type CustomComponents, type FieldComponentProps, type FieldComponents, type FieldHandle, Fillo, type FilloApi, type FilloFieldIds, FileUploadField as FilloFileUpload, FilloForm, type FilloFormProps, type FilloJsxFormProps, FilloProvider, type FilloProviderProps, FormField, useField, useFillo, useFilloAppearance, useFilloController };
|