Skip to content

Commit

Permalink
feat(md-snack-bar): Create initial MdSnackBar.
Browse files Browse the repository at this point in the history
  • Loading branch information
josephperrott committed Sep 21, 2016
1 parent ac86ddf commit 7f1485a
Show file tree
Hide file tree
Showing 22 changed files with 404 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/demo-app/demo-app-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {MdCheckboxDemoNestedChecklist, CheckboxDemo} from './checkbox/checkbox-d
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 {TabsDemo} from './tabs/tab-group-demo';
Expand Down Expand Up @@ -61,6 +62,7 @@ import {TabsDemo} from './tabs/tab-group-demo';
LiveAnnouncerDemo,
MdCheckboxDemoNestedChecklist,
MenuDemo,
SnackBarDemo,
OverlayDemo,
PortalDemo,
ProgressBarDemo,
Expand Down
1 change: 1 addition & 0 deletions src/demo-app/demo-app/demo-app.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<a md-list-item [routerLink]="['sidenav']">Sidenav</a>
<a md-list-item [routerLink]="['slider']">Slider</a>
<a md-list-item [routerLink]="['slide-toggle']">Slide Toggle</a>
<a md-list-item [routerLink]="['snack-bar']">Snack Bar</a>
<a md-list-item [routerLink]="['tabs']">Tabs</a>
<a md-list-item [routerLink]="['toolbar']">Toolbar</a>
<a md-list-item [routerLink]="['tooltip']">Tooltip</a>
Expand Down
2 changes: 2 additions & 0 deletions src/demo-app/demo-app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ 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';


