@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,146 +0,0 @@
|
|
|
1
|
-
import { ExpressionEngine } 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 class CustomValidationEngine {
|
|
13
|
-
expressionEngine;
|
|
14
|
-
constructor() {
|
|
15
|
-
this.expressionEngine = new ExpressionEngine();
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Validate field using custom validation expression
|
|
19
|
-
*
|
|
20
|
-
* @param expression - FormIO-style validation expression (generated by UI)
|
|
21
|
-
* @param fieldValue - Current field value (as 'input')
|
|
22
|
-
* @param formValues - All form values for cross-field references
|
|
23
|
-
* @returns true if valid, error message string if invalid
|
|
24
|
-
*/
|
|
25
|
-
validate(expression, fieldValue, formValues) {
|
|
26
|
-
if (!expression || expression.trim() === '') {
|
|
27
|
-
return true; // No validation rule = valid
|
|
28
|
-
}
|
|
29
|
-
try {
|
|
30
|
-
// Inject 'input' as current field value
|
|
31
|
-
const context = {
|
|
32
|
-
...formValues,
|
|
33
|
-
input: fieldValue,
|
|
34
|
-
valid: true // Initialize valid variable
|
|
35
|
-
};
|
|
36
|
-
// Parse expression - FormIO pattern uses assignment: valid = ...
|
|
37
|
-
// Pattern: valid = (condition) ? true : 'error message'
|
|
38
|
-
const validPattern = /valid\s*=\s*(.+?)\s*\?\s*true\s*:\s*['"](.+?)['"]\s*$/;
|
|
39
|
-
const match = expression.match(validPattern);
|
|
40
|
-
if (!match) {
|
|
41
|
-
console.warn('Custom validation expression must follow format: valid = (condition) ? true : "error message"');
|
|
42
|
-
return 'Invalid validation expression format';
|
|
43
|
-
}
|
|
44
|
-
const condition = match[1].trim();
|
|
45
|
-
const errorMessage = match[2];
|
|
46
|
-
// Evaluate the condition (should return boolean)
|
|
47
|
-
const conditionResult = this.expressionEngine.evaluate(condition, context, { throwOnError: false }, true);
|
|
48
|
-
// If condition is true, validation passes
|
|
49
|
-
if (conditionResult === true) {
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
// Condition is false, return the error message
|
|
54
|
-
return errorMessage;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
console.error('Custom validation error:', error);
|
|
59
|
-
return 'Validation expression error';
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Extract field dependencies from validation expression
|
|
64
|
-
*
|
|
65
|
-
* @param expression - Custom validation expression (or just condition)
|
|
66
|
-
* @returns Array of field names referenced in expression
|
|
67
|
-
*/
|
|
68
|
-
extractDependencies(expression) {
|
|
69
|
-
if (!expression)
|
|
70
|
-
return [];
|
|
71
|
-
// Extract validation logic (right side of = sign if present)
|
|
72
|
-
const validPattern = /valid\s*=\s*(.+)/;
|
|
73
|
-
const match = expression.match(validPattern);
|
|
74
|
-
const validationLogic = match ? match[1] : expression;
|
|
75
|
-
// Use ExpressionEngine to extract field references
|
|
76
|
-
const deps = this.expressionEngine.extractDependencies(validationLogic);
|
|
77
|
-
// Filter out 'input' as it's the current field, not a dependency
|
|
78
|
-
return deps.filter(dep => dep !== 'input');
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Validate condition syntax (simplified - no need for "valid =" check)
|
|
82
|
-
*
|
|
83
|
-
* @param condition - Validation condition (without "valid =" prefix)
|
|
84
|
-
* @param availableFields - Available field names for reference validation
|
|
85
|
-
* @returns Array of validation error messages
|
|
86
|
-
*/
|
|
87
|
-
validateConditionSyntax(condition, availableFields) {
|
|
88
|
-
if (!condition || condition.trim() === '') {
|
|
89
|
-
return ['Condition cannot be empty'];
|
|
90
|
-
}
|
|
91
|
-
const errors = [];
|
|
92
|
-
// Check for balanced parentheses
|
|
93
|
-
const openParens = (condition.match(/\(/g) || []).length;
|
|
94
|
-
const closeParens = (condition.match(/\)/g) || []).length;
|
|
95
|
-
if (openParens !== closeParens) {
|
|
96
|
-
errors.push(`Unbalanced parentheses (${openParens} open, ${closeParens} close)`);
|
|
97
|
-
}
|
|
98
|
-
// Check for balanced braces
|
|
99
|
-
const openBraces = (condition.match(/\{/g) || []).length;
|
|
100
|
-
const closeBraces = (condition.match(/\}/g) || []).length;
|
|
101
|
-
if (openBraces !== closeBraces) {
|
|
102
|
-
errors.push(`Unbalanced braces (${openBraces} open, ${closeBraces} close)`);
|
|
103
|
-
}
|
|
104
|
-
// Validate field references
|
|
105
|
-
const deps = this.extractDependencies(condition);
|
|
106
|
-
const invalidFields = deps.filter(field => !availableFields.includes(field));
|
|
107
|
-
if (invalidFields.length > 0) {
|
|
108
|
-
errors.push(`Unknown field references: ${invalidFields.join(', ')}`);
|
|
109
|
-
}
|
|
110
|
-
return errors;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Build full FormIO expression from condition and error message
|
|
114
|
-
*
|
|
115
|
-
* @param condition - Validation condition (e.g., "(input === {password})")
|
|
116
|
-
* @param errorMessage - Error message to show when validation fails
|
|
117
|
-
* @returns Full FormIO expression
|
|
118
|
-
*/
|
|
119
|
-
buildExpression(condition, errorMessage) {
|
|
120
|
-
// Remove outer parentheses if present (we'll add them back in ternary)
|
|
121
|
-
const trimmedCondition = condition.trim();
|
|
122
|
-
// Escape single quotes in error message
|
|
123
|
-
const escapedMessage = errorMessage.replace(/'/g, "\\'");
|
|
124
|
-
// Build FormIO expression
|
|
125
|
-
return `valid = ${trimmedCondition} ? true : '${escapedMessage}'`;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Extract condition and error message from full FormIO expression
|
|
129
|
-
* For editing existing rules
|
|
130
|
-
*
|
|
131
|
-
* @param expression - Full FormIO expression
|
|
132
|
-
* @returns { condition, errorMessage } or null if invalid
|
|
133
|
-
*/
|
|
134
|
-
parseExpression(expression) {
|
|
135
|
-
// Pattern: valid = (condition) ? true : 'error message'
|
|
136
|
-
const pattern = /valid\s*=\s*(.+?)\s*\?\s*true\s*:\s*'(.+)'/;
|
|
137
|
-
const match = expression.match(pattern);
|
|
138
|
-
if (match) {
|
|
139
|
-
return {
|
|
140
|
-
condition: match[1].trim(),
|
|
141
|
-
errorMessage: match[2].replace(/\\'/g, "'") // Unescape quotes
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { GridComponentSchema } from '../FormBuilder/types/FormSchema';
|
|
3
|
-
/**
|
|
4
|
-
* @private
|
|
5
|
-
*/
|
|
6
|
-
export interface DataGridRef {
|
|
7
|
-
getGridData: () => Record<string, any>[];
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* @private
|
|
11
|
-
*/
|
|
12
|
-
export interface DataGridComponentProps extends GridComponentSchema {
|
|
13
|
-
isPreviewMode?: boolean;
|
|
14
|
-
onDataChange?: (data: Record<string, any>[]) => void;
|
|
15
|
-
enableRtl?: boolean;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* @private
|
|
19
|
-
*/
|
|
20
|
-
export declare const DataGridComponent: React.ForwardRefExoticComponent<DataGridComponentProps & React.RefAttributes<DataGridRef>>;
|
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useImperativeHandle, useRef, useState, useCallback, useMemo, useEffect } from 'react';
|
|
3
|
-
import { GridComponent, ColumnsDirective, ColumnDirective, Inject, Toolbar, Edit, Page, Filter, Resize, Sort, } from '@syncfusion/ej2-react-grids';
|
|
4
|
-
import { useGridExpressions } from './expressions/useGridExpressions';
|
|
5
|
-
import { CustomValidationEngine } from './CustomValidationEngine';
|
|
6
|
-
(() => {
|
|
7
|
-
const filterPrefix = '[EJ2Grid.Warning]';
|
|
8
|
-
const _origWarn = console.warn;
|
|
9
|
-
const _origLog = console.log;
|
|
10
|
-
const _origError = console.error;
|
|
11
|
-
const makeFiltered = (orig) => (...args) => {
|
|
12
|
-
const first = args[0];
|
|
13
|
-
if (typeof first === 'string' && first.includes(filterPrefix))
|
|
14
|
-
return;
|
|
15
|
-
orig.apply(console, args);
|
|
16
|
-
};
|
|
17
|
-
// Apply only once
|
|
18
|
-
if (!console.__ej2WarnsFiltered) {
|
|
19
|
-
console.warn = makeFiltered(_origWarn);
|
|
20
|
-
console.log = makeFiltered(_origLog);
|
|
21
|
-
console.error = makeFiltered(_origError);
|
|
22
|
-
console.__ej2WarnsFiltered = true;
|
|
23
|
-
}
|
|
24
|
-
})();
|
|
25
|
-
/**
|
|
26
|
-
* @private
|
|
27
|
-
*/
|
|
28
|
-
export const DataGridComponent = React.forwardRef(({ id, columns, dataSource = [], height = '200px', width = '100%', locale, cssClass, pageSize = 6, allowPaging = true, allowAdding = true, allowEditing = true, allowDeleting = true, allowFiltering = false, onDataChange, isPreviewMode, enableRtl }, ref) => {
|
|
29
|
-
// Internal state: maintain current grid data
|
|
30
|
-
const [_currentData, setCurrentData] = useState(Array.isArray(dataSource) ? dataSource : []);
|
|
31
|
-
const gridRef = useRef(null);
|
|
32
|
-
const { evaluateRowExpressions, extractCalculatedColumns } = useGridExpressions();
|
|
33
|
-
const validationEngine = useRef(new CustomValidationEngine()).current;
|
|
34
|
-
const calculatedColumns = useMemo(() => extractCalculatedColumns(columns || []), [columns, extractCalculatedColumns]);
|
|
35
|
-
const hasExpressions = calculatedColumns.length > 0;
|
|
36
|
-
/**
|
|
37
|
-
* Detect column definition changes and refresh grid
|
|
38
|
-
* This ensures that changes to headerText, type, width, etc. are immediately reflected
|
|
39
|
-
* Only enabled in preview mode to avoid issues in the main form builder view
|
|
40
|
-
*/
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (gridRef.current) {
|
|
43
|
-
if (columns && !(columns.length > 0)) {
|
|
44
|
-
gridRef.current.columns = [];
|
|
45
|
-
}
|
|
46
|
-
else if (gridRef.current.columns.length === 0 && columns && columns.length == 1) {
|
|
47
|
-
gridRef.current.columns = columns;
|
|
48
|
-
}
|
|
49
|
-
setTimeout(() => {
|
|
50
|
-
if (gridRef.current?.refresh && !isPreviewMode) {
|
|
51
|
-
if (dataSource && Array.isArray(dataSource) && dataSource.length > 0 && !hasExpressions) {
|
|
52
|
-
gridRef.current.dataSource = dataSource;
|
|
53
|
-
}
|
|
54
|
-
gridRef.current.refresh();
|
|
55
|
-
}
|
|
56
|
-
}, 10);
|
|
57
|
-
}
|
|
58
|
-
}, [columns, allowAdding, allowDeleting, allowEditing, allowPaging, pageSize, allowFiltering, isPreviewMode]);
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
const normalized = Array.isArray(dataSource) ? dataSource : [];
|
|
61
|
-
if (hasExpressions && normalized.length > 0) {
|
|
62
|
-
// Calculate expressions for initial data
|
|
63
|
-
const calculated = normalized.map((row) => {
|
|
64
|
-
const result = evaluateRowExpressions(row, columns || []);
|
|
65
|
-
return { ...row, ...result };
|
|
66
|
-
});
|
|
67
|
-
setCurrentData(calculated);
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
setCurrentData(normalized);
|
|
71
|
-
}
|
|
72
|
-
}, [dataSource, hasExpressions, columns, evaluateRowExpressions]);
|
|
73
|
-
/**
|
|
74
|
-
* Expose getGridData() via ref - returns current grid data for form submission
|
|
75
|
-
*/
|
|
76
|
-
useImperativeHandle(ref, () => ({
|
|
77
|
-
getGridData: () => _currentData,
|
|
78
|
-
gridRef
|
|
79
|
-
}), [_currentData]);
|
|
80
|
-
const mapCustomValidationToSyncfusion = useCallback((col) => {
|
|
81
|
-
if (!col.customValidation || col.customValidation.length === 0) {
|
|
82
|
-
return undefined;
|
|
83
|
-
}
|
|
84
|
-
// Return a custom validation function that receives the field value
|
|
85
|
-
return (value) => {
|
|
86
|
-
// Get the current form instance during edit (similar to grid-example pattern)
|
|
87
|
-
const formObj = gridRef.current?.editModule?.formObj;
|
|
88
|
-
if (!formObj)
|
|
89
|
-
return true; // Form not available, skip validation
|
|
90
|
-
// Build row context from current form values
|
|
91
|
-
const rowContext = {};
|
|
92
|
-
(columns || []).forEach((gridCol) => {
|
|
93
|
-
const input = formObj.getInputElement(gridCol.field);
|
|
94
|
-
if (input) {
|
|
95
|
-
const value = input.value;
|
|
96
|
-
rowContext[gridCol.field] = gridCol.type === 'number' ? parseInt(value, 10) : value;
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
// Evaluate all custom validation rules for this column
|
|
100
|
-
for (const rule of col.customValidation) {
|
|
101
|
-
if (!rule.expression)
|
|
102
|
-
continue;
|
|
103
|
-
const fieldValue = col.type === 'number' ? parseInt(value.value, 10) : value.value;
|
|
104
|
-
const result = validationEngine.validate(rule.expression, fieldValue, rowContext);
|
|
105
|
-
// If validation fails, return error message
|
|
106
|
-
return result === true;
|
|
107
|
-
}
|
|
108
|
-
return null; // All validations passed
|
|
109
|
-
};
|
|
110
|
-
}, [validationEngine, columns, gridRef]);
|
|
111
|
-
/**
|
|
112
|
-
* Create edit params with expression calculation callback
|
|
113
|
-
* Attaches to columns that have dependencies
|
|
114
|
-
*/
|
|
115
|
-
const createEditParams = useCallback((col) => {
|
|
116
|
-
if (!hasExpressions)
|
|
117
|
-
return undefined;
|
|
118
|
-
// Check if any calculated column depends on this field
|
|
119
|
-
const hasDependents = calculatedColumns.some((calcCol) => {
|
|
120
|
-
if (!calcCol.expression)
|
|
121
|
-
return false;
|
|
122
|
-
return calcCol.expression.includes(`{${col.field}}`);
|
|
123
|
-
});
|
|
124
|
-
if (!hasDependents)
|
|
125
|
-
return undefined;
|
|
126
|
-
// Return edit params with change callback
|
|
127
|
-
return {
|
|
128
|
-
params: {
|
|
129
|
-
change: () => {
|
|
130
|
-
// Get form element and grid reference
|
|
131
|
-
if (!gridRef.current?.element)
|
|
132
|
-
return;
|
|
133
|
-
const form = gridRef.current.element.querySelector('form');
|
|
134
|
-
if (!form || !form.ej2_instances || !form.ej2_instances[0])
|
|
135
|
-
return;
|
|
136
|
-
const formInstance = form.ej2_instances[0];
|
|
137
|
-
// Update all calculated columns
|
|
138
|
-
calculatedColumns.forEach((calcCol) => {
|
|
139
|
-
const input = formInstance.getInputElement(calcCol.field);
|
|
140
|
-
if (!input)
|
|
141
|
-
return;
|
|
142
|
-
try {
|
|
143
|
-
// Collect current form values
|
|
144
|
-
const rowValues = {};
|
|
145
|
-
columns?.forEach((col) => {
|
|
146
|
-
const fieldInput = formInstance.getInputElement(col.field);
|
|
147
|
-
if (fieldInput) {
|
|
148
|
-
rowValues[col.field] = fieldInput.value;
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
// Evaluate expression
|
|
152
|
-
const result = evaluateRowExpressions(rowValues, columns || []);
|
|
153
|
-
const calculatedValue = result[calcCol.field];
|
|
154
|
-
// Update UI
|
|
155
|
-
if (calculatedValue !== undefined && calculatedValue !== null) {
|
|
156
|
-
if (calcCol.type === 'boolean') {
|
|
157
|
-
input.checked = !!calculatedValue;
|
|
158
|
-
}
|
|
159
|
-
else if (calcCol.type === 'number') {
|
|
160
|
-
const wrapper = input.closest('.e-control-wrapper');
|
|
161
|
-
const numericInput = wrapper?.querySelector('input.e-control:not([type="hidden"])');
|
|
162
|
-
if (numericInput?.ej2_instances?.[0]) {
|
|
163
|
-
numericInput.ej2_instances[0].value = calculatedValue;
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
input.value = calculatedValue;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
else if (calcCol.type === 'date') {
|
|
170
|
-
input.ej2_instances[0].value = new Date(calculatedValue);
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
input.value = calculatedValue;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
catch (error) {
|
|
178
|
-
console.warn(`Failed to calculate ${calcCol.field}:`, error);
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
}, [hasExpressions, calculatedColumns, columns, evaluateRowExpressions]);
|
|
185
|
-
/**
|
|
186
|
-
* Handle Syncfusion grid action events (add/edit/delete)
|
|
187
|
-
* Update _currentData state when rows are modified
|
|
188
|
-
*/
|
|
189
|
-
const handleActionComplete = useCallback((args) => {
|
|
190
|
-
if (!gridRef.current)
|
|
191
|
-
return;
|
|
192
|
-
const eventType = args.requestType;
|
|
193
|
-
// Handle different action types
|
|
194
|
-
switch (eventType) {
|
|
195
|
-
case 'save':
|
|
196
|
-
case 'delete':
|
|
197
|
-
case 'add':
|
|
198
|
-
// After any data modification, sync grid data to state
|
|
199
|
-
// Use dataSource directly as it's the current working data in Syncfusion
|
|
200
|
-
if (gridRef.current.dataSource) {
|
|
201
|
-
const updatedData = Array.isArray(gridRef.current.dataSource)
|
|
202
|
-
? gridRef.current.dataSource
|
|
203
|
-
: [];
|
|
204
|
-
setCurrentData(updatedData);
|
|
205
|
-
onDataChange?.(updatedData);
|
|
206
|
-
}
|
|
207
|
-
break;
|
|
208
|
-
default:
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
|
-
}, [onDataChange]);
|
|
212
|
-
/**
|
|
213
|
-
* Build toolbar array dynamically based on allowAdding/Editing/Deleting
|
|
214
|
-
* Default toolbar includes: Add, Edit, Delete, Update, Cancel, ExcelExport, Search
|
|
215
|
-
*/
|
|
216
|
-
const buildToolbar = useCallback(() => {
|
|
217
|
-
const toolbarItems = [];
|
|
218
|
-
if (allowAdding) {
|
|
219
|
-
toolbarItems.push('Add');
|
|
220
|
-
}
|
|
221
|
-
if (allowEditing) {
|
|
222
|
-
toolbarItems.push('Edit');
|
|
223
|
-
}
|
|
224
|
-
if (allowDeleting) {
|
|
225
|
-
toolbarItems.push('Delete');
|
|
226
|
-
}
|
|
227
|
-
// Always include Update and Cancel for inline editing flow
|
|
228
|
-
toolbarItems.push('Update', 'Cancel');
|
|
229
|
-
return toolbarItems;
|
|
230
|
-
}, [allowAdding, allowEditing, allowDeleting]);
|
|
231
|
-
/**
|
|
232
|
-
* Map validation rules from GridColumn.validationRules to Syncfusion format
|
|
233
|
-
* Syncfusion ValidationRules type supports:
|
|
234
|
-
* - required: boolean
|
|
235
|
-
* - min/max: number (for numeric types)
|
|
236
|
-
* - minLength/maxLength: number (for string types)
|
|
237
|
-
*/
|
|
238
|
-
const mapValidationRules = useCallback((col) => {
|
|
239
|
-
if (!col.validationRules) {
|
|
240
|
-
return undefined;
|
|
241
|
-
}
|
|
242
|
-
return col.validationRules;
|
|
243
|
-
}, []);
|
|
244
|
-
/**
|
|
245
|
-
* Memoize toolbar to prevent unnecessary re-renders
|
|
246
|
-
*/
|
|
247
|
-
const toolbarConfig = useMemo(() => buildToolbar(), [buildToolbar]);
|
|
248
|
-
return (_jsx("div", { className: "datagrid-wrapper", style: { width, height: 'auto' }, children: _jsx("div", { className: "datagrid-grid", children: _jsxs(GridComponent, { ref: gridRef, id: id, dataSource: _currentData, allowPaging: allowPaging, filterSettings: { mode: "Immediate" }, pageSettings: { pageSize }, editSettings: {
|
|
249
|
-
allowEditing,
|
|
250
|
-
allowAdding,
|
|
251
|
-
allowDeleting,
|
|
252
|
-
mode: 'Normal',
|
|
253
|
-
}, enableRtl: enableRtl, locale: locale || 'en-US', cssClass: cssClass, toolbar: toolbarConfig, actionComplete: handleActionComplete, height: typeof height === 'string' ? height : `${height}px`, width: typeof width === 'string' ? width : `${width}px`, allowSorting: true, allowFiltering: allowFiltering, allowSelection: true, children: [_jsx(ColumnsDirective, { children: (columns || []).map((col) => {
|
|
254
|
-
const validationRules = mapValidationRules(col);
|
|
255
|
-
const customValidator = mapCustomValidationToSyncfusion(col);
|
|
256
|
-
// Merge standard and custom validation rules
|
|
257
|
-
const mergedValidationRules = validationRules ? { ...validationRules } : {};
|
|
258
|
-
// Add custom validator to validationRules if custom validation exists
|
|
259
|
-
if (customValidator) {
|
|
260
|
-
// Extract error message from custom validation expression
|
|
261
|
-
const errorMessage = col.customValidation?.[0]?.expression
|
|
262
|
-
? validationEngine.parseExpression(col.customValidation[0].expression)?.errorMessage || 'Validation failed'
|
|
263
|
-
: 'Validation failed';
|
|
264
|
-
mergedValidationRules.required = [true, errorMessage];
|
|
265
|
-
mergedValidationRules.custom = [
|
|
266
|
-
customValidator,
|
|
267
|
-
errorMessage
|
|
268
|
-
];
|
|
269
|
-
}
|
|
270
|
-
return (_jsx(ColumnDirective, { field: col.field, headerText: col.headerText, type: col.type || 'string', isPrimaryKey: col.isPrimaryKey || false, width: col.width, format: col.type === 'date' ? (col.format || 'MM/dd/yyyy') : col.format, editType: col.editType, allowEditing: col.allowEditing !== false && !col.expression, validationRules: mergedValidationRules, edit: createEditParams(col) }, col.field));
|
|
271
|
-
}) }), _jsx(Inject, { services: [Edit, Toolbar, Page, Resize, Sort, Filter] })] }) }) }));
|
|
272
|
-
});
|
|
273
|
-
DataGridComponent.displayName = 'DataGridComponent';
|