From 6980649c132a895416101089ac0dd643c25e73cd Mon Sep 17 00:00:00 2001 From: crisbeto Date: Wed, 24 Jul 2019 21:45:40 +0200 Subject: [PATCH] fix(sidenav): focus trap enabled state not updated if mode changes while open Currently we update the focus trap enabled state only on open/close, however this means that it'll be incorrect if the sidenav mode changes while it's open. Fixes #16601. --- src/material/sidenav/drawer.spec.ts | 21 +++++++++++++++++++++ src/material/sidenav/drawer.ts | 14 ++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/material/sidenav/drawer.spec.ts b/src/material/sidenav/drawer.spec.ts index 1ddb8e0bb500..84ee1a9b7f37 100644 --- a/src/material/sidenav/drawer.spec.ts +++ b/src/material/sidenav/drawer.spec.ts @@ -515,6 +515,27 @@ describe('MatDrawer', () => { expect(document.activeElement).not.toBe(firstFocusableElement); })); + it('should update the focus trap enable state if the mode changes while open', fakeAsync(() => { + testComponent.mode = 'side'; + fixture.detectChanges(); + + drawer.open(); + fixture.detectChanges(); + tick(); + + const anchors = + Array.from(fixture.nativeElement.querySelectorAll('.cdk-focus-trap-anchor')); + + expect(anchors.every(anchor => !anchor.hasAttribute('tabindex'))) + .toBe(true, 'Expected focus trap anchors to be disabled in side mode.'); + + testComponent.mode = 'over'; + fixture.detectChanges(); + + expect(anchors.every(anchor => anchor.getAttribute('tabindex') === '0')) + .toBe(true, 'Expected focus trap anchors to be enabled in over mode.'); + })); + }); }); diff --git a/src/material/sidenav/drawer.ts b/src/material/sidenav/drawer.ts index a3d28c8d6206..6f2e15363773 100644 --- a/src/material/sidenav/drawer.ts +++ b/src/material/sidenav/drawer.ts @@ -153,6 +153,7 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr get mode(): 'over' | 'push' | 'side' { return this._mode; } set mode(value: 'over' | 'push' | 'side') { this._mode = value; + this._updateFocusTrapState(); this._modeChanged.next(); } private _mode: 'over' | 'push' | 'side' = 'over'; @@ -332,7 +333,7 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr ngAfterContentInit() { this._focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement); - this._focusTrap.enabled = this._isFocusTrapEnabled; + this._updateFocusTrapState(); } ngAfterContentChecked() { @@ -399,9 +400,7 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr this._restoreFocus(); } - if (this._focusTrap) { - this._focusTrap.enabled = this._isFocusTrapEnabled; - } + this._updateFocusTrapState(); return new Promise(resolve => { this.openedChange.pipe(take(1)).subscribe(open => resolve(open ? 'open' : 'close')); @@ -412,6 +411,13 @@ export class MatDrawer implements AfterContentInit, AfterContentChecked, OnDestr return this._elementRef.nativeElement ? (this._elementRef.nativeElement.offsetWidth || 0) : 0; } + /** Updates the enabled state of the focus trap. */ + private _updateFocusTrapState() { + if (this._focusTrap) { + this._focusTrap.enabled = this._isFocusTrapEnabled; + } + } + // We have to use a `HostListener` here in order to support both Ivy and ViewEngine. // In Ivy the `host` bindings will be merged when this class is extended, whereas in // ViewEngine they're overwritte.