export const DEMO_APP_ROUTES: Routes = [
Expand Down Expand Up @@ -56,4 +57,5 @@ export const DEMO_APP_ROUTES: Routes = [
{path: 'ripple', component: RippleDemo},
{path: 'dialog', component: DialogDemo},
{path: 'tooltip', component: TooltipDemo},
{path: 'snack-bar', component: SnackBarDemo},
];
13 changes: 13 additions & 0 deletions src/demo-app/snack-bar/snack-bar-demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<h1>SnackBar demo</h1>
<div>
<div>Message: <md-input type="text" [(ngModel)]="message"></md-input></div>
<div>
<md-checkbox [(ngModel)]="action">Show button</md-checkbox>
<md-input type="text" class="button-label-input"
placeholder="Button Label"
[disabled]="!action"
[(ngModel)]="actionButtonLabel"></md-input>
</div>
</div>

<button md-raised-button (click)="open()">Open</button>
3 changes: 3 additions & 0 deletions src/demo-app/snack-bar/snack-bar-demo.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.button-label-input {
display: inline-block;
}
31 changes: 31 additions & 0 deletions src/demo-app/snack-bar/snack-bar-demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {Component, ViewContainerRef} from '@angular/core';
import {MdSnackBar, MdSnackBarConfig} from '@angular2-material/snack-bar';

@Component({
moduleId: module.id,
selector: 'snack-bar-demo',
templateUrl: 'snack-bar-demo.html',
})
export class SnackBarDemo {
message: string = 'Snack Bar opened.';
actionButtonLabel: string = 'Retry';
action: boolean = false;

constructor(
public snackBar: MdSnackBar,
public viewContainerRef: ViewContainerRef) { }

open() {
let config = new MdSnackBarConfig(this.viewContainerRef);
this.snackBar.open(this.message, this.action && this.actionButtonLabel, config);
}
}


@Component({
moduleId: module.id,
selector: 'demo-snack',
templateUrl: 'snack-bar-demo.html',
styleUrls: ['./snack-bar-demo.css'],
})
export class DemoSnack {}
1 change: 1 addition & 0 deletions src/demo-app/system-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const components = [
'sidenav',
'slider',
'slide-toggle',
'snack-bar',
'button-toggle',
'tabs',
'toolbar',
Expand Down
3 changes: 3 additions & 0 deletions src/lib/all/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {MdProgressCircleModule} from '@angular2-material/progress-circle';
import {MdProgressBarModule} from '@angular2-material/progress-bar';
import {MdInputModule} from '@angular2-material/input';
import {MdTabsModule} from '@angular2-material/tabs';
import {MdSnackBarModule} from '@angular2-material/snack-bar';
import {MdToolbarModule} from '@angular2-material/toolbar';
import {MdTooltipModule} from '@angular2-material/tooltip';
import {
Expand Down Expand Up @@ -47,6 +48,7 @@ const MATERIAL_MODULES = [
MdSidenavModule,
MdSliderModule,
MdSlideToggleModule,
MdSnackBarModule,
MdTabsModule,
MdToolbarModule,
MdTooltipModule,
Expand Down Expand Up @@ -81,6 +83,7 @@ const MATERIAL_MODULES = [
MdRadioModule.forRoot(),
MdSliderModule.forRoot(),
MdSlideToggleModule.forRoot(),
MdSnackBarModule.forRoot(),
MdTooltipModule.forRoot(),
OverlayModule.forRoot(),
],
Expand Down
12 changes: 12 additions & 0 deletions src/lib/snack-bar/base-snack-bar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {MdSnackBarRef} from './snack-bar-ref';


export class BaseSnackBarContent<T> {
/** The instance of the component making up the content of the snack bar. */
snackBarRef: MdSnackBarRef<T>;

/** Dismisses the snack bar. */
dismiss(): void {
this.snackBarRef.dismiss();
}
}
1 change: 1 addition & 0 deletions src/lib/snack-bar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './snack-bar';
29 changes: 29 additions & 0 deletions src/lib/snack-bar/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@angular2-material/snack-bar",
"version": "2.0.0-alpha.8-1",
"description": "Angular 2 Material snack bar",
"main": "./snack-bar.umd.js",
"module": "./index.js",
"typings": "./index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/angular/material2.git"
},
"keywords": [
"angular",
"material",
"material design",
"components",
"snackbar",
"toast",
"notification"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/angular/material2/issues"
},
"homepage": "https://github.com/angular/material2#readme",
"peerDependencies": {
"@angular2-material/core": "2.0.0-alpha.8-1"
}
}
2 changes: 2 additions & 0 deletions src/lib/snack-bar/simple-snack-bar.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<span class="message">{{message}}</span>
<button md-button *ngIf="hasAction" (click)="dismiss()">{{action}}</button>
28 changes: 28 additions & 0 deletions src/lib/snack-bar/simple-snack-bar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
:host {
display: flex;
justify-content: space-between;

span {
box-sizing: border-box;
border: none;
color: white;
font-family: Roboto, 'Helvetica Neue', sans-serif;
font-size: 14px;
line-height: 20px;
outline: none;
text-decoration: none;
word-break: break-all;
}

button {
box-sizing: border-box;
color: white;
float: right;
font-weight: 600;
line-height: 20px;
margin: -5px 0 0 48px;
min-width: initial;
padding: 5px;
text-transform: uppercase;
}
}
20 changes: 20 additions & 0 deletions src/lib/snack-bar/simple-snack-bar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {Component} from '@angular/core';
import {BaseSnackBarContent} from './base-snack-bar';


@Component({
moduleId: module.id,
selector: 'simple-snack-bar',
templateUrl: 'simple-snack-bar.html',
styleUrls: ['simple-snack-bar.css'],
})
export class SimpleSnackBar extends BaseSnackBarContent<SimpleSnackBar> {
/** The message to be shown in the snack bar. */
message: string;

/** The label for the button in the snack bar. */
action: string;

/** If the action button should be shown. */
get hasAction(): boolean { return !!this.action; }
}
16 changes: 16 additions & 0 deletions src/lib/snack-bar/snack-bar-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {ViewContainerRef} from '@angular/core';


export type SnackBarRole = 'alert' | 'polite';

export class MdSnackBarConfig {
/** The aria-role of the snack bar. */
role: SnackBarRole = 'alert';

/** The view container to place the overlay for the snack bar into. */
viewContainerRef: ViewContainerRef;

constructor(viewContainerRef: ViewContainerRef) {
this.viewContainerRef = viewContainerRef;
}
}
1 change: 1 addition & 0 deletions src/lib/snack-bar/snack-bar-container.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<template portalHost></template>
19 changes: 19 additions & 0 deletions src/lib/snack-bar/snack-bar-container.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@import '../core/style/elevation';

$md-snack-bar-padding: 14px 24px !default;
$md-snack-bar-height: 20px !default;
$md-snack-bar-min-width: 288px !default;
$md-snack-bar-max-width: 568px !default;


:host {
background: #323232;
border-radius: 2px;
display: block;
height: $md-snack-bar-height;
@include md-elevation(24);
max-width: $md-snack-bar-max-width;
min-width: $md-snack-bar-min-width;
overflow: hidden;
padding: $md-snack-bar-padding;
}
46 changes: 46 additions & 0 deletions src/lib/snack-bar/snack-bar-container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
Component,
ComponentRef,
ViewChild
} from '@angular/core';
import {
BasePortalHost,
ComponentPortal,
TemplatePortal,
PortalHostDirective} from '@angular2-material/core';
import {MdSnackBarConfig} from './snack-bar-config';
import {MdSnackBarContentAlreadyAttached} from './snack-bar-errors';


/**
* Internal component that wraps user-provided snack bar content.
*/
@Component({
moduleId: module.id,
selector: 'snack-bar-content',
templateUrl: 'snack-bar-container.html',
styleUrls: ['snack-bar-container.css'],
host: {
'[attr.role]': 'snackBarConfig?.role'
}
})
export class MdSnackBarContainer extends BasePortalHost {
/** The portal host inside of this container into which the snack bar content will be loaded. */
@ViewChild(PortalHostDirective) private _portalHost: PortalHostDirective;

/** The snack bar configuration. */
snackBarConfig: MdSnackBarConfig;

/** Attach a portal as content to this snack bar container. */
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
if (this._portalHost.hasAttached()) {
throw new MdSnackBarContentAlreadyAttached();
}

return this._portalHost.attachComponentPortal(portal);
}

attachTemplatePortal(portal: TemplatePortal): Map<string, any> {
throw Error('Not yet implemented');
}
}
8 changes: 8 additions & 0 deletions src/lib/snack-bar/snack-bar-errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {MdError} from '@angular2-material/core';


