@topconsultnpm/sdkui-react 6.20.0-dev1.13 → 6.20.0-dev1.130
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.
- package/lib/assets/Toppy-help-center.png +0 -0
- package/lib/assets/headergradient.svg +87 -0
- package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +322 -30
- package/lib/components/NewComponents/ContextMenu/hooks.d.ts +8 -1
- package/lib/components/NewComponents/ContextMenu/hooks.js +80 -8
- package/lib/components/NewComponents/ContextMenu/index.d.ts +3 -0
- package/lib/components/NewComponents/ContextMenu/index.js +2 -0
- package/lib/components/NewComponents/ContextMenu/styles.d.ts +9 -1
- package/lib/components/NewComponents/ContextMenu/styles.js +146 -47
- package/lib/components/NewComponents/ContextMenu/types.d.ts +22 -3
- package/lib/components/NewComponents/ContextMenu/useLongPress.d.ts +21 -0
- package/lib/components/NewComponents/ContextMenu/useLongPress.js +112 -0
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +620 -125
- package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +25 -5
- package/lib/components/NewComponents/FloatingMenuBar/styles.js +215 -59
- package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +12 -3
- package/lib/components/base/TMAccordionNew.js +35 -14
- package/lib/components/base/TMButton.js +6 -0
- package/lib/components/base/TMClosableList.js +4 -0
- package/lib/components/base/TMCustomButton.js +61 -17
- package/lib/components/base/TMDataGrid.d.ts +7 -4
- package/lib/components/base/TMDataGrid.js +153 -11
- package/lib/components/base/TMDropDownMenu.js +21 -18
- package/lib/components/base/TMFileManager.d.ts +4 -3
- package/lib/components/base/TMFileManager.js +32 -24
- package/lib/components/base/TMFileManagerDataGridView.d.ts +3 -2
- package/lib/components/base/TMFileManagerDataGridView.js +1 -11
- package/lib/components/base/TMFileManagerThumbnailItems.d.ts +7 -1
- package/lib/components/base/TMFileManagerThumbnailItems.js +5 -2
- package/lib/components/base/TMFileManagerThumbnailsView.d.ts +17 -4
- package/lib/components/base/TMFileManagerThumbnailsView.js +18 -6
- package/lib/components/base/TMFileManagerUtils.d.ts +0 -12
- package/lib/components/base/TMListView.js +33 -15
- package/lib/components/base/TMPanel.d.ts +1 -1
- package/lib/components/base/TMPanel.js +4 -2
- package/lib/components/base/TMPopUp.js +6 -0
- package/lib/components/base/TMToolbarCard.js +2 -0
- package/lib/components/base/TMTreeView.d.ts +2 -1
- package/lib/components/base/TMTreeView.js +33 -26
- package/lib/components/choosers/TMDataListItemChooser.d.ts +2 -0
- package/lib/components/choosers/TMDataListItemChooser.js +8 -2
- package/lib/components/choosers/TMDcmtTypeChooser.d.ts +1 -0
- package/lib/components/choosers/TMDcmtTypeChooser.js +11 -3
- package/lib/components/choosers/TMDistinctValues.js +2 -2
- package/lib/components/choosers/TMDynDataListItemChooser.d.ts +2 -0
- package/lib/components/choosers/TMDynDataListItemChooser.js +8 -2
- package/lib/components/choosers/TMInvoiceRetrieveFormats.js +1 -1
- package/lib/components/choosers/TMMetadataChooser.d.ts +2 -0
- package/lib/components/choosers/TMMetadataChooser.js +19 -4
- package/lib/components/choosers/TMOrderRetrieveFormats.js +1 -1
- package/lib/components/choosers/TMUserChooser.d.ts +2 -5
- package/lib/components/choosers/TMUserChooser.js +33 -47
- package/lib/components/editors/TMCheckBox.js +2 -0
- package/lib/components/editors/TMDateBox.js +18 -9
- package/lib/components/editors/TMEditorStyled.js +7 -0
- package/lib/components/editors/TMLocalizedTextBox.d.ts +3 -1
- package/lib/components/editors/TMLocalizedTextBox.js +16 -14
- package/lib/components/editors/TMMetadataEditor.d.ts +1 -0
- package/lib/components/editors/TMMetadataEditor.js +4 -4
- package/lib/components/editors/TMMetadataTextBox.d.ts +9 -0
- package/lib/components/editors/TMMetadataTextBox.js +92 -0
- package/lib/components/editors/TMMetadataValues.d.ts +2 -0
- package/lib/components/editors/TMMetadataValues.js +26 -8
- package/lib/components/editors/TMRadioButton.js +2 -0
- package/lib/components/editors/TMTextArea.js +18 -30
- package/lib/components/editors/TMTextBox.d.ts +1 -1
- package/lib/components/editors/TMTextBox.js +29 -4
- package/lib/components/editors/TMTextExpression.js +6 -91
- package/lib/components/features/archive/TMArchive.js +2 -2
- package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +15 -0
- package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +462 -0
- package/lib/components/features/assistant/TMToppySpeechBubble.d.ts +11 -0
- package/lib/components/features/assistant/TMToppySpeechBubble.js +126 -0
- package/lib/components/features/documents/TMDcmtBlog.js +1 -1
- package/lib/components/features/documents/TMDcmtForm.d.ts +14 -2
- package/lib/components/features/documents/TMDcmtForm.js +576 -292
- package/lib/components/features/documents/TMDcmtPreview.js +42 -155
- package/lib/components/features/documents/TMDcmtTasks.js +9 -9
- package/lib/components/features/documents/TMMasterDetailDcmts.js +38 -53
- package/lib/components/features/documents/TMRelationViewer.d.ts +1 -1
- package/lib/components/features/documents/TMRelationViewer.js +2 -2
- package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +8 -0
- package/lib/components/features/search/{TMSearchResultCheckoutInfoForm.js → TMDcmtCheckoutInfoForm.js} +2 -2
- package/lib/components/features/search/TMSavedQuerySelector.js +72 -67
- package/lib/components/features/search/TMSearch.d.ts +3 -0
- package/lib/components/features/search/TMSearch.js +50 -11
- package/lib/components/features/search/TMSearchQueryEditor.d.ts +1 -0
- package/lib/components/features/search/TMSearchQueryEditor.js +10 -10
- package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -0
- package/lib/components/features/search/TMSearchQueryPanel.js +40 -25
- package/lib/components/features/search/TMSearchResult.d.ts +3 -0
- package/lib/components/features/search/TMSearchResult.js +370 -252
- package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +3 -3
- package/lib/components/features/search/TMSearchResultsMenuItems.js +227 -171
- package/lib/components/features/search/TMSignSettingsForm.js +1 -1
- package/lib/components/features/search/TMSignatureInfoContent.d.ts +6 -0
- package/lib/components/features/search/TMSignatureInfoContent.js +140 -0
- package/lib/components/features/search/TMViewHistoryDcmt.js +47 -52
- package/lib/components/features/tasks/TMTaskForm.js +75 -25
- package/lib/components/features/tasks/TMTasksAgenda.d.ts +3 -1
- package/lib/components/features/tasks/TMTasksAgenda.js +48 -9
- package/lib/components/features/tasks/TMTasksCalendar.d.ts +2 -0
- package/lib/components/features/tasks/TMTasksCalendar.js +19 -7
- package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
- package/lib/components/features/tasks/TMTasksUtils.js +57 -37
- package/lib/components/features/tasks/TMTasksView.js +28 -19
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +33 -2
- package/lib/components/features/workflow/TMWorkflowPopup.js +140 -34
- package/lib/components/features/workflow/diagram/DiagramItemComponent.d.ts +2 -0
- package/lib/components/features/workflow/diagram/DiagramItemComponent.js +14 -7
- package/lib/components/features/workflow/diagram/DiagramItemForm.js +1 -1
- package/lib/components/features/workflow/diagram/RecipientList.js +3 -2
- package/lib/components/features/workflow/diagram/WFDiagram.d.ts +4 -0
- package/lib/components/features/workflow/diagram/WFDiagram.js +164 -13
- package/lib/components/forms/Login/LoginValidatorService.d.ts +2 -0
- package/lib/components/forms/Login/LoginValidatorService.js +7 -2
- package/lib/components/forms/Login/TMLoginForm.js +35 -7
- package/lib/components/forms/TMChooserForm.js +1 -1
- package/lib/components/grids/TMBlogsPost.js +56 -31
- package/lib/components/grids/TMRecentsManager.js +20 -10
- package/lib/components/grids/TMValidationItemsList.js +6 -0
- package/lib/components/index.d.ts +6 -3
- package/lib/components/index.js +6 -3
- package/lib/components/layout/panelManager/TMPanelManagerContext.js +13 -5
- package/lib/components/query/TMQueryEditor.d.ts +6 -1
- package/lib/components/query/TMQueryEditor.js +105 -101
- package/lib/components/settings/SettingsAppearance.d.ts +2 -1
- package/lib/components/settings/SettingsAppearance.js +99 -30
- package/lib/components/sidebar/TMHeader.js +11 -7
- package/lib/components/sidebar/TMSidebar.d.ts +0 -1
- package/lib/components/sidebar/TMSidebar.js +16 -44
- package/lib/components/sidebar/TMSidebarItem.js +36 -17
- package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -1
- package/lib/components/viewers/TMDataListItemViewer.js +35 -71
- package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +8 -0
- package/lib/components/viewers/TMDataUserIdItemViewer.js +39 -0
- package/lib/css/tm-sdkui.css +1 -1
- package/lib/helper/SDKUI_Globals.d.ts +22 -0
- package/lib/helper/SDKUI_Globals.js +10 -1
- package/lib/helper/SDKUI_Localizator.d.ts +21 -3
- package/lib/helper/SDKUI_Localizator.js +196 -10
- package/lib/helper/TMCommandsContextMenu.d.ts +4 -2
- package/lib/helper/TMCommandsContextMenu.js +15 -4
- package/lib/helper/TMIcons.d.ts +4 -0
- package/lib/helper/TMIcons.js +13 -3
- package/lib/helper/TMPdfViewer.d.ts +8 -0
- package/lib/helper/TMPdfViewer.js +373 -0
- package/lib/helper/TMToppyMessage.js +4 -0
- package/lib/helper/checkinCheckoutManager.d.ts +31 -1
- package/lib/helper/checkinCheckoutManager.js +112 -30
- package/lib/helper/devextremeCustomMessages.d.ts +30 -0
- package/lib/helper/devextremeCustomMessages.js +30 -0
- package/lib/helper/helpers.d.ts +30 -2
- package/lib/helper/helpers.js +132 -4
- package/lib/helper/index.d.ts +2 -0
- package/lib/helper/index.js +2 -0
- package/lib/helper/queryHelper.d.ts +2 -2
- package/lib/helper/queryHelper.js +80 -24
- package/lib/helper/workItemsHelper.d.ts +6 -0
- package/lib/helper/workItemsHelper.js +230 -0
- package/lib/hooks/useCheckInOutOperations.d.ts +28 -0
- package/lib/hooks/useCheckInOutOperations.js +223 -0
- package/lib/hooks/useDataListItem.d.ts +12 -0
- package/lib/hooks/useDataListItem.js +132 -0
- package/lib/hooks/useDataUserIdItem.d.ts +10 -0
- package/lib/hooks/useDataUserIdItem.js +96 -0
- package/lib/hooks/useFloatingBarPinnedItems.d.ts +11 -0
- package/lib/hooks/useFloatingBarPinnedItems.js +54 -0
- package/lib/hooks/useMetadataExpression.d.ts +19 -0
- package/lib/hooks/useMetadataExpression.js +99 -0
- package/lib/hooks/useSettingsFeedback.d.ts +11 -0
- package/lib/hooks/useSettingsFeedback.js +38 -0
- package/lib/hooks/useWorkflowApprove.d.ts +4 -0
- package/lib/hooks/useWorkflowApprove.js +14 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3 -2
- package/lib/services/platform_services.d.ts +3 -3
- package/lib/ts/types.d.ts +61 -1
- package/lib/utils/theme.d.ts +1 -1
- package/lib/utils/theme.js +1 -1
- package/package.json +6 -5
- package/lib/components/NewComponents/Notification/Notification.d.ts +0 -4
- package/lib/components/NewComponents/Notification/Notification.js +0 -60
- package/lib/components/NewComponents/Notification/NotificationContainer.d.ts +0 -8
- package/lib/components/NewComponents/Notification/NotificationContainer.js +0 -33
- package/lib/components/NewComponents/Notification/index.d.ts +0 -2
- package/lib/components/NewComponents/Notification/index.js +0 -2
- package/lib/components/NewComponents/Notification/styles.d.ts +0 -21
- package/lib/components/NewComponents/Notification/styles.js +0 -180
- package/lib/components/NewComponents/Notification/types.d.ts +0 -18
- package/lib/components/NewComponents/Notification/types.js +0 -1
- package/lib/components/base/TMContextMenu.d.ts +0 -25
- package/lib/components/base/TMContextMenu.js +0 -109
- package/lib/components/base/TMContextMenuOLD.d.ts +0 -26
- package/lib/components/base/TMContextMenuOLD.js +0 -56
- package/lib/components/base/TMFloatingToolbar.d.ts +0 -9
- package/lib/components/base/TMFloatingToolbar.js +0 -101
- package/lib/components/features/assistant/ToppyDraggableHelpCenter.d.ts +0 -30
- package/lib/components/features/assistant/ToppyDraggableHelpCenter.js +0 -482
- package/lib/components/features/assistant/ToppySpeechBubble.d.ts +0 -9
- package/lib/components/features/assistant/ToppySpeechBubble.js +0 -117
- package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +0 -8
|
Binary file
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg id="Livello_2" data-name="Livello 2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1920 505.45">
|
|
3
|
+
<defs>
|
|
4
|
+
<style>
|
|
5
|
+
.cls-1 {
|
|
6
|
+
fill: url(#Sfumatura_senza_nome_6);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.cls-1, .cls-2, .cls-3, .cls-4 {
|
|
10
|
+
opacity: .5;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.cls-5 {
|
|
14
|
+
clip-path: url(#clippath-2);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.cls-5, .cls-6, .cls-7, .cls-8, .cls-9 {
|
|
18
|
+
fill: none;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.cls-2 {
|
|
22
|
+
fill: url(#Sfumatura_senza_nome_2);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.cls-6 {
|
|
26
|
+
clip-path: url(#clippath-3);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.cls-8 {
|
|
30
|
+
clip-path: url(#clippath);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.cls-3 {
|
|
34
|
+
fill: url(#Sfumatura_senza_nome_3-2);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.cls-9 {
|
|
38
|
+
clip-path: url(#clippath-1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.cls-4 {
|
|
42
|
+
fill: url(#Sfumatura_senza_nome_3);
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
45
|
+
<clipPath id="clippath">
|
|
46
|
+
<rect class="cls-7" x="1237.53" y="0" width="682.47" height="326.62"/>
|
|
47
|
+
</clipPath>
|
|
48
|
+
<radialGradient id="Sfumatura_senza_nome_3" data-name="Sfumatura senza nome 3" cx="1285.93" cy="3418.23" fx="1285.93" fy="3418.23" r="50" gradientTransform="translate(-6983.46 -9577.73) scale(6.82 2.8)" gradientUnits="userSpaceOnUse">
|
|
49
|
+
<stop offset="0" stop-color="#2459a4"/>
|
|
50
|
+
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
|
|
51
|
+
</radialGradient>
|
|
52
|
+
<clipPath id="clippath-1">
|
|
53
|
+
<rect class="cls-7" x="0" y="0" width="682.47" height="326.62" transform="translate(682.47 326.62) rotate(-180)"/>
|
|
54
|
+
</clipPath>
|
|
55
|
+
<radialGradient id="Sfumatura_senza_nome_6" data-name="Sfumatura senza nome 6" cx="1673.12" cy="3418.23" fx="1673.12" fy="3418.23" r="50" gradientTransform="translate(11545.93 -9577.73) rotate(-180) scale(6.82 -2.8)" gradientUnits="userSpaceOnUse">
|
|
56
|
+
<stop offset="0" stop-color="#2459a4"/>
|
|
57
|
+
<stop offset="1" stop-color="#fff" stop-opacity="0"/>
|
|
58
|
+
</radialGradient>
|
|
59
|
+
<clipPath id="clippath-2">
|
|
60
|
+
<rect class="cls-7" x="0" y="0" width="1055.7" height="297.5"/>
|
|
61
|
+
</clipPath>
|
|
62
|
+
<radialGradient id="Sfumatura_senza_nome_3-2" data-name="Sfumatura senza nome 3" cx="955.6" cy="3436.6" fx="955.6" fy="3436.6" r="50" gradientTransform="translate(-9560.44 -8770.57) scale(10.56 2.55)" xlink:href="#Sfumatura_senza_nome_3"/>
|
|
63
|
+
<clipPath id="clippath-3">
|
|
64
|
+
<rect class="cls-7" x="297.09" y="0" width="1055.7" height="505.45"/>
|
|
65
|
+
</clipPath>
|
|
66
|
+
<radialGradient id="Sfumatura_senza_nome_2" data-name="Sfumatura senza nome 2" cx="983.74" cy="3351.83" fx="983.74" fy="3351.83" r="50" gradientTransform="translate(-9560.44 -14533.91) scale(10.56 4.33)" gradientUnits="userSpaceOnUse">
|
|
67
|
+
<stop offset="0" stop-color="#2459a4"/>
|
|
68
|
+
<stop offset="1" stop-color="#fff"/>
|
|
69
|
+
</radialGradient>
|
|
70
|
+
</defs>
|
|
71
|
+
<g id="Livello_1-2" data-name="Livello 1">
|
|
72
|
+
<g>
|
|
73
|
+
<g class="cls-8">
|
|
74
|
+
<ellipse class="cls-4" cx="1792.58" cy="-7.96" rx="341.23" ry="139.98"/>
|
|
75
|
+
</g>
|
|
76
|
+
<g class="cls-9">
|
|
77
|
+
<ellipse class="cls-1" cx="127.42" cy="-7.96" rx="341.23" ry="139.98"/>
|
|
78
|
+
</g>
|
|
79
|
+
<g class="cls-5">
|
|
80
|
+
<ellipse class="cls-3" cx="527.85" cy="-7.25" rx="527.85" ry="127.5"/>
|
|
81
|
+
</g>
|
|
82
|
+
<g class="cls-6">
|
|
83
|
+
<ellipse class="cls-2" cx="824.94" cy="-12.32" rx="527.85" ry="216.62"/>
|
|
84
|
+
</g>
|
|
85
|
+
</g>
|
|
86
|
+
</g>
|
|
87
|
+
</svg>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useRef, useEffect } from 'react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
3
4
|
import * as S from './styles';
|
|
4
|
-
import { useIsMobile, useMenuPosition } from './hooks';
|
|
5
|
-
|
|
5
|
+
import { useIsMobile, useMenuPosition, useIsIOS } from './hooks';
|
|
6
|
+
import { IconArrowLeft } from '../../../helper';
|
|
7
|
+
const TMContextMenu = ({ items, trigger = 'right', children, target, externalControl, keepOpenOnClick = false }) => {
|
|
6
8
|
const [menuState, setMenuState] = useState({
|
|
7
9
|
visible: false,
|
|
8
10
|
position: { x: 0, y: 0 },
|
|
@@ -10,24 +12,217 @@ const TMContextMenu = ({ items, trigger = 'right', children }) => {
|
|
|
10
12
|
parentNames: [],
|
|
11
13
|
});
|
|
12
14
|
const [hoveredSubmenus, setHoveredSubmenus] = useState([]);
|
|
15
|
+
// Tracks items whose rightIconProps have been clicked, so the icon color flips immediately
|
|
16
|
+
const [toggledItemIds, setToggledItemIds] = useState(new Set());
|
|
13
17
|
const isMobile = useIsMobile();
|
|
18
|
+
const isIOS = useIsIOS();
|
|
14
19
|
const menuRef = useRef(null);
|
|
15
20
|
const triggerRef = useRef(null);
|
|
16
21
|
const submenuTimeoutRef = useRef(null);
|
|
17
|
-
const
|
|
22
|
+
const longPressTimeoutRef = useRef(null);
|
|
23
|
+
const touchStartPos = useRef(null);
|
|
24
|
+
// Get current menu to pass items count to positioning hook
|
|
25
|
+
const currentMenu = menuState.submenuStack.at(-1) || items;
|
|
26
|
+
const { openLeft, openUp, isCalculated, needsScroll, maxHeight } = useMenuPosition(menuRef, menuState.position, currentMenu.length);
|
|
18
27
|
const handleClose = () => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
if (externalControl) {
|
|
29
|
+
externalControl.onClose();
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
setMenuState(prev => ({
|
|
33
|
+
...prev,
|
|
34
|
+
visible: false,
|
|
35
|
+
submenuStack: [items],
|
|
36
|
+
parentNames: [],
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
25
39
|
setHoveredSubmenus([]);
|
|
40
|
+
setToggledItemIds(new Set());
|
|
26
41
|
};
|
|
42
|
+
// Sync with external control when provided
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (externalControl) {
|
|
45
|
+
setMenuState(prev => ({
|
|
46
|
+
...prev,
|
|
47
|
+
visible: externalControl.visible,
|
|
48
|
+
position: externalControl.position,
|
|
49
|
+
submenuStack: [items],
|
|
50
|
+
parentNames: [],
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
}, [externalControl, items]);
|
|
54
|
+
// iOS long-press support: attach touch listeners to target elements
|
|
55
|
+
// On long-press, dispatch synthetic contextmenu event to trigger existing handlers
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!target || !isIOS)
|
|
58
|
+
return;
|
|
59
|
+
const elements = document.querySelectorAll(target);
|
|
60
|
+
if (elements.length === 0)
|
|
61
|
+
return;
|
|
62
|
+
const touchStateMap = new WeakMap();
|
|
63
|
+
const handleTouchStart = (e) => {
|
|
64
|
+
const touchEvent = e;
|
|
65
|
+
const element = e.currentTarget;
|
|
66
|
+
const touch = touchEvent.touches[0];
|
|
67
|
+
let state = touchStateMap.get(element);
|
|
68
|
+
if (!state) {
|
|
69
|
+
state = { timeout: null, startX: 0, startY: 0, longPressTriggered: false };
|
|
70
|
+
touchStateMap.set(element, state);
|
|
71
|
+
}
|
|
72
|
+
state.startX = touch.clientX;
|
|
73
|
+
state.startY = touch.clientY;
|
|
74
|
+
state.longPressTriggered = false;
|
|
75
|
+
if (state.timeout)
|
|
76
|
+
clearTimeout(state.timeout);
|
|
77
|
+
state.timeout = setTimeout(() => {
|
|
78
|
+
if (state)
|
|
79
|
+
state.longPressTriggered = true;
|
|
80
|
+
// Haptic feedback
|
|
81
|
+
if ('vibrate' in navigator)
|
|
82
|
+
navigator.vibrate(50);
|
|
83
|
+
const syntheticEvent = new MouseEvent('contextmenu', {
|
|
84
|
+
bubbles: true,
|
|
85
|
+
cancelable: true,
|
|
86
|
+
clientX: touch.clientX,
|
|
87
|
+
clientY: touch.clientY,
|
|
88
|
+
});
|
|
89
|
+
// Mark this as our synthetic event
|
|
90
|
+
syntheticEvent.isSynthetic = true;
|
|
91
|
+
element.dispatchEvent(syntheticEvent);
|
|
92
|
+
if (state)
|
|
93
|
+
state.timeout = null;
|
|
94
|
+
}, 500);
|
|
95
|
+
};
|
|
96
|
+
const handleTouchMove = (e) => {
|
|
97
|
+
const touchEvent = e;
|
|
98
|
+
const element = e.currentTarget;
|
|
99
|
+
const state = touchStateMap.get(element);
|
|
100
|
+
if (!state?.timeout)
|
|
101
|
+
return;
|
|
102
|
+
const touch = touchEvent.touches[0];
|
|
103
|
+
const dx = Math.abs(touch.clientX - state.startX);
|
|
104
|
+
const dy = Math.abs(touch.clientY - state.startY);
|
|
105
|
+
if (dx > 10 || dy > 10) {
|
|
106
|
+
clearTimeout(state.timeout);
|
|
107
|
+
state.timeout = null;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const handleTouchEnd = (e) => {
|
|
111
|
+
const element = e.currentTarget;
|
|
112
|
+
const state = touchStateMap.get(element);
|
|
113
|
+
if (state?.timeout) {
|
|
114
|
+
clearTimeout(state.timeout);
|
|
115
|
+
state.timeout = null;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
// Prevent click event after long-press was triggered
|
|
119
|
+
const handleClick = (e) => {
|
|
120
|
+
const element = e.currentTarget;
|
|
121
|
+
const state = touchStateMap.get(element);
|
|
122
|
+
if (state?.longPressTriggered) {
|
|
123
|
+
e.preventDefault();
|
|
124
|
+
e.stopPropagation();
|
|
125
|
+
e.stopImmediatePropagation();
|
|
126
|
+
state.longPressTriggered = false;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
// Prevent default iOS context menu (but allow our synthetic events)
|
|
130
|
+
const handleContextMenu = (e) => {
|
|
131
|
+
// Don't prevent our own synthetic contextmenu events
|
|
132
|
+
if (e.isSynthetic)
|
|
133
|
+
return;
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
e.stopPropagation();
|
|
136
|
+
return false;
|
|
137
|
+
};
|
|
138
|
+
// Attach listeners to all matching elements
|
|
139
|
+
elements.forEach(element => {
|
|
140
|
+
const el = element;
|
|
141
|
+
// Prevent iOS native callout and text selection - must be set before touch starts
|
|
142
|
+
const style = el.style;
|
|
143
|
+
style.webkitTouchCallout = 'none';
|
|
144
|
+
style.webkitUserSelect = 'none';
|
|
145
|
+
el.addEventListener('touchstart', handleTouchStart, { passive: true });
|
|
146
|
+
el.addEventListener('touchmove', handleTouchMove, { passive: true });
|
|
147
|
+
el.addEventListener('touchend', handleTouchEnd);
|
|
148
|
+
el.addEventListener('touchcancel', handleTouchEnd);
|
|
149
|
+
el.addEventListener('contextmenu', handleContextMenu);
|
|
150
|
+
el.addEventListener('click', handleClick, { capture: true });
|
|
151
|
+
});
|
|
152
|
+
return () => {
|
|
153
|
+
elements.forEach(element => {
|
|
154
|
+
const el = element;
|
|
155
|
+
// Restore webkit properties
|
|
156
|
+
const style = el.style;
|
|
157
|
+
style.webkitTouchCallout = '';
|
|
158
|
+
style.webkitUserSelect = '';
|
|
159
|
+
el.removeEventListener('touchstart', handleTouchStart);
|
|
160
|
+
el.removeEventListener('touchmove', handleTouchMove);
|
|
161
|
+
el.removeEventListener('touchend', handleTouchEnd);
|
|
162
|
+
el.removeEventListener('touchcancel', handleTouchEnd);
|
|
163
|
+
el.removeEventListener('contextmenu', handleContextMenu);
|
|
164
|
+
el.removeEventListener('click', handleClick, { capture: true });
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
}, [target, isIOS]);
|
|
168
|
+
// Update items when they change while menu is visible (for keepOpenOnClick behavior)
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (!keepOpenOnClick)
|
|
171
|
+
return;
|
|
172
|
+
if (!externalControl && menuState.visible) {
|
|
173
|
+
setMenuState(prev => ({
|
|
174
|
+
...prev,
|
|
175
|
+
submenuStack: [items],
|
|
176
|
+
}));
|
|
177
|
+
// Update hoveredSubmenus with fresh items while keeping them open
|
|
178
|
+
setHoveredSubmenus(prev => {
|
|
179
|
+
if (prev.length === 0)
|
|
180
|
+
return prev;
|
|
181
|
+
// Rebuild hoveredSubmenus with updated items from the new items structure
|
|
182
|
+
return prev.map(submenu => {
|
|
183
|
+
// Find the matching submenu in the new items structure
|
|
184
|
+
const findSubmenuInItems = (searchItems) => {
|
|
185
|
+
for (const item of searchItems) {
|
|
186
|
+
if (item.submenu && item.submenu.length > 0) {
|
|
187
|
+
// Check if this submenu matches (compare first item name as identifier)
|
|
188
|
+
if (submenu.items.length > 0 && item.submenu.length > 0 &&
|
|
189
|
+
item.submenu[0].name === submenu.items[0].name) {
|
|
190
|
+
return item.submenu;
|
|
191
|
+
}
|
|
192
|
+
// Recursively search in nested submenus
|
|
193
|
+
const found = findSubmenuInItems(item.submenu);
|
|
194
|
+
if (found)
|
|
195
|
+
return found;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
199
|
+
};
|
|
200
|
+
const updatedItems = findSubmenuInItems(items);
|
|
201
|
+
return {
|
|
202
|
+
...submenu,
|
|
203
|
+
items: updatedItems || submenu.items, // Use updated items if found, otherwise keep old
|
|
204
|
+
};
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}, [items, menuState.visible, externalControl, keepOpenOnClick]);
|
|
209
|
+
// Track when the menu was opened to prevent immediate close on iOS
|
|
210
|
+
const menuOpenedAtRef = useRef(0);
|
|
211
|
+
useEffect(() => {
|
|
212
|
+
if (menuState.visible) {
|
|
213
|
+
menuOpenedAtRef.current = Date.now();
|
|
214
|
+
}
|
|
215
|
+
}, [menuState.visible]);
|
|
27
216
|
useEffect(() => {
|
|
28
217
|
if (!menuState.visible)
|
|
29
218
|
return;
|
|
30
219
|
const handleClickOutside = (event) => {
|
|
220
|
+
// On iOS, prevent closing immediately after opening (within 500ms for iOS, 300ms for others)
|
|
221
|
+
// This handles the case where touchend from long-press triggers touchstart listener
|
|
222
|
+
const delay = isIOS ? 500 : 300;
|
|
223
|
+
if (Date.now() - menuOpenedAtRef.current < delay) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
31
226
|
const target = event.target;
|
|
32
227
|
// Check if click is inside main menu
|
|
33
228
|
if (menuRef.current?.contains(target)) {
|
|
@@ -45,20 +240,35 @@ const TMContextMenu = ({ items, trigger = 'right', children }) => {
|
|
|
45
240
|
};
|
|
46
241
|
document.addEventListener('mousedown', handleClickOutside);
|
|
47
242
|
document.addEventListener('touchstart', handleClickOutside);
|
|
243
|
+
document.addEventListener('contextmenu', handleClickOutside); // Close on right-click outside
|
|
48
244
|
return () => {
|
|
49
245
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
50
246
|
document.removeEventListener('touchstart', handleClickOutside);
|
|
247
|
+
document.removeEventListener('contextmenu', handleClickOutside);
|
|
51
248
|
};
|
|
52
249
|
}, [menuState.visible]);
|
|
53
250
|
const handleContextMenu = (e) => {
|
|
54
251
|
if (trigger === 'right') {
|
|
55
252
|
e.preventDefault();
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
253
|
+
// Close any other open context menus by dispatching a synthetic contextmenu event to document
|
|
254
|
+
// This triggers the document listener in other ContextMenu instances to close them
|
|
255
|
+
const syntheticEvent = new MouseEvent('contextmenu', {
|
|
256
|
+
bubbles: true,
|
|
257
|
+
cancelable: true,
|
|
258
|
+
clientX: -1000, // Position outside viewport so it doesn't interfere
|
|
259
|
+
clientY: -1000,
|
|
61
260
|
});
|
|
261
|
+
document.dispatchEvent(syntheticEvent);
|
|
262
|
+
e.stopPropagation(); // Prevent event from bubbling after closing others
|
|
263
|
+
// Small delay to ensure other menus close first
|
|
264
|
+
setTimeout(() => {
|
|
265
|
+
setMenuState({
|
|
266
|
+
visible: true,
|
|
267
|
+
position: { x: e.clientX, y: e.clientY },
|
|
268
|
+
submenuStack: [items],
|
|
269
|
+
parentNames: [],
|
|
270
|
+
});
|
|
271
|
+
}, 0);
|
|
62
272
|
}
|
|
63
273
|
};
|
|
64
274
|
const handleClick = (e) => {
|
|
@@ -72,27 +282,73 @@ const TMContextMenu = ({ items, trigger = 'right', children }) => {
|
|
|
72
282
|
});
|
|
73
283
|
}
|
|
74
284
|
};
|
|
285
|
+
// iOS-specific touch handlers for long press
|
|
286
|
+
const handleTouchStart = (e) => {
|
|
287
|
+
if (!isIOS || trigger !== 'right')
|
|
288
|
+
return;
|
|
289
|
+
const touch = e.touches[0];
|
|
290
|
+
touchStartPos.current = { x: touch.clientX, y: touch.clientY };
|
|
291
|
+
if (longPressTimeoutRef.current) {
|
|
292
|
+
clearTimeout(longPressTimeoutRef.current);
|
|
293
|
+
}
|
|
294
|
+
longPressTimeoutRef.current = setTimeout(() => {
|
|
295
|
+
if (touchStartPos.current) {
|
|
296
|
+
if ('vibrate' in navigator) {
|
|
297
|
+
navigator.vibrate(50);
|
|
298
|
+
}
|
|
299
|
+
setMenuState({
|
|
300
|
+
visible: true,
|
|
301
|
+
position: { x: touchStartPos.current.x, y: touchStartPos.current.y },
|
|
302
|
+
submenuStack: [items],
|
|
303
|
+
parentNames: [],
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}, 500);
|
|
307
|
+
};
|
|
308
|
+
const handleTouchMove = (e) => {
|
|
309
|
+
if (!isIOS || trigger !== 'right' || !touchStartPos.current)
|
|
310
|
+
return;
|
|
311
|
+
const touch = e.touches[0];
|
|
312
|
+
const moveThreshold = 10; // pixels
|
|
313
|
+
// If finger moved too much, cancel long press
|
|
314
|
+
const deltaX = Math.abs(touch.clientX - touchStartPos.current.x);
|
|
315
|
+
const deltaY = Math.abs(touch.clientY - touchStartPos.current.y);
|
|
316
|
+
if (deltaX > moveThreshold || deltaY > moveThreshold) {
|
|
317
|
+
if (longPressTimeoutRef.current) {
|
|
318
|
+
clearTimeout(longPressTimeoutRef.current);
|
|
319
|
+
longPressTimeoutRef.current = null;
|
|
320
|
+
}
|
|
321
|
+
touchStartPos.current = null;
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
const handleTouchEnd = () => {
|
|
325
|
+
if (!isIOS || trigger !== 'right')
|
|
326
|
+
return;
|
|
327
|
+
if (longPressTimeoutRef.current) {
|
|
328
|
+
clearTimeout(longPressTimeoutRef.current);
|
|
329
|
+
longPressTimeoutRef.current = null;
|
|
330
|
+
}
|
|
331
|
+
touchStartPos.current = null;
|
|
332
|
+
};
|
|
75
333
|
const handleItemClick = (item) => {
|
|
76
334
|
if (item.disabled)
|
|
77
335
|
return;
|
|
78
|
-
// Always execute onClick if present
|
|
79
336
|
if (item.onClick) {
|
|
80
337
|
item.onClick();
|
|
81
338
|
}
|
|
82
339
|
if (item.submenu && item.submenu.length > 0) {
|
|
83
340
|
if (isMobile) {
|
|
84
|
-
// Mobile: Push submenu to stack
|
|
85
341
|
setMenuState(prev => ({
|
|
86
342
|
...prev,
|
|
87
343
|
submenuStack: [...prev.submenuStack, item.submenu],
|
|
88
344
|
parentNames: [...prev.parentNames, item.name],
|
|
89
345
|
}));
|
|
90
346
|
}
|
|
91
|
-
// Desktop: Submenus are handled by hover, don't close menu
|
|
92
347
|
}
|
|
93
348
|
else {
|
|
94
|
-
|
|
95
|
-
|
|
349
|
+
if (!keepOpenOnClick) {
|
|
350
|
+
handleClose();
|
|
351
|
+
}
|
|
96
352
|
}
|
|
97
353
|
};
|
|
98
354
|
const handleBack = () => {
|
|
@@ -103,20 +359,24 @@ const TMContextMenu = ({ items, trigger = 'right', children }) => {
|
|
|
103
359
|
}));
|
|
104
360
|
};
|
|
105
361
|
const handleMouseEnter = (item, event, depth = 0) => {
|
|
106
|
-
if (isMobile || !item.submenu || item.submenu.length === 0)
|
|
362
|
+
if (isMobile || !item.submenu || item.submenu.length === 0 || item.disabled)
|
|
107
363
|
return;
|
|
108
364
|
if (submenuTimeoutRef.current) {
|
|
109
365
|
clearTimeout(submenuTimeoutRef.current);
|
|
110
366
|
submenuTimeoutRef.current = null;
|
|
111
367
|
}
|
|
112
368
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
113
|
-
// Calculate
|
|
114
|
-
// Estimate submenu height: ~35px per item (accounting for smaller padding) + container padding
|
|
369
|
+
// Calculate submenu height dynamically
|
|
115
370
|
const estimatedSubmenuHeight = (item.submenu.length * 35) + 8;
|
|
116
371
|
const spaceBelow = window.innerHeight - rect.top;
|
|
117
372
|
const spaceAbove = rect.bottom;
|
|
118
|
-
|
|
373
|
+
const padding = 8;
|
|
374
|
+
// Determine if submenu should open upward
|
|
119
375
|
const shouldOpenUp = spaceBelow < estimatedSubmenuHeight && spaceAbove > spaceBelow;
|
|
376
|
+
// Calculate if submenu needs scroll and max-height
|
|
377
|
+
const availableSpace = shouldOpenUp ? spaceAbove : spaceBelow;
|
|
378
|
+
const needsScroll = estimatedSubmenuHeight > availableSpace - padding;
|
|
379
|
+
const maxHeight = needsScroll ? availableSpace - padding : undefined;
|
|
120
380
|
// Remove all submenus at this depth and deeper
|
|
121
381
|
setHoveredSubmenus(prev => {
|
|
122
382
|
const filtered = prev.filter(sub => sub.depth < depth);
|
|
@@ -129,6 +389,8 @@ const TMContextMenu = ({ items, trigger = 'right', children }) => {
|
|
|
129
389
|
parentRect: rect,
|
|
130
390
|
depth: depth,
|
|
131
391
|
openUp: shouldOpenUp,
|
|
392
|
+
needsScroll,
|
|
393
|
+
maxHeight,
|
|
132
394
|
}
|
|
133
395
|
];
|
|
134
396
|
});
|
|
@@ -155,6 +417,9 @@ const TMContextMenu = ({ items, trigger = 'right', children }) => {
|
|
|
155
417
|
if (submenuTimeoutRef.current) {
|
|
156
418
|
clearTimeout(submenuTimeoutRef.current);
|
|
157
419
|
}
|
|
420
|
+
if (longPressTimeoutRef.current) {
|
|
421
|
+
clearTimeout(longPressTimeoutRef.current);
|
|
422
|
+
}
|
|
158
423
|
};
|
|
159
424
|
}, []);
|
|
160
425
|
const renderMenuItems = (menuItems, depth = 0) => {
|
|
@@ -168,20 +433,47 @@ const TMContextMenu = ({ items, trigger = 'right', children }) => {
|
|
|
168
433
|
e.stopPropagation();
|
|
169
434
|
handleItemClick(item);
|
|
170
435
|
};
|
|
171
|
-
const
|
|
436
|
+
const handleRightIconPropsClick = (e) => {
|
|
437
|
+
e.preventDefault();
|
|
172
438
|
e.stopPropagation();
|
|
173
|
-
|
|
174
|
-
item.
|
|
439
|
+
e.nativeEvent.stopImmediatePropagation();
|
|
440
|
+
item.rightIconProps?.onClick?.();
|
|
441
|
+
if (item.id) {
|
|
442
|
+
setToggledItemIds(prev => {
|
|
443
|
+
const next = new Set(prev);
|
|
444
|
+
if (next.has(item.id))
|
|
445
|
+
next.delete(item.id);
|
|
446
|
+
else
|
|
447
|
+
next.add(item.id);
|
|
448
|
+
return next;
|
|
449
|
+
});
|
|
450
|
+
}
|
|
175
451
|
};
|
|
176
|
-
|
|
452
|
+
// rightIconProps takes precedence over rightIcon
|
|
453
|
+
let rightIconElement = null;
|
|
454
|
+
let rightIconClickHandler = null;
|
|
455
|
+
if (item.rightIconProps) {
|
|
456
|
+
const rip = item.rightIconProps;
|
|
457
|
+
const wasToggled = item.id ? toggledItemIds.has(item.id) : false;
|
|
458
|
+
const isActive = wasToggled ? !rip.isActive : rip.isActive;
|
|
459
|
+
const color = isActive ? (rip.activeColor || '#d32f2f') : (rip.inactiveColor || '#626262');
|
|
460
|
+
rightIconElement = _jsx("span", { style: { color, display: 'flex', alignItems: 'center' }, children: rip.icon });
|
|
461
|
+
if (rip.onClick) {
|
|
462
|
+
rightIconClickHandler = handleRightIconPropsClick;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return (_jsxs(S.MenuItem, { "$disabled": item.disabled, "$hasSubmenu": !!item.submenu && item.submenu.length > 0, "$beginGroup": item.beginGroup, "data-disabled": item.disabled ? "true" : undefined, 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 })] }), rightIconElement && rightIconClickHandler ? (_jsx(S.RightIconButton, { onClick: rightIconClickHandler, onMouseDown: (e) => e.stopPropagation(), "aria-label": `Action for ${item.name}`, children: rightIconElement })) : rightIconElement ? (_jsx(S.IconWrapper, { children: rightIconElement })) : null, item.submenu && item.submenu.length > 0 && (_jsx(S.SubmenuIndicator, { "$isMobile": isMobile, children: isMobile ? '›' : '▸' }))] }, itemKey));
|
|
177
466
|
});
|
|
178
467
|
};
|
|
179
|
-
const currentMenu = menuState.submenuStack.at(-1) || items;
|
|
180
468
|
const currentParentName = menuState.parentNames.at(-1) || '';
|
|
181
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, onClick: handleClick, onKeyDown: (e) => {
|
|
469
|
+
return (_jsxs(_Fragment, { children: [!externalControl && children && (_jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, onClick: handleClick, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, onTouchCancel: handleTouchEnd, onKeyDown: (e) => {
|
|
182
470
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
183
471
|
handleClick(e);
|
|
184
472
|
}
|
|
185
|
-
}, role: "button", tabIndex: 0, style: {
|
|
473
|
+
}, role: "button", tabIndex: 0, style: {
|
|
474
|
+
// display: 'inline-block',
|
|
475
|
+
WebkitTouchCallout: isIOS ? 'none' : undefined,
|
|
476
|
+
WebkitUserSelect: isIOS ? 'none' : undefined,
|
|
477
|
+
}, children: children })), menuState.visible && createPortal(_jsxs(_Fragment, { children: [_jsxs(S.MenuContainer, { ref: menuRef, "$x": menuState.position.x, "$y": menuState.position.y, "$openLeft": openLeft, "$openUp": openUp, "$isPositioned": isCalculated, "$externalControl": !!externalControl, "$needsScroll": needsScroll, "$maxHeight": maxHeight, 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}`)))] }), document.body)] }));
|
|
186
478
|
};
|
|
187
479
|
export default TMContextMenu;
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
export declare const useIsIOS: () => boolean;
|
|
1
2
|
export declare const useIsMobile: () => boolean;
|
|
2
3
|
export declare const useClickOutside: (callback: () => void) => import("react").RefObject<HTMLDivElement>;
|
|
3
4
|
interface Position {
|
|
4
5
|
x: number;
|
|
5
6
|
y: number;
|
|
6
7
|
}
|
|
7
|
-
export declare const useMenuPosition: (menuRef: React.RefObject<HTMLDivElement | null>, position: Position) => {
|
|
8
|
+
export declare const useMenuPosition: (menuRef: React.RefObject<HTMLDivElement | null>, position: Position, itemsCount?: number) => {
|
|
9
|
+
isCalculated: boolean;
|
|
8
10
|
openLeft: boolean;
|
|
9
11
|
openUp: boolean;
|
|
12
|
+
needsScroll: boolean;
|
|
13
|
+
maxHeight: number | undefined;
|
|
10
14
|
};
|
|
15
|
+
export declare const getContextMenuTarget: <T extends {
|
|
16
|
+
id: string;
|
|
17
|
+
}>(event: React.MouseEvent | undefined, focusedItem: T | undefined, selectedItem: T | undefined, dataSource: T[], idPrefix: string, isMobile: boolean) => T | undefined;
|
|
11
18
|
export {};
|