extended-dynamic-forms 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +398 -1075
- package/dist/WizardForm.d.ts +4 -1
- package/dist/events/FormEventContext.d.ts +3 -0
- package/dist/events/FormEventHub.d.ts +19 -2
- package/dist/index.es.js +21051 -12923
- package/dist/index.umd.js +63 -36
- package/dist/style.css +1 -1
- package/dist/types/index.d.ts +6 -1
- package/dist/utils/fieldChangeDetector.d.ts +22 -0
- package/dist/widgets/base/index.d.ts +2 -0
- package/dist/widgets/base/types.d.ts +135 -0
- package/dist/widgets/base/utils.d.ts +63 -0
- package/dist/widgets/choice/ChoiceWidget.d.ts +30 -0
- package/dist/widgets/choice/ChoiceWidget.types.d.ts +496 -0
- package/dist/widgets/choice/examples/ChoiceWidget.example.d.ts +7 -0
- package/dist/widgets/choice/hooks/__tests__/useChoiceWidget.test.d.ts +1 -0
- package/dist/widgets/choice/hooks/__tests__/useDataSource.test.d.ts +1 -0
- package/dist/widgets/choice/hooks/examples/useChoiceWidget.example.d.ts +18 -0
- package/dist/widgets/choice/hooks/examples/useDataSourceExample.d.ts +22 -0
- package/dist/widgets/choice/hooks/index.d.ts +6 -0
- package/dist/widgets/choice/hooks/useChoiceWidget.d.ts +65 -0
- package/dist/widgets/choice/hooks/useDataSource.d.ts +69 -0
- package/dist/widgets/choice/index.d.ts +59 -0
- package/dist/widgets/choice/presenters/CheckboxPresenter.d.ts +70 -0
- package/dist/widgets/choice/presenters/DropdownPresenter.d.ts +37 -0
- package/dist/widgets/choice/presenters/PresenterStrategy.d.ts +230 -0
- package/dist/widgets/choice/presenters/RadioPresenter.d.ts +39 -0
- package/dist/widgets/choice/presenters/examples/RadioPresenterExample.d.ts +7 -0
- package/dist/widgets/choice/presenters/index.d.ts +20 -0
- package/dist/widgets/choice/providers/ApiDataSource.d.ts +241 -0
- package/dist/widgets/choice/providers/DataSourceProvider.d.ts +260 -0
- package/dist/widgets/choice/providers/StaticDataSource.d.ts +258 -0
- package/dist/widgets/choice/providers/WebSocketDataSource.d.ts +310 -0
- package/dist/widgets/choice/providers/index.d.ts +12 -0
- package/dist/widgets/choice/utils/index.d.ts +1 -0
- package/dist/widgets/choice/utils/responseMappers.d.ts +342 -0
- package/dist/widgets/date/DateTimeWidget.d.ts +26 -0
- package/dist/widgets/date/EnhancedDateWidget.d.ts +26 -0
- package/dist/widgets/date/index.d.ts +13 -0
- package/dist/widgets/file/FileUploadWidget.d.ts +40 -0
- package/dist/widgets/file/index.d.ts +2 -0
- package/dist/widgets/index.d.ts +33 -17
- package/dist/widgets/input/EmailWidget.d.ts +34 -0
- package/dist/widgets/input/NumberWidget.d.ts +39 -0
- package/dist/widgets/input/TelephoneWidget.d.ts +34 -0
- package/dist/widgets/input/URLWidget.d.ts +34 -0
- package/dist/widgets/input/index.d.ts +7 -0
- package/dist/widgets/text/PasswordWidget.d.ts +45 -0
- package/dist/widgets/text/TextWidget.d.ts +40 -0
- package/dist/widgets/text/TextareaWidget.d.ts +38 -0
- package/dist/widgets/text/index.d.ts +20 -0
- package/package.json +8 -8
- package/dist/vanilla-entry.d.ts +0 -204
- package/dist/widgets/enhanced/EnhancedWidgets.d.ts +0 -37
- package/examples/conditional-v2-example.tsx +0 -64
- package/examples/dynamic-array-items-example.tsx +0 -211
- package/examples/form-devtools-example.tsx +0 -384
- package/examples/global-ui-rules-example.tsx +0 -371
- package/examples/vanilla-js/README.md +0 -212
- package/examples/vanilla-js/basic-form.html +0 -142
- package/examples/vanilla-js/conditional-form.html +0 -159
- package/examples/vanilla-js/wizard-form.html +0 -185
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ExtendedForm } from '../src/ExtendedForm';
|
|
3
|
-
import { RJSFSchema, UiSchema } from '@rjsf/utils';
|
|
4
|
-
import {
|
|
5
|
-
createDynamicArrayItemsUiSchema,
|
|
6
|
-
arrayItemPatterns
|
|
7
|
-
} from '../src/conditionals/v2/utils/dynamicArrayItems';
|
|
8
|
-
|
|
9
|
-
const schema: RJSFSchema = {
|
|
10
|
-
type: 'object',
|
|
11
|
-
properties: {
|
|
12
|
-
directors: {
|
|
13
|
-
type: 'array',
|
|
14
|
-
title: 'Company Directors',
|
|
15
|
-
items: {
|
|
16
|
-
type: 'object',
|
|
17
|
-
required: ['name', 'directorType'],
|
|
18
|
-
properties: {
|
|
19
|
-
name: { type: 'string', title: 'Name' },
|
|
20
|
-
directorType: {
|
|
21
|
-
type: 'string',
|
|
22
|
-
title: 'Director Type',
|
|
23
|
-
enum: ['executive', 'non-executive'],
|
|
24
|
-
enumNames: ['Executive', 'Non-Executive']
|
|
25
|
-
},
|
|
26
|
-
executiveRole: {
|
|
27
|
-
type: 'string',
|
|
28
|
-
title: 'Executive Role',
|
|
29
|
-
enum: ['CEO', 'CFO', 'CTO', 'COO', 'Other'],
|
|
30
|
-
enumNames: ['CEO', 'CFO', 'CTO', 'COO', 'Other']
|
|
31
|
-
},
|
|
32
|
-
otherRoleDetails: {
|
|
33
|
-
type: 'string',
|
|
34
|
-
title: 'Other Role Details'
|
|
35
|
-
},
|
|
36
|
-
hasShareholding: { type: 'boolean', title: 'Has Shareholding?' },
|
|
37
|
-
shareholdingPercentage: {
|
|
38
|
-
type: 'number',
|
|
39
|
-
title: 'Shareholding %',
|
|
40
|
-
minimum: 0,
|
|
41
|
-
maximum: 100
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// Base UI schema for all array items
|
|
50
|
-
const baseItemUiSchema: UiSchema = {
|
|
51
|
-
'ui:order': ['name', 'directorType', 'executiveRole', 'otherRoleDetails', 'hasShareholding', 'shareholdingPercentage'],
|
|
52
|
-
name: {
|
|
53
|
-
'ui:widget': 'text',
|
|
54
|
-
'ui:placeholder': 'Enter director name'
|
|
55
|
-
},
|
|
56
|
-
directorType: {
|
|
57
|
-
'ui:widget': 'select'
|
|
58
|
-
},
|
|
59
|
-
executiveRole: {
|
|
60
|
-
'ui:widget': 'select'
|
|
61
|
-
},
|
|
62
|
-
otherRoleDetails: {
|
|
63
|
-
'ui:widget': 'text',
|
|
64
|
-
'ui:placeholder': 'Specify other role'
|
|
65
|
-
},
|
|
66
|
-
hasShareholding: {
|
|
67
|
-
'ui:widget': 'checkbox'
|
|
68
|
-
},
|
|
69
|
-
shareholdingPercentage: {
|
|
70
|
-
'ui:widget': 'updown'
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Create dynamic UI schema using the utility
|
|
75
|
-
const uiSchema: UiSchema = {
|
|
76
|
-
directors: {
|
|
77
|
-
items: createDynamicArrayItemsUiSchema(
|
|
78
|
-
baseItemUiSchema,
|
|
79
|
-
(itemData, index) => {
|
|
80
|
-
const conditionalUi: Partial<UiSchema> = {};
|
|
81
|
-
|
|
82
|
-
// Three-level conditional dependency chain
|
|
83
|
-
// Level 1: Director type determines if executive role is shown
|
|
84
|
-
if (itemData?.directorType !== 'executive') {
|
|
85
|
-
conditionalUi.executiveRole = { 'ui:widget': 'hidden' };
|
|
86
|
-
// Also hide dependent field since parent is hidden
|
|
87
|
-
conditionalUi.otherRoleDetails = { 'ui:widget': 'hidden' };
|
|
88
|
-
} else {
|
|
89
|
-
// Level 2: Executive role determines if other role details is shown
|
|
90
|
-
if (itemData?.executiveRole !== 'Other') {
|
|
91
|
-
conditionalUi.otherRoleDetails = { 'ui:widget': 'hidden' };
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Hide shareholding percentage if not a shareholder
|
|
96
|
-
if (!itemData?.hasShareholding) {
|
|
97
|
-
conditionalUi.shareholdingPercentage = { 'ui:widget': 'hidden' };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Add special styling for first director
|
|
101
|
-
if (index === 0) {
|
|
102
|
-
conditionalUi['ui:classNames'] = 'primary-director';
|
|
103
|
-
conditionalUi['ui:title'] = 'Primary Director';
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return conditionalUi;
|
|
107
|
-
}
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
export function DynamicArrayItemsExample() {
|
|
113
|
-
const [formData, setFormData] = React.useState({
|
|
114
|
-
directors: [
|
|
115
|
-
{
|
|
116
|
-
name: 'John Doe',
|
|
117
|
-
directorType: 'executive',
|
|
118
|
-
executiveRole: 'CEO',
|
|
119
|
-
hasShareholding: true,
|
|
120
|
-
shareholdingPercentage: 51
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
name: 'Jane Smith',
|
|
124
|
-
directorType: 'executive',
|
|
125
|
-
executiveRole: 'Other',
|
|
126
|
-
otherRoleDetails: 'Head of Innovation',
|
|
127
|
-
hasShareholding: true,
|
|
128
|
-
shareholdingPercentage: 30
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
name: 'Bob Johnson',
|
|
132
|
-
directorType: 'non-executive',
|
|
133
|
-
hasShareholding: false
|
|
134
|
-
}
|
|
135
|
-
]
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<div>
|
|
140
|
-
<h1>Dynamic Array Items Example</h1>
|
|
141
|
-
<p>
|
|
142
|
-
This example demonstrates O(n) performance for array conditionals using
|
|
143
|
-
the RJSF fork's dynamic uiSchema.items capability. It showcases:
|
|
144
|
-
</p>
|
|
145
|
-
<ul>
|
|
146
|
-
<li>Three-level conditional dependencies (Director Type → Executive Role → Other Role Details)</li>
|
|
147
|
-
<li>Enum-based conditions for more realistic form patterns</li>
|
|
148
|
-
<li>The common "Other" option pattern with additional text field</li>
|
|
149
|
-
<li>Multiple independent conditionals within each array item</li>
|
|
150
|
-
</ul>
|
|
151
|
-
|
|
152
|
-
<ExtendedForm
|
|
153
|
-
schema={schema}
|
|
154
|
-
uiSchema={uiSchema}
|
|
155
|
-
formData={formData}
|
|
156
|
-
onChange={({ formData }) => setFormData(formData)}
|
|
157
|
-
/>
|
|
158
|
-
|
|
159
|
-
<div style={{ marginTop: '20px' }}>
|
|
160
|
-
<h3>Performance Benefits:</h3>
|
|
161
|
-
<ul>
|
|
162
|
-
<li>Each array item's UI is calculated independently</li>
|
|
163
|
-
<li>No wildcard pattern expansion needed</li>
|
|
164
|
-
<li>O(n) complexity instead of O(n²)</li>
|
|
165
|
-
<li>Scales efficiently with large arrays</li>
|
|
166
|
-
</ul>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Alternative example using helper patterns
|
|
173
|
-
export function DynamicArrayPatternsExample() {
|
|
174
|
-
const uiSchemaWithPatterns: UiSchema = {
|
|
175
|
-
directors: {
|
|
176
|
-
items: createDynamicArrayItemsUiSchema(
|
|
177
|
-
baseItemUiSchema,
|
|
178
|
-
(itemData, index) => {
|
|
179
|
-
// Combine multiple pattern helpers for cleaner code
|
|
180
|
-
const hideShareholding = arrayItemPatterns.hideField(
|
|
181
|
-
'shareholdingPercentage',
|
|
182
|
-
(data) => !data?.hasShareholding
|
|
183
|
-
)(itemData, index);
|
|
184
|
-
|
|
185
|
-
const hideExecutiveRole = arrayItemPatterns.hideField(
|
|
186
|
-
'executiveRole',
|
|
187
|
-
(data) => data?.directorType !== 'executive'
|
|
188
|
-
)(itemData, index);
|
|
189
|
-
|
|
190
|
-
const hideOtherRoleDetails = arrayItemPatterns.hideField(
|
|
191
|
-
'otherRoleDetails',
|
|
192
|
-
(data) => data?.directorType !== 'executive' || data?.executiveRole !== 'Other'
|
|
193
|
-
)(itemData, index);
|
|
194
|
-
|
|
195
|
-
return {
|
|
196
|
-
...hideShareholding,
|
|
197
|
-
...hideExecutiveRole,
|
|
198
|
-
...hideOtherRoleDetails
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
)
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
return (
|
|
206
|
-
<ExtendedForm
|
|
207
|
-
schema={schema}
|
|
208
|
-
uiSchema={uiSchemaWithPatterns}
|
|
209
|
-
/>
|
|
210
|
-
);
|
|
211
|
-
}
|
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import Form from '@rjsf/antd';
|
|
3
|
-
import { IChangeEvent } from '@rjsf/core';
|
|
4
|
-
import { RJSFSchema, UiSchema } from '@rjsf/utils';
|
|
5
|
-
import validator from '@rjsf/validator-ajv8';
|
|
6
|
-
import {
|
|
7
|
-
Card,
|
|
8
|
-
Collapse,
|
|
9
|
-
Badge,
|
|
10
|
-
Tag,
|
|
11
|
-
Space,
|
|
12
|
-
Switch,
|
|
13
|
-
Typography,
|
|
14
|
-
Alert,
|
|
15
|
-
} from 'antd';
|
|
16
|
-
import {
|
|
17
|
-
Rule,
|
|
18
|
-
UiEffect,
|
|
19
|
-
SchemaEffect,
|
|
20
|
-
ValidationEffect,
|
|
21
|
-
JsonLogicRule,
|
|
22
|
-
} from '../src/conditionals/v2/types';
|
|
23
|
-
import {
|
|
24
|
-
useConditionalUi,
|
|
25
|
-
useConditionalSchema,
|
|
26
|
-
useConditionalValidation,
|
|
27
|
-
} from '../src/conditionals/v2';
|
|
28
|
-
import { useFormDevTools } from '../src/hooks/useFormDevTools';
|
|
29
|
-
|
|
30
|
-
const { Panel } = Collapse;
|
|
31
|
-
const { Text } = Typography;
|
|
32
|
-
|
|
33
|
-
// Base schema
|
|
34
|
-
const baseSchema: RJSFSchema = {
|
|
35
|
-
type: 'object',
|
|
36
|
-
title: 'Form with DevTools Example',
|
|
37
|
-
properties: {
|
|
38
|
-
country: {
|
|
39
|
-
type: 'string',
|
|
40
|
-
title: 'Country',
|
|
41
|
-
enum: ['USA', 'Canada', 'UK', 'Other'],
|
|
42
|
-
},
|
|
43
|
-
requiresShipping: {
|
|
44
|
-
type: 'boolean',
|
|
45
|
-
title: 'Requires Shipping?',
|
|
46
|
-
},
|
|
47
|
-
shippingAddress: {
|
|
48
|
-
type: 'object',
|
|
49
|
-
title: 'Shipping Address',
|
|
50
|
-
properties: {
|
|
51
|
-
street: { type: 'string', title: 'Street' },
|
|
52
|
-
city: { type: 'string', title: 'City' },
|
|
53
|
-
state: { type: 'string', title: 'State' },
|
|
54
|
-
zip: { type: 'string', title: 'ZIP Code' },
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
maritalStatus: {
|
|
58
|
-
type: 'string',
|
|
59
|
-
title: 'Marital Status',
|
|
60
|
-
enum: ['single', 'married', 'divorced', 'widowed'],
|
|
61
|
-
},
|
|
62
|
-
spouseName: {
|
|
63
|
-
type: 'string',
|
|
64
|
-
title: 'Spouse Name',
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
// Base UI schema
|
|
70
|
-
const baseUiSchema: UiSchema = {
|
|
71
|
-
'ui:order': [
|
|
72
|
-
'country',
|
|
73
|
-
'requiresShipping',
|
|
74
|
-
'shippingAddress',
|
|
75
|
-
'maritalStatus',
|
|
76
|
-
'spouseName',
|
|
77
|
-
],
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// UI Rules
|
|
81
|
-
const uiRules: Rule<UiEffect>[] = [
|
|
82
|
-
{
|
|
83
|
-
name: 'Hide shipping address when not required',
|
|
84
|
-
condition: { "!": { "var": "requiresShipping" } } as JsonLogicRule,
|
|
85
|
-
effect: [
|
|
86
|
-
{ op: 'add', path: '/shippingAddress/ui:widget', value: 'hidden' },
|
|
87
|
-
],
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: 'Show state dropdown for US/Canada',
|
|
91
|
-
condition: { "or": [{ "==": [{ "var": "country" }, "USA"] }, { "==": [{ "var": "country" }, "Canada"] }] } as JsonLogicRule,
|
|
92
|
-
effect: [
|
|
93
|
-
{
|
|
94
|
-
op: 'add',
|
|
95
|
-
path: '/shippingAddress/state/ui:widget',
|
|
96
|
-
value: 'select',
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
},
|
|
100
|
-
];
|
|
101
|
-
|
|
102
|
-
// Schema Rules
|
|
103
|
-
const schemaRules: Rule<SchemaEffect>[] = [
|
|
104
|
-
{
|
|
105
|
-
name: 'Add spouse fields when married',
|
|
106
|
-
condition: { "===": [{ "var": "maritalStatus" }, "married"] } as JsonLogicRule,
|
|
107
|
-
effect: [{ op: 'add', path: '/required/-', value: 'spouseName' }],
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
name: 'Remove spouse field when not married',
|
|
111
|
-
condition: { "!==": [{ "var": "maritalStatus" }, "married"] } as JsonLogicRule,
|
|
112
|
-
effect: [{ op: 'remove', path: '/properties/spouseName' }],
|
|
113
|
-
},
|
|
114
|
-
];
|
|
115
|
-
|
|
116
|
-
// Validation Rules
|
|
117
|
-
const validationRules: Rule<ValidationEffect>[] = [
|
|
118
|
-
{
|
|
119
|
-
name: 'US ZIP code format validation',
|
|
120
|
-
effect: {
|
|
121
|
-
name: 'US ZIP code format',
|
|
122
|
-
isActive: { "and": [{ "==": [{ "var": "country" }, "USA"] }, { "var": "requiresShipping" }] } as JsonLogicRule,
|
|
123
|
-
validate: (errors, formData) => {
|
|
124
|
-
if (
|
|
125
|
-
formData.shippingAddress?.zip &&
|
|
126
|
-
!/^\d{5}(-\d{4})?$/.test(formData.shippingAddress.zip)
|
|
127
|
-
) {
|
|
128
|
-
if (!errors.shippingAddress) errors.shippingAddress = {};
|
|
129
|
-
if (!errors.shippingAddress.zip) errors.shippingAddress.zip = {};
|
|
130
|
-
errors.shippingAddress.zip.__errors = [
|
|
131
|
-
'ZIP code must be XXXXX or XXXXX-XXXX format',
|
|
132
|
-
];
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
name: 'Canadian postal code validation',
|
|
139
|
-
effect: {
|
|
140
|
-
name: 'Canadian postal code',
|
|
141
|
-
isActive: { "and": [{ "==": [{ "var": "country" }, "Canada"] }, { "var": "requiresShipping" }] } as JsonLogicRule,
|
|
142
|
-
validate: (errors, formData) => {
|
|
143
|
-
if (
|
|
144
|
-
formData.shippingAddress?.zip &&
|
|
145
|
-
!/^[A-Z]\d[A-Z] \d[A-Z]\d$/.test(formData.shippingAddress.zip)
|
|
146
|
-
) {
|
|
147
|
-
if (!errors.shippingAddress) errors.shippingAddress = {};
|
|
148
|
-
if (!errors.shippingAddress.zip) errors.shippingAddress.zip = {};
|
|
149
|
-
errors.shippingAddress.zip.__errors = [
|
|
150
|
-
'Postal code must be A1A 1A1 format',
|
|
151
|
-
];
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
];
|
|
157
|
-
|
|
158
|
-
// DevTools Panel Component
|
|
159
|
-
const DevToolsPanel: React.FC<{
|
|
160
|
-
devTools: ReturnType<typeof useFormDevTools>;
|
|
161
|
-
}> = ({ devTools }) => {
|
|
162
|
-
const { evaluations, activeRules, hasErrors, errors, summary } = devTools;
|
|
163
|
-
|
|
164
|
-
return (
|
|
165
|
-
<Card title='Form DevTools' style={{ marginTop: 24 }}>
|
|
166
|
-
<Space direction='vertical' style={{ width: '100%' }}>
|
|
167
|
-
{/* Summary */}
|
|
168
|
-
<Alert
|
|
169
|
-
message={
|
|
170
|
-
<Space>
|
|
171
|
-
<Text>Total Rules: {summary.totalRules}</Text>
|
|
172
|
-
<Badge
|
|
173
|
-
count={summary.activeCount}
|
|
174
|
-
style={{ backgroundColor: '#52c41a' }}
|
|
175
|
-
/>
|
|
176
|
-
<Text>Active</Text>
|
|
177
|
-
{hasErrors && (
|
|
178
|
-
<>
|
|
179
|
-
<Badge count={summary.errorCount} />
|
|
180
|
-
<Text>Errors</Text>
|
|
181
|
-
</>
|
|
182
|
-
)}
|
|
183
|
-
</Space>
|
|
184
|
-
}
|
|
185
|
-
type={hasErrors ? 'warning' : 'info'}
|
|
186
|
-
/>
|
|
187
|
-
|
|
188
|
-
{/* Errors */}
|
|
189
|
-
{hasErrors && (
|
|
190
|
-
<Alert
|
|
191
|
-
message='Rule Evaluation Errors'
|
|
192
|
-
description={
|
|
193
|
-
<ul>
|
|
194
|
-
{errors.map((error, idx) => (
|
|
195
|
-
<li key={idx}>
|
|
196
|
-
<Text type='danger'>
|
|
197
|
-
{error.pillar} Rule "{error.ruleName}": {error.error}
|
|
198
|
-
</Text>
|
|
199
|
-
</li>
|
|
200
|
-
))}
|
|
201
|
-
</ul>
|
|
202
|
-
}
|
|
203
|
-
type='error'
|
|
204
|
-
/>
|
|
205
|
-
)}
|
|
206
|
-
|
|
207
|
-
{/* Rule Details */}
|
|
208
|
-
<Collapse defaultActiveKey={['ui']}>
|
|
209
|
-
<Panel
|
|
210
|
-
header={`UI Rules (${activeRules.ui.length} active)`}
|
|
211
|
-
key='ui'
|
|
212
|
-
extra={
|
|
213
|
-
<Badge
|
|
214
|
-
count={activeRules.ui.length}
|
|
215
|
-
style={{ backgroundColor: '#52c41a' }}
|
|
216
|
-
/>
|
|
217
|
-
}
|
|
218
|
-
>
|
|
219
|
-
{evaluations
|
|
220
|
-
.filter(e => e.pillar === 'UI')
|
|
221
|
-
.map((evaluation, idx) => (
|
|
222
|
-
<div key={idx} style={{ marginBottom: 8 }}>
|
|
223
|
-
<Tag color={evaluation.active ? 'green' : 'default'}>
|
|
224
|
-
{evaluation.active ? '✓' : '○'}
|
|
225
|
-
</Tag>
|
|
226
|
-
<Text>{evaluation.ruleName}</Text>
|
|
227
|
-
{evaluation.error && (
|
|
228
|
-
<Text type='danger'> (Error: {evaluation.error})</Text>
|
|
229
|
-
)}
|
|
230
|
-
</div>
|
|
231
|
-
))}
|
|
232
|
-
</Panel>
|
|
233
|
-
|
|
234
|
-
<Panel
|
|
235
|
-
header={`Schema Rules (${activeRules.schema.length} active)`}
|
|
236
|
-
key='schema'
|
|
237
|
-
extra={
|
|
238
|
-
<Badge
|
|
239
|
-
count={activeRules.schema.length}
|
|
240
|
-
style={{ backgroundColor: '#52c41a' }}
|
|
241
|
-
/>
|
|
242
|
-
}
|
|
243
|
-
>
|
|
244
|
-
{evaluations
|
|
245
|
-
.filter(e => e.pillar === 'Schema')
|
|
246
|
-
.map((evaluation, idx) => (
|
|
247
|
-
<div key={idx} style={{ marginBottom: 8 }}>
|
|
248
|
-
<Tag color={evaluation.active ? 'green' : 'default'}>
|
|
249
|
-
{evaluation.active ? '✓' : '○'}
|
|
250
|
-
</Tag>
|
|
251
|
-
<Text>{evaluation.ruleName}</Text>
|
|
252
|
-
{evaluation.error && (
|
|
253
|
-
<Text type='danger'> (Error: {evaluation.error})</Text>
|
|
254
|
-
)}
|
|
255
|
-
</div>
|
|
256
|
-
))}
|
|
257
|
-
</Panel>
|
|
258
|
-
|
|
259
|
-
<Panel
|
|
260
|
-
header={`Validation Rules (${activeRules.validation.length} active)`}
|
|
261
|
-
key='validation'
|
|
262
|
-
extra={
|
|
263
|
-
<Badge
|
|
264
|
-
count={activeRules.validation.length}
|
|
265
|
-
style={{ backgroundColor: '#52c41a' }}
|
|
266
|
-
/>
|
|
267
|
-
}
|
|
268
|
-
>
|
|
269
|
-
{evaluations
|
|
270
|
-
.filter(e => e.pillar === 'Validation')
|
|
271
|
-
.map((evaluation, idx) => (
|
|
272
|
-
<div key={idx} style={{ marginBottom: 8 }}>
|
|
273
|
-
<Tag color={evaluation.active ? 'green' : 'default'}>
|
|
274
|
-
{evaluation.active ? '✓' : '○'}
|
|
275
|
-
</Tag>
|
|
276
|
-
<Text>{evaluation.ruleName}</Text>
|
|
277
|
-
{evaluation.error && (
|
|
278
|
-
<Text type='danger'> (Error: {evaluation.error})</Text>
|
|
279
|
-
)}
|
|
280
|
-
</div>
|
|
281
|
-
))}
|
|
282
|
-
</Panel>
|
|
283
|
-
</Collapse>
|
|
284
|
-
</Space>
|
|
285
|
-
</Card>
|
|
286
|
-
);
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
export default function FormDevToolsExample() {
|
|
290
|
-
const [formData, setFormData] = useState({});
|
|
291
|
-
const [devToolsEnabled, setDevToolsEnabled] = useState(true);
|
|
292
|
-
const [logToConsole, setLogToConsole] = useState(false);
|
|
293
|
-
const [captureHistory, setCaptureHistory] = useState(false);
|
|
294
|
-
|
|
295
|
-
// Apply conditional logic
|
|
296
|
-
const conditionalUiSchema = useConditionalUi(uiRules, baseUiSchema, formData);
|
|
297
|
-
const conditionalSchema = useConditionalSchema(
|
|
298
|
-
schemaRules,
|
|
299
|
-
baseSchema,
|
|
300
|
-
formData
|
|
301
|
-
);
|
|
302
|
-
const customValidate = useConditionalValidation(validationRules, formData);
|
|
303
|
-
|
|
304
|
-
// Use DevTools
|
|
305
|
-
const devTools = useFormDevTools(
|
|
306
|
-
formData,
|
|
307
|
-
uiRules,
|
|
308
|
-
schemaRules,
|
|
309
|
-
validationRules,
|
|
310
|
-
{
|
|
311
|
-
enabled: devToolsEnabled,
|
|
312
|
-
logToConsole,
|
|
313
|
-
captureHistory,
|
|
314
|
-
historySize: 10,
|
|
315
|
-
}
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
const handleChange = (e: IChangeEvent) => {
|
|
319
|
-
setFormData(e.formData);
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
return (
|
|
323
|
-
<div style={{ padding: '24px', maxWidth: '1200px', margin: '0 auto' }}>
|
|
324
|
-
<Card title='DevTools Settings' style={{ marginBottom: 24 }}>
|
|
325
|
-
<Space>
|
|
326
|
-
<label>
|
|
327
|
-
<Switch checked={devToolsEnabled} onChange={setDevToolsEnabled} />
|
|
328
|
-
<Text style={{ marginLeft: 8 }}>Enable DevTools</Text>
|
|
329
|
-
</label>
|
|
330
|
-
<label>
|
|
331
|
-
<Switch checked={logToConsole} onChange={setLogToConsole} />
|
|
332
|
-
<Text style={{ marginLeft: 8 }}>Log to Console</Text>
|
|
333
|
-
</label>
|
|
334
|
-
<label>
|
|
335
|
-
<Switch checked={captureHistory} onChange={setCaptureHistory} />
|
|
336
|
-
<Text style={{ marginLeft: 8 }}>Capture History</Text>
|
|
337
|
-
</label>
|
|
338
|
-
</Space>
|
|
339
|
-
</Card>
|
|
340
|
-
|
|
341
|
-
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24 }}>
|
|
342
|
-
<div>
|
|
343
|
-
<Form
|
|
344
|
-
schema={conditionalSchema}
|
|
345
|
-
uiSchema={conditionalUiSchema}
|
|
346
|
-
formData={formData}
|
|
347
|
-
onChange={handleChange}
|
|
348
|
-
validator={validator}
|
|
349
|
-
customValidate={customValidate}
|
|
350
|
-
/>
|
|
351
|
-
</div>
|
|
352
|
-
|
|
353
|
-
<div>
|
|
354
|
-
{devToolsEnabled && <DevToolsPanel devTools={devTools} />}
|
|
355
|
-
|
|
356
|
-
{captureHistory && devTools.history.length > 0 && (
|
|
357
|
-
<Card title='History' style={{ marginTop: 24 }}>
|
|
358
|
-
<Text>History entries: {devTools.history.length}</Text>
|
|
359
|
-
<div style={{ maxHeight: 200, overflow: 'auto', marginTop: 8 }}>
|
|
360
|
-
{devTools.history.map((entry, idx) => (
|
|
361
|
-
<div
|
|
362
|
-
key={idx}
|
|
363
|
-
style={{
|
|
364
|
-
marginBottom: 8,
|
|
365
|
-
padding: 8,
|
|
366
|
-
background: '#f0f0f0',
|
|
367
|
-
}}
|
|
368
|
-
>
|
|
369
|
-
<Text type='secondary'>
|
|
370
|
-
{new Date(entry.timestamp).toLocaleTimeString()}
|
|
371
|
-
</Text>
|
|
372
|
-
<pre style={{ fontSize: 12, margin: 0 }}>
|
|
373
|
-
{JSON.stringify(entry.formData, null, 2)}
|
|
374
|
-
</pre>
|
|
375
|
-
</div>
|
|
376
|
-
))}
|
|
377
|
-
</div>
|
|
378
|
-
</Card>
|
|
379
|
-
)}
|
|
380
|
-
</div>
|
|
381
|
-
</div>
|
|
382
|
-
</div>
|
|
383
|
-
);
|
|
384
|
-
}
|