From 6034418b33c32fdd682c470eaf61b9fcbe86c4bb Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Thu, 19 May 2022 12:19:34 -0400 Subject: [PATCH] fix(react): IonTabButton will call custom onClick handlers (#25313) Resolves #22511 --- .../src/components/navigation/IonTabBar.tsx | 14 +++++++++-- .../components/navigation/IonTabButton.tsx | 5 ++++ .../cypress/integration/tabs/tabs.spec.ts | 15 ++++++++++++ packages/react/test-app/package.json | 1 + packages/react/test-app/src/App.tsx | 2 ++ packages/react/test-app/src/pages/Main.tsx | 8 +++++-- packages/react/test-app/src/pages/Tabs.tsx | 23 +++++++++++++++++++ 7 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 packages/react/test-app/cypress/integration/tabs/tabs.spec.ts create mode 100644 packages/react/test-app/src/pages/Tabs.tsx diff --git a/packages/react/src/components/navigation/IonTabBar.tsx b/packages/react/src/components/navigation/IonTabBar.tsx index 5a906a42d7..1a88f8e4b7 100644 --- a/packages/react/src/components/navigation/IonTabBar.tsx +++ b/packages/react/src/components/navigation/IonTabBar.tsx @@ -178,12 +178,22 @@ class IonTabBarUnwrapped extends React.PureComponent + e: CustomEvent<{ href: string; selected: boolean; tab: string; routeOptions: unknown }>, + onClickFn?: (e: any) => void ) { const tappedTab = this.state.tabs[e.detail.tab]; const originalHref = tappedTab.originalHref; const currentHref = e.detail.href; const { activeTab: prevActiveTab } = this.state; + + if (onClickFn) { + /** + * If the user provides an onClick function, we call it + * with the original event. + */ + onClickFn(e); + } + // this.props.onSetCurrentTab(e.detail.tab, this.props.routeInfo); // Clicking the current tab will bring you back to the original href if (prevActiveTab === e.detail.tab) { @@ -232,7 +242,7 @@ class IonTabBarUnwrapped extends React.PureComponent this.onTabButtonClick(ev, child.props.onClick), }); } return null; diff --git a/packages/react/src/components/navigation/IonTabButton.tsx b/packages/react/src/components/navigation/IonTabButton.tsx index 98d6014e97..102e638338 100644 --- a/packages/react/src/components/navigation/IonTabButton.tsx +++ b/packages/react/src/components/navigation/IonTabButton.tsx @@ -34,6 +34,11 @@ export const IonTabButton = /*@__PURE__*/ (() => } render() { + /** + * onClick is excluded from the props, since it has a custom + * implementation within IonTabBar.tsx. Calling onClick within this + * component would result in duplicate handler calls. + */ const { onClick, ...rest } = this.props; return ( { + beforeEach(() => { + cy.visit('/tabs/tab1'); + }); + + it('should handle onClick handlers on IonTabButton', () => { + const stub = cy.stub(); + + cy.on('window:alert', stub); + cy.get('ion-tab-button[tab="tab1"]').click().then(() => { + expect(stub.getCall(0)).to.be.calledWith('Tab was clicked') + }); + + }); +}); diff --git a/packages/react/test-app/package.json b/packages/react/test-app/package.json index 6e5adde373..96865667dc 100644 --- a/packages/react/test-app/package.json +++ b/packages/react/test-app/package.json @@ -23,6 +23,7 @@ "eject": "react-scripts eject", "sync": "sh ./scripts/sync.sh", "cypress": "cypress run --headless --browser chrome", + "cypress.open": "cypress open", "e2e": "concurrently \"serve -s build -l 3000\" \"wait-on http-get://localhost:3000 && npm run cypress\" --kill-others --success first" }, "eslintConfig": { diff --git a/packages/react/test-app/src/App.tsx b/packages/react/test-app/src/App.tsx index 28d27fedfc..11cb79fba1 100644 --- a/packages/react/test-app/src/App.tsx +++ b/packages/react/test-app/src/App.tsx @@ -24,6 +24,7 @@ import './theme/variables.css'; import Main from './pages/Main'; import OverlayHooks from './pages/overlay-hooks/OverlayHooks'; import OverlayComponents from './pages/overlay-components/OverlayComponents'; +import Tabs from './pages/Tabs'; setupIonicReact(); @@ -34,6 +35,7 @@ const App: React.FC = () => ( + diff --git a/packages/react/test-app/src/pages/Main.tsx b/packages/react/test-app/src/pages/Main.tsx index 88e21502cb..944ac25419 100644 --- a/packages/react/test-app/src/pages/Main.tsx +++ b/packages/react/test-app/src/pages/Main.tsx @@ -4,11 +4,10 @@ import { IonHeader, IonLabel, IonPage, - IonTitle, IonToolbar, IonItem, - IonList + IonList, } from '@ionic/react'; interface MainProps {} @@ -32,6 +31,11 @@ const Main: React.FC = () => { Overlay Components + + + Tabs + + ); diff --git a/packages/react/test-app/src/pages/Tabs.tsx b/packages/react/test-app/src/pages/Tabs.tsx new file mode 100644 index 0000000000..08a2cfa8af --- /dev/null +++ b/packages/react/test-app/src/pages/Tabs.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react'; +import { Route, Redirect } from 'react-router'; + +interface TabsProps {} + +const Tabs: React.FC = () => { + return ( + + + + Tab 1} /> + + + window.alert('Tab was clicked')}> + Click Handler + + + + ); +}; + +export default Tabs;