"use client"; import { useEffect, useRef, type ReactNode, type RefObject } from "react"; import { handleTabTrap } from "@/lib/a11y/focusTrap"; interface DrawerProps { open: boolean; onClose: () => void; // 滑出方向:导航在左、本章助手在右。 side?: "left" | "right"; // 无障碍标签(role=dialog)。 label: string; triggerRef?: RefObject; children: ReactNode; } // 移动端侧滑抽屉((null); const wasOpenRef = useRef(false); useEffect(() => { if (!open) { if (wasOpenRef.current) { wasOpenRef.current = false; triggerRef?.current?.focus(); } return; } wasOpenRef.current = true; const onKey = (e: KeyboardEvent): void => { if (e.key === "Escape") { e.preventDefault(); onClose(); } }; window.addEventListener("keydown", onKey); panelRef.current?.focus(); return () => window.removeEventListener("keydown", onKey); }, [open, onClose, triggerRef]); if (!open) return null; const sideClass = side === "left" ? "left-0 border-r" : "right-0 border-l"; return (
e.stopPropagation()} onKeyDown={(e) => { // focus trap:Tab/Shift+Tab 在抽屉内循环,不逃逸到背景(WCAG 2.1.2)。 if (panelRef.current) handleTabTrap(panelRef.current, e); }} className={`absolute top-0 h-full w-64 max-w-[80vw] overflow-auto border-line bg-panel py-4 shadow-paper outline-none ${sideClass}`} > {children}
); }