extended-dynamic-forms 0.1.15 → 0.1.18

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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +859 -551
  3. package/dist/extended-dynamic-forms.standalone.js +882 -0
  4. package/dist/style.css +1 -1
  5. package/examples/conditional-v2-example.tsx +64 -0
  6. package/examples/dynamic-array-items-example.tsx +211 -0
  7. package/examples/form-devtools-example.tsx +386 -0
  8. package/examples/global-ui-rules-example.tsx +356 -0
  9. package/examples/vanilla-js/README.md +212 -0
  10. package/examples/vanilla-js/basic-form.html +142 -0
  11. package/examples/vanilla-js/conditional-form.html +159 -0
  12. package/examples/vanilla-js/wizard-form.html +185 -0
  13. package/package.json +53 -37
  14. package/dist/ExtendedForm.d.ts +0 -4
  15. package/dist/components/arrays/ArrayFieldItemTemplate.d.ts +0 -3
  16. package/dist/components/arrays/ArrayFieldTemplate.d.ts +0 -3
  17. package/dist/components/arrays/index.d.ts +0 -2
  18. package/dist/components/fields/AddressField.d.ts +0 -4
  19. package/dist/components/fields/CurrencyField.d.ts +0 -4
  20. package/dist/components/fields/PhoneField.d.ts +0 -4
  21. package/dist/components/index.d.ts +0 -15
  22. package/dist/components/ui/badge.d.ts +0 -9
  23. package/dist/components/ui/button.d.ts +0 -11
  24. package/dist/components/ui/calendar.d.ts +0 -8
  25. package/dist/components/ui/card.d.ts +0 -8
  26. package/dist/components/ui/checkbox.d.ts +0 -4
  27. package/dist/components/ui/date-picker.d.ts +0 -13
  28. package/dist/components/ui/input.d.ts +0 -5
  29. package/dist/components/ui/label.d.ts +0 -5
  30. package/dist/components/ui/popover.d.ts +0 -6
  31. package/dist/components/ui/select.d.ts +0 -13
  32. package/dist/components/ui/slider.d.ts +0 -4
  33. package/dist/components/ui/textarea.d.ts +0 -5
  34. package/dist/conditionals/ConditionalForm.d.ts +0 -7
  35. package/dist/conditionals/index.d.ts +0 -4
  36. package/dist/conditionals/initialStateUtils.d.ts +0 -18
  37. package/dist/conditionals/types.d.ts +0 -65
  38. package/dist/conditionals/utils.d.ts +0 -22
  39. package/dist/events/FormEventContext.d.ts +0 -20
  40. package/dist/events/FormEventHub.d.ts +0 -27
  41. package/dist/events/FormEventManager.d.ts +0 -10
  42. package/dist/events/index.d.ts +0 -4
  43. package/dist/index.d.ts +0 -15
  44. package/dist/index.es.js +0 -15405
  45. package/dist/index.umd.js +0 -116
  46. package/dist/layouts/grid/GridLayout.d.ts +0 -11
  47. package/dist/layouts/horizontal/HorizontalLayout.d.ts +0 -10
  48. package/dist/layouts/index.d.ts +0 -3
  49. package/dist/layouts/vertical/VerticalLayout.d.ts +0 -9
  50. package/dist/lib/utils.d.ts +0 -3
  51. package/dist/types/index.d.ts +0 -47
  52. package/dist/utils/formDataUtils.d.ts +0 -22
  53. package/dist/utils/index.d.ts +0 -3
  54. package/dist/utils/schemaUtils.d.ts +0 -24
  55. package/dist/utils/validationUtils.d.ts +0 -26
  56. package/dist/vanilla-wrapper.d.ts +0 -35
  57. package/dist/widgets/date/DateWidget.d.ts +0 -4
  58. package/dist/widgets/enhanced/EnhancedWidgets.d.ts +0 -36
  59. package/dist/widgets/file/FileWidget.d.ts +0 -4
  60. package/dist/widgets/index.d.ts +0 -33
  61. package/dist/widgets/input/ColorWidget.d.ts +0 -4
  62. package/dist/widgets/input/RangeWidget.d.ts +0 -4
  63. package/dist/widgets/input/RatingWidget.d.ts +0 -4
