form-page-builder 1.0.0 → 2.1.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 +88 -2
- package/dist/index.cjs +415 -233
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -2
- package/dist/index.d.ts +46 -2
- package/dist/index.js +447 -267
- package/dist/index.js.map +1 -1
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -8,6 +8,21 @@
|
|
|
8
8
|
|
|
9
9
|
Embeddable, bilingual (EN/JA by default, extensible), drag-and-drop form builder widget for React. Ships a single `<FormBuilder />` component with a Build mode (drag/drop canvas, field inspector) and a Preview mode (responsive, validating runtime form), plus a JSON export of the resulting document.
|
|
10
10
|
|
|
11
|
+
## Examples
|
|
12
|
+
|
|
13
|
+
The [live demo](https://mainsolutioncoltd.github.io/form-page-builder/) is a gallery of six `<FormBuilder />` configurations, each showing a different realistic way to compose `features`/`theme`/`storage`/`initialDocument`/`language` — jump straight to one. Its sticky header (its headings/captions, not the widget's own EN/JA switcher) has an EN/日本語 toggle, a Light/Dark toggle that swaps every example except "Branded" (badged "Fixed theme", since its whole point is a locked theme) between `DEFAULT_THEME` and `DARK_THEME`, and links back to this repo and the npm package.
|
|
14
|
+
|
|
15
|
+
| Example | What it shows |
|
|
16
|
+
|---|---|
|
|
17
|
+
| [Full-featured](https://mainsolutioncoltd.github.io/form-page-builder/#full-featured) | No props beyond `features={{ design: true }}` — the default, everything on. |
|
|
18
|
+
| [Minimal (forms-only embed)](https://mainsolutioncoltd.github.io/form-page-builder/#minimal) | Every optional surface off, a 3-type field allowlist — stripped down for embedding inside a larger app's own chrome. |
|
|
19
|
+
| [Branded, theme locked](https://mainsolutioncoltd.github.io/form-page-builder/#branded) | A fixed `theme` plus `features.design`/`blockStyling` off — colors are locked to the brand, no styling UI exposed. |
|
|
20
|
+
| [Survey builder](https://mainsolutioncoltd.github.io/form-page-builder/#survey) | `fieldTypes`/`contentBlocks` allowlists plus `onSubmit` — a single-shape survey embed that hands you the answers. |
|
|
21
|
+
| [Locked-structure form](https://mainsolutioncoltd.github.io/form-page-builder/#locked-structure) | `initialDocument` seeds a fixed field set; structural toggles are off so only styling/labels stay editable. |
|
|
22
|
+
| [Localized (French)](https://mainsolutioncoltd.github.io/form-page-builder/#localized) | `language`/`languages`/`strings`/`chrome` — a language beyond the built-in EN/JA, partially translated. |
|
|
23
|
+
|
|
24
|
+
The source for all six lives in [dev/main.tsx](./dev/main.tsx) — `npm run dev` runs the same gallery locally against `src/` directly, and is the fastest way to try a `features`/`theme` combination before wiring it into your app.
|
|
25
|
+
|
|
11
26
|
**This is a builder + viewer, not a data handler.** It builds and previews a JSON *schema* describing a form's fields, sections, and layout blocks (including plain content blocks like paragraphs and images, not just inputs). Preview mode's "Submit" validates and shows a mock "here's what would be sent to your backend" modal, and — if you pass `onSubmit` — hands you the entered values too; either way, this package never sends or stores them itself. The only thing it persists on its own is the *builder's own* draft/Templates state (via the pluggable `StorageAdapter` below); actually delivering submissions to a backend is up to the host app.
|
|
12
27
|
|
|
13
28
|
## Install
|
|
@@ -38,12 +53,16 @@ The widget caps itself at the viewport height (`100vh`, upgrading to `100dvh` on
|
|
|
38
53
|
|
|
39
54
|
If you *do* size a wrapper to exactly `100vh`/`100dvh` and still see the page itself scroll by a few extra pixels, that's almost always the browser's default `<body>` margin (commonly `8px`) adding to that full-viewport height — reset it yourself (`body { margin: 0; }`), same as you would for any other full-height layout; this package doesn't touch your page's global styles.
|
|
40
55
|
|
|
56
|
+
### Responsive layout
|
|
57
|
+
|
|
58
|
+
Above ~720px wide, Build mode is the usual three-column Palette/Canvas/Inspector layout. Below that, Canvas becomes the full-width primary view, and Palette/Inspector become full-bleed drawers that slide over it instead of permanently eating vertical space — a small "Blocks"/"Properties" bar (reusing the same chrome labels as the desktop tabs, no separate i18n) toggles between them. Tapping a block type in the drawer adds it and returns straight to Canvas; tapping a field in Canvas opens the Properties drawer on it automatically. Nothing gets clipped by the widget's own `overflow: hidden`, and there's no horizontal scrolling. This is CSS-only (a media query in the stylesheet the widget injects) with a small bit of state driving which drawer is open, so it responds to the container's width, not a JS-measured breakpoint — useful if you're embedding it in a narrow sidebar on an otherwise-wide page. Modals size themselves as `width: 100%` up to a `max-width` (with padding around the overlay) instead of a fixed pixel width, so they never overflow a narrow viewport either.
|
|
59
|
+
|
|
41
60
|
### Props
|
|
42
61
|
|
|
43
62
|
| Prop | Type | Description |
|
|
44
63
|
|---|---|---|
|
|
45
|
-
| `theme` | `Partial<Theme>` | Override default colors/layout spacing. |
|
|
46
|
-
| `
|
|
64
|
+
| `theme` | `Partial<Theme>` | Override default colors/layout spacing — see "Features vs. theming" below. |
|
|
65
|
+
| `features` | `FormBuilderFeatures` | Independently toggle UI surfaces on/off — full-featured by default. See "Features" below. |
|
|
47
66
|
| `language` | `string` | Initial builder language (defaults to the first entry in `languages`). |
|
|
48
67
|
| `languages` | `{ code: string; label: string }[]` | Language switcher options (default: EN/JA). |
|
|
49
68
|
| `strings` | partial override of runtime/validation strings, keyed by language code | |
|
|
@@ -51,9 +70,73 @@ If you *do* size a wrapper to exactly `100vh`/`100dvh` and still see the page it
|
|
|
51
70
|
| `storage` | `StorageAdapter` | Pluggable persistence backend for the builder's own draft/Templates library — see below. |
|
|
52
71
|
| `onSubmit` | `(payload: SubmitPayload) => void` | Called when Preview mode's Submit button is clicked and validation passes — see below. |
|
|
53
72
|
| `initialDocument` | `FormDocument` | Seeds the builder with this document on mount instead of the autosaved draft — see "Programmatic integration" below. |
|
|
73
|
+
| `initialMode` | `"build" \| "preview"` | Which mode the widget mounts into (default `"build"`). Pair with `features.previewMode: false` to lock a consumer to just one mode with no tabs — e.g. a fill-only embed that never shows the Build canvas. Or leave `previewMode` on and pick `initialMode` per document (e.g. `"preview"` once a document already has saved data) so the widget opens on the right mode while still letting the built-in tabs switch it. |
|
|
74
|
+
| `onModeChange` | `(mode: "build" \| "preview") => void` | Fires on mount and on every Build/Preview toggle. Lets a host mirror the current mode (e.g. to show its own Save button only in Build mode) without building a separate tab UI around the widget. |
|
|
54
75
|
|
|
55
76
|
A `ref` on `<FormBuilder />` gives you a `FormBuilderHandle` (`getDocument()` / `loadDocument()` / `exportJson()`) — see "Programmatic integration" below.
|
|
56
77
|
|
|
78
|
+
### Features: `features`
|
|
79
|
+
|
|
80
|
+
Every optional UI surface can be switched on or off independently through one `features` prop, kept deliberately separate from `theme`/`ThemeOverrides` (which control *how* things look, not *whether* they appear). Everything defaults to `true` (`design` defaults to `false`, matching the pre-`features` default), so the default `<FormBuilder />` is unchanged and fully featured; pass only the keys you want to restrict.
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
// A forms-only embed: no title editing, no templates/JSON/preview chrome,
|
|
84
|
+
// no theming UI, and only two field types available to add.
|
|
85
|
+
<FormBuilder
|
|
86
|
+
features={{
|
|
87
|
+
naming: false,
|
|
88
|
+
templates: false,
|
|
89
|
+
newForm: false,
|
|
90
|
+
autosave: false,
|
|
91
|
+
jsonView: false,
|
|
92
|
+
previewMode: false,
|
|
93
|
+
languageSwitcher: false,
|
|
94
|
+
design: false,
|
|
95
|
+
blockStyling: false,
|
|
96
|
+
contentBlocks: false,
|
|
97
|
+
fieldTypes: ["input", "select"],
|
|
98
|
+
sections: false,
|
|
99
|
+
dragReorder: false,
|
|
100
|
+
}}
|
|
101
|
+
/>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
| Key | Type | Default | Controls |
|
|
105
|
+
|---|---|---|---|
|
|
106
|
+
| `naming` | `boolean` | `true` | The editable form-title input in the toolbar. |
|
|
107
|
+
| `templates` | `boolean` | `true` | The Templates library (browse/open/delete) and the "Save" button. |
|
|
108
|
+
| `newForm` | `boolean` | `true` | The "New Form" reset button. |
|
|
109
|
+
| `autosave` | `boolean` | `true` | Autosaving the draft to `storage`. The initial draft *load* always happens regardless — this only gates the write path. |
|
|
110
|
+
| `jsonView` | `boolean` | `true` | The "View JSON" button and modal. |
|
|
111
|
+
| `previewMode` | `boolean` | `true` | The Build/Preview tabs. When `false`, the tabs are hidden and the builder stays in whichever mode it started in (`initialMode`, Build by default). |
|
|
112
|
+
| `languageSwitcher` | `boolean` | `true` | The language-switcher pill in the toolbar. |
|
|
113
|
+
| `design` | `boolean` | `false` | The global "Design" tab (colors/spacing), i.e. the old `themeEditable` prop. |
|
|
114
|
+
| `blockStyling` | `boolean` | `true` | Per-field styling controls: paragraph heading/font/color, button color — independent of `design`. |
|
|
115
|
+
| `contentBlocks` | `boolean \| ("paragraph" \| "image" \| "button")[]` | `true` | Which content blocks can be *added* from the palette. `true` = all, `false` = none, or an allowlist. |
|
|
116
|
+
| `fieldTypes` | `boolean \| ("input" \| "textarea" \| "select" \| "radio" \| "checkboxGroup" \| "checkbox" \| "toggle")[]` | `true` | Which form field types can be *added* from the palette. `true` = all, `false` = none, or an allowlist. |
|
|
117
|
+
| `sections` | `boolean` | `true` | Add/duplicate/move/delete-section controls and the section background picker. |
|
|
118
|
+
| `dragReorder` | `boolean` | `true` | Drag-to-reorder fields within a section. |
|
|
119
|
+
| `deviceToggle` | `boolean` | `true` | The Laptop/Tablet/Mobile width switcher above the Preview canvas. When `false`, Preview always renders at the Laptop (full) width. |
|
|
120
|
+
| `maxFields` | `number` | `undefined` (unlimited) | Caps the total number of input-type fields (not content blocks) addable across the whole document. Once reached, the Form Fields palette buttons disable until a field is removed. |
|
|
121
|
+
|
|
122
|
+
Disabling `contentBlocks`/`fieldTypes` for a given type only hides it from the palette going forward — if a document loaded via `initialDocument` (or a saved template) already contains fields of a now-disabled type, they still render and remain editable in Build mode; nothing is stripped or hidden.
|
|
123
|
+
|
|
124
|
+
### Features vs. theming
|
|
125
|
+
|
|
126
|
+
`features` and `theme` are separate, composable concerns: `features.design` decides whether the Design tab's color/spacing *controls* are shown at all, while `theme` (and the Design tab, when shown) decide what those colors/spacing values *are*. You can, for instance, pass a fixed `theme` with `features.design` and `features.blockStyling` both `false` to lock a form to your brand's colors with zero styling UI exposed to the builder's user.
|
|
127
|
+
|
|
128
|
+
### Dark theme
|
|
129
|
+
|
|
130
|
+
Every color in the widget — including modals, toggles, and badges, not just the canvas/toolbar — is driven by the `theme` prop via CSS custom properties, so dark mode is just a different set of color values, no separate "dark mode" flag needed:
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { FormBuilder, DARK_THEME } from "form-page-builder";
|
|
134
|
+
|
|
135
|
+
<FormBuilder theme={DARK_THEME} />;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`DARK_THEME` (and `DEFAULT_THEME`, the light palette used when `theme` is omitted) are both exported as plain `Theme` objects, so you can spread and tweak either one (`{ ...DARK_THEME, primary: "#22c55e" }`) or swap between them at runtime for a user-facing light/dark toggle — see the "Localized (French)"-adjacent light/Dark switch in the [live demo](https://mainsolutioncoltd.github.io/form-page-builder/) for a working example.
|
|
139
|
+
|
|
57
140
|
### Persistence: `StorageAdapter`
|
|
58
141
|
|
|
59
142
|
By default the component autosaves a draft, plus a "Templates" library (up to 5 saved forms, shown via the toolbar's Templates button), to `window.localStorage`. Being local-storage-only means neither persists across devices or browsers. To persist the builder's state to your own backend (a Next.js API route, a PHP endpoint, etc.) instead — so drafts and templates are shared across devices, and your backend can populate/manage the template list itself — implement and pass a `StorageAdapter`. Its `get`/`set`/`delete` calls *are* the create/update/delete hooks: whatever your implementation does inside them (write to a database, call your API) runs on every template save/update/delete, so no separate event callbacks are needed.
|
|
@@ -183,10 +266,13 @@ The `?external=react,react-dom` query on the `form-page-builder` import tells es
|
|
|
183
266
|
npm install
|
|
184
267
|
npm run dev # Vite dev harness at http://localhost:5173, imports FormBuilder from src/
|
|
185
268
|
npm run typecheck
|
|
269
|
+
npm run test # vitest run -- see tests/
|
|
186
270
|
npm run build # tsup -> dist/ (ESM + CJS + .d.ts), the published package
|
|
187
271
|
npm run build:demo # vite build -> pages-dist/, the GitHub Pages demo site
|
|
188
272
|
```
|
|
189
273
|
|
|
274
|
+
Tests use [Vitest](https://vitest.dev) + [Testing Library](https://testing-library.com/react) against jsdom, covering rendering, the `features` prop's gating of each UI surface, the `FormBuilderHandle` ref API, autosave/`initialDocument`, and the Preview-mode validation + `onSubmit` flow. `npm run test:watch` re-runs on change.
|
|
275
|
+
|
|
190
276
|
## Releasing
|
|
191
277
|
|
|
192
278
|
Versioning and the changelog are managed by [Changesets](https://github.com/changesets/changesets); publishing to npm is a separate, deliberate step.
|