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

Commit

Permalink
feat(peekaboo): different breaks for different viewport sizes
Browse files Browse the repository at this point in the history
 - support binding to breakXs,breakSm,breakMd,breakLg,breakXl to set specific scrollTop breakpoints for various media queries.
 - refactor bindings to be more clear with break prefix (action->breakAction)
 - By default have no breakAction (which is effectively saying you just want the md-peekaboo-active class and will handle the "action" on your own)
 - add Media.getQuery static method for getting the media query for a given size, e.g. 'sm', 'xl', 'xs', ...
  • Loading branch information
justindujardin committed Dec 28, 2015
1 parent 0623f5d commit 0fff4cc
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 24 deletions.
22 changes: 17 additions & 5 deletions examples/app.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<md-toolbar class="fixed-toolbar md-whiteframe-z1" md-peekaboo [breaks]="190" action="show">
<md-toolbar class="fixed-toolbar md-whiteframe-z1"
md-peekaboo
[break]="190"
breakAction="show">
<div class="md-toolbar-tools">
<h2>
<span>Angular2 Material</span>
Expand All @@ -7,19 +10,28 @@ <h2>
</div>
</md-toolbar>
<md-toolbar class="hero">
<h1 md-peekaboo [breaks]="72" action="hide">Angular2 Material</h1>
<h1 md-peekaboo
[breakMd]="72"
[breakXs]="20"
breakAction="hide">Angular2 Material</h1>
</md-toolbar>
<md-toolbar class="fixed-toolbar">
<div class="md-toolbar-tools">
<button md-button class="md-hamburger md-icon-button" aria-label="Settings">
<i md-icon class="md-light">menu</i>
</button>
<h2 md-peekaboo [breaks]="72" action="show">Angular2 Material</h2>
<h2 md-peekaboo
[breakMd]="72"
[breakXs]="20"
breakAction="show">Angular2 Material</h2>
<span flex></span>
<span md-peekaboo [breaks]="72" action="show" *ngIf="version" class="md-caption">v{{version}}</span>
<span md-peekaboo
[breakMd]="72"
breakAction="show"
*ngIf="version" class="md-caption">v{{version}}</span>
</div>
</md-toolbar>
<md-toolbar class="shadow-toolbar md-whiteframe-z1" md-peekaboo [breaks]="190" action="show"></md-toolbar>
<md-toolbar class="shadow-toolbar md-whiteframe-z1" md-peekaboo [break]="190" breakAction="show"></md-toolbar>

<md-content class="examples" md-scroll-y layout-padding>

Expand Down
3 changes: 1 addition & 2 deletions examples/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ $md-font-url: '../public/font/';

