extended-dynamic-forms 0.2.1 → 0.3.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.
Files changed (50) hide show
  1. package/README.md +387 -1392
  2. package/dist/events/FormEventContext.d.ts +3 -0
  3. package/dist/index.es.js +22516 -14517
  4. package/dist/index.umd.js +63 -36
  5. package/dist/style.css +1 -1
  6. package/dist/widgets/base/index.d.ts +2 -0
  7. package/dist/widgets/base/types.d.ts +135 -0
  8. package/dist/widgets/base/utils.d.ts +63 -0
  9. package/dist/widgets/choice/ChoiceWidget.d.ts +30 -0
  10. package/dist/widgets/choice/ChoiceWidget.types.d.ts +496 -0
  11. package/dist/widgets/choice/examples/ChoiceWidget.example.d.ts +7 -0
  12. package/dist/widgets/choice/hooks/__tests__/useChoiceWidget.test.d.ts +1 -0
  13. package/dist/widgets/choice/hooks/__tests__/useDataSource.test.d.ts +1 -0
  14. package/dist/widgets/choice/hooks/examples/useChoiceWidget.example.d.ts +18 -0
  15. package/dist/widgets/choice/hooks/examples/useDataSourceExample.d.ts +22 -0
  16. package/dist/widgets/choice/hooks/index.d.ts +6 -0
  17. package/dist/widgets/choice/hooks/useChoiceWidget.d.ts +65 -0
  18. package/dist/widgets/choice/hooks/useDataSource.d.ts +69 -0
  19. package/dist/widgets/choice/index.d.ts +59 -0
  20. package/dist/widgets/choice/presenters/CheckboxPresenter.d.ts +70 -0
  21. package/dist/widgets/choice/presenters/DropdownPresenter.d.ts +37 -0
  22. package/dist/widgets/choice/presenters/PresenterStrategy.d.ts +230 -0
  23. package/dist/widgets/choice/presenters/RadioPresenter.d.ts +39 -0
  24. package/dist/widgets/choice/presenters/examples/RadioPresenterExample.d.ts +7 -0
  25. package/dist/widgets/choice/presenters/index.d.ts +20 -0
  26. package/dist/widgets/choice/providers/ApiDataSource.d.ts +241 -0
  27. package/dist/widgets/choice/providers/DataSourceProvider.d.ts +260 -0
  28. package/dist/widgets/choice/providers/StaticDataSource.d.ts +258 -0
  29. package/dist/widgets/choice/providers/WebSocketDataSource.d.ts +310 -0
  30. package/dist/widgets/choice/providers/index.d.ts +12 -0
  31. package/dist/widgets/choice/utils/index.d.ts +1 -0
  32. package/dist/widgets/choice/utils/responseMappers.d.ts +342 -0
  33. package/dist/widgets/date/DateTimeWidget.d.ts +26 -0
  34. package/dist/widgets/date/EnhancedDateWidget.d.ts +26 -0
  35. package/dist/widgets/date/index.d.ts +13 -0
  36. package/dist/widgets/file/FileUploadWidget.d.ts +40 -0
  37. package/dist/widgets/file/index.d.ts +2 -0
  38. package/dist/widgets/index.d.ts +33 -17
  39. package/dist/widgets/input/EmailWidget.d.ts +34 -0
  40. package/dist/widgets/input/NumberWidget.d.ts +39 -0
  41. package/dist/widgets/input/TelephoneWidget.d.ts +34 -0
  42. package/dist/widgets/input/URLWidget.d.ts +34 -0
  43. package/dist/widgets/input/index.d.ts +7 -0
  44. package/dist/widgets/text/PasswordWidget.d.ts +45 -0
  45. package/dist/widgets/text/TextWidget.d.ts +40 -0
  46. package/dist/widgets/text/TextareaWidget.d.ts +38 -0
  47. package/dist/widgets/text/index.d.ts +20 -0
  48. package/package.json +5 -5
  49. package/dist/vanilla-entry.d.ts +0 -232
  50. package/dist/widgets/enhanced/EnhancedWidgets.d.ts +0 -37
package/README.md CHANGED
@@ -1,1548 +1,543 @@
1
1
  # Extended Dynamic Forms
2
2
 
3
- ## 🚨 BREAKING CHANGE: v0.2.0 - JsonLogic Only Conditions
3
+ ## BREAKING CHANGE: v0.2.0
4
4
 
5
- > **⚠️ IMPORTANT**: Starting with v0.2.0, Extended Dynamic Forms **ONLY** supports JsonLogic for conditional logic. Function-based conditions are no longer supported. This is a breaking change that improves security, performance, and maintainability.
6
- >
7
- > **Migration Required**: If you are using function-based conditions like `condition: (formData) => ...`, you must migrate to JsonLogic format: `condition: { "==": [{ "var": "fieldName" }, "value"] }`
5
+ All conditional logic now uses **JsonLogic rules only** for conditions. Function-based conditions have been removed for security and portability. Note that validation effects may still use functions. See migration examples below.
8
6
 
9
- ## ⚠️ Project Status: Active Development & Documentation Refinement
7
+ ## Project Status
10
8
 
11
- **Important Notice**: This project is currently undergoing significant documentation updates to better reflect the actual implementation. Some features described in this README may not be fully implemented or may differ from the documentation. We are actively working to align the documentation with the codebase.
9
+ **Important Notes:**
10
+ - Requires RJSF source in sibling directory for development
11
+ - Cannot be installed from npm due to local file dependencies
12
+ - JSON logic conditions don't work with vanilla JavaScript builds
13
+ - Array drag-and-drop is not implemented
14
+ - Limited test coverage for UI components and event system
15
+ - JSON Patch implementation supports add/remove/replace only (not move/copy/test)
12
16
 
13
- **Known Issues**:
14
- - The project currently uses local file dependencies that require a specific directory structure to build
15
- - The project requires RJSF packages from a sibling directory (../react-jsonschema-form/)
16
- - Array drag-and-drop functionality mentioned in documentation is not implemented
17
- - Test coverage is limited for UI components and event systems
18
- - Several documented features have incomplete implementations
19
- - Significant dead code: 76% of utility functions are unused (13 out of 17 functions)
20
- - JSON Patch implementation in v2 doesn't fully comply with RFC 6902 (no move/copy/test operations)
17
+ ## Overview
21
18
 
