From f34d3752e3462c9d81487fc86af5ec185cc3d1e3 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 8 Jun 2020 15:49:14 -0400 Subject: [PATCH] feat(all): add support for configuring animations on a per-page basis (#21433) --- .../directives/navigation/ion-back-button.ts | 7 ++- .../navigation/router-link-delegate.ts | 7 ++- .../directives/navigation/stack-controller.ts | 42 ++++++++++--- .../src/directives/navigation/stack-utils.ts | 3 +- angular/src/directives/proxies.ts | 24 +++---- angular/src/providers/nav-controller.ts | 20 +++--- .../src/app/alert/alert.component.html | 3 + .../app/home-page/home-page.component.html | 2 +- .../src/app/home-page/home-page.component.ts | 16 +++++ core/api.txt | 9 ++- core/src/components.d.ts | 62 ++++++++++++++++++- .../components/back-button/back-button.tsx | 12 +++- core/src/components/back-button/readme.md | 19 +++--- core/src/components/button/button.tsx | 10 ++- core/src/components/button/readme.md | 1 + core/src/components/card/card.tsx | 12 +++- core/src/components/card/readme.md | 25 ++++---- core/src/components/fab-button/fab-button.tsx | 10 ++- core/src/components/fab-button/readme.md | 31 +++++----- core/src/components/item/item.tsx | 12 +++- core/src/components/item/readme.md | 31 +++++----- .../src/components/nav-link/nav-link-utils.ts | 10 +-- core/src/components/nav-link/nav-link.tsx | 9 ++- core/src/components/nav-link/readme.md | 1 + core/src/components/nav/nav.tsx | 27 ++++++-- core/src/components/nav/view-controller.ts | 3 +- core/src/components/router-link/readme.md | 15 ++--- .../components/router-link/router-link.tsx | 10 ++- .../components/router-outlet/route-outlet.tsx | 3 +- core/src/components/router/readme.md | 2 +- core/src/components/router/router.tsx | 19 +++--- core/src/components/router/utils/dom.ts | 9 +-- core/src/components/router/utils/interface.ts | 4 +- core/src/utils/theme.ts | 6 +- 34 files changed, 334 insertions(+), 142 deletions(-) diff --git a/angular/src/directives/navigation/ion-back-button.ts b/angular/src/directives/navigation/ion-back-button.ts index d4ba31407c..e642306380 100644 --- a/angular/src/directives/navigation/ion-back-button.ts +++ b/angular/src/directives/navigation/ion-back-button.ts @@ -1,4 +1,5 @@ import { Directive, HostListener, Optional } from '@angular/core'; +import { AnimationBuilder } from '@ionic/core'; import { Config } from '../../providers/config'; import { NavController } from '../../providers/nav-controller'; @@ -7,11 +8,12 @@ import { IonRouterOutlet } from './ion-router-outlet'; @Directive({ selector: 'ion-back-button', - inputs: ['defaultHref'], + inputs: ['defaultHref', 'routerAnimation'], }) export class IonBackButtonDelegate { defaultHref: string | undefined | null; + routerAnimation?: AnimationBuilder; constructor( @Optional() private routerOutlet: IonRouterOutlet, @@ -27,10 +29,11 @@ export class IonBackButtonDelegate { const defaultHref = this.defaultHref || this.config.get('backButtonDefaultHref'); if (this.routerOutlet && this.routerOutlet.canGoBack()) { + this.navCtrl.setDirection('back', undefined, undefined, this.routerAnimation); this.routerOutlet.pop(); ev.preventDefault(); } else if (defaultHref != null) { - this.navCtrl.navigateBack(defaultHref); + this.navCtrl.navigateBack(defaultHref, { animation: this.routerAnimation }); ev.preventDefault(); } } diff --git a/angular/src/directives/navigation/router-link-delegate.ts b/angular/src/directives/navigation/router-link-delegate.ts index b3c73c7bb7..b992e86ffe 100644 --- a/angular/src/directives/navigation/router-link-delegate.ts +++ b/angular/src/directives/navigation/router-link-delegate.ts @@ -1,20 +1,21 @@ import { LocationStrategy } from '@angular/common'; import { Directive, ElementRef, HostListener, Optional } from '@angular/core'; import { Router, RouterLink } from '@angular/router'; -import { RouterDirection } from '@ionic/core'; +import { AnimationBuilder, RouterDirection } from '@ionic/core'; import { Subscription } from 'rxjs'; import { NavController } from '../../providers/nav-controller'; @Directive({ selector: '[routerLink]', - inputs: ['routerDirection'] + inputs: ['routerDirection', 'routerAnimation'] }) export class RouterLinkDelegate { private subscription?: Subscription; routerDirection: RouterDirection = 'forward'; + routerAnimation?: AnimationBuilder; constructor( private locationStrategy: LocationStrategy, @@ -50,7 +51,7 @@ export class RouterLinkDelegate { */ @HostListener('click', ['$event']) onClick(ev: UIEvent) { - this.navCtrl.setDirection(this.routerDirection); + this.navCtrl.setDirection(this.routerDirection, undefined, undefined, this.routerAnimation); ev.preventDefault(); } } diff --git a/angular/src/directives/navigation/stack-controller.ts b/angular/src/directives/navigation/stack-controller.ts index 3465bbe371..3274277833 100644 --- a/angular/src/directives/navigation/stack-controller.ts +++ b/angular/src/directives/navigation/stack-controller.ts @@ -1,7 +1,7 @@ import { Location } from '@angular/common'; import { ComponentRef, NgZone } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { RouterDirection } from '@ionic/core'; +import { AnimationBuilder, RouterDirection } from '@ionic/core'; import { bindLifecycleEvents } from '../../providers/angular-delegate'; import { NavController } from '../../providers/nav-controller'; @@ -52,7 +52,8 @@ export class StackController { } setActive(enteringView: RouteView): Promise { - let { direction, animation } = this.navCtrl.consumeTransition(); + const consumeResult = this.navCtrl.consumeTransition(); + let { direction, animation, animationBuilder } = consumeResult; const leavingView = this.activeView; const tabSwitch = isTabSwitch(enteringView, leavingView); if (tabSwitch) { @@ -105,6 +106,31 @@ export class StackController { enteringView.ref.changeDetectorRef.detectChanges(); } + /** + * If we are going back from a page that + * was presented using a custom animation + * we should default to using that + * unless the developer explicitly + * provided another animation. + */ + const customAnimation = enteringView.animationBuilder; + if ( + animationBuilder === undefined && + direction === 'back' && + !tabSwitch && + customAnimation !== undefined + ) { + animationBuilder = customAnimation; + } + + /** + * Save any custom animation so that navigating + * back will use this custom animation by default. + */ + if (animationBuilder !== undefined && leavingView) { + leavingView.animationBuilder = animationBuilder; + } + // Wait until previous transitions finish return this.zone.runOutsideAngular(() => { return this.wait(() => { @@ -116,7 +142,7 @@ export class StackController { // In case the enteringView is the same as the leavingPage we need to reattach() enteringView.ref.changeDetectorRef.reattach(); - return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false) + return this.transition(enteringView, leavingView, animation, this.canGoBack(1), false, animationBuilder) .then(() => cleanupAsync(enteringView, views, viewsSnapshot, this.location)) .then(() => ({ enteringView, @@ -154,8 +180,8 @@ export class StackController { url = primaryOutlet.route._routerState.snapshot.url; } } - - return this.navCtrl.navigateBack(url, view.savedExtras).then(() => true); + const { animationBuilder } = this.navCtrl.consumeTransition(); + return this.navCtrl.navigateBack(url, { ...view.savedExtras, animation: animationBuilder }).then(() => true); }); } @@ -225,7 +251,8 @@ export class StackController { leavingView: RouteView | undefined, direction: 'forward' | 'back' | undefined, showGoBack: boolean, - progressAnimation: boolean + progressAnimation: boolean, + animationBuilder?: AnimationBuilder ) { if (this.skipTransition) { this.skipTransition = false; @@ -250,7 +277,8 @@ export class StackController { duration: direction === undefined ? 0 : undefined, direction, showGoBack, - progressAnimation + progressAnimation, + animationBuilder }); } } diff --git a/angular/src/directives/navigation/stack-utils.ts b/angular/src/directives/navigation/stack-utils.ts index b6ab21c24a..23c5cd5404 100644 --- a/angular/src/directives/navigation/stack-utils.ts +++ b/angular/src/directives/navigation/stack-utils.ts @@ -1,6 +1,6 @@ import { ComponentRef } from '@angular/core'; import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; -import { NavDirection, RouterDirection } from '@ionic/core'; +import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core'; export const insertView = (views: RouteView[], view: RouteView, direction: RouterDirection) => { if (direction === 'root') { @@ -96,4 +96,5 @@ export interface RouteView { savedData?: any; savedExtras?: NavigationExtras; unlistenEvents: () => void; + animationBuilder?: AnimationBuilder; } diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts index d1ca187a0c..dd2a60a831 100644 --- a/angular/src/directives/proxies.ts +++ b/angular/src/directives/proxies.ts @@ -26,8 +26,8 @@ export class IonAvatar { } export declare interface IonBackButton extends Components.IonBackButton { } -@ProxyCmp({ inputs: ["color", "defaultHref", "disabled", "icon", "mode", "text", "type"] }) -@Component({ selector: "ion-back-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["color", "defaultHref", "disabled", "icon", "mode", "text", "type"] }) +@ProxyCmp({ inputs: ["color", "defaultHref", "disabled", "icon", "mode", "routerAnimation", "text", "type"] }) +@Component({ selector: "ion-back-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["color", "defaultHref", "disabled", "icon", "mode", "routerAnimation", "text", "type"] }) export class IonBackButton { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { @@ -61,8 +61,8 @@ export class IonBadge { } export declare interface IonButton extends Components.IonButton { } -@ProxyCmp({ inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerDirection", "shape", "size", "strong", "target", "type"] }) -@Component({ selector: "ion-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerDirection", "shape", "size", "strong", "target", "type"] }) +@ProxyCmp({ inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }) +@Component({ selector: "ion-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }) export class IonButton { ionFocus!: EventEmitter; ionBlur!: EventEmitter; @@ -86,8 +86,8 @@ export class IonButtons { } export declare interface IonCard extends Components.IonCard { } -@ProxyCmp({ inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "target", "type"] }) -@Component({ selector: "ion-card", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "target", "type"] }) +@ProxyCmp({ inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }) +@Component({ selector: "ion-card", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }) export class IonCard { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { @@ -220,8 +220,8 @@ export class IonFab { } export declare interface IonFabButton extends Components.IonFabButton { } -@ProxyCmp({ inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "show", "size", "target", "translucent", "type"] }) -@Component({ selector: "ion-fab-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerDirection", "show", "size", "target", "translucent", "type"] }) +@ProxyCmp({ inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] }) +@Component({ selector: "ion-fab-button", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["activated", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] }) export class IonFabButton { ionFocus!: EventEmitter; ionBlur!: EventEmitter; @@ -344,8 +344,8 @@ export class IonInput { } export declare interface IonItem extends Components.IonItem { } -@ProxyCmp({ inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerDirection", "target", "type"] }) -@Component({ selector: "ion-item", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerDirection", "target", "type"] }) +@ProxyCmp({ inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }) +@Component({ selector: "ion-item", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }) export class IonItem { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { @@ -498,8 +498,8 @@ export class IonNav { } export declare interface IonNavLink extends Components.IonNavLink { } -@ProxyCmp({ inputs: ["component", "componentProps", "routerDirection"] }) -@Component({ selector: "ion-nav-link", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["component", "componentProps", "routerDirection"] }) +@ProxyCmp({ inputs: ["component", "componentProps", "routerAnimation", "routerDirection"] }) +@Component({ selector: "ion-nav-link", changeDetection: ChangeDetectionStrategy.OnPush, template: "", inputs: ["component", "componentProps", "routerAnimation", "routerDirection"] }) export class IonNavLink { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { diff --git a/angular/src/providers/nav-controller.ts b/angular/src/providers/nav-controller.ts index a5d8786ea0..e99d45c523 100644 --- a/angular/src/providers/nav-controller.ts +++ b/angular/src/providers/nav-controller.ts @@ -1,7 +1,7 @@ import { Location } from '@angular/common'; import { Injectable, Optional } from '@angular/core'; import { NavigationExtras, NavigationStart, Router, UrlSerializer, UrlTree } from '@angular/router'; -import { NavDirection, RouterDirection } from '@ionic/core'; +import { AnimationBuilder, NavDirection, RouterDirection } from '@ionic/core'; import { IonRouterOutlet } from '../directives/navigation/ion-router-outlet'; @@ -9,6 +9,7 @@ import { Platform } from './platform'; export interface AnimationOptions { animated?: boolean; + animation?: AnimationBuilder; animationDirection?: 'forward' | 'back'; } @@ -22,6 +23,7 @@ export class NavController { private topOutlet?: IonRouterOutlet; private direction: 'forward' | 'back' | 'root' | 'auto' = DEFAULT_DIRECTION; private animated?: NavDirection = DEFAULT_ANIMATED; + private animationBuilder?: AnimationBuilder; private guessDirection: RouterDirection = 'forward'; private guessAnimation?: NavDirection; private lastNavId = -1; @@ -65,7 +67,7 @@ export class NavController { * ``` */ navigateForward(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise { - this.setDirection('forward', options.animated, options.animationDirection); + this.setDirection('forward', options.animated, options.animationDirection, options.animation); return this.navigate(url, options); } @@ -88,7 +90,7 @@ export class NavController { * ``` */ navigateBack(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise { - this.setDirection('back', options.animated, options.animationDirection); + this.setDirection('back', options.animated, options.animationDirection, options.animation); return this.navigate(url, options); } @@ -111,7 +113,7 @@ export class NavController { * ``` */ navigateRoot(url: string | UrlTree | any[], options: NavigationOptions = {}): Promise { - this.setDirection('root', options.animated, options.animationDirection); + this.setDirection('root', options.animated, options.animationDirection, options.animation); return this.navigate(url, options); } @@ -121,7 +123,7 @@ export class NavController { * by default. */ back(options: AnimationOptions = { animated: true, animationDirection: 'back' }) { - this.setDirection('back', options.animated, options.animationDirection); + this.setDirection('back', options.animated, options.animationDirection, options.animation); return this.location.back(); } @@ -150,9 +152,10 @@ export class NavController { * * It's recommended to use `navigateForward()`, `navigateBack()` and `navigateRoot()` instead of `setDirection()`. */ - setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back') { + setDirection(direction: RouterDirection, animated?: boolean, animationDirection?: 'forward' | 'back', animationBuilder?: AnimationBuilder) { this.direction = direction; this.animated = getAnimation(direction, animated, animationDirection); + this.animationBuilder = animationBuilder; } /** @@ -168,6 +171,7 @@ export class NavController { consumeTransition() { let direction: RouterDirection = 'root'; let animation: NavDirection | undefined; + const animationBuilder = this.animationBuilder; if (this.direction === 'auto') { direction = this.guessDirection; @@ -178,10 +182,12 @@ export class NavController { } this.direction = DEFAULT_DIRECTION; this.animated = DEFAULT_ANIMATED; + this.animationBuilder = undefined; return { direction, - animation + animation, + animationBuilder }; } diff --git a/angular/test/test-app/src/app/alert/alert.component.html b/angular/test/test-app/src/app/alert/alert.component.html index e3e40fc692..8bb91e0cba 100644 --- a/angular/test/test-app/src/app/alert/alert.component.html +++ b/angular/test/test-app/src/app/alert/alert.component.html @@ -1,5 +1,8 @@ + + + Alert test diff --git a/angular/test/test-app/src/app/home-page/home-page.component.html b/angular/test/test-app/src/app/home-page/home-page.component.html index f4fd908cab..8609ca6997 100644 --- a/angular/test/test-app/src/app/home-page/home-page.component.html +++ b/angular/test/test-app/src/app/home-page/home-page.component.html @@ -7,7 +7,7 @@ - + Alerts test diff --git a/angular/test/test-app/src/app/home-page/home-page.component.ts b/angular/test/test-app/src/app/home-page/home-page.component.ts index a5b32ea17f..bddd005df8 100644 --- a/angular/test/test-app/src/app/home-page/home-page.component.ts +++ b/angular/test/test-app/src/app/home-page/home-page.component.ts @@ -1,9 +1,25 @@ import { Component } from '@angular/core'; +import { AnimationBuilder, AnimationController } from '@ionic/angular'; @Component({ selector: 'app-home-page', templateUrl: './home-page.component.html', }) export class HomePageComponent { + routerAnimation: AnimationBuilder = (_, opts) => { + const { direction, enteringEl, leavingEl } = opts; + const animation = this.animationCtrl.create().duration(500).easing('ease-out'); + const enteringAnimation = this.animationCtrl.create().addElement(enteringEl).beforeRemoveClass(['ion-page-invisible']); + const leavingAnimation = this.animationCtrl.create().addElement(leavingEl).beforeRemoveClass(['ion-page-invisible']); + if (direction === 'back') { + enteringAnimation.fromTo('transform', 'translateX(-100%)', 'translateX(0%)'); + leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(100%)'); + } else { + enteringAnimation.fromTo('transform', 'translateX(100%)', 'translateX(0%)'); + leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(-100%)'); + } + return animation.addAnimation([enteringAnimation, leavingAnimation]); + }; + constructor(private animationCtrl: AnimationController) {} } diff --git a/core/api.txt b/core/api.txt index e9086b0e57..0feb35cf61 100644 --- a/core/api.txt +++ b/core/api.txt @@ -85,6 +85,7 @@ ion-back-button,prop,defaultHref,string | undefined,undefined,false,false ion-back-button,prop,disabled,boolean,false,false,true ion-back-button,prop,icon,null | string | undefined,undefined,false,false ion-back-button,prop,mode,"ios" | "md",undefined,false,false +ion-back-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-back-button,prop,text,null | string | undefined,undefined,false,false ion-back-button,prop,type,"button" | "reset" | "submit",'button',false,false ion-back-button,css-prop,--background @@ -146,6 +147,7 @@ ion-button,prop,fill,"clear" | "default" | "outline" | "solid" | undefined,undef ion-button,prop,href,string | undefined,undefined,false,false ion-button,prop,mode,"ios" | "md",undefined,false,false ion-button,prop,rel,string | undefined,undefined,false,false +ion-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,false ion-button,prop,shape,"round" | undefined,undefined,false,true ion-button,prop,size,"default" | "large" | "small" | undefined,undefined,false,true @@ -189,6 +191,7 @@ ion-card,prop,download,string | undefined,undefined,false,false ion-card,prop,href,string | undefined,undefined,false,false ion-card,prop,mode,"ios" | "md",undefined,false,false ion-card,prop,rel,string | undefined,undefined,false,false +ion-card,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-card,prop,routerDirection,"back" | "forward" | "root",'forward',false,false ion-card,prop,target,string | undefined,undefined,false,false ion-card,prop,type,"button" | "reset" | "submit",'button',false,false @@ -357,6 +360,7 @@ ion-fab-button,prop,download,string | undefined,undefined,false,false ion-fab-button,prop,href,string | undefined,undefined,false,false ion-fab-button,prop,mode,"ios" | "md",undefined,false,false ion-fab-button,prop,rel,string | undefined,undefined,false,false +ion-fab-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-fab-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,false ion-fab-button,prop,show,boolean,false,false,false ion-fab-button,prop,size,"small" | undefined,undefined,false,false @@ -492,6 +496,7 @@ ion-item,prop,href,string | undefined,undefined,false,false ion-item,prop,lines,"full" | "inset" | "none" | undefined,undefined,false,false ion-item,prop,mode,"ios" | "md",undefined,false,false ion-item,prop,rel,string | undefined,undefined,false,false +ion-item,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-item,prop,routerDirection,"back" | "forward" | "root",'forward',false,false ion-item,prop,target,string | undefined,undefined,false,false ion-item,prop,type,"button" | "reset" | "submit",'button',false,false @@ -740,6 +745,7 @@ ion-nav,event,ionNavWillChange,void,false ion-nav-link,none ion-nav-link,prop,component,Function | HTMLElement | ViewController | null | string | undefined,undefined,false,false ion-nav-link,prop,componentProps,undefined | { [key: string]: any; },undefined,false,false +ion-nav-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-nav-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false ion-note,shadow @@ -927,7 +933,7 @@ ion-router,none ion-router,prop,root,string,'/',false,false ion-router,prop,useHash,boolean,true,false,false ion-router,method,back,back() => Promise -ion-router,method,push,push(url: string, direction?: RouterDirection) => Promise +ion-router,method,push,push(url: string, direction?: RouterDirection, animation?: AnimationBuilder | undefined) => Promise ion-router,event,ionRouteDidChange,RouterEventDetail,true ion-router,event,ionRouteWillChange,RouterEventDetail,true @@ -935,6 +941,7 @@ ion-router-link,shadow ion-router-link,prop,color,string | undefined,undefined,false,false ion-router-link,prop,href,string | undefined,undefined,false,false ion-router-link,prop,rel,string | undefined,undefined,false,false +ion-router-link,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-router-link,prop,routerDirection,"back" | "forward" | "root",'forward',false,false ion-router-link,prop,target,string | undefined,undefined,false,false ion-router-link,css-prop,--background diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 4ddbacb283..d1d3d3e874 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -172,6 +172,10 @@ export namespace Components { * The mode determines which platform styles to use. */ "mode"?: "ios" | "md"; + /** + * When using a router, it specifies the transition animation when navigating to another page. + */ + "routerAnimation": AnimationBuilder | undefined; /** * The text to display in the back button. */ @@ -242,6 +246,10 @@ export namespace Components { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel": string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation": AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ @@ -302,6 +310,10 @@ export namespace Components { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel": string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation": AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ @@ -700,6 +712,10 @@ export namespace Components { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel": string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation": AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ @@ -966,6 +982,10 @@ export namespace Components { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel": string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation": AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ @@ -1443,7 +1463,7 @@ export namespace Components { * @param done The transition complete function. */ "setRoot": (component: T, componentProps?: ComponentProps | null | undefined, opts?: NavOptions | null | undefined, done?: TransitionDoneFn | undefined) => Promise; - "setRouteId": (id: string, params: ComponentProps | undefined, direction: RouterDirection) => Promise; + "setRouteId": (id: string, params: ComponentProps | undefined, direction: RouterDirection, animation?: AnimationBuilder | undefined) => Promise; /** * If the nav component should allow for swipe-to-go-back. */ @@ -1458,6 +1478,10 @@ export namespace Components { * Data you want to pass to the component as props. Only used if the `"routerDirection"` is `"forward"` or `"root"`. */ "componentProps"?: ComponentProps; + /** + * The transition animation when navigating to another page. + */ + "routerAnimation"?: AnimationBuilder; /** * The transition direction when navigating to another page. */ @@ -1854,7 +1878,7 @@ export namespace Components { * @param url The url to navigate to. * @param direction The direction of the animation. Defaults to `"forward"`. */ - "push": (url: string, direction?: RouterDirection) => Promise; + "push": (url: string, direction?: RouterDirection, animation?: AnimationBuilder | undefined) => Promise; /** * By default `ion-router` will match the routes at the root path ("/"). That can be changed when */ @@ -1877,6 +1901,10 @@ export namespace Components { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel": string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation": AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ @@ -1902,7 +1930,7 @@ export namespace Components { * The mode determines which platform styles to use. */ "mode": "ios" | "md"; - "setRouteId": (id: string, params: ComponentProps | undefined, direction: RouterDirection) => Promise; + "setRouteId": (id: string, params: ComponentProps | undefined, direction: RouterDirection, animation?: AnimationBuilder | undefined) => Promise; "swipeHandler"?: SwipeGestureHandler; } interface IonRow { @@ -3404,6 +3432,10 @@ declare namespace LocalJSX { * The mode determines which platform styles to use. */ "mode"?: "ios" | "md"; + /** + * When using a router, it specifies the transition animation when navigating to another page. + */ + "routerAnimation"?: AnimationBuilder | undefined; /** * The text to display in the back button. */ @@ -3486,6 +3518,10 @@ declare namespace LocalJSX { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel"?: string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation"?: AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ @@ -3546,6 +3582,10 @@ declare namespace LocalJSX { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel"?: string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation"?: AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ @@ -3956,6 +3996,10 @@ declare namespace LocalJSX { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel"?: string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation"?: AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ @@ -4242,6 +4286,10 @@ declare namespace LocalJSX { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel"?: string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation"?: AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ @@ -4620,6 +4668,10 @@ declare namespace LocalJSX { * Data you want to pass to the component as props. Only used if the `"routerDirection"` is `"forward"` or `"root"`. */ "componentProps"?: ComponentProps; + /** + * The transition animation when navigating to another page. + */ + "routerAnimation"?: AnimationBuilder; /** * The transition direction when navigating to another page. */ @@ -5048,6 +5100,10 @@ declare namespace LocalJSX { * Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). */ "rel"?: string | undefined; + /** + * When using a router, it specifies the transition animation when navigating to another page using `href`. + */ + "routerAnimation"?: AnimationBuilder | undefined; /** * When using a router, it specifies the transition direction when navigating to another page using `href`. */ diff --git a/core/src/components/back-button/back-button.tsx b/core/src/components/back-button/back-button.tsx index b5f6dfe437..886456c7a9 100644 --- a/core/src/components/back-button/back-button.tsx +++ b/core/src/components/back-button/back-button.tsx @@ -2,7 +2,7 @@ import { Component, ComponentInterface, Element, Host, Prop, h } from '@stencil/ import { config } from '../../global/config'; import { getIonMode } from '../../global/ionic-global'; -import { Color } from '../../interface'; +import { AnimationBuilder, Color } from '../../interface'; import { ButtonInterface } from '../../utils/element-interface'; import { createColorClasses, hostContext, openURL } from '../../utils/theme'; @@ -53,6 +53,12 @@ export class BackButton implements ComponentInterface, ButtonInterface { */ @Prop() type: 'submit' | 'reset' | 'button' = 'button'; + /** + * When using a router, it specifies the transition animation when navigating to + * another page. + */ + @Prop() routerAnimation: AnimationBuilder | undefined; + componentWillLoad() { if (this.defaultHref === undefined) { this.defaultHref = config.get('backButtonDefaultHref'); @@ -99,9 +105,9 @@ export class BackButton implements ComponentInterface, ButtonInterface { ev.preventDefault(); if (nav && await nav.canGoBack()) { - return nav.pop({ skipIfBusy: true }); + return nav.pop({ animationBuilder: this.routerAnimation, skipIfBusy: true }); } - return openURL(this.defaultHref, ev, 'back'); + return openURL(this.defaultHref, ev, 'back', this.routerAnimation); } render() { diff --git a/core/src/components/back-button/readme.md b/core/src/components/back-button/readme.md index 173c554321..0f8b6fc70d 100644 --- a/core/src/components/back-button/readme.md +++ b/core/src/components/back-button/readme.md @@ -301,15 +301,16 @@ export class BackButtonExample { ## Properties -| Property | Attribute | Description | Type | Default | -| ------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------- | -| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | -| `defaultHref` | `default-href` | The url to navigate back to by default when there is no history. | `string \| undefined` | `undefined` | -| `disabled` | `disabled` | If `true`, the user cannot interact with the button. | `boolean` | `false` | -| `icon` | `icon` | The icon name to use for the back button. | `null \| string \| undefined` | `undefined` | -| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | -| `text` | `text` | The text to display in the back button. | `null \| string \| undefined` | `undefined` | -| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` | +| Property | Attribute | Description | Type | Default | +| ----------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- | +| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | +| `defaultHref` | `default-href` | The url to navigate back to by default when there is no history. | `string \| undefined` | `undefined` | +| `disabled` | `disabled` | If `true`, the user cannot interact with the button. | `boolean` | `false` | +| `icon` | `icon` | The icon name to use for the back button. | `null \| string \| undefined` | `undefined` | +| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | +| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` | +| `text` | `text` | The text to display in the back button. | `null \| string \| undefined` | `undefined` | +| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` | ## CSS Custom Properties diff --git a/core/src/components/button/button.tsx b/core/src/components/button/button.tsx index 43f9c112ba..1cb4a8f138 100644 --- a/core/src/components/button/button.tsx +++ b/core/src/components/button/button.tsx @@ -1,7 +1,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; -import { Color, RouterDirection } from '../../interface'; +import { AnimationBuilder, Color, RouterDirection } from '../../interface'; import { AnchorInterface, ButtonInterface } from '../../utils/element-interface'; import { hasShadowDom } from '../../utils/helpers'; import { createColorClasses, hostContext, openURL } from '../../utils/theme'; @@ -65,6 +65,12 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf */ @Prop() routerDirection: RouterDirection = 'forward'; + /** + * When using a router, it specifies the transition animation when navigating to + * another page using `href`. + */ + @Prop() routerAnimation: AnimationBuilder | undefined; + /** * This attribute instructs browsers to download a URL instead of navigating to * it, so the user will be prompted to save it as a local file. If the attribute @@ -146,7 +152,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf private handleClick = (ev: Event) => { if (this.type === 'button') { - openURL(this.href, ev, this.routerDirection); + openURL(this.href, ev, this.routerDirection, this.routerAnimation); } else if (hasShadowDom(this.el)) { // this button wants to specifically submit a form diff --git a/core/src/components/button/readme.md b/core/src/components/button/readme.md index b8fd10007c..408315db9b 100644 --- a/core/src/components/button/readme.md +++ b/core/src/components/button/readme.md @@ -291,6 +291,7 @@ export class ButtonExample { | `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | | `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | | `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` | +| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` | | `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | | `shape` | `shape` | The button shape. | `"round" \| undefined` | `undefined` | | `size` | `size` | The button size. | `"default" \| "large" \| "small" \| undefined` | `undefined` | diff --git a/core/src/components/card/card.tsx b/core/src/components/card/card.tsx index d25ec70b0c..d571bc693e 100644 --- a/core/src/components/card/card.tsx +++ b/core/src/components/card/card.tsx @@ -1,7 +1,7 @@ import { Component, ComponentInterface, Host, Prop, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; -import { Color, Mode, RouterDirection } from '../../interface'; +import { AnimationBuilder, Color, Mode, RouterDirection } from '../../interface'; import { AnchorInterface, ButtonInterface } from '../../utils/element-interface'; import { createColorClasses, openURL } from '../../utils/theme'; @@ -66,6 +66,12 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac */ @Prop() routerDirection: RouterDirection = 'forward'; + /** + * When using a router, it specifies the transition animation when navigating to + * another page using `href`. + */ + @Prop() routerAnimation: AnimationBuilder | undefined; + /** * Specifies where to display the linked URL. * Only applies when an `href` is provided. @@ -85,7 +91,7 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac ]; } - const { href, routerDirection } = this; + const { href, routerAnimation, routerDirection } = this; const TagType = clickable ? (href === undefined ? 'button' : 'a') : 'div' as any; const attrs = (TagType === 'button') ? { type: this.type } @@ -101,7 +107,7 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac {...attrs} class="card-native" disabled={this.disabled} - onClick={(ev: Event) => openURL(href, ev, routerDirection)} + onClick={(ev: Event) => openURL(href, ev, routerDirection, routerAnimation)} > {clickable && mode === 'md' && } diff --git a/core/src/components/card/readme.md b/core/src/components/card/readme.md index 66ef391017..0fdb87fa1e 100644 --- a/core/src/components/card/readme.md +++ b/core/src/components/card/readme.md @@ -254,18 +254,19 @@ export class CardExample { ## Properties -| Property | Attribute | Description | Type | Default | -| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------- | -| `button` | `button` | If `true`, a button tag will be rendered and the card will be tappable. | `boolean` | `false` | -| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | -| `disabled` | `disabled` | If `true`, the user cannot interact with the card. | `boolean` | `false` | -| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` | -| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | -| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | -| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` | -| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | -| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` | -| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` | +| Property | Attribute | Description | Type | Default | +| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- | +| `button` | `button` | If `true`, a button tag will be rendered and the card will be tappable. | `boolean` | `false` | +| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | +| `disabled` | `disabled` | If `true`, the user cannot interact with the card. | `boolean` | `false` | +| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` | +| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | +| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | +| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` | +| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` | +| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | +| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` | +| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` | ## CSS Custom Properties diff --git a/core/src/components/fab-button/fab-button.tsx b/core/src/components/fab-button/fab-button.tsx index 61ff7dad97..bc904d0850 100755 --- a/core/src/components/fab-button/fab-button.tsx +++ b/core/src/components/fab-button/fab-button.tsx @@ -1,7 +1,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; -import { Color, RouterDirection } from '../../interface'; +import { AnimationBuilder, Color, RouterDirection } from '../../interface'; import { AnchorInterface, ButtonInterface } from '../../utils/element-interface'; import { createColorClasses, hostContext, openURL } from '../../utils/theme'; @@ -62,6 +62,12 @@ export class FabButton implements ComponentInterface, AnchorInterface, ButtonInt */ @Prop() routerDirection: RouterDirection = 'forward'; + /** + * When using a router, it specifies the transition animation when navigating to + * another page using `href`. + */ + @Prop() routerAnimation: AnimationBuilder | undefined; + /** * Specifies where to display the linked URL. * Only applies when an `href` is provided. @@ -147,7 +153,7 @@ export class FabButton implements ComponentInterface, AnchorInterface, ButtonInt disabled={disabled} onFocus={this.onFocus} onBlur={this.onBlur} - onClick={(ev: Event) => openURL(href, ev, this.routerDirection)} + onClick={(ev: Event) => openURL(href, ev, this.routerDirection, this.routerAnimation)} > diff --git a/core/src/components/fab-button/readme.md b/core/src/components/fab-button/readme.md index efd025fee3..991205e8f8 100644 --- a/core/src/components/fab-button/readme.md +++ b/core/src/components/fab-button/readme.md @@ -137,21 +137,22 @@ export class FabButtonExample { ## Properties -| Property | Attribute | Description | Type | Default | -| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------- | -| `activated` | `activated` | If `true`, the fab button will be show a close icon. | `boolean` | `false` | -| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | -| `disabled` | `disabled` | If `true`, the user cannot interact with the fab button. | `boolean` | `false` | -| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` | -| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | -| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | -| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` | -| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | -| `show` | `show` | If `true`, the fab button will show when in a fab-list. | `boolean` | `false` | -| `size` | `size` | The size of the button. Set this to `small` in order to have a mini fab. | `"small" \| undefined` | `undefined` | -| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` | -| `translucent` | `translucent` | If `true`, the fab button will be translucent. Only applies when the mode is `"ios"` and the device supports [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). | `boolean` | `false` | -| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` | +| Property | Attribute | Description | Type | Default | +| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- | +| `activated` | `activated` | If `true`, the fab button will be show a close icon. | `boolean` | `false` | +| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | +| `disabled` | `disabled` | If `true`, the user cannot interact with the fab button. | `boolean` | `false` | +| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` | +| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | +| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | +| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` | +| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` | +| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | +| `show` | `show` | If `true`, the fab button will show when in a fab-list. | `boolean` | `false` | +| `size` | `size` | The size of the button. Set this to `small` in order to have a mini fab. | `"small" \| undefined` | `undefined` | +| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` | +| `translucent` | `translucent` | If `true`, the fab button will be translucent. Only applies when the mode is `"ios"` and the device supports [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility). | `boolean` | `false` | +| `type` | `type` | The type of the button. | `"button" \| "reset" \| "submit"` | `'button'` | ## Events diff --git a/core/src/components/item/item.tsx b/core/src/components/item/item.tsx index 6e69971e80..fb55dbfc32 100644 --- a/core/src/components/item/item.tsx +++ b/core/src/components/item/item.tsx @@ -1,7 +1,7 @@ import { Component, ComponentInterface, Element, Host, Listen, Prop, State, forceUpdate, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; -import { Color, CssClassMap, RouterDirection, StyleEventDetail } from '../../interface'; +import { AnimationBuilder, Color, CssClassMap, RouterDirection, StyleEventDetail } from '../../interface'; import { AnchorInterface, ButtonInterface } from '../../utils/element-interface'; import { createColorClasses, hostContext, openURL } from '../../utils/theme'; @@ -85,6 +85,12 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac */ @Prop() lines?: 'full' | 'inset' | 'none'; + /** + * When using a router, it specifies the transition animation when navigating to + * another page using `href`. + */ + @Prop() routerAnimation: AnimationBuilder | undefined; + /** * When using a router, it specifies the transition direction when navigating to * another page using `href`. @@ -170,7 +176,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac } render() { - const { detail, detailIcon, download, lines, disabled, href, rel, target, routerDirection } = this; + const { detail, detailIcon, download, lines, disabled, href, rel, target, routerAnimation, routerDirection } = this; const childStyles = {}; const mode = getIonMode(this); const clickable = this.isClickable(); @@ -209,7 +215,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac {...attrs} class="item-native" disabled={disabled} - onClick={(ev: Event) => openURL(href, ev, routerDirection)} + onClick={(ev: Event) => openURL(href, ev, routerDirection, routerAnimation)} >
diff --git a/core/src/components/item/readme.md b/core/src/components/item/readme.md index 3f8e436d5e..53791eb2d0 100644 --- a/core/src/components/item/readme.md +++ b/core/src/components/item/readme.md @@ -1783,21 +1783,22 @@ export class ItemExample { ## Properties -| Property | Attribute | Description | Type | Default | -| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------------------- | -| `button` | `button` | If `true`, a button tag will be rendered and the item will be tappable. | `boolean` | `false` | -| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | -| `detail` | `detail` | If `true`, a detail arrow will appear on the item. Defaults to `false` unless the `mode` is `ios` and an `href` or `button` property is present. | `boolean \| undefined` | `undefined` | -| `detailIcon` | `detail-icon` | The icon to use when `detail` is set to `true`. | `string` | `'chevron-forward'` | -| `disabled` | `disabled` | If `true`, the user cannot interact with the item. | `boolean` | `false` | -| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` | -| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | -| `lines` | `lines` | How the bottom border should be displayed on the item. | `"full" \| "inset" \| "none" \| undefined` | `undefined` | -| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | -| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` | -| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | -| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` | -| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` | +| Property | Attribute | Description | Type | Default | +| ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------- | +| `button` | `button` | If `true`, a button tag will be rendered and the item will be tappable. | `boolean` | `false` | +| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | +| `detail` | `detail` | If `true`, a detail arrow will appear on the item. Defaults to `false` unless the `mode` is `ios` and an `href` or `button` property is present. | `boolean \| undefined` | `undefined` | +| `detailIcon` | `detail-icon` | The icon to use when `detail` is set to `true`. | `string` | `'chevron-forward'` | +| `disabled` | `disabled` | If `true`, the user cannot interact with the item. | `boolean` | `false` | +| `download` | `download` | This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want). | `string \| undefined` | `undefined` | +| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | +| `lines` | `lines` | How the bottom border should be displayed on the item. | `"full" \| "inset" \| "none" \| undefined` | `undefined` | +| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | +| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` | +| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` | +| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | +| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` | +| `type` | `type` | The type of the button. Only used when an `onclick` or `button` property is present. | `"button" \| "reset" \| "submit"` | `'button'` | ## Slots diff --git a/core/src/components/nav-link/nav-link-utils.ts b/core/src/components/nav-link/nav-link-utils.ts index eea8851aea..e06d8740c8 100644 --- a/core/src/components/nav-link/nav-link-utils.ts +++ b/core/src/components/nav-link/nav-link-utils.ts @@ -1,19 +1,19 @@ -import { ComponentProps, NavComponent } from '../../interface'; +import { AnimationBuilder, ComponentProps, NavComponent } from '../../interface'; import { RouterDirection } from '../router/utils/interface'; -export const navLink = (el: HTMLElement, routerDirection: RouterDirection, component?: NavComponent, componentProps?: ComponentProps) => { +export const navLink = (el: HTMLElement, routerDirection: RouterDirection, component?: NavComponent, componentProps?: ComponentProps, routerAnimation?: AnimationBuilder) => { const nav = el.closest('ion-nav'); if (nav) { if (routerDirection === 'forward') { if (component !== undefined) { - return nav.push(component, componentProps, { skipIfBusy: true }); + return nav.push(component, componentProps, { skipIfBusy: true, animationBuilder: routerAnimation }); } } else if (routerDirection === 'root') { if (component !== undefined) { - return nav.setRoot(component, componentProps, { skipIfBusy: true }); + return nav.setRoot(component, componentProps, { skipIfBusy: true, animationBuilder: routerAnimation }); } } else if (routerDirection === 'back') { - return nav.pop({ skipIfBusy: true }); + return nav.pop({ skipIfBusy: true, animationBuilder: routerAnimation }); } } return Promise.resolve(false); diff --git a/core/src/components/nav-link/nav-link.tsx b/core/src/components/nav-link/nav-link.tsx index 5ca2a340ad..50a58d089e 100644 --- a/core/src/components/nav-link/nav-link.tsx +++ b/core/src/components/nav-link/nav-link.tsx @@ -1,6 +1,6 @@ import { Component, ComponentInterface, Element, Host, Prop, h } from '@stencil/core'; -import { ComponentProps, NavComponent, RouterDirection } from '../../interface'; +import { AnimationBuilder, ComponentProps, NavComponent, RouterDirection } from '../../interface'; import { navLink } from './nav-link-utils'; @@ -25,8 +25,13 @@ export class NavLink implements ComponentInterface { */ @Prop() routerDirection: RouterDirection = 'forward'; + /** + * The transition animation when navigating to another page. + */ + @Prop() routerAnimation?: AnimationBuilder; + private onClick = () => { - return navLink(this.el, this.routerDirection, this.component, this.componentProps); + return navLink(this.el, this.routerDirection, this.component, this.componentProps, this.routerAnimation); } render() { diff --git a/core/src/components/nav-link/readme.md b/core/src/components/nav-link/readme.md index 6f601c741f..c95e3a8f04 100644 --- a/core/src/components/nav-link/readme.md +++ b/core/src/components/nav-link/readme.md @@ -14,6 +14,7 @@ It is the element form of calling the `push()`, `pop()`, and `setRoot()` methods | ----------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ----------- | | `component` | `component` | Component to navigate to. Only used if the `routerDirection` is `"forward"` or `"root"`. | `Function \| HTMLElement \| ViewController \| null \| string \| undefined` | `undefined` | | `componentProps` | -- | Data you want to pass to the component as props. Only used if the `"routerDirection"` is `"forward"` or `"root"`. | `undefined \| { [key: string]: any; }` | `undefined` | +| `routerAnimation` | -- | The transition animation when navigating to another page. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` | | `routerDirection` | `router-direction` | The transition direction when navigating to another page. | `"back" \| "forward" \| "root"` | `'forward'` | diff --git a/core/src/components/nav/nav.tsx b/core/src/components/nav/nav.tsx index 982971ed06..ffa84f5f70 100644 --- a/core/src/components/nav/nav.tsx +++ b/core/src/components/nav/nav.tsx @@ -372,7 +372,8 @@ export class Nav implements NavOutlet { setRouteId( id: string, params: ComponentProps | undefined, - direction: RouterDirection + direction: RouterDirection, + animation?: AnimationBuilder ): Promise { const active = this.getActiveSync(); if (matches(active, id, params)) { @@ -410,15 +411,20 @@ export class Nav implements NavOutlet { if (viewController) { finish = this.popTo(viewController, { ...commonOpts, - direction: 'back' + direction: 'back', + animationBuilder: animation }); } else if (direction === 'forward') { - finish = this.push(id, params, commonOpts); + finish = this.push(id, params, { + ...commonOpts, + animationBuilder: animation + }); } else if (direction === 'back') { finish = this.setRoot(id, params, { ...commonOpts, direction: 'back', - animated: true + animated: true, + animationBuilder: animation }); } } @@ -623,6 +629,19 @@ export class Nav implements NavOutlet { const requiresTransition = (ti.enteringRequiresTransition || ti.leavingRequiresTransition) && enteringView !== leavingView; + if (requiresTransition && ti.opts && leavingView) { + const isBackDirection = ti.opts.direction === 'back'; + + /** + * If heading back, use the entering page's animation + * unless otherwise specified by the developer. + */ + if (isBackDirection) { + ti.opts.animationBuilder = ti.opts.animationBuilder || (enteringView && enteringView.animationBuilder); + } + + leavingView.animationBuilder = ti.opts.animationBuilder; + } const result = requiresTransition ? await this.transition(enteringView!, leavingView, ti) : { diff --git a/core/src/components/nav/view-controller.ts b/core/src/components/nav/view-controller.ts index ab62b1b455..a8942b04e8 100644 --- a/core/src/components/nav/view-controller.ts +++ b/core/src/components/nav/view-controller.ts @@ -1,4 +1,4 @@ -import { ComponentProps, FrameworkDelegate } from '../../interface'; +import { AnimationBuilder, ComponentProps, FrameworkDelegate } from '../../interface'; import { attachComponent } from '../../utils/framework-delegate'; import { assert } from '../../utils/helpers'; @@ -12,6 +12,7 @@ export class ViewController { nav?: any; element?: HTMLElement; delegate?: FrameworkDelegate; + animationBuilder?: AnimationBuilder; constructor( public component: any, diff --git a/core/src/components/router-link/readme.md b/core/src/components/router-link/readme.md index c65c3af851..6aca4e26fd 100644 --- a/core/src/components/router-link/readme.md +++ b/core/src/components/router-link/readme.md @@ -9,13 +9,14 @@ The router link component is used for navigating to a specified link. Similar to ## Properties -| Property | Attribute | Description | Type | Default | -| ----------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ----------- | -| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | -| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | -| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` | -| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | -| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ----------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- | +| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | +| `href` | `href` | Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered. | `string \| undefined` | `undefined` | +| `rel` | `rel` | Specifies the relationship of the target object to the link object. The value is a space-separated list of [link types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types). | `string \| undefined` | `undefined` | +| `routerAnimation` | -- | When using a router, it specifies the transition animation when navigating to another page using `href`. | `((baseEl: any, opts?: any) => Animation) \| undefined` | `undefined` | +| `routerDirection` | `router-direction` | When using a router, it specifies the transition direction when navigating to another page using `href`. | `"back" \| "forward" \| "root"` | `'forward'` | +| `target` | `target` | Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`. | `string \| undefined` | `undefined` | ## CSS Custom Properties diff --git a/core/src/components/router-link/router-link.tsx b/core/src/components/router-link/router-link.tsx index 66dd51a6df..994ffaa2c5 100644 --- a/core/src/components/router-link/router-link.tsx +++ b/core/src/components/router-link/router-link.tsx @@ -1,7 +1,7 @@ import { Component, ComponentInterface, Host, Prop, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; -import { Color, RouterDirection } from '../../interface'; +import { AnimationBuilder, Color, RouterDirection } from '../../interface'; import { createColorClasses, openURL } from '../../utils/theme'; @Component({ @@ -36,6 +36,12 @@ export class RouterLink implements ComponentInterface { */ @Prop() routerDirection: RouterDirection = 'forward'; + /** + * When using a router, it specifies the transition animation when navigating to + * another page using `href`. + */ + @Prop() routerAnimation: AnimationBuilder | undefined; + /** * Specifies where to display the linked URL. * Only applies when an `href` is provided. @@ -44,7 +50,7 @@ export class RouterLink implements ComponentInterface { @Prop() target: string | undefined; private onClick = (ev: Event) => { - openURL(this.href, ev, this.routerDirection); + openURL(this.href, ev, this.routerDirection, this.routerAnimation); } render() { diff --git a/core/src/components/router-outlet/route-outlet.tsx b/core/src/components/router-outlet/route-outlet.tsx index ac53234fe6..8635503cb1 100644 --- a/core/src/components/router-outlet/route-outlet.tsx +++ b/core/src/components/router-outlet/route-outlet.tsx @@ -131,10 +131,11 @@ export class RouterOutlet implements ComponentInterface, NavOutlet { /** @internal */ @Method() - async setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection): Promise { + async setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection, animation?: AnimationBuilder): Promise { const changed = await this.setRoot(id, params, { duration: direction === 'root' ? 0 : undefined, direction: direction === 'back' ? 'back' : 'forward', + animationBuilder: animation }); return { changed, diff --git a/core/src/components/router/readme.md b/core/src/components/router/readme.md index 616a2c1a5f..c79a5606fe 100644 --- a/core/src/components/router/readme.md +++ b/core/src/components/router/readme.md @@ -78,7 +78,7 @@ Type: `Promise` -### `push(url: string, direction?: RouterDirection) => Promise` +### `push(url: string, direction?: RouterDirection, animation?: AnimationBuilder | undefined) => Promise` Navigate to the specified URL. diff --git a/core/src/components/router/router.tsx b/core/src/components/router/router.tsx index 1a6d41f8d9..4b186bff6c 100644 --- a/core/src/components/router/router.tsx +++ b/core/src/components/router/router.tsx @@ -1,6 +1,6 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core'; -import { BackButtonEvent, RouteChain, RouterDirection, RouterEventDetail } from '../../interface'; +import { AnimationBuilder, BackButtonEvent, RouteChain, RouterDirection, RouterEventDetail } from '../../interface'; import { debounce } from '../../utils/helpers'; import { ROUTER_INTENT_BACK, ROUTER_INTENT_FORWARD, ROUTER_INTENT_NONE } from './utils/constants'; @@ -92,7 +92,7 @@ export class Router implements ComponentInterface { * @param direction The direction of the animation. Defaults to `"forward"`. */ @Method() - push(url: string, direction: RouterDirection = 'forward') { + push(url: string, direction: RouterDirection = 'forward', animation?: AnimationBuilder) { if (url.startsWith('.')) { url = (new URL(url, window.location.href)).pathname; } @@ -101,7 +101,7 @@ export class Router implements ComponentInterface { const path = parsePath(url); const queryString = url.split('?')[1]; this.setPath(path, direction, queryString); - return this.writeNavStateRoot(path, direction); + return this.writeNavStateRoot(path, direction, animation); } /** @@ -182,7 +182,7 @@ export class Router implements ComponentInterface { } } - private async writeNavStateRoot(path: string[] | null, direction: RouterDirection): Promise { + private async writeNavStateRoot(path: string[] | null, direction: RouterDirection, animation?: AnimationBuilder): Promise { if (!path) { console.error('[ion-router] URL is not part of the routing set'); return false; @@ -207,18 +207,19 @@ export class Router implements ComponentInterface { } // write DOM give - return this.safeWriteNavState(document.body, chain, direction, path, redirectFrom); + return this.safeWriteNavState(document.body, chain, direction, path, redirectFrom, 0, animation); } private async safeWriteNavState( node: HTMLElement | undefined, chain: RouteChain, direction: RouterDirection, path: string[], redirectFrom: string[] | null, - index = 0 + index = 0, + animation?: AnimationBuilder ): Promise { const unlock = await this.lock(); let changed = false; try { - changed = await this.writeNavState(node, chain, direction, path, redirectFrom, index); + changed = await this.writeNavState(node, chain, direction, path, redirectFrom, index, animation); } catch (e) { console.error(e); } @@ -240,7 +241,7 @@ export class Router implements ComponentInterface { private async writeNavState( node: HTMLElement | undefined, chain: RouteChain, direction: RouterDirection, path: string[], redirectFrom: string[] | null, - index = 0 + index = 0, animation?: AnimationBuilder ): Promise { if (this.busy) { console.warn('[ion-router] router is busy, transition was cancelled'); @@ -254,7 +255,7 @@ export class Router implements ComponentInterface { this.ionRouteWillChange.emit(routeEvent); } - const changed = await writeNavState(node, chain, direction, index); + const changed = await writeNavState(node, chain, direction, index, false, animation); this.busy = false; if (changed) { diff --git a/core/src/components/router/utils/dom.ts b/core/src/components/router/utils/dom.ts index 1330e4cfae..8587899ee0 100644 --- a/core/src/components/router/utils/dom.ts +++ b/core/src/components/router/utils/dom.ts @@ -1,4 +1,4 @@ -import { NavOutletElement, RouteChain, RouteID, RouterDirection } from '../../../interface'; +import { AnimationBuilder, NavOutletElement, RouteChain, RouteID, RouterDirection } from '../../../interface'; import { ROUTER_INTENT_NONE } from './constants'; @@ -7,7 +7,8 @@ export const writeNavState = async ( chain: RouteChain, direction: RouterDirection, index: number, - changed = false + changed = false, + animation?: AnimationBuilder ): Promise => { try { // find next navigation outlet in the DOM @@ -20,7 +21,7 @@ export const writeNavState = async ( await outlet.componentOnReady(); const route = chain[index]; - const result = await outlet.setRouteId(route.id, route.params, direction); + const result = await outlet.setRouteId(route.id, route.params, direction, animation); // if the outlet changed the page, reset navigation to neutral (no direction) // this means nested outlets will not animate @@ -30,7 +31,7 @@ export const writeNavState = async ( } // recursively set nested outlets - changed = await writeNavState(result.element, chain, direction, index + 1, changed); + changed = await writeNavState(result.element, chain, direction, index + 1, changed, animation); // once all nested outlets are visible let's make the parent visible too, // using markVisible prevents flickering diff --git a/core/src/components/router/utils/interface.ts b/core/src/components/router/utils/interface.ts index 6c5151ec3e..a9dfe81313 100644 --- a/core/src/components/router/utils/interface.ts +++ b/core/src/components/router/utils/interface.ts @@ -1,11 +1,11 @@ -import { ComponentProps } from '../../../interface'; +import { AnimationBuilder, ComponentProps } from '../../../interface'; export interface HTMLStencilElement extends HTMLElement { componentOnReady(): Promise; } export interface NavOutlet { - setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection): Promise; + setRouteId(id: string, params: ComponentProps | undefined, direction: RouterDirection, animation?: AnimationBuilder): Promise; getRouteId(): Promise; } diff --git a/core/src/utils/theme.ts b/core/src/utils/theme.ts index d222d92105..a85726c0a6 100644 --- a/core/src/utils/theme.ts +++ b/core/src/utils/theme.ts @@ -1,4 +1,4 @@ -import { Color, CssClassMap, RouterDirection } from '../interface'; +import { AnimationBuilder, Color, CssClassMap, RouterDirection } from '../interface'; export const hostContext = (selector: string, el: HTMLElement): boolean => { return el.closest(selector) !== null; @@ -33,14 +33,14 @@ export const getClassMap = (classes: string | string[] | undefined): CssClassMap const SCHEME = /^[a-z][a-z0-9+\-.]*:/; -export const openURL = async (url: string | undefined | null, ev: Event | undefined | null, direction: RouterDirection): Promise => { +export const openURL = async (url: string | undefined | null, ev: Event | undefined | null, direction: RouterDirection, animation?: AnimationBuilder): Promise => { if (url != null && url[0] !== '#' && !SCHEME.test(url)) { const router = document.querySelector('ion-router'); if (router) { if (ev != null) { ev.preventDefault(); } - return router.push(url, direction); + return router.push(url, direction, animation); } } return false;