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 import { ref, reactive } from 'vue'
import { useEventListener } from '@vueuse/core'
export const ContextMenu = ({ enabled = true }: { enabled?: boolean }) => {
const
el = ref<Element | null>(null),
visible = ref<boolean>(false),
position = ref({ top: 0, left: 0 })
useEventListener(document, 'contextmenu', (event) => {
if (
enabled &&
el.value &&
event.target &&
(event.target === el.value || el.value.contains(event.target as Element))
) {
event.preventDefault()
position.value = { top: event.offsetY, left: event.offsetX }
visible.value = true
} else {
visible.value = false
}
})
useEventListener(document, 'click', () => {
visible.value = false
})
useEventListener(document, 'keyup', (event) => {
if (event.key === 'Escape')
visible.value = false
})
vineStyle.scoped(`
.dropdown-menu {
min-width: 3rem !important;
z-index: 3000 !important;
}
.dropdown-menu .dropdown-item {
z-index: 9000 !important;
}
`)
const style = reactive({
left: `${position.value.left}px`,
top: `${position.value.top}px`,
})
return vine`
<div ref="el">
<slot />
<ul
v-if="enabled && visible"
class="dropdown-menu position-absolute show"
:style="style"
>
<slot name="context-menu" />
</ul>
</div>
`
}