@@ -14,6 +14,8 @@ import {take} from 'rxjs/operators/take';
14
14
import { Subject } from 'rxjs/Subject' ;
15
15
import { OverlayKeyboardDispatcher } from './keyboard/overlay-keyboard-dispatcher' ;
16
16
import { OverlayConfig } from './overlay-config' ;
17
+ import { MatBackdrop } from './backdrop' ;
18
+ import { empty } from 'rxjs/observable/empty' ;
17
19
18
20
19
21
/** An object where all of its properties cannot be written. */
@@ -26,17 +28,18 @@ export type ImmutableObject<T> = {
26
28
* Used to manipulate or dispose of said overlay.
27
29
*/
28
30
export class OverlayRef implements PortalOutlet {
29
- private _backdropElement : HTMLElement | null = null ;
30
31
private _backdropClick : Subject < any > = new Subject ( ) ;
31
32
private _attachments = new Subject < void > ( ) ;
32
33
private _detachments = new Subject < void > ( ) ;
34
+ private _backdropInstance : MatBackdrop | null ;
33
35
34
36
/** Stream of keydown events dispatched to this overlay. */
35
37
_keydownEvents = new Subject < KeyboardEvent > ( ) ;
36
38
37
39
constructor (
38
40
private _portalOutlet : PortalOutlet ,
39
41
private _pane : HTMLElement ,
42
+ private _backdropHost : PortalOutlet | null ,
40
43
private _config : ImmutableObject < OverlayConfig > ,
41
44
private _ngZone : NgZone ,
42
45
private _keyboardDispatcher : OverlayKeyboardDispatcher ) {
@@ -63,7 +66,7 @@ export class OverlayRef implements PortalOutlet {
63
66
* @returns The portal attachment result.
64
67
*/
65
68
attach ( portal : Portal < any > ) : any {
66
- let attachResult = this . _portalOutlet . attach ( portal ) ;
69
+ const attachResult = this . _portalOutlet . attach ( portal ) ;
67
70
68
71
if ( this . _config . positionStrategy ) {
69
72
this . _config . positionStrategy . attach ( this ) ;
@@ -88,14 +91,15 @@ export class OverlayRef implements PortalOutlet {
88
91
// Enable pointer events for the overlay pane element.
89
92
this . _togglePointerEvents ( true ) ;
90
93
91
- if ( this . _config . hasBackdrop ) {
92
- this . _attachBackdrop ( ) ;
94
+ if ( this . _backdropHost ) {
95
+ this . _backdropInstance = this . _backdropHost . attach ( new ComponentPortal ( MatBackdrop ) ) . instance ;
96
+ this . _backdropInstance ! . _setClass ( this . _config . backdropClass ! ) ;
93
97
}
94
98
95
99
if ( this . _config . panelClass ) {
96
100
// We can't do a spread here, because IE doesn't support setting multiple classes.
97
101
if ( Array . isArray ( this . _config . panelClass ) ) {
98
- this . _config . panelClass . forEach ( cls => this . _pane . classList . add ( cls ) ) ;
102
+ this . _config . panelClass . forEach ( cssClass => this . _pane . classList . add ( cssClass ) ) ;
99
103
} else {
100
104
this . _pane . classList . add ( this . _config . panelClass ) ;
101
105
}
@@ -119,7 +123,9 @@ export class OverlayRef implements PortalOutlet {
119
123
return ;
120
124
}
121
125
122
- this . detachBackdrop ( ) ;
126
+ if ( this . _backdropHost && this . _backdropHost . hasAttached ( ) ) {
127
+ this . _backdropHost . detach ( ) ;
128
+ }
123
129
124
130
// When the overlay is detached, the pane element should disable pointer events.
125
131
// This is necessary because otherwise the pane element will cover the page and disable
@@ -157,7 +163,7 @@ export class OverlayRef implements PortalOutlet {
157
163
this . _config . scrollStrategy . disable ( ) ;
158
164
}
159
165
160
- this . detachBackdrop ( ) ;
166
+ this . disposeBackdrop ( ) ;
161
167
this . _keyboardDispatcher . remove ( this ) ;
162
168
this . _portalOutlet . dispose ( ) ;
163
169
this . _attachments . complete ( ) ;
@@ -178,7 +184,7 @@ export class OverlayRef implements PortalOutlet {
178
184
179
185
/** Gets an observable that emits when the backdrop has been clicked. */
180
186
backdropClick ( ) : Observable < void > {
181
- return this . _backdropClick . asObservable ( ) ;
187
+ return this . _backdropInstance ? this . _backdropInstance . _clickStream : empty < void > ( ) ;
182
188
}
183
189
184
190
/** Gets an observable that emits when the overlay has been attached. */
@@ -257,33 +263,6 @@ export class OverlayRef implements PortalOutlet {
257
263
this . _pane . style . pointerEvents = enablePointer ? 'auto' : 'none' ;
258
264
}
259
265
260
- /** Attaches a backdrop for this overlay. */
261
- private _attachBackdrop ( ) {
262
- this . _backdropElement = document . createElement ( 'div' ) ;
263
- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop' ) ;
264
-
265
- if ( this . _config . backdropClass ) {
266
- this . _backdropElement . classList . add ( this . _config . backdropClass ) ;
267
- }
268
-
269
- // Insert the backdrop before the pane in the DOM order,
270
- // in order to handle stacked overlays properly.
271
- this . _pane . parentElement ! . insertBefore ( this . _backdropElement , this . _pane ) ;
272
-
273
- // Forward backdrop clicks such that the consumer of the overlay can perform whatever
274
- // action desired when such a click occurs (usually closing the overlay).
275
- this . _backdropElement . addEventListener ( 'click' , ( ) => this . _backdropClick . next ( null ) ) ;
276
-
277
- // Add class to fade-in the backdrop after one frame.
278
- this . _ngZone . runOutsideAngular ( ( ) => {
279
- requestAnimationFrame ( ( ) => {
280
- if ( this . _backdropElement ) {
281
- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop-showing' ) ;
282
- }
283
- } ) ;
284
- } ) ;
285
- }
286
-
287
266
/**
288
267
* Updates the stacking order of the element, moving it to the top if necessary.
289
268
* This is required in cases where one overlay was detached, while another one,
@@ -297,45 +276,29 @@ export class OverlayRef implements PortalOutlet {
297
276
}
298
277
}
299
278
300
- /** Detaches the backdrop (if any) associated with the overlay. */
301
- detachBackdrop ( ) : void {
302
- let backdropToDetach = this . _backdropElement ;
303
-
304
- if ( backdropToDetach ) {
305
- let finishDetach = ( ) => {
306
- // It may not be attached to anything in certain cases (e.g. unit tests).
307
- if ( backdropToDetach && backdropToDetach . parentNode ) {
308
- backdropToDetach . parentNode . removeChild ( backdropToDetach ) ;
309
- }
310
-
311
- // It is possible that a new portal has been attached to this overlay since we started
312
- // removing the backdrop. If that is the case, only clear the backdrop reference if it
313
- // is still the same instance that we started to remove.
314
- if ( this . _backdropElement == backdropToDetach ) {
315
- this . _backdropElement = null ;
316
- }
317
- } ;
318
-
319
- backdropToDetach . classList . remove ( 'cdk-overlay-backdrop-showing' ) ;
320
-
321
- if ( this . _config . backdropClass ) {
322
- backdropToDetach . classList . remove ( this . _config . backdropClass ) ;
323
- }
324
-
325
- backdropToDetach . addEventListener ( 'transitionend' , finishDetach ) ;
326
-
327
- // If the backdrop doesn't have a transition, the `transitionend` event won't fire.
328
- // In this case we make it unclickable and we try to remove it after a delay.
329
- backdropToDetach . style . pointerEvents = 'none' ;
279
+ /** Animates out and disposes of the backdrop. */
280
+ disposeBackdrop ( ) : void {
281
+ if ( this . _backdropHost ) {
282
+ if ( this . _backdropHost . hasAttached ( ) ) {
283
+ this . _backdropHost . detach ( ) ;
330
284
331
- // Run this outside the Angular zone because there's nothing that Angular cares about.
332
- // If it were to run inside the Angular zone, every test that used Overlay would have to be
333
- // either async or fakeAsync.
334
- this . _ngZone . runOutsideAngular ( ( ) => {
335
- setTimeout ( finishDetach , 500 ) ;
336
- } ) ;
285
+ this . _backdropInstance ! . _animationStream . pipe ( take ( 1 ) ) . subscribe ( ( ) => {
286
+ this . _backdropHost ! . dispose ( ) ;
287
+ this . _backdropHost = this . _backdropInstance = null ;
288
+ } ) ;
289
+ } else {
290
+ this . _backdropHost . dispose ( ) ;
291
+ }
337
292
}
338
293
}
294
+
295
+ /**
296
+ * Detaches the backdrop (if any) associated with the overlay.
297
+ * @deprecated Use `disposeBackdrop` instead.
298
+ */
299
+ detachBackdrop ( ) : void {
300
+ this . disposeBackdrop ( ) ;
301
+ }
339
302
}
340
303
341
304
function formatCssUnit ( value : number | string ) {
0 commit comments