forked from BoostIO/BoostNote-App
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontextMenu.ts
More file actions
121 lines (103 loc) · 2.83 KB
/
Copy pathcontextMenu.ts
File metadata and controls
121 lines (103 loc) · 2.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { useState, useCallback } from 'react'
import { createStoreContext } from './context'
export enum MenuTypes {
Normal = 'Normal',
Separator = 'Separator',
Submenu = 'Submenu',
// TODO: Implement later
Checkbox = 'Checkbox',
Radio = 'Radio',
}
interface MenuItemBase {
type: MenuTypes
enabled?: boolean
visible?: boolean
}
export interface NormalMenuItem extends MenuItemBase {
type: MenuTypes.Normal
icon?: string
label: string
onClick: () => void
}
export interface SeparatorMenuItem extends MenuItemBase {
type: MenuTypes.Separator
}
export interface SubmenuMenuItem extends MenuItemBase {
type: MenuTypes.Submenu
submenu: MenuItem[]
}
export type MenuItem = NormalMenuItem | SeparatorMenuItem
export type Position = { x: number; y: number }
export interface ContextMenuContext {
closed: boolean
position: Position
menuItems: MenuItem[]
id: number
popup(event: React.MouseEvent<unknown>, menuItems: MenuItem[]): void
popupWithPosition(
position: { x: number; y: number },
menuItems: MenuItem[]
): void
close(): void
}
export const menuHeight = 24
export const menuSeparatorHeight = 12
export const menuMargin = 10
export const menuVerticalPadding = 4
export const menuZIndex = 9000
function useContextMenuStore(): ContextMenuContext {
const [closed, setClosed] = useState(true)
const [position, setPosition] = useState({ x: 0, y: 0 })
const [menuItems, setMenuItems] = useState<MenuItem[]>([])
const [id, setId] = useState(0)
const popupWithPosition = useCallback(
({ x, y }: { x: number; y: number }, menuItems: MenuItem[]) => {
setId(id + 1)
setClosed(false)
setMenuItems(menuItems)
const menuContentHeight = menuItems.reduce((height, menuItem) => {
const menuItemHeight =
menuItem.type === MenuTypes.Separator
? menuSeparatorHeight
: menuHeight
return height + menuItemHeight
}, 0)
const yPositionLimit =
window.innerHeight -
menuContentHeight -
menuMargin -
menuVerticalPadding * 2
const clientYIsLowerThanYPositionLimit = y > yPositionLimit
const position = {
// TODO: Limit xPosition
x,
y: clientYIsLowerThanYPositionLimit ? yPositionLimit : y,
}
setPosition(position)
},
[id]
)
const popup = useCallback(
(event: React.MouseEvent<unknown>, menuItems: MenuItem[]) => {
popupWithPosition({ x: event.clientX, y: event.clientY }, menuItems)
},
[popupWithPosition]
)
const close = useCallback(() => {
setClosed(true)
setMenuItems([])
}, [])
return {
closed,
position,
menuItems,
id,
popupWithPosition,
popup,
close,
}
}
export const {
StoreProvider: ContextMenuProvider,
useStore: useContextMenu,
} = createStoreContext(useContextMenuStore, 'context menu')