reactaform 1.1.3 → 1.1.5
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 +160 -330
- package/dist/reactaform.cjs.js +6 -6
- package/dist/reactaform.es.js +1305 -1426
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -1,18 +1,37 @@
|
|
|
1
1
|
# ReactaForm
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ReactaForm is a fully dynamic, ultra-customizable form engine for modern React applications. With schema-driven rendering, full TypeScript support, and built-in performance optimizations, it provides everything you need to build powerful forms—without the boilerplate.
|
|
4
4
|
|
|
5
5
|
## ✨ Features
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
7
|
+
### 🔧 Core Capabilities
|
|
8
|
+
|
|
9
|
+
- **Dynamic Schema-Driven Forms** — Generate entire forms from JSON definitions.
|
|
10
|
+
- **Type-Safe by Design** — Strongly typed fields, validators, and submission handlers.
|
|
11
|
+
- **20+ Built-In Field Types** — Text, email, phone, dropdown, slider, rating, date, file upload, and more.
|
|
12
|
+
|
|
13
|
+
### 🎨 Customization & Theming
|
|
14
|
+
|
|
15
|
+
- **Themeable via CSS Variables** — Customize colors, spacing, borders, typography, and support light/dark modes.
|
|
16
|
+
- **Component Registry** — Register custom field components.
|
|
17
|
+
|
|
18
|
+
### 🧠 Logic & Validation
|
|
19
|
+
|
|
20
|
+
- **Custom Validation System** — Register validators globally or per field.
|
|
21
|
+
- **Conditional Logic** — Show or hide fields dynamically based on parent values.
|
|
22
|
+
|
|
23
|
+
### 🌍 Internationalization
|
|
24
|
+
|
|
25
|
+
- **Built-In Multi-Language Support** — i18n with translation caching for fast rendering.
|
|
26
|
+
|
|
27
|
+
### ⚡ Performance & UX
|
|
28
|
+
|
|
29
|
+
- **Optimized Input Handling** — Debounced updates + requestAnimationFrame-driven state management.
|
|
30
|
+
- **Accessible by Default** — ARIA attributes, keyboard navigation, and focus management.
|
|
31
|
+
|
|
32
|
+
### 🔌 Flexible Submission Flow
|
|
33
|
+
|
|
34
|
+
- **Custom Submission Handlers** — Integrate any workflow, API, or async logic.
|
|
16
35
|
|
|
17
36
|
## 📦 Installation
|
|
18
37
|
|
|
@@ -21,32 +40,20 @@ npm install reactaform react react-dom
|
|
|
21
40
|
```
|
|
22
41
|
|
|
23
42
|
**Peer Dependencies:**
|
|
24
|
-
- React ^19.2.0
|
|
25
|
-
- React-DOM ^19.2.0
|
|
26
|
-
|
|
27
|
-
## 🌐 Environment Compatibility
|
|
28
43
|
|
|
29
|
-
|
|
44
|
+
- React `^18.0.0 || ^19.0.0`
|
|
45
|
+
- React-DOM `^18.0.0 || ^19.0.0`
|
|
30
46
|
|
|
31
|
-
|
|
32
|
-
✅ **Webpack** (Create React App) - Fully supported
|
|
33
|
-
✅ **Next.js** - Fully supported
|
|
34
|
-
✅ **Parcel, esbuild, Rollup** - Fully supported
|
|
47
|
+
## 🌐 Environment Compatibility
|
|
35
48
|
|
|
36
|
-
|
|
49
|
+
ReactaForm works seamlessly with:
|
|
37
50
|
|
|
38
|
-
|
|
51
|
+
- Vite (recommended)
|
|
52
|
+
- Webpack / CRA
|
|
53
|
+
- Next.js
|
|
54
|
+
- Parcel, esbuild, Rollup
|
|
39
55
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
// src/global.d.ts
|
|
44
|
-
declare module '*.css';
|
|
45
|
-
declare module '*.module.css' {
|
|
46
|
-
const classes: { readonly [key: string]: string };
|
|
47
|
-
export default classes;
|
|
48
|
-
}
|
|
49
|
-
```
|
|
56
|
+
The library intelligently handles `import.meta.env` and `process.env` with automatic fallbacks—no config tweaks required.
|
|
50
57
|
|
|
51
58
|
## 🚀 Quick Start
|
|
52
59
|
|
|
@@ -54,39 +61,21 @@ declare module '*.module.css' {
|
|
|
54
61
|
import { ReactaForm, createInstanceFromDefinition } from 'reactaform';
|
|
55
62
|
import { useState } from 'react';
|
|
56
63
|
|
|
64
|
+
// Define definition, can be load from server
|
|
57
65
|
const definition = {
|
|
58
66
|
name: "contactForm",
|
|
59
67
|
version: "1.0",
|
|
60
68
|
displayName: "Contact Form",
|
|
61
69
|
properties: [
|
|
62
|
-
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
type: "string",
|
|
66
|
-
defaultValue: "",
|
|
67
|
-
required: true,
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: "email",
|
|
71
|
-
displayName: "Email",
|
|
72
|
-
type: "email",
|
|
73
|
-
defaultValue: "",
|
|
74
|
-
required: true,
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
name: "message",
|
|
78
|
-
displayName: "Message",
|
|
79
|
-
type: "text",
|
|
80
|
-
defaultValue: "",
|
|
81
|
-
required: true,
|
|
82
|
-
}
|
|
70
|
+
{ name: "fullName", displayName: "Full Name", type: "string", required: true },
|
|
71
|
+
{ name: "email", displayName: "Email", type: "email", required: true },
|
|
72
|
+
{ name: "message", displayName: "Message", type: "text", required: true }
|
|
83
73
|
]
|
|
84
74
|
};
|
|
85
75
|
|
|
86
76
|
function App() {
|
|
87
|
-
// Create an instance from the definition
|
|
88
77
|
const result = createInstanceFromDefinition(definition, "myForm");
|
|
89
|
-
const [instance
|
|
78
|
+
const [instance] = useState(result.instance);
|
|
90
79
|
|
|
91
80
|
return (
|
|
92
81
|
<ReactaForm
|
|
@@ -98,339 +87,221 @@ function App() {
|
|
|
98
87
|
}
|
|
99
88
|
```
|
|
100
89
|
|
|
101
|
-
> **Note
|
|
90
|
+
> **Note:** ReactaForm manages internal form state automatically. Use `setInstance()` only for programmatic overrides.
|
|
91
|
+
|
|
102
92
|
|
|
103
93
|
## 📖 Core Concepts
|
|
104
94
|
|
|
105
95
|
### Form Definitions
|
|
106
96
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
```typescript
|
|
97
|
+
```ts
|
|
110
98
|
interface ReactaDefinition {
|
|
111
|
-
name: string;
|
|
112
|
-
version: string;
|
|
113
|
-
displayName: string;
|
|
114
|
-
properties: FieldDefinition[];
|
|
99
|
+
name: string;
|
|
100
|
+
version: string;
|
|
101
|
+
displayName: string;
|
|
102
|
+
properties: FieldDefinition[];
|
|
115
103
|
}
|
|
116
104
|
```
|
|
117
105
|
|
|
118
|
-
### Field Types
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
|
123
|
-
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `email` | Email
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `rating` | Star rating |
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
Fields can be conditionally shown/hidden based on parent field values:
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
106
|
+
### Supported Field Types
|
|
107
|
+
|
|
108
|
+
| Type | Description |
|
|
109
|
+
|------|-------------|
|
|
110
|
+
| `checkbox` | Boolean |
|
|
111
|
+
| `color` | Color picker |
|
|
112
|
+
| `date` | Date Picker |
|
|
113
|
+
| `dropdown` | Select menu |
|
|
114
|
+
| `email` | Email input |
|
|
115
|
+
| `file` | Upload |
|
|
116
|
+
| `float` | Float input |
|
|
117
|
+
| `float-array` | Float array input |
|
|
118
|
+
| `image` | Image preview |
|
|
119
|
+
| `int-array`| Integer array input |
|
|
120
|
+
| `int` | Integer input |
|
|
121
|
+
| `multiSelection` | Multiple selection |
|
|
122
|
+
| `phone` | Phone number input |
|
|
123
|
+
| `radio` | Radio button group |
|
|
124
|
+
| `rating` | Star rating |
|
|
125
|
+
| `slider` | Range slider |
|
|
126
|
+
| `switch` | Boolean |
|
|
127
|
+
| `text` | Single line input |
|
|
128
|
+
| `time` | Time input |
|
|
129
|
+
| `unitValue` | Value + unit conversion |
|
|
130
|
+
| `url` | URL validation |
|
|
131
|
+
|
|
132
|
+
### 🎭 Conditional Visibility
|
|
133
|
+
|
|
134
|
+
```json
|
|
150
135
|
{
|
|
151
|
-
name: "country",
|
|
152
|
-
displayName: "Country",
|
|
153
|
-
type: "dropdown",
|
|
154
|
-
options: [
|
|
155
|
-
{ label: "United States", value: "US" },
|
|
156
|
-
{ label: "Canada", value: "CA" }
|
|
136
|
+
"name": "country",
|
|
137
|
+
"displayName": "Country",
|
|
138
|
+
"type": "dropdown",
|
|
139
|
+
"options": [
|
|
140
|
+
{ "label": "United States", "value": "US" },
|
|
141
|
+
{ "label": "Canada", "value": "CA" }
|
|
157
142
|
]
|
|
158
143
|
},
|
|
159
144
|
{
|
|
160
|
-
name: "state",
|
|
161
|
-
displayName: "State
|
|
162
|
-
type: "dropdown",
|
|
163
|
-
parents: {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
]
|
|
145
|
+
"name": "state",
|
|
146
|
+
"displayName": "State",
|
|
147
|
+
"type": "dropdown",
|
|
148
|
+
"parents": { "country": ["US"] }
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "province",
|
|
152
|
+
"displayName": "Province",
|
|
153
|
+
"type": "dropdown",
|
|
154
|
+
"parents": { "country": ["CA"] }
|
|
170
155
|
}
|
|
171
|
-
```
|
|
172
156
|
|
|
173
|
-
|
|
157
|
+
```
|
|
174
158
|
|
|
175
|
-
|
|
159
|
+
### 🔍 Validation
|
|
176
160
|
|
|
177
|
-
```
|
|
161
|
+
```json
|
|
178
162
|
{
|
|
179
|
-
name: "email",
|
|
180
|
-
displayName: "Email
|
|
181
|
-
type: "email",
|
|
182
|
-
required: true,
|
|
183
|
-
pattern: "^[a-z]+$",
|
|
184
|
-
minLength: 5,
|
|
185
|
-
maxLength: 100
|
|
163
|
+
"name": "email",
|
|
164
|
+
"displayName": "Email",
|
|
165
|
+
"type": "email",
|
|
166
|
+
"required": true,
|
|
167
|
+
"pattern": "^[a-z]+$",
|
|
168
|
+
"minLength": 5,
|
|
169
|
+
"maxLength": 100
|
|
186
170
|
}
|
|
187
171
|
```
|
|
188
172
|
|
|
189
173
|
## 🎨 Theming
|
|
190
174
|
|
|
191
|
-
|
|
175
|
+
Customize with CSS variables:
|
|
192
176
|
|
|
193
177
|
```css
|
|
194
178
|
:root {
|
|
195
|
-
/* Colors */
|
|
196
179
|
--reactaform-color-primary: #2563eb;
|
|
197
180
|
--reactaform-color-error: #ef4444;
|
|
198
|
-
--reactaform-color-success: #10b981;
|
|
199
|
-
|
|
200
|
-
/* Typography */
|
|
201
|
-
--reactaform-font-family: system-ui, sans-serif;
|
|
202
181
|
--reactaform-font-size: 1rem;
|
|
203
|
-
--reactaform-font-weight: 400;
|
|
204
|
-
|
|
205
|
-
/* Spacing */
|
|
206
|
-
--reactaform-space-xs: 4px;
|
|
207
|
-
--reactaform-space-sm: 8px;
|
|
208
|
-
--reactaform-space-md: 16px;
|
|
209
|
-
|
|
210
|
-
/* Borders */
|
|
211
|
-
--reactaform-border-radius: 4px;
|
|
212
|
-
--reactaform-border-color: #d1d5db;
|
|
213
|
-
|
|
214
|
-
/* Inputs */
|
|
215
182
|
--reactaform-input-bg: #ffffff;
|
|
216
|
-
--reactaform-input-padding: 8px 12px;
|
|
217
183
|
}
|
|
218
184
|
|
|
219
|
-
/* Dark
|
|
185
|
+
/* Dark */
|
|
220
186
|
[data-reactaform-theme="dark"] {
|
|
221
|
-
--reactaform-bg-primary: #
|
|
222
|
-
--reactaform-text-color: #
|
|
223
|
-
--reactaform-input-bg: #2A2A2A;
|
|
224
|
-
--reactaform-border-color: #3A3A3A;
|
|
187
|
+
--reactaform-bg-primary: #1a1a1a;
|
|
188
|
+
--reactaform-text-color: #ededed;
|
|
225
189
|
}
|
|
226
190
|
```
|
|
227
191
|
|
|
228
|
-
|
|
192
|
+
**Enable Dark Mode:**
|
|
229
193
|
|
|
230
194
|
```tsx
|
|
231
|
-
<ReactaForm
|
|
232
|
-
definitionData={definition}
|
|
233
|
-
instance={formData}
|
|
234
|
-
darkMode={true} // Enable dark mode
|
|
235
|
-
/>
|
|
195
|
+
<ReactaForm darkMode={true} ... />
|
|
236
196
|
```
|
|
237
197
|
|
|
238
|
-
## 🌍 Internationalization
|
|
239
|
-
|
|
240
|
-
ReactaForm supports multiple languages:
|
|
198
|
+
## 🌍 Internationalization (i18n)
|
|
241
199
|
|
|
242
200
|
```tsx
|
|
243
|
-
<ReactaForm
|
|
244
|
-
definitionData={definition}
|
|
245
|
-
instance={formData}
|
|
246
|
-
language="fr" // 'en', 'fr', 'de', 'es', 'zh-cn'
|
|
247
|
-
/>
|
|
201
|
+
<ReactaForm language="fr" ... />
|
|
248
202
|
```
|
|
249
203
|
|
|
250
204
|
### Custom Translations
|
|
251
205
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
206
|
+
```json
|
|
255
207
|
// public/locales/fr/myform.json
|
|
256
208
|
{
|
|
257
209
|
"Full Name": "Nom complet",
|
|
258
|
-
"Email": "Courriel"
|
|
259
|
-
"Submit": "Soumettre"
|
|
210
|
+
"Email": "Courriel"
|
|
260
211
|
}
|
|
261
212
|
```
|
|
262
213
|
|
|
263
|
-
## 🔧 Advanced Usage
|
|
264
214
|
|
|
265
|
-
|
|
215
|
+
## 🔧 Advanced Usage
|
|
266
216
|
|
|
267
|
-
|
|
217
|
+
### Custom Components
|
|
268
218
|
|
|
269
219
|
```tsx
|
|
270
220
|
import { registerComponent } from 'reactaform';
|
|
271
221
|
|
|
272
|
-
const CustomInput = ({
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
);
|
|
280
|
-
};
|
|
222
|
+
const CustomInput = ({ value, onChange, field }) => (
|
|
223
|
+
<input
|
|
224
|
+
value={value}
|
|
225
|
+
placeholder={field.displayName}
|
|
226
|
+
onChange={(e) => onChange(e.target.value, null)}
|
|
227
|
+
/>
|
|
228
|
+
);
|
|
281
229
|
|
|
282
|
-
registerComponent(
|
|
230
|
+
registerComponent("customType", CustomInput);
|
|
283
231
|
```
|
|
284
232
|
|
|
285
233
|
### Custom Validation
|
|
286
234
|
|
|
287
|
-
Register custom validators:
|
|
288
|
-
|
|
289
235
|
```tsx
|
|
290
236
|
import { registerValidationHandler } from 'reactaform';
|
|
291
237
|
|
|
292
|
-
registerValidationHandler(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
return null; // No error
|
|
297
|
-
});
|
|
238
|
+
registerValidationHandler("customType", (value) =>
|
|
239
|
+
value.length < 10 ? "Must be at least 10 characters" : null
|
|
240
|
+
);
|
|
298
241
|
```
|
|
299
242
|
|
|
300
|
-
###
|
|
301
|
-
|
|
302
|
-
Handle form submission with custom logic:
|
|
243
|
+
### Custom Submission
|
|
303
244
|
|
|
304
245
|
```tsx
|
|
305
246
|
import { registerSubmissionHandler } from 'reactaform';
|
|
306
247
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
'mySubmitHandler', // Handler name (referenced in definition.submitHandlerName)
|
|
310
|
-
(definition, instanceName, valuesMap, t) => {
|
|
311
|
-
// definition: The form definition
|
|
312
|
-
// instanceName: Current instance name
|
|
313
|
-
// valuesMap: Object with all field values { fieldName: value }
|
|
314
|
-
// t: Translation function for error messages
|
|
315
|
-
|
|
316
|
-
// Custom validation
|
|
317
|
-
if (!valuesMap.email?.includes('@')) {
|
|
318
|
-
return [t('Invalid email address')]; // Return array of error strings
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Submit to API
|
|
322
|
-
fetch('/api/contact', {
|
|
323
|
-
method: 'POST',
|
|
324
|
-
headers: { 'Content-Type': 'application/json' },
|
|
325
|
-
body: JSON.stringify(valuesMap),
|
|
326
|
-
}).catch(err => {
|
|
327
|
-
console.error('Submission failed:', err);
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
// Return undefined for success, or array of error strings for failure
|
|
331
|
-
return undefined;
|
|
332
|
-
}
|
|
333
|
-
);
|
|
334
|
-
```
|
|
248
|
+
registerSubmissionHandler("mySubmitHandler", async (_, __, values, t) => {
|
|
249
|
+
if (!values.email.includes("@")) return [t("Invalid email address")];
|
|
335
250
|
|
|
336
|
-
|
|
251
|
+
await fetch("/api/contact", {
|
|
252
|
+
method: "POST",
|
|
253
|
+
body: JSON.stringify(values),
|
|
254
|
+
});
|
|
255
|
+
});
|
|
337
256
|
|
|
338
|
-
```tsx
|
|
339
257
|
const definition = {
|
|
340
258
|
name: "contactForm",
|
|
341
|
-
submitHandlerName: "mySubmitHandler"
|
|
342
|
-
// ... rest of definition
|
|
259
|
+
submitHandlerName: "mySubmitHandler"
|
|
343
260
|
};
|
|
344
261
|
```
|
|
345
262
|
|
|
346
|
-
###
|
|
347
|
-
|
|
348
|
-
Wrap your app for global configuration:
|
|
263
|
+
### Provider Usage
|
|
349
264
|
|
|
350
265
|
```tsx
|
|
351
266
|
import { ReactaFormProvider, ReactaFormRenderer } from 'reactaform';
|
|
352
267
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
defaultLanguage="en"
|
|
357
|
-
defaultDarkMode={false}
|
|
358
|
-
definitionName="myForm"
|
|
359
|
-
>
|
|
360
|
-
<ReactaFormRenderer
|
|
361
|
-
properties={definition.properties}
|
|
362
|
-
instance={formData}
|
|
363
|
-
/>
|
|
364
|
-
</ReactaFormProvider>
|
|
365
|
-
);
|
|
366
|
-
}
|
|
268
|
+
<ReactaFormProvider defaultLanguage="en">
|
|
269
|
+
<ReactaFormRenderer properties={definition.properties} instance={formData} />
|
|
270
|
+
</ReactaFormProvider>
|
|
367
271
|
```
|
|
368
272
|
|
|
369
|
-
### Note: `definitionName` vs renderer-level override
|
|
370
|
-
|
|
371
|
-
- `ReactaFormProvider` accepts an optional `definitionName` prop which can be used as a top-level default when you are rendering a single form or when tests/storybook rely on a global active definition.
|
|
372
|
-
- `ReactaFormRenderer` injects its own `definitionName` into the React context (it wraps its output in a nested provider). This means multiple renderers with different definitions can safely coexist under the same `ReactaFormProvider`.
|
|
373
|
-
- Recommendation: prefer leaving `definitionName` empty at the top-level and let each `ReactaFormRenderer` provide the definitive `definitionName` for the fields it renders. Use the provider-level `definitionName` only for special cases (tests, single-form pages) where you need a global fallback.
|
|
374
|
-
|
|
375
|
-
|
|
376
273
|
## 📚 API Reference
|
|
377
274
|
|
|
378
275
|
### ReactaForm Props
|
|
379
276
|
|
|
380
277
|
| Prop | Type | Required | Description |
|
|
381
278
|
|------|------|----------|-------------|
|
|
382
|
-
| `definitionData` | `ReactaDefinition \| string` |
|
|
383
|
-
| `instance` | `ReactaInstance` |
|
|
384
|
-
| `language` | `string` |
|
|
385
|
-
| `darkMode` | `boolean` |
|
|
386
|
-
| `className` | `string` |
|
|
387
|
-
| `style` | `CSSProperties` |
|
|
388
|
-
|
|
389
|
-
*While `instance` is technically optional (auto-created if omitted), providing it is recommended for proper state management.
|
|
390
|
-
|
|
391
|
-
### Field Definition Props
|
|
392
|
-
|
|
393
|
-
| Prop | Type | Required | Description |
|
|
394
|
-
|------|------|----------|-------------|
|
|
395
|
-
| `name` | `string` | Yes | Unique field identifier |
|
|
396
|
-
| `displayName` | `string` | Yes | Field label |
|
|
397
|
-
| `type` | `string` | Yes | Field type (see Field Types) |
|
|
398
|
-
| `defaultValue` | `any` | No | Default field value |
|
|
399
|
-
| `required` | `boolean` | No | Field is required |
|
|
400
|
-
| `disabled` | `boolean` | No | Field is disabled |
|
|
401
|
-
| `readOnly` | `boolean` | No | Field is read-only |
|
|
402
|
-
| `tooltip` | `string` | No | Tooltip text |
|
|
403
|
-
| `placeholder` | `string` | No | Placeholder text |
|
|
404
|
-
| `options` | `Option[]` | No | Options for dropdown/radio/multi-selection |
|
|
405
|
-
| `parents` | `Record<string, string[]>` | No | Conditional visibility rules |
|
|
406
|
-
| `pattern` | `string` | No | Regex validation pattern |
|
|
407
|
-
| `minLength` | `number` | No | Minimum input length |
|
|
408
|
-
| `maxLength` | `number` | No | Maximum input length |
|
|
409
|
-
| `min` | `number` | No | Minimum numeric value |
|
|
410
|
-
| `max` | `number` | No | Maximum numeric value |
|
|
411
|
-
| `step` | `number` | No | Numeric step increment |
|
|
412
|
-
| `labelLayout` | `'row' \| 'column-left' \| 'column-center'` | No | Label positioning |
|
|
279
|
+
| `definitionData` | `ReactaDefinition \| string` | ✔ | Form definition |
|
|
280
|
+
| `instance` | `ReactaInstance` | – | Form state instance |
|
|
281
|
+
| `language` | `string` | – | e.g. "en", "fr" |
|
|
282
|
+
| `darkMode` | `boolean` | – | Force dark mode |
|
|
283
|
+
| `className` | `string` | – | Custom CSS class |
|
|
284
|
+
| `style` | `CSSProperties` | – | Inline styles |
|
|
413
285
|
|
|
414
286
|
## 🧪 Testing
|
|
415
287
|
|
|
416
|
-
ReactaForm uses Vitest for testing:
|
|
417
|
-
|
|
418
288
|
```bash
|
|
419
|
-
npm run test
|
|
420
|
-
npm run typecheck
|
|
289
|
+
npm run test
|
|
290
|
+
npm run typecheck
|
|
421
291
|
```
|
|
422
292
|
|
|
423
293
|
## 🏗️ Building
|
|
424
294
|
|
|
425
295
|
```bash
|
|
426
|
-
npm run build:lib
|
|
427
|
-
npm pack
|
|
296
|
+
npm run build:lib
|
|
297
|
+
npm pack
|
|
428
298
|
```
|
|
429
299
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
-
|
|
433
|
-
-
|
|
300
|
+
**Outputs:**
|
|
301
|
+
|
|
302
|
+
- ESM: `dist/reactaform.es.js`
|
|
303
|
+
- CJS: `dist/reactaform.cjs.js`
|
|
304
|
+
- Types: `dist/index.d.ts`
|
|
434
305
|
|
|
435
306
|
## 📄 License
|
|
436
307
|
|
|
@@ -438,57 +309,16 @@ MIT
|
|
|
438
309
|
|
|
439
310
|
## 🤝 Contributing
|
|
440
311
|
|
|
441
|
-
Contributions
|
|
442
|
-
|
|
443
|
-
## 🐛 Known Issues
|
|
444
|
-
|
|
445
|
-
- Virtual scrolling optimization in progress for forms with 1000+ fields
|
|
446
|
-
- Screen reader testing ongoing for complex conditional fields
|
|
312
|
+
Contributions welcome! Open a pull request anytime.
|
|
447
313
|
|
|
448
314
|
## 🗺️ Roadmap
|
|
449
315
|
|
|
450
316
|
- [ ] Enhanced accessibility audit
|
|
451
|
-
- [ ]
|
|
452
|
-
- [ ]
|
|
317
|
+
- [ ] Additional built-in validators
|
|
318
|
+
- [ ] Visual form-builder UI
|
|
453
319
|
- [ ] Schema migration tools
|
|
454
320
|
- [ ] Performance profiling dashboard
|
|
455
321
|
|
|
456
|
-
## 🔍 Troubleshooting
|
|
457
|
-
|
|
458
|
-
### "Cannot find module './style.css'"
|
|
459
|
-
|
|
460
|
-
**Solution**: Add a `global.d.ts` file (see Environment Compatibility section above).
|
|
461
|
-
|
|
462
|
-
### Form not updating when instance changes
|
|
463
|
-
|
|
464
|
-
**Solution**: Ensure you're passing a **new instance object** (immutable updates):
|
|
465
|
-
|
|
466
|
-
```tsx
|
|
467
|
-
// ✅ Correct - creates new object
|
|
468
|
-
setInstance({ ...instance, values: { ...instance.values, name: 'John' } });
|
|
469
|
-
|
|
470
|
-
// ❌ Wrong - mutates existing object
|
|
471
|
-
instance.values.name = 'John';
|
|
472
|
-
setInstance(instance);
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
### Submission handler not called
|
|
476
|
-
|
|
477
|
-
**Solution**: Ensure `submitHandlerName` in your definition matches the registered handler name:
|
|
478
|
-
|
|
479
|
-
```tsx
|
|
480
|
-
registerSubmissionHandler('myHandler', ...);
|
|
481
|
-
// Definition must have: submitHandlerName: "myHandler"
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
### TypeScript errors about `import.meta` or `process`
|
|
485
|
-
|
|
486
|
-
**Solution**: The library handles these internally with fallbacks. If you see errors in **your** code, ensure you're not directly importing library internals. If errors persist, update to the latest version.
|
|
487
|
-
|
|
488
|
-
### Dark mode not working
|
|
489
|
-
|
|
490
|
-
**Solution**: Either pass `darkMode={true}` prop, or wrap your app with `[data-reactaform-theme="dark"]` attribute on a parent element.
|
|
491
|
-
|
|
492
322
|
---
|
|
493
323
|
|
|
494
|
-
|
|
324
|
+
Built with ❤️ using React and TypeScript
|