mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(sidenav): Add support for fixed sidenavs (#6712)
This commit is contained in:
@@ -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,22 +43,25 @@ 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'},
|
||||
@@ -71,16 +69,15 @@ export class DemoApp {
|
||||
{name: 'Ripple', route: '/ripple'},
|
||||
{name: 'Select', route: '/select'},
|
||||
{name: 'Sidenav', route: '/sidenav'},
|
||||
{name: 'Slider', route: '/slider'},
|
||||
{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'}
|
||||
];
|
||||
|
||||
|
||||
@@ -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 {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 {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 {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 {SnackBarDemo} from '../snack-bar/snack-bar-demo';
|
||||
import {StepperDemo} from '../stepper/stepper-demo';
|
||||
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';
|
||||
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 {CardDemo} from '../card/card-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 {GridListDemo} from '../grid-list/grid-list-demo';
|
||||
import {LiveAnnouncerDemo} from '../live-announcer/live-announcer-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 {SelectDemo} from '../select/select-demo';
|
||||
import {SliderDemo} from '../slider/slider-demo';
|
||||
import {SidenavDemo} from '../sidenav/sidenav-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 {TableHeaderDemo} from '../table/table-header-demo';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -62,29 +60,34 @@ 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,
|
||||
@@ -92,30 +95,26 @@ import {TableHeaderDemo} from '../table/table-header-demo';
|
||||
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,
|
||||
|
||||
@@ -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 {GesturesDemo} from '../gestures/gestures-demo';
|
||||
import {LiveAnnouncerDemo} from '../live-announcer/live-announcer-demo';
|
||||
import {ListDemo} from '../list/list-demo';
|
||||
import {IconDemo} from '../icon/icon-demo';
|
||||
import {ToolbarDemo} from '../toolbar/toolbar-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 {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} 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 {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 {TableDemo} from '../table/table-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 {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 {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: 'dialog', component: DialogDemo},
|
||||
{path: 'drawer', component: DrawerDemo},
|
||||
{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: 'live-announcer', component: LiveAnnouncerDemo},
|
||||
{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: 'select', component: SelectDemo},
|
||||
{path: 'sidenav', component: SidenavDemo},
|
||||
{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: 'icon', component: IconDemo},
|
||||
{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: 'ripple', component: RippleDemo},
|
||||
{path: 'dialog', component: DialogDemo},
|
||||
{path: 'tooltip', component: TooltipDemo},
|
||||
{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}
|
||||
]}
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<h2>Basic Use Case</h2>
|
||||
|
||||
<md-drawer-container class="demo-drawer-container">
|
||||
<md-drawer #start (open)="myinput.focus()" mode="side">
|
||||
Start Side Drawer
|
||||
<br>
|
||||
<button md-button (click)="start.close()">Close</button>
|
||||
<br>
|
||||
<button md-button (click)="end.open()">Open End Side</button>
|
||||
<br>
|
||||
<button md-button
|
||||
(click)="start.mode = (start.mode == 'push' ? 'over' : (start.mode == 'over' ? 'side' : 'push'))">Toggle Mode</button>
|
||||
<div>Mode: {{start.mode}}</div>
|
||||
<br>
|
||||
<input #myinput>
|
||||
</md-drawer>
|
||||
|
||||
<md-drawer #end position="end">
|
||||
End Side Drawer
|
||||
<br>
|
||||
<button md-button (click)="end.close()">Close</button>
|
||||
</md-drawer>
|
||||
|
||||
<div class="demo-drawer-content">
|
||||
<h1>My Content</h1>
|
||||
|
||||
<div>
|
||||
<header>Drawer</header>
|
||||
<button md-button (click)="start.toggle()">Toggle Start Side Drawer</button>
|
||||
<button md-button (click)="end.toggle()">Toggle End Side Drawer</button>
|
||||
</div>
|
||||
|
||||
<button md-button>HELLO</button>
|
||||
<button md-raised-button class="mat-primary">HELLO</button>
|
||||
<button md-fab class="mat-accent">HI</button>
|
||||
</div>
|
||||
</md-drawer-container>
|
||||
|
||||
<h2>Drawer Already Opened</h2>
|
||||
|
||||
<md-drawer-container class="demo-drawer-container">
|
||||
<md-drawer #start2 opened mode="side">
|
||||
Drawer
|
||||
</md-drawer>
|
||||
|
||||
<div class="demo-drawer-content">
|
||||
<button md-button (click)="start2.toggle()">Toggle Start Side Drawer</button>
|
||||
</div>
|
||||
</md-drawer-container>
|
||||
|
||||
<h2>Dynamic Position Drawer</h2>
|
||||
|
||||
<md-drawer-container class="demo-drawer-container">
|
||||
<md-drawer #dynamicPosDrawer1 mode="side" [position]="invert ? 'end' : 'start'">Start</md-drawer>
|
||||
<md-drawer #dynamicPosDrawer2 mode="side" [position]="invert ? 'start' : 'end'">End</md-drawer>
|
||||
|
||||
<div class="demo-drawer-content">
|
||||
<button (click)="dynamicPosDrawer1.toggle(); dynamicPosDrawer2.toggle()">
|
||||
Toggle drawers
|
||||
</button>
|
||||
<button (click)="invert = !invert">Change sides</button>
|
||||
</div>
|
||||
</md-drawer-container>
|
||||
|
||||
<h2>Drawer with focus attributes</h2>
|
||||
|
||||
<md-drawer-container class="demo-drawer-container">
|
||||
<md-drawer #focusDrawer>
|
||||
<md-nav-list>
|
||||
<a md-list-item routerLink>Link</a>
|
||||
<a md-list-item routerLink cdk-focus-region-start>Focus region start</a>
|
||||
<a md-list-item routerLink>Link</a>
|
||||
<a md-list-item routerLink cdk-focus-initial>Initially focused</a>
|
||||
<a md-list-item routerLink cdk-focus-region-end>Focus region end</a>
|
||||
<a md-list-item routerLink>Link</a>
|
||||
</md-nav-list>
|
||||
</md-drawer>
|
||||
|
||||
<div class="demo-drawer-content">
|
||||
<h1>My Content</h1>
|
||||
|
||||
<div>
|
||||
<header>Drawer</header>
|
||||
<button md-button (click)="focusDrawer.toggle()">Toggle Drawer</button>
|
||||
</div>
|
||||
</div>
|
||||
</md-drawer-container>
|
||||
@@ -0,0 +1,7 @@
|
||||
.demo-drawer-container {
|
||||
border: 3px solid black;
|
||||
}
|
||||
|
||||
.demo-drawer-content {
|
||||
padding: 15px;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import {Component, ViewEncapsulation} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'drawer-demo',
|
||||
templateUrl: 'drawer-demo.html',
|
||||
styleUrls: ['drawer-demo.css'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
export class DrawerDemo {
|
||||
invert = false;
|
||||
}
|
||||
@@ -1,87 +1,60 @@
|
||||
<h2>Basic Use Case</h2>
|
||||
<button md-raised-button (click)="isLaunched = true" *ngIf="!isLaunched" color="primary">
|
||||
Launch Fullscreen Sidenav Demo
|
||||
</button>
|
||||
|
||||
<md-sidenav-container class="demo-sidenav-container">
|
||||
<md-sidenav #start (open)="myinput.focus()" mode="side">
|
||||
Start Side Drawer
|
||||
<br>
|
||||
<button md-button (click)="start.close()">Close</button>
|
||||
<br>
|
||||
<button md-button (click)="end.open()">Open End Side</button>
|
||||
<br>
|
||||
<button md-button
|
||||
(click)="start.mode = (start.mode == 'push' ? 'over' : (start.mode == 'over' ? 'side' : 'push'))">Toggle Mode</button>
|
||||
<div>Mode: {{start.mode}}</div>
|
||||
<br>
|
||||
<input #myinput>
|
||||
</md-sidenav>
|
||||
<div class="demo-sidenav-area" *ngIf="isLaunched">
|
||||
<md-toolbar *ngIf="showHeader && !coverHeader">Header</md-toolbar>
|
||||
<md-sidenav-container>
|
||||
<md-sidenav #start (open)="myinput.focus()" [mode]="mode"
|
||||
[fixedInViewport]="fixed" [fixedTopGap]="fixedTop" [fixedBottomGap]="fixedBottom">
|
||||
Start Side Sidenav
|
||||
<br>
|
||||
<button md-button (click)="start.close()">Close</button>
|
||||
<br>
|
||||
<button md-button (click)="end.open()">Open End Side</button>
|
||||
<br>
|
||||
<button md-button (click)="modeIndex = (modeIndex + 1) % 3">Toggle Mode</button>
|
||||
<div>Mode: {{start.mode}}</div>
|
||||
<br>
|
||||
<input #myinput>
|
||||
<div class="demo-filler-content" *ngFor="let c of fillerContent">Filler Content</div>
|
||||
</md-sidenav>
|
||||
|
||||
<md-sidenav #end position="end">
|
||||
End Side Drawer
|
||||
<br>
|
||||
<button md-button (click)="end.close()">Close</button>
|
||||
</md-sidenav>
|
||||
<md-sidenav #end position="end"
|
||||
[fixedInViewport]="fixed" [fixedTopGap]="fixedTop" [fixedBottomGap]="fixedBottom">
|
||||
End Side Sidenav
|
||||
<br>
|
||||
<button md-button (click)="end.close()">Close</button>
|
||||
<div class="demo-filler-content" *ngFor="let c of fillerContent">Filler Content</div>
|
||||
</md-sidenav>
|
||||
|
||||
<div class="demo-sidenav-content">
|
||||
<h1>My Content</h1>
|
||||
<md-sidenav-content>
|
||||
<md-toolbar *ngIf="showHeader && coverHeader">Header</md-toolbar>
|
||||
<div class="demo-sidenav-content">
|
||||
<div>
|
||||
<button md-raised-button (click)="isLaunched = false">
|
||||
Exit Fullscreen Sidenav Demo
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<header>Sidenav</header>
|
||||
<button md-button (click)="start.toggle()">Toggle Start Side Drawer</button>
|
||||
<button md-button (click)="end.toggle()">Toggle End Side Drawer</button>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Sidenav</h3>
|
||||
<button md-button (click)="start.toggle()">Toggle Start Side Sidenav</button>
|
||||
<button md-button (click)="end.toggle()">Toggle End Side Sidenav</button>
|
||||
<md-checkbox [(ngModel)]="fixed">Fixed mode</md-checkbox>
|
||||
<md-checkbox [(ngModel)]="coverHeader">Sidenav covers header/footer</md-checkbox>
|
||||
</div>
|
||||
|
||||
<button md-button>HELLO</button>
|
||||
<button md-raised-button class="mat-primary">HELLO</button>
|
||||
<button md-fab class="mat-accent">HI</button>
|
||||
</div>
|
||||
</md-sidenav-container>
|
||||
<div>
|
||||
<h3>Header / Footer</h3>
|
||||
<md-checkbox [(ngModel)]="showHeader">Show header</md-checkbox>
|
||||
<md-checkbox [(ngModel)]="showFooter">Show footer</md-checkbox>
|
||||
</div>
|
||||
|
||||
<h2>Sidenav Already Opened</h2>
|
||||
|
||||
<md-sidenav-container class="demo-sidenav-container">
|
||||
<md-sidenav #start2 opened mode="side">
|
||||
Drawer
|
||||
</md-sidenav>
|
||||
|
||||
<div class="demo-sidenav-content">
|
||||
<button md-button (click)="start2.toggle()">Toggle Start Side Drawer</button>
|
||||
</div>
|
||||
</md-sidenav-container>
|
||||
|
||||
<h2>Dynamic Position Sidenav</h2>
|
||||
|
||||
<md-sidenav-container class="demo-sidenav-container">
|
||||
<md-sidenav #dynamicPosSidenav1 mode="side" [position]="invert ? 'end' : 'start'">Start</md-sidenav>
|
||||
<md-sidenav #dynamicPosSidenav2 mode="side" [position]="invert ? 'start' : 'end'">End</md-sidenav>
|
||||
|
||||
<div class="demo-sidenav-content">
|
||||
<button (click)="dynamicPosSidenav1.toggle(); dynamicPosSidenav2.toggle()">
|
||||
Toggle sidenavs
|
||||
</button>
|
||||
<button (click)="invert = !invert">Change sides</button>
|
||||
</div>
|
||||
</md-sidenav-container>
|
||||
|
||||
<h2>Sidenav with focus attributes</h2>
|
||||
|
||||
<md-sidenav-container class="demo-sidenav-container">
|
||||
<md-sidenav #focusSidenav>
|
||||
<md-nav-list>
|
||||
<a md-list-item routerLink>Link</a>
|
||||
<a md-list-item routerLink cdk-focus-region-start>Focus region start</a>
|
||||
<a md-list-item routerLink>Link</a>
|
||||
<a md-list-item routerLink cdk-focus-initial>Initially focused</a>
|
||||
<a md-list-item routerLink cdk-focus-region-end>Focus region end</a>
|
||||
<a md-list-item routerLink>Link</a>
|
||||
</md-nav-list>
|
||||
</md-sidenav>
|
||||
|
||||
<div class="demo-sidenav-content">
|
||||
<h1>My Content</h1>
|
||||
|
||||
<div>
|
||||
<header>Sidenav</header>
|
||||
<button md-button (click)="focusSidenav.toggle()">Toggle Drawer</button>
|
||||
</div>
|
||||
</div>
|
||||
</md-sidenav-container>
|
||||
<div class="demo-filler-content" *ngFor="let c of fillerContent">Filler Content</div>
|
||||
</div>
|
||||
<md-toolbar *ngIf="showFooter && coverHeader">Footer</md-toolbar>
|
||||
</md-sidenav-content>
|
||||
</md-sidenav-container>
|
||||
<md-toolbar *ngIf="showFooter && !coverHeader">Footer</md-toolbar>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
.demo-sidenav-container {
|
||||
border: 3px solid black;
|
||||
.demo-sidenav-area {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.mat-sidenav-focus-trap > .cdk-focus-trap-content {
|
||||
padding: 10px;
|
||||
.mat-toolbar {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.mat-sidenav-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.demo-sidenav-content {
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
.demo-filler-content {
|
||||
padding: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-sidenav-content {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,16 @@ import {Component, ViewEncapsulation} from '@angular/core';
|
||||
templateUrl: 'sidenav-demo.html',
|
||||
styleUrls: ['sidenav-demo.css'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
export class SidenavDemo {
|
||||
invert = false;
|
||||
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; }
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<div class="mat-drawer-backdrop" (click)="_onBackdropClicked()"
|
||||
[class.mat-drawer-shown]="_isShowingBackdrop()"></div>
|
||||
|
||||
<ng-content select="md-drawer, mat-drawer, md-sidenav, mat-sidenav"></ng-content>
|
||||
<ng-content select="md-drawer, mat-drawer"></ng-content>
|
||||
|
||||
<div class="mat-drawer-content" [ngStyle]="_styles" cdk-scrollable>
|
||||
<ng-content select="md-drawer-content, mat-drawer-content">
|
||||
</ng-content>
|
||||
<md-drawer-content *ngIf="!_content">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
</md-drawer-content>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<ng-content></ng-content>
|
||||
@@ -3,15 +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 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: $z-index;
|
||||
}
|
||||
|
||||
.mat-drawer-container {
|
||||
@@ -47,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.
|
||||
@@ -65,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%;
|
||||
@@ -73,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;
|
||||
@@ -83,12 +89,11 @@
|
||||
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);
|
||||
|
||||
&.mat-drawer-side {
|
||||
z-index: 1;
|
||||
z-index: $mat-drawer-side-drawer-z-index;
|
||||
}
|
||||
|
||||
&.mat-drawer-end {
|
||||
@@ -114,3 +119,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mat-sidenav-fixed {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+101
-26
@@ -16,9 +16,11 @@ import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ContentChild,
|
||||
ContentChildren,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
forwardRef,
|
||||
Inject,
|
||||
Input,
|
||||
NgZone,
|
||||
@@ -34,6 +36,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 +54,42 @@ export class MdDrawerToggleResult {
|
||||
constructor(public type: 'open' | 'close', public animationFinished: boolean) {}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'md-drawer-content, mat-drawer-content',
|
||||
template: '<ng-content></ng-content>',
|
||||
host: {
|
||||
'class': 'mat-drawer-content',
|
||||
'[style.marginLeft.px]': '_margins.left',
|
||||
'[style.marginRight.px]': '_margins.right',
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
export class MdDrawerContent implements AfterContentInit {
|
||||
/**
|
||||
* 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(
|
||||
private _changeDetectorRef: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => MdDrawerContainer)) private _container: MdDrawerContainer) {
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
this._container._contentMargins.subscribe(margins => {
|
||||
this._margins = margins;
|
||||
this._changeDetectorRef.markForCheck();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <md-drawer> component.
|
||||
*
|
||||
@@ -61,7 +100,7 @@ export class MdDrawerToggleResult {
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'md-drawer, mat-drawer',
|
||||
templateUrl: 'drawer.html',
|
||||
template: '<ng-content></ng-content>',
|
||||
animations: [
|
||||
trigger('transform', [
|
||||
state('open, open-instant', style({
|
||||
@@ -121,7 +160,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 +205,12 @@ export class MdDrawer implements AfterContentInit, OnDestroy {
|
||||
/** @deprecated */
|
||||
@Output('align-changed') onAlignChanged = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
// 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 +349,7 @@ export class MdDrawer implements AfterContentInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <md-drawer-container> component.
|
||||
*
|
||||
@@ -322,6 +374,8 @@ export class MdDrawer implements AfterContentInit, OnDestroy {
|
||||
export class MdDrawerContainer implements AfterContentInit, OnDestroy {
|
||||
@ContentChildren(MdDrawer) _drawers: QueryList<MdDrawer>;
|
||||
|
||||
@ContentChild(MdDrawerContent) _content: MdDrawerContent;
|
||||
|
||||
/** The drawer child with the `start` position. */
|
||||
get start() { return this._start; }
|
||||
|
||||
@@ -347,8 +401,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,
|
||||
@@ -366,6 +419,7 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy {
|
||||
this._drawers.forEach((drawer: MdDrawer) => {
|
||||
this._watchDrawerToggle(drawer);
|
||||
this._watchDrawerPosition(drawer);
|
||||
this._watchDrawerMode(drawer);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -394,7 +448,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();
|
||||
});
|
||||
|
||||
@@ -421,6 +475,16 @@ 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._updateContentMargins();
|
||||
this._changeDetectorRef.markForCheck();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Toggles the 'mat-drawer-opened' class on the main 'md-drawer-container' element. */
|
||||
private _setContainerClass(isAdd: boolean): void {
|
||||
if (isAdd) {
|
||||
@@ -483,29 +547,40 @@ 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() {
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* 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;
|
||||
let left = 0;
|
||||
let right = 0;
|
||||
|
||||
this._styles = {
|
||||
marginLeft: `${marginLeft}px`,
|
||||
marginRight: `${marginRight}px`,
|
||||
transform: `translate3d(${leftWidth - rightWidth}px, 0, 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;
|
||||
}
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="mat-drawer-backdrop" (click)="_onBackdropClicked()"
|
||||
[class.mat-drawer-shown]="_isShowingBackdrop()"></div>
|
||||
|
||||
<ng-content select="md-sidenav, mat-sidenav"></ng-content>
|
||||
|
||||
<ng-content select="md-sidenav-content, mat-sidenav-content">
|
||||
</ng-content>
|
||||
<md-sidenav-content *ngIf="!_content">
|
||||
<ng-content></ng-content>
|
||||
</md-sidenav-content>
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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<SidenavWithFixedPosition>;
|
||||
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: `
|
||||
<md-sidenav-container>
|
||||
<md-sidenav
|
||||
#drawer
|
||||
[fixedInViewport]="fixed"
|
||||
[fixedTopGap]="fixedTop"
|
||||
[fixedBottomGap]="fixedBottom">
|
||||
Drawer.
|
||||
</md-sidenav>
|
||||
<md-sidenav-content>
|
||||
Some content.
|
||||
</md-sidenav-content>
|
||||
</md-sidenav-container>`,
|
||||
})
|
||||
class SidenavWithFixedPosition {
|
||||
fixed = true;
|
||||
fixedTop = 20;
|
||||
fixedBottom = 30;
|
||||
}
|
||||
@@ -7,19 +7,42 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ContentChildren,
|
||||
ChangeDetectionStrategy, ChangeDetectorRef,
|
||||
Component, ContentChild,
|
||||
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';
|
||||
import {coerceBooleanProperty, coerceNumberProperty} from '@angular/cdk/coercion';
|
||||
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'md-sidenav-content, mat-sidenav-content',
|
||||
template: '<ng-content></ng-content>',
|
||||
host: {
|
||||
'class': 'mat-drawer-content mat-sidenav-content',
|
||||
'[style.marginLeft.px]': '_margins.left',
|
||||
'[style.marginRight.px]': '_margins.right',
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
preserveWhitespaces: false,
|
||||
})
|
||||
export class MdSidenavContent extends MdDrawerContent {
|
||||
constructor(
|
||||
changeDetectorRef: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => MdSidenavContainer)) container: MdSidenavContainer) {
|
||||
super(changeDetectorRef, container);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'md-sidenav, mat-sidenav',
|
||||
templateUrl: 'drawer.html',
|
||||
template: '<ng-content></ng-content>',
|
||||
animations: [
|
||||
trigger('transform', [
|
||||
state('open, open-instant', style({
|
||||
@@ -36,6 +59,7 @@ import {animate, state, style, transition, trigger} from '@angular/animations';
|
||||
],
|
||||
host: {
|
||||
'class': 'mat-drawer mat-sidenav',
|
||||
'tabIndex': '-1',
|
||||
'[@transform]': '_animationState',
|
||||
'(@transform.start)': '_onAnimationStart()',
|
||||
'(@transform.done)': '_onAnimationEnd($event)',
|
||||
@@ -46,19 +70,45 @@ import {animate, state, style, transition, trigger} from '@angular/animations';
|
||||
'[class.mat-drawer-over]': 'mode === "over"',
|
||||
'[class.mat-drawer-push]': 'mode === "push"',
|
||||
'[class.mat-drawer-side]': 'mode === "side"',
|
||||
'tabIndex': '-1',
|
||||
'[class.mat-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()
|
||||
get fixedInViewport() { return this._fixedInViewport; }
|
||||
set fixedInViewport(value) { this._fixedInViewport = coerceBooleanProperty(value); }
|
||||
private _fixedInViewport = false;
|
||||
|
||||
/**
|
||||
* The gap between the top of the sidenav and the top of the viewport when the sidenav is in fixed
|
||||
* mode.
|
||||
*/
|
||||
@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()
|
||||
get fixedBottomGap() { return this._fixedBottomGap; }
|
||||
set fixedBottomGap(value) { this._fixedBottomGap = coerceNumberProperty(value); }
|
||||
private _fixedBottomGap = 0;
|
||||
}
|
||||
|
||||
|
||||
@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 +122,6 @@ export class MdSidenav extends MdDrawer {}
|
||||
})
|
||||
export class MdSidenavContainer extends MdDrawerContainer {
|
||||
@ContentChildren(MdSidenav) _drawers;
|
||||
|
||||
@ContentChild(MdSidenavContent) _content;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user