@topconsultnpm/sdkui-react 6.20.0-dev1.13 → 6.20.0-dev1.131

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 (202) 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 +322 -30
  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 +146 -47
  10. package/lib/components/NewComponents/ContextMenu/types.d.ts +22 -3
  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 +620 -125
  14. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +25 -5
  15. package/lib/components/NewComponents/FloatingMenuBar/styles.js +215 -59
  16. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +12 -3
  17. package/lib/components/base/TMAccordionNew.js +35 -14
  18. package/lib/components/base/TMButton.js +6 -0
  19. package/lib/components/base/TMClosableList.js +4 -0
  20. package/lib/components/base/TMCustomButton.js +61 -17
  21. package/lib/components/base/TMDataGrid.d.ts +7 -4
  22. package/lib/components/base/TMDataGrid.js +153 -11
  23. package/lib/components/base/TMDropDownMenu.js +21 -18
  24. package/lib/components/base/TMFileManager.d.ts +4 -3
  25. package/lib/components/base/TMFileManager.js +32 -24
  26. package/lib/components/base/TMFileManagerDataGridView.d.ts +3 -2
  27. package/lib/components/base/TMFileManagerDataGridView.js +1 -11
  28. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +7 -1
  29. package/lib/components/base/TMFileManagerThumbnailItems.js +5 -2
  30. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +17 -4
  31. package/lib/components/base/TMFileManagerThumbnailsView.js +18 -6
  32. package/lib/components/base/TMFileManagerUtils.d.ts +0 -12
  33. package/lib/components/base/TMListView.js +33 -15
  34. package/lib/components/base/TMPanel.d.ts +1 -1
  35. package/lib/components/base/TMPanel.js +4 -2
  36. package/lib/components/base/TMPopUp.js +6 -0
  37. package/lib/components/base/TMToolbarCard.js +2 -0
  38. package/lib/components/base/TMTreeView.d.ts +2 -1
  39. package/lib/components/base/TMTreeView.js +33 -26
  40. package/lib/components/choosers/TMDataListItemChooser.d.ts +2 -0
  41. package/lib/components/choosers/TMDataListItemChooser.js +8 -2
  42. package/lib/components/choosers/TMDcmtTypeChooser.d.ts +1 -0
  43. package/lib/components/choosers/TMDcmtTypeChooser.js +11 -3
  44. package/lib/components/choosers/TMDistinctValues.js +2 -2
  45. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +2 -0
  46. package/lib/components/choosers/TMDynDataListItemChooser.js +8 -2
  47. package/lib/components/choosers/TMInvoiceRetrieveFormats.js +1 -1
  48. package/lib/components/choosers/TMMetadataChooser.d.ts +2 -0
  49. package/lib/components/choosers/TMMetadataChooser.js +19 -4
  50. package/lib/components/choosers/TMOrderRetrieveFormats.js +1 -1
  51. package/lib/components/choosers/TMUserChooser.d.ts +2 -5
  52. package/lib/components/choosers/TMUserChooser.js +33 -47
  53. package/lib/components/editors/TMCheckBox.js +2 -0
  54. package/lib/components/editors/TMDateBox.js +18 -9
  55. package/lib/components/editors/TMEditorStyled.js +7 -0
  56. package/lib/components/editors/TMLocalizedTextBox.d.ts +3 -1
  57. package/lib/components/editors/TMLocalizedTextBox.js +16 -14
  58. package/lib/components/editors/TMMetadataEditor.d.ts +1 -0
  59. package/lib/components/editors/TMMetadataEditor.js +4 -4
  60. package/lib/components/editors/TMMetadataTextBox.d.ts +9 -0
  61. package/lib/components/editors/TMMetadataTextBox.js +92 -0
  62. package/lib/components/editors/TMMetadataValues.d.ts +2 -0
  63. package/lib/components/editors/TMMetadataValues.js +26 -8
  64. package/lib/components/editors/TMRadioButton.js +2 -0
  65. package/lib/components/editors/TMTextArea.js +18 -30
  66. package/lib/components/editors/TMTextBox.d.ts +1 -1
  67. package/lib/components/editors/TMTextBox.js +29 -4
  68. package/lib/components/editors/TMTextExpression.js +6 -91
  69. package/lib/components/features/archive/TMArchive.js +2 -2
  70. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +15 -0
  71. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +462 -0
  72. package/lib/components/features/assistant/TMToppySpeechBubble.d.ts +11 -0
  73. package/lib/components/features/assistant/TMToppySpeechBubble.js +126 -0
  74. package/lib/components/features/documents/TMDcmtBlog.js +1 -1
  75. package/lib/components/features/documents/TMDcmtForm.d.ts +14 -2
  76. package/lib/components/features/documents/TMDcmtForm.js +576 -292
  77. package/lib/components/features/documents/TMDcmtPreview.js +42 -155
  78. package/lib/components/features/documents/TMDcmtTasks.js +9 -9
  79. package/lib/components/features/documents/TMMasterDetailDcmts.js +38 -53
  80. package/lib/components/features/documents/TMRelationViewer.d.ts +1 -1
  81. package/lib/components/features/documents/TMRelationViewer.js +2 -2
  82. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +8 -0
  83. package/lib/components/features/search/{TMSearchResultCheckoutInfoForm.js → TMDcmtCheckoutInfoForm.js} +2 -2
  84. package/lib/components/features/search/TMSavedQuerySelector.js +72 -67
  85. package/lib/components/features/search/TMSearch.d.ts +3 -0
  86. package/lib/components/features/search/TMSearch.js +50 -11
  87. package/lib/components/features/search/TMSearchQueryEditor.d.ts +1 -0
  88. package/lib/components/features/search/TMSearchQueryEditor.js +10 -10
  89. package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -0
  90. package/lib/components/features/search/TMSearchQueryPanel.js +40 -25
  91. package/lib/components/features/search/TMSearchResult.d.ts +3 -0
  92. package/lib/components/features/search/TMSearchResult.js +370 -252
  93. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +3 -3
  94. package/lib/components/features/search/TMSearchResultsMenuItems.js +227 -171
  95. package/lib/components/features/search/TMSignSettingsForm.js +1 -1
  96. package/lib/components/features/search/TMSignatureInfoContent.d.ts +6 -0
  97. package/lib/components/features/search/TMSignatureInfoContent.js +140 -0
  98. package/lib/components/features/search/TMViewHistoryDcmt.js +47 -52
  99. package/lib/components/features/tasks/TMTaskForm.js +75 -25
  100. package/lib/components/features/tasks/TMTasksAgenda.d.ts +3 -1
  101. package/lib/components/features/tasks/TMTasksAgenda.js +48 -9
  102. package/lib/components/features/tasks/TMTasksCalendar.d.ts +2 -0
  103. package/lib/components/features/tasks/TMTasksCalendar.js +19 -7
  104. package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
  105. package/lib/components/features/tasks/TMTasksUtils.js +57 -37
  106. package/lib/components/features/tasks/TMTasksView.js +28 -19
  107. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +33 -2
  108. package/lib/components/features/workflow/TMWorkflowPopup.js +140 -34
  109. package/lib/components/features/workflow/diagram/DiagramItemComponent.d.ts +2 -0
  110. package/lib/components/features/workflow/diagram/DiagramItemComponent.js +14 -7
  111. package/lib/components/features/workflow/diagram/DiagramItemForm.js +1 -1
  112. package/lib/components/features/workflow/diagram/RecipientList.js +3 -2
  113. package/lib/components/features/workflow/diagram/WFDiagram.d.ts +4 -0
  114. package/lib/components/features/workflow/diagram/WFDiagram.js +164 -13
  115. package/lib/components/forms/Login/LoginValidatorService.d.ts +2 -0
  116. package/lib/components/forms/Login/LoginValidatorService.js +7 -2
  117. package/lib/components/forms/Login/TMLoginForm.js +35 -7
  118. package/lib/components/forms/TMChooserForm.js +1 -1
  119. package/lib/components/grids/TMBlogsPost.js +56 -31
  120. package/lib/components/grids/TMRecentsManager.js +20 -10
  121. package/lib/components/grids/TMValidationItemsList.js +6 -0
  122. package/lib/components/index.d.ts +6 -3
  123. package/lib/components/index.js +6 -3
  124. package/lib/components/layout/panelManager/TMPanelManagerContext.js +13 -5
  125. package/lib/components/query/TMQueryEditor.d.ts +6 -1
  126. package/lib/components/query/TMQueryEditor.js +105 -101
  127. package/lib/components/settings/SettingsAppearance.d.ts +2 -1
  128. package/lib/components/settings/SettingsAppearance.js +99 -30
  129. package/lib/components/sidebar/TMHeader.js +11 -7
  130. package/lib/components/sidebar/TMSidebar.d.ts +0 -1
  131. package/lib/components/sidebar/TMSidebar.js +16 -44
  132. package/lib/components/sidebar/TMSidebarItem.js +36 -17
  133. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -1
  134. package/lib/components/viewers/TMDataListItemViewer.js +35 -71
  135. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +8 -0
  136. package/lib/components/viewers/TMDataUserIdItemViewer.js +39 -0
  137. package/lib/css/tm-sdkui.css +1 -1
  138. package/lib/helper/SDKUI_Globals.d.ts +22 -0
  139. package/lib/helper/SDKUI_Globals.js +10 -1
  140. package/lib/helper/SDKUI_Localizator.d.ts +21 -3
  141. package/lib/helper/SDKUI_Localizator.js +196 -10
  142. package/lib/helper/TMCommandsContextMenu.d.ts +4 -2
  143. package/lib/helper/TMCommandsContextMenu.js +15 -4
  144. package/lib/helper/TMIcons.d.ts +4 -0
  145. package/lib/helper/TMIcons.js +13 -3
  146. package/lib/helper/TMPdfViewer.d.ts +8 -0
  147. package/lib/helper/TMPdfViewer.js +373 -0
  148. package/lib/helper/TMToppyMessage.js +4 -0
  149. package/lib/helper/checkinCheckoutManager.d.ts +31 -1
  150. package/lib/helper/checkinCheckoutManager.js +112 -30
  151. package/lib/helper/devextremeCustomMessages.d.ts +30 -0
  152. package/lib/helper/devextremeCustomMessages.js +30 -0
  153. package/lib/helper/helpers.d.ts +30 -2
  154. package/lib/helper/helpers.js +132 -4
  155. package/lib/helper/index.d.ts +2 -0
  156. package/lib/helper/index.js +2 -0
  157. package/lib/helper/queryHelper.d.ts +2 -2
  158. package/lib/helper/queryHelper.js +80 -24
  159. package/lib/helper/workItemsHelper.d.ts +6 -0
  160. package/lib/helper/workItemsHelper.js +230 -0
  161. package/lib/hooks/useCheckInOutOperations.d.ts +28 -0
  162. package/lib/hooks/useCheckInOutOperations.js +223 -0
  163. package/lib/hooks/useDataListItem.d.ts +12 -0
  164. package/lib/hooks/useDataListItem.js +132 -0
  165. package/lib/hooks/useDataUserIdItem.d.ts +10 -0
  166. package/lib/hooks/useDataUserIdItem.js +96 -0
  167. package/lib/hooks/useFloatingBarPinnedItems.d.ts +11 -0
  168. package/lib/hooks/useFloatingBarPinnedItems.js +54 -0
  169. package/lib/hooks/useMetadataExpression.d.ts +19 -0
  170. package/lib/hooks/useMetadataExpression.js +99 -0
  171. package/lib/hooks/useSettingsFeedback.d.ts +11 -0
  172. package/lib/hooks/useSettingsFeedback.js +38 -0
  173. package/lib/hooks/useWorkflowApprove.d.ts +4 -0
  174. package/lib/hooks/useWorkflowApprove.js +14 -1
  175. package/lib/index.d.ts +1 -0
  176. package/lib/index.js +3 -2
  177. package/lib/services/platform_services.d.ts +3 -3
  178. package/lib/ts/types.d.ts +61 -1
  179. package/lib/utils/theme.d.ts +1 -1
  180. package/lib/utils/theme.js +1 -1
  181. package/package.json +8 -6
  182. package/lib/components/NewComponents/Notification/Notification.d.ts +0 -4
  183. package/lib/components/NewComponents/Notification/Notification.js +0 -60
  184. package/lib/components/NewComponents/Notification/NotificationContainer.d.ts +0 -8
  185. package/lib/components/NewComponents/Notification/NotificationContainer.js +0 -33
  186. package/lib/components/NewComponents/Notification/index.d.ts +0 -2
  187. package/lib/components/NewComponents/Notification/index.js +0 -2
  188. package/lib/components/NewComponents/Notification/styles.d.ts +0 -21
  189. package/lib/components/NewComponents/Notification/styles.js +0 -180
  190. package/lib/components/NewComponents/Notification/types.d.ts +0 -18
  191. package/lib/components/NewComponents/Notification/types.js +0 -1
  192. package/lib/components/base/TMContextMenu.d.ts +0 -25
  193. package/lib/components/base/TMContextMenu.js +0 -109
  194. package/lib/components/base/TMContextMenuOLD.d.ts +0 -26
  195. package/lib/components/base/TMContextMenuOLD.js +0 -56
  196. package/lib/components/base/TMFloatingToolbar.d.ts +0 -9
  197. package/lib/components/base/TMFloatingToolbar.js +0 -101
  198. package/lib/components/features/assistant/ToppyDraggableHelpCenter.d.ts +0 -30
  199. package/lib/components/features/assistant/ToppyDraggableHelpCenter.js +0 -482
  200. package/lib/components/features/assistant/ToppySpeechBubble.d.ts +0 -9
  201. package/lib/components/features/assistant/ToppySpeechBubble.js +0 -117
  202. package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +0 -8
