@topconsultnpm/sdkui-react 6.20.0-dev1.3 → 6.20.0-dev1.31

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 (65) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +29 -11
  2. package/lib/components/NewComponents/ContextMenu/hooks.d.ts +1 -0
  3. package/lib/components/NewComponents/ContextMenu/hooks.js +8 -4
  4. package/lib/components/NewComponents/ContextMenu/styles.d.ts +5 -1
  5. package/lib/components/NewComponents/ContextMenu/styles.js +56 -28
  6. package/lib/components/NewComponents/ContextMenu/types.d.ts +10 -0
  7. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +39 -51
  8. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +8 -0
  9. package/lib/components/NewComponents/FloatingMenuBar/styles.js +29 -19
  10. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +0 -1
  11. package/lib/components/base/TMAccordion.js +2 -2
  12. package/lib/components/base/TMCustomButton.js +61 -17
  13. package/lib/components/base/TMDataGrid.d.ts +5 -2
  14. package/lib/components/base/TMDataGrid.js +98 -7
  15. package/lib/components/editors/TMHtmlEditor.js +1 -1
  16. package/lib/components/editors/TMMetadataValues.js +20 -2
  17. package/lib/components/features/documents/TMDcmtBlog.d.ts +1 -7
  18. package/lib/components/features/documents/TMDcmtBlog.js +29 -2
  19. package/lib/components/features/documents/TMDcmtForm.js +268 -168
  20. package/lib/components/features/documents/TMDcmtPreview.js +37 -66
  21. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +8 -0
  22. package/lib/components/features/search/{TMSearchResultCheckoutInfoForm.js → TMDcmtCheckoutInfoForm.js} +6 -11
  23. package/lib/components/features/search/TMSearchQueryPanel.js +13 -12
  24. package/lib/components/features/search/TMSearchResult.js +66 -117
  25. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +3 -3
  26. package/lib/components/features/search/TMSearchResultsMenuItems.js +163 -180
  27. package/lib/components/features/search/TMSignatureInfoContent.d.ts +6 -0
  28. package/lib/components/features/search/TMSignatureInfoContent.js +140 -0
  29. package/lib/components/forms/Login/LoginValidatorService.d.ts +2 -0
  30. package/lib/components/forms/Login/LoginValidatorService.js +7 -2
  31. package/lib/components/forms/Login/TMLoginForm.js +34 -6
  32. package/lib/css/tm-sdkui.css +1 -1
  33. package/lib/helper/SDKUI_Globals.d.ts +12 -14
  34. package/lib/helper/SDKUI_Globals.js +8 -0
  35. package/lib/helper/SDKUI_Localizator.d.ts +8 -0
  36. package/lib/helper/SDKUI_Localizator.js +98 -0
  37. package/lib/helper/TMPdfViewer.d.ts +8 -0
  38. package/lib/helper/TMPdfViewer.js +187 -0
  39. package/lib/helper/TMUtils.d.ts +3 -1
  40. package/lib/helper/TMUtils.js +51 -0
  41. package/lib/helper/checkinCheckoutManager.d.ts +85 -0
  42. package/lib/helper/checkinCheckoutManager.js +348 -0
  43. package/lib/helper/devextremeCustomMessages.d.ts +30 -0
  44. package/lib/helper/devextremeCustomMessages.js +30 -0
  45. package/lib/helper/helpers.js +7 -1
  46. package/lib/helper/index.d.ts +2 -0
  47. package/lib/helper/index.js +2 -0
  48. package/lib/helper/queryHelper.js +29 -0
  49. package/lib/hooks/useCheckInOutOperations.d.ts +28 -0
  50. package/lib/hooks/useCheckInOutOperations.js +223 -0
  51. package/lib/services/platform_services.d.ts +1 -1
  52. package/package.json +5 -2
  53. package/lib/components/NewComponents/Notification/Notification.d.ts +0 -4
  54. package/lib/components/NewComponents/Notification/Notification.js +0 -60
  55. package/lib/components/NewComponents/Notification/NotificationContainer.d.ts +0 -8
  56. package/lib/components/NewComponents/Notification/NotificationContainer.js +0 -33
  57. package/lib/components/NewComponents/Notification/index.d.ts +0 -2
  58. package/lib/components/NewComponents/Notification/index.js +0 -2
  59. package/lib/components/NewComponents/Notification/styles.d.ts +0 -21
  60. package/lib/components/NewComponents/Notification/styles.js +0 -180
  61. package/lib/components/NewComponents/Notification/types.d.ts +0 -18
  62. package/lib/components/NewComponents/Notification/types.js +0 -1
  63. package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +0 -8
  64. package/lib/helper/cicoHelper.d.ts +0 -31
  65. package/lib/helper/cicoHelper.js +0 -155
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useState, useRef, useEffect } from 'react';
3
3
  import * as S from './styles';
