feat(route): adds route-link

This commit is contained in:
Manu Mtz.-Almeida
2018-03-08 01:42:08 +01:00
parent d609a222eb
commit 4a3030f087
9 changed files with 74 additions and 52 deletions

View File

@ -2546,31 +2546,30 @@ declare global {
import {
RouteLink as IonRouteLink
RouteLink as IonAnchor
} from './components/route-link/route-link';
declare global {
interface HTMLIonRouteLinkElement extends IonRouteLink, HTMLStencilElement {
interface HTMLIonAnchorElement extends IonAnchor, HTMLStencilElement {
}
var HTMLIonRouteLinkElement: {
prototype: HTMLIonRouteLinkElement;
new (): HTMLIonRouteLinkElement;
var HTMLIonAnchorElement: {
prototype: HTMLIonAnchorElement;
new (): HTMLIonAnchorElement;
};
interface HTMLElementTagNameMap {
"ion-route-link": HTMLIonRouteLinkElement;
"ion-anchor": HTMLIonAnchorElement;
}
interface ElementTagNameMap {
"ion-route-link": HTMLIonRouteLinkElement;
"ion-anchor": HTMLIonAnchorElement;
}
namespace JSX {
interface IntrinsicElements {
"ion-route-link": JSXElements.IonRouteLinkAttributes;
"ion-anchor": JSXElements.IonAnchorAttributes;
}
}
namespace JSXElements {
export interface IonRouteLinkAttributes extends HTMLAttributes {
router?: any;
url?: string;
export interface IonAnchorAttributes extends HTMLAttributes {
href?: string;
}
}
}

View File

@ -1,7 +1,7 @@
import { Component, Element, Event, EventEmitter, Prop, State } from '@stencil/core';
import { CssClassMap } from '../../index';
import { BlurEvent, FocusEvent } from '../../utils/input-interfaces';
import { getButtonClassMap, getElementClassMap } from '../../utils/theme';
import { getButtonClassMap, getElementClassMap, openURL } from '../../utils/theme';
@Component({
@ -133,16 +133,16 @@ export class Button {
const attrs = (TagType === 'button')
? { type: this.type }
: {};
: { href: this.href };
return (
<TagType
{...attrs}
class={buttonClasses}
disabled={this.disabled}
href={this.href}
onFocus={this.onFocus.bind(this)}
onKeyUp={this.onKeyUp.bind(this)}
onClick={(ev) => openURL(this.href, ev)}
onBlur={this.onBlur.bind(this)}>
<span class='button-inner'>
<slot name='icon-only'></slot>

View File

@ -1,5 +1,5 @@
import { Component, Element, Listen, Prop, State } from '@stencil/core';
import { createThemedClasses, getElementClassMap } from '../../utils/theme';
import { createThemedClasses, getElementClassMap, openURL } from '../../utils/theme';
import { CssClassMap } from '../../index';
@ -104,10 +104,10 @@ export class Item {
const clickable = !!(this.href || this.onclick || this.tappable);
let TagType = 'div';
if (clickable) {
TagType = this.href ? 'a' : 'button';
}
const TagType = clickable
? this.href ? 'a' : 'button'
: 'div';
const attrs = (TagType === 'button')
? {type: 'button'}
: {href: this.href};
@ -125,7 +125,10 @@ export class Item {
this.hasStyleChange = false;
return (
<TagType class={themedClasses} {...attrs}>
<TagType
{...attrs}
class={themedClasses}
onClick={(ev) => openURL(this.href, ev)}>
<slot name='start'></slot>
<div class='item-inner'>
<div class='input-wrapper'>

View File

@ -7,24 +7,14 @@
## Properties
#### router
any
#### url
#### href
string
## Attributes
#### router
any
#### url
#### href
string

View File

@ -1,12 +1,17 @@
import { Component, Prop } from '@stencil/core';
import { openURL } from '../../utils/theme';
@Component({
tag: 'ion-route-link'
tag: 'ion-anchor'
})
export class RouteLink {
@Prop() url: string;
// The instance of the router
@Prop() router: any;
@Prop() href: string;
render() {
return <a
href={this.href}
onClick={(ev) => openURL(this.href, ev)}><slot/></a>;
}
}

View File

@ -29,6 +29,11 @@ string
boolean
## Methods
#### pushURL()
----------------------------------------------

View File

@ -1,8 +1,8 @@
import { Component, Element, Listen, Prop } from '@stencil/core';
import { Component, Element, Listen, Method, Prop } from '@stencil/core';
import { Config, DomController } from '../../index';
import { flattenRouterTree, readRoutes } from './utils/parser';
import { readNavState, writeNavState } from './utils/dom';
import { chainToPath, readPath, writePath } from './utils/path';
import { chainToPath, parsePath, readPath, writePath } from './utils/path';
import { RouteChain } from './utils/interfaces';
import { routerIDsToChain, routerPathToChain } from './utils/matching';
@ -42,10 +42,7 @@ export class Router {
this.state++;
window.history.replaceState(this.state, document.title, document.location.href);
}
if (!this.busy) {
console.debug('[OUT] hash changed -> write nav state');
this.writeNavStateRoot();
}
this.writeNavStateRoot();
}
@Listen('body:ionNavChanged')
@ -63,21 +60,34 @@ export class Router {
}
const isPop = ev.detail.isPop === true;
this.writePath(chain, isPop);
const path = chainToPath(chain);
this.writePath(path, isPop);
}
@Method()
pushURL(url: string) {
this.writePath(parsePath(url), false);
return this.writeNavStateRoot();
}
private writeNavStateRoot(): Promise<any> {
const node = document.querySelector('ion-app');
const currentPath = this.readPath();
const direction = window.history.state >= this.state ? 1 : -1;
if (currentPath) {
const {chain} = routerPathToChain(currentPath, this.routes);
return this.writeNavState(node, chain, direction);
if (this.busy) {
return Promise.resolve();
}
return Promise.resolve();
const currentPath = this.readPath();
if (!currentPath) {
return Promise.resolve();
}
const direction = window.history.state >= this.state ? 1 : -1;
const node = document.querySelector('ion-app');
const {chain} = routerPathToChain(currentPath, this.routes);
return this.writeNavState(node, chain, direction);
}
private writeNavState(node: any, chain: RouteChain, direction: number): Promise<any> {
if (this.busy) {
return Promise.resolve();
}
this.busy = true;
return writeNavState(node, chain, 0, direction)
.catch(err => console.error(err))
@ -89,8 +99,7 @@ export class Router {
return readNavState(root);
}
private writePath(chain: RouteChain, isPop: boolean) {
const path = chainToPath(chain);
private writePath(path: string[], isPop: boolean) {
this.state = writePath(window.history, this.base, this.useHash, path, isPop, this.state);
}

View File

@ -62,3 +62,14 @@ export function getClassMap(classes: string | undefined): CssClassMap {
return map;
}
export function openURL(url: string, ev: Event) {
if (url && url.indexOf('://') === -1) {
const router = document.querySelector('ion-router');
if (router) {
ev && ev.preventDefault();
return router.componentOnReady().then(() => router.pushURL(url));
}
}
return Promise.resolve();
}