"use client"; import { useState, useEffect, useRef, useCallback } from "react"; import { DocsSidebar } from "../components/docs-sidebar"; import { DocsPager } from "../components/docs-pager"; export function DocsNav({ children }: { children: React.ReactNode }) { const [open, setOpen] = useState(false); const sidebarRef = useRef(null); const buttonRef = useRef(null); const close = useCallback(() => { setOpen(false); buttonRef.current?.focus(); }, []); // Close on Escape useEffect(() => { if (!open) return; const handler = (e: KeyboardEvent) => { if (e.key === "Escape") close(); }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, [open, close]); // Trap focus inside sidebar when open on mobile useEffect(() => { if (!open || !sidebarRef.current) return; const sidebar = sidebarRef.current; const focusable = sidebar.querySelectorAll( 'a[href], button, [tabindex]:not([tabindex="-1"])' ); if (focusable.length === 0) return; const first = focusable[0]; const last = focusable[focusable.length - 1]; // Focus first link first.focus(); const trap = (e: KeyboardEvent) => { if (e.key !== "Tab") return; if (e.shiftKey) { if (document.activeElement === first) { e.preventDefault(); last.focus(); } } else { if (document.activeElement === last) { e.preventDefault(); first.focus(); } } }; sidebar.addEventListener("keydown", trap); return () => sidebar.removeEventListener("keydown", trap); }, [open]); // Lock body scroll when open on mobile useEffect(() => { if (!open) return; const mq = window.matchMedia("(min-width: 768px)"); if (mq.matches) return; // don't lock on desktop document.body.style.overflow = "hidden"; return () => { document.body.style.overflow = ""; }; }, [open]); return (
{/* Mobile menu button */} {/* Mobile overlay */} {open && ( ); }