From 87db138faf8942da3c159485cc7bbb34cc77a107 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Wed, 9 May 2018 00:21:22 +0200 Subject: [PATCH] fix(stepper): handle keyboard interactions if direction changes after init Currently the stepper checks for its direction once on init, in order to configure its keyboard control direction, however this doesn't account for the cases where the direction changes dynamically afterwards. These changes ensure that the keyboard controls are correct in case the layout direction changes. --- src/cdk/stepper/stepper.ts | 8 ++++++-- src/lib/stepper/stepper.spec.ts | 31 ++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/cdk/stepper/stepper.ts b/src/cdk/stepper/stepper.ts index b09d4a87e5c4..b39a270ba335 100644 --- a/src/cdk/stepper/stepper.ts +++ b/src/cdk/stepper/stepper.ts @@ -33,7 +33,8 @@ import { } from '@angular/core'; import {AbstractControl} from '@angular/forms'; import {CdkStepLabel} from './step-label'; -import {Subject} from 'rxjs'; +import {Observable, Subject, of as obaservableOf} from 'rxjs'; +import {startWith, takeUntil} from 'rxjs/operators'; /** Used to generate unique ID for each stepper component. */ let nextId = 0; @@ -212,9 +213,12 @@ export class CdkStepper implements AfterViewInit, OnDestroy { ngAfterViewInit() { this._keyManager = new FocusKeyManager(this._stepHeader) .withWrap() - .withHorizontalOrientation(this._layoutDirection()) .withVerticalOrientation(this._orientation === 'vertical'); + (this._dir ? this._dir.change as Observable : obaservableOf()) + .pipe(startWith(this._layoutDirection()), takeUntil(this._destroyed)) + .subscribe(direction => this._keyManager.withHorizontalOrientation(direction)); + this._keyManager.updateActiveItemIndex(this._selectedIndex); } diff --git a/src/lib/stepper/stepper.spec.ts b/src/lib/stepper/stepper.spec.ts index 8b63658ec162..72b8bff708dd 100644 --- a/src/lib/stepper/stepper.spec.ts +++ b/src/lib/stepper/stepper.spec.ts @@ -11,7 +11,7 @@ import { } from '@angular/cdk/keycodes'; import {StepperOrientation} from '@angular/cdk/stepper'; import {dispatchKeyboardEvent} from '@angular/cdk/testing'; -import {Component, DebugElement} from '@angular/core'; +import {Component, DebugElement, EventEmitter} from '@angular/core'; import {async, ComponentFixture, inject, TestBed, fakeAsync, flush} from '@angular/core/testing'; import { AbstractControl, @@ -35,10 +35,13 @@ import {MatStepperIntl} from './stepper-intl'; const VALID_REGEX = /valid/; describe('MatStepper', () => { - let dir: Direction; + let dir: {value: Direction, change: EventEmitter}; beforeEach(async(() => { - dir = 'ltr'; + dir = { + value: 'ltr', + change: new EventEmitter() + }; TestBed.configureTestingModule({ imports: [MatStepperModule, NoopAnimationsModule, ReactiveFormsModule], @@ -53,7 +56,7 @@ describe('MatStepper', () => { LinearStepperWithValidOptionalStep, ], providers: [ - {provide: Directionality, useFactory: () => ({value: dir})} + {provide: Directionality, useFactory: () => dir} ] }); @@ -388,7 +391,7 @@ describe('MatStepper', () => { let fixture: ComponentFixture; beforeEach(() => { - dir = 'rtl'; + dir.value = 'rtl'; fixture = TestBed.createComponent(SimpleMatVerticalStepperApp); fixture.detectChanges(); }); @@ -717,7 +720,7 @@ describe('MatStepper', () => { }); it('should reverse arrow key focus in RTL mode', () => { - dir = 'rtl'; + dir.value = 'rtl'; let fixture = TestBed.createComponent(SimpleMatVerticalStepperApp); fixture.detectChanges(); @@ -744,13 +747,27 @@ describe('MatStepper', () => { }); it('should reverse arrow key focus in RTL mode', () => { - dir = 'rtl'; + dir.value = 'rtl'; let fixture = TestBed.createComponent(SimpleMatHorizontalStepperApp); fixture.detectChanges(); let stepHeaders = fixture.debugElement.queryAll(By.css('.mat-horizontal-stepper-header')); assertArrowKeyInteractionInRtl(fixture, stepHeaders); }); + + it('should reverse arrow key focus when switching into RTL after init', () => { + let fixture = TestBed.createComponent(SimpleMatHorizontalStepperApp); + fixture.detectChanges(); + + let stepHeaders = fixture.debugElement.queryAll(By.css('.mat-horizontal-stepper-header')); + assertCorrectKeyboardInteraction(fixture, stepHeaders, 'horizontal'); + + dir.value = 'rtl'; + dir.change.emit('rtl'); + fixture.detectChanges(); + + assertArrowKeyInteractionInRtl(fixture, stepHeaders); + }); }); describe('valid step in linear stepper', () => {