77 */
88
99import { animate , AnimationEvent , state , style , transition , trigger } from '@angular/animations' ;
10- import { FocusTrap , FocusTrapFactory } from '@angular/cdk/a11y' ;
10+ import { FocusTrap , FocusTrapFactory , FocusMonitor , FocusOrigin } from '@angular/cdk/a11y' ;
1111import { Directionality } from '@angular/cdk/bidi' ;
1212import { coerceBooleanProperty } from '@angular/cdk/coercion' ;
1313import { ESCAPE } from '@angular/cdk/keycodes' ;
@@ -172,6 +172,9 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
172172 /** Whether the drawer is opened. */
173173 private _opened : boolean = false ;
174174
175+ /** How the sidenav was opened (keypress, mouse click etc.) */
176+ private _openedVia : FocusOrigin | null ;
177+
175178 /** Emits whenever the drawer has started animating. */
176179 _animationStarted = new EventEmitter < AnimationEvent > ( ) ;
177180
@@ -230,6 +233,7 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
230233
231234 constructor ( private _elementRef : ElementRef ,
232235 private _focusTrapFactory : FocusTrapFactory ,
236+ private _focusMonitor : FocusMonitor ,
233237 @Optional ( ) @Inject ( DOCUMENT ) private _doc : any ) {
234238 this . openedChange . subscribe ( ( opened : boolean ) => {
235239 if ( opened ) {
@@ -251,16 +255,18 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
251255 * opened.
252256 */
253257 private _restoreFocus ( ) {
254- let activeEl = this . _doc && this . _doc . activeElement ;
258+ const activeEl = this . _doc && this . _doc . activeElement ;
259+
255260 if ( activeEl && this . _elementRef . nativeElement . contains ( activeEl ) ) {
256261 if ( this . _elementFocusedBeforeDrawerWasOpened instanceof HTMLElement ) {
257- this . _elementFocusedBeforeDrawerWasOpened . focus ( ) ;
262+ this . _focusMonitor . focusVia ( this . _elementFocusedBeforeDrawerWasOpened , this . _openedVia ) ;
258263 } else {
259264 this . _elementRef . nativeElement . blur ( ) ;
260265 }
261266 }
262267
263268 this . _elementFocusedBeforeDrawerWasOpened = null ;
269+ this . _openedVia = null ;
264270 }
265271
266272 ngAfterContentInit ( ) {
@@ -285,10 +291,13 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
285291 this . toggle ( coerceBooleanProperty ( v ) ) ;
286292 }
287293
288-
289- /** Open the drawer. */
290- open ( ) : Promise < MatDrawerToggleResult > {
291- return this . toggle ( true ) ;
294+ /**
295+ * Open the drawer.
296+ * @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.
297+ * Used for focus management after the sidenav is closed.
298+ */
299+ open ( openedVia ?: FocusOrigin ) : Promise < MatDrawerToggleResult > {
300+ return this . toggle ( true , openedVia ) ;
292301 }
293302
294303 /** Close the drawer. */
@@ -299,12 +308,17 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
299308 /**
300309 * Toggle this drawer.
301310 * @param isOpen Whether the drawer should be open.
311+ * @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.
312+ * Used for focus management after the sidenav is closed.
302313 */
303- toggle ( isOpen : boolean = ! this . opened ) : Promise < MatDrawerToggleResult > {
314+ toggle ( isOpen : boolean = ! this . opened , openedVia : FocusOrigin = 'program' ) :
315+ Promise < MatDrawerToggleResult > {
316+
304317 this . _opened = isOpen ;
305318
306319 if ( isOpen ) {
307320 this . _animationState = this . _enableAnimations ? 'open' : 'open-instant' ;
321+ this . _openedVia = openedVia ;
308322 } else {
309323 this . _animationState = 'void' ;
310324 this . _restoreFocus ( ) ;
0 commit comments