@syncfusion/ej2-react-form-builder 0.1.0-beta → 35.1.42
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 +81 -36
- package/diConfig.json +148 -0
- package/dist/ej2-react-form-builder.min.js +10 -0
- package/dist/ej2-react-form-builder.umd.min.js +11 -0
- package/dist/ej2-react-form-builder.umd.min.js.map +1 -0
- package/dist/es6/ej2-react-form-builder.es2015.js +60 -0
- package/dist/es6/ej2-react-form-builder.es2015.js.map +1 -0
- package/form-builder.d.ts +4 -0
- package/form-builder.js +4 -0
- package/index.d.ts +2 -4
- package/index.js +2 -4
- package/license +6 -13
- package/package.json +19 -43
- package/src/form-builder/formbuilder.component.d.ts +37 -0
- package/src/form-builder/formbuilder.component.js +50 -0
- package/src/form-builder/index.d.ts +2 -0
- package/src/form-builder/index.js +2 -0
- package/src/form-builder/toolboxitems-directive.d.ts +28 -0
- package/src/form-builder/toolboxitems-directive.js +47 -0
- package/src/global.js +1 -0
- package/src/index.d.ts +2 -16
- package/src/index.js +2 -6
- package/Common/CheckboxGroup.d.ts +0 -13
- package/Common/CheckboxGroup.js +0 -50
- package/Common/ConditionalRuleEngine.d.ts +0 -296
- package/Common/ConditionalRuleEngine.js +0 -566
- package/Common/CustomTabComponent.d.ts +0 -17
- package/Common/CustomTabComponent.js +0 -30
- package/Common/CustomValidationEngine.d.ts +0 -58
- package/Common/CustomValidationEngine.js +0 -146
- package/Common/DataGridComponent.d.ts +0 -20
- package/Common/DataGridComponent.js +0 -273
- package/Common/FormValidator.d.ts +0 -485
- package/Common/FormValidator.js +0 -575
- package/Common/MinMaxRuleEngine.d.ts +0 -105
- package/Common/MinMaxRuleEngine.js +0 -365
- package/Common/StaticHtmlRenderer.d.ts +0 -14
- package/Common/StaticHtmlRenderer.js +0 -24
- package/Common/expressions/DependencyTracker.d.ts +0 -30
- package/Common/expressions/DependencyTracker.js +0 -128
- package/Common/expressions/ExpressionEngine.d.ts +0 -95
- package/Common/expressions/ExpressionEngine.js +0 -506
- package/Common/expressions/ExpressionParser.d.ts +0 -41
- package/Common/expressions/ExpressionParser.js +0 -269
- package/Common/expressions/useGridExpressions.d.ts +0 -12
- package/Common/expressions/useGridExpressions.js +0 -71
- package/Common/globalFormId.d.ts +0 -26
- package/Common/globalFormId.js +0 -45
- package/Common/json-converter.d.ts +0 -444
- package/Common/json-converter.js +0 -1184
- package/Common/parser.d.ts +0 -98
- package/Common/parser.js +0 -753
- package/Common/utils.d.ts +0 -130
- package/Common/utils.js +0 -574
- package/src/FormBuilder.d.ts +0 -211
- package/src/FormBuilder.js +0 -1299
- package/src/components/Database/ConnectionForm.d.ts +0 -8
- package/src/components/Database/ConnectionForm.js +0 -28
- package/src/components/TopBar.d.ts +0 -10
- package/src/components/TopBar.js +0 -7
- package/src/components/icons/ComponentIcons.d.ts +0 -44
- package/src/components/icons/ComponentIcons.js +0 -40
- package/src/components/layout/FormFieldWrapper.d.ts +0 -41
- package/src/components/layout/FormFieldWrapper.js +0 -112
- package/src/components/layout/LeftPane.d.ts +0 -23
- package/src/components/layout/LeftPane.js +0 -310
- package/src/components/layout/ListBoxPane.d.ts +0 -24
- package/src/components/layout/ListBoxPane.js +0 -94
- package/src/components/layout/MainSection.d.ts +0 -39
- package/src/components/layout/MainSection.js +0 -1766
- package/src/components/layout/Preview.d.ts +0 -12
- package/src/components/layout/Preview.js +0 -337
- package/src/components/layout/RightPane.d.ts +0 -22
- package/src/components/layout/RightPane.js +0 -370
- package/src/components/theme/ThemeSwitcher.d.ts +0 -14
- package/src/components/theme/ThemeSwitcher.js +0 -24
- package/src/components/theme/theme-constant.d.ts +0 -37
- package/src/components/theme/theme-constant.js +0 -23
- package/src/config/component-properties.json +0 -4929
- package/src/config/form-setting.json +0 -56
- package/src/config/locale.d.ts +0 -449
- package/src/config/locale.js +0 -449
- package/src/context/FormSchemaContext.d.ts +0 -32
- package/src/context/FormSchemaContext.js +0 -155
- package/src/context/LocalizationContext.d.ts +0 -27
- package/src/context/LocalizationContext.js +0 -43
- package/src/context/ThemeContext.d.ts +0 -23
- package/src/context/ThemeContext.js +0 -161
- package/src/context/contexts.d.ts +0 -6
- package/src/context/contexts.js +0 -6
- package/src/context/defaultFormSchema.d.ts +0 -6
- package/src/context/defaultFormSchema.js +0 -20
- package/src/defaultPalette.d.ts +0 -9
- package/src/defaultPalette.js +0 -45
- package/src/defaultTemplate.d.ts +0 -3
- package/src/defaultTemplate.js +0 -185
- package/src/import/schemaImportUtils.d.ts +0 -24
- package/src/import/schemaImportUtils.js +0 -121
- package/src/types/ActionButtons.d.ts +0 -44
- package/src/types/ActionButtons.js +0 -27
- package/src/types/ComponentProperties.d.ts +0 -33
- package/src/types/ComponentProperties.js +0 -2
- package/src/types/FormSchema.d.ts +0 -585
- package/src/types/FormSchema.js +0 -147
- package/src/types/connection.d.ts +0 -19
- package/src/types/connection.js +0 -9
- package/src/utils/AttributesEditor.d.ts +0 -13
- package/src/utils/AttributesEditor.js +0 -117
- package/src/utils/ButtonGroupEditor.d.ts +0 -15
- package/src/utils/ButtonGroupEditor.js +0 -141
- package/src/utils/ChoiceBasedFieldEditor.d.ts +0 -16
- package/src/utils/ChoiceBasedFieldEditor.js +0 -87
- package/src/utils/ClipboardHelper.d.ts +0 -26
- package/src/utils/ClipboardHelper.js +0 -83
- package/src/utils/ColumnBuilder.d.ts +0 -11
- package/src/utils/ColumnBuilder.js +0 -153
- package/src/utils/ColumnSpanEditor.d.ts +0 -8
- package/src/utils/ColumnSpanEditor.js +0 -98
- package/src/utils/ConditionDataEditor.d.ts +0 -29
- package/src/utils/ConditionDataEditor.js +0 -177
- package/src/utils/ConditionalEditorUtils.d.ts +0 -27
- package/src/utils/ConditionalEditorUtils.js +0 -310
- package/src/utils/ConditionsEditor.d.ts +0 -20
- package/src/utils/ConditionsEditor.js +0 -571
- package/src/utils/CustomAccordion.d.ts +0 -13
- package/src/utils/CustomAccordion.js +0 -38
- package/src/utils/CustomValidationEditor.d.ts +0 -11
- package/src/utils/CustomValidationEditor.js +0 -208
- package/src/utils/DataSourceCollector.d.ts +0 -3
- package/src/utils/DataSourceCollector.js +0 -252
- package/src/utils/ExpressionEditor.d.ts +0 -13
- package/src/utils/ExpressionEditor.js +0 -99
- package/src/utils/FormSettingsPanel.d.ts +0 -9
- package/src/utils/FormSettingsPanel.js +0 -60
- package/src/utils/LookupConfig.d.ts +0 -11
- package/src/utils/LookupConfig.js +0 -159
- package/src/utils/MinMaxValueEditor.d.ts +0 -25
- package/src/utils/MinMaxValueEditor.js +0 -188
- package/src/utils/OptionsEditor.d.ts +0 -8
- package/src/utils/OptionsEditor.js +0 -79
- package/src/utils/PropertyRenderer.d.ts +0 -22
- package/src/utils/PropertyRenderer.js +0 -210
- package/src/utils/ValueRenderer.d.ts +0 -2
- package/src/utils/ValueRenderer.js +0 -91
- package/src/utils/ej2DbAdaptor.d.ts +0 -6
- package/src/utils/ej2DbAdaptor.js +0 -38
- package/src/utils/mappingHeuristics.d.ts +0 -10
- package/src/utils/mappingHeuristics.js +0 -33
- package/src/utils/renderComponent.d.ts +0 -18
- package/src/utils/renderComponent.js +0 -300
- package/styles/tailwind3.css +0 -67
- package/styles/themes/action-buttons.css +0 -110
- package/styles/themes/datagrid.css +0 -380
- package/styles/themes/drag-reorder.css +0 -248
- package/styles/themes/import-dialog.css +0 -292
- package/styles/themes/index.css +0 -658
- package/styles/themes/left-pane.css +0 -253
- package/styles/themes/options-editor.css +0 -63
- package/styles/themes/preview.css +0 -702
- package/styles/themes/property-dialog.css +0 -371
|
@@ -1,566 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ConditionalRuleEngine - Core rule evaluation engine for conditional behaviors
|
|
3
|
-
*
|
|
4
|
-
* Evaluates declarative condition rules (from QueryBuilder or manual JSON) against
|
|
5
|
-
* form state to determine field visibility, read-only state, disabled state, and
|
|
6
|
-
* which validators should apply.
|
|
7
|
-
*
|
|
8
|
-
* @spec CONDITIONAL-VALIDATION.md
|
|
9
|
-
* @requirement Tasks 3.1-3.12: ConditionalRuleEngine implementation
|
|
10
|
-
*
|
|
11
|
-
* Features:
|
|
12
|
-
* - Simple rule evaluation (field operator value)
|
|
13
|
-
* - Composite rules (AND/OR combinations with nesting)
|
|
14
|
-
* - Conditional validators (apply validator only when condition met)
|
|
15
|
-
* - Relationship validators (cross-field validation with safe expression eval)
|
|
16
|
-
* - Behavioral flags (visibility, readOnly, disabled)
|
|
17
|
-
* - Error handling with safe defaults
|
|
18
|
-
*
|
|
19
|
-
* Security:
|
|
20
|
-
* - Uses expr-eval for safe expression evaluation (no eval())
|
|
21
|
-
* - Defaults to safe behavior on errors (visible, not disabled, not read-only)
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* const isVisible = ConditionalRuleEngine.isFieldVisible(
|
|
26
|
-
* component.conditions,
|
|
27
|
-
* { country: 'US', age: 25 }
|
|
28
|
-
* );
|
|
29
|
-
*
|
|
30
|
-
* const behaviors = ConditionalRuleEngine.applyConditionalBehaviors(
|
|
31
|
-
* component.conditions,
|
|
32
|
-
* formValues
|
|
33
|
-
* );
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
import { Internationalization } from '@syncfusion/ej2-base';
|
|
37
|
-
/**
|
|
38
|
-
* ConditionalRuleEngine class
|
|
39
|
-
* @private
|
|
40
|
-
* @spec CONDITIONAL-VALIDATION.md - Core rule evaluation engine
|
|
41
|
-
* @requirement Phase 1: Conditional visibility, readOnly, disabled behaviors
|
|
42
|
-
*/
|
|
43
|
-
export class ConditionalRuleEngine {
|
|
44
|
-
/**
|
|
45
|
-
* Evaluate a conditional rule against form values
|
|
46
|
-
*
|
|
47
|
-
* Handles both simple rules (field operator value) and composite rules (AND/OR).
|
|
48
|
-
* Returns false for malformed rules.
|
|
49
|
-
*
|
|
50
|
-
* @spec CONDITIONAL-VALIDATION.md - evaluateCondition method
|
|
51
|
-
* @requirement Task 3.2: Implement evaluateCondition with simple and composite handling
|
|
52
|
-
*
|
|
53
|
-
* @param rule - ConditionalRule or CompositeConditionalRule
|
|
54
|
-
* @param formValues - Current form field values (key = field name, value = field value)
|
|
55
|
-
* @returns true if condition met, false otherwise
|
|
56
|
-
* @private
|
|
57
|
-
* @example
|
|
58
|
-
* ```typescript
|
|
59
|
-
* const rule = { field: 'age', operator: 'greaterThan', value: 18 };
|
|
60
|
-
* const isAdult = ConditionalRuleEngine.evaluateCondition(rule, { age: 25 });
|
|
61
|
-
* // isAdult = true
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
64
|
-
static evaluateCondition(rule, formValues) {
|
|
65
|
-
try {
|
|
66
|
-
// Handle simple rule (field operator value)
|
|
67
|
-
if ('field' in rule && 'operator' in rule && 'value' in rule) {
|
|
68
|
-
return this.evaluateSimpleRule(rule, formValues);
|
|
69
|
-
}
|
|
70
|
-
// Handle composite rule (AND/OR)
|
|
71
|
-
if ('condition' in rule && 'rules' in rule) {
|
|
72
|
-
return this.evaluateCompositeRule(rule, formValues);
|
|
73
|
-
}
|
|
74
|
-
// Malformed rule - default to false (safe default)
|
|
75
|
-
console.warn('ConditionalRuleEngine: Malformed rule detected', rule);
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
console.error('ConditionalRuleEngine: Error evaluating condition', error);
|
|
80
|
-
return false; // Safe default on error
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Evaluate simple field comparison rule
|
|
85
|
-
*
|
|
86
|
-
* Supports operators: equal, notEqual, greaterThan, lessThan, greaterThanOrEqual,
|
|
87
|
-
* lessThanOrEqual, in, notIn, contains, notContains.
|
|
88
|
-
*
|
|
89
|
-
* Handles both camelCase (greaterThan) and lowercase (greaterthan) operator formats
|
|
90
|
-
* for compatibility with QueryBuilder output.
|
|
91
|
-
*
|
|
92
|
-
* @spec CONDITIONAL-VALIDATION.md - evaluateSimpleRule method
|
|
93
|
-
* @requirement Task 3.3: Implement evaluateSimpleRule supporting all operators
|
|
94
|
-
*
|
|
95
|
-
* @param rule - Simple conditional rule with field, operator, value
|
|
96
|
-
* @param formValues - Current form field values
|
|
97
|
-
* @returns true if comparison is true, false otherwise
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* ```typescript
|
|
101
|
-
* const rule = { field: 'email', operator: 'contains', value: '@' };
|
|
102
|
-
* const hasAt = evaluateSimpleRule(rule, { email: 'test@example.com' });
|
|
103
|
-
* // hasAt = true
|
|
104
|
-
* ```
|
|
105
|
-
*/
|
|
106
|
-
static evaluateSimpleRule(rule, formValues) {
|
|
107
|
-
try {
|
|
108
|
-
const fieldValue = formValues[rule.field];
|
|
109
|
-
const operator = rule.operator.toLowerCase();
|
|
110
|
-
// Allow evaluation for operators that make sense when value is undefined/empty
|
|
111
|
-
if (fieldValue === undefined) {
|
|
112
|
-
const allowedForUndefined = ['equal', 'equals', 'notequal', 'notequals', 'isempty', 'isnotempty'];
|
|
113
|
-
if (!allowedForUndefined.includes(operator)) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
// Check if field value is an array (for multiselect, checkboxGroup)
|
|
118
|
-
const isFieldArray = Array.isArray(fieldValue);
|
|
119
|
-
const intl = new Internationalization();
|
|
120
|
-
switch (operator) {
|
|
121
|
-
case 'equal':
|
|
122
|
-
case 'equals':
|
|
123
|
-
return fieldValue === rule.value;
|
|
124
|
-
case 'notequal':
|
|
125
|
-
case 'notequals':
|
|
126
|
-
return fieldValue !== rule.value;
|
|
127
|
-
case 'startswith': return fieldValue.startsWith(rule.value);
|
|
128
|
-
case 'doesnotstartswith': return !fieldValue.startsWith(rule.value);
|
|
129
|
-
case 'greaterthan':
|
|
130
|
-
case 'lessthan':
|
|
131
|
-
case 'greaterthanorequal':
|
|
132
|
-
case 'lessthanorequal': {
|
|
133
|
-
const ln = Number(fieldValue);
|
|
134
|
-
const rn = Number(rule.value);
|
|
135
|
-
if (!Number.isNaN(ln) && !Number.isNaN(rn)) {
|
|
136
|
-
if (operator === 'greaterthan')
|
|
137
|
-
return ln > rn;
|
|
138
|
-
if (operator === 'lessthan')
|
|
139
|
-
return ln < rn;
|
|
140
|
-
if (operator === 'greaterthanorequal')
|
|
141
|
-
return ln >= rn;
|
|
142
|
-
return ln <= rn;
|
|
143
|
-
}
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
case 'dategreaterthan':
|
|
147
|
-
case 'datelessthan': {
|
|
148
|
-
// try date comparison first
|
|
149
|
-
const leftTs = intl.parseDate(fieldValue, { format: 'MM/dd/yyyy' });
|
|
150
|
-
const rightTs = intl.parseDate(rule.value, { format: 'MM/dd/yyyy' });
|
|
151
|
-
if (leftTs !== null && rightTs !== null) {
|
|
152
|
-
if (operator === 'dategreaterthan')
|
|
153
|
-
return leftTs > rightTs;
|
|
154
|
-
if (operator === 'datelessthan')
|
|
155
|
-
return leftTs < rightTs;
|
|
156
|
-
return leftTs <= rightTs;
|
|
157
|
-
}
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
case 'timegreaterthan':
|
|
161
|
-
case 'timelessthan': {
|
|
162
|
-
// Parse time strings (format: hh:mm a)
|
|
163
|
-
const leftTime = intl.parseDate(fieldValue, { format: 'hh:mm a', type: 'time' });
|
|
164
|
-
const rightTime = intl.parseDate(rule.value, { format: 'hh:mm a', type: 'time' });
|
|
165
|
-
if (leftTime !== null && rightTime !== null) {
|
|
166
|
-
if (operator === 'timegreaterthan')
|
|
167
|
-
return leftTime > rightTime;
|
|
168
|
-
if (operator === 'timelessthan')
|
|
169
|
-
return leftTime < rightTime;
|
|
170
|
-
}
|
|
171
|
-
return false;
|
|
172
|
-
}
|
|
173
|
-
case 'datetimegreaterthan':
|
|
174
|
-
case 'datetimelessthan': {
|
|
175
|
-
// Parse datetime strings (format: MM/dd/yyyy hh:mm a)
|
|
176
|
-
const leftDateTime = intl.parseDate(fieldValue, { format: 'MM/dd/yyyy hh:mm a', type: 'dateTime' });
|
|
177
|
-
const rightDateTime = intl.parseDate(rule.value, { format: 'MM/dd/yyyy hh:mm a', type: 'dateTime' });
|
|
178
|
-
if (leftDateTime !== null && rightDateTime !== null) {
|
|
179
|
-
if (operator === 'datetimegreaterthan')
|
|
180
|
-
return leftDateTime > rightDateTime;
|
|
181
|
-
if (operator === 'datetimelessthan')
|
|
182
|
-
return leftDateTime < rightDateTime;
|
|
183
|
-
}
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
case 'contains':
|
|
187
|
-
// If field value is array, check if array contains the specific value(s)
|
|
188
|
-
if (isFieldArray) {
|
|
189
|
-
// Parse comma-separated values in rule.value if it's a string
|
|
190
|
-
if (typeof rule.value === 'string' && rule.value.includes(',')) {
|
|
191
|
-
const searchValues = rule.value.split(',').map(v => v.trim());
|
|
192
|
-
// Check if array contains ANY of the search values
|
|
193
|
-
return searchValues.some(searchVal => fieldValue.includes(searchVal));
|
|
194
|
-
}
|
|
195
|
-
return fieldValue.includes(rule.value);
|
|
196
|
-
}
|
|
197
|
-
// Otherwise, check string contains
|
|
198
|
-
return String(fieldValue).includes(String(rule.value));
|
|
199
|
-
case 'notcontains':
|
|
200
|
-
// If field value is array, check if array does NOT contain the specific value(s)
|
|
201
|
-
if (isFieldArray) {
|
|
202
|
-
// Parse comma-separated values in rule.value if it's a string
|
|
203
|
-
if (typeof rule.value === 'string' && rule.value.includes(',')) {
|
|
204
|
-
const searchValues = rule.value.split(',').map(v => v.trim());
|
|
205
|
-
// Check if array contains NONE of the search values
|
|
206
|
-
return !searchValues.some(searchVal => fieldValue.includes(searchVal));
|
|
207
|
-
}
|
|
208
|
-
return !fieldValue.includes(rule.value);
|
|
209
|
-
}
|
|
210
|
-
// Otherwise, check string does not contain
|
|
211
|
-
return !String(fieldValue).includes(String(rule.value));
|
|
212
|
-
case 'isempty':
|
|
213
|
-
// Check if array is empty
|
|
214
|
-
if (isFieldArray) {
|
|
215
|
-
return fieldValue.length === 0;
|
|
216
|
-
}
|
|
217
|
-
// For non-arrays, check if falsy or empty string
|
|
218
|
-
return !fieldValue || String(fieldValue).length === 0;
|
|
219
|
-
case 'isnotempty':
|
|
220
|
-
// Check if array has items
|
|
221
|
-
if (isFieldArray) {
|
|
222
|
-
return fieldValue.length > 0;
|
|
223
|
-
}
|
|
224
|
-
// For non-arrays, check if truthy and not empty string
|
|
225
|
-
return !!fieldValue && String(fieldValue).length > 0;
|
|
226
|
-
default:
|
|
227
|
-
console.warn(`ConditionalRuleEngine: Unknown operator "${rule.operator}"`);
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
catch (error) {
|
|
232
|
-
console.error('ConditionalRuleEngine: Error in evaluateSimpleRule', error);
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Evaluate composite rule with AND/OR logic
|
|
238
|
-
*
|
|
239
|
-
* Recursively evaluates nested rules with AND (all must be true) or OR
|
|
240
|
-
* (at least one must be true) logic.
|
|
241
|
-
*
|
|
242
|
-
* @spec CONDITIONAL-VALIDATION.md - evaluateCompositeRule method
|
|
243
|
-
* @requirement Task 3.4: Implement evaluateCompositeRule for AND/OR logic
|
|
244
|
-
*
|
|
245
|
-
* @param rule - Composite rule with condition ('and'|'or') and rules array
|
|
246
|
-
* @param formValues - Current form field values
|
|
247
|
-
* @returns true if composite condition met, false otherwise
|
|
248
|
-
*
|
|
249
|
-
* @example
|
|
250
|
-
* ```typescript
|
|
251
|
-
* const rule = {
|
|
252
|
-
* condition: 'and',
|
|
253
|
-
* rules: [
|
|
254
|
-
* { field: 'age', operator: 'greaterThan', value: 18 },
|
|
255
|
-
* { field: 'country', operator: 'equal', value: 'US' }
|
|
256
|
-
* ]
|
|
257
|
-
* };
|
|
258
|
-
* const isEligible = evaluateCompositeRule(rule, { age: 25, country: 'US' });
|
|
259
|
-
* // isEligible = true
|
|
260
|
-
* ```
|
|
261
|
-
*/
|
|
262
|
-
static evaluateCompositeRule(rule, formValues) {
|
|
263
|
-
try {
|
|
264
|
-
if (!Array.isArray(rule.rules) || rule.rules.length === 0) {
|
|
265
|
-
console.warn('ConditionalRuleEngine: Composite rule has no rules');
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
const condition = rule.condition.toLowerCase();
|
|
269
|
-
if (condition === 'and') {
|
|
270
|
-
// All rules must be true
|
|
271
|
-
return rule.rules.every((childRule) => this.evaluateCondition(childRule, formValues));
|
|
272
|
-
}
|
|
273
|
-
else if (condition === 'or') {
|
|
274
|
-
// At least one rule must be true
|
|
275
|
-
return rule.rules.some((childRule) => this.evaluateCondition(childRule, formValues));
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
console.warn(`ConditionalRuleEngine: Unknown composite condition "${rule.condition}"`);
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
catch (error) {
|
|
283
|
-
console.error('ConditionalRuleEngine: Error in evaluateCompositeRule', error);
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Check if field should be visible
|
|
289
|
-
*
|
|
290
|
-
* Evaluates visibleWhen condition. Defaults to true (visible) if no condition
|
|
291
|
-
* is defined or on error.
|
|
292
|
-
*
|
|
293
|
-
* @spec CONDITIONAL-VALIDATION.md - isFieldVisible method
|
|
294
|
-
* @requirement Task 3.8: Implement isFieldVisible (defaults to true if no condition)
|
|
295
|
-
*
|
|
296
|
-
* @param conditions - FormComponentConditions containing visibleWhen rule
|
|
297
|
-
* @param formValues - Current form field values
|
|
298
|
-
* @returns true if field should be visible, false if hidden
|
|
299
|
-
*
|
|
300
|
-
* @example
|
|
301
|
-
* ```typescript
|
|
302
|
-
* const conditions = {
|
|
303
|
-
* visibleWhen: { field: 'showEmail', operator: 'equal', value: true }
|
|
304
|
-
* };
|
|
305
|
-
* const visible = isFieldVisible(conditions, { showEmail: true });
|
|
306
|
-
* // visible = true
|
|
307
|
-
* ```
|
|
308
|
-
*/
|
|
309
|
-
static isFieldVisible(conditions, formValues) {
|
|
310
|
-
try {
|
|
311
|
-
if (!conditions?.visibleWhen) {
|
|
312
|
-
return true; // Default: visible if no condition
|
|
313
|
-
}
|
|
314
|
-
return this.evaluateCondition(conditions.visibleWhen, formValues);
|
|
315
|
-
}
|
|
316
|
-
catch (error) {
|
|
317
|
-
console.error('ConditionalRuleEngine: Error in isFieldVisible', error);
|
|
318
|
-
return true; // Safe default: visible on error
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* Check if field should be read-only
|
|
323
|
-
*
|
|
324
|
-
* Evaluates readOnlyWhen condition. Defaults to false (editable) if no
|
|
325
|
-
* condition is defined or on error.
|
|
326
|
-
*
|
|
327
|
-
* @spec CONDITIONAL-VALIDATION.md - isFieldReadOnly method
|
|
328
|
-
* @requirement Task 3.9: Implement isFieldReadOnly (defaults to false if no condition)
|
|
329
|
-
*
|
|
330
|
-
* @param conditions - FormComponentConditions containing readOnlyWhen rule
|
|
331
|
-
* @param formValues - Current form field values
|
|
332
|
-
* @returns true if field should be read-only, false if editable
|
|
333
|
-
*
|
|
334
|
-
* @example
|
|
335
|
-
* ```typescript
|
|
336
|
-
* const conditions = {
|
|
337
|
-
* readOnlyWhen: { field: 'isVerified', operator: 'equal', value: true }
|
|
338
|
-
* };
|
|
339
|
-
* const readOnly = isFieldReadOnly(conditions, { isVerified: true });
|
|
340
|
-
* // readOnly = true
|
|
341
|
-
* ```
|
|
342
|
-
*/
|
|
343
|
-
static isFieldReadOnly(conditions, formValues) {
|
|
344
|
-
try {
|
|
345
|
-
if (!conditions?.readOnlyWhen) {
|
|
346
|
-
return false; // Default: not read-only if no condition
|
|
347
|
-
}
|
|
348
|
-
return this.evaluateCondition(conditions.readOnlyWhen, formValues);
|
|
349
|
-
}
|
|
350
|
-
catch (error) {
|
|
351
|
-
console.error('ConditionalRuleEngine: Error in isFieldReadOnly', error);
|
|
352
|
-
return false; // Safe default: not read-only on error
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Check if field should be disabled
|
|
357
|
-
*
|
|
358
|
-
* Evaluates disabledWhen condition. Defaults to false (enabled) if no
|
|
359
|
-
* condition is defined or on error.
|
|
360
|
-
*
|
|
361
|
-
* @spec CONDITIONAL-VALIDATION.md - isFieldDisabled method
|
|
362
|
-
* @requirement Task 3.10: Implement isFieldDisabled (defaults to false if no condition)
|
|
363
|
-
*
|
|
364
|
-
* @param conditions - FormComponentConditions containing disabledWhen rule
|
|
365
|
-
* @param formValues - Current form field values
|
|
366
|
-
* @returns true if field should be disabled, false if enabled
|
|
367
|
-
*
|
|
368
|
-
* @example
|
|
369
|
-
* ```typescript
|
|
370
|
-
* const conditions = {
|
|
371
|
-
* disabledWhen: { field: 'orderStatus', operator: 'equal', value: 'completed' }
|
|
372
|
-
* };
|
|
373
|
-
* const disabled = isFieldDisabled(conditions, { orderStatus: 'completed' });
|
|
374
|
-
* // disabled = true
|
|
375
|
-
* ```
|
|
376
|
-
*/
|
|
377
|
-
static isFieldDisabled(conditions, formValues) {
|
|
378
|
-
try {
|
|
379
|
-
if (!conditions?.disabledWhen) {
|
|
380
|
-
return false; // Default: not disabled if no condition
|
|
381
|
-
}
|
|
382
|
-
return this.evaluateCondition(conditions.disabledWhen, formValues);
|
|
383
|
-
}
|
|
384
|
-
catch (error) {
|
|
385
|
-
console.error('ConditionalRuleEngine: Error in isFieldDisabled', error);
|
|
386
|
-
return false; // Safe default: not disabled on error
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Check if field should be hidden
|
|
391
|
-
*
|
|
392
|
-
* Evaluates hideWhen condition. Defaults to false (visible) if no condition
|
|
393
|
-
* is defined or on error.
|
|
394
|
-
*
|
|
395
|
-
* @param conditions - FormComponentConditions containing hideWhen rule
|
|
396
|
-
* @param formValues - Current form field values
|
|
397
|
-
* @returns true if field should be hidden, false if visible
|
|
398
|
-
*
|
|
399
|
-
* @example
|
|
400
|
-
* ```typescript
|
|
401
|
-
* const conditions = {
|
|
402
|
-
* hideWhen: { field: 'hideEmail', operator: 'equal', value: true }
|
|
403
|
-
* };
|
|
404
|
-
* const hidden = isFieldHidden(conditions, { hideEmail: true });
|
|
405
|
-
* // hidden = true
|
|
406
|
-
* ```
|
|
407
|
-
*/
|
|
408
|
-
static isFieldHidden(conditions, formValues) {
|
|
409
|
-
try {
|
|
410
|
-
if (!conditions?.hideWhen) {
|
|
411
|
-
return false; // Default: not hidden if no condition
|
|
412
|
-
}
|
|
413
|
-
return this.evaluateCondition(conditions.hideWhen, formValues);
|
|
414
|
-
}
|
|
415
|
-
catch (error) {
|
|
416
|
-
console.error('ConditionalRuleEngine: Error in isFieldHidden', error);
|
|
417
|
-
return false; // Safe default: not hidden on error
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
/**
|
|
421
|
-
* Check if field should be required
|
|
422
|
-
*
|
|
423
|
-
* Evaluates requiredWhen condition. Defaults to false (not required) if no condition
|
|
424
|
-
* is defined or on error.
|
|
425
|
-
*
|
|
426
|
-
* @param conditions - FormComponentConditions containing requiredWhen rule
|
|
427
|
-
* @param formValues - Current form field values
|
|
428
|
-
* @returns true if field should be required, false if optional
|
|
429
|
-
*
|
|
430
|
-
* @example
|
|
431
|
-
* ```typescript
|
|
432
|
-
* const conditions = {
|
|
433
|
-
* requiredWhen: { field: 'requireDetails', operator: 'equal', value: true }
|
|
434
|
-
* };
|
|
435
|
-
* const required = isFieldRequired(conditions, { requireDetails: true });
|
|
436
|
-
* // required = true
|
|
437
|
-
* ```
|
|
438
|
-
*/
|
|
439
|
-
static isFieldRequired(conditions, formValues) {
|
|
440
|
-
try {
|
|
441
|
-
if (!conditions?.requiredWhen) {
|
|
442
|
-
return false; // Default: not required if no condition
|
|
443
|
-
}
|
|
444
|
-
return this.evaluateCondition(conditions.requiredWhen, formValues);
|
|
445
|
-
}
|
|
446
|
-
catch (error) {
|
|
447
|
-
console.error('ConditionalRuleEngine: Error in isFieldRequired', error);
|
|
448
|
-
return false; // Safe default: not required on error
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Get value to set for field if condition is met
|
|
453
|
-
*
|
|
454
|
-
* Evaluates setValueWhen condition and returns the value to assign if true.
|
|
455
|
-
* Returns undefined if no condition is defined, condition not met, or on error.
|
|
456
|
-
*
|
|
457
|
-
* @param conditions - FormComponentConditions containing setValueWhen rule
|
|
458
|
-
* @param formValues - Current form field values
|
|
459
|
-
* @returns The value to set if condition met, undefined otherwise
|
|
460
|
-
*
|
|
461
|
-
* @example
|
|
462
|
-
* ```typescript
|
|
463
|
-
* const conditions = {
|
|
464
|
-
* setValueWhen: {
|
|
465
|
-
* condition: { field: 'country', operator: 'equal', value: 'US' },
|
|
466
|
-
* value: 'United States'
|
|
467
|
-
* }
|
|
468
|
-
* };
|
|
469
|
-
* const value = getConditionalValue(conditions, { country: 'US' });
|
|
470
|
-
* // value = 'United States'
|
|
471
|
-
* ```
|
|
472
|
-
*/
|
|
473
|
-
static getConditionalValue(conditions, formValues) {
|
|
474
|
-
try {
|
|
475
|
-
if (!conditions?.setValueWhen) {
|
|
476
|
-
return undefined;
|
|
477
|
-
}
|
|
478
|
-
const isMet = this.evaluateCondition(conditions.setValueWhen.condition, formValues);
|
|
479
|
-
if (isMet) {
|
|
480
|
-
return conditions.setValueWhen.value;
|
|
481
|
-
}
|
|
482
|
-
return undefined;
|
|
483
|
-
}
|
|
484
|
-
catch (error) {
|
|
485
|
-
console.error('ConditionalRuleEngine: Error in getConditionalValue', error);
|
|
486
|
-
return undefined;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
* Evaluate conditional data availability
|
|
491
|
-
* Returns true if any conditional data rule's condition is met
|
|
492
|
-
*
|
|
493
|
-
* @param conditionalDataRules - Array of ConditionalDataRule objects
|
|
494
|
-
* @param formValues - Current form field values
|
|
495
|
-
* @returns Index of first matching rule, or -1 if none match
|
|
496
|
-
*/
|
|
497
|
-
static evaluateConditionalDataRules(conditionalDataRules, formValues) {
|
|
498
|
-
if (!conditionalDataRules || !Array.isArray(conditionalDataRules)) {
|
|
499
|
-
return -1;
|
|
500
|
-
}
|
|
501
|
-
for (let i = 0; i < conditionalDataRules.length; i++) {
|
|
502
|
-
const rule = conditionalDataRules[i];
|
|
503
|
-
if (this.evaluateCondition(rule.condition, formValues)) {
|
|
504
|
-
return i; // Return index of first matching rule
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return -1;
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Get filtered options for a dependent dropdown based on choice-based field rule
|
|
511
|
-
*
|
|
512
|
-
* If choiceBasedField rule exists and primary field has a value,
|
|
513
|
-
* return only the mapped dependent options for that primary value.
|
|
514
|
-
* Otherwise return all options.
|
|
515
|
-
*
|
|
516
|
-
* @param rule - ChoiceBasedFieldRule configuration
|
|
517
|
-
* @param allDependentOptions - Complete list of dependent field options
|
|
518
|
-
* @param formValues - Current form values
|
|
519
|
-
* @param primaryFieldId - ID of primary field
|
|
520
|
-
* @returns Filtered options array
|
|
521
|
-
*
|
|
522
|
-
* @example
|
|
523
|
-
* ```typescript
|
|
524
|
-
* const rule = {
|
|
525
|
-
* primaryFieldId: 'dept-id',
|
|
526
|
-
* choiceMapping: {
|
|
527
|
-
* 'Marketing': ['Markers', 'Sticky Notes'],
|
|
528
|
-
* 'Finance': ['Calculator']
|
|
529
|
-
* }
|
|
530
|
-
* };
|
|
531
|
-
*
|
|
532
|
-
* const filtered = ConditionalRuleEngine.getChoiceBasedOptions(
|
|
533
|
-
* rule,
|
|
534
|
-
* ['Markers', 'Sticky Notes', 'Calculator'],
|
|
535
|
-
* { 'dept-id': 'Marketing' },
|
|
536
|
-
* 'dept-id'
|
|
537
|
-
* );
|
|
538
|
-
* // Returns: ['Markers', 'Sticky Notes']
|
|
539
|
-
* ```
|
|
540
|
-
*/
|
|
541
|
-
static getChoiceBasedOptions(rule, allDependentOptions, formValues, primaryFieldId) {
|
|
542
|
-
try {
|
|
543
|
-
// Get primary field value from form
|
|
544
|
-
const primaryValue = formValues && formValues[primaryFieldId];
|
|
545
|
-
if (primaryValue === null || primaryValue === undefined) {
|
|
546
|
-
// No primary value selected - return all or empty based on rule config
|
|
547
|
-
return rule.showAllWhenNotMapped ? allDependentOptions : [];
|
|
548
|
-
}
|
|
549
|
-
// Ensure primary value is treated as string for comparison
|
|
550
|
-
const primaryValueStr = String(primaryValue);
|
|
551
|
-
// Check if this primary value is mapped in the rule
|
|
552
|
-
if (primaryValueStr in rule.choiceMapping) {
|
|
553
|
-
const mappedOptions = rule.choiceMapping[primaryValueStr];
|
|
554
|
-
// Validate mapped options exist in all options (safety check)
|
|
555
|
-
return mappedOptions.filter(opt => allDependentOptions.includes(opt));
|
|
556
|
-
}
|
|
557
|
-
// Primary value not mapped - return all or empty based on rule config
|
|
558
|
-
return rule.showAllWhenNotMapped ? allDependentOptions : [];
|
|
559
|
-
}
|
|
560
|
-
catch (error) {
|
|
561
|
-
console.error('Error in getChoiceBasedOptions:', error);
|
|
562
|
-
// Safe default - return all options
|
|
563
|
-
return allDependentOptions;
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
interface TabItem {
|
|
3
|
-
header: string;
|
|
4
|
-
content: React.ReactNode;
|
|
5
|
-
}
|
|
6
|
-
interface CustomTabComponentProps {
|
|
7
|
-
tabs: TabItem[];
|
|
8
|
-
selectedIndex?: number;
|
|
9
|
-
onTabSelect?: (index: number) => void;
|
|
10
|
-
className?: string;
|
|
11
|
-
enableRtl?: boolean;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* @private
|
|
15
|
-
*/
|
|
16
|
-
export declare const CustomTabComponent: React.FC<CustomTabComponentProps>;
|
|
17
|
-
export {};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect, useRef } from 'react';
|
|
3
|
-
import { ToolbarComponent, ItemsDirective, ItemDirective } from '@syncfusion/ej2-react-navigations';
|
|
4
|
-
/**
|
|
5
|
-
* @private
|
|
6
|
-
*/
|
|
7
|
-
export const CustomTabComponent = ({ tabs, selectedIndex = 0, onTabSelect, className = '', enableRtl }) => {
|
|
8
|
-
const [activeIndex, setActiveIndex] = useState(selectedIndex);
|
|
9
|
-
const toolbarRef = useRef(null);
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
setActiveIndex(selectedIndex);
|
|
12
|
-
}, [selectedIndex]);
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
const toolbar = toolbarRef.current;
|
|
15
|
-
if (!toolbar || !toolbar.element) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
const items = toolbar.element.querySelectorAll('.e-toolbar-item');
|
|
19
|
-
items.forEach((el, i) => {
|
|
20
|
-
el.setAttribute('aria-selected', i === activeIndex ? 'true' : 'false');
|
|
21
|
-
});
|
|
22
|
-
}, [activeIndex, tabs]);
|
|
23
|
-
const handleItemClick = (index) => {
|
|
24
|
-
if (index > -1 && index !== activeIndex) {
|
|
25
|
-
setActiveIndex(index);
|
|
26
|
-
onTabSelect?.(index);
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
return (_jsxs("div", { className: `form-tabs e-control e-tab custom-tab e-lib e-keyboard ${className} ${enableRtl ? 'e-rtl' : ''}`, "aria-disabled": "false", style: { width: '100%', height: 'auto' }, children: [_jsx("div", { style: { position: 'relative' }, children: _jsx(ToolbarComponent, { ref: toolbarRef, className: 'e-tab-header', overflowMode: 'Scrollable', enableRtl: enableRtl, width: "100%", height: "auto", cssClass: "custom-tab-toolbar", children: _jsx(ItemsDirective, { children: tabs.map((tab, index) => (_jsx(ItemDirective, { id: `e-item-tab_${index}`, "data-id": `tabitem_${index}`, cssClass: activeIndex === index ? 'e-active' : '', template: () => (_jsx("div", { className: "e-tab-wrap", tabIndex: activeIndex === index ? 0 : -1, "data-tabindex": "-1", role: "tab", "aria-selected": activeIndex === index, "aria-disabled": "false", "aria-labelledby": `e-content-tab_${index}`, onClick: () => handleItemClick(index), style: { cursor: 'pointer' }, children: _jsx("div", { className: "e-text-wrap", children: _jsx("div", { className: "e-tab-text", role: "presentation", children: tab.header }) }) })) }, index))) }) }, tabs.length) }), _jsx("div", { className: "e-content e-lib e-touch", style: { height: 'auto' }, children: tabs.map((tab, index) => (_jsx("div", { className: `e-item ${activeIndex === index ? 'e-active' : ''}`, id: `e-content-tab_${index}`, role: "tabpanel", "aria-labelledby": `e-item-tab_${index}`, style: { display: activeIndex === index ? 'block' : 'none' }, children: _jsx("div", { children: tab.content }, index) }, index))) }, activeIndex)] }));
|
|
30
|
-
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { type FormValueType } from './expressions/ExpressionEngine';
|
|
2
|
-
/**
|
|
3
|
-
* Custom Validation Engine
|
|
4
|
-
*
|
|
5
|
-
* Evaluates FormIO-style custom validation expressions:
|
|
6
|
-
* valid = (condition) ? true : 'error message';
|
|
7
|
-
*
|
|
8
|
-
* Reuses ExpressionEngine for dependency extraction and expression parsing
|
|
9
|
-
* @private
|
|
10
|
-
* @spec custom_validation_spec_new.md
|
|
11
|
-
*/
|
|
12
|
-
export declare class CustomValidationEngine {
|
|
13
|
-
private expressionEngine;
|
|
14
|
-
constructor();
|
|
15
|
-
/**
|
|
16
|
-
* Validate field using custom validation expression
|
|
17
|
-
*
|
|
18
|
-
* @param expression - FormIO-style validation expression (generated by UI)
|
|
19
|
-
* @param fieldValue - Current field value (as 'input')
|
|
20
|
-
* @param formValues - All form values for cross-field references
|
|
21
|
-
* @returns true if valid, error message string if invalid
|
|
22
|
-
*/
|
|
23
|
-
validate(expression: string, fieldValue: any, formValues: Record<string, FormValueType>): true | string;
|
|
24
|
-
/**
|
|
25
|
-
* Extract field dependencies from validation expression
|
|
26
|
-
*
|
|
27
|
-
* @param expression - Custom validation expression (or just condition)
|
|
28
|
-
* @returns Array of field names referenced in expression
|
|
29
|
-
*/
|
|
30
|
-
extractDependencies(expression: string): string[];
|
|
31
|
-
/**
|
|
32
|
-
* Validate condition syntax (simplified - no need for "valid =" check)
|
|
33
|
-
*
|
|
34
|
-
* @param condition - Validation condition (without "valid =" prefix)
|
|
35
|
-
* @param availableFields - Available field names for reference validation
|
|
36
|
-
* @returns Array of validation error messages
|
|
37
|
-
*/
|
|
38
|
-
validateConditionSyntax(condition: string, availableFields: string[]): string[];
|
|
39
|
-
/**
|
|
40
|
-
* Build full FormIO expression from condition and error message
|
|
41
|
-
*
|
|
42
|
-
* @param condition - Validation condition (e.g., "(input === {password})")
|
|
43
|
-
* @param errorMessage - Error message to show when validation fails
|
|
44
|
-
* @returns Full FormIO expression
|
|
45
|
-
*/
|
|
46
|
-
buildExpression(condition: string, errorMessage: string): string;
|
|
47
|
-
/**
|
|
48
|
-
* Extract condition and error message from full FormIO expression
|
|
49
|
-
* For editing existing rules
|
|
50
|
-
*
|
|
51
|
-
* @param expression - Full FormIO expression
|
|
52
|
-
* @returns { condition, errorMessage } or null if invalid
|
|
53
|
-
*/
|
|
54
|
-
parseExpression(expression: string): {
|
|
55
|
-
condition: string;
|
|
56
|
-
errorMessage: string;
|
|
57
|
-
} | null;
|
|
58
|
-
}
|