@usefillo/react 0.2.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/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/index.d.ts +172 -0
- package/dist/index.js +1094 -0
- package/dist/styles.css +382 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fillo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @usefillo/react
|
|
2
|
+
|
|
3
|
+
Headless 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
|
+
|
|
5
|
+
### 📚 Full documentation → **[fillo.so/docs](https://fillo.so/docs)**
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm i @usefillo/react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`react` and `react-dom` (18 or 19) are peer dependencies.
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { FilloForm, createClient } from "@usefillo/react";
|
|
15
|
+
import "@usefillo/react/styles.css"; // optional default theme — or bring your own
|
|
16
|
+
|
|
17
|
+
const client = createClient({ baseUrl: "https://fillo.so" });
|
|
18
|
+
|
|
19
|
+
export function Feedback() {
|
|
20
|
+
return <FilloForm client={client} formId="cust-feedback" onSubmitted={(r) => confetti()} />;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Every part is replaceable. Pass your own field components, theme the form via the `theme` prop, or drop down to the hooks and own the entire render:
|
|
25
|
+
|
|
26
|
+
- `<FilloForm>` / `<FilloProvider>` — render a form, or wrap your own layout
|
|
27
|
+
- `useFillo()` / `useField()` — build a fully custom UI against form state
|
|
28
|
+
- `useFilloController()` — headless controller for total control
|
|
29
|
+
- `FormField` / `BlockRenderer` — render individual blocks
|
|
30
|
+
- `defineForm()` — author a form in code and sync it to your workspace on first run
|
|
31
|
+
|
|
32
|
+
This package re-exports the embedding surface from [`@usefillo/core`](https://www.npmjs.com/package/@usefillo/core) (`createClient`, `FormSchema`, `FormTheme`, …) so a single import is usually enough.
|
|
33
|
+
|
|
34
|
+
## Links
|
|
35
|
+
|
|
36
|
+
- **Docs:** [fillo.so/docs](https://fillo.so/docs)
|
|
37
|
+
- **Website:** [fillo.so](https://fillo.so)
|
|
38
|
+
|
|
39
|
+
MIT licensed.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentType, ReactNode } from 'react';
|
|
3
|
+
import { FormSchema, FilloClient, ResponseData, FieldValue, FormPage, Block, FormStatus, FieldKind, Field, CodeForm, FormTheme, FilloError } from '@usefillo/core';
|
|
4
|
+
export { CodeForm, Field, FieldValue, FileValue, FilloClient, FilloError, FormSchema, FormStatus, FormTheme, PublishedForm, ResponseData, createClient, defineForm } from '@usefillo/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Everything a custom renderer needs. Returned by useFillo() and provided
|
|
8
|
+
* to every field component — the default ones and yours.
|
|
9
|
+
*/
|
|
10
|
+
interface FilloApi {
|
|
11
|
+
form: FormSchema;
|
|
12
|
+
formId?: string;
|
|
13
|
+
client?: FilloClient;
|
|
14
|
+
data: ResponseData;
|
|
15
|
+
errors: Record<string, string>;
|
|
16
|
+
setValue: (fieldId: string, value: FieldValue) => void;
|
|
17
|
+
pageIndex: number;
|
|
18
|
+
pageCount: number;
|
|
19
|
+
page: FormPage;
|
|
20
|
+
/** Blocks on the current page after visibility logic. */
|
|
21
|
+
blocks: Block[];
|
|
22
|
+
isFirstPage: boolean;
|
|
23
|
+
isLastPage: boolean;
|
|
24
|
+
next: () => void;
|
|
25
|
+
back: () => void;
|
|
26
|
+
submit: () => Promise<void>;
|
|
27
|
+
status: FormStatus;
|
|
28
|
+
/** True while any file upload is in flight — submit is blocked. */
|
|
29
|
+
uploading: boolean;
|
|
30
|
+
/** Used by upload fields to gate submission. */
|
|
31
|
+
setUploading: (fieldId: string, busy: boolean) => void;
|
|
32
|
+
}
|
|
33
|
+
interface FieldComponentProps {
|
|
34
|
+
field: Field;
|
|
35
|
+
value: FieldValue;
|
|
36
|
+
error: string | undefined;
|
|
37
|
+
setValue: (value: FieldValue) => void;
|
|
38
|
+
api: FilloApi;
|
|
39
|
+
}
|
|
40
|
+
/** Per-kind component overrides — swap any built-in field for your own. */
|
|
41
|
+
type FieldComponents = Partial<Record<FieldKind, ComponentType<FieldComponentProps>>>;
|
|
42
|
+
/**
|
|
43
|
+
* Renderers for your own field kinds, keyed by a custom field's `component`.
|
|
44
|
+
* A block `{ kind: "custom", component: "color", config: {...} }` renders
|
|
45
|
+
* `customComponents.color`. The component reads `field.config` for options.
|
|
46
|
+
*/
|
|
47
|
+
type CustomComponents = Record<string, ComponentType<FieldComponentProps>>;
|
|
48
|
+
|
|
49
|
+
interface FilloFormProps {
|
|
50
|
+
/** Render a schema directly, or a code-defined form from defineForm(). */
|
|
51
|
+
form?: FormSchema | CodeForm;
|
|
52
|
+
/** Or fetch it: a client plus the form id/slug. */
|
|
53
|
+
client?: FilloClient;
|
|
54
|
+
formId?: string;
|
|
55
|
+
theme?: FormTheme;
|
|
56
|
+
/** Swap any built-in field kind for your own component. */
|
|
57
|
+
components?: FieldComponents;
|
|
58
|
+
/** Renderers for your own `custom` field kinds, keyed by `component`. */
|
|
59
|
+
customComponents?: CustomComponents;
|
|
60
|
+
initialData?: ResponseData;
|
|
61
|
+
onChange?: (data: ResponseData) => void;
|
|
62
|
+
onSubmitted?: (responseId: string | undefined, data: ResponseData) => void;
|
|
63
|
+
/** Take over submission entirely (instead of the client). */
|
|
64
|
+
onSubmit?: (data: ResponseData) => Promise<void> | void;
|
|
65
|
+
/** Observe load and code-form sync failures (otherwise only logged). */
|
|
66
|
+
onError?: (error: FilloError) => void;
|
|
67
|
+
/**
|
|
68
|
+
* Render the form's own title/description header (default true). Set false
|
|
69
|
+
* when the embedding page already provides a heading, to avoid a second
|
|
70
|
+
* page-level `<h1>`.
|
|
71
|
+
*/
|
|
72
|
+
showTitle?: boolean;
|
|
73
|
+
/** Custom success screen. */
|
|
74
|
+
renderSuccess?: () => ReactNode;
|
|
75
|
+
/** Custom error screen — receives the failure (e.g. 404 vs network). */
|
|
76
|
+
renderError?: (error: FilloError) => ReactNode;
|
|
77
|
+
className?: string;
|
|
78
|
+
}
|
|
79
|
+
declare function FilloForm(props: FilloFormProps): react.JSX.Element;
|
|
80
|
+
|
|
81
|
+
interface ControllerOptions {
|
|
82
|
+
form: FormSchema;
|
|
83
|
+
formId?: string;
|
|
84
|
+
client?: FilloClient;
|
|
85
|
+
initialData?: ResponseData;
|
|
86
|
+
onChange?: (data: ResponseData) => void;
|
|
87
|
+
onSubmitted?: (responseId: string | undefined, data: ResponseData) => void;
|
|
88
|
+
/** Custom submit handler — used instead of the client when provided. */
|
|
89
|
+
onSubmit?: (data: ResponseData) => Promise<void> | void;
|
|
90
|
+
/** Anti-spam signals provided by the renderer (honeypot value). */
|
|
91
|
+
getHoneypot?: () => string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* React binding for the framework-agnostic engine in @usefillo/core
|
|
95
|
+
* (createFormController). The engine owns all state and logic — validation,
|
|
96
|
+
* conditional visibility, paging, spam signals, submission, funnel tracking.
|
|
97
|
+
* This wraps it with useSyncExternalStore and keeps the latest callbacks and
|
|
98
|
+
* submit context wired in, so React, the DOM renderer, and the headless API all
|
|
99
|
+
* share one implementation.
|
|
100
|
+
*/
|
|
101
|
+
declare function useFilloController(options: ControllerOptions): FilloApi;
|
|
102
|
+
|
|
103
|
+
interface FilloProviderProps extends Omit<ControllerOptions, "form"> {
|
|
104
|
+
/** A schema, or a code-defined form from defineForm() — which also syncs. */
|
|
105
|
+
form: FormSchema | CodeForm;
|
|
106
|
+
children: ReactNode;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The headless escape hatch. Sets up the form engine (validation, conditional
|
|
110
|
+
* logic, uploads, submit) and renders **no layout at all** — you compose the
|
|
111
|
+
* entire form yourself with <FormField>, useField() and useFillo(),
|
|
112
|
+
* interleaving any markup of your own between fields.
|
|
113
|
+
*
|
|
114
|
+
* <FilloProvider form={feedback} client={client}>
|
|
115
|
+
* <YourErrorContext />
|
|
116
|
+
* <FormField id="reason" />
|
|
117
|
+
* <p>We read every report.</p>
|
|
118
|
+
* <FormField id="email" />
|
|
119
|
+
* <MySubmitButton /> // calls useFillo().submit()
|
|
120
|
+
* </FilloProvider>
|
|
121
|
+
*
|
|
122
|
+
* The schema stays the source of truth — render every required field, or
|
|
123
|
+
* submission will fail validation on a field the visitor can't see. With a
|
|
124
|
+
* defineForm() form and a keyed client, the structure also syncs into your
|
|
125
|
+
* workspace, exactly like <FilloForm>.
|
|
126
|
+
*/
|
|
127
|
+
declare function FilloProvider({ children, form, formId, client, ...options }: FilloProviderProps): react.JSX.Element;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The full form engine — data, errors, pages, submit, status. Use inside a
|
|
131
|
+
* <FilloForm> or <FilloProvider> to build completely custom layouts.
|
|
132
|
+
*/
|
|
133
|
+
declare function useFillo(): FilloApi;
|
|
134
|
+
interface FieldHandle {
|
|
135
|
+
/** The field's schema entry, or undefined if no field has this id. */
|
|
136
|
+
field: Field | undefined;
|
|
137
|
+
value: FieldValue;
|
|
138
|
+
error: string | undefined;
|
|
139
|
+
setValue: (value: FieldValue) => void;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Drive a single field by id — render it however you like, wherever you like.
|
|
143
|
+
* The engine still validates it, runs logic and handles submit. This is the
|
|
144
|
+
* lowest-level hook: with it you owe Fillo nothing but the field id.
|
|
145
|
+
*/
|
|
146
|
+
declare function useField(fieldId: string): FieldHandle;
|
|
147
|
+
|
|
148
|
+
declare function BlockRenderer({ block, api, components, customComponents, }: {
|
|
149
|
+
block: Block;
|
|
150
|
+
api: FilloApi;
|
|
151
|
+
components?: FieldComponents;
|
|
152
|
+
customComponents?: CustomComponents;
|
|
153
|
+
}): react.JSX.Element | null;
|
|
154
|
+
/**
|
|
155
|
+
* Render a single field by id using the default (or overridden) component —
|
|
156
|
+
* drop it anywhere inside a <FilloProvider> to place fields in your own
|
|
157
|
+
* layout. For total control over the markup, use the useField() hook instead.
|
|
158
|
+
*/
|
|
159
|
+
declare function FormField({ id, components, customComponents, }: {
|
|
160
|
+
id: string;
|
|
161
|
+
components?: FieldComponents;
|
|
162
|
+
customComponents?: CustomComponents;
|
|
163
|
+
}): react.JSX.Element | null;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Default file upload field: drag & drop, resumable chunked uploads with live
|
|
167
|
+
* progress, multiple files. Replace it entirely via the `components` prop if
|
|
168
|
+
* you want your own — completed uploads are just FileValue[] in the data.
|
|
169
|
+
*/
|
|
170
|
+
declare function FileUploadField({ field, value, error, setValue, api }: FieldComponentProps): react.JSX.Element;
|
|
171
|
+
|
|
172
|
+
export { BlockRenderer, type ControllerOptions, type CustomComponents, type FieldComponentProps, type FieldComponents, type FieldHandle, type FilloApi, FileUploadField as FilloFileUpload, FilloForm, type FilloFormProps, FilloProvider, type FilloProviderProps, FormField, useField, useFillo, useFilloController };
|