mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(menu): allow focus restoration to be disabled (#15205)
Allows for focus restoration to be disabled in a menu, similarly to some other components. In some cases restoring focus automatically might not make sense (e.g. if the user closes the menu by selecting something which then opens a dialog) and this allows consumers to customize the behavior as needed. Fixes #15168.
This commit is contained in:
committed by
Jeremy Elbourn
parent
413fe33c73
commit
dfa40fc7fb
@@ -137,6 +137,13 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
|
||||
/** Data to be passed along to any lazily-rendered content. */
|
||||
@Input('matMenuTriggerData') menuData: any;
|
||||
|
||||
/**
|
||||
* Whether focus should be restored when the menu is closed.
|
||||
* Note that disabling this option can have accessibility implications
|
||||
* and it's up to you to manage focus, if you decide to turn it off.
|
||||
*/
|
||||
@Input('matMenuTriggerRestoreFocus') restoreFocus: boolean = true;
|
||||
|
||||
/** Event emitted when the associated menu is opened. */
|
||||
@Output() readonly menuOpened: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
@@ -339,12 +346,14 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy {
|
||||
// We should reset focus if the user is navigating using a keyboard or
|
||||
// if we have a top-level trigger which might cause focus to be lost
|
||||
// when clicking on the backdrop.
|
||||
if (!this._openedBy) {
|
||||
// Note that the focus style will show up both for `program` and
|
||||
// `keyboard` so we don't have to specify which one it is.
|
||||
this.focus();
|
||||
} else if (!this.triggersSubmenu()) {
|
||||
this.focus(this._openedBy);
|
||||
if (this.restoreFocus) {
|
||||
if (!this._openedBy) {
|
||||
// Note that the focus style will show up both for `program` and
|
||||
// `keyboard` so we don't have to specify which one it is.
|
||||
this.focus();
|
||||
} else if (!this.triggersSubmenu()) {
|
||||
this.focus(this._openedBy);
|
||||
}
|
||||
}
|
||||
|
||||
this._openedBy = null;
|
||||
|
||||
@@ -159,6 +159,27 @@ describe('MatMenu', () => {
|
||||
expect(document.activeElement).toBe(triggerEl);
|
||||
}));
|
||||
|
||||
it('should not restore focus to the trigger if focus restoration is disabled', fakeAsync(() => {
|
||||
const fixture = createComponent(SimpleMenu, [], [FakeIcon]);
|
||||
fixture.detectChanges();
|
||||
const triggerEl = fixture.componentInstance.triggerEl.nativeElement;
|
||||
|
||||
fixture.componentInstance.restoreFocus = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
// A click without a mousedown before it is considered a keyboard open.
|
||||
triggerEl.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(overlayContainerElement.querySelector('.mat-menu-panel')).toBeTruthy();
|
||||
|
||||
fixture.componentInstance.trigger.closeMenu();
|
||||
fixture.detectChanges();
|
||||
tick(500);
|
||||
|
||||
expect(document.activeElement).not.toBe(triggerEl);
|
||||
}));
|
||||
|
||||
it('should be able to set a custom class on the backdrop', fakeAsync(() => {
|
||||
const fixture = createComponent(SimpleMenu, [], [FakeIcon]);
|
||||
|
||||
@@ -1976,7 +1997,10 @@ describe('MatMenu default overrides', () => {
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<button [matMenuTriggerFor]="menu" #triggerEl>Toggle menu</button>
|
||||
<button
|
||||
[matMenuTriggerFor]="menu"
|
||||
[matMenuTriggerRestoreFocus]="restoreFocus"
|
||||
#triggerEl>Toggle menu</button>
|
||||
<mat-menu
|
||||
#menu="matMenu"
|
||||
[class]="panelClass"
|
||||
@@ -2002,6 +2026,7 @@ class SimpleMenu {
|
||||
closeCallback = jasmine.createSpy('menu closed callback');
|
||||
backdropClass: string;
|
||||
panelClass: string;
|
||||
restoreFocus = true;
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
||||
Vendored
+1
@@ -112,6 +112,7 @@ export declare class MatMenuTrigger implements AfterContentInit, OnDestroy {
|
||||
readonly menuOpened: EventEmitter<void>;
|
||||
readonly onMenuClose: EventEmitter<void>;
|
||||
readonly onMenuOpen: EventEmitter<void>;
|
||||
restoreFocus: boolean;
|
||||
constructor(_overlay: Overlay, _element: ElementRef<HTMLElement>, _viewContainerRef: ViewContainerRef, scrollStrategy: any, _parentMenu: MatMenu, _menuItemInstance: MatMenuItem, _dir: Directionality, _focusMonitor?: FocusMonitor | undefined);
|
||||
_handleClick(event: MouseEvent): void;
|
||||
_handleKeydown(event: KeyboardEvent): void;
|
||||
|
||||
Reference in New Issue
Block a user