| 1 | import { type JSX, onCleanup, onMount } from "solid-js"; |
| 2 | import ChevronDown from "lucide-solid/icons/chevron-down"; |
| 3 | |
| 4 | export function VMMenu(props: { label: string; children: JSX.Element }) { |
| 5 | let menu!: HTMLDetailsElement; |
| 6 | const outside = (event: PointerEvent) => { |
| 7 | if (event.target instanceof Node && !menu.contains(event.target)) menu.open = false; |
| 8 | }; |
| 9 | onMount(() => document.addEventListener("pointerdown", outside)); |
| 10 | onCleanup(() => document.removeEventListener("pointerdown", outside)); |
| 11 | return <details ref={menu} class="vm-menu" name="vm-actions" onKeyDown={(event) => { |
| 12 | if (event.key === "Escape") { |
| 13 | menu.open = false; |
| 14 | menu.querySelector("summary")?.focus(); |
| 15 | event.stopPropagation(); |
| 16 | } |
| 17 | }}> |
| 18 | <summary>{props.label}<ChevronDown size={12} aria-hidden="true" /></summary> |
| 19 | <div role="group" aria-label={`${props.label} actions`} onClick={(event) => { |
| 20 | if (event.target instanceof HTMLElement && event.target.closest("button")) menu.open = false; |
| 21 | }}>{props.children}</div> |
| 22 | </details>; |
| 23 | } |