@@ -1,4 +1,13 @@
1
- import { useState, useEffect, useRef } from 'react';
1
+ import { useState, useEffect, useLayoutEffect, useRef } from 'react';
2
+ export const useIsIOS = () => {
3
+ const [isIOS, setIsIOS] = useState(false);
4
+ useEffect(() => {
5
+ const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
6
+ (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
7
+ setIsIOS(iOS);
8
+ }, []);
9
+ return isIOS;
10
+ };
2
11
  export const useIsMobile = () => {
3
12
  const [isMobile, setIsMobile] = useState(false);
4
13
  useEffect(() => {
@@ -29,20 +38,83 @@ export const useClickOutside = (callback) => {
29
38
  }, [callback]);
30
39
  return ref;
31
40
  };
32
- export const useMenuPosition = (menuRef, position) => {
33
- const [adjustedPosition, setAdjustedPosition] = useState({ openLeft: false, openUp: false });
34
- useEffect(() => {
35
- if (!menuRef.current)
41
+ export const useMenuPosition = (menuRef, position, itemsCount) => {
42
+ const [adjustedPosition, setAdjustedPosition] = useState({ openLeft: false, openUp: false, needsScroll: false, maxHeight: undefined });
43
+ const [isCalculated, setIsCalculated] = useState(false);
44
+ useLayoutEffect(() => {
45
+ if (!menuRef.current) {
46
+ setIsCalculated(false);
36
47
  return;
48
+ }
37
49
  const menuRect = menuRef.current.getBoundingClientRect();
38
50
  const viewportWidth = window.innerWidth;
39
51
  const viewportHeight = window.innerHeight;
52
+ const isMobile = viewportWidth <= 768;
40
53
  const spaceRight = viewportWidth - position.x;
41
54
  const spaceBottom = viewportHeight - position.y;
55
+ const spaceAbove = position.y;
56
+ const padding = 8; // Minimal padding from viewport edges - be more aggressive about using available space
57
+ // Use scrollHeight to get natural content height, not constrained height
58
+ const menuHeight = menuRef.current.scrollHeight;
59
+ // Mobile: Always calculate max-height based on position to prevent overflow
60
+ if (isMobile) {
61
+ const maxHeightFromBottom = spaceBottom - padding;
62
+ const maxHeightFromTop = spaceAbove - padding;
63
+ const mobileMaxHeight = Math.max(maxHeightFromBottom, maxHeightFromTop);
64
+ setAdjustedPosition({
65
+ openLeft: spaceRight < menuRect.width + 20,
66
+ openUp: maxHeightFromTop > maxHeightFromBottom && menuHeight > maxHeightFromBottom,
67
+ needsScroll: menuHeight > mobileMaxHeight,
68
+ maxHeight: mobileMaxHeight,
69
+ });
70
+ setIsCalculated(true);
71
+ return;
72
+ }
73
+ // Desktop: Check if menu is too tall to fit in either direction
74
+ const fitsBelow = menuHeight + padding <= spaceBottom;
75
+ const fitsAbove = menuHeight + padding <= spaceAbove;
76
+ const needsScroll = !fitsBelow && !fitsAbove;
77
+ // Calculate max height when scrolling is needed
78
+ let maxHeight = undefined;
79
+ let shouldOpenUp = false;
80
+ if (needsScroll) {
81
+ // When scrolling is needed, open in the direction with MORE space
82
+ const availableSpace = Math.max(spaceBottom, spaceAbove);
83
+ maxHeight = availableSpace - padding;
84
+ shouldOpenUp = spaceAbove > spaceBottom; // Open upward if more space above
85
+ }
86
+ else {
87
+ // Normal behavior: open up only if it fits above but not below
88
+ shouldOpenUp = !fitsBelow && fitsAbove;
89
+ }
42
90
  setAdjustedPosition({
43
91
  openLeft: spaceRight < menuRect.width + 20,
44
- openUp: spaceBottom < menuRect.height + 20,
92
+ openUp: shouldOpenUp,
93
+ needsScroll,
94
+ maxHeight,
45
95
  });
46
- }, [position, menuRef]);
47
- return adjustedPosition;
96
+ setIsCalculated(true);
97
+ }, [position, menuRef, itemsCount]); // Added itemsCount to recalculate when menu content changes
98
+ return { ...adjustedPosition, isCalculated };
99
+ };
100
+ export const getContextMenuTarget = (event, focusedItem, selectedItem, dataSource, idPrefix, isMobile) => {
101
+ if (!event)
102
+ return undefined;
103
+ let targetItem = focusedItem ?? selectedItem;
104
+ if (!focusedItem && isMobile) {
105
+ // Find the actual item that was long-pressed by traversing up from the event target
106
+ let element = event.target;
107
+ while (element && element !== event.currentTarget) {
108
+ if (element.id && element.id.startsWith(`${idPrefix}-`)) {
109
+ const itemId = element.id.replace(`${idPrefix}-`, '');
110
+ const foundItem = dataSource.find(item => item.id === itemId);
111
+ if (foundItem) {
112
+ targetItem = foundItem;
113
+ break;
114
+ }
115
+ }
116
+ element = element.parentElement;
117
+ }
118
+ }
119
+ return targetItem;
48
120
  };
@@ -1,2 +1,5 @@
1
1
  export { default as ContextMenu } from './TMContextMenu';
2
2
  export type { TMContextMenuItemProps, TMContextMenuProps } from './types';
3
+ export { useLongPress, triggerContextMenuEvent } from './useLongPress';
4
+ export type { UseLongPressOptions } from './useLongPress';
5
+ export { useIsIOS } from './hooks';
@@ -1 +1,3 @@
1
1
  export { default as ContextMenu } from './TMContextMenu';
2
+ export { useLongPress, triggerContextMenuEvent } from './useLongPress';
3
+ export { useIsIOS } from './hooks';
@@ -3,6 +3,10 @@ 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;
8
+ $needsScroll?: boolean;
9
+ $maxHeight?: number;
6
10
  }>> & string;
7
11
  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
12
  $disabled?: boolean;
@@ -12,13 +16,17 @@ export declare const MenuItem: import("styled-components/dist/types").IStyledCom
12
16
  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
17
  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
18
  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;
19
+ 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"> & {
20
+ 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;
21
+ }>, never>, never>> & string;
16
22
  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
23
  $isMobile?: boolean;
18
24
  }>> & string;
