@topconsultnpm/sdkui-react 6.20.0-dev1.7 → 6.20.0-dev1.70

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 (116) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +258 -17
  2. package/lib/components/NewComponents/ContextMenu/hooks.d.ts +2 -0
  3. package/lib/components/NewComponents/ContextMenu/hooks.js +17 -4
  4. package/lib/components/NewComponents/ContextMenu/index.d.ts +3 -0
  5. package/lib/components/NewComponents/ContextMenu/index.js +2 -0
  6. package/lib/components/NewComponents/ContextMenu/styles.d.ts +5 -1
  7. package/lib/components/NewComponents/ContextMenu/styles.js +59 -31
  8. package/lib/components/NewComponents/ContextMenu/types.d.ts +13 -0
  9. package/lib/components/NewComponents/ContextMenu/useLongPress.d.ts +21 -0
  10. package/lib/components/NewComponents/ContextMenu/useLongPress.js +112 -0
  11. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +517 -100
  12. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +19 -5
  13. package/lib/components/NewComponents/FloatingMenuBar/styles.js +206 -54
  14. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +1 -2
  15. package/lib/components/base/TMAccordionNew.js +35 -14
  16. package/lib/components/base/TMCustomButton.js +61 -17
  17. package/lib/components/base/TMDataGrid.d.ts +7 -4
  18. package/lib/components/base/TMDataGrid.js +142 -11
  19. package/lib/components/base/TMDropDownMenu.js +19 -18
  20. package/lib/components/base/TMPanel.js +1 -1
  21. package/lib/components/choosers/TMInvoiceRetrieveFormats.js +1 -1
  22. package/lib/components/choosers/TMMetadataChooser.js +8 -1
  23. package/lib/components/choosers/TMOrderRetrieveFormats.js +1 -1
  24. package/lib/components/choosers/TMUserChooser.d.ts +0 -5
  25. package/lib/components/choosers/TMUserChooser.js +25 -45
  26. package/lib/components/editors/TMMetadataValues.js +23 -5
  27. package/lib/components/editors/TMTextBox.js +6 -3
  28. package/lib/components/features/documents/TMDcmtForm.d.ts +13 -1
  29. package/lib/components/features/documents/TMDcmtForm.js +386 -194
  30. package/lib/components/features/documents/TMDcmtPreview.js +41 -105
  31. package/lib/components/features/documents/TMMasterDetailDcmts.js +37 -52
  32. package/lib/components/features/documents/TMRelationViewer.d.ts +1 -1
  33. package/lib/components/features/documents/TMRelationViewer.js +2 -2
  34. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +8 -0
  35. package/lib/components/features/search/{TMSearchResultCheckoutInfoForm.js → TMDcmtCheckoutInfoForm.js} +5 -10
  36. package/lib/components/features/search/TMSavedQuerySelector.js +72 -67
  37. package/lib/components/features/search/TMSearch.js +41 -9
  38. package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -0
  39. package/lib/components/features/search/TMSearchQueryPanel.js +19 -18
  40. package/lib/components/features/search/TMSearchResult.js +118 -242
  41. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +3 -3
  42. package/lib/components/features/search/TMSearchResultsMenuItems.js +205 -169
  43. package/lib/components/features/search/TMSignSettingsForm.js +1 -1
  44. package/lib/components/features/search/TMSignatureInfoContent.d.ts +6 -0
  45. package/lib/components/features/search/TMSignatureInfoContent.js +140 -0
  46. package/lib/components/features/search/TMViewHistoryDcmt.js +1 -1
  47. package/lib/components/features/tasks/TMTaskForm.js +20 -1
  48. package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
  49. package/lib/components/features/tasks/TMTasksUtils.js +62 -52
  50. package/lib/components/features/tasks/TMTasksView.js +6 -6
  51. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +33 -2
  52. package/lib/components/features/workflow/TMWorkflowPopup.js +134 -24
  53. package/lib/components/features/workflow/diagram/DiagramItemComponent.d.ts +1 -0
  54. package/lib/components/features/workflow/diagram/DiagramItemComponent.js +2 -3
  55. package/lib/components/features/workflow/diagram/RecipientList.js +3 -2
  56. package/lib/components/features/workflow/diagram/WFDiagram.d.ts +2 -0
  57. package/lib/components/features/workflow/diagram/WFDiagram.js +21 -4
  58. package/lib/components/forms/Login/LoginValidatorService.d.ts +2 -0
  59. package/lib/components/forms/Login/LoginValidatorService.js +7 -2
  60. package/lib/components/forms/Login/TMLoginForm.js +34 -6
  61. package/lib/components/forms/TMChooserForm.js +1 -1
  62. package/lib/components/grids/TMBlogsPost.js +55 -30
  63. package/lib/components/grids/TMRecentsManager.js +20 -10
  64. package/lib/components/index.d.ts +4 -0
  65. package/lib/components/index.js +4 -0
  66. package/lib/components/settings/SettingsAppearance.js +92 -29
  67. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -1
  68. package/lib/components/viewers/TMDataListItemViewer.js +35 -71
  69. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +8 -0
  70. package/lib/components/viewers/TMDataUserIdItemViewer.js +39 -0
  71. package/lib/css/tm-sdkui.css +1 -1
  72. package/lib/helper/SDKUI_Globals.d.ts +19 -0
  73. package/lib/helper/SDKUI_Globals.js +11 -0
  74. package/lib/helper/SDKUI_Localizator.d.ts +15 -1
  75. package/lib/helper/SDKUI_Localizator.js +147 -1
  76. package/lib/helper/TMIcons.d.ts +2 -0
  77. package/lib/helper/TMIcons.js +6 -0
  78. package/lib/helper/TMPdfViewer.d.ts +8 -0
  79. package/lib/helper/TMPdfViewer.js +373 -0
  80. package/lib/helper/checkinCheckoutManager.d.ts +32 -2
  81. package/lib/helper/checkinCheckoutManager.js +115 -38
  82. package/lib/helper/devextremeCustomMessages.d.ts +30 -0
  83. package/lib/helper/devextremeCustomMessages.js +30 -0
  84. package/lib/helper/helpers.d.ts +2 -1
  85. package/lib/helper/helpers.js +14 -3
  86. package/lib/helper/index.d.ts +1 -0
  87. package/lib/helper/index.js +1 -0
  88. package/lib/helper/queryHelper.d.ts +1 -1
  89. package/lib/helper/queryHelper.js +33 -3
  90. package/lib/hooks/useCheckInOutOperations.d.ts +28 -0
  91. package/lib/hooks/useCheckInOutOperations.js +223 -0
  92. package/lib/hooks/useDataListItem.d.ts +12 -0
  93. package/lib/hooks/useDataListItem.js +131 -0
  94. package/lib/hooks/useDataUserIdItem.d.ts +10 -0
  95. package/lib/hooks/useDataUserIdItem.js +96 -0
  96. package/lib/hooks/useSettingsFeedback.d.ts +11 -0
  97. package/lib/hooks/useSettingsFeedback.js +38 -0
  98. package/lib/hooks/useWorkflowApprove.d.ts +4 -0
  99. package/lib/hooks/useWorkflowApprove.js +14 -1
  100. package/lib/index.d.ts +1 -0
  101. package/lib/index.js +1 -0
  102. package/lib/ts/types.d.ts +58 -1
  103. package/lib/utils/theme.d.ts +1 -1
  104. package/lib/utils/theme.js +1 -1
  105. package/package.json +5 -2
  106. package/lib/components/NewComponents/Notification/Notification.d.ts +0 -4
  107. package/lib/components/NewComponents/Notification/Notification.js +0 -60
  108. package/lib/components/NewComponents/Notification/NotificationContainer.d.ts +0 -8
  109. package/lib/components/NewComponents/Notification/NotificationContainer.js +0 -33
  110. package/lib/components/NewComponents/Notification/index.d.ts +0 -2
  111. package/lib/components/NewComponents/Notification/index.js +0 -2
  112. package/lib/components/NewComponents/Notification/styles.d.ts +0 -21
  113. package/lib/components/NewComponents/Notification/styles.js +0 -180
  114. package/lib/components/NewComponents/Notification/types.d.ts +0 -18
  115. package/lib/components/NewComponents/Notification/types.js +0 -1
  116. package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +0 -8
