@topconsultnpm/sdkui-react 6.20.0-dev1.11 → 6.20.0-dev1.110

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 (175) hide show
  1. package/lib/assets/Toppy-help-center.png +0 -0
  2. package/lib/assets/headergradient.svg +87 -0
  3. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +285 -28
  4. package/lib/components/NewComponents/ContextMenu/hooks.d.ts +8 -1
  5. package/lib/components/NewComponents/ContextMenu/hooks.js +80 -8
  6. package/lib/components/NewComponents/ContextMenu/index.d.ts +3 -0
  7. package/lib/components/NewComponents/ContextMenu/index.js +2 -0
  8. package/lib/components/NewComponents/ContextMenu/styles.d.ts +9 -1
  9. package/lib/components/NewComponents/ContextMenu/styles.js +157 -37
  10. package/lib/components/NewComponents/ContextMenu/types.d.ts +14 -1
  11. package/lib/components/NewComponents/ContextMenu/useLongPress.d.ts +21 -0
  12. package/lib/components/NewComponents/ContextMenu/useLongPress.js +112 -0
  13. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +563 -112
  14. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +21 -5
  15. package/lib/components/NewComponents/FloatingMenuBar/styles.js +210 -58
  16. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +8 -2
  17. package/lib/components/base/TMAccordionNew.js +35 -14
  18. package/lib/components/base/TMCustomButton.js +61 -17
  19. package/lib/components/base/TMDataGrid.d.ts +7 -4
  20. package/lib/components/base/TMDataGrid.js +153 -11
  21. package/lib/components/base/TMDropDownMenu.js +19 -18
  22. package/lib/components/base/TMFileManager.d.ts +4 -3
  23. package/lib/components/base/TMFileManager.js +32 -24
  24. package/lib/components/base/TMFileManagerDataGridView.d.ts +3 -2
  25. package/lib/components/base/TMFileManagerDataGridView.js +1 -11
  26. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +7 -1
  27. package/lib/components/base/TMFileManagerThumbnailItems.js +5 -2
  28. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +17 -4
  29. package/lib/components/base/TMFileManagerThumbnailsView.js +18 -6
  30. package/lib/components/base/TMFileManagerUtils.d.ts +0 -12
  31. package/lib/components/base/TMListView.js +33 -15
  32. package/lib/components/base/TMPanel.d.ts +1 -1
  33. package/lib/components/base/TMPanel.js +1 -1
  34. package/lib/components/choosers/TMDistinctValues.js +2 -2
  35. package/lib/components/choosers/TMInvoiceRetrieveFormats.js +1 -1
  36. package/lib/components/choosers/TMMetadataChooser.js +8 -1
  37. package/lib/components/choosers/TMOrderRetrieveFormats.js +1 -1
  38. package/lib/components/choosers/TMUserChooser.d.ts +0 -5
  39. package/lib/components/choosers/TMUserChooser.js +25 -45
  40. package/lib/components/editors/TMDateBox.js +18 -9
  41. package/lib/components/editors/TMLocalizedTextBox.d.ts +3 -1
  42. package/lib/components/editors/TMLocalizedTextBox.js +16 -14
  43. package/lib/components/editors/TMMetadataTextBox.d.ts +9 -0
  44. package/lib/components/editors/TMMetadataTextBox.js +92 -0
  45. package/lib/components/editors/TMMetadataValues.js +23 -5
  46. package/lib/components/editors/TMTextArea.js +18 -30
  47. package/lib/components/editors/TMTextBox.d.ts +1 -1
  48. package/lib/components/editors/TMTextBox.js +6 -3
  49. package/lib/components/editors/TMTextExpression.js +6 -91
  50. package/lib/components/features/archive/TMArchive.js +2 -2
  51. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +15 -0
  52. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +460 -0
  53. package/lib/components/features/assistant/TMToppySpeechBubble.d.ts +11 -0
  54. package/lib/components/features/assistant/TMToppySpeechBubble.js +126 -0
  55. package/lib/components/features/documents/TMDcmtForm.d.ts +14 -2
  56. package/lib/components/features/documents/TMDcmtForm.js +457 -206
  57. package/lib/components/features/documents/TMDcmtPreview.js +44 -110
  58. package/lib/components/features/documents/TMDcmtTasks.js +9 -9
  59. package/lib/components/features/documents/TMMasterDetailDcmts.js +38 -53
  60. package/lib/components/features/documents/TMRelationViewer.d.ts +1 -1
  61. package/lib/components/features/documents/TMRelationViewer.js +2 -2
  62. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +8 -0
  63. package/lib/components/features/search/{TMSearchResultCheckoutInfoForm.js → TMDcmtCheckoutInfoForm.js} +2 -2
  64. package/lib/components/features/search/TMSavedQuerySelector.js +72 -67
  65. package/lib/components/features/search/TMSearch.d.ts +3 -0
  66. package/lib/components/features/search/TMSearch.js +50 -11
  67. package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -0
  68. package/lib/components/features/search/TMSearchQueryPanel.js +29 -21
  69. package/lib/components/features/search/TMSearchResult.d.ts +3 -0
  70. package/lib/components/features/search/TMSearchResult.js +208 -250
  71. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +3 -3
  72. package/lib/components/features/search/TMSearchResultsMenuItems.js +205 -169
  73. package/lib/components/features/search/TMSignSettingsForm.js +1 -1
  74. package/lib/components/features/search/TMSignatureInfoContent.d.ts +6 -0
  75. package/lib/components/features/search/TMSignatureInfoContent.js +140 -0
  76. package/lib/components/features/search/TMViewHistoryDcmt.js +2 -2
  77. package/lib/components/features/tasks/TMTaskForm.js +20 -1
  78. package/lib/components/features/tasks/TMTasksAgenda.d.ts +3 -1
  79. package/lib/components/features/tasks/TMTasksAgenda.js +48 -9
  80. package/lib/components/features/tasks/TMTasksCalendar.d.ts +2 -0
  81. package/lib/components/features/tasks/TMTasksCalendar.js +19 -7
  82. package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
  83. package/lib/components/features/tasks/TMTasksUtils.js +43 -36
  84. package/lib/components/features/tasks/TMTasksView.js +28 -19
  85. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +33 -2
  86. package/lib/components/features/workflow/TMWorkflowPopup.js +139 -34
  87. package/lib/components/features/workflow/diagram/DiagramItemComponent.d.ts +2 -0
  88. package/lib/components/features/workflow/diagram/DiagramItemComponent.js +12 -7
  89. package/lib/components/features/workflow/diagram/DiagramItemForm.js +1 -1
  90. package/lib/components/features/workflow/diagram/RecipientList.js +3 -2
  91. package/lib/components/features/workflow/diagram/WFDiagram.d.ts +4 -0
  92. package/lib/components/features/workflow/diagram/WFDiagram.js +164 -13
  93. package/lib/components/forms/Login/LoginValidatorService.d.ts +2 -0
  94. package/lib/components/forms/Login/LoginValidatorService.js +7 -2
  95. package/lib/components/forms/Login/TMLoginForm.js +34 -6
  96. package/lib/components/forms/TMChooserForm.js +1 -1
  97. package/lib/components/grids/TMBlogsPost.js +56 -31
  98. package/lib/components/grids/TMRecentsManager.js +20 -10
  99. package/lib/components/index.d.ts +6 -3
  100. package/lib/components/index.js +6 -3
  101. package/lib/components/query/TMQueryEditor.d.ts +2 -1
  102. package/lib/components/query/TMQueryEditor.js +92 -92
  103. package/lib/components/settings/SettingsAppearance.d.ts +2 -1
  104. package/lib/components/settings/SettingsAppearance.js +99 -30
  105. package/lib/components/sidebar/TMHeader.js +7 -7
  106. package/lib/components/sidebar/TMSidebar.d.ts +0 -1
  107. package/lib/components/sidebar/TMSidebar.js +16 -44
  108. package/lib/components/sidebar/TMSidebarItem.js +34 -17
  109. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -1
  110. package/lib/components/viewers/TMDataListItemViewer.js +35 -71
  111. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +8 -0
  112. package/lib/components/viewers/TMDataUserIdItemViewer.js +39 -0
  113. package/lib/css/tm-sdkui.css +1 -1
  114. package/lib/helper/SDKUI_Globals.d.ts +22 -0
  115. package/lib/helper/SDKUI_Globals.js +10 -1
  116. package/lib/helper/SDKUI_Localizator.d.ts +17 -1
  117. package/lib/helper/SDKUI_Localizator.js +167 -1
  118. package/lib/helper/TMCommandsContextMenu.d.ts +4 -2
  119. package/lib/helper/TMCommandsContextMenu.js +15 -4
  120. package/lib/helper/TMIcons.d.ts +4 -0
  121. package/lib/helper/TMIcons.js +13 -3
  122. package/lib/helper/TMPdfViewer.d.ts +8 -0
  123. package/lib/helper/TMPdfViewer.js +373 -0
  124. package/lib/helper/checkinCheckoutManager.d.ts +31 -1
  125. package/lib/helper/checkinCheckoutManager.js +112 -30
  126. package/lib/helper/devextremeCustomMessages.d.ts +30 -0
  127. package/lib/helper/devextremeCustomMessages.js +30 -0
  128. package/lib/helper/helpers.d.ts +28 -1
  129. package/lib/helper/helpers.js +130 -3
  130. package/lib/helper/index.d.ts +2 -0
  131. package/lib/helper/index.js +2 -0
  132. package/lib/helper/queryHelper.d.ts +1 -1
  133. package/lib/helper/queryHelper.js +33 -3
  134. package/lib/helper/workItemsHelper.d.ts +6 -0
  135. package/lib/helper/workItemsHelper.js +230 -0
  136. package/lib/hooks/useCheckInOutOperations.d.ts +28 -0
  137. package/lib/hooks/useCheckInOutOperations.js +223 -0
  138. package/lib/hooks/useDataListItem.d.ts +12 -0
  139. package/lib/hooks/useDataListItem.js +132 -0
  140. package/lib/hooks/useDataUserIdItem.d.ts +10 -0
  141. package/lib/hooks/useDataUserIdItem.js +96 -0
  142. package/lib/hooks/useMetadataExpression.d.ts +19 -0
  143. package/lib/hooks/useMetadataExpression.js +99 -0
  144. package/lib/hooks/useSettingsFeedback.d.ts +11 -0
  145. package/lib/hooks/useSettingsFeedback.js +38 -0
  146. package/lib/hooks/useWorkflowApprove.d.ts +4 -0
  147. package/lib/hooks/useWorkflowApprove.js +14 -1
  148. package/lib/index.d.ts +1 -0
  149. package/lib/index.js +3 -2
  150. package/lib/services/platform_services.d.ts +3 -3
  151. package/lib/ts/types.d.ts +61 -1
  152. package/lib/utils/theme.d.ts +1 -1
  153. package/lib/utils/theme.js +1 -1
  154. package/package.json +7 -4
  155. package/lib/components/NewComponents/Notification/Notification.d.ts +0 -4
  156. package/lib/components/NewComponents/Notification/Notification.js +0 -60
  157. package/lib/components/NewComponents/Notification/NotificationContainer.d.ts +0 -8
  158. package/lib/components/NewComponents/Notification/NotificationContainer.js +0 -33
  159. package/lib/components/NewComponents/Notification/index.d.ts +0 -2
  160. package/lib/components/NewComponents/Notification/index.js +0 -2
  161. package/lib/components/NewComponents/Notification/styles.d.ts +0 -21
  162. package/lib/components/NewComponents/Notification/styles.js +0 -180
  163. package/lib/components/NewComponents/Notification/types.d.ts +0 -18
  164. package/lib/components/NewComponents/Notification/types.js +0 -1
  165. package/lib/components/base/TMContextMenu.d.ts +0 -25
  166. package/lib/components/base/TMContextMenu.js +0 -109
  167. package/lib/components/base/TMContextMenuOLD.d.ts +0 -26
  168. package/lib/components/base/TMContextMenuOLD.js +0 -56
  169. package/lib/components/base/TMFloatingToolbar.d.ts +0 -9
  170. package/lib/components/base/TMFloatingToolbar.js +0 -101
  171. package/lib/components/features/assistant/ToppyDraggableHelpCenter.d.ts +0 -30
  172. package/lib/components/features/assistant/ToppyDraggableHelpCenter.js +0 -482
  173. package/lib/components/features/assistant/ToppySpeechBubble.d.ts +0 -9
  174. package/lib/components/features/assistant/ToppySpeechBubble.js +0 -117
  175. package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +0 -8
