diff --git a/packages/react-router/src/ReactRouter/IonRouter.tsx b/packages/react-router/src/ReactRouter/IonRouter.tsx index d3167ed4bc..994f70035a 100644 --- a/packages/react-router/src/ReactRouter/IonRouter.tsx +++ b/packages/react-router/src/ReactRouter/IonRouter.tsx @@ -41,7 +41,7 @@ class IonRouterInner extends React.PureComponent { routeMangerContextState: RouteManagerContextState = { canGoBack: () => this.locationHistory.canGoBack(), clearOutlet: this.viewStack.clear, - getViewItemForTransition: this.viewStack.getViewItemForTransition, + findViewItemByPathname: this.viewStack.findViewItemByPathname, getChildrenToRender: this.viewStack.getChildrenToRender, goBack: () => this.handleNavigateBack(), createViewItem: this.viewStack.createViewItem, @@ -154,7 +154,8 @@ class IonRouterInner extends React.PureComponent { lastPathname: leavingLocationInfo.pathname, pathname: location.pathname, search: location.search, - params: this.props.match.params + params: this.props.match.params, + prevRouteLastPathname: leavingLocationInfo.lastPathname }; if (isPushed) { routeInfo.tab = leavingLocationInfo.tab; @@ -170,6 +171,7 @@ class IonRouterInner extends React.PureComponent { // Make sure to set the lastPathname, etc.. to the current route so the page transitions out const currentRouteInfo = this.locationHistory.current(); routeInfo.lastPathname = currentRouteInfo?.pathname || routeInfo.lastPathname; + routeInfo.prevRouteLastPathname = currentRouteInfo?.lastPathname; routeInfo.pushedByRoute = currentRouteInfo?.pushedByRoute || routeInfo.pushedByRoute; routeInfo.routeDirection = currentRouteInfo?.routeDirection || routeInfo.routeDirection; routeInfo.routeAnimation = currentRouteInfo?.routeAnimation || routeInfo.routeAnimation; @@ -187,13 +189,13 @@ class IonRouterInner extends React.PureComponent { } handleNavigate(path: string, routeAction: RouteAction, routeDirection?: RouterDirection, routeAnimation?: AnimationBuilder, routeOptions?: any, tab?: string) { - this.incomingRouteParams = { + this.incomingRouteParams = Object.assign(this.incomingRouteParams || {}, { routeAction, routeDirection, routeOptions, routeAnimation, tab - }; + }); if (routeAction === 'push') { this.props.history.push(path); @@ -213,7 +215,7 @@ class IonRouterInner extends React.PureComponent { if (routeInfo.lastPathname === routeInfo.pushedByRoute) { this.props.history.goBack(); } else { - this.props.history.replace(prevInfo.pathname + (prevInfo.search || '')); + this.handleNavigate(prevInfo.pathname + (prevInfo.search || ''), 'pop', 'back'); } } else { this.handleNavigate(defaultHref as string, 'pop', 'back'); diff --git a/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx b/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx index daba037a22..a25582db5a 100644 --- a/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx +++ b/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx @@ -10,7 +10,7 @@ export class ReactRouterViewStack extends ViewStacks { this.findViewItemByRouteInfo = this.findViewItemByRouteInfo.bind(this); this.findLeavingViewItemByRouteInfo = this.findLeavingViewItemByRouteInfo.bind(this); this.getChildrenToRender = this.getChildrenToRender.bind(this); - this.getViewItemForTransition = this.getViewItemForTransition.bind(this); + this.findViewItemByPathname = this.findViewItemByPathname.bind(this); } createViewItem(outletId: string, reactElement: React.ReactElement, routeInfo: RouteInfo, page?: HTMLElement) { @@ -97,13 +97,13 @@ export class ReactRouterViewStack extends ViewStacks { return viewItem; } - findLeavingViewItemByRouteInfo(routeInfo: RouteInfo, outletId?: string) { - const { viewItem } = this.findViewItemByPath(routeInfo.lastPathname!, outletId, false, true); + findLeavingViewItemByRouteInfo(routeInfo: RouteInfo, outletId?: string, mustBeIonRoute = true) { + const { viewItem } = this.findViewItemByPath(routeInfo.lastPathname!, outletId, false, mustBeIonRoute); return viewItem; } - getViewItemForTransition(pathname: string) { - const { viewItem } = this.findViewItemByPath(pathname, undefined, true, true); + findViewItemByPathname(pathname: string, outletId?: string) { + const { viewItem } = this.findViewItemByPath(pathname, outletId); return viewItem; } diff --git a/packages/react-router/src/ReactRouter/StackManager.tsx b/packages/react-router/src/ReactRouter/StackManager.tsx index eafed6b679..c2be95751b 100644 --- a/packages/react-router/src/ReactRouter/StackManager.tsx +++ b/packages/react-router/src/ReactRouter/StackManager.tsx @@ -63,7 +63,11 @@ export class StackManager extends React.PureComponent this.handlePageTransition(routeInfo), 10); } else { let enteringViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id); - const leavingViewItem = this.context.findLeavingViewItemByRouteInfo(routeInfo, this.id); + let leavingViewItem = this.context.findLeavingViewItemByRouteInfo(routeInfo, this.id); + + if (!leavingViewItem && routeInfo.prevRouteLastPathname) { + leavingViewItem = this.context.findViewItemByPathname(routeInfo.prevRouteLastPathname, this.id); + } // Check if leavingViewItem should be unmounted if (leavingViewItem) { @@ -76,7 +80,6 @@ export class StackManager extends React.PureComponent { - if (leavingViewItem.ionPageElement) { - leavingViewItem.ionPageElement.classList.add('ion-page-hidden'); - leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true'); - } - }, 250); + // setTimeout(() => { + if (leavingViewItem.ionPageElement) { + leavingViewItem.ionPageElement.classList.add('ion-page-hidden'); + leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true'); + } + // }, 250); } this.forceUpdate(); diff --git a/packages/react-router/test-app/cypress/integration/routing.spec.js b/packages/react-router/test-app/cypress/integration/routing.spec.js index 065166fff5..9885e50a40 100644 --- a/packages/react-router/test-app/cypress/integration/routing.spec.js +++ b/packages/react-router/test-app/cypress/integration/routing.spec.js @@ -269,6 +269,28 @@ describe('Routing Tests', () => { cy.ionTabClick('Home') cy.ionPageVisible('home-details-page-2') }) + + it('/routing/tabs/home Menu > Favorites > Menu > Home with redirect, Home page should be visible, and Favorites should be hidden', () => { + cy.visit(`http://localhost:${port}/routing/tabs/home`) + cy.ionMenuClick() + cy.ionMenuNav('Favorites') + cy.ionPageVisible('favorites-page') + cy.ionMenuClick() + cy.ionMenuNav('Home with redirect') + cy.ionPageVisible('home-page') + cy.ionPageDoesNotExist('favorites-page') + }) + + it('/routing/tabs/home Menu > Favorites > Menu > Home with router, Home page should be visible, and Favorites should be hidden', () => { + cy.visit(`http://localhost:${port}/routing/tabs/home`) + cy.ionMenuClick() + cy.ionMenuNav('Favorites') + cy.ionPageVisible('favorites-page') + cy.ionMenuClick() + cy.ionMenuNav('Home with router') + cy.ionPageVisible('home-page') + cy.ionPageHidden('favorites-page') + }) /* Tests to add: Test that lifecycle events fire diff --git a/packages/react-router/test-app/cypress/support/commands.js b/packages/react-router/test-app/cypress/support/commands.js index 6028a0845e..16da9228c0 100644 --- a/packages/react-router/test-app/cypress/support/commands.js +++ b/packages/react-router/test-app/cypress/support/commands.js @@ -47,11 +47,16 @@ Cypress.Commands.add('ionPageVisible', (pageId) => { // cy.get(`div.ion-page[data-pageid=${pageId}]`).should('have.attr', 'style', 'z-index: 101;') }) +Cypress.Commands.add('ionPageInvisible', (pageId) => { + cy.get(`div.ion-page[data-pageid=${pageId}]`) + .should('have.class', 'ion-page-invisible') + .should('have.length', 1) +}) + Cypress.Commands.add('ionPageHidden', (pageId) => { cy.get(`div.ion-page[data-pageid=${pageId}]`) .should('have.class', 'ion-page-hidden') - .should('have.class', 'ion-page-invisible') .should('have.length', 1) }) diff --git a/packages/react-router/test-app/src/pages/replace-action/Replace.tsx b/packages/react-router/test-app/src/pages/replace-action/Replace.tsx index d02e024c04..ea78627ec1 100644 --- a/packages/react-router/test-app/src/pages/replace-action/Replace.tsx +++ b/packages/react-router/test-app/src/pages/replace-action/Replace.tsx @@ -10,7 +10,7 @@ const ReplaceAction: React.FC = () => { - + } /> ); @@ -61,7 +61,7 @@ const Page2: React.FC = () => { ); }; -const Edit: React.FC = () => { +const Page3: React.FC = () => { return ( diff --git a/packages/react-router/test-app/src/pages/routing/Menu.tsx b/packages/react-router/test-app/src/pages/routing/Menu.tsx index 9c1b4f262a..36765e9731 100644 --- a/packages/react-router/test-app/src/pages/routing/Menu.tsx +++ b/packages/react-router/test-app/src/pages/routing/Menu.tsx @@ -41,7 +41,19 @@ const appPages: AppPage[] = [ url: '/routing/otherpage', iosIcon: heartOutline, mdIcon: heartSharp - } + }, + { + title: 'Home with redirect', + url: '/routing/redirect', + iosIcon: heartOutline, + mdIcon: heartSharp + }, + { + title: 'Home with router', + url: '/routing/redirect-routing', + iosIcon: heartOutline, + mdIcon: heartSharp + }, ]; const Menu: React.FunctionComponent = () => { @@ -67,4 +79,4 @@ const Menu: React.FunctionComponent = () => { ); }; -export default Menu; \ No newline at end of file +export default Menu; diff --git a/packages/react-router/test-app/src/pages/routing/RedirectRouting.tsx b/packages/react-router/test-app/src/pages/routing/RedirectRouting.tsx new file mode 100644 index 0000000000..8f6590a63d --- /dev/null +++ b/packages/react-router/test-app/src/pages/routing/RedirectRouting.tsx @@ -0,0 +1,12 @@ +import React, { useEffect, useContext } from 'react'; +import { IonRouterContext } from '@ionic/react'; + +const RedirectRouting: React.FC= () => { + const ionRouterContext = useContext(IonRouterContext); + useEffect(() => { + ionRouterContext.push('/routing/tabs', 'none') + }, []); + return null; +}; + +export default RedirectRouting; diff --git a/packages/react-router/test-app/src/pages/routing/Routing.tsx b/packages/react-router/test-app/src/pages/routing/Routing.tsx index 28ce52728c..c34522c328 100644 --- a/packages/react-router/test-app/src/pages/routing/Routing.tsx +++ b/packages/react-router/test-app/src/pages/routing/Routing.tsx @@ -6,6 +6,7 @@ import Tabs from './Tabs'; import Favorites from './Favorites'; import OtherPage from './OtherPage'; import PropsTest from './PropsTest'; +import RedirectRouting from './RedirectRouting'; interface RoutingProps { } @@ -35,6 +36,8 @@ const Routing: React.FC = () => { }} /> */} + } /> + } />
Not found
} /> {/* } /> */} diff --git a/packages/react-router/tslint.json b/packages/react-router/tslint.json index 954ac87da9..c8b9c32620 100644 --- a/packages/react-router/tslint.json +++ b/packages/react-router/tslint.json @@ -33,6 +33,7 @@ "no-unused-expression": false, "no-constant-condition": false, "no-empty-interface": false, - "prefer-conditional-expression": false + "prefer-conditional-expression": false, + "prefer-object-spread": false } } diff --git a/packages/react/src/models/RouteInfo.ts b/packages/react/src/models/RouteInfo.ts index 61ae9e8558..91d8adaab4 100644 --- a/packages/react/src/models/RouteInfo.ts +++ b/packages/react/src/models/RouteInfo.ts @@ -7,6 +7,7 @@ import { RouterDirection } from './RouterDirection'; export interface RouteInfo { id: string; lastPathname?: string; + prevRouteLastPathname?: string; routeAction?: RouteAction; routeDirection?: RouterDirection; routeAnimation?: AnimationBuilder; diff --git a/packages/react/src/routing/RouteManagerContext.ts b/packages/react/src/routing/RouteManagerContext.ts index a9ed4c1a89..09be1ccddd 100644 --- a/packages/react/src/routing/RouteManagerContext.ts +++ b/packages/react/src/routing/RouteManagerContext.ts @@ -9,10 +9,10 @@ export interface RouteManagerContextState { canGoBack: () => boolean; clearOutlet: (outletId: string) => void; createViewItem: (outletId: string, reactElement: React.ReactElement, routeInfo: RouteInfo, page?: HTMLElement) => ViewItem; + findViewItemByPathname(pathname: string, outletId?: string): ViewItem | undefined; findLeavingViewItemByRouteInfo: (routeInfo: RouteInfo, outletId?: string) => ViewItem | undefined; findViewItemByRouteInfo: (routeInfo: RouteInfo, outletId?: string) => ViewItem | undefined; getChildrenToRender: (outletId: string, ionRouterOutlet: React.ReactElement, routeInfo: RouteInfo, reRender: () => void) => React.ReactNode[]; - getViewItemForTransition: (pathname: string) => ViewItem | undefined; goBack: () => void; unMountViewItem: (viewItem: ViewItem) => void; } @@ -22,10 +22,10 @@ export const RouteManagerContext = /*@__PURE__*/React.createContext undefined as any, clearOutlet: () => undefined, createViewItem: () => undefined as any, + findViewItemByPathname: () => undefined, findLeavingViewItemByRouteInfo: () => undefined, findViewItemByRouteInfo: () => undefined, getChildrenToRender: () => undefined as any, - getViewItemForTransition: () => undefined, goBack: () => undefined, unMountViewItem: () => undefined, }); diff --git a/packages/react/src/routing/ViewStacks.ts b/packages/react/src/routing/ViewStacks.ts index 318f65234c..b0893e1235 100644 --- a/packages/react/src/routing/ViewStacks.ts +++ b/packages/react/src/routing/ViewStacks.ts @@ -59,9 +59,8 @@ export abstract class ViewStacks { } abstract createViewItem(outletId: string, reactElement: React.ReactElement, routeInfo: RouteInfo, page?: HTMLElement): ViewItem; - // abstract findViewItemByPathname(pathname: string, outletId?: string): ViewItem | undefined; + abstract findViewItemByPathname(pathname: string, outletId?: string): ViewItem | undefined; abstract findViewItemByRouteInfo(routeInfo: RouteInfo, outletId?: string): ViewItem | undefined; abstract findLeavingViewItemByRouteInfo(routeInfo: RouteInfo, outletId?: string): ViewItem | undefined; abstract getChildrenToRender(outletId: string, ionRouterOutlet: React.ReactElement, routeInfo: RouteInfo, reRender: () => void, setInTransition: () => void): React.ReactNode[]; - abstract getViewItemForTransition(pathname: string): ViewItem | undefined; }