import Link from "next/link"; import { useEffect, useId, useRef, useState, type KeyboardEvent } from "react"; import type { DocLink } from "@/lib/docs"; import { collectionEntries, collectionIcon, collectionLabel, collectionTone } from "@/lib/collections"; import { Icon } from "./Icon"; export function CategoryNavigation({ docs, current }: { docs: DocLink[]; current?: string }) { const navigation = useRef(null); const triggers = useRef(new Map()); const [open, setOpen] = useState(null); const id = useId(); const categories = [...new Set(docs.map((doc) => doc.category))]; const collections = collectionEntries(docs); const selected = docs.find((doc) => doc.slug === current); useEffect(() => { function outside(event: PointerEvent) { if (event.target instanceof Node && !navigation.current?.contains(event.target)) setOpen(null); } function escape(event: globalThis.KeyboardEvent) { if (event.key !== "Escape" || !open) return; if (navigation.current?.contains(document.activeElement)) { event.preventDefault(); triggers.current.get(open)?.focus(); } setOpen(null); } document.addEventListener("pointerdown", outside); document.addEventListener("keydown", escape); return () => { document.removeEventListener("pointerdown", outside); document.removeEventListener("keydown", escape); }; }, [open]); function focusItem(panel: string, last = false) { requestAnimationFrame(() => { const links = document.getElementById(panel)?.querySelectorAll("a"); links?.[last ? links.length - 1 : 0]?.focus(); }); } function move(event: KeyboardEvent) { if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return; const links = [...event.currentTarget.querySelectorAll("a")]; const index = links.indexOf(document.activeElement as HTMLAnchorElement); if (index < 0) return; event.preventDefault(); const next = event.key === "Home" ? 0 : event.key === "End" ? links.length - 1 : (index + (event.key === "ArrowDown" ? 1 : -1) + links.length) % links.length; links[next]?.focus(); } return ; }