export class MdSnackBarContentAlreadyAttached extends MdError {
constructor() {
super('Attempting to attach snack bar content after content is already attached');
}
}
41 changes: 41 additions & 0 deletions src/lib/snack-bar/snack-bar-ref.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {OverlayRef} from '@angular2-material/core';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';

// TODO(josephperrott): Implement onAction observable.


/**
* Reference to a snack bar dispatched from the snack bar service.
*/
export class MdSnackBarRef<T> {
/** The instance of the component making up the content of the snack bar. */
readonly instance: T|any;

/** Subject for notifying the user that the snack bar has closed. */
private _afterClosed: Subject<any> = new Subject();

/** If the snack bar is active. */
private _isActive: boolean = true;

constructor(instance: T|any, private _overlayRef: OverlayRef) {
// Sets the readonly instance of the snack bar content component.
this.instance = instance;
this.afterDismissed().subscribe(null, null, () => { this._isActive = false; });
}


/** Dismisses the snack bar. */
dismiss(): void {
if (this._isActive) {
this._overlayRef.dispose();
this._afterClosed.complete();
}
}


/** Gets an observable that is notified when the snack bar is finished closing. */
afterDismissed(): Observable<void> {
return this._afterClosed.asObservable();
}
}
Loading

0 comments on commit 7f1485a

Please sign in to comment.