Provides React context primitives for `AppLayout`'s drawer portal targeting and multi-panel open/close coordination, intentionally isolated to prevent circular module imports. ## Key Components | Export | Type | Description | |---|---|---| | `AppLayoutDrawerContainerContext` | `Context` | Reference to the `
` wrapper element used as the portal mount target for `AppLayoutDrawer` | | `useAppLayoutDrawerContainer` | Hook | Consumes `AppLayoutDrawerContainerContext`; returns `null` outside of `AppLayout` | | `AppLayoutDrawerHandle` | Interface | Shape each panel must expose — a single `close()` method | | `AppLayoutDrawerCoordination` | Interface | Coordination contract: `notifyDrawerDidOpen` and `registerDrawer` | | `AppLayoutDrawerCoordinationContext` | `Context` | Shared bus enforcing the one-panel-at-a-time rule | | `useAppLayoutDrawerCoordination` | Hook | Consumes `AppLayoutDrawerCoordinationContext`; returns `null` outside of `AppLayout` | ## Usage Example ```typescript // Inside a drawer panel (e.g. AppLayoutDrawer or NotificationDrawer) import { useAppLayoutDrawerContainer, useAppLayoutDrawerCoordination, type AppLayoutDrawerHandle, } from './app-layout-context' function MyDrawer() { const container = useAppLayoutDrawerContainer() const coordination = useAppLayoutDrawerCoordination() const handle: AppLayoutDrawerHandle = { close: () => setOpen(false) } useEffect(() => { if (!coordination) return // Register so other panels can close this one return coordination.registerDrawer(handle) }, [coordination]) function open() { // Closes the burger menu + every other registered panel coordination?.notifyDrawerDidOpen(handle) setOpen(true) } if (!container) return null return createPortal(
Drawer content
, container) } ``` > **Why a separate module?** `AppLayout` renders `AppLayoutDrawer`, `NotificationDrawer`, and `TimeTrackerHeaderButton`. If those panels imported `AppLayout` to access these contexts, a module cycle would form. Keeping contexts here breaks the cycle.