fix(routing): tabs integration

This commit is contained in:
Manu Mtz.-Almeida
2018-02-08 19:43:29 +01:00
parent bf143fe96a
commit a337bd019c
14 changed files with 356 additions and 51 deletions

View File

@ -0,0 +1,166 @@
/**
* This is an autogenerated file created by the Stencil build process.
* It contains typing information for all components that exist in this project
* and imports for stencil collections that might be configured in your stencil.config.js file
*/
declare global {
interface HTMLStencilElement extends HTMLElement {
componentOnReady(): Promise<this>;
componentOnReady(done: (ele?: this) => void): void;
}
}
import {
PageOne as PageOne
} from './components/page-one/page-one';
declare global {
interface HTMLPageOneElement extends PageOne, HTMLStencilElement {
}
var HTMLPageOneElement: {
prototype: HTMLPageOneElement;
new (): HTMLPageOneElement;
};
interface HTMLElementTagNameMap {
"page-one": HTMLPageOneElement;
}
interface ElementTagNameMap {
"page-one": HTMLPageOneElement;
}
namespace JSX {
interface IntrinsicElements {
"page-one": JSXElements.PageOneAttributes;
}
}
namespace JSXElements {
export interface PageOneAttributes extends HTMLAttributes {
}
}
}
import {
PageTwo as PageTwo
} from './components/page-two/page-two';
declare global {
interface HTMLPageTwoElement extends PageTwo, HTMLStencilElement {
}
var HTMLPageTwoElement: {
prototype: HTMLPageTwoElement;
new (): HTMLPageTwoElement;
};
interface HTMLElementTagNameMap {
"page-two": HTMLPageTwoElement;
}
interface ElementTagNameMap {
"page-two": HTMLPageTwoElement;
}
namespace JSX {
interface IntrinsicElements {
"page-two": JSXElements.PageTwoAttributes;
}
}
namespace JSXElements {
export interface PageTwoAttributes extends HTMLAttributes {
}
}
}
import {
TabOne as TabOne
} from './components/tab-one/tab-one';
declare global {
interface HTMLTabOneElement extends TabOne, HTMLStencilElement {
}
var HTMLTabOneElement: {
prototype: HTMLTabOneElement;
new (): HTMLTabOneElement;
};
interface HTMLElementTagNameMap {
"tab-one": HTMLTabOneElement;
}
interface ElementTagNameMap {
"tab-one": HTMLTabOneElement;
}
namespace JSX {
interface IntrinsicElements {
"tab-one": JSXElements.TabOneAttributes;
}
}
namespace JSXElements {
export interface TabOneAttributes extends HTMLAttributes {
}
}
}
import {
TabThree as TabThree
} from './components/tab-three/tab-three';
declare global {
interface HTMLTabThreeElement extends TabThree, HTMLStencilElement {
}
var HTMLTabThreeElement: {
prototype: HTMLTabThreeElement;
new (): HTMLTabThreeElement;
};
interface HTMLElementTagNameMap {
"tab-three": HTMLTabThreeElement;
}
interface ElementTagNameMap {
"tab-three": HTMLTabThreeElement;
}
namespace JSX {
interface IntrinsicElements {
"tab-three": JSXElements.TabThreeAttributes;
}
}
namespace JSXElements {
export interface TabThreeAttributes extends HTMLAttributes {
}
}
}
import {
TabTwo as TabTwo
} from './components/tab-two/tab-two';
declare global {
interface HTMLTabTwoElement extends TabTwo, HTMLStencilElement {
}
var HTMLTabTwoElement: {
prototype: HTMLTabTwoElement;
new (): HTMLTabTwoElement;
};
interface HTMLElementTagNameMap {
"tab-two": HTMLTabTwoElement;
}
interface ElementTagNameMap {
"tab-two": HTMLTabTwoElement;
}
namespace JSX {
interface IntrinsicElements {
"tab-two": JSXElements.TabTwoAttributes;
}
}
namespace JSXElements {
export interface TabTwoAttributes extends HTMLAttributes {
}
}
}
declare global { namespace JSX { interface StencilJSX {} } }

View File

@ -0,0 +1,22 @@
import { Component } from '@stencil/core';
@Component({
tag: 'tab-one',
})
export class TabOne {
render() {
return [
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Page One</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
tab one
</ion-content>
</ion-page>
];
}
}

