diff --git a/src/material/menu/menu-item.ts b/src/material/menu/menu-item.ts index ca7215b67981..79df14589031 100644 --- a/src/material/menu/menu-item.ts +++ b/src/material/menu/menu-item.ts @@ -94,8 +94,8 @@ export class MatMenuItem extends _MatMenuItemMixinBase } /** Focuses the menu item. */ - focus(origin: FocusOrigin = 'program', options?: FocusOptions): void { - if (this._focusMonitor) { + focus(origin?: FocusOrigin, options?: FocusOptions): void { + if (this._focusMonitor && origin) { this._focusMonitor.focusVia(this._getHostElement(), origin, options); } else { this._getHostElement().focus(options); diff --git a/src/material/menu/menu-trigger.ts b/src/material/menu/menu-trigger.ts index 1292765a7981..06de01f4fb1d 100644 --- a/src/material/menu/menu-trigger.ts +++ b/src/material/menu/menu-trigger.ts @@ -275,8 +275,8 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { * Focuses the menu trigger. * @param origin Source of the menu trigger's focus. */ - focus(origin: FocusOrigin = 'program', options?: FocusOptions) { - if (this._focusMonitor) { + focus(origin?: FocusOrigin, options?: FocusOptions) { + if (this._focusMonitor && origin) { this._focusMonitor.focusVia(this._element, origin, options); } else { this._element.nativeElement.focus(options); diff --git a/src/material/menu/menu.spec.ts b/src/material/menu/menu.spec.ts index 283e722ba2fa..17427f83cc18 100644 --- a/src/material/menu/menu.spec.ts +++ b/src/material/menu/menu.spec.ts @@ -615,6 +615,25 @@ describe('MatMenu', () => { expect(items.every(item => item.getAttribute('role') === 'menuitemcheckbox')).toBe(true); }); + it('should not change focus origin if origin not specified for menu items', () => { + const fixture = createComponent(MenuWithCheckboxItems); + fixture.detectChanges(); + fixture.componentInstance.trigger.openMenu(); + fixture.detectChanges(); + + let [firstMenuItemDebugEl, secondMenuItemDebugEl] = + fixture.debugElement.queryAll(By.css('.mat-menu-item'))!; + + const firstMenuItemInstance = firstMenuItemDebugEl.componentInstance as MatMenuItem; + const secondMenuItemInstance = secondMenuItemDebugEl.componentInstance as MatMenuItem; + + firstMenuItemInstance.focus('mouse'); + secondMenuItemInstance.focus(); + + expect(secondMenuItemDebugEl.nativeElement.classList).toContain('cdk-focused'); + expect(secondMenuItemDebugEl.nativeElement.classList).toContain('cdk-mouse-focused'); + }); + it('should not throw an error on destroy', () => { const fixture = createComponent(SimpleMenu, [], [FakeIcon]); expect(fixture.destroy.bind(fixture)).not.toThrow(); @@ -2006,6 +2025,24 @@ describe('MatMenu', () => { .toContain('mat-elevation-z4', 'Expected menu to have the proper updated elevation.'); })); + it('should not change focus origin if origin not specified for menu trigger', + fakeAsync(() => { + compileTestComponent(); + + instance.levelOneTrigger.openMenu(); + instance.levelOneTrigger.focus('mouse'); + fixture.detectChanges(); + + instance.levelTwoTrigger.focus(); + fixture.detectChanges(); + tick(500); + + const levelTwoTrigger = overlay.querySelector('#level-two-trigger')! as HTMLElement; + + expect(levelTwoTrigger.classList).toContain('cdk-focused'); + expect(levelTwoTrigger.classList).toContain('cdk-mouse-focused'); + })); + it('should not increase the elevation if the user specified a custom one', () => { const elevationFixture = createComponent(NestedMenuCustomElevation);