4
4
  import { useIsMobile, useMenuPosition } from './hooks';
5
- const TMContextMenu = ({ items, trigger = 'right', children }) => {
5
+ import { IconArrowLeft } from '../../../helper';
6
+ const TMContextMenu = ({ items, trigger = 'right', children, externalControl }) => {
6
7
  const [menuState, setMenuState] = useState({
7
8
  visible: false,
8
9
  position: { x: 0, y: 0 },
@@ -14,16 +15,33 @@ const TMContextMenu = ({ items, trigger = 'right', children }) => {
14
15
  const menuRef = useRef(null);
15
16
  const triggerRef = useRef(null);
16
17
  const submenuTimeoutRef = useRef(null);
17
- const { openLeft, openUp } = useMenuPosition(menuRef, menuState.position);
18
+ const { openLeft, openUp, isCalculated } = useMenuPosition(menuRef, menuState.position);
18
19
  const handleClose = () => {
19
- setMenuState(prev => ({
20
- ...prev,
21
- visible: false,
22
- submenuStack: [items],
23
- parentNames: [],
24
- }));
20
+ if (externalControl) {
21
+ externalControl.onClose();
22
+ }
23
+ else {
24
+ setMenuState(prev => ({
25
+ ...prev,
26
+ visible: false,
27
+ submenuStack: [items],
28
+ parentNames: [],
29
+ }));
30
+ }
25
31
  setHoveredSubmenus([]);
26
32
  };
33
+ // Sync with external control when provided
34
+ useEffect(() => {
35
+ if (externalControl) {
36
+ setMenuState(prev => ({
37
+ ...prev,
38
+ visible: externalControl.visible,
39
+ position: externalControl.position,
40
+ submenuStack: [items],
41
+ parentNames: [],
42
+ }));
43
+ }
44
+ }, [externalControl, items]);
27
45
  useEffect(() => {
28
46
  if (!menuState.visible)
29
47
  return;
@@ -173,15 +191,15 @@ const TMContextMenu = ({ items, trigger = 'right', children }) => {
173
191
  // if (item.disabled) return;
174
192
  item.onRightIconClick?.();
175
193
  };
176
- return (_jsxs(S.MenuItem, { "$disabled": item.disabled, "$hasSubmenu": !!item.submenu && item.submenu.length > 0, "$beginGroup": item.beginGroup, onMouseDown: handleClick, onMouseEnter: (e) => !isMobile && handleMouseEnter(item, e, depth + 1), onMouseLeave: () => !isMobile && handleMouseLeave(depth + 1), children: [_jsxs(S.MenuItemContent, { children: [item.icon && _jsx(S.IconWrapper, { children: item.icon }), _jsx(S.MenuItemName, { children: item.name })] }), item.rightIcon && item.onRightIconClick && (_jsx(S.RightIconButton, { onClick: handleRightIconClick, onMouseDown: (e) => e.stopPropagation(), "aria-label": `Action for ${item.name}`, children: item.rightIcon })), item.submenu && item.submenu.length > 0 && (_jsx(S.SubmenuIndicator, { "$isMobile": isMobile, children: isMobile ? '›' : '▸' }))] }, itemKey));
194
+ return (_jsxs(S.MenuItem, { "$disabled": item.disabled, "$hasSubmenu": !!item.submenu && item.submenu.length > 0, "$beginGroup": item.beginGroup, onMouseDown: handleClick, onMouseEnter: (e) => !isMobile && handleMouseEnter(item, e, depth + 1), onMouseLeave: () => !isMobile && handleMouseLeave(depth + 1), title: item.tooltip, children: [_jsxs(S.MenuItemContent, { children: [item.icon && _jsx(S.IconWrapper, { children: item.icon }), _jsx(S.MenuItemName, { children: item.name })] }), item.rightIcon && item.onRightIconClick && (_jsx(S.RightIconButton, { onClick: handleRightIconClick, onMouseDown: (e) => e.stopPropagation(), "aria-label": `Action for ${item.name}`, children: item.rightIcon })), item.submenu && item.submenu.length > 0 && (_jsx(S.SubmenuIndicator, { "$isMobile": isMobile, children: isMobile ? '›' : '▸' }))] }, itemKey));
177
195
  });
178
196
  };
179
197
  const currentMenu = menuState.submenuStack.at(-1) || items;
180
198
  const currentParentName = menuState.parentNames.at(-1) || '';
181
- return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, onClick: handleClick, onKeyDown: (e) => {
199
+ return (_jsxs(_Fragment, { children: [!externalControl && children && (_jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, onClick: handleClick, onKeyDown: (e) => {
182
200
  if (e.key === 'Enter' || e.key === ' ') {
183
201
  handleClick(e);
184
202
  }
185
- }, role: "button", tabIndex: 0, style: { display: 'inline-block' }, children: children }), menuState.visible && (_jsxs(_Fragment, { children: [_jsx(S.Overlay, { onClick: handleClose }), _jsxs(S.MenuContainer, { ref: menuRef, "$x": menuState.position.x, "$y": menuState.position.y, "$openLeft": openLeft, "$openUp": openUp, children: [isMobile && menuState.parentNames.length > 0 && (_jsxs(S.MobileMenuHeader, { children: [_jsx(S.BackButton, { onClick: handleBack, "aria-label": "Go back", children: "\u2190" }), _jsx(S.HeaderTitle, { children: currentParentName })] })), renderMenuItems(currentMenu, 0)] }), !isMobile && hoveredSubmenus.map((submenu, idx) => (_jsx(S.Submenu, { "$parentRect": submenu.parentRect, "$openUp": submenu.openUp, "data-submenu": "true", onMouseEnter: handleSubmenuMouseEnter, onMouseLeave: () => handleMouseLeave(submenu.depth), children: renderMenuItems(submenu.items, submenu.depth) }, `submenu-${submenu.depth}-${idx}`)))] }))] }));
203
+ }, role: "button", tabIndex: 0, style: { display: 'inline-block' }, children: children })), menuState.visible && (_jsxs(_Fragment, { children: [_jsx(S.Overlay, { onClick: handleClose }), _jsxs(S.MenuContainer, { ref: menuRef, "$x": menuState.position.x, "$y": menuState.position.y, "$openLeft": openLeft, "$openUp": openUp, "$isPositioned": isCalculated, "$externalControl": !!externalControl, children: [isMobile && menuState.parentNames.length > 0 && (_jsxs(S.MobileMenuHeader, { children: [_jsx(S.BackButton, { onClick: handleBack, "aria-label": "Go back", children: _jsx(IconArrowLeft, {}) }), _jsx(S.HeaderTitle, { children: currentParentName })] })), renderMenuItems(currentMenu, 0)] }), !isMobile && hoveredSubmenus.map((submenu, idx) => (_jsx(S.Submenu, { "$parentRect": submenu.parentRect, "$openUp": submenu.openUp, "data-submenu": "true", onMouseEnter: handleSubmenuMouseEnter, onMouseLeave: () => handleMouseLeave(submenu.depth), children: renderMenuItems(submenu.items, submenu.depth) }, `submenu-${submenu.depth}-${idx}`)))] }))] }));
186
204
  };