22
- **A revolutionary extension library for [React JSON Schema Form (RJSF)](https://github.com/rjsf-team/react-jsonschema-form)** that transforms schema-driven forms into sophisticated, enterprise-ready applications with O(N) performance and professional UI components.
19
+ Extended Dynamic Forms is an extension library for React JSON Schema Form (RJSF) v6 that adds:
23
20
 
24
- Built on top of the excellent RJSF v6 foundation, this library introduces the **Three Pillars Architecture** for conditional logic, multi-step wizard orchestration, central event systems with webhook integration, and a comprehensive suite of 25+ Ant Design components.
25
-
26
- [![npm version](https://img.shields.io/npm/v/extended-dynamic-forms.svg)](https://www.npmjs.com/package/extended-dynamic-forms)
27
- [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/user/extended-dynamic-forms/blob/main/LICENSE)
28
- [![Built on RJSF](https://img.shields.io/badge/built%20on-RJSF%20v6-brightgreen)](https://github.com/rjsf-team/react-jsonschema-form)
29
- [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
30
- [![Standalone JS](https://img.shields.io/badge/Vanilla%20JS-Supported-orange.svg)](#standalone-javascript-support)
31
-
32
- ## Why Extended Dynamic Forms?
33
-
34
- While [RJSF](https://github.com/rjsf-team/react-jsonschema-form) provides an excellent foundation for generating forms from JSON Schema, enterprise applications demand more sophisticated capabilities:
35
-
36
- ### 🚀 **Performance Revolution**
37
- - **O(N) Conditional Logic**: Advanced Three Pillars architecture with optimized performance
38
- - **Optimized Array Processing**: Per-item evaluation with dynamic array conditionals
39
- - **Memory Efficient**: Immutable schema processing with intelligent caching
40
-
41
- ### 🎯 **Enterprise-Grade Features**
42
- - **Complex Conditional Logic**: Multi-field dependencies, nested conditions, and dynamic validation
43
- - **Multi-Step Workflows**: Automatic wizard detection with step-aware conditional logic
44
- - **Real-Time Integration**: Production-ready webhooks with retry logic and error isolation
45
- - **Professional UI**: Comprehensive suite of enhanced Ant Design components with consistent styling
46
-
47
- ### 🔄 **Developer Experience**
48
- - **Dual Architecture Support**: Modern React hooks + vanilla JavaScript compatibility
49
- - **Type-Safe Throughout**: Comprehensive TypeScript interfaces and validation
50
- - **Rich Ecosystem**: Interactive playground with comprehensive real-world demos
51
-
52
- This library transforms RJSF from a simple form generator into a complete enterprise form solution while preserving its declarative approach.
53
-
54
- ## Core Features
55
-
56
- ### 🚀 Three Pillars Architecture with JsonLogic
57
- - **UI Logic Pillar**: Control form appearance with JsonLogic conditions and JSON Patch operations
58
- - **Schema Logic Pillar**: Modify data structure with JsonLogic rules when truly needed
59
- - **Validation Logic Pillar**: Dynamic validation rules with JsonLogic conditions
60
- - **O(N) Performance**: Superior array handling with optimized evaluation
61
- - **JsonLogic-Only**: Secure, data-driven conditions without code execution
62
- - **React Hooks**: Modern, declarative API with `useConditionalUi`, `useConditionalSchema`, `useConditionalValidation`
63
-
64
- ### 🎯 Declarative Conditional Logic with JsonLogic
65
- - Define complex form behavior with secure JsonLogic rules
66
- - Dynamic array support with per-item evaluation
67
- - No code execution - all conditions are data-driven
68
- - Type-safe with comprehensive TypeScript support
69
-
70
- ```tsx
71
- import { UiRule, JsonLogicRule } from 'extended-dynamic-forms/conditionals/v2';
72
-
73
- const uiRules: UiRule[] = [{
74
- name: 'Show premium features for premium users',
75
- condition: {
76
- "==": [{ "var": "accountType" }, "premium"]
77
- } as JsonLogicRule,
78
- effect: [
79
- { op: 'remove', path: '/premiumFeatures/ui:widget' }
80
- ]
81
- }];
82
- ```
83
-
84
- ### 🧙‍♂️ Multi-Step Wizard Forms
85
- - Automatic step detection from schema structure
86
- - **Full conditional logic support** with step-aware rule processing
87
- - Built-in progress indicators and navigation
88
- - Per-step validation
89
- - Supports Three Pillars architecture with JsonLogic conditions
90
-
91
- **Step-Aware Conditional Logic**
92
-
93
- The `WizardForm` automatically filters and transforms conditional rules to work within the current step's context. This means you can define conditions that reference fields across different steps, and the wizard will intelligently apply only the relevant rules for the active step:
94
-
95
- ```tsx
96
- // Define steps with prefixed field names to avoid collisions
97
- const schema = {
98
- type: 'object',
99
- properties: {
100
- STEP_PERSONAL: {
101
- type: 'object',
102
- title: 'Personal Information',
103
- properties: {
104
- isUSCitizen: { type: 'boolean', title: 'Are you a US Citizen?' },
105
- ssn: { type: 'string', title: 'Social Security Number' }
106
- }
107
- }
108
- // ... other steps
109
- }
110
- };
111
-
112
- // Use UiRules with JsonLogic to handle step-aware conditionals
113
- const uiRules: UiRule[] = [{
114
- name: 'Show SSN only for US Citizens in Personal step',
115
- condition: {
116
- "!": { "var": "STEP_PERSONAL.isUSCitizen" }
117
- } as JsonLogicRule,
118
- effect: [
119
- { op: 'add', path: '/STEP_PERSONAL/properties/ssn/ui:widget', value: 'hidden' }
120
- ]
121
- }];
122
-
123
- // The WizardForm handles the step isolation automatically
124
- ```
125
-
126
- ### 🔗 Central Event Orchestration
127
- - Unified event system for all field interactions
128
- - Webhook integration with retry logic
129
- - Real-time form analytics capabilities
130
- - Debounced event processing
131
- - **Enhanced webhook support** for form-level events (submit, stepChange, validationError)
132
-
133
- ### 🎨 Ant Design Components
134
- - Complete widget suite built with Ant Design v5
135
- - Enhanced standard widgets with event integration
136
- - Custom widgets: Rating, Color Picker, Range Slider
137
- - Professional field components: Address, Phone, Currency
138
-
139
- ### ⚡ Form Lifecycle Hooks
140
- - Intercept and modify form data at key stages
141
- - `beforeSubmit`, `afterSubmit`, `beforeValidation`, `afterValidation`
142
- - Ideal for data transformation, logging, or triggering side effects
143
-
144
- ### 📦 Additional Features
145
- - **TypeScript**: Full type safety and IntelliSense with comprehensive interface definitions
146
- - **Performance**: Optimized re-renders and memoization with intelligent caching
147
- - **Extensible**: Add custom widgets, fields, and actions with clean APIs
148
- - **Test Coverage**: Focused on conditional logic and wizard forms (UI components have limited coverage)
149
- - **Developer Experience**: Interactive playground with real-world demos (note: some deprecated)
150
-
151
- ### 🌐 Standalone JavaScript Support
152
-
153
- **Complete vanilla JavaScript compatibility** with a production-ready UMD bundle that includes React, Ant Design, and all dependencies:
154
-
155
- ```html
156
- <!DOCTYPE html>
157
- <html>
158
- <head>
159
- <script src="https://unpkg.com/extended-dynamic-forms/dist/standalone.umd.js"></script>
160
- <link rel="stylesheet" href="https://unpkg.com/extended-dynamic-forms/dist/style.css">
161
- </head>
162
- <body>
163
- <div id="form-container"></div>
164
-
165
- <script>
166
- const { createForm, createWizard } = ExtendedDynamicForms;
167
-
168
- // Create a complete form without React knowledge
169
- const form = createForm({
170
- schema: {
171
- type: 'object',
172
- properties: {
173
- name: { type: 'string', title: 'Full Name' },
174
- email: { type: 'string', format: 'email', title: 'Email' }
175
- }
176
- },
177
- container: document.getElementById('form-container'),
178
- onSubmit: (data) => console.log('Form submitted:', data)
179
- });
180
- </script>
181
- </body>
182
- </html>
183
- ```
184
-
185
- **Important Notes on Conditional Logic in Vanilla JS:**
186
- - **JsonLogic is NOT supported in vanilla JS** - The JsonLogic runtime requires React hooks
187
- - For JsonLogic benefits, you must use the React-based API
188
-
189
- **Perfect for:**
190
- - WordPress/Drupal integrations
191
- - Legacy applications
192
- - CMS form builders
193
- - No-build environments
194
- - PHP/ASP.NET applications
195
-
196
- ## Credits & Acknowledgments
197
-
198
- This library is built on top of [React JSON Schema Form (RJSF)](https://github.com/rjsf-team/react-jsonschema-form), an amazing open-source project that provides the core form generation engine. We extend RJSF's capabilities while maintaining full compatibility with its ecosystem.
199
-
200
- Special thanks to the RJSF team and contributors for creating such a flexible and well-architected foundation.
21
+ - **Three Pillars Architecture** for conditional logic with O(N) performance (where N is the number of conditional rules/array items)
22
+ - **Multi-step wizard forms** with automatic step detection
23
+ - **Central event orchestration** with webhook support
24
+ - **25+ Ant Design components** for professional UI
25
+ - **TypeScript-first** development with full type safety
201
26
 
202
27
  ## Installation
203
28
 
204
- > ⚠️ **Important Note**: This library currently uses local file dependencies for RJSF packages (pointing to `../react-jsonschema-form/`). This means:
205
- > - The library cannot be installed directly from npm without modifications
206
- > - You need the RJSF source code in a sibling directory for development
207
- > - Consider using a monorepo structure or git submodules for proper dependency management
208
-
209
- ### React Projects
29
+ **Note:** This library currently requires local development setup and cannot be installed via npm due to local file dependencies.
210
30
 
211
31
  ```bash
212
- npm install extended-dynamic-forms
213
- # or
214
- yarn add extended-dynamic-forms
215
- # or
216
- pnpm add extended-dynamic-forms
217
- ```
218
-
219
- ### Standalone JavaScript (No Build Required)
220
-
221
- ```html
222
- <!-- Production CDN -->
223
- <script src="https://unpkg.com/extended-dynamic-forms@latest/dist/standalone.umd.js"></script>
224
- <link rel="stylesheet" href="https://unpkg.com/extended-dynamic-forms@latest/dist/style.css">
32
+ # Clone RJSF as sibling directory (required)
33
+ cd ..
34
+ git clone https://github.com/rjsf-team/react-jsonschema-form.git
225
35
 
226
- <!-- Or download and host locally -->
227
- <script src="./path/to/extended-dynamic-forms-standalone.js"></script>
228
- ```
229
-
230
- ### Peer Dependencies
231
-
232
- **Current Version**: `0.2.0` - Built for **RJSF v6** with Three Pillars architecture (JsonLogic-only).
233
-
234
- ```json
235
- {
236
- "react": "^18.0.0 || ^19.0.0",
237
- "react-dom": "^18.0.0 || ^19.0.0",
238
- "antd": "^5.24.0"
239
- }
36
+ # Setup Extended Dynamic Forms
37
+ cd extended-dynamic-forms
38
+ npm install
39
+ npm run dev
240
40
  ```
241
41
 
242
- > **React 19 Support**: This library supports both React 18 and React 19. See [REACT-19-COMPATIBILITY.md](archive/REACT-19-COMPATIBILITY.md) for migration details.
243
-
244
- **RJSF Dependencies** (automatically handled):
245
- - `@rjsf/core`: ^6.0.0+
246
- - `@rjsf/utils`: ^6.0.0+
247
- - `@rjsf/validator-ajv8`: ^6.0.0+
248
- - `@rjsf/antd`: ^6.0.0+
42
+ **Important:** The library is currently designed for internal use or as part of a monorepo setup. Standalone npm package distribution is not yet supported.
249
43
 
250
- > **Development Note**: This library is currently developed against RJSF v6 and includes all necessary RJSF dependencies. No additional RJSF packages need to be installed separately.
44
+ ## Core Architecture
251
45
 
252
- **Additional Dependencies**:
253
- - `dayjs`: ^1.11.13 (Date handling)
254
- - `json-rules-engine-simplified`: ^0.2.0
46
+ ### Three Pillars Conditional System
255
47
 
256
- > **Note**: This library is specifically built for RJSF v6 to leverage the latest performance improvements and API enhancements. All examples and documentation assume RJSF v6.
48
+ The conditional logic system is divided into three independent pillars:
257
49
 
258
- ## Setup
50
+ #### 1. UI Logic Pillar
51
+ Controls form appearance using JsonLogic conditions and JSON Patch operations:
259
52
 
260
- ### CSS Requirements
261
-
262
- This package uses Ant Design components. Import the CSS in your application:
53
+ ```typescript
54
+ import { useConditionalUi, UiRule } from 'extended-dynamic-forms/conditionals/v2';
263
55
 
264
- ```tsx
265
- // In your main entry file (e.g., App.tsx or index.tsx)
266
- import 'extended-dynamic-forms/dist/style.css'; // Or your specific CSS entry point
267
- ```
56
+ const uiRules: UiRule[] = [{
57
+ name: 'Show license number when has license',
58
+ condition: { "==": [{ "var": "hasDriversLicense" }, true] },
59
+ effect: [{ op: 'remove', path: '/licenseNumber/ui:widget' }]
60
+ }];
268
61
 
269
- ### Theming & Customization
270
-
271
- Since Extended Dynamic Forms uses Ant Design components, you can customize the appearance using Ant Design's powerful theming system:
272
-
273
- ```tsx
274
- import { ConfigProvider, theme } from 'antd';
275
- import { ExtendedForm, WizardForm } from 'extended-dynamic-forms';
276
-
277
- function App() {
278
- return (
279
- <ConfigProvider
280
- theme={{
281
- token: {
282
- colorPrimary: '#00b96b',
283
- borderRadius: 8,
284
- fontSize: 16,
285
- },
286
- algorithm: theme.darkAlgorithm, // Optional: Use dark theme
287
- }}
288
- >
289
- <WizardForm
290
- schema={schema}
291
- uiSchema={uiSchema}
292
- conditionals={conditionals}
293
- />
294
- </ConfigProvider>
295
- );
296
- }
62
+ const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
297
63
  ```
298
64
 
299
- ## Three Pillars Architecture with JsonLogic (Required Approach)
300
-
301
- > ⚠️ **BREAKING CHANGE**: As of v0.2.0, the Three Pillars system ONLY supports JsonLogic conditions. Function-based conditions are no longer supported for security and maintainability reasons.
302
-
303
- The Three Pillars system with JsonLogic provides superior performance, cleaner separation of concerns, and better security. It consists of three independent pillars:
65
+ #### 2. Schema Logic Pillar
66
+ Modifies JSON Schema structure dynamically (use sparingly):
304
67
 
305
- ### 1. UI Logic Pillar (`useConditionalUi`)
306
-
307
- Controls form appearance using JSON Patch operations with JsonLogic conditions:
308
-
309
- ```tsx
310
- // Note: conditionals require deep import for optimal tree-shaking
311
- import { useConditionalUi, UiRule, JsonLogicRule } from 'extended-dynamic-forms/conditionals/v2';
312
-
313
- // Define UI rules with JsonLogic conditions and JSON Patch operations
314
- const uiRules: UiRule[] = [
315
- {
316
- name: 'Show shipping address when required',
317
- condition: {
318
- "==": [{ "var": "requiresShipping" }, true]
319
- } as JsonLogicRule,
320
- effect: [{ op: 'remove', path: '/shippingAddress/ui:widget' }],
321
- order: 1
322
- },
323
- {
324
- name: 'Dynamic country fields',
325
- condition: {
326
- "==": [{ "var": "shippingAddress.country" }, "USA"]
327
- } as JsonLogicRule,
328
- effect: [
329
- { op: 'remove', path: '/shippingAddress/state/ui:widget' },
330
- { op: 'add', path: '/shippingAddress/province/ui:widget', value: 'hidden' }
331
- ],
332
- order: 2
333
- }
334
- ];
335
-
336
- const baseUiSchema = {
337
- shippingAddress: {
338
- 'ui:widget': 'hidden', // Initially hidden
339
- state: { 'ui:widget': 'text' },
340
- province: { 'ui:widget': 'hidden' } // Initially hidden
341
- }
342
- };
343
-
344
- // In your component
345
- function MyForm() {
346
- const [formData, setFormData] = useState({});
347
-
348
- // IMPORTANT: Define rules outside render or memoize them!
349
- const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
350
-
351
- return (
352
- <ExtendedForm
353
- schema={schema}
354
- uiSchema={conditionalUiSchema}
355
- formData={formData}
356
- onChange={({ formData }) => setFormData(formData)}
357
- />
358
- );
359
- }
68
+ ```typescript
69
+ const schemaRules: SchemaRule[] = [{
70
+ name: 'Add premium fields',
71
+ condition: { "==": [{ "var": "accountType" }, "premium"] },
72
+ effect: [{ op: 'add', path: '/properties/premiumFeatures', value: {...} }]
73
+ }];
360
74
  ```
361
75
 
362
- ### 2. Schema Logic Pillar (`useConditionalSchema`)
363
-
364
- Modifies JSON Schema structure (use sparingly - prefer UI or Validation pillars):
365
-
366
- ```tsx
367
- import { useConditionalSchema, SchemaRule, JsonLogicRule } from 'extended-dynamic-forms/conditionals/v2';
368
-
369
- const schemaRules: SchemaRule[] = [
370
- {
371
- name: 'Add premium fields',
372
- condition: {
373
- "==": [{ "var": "accountType" }, "premium"]
374
- } as JsonLogicRule,
375
- effect: [
376
- {
377
- op: 'add',
378
- path: '/properties/premiumFeatures',
379
- value: {
380
- type: 'object',
381
- properties: {
382
- priority: { type: 'string', enum: ['high', 'medium', 'low'] }
383
- }
384
- }
385
- }
386
- ]
387
- }
388
- ];
76
+ #### 3. Validation Logic Pillar
77
+ Adds conditional validation rules:
389
78
 
390
- const conditionalSchema = useConditionalSchema(schemaRules, baseSchema, formData);
391
- ```
392
-
393
- ### 3. Validation Logic Pillar (`useConditionalValidation`)
394
-
395
- Adds conditional validation without modifying schema:
396
-
397
- ```tsx
398
- import { useMemo } from 'react';
399
- import { useConditionalValidation, ValidationRule, JsonLogicRule, createCustomValidate } from 'extended-dynamic-forms/conditionals/v2';
400
-
401
- const validationRules: ValidationRule[] = [
402
- {
403
- name: 'Require consent for minors',
404
- condition: {
405
- "<": [{ "var": "age" }, 18]
406
- } as JsonLogicRule,
407
- effect: {
408
- type: 'validation',
409
- validate: (errors, formData) => {
410
- if (!formData.parentConsent) {
411
- errors.parentConsent.addError('Parent consent is required for minors');
412
- }
79
+ ```typescript
80
+ const validationRules: ValidationRule[] = [{
81
+ name: 'Require consent for minors',
82
+ condition: { "<": [{ "var": "age" }, 18] },
83
+ effect: {
84
+ name: 'Parent consent validation',
85
+ isActive: { "<": [{ "var": "age" }, 18] },
86
+ validate: (errors, formData) => {
87
+ if (!formData.parentConsent) {
88
+ errors.parentConsent.__errors = ['Parent consent required'];
413
89
  }
414
90
  }
415
91
  }
416
- ];
417
-
418
- // In your component
419
- function MyForm({ schema }) {
420
- const [formData, setFormData] = useState({});
421
-
422
- // 1. Get the conditional validation configuration
423
- const conditionalValidationConfig = useConditionalValidation(validationRules, {}, formData);
424
-
425
- // 2. Create the memoized validate function
426
- const customValidate = useMemo(
427
- () => createCustomValidate(conditionalValidationConfig),
428
- [conditionalValidationConfig]
429
- );
430
-
431
- // 3. Use with ExtendedForm
432
- return (
433
- <ExtendedForm
434
- schema={schema}
435
- formData={formData}
436
- onChange={({ formData }) => setFormData(formData)}
437
- customValidate={customValidate}
438
- />
439
- );
440
- }
92
+ }];
441
93
  ```
442
94
 
443
95
  ### Dynamic Arrays with O(N) Performance
444
96
 
445
- #### **The Performance Revolution: `createDynamicArrayItemsUiSchema`**
97
+ Provides efficient handling of conditional logic within arrays, where N is the number of array items:
446
98
 
447
- One of the most significant breakthroughs is the `createDynamicArrayItemsUiSchema` function, which enables **true O(N) performance** for array conditionals. This is a fundamental improvement over traditional form libraries that struggle with dynamic array logic.
448
-
449
- **How It Works:**
450
- - **Per-Item Evaluation**: Each array item's conditionals are evaluated independently during render
451
- - **No Rule Explosion**: No rules are multiplied by array size
452
- - **React-Optimized**: Leverages React's rendering cycle for optimal performance
453
-
454
- > **Note**: `createDynamicArrayItemsUiSchema` still supports function-based conditions as it evaluates per-item during render. This is not a security risk as the functions are defined in your code, not from user input.
455
-
456
- ```tsx
99
+ ```typescript
457
100
  import { createDynamicArrayItemsUiSchema } from 'extended-dynamic-forms/conditionals/v2';
458
101
 
459
- // Define per-item conditional logic - this function runs for each array item
460
- const directorItemConditions = (director, index) => ({
461
- shareholdingPercentage: {
462
- 'ui:widget': director.hasShareholding ? 'percentage' : 'hidden'
463
- },
464
- tfn: {
465
- 'ui:widget': director.isAustralianResident ? 'text' : 'hidden'
466
- },
467
- passport: {
468
- 'ui:widget': !director.isAustralianResident ? 'text' : 'hidden'
469
- },
470
- // Add visual indicator for the chairman
471
- 'ui:classNames': index === 0 ? 'chairman-director' : 'regular-director'
472
- });
473
-
474
- // Apply to your array field
475
102
  const uiSchema = {
476
103
  directors: {
477
- 'ui:title': 'Company Directors',
478
- 'ui:description': 'Add all company directors and their details',
479
- items: createDynamicArrayItemsUiSchema(directorItemConditions)
480
- }
481
- };
482
- ```
483
-
484
- **Performance Comparison:**
485
- ```typescript
486
- // ❌ Traditional approach: O(M×N) - Rules × Array Items
487
- // With 10 rules and 50 directors = 500 evaluations
488
-
489
- // ✅ Our approach: O(N) - Per-item evaluation
490
- // With 50 directors = 50 evaluations (regardless of rule complexity)
491
- ```
492
-
493
- **Advanced Patterns:**
494
- ```tsx
495
- // Complex business logic with multiple conditions
496
- const productItemConditions = (product, index) => {
497
- const baseConfig = {
498
- price: { 'ui:widget': 'currency' },
499
- quantity: { 'ui:widget': 'number' }
500
- };
501
-
502
- // Category-specific fields
503
- if (product.category === 'software') {
504
- baseConfig.licenseType = { 'ui:widget': 'select' };
505
- baseConfig.maintenancePeriod = { 'ui:widget': 'hidden' };
506
- }
507
-
508
- // Subscription-specific logic
509
- if (product.billingType === 'subscription') {
510
- baseConfig.recurringPrice = { 'ui:widget': 'currency' };
511
- baseConfig.billingCycle = { 'ui:widget': 'select' };
104
+ items: createDynamicArrayItemsUiSchema((director, index) => ({
105
+ shareholdingPercentage: {
106
+ 'ui:widget': director.hasShareholding ? 'percentage' : 'hidden'
107
+ }
108
+ }))
512
109
  }
513
-
514
- return baseConfig;
515
- };
516
- ```
517
-
518
- ### Performance Best Practices
519
-
520
- > ⚠️ **Critical**: Always define rules and base schemas outside render or memoize them!
521
-
522
- ```tsx
523
- // ❌ BAD - Creates new objects every render
524
- function MyForm() {
525
- const conditionalUiSchema = useConditionalUi(
526
- [{ condition: () => true, effect: [...] }], // New array every render!
527
- { field: { 'ui:widget': 'text' } }, // New object every render!
528
- formData
529
- );
530
- }
531
-
532
- // ✅ GOOD - Stable references
533
- const rules = [{ condition: () => true, effect: [...] }];
534
- const baseUiSchema = { field: { 'ui:widget': 'text' } };
535
-
536
- function MyForm() {
537
- const conditionalUiSchema = useConditionalUi(rules, baseUiSchema, formData);
538
- }
539
- ```
540
-
541
- ### JsonLogic Conditions (Required)
542
-
543
- As of v0.2.0, ONLY JsonLogic conditions are supported for security and maintainability:
544
-
545
- ```tsx
546
- import { JsonLogicRule, UiRule } from 'extended-dynamic-forms/conditionals/v2';
547
-
548
- // JsonLogic rule examples
549
- const simpleRule: UiRule = {
550
- name: 'Show field B when A is true',
551
- condition: { "==": [{ "var": "fieldA" }, true] } as JsonLogicRule,
552
- effect: [{ op: 'remove', path: '/fieldB/ui:widget' }]
553
- };
554
-
555
- const complexRule: UiRule = {
556
- name: 'Complex business logic',
557
- condition: {
558
- "and": [
559
- { "==": [{ "var": "accountType" }, "premium"] },
560
- { ">": [{ "var": "revenue" }, 100000] },
561
- { "in": [{ "var": "country" }, ["USA", "Canada", "UK"]] }
562
- ]
563
- } as JsonLogicRule,
564
- effect: [{ op: 'remove', path: '/advancedFeatures/ui:widget' }]
565
110
  };
566
111
  ```
567
112
 
568
- ## Quick Start
569
-
570
- ### Simple Wizard Form (Recommended)
113
+ ## Multi-Step Wizard Forms
571
114
 
572
- The `WizardForm` component automatically detects multi-step forms and handles navigation. It fully supports conditional logic through the Three Pillars architecture:
115
+ Create wizard forms with automatic step detection:
573
116
 
574
- ```tsx
575
- import { useState } from 'react';
117
+ ```typescript
576
118
  import { WizardForm } from 'extended-dynamic-forms';
577
- import { useConditionalUi, UiRule } from 'extended-dynamic-forms/conditionals/v2';
578
- import schema from './schema.json';
579
- import baseUiSchema from './ui-schema.json';
580
- import webhooks from './webhooks.json';
581
-
582
- // Example: Three Pillars approach with JsonLogic (required)
583
- const uiRules: UiRule[] = [
584
- {
585
- name: 'Show tax ID in company step when listed',
586
- condition: {
587
- "==": [{ "var": "STEP_COMPANY.isListedCompany" }, true]
588
- } as JsonLogicRule,
589
- effect: [{ op: 'remove', path: '/STEP_COMPANY/taxId/ui:widget' }]
590
- },
591
- {
592
- name: 'Show shareholding percentage for directors with shares',
593
- condition: {
594
- "some": [
595
- { "var": "STEP_DIRECTORS.directors" },
596
- { "var": "hasShareholding" }
597
- ]
598
- } as JsonLogicRule,
599
- effect: [{ op: 'remove', path: '/STEP_DIRECTORS/directors/items/shareholdingPercentage/ui:widget' }]
600
- }
601
- ];
602
-
603
- function App() {
604
- const [formData, setFormData] = useState({});
605
- const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
606
-
607
- return (
608
- <WizardForm
609
- schema={schema}
610
- uiSchema={conditionalUiSchema}
611
- formData={formData}
612
- onChange={({ formData }) => setFormData(formData)}
613
- webhooks={webhooks}
614
- onSubmit={(data) => console.log('Submitted:', data.formData)}
615
- />
616
- );
617
- }
618
119
 
120
+ <WizardForm
121
+ schema={wizardSchema}
122
+ uiSchema={conditionalUiSchema}
123
+ formData={formData}
124
+ onStepChange={(fromStep, toStep) => {
125
+ console.log(`Step ${fromStep} → ${toStep}`);
126
+ }}
127
+ />
619
128
  ```
620
129
 
621
- ### Basic Form with Three Pillars
622
-
623
- ```tsx
624
- import { ExtendedForm } from 'extended-dynamic-forms';
625
- import { useConditionalUi, UiRule, JsonLogicRule } from 'extended-dynamic-forms/conditionals/v2';
130
+ **Important:** Wizard forms flatten nested step data. Use flat paths in conditions:
626
131
 
132
+ ```typescript
133
+ // Schema uses STEP_ prefixes
627
134
  const schema = {
628
- type: 'object',
629
135
  properties: {
630
- isStudent: { type: 'boolean', title: 'Are you a student?' },
631
- studentId: { type: 'string', title: 'Student ID' },
632
- school: { type: 'string', title: 'School Name' }
136
+ STEP_PERSONAL: {
137
+ properties: {
138
+ hasDriversLicense: { type: 'boolean' }
139
+ }
140
+ }
633
141
  }
634
142
  };
635
143
 
636
- const baseUiSchema = {
637
- studentId: { 'ui:widget': 'text' },
638
- school: { 'ui:widget': 'text' }
639
- };
640
-
641
- // Define UI rules outside component with JsonLogic
642
- const uiRules: UiRule[] = [
643
- {
644
- name: 'Show student fields when student',
645
- condition: {
646
- "!": { "var": "isStudent" }
647
- } as JsonLogicRule,
648
- effect: [
649
- { op: 'add', path: '/studentId/ui:widget', value: 'hidden' },
650
- { op: 'add', path: '/school/ui:widget', value: 'hidden' }
651
- ]
652
- }
653
- ];
654
-
655
- function App() {
656
- const [formData, setFormData] = useState({});
657
- const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
658
-
659
- return (
660
- <ExtendedForm
661
- schema={schema}
662
- uiSchema={conditionalUiSchema}
663
- formData={formData}
664
- onChange={({ formData }) => setFormData(formData)}
665
- />
666
- );
667
- }
144
+ // Conditions use flat paths (no STEP_ prefix)
145
+ condition: { "==": [{ "var": "hasDriversLicense" }, true] }
668
146
  ```
669
147
 
670
- ## Custom Widgets
148
+ ## Event System & Webhooks
671
149
 
672
- ### Available Widgets
150
+ Central event orchestration for all form interactions:
673
151
 
674
- The library includes enhanced versions of all standard RJSF widgets plus custom ones:
152
+ ```typescript
153
+ <ExtendedForm
154
+ schema={schema}
155
+ uiSchema={uiSchema}
156
+ webhooks={[{
157
+ url: 'https://api.example.com/events',
158
+ events: ['change', 'blur'],
159
+ debounceMs: 500,
160
+ retries: 3
161
+ }]}
162
+ onFieldChange={(event) => console.log(event.fieldId, event.fieldValue)}
163
+ />
164
+ ```
675
165
 
676
- #### Custom Widgets
166
+ **Event Types:**
167
+ - `focus` - Field focus
168
+ - `blur` - Field blur
169
+ - `change` - Value changes
170
+ - `submit` - Form submission
171
+ - `stepChange` - Wizard navigation
172
+ - `validationError` - Validation failures
677
173
 
678
- ```tsx
679
- // Color Picker
680
- const uiSchema = {
681
- favoriteColor: {
682
- 'ui:widget': 'color'
683
- }
684
- };
174
+ ## Custom Widgets
685
175
 
686
- // Rating Widget
687
- const uiSchema = {
688
- satisfaction: {
689
- 'ui:widget': 'rating',
690
- 'ui:options': {
691
- max: 10 // default is 5
692
- }
693
- }
694
- };
176
+ All widgets must integrate with the event system:
695
177
 
696
- // Range Slider
697
- const schema = {
698
- volume: {
699
- type: 'number',
700
- minimum: 0,
701
- maximum: 100
702
- }
703
- };
704
- const uiSchema = {
705
- volume: {
706
- 'ui:widget': 'range'
707
- }
708
- };
178
+ ```typescript
179
+ import { WidgetProps } from '@rjsf/utils';
180
+ import { useFieldEventHandlers } from 'extended-dynamic-forms/events';
709
181
 
710
- // File Upload
711
- const uiSchema = {
712
- documents: {
713
- 'ui:widget': 'file',
714
- 'ui:options': {
715
- accept: '.pdf,.doc,.docx',
716
- multiple: true
717
- }
718
- }
182
+ export const CustomWidget: FC<WidgetProps> = ({ id, value, onChange, schema }) => {
183
+ const fieldEventHandlers = useFieldEventHandlers(id, schema);
184
+
185
+ const handleChange = async (newValue) => {
186
+ onChange(newValue); // RJSF update
187
+ await fieldEventHandlers.onChange(newValue); // Event system
188
+ };
189
+
190
+ return <Input value={value} onChange={(e) => handleChange(e.target.value)} />;
719
191
  };
720
192
  ```
721
193
 
722
- #### Enhanced Standard Widgets
194
+ ## JsonLogic Migration Examples
723
195
 
724
- All standard RJSF widgets are enhanced with:
725
- - **Event Integration**: Automatic integration with the central event system
726
- - **Ant Design Styling**: Modern, consistent appearance
727
- - **Error States**: Proper error indication and messaging
728
- - **Accessibility**: Enhanced ARIA support
196
+ Common patterns for migrating from function-based conditions:
729
197
 
730
- ### Array Templates
198
+ ```typescript
199
+ // Equality
200
+ // Before: (formData) => formData.field === "value"
201
+ // After: { "==": [{ "var": "field" }, "value"] }
731
202
 
732
- The library provides Ant Design Card-based array templates for better visual organization:
733
- - **ArrayFieldTemplate**: Card container with proper spacing and visual hierarchy
734
- - **ArrayFieldItemTemplate**: Individual array items with integrated add/remove buttons
735
- - **Visual Design**: Clean card-based layout for array management
736
- - **Note**: Drag-and-drop reordering is not currently implemented
203
+ // Boolean check
204
+ // Before: (formData) => formData.isEnabled
205
+ // After: { "var": "isEnabled" }
737
206
 
738
- ## Central Event Orchestration System
207
+ // AND condition
208
+ // Before: (formData) => formData.a && formData.b
209
+ // After: { "and": [{ "var": "a" }, { "var": "b" }] }
739
210
 
740
- ### Field-Level Event Handling
211
+ // Array contains
212
+ // Before: (formData) => formData.roles?.includes("admin")
213
+ // After: { "in": ["admin", { "var": "roles" }] }
214
+ ```
741
215
 
742
- ```tsx
743
- import { ExtendedForm, type FormFieldEvent } from 'extended-dynamic-forms';
216
+ ## Available Widgets
744
217
 
745
- <ExtendedForm
746
- schema={schema}
747
- uiSchema={uiSchema}
748
- formData={formData}
749
-
750
- // Field-level event handlers
751
- onFieldFocus={(event: FormFieldEvent) => {
752
- console.log(`Field ${event.fieldId} focused:`, event.fieldValue);
753
- }}
754
-
755
- onFieldChange={(event: FormFieldEvent) => {
756
- console.log(`Field ${event.fieldId} changed:`, event.fieldValue);
757
- // Real-time validation or processing
758
- }}
759
-
760
- onFieldBlur={(event: FormFieldEvent) => {
761
- console.log(`Field ${event.fieldId} blurred:`, event.fieldValue);
762
- }}
763
- />
764
- ```
218
+ ### Complete Widget List
765
219
 
766
- ### Enhanced Webhook Integration
767
-
768
- Configure multiple webhook endpoints to receive real-time form events, including form-level events for submit, validation errors, and wizard step changes:
769
-
770
- ```tsx
771
- import { ExtendedForm, WizardForm, type WebhookConfig } from 'extended-dynamic-forms';
772
-
773
- // Comprehensive webhook configuration for all event types
774
- const webhookConfigs: WebhookConfig[] = [
775
- {
776
- url: 'https://api.yourapp.com/form-events',
777
- method: 'POST',
778
- events: ['change', 'blur', 'submit', 'validationError'], // Multiple event types
779
- debounceMs: 500, // Wait 500ms before sending (field events)
780
- retries: 3, // Retry failed requests
781
- timeout: 5000, // 5 second timeout
782
- headers: {
783
- 'Authorization': 'Bearer your-api-token',
784
- 'X-Form-ID': 'contact-form'
785
- }
786
- },
787
- {
788
- url: 'https://analytics.yourapp.com/wizard-tracking',
789
- method: 'POST',
790
- events: ['stepChange', 'submit'], // Wizard-specific events
791
- debounceMs: 0, // No debouncing for navigation
792
- headers: {
793
- 'X-Session-ID': sessionId
794
- }
795
- }
796
- ];
220
+ #### Choice Widget (Unified Selection)
221
+ - **ChoiceWidget** - Intelligent widget that automatically adapts based on schema:
222
+ - Renders as dropdown/select for regular choices
223
+ - Renders as radio group when `ui:widget` is "radio"
224
+ - Renders as checkbox group for multi-select arrays
225
+ - Supports static and dynamic data sources (API, WebSocket)
797
226
 
798
- // Use with ExtendedForm - includes webhook status callbacks
799
- <ExtendedForm
800
- schema={schema}
801
- uiSchema={uiSchema}
802
- webhooks={webhookConfigs}
803
- onWebhookStart={(webhook, event) => {
804
- console.log('Webhook started:', webhook.url, event.eventType);
805
- }}
806
- onWebhookComplete={(webhook, event, response) => {
807
- console.log('Webhook completed:', response.status);
808
- }}
809
- onWebhookError={(webhook, event, error) => {
810
- console.error('Webhook failed:', error.message);
811
- }}
812
- />
227
+ #### Text Input Widgets
228
+ - **TextWidget** - Standard text input with Ant Design styling
229
+ - **TextareaWidget** - Multi-line text input
230
+ - **PasswordWidget** - Password input with visibility toggle
813
231
 
814
- // Use with WizardForm - automatically tracks step changes
815
- <WizardForm
816
- schema={wizardSchema}
817
- uiSchema={wizardUiSchema}
818
- webhooks={webhookConfigs}
819
- onWebhookError={(webhook, event, error) => {
820
- // Handle webhook failures gracefully
821
- notifyUser('Form data saved locally, will sync when online');
822
- }}
823
- />
824
- ```
232
+ #### Specialized Input Widgets
233
+ - **ColorWidget** - Color picker using HTML5 color input
234
+ - **EmailWidget** - Email input with validation
235
+ - **URLWidget** - URL input with validation
236
+ - **TelephoneWidget** - Phone number input
237
+ - **NumberWidget** - Numeric input with increment/decrement controls
825
238
 
826
- #### Webhook Event Types and Payloads
239
+ #### Visual Input Widgets
240
+ - **RangeWidget** / **SliderWidget** - Slider for numeric ranges
241
+ - **RatingWidget** - Star rating component
827
242
 
828
- All webhook events follow a standardized payload structure with common fields plus event-specific data:
243
+ #### Date & Time Widgets
244
+ - **DateWidget** / **EnhancedDateWidget** - Date picker with Ant Design DatePicker
245
+ - **DateTimeWidget** - Combined date and time picker
829
246
 
830
- ##### Field Events (existing)
831
- ```typescript
832
- // Focus, Blur, Change events
833
- {
834
- eventType: 'focus' | 'blur' | 'change',
835
- fieldId: 'email',
836
- fieldValue: 'user@example.com',
837
- schema: { type: 'string', format: 'email' },
838
- fieldPath: ['contact', 'email'],
839
- timestamp: 1234567890123,
840
- formData: { /* complete form data */ },
841
- source: 'extended-dynamic-forms'
842
- }
843
- ```
247
+ #### File Upload Widgets
248
+ - **FileWidget** - Basic file input
249
+ - **FileUploadWidget** - Enhanced upload with progress, preview, and base64 support
844
250
 
845
- ##### Submit Event
846
- ```typescript
847
- // Triggered after successful form submission
251
+ ### Widget Configuration Examples
252
+
253
+ #### Basic Text Input
254
+ ```json
848
255
  {
849
- eventType: 'submit',
850
- formData: {
851
- name: 'John Doe',
852
- email: 'john@example.com',
853
- // ... all submitted data
256
+ "schema": {
257
+ "type": "string",
258
+ "title": "Full Name"
854
259
  },
855
- timestamp: 1234567890123,
856
- source: 'extended-dynamic-forms'
260
+ "uiSchema": {
261
+ "ui:widget": "text",
262
+ "ui:placeholder": "Enter your full name"
263
+ }
857
264
  }
858
265
  ```
859
266
 
860
- ##### Step Change Event (WizardForm only)
861
- ```typescript
862
- // Triggered when user navigates between wizard steps
267
+ #### Number Input with Range
268
+ ```json
863
269
  {
864
- eventType: 'stepChange',
865
- fromStep: 0, // Previous step index
866
- toStep: 1, // New step index
867
- formData: { /* current form data */ },
868
- timestamp: 1234567890123,
869
- source: 'extended-dynamic-forms'
270
+ "schema": {
271
+ "type": "number",
272
+ "title": "Age",
273
+ "minimum": 0,
274
+ "maximum": 120
275
+ },
276
+ "uiSchema": {
277
+ "ui:widget": "number"
278
+ }
870
279
  }
871
280
  ```
872
281
 
873
- ##### Validation Error Event
874
- ```typescript
875
- // Triggered when form validation fails
282
+ #### Rating Widget
283
+ ```json
876
284
  {
877
- eventType: 'validationError',
878
- errors: [
879
- {
880
- property: '.email',
881
- message: 'Email is required',
882
- name: 'required',
883
- stack: '.email Email is required',
884
- schemaPath: '#/properties/email'
885
- },
886
- {
887
- property: '.age',
888
- message: 'Age must be at least 18',
889
- name: 'minimum',
890
- argument: 18,
891
- stack: '.age Age must be at least 18',
892
- schemaPath: '#/properties/age/minimum'
285
+ "schema": {
286
+ "type": "number",
287
+ "title": "Rate your experience",
288
+ "minimum": 0,
289
+ "maximum": 5
290
+ },
291
+ "uiSchema": {
292
+ "ui:widget": "rating",
293
+ "ui:options": {
294
+ "count": 5,
295
+ "allowHalf": true
893
296
  }
894
- ],
895
- formData: { /* form data that failed validation */ },
896
- timestamp: 1234567890123,
897
- source: 'extended-dynamic-forms'
297
+ }
898
298
  }
899
299
  ```
900
300
 
901
- #### Advanced Webhook Examples
902
-
903
- ##### Form Analytics and Monitoring
904
- ```tsx
905
- // Track user behavior and form completion rates
906
- const analyticsWebhook: WebhookConfig = {
907
- url: 'https://analytics.yourapp.com/form-events',
908
- events: ['stepChange', 'submit', 'validationError'],
909
- headers: {
910
- 'X-Analytics-Key': process.env.ANALYTICS_KEY
301
+ #### Choice Widget (Dropdown)
302
+ ```json
303
+ {
304
+ "schema": {
305
+ "type": "string",
306
+ "title": "Country",
307
+ "enum": ["us", "uk", "au", "ca"],
308
+ "enumNames": ["United States", "United Kingdom", "Australia", "Canada"]
309
+ },
310
+ "uiSchema": {
311
+ "ui:widget": "choice"
911
312
  }
912
- };
913
-
914
- // Monitor form health and errors
915
- const monitoringWebhook: WebhookConfig = {
916
- url: 'https://monitoring.yourapp.com/form-errors',
917
- events: ['validationError'], // Only track errors
918
- method: 'POST',
919
- retries: 5 // Ensure error tracking is reliable
920
- };
313
+ }
921
314
  ```
922
315
 
923
- ##### Progressive Form Saving
924
- ```tsx
925
- // Auto-save form progress
926
- const autoSaveWebhook: WebhookConfig = {
927
- url: 'https://api.yourapp.com/form-drafts',
928
- events: ['change', 'stepChange'],
929
- debounceMs: 2000, // Save every 2 seconds of inactivity
930
- headers: {
931
- 'X-User-ID': userId,
932
- 'X-Draft': 'true'
933
- }
934
- };
935
-
936
- // Final submission
937
- const submitWebhook: WebhookConfig = {
938
- url: 'https://api.yourapp.com/form-submissions',
939
- events: ['submit'],
940
- headers: {
941
- 'X-User-ID': userId,
942
- 'X-Final': 'true'
316
+ #### Choice Widget (Radio Group)
317
+ ```json
318
+ {
319
+ "schema": {
320
+ "type": "string",
321
+ "title": "Gender",
322
+ "enum": ["male", "female", "other"]
323
+ },
324
+ "uiSchema": {
325
+ "ui:widget": "choice",
326
+ "ui:options": {
327
+ "presenter": "radio"
328
+ }
943
329
  }
944
- };
330
+ }
945
331
  ```
946
332
 
947
- ##### Conditional Webhook Logic
948
- ```tsx
949
- // Different endpoints based on form data
950
- function App() {
951
- const [formData, setFormData] = useState({});
952
-
953
- // Dynamic webhook configuration based on form state
954
- const webhooks = useMemo(() => {
955
- const configs: WebhookConfig[] = [];
956
-
957
- // Add region-specific webhook
958
- if (formData.country === 'USA') {
959
- configs.push({
960
- url: 'https://us-api.yourapp.com/forms',
961
- events: ['submit'],
962
- headers: { 'X-Region': 'US' }
963
- });
964
- } else if (formData.country === 'EU') {
965
- configs.push({
966
- url: 'https://eu-api.yourapp.com/forms',
967
- events: ['submit'],
968
- headers: { 'X-Region': 'EU', 'X-GDPR': 'true' }
969
- });
333
+ #### Choice Widget (Checkbox Group - Multi-select)
334
+ ```json
335
+ {
336
+ "schema": {
337
+ "type": "array",
338
+ "title": "Interests",
339
+ "items": {
340
+ "type": "string",
341
+ "enum": ["sports", "music", "reading", "travel"]
342
+ },
343
+ "uniqueItems": true
344
+ },
345
+ "uiSchema": {
346
+ "ui:widget": "choice",
347
+ "ui:options": {
348
+ "presenter": "checkbox"
970
349
  }
971
-
972
- return configs;
973
- }, [formData.country]);
974
-
975
- return (
976
- <ExtendedForm
977
- schema={schema}
978
- formData={formData}
979
- onChange={({ formData }) => setFormData(formData)}
980
- webhooks={webhooks}
981
- />
982
- );
350
+ }
983
351
  }
984
352
  ```
985
353
 
986
- ##### Error Handling and Retry Strategies
987
- ```tsx
988
- // Robust webhook configuration with fallbacks
989
- const primaryWebhook: WebhookConfig = {
990
- url: 'https://api.yourapp.com/primary',
991
- events: ['submit'],
992
- timeout: 5000,
993
- retries: 3
994
- };
995
-
996
- // Fallback webhook for critical data
997
- const fallbackWebhook: WebhookConfig = {
998
- url: 'https://backup.yourapp.com/forms',
999
- events: ['submit'],
1000
- timeout: 10000,
1001
- retries: 5
1002
- };
1003
-
1004
- <ExtendedForm
1005
- webhooks={[primaryWebhook, fallbackWebhook]}
1006
- onWebhookError={(webhook, event, error) => {
1007
- if (webhook.url === primaryWebhook.url) {
1008
- console.log('Primary webhook failed, fallback will handle');
354
+ #### Date Picker
355
+ ```json
356
+ {
357
+ "schema": {
358
+ "type": "string",
359
+ "title": "Date of Birth",
360
+ "format": "date"
361
+ },
362
+ "uiSchema": {
363
+ "ui:widget": "date",
364
+ "ui:options": {
365
+ "format": "DD/MM/YYYY",
366
+ "picker": "date"
1009
367
  }
1010
-
1011
- // Store locally for later sync
1012
- localStorage.setItem(`pending-${Date.now()}`, JSON.stringify(event));
1013
- }}
1014
- />
1015
- ```
1016
-
1017
-
1018
- ## API Reference
1019
-
1020
- ### ExtendedFormProps
1021
-
1022
- ```typescript
1023
- interface ExtendedFormProps<T = any, S extends RJSFSchema = RJSFSchema, F = any> extends FormProps<T, S, F> {
1024
- // Standard RJSF props
1025
- schema: S;
1026
- uiSchema?: UiSchema<T, S, F>;
1027
- formData?: T;
1028
- onSubmit?: (data: IChangeEvent<T, S, F>, event?: React.FormEvent<HTMLFormElement>) => void;
1029
- onChange?: (data: IChangeEvent<T, S, F>) => void;
1030
-
1031
- // Field-level event handlers
1032
- onFieldFocus?: (event: FormFieldEvent) => Promise<void> | void;
1033
- onFieldBlur?: (event: FormFieldEvent) => Promise<void> | void;
1034
- onFieldChange?: (event: FormFieldEvent) => Promise<void> | void;
1035
-
1036
- // Webhook configuration
1037
- webhooks?: WebhookConfig[];
1038
-
1039
- // Webhook status callbacks
1040
- onWebhookStart?: (webhook: WebhookConfig, event: any) => void;
1041
- onWebhookComplete?: (webhook: WebhookConfig, event: any, response: any) => void;
1042
- onWebhookError?: (webhook: WebhookConfig, event: any, error: Error) => void;
1043
-
1044
-
1045
- // Form lifecycle events
1046
- beforeSubmit?: (data: T) => Promise<T> | T;
1047
- afterSubmit?: (data: T) => Promise<void> | void;
1048
- beforeValidation?: (data: T) => Promise<T> | T;
1049
- afterValidation?: (data: T, errors: RJSFValidationError[]) => Promise<void> | void;
368
+ }
1050
369
  }
1051
370
  ```
1052
371
 
1053
- ### WebhookConfig
1054
-
1055
- ```typescript
1056
- interface WebhookConfig {
1057
- url: string;
1058
- method?: 'POST' | 'PUT' | 'PATCH';
1059
- headers?: Record<string, string>;
1060
- events?: ('focus' | 'blur' | 'change' | 'submit' | 'stepChange' | 'validationError')[];
1061
- debounceMs?: number;
1062
- retries?: number;
1063
- timeout?: number;
372
+ #### File Upload
373
+ ```json
374
+ {
375
+ "schema": {
376
+ "type": "string",
377
+ "title": "Resume",
378
+ "format": "data-url"
379
+ },
380
+ "uiSchema": {
381
+ "ui:widget": "FileUploadWidget",
382
+ "ui:options": {
383
+ "accept": ".pdf,.doc,.docx",
384
+ "maxSize": 5242880,
385
+ "multiple": false
386
+ }
387
+ }
1064
388
  }
1065
389
  ```
1066
390
 
1067
- ### Webhook Event Types
1068
-
1069
- ```typescript
1070
- type WebhookEventType = 'focus' | 'blur' | 'change' | 'submit' | 'stepChange' | 'validationError';
1071
-
1072
- // Base event structure
1073
- interface BaseWebhookEvent {
1074
- eventType: WebhookEventType;
1075
- timestamp: number;
1076
- formData: any;
1077
- source: 'extended-dynamic-forms';
1078
- }
1079
-
1080
- // Field events
1081
- interface FieldWebhookEvent extends BaseWebhookEvent {
1082
- eventType: 'focus' | 'blur' | 'change';
1083
- fieldId: string;
1084
- fieldValue: any;
1085
- schema?: any;
1086
- fieldPath?: string[];
1087
- }
1088
-
1089
- // Submit event
1090
- interface SubmitWebhookEvent extends BaseWebhookEvent {
1091
- eventType: 'submit';
1092
- }
1093
-
1094
- // Step change event
1095
- interface StepChangeWebhookEvent extends BaseWebhookEvent {
1096
- eventType: 'stepChange';
1097
- fromStep: number;
1098
- toStep: number;
1099
- }
1100
-
1101
- // Validation error event
1102
- interface ValidationErrorWebhookEvent extends BaseWebhookEvent {
1103
- eventType: 'validationError';
1104
- errors: Array<{
1105
- property: string;
1106
- message: string;
1107
- name: string;
1108
- argument?: any;
1109
- stack: string;
1110
- schemaPath: string;
1111
- }>;
391
+ #### Color Picker
392
+ ```json
393
+ {
394
+ "schema": {
395
+ "type": "string",
396
+ "title": "Favorite Color",
397
+ "format": "color"
398
+ },
399
+ "uiSchema": {
400
+ "ui:widget": "color"
401
+ }
1112
402
  }
1113
403
  ```
1114
404
 
1115
- ### Three Pillars Hooks
1116
-
1117
- ```typescript
1118
- // UI Logic Pillar
1119
- function useConditionalUi(
1120
- rules: UiRule[],
1121
- baseUiSchema: UiSchema,
1122
- formData: any
1123
- ): UiSchema
1124
-
1125
- // Schema Logic Pillar
1126
- function useConditionalSchema(
1127
- rules: SchemaRule[],
1128
- baseSchema: RJSFSchema,
1129
- formData: any
1130
- ): RJSFSchema
1131
-
1132
- // Validation Logic Pillar
1133
- function useConditionalValidation(
1134
- rules: ValidationRule[],
1135
- baseConfig: ValidationConfig,
1136
- formData: any
1137
- ): ValidationConfig
1138
- ```
1139
-
1140
- ## Real-World Use Cases
1141
-
1142
- ### 🏢 Enterprise Business Applications
1143
-
1144
- **Australian Company Registration** (Featured Demo)
1145
- ```tsx
1146
- // Complete 5-step wizard with dynamic conditionals
1147
- const companyOnboardingSchema = {
1148
- STEP_COMPANY: { /* Company details */ },
1149
- STEP_DIRECTORS: { /* Dynamic director array */ },
1150
- STEP_ADDRESS: { /* Address with postal logic */ },
1151
- STEP_FINANCIAL: { /* Banking with international support */ },
1152
- STEP_COMPLIANCE: { /* Regulatory requirements */ }
1153
- };
1154
-
1155
- // Per-director conditionals with O(N) performance
1156
- const uiSchema = {
1157
- STEP_DIRECTORS: {
1158
- directors: {
1159
- items: createDynamicArrayItemsUiSchema((director) => ({
1160
- tfn: { 'ui:widget': director.isAustralianResident ? 'text' : 'hidden' },
1161
- passport: { 'ui:widget': !director.isAustralianResident ? 'text' : 'hidden' }
1162
- }))
405
+ #### Range/Slider Widget
406
+ ```json
407
+ {
408
+ "schema": {
409
+ "type": "number",
410
+ "title": "Volume",
411
+ "minimum": 0,
412
+ "maximum": 100
413
+ },
414
+ "uiSchema": {
415
+ "ui:widget": "range",
416
+ "ui:options": {
417
+ "marks": {
418
+ "0": "Mute",
419
+ "50": "50%",
420
+ "100": "Max"
421
+ }
1163
422
  }
1164
423
  }
1165
- };
424
+ }
1166
425
  ```
1167
426
 
1168
- ### 💼 Multi-Step Workflows
1169
-
1170
- **Loan Applications**
1171
- - Conditional document requirements based on loan type
1172
- - Income verification with employment status logic
1173
- - Asset declaration with property type conditionals
1174
-
1175
- **Employee Onboarding**
1176
- - Role-based form sections (technical vs. non-technical)
1177
- - Security clearance workflows
1178
- - Benefits enrollment with eligibility rules
1179
-
1180
- **Grant Applications**
1181
- - Multi-stage submissions with validation gates
1182
- - Budget calculations with category-based rules
1183
- - Compliance checks based on funding type
1184
-
1185
- ### 🔄 Dynamic Array Management
1186
-
1187
- **Board of Directors Management**
1188
- ```tsx
1189
- // Professional-grade array handling with O(N) performance
1190
- import { createDynamicArrayItemsUiSchema } from 'extended-dynamic-forms';
1191
-
1192
- const uiSchema = {
1193
- STEP_DIRECTORS: {
1194
- directors: {
1195
- items: createDynamicArrayItemsUiSchema((director, index) => ({
1196
- shareholdingPercentage: {
1197
- 'ui:widget': director.hasShareholding ? 'percentage' : 'hidden'
1198
- },
1199
- tfn: {
1200
- 'ui:widget': director.isAustralianResident ? 'text' : 'hidden'
1201
- },
1202
- passport: {
1203
- 'ui:widget': !director.isAustralianResident ? 'text' : 'hidden'
1204
- }
1205
- }))
1206
- }
427
+ #### Hidden Field
428
+ ```json
429
+ {
430
+ "schema": {
431
+ "type": "string",
432
+ "title": "User ID"
433
+ },
434
+ "uiSchema": {
435
+ "ui:widget": "hidden"
1207
436
  }
1208
- };
437
+ }
1209
438
  ```
1210
439
 
1211
- **Product Configurations**
1212
- - Dynamic product options based on category
1213
- - Pricing calculations with quantity breaks
1214
- - Feature availability by subscription tier
1215
-
1216
- **Address Management**
1217
- - International vs. domestic address formats
1218
- - State/province selection based on country
1219
- - Postal code validation by region
440
+ ### Widget Registration
1220
441
 
1221
- ### 🌐 CMS & Integration Use Cases
442
+ Register custom widgets with ExtendedForm:
1222
443
 
1223
- **WordPress/Drupal Forms**
1224
- ```html
1225
- <!-- Standalone JavaScript integration -->
1226
- <script>
1227
- const { createWizard } = ExtendedDynamicForms;
1228
-
1229
- createWizard({
1230
- schema: wpFormSchema,
1231
- container: '#wp-form-container',
1232
- onSubmit: (data) => {
1233
- // Submit to WordPress REST API
1234
- wp.apiRequest({ path: '/wp/v2/forms', method: 'POST', data });
1235
- }
1236
- });
1237
- </script>
1238
- ```
1239
-
1240
- **Legacy System Modernization**
1241
- - Drop-in replacement for static HTML forms
1242
- - Progressive enhancement of existing forms
1243
- - No-build deployment to production environments
1244
-
1245
- ## Architecture
444
+ ```typescript
445
+ import { ExtendedForm, customWidgets } from 'extended-dynamic-forms';
1246
446
 
1247
- Extended Dynamic Forms uses a layered architecture that cleanly extends RJSF:
447
+ // Use all built-in widgets
448
+ <ExtendedForm
449
+ widgets={customWidgets}
450
+ schema={schema}
451
+ uiSchema={uiSchema}
452
+ />
1248
453
 
454
+ // Or register specific widgets
455
+ <ExtendedForm
456
+ widgets={{
457
+ text: customWidgets.text,
458
+ date: customWidgets.date,
459
+ choice: customWidgets.choice
460
+ }}
461
+ />
1249
462
  ```
1250
- ┌─────────────────────────────────────────────────┐
1251
- │ Three Pillars v2 (Conditional System) │
1252
- ├─────────────────────────────────────────────────┤
1253
- │ Application Layer (WizardForm) │
1254
- ├─────────────────────────────────────────────────┤
1255
- │ Event Layer (FormEventHub) │
1256
- ├─────────────────────────────────────────────────┤
1257
- │ Component Layer (Widgets/Fields/Templates) │
1258
- ├─────────────────────────────────────────────────┤
1259
- │ Base Layer (@rjsf/antd) │
1260
- └─────────────────────────────────────────────────┘
1261
- ```
1262
-
1263
- ## Feature Comparison
1264
-
1265
- | Feature | Basic RJSF | Extended Dynamic Forms |
1266
- |---------|------------|----------------------|
1267
- | **Form Generation** | ✅ JSON Schema | ✅ Enhanced JSON Schema |
1268
- | **UI Components** | Basic HTML | ✅ Comprehensive Ant Design Suite |
1269
- | **Conditional Logic** | ❌ Manual | ✅ Three Pillars (O(N)) |
1270
- | **Multi-Step Forms** | ❌ Manual | ✅ Automatic Wizard Detection |
1271
- | **Event System** | Basic onChange | ✅ Central Event Orchestration |
1272
- | **Webhook Integration** | ❌ None | ✅ Production-Ready with Retry |
1273
- | **Array Conditionals** | ❌ None | ✅ Per-Item O(N) Performance |
1274
- | **TypeScript** | Partial | ✅ Comprehensive Type Definitions |
1275
- | **Standalone JS** | ❌ React Only | ✅ Complete UMD Bundle |
1276
- | **Testing** | Basic | ⚠️ Focused on Conditionals/Wizards |
1277
- | **Performance** | Standard | ✅ Optimized with Caching |
1278
- | **Validation** | Basic | ✅ Dynamic + Custom Rules |
1279
- | **Developer Tools** | Limited | ✅ Interactive Playground |
1280
463
 
1281
464
  ## Development
1282
465
 
1283
- ### 🚀 Quick Start
1284
-
1285
- > **Development Setup Note**: Due to local file dependencies, you need:
1286
- > 1. Clone RJSF repository in a sibling directory: `../react-jsonschema-form/`
1287
- > 2. Ensure the RJSF packages are built and available
1288
-
1289
466
  ```bash
1290
- # Clone and setup (requires specific directory structure)
1291
- git clone https://github.com/user/extended-dynamic-forms.git
1292
- cd extended-dynamic-forms
1293
- npm install # Note: Will fail without ../react-jsonschema-form/ directory
467
+ # Development
468
+ npm run dev # Start playground
469
+ npm run test # Run tests
470
+ npm run test:ui # Test with UI
1294
471
 
1295
- # Start development with playground
1296
- npm run dev # Launches interactive playground
1297
- npm run playground # Alternative playground command
472
+ # Building
473
+ npm run build # Build library
474
+ npm run build:vanilla # Build standalone (currently broken - JsonLogic incompatible)
475
+ npm run preview # Preview build
1298
476
 
1299
- # Development workflow
1300
- npm run test # Run complete test suite
1301
- npm run test:ui # Visual test runner
1302
- npm run lint # ESLint validation
1303
- npm run format # Prettier formatting
477
+ # Code Quality
478
+ npm run lint # ESLint
479
+ npm run format # Prettier
1304
480
  ```
1305
481
 
1306
- ### 📦 Build Commands
482
+ ## Project Structure
1307
483
 
1308
- ```bash
1309
- # Library builds
1310
- npm run build # TypeScript + Vite library build
1311
- npm run build:vanilla # Standalone UMD bundle
1312
- npm run build:all # Both library and standalone
1313
-
1314
- # Production validation
1315
- npm run preview # Preview library build
1316
- npm run serve:examples # Serve vanilla JS examples
1317
- ```
1318
-
1319
- ### 🧪 Testing
1320
-
1321
- **Test Coverage**: Test suite focuses primarily on:
1322
- - **Conditional Logic**: Comprehensive coverage for conditional systems (16+ test files)
1323
- - **Wizard Forms**: Step navigation and validation
1324
- - **Performance**: Array conditional optimization
1325
- - **Note**: Limited coverage for UI components, event system, and utility functions
1326
-
1327
- ```bash
1328
- npm run test # Run complete test suite
1329
- npm run test -- --grep "conditional" # Test conditional logic
1330
- npm run test -- --grep "wizard" # Test wizard forms
1331
- npm run test -- --grep "array" # Test array handling
1332
- ```
1333
-
1334
- ### 🏗️ Architecture
1335
-
1336
- **Build Configuration**:
1337
- - **Library**: ES + UMD via Vite with TypeScript declarations
1338
- - **Standalone**: Complete UMD bundle with React/antd included
1339
- - **External Dependencies**: React, antd marked as externals in library build
1340
- - **Type Generation**: `vite-plugin-dts` for .d.ts files
1341
-
1342
- **File Structure**:
1343
484
  ```
1344
485
  src/
1345
- ├── ExtendedForm.tsx # Main form wrapper
1346
- ├── WizardForm.tsx # Multi-step orchestrator
1347
- ├── conditionals/ # Conditional systems
1348
- │ ├── v2/ # Three Pillars architecture
1349
- │ └── DynamicArrayConditionalEngine.ts
1350
- ├── events/ # Central event orchestration
1351
- ├── widgets/ # Enhanced component suite
1352
- ├── components/ # Field and template components
1353
- └── utils/ # Utilities (Note: 76% are unused)
1354
- ```
1355
-
1356
- ## Examples & Demos
1357
-
1358
- ### 🎮 Interactive Playground
1359
-
1360
- The library includes a comprehensive **interactive playground** with extensive real-world demos demonstrating all features:
1361
-
1362
- ```bash
1363
- # Run the playground locally
1364
- npm run dev
1365
- # or
1366
- npm run playground
1367
- ```
1368
-
1369
- ### 📚 Demo Categories
1370
-
1371
- > **Note**: Some playground demos may be outdated.
1372
-
1373
- #### **Three Pillars Demonstrations**
1374
- - **Global UI Rules**: Dynamic show/hide with JSON Patch operations
1375
- - **Dynamic Array Items**: Per-item conditional logic with O(N) performance
1376
- - **Conditional Validation**: Custom validation rules without schema changes
1377
-
1378
- #### **🧙‍♂️ Wizard Form Showcases**
1379
- - **Australian Company Onboarding**: 5-step enterprise form with:
1380
- - Dynamic director arrays with per-item conditionals
1381
- - Real-time fee calculations based on business rules
1382
- - Complex validation (ABN/ACN numbers, postcodes)
1383
- - Step-aware conditional logic
1384
- - Professional business workflow
1385
-
1386
- #### **🔗 Event System Demos**
1387
- - **Real-time Form Analytics**: Webhook integration with retry logic
1388
- - **Field-Level Event Handling**: Focus/blur/change event orchestration
1389
- - **Form-Level Event Handling**: Submit, validation error, and step change events
1390
- - **Webhook Configuration**: Multiple endpoints with custom headers and event filtering
1391
- - **Webhook Status Tracking**: Callbacks for monitoring webhook success/failure
1392
-
1393
- #### **🎨 Widget Showcase**
1394
- - **Enhanced Standard Widgets**: All RJSF widgets with Ant Design styling
1395
- - **Custom Widgets**: Color picker, rating, range slider, file upload
1396
- - **Professional Fields**: Address, currency, phone number components
1397
-
1398
- ### 📱 Vanilla JavaScript Examples
1399
-
1400
- Complete standalone examples in `/examples/vanilla-js/`:
1401
-
1402
- ```html
1403
- <!-- Basic Form -->
1404
- basic-form.html <!-- Simple contact form -->
1405
- conditional-form.html <!-- Dynamic field visibility -->
1406
- wizard-form.html <!-- Multi-step onboarding -->
1407
- ```
1408
-
1409
- ### 🔗 Live Demo Links
1410
-
1411
- - **[Playground](https://extended-dynamic-forms-playground.vercel.app)** - Interactive demo environment
1412
- - **[Australian Company Onboarding](https://extended-dynamic-forms-playground.vercel.app/wizard/australian-company)** - Full enterprise form showcase
1413
- - **[Three Pillars Demo](https://extended-dynamic-forms-playground.vercel.app/conditionals/three-pillars)** - Modern conditional logic patterns
1414
-
1415
- ## Contributing
1416
-
1417
- We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
1418
-
1419
- ## Migration Guide: Enhanced Webhook Events
1420
-
1421
- ### Upgrading to Enhanced Webhook System
1422
-
1423
- The enhanced webhook system is **fully backward compatible**. Existing webhook configurations will continue to work without any changes. The new event types are additive and opt-in.
1424
-
1425
- #### For Existing Webhook Users
1426
-
1427
- Your current webhook configurations will continue to work exactly as before:
1428
-
1429
- ```typescript
1430
- // This existing configuration still works perfectly
1431
- const webhookConfig: WebhookConfig = {
1432
- url: 'https://api.example.com/form-events',
1433
- method: 'POST',
1434
- debounceMs: 500
1435
- };
1436
- // Without the 'events' array, it receives ALL events (backward compatible)
486
+ ├── components/ # Core form components
487
+ ├── conditionals/ # Three Pillars system
488
+ │ └── v2/ # Current implementation
489
+ ├── events/ # Event orchestration
490
+ ├── layouts/ # Layout systems
491
+ │ └── wizard/ # Wizard form components
492
+ ├── widgets/ # Input widgets
493
+ └── utils/ # Utilities
1437
494
  ```
1438
495
 
1439
- To take advantage of new event types:
496
+ ## Examples
1440
497
 
1441
- ```typescript
1442
- // Option 1: Subscribe to specific new events only
1443
- const webhookConfig: WebhookConfig = {
1444
- url: 'https://api.example.com/form-events',
1445
- events: ['submit', 'validationError'], // Only these new events
1446
- debounceMs: 1000
1447
- };
498
+ Interactive examples available at `/playground/src/demos/`:
1448
499
 
1449
- // Option 2: Mix old and new events
1450
- const webhookConfig: WebhookConfig = {
1451
- url: 'https://api.example.com/form-events',
1452
- events: ['change', 'blur', 'submit', 'stepChange'], // Mixed event types
1453
- debounceMs: 500
1454
- };
1455
- ```
500
+ - **Wizard Forms**: Australian Company Onboarding, Employee Onboarding
501
+ - **Conditionals**: Dynamic visibility, validation, array handling
502
+ - **Events**: Webhook integration, field tracking
503
+ - **Widgets**: All available components
1456
504
 
1457
- #### For New Implementations
505
+ Run `npm run dev` to explore examples.
1458
506
 
1459
- If you're implementing webhooks for the first time, consider these patterns:
507
+ ## Known Limitations
1460
508
 
1461
- ```typescript
1462
- // Complete form lifecycle monitoring
1463
- const lifecycleWebhook: WebhookConfig = {
1464
- url: 'https://api.example.com/form-lifecycle',
1465
- events: ['focus', 'change', 'blur', 'submit', 'validationError'],
1466
- method: 'POST',
1467
- headers: {
1468
- 'X-API-Key': 'your-api-key'
1469
- },
1470
- debounceMs: 500,
1471
- retries: 3,
1472
- timeout: 10000
1473
- };
1474
-
1475
- // Wizard-specific tracking
1476
- const wizardWebhook: WebhookConfig = {
1477
- url: 'https://analytics.example.com/wizard-tracking',
1478
- events: ['stepChange', 'submit'],
1479
- method: 'POST',
1480
- debounceMs: 0, // No debouncing for navigation events
1481
- retries: 1
1482
- };
1483
-
1484
- // Error monitoring only
1485
- const errorWebhook: WebhookConfig = {
1486
- url: 'https://monitoring.example.com/form-errors',
1487
- events: ['validationError'],
1488
- method: 'POST',
1489
- retries: 5 // Ensure error tracking is reliable
1490
- };
1491
- ```
509
+ 1. **Dependencies**: Requires RJSF source in sibling directory
510
+ 2. **Installation**: Cannot install from npm
511
+ 3. **Vanilla JS**: JsonLogic not supported in standalone builds
512
+ 4. **Arrays**: No drag-and-drop functionality
513
+ 5. **JSON Patch**: Only supports add/remove/replace operations
514
+ 6. **Test Coverage**: Limited for UI components and events
1492
515
 
1493
- #### Using Webhook Status Callbacks
516
+ ## TypeScript
1494
517
 
1495
- The new webhook status callbacks provide visibility into webhook processing:
518
+ Full TypeScript support with exported types:
1496
519
 
1497
520
  ```typescript
1498
- <ExtendedForm
1499
- schema={schema}
1500
- webhooks={webhooks}
1501
- onWebhookStart={(webhook, event) => {
1502
- // Show loading indicator
1503
- setWebhookLoading(true);
1504
- }}
1505
- onWebhookComplete={(webhook, event, response) => {
1506
- // Hide loading indicator
1507
- setWebhookLoading(false);
1508
-
1509
- // Handle success
1510
- if (response.ok) {
1511
- showNotification('Data saved successfully');
1512
- }
1513
- }}
1514
- onWebhookError={(webhook, event, error) => {
1515
- // Hide loading indicator
1516
- setWebhookLoading(false);
1517
-
1518
- // Handle error gracefully
1519
- console.error('Webhook failed:', error);
1520
- showNotification('Saving to server failed, will retry later');
1521
-
1522
- // Store for offline sync
1523
- queueForLaterSync(event);
1524
- }}
1525
- />
521
+ import {
522
+ ExtendedForm,
523
+ WizardForm,
524
+ UiRule,
525
+ SchemaRule,
526
+ ValidationRule,
527
+ JsonLogicRule,
528
+ FormEvent,
529
+ WebhookConfig
530
+ } from 'extended-dynamic-forms';
1526
531
  ```
1527
532
 
1528
- #### Important Notes
1529
-
1530
- 1. **Event Filtering**: If you specify the `events` array, only those events will trigger webhooks
1531
- 2. **Debouncing**: Form-level events (submit, stepChange, validationError) respect debounceMs settings
1532
- 3. **Payload Structure**: All events now include standard fields (timestamp, formData, eventType, source)
1533
- 4. **No Breaking Changes**: All existing functionality remains unchanged
1534
-
1535
- ## Community & Support
1536
-
1537
- - 📚 [Documentation](https://extended-dynamic-forms.dev)
1538
- - 🐛 [Issue Tracker](https://github.com/user/extended-dynamic-forms/issues)
1539
- - 💬 [Discussions](https://github.com/user/extended-dynamic-forms/discussions)
1540
- - 📧 [Email Support](mailto:support@extended-dynamic-forms.dev)
1541
-
533
+ ## Contributing
1542
534
 
535
+ 1. Fork the repository
536
+ 2. Create your feature branch
537
+ 3. Add tests for new functionality
538
+ 4. Ensure all tests pass
539
+ 5. Submit a pull request
1543
540
 
1544
- ---
541
+ ## License
1545
542
 
1546
- <p align="center">
1547
- Built with ❤️ on top of <a href="https://github.com/rjsf-team/react-jsonschema-form">React JSON Schema Form</a>
1548
- </p>
543
+ MIT License - see LICENSE file for details.