@@ -1,36 +1,133 @@
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: 1, y: 90 }, defaultOrientation = 'horizontal', maxItems = 100, contextMenuDefaultPinnedIds = [], defaultItems = [], disbaleConfigMode = false, bgColor = undefined, }) => {
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: defaultOrientation,
32
+ savedItemIds: contextMenuDefaultPinnedIds,
33
+ position: defaultPosition,
34
+ });
35
+ const resetFloatingBarSettings = () => {
36
+ // Reset the floatingMenuBar settings in SDKUI_Globals to empty
37
+ SDKUI_Globals.userSettings.searchSettings.floatingMenuBar = {
38
+ orientation: undefined,
39
+ itemIds: undefined,
40
+ position: undefined,
41
+ };
42
+ };
10
43
  const loadConfig = () => {
44
+ // If config mode is disabled, use default position and orientation
45
+ if (disbaleConfigMode) {
46
+ return {
47
+ orientation: defaultOrientation,
48
+ savedItemIds: contextMenuDefaultPinnedIds,
49
+ position: defaultPosition,
50
+ };
51
+ }
11
52
  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 || [],
53
+ const settings = SDKUI_Globals.userSettings.searchSettings.floatingMenuBar;
54
+ // If localStorage is empty (first time), use props as defaults
55
+ if (!settings || !settings.position || !settings.itemIds) {
56
+ return getDefaultConfig();
57
+ }
58
+ // Validate position
59
+ const hasValidPosition = settings.position &&
60
+ typeof settings.position.x === 'number' &&
61
+ typeof settings.position.y === 'number' &&
62
+ !Number.isNaN(settings.position.x) &&
63
+ !Number.isNaN(settings.position.y) &&
64
+ Number.isFinite(settings.position.x) &&
65
+ Number.isFinite(settings.position.y);
66
+ if (!hasValidPosition) {
67
+ console.warn('FloatingMenuBar: Invalid position, resetting to defaults');
68
+ resetFloatingBarSettings();
69
+ return getDefaultConfig();
70
+ }
71
+ // Ensure position is within reasonable viewport bounds
72
+ const maxX = globalThis.window?.innerWidth ? globalThis.window.innerWidth - 50 : 1000;
73
+ const maxY = globalThis.window?.innerHeight ? globalThis.window.innerHeight - 50 : 800;
74
+ if (settings.position.x < 0 || settings.position.x > maxX ||
75
+ settings.position.y < 0 || settings.position.y > maxY) {
76
+ console.warn('FloatingMenuBar: Position out of bounds, resetting to defaults');
77
+ resetFloatingBarSettings();
78
+ return getDefaultConfig();
79
+ }
80
+ // Validate orientation
81
+ const validOrientation = (settings.orientation === 'horizontal' || settings.orientation === 'vertical')
82
+ ? settings.orientation
83
+ : 'horizontal';
84
+ // Validate itemIds
85
+ const validItemIds = Array.isArray(settings.itemIds) ? settings.itemIds : [];
86
+ if (validItemIds.length > 0) {
87
+ // Check if any ID looks like the old format (contains language-specific text or is too long)
88
+ const hasOldFormatIds = validItemIds.some(id => typeof id === 'string' &&
89
+ !id.startsWith('separator-') &&
90
+ (id.length > 20 || id.includes(' ')));
91
+ if (hasOldFormatIds) {
92
+ console.warn('FloatingMenuBar: Detected old name-based configuration, resetting to defaults');
93
+ resetFloatingBarSettings();
94
+ return getDefaultConfig();
95
+ }
96
+ }
97
+ // Migrate old pixel-based position to percentage-based
98
+ let finalPosition = settings.position;
99
+ if (isPixelFormat(settings.position) || settings.positionFormat === 'pixels') {
100
+ console.log('FloatingMenuBar: Migrating pixel-based position to percentage-based');
101
+ finalPosition = migrateToPercentage(settings.position);
102
+ // Save migrated position immediately
103
+ SDKUI_Globals.userSettings.searchSettings.floatingMenuBar = {
104
+ orientation: validOrientation,
105
+ itemIds: validItemIds,
106
+ position: finalPosition,
107
+ positionFormat: 'percentage',
19
108
  };
20
109
  }
110
+ return {
111
+ orientation: validOrientation,
112
+ savedItemIds: validItemIds,
113
+ position: finalPosition,
114
+ };
21
115
  }