@@ -1,36 +1,127 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { ContextMenu } from '../ContextMenu';
4
- import Notification from '../Notification';
4
+ import ShowAlert from '../../base/TMAlert';
5
5
  import TMTooltip from '../../base/TMTooltip';
6
6
  import * as S from './styles';
7
- import { IconApply, IconMenuKebab, IconMenuVertical, IconSettings, IconStar } from '../../../helper';
7
+ import { IconAdd, IconCloseOutline, IconMenuVertical, IconPin, IconSave, IconSeparator, IconUndo, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
8
+ import { ButtonNames, TMMessageBoxManager } from '../../base/TMPopUp';
9
+ const Separator = (props) => (_jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em", ...props, children: _jsx("path", { d: "M12 2v20", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round" }) }));
8
10
  const IconDraggableDots = (props) => (_jsx("svg", { fontSize: 18, viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em", ...props, children: _jsx("path", { d: "M9 3a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm10-18a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0z" }) }));
9
- const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = 'floatingMenuBar-config', isConstrained = false, defaultPosition = { x: 100, y: 100 }, maxItems = 8, }) => {
11
+ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained = false, defaultPosition = { x: 100, y: 100 }, maxItems = 100, }) => {
12
+ const percentToPixels = (percent, containerSize) => {
13
+ return (percent / 100) * containerSize;
14
+ };
15
+ const pixelsToPercent = (pixels, containerSize) => {
16
+ return (pixels / containerSize) * 100;
17
+ };
18
+ const isPixelFormat = (pos) => {
19
+ return pos.x > 100 || pos.y > 100;
20
+ };
21
+ const migrateToPercentage = (pixelPos) => {
22
+ const container = containerRef.current?.getBoundingClientRect();
23
+ const containerWidth = isConstrained && container ? container.width : window.innerWidth;
24
+ const containerHeight = isConstrained && container ? container.height : window.innerHeight;
25
+ return {
26
+ x: pixelsToPercent(pixelPos.x, containerWidth),
27
+ y: pixelsToPercent(pixelPos.y, containerHeight),
28
+ };
29
+ };
30
+ const getDefaultConfig = () => ({
31
+ orientation: 'horizontal',
32
+ savedItemIds: [],
33
+ position: defaultPosition,
34
+ });
35
+ const resetFloatingBarSettings = () => {
36
+ // Reset the floatingMenuBar settings in SDKUI_Globals to trigger save to localStorage
37
+ SDKUI_Globals.userSettings.searchSettings.floatingMenuBar = {
38
+ orientation: 'horizontal',
39
+ itemIds: [],
40
+ position: defaultPosition,
41
+ };
42
+ };
10
43
  const loadConfig = () => {
11
44
  try {
12
- const saved = localStorage.getItem(storageKey);
13
- if (saved) {
14
- const config = JSON.parse(saved);
15
- return {
16
- orientation: config.orientation || 'horizontal',
17
- pinnedItemIds: new Set(config.pinnedItemIds || []),
18
- savedItemIds: config.itemIds || [],
45
+ const settings = SDKUI_Globals.userSettings.searchSettings.floatingMenuBar;
46
+ // Validate that settings object exists and has required properties with correct types
47
+ if (!settings || typeof settings !== 'object') {
48
+ console.warn('FloatingMenuBar: Invalid settings object, resetting to defaults');
49
+ resetFloatingBarSettings();
50
+ return getDefaultConfig();
51
+ }
52
+ // Validate position
53
+ const hasValidPosition = settings.position &&
54
+ typeof settings.position.x === 'number' &&
55
+ typeof settings.position.y === 'number' &&
56
+ !Number.isNaN(settings.position.x) &&
57
+ !Number.isNaN(settings.position.y) &&
58
+ Number.isFinite(settings.position.x) &&
59
+ Number.isFinite(settings.position.y);
60
+ if (!hasValidPosition) {
61
+ console.warn('FloatingMenuBar: Invalid position, resetting to defaults');
62
+ resetFloatingBarSettings();
63
+ return getDefaultConfig();
64
+ }
65
+ // Ensure position is within reasonable viewport bounds
66
+ const maxX = globalThis.window?.innerWidth ? globalThis.window.innerWidth - 50 : 1000;
67
+ const maxY = globalThis.window?.innerHeight ? globalThis.window.innerHeight - 50 : 800;
68
+ if (settings.position.x < 0 || settings.position.x > maxX ||
69
+ settings.position.y < 0 || settings.position.y > maxY) {
70
+ console.warn('FloatingMenuBar: Position out of bounds, resetting to defaults');
71
+ resetFloatingBarSettings();
72
+ return getDefaultConfig();
73
+ }
74
+ // Validate orientation
75
+ const validOrientation = (settings.orientation === 'horizontal' || settings.orientation === 'vertical')
76
+ ? settings.orientation
77
+ : 'horizontal';
78
+ // Validate itemIds
79
+ const validItemIds = Array.isArray(settings.itemIds) ? settings.itemIds : [];
80
+ if (validItemIds.length > 0) {
81
+ // Check if any ID looks like the old format (contains language-specific text or is too long)
82
+ const hasOldFormatIds = validItemIds.some(id => typeof id === 'string' &&
83
+ !id.startsWith('separator-') &&
84
+ (id.length > 20 || id.includes(' ')));
85
+ if (hasOldFormatIds) {
86
+ console.warn('FloatingMenuBar: Detected old name-based configuration, resetting to defaults');
87
+ resetFloatingBarSettings();
88
+ return getDefaultConfig();
89
+ }
90
+ }
91
+ // Migrate old pixel-based position to percentage-based
92
+ let finalPosition = settings.position;
93
+ if (isPixelFormat(settings.position) || settings.positionFormat === 'pixels') {
94
+ console.log('FloatingMenuBar: Migrating pixel-based position to percentage-based');
95
+ finalPosition = migrateToPercentage(settings.position);
96
+ // Save migrated position immediately
97
+ SDKUI_Globals.userSettings.searchSettings.floatingMenuBar = {
98
+ orientation: validOrientation,
99
+ itemIds: validItemIds,
100
+ position: finalPosition,
101
+ positionFormat: 'percentage',
19
102
  };
20
103
  }
104
+ return {
105
+ orientation: validOrientation,
106
+ savedItemIds: validItemIds,
107
+ position: finalPosition,
108
+ };
21
109
  }
22
110
  catch (error) {
23
111
  console.error('Failed to load FloatingMenuBar config:', error);
112
+ // Reset to defaults on any error
113
+ try {
114
+ resetFloatingBarSettings();
115
+ }
116
+ catch (e) {
117
+ console.error('Failed to reset FloatingMenuBar settings:', e);
118
+ }
119
+ return getDefaultConfig();
24
120
  }
25
- return {
26
- orientation: 'horizontal',
27
- pinnedItemIds: new Set(),
28
- savedItemIds: [],
29
- };
30
121
  };
31
122
  const initialConfig = loadConfig();
32
123
  const [state, setState] = useState({
33
- position: defaultPosition,
124
+ position: initialConfig.position, // Stored as percentage
34
125
  isDragging: false,
35
126
  isConfigMode: false,
36
127
  orientation: initialConfig.orientation,
@@ -39,32 +130,62 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
39
130
  });
40
131
  const floatingRef = useRef(null);
41
132
  const dragOffset = useRef({ x: 0, y: 0 });
42
- const [pinnedItemIds, setPinnedItemIds] = useState(initialConfig.pinnedItemIds);
43
133
  const [dragOverIndex, setDragOverIndex] = useState(null);
44
- const [showMaxItemsNotification, setShowMaxItemsNotification] = useState(false);
45
- // Use refs to track item IDs without causing re-renders
134
+ const [pixelPosition, setPixelPosition] = useState({ x: 0, y: 0 }); // Calculated pixel position
135
+ const containerSizeRef = useRef({ width: 0, height: 0 });
136
+ const stateSnapshot = useRef(null);
46
137
  const floatingBarItemIds = useRef(new Set());
47
138
  const floatingBarItemNames = useRef(new Set());
48
- // Update refs when items change, but don't trigger re-renders
49
139
  useEffect(() => {
50
140
  floatingBarItemIds.current = new Set(state.items.map(i => i.id));
51
141
  floatingBarItemNames.current = new Set(state.items.map(i => i.name));
52
142
  }, [state.items]);
53
- // Convert menu items to flat list with pinned status
143
+ // Calculate pixel position from percentage when container size or position changes
144
+ useEffect(() => {
145
+ const updatePixelPosition = () => {
146
+ if (!containerRef.current || !floatingRef.current)
147
+ return;
148
+ const container = containerRef.current.getBoundingClientRect();
149
+ const floating = floatingRef.current.getBoundingClientRect();
150
+ const containerWidth = isConstrained ? container.width : window.innerWidth;
151
+ const containerHeight = isConstrained ? container.height : window.innerHeight;
152
+ containerSizeRef.current = { width: containerWidth, height: containerHeight };
153
+ let newX = percentToPixels(state.position.x, containerWidth);
154
+ let newY = percentToPixels(state.position.y, containerHeight);
155
+ newX = Math.max(0, Math.min(newX, containerWidth - floating.width));
156
+ newY = Math.max(0, Math.min(newY, containerHeight - floating.height));
157
+ setPixelPosition({ x: newX, y: newY });
158
+ };
159
+ updatePixelPosition();
160
+ const resizeObserver = new ResizeObserver(() => {
161
+ updatePixelPosition();
162
+ });
163
+ if (containerRef.current) {
164
+ resizeObserver.observe(containerRef.current);
165
+ }
166
+ if (!isConstrained) {
167
+ window.addEventListener('resize', updatePixelPosition);
168
+ }
169
+ return () => {
170
+ resizeObserver.disconnect();
171
+ if (!isConstrained) {
172
+ window.removeEventListener('resize', updatePixelPosition);
173
+ }
174
+ };
175
+ }, [state.position, isConstrained]);
54
176
  const flattenMenuItems = useCallback((items, parentPath = '') => {
55
177
  const result = [];
56
178
  items.forEach((item, index) => {
57
- const itemId = `${parentPath}${item.name}-${index}`;
58
- // Only add items that have onClick (final actions, not submenu parents)
179
+ const itemId = item.id || `${parentPath}${item.name}-${index}`;
59
180
  if (item.onClick && !item.submenu) {
181
+ const isPinned = state.items.some(i => i.id === itemId);
60
182
  result.push({
61
183
  id: itemId,
62
184
  name: item.name,
63
- icon: item.icon || _jsx(IconStar, {}),
185
+ icon: item.icon || _jsx(IconPin, {}),
64
186
  onClick: item.onClick,
65
187
  disabled: item.disabled,
66
- isPinned: pinnedItemIds.has(itemId),
67
- originalMenuItem: item,
188
+ isPinned: isPinned,
68
189
  });
69
190
  }
70
191
  // Recursively process submenus
@@ -73,14 +194,25 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
73
194
  }
74
195
  });
75
196
  return result;
76
- }, [pinnedItemIds]);
197
+ }, [state.items]);
77
198
  // Restore items on mount from savedItemIds