187
205
  export default TMContextMenu;
@@ -5,6 +5,7 @@ interface Position {
5
5
  y: number;
6
6
  }
7
7
  export declare const useMenuPosition: (menuRef: React.RefObject<HTMLDivElement | null>, position: Position) => {
8
+ isCalculated: boolean;
8
9
  openLeft: boolean;
9
10
  openUp: boolean;
10
11
  };
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, useRef } from 'react';
1
+ import { useState, useEffect, useLayoutEffect, useRef } from 'react';
2
2
  export const useIsMobile = () => {
3
3
  const [isMobile, setIsMobile] = useState(false);
4
4
  useEffect(() => {
@@ -31,9 +31,12 @@ export const useClickOutside = (callback) => {
31
31
  };
32
32
  export const useMenuPosition = (menuRef, position) => {
33
33
  const [adjustedPosition, setAdjustedPosition] = useState({ openLeft: false, openUp: false });
34
- useEffect(() => {
35
- if (!menuRef.current)
34
+ const [isCalculated, setIsCalculated] = useState(false);
35
+ useLayoutEffect(() => {
36
+ if (!menuRef.current) {
37
+ setIsCalculated(false);
36
38
  return;
39
+ }
37
40
  const menuRect = menuRef.current.getBoundingClientRect();
38
41
  const viewportWidth = window.innerWidth;
39
42
  const viewportHeight = window.innerHeight;
@@ -43,6 +46,7 @@ export const useMenuPosition = (menuRef, position) => {
43
46
  openLeft: spaceRight < menuRect.width + 20,
44
47
  openUp: spaceBottom < menuRect.height + 20,
45
48
  });
49
+ setIsCalculated(true);
46
50
  }, [position, menuRef]);
47
- return adjustedPosition;
51
+ return { ...adjustedPosition, isCalculated };
48
52
  };
@@ -3,6 +3,8 @@ export declare const MenuContainer: import("styled-components/dist/types").IStyl
3
3
  $y: number;
4
4
  $openLeft: boolean;
5
5
  $openUp: boolean;
6
+ $isPositioned: boolean;
7
+ $externalControl?: boolean;
6
8
  }>> & string;
7
9
  export declare const MenuItem: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
8
10
  $disabled?: boolean;
@@ -12,7 +14,9 @@ export declare const MenuItem: import("styled-components/dist/types").IStyledCom
12
14
  export declare const MenuItemContent: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
13
15
  export declare const IconWrapper: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
14
16
  export declare const MenuItemName: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
15
- export declare const RightIconButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
17
+ export declare const RightIconButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
18
+ ref?: ((instance: HTMLButtonElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLButtonElement> | null | undefined;
19
+ }>, never>, never>> & string;
16
20
  export declare const SubmenuIndicator: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {
17
21
  $isMobile?: boolean;
18
22
  }>> & string;
@@ -36,6 +36,13 @@ export const MenuContainer = styled.div `
36
36
  animation: ${fadeIn} 0.15s ease-out;
37
37
  backdrop-filter: blur(10px);
38
38
  border: 1px solid rgba(0, 0, 0, 0.06);
39
+ opacity: ${props => props.$isPositioned ? 1 : 0};
40
+ transition: opacity 0.05s ease-in;
41
+
42
+ /* Reset color inheritance from parent with !important to override panel header styles */
43
+ & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
44
+ color: #1a1a1a !important;
45
+ }
39
46
 
40
47
  [data-theme='dark'] & {
41
48
  background: #2a2a2a;
@@ -43,6 +50,20 @@ export const MenuContainer = styled.div `
43
50
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4),
44
51
  0 2px 8px rgba(0, 0, 0, 0.3);
45
52
  }
53
+
54
+ [data-theme='dark'] & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
55
+ color: #e0e0e0 !important;
56
+ }
57
+
58
+ ${props => props.$externalControl && `
59
+ @media (max-width: 768px) {
60
+ left: 100px !important;
61
+ right: 100px !important;
62
+ max-width: calc(100vw - 200px);
63
+ width: auto;
64
+ min-width: auto;
65
+ }
66
+ `}
46
67
  `;
47
68
  export const MenuItem = styled.div `
48
69
  display: flex;
@@ -50,7 +71,6 @@ export const MenuItem = styled.div `
50
71
  justify-content: space-between;
51
72
  padding: 4px 12px;
52
73
  cursor: ${props => props.$disabled ? 'not-allowed' : 'pointer'};
53
- opacity: ${props => props.$disabled ? 0.4 : 1};
54
74
  transition: all 0.15s ease;
55
75
  position: relative;
56
76
  user-select: none;
@@ -63,12 +83,26 @@ export const MenuItem = styled.div `
63
83
  padding-top: 8px;
64
84
  `}
65
85
 
86
+ /* Apply opacity only to direct children except right-icon-btn */
87
+ & > *:not(.right-icon-btn) {
88
+ opacity: ${props => props.$disabled ? 0.4 : 1};
89
+ }
90
+
91
+ /* Right icon button hidden by default, shown on hover */
92
+ & .right-icon-btn {
93
+ cursor: pointer !important;
94
+ }
95
+
66
96
  &:hover {
67
97
  ${props => !props.$disabled && `
68
98
  background: linear-gradient(90deg, #f0f7ff 0%, #e6f2ff 100%);
69
99
  color: #0066cc;
70
- padding-left: 14px;
71
100
  `}
101
+
102
+ /* Show right icon on hover */
103
+ & .right-icon-btn {
104
+ opacity: 1 !important;
105
+ }
72
106
  }
73
107
 
74
108
  &:active {
@@ -99,8 +133,8 @@ export const MenuItem = styled.div `
99
133
  }
100
134
 
101
135
  @media (max-width: 768px) {
102
- padding: 14px 16px;
103
- font-size: 15px;
136
+ padding: 4px 10px;
137
+ font-size: 12px;
104
138
  }
105
139
  `;
106
140
  export const MenuItemContent = styled.div `
@@ -124,23 +158,23 @@ export const MenuItemName = styled.span `
124
158
  overflow-wrap: break-word;
125
159
  line-height: 1.4;
126
160
  `;
127
- export const RightIconButton = styled.button `
161
+ export const RightIconButton = styled.button.attrs({
162
+ className: 'right-icon-btn'
163
+ }) `
128
164
  display: flex;
129
165
  align-items: center;
130
166
  justify-content: center;
131
167
  background: transparent;
132
168
  border: none;
133
- cursor: pointer;
169
+ cursor: pointer !important;
134
170
  padding: 4px 8px;
135
171
  margin-left: 8px;
136
172
  border-radius: 6px;
137
- color: inherit;
138
173
  font-size: 14px;
139
- opacity: 0.6;
140
- transition: all 0.15s ease;
174
+ opacity: 0 !important;
175
+ transition: opacity 0.15s ease, background 0.15s ease, transform 0.15s ease;
141
176
 
142
177
  &:hover {
143
- opacity: 1;
144
178
  background: rgba(0, 0, 0, 0.05);
145
179
  transform: scale(1.1);
146
180
  }
@@ -223,17 +257,26 @@ export const Submenu = styled.div `
223
257
  background: transparent;
224
258
  }
225
259
 
260
+ /* Reset color inheritance from parent with !important to override panel header styles */
261
+ & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
262
+ color: #1a1a1a !important;
263
+ }
264
+
226
265
  [data-theme='dark'] & {
227
266
  background: #2a2a2a;
228
267
  border-color: rgba(255, 255, 255, 0.1);
229
268
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4),
230
269
  0 2px 8px rgba(0, 0, 0, 0.3);
231
270
  }
271
+
272
+ [data-theme='dark'] & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
273
+ color: #e0e0e0 !important;
274
+ }
232
275
  `;
233
276
  export const MobileMenuHeader = styled.div `
234
277
  display: flex;
235
278
  align-items: center;
236
- padding: 12px 16px;
279
+ padding: 4px 8px;
237
280
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
238
281
  margin-bottom: 8px;
239
282
  gap: 12px;
@@ -249,33 +292,18 @@ export const BackButton = styled.button `
249
292
  display: flex;
250
293
  align-items: center;
251
294
  justify-content: center;
252
- background: #0066cc;
253
- color: white;
254
295
  border: none;
255
296
  border-radius: 8px;
256
297
  width: 32px;
257
298
  height: 32px;
258
299
  cursor: pointer;
259
- font-size: 18px;
260
300
  transition: all 0.15s ease;
261
-
262
- &:hover {
263
- background: #0052a3;
264
- transform: scale(1.05);
265
- }
301
+ font-size: 16px;
302
+ transform: translateY(-2px);
266
303
 
267
304
  &:active {
268
305
  transform: scale(0.95);
269
306
  }
270
-
271
- [data-theme='dark'] & {
272
- background: #4db8ff;
273
- color: #1a1a1a;
274
-
275
- &:hover {
276
- background: #66c2ff;
277
- }
278
- }
279
307
  `;
280
308
  export const HeaderTitle = styled.h3 `
281
309
  margin: 0;
@@ -8,11 +8,21 @@ export interface TMContextMenuItemProps {
8
8
  rightIcon?: React.ReactNode;
9
9
  onRightIconClick?: () => void;
10
10
  beginGroup?: boolean;
11
+ tooltip?: string;
12
+ operationType?: 'singleRow' | 'multiRow';
11
13
  }
12
14
  export interface TMContextMenuProps {
13
15
  items: TMContextMenuItemProps[];
14
16
  trigger?: 'right' | 'left';
15
17
  children?: React.ReactNode;
18
+ externalControl?: {
19
+ visible: boolean;
20
+ position: {
21
+ x: number;
22
+ y: number;
23
+ };
24
+ onClose: () => void;
25
+ };
16
26
  }
17
27
  export interface Position {
18
28
  x: number;
@@ -1,36 +1,37 @@
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 { IconApply, IconMenuKebab, IconMenuVertical, IconPencil, IconPin, SDKUI_Globals } from '../../../helper';
8
8
  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, }) => {
9
+ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained = false, defaultPosition = { x: 100, y: 100 }, maxItems = 8, }) => {
10
10
  const loadConfig = () => {
11
11
  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 || [],
19
- };
20
- }
12
+ const settings = SDKUI_Globals.userSettings.searchSettings.floatingMenuBar;
13
+ // Check if position was actually saved (not just the default class value)
14
+ const hasSavedPosition = settings.position &&
15
+ (settings.position.x !== 100 || settings.position.y !== 100 ||
16
+ (settings.itemIds && settings.itemIds.length > 0));
17
+ return {
18
+ orientation: settings.orientation || 'horizontal',
19
+ savedItemIds: settings.itemIds || [],
20
+ position: hasSavedPosition ? settings.position : defaultPosition,
21
+ };
21
22
  }
