From 63398f345052014a9c88f9b1383aa408682303b4 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Mon, 28 Sep 2015 23:36:48 -0500 Subject: [PATCH] feat(md): tab ripple and highlight line --- demos/yerk/main.html | 2 +- ionic/components/ion.ts | 4 +-- ionic/components/tabs/modes/ios.scss | 10 +++--- ionic/components/tabs/modes/md.scss | 19 ++++++++--- ionic/components/tabs/tab.ts | 1 - ionic/components/tabs/tabs.scss | 29 ++++++++++------ ionic/components/tabs/tabs.ts | 49 ++++++++++++++++++++++++---- ionic/util/dom.ts | 6 ++-- 8 files changed, 88 insertions(+), 32 deletions(-) diff --git a/demos/yerk/main.html b/demos/yerk/main.html index 69d1796205..59e85c1e73 100644 --- a/demos/yerk/main.html +++ b/demos/yerk/main.html @@ -7,7 +7,7 @@ .md .nav .navbar-title { color: #FDFEFE; } - #tabs .tab-bar:before { + #tabs tab-bar:before { position: absolute; top: 0; right: auto; diff --git a/ionic/components/ion.ts b/ionic/components/ion.ts index a0f0a478f6..d6c0d375dc 100644 --- a/ionic/components/ion.ts +++ b/ionic/components/ion.ts @@ -60,11 +60,11 @@ export class Ion { } width() { - return this.getDimensions().w; + return dom.getDimensions(this).width; } height() { - return this.getDimensions().h; + return dom.getDimensions(this).height; } } diff --git a/ionic/components/tabs/modes/ios.scss b/ionic/components/tabs/modes/ios.scss index 5ce9e32e80..dd1c53dee2 100644 --- a/ionic/components/tabs/modes/ios.scss +++ b/ionic/components/tabs/modes/ios.scss @@ -8,11 +8,11 @@ $tab-bar-ios-item-icon-size: 32px !default; $tab-bar-ios-height: 49px !default; -.tab-bar { +tab-bar { border-top: 1px solid $toolbar-ios-border-color; } -.tabs[tab-bar-placement=top] .tab-bar { +ion-tabs[tab-bar-placement=top] tab-bar { border-top: none; border-bottom: 1px solid $toolbar-ios-border-color; } @@ -72,13 +72,13 @@ $tab-bar-ios-height: 49px !default; min-height: $tab-bar-ios-height - 8; } -&.hairlines .tabs { +&.hairlines ion-tabs { - .tab-bar { + tab-bar { border-top-width: 0.5px; } - &[tab-bar-placement="top"] .tab-bar { + &[tab-bar-placement="top"] tab-bar { border-bottom-width: 0.55px; } diff --git a/ionic/components/tabs/modes/md.scss b/ionic/components/tabs/modes/md.scss index 9921be2339..9f9e03a8c4 100644 --- a/ionic/components/tabs/modes/md.scss +++ b/ionic/components/tabs/modes/md.scss @@ -20,10 +20,6 @@ $tab-bar-md-item-height: 4.8rem !default; border-bottom: 2px solid transparent; } -.tab-button[aria-selected=true] { - border-bottom-color: $tab-button-text-active; -} - .tab-button-text { margin-top: 5px; margin-bottom: 5px; @@ -53,3 +49,18 @@ $tab-bar-md-item-height: 4.8rem !default; .tab-button.has-title-only { padding: 6px 10px 6px 10px; } + +tab-highlight { + position: absolute; + display: block; + height: 2px; + width: 1px; + bottom: 0; + left: 0; + background: $tab-button-active-color; + transform-origin: 0 0; + + &.animate { + transition-duration: 300ms; + } +} diff --git a/ionic/components/tabs/tab.ts b/ionic/components/tabs/tab.ts index c4f4ae99e8..22b29d168d 100644 --- a/ionic/components/tabs/tab.ts +++ b/ionic/components/tabs/tab.ts @@ -27,7 +27,6 @@ import {Tabs} from './tabs'; '[attr.id]': 'panelId', '[attr.aria-labelledby]': 'labeledBy', '[attr.aria-hidden]': 'isNotSelected', - '[class.tab-selected]': 'isSelected', 'role': 'tabpanel' } }) diff --git a/ionic/components/tabs/tabs.scss b/ionic/components/tabs/tabs.scss index 2aa32fc28b..49b7761dcd 100644 --- a/ionic/components/tabs/tabs.scss +++ b/ionic/components/tabs/tabs.scss @@ -2,13 +2,14 @@ // Tabs // -------------------------------------------------- -$tab-bar-background-color: $toolbar-background-color !default; +$tab-bar-background-color: $toolbar-background-color !default; -$tab-button-text-active: $toolbar-active-color !default; -$tab-button-text-inactive: $toolbar-inactive-color !default; -$tab-button-padding: 10px !default; -$tab-button-min-width: 80px !default; -$tab-button-max-width: 160px !default; +$tab-button-text-color: $toolbar-text-color !default; +$tab-button-active-color: $toolbar-active-color !default; +$tab-button-inactive-color: $toolbar-inactive-color !default; +$tab-button-padding: 10px !default; +$tab-button-min-width: 80px !default; +$tab-button-max-width: 240px !default; ion-tabs { @@ -50,7 +51,8 @@ ion-tab { order: $flex-order-tab-bar-top; } -.tab-bar { +tab-bar { + position: relative; display: flex; justify-content: center; overflow: hidden; @@ -58,6 +60,9 @@ ion-tab { } .tab-button { + position: relative; + z-index: 0; + overflow: hidden; display: flex; flex-direction: column; justify-content: center; @@ -74,13 +79,13 @@ ion-tab { cursor: pointer; @include user-select-none(); - color: $tab-button-text-inactive; + color: $tab-button-inactive-color; border: 0; border-radius: 0; background: none; &:hover:not(.disable-hover) { - color: $tab-button-text-inactive; + color: $tab-button-active-color; } } @@ -138,5 +143,9 @@ ion-tab { } .tab-button[aria-selected=true] { - color: $toolbar-active-color; + color: $tab-button-active-color; +} + +tab-highlight { + display: none; } diff --git a/ionic/components/tabs/tabs.ts b/ionic/components/tabs/tabs.ts index 4af82b1acd..a2ed163e71 100644 --- a/ionic/components/tabs/tabs.ts +++ b/ionic/components/tabs/tabs.ts @@ -1,10 +1,12 @@ import {Component, Directive, View, Injector, NgFor, ElementRef, Optional, Host, forwardRef, NgZone} from 'angular2/angular2'; +import {Ion} from '../ion'; import {IonicApp} from '../app/app'; import {NavController} from '../nav/nav-controller'; import {ViewController} from '../nav/view-controller'; import {IonicComponent, IonicView} from '../../config/decorators'; import {IonicConfig} from '../../config/config'; +import * as dom from 'ionic/util/dom'; /** @@ -24,9 +26,9 @@ import {IonicConfig} from '../../config/config'; * @usage * ```html * - * - * - * + * + * + * * * ``` * @@ -41,17 +43,18 @@ import {IonicConfig} from '../../config/config'; @IonicView({ template: '' + '' + '
' + '' + '
', - directives: [forwardRef(() => TabButton)] + directives: [forwardRef(() => TabButton), forwardRef(() => TabHighlight)] }) export class Tabs extends NavController { /** @@ -138,6 +141,7 @@ export class Tabs extends NavController { leavingView.shouldCache = true; this.transition(enteringView, leavingView, opts, () => { + this.highlight && this.highlight.select(tab); resolve(); }); }); @@ -168,8 +172,9 @@ export class Tabs extends NavController { '(click)': 'onClick($event)', } }) -class TabButton { +class TabButton extends Ion { constructor(@Host() tabs: Tabs, config: IonicConfig, elementRef: ElementRef) { + super(elementRef, config); this.tabs = tabs; if (config.setting('hoverCSS') === false) { @@ -178,6 +183,7 @@ class TabButton { } onInit() { + this.tab.btn = this; let id = this.tab.viewCtrl.id; this.btnId = 'tab-button-' + id; this.panelId = 'tab-panel-' + id; @@ -194,3 +200,32 @@ class TabButton { this.tabs.select(this.tab); } } + + +@Directive({ + selector: 'tab-highlight' +}) +class TabHighlight { + constructor(@Host() tabs: Tabs, config: IonicConfig, elementRef: ElementRef) { + if (config.setting('mode') === 'md') { + tabs.highlight = this; + this.elementRef = elementRef; + } + } + + select(tab) { + setTimeout(() => { + let d = tab.btn.getDimensions(); + let ele = this.elementRef.nativeElement; + ele.style.transform = 'translate3d(' + d.left + 'px,0,0) scaleX(' + d.width + ')'; + + if (!this.init) { + this.init = true; + setTimeout(() => { + ele.classList.add('animate'); + }, 64) + } + }, 32); + } + +} diff --git a/ionic/util/dom.ts b/ionic/util/dom.ts index d9e8939eb3..2980fd0c0f 100644 --- a/ionic/util/dom.ts +++ b/ionic/util/dom.ts @@ -242,8 +242,10 @@ export function getDimensions(ion) { if (!dimensions) { let ele = ion.getNativeElement(); dimensions = dimensionCache[ion._dimId] = { - w: ele.offsetWidth, - h: ele.offsetHeight + width: ele.offsetWidth, + height: ele.offsetHeight, + left: ele.offsetLeft, + top: ele.offsetTop }; }