Skip to content

Commit dbcb921

Browse files
committedNov 14, 2024·
fix(material/menu): handle keyboard events through dispatcher (#29997)
Currently `mat-menu` handles it keyboard events in the template, however this ignores the overlay's stacking context which can capture some events that it shouldn't. These changes switch the menu to handling the events through the common dispatcher instead. Fixes #29996. (cherry picked from commit 42f6a4a)
1 parent 5345a87 commit dbcb921

File tree

5 files changed

+7
-16
lines changed

5 files changed

+7
-16
lines changed
 

Diff for: ‎src/material/menu/menu-trigger.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -412,11 +412,11 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
412412
config.positionStrategy as FlexibleConnectedPositionStrategy,
413413
);
414414
this._overlayRef = this._overlay.create(config);
415-
416-
// Consume the `keydownEvents` in order to prevent them from going to another overlay.
417-
// Ideally we'd also have our keyboard event logic in here, however doing so will
418-
// break anybody that may have implemented the `MatMenuPanel` themselves.
419-
this._overlayRef.keydownEvents().subscribe();
415+
this._overlayRef.keydownEvents().subscribe(event => {
416+
if (this.menu instanceof MatMenu) {
417+
this.menu._handleKeydown(event);
418+
}
419+
});
420420
}
421421

422422
return this._overlayRef;

Diff for: ‎src/material/menu/menu.html

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
class="mat-mdc-menu-panel"
44
[id]="panelId"
55
[class]="_classList"
6-
(keydown)="_handleKeydown($event)"
76
(click)="closed.emit('click')"
87
[@transformMenu]="_panelAnimationState"
98
(@transformMenu.start)="_onAnimationStart($event)"

Diff for: ‎src/material/menu/menu.spec.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -473,16 +473,13 @@ describe('MatMenu', () => {
473473
fixture.componentInstance.trigger.openMenu();
474474

475475
const panel = overlayContainerElement.querySelector('.mat-mdc-menu-panel')!;
476-
const event = createKeyboardEvent('keydown', ESCAPE);
477-
spyOn(event, 'stopPropagation').and.callThrough();
476+
const event = dispatchKeyboardEvent(panel, 'keydown', ESCAPE);
478477

479-
dispatchEvent(panel, event);
480478
fixture.detectChanges();
481479
tick(500);
482480

483481
expect(overlayContainerElement.textContent).toBe('');
484482
expect(event.defaultPrevented).toBe(true);
485-
expect(event.stopPropagation).toHaveBeenCalled();
486483
}));
487484

488485
it('should not close the menu when pressing ESCAPE with a modifier', fakeAsync(() => {

Diff for: ‎src/material/menu/menu.ts

-4
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,6 @@ export class MatMenu implements AfterContentInit, MatMenuPanel<MatMenuItem>, OnI
385385
manager.onKeydown(event);
386386
return;
387387
}
388-
389-
// Don't allow the event to propagate if we've already handled it, or it may
390-
// end up reaching other overlays that were opened earlier (see #22694).
391-
event.stopPropagation();
392388
}
393389

394390
/**

Diff for: ‎src/material/menu/testing/menu-harness.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
HarnessLoader,
1313
HarnessPredicate,
1414
TestElement,
15-
TestKey,
1615
} from '@angular/cdk/testing';
1716
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1817
import {MenuHarnessFilters, MenuItemHarnessFilters} from './menu-harness-filters';
@@ -82,7 +81,7 @@ export class MatMenuHarness extends ContentContainerComponentHarness<string> {
8281
async close(): Promise<void> {
8382
const panel = await this._getMenuPanel();
8483
if (panel) {
85-
return panel.sendKeys(TestKey.ESCAPE);
84+
return panel.click();
8685
}
8786
}
8887

0 commit comments

Comments
 (0)
Please sign in to comment.