78
199
  useEffect(() => {
79
- if (contextMenuItems.length > 0) {
200
+ if (contextMenuItems.length > 0 || initialConfig.savedItemIds.length > 0) {
80
201
  const flatItems = flattenMenuItems(contextMenuItems);
81
202
  // Restore items in the saved order from localStorage
82
203
  const restoredItems = initialConfig.savedItemIds
83
- .map((id) => flatItems.find(item => item.id === id))
204
+ .map((id) => {
205
+ if (id.startsWith('separator-')) {
206
+ return {
207
+ id,
208
+ name: 'Separator',
209
+ icon: _jsx(Separator, {}),
210
+ onClick: () => { },
211
+ isSeparator: true,
212
+ };
213
+ }
214
+ return flatItems.find(item => item.id === id);
215
+ })
84
216
  .filter((item) => item !== undefined);
85
217
  if (restoredItems.length > 0) {
86
218
  setState(s => ({ ...s, items: restoredItems }));
@@ -89,40 +221,36 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
89
221
  }, []); // Only run once on mount
90
222
  const togglePin = useCallback((item) => {
91
223
  setState(s => {
92
- const isInFloatingBar = s.items.some(i => i.id === item.id || i.name === item.name);
224
+ const isInFloatingBar = s.items.some(i => i.id === item.id);
93
225
  if (isInFloatingBar) {
94
226
  // Remove from floating bar
95
- const newItems = s.items.filter(i => i.id !== item.id && i.name !== item.name);
227
+ const newItems = s.items.filter(i => i.id !== item.id);
96
228
  return { ...s, items: newItems };
97
229
  }
98
230
  else {
99
231
  // Add to floating bar
100
232
  if (s.items.length >= maxItems) {
101
- setShowMaxItemsNotification(true);
102
- setTimeout(() => setShowMaxItemsNotification(false), 3000);
233
+ ShowAlert({
234
+ mode: 'warning',
235
+ title: 'Limite Massimo Raggiunto',
236
+ message: `Hai raggiunto il massimo di ${maxItems} elementi. Rimuovine uno prima di aggiungerne altri.`,
237
+ duration: 4000,
238
+ });
103
239
  return s;
104
240
  }
105
241
  return { ...s, items: [...s.items, item] };
106
242
  }
107
243
  });
108
- // Update pinned IDs for context menu items
109
- setPinnedItemIds(prev => {
110
- const newSet = new Set(prev);
111
- if (newSet.has(item.id)) {
112
- newSet.delete(item.id);
113
- }
114
- else {
115
- newSet.add(item.id);
116
- }
117
- return newSet;
118
- });
119
244
  }, [maxItems]);
120
245
  // Get current item state (disabled and onClick) from contextMenuItems
121
- const getCurrentItemState = useCallback((itemName) => {
246
+ const getCurrentItemState = useCallback((itemId) => {
122
247
  const findInItems = (items) => {
123
- for (const item of items) {
124
- if (item.name === itemName)
248
+ for (let i = 0; i < items.length; i++) {
249
+ const item = items[i];
250
+ // Match by ID if the item has one
251
+ if (item.id === itemId)
125
252
  return item;
253
+ // Check in submenu
126
254
  if (item.submenu) {
127
255
  const found = findInItems(item.submenu);
128
256
  if (found)
@@ -136,34 +264,96 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
136
264
  disabled: foundItem?.disabled,
137
265
  onClick: foundItem?.onClick
138
266
  };
139
- }, [contextMenuItems]); // Enhanced context menu items with pin functionality
140
- const enhancedContextMenuItems = useCallback(() => {
267
+ }, [contextMenuItems]);
268
+ // Remove trailing separators from items array
269
+ const removeTrailingSeparators = useCallback((items) => {
270
+ const result = [...items];
271
+ while (result.length > 0 && result.at(-1)?.isSeparator) {
272
+ result.pop();
273
+ }
274
+ return result;
275
+ }, []);
276
+ // Create a new separator item
277
+ const createSeparator = useCallback(() => {
278
+ const separatorId = `separator-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
279
+ return {
280
+ id: separatorId,
281
+ name: 'Separator',
282
+ icon: _jsx(Separator, {}),
283
+ onClick: () => { },
284
+ isSeparator: true,
285
+ };
286
+ }, []);
287
+ // Add separator to items
288
+ const addSeparator = useCallback(() => {
289
+ if (state.items.length >= maxItems) {
290
+ ShowAlert({
291
+ mode: 'warning',
292
+ title: 'Limite Massimo Raggiunto',
293
+ message: `Hai raggiunto il massimo di ${maxItems} elementi. Rimuovine uno prima di aggiungerne altri.`,
294
+ duration: 4000,
295
+ });
296
+ return;
297
+ }
298
+ const separator = createSeparator();
299
+ setState(s => ({ ...s, items: [...s.items, separator] }));
300
+ }, [state.items.length, maxItems, createSeparator]);
301
+ const getPinContextMenuItems = useCallback(() => {
141
302
  const flatItems = flattenMenuItems(contextMenuItems);
142
- // Calculate current pinned items directly from state.items (not refs)
143
303
  const currentItemIds = new Set(state.items.map(i => i.id));
144
- const currentItemNames = new Set(state.items.map(i => i.name));
145
- const enhanceItems = (items) => {
304
+ const createPinItems = (items) => {
146
305
  return items.map(item => {
147
- const flatItem = flatItems.find(fi => fi.name === item.name);
148
- const itemId = flatItem?.id || '';
149
- // Check if item is in the floating bar using current state
150
- const isInFloatingBar = currentItemIds.has(itemId) || currentItemNames.has(item.name);
151
- const enhanced = {
306
+ const flatItem = flatItems.find(fi => fi.id === item.id);
307
+ const itemId = flatItem?.id || item.id || '';
308
+ const isAlreadyPinned = currentItemIds.has(itemId);
309
+ const pinItem = {
152
310
  ...item,
153
- rightIcon: item.onClick && !item.submenu ? (isInFloatingBar ? _jsx(IconStar, { color: "#FFD700" }) : _jsx(IconStar, {})) : undefined,
154
- onRightIconClick: item.onClick && !item.submenu ? () => {
155
- if (flatItem) {
311
+ onClick: item.onClick && !item.submenu ? () => {
312
+ if (flatItem && !isAlreadyPinned) {
156
313
  togglePin(flatItem);
157
314
  }
158
315
  } : undefined,
316
+ disabled: isAlreadyPinned,
159
317
  };
160
318
  if (item.submenu) {
161
- enhanced.submenu = enhanceItems(item.submenu);
319
+ pinItem.submenu = createPinItems(item.submenu);
162
320
  }
163
- return enhanced;
321
+ return pinItem;
164
322
  });
165
323
  };
166
- return enhanceItems(contextMenuItems);
324
+ const pinItems = createPinItems(contextMenuItems);
325
+ // Add separator option at the end
326
+ pinItems.push({
327
+ id: 'add-separator',
328
+ name: SDKUI_Localizator.Add + ' separatore',
329
+ icon: _jsx(IconSeparator, {}),
330
+ onClick: addSeparator,
331
+ beginGroup: true
332
+ });
333
+ return pinItems;
334
+ }, [contextMenuItems, flattenMenuItems, togglePin, state.items, addSeparator]);
335
+ const getContextMenuItemsWithPinIcons = useCallback(() => {
336
+ const flatItems = flattenMenuItems(contextMenuItems);
337
+ const currentItemIds = new Set(state.items.map(i => i.id));
338
+ const addPinIcons = (items) => {
339
+ return items.map(item => {
340
+ const flatItem = flatItems.find(fi => fi.id === item.id);
341
+ const itemId = flatItem?.id || item.id || '';
342
+ const isPinned = currentItemIds.has(itemId);
343
+ const itemWithPin = {
344
+ ...item,
345
+ rightIcon: flatItem ? _jsx(IconPin, { color: isPinned ? 'red' : 'black' }) : undefined,
346
+ onRightIconClick: flatItem ? () => {
347
+ togglePin(flatItem);
348
+ } : undefined,
349
+ };
350
+ if (item.submenu) {
351
+ itemWithPin.submenu = addPinIcons(item.submenu);
352
+ }
353
+ return itemWithPin;
354
+ });
355
+ };
356
+ return addPinIcons(contextMenuItems);
167
357
  }, [contextMenuItems, flattenMenuItems, togglePin, state.items]);
168
358
  const handleMouseDown = (e) => {
169
359
  if (state.isConfigMode)
@@ -174,20 +364,25 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
174
364
  if (isConstrained) {
175
365
  // For absolute positioning, offset is relative to container
176
366
  dragOffset.current = {
177
- x: e.clientX - containerRect.left - state.position.x,
178
- y: e.clientY - containerRect.top - state.position.y,
367
+ x: e.clientX - containerRect.left - pixelPosition.x,
368
+ y: e.clientY - containerRect.top - pixelPosition.y,
179
369
  };
180
370
  }
181
371
  else {
182
372
  // For fixed positioning, offset is relative to viewport
183
373
  dragOffset.current = {
184
- x: e.clientX - state.position.x,
185
- y: e.clientY - state.position.y,
374
+ x: e.clientX - pixelPosition.x,
375
+ y: e.clientY - pixelPosition.y,
186
376
  };
187
377
  }
188
378
  }
189
379
  setState(s => ({ ...s, isDragging: true }));
190
380
  };
381
+ const handleGripDoubleClick = () => {
382
+ if (state.isConfigMode)
383
+ return;
384
+ toggleOrientation();
385
+ };
191
386
  const handleMouseMove = useCallback((e) => {
192
387
  if (!state.isDragging || !containerRef.current || !floatingRef.current)
193
388
  return;
@@ -210,50 +405,265 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
210
405
  newX = Math.max(0, Math.min(newX, window.innerWidth - floating.width));
211
406
  newY = Math.max(0, Math.min(newY, window.innerHeight - floating.height));
212
407
  }
213
- setState(s => ({
214
- ...s,
215
- position: { x: newX, y: newY },
216
- }));
408
+ // Update pixel position directly during drag
409
+ setPixelPosition({ x: newX, y: newY });
217
410
  }, [state.isDragging, containerRef, isConstrained]);
218
411
  const handleMouseUp = useCallback(() => {
219
- setState(s => ({ ...s, isDragging: false }));
220
- }, []);
412
+ if (state.isDragging && containerSizeRef.current.width > 0) {
413
+ // Convert final pixel position to percentage before updating state
414
+ const percentagePosition = {
415
+ x: pixelsToPercent(pixelPosition.x, containerSizeRef.current.width),
416
+ y: pixelsToPercent(pixelPosition.y, containerSizeRef.current.height),
417
+ };
418
+ setState(s => ({
419
+ ...s,
420
+ isDragging: false,
421
+ position: percentagePosition,
422
+ }));
423
+ }
424
+ else {
425
+ setState(s => ({ ...s, isDragging: false }));
426
+ }
427
+ }, [state.isDragging, pixelPosition]);
428
+ // Touch event handlers for tablet support
429
+ const handleTouchStart = (e) => {
430
+ if (state.isConfigMode)
431
+ return;
432
+ const touch = e.touches[0];
433
+ const containerRect = containerRef.current?.getBoundingClientRect();
434
+ if (containerRect) {
435
+ if (isConstrained) {
436
+ dragOffset.current = {
437
+ x: touch.clientX - containerRect.left - pixelPosition.x,
438
+ y: touch.clientY - containerRect.top - pixelPosition.y,
439
+ };
440
+ }
441
+ else {
442
+ dragOffset.current = {
443
+ x: touch.clientX - pixelPosition.x,
444
+ y: touch.clientY - pixelPosition.y,
445
+ };
446
+ }
447
+ }
448
+ setState(s => ({ ...s, isDragging: true }));
449
+ };
450
+ const handleTouchMove = useCallback((e) => {
451
+ if (!state.isDragging || !containerRef.current || !floatingRef.current)
452
+ return;
453
+ const touch = e.touches[0];
454
+ const container = containerRef.current.getBoundingClientRect();
455
+ const floating = floatingRef.current.getBoundingClientRect();
456
+ let newX, newY;
457
+ if (isConstrained) {
458
+ newX = touch.clientX - container.left - dragOffset.current.x;
459
+ newY = touch.clientY - container.top - dragOffset.current.y;
460
+ newX = Math.max(0, Math.min(newX, container.width - floating.width));
461
+ newY = Math.max(0, Math.min(newY, container.height - floating.height));
462
+ }
463
+ else {
464
+ newX = touch.clientX - dragOffset.current.x;
465
+ newY = touch.clientY - dragOffset.current.y;
466
+ newX = Math.max(0, Math.min(newX, window.innerWidth - floating.width));
467
+ newY = Math.max(0, Math.min(newY, window.innerHeight - floating.height));
468
+ }
469
+ setPixelPosition({ x: newX, y: newY });
470
+ }, [state.isDragging, containerRef, isConstrained]);
471
+ const handleTouchEnd = useCallback(() => {
472
+ if (state.isDragging && containerSizeRef.current.width > 0) {
473
+ const percentagePosition = {
474
+ x: pixelsToPercent(pixelPosition.x, containerSizeRef.current.width),
475
+ y: pixelsToPercent(pixelPosition.y, containerSizeRef.current.height),
476
+ };
477
+ setState(s => ({
478
+ ...s,
479
+ isDragging: false,
480
+ position: percentagePosition,
481
+ }));
482
+ }
483
+ else {
484
+ setState(s => ({ ...s, isDragging: false }));
485
+ }
486
+ }, [state.isDragging, pixelPosition]);
221
487
  useEffect(() => {
222
488
  if (state.isDragging) {
223
489
  document.addEventListener('mousemove', handleMouseMove);
224
490
  document.addEventListener('mouseup', handleMouseUp);
491
+ document.addEventListener('touchmove', handleTouchMove);
492
+ document.addEventListener('touchend', handleTouchEnd);
225
493
  return () => {
226
494
  document.removeEventListener('mousemove', handleMouseMove);
227
495
  document.removeEventListener('mouseup', handleMouseUp);
496
+ document.removeEventListener('touchmove', handleTouchMove);
497
+ document.removeEventListener('touchend', handleTouchEnd);
228
498
  };
229
499
  }
230
500
  return undefined;
231
- }, [state.isDragging, handleMouseMove, handleMouseUp]);
232
- // Save to localStorage whenever config changes (excluding position)
501
+ }, [state.isDragging, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
502
+ // Save to SDKUI_Globals.userSettings only when NOT in config mode (when applying changes)
233
503
  useEffect(() => {
504
+ if (state.isConfigMode)
505
+ return; // Don't save during edit mode
234
506
  try {
235
- const config = {
507
+ // Replace the entire object to trigger the Proxy
508
+ SDKUI_Globals.userSettings.searchSettings.floatingMenuBar = {
236
509
  orientation: state.orientation,
237
- pinnedItemIds: Array.from(pinnedItemIds),
238
- itemIds: state.items.map(item => item.id), // Save only IDs, not functions
510
+ itemIds: state.items.map(item => item.id),
511
+ position: state.position,
512
+ positionFormat: 'percentage',
239
513
  };
240
- localStorage.setItem(storageKey, JSON.stringify(config));
241
514
  }
242
515
  catch (error) {
243
516
  console.error('Failed to save FloatingMenuBar config:', error);
244
517
  }
245
- }, [state.orientation, state.items, pinnedItemIds, storageKey]);
518
+ }, [state.orientation, state.items, state.position, state.isConfigMode]);
246
519
  const toggleConfigMode = () => {
247
- setState(s => ({ ...s, isConfigMode: !s.isConfigMode }));
520
+ setState(s => {
521
+ if (!s.isConfigMode) {
522
+ stateSnapshot.current = {
523
+ items: [...s.items],
524
+ orientation: s.orientation,
525
+ position: { ...s.position },
526
+ };
527
+ return { ...s, isConfigMode: true };
528
+ }
529
+ else {
530
+ // Exiting edit mode (applying changes) - clean up trailing separators and clear snapshot
531
+ stateSnapshot.current = null;
532
+ const cleanedItems = removeTrailingSeparators(s.items);
533
+ return { ...s, isConfigMode: false, items: cleanedItems };
534
+ }
535
+ });
536
+ };
537
+ // Auto-reposition when entering edit mode to ensure Apply/Undo buttons are visible
538
+ useEffect(() => {
539
+ if (!state.isConfigMode || !floatingRef.current)
540
+ return;
541
+ // Use double requestAnimationFrame to ensure the DOM has fully updated with new buttons
542
+ requestAnimationFrame(() => {
543
+ requestAnimationFrame(() => {
544
+ if (!floatingRef.current)
545
+ return;
546
+ const floating = floatingRef.current.getBoundingClientRect();
547
+ const containerWidth = isConstrained && containerRef.current
548
+ ? containerRef.current.getBoundingClientRect().width
549
+ : window.innerWidth;
550
+ const containerHeight = isConstrained && containerRef.current
551
+ ? containerRef.current.getBoundingClientRect().height
552
+ : window.innerHeight;
553
+ // Use current pixel position
554
+ let newPixelX = pixelPosition.x;
555
+ let newPixelY = pixelPosition.y;
556
+ let needsUpdate = false;
557
+ // Check horizontal overflow
558
+ if (newPixelX + floating.width > containerWidth) {
559
+ newPixelX = Math.max(0, containerWidth - floating.width);
560
+ needsUpdate = true;
561
+ }
562
+ // Check vertical overflow
563
+ if (newPixelY + floating.height > containerHeight) {
564
+ newPixelY = Math.max(0, containerHeight - floating.height);
565
+ needsUpdate = true;
566
+ }
567
+ if (needsUpdate) {
568
+ // Update pixel position immediately
569
+ setPixelPosition({ x: newPixelX, y: newPixelY });
570
+ // Convert to percentage for state
571
+ const newPercentagePosition = {
572
+ x: pixelsToPercent(newPixelX, containerWidth),
573
+ y: pixelsToPercent(newPixelY, containerHeight),
574
+ };
575
+ setState(s => ({
576
+ ...s,
577
+ position: newPercentagePosition,
578
+ }));
579
+ // Update snapshot position to the corrected position so Undo restores to visible position
580
+ if (stateSnapshot.current) {
581
+ stateSnapshot.current.position = newPercentagePosition;
582
+ }
583
+ }
584
+ });
585
+ });
586
+ }, [state.isConfigMode, state.orientation, isConstrained, state.items, pixelPosition.x, pixelPosition.y]);
587
+ const handleUndo = () => {
588
+ if (stateSnapshot.current) {
589
+ setState(s => ({
590
+ ...s,
591
+ items: [...stateSnapshot.current.items],
592
+ orientation: stateSnapshot.current.orientation,
593
+ position: { ...stateSnapshot.current.position },
594
+ isConfigMode: true,
595
+ }));
596
+ }
597
+ };
598
+ // Check if current state has changed from snapshot
599
+ const hasChanges = () => {
600
+ if (!stateSnapshot.current)
601
+ return false;
602
+ // Check if items have changed (different IDs or different order)
603
+ const currentIds = state.items.map(i => i.id).join(',');
604
+ const snapshotIds = stateSnapshot.current.items.map(i => i.id).join(',');
605
+ return currentIds !== snapshotIds;
606
+ };
607
+ const handleClose = () => {
608
+ // If all items removed, exit without asking and restore last items
609
+ if (state.items.length === 0 && stateSnapshot.current) {
610
+ setState(s => ({
611
+ ...s,
612
+ items: [...stateSnapshot.current.items],
613
+ orientation: stateSnapshot.current.orientation,
614
+ position: { ...stateSnapshot.current.position },
615
+ isConfigMode: false,
616
+ }));
617
+ stateSnapshot.current = null;
618
+ return;
619
+ }
620
+ // If no changes, simply exit config mode
621
+ if (!hasChanges()) {
622
+ stateSnapshot.current = null;
623
+ const cleanedItems = removeTrailingSeparators(state.items);
624
+ setState(s => ({ ...s, isConfigMode: false, items: cleanedItems }));
625
+ return;
626
+ }
627
+ // If there are changes, ask for confirmation
628
+ TMMessageBoxManager.show({
629
+ message: 'Perderai le tue modifiche, sei sicuro?',
630
+ buttons: [ButtonNames.YES, ButtonNames.NO],
631
+ onButtonClick: (buttonName) => {
632
+ if (buttonName === ButtonNames.YES && stateSnapshot.current) {
633
+ // Restore snapshot and exit config mode
634
+ setState(s => ({
635
+ ...s,
636
+ items: [...stateSnapshot.current.items],
637
+ orientation: stateSnapshot.current.orientation,
638
+ position: { ...stateSnapshot.current.position },
639
+ isConfigMode: false,
640
+ }));
641
+ stateSnapshot.current = null;
642
+ }
643
+ },
644
+ });
248
645
  };
249
646
  const toggleOrientation = () => {
250
647
  const newOrientation = state.orientation === 'horizontal' ? 'vertical' : 'horizontal';
251
- // First, change the orientation
648
+ if (state.orientation === 'horizontal' && newOrientation === 'vertical') {
649
+ if (floatingRef.current) {
650
+ const floating = floatingRef.current.getBoundingClientRect();
651
+ const screenHeight = window.innerHeight;
652
+ if (floating.width > screenHeight - 70) {
653
+ ShowAlert({
654
+ mode: 'warning',
655
+ title: 'Troppi elementi',
656
+ message: 'Ci sono troppi elementi nella barra mobile per la modalità verticale.',
657
+ duration: 4000,
658
+ });
659
+ return;
660
+ }
661
+ }
662
+ }
252
663
  setState(s => ({
253
664
  ...s,
254
665
  orientation: newOrientation,
255
666
  }));
256
- // Then, after DOM updates, adjust position to stay in bounds
257
667
  requestAnimationFrame(() => {
258
668
  requestAnimationFrame(() => {
259
669
  if (containerRef.current && floatingRef.current) {
@@ -286,12 +696,6 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
286
696
  ...s,
287
697
  items: s.items.filter(item => item.id !== itemId),
288
698
  }));
289
- // Also remove from pinned items if it was pinned
290
- setPinnedItemIds(prev => {
291
- const newSet = new Set(prev);
292
- newSet.delete(itemId);
293
- return newSet;
294
- });
295
699
  };
296
700
  // Drag and drop for reordering
297
701
  const handleDragStart = (e, index) => {
@@ -347,24 +751,37 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
347
751
  setState(s => ({ ...s, draggedItemIndex: null }));
348
752
  setDragOverIndex(null);
349
753
  };
350
- return (_jsxs(_Fragment, { children: [_jsx(S.Overlay, { "$visible": state.isConfigMode }), _jsxs(S.FloatingContainer, { ref: floatingRef, "$x": state.position.x, "$y": state.position.y, "$orientation": state.orientation, "$isDragging": state.isDragging, "$isConfigMode": state.isConfigMode, "$isConstrained": isConstrained, children: [_jsx(S.GripHandle, { "$orientation": state.orientation, onMouseDown: handleMouseDown, children: _jsx(IconDraggableDots, {}) }), _jsx(S.ConfigButton, { onClick: toggleConfigMode, "$isActive": state.isConfigMode, children: state.isConfigMode ? _jsx(IconApply, {}) : _jsx(IconSettings, {}) }), state.items.map((item, index) => {
754
+ return (_jsxs(_Fragment, { children: [_jsx(S.Overlay, { "$visible": state.isConfigMode }), _jsxs(S.FloatingContainer, { ref: floatingRef, "$x": pixelPosition.x, "$y": pixelPosition.y, "$orientation": state.orientation, "$isDragging": state.isDragging, "$isConfigMode": state.isConfigMode, "$isConstrained": isConstrained, onContextMenu: (e) => e.preventDefault(), children: [!state.isConfigMode ? (_jsx(ContextMenu, { items: [
755
+ {
756
+ name: SDKUI_Localizator.Configure,
757
+ onClick: () => {
758
+ if (!state.isConfigMode) {
759
+ toggleConfigMode();
760
+ }
761
+ },
762
+ },
763
+ {
764
+ name: state.orientation === 'horizontal' ? 'Floating bar verticale' : 'Floating bar orizzontale',
765
+ onClick: toggleOrientation,
766
+ },
767
+ ], trigger: "right", children: _jsx(S.GripHandle, { "$orientation": state.orientation, onMouseDown: handleMouseDown, onTouchStart: handleTouchStart, onDoubleClick: handleGripDoubleClick, children: _jsx(IconDraggableDots, {}) }) })) : (_jsx(S.GripHandle, { "$orientation": state.orientation, onMouseDown: handleMouseDown, onTouchStart: handleTouchStart, onDoubleClick: handleGripDoubleClick, children: _jsx(IconDraggableDots, {}) })), _jsx(S.Separator, { "$orientation": state.orientation }), state.items.map((item, index) => {
768
+ // Handle separator items
769
+ if (item.isSeparator) {
770
+ return (_jsxs(S.DraggableItem, { "$isDragging": state.draggedItemIndex === index, "$isDragOver": dragOverIndex === index && state.draggedItemIndex !== index, draggable: state.isConfigMode, onDragStart: (e) => handleDragStart(e, index), onDragEnter: (e) => handleDragEnter(e, index), onDragOver: handleDragOver, onDragLeave: (e) => handleDragLeave(e, index), onDrop: (e) => handleDrop(e, index), onDragEnd: handleDragEnd, children: [_jsx(S.ItemSeparator, { "$orientation": state.orientation, "$isConfigMode": state.isConfigMode }), state.isConfigMode && (_jsx(S.RemoveButton, { onClick: () => removeItem(item.id), children: "\u00D7" }))] }, item.id));
771
+ }
351
772
  // Get current state (disabled and onClick) from contextMenuItems
352
- const currentState = getCurrentItemState(item.name);
773
+ const currentState = getCurrentItemState(item.id);
353
774
  const isDisabled = currentState.disabled || false;
354
775
  const currentOnClick = currentState.onClick || item.onClick; // Fallback to stored onClick if not found
355
- return (_jsxs(S.DraggableItem, { "$isDragging": state.draggedItemIndex === index, "$isDragOver": dragOverIndex === index && state.draggedItemIndex !== index, draggable: state.isConfigMode, onDragStart: (e) => handleDragStart(e, index), onDragEnter: (e) => handleDragEnter(e, index), onDragOver: handleDragOver, onDragLeave: (e) => handleDragLeave(e, index), onDrop: (e) => handleDrop(e, index), onDragEnd: handleDragEnd, children: [state.isConfigMode ? (_jsx(S.MenuButton, { onClick: () => {
356
- if (state.isConfigMode || isDisabled)
357
- return;
358
- if (currentOnClick) {
359
- currentOnClick();
360
- }
361
- }, disabled: isDisabled && !state.isConfigMode, children: item.icon })) : (_jsx(TMTooltip, { content: item.name, position: "top", children: _jsx(S.MenuButton, { onClick: () => {
776
+ return (_jsxs(S.DraggableItem, { "$isDragging": state.draggedItemIndex === index, "$isDragOver": dragOverIndex === index && state.draggedItemIndex !== index, draggable: state.isConfigMode, onDragStart: (e) => handleDragStart(e, index), onDragEnter: (e) => handleDragEnter(e, index), onDragOver: handleDragOver, onDragLeave: (e) => handleDragLeave(e, index), onDrop: (e) => handleDrop(e, index), onDragEnd: handleDragEnd, children: [_jsx(TMTooltip, { content: item.name, position: "bottom", children: _jsx(S.MenuButton, { onClick: () => {
362
777
  if (state.isConfigMode || isDisabled)
363
778
  return;
364
779
  if (currentOnClick) {
365
780
  currentOnClick();
366
781
  }
367
- }, disabled: isDisabled, children: item.icon }) })), state.isConfigMode && (_jsx(S.RemoveButton, { onClick: () => removeItem(item.id), children: "\u00D7" }))] }, item.id));
368
- }), !state.isConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: enhancedContextMenuItems(), trigger: "left", children: _jsx(S.MenuButton, { children: _jsx(IconMenuVertical, {}) }) }, Array.from(pinnedItemIds).join(','))), !state.isConfigMode && (_jsx(S.OrientationToggle, { "$orientation": state.orientation, onClick: toggleOrientation, children: _jsx(IconMenuKebab, {}) }))] }), showMaxItemsNotification && (_jsx("div", { style: { position: 'fixed', top: '20px', left: '50%', transform: 'translateX(-50%)', zIndex: 100001 }, children: _jsx(Notification, { title: "Maximum Items Reached", message: `You have reached the maximum number of pinned items (${maxItems}). Please unpin an item before adding a new one.`, mode: "warning", position: "top-center", duration: 4000, closable: true, stopOnMouseEnter: true, hasProgress: true, onClose: () => setShowMaxItemsNotification(false) }) }))] }));
782
+ }, disabled: state.isConfigMode ? isDisabled && !state.isConfigMode : isDisabled, children: item.icon }) }), state.isConfigMode && (_jsx(S.RemoveButton, { onClick: () => removeItem(item.id), children: "\u00D7" }))] }, item.id));
783
+ }), !state.isConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getContextMenuItemsWithPinIcons(), trigger: "left", keepOpenOnClick: true, children: _jsx(S.ContextMenuButton, { children: _jsx(IconMenuVertical, {}) }) })), state.isConfigMode && state.items.length < maxItems && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getPinContextMenuItems(), trigger: "left", keepOpenOnClick: true, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Add, children: _jsx(S.AddButton, { children: _jsx(IconAdd, {}) }) }) })), state.isConfigMode && (_jsxs(_Fragment, { children: [_jsx(S.Separator, { "$orientation": state.orientation }), _jsxs(S.ButtonGroup, { "$orientation": state.orientation, children: [_jsx(TMTooltip, { content: SDKUI_Localizator.Undo, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.UndoButton, { onClick: handleUndo, disabled: !hasChanges(), children: _jsx(IconUndo, { fontSize: 18 }) }) }), _jsx(TMTooltip, { content: state.items.length === 0
784
+ ? 'Devi aggiungere almeno un item'
785
+ : SDKUI_Localizator.Save, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.ApplyButton, { onClick: toggleConfigMode, disabled: state.items.length === 0 || !hasChanges(), children: _jsx(IconSave, { fontSize: 20 }) }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Close, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.CloseButton, { onClick: handleClose, children: _jsx(IconCloseOutline, { fontSize: 20 }) }) })] })] }))] })] }));
369
786
  };
370
787
  export default TMFloatingMenuBar;