@topconsultnpm/sdkui-react-beta 6.13.65 → 6.13.67

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.
@@ -1,478 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useMemo, useState } from 'react';
3
- import { flattenPanels, isAtLeastOnePanelVisible, isPanelArray } from './TMPanelManagerUtils';
4
- import { SDKUI_Globals, IconInfo, SDKUI_Localizator } from '../../helper';
5
- import { useDeviceType, DeviceType } from './TMDeviceProvider';
6
- import TMPanel from './TMPanel';
7
- import TMPanelManagerToolbar from './TMPanelManagerToolbar';
8
- const TMPanelManager = (props) => {
9
- const { panels, initialMobilePanelId, showToolbar = true, toolbarMode = 0, gutters = SDKUI_Globals.userSettings.themeSettings.gutters, minPanelPercent = 5 } = props;
10
- const deviceType = useDeviceType();
11
- let isMobile = useMemo(() => { return deviceType === DeviceType.MOBILE; }, [deviceType]);
12
- const allPanels = useMemo(() => flattenPanels(panels), [panels]);
13
- const panelMap = useMemo(() => {
14
- const map = new Map();
15
- allPanels.forEach(p => map.set(p.fullId, p));
16
- return map;
17
- }, [allPanels]);
18
- // Active buttons state & panel map
19
- const [activeButtons, setActiveButtons] = useState({});
20
- const [originalSizes, setOriginalSizes] = useState(new Map());
21
- const [panelsState, setPanelsState] = useState(new Map());
22
- const [maximizedPanelPath, setMaximizedPanelPath] = useState([]);
23
- const [isRowDragging, setIsRowDragging] = useState(null);
24
- const [isColumnDragging, setIsColumnDragging] = useState(null);
25
- const [updatedDisabledButton, setUpdatedDisabledButton] = useState(undefined);
26
- const [updatedVisibleButton, setUpdatedVisibleButton] = useState(undefined);
27
- // Initialize two new Maps to store panel state and their original sizes
28
- useEffect(() => {
29
- const newState = new Map();
30
- const newOriginalSizes = new Map();
31
- // Recursive function to initialize panel map data
32
- const initPanelsMap = (panels, parentPath = '') => {
33
- panels.forEach(panel => {
34
- // Skip if the panel has no contentOptions
35
- if (!panel.contentOptions)
36
- return;
37
- // Construct a unique full ID for each panel based on its parent path
38
- const fullId = parentPath ? `${parentPath}.${panel.id}` : panel.id;
39
- // Use default values '0' if width/height is not provided
40
- const width = panel.contentOptions.width;
41
- const height = panel.contentOptions.height;
42
- // Check if the panel contains nested children
43
- const hasChildren = Array.isArray(panel.contentOptions.content);
44
- // Store the original width and height for future reference
45
- newOriginalSizes.set(fullId, { width, height });
46
- // Determine the layout orientation
47
- // A panel is considered a "column" layout if height is 100% and width isn't.
48
- // A panel is considered a "row" layout if width is 100% and height isn't.
49
- const isColumn = height === '100%' && width !== '100%';
50
- const isRow = width === '100%' && height !== '100%';
51
- // Save the current panel's state including dimensions and layout direction
52
- newState.set(fullId, { width, height, isColumn, isRow, });
53
- // If the panel has nested children, recursively initialize their states
54
- if (hasChildren) {
55
- initPanelsMap(panel.contentOptions.content, fullId);
56
- }
57
- });
58
- };
59
- initPanelsMap(panels);
60
- setOriginalSizes(newOriginalSizes);
61
- setPanelsState(newState);
62
- }, [panels]);
63
- useEffect(() => {
64
- if (allPanels.length > 0) {
65
- const initialButtons = Object.fromEntries(allPanels.map(p => [p.fullId, p.config.toolbarOptions?.isActive ?? false]));
66
- setActiveButtons(initialButtons);
67
- }
68
- }, [allPanels]);
69
- useEffect(() => {
70
- // If there are no original sizes available, exit early
71
- if (!originalSizes.size)
72
- return;
73
- // Clone the current state of the panels into a new Map to modify it safely
74
- const newState = new Map(panelsState);
75
- // Helper function to check if a panel is currently maximized
76
- const isMaximized = (panelId) => maximizedPanelPath.includes(panelId);
77
- // Iterate through all panel sizes stored in originalSizes
78
- for (const [panelId, sizes] of originalSizes.entries()) {
79
- const currentPanel = newState.get(panelId);
80
- if (!currentPanel) {
81
- // If for some reason the panel doesn't exist in state, skip it
82
- continue;
83
- }
84
- if (isMaximized(panelId)) {
85
- // If the panel is maximized, set its dimensions to take up the full available space
86
- newState.set(panelId, { ...currentPanel, width: '100%', height: '100%' });
87
- }
88
- else if (maximizedPanelPath.length > 0) {
89
- // If at least one panel is maximized, collapse all others to zero size
90
- newState.set(panelId, { ...currentPanel, width: '0%', height: '0%' });
91
- }
92
- else {
93
- // If no panels are maximized, restore their original dimensions
94
- newState.set(panelId, { ...currentPanel, width: sizes.width, height: sizes.height });
95
- }
96
- }
97
- // Apply the updated panel states
98
- setPanelsState(newState);
99
- // Run this effect whenever maximizedPanelPath or originalSizes change
100
- }, [maximizedPanelPath, originalSizes]);
101
- useEffect(() => {
102
- const isDragging = isColumnDragging || isRowDragging;
103
- // Handles the end of dragging (mouse release)
104
- const onMouseUp = () => {
105
- setIsColumnDragging(null);
106
- setIsRowDragging(null);
107
- document.body.style.userSelect = '';
108
- };
109
- // Handles column resizing during dragging
110
- const onColumnMouseMove = (e) => {
111
- if (!isColumnDragging)
112
- return;
113
- const columnKeys = getKeysByOrientation('column');
114
- const currentIndex = columnKeys.indexOf(isColumnDragging);
115
- const nextKey = columnKeys[currentIndex + 1];
116
- if (!nextKey)
117
- return;
118
- const deltaPercent = (e.movementX / window.innerWidth) * 100;
119
- resizePanels(columnKeys, currentIndex, nextKey, deltaPercent, 'width');
120
- };
121
- // Handles row resizing during dragging
122
- const onRowMouseMove = (e) => {
123
- if (!isRowDragging)
124
- return;
125
- const rowKeys = getKeysByOrientation('row');
126
- const currentIndex = rowKeys.indexOf(isRowDragging);
127
- const nextKey = rowKeys[currentIndex + 1];
128
- if (!nextKey)
129
- return;
130
- const deltaPercent = (e.movementY / window.innerHeight) * 100;
131
- resizePanels(rowKeys, currentIndex, nextKey, deltaPercent, 'height');
132
- };
133
- // Returns panel keys that match the given orientation (row or column)
134
- const getKeysByOrientation = (type) => {
135
- return Array.from(panelsState.entries())
136
- .filter(([_, value]) => (type === 'row' ? value.isRow : value.isColumn))
137
- .map(([key]) => key);
138
- };
139
- // Shared resizing logic for both rows and columns
140
- const resizePanels = (keys, currentIndex, nextKey, deltaPercent, dimension) => {
141
- setPanelsState(prev => {
142
- const updated = new Map(prev);
143
- const updatedOriginalSizes = new Map(originalSizes);
144
- const currentKey = keys[currentIndex];
145
- const currentSize = parseFloat(updated.get(currentKey)?.[dimension] || '0');
146
- const nextSize = parseFloat(updated.get(nextKey)?.[dimension] || '0');
147
- const total = currentSize + nextSize;
148
- let newCurrent = Math.min(currentSize + deltaPercent, 100);
149
- let newNext = Math.min(nextSize - deltaPercent, 100);
150
- // Enforce minimum panel size
151
- if (newCurrent < minPanelPercent) {
152
- newCurrent = minPanelPercent;
153
- newNext = total - newCurrent;
154
- }
155
- else if (newNext < minPanelPercent) {
156
- newNext = minPanelPercent;
157
- newCurrent = total - newNext;
158
- }
159
- // Safely get current and next panel data
160
- const currentPanel = updated.get(currentKey);
161
- const nextPanel = updated.get(nextKey);
162
- // Ensure both panels exist before updating
163
- if (!currentPanel || !nextPanel)
164
- return prev;
165
- // Update panel dimensions
166
- updated.set(currentKey, { ...currentPanel, [dimension]: `${newCurrent}%` });
167
- updated.set(nextKey, { ...nextPanel, [dimension]: `${newNext}%` });
168
- // Update original sizes for persistence
169
- updatedOriginalSizes.set(currentKey, { ...currentPanel, [dimension]: `${newCurrent}%` });
170
- updatedOriginalSizes.set(nextKey, { ...nextPanel, [dimension]: `${newNext}%` });
171
- setOriginalSizes(updatedOriginalSizes);
172
- return updated;
173
- });
174
- };
175
- // Add event listeners when dragging starts
176
- if (isDragging) {
177
- if (isColumnDragging) {
178
- window.addEventListener('mousemove', onColumnMouseMove);
179
- }
180
- else if (isRowDragging) {
181
- window.addEventListener('mousemove', onRowMouseMove);
182
- }
183
- window.addEventListener('mouseup', onMouseUp);
184
- document.body.style.userSelect = 'none'; // Prevents text selection during drag
185
- }
186
- // Cleanup function to remove event listeners
187
- return () => {
188
- window.removeEventListener('mousemove', onColumnMouseMove);
189
- window.removeEventListener('mousemove', onRowMouseMove);
190
- window.removeEventListener('mouseup', onMouseUp);
191
- document.body.style.userSelect = '';
192
- };
193
- }, [isColumnDragging, isRowDragging, panelsState, originalSizes]);
194
- useEffect(() => {
195
- if (isMobile) {
196
- setActiveButtons(prev => {
197
- // Clone the previous state to avoid mutating it directly
198
- const newActive = { ...prev };
199
- // Get the panel object from the panel map
200
- const panel = panelMap.get(initialMobilePanelId);
201
- Object.keys(newActive).forEach(panelId => {
202
- newActive[panelId] = false;
203
- });
204
- // Toggle the selected panel's visibility
205
- newActive[initialMobilePanelId] = true;
206
- // If the panel is being hidden and has children, recursively hide its children
207
- if (panel && panel.childrenIds.length > 0 && !newActive[initialMobilePanelId]) {
208
- const hideChildrenRecursively = (ids) => {
209
- ids.forEach(childId => {
210
- newActive[childId] = false;
211
- const childPanel = panelMap.get(childId);
212
- if (childPanel?.childrenIds.length) {
213
- hideChildrenRecursively(childPanel.childrenIds);
214
- }
215
- });
216
- };
217
- hideChildrenRecursively(panel.childrenIds);
218
- }
219
- // After toggling, ensure the visibility of parent panels is in sync with their children
220
- if (panel?.parentId) {
221
- syncParentVisibilityWithChildren(panel.parentId, newActive);
222
- }
223
- // Return the updated visibility map
224
- return newActive;
225
- });
226
- }
227
- }, [isMobile, panelMap]);
228
- // Handler for starting to drag a column divider (for resizing panels horizontally)
229
- const onColumnMouseDown = (panelKey) => {
230
- setIsColumnDragging(panelKey); // Set the state to indicate which column is being dragged
231
- };
232
- // Handler for starting to drag a row divider (for resizing panels vertically)
233
- const onRowMouseDown = (rowKey) => {
234
- setIsRowDragging(rowKey); // Set the state to indicate which row is being dragged
235
- };
236
- // Function to disable a toolbar button by its ID
237
- const handleDisableButton = (id, value) => {
238
- // Update state to inform toolbar which button should be disabled/enabled
239
- setUpdatedDisabledButton({ id, value });
240
- };
241
- // Function to change the visibility of a toolbar button by its ID
242
- const handleVisibilityButton = (id, value) => {
243
- // Update state to inform toolbar which button should be shown/hidden
244
- setUpdatedVisibleButton({ id, value });
245
- };
246
- /**
247
- * Recursively updates the visibility status of parent panels based on the visibility of their child panels.
248
- * If all children are hidden, the parent is hidden.
249
- * If at least one child is visible, the parent is shown. Propagates visibility changes up the tree.
250
- */
251
- const syncParentVisibilityWithChildren = (panelId, visibleMap) => {
252
- const panel = panelMap.get(panelId);
253
- if (!panel || panel.childrenIds.length === 0)
254
- return;
255
- const allChildrenHidden = panel.childrenIds.every(id => !visibleMap[id]);
256
- if (allChildrenHidden && visibleMap[panelId]) {
257
- visibleMap[panelId] = false;
258
- if (panel.parentId) {
259
- syncParentVisibilityWithChildren(panel.parentId, visibleMap);
260
- }
261
- }
262
- else if (!allChildrenHidden && !visibleMap[panelId]) {
263
- visibleMap[panelId] = true;
264
- }
265
- };
266
- /**
267
- * Toggles the maximized state of a panel based on its full ID.
268
- * If the panel is already maximized (i.e., the maximized path matches its hierarchy path),
269
- * it will be unmaximized. Otherwise, it will be maximized along with its ancestor panels.
270
- * The full dot-separated ID of the panel (e.g., "root.section.panel")
271
- */
272
- const handleToggleMaximize = (fullId) => {
273
- // Split the full panel ID into its segments (e.g., ["root", "section", "panel"])
274
- const segments = fullId.split('.');
275
- // Build the full path hierarchy up to this panel (e.g., ["root", "root.section", "root.section.panel"])
276
- const path = segments.map((_, i) => segments.slice(0, i + 1).join('.'));
277
- // Check if this panel is already maximized by comparing path arrays
278
- const isAlreadyMaximized = maximizedPanelPath.length === path.length && maximizedPanelPath.every((v, i) => v === path[i]);
279
- if (isAlreadyMaximized) {
280
- // Unmaximize by clearing the maximized path
281
- setMaximizedPanelPath([]);
282
- }
283
- else {
284
- // Maximize this panel and its parent hierarchy
285
- setMaximizedPanelPath(path);
286
- }
287
- };
288
- /**
289
- * Toggles the active (visible) state of a panel by its ID.
290
- * - On **desktop**, the panel's visibility is toggled independently,
291
- * and if the panel is hidden, all its child panels are also recursively hidden.
292
- * - On **mobile**, only one panel can be visible at a time:
293
- * activating a panel will hide all others, including their children.
294
- * After updating visibility, the function also ensures that each parent panel's
295
- * visibility is synchronized with the state of its children.
296
- *
297
- */
298
- const handleTogglePanel = (id) => {
299
- // If the panel is currently maximized, toggle its maximization state first
300
- if (maximizedPanelPath.includes(id)) {
301
- handleToggleMaximize(id);
302
- }
303
- // Update the activeButtons state
304
- setActiveButtons(prev => {
305
- // Clone the previous state to avoid mutating it directly
306
- const newActive = { ...prev };
307
- // Get the panel object from the panel map
308
- const panel = panelMap.get(id);
309
- // Determine if the current panel is currently visible
310
- const currentlyVisible = !!newActive[id];
311
- // Mobile-specific behavior: only one panel can be visible at a time
312
- if (isMobile) {
313
- // Hide all panels
314
- Object.keys(newActive).forEach(panelId => {
315
- newActive[panelId] = false;
316
- });
317
- // Toggle the selected panel's visibility
318
- newActive[id] = !currentlyVisible;
319
- // If the panel is being hidden and has children, recursively hide its children
320
- if (panel && panel.childrenIds.length > 0 && !newActive[id]) {
321
- const hideChildrenRecursively = (ids) => {
322
- ids.forEach(childId => {
323
- newActive[childId] = false;
324
- const childPanel = panelMap.get(childId);
325
- if (childPanel?.childrenIds.length) {
326
- hideChildrenRecursively(childPanel.childrenIds);
327
- }
328
- });
329
- };
330
- hideChildrenRecursively(panel.childrenIds);
331
- }
332
- }
333
- else {
334
- // Desktop behavior: toggle visibility of the selected panel
335
- if (!currentlyVisible) {
336
- // If the panel is currently not visible (we are activating it)
337
- if (panel?.alternativePanelIds.length) {
338
- // If the panel has alternative panels defined
339
- panel.alternativePanelIds.forEach(altId => {
340
- // Deactivate each alternative panel
341
- newActive[altId] = false;
342
- });
343
- }
344
- // Activate the selected panel
345
- newActive[id] = true;
346
- }
347
- else {
348
- // The panel is currently visible, so we are deactivating it
349
- newActive[id] = false;
350
- }
351
- // If hiding the panel and it has children, hide them recursively
352
- if (panel && panel.childrenIds.length > 0 && !newActive[id]) {
353
- const hideChildrenRecursively = (ids) => {
354
- ids.forEach(childId => {
355
- newActive[childId] = false;
356
- const childPanel = panelMap.get(childId);
357
- if (childPanel?.childrenIds.length) {
358
- hideChildrenRecursively(childPanel.childrenIds);
359
- }
360
- });
361
- };
362
- hideChildrenRecursively(panel.childrenIds);
363
- }
364
- }
365
- // After toggling, ensure the visibility of parent panels is in sync with their children
366
- if (panel?.parentId) {
367
- syncParentVisibilityWithChildren(panel.parentId, newActive);
368
- }
369
- // Return the updated visibility map
370
- return newActive;
371
- });
372
- };
373
- // Render panels
374
- const renderPanels = (panels, parentPath = '', direction = 'horizontal') => {
375
- const visiblePanels = panels.filter(p => {
376
- const fullId = parentPath ? `${parentPath}.${p.id}` : p.id;
377
- return p.contentOptions?.content && activeButtons[fullId];
378
- });
379
- const keys = visiblePanels.map(p => (parentPath ? `${parentPath}.${p.id}` : p.id));
380
- const totalSize = keys.reduce((sum, key) => {
381
- const entry = panelsState.get(key);
382
- const size = parseFloat(direction === 'horizontal' ? entry?.width || '0' : entry?.height || '0');
383
- return sum + size;
384
- }, 0);
385
- const sizeMap = Object.fromEntries(keys.map(key => {
386
- const entry = panelsState.get(key);
387
- const size = parseFloat(direction === 'horizontal' ? entry?.width || '0' : entry?.height || '0');
388
- const percent = totalSize > 0 ? (size / totalSize) * 100 : 0;
389
- return [key, `${percent}%`];
390
- }));
391
- return panels.map(panel => {
392
- if (!panel.contentOptions)
393
- return null;
394
- const fullId = parentPath ? `${parentPath}.${panel.id}` : panel.id;
395
- const isActive = activeButtons[fullId];
396
- const hasChildren = isPanelArray(panel.contentOptions?.content);
397
- const isLastVisible = keys.indexOf(fullId) === keys.length - 1;
398
- const flexDirection = direction === 'horizontal' ? 'row' : 'column';
399
- const panelStyle = {
400
- display: 'flex',
401
- flexDirection,
402
- width: direction === 'horizontal' ? (isActive ? sizeMap[fullId] : '0%') : '100%',
403
- height: direction === 'vertical' ? (isActive ? sizeMap[fullId] : '0%') : '100%',
404
- visibility: isActive ? 'visible' : 'hidden',
405
- overflow: 'hidden',
406
- position: 'relative',
407
- };
408
- const contentStyle = {
409
- flexGrow: 1,
410
- overflow: 'auto',
411
- };
412
- return (_jsxs("div", { style: panelStyle, children: [_jsx("div", { style: contentStyle, children: hasChildren
413
- ? renderPanels(panel.contentOptions.content, fullId, 'vertical')
414
- : panel.contentOptions?.panelContainer ? _jsx(TMPanel, { title: panel.contentOptions.panelContainer.title, totalItems: panel.contentOptions.panelContainer.totalItems, displayedItemsCount: panel.contentOptions.panelContainer.displayedItemsCount, onBack: panel.contentOptions.panelContainer.onBack, onClose: () => handleTogglePanel(fullId), onMaximize: () => handleToggleMaximize(fullId), onHeaderDoubleClick: () => handleToggleMaximize(fullId), allowMaximize: !isMobile, toolbar: panel.contentOptions.panelContainer.toolbar, children: typeof panel.contentOptions.content === "function" ? panel.contentOptions.content(handleTogglePanel, handleToggleMaximize, handleVisibilityButton, handleDisableButton) : panel.contentOptions.content })
415
- :
416
- typeof panel.contentOptions.content === "function" ? panel.contentOptions.content(handleTogglePanel, handleToggleMaximize, handleVisibilityButton, handleDisableButton) : panel.contentOptions.content }), !isLastVisible && isActive && maximizedPanelPath.length === 0 && (_jsx("div", { style: {
417
- cursor: direction === 'horizontal' ? 'col-resize' : 'row-resize',
418
- userSelect: 'none',
419
- flexShrink: 0,
420
- backgroundColor: 'transparent',
421
- width: direction === 'horizontal' ? '4px' : '100%',
422
- height: direction === 'vertical' ? '4px' : '100%',
423
- marginLeft: maximizedPanelPath.length === 0 && direction === 'horizontal' ? `${(gutters - 4) / 2}px` : undefined,
424
- marginTop: maximizedPanelPath.length === 0 && direction === 'vertical' ? `${(gutters - 4) / 2}px` : undefined,
425
- marginRight: maximizedPanelPath.length === 0 && direction === 'horizontal' ? `${(gutters - 4) / 2}px` : undefined,
426
- marginBottom: maximizedPanelPath.length === 0 && direction === 'vertical' ? `${(gutters - 4) / 2}px` : undefined,
427
- }, onMouseDown: () => {
428
- if (direction === 'horizontal') {
429
- onColumnMouseDown(fullId);
430
- }
431
- else {
432
- onRowMouseDown(fullId);
433
- }
434
- } }))] }, fullId));
435
- });
436
- };
437
- return (_jsxs("div", { style: { display: 'flex', flexDirection: isMobile ? 'column' : 'row', height: '100%', width: '100%', gap: !isMobile ? gutters : 0 }, children: [_jsx("div", { style: {
438
- display: 'flex',
439
- flexGrow: 1,
440
- width: isAtLeastOnePanelVisible(activeButtons) ? `calc(100% - ${showToolbar ? (isMobile ? 0 : 70) : 0}px)` : '0%',
441
- height: isAtLeastOnePanelVisible(activeButtons) ? `calc(100% - ${isMobile ? 55 : 0}px)` : '0%',
442
- visibility: isAtLeastOnePanelVisible(activeButtons) ? 'visible' : 'hidden',
443
- flexDirection: 'row',
444
- }, children: renderPanels(panels, '', 'horizontal') }), !isAtLeastOnePanelVisible(activeButtons) && (_jsxs("div", { style: {
445
- width: `calc(100% - ${showToolbar ? (isMobile ? 0 : 70) : 0}px)`,
446
- height: `calc(100% - ${isMobile ? 55 : 0}px)`,
447
- display: 'flex',
448
- flexDirection: 'column',
449
- alignItems: 'center',
450
- justifyContent: 'center',
451
- backgroundColor: '#fff',
452
- borderRadius: '12px',
453
- textAlign: 'center',
454
- color: '#555',
455
- fontSize: '18px',
456
- }, children: [_jsx(IconInfo, { style: { fontSize: 50 } }), _jsx("div", { children: SDKUI_Localizator.NoPanelSelected })] })), showToolbar && _jsx("div", { style: toolbarMode === 0 ? {
457
- width: isMobile ? '100%' : '50px',
458
- height: isMobile ? '50px' : '100%',
459
- borderLeft: '1px solid #ccc',
460
- display: 'flex',
461
- flexDirection: isMobile ? 'row' : 'column',
462
- padding: '10px',
463
- boxSizing: 'border-box',
464
- gap: '10px',
465
- backgroundColor: '#f9f9f9',
466
- } : {
467
- display: 'flex',
468
- flexDirection: isMobile ? 'row' : 'column',
469
- alignItems: 'center',
470
- width: isMobile ? '100%' : '50px',
471
- height: isMobile ? '50px' : 'max-content',
472
- background: 'transparent linear-gradient(90deg, #CCE0F4 0%, #7EC1E7 14%, #39A6DB 28%, #1E9CD7 35%, #0075BE 78%, #005B97 99%) 0% 0% no-repeat padding-box',
473
- borderRadius: isMobile ? '10px' : '10px 0px 0px 10px',
474
- padding: '10px',
475
- gap: '10px'
476
- }, children: _jsx(TMPanelManagerToolbar, { allPanels: allPanels, activeButtons: activeButtons, handleTogglePanel: handleTogglePanel, updatedDisabledButton: updatedDisabledButton, updatedVisibleButton: updatedVisibleButton, toolbarMode: toolbarMode }) })] }));
477
- };
478
- export default TMPanelManager;
@@ -1,23 +0,0 @@
1
- import React from 'react';
2
- import { TMPanelEntry } from './TMPanelManagerUtils';
3
- interface TNPanelManagerToolbarProps {
4
- allPanels: Array<TMPanelEntry>;
5
- activeButtons: Record<string, boolean>;
6
- handleTogglePanel: (id: string) => void;
7
- updatedDisabledButton?: {
8
- id: string;
9
- value: boolean;
10
- };
11
- updatedVisibleButton?: {
12
- id: string;
13
- value: boolean;
14
- };
15
- toolbarMode?: number;
16
- }
17
- declare const TMPanelManagerToolbar: (props: TNPanelManagerToolbarProps) => import("react/jsx-runtime").JSX.Element;
18
- export default TMPanelManagerToolbar;
19
- export declare const StyledToolbarButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
20
- $toolbarMode?: number;
21
- $isActive?: boolean;
22
- $isDisabled?: boolean;
23
- }>> & string;
@@ -1,109 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useEffect, useMemo, useState } from 'react';
3
- import styled from 'styled-components';
4
- import { useDeviceType, DeviceType } from './TMDeviceProvider';
5
- import TMTooltip from './TMTooltip';
6
- const TMPanelManagerToolbar = (props) => {
7
- const { allPanels, activeButtons, handleTogglePanel, updatedDisabledButton, updatedVisibleButton, toolbarMode = 0 } = props;
8
- const deviceType = useDeviceType();
9
- let isMobile = useMemo(() => { return deviceType === DeviceType.MOBILE; }, [deviceType]);
10
- const [filteredPanels, setFilteredPanels] = useState([]);
11
- const [disabledButtons, setDisabledButtons] = useState({});
12
- const [visibleButtons, setVisibleButtons] = useState({});
13
- // Initialize visibility and disabled states
14
- useEffect(() => {
15
- const visible = {};
16
- const disabled = {};
17
- const filtered = allPanels
18
- .filter((p) => {
19
- const vis = !!p.config.toolbarOptions?.visible;
20
- visible[p.fullId] = vis;
21
- disabled[p.fullId] = !!p.config.toolbarOptions?.disabled;
22
- return vis;
23
- })
24
- .sort((a, b) => (a.config.toolbarOptions?.orderNumber ?? 0) - (b.config.toolbarOptions?.orderNumber ?? 0));
25
- setVisibleButtons(visible);
26
- setDisabledButtons(disabled);
27
- setFilteredPanels(filtered);
28
- }, [allPanels]);
29
- // Update disabled button
30
- useEffect(() => {
31
- if (updatedDisabledButton) {
32
- setDisabledButtons((prev) => ({
33
- ...prev,
34
- [updatedDisabledButton.id]: updatedDisabledButton.value,
35
- }));
36
- }
37
- }, [updatedDisabledButton]);
38
- // Update visible button
39
- useEffect(() => {
40
- if (updatedVisibleButton) {
41
- const { id, value } = updatedVisibleButton;
42
- setVisibleButtons((prev) => ({ ...prev, [id]: value }));
43
- setFilteredPanels((prev) => {
44
- if (value) {
45
- const newPanel = allPanels.find((p) => p.fullId === id);
46
- if (newPanel && !prev.some((p) => p.fullId === id)) {
47
- return [...prev, newPanel].sort((a, b) => (a.config.toolbarOptions?.orderNumber ?? 0) - (b.config.toolbarOptions?.orderNumber ?? 0));
48
- }
49
- return prev;
50
- }
51
- else {
52
- return prev.filter((p) => p.fullId !== id);
53
- }
54
- });
55
- }
56
- }, [updatedVisibleButton, allPanels]);
57
- return (_jsx("div", { style: {
58
- display: 'flex',
59
- flexDirection: isMobile ? 'row' : 'column',
60
- gap: '6px',
61
- // alignItems: isMobile ? 'center' : 'flex-start',
62
- alignItems: 'center',
63
- justifyContent: isMobile ? 'center' : 'flex-start',
64
- width: '100%',
65
- height: '100%',
66
- }, children: filteredPanels.map((p, idx) => {
67
- const isActive = activeButtons[p.fullId];
68
- const handleClick = p.config.buttonOptions?.onClick;
69
- const isToolbarDisabled = disabledButtons[p.fullId];
70
- // Separator JSX if beginGroup is true and NOT first button (otherwise no separator before first button)
71
- const separator = (p.config.toolbarOptions?.beginGroup && idx > 0) ? (_jsx("div", { style: {
72
- width: isMobile ? '1px' : '80%',
73
- height: isMobile ? '80%' : '1px',
74
- backgroundColor: '#ccc',
75
- margin: isMobile ? '0 6px' : '6px 0',
76
- alignSelf: 'center',
77
- } }, `sep-${p.fullId}`)) : null;
78
- // Button JSX
79
- const button = (_jsx(TMTooltip, { content: p.config.name, position: isMobile ? 'top' : 'left', children: _jsx(StyledToolbarButton, { "$toolbarMode": toolbarMode, "$isActive": isActive || p.config.toolbarOptions?.alwaysActiveColor, "$isDisabled": isToolbarDisabled, disabled: isToolbarDisabled, onClick: () => { handleTogglePanel(p.fullId); if (handleClick)
80
- handleClick(); }, onMouseEnter: (e) => { if (!isToolbarDisabled && toolbarMode === 0) {
81
- e.currentTarget.style.transform = 'scale(1.1)';
82
- } }, onMouseLeave: (e) => { e.currentTarget.style.transform = 'scale(1)'; }, children: typeof p.config.toolbarOptions?.icon === 'string' ? (_jsx("i", { className: `dx-icon dx-icon-${p.config.toolbarOptions?.icon}` })) : (p.config.toolbarOptions?.icon) }) }, p.fullId));
83
- // Return separator first, then button
84
- return [separator, button];
85
- }) }));
86
- };
87
- export default TMPanelManagerToolbar;
88
- export const StyledToolbarButton = styled.button `
89
- display: flex;
90
- align-items: center;
91
- justify-content: center;
92
- height: ${({ $toolbarMode }) => ($toolbarMode === 0 ? '40px' : '32px')};
93
- width: ${({ $toolbarMode }) => ($toolbarMode === 0 ? '40px' : '32px')};
94
- border: none;
95
- border-radius: ${({ $toolbarMode }) => ($toolbarMode === 0 ? '10px' : '8px')};
96
- font-size: 18px;
97
- padding: ${({ $toolbarMode }) => ($toolbarMode === 0 ? '8px 10px' : '0px')}; ;
98
- color: #fff;
99
- transition: transform 0.2s ease, box-shadow 0.2s ease;
100
- cursor: ${({ $isDisabled }) => ($isDisabled ? 'not-allowed' : 'pointer')};
101
- opacity: ${({ $isDisabled }) => ($isDisabled ? 0.6 : 1)};
102
- background: ${({ $toolbarMode, $isActive }) => $toolbarMode === 0
103
- ? ($isActive ? '#81c784' : '#e57373')
104
- : ($isActive ? 'rgba(255,255,255,0.35)' : 'transparent')};
105
-
106
- &:hover {
107
- background: ${({ $toolbarMode, $isDisabled }) => $toolbarMode !== 0 && !$isDisabled ? 'rgba(255,255,255,0.35)' : undefined};
108
- }
109
- `;
@@ -1,37 +0,0 @@
1
- import { ITMPanelProps } from "./TMPanel";
2
- export type TMPanelItemConfig = {
3
- id: string;
4
- name: string;
5
- type: 'content' | 'button';
6
- alternativePanelIds?: Array<string>;
7
- buttonOptions?: {
8
- onClick: () => void;
9
- };
10
- contentOptions?: {
11
- height: string;
12
- width: string;
13
- visible?: boolean;
14
- content?: JSX.Element | ((handleTogglePanel: (id: string) => void, handleToggleMaximize: (fullId: string) => void, handleVisibilityButton: (id: string, value: boolean) => void, handleDisableButton: (id: string, value: boolean) => void) => JSX.Element) | Array<TMPanelItemConfig>;
15
- panelContainer?: ITMPanelProps;
16
- };
17
- toolbarOptions?: {
18
- icon: string | JSX.Element;
19
- isActive: boolean;
20
- visible: boolean;
21
- disabled?: boolean;
22
- orderNumber?: number;
23
- beginGroup?: boolean;
24
- alwaysActiveColor?: boolean;
25
- };
26
- };
27
- export type TMPanelEntry = {
28
- fullId: string;
29
- config: TMPanelItemConfig;
30
- parentId: string | null;
31
- childrenIds: Array<string>;
32
- alternativePanelIds: Array<string>;
33
- };
34
- export declare const isPanelArray: (content: unknown) => content is Array<TMPanelItemConfig>;
35
- export declare const flattenPanels: (panels: Array<TMPanelItemConfig>, parentId?: string | null, parentPath?: string) => Array<TMPanelEntry>;
36
- export declare const isAtLeastOnePanelVisible: (activeButtons: Record<string, boolean>) => boolean;
37
- export declare const isExactlyOnePanelVisible: (activeButtons: Record<string, boolean>) => boolean;