22
23
  catch (error) {
23
24
  console.error('Failed to load FloatingMenuBar config:', error);
25
+ return {
26
+ orientation: 'horizontal',
27
+ savedItemIds: [],
28
+ position: defaultPosition,
29
+ };
24
30
  }
25
- return {
26
- orientation: 'horizontal',
27
- pinnedItemIds: new Set(),
28
- savedItemIds: [],
29
- };
30
31
  };
31
32
  const initialConfig = loadConfig();
32
33
  const [state, setState] = useState({
33
- position: defaultPosition,
34
+ position: initialConfig.position,
34
35
  isDragging: false,
35
36
  isConfigMode: false,
36
37
  orientation: initialConfig.orientation,
@@ -39,9 +40,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
39
40
  });
40
41
  const floatingRef = useRef(null);
41
42
  const dragOffset = useRef({ x: 0, y: 0 });
42
- const [pinnedItemIds, setPinnedItemIds] = useState(initialConfig.pinnedItemIds);
43
43
  const [dragOverIndex, setDragOverIndex] = useState(null);
44
- const [showMaxItemsNotification, setShowMaxItemsNotification] = useState(false);
45
44
  // Use refs to track item IDs without causing re-renders
46
45
  const floatingBarItemIds = useRef(new Set());
47
46
  const floatingBarItemNames = useRef(new Set());
