Skip to content

Commit

Permalink
feat(ion-router-outlet): adds router-outlet
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat committed Mar 21, 2018
1 parent 17a3001 commit c03afab
Show file tree
Hide file tree
Showing 6 changed files with 324 additions and 27 deletions.
33 changes: 33 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
Side,
} from './utils/helpers';
import {
AnimationBuilder as AnimationBuilder2,
FrameworkDelegate as FrameworkDelegate2,
} from '.';
import {
Expand Down Expand Up @@ -2623,6 +2624,38 @@ declare global {
}


import {
RouterOutlet as IonRouterOutlet
} from './components/router-outlet/route-outlet';

declare global {
interface HTMLIonRouterOutletElement extends IonRouterOutlet, HTMLStencilElement {
}
var HTMLIonRouterOutletElement: {
prototype: HTMLIonRouterOutletElement;
new (): HTMLIonRouterOutletElement;
};
interface HTMLElementTagNameMap {
"ion-router-outlet": HTMLIonRouterOutletElement;
}
interface ElementTagNameMap {
"ion-router-outlet": HTMLIonRouterOutletElement;
}
namespace JSX {
interface IntrinsicElements {
"ion-router-outlet": JSXElements.IonRouterOutletAttributes;
}
}
namespace JSXElements {
export interface IonRouterOutletAttributes extends HTMLAttributes {
animated?: boolean;
animationBuilder?: AnimationBuilder;
delegate?: FrameworkDelegate;
}
}
}


import {
Router as IonRouter
} from './components/router/router';
Expand Down
29 changes: 29 additions & 0 deletions core/src/components/app/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,35 @@ ion-app,
contain: layout size style;
}

.hide-page {
opacity: 0;
}

// TODO: move to somewhere else

$navigation-ios-transition-background: #000 !default;

.nav-decor {
display: none;
}

.show-decor > .nav-decor {
@include position(0, null, null, 0);

// when ios pages transition, the leaving page grays out
// this is the black square behind all pages so they gray out
position: absolute;
z-index: 0;
display: block;

width: 100%;
height: 100%;

background: $navigation-ios-transition-background;

pointer-events: none;
}

// Misc
// --------------------------------------------------

Expand Down
27 changes: 0 additions & 27 deletions core/src/components/nav/nav.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
@import "../../themes/util";

$navigation-ios-transition-background: #000 !default;

