extended-dynamic-forms 0.1.17 โ 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.
- package/LICENSE +21 -0
- package/README.md +835 -393
- package/dist/extended-dynamic-forms.standalone.js +882 -0
- package/dist/style.css +1 -1
- package/examples/conditional-v2-example.tsx +64 -0
- package/examples/dynamic-array-items-example.tsx +211 -0
- package/examples/form-devtools-example.tsx +386 -0
- package/examples/global-ui-rules-example.tsx +356 -0
- package/examples/vanilla-js/README.md +212 -0
- package/examples/vanilla-js/basic-form.html +142 -0
- package/examples/vanilla-js/conditional-form.html +159 -0
- package/examples/vanilla-js/wizard-form.html +185 -0
- package/package.json +40 -47
- package/dist/ExtendedForm.d.ts +0 -4
- package/dist/WizardForm.d.ts +0 -26
- package/dist/components/arrays/ArrayFieldItemTemplate.d.ts +0 -3
- package/dist/components/arrays/ArrayFieldTemplate.d.ts +0 -3
- package/dist/components/arrays/index.d.ts +0 -2
- package/dist/components/fields/AddressField.d.ts +0 -3
- package/dist/components/fields/CurrencyField.d.ts +0 -4
- package/dist/components/fields/PhoneField.d.ts +0 -4
- package/dist/components/index.d.ts +0 -24
- package/dist/components/templates/FieldTemplate.d.ts +0 -4
- package/dist/components/templates/SubmitButton.d.ts +0 -4
- package/dist/components/templates/index.d.ts +0 -2
- package/dist/conditionals/ConditionalActions.d.ts +0 -13
- package/dist/conditionals/ConditionalContext.d.ts +0 -32
- package/dist/conditionals/DynamicArrayConditionalEngine.d.ts +0 -77
- package/dist/conditionals/SimpleConditionalEngine.d.ts +0 -41
- package/dist/conditionals/SmartJsonRulesTransformer.d.ts +0 -10
- package/dist/conditionals/index.d.ts +0 -7
- package/dist/events/FormEventContext.d.ts +0 -20
- package/dist/events/FormEventHub.d.ts +0 -27
- package/dist/events/FormEventManager.d.ts +0 -10
- package/dist/events/index.d.ts +0 -4
- package/dist/index.d.ts +0 -14
- package/dist/index.es.js +0 -44459
- package/dist/index.umd.js +0 -399
- package/dist/layouts/index.d.ts +0 -2
- package/dist/layouts/wizard/ProgressIndicator.d.ts +0 -10
- package/dist/layouts/wizard/StepNavigation.d.ts +0 -11
- package/dist/layouts/wizard/WizardLayout.d.ts +0 -31
- package/dist/layouts/wizard/WizardNavigation.d.ts +0 -16
- package/dist/layouts/wizard/WizardObjectFieldTemplate.d.ts +0 -4
- package/dist/layouts/wizard/WizardSectionTemplate.d.ts +0 -11
- package/dist/layouts/wizard/index.d.ts +0 -7
- package/dist/types/index.d.ts +0 -88
- package/dist/utils/formDataUtils.d.ts +0 -22
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/schemaUtils.d.ts +0 -24
- package/dist/utils/validationUtils.d.ts +0 -26
- package/dist/vanilla-wrapper.d.ts +0 -33
- package/dist/widgets/date/DateWidget.d.ts +0 -4
- package/dist/widgets/enhanced/EnhancedWidgets.d.ts +0 -36
- package/dist/widgets/file/FileWidget.d.ts +0 -4
- package/dist/widgets/index.d.ts +0 -33
- package/dist/widgets/input/ColorWidget.d.ts +0 -4
- package/dist/widgets/input/RangeWidget.d.ts +0 -4
- package/dist/widgets/input/RatingWidget.d.ts +0 -4
package/README.md
CHANGED
|
@@ -1,44 +1,228 @@
|
|
|
1
1
|
# Extended Dynamic Forms
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
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
|
+
[](https://www.npmjs.com/package/extended-dynamic-forms)
|
|
8
|
+
[](https://github.com/user/extended-dynamic-forms/blob/main/LICENSE)
|
|
9
|
+
[](https://github.com/rjsf-team/react-jsonschema-form)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
[](#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.
|
|
19
176
|
|
|
20
177
|
## Installation
|
|
21
178
|
|
|
179
|
+
### React Projects
|
|
180
|
+
|
|
22
181
|
```bash
|
|
23
182
|
npm install extended-dynamic-forms
|
|
24
183
|
# or
|
|
25
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>
|
|
26
198
|
```
|
|
27
199
|
|
|
28
200
|
### Peer Dependencies
|
|
29
201
|
|
|
30
|
-
|
|
202
|
+
**Current Version**: `0.1.17` - Optimized for **RJSF v6** with Three Pillars v2 architecture.
|
|
31
203
|
|
|
32
204
|
```json
|
|
33
205
|
{
|
|
34
206
|
"react": "^18.0.0",
|
|
35
207
|
"react-dom": "^18.0.0",
|
|
36
|
-
"
|
|
37
|
-
"@rjsf/utils": "^5.0.0 || ^6.0.0-beta.10",
|
|
38
|
-
"@rjsf/validator-ajv8": "^5.0.0 || ^6.0.0-beta.10"
|
|
208
|
+
"antd": "^5.24.0"
|
|
39
209
|
}
|
|
40
210
|
```
|
|
41
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
|
+
|
|
42
226
|
## Setup
|
|
43
227
|
|
|
44
228
|
### CSS Requirements
|
|
@@ -50,73 +234,364 @@ This package uses Ant Design components. Import the CSS in your application:
|
|
|
50
234
|
import 'extended-dynamic-forms/dist/style.css'; // Or your specific CSS entry point
|
|
51
235
|
```
|
|
52
236
|
|
|
237
|
+
### Theming & Customization
|
|
238
|
+
|
|
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
|
+
);
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
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.
|
|
270
|
+
|
|
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:
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
// Note: v2 conditionals require deep import for optimal tree-shaking
|
|
279
|
+
import { useConditionalUi, UiRule } from 'extended-dynamic-forms/conditionals/v2';
|
|
280
|
+
|
|
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
|
|
288
|
+
},
|
|
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
|
+
];
|
|
299
|
+
|
|
300
|
+
const baseUiSchema = {
|
|
301
|
+
shippingAddress: {
|
|
302
|
+
'ui:widget': 'hidden', // Initially hidden
|
|
303
|
+
state: { 'ui:widget': 'text' },
|
|
304
|
+
province: { 'ui:widget': 'hidden' } // Initially hidden
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
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
|
+
|
|
315
|
+
return (
|
|
316
|
+
<ExtendedForm
|
|
317
|
+
schema={schema}
|
|
318
|
+
uiSchema={conditionalUiSchema}
|
|
319
|
+
formData={formData}
|
|
320
|
+
onChange={({ formData }) => setFormData(formData)}
|
|
321
|
+
/>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### 2. Schema Logic Pillar (`useConditionalSchema`)
|
|
327
|
+
|
|
328
|
+
Modifies JSON Schema structure (use sparingly - prefer UI or Validation pillars):
|
|
329
|
+
|
|
330
|
+
```tsx
|
|
331
|
+
import { useConditionalSchema, SchemaRule } from 'extended-dynamic-forms/conditionals/v2';
|
|
332
|
+
|
|
333
|
+
const schemaRules: SchemaRule[] = [
|
|
334
|
+
{
|
|
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
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
];
|
|
377
|
+
|
|
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
|
|
392
|
+
return (
|
|
393
|
+
<ExtendedForm
|
|
394
|
+
schema={schema}
|
|
395
|
+
formData={formData}
|
|
396
|
+
onChange={({ formData }) => setFormData(formData)}
|
|
397
|
+
customValidate={customValidate}
|
|
398
|
+
/>
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
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
|
|
413
|
+
|
|
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
|
|
433
|
+
const uiSchema = {
|
|
434
|
+
directors: {
|
|
435
|
+
'ui:title': 'Company Directors',
|
|
436
|
+
'ui:description': 'Add all company directors and their details',
|
|
437
|
+
items: createDynamicArrayItemsUiSchema(directorItemConditions)
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
```
|
|
441
|
+
|
|
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)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**Advanced Patterns:**
|
|
452
|
+
```tsx
|
|
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' };
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return baseConfig;
|
|
473
|
+
};
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Performance Best Practices
|
|
477
|
+
|
|
478
|
+
> โ ๏ธ **Critical**: Always define rules and base schemas outside render or memoize them!
|
|
479
|
+
|
|
480
|
+
```tsx
|
|
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
|
+
}
|
|
489
|
+
|
|
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
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Migration from v1 to v2
|
|
500
|
+
|
|
501
|
+
```tsx
|
|
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
|
+
});
|
|
519
|
+
```
|
|
520
|
+
|
|
53
521
|
## Quick Start
|
|
54
522
|
|
|
55
523
|
### Simple Wizard Form (Recommended)
|
|
56
524
|
|
|
57
|
-
The `WizardForm` component automatically detects multi-step forms and handles navigation:
|
|
525
|
+
The `WizardForm` component automatically detects multi-step forms and handles navigation. Use it with Three Pillars v2:
|
|
58
526
|
|
|
59
527
|
```tsx
|
|
528
|
+
import { useState } from 'react';
|
|
60
529
|
import { WizardForm } from 'extended-dynamic-forms';
|
|
530
|
+
import { useConditionalUi, UiRule } from 'extended-dynamic-forms/conditionals/v2';
|
|
61
531
|
import schema from './schema.json';
|
|
62
|
-
import
|
|
63
|
-
import
|
|
532
|
+
import baseUiSchema from './ui-schema.json';
|
|
533
|
+
import uiRules from './ui-rules'; // Your v2 UI rules
|
|
64
534
|
import webhooks from './webhooks.json';
|
|
65
535
|
|
|
66
536
|
function App() {
|
|
537
|
+
const [formData, setFormData] = useState({});
|
|
538
|
+
const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
|
|
539
|
+
|
|
67
540
|
return (
|
|
68
541
|
<WizardForm
|
|
69
542
|
schema={schema}
|
|
70
|
-
uiSchema={
|
|
71
|
-
|
|
543
|
+
uiSchema={conditionalUiSchema}
|
|
544
|
+
formData={formData}
|
|
545
|
+
onChange={({ formData }) => setFormData(formData)}
|
|
72
546
|
webhooks={webhooks}
|
|
73
|
-
onSubmit={(data) => console.log('Submitted:', data)}
|
|
547
|
+
onSubmit={(data) => console.log('Submitted:', data.formData)}
|
|
74
548
|
/>
|
|
75
549
|
);
|
|
76
550
|
}
|
|
77
551
|
```
|
|
78
552
|
|
|
79
|
-
|
|
80
|
-
- โ
Auto-detects wizard structure (properties starting with `STEP_`)
|
|
81
|
-
- โ
Creates progress tracking and navigation
|
|
82
|
-
- โ
Handles step-aware conditional logic
|
|
83
|
-
- โ
Manages form state and validation
|
|
84
|
-
- โ
Integrates webhooks for real-time events
|
|
85
|
-
|
|
86
|
-
### Basic Form (Using ExtendedForm)
|
|
87
|
-
|
|
88
|
-
For more control, use the `ExtendedForm` component directly:
|
|
553
|
+
### Basic Form with Three Pillars v2
|
|
89
554
|
|
|
90
555
|
```tsx
|
|
91
556
|
import { ExtendedForm } from 'extended-dynamic-forms';
|
|
557
|
+
import { useConditionalUi, UiRule } from 'extended-dynamic-forms/conditionals/v2';
|
|
92
558
|
|
|
93
559
|
const schema = {
|
|
94
560
|
type: 'object',
|
|
95
561
|
properties: {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
},
|
|
101
|
-
required: ['name', 'email']
|
|
562
|
+
isStudent: { type: 'boolean', title: 'Are you a student?' },
|
|
563
|
+
studentId: { type: 'string', title: 'Student ID' },
|
|
564
|
+
school: { type: 'string', title: 'School Name' }
|
|
565
|
+
}
|
|
102
566
|
};
|
|
103
567
|
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
'ui:options': { max: 5 }
|
|
108
|
-
},
|
|
109
|
-
favoriteColor: {
|
|
110
|
-
'ui:widget': 'color'
|
|
111
|
-
}
|
|
568
|
+
const baseUiSchema = {
|
|
569
|
+
studentId: { 'ui:widget': 'text' },
|
|
570
|
+
school: { 'ui:widget': 'text' }
|
|
112
571
|
};
|
|
113
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
|
+
|
|
114
585
|
function App() {
|
|
586
|
+
const [formData, setFormData] = useState({});
|
|
587
|
+
const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
|
|
588
|
+
|
|
115
589
|
return (
|
|
116
590
|
<ExtendedForm
|
|
117
591
|
schema={schema}
|
|
118
|
-
uiSchema={
|
|
119
|
-
|
|
592
|
+
uiSchema={conditionalUiSchema}
|
|
593
|
+
formData={formData}
|
|
594
|
+
onChange={({ formData }) => setFormData(formData)}
|
|
120
595
|
/>
|
|
121
596
|
);
|
|
122
597
|
}
|
|
@@ -182,99 +657,12 @@ All standard RJSF widgets are enhanced with:
|
|
|
182
657
|
- **Error States**: Proper error indication and messaging
|
|
183
658
|
- **Accessibility**: Enhanced ARIA support
|
|
184
659
|
|
|
185
|
-
## Custom Fields
|
|
186
|
-
|
|
187
|
-
### Address Field
|
|
188
|
-
```tsx
|
|
189
|
-
const schema = {
|
|
190
|
-
homeAddress: {
|
|
191
|
-
type: 'object',
|
|
192
|
-
properties: {
|
|
193
|
-
street: { type: 'string' },
|
|
194
|
-
city: { type: 'string' },
|
|
195
|
-
state: { type: 'string' },
|
|
196
|
-
zip: { type: 'string' },
|
|
197
|
-
country: { type: 'string' }
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
const uiSchema = {
|
|
203
|
-
homeAddress: {
|
|
204
|
-
'ui:field': 'address'
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Phone Field
|
|
210
|
-
```tsx
|
|
211
|
-
const uiSchema = {
|
|
212
|
-
phoneNumber: {
|
|
213
|
-
'ui:field': 'phone'
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Currency Field
|
|
219
|
-
```tsx
|
|
220
|
-
const uiSchema = {
|
|
221
|
-
price: {
|
|
222
|
-
'ui:field': 'currency',
|
|
223
|
-
'ui:options': {
|
|
224
|
-
currency: 'EUR',
|
|
225
|
-
symbol: 'โฌ'
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
## Array Fields
|
|
232
|
-
|
|
233
|
-
The library provides Ant Design-styled array field templates with enhanced functionality:
|
|
234
|
-
|
|
235
|
-
```tsx
|
|
236
|
-
const schema = {
|
|
237
|
-
type: 'object',
|
|
238
|
-
properties: {
|
|
239
|
-
directors: {
|
|
240
|
-
type: 'array',
|
|
241
|
-
title: 'Company Directors',
|
|
242
|
-
items: {
|
|
243
|
-
type: 'object',
|
|
244
|
-
properties: {
|
|
245
|
-
firstName: { type: 'string', title: 'First Name' },
|
|
246
|
-
lastName: { type: 'string', title: 'Last Name' },
|
|
247
|
-
email: { type: 'string', format: 'email', title: 'Email' }
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
const uiSchema = {
|
|
255
|
-
directors: {
|
|
256
|
-
'ui:options': {
|
|
257
|
-
orderable: true, // Enable move up/down buttons
|
|
258
|
-
addable: true, // Enable add button
|
|
259
|
-
removable: true // Enable remove button
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
**Array Features:**
|
|
266
|
-
- ๐จ **Ant Design Cards**: Clean, modern appearance
|
|
267
|
-
- โ **Add Button**: Prominent "Add [Item]" button
|
|
268
|
-
- ๐๏ธ **Remove Buttons**: Individual remove buttons for each item
|
|
269
|
-
- ๐ **Reordering**: Move items up/down with controls
|
|
270
|
-
- ๐ฑ **Responsive**: Mobile-friendly design
|
|
271
|
-
|
|
272
660
|
## Central Event Orchestration System
|
|
273
661
|
|
|
274
662
|
### Field-Level Event Handling
|
|
275
663
|
|
|
276
664
|
```tsx
|
|
277
|
-
import { ExtendedForm, FormFieldEvent } from 'extended-dynamic-forms';
|
|
665
|
+
import { ExtendedForm, type FormFieldEvent } from 'extended-dynamic-forms';
|
|
278
666
|
|
|
279
667
|
<ExtendedForm
|
|
280
668
|
schema={schema}
|
|
@@ -302,7 +690,7 @@ import { ExtendedForm, FormFieldEvent } from 'extended-dynamic-forms';
|
|
|
302
690
|
Configure multiple webhook endpoints to receive real-time form events:
|
|
303
691
|
|
|
304
692
|
```tsx
|
|
305
|
-
import { ExtendedForm, WebhookConfig } from 'extended-dynamic-forms';
|
|
693
|
+
import { ExtendedForm, type WebhookConfig } from 'extended-dynamic-forms';
|
|
306
694
|
|
|
307
695
|
const webhookConfigs: WebhookConfig[] = [
|
|
308
696
|
{
|
|
@@ -326,190 +714,57 @@ const webhookConfigs: WebhookConfig[] = [
|
|
|
326
714
|
/>
|
|
327
715
|
```
|
|
328
716
|
|
|
329
|
-
|
|
717
|
+
## V1 Conditional System (Deprecated)
|
|
330
718
|
|
|
331
|
-
|
|
332
|
-
{
|
|
333
|
-
"event": {
|
|
334
|
-
"eventType": "change",
|
|
335
|
-
"fieldId": "root_email",
|
|
336
|
-
"fieldValue": "user@example.com",
|
|
337
|
-
"schema": {
|
|
338
|
-
"type": "string",
|
|
339
|
-
"format": "email",
|
|
340
|
-
"title": "Email Address"
|
|
341
|
-
},
|
|
342
|
-
"formData": {
|
|
343
|
-
"email": "user@example.com",
|
|
344
|
-
"name": "John Doe"
|
|
345
|
-
},
|
|
346
|
-
"timestamp": 1678901234567,
|
|
347
|
-
"fieldPath": ["email"]
|
|
348
|
-
},
|
|
349
|
-
"timestamp": 1678901234567,
|
|
350
|
-
"source": "extended-dynamic-forms"
|
|
351
|
-
}
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
## Advanced Conditional Logic System
|
|
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.
|
|
355
720
|
|
|
356
|
-
The
|
|
721
|
+
The v1 system uses imperative engines with O(MรN) performance for arrays. While still functional, it has significant limitations compared to v2.
|
|
357
722
|
|
|
358
|
-
### Basic
|
|
723
|
+
### Basic V1 Usage (Not Recommended)
|
|
359
724
|
|
|
360
725
|
```tsx
|
|
361
726
|
import { ExtendedForm } from 'extended-dynamic-forms';
|
|
362
|
-
import { smartTransformJsonRulesEngine } from 'extended-dynamic-forms';
|
|
363
727
|
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
isStudent: true
|
|
728
|
+
const conditionals = {
|
|
729
|
+
rules: [
|
|
730
|
+
{
|
|
731
|
+
conditions: { isStudent: true },
|
|
732
|
+
event: { type: "require", params: { field: ["studentId", "school"] } }
|
|
368
733
|
},
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
params: { field: ["studentId", "school"] }
|
|
734
|
+
{
|
|
735
|
+
conditions: { isStudent: false },
|
|
736
|
+
event: { type: "remove", params: { field: ["studentId", "school"] } }
|
|
372
737
|
}
|
|
373
|
-
|
|
374
|
-
{
|
|
375
|
-
conditions: {
|
|
376
|
-
isStudent: false
|
|
377
|
-
},
|
|
378
|
-
event: {
|
|
379
|
-
type: "hide",
|
|
380
|
-
params: { field: ["studentId", "school"] }
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
];
|
|
384
|
-
|
|
385
|
-
// Transform JSON Rules Engine format to internal format
|
|
386
|
-
const transformedRules = smartTransformJsonRulesEngine(conditions);
|
|
387
|
-
|
|
388
|
-
const conditionalConfig = {
|
|
389
|
-
rules: transformedRules,
|
|
390
|
-
onSchemaChange: ({ schema, uiSchema }) => {
|
|
391
|
-
console.log('Schema updated:', { schema, uiSchema });
|
|
392
|
-
}
|
|
738
|
+
]
|
|
393
739
|
};
|
|
394
740
|
|
|
395
|
-
<ExtendedForm
|
|
741
|
+
<ExtendedForm
|
|
396
742
|
schema={schema}
|
|
397
743
|
uiSchema={uiSchema}
|
|
398
|
-
conditionals={
|
|
399
|
-
onChange={handleChange}
|
|
744
|
+
conditionals={conditionals}
|
|
400
745
|
/>
|
|
401
746
|
```
|
|
402
747
|
|
|
403
|
-
###
|
|
748
|
+
### Why Migrate to v2?
|
|
404
749
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
// Schema with step structure
|
|
411
|
-
const wizardSchema = {
|
|
412
|
-
type: 'object',
|
|
413
|
-
properties: {
|
|
414
|
-
STEP_PERSONAL: {
|
|
415
|
-
type: 'object',
|
|
416
|
-
title: 'Personal Information',
|
|
417
|
-
properties: {
|
|
418
|
-
name: { type: 'string', title: 'Name' },
|
|
419
|
-
isStudent: { type: 'boolean', title: 'Are you a student?' },
|
|
420
|
-
studentId: { type: 'string', title: 'Student ID' }
|
|
421
|
-
}
|
|
422
|
-
},
|
|
423
|
-
STEP_CONTACT: {
|
|
424
|
-
type: 'object',
|
|
425
|
-
title: 'Contact Information',
|
|
426
|
-
properties: {
|
|
427
|
-
email: { type: 'string', format: 'email' },
|
|
428
|
-
phone: { type: 'string' }
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
// Conditions that reference step fields
|
|
435
|
-
const stepConditions = [
|
|
436
|
-
{
|
|
437
|
-
conditions: {
|
|
438
|
-
"STEP_PERSONAL.isStudent": false
|
|
439
|
-
},
|
|
440
|
-
event: {
|
|
441
|
-
type: "hide",
|
|
442
|
-
params: { field: "STEP_PERSONAL.studentId" }
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
];
|
|
446
|
-
|
|
447
|
-
<WizardForm
|
|
448
|
-
schema={wizardSchema}
|
|
449
|
-
uiSchema={uiSchema}
|
|
450
|
-
conditions={stepConditions}
|
|
451
|
-
onSubmit={handleSubmit}
|
|
452
|
-
/>
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
### Supported Conditional Actions
|
|
456
|
-
The conditional engine directly supports the following actions (defined in `ConditionalActions.ts`):
|
|
457
|
-
- `show` - Makes fields visible (adds them back to the schema if previously removed).
|
|
458
|
-
- `remove` - Removes fields from the schema and uiSchema (effectively hides them).
|
|
459
|
-
- `enable` / `disable` - Enable or disable fields.
|
|
460
|
-
- `require` / `optional` - Make fields required or optional.
|
|
461
|
-
- `uiAppend` - Appends to existing uiSchema properties (e.g., concatenates classNames, merges `ui:order`).
|
|
462
|
-
- `uiOverride` - Overrides specific uiSchema fields.
|
|
463
|
-
- `uiReplace` - Replaces entire uiSchema sections.
|
|
464
|
-
- Custom actions - Register your own conditional actions
|
|
465
|
-
|
|
466
|
-
**Note on `smartTransformJsonRulesEngine`:**
|
|
467
|
-
When providing conditions in the JSON Rules Engine format (e.g., to `WizardForm` or by calling `smartTransformJsonRulesEngine` directly):
|
|
468
|
-
- Input rules with `event.type: "show"` are typically converted into an internal `remove` action with *inverted* conditions.
|
|
469
|
-
- Input rules with `event.type: "hide"` are converted into an internal `remove` action.
|
|
470
|
-
- Input rules with `event.type: "required"` or `"optional"` are transformed into internal `require` or `optional` actions, respectively.
|
|
471
|
-
|
|
472
|
-
### JSON Rules Engine Support
|
|
473
|
-
|
|
474
|
-
The library includes transformation utilities for json-rules-engine format:
|
|
475
|
-
|
|
476
|
-
```tsx
|
|
477
|
-
import { smartTransformJsonRulesEngine } from 'extended-dynamic-forms';
|
|
478
|
-
|
|
479
|
-
const jsonRulesEngineFormat = [
|
|
480
|
-
{
|
|
481
|
-
conditions: {
|
|
482
|
-
all: [
|
|
483
|
-
{
|
|
484
|
-
fact: "age",
|
|
485
|
-
operator: "greaterThanInclusive",
|
|
486
|
-
value: 18
|
|
487
|
-
}
|
|
488
|
-
]
|
|
489
|
-
},
|
|
490
|
-
event: {
|
|
491
|
-
type: "show",
|
|
492
|
-
params: { field: "driverLicense" }
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
];
|
|
496
|
-
|
|
497
|
-
// Automatically transforms operators and structure
|
|
498
|
-
const internalRules = smartTransformJsonRulesEngine(jsonRulesEngineFormat);
|
|
499
|
-
```
|
|
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
|
|
500
755
|
|
|
501
756
|
## API Reference
|
|
502
757
|
|
|
503
758
|
### ExtendedFormProps
|
|
504
759
|
|
|
505
760
|
```typescript
|
|
506
|
-
interface ExtendedFormProps extends FormProps {
|
|
761
|
+
interface ExtendedFormProps<T = any, S extends RJSFSchema = RJSFSchema, F = any> extends FormProps<T, S, F> {
|
|
507
762
|
// Standard RJSF props
|
|
508
|
-
schema:
|
|
509
|
-
uiSchema?: UiSchema
|
|
510
|
-
formData?:
|
|
511
|
-
onSubmit?: (data:
|
|
512
|
-
onChange?: (data:
|
|
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;
|
|
513
768
|
|
|
514
769
|
// Field-level event handlers
|
|
515
770
|
onFieldFocus?: (event: FormFieldEvent) => Promise<void> | void;
|
|
@@ -519,140 +774,327 @@ interface ExtendedFormProps extends FormProps {
|
|
|
519
774
|
// Webhook configuration
|
|
520
775
|
webhooks?: WebhookConfig[];
|
|
521
776
|
|
|
522
|
-
// Conditional logic
|
|
777
|
+
// Conditional logic (v1 - deprecated)
|
|
523
778
|
conditionals?: ConditionalConfig;
|
|
524
779
|
|
|
525
780
|
// Form lifecycle events
|
|
526
|
-
beforeSubmit?: (data:
|
|
527
|
-
afterSubmit?: (data:
|
|
528
|
-
beforeValidation?: (data:
|
|
529
|
-
afterValidation?: (data:
|
|
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;
|
|
530
785
|
}
|
|
531
786
|
```
|
|
532
787
|
|
|
533
|
-
###
|
|
788
|
+
### Three Pillars v2 Hooks
|
|
534
789
|
|
|
535
790
|
```typescript
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
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
|
+
```
|
|
542
812
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
813
|
+
## Real-World Use Cases
|
|
814
|
+
|
|
815
|
+
### ๐ข Enterprise Business Applications
|
|
816
|
+
|
|
817
|
+
**Australian Company Registration** (Featured Demo)
|
|
818
|
+
```tsx
|
|
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 */ }
|
|
826
|
+
};
|
|
827
|
+
|
|
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
|
+
}))
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
};
|
|
560
839
|
```
|
|
561
840
|
|
|
562
|
-
###
|
|
841
|
+
### ๐ผ Multi-Step Workflows
|
|
563
842
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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**
|
|
861
|
+
```tsx
|
|
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'
|
|
874
|
+
},
|
|
875
|
+
passport: {
|
|
876
|
+
'ui:widget': !director.isAustralianResident ? 'text' : 'hidden'
|
|
877
|
+
}
|
|
878
|
+
}))
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
};
|
|
574
882
|
```
|
|
575
883
|
|
|
576
|
-
|
|
884
|
+
**Product Configurations**
|
|
885
|
+
- Dynamic product options based on category
|
|
886
|
+
- Pricing calculations with quantity breaks
|
|
887
|
+
- Feature availability by subscription tier
|
|
577
888
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
889
|
+
**Address Management**
|
|
890
|
+
- International vs. domestic address formats
|
|
891
|
+
- State/province selection based on country
|
|
892
|
+
- Postal code validation by region
|
|
893
|
+
|
|
894
|
+
### ๐ CMS & Integration Use Cases
|
|
895
|
+
|
|
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 });
|
|
908
|
+
}
|
|
909
|
+
});
|
|
910
|
+
</script>
|
|
911
|
+
```
|
|
912
|
+
|
|
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
|
|
917
|
+
|
|
918
|
+
## Architecture
|
|
919
|
+
|
|
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
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
588
934
|
```
|
|
589
935
|
|
|
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 |
|
|
953
|
+
|
|
590
954
|
## Development
|
|
591
955
|
|
|
956
|
+
### ๐ Quick Start
|
|
957
|
+
|
|
592
958
|
```bash
|
|
593
|
-
#
|
|
959
|
+
# Clone and setup
|
|
960
|
+
git clone https://github.com/user/extended-dynamic-forms.git
|
|
961
|
+
cd extended-dynamic-forms
|
|
594
962
|
npm install
|
|
595
963
|
|
|
596
|
-
#
|
|
597
|
-
npm run dev
|
|
964
|
+
# Start development with playground
|
|
965
|
+
npm run dev # Launches interactive playground
|
|
966
|
+
npm run playground # Alternative playground command
|
|
598
967
|
|
|
599
|
-
#
|
|
600
|
-
npm run
|
|
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
|
|
973
|
+
```
|
|
601
974
|
|
|
602
|
-
|
|
603
|
-
npm test
|
|
975
|
+
### ๐ฆ Build Commands
|
|
604
976
|
|
|
605
|
-
|
|
606
|
-
|
|
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
|
|
607
986
|
```
|
|
608
987
|
|
|
609
|
-
|
|
988
|
+
### ๐งช Testing
|
|
610
989
|
|
|
611
|
-
|
|
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
|
|
612
995
|
|
|
613
996
|
```bash
|
|
614
|
-
npm run
|
|
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
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
### ๐๏ธ Architecture
|
|
1004
|
+
|
|
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
|
|
615
1023
|
```
|
|
616
1024
|
|
|
617
|
-
|
|
1025
|
+
## Examples & Demos
|
|
618
1026
|
|
|
619
|
-
|
|
620
|
-
- **Conditional Logic Demo**: Dynamic field visibility and requirements
|
|
621
|
-
- **Event System Demo**: Real-time form analytics and webhooks
|
|
622
|
-
- **Custom Widget Showcase**: All available widgets and their options
|
|
1027
|
+
### ๐ฎ Interactive Playground
|
|
623
1028
|
|
|
624
|
-
|
|
1029
|
+
The library includes a comprehensive **interactive playground** with extensive real-world demos demonstrating all features:
|
|
625
1030
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
1031
|
+
```bash
|
|
1032
|
+
# Run the playground locally
|
|
1033
|
+
npm run dev
|
|
1034
|
+
# or
|
|
1035
|
+
npm run playground
|
|
1036
|
+
```
|
|
630
1037
|
|
|
631
|
-
###
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
-
|
|
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
|
+
```
|
|
635
1074
|
|
|
636
|
-
###
|
|
637
|
-
- Show/hide fields based on user input
|
|
638
|
-
- Change validation rules dynamically
|
|
639
|
-
- Progressive form enhancement
|
|
1075
|
+
### ๐ Live Demo Links
|
|
640
1076
|
|
|
641
|
-
|
|
642
|
-
-
|
|
643
|
-
-
|
|
644
|
-
- Application and registration forms
|
|
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
|
|
645
1080
|
|
|
646
|
-
##
|
|
1081
|
+
## Contributing
|
|
647
1082
|
|
|
648
|
-
|
|
1083
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
649
1084
|
|
|
650
|
-
|
|
651
|
-
2. **Central Event Orchestration**: All form interactions flow through a unified event system
|
|
652
|
-
3. **Conditional Logic Engine**: Dynamic schema transformations with comprehensive rule support
|
|
1085
|
+
## Community & Support
|
|
653
1086
|
|
|
654
|
-
|
|
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)
|
|
655
1091
|
|
|
656
1092
|
## License
|
|
657
1093
|
|
|
658
|
-
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>
|