Files
dbx/apps/desktop/src/components/ui/customContextMenuRegistry.ts
T

70 lines
1.9 KiB
TypeScript

export type ContextMenuClose = () => void;
export interface ContextMenuRegistration {
setOpen(open: boolean): void;
dispose(): void;
}
export interface ContextMenuRegistry {
register(close: ContextMenuClose): ContextMenuRegistration;
}
export function createContextMenuRegistry(documentTarget: EventTarget, windowTarget: EventTarget): ContextMenuRegistry {
const openMenus = new Set<ContextMenuClose>();
let hostCount = 0;
let listenersAttached = false;
function closeAll() {
const closers = [...openMenus];
openMenus.clear();
for (const close of closers) close();
}
function attachListeners() {
if (listenersAttached) return;
documentTarget.addEventListener("contextmenu", closeAll, true);
documentTarget.addEventListener("scroll", closeAll, true);
windowTarget.addEventListener("resize", closeAll);
listenersAttached = true;
}
function detachListeners() {
if (!listenersAttached) return;
documentTarget.removeEventListener("contextmenu", closeAll, true);
documentTarget.removeEventListener("scroll", closeAll, true);
windowTarget.removeEventListener("resize", closeAll);
listenersAttached = false;
openMenus.clear();
}
return {
register(close) {
hostCount += 1;
attachListeners();
let disposed = false;
return {
setOpen(open) {
if (disposed) return;
if (open) openMenus.add(close);
else openMenus.delete(close);
},
dispose() {
if (disposed) return;
disposed = true;
openMenus.delete(close);
hostCount -= 1;
if (hostCount === 0) detachListeners();
},
};
},
};
}
let globalContextMenuRegistry: ContextMenuRegistry | undefined;
export function registerGlobalContextMenu(close: ContextMenuClose): ContextMenuRegistration {
globalContextMenuRegistry ??= createContextMenuRegistry(document, window);
return globalContextMenuRegistry.register(close);
}