diff --git a/packages/react-router/src/ReactRouter/IonRouter.tsx b/packages/react-router/src/ReactRouter/IonRouter.tsx index 434b1b10a5..0083312ab1 100644 --- a/packages/react-router/src/ReactRouter/IonRouter.tsx +++ b/packages/react-router/src/ReactRouter/IonRouter.tsx @@ -39,9 +39,11 @@ class IonRouterInner extends React.PureComponent { locationHistory = new LocationHistory(); viewStack = new ReactRouterViewStack(); routeMangerContextState: RouteManagerContextState = { + canGoBack: () => this.locationHistory.canGoBack(), clearOutlet: this.viewStack.clear, getViewItemForTransition: this.viewStack.getViewItemForTransition, getChildrenToRender: this.viewStack.getChildrenToRender, + goBack: () => this.handleNavigateBack(), createViewItem: this.viewStack.createViewItem, findViewItemByRouteInfo: this.viewStack.findViewItemByRouteInfo, findLeavingViewItemByRouteInfo: this.viewStack.findLeavingViewItemByRouteInfo, diff --git a/packages/react-router/src/ReactRouter/StackManager.tsx b/packages/react-router/src/ReactRouter/StackManager.tsx index f281f47255..a636bc7ceb 100644 --- a/packages/react-router/src/ReactRouter/StackManager.tsx +++ b/packages/react-router/src/ReactRouter/StackManager.tsx @@ -4,7 +4,8 @@ import { StackContext, StackContextState, ViewItem, - generateId + generateId, + getConfig } from '@ionic/react'; import React from 'react'; import { matchPath } from 'react-router-dom'; @@ -38,6 +39,7 @@ export class StackManager extends React.PureComponent { + const config = getConfig(); + const swipeEnabled = config && config.get('swipeBackEnabled', routerOutlet.mode === 'ios'); + if (swipeEnabled) { + return this.context.canGoBack(); + } else { + return false; + } + }; + + const onStart = () => { + this.context.goBack(); + }; + routerOutlet.swipeHandler = { + canStart, + onStart, + onEnd: _shouldContinue => true + }; + } + async transitionPage(routeInfo: RouteInfo, enteringViewItem: ViewItem, leavingViewItem?: ViewItem) { const routerOutlet = this.routerOutletElement!; diff --git a/packages/react-router/test-app/cypress/integration/dynamic-routes.spec.js b/packages/react-router/test-app/cypress/integration/dynamic-routes.spec.js index 80acec8cb8..5c2a83051d 100644 --- a/packages/react-router/test-app/cypress/integration/dynamic-routes.spec.js +++ b/packages/react-router/test-app/cypress/integration/dynamic-routes.spec.js @@ -4,7 +4,7 @@ This spec covers that routes can be added and navigated to at runtime. Fixes bug reported in https://github.com/ionic-team/ionic/issues/21329 */ -describe('Dynamic Route Tests', () => { +describe('Dynamic Routes', () => { it('/dynamic-routes, when adding a dynamic route, we should be able to navigate to it', () => { cy.visit(`http://localhost:${port}/dynamic-routes`) cy.ionPageVisible('dynamic-routes-home') @@ -19,4 +19,4 @@ describe('Dynamic Route Tests', () => { cy.get('a').contains('Take me to the newRoute').click(); cy.ionPageVisible('dynamic-routes-failed') }) -}) \ No newline at end of file +}) diff --git a/packages/react-router/test-app/cypress/integration/outlet-ref.spec.js b/packages/react-router/test-app/cypress/integration/outlet-ref.spec.js index 641b3fa48c..79e88c54d4 100644 --- a/packages/react-router/test-app/cypress/integration/outlet-ref.spec.js +++ b/packages/react-router/test-app/cypress/integration/outlet-ref.spec.js @@ -1,6 +1,6 @@ const port = 3000; -describe('Multiple Tabs', () => { +describe('IonRouterOutlet Ref', () => { /* This spec tests that setting a ref on an IonRouterOutlet works */ diff --git a/packages/react-router/test-app/cypress/integration/swipe-to-go-back.js b/packages/react-router/test-app/cypress/integration/swipe-to-go-back.js new file mode 100644 index 0000000000..c0007100bc --- /dev/null +++ b/packages/react-router/test-app/cypress/integration/swipe-to-go-back.js @@ -0,0 +1,18 @@ +const port = 3000; + +describe('Swipe To Go Back', () => { + /* + This spec tests that swipe to go back works + */ + + it('/swipe-to-go-back, ', () => { + cy.visit(`http://localhost:${port}/swipe-to-go-back`) + cy.ionPageVisible('main') + cy.ionNav('ion-item', 'Details') + cy.ionPageVisible('details') + cy.wait(350); + cy.ionSwipeRight(); + cy.ionPageVisible('main') + }) + +}) diff --git a/packages/react-router/test-app/cypress/support/commands.js b/packages/react-router/test-app/cypress/support/commands.js index 6f08b7965a..6028a0845e 100644 --- a/packages/react-router/test-app/cypress/support/commands.js +++ b/packages/react-router/test-app/cypress/support/commands.js @@ -66,6 +66,14 @@ Cypress.Commands.add('ionNav', (element, contains) => { cy.wait(250); }) +Cypress.Commands.add('ionSwipeRight', (element, contains) => { + cy.get('ion-router-outlet') + .trigger('mousedown', { position: "left" }) + .trigger('mousemove', { clientX: 100, clientY: 275 }) + .trigger('mouseup', { force: true }) + cy.wait(150); +}) + Cypress.Commands.add('ionMenuNav', (contains) => { // cy.get('ion-menu.show-menu').should('exist'); // cy.wait(1000) diff --git a/packages/react-router/test-app/src/App.tsx b/packages/react-router/test-app/src/App.tsx index f1dc4763c6..fde63b9829 100644 --- a/packages/react-router/test-app/src/App.tsx +++ b/packages/react-router/test-app/src/App.tsx @@ -34,6 +34,7 @@ import NestedOutlet2 from './pages/nested-outlet/NestedOutlet2'; import ReplaceAction from './pages/replace-action/Replace'; import TabsContext from './pages/tab-context/TabContext'; import { OutletRef } from './pages/outlet-ref/OutletRef'; +import { SwipeToGoBack } from './pages/swipe-to-go-back/SwipToGoBack'; debugger; const App: React.FC = () => { return ( @@ -49,6 +50,7 @@ const App: React.FC = () => { + ); diff --git a/packages/react-router/test-app/src/pages/Main.tsx b/packages/react-router/test-app/src/pages/Main.tsx index 9a3ca9f7cd..ed88998d6b 100644 --- a/packages/react-router/test-app/src/pages/Main.tsx +++ b/packages/react-router/test-app/src/pages/Main.tsx @@ -41,6 +41,9 @@ const Main: React.FC = () => { Outlet Ref + + Swipe to go back + diff --git a/packages/react-router/test-app/src/pages/outlet-ref/OutletRef.tsx b/packages/react-router/test-app/src/pages/outlet-ref/OutletRef.tsx index 7941bac9d5..5904c80c5e 100644 --- a/packages/react-router/test-app/src/pages/outlet-ref/OutletRef.tsx +++ b/packages/react-router/test-app/src/pages/outlet-ref/OutletRef.tsx @@ -22,8 +22,6 @@ export const OutletRef: React.FC = () => { ); }; - - const Main: React.FC<{ outletId?: string; }> = ({ outletId }) => { return ( @@ -38,5 +36,3 @@ const Main: React.FC<{ outletId?: string; }> = ({ outletId }) => { ); }; - -export default Main; diff --git a/packages/react-router/test-app/src/pages/swipe-to-go-back/SwipToGoBack.tsx b/packages/react-router/test-app/src/pages/swipe-to-go-back/SwipToGoBack.tsx new file mode 100644 index 0000000000..283d597d04 --- /dev/null +++ b/packages/react-router/test-app/src/pages/swipe-to-go-back/SwipToGoBack.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { IonRouterOutlet, IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonItem, IonButtons, IonBackButton } from '@ionic/react'; +import { Route } from 'react-router'; + +interface SwipeToGoBackProps { +} + +export const SwipeToGoBack: React.FC = () => { + + + return ( + + + + + ); +}; + +const Main: React.FC = () => { + return ( + + + + Main + + + + + Details + + + + ); +}; + +const Details: React.FC = () => { + return ( + + + + + + + Details + + + +
Details
+
+
+ ); +}; + diff --git a/packages/react/src/routing/RouteManagerContext.ts b/packages/react/src/routing/RouteManagerContext.ts index d53428abc5..a9ed4c1a89 100644 --- a/packages/react/src/routing/RouteManagerContext.ts +++ b/packages/react/src/routing/RouteManagerContext.ts @@ -6,24 +6,26 @@ import { ViewItem } from './ViewItem'; export interface RouteManagerContextState { addViewItem: (viewItem: ViewItem) => void; + canGoBack: () => boolean; clearOutlet: (outletId: string) => void; createViewItem: (outletId: string, reactElement: React.ReactElement, routeInfo: RouteInfo, page?: HTMLElement) => ViewItem; findLeavingViewItemByRouteInfo: (routeInfo: RouteInfo, outletId?: string) => ViewItem | undefined; - // findViewItemByPathname: (pathname: string, 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; } export const RouteManagerContext = /*@__PURE__*/React.createContext({ addViewItem: () => undefined, + canGoBack: () => undefined as any, clearOutlet: () => undefined, createViewItem: () => undefined as any, findLeavingViewItemByRouteInfo: () => undefined, - // findViewItemByPathname: () => undefined, findViewItemByRouteInfo: () => undefined, getChildrenToRender: () => undefined as any, getViewItemForTransition: () => undefined, + goBack: () => undefined, unMountViewItem: () => undefined, });