diff --git a/goldens/cdk/menu/index.api.md b/goldens/cdk/menu/index.api.md index 1f48227d1088..1b21e9148e8d 100644 --- a/goldens/cdk/menu/index.api.md +++ b/goldens/cdk/menu/index.api.md @@ -229,6 +229,7 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD // @public export abstract class CdkMenuTriggerBase implements OnDestroy { protected childMenu?: Menu; + abstract close(): void; readonly closed: EventEmitter; protected readonly destroyed: Subject; protected getMenuContentPortal(): TemplatePortal; @@ -273,15 +274,6 @@ export type ContextMenuCoordinates = { y: number; }; -// @public -export class ContextMenuTracker { - update(trigger: CdkContextMenuTrigger): void; - // (undocumented) - static ɵfac: i0.ɵɵFactoryDeclaration; - // (undocumented) - static ɵprov: i0.ɵɵInjectableDeclaration; -} - // @public export interface FocusableElement { _elementRef: ElementRef; @@ -358,6 +350,15 @@ export interface MenuStackItem { menuStack?: MenuStack; } +// @public +export class MenuTracker { + update(trigger: CdkMenuTriggerBase): void; + // (undocumented) + static ɵfac: i0.ɵɵFactoryDeclaration; + // (undocumented) + static ɵprov: i0.ɵɵInjectableDeclaration; +} + // @public export const PARENT_OR_NEW_INLINE_MENU_STACK_PROVIDER: (orientation: "vertical" | "horizontal") => { provide: InjectionToken; diff --git a/src/cdk/menu/context-menu-trigger.ts b/src/cdk/menu/context-menu-trigger.ts index 2c2640d4b2c1..84e35cabf503 100644 --- a/src/cdk/menu/context-menu-trigger.ts +++ b/src/cdk/menu/context-menu-trigger.ts @@ -11,7 +11,6 @@ import { ChangeDetectorRef, Directive, inject, - Injectable, Injector, Input, OnDestroy, @@ -28,7 +27,7 @@ import {_getEventTarget} from '../platform'; import {merge, partition} from 'rxjs'; import {skip, takeUntil, skipWhile} from 'rxjs/operators'; import {MENU_STACK, MenuStack} from './menu-stack'; -import {CdkMenuTriggerBase, MENU_TRIGGER} from './menu-trigger-base'; +import {CdkMenuTriggerBase, MENU_TRIGGER, MenuTracker} from './menu-trigger-base'; /** The preferred menu positions for the context menu. */ const CONTEXT_MENU_POSITIONS = STANDARD_DROPDOWN_BELOW_POSITIONS.map(position => { @@ -39,24 +38,6 @@ const CONTEXT_MENU_POSITIONS = STANDARD_DROPDOWN_BELOW_POSITIONS.map(position => return {...position, offsetX, offsetY}; }); -/** Tracks the last open context menu trigger across the entire application. */ -@Injectable({providedIn: 'root'}) -export class ContextMenuTracker { - /** The last open context menu trigger. */ - private static _openContextMenuTrigger?: CdkContextMenuTrigger; - - /** - * Close the previous open context menu and set the given one as being open. - * @param trigger The trigger for the currently open Context Menu. - */ - update(trigger: CdkContextMenuTrigger) { - if (ContextMenuTracker._openContextMenuTrigger !== trigger) { - ContextMenuTracker._openContextMenuTrigger?.close(); - ContextMenuTracker._openContextMenuTrigger = trigger; - } - } -} - /** The coordinates where the context menu should open. */ export type ContextMenuCoordinates = {x: number; y: number}; @@ -85,7 +66,10 @@ export type ContextMenuCoordinates = {x: number; y: number}; export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestroy { private readonly _injector = inject(Injector); private readonly _directionality = inject(Directionality, {optional: true}); - private readonly _contextMenuTracker = inject(ContextMenuTracker); + + /** The app's menu tracking registry */ + private readonly _menuTracker = inject(MenuTracker); + private readonly _changeDetectorRef = inject(ChangeDetectorRef); /** Whether the context menu is disabled. */ @@ -124,7 +108,7 @@ export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestr // resulting in multiple stacked context menus being displayed. event.stopPropagation(); - this._contextMenuTracker.update(this); + this._menuTracker.update(this); this._open(event, {x: event.clientX, y: event.clientY}); // A context menu can be triggered via a mouse right click or a keyboard shortcut. diff --git a/src/cdk/menu/menu-trigger-base.ts b/src/cdk/menu/menu-trigger-base.ts index d0ba4728920a..7656603cc00a 100644 --- a/src/cdk/menu/menu-trigger-base.ts +++ b/src/cdk/menu/menu-trigger-base.ts @@ -10,6 +10,7 @@ import { Directive, EventEmitter, inject, + Injectable, InjectionToken, Injector, OnDestroy, @@ -42,6 +43,24 @@ export const MENU_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy>( }, ); +/** Tracks the last open menu trigger across the entire application. */ +@Injectable({providedIn: 'root'}) +export class MenuTracker { + /** The last open menu trigger. */ + private static _openMenuTrigger?: CdkMenuTriggerBase; + + /** + * Close the previous open menu and set the given one as being open. + * @param trigger The trigger for the currently open Menu. + */ + update(trigger: CdkMenuTriggerBase) { + if (MenuTracker._openMenuTrigger !== trigger) { + MenuTracker._openMenuTrigger?.close(); + MenuTracker._openMenuTrigger = trigger; + } + } +} + /** * Abstract directive that implements shared logic common to all menu triggers. * This class can be extended to create custom menu trigger types. @@ -83,6 +102,9 @@ export abstract class CdkMenuTriggerBase implements OnDestroy { /** Context data to be passed along to the menu template */ menuData: unknown; + /** Close the opened menu. */ + abstract close(): void; + /** A reference to the overlay which manages the triggered menu */ protected overlayRef: OverlayRef | null = null; diff --git a/src/cdk/menu/menu-trigger.ts b/src/cdk/menu/menu-trigger.ts index 6fa7c834fe74..d37ab81a4205 100644 --- a/src/cdk/menu/menu-trigger.ts +++ b/src/cdk/menu/menu-trigger.ts @@ -43,7 +43,7 @@ import {takeUntil} from 'rxjs/operators'; import {CDK_MENU, Menu} from './menu-interface'; import {PARENT_OR_NEW_MENU_STACK_PROVIDER} from './menu-stack'; import {MENU_AIM} from './menu-aim'; -import {CdkMenuTriggerBase, MENU_TRIGGER} from './menu-trigger-base'; +import {CdkMenuTriggerBase, MENU_TRIGGER, MenuTracker} from './menu-trigger-base'; import {eventDispatchesNativeClick} from './event-detection'; /** @@ -86,6 +86,9 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD private readonly _injector = inject(Injector); private _cleanupMouseenter: () => void; + /** The app's menu tracking registry */ + private readonly _menuTracker = inject(MenuTracker); + /** The parent menu this trigger belongs to. */ private readonly _parentMenu = inject(CDK_MENU, {optional: true}); @@ -109,6 +112,9 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD /** Open the attached menu. */ open() { + if (!this._parentMenu) { + this._menuTracker.update(this); + } if (!this.isOpen() && this.menuTemplateRef != null) { this.opened.next();