From 9f42b2a44be9501b37eb75a031b71a4bed61805f Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sat, 1 Apr 2023 06:59:42 +0200 Subject: [PATCH] fix(cdk/menu): move focus when opening via click Fixes that the CDK menu wasn't moving focus to the first item when opening using a click. This caused other issues like not being able to use the escape key to close the menu. Fixes #26858. --- src/cdk/menu/menu-bar.spec.ts | 4 ++-- src/cdk/menu/menu-trigger.spec.ts | 25 ++++++++++++++++++++++++- src/cdk/menu/menu-trigger.ts | 1 + src/cdk/menu/menu.spec.ts | 3 +++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/cdk/menu/menu-bar.spec.ts b/src/cdk/menu/menu-bar.spec.ts index 631616860ce2..a8c1f960d247 100644 --- a/src/cdk/menu/menu-bar.spec.ts +++ b/src/cdk/menu/menu-bar.spec.ts @@ -1037,11 +1037,11 @@ describe('MenuBar', () => { dispatchKeyboardEvent(nativeMenus[0], 'keydown', DOWN_ARROW); detectChanges(); - expect(document.activeElement).toEqual(fileMenuNativeItems[0]); + expect(document.activeElement).toEqual(fileMenuNativeItems[1]); dispatchKeyboardEvent(nativeMenus[0], 'keydown', DOWN_ARROW); detectChanges(); - expect(document.activeElement).toEqual(fileMenuNativeItems[1]); + expect(document.activeElement).toEqual(fileMenuNativeItems[2]); }); it( diff --git a/src/cdk/menu/menu-trigger.spec.ts b/src/cdk/menu/menu-trigger.spec.ts index e2959c3391b0..547b3c458826 100644 --- a/src/cdk/menu/menu-trigger.spec.ts +++ b/src/cdk/menu/menu-trigger.spec.ts @@ -1,5 +1,5 @@ import {Component, ViewChildren, QueryList, ElementRef, ViewChild, Type} from '@angular/core'; -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {ComponentFixture, TestBed, fakeAsync, tick, waitForAsync} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {dispatchKeyboardEvent} from '../../cdk/testing/private'; import {TAB, SPACE, ENTER} from '@angular/cdk/keycodes'; @@ -539,6 +539,26 @@ describe('MenuTrigger', () => { expect(fixture.componentInstance.trigger.isOpen()).toBeFalse(); }); }); + + it('should focus the first item when opening on click', fakeAsync(() => { + TestBed.configureTestingModule({ + imports: [CdkMenuModule], + declarations: [TriggersWithSameMenuDifferentMenuBars], + }).compileComponents(); + + const fixture = TestBed.createComponent(TriggersWithSameMenuDifferentMenuBars); + fixture.detectChanges(); + + fixture.componentInstance.nativeTriggers.first.nativeElement.click(); + fixture.detectChanges(); + tick(); + + const firstItem = + fixture.componentInstance.nativeMenus.first.nativeElement.querySelector('.cdk-menu-item'); + + expect(firstItem).toBeTruthy(); + expect(document.activeElement).toBe(firstItem); + })); }); @Component({ @@ -599,7 +619,10 @@ class MenuBarWithNestedSubMenus { }) class TriggersWithSameMenuDifferentMenuBars { @ViewChildren(CdkMenuTrigger) triggers: QueryList; + @ViewChildren(CdkMenuTrigger, {read: ElementRef}) nativeTriggers: QueryList; + @ViewChildren(CdkMenu) menus: QueryList; + @ViewChildren(CdkMenu, {read: ElementRef}) nativeMenus: QueryList; } @Component({ diff --git a/src/cdk/menu/menu-trigger.ts b/src/cdk/menu/menu-trigger.ts index c4fdade15994..481e8d7b0fea 100644 --- a/src/cdk/menu/menu-trigger.ts +++ b/src/cdk/menu/menu-trigger.ts @@ -177,6 +177,7 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnDestroy { // already do the same on `keydown` events for enter and space. if (this._inputModalityDetector.mostRecentModality !== 'keyboard') { this.toggle(); + this.childMenu?.focusFirstItem('mouse'); } } diff --git a/src/cdk/menu/menu.spec.ts b/src/cdk/menu/menu.spec.ts index cafe52294923..3399f81edda8 100644 --- a/src/cdk/menu/menu.spec.ts +++ b/src/cdk/menu/menu.spec.ts @@ -447,6 +447,7 @@ describe('Menu', () => { it('should close the edit menu when hovering directly up from the edit menu trigger to the print item without waiting', fakeAsync(() => { openFileMenu(); openMenuOnHover(nativeEditTrigger!); + tick(); const editPosition = nativeEditTrigger!.getBoundingClientRect(); const printPosition = nativeFileButtons![0].getBoundingClientRect(); @@ -490,6 +491,8 @@ describe('Menu', () => { it('should not close the edit submenu when hovering into its items in time', fakeAsync(() => { openFileMenu(); openMenuOnHover(nativeEditTrigger!); + tick(); + const editPosition = nativeEditTrigger!.getBoundingClientRect(); const undoPosition = nativeEditButtons![0].getBoundingClientRect();