7
7
*/
8
8
9
9
import { 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' ;
11
11
import { Directionality } from '@angular/cdk/bidi' ;
12
12
import { coerceBooleanProperty } from '@angular/cdk/coercion' ;
13
13
import { ESCAPE } from '@angular/cdk/keycodes' ;
@@ -171,6 +171,9 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
171
171
/** Whether the drawer is opened. */
172
172
private _opened : boolean = false ;
173
173
174
+ /** How the sidenav was opened (keypress, mouse click etc.) */
175
+ private _openedVia : FocusOrigin | null ;
176
+
174
177
/** Emits whenever the drawer has started animating. */
175
178
_animationStarted = new EventEmitter < AnimationEvent > ( ) ;
176
179
@@ -202,7 +205,9 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
202
205
203
206
constructor ( private _elementRef : ElementRef ,
204
207
private _focusTrapFactory : FocusTrapFactory ,
208
+ private _focusMonitor : FocusMonitor ,
205
209
@Optional ( ) @Inject ( DOCUMENT ) private _doc : any ) {
210
+
206
211
this . onOpen . subscribe ( ( ) => {
207
212
if ( this . _doc ) {
208
213
this . _elementFocusedBeforeDrawerWasOpened = this . _doc . activeElement as HTMLElement ;
@@ -221,16 +226,18 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
221
226
* opened.
222
227
*/
223
228
private _restoreFocus ( ) {
224
- let activeEl = this . _doc && this . _doc . activeElement ;
229
+ const activeEl = this . _doc && this . _doc . activeElement ;
230
+
225
231
if ( activeEl && this . _elementRef . nativeElement . contains ( activeEl ) ) {
226
232
if ( this . _elementFocusedBeforeDrawerWasOpened instanceof HTMLElement ) {
227
- this . _elementFocusedBeforeDrawerWasOpened . focus ( ) ;
233
+ this . _focusMonitor . focusVia ( this . _elementFocusedBeforeDrawerWasOpened , this . _openedVia ) ;
228
234
} else {
229
235
this . _elementRef . nativeElement . blur ( ) ;
230
236
}
231
237
}
232
238
233
239
this . _elementFocusedBeforeDrawerWasOpened = null ;
240
+ this . _openedVia = null ;
234
241
}
235
242
236
243
ngAfterContentInit ( ) {
@@ -255,10 +262,13 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
255
262
this . toggle ( coerceBooleanProperty ( v ) ) ;
256
263
}
257
264
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 ) ;
262
272
}
263
273
264
274
/** Close the drawer. */
@@ -269,12 +279,17 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
269
279
/**
270
280
* Toggle this drawer.
271
281
* @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.
272
284
*/
273
- toggle ( isOpen : boolean = ! this . opened ) : Promise < MatDrawerToggleResult > {
285
+ toggle ( isOpen : boolean = ! this . opened , openedVia : FocusOrigin = 'program' ) :
286
+ Promise < MatDrawerToggleResult > {
287
+
274
288
this . _opened = isOpen ;
275
289
276
290
if ( isOpen ) {
277
291
this . _animationState = this . _enableAnimations ? 'open' : 'open-instant' ;
292
+ this . _openedVia = openedVia ;
278
293
} else {
279
294
this . _animationState = 'void' ;
280
295
}
0 commit comments