@topconsultnpm/sdkui-react 6.20.0-dev1.99 → 6.20.0-dev2.1

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 (91) hide show
  1. package/lib/assets/headergradient.svg +87 -0
  2. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +56 -18
  3. package/lib/components/NewComponents/ContextMenu/styles.js +13 -34
  4. package/lib/components/NewComponents/ContextMenu/types.d.ts +8 -2
  5. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +315 -271
  6. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +4 -0
  7. package/lib/components/NewComponents/FloatingMenuBar/styles.js +6 -2
  8. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +7 -4
  9. package/lib/components/base/TMButton.js +6 -0
  10. package/lib/components/base/TMClosableList.js +4 -0
  11. package/lib/components/base/TMDropDownMenu.js +2 -0
  12. package/lib/components/base/TMListView.js +1 -1
  13. package/lib/components/base/TMPanel.d.ts +1 -1
  14. package/lib/components/base/TMPanel.js +9 -5
  15. package/lib/components/base/TMPopUp.js +6 -0
  16. package/lib/components/base/TMToolbarCard.js +2 -0
  17. package/lib/components/base/TMTreeView.d.ts +2 -1
  18. package/lib/components/base/TMTreeView.js +33 -26
  19. package/lib/components/choosers/TMDataListItemChooser.d.ts +2 -0
  20. package/lib/components/choosers/TMDataListItemChooser.js +8 -2
  21. package/lib/components/choosers/TMDcmtTypeChooser.d.ts +1 -0
  22. package/lib/components/choosers/TMDcmtTypeChooser.js +11 -3
  23. package/lib/components/choosers/TMDistinctValues.js +2 -2
  24. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +2 -0
  25. package/lib/components/choosers/TMDynDataListItemChooser.js +8 -2
  26. package/lib/components/choosers/TMMetadataChooser.d.ts +2 -0
  27. package/lib/components/choosers/TMMetadataChooser.js +11 -3
  28. package/lib/components/choosers/TMUserChooser.d.ts +2 -0
  29. package/lib/components/choosers/TMUserChooser.js +8 -2
  30. package/lib/components/editors/TMCheckBox.js +2 -0
  31. package/lib/components/editors/TMDateBox.js +18 -9
  32. package/lib/components/editors/TMEditorStyled.js +7 -0
  33. package/lib/components/editors/TMLocalizedTextBox.d.ts +3 -1
  34. package/lib/components/editors/TMLocalizedTextBox.js +16 -14
  35. package/lib/components/editors/TMMetadataEditor.d.ts +1 -0
  36. package/lib/components/editors/TMMetadataEditor.js +4 -4
  37. package/lib/components/editors/TMMetadataTextBox.d.ts +9 -0
  38. package/lib/components/editors/TMMetadataTextBox.js +92 -0
  39. package/lib/components/editors/TMMetadataValues.d.ts +2 -0
  40. package/lib/components/editors/TMMetadataValues.js +3 -3
  41. package/lib/components/editors/TMRadioButton.js +2 -0
  42. package/lib/components/editors/TMTextBox.d.ts +1 -1
  43. package/lib/components/editors/TMTextBox.js +23 -1
  44. package/lib/components/editors/TMTextExpression.js +6 -91
  45. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +2 -0
  46. package/lib/components/features/documents/TMDcmtBlog.js +1 -1
  47. package/lib/components/features/documents/TMDcmtForm.js +120 -87
  48. package/lib/components/features/documents/TMDcmtPreview.js +27 -30
  49. package/lib/components/features/search/TMSearch.js +5 -1
  50. package/lib/components/features/search/TMSearchQueryEditor.d.ts +1 -0
  51. package/lib/components/features/search/TMSearchQueryEditor.js +10 -10
  52. package/lib/components/features/search/TMSearchQueryPanel.js +24 -10
  53. package/lib/components/features/search/TMSearchResult.js +168 -8
  54. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +1 -1
  55. package/lib/components/features/search/TMSearchResultsMenuItems.js +24 -4
  56. package/lib/components/features/search/TMViewHistoryDcmt.js +45 -50
  57. package/lib/components/features/tasks/TMTaskForm.js +55 -24
  58. package/lib/components/features/tasks/TMTasksUtils.js +14 -1
  59. package/lib/components/features/workflow/TMWorkflowPopup.js +5 -4
  60. package/lib/components/features/workflow/diagram/DiagramItemComponent.js +2 -0
  61. package/lib/components/features/workflow/diagram/DiagramItemForm.js +1 -1
  62. package/lib/components/features/workflow/diagram/WFDiagram.js +1 -1
  63. package/lib/components/forms/Login/TMLoginForm.js +1 -1
  64. package/lib/components/grids/TMValidationItemsList.js +6 -0
  65. package/lib/components/index.d.ts +1 -0
  66. package/lib/components/index.js +1 -0
  67. package/lib/components/layout/panelManager/TMPanelManagerContext.js +13 -5
  68. package/lib/components/query/TMQueryEditor.d.ts +4 -0
  69. package/lib/components/query/TMQueryEditor.js +14 -10
  70. package/lib/components/sidebar/TMHeader.js +11 -7
  71. package/lib/components/sidebar/TMSidebar.d.ts +0 -1
  72. package/lib/components/sidebar/TMSidebar.js +16 -44
  73. package/lib/components/sidebar/TMSidebarItem.js +36 -17
  74. package/lib/helper/SDKUI_Globals.d.ts +3 -0
  75. package/lib/helper/SDKUI_Globals.js +6 -3
  76. package/lib/helper/SDKUI_Localizator.d.ts +4 -16
  77. package/lib/helper/SDKUI_Localizator.js +37 -157
  78. package/lib/helper/TMIcons.d.ts +1 -0
  79. package/lib/helper/TMIcons.js +3 -0
  80. package/lib/helper/TMToppyMessage.js +4 -0
  81. package/lib/helper/TMUtils.d.ts +2 -1
  82. package/lib/helper/TMUtils.js +13 -1
  83. package/lib/helper/helpers.d.ts +27 -1
  84. package/lib/helper/helpers.js +107 -1
  85. package/lib/helper/queryHelper.d.ts +1 -1
  86. package/lib/helper/queryHelper.js +24 -1
  87. package/lib/hooks/useFloatingBarPinnedItems.d.ts +11 -0
  88. package/lib/hooks/useFloatingBarPinnedItems.js +54 -0
  89. package/lib/hooks/useMetadataExpression.d.ts +19 -0
  90. package/lib/hooks/useMetadataExpression.js +99 -0
  91. package/package.json +56 -56
