@@ -8,7 +8,6 @@ import { IonRouterOutlet } from '../IonRouterOutlet';
88import { IonTabsInner } from '../inner-proxies' ;
99import { IonTab } from '../proxies' ;
1010
11- import { IonTabBar } from './IonTabBar' ;
1211import type { IonTabsContextState } from './IonTabsContext' ;
1312import { IonTabsContext } from './IonTabsContext' ;
1413
@@ -43,35 +42,30 @@ interface Props extends LocalJSX.IonTabs {
4342 children : ChildFunction | React . ReactNode ;
4443}
4544
46- const hostStyles : React . CSSProperties = {
47- display : 'flex' ,
48- position : 'absolute' ,
49- top : '0' ,
50- left : '0' ,
51- right : '0' ,
52- bottom : '0' ,
53- flexDirection : 'column' ,
54- width : '100%' ,
55- height : '100%' ,
56- contain : 'layout size style' ,
57- } ;
58-
59- const tabsInner : React . CSSProperties = {
60- position : 'relative' ,
61- flex : 1 ,
62- contain : 'layout size style' ,
63- } ;
64-
6545export const IonTabs = /*@__PURE__ */ ( ( ) =>
6646 class extends React . Component < Props > {
6747 context ! : React . ContextType < typeof NavContext > ;
48+ /**
49+ * `routerOutletRef` allows users to add a `ref` to `IonRouterOutlet`.
50+ * Without this, `ref.current` will be `undefined` in the user's app,
51+ * breaking their ability to access the `IonRouterOutlet` instance.
52+ * Do not remove this ref.
53+ */
6854 routerOutletRef : React . Ref < HTMLIonRouterOutletElement > = React . createRef ( ) ;
6955 selectTabHandler ?: ( tag : string ) => boolean ;
7056 tabBarRef = React . createRef < any > ( ) ;
7157
7258 ionTabContextState : IonTabsContextState = {
7359 activeTab : undefined ,
7460 selectTab : ( ) => false ,
61+ hasRouterOutlet : false ,
62+ /**
63+ * Tab bar can be used as a standalone component,
64+ * so the props can not be passed directly to the
65+ * tab bar component. Instead, props will be
66+ * passed through the context.
67+ */
68+ tabBarProps : { ref : this . tabBarRef } ,
7569 } ;
7670
7771 constructor ( props : Props ) {
@@ -90,9 +84,32 @@ export const IonTabs = /*@__PURE__*/ (() =>
9084 }
9185 }
9286
87+ renderTabsInner ( children : React . ReactNode , outlet : React . ReactElement < { } > | undefined ) {
88+ return (
89+ < IonTabsInner { ...this . props } >
90+ { React . Children . map ( children , ( child : React . ReactNode ) => {
91+ if ( React . isValidElement ( child ) ) {
92+ const isRouterOutlet =
93+ child . type === IonRouterOutlet ||
94+ ( child . type as any ) . isRouterOutlet ||
95+ ( child . type === Fragment && child . props . children [ 0 ] . type === IonRouterOutlet ) ;
96+
97+ if ( isRouterOutlet ) {
98+ /**
99+ * The modified outlet needs to be returned to include
100+ * the ref.
101+ */
102+ return outlet ;
103+ }
104+ }
105+ return child ;
106+ } ) }
107+ </ IonTabsInner >
108+ ) ;
109+ }
110+
93111 render ( ) {
94112 let outlet : React . ReactElement < { } > | undefined ;
95- let tabBar : React . ReactElement | undefined ;
96113 // Check if IonTabs has any IonTab children
97114 let hasTab = false ;
98115 const { className, onIonTabsDidChange, onIonTabsWillChange, ...props } = this . props ;
@@ -102,19 +119,15 @@ export const IonTabs = /*@__PURE__*/ (() =>
102119 ? ( this . props . children as ChildFunction ) ( this . ionTabContextState )
103120 : this . props . children ;
104121
105- const outletProps = {
106- ref : this . routerOutletRef ,
107- } ;
108-
109122 React . Children . forEach ( children , ( child : any ) => {
110123 // eslint-disable-next-line no-prototype-builtins
111124 if ( child == null || typeof child !== 'object' || ! child . hasOwnProperty ( 'type' ) ) {
112125 return ;
113126 }
114127 if ( child . type === IonRouterOutlet || child . type . isRouterOutlet ) {
115- outlet = React . cloneElement ( child , outletProps ) ;
128+ outlet = React . cloneElement ( child ) ;
116129 } else if ( child . type === Fragment && child . props . children [ 0 ] . type === IonRouterOutlet ) {
117- outlet = React . cloneElement ( child . props . children [ 0 ] , outletProps ) ;
130+ outlet = React . cloneElement ( child . props . children [ 0 ] ) ;
118131 } else if ( child . type === IonTab ) {
119132 /**
120133 * This indicates that IonTabs will be using a basic tab-based navigation
@@ -123,9 +136,10 @@ export const IonTabs = /*@__PURE__*/ (() =>
123136 hasTab = true ;
124137 }
125138
139+ this . ionTabContextState . hasRouterOutlet = ! ! outlet ;
140+
126141 let childProps : any = {
127- ref : this . tabBarRef ,
128- routerOutletRef : this . routerOutletRef ,
142+ ...this . ionTabContextState . tabBarProps ,
129143 } ;
130144
131145 /**
@@ -149,14 +163,7 @@ export const IonTabs = /*@__PURE__*/ (() =>
149163 } ;
150164 }
151165
152- if ( child . type === IonTabBar || child . type . isTabBar ) {
153- tabBar = React . cloneElement ( child , childProps ) ;
154- } else if (
155- child . type === Fragment &&
156- ( child . props . children [ 1 ] . type === IonTabBar || child . props . children [ 1 ] . type . isTabBar )
157- ) {
158- tabBar = React . cloneElement ( child . props . children [ 1 ] , childProps ) ;
159- }
166+ this . ionTabContextState . tabBarProps = childProps ;
160167 } ) ;
161168
162169 if ( ! outlet && ! hasTab ) {
@@ -186,46 +193,10 @@ export const IonTabs = /*@__PURE__*/ (() =>
186193 < IonTabsContext . Provider value = { this . ionTabContextState } >
187194 { this . context . hasIonicRouter ( ) ? (
188195 < PageManager className = { className ? `${ className } ` : '' } routeInfo = { this . context . routeInfo } { ...props } >
189- < IonTabsInner { ...this . props } >
190- { React . Children . map ( children , ( child : React . ReactNode ) => {
191- if ( React . isValidElement ( child ) ) {
192- const isTabBar =
193- child . type === IonTabBar ||
194- ( child . type as any ) . isTabBar ||
195- ( child . type === Fragment &&
196- ( child . props . children [ 1 ] . type === IonTabBar || child . props . children [ 1 ] . type . isTabBar ) ) ;
197- const isRouterOutlet =
198- child . type === IonRouterOutlet ||
199- ( child . type as any ) . isRouterOutlet ||
200- ( child . type === Fragment && child . props . children [ 0 ] . type === IonRouterOutlet ) ;
201-
202- if ( isTabBar ) {
203- /**
204- * The modified tabBar needs to be returned to include
205- * the context and the overridden methods.
206- */
207- return tabBar ;
208- }
209- if ( isRouterOutlet ) {
210- /**
211- * The modified outlet needs to be returned to include
212- * the ref.
213- */
214- return outlet ;
215- }
216- }
217- return child ;
218- } ) }
219- </ IonTabsInner >
196+ { this . renderTabsInner ( children , outlet ) }
220197 </ PageManager >
221198 ) : (
222- < div className = { className ? `${ className } ` : 'ion-tabs' } { ...props } style = { hostStyles } >
223- { tabBar ?. props . slot === 'top' ? tabBar : null }
224- < div style = { tabsInner } className = "tabs-inner" >
225- { outlet }
226- </ div >
227- { tabBar ?. props . slot === 'bottom' ? tabBar : null }
228- </ div >
199+ this . renderTabsInner ( children , outlet )
229200 ) }
230201 </ IonTabsContext . Provider >
231202 ) ;
0 commit comments