-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(react): IonNav works with react (#25565)
Resolves #24002 Co-authored-by: Liam DeBeasi <[email protected]>
- Loading branch information
1 parent
ffb0311
commit 420f9bb
Showing
9 changed files
with
197 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import type { FrameworkDelegate, JSX } from '@ionic/core/components'; | ||
import { defineCustomElement } from '@ionic/core/components/ion-nav.js'; | ||
import React, { useState } from 'react'; | ||
|
||
import { ReactDelegate } from '../../framework-delegate'; | ||
import { createReactComponent } from '../react-component-lib'; | ||
|
||
const IonNavInner = createReactComponent< | ||
JSX.IonNav & { delegate: FrameworkDelegate }, | ||
HTMLIonNavElement | ||
>('ion-nav', undefined, undefined, defineCustomElement); | ||
|
||
export const IonNav: React.FC<JSX.IonNav> = ({ children, ...restOfProps }) => { | ||
const [views, setViews] = useState<React.ReactPortal[]>([]); | ||
|
||
/** | ||
* Allows us to create React components that are rendered within | ||
* the context of the IonNav component. | ||
*/ | ||
const addView = (view: React.ReactPortal) => setViews([...views, view]); | ||
const removeView = (view: React.ReactPortal) => setViews(views.filter((v) => v !== view)); | ||
|
||
const delegate = ReactDelegate(addView, removeView); | ||
|
||
return ( | ||
<IonNavInner delegate={delegate} {...restOfProps}> | ||
{views} | ||
</IonNavInner> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { FrameworkDelegate } from '@ionic/core/components'; | ||
import { createPortal } from 'react-dom'; | ||
|
||
export const ReactDelegate = ( | ||
addView: (view: React.ReactPortal) => void, | ||
removeView: (view: React.ReactPortal) => void | ||
): FrameworkDelegate => { | ||
let Component: React.ReactPortal; | ||
|
||
const attachViewToDom = async ( | ||
parentElement: HTMLElement, | ||
component: () => JSX.Element, | ||
propsOrDataObj?: any, | ||
cssClasses?: string[] | ||
): Promise<any> => { | ||
const div = document.createElement('div'); | ||
cssClasses && div.classList.add(...cssClasses); | ||
parentElement.appendChild(div); | ||
|
||
Component = createPortal(component(), div); | ||
|
||
Component.props = propsOrDataObj; | ||
|
||
addView(Component); | ||
|
||
return Promise.resolve(div); | ||
}; | ||
|
||
const removeViewFromDom = (): Promise<void> => { | ||
Component && removeView(Component); | ||
return Promise.resolve(); | ||
}; | ||
|
||
return { | ||
attachViewToDom, | ||
removeViewFromDom, | ||
}; | ||
}; |
28 changes: 28 additions & 0 deletions
28
packages/react/test-app/cypress/integration/navigation/IonNav.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
describe('IonNav', () => { | ||
beforeEach(() => { | ||
cy.visit('/navigation'); | ||
}); | ||
|
||
it('should render the root page', () => { | ||
cy.get('ion-nav').contains('Page one content'); | ||
}); | ||
|
||
it('should push a page', () => { | ||
cy.get('ion-button').contains('Go to Page Two').click(); | ||
cy.get('#pageTwoContent').should('be.visible'); | ||
cy.get('ion-nav').contains('Page two content'); | ||
}); | ||
|
||
it('should pop a page', () => { | ||
cy.get('ion-button').contains('Go to Page Two').click(); | ||
|
||
cy.get('#pageTwoContent').should('be.visible'); | ||
cy.get('ion-nav').contains('Page two content'); | ||
|
||
cy.get('.ion-page.can-go-back ion-back-button').click(); | ||
|
||
cy.get('#pageOneContent').should('be.visible'); | ||
cy.get('ion-nav').contains('Page one content'); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
packages/react/test-app/src/pages/navigation/NavComponent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { | ||
IonButton, | ||
IonContent, | ||
IonHeader, | ||
IonLabel, | ||
IonNav, | ||
IonNavLink, | ||
IonTitle, | ||
IonToolbar, | ||
IonButtons, | ||
IonBackButton, | ||
IonPage, | ||
} from '@ionic/react'; | ||
import React from 'react'; | ||
|
||
const NavComponent: React.FC = () => { | ||
return ( | ||
<IonPage> | ||
<IonNav | ||
root={() => { | ||
return ( | ||
<> | ||
<IonHeader> | ||
<IonToolbar> | ||
<IonTitle>Page One</IonTitle> | ||
<IonButtons> | ||
<IonBackButton /> | ||
</IonButtons> | ||
</IonToolbar> | ||
</IonHeader> | ||
<IonContent id="pageOneContent"> | ||
<IonLabel>Page one content</IonLabel> | ||
<IonNavLink | ||
routerDirection="forward" | ||
component={() => { | ||
return ( | ||
<> | ||
<IonHeader> | ||
<IonToolbar> | ||
<IonTitle>Page Two</IonTitle> | ||
<IonButtons> | ||
<IonBackButton /> | ||
</IonButtons> | ||
</IonToolbar> | ||
</IonHeader> | ||
<IonContent id="pageTwoContent"> | ||
<IonLabel>Page two content</IonLabel> | ||
<IonNavLink | ||
routerDirection="forward" | ||
component={() => ( | ||
<> | ||
<IonHeader> | ||
<IonToolbar> | ||
<IonTitle>Page Three</IonTitle> | ||
<IonButtons> | ||
<IonBackButton /> | ||
</IonButtons> | ||
</IonToolbar> | ||
</IonHeader> | ||
<IonContent> | ||
<IonLabel>Page three content</IonLabel> | ||
</IonContent> | ||
</> | ||
)} | ||
> | ||
<IonButton>Go to Page Three</IonButton> | ||
</IonNavLink> | ||
</IonContent> | ||
</> | ||
); | ||
}} | ||
> | ||
<IonButton>Go to Page Two</IonButton> | ||
</IonNavLink> | ||
</IonContent> | ||
</> | ||
); | ||
}} | ||
></IonNav> | ||
</IonPage> | ||
); | ||
}; | ||
|
||
export default NavComponent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters