From 2213c040bfb5c415c0d82a2785138830f7b38e0d Mon Sep 17 00:00:00 2001 From: 3720 Date: Thu, 19 Dec 2024 21:44:50 +0800 Subject: [PATCH] feat(database): add global menu open listener (#9032) --- .../src/context-menu/menu-renderer.ts | 14 ++++---- .../components/src/context-menu/menu.ts | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/packages/affine/components/src/context-menu/menu-renderer.ts b/packages/affine/components/src/context-menu/menu-renderer.ts index a1b9e88293ca..a4c45de03104 100644 --- a/packages/affine/components/src/context-menu/menu-renderer.ts +++ b/packages/affine/components/src/context-menu/menu-renderer.ts @@ -502,11 +502,12 @@ const popMobileMenu = (options: MenuOptions): MenuHandler => { }; return { close: () => { - closePopup(); + menu.close(); }, menu, reopen: () => { - options.onClose?.(); + menu.close(); + popMobileMenu(options); }, }; }; @@ -526,15 +527,16 @@ export const popMenu = ( const onClose = () => { props.options.onClose?.(); popupEnd(); + closePopup(); }; const menu = new Menu({ ...props.options, - onClose: () => { - closePopup(); - }, + onClose: onClose, }); const closePopup = createPopup(target, menu.menuElement, { - onClose: onClose, + onClose: () => { + menu.close(); + }, middleware: props.middleware ?? [ autoPlacement({ allowedPlacements: [ diff --git a/packages/affine/components/src/context-menu/menu.ts b/packages/affine/components/src/context-menu/menu.ts index 8fa27e4cb5ee..bb575b3070db 100644 --- a/packages/affine/components/src/context-menu/menu.ts +++ b/packages/affine/components/src/context-menu/menu.ts @@ -40,11 +40,30 @@ export type MenuOptions = { items: MenuConfig[]; }; +// Global menu open listener type +type MenuOpenListener = (menu: Menu) => (() => void) | void; + +// Global menu open listeners +const menuOpenListeners = new Set(); + +// Add global menu open listener +export function onMenuOpen(listener: MenuOpenListener) { + menuOpenListeners.add(listener); + // Return cleanup function + return () => { + menuOpenListeners.delete(listener); + }; +} + export class Menu { + private _cleanupFns: Array<() => void> = []; + private _currentFocused$ = signal(); private _subMenu$ = signal(); + closed = false; + readonly currentFocused$ = computed(() => this._currentFocused$.value); menuElement: MenuComponentInterface; @@ -68,9 +87,25 @@ export class Menu { ? new MobileMenuComponent() : new MenuComponent(); this.menuElement.menu = this; + + // Call global menu open listeners + menuOpenListeners.forEach(listener => { + const cleanup = listener(this); + if (cleanup) { + this._cleanupFns.push(cleanup); + } + }); } close() { + if (this.closed) { + return; + } + this.closed = true; + // Execute cleanup functions + this._cleanupFns.forEach(cleanup => cleanup()); + this._cleanupFns = []; + this.menuElement.remove(); this.options.onClose?.(); }