that whole nav overhaul thing again

This commit is contained in:
Adam Bradley
2015-05-28 10:19:28 -05:00
parent 2d8a6d9079
commit d827279a4f
36 changed files with 414 additions and 394 deletions

View File

@ -46,18 +46,11 @@ export class Animation {
return this; return this;
} }
addChild(childAnimation) { addAnimation(childAnimations) {
if (childAnimation) { childAnimations = Array.isArray(childAnimations) ? childAnimations : arguments;
childAnimation.parent(this); for (let i = 0; i < childAnimations.length; i++) {
this._children.push(childAnimation); childAnimations[i].parent(this);
} this._children.push(childAnimations[i]);
return this;
}
children(arr) {
arr = Array.isArray(arr) ? arr : arguments;
for (let i = 0; i < arr.length; i++) {
this.addChild(arr[i]);
} }
return this; return this;
} }

View File

@ -15,7 +15,7 @@ export * from 'ionic/components/list/list'
export * from 'ionic/components/nav/nav' export * from 'ionic/components/nav/nav'
export * from 'ionic/components/nav/nav-controller' export * from 'ionic/components/nav/nav-controller'
export * from 'ionic/components/nav/nav-item' export * from 'ionic/components/nav/nav-item'
// export * from 'ionic/components/nav/decorators' export * from 'ionic/components/nav-bar/nav-bar'
export * from 'ionic/components/slides/slides' export * from 'ionic/components/slides/slides'
export * from 'ionic/components/radio/radio' export * from 'ionic/components/radio/radio'
// export * from 'ionic/components/search-bar/search-bar' // export * from 'ionic/components/search-bar/search-bar'
@ -24,4 +24,3 @@ export * from 'ionic/components/segment/segment'
export * from 'ionic/components/switch/switch' export * from 'ionic/components/switch/switch'
//export * from 'ionic/components/tabs/tabs' //export * from 'ionic/components/tabs/tabs'
//export * from 'ionic/components/tabs/tab' //export * from 'ionic/components/tabs/tab'
export * from 'ionic/components/toolbar/toolbar'

View File

@ -4,11 +4,11 @@
// the rock that everything orders around // the rock that everything orders around
$flex-order-view-content: 40 !default; $flex-order-view-content: 0 !default;
$flex-order-toolbar-top: 20 !default; $flex-order-toolbar-top: -10 !default;
$flex-order-toolbar-bottom: 60 !default; $flex-order-toolbar-bottom: 10 !default;
$flex-order-tab-bar-top: 30 !default; $flex-order-tab-bar-top: 30 !default;

View File

