Skip to content

Commit b5889ca

Browse files
crisbetojelbourn
authored andcommitted
refactor(sidenav): expose api to update content margins (#15833)
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 94c27b5 commit b5889ca

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)