ion-nav {
@include position(0);

Expand All @@ -14,28 +12,3 @@ ion-nav {

contain: layout size style;
}

.hide-page {
opacity: 0;
}

.nav-decor {
display: none;
}

.show-decor > .nav-decor {
@include position(0, null, null, 0);

// when ios pages transition, the leaving page grays out
// this is the black square behind all pages so they gray out
position: absolute;
z-index: 0;
display: block;

width: 100%;
height: 100%;

background: $navigation-ios-transition-background;

pointer-events: none;
}
59 changes: 59 additions & 0 deletions core/src/components/router-outlet/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# ion-router-outlet



<!-- Auto Generated Below -->


## Properties

#### animated

boolean


#### animationBuilder




#### delegate




## Attributes

#### animated

boolean


#### animation-builder




#### delegate




## Methods

#### commit()


#### getRouteId()


#### setRoot()


#### setRouteId()



----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
125 changes: 125 additions & 0 deletions core/src/components/router-outlet/route-outlet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { Component, Element, Method, Prop } from '@stencil/core';
import { transition } from '../../utils';
import { NavDirection } from '../nav/nav-util';
import { AnimationBuilder, Config, FrameworkDelegate, NavOutlet } from '../..';
import { attachComponent, detachComponent } from '../../utils/overlays';

import iosTransitionAnimation from '../nav/animations/ios.transition';
import mdTransitionAnimation from '../nav/animations/md.transition';
import { RouteID, RouteWrite } from '../router/utils/interfaces';

@Component({
tag: 'ion-router-outlet'
})
export class RouterOutlet implements NavOutlet {

private isTransitioning = false;
private activeEl: HTMLElement = undefined;

mode: string;

@Element() el: HTMLElement;

@Prop({context: 'config'}) config: Config;
@Prop({connect: 'ion-animation-controller'}) animationCtrl: HTMLIonAnimationControllerElement;

@Prop() animated = true;
@Prop() animationBuilder: AnimationBuilder;
@Prop() delegate: FrameworkDelegate;

componentDidUnload() {
this.activeEl = undefined;
}

@Method()
async setRoot(component: HTMLElement|string, params?: {[key: string]: any}, opts?: RouterOutletOptions): Promise<boolean> {
if (this.isTransitioning) {
return false;
}
// attach entering view to DOM
const enteringEl = await attachComponent(this.delegate, this.el, component, NAV_CLASSES, params);
const leavingEl = this.activeEl;

// commit animation
await this.commit(enteringEl, opts);

// remove leaving view
detachComponent(this.delegate, leavingEl);

return true;
}

@Method()
async commit(enteringEl: HTMLElement, opts?: RouterOutletOptions): Promise<boolean> {
// isTransitioning acts as a lock to prevent reentering
if (this.isTransitioning || this.activeEl === enteringEl) {
return false;
}
this.isTransitioning = true;

opts = opts || {};

await transition({
animationBuilder: this.getAnimationBuilder(opts),
direction: opts.direction,
duration: opts.duration,
easing: opts.easing,

animationCtrl: this.animationCtrl,
enteringEl: enteringEl,
leavingEl: this.activeEl,
baseEl: this.el,
});
this.activeEl = enteringEl;
this.isTransitioning = false;
return true;
}

@Method()
async setRouteId(id: string, data: any, direction: number): Promise<RouteWrite> {
const changed = await this.setRoot(id, data, {
duration: direction === 0 ? 0 : undefined,
direction: direction === -1 ? NavDirection.back : NavDirection.forward,
});
return {
changed,
element: this.activeEl
};
}

@Method()
getRouteId(): RouteID|undefined {
const active = this.activeEl;
return active ? {
id: active.tagName,
element: active,
} : undefined;
}

private getAnimationBuilder(opts: RouterOutletOptions) {
if (opts.duration === 0 || this.animated === false || this.activeEl === undefined) {
return undefined;
}
const mode = opts.mode || this.config.get('pageTransition', this.mode);
return opts.animationBuilder
|| this.animationBuilder
|| mode === 'ios' ? iosTransitionAnimation : mdTransitionAnimation;
}

render() {
return [
this.mode === 'ios' && <div class='nav-decor'/>,
<slot/>
];
}
}

export interface RouterOutletOptions {
animationBuilder?: AnimationBuilder;
duration?: number;
easing?: string;
direction?: NavDirection;
mode?: 'md' | 'ios';
}

const NAV_CLASSES = {'ion-page': true, 'hide-page': true};
78 changes: 78 additions & 0 deletions core/src/components/router-outlet/test/basic/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!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>
class PageOne extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<ion-header>
<ion-toolbar>
<ion-title>Page One</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<h1>Page One</h1>
<ion-button href="#/two">Go to Page Two</ion-button>
</ion-content>
`;
}
}
class PageTwo extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button text="Page One"></ion-back-button>
</ion-buttons>
<ion-title>Page Two</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<h1>Page Two</h1>
<div>
<ion-nav-push component="page-three">
<ion-button href="#/page-3">Go to Page Two</ion-button>
</ion-nav-push>
</div>
</ion-content>
`;
}
}
class PageThree extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button text="Page Two"></ion-back-button>
</ion-buttons>
<ion-title>Page Three</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<h1>Page Three</h1>
</ion-content>
`;
}
}
customElements.define('page-one', PageOne);
customElements.define('page-two', PageTwo);
customElements.define('page-three', PageThree);
</script>
</head>
<body>
<ion-app>
<ion-router>
<ion-route url="/" component="page-one"> </ion-route>
<ion-route url="/two" component="page-two"> </ion-route>
<ion-route url="/page-3" component="page-three"> </ion-route>
</ion-router>
<ion-router-outlet></ion-router-outlet>
</ion-app>
</body>
</html>

0 comments on commit c03afab

Please sign in to comment.