From 4643139d444fec1908275be71db8ffc43a10fa82 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: 2020年10月17日 17:56:00 +0200 Subject: [PATCH] fix(cdk/a11y): clear active item in key manager if it is removed from the list The active item in the `ListKeyManager` gets updated on keyboard events, but if the list changes between them, we may end up in a state where it's pointing to an item that's not in the DOM anymore. This can cause something like `aria-activedescendant` to point to an invalid element. These changes add some logic that clear the active element if it's removed from the list and there's nothing at its new index. --- .../a11y/key-manager/list-key-manager.spec.ts | 36 +++++++++++++++++++ src/cdk/a11y/key-manager/list-key-manager.ts | 6 ++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/cdk/a11y/key-manager/list-key-manager.spec.ts b/src/cdk/a11y/key-manager/list-key-manager.spec.ts index fdbcd65d4dec..439344abe4b4 100644 --- a/src/cdk/a11y/key-manager/list-key-manager.spec.ts +++ b/src/cdk/a11y/key-manager/list-key-manager.spec.ts @@ -93,6 +93,42 @@ describe('Key managers', () => { expect(keyManager.activeItem!.getLabel()).toBe('one'); }); + it('should update the active item if the current one is removed and there is ' + + 'a new one at the same index', () => { + expect(keyManager.activeItemIndex).toBe(0); + expect(keyManager.activeItem!.getLabel()).toBe('one'); + + itemList.reset([new FakeFocusable('new-0'), new FakeFocusable('new-1')]); + itemList.notifyOnChanges(); + + expect(keyManager.activeItemIndex).toBe(0); + expect(keyManager.activeItem!.getLabel()).toBe('new-0'); + }); + + it('should clear the active item if nothing exists at the new index', () => { + keyManager.setActiveItem(2); + + expect(keyManager.activeItemIndex).toBe(2); + expect(keyManager.activeItem!.getLabel()).toBe('three'); + + itemList.reset(itemList.toArray().slice(0, 1)); + itemList.notifyOnChanges(); + + expect(keyManager.activeItemIndex).toBe(-1); + expect(keyManager.activeItem).toBe(null); + }); + + it('should clear the active item if the list is cleared', () => { + expect(keyManager.activeItemIndex).toBe(0); + expect(keyManager.activeItem!.getLabel()).toBe('one'); + + itemList.reset([]); + itemList.notifyOnChanges(); + + expect(keyManager.activeItemIndex).toBe(-1); + expect(keyManager.activeItem).toBe(null); + }); + it('should start off the activeItem as null', () => { expect(new ListKeyManager([]).activeItem).toBeNull(); }); diff --git a/src/cdk/a11y/key-manager/list-key-manager.ts b/src/cdk/a11y/key-manager/list-key-manager.ts index fcd27e27c7e0..afeaa42e8825 100644 --- a/src/cdk/a11y/key-manager/list-key-manager.ts +++ b/src/cdk/a11y/key-manager/list-key-manager.ts @@ -70,7 +70,9 @@ export class ListKeyManager { const itemArray = newItems.toArray(); const newIndex = itemArray.indexOf(this._activeItem); - if (newIndex> -1 && newIndex !== this._activeItemIndex) { + if (newIndex === -1) { + this.updateActiveItem(this._activeItemIndex); + } else if (newIndex !== this._activeItemIndex) { this._activeItemIndex = newIndex; } } @@ -349,7 +351,7 @@ export class ListKeyManager { // Explicitly check for `null` and `undefined` because other falsy values are valid. this._activeItem = activeItem == null ? null : activeItem; - this._activeItemIndex = index; + this._activeItemIndex = activeItem == null ? -1 : index; } /**

AltStyle によって変換されたページ (->オリジナル) /