@@ -28,13 +28,15 @@ import {
2828 Output ,
2929 QueryList ,
3030 ViewEncapsulation ,
31+ InjectionToken ,
3132} from '@angular/core' ;
3233import { DOCUMENT } from '@angular/common' ;
3334import { merge } from 'rxjs/observable/merge' ;
3435import { filter } from 'rxjs/operators/filter' ;
3536import { take } from 'rxjs/operators/take' ;
3637import { startWith } from 'rxjs/operators/startWith' ;
3738import { takeUntil } from 'rxjs/operators/takeUntil' ;
39+ import { debounceTime } from 'rxjs/operators/debounceTime' ;
3840import { map } from 'rxjs/operators/map' ;
3941import { Subject } from 'rxjs/Subject' ;
4042import { Observable } from 'rxjs/Observable' ;
@@ -54,6 +56,9 @@ export class MatDrawerToggleResult {
5456 constructor ( public type : 'open' | 'close' , public animationFinished : boolean ) { }
5557}
5658
59+ /** Configures whether drawers should use auto sizing by default. */
60+ export const MAT_DRAWER_DEFAULT_AUTOSIZE =
61+ new InjectionToken < boolean > ( 'MAT_DRAWER_DEFAULT_AUTOSIZE' ) ;
5762
5863@Component ( {
5964 moduleId : module . id ,
@@ -74,7 +79,7 @@ export class MatDrawerContent implements AfterContentInit {
7479 * drawer is open. We use margin rather than transform even for push mode because transform breaks
7580 * fixed position elements inside of the transformed element.
7681 */
77- _margins : { left : number , right : number } = { left : 0 , right : 0 } ;
82+ _margins : { left : number | null , right : number | null } = { left : null , right : null } ;
7883
7984 constructor (
8085 private _changeDetectorRef : ChangeDetectorRef ,
@@ -403,7 +408,6 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
403408} )
404409export class MatDrawerContainer implements AfterContentInit , OnDestroy {
405410 @ContentChildren ( MatDrawer ) _drawers : QueryList < MatDrawer > ;
406-
407411 @ContentChild ( MatDrawerContent ) _content : MatDrawerContent ;
408412
409413 /** The drawer child with the `start` position. */
@@ -412,6 +416,19 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
412416 /** The drawer child with the `end` position. */
413417 get end ( ) : MatDrawer | null { return this . _end ; }
414418
419+ /**
420+ * Whether to automatically resize the container whenever
421+ * the size of any of its drawers changes.
422+ *
423+ * **Use at your own risk!** Enabling this option can cause layout thrashing by measuring
424+ * the drawers on every change detection cycle. Can be configured globally via the
425+ * `MAT_DRAWER_DEFAULT_AUTOSIZE` token.
426+ */
427+ @Input ( )
428+ get autosize ( ) : boolean { return this . _autosize ; }
429+ set autosize ( value : boolean ) { this . _autosize = coerceBooleanProperty ( value ) ; }
430+ private _autosize : boolean ;
431+
415432 /** Event emitted when the drawer backdrop is clicked. */
416433 @Output ( ) backdropClick = new EventEmitter < void > ( ) ;
417434
@@ -431,15 +448,23 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
431448 /** Emits when the component is destroyed. */
432449 private _destroyed = new Subject < void > ( ) ;
433450
434- _contentMargins = new Subject < { left : number , right : number } > ( ) ;
451+ /** Emits on every ngDoCheck. Used for debouncing reflows. */
452+ private _doCheckSubject = new Subject < void > ( ) ;
453+
454+ _contentMargins = new Subject < { left : number | null , right : number | null } > ( ) ;
435455
436- constructor ( @Optional ( ) private _dir : Directionality , private _element : ElementRef ,
437- private _ngZone : NgZone , private _changeDetectorRef : ChangeDetectorRef ) {
456+ constructor ( @Optional ( ) private _dir : Directionality ,
457+ private _element : ElementRef ,
458+ private _ngZone : NgZone ,
459+ private _changeDetectorRef : ChangeDetectorRef ,
460+ @Inject ( MAT_DRAWER_DEFAULT_AUTOSIZE ) defaultAutosize = false ) {
438461 // If a `Dir` directive exists up the tree, listen direction changes and update the left/right
439462 // properties to point to the proper start/end.
440463 if ( _dir != null ) {
441464 _dir . change . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( ( ) => this . _validateDrawers ( ) ) ;
442465 }
466+
467+ this . _autosize = defaultAutosize ;
443468 }
444469
445470 ngAfterContentInit ( ) {
@@ -460,9 +485,15 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
460485
461486 this . _changeDetectorRef . markForCheck ( ) ;
462487 } ) ;
488+
489+ this . _doCheckSubject . pipe (
490+ debounceTime ( 10 ) , // Arbitrary debounce time, less than a frame at 60fps
491+ takeUntil ( this . _destroyed )
492+ ) . subscribe ( ( ) => this . _updateContentMargins ( ) ) ;
463493 }
464494
465495 ngOnDestroy ( ) {
496+ this . _doCheckSubject . complete ( ) ;
466497 this . _destroyed . next ( ) ;
467498 this . _destroyed . complete ( ) ;
468499 }
@@ -477,6 +508,14 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
477508 this . _drawers . forEach ( drawer => drawer . close ( ) ) ;
478509 }
479510
511+ ngDoCheck ( ) {
512+ // If users opted into autosizing, do a check every change detection cycle.
513+ if ( this . _autosize && this . _isPushed ( ) ) {
514+ // Run outside the NgZone, otherwise the debouncer will throw us into an infinite loop.
515+ this . _ngZone . runOutsideAngular ( ( ) => this . _doCheckSubject . next ( ) ) ;
516+ }
517+ }
518+
480519 /**
481520 * Subscribes to drawer events in order to set a class on the main container element when the
482521 * drawer is open and the backdrop is visible. This ensures any overflow on the container element
@@ -572,6 +611,12 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
572611 }
573612 }
574613
614+ /** Whether the container is being pushed to the side by one of the drawers. */
615+ private _isPushed ( ) {
616+ return ( this . _isDrawerOpen ( this . _start ) && this . _start ! . mode != 'over' ) ||
617+ ( this . _isDrawerOpen ( this . _end ) && this . _end ! . mode != 'over' ) ;
618+ }
619+
575620 _onBackdropClicked ( ) {
576621 this . backdropClick . emit ( ) ;
577622 this . _closeModalDrawer ( ) ;
@@ -628,6 +673,7 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
628673 }
629674 }
630675
631- this . _contentMargins . next ( { left, right} ) ;
676+ // Pull back into the NgZone since in some cases we could be outside.
677+ this . _ngZone . run ( ( ) => this . _contentMargins . next ( { left, right} ) ) ;
632678 }
633679}
0 commit comments