99import { Direction } from '@angular/cdk/bidi' ;
1010import { ComponentPortal , Portal , PortalOutlet , TemplatePortal } from '@angular/cdk/portal' ;
1111import { ComponentRef , EmbeddedViewRef , NgZone } from '@angular/core' ;
12- import { Observable , Subject } from 'rxjs' ;
12+ import { Observable , Subject , empty } from 'rxjs' ;
1313import { take } from 'rxjs/operators' ;
1414import { OverlayKeyboardDispatcher } from './keyboard/overlay-keyboard-dispatcher' ;
1515import { OverlayConfig } from './overlay-config' ;
1616import { coerceCssPixelValue } from '@angular/cdk/coercion' ;
17+ import { CdkOverlayBackdrop } from './backdrop' ;
1718
1819
1920/** An object where all of its properties cannot be written. */
@@ -26,10 +27,10 @@ export type ImmutableObject<T> = {
2627 * Used to manipulate or dispose of said overlay.
2728 */
2829export class OverlayRef implements PortalOutlet {
29- private _backdropElement : HTMLElement | null = null ;
30- private _backdropClick : Subject < MouseEvent > = new Subject ( ) ;
30+ private _backdropClick = new Subject < MouseEvent > ( ) ;
3131 private _attachments = new Subject < void > ( ) ;
3232 private _detachments = new Subject < void > ( ) ;
33+ private _backdropInstance : CdkOverlayBackdrop | null ;
3334
3435 /** Stream of keydown events dispatched to this overlay. */
3536 _keydownEvents = new Subject < KeyboardEvent > ( ) ;
@@ -38,10 +39,10 @@ export class OverlayRef implements PortalOutlet {
3839 private _portalOutlet : PortalOutlet ,
3940 private _host : HTMLElement ,
4041 private _pane : HTMLElement ,
42+ private _backdropHost : PortalOutlet | null ,
4143 private _config : ImmutableObject < OverlayConfig > ,
4244 private _ngZone : NgZone ,
43- private _keyboardDispatcher : OverlayKeyboardDispatcher ,
44- private _document : Document ) {
45+ private _keyboardDispatcher : OverlayKeyboardDispatcher ) {
4546
4647 if ( _config . scrollStrategy ) {
4748 _config . scrollStrategy . attach ( this ) ;
@@ -55,7 +56,7 @@ export class OverlayRef implements PortalOutlet {
5556
5657 /** The overlay's backdrop HTML element. */
5758 get backdropElement ( ) : HTMLElement | null {
58- return this . _backdropElement ;
59+ return this . _backdropInstance ? this . _backdropInstance . _element . nativeElement : null ;
5960 }
6061
6162 /**
@@ -79,7 +80,7 @@ export class OverlayRef implements PortalOutlet {
7980 * @returns The portal attachment result.
8081 */
8182 attach ( portal : Portal < any > ) : any {
82- let attachResult = this . _portalOutlet . attach ( portal ) ;
83+ const attachResult = this . _portalOutlet . attach ( portal ) ;
8384
8485 if ( this . _config . positionStrategy ) {
8586 this . _config . positionStrategy . attach ( this ) ;
@@ -110,8 +111,10 @@ export class OverlayRef implements PortalOutlet {
110111 // Enable pointer events for the overlay pane element.
111112 this . _togglePointerEvents ( true ) ;
112113
113- if ( this . _config . hasBackdrop ) {
114- this . _attachBackdrop ( ) ;
114+ if ( this . _backdropHost ) {
115+ this . _backdropInstance =
116+ this . _backdropHost . attach ( new ComponentPortal ( CdkOverlayBackdrop ) ) . instance ;
117+ this . _backdropInstance ! . _setClass ( this . _config . backdropClass ! ) ;
115118 }
116119
117120 if ( this . _config . panelClass ) {
@@ -141,7 +144,9 @@ export class OverlayRef implements PortalOutlet {
141144 return ;
142145 }
143146
144- this . detachBackdrop ( ) ;
147+ if ( this . _backdropHost && this . _backdropHost . hasAttached ( ) ) {
148+ this . _backdropHost . detach ( ) ;
149+ }
145150
146151 // When the overlay is detached, the pane element should disable pointer events.
147152 // This is necessary because otherwise the pane element will cover the page and disable
@@ -179,7 +184,7 @@ export class OverlayRef implements PortalOutlet {
179184 this . _config . scrollStrategy . disable ( ) ;
180185 }
181186
182- this . detachBackdrop ( ) ;
187+ this . disposeBackdrop ( ) ;
183188 this . _keyboardDispatcher . remove ( this ) ;
184189 this . _portalOutlet . dispose ( ) ;
185190 this . _attachments . complete ( ) ;
@@ -205,7 +210,7 @@ export class OverlayRef implements PortalOutlet {
205210
206211 /** Gets an observable that emits when the backdrop has been clicked. */
207212 backdropClick ( ) : Observable < MouseEvent > {
208- return this . _backdropClick . asObservable ( ) ;
213+ return this . _backdropInstance ? this . _backdropInstance . _clickStream : empty ( ) ;
209214 }
210215
211216 /** Gets an observable that emits when the overlay has been attached. */
@@ -284,40 +289,6 @@ export class OverlayRef implements PortalOutlet {
284289 this . _pane . style . pointerEvents = enablePointer ? 'auto' : 'none' ;
285290 }
286291
287- /** Attaches a backdrop for this overlay. */
288- private _attachBackdrop ( ) {
289- const showingClass = 'cdk-overlay-backdrop-showing' ;
290-
291- this . _backdropElement = this . _document . createElement ( 'div' ) ;
292- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop' ) ;
293-
294- if ( this . _config . backdropClass ) {
295- this . _backdropElement . classList . add ( this . _config . backdropClass ) ;
296- }
297-
298- // Insert the backdrop before the pane in the DOM order,
299- // in order to handle stacked overlays properly.
300- this . _host . parentElement ! . insertBefore ( this . _backdropElement , this . _host ) ;
301-
302- // Forward backdrop clicks such that the consumer of the overlay can perform whatever
303- // action desired when such a click occurs (usually closing the overlay).
304- this . _backdropElement . addEventListener ( 'click' ,
305- ( event : MouseEvent ) => this . _backdropClick . next ( event ) ) ;
306-
307- // Add class to fade-in the backdrop after one frame.
308- if ( typeof requestAnimationFrame !== 'undefined' ) {
309- this . _ngZone . runOutsideAngular ( ( ) => {
310- requestAnimationFrame ( ( ) => {
311- if ( this . _backdropElement ) {
312- this . _backdropElement . classList . add ( showingClass ) ;
313- }
314- } ) ;
315- } ) ;
316- } else {
317- this . _backdropElement . classList . add ( showingClass ) ;
318- }
319- }
320-
321292 /**
322293 * Updates the stacking order of the element, moving it to the top if necessary.
323294 * This is required in cases where one overlay was detached, while another one,
@@ -331,43 +302,30 @@ export class OverlayRef implements PortalOutlet {
331302 }
332303 }
333304
334- /** Detaches the backdrop (if any) associated with the overlay. */
335- detachBackdrop ( ) : void {
336- let backdropToDetach = this . _backdropElement ;
337-
338- if ( backdropToDetach ) {
339- let finishDetach = ( ) => {
340- // It may not be attached to anything in certain cases (e.g. unit tests).
341- if ( backdropToDetach && backdropToDetach . parentNode ) {
342- backdropToDetach . parentNode . removeChild ( backdropToDetach ) ;
343- }
344-
345- // It is possible that a new portal has been attached to this overlay since we started
346- // removing the backdrop. If that is the case, only clear the backdrop reference if it
347- // is still the same instance that we started to remove.
348- if ( this . _backdropElement == backdropToDetach ) {
349- this . _backdropElement = null ;
350- }
351- } ;
352-
353- backdropToDetach . classList . remove ( 'cdk-overlay-backdrop-showing' ) ;
305+ /** Animates out and disposes of the backdrop. */
306+ disposeBackdrop ( ) : void {
307+ if ( this . _backdropHost ) {
308+ if ( this . _backdropHost . hasAttached ( ) ) {
309+ this . _backdropHost . detach ( ) ;
354310
355- if ( this . _config . backdropClass ) {
356- backdropToDetach . classList . remove ( this . _config . backdropClass ) ;
311+ this . _backdropInstance ! . _animationStream . pipe ( take ( 1 ) ) . subscribe ( ( ) => {
312+ this . _backdropHost ! . dispose ( ) ;
313+ this . _backdropHost = this . _backdropInstance = null ;
314+ } ) ;
315+ } else {
316+ this . _backdropHost . dispose ( ) ;
357317 }
358-
359- backdropToDetach . addEventListener ( 'transitionend' , finishDetach ) ;
360-
361- // If the backdrop doesn't have a transition, the `transitionend` event won't fire.
362- // In this case we make it unclickable and we try to remove it after a delay.
363- backdropToDetach . style . pointerEvents = 'none' ;
364-
365- // Run this outside the Angular zone because there's nothing that Angular cares about.
366- // If it were to run inside the Angular zone, every test that used Overlay would have to be
367- // either async or fakeAsync.
368- this . _ngZone . runOutsideAngular ( ( ) => setTimeout ( finishDetach , 500 ) ) ;
369318 }
370319 }
320+
321+ /**
322+ * Detaches the backdrop (if any) associated with the overlay.
323+ * @deprecated Use `disposeBackdrop` instead.
324+ * @deletion -target 7.0.0
325+ */
326+ detachBackdrop ( ) : void {
327+ this . disposeBackdrop ( ) ;
328+ }
371329}
372330
373331
0 commit comments