Skip to content

Commit 846cc13

Browse files
crisbetokara
authored andcommitted
fix(list-key-manager): align matching logic with native listbox (#7212)
1 parent 7714a5c commit 846cc13

File tree

2 files changed

+62
-3
lines changed

2 files changed

+62
-3
lines changed

src/cdk/a11y/list-key-manager.spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,62 @@ describe('Key managers', () => {
491491
expect(keyManager.activeItem).toBeFalsy();
492492
}));
493493

494+
it('should start looking for matches after the active item', fakeAsync(() => {
495+
itemList.items = [
496+
new FakeFocusable('Bilbo'),
497+
new FakeFocusable('Frodo'),
498+
new FakeFocusable('Pippin'),
499+
new FakeFocusable('Boromir'),
500+
new FakeFocusable('Aragorn')
501+
];
502+
503+
keyManager.setActiveItem(1);
504+
keyManager.onKeydown(createKeyboardEvent('keydown', 66, undefined, 'b'));
505+
tick(debounceInterval);
506+
507+
expect(keyManager.activeItem).toBe(itemList.items[3]);
508+
}));
509+
510+
it('should wrap back around if there were no matches after the active item', fakeAsync(() => {
511+
itemList.items = [
512+
new FakeFocusable('Bilbo'),
513+
new FakeFocusable('Frodo'),
514+
new FakeFocusable('Pippin'),
515+
new FakeFocusable('Boromir'),
516+
new FakeFocusable('Aragorn')
517+
];
518+
519+
keyManager.setActiveItem(3);
520+
keyManager.onKeydown(createKeyboardEvent('keydown', 66, undefined, 'b'));
521+
tick(debounceInterval);
522+
523+
expect(keyManager.activeItem).toBe(itemList.items[0]);
524+
}));
525+
526+
it('should wrap back around if the last item is active', fakeAsync(() => {
527+
keyManager.setActiveItem(2);
528+
keyManager.onKeydown(createKeyboardEvent('keydown', 79, undefined, 'o'));
529+
tick(debounceInterval);
530+
531+
expect(keyManager.activeItem).toBe(itemList.items[0]);
532+
}));
533+
534+
it('should be able to select the first item', fakeAsync(() => {
535+
keyManager.setActiveItem(-1);
536+
keyManager.onKeydown(createKeyboardEvent('keydown', 79, undefined, 'o'));
537+
tick(debounceInterval);
538+
539+
expect(keyManager.activeItem).toBe(itemList.items[0]);
540+
}));
541+
542+
it('should not do anything if there is no match', fakeAsync(() => {
543+
keyManager.setActiveItem(1);
544+
keyManager.onKeydown(createKeyboardEvent('keydown', 87, undefined, 'w'));
545+
tick(debounceInterval);
546+
547+
expect(keyManager.activeItem).toBe(itemList.items[1]);
548+
}));
549+
494550
});
495551

496552
});

src/cdk/a11y/list-key-manager.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,14 @@ export class ListKeyManager<T extends ListKeyManagerOption> {
7373
.subscribe(inputString => {
7474
const items = this._items.toArray();
7575

76-
for (let i = 0; i < items.length; i++) {
77-
let item = items[i];
76+
// Start at 1 because we want to start searching at the item immediately
77+
// following the current active item.
78+
for (let i = 1; i < items.length + 1; i++) {
79+
const index = (this._activeItemIndex + i) % items.length;
80+
const item = items[index];
7881

7982
if (!item.disabled && item.getLabel!().toUpperCase().trim().indexOf(inputString) === 0) {
80-
this.setActiveItem(i);
83+
this.setActiveItem(index);
8184
break;
8285
}
8386
}

0 commit comments

Comments
 (0)