extended-dynamic-forms 0.2.0 → 0.2.1

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.
@@ -1,371 +0,0 @@
1
- import React from 'react';
2
- import { ExtendedForm } from '../src/ExtendedForm';
3
- import { RJSFSchema, UiSchema, IChangeEvent } from '@rjsf/utils';
4
- import { useConditionalUi, UiRule, JsonLogicRule } from '../src/conditionals/v2';
5
-
6
- /**
7
- * Global UI Rules Example
8
- *
9
- * This example demonstrates the UI Logic Pillar of the Three Pillars architecture.
10
- * It shows how to:
11
- * 1. Show/hide form sections based on conditions
12
- * 2. Dynamically change widget types
13
- * 3. Modify field ordering based on user input
14
- * 4. Handle data clearing in the onChange handler (separation of concerns)
15
- */
16
-
17
- // Type definition for our form data
18
- type ShippingFormData = {
19
- name: string;
20
- email: string;
21
- requiresShipping: boolean;
22
- shippingAddress?: {
23
- street?: string;
24
- city?: string;
25
- zipCode?: string;
26
- country?: 'USA' | 'Canada' | 'Mexico' | 'Other';
27
- state?: string;
28
- province?: string;
29
- region?: string;
30
- internationalDetails?: string;
31
- };
32
- deliveryInstructions?: string;
33
- expressShipping?: boolean;
34
- };
35
-
36
- // Schema definition for a comprehensive shipping form
37
- const schema: RJSFSchema = {
38
- type: 'object',
39
- required: ['name', 'email'],
40
- properties: {
41
- name: {
42
- type: 'string',
43
- title: 'Full Name'
44
- },
45
- email: {
46
- type: 'string',
47
- format: 'email',
48
- title: 'Email Address'
49
- },
50
- requiresShipping: {
51
- type: 'boolean',
52
- title: 'Requires Physical Shipping?',
53
- default: false
54
- },
55
- shippingAddress: {
56
- type: 'object',
57
- title: 'Shipping Address',
58
- required: ['street', 'city', 'zipCode', 'country'],
59
- properties: {
60
- street: {
61
- type: 'string',
62
- title: 'Street Address'
63
- },
64
- city: {
65
- type: 'string',
66
- title: 'City'
67
- },
68
- zipCode: {
69
- type: 'string',
70
- title: 'ZIP/Postal Code'
71
- },
72
- country: {
73
- type: 'string',
74
- title: 'Country',
75
- enum: ['USA', 'Canada', 'Mexico', 'Other'],
76
- default: 'USA'
77
- },
78
- // Different fields for different countries
79
- state: {
80
- type: 'string',
81
- title: 'State',
82
- enum: ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'FL', 'GA',
83
- 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD',
84
- 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ',
85
- 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC',
86
- 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY']
87
- },
88
- province: {
89
- type: 'string',
90
- title: 'Province',
91
- enum: ['AB', 'BC', 'MB', 'NB', 'NL', 'NS', 'NT', 'NU', 'ON', 'PE', 'QC', 'SK', 'YT']
92
- },
93
- region: {
94
- type: 'string',
95
- title: 'State/Province/Region'
96
- },
97
- internationalDetails: {
98
- type: 'string',
99
- title: 'International Shipping Details',
100
- description: 'Please provide any special international shipping requirements'
101
- }
102
- }
103
- },
104
- deliveryInstructions: {
105
- type: 'string',
106
- title: 'Delivery Instructions',
107
- description: 'Special instructions for the delivery person'
108
- },
109
- expressShipping: {
110
- type: 'boolean',
111
- title: 'Express Shipping (2-3 days)',
112
- default: false
113
- }
114
- }
115
- };
116
-
117
- // Base UI Schema - defines the default UI configuration
118
- const baseUiSchema: UiSchema = {
119
- 'ui:order': ['name', 'email', 'requiresShipping', 'shippingAddress', 'expressShipping', 'deliveryInstructions'],
120
- name: {
121
- 'ui:autofocus': true,
122
- 'ui:placeholder': 'Enter your full name'
123
- },
124
- email: {
125
- 'ui:placeholder': 'email@example.com',
126
- 'ui:help': 'We\'ll use this for order confirmation'
127
- },
128
- shippingAddress: {
129
- // Initially hidden until shipping is required
130
- 'ui:widget': 'hidden',
131
- 'ui:order': ['street', 'city', 'country', 'state', 'province', 'region', 'zipCode'],
132
- street: {
133
- 'ui:placeholder': '123 Main St'
134
- },
135
- city: {
136
- 'ui:placeholder': 'New York'
137
- },
138
- zipCode: {
139
- 'ui:placeholder': '10001'
140
- },
141
- state: {
142
- 'ui:widget': 'select',
143
- 'ui:placeholder': 'Select a state'
144
- },
145
- province: {
146
- 'ui:placeholder': 'Select a province',
147
- // Initially hidden
148
- 'ui:widget': 'hidden'
149
- },
150
- region: {
151
- 'ui:placeholder': 'Enter state/province/region',
152
- // Initially hidden
153
- 'ui:widget': 'hidden'
154
- },
155
- internationalDetails: {
156
- 'ui:widget': 'hidden', // Hidden by default
157
- 'ui:options': {
158
- rows: 3
159
- }
160
- }
161
- },
162
- deliveryInstructions: {
163
- 'ui:widget': 'hidden',
164
- 'ui:options': {
165
- rows: 3
166
- }
167
- },
168
- expressShipping: {
169
- 'ui:widget': 'hidden'
170
- }
171
- };
172
-
173
- // Global UI Rules using JSON Patch operations
174
- const globalUiRules: UiRule[] = [
175
- // Rule 1: Show shipping address when shipping is required
176
- {
177
- name: 'Show shipping address when shipping required',
178
- condition: { "===": [{ "var": "requiresShipping" }, true] } as JsonLogicRule,
179
- effect: [
180
- { op: 'remove', path: '/shippingAddress/ui:widget' }
181
- ],
182
- order: 1
183
- },
184
-
185
- // Rule 2: Show delivery instructions when shipping is required
186
- {
187
- name: 'Show delivery instructions when shipping required',
188
- condition: { "===": [{ "var": "requiresShipping" }, true] } as JsonLogicRule,
189
- effect: [
190
- { op: 'replace', path: '/deliveryInstructions/ui:widget', value: 'textarea' }
191
- ],
192
- order: 2
193
- },
194
-
195
- // Rule 3: Show express shipping option when shipping is required
196
- {
197
- name: 'Show express shipping option when shipping required',
198
- condition: { "===": [{ "var": "requiresShipping" }, true] } as JsonLogicRule,
199
- effect: [
200
- { op: 'remove', path: '/expressShipping/ui:widget' }
201
- ],
202
- order: 3
203
- },
204
-
205
- // Rule 4: Show state dropdown only for USA
206
- {
207
- name: 'Show state field for USA',
208
- condition: {
209
- "and": [
210
- { "===": [{ "var": "requiresShipping" }, true] },
211
- { "===": [{ "var": "shippingAddress.country" }, "USA"] }
212
- ]
213
- } as JsonLogicRule,
214
- effect: [
215
- { op: 'remove', path: '/shippingAddress/state/ui:widget' },
216
- { op: 'add', path: '/shippingAddress/province/ui:widget', value: 'hidden' },
217
- { op: 'add', path: '/shippingAddress/region/ui:widget', value: 'hidden' }
218
- ],
219
- order: 4
220
- },
221
-
222
- // Rule 5: Show province dropdown only for Canada
223
- {
224
- name: 'Show province field for Canada',
225
- condition: {
226
- "and": [
227
- { "===": [{ "var": "requiresShipping" }, true] },
228
- { "===": [{ "var": "shippingAddress.country" }, "Canada"] }
229
- ]
230
- } as JsonLogicRule,
231
- effect: [
232
- { op: 'add', path: '/shippingAddress/state/ui:widget', value: 'hidden' },
233
- { op: 'remove', path: '/shippingAddress/province/ui:widget' },
234
- { op: 'add', path: '/shippingAddress/region/ui:widget', value: 'hidden' }
235
- ],
236
- order: 5
237
- },
238
-
239
- // Rule 6: Show region text field for Mexico and Other
240
- {
241
- name: 'Show region field for Mexico and Other countries',
242
- condition: {
243
- "and": [
244
- { "===": [{ "var": "requiresShipping" }, true] },
245
- { "in": [{ "var": "shippingAddress.country" }, ["Mexico", "Other"]] }
246
- ]
247
- } as JsonLogicRule,
248
- effect: [
249
- { op: 'add', path: '/shippingAddress/state/ui:widget', value: 'hidden' },
250
- { op: 'add', path: '/shippingAddress/province/ui:widget', value: 'hidden' },
251
- { op: 'remove', path: '/shippingAddress/region/ui:widget' }
252
- ],
253
- order: 6
254
- },
255
-
256
- // Rule 7: Show international details only for "Other" countries
257
- {
258
- name: 'Show international details for non-North American countries',
259
- condition: {
260
- "and": [
261
- { "===": [{ "var": "requiresShipping" }, true] },
262
- { "===": [{ "var": "shippingAddress.country" }, "Other"] }
263
- ]
264
- } as JsonLogicRule,
265
- effect: [
266
- { op: 'replace', path: '/shippingAddress/internationalDetails/ui:widget', value: 'textarea' }
267
- ],
268
- order: 7
269
- },
270
-
271
- // Rule 8: Reorder fields to put international details at end when visible
272
- {
273
- name: 'Reorder fields for international shipping',
274
- condition: {
275
- "and": [
276
- { "===": [{ "var": "requiresShipping" }, true] },
277
- { "===": [{ "var": "shippingAddress.country" }, "Other"] }
278
- ]
279
- } as JsonLogicRule,
280
- effect: [
281
- {
282
- op: 'replace',
283
- path: '/shippingAddress/ui:order',
284
- value: ['street', 'city', 'country', 'region', 'zipCode', 'internationalDetails']
285
- }
286
- ],
287
- order: 8
288
- }
289
- ];
290
-
291
- export function GlobalUiRulesExample() {
292
- const [formData, setFormData] = React.useState<ShippingFormData>({
293
- name: '',
294
- email: '',
295
- requiresShipping: false,
296
- shippingAddress: {
297
- country: 'USA'
298
- }
299
- });
300
-
301
- // Apply UI rules to base UI schema
302
- // This is a pure function that only modifies the UI schema
303
- const conditionalUiSchema = useConditionalUi(globalUiRules, baseUiSchema, formData);
304
-
305
- // Handle form changes with data side effects
306
- // This demonstrates the separation of concerns between UI and data logic
307
- const handleChange = ({ formData: newFormData }: IChangeEvent<ShippingFormData>) => {
308
- let dataToSet = { ...newFormData };
309
-
310
- // DATA SIDE EFFECT: Clear shipping address when shipping is disabled
311
- if (formData.requiresShipping && !newFormData.requiresShipping) {
312
- dataToSet.shippingAddress = {
313
- country: 'USA' // Reset to default country
314
- };
315
- dataToSet.deliveryInstructions = '';
316
- dataToSet.expressShipping = false;
317
- }
318
-
319
- // DATA SIDE EFFECT: Clear state/province/region when country changes
320
- const oldCountry = formData.shippingAddress?.country;
321
- const newCountry = newFormData.shippingAddress?.country;
322
-
323
- if (oldCountry !== newCountry && newFormData.shippingAddress) {
324
- // Clear location fields when switching countries
325
- delete dataToSet.shippingAddress.state;
326
- delete dataToSet.shippingAddress.province;
327
- delete dataToSet.shippingAddress.region;
328
- delete dataToSet.shippingAddress.internationalDetails;
329
- }
330
-
331
- setFormData(dataToSet);
332
- };
333
-
334
- const handleSubmit = ({ formData }: IChangeEvent<ShippingFormData>) => {
335
- console.log('Form submitted:', formData);
336
- alert('Form submitted! Check console for details.');
337
- };
338
-
339
- return (
340
- <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
341
- <h1>Global UI Rules Example</h1>
342
- <p>
343
- This example demonstrates the UI Logic Pillar of the Three Pillars conditional system.
344
- Try toggling "Requires Physical Shipping" and changing countries to see dynamic UI updates.
345
- </p>
346
-
347
- <div style={{ marginBottom: '20px', padding: '10px', backgroundColor: '#f0f0f0', borderRadius: '4px' }}>
348
- <h3>Features Demonstrated:</h3>
349
- <ul>
350
- <li>Show/hide form sections based on shipping requirement</li>
351
- <li>Dynamic widget changes (state dropdown vs province dropdown vs region text field)</li>
352
- <li>Conditional field ordering (international details appears at end)</li>
353
- <li>Data clearing when sections are hidden (handled in onChange)</li>
354
- </ul>
355
- </div>
356
-
357
- <ExtendedForm
358
- schema={schema}
359
- uiSchema={conditionalUiSchema}
360
- formData={formData}
361
- onChange={handleChange}
362
- onSubmit={handleSubmit}
363
- />
364
-
365
- <div style={{ marginTop: '20px', padding: '10px', backgroundColor: '#f9f9f9', borderRadius: '4px' }}>
366
- <h4>Current Form Data:</h4>
367
- <pre>{JSON.stringify(formData, null, 2)}</pre>
368
- </div>
369
- </div>
370
- );
371
- }
@@ -1,212 +0,0 @@
1
- # Vanilla JS Usage Guide
2
-
3
- This directory contains examples of how to use Extended Dynamic Forms as a vanilla JavaScript library without React knowledge.
4
-
5
- ## Quick Start
6
-
7
- 1. **Include the standalone bundle:**
8
- ```html
9
- <script src="path/to/extended-dynamic-forms.standalone.js"></script>
10
- ```
11
-
12
- 2. **Create a basic form:**
13
- ```javascript
14
- const form = ExtendedDynamicForms.createForm({
15
- container: '#my-form',
16
- schema: {
17
- type: 'object',
18
- properties: {
19
- name: { type: 'string', title: 'Name' },
20
- email: { type: 'string', format: 'email', title: 'Email' }
21
- }
22
- },
23
- onChange: (formData) => console.log(formData),
24
- onSubmit: (formData) => alert('Submitted: ' + JSON.stringify(formData))
25
- });
26
- ```
27
-
28
- ## Examples
29
-
30
- - **`basic-form.html`** - Simple contact form with validation
31
- - **`conditional-form.html`** - Form with conditional field visibility
32
- - **`wizard-form.html`** - Multi-step wizard form
33
-
34
- ## API Reference
35
-
36
- ### ExtendedDynamicForms.createForm(config)
37
-
38
- Creates a standard form.
39
-
40
- **Config Options:**
41
- - `container` (string|HTMLElement) - Container selector or element
42
- - `schema` (object) - JSON Schema defining form structure
43
- - `uiSchema` (object) - UI customizations and widget selections
44
- - `formData` (object) - Initial form data
45
- - `onChange` (function) - Called when form data changes
46
- - `onSubmit` (function) - Called when form is submitted
47
- - `onError` (function) - Called when validation errors occur
48
- - `conditionals` (object) - Conditional logic rules
49
- - `webhooks` (array) - Webhook configurations
50
- - `widgets` (object) - Custom widget overrides
51
- - `fields` (object) - Custom field components
52
-
53
- **Returns:**
54
- - `setFormData(data)` - Update form data
55
- - `destroy()` - Remove form from DOM
56
-
57
- ### ExtendedDynamicForms.createWizardForm(config)
58
-
59
- Creates a multi-step wizard form.
60
-
61
- **Config Options:**
62
- - `container` (string|HTMLElement) - Container selector or element
63
- - `steps` (array) - Array of step definitions
64
- - `initialData` (object) - Initial form data
65
- - `onStepChange` (function) - Called when step changes
66
- - `onComplete` (function) - Called when wizard completes
67
- - `conditionals` (object) - Conditional logic rules
68
-
69
- ### Schema Definition
70
-
71
- JSON Schema format with additional UI enhancements:
72
-
73
- ```javascript
74
- const schema = {
75
- type: 'object',
76
- properties: {
77
- fieldName: {
78
- type: 'string', // string, number, boolean, array, object
79
- title: 'Display Name',
80
- description: 'Help text',
81
- minLength: 2, // Validation rules
82
- pattern: '^[A-Za-z]+$'
83
- }
84
- },
85
- required: ['fieldName']
86
- };
87
- ```
88
-
89
- ### UI Schema
90
-
91
- Customize field appearance and behavior:
92
-
93
- ```javascript
94
- const uiSchema = {
95
- fieldName: {
96
- 'ui:widget': 'textarea', // Widget type
97
- 'ui:placeholder': 'Enter text...',
98
- 'ui:autofocus': true,
99
- 'ui:options': {
100
- rows: 4
101
- }
102
- }
103
- };
104
- ```
105
-
106
- ### Available Widgets
107
-
108
- - `text` - Single line text input
109
- - `textarea` - Multi-line text area
110
- - `email` - Email input with validation
111
- - `password` - Password input (masked)
112
- - `number` - Numeric input
113
- - `select` - Dropdown selection
114
- - `radio` - Radio button group
115
- - `checkbox` - Single checkbox
116
- - `checkboxes` - Multiple checkboxes
117
- - `date` - Date picker
118
- - `datetime` - Date and time picker
119
- - `file` - File upload
120
- - `hidden` - Hidden field
121
-
122
- ### Conditional Logic
123
-
124
- Control field visibility and behavior based on form data:
125
-
126
- ```javascript
127
- const conditionals = {
128
- rules: [
129
- {
130
- conditions: { userType: 'business' },
131
- event: {
132
- type: 'require',
133
- params: { field: ['businessName', 'taxId'] }
134
- }
135
- },
136
- {
137
- conditions: { age: { less: 18 } },
138
- event: {
139
- type: 'remove',
140
- params: { field: 'driversLicense' }
141
- }
142
- }
143
- ]
144
- };
145
- ```
146
-
147
- ### Webhook Integration
148
-
149
- Send form events to external APIs:
150
-
151
- ```javascript
152
- const webhooks = [{
153
- url: 'https://api.example.com/form-events',
154
- method: 'POST',
155
- events: ['change', 'submit'],
156
- debounceMs: 500,
157
- retries: 3,
158
- headers: {
159
- 'Authorization': 'Bearer your-token'
160
- }
161
- }];
162
- ```
163
-
164
- ## Building Standalone Version
165
-
166
- To build the standalone version for vanilla JS:
167
-
168
- ```bash
169
- npm run build:vanilla
170
- ```
171
-
172
- This creates `dist/extended-dynamic-forms.standalone.js` with all dependencies bundled.
173
-
174
- ## Browser Compatibility
175
-
176
- - Modern browsers (Chrome 80+, Firefox 75+, Safari 13+, Edge 80+)
177
- - ES2018+ features required
178
- - CSS Grid and Flexbox support needed for layouts
179
-
180
- ## Bundle Size
181
-
182
- The standalone bundle is approximately 2-3MB (uncompressed) and includes:
183
- - React and ReactDOM
184
- - Ant Design components
185
- - RJSF core libraries
186
- - All form components and widgets
187
-
188
- Consider using gzip compression on your server to reduce transfer size.
189
-
190
- ## Troubleshooting
191
-
192
- **Forms not rendering:**
193
- - Check browser console for errors
194
- - Ensure container element exists in DOM
195
- - Verify script is loaded after DOM ready
196
-
197
- **Styling issues:**
198
- - Include Ant Design CSS
199
- - Check for CSS conflicts with existing styles
200
- - Ensure proper viewport meta tag
201
-
202
- **Validation not working:**
203
- - Verify schema format is valid JSON Schema
204
- - Check required field definitions
205
- - Review conditional logic syntax
206
-
207
- ## Support
208
-
209
- For issues and questions:
210
- - Check the main repository documentation
211
- - Review example HTML files
212
- - Open issues on GitHub repository