@@ -57,13 +56,15 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
57
56
  const itemId = `${parentPath}${item.name}-${index}`;
58
57
  // Only add items that have onClick (final actions, not submenu parents)
59
58
  if (item.onClick && !item.submenu) {
59
+ // Check if item is currently in the floating bar
60
+ const isPinned = state.items.some(i => i.id === itemId || i.name === item.name);
60
61
  result.push({
61
62
  id: itemId,
62
63
  name: item.name,
63
- icon: item.icon || _jsx(IconStar, {}),
64
+ icon: item.icon || _jsx(IconPin, {}),
64
65
  onClick: item.onClick,
65
66
  disabled: item.disabled,
66
- isPinned: pinnedItemIds.has(itemId),
67
+ isPinned: isPinned,
67
68
  originalMenuItem: item,
68
69
  });
69
70
  }
@@ -73,7 +74,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
73
74
  }
74
75
  });
75
76
  return result;
76
- }, [pinnedItemIds]);
77
+ }, [state.items]);
77
78
  // Restore items on mount from savedItemIds
78
79
  useEffect(() => {
79
80
  if (contextMenuItems.length > 0) {
@@ -98,24 +99,17 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
98
99
  else {
99
100
  // Add to floating bar
100
101
  if (s.items.length >= maxItems) {
101
- setShowMaxItemsNotification(true);
102
- setTimeout(() => setShowMaxItemsNotification(false), 3000);
102
+ ShowAlert({
103
+ mode: 'warning',
104
+ title: 'Limite Massimo Raggiunto',
105
+ message: `Hai raggiunto il massimo di ${maxItems} elementi. Rimuovine uno prima di aggiungerne altri.`,
106
+ duration: 4000,
107
+ });
103
108
  return s;
104
109
  }
105
110
  return { ...s, items: [...s.items, item] };
106
111
  }
107
112
  });
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
113
  }, [maxItems]);