@ -33,6 +33,32 @@ ion-nav {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
display: flex;
flex-direction: column;
}
.navbar-container {
position: relative;
min-height: 4.4rem;
}
.content-container {
position: relative;
flex: 1;
}
ion-navbar {
position: absolute;
width: 100%;
height: 100%;
min-height: 4.4rem;
order: $flex-order-toolbar-top;
display: none;
&.show-navbar {
display: flex;
}
} }
ion-view { ion-view {
@ -55,15 +81,7 @@ ion-view {
ion-toolbar { ion-toolbar {
display: flex; display: flex;
min-height: 4.4rem; min-height: 4.4rem;
order: $flex-order-toolbar-top; background: white;
}
.stage-off {
transform: translateX(9999px);
}
ion-toolbar[footer] {
order: $flex-order-toolbar-bottom;
} }
ion-content { ion-content {

View File

@ -0,0 +1,70 @@
// iOS Navbar
// --------------------------------------------------
$navbar-order-ios: (
back-button: 10,
primary: 20,
title: 30,
secondary: 40
);
$navbar-ios-height: 4.4rem !default;
$navbar-ios-background: #f7f7f8 !default;
$navbar-ios-border-color: #c4c4c4 !default;
$navbar-ios-title-font-size: 1.7rem !default;
$navbar-ios-button-font-size: 1.7rem !default;
$navbar-ios-button-text-color: #007aff !default;
$navbar-ios-button-background-color: transparent !default;
.nav-ios .navbar-container {
height: $navbar-ios-height;
background: $navbar-ios-background;
// navbar on top, border on bottom (default)
@include hairline(bottom, $navbar-ios-border-color);
// navbar on bottom, border on top
&.navbar-bottom:after {
top: 0;
bottom: auto;
}
.navbar [side="primary"] {
order: map-get($navbar-order-ios, 'primary');
}
.navbar [side="secondary"] {
order: map-get($navbar-order-ios, 'secondary');
}
ion-title {
order: map-get($navbar-order-ios, 'title');
text-align: center;
font-size: $navbar-ios-title-font-size;
font-weight: 500;
}
.navbar-back-button {
order: map-get($navbar-order-ios, 'back-button');
}
.button {
font-size: $navbar-ios-button-font-size;
color: $navbar-ios-button-text-color;
border: none;
padding: 0;
margin: 0 10px;
min-height: $navbar-ios-height;
min-width: 0;
background: $navbar-ios-button-background-color;
}
.back-button-icon {
padding-right: 6px;
}
}

View File

@ -0,0 +1,33 @@
// Material Design Navbar
// --------------------------------------------------
$navbar-material-height: 6.4rem !default;
$navbar-material-background: #f7f7f8 !default;
$navbar-material-title-font-size: 2rem !default;
$navbar-material-button-font-size: 2rem !default;
$navbar-material-button-text-color: #007aff !default;
.navbar-md {
height: $navbar-material-height;
background: $navbar-material-background;
.navbar-title {
font-size: $navbar-material-title-font-size;
}
.button {
font-size: $navbar-material-button-font-size;
color: $navbar-material-button-text-color;
border: none;
padding: 0;
margin: 0 10px;
min-height: $navbar-material-height;
min-width: 0;
}
}

View File

@ -3,58 +3,55 @@ import {View} from 'angular2/src/core/annotations_impl/view';
import {ElementRef} from 'angular2/src/core/compiler/element_ref'; import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref'; import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
import * as dom from 'ionic/util/dom'; import * as dom from '../../util/dom';
import {IonicComponent} from 'ionic/config/component';
import {NavItem} from 'ionic/ionic';
import {Platform} from 'ionic/platform/platform'; import {Platform} from 'ionic/platform/platform';
import {NavItem} from '../nav/nav-item';
import {BackButton} from './back-button'; import {BackButton} from './back-button';
@Component({ @Component({
selector: 'ion-toolbar' selector: 'ion-navbar'
}) })
@View({ @View({
template: ` template: `
<div class="toolbar-inner"> <div class="navbar-inner">
<back-button class="button toolbar-item" [hidden]="!navItem.enableBack"></back-button> <back-button class="button navbar-item" [hidden]="!navItem.enableBack"></back-button>
<div class="toolbar-title"> <div class="navbar-title">
<div class="toolbar-inner-title toolbar-title-hide"> <div class="navbar-inner-title navbar-title-hide">
<content select="ion-title"></content> <content select="ion-title"></content>
</div> </div>
</div> </div>
<!--<div class="toolbar-item toolbar-primary-item"> <div class="navbar-item navbar-primary-item">
<content select=".primary"></content> <content select=".primary"></content>
</div> </div>
<div class="toolbar-item toolbar-secondary-item"> <div class="navbar-item navbar-secondary-item">
<content select=".secondary"></content> <content select=".secondary"></content>
</div>--> </div>
</div> </div>
`, `,
directives: [BackButton] directives: [BackButton]
}) })
export class Toolbar { export class Navbar {
constructor(navItem: NavItem, elementRef: ElementRef) { constructor(navItem: NavItem, elementRef: ElementRef) {
this.navItem = navItem; this.navItem = navItem;
this.domElement = elementRef.domElement; this.domElement = elementRef.domElement;
this.config = Toolbar.config.invoke(this);
// http://davidwalsh.name/detect-node-insertion // http://davidwalsh.name/detect-node-insertion
dom.animationStart(this.domElement, 'nodeInserted').then(() => { dom.animationStart(this.domElement, 'nodeInserted').then(() => {
this.alignTitle(); this.alignTitle();
}); });
} }
alignTitle() { alignTitle() {
const toolbarEle = this.domElement; const navbarEle = this.domElement;
const innerTitleEle = this._innerTitleEle || (this._innerTitleEle = toolbarEle.querySelector('.toolbar-inner-title')); const innerTitleEle = this._innerTitleEle || (this._innerTitleEle = navbarEle.querySelector('.navbar-inner-title'));
const titleEle = this._titleEle || (this._titleEle = innerTitleEle.querySelector('ion-title')); const titleEle = this._titleEle || (this._titleEle = innerTitleEle.querySelector('ion-title'));
const style = this._style || (this._style = window.getComputedStyle(titleEle)); const style = this._style || (this._style = window.getComputedStyle(titleEle));
const titleOffsetWidth = titleEle.offsetWidth; const titleOffsetWidth = titleEle.offsetWidth;
const titleOffsetLeft = titleEle.offsetLeft; const titleOffsetLeft = titleEle.offsetLeft;
const titleScrollWidth = titleEle.scrollWidth; const titleScrollWidth = titleEle.scrollWidth;
const toolbarOffsetWidth = toolbarEle.offsetWidth; const navbarOffsetWidth = navbarEle.offsetWidth;
// TODO!!! When an element is being reused by angular2, it'll sometimes keep the // TODO!!! When an element is being reused by angular2, it'll sometimes keep the
// styles from the original element's use, causing these calculations to be wrong // styles from the original element's use, causing these calculations to be wrong
@ -68,7 +65,7 @@ export class Toolbar {
this._showTitle(); this._showTitle();
} else { } else {
let rightMargin = toolbarOffsetWidth - (titleOffsetLeft + titleOffsetWidth); let rightMargin = navbarOffsetWidth - (titleOffsetLeft + titleOffsetWidth);
let centerMargin = titleOffsetLeft - rightMargin; let centerMargin = titleOffsetLeft - rightMargin;
innerTitleEle.style.margin = `0 ${centerMargin}px 0 0`; innerTitleEle.style.margin = `0 ${centerMargin}px 0 0`;
@ -87,10 +84,23 @@ export class Toolbar {
_showTitle() { _showTitle() {
if (!this._shown) { if (!this._shown) {
this._shown = true; this._shown = true;
this._innerTitleEle.classList.remove('toolbar-title-hide'); this._innerTitleEle.classList.remove('navbar-title-hide');
} }
} }
} }
new IonicComponent(Toolbar, {});
/*
Used to find and register headers in a view, and this directive's
content will be moved up to the common navbar location, and created
using the same context as the view's content area.
*/
@Directive({
selector: 'template[navbar]'
})
export class NavbarTemplate {
constructor(navItem: NavItem, protoViewRef: ProtoViewRef) {
navItem.navbarProto(protoViewRef);
}
}

View File

@ -1,10 +1,8 @@
// Toolbar // Navbar
// -------------------------------------------------- // --------------------------------------------------
$toolbar-background-color: #fff !default; $navbar-order: (
$toolbar-order: (
back-button: 10, back-button: 10,
title: 20, title: 20,
primary: 30, primary: 30,
@ -12,25 +10,24 @@ $toolbar-order: (
); );
ion-toolbar { ion-navbar {
background: $toolbar-background-color;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.toolbar-inner { .navbar-inner {
display: flex; display: flex;
width: 100%; width: 100%;
} }
ion-toolbar back-button.toolbar-item { ion-navbar back-button.navbar-item {
order: map-get($toolbar-order, 'back-button'); order: map-get($navbar-order, 'back-button');
} }
.toolbar-title { .navbar-title {
flex: 1; flex: 1;
order: map-get($toolbar-order, 'title'); order: map-get($navbar-order, 'title');
display: flex; display: flex;
align-items: center; align-items: center;
@ -38,13 +35,13 @@ ion-toolbar back-button.toolbar-item {
} }
// buttons are primary by default // buttons are primary by default
ion-toolbar .button, ion-navbar .button,
ion-toolbar [side="primary"] { ion-navbar [side="primary"] {
order: map-get($toolbar-order, 'primary'); order: map-get($navbar-order, 'primary');
} }
ion-toolbar [side="secondary"] { ion-navbar [side="secondary"] {
order: map-get($toolbar-order, 'secondary'); order: map-get($navbar-order, 'secondary');
} }
ion-title { ion-title {
@ -56,18 +53,18 @@ ion-title {
animation-name: nodeInserted; animation-name: nodeInserted;
} }
.toolbar-inner-title { .navbar-inner-title {
width: 100%; width: 100%;
padding: 0 15px; padding: 0 15px;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.toolbar .button { .navbar .button {
background: transparent; background: transparent;
border: none; border: none;
} }
.toolbar-title-hide { .navbar-title-hide {
opacity: 0; opacity: 0;
} }

View File

@ -3,9 +3,6 @@ import {bind} from 'angular2/di';
import * as util from 'ionic/util'; import * as util from 'ionic/util';
import {NavController} from './nav-controller'; import {NavController} from './nav-controller';
import {NavView} from './nav-view';
const SHOW_VIEW_CSS = 'show-view';
export class NavItem { export class NavItem {
@ -15,9 +12,11 @@ export class NavItem {
this.Component = Component; this.Component = Component;
this.params = params; this.params = params;
this.id = util.nextUid(); this.id = util.nextUid();
this.headerProtos = []; this._navbarProto = null;
this.toolbarViews = []; this._navbarView = null;
this._titleEle = undefined; this._titleEle = undefined;
this._backBtn = undefined;
this.disposals = [];
// if it's possible to go back from this nav item // if it's possible to go back from this nav item
this.enableBack = false; this.enableBack = false;
@ -27,16 +26,12 @@ export class NavItem {
// update if it's possible to go back from this nav item // update if it's possible to go back from this nav item
this.enableBack = !!this.nav.getPrevious(this); this.enableBack = !!this.nav.getPrevious(this);
return this.create().then(() => { return this.render();;
return new Promise(resolve => {
this.viewEle && this.viewEle.classList.add(SHOW_VIEW_CSS);
resolve();
});
});
} }
create() { render() {
if (this.created) { if (this.created) {
console.log('showed existing view', this.id);
return Promise.resolve(); return Promise.resolve();
} }
@ -51,41 +46,80 @@ export class NavItem {
bind(NavItem).toValue(this) bind(NavItem).toValue(this)
]); ]);
this.nav.loader.loadNextToExistingLocation(this.Component, this.nav.viewElementRef, injector).then((componentRef) => { this.nav.loader.loadNextToExistingLocation(this.Component, this.nav.contentElementRef, injector).then((componentRef) => {
// content let navbarContainer = this.nav.navbarContainerRef;
this.component = componentRef;
if (componentRef && componentRef.dispose && navbarContainer) {
this.disposals.push(componentRef.dispose);
this.viewEle = componentRef.location.domElement; this.viewEle = componentRef.location.domElement;
this.viewEle.setAttribute('id', 'view-' + this.id);
if (componentRef && componentRef.dispose) { let context = {
this._dispose = componentRef.dispose; boundElementIndex: 0,
parentView: {
_view: componentRef.location.parentView._view.componentChildViews[0]
}
};
let atIndex = -1;
this._navbarView = navbarContainer.create(this._navbarProto, atIndex, context, injector);
if (this._navbarView) {
this.disposals.push(() => {
navbarContainer.remove( navbarContainer.indexOf(this._navbarView) );
});
}
} }
console.log('created view', this.id);
resolve(); resolve();
}); });
return promise; return promise;
} }
cache() {
console.log('cached view', this.id);
}
destroy() {
console.log('destroyed view', this.id);
for (let i = 0; i < this.disposals.length; i++) {
this.disposals[i]();
}
// just to help prevent any possible memory leaks
for (let name in this) {
if (this.hasOwnProperty(name)) {
this[name] = null;
}
}
}
navbarProto(navbarProtoView) {
this._navbarProto = navbarProtoView;
}
viewElement() { viewElement() {
return this.viewEle; return this.viewEle;
} }
navbarElement() {
return this._navbarView._view.render._view.rootNodes[0];
}
contentElement() { contentElement() {
return this.viewEle.querySelector('ion-content'); return this.viewEle.querySelector('ion-content');
} }
toolbarElements() {
return this.viewEle.querySelectorAll('ion-toolbar');
}
titleElement() { titleElement() {
if (this._titleEle === undefined) { if (this._titleEle === undefined) {
let toolbarElements = this.toolbarElements(); let navbarElement = this.navbarElement();
for (let i = 0; i < toolbarElements.length; i++) { if (navbarElement) {
var titleEle = toolbarElements[i].querySelector('ion-title'); let titleEle = navbarElement.querySelector('ion-title');
if (titleEle) { if (titleEle) {
this._titleEle = titleEle; this._titleEle = titleEle;
return this._titleEle; return this._titleEle;
@ -98,9 +132,9 @@ export class NavItem {
backButtonElement() { backButtonElement() {
if (this._backBtn === undefined) { if (this._backBtn === undefined) {
let toolbarElements = this.toolbarElements(); let navbarElement = this.navbarElement();
for (let i = 0; i < toolbarElements.length; i++) { if (navbarElement) {
var backBtn = toolbarElements[i].querySelector('back-button'); let backBtn = navbarElement.querySelector('back-button');
if (backBtn) { if (backBtn) {
this._backBtn = backBtn; this._backBtn = backBtn;
return this._backBtn; return this._backBtn;
@ -111,21 +145,6 @@ export class NavItem {
return this._backBtn; return this._backBtn;
} }
cache() {
this.viewEle.classList.remove(SHOW_VIEW_CSS);
}
destroy() {
this._dispose && this._dispose();
// just to help prevent any possible memory leaks
for (let name in this) {
if (this.hasOwnProperty(name)) {
this[name] = null;
}
}
}
} }
export class NavParams { export class NavParams {

View File

@ -7,7 +7,7 @@ import {Injector} from 'angular2/di';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref'; import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {NavBase} from './nav-base'; import {NavBase} from './nav-base';
import {ToolbarContainer} from '../toolbar/toolbar-container'; import {IonicComponent} from 'ionic/config/component'
@Component({ @Component({
@ -17,26 +17,45 @@ import {ToolbarContainer} from '../toolbar/toolbar-container';
} }
}) })
@View({ @View({
template: `<template view-anchor></template>`, template: `
directives: [ViewAnchor] <header class="navbar-container">
<template navbar-anchor></template>
</header>
<section class="content-container">
<template content-anchor></template>
</section>
`,
directives: [NavbarAnchor, ContentAnchor]
}) })
export class Nav extends NavBase { export class Nav extends NavBase {
constructor(elementRef: ElementRef, loader: DynamicComponentLoader, injector: Injector) { constructor(elementRef: ElementRef, loader: DynamicComponentLoader, injector: Injector) {
super(loader, injector); super(loader, injector);
this.domElement = elementRef.domElement; this.domElement = elementRef.domElement;
this.config = Nav.config.invoke(this);
} }
width() { width() {
return this.domElement.offsetWidth; return this.domElement.offsetWidth;
} }
} }
new IonicComponent(Nav, {});
@Directive({ @Directive({
selector: '[view-anchor]' selector: '[navbar-anchor]'
}) })
class ViewAnchor { class NavbarAnchor {
constructor(@Ancestor() nav: Nav, elementRef: ElementRef) { constructor(@Ancestor() nav: Nav, viewContainerRef: ViewContainerRef) {
nav.viewElementRef = elementRef; nav.navbarContainerRef = viewContainerRef;
}
}
@Directive({
selector: '[content-anchor]'
})
class ContentAnchor {
constructor(@Ancestor() nav: Nav, elementRef: ElementRef) {
nav.contentElementRef = elementRef;
} }
} }

View File

@ -1,14 +1,2 @@
<ion-nav [initial]="initial">
</ion-nav>
<style> <ion-nav [initial]="initial"></ion-nav>
ion-nav {
background: black;
}
.nav-item {
background: white;
}
</style>

View File

@ -1,5 +1,9 @@
<ion-toolbar><ion-title>First Page: {{ val }}</ion-title></ion-toolbar> <ion-navbar *navbar><ion-title>First Page Header: {{ val }}</ion-title></ion-navbar>
<!-- <ion-toolbar>
First Page Sub Header: {{ val }}
</ion-toolbar> -->
<ion-content class="padding"> <ion-content class="padding">

View File

@ -1,14 +1,14 @@
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations'; import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view'; import {View} from 'angular2/src/core/annotations_impl/view';
import {NavController, Toolbar, Content} from 'ionic/ionic'; import {NavController, NavbarTemplate, Navbar, Content} from 'ionic/ionic';
import {SecondPage} from './second-page'; import {SecondPage} from './second-page';
@Component({selector: 'ion-view'}) @Component({selector: 'ion-view'})
@View({ @View({
templateUrl: 'pages/first-page.html', templateUrl: 'pages/first-page.html',
directives: [Toolbar, Content] directives: [NavbarTemplate, Navbar, Content]
}) })
export class FirstPage { export class FirstPage {
constructor( constructor(

View File

@ -1,6 +1,13 @@
<ion-toolbar><ion-title>Second Page</ion-title></ion-toolbar> <ion-navbar *navbar><ion-title>Second Page Header</ion-title></ion-navbar>
<!-- <ion-toolbar>
Second Page Sub Header
</ion-toolbar>
<ion-toolbar>
Second Page Sub Sub Header
</ion-toolbar> -->
<ion-content class="padding"> <ion-content class="padding">
@ -13,3 +20,12 @@
</p> </p>
</ion-content> </ion-content>
<!-- <ion-toolbar>
Second Page Sub Footer
</ion-toolbar>
<ion-toolbar>
Second Page Footer
</ion-toolbar>
-->

View File

@ -1,14 +1,14 @@
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations'; import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view'; import {View} from 'angular2/src/core/annotations_impl/view';
import {NavController, NavParams, Toolbar, Content} from 'ionic/ionic'; import {NavController, NavParams, NavbarTemplate, Navbar, Content} from 'ionic/ionic';
import {ThirdPage} from './third-page'; import {ThirdPage} from './third-page';
@Component({selector: 'ion-view'}) @Component({selector: 'ion-view'})
@View({ @View({
templateUrl: 'pages/second-page.html', templateUrl: 'pages/second-page.html',
directives: [Toolbar, Content] directives: [NavbarTemplate, Navbar, Content]
}) })
export class SecondPage { export class SecondPage {
constructor( constructor(

View File

@ -1,6 +1,9 @@
<ion-toolbar><ion-title>Third Page</ion-title></ion-toolbar> <ion-navbar *navbar><ion-title>Third Page Header</ion-title></ion-navbar>
<!-- <ion-toolbar>
Third Page Footer
</ion-toolbar> -->
<ion-content class="padding"> <ion-content class="padding">

View File

@ -1,13 +1,13 @@
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations'; import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view'; import {View} from 'angular2/src/core/annotations_impl/view';
import {NavController, Toolbar, Content} from 'ionic/ionic'; import {NavController, NavbarTemplate, Navbar, Content} from 'ionic/ionic';
@Component({selector: 'ion-view'}) @Component({selector: 'ion-view'})
@View({ @View({
templateUrl: 'pages/third-page.html', templateUrl: 'pages/third-page.html',
directives: [Toolbar, Content] directives: [NavbarTemplate, Navbar, Content]
}) })
export class ThirdPage { export class ThirdPage {
constructor( constructor(

View File

@ -1,5 +1,5 @@
// iOS Toolbar // iOS Tab Bar
// -------------------------------------------------- // --------------------------------------------------
$tab-bar-ios-item-padding: 3px 10px !default; $tab-bar-ios-item-padding: 3px 10px !default;
@ -22,14 +22,14 @@ $tab-bar-ios-item-icon-size: 2.8rem !default;
} }
&[tab-bar-placement="bottom"] > .tab-bar-container { &[tab-bar-placement="bottom"] > .tab-bar-container {
@include hairline(top, $toolbar-ios-border-color); @include hairline(top, $navbar-ios-border-color);
} }
&[tab-bar-placement="top"] > .tab-bar-container { &[tab-bar-placement="top"] > .tab-bar-container {
@include hairline(bottom, $toolbar-ios-border-color); @include hairline(bottom, $navbar-ios-border-color);
} }
&[tab-bar-placement="top"] > .toolbar-container .toolbar { &[tab-bar-placement="top"] > .navbar-container .navbar {
@include hairline(bottom, none); @include hairline(bottom, none);
} }

View File

@ -1,73 +0,0 @@
// iOS Toolbar
// --------------------------------------------------
$toolbar-order-ios: (
back-button: 10,
primary: 20,
title: 30,
secondary: 40
);
$toolbar-ios-height: 4.4rem !default;
$toolbar-ios-background: #f7f7f8 !default;
$toolbar-ios-border-color: #c4c4c4 !default;
$toolbar-ios-title-font-size: 1.7rem !default;
$toolbar-ios-button-font-size: 1.7rem !default;
$toolbar-ios-button-text-color: #007aff !default;
$toolbar-ios-button-background-color: transparent !default;
.toolbar-container-ios {
height: $toolbar-ios-height;
background: $toolbar-ios-background;
// toolbar on top, border on bottom (default)
@include hairline(bottom, $toolbar-ios-border-color);
// toolbar on bottom, border on top
&.toolbar-bottom:after {
top: 0;
bottom: auto;
}
}
.toolbar-ios {
.toolbar [side="primary"] {
order: map-get($toolbar-order-ios, 'primary');
}
.toolbar [side="secondary"] {
order: map-get($toolbar-order-ios, 'secondary');
}
ion-title {
order: map-get($toolbar-order-ios, 'title');
text-align: center;
font-size: $toolbar-ios-title-font-size;
font-weight: 500;
}
.toolbar-back-button {
order: map-get($toolbar-order-ios, 'back-button');
}
.button {
font-size: $toolbar-ios-button-font-size;
color: $toolbar-ios-button-text-color;
border: none;
padding: 0;
margin: 0 10px;
min-height: $toolbar-ios-height;
min-width: 0;
background: $toolbar-ios-button-background-color;
}
.back-button-icon {
padding-right: 6px;
}
}

View File

@ -1,33 +0,0 @@
// Material Design Toolbar
// --------------------------------------------------
$toolbar-material-height: 6.4rem !default;
$toolbar-material-background: #f7f7f8 !default;
$toolbar-material-title-font-size: 2rem !default;
$toolbar-material-button-font-size: 2rem !default;
$toolbar-material-button-text-color: #007aff !default;
.toolbar-md {
height: $toolbar-material-height;
background: $toolbar-material-background;
.toolbar-title {
font-size: $toolbar-material-title-font-size;
}
.button {
font-size: $toolbar-material-button-font-size;
color: $toolbar-material-button-text-color;
border: none;
padding: 0;
margin: 0 10px;
min-height: $toolbar-material-height;
min-width: 0;
}
}

View File

@ -1,18 +0,0 @@
import {ElementRef} from 'angular2/angular2'
import {Directive} from 'angular2/src/core/annotations_impl/annotations';
import {IonicComponent} from 'ionic/config/component'
@Directive({
selector: '.toolbar-container'
})
export class ToolbarContainer {
constructor(elementRef: ElementRef) {
this.domElement = elementRef.domElement;
this.config = ToolbarContainer.config.invoke(this);
}
}
new IonicComponent(ToolbarContainer, {})

View File

@ -1,32 +1,11 @@
// HACKYFILLS (hack + polyfill)
import {NgElement, ViewContainerRef} from 'angular2/angular2'
//import {DomRenderedElement} from 'ionic/util/render/dom'; // Object.defineProperties(ViewContainerRef.prototype, {
// domElement: {
/* // get: function() {
Object.defineProperties(NgElement.prototype, { // return this._defaultProtoView.render.delegate.element;
renderElement: { // }
get: function() { // }
return new DomRenderedElement(this._view.render.delegate.boundElements[this._boundElementIndex]); // });
}
},
domElement: {
get: function() {
console.log('GETTING DOM ELEMENT');
return this._view.render.delegate.boundElements[this._boundElementIndex];
}
}
});
*/
Object.defineProperties(ViewContainerRef.prototype, {
domElement: {
get: function() {
return this._defaultProtoView.render.delegate.element;
}
}
});
export * from 'ionic/components' export * from 'ionic/components'
@ -43,5 +22,4 @@ export * from 'ionic/engine/electron/electron'
export * from 'ionic/animations/animation' export * from 'ionic/animations/animation'
export * from 'ionic/transitions/transition' export * from 'ionic/transitions/transition'
export * from 'ionic/transitions/none-transition'
export * from 'ionic/transitions/ios-transition' export * from 'ionic/transitions/ios-transition'

View File

@ -39,18 +39,18 @@
"components/layout/layout", "components/layout/layout",
"components/list/list", "components/list/list",
"components/modal/modal", "components/modal/modal",
"components/nav-bar/nav-bar",
"components/slides/slides", "components/slides/slides",
"components/radio/radio", "components/radio/radio",
"components/search-bar/search-bar", "components/search-bar/search-bar",
"components/segment/segment", "components/segment/segment",
"components/switch/switch", "components/switch/switch",
"components/tabs/tabs", "components/tabs/tabs";
"components/toolbar/toolbar";
// iOS Components // iOS Components
@import @import
"components/toolbar/extensions/ios", "components/nav-bar/extensions/ios",
"components/action-menu/extensions/ios", "components/action-menu/extensions/ios",
"components/alert/extensions/ios", "components/alert/extensions/ios",
"components/button/extensions/ios", "components/button/extensions/ios",
@ -70,8 +70,7 @@
@import @import
"components/alert/extensions/material", "components/alert/extensions/material",
"components/button/extensions/material", "components/button/extensions/material",
"components/tabs/extensions/material", "components/tabs/extensions/material";
"components/toolbar/extensions/material";
// Icons // Icons

View File

@ -1,6 +1,5 @@
import {Animation} from '../animations/animation';
import {rafPromise} from '../util/dom';
import {Transition} from './transition'; import {Transition} from './transition';
import {Animation} from '../animations/animation';
const DURATION = 500; const DURATION = 500;
@ -14,128 +13,89 @@ const OFF_LEFT = '-33%';
const CENTER = '0%' const CENTER = '0%'
const OFF_OPACITY = 0.8; const OFF_OPACITY = 0.8;
const SHOW_TOOLBAR_CSS = 'show-toolbar';
const SHOW_NAV_ITEM_CSS = 'show-nav-item';
class IOSTransition extends Transition {
class IOSTransition extends Animation {
constructor(navCtrl, opts) { constructor(navCtrl, opts) {
super(); super(navCtrl);
// global duration and easing for all child animations // global duration and easing for all child animations
this.duration(DURATION); this.duration(DURATION);
this.easing(EASING); this.easing(EASING);
// get the entering and leaving items
let enteringItem = navCtrl.getStagedEnteringItem();
let leavingItem = navCtrl.getStagedLeavingItem();
// create animation for the entering content
let enteringContent = new Animation(enteringItem.contentElement());
// create animation for the entering toolbars
let enteringToolbars = new Animation(enteringItem.toolbarElements());
// create animation for the entering title element
let enteringTitle = new Animation(enteringItem.titleElement());
// create animation for the leaving content
// leavingItem could be null, but the animation instance knows to do nothing
let leavingContent = new Animation(leavingItem && leavingItem.contentElement());
// create animation for the leaving content
// leavingItem could be null, but the animation instance knows to do nothing
let leavingToolbars = new Animation(leavingItem && leavingItem.toolbarElements());
// create animation for the entering title element
let leavingTitle = new Animation(leavingItem && leavingItem.titleElement());
// entering item moves to center // entering item moves to center
// before starting, set enteringItem to display: block // before starting, set enteringItem to display: block
enteringContent this.enteringContent
.beforePlay.addClass(SHOW_NAV_ITEM_CSS)
.to(TRANSLATEX, CENTER) .to(TRANSLATEX, CENTER)
.to(OPACITY, 1); .to(OPACITY, 1);
enteringTitle this.enteringTitle
.from(OPACITY, 0) .from(OPACITY, 0)
.to(OPACITY, 1) .to(OPACITY, 1)
.to(TRANSLATEX, CENTER); .to(TRANSLATEX, CENTER);
enteringToolbars
.beforePlay.addClass(SHOW_TOOLBAR_CSS);
// if the back button should show, then fade it in // if the back button should show, then fade it in
if (enteringItem.enableBack) { if (this.entering.enableBack) {
let enteringBackButton = new Animation(enteringItem.backButtonElement()) let enteringBackButton = new Animation(this.entering.backButtonElement())
enteringBackButton.from(OPACITY, 0).to(OPACITY, 1); enteringBackButton
this.addChild(enteringBackButton); .from(OPACITY, 0)
.to(OPACITY, 1);
this.addAnimation(enteringBackButton);
} }
// leaving view moves off screen // leaving view moves off screen
// when completed, set leavingItem to display: none // when completed, set leaving to display: none
leavingContent this.leavingContent
.afterFinish.removeClass(SHOW_NAV_ITEM_CSS)
.from(TRANSLATEX, CENTER) .from(TRANSLATEX, CENTER)
.from(OPACITY, 1); .from(OPACITY, 1);
leavingToolbars this.leavingTitle
.afterFinish.removeClass(SHOW_TOOLBAR_CSS);
leavingTitle
.from(TRANSLATEX, CENTER) .from(TRANSLATEX, CENTER)
.from(OPACITY, 1); .from(OPACITY, 1);
if (leavingItem) { let leavingBackButton = new Animation(this.leaving.backButtonElement());
let leavingBackButton = new Animation(leavingItem.backButtonElement()); leavingBackButton
leavingBackButton.from(OPACITY, 1).to(OPACITY, 0); .from(OPACITY, 1)
this.addChild(leavingBackButton); .to(OPACITY, 0);
} this.addAnimation(leavingBackButton);
// set properties depending on direction // set properties depending on direction
if (opts.direction === 'back') { if (opts.direction === 'back') {
// back direction // back direction
enteringContent this.enteringContent
.from(TRANSLATEX, OFF_LEFT) .from(TRANSLATEX, OFF_LEFT)
.from(OPACITY, OFF_OPACITY) .from(OPACITY, OFF_OPACITY)
.to(OPACITY, 1); .to(OPACITY, 1);
enteringTitle this.enteringTitle
.from(TRANSLATEX, OFF_LEFT); .from(TRANSLATEX, OFF_LEFT);
leavingContent this.leavingContent
.to(TRANSLATEX, OFF_RIGHT) .to(TRANSLATEX, OFF_RIGHT)
.to(OPACITY, 1); .to(OPACITY, 1);
leavingTitle this.leavingTitle
.to(TRANSLATEX, OFF_RIGHT) .to(TRANSLATEX, OFF_RIGHT)
.to(OPACITY, 0); .to(OPACITY, 0);
} else { } else {
// forward direction // forward direction
enteringContent this.enteringContent
.from(TRANSLATEX, OFF_RIGHT) .from(TRANSLATEX, OFF_RIGHT)
.from(OPACITY, 1); .from(OPACITY, 1);
enteringTitle this.enteringTitle
.from(TRANSLATEX, OFF_RIGHT); .from(TRANSLATEX, OFF_RIGHT);
leavingContent this.leavingContent
.to(TRANSLATEX, OFF_LEFT) .to(TRANSLATEX, OFF_LEFT)
.to(OPACITY, OFF_OPACITY); .to(OPACITY, OFF_OPACITY);
leavingTitle this.leavingTitle
.to(TRANSLATEX, OFF_LEFT) .to(TRANSLATEX, OFF_LEFT)
.to(OPACITY, 0); .to(OPACITY, 0);
} }
// set child animations
this.children(enteringContent, enteringToolbars, enteringTitle, leavingContent, leavingToolbars, leavingTitle);
}
stage() {
return rafPromise();
} }
} }

View File

@ -1,19 +0,0 @@
import {Animation} from '../animations/animation';
import {Transition} from './transition';
import {rafPromise} from '../util/dom';
class NoneTransition extends Animation {
constructor(navCtrl) {
super();
}
stage() {
// immediately resolve
return rafPromise();
}
}
Transition.register('none', NoneTransition);

View File

@ -1,23 +1,80 @@
import {Animation} from '../animations/animation';
import {rafPromise} from '../util/dom';
const SHOW_NAVBAR_CSS = 'show-navbar';
const SHOW_VIEW_CSS = 'show-view';
let registry = {}; let registry = {};
class TransitionController { export class Transition extends Animation {
create(navCtrl, opts = {}) { constructor(navCtrl) {
super();
// get the entering and leaving items
let enteringItem = this.entering = navCtrl.getStagedEnteringItem();
let leavingItem = this.leaving = navCtrl.getStagedLeavingItem();
// create animation for the entering item's "ion-view" element
this.enteringView = new Animation(enteringItem.viewElement());
this.enteringView.beforePlay.addClass(SHOW_VIEW_CSS);
// create animation for the entering item's "ion-navbar" element
this.enteringNavbar = new Animation(enteringItem.navbarElement());
this.enteringNavbar.beforePlay.addClass(SHOW_NAVBAR_CSS);
// create animation for the entering item's "ion-content" element
this.enteringContent = new Animation(enteringItem.contentElement());
// create animation for the entering item's "ion-title" element
this.enteringTitle = new Animation(enteringItem.titleElement());
this.addAnimation(this.enteringView, this.enteringNavbar, this.enteringContent, this.enteringTitle);
if (leavingItem) {
// create animation for the entering item's "ion-view" element
this.leavingView = new Animation(leavingItem.viewElement());
this.leavingView.afterFinish.removeClass(SHOW_VIEW_CSS);
// create animation for the entering item's "ion-navbar" element
this.leavingNavbar = new Animation(leavingItem.navbarElement());
this.leavingNavbar.afterFinish.removeClass(SHOW_NAVBAR_CSS);
// create animation for the leaving item's "ion-content" element
this.leavingContent = new Animation(leavingItem.contentElement());
// create animation for the leaving item's "ion-title" element
this.leavingTitle = new Animation(leavingItem.titleElement());
this.addAnimation(this.leavingView, this.leavingNavbar, this.leavingContent, this.leavingTitle);
}
}
stage() {
return rafPromise();
}
/*
STATIC CLASSES
*/
static create(navCtrl, opts = {}) {
let name = opts.animation || 'ios'; let name = opts.animation || 'ios';
let TransitionClass = registry[name]; let TransitionClass = registry[name];
if (!TransitionClass) { if (!TransitionClass) {
TransitionClass = registry['none']; // transition wasn't found, default to a 'none' transition
// which doesn't animate anything, just shows and hides
TransitionClass = Transition;
} }
return new TransitionClass(navCtrl, opts); return new TransitionClass(navCtrl, opts);
} }
register(name, transitionClass) { static register(name, TransitionClass) {
registry[name] = transitionClass; registry[name] = TransitionClass;
} }
} }
export let Transition = new TransitionController();