@@ -1,14 +1,13 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { ContextMenu } from '../ContextMenu';
4
4
  import ShowAlert from '../../base/TMAlert';
5
5
  import TMTooltip from '../../base/TMTooltip';
6
6
  import * as S from './styles';
7
- import { IconAdd, IconCloseOutline, IconMenuVertical, IconPin, IconSave, IconSeparator, IconUndo, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
8
- import { ButtonNames, TMMessageBoxManager } from '../../base/TMPopUp';
7
+ import { IconDelete, IconMenuVertical, IconPin, IconRotate, IconSeparator, SDKUI_Globals } from '../../../helper';
9
8
  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" }) }));
10
9
  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" }) }));
11
- const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained = false, defaultPosition = { x: 1, y: 90 }, defaultOrientation = 'horizontal', maxItems = 100, contextMenuDefaultPinnedIds = [], defaultItems = [], disbaleConfigMode = false, bgColor = undefined, }) => {
10
+ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained = false, defaultPosition = { x: 1, y: 90 }, defaultOrientation = 'horizontal', maxItems = 100, defaultPinnedItems = [], fixedItems = [], enableConfigMode = true, bgColor = undefined, hasContextMenu = true, pinnedItemIds: externalPinnedItemIds, onPinChange, }) => {
12
11
  const percentToPixels = (percent, containerSize) => {
13
12
  return (percent / 100) * containerSize;
14
13
  };
@@ -29,7 +28,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
29
28
  };
30
29
  const getDefaultConfig = () => ({
31
30
  orientation: defaultOrientation,
32
- savedItemIds: contextMenuDefaultPinnedIds,
31
+ savedItemIds: defaultPinnedItems,
33
32
  position: defaultPosition,
34
33
  });
35
34
  const resetFloatingBarSettings = () => {
@@ -42,17 +41,17 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
42
41
  };