22
116
  catch (error) {
23
117
  console.error('Failed to load FloatingMenuBar config:', error);
118
+ // Reset to defaults on any error
119
+ try {
120
+ resetFloatingBarSettings();
121
+ }
122
+ catch (e) {
123
+ console.error('Failed to reset FloatingMenuBar settings:', e);
124
+ }
125
+ return getDefaultConfig();
24
126
  }
25
- return {
26
- orientation: 'horizontal',
27
- pinnedItemIds: new Set(),
28
- savedItemIds: [],
29
- };
30
127
  };
31
128
  const initialConfig = loadConfig();
32
129
  const [state, setState] = useState({
33
- position: defaultPosition,
130
+ position: initialConfig.position, // Stored as percentage
34
131
  isDragging: false,
35
132
  isConfigMode: false,
36
133
  orientation: initialConfig.orientation,
@@ -39,32 +136,62 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
39
136
  });
40
137
  const floatingRef = useRef(null);
41
138
  const dragOffset = useRef({ x: 0, y: 0 });
42
- const [pinnedItemIds, setPinnedItemIds] = useState(initialConfig.pinnedItemIds);
43
139
  const [dragOverIndex, setDragOverIndex] = useState(null);
44
- const [showMaxItemsNotification, setShowMaxItemsNotification] = useState(false);
45
- // Use refs to track item IDs without causing re-renders
140
+ const [pixelPosition, setPixelPosition] = useState({ x: 0, y: 0 }); // Calculated pixel position
141
+ const containerSizeRef = useRef({ width: 0, height: 0 });
142
+ const stateSnapshot = useRef(null);
46
143
  const floatingBarItemIds = useRef(new Set());
