diff --git a/src/cdk/a11y/list-key-manager.spec.ts b/src/cdk/a11y/list-key-manager.spec.ts index ac0e83a45e91..b6cc2d5e8d5d 100644 --- a/src/cdk/a11y/list-key-manager.spec.ts +++ b/src/cdk/a11y/list-key-manager.spec.ts @@ -491,6 +491,62 @@ describe('Key managers', () => { expect(keyManager.activeItem).toBeFalsy(); })); + it('should start looking for matches after the active item', fakeAsync(() => { + itemList.items = [ + new FakeFocusable('Bilbo'), + new FakeFocusable('Frodo'), + new FakeFocusable('Pippin'), + new FakeFocusable('Boromir'), + new FakeFocusable('Aragorn') + ]; + + keyManager.setActiveItem(1); + keyManager.onKeydown(createKeyboardEvent('keydown', 66, undefined, 'b')); + tick(debounceInterval); + + expect(keyManager.activeItem).toBe(itemList.items[3]); + })); + + it('should wrap back around if there were no matches after the active item', fakeAsync(() => { + itemList.items = [ + new FakeFocusable('Bilbo'), + new FakeFocusable('Frodo'), + new FakeFocusable('Pippin'), + new FakeFocusable('Boromir'), + new FakeFocusable('Aragorn') + ]; + + keyManager.setActiveItem(3); + keyManager.onKeydown(createKeyboardEvent('keydown', 66, undefined, 'b')); + tick(debounceInterval); + + expect(keyManager.activeItem).toBe(itemList.items[0]); + })); + + it('should wrap back around if the last item is active', fakeAsync(() => { + keyManager.setActiveItem(2); + keyManager.onKeydown(createKeyboardEvent('keydown', 79, undefined, 'o')); + tick(debounceInterval); + + expect(keyManager.activeItem).toBe(itemList.items[0]); + })); + + it('should be able to select the first item', fakeAsync(() => { + keyManager.setActiveItem(-1); + keyManager.onKeydown(createKeyboardEvent('keydown', 79, undefined, 'o')); + tick(debounceInterval); + + expect(keyManager.activeItem).toBe(itemList.items[0]); + })); + + it('should not do anything if there is no match', fakeAsync(() => { + keyManager.setActiveItem(1); + keyManager.onKeydown(createKeyboardEvent('keydown', 87, undefined, 'w')); + tick(debounceInterval); + + expect(keyManager.activeItem).toBe(itemList.items[1]); + })); + }); }); diff --git a/src/cdk/a11y/list-key-manager.ts b/src/cdk/a11y/list-key-manager.ts index c3a3def7175e..6268194925eb 100644 --- a/src/cdk/a11y/list-key-manager.ts +++ b/src/cdk/a11y/list-key-manager.ts @@ -73,11 +73,14 @@ export class ListKeyManager { .subscribe(inputString => { const items = this._items.toArray(); - for (let i = 0; i < items.length; i++) { - let item = items[i]; + // Start at 1 because we want to start searching at the item immediately + // following the current active item. + for (let i = 1; i < items.length + 1; i++) { + const index = (this._activeItemIndex + i) % items.length; + const item = items[index]; if (!item.disabled && item.getLabel!().toUpperCase().trim().indexOf(inputString) === 0) { - this.setActiveItem(i); + this.setActiveItem(index); break; } }