mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 09:34:19 +08:00
fix(react): fixes swipe to go back regression (#21791)
This commit is contained in:
@ -39,9 +39,11 @@ class IonRouterInner extends React.PureComponent<IonRouteProps, IonRouteState> {
|
|||||||
locationHistory = new LocationHistory();
|
locationHistory = new LocationHistory();
|
||||||
viewStack = new ReactRouterViewStack();
|
viewStack = new ReactRouterViewStack();
|
||||||
routeMangerContextState: RouteManagerContextState = {
|
routeMangerContextState: RouteManagerContextState = {
|
||||||
|
canGoBack: () => this.locationHistory.canGoBack(),
|
||||||
clearOutlet: this.viewStack.clear,
|
clearOutlet: this.viewStack.clear,
|
||||||
getViewItemForTransition: this.viewStack.getViewItemForTransition,
|
getViewItemForTransition: this.viewStack.getViewItemForTransition,
|
||||||
getChildrenToRender: this.viewStack.getChildrenToRender,
|
getChildrenToRender: this.viewStack.getChildrenToRender,
|
||||||
|
goBack: () => this.handleNavigateBack(),
|
||||||
createViewItem: this.viewStack.createViewItem,
|
createViewItem: this.viewStack.createViewItem,
|
||||||
findViewItemByRouteInfo: this.viewStack.findViewItemByRouteInfo,
|
findViewItemByRouteInfo: this.viewStack.findViewItemByRouteInfo,
|
||||||
findLeavingViewItemByRouteInfo: this.viewStack.findLeavingViewItemByRouteInfo,
|
findLeavingViewItemByRouteInfo: this.viewStack.findLeavingViewItemByRouteInfo,
|
||||||
|
@ -4,7 +4,8 @@ import {
|
|||||||
StackContext,
|
StackContext,
|
||||||
StackContextState,
|
StackContextState,
|
||||||
ViewItem,
|
ViewItem,
|
||||||
generateId
|
generateId,
|
||||||
|
getConfig
|
||||||
} from '@ionic/react';
|
} from '@ionic/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { matchPath } from 'react-router-dom';
|
import { matchPath } from 'react-router-dom';
|
||||||
@ -38,6 +39,7 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (this.routerOutletElement) {
|
if (this.routerOutletElement) {
|
||||||
|
this.setupRouterOutlet(this.routerOutletElement);
|
||||||
// console.log(`SM Mount - ${this.routerOutletElement.id} (${this.id})`);
|
// console.log(`SM Mount - ${this.routerOutletElement.id} (${this.id})`);
|
||||||
this.handlePageTransition(this.props.routeInfo);
|
this.handlePageTransition(this.props.routeInfo);
|
||||||
}
|
}
|
||||||
@ -111,6 +113,28 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
|||||||
this.handlePageTransition(routeInfo);
|
this.handlePageTransition(routeInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setupRouterOutlet(routerOutlet: HTMLIonRouterOutletElement) {
|
||||||
|
|
||||||
|
const canStart = () => {
|
||||||
|
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) {
|
async transitionPage(routeInfo: RouteInfo, enteringViewItem: ViewItem, leavingViewItem?: ViewItem) {
|
||||||
|
|
||||||
const routerOutlet = this.routerOutletElement!;
|
const routerOutlet = this.routerOutletElement!;
|
||||||
|
@ -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
|
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', () => {
|
it('/dynamic-routes, when adding a dynamic route, we should be able to navigate to it', () => {
|
||||||
cy.visit(`http://localhost:${port}/dynamic-routes`)
|
cy.visit(`http://localhost:${port}/dynamic-routes`)
|
||||||
cy.ionPageVisible('dynamic-routes-home')
|
cy.ionPageVisible('dynamic-routes-home')
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const port = 3000;
|
const port = 3000;
|
||||||
|
|
||||||
describe('Multiple Tabs', () => {
|
describe('IonRouterOutlet Ref', () => {
|
||||||
/*
|
/*
|
||||||
This spec tests that setting a ref on an IonRouterOutlet works
|
This spec tests that setting a ref on an IonRouterOutlet works
|
||||||
*/
|
*/
|
||||||
|
18
packages/react-router/test-app/cypress/integration/swipe-to-go-back.js
vendored
Normal file
18
packages/react-router/test-app/cypress/integration/swipe-to-go-back.js
vendored
Normal file
@ -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')
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
@ -66,6 +66,14 @@ Cypress.Commands.add('ionNav', (element, contains) => {
|
|||||||
cy.wait(250);
|
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) => {
|
Cypress.Commands.add('ionMenuNav', (contains) => {
|
||||||
// cy.get('ion-menu.show-menu').should('exist');
|
// cy.get('ion-menu.show-menu').should('exist');
|
||||||
// cy.wait(1000)
|
// cy.wait(1000)
|
||||||
|
@ -34,6 +34,7 @@ import NestedOutlet2 from './pages/nested-outlet/NestedOutlet2';
|
|||||||
import ReplaceAction from './pages/replace-action/Replace';
|
import ReplaceAction from './pages/replace-action/Replace';
|
||||||
import TabsContext from './pages/tab-context/TabContext';
|
import TabsContext from './pages/tab-context/TabContext';
|
||||||
import { OutletRef } from './pages/outlet-ref/OutletRef';
|
import { OutletRef } from './pages/outlet-ref/OutletRef';
|
||||||
|
import { SwipeToGoBack } from './pages/swipe-to-go-back/SwipToGoBack';
|
||||||
debugger;
|
debugger;
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
@ -49,6 +50,7 @@ const App: React.FC = () => {
|
|||||||
<Route path="/replace-action" component={ReplaceAction} />
|
<Route path="/replace-action" component={ReplaceAction} />
|
||||||
<Route path="/tab-context" component={TabsContext} />
|
<Route path="/tab-context" component={TabsContext} />
|
||||||
<Route path="/outlet-ref" component={OutletRef} />
|
<Route path="/outlet-ref" component={OutletRef} />
|
||||||
|
<Route path="/swipe-to-go-back" component={SwipeToGoBack} />
|
||||||
</IonReactRouter>
|
</IonReactRouter>
|
||||||
</IonApp>
|
</IonApp>
|
||||||
);
|
);
|
||||||
|
@ -41,6 +41,9 @@ const Main: React.FC<MainProps> = () => {
|
|||||||
<IonItem routerLink="/outlet-ref">
|
<IonItem routerLink="/outlet-ref">
|
||||||
<IonLabel>Outlet Ref</IonLabel>
|
<IonLabel>Outlet Ref</IonLabel>
|
||||||
</IonItem>
|
</IonItem>
|
||||||
|
<IonItem routerLink="/swipe-to-go-back">
|
||||||
|
<IonLabel>Swipe to go back</IonLabel>
|
||||||
|
</IonItem>
|
||||||
</IonList>
|
</IonList>
|
||||||
</IonContent>
|
</IonContent>
|
||||||
</IonPage>
|
</IonPage>
|
||||||
|
@ -22,8 +22,6 @@ export const OutletRef: React.FC<OutletRefProps> = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const Main: React.FC<{ outletId?: string; }> = ({ outletId }) => {
|
const Main: React.FC<{ outletId?: string; }> = ({ outletId }) => {
|
||||||
return (
|
return (
|
||||||
<IonPage data-pageid="main">
|
<IonPage data-pageid="main">
|
||||||
@ -38,5 +36,3 @@ const Main: React.FC<{ outletId?: string; }> = ({ outletId }) => {
|
|||||||
</IonPage>
|
</IonPage>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Main;
|
|
||||||
|
@ -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<SwipeToGoBackProps> = () => {
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonRouterOutlet id="swipe-to-go-back">
|
||||||
|
<Route path="/swipe-to-go-back" component={Main} exact />
|
||||||
|
<Route path="/swipe-to-go-back/details" component={Details} />
|
||||||
|
</IonRouterOutlet>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Main: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<IonPage data-pageid="main">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle>Main</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
<IonItem routerLink="/swipe-to-go-back/details">
|
||||||
|
Details
|
||||||
|
</IonItem>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Details: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<IonPage data-pageid="details">
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonButtons>
|
||||||
|
<IonBackButton></IonBackButton>
|
||||||
|
</IonButtons>
|
||||||
|
<IonTitle>Details</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
<div>Details</div>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -6,24 +6,26 @@ import { ViewItem } from './ViewItem';
|
|||||||
|
|
||||||
export interface RouteManagerContextState {
|
export interface RouteManagerContextState {
|
||||||
addViewItem: (viewItem: ViewItem) => void;
|
addViewItem: (viewItem: ViewItem) => void;
|
||||||
|
canGoBack: () => boolean;
|
||||||
clearOutlet: (outletId: string) => void;
|
clearOutlet: (outletId: string) => void;
|
||||||
createViewItem: (outletId: string, reactElement: React.ReactElement, routeInfo: RouteInfo, page?: HTMLElement) => ViewItem;
|
createViewItem: (outletId: string, reactElement: React.ReactElement, routeInfo: RouteInfo, page?: HTMLElement) => ViewItem;
|
||||||
findLeavingViewItemByRouteInfo: (routeInfo: RouteInfo, outletId?: string) => ViewItem | undefined;
|
findLeavingViewItemByRouteInfo: (routeInfo: RouteInfo, outletId?: string) => ViewItem | undefined;
|
||||||
// findViewItemByPathname: (pathname: string, outletId?: string) => ViewItem | undefined;
|
|
||||||
findViewItemByRouteInfo: (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[];
|
getChildrenToRender: (outletId: string, ionRouterOutlet: React.ReactElement, routeInfo: RouteInfo, reRender: () => void) => React.ReactNode[];
|
||||||
getViewItemForTransition: (pathname: string) => ViewItem | undefined;
|
getViewItemForTransition: (pathname: string) => ViewItem | undefined;
|
||||||
|
goBack: () => void;
|
||||||
unMountViewItem: (viewItem: ViewItem) => void;
|
unMountViewItem: (viewItem: ViewItem) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RouteManagerContext = /*@__PURE__*/React.createContext<RouteManagerContextState>({
|
export const RouteManagerContext = /*@__PURE__*/React.createContext<RouteManagerContextState>({
|
||||||
addViewItem: () => undefined,
|
addViewItem: () => undefined,
|
||||||
|
canGoBack: () => undefined as any,
|
||||||
clearOutlet: () => undefined,
|
clearOutlet: () => undefined,
|
||||||
createViewItem: () => undefined as any,
|
createViewItem: () => undefined as any,
|
||||||
findLeavingViewItemByRouteInfo: () => undefined,
|
findLeavingViewItemByRouteInfo: () => undefined,
|
||||||
// findViewItemByPathname: () => undefined,
|
|
||||||
findViewItemByRouteInfo: () => undefined,
|
findViewItemByRouteInfo: () => undefined,
|
||||||
getChildrenToRender: () => undefined as any,
|
getChildrenToRender: () => undefined as any,
|
||||||
getViewItemForTransition: () => undefined,
|
getViewItemForTransition: () => undefined,
|
||||||
|
goBack: () => undefined,
|
||||||
unMountViewItem: () => undefined,
|
unMountViewItem: () => undefined,
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user