120
114
  // Get current item state (disabled and onClick) from contextMenuItems
121
115
  const getCurrentItemState = useCallback((itemName) => {
@@ -150,7 +144,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
150
144
  const isInFloatingBar = currentItemIds.has(itemId) || currentItemNames.has(item.name);
151
145
  const enhanced = {
152
146
  ...item,
153
- rightIcon: item.onClick && !item.submenu ? (isInFloatingBar ? _jsx(IconStar, { color: "#FFD700" }) : _jsx(IconStar, {})) : undefined,
147
+ rightIcon: item.onClick && !item.submenu ? (isInFloatingBar ? _jsx(IconPin, { color: "#e12a2a" }) : _jsx(IconPin, {})) : undefined,
154
148
  onRightIconClick: item.onClick && !item.submenu ? () => {
155
149
  if (flatItem) {
156
150
  togglePin(flatItem);
@@ -229,20 +223,20 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
229
223
  }
230
224
  return undefined;
231
225
  }, [state.isDragging, handleMouseMove, handleMouseUp]);
232
- // Save to localStorage whenever config changes (excluding position)
226
+ // Save to SDKUI_Globals.userSettings whenever config changes (including position)
233
227
  useEffect(() => {
234
228
  try {
235
- const config = {
229
+ // Replace the entire object to trigger the Proxy
230
+ SDKUI_Globals.userSettings.searchSettings.floatingMenuBar = {
236
231
  orientation: state.orientation,
237
- pinnedItemIds: Array.from(pinnedItemIds),
238
- itemIds: state.items.map(item => item.id), // Save only IDs, not functions
232
+ itemIds: state.items.map(item => item.id),
233
+ position: state.position,
239
234
  };
240
- localStorage.setItem(storageKey, JSON.stringify(config));
241
235
  }
242
236
  catch (error) {
243
237
  console.error('Failed to save FloatingMenuBar config:', error);
244
238
  }
245
- }, [state.orientation, state.items, pinnedItemIds, storageKey]);
239
+ }, [state.orientation, state.items, state.position]);
246
240
  const toggleConfigMode = () => {
247
241
  setState(s => ({ ...s, isConfigMode: !s.isConfigMode }));
248
242
  };
@@ -286,12 +280,6 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
286
280
  ...s,
287
281
  items: s.items.filter(item => item.id !== itemId),
288
282
  }));
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
283
  };