19
25
  export declare const Submenu: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
20
26
  $parentRect: DOMRect;
21
27
  $openUp?: boolean;
28
+ $needsScroll?: boolean;
29
+ $maxHeight?: number;
22
30
  }>> & string;
23
31
  export declare const MobileMenuHeader: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
24
32
  export declare const BackButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
@@ -25,7 +25,7 @@ export const MenuContainer = styled.div `
25
25
  right: ${props => props.$openLeft ? `${window.innerWidth - props.$x}px` : 'auto'};
26
26
  top: ${props => props.$openUp ? 'auto' : `${props.$y}px`};
27
27
  bottom: ${props => props.$openUp ? `${window.innerHeight - props.$y}px` : 'auto'};
28
- z-index: 10000;
28
+ z-index: 10100;
29
29
  background: #ffffff;
30
30
  border-radius: 12px;
31
31
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12),
@@ -36,6 +36,42 @@ 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
+ /* Add scrolling when menu is too tall to fit in either direction */
43
+ ${props => props.$needsScroll && props.$maxHeight && `
44
+ max-height: ${props.$maxHeight}px;
45
+ overflow-y: auto;
46
+ overflow-x: hidden;
47
+
48
+ /* Smooth scrolling */
49
+ scroll-behavior: smooth;
50
+
51
+ /* Custom scrollbar styling */
52
+ &::-webkit-scrollbar {
53
+ width: 8px;
54
+ }
55
+
56
+ &::-webkit-scrollbar-track {
57
+ background: rgba(0, 0, 0, 0.05);
58
+ border-radius: 4px;
59
+ }
60
+
61
+ &::-webkit-scrollbar-thumb {
62
+ background: rgba(0, 0, 0, 0.2);
63
+ border-radius: 4px;
64
+ }
65
+
66
+ &::-webkit-scrollbar-thumb:hover {
67
+ background: rgba(0, 0, 0, 0.3);
68
+ }
69
+ `}
70
+
71
+ /* Reset color inheritance from parent with !important to override panel header styles */
72
+ & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
73
+ color: #1a1a1a !important;
74
+ }
39
75
 
40
76
  [data-theme='dark'] & {
41
77
  background: #2a2a2a;
@@ -43,18 +79,33 @@ export const MenuContainer = styled.div `
43
79
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4),
44
80
  0 2px 8px rgba(0, 0, 0, 0.3);
