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

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 (145) hide show
  1. package/Common/CheckboxGroup.d.ts +13 -0
  2. package/Common/CheckboxGroup.js +50 -0
  3. package/Common/ConditionalRuleEngine.d.ts +296 -0
  4. package/Common/ConditionalRuleEngine.js +566 -0
  5. package/Common/CustomTabComponent.d.ts +17 -0
  6. package/Common/CustomTabComponent.js +30 -0
  7. package/Common/CustomValidationEngine.d.ts +58 -0
  8. package/Common/CustomValidationEngine.js +146 -0
  9. package/Common/DataGridComponent.d.ts +20 -0
  10. package/Common/DataGridComponent.js +273 -0
  11. package/Common/FormValidator.d.ts +485 -0
  12. package/Common/FormValidator.js +575 -0
  13. package/Common/MinMaxRuleEngine.d.ts +105 -0
  14. package/Common/MinMaxRuleEngine.js +365 -0
  15. package/Common/StaticHtmlRenderer.d.ts +14 -0
  16. package/Common/StaticHtmlRenderer.js +24 -0
  17. package/Common/expressions/DependencyTracker.d.ts +30 -0
  18. package/Common/expressions/DependencyTracker.js +128 -0
  19. package/Common/expressions/ExpressionEngine.d.ts +95 -0
  20. package/Common/expressions/ExpressionEngine.js +506 -0
  21. package/Common/expressions/ExpressionParser.d.ts +41 -0
  22. package/Common/expressions/ExpressionParser.js +269 -0
  23. package/Common/expressions/useGridExpressions.d.ts +12 -0
  24. package/Common/expressions/useGridExpressions.js +71 -0
  25. package/Common/globalFormId.d.ts +26 -0
  26. package/Common/globalFormId.js +45 -0
  27. package/Common/json-converter.d.ts +444 -0
  28. package/Common/json-converter.js +1184 -0
  29. package/Common/parser.d.ts +98 -0
  30. package/Common/parser.js +753 -0
  31. package/Common/utils.d.ts +130 -0
  32. package/Common/utils.js +574 -0
  33. package/README.md +53 -0
  34. package/index.d.ts +6 -0
  35. package/index.js +6 -0
  36. package/license +13 -0
  37. package/package.json +54 -0
  38. package/src/FormBuilder.d.ts +211 -0
  39. package/src/FormBuilder.js +1299 -0
  40. package/src/components/Database/ConnectionForm.d.ts +8 -0
  41. package/src/components/Database/ConnectionForm.js +28 -0
  42. package/src/components/TopBar.d.ts +10 -0
  43. package/src/components/TopBar.js +7 -0
  44. package/src/components/icons/ComponentIcons.d.ts +44 -0
  45. package/src/components/icons/ComponentIcons.js +40 -0
  46. package/src/components/layout/FormFieldWrapper.d.ts +41 -0
  47. package/src/components/layout/FormFieldWrapper.js +112 -0
  48. package/src/components/layout/LeftPane.d.ts +23 -0
  49. package/src/components/layout/LeftPane.js +310 -0
  50. package/src/components/layout/ListBoxPane.d.ts +24 -0
  51. package/src/components/layout/ListBoxPane.js +94 -0
  52. package/src/components/layout/MainSection.d.ts +39 -0
  53. package/src/components/layout/MainSection.js +1766 -0
  54. package/src/components/layout/Preview.d.ts +12 -0
  55. package/src/components/layout/Preview.js +337 -0
  56. package/src/components/layout/RightPane.d.ts +22 -0
  57. package/src/components/layout/RightPane.js +370 -0
  58. package/src/components/theme/ThemeSwitcher.d.ts +14 -0
  59. package/src/components/theme/ThemeSwitcher.js +24 -0
  60. package/src/components/theme/theme-constant.d.ts +37 -0
  61. package/src/components/theme/theme-constant.js +23 -0
  62. package/src/config/component-properties.json +4929 -0
  63. package/src/config/form-setting.json +56 -0
  64. package/src/config/locale.d.ts +449 -0
  65. package/src/config/locale.js +449 -0
  66. package/src/context/FormSchemaContext.d.ts +32 -0
  67. package/src/context/FormSchemaContext.js +155 -0
  68. package/src/context/LocalizationContext.d.ts +27 -0
  69. package/src/context/LocalizationContext.js +43 -0
  70. package/src/context/ThemeContext.d.ts +23 -0
  71. package/src/context/ThemeContext.js +161 -0
  72. package/src/context/contexts.d.ts +6 -0
  73. package/src/context/contexts.js +6 -0
  74. package/src/context/defaultFormSchema.d.ts +6 -0
  75. package/src/context/defaultFormSchema.js +20 -0
  76. package/src/defaultPalette.d.ts +9 -0
  77. package/src/defaultPalette.js +45 -0
  78. package/src/defaultTemplate.d.ts +3 -0
  79. package/src/defaultTemplate.js +185 -0
  80. package/src/import/schemaImportUtils.d.ts +24 -0
  81. package/src/import/schemaImportUtils.js +121 -0
  82. package/src/index.d.ts +16 -0
  83. package/src/index.js +6 -0
  84. package/src/types/ActionButtons.d.ts +44 -0
  85. package/src/types/ActionButtons.js +27 -0
  86. package/src/types/ComponentProperties.d.ts +33 -0
  87. package/src/types/ComponentProperties.js +2 -0
  88. package/src/types/FormSchema.d.ts +585 -0
  89. package/src/types/FormSchema.js +147 -0
  90. package/src/types/connection.d.ts +19 -0
  91. package/src/types/connection.js +9 -0
  92. package/src/utils/AttributesEditor.d.ts +13 -0
  93. package/src/utils/AttributesEditor.js +117 -0
  94. package/src/utils/ButtonGroupEditor.d.ts +15 -0
  95. package/src/utils/ButtonGroupEditor.js +141 -0
  96. package/src/utils/ChoiceBasedFieldEditor.d.ts +16 -0
  97. package/src/utils/ChoiceBasedFieldEditor.js +87 -0
  98. package/src/utils/ClipboardHelper.d.ts +26 -0
  99. package/src/utils/ClipboardHelper.js +83 -0
  100. package/src/utils/ColumnBuilder.d.ts +11 -0
  101. package/src/utils/ColumnBuilder.js +153 -0
  102. package/src/utils/ColumnSpanEditor.d.ts +8 -0
  103. package/src/utils/ColumnSpanEditor.js +98 -0
  104. package/src/utils/ConditionDataEditor.d.ts +29 -0
  105. package/src/utils/ConditionDataEditor.js +177 -0
  106. package/src/utils/ConditionalEditorUtils.d.ts +27 -0
  107. package/src/utils/ConditionalEditorUtils.js +310 -0
  108. package/src/utils/ConditionsEditor.d.ts +20 -0
  109. package/src/utils/ConditionsEditor.js +571 -0
  110. package/src/utils/CustomAccordion.d.ts +13 -0
  111. package/src/utils/CustomAccordion.js +38 -0
  112. package/src/utils/CustomValidationEditor.d.ts +11 -0
  113. package/src/utils/CustomValidationEditor.js +208 -0
  114. package/src/utils/DataSourceCollector.d.ts +3 -0
  115. package/src/utils/DataSourceCollector.js +252 -0
  116. package/src/utils/ExpressionEditor.d.ts +13 -0
  117. package/src/utils/ExpressionEditor.js +99 -0
  118. package/src/utils/FormSettingsPanel.d.ts +9 -0
  119. package/src/utils/FormSettingsPanel.js +60 -0
  120. package/src/utils/LookupConfig.d.ts +11 -0
  121. package/src/utils/LookupConfig.js +159 -0
  122. package/src/utils/MinMaxValueEditor.d.ts +25 -0
  123. package/src/utils/MinMaxValueEditor.js +188 -0
  124. package/src/utils/OptionsEditor.d.ts +8 -0
  125. package/src/utils/OptionsEditor.js +79 -0
  126. package/src/utils/PropertyRenderer.d.ts +22 -0
  127. package/src/utils/PropertyRenderer.js +210 -0
  128. package/src/utils/ValueRenderer.d.ts +2 -0
  129. package/src/utils/ValueRenderer.js +91 -0
  130. package/src/utils/ej2DbAdaptor.d.ts +6 -0
  131. package/src/utils/ej2DbAdaptor.js +38 -0
  132. package/src/utils/mappingHeuristics.d.ts +10 -0
  133. package/src/utils/mappingHeuristics.js +33 -0
  134. package/src/utils/renderComponent.d.ts +18 -0
  135. package/src/utils/renderComponent.js +300 -0
  136. package/styles/tailwind3.css +67 -0
  137. package/styles/themes/action-buttons.css +110 -0
  138. package/styles/themes/datagrid.css +380 -0
  139. package/styles/themes/drag-reorder.css +248 -0
  140. package/styles/themes/import-dialog.css +292 -0
  141. package/styles/themes/index.css +658 -0
  142. package/styles/themes/left-pane.css +253 -0
  143. package/styles/themes/options-editor.css +63 -0
  144. package/styles/themes/preview.css +702 -0
  145. package/styles/themes/property-dialog.css +371 -0
