@syncfusion/ej2-react-form-builder 0.1.0-beta → 35.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +81 -36
  2. package/diConfig.json +148 -0
  3. package/dist/ej2-react-form-builder.min.js +10 -0
  4. package/dist/ej2-react-form-builder.umd.min.js +11 -0
  5. package/dist/ej2-react-form-builder.umd.min.js.map +1 -0
  6. package/dist/es6/ej2-react-form-builder.es2015.js +60 -0
  7. package/dist/es6/ej2-react-form-builder.es2015.js.map +1 -0
  8. package/form-builder.d.ts +4 -0
  9. package/form-builder.js +4 -0
  10. package/index.d.ts +2 -4
  11. package/index.js +2 -4
  12. package/license +6 -13
  13. package/package.json +19 -43
  14. package/src/form-builder/formbuilder.component.d.ts +37 -0
  15. package/src/form-builder/formbuilder.component.js +50 -0
  16. package/src/form-builder/index.d.ts +2 -0
  17. package/src/form-builder/index.js +2 -0
  18. package/src/form-builder/toolboxitems-directive.d.ts +28 -0
  19. package/src/form-builder/toolboxitems-directive.js +47 -0
  20. package/src/global.js +1 -0
  21. package/src/index.d.ts +2 -16
  22. package/src/index.js +2 -6
  23. package/Common/CheckboxGroup.d.ts +0 -13
  24. package/Common/CheckboxGroup.js +0 -50
  25. package/Common/ConditionalRuleEngine.d.ts +0 -296
  26. package/Common/ConditionalRuleEngine.js +0 -566
  27. package/Common/CustomTabComponent.d.ts +0 -17
  28. package/Common/CustomTabComponent.js +0 -30
  29. package/Common/CustomValidationEngine.d.ts +0 -58
  30. package/Common/CustomValidationEngine.js +0 -146
  31. package/Common/DataGridComponent.d.ts +0 -20
  32. package/Common/DataGridComponent.js +0 -273
  33. package/Common/FormValidator.d.ts +0 -485
  34. package/Common/FormValidator.js +0 -575
  35. package/Common/MinMaxRuleEngine.d.ts +0 -105
  36. package/Common/MinMaxRuleEngine.js +0 -365
  37. package/Common/StaticHtmlRenderer.d.ts +0 -14
  38. package/Common/StaticHtmlRenderer.js +0 -24
  39. package/Common/expressions/DependencyTracker.d.ts +0 -30
  40. package/Common/expressions/DependencyTracker.js +0 -128
  41. package/Common/expressions/ExpressionEngine.d.ts +0 -95
  42. package/Common/expressions/ExpressionEngine.js +0 -506
  43. package/Common/expressions/ExpressionParser.d.ts +0 -41
  44. package/Common/expressions/ExpressionParser.js +0 -269
  45. package/Common/expressions/useGridExpressions.d.ts +0 -12
  46. package/Common/expressions/useGridExpressions.js +0 -71
  47. package/Common/globalFormId.d.ts +0 -26
  48. package/Common/globalFormId.js +0 -45
  49. package/Common/json-converter.d.ts +0 -444
  50. package/Common/json-converter.js +0 -1184
  51. package/Common/parser.d.ts +0 -98
  52. package/Common/parser.js +0 -753
  53. package/Common/utils.d.ts +0 -130
  54. package/Common/utils.js +0 -574
  55. package/src/FormBuilder.d.ts +0 -211
  56. package/src/FormBuilder.js +0 -1299
  57. package/src/components/Database/ConnectionForm.d.ts +0 -8
  58. package/src/components/Database/ConnectionForm.js +0 -28
  59. package/src/components/TopBar.d.ts +0 -10
  60. package/src/components/TopBar.js +0 -7
  61. package/src/components/icons/ComponentIcons.d.ts +0 -44
  62. package/src/components/icons/ComponentIcons.js +0 -40
  63. package/src/components/layout/FormFieldWrapper.d.ts +0 -41
  64. package/src/components/layout/FormFieldWrapper.js +0 -112
  65. package/src/components/layout/LeftPane.d.ts +0 -23
  66. package/src/components/layout/LeftPane.js +0 -310
  67. package/src/components/layout/ListBoxPane.d.ts +0 -24
  68. package/src/components/layout/ListBoxPane.js +0 -94
  69. package/src/components/layout/MainSection.d.ts +0 -39
  70. package/src/components/layout/MainSection.js +0 -1766
  71. package/src/components/layout/Preview.d.ts +0 -12
  72. package/src/components/layout/Preview.js +0 -337
  73. package/src/components/layout/RightPane.d.ts +0 -22
  74. package/src/components/layout/RightPane.js +0 -370
  75. package/src/components/theme/ThemeSwitcher.d.ts +0 -14
  76. package/src/components/theme/ThemeSwitcher.js +0 -24
  77. package/src/components/theme/theme-constant.d.ts +0 -37
  78. package/src/components/theme/theme-constant.js +0 -23
  79. package/src/config/component-properties.json +0 -4929
  80. package/src/config/form-setting.json +0 -56
  81. package/src/config/locale.d.ts +0 -449
  82. package/src/config/locale.js +0 -449
  83. package/src/context/FormSchemaContext.d.ts +0 -32
  84. package/src/context/FormSchemaContext.js +0 -155
  85. package/src/context/LocalizationContext.d.ts +0 -27
  86. package/src/context/LocalizationContext.js +0 -43
  87. package/src/context/ThemeContext.d.ts +0 -23
  88. package/src/context/ThemeContext.js +0 -161
  89. package/src/context/contexts.d.ts +0 -6
  90. package/src/context/contexts.js +0 -6
  91. package/src/context/defaultFormSchema.d.ts +0 -6
  92. package/src/context/defaultFormSchema.js +0 -20
  93. package/src/defaultPalette.d.ts +0 -9
  94. package/src/defaultPalette.js +0 -45
  95. package/src/defaultTemplate.d.ts +0 -3
  96. package/src/defaultTemplate.js +0 -185
  97. package/src/import/schemaImportUtils.d.ts +0 -24
  98. package/src/import/schemaImportUtils.js +0 -121
  99. package/src/types/ActionButtons.d.ts +0 -44
  100. package/src/types/ActionButtons.js +0 -27
  101. package/src/types/ComponentProperties.d.ts +0 -33
  102. package/src/types/ComponentProperties.js +0 -2
  103. package/src/types/FormSchema.d.ts +0 -585
  104. package/src/types/FormSchema.js +0 -147
  105. package/src/types/connection.d.ts +0 -19
  106. package/src/types/connection.js +0 -9
  107. package/src/utils/AttributesEditor.d.ts +0 -13
  108. package/src/utils/AttributesEditor.js +0 -117
  109. package/src/utils/ButtonGroupEditor.d.ts +0 -15
  110. package/src/utils/ButtonGroupEditor.js +0 -141
  111. package/src/utils/ChoiceBasedFieldEditor.d.ts +0 -16
  112. package/src/utils/ChoiceBasedFieldEditor.js +0 -87
  113. package/src/utils/ClipboardHelper.d.ts +0 -26
  114. package/src/utils/ClipboardHelper.js +0 -83
  115. package/src/utils/ColumnBuilder.d.ts +0 -11
  116. package/src/utils/ColumnBuilder.js +0 -153
  117. package/src/utils/ColumnSpanEditor.d.ts +0 -8
  118. package/src/utils/ColumnSpanEditor.js +0 -98
  119. package/src/utils/ConditionDataEditor.d.ts +0 -29
  120. package/src/utils/ConditionDataEditor.js +0 -177
  121. package/src/utils/ConditionalEditorUtils.d.ts +0 -27
  122. package/src/utils/ConditionalEditorUtils.js +0 -310
  123. package/src/utils/ConditionsEditor.d.ts +0 -20
  124. package/src/utils/ConditionsEditor.js +0 -571
  125. package/src/utils/CustomAccordion.d.ts +0 -13
  126. package/src/utils/CustomAccordion.js +0 -38
  127. package/src/utils/CustomValidationEditor.d.ts +0 -11
  128. package/src/utils/CustomValidationEditor.js +0 -208
  129. package/src/utils/DataSourceCollector.d.ts +0 -3
  130. package/src/utils/DataSourceCollector.js +0 -252
  131. package/src/utils/ExpressionEditor.d.ts +0 -13
  132. package/src/utils/ExpressionEditor.js +0 -99
  133. package/src/utils/FormSettingsPanel.d.ts +0 -9
  134. package/src/utils/FormSettingsPanel.js +0 -60
  135. package/src/utils/LookupConfig.d.ts +0 -11
  136. package/src/utils/LookupConfig.js +0 -159
  137. package/src/utils/MinMaxValueEditor.d.ts +0 -25
  138. package/src/utils/MinMaxValueEditor.js +0 -188
  139. package/src/utils/OptionsEditor.d.ts +0 -8
  140. package/src/utils/OptionsEditor.js +0 -79
  141. package/src/utils/PropertyRenderer.d.ts +0 -22
  142. package/src/utils/PropertyRenderer.js +0 -210
  143. package/src/utils/ValueRenderer.d.ts +0 -2
  144. package/src/utils/ValueRenderer.js +0 -91
  145. package/src/utils/ej2DbAdaptor.d.ts +0 -6
  146. package/src/utils/ej2DbAdaptor.js +0 -38
  147. package/src/utils/mappingHeuristics.d.ts +0 -10
  148. package/src/utils/mappingHeuristics.js +0 -33
  149. package/src/utils/renderComponent.d.ts +0 -18
  150. package/src/utils/renderComponent.js +0 -300
  151. package/styles/tailwind3.css +0 -67
  152. package/styles/themes/action-buttons.css +0 -110
  153. package/styles/themes/datagrid.css +0 -380
  154. package/styles/themes/drag-reorder.css +0 -248
  155. package/styles/themes/import-dialog.css +0 -292
  156. package/styles/themes/index.css +0 -658
  157. package/styles/themes/left-pane.css +0 -253
  158. package/styles/themes/options-editor.css +0 -63
  159. package/styles/themes/preview.css +0 -702
  160. package/styles/themes/property-dialog.css +0 -371
