'use client' import { useEffect } from 'react' import Link from 'next/link' import BrandLogo from './brand-logo' import { usePathname } from 'next/navigation' import { SITE_LINKS } from './site-links' import AccountLink from './account-link' /* Shared mobile navigation, including keyboard focus and background locking. */ export default function SiteMenu({ menuId = 'siteMenu', viewer, }: { menuId?: string viewer?: { email: string } | null }) { const pathname = usePathname() useEffect(() => { const menu = document.getElementById(menuId) const trigger = document.getElementById('menuTrigger') if (!menu || !trigger) return const background = [...document.querySelectorAll('#site > *')] .filter(element => element !== menu) const originalInert = background.map(element => element.inert) function setOpen(open: boolean) { menu!.classList.toggle('open', open) menu!.setAttribute('aria-hidden', String(!open)) trigger!.setAttribute('aria-expanded', String(open)) document.body.classList.toggle('locked', open) background.forEach((element, index) => { element.inert = open || originalInert[index] }) if (open) (menu!.querySelector('.menu-head [data-menu-close]') as HTMLElement | null)?.focus() else trigger!.focus() } const onTrigger = () => setOpen(true) const onScrim = (e: Event) => { if ((e.target as HTMLElement).closest('[data-menu-close]')) setOpen(false) } const onLink = () => setOpen(false) const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape' && menu!.classList.contains('open')) setOpen(false) if (e.key === 'Tab' && menu!.classList.contains('open')) { const focusable = [...menu!.querySelectorAll('a[href], button:not([disabled])')] .filter(element => element.getClientRects().length && !element.classList.contains('menu-scrim')) const first = focusable[0] const last = focusable[focusable.length - 1] if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last?.focus() } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first?.focus() } } } trigger.addEventListener('click', onTrigger) menu.addEventListener('click', onScrim) menu.querySelectorAll('a').forEach((a) => a.addEventListener('click', onLink)) document.addEventListener('keydown', onKey) return () => { trigger.removeEventListener('click', onTrigger) menu.removeEventListener('click', onScrim) menu.querySelectorAll('a').forEach(a => a.removeEventListener('click', onLink)) document.removeEventListener('keydown', onKey) document.body.classList.remove('locked') background.forEach((element, index) => { element.inert = originalInert[index] }) } }, [menuId]) return ( ) }