reactaform 1.8.1 → 1.8.2
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 +247 -379
- package/dist/{common-DnEDu-7h.mjs → common-B4FQDljX.mjs} +8 -19
- package/dist/common-BeQ3x_ll.js +1 -0
- package/dist/common-C9xi6Anp.js +1 -0
- package/dist/{common-CsY8BnXg.mjs → common-CCGIMXY_.mjs} +7 -19
- package/dist/common-CiL5z7rS.js +1 -0
- package/dist/{common-BZgeDhcm.mjs → common-Dd94fy-Y.mjs} +2 -11
- package/dist/{common-CBecOKIA.mjs → common-Ws7ob6hh.mjs} +3 -14
- package/dist/common-pqSYL5rx.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/reactaform.cjs.js +5 -5
- package/dist/reactaform.es.js +821 -784
- package/dist/utils/translationCache.d.ts +8 -0
- package/package.json +1 -1
- package/dist/common-Awfy-0XP.js +0 -1
- package/dist/common-BmlrZtLZ.js +0 -1
- package/dist/common-D8L4oP0c.js +0 -1
- package/dist/common-udunqMU-.js +0 -1
package/README.md
CHANGED
|
@@ -1,465 +1,333 @@
|
|
|
1
1
|
# ReactaForm
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Build dynamic React forms visually — no JSX, no boilerplate.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**ReactaForm is a dynamic, schema-driven form platform for React, built for visual workflows.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Design forms using the drag-and-drop builder or JSON schemas, render them instantly, and scale complex, configurable UIs without rewriting JSX.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
✨ Visual Builder included
|
|
10
|
+
✨ TypeScript-first
|
|
11
|
+
✨ Themeable & extensible
|
|
12
|
+
✨ Designed for dynamic, backend-driven UIs
|
|
13
|
+
✨ Optimized performance dynamic forms — fast, predictable rendering.
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
- **
|
|
14
|
-
- **Visual Form Builder** — Design forms visually with drag-and-drop at [reactaform.vercel.app/builder](https://reactaform.vercel.app/builder) and export production-ready schemas instantly.
|
|
15
|
+
🌐 **Documentation & Demos**
|
|
16
|
+
- https://reactaform.vercel.app
|
|
17
|
+
- **Builder:** https://reactaform.vercel.app/builder
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- **Themeable via CSS Variables** — Customize colors, spacing, borders, typography, and support light/dark modes.
|
|
19
|
-
- **Component Registry** — Register custom field components.
|
|
20
|
-
|
|
21
|
-
### 🧠 Logic & Validation
|
|
22
|
-
|
|
23
|
-
- **Custom Validation System** — Register validators globally or per field.
|
|
24
|
-
- **Conditional Logic** — Show or hide fields dynamically based on parent values.
|
|
25
|
-
|
|
26
|
-
### 🌍 Internationalization
|
|
27
|
-
|
|
28
|
-
- **Built-In Multi-Language Support** — i18n with translation caching for fast rendering.
|
|
29
|
-
|
|
30
|
-
### ⚡ Performance & UX
|
|
31
|
-
|
|
32
|
-
- **Optimized Input Handling** — Debounced updates + requestAnimationFrame-driven state management.
|
|
33
|
-
- **Accessible by Default** — ARIA attributes, keyboard navigation, and focus management.
|
|
34
|
-
|
|
35
|
-
### 🔌 Flexible Submission Flow
|
|
36
|
-
|
|
37
|
-
- **Custom Submission Handlers** — Integrate any workflow, API, or async logic.
|
|
38
|
-
|
|
39
|
-
## 📦 Installation
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
npm install reactaform react react-dom
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
**Peer Dependencies:**
|
|
46
|
-
|
|
47
|
-
- React `^18.0.0 || ^19.0.0`
|
|
48
|
-
- React-DOM `^18.0.0 || ^19.0.0`
|
|
49
|
-
|
|
50
|
-
## 🌐 Environment Compatibility
|
|
51
|
-
|
|
52
|
-
ReactaForm works seamlessly with:
|
|
53
|
-
|
|
54
|
-
- Vite (recommended)
|
|
55
|
-
- Webpack / CRA
|
|
56
|
-
- Next.js
|
|
57
|
-
- Parcel, esbuild, Rollup
|
|
58
|
-
|
|
59
|
-
The library intelligently handles `import.meta.env` and `process.env` with automatic fallbacks—no config tweaks required.
|
|
19
|
+
---
|
|
60
20
|
|
|
61
|
-
##
|
|
21
|
+
## Table of Contents
|
|
62
22
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
23
|
+
- [Why ReactaForm?](#why-reactaform)
|
|
24
|
+
- [ReactaForm Builder](#reactaform-builder)
|
|
25
|
+
- [Key Features](#key-features)
|
|
26
|
+
- [Installation](#installation)
|
|
27
|
+
- [Quick Start](#quick-start)
|
|
28
|
+
- [Conditional Logic](#conditional-logic)
|
|
29
|
+
- [Validation and Validators](#validation-and-validators)
|
|
30
|
+
- [Documentation](#documentation)
|
|
31
|
+
- [Roadmap](#roadmap)
|
|
32
|
+
- [Contributing](#contributing)
|
|
33
|
+
- [License](#license)
|
|
66
34
|
|
|
67
|
-
// Define definition, can be load from server
|
|
68
|
-
const definition = {
|
|
69
|
-
name: "contactForm",
|
|
70
|
-
version: "1.0",
|
|
71
|
-
displayName: "Contact Form",
|
|
72
|
-
properties: [
|
|
73
|
-
{ name: "fullName", displayName: "Full Name", type: "string", required: true },
|
|
74
|
-
{ name: "email", displayName: "Email", type: "email", required: true },
|
|
75
|
-
{ name: "message", displayName: "Message", type: "text", required: true }
|
|
76
|
-
]
|
|
77
|
-
};
|
|
78
35
|
|
|
79
|
-
|
|
80
|
-
const result = createInstanceFromDefinition(definition, "myForm");
|
|
81
|
-
const [instance] = useState(result.instance);
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<ReactaForm
|
|
85
|
-
definitionData={definition}
|
|
86
|
-
instance={instance}
|
|
87
|
-
language="en"
|
|
88
|
-
/>
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
```
|
|
36
|
+
## <a id="why-reactaform"></a> 🤔 Why ReactaForm?
|
|
92
37
|
|
|
93
|
-
|
|
38
|
+
Most React form libraries assume your form structure is **static JSX**.
|
|
94
39
|
|
|
95
|
-
|
|
40
|
+
ReactaForm is built for cases where forms are:
|
|
41
|
+
- Generated from backend data
|
|
42
|
+
- Configurable at runtime
|
|
43
|
+
- Built visually (low-code / no-code)
|
|
44
|
+
- Shared across multiple apps
|
|
45
|
+
- Highly customizable and themeable
|
|
96
46
|
|
|
97
|
-
|
|
47
|
+
### Comparison
|
|
98
48
|
|
|
99
|
-
|
|
49
|
+
| Feature | React Hook Form | Formik | ReactaForm |
|
|
50
|
+
|------|------|------|------|
|
|
51
|
+
| JSX required | ✔ | ✔ | ❌ |
|
|
52
|
+
| Schema-driven | ❌ | ❌ | ✔ |
|
|
53
|
+
| Runtime dynamic forms | ⚠️ | ⚠️ | ✔ |
|
|
54
|
+
| Visual form builder | ❌ | ❌ | ✔ |
|
|
55
|
+
| Built-in theming | ❌ | ⚠️ | ✔ |
|
|
56
|
+
| Plugin architecture | ❌ | ❌ | ✔ |
|
|
57
|
+
| Backend-driven UI | ❌ | ❌ | ✔ |
|
|
100
58
|
|
|
101
|
-
|
|
102
|
-
, you can:
|
|
59
|
+
---
|
|
103
60
|
|
|
104
|
-
|
|
105
|
-
- See Results Instantly — Real-time previews ensure your form behaves exactly as expected while you design
|
|
106
|
-
- Reuse & Iterate Easily — Import existing form definitions, make changes visually, and re-export in seconds
|
|
107
|
-
- Ship Production-Ready Schemas — Export clean, validated JSON definitions ready to plug directly into ReactaForm
|
|
108
|
-
- Reduce Errors — Configure validation, conditional logic, and styling visually to avoid schema mistakes
|
|
109
|
-
- Start with Confidence — Use built-in templates to jump-start common form use cases
|
|
61
|
+
## <a id="reactaform-builder"></a> 🏗 ReactaForm Builder
|
|
110
62
|
|
|
111
|
-
|
|
63
|
+
Visual drag-and-drop builder for creating dynamic forms:
|
|
112
64
|
|
|
113
|
-
|
|
65
|
+
<img src="./docs/assets/images/builder_ui.jpg" alt="ReactaForm Builder Screenshot" width="900" style="max-width:100%;height:auto;display:block;margin:0.5rem auto;" />
|
|
114
66
|
|
|
115
|
-
|
|
67
|
+
## <a id="key-features"></a> ✨ Key Features
|
|
116
68
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
properties: FieldDefinition[];
|
|
123
|
-
}
|
|
124
|
-
```
|
|
69
|
+
### 🔧 Core
|
|
70
|
+
- Schema-driven form rendering
|
|
71
|
+
- 20+ built-in field types
|
|
72
|
+
- Automatic state management
|
|
73
|
+
- Full TypeScript support
|
|
125
74
|
|
|
126
|
-
###
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
| `color` | Color picker |
|
|
132
|
-
| `date` | Date Picker |
|
|
133
|
-
| `dropdown` | Select menu |
|
|
134
|
-
| `email` | Email input |
|
|
135
|
-
| `file` | File selection |
|
|
136
|
-
| `float` | Float input |
|
|
137
|
-
| `float-array` | Float array input |
|
|
138
|
-
| `image` | Image preview |
|
|
139
|
-
| `int-array`| Integer array input |
|
|
140
|
-
| `int` | Integer input |
|
|
141
|
-
| `multi-selection` | Multiple selection |
|
|
142
|
-
| `password` | Password input |
|
|
143
|
-
| `phone` | Phone number input |
|
|
144
|
-
| `radio` | Radio button group |
|
|
145
|
-
| `rating` | Star rating |
|
|
146
|
-
| `slider` | Range slider |
|
|
147
|
-
| `switch` | Boolean |
|
|
148
|
-
| `text` | Single line input |
|
|
149
|
-
| `time` | Time input |
|
|
150
|
-
| `unitValue` | Value + unit conversion |
|
|
151
|
-
| `url` | URL input |
|
|
152
|
-
|
|
153
|
-
### 🎭 Conditional Visibility
|
|
75
|
+
### 🛠 Visual Form Builder
|
|
76
|
+
- Drag-and-drop form creation
|
|
77
|
+
- Live preview
|
|
78
|
+
- Validation & conditional logic
|
|
79
|
+
- Export production-ready JSON schemas
|
|
154
80
|
|
|
155
|
-
|
|
156
|
-
{
|
|
157
|
-
"name": "country",
|
|
158
|
-
"displayName": "Country",
|
|
159
|
-
"type": "dropdown",
|
|
160
|
-
"options": [
|
|
161
|
-
{ "label": "United States", "value": "US" },
|
|
162
|
-
{ "label": "Canada", "value": "CA" }
|
|
163
|
-
]
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
"name": "state",
|
|
167
|
-
"displayName": "State",
|
|
168
|
-
"type": "dropdown",
|
|
169
|
-
"parents": { "country": ["US"] }
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
"name": "province",
|
|
173
|
-
"displayName": "Province",
|
|
174
|
-
"type": "dropdown",
|
|
175
|
-
"parents": { "country": ["CA"] }
|
|
176
|
-
}
|
|
81
|
+
👉 https://reactaform.vercel.app/builder
|
|
177
82
|
|
|
178
|
-
|
|
83
|
+
### 🎨 Theming
|
|
84
|
+
- CSS-variable-based themes
|
|
85
|
+
- Light & dark modes
|
|
86
|
+
- 20+ built-in themes
|
|
179
87
|
|
|
180
|
-
###
|
|
88
|
+
### 🧠 Logic & Validation
|
|
89
|
+
- Conditional visibility
|
|
90
|
+
- Custom validators
|
|
91
|
+
- Custom submission handlers
|
|
92
|
+
|
|
93
|
+
### 🔌 Extensibility
|
|
94
|
+
- Component registry
|
|
95
|
+
- Plugin system
|
|
96
|
+
- Custom fields and workflows
|
|
97
|
+
|
|
98
|
+
### 🌍 i18n
|
|
99
|
+
- Built-in multi-language support
|
|
100
|
+
- Translation caching
|
|
101
|
+
- Support custom per-form translation dictionaries for user defined translation.
|
|
102
|
+
|
|
103
|
+
### ⚡ Performance & Accessibility
|
|
104
|
+
- Fast initial load via incremental (chunked) mounting.
|
|
105
|
+
- Efficient updates using requestAnimationFrame batching and targeted visibility recomputation.
|
|
106
|
+
- Reduced input overhead with debounced callbacks for expensive handlers.
|
|
107
|
+
- ARIA-compliant by default
|
|
181
108
|
|
|
182
|
-
|
|
183
|
-
{
|
|
184
|
-
"name": "email",
|
|
185
|
-
"displayName": "Email",
|
|
186
|
-
"type": "email",
|
|
187
|
-
"required": true,
|
|
188
|
-
"pattern": "^[a-z]+$",
|
|
189
|
-
"minLength": 5,
|
|
190
|
-
"maxLength": 100
|
|
191
|
-
}
|
|
192
|
-
```
|
|
109
|
+
---
|
|
193
110
|
|
|
194
|
-
##
|
|
111
|
+
## 👥 Who Is ReactaForm For?
|
|
195
112
|
|
|
196
|
-
|
|
113
|
+
- SaaS settings pages
|
|
114
|
+
- Admin dashboards
|
|
115
|
+
- Product configurators
|
|
116
|
+
- CMS-driven forms
|
|
117
|
+
- Low-code tools
|
|
118
|
+
- Enterprise dynamic UIs
|
|
197
119
|
|
|
198
|
-
|
|
120
|
+
---
|
|
199
121
|
|
|
200
|
-
|
|
201
|
-
// Import a theme
|
|
202
|
-
import 'reactaform/themes/material.css';
|
|
203
|
-
import { ReactaForm } from 'reactaform';
|
|
122
|
+
## <a id="installation"></a> 📦 Installation
|
|
204
123
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
124
|
+
```bash
|
|
125
|
+
npm install reactaform
|
|
208
126
|
```
|
|
209
127
|
|
|
210
|
-
|
|
128
|
+
**Peer Dependencies**
|
|
129
|
+
- React ^18 || ^19
|
|
130
|
+
- React-DOM ^18 || ^19
|
|
211
131
|
|
|
212
|
-
|
|
213
|
-
- `material`, `ant-design`, `blueprint`, `fluent`, `shadcn`, `tailwind`
|
|
214
|
-
- `modern-light`, `macos-native`, `ios-mobile`, `soft-pastel`
|
|
215
|
-
- `glass-morphism`, `high-contrast-accessible`
|
|
216
|
-
|
|
217
|
-
**Dark Themes:**
|
|
218
|
-
- `material-dark`, `ant-design-dark`, `blueprint-dark`, `tailwind-dark`
|
|
219
|
-
- `midnight-dark`, `neon-cyber-dark`
|
|
220
|
-
|
|
221
|
-
**Variants:**
|
|
222
|
-
- `compact-variant`, `spacious-variant` (size adjustments)
|
|
132
|
+
---
|
|
223
133
|
|
|
224
|
-
|
|
134
|
+
## <a id="quick-start"></a> 🚀 Quick Start
|
|
225
135
|
|
|
226
136
|
```tsx
|
|
227
|
-
import 'reactaform/themes/material.css';
|
|
228
|
-
import 'reactaform/themes/material-dark.css';
|
|
229
137
|
import { ReactaForm } from 'reactaform';
|
|
230
|
-
import { useState } from 'react';
|
|
231
|
-
|
|
232
|
-
function App() {
|
|
233
|
-
const [isDark, setIsDark] = useState(false);
|
|
234
|
-
|
|
235
|
-
return (
|
|
236
|
-
<>
|
|
237
|
-
<button onClick={() => setIsDark(!isDark)}>Toggle Theme</button>
|
|
238
|
-
<ReactaForm
|
|
239
|
-
theme={isDark ? 'material-dark' : 'material'}
|
|
240
|
-
definitionData={...}
|
|
241
|
-
/>
|
|
242
|
-
</>
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### Custom Theme
|
|
248
138
|
|
|
249
|
-
|
|
139
|
+
const definition = {
|
|
140
|
+
name: "simpleForm",
|
|
141
|
+
displayName: "Simple Form",
|
|
142
|
+
properties: [
|
|
143
|
+
{ name: "email", type: "email", required: true }
|
|
144
|
+
]
|
|
145
|
+
};
|
|
250
146
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
--reactaform-primary-bg: #ffffff;
|
|
254
|
-
--reactaform-secondary-bg: #f9f9f9;
|
|
255
|
-
--reactaform-text-color: #000000;
|
|
256
|
-
--reactaform-border-color: #cccccc;
|
|
257
|
-
--reactaform-border-radius: 8px;
|
|
258
|
-
/* ... see theme files for all variables */
|
|
147
|
+
export default function App() {
|
|
148
|
+
return <ReactaForm definitionData={definition} />;
|
|
259
149
|
}
|
|
260
150
|
```
|
|
261
151
|
|
|
262
|
-
|
|
263
|
-
<ReactaForm theme="my-custom" definitionData={...} />
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
**Dark Theme Convention:** Include "dark" in your theme name (e.g., `my-custom-dark`) for automatic dark mode detection.
|
|
267
|
-
|
|
268
|
-
### Detect Dark Themes
|
|
269
|
-
|
|
270
|
-
```tsx
|
|
271
|
-
import { isDarkTheme } from 'reactaform';
|
|
272
|
-
|
|
273
|
-
isDarkTheme('material-dark'); // true
|
|
274
|
-
isDarkTheme('material'); // false
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
📖 **Full theme documentation:** [docs/theme-integration.md](docs/theme-integration.md)
|
|
152
|
+
## <a id="conditional-logic"></a> 🎭 Conditional Logic
|
|
278
153
|
|
|
279
|
-
|
|
154
|
+
Dynamically show or hide individual fields or groups based on parent–child rules or group conditions.
|
|
280
155
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### Custom Translations
|
|
156
|
+
Parent–child example (schema fragment):
|
|
157
|
+
Parents are defined in the parents field by specifying the parent field name and the corresponding values.
|
|
286
158
|
|
|
287
159
|
```json
|
|
288
|
-
// public/locales/fr/myform.json
|
|
289
160
|
{
|
|
290
|
-
"
|
|
291
|
-
|
|
161
|
+
"properties": [
|
|
162
|
+
{
|
|
163
|
+
"name": "country",
|
|
164
|
+
"displayName": "Country",
|
|
165
|
+
"type": "dropdown",
|
|
166
|
+
"options": [
|
|
167
|
+
{ "label": "United States", "value": "US" },
|
|
168
|
+
{ "label": "Canada", "value": "CA" }
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"name": "state",
|
|
173
|
+
"displayName": "State",
|
|
174
|
+
"type": "dropdown",
|
|
175
|
+
"parents": { "country": ["US"] }
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"name": "province",
|
|
179
|
+
"displayName": "Province",
|
|
180
|
+
"type": "dropdown",
|
|
181
|
+
"parents": { "country": ["CA"] }
|
|
182
|
+
}
|
|
183
|
+
]
|
|
292
184
|
}
|
|
293
185
|
```
|
|
294
186
|
|
|
187
|
+
### Group support
|
|
295
188
|
|
|
296
|
-
|
|
189
|
+
Groups let you treat multiple fields as a unit and control the group's visibility with group name defined in field. Consecutive fields with same group name will be grouped while non consecutive fields with same group name are treated as different groups.
|
|
297
190
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
```tsx
|
|
301
|
-
import { registerComponent } from 'reactaform';
|
|
302
|
-
|
|
303
|
-
const CustomInput = ({ value, onChange, field }) => (
|
|
304
|
-
<input
|
|
305
|
-
value={value}
|
|
306
|
-
placeholder={field.displayName}
|
|
307
|
-
onChange={(e) => onChange(e.target.value, null)}
|
|
308
|
-
/>
|
|
309
|
-
);
|
|
310
|
-
|
|
311
|
-
registerComponent("customType", CustomInput);
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### Custom Validation
|
|
315
|
-
|
|
316
|
-
```tsx
|
|
317
|
-
import { registerValidationHandler } from 'reactaform';
|
|
191
|
+
Example — `Address` group contains `address1` and `address2`
|
|
318
192
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
{
|
|
196
|
+
"type": "text",
|
|
197
|
+
"name": "address1",
|
|
198
|
+
"displayName": "Address Line 1",
|
|
199
|
+
"defaultValue": "",
|
|
200
|
+
"group": "Address"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"type": "text",
|
|
204
|
+
"name": "address2",
|
|
205
|
+
"displayName": "Address Line 2",
|
|
206
|
+
"defaultValue": "",
|
|
207
|
+
"group": "Address"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
322
210
|
```
|
|
323
211
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
```tsx
|
|
327
|
-
import { registerSubmissionHandler } from 'reactaform';
|
|
212
|
+
---
|
|
328
213
|
|
|
329
|
-
|
|
330
|
-
if (!values.email.includes("@")) return [t("Invalid email address")];
|
|
214
|
+
## <a id="validation-and-validators"></a> 🔒 Validation and Validators
|
|
331
215
|
|
|
332
|
-
|
|
333
|
-
method: "POST",
|
|
334
|
-
body: JSON.stringify(values),
|
|
335
|
-
});
|
|
336
|
-
});
|
|
216
|
+
ReactaForm supports both field-level and form-level validation.
|
|
337
217
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
submitHandlerName: "mySubmitHandler"
|
|
341
|
-
};
|
|
342
|
-
```
|
|
218
|
+
- Field-level: validation for a single field; can happen in real-time (while editing) or on submission.
|
|
219
|
+
- Form-level: cross-field validation performed during submission.
|
|
343
220
|
|
|
344
|
-
###
|
|
221
|
+
### Field validation modes
|
|
345
222
|
|
|
346
|
-
|
|
347
|
-
|
|
223
|
+
`FieldValidationMode`:
|
|
224
|
+
- `realTime`: Runs validation while the user edits a field.
|
|
225
|
+
- `onSubmission`: Runs validation only when the form is submitted.
|
|
348
226
|
|
|
349
|
-
|
|
350
|
-
<ReactaFormRenderer properties={definition.properties} instance={formData} />
|
|
351
|
-
</ReactaFormProvider>
|
|
352
|
-
```
|
|
227
|
+
### Validators
|
|
353
228
|
|
|
354
|
-
|
|
229
|
+
- Field custom validator — register a handler for individual-field logic.
|
|
230
|
+
- Form custom validator — register a handler for cross-field logic (runs during submission).
|
|
231
|
+
- Field type validator — define validation for a custom field/component type.
|
|
232
|
+
---
|
|
355
233
|
|
|
356
|
-
|
|
234
|
+
## Submission Handler
|
|
235
|
+
Since ReactaForm is a dynamic form system, it provides a submission handler mechanism that allows you to define and plug in custom submission logic, such as validation, data processing, or API calls.
|
|
357
236
|
|
|
358
|
-
|
|
237
|
+
**How It Works**
|
|
359
238
|
|
|
360
|
-
|
|
361
|
-
const myPlugin: ReactaFormPlugin = {
|
|
362
|
-
name: 'my-awesome-plugin',
|
|
363
|
-
version: '0.1.0',
|
|
364
|
-
description: 'Adds a custom field and validators',
|
|
365
|
-
components: {
|
|
366
|
-
customType: CustomInput,
|
|
367
|
-
},
|
|
368
|
-
fieldValidators: {
|
|
369
|
-
default: {
|
|
370
|
-
myValidator: (value) => (value ? null : 'Required'),
|
|
371
|
-
},
|
|
372
|
-
},
|
|
373
|
-
submissionHandlers: {
|
|
374
|
-
mySubmitHandler: async (_, __, values) => {
|
|
375
|
-
// Custom submission logic
|
|
376
|
-
return [] as string[]; // return array of errors or empty array
|
|
377
|
-
},
|
|
378
|
-
},
|
|
379
|
-
setup() {
|
|
380
|
-
// optional init logic
|
|
381
|
-
},
|
|
382
|
-
cleanup() {
|
|
383
|
-
// optional teardown logic
|
|
384
|
-
},
|
|
385
|
-
};
|
|
386
|
-
```
|
|
239
|
+
Submission handling is configured in two steps:
|
|
387
240
|
|
|
388
|
-
|
|
241
|
+
1. Define and Register a Submission Handler
|
|
389
242
|
|
|
390
243
|
```ts
|
|
391
|
-
import {
|
|
244
|
+
import { registerSubmissionHandler } from 'reactaform';
|
|
392
245
|
|
|
393
|
-
|
|
246
|
+
registerSubmissionHandler('api:saveForm', async (definition, instanceName, valuesMap, t) => {
|
|
247
|
+
// send valuesMap to your API
|
|
248
|
+
const res = await fetch('/api/save', { method: 'POST', body: JSON.stringify(valuesMap), headers: { 'Content-Type': 'application/json' } });
|
|
249
|
+
if (!res.ok) return [t('Server error while submitting form')];
|
|
250
|
+
return undefined; // returning undefined (or falsy) means success
|
|
251
|
+
});
|
|
394
252
|
```
|
|
395
253
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
- `conflictResolution`: one of `'error'` (default), `'warn'`, `'override'`, or `'skip'`.
|
|
399
|
-
- `onConflict`: optional callback `(conflict: PluginConflict) => boolean` to programmatically decide whether to proceed when a conflict occurs.
|
|
400
|
-
|
|
401
|
-
Unregistering and inspecting plugins:
|
|
254
|
+
2. Reference the Registered Handler in the Form Definition
|
|
402
255
|
|
|
403
|
-
|
|
404
|
-
import { unregisterPlugin, getPlugin, getAllPlugins, hasPlugin } from 'reactaform';
|
|
256
|
+
Schema example (Reference a registered handler using the submitHandlerName property):
|
|
405
257
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"name": "contactForm",
|
|
261
|
+
"version": "1.0",
|
|
262
|
+
"displayName": "Contact",
|
|
263
|
+
"submitHandlerName": "api:saveForm",
|
|
264
|
+
"properties": [ /* ... */ ]
|
|
265
|
+
}
|
|
410
266
|
```
|
|
411
267
|
|
|
412
|
-
|
|
268
|
+
## <a id="documentation"></a> 📚 Documentation
|
|
413
269
|
|
|
414
|
-
|
|
270
|
+
👉 https://reactaform.vercel.app/docs
|
|
415
271
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
| Prop | Type | Required | Description |
|
|
419
|
-
|------|------|----------|-------------|
|
|
420
|
-
| `definitionData` | `ReactaDefinition \| string` | ✔ | Form definition |
|
|
421
|
-
| `instance` | `ReactaInstance` | – | Form state instance |
|
|
422
|
-
| `language` | `string` | – | e.g. "en", "fr" |
|
|
423
|
-
| `darkMode` | `boolean` | – | Force dark mode |
|
|
424
|
-
| `className` | `string` | – | Custom CSS class |
|
|
425
|
-
| `style` | `CSSProperties` | – | Inline styles |
|
|
426
|
-
|
|
427
|
-
## 🧪 Testing
|
|
272
|
+
---
|
|
428
273
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
274
|
+
## <a id="roadmap"></a> 🗺️ Roadmap
|
|
275
|
+
|
|
276
|
+
### Core & Standards
|
|
277
|
+
- [ ] Accessibility certification (WCAG 2.2 AA)
|
|
278
|
+
- [ ] Performance & accessibility audit tooling
|
|
279
|
+
- [ ] Schema versioning & migration tools
|
|
280
|
+
|
|
281
|
+
### Conditional Logic
|
|
282
|
+
- [x] Parent–child conditional visibility (current)
|
|
283
|
+
- [x] Field grouping (current)
|
|
284
|
+
- [ ] Advanced conditional logic engine
|
|
285
|
+
- [ ] Logical operators (AND / OR / NOT)
|
|
286
|
+
- [ ] Multi-field conditions
|
|
287
|
+
- [ ] Expression-based rules
|
|
288
|
+
- [ ] Nested condition groups
|
|
289
|
+
- [ ] Layout enhancement
|
|
290
|
+
- [ ] Tabbed forms (planned)
|
|
291
|
+
- [ ] Navigation sections (planned)
|
|
292
|
+
- [ ] Multi-step forms
|
|
293
|
+
|
|
294
|
+
### Visual Builders
|
|
295
|
+
- [ ] Enhanced visual form builder
|
|
296
|
+
- [ ]Advanced conditional logic editor
|
|
297
|
+
- [ ]Validation rule designer
|
|
298
|
+
- [ ] **Theme Builder (Visual)**
|
|
299
|
+
- [ ]Visual CSS-variable editor
|
|
300
|
+
- [ ]Live preview across field types
|
|
301
|
+
- [ ]Light / dark theme generation
|
|
302
|
+
- [ ]Exportable, versioned theme packages
|
|
303
|
+
- [ ]Tailwind-compatible themes
|
|
304
|
+
- [ ] **Plugin Builder**
|
|
305
|
+
- [ ] Scaffold custom field components
|
|
306
|
+
- [ ] Scaffold validators & submission handlers
|
|
307
|
+
- [ ] Plugin metadata & versioning
|
|
308
|
+
- [ ] One-click plugin export
|
|
309
|
+
|
|
310
|
+
### Ecosystem
|
|
311
|
+
- [ ] Definition templates (community-driven)
|
|
312
|
+
- [ ] Plugin marketplace (community-driven)
|
|
313
|
+
- [ ] Theme sharing & presets gallery
|
|
314
|
+
- [ ] Official plugin & theme collections
|
|
315
|
+
|
|
316
|
+
### Enterprise
|
|
317
|
+
- [ ] Form analytics & submission insights
|
|
318
|
+
- [ ] Role-based builder permissions
|
|
319
|
+
- [ ] Hosted schema & asset management
|
|
320
|
+
- [ ] Enterprise integrations
|
|
433
321
|
|
|
434
|
-
|
|
322
|
+
---
|
|
435
323
|
|
|
436
|
-
|
|
437
|
-
npm run build:lib
|
|
438
|
-
npm pack
|
|
439
|
-
```
|
|
324
|
+
## <a id="contributing"></a> 🤝 Contributing
|
|
440
325
|
|
|
441
|
-
|
|
326
|
+
Contributions are welcome!
|
|
327
|
+
Open an issue or submit a pull request.
|
|
442
328
|
|
|
443
|
-
|
|
444
|
-
- CJS: `dist/reactaform.cjs.js`
|
|
445
|
-
- Types: `dist/index.d.ts`
|
|
329
|
+
---
|
|
446
330
|
|
|
447
|
-
## 📄 License
|
|
331
|
+
## <a id="license"></a> 📄 License
|
|
448
332
|
|
|
449
333
|
MIT
|
|
450
|
-
|
|
451
|
-
## 🤝 Contributing
|
|
452
|
-
|
|
453
|
-
Contributions welcome! Open a pull request anytime.
|
|
454
|
-
|
|
455
|
-
## 🗺️ Roadmap
|
|
456
|
-
|
|
457
|
-
- [ ] Enhanced accessibility audit
|
|
458
|
-
- [ ] Additional built-in validators
|
|
459
|
-
- [ ] Visual form-builder UI
|
|
460
|
-
- [ ] Schema migration tools
|
|
461
|
-
- [ ] Performance profiling dashboard
|
|
462
|
-
|
|
463
|
-
---
|
|
464
|
-
|
|
465
|
-
Built with ❤️ using React and TypeScript
|