296
284
  // Drag and drop for reordering
297
285
  const handleDragStart = (e, index) => {
@@ -347,7 +335,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
347
335
  setState(s => ({ ...s, draggedItemIndex: null }));
348
336
  setDragOverIndex(null);
349
337
  };
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) => {
338
+ 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.Separator, { "$orientation": state.orientation }), state.items.map((item, index) => {
351
339
  // Get current state (disabled and onClick) from contextMenuItems
352
340
  const currentState = getCurrentItemState(item.name);
353
341
  const isDisabled = currentState.disabled || false;
@@ -365,6 +353,6 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
365
353
  currentOnClick();
366
354
  }
367
355
  }, 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) }) }))] }));
356
+ }), !state.isConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: enhancedContextMenuItems(), trigger: "left", children: _jsx(S.ContextMenuButton, { children: _jsx(IconMenuVertical, {}) }) }, state.items.map(i => i.id).join(','))), _jsx(S.ConfigButton, { onClick: toggleConfigMode, "$isActive": state.isConfigMode, children: state.isConfigMode ? _jsx(IconApply, {}) : _jsx(IconPencil, {}) }), !state.isConfigMode && (_jsx(S.OrientationToggle, { "$orientation": state.orientation, onClick: toggleOrientation, children: _jsx(IconMenuKebab, {}) }))] })] }));
369
357
  };
370
358
  export default TMFloatingMenuBar;
@@ -21,12 +21,20 @@ export declare const FloatingContainer: import("styled-components/dist/types").I
21
21
  export declare const GripHandle: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
22
22
  $orientation: "horizontal" | "vertical";
23
23
  }>> & string;
24
+ export declare const Separator: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
25
+ $orientation: "horizontal" | "vertical";
26
+ }>> & string;
24
27
  export declare const MenuButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
25
28
  $isActive?: boolean;
26
29
  }>> & string;
27
30
  export declare const ConfigButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
28
31
  $isActive?: boolean;
29
32
  }>> & string;
33
+ export declare const ContextMenuButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
34
+ $isActive?: boolean;
35
+ }, "ref"> & {
36
+ ref?: ((instance: HTMLButtonElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLButtonElement> | null | undefined;
37
+ }, never>> & string;
30
38
  export declare const RemoveButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
31
39
  export declare const OrientationToggle: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
32
40
  $orientation: "horizontal" | "vertical";