45
81
  }
82
+
83
+ [data-theme='dark'] & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
84
+ color: #e0e0e0 !important;
85
+ }
86
+
87
+ ${props => props.$externalControl && `
88
+ @media (max-width: 768px) {
89
+ left: 75px !important;
90
+ right: 75px !important;
91
+ max-width: calc(100vw - 150px);
92
+ width: auto;
93
+ min-width: auto;
94
+ }
95
+ `}
46
96
  `;
47
97
  export const MenuItem = styled.div `
48
98
  display: flex;
49
99
  align-items: center;
50
100
  justify-content: space-between;
51
101
  padding: 4px 12px;
52
- cursor: ${props => props.$disabled ? 'not-allowed' : 'pointer'};
53
- opacity: ${props => props.$disabled ? 0.4 : 1};
102
+ cursor: ${props => props.$disabled ? 'default' : 'pointer'};
54
103
  transition: all 0.15s ease;
55
104
  position: relative;
56
105
  user-select: none;
57
- font-size: 13px;
106
+ -webkit-touch-callout: none;
107
+ -webkit-user-select: none;
108
+ font-size: var(--base-font-size, 13px);
58
109
  color: ${props => props.$disabled ? '#999' : '#1a1a1a'};
59
110
  font-weight: 500;
60
111
  ${props => props.$beginGroup && `
@@ -63,12 +114,26 @@ export const MenuItem = styled.div `
63
114
  padding-top: 8px;
64
115
  `}
65
116
 
117
+ /* Apply opacity only to direct children except right-icon-btn */
118
+ & > *:not(.right-icon-btn) {
119
+ opacity: ${props => props.$disabled ? 0.4 : 1};
120
+ }
121
+
122
+ /* Right icon button hidden by default, shown on hover */
123
+ & .right-icon-btn {
124
+ cursor: pointer !important;
125
+ }
126
+
66
127
  &:hover {
67
128
  ${props => !props.$disabled && `
68
129
  background: linear-gradient(90deg, #f0f7ff 0%, #e6f2ff 100%);
69
130
  color: #0066cc;
70
- padding-left: 14px;
71
131
  `}
132
+
133
+ /* Show right icon on hover */
134
+ & .right-icon-btn {
135
+ opacity: 1 !important;
136
+ }
72
137
  }
73
138
 
74
139
  &:active {
@@ -99,8 +164,8 @@ export const MenuItem = styled.div `
99
164
  }
100
165
 
101
166
  @media (max-width: 768px) {
102
- padding: 14px 16px;
103
- font-size: 15px;
167
+ padding: 4px 10px;
168
+ font-size: calc(var(--base-font-size, 13px) * 0.92);
104
169
  }
105
170
  `;
106
171
  export const MenuItemContent = styled.div `
@@ -113,7 +178,7 @@ export const IconWrapper = styled.span `
113
178
  display: flex;
114
179
  align-items: center;
115
180
  justify-content: center;
116
- font-size: 14px;
181
+ font-size: calc(var(--base-font-size, 13px) * 1.08);
117
182
  width: 18px;
118
183
  height: 18px;
119
184
  `;
@@ -124,23 +189,23 @@ export const MenuItemName = styled.span `
124
189
  overflow-wrap: break-word;
125
190
  line-height: 1.4;
126
191
  `;
127
- export const RightIconButton = styled.button `
192
+ export const RightIconButton = styled.button.attrs({
193
+ className: 'right-icon-btn'
194
+ }) `
128
195
  display: flex;
129
196
  align-items: center;
130
197
  justify-content: center;
131
198
  background: transparent;
132
199
  border: none;
133
- cursor: pointer;
200
+ cursor: pointer !important;
134
201
  padding: 4px 8px;
135
202
  margin-left: 8px;
136
203
  border-radius: 6px;
137
- color: inherit;
138
- font-size: 14px;
139
- opacity: 0.6;
140
- transition: all 0.15s ease;
204
+ font-size: calc(var(--base-font-size, 13px) * 1.08);
205
+ opacity: 0 !important;
206
+ transition: opacity 0.15s ease, background 0.15s ease, transform 0.15s ease;
141
207
 
142
208
  &:hover {
143
- opacity: 1;
144
209
  background: rgba(0, 0, 0, 0.05);
145
210
  transform: scale(1.1);
146
211
  }
@@ -158,12 +223,12 @@ export const RightIconButton = styled.button `
158
223
  export const SubmenuIndicator = styled.span `
159
224
  display: flex;
160
225
  align-items: center;
161
- font-size: 12px;
226
+ font-size: calc(var(--base-font-size, 13px) * 0.92);
162
227
  margin-left: 8px;
163
228
  opacity: 0.6;
164
229
  transition: transform 0.15s ease;
165
230
 
166
- ${MenuItem}:hover & {
231
+ ${MenuItem}:hover:not([data-disabled="true"]) & {
167
232
  ${props => !props.$isMobile && `
168
233
  transform: translateX(2px);
169
234
  opacity: 1;
@@ -174,11 +239,11 @@ export const Submenu = styled.div `
174
239
  position: fixed;
175
240
  left: ${props => {
176
241
  const spaceOnRight = globalThis.innerWidth - props.$parentRect.right;
177
- return spaceOnRight > 240 ? `${props.$parentRect.right - 8}px` : 'auto';
242
+ return spaceOnRight > 240 ? `${props.$parentRect.right - 4}px` : 'auto';
178
243
  }};
179
244
  right: ${props => {
180
245
  const spaceOnRight = globalThis.innerWidth - props.$parentRect.right;
181
- return spaceOnRight > 240 ? 'auto' : `${globalThis.innerWidth - props.$parentRect.left + 8}px`;
246
+ return spaceOnRight > 240 ? 'auto' : `${globalThis.innerWidth - props.$parentRect.left + 4}px`;
182
247
  }};
183
248
  /* Vertical positioning: Each submenu independently decides direction based on its own space */
184
249
  top: ${props => {
@@ -189,7 +254,7 @@ export const Submenu = styled.div `
189
254
  // If openUp is true, anchor to bottom and grow upward
190
255
  return props.$openUp ? `${globalThis.innerHeight - props.$parentRect.bottom - 8}px` : 'auto';
191
256
  }};
192
- z-index: 10001;
257
+ z-index: 10101;
193
258
  background: #ffffff;
194
259
  border-radius: 12px;
195
260
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12),
@@ -201,39 +266,88 @@ export const Submenu = styled.div `
201
266
  backdrop-filter: blur(10px);
202
267
  border: 1px solid rgba(0, 0, 0, 0.06);
203
268
 
204
- /* Add invisible padding to bridge the gap - works for both sides */
269
+ /* Invisible hover bridge on the LEFT side (for submenus opening left) */
205
270
  &::before {
206
271
  content: '';
207
272
  position: absolute;
208
273
  right: 100%;
209
- top: 0;
210
- bottom: 0;
211
- width: 15px;
274
+ top: -20px;
275
+ bottom: -20px;
276
+ width: 25px;
212
277
  background: transparent;
213
278
  }
214
279
 
215
- /* Bridge on the right side for nested submenus */
280
+ /* Invisible hover bridge on the RIGHT side (for submenus opening right) */
216
281
  &::after {
217
282
  content: '';
218
283
  position: absolute;
219
284
  left: 100%;
220
- top: 0;
221
- bottom: 0;
222
- width: 15px;
285
+ top: -20px;
286
+ bottom: -20px;
287
+ width: 25px;
223
288
  background: transparent;
224
289
  }
225
290
 
291
+ /* Reset color inheritance from parent with !important to override panel header styles */
292
+ & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
293
+ color: #1a1a1a !important;
294
+ }
295
+
226
296
  [data-theme='dark'] & {
227
297
  background: #2a2a2a;
228
298
  border-color: rgba(255, 255, 255, 0.1);
229
299
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4),
230
300
  0 2px 8px rgba(0, 0, 0, 0.3);
231
301
  }
302
+
303
+ [data-theme='dark'] & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
304
+ color: #e0e0e0 !important;
305
+ }
306
+
307
+ /* Dynamic scroll handling when submenu is too tall */
308
+ ${props => props.$needsScroll && props.$maxHeight ? `
309
+ max-height: ${props.$maxHeight}px;
310
+ overflow-y: auto;
311
+ overflow-x: hidden;
312
+
313
+ /* Custom scrollbar styling for submenus */
314
+ &::-webkit-scrollbar {
315
+ width: 8px;
316
+ }
317
+
318
+ &::-webkit-scrollbar-track {
319
+ background: rgba(0, 0, 0, 0.05);
320
+ border-radius: 4px;
321
+ }
322
+
323
+ &::-webkit-scrollbar-thumb {
324
+ background: rgba(0, 0, 0, 0.2);
325
+ border-radius: 4px;
326
+ }
327
+
328
+ &::-webkit-scrollbar-thumb:hover {
329
+ background: rgba(0, 0, 0, 0.3);
330
+ }
331
+ ` : ``}
332
+
333
+ [data-theme='dark'] & {
334
+ &::-webkit-scrollbar-track {
335
+ background: rgba(255, 255, 255, 0.05);
336
+ }
337
+
338
+ &::-webkit-scrollbar-thumb {
339
+ background: rgba(255, 255, 255, 0.2);
340
+ }
341
+
342
+ &::-webkit-scrollbar-thumb:hover {
343
+ background: rgba(255, 255, 255, 0.3);
344
+ }
345
+ }
232
346
  `;
233
347
  export const MobileMenuHeader = styled.div `
234
348
  display: flex;
235
349
  align-items: center;
236
- padding: 12px 16px;
350
+ padding: 4px 8px;
237
351
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
238
352
  margin-bottom: 8px;
239
353
  gap: 12px;
@@ -249,37 +363,22 @@ export const BackButton = styled.button `
249
363
  display: flex;
250
364
  align-items: center;
251
365
  justify-content: center;
252
- background: #0066cc;
253
- color: white;
254
366
  border: none;
255
367
  border-radius: 8px;
256
368
  width: 32px;
257
369
  height: 32px;
258
370
  cursor: pointer;
259
- font-size: 18px;
260
371
  transition: all 0.15s ease;
261
-
262
- &:hover {
263
- background: #0052a3;
264
- transform: scale(1.05);
265
- }
372
+ font-size: 16px;
373
+ transform: translateY(-2px);
266
374
 
267
375
  &:active {
268
376
  transform: scale(0.95);
269
377
  }
270
-
271
- [data-theme='dark'] & {
272
- background: #4db8ff;
273
- color: #1a1a1a;
274
-
275
- &:hover {
276
- background: #66c2ff;
277
- }
278
- }
279
378
  `;
280
379
  export const HeaderTitle = styled.h3 `
281
380
  margin: 0;
282
- font-size: 16px;
381
+ font-size: calc(var(--base-font-size, 13px) * 1.23);
283
382
  font-weight: 600;
284
383
  color: #1a1a1a;
285
384
  flex: 1;
@@ -1,18 +1,37 @@
1
+ export interface RightIconProps {
2
+ icon: React.ReactNode;
3
+ activeColor?: string;
4
+ inactiveColor?: string;
5
+ isActive?: boolean;
6
+ onClick?: () => void;
7
+ }
1
8
  export interface TMContextMenuItemProps {
9
+ id?: string;
2
10
  name: string;
3
11
  icon?: React.ReactNode;
4
12
  disabled?: boolean;
5
- onClick?: () => void;
13
+ onClick?: (data?: any) => void;
6
14
  submenu?: TMContextMenuItemProps[];
7
15
  visible?: boolean;
8
- rightIcon?: React.ReactNode;
9
- onRightIconClick?: () => void;
16
+ rightIconProps?: RightIconProps;
10
17
  beginGroup?: boolean;
18
+ tooltip?: string;
19
+ operationType?: 'singleRow' | 'multiRow';
11
20
  }
12
21
  export interface TMContextMenuProps {
13
22
  items: TMContextMenuItemProps[];
14
23
  trigger?: 'right' | 'left';
15
24
  children?: React.ReactNode;
25
+ target?: string;
26
+ externalControl?: {
27
+ visible: boolean;
28
+ position: {
29
+ x: number;
30
+ y: number;
31
+ };
32
+ onClose: () => void;
33
+ };
34
+ keepOpenOnClick?: boolean;
16
35
  }
17
36
  export interface Position {
18
37
  x: number;
@@ -0,0 +1,21 @@
1
+ export interface UseLongPressOptions {
2
+ containerRef: React.RefObject<HTMLElement>;
3
+ targetSelector: string | string[];
4
+ onLongPress: (event: {
5
+ clientX: number;
6
+ clientY: number;
7
+ target: HTMLElement;
8
+ }) => void;
9
+ onTouchStart?: (event: {
10
+ clientX: number;
11
+ clientY: number;
12
+ target: HTMLElement;
13
+ rowElement: HTMLElement;
14
+ }) => void;
15
+ duration?: number;
16
+ moveThreshold?: number;
17
+ hapticFeedback?: boolean;
18
+ enabled?: boolean;
19
+ }
20
+ export declare function useLongPress({ containerRef, targetSelector, onLongPress, onTouchStart, duration, moveThreshold, hapticFeedback, enabled, }: UseLongPressOptions): void;
21
+ export declare function triggerContextMenuEvent(target: HTMLElement, clientX: number, clientY: number): void;
@@ -0,0 +1,112 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { useIsIOS } from './hooks';
3
+ export function useLongPress({ containerRef, targetSelector, onLongPress, onTouchStart, duration = 500, moveThreshold = 10, hapticFeedback = true, enabled = true, }) {
4
+ const isIOS = useIsIOS();
5
+ const longPressTriggeredRef = useRef(false);
6
+ useEffect(() => {
7
+ if (!isIOS || !enabled || !containerRef.current)
8
+ return;
9
+ const container = containerRef.current;
10
+ let longPressTimeout = null;
11
+ let touchStartPos = null;
12
+ let longPressTarget = null;
13
+ const matchesSelector = (element) => {
14
+ const selectors = Array.isArray(targetSelector) ? targetSelector : [targetSelector];
15
+ for (const selector of selectors) {
16
+ const match = element.closest(selector);
17
+ if (match)
18
+ return match;
19
+ }
20
+ return null;
21
+ };
22
+ const handleTouchStart = (e) => {
23
+ const touch = e.touches[0];
24
+ const target = touch.target;
25
+ // Check if target matches any of the specified selectors
26
+ const matchedElement = matchesSelector(target);
27
+ if (!matchedElement)
28
+ return;
29
+ touchStartPos = { x: touch.clientX, y: touch.clientY };
30
+ longPressTriggeredRef.current = false;
31
+ longPressTarget = target;
32
+ // Call optional onTouchStart callback
33
+ if (onTouchStart) {
34
+ onTouchStart({
35
+ clientX: touch.clientX,
36
+ clientY: touch.clientY,
37
+ target,
38
+ rowElement: matchedElement,
39
+ });
40
+ }
41
+ if (longPressTimeout)
42
+ clearTimeout(longPressTimeout);
43
+ longPressTimeout = setTimeout(() => {
44
+ longPressTriggeredRef.current = true;
45
+ // Haptic feedback
46
+ if (hapticFeedback && 'vibrate' in navigator) {
47
+ navigator.vibrate(50);
48
+ }
49
+ // Call onLongPress callback
50
+ onLongPress({
51
+ clientX: touch.clientX,
52
+ clientY: touch.clientY,
53
+ target: longPressTarget,
54
+ });
55
+ longPressTimeout = null;
56
+ }, duration);
57
+ };
58
+ const handleTouchMove = (e) => {
59
+ if (!touchStartPos || !longPressTimeout)
60
+ return;
61
+ const touch = e.touches[0];
62
+ const dx = Math.abs(touch.clientX - touchStartPos.x);
63
+ const dy = Math.abs(touch.clientY - touchStartPos.y);
64
+ // Cancel long-press if finger moved too much
65
+ if (dx > moveThreshold || dy > moveThreshold) {
66
+ clearTimeout(longPressTimeout);
67
+ longPressTimeout = null;
68
+ }
69
+ };
70
+ const handleTouchEnd = () => {
71
+ if (longPressTimeout) {
72
+ clearTimeout(longPressTimeout);
73
+ longPressTimeout = null;
74
+ }
75
+ touchStartPos = null;
76
+ longPressTarget = null;
77
+ };
78
+ // Prevent click after long-press to avoid unintended actions
79
+ const handleClick = (e) => {
80
+ if (longPressTriggeredRef.current) {
81
+ e.preventDefault();
82
+ e.stopPropagation();
83
+ e.stopImmediatePropagation();
84
+ longPressTriggeredRef.current = false;
85
+ }
86
+ };
87
+ container.addEventListener('touchstart', handleTouchStart, { passive: true });
88
+ container.addEventListener('touchmove', handleTouchMove, { passive: true });
89
+ container.addEventListener('touchend', handleTouchEnd);
90
+ container.addEventListener('touchcancel', handleTouchEnd);
91
+ container.addEventListener('click', handleClick, { capture: true });
92
+ return () => {
93
+ if (longPressTimeout)
94
+ clearTimeout(longPressTimeout);
95
+ container.removeEventListener('touchstart', handleTouchStart);
96
+ container.removeEventListener('touchmove', handleTouchMove);
97
+ container.removeEventListener('touchend', handleTouchEnd);
98
+ container.removeEventListener('touchcancel', handleTouchEnd);
99
+ container.removeEventListener('click', handleClick, { capture: true });
100
+ };
101
+ }, [isIOS, enabled, containerRef, targetSelector, onLongPress, onTouchStart, duration, moveThreshold, hapticFeedback]);
102
+ }
103
+ export function triggerContextMenuEvent(target, clientX, clientY) {
104
+ const contextMenuEvent = new MouseEvent('contextmenu', {
105
+ bubbles: true,
106
+ cancelable: true,
107
+ clientX,
108
+ clientY,
109
+ button: 2,
110
+ });
111
+ target.dispatchEvent(contextMenuEvent);
112
+ }