@@ -0,0 +1,310 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useState, useMemo, useCallback } from 'react';
3
+ import { Draggable } from '@syncfusion/react-base';
4
+ import { AccordionComponent, AccordionItemsDirective, AccordionItemDirective } from '@syncfusion/ej2-react-navigations';
5
+ import { ComponentCategory } from '../../types/FormSchema';
6
+ import { defaultPalette } from '../../defaultPalette';
7
+ import { generateId, generateName } from '../../../Common/json-converter';
8
+ import { TextBoxIcon, TextAreaIcon, NumericIcon, EmailIcon, UrlIcon, PhoneIcon, PasswordIcon, CheckboxIcon, CheckboxGroupIcon, RadioIcon, DropdownIcon, MultiSelectIcon, ButtonIcon, DatePickerIcon, DateTimePickerIcon, TimePickerIcon, DateRangeIcon, SwitchIcon, SignatureIcon, RatingIcon, ImageEditorIcon, FileUploadIcon, RangeSliderIcon, ColorPickerIcon, InputMaskIcon, MessageIcon, PanelIcon, TableIcon, DataGridIcon, TabsIcon, TemplateIcon, CardIcon, SplitButtonIcon, RichTextEditorIcon, StaticHtmlIcon, LookupIcon, OrderNumberIcon } from '../icons/ComponentIcons';
9
+ import { useLocalization } from '../../context/LocalizationContext';
10
+ export const floatFocus = (args) => {
11
+ args.target.parentElement.classList.add("e-input-focus");
12
+ };
13
+ export const floatBlur = (args) => {
14
+ args.target.parentElement.classList.remove('e-input-focus');
15
+ };
16
+ export const getIconComponent = (type) => {
17
+ switch (type) {
18
+ case 'textbox':
19
+ return _jsx(TextBoxIcon, { className: "palette-item-icon-svg" });
20
+ case 'textarea':
21
+ return _jsx(TextAreaIcon, { className: "palette-item-icon-svg" });
22
+ case 'number':
23
+ return _jsx(NumericIcon, { className: "palette-item-icon-svg" });
24
+ case 'email':
25
+ return _jsx(EmailIcon, { className: "palette-item-icon-svg" });
26
+ case 'url':
27
+ return _jsx(UrlIcon, { className: "palette-item-icon-svg" });
28
+ case 'phone':
29
+ return _jsx(PhoneIcon, { className: "palette-item-icon-svg" });
30
+ case 'password':
31
+ return _jsx(PasswordIcon, { className: "palette-item-icon-svg" });
32
+ case 'checkbox':
33
+ return _jsx(CheckboxIcon, { className: "palette-item-icon-svg" });
34
+ case 'checkboxGroup':
35
+ return _jsx(CheckboxGroupIcon, { className: "palette-item-icon-svg" });
36
+ case 'radio':
37
+ return _jsx(RadioIcon, { className: "palette-item-icon-svg" });
38
+ case 'dropdown':
39
+ return _jsx(DropdownIcon, { className: "palette-item-icon-svg" });
40
+ case 'multiselect':
41
+ return _jsx(MultiSelectIcon, { className: "palette-item-icon-svg" });
42
+ case 'button':
43
+ return _jsx(ButtonIcon, { className: "palette-item-icon-svg" });
44
+ case 'date':
45
+ return _jsx(DatePickerIcon, { className: "palette-item-icon-svg" });
46
+ case 'dateTime':
47
+ return _jsx(DateTimePickerIcon, { className: "palette-item-icon-svg" });
48
+ case 'time':
49
+ return _jsx(TimePickerIcon, { className: "palette-item-icon-svg" });
50
+ case 'dateRange':
51
+ return _jsx(DateRangeIcon, { className: "palette-item-icon-svg" });
52
+ case 'switch':
53
+ return _jsx(SwitchIcon, { className: "palette-item-icon-svg" });
54
+ case 'signature':
55
+ return _jsx(SignatureIcon, { className: "palette-item-icon-svg" });
56
+ case 'rating':
57
+ return _jsx(RatingIcon, { className: "palette-item-icon-svg" });
58
+ case 'imageEditor':
59
+ return _jsx(ImageEditorIcon, { className: "palette-item-icon-svg" });
60
+ case 'fileUpload':
61
+ return _jsx(FileUploadIcon, { className: "palette-item-icon-svg" });
62
+ case 'rangeSlider':
63
+ return _jsx(RangeSliderIcon, { className: "palette-item-icon-svg" });
64
+ case 'colorPicker':
65
+ return _jsx(ColorPickerIcon, { className: "palette-item-icon-svg" });
66
+ case 'inputMask':
67
+ return _jsx(InputMaskIcon, { className: "palette-item-icon-svg" });
68
+ case 'message':
69
+ return _jsx(MessageIcon, { className: "palette-item-icon-svg" });
70
+ case 'panel':
71
+ return _jsx(PanelIcon, { className: "palette-item-icon-svg" });
72
+ case 'table':
73
+ return _jsx(TableIcon, { className: "palette-item-icon-svg" });
74
+ case 'dataGrid':
75
+ return _jsx(DataGridIcon, { className: "palette-item-icon-svg" });
76
+ case 'tabs':
77
+ return _jsx(TabsIcon, { className: "palette-item-icon-svg" });
78
+ case 'card':
79
+ return _jsx(CardIcon, { className: "palette-item-icon-svg" });
80
+ case 'splitButton':
81
+ return _jsx(SplitButtonIcon, { className: "palette-item-icon-svg" });
82
+ case 'richTextEditor':
83
+ return _jsx(RichTextEditorIcon, { className: "palette-item-icon-svg" });
84
+ case 'lookup':
85
+ return _jsx(LookupIcon, { className: "palette-item-icon-svg" });
86
+ case 'staticHtml':
87
+ return _jsx(StaticHtmlIcon, { className: "palette-item-icon-svg" });
88
+ case 'autoNumber':
89
+ return _jsx(OrderNumberIcon, { className: "palette-item-icon-svg" });
90
+ default:
91
+ return null;
92
+ }
93
+ };
94
+ export const simpleModeHiddenTypes = new Set([
95
+ 'splitButton',
96
+ 'imageEditor',
97
+ 'dataGrid',
98
+ 'richTextEditor',
99
+ 'lookup',
100
+ 'autoNumber',
101
+ 'colorPicker',
102
+ 'signature'
103
+ ]);
104
+ const LeftPane = ({ className, templates = [], paletteConfig, onFieldDragStarted, mode = 'Simple', onDrop, containerWidth = 1024 }) => {
105
+ const cloneHelperRef = useRef(null);
106
+ const draggedComponentRef = useRef(null);
107
+ const { l10n } = useLocalization();
108
+ const [searchInput, setSearchInput] = useState('');
109
+ const [showSplitView, setShowSplitView] = useState(false);
110
+ const [templateSearchInput, setTemplateSearchInput] = useState('');
111
+ const isMobile = containerWidth <= 820;
112
+ // Initialize palette with user config or defaults, resolve labels internally from l10n
113
+ const palette = useMemo(() => {
114
+ const merged = { ...defaultPalette };
115
+ if (paletteConfig) {
116
+ Object.entries(paletteConfig).forEach(([category, components]) => {
117
+ if (components) {
118
+ merged[category] = components;
119
+ }
120
+ });
121
+ }
122
+ // Filter out advanced components when in Simple mode
123
+ if (mode === 'Simple' && merged[ComponentCategory.ADVANCED]) {
124
+ merged[ComponentCategory.ADVANCED] = merged[ComponentCategory.ADVANCED].filter(comp => !simpleModeHiddenTypes.has(comp.type));
125
+ }
126
+ // Resolve labels internally from l10n for all components
127
+ const withLabels = {};
128
+ Object.entries(merged).forEach(([category, components]) => {
129
+ withLabels[category] = (components || []).map(comp => ({
130
+ ...comp,
131
+ label: comp.label || l10n.getConstant(comp.type) || comp.type
132
+ }));
133
+ });
134
+ return withLabels;
135
+ }, [paletteConfig, l10n, mode, simpleModeHiddenTypes]); // ADD mode dependencies
136
+ // Get label from component or resolve from l10n
137
+ const getComponentLabel = (component) => {
138
+ if (component.label)
139
+ return component.label;
140
+ return l10n.getConstant(component.type) || component.type;
141
+ };
142
+ // Mobile click-to-add handler: builds a FormComponent and drops it at the bottom of the canvas
143
+ const handlePaletteItemClick = useCallback((component) => {
144
+ if (!isMobile || !onDrop)
145
+ return;
146
+ const newComponent = {
147
+ id: generateId(component.type),
148
+ type: component.type,
149
+ label: component.label || '',
150
+ name: generateName(component.type),
151
+ };
152
+ // Append to bottom of canvas (default behavior, smart submit-button handling is applied downstream)
153
+ onDrop(newComponent);
154
+ }, [isMobile, onDrop]);
155
+ // Mobile keydown handler: builds a FormComponent and drops it at the bottom of the canvas
156
+ const handlePaletteItemKeyDown = useCallback((e, component) => {
157
+ if (!onDrop || e.code !== 'Enter')
158
+ return;
159
+ const newComponent = {
160
+ id: generateId(component.type),
161
+ type: component.type,
162
+ label: component.label || '',
163
+ name: generateName(component.type),
164
+ };
165
+ // Append to bottom of canvas (default behavior, smart submit-button handling is applied downstream)
166
+ onDrop(newComponent);
167
+ }, [onDrop]);
168
+ // Extract components from palette (labels already resolved)
169
+ const basicComponents = useMemo(() => palette[ComponentCategory.BASIC] || [], [palette]);
170
+ const isBlockedInSimpleMode = (type) => {
171
+ return mode === 'Simple' && [
172
+ 'splitButton', 'imageEditor', 'dataGrid', 'richTextEditor',
173
+ 'lookup', 'autoNumber', 'colorPicker', 'signature'
174
+ ].includes(type);
175
+ };
176
+ const advancedComponents = useMemo(() => (palette[ComponentCategory.ADVANCED] || []).filter(c => !isBlockedInSimpleMode(c.type)), [palette, mode]);
177
+ const layoutComponents = useMemo(() => palette[ComponentCategory.LAYOUT] || [], [palette]);
178
+ const allComponents = useMemo(() => [
179
+ ...basicComponents,
180
+ ...advancedComponents,
181
+ ...layoutComponents
182
+ ], [basicComponents, advancedComponents, layoutComponents]);
183
+ const filteredComponents = useMemo(() => {
184
+ if (!searchInput.trim()) {
185
+ return [];
186
+ }
187
+ const lowerSearch = searchInput.toLowerCase();
188
+ return allComponents.filter(component => component.label?.toLowerCase().includes(lowerSearch) ||
189
+ component.type.toLowerCase().includes(lowerSearch));
190
+ }, [searchInput, allComponents]);
191
+ const filteredTemplates = useMemo(() => {
192
+ if (!templateSearchInput.trim()) {
193
+ return templates;
194
+ }
195
+ const lowerSearch = templateSearchInput.toLowerCase();
196
+ return templates.filter(t => (l10n.getConstant(t.id) || t.title)?.toLowerCase().includes(lowerSearch) ||
197
+ t.id.toLowerCase().includes(lowerSearch));
198
+ }, [templateSearchInput, templates, l10n]);
199
+ // Syncfusion Draggable handlers
200
+ const helper = (args) => {
201
+ const paletteItem = (args.sender?.target).closest('.palette-item');
202
+ if (!paletteItem)
203
+ return null;
204
+ const templateId = paletteItem.getAttribute('data-template-id');
205
+ if (templateId && templates.length) {
206
+ const tpl = templates.find(t => t.id === templateId);
207
+ if (tpl) {
208
+ draggedComponentRef.current = { type: 'template', label: (l10n.getConstant(tpl.id) || tpl.title), isTemplate: true, templateData: tpl };
209
+ return cloneHelperRef.current;
210
+ }
211
+ }
212
+ const componentType = paletteItem.getAttribute('data-component-type');
213
+ const component = allComponents.find(c => c.type === componentType);
214
+ if (component) {
215
+ draggedComponentRef.current = component;
216
+ }
217
+ return cloneHelperRef.current;
218
+ };
219
+ const syncDragStart = (args) => {
220
+ if (isMobile) {
221
+ args.cancel = true;
222
+ return;
223
+ }
224
+ if (cloneHelperRef.current && draggedComponentRef.current) {
225
+ cloneHelperRef.current.style.display = 'flex';
226
+ // If dragging a template, serialize template JSON into the clone as `data-template-json`
227
+ if (draggedComponentRef.current.isTemplate) {
228
+ const tpl = draggedComponentRef.current.templateData;
229
+ try {
230
+ cloneHelperRef.current.setAttribute('data-template-json', JSON.stringify(tpl));
231
+ }
232
+ catch (e) {
233
+ }
234
+ cloneHelperRef.current.removeAttribute('data-component-json');
235
+ }
236
+ else {
237
+ cloneHelperRef.current.setAttribute('data-component-json', JSON.stringify(draggedComponentRef.current));
238
+ }
239
+ const iconSpan = cloneHelperRef.current.querySelector('.palette-item-icon');
240
+ if (draggedComponentRef.current.isTemplate && iconSpan) {
241
+ iconSpan.innerHTML = '';
242
+ }
243
+ const labelSpan = cloneHelperRef.current.querySelector('.clone-label');
244
+ const paletteItem = document.querySelector(`.palette-item[data-component-type="${draggedComponentRef.current.type}"]`);
245
+ if (iconSpan && paletteItem) {
246
+ const sourceIcon = paletteItem.querySelector('.palette-item-icon');
247
+ if (sourceIcon) {
248
+ iconSpan.innerHTML = sourceIcon.innerHTML;
249
+ }
250
+ }
251
+ if (labelSpan) {
252
+ labelSpan.textContent = draggedComponentRef.current.label;
253
+ }
254
+ // Trigger onFieldDragStarted event for palette drags
255
+ if (onFieldDragStarted && draggedComponentRef.current) {
256
+ const isTemplate = !!draggedComponentRef.current.isTemplate;
257
+ onFieldDragStarted({
258
+ componentName: null, // Palette items don't have IDs yet
259
+ componentType: isTemplate ? 'template' : draggedComponentRef.current.type,
260
+ sourceContainerId: 'palette',
261
+ isNested: false
262
+ });
263
+ }
264
+ }
265
+ };
266
+ const syncDrag = () => {
267
+ if (cloneHelperRef.current) {
268
+ cloneHelperRef.current.style.opacity = '0.97';
269
+ }
270
+ };
271
+ const syncDragStop = () => {
272
+ setTimeout(() => {
273
+ if (cloneHelperRef.current) {
274
+ cloneHelperRef.current.style.display = 'none';
275
+ cloneHelperRef.current.style.opacity = '0';
276
+ cloneHelperRef.current.removeAttribute('data-component-json');
277
+ cloneHelperRef.current.removeAttribute('data-template-json');
278
+ }
279
+ }, 100);
280
+ draggedComponentRef.current = null;
281
+ };
282
+ const handleTabKeyDown = useCallback((e, showTemplates) => {
283
+ if (e.code === 'Enter') {
284
+ e.preventDefault();
285
+ setShowSplitView(showTemplates);
286
+ }
287
+ }, []);
288
+ return (_jsxs("aside", { "aria-label": l10n.getConstant('fields'), role: "navigation", className: `left-pane ${className || ''}`, style: containerWidth <= 820 ? { position: 'absolute', zIndex: 1000 } : {}, children: [_jsx("div", { className: "sidebar-header", children: _jsxs("div", { style: { display: 'flex', gap: '30px' }, role: "tablist", "aria-label": "Builder Navigation", children: [_jsx("div", { role: "tab", "aria-selected": !showSplitView, "aria-labelledby": "fields-panel", className: `tab ${!showSplitView && mode === 'Developer' ? 'active' : ''}`, style: { cursor: 'pointer' }, onClick: () => setShowSplitView(false), onKeyDown: (e) => handleTabKeyDown(e, false), tabIndex: 0, children: _jsx("p", { children: l10n.getConstant('fields') }) }), mode === 'Developer' && !isMobile &&
289
+ _jsx("div", { className: `tab ${showSplitView ? 'active' : ''}`, style: { cursor: 'pointer' }, onClick: () => setShowSplitView(true), onKeyDown: (e) => handleTabKeyDown(e, true), tabIndex: 0, role: "tab", "aria-selected": showSplitView, "aria-labelledby": "templates-panel", children: _jsx("p", { children: l10n.getConstant('templates') }) })] }) }), _jsxs("div", { className: "palette-container fb-scrollbar", children: [_jsxs("div", { className: "e-input-group", style: { marginBottom: "10px" }, children: [_jsx("input", { className: "e-input", type: "text", "aria-label": l10n.getConstant('search'), placeholder: l10n.getConstant('search'), value: showSplitView ? templateSearchInput : searchInput, onFocus: floatFocus, onBlur: floatBlur, onChange: (e) => showSplitView ? setTemplateSearchInput(e.target.value) : setSearchInput(e.target.value) }), _jsx("span", { "aria-hidden": "true", className: "e-input-group-icon e-icons e-search" })] }), !showSplitView && (_jsx(Draggable, { scope: 'new-field', clone: true, enableTailMode: true, helper: helper, isPreventSelect: true, onDragStart: syncDragStart, onDrag: syncDrag, onDragStop: syncDragStop, children: searchInput.trim() ? (
290
+ // Render filtered field items when search is active
291
+ _jsx("div", { role: "tabpanel", "aria-labelledby": "fields-tab", className: "palette-items", style: { paddingTop: '8px' }, children: filteredComponents.length > 0 ? (filteredComponents.map((component) => (_jsxs("div", { className: "palette-item", tabIndex: 0, "data-component-type": component.type, style: { userSelect: 'none', WebkitUserSelect: 'none' }, onClick: () => handlePaletteItemClick(component), onKeyDown: (e) => handlePaletteItemKeyDown(e, component), "aria-label": getComponentLabel(component), children: [_jsx("span", { "aria-hidden": "true", className: "palette-item-icon", children: getIconComponent(component.type) }), _jsx("span", { className: "palette-item-label", children: getComponentLabel(component) })] }, component.type)))) : (_jsx("div", { role: "status", "aria-live": "polite", style: { padding: '16px', textAlign: 'center', color: 'var(--sf-text-secondary)' }, children: "No results found" })) })) : (
292
+ // Render accordion when search is empty
293
+ _jsx(AccordionComponent, { expandMode: "Single", children: _jsxs(AccordionItemsDirective, { children: [_jsx(AccordionItemDirective, { header: l10n.getConstant('basic'), content: "#leftpane-basic", expanded: true }), _jsx(AccordionItemDirective, { header: l10n.getConstant('advanced'), content: "#leftpane-advanced" }), _jsx(AccordionItemDirective, { header: l10n.getConstant('layout'), content: "#leftpane-layout" })] }) })) })), showSplitView && (_jsx(Draggable, { scope: 'new-field', clone: true, enableTailMode: true, helper: helper, isPreventSelect: true, onDragStart: syncDragStart, onDrag: syncDrag, onDragStop: syncDragStop, children: _jsx("div", { role: "tabpanel", "aria-labelledby": "templates-tab", className: "palette-items", style: { paddingTop: '8px' }, children: filteredTemplates.length > 0 ? (filteredTemplates.map(t => (_jsxs("div", { tabIndex: 0, className: "palette-item template-item", "data-template-id": t.id, style: { userSelect: 'none', WebkitUserSelect: 'none' }, children: [_jsx("span", { className: "palette-item-icon", children: _jsx(TemplateIcon, { className: "palette-item-icon-svg" }) }), _jsx("span", { className: "palette-item-label", children: (l10n.getConstant(t.id) || t.title) })] }, t.id)))) : (_jsx("div", { role: "status", "aria-live": "polite", style: { padding: '16px', textAlign: 'center', color: 'var(--sf-text-secondary)' }, children: "No templates found" })) }) })), _jsxs("div", { style: { display: 'none' }, "aria-hidden": true, children: [_jsx("div", { id: "leftpane-basic", children: _jsx("div", { className: "palette-items", children: basicComponents.map((component) => (_jsxs("div", { tabIndex: 0, className: "palette-item", "data-component-type": component.type, style: { userSelect: 'none', WebkitUserSelect: 'none' }, onClick: () => handlePaletteItemClick(component), onKeyDown: (e) => handlePaletteItemKeyDown(e, component), "aria-label": getComponentLabel(component), children: [_jsx("span", { "aria-hidden": "true", className: "palette-item-icon", children: getIconComponent(component.type) }), _jsx("span", { className: "palette-item-label", children: getComponentLabel(component) })] }, component.type))) }) }), _jsx("div", { id: "leftpane-advanced", children: _jsx("div", { className: "palette-items", children: advancedComponents.map((component) => (_jsxs("div", { tabIndex: 0, className: "palette-item", "data-component-type": component.type, style: { userSelect: 'none', WebkitUserSelect: 'none' }, onClick: () => handlePaletteItemClick(component), onKeyDown: (e) => handlePaletteItemKeyDown(e, component), "aria-label": getComponentLabel(component), children: [_jsx("span", { "aria-hidden": "true", className: "palette-item-icon", children: getIconComponent(component.type) }), _jsx("span", { className: "palette-item-label", children: getComponentLabel(component) })] }, component.type))) }) }), _jsx("div", { id: "leftpane-layout", children: _jsx("div", { className: "palette-items", children: layoutComponents.map((component) => (_jsxs("div", { tabIndex: 0, className: "palette-item", "data-component-type": component.type, style: { userSelect: 'none', WebkitUserSelect: 'none' }, onClick: () => handlePaletteItemClick(component), onKeyDown: (e) => handlePaletteItemKeyDown(e, component), "aria-label": getComponentLabel(component), children: [_jsx("span", { "aria-hidden": "true", className: "palette-item-icon", children: getIconComponent(component.type) }), _jsx("span", { className: "palette-item-label", children: getComponentLabel(component) })] }, component.type))) }) })] }), _jsxs("div", { ref: cloneHelperRef, className: "palette-item-clone", "aria-hidden": "true", style: {
294
+ opacity: '0',
295
+ padding: '8px 12px',
296
+ zIndex: '10000',
297
+ display: 'none',
298
+ justifyContent: 'center',
299
+ alignItems: 'center',
300
+ gap: '8px',
301
+ height: '37px',
302
+ minWidth: '120px',
303
+ backgroundColor: 'rgb(var(--sf-drag-clone))',
304
+ border: '2px solid var(--sf-color-primary)',
305
+ borderRadius: '8px',
306
+ boxShadow: '0 4px 12px rgba(0,0,0,0.2)',
307
+ pointerEvents: 'none',
308
+ }, children: [_jsx("span", { "aria-hidden": "true", className: "palette-item-icon", style: { fontSize: '16px' } }), _jsx("span", { className: "clone-label", style: { fontSize: '14px', fontWeight: '500' } })] })] })] }));
309
+ };
310
+ export default LeftPane;
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { type PaletteComponent, type PaletteConfig } from '../../types/FormSchema';
3
+ interface ListBoxPaneProps {
4
+ isOpen: boolean;
5
+ onClose: () => void;
6
+ onSelect: (component: PaletteComponent) => void;
7
+ paletteConfig?: PaletteConfig;
8
+ mode?: 'Simple' | 'Developer';
9
+ }
10
+ /**
11
+ * ListBoxPane - Syncfusion ListBox grouped list popup for quick field addition
12
+ *
13
+ * Features:
14
+ * - Syncfusion ListBox with native grouping
15
+ * - Searchable via filter
16
+ * - Click outside to close
17
+ * - Escape key to close
18
+ * - Component selection triggers onSelect callback
19
+ *
20
+ * @param props - Component props
21
+ * @returns Popup component with Syncfusion ListBox
22
+ */
23
+ declare const ListBoxPane: React.FC<ListBoxPaneProps>;
24
+ export default ListBoxPane;
@@ -0,0 +1,94 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useMemo, useCallback } from 'react';
3
+ import { ListBoxComponent } from '@syncfusion/ej2-react-dropdowns';
4
+ import { defaultPalette } from '../../defaultPalette';
5
+ import { useLocalization } from '../../context/LocalizationContext';
6
+ import { getIconComponent, simpleModeHiddenTypes } from './LeftPane';
7
+ import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
8
+ /**
9
+ * ListBoxPane - Syncfusion ListBox grouped list popup for quick field addition
10
+ *
11
+ * Features:
12
+ * - Syncfusion ListBox with native grouping
13
+ * - Searchable via filter
14
+ * - Click outside to close
15
+ * - Escape key to close
16
+ * - Component selection triggers onSelect callback
17
+ *
18
+ * @param props - Component props
19
+ * @returns Popup component with Syncfusion ListBox
20
+ */
21
+ const ListBoxPane = ({ isOpen, onClose, onSelect, paletteConfig, mode }) => {
22
+ const popupRef = useRef(null);
23
+ const listboxRef = useRef(null);
24
+ const { l10n } = useLocalization();
25
+ const palette = useMemo(() => {
26
+ const merged = { ...defaultPalette };
27
+ if (paletteConfig) {
28
+ Object.entries(paletteConfig).forEach(([category, components]) => {
29
+ if (components) {
30
+ merged[category] = components;
31
+ }
32
+ });
33
+ }
34
+ // Resolve labels from l10n and flatten with group info
35
+ const items = [];
36
+ Object.entries(merged).forEach(([category, components]) => {
37
+ (components || []).forEach((comp) => {
38
+ // Filter out advanced components in Simple mode
39
+ if (mode === 'Simple' && simpleModeHiddenTypes.has(comp.type)) {
40
+ return;
41
+ }
42
+ items.push({
43
+ ...comp,
44
+ label: comp.label || l10n.getConstant(comp.type) || comp.type,
45
+ group: category
46
+ });
47
+ });
48
+ });
49
+ return items;
50
+ }, [paletteConfig, l10n, mode, simpleModeHiddenTypes]);
51
+ useEffect(() => {
52
+ if (!isOpen)
53
+ return;
54
+ const handleClickOutside = (event) => {
55
+ if (popupRef.current && !popupRef.current.contains(event.target)) {
56
+ onClose();
57
+ }
58
+ };
59
+ // Handle Escape key
60
+ const handleKeyDown = (event) => {
61
+ if (event.key === 'Escape') {
62
+ onClose();
63
+ }
64
+ };
65
+ document.addEventListener('mousedown', handleClickOutside);
66
+ document.addEventListener('keydown', handleKeyDown);
67
+ return () => {
68
+ document.removeEventListener('mousedown', handleClickOutside);
69
+ document.removeEventListener('keydown', handleKeyDown);
70
+ };
71
+ }, [isOpen, onClose]);
72
+ const handleSelect = useCallback((args) => {
73
+ if (!args.event.isTrusted) {
74
+ return;
75
+ }
76
+ const dataType = args.elements[0].getAttribute('data-value');
77
+ const selectedComponent = palette.find((p) => p.type === dataType);
78
+ if (selectedComponent) {
79
+ onSelect({
80
+ type: selectedComponent.type,
81
+ label: selectedComponent.label
82
+ });
83
+ onClose();
84
+ }
85
+ }, [palette, onSelect, onClose]);
86
+ if (!isOpen)
87
+ return null;
88
+ return (_jsx("div", { className: "listbox-pane-wrapper", "aria-modal": "true", tabIndex: -1, role: 'dialog', "aria-label": "Component Selection", onClick: (e) => {
89
+ if (e.target === e.currentTarget) {
90
+ onClose();
91
+ }
92
+ }, children: _jsx("div", { className: "listbox-pane-popup", ref: popupRef, "aria-label": "Available Components", children: _jsx(ListBoxComponent, { ref: listboxRef, dataSource: palette, tabIndex: 0, fields: { groupBy: 'group', text: 'label', value: 'type' }, change: handleSelect, allowFiltering: true, filterBarPlaceholder: "Search", height: "400px", "aria-label": "Available Components", itemTemplate: (props) => (_jsxs(ButtonComponent, { cssClass: 'e-flat', style: { display: 'flex', justifyContent: 'flex-start', padding: 0, fontWeight: 500, backgroundColor: 'transparent', border: 'none' }, "data-type": props.type, className: "listbox-item-with-icon", "aria-label": props.label, children: [_jsx("div", { "aria-hidden": true, className: "listbox-item-icon", children: getIconComponent(props.type) }), _jsx("span", { className: "listbox-item-label", children: props.label })] })) }) }) }));
93
+ };
94
+ export default ListBoxPane;
@@ -0,0 +1,39 @@
1
+ import { type FormSchema, type FormComponent } from '../../types/FormSchema';
2
+ import { type FieldDragStartedEventArgs, type FieldDraggingOverEventArgs, type FieldDroppedEventArgs } from '../../FormBuilder';
3
+ import React from 'react';
4
+ interface MainSectionProps {
5
+ formSchema: FormSchema;
6
+ enablePreview?: boolean;
7
+ activeFieldId?: string;
8
+ className?: string;
9
+ mode?: 'Simple' | 'Developer';
10
+ paletteConfig?: any;
11
+ onDrop: (component: FormComponent, dropTargetIndex?: number | null, dropPosition?: 'before' | 'after' | null) => void;
12
+ onNestedDrop: (parentId: string, component: FormComponent, cellInfo?: {
13
+ row: number;
14
+ col: number;
15
+ tabIndex?: number;
16
+ }, parentPath?: string, dropTargetIndex?: number | null, dropPosition?: 'before' | 'after' | null) => void;
17
+ onReorder: (newComponents: FormComponent[]) => void;
18
+ onNestedReorder: (parentId: string, parentPath: string, newChildren: FormComponent[], cellInfo?: {
19
+ row?: number;
20
+ col?: number;
21
+ tabIndex?: number;
22
+ }) => void;
23
+ onDelete: (fieldId: string, isReordering?: boolean) => void;
24
+ onEdit: (fieldId: string) => void;
25
+ onCopy: (field: FormComponent) => void;
26
+ onPaste: (targetFieldId: string) => void;
27
+ onDeleteAction: (fieldId: string) => void;
28
+ onSwitchWidget?: (fieldId: string, newWidgetTypePascal: string) => void;
29
+ hasClipboardData?: boolean;
30
+ onFieldDragStarted?: (args: FieldDragStartedEventArgs) => void;
31
+ onFieldDraggingOver?: (args: FieldDraggingOverEventArgs) => void;
32
+ onFieldDropped?: (args: FieldDroppedEventArgs) => void;
33
+ }
34
+ export declare const isDefaultFormSchema: (schema: FormSchema) => boolean;
35
+ export interface MainSectionRef {
36
+ getGridRefs: () => Record<string, React.RefObject<any>>;
37
+ }
38
+ declare const MainSection: React.ForwardRefExoticComponent<MainSectionProps & React.RefAttributes<MainSectionRef>>;
39
+ export default MainSection;