Skip to content

Commit

Permalink
fix(material/menu): not interrupting keyboard events to other overlays (
Browse files Browse the repository at this point in the history
angular#22856)

For historical reasons, `mat-menu` doesn't use the same keyboard event dispatcher as the other overlays. To work around it, previously we added a dummy subscription so that the menu would still show up in the overlay keyboard stack.

This works for most events, but it breaks down for the escape key, because closing the menu removes it from the stack immediately, allowing the event to bubble up to the document and be dispatched to the next overlay in the stack.

These changes resolve the issue by adding a `stopPropagation` call.

Fixes angular#22694.
  • Loading branch information
crisbeto committed Jun 7, 2021
1 parent d185294 commit aeecb3c
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/material-experimental/mdc-menu/menu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,12 +437,14 @@ describe('MDC-based MatMenu', () => {
const panel = overlayContainerElement.querySelector('.mat-mdc-menu-panel')!;
const event = createKeyboardEvent('keydown', ESCAPE);

spyOn(event, 'stopPropagation').and.callThrough();
dispatchEvent(panel, event);
fixture.detectChanges();
tick(500);

expect(overlayContainerElement.textContent).toBe('');
expect(event.defaultPrevented).toBe(true);
expect(event.stopPropagation).toHaveBeenCalled();
}));

it('should not close the menu when pressing ESCAPE with a modifier', fakeAsync(() => {
Expand Down
2 changes: 2 additions & 0 deletions src/material/menu/menu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -436,13 +436,15 @@ describe('MatMenu', () => {

const panel = overlayContainerElement.querySelector('.mat-menu-panel')!;
const event = createKeyboardEvent('keydown', ESCAPE);
spyOn(event, 'stopPropagation').and.callThrough();

dispatchEvent(panel, event);
fixture.detectChanges();
tick(500);

expect(overlayContainerElement.textContent).toBe('');
expect(event.defaultPrevented).toBe(true);
expect(event.stopPropagation).toHaveBeenCalled();
}));

it('should not close the menu when pressing ESCAPE with a modifier', fakeAsync(() => {
Expand Down
5 changes: 5 additions & 0 deletions src/material/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,12 @@ export class _MatMenuBase implements AfterContentInit, MatMenuPanel<MatMenuItem>
}

manager.onKeydown(event);
return;
}

// Don't allow the event to propagate if we've already handled it, or it may
// end up reaching other overlays that were opened earlier (see #22694).
event.stopPropagation();
}

/**
Expand Down

0 comments on commit aeecb3c

Please sign in to comment.