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' ;
@@ -171,6 +171,9 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
171171 /** Whether the drawer is opened. */
172172 private _opened : boolean = false ;
173173
174+ /** How the sidenav was opened (keypress, mouse click etc.) */
175+ private _openedVia : FocusOrigin | null ;
176+
174177 /** Emits whenever the drawer has started animating. */
175178 _animationStarted = new EventEmitter < AnimationEvent > ( ) ;
176179
@@ -202,7 +205,9 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
202205
203206 constructor ( private _elementRef : ElementRef ,
204207 private _focusTrapFactory : FocusTrapFactory ,
208+ private _focusMonitor : FocusMonitor ,
205209 @Optional ( ) @Inject ( DOCUMENT ) private _doc : any ) {
210+
206211 this . onOpen . subscribe ( ( ) => {
207212 if ( this . _doc ) {
208213 this . _elementFocusedBeforeDrawerWasOpened = this . _doc . activeElement as HTMLElement ;
@@ -221,16 +226,18 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
221226 * opened.
222227 */
223228 private _restoreFocus ( ) {
224- let activeEl = this . _doc && this . _doc . activeElement ;
229+ const activeEl = this . _doc && this . _doc . activeElement ;
230+
225231 if ( activeEl && this . _elementRef . nativeElement . contains ( activeEl ) ) {
226232 if ( this . _elementFocusedBeforeDrawerWasOpened instanceof HTMLElement ) {
227- this . _elementFocusedBeforeDrawerWasOpened . focus ( ) ;
233+ this . _focusMonitor . focusVia ( this . _elementFocusedBeforeDrawerWasOpened , this . _openedVia ) ;
228234 } else {
229235 this . _elementRef . nativeElement . blur ( ) ;
230236 }
231237 }
232238
233239 this . _elementFocusedBeforeDrawerWasOpened = null ;
240+ this . _openedVia = null ;
234241 }
235242
236243 ngAfterContentInit ( ) {
@@ -255,10 +262,13 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
255262 this . toggle ( coerceBooleanProperty ( v ) ) ;
256263 }
257264
258-
259- /** Open the drawer. */
260- open ( ) : Promise < MatDrawerToggleResult > {
261- return this . toggle ( true ) ;
265+ /**
266+ * Open the drawer.
267+ * @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.
268+ * Used for focus management after the sidenav is closed.
269+ */
270+ open ( openedVia ?: FocusOrigin ) : Promise < MatDrawerToggleResult > {
271+ return this . toggle ( true , openedVia ) ;
262272 }
263273
264274 /** Close the drawer. */
@@ -269,12 +279,17 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
269279 /**
270280 * Toggle this drawer.
271281 * @param isOpen Whether the drawer should be open.
282+ * @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.
283+ * Used for focus management after the sidenav is closed.
272284 */
273- toggle ( isOpen : boolean = ! this . opened ) : Promise < MatDrawerToggleResult > {
285+ toggle ( isOpen : boolean = ! this . opened , openedVia : FocusOrigin = 'program' ) :
286+ Promise < MatDrawerToggleResult > {
287+
274288 this . _opened = isOpen ;
275289
276290 if ( isOpen ) {
277291 this . _animationState = this . _enableAnimations ? 'open' : 'open-instant' ;
292+ this . _openedVia = openedVia ;
278293 } else {
279294 this . _animationState = 'void' ;
280295 }
0 commit comments