import { createContext, useContext, useEffect } from "react"; import { useContextMenu, type ContextMenuController } from "./useContextMenu"; // docs/DESIGN.md "Background menu": a right-click on the EMPTY area of a page opens a menu of that // page's own toolbar actions (sort, view, quick filters) — never a new function, and desktop only. // PageShell listens on the page area and decides "empty" (lib/backgroundTarget); a page that has such a // menu renders `` (./PageMenu), which registers here while mounted and draws the same // `ContextMenu` as a row's, from the page's live state. A page that registers nothing keeps the // browser's menu everywhere. // // Its own module (not in PageShell.tsx / PageMenu.tsx) so those export only components (Fast Refresh). /** Opens the page's menu at a viewport point, anchored to the page area. */ export type PageMenuOpener = (x: number, y: number, contextElement: Element) => void; /** PageShell's registry: the latest registered opener answers (a feed inside a channel page takes * over while mounted); the returned function unregisters. */ export const PageMenuSlot = createContext<((opener: PageMenuOpener) => () => void) | null>(null); /** The page's background menu: render `` with the page's actions, in * every state where `enabled` — a menu registered with no surface drawn would eat the right-click * and show nothing. `` is the short form; a page that needs the open state (a row that * fetches on open) takes the hook. */ export function usePageMenu(enabled = true): ContextMenuController<"page"> { const register = useContext(PageMenuSlot); const menu = useContextMenu<"page">(); const { openAt } = menu; useEffect( () => (enabled ? register?.((x, y, el) => openAt(x, y, "page", el)) : undefined), [enabled, register, openAt], ); return menu; }