@@ -29,13 +29,15 @@ import {
29
29
QueryList ,
30
30
Renderer2 ,
31
31
ViewEncapsulation ,
32
+ InjectionToken ,
32
33
} from '@angular/core' ;
33
34
import { DOCUMENT } from '@angular/platform-browser' ;
34
35
import { merge } from 'rxjs/observable/merge' ;
35
36
import { filter } from 'rxjs/operators/filter' ;
36
37
import { first } from 'rxjs/operators/first' ;
37
38
import { startWith } from 'rxjs/operators/startWith' ;
38
39
import { takeUntil } from 'rxjs/operators/takeUntil' ;
40
+ import { debounceTime } from 'rxjs/operators/debounceTime' ;
39
41
import { map } from 'rxjs/operators/map' ;
40
42
import { Subject } from 'rxjs/Subject' ;
41
43
import { Observable } from 'rxjs/Observable' ;
@@ -55,6 +57,9 @@ export class MatDrawerToggleResult {
55
57
constructor ( public type : 'open' | 'close' , public animationFinished : boolean ) { }
56
58
}
57
59
60
+ /** Configures whether drawers should use auto sizing by default. */
61
+ export const MAT_DRAWER_DEFAULT_AUTOSIZE =
62
+ new InjectionToken < boolean > ( 'MAT_DRAWER_DEFAULT_AUTOSIZE' ) ;
58
63
59
64
@Component ( {
60
65
moduleId : module . id ,
@@ -404,7 +409,6 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
404
409
} )
405
410
export class MatDrawerContainer implements AfterContentInit , OnDestroy {
406
411
@ContentChildren ( MatDrawer ) _drawers : QueryList < MatDrawer > ;
407
-
408
412
@ContentChild ( MatDrawerContent ) _content : MatDrawerContent ;
409
413
410
414
/** The drawer child with the `start` position. */
@@ -413,6 +417,19 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
413
417
/** The drawer child with the `end` position. */
414
418
get end ( ) : MatDrawer | null { return this . _end ; }
415
419
420
+ /**
421
+ * Whether to automatically resize the container whenever
422
+ * the size of any of its drawers changes.
423
+ *
424
+ * **Use at your own risk!** Enabling this option can cause layout thrashing by measuring
425
+ * the drawers on every change detection cycle. Can be configured globally via the
426
+ * `MAT_DRAWER_DEFAULT_AUTOSIZE` token.
427
+ */
428
+ @Input ( )
429
+ get autosize ( ) : boolean { return this . _autosize ; }
430
+ set autosize ( value : boolean ) { this . _autosize = coerceBooleanProperty ( value ) ; }
431
+ private _autosize : boolean ;
432
+
416
433
/** Event emitted when the drawer backdrop is clicked. */
417
434
@Output ( ) backdropClick = new EventEmitter < void > ( ) ;
418
435
@@ -432,16 +449,27 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
432
449
/** Emits when the component is destroyed. */
433
450
private _destroyed = new Subject < void > ( ) ;
434
451
452
+ /** Cached margins used to verify that the values have changed. */
453
+ private _margins = { left : 0 , right : 0 } ;
454
+
455
+ /** Used for debouncing reflows. */
456
+ private _debouncer = new Subject < void > ( ) ;
457
+
435
458
_contentMargins = new Subject < { left : number , right : number } > ( ) ;
436
459
437
- constructor ( @Optional ( ) private _dir : Directionality , private _element : ElementRef ,
438
- private _renderer : Renderer2 , private _ngZone : NgZone ,
460
+ constructor ( @Optional ( ) private _dir : Directionality ,
461
+ @Inject ( MAT_DRAWER_DEFAULT_AUTOSIZE ) defaultAutosize : boolean ,
462
+ private _element : ElementRef ,
463
+ private _renderer : Renderer2 ,
464
+ private _ngZone : NgZone ,
439
465
private _changeDetectorRef : ChangeDetectorRef ) {
440
466
// If a `Dir` directive exists up the tree, listen direction changes and update the left/right
441
467
// properties to point to the proper start/end.
442
468
if ( _dir != null ) {
443
469
_dir . change . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( ( ) => this . _validateDrawers ( ) ) ;
444
470
}
471
+
472
+ this . _autosize = defaultAutosize ;
445
473
}
446
474
447
475
ngAfterContentInit ( ) {
@@ -462,9 +490,15 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
462
490
463
491
this . _changeDetectorRef . markForCheck ( ) ;
464
492
} ) ;
493
+
494
+ this . _debouncer . pipe (
495
+ debounceTime ( 10 ) , // Arbitrary debounce time, less than a frame at 60fps
496
+ takeUntil ( this . _destroyed )
497
+ ) . subscribe ( ( ) => this . _updateContentMargins ( ) ) ;
465
498
}
466
499
467
500
ngOnDestroy ( ) {
501
+ this . _debouncer . complete ( ) ;
468
502
this . _destroyed . next ( ) ;
469
503
this . _destroyed . complete ( ) ;
470
504
}
@@ -479,6 +513,14 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
479
513
this . _drawers . forEach ( drawer => drawer . close ( ) ) ;
480
514
}
481
515
516
+ ngDoCheck ( ) {
517
+ // If users opted into autosizing, do a check every change detection cycle.
518
+ if ( this . _autosize && this . _isPushed ( ) ) {
519
+ // Run outside the NgZone, otherwise the debouncer will throw us into an infinite loop.
520
+ this . _ngZone . runOutsideAngular ( ( ) => this . _debouncer . next ( ) ) ;
521
+ }
522
+ }
523
+
482
524
/**
483
525
* Subscribes to drawer events in order to set a class on the main container element when the
484
526
* drawer is open and the backdrop is visible. This ensures any overflow on the container element
@@ -574,6 +616,12 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
574
616
}
575
617
}
576
618
619
+ /** Whether the container is being pushed to the side by one of the drawers. */
620
+ private _isPushed ( ) {
621
+ return ( this . _isDrawerOpen ( this . _start ) && this . _start ! . mode != 'over' ) ||
622
+ ( this . _isDrawerOpen ( this . _end ) && this . _end ! . mode != 'over' ) ;
623
+ }
624
+
577
625
_onBackdropClicked ( ) {
578
626
this . backdropClick . emit ( ) ;
579
627
this . _closeModalDrawer ( ) ;
@@ -630,6 +678,12 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
630
678
}
631
679
}
632
680
633
- this . _contentMargins . next ( { left, right} ) ;
681
+ if ( left !== this . _margins . left || right !== this . _margins . right ) {
682
+ this . _margins . left = left ;
683
+ this . _margins . right = right ;
684
+
685
+ // Pull back into the NgZone since in some cases we could be outside.
686
+ this . _ngZone . run ( ( ) => this . _contentMargins . next ( this . _margins ) ) ;
687
+ }
634
688
}
635
689
}
0 commit comments