View File

@ -0,0 +1,22 @@
import { Component } from '@stencil/core';
@Component({
tag: 'tab-three',
})
export class TabThree {
render() {
return [
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Tab 3</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
tab three
</ion-content>
</ion-page>
];
}
}

View File

@ -0,0 +1,22 @@
import { Component } from '@stencil/core';
@Component({
tag: 'tab-two',
})
export class TabTwo {
render() {
return [
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Tab two (2)</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-nav></ion-nav>
</ion-content>
</ion-page>
];
}
}

View File

@ -2437,9 +2437,9 @@ declare global {
}
namespace JSXElements {
export interface IonRouteAttributes extends HTMLAttributes {
component?: string;
path?: string;
props?: any;
sel?: string;
}
}
}
@ -3002,7 +3002,7 @@ declare global {
delegate?: FrameworkDelegate;
disabled?: boolean;
icon?: string;
path?: string;
name?: string;
selected?: boolean;
show?: boolean;
tabsHideOnSubPages?: boolean;

View File

@ -7,11 +7,6 @@
## Properties
#### component
string
#### path
string
@ -22,13 +17,13 @@ string
any
#### sel
string
## Attributes
#### component
string
#### path
string
@ -39,6 +34,11 @@ string
any
#### sel
string
----------------------------------------------

View File

@ -7,7 +7,7 @@ import { Component, Prop } from '@stencil/core';
export class Route {
@Prop() path: string;
@Prop() component: string;
@Prop() sel: string;
@Prop() props: any = {};
}

View File

@ -70,11 +70,11 @@ export function readNavState(node: HTMLElement) {
}
return {
stack: stack,
pivot: pivot
pivot: pivot,
};
}
export function matchPath(stack: string[], routes: RouterEntries): string[] {
export function matchPath(stack: string[], routes: RouterEntries) {
const path: string[] = [];
for (const id of stack) {
const route = routes.find(r => r.id === id);
@ -85,7 +85,10 @@ export function matchPath(stack: string[], routes: RouterEntries): string[] {
break;
}
}
return path;
return {
path: path,
routes: routes,
};
}
export function matchRouteChain(path: string[], routes: RouterEntries): RouterEntries {
@ -140,7 +143,7 @@ export function readRoutes(root: Element): RouterEntries {
.filter(el => el.tagName === 'ION-ROUTE')
.map(el => ({
path: parsePath(el.path),
id: el.component,
id: el.sel,
props: el.props,
subroutes: readRoutes(el)
}));

View File

@ -46,15 +46,15 @@ export class Router {
console.debug('[IN] nav changed -> update URL');
const { stack, pivot } = this.readNavState();
const { path, routes} = matchPath(stack, this.routes);
if (pivot) {
// readNavState() found a pivot that is not initialized
console.debug('[IN] pivot uninitialized -> write partial nav state');
this.writeNavState(pivot, []);
this.writeNavState(pivot, [], routes);
}
const isPop = ev.detail.isPop === true;
const segments = matchPath(stack, this.routes);
this.writePath(segments, isPop);
this.writePath(path, isPop);
}
@ -62,13 +62,13 @@ export class Router {
const node = document.querySelector('ion-app') as HTMLElement;
const currentPath = this.readPath();
if (currentPath) {
return this.writeNavState(node, currentPath);
return this.writeNavState(node, currentPath, this.routes);
}
return Promise.resolve();
}
private writeNavState(node: any, path: string[]): Promise<any> {
const chain = matchRouteChain(path, this.routes);
private writeNavState(node: any, path: string[], routes: RouterEntries): Promise<any> {
const chain = matchRouteChain(path, routes);
this.busy = true;
return writeNavState(node, chain)

View File

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Nav</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="/dist/ionic.js"></script>
<script src="/test-components/build/app.js"></script>
</head>
<body>
<ion-app>
<ion-router>
<ion-route path="/" sel="tab1"> </ion-route>
<ion-route path="/two" sel="tab2">
<ion-route path="/" sel="page-one"> </ion-route>
<ion-route path="/second-page" sel="page-two"> </ion-route>
</ion-route>
<ion-route path="/three" sel="tab-three"> </ion-route>
<ion-route path="/four" sel="tab4"> </ion-route>
</ion-router>
<ion-tabs>
<ion-tab name="tab1"
title="Plain List"
icon="star"
component="tab-one"></ion-tab>
<ion-tab name="tab2"
title="Schedule"
icon="globe"
component="tab-two"></ion-tab>
<ion-tab
title="Stopwatch"
icon="logo-facebook"
component="tab-three"></ion-tab>
<ion-tab name="tab4"
title="Messages"
icon="chatboxes"
name="tab-four">
INLINE CONTENT
</ion-tab>
</ion-tabs>
</ion-app>
<style>
f {
display: block;
margin: 15px auto;
max-width: 150px;
height: 150px;
background: blue;
}
f:last-of-type {
background: yellow;
}
</style>
</body>
<script>
</script>
</html>

View File

@ -97,12 +97,10 @@ string
The icon for the tab button.
#### path
#### name
string
The URL path name to represent this tab within the URL.
#### selected
@ -180,12 +178,10 @@ string
The icon for the tab button.
#### path
#### name
string
The URL path name to represent this tab within the URL.
#### selected
@ -223,7 +219,7 @@ Emitted when the current tab is selected.
## Methods
#### getPath()
#### getRouteId()
#### setActive()

View File

@ -19,11 +19,6 @@ export class Tab {
*/
@Prop() btnId: string;
/**
* The URL path name to represent this tab within the URL.
*/
@Prop() path: string;
/**
* The title of the tab button.
*/
@ -43,6 +38,7 @@ export class Tab {
* The badge for the tab button.
*/
@Prop() component: any;
@Prop() name: string;
/**
* The badge color for the tab button.
@ -102,7 +98,18 @@ export class Tab {
return promise.then(() => this.fireChildren());
}
fireChildren() {
@Method()
getRouteId(): string|null {
if (this.name) {
return this.name;
}
if (typeof this.component === 'string') {
return this.component;
}
return null;
}
private fireChildren() {
const nav = getNavAsChildIfExists(this.el);
if (nav && nav.getViews().length === 0 && nav.root) {
// we need to initialize
@ -112,17 +119,6 @@ export class Tab {
return Promise.resolve();
}
@Method()
getPath(): string {
if (this.path != null) {
return this.path;
}
if (this.title) {
return this.title.toLowerCase();
}
return '';
}
hostData() {
const visible = this.active && this.selected;
return {

View File

@ -217,6 +217,9 @@ Only affects `ios` mode. Defaults to `false`.
Emitted when the tab changes.
#### ionNavChanged
## Methods
#### getByIndex()

View File

@ -1,5 +1,5 @@
import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core';
import { Config, NavOutlet } from '../../index';
import { Config, NavOutlet, NavEventDetail } from '../../index';
@Component({
@ -66,6 +66,7 @@ export class Tabs implements NavOutlet {
* Emitted when the tab changes.
*/
@Event() ionChange: EventEmitter;
@Event() ionNavChanged: EventEmitter<NavEventDetail>;
componentDidLoad() {
this.loadConfig('tabsPlacement', 'bottom');
@ -116,10 +117,10 @@ export class Tabs implements NavOutlet {
return promise.then(() => {
this.ionChange.emit(selectedTab);
this.ionNavChanged.emit({isPop: false});
});
}
/**
* @param {number} index Index of the tab you want to get
* @returns {HTMLIonTabElement} Returns the tab who's index matches the one passed
@ -152,14 +153,15 @@ export class Tabs implements NavOutlet {
if (this.selectedTab === id) {
return Promise.resolve();
}
return this.select(id);
const tab = this.tabs.find(t => id === t.getRouteId());
return this.select(tab);
}
@Method()
getRouteId(): string|null {
if (this.selectedTab) {
return this.selectedTab.tagName;
return this.selectedTab.getRouteId();
}
return null;
}
@ -180,6 +182,9 @@ export class Tabs implements NavOutlet {
}
private initSelect() {
if (document.querySelector('ion-router')) {
return;
}
// find pre-selected tabs
const selectedTab = this.tabs.find(t => t.selected) ||
this.tabs.find(t => t.show && !t.disabled);