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
package/README.md CHANGED
@@ -1,318 +1,668 @@
1
1
  # Extended Dynamic Forms
2
2
 
3
- A comprehensive extension of React JSON Schema Form (RJSF) v5 with shadcn/ui components, custom widgets, fields, layouts, and a powerful central event orchestration system with webhook capabilities.
4
-
5
- ## Features
6
-
7
- - 🎨 **shadcn/ui Integration**: Built on top of @rjsf/shadcn for beautiful, accessible components
8
- - ✨ **Custom Widgets**: Color picker, date picker, file upload, range slider, rating stars
9
- - 🏗️ **Custom Fields**: Address, phone number, currency input with formatting
10
- - 📐 **Layout Components**: Vertical, horizontal, and grid layouts
11
- - 🎯 **Central Event Orchestration**: Unified system capturing all form field events (focus, blur, change)
12
- - 🔗 **Webhook Integration**: Configure multiple webhook endpoints with debouncing and retry logic
13
- - 🔧 **Enhanced Form Events**: Before/after submit and validation hooks plus field-level events
14
- - 🚀 **Conditional Logic**: Show/hide fields, make fields required/optional based on complex conditions
15
- - 📦 **TypeScript Support**: Fully typed with comprehensive type definitions
16
- - ⚡ **Vite Powered**: Fast development and optimized builds
17
- - 🎯 **Tailwind CSS**: Utility-first styling with full customization
18
- - 🛡️ **Error Handling**: Robust error recovery and retry mechanisms
19
- - ⚡ **Performance Optimized**: Debouncing, queuing, and async processing
3
+ **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.
4
+
5
+ Built on top of the excellent RJSF v6 foundation, this library introduces the **Three Pillars v2 Architecture** for conditional logic, multi-step wizard orchestration, central event systems with webhook integration, and a comprehensive suite of 25+ Ant Design components.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/extended-dynamic-forms.svg)](https://www.npmjs.com/package/extended-dynamic-forms)
8
+ [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/user/extended-dynamic-forms/blob/main/LICENSE)
9
+ [![Built on RJSF](https://img.shields.io/badge/built%20on-RJSF%20v6-brightgreen)](https://github.com/rjsf-team/react-jsonschema-form)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
11
+ [![Standalone JS](https://img.shields.io/badge/Vanilla%20JS-Supported-orange.svg)](#standalone-javascript-support)
12
+
13
+ ## Why Extended Dynamic Forms?
14
+
15
+ 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:
16
+
17
+ ### 🚀 **Performance Revolution**
18
+ - **O(N) Conditional Logic**: Advanced Three Pillars v2 architecture vs traditional O(M×N) systems
19
+ - **Optimized Array Processing**: Per-item evaluation with dynamic array conditionals
20
+ - **Memory Efficient**: Immutable schema processing with intelligent caching
21
+
22
+ ### 🎯 **Enterprise-Grade Features**
23
+ - **Complex Conditional Logic**: Multi-field dependencies, nested conditions, and dynamic validation
24
+ - **Multi-Step Workflows**: Automatic wizard detection with step-aware conditional logic
25
+ - **Real-Time Integration**: Production-ready webhooks with retry logic and error isolation
26
+ - **Professional UI**: Comprehensive suite of enhanced Ant Design components with consistent styling
27
+
28
+ ### 🔄 **Developer Experience**
29
+ - **Dual Architecture Support**: Modern React hooks + vanilla JavaScript compatibility
30
+ - **Type-Safe Throughout**: Comprehensive TypeScript interfaces and validation
31
+ - **Rich Ecosystem**: Interactive playground with comprehensive real-world demos
32
+ - **Migration Ready**: Automated v1-to-v2 conversion utilities
33
+
34
+ This library transforms RJSF from a simple form generator into a complete enterprise form solution while preserving its declarative approach.
35
+
36
+ ## Core Features
37
+
38
+ ### 🚀 Three Pillars v2 Architecture (Recommended)
39
+ - **UI Logic Pillar**: Control form appearance with JSON Patch operations
40
+ - **Schema Logic Pillar**: Modify data structure when truly needed
41
+ - **Validation Logic Pillar**: Dynamic validation rules without schema changes
42
+ - **O(N) Performance**: Superior array handling vs v1's O(M×N)
43
+ - **React Hooks**: Modern, declarative API with `useConditionalUi`, `useConditionalSchema`, `useConditionalValidation`
44
+
45
+ ### 🎯 Declarative Conditional Logic
46
+ - Define complex form behavior without code
47
+ - Dynamic array support with per-item evaluation
48
+ - Compatible with `json-rules-engine` format
49
+ - Built-in migration utilities from v1 to v2
50
+
51
+ For example, you can integrate existing business logic:
52
+
53
+ ```tsx
54
+ import { engine } from './rules-engine'; // Your configured json-rules-engine instance
55
+
56
+ const uiRules: UiRule[] = [{
57
+ name: 'Apply business logic for premium users',
58
+ // The condition can be a promise-based async function
59
+ condition: async (formData) => {
60
+ const { events } = await engine.run(formData);
61
+ return events.some(event => event.type === 'show-premium-feature');
62
+ },
63
+ effect: [...]
64
+ }];
65
+ ```
66
+
67
+ ### 🧙‍♂️ Multi-Step Wizard Forms
68
+ - Automatic step detection from schema structure
69
+ - Step-aware conditional logic
70
+ - Built-in progress indicators and navigation
71
+ - Per-step validation
72
+
73
+ **Step-Aware Conditional Logic**
74
+
75
+ The `WizardForm` automatically scopes conditional logic to the current step. Use v2 `UiRule`s with field prefixes:
76
+
77
+ ```tsx
78
+ // Define steps with prefixed field names to avoid collisions
79
+ const schema = {
80
+ type: 'object',
81
+ properties: {
82
+ STEP_PERSONAL: {
83
+ type: 'object',
84
+ title: 'Personal Information',
85
+ properties: {
86
+ isUSCitizen: { type: 'boolean', title: 'Are you a US Citizen?' },
87
+ ssn: { type: 'string', title: 'Social Security Number' }
88
+ }
89
+ }
90
+ // ... other steps
91
+ }
92
+ };
93
+
94
+ // Use v2 UiRules to handle step-aware conditionals
95
+ const uiRules: UiRule[] = [{
96
+ name: 'Show SSN only for US Citizens in Personal step',
97
+ condition: (formData) => !formData.STEP_PERSONAL?.isUSCitizen,
98
+ effect: [
99
+ { op: 'add', path: '/STEP_PERSONAL/properties/ssn/ui:widget', value: 'hidden' }
100
+ ]
101
+ }];
102
+
103
+ // The WizardForm handles the step isolation automatically
104
+ ```
105
+
106
+ ### 🔗 Central Event Orchestration
107
+ - Unified event system for all field interactions
108
+ - Webhook integration with retry logic
109
+ - Real-time form analytics capabilities
110
+ - Debounced event processing
111
+
112
+ ### 🎨 Ant Design Components
113
+ - Complete widget suite built with Ant Design v5
114
+ - Enhanced standard widgets with event integration
115
+ - Custom widgets: Rating, Color Picker, Range Slider
116
+ - Professional field components: Address, Phone, Currency
117
+
118
+ ### ⚡ Form Lifecycle Hooks
119
+ - Intercept and modify form data at key stages
120
+ - `beforeSubmit`, `afterSubmit`, `beforeValidation`, `afterValidation`
121
+ - Ideal for data transformation, logging, or triggering side effects
122
+
123
+ ### 📦 Additional Features
124
+ - **TypeScript**: Full type safety and IntelliSense with comprehensive interface definitions
125
+ - **Performance**: Optimized re-renders and memoization with intelligent caching
126
+ - **Extensible**: Add custom widgets, fields, and actions with clean APIs
127
+ - **Well-Tested**: Extensive test suite covering all major features and edge cases
128
+ - **Developer Experience**: Interactive playground with dozens of real-world demos
129
+
130
+ ### 🌐 Standalone JavaScript Support
131
+
132
+ **Complete vanilla JavaScript compatibility** with a production-ready UMD bundle that includes React, Ant Design, and all dependencies:
133
+
134
+ ```html
135
+ <!DOCTYPE html>
136
+ <html>
137
+ <head>
138
+ <script src="https://unpkg.com/extended-dynamic-forms/dist/standalone.umd.js"></script>
139
+ <link rel="stylesheet" href="https://unpkg.com/extended-dynamic-forms/dist/style.css">
140
+ </head>
141
+ <body>
142
+ <div id="form-container"></div>
143
+
144
+ <script>
145
+ const { createForm, createWizard } = ExtendedDynamicForms;
146
+
147
+ // Create a complete form without React knowledge
148
+ const form = createForm({
149
+ schema: {
150
+ type: 'object',
151
+ properties: {
152
+ name: { type: 'string', title: 'Full Name' },
153
+ email: { type: 'string', format: 'email', title: 'Email' }
154
+ }
155
+ },
156
+ container: document.getElementById('form-container'),
157
+ onSubmit: (data) => console.log('Form submitted:', data)
158
+ });
159
+ </script>
160
+ </body>
161
+ </html>
162
+ ```
163
+
164
+ **Perfect for:**
165
+ - WordPress/Drupal integrations
166
+ - Legacy applications
167
+ - CMS form builders
168
+ - No-build environments
169
+ - PHP/ASP.NET applications
170
+
171
+ ## Credits & Acknowledgments
172
+
173
+ 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.
174
+
175
+ Special thanks to the RJSF team and contributors for creating such a flexible and well-architected foundation.
20
176
 
21
177
  ## Installation
22
178
 
179
+ ### React Projects
180
+
23
181
  ```bash
24
182
  npm install extended-dynamic-forms
25
183
  # or
26
184
  yarn add extended-dynamic-forms
185
+ # or
186
+ pnpm add extended-dynamic-forms
187
+ ```
188
+
189
+ ### Standalone JavaScript (No Build Required)
190
+
191
+ ```html
192
+ <!-- Production CDN -->
193
+ <script src="https://unpkg.com/extended-dynamic-forms@latest/dist/standalone.umd.js"></script>
194
+ <link rel="stylesheet" href="https://unpkg.com/extended-dynamic-forms@latest/dist/style.css">
195
+
196
+ <!-- Or download and host locally -->
197
+ <script src="./path/to/extended-dynamic-forms-standalone.js"></script>
27
198
  ```
28
199
 
29
200
  ### Peer Dependencies
30
201
 
31
- This package requires the following peer dependencies:
202
+ **Current Version**: `0.1.17` - Optimized for **RJSF v6** with Three Pillars v2 architecture.
32
203
 
33
204
  ```json
34
205
  {
35
206
  "react": "^18.0.0",
36
207
  "react-dom": "^18.0.0",
37
- "@rjsf/core": "^5.15.0",
38
- "@rjsf/utils": "^5.15.0",
39
- "@rjsf/validator-ajv8": "^5.15.0",
40
- "@rjsf/shadcn": "^0.1.0"
208
+ "antd": "^5.24.0"
41
209
  }
42
210
  ```
43
211
 
212
+ **RJSF Dependencies** (automatically handled):
213
+ - `@rjsf/core`: ^6.0.0+
214
+ - `@rjsf/utils`: ^6.0.0+
215
+ - `@rjsf/validator-ajv8`: ^6.0.0+
216
+ - `@rjsf/antd`: ^6.0.0+
217
+
218
+ > **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.
219
+
220
+ **Additional Dependencies**:
221
+ - `dayjs`: ^1.11.13 (Date handling)
222
+ - `json-rules-engine-simplified`: ^0.2.0 (v1 conditional logic)
223
+
224
+ > **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.
225
+
44
226
  ## Setup
45
227
 
46
228
  ### CSS Requirements
47
229
 
48
- This package uses Tailwind CSS and shadcn/ui components. Make sure to include the required CSS in your application:
230
+ This package uses Ant Design components. Import the CSS in your application:
49
231
 
50
232
  ```tsx
51
233
  // In your main entry file (e.g., App.tsx or index.tsx)
52
- import 'extended-dynamic-forms/dist/index.css';
234
+ import 'extended-dynamic-forms/dist/style.css'; // Or your specific CSS entry point
53
235
  ```
54
236
 
55
- If you're using Tailwind CSS in your project, ensure your `tailwind.config.js` includes the package in the content array:
237
+ ### Theming & Customization
56
238
 
57
- ```js
58
- module.exports = {
59
- content: [
60
- // ... your other content paths
61
- "./node_modules/extended-dynamic-forms/**/*.{js,ts,jsx,tsx}",
62
- ],
63
- // ... rest of your config
239
+ Since Extended Dynamic Forms uses Ant Design components, you can customize the appearance using Ant Design's powerful theming system:
240
+
241
+ ```tsx
242
+ import { ConfigProvider, theme } from 'antd';
243
+ import { ExtendedForm, WizardForm } from 'extended-dynamic-forms';
244
+
245
+ function App() {
246
+ return (
247
+ <ConfigProvider
248
+ theme={{
249
+ token: {
250
+ colorPrimary: '#00b96b',
251
+ borderRadius: 8,
252
+ fontSize: 16,
253
+ },
254
+ algorithm: theme.darkAlgorithm, // Optional: Use dark theme
255
+ }}
256
+ >
257
+ <WizardForm
258
+ schema={schema}
259
+ uiSchema={uiSchema}
260
+ conditionals={conditionals}
261
+ />
262
+ </ConfigProvider>
263
+ );
64
264
  }
65
265
  ```
66
266
 
67
- ## Quick Start
267
+ ## Three Pillars v2 Architecture (Recommended Approach)
268
+
269
+ > ⚠️ **IMPORTANT**: The v1 conditional system is deprecated. We strongly recommend using the Three Pillars v2 architecture for all new implementations.
68
270
 
69
- ### Basic Form
271
+ The Three Pillars v2 system provides superior performance, cleaner separation of concerns, and better maintainability. It consists of three independent pillars:
272
+
273
+ ### 1. UI Logic Pillar (`useConditionalUi`)
274
+
275
+ Controls form appearance using JSON Patch operations:
70
276
 
71
277
  ```tsx
72
- import React from 'react';
73
- import { ExtendedForm } from 'extended-dynamic-forms';
278
+ // Note: v2 conditionals require deep import for optimal tree-shaking
279
+ import { useConditionalUi, UiRule } from 'extended-dynamic-forms/conditionals/v2';
74
280
 
75
- const schema = {
76
- type: 'object',
77
- properties: {
78
- name: { type: 'string', title: 'Name' },
79
- email: { type: 'string', format: 'email', title: 'Email' },
80
- rating: { type: 'number', title: 'Rating' },
81
- favoriteColor: { type: 'string', title: 'Favorite Color' }
281
+ // Define UI rules with JSON Patch operations
282
+ const uiRules: UiRule[] = [
283
+ {
284
+ name: 'Show shipping address when required',
285
+ condition: (formData) => formData.requiresShipping === true,
286
+ effect: [{ op: 'remove', path: '/shippingAddress/ui:widget' }],
287
+ order: 1
82
288
  },
83
- required: ['name', 'email']
84
- };
289
+ {
290
+ name: 'Dynamic country fields',
291
+ condition: (formData) => formData.shippingAddress?.country === 'USA',
292
+ effect: [
293
+ { op: 'remove', path: '/shippingAddress/state/ui:widget' },
294
+ { op: 'add', path: '/shippingAddress/province/ui:widget', value: 'hidden' }
295
+ ],
296
+ order: 2
297
+ }
298
+ ];
85
299
 
86
- const uiSchema = {
87
- rating: {
88
- 'ui:widget': 'rating',
89
- 'ui:options': { max: 5 }
90
- },
91
- favoriteColor: {
92
- 'ui:widget': 'color'
300
+ const baseUiSchema = {
301
+ shippingAddress: {
302
+ 'ui:widget': 'hidden', // Initially hidden
303
+ state: { 'ui:widget': 'text' },
304
+ province: { 'ui:widget': 'hidden' } // Initially hidden
93
305
  }
94
306
  };
95
307
 
96
- function App() {
97
- const handleSubmit = ({ formData }) => {
98
- console.log('Form data:', formData);
99
- };
100
-
101
- const handleFieldChange = (event) => {
102
- console.log(`Field ${event.fieldId} changed to:`, event.fieldValue);
103
- };
104
-
308
+ // In your component
309
+ function MyForm() {
310
+ const [formData, setFormData] = useState({});
311
+
312
+ // IMPORTANT: Define rules outside render or memoize them!
313
+ const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
314
+
105
315
  return (
106
316
  <ExtendedForm
107
317
  schema={schema}
108
- uiSchema={uiSchema}
109
- onSubmit={handleSubmit}
110
- onFieldChange={handleFieldChange}
318
+ uiSchema={conditionalUiSchema}
319
+ formData={formData}
320
+ onChange={({ formData }) => setFormData(formData)}
111
321
  />
112
322
  );
113
323
  }
114
324
  ```
115
325
 
116
- ### With Webhook Integration
326
+ ### 2. Schema Logic Pillar (`useConditionalSchema`)
327
+
328
+ Modifies JSON Schema structure (use sparingly - prefer UI or Validation pillars):
117
329
 
118
330
  ```tsx
119
- import React from 'react';
120
- import { ExtendedForm, WebhookConfig } from 'extended-dynamic-forms';
331
+ import { useConditionalSchema, SchemaRule } from 'extended-dynamic-forms/conditionals/v2';
121
332
 
122
- const webhooks: WebhookConfig[] = [
333
+ const schemaRules: SchemaRule[] = [
123
334
  {
124
- url: 'https://your-api.com/webhooks/form-events',
125
- events: ['change'],
126
- debounceMs: 300,
127
- headers: {
128
- 'Authorization': 'Bearer your-token'
335
+ name: 'Add premium fields',
336
+ condition: (formData) => formData.accountType === 'premium',
337
+ effect: [
338
+ {
339
+ op: 'add',
340
+ path: '/properties/premiumFeatures',
341
+ value: {
342
+ type: 'object',
343
+ properties: {
344
+ priority: { type: 'string', enum: ['high', 'medium', 'low'] }
345
+ }
346
+ }
347
+ }
348
+ ]
349
+ }
350
+ ];
351
+
352
+ const conditionalSchema = useConditionalSchema(schemaRules, baseSchema, formData);
353
+ ```
354
+
355
+ ### 3. Validation Logic Pillar (`useConditionalValidation`)
356
+
357
+ Adds conditional validation without modifying schema:
358
+
359
+ ```tsx
360
+ import { useMemo } from 'react';
361
+ import { useConditionalValidation, ValidationRule, createCustomValidate } from 'extended-dynamic-forms/conditionals/v2';
362
+
363
+ const validationRules: ValidationRule[] = [
364
+ {
365
+ name: 'Require consent for minors',
366
+ condition: (formData) => formData.age < 18,
367
+ effect: {
368
+ type: 'validation',
369
+ validate: (errors, formData) => {
370
+ if (!formData.parentConsent) {
371
+ errors.parentConsent.addError('Parent consent is required for minors');
372
+ }
373
+ }
129
374
  }
130
375
  }
131
376
  ];
132
377
 
133
- function App() {
378
+ // In your component
379
+ function MyForm({ schema }) {
380
+ const [formData, setFormData] = useState({});
381
+
382
+ // 1. Get the conditional validation configuration
383
+ const conditionalValidationConfig = useConditionalValidation(validationRules, {}, formData);
384
+
385
+ // 2. Create the memoized validate function
386
+ const customValidate = useMemo(
387
+ () => createCustomValidate(conditionalValidationConfig),
388
+ [conditionalValidationConfig]
389
+ );
390
+
391
+ // 3. Use with ExtendedForm
134
392
  return (
135
393
  <ExtendedForm
136
394
  schema={schema}
137
- uiSchema={uiSchema}
138
- webhooks={webhooks}
139
- onSubmit={({ formData }) => {
140
- console.log('Form submitted:', formData);
141
- }}
142
- onFieldFocus={(event) => {
143
- console.log('Field focused:', event.fieldId);
144
- }}
395
+ formData={formData}
396
+ onChange={({ formData }) => setFormData(formData)}
397
+ customValidate={customValidate}
145
398
  />
146
399
  );
147
400
  }
148
401
  ```
149
402
 
150
- ## Custom Widgets
403
+ ### Dynamic Arrays with O(N) Performance
404
+
405
+ #### **The Performance Revolution: `createDynamicArrayItemsUiSchema`**
406
+
407
+ One of the most significant breakthroughs in v2 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.
408
+
409
+ **How It Works:**
410
+ - **Per-Item Evaluation**: Each array item's conditionals are evaluated independently during render
411
+ - **No Rule Explosion**: Unlike v1's wildcard expansion, no rules are multiplied by array size
412
+ - **React-Optimized**: Leverages React's rendering cycle for optimal performance
151
413
 
152
- ### Color Widget
153
414
  ```tsx
415
+ import { createDynamicArrayItemsUiSchema } from 'extended-dynamic-forms/conditionals/v2';
416
+
417
+ // Define per-item conditional logic - this function runs for each array item
418
+ const directorItemConditions = (director, index) => ({
419
+ shareholdingPercentage: {
420
+ 'ui:widget': director.hasShareholding ? 'percentage' : 'hidden'
421
+ },
422
+ tfn: {
423
+ 'ui:widget': director.isAustralianResident ? 'text' : 'hidden'
424
+ },
425
+ passport: {
426
+ 'ui:widget': !director.isAustralianResident ? 'text' : 'hidden'
427
+ },
428
+ // Add visual indicator for the chairman
429
+ 'ui:classNames': index === 0 ? 'chairman-director' : 'regular-director'
430
+ });
431
+
432
+ // Apply to your array field
154
433
  const uiSchema = {
155
- favoriteColor: {
156
- 'ui:widget': 'color'
434
+ directors: {
435
+ 'ui:title': 'Company Directors',
436
+ 'ui:description': 'Add all company directors and their details',
437
+ items: createDynamicArrayItemsUiSchema(directorItemConditions)
157
438
  }
158
439
  };
159
440
  ```
160
441
 
161
- ### Date Widget
162
- ```tsx
163
- const uiSchema = {
164
- birthDate: {
165
- 'ui:widget': 'date',
166
- 'ui:options': {
167
- inputType: 'datetime-local', // or 'date', 'time'
168
- minDate: '2000-01-01',
169
- maxDate: '2025-12-31'
170
- }
171
- }
172
- };
442
+ **Performance Comparison:**
443
+ ```typescript
444
+ // ❌ Traditional approach: O(M×N) - Rules × Array Items
445
+ // With 10 rules and 50 directors = 500 evaluations
446
+
447
+ // ✅ v2 approach: O(N) - Per-item evaluation
448
+ // With 50 directors = 50 evaluations (regardless of rule complexity)
173
449
  ```
174
450
 
175
- ### File Widget
451
+ **Advanced Patterns:**
176
452
  ```tsx
177
- const uiSchema = {
178
- documents: {
179
- 'ui:widget': 'file',
180
- 'ui:options': {
181
- accept: '.pdf,.doc,.docx',
182
- multiple: true
183
- }
453
+ // Complex business logic with multiple conditions
454
+ const productItemConditions = (product, index) => {
455
+ const baseConfig = {
456
+ price: { 'ui:widget': 'currency' },
457
+ quantity: { 'ui:widget': 'number' }
458
+ };
459
+
460
+ // Category-specific fields
461
+ if (product.category === 'software') {
462
+ baseConfig.licenseType = { 'ui:widget': 'select' };
463
+ baseConfig.maintenancePeriod = { 'ui:widget': 'hidden' };
464
+ }
465
+
466
+ // Subscription-specific logic
467
+ if (product.billingType === 'subscription') {
468
+ baseConfig.recurringPrice = { 'ui:widget': 'currency' };
469
+ baseConfig.billingCycle = { 'ui:widget': 'select' };
184
470
  }
471
+
472
+ return baseConfig;
185
473
  };
186
474
  ```
187
475
 
188
- ### Range Widget
476
+ ### Performance Best Practices
477
+
478
+ > ⚠️ **Critical**: Always define rules and base schemas outside render or memoize them!
479
+
189
480
  ```tsx
190
- const schema = {
191
- volume: {
192
- type: 'number',
193
- minimum: 0,
194
- maximum: 100,
195
- multipleOf: 5
196
- }
197
- };
481
+ // ❌ BAD - Creates new objects every render
482
+ function MyForm() {
483
+ const conditionalUiSchema = useConditionalUi(
484
+ [{ condition: () => true, effect: [...] }], // New array every render!
485
+ { field: { 'ui:widget': 'text' } }, // New object every render!
486
+ formData
487
+ );
488
+ }
198
489
 
199
- const uiSchema = {
200
- volume: {
201
- 'ui:widget': 'range'
202
- }
203
- };
490
+ // ✅ GOOD - Stable references
491
+ const rules = [{ condition: () => true, effect: [...] }];
492
+ const baseUiSchema = { field: { 'ui:widget': 'text' } };
493
+
494
+ function MyForm() {
495
+ const conditionalUiSchema = useConditionalUi(rules, baseUiSchema, formData);
496
+ }
204
497
  ```
205
498
 
206
- ### Rating Widget
499
+ ### Migration from v1 to v2
500
+
207
501
  ```tsx
208
- const uiSchema = {
209
- satisfaction: {
210
- 'ui:widget': 'rating',
211
- 'ui:options': {
212
- max: 10 // default is 5
213
- }
214
- }
215
- };
502
+ import {
503
+ migrateV1ToUiRules,
504
+ generateMigrationReport,
505
+ analyzeRules
506
+ } from 'extended-dynamic-forms/conditionals/v2';
507
+
508
+ // Analyze existing rules
509
+ const analysis = analyzeRules(v1Rules);
510
+
511
+ // Auto-migrate UI rules
512
+ const { rules: migratedRules, report } = migrateV1ToUiRules(v1Rules);
513
+
514
+ // Generate detailed migration report
515
+ const migrationReport = generateMigrationReport(v1Rules, {
516
+ includeExamples: true,
517
+ outputFormat: 'markdown'
518
+ });
216
519
  ```
217
520
 
218
- ## Custom Fields
521
+ ## Quick Start
522
+
523
+ ### Simple Wizard Form (Recommended)
524
+
525
+ The `WizardForm` component automatically detects multi-step forms and handles navigation. Use it with Three Pillars v2:
219
526
 
220
- ### Address Field
221
527
  ```tsx
528
+ import { useState } from 'react';
529
+ import { WizardForm } from 'extended-dynamic-forms';
530
+ import { useConditionalUi, UiRule } from 'extended-dynamic-forms/conditionals/v2';
531
+ import schema from './schema.json';
532
+ import baseUiSchema from './ui-schema.json';
533
+ import uiRules from './ui-rules'; // Your v2 UI rules
534
+ import webhooks from './webhooks.json';
535
+
536
+ function App() {
537
+ const [formData, setFormData] = useState({});
538
+ const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
539
+
540
+ return (
541
+ <WizardForm
542
+ schema={schema}
543
+ uiSchema={conditionalUiSchema}
544
+ formData={formData}
545
+ onChange={({ formData }) => setFormData(formData)}
546
+ webhooks={webhooks}
547
+ onSubmit={(data) => console.log('Submitted:', data.formData)}
548
+ />
549
+ );
550
+ }
551
+ ```
552
+
553
+ ### Basic Form with Three Pillars v2
554
+
555
+ ```tsx
556
+ import { ExtendedForm } from 'extended-dynamic-forms';
557
+ import { useConditionalUi, UiRule } from 'extended-dynamic-forms/conditionals/v2';
558
+
222
559
  const schema = {
223
- homeAddress: {
224
- type: 'object',
225
- properties: {
226
- street: { type: 'string' },
227
- city: { type: 'string' },
228
- state: { type: 'string' },
229
- zip: { type: 'string' },
230
- country: { type: 'string' }
231
- }
560
+ type: 'object',
561
+ properties: {
562
+ isStudent: { type: 'boolean', title: 'Are you a student?' },
563
+ studentId: { type: 'string', title: 'Student ID' },
564
+ school: { type: 'string', title: 'School Name' }
232
565
  }
233
566
  };
234
567
 
235
- const uiSchema = {
236
- homeAddress: {
237
- 'ui:field': 'address'
238
- }
568
+ const baseUiSchema = {
569
+ studentId: { 'ui:widget': 'text' },
570
+ school: { 'ui:widget': 'text' }
239
571
  };
572
+
573
+ // Define UI rules outside component
574
+ const uiRules: UiRule[] = [
575
+ {
576
+ name: 'Show student fields when student',
577
+ condition: (formData) => !formData.isStudent,
578
+ effect: [
579
+ { op: 'add', path: '/studentId/ui:widget', value: 'hidden' },
580
+ { op: 'add', path: '/school/ui:widget', value: 'hidden' }
581
+ ]
582
+ }
583
+ ];
584
+
585
+ function App() {
586
+ const [formData, setFormData] = useState({});
587
+ const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
588
+
589
+ return (
590
+ <ExtendedForm
591
+ schema={schema}
592
+ uiSchema={conditionalUiSchema}
593
+ formData={formData}
594
+ onChange={({ formData }) => setFormData(formData)}
595
+ />
596
+ );
597
+ }
240
598
  ```
241
599
 
242
- ### Phone Field
600
+ ## Custom Widgets
601
+
602
+ ### Available Widgets
603
+
604
+ The library includes enhanced versions of all standard RJSF widgets plus custom ones:
605
+
606
+ #### Custom Widgets
607
+
243
608
  ```tsx
609
+ // Color Picker
244
610
  const uiSchema = {
245
- phoneNumber: {
246
- 'ui:field': 'phone'
611
+ favoriteColor: {
612
+ 'ui:widget': 'color'
247
613
  }
248
614
  };
249
- ```
250
615
 
251
- ### Currency Field
252
- ```tsx
616
+ // Rating Widget
253
617
  const uiSchema = {
254
- price: {
255
- 'ui:field': 'currency',
618
+ satisfaction: {
619
+ 'ui:widget': 'rating',
256
620
  'ui:options': {
257
- currency: 'EUR',
258
- symbol: '€'
621
+ max: 10 // default is 5
259
622
  }
260
623
  }
261
624
  };
262
- ```
263
-
264
- ## Array Fields
265
-
266
- Extended Dynamic Forms provides custom-styled array field templates using shadcn/ui components. Arrays automatically get styled add/remove buttons, reordering controls, and proper visual hierarchy.
267
625
 
268
- ### Basic Array Example
269
- ```tsx
626
+ // Range Slider
270
627
  const schema = {
271
- type: 'object',
272
- properties: {
273
- directors: {
274
- type: 'array',
275
- title: 'Company Directors',
276
- items: {
277
- type: 'object',
278
- properties: {
279
- firstName: { type: 'string', title: 'First Name' },
280
- lastName: { type: 'string', title: 'Last Name' },
281
- email: { type: 'string', format: 'email', title: 'Email' }
282
- }
283
- }
284
- }
628
+ volume: {
629
+ type: 'number',
630
+ minimum: 0,
631
+ maximum: 100
632
+ }
633
+ };
634
+ const uiSchema = {
635
+ volume: {
636
+ 'ui:widget': 'range'
285
637
  }
286
638
  };
287
639
 
640
+ // File Upload
288
641
  const uiSchema = {
289
- directors: {
642
+ documents: {
643
+ 'ui:widget': 'file',
290
644
  'ui:options': {
291
- orderable: true, // Enable move up/down buttons
292
- addable: true, // Enable add button
293
- removable: true // Enable remove button
645
+ accept: '.pdf,.doc,.docx',
646
+ multiple: true
294
647
  }
295
648
  }
296
649
  };
297
650
  ```
298
651
 
299
- ### Array Features
300
- - 🎨 **Styled with shadcn/ui Card components**: Clean, modern appearance
301
- - ➕ **Add button**: Prominent "Add [Item]" button at the bottom
302
- - 🗑️ **Remove buttons**: Individual remove buttons for each item
303
- - 🔄 **Reordering**: Move items up/down with chevron buttons
304
- - 📱 **Responsive**: Mobile-friendly controls
652
+ #### Enhanced Standard Widgets
305
653
 
306
- Arrays work seamlessly with all other custom widgets and fields in the library, including within nested structures.
654
+ All standard RJSF widgets are enhanced with:
655
+ - **Event Integration**: Automatic integration with the central event system
656
+ - **Ant Design Styling**: Modern, consistent appearance
657
+ - **Error States**: Proper error indication and messaging
658
+ - **Accessibility**: Enhanced ARIA support
307
659
 
308
660
  ## Central Event Orchestration System
309
661
 
310
- The library features a comprehensive event orchestration system that captures all form field events and enables webhook integration.
311
-
312
662
  ### Field-Level Event Handling
313
663
 
314
664
  ```tsx
315
- import { ExtendedForm, FormFieldEvent } from 'extended-dynamic-forms';
665
+ import { ExtendedForm, type FormFieldEvent } from 'extended-dynamic-forms';
316
666
 
317
667
  <ExtendedForm
318
668
  schema={schema}
@@ -322,29 +672,15 @@ import { ExtendedForm, FormFieldEvent } from 'extended-dynamic-forms';
322
672
  // Field-level event handlers
323
673
  onFieldFocus={(event: FormFieldEvent) => {
324
674
  console.log(`Field ${event.fieldId} focused:`, event.fieldValue);
325
- // Track user interactions for analytics
326
675
  }}
327
676
 
328
677
  onFieldChange={(event: FormFieldEvent) => {
329
678
  console.log(`Field ${event.fieldId} changed:`, event.fieldValue);
330
679
  // Real-time validation or processing
331
- if (event.fieldId === 'root_email') {
332
- validateEmailRealTime(event.fieldValue);
333
- }
334
680
  }}
335
681
 
336
682
  onFieldBlur={(event: FormFieldEvent) => {
337
683
  console.log(`Field ${event.fieldId} blurred:`, event.fieldValue);
338
- // Format field values or trigger validation
339
- }}
340
-
341
- // Traditional form-level events (still supported)
342
- beforeSubmit={async (data) => {
343
- return { ...data, timestamp: Date.now() };
344
- }}
345
-
346
- afterSubmit={async (data) => {
347
- console.log('Form submitted:', data);
348
684
  }}
349
685
  />
350
686
  ```
@@ -354,7 +690,7 @@ import { ExtendedForm, FormFieldEvent } from 'extended-dynamic-forms';
354
690
  Configure multiple webhook endpoints to receive real-time form events:
355
691
 
356
692
  ```tsx
357
- import { ExtendedForm, WebhookConfig } from 'extended-dynamic-forms';
693
+ import { ExtendedForm, type WebhookConfig } from 'extended-dynamic-forms';
358
694
 
359
695
  const webhookConfigs: WebhookConfig[] = [
360
696
  {
@@ -366,17 +702,7 @@ const webhookConfigs: WebhookConfig[] = [
366
702
  timeout: 5000, // 5 second timeout
367
703
  headers: {
368
704
  'Authorization': 'Bearer your-api-token',
369
- 'X-Form-ID': 'contact-form',
370
- 'Content-Type': 'application/json'
371
- }
372
- },
373
- {
374
- url: 'https://analytics.yourapp.com/field-interactions',
375
- events: ['focus'], // Track focus events for analytics
376
- debounceMs: 0, // No debouncing for real-time analytics
377
- retries: 1,
378
- headers: {
379
- 'X-Analytics-Key': 'your-analytics-key'
705
+ 'X-Form-ID': 'contact-form'
380
706
  }
381
707
  }
382
708
  ];
@@ -385,408 +711,390 @@ const webhookConfigs: WebhookConfig[] = [
385
711
  schema={schema}
386
712
  uiSchema={uiSchema}
387
713
  webhooks={webhookConfigs}
388
-
389
- onFieldChange={(event) => {
390
- // Local processing alongside webhooks
391
- if (event.fieldId === 'root_email') {
392
- setEmailValid(validateEmail(event.fieldValue));
393
- }
394
- }}
395
714
  />
396
715
  ```
397
716
 
398
- ### Webhook Payload Structure
399
-
400
- Your webhook endpoints will receive payloads in this format:
401
-
402
- ```json
403
- {
404
- "event": {
405
- "eventType": "change",
406
- "fieldId": "root_email",
407
- "fieldValue": "user@example.com",
408
- "schema": {
409
- "type": "string",
410
- "format": "email",
411
- "title": "Email Address"
412
- },
413
- "formData": {
414
- "email": "user@example.com",
415
- "name": "John Doe"
416
- },
417
- "timestamp": 1678901234567,
418
- "fieldPath": ["email"]
419
- },
420
- "timestamp": 1678901234567,
421
- "source": "extended-dynamic-forms"
422
- }
423
- ```
717
+ ## V1 Conditional System (Deprecated)
424
718
 
425
- ### Advanced Features
719
+ > ⚠️ **DEPRECATED**: The v1 conditional system is deprecated and will be removed in a future version. Use the Three Pillars v2 system for all new implementations.
426
720
 
427
- - **Debouncing**: Prevent webhook spam on rapid input changes
428
- - **Retry Logic**: Automatic retry with exponential backoff for failed requests
429
- - **Error Isolation**: Webhook failures don't block form functionality
430
- - **Event Filtering**: Configure which events trigger each webhook
431
- - **Queue Management**: Asynchronous processing with proper ordering
432
- - **Custom Headers**: Add authentication, tracking, or custom metadata
721
+ The v1 system uses imperative engines with O(M×N) performance for arrays. While still functional, it has significant limitations compared to v2.
433
722
 
434
- ## Layouts
723
+ ### Basic V1 Usage (Not Recommended)
435
724
 
436
725
  ```tsx
437
- import { VerticalLayout, HorizontalLayout, GridLayout } from 'extended-dynamic-forms';
438
-
439
- // Vertical Layout
440
- <VerticalLayout spacing="medium">
441
- <input />
442
- <button />
443
- </VerticalLayout>
726
+ import { ExtendedForm } from 'extended-dynamic-forms';
444
727
 
445
- // Horizontal Layout
446
- <HorizontalLayout spacing="large" align="center">
447
- <label />
448
- <input />
449
- </HorizontalLayout>
728
+ const conditionals = {
729
+ rules: [
730
+ {
731
+ conditions: { isStudent: true },
732
+ event: { type: "require", params: { field: ["studentId", "school"] } }
733
+ },
734
+ {
735
+ conditions: { isStudent: false },
736
+ event: { type: "remove", params: { field: ["studentId", "school"] } }
737
+ }
738
+ ]
739
+ };
450
740
 
451
- // Grid Layout
452
- <GridLayout columns={3} gap="medium">
453
- <Card />
454
- <Card />
455
- <Card />
456
- </GridLayout>
741
+ <ExtendedForm
742
+ schema={schema}
743
+ uiSchema={uiSchema}
744
+ conditionals={conditionals}
745
+ />
457
746
  ```
458
747
 
459
- ## Use Cases
748
+ ### Why Migrate to v2?
460
749
 
461
- ### Real-time Form Analytics
462
- ```tsx
463
- const webhooks: WebhookConfig[] = [
464
- {
465
- url: 'https://analytics.yourapp.com/form-interactions',
466
- events: ['focus', 'blur', 'change'],
467
- debounceMs: 100,
468
- headers: { 'X-Analytics-Token': 'your-token' }
469
- }
470
- ];
750
+ - **Performance**: O(N) vs O(M×N) for arrays
751
+ - **Maintainability**: Clear separation of concerns
752
+ - **Type Safety**: Full TypeScript support
753
+ - **Predictability**: No complex rule interactions
754
+ - **Modern React**: Hooks-based architecture
471
755
 
472
- // Track user behavior, field completion rates, abandonment points
473
- ```
756
+ ## API Reference
474
757
 
475
- ### Auto-save & Recovery
476
- ```tsx
477
- <ExtendedForm
478
- schema={schema}
479
- onFieldChange={(event) => {
480
- // Auto-save to localStorage or server
481
- localStorage.setItem(`form_${event.fieldId}`, event.fieldValue);
482
- }}
483
- webhooks={[{
484
- url: 'https://api.yourapp.com/autosave',
485
- events: ['change'],
486
- debounceMs: 2000 // Save every 2 seconds
487
- }]}
488
- />
489
- ```
758
+ ### ExtendedFormProps
490
759
 
491
- ### Real-time Validation
492
- ```tsx
493
- <ExtendedForm
494
- schema={schema}
495
- onFieldBlur={async (event) => {
496
- if (event.fieldId === 'root_email') {
497
- const isValid = await validateEmailWithAPI(event.fieldValue);
498
- setEmailValidation(isValid);
499
- }
500
- }}
501
- webhooks={[{
502
- url: 'https://validation.yourapp.com/validate',
503
- events: ['blur'],
504
- headers: { 'Content-Type': 'application/json' }
505
- }]}
506
- />
760
+ ```typescript
761
+ interface ExtendedFormProps<T = any, S extends RJSFSchema = RJSFSchema, F = any> extends FormProps<T, S, F> {
762
+ // Standard RJSF props
763
+ schema: S;
764
+ uiSchema?: UiSchema<T, S, F>;
765
+ formData?: T;
766
+ onSubmit?: (data: IChangeEvent<T, S, F>, event?: React.FormEvent<HTMLFormElement>) => void;
767
+ onChange?: (data: IChangeEvent<T, S, F>) => void;
768
+
769
+ // Field-level event handlers
770
+ onFieldFocus?: (event: FormFieldEvent) => Promise<void> | void;
771
+ onFieldBlur?: (event: FormFieldEvent) => Promise<void> | void;
772
+ onFieldChange?: (event: FormFieldEvent) => Promise<void> | void;
773
+
774
+ // Webhook configuration
775
+ webhooks?: WebhookConfig[];
776
+
777
+ // Conditional logic (v1 - deprecated)
778
+ conditionals?: ConditionalConfig;
779
+
780
+ // Form lifecycle events
781
+ beforeSubmit?: (data: T) => Promise<T> | T;
782
+ afterSubmit?: (data: T) => Promise<void> | void;
783
+ beforeValidation?: (data: T) => Promise<T> | T;
784
+ afterValidation?: (data: T, errors: RJSFValidationError[]) => Promise<void> | void;
785
+ }
507
786
  ```
508
787
 
509
- ### Progressive Form Enhancement
510
- ```tsx
511
- <ExtendedForm
512
- schema={schema}
513
- onFieldChange={(event) => {
514
- // Show additional fields based on user input
515
- if (event.fieldId === 'root_country' && event.fieldValue === 'US') {
516
- setShowStateField(true);
517
- }
518
- }}
519
- />
520
- ```
788
+ ### Three Pillars v2 Hooks
521
789
 
522
- ## Conditional Forms
790
+ ```typescript
791
+ // UI Logic Pillar
792
+ function useConditionalUi(
793
+ rules: UiRule[],
794
+ baseUiSchema: UiSchema,
795
+ formData: any
796
+ ): UiSchema
797
+
798
+ // Schema Logic Pillar
799
+ function useConditionalSchema(
800
+ rules: SchemaRule[],
801
+ baseSchema: RJSFSchema,
802
+ formData: any
803
+ ): RJSFSchema
804
+
805
+ // Validation Logic Pillar
806
+ function useConditionalValidation(
807
+ rules: ValidationRule[],
808
+ baseConfig: ValidationConfig,
809
+ formData: any
810
+ ): ValidationConfig
811
+ ```
523
812
 
524
- Extended Dynamic Forms includes powerful conditional logic capabilities that allow you to:
525
- - Show/hide fields based on other field values
526
- - Make fields required/optional conditionally
527
- - Enable/disable fields based on complex conditions
528
- - Support multiple conditions with AND/OR logic
813
+ ## Real-World Use Cases
529
814
 
530
- ### Basic Conditional Example
815
+ ### 🏢 Enterprise Business Applications
531
816
 
817
+ **Australian Company Registration** (Featured Demo)
532
818
  ```tsx
533
- import { ConditionalForm, ConditionalRule } from 'extended-dynamic-forms';
534
-
535
- const schema = {
536
- type: 'object',
537
- properties: {
538
- accountType: {
539
- type: 'string',
540
- enum: ['personal', 'business'],
541
- title: 'Account Type'
542
- },
543
- firstName: { type: 'string', title: 'First Name' },
544
- lastName: { type: 'string', title: 'Last Name' },
545
- businessName: { type: 'string', title: 'Business Name' },
546
- taxId: { type: 'string', title: 'Tax ID' }
547
- }
819
+ // Complete 5-step wizard with dynamic conditionals
820
+ const companyOnboardingSchema = {
821
+ STEP_COMPANY: { /* Company details */ },
822
+ STEP_DIRECTORS: { /* Dynamic director array */ },
823
+ STEP_ADDRESS: { /* Address with postal logic */ },
824
+ STEP_FINANCIAL: { /* Banking with international support */ },
825
+ STEP_COMPLIANCE: { /* Regulatory requirements */ }
548
826
  };
549
827
 
550
- const conditionalRules: ConditionalRule[] = [
551
- {
552
- conditions: {
553
- accountType: { equals: 'personal' }
554
- },
555
- event: {
556
- type: 'show',
557
- params: { fields: ['firstName', 'lastName'] }
558
- }
559
- },
560
- {
561
- conditions: {
562
- accountType: { equals: 'business' }
563
- },
564
- event: {
565
- type: 'show',
566
- params: { fields: ['businessName', 'taxId'] }
828
+ // Per-director conditionals with O(N) performance
829
+ const uiSchema = {
830
+ STEP_DIRECTORS: {
831
+ directors: {
832
+ items: createDynamicArrayItemsUiSchema((director) => ({
833
+ tfn: { 'ui:widget': director.isAustralianResident ? 'text' : 'hidden' },
834
+ passport: { 'ui:widget': !director.isAustralianResident ? 'text' : 'hidden' }
835
+ }))
567
836
  }
568
837
  }
569
- ];
570
-
571
- <ConditionalForm
572
- schema={schema}
573
- conditionalRules={conditionalRules}
574
- onSubmit={handleSubmit}
575
- />
838
+ };
576
839
  ```
577
840
 
578
- ### Complex Conditions
841
+ ### 💼 Multi-Step Workflows
579
842
 
843
+ **Loan Applications**
844
+ - Conditional document requirements based on loan type
845
+ - Income verification with employment status logic
846
+ - Asset declaration with property type conditionals
847
+
848
+ **Employee Onboarding**
849
+ - Role-based form sections (technical vs. non-technical)
850
+ - Security clearance workflows
851
+ - Benefits enrollment with eligibility rules
852
+
853
+ **Grant Applications**
854
+ - Multi-stage submissions with validation gates
855
+ - Budget calculations with category-based rules
856
+ - Compliance checks based on funding type
857
+
858
+ ### 🔄 Dynamic Array Management
859
+
860
+ **Board of Directors Management**
580
861
  ```tsx
581
- const complexRules: ConditionalRule[] = [
582
- {
583
- // Show state field when country is US AND has address
584
- conditions: {
585
- all: [
586
- { country: { equals: 'US' } },
587
- { hasAddress: { equals: true } }
588
- ]
589
- },
590
- event: {
591
- type: 'show',
592
- params: { fields: ['state', 'zipCode'] }
593
- }
594
- },
595
- {
596
- // Show verification for high income personal OR business accounts
597
- conditions: {
598
- any: [
599
- {
600
- all: [
601
- { accountType: { equals: 'personal' } },
602
- { income: { greaterThan: 100000 } }
603
- ]
862
+ // Professional-grade array handling with O(N) performance
863
+ import { createDynamicArrayItemsUiSchema } from 'extended-dynamic-forms';
864
+
865
+ const uiSchema = {
866
+ STEP_DIRECTORS: {
867
+ directors: {
868
+ items: createDynamicArrayItemsUiSchema((director, index) => ({
869
+ shareholdingPercentage: {
870
+ 'ui:widget': director.hasShareholding ? 'percentage' : 'hidden'
871
+ },
872
+ tfn: {
873
+ 'ui:widget': director.isAustralianResident ? 'text' : 'hidden'
604
874
  },
605
- {
606
- accountType: { equals: 'business' }
875
+ passport: {
876
+ 'ui:widget': !director.isAustralianResident ? 'text' : 'hidden'
607
877
  }
608
- ]
609
- },
610
- event: {
611
- type: 'require',
612
- params: { fields: ['verificationDocument'] }
878
+ }))
613
879
  }
614
880
  }
615
- ];
881
+ };
616
882
  ```
617
883
 
618
- ### Available Conditions
884
+ **Product Configurations**
885
+ - Dynamic product options based on category
886
+ - Pricing calculations with quantity breaks
887
+ - Feature availability by subscription tier
619
888
 
620
- - `equals` / `notEquals` - Exact value matching
621
- - `greaterThan` / `lessThan` - Numeric comparisons
622
- - `greaterThanOrEqual` / `lessThanOrEqual` - Inclusive numeric comparisons
623
- - `contains` / `notContains` - String contains
624
- - `in` / `notIn` - Value in array
625
- - `empty` / `notEmpty` - Check if field has value
889
+ **Address Management**
890
+ - International vs. domestic address formats
891
+ - State/province selection based on country
892
+ - Postal code validation by region
626
893
 
627
- ### Available Events
894
+ ### 🌐 CMS & Integration Use Cases
628
895
 
629
- - `show` / `hide` - Control field visibility
630
- - `require` / `unrequire` - Make fields required/optional
631
- - `enable` / `disable` - Enable/disable fields
632
-
633
- ### Combining with Webhooks
634
-
635
- ```tsx
636
- <ConditionalForm
637
- schema={schema}
638
- conditionalRules={rules}
639
- webhooks={[
640
- {
641
- url: 'https://api.example.com/validate',
642
- events: ['change'],
643
- debounceMs: 500
896
+ **WordPress/Drupal Forms**
897
+ ```html
898
+ <!-- Standalone JavaScript integration -->
899
+ <script>
900
+ const { createWizard } = ExtendedDynamicForms;
901
+
902
+ createWizard({
903
+ schema: wpFormSchema,
904
+ container: '#wp-form-container',
905
+ onSubmit: (data) => {
906
+ // Submit to WordPress REST API
907
+ wp.apiRequest({ path: '/wp/v2/forms', method: 'POST', data });
644
908
  }
645
- ]}
646
- onFieldChange={(event) => {
647
- // Local handling alongside conditional logic
648
- console.log('Field changed:', event);
649
- }}
650
- />
909
+ });
910
+ </script>
651
911
  ```
652
912
 
653
- ## API Reference
913
+ **Legacy System Modernization**
914
+ - Drop-in replacement for static HTML forms
915
+ - Progressive enhancement of existing forms
916
+ - No-build deployment to production environments
654
917
 
655
- ### ExtendedFormProps
918
+ ## Architecture
656
919
 
657
- ```typescript
658
- interface ExtendedFormProps extends FormProps {
659
- // Standard RJSF props
660
- schema: RJSFSchema;
661
- uiSchema?: UiSchema;
662
- formData?: any;
663
- onSubmit?: (data: any, event: any) => void;
664
- onChange?: (data: any) => void;
665
-
666
- // Field-level event handlers
667
- onFieldFocus?: (event: FormFieldEvent) => Promise<void> | void;
668
- onFieldBlur?: (event: FormFieldEvent) => Promise<void> | void;
669
- onFieldChange?: (event: FormFieldEvent) => Promise<void> | void;
670
-
671
- // Webhook configuration
672
- webhooks?: WebhookConfig[];
673
-
674
- // Form lifecycle events
675
- beforeSubmit?: (data: any) => Promise<any> | any;
676
- afterSubmit?: (data: any) => Promise<void> | void;
677
- beforeValidation?: (data: any) => Promise<any> | any;
678
- afterValidation?: (data: any, errors: any) => Promise<void> | void;
679
- }
920
+ Extended Dynamic Forms uses a layered architecture that cleanly extends RJSF:
921
+
922
+ ```
923
+ ┌─────────────────────────────────────────────────┐
924
+ │ Three Pillars v2 (Conditional System) │
925
+ ├─────────────────────────────────────────────────┤
926
+ │ Application Layer (WizardForm) │
927
+ ├─────────────────────────────────────────────────┤
928
+ │ Event Layer (FormEventHub) │
929
+ ├─────────────────────────────────────────────────┤
930
+ │ Component Layer (Widgets/Fields/Templates) │
931
+ ├─────────────────────────────────────────────────┤
932
+ │ Base Layer (@rjsf/antd) │
933
+ └─────────────────────────────────────────────────┘
680
934
  ```
681
935
 
682
- ### FormFieldEvent
936
+ ## Feature Comparison
937
+
938
+ | Feature | Basic RJSF | Extended Dynamic Forms |
939
+ |---------|------------|----------------------|
940
+ | **Form Generation** | ✅ JSON Schema | ✅ Enhanced JSON Schema |
941
+ | **UI Components** | Basic HTML | ✅ Comprehensive Ant Design Suite |
942
+ | **Conditional Logic** | ❌ Manual | ✅ Three Pillars v2 (O(N)) |
943
+ | **Multi-Step Forms** | ❌ Manual | ✅ Automatic Wizard Detection |
944
+ | **Event System** | Basic onChange | ✅ Central Event Orchestration |
945
+ | **Webhook Integration** | ❌ None | ✅ Production-Ready with Retry |
946
+ | **Array Conditionals** | ❌ None | ✅ Per-Item O(N) Performance |
947
+ | **TypeScript** | Partial | ✅ Comprehensive Type Definitions |
948
+ | **Standalone JS** | ❌ React Only | ✅ Complete UMD Bundle |
949
+ | **Testing** | Basic | ✅ Extensive Test Coverage |
950
+ | **Performance** | Standard | ✅ Optimized with Caching |
951
+ | **Validation** | Basic | ✅ Dynamic + Custom Rules |
952
+ | **Developer Tools** | Limited | ✅ Interactive Playground |
683
953
 
684
- ```typescript
685
- interface FormFieldEvent {
686
- eventType: 'focus' | 'blur' | 'change';
687
- fieldId: string;
688
- fieldValue: any;
689
- schema?: any;
690
- formData?: any;
691
- timestamp: number;
692
- fieldPath?: string[];
693
- }
954
+ ## Development
955
+
956
+ ### 🚀 Quick Start
957
+
958
+ ```bash
959
+ # Clone and setup
960
+ git clone https://github.com/user/extended-dynamic-forms.git
961
+ cd extended-dynamic-forms
962
+ npm install
963
+
964
+ # Start development with playground
965
+ npm run dev # Launches interactive playground
966
+ npm run playground # Alternative playground command
967
+
968
+ # Development workflow
969
+ npm run test # Run complete test suite
970
+ npm run test:ui # Visual test runner
971
+ npm run lint # ESLint validation
972
+ npm run format # Prettier formatting
694
973
  ```
695
974
 
696
- ### WebhookConfig
975
+ ### 📦 Build Commands
697
976
 
698
- ```typescript
699
- interface WebhookConfig {
700
- url: string;
701
- method?: 'POST' | 'PUT' | 'PATCH';
702
- headers?: Record<string, string>;
703
- events?: ('focus' | 'blur' | 'change')[];
704
- debounceMs?: number;
705
- retries?: number;
706
- timeout?: number;
707
- }
977
+ ```bash
978
+ # Library builds
979
+ npm run build # TypeScript + Vite library build
980
+ npm run build:vanilla # Standalone UMD bundle
981
+ npm run build:all # Both library and standalone
982
+
983
+ # Production validation
984
+ npm run preview # Preview library build
985
+ npm run serve:examples # Serve vanilla JS examples
708
986
  ```
709
987
 
710
- ### ConditionalRule
988
+ ### 🧪 Testing
711
989
 
712
- ```typescript
713
- interface ConditionalRule {
714
- conditions: {
715
- [fieldPath: string]: FieldCondition;
716
- all?: Array<{ [fieldPath: string]: FieldCondition }>;
717
- any?: Array<{ [fieldPath: string]: FieldCondition }>;
718
- };
719
- event: {
720
- type: 'show' | 'hide' | 'require' | 'unrequire' | 'disable' | 'enable';
721
- params: {
722
- fields: string[];
723
- };
724
- };
725
- }
990
+ **Test Coverage**: Extensive test suite with focus on:
991
+ - **Conditional Logic**: Comprehensive coverage for v1 and v2 systems
992
+ - **Wizard Forms**: Step navigation and validation
993
+ - **Performance**: Array conditional optimization
994
+ - **Integration**: Component interaction testing
726
995
 
727
- interface FieldCondition {
728
- equals?: any;
729
- notEquals?: any;
730
- greaterThan?: number;
731
- lessThan?: number;
732
- greaterThanOrEqual?: number;
733
- lessThanOrEqual?: number;
734
- contains?: string;
735
- notContains?: string;
736
- in?: any[];
737
- notIn?: any[];
738
- empty?: boolean;
739
- notEmpty?: boolean;
740
- }
996
+ ```bash
997
+ npm run test # Run complete test suite
998
+ npm run test -- --grep "conditional" # Test conditional logic
999
+ npm run test -- --grep "wizard" # Test wizard forms
1000
+ npm run test -- --grep "array" # Test array handling
741
1001
  ```
742
1002
 
743
- ## Utility Functions
1003
+ ### 🏗️ Architecture
744
1004
 
745
- ```tsx
746
- import { formDataUtils, schemaUtils, validationUtils } from 'extended-dynamic-forms';
747
-
748
- // Form Data Utils
749
- const clonedData = formDataUtils.cloneFormData(formData);
750
- const mergedData = formDataUtils.mergeFormData(current, updates);
751
- const nestedValue = formDataUtils.getNestedValue(data, 'user.address.city');
752
- const updatedData = formDataUtils.setNestedValue(data, 'user.name', 'John');
753
- const cleanData = formDataUtils.removeEmptyValues(data);
754
-
755
- // Schema Utils
756
- const required = schemaUtils.getRequiredFields(schema);
757
- const isRequired = schemaUtils.isFieldRequired(schema, 'email');
758
- const fieldSchema = schemaUtils.getFieldSchema(schema, 'user.address');
759
- const merged = schemaUtils.mergeSchemas(schema1, schema2);
760
- const paths = schemaUtils.getAllFieldPaths(schema);
761
-
762
- // Validation Utils
763
- const isEmail = validationUtils.isValidEmail('test@example.com');
764
- const isPhone = validationUtils.isValidPhone('(555) 123-4567');
765
- const isUrl = validationUtils.isValidUrl('https://example.com');
766
- const isDate = validationUtils.isValidDate('2024-01-01');
767
- const inRange = validationUtils.isInRange(5, 1, 10);
768
- const message = validationUtils.getValidationMessage('required');
1005
+ **Build Configuration**:
1006
+ - **Library**: ES + UMD via Vite with TypeScript declarations
1007
+ - **Standalone**: Complete UMD bundle with React/antd included
1008
+ - **External Dependencies**: React, antd marked as externals in library build
1009
+ - **Type Generation**: `vite-plugin-dts` for .d.ts files
1010
+
1011
+ **File Structure**:
1012
+ ```
1013
+ src/
1014
+ ├── ExtendedForm.tsx # Main form wrapper
1015
+ ├── WizardForm.tsx # Multi-step orchestrator
1016
+ ├── conditionals/ # v1 + v2 conditional systems
1017
+ │ ├── v2/ # Three Pillars architecture
1018
+ │ └── DynamicArrayConditionalEngine.ts
1019
+ ├── events/ # Central event orchestration
1020
+ ├── widgets/ # Enhanced component suite
1021
+ ├── components/ # Field and template components
1022
+ └── utils/ # Form manipulation utilities
769
1023
  ```
770
1024
 
771
- ## Development
1025
+ ## Examples & Demos
772
1026
 
773
- ```bash
774
- # Install dependencies
775
- npm install
1027
+ ### 🎮 Interactive Playground
776
1028
 
777
- # Run development server
1029
+ The library includes a comprehensive **interactive playground** with extensive real-world demos demonstrating all features:
1030
+
1031
+ ```bash
1032
+ # Run the playground locally
778
1033
  npm run dev
1034
+ # or
1035
+ npm run playground
1036
+ ```
779
1037
 
780
- # Build library
781
- npm run build
1038
+ ### 📚 Demo Categories
1039
+
1040
+ #### **Three Pillars v2 Demonstrations**
1041
+ - **Global UI Rules**: Dynamic show/hide with JSON Patch operations
1042
+ - **Dynamic Array Items**: Per-item conditional logic with O(N) performance
1043
+ - **Conditional Validation**: Custom validation rules without schema changes
1044
+ - **Migration Examples**: Automated v1-to-v2 rule conversion
1045
+
1046
+ #### **🧙‍♂️ Wizard Form Showcases**
1047
+ - **Australian Company Onboarding**: 5-step enterprise form with:
1048
+ - Dynamic director arrays with per-item conditionals
1049
+ - Real-time fee calculations based on business rules
1050
+ - Complex validation (ABN/ACN numbers, postcodes)
1051
+ - Step-aware conditional logic
1052
+ - Professional business workflow
1053
+
1054
+ #### **🔗 Event System Demos**
1055
+ - **Real-time Form Analytics**: Webhook integration with retry logic
1056
+ - **Field-Level Event Handling**: Focus/blur/change event orchestration
1057
+ - **Webhook Configuration**: Multiple endpoints with custom headers
1058
+
1059
+ #### **🎨 Widget Showcase**
1060
+ - **Enhanced Standard Widgets**: All RJSF widgets with Ant Design styling
1061
+ - **Custom Widgets**: Color picker, rating, range slider, file upload
1062
+ - **Professional Fields**: Address, currency, phone number components
1063
+
1064
+ ### 📱 Vanilla JavaScript Examples
1065
+
1066
+ Complete standalone examples in `/examples/vanilla-js/`:
1067
+
1068
+ ```html
1069
+ <!-- Basic Form -->
1070
+ basic-form.html <!-- Simple contact form -->
1071
+ conditional-form.html <!-- Dynamic field visibility -->
1072
+ wizard-form.html <!-- Multi-step onboarding -->
1073
+ ```
782
1074
 
783
- # Run tests
784
- npm test
1075
+ ### 🔗 Live Demo Links
785
1076
 
786
- # Lint code
787
- npm run lint
788
- ```
1077
+ - **[Playground](https://extended-dynamic-forms-playground.vercel.app)** - Interactive demo environment
1078
+ - **[Australian Company Onboarding](https://extended-dynamic-forms-playground.vercel.app/wizard/australian-company)** - Full enterprise form showcase
1079
+ - **[Three Pillars v2 Demo](https://extended-dynamic-forms-playground.vercel.app/conditionals/three-pillars)** - Modern conditional logic patterns
1080
+
1081
+ ## Contributing
1082
+
1083
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
1084
+
1085
+ ## Community & Support
1086
+
1087
+ - 📚 [Documentation](https://extended-dynamic-forms.dev)
1088
+ - 🐛 [Issue Tracker](https://github.com/user/extended-dynamic-forms/issues)
1089
+ - 💬 [Discussions](https://github.com/user/extended-dynamic-forms/discussions)
1090
+ - 📧 [Email Support](mailto:support@extended-dynamic-forms.dev)
789
1091
 
790
1092
  ## License
791
1093
 
792
- MIT
1094
+ MIT © [Your Name/Organization]
1095
+
1096
+ ---
1097
+
1098
+ <p align="center">
1099
+ Built with ❤️ on top of <a href="https://github.com/rjsf-team/react-jsonschema-form">React JSON Schema Form</a>
1100
+ </p>