mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-22 21:48:42 +08:00
feat(animations): back button and view animationsa (#13989)
* feat(animations): back button and view animations * chore(): remove unused css * fix(): fix unsaved css * fix(): hide back button when no history
This commit is contained in:
2
packages/core/src/components.d.ts
vendored
2
packages/core/src/components.d.ts
vendored
@ -312,7 +312,7 @@ declare global {
|
||||
}
|
||||
namespace JSXElements {
|
||||
export interface IonBackButtonAttributes extends HTMLAttributes {
|
||||
|
||||
mode?: 'ios' | 'md';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
@import "./back-button";
|
||||
@import "./back-button.ios.vars";
|
||||
|
||||
// iOS Back Button
|
||||
// --------------------------------------------------
|
@ -1,4 +0,0 @@
|
||||
@import "../../themes/ionic.globals.ios";
|
||||
|
||||
// iOS Back Button
|
||||
// --------------------------------------------------
|
@ -1,22 +0,0 @@
|
||||
@import "./back-button";
|
||||
@import "./back-button.md.vars";
|
||||
|
||||
// Material Design Back Button
|
||||
// --------------------------------------------------
|
||||
|
||||
.back-button-md {
|
||||
@include margin(0, 6px);
|
||||
|
||||
min-width: 44px;
|
||||
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.back-button-icon-md {
|
||||
@include margin(0);
|
||||
@include padding(0, 6px);
|
||||
@include text-align(start);
|
||||
|
||||
font-size: 2.4rem;
|
||||
font-weight: normal;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
@import "../../themes/ionic.globals.md";
|
||||
|
||||
// Material Design Back Button
|
||||
// --------------------------------------------------
|
@ -2,14 +2,12 @@
|
||||
// Back Button
|
||||
// --------------------------------------------------
|
||||
|
||||
// .back-button {
|
||||
// display: none;
|
||||
// }
|
||||
|
||||
// .back-button.show-back-button {
|
||||
.back-button {
|
||||
display: inline-block;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.back-button.show-back-button {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.back-button-text {
|
||||
|
@ -1,53 +1,53 @@
|
||||
import { Component, Prop } from '@stencil/core';
|
||||
import { Component, Element, Prop, State } from '@stencil/core';
|
||||
import { Config } from '../../index';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'ion-back-button',
|
||||
styleUrls: {
|
||||
ios: 'back-button.ios.scss',
|
||||
md: 'back-button.md.scss'
|
||||
},
|
||||
styleUrl: 'back-button.scss',
|
||||
host: {
|
||||
theme: 'back-button'
|
||||
}
|
||||
})
|
||||
export class BackButton {
|
||||
private mode: string;
|
||||
|
||||
@State() custom: boolean;
|
||||
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
* Possible values are: `"ios"` or `"md"`.
|
||||
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
|
||||
*/
|
||||
@Prop() mode: 'ios' | 'md';
|
||||
|
||||
@Prop({ context: 'config' }) config: Config;
|
||||
|
||||
@Element() el: HTMLElement;
|
||||
|
||||
componentWillLoad() {
|
||||
this.custom = this.el.childElementCount > 0;
|
||||
}
|
||||
render() {
|
||||
const iconName = this.config.get('backButtonIcon', this.mode + '-arrow-back');
|
||||
const text = this.config.get('backButtonText', 'Back');
|
||||
const backButtonIcon = this.config.get('backButtonIcon', 'arrow-back');
|
||||
const backButtonText = this.config.get('backButtonText', 'Back');
|
||||
const buttonColor = this.mode === 'ios' ? 'primary' : '';
|
||||
|
||||
const iconClass: any = {
|
||||
'back-button-icon': true
|
||||
};
|
||||
const textClass: any = {
|
||||
'back-button-text': true
|
||||
};
|
||||
|
||||
if (this.mode) {
|
||||
iconClass['back-button-icon-' + this.mode] = true;
|
||||
iconClass['back-button-text-' + this.mode] = true;
|
||||
if (this.custom) {
|
||||
return (
|
||||
<ion-nav-pop>
|
||||
<slot />
|
||||
</ion-nav-pop>
|
||||
);
|
||||
} else if (!this.custom) {
|
||||
return (
|
||||
<ion-nav-pop>
|
||||
<ion-button color={buttonColor}>
|
||||
<ion-icon name={backButtonIcon} slot='start' />
|
||||
{backButtonText}
|
||||
</ion-button>
|
||||
</ion-nav-pop>
|
||||
);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<ion-nav-pop>
|
||||
<button>
|
||||
<span class={iconClass}>
|
||||
<slot name='icon'>
|
||||
<ion-icon name={iconName}></ion-icon>
|
||||
</slot>
|
||||
</span>
|
||||
<span class={textClass}>
|
||||
<slot name='text'>
|
||||
{text}
|
||||
</slot>
|
||||
</span>
|
||||
</button>
|
||||
</ion-nav-pop>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,86 @@
|
||||
# ion-back-button
|
||||
|
||||
A back button is a component that allows you navigate back into app history. To
|
||||
add a back button to your view, all you need is:
|
||||
|
||||
```html
|
||||
<ion-page>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-page>
|
||||
```
|
||||
|
||||
The back button component is smart enough to know what to render and what content to show.
|
||||
|
||||
If, however, you want more control over what is shown in the back button, you can pass your own button markup.
|
||||
|
||||
```html
|
||||
<ion-page>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button>
|
||||
<ion-button>
|
||||
Button Text
|
||||
<ion-icon name="add" slot="start"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-back-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-page>
|
||||
```
|
||||
|
||||
Or no button text at all:
|
||||
|
||||
|
||||
```html
|
||||
<ion-page>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button>
|
||||
<ion-button>
|
||||
<ion-icon name="add" slot="icon-only"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-back-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
</ion-page>
|
||||
```
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
#### mode
|
||||
|
||||
|
||||
|
||||
The mode determines which platform styles to use.
|
||||
Possible values are: `"ios"` or `"md"`.
|
||||
For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
|
||||
|
||||
|
||||
## Attributes
|
||||
|
||||
#### mode
|
||||
|
||||
|
||||
|
||||
The mode determines which platform styles to use.
|
||||
Possible values are: `"ios"` or `"md"`.
|
||||
For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -35,6 +35,9 @@
|
||||
firstPage.innerHTML = `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Page One</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
@ -47,7 +50,7 @@
|
||||
await nav.push(firstPage);
|
||||
|
||||
// okay cool, we're in the DOM now
|
||||
const button = firstPage.querySelector('ion-button');
|
||||
const button = firstPage.querySelector('.next');
|
||||
button.addEventListener('click', async () => {
|
||||
await goToPageTwo(nav);
|
||||
});
|
||||
@ -60,14 +63,14 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button>
|
||||
</ion-back-button>
|
||||
<ion-back-button></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Page Two</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
<h1>Page Two</h1>
|
||||
<p>Just an empty <code>ion-back-button</code></p>
|
||||
<ion-button class="next">Go to Page Three</ion-button>
|
||||
</ion-content>
|
||||
`;
|
||||
@ -89,6 +92,9 @@
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button>
|
||||
<ion-button>
|
||||
<ion-icon name="add" slot="icon-only"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Page Three</ion-title>
|
||||
@ -96,6 +102,7 @@
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
<h1>Page Three</h1>
|
||||
<p>Custom back button</p>
|
||||
</ion-content>
|
||||
`;
|
||||
|
||||
@ -103,10 +110,10 @@
|
||||
await nav.push(thirdPage);
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
ion-back-button {
|
||||
height: 50px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
<!-- <style> -->
|
||||
<!-- ion-back-button { -->
|
||||
<!-- height: 50px; -->
|
||||
<!-- background-color: blue; -->
|
||||
<!-- } -->
|
||||
<!-- </style> -->
|
||||
</html>
|
||||
|
@ -134,7 +134,7 @@ export class Button {
|
||||
<span class='button-inner'>
|
||||
<slot name='icon-only'></slot>
|
||||
<slot name='start'></slot>
|
||||
<slot></slot>
|
||||
<span class='button-text'><slot></slot></span>
|
||||
<slot name='end'></slot>
|
||||
</span>
|
||||
{ this.mode === 'md' && <ion-ripple-effect useTapClick={true} /> }
|
||||
|
@ -2,13 +2,6 @@ import { Component, Element, Listen } from '@stencil/core';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-nav-pop',
|
||||
styleUrls: {
|
||||
ios: 'nav-pop.ios.scss',
|
||||
md: 'nav-pop.md.scss'
|
||||
},
|
||||
host: {
|
||||
theme: 'nav-pop'
|
||||
}
|
||||
})
|
||||
export class NavPop {
|
||||
|
||||
|
@ -70,17 +70,15 @@ export function updateZIndex(viewController: ViewController, newZIndex: number)
|
||||
}
|
||||
}
|
||||
|
||||
export function toggleHidden(element: HTMLElement, isVisible: Boolean, shouldBeVisible: boolean) {
|
||||
if (isVisible !== shouldBeVisible) {
|
||||
element.hidden = shouldBeVisible;
|
||||
}
|
||||
export function toggleHidden(element: HTMLElement, shouldBeHidden: boolean) {
|
||||
element.hidden = shouldBeHidden;
|
||||
}
|
||||
|
||||
export function canNavGoBack(nav: Nav) {
|
||||
export function canNavGoBack(nav: Nav, view?: ViewController) {
|
||||
if (!nav) {
|
||||
return false;
|
||||
}
|
||||
return !!nav.getPrevious();
|
||||
return nav.getPrevious(view);
|
||||
}
|
||||
|
||||
export function transitionFactory(animation: Animation): Transition {
|
||||
|
@ -13,7 +13,10 @@ ion-nav {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
background-color: black;
|
||||
|
||||
contain: layout size style;
|
||||
|
||||
}
|
||||
|
||||
.ion-page {
|
||||
|
@ -737,7 +737,6 @@ export function loadViewAndTransition(nav: Nav, enteringView: ViewController, le
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function executeAsyncTransition(nav: Nav, transition: Transition, enteringView: ViewController, leavingView: ViewController, delegate: FrameworkDelegate, opts: NavOptions, configShouldAnimate: boolean): Promise<void> {
|
||||
assert(nav.transitioning, 'must be transitioning');
|
||||
nav.transitionId = null;
|
||||
@ -746,11 +745,11 @@ export function executeAsyncTransition(nav: Nav, transition: Transition, enterin
|
||||
// always ensure the entering view is viewable
|
||||
// ******** DOM WRITE ****************
|
||||
// TODO, figure out where we want to read this data from
|
||||
enteringView && toggleHidden(enteringView.element, true, true);
|
||||
enteringView && toggleHidden(enteringView.element, false);
|
||||
|
||||
// always ensure the leaving view is viewable
|
||||
// ******** DOM WRITE ****************
|
||||
leavingView && toggleHidden(leavingView.element, true, true);
|
||||
leavingView && toggleHidden(leavingView.element, false);
|
||||
|
||||
const isFirstPage = !nav.isViewInitialized && nav.views.length === 1;
|
||||
const shouldNotAnimate = isFirstPage && !nav.isPortal;
|
||||
@ -834,15 +833,16 @@ export function transitionFinish(nav: Nav, transition: Transition, delegate: Fra
|
||||
}
|
||||
|
||||
export function cleanUpView(nav: Nav, delegate: FrameworkDelegate, activeViewController: ViewController): Promise<any> {
|
||||
|
||||
if (nav.destroyed) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const activeIndex = nav.views.indexOf(activeViewController);
|
||||
const promises: Promise<any>[] = [];
|
||||
|
||||
for (let i = nav.views.length - 1; i >= 0; i--) {
|
||||
const inactiveViewController = nav.views[i];
|
||||
|
||||
if (i > activeIndex) {
|
||||
// this view comes after the active view
|
||||
inactiveViewController.willUnload();
|
||||
@ -850,14 +850,14 @@ export function cleanUpView(nav: Nav, delegate: FrameworkDelegate, activeViewCon
|
||||
} else if ( i < activeIndex && !nav.isPortal) {
|
||||
// this view comes before the active view
|
||||
// and it is not a portal then ensure it is hidden
|
||||
toggleHidden(inactiveViewController.element, true, false);
|
||||
toggleHidden(inactiveViewController.element, true);
|
||||
}
|
||||
|
||||
// TODO - review existing z index code!
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
|
||||
export function fireViewWillLifecycles(enteringView: ViewController, leavingView: ViewController) {
|
||||
leavingView && leavingView.willLeave(!enteringView);
|
||||
enteringView && enteringView.willEnter();
|
||||
|
@ -11,174 +11,198 @@ const CENTER = '0%';
|
||||
const OFF_OPACITY = 0.8;
|
||||
const SHOW_BACK_BTN_CSS = 'show-back-button';
|
||||
|
||||
// TODO - make sure this uses the `ion-page` logic from the md transition
|
||||
// DO this later since the transition is broke as a joke anyway
|
||||
// Dan B 1/9/2018
|
||||
|
||||
export function buildIOSTransition(rootTransition: Transition, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions): Promise<Transition> {
|
||||
|
||||
rootTransition.enteringView = enteringView;
|
||||
rootTransition.leavingView = leavingView;
|
||||
|
||||
const isRTL = document.dir === 'rtl';
|
||||
const OFF_RIGHT = isRTL ? '-99.5%' : '99.5%';
|
||||
const OFF_LEFT = isRTL ? '33%' : '-33%';
|
||||
|
||||
rootTransition.duration(isDef(opts.duration) ? opts.duration : DURATION);
|
||||
rootTransition.easing(isDef(opts.easing) ? opts.easing : EASING);
|
||||
|
||||
|
||||
rootTransition.addElement(enteringView.element);
|
||||
rootTransition.beforeRemoveClass('hide-page');
|
||||
|
||||
const backDirection = (opts.direction === 'back');
|
||||
|
||||
const componentReadyPromise: Promise<any>[] = [];
|
||||
// Let makes sure everything is hydrated and ready to animate
|
||||
if (enteringView) {
|
||||
const enteringContent = rootTransition.create();
|
||||
enteringContent.addElement(enteringView.element.querySelectorAll('ion-header > *:not(ion-toolbar),ion-footer > *'));
|
||||
componentReadyPromise.push((enteringView.element as any).componentOnReady());
|
||||
}
|
||||
if (leavingView) {
|
||||
componentReadyPromise.push((leavingView.element as any).componentOnReady());
|
||||
}
|
||||
|
||||
rootTransition.add(enteringContent);
|
||||
return Promise.all(componentReadyPromise).then(() => {
|
||||
// Cool we're all hydrated, and can do deep selector
|
||||
rootTransition.enteringView = enteringView;
|
||||
rootTransition.leavingView = leavingView;
|
||||
|
||||
if (backDirection) {
|
||||
enteringContent.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true).fromTo(OPACITY, OFF_OPACITY, 1, true);
|
||||
} else {
|
||||
// entering content, forward direction
|
||||
enteringContent.beforeClearStyles([OPACITY]).fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
|
||||
}
|
||||
const isRTL = document.dir === 'rtl';
|
||||
const OFF_RIGHT = isRTL ? '-99.5%' : '99.5%';
|
||||
const OFF_LEFT = isRTL ? '33%' : '-33%';
|
||||
|
||||
const enteringToolBarEle = enteringView.element.querySelector('ion-toolbar');
|
||||
if (enteringToolBarEle) {
|
||||
const enteringToolBar = rootTransition.create();
|
||||
enteringToolBar.addElement(enteringToolBarEle);
|
||||
rootTransition.duration(isDef(opts.duration) ? opts.duration : DURATION);
|
||||
rootTransition.easing(isDef(opts.easing) ? opts.easing : EASING);
|
||||
|
||||
rootTransition.add(enteringToolBar);
|
||||
|
||||
const enteringTitle = rootTransition.create();
|
||||
enteringTitle.addElement(enteringToolBarEle.querySelector('ion-title'));
|
||||
const enteringToolBarItems = rootTransition.create();
|
||||
enteringToolBarItems.addElement(enteringToolBarEle.querySelectorAll('ion-buttons,[menuToggle]'));
|
||||
const enteringToolBarBg = rootTransition.create();
|
||||
enteringToolBarBg.addElement(enteringToolBarEle.querySelector('.toolbar-background'));
|
||||
const enteringBackButton = rootTransition.create();
|
||||
enteringBackButton.addElement(enteringToolBarEle.querySelector('.back-button'));
|
||||
rootTransition.addElement(enteringView.element);
|
||||
rootTransition.beforeRemoveClass('hide-page');
|
||||
|
||||
enteringToolBar
|
||||
.add(enteringTitle)
|
||||
.add(enteringToolBarItems)
|
||||
.add(enteringToolBarBg)
|
||||
.add(enteringBackButton);
|
||||
const backDirection = (opts.direction === 'back');
|
||||
|
||||
enteringTitle.fromTo(OPACITY, 0.01, 1, true);
|
||||
enteringToolBarItems.fromTo(OPACITY, 0.01, 1, true);
|
||||
// setting up enter view
|
||||
if (enteringView) {
|
||||
|
||||
const enteringContent = rootTransition.create();
|
||||
enteringContent.addElement(enteringView.element.querySelector('ion-content'));
|
||||
enteringContent.addElement(enteringView.element.querySelectorAll('ion-header > *:not(ion-toolbar),ion-footer > *'));
|
||||
rootTransition.add(enteringContent);
|
||||
|
||||
if (backDirection) {
|
||||
enteringTitle.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true);
|
||||
|
||||
if (canNavGoBack(enteringView.nav)) {
|
||||
// back direction, entering page has a back button
|
||||
enteringBackButton.beforeAddClass(SHOW_BACK_BTN_CSS).fromTo(OPACITY, 0.01, 1, true);
|
||||
}
|
||||
enteringContent
|
||||
.beforeClearStyles([OPACITY])
|
||||
.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true)
|
||||
.fromTo(OPACITY, OFF_OPACITY, 1, true);
|
||||
} else {
|
||||
// entering toolbar, forward direction
|
||||
enteringTitle.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
|
||||
// entering content, forward direction
|
||||
enteringContent
|
||||
.beforeClearStyles([OPACITY])
|
||||
.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
|
||||
|
||||
enteringToolBarBg.beforeClearStyles([OPACITY]).fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
|
||||
}
|
||||
|
||||
if (canNavGoBack(enteringView.nav)) {
|
||||
// forward direction, entering page has a back button
|
||||
enteringBackButton.beforeAddClass(SHOW_BACK_BTN_CSS).fromTo(OPACITY, 0.01, 1, true);
|
||||
const enteringToolBarEle = enteringView.element.querySelector('ion-toolbar');
|
||||
if (enteringToolBarEle) {
|
||||
const enteringToolBar = rootTransition.create();
|
||||
enteringToolBar.addElement(enteringToolBarEle);
|
||||
rootTransition.add(enteringToolBar);
|
||||
|
||||
const enteringTitle = rootTransition.create();
|
||||
enteringTitle.addElement(enteringToolBarEle.querySelector('ion-title'));
|
||||
|
||||
const enteringBackBtnText = rootTransition.create();
|
||||
enteringBackBtnText.addElement(enteringToolBarEle.querySelector('.back-button-text'));
|
||||
const enteringToolBarItems = rootTransition.create();
|
||||
enteringToolBarItems.addElement(enteringToolBarEle.querySelectorAll('ion-buttons,[menuToggle]'));
|
||||
|
||||
enteringBackBtnText.fromTo(TRANSLATEX, (isRTL ? '-100px' : '100px'), '0px');
|
||||
enteringToolBar.add(enteringBackBtnText);
|
||||
const enteringToolBarBg = rootTransition.create();
|
||||
enteringToolBarBg.addElement(enteringToolBarEle.querySelector('.toolbar-background'));
|
||||
|
||||
const enteringBackButton = rootTransition.create();
|
||||
enteringBackButton.addElement(enteringToolBarEle.querySelector('.back-button'));
|
||||
|
||||
enteringToolBar
|
||||
.add(enteringTitle)
|
||||
.add(enteringToolBarItems)
|
||||
.add(enteringToolBarBg)
|
||||
.add(enteringBackButton);
|
||||
|
||||
enteringTitle.fromTo(OPACITY, 0.01, 1, true);
|
||||
enteringToolBarItems.fromTo(OPACITY, 0.01, 1, true);
|
||||
|
||||
if (backDirection) {
|
||||
enteringTitle.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true);
|
||||
|
||||
if (canNavGoBack(enteringView.nav, enteringView)) {
|
||||
// back direction, entering page has a back button
|
||||
enteringBackButton.beforeAddClass(SHOW_BACK_BTN_CSS).fromTo(OPACITY, 0.01, 1, true);
|
||||
}
|
||||
} else {
|
||||
enteringBackButton.beforeRemoveClass(SHOW_BACK_BTN_CSS);
|
||||
// entering toolbar, forward direction
|
||||
enteringTitle.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
|
||||
|
||||
enteringToolBarBg
|
||||
.beforeClearStyles([OPACITY])
|
||||
.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
|
||||
|
||||
if (canNavGoBack(enteringView.nav, enteringView)) {
|
||||
|
||||
// forward direction, entering page has a back button
|
||||
enteringBackButton
|
||||
.beforeAddClass(SHOW_BACK_BTN_CSS)
|
||||
.fromTo(OPACITY, 0.01, 1, true);
|
||||
|
||||
|
||||
const enteringBackBtnText = rootTransition.create();
|
||||
enteringBackBtnText.addElement(enteringToolBarEle.querySelector('.back-button .button-text'));
|
||||
|
||||
enteringBackBtnText.fromTo(TRANSLATEX, (isRTL ? '-100px' : '100px'), '0px');
|
||||
enteringToolBar.add(enteringBackBtnText);
|
||||
} else {
|
||||
enteringBackButton.beforeRemoveClass(SHOW_BACK_BTN_CSS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup leaving view
|
||||
if (leavingView) {
|
||||
// setup leaving view
|
||||
if (leavingView) {
|
||||
|
||||
const leavingContent = rootTransition.create();
|
||||
leavingContent.addElement(leavingView.element);
|
||||
leavingContent.addElement(leavingView.element.querySelectorAll('ion-header > *:not(ion-toolbar),ion-footer > *'));
|
||||
|
||||
rootTransition.add(leavingContent);
|
||||
|
||||
if (backDirection) {
|
||||
// leaving content, back direction
|
||||
leavingContent.beforeClearStyles([OPACITY]).fromTo(TRANSLATEX, CENTER, (isRTL ? '-100%' : '100%'));
|
||||
|
||||
} else {
|
||||
// leaving content, forward direction
|
||||
leavingContent
|
||||
.fromTo(TRANSLATEX, CENTER, OFF_LEFT)
|
||||
.fromTo(OPACITY, 1, OFF_OPACITY)
|
||||
.afterClearStyles([TRANSFORM, OPACITY]);
|
||||
}
|
||||
|
||||
const leavingToolBarEle = leavingView.element.querySelector('ion-toolbar');
|
||||
if (leavingToolBarEle) {
|
||||
const leavingToolBar = rootTransition.create();
|
||||
leavingToolBar.addElement(leavingToolBarEle);
|
||||
|
||||
const leavingTitle = rootTransition.create();
|
||||
leavingTitle.addElement(leavingToolBarEle.querySelector('ion-title'));
|
||||
|
||||
const leavingToolBarItems = rootTransition.create();
|
||||
leavingToolBarItems.addElement(leavingToolBarEle.querySelectorAll('ion-buttons,[menuToggle]'));
|
||||
|
||||
const leavingToolBarBg = rootTransition.create();
|
||||
leavingToolBarBg.addElement(leavingToolBarEle.querySelector('.toolbar-background'));
|
||||
|
||||
const leavingBackButton = rootTransition.create();
|
||||
leavingBackButton.addElement(leavingToolBarEle.querySelector('.back-button'));
|
||||
|
||||
leavingToolBar
|
||||
.add(leavingTitle)
|
||||
.add(leavingToolBarItems)
|
||||
.add(leavingBackButton)
|
||||
.add(leavingToolBarBg);
|
||||
|
||||
rootTransition.add(leavingToolBar);
|
||||
|
||||
// fade out leaving toolbar items
|
||||
leavingBackButton.fromTo(OPACITY, 0.99, 0);
|
||||
leavingTitle.fromTo(OPACITY, 0.99, 0);
|
||||
leavingToolBarItems.fromTo(OPACITY, 0.99, 0);
|
||||
const leavingContent = rootTransition.create();
|
||||
leavingContent.addElement(leavingView.element.querySelector('ion-content'));
|
||||
leavingContent.addElement(leavingView.element.querySelectorAll('ion-header > *:not(ion-toolbar),ion-footer > *'));
|
||||
rootTransition.add(leavingContent);
|
||||
|
||||
if (backDirection) {
|
||||
// leaving toolbar, back direction
|
||||
leavingTitle.fromTo(TRANSLATEX, CENTER, (isRTL ? '-100%' : '100%'));
|
||||
|
||||
// leaving toolbar, back direction, and there's no entering toolbar
|
||||
// should just slide out, no fading out
|
||||
leavingToolBarBg
|
||||
// leaving content, back direction
|
||||
leavingContent
|
||||
.beforeClearStyles([OPACITY])
|
||||
.fromTo(TRANSLATEX, CENTER, (isRTL ? '-100%' : '100%'));
|
||||
|
||||
const leavingBackBtnText = rootTransition.create();
|
||||
leavingBackBtnText.addElement(leavingToolBarEle.querySelector('.back-button-text'));
|
||||
leavingBackBtnText.fromTo(TRANSLATEX, CENTER, (isRTL ? -300 : 300) + 'px');
|
||||
leavingToolBar.add(leavingBackBtnText);
|
||||
|
||||
} else {
|
||||
// leaving toolbar, forward direction
|
||||
leavingTitle
|
||||
.fromTo(TRANSLATEX, CENTER, OFF_LEFT)
|
||||
.afterClearStyles([TRANSFORM]);
|
||||
// leaving content, forward direction
|
||||
leavingContent
|
||||
.fromTo(TRANSLATEX, CENTER, OFF_LEFT, true)
|
||||
.fromTo(OPACITY, 1, OFF_OPACITY, true);
|
||||
}
|
||||
|
||||
leavingBackButton.afterClearStyles([OPACITY]);
|
||||
leavingTitle.afterClearStyles([OPACITY]);
|
||||
leavingToolBarItems.afterClearStyles([OPACITY]);
|
||||
const leavingToolBarEle = leavingView.element.querySelector('ion-toolbar');
|
||||
if (leavingToolBarEle) {
|
||||
const leavingToolBar = rootTransition.create();
|
||||
leavingToolBar.addElement(leavingToolBarEle);
|
||||
|
||||
const leavingTitle = rootTransition.create();
|
||||
leavingTitle.addElement(leavingToolBarEle.querySelector('ion-title'));
|
||||
|
||||
const leavingToolBarItems = rootTransition.create();
|
||||
leavingToolBarItems.addElement(leavingToolBarEle.querySelectorAll('ion-buttons,[menuToggle]'));
|
||||
|
||||
const leavingToolBarBg = rootTransition.create();
|
||||
leavingToolBarBg.addElement(leavingToolBarEle.querySelector('.toolbar-background'));
|
||||
|
||||
const leavingBackButton = rootTransition.create();
|
||||
leavingBackButton.addElement(leavingToolBarEle.querySelector('.back-button'));
|
||||
|
||||
leavingToolBar
|
||||
.add(leavingTitle)
|
||||
.add(leavingToolBarItems)
|
||||
.add(leavingBackButton)
|
||||
.add(leavingToolBarBg);
|
||||
|
||||
rootTransition.add(leavingToolBar);
|
||||
|
||||
// fade out leaving toolbar items
|
||||
leavingBackButton.fromTo(OPACITY, 0.99, 0, true);
|
||||
leavingTitle.fromTo(OPACITY, 0.99, 0, true);
|
||||
leavingToolBarItems.fromTo(OPACITY, 0.99, 0, true);
|
||||
|
||||
if (backDirection) {
|
||||
// leaving toolbar, back direction
|
||||
leavingTitle.fromTo(TRANSLATEX, CENTER, (isRTL ? '-100%' : '100%'));
|
||||
|
||||
// leaving toolbar, back direction, and there's no entering toolbar
|
||||
// should just slide out, no fading out
|
||||
leavingToolBarBg
|
||||
.beforeClearStyles([OPACITY])
|
||||
.fromTo(TRANSLATEX, CENTER, (isRTL ? '-100%' : '100%'));
|
||||
|
||||
const leavingBackBtnText = rootTransition.create();
|
||||
leavingBackBtnText.addElement(leavingToolBarEle.querySelector('.back-button .button-text'));
|
||||
leavingBackBtnText.fromTo(TRANSLATEX, CENTER, (isRTL ? -300 : 300) + 'px');
|
||||
leavingToolBar.add(leavingBackBtnText);
|
||||
|
||||
} else {
|
||||
// leaving toolbar, forward direction
|
||||
leavingTitle
|
||||
.fromTo(TRANSLATEX, CENTER, OFF_LEFT)
|
||||
.afterClearStyles([TRANSFORM]);
|
||||
|
||||
leavingBackButton.afterClearStyles([OPACITY]);
|
||||
leavingTitle.afterClearStyles([OPACITY]);
|
||||
leavingToolBarItems.afterClearStyles([OPACITY]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.resolve(rootTransition);
|
||||
|
||||
// Return the rootTransition promise
|
||||
return rootTransition;
|
||||
});
|
||||
}
|
||||
|
@ -9,6 +9,15 @@ const SHOW_BACK_BTN_CSS = 'show-back-button';
|
||||
|
||||
export function buildMdTransition(rootTransition: Transition, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions): Promise<Transition> {
|
||||
|
||||
const componentReadyPromise: Promise<any>[] = [];
|
||||
if (enteringView) {
|
||||
componentReadyPromise.push((enteringView.element as any).componentOnReady());
|
||||
}
|
||||
if (leavingView) {
|
||||
componentReadyPromise.push((leavingView.element as any).componentOnReady());
|
||||
}
|
||||
|
||||
return Promise.all(componentReadyPromise).then(() => {
|
||||
rootTransition.enteringView = enteringView;
|
||||
rootTransition.leavingView = leavingView;
|
||||
|
||||
@ -19,9 +28,12 @@ export function buildMdTransition(rootTransition: Transition, enteringView: View
|
||||
|
||||
const backDirection = (opts.direction === 'back');
|
||||
if (enteringView) {
|
||||
|
||||
// animate the component itself
|
||||
if (backDirection) {
|
||||
rootTransition.duration(isDef(opts.duration) ? opts.duration : 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
rootTransition.duration(isDef(opts.duration) ? opts.duration : 280).easing('cubic-bezier(0.36,0.66,0.04,1)');
|
||||
|
||||
rootTransition
|
||||
@ -29,8 +41,10 @@ export function buildMdTransition(rootTransition: Transition, enteringView: View
|
||||
.fromTo('opacity', 0.01, 1, true);
|
||||
}
|
||||
|
||||
// Animate toolbar if it's there
|
||||
const enteringToolbarEle = ionPageElement.querySelector('ion-toolbar');
|
||||
if (enteringToolbarEle) {
|
||||
|
||||
const enteringToolBar = rootTransition.create();
|
||||
enteringToolBar.addElement(enteringToolbarEle);
|
||||
rootTransition.add(enteringToolBar);
|
||||
@ -38,8 +52,7 @@ export function buildMdTransition(rootTransition: Transition, enteringView: View
|
||||
const enteringBackButton = rootTransition.create();
|
||||
enteringBackButton.addElement(enteringToolbarEle.querySelector('.back-button'));
|
||||
rootTransition.add(enteringBackButton);
|
||||
|
||||
if (canNavGoBack(enteringView.nav)) {
|
||||
if (canNavGoBack(enteringView.nav, enteringView)) {
|
||||
enteringBackButton.beforeAddClass(SHOW_BACK_BTN_CSS);
|
||||
} else {
|
||||
enteringBackButton.beforeRemoveClass(SHOW_BACK_BTN_CSS);
|
||||
@ -56,7 +69,10 @@ export function buildMdTransition(rootTransition: Transition, enteringView: View
|
||||
rootTransition.add(leavingPage.fromTo(TRANSLATEY, CENTER, OFF_BOTTOM).fromTo('opacity', 1, 0));
|
||||
}
|
||||
|
||||
return Promise.resolve(rootTransition);
|
||||
return rootTransition;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function getIonPageElement(element: HTMLElement) {
|
||||
|
@ -299,33 +299,33 @@
|
||||
// iOS Toolbar Back Button
|
||||
// --------------------------------------------------
|
||||
|
||||
.back-button-ios {
|
||||
@include margin(0);
|
||||
|
||||
z-index: $z-index-toolbar-buttons;
|
||||
overflow: visible;
|
||||
|
||||
order: map-get($toolbar-order-ios, back-button);
|
||||
|
||||
min-height: 32px;
|
||||
|
||||
line-height: 1;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
.back-button-icon-ios {
|
||||
@include margin(-1px, 0, 0, 0);
|
||||
|
||||
display: inherit;
|
||||
|
||||
min-width: 18px;
|
||||
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.back-button-text-ios {
|
||||
letter-spacing: -.01em;
|
||||
}
|
||||
// .back-button-ios {
|
||||
// @include margin(0);
|
||||
//
|
||||
// z-index: $z-index-toolbar-buttons;
|
||||
// overflow: visible;
|
||||
//
|
||||
// order: map-get($toolbar-order-ios, back-button);
|
||||
//
|
||||
// min-height: 32px;
|
||||
//
|
||||
// line-height: 1;
|
||||
// transform: translateZ(0);
|
||||
// }
|
||||
//
|
||||
// .back-button-icon-ios {
|
||||
// @include margin(-1px, 0, 0, 0);
|
||||
//
|
||||
// display: inherit;
|
||||
//
|
||||
// min-width: 18px;
|
||||
//
|
||||
// font-size: 34px;
|
||||
// }
|
||||
//
|
||||
// .back-button-text-ios {
|
||||
// letter-spacing: -.01em;
|
||||
// }
|
||||
|
||||
|
||||
// iOS Toolbar Menu Toggle
|
||||
|
@ -130,20 +130,3 @@ ion-buttons,
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
// Back Button
|
||||
// --------------------------------------------------
|
||||
|
||||
.back-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.back-button.show-back-button {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.back-button-text {
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
export function isCordova(): boolean {
|
||||
const win = window as any;
|
||||
return !!(win['cordova'] || win['PhoneGap'] || win['phonegap']);
|
||||
return !!(win['cordova'] || win['PhoneGap'] || win['phonegap'] || win['Capacitor']);
|
||||
}
|
||||
|
Reference in New Issue
Block a user