Skip to content
This repository has been archived by the owner on Feb 2, 2019. It is now read-only.

Commit

Permalink
feat(sidenav): basic sidenav component extended from backdrop
Browse files Browse the repository at this point in the history
 - extend backdrop and specify custom transition class to add md-closed to the sidenav as it is shown/hidden.
 - has an opaque backdrop for when not locked open
  • Loading branch information
justindujardin committed Jan 24, 2016
1 parent cb85ae4 commit 6043b12
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 11 deletions.
6 changes: 5 additions & 1 deletion ng2-material/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,15 @@ export * from './components/switcher/switch';
import {MdSubheader} from "./components/subheader/subheader";
export * from './components/subheader/subheader';

import {MdSidenav, SidenavService} from './components/sidenav/sidenav';
export * from './components/sidenav/sidenav';

import {MdToolbar} from './components/toolbar/toolbar';
export * from './components/toolbar/toolbar';

import {MdTabs, MdTab} from './components/tabs/tabs';
import {UrlResolver} from "angular2/compiler";
import {Media} from "./core/util/media";
export * from './components/toolbar/toolbar';

/**
* Collection of Material Design component directives.
Expand All @@ -81,6 +83,7 @@ export const MATERIAL_DIRECTIVES: Type[] = CONST_EXPR([
MdProgressLinear,
MdProgressCircular,
MdRadioButton, MdRadioGroup,
MdSidenav,
MdSubheader,
MdSwitch,
MdToolbar,
Expand All @@ -93,6 +96,7 @@ export const MATERIAL_DIRECTIVES: Type[] = CONST_EXPR([
export const MATERIAL_PROVIDERS: any[] = [
MdDialog,
Media,
SidenavService,
MdRadioDispatcher,
INPUT_VALIDATORS
];
12 changes: 6 additions & 6 deletions ng2-material/components/sidenav/sidenav.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ $sidenav-mobile-width: 320px !default;
$sidenav-desktop-width: 400px !default;
$sidenav-min-space: 56px !default;

md-sidenav {
[md-sidenav] {
box-sizing: border-box;
position: absolute;
position: fixed;
flex-direction: column;
z-index: $z-index-sidenav;

Expand Down Expand Up @@ -97,13 +97,13 @@ md-sidenav {
}

@media screen and (min-width: $layout-breakpoint-sm) {
md-sidenav {
[md-sidenav] {
max-width: $sidenav-desktop-width;
}
}

@media screen and (max-width: $sidenav-desktop-width + $sidenav-min-space) {
md-sidenav {
[md-sidenav] {
width: calc(100% - #{$sidenav-min-space});
min-width: calc(100% - #{$sidenav-min-space});
max-width: calc(100% - #{$sidenav-min-space});
Expand All @@ -120,6 +120,6 @@ md-sidenav {
}


md-sidenav {
background-color: md-color($md-background,500); //'{{background-color}}';
[md-sidenav] {
background-color: md-color($md-background,A100); //'{{background-color}}';
}
167 changes: 163 additions & 4 deletions ng2-material/components/sidenav/sidenav.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,166 @@
import {Directive} from 'angular2/core';
import {Directive, Injectable} from 'angular2/core';
import {Input} from 'angular2/core';
import {Animate} from "../../core/util/animate";
import {MdDialog} from "../dialog/dialog";
import {MdDialogRef} from "../dialog/dialog_ref";
import {Media} from "../../core/util/media";
import {MdBackdrop} from "../backdrop/backdrop";
import {ElementRef} from "angular2/core";
import {ContentChildren} from "angular2/core";
import {OnDestroy} from "angular2/core";
import {AfterContentInit} from "angular2/core";
import {OnInit} from "angular2/core";
import {QueryList} from "angular2/core";
import {Component} from "angular2/core";
import {ViewChild} from "angular2/core";
import {ComponentRef} from "angular2/core";
import {Renderer} from "angular2/core";
import {DynamicComponentLoader} from "angular2/core";
import {DOM} from "angular2/src/platform/dom/dom_adapter";
import {Attribute} from "angular2/core";
import {isPresent} from "angular2/src/facade/lang";
import {forwardRef} from "angular2/core";
import {Inject} from "angular2/core";

@Directive({selector: 'md-sidenav'})
export class MdSidenav {
@Input() public opened: boolean = true;
// TODO(jd): Lock open sidenav
// TODO(jd): Right alignment
// TODO(jd): Behaviors for testing
// - can lock open
// - service can find sidenavs by name


/**
* A slide-out navigation element that transitions in from the left or right.
*
* ```html
* <nav md-sidenav="menu">
* <h1>Components</h1>
* <button md-button (click)="close()">Close</button>
* </nav>
* ```
*/
@Directive({
selector: '[md-sidenav]'
})
export class MdSidenav extends MdBackdrop implements OnInit, OnDestroy {
@Input('md-sidenav')
name: string = 'default';

private _backdropRef: ComponentRef = null;

private _defaultContainer = DOM.query('body');

transitionClass: string = 'md-closed';
transitionAddClass = false;

constructor(public element: ElementRef,
public dcl: DynamicComponentLoader,
public renderer: Renderer,
@Inject(forwardRef(() => SidenavService)) public service: SidenavService,
@Attribute('md-sidenav') name: string) {
super(element);
DOM.addClass(this.element.nativeElement, this.transitionClass);
if (isPresent(name)) {
this.name = name;
}
}

show(): Promise<void> {
return this._createBackdrop(this.element).then(() => super.show());
}

_destroyBackdrop(): Promise<void> {
if (this._backdropRef) {
this._backdropRef.dispose();
this._backdropRef = null;
}
return Promise.resolve();
}


toggle(): Promise<void> {
return this.visible ? this.hide() : this.show();
}

isOpen(): boolean {
return this.visible;
}

private _lockedOpen: boolean = false;

isLockedOpen(): boolean {
return this._lockedOpen;
}


_createBackdrop(elementRef: ElementRef): Promise<ComponentRef> {
if (this._backdropRef) {
return Promise.resolve(this._backdropRef);
}
return this.dcl.loadNextToLocation(MdBackdrop, elementRef)
.then((componentRef) => {
let backdrop: MdBackdrop = componentRef.instance;
backdrop.clickClose = true;
this.renderer.setElementClass(componentRef.location, 'md-backdrop', true);
this.renderer.setElementClass(componentRef.location, 'md-opaque', true);
DOM.appendChild(this._defaultContainer, componentRef.location.nativeElement);

this._backdropRef = componentRef;
// When this component is shown/hidden, sync the backdrop
this.onShowing.subscribe(() => backdrop.show());
this.onHiding.subscribe(() => backdrop.hide());
// If the sidenav is hidden, release the backdrop
this.onHidden.subscribe(() => this._destroyBackdrop());
// If the backdrop is hidden, hide the nav
backdrop.onHiding.subscribe(() => this.hide());

return componentRef;
});
}

ngOnInit(): any {
this.service.register(this);
}

ngOnDestroy(): any {
this.service.unregister(this);
}

}

@Injectable()
export class SidenavService {
private _instances: MdSidenav[] = [];

register(instance: MdSidenav) {
this._instances.push(instance);
}

unregister(instance: MdSidenav) {
this._instances = this._instances.filter((c: MdSidenav) => {
return c.name !== instance.name;
});
}

show(name: string): Promise<void> {
let instance: MdSidenav = this._findInstance(name);
if (!instance) {
return Promise.reject<void>('invalid container');
}
return instance.show();
}

hide(name: string): Promise<void> {
let instance: MdSidenav = this._findInstance(name);
if (!instance) {
return Promise.reject<void>('invalid container');
}
return instance.hide();
}

private _findInstance(name: string): MdSidenav {
return this._instances.filter((c: MdSidenav) => {
return c.name === name;
})[0];
}
}

0 comments on commit 6043b12

Please sign in to comment.