@@ -0,0 +1,386 @@
1
+ import React, { useState } from 'react';
2
+ import Form from '@rjsf/antd';
3
+ import { IChangeEvent } from '@rjsf/core';
4
+ import { RJSFSchema, UiSchema } from '@rjsf/utils';
5
+ import validator from '@rjsf/validator-ajv8';
6
+ import {
7
+ Card,
8
+ Collapse,
9
+ Badge,
10
+ Tag,
11
+ Space,
12
+ Switch,
13
+ Typography,
14
+ Alert,
15
+ } from 'antd';
16
+ import {
17
+ Rule,
18
+ UiEffect,
19
+ SchemaEffect,
20
+ ValidationEffect,
21
+ } from '../src/conditionals/v2/types';
22
+ import {
23
+ useConditionalUi,
24
+ useConditionalSchema,
25
+ useConditionalValidation,
26
+ } from '../src/conditionals/v2';
27
+ import { useFormDevTools } from '../src/hooks/useFormDevTools';
28
+
29
+ const { Panel } = Collapse;
30
+ const { Text } = Typography;
31
+
32
+ // Base schema
33
+ const baseSchema: RJSFSchema = {
34
+ type: 'object',
35
+ title: 'Form with DevTools Example',
36
+ properties: {
37
+ country: {
38
+ type: 'string',
39
+ title: 'Country',
40
+ enum: ['USA', 'Canada', 'UK', 'Other'],
41
+ },
42
+ requiresShipping: {
43
+ type: 'boolean',
44
+ title: 'Requires Shipping?',
45
+ },
46
+ shippingAddress: {
47
+ type: 'object',
48
+ title: 'Shipping Address',
49
+ properties: {
50
+ street: { type: 'string', title: 'Street' },
51
+ city: { type: 'string', title: 'City' },
52
+ state: { type: 'string', title: 'State' },
53
+ zip: { type: 'string', title: 'ZIP Code' },
54
+ },
55
+ },
56
+ maritalStatus: {
57
+ type: 'string',
58
+ title: 'Marital Status',
59
+ enum: ['single', 'married', 'divorced', 'widowed'],
60
+ },
61
+ spouseName: {
62
+ type: 'string',
63
+ title: 'Spouse Name',
64
+ },
65
+ },
66
+ };
67
+
68
+ // Base UI schema
69
+ const baseUiSchema: UiSchema = {
70
+ 'ui:order': [
71
+ 'country',
72
+ 'requiresShipping',
73
+ 'shippingAddress',
74
+ 'maritalStatus',
75
+ 'spouseName',
76
+ ],
77
+ };
78
+
79
+ // UI Rules
80
+ const uiRules: Rule<UiEffect>[] = [
81
+ {
82
+ name: 'Hide shipping address when not required',
83
+ condition: formData => !formData.requiresShipping,
84
+ effect: [
85
+ { op: 'add', path: '/shippingAddress/ui:widget', value: 'hidden' },
86
+ ],
87
+ },
88
+ {
89
+ name: 'Show state dropdown for US/Canada',
90
+ condition: formData =>
91
+ formData.country === 'USA' || formData.country === 'Canada',
92
+ effect: [
93
+ {
94
+ op: 'add',
95
+ path: '/shippingAddress/state/ui:widget',
96
+ value: 'select',
97
+ },
98
+ ],
99
+ },
100
+ ];
101
+
102
+ // Schema Rules
103
+ const schemaRules: Rule<SchemaEffect>[] = [
104
+ {
105
+ name: 'Add spouse fields when married',
106
+ condition: formData => formData.maritalStatus === 'married',
107
+ effect: [{ op: 'add', path: '/required/-', value: 'spouseName' }],
108
+ },
109
+ {
110
+ name: 'Remove spouse field when not married',
111
+ condition: formData => formData.maritalStatus !== 'married',
112
+ effect: [{ op: 'remove', path: '/properties/spouseName' }],
113
+ },
114
+ ];
115
+
116
+ // Validation Rules
117
+ const validationRules: Rule<ValidationEffect>[] = [
118
+ {
119
+ name: 'US ZIP code format validation',
120
+ effect: {
121
+ name: 'US ZIP code format',
122
+ isActive: formData =>
123
+ formData.country === 'USA' && formData.requiresShipping,
124
+ validate: (errors, formData) => {
125
+ if (
126
+ formData.shippingAddress?.zip &&
127
+ !/^\d{5}(-\d{4})?$/.test(formData.shippingAddress.zip)
128
+ ) {
129
+ if (!errors.shippingAddress) errors.shippingAddress = {};
130
+ if (!errors.shippingAddress.zip) errors.shippingAddress.zip = {};
131
+ errors.shippingAddress.zip.__errors = [
132
+ 'ZIP code must be XXXXX or XXXXX-XXXX format',
133
+ ];
134
+ }
135
+ },
136
+ },
137
+ },
138
+ {
139
+ name: 'Canadian postal code validation',
140
+ effect: {
141
+ name: 'Canadian postal code',
142
+ isActive: formData =>
143
+ formData.country === 'Canada' && formData.requiresShipping,
144
+ validate: (errors, formData) => {
145
+ if (
146
+ formData.shippingAddress?.zip &&
147
+ !/^[A-Z]\d[A-Z] \d[A-Z]\d$/.test(formData.shippingAddress.zip)
148
+ ) {
149
+ if (!errors.shippingAddress) errors.shippingAddress = {};
150
+ if (!errors.shippingAddress.zip) errors.shippingAddress.zip = {};
151
+ errors.shippingAddress.zip.__errors = [
152
+ 'Postal code must be A1A 1A1 format',
153
+ ];
154
+ }
155
+ },
156
+ },
157
+ },
158
+ ];
159
+
160
+ // DevTools Panel Component
161
+ const DevToolsPanel: React.FC<{
162
+ devTools: ReturnType<typeof useFormDevTools>;
163
+ }> = ({ devTools }) => {
164
+ const { evaluations, activeRules, hasErrors, errors, summary } = devTools;
165
+
166
+ return (
167
+ <Card title='Form DevTools' style={{ marginTop: 24 }}>
168
+ <Space direction='vertical' style={{ width: '100%' }}>
169
+ {/* Summary */}
170
+ <Alert
171
+ message={
172
+ <Space>
173
+ <Text>Total Rules: {summary.totalRules}</Text>
174
+ <Badge
175
+ count={summary.activeCount}
176
+ style={{ backgroundColor: '#52c41a' }}
177
+ />
178
+ <Text>Active</Text>
179
+ {hasErrors && (
180
+ <>
181
+ <Badge count={summary.errorCount} />
182
+ <Text>Errors</Text>
183
+ </>
184
+ )}
185
+ </Space>
186
+ }
187
+ type={hasErrors ? 'warning' : 'info'}
188
+ />
189
+
190
+ {/* Errors */}
191
+ {hasErrors && (
192
+ <Alert
193
+ message='Rule Evaluation Errors'
194
+ description={
195
+ <ul>
196
+ {errors.map((error, idx) => (
197
+ <li key={idx}>
198
+ <Text type='danger'>
199
+ {error.pillar} Rule "{error.ruleName}": {error.error}
200
+ </Text>
201
+ </li>
202
+ ))}
203
+ </ul>
204
+ }
205
+ type='error'
206
+ />
207
+ )}
208
+
209
+ {/* Rule Details */}
210
+ <Collapse defaultActiveKey={['ui']}>
211
+ <Panel
212
+ header={`UI Rules (${activeRules.ui.length} active)`}
213
+ key='ui'
214
+ extra={
215
+ <Badge
216
+ count={activeRules.ui.length}
217
+ style={{ backgroundColor: '#52c41a' }}
218
+ />
219
+ }
220
+ >
221
+ {evaluations
222
+ .filter(e => e.pillar === 'UI')
223
+ .map((evaluation, idx) => (
224
+ <div key={idx} style={{ marginBottom: 8 }}>
225
+ <Tag color={evaluation.active ? 'green' : 'default'}>
226
+ {evaluation.active ? '✓' : '○'}
227
+ </Tag>
228
+ <Text>{evaluation.ruleName}</Text>
229
+ {evaluation.error && (
230
+ <Text type='danger'> (Error: {evaluation.error})</Text>
231
+ )}
232
+ </div>
233
+ ))}
234
+ </Panel>
235
+
236
+ <Panel
237
+ header={`Schema Rules (${activeRules.schema.length} active)`}
238
+ key='schema'
239
+ extra={
240
+ <Badge
241
+ count={activeRules.schema.length}
242
+ style={{ backgroundColor: '#52c41a' }}
243
+ />
244
+ }
245
+ >
246
+ {evaluations
247
+ .filter(e => e.pillar === 'Schema')
248
+ .map((evaluation, idx) => (
249
+ <div key={idx} style={{ marginBottom: 8 }}>
250
+ <Tag color={evaluation.active ? 'green' : 'default'}>
251
+ {evaluation.active ? '✓' : '○'}
252
+ </Tag>
253
+ <Text>{evaluation.ruleName}</Text>
254
+ {evaluation.error && (
255
+ <Text type='danger'> (Error: {evaluation.error})</Text>
256
+ )}
257
+ </div>
258
+ ))}
259
+ </Panel>
260
+
261
+ <Panel
262
+ header={`Validation Rules (${activeRules.validation.length} active)`}
263
+ key='validation'
264
+ extra={
265
+ <Badge
266
+ count={activeRules.validation.length}
267
+ style={{ backgroundColor: '#52c41a' }}
268
+ />
269
+ }
270
+ >
271
+ {evaluations
272
+ .filter(e => e.pillar === 'Validation')
273
+ .map((evaluation, idx) => (
274
+ <div key={idx} style={{ marginBottom: 8 }}>
275
+ <Tag color={evaluation.active ? 'green' : 'default'}>
276
+ {evaluation.active ? '✓' : '○'}
277
+ </Tag>
278
+ <Text>{evaluation.ruleName}</Text>
279
+ {evaluation.error && (
280
+ <Text type='danger'> (Error: {evaluation.error})</Text>
281
+ )}
282
+ </div>
283
+ ))}
284
+ </Panel>
285
+ </Collapse>
286
+ </Space>
287
+ </Card>
288
+ );
289
+ };
290
+
291
+ export default function FormDevToolsExample() {
292
+ const [formData, setFormData] = useState({});
293
+ const [devToolsEnabled, setDevToolsEnabled] = useState(true);
294
+ const [logToConsole, setLogToConsole] = useState(false);
295
+ const [captureHistory, setCaptureHistory] = useState(false);
296
+
297
+ // Apply conditional logic
298
+ const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
299
+ const conditionalSchema = useConditionalSchema(
300
+ schemaRules,
301
+ baseSchema,
302
+ formData
303
+ );
304
+ const customValidate = useConditionalValidation(validationRules, formData);
305
+
306
+ // Use DevTools
307
+ const devTools = useFormDevTools(
308
+ formData,
309
+ uiRules,
310
+ schemaRules,
311
+ validationRules,
312
+ {
313
+ enabled: devToolsEnabled,
314
+ logToConsole,
315
+ captureHistory,
316
+ historySize: 10,
317
+ }
318
+ );
319
+
320
+ const handleChange = (e: IChangeEvent) => {
321
+ setFormData(e.formData);
322
+ };
323
+
324
+ return (
325
+ <div style={{ padding: '24px', maxWidth: '1200px', margin: '0 auto' }}>
326
+ <Card title='DevTools Settings' style={{ marginBottom: 24 }}>
327
+ <Space>
328
+ <label>
329
+ <Switch checked={devToolsEnabled} onChange={setDevToolsEnabled} />
330
+ <Text style={{ marginLeft: 8 }}>Enable DevTools</Text>
331
+ </label>
332
+ <label>
333
+ <Switch checked={logToConsole} onChange={setLogToConsole} />
334
+ <Text style={{ marginLeft: 8 }}>Log to Console</Text>
335
+ </label>
336
+ <label>
337
+ <Switch checked={captureHistory} onChange={setCaptureHistory} />
338
+ <Text style={{ marginLeft: 8 }}>Capture History</Text>
339
+ </label>
340
+ </Space>
341
+ </Card>
342
+
343
+ <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24 }}>
344
+ <div>
345
+ <Form
346
+ schema={conditionalSchema}
347
+ uiSchema={conditionalUiSchema}
348
+ formData={formData}
349
+ onChange={handleChange}
350
+ validator={validator}
351
+ customValidate={customValidate}
352
+ />
353
+ </div>
354
+
355
+ <div>
356
+ {devToolsEnabled && <DevToolsPanel devTools={devTools} />}
357
+
358
+ {captureHistory && devTools.history.length > 0 && (
359
+ <Card title='History' style={{ marginTop: 24 }}>
360
+ <Text>History entries: {devTools.history.length}</Text>
361
+ <div style={{ maxHeight: 200, overflow: 'auto', marginTop: 8 }}>
362
+ {devTools.history.map((entry, idx) => (
363
+ <div
364
+ key={idx}
365
+ style={{
366
+ marginBottom: 8,
367
+ padding: 8,
368
+ background: '#f0f0f0',
369
+ }}
370
+ >
371
+ <Text type='secondary'>
372
+ {new Date(entry.timestamp).toLocaleTimeString()}
373
+ </Text>
374
+ <pre style={{ fontSize: 12, margin: 0 }}>
375
+ {JSON.stringify(entry.formData, null, 2)}
376
+ </pre>
377
+ </div>
378
+ ))}
379
+ </div>
380
+ </Card>
381
+ )}
382
+ </div>
383
+ </div>
384
+ </div>
385
+ );
386
+ }