demos-app {

h1, h2, h3, h4, h5 {
> md-toolbar {
font-family: $font-family;
}

.fixed-toolbar, .shadow-toolbar {
position: fixed;
top: 0;
Expand Down
4 changes: 2 additions & 2 deletions ng2-material/components/peekaboo/peekaboo.scss
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[md-peekaboo] {
&[action=show] {
&[breakAction=show] {
display: none;
&.md-peekaboo-active {
display: inherit;
}
}
&[action=hide] {
&[breakAction=hide] {
display: inherit;
&.md-peekaboo-active {
display: none;
Expand Down
123 changes: 110 additions & 13 deletions ng2-material/components/peekaboo/peekaboo.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Directive} from "angular2/core";
import {Media, MediaListener} from '../../core/util/media';
import {Media, MediaListener, MEDIA_PRIORITY} from '../../core/util/media';
import {DOM} from "angular2/src/platform/dom/dom_adapter";
import {OnDestroy} from "angular2/core";
import {debounce} from "../../core/util/util";
Expand All @@ -8,7 +8,6 @@ import {CONST} from "angular2/src/facade/lang";
import {isPresent} from "angular2/src/facade/lang";
import {Attribute} from "angular2/core";


/** Different peekaboo actions to apply when active */
@CONST()
export class PeekabooAction {
Expand All @@ -26,17 +25,19 @@ export class PeekabooAction {
*/
@Directive({
selector: '[md-peekaboo]',
inputs: ['breaks'],
inputs: ['break', 'breakXs', 'breakSm', 'breakMd', 'breakLg', 'breakXl'],
host: {
'[class.md-peekaboo-active]': 'active',
'[attr.action]': 'action'
'[attr.breakAction]': 'breakAction'
}
})
export class MdPeekaboo implements OnDestroy {
//TODO(jdd): This is just testing hacks, use mapping size->scrollTop
@Input() breaks: number = 100;

@Input() action: string;
static SIZES: string[] = ['xs', 'sm', 'md', 'lg', 'xl'];

@Input() break: number = 100;

@Input() breakAction: string;

private _active: boolean;
get active(): boolean {
Expand All @@ -47,21 +48,117 @@ export class MdPeekaboo implements OnDestroy {
return window.pageYOffset || document.documentElement.scrollTop;
}

constructor(@Attribute('action') action: string) {
this.action = isPresent(action) ? action : PeekabooAction.SHOW;
this._active = this._evaluate(this.scrollTop);
private _breakXs: number = -1;
@Input() set breakXs(value: number) {
this._breakXs = value;
}

get breakXs(): number {
return this._breakXs;
}

private _breakSm: number = -1;
@Input() set breakSm(value: number) {
this._breakSm = value;
}

get breakSm(): number {
return this._breakSm;
}

private _breakMd: number = -1;
@Input() set breakMd(value: number) {
this._breakMd = value;
}

get breakMd(): number {
return this._breakMd;
}

private _breakLg: number = -1;
@Input() set breakLg(value: number) {
this._breakLg = value;
}

get breakLg(): number {
return this._breakLg;
}

private _breakXl: number = -1;
@Input() set breakXl(value: number) {
this._breakXl = value;
}

get breakXl(): number {
return this._breakXl;
}

private _mediaListeners: MediaListener[] = [];
private _breakpoint: string = null;

constructor(@Attribute('breakAction') action: string, public media: Media) {
this.breakAction = isPresent(action) ? action : PeekabooAction.SHOW;
this._evaluate();
window.addEventListener('scroll', this._windowScroll);
MdPeekaboo.SIZES.forEach((size: string) => {
this._watchMediaQuery(size);
if (Media.hasMedia(size)) {
this._breakpoint = size;
}
});
}

ngOnDestroy(): any {
this._mediaListeners.forEach((l: MediaListener) => {
l.destroy();
});
this._mediaListeners = [];
window.removeEventListener('scroll', this._windowScroll);
}

private _evaluate(scrollTop: number): boolean {
return scrollTop >= this.breaks;
private _watchMediaQuery(size: string) {
let l = this.media.listen(Media.getQuery(size));
l.onMatched.subscribe((q: string) => {
this._breakpoint = size;
this._evaluate();
});
this._mediaListeners.push(l);
}

private _windowScroll = (ev: Event) => {
this._active = this._evaluate(this.scrollTop);
this._evaluate();
};

private _evaluate(): void {
let bp: number = this.break;
switch (this._breakpoint) {
case 'xl':
if (this._breakXl !== -1) {
bp = this._breakXl;
break;
}
case 'lg':
if (this._breakLg !== -1) {
bp = this._breakLg;
break;
}
case 'md':
if (this._breakMd !== -1) {
bp = this._breakMd;
break;
}
case 'sm':
if (this._breakSm !== -1) {
bp = this._breakSm;
break;
}
case 'xs':
if (this._breakXs !== -1) {
bp = this._breakXs;
break;
}
}
this._active = this.scrollTop >= bp;
}

}
12 changes: 10 additions & 2 deletions ng2-material/core/util/media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,20 @@ export class Media {
}

static hasMedia(size: string): boolean {
let query = MEDIA[size];
let query = Media.getQuery(size);
if (!query) {
console.warn(`unknown media query size ${size}. Expected one of [${MEDIA_PRIORITY.join(',')}]`);
return false;
}
return window.matchMedia(query).matches;
}

static getQuery(size: string): string {
let query = MEDIA[size];
if (!query) {
console.warn(`unknown media query size ${size}. Expected one of [${MEDIA_PRIORITY.join(',')}]`);
return null;
}
return query;
}

}

0 comments on commit 0fff4cc

Please sign in to comment.