From 057304f75197000fdacacb753bdb501479c44a97 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 22 Aug 2017 11:51:40 -0700 Subject: [PATCH 01/11] add md-drawer-content --- src/lib/sidenav/drawer-container.html | 8 ++++-- src/lib/sidenav/drawer.html | 1 - src/lib/sidenav/drawer.ts | 40 ++++++++++++++++++++++++-- src/lib/sidenav/sidenav-container.html | 10 +++++++ src/lib/sidenav/sidenav-module.ts | 27 +++++++++++++---- src/lib/sidenav/sidenav.ts | 21 ++++++++++++-- 6 files changed, 92 insertions(+), 15 deletions(-) delete mode 100644 src/lib/sidenav/drawer.html create mode 100644 src/lib/sidenav/sidenav-container.html diff --git a/src/lib/sidenav/drawer-container.html b/src/lib/sidenav/drawer-container.html index f305c0545a87..a7f8457f08ca 100644 --- a/src/lib/sidenav/drawer-container.html +++ b/src/lib/sidenav/drawer-container.html @@ -1,8 +1,10 @@
- + -
+ + + -
+ diff --git a/src/lib/sidenav/drawer.html b/src/lib/sidenav/drawer.html deleted file mode 100644 index 6dbc74306383..000000000000 --- a/src/lib/sidenav/drawer.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts index ef241cacd3fa..26714f720180 100644 --- a/src/lib/sidenav/drawer.ts +++ b/src/lib/sidenav/drawer.ts @@ -16,6 +16,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + ContentChild, ContentChildren, ElementRef, EventEmitter, @@ -34,6 +35,7 @@ import {merge} from 'rxjs/observable/merge'; import {first} from 'rxjs/operator/first'; import {startWith} from 'rxjs/operator/startWith'; import {takeUntil} from 'rxjs/operator/takeUntil'; +import {Subject} from 'rxjs/Subject'; import {Subscription} from 'rxjs/Subscription'; @@ -51,6 +53,20 @@ export class MdDrawerToggleResult { constructor(public type: 'open' | 'close', public animationFinished: boolean) {} } + +@Component({ + moduleId: module.id, + selector: 'md-drawer-content, mat-drawer-content', + template: '', + host: { + 'class': 'mat-drawer-content', + }, + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, +}) +export class MdDrawerContent {} + + /** * component. * @@ -61,7 +77,7 @@ export class MdDrawerToggleResult { @Component({ moduleId: module.id, selector: 'md-drawer, mat-drawer', - templateUrl: 'drawer.html', + template: '', animations: [ trigger('transform', [ state('open, open-instant', style({ @@ -121,7 +137,13 @@ export class MdDrawer implements AfterContentInit, OnDestroy { set align(value) { this.position = value; } /** Mode of the drawer; one of 'over', 'push' or 'side'. */ - @Input() mode: 'over' | 'push' | 'side' = 'over'; + @Input() + get mode() { return this._mode; } + set mode(value) { + this._mode = value; + this._modeChanged.next(); + } + private _mode: 'over' | 'push' | 'side' = 'over'; /** Whether the drawer can be closed with the escape key or by clicking on the backdrop. */ @Input() @@ -160,6 +182,8 @@ export class MdDrawer implements AfterContentInit, OnDestroy { /** @deprecated */ @Output('align-changed') onAlignChanged = new EventEmitter(); + _modeChanged = new Subject(); + get isFocusTrapEnabled() { // The focus trap is only enabled when the drawer is open in any mode other than side. return this.opened && this.mode !== 'side'; @@ -298,6 +322,7 @@ export class MdDrawer implements AfterContentInit, OnDestroy { } } + /** * component. * @@ -322,6 +347,8 @@ export class MdDrawer implements AfterContentInit, OnDestroy { export class MdDrawerContainer implements AfterContentInit, OnDestroy { @ContentChildren(MdDrawer) _drawers: QueryList; + @ContentChild(MdDrawerContent) _content: MdDrawerContent; + /** The drawer child with the `start` position. */ get start() { return this._start; } @@ -366,6 +393,7 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { this._drawers.forEach((drawer: MdDrawer) => { this._watchDrawerToggle(drawer); this._watchDrawerPosition(drawer); + this._watchDrawerMode(drawer); }); }); } @@ -421,6 +449,14 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { }); } + /** Subscribes to changes in drawer mode so we can run change detection. */ + private _watchDrawerMode(drawer: MdDrawer): void { + if (drawer) { + takeUntil.call(drawer._modeChanged, this._drawers.changes).subscribe( + () => this._changeDetectorRef.markForCheck()); + } + } + /** Toggles the 'mat-drawer-opened' class on the main 'md-drawer-container' element. */ private _setContainerClass(isAdd: boolean): void { if (isAdd) { diff --git a/src/lib/sidenav/sidenav-container.html b/src/lib/sidenav/sidenav-container.html new file mode 100644 index 000000000000..7068bbdf4382 --- /dev/null +++ b/src/lib/sidenav/sidenav-container.html @@ -0,0 +1,10 @@ +
+ + + + + + + + diff --git a/src/lib/sidenav/sidenav-module.ts b/src/lib/sidenav/sidenav-module.ts index 16f14d9d98fc..577f9205826c 100644 --- a/src/lib/sidenav/sidenav-module.ts +++ b/src/lib/sidenav/sidenav-module.ts @@ -6,18 +6,33 @@ * found in the LICENSE file at https://angular.io/license */ -import {NgModule} from '@angular/core'; -import {CommonModule} from '@angular/common'; import {A11yModule} from '@angular/cdk/a11y'; import {OverlayModule} from '@angular/cdk/overlay'; +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; import {MdCommonModule} from '@angular/material/core'; -import {MdDrawer, MdDrawerContainer} from './drawer'; -import {MdSidenav, MdSidenavContainer} from './sidenav'; +import {MdDrawer, MdDrawerContainer, MdDrawerContent} from './drawer'; +import {MdSidenav, MdSidenavContainer, MdSidenavContent} from './sidenav'; @NgModule({ imports: [CommonModule, MdCommonModule, A11yModule, OverlayModule], - exports: [MdDrawerContainer, MdDrawer, MdSidenavContainer, MdSidenav, MdCommonModule], - declarations: [MdDrawerContainer, MdDrawer, MdSidenavContainer, MdSidenav], + exports: [ + MdCommonModule, + MdDrawer, + MdDrawerContainer, + MdDrawerContent, + MdSidenav, + MdSidenavContainer, + MdSidenavContent, + ], + declarations: [ + MdDrawer, + MdDrawerContainer, + MdDrawerContent, + MdSidenav, + MdSidenavContainer, + MdSidenavContent, + ], }) export class MdSidenavModule {} diff --git a/src/lib/sidenav/sidenav.ts b/src/lib/sidenav/sidenav.ts index 12e8b925bcfa..7bc08d9a4570 100644 --- a/src/lib/sidenav/sidenav.ts +++ b/src/lib/sidenav/sidenav.ts @@ -8,7 +8,7 @@ import { ChangeDetectionStrategy, - Component, + Component, ContentChild, ContentChildren, ViewEncapsulation } from '@angular/core'; @@ -16,10 +16,23 @@ import {MdDrawer, MdDrawerContainer} from './drawer'; import {animate, state, style, transition, trigger} from '@angular/animations'; +@Component({ + moduleId: module.id, + selector: 'md-sidenav-content, mat-sidenav-content', + template: '', + host: { + 'class': 'mat-drawer-content mat-sidenav-content', + }, + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, +}) +export class MdSidenavContent {} + + @Component({ moduleId: module.id, selector: 'md-sidenav, mat-sidenav', - templateUrl: 'drawer.html', + template: '', animations: [ trigger('transform', [ state('open, open-instant', style({ @@ -58,7 +71,7 @@ export class MdSidenav extends MdDrawer {} @Component({ moduleId: module.id, selector: 'md-sidenav-container, mat-sidenav-container', - templateUrl: 'drawer-container.html', + templateUrl: 'sidenav-container.html', styleUrls: [ 'drawer.css', 'drawer-transitions.css', @@ -72,4 +85,6 @@ export class MdSidenav extends MdDrawer {} }) export class MdSidenavContainer extends MdDrawerContainer { @ContentChildren(MdSidenav) _drawers; + + @ContentChild(MdSidenavContent) _content; } From 53cd1bc0e769309b52027604ae50e68626644b6e Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 22 Aug 2017 14:28:35 -0700 Subject: [PATCH 02/11] add back margins on content --- src/lib/sidenav/drawer-transitions.scss | 2 +- src/lib/sidenav/drawer.ts | 79 ++++++++++++++++--------- src/lib/sidenav/sidenav.ts | 38 ++++++++++-- 3 files changed, 84 insertions(+), 35 deletions(-) diff --git a/src/lib/sidenav/drawer-transitions.scss b/src/lib/sidenav/drawer-transitions.scss index f14d83784f24..7be6e763b610 100644 --- a/src/lib/sidenav/drawer-transitions.scss +++ b/src/lib/sidenav/drawer-transitions.scss @@ -6,7 +6,7 @@ transition: { duration: $swift-ease-out-duration; timing-function: $swift-ease-out-timing-function; - property: transform, margin-left, margin-right; + property: margin-left, margin-right; } } diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts index 26714f720180..90a888dacbcf 100644 --- a/src/lib/sidenav/drawer.ts +++ b/src/lib/sidenav/drawer.ts @@ -20,6 +20,7 @@ import { ContentChildren, ElementRef, EventEmitter, + forwardRef, Inject, Input, NgZone, @@ -60,11 +61,28 @@ export class MdDrawerToggleResult { template: '', host: { 'class': 'mat-drawer-content', + '[style.marginLeft.px]': '_margins.left', + '[style.marginRight.px]': '_margins.right', }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, }) -export class MdDrawerContent {} +export class MdDrawerContent implements AfterContentInit { + /** Margins to be applied to the content. */ + _margins: {left: number, right: number} = {left: 0, right: 0}; + + constructor( + private _changeDetectorRef: ChangeDetectorRef, + @Inject(forwardRef(() => MdDrawerContainer)) private _container: MdDrawerContainer) { + } + + ngAfterContentInit() { + this._container._contentMargins.subscribe((margins) => { + this._margins = margins; + this._changeDetectorRef.markForCheck(); + }); + } +} /** @@ -374,8 +392,7 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { /** Subscription to the Directionality change EventEmitter. */ private _dirChangeSubscription = Subscription.EMPTY; - /** Inline styles to be applied to the container. */ - _styles: { marginLeft: string; marginRight: string; transform: string; }; + _contentMargins = new Subject<{left: number, right: number}>(); constructor(@Optional() private _dir: Directionality, private _element: ElementRef, private _renderer: Renderer2, private _ngZone: NgZone, @@ -422,7 +439,7 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { // Set the transition class on the container so that the animations occur. This should not // be set initially because animations should only be triggered via a change in state. this._renderer.addClass(this._element.nativeElement, 'mat-drawer-transition'); - this._updateStyles(); + this._updateContentMargins(); this._changeDetectorRef.markForCheck(); }); @@ -452,8 +469,10 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { /** Subscribes to changes in drawer mode so we can run change detection. */ private _watchDrawerMode(drawer: MdDrawer): void { if (drawer) { - takeUntil.call(drawer._modeChanged, this._drawers.changes).subscribe( - () => this._changeDetectorRef.markForCheck()); + takeUntil.call(drawer._modeChanged, this._drawers.changes).subscribe(() => { + this._updateContentMargins(); + this._changeDetectorRef.markForCheck() + }); } } @@ -519,29 +538,33 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { } /** - * Return the width of the drawer, if it's in the proper mode and opened. - * This may relayout the view, so do not call this often. - * @param drawer - * @param mode + * Recalculates and updates the inline styles for the content. Note that this should be used + * sparingly, because it causes a reflow. */ - private _getDrawerEffectiveWidth(drawer: MdDrawer, mode: string): number { - return (this._isDrawerOpen(drawer) && drawer.mode == mode) ? drawer._width : 0; - } + private _updateContentMargins() { + let left = 0; + let right = 0; + + if (this._left && this._left.opened) { + if (this._left.mode == 'side') { + left += this._left._width; + } else if (this._left.mode == 'push') { + let width = this._left._width; + left += width; + right -= width; + } + } - /** - * Recalculates and updates the inline styles. Note that this - * should be used sparingly, because it causes a reflow. - */ - private _updateStyles() { - const marginLeft = this._left ? this._getDrawerEffectiveWidth(this._left, 'side') : 0; - const marginRight = this._right ? this._getDrawerEffectiveWidth(this._right, 'side') : 0; - const leftWidth = this._left ? this._getDrawerEffectiveWidth(this._left, 'push') : 0; - const rightWidth = this._right ? this._getDrawerEffectiveWidth(this._right, 'push') : 0; - - this._styles = { - marginLeft: `${marginLeft}px`, - marginRight: `${marginRight}px`, - transform: `translate3d(${leftWidth - rightWidth}px, 0, 0)` - }; + if (this._right && this._right.opened) { + if (this._right.mode == 'side') { + right += this._right._width; + } else if (this._right.mode == 'push') { + let width = this._right._width; + right += width; + left -= width; + } + } + + this._contentMargins.next({left, right}); } } diff --git a/src/lib/sidenav/sidenav.ts b/src/lib/sidenav/sidenav.ts index 7bc08d9a4570..01d45178d935 100644 --- a/src/lib/sidenav/sidenav.ts +++ b/src/lib/sidenav/sidenav.ts @@ -7,12 +7,12 @@ */ import { - ChangeDetectionStrategy, + ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, - ContentChildren, + ContentChildren, forwardRef, Inject, Input, ViewEncapsulation } from '@angular/core'; -import {MdDrawer, MdDrawerContainer} from './drawer'; +import {MdDrawer, MdDrawerContainer, MdDrawerContent} from './drawer'; import {animate, state, style, transition, trigger} from '@angular/animations'; @@ -22,11 +22,19 @@ import {animate, state, style, transition, trigger} from '@angular/animations'; template: '', host: { 'class': 'mat-drawer-content mat-sidenav-content', + '[style.marginLeft.px]': '_margins.left', + '[style.marginRight.px]': '_margins.right', }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, }) -export class MdSidenavContent {} +export class MdSidenavContent extends MdDrawerContent { + constructor( + changeDetectorRef: ChangeDetectorRef, + @Inject(forwardRef(() => MdSidenavContainer)) container: MdSidenavContainer) { + super(changeDetectorRef, container); + } +} @Component({ @@ -49,6 +57,7 @@ export class MdSidenavContent {} ], host: { 'class': 'mat-drawer mat-sidenav', + 'tabIndex': '-1', '[@transform]': '_animationState', '(@transform.start)': '_onAnimationStart()', '(@transform.done)': '_onAnimationEnd($event)', @@ -59,13 +68,30 @@ export class MdSidenavContent {} '[class.mat-drawer-over]': 'mode === "over"', '[class.mat-drawer-push]': 'mode === "push"', '[class.mat-drawer-side]': 'mode === "side"', - 'tabIndex': '-1', + '[class.mat-app-sidenav-fixed]': 'fixedInViewport', + '[style.top.px]': 'fixedInViewport ? fixedTopGap : null', + '[style.bottom.px]': 'fixedInViewport ? fixedBottomGap : null', }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, }) -export class MdSidenav extends MdDrawer {} +export class MdSidenav extends MdDrawer { + /** Whether the sidenav is fixed in the viewport. */ + @Input() fixedInViewport = true; + + /** + * The gap between the top of the sidenav and the top of the viewport when the sidenav is in fixed + * mode. + */ + @Input() fixedTopGap = 0; + + /** + * The gap between the bottom of the sidenav and the bottom of the viewport when the sidenav is in + * fixed mode. + */ + @Input() fixedBottomGap = 0; +} @Component({ From 3b53330216e47047ce5c287772d5c6db79fb1596 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 22 Aug 2017 16:08:06 -0700 Subject: [PATCH 03/11] stop using transform on container and content --- src/lib/sidenav/drawer.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/sidenav/drawer.scss b/src/lib/sidenav/drawer.scss index 9d46906c21fd..24100e425f6b 100644 --- a/src/lib/sidenav/drawer.scss +++ b/src/lib/sidenav/drawer.scss @@ -10,8 +10,9 @@ @mixin mat-drawer-stacking-context() { position: relative; - // Use a transform to create a new stacking context. - transform: translate3d(0, 0, 0); + // Use a z-index to create a new stacking context. (We can't use transform because it breaks fixed + // positioning inside of the transformed element). + z-index: 1; } .mat-drawer-container { From 101f5b56e64f9eba01022b79dc6620b9abbff146 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 22 Aug 2017 17:11:37 -0700 Subject: [PATCH 04/11] change sidenav demo to drawer --- src/demo-app/demo-app/demo-app.ts | 2 +- src/demo-app/demo-app/demo-module.ts | 4 +- src/demo-app/demo-app/routes.ts | 4 +- .../drawer-demo.html} | 60 +++++++++---------- src/demo-app/drawer/drawer-demo.scss | 7 +++ .../sidenav-demo.ts => drawer/drawer-demo.ts} | 8 +-- src/demo-app/sidenav/sidenav-demo.scss | 11 ---- 7 files changed, 46 insertions(+), 50 deletions(-) rename src/demo-app/{sidenav/sidenav-demo.html => drawer/drawer-demo.html} (55%) create mode 100644 src/demo-app/drawer/drawer-demo.scss rename src/demo-app/{sidenav/sidenav-demo.ts => drawer/drawer-demo.ts} (60%) delete mode 100644 src/demo-app/sidenav/sidenav-demo.scss diff --git a/src/demo-app/demo-app/demo-app.ts b/src/demo-app/demo-app/demo-app.ts index 26d96a4ee0e0..1b8eff666302 100644 --- a/src/demo-app/demo-app/demo-app.ts +++ b/src/demo-app/demo-app/demo-app.ts @@ -55,6 +55,7 @@ export class DemoApp { {name: 'Checkbox', route: '/checkbox'}, {name: 'Datepicker', route: '/datepicker'}, {name: 'Dialog', route: '/dialog'}, + {name: 'Drawer', route: '/drawer'}, {name: 'Expansion Panel', route: '/expansion'}, {name: 'Gestures', route: '/gestures'}, {name: 'Grid List', route: '/grid-list'}, @@ -70,7 +71,6 @@ export class DemoApp { {name: 'Radio', route: '/radio'}, {name: 'Ripple', route: '/ripple'}, {name: 'Select', route: '/select'}, - {name: 'Sidenav', route: '/sidenav'}, {name: 'Slider', route: '/slider'}, {name: 'Slide Toggle', route: '/slide-toggle'}, {name: 'Snack Bar', route: '/snack-bar'}, diff --git a/src/demo-app/demo-app/demo-module.ts b/src/demo-app/demo-app/demo-module.ts index 59a632277ee1..5f0f6d3680a4 100644 --- a/src/demo-app/demo-app/demo-module.ts +++ b/src/demo-app/demo-app/demo-module.ts @@ -26,7 +26,7 @@ import {ButtonDemo} from '../button/button-demo'; import {CheckboxDemo, MdCheckboxDemoNestedChecklist} from '../checkbox/checkbox-demo'; import {SelectDemo} from '../select/select-demo'; import {SliderDemo} from '../slider/slider-demo'; -import {SidenavDemo} from '../sidenav/sidenav-demo'; +import {DrawerDemo} from '../drawer/drawer-demo'; import {SnackBarDemo} from '../snack-bar/snack-bar-demo'; import {PortalDemo, ScienceJoke} from '../portal/portal-demo'; import {MenuDemo} from '../menu/menu-demo'; @@ -89,7 +89,7 @@ import {TableHeaderDemo} from '../table/table-header-demo'; RotiniPanel, ScienceJoke, SelectDemo, - SidenavDemo, + DrawerDemo, SliderDemo, SlideToggleDemo, SpagettiPanel, diff --git a/src/demo-app/demo-app/routes.ts b/src/demo-app/demo-app/routes.ts index 7ee134565fdb..1bc65ce5eed5 100644 --- a/src/demo-app/demo-app/routes.ts +++ b/src/demo-app/demo-app/routes.ts @@ -16,7 +16,7 @@ import {PortalDemo} from '../portal/portal-demo'; import {ProgressBarDemo} from '../progress-bar/progress-bar-demo'; import {ProgressSpinnerDemo} from '../progress-spinner/progress-spinner-demo'; import {SelectDemo} from '../select/select-demo'; -import {SidenavDemo} from '../sidenav/sidenav-demo'; +import {DrawerDemo} from '../drawer/drawer-demo'; import {SlideToggleDemo} from '../slide-toggle/slide-toggle-demo'; import {SliderDemo} from '../slider/slider-demo'; import {RadioDemo} from '../radio/radio-demo'; @@ -52,7 +52,7 @@ export const DEMO_APP_ROUTES: Routes = [ {path: 'datepicker', component: DatepickerDemo}, {path: 'radio', component: RadioDemo}, {path: 'select', component: SelectDemo}, - {path: 'sidenav', component: SidenavDemo}, + {path: 'drawer', component: DrawerDemo}, {path: 'slide-toggle', component: SlideToggleDemo}, {path: 'slider', component: SliderDemo}, {path: 'progress-spinner', component: ProgressSpinnerDemo}, diff --git a/src/demo-app/sidenav/sidenav-demo.html b/src/demo-app/drawer/drawer-demo.html similarity index 55% rename from src/demo-app/sidenav/sidenav-demo.html rename to src/demo-app/drawer/drawer-demo.html index bdddd69c381a..3a2dddc4d1d2 100644 --- a/src/demo-app/sidenav/sidenav-demo.html +++ b/src/demo-app/drawer/drawer-demo.html @@ -1,7 +1,7 @@

Basic Use Case

- - + + Start Side Drawer
@@ -13,19 +13,19 @@

Basic Use Case

Mode: {{start.mode}}

-
+
- + End Side Drawer
-
+ -
+

My Content

-
Sidenav
+
Drawer
@@ -34,38 +34,38 @@

My Content

- + -

Sidenav Already Opened

+

Drawer Already Opened

- - + + Drawer - + -
+
- + -

Dynamic Position Sidenav

+

Dynamic Position Drawer

- - Start - End + + Start + End -
-
-
+ -

Sidenav with focus attributes

+

Drawer with focus attributes

- - + + Link Focus region start @@ -74,14 +74,14 @@

Sidenav with focus attributes

Focus region end Link
-
+ -
+

My Content

-
Sidenav
- +
Drawer
+
- + diff --git a/src/demo-app/drawer/drawer-demo.scss b/src/demo-app/drawer/drawer-demo.scss new file mode 100644 index 000000000000..1bf747c0615b --- /dev/null +++ b/src/demo-app/drawer/drawer-demo.scss @@ -0,0 +1,7 @@ +.demo-drawer-container { + border: 3px solid black; +} + +.demo-drawer-content { + padding: 15px; +} diff --git a/src/demo-app/sidenav/sidenav-demo.ts b/src/demo-app/drawer/drawer-demo.ts similarity index 60% rename from src/demo-app/sidenav/sidenav-demo.ts rename to src/demo-app/drawer/drawer-demo.ts index 60be081c2a85..87a740988f7e 100644 --- a/src/demo-app/sidenav/sidenav-demo.ts +++ b/src/demo-app/drawer/drawer-demo.ts @@ -3,12 +3,12 @@ import {Component, ViewEncapsulation} from '@angular/core'; @Component({ moduleId: module.id, - selector: 'sidenav-demo', - templateUrl: 'sidenav-demo.html', - styleUrls: ['sidenav-demo.css'], + selector: 'drawer-demo', + templateUrl: 'drawer-demo.html', + styleUrls: ['drawer-demo.css'], encapsulation: ViewEncapsulation.None, preserveWhitespaces: false, }) -export class SidenavDemo { +export class DrawerDemo { invert = false; } diff --git a/src/demo-app/sidenav/sidenav-demo.scss b/src/demo-app/sidenav/sidenav-demo.scss deleted file mode 100644 index a04b3bb58124..000000000000 --- a/src/demo-app/sidenav/sidenav-demo.scss +++ /dev/null @@ -1,11 +0,0 @@ -.demo-sidenav-container { - border: 3px solid black; - - .mat-sidenav-focus-trap > .cdk-focus-trap-content { - padding: 10px; - } -} - -.demo-sidenav-content { - padding: 15px; -} From 40d760ee62b121dd1c777b5d95bb735d873971cc Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 29 Aug 2017 15:07:00 -0700 Subject: [PATCH 05/11] create sidenav demo --- src/demo-app/demo-app/demo-app.ts | 21 +++-- src/demo-app/demo-app/demo-module.ts | 101 ++++++++++++------------ src/demo-app/demo-app/routes.ts | 103 +++++++++++++------------ src/demo-app/sidenav/sidenav-demo.html | 53 +++++++++++++ src/demo-app/sidenav/sidenav-demo.scss | 23 ++++++ src/demo-app/sidenav/sidenav-demo.ts | 14 ++++ src/lib/sidenav/drawer.scss | 17 ++-- 7 files changed, 212 insertions(+), 120 deletions(-) create mode 100644 src/demo-app/sidenav/sidenav-demo.html create mode 100644 src/demo-app/sidenav/sidenav-demo.scss create mode 100644 src/demo-app/sidenav/sidenav-demo.ts diff --git a/src/demo-app/demo-app/demo-app.ts b/src/demo-app/demo-app/demo-app.ts index 1b8eff666302..95c70b92cf21 100644 --- a/src/demo-app/demo-app/demo-app.ts +++ b/src/demo-app/demo-app/demo-app.ts @@ -1,10 +1,5 @@ -import { - Component, - ViewEncapsulation, - ElementRef, - Renderer2, -} from '@angular/core'; import {OverlayContainer} from '@angular/cdk/overlay'; +import {Component, ElementRef, Renderer2, ViewEncapsulation,} from '@angular/core'; /** * The entry app for demo site. Routes under `accessibility` will use AccessibilityDemo component, @@ -48,39 +43,41 @@ export class DemoApp { dark = false; navItems = [ {name: 'Autocomplete', route: '/autocomplete'}, - {name: 'Button', route: '/button'}, {name: 'Button Toggle', route: '/button-toggle'}, + {name: 'Button', route: '/button'}, {name: 'Card', route: '/card'}, - {name: 'Chips', route: '/chips'}, {name: 'Checkbox', route: '/checkbox'}, + {name: 'Chips', route: '/chips'}, {name: 'Datepicker', route: '/datepicker'}, {name: 'Dialog', route: '/dialog'}, {name: 'Drawer', route: '/drawer'}, {name: 'Expansion Panel', route: '/expansion'}, + {name: 'Focus Origin', route: '/focus-origin'}, {name: 'Gestures', route: '/gestures'}, {name: 'Grid List', route: '/grid-list'}, {name: 'Icon', route: '/icon'}, {name: 'Input', route: '/input'}, {name: 'List', route: '/list'}, - {name: 'Menu', route: '/menu'}, {name: 'Live Announcer', route: '/live-announcer'}, + {name: 'Menu', route: '/menu'}, {name: 'Overlay', route: '/overlay'}, + {name: 'Platform', route: '/platform'}, {name: 'Portal', route: '/portal'}, {name: 'Progress Bar', route: '/progress-bar'}, {name: 'Progress Spinner', route: '/progress-spinner'}, {name: 'Radio', route: '/radio'}, {name: 'Ripple', route: '/ripple'}, {name: 'Select', route: '/select'}, - {name: 'Slider', route: '/slider'}, + {name: 'Sidenav', route: '/sidenav'}, {name: 'Slide Toggle', route: '/slide-toggle'}, + {name: 'Slider', route: '/slider'}, {name: 'Snack Bar', route: '/snack-bar'}, {name: 'Stepper', route: '/stepper'}, + {name: 'Style', route: '/style'}, {name: 'Table', route: '/table'}, {name: 'Tabs', route: '/tabs'}, {name: 'Toolbar', route: '/toolbar'}, {name: 'Tooltip', route: '/tooltip'}, - {name: 'Platform', route: '/platform'}, - {name: 'Focus Origin', route: '/focus-origin'}, {name: 'Typography', route: '/typography'} ]; diff --git a/src/demo-app/demo-app/demo-module.ts b/src/demo-app/demo-app/demo-module.ts index 5f0f6d3680a4..850f080fc811 100644 --- a/src/demo-app/demo-app/demo-module.ts +++ b/src/demo-app/demo-app/demo-module.ts @@ -1,52 +1,50 @@ -import {NgModule} from '@angular/core'; +import {FullscreenOverlayContainer, OverlayContainer,} from '@angular/cdk/overlay'; import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {RouterModule} from '@angular/router'; -import {DemoApp, Home} from './demo-app'; -import {DEMO_APP_ROUTES} from './routes'; -import {ProgressBarDemo} from '../progress-bar/progress-bar-demo'; -import {ContentElementDialog, DialogDemo, IFrameDialog, JazzDialog} from '../dialog/dialog-demo'; -import {RippleDemo} from '../ripple/ripple-demo'; -import {IconDemo} from '../icon/icon-demo'; -import {GesturesDemo} from '../gestures/gestures-demo'; +import {AutocompleteDemo} from '../autocomplete/autocomplete-demo'; +import {BaselineDemo} from '../baseline/baseline-demo'; +import {ButtonToggleDemo} from '../button-toggle/button-toggle-demo'; +import {ButtonDemo} from '../button/button-demo'; import {CardDemo} from '../card/card-demo'; +import {CheckboxDemo, MdCheckboxDemoNestedChecklist} from '../checkbox/checkbox-demo'; import {ChipsDemo} from '../chips/chips-demo'; -import {RadioDemo} from '../radio/radio-demo'; -import {ButtonToggleDemo} from '../button-toggle/button-toggle-demo'; -import {ProgressSpinnerDemo} from '../progress-spinner/progress-spinner-demo'; -import {TooltipDemo} from '../tooltip/tooltip-demo'; -import {ListDemo} from '../list/list-demo'; -import {BaselineDemo} from '../baseline/baseline-demo'; +import {DatepickerDemo} from '../datepicker/datepicker-demo'; +import {DemoMaterialModule} from '../demo-material-module'; +import {ContentElementDialog, DialogDemo, IFrameDialog, JazzDialog} from '../dialog/dialog-demo'; +import {DrawerDemo} from '../drawer/drawer-demo'; +import {ExpansionDemo} from '../expansion/expansion-demo'; +import {FocusOriginDemo} from '../focus-origin/focus-origin-demo'; +import {GesturesDemo} from '../gestures/gestures-demo'; import {GridListDemo} from '../grid-list/grid-list-demo'; +import {IconDemo} from '../icon/icon-demo'; +import {InputDemo} from '../input/input-demo'; +import {ListDemo} from '../list/list-demo'; import {LiveAnnouncerDemo} from '../live-announcer/live-announcer-demo'; +import {MenuDemo} from '../menu/menu-demo'; import {OverlayDemo, RotiniPanel, SpagettiPanel} from '../overlay/overlay-demo'; -import {SlideToggleDemo} from '../slide-toggle/slide-toggle-demo'; -import {ToolbarDemo} from '../toolbar/toolbar-demo'; -import {ButtonDemo} from '../button/button-demo'; -import {CheckboxDemo, MdCheckboxDemoNestedChecklist} from '../checkbox/checkbox-demo'; +import {PlatformDemo} from '../platform/platform-demo'; +import {PortalDemo, ScienceJoke} from '../portal/portal-demo'; +import {ProgressBarDemo} from '../progress-bar/progress-bar-demo'; +import {ProgressSpinnerDemo} from '../progress-spinner/progress-spinner-demo'; +import {RadioDemo} from '../radio/radio-demo'; +import {RippleDemo} from '../ripple/ripple-demo'; import {SelectDemo} from '../select/select-demo'; +import {SidenavDemo} from '../sidenav/sidenav-demo'; +import {SlideToggleDemo} from '../slide-toggle/slide-toggle-demo'; import {SliderDemo} from '../slider/slider-demo'; -import {DrawerDemo} from '../drawer/drawer-demo'; import {SnackBarDemo} from '../snack-bar/snack-bar-demo'; -import {PortalDemo, ScienceJoke} from '../portal/portal-demo'; -import {MenuDemo} from '../menu/menu-demo'; -import {FoggyTabContent, RainyTabContent, SunnyTabContent, TabsDemo} from '../tabs/tabs-demo'; -import {PlatformDemo} from '../platform/platform-demo'; -import {AutocompleteDemo} from '../autocomplete/autocomplete-demo'; -import {InputDemo} from '../input/input-demo'; -import {FocusOriginDemo} from '../focus-origin/focus-origin-demo'; -import {TableDemo} from '../table/table-demo'; -import {PeopleDatabase} from '../table/people-database'; -import {DatepickerDemo} from '../datepicker/datepicker-demo'; -import {TypographyDemo} from '../typography/typography-demo'; -import {ExpansionDemo} from '../expansion/expansion-demo'; import {StepperDemo} from '../stepper/stepper-demo'; -import {DemoMaterialModule} from '../demo-material-module'; -import { - FullscreenOverlayContainer, - OverlayContainer, -} from '@angular/cdk/overlay'; +import {PeopleDatabase} from '../table/people-database'; +import {TableDemo} from '../table/table-demo'; import {TableHeaderDemo} from '../table/table-header-demo'; +import {FoggyTabContent, RainyTabContent, SunnyTabContent, TabsDemo} from '../tabs/tabs-demo'; +import {ToolbarDemo} from '../toolbar/toolbar-demo'; +import {TooltipDemo} from '../tooltip/tooltip-demo'; +import {TypographyDemo} from '../typography/typography-demo'; +import {DemoApp, Home} from './demo-app'; +import {DEMO_APP_ROUTES} from './routes'; @NgModule({ imports: [ @@ -62,60 +60,61 @@ import {TableHeaderDemo} from '../table/table-header-demo'; ButtonDemo, ButtonToggleDemo, CardDemo, - ChipsDemo, CheckboxDemo, + ChipsDemo, + ContentElementDialog, DatepickerDemo, DemoApp, DialogDemo, + DrawerDemo, + ExpansionDemo, + FocusOriginDemo, + FoggyTabContent, GesturesDemo, GridListDemo, Home, IconDemo, + IFrameDialog, InputDemo, JazzDialog, - ContentElementDialog, - IFrameDialog, ListDemo, LiveAnnouncerDemo, MdCheckboxDemoNestedChecklist, MenuDemo, - SnackBarDemo, OverlayDemo, + PlatformDemo, PortalDemo, ProgressBarDemo, ProgressSpinnerDemo, RadioDemo, + RainyTabContent, RippleDemo, RotiniPanel, ScienceJoke, SelectDemo, - DrawerDemo, + SidenavDemo, SliderDemo, SlideToggleDemo, + SnackBarDemo, SpagettiPanel, StepperDemo, - FocusOriginDemo, + SunnyTabContent, + TableDemo, TableHeaderDemo, + TabsDemo, ToolbarDemo, TooltipDemo, - TableDemo, - TabsDemo, - SunnyTabContent, - RainyTabContent, - FoggyTabContent, - PlatformDemo, TypographyDemo, - ExpansionDemo, ], providers: [ {provide: OverlayContainer, useClass: FullscreenOverlayContainer}, PeopleDatabase ], entryComponents: [ - DemoApp, - JazzDialog, ContentElementDialog, + DemoApp, IFrameDialog, + JazzDialog, RotiniPanel, ScienceJoke, SpagettiPanel, diff --git a/src/demo-app/demo-app/routes.ts b/src/demo-app/demo-app/routes.ts index 1bc65ce5eed5..cebe53bdb29e 100644 --- a/src/demo-app/demo-app/routes.ts +++ b/src/demo-app/demo-app/routes.ts @@ -1,85 +1,86 @@ import {Routes} from '@angular/router'; -import {Home} from './demo-app'; -import {ButtonDemo} from '../button/button-demo'; +import {AccessibilityDemo} from '../a11y/a11y'; +import {ACCESSIBILITY_DEMO_ROUTES} from '../a11y/routes'; +import {AutocompleteDemo} from '../autocomplete/autocomplete-demo'; import {BaselineDemo} from '../baseline/baseline-demo'; import {ButtonToggleDemo} from '../button-toggle/button-toggle-demo'; -import {TabsDemo} from '../tabs/tabs-demo'; -import {GridListDemo} from '../grid-list/grid-list-demo'; +import {ButtonDemo} from '../button/button-demo'; +import {CardDemo} from '../card/card-demo'; +import {CheckboxDemo} from '../checkbox/checkbox-demo'; +import {ChipsDemo} from '../chips/chips-demo'; +import {DatepickerDemo} from '../datepicker/datepicker-demo'; +import {DialogDemo} from '../dialog/dialog-demo'; +import {DrawerDemo} from '../drawer/drawer-demo'; +import {ExpansionDemo} from '../expansion/expansion-demo'; +import {FocusOriginDemo} from '../focus-origin/focus-origin-demo'; import {GesturesDemo} from '../gestures/gestures-demo'; -import {LiveAnnouncerDemo} from '../live-announcer/live-announcer-demo'; -import {ListDemo} from '../list/list-demo'; +import {GridListDemo} from '../grid-list/grid-list-demo'; import {IconDemo} from '../icon/icon-demo'; -import {ToolbarDemo} from '../toolbar/toolbar-demo'; -import {CheckboxDemo} from '../checkbox/checkbox-demo'; +import {InputDemo} from '../input/input-demo'; +import {ListDemo} from '../list/list-demo'; +import {LiveAnnouncerDemo} from '../live-announcer/live-announcer-demo'; +import {MenuDemo} from '../menu/menu-demo'; import {OverlayDemo} from '../overlay/overlay-demo'; +import {PlatformDemo} from '../platform/platform-demo'; import {PortalDemo} from '../portal/portal-demo'; import {ProgressBarDemo} from '../progress-bar/progress-bar-demo'; import {ProgressSpinnerDemo} from '../progress-spinner/progress-spinner-demo'; +import {RadioDemo} from '../radio/radio-demo'; +import {RippleDemo} from '../ripple/ripple-demo'; import {SelectDemo} from '../select/select-demo'; -import {DrawerDemo} from '../drawer/drawer-demo'; +import {SidenavDemo} from '../sidenav/sidenav-demo'; import {SlideToggleDemo} from '../slide-toggle/slide-toggle-demo'; import {SliderDemo} from '../slider/slider-demo'; -import {RadioDemo} from '../radio/radio-demo'; -import {CardDemo} from '../card/card-demo'; -import {ChipsDemo} from '../chips/chips-demo'; -import {MenuDemo} from '../menu/menu-demo'; -import {RippleDemo} from '../ripple/ripple-demo'; -import {DialogDemo} from '../dialog/dialog-demo'; -import {TooltipDemo} from '../tooltip/tooltip-demo'; import {SnackBarDemo} from '../snack-bar/snack-bar-demo'; -import {TABS_DEMO_ROUTES} from '../tabs/routes'; -import {PlatformDemo} from '../platform/platform-demo'; -import {AutocompleteDemo} from '../autocomplete/autocomplete-demo'; -import {InputDemo} from '../input/input-demo'; -import {FocusOriginDemo} from '../focus-origin/focus-origin-demo'; -import {DatepickerDemo} from '../datepicker/datepicker-demo'; +import {StepperDemo} from '../stepper/stepper-demo'; import {TableDemo} from '../table/table-demo'; +import {TABS_DEMO_ROUTES} from '../tabs/routes'; +import {TabsDemo} from '../tabs/tabs-demo'; +import {ToolbarDemo} from '../toolbar/toolbar-demo'; +import {TooltipDemo} from '../tooltip/tooltip-demo'; import {TypographyDemo} from '../typography/typography-demo'; -import {ExpansionDemo} from '../expansion/expansion-demo'; -import {StepperDemo} from '../stepper/stepper-demo'; -import {DemoApp} from './demo-app'; -import {AccessibilityDemo} from '../a11y/a11y'; -import {ACCESSIBILITY_DEMO_ROUTES} from '../a11y/routes'; +import {DemoApp, Home} from './demo-app'; export const DEMO_APP_ROUTES: Routes = [ {path: '', component: DemoApp, children: [ {path: '', component: Home}, {path: 'autocomplete', component: AutocompleteDemo}, + {path: 'baseline', component: BaselineDemo}, {path: 'button', component: ButtonDemo}, + {path: 'button-toggle', component: ButtonToggleDemo}, {path: 'card', component: CardDemo}, + {path: 'checkbox', component: CheckboxDemo}, {path: 'chips', component: ChipsDemo}, - {path: 'table', component: TableDemo}, {path: 'datepicker', component: DatepickerDemo}, - {path: 'radio', component: RadioDemo}, - {path: 'select', component: SelectDemo}, + {path: 'dialog', component: DialogDemo}, {path: 'drawer', component: DrawerDemo}, - {path: 'slide-toggle', component: SlideToggleDemo}, - {path: 'slider', component: SliderDemo}, - {path: 'progress-spinner', component: ProgressSpinnerDemo}, - {path: 'progress-bar', component: ProgressBarDemo}, - {path: 'portal', component: PortalDemo}, - {path: 'overlay', component: OverlayDemo}, - {path: 'checkbox', component: CheckboxDemo}, - {path: 'input', component: InputDemo}, - {path: 'toolbar', component: ToolbarDemo}, + {path: 'expansion', component: ExpansionDemo}, + {path: 'focus-origin', component: FocusOriginDemo}, + {path: 'gestures', component: GesturesDemo}, + {path: 'grid-list', component: GridListDemo}, {path: 'icon', component: IconDemo}, + {path: 'input', component: InputDemo}, {path: 'list', component: ListDemo}, - {path: 'menu', component: MenuDemo}, {path: 'live-announcer', component: LiveAnnouncerDemo}, - {path: 'gestures', component: GesturesDemo}, - {path: 'grid-list', component: GridListDemo}, - {path: 'tabs', component: TabsDemo, children: TABS_DEMO_ROUTES}, - {path: 'button-toggle', component: ButtonToggleDemo}, - {path: 'baseline', component: BaselineDemo}, + {path: 'menu', component: MenuDemo}, + {path: 'overlay', component: OverlayDemo}, + {path: 'platform', component: PlatformDemo}, + {path: 'portal', component: PortalDemo}, + {path: 'progress-bar', component: ProgressBarDemo}, + {path: 'progress-spinner', component: ProgressSpinnerDemo}, + {path: 'radio', component: RadioDemo}, {path: 'ripple', component: RippleDemo}, - {path: 'dialog', component: DialogDemo}, - {path: 'tooltip', component: TooltipDemo}, + {path: 'select', component: SelectDemo}, + {path: 'sidenav', component: SidenavDemo}, + {path: 'slide-toggle', component: SlideToggleDemo}, + {path: 'slider', component: SliderDemo}, {path: 'snack-bar', component: SnackBarDemo}, - {path: 'platform', component: PlatformDemo}, - {path: 'focus-origin', component: FocusOriginDemo}, + {path: 'stepper', component: StepperDemo}, + {path: 'table', component: TableDemo}, + {path: 'tabs', component: TabsDemo, children: TABS_DEMO_ROUTES}, + {path: 'toolbar', component: ToolbarDemo}, + {path: 'tooltip', component: TooltipDemo}, {path: 'typography', component: TypographyDemo}, - {path: 'expansion', component: ExpansionDemo}, - {path: 'stepper', component: StepperDemo} ]} ]; diff --git a/src/demo-app/sidenav/sidenav-demo.html b/src/demo-app/sidenav/sidenav-demo.html new file mode 100644 index 000000000000..6bc90c1f6ee7 --- /dev/null +++ b/src/demo-app/sidenav/sidenav-demo.html @@ -0,0 +1,53 @@ + + +
+ + + Start Side Sidenav +
+ +
+ +
+ +
Mode: {{start.mode}}
+
+ +
Filler Content
+
+ + + End Side Sidenav +
+ +
Filler Content
+
+ + +
+ +
+ +
+

Sidenav

+ + + + +
+ +
+

Header / Footer

+ + +
+ +
Filler Content
+
+
+
diff --git a/src/demo-app/sidenav/sidenav-demo.scss b/src/demo-app/sidenav/sidenav-demo.scss new file mode 100644 index 000000000000..14867b80481c --- /dev/null +++ b/src/demo-app/sidenav/sidenav-demo.scss @@ -0,0 +1,23 @@ +.demo-sidenav-area { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + + .mat-sidenav-container { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + } + + .mat-sidenav-content { + padding: 32px; + } + + .demo-filler-content { + padding: 60px; + } +} diff --git a/src/demo-app/sidenav/sidenav-demo.ts b/src/demo-app/sidenav/sidenav-demo.ts new file mode 100644 index 000000000000..35670cfdf5e6 --- /dev/null +++ b/src/demo-app/sidenav/sidenav-demo.ts @@ -0,0 +1,14 @@ +import {Component, ViewEncapsulation} from '@angular/core'; + + +@Component({ + moduleId: module.id, + selector: 'sidenav-demo', + templateUrl: 'sidenav-demo.html', + styleUrls: ['sidenav-demo.css'], + encapsulation: ViewEncapsulation.None, +}) +export class SidenavDemo { + isLaunched = false; + fillerContent = Array(30); +} diff --git a/src/lib/sidenav/drawer.scss b/src/lib/sidenav/drawer.scss index 24100e425f6b..f7383ae01bf1 100644 --- a/src/lib/sidenav/drawer.scss +++ b/src/lib/sidenav/drawer.scss @@ -3,16 +3,21 @@ @import '../core/style/layout-common'; @import '../../cdk/a11y/a11y'; +$mat-drawer-content-z-index: 1; +$mat-drawer-side-drawer-z-index: 2; +$mat-drawer-backdrop-z-index: 3; +$mat-drawer-over-drawer-z-index: 4; + // stylelint-disable max-line-length // Mixin that creates a new stacking context. // see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context // stylelint-enable -@mixin mat-drawer-stacking-context() { +@mixin mat-drawer-stacking-context($z-index:1) { position: relative; // Use a z-index to create a new stacking context. (We can't use transform because it breaks fixed // positioning inside of the transformed element). - z-index: 1; + z-index: $z-index; } .mat-drawer-container { @@ -48,7 +53,7 @@ // Because of the new stacking context, the z-index stack is new and we can use our own // numbers. - z-index: 2; + z-index: $mat-drawer-backdrop-z-index; // We use 'visibility: hidden | visible' because 'display: none' will not animate any // transitions, while visibility will interpolate transitions properly. @@ -66,7 +71,7 @@ } .mat-drawer-content { - @include mat-drawer-stacking-context(); + @include mat-drawer-stacking-context($mat-drawer-content-z-index); display: block; height: 100%; @@ -74,7 +79,7 @@ } .mat-drawer { - @include mat-drawer-stacking-context(); + @include mat-drawer-stacking-context($mat-drawer-over-drawer-z-index); display: block; position: absolute; @@ -89,7 +94,7 @@ transform: translate3d(-100%, 0, 0); &.mat-drawer-side { - z-index: 1; + z-index: $mat-drawer-side-drawer-z-index; } &.mat-drawer-end { From 2038cbdcc18ddbe767739e01eeec30e502661a41 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 29 Aug 2017 16:38:21 -0700 Subject: [PATCH 06/11] Finish up demo --- src/demo-app/sidenav/sidenav-demo.html | 51 +++++++++++++++----------- src/demo-app/sidenav/sidenav-demo.scss | 14 ++++--- src/demo-app/sidenav/sidenav-demo.ts | 8 ++++ src/lib/sidenav/drawer.scss | 5 ++- src/lib/sidenav/sidenav.ts | 2 +- 5 files changed, 50 insertions(+), 30 deletions(-) diff --git a/src/demo-app/sidenav/sidenav-demo.html b/src/demo-app/sidenav/sidenav-demo.html index 6bc90c1f6ee7..fdc13d483172 100644 --- a/src/demo-app/sidenav/sidenav-demo.html +++ b/src/demo-app/sidenav/sidenav-demo.html @@ -3,23 +3,25 @@
+ Header - + Start Side Sidenav


- +
Mode: {{start.mode}}

Filler Content
- + End Side Sidenav
@@ -27,27 +29,32 @@
-
- -
+ Header +
+
+ +
-
-

Sidenav

- - - - -
+
+

Sidenav

+ + + Fixed mode + Sidenav covers header/footer +
-
-

Header / Footer

- - -
+
+

Header / Footer

+ Show header + Show footer +
-
Filler Content
+
Filler Content
+
+ Footer
+ Footer
diff --git a/src/demo-app/sidenav/sidenav-demo.scss b/src/demo-app/sidenav/sidenav-demo.scss index 14867b80481c..b9b359f85460 100644 --- a/src/demo-app/sidenav/sidenav-demo.scss +++ b/src/demo-app/sidenav/sidenav-demo.scss @@ -4,16 +4,18 @@ bottom: 0; left: 0; right: 0; + display: flex; + flex-direction: column; + + .mat-toolbar { + flex: 0; + } .mat-sidenav-container { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; + flex: 1; } - .mat-sidenav-content { + .demo-sidenav-content { padding: 32px; } diff --git a/src/demo-app/sidenav/sidenav-demo.ts b/src/demo-app/sidenav/sidenav-demo.ts index 35670cfdf5e6..37a8873aad82 100644 --- a/src/demo-app/sidenav/sidenav-demo.ts +++ b/src/demo-app/sidenav/sidenav-demo.ts @@ -11,4 +11,12 @@ import {Component, ViewEncapsulation} from '@angular/core'; export class SidenavDemo { isLaunched = false; fillerContent = Array(30); + fixed = false; + coverHeader = false; + showHeader = false; + showFooter = false; + modeIndex = 0; + get mode() { return ['side', 'over', 'push'][this.modeIndex]; } + get fixedTop() { return this.fixed && this.showHeader && !this.coverHeader ? 64 : 0; } + get fixedBottom() { return this.fixed && this.showFooter && !this.coverHeader ? 64 : 0; } } diff --git a/src/lib/sidenav/drawer.scss b/src/lib/sidenav/drawer.scss index f7383ae01bf1..d3efaa66d351 100644 --- a/src/lib/sidenav/drawer.scss +++ b/src/lib/sidenav/drawer.scss @@ -89,7 +89,6 @@ $mat-drawer-over-drawer-z-index: 4; min-width: 5vw; outline: 0; box-sizing: border-box; - height: 100%; overflow-y: auto; // TODO(kara): revisit scrolling behavior for drawers transform: translate3d(-100%, 0, 0); @@ -120,3 +119,7 @@ $mat-drawer-over-drawer-z-index: 4; } } } + +.mat-sidenav-fixed { + position: fixed; +} diff --git a/src/lib/sidenav/sidenav.ts b/src/lib/sidenav/sidenav.ts index 01d45178d935..5c102bb59926 100644 --- a/src/lib/sidenav/sidenav.ts +++ b/src/lib/sidenav/sidenav.ts @@ -68,7 +68,7 @@ export class MdSidenavContent extends MdDrawerContent { '[class.mat-drawer-over]': 'mode === "over"', '[class.mat-drawer-push]': 'mode === "push"', '[class.mat-drawer-side]': 'mode === "side"', - '[class.mat-app-sidenav-fixed]': 'fixedInViewport', + '[class.mat-sidenav-fixed]': 'fixedInViewport', '[style.top.px]': 'fixedInViewport ? fixedTopGap : null', '[style.bottom.px]': 'fixedInViewport ? fixedBottomGap : null', }, From 34aaf22be8ff5fbdeecc938358f24cd0ca030ebd Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Wed, 30 Aug 2017 15:12:26 -0700 Subject: [PATCH 07/11] fix tests and lint --- src/lib/sidenav/drawer.spec.ts | 2 ++ src/lib/sidenav/drawer.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/sidenav/drawer.spec.ts b/src/lib/sidenav/drawer.spec.ts index 6d0a5171a06b..d858a6a2d8a1 100644 --- a/src/lib/sidenav/drawer.spec.ts +++ b/src/lib/sidenav/drawer.spec.ts @@ -76,6 +76,8 @@ describe('MdDrawer', () => { it('should emit the backdropClick event when the backdrop is clicked', fakeAsync(() => { let fixture = TestBed.createComponent(BasicTestApp); + fixture.detectChanges(); + let testComponent: BasicTestApp = fixture.debugElement.componentInstance; let openButtonElement = fixture.debugElement.query(By.css('.open')).nativeElement; diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts index 90a888dacbcf..ac4e28814bc0 100644 --- a/src/lib/sidenav/drawer.ts +++ b/src/lib/sidenav/drawer.ts @@ -471,7 +471,7 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { if (drawer) { takeUntil.call(drawer._modeChanged, this._drawers.changes).subscribe(() => { this._updateContentMargins(); - this._changeDetectorRef.markForCheck() + this._changeDetectorRef.markForCheck(); }); } } From 4ed91379f53570358d6d4cdd413c01843febb365 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 31 Aug 2017 16:53:49 -0700 Subject: [PATCH 08/11] address comments --- src/lib/sidenav/drawer.ts | 19 +++++++++- src/lib/sidenav/sidenav.spec.ts | 67 +++++++++++++++++++++++++++++++++ src/lib/sidenav/sidenav.ts | 16 ++++++-- 3 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/lib/sidenav/sidenav.spec.ts diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts index ac4e28814bc0..dd82bf916056 100644 --- a/src/lib/sidenav/drawer.ts +++ b/src/lib/sidenav/drawer.ts @@ -68,7 +68,11 @@ export class MdDrawerToggleResult { encapsulation: ViewEncapsulation.None, }) export class MdDrawerContent implements AfterContentInit { - /** Margins to be applied to the content. */ + /** + * Margins to be applied to the content. These are used to push / shrink the drawer content when a + * drawer is open. We use margin rather than transform even for push mode because transform breaks + * fixed position elements inside of the transformed element. + */ _margins: {left: number, right: number} = {left: 0, right: 0}; constructor( @@ -77,7 +81,7 @@ export class MdDrawerContent implements AfterContentInit { } ngAfterContentInit() { - this._container._contentMargins.subscribe((margins) => { + this._container._contentMargins.subscribe(margins => { this._margins = margins; this._changeDetectorRef.markForCheck(); }); @@ -200,6 +204,10 @@ export class MdDrawer implements AfterContentInit, OnDestroy { /** @deprecated */ @Output('align-changed') onAlignChanged = new EventEmitter(); + /** + * An observable that emits when the drawer mode changes. This is used by the drawer container to + * to know when to when the mode changes so it can adapt the margins on the content. + */ _modeChanged = new Subject(); get isFocusTrapEnabled() { @@ -542,6 +550,13 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy { * sparingly, because it causes a reflow. */ private _updateContentMargins() { + // 1. For drawers in `over` mode, they don't affect the content. + // 2. For drawers in `side` mode they should shrink the content. We do this by adding to the + // left margin (for left drawer) or right margin (for right the drawer). + // 3. For drawers in `push` mode the should shift the content without resizing it. We do this by + // adding to the left or right margin and simultaneously subtracting the same amount of + // margin from the other side. + let left = 0; let right = 0; diff --git a/src/lib/sidenav/sidenav.spec.ts b/src/lib/sidenav/sidenav.spec.ts new file mode 100644 index 000000000000..0de4571a2638 --- /dev/null +++ b/src/lib/sidenav/sidenav.spec.ts @@ -0,0 +1,67 @@ +import {Component} from '@angular/core'; +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {MdSidenav, MdSidenavModule} from './index'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {By} from '@angular/platform-browser'; + + +describe('MdSidenav', () => { + let fixture: ComponentFixture; + let sidenavEl: HTMLElement; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MdSidenavModule, NoopAnimationsModule], + declarations: [SidenavWithFixedPosition], + }); + + TestBed.compileComponents(); + + fixture = TestBed.createComponent(SidenavWithFixedPosition); + fixture.detectChanges(); + + sidenavEl = fixture.debugElement.query(By.directive(MdSidenav)).nativeElement; + })); + + it('should be fixed position when in fixed mode', () => { + expect(sidenavEl.classList).toContain('mat-sidenav-fixed'); + + fixture.componentInstance.fixed = false; + fixture.detectChanges(); + + expect(sidenavEl.classList).not.toContain('mat-sidenav-fixed'); + }); + + it('should set fixed bottom and top when in fixed mode', () => { + expect(sidenavEl.style.top).toBe('20px'); + expect(sidenavEl.style.bottom).toBe('30px'); + + fixture.componentInstance.fixed = false; + fixture.detectChanges(); + + expect(sidenavEl.style.top).toBeFalsy(); + expect(sidenavEl.style.bottom).toBeFalsy(); + }); +}); + + +@Component({ + template: ` + + + Drawer. + + + Some content. + + `, +}) +class SidenavWithFixedPosition { + fixed = true; + fixedTop = 20; + fixedBottom = 30; +} diff --git a/src/lib/sidenav/sidenav.ts b/src/lib/sidenav/sidenav.ts index 5c102bb59926..383b9a5e8f4a 100644 --- a/src/lib/sidenav/sidenav.ts +++ b/src/lib/sidenav/sidenav.ts @@ -14,6 +14,7 @@ import { } from '@angular/core'; import {MdDrawer, MdDrawerContainer, MdDrawerContent} from './drawer'; import {animate, state, style, transition, trigger} from '@angular/animations'; +import {coerceBooleanProperty, coerceNumberProperty} from '@angular/cdk/coercion'; @Component({ @@ -78,19 +79,28 @@ export class MdSidenavContent extends MdDrawerContent { }) export class MdSidenav extends MdDrawer { /** Whether the sidenav is fixed in the viewport. */ - @Input() fixedInViewport = true; + @Input() + get fixedInViewport() { return this._fixedInViewport; } + set fixedInViewport(value) { this._fixedInViewport = coerceBooleanProperty(value); } + private _fixedInViewport = true; /** * The gap between the top of the sidenav and the top of the viewport when the sidenav is in fixed * mode. */ - @Input() fixedTopGap = 0; + @Input() + get fixedTopGap() { return this._fixedTopGap; } + set fixedTopGap(value) { this._fixedTopGap = coerceNumberProperty(value); } + private _fixedTopGap = 0; /** * The gap between the bottom of the sidenav and the bottom of the viewport when the sidenav is in * fixed mode. */ - @Input() fixedBottomGap = 0; + @Input() + get fixedBottomGap() { return this._fixedBottomGap; } + set fixedBottomGap(value) { this._fixedBottomGap = coerceNumberProperty(value); } + private _fixedBottomGap = 0; } From 0616d1f87f7035e1fe9390092c4a0c202b4aea84 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Wed, 6 Sep 2017 14:38:53 -0700 Subject: [PATCH 09/11] default fixedInViewport to false --- src/lib/sidenav/sidenav.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sidenav/sidenav.ts b/src/lib/sidenav/sidenav.ts index 383b9a5e8f4a..a4436b47975b 100644 --- a/src/lib/sidenav/sidenav.ts +++ b/src/lib/sidenav/sidenav.ts @@ -82,7 +82,7 @@ export class MdSidenav extends MdDrawer { @Input() get fixedInViewport() { return this._fixedInViewport; } set fixedInViewport(value) { this._fixedInViewport = coerceBooleanProperty(value); } - private _fixedInViewport = true; + private _fixedInViewport = false; /** * The gap between the top of the sidenav and the top of the viewport when the sidenav is in fixed From 133702c5b6e9af0682af0c692fe85063ee356221 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 19 Sep 2017 09:04:13 -0700 Subject: [PATCH 10/11] fix lint --- src/demo-app/demo-app/demo-app.ts | 2 +- src/demo-app/demo-app/demo-module.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/demo-app/demo-app/demo-app.ts b/src/demo-app/demo-app/demo-app.ts index 95c70b92cf21..f1f9fa5cd178 100644 --- a/src/demo-app/demo-app/demo-app.ts +++ b/src/demo-app/demo-app/demo-app.ts @@ -1,5 +1,5 @@ import {OverlayContainer} from '@angular/cdk/overlay'; -import {Component, ElementRef, Renderer2, ViewEncapsulation,} from '@angular/core'; +import {Component, ElementRef, Renderer2, ViewEncapsulation} from '@angular/core'; /** * The entry app for demo site. Routes under `accessibility` will use AccessibilityDemo component, diff --git a/src/demo-app/demo-app/demo-module.ts b/src/demo-app/demo-app/demo-module.ts index 850f080fc811..80e21dbe5c26 100644 --- a/src/demo-app/demo-app/demo-module.ts +++ b/src/demo-app/demo-app/demo-module.ts @@ -1,4 +1,4 @@ -import {FullscreenOverlayContainer, OverlayContainer,} from '@angular/cdk/overlay'; +import {FullscreenOverlayContainer, OverlayContainer} from '@angular/cdk/overlay'; import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; From 8d77c32e0680deb7d50a5b567e8c625467e038eb Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Wed, 20 Sep 2017 16:28:54 -0700 Subject: [PATCH 11/11] don't preserve whitespace --- src/lib/sidenav/drawer.ts | 1 + src/lib/sidenav/sidenav.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/lib/sidenav/drawer.ts b/src/lib/sidenav/drawer.ts index dd82bf916056..3d306303fac0 100644 --- a/src/lib/sidenav/drawer.ts +++ b/src/lib/sidenav/drawer.ts @@ -66,6 +66,7 @@ export class MdDrawerToggleResult { }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, + preserveWhitespaces: false, }) export class MdDrawerContent implements AfterContentInit { /** diff --git a/src/lib/sidenav/sidenav.ts b/src/lib/sidenav/sidenav.ts index a4436b47975b..aff0a5b25137 100644 --- a/src/lib/sidenav/sidenav.ts +++ b/src/lib/sidenav/sidenav.ts @@ -28,6 +28,7 @@ import {coerceBooleanProperty, coerceNumberProperty} from '@angular/cdk/coercion }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, + preserveWhitespaces: false, }) export class MdSidenavContent extends MdDrawerContent { constructor(