Skip to content

Commit e0d8260

Browse files
committed
refactor(sidenav): expose api to update content margins
Exposes an API so that consumers can trigger an update of the content margins manually. This allows the sidenav to handle some cases that might not have accounted for. Fixes #15777.
1 parent fde980c commit e0d8260

File tree

2 files changed

+57
-57
lines changed

2 files changed

+57
-57
lines changed

src/material/sidenav/drawer.ts

Lines changed: 56 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -541,15 +541,15 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
541541
if (_dir) {
542542
_dir.change.pipe(takeUntil(this._destroyed)).subscribe(() => {
543543
this._validateDrawers();
544-
this._updateContentMargins();
544+
this.updateContentMargins();
545545
});
546546
}
547547

548548
// Since the minimum width of the sidenav depends on the viewport width,
549549
// we need to recompute the margins if the viewport changes.
550550
viewportRuler.change()
551551
.pipe(takeUntil(this._destroyed))
552-
.subscribe(() => this._updateContentMargins());
552+
.subscribe(() => this.updateContentMargins());
553553

554554
this._autosize = defaultAutosize;
555555
}
@@ -567,7 +567,7 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
567567
if (!this._drawers.length ||
568568
this._isDrawerOpen(this._start) ||
569569
this._isDrawerOpen(this._end)) {
570-
this._updateContentMargins();
570+
this.updateContentMargins();
571571
}
572572

573573
this._changeDetectorRef.markForCheck();
@@ -576,7 +576,7 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
576576
this._doCheckSubject.pipe(
577577
debounceTime(10), // Arbitrary debounce time, less than a frame at 60fps
578578
takeUntil(this._destroyed)
579-
).subscribe(() => this._updateContentMargins());
579+
).subscribe(() => this.updateContentMargins());
580580
}
581581

582582
ngOnDestroy() {
@@ -596,6 +596,56 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
596596
this._drawers.forEach(drawer => drawer.close());
597597
}
598598

599+
/**
600+
* Recalculates and updates the inline styles for the content. Note that this should be used
601+
* sparingly, because it causes a reflow.
602+
*/
603+
updateContentMargins() {
604+
// 1. For drawers in `over` mode, they don't affect the content.
605+
// 2. For drawers in `side` mode they should shrink the content. We do this by adding to the
606+
// left margin (for left drawer) or right margin (for right the drawer).
607+
// 3. For drawers in `push` mode the should shift the content without resizing it. We do this by
608+
// adding to the left or right margin and simultaneously subtracting the same amount of
609+
// margin from the other side.
610+
let left = 0;
611+
let right = 0;
612+
613+
if (this._left && this._left.opened) {
614+
if (this._left.mode == 'side') {
615+
left += this._left._width;
616+
} else if (this._left.mode == 'push') {
617+
const width = this._left._width;
618+
left += width;
619+
right -= width;
620+
}
621+
}
622+
623+
if (this._right && this._right.opened) {
624+
if (this._right.mode == 'side') {
625+
right += this._right._width;
626+
} else if (this._right.mode == 'push') {
627+
const width = this._right._width;
628+
right += width;
629+
left -= width;
630+
}
631+
}
632+
633+
// If either `right` or `left` is zero, don't set a style to the element. This
634+
// allows users to specify a custom size via CSS class in SSR scenarios where the
635+
// measured widths will always be zero. Note that we reset to `null` here, rather
636+
// than below, in order to ensure that the types in the `if` below are consistent.
637+
left = left || null!;
638+
right = right || null!;
639+
640+
if (left !== this._contentMargins.left || right !== this._contentMargins.right) {
641+
this._contentMargins = {left, right};
642+
643+
// Pull back into the NgZone since in some cases we could be outside. We need to be careful
644+
// to do it only when something changed, otherwise we can end up hitting the zone too often.
645+
this._ngZone.run(() => this._contentMarginChanges.next(this._contentMargins));
646+
}
647+
}
648+
599649
ngDoCheck() {
600650
// If users opted into autosizing, do a check every change detection cycle.
601651
if (this._autosize && this._isPushed()) {
@@ -621,7 +671,7 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
621671
this._element.nativeElement.classList.add('mat-drawer-transition');
622672
}
623673

624-
this._updateContentMargins();
674+
this.updateContentMargins();
625675
this._changeDetectorRef.markForCheck();
626676
});
627677

@@ -653,7 +703,7 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
653703
if (drawer) {
654704
drawer._modeChanged.pipe(takeUntil(merge(this._drawers.changes, this._destroyed)))
655705
.subscribe(() => {
656-
this._updateContentMargins();
706+
this.updateContentMargins();
657707
this._changeDetectorRef.markForCheck();
658708
});
659709
}
@@ -730,55 +780,4 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy
730780
return drawer != null && drawer.opened;
731781
}
732782

733-
/**
734-
* Recalculates and updates the inline styles for the content. Note that this should be used
735-
* sparingly, because it causes a reflow.
736-
*/
737-
private _updateContentMargins() {
738-
// 1. For drawers in `over` mode, they don't affect the content.
739-
// 2. For drawers in `side` mode they should shrink the content. We do this by adding to the
740-
// left margin (for left drawer) or right margin (for right the drawer).
741-
// 3. For drawers in `push` mode the should shift the content without resizing it. We do this by
742-
// adding to the left or right margin and simultaneously subtracting the same amount of
743-
// margin from the other side.
744-
745-
let left = 0;
746-
let right = 0;
747-
748-
if (this._left && this._left.opened) {
749-
if (this._left.mode == 'side') {
750-
left += this._left._width;
751-
} else if (this._left.mode == 'push') {
752-
let width = this._left._width;
753-
left += width;
754-
right -= width;
755-
}
756-
}
757-
758-
if (this._right && this._right.opened) {
759-
if (this._right.mode == 'side') {
760-
right += this._right._width;
761-
} else if (this._right.mode == 'push') {
762-
let width = this._right._width;
763-
right += width;
764-
left -= width;
765-
}
766-
}
767-
768-
// If either `right` or `left` is zero, don't set a style to the element. This
769-
// allows users to specify a custom size via CSS class in SSR scenarios where the
770-
// measured widths will always be zero. Note that we reset to `null` here, rather
771-
// than below, in order to ensure that the types in the `if` below are consistent.
772-
left = left || null!;
773-
right = right || null!;
774-
775-
if (left !== this._contentMargins.left || right !== this._contentMargins.right) {
776-
this._contentMargins = {left, right};
777-
778-
// Pull back into the NgZone since in some cases we could be outside. We need to be careful
779-
// to do it only when something changed, otherwise we can end up hitting the zone too often.
780-
this._ngZone.run(() => this._contentMarginChanges.next(this._contentMargins));
781-
}
782-
783-
}
784783
}

tools/public_api_guard/material/sidenav.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export declare class MatDrawerContainer implements AfterContentInit, DoCheck, On
6363
ngDoCheck(): void;
6464
ngOnDestroy(): void;
6565
open(): void;
66+
updateContentMargins(): void;
6667
}
6768

6869
export declare class MatDrawerContent extends CdkScrollable implements AfterContentInit {

0 commit comments

Comments
 (0)