reactaform 1.0.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 +499 -0
- package/dist/common-BD9zx3GT.js +1 -0
- package/dist/common-BQcVe8MY.mjs +87 -0
- package/dist/common-BnnwzTl2.mjs +87 -0
- package/dist/common-BxyjIoe1.js +1 -0
- package/dist/common-Bzz0clAC.mjs +87 -0
- package/dist/common-COyDhNL-.js +1 -0
- package/dist/common-DLqVHgfX.mjs +87 -0
- package/dist/common-hRFTL4KF.js +1 -0
- package/dist/components/LayoutComponents.d.ts +74 -0
- package/dist/components/PopupOptionMenu.d.ts +15 -0
- package/dist/components/ReactaForm.d.ts +4 -0
- package/dist/components/ReactaFormProvider.d.ts +3 -0
- package/dist/components/ReactaFormRenderer.d.ts +13 -0
- package/dist/components/Tooltip.d.ts +8 -0
- package/dist/components/VirtualizedFieldList.d.ts +36 -0
- package/dist/components/fields/CheckboxInput.d.ts +9 -0
- package/dist/components/fields/ColorInput.d.ts +17 -0
- package/dist/components/fields/DateInput.d.ts +11 -0
- package/dist/components/fields/DropdownInput.d.ts +13 -0
- package/dist/components/fields/EmailInput.d.ts +5 -0
- package/dist/components/fields/FileInput.d.ts +5 -0
- package/dist/components/fields/FloatArrayInput.d.ts +5 -0
- package/dist/components/fields/FloatInput.d.ts +24 -0
- package/dist/components/fields/ImageDisplay.d.ts +17 -0
- package/dist/components/fields/IntegerArrayInput.d.ts +23 -0
- package/dist/components/fields/IntegerInput.d.ts +28 -0
- package/dist/components/fields/MultiSelection.d.ts +9 -0
- package/dist/components/fields/MultilineTextInput.d.ts +6 -0
- package/dist/components/fields/NumericStepperInput.d.ts +6 -0
- package/dist/components/fields/PhoneInput.d.ts +6 -0
- package/dist/components/fields/RadioInput.d.ts +13 -0
- package/dist/components/fields/RatingInput.d.ts +6 -0
- package/dist/components/fields/Separator.d.ts +20 -0
- package/dist/components/fields/SliderInput.d.ts +22 -0
- package/dist/components/fields/SpinInput.d.ts +6 -0
- package/dist/components/fields/SwitchInput.d.ts +13 -0
- package/dist/components/fields/TextInput.d.ts +6 -0
- package/dist/components/fields/TimeInput.d.ts +6 -0
- package/dist/components/fields/UnitValueInput.d.ts +5 -0
- package/dist/components/fields/UrlInput.d.ts +21 -0
- package/dist/components/renderFields.d.ts +4 -0
- package/dist/core/fieldVisibility.d.ts +25 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/reactaFormModel.d.ts +38 -0
- package/dist/core/reactaFormTypes.d.ts +137 -0
- package/dist/core/registries/baseRegistry.d.ts +15 -0
- package/dist/core/registries/componentRegistry.d.ts +9 -0
- package/dist/core/registries/index.d.ts +7 -0
- package/dist/core/registries/submissionHandlerRegistry.d.ts +6 -0
- package/dist/core/registries/validationHandlerRegistry.d.ts +16 -0
- package/dist/core/submitForm.d.ts +12 -0
- package/dist/core/validation.d.ts +10 -0
- package/dist/hooks/useDebouncedCallback.d.ts +25 -0
- package/dist/hooks/useReactaFormContext.d.ts +4 -0
- package/dist/index.d.ts +15 -0
- package/dist/reactaform.cjs.js +289 -0
- package/dist/reactaform.css +1 -0
- package/dist/reactaform.es.js +5085 -0
- package/dist/templates/conditionalAddress.d.ts +3 -0
- package/dist/templates/contactForm.d.ts +3 -0
- package/dist/templates/optionsAndParents.d.ts +3 -0
- package/dist/templates/surveyForm.d.ts +3 -0
- package/dist/utils/cssClasses.d.ts +14 -0
- package/dist/utils/definitionSerializers.d.ts +62 -0
- package/dist/utils/groupingHelpers.d.ts +24 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/translationCache.d.ts +43 -0
- package/dist/utils/unitValueMapper.d.ts +8 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 yanggmtl
|
|
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,499 @@
|
|
|
1
|
+
# ReactaForm
|
|
2
|
+
|
|
3
|
+
A powerful, type-safe React form builder library with dynamic field rendering, conditional visibility, multi-language support, and extensible validation. Built with TypeScript and React 19+.
|
|
4
|
+
|
|
5
|
+
## ✨ Features
|
|
6
|
+
|
|
7
|
+
- 🎯 **Type-Safe**: Full TypeScript support with generic field types
|
|
8
|
+
- 🎨 **Themeable**: CSS variables for easy customization (light/dark mode built-in)
|
|
9
|
+
- 🌍 **i18n Ready**: Built-in internationalization with translation caching
|
|
10
|
+
- 🔌 **Extensible**: Registry pattern for custom components, validators, and handlers
|
|
11
|
+
- ⚡ **Performance**: Virtual scrolling, debounced inputs, RAF-based state management
|
|
12
|
+
- 🎭 **Conditional Logic**: Field visibility based on parent field values
|
|
13
|
+
- 📱 **Responsive**: Works seamlessly across devices
|
|
14
|
+
- ♿ **Accessible**: ARIA attributes and keyboard navigation support
|
|
15
|
+
- 🧩 **20+ Field Types**: Text, email, phone, dropdown, checkbox, slider, rating, date, file upload, and more
|
|
16
|
+
|
|
17
|
+
## 📦 Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install reactaform react react-dom
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Peer Dependencies:**
|
|
24
|
+
- React ^19.2.0
|
|
25
|
+
- React-DOM ^19.2.0
|
|
26
|
+
|
|
27
|
+
## 🌐 Environment Compatibility
|
|
28
|
+
|
|
29
|
+
ReactaForm is **bundler-agnostic** and works seamlessly across different build tools:
|
|
30
|
+
|
|
31
|
+
✅ **Vite** - Fully supported (recommended)
|
|
32
|
+
✅ **Webpack** (Create React App) - Fully supported
|
|
33
|
+
✅ **Next.js** - Fully supported
|
|
34
|
+
✅ **Parcel, esbuild, Rollup** - Fully supported
|
|
35
|
+
|
|
36
|
+
The library gracefully handles environment-specific APIs (`import.meta.env`, `process.env`) with automatic fallbacks. No special configuration needed!
|
|
37
|
+
|
|
38
|
+
### TypeScript Setup (Non-Vite Projects)
|
|
39
|
+
|
|
40
|
+
If you see TypeScript errors about CSS imports in non-Vite projects, add a `global.d.ts`:
|
|
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
|
+
```
|
|
50
|
+
|
|
51
|
+
## 🚀 Quick Start
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { ReactaForm, createInstanceFromDefinition } from 'reactaform';
|
|
55
|
+
import { useState } from 'react';
|
|
56
|
+
|
|
57
|
+
const definition = {
|
|
58
|
+
name: "contactForm",
|
|
59
|
+
version: "1.0",
|
|
60
|
+
displayName: "Contact Form",
|
|
61
|
+
properties: [
|
|
62
|
+
{
|
|
63
|
+
name: "fullName",
|
|
64
|
+
displayName: "Full Name",
|
|
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
|
+
}
|
|
83
|
+
]
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
function App() {
|
|
87
|
+
// Create an instance from the definition
|
|
88
|
+
const result = createInstanceFromDefinition(definition, "myForm");
|
|
89
|
+
const [instance, setInstance] = useState(result.instance);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<ReactaForm
|
|
93
|
+
definitionData={definition}
|
|
94
|
+
instance={instance}
|
|
95
|
+
language="en"
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> **Note**: `ReactaForm` manages form state internally. If you need to programmatically update values, use `setInstance()` with a new instance object.
|
|
102
|
+
|
|
103
|
+
## 📖 Core Concepts
|
|
104
|
+
|
|
105
|
+
### Form Definitions
|
|
106
|
+
|
|
107
|
+
A form definition is a JSON object that describes the structure of your form:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
interface ReactaDefinition {
|
|
111
|
+
name: string; // Unique form identifier
|
|
112
|
+
version: string; // Version for tracking changes
|
|
113
|
+
displayName: string; // Human-readable form title
|
|
114
|
+
properties: FieldDefinition[]; // Array of field definitions
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Field Types
|
|
119
|
+
|
|
120
|
+
ReactaForm supports 20+ field types out of the box:
|
|
121
|
+
|
|
122
|
+
| Type | Description | Example |
|
|
123
|
+
|------|-------------|---------|
|
|
124
|
+
| `string` | Single-line text input | Name, username |
|
|
125
|
+
| `text` | Multi-line text area | Comments, descriptions |
|
|
126
|
+
| `email` | Email with validation | user@example.com |
|
|
127
|
+
| `phone` | Phone number input | +1 (555) 123-4567 |
|
|
128
|
+
| `url` | URL with validation | https://example.com |
|
|
129
|
+
| `integer` | Whole numbers | Age, quantity |
|
|
130
|
+
| `float` | Decimal numbers | Price, weight |
|
|
131
|
+
| `boolean` | Checkbox | Accept terms |
|
|
132
|
+
| `dropdown` | Select from options | Country, category |
|
|
133
|
+
| `radio` | Radio button group | Gender, size |
|
|
134
|
+
| `multiSelection` | Multiple checkboxes | Interests, tags |
|
|
135
|
+
| `slider` | Range slider | Volume, brightness |
|
|
136
|
+
| `rating` | Star rating | Product rating |
|
|
137
|
+
| `date` | Date picker | Birth date |
|
|
138
|
+
| `dateTime` | Date and time picker | Appointment |
|
|
139
|
+
| `time` | Time picker | Meeting time |
|
|
140
|
+
| `color` | Color picker | Theme color |
|
|
141
|
+
| `file` | File upload | Documents, images |
|
|
142
|
+
| `image` | Image display | Preview, thumbnail |
|
|
143
|
+
| `unitValue` | Value with unit conversion | 100 cm → 1 m |
|
|
144
|
+
|
|
145
|
+
### Conditional Visibility
|
|
146
|
+
|
|
147
|
+
Fields can be conditionally shown/hidden based on parent field values:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
{
|
|
151
|
+
name: "country",
|
|
152
|
+
displayName: "Country",
|
|
153
|
+
type: "dropdown",
|
|
154
|
+
options: [
|
|
155
|
+
{ label: "United States", value: "US" },
|
|
156
|
+
{ label: "Canada", value: "CA" }
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: "state",
|
|
161
|
+
displayName: "State/Province",
|
|
162
|
+
type: "dropdown",
|
|
163
|
+
parents: {
|
|
164
|
+
country: ["US", "CA"] // Only show when country is US or CA
|
|
165
|
+
},
|
|
166
|
+
options: [
|
|
167
|
+
{ label: "California", value: "CA" },
|
|
168
|
+
{ label: "Ontario", value: "ON" }
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Validation
|
|
174
|
+
|
|
175
|
+
Built-in validation for common patterns:
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
{
|
|
179
|
+
name: "email",
|
|
180
|
+
displayName: "Email Address",
|
|
181
|
+
type: "email",
|
|
182
|
+
required: true, // Field is required
|
|
183
|
+
pattern: "^[a-z]+$", // Custom regex pattern (optional)
|
|
184
|
+
minLength: 5, // Minimum length (optional)
|
|
185
|
+
maxLength: 100, // Maximum length (optional)
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 🎨 Theming
|
|
190
|
+
|
|
191
|
+
ReactaForm uses CSS variables for easy theming:
|
|
192
|
+
|
|
193
|
+
```css
|
|
194
|
+
:root {
|
|
195
|
+
/* Colors */
|
|
196
|
+
--reactaform-color-primary: #2563eb;
|
|
197
|
+
--reactaform-color-error: #ef4444;
|
|
198
|
+
--reactaform-color-success: #10b981;
|
|
199
|
+
|
|
200
|
+
/* Typography */
|
|
201
|
+
--reactaform-font-family: system-ui, sans-serif;
|
|
202
|
+
--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
|
+
--reactaform-input-bg: #ffffff;
|
|
216
|
+
--reactaform-input-padding: 8px 12px;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* Dark mode */
|
|
220
|
+
[data-reactaform-theme="dark"] {
|
|
221
|
+
--reactaform-bg-primary: #1A1A1A;
|
|
222
|
+
--reactaform-text-color: #EDEDED;
|
|
223
|
+
--reactaform-input-bg: #2A2A2A;
|
|
224
|
+
--reactaform-border-color: #3A3A3A;
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Using Dark Mode
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
<ReactaForm
|
|
232
|
+
definitionData={definition}
|
|
233
|
+
instance={formData}
|
|
234
|
+
darkMode={true} // Enable dark mode
|
|
235
|
+
/>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## 🌍 Internationalization
|
|
239
|
+
|
|
240
|
+
ReactaForm supports multiple languages:
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
<ReactaForm
|
|
244
|
+
definitionData={definition}
|
|
245
|
+
instance={formData}
|
|
246
|
+
language="fr" // 'en', 'fr', 'de', 'es', 'zh-cn'
|
|
247
|
+
/>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Custom Translations
|
|
251
|
+
|
|
252
|
+
Provide custom translations for your form:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// public/locales/fr/myform.json
|
|
256
|
+
{
|
|
257
|
+
"Full Name": "Nom complet",
|
|
258
|
+
"Email": "Courriel",
|
|
259
|
+
"Submit": "Soumettre"
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## 🔧 Advanced Usage
|
|
264
|
+
|
|
265
|
+
### Custom Field Components
|
|
266
|
+
|
|
267
|
+
Register custom field components:
|
|
268
|
+
|
|
269
|
+
```tsx
|
|
270
|
+
import { registerComponent } from 'reactaform';
|
|
271
|
+
|
|
272
|
+
const CustomInput = ({ field, value, onChange }) => {
|
|
273
|
+
return (
|
|
274
|
+
<input
|
|
275
|
+
value={value}
|
|
276
|
+
onChange={(e) => onChange(e.target.value, null)}
|
|
277
|
+
placeholder={field.displayName}
|
|
278
|
+
/>
|
|
279
|
+
);
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
registerComponent('customType', CustomInput);
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Custom Validation
|
|
286
|
+
|
|
287
|
+
Register custom validators:
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
import { registerValidationHandler } from 'reactaform';
|
|
291
|
+
|
|
292
|
+
registerValidationHandler('customType', (value, field) => {
|
|
293
|
+
if (value.length < 10) {
|
|
294
|
+
return "Value must be at least 10 characters";
|
|
295
|
+
}
|
|
296
|
+
return null; // No error
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Form Submission
|
|
301
|
+
|
|
302
|
+
Handle form submission with custom logic:
|
|
303
|
+
|
|
304
|
+
```tsx
|
|
305
|
+
import { registerSubmissionHandler } from 'reactaform';
|
|
306
|
+
|
|
307
|
+
// Register a submission handler for your form
|
|
308
|
+
registerSubmissionHandler(
|
|
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
|
+
```
|
|
335
|
+
|
|
336
|
+
**Then reference it in your definition:**
|
|
337
|
+
|
|
338
|
+
```tsx
|
|
339
|
+
const definition = {
|
|
340
|
+
name: "contactForm",
|
|
341
|
+
submitHandlerName: "mySubmitHandler", // Link to registered handler
|
|
342
|
+
// ... rest of definition
|
|
343
|
+
};
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Using ReactaFormProvider
|
|
347
|
+
|
|
348
|
+
Wrap your app for global configuration:
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
import { ReactaFormProvider, ReactaFormRenderer } from 'reactaform';
|
|
352
|
+
|
|
353
|
+
function App() {
|
|
354
|
+
return (
|
|
355
|
+
<ReactaFormProvider
|
|
356
|
+
defaultLanguage="en"
|
|
357
|
+
defaultDarkMode={false}
|
|
358
|
+
defaultDefinitionName="myForm"
|
|
359
|
+
>
|
|
360
|
+
<ReactaFormRenderer
|
|
361
|
+
properties={definition.properties}
|
|
362
|
+
instance={formData}
|
|
363
|
+
/>
|
|
364
|
+
</ReactaFormProvider>
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## 📚 API Reference
|
|
370
|
+
|
|
371
|
+
### ReactaForm Props
|
|
372
|
+
|
|
373
|
+
| Prop | Type | Required | Description |
|
|
374
|
+
|------|------|----------|-------------|
|
|
375
|
+
| `definitionData` | `ReactaDefinition \| string` | Yes | Form definition object or JSON string |
|
|
376
|
+
| `instance` | `ReactaInstance` | No* | Form instance with values and metadata. If not provided, will be auto-created from definition |
|
|
377
|
+
| `language` | `string` | No | Language code (default: 'en') |
|
|
378
|
+
| `darkMode` | `boolean` | No | Enable dark mode (default: auto-detect from parent theme) |
|
|
379
|
+
| `className` | `string` | No | Custom CSS class |
|
|
380
|
+
| `style` | `CSSProperties` | No | Custom inline styles |
|
|
381
|
+
|
|
382
|
+
*While `instance` is technically optional (auto-created if omitted), providing it is recommended for proper state management.
|
|
383
|
+
|
|
384
|
+
### Field Definition Props
|
|
385
|
+
|
|
386
|
+
| Prop | Type | Required | Description |
|
|
387
|
+
|------|------|----------|-------------|
|
|
388
|
+
| `name` | `string` | Yes | Unique field identifier |
|
|
389
|
+
| `displayName` | `string` | Yes | Field label |
|
|
390
|
+
| `type` | `string` | Yes | Field type (see Field Types) |
|
|
391
|
+
| `defaultValue` | `any` | No | Default field value |
|
|
392
|
+
| `required` | `boolean` | No | Field is required |
|
|
393
|
+
| `disabled` | `boolean` | No | Field is disabled |
|
|
394
|
+
| `readOnly` | `boolean` | No | Field is read-only |
|
|
395
|
+
| `tooltip` | `string` | No | Tooltip text |
|
|
396
|
+
| `placeholder` | `string` | No | Placeholder text |
|
|
397
|
+
| `options` | `Option[]` | No | Options for dropdown/radio/multi-selection |
|
|
398
|
+
| `parents` | `Record<string, string[]>` | No | Conditional visibility rules |
|
|
399
|
+
| `pattern` | `string` | No | Regex validation pattern |
|
|
400
|
+
| `minLength` | `number` | No | Minimum input length |
|
|
401
|
+
| `maxLength` | `number` | No | Maximum input length |
|
|
402
|
+
| `min` | `number` | No | Minimum numeric value |
|
|
403
|
+
| `max` | `number` | No | Maximum numeric value |
|
|
404
|
+
| `step` | `number` | No | Numeric step increment |
|
|
405
|
+
| `labelLayout` | `'row' \| 'column' \| 'column-center'` | No | Label positioning |
|
|
406
|
+
|
|
407
|
+
## 🧪 Testing
|
|
408
|
+
|
|
409
|
+
ReactaForm uses Vitest for testing:
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
npm run test # Run all tests
|
|
413
|
+
npm run typecheck # Type checking
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## 🏗️ Building
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
npm run build:lib # Build library
|
|
420
|
+
npm run pack:staging # Create .tgz package
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Output formats:
|
|
424
|
+
- **ESM**: `dist/reactaform.es.js`
|
|
425
|
+
- **CommonJS**: `dist/reactaform.cjs.js`
|
|
426
|
+
- **UMD**: `dist/reactaform.umd.js`
|
|
427
|
+
- **Types**: `dist/index.d.ts`
|
|
428
|
+
|
|
429
|
+
## 📄 License
|
|
430
|
+
|
|
431
|
+
MIT
|
|
432
|
+
|
|
433
|
+
## 🤝 Contributing
|
|
434
|
+
|
|
435
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
436
|
+
|
|
437
|
+
## 🐛 Known Issues
|
|
438
|
+
|
|
439
|
+
- Virtual scrolling optimization in progress for forms with 1000+ fields
|
|
440
|
+
- Screen reader testing ongoing for complex conditional fields
|
|
441
|
+
|
|
442
|
+
## 🗺️ Roadmap
|
|
443
|
+
|
|
444
|
+
- [ ] Enhanced accessibility audit
|
|
445
|
+
- [ ] More built-in validators
|
|
446
|
+
- [ ] Form builder UI
|
|
447
|
+
- [ ] Schema migration tools
|
|
448
|
+
- [ ] Performance profiling dashboard
|
|
449
|
+
|
|
450
|
+
## 🔍 Troubleshooting
|
|
451
|
+
|
|
452
|
+
### "Cannot find module './style.css'"
|
|
453
|
+
|
|
454
|
+
**Solution**: Add a `global.d.ts` file (see Environment Compatibility section above).
|
|
455
|
+
|
|
456
|
+
### Form not updating when instance changes
|
|
457
|
+
|
|
458
|
+
**Solution**: Ensure you're passing a **new instance object** (immutable updates):
|
|
459
|
+
|
|
460
|
+
```tsx
|
|
461
|
+
// ✅ Correct - creates new object
|
|
462
|
+
setInstance({ ...instance, values: { ...instance.values, name: 'John' } });
|
|
463
|
+
|
|
464
|
+
// ❌ Wrong - mutates existing object
|
|
465
|
+
instance.values.name = 'John';
|
|
466
|
+
setInstance(instance);
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Submission handler not called
|
|
470
|
+
|
|
471
|
+
**Solution**: Ensure `submitHandlerName` in your definition matches the registered handler name:
|
|
472
|
+
|
|
473
|
+
```tsx
|
|
474
|
+
registerSubmissionHandler('myHandler', ...);
|
|
475
|
+
// Definition must have: submitHandlerName: "myHandler"
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### TypeScript errors about `import.meta` or `process`
|
|
479
|
+
|
|
480
|
+
**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.
|
|
481
|
+
|
|
482
|
+
### Dark mode not working
|
|
483
|
+
|
|
484
|
+
**Solution**: Either pass `darkMode={true}` prop, or wrap your app with `[data-reactaform-theme="dark"]` attribute on a parent element.
|
|
485
|
+
|
|
486
|
+
## 💡 Examples
|
|
487
|
+
|
|
488
|
+
Check the `packages/apps` directory for complete working examples:
|
|
489
|
+
- **instance-app** - Create, load, and edit multiple form instances
|
|
490
|
+
- **group-app** - Organize fields into logical groups
|
|
491
|
+
- **parents-app** - Conditional field visibility based on parent values
|
|
492
|
+
- **custom-validation-app** - Custom validation rules
|
|
493
|
+
- **translation-app** - Multi-language forms with custom translations
|
|
494
|
+
- **dark-mode-app** - Light/dark theme switching
|
|
495
|
+
- **submit-handler-app** - Custom submission handlers
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
**Built with ❤️ using React and TypeScript**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="Absenden",t="Rot",n="Blau",s="Grün",a="Gelb",i="Lila",r="Cyan",l="Magenta",o="Schwarz",m="Weiß",u="Orange",d="Grau",h="Braun",c="Rosa",g="Benutzerdefiniert",b="Erhöhen",f="Verringern",M="Zeitzone",D={Submit:e,"Please fix validation errors before submitting.":"Bitte beheben Sie die Validierungsfehler vor dem Absenden.","Data transformation errors occurred.":"Datentransformationsfehler sind aufgetreten.","Validation errors occurred.":"Validierungsfehler sind aufgetreten.","Submission failed.":"Das Absenden ist fehlgeschlagen.","Submission handler error occurred.":"Ein Fehler im Übermittlungshandler ist aufgetreten.","Form submitted successfully.":"Formular erfolgreich übermittelt.",Red:t,Blue:n,Green:s,Yellow:a,Purple:i,Cyan:r,Magenta:l,Black:o,White:m,Orange:u,Gray:d,Brown:h,Pink:c,"Light Gray":"Hellgrau",Custom:g,"Value required":"Wert erforderlich","Invalid option selected":"Ungültige Option ausgewählt","Must be a valid integer":"Muss eine gültige Ganzzahl sein","Must be an integer":"Muss eine Ganzzahl sein","Must be a valid float":"Muss eine gültige Gleitkommazahl sein","Must be a valid number":"Muss eine gültige Zahl sein","Invalid number":"Ungültige Zahl","Must be ≥{{1}}":"Muss ≥{{1}} sein","Must be ≤{{1}}":"Muss ≤{{1}} sein","Value should be at least {{1}}":"Der Wert sollte mindestens {{1}} sein","Value should be at most {{1}}":"Der Wert sollte höchstens {{1}} sein","Must be at least {{1}} characters":"Muss mindestens {{1}} Zeichen lang sein","Must be at most {{1}} characters":"Darf höchstens {{1}} Zeichen lang sein","Input does not match pattern: {{1}}":"Eingabe stimmt nicht mit dem Muster überein: {{1}}","Must be valid email format":"Muss ein gültiges E-Mail-Format sein","Email does not match pattern: {{%1}}":"E-Mail stimmt nicht mit dem Muster überein: {{%1}}","Must be a valid URL":"Muss eine gültige URL sein","Phone number does not match pattern: {{1}}":"Telefonnummer stimmt nicht mit dem Muster überein: {{1}}","Each value must be a valid integer":"Jeder Wert muss eine gültige Ganzzahl sein","Each value must be a valid float":"Jeder Wert muss eine gültige Gleitkommazahl sein","Minimum number of values: {{1}}":"Minimale Anzahl an Werten: {{1}}","Maximum number of values: {{1}}":"Maximale Anzahl an Werten: {{1}}","Minimum number of rows: {{1}}":"Mindestanzahl von Zeilen: {{1}}","Maximum number of rows: {{1}}":"Höchstanzahl von Zeilen: {{1}}","Invalid date format":"Ungültiges Datumsformat","Invalid date/time":"Ungültiges Datum/Uhrzeit","Invalid time format":"Ungültiges Uhrzeitformat","Date must be on or after {{1}}":"Das Datum muss am {{1}} oder danach sein","Date must be on or before {{1}}":"Das Datum muss am {{1}} oder davor sein","Date/time must be on or after {{1}}":"Datum/Uhrzeit muss am {{1}} oder danach sein","Date/time must be on or before {{1}}":"Datum/Uhrzeit muss am {{1}} oder davor sein","Time must be on or after {{1}}":"Die Uhrzeit muss {{1}} oder danach sein","Time must be on or before {{1}}":"Die Uhrzeit muss {{1}} oder davor sein","Choose File...":"Datei auswählen...","Choose Files...":"Dateien auswählen...","No file selected":"Keine Datei ausgewählt","Show selected files":"Ausgewählte Dateien anzeigen","Selected File":"Ausgewählte Datei","Selected Files":"Ausgewählte Dateien",Increment:b,Decrement:f,Timezone:M};exports.Black=o;exports.Blue=n;exports.Brown=h;exports.Custom=g;exports.Cyan=r;exports.Decrement=f;exports.Gray=d;exports.Green=s;exports.Increment=b;exports.Magenta=l;exports.Orange=u;exports.Pink=c;exports.Purple=i;exports.Red=t;exports.Submit=e;exports.Timezone=M;exports.White=m;exports.Yellow=a;exports.default=D;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const e = "Absenden", M = "Rot", t = "Blau", n = "Grün", s = "Gelb", a = "Lila", i = "Cyan", r = "Magenta", l = "Schwarz", o = "Weiß", m = "Orange", u = "Grau", d = "Braun", h = "Rosa", c = "Benutzerdefiniert", g = "Erhöhen", b = "Verringern", f = "Zeitzone", D = {
|
|
2
|
+
Submit: e,
|
|
3
|
+
"Please fix validation errors before submitting.": "Bitte beheben Sie die Validierungsfehler vor dem Absenden.",
|
|
4
|
+
"Data transformation errors occurred.": "Datentransformationsfehler sind aufgetreten.",
|
|
5
|
+
"Validation errors occurred.": "Validierungsfehler sind aufgetreten.",
|
|
6
|
+
"Submission failed.": "Das Absenden ist fehlgeschlagen.",
|
|
7
|
+
"Submission handler error occurred.": "Ein Fehler im Übermittlungshandler ist aufgetreten.",
|
|
8
|
+
"Form submitted successfully.": "Formular erfolgreich übermittelt.",
|
|
9
|
+
Red: "Rot",
|
|
10
|
+
Blue: t,
|
|
11
|
+
Green: n,
|
|
12
|
+
Yellow: s,
|
|
13
|
+
Purple: a,
|
|
14
|
+
Cyan: i,
|
|
15
|
+
Magenta: r,
|
|
16
|
+
Black: l,
|
|
17
|
+
White: o,
|
|
18
|
+
Orange: m,
|
|
19
|
+
Gray: u,
|
|
20
|
+
Brown: d,
|
|
21
|
+
Pink: h,
|
|
22
|
+
"Light Gray": "Hellgrau",
|
|
23
|
+
Custom: c,
|
|
24
|
+
"Value required": "Wert erforderlich",
|
|
25
|
+
"Invalid option selected": "Ungültige Option ausgewählt",
|
|
26
|
+
"Must be a valid integer": "Muss eine gültige Ganzzahl sein",
|
|
27
|
+
"Must be an integer": "Muss eine Ganzzahl sein",
|
|
28
|
+
"Must be a valid float": "Muss eine gültige Gleitkommazahl sein",
|
|
29
|
+
"Must be a valid number": "Muss eine gültige Zahl sein",
|
|
30
|
+
"Invalid number": "Ungültige Zahl",
|
|
31
|
+
"Must be ≥{{1}}": "Muss ≥{{1}} sein",
|
|
32
|
+
"Must be ≤{{1}}": "Muss ≤{{1}} sein",
|
|
33
|
+
"Value should be at least {{1}}": "Der Wert sollte mindestens {{1}} sein",
|
|
34
|
+
"Value should be at most {{1}}": "Der Wert sollte höchstens {{1}} sein",
|
|
35
|
+
"Must be at least {{1}} characters": "Muss mindestens {{1}} Zeichen lang sein",
|
|
36
|
+
"Must be at most {{1}} characters": "Darf höchstens {{1}} Zeichen lang sein",
|
|
37
|
+
"Input does not match pattern: {{1}}": "Eingabe stimmt nicht mit dem Muster überein: {{1}}",
|
|
38
|
+
"Must be valid email format": "Muss ein gültiges E-Mail-Format sein",
|
|
39
|
+
"Email does not match pattern: {{%1}}": "E-Mail stimmt nicht mit dem Muster überein: {{%1}}",
|
|
40
|
+
"Must be a valid URL": "Muss eine gültige URL sein",
|
|
41
|
+
"Phone number does not match pattern: {{1}}": "Telefonnummer stimmt nicht mit dem Muster überein: {{1}}",
|
|
42
|
+
"Each value must be a valid integer": "Jeder Wert muss eine gültige Ganzzahl sein",
|
|
43
|
+
"Each value must be a valid float": "Jeder Wert muss eine gültige Gleitkommazahl sein",
|
|
44
|
+
"Minimum number of values: {{1}}": "Minimale Anzahl an Werten: {{1}}",
|
|
45
|
+
"Maximum number of values: {{1}}": "Maximale Anzahl an Werten: {{1}}",
|
|
46
|
+
"Minimum number of rows: {{1}}": "Mindestanzahl von Zeilen: {{1}}",
|
|
47
|
+
"Maximum number of rows: {{1}}": "Höchstanzahl von Zeilen: {{1}}",
|
|
48
|
+
"Invalid date format": "Ungültiges Datumsformat",
|
|
49
|
+
"Invalid date/time": "Ungültiges Datum/Uhrzeit",
|
|
50
|
+
"Invalid time format": "Ungültiges Uhrzeitformat",
|
|
51
|
+
"Date must be on or after {{1}}": "Das Datum muss am {{1}} oder danach sein",
|
|
52
|
+
"Date must be on or before {{1}}": "Das Datum muss am {{1}} oder davor sein",
|
|
53
|
+
"Date/time must be on or after {{1}}": "Datum/Uhrzeit muss am {{1}} oder danach sein",
|
|
54
|
+
"Date/time must be on or before {{1}}": "Datum/Uhrzeit muss am {{1}} oder davor sein",
|
|
55
|
+
"Time must be on or after {{1}}": "Die Uhrzeit muss {{1}} oder danach sein",
|
|
56
|
+
"Time must be on or before {{1}}": "Die Uhrzeit muss {{1}} oder davor sein",
|
|
57
|
+
"Choose File...": "Datei auswählen...",
|
|
58
|
+
"Choose Files...": "Dateien auswählen...",
|
|
59
|
+
"No file selected": "Keine Datei ausgewählt",
|
|
60
|
+
"Show selected files": "Ausgewählte Dateien anzeigen",
|
|
61
|
+
"Selected File": "Ausgewählte Datei",
|
|
62
|
+
"Selected Files": "Ausgewählte Dateien",
|
|
63
|
+
Increment: g,
|
|
64
|
+
Decrement: b,
|
|
65
|
+
Timezone: f
|
|
66
|
+
};
|
|
67
|
+
export {
|
|
68
|
+
l as Black,
|
|
69
|
+
t as Blue,
|
|
70
|
+
d as Brown,
|
|
71
|
+
c as Custom,
|
|
72
|
+
i as Cyan,
|
|
73
|
+
b as Decrement,
|
|
74
|
+
u as Gray,
|
|
75
|
+
n as Green,
|
|
76
|
+
g as Increment,
|
|
77
|
+
r as Magenta,
|
|
78
|
+
m as Orange,
|
|
79
|
+
h as Pink,
|
|
80
|
+
a as Purple,
|
|
81
|
+
M as Red,
|
|
82
|
+
e as Submit,
|
|
83
|
+
f as Timezone,
|
|
84
|
+
o as White,
|
|
85
|
+
s as Yellow,
|
|
86
|
+
D as default
|
|
87
|
+
};
|