11import type { ComponentInterface , EventEmitter } from '@stencil/core' ;
2- import { Component , Element , Event , Host , Prop , State , Watch , h } from '@stencil/core' ;
2+ import { Component , Element , Event , Host , Prop , State , Watch , h , readTask , writeTask } from '@stencil/core' ;
3+ import { findIonContent , getScrollElement } from '@utils/content' ;
34import type { KeyboardController } from '@utils/keyboard/keyboard-controller' ;
45import { createKeyboardController } from '@utils/keyboard/keyboard-controller' ;
56import { createColorClasses } from '@utils/theme' ;
@@ -26,11 +27,17 @@ export class TabBar implements ComponentInterface {
2627 private keyboardCtrl : KeyboardController | null = null ;
2728 private keyboardCtrlPromise : Promise < KeyboardController > | null = null ;
2829 private didLoad = false ;
30+ private scrollEl ?: HTMLElement ;
31+ private contentScrollCallback ?: ( ) => void ;
32+ private lastScrollTop = 0 ;
33+ private scrollDirectionChangeTop = 0 ;
2934
3035 @Element ( ) el ! : HTMLElement ;
3136
3237 @State ( ) keyboardVisible = false ;
3338
39+ @State ( ) scrollHidden = false ;
40+
3441 /**
3542 * The color to use from your application's color palette.
3643 * Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
@@ -57,6 +64,13 @@ export class TabBar implements ComponentInterface {
5764 }
5865 }
5966
67+ /**
68+ * If `true`, the tab bar will be hidden when the user scrolls down
69+ * and shown when the user scrolls up.
70+ * Only applies when the theme is `"ionic"` and `expand` is `"compact"`.
71+ */
72+ @Prop ( ) hideOnScroll = false ;
73+
6074 /**
6175 * If `true`, the tab bar will be translucent.
6276 * Only applies when the theme is `"ios"` and the device supports
@@ -108,6 +122,8 @@ export class TabBar implements ComponentInterface {
108122 tab : this . selectedTab ,
109123 } ) ;
110124 }
125+
126+ this . setupHideOnScroll ( ) ;
111127 }
112128
113129 async connectedCallback ( ) {
@@ -150,6 +166,64 @@ export class TabBar implements ComponentInterface {
150166 this . keyboardCtrl . destroy ( ) ;
151167 this . keyboardCtrl = null ;
152168 }
169+
170+ this . destroyHideOnScroll ( ) ;
171+ }
172+
173+ private setupHideOnScroll ( ) {
174+ const theme = getIonTheme ( this ) ;
175+ if ( theme !== 'ionic' || ! this . hideOnScroll || this . expand !== 'compact' ) {
176+ return ;
177+ }
178+
179+ const footerEl = this . el . closest ( 'ion-footer' ) ;
180+ const pageEl = footerEl ?. closest ( 'ion-page, .ion-page' ) ?? this . el . closest ( 'ion-page, .ion-page' ) ;
181+ const contentEl = pageEl ? findIonContent ( pageEl ) : null ;
182+
183+ if ( ! contentEl ) {
184+ return ;
185+ }
186+
187+ this . initScrollListener ( contentEl ) ;
188+ }
189+
190+ private async initScrollListener ( contentEl : HTMLElement ) {
191+ const scrollEl = ( this . scrollEl = await getScrollElement ( contentEl ) ) ;
192+
193+ const scrollThreshold = 10 ;
194+
195+ this . contentScrollCallback = ( ) => {
196+ readTask ( ( ) => {
197+ const scrollTop = scrollEl . scrollTop ;
198+ const isScrollingDown = scrollTop > this . lastScrollTop ;
199+
200+ if ( isScrollingDown !== this . lastScrollTop > this . scrollDirectionChangeTop ) {
201+ this . scrollDirectionChangeTop = this . lastScrollTop ;
202+ }
203+
204+ const delta = Math . abs ( scrollTop - this . scrollDirectionChangeTop ) ;
205+
206+ if ( delta >= scrollThreshold ) {
207+ const shouldHide = isScrollingDown && scrollTop > 0 ;
208+ if ( shouldHide !== this . scrollHidden ) {
209+ writeTask ( ( ) => {
210+ this . scrollHidden = shouldHide ;
211+ } ) ;
212+ }
213+ }
214+
215+ this . lastScrollTop = scrollTop ;
216+ } ) ;
217+ } ;
218+
219+ scrollEl . addEventListener ( 'scroll' , this . contentScrollCallback , { passive : true } ) ;
220+ }
221+
222+ private destroyHideOnScroll ( ) {
223+ if ( this . scrollEl && this . contentScrollCallback ) {
224+ this . scrollEl . removeEventListener ( 'scroll' , this . contentScrollCallback ) ;
225+ this . contentScrollCallback = undefined ;
226+ }
153227 }
154228
155229 private getShape ( ) : string | undefined {
@@ -169,7 +243,7 @@ export class TabBar implements ComponentInterface {
169243 }
170244
171245 render ( ) {
172- const { color, translucent, keyboardVisible, expand } = this ;
246+ const { color, translucent, keyboardVisible, scrollHidden , expand, hideOnScroll } = this ;
173247 const theme = getIonTheme ( this ) ;
174248 const shape = this . getShape ( ) ;
175249 const shouldHide = keyboardVisible && this . el . getAttribute ( 'slot' ) !== 'top' ;
@@ -182,6 +256,8 @@ export class TabBar implements ComponentInterface {
182256 [ theme ] : true ,
183257 'tab-bar-translucent' : translucent ,
184258 'tab-bar-hidden' : shouldHide ,
259+ 'tab-bar-hide-on-scroll' : hideOnScroll ,
260+ 'tab-bar-scroll-hidden' : scrollHidden ,
185261 [ `tab-bar-${ expand } ` ] : true ,
186262 [ `tab-bar-${ shape } ` ] : shape !== undefined ,
187263 } ) }
0 commit comments