-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathShyMenu.svelte
65 lines (56 loc) · 1.47 KB
/
ShyMenu.svelte
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
<script>
import Menu from "./Menu.svelte";
import { keyEventToString } from "./keyboard.js";
const { menu, clickable, children, ...rest } = $props();
const globalHideEvents = ["pointerdown", "keydown", "resize"];
let show = $state(false),
menuElement = $state();
function hasAncestor(node, check) {
if (node == null) return false;
if (node.parentNode == check) return true;
return hasAncestor(node.parentNode, check);
}
function hide(e) {
switch (event.type) {
case "keydown":
switch (keyEventToString(e)) {
case undefined:
case "tab":
case "Shift+tab":
// TODO: Handle focus within context menu
return;
}
break;
case "pointerdown":
if (hasAncestor(e.target, menuElement)) {
return;
}
}
e.preventDefault();
show = false;
globalHideEvents.forEach((type) => window.removeEventListener(type, hide));
}
async function handler(e) {
show = true;
e.preventDefault();
globalHideEvents.forEach((type) => window.addEventListener(type, hide));
}
</script>
{#snippet menuBuilder(menuData)}
<Menu
bind:menu={menuElement}
entries={menuData.map((entry) => {
const onclick = entry.onclick;
entry.onclick = (e) => {
onclick(e);
hide(e);
};
return entry;
})}
/>
{/snippet}
{#if show}
{@render menu?.(menuBuilder)}
{/if}
{@render clickable?.(handler)}
{@render children?.()}