43
42
  const loadConfig = () => {
44
43
  // If config mode is disabled, use default position and orientation
45
- if (disbaleConfigMode) {
44
+ if (!enableConfigMode) {
46
45
  return {
47
46
  orientation: defaultOrientation,
48
- savedItemIds: contextMenuDefaultPinnedIds,
47
+ savedItemIds: defaultPinnedItems,
49
48
  position: defaultPosition,
50
49
  };
51
50
  }
52
51
  try {
53
52
  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) {
53
+ // If localStorage is empty (first time) or itemIds is empty array, use props as defaults
54
+ if (!settings || !settings.position || !settings.itemIds || settings.itemIds.length === 0) {
56
55
  return getDefaultConfig();
57
56
  }
58
57
  // Validate position
@@ -129,8 +128,8 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
129
128
  const [state, setState] = useState({
130
129
  position: initialConfig.position, // Stored as percentage
131
130
  isDragging: false,
132
- isConfigMode: false,
133
131
  orientation: initialConfig.orientation,
132
+ verticalDirection: 'down',
134
133
  items: [],
135
134
  draggedItemIndex: null,
136
135
  });
@@ -138,10 +137,15 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
138
137
  const dragOffset = useRef({ x: 0, y: 0 });
139
138
  const [dragOverIndex, setDragOverIndex] = useState(null);
140
139
  const [pixelPosition, setPixelPosition] = useState({ x: 0, y: 0 }); // Calculated pixel position
140
+ const [isOrientationChanging, setIsOrientationChanging] = useState(false); // Hide bar during orientation transition
141
141
  const containerSizeRef = useRef({ width: 0, height: 0 });
142
- const stateSnapshot = useRef(null);
142
+ const positionBeforeOrientationChange = useRef(null);
143
143
  const floatingBarItemIds = useRef(new Set());
144
144
  const floatingBarItemNames = useRef(new Set());
145
+ const isSyncingFromExternal = useRef(false);
146
+ const isLocalChange = useRef(false);
147
+ const dragStartPosition = useRef(null);
148
+ const isItemsInitialized = useRef(false);
145
149
  useEffect(() => {
146
150
  floatingBarItemIds.current = new Set(state.items.map(i => i.id));
147
151
  floatingBarItemNames.current = new Set(state.items.map(i => i.name));
@@ -201,49 +205,93 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
201
205
  });
202
206
  return result;
203
207
  }, [state.items]);
204
- // Restore items on mount from savedItemIds
208
+ // Restore items on mount (and when contextMenuItems become available) from savedItemIds
205
209
  useEffect(() => {
206
- if (contextMenuItems.length > 0 || initialConfig.savedItemIds.length > 0 || defaultItems.length > 0) {
207
- const flatItems = flattenMenuItems(contextMenuItems);
208
- let itemsToSet = [];
209
- // If disbaleConfigMode is true and defaultItems provided, use only defaultItems
210
- if (disbaleConfigMode && defaultItems.length > 0) {
211
- itemsToSet = defaultItems;
210
+ // For enableConfigMode=false: always sync with fixedItems
211
+ if (!enableConfigMode) {
212
+ if (fixedItems.length > 0) {
213
+ setState(s => ({ ...s, items: fixedItems }));
212
214
  }
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 }));
215
+ return;
216
+ }
217
+ // For enableConfigMode=true: only initialize once
218
+ if (isItemsInitialized.current)
219
+ return;
220
+ // Wait until contextMenuItems is populated
221
+ if (contextMenuItems.length === 0)
222
+ return;
223
+ const flatItems = flattenMenuItems(contextMenuItems);
224
+ if (flatItems.length === 0)
225
+ return;
226
+ let itemsToSet = [];
227
+ if (initialConfig.savedItemIds.length > 0) {
228
+ // Restore items in the saved order from localStorage
229
+ const restoredItems = initialConfig.savedItemIds
230
+ .map((id) => {
231
+ if (id.startsWith('separator-')) {
232
+ return {
233
+ id,
234
+ name: 'Separator',
235
+ icon: _jsx(Separator, {}),
236
+ onClick: () => { },
237
+ isSeparator: true,
238
+ };
239
+ }
240
+ return flatItems.find(item => item.id === id);
241
+ })
242
+ .filter((item) => item !== undefined);
243
+ itemsToSet = restoredItems;
244
+ }
245
+ // If still empty, try defaultPinnedItems
246
+ if (itemsToSet.length === 0 && defaultPinnedItems.length > 0) {
247
+ const resolvedDefaultItems = defaultPinnedItems
248
+ .map((id) => flatItems.find(item => item.id === id))
249
+ .filter((item) => item !== undefined);
250
+ itemsToSet = resolvedDefaultItems;
251
+ }
252
+ if (itemsToSet.length > 0) {
253
+ isItemsInitialized.current = true;
254
+ setState(s => ({ ...s, items: itemsToSet }));
255
+ }
256
+ // eslint-disable-next-line react-hooks/exhaustive-deps
257
+ }, [contextMenuItems, fixedItems, enableConfigMode]);
258
+ // Sync with external pinnedItemIds when they change (from parent component)
259
+ useEffect(() => {
260
+ // Skip sync if a local change was just made (e.g. right-click remove/add separator)
261
+ if (isLocalChange.current) {
262
+ isLocalChange.current = false;
263
+ return;
264
+ }
265
+ if (externalPinnedItemIds === undefined || !enableConfigMode)
266
+ return;
267
+ // Skip sync if external is empty but we have initialized items (first login case)
268
+ // The parent hook starts with [] but we've initialized with defaults
269
+ if (externalPinnedItemIds.length === 0 && state.items.length > 0)
270
+ return;
271
+ const flatItems = flattenMenuItems(contextMenuItems);
272
+ // Build items from external pinned IDs
273
+ const itemsFromExternal = externalPinnedItemIds
274
+ .map((id) => {
275
+ if (id.startsWith('separator-')) {
276
+ return {
277
+ id,
278
+ name: 'Separator',
279
+ icon: _jsx(Separator, {}),
280
+ onClick: () => { },
281
+ isSeparator: true,
282
+ };
244
283
  }
284
+ return flatItems.find(item => item.id === id);
285
+ })
286
+ .filter((item) => item !== undefined);
287
+ // Only update if different
288
+ const currentIds = state.items.map(i => i.id).join(',');
289
+ const newIds = itemsFromExternal.map(i => i.id).join(',');
290
+ if (currentIds !== newIds) {
291
+ isSyncingFromExternal.current = true; // Mark that we're syncing from external
292
+ setState(s => ({ ...s, items: itemsFromExternal }));
245
293
  }
246
- }, disbaleConfigMode ? [defaultItems] : []); // Update when defaultItems change if config mode is disabled
294
+ }, [externalPinnedItemIds, contextMenuItems, enableConfigMode, flattenMenuItems]);
247
295
  const togglePin = useCallback((item) => {
248
296
  setState(s => {
249
297
  const isInFloatingBar = s.items.some(i => i.id === item.id);
@@ -323,40 +371,6 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
323
371
  const separator = createSeparator();
324
372
  setState(s => ({ ...s, items: [...s.items, separator] }));
325
373
  }, [state.items.length, maxItems, createSeparator]);
326
- const getPinContextMenuItems = useCallback(() => {
327
- const flatItems = flattenMenuItems(contextMenuItems);
328
- const currentItemIds = new Set(state.items.map(i => i.id));
329
- const createPinItems = (items) => {
330
- return items.map(item => {
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 = {
335
- ...item,
336
- onClick: item.onClick && !item.submenu ? () => {
337
- if (flatItem && !isAlreadyPinned) {
338
- togglePin(flatItem);
339
- }
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
374
  const getContextMenuItemsWithPinIcons = useCallback(() => {
361
375
  const flatItems = flattenMenuItems(contextMenuItems);
362
376
  const currentItemIds = new Set(state.items.map(i => i.id));
@@ -367,9 +381,12 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
367
381
  const isPinned = currentItemIds.has(itemId);
368
382
  const itemWithPin = {
369
383
  ...item,
370
- rightIcon: flatItem ? _jsx(IconPin, { color: isPinned ? 'red' : 'black' }) : undefined,
371
- onRightIconClick: flatItem ? () => {
372
- togglePin(flatItem);
384
+ rightIconProps: flatItem ? {
385
+ icon: _jsx(IconPin, {}),
386
+ activeColor: 'red',
387
+ inactiveColor: 'black',
388
+ isActive: isPinned,
389
+ onClick: () => togglePin(flatItem),
373
390
  } : undefined,
374
391
  };
375
392
  if (item.submenu) {
@@ -381,8 +398,6 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
381
398
  return addPinIcons(contextMenuItems);
382
399
  }, [contextMenuItems, flattenMenuItems, togglePin, state.items]);
383
400
  const handleMouseDown = (e) => {
384
- if (state.isConfigMode)
385
- return;
386
401
  const containerRect = containerRef.current?.getBoundingClientRect();
387
402
  if (containerRect) {
388
403
  // Calculate drag offset based on positioning mode
@@ -401,11 +416,11 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
401
416
  };
402
417
  }
403
418
  }
419
+ // Save starting position to detect if user actually moved the bar
420
+ dragStartPosition.current = { ...pixelPosition };
404
421
  setState(s => ({ ...s, isDragging: true }));
405
422
  };
406
423
  const handleGripDoubleClick = () => {
407
- if (state.isConfigMode)
408
- return;
409
424
  toggleOrientation();
410
425
  };
411
426
  const handleMouseMove = useCallback((e) => {
@@ -440,6 +455,15 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
440
455
  x: pixelsToPercent(pixelPosition.x, containerSizeRef.current.width),
441
456
  y: pixelsToPercent(pixelPosition.y, containerSizeRef.current.height),
442
457
  };
458
+ // Only clear saved position if user actually moved the bar significantly (more than 5 pixels)
459
+ if (dragStartPosition.current) {
460
+ const dx = Math.abs(pixelPosition.x - dragStartPosition.current.x);
461
+ const dy = Math.abs(pixelPosition.y - dragStartPosition.current.y);
462
+ if (dx > 5 || dy > 5) {
463
+ positionBeforeOrientationChange.current = null;
464
+ }
465
+ }
466
+ dragStartPosition.current = null;
443
467
  setState(s => ({
444
468
  ...s,
445
469
  isDragging: false,
@@ -452,8 +476,6 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
452
476
  }, [state.isDragging, pixelPosition]);
453
477
  // Touch event handlers for tablet support
454
478
  const handleTouchStart = (e) => {
455
- if (state.isConfigMode)
456
- return;
457
479
  const touch = e.touches[0];
458
480
  const containerRect = containerRef.current?.getBoundingClientRect();
459
481
  if (containerRect) {
@@ -470,6 +492,8 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
470
492
  };
471
493
  }
472
494
  }
495
+ // Save starting position to detect if user actually moved the bar
496
+ dragStartPosition.current = { ...pixelPosition };
473
497
  setState(s => ({ ...s, isDragging: true }));
474
498
  };
475
499
  const handleTouchMove = useCallback((e) => {
@@ -499,6 +523,15 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
499
523
  x: pixelsToPercent(pixelPosition.x, containerSizeRef.current.width),
500
524
  y: pixelsToPercent(pixelPosition.y, containerSizeRef.current.height),
501
525
  };
526
+ // Only clear saved position if user actually moved the bar significantly (more than 5 pixels)
527
+ if (dragStartPosition.current) {
528
+ const dx = Math.abs(pixelPosition.x - dragStartPosition.current.x);
529
+ const dy = Math.abs(pixelPosition.y - dragStartPosition.current.y);
530
+ if (dx > 5 || dy > 5) {
531
+ positionBeforeOrientationChange.current = null;
532
+ }
533
+ }
534
+ dragStartPosition.current = null;
502
535
  setState(s => ({
503
536
  ...s,
504
537
  isDragging: false,
@@ -524,17 +557,16 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
524
557
  }
525
558
  return undefined;
526
559
  }, [state.isDragging, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
527
- // Save to SDKUI_Globals.userSettings only when NOT in config mode (when applying changes)
560
+ // Save to SDKUI_Globals.userSettings
528
561
  useEffect(() => {
529
- if (state.isConfigMode)
530
- return; // Don't save during edit mode
531
- if (disbaleConfigMode)
562
+ if (!enableConfigMode)
532
563
  return; // Don't save if config mode is disabled
564
+ const pinnedIds = state.items.map(item => item.id);
533
565
  try {
534
566
  // Replace the entire object to trigger the Proxy
535
567
  SDKUI_Globals.userSettings.searchSettings.floatingMenuBar = {
536
568
  orientation: state.orientation,
537
- itemIds: state.items.map(item => item.id),
569
+ itemIds: pinnedIds,
538
570
  position: state.position,
539
571
  positionFormat: 'percentage',
540
572
  };
@@ -542,154 +574,100 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
542
574
  catch (error) {
543
575
  console.error('Failed to save FloatingMenuBar config:', error);
544
576
  }
545
- }, [state.orientation, state.items, state.position, state.isConfigMode, disbaleConfigMode]);
546
- const toggleConfigMode = () => {
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;
577
+ // Notify parent about pin changes only if not syncing from external
578
+ // This prevents infinite loop: external change -> sync -> save -> onPinChange -> external change
579
+ if (!isSyncingFromExternal.current) {
580
+ onPinChange?.(pinnedIds);
653
581
  }
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
- });
672
- };
582
+ isSyncingFromExternal.current = false; // Reset the flag
583
+ }, [state.orientation, state.items, state.position, enableConfigMode, onPinChange]);
673
584
  const toggleOrientation = () => {
674
585
  const newOrientation = state.orientation === 'horizontal' ? 'vertical' : 'horizontal';
586
+ // When switching from vertical back to horizontal, restore the original position
587
+ // Use visibility hiding only for this case to prevent flicker during position restoration
588
+ if (state.orientation === 'vertical' && newOrientation === 'horizontal') {
589
+ if (positionBeforeOrientationChange.current) {
590
+ setIsOrientationChanging(true); // Hide only when restoring position
591
+ const savedPosition = positionBeforeOrientationChange.current.position;
592
+ const savedPixelPosition = positionBeforeOrientationChange.current.pixelPosition;
593
+ setPixelPosition(savedPixelPosition);
594
+ setState(s => ({
595
+ ...s,
596
+ orientation: newOrientation,
597
+ verticalDirection: 'down',
598
+ position: savedPosition,
599
+ }));
600
+ positionBeforeOrientationChange.current = null;
601
+ // Show the bar after the state has been applied
602
+ requestAnimationFrame(() => {
603
+ setIsOrientationChanging(false);
604
+ });
605
+ return;
606
+ }
607
+ }
608
+ // When switching to vertical, save current position and check if we need to expand upward
609
+ // Use opacity hiding (doesn't affect focus unlike visibility:hidden)
675
610
  if (state.orientation === 'horizontal' && newOrientation === 'vertical') {
611
+ setIsOrientationChanging(true);
612
+ // Save the current position before changing orientation
613
+ positionBeforeOrientationChange.current = {
614
+ position: { ...state.position },
615
+ pixelPosition: { ...pixelPosition },
616
+ };
676
617
  if (floatingRef.current) {
677
618
  const floating = floatingRef.current.getBoundingClientRect();
678
- const screenHeight = window.innerHeight;
679
- if (floating.width > screenHeight - 70) {
619
+ const containerHeight = isConstrained && containerRef.current
620
+ ? containerRef.current.getBoundingClientRect().height
621
+ : window.innerHeight;
622
+ // Estimate vertical height (horizontal width becomes vertical height)
623
+ const estimatedVerticalHeight = floating.width;
624
+ if (estimatedVerticalHeight > containerHeight - 70) {
680
625
  ShowAlert({
681
626
  mode: 'warning',
682
627
  title: 'Troppi elementi',
683
628
  message: 'Ci sono troppi elementi nella barra mobile per la modalità verticale.',
684
629
  duration: 4000,
685
630
  });
631
+ positionBeforeOrientationChange.current = null; // Clear saved position since we're not changing
632
+ setIsOrientationChanging(false); // Show bar again since we're not changing
633
+ return;
634
+ }
635
+ // Check if we're in the bottom part of the screen and don't have enough space below
636
+ const spaceBelow = containerHeight - floating.bottom;
637
+ const spaceAbove = floating.top;
638
+ const needsVerticalSpace = estimatedVerticalHeight - floating.height; // Additional space needed
639
+ // If not enough space below but enough space above, expand upward
640
+ if (spaceBelow < needsVerticalSpace && spaceAbove >= needsVerticalSpace) {
641
+ // Calculate the new Y position so the bottom of the bar stays at the same place
642
+ const currentBottom = pixelPosition.y + floating.height;
643
+ const newPixelY = currentBottom - estimatedVerticalHeight;
644
+ setState(s => ({
645
+ ...s,
646
+ orientation: newOrientation,
647
+ verticalDirection: 'up',
648
+ }));
649
+ // Update pixel position and percentage after orientation change
650
+ requestAnimationFrame(() => {
651
+ requestAnimationFrame(() => {
652
+ const newY = Math.max(0, newPixelY);
653
+ setPixelPosition(prev => ({ ...prev, y: newY }));
654
+ const newPercentY = pixelsToPercent(newY, containerHeight);
655
+ setState(s => ({
656
+ ...s,
657
+ position: { ...s.position, y: newPercentY },
658
+ }));
659
+ setIsOrientationChanging(false);
660
+ });
661
+ });
686
662
  return;
687
663
  }
688
664
  }
689
665
  }
666
+ // Default case: just change orientation without special positioning
690
667
  setState(s => ({
691
668
  ...s,
692
669
  orientation: newOrientation,
670
+ verticalDirection: 'down',
693
671
  }));
694
672
  requestAnimationFrame(() => {
695
673
  requestAnimationFrame(() => {
@@ -715,25 +693,97 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
715
693
  }));
716
694
  }
717
695
  }
696
+ setIsOrientationChanging(false);
718
697
  });
719
698
  });
720
699
  };
721
700
  const removeItem = (itemId) => {
701
+ isLocalChange.current = true;
722
702
  setState(s => ({
723
703
  ...s,
724
704
  items: s.items.filter(item => item.id !== itemId),
725
705
  }));
726
706
  };
707
+ const getItemRightClickMenuItems = useCallback((item, index) => {
708
+ const hasSeparatorOnRight = index < state.items.length - 1 && state.items[index + 1]?.isSeparator;
709
+ const hasSeparatorOnLeft = index > 0 && state.items[index - 1]?.isSeparator;
710
+ return [
711
+ {
712
+ name: 'Rimuovi',
713
+ icon: _jsx(IconDelete, { fontSize: 16 }),
714
+ onClick: () => removeItem(item.id),
715
+ },
716
+ {
717
+ name: 'Aggiungi separatore a sinistra',
718
+ icon: _jsx(IconSeparator, { fontSize: 16 }),
719
+ disabled: hasSeparatorOnLeft,
720
+ onClick: () => {
721
+ isLocalChange.current = true;
722
+ const separator = createSeparator();
723
+ setState(s => {
724
+ const newItems = [...s.items];
725
+ newItems.splice(index, 0, separator);
726
+ return { ...s, items: newItems };
727
+ });
728
+ },
729
+ },
730
+ {
731
+ name: 'Aggiungi separatore a destra',
732
+ icon: _jsx(IconSeparator, { style: { transform: 'rotate(-90deg)' }, fontSize: 16 }),
733
+ disabled: hasSeparatorOnRight,
734
+ onClick: () => {
735
+ isLocalChange.current = true;
736
+ const separator = createSeparator();
737
+ setState(s => {
738
+ const newItems = [...s.items];
739
+ newItems.splice(index + 1, 0, separator);
740
+ return { ...s, items: newItems };
741
+ });
742
+ },
743
+ },
744
+ {
745
+ beginGroup: true,
746
+ name: state.orientation === 'horizontal' ? 'Floating bar verticale' : 'Floating bar orizzontale',
747
+ icon: _jsx(IconRotate, { fontSize: 16 }),
748
+ onClick: toggleOrientation,
749
+ },
750
+ ];
751
+ }, [state.items, state.orientation, removeItem, createSeparator, toggleOrientation]);
752
+ const getSeparatorRightClickMenuItems = useCallback((index) => {
753
+ return [
754
+ {
755
+ name: 'Rimuovi',
756
+ icon: _jsx(IconDelete, { fontSize: 16 }),
757
+ onClick: () => removeItem(state.items[index].id),
758
+ },
759
+ {
760
+ name: 'Aggiungi separatore a sinistra',
761
+ icon: _jsx(IconSeparator, { fontSize: 16 }),
762
+ disabled: true,
763
+ },
764
+ {
765
+ name: 'Aggiungi separatore a destra',
766
+ icon: _jsx(IconSeparator, { style: { transform: 'rotate(-90deg)' }, fontSize: 16 }),
767
+ disabled: true,
768
+ },
769
+ {
770
+ beginGroup: true,
771
+ name: state.orientation === 'horizontal' ? 'Floating bar verticale' : 'Floating bar orizzontale',
772
+ icon: _jsx(IconRotate, { fontSize: 16 }),
773
+ onClick: toggleOrientation,
774
+ },
775
+ ];
776
+ }, [state.items, state.orientation, removeItem, toggleOrientation]);
727
777
  // Drag and drop for reordering
728
778
  const handleDragStart = (e, index) => {
729
- if (!state.isConfigMode)
779
+ if (!enableConfigMode)
730
780
  return;
731
781
  e.dataTransfer.effectAllowed = 'move';
732
782
  e.dataTransfer.setData('text/plain', index.toString());
733
783
  setState(s => ({ ...s, draggedItemIndex: index }));
734
784
  };
735
785
  const handleDragEnter = (e, index) => {
736
- if (!state.isConfigMode)
786
+ if (!enableConfigMode)
737
787
  return;
738
788
  e.preventDefault();
739
789
  if (state.draggedItemIndex !== index) {
@@ -741,13 +791,13 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
741
791
  }
742
792
  };
743
793
  const handleDragOver = (e) => {
744
- if (!state.isConfigMode)
794
+ if (!enableConfigMode)
745
795
  return;
746
796
  e.preventDefault();
747
797
  e.dataTransfer.dropEffect = 'move';
748
798
  };
749
799
  const handleDragLeave = (_e, index) => {
750
- if (!state.isConfigMode)
800
+ if (!enableConfigMode)
751
801
  return;
752
802
  // Only clear if we're actually leaving this specific item
753
803
  if (dragOverIndex === index) {
@@ -755,7 +805,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
755
805
  }
756
806
  };
757
807
  const handleDrop = (e, dropIndex) => {
758
- if (!state.isConfigMode || state.draggedItemIndex === null)
808
+ if (!enableConfigMode || state.draggedItemIndex === null)
759
809
  return;
760
810
  e.preventDefault();
761
811
  e.stopPropagation();
@@ -764,6 +814,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
764
814
  setDragOverIndex(null);
765
815
  return;
766
816
  }
817
+ isLocalChange.current = true;
767
818
  const newItems = [...state.items];
768
819
  const [draggedItem] = newItems.splice(dragIndex, 1);
769
820
  newItems.splice(dropIndex, 0, draggedItem);
@@ -778,44 +829,37 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
778
829
  setState(s => ({ ...s, draggedItemIndex: null }));
779
830
  setDragOverIndex(null);
780
831
  };
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
- }
799
- // Get current state (disabled and onClick) from contextMenuItems
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;
805
- const currentOnClick = currentState.onClick || item.onClick; // Fallback to stored onClick if not found
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 }) }) })] })] }))] })] }));
832
+ return (_jsxs(S.FloatingContainer, { ref: floatingRef, "$x": pixelPosition.x, "$y": pixelPosition.y, "$orientation": state.orientation, "$verticalDirection": state.verticalDirection, "$isDragging": state.isDragging, "$isConfigMode": false, "$isConstrained": isConstrained, "$isHidden": isOrientationChanging, "$bgColor": bgColor, onContextMenu: undefined, children: [_jsx(ContextMenu, { items: [
833
+ {
834
+ name: state.orientation === 'horizontal' ? 'Floating bar verticale' : 'Floating bar orizzontale',
835
+ icon: _jsx(IconRotate, { fontSize: 16, style: { transform: state.orientation === 'horizontal' ? 'rotate(90deg)' : 'rotate(0deg)' } }),
836
+ onClick: toggleOrientation,
837
+ },
838
+ ], trigger: "right", children: _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) => {
839
+ // Handle separator items
840
+ if (item.isSeparator) {
841
+ return (_jsx(S.DraggableItem, { "$isDragging": state.draggedItemIndex === index, "$isDragOver": dragOverIndex === index && state.draggedItemIndex !== index, draggable: enableConfigMode, 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: enableConfigMode ? (_jsx(ContextMenu, { items: getSeparatorRightClickMenuItems(index), trigger: "right", children: _jsx(S.ItemSeparator, { "$orientation": state.orientation, "$isConfigMode": false }) })) : (_jsx(S.ItemSeparator, { "$orientation": state.orientation, "$isConfigMode": false })) }, item.id));
842
+ }
843
+ // Get current state (disabled and onClick) from contextMenuItems
844
+ const currentState = getCurrentItemState(item.id);
845
+ // Prefer currentState.disabled if contextMenuItems has items, otherwise use item.disabled
846
+ const isDisabled = (contextMenuItems.length > 0 && currentState.disabled !== undefined)
847
+ ? currentState.disabled === true
848
+ : item.disabled === true;
849
+ const currentOnClick = currentState.onClick || item.onClick; // Fallback to stored onClick if not found
850
+ return (_jsx(S.DraggableItem, { "$isDragging": state.draggedItemIndex === index, "$isDragOver": dragOverIndex === index && state.draggedItemIndex !== index, draggable: enableConfigMode, 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: enableConfigMode ? (_jsx(ContextMenu, { items: getItemRightClickMenuItems(item, index), trigger: "right", children: item.staticItem ? (_jsx("div", { children: item.staticItem })) : (_jsx(TMTooltip, { content: item.name, position: "bottom", children: _jsx(S.MenuButton, { onClick: () => {
851
+ if (isDisabled)
852
+ return;
853
+ if (currentOnClick) {
854
+ currentOnClick();
855
+ }
856
+ }, disabled: isDisabled, "$isActive": item.isToggle, children: item.icon }) })) })) : (item.staticItem ? (_jsx("div", { children: item.staticItem })) : (_jsx(TMTooltip, { content: item.name, position: "bottom", children: _jsx(S.MenuButton, { onClick: () => {
857
+ if (isDisabled)
858
+ return;
859
+ if (currentOnClick) {
860
+ currentOnClick();
861
+ }
862
+ }, disabled: isDisabled, "$isActive": item.isToggle, children: item.icon }) }))) }, item.id));
863
+ }), enableConfigMode && hasContextMenu && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getContextMenuItemsWithPinIcons(), trigger: "left", keepOpenOnClick: false, children: _jsx(S.ContextMenuButton, { children: _jsx(IconMenuVertical, {}) }) }))] }));
820
864
  };
821
865
  export default TMFloatingMenuBar;