Skip to content

Commit 63bd6a1

Browse files
committed
fix(cdk/menu): close sibling triggers when opening a menu
Currently, when any sibling menu is opened then it overlaps and in cases it makes the screen unresponsive. This fix will close any sibling menu if its open Fixes #30881
1 parent 357cfd3 commit 63bd6a1

File tree

4 files changed

+40
-31
lines changed

4 files changed

+40
-31
lines changed

Diff for: goldens/cdk/menu/index.api.md

-9
Original file line numberDiff line numberDiff line change
@@ -273,15 +273,6 @@ export type ContextMenuCoordinates = {
273273
y: number;
274274
};
275275

276-
// @public
277-
export class ContextMenuTracker {
278-
update(trigger: CdkContextMenuTrigger): void;
279-
// (undocumented)
280-
static ɵfac: i0.ɵɵFactoryDeclaration<ContextMenuTracker, never>;
281-
// (undocumented)
282-
static ɵprov: i0.ɵɵInjectableDeclaration<ContextMenuTracker>;
283-
}
284-
285276
// @public
286277
export interface FocusableElement {
287278
_elementRef: ElementRef<HTMLElement>;

Diff for: src/cdk/menu/context-menu-trigger.ts

+4-22
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
ChangeDetectorRef,
1212
Directive,
1313
inject,
14-
Injectable,
1514
Input,
1615
OnDestroy,
1716
} from '@angular/core';
@@ -27,6 +26,7 @@ import {merge, partition} from 'rxjs';
2726
import {skip, takeUntil, skipWhile} from 'rxjs/operators';
2827
import {MENU_STACK, MenuStack} from './menu-stack';
2928
import {CdkMenuTriggerBase, MENU_TRIGGER} from './menu-trigger-base';
29+
import {MenuTracker} from './menu-tracker';
3030

3131
/** The preferred menu positions for the context menu. */
3232
const CONTEXT_MENU_POSITIONS = STANDARD_DROPDOWN_BELOW_POSITIONS.map(position => {
@@ -37,24 +37,6 @@ const CONTEXT_MENU_POSITIONS = STANDARD_DROPDOWN_BELOW_POSITIONS.map(position =>
3737
return {...position, offsetX, offsetY};
3838
});
3939

40-
/** Tracks the last open context menu trigger across the entire application. */
41-
@Injectable({providedIn: 'root'})
42-
export class ContextMenuTracker {
43-
/** The last open context menu trigger. */
44-
private static _openContextMenuTrigger?: CdkContextMenuTrigger;
45-
46-
/**
47-
* Close the previous open context menu and set the given one as being open.
48-
* @param trigger The trigger for the currently open Context Menu.
49-
*/
50-
update(trigger: CdkContextMenuTrigger) {
51-
if (ContextMenuTracker._openContextMenuTrigger !== trigger) {
52-
ContextMenuTracker._openContextMenuTrigger?.close();
53-
ContextMenuTracker._openContextMenuTrigger = trigger;
54-
}
55-
}
56-
}
57-
5840
/** The coordinates where the context menu should open. */
5941
export type ContextMenuCoordinates = {x: number; y: number};
6042

@@ -87,8 +69,8 @@ export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestr
8769
/** The directionality of the page. */
8870
private readonly _directionality = inject(Directionality, {optional: true});
8971

90-
/** The app's context menu tracking registry */
91-
private readonly _contextMenuTracker = inject(ContextMenuTracker);
72+
/** The app's menu tracking registry */
73+
private readonly _menuTracker = inject(MenuTracker);
9274

9375
private readonly _changeDetectorRef = inject(ChangeDetectorRef);
9476

@@ -128,7 +110,7 @@ export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestr
128110
// resulting in multiple stacked context menus being displayed.
129111
event.stopPropagation();
130112

131-
this._contextMenuTracker.update(this);
113+
this._menuTracker.update(this);
132114
this._open(event, {x: event.clientX, y: event.clientY});
133115

134116
// A context menu can be triggered via a mouse right click or a keyboard shortcut.

Diff for: src/cdk/menu/menu-tracker.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import {Injectable} from '@angular/core';
10+
import {CdkContextMenuTrigger} from './context-menu-trigger';
11+
import {CdkMenuTrigger} from './menu-trigger';
12+
13+
/** Tracks the last open menu trigger across the entire application. */
14+
@Injectable({providedIn: 'root'})
15+
export class MenuTracker<T extends CdkContextMenuTrigger | CdkMenuTrigger> {
16+
/** The last open menu trigger. */
17+
private static _openMenuTrigger?: CdkContextMenuTrigger | CdkMenuTrigger;
18+
19+
/**
20+
* Close the previous open menu and set the given one as being open.
21+
* @param trigger The trigger for the currently open Menu.
22+
*/
23+
update(trigger: T) {
24+
if (MenuTracker._openMenuTrigger !== trigger) {
25+
MenuTracker._openMenuTrigger?.close();
26+
MenuTracker._openMenuTrigger = trigger;
27+
}
28+
}
29+
}

Diff for: src/cdk/menu/menu-trigger.ts

+7
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {PARENT_OR_NEW_MENU_STACK_PROVIDER} from './menu-stack';
4343
import {MENU_AIM} from './menu-aim';
4444
import {CdkMenuTriggerBase, MENU_TRIGGER} from './menu-trigger-base';
4545
import {eventDispatchesNativeClick} from './event-detection';
46+
import {MenuTracker} from './menu-tracker';
4647

4748
/**
4849
* A directive that turns its host element into a trigger for a popup menu.
@@ -84,6 +85,9 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD
8485
private readonly _renderer = inject(Renderer2);
8586
private _cleanupMouseenter: () => void;
8687

88+
/** The app's menu tracking registry */
89+
private readonly _menuTracker = inject(MenuTracker);
90+
8791
/** The parent menu this trigger belongs to. */
8892
private readonly _parentMenu = inject(CDK_MENU, {optional: true});
8993

@@ -107,6 +111,9 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD
107111

108112
/** Open the attached menu. */
109113
open() {
114+
if (!this._parentMenu) {
115+
this._menuTracker.update(this);
116+
}
110117
if (!this.isOpen() && this.menuTemplateRef != null) {
111118
this.opened.next();
112119

0 commit comments

Comments
 (0)