47
144
  const floatingBarItemNames = useRef(new Set());
48
- // Update refs when items change, but don't trigger re-renders
49
145
  useEffect(() => {
50
146
  floatingBarItemIds.current = new Set(state.items.map(i => i.id));
51
147
  floatingBarItemNames.current = new Set(state.items.map(i => i.name));
52
148
  }, [state.items]);
53
- // Convert menu items to flat list with pinned status
149
+ // Calculate pixel position from percentage when container size or position changes
150
+ useEffect(() => {
151
+ const updatePixelPosition = () => {
152
+ if (!containerRef.current || !floatingRef.current)
153
+ return;
154
+ const container = containerRef.current.getBoundingClientRect();
155
+ const floating = floatingRef.current.getBoundingClientRect();
156
+ const containerWidth = isConstrained ? container.width : window.innerWidth;
157
+ const containerHeight = isConstrained ? container.height : window.innerHeight;
158
+ containerSizeRef.current = { width: containerWidth, height: containerHeight };
159
+ let newX = percentToPixels(state.position.x, containerWidth);
160
+ let newY = percentToPixels(state.position.y, containerHeight);
161
+ newX = Math.max(0, Math.min(newX, containerWidth - floating.width));
162
+ newY = Math.max(0, Math.min(newY, containerHeight - floating.height));
163
+ setPixelPosition({ x: newX, y: newY });
164
+ };
165
+ updatePixelPosition();
166
+ const resizeObserver = new ResizeObserver(() => {
167
+ updatePixelPosition();
168
+ });
169
+ if (containerRef.current) {
170
+ resizeObserver.observe(containerRef.current);
171
+ }
172
+ if (!isConstrained) {
173
+ window.addEventListener('resize', updatePixelPosition);
174
+ }
175
+ return () => {
176
+ resizeObserver.disconnect();
177
+ if (!isConstrained) {
178
+ window.removeEventListener('resize', updatePixelPosition);
179
+ }
180
+ };
181
+ }, [state.position, isConstrained]);
54
182
  const flattenMenuItems = useCallback((items, parentPath = '') => {
55
183
  const result = [];
56
184
  items.forEach((item, index) => {
57
- const itemId = `${parentPath}${item.name}-${index}`;
58
- // Only add items that have onClick (final actions, not submenu parents)
185
+ const itemId = item.id || `${parentPath}${item.name}-${index}`;
59
186
  if (item.onClick && !item.submenu) {
187
+ const isPinned = state.items.some(i => i.id === itemId);
60
188
  result.push({
61
189
  id: itemId,
62
190
  name: item.name,
63
- icon: item.icon || _jsx(IconStar, {}),
191
+ icon: item.icon || _jsx(IconPin, {}),
64
192
  onClick: item.onClick,
65
193
  disabled: item.disabled,
66
- isPinned: pinnedItemIds.has(itemId),
67
- originalMenuItem: item,
194
+ isPinned: isPinned,
68
195
  });
69
196
  }
70
197
  // Recursively process submenus
@@ -73,56 +200,82 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
73
200
  }
74
201
  });
75
202
  return result;
76
- }, [pinnedItemIds]);
203
+ }, [state.items]);
77
204
  // Restore items on mount from savedItemIds
78
205
  useEffect(() => {
79
- if (contextMenuItems.length > 0) {
206
+ if (contextMenuItems.length > 0 || initialConfig.savedItemIds.length > 0 || defaultItems.length > 0) {
80
207
  const flatItems = flattenMenuItems(contextMenuItems);
81
- // Restore items in the saved order from localStorage
82
- const restoredItems = initialConfig.savedItemIds
83
- .map((id) => flatItems.find(item => item.id === id))
84
- .filter((item) => item !== undefined);
85
- if (restoredItems.length > 0) {
86
- setState(s => ({ ...s, items: restoredItems }));
208
+ let itemsToSet = [];
209
+ // If disbaleConfigMode is true and defaultItems provided, use only defaultItems
210
+ if (disbaleConfigMode && defaultItems.length > 0) {
211
+ itemsToSet = defaultItems;
212
+ }
213
+ else if (!disbaleConfigMode && initialConfig.savedItemIds.length > 0) {
214
+ // Restore items in the saved order from localStorage (only if config mode is enabled)
215
+ const restoredItems = initialConfig.savedItemIds
216
+ .map((id) => {
217
+ if (id.startsWith('separator-')) {
218
+ return {
219
+ id,
220
+ name: 'Separator',
221
+ icon: _jsx(Separator, {}),
222
+ onClick: () => { },
223
+ isSeparator: true,
224
+ };
225
+ }
226
+ return flatItems.find(item => item.id === id);
227
+ })
228
+ .filter((item) => item !== undefined);
229
+ itemsToSet = restoredItems;
230
+ }
231
+ else if (contextMenuDefaultPinnedIds.length > 0) {
232
+ // First time: Use contextMenuDefaultPinnedIds from props to find items by ID
233
+ const defaultPinnedItems = contextMenuDefaultPinnedIds
234
+ .map((id) => flatItems.find(item => item.id === id))
235
+ .filter((item) => item !== undefined);
236
+ itemsToSet = defaultPinnedItems;
237
+ }
238
+ else if (defaultItems.length > 0) {
239
+ // Use defaultItems as fallback
240
+ itemsToSet = defaultItems;
241
+ }
242
+ if (itemsToSet.length > 0) {
243
+ setState(s => ({ ...s, items: itemsToSet }));
87
244
  }
88
245
  }
89
- }, []); // Only run once on mount
246
+ }, disbaleConfigMode ? [defaultItems] : []); // Update when defaultItems change if config mode is disabled
90
247
  const togglePin = useCallback((item) => {
91
248
  setState(s => {
92
- const isInFloatingBar = s.items.some(i => i.id === item.id || i.name === item.name);
249
+ const isInFloatingBar = s.items.some(i => i.id === item.id);
93
250
  if (isInFloatingBar) {
94
251
  // Remove from floating bar
95
- const newItems = s.items.filter(i => i.id !== item.id && i.name !== item.name);
252
+ const newItems = s.items.filter(i => i.id !== item.id);
96
253
  return { ...s, items: newItems };
97
254
  }
98
255
  else {
99
256
  // Add to floating bar
100
257
  if (s.items.length >= maxItems) {
101
- setShowMaxItemsNotification(true);
102
- setTimeout(() => setShowMaxItemsNotification(false), 3000);
258
+ ShowAlert({
259
+ mode: 'warning',
260
+ title: 'Limite Massimo Raggiunto',
261
+ message: `Hai raggiunto il massimo di ${maxItems} elementi. Rimuovine uno prima di aggiungerne altri.`,
262
+ duration: 4000,
263
+ });
103
264
  return s;
104
265
  }
105
266
  return { ...s, items: [...s.items, item] };
106
267
  }
107
268
  });
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
269
  }, [maxItems]);
