diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts index 490ba33ac4fc..a932b10da025 100644 --- a/src/lib/select/select.spec.ts +++ b/src/lib/select/select.spec.ts @@ -403,6 +403,68 @@ describe('MatSelect', () => { .toBe(false, 'Expected panel to stay closed.'); })); + it('should toggle the next option when pressing shift + DOWN_ARROW on a multi-select', + fakeAsync(() => { + fixture.destroy(); + + const multiFixture = TestBed.createComponent(MultiSelect); + const event = createKeyboardEvent('keydown', DOWN_ARROW); + Object.defineProperty(event, 'shiftKey', {get: () => true}); + + multiFixture.detectChanges(); + select = multiFixture.debugElement.query(By.css('mat-select')).nativeElement; + + multiFixture.componentInstance.select.open(); + multiFixture.detectChanges(); + flush(); + + expect(multiFixture.componentInstance.select.value).toBeFalsy(); + + dispatchEvent(select, event); + multiFixture.detectChanges(); + + expect(multiFixture.componentInstance.select.value).toEqual(['pizza-1']); + + dispatchEvent(select, event); + multiFixture.detectChanges(); + + expect(multiFixture.componentInstance.select.value).toEqual(['pizza-1', 'tacos-2']); + })); + + it('should toggle the previous option when pressing shift + UP_ARROW on a multi-select', + fakeAsync(() => { + fixture.destroy(); + + const multiFixture = TestBed.createComponent(MultiSelect); + const event = createKeyboardEvent('keydown', UP_ARROW); + Object.defineProperty(event, 'shiftKey', {get: () => true}); + + multiFixture.detectChanges(); + select = multiFixture.debugElement.query(By.css('mat-select')).nativeElement; + + multiFixture.componentInstance.select.open(); + multiFixture.detectChanges(); + flush(); + + // Move focus down first. + for (let i = 0; i < 5; i++) { + dispatchKeyboardEvent(select, 'keydown', DOWN_ARROW); + multiFixture.detectChanges(); + } + + expect(multiFixture.componentInstance.select.value).toBeFalsy(); + + dispatchEvent(select, event); + multiFixture.detectChanges(); + + expect(multiFixture.componentInstance.select.value).toEqual(['chips-4']); + + dispatchEvent(select, event); + multiFixture.detectChanges(); + + expect(multiFixture.componentInstance.select.value).toEqual(['sandwich-3', 'chips-4']); + })); + it('should prevent the default action when pressing space', fakeAsync(() => { const event = dispatchKeyboardEvent(select, 'keydown', SPACE); expect(event.defaultPrevented).toBe(true); diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts index 0cee44c76514..b2d73ab3de77 100644 --- a/src/lib/select/select.ts +++ b/src/lib/select/select.ts @@ -662,7 +662,15 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, event.preventDefault(); this._keyManager.activeItem._selectViaInteraction(); } else { + const isArrowKey = keyCode === DOWN_ARROW || keyCode === UP_ARROW; + const previouslyFocusedIndex = this._keyManager.activeItemIndex; + this._keyManager.onKeydown(event); + + if (this._multiple && isArrowKey && event.shiftKey && this._keyManager.activeItem && + this._keyManager.activeItemIndex !== previouslyFocusedIndex) { + this._keyManager.activeItem._selectViaInteraction(); + } } }