@@ -1,208 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useState, useRef, useEffect } from 'react';
3
- import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';
4
- import { CustomValidationEngine } from '../../Common/CustomValidationEngine';
5
- import { ButtonComponent, RadioButtonComponent } from '@syncfusion/ej2-react-buttons';
6
- import { useLocalization } from '../context/LocalizationContext';
7
- export const CustomValidationEditor = ({ componentFields, excludeFieldId, values, existingRules = [], onChange }) => {
8
- const validationEngine = useRef(new CustomValidationEngine()).current;
9
- const [errorMessage, setErrorMessage] = useState('Please enter a valid value.');
10
- const [errorMessageError, setErrorMessageError] = useState('');
11
- const [logicalOp, setLogicalOp] = useState('and');
12
- const [rules, setRules] = useState([]);
13
- const { l10n } = useLocalization();
14
- // Build available field names
15
- const availableFields = componentFields
16
- .filter(c => c.name !== excludeFieldId)
17
- .map(c => c.name);
18
- // Initialize from existing rules - parse multiple conditions
19
- useEffect(() => {
20
- if (existingRules.length > 0 && existingRules[0].expression) {
21
- const parsed = validationEngine.parseExpression(existingRules[0].expression);
22
- if (parsed) {
23
- setErrorMessage(parsed.errorMessage);
24
- // Detect logical operator (AND or OR) and split conditions
25
- const condition = parsed.condition;
26
- let detectedOp = 'and';
27
- let splitConditions = [];
28
- if (condition.includes(' || ')) {
29
- detectedOp = 'or';
30
- // Split by || but be careful with parentheses
31
- splitConditions = splitConditionsByOperator(condition, '||');
32
- }
33
- else if (condition.includes(' && ')) {
34
- detectedOp = 'and';
35
- splitConditions = splitConditionsByOperator(condition, '&&');
36
- }
37
- else {
38
- // Single condition
39
- splitConditions = [condition];
40
- }
41
- setLogicalOp(detectedOp);
42
- // Create rule objects for each condition
43
- const newRules = splitConditions.map((cond, idx) => ({
44
- id: (idx + 1).toString(),
45
- condition: cond.trim(),
46
- errors: []
47
- }));
48
- setRules(newRules.length > 0 ? newRules : [{ id: '1', condition: '', errors: [] }]);
49
- }
50
- }
51
- }, []);
52
- // Helper to split conditions by operator while respecting parentheses
53
- const splitConditionsByOperator = (expression, operator) => {
54
- const conditions = [];
55
- let current = '';
56
- let depth = 0;
57
- for (let i = 0; i < expression.length; i++) {
58
- const char = expression[i];
59
- if (char === '(')
60
- depth++;
61
- else if (char === ')')
62
- depth--;
63
- // Check for operator at depth 0
64
- if (depth === 0 && expression.substr(i, operator.length) === operator) {
65
- conditions.push(current.trim());
66
- current = '';
67
- i += operator.length - 1;
68
- }
69
- else {
70
- current += char;
71
- }
72
- }
73
- if (current.trim()) {
74
- conditions.push(current.trim());
75
- }
76
- return conditions.map(c => {
77
- // Remove outer parentheses if present
78
- c = c.trim();
79
- if (c.startsWith('(') && c.endsWith(')')) {
80
- c = c.slice(1, -1).trim();
81
- }
82
- return c;
83
- });
84
- };
85
- const handleConditionChange = (id, condition) => {
86
- const errors = validationEngine.validateConditionSyntax(condition, availableFields);
87
- setRules(prev => {
88
- const updated = prev.map(r => r.id === id ? { ...r, condition, errors } : r);
89
- notifyParent(updated, errorMessage, logicalOp);
90
- return updated;
91
- });
92
- };
93
- const handleErrorMessageChange = (e) => {
94
- const msg = e.value || '';
95
- setErrorMessage(msg);
96
- notifyParent(rules, msg, logicalOp);
97
- };
98
- const handleLogicalOpChange = (op) => {
99
- setLogicalOp(op);
100
- notifyParent(rules, errorMessage, op);
101
- };
102
- const addRule = () => {
103
- const newId = Date.now().toString();
104
- setRules(prev => [
105
- ...prev,
106
- { id: newId, condition: '', errors: [] }
107
- ]);
108
- };
109
- const removeRule = (id) => {
110
- if (rules.length > 1) {
111
- setRules(prev => {
112
- const updated = prev.filter(r => r.id !== id);
113
- notifyParent(updated, errorMessage, logicalOp);
114
- return updated;
115
- });
116
- }
117
- else {
118
- clearAll();
119
- }
120
- };
121
- const clearAll = () => {
122
- // Reset to initial state
123
- setErrorMessage('');
124
- setErrorMessageError('');
125
- setLogicalOp('and');
126
- setRules([]);
127
- // Notify parent to remove from schema
128
- onChange([]);
129
- };
130
- const notifyParent = (currentRules, msg, op) => {
131
- const validConditions = currentRules
132
- .filter(r => r.condition.trim() && r.errors.length === 0)
133
- .map(r => {
134
- let cond = r.condition.trim();
135
- // Strip outer parentheses to normalize
136
- while (cond.startsWith('(') && cond.endsWith(')')) {
137
- const inner = cond.slice(1, -1).trim();
138
- // Check if outer parens are actually matched
139
- let depth = 0;
140
- let isMatched = true;
141
- for (let i = 0; i < inner.length; i++) {
142
- if (inner[i] === '(')
143
- depth++;
144
- else if (inner[i] === ')')
145
- depth--;
146
- if (depth < 0) {
147
- isMatched = false;
148
- break;
149
- }
150
- }
151
- if (isMatched && depth === 0) {
152
- cond = inner;
153
- }
154
- else {
155
- break;
156
- }
157
- }
158
- return cond;
159
- });
160
- // Only notify if we have at least one valid condition and error message
161
- if (validConditions.length > 0 && msg) {
162
- // Combine conditions with && or ||
163
- const operator = op === 'and' ? ' && ' : ' || ';
164
- // Wrap each condition in parentheses (only one layer)
165
- const wrappedConditions = validConditions.map(cond => `(${cond})`);
166
- const combinedCondition = wrappedConditions.join(` ${operator} `);
167
- const fullExpression = validationEngine.buildExpression(combinedCondition, msg);
168
- onChange([{
169
- condition: undefined,
170
- expression: fullExpression
171
- }]);
172
- }
173
- };
174
- return (_jsxs("div", { className: "custom-validation-editor", role: "group", "aria-label": l10n.getConstant(values.label), children: [_jsxs("div", { style: { display: 'flex', justifyContent: "space-between" }, children: [_jsx("label", { className: "property-label", style: { fontWeight: '600', marginBottom: "0.5rem", fontSize: '0.875rem' }, children: l10n.getConstant(values.label) }), _jsx("div", { style: { marginBottom: "0.5rem" }, children: _jsx(ButtonComponent, { onClick: addRule, iconCss: 'e-icons e-plus', cssClass: "e-flat", title: "Add Condition", "aria-label": l10n.getConstant('addHeader'), children: l10n.getConstant('addHeader') }) })] }), _jsx("div", { className: "custom-validation-description", style: { marginBottom: "0.75rem" }, children: _jsx("p", { className: "property-description", children: l10n.getConstant('customValidationDescription') }) }), _jsxs("div", { className: "e-group-container", "aria-labelledby": "custom-validation-heading", "aria-describedby": "custom-validation-description", children: [rules.length > 1 && (_jsx("div", { className: "e-group-header", children: _jsxs("div", { className: "e-logical-op-radio-group", role: "radiogroup", "aria-label": "Logical Operator", style: { display: 'flex', flexDirection: 'column', gap: '1.5rem' }, children: [_jsx(RadioButtonComponent, { id: "qb-and-rules", name: "qb-logical-op", value: "and", label: "AND", checked: logicalOp === 'and', labelPosition: "After", change: (e) => {
175
- if (e)
176
- handleLogicalOpChange(e.value);
177
- } }), _jsx(RadioButtonComponent, { id: "qb-or-rules", name: "qb-logical-op", value: "or", label: "OR", checked: logicalOp === 'or', labelPosition: "After", change: (e) => {
178
- if (e)
179
- handleLogicalOpChange(e.value);
180
- } })] }) })), _jsx("div", { className: "e-group-body", children: _jsx("div", { className: "e-rule-list", children: rules.map((rule, idx) => (_jsxs(React.Fragment, { children: [idx > 0 && (_jsxs("div", { "aria-hidden": "true", style: {
181
- display: 'flex',
182
- alignItems: 'center',
183
- gap: '8px',
184
- margin: '8px 0'
185
- }, children: [_jsx("div", { style: { flex: 1, height: '1px', background: 'rgb(var(--sf-color-line-color))' } }), _jsx("span", { style: {
186
- border: '1px solid rgb(var(--sf-color-line-color))',
187
- borderRadius: '9999px',
188
- padding: '2px 5px',
189
- fontSize: '10px',
190
- lineHeight: 1.5,
191
- }, children: logicalOp === 'and' ? 'AND' : 'OR' }), _jsx("div", { style: { flex: 1, height: '1px', background: 'rgb(var(--sf-color-line-color))' } })] })), _jsxs("div", { className: "e-rule-container e-horizontal-mode", role: "group", "aria-label": `Condition ${idx + 1}`, children: [_jsxs("div", { className: "e-rule-field", children: [_jsx("div", { className: "e-rule-value", children: _jsx("input", { value: rule.condition, onChange: (e) => handleConditionChange(rule.id, e.target.value), placeholder: "(input === {fieldName})", className: "e-input custom-validation-textarea", "aria-label": `Condition ${idx + 1}`, "aria-invalid": rule.errors.length > 0, "aria-describedby": rule.errors.length > 0
192
- ? `condition-errors-${rule.id}`
193
- : undefined }) }), _jsx("div", { children: _jsx(ButtonComponent, { iconCss: 'e-icons e-trash', onClick: () => removeRule(rule.id), title: "Remove this condition", cssClass: "e-small e-flat", "aria-label": `Remove condition ${idx + 1}` }) })] }), rule.errors.length > 0 && (_jsx("div", { className: "custom-validation-field-errors", role: "alert", "aria-live": "polite", children: rule.errors.map((error, errIdx) => (_jsx("div", { className: "e-error", children: error }, errIdx))) }))] })] }, rule.id))) }) })] }), _jsxs("div", { className: "custom-validation-error-message form-group", style: { marginTop: '0.75rem' }, children: [_jsxs("label", { style: { fontWeight: 400, fontSize: '14px' }, children: [l10n.getConstant('validationMessage'), " ", _jsx("span", { style: { color: '#e74c3c' }, children: "*" })] }), _jsx(TextBoxComponent, { placeholder: l10n.getConstant('provideCustomValidationMessage'), value: errorMessage, change: handleErrorMessageChange, blur: (e) => {
194
- if (e.value === '') {
195
- setErrorMessageError(l10n.getConstant('customValidationErrorMessage'));
196
- }
197
- else {
198
- setErrorMessageError('');
199
- }
200
- }, floatLabelType: "Never", cssClass: `custom-validation-error-input ${errorMessageError ? 'e-error' : ''}`, htmlAttributes: {
201
- 'aria-labelledby': 'validation-message-label',
202
- 'aria-required': 'true',
203
- 'aria-invalid': errorMessageError ? 'true' : 'false',
204
- ...(errorMessageError && {
205
- 'aria-describedby': 'validation-message-error'
206
- })
207
- } }), errorMessageError && (_jsx("div", { className: "e-error", style: { marginTop: '6px' }, role: "alert", "aria-live": "polite", children: errorMessageError }))] })] }));
208
- };
@@ -1,3 +0,0 @@
1
- import React from 'react';
2
- import type { DataSourceCollectorProps } from '../types/FormSchema';
3
- export declare const DataSourceCollector: React.FC<DataSourceCollectorProps>;
@@ -1,252 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useState, useEffect, useCallback } from 'react';
3
- import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';
4
- import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
5
- import { ButtonComponent, RadioButtonComponent, SwitchComponent } from '@syncfusion/ej2-react-buttons';
6
- import { useLocalization } from '../context/LocalizationContext';
7
- import { OptionsEditor } from './OptionsEditor';
8
- import { AccordionWrapper } from './CustomAccordion';
9
- export const DataSourceCollector = ({ value, onChange, type = 'options', datakey, isAccordion = false }) => {
10
- const { l10n } = useLocalization();
11
- const isGridType = type === 'grid';
12
- const defaultType = isGridType ? 'raw_data' : 'options';
13
- const [dataSourceType, setDataSourceType] = useState(defaultType);
14
- const [rawJsonData, setRawJsonData] = useState(JSON.stringify(value));
15
- const [optionData, setOptionData] = useState(null);
16
- const [formNames, setFormNames] = useState([]);
17
- const [selectedFormName, setSelectedFormName] = useState(typeof value === 'object' && (value?.formName) ? value?.formName : '');
18
- const [isLoadingFormNames, setIsLoadingFormNames] = useState(true);
19
- const [lookupErrorMessage, setLookupErrorMessage] = useState('');
20
- const [remoteUrl, setRemoteUrl] = useState('');
21
- const [headers, setHeaders] = useState([]);
22
- const [dataPath, setDataPath] = useState('');
23
- const [search, setSearch] = useState({ enabled: false, fields: [] });
24
- const [sort, setSort] = useState({ enabled: false, field: '', direction: 'ascending' });
25
- const [filters, setFilters] = useState([]);
26
- const [adaptorType, setAdaptorType] = useState('WebApiAdaptor');
27
- const [take, setTake] = useState(null);
28
- const [skip, setSkip] = useState(null);
29
- const [errorMessage, setErrorMessage] = useState('');
30
- const [successMessage, setSuccessMessage] = useState('');
31
- // Initialize with current value
32
- useEffect(() => {
33
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
34
- setDataSourceType(value.type === 'url' ? 'remote_url' : value.type === 'raw' ? 'raw_data' : (isGridType ? 'raw_data' : 'options'));
35
- if (value.type === 'lookup' && value.formName) {
36
- setDataSourceType('lookup');
37
- setSelectedFormName(value.formName);
38
- }
39
- if (value.url)
40
- setRemoteUrl(value.url);
41
- if (value.headers)
42
- setHeaders(value.headers);
43
- if (value.search)
44
- setSearch(value.search);
45
- if (value.sort)
46
- setSort(value.sort);
47
- if (value.filters)
48
- setFilters(value.filters);
49
- if (value.adaptorType)
50
- setAdaptorType(value.adaptorType);
51
- if (value.take)
52
- setTake(value.take);
53
- if (value.skip)
54
- setSkip(value.skip);
55
- if (value.dataPath)
56
- setDataPath(value.dataPath);
57
- }
58
- else if (Array.isArray(value)) {
59
- setRawJsonData(JSON.stringify(value));
60
- }
61
- }, []);
62
- useEffect(() => {
63
- const fetchFormNames = async () => {
64
- try {
65
- const response = await fetch(/*formNameUrl*/ '');
66
- if (!response.ok) {
67
- throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`);
68
- }
69
- const data = await response.json();
70
- const names = Array.isArray(data) ? data.map((item) => item.name).filter(Boolean) : [];
71
- setFormNames(names);
72
- }
73
- catch (error) {
74
- console.error('Error fetching form names:', error);
75
- setFormNames([]);
76
- }
77
- finally {
78
- setIsLoadingFormNames(false);
79
- }
80
- };
81
- if (isGridType) {
82
- fetchFormNames();
83
- }
84
- }, [isGridType]);
85
- // Filter options based on type
86
- const allDataSourceOptions = [
87
- { text: l10n.getConstant('options'), value: 'options' },
88
- { text: l10n.getConstant('rawData') || 'Raw Data', value: 'raw_data' },
89
- { text: l10n.getConstant('remoteUrl') || 'Remote URL', value: 'remote_url' }
90
- ];
91
- const dataSourceOptions = isGridType
92
- ? allDataSourceOptions.filter(opt => opt.value !== 'options') /*.concat([{ text: l10n.getConstant('lookup') || 'Lookup', value: 'lookup' }])*/
93
- : allDataSourceOptions;
94
- const handleDataSourceTypeChange = (e) => {
95
- setDataSourceType(e.value);
96
- setErrorMessage('');
97
- setSuccessMessage('');
98
- setHeaders([]);
99
- if (e.value !== 'lookup') {
100
- setSelectedFormName('');
101
- setLookupErrorMessage('');
102
- }
103
- };
104
- const handleHeaderKeyChange = (index, newKey) => {
105
- const updatedHeaders = [...headers];
106
- updatedHeaders[index].key = newKey;
107
- setHeaders(updatedHeaders);
108
- };
109
- const handleHeaderValueChange = (index, newValue) => {
110
- const updatedHeaders = [...headers];
111
- updatedHeaders[index].value = newValue;
112
- setHeaders(updatedHeaders);
113
- };
114
- const handleAddHeader = () => {
115
- setHeaders([...headers, { key: '', value: '' }]);
116
- };
117
- const handleRemoveHeader = (index) => {
118
- const updatedHeaders = headers.filter((_, i) => i !== index);
119
- setHeaders(updatedHeaders);
120
- };
121
- const handleRawDataChange = (e) => {
122
- setRawJsonData(e.value);
123
- setErrorMessage('');
124
- try {
125
- const parsed = JSON.parse(e.value);
126
- if (Array.isArray(parsed)) {
127
- onChange(parsed);
128
- }
129
- }
130
- catch (err) {
131
- const errorMsg = err instanceof Error ? err.message : 'Invalid JSON format';
132
- setErrorMessage(l10n.getConstant('invalidJson') || `Invalid JSON: ${errorMsg}`);
133
- }
134
- };
135
- const handleOptionDataChange = (e) => {
136
- onChange(e);
137
- setOptionData(e);
138
- };
139
- const handleSaveUrl = () => {
140
- if (!remoteUrl.trim()) {
141
- setErrorMessage(l10n.getConstant('pleaseEnterUrl') || 'Please enter a URL');
142
- setSuccessMessage('');
143
- onChange([]);
144
- return;
145
- }
146
- // Save URL and query parameters
147
- const config = {
148
- type: 'url',
149
- url: remoteUrl,
150
- headers: headers.filter(h => h.key.trim()),
151
- adaptorType: adaptorType,
152
- dataPath: dataPath || undefined, // Add this line
153
- search: search?.enabled ? search : undefined,
154
- sort: sort?.enabled ? sort : undefined,
155
- filters: filters?.length > 0 ? filters : undefined,
156
- take: take != null && take > 0 ? take : undefined,
157
- skip: skip != null && skip > 0 ? skip : undefined
158
- };
159
- onChange(config);
160
- setErrorMessage('');
161
- setSuccessMessage(l10n.getConstant('urlSavedSuccessfully') || 'URL configuration saved successfully');
162
- };
163
- const handleLookupFormNameChange = useCallback((args) => {
164
- const formName = args.value;
165
- setSelectedFormName(formName);
166
- setLookupErrorMessage('');
167
- if (formName) {
168
- onChange({
169
- type: 'lookup',
170
- formName: formName
171
- });
172
- }
173
- else {
174
- onChange([]);
175
- }
176
- }, [onChange]);
177
- const content = (_jsxs("div", { className: "data-source-collector", children: [_jsxs("div", { className: "data-source-type-selector", role: "radiogroup", "aria-label": l10n.getConstant('dataSource'), style: { marginBottom: "1rem", display: 'flex', flexDirection: 'column', gap: '1rem' }, children: [dataSourceOptions.map((option) => (_jsx(RadioButtonComponent, { id: `ds-${option.value}-${datakey}`, name: `dataSourceType-${datakey}`, value: option.value, label: option.text, checked: dataSourceType === option.value, labelPosition: "After", change: (e) => {
178
- if (e) {
179
- handleDataSourceTypeChange({ value: e.value });
180
- }
181
- } }, `${option.value}`))), _jsx("div", { style: { height: '1px', background: 'rgb(var(--sf-color-line-color))' } })] }, datakey), _jsxs("div", { className: "data-source-content", children: [dataSourceType === 'options' && !isGridType && (_jsx(OptionsEditor, { options: optionData !== null ? optionData : Array.isArray(value) ? value : (value?.data || []), onChange: handleOptionDataChange, type: type })), dataSourceType === 'raw_data' && (_jsxs("div", { className: "raw-data-editor", children: [_jsxs("label", { className: 'property-label', style: { fontWeight: 500, marginBottom: '0.75rem' }, children: [l10n.getConstant('json'), " ", l10n.getConstant('data')] }), _jsx(TextBoxComponent, { value: rawJsonData, placeholder: l10n.getConstant('pasteJsonArrayRecords') || 'e.g., ["Option 1", "Option 2"]', multiline: true, change: handleRawDataChange, floatLabelType: "Never", htmlAttributes: {
182
- 'aria-labelledby': `${datakey}-json-data-label`
183
- } })] })), dataSourceType === 'remote_url' && (_jsxs("div", { className: "remote-url-editor", children: [_jsxs("div", { className: "url-input-group", style: { marginBottom: "1rem" }, children: [_jsx("label", { className: 'property-label', style: { fontWeight: 500, marginBottom: '0.5rem' }, children: l10n.getConstant('endpointUrl') }), _jsx(TextBoxComponent, { value: remoteUrl, placeholder: l10n.getConstant('enterUrl'), change: (e) => {
184
- setRemoteUrl(e.value);
185
- setErrorMessage('');
186
- }, floatLabelType: "Never", htmlAttributes: {
187
- 'aria-labelledby': `${datakey}-endpoint-url-label`
188
- } })] }), _jsxs("div", { className: "data-path-input", style: { marginBottom: "1rem" }, children: [_jsx("div", { className: 'property-label', style: { fontWeight: 500, marginBottom: "0.5rem" }, children: l10n.getConstant('dataPath') }), _jsx(TextBoxComponent, { value: dataPath, placeholder: l10n.getConstant('dataPathPlaceholder'), change: (e) => setDataPath(e.value), floatLabelType: "Never", htmlAttributes: {
189
- 'aria-labelledby': `${datakey}-data-path-label`
190
- } })] }), _jsxs("div", { className: "headers-editor", style: { marginBottom: "0.25rem" }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: "space-between" }, children: [_jsx("div", { className: 'property-label', style: { fontWeight: 500, marginBottom: "0.75rem" }, children: l10n.getConstant('headers') }), _jsx(ButtonComponent, { style: { marginBottom: "0.75rem" }, onClick: handleAddHeader, iconCss: 'e-icons e-plus', cssClass: "e-flat", title: "Add Condition", "aria-label": l10n.getConstant('addHeader'), children: l10n.getConstant('addHeader') })] }), headers.map((header, index) => (_jsxs("div", { style: { display: "flex", gap: "0.5rem", marginBottom: "0.75rem" }, children: [_jsx(TextBoxComponent, { value: header.key, placeholder: l10n.getConstant('headerKey'), change: (e) => handleHeaderKeyChange(index, e.value), floatLabelType: "Never", style: { flex: 1 }, width: '90px', htmlAttributes: {
191
- 'aria-label': `${l10n.getConstant('headerKey')} ${index + 1}`
192
- } }), _jsx(TextBoxComponent, { value: header.value, placeholder: "Value", change: (e) => handleHeaderValueChange(index, e.value), floatLabelType: "Never", style: { flex: 1 }, width: '90px', htmlAttributes: {
193
- 'aria-label': `${l10n.getConstant('value')} ${index + 1}`
194
- } }), _jsx(ButtonComponent, { onClick: () => handleRemoveHeader(index), cssClass: 'e-flat', iconCss: 'e-icons e-trash', type: "button", "aria-label": `${l10n.getConstant('delete')} ${l10n.getConstant('header')} ${index + 1}` })] }, index)))] }), _jsxs("div", { className: "adaptor-selector", style: { marginBottom: "0.75rem" }, children: [_jsx("div", { className: 'property-label', style: { fontWeight: 500, marginBottom: "0.5rem" }, children: l10n.getConstant('adaptorType') }), _jsx("div", { style: { marginBottom: "1rem" }, children: _jsx(DropDownListComponent, { dataSource: [
195
- { text: 'Web API Adaptor', value: 'WebApiAdaptor' },
196
- { text: 'URL Adaptor', value: 'UrlAdaptor' },
197
- { text: 'OData V4 Adaptor', value: 'ODataV4Adaptor' }
198
- ], fields: { text: 'text', value: 'value' }, value: adaptorType, change: (e) => setAdaptorType(e.value), floatLabelType: "Never", htmlAttributes: {
199
- 'aria-labelledby': `${datakey}-adaptor-type-label`
200
- } }) }), _jsx("div", { style: { height: '0.5px', background: 'rgb(var(--sf-color-line-color))' } })] }), _jsxs(_Fragment, { children: [_jsx("div", { className: 'property-label', style: { fontWeight: 600, marginBottom: "0.5rem" }, children: l10n.getConstant('queryConfiguration') }), _jsxs("div", { className: 'query-section', children: [_jsxs("div", { style: { display: 'flex', justifyContent: "space-between" }, children: [_jsx("label", { className: 'property-label', style: { fontWeight: 600, marginBottom: "0.5rem" }, children: l10n.getConstant('search') }), _jsx("div", { children: _jsx(SwitchComponent, { checked: search.enabled, change: (e) => setSearch({ ...search, enabled: e.checked }), htmlAttributes: {
201
- 'aria-label': l10n.getConstant('search')
202
- } }) })] }), search.enabled && (_jsxs(_Fragment, { children: [_jsxs("div", { style: { marginBottom: "0.75rem" }, children: [_jsx("div", { className: 'property-label', style: { fontWeight: 500, marginBottom: "0.5rem" }, children: l10n.getConstant('queryParameterName') }), _jsx("div", { className: 'property-description', children: l10n.getConstant('fieldToSearch') }), _jsx(TextBoxComponent, { value: search.key || `${l10n.getConstant('search')}`, change: (e) => setSearch({ ...search, key: e.value }), floatLabelType: "Always", htmlAttributes: {
203
- 'aria-label': l10n.getConstant('queryParameterName')
204
- } })] }), _jsxs("div", { children: [_jsx("div", { className: 'property-label', style: { fontWeight: 500, marginBottom: "0.5rem" }, children: "Fields" }), _jsx("div", { className: 'property-description', children: l10n.getConstant('fieldsToSearchIn') }), _jsx(TextBoxComponent, { value: search.fields.join(', '), change: (e) => setSearch({ ...search, fields: e.value.split(',').map((f) => f.trim()).filter((f) => f) }), floatLabelType: "Always", multiline: true, htmlAttributes: {
205
- 'aria-label': l10n.getConstant('fieldsToSearchIn')
206
- } })] })] }))] }), _jsxs("div", { className: "query-section", children: [_jsxs("div", { style: { display: 'flex', justifyContent: "space-between" }, children: [_jsx("label", { className: 'property-label', style: { fontWeight: 600, marginBottom: "0.5rem" }, children: l10n.getConstant('sort') }), _jsx("div", { children: _jsx(SwitchComponent, { checked: sort.enabled, change: (e) => setSort({ ...sort, enabled: e.checked }), htmlAttributes: {
207
- 'aria-label': l10n.getConstant('sort')
208
- } }) })] }), sort.enabled && (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [_jsx("div", { className: 'property-label', style: { fontWeight: 500 }, children: "Field" }), _jsx(TextBoxComponent, { value: sort.field, placeholder: l10n.getConstant('fieldToSortBy'), change: (e) => setSort({ ...sort, field: e.value }), floatLabelType: "Never", style: { flex: 1 }, htmlAttributes: {
209
- 'aria-label': l10n.getConstant('fieldToSortBy')
210
- } }), _jsx("div", { className: 'property-label', style: { fontWeight: 500 }, children: "Direction" }), _jsx(DropDownListComponent, { dataSource: [
211
- { text: l10n.getConstant('ascending'), value: 'ascending' },
212
- { text: l10n.getConstant('descending'), value: 'descending' }
213
- ], fields: { text: 'text', value: 'value' }, value: sort.direction, change: (e) => setSort({ ...sort, direction: e.value }), floatLabelType: "Never", style: { flex: 1 }, htmlAttributes: {
214
- 'aria-label': 'Direction'
215
- } })] }))] }), _jsxs("div", { className: "query-section", children: [_jsxs("div", { style: { display: 'flex', justifyContent: "space-between" }, children: [_jsx("div", { className: 'property-label', style: { fontWeight: 500, marginBottom: "0.25rem" }, children: l10n.getConstant('filters') }), _jsx(ButtonComponent, { style: { marginBottom: "0.25rem" }, onClick: () => setFilters([...filters, { field: '', operator: 'equal', value: '' }]), iconCss: 'e-icons e-plus', cssClass: "e-flat", title: "Add Condition", "aria-label": l10n.getConstant('addHeader'), children: l10n.getConstant('addHeader') })] }), filters.length > 0 &&
216
- _jsx("div", { className: 'property-description', style: { marginBottom: "0.75rem" }, children: l10n.getConstant('fieldToSearch') }), filters.map((filter, index) => (_jsxs("div", { style: { display: "flex", gap: "0.5rem", marginBottom: "0.5rem", flexWrap: 'wrap', padding: '6px', border: '1px solid rgb(var(--sf-color-line-color))', borderRadius: '12px' }, children: [_jsx(TextBoxComponent, { value: filter.field, width: "185px", placeholder: l10n.getConstant('fieldStatus'), change: (e) => {
217
- const updated = [...filters];
218
- updated[index].field = e.value;
219
- setFilters(updated);
220
- }, floatLabelType: "Never", style: { flex: 1 }, htmlAttributes: {
221
- 'aria-label': `${l10n.getConstant('fieldStatus')} ${index + 1}`
222
- } }), datakey === 'data' &&
223
- _jsx(ButtonComponent, { cssClass: "e-flat", iconCss: 'e-icons e-trash', onClick: () => setFilters(filters.filter((_, i) => i !== index)), type: "button", "aria-label": `${l10n.getConstant('delete')} ${l10n.getConstant('filters')} ${index + 1}` }), _jsx(DropDownListComponent, { dataSource: [
224
- { text: '=', value: 'equal' },
225
- { text: '!=', value: 'notequal' },
226
- { text: 'contains', value: 'contains' },
227
- { text: '>', value: 'greaterthan' },
228
- { text: '<', value: 'lessthan' },
229
- { text: '>=', value: 'greaterthanorequal' },
230
- { text: '<=', value: 'lessthanorequal' }
231
- ], fields: { text: 'text', value: 'value' }, value: filter.operator, width: "105px", popupWidth: "100px", change: (e) => {
232
- const updated = [...filters];
233
- updated[index].operator = e.value;
234
- setFilters(updated);
235
- }, floatLabelType: "Never", style: { flex: 1 }, htmlAttributes: {
236
- 'aria-label': `Operator ${index + 1}`
237
- } }), _jsx(TextBoxComponent, { value: filter.value, placeholder: l10n.getConstant('value'), width: "105px", change: (e) => {
238
- const updated = [...filters];
239
- updated[index].value = e.value;
240
- setFilters(updated);
241
- }, floatLabelType: "Never", style: { flex: 1 }, htmlAttributes: {
242
- 'aria-label': `${l10n.getConstant('value')} ${index + 1}`
243
- } }), datakey === 'Conditionaldata' &&
244
- _jsx(ButtonComponent, { cssClass: "e-flat", iconCss: 'e-icons e-trash', onClick: () => setFilters(filters.filter((_, i) => i !== index)), type: "button", "aria-label": `${l10n.getConstant('delete')} ${l10n.getConstant('filters')} ${index + 1}` })] }, index)))] }), _jsx("div", { className: "query-section", children: _jsxs("div", { style: { display: "flex", gap: "0.5rem" }, children: [_jsxs("div", { children: [_jsx("div", { className: 'property-label', style: { fontWeight: 500, marginBottom: "0.25rem" }, children: l10n.getConstant('offset') }), _jsx(TextBoxComponent, { value: skip !== null ? skip.toString() : '', placeholder: l10n.getConstant('skipOffset'), change: (e) => setSkip(parseInt(e.value) || 0), floatLabelType: "Never", type: "number", style: { flex: 1 }, htmlAttributes: {
245
- 'aria-label': l10n.getConstant('offset')
246
- } })] }), _jsxs("div", { children: [_jsx("div", { className: 'property-label', style: { fontWeight: 500, marginBottom: "0.25rem" }, children: l10n.getConstant('limit') }), _jsx(TextBoxComponent, { value: take !== null ? take.toString() : '', placeholder: l10n.getConstant('takeLimit'), change: (e) => setTake(parseInt(e.value) || 0), floatLabelType: "Never", type: "number", style: { flex: 1 }, htmlAttributes: {
247
- 'aria-label': l10n.getConstant('limit')
248
- } })] })] }) })] }), _jsx(ButtonComponent, { style: { marginTop: '0.75rem' }, cssClass: "e-primary", onClick: handleSaveUrl, type: "button", "aria-label": l10n.getConstant('save'), children: l10n.getConstant('save') })] })), dataSourceType === 'lookup' && (_jsxs("div", { className: "lookup-editor", style: { marginBottom: '0.75rem' }, children: [_jsx("div", { className: 'property-description', style: { marginBottom: '0.5rem' }, children: l10n.getConstant('selectFormSubmissions') }), _jsxs("div", { style: { marginBottom: '0.5rem' }, children: [_jsx("label", { style: { display: 'block', marginBottom: '0.5rem', fontWeight: 500 }, children: l10n.getConstant('selectFormName') }), _jsx(DropDownListComponent, { dataSource: formNames, value: selectedFormName, change: handleLookupFormNameChange, placeholder: l10n.getConstant('selectFormName'), popupHeight: "200px", allowFiltering: true, enabled: !isLoadingFormNames, floatLabelType: "Never", htmlAttributes: {
249
- 'aria-labelledby': `${datakey}-form-name-label`
250
- } })] }), lookupErrorMessage && (_jsx("p", { className: "e-error", style: { marginTop: '0.5rem' }, role: "alert", "aria-live": "assertive", children: lookupErrorMessage }))] })), errorMessage && (_jsx("p", { className: "e-error", role: "alert", "aria-live": "assertive", children: errorMessage })), successMessage && (_jsx("p", { className: "e-success", role: "alert", "aria-live": "assertive", children: successMessage }))] }), type != 'grid' ? (_jsx("div", { style: { height: '0.5px', background: 'rgb(var(--sf-color-line-color))', marginTop: '1rem' } })) : null] }));
251
- return isAccordion ? (_jsx(AccordionWrapper, { title: l10n.getConstant('dataSource'), children: content })) : (content);
252
- };
@@ -1,13 +0,0 @@
1
- import React from 'react';
2
- export interface ExpressionEditorProps {
3
- expression?: string;
4
- availableFields: string[] | any[];
5
- onExpressionChange: (expression: string) => void;
6
- }
7
- export interface ColumnExpressionEditorProps {
8
- expression?: string;
9
- availableFields: string[];
10
- onExpressionChange: (expression: string) => void;
11
- }
12
- export declare const ExpressionEditor: React.FC<ExpressionEditorProps>;
13
- export declare const ColumnExpressionEditor: React.FC<ColumnExpressionEditorProps>;
@@ -1,99 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect, useMemo } from 'react';
3
- import { ExpressionEngine, ExpressionValidator } from '../../Common/expressions/ExpressionEngine';
4
- import { floatBlur, floatFocus } from '../components/layout/LeftPane';
5
- import { useLocalization } from '../context/LocalizationContext';
6
- import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';
7
- export const ExpressionEditor = ({ expression = '', availableFields, onExpressionChange }) => {
8
- const [localExpression, setLocalExpression] = useState(expression);
9
- const [errors, setErrors] = useState([]);
10
- const [hasDependencies, setHasDependencies] = useState(false);
11
- const validator = new ExpressionValidator();
12
- const engine = new ExpressionEngine();
13
- // Validate expression and extract dependencies
14
- useEffect(() => {
15
- if (localExpression.trim() === '') {
16
- setErrors([]);
17
- setHasDependencies(false);
18
- return;
19
- }
20
- const validationErrors = validator.validate(localExpression, availableFields);
21
- const deps = engine.extractDependencies(localExpression);
22
- const errorMessages = validationErrors.map(e => e.message);
23
- // If no dependencies found, add error
24
- if (deps.length === 0) {
25
- errorMessages.push('Expression must contain at least one field reference');
26
- }
27
- setErrors(errorMessages);
28
- setHasDependencies(deps.length > 0);
29
- }, [localExpression, availableFields]);
30
- // Update parent on change (even if there are validation errors)
31
- // Syntax errors are shown but don't block expression from being saved
32
- // Runtime validation will catch field reference errors at evaluation time
33
- useEffect(() => {
34
- if (errors.length === 0 && hasDependencies) {
35
- onExpressionChange(localExpression);
36
- }
37
- else {
38
- onExpressionChange('');
39
- }
40
- }, [localExpression, onExpressionChange, hasDependencies, errors]);
41
- // Show field suggestions when typing {
42
- const handleChange = (e) => {
43
- const value = e.target.value || e.value || '';
44
- setLocalExpression(value);
45
- };
46
- return (_jsxs("div", { className: "expression-editor", children: [_jsx("div", { className: "expression-input-wrapper", children: _jsx("div", { className: "e-input-group", children: _jsx("textarea", { className: `e-input ${errors.length > 0 ? 'e-error' : ''}`, placeholder: "e.g., {qty} * {price}", onFocus: floatFocus, onBlur: floatBlur, value: localExpression, onChange: handleChange, "aria-label": 'Expression Editor textbox', "aria-invalid": errors.length > 0 ? 'true' : 'false' }) }) }), errors.length > 0 && (_jsx("div", { className: "expression-errors", role: "alert", "aria-live": "assertive", children: errors.map((error, idx) => (_jsx("div", { className: "e-error", role: "alert", "aria-live": "assertive", children: error }, idx))) }))] }));
47
- };
48
- export const ColumnExpressionEditor = ({ expression = '', availableFields, onExpressionChange }) => {
49
- const [inputValue, setInputValue] = useState(expression);
50
- const validator = useMemo(() => new ExpressionValidator(), []);
51
- const engine = useMemo(() => new ExpressionEngine(), []);
52
- const { l10n } = useLocalization();
53
- // Validate only when expression is updated externally
54
- useEffect(() => {
55
- setInputValue(expression);
56
- }, [expression]);
57
- // Validation errors
58
- const errors = useMemo(() => {
59
- if (!inputValue || inputValue.trim() === '') {
60
- return [];
61
- }
62
- const validationErrors = validator.validate(inputValue, availableFields);
63
- const errorMessages = validationErrors.map(e => e.message);
64
- // Check for field dependencies
65
- const deps = engine.extractDependencies(inputValue);
66
- // If no dependencies found, add error
67
- if (deps.length === 0) {
68
- errorMessages.push('Expression must contain at least one field reference');
69
- }
70
- return errorMessages;
71
- }, [inputValue, availableFields, validator, engine]);
72
- // Handle local input change
73
- const handleInputChange = (e) => {
74
- const newValue = e.value || '';
75
- setInputValue(newValue);
76
- // Validate before calling parent onChange
77
- let tempErrors = [];
78
- if (newValue && newValue.trim() !== '') {
79
- const validationErrors = validator.validate(newValue, availableFields);
80
- tempErrors = validationErrors.map(e => e.message);
81
- // Check for field dependencies
82
- const deps = engine.extractDependencies(newValue);
83
- if (deps.length === 0) {
84
- tempErrors.push('Expression must contain at least one field reference');
85
- }
86
- }
87
- // Only notify parent if no errors
88
- if (tempErrors.length === 0) {
89
- onExpressionChange(newValue);
90
- }
91
- };
92
- return (_jsxs("div", { "aria-label": 'Expression Editor textbox', className: "column-expression-editor", style: { display: 'flex', flexDirection: 'column' }, children: [_jsx(TextBoxComponent, { multiline: true, placeholder: l10n.getConstant("expressionPlaceholder"), value: inputValue, change: handleInputChange, className: "e-textbox expression-input", htmlAttributes: {
93
- 'aria-label': 'Expression Editor textbox',
94
- 'aria-invalid': errors.length > 0 ? 'true' : 'false',
95
- ...(errors.length > 0 && {
96
- 'aria-describedby': 'column-expression-errors'
97
- })
98
- } }), errors.length > 0 && (_jsx("div", { className: "e-error", id: "column-expression-errors", role: "alert", "aria-live": "assertive", children: errors.map((error, idx) => (_jsx("p", { style: { margin: 0 }, children: error }, idx))) }))] }));
99
- };
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import type { FormSettings } from '../types/FormSchema';
3
- interface FormSettingsPanelProps {
4
- settings: FormSettings | undefined;
5
- formSettingsConfig: any;
6
- onSave: (settings: FormSettings, key: string) => void;
7
- }
8
- export declare const FormSettingsPanel: React.FC<FormSettingsPanelProps>;
9
- export {};