120
270
  // Get current item state (disabled and onClick) from contextMenuItems
121
- const getCurrentItemState = useCallback((itemName) => {
271
+ const getCurrentItemState = useCallback((itemId) => {
122
272
  const findInItems = (items) => {
123
- for (const item of items) {
124
- if (item.name === itemName)
273
+ for (let i = 0; i < items.length; i++) {
274
+ const item = items[i];
275
+ // Match by ID if the item has one
276
+ if (item.id === itemId)
125
277
  return item;
278
+ // Check in submenu
126
279
  if (item.submenu) {
127
280
  const found = findInItems(item.submenu);
128
281
  if (found)
@@ -136,34 +289,96 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
136
289
  disabled: foundItem?.disabled,
137
290
  onClick: foundItem?.onClick
138
291
  };
139
- }, [contextMenuItems]); // Enhanced context menu items with pin functionality
140
- const enhancedContextMenuItems = useCallback(() => {
292
+ }, [contextMenuItems]);
293
+ // Remove trailing separators from items array
294
+ const removeTrailingSeparators = useCallback((items) => {
295
+ const result = [...items];
296
+ while (result.length > 0 && result.at(-1)?.isSeparator) {
297
+ result.pop();
298
+ }
299
+ return result;
300
+ }, []);
301
+ // Create a new separator item
302
+ const createSeparator = useCallback(() => {
303
+ const separatorId = `separator-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
304
+ return {
305
+ id: separatorId,
306
+ name: 'Separator',
307
+ icon: _jsx(Separator, {}),
308
+ onClick: () => { },
309
+ isSeparator: true,
310
+ };
311
+ }, []);
312
+ // Add separator to items
313
+ const addSeparator = useCallback(() => {
314
+ if (state.items.length >= maxItems) {
315
+ ShowAlert({
316
+ mode: 'warning',
317
+ title: 'Limite Massimo Raggiunto',
318
+ message: `Hai raggiunto il massimo di ${maxItems} elementi. Rimuovine uno prima di aggiungerne altri.`,
319
+ duration: 4000,
320
+ });
321
+ return;
322
+ }
323
+ const separator = createSeparator();
324
+ setState(s => ({ ...s, items: [...s.items, separator] }));
325
+ }, [state.items.length, maxItems, createSeparator]);
326
+ const getPinContextMenuItems = useCallback(() => {
141
327
  const flatItems = flattenMenuItems(contextMenuItems);
142
- // Calculate current pinned items directly from state.items (not refs)
143
328
  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) => {
329
+ const createPinItems = (items) => {
146
330
  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 = {
331
+ const flatItem = flatItems.find(fi => fi.id === item.id);
332
+ const itemId = flatItem?.id || item.id || '';
333
+ const isAlreadyPinned = currentItemIds.has(itemId);
334
+ const pinItem = {
152
335
  ...item,
153
- rightIcon: item.onClick && !item.submenu ? (isInFloatingBar ? _jsx(IconStar, { color: "#FFD700" }) : _jsx(IconStar, {})) : undefined,
154
- onRightIconClick: item.onClick && !item.submenu ? () => {
155
- if (flatItem) {
336
+ onClick: item.onClick && !item.submenu ? () => {
337
+ if (flatItem && !isAlreadyPinned) {
156
338
  togglePin(flatItem);
157
339
  }
158
340
  } : undefined,
341
+ disabled: isAlreadyPinned,
342
+ };
343
+ if (item.submenu) {
344
+ pinItem.submenu = createPinItems(item.submenu);
345
+ }
346
+ return pinItem;
347
+ });
348
+ };
349
+ const pinItems = createPinItems(contextMenuItems);
350
+ // Add separator option at the end
351
+ pinItems.push({
352
+ id: 'add-separator',
353
+ name: SDKUI_Localizator.Add + ' separatore',
354
+ icon: _jsx(IconSeparator, {}),
355
+ onClick: addSeparator,
356
+ beginGroup: true
357
+ });
358
+ return pinItems;
359
+ }, [contextMenuItems, flattenMenuItems, togglePin, state.items, addSeparator]);
360
+ const getContextMenuItemsWithPinIcons = useCallback(() => {
361
+ const flatItems = flattenMenuItems(contextMenuItems);
362
+ const currentItemIds = new Set(state.items.map(i => i.id));
363
+ const addPinIcons = (items) => {
364
+ return items.map(item => {
365
+ const flatItem = flatItems.find(fi => fi.id === item.id);
366
+ const itemId = flatItem?.id || item.id || '';
367
+ const isPinned = currentItemIds.has(itemId);
368
+ const itemWithPin = {
369
+ ...item,
370
+ rightIcon: flatItem ? _jsx(IconPin, { color: isPinned ? 'red' : 'black' }) : undefined,
371
+ onRightIconClick: flatItem ? () => {
372
+ togglePin(flatItem);
373
+ } : undefined,
159
374
  };
160
375
  if (item.submenu) {
161
- enhanced.submenu = enhanceItems(item.submenu);
376
+ itemWithPin.submenu = addPinIcons(item.submenu);
162
377
  }
163
- return enhanced;
378
+ return itemWithPin;
164
379
  });
165
380
  };
166
- return enhanceItems(contextMenuItems);
381
+ return addPinIcons(contextMenuItems);
167
382
  }, [contextMenuItems, flattenMenuItems, togglePin, state.items]);
168
383
  const handleMouseDown = (e) => {
169
384
  if (state.isConfigMode)
@@ -174,20 +389,25 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
174
389
  if (isConstrained) {
175
390
  // For absolute positioning, offset is relative to container
176
391
  dragOffset.current = {
177
- x: e.clientX - containerRect.left - state.position.x,
178
- y: e.clientY - containerRect.top - state.position.y,
392
+ x: e.clientX - containerRect.left - pixelPosition.x,
393
+ y: e.clientY - containerRect.top - pixelPosition.y,
179
394
  };
180
395
  }
181
396
  else {
182
397
  // For fixed positioning, offset is relative to viewport
183
398
  dragOffset.current = {
184
- x: e.clientX - state.position.x,
185
- y: e.clientY - state.position.y,
399
+ x: e.clientX - pixelPosition.x,
400
+ y: e.clientY - pixelPosition.y,
186
401
  };
187
402
  }
188
403
  }
189
404
  setState(s => ({ ...s, isDragging: true }));
190
405
  };
406
+ const handleGripDoubleClick = () => {
407
+ if (state.isConfigMode)
408
+ return;
409
+ toggleOrientation();
410
+ };
191
411
  const handleMouseMove = useCallback((e) => {
192
412
  if (!state.isDragging || !containerRef.current || !floatingRef.current)
193
413
  return;
@@ -210,50 +430,267 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
210
430
  newX = Math.max(0, Math.min(newX, window.innerWidth - floating.width));
211
431
  newY = Math.max(0, Math.min(newY, window.innerHeight - floating.height));
212
432
  }
213
- setState(s => ({
214
- ...s,
215
- position: { x: newX, y: newY },
216
- }));
433
+ // Update pixel position directly during drag
434
+ setPixelPosition({ x: newX, y: newY });
217
435
  }, [state.isDragging, containerRef, isConstrained]);
218
436
  const handleMouseUp = useCallback(() => {
219
- setState(s => ({ ...s, isDragging: false }));
220
- }, []);
437
+ if (state.isDragging && containerSizeRef.current.width > 0) {
438
+ // Convert final pixel position to percentage before updating state
439
+ const percentagePosition = {
440
+ x: pixelsToPercent(pixelPosition.x, containerSizeRef.current.width),
441
+ y: pixelsToPercent(pixelPosition.y, containerSizeRef.current.height),
442
+ };
443
+ setState(s => ({
444
+ ...s,
445
+ isDragging: false,
446
+ position: percentagePosition,
447
+ }));
448
+ }
449
+ else {
450
+ setState(s => ({ ...s, isDragging: false }));
451
+ }
452
+ }, [state.isDragging, pixelPosition]);
453
+ // Touch event handlers for tablet support
454
+ const handleTouchStart = (e) => {
455
+ if (state.isConfigMode)
456
+ return;
457
+ const touch = e.touches[0];
458
+ const containerRect = containerRef.current?.getBoundingClientRect();
459
+ if (containerRect) {
460
+ if (isConstrained) {
461
+ dragOffset.current = {
462
+ x: touch.clientX - containerRect.left - pixelPosition.x,
463
+ y: touch.clientY - containerRect.top - pixelPosition.y,
464
+ };
465
+ }
466
+ else {
467
+ dragOffset.current = {
468
+ x: touch.clientX - pixelPosition.x,
469
+ y: touch.clientY - pixelPosition.y,
470
+ };
471
+ }
472
+ }
473
+ setState(s => ({ ...s, isDragging: true }));
474
+ };
475
+ const handleTouchMove = useCallback((e) => {
476
+ if (!state.isDragging || !containerRef.current || !floatingRef.current)
477
+ return;
478
+ const touch = e.touches[0];
479
+ const container = containerRef.current.getBoundingClientRect();
480
+ const floating = floatingRef.current.getBoundingClientRect();
481
+ let newX, newY;
482
+ if (isConstrained) {
483
+ newX = touch.clientX - container.left - dragOffset.current.x;
484
+ newY = touch.clientY - container.top - dragOffset.current.y;
485
+ newX = Math.max(0, Math.min(newX, container.width - floating.width));
486
+ newY = Math.max(0, Math.min(newY, container.height - floating.height));
487
+ }
488
+ else {
489
+ newX = touch.clientX - dragOffset.current.x;
490
+ newY = touch.clientY - dragOffset.current.y;
491
+ newX = Math.max(0, Math.min(newX, window.innerWidth - floating.width));
492
+ newY = Math.max(0, Math.min(newY, window.innerHeight - floating.height));
493
+ }
494
+ setPixelPosition({ x: newX, y: newY });
495
+ }, [state.isDragging, containerRef, isConstrained]);
496
+ const handleTouchEnd = useCallback(() => {
497
+ if (state.isDragging && containerSizeRef.current.width > 0) {
498
+ const percentagePosition = {
499
+ x: pixelsToPercent(pixelPosition.x, containerSizeRef.current.width),
500
+ y: pixelsToPercent(pixelPosition.y, containerSizeRef.current.height),
501
+ };
502
+ setState(s => ({
503
+ ...s,
504
+ isDragging: false,
505
+ position: percentagePosition,
506
+ }));
507
+ }
508
+ else {
509
+ setState(s => ({ ...s, isDragging: false }));
510
+ }
511
+ }, [state.isDragging, pixelPosition]);
221
512
  useEffect(() => {
222
513
  if (state.isDragging) {
223
514
  document.addEventListener('mousemove', handleMouseMove);
224
515
  document.addEventListener('mouseup', handleMouseUp);
516
+ document.addEventListener('touchmove', handleTouchMove);
517
+ document.addEventListener('touchend', handleTouchEnd);
225
518
  return () => {
226
519
  document.removeEventListener('mousemove', handleMouseMove);
227
520
  document.removeEventListener('mouseup', handleMouseUp);
521
+ document.removeEventListener('touchmove', handleTouchMove);
522
+ document.removeEventListener('touchend', handleTouchEnd);
228
523
  };
229
524
  }
230
525
  return undefined;
231
- }, [state.isDragging, handleMouseMove, handleMouseUp]);
232
- // Save to localStorage whenever config changes (excluding position)
526
+ }, [state.isDragging, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
527
+ // Save to SDKUI_Globals.userSettings only when NOT in config mode (when applying changes)
233
528
  useEffect(() => {
529
+ if (state.isConfigMode)
530
+ return; // Don't save during edit mode
531
+ if (disbaleConfigMode)
532
+ return; // Don't save if config mode is disabled
234
533
  try {
235
- const config = {
534
+ // Replace the entire object to trigger the Proxy
535
+ SDKUI_Globals.userSettings.searchSettings.floatingMenuBar = {
236
536
  orientation: state.orientation,
237
- pinnedItemIds: Array.from(pinnedItemIds),
238
- itemIds: state.items.map(item => item.id), // Save only IDs, not functions
537
+ itemIds: state.items.map(item => item.id),
538
+ position: state.position,
539
+ positionFormat: 'percentage',
239
540
  };
240
- localStorage.setItem(storageKey, JSON.stringify(config));
241
541
  }
242
542
  catch (error) {
243
543
  console.error('Failed to save FloatingMenuBar config:', error);
244
544
  }
245
- }, [state.orientation, state.items, pinnedItemIds, storageKey]);
545
+ }, [state.orientation, state.items, state.position, state.isConfigMode, disbaleConfigMode]);
246
546
  const toggleConfigMode = () => {
247
- setState(s => ({ ...s, isConfigMode: !s.isConfigMode }));
547
+ setState(s => {
548
+ if (!s.isConfigMode) {
549
+ stateSnapshot.current = {
550
+ items: [...s.items],
551
+ orientation: s.orientation,
552
+ position: { ...s.position },
553
+ };
554
+ return { ...s, isConfigMode: true };
555
+ }
556
+ else {
557
+ // Exiting edit mode (applying changes) - clean up trailing separators and clear snapshot
558
+ stateSnapshot.current = null;
559
+ const cleanedItems = removeTrailingSeparators(s.items);
560
+ return { ...s, isConfigMode: false, items: cleanedItems };
561
+ }
562
+ });
563
+ };
564
+ // Auto-reposition when entering edit mode to ensure Apply/Undo buttons are visible
565
+ useEffect(() => {
566
+ if (!state.isConfigMode || !floatingRef.current)
567
+ return;
568
+ // Use double requestAnimationFrame to ensure the DOM has fully updated with new buttons
569
+ requestAnimationFrame(() => {
570
+ requestAnimationFrame(() => {
571
+ if (!floatingRef.current)
572
+ return;
573
+ const floating = floatingRef.current.getBoundingClientRect();
574
+ const containerWidth = isConstrained && containerRef.current
575
+ ? containerRef.current.getBoundingClientRect().width
576
+ : window.innerWidth;
577
+ const containerHeight = isConstrained && containerRef.current
578
+ ? containerRef.current.getBoundingClientRect().height
579
+ : window.innerHeight;
580
+ // Use current pixel position
581
+ let newPixelX = pixelPosition.x;
582
+ let newPixelY = pixelPosition.y;
583
+ let needsUpdate = false;
584
+ // Check horizontal overflow
585
+ if (newPixelX + floating.width > containerWidth) {
586
+ newPixelX = Math.max(0, containerWidth - floating.width);
587
+ needsUpdate = true;
588
+ }
589
+ // Check vertical overflow
590
+ if (newPixelY + floating.height > containerHeight) {
591
+ newPixelY = Math.max(0, containerHeight - floating.height);
592
+ needsUpdate = true;
593
+ }
594
+ if (needsUpdate) {
595
+ // Update pixel position immediately
596
+ setPixelPosition({ x: newPixelX, y: newPixelY });
597
+ // Convert to percentage for state
598
+ const newPercentagePosition = {
599
+ x: pixelsToPercent(newPixelX, containerWidth),
600
+ y: pixelsToPercent(newPixelY, containerHeight),
601
+ };
602
+ setState(s => ({
603
+ ...s,
604
+ position: newPercentagePosition,
605
+ }));
606
+ // Update snapshot position to the corrected position so Undo restores to visible position
607
+ if (stateSnapshot.current) {
608
+ stateSnapshot.current.position = newPercentagePosition;
609
+ }
610
+ }
611
+ });
612
+ });
613
+ }, [state.isConfigMode, state.orientation, isConstrained, state.items, pixelPosition.x, pixelPosition.y]);
614
+ const handleUndo = () => {
615
+ if (stateSnapshot.current) {
616
+ setState(s => ({
617
+ ...s,
618
+ items: [...stateSnapshot.current.items],
619
+ orientation: stateSnapshot.current.orientation,
620
+ position: { ...stateSnapshot.current.position },
621
+ isConfigMode: true,
622
+ }));
623
+ }
624
+ };
625
+ // Check if current state has changed from snapshot
626
+ const hasChanges = () => {
627
+ if (!stateSnapshot.current)
628
+ return false;
629
+ // Check if items have changed (different IDs or different order)
630
+ const currentIds = state.items.map(i => i.id).join(',');
631
+ const snapshotIds = stateSnapshot.current.items.map(i => i.id).join(',');
632
+ return currentIds !== snapshotIds;
633
+ };
634
+ const handleClose = () => {
635
+ // If all items removed, exit without asking and restore last items
636
+ if (state.items.length === 0 && stateSnapshot.current) {
637
+ setState(s => ({
638
+ ...s,
639
+ items: [...stateSnapshot.current.items],
640
+ orientation: stateSnapshot.current.orientation,
641
+ position: { ...stateSnapshot.current.position },
642
+ isConfigMode: false,
643
+ }));
644
+ stateSnapshot.current = null;
645
+ return;
646
+ }
647
+ // If no changes, simply exit config mode
648
+ if (!hasChanges()) {
649
+ stateSnapshot.current = null;
650
+ const cleanedItems = removeTrailingSeparators(state.items);
651
+ setState(s => ({ ...s, isConfigMode: false, items: cleanedItems }));
652
+ return;
653
+ }
654
+ // If there are changes, ask for confirmation
655
+ TMMessageBoxManager.show({
656
+ message: 'Perderai le tue modifiche, sei sicuro?',
657
+ buttons: [ButtonNames.YES, ButtonNames.NO],
658
+ onButtonClick: (buttonName) => {
659
+ if (buttonName === ButtonNames.YES && stateSnapshot.current) {
660
+ // Restore snapshot and exit config mode
661
+ setState(s => ({
662
+ ...s,
663
+ items: [...stateSnapshot.current.items],
664
+ orientation: stateSnapshot.current.orientation,
665
+ position: { ...stateSnapshot.current.position },
666
+ isConfigMode: false,
667
+ }));
668
+ stateSnapshot.current = null;
669
+ }
670
+ },
671
+ });
248
672
  };
249
673
  const toggleOrientation = () => {
250
674
  const newOrientation = state.orientation === 'horizontal' ? 'vertical' : 'horizontal';
251
- // First, change the orientation
675
+ if (state.orientation === 'horizontal' && newOrientation === 'vertical') {
676
+ if (floatingRef.current) {
677
+ const floating = floatingRef.current.getBoundingClientRect();
678
+ const screenHeight = window.innerHeight;
679
+ if (floating.width > screenHeight - 70) {
680
+ ShowAlert({
681
+ mode: 'warning',
682
+ title: 'Troppi elementi',
683
+ message: 'Ci sono troppi elementi nella barra mobile per la modalità verticale.',
684
+ duration: 4000,
685
+ });
686
+ return;
687
+ }
688
+ }
689
+ }
252
690
  setState(s => ({
253
691
  ...s,
254
692
  orientation: newOrientation,
255
693
  }));
256
- // Then, after DOM updates, adjust position to stay in bounds
257
694
  requestAnimationFrame(() => {
258
695
  requestAnimationFrame(() => {
259
696
  if (containerRef.current && floatingRef.current) {
@@ -286,12 +723,6 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
286
723
  ...s,
287
724
  items: s.items.filter(item => item.id !== itemId),
288
725
  }));
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
726
  };
296
727
  // Drag and drop for reordering
297
728
  const handleDragStart = (e, index) => {
@@ -347,24 +778,44 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
347
778
  setState(s => ({ ...s, draggedItemIndex: null }));
348
779
  setDragOverIndex(null);
349
780
  };
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) => {
781
+ 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, "$bgColor": bgColor, onContextMenu: (e) => e.preventDefault(), children: [!state.isConfigMode ? (_jsx(ContextMenu, { items: [
782
+ ...(!disbaleConfigMode ? [{
783
+ name: SDKUI_Localizator.Configure,
784
+ onClick: () => {
785
+ if (!state.isConfigMode) {
786
+ toggleConfigMode();
787
+ }
788
+ },
789
+ }] : []),
790
+ {
791
+ name: state.orientation === 'horizontal' ? 'Floating bar verticale' : 'Floating bar orizzontale',
792
+ onClick: toggleOrientation,
793
+ },
794
+ ], 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) => {
795
+ // Handle separator items
796
+ if (item.isSeparator) {
797
+ 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));
798
+ }
351
799
  // Get current state (disabled and onClick) from contextMenuItems
352
- const currentState = getCurrentItemState(item.name);
353
- const isDisabled = currentState.disabled || false;
800
+ const currentState = getCurrentItemState(item.id);
801
+ // Prefer currentState.disabled if contextMenuItems has items, otherwise use item.disabled
802
+ const isDisabled = (contextMenuItems.length > 0 && currentState.disabled !== undefined)
803
+ ? currentState.disabled === true
804
+ : item.disabled === true;
354
805
  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: () => {
362
- if (state.isConfigMode || isDisabled)
363
- return;
364
- if (currentOnClick) {
365
- currentOnClick();
366
- }
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) }) }))] }));
806
+ return (_jsx(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: item.staticItem ? (
807
+ // Visualizza l'elemento statico personalizzato
808
+ _jsxs(_Fragment, { children: [item.staticItem, state.isConfigMode && (_jsx(S.RemoveButton, { onClick: () => removeItem(item.id), children: "\u00D7" }))] })) : (
809
+ // Visualizza il pulsante standard
810
+ _jsxs(_Fragment, { children: [_jsx(TMTooltip, { content: item.name, position: "bottom", children: _jsx(S.MenuButton, { onClick: () => {
811
+ if (state.isConfigMode || isDisabled)
812
+ return;
813
+ if (currentOnClick) {
814
+ currentOnClick();
815
+ }
816
+ }, disabled: isDisabled, "$isActive": item.isToggle, children: item.icon }) }), state.isConfigMode && (_jsx(S.RemoveButton, { onClick: () => removeItem(item.id), children: "\u00D7" }))] })) }, item.id));
817
+ }), !state.isConfigMode && !disbaleConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getContextMenuItemsWithPinIcons(), trigger: "left", keepOpenOnClick: false, 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
818
+ ? 'Devi aggiungere almeno un item'
819
+ : 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
820
  };
370
821
  export default TMFloatingMenuBar;