@@ -7,29 +7,31 @@ import { useMediaQuery } from "usehooks-ts";
77type IProps = {
88 style ?: any ;
99 className ?: any ;
10- onBottom : ( ) => void ;
10+ onBottom ? : ( ) => void ;
1111 onRefresh ?: ( ) => Promise < any > ;
1212 children : any ;
1313 pullDownThreshold ?: number ;
1414 maxPullDownDistance ?: number ;
15+ fixMobileTopBar ?: boolean
1516} ;
1617
1718export type ScrollAreaHandles = {
1819 scrollToBottom : ( ) => void ;
1920}
2021
21- export const ScrollArea = observer ( forwardRef < ScrollAreaHandles , IProps > ( ( {
22- style,
23- className,
24- children,
22+ export const ScrollArea = observer ( forwardRef < ScrollAreaHandles , IProps > ( ( {
23+ style,
24+ className,
25+ children,
2526 onBottom,
2627 onRefresh,
2728 pullDownThreshold = 60 ,
28- maxPullDownDistance = 100
29+ maxPullDownDistance = 100 ,
30+ fixMobileTopBar = false
2931} , ref ) => {
3032 const scrollRef = useRef < HTMLDivElement > ( null ) ;
3133 const isPc = useMediaQuery ( '(min-width: 768px)' ) ;
32-
34+
3335 // Pull to refresh states
3436 const [ pullDistance , setPullDistance ] = useState ( 0 ) ;
3537 const [ isRefreshing , setIsRefreshing ] = useState ( false ) ;
@@ -39,7 +41,7 @@ export const ScrollArea = observer(forwardRef<ScrollAreaHandles, IProps>(({
3941 const startYRef = useRef ( 0 ) ;
4042 const canPullRef = useRef ( true ) ; // Initialize as true for initial state
4143 const currentInstanceRef = useRef ( Math . random ( ) . toString ( 36 ) ) ; // Unique identifier for this ScrollArea instance
42-
44+
4345 let debounceBottom ;
4446 if ( onBottom ) {
4547 debounceBottom = _ . debounce ( onBottom ! , 500 , { leading : true , trailing : false } ) ;
@@ -57,7 +59,7 @@ export const ScrollArea = observer(forwardRef<ScrollAreaHandles, IProps>(({
5759 if ( bottom ) {
5860 debounceBottom ?.( ) ;
5961 }
60-
62+
6163 // Update can pull state
6264 canPullRef . current = target . scrollTop === 0 ;
6365 } ;
@@ -149,19 +151,19 @@ export const ScrollArea = observer(forwardRef<ScrollAreaHandles, IProps>(({
149151 useEffect ( ( ) => {
150152 const divElement = scrollRef . current ;
151153 if ( ! divElement ) return ;
152-
154+
153155 // Initialize canPull state
154156 canPullRef . current = divElement . scrollTop === 0 ;
155-
157+
156158 divElement . addEventListener ( "scroll" , handleScroll ) ;
157-
159+
158160 // Add pull-to-refresh listeners only if onRefresh exists AND device is mobile
159161 if ( onRefresh && ! isPc ) {
160162 divElement . addEventListener ( 'touchstart' , handleTouchStart , { passive : false } ) ;
161163 divElement . addEventListener ( 'touchmove' , handleTouchMove , { passive : false } ) ;
162164 divElement . addEventListener ( 'touchend' , handleTouchEnd , { passive : true } ) ;
163165 }
164-
166+
165167 return ( ) => {
166168 divElement . removeEventListener ( "scroll" , handleScroll ) ;
167169 if ( onRefresh && ! isPc ) {
@@ -176,32 +178,32 @@ export const ScrollArea = observer(forwardRef<ScrollAreaHandles, IProps>(({
176178 const pullProgress = Math . min ( pullDistance / pullDownThreshold , 1 ) ;
177179 const arrowRotation = pullProgress * 180 ; // 0 to 180 degrees
178180 const isReadyToRefresh = pullDistance >= pullDownThreshold ;
179-
181+
180182 const showRefreshIndicator = onRefresh && ! isPc && ( pullDistance > 0 || isRefreshing ) ;
181- const refreshText = isRefreshing
182- ? i18n . t ( 'common.refreshing' )
183- : isReadyToRefresh
184- ? i18n . t ( 'common.releaseToRefresh' )
183+ const refreshText = isRefreshing
184+ ? i18n . t ( 'common.refreshing' )
185+ : isReadyToRefresh
186+ ? i18n . t ( 'common.releaseToRefresh' )
185187 : i18n . t ( 'common.pullToRefresh' ) ;
186188
187189 // Arrow Icon Component
188190 const ArrowIcon = ( ) => (
189- < svg
190- width = "16"
191- height = "16"
192- viewBox = "0 0 24 24"
193- fill = "none"
191+ < svg
192+ width = "16"
193+ height = "16"
194+ viewBox = "0 0 24 24"
195+ fill = "none"
194196 className = { `transition-transform duration-150 ${ isDragging ? '' : 'duration-300' } ` }
195- style = { {
197+ style = { {
196198 transform : `rotate(${ arrowRotation } deg)` ,
197199 opacity : pullProgress
198200 } }
199201 >
200- < path
201- d = "M12 5l0 14m-7-7l7-7 7 7"
202- stroke = "currentColor"
203- strokeWidth = "2"
204- strokeLinecap = "round"
202+ < path
203+ d = "M12 5l0 14m-7-7l7-7 7 7"
204+ stroke = "currentColor"
205+ strokeWidth = "2"
206+ strokeLinecap = "round"
205207 strokeLinejoin = "round"
206208 />
207209 </ svg >
@@ -218,14 +220,13 @@ export const ScrollArea = observer(forwardRef<ScrollAreaHandles, IProps>(({
218220 } }
219221 className = { `${ className } overflow-y-scroll overflow-x-hidden ${ isPc ? '' : 'scrollbar-hide' } scroll-smooth scroll-area` }
220222 >
223+ { fixMobileTopBar && ! isPc && < div className = "h-16" > </ div > }
221224 { /* Pull to refresh indicator */ }
222225 { showRefreshIndicator && (
223- < div
224- className = { `flex items-center justify-center transition-all duration-150 ${
225- isDragging ? '' : 'duration-300'
226- } ${ isReadyToRefresh ? 'text-primary' : 'text-gray-500' } ${
227- isReadyToRefresh ? 'bg-primary/5' : 'bg-gray-50/80'
228- } `}
226+ < div
227+ className = { `flex items-center justify-center transition-all duration-150 ${ isDragging ? '' : 'duration-300'
228+ } ${ isReadyToRefresh ? 'text-primary' : 'text-gray-500' } ${ isReadyToRefresh ? 'bg-primary/5' : 'bg-gray-50/80'
229+ } `}
229230 style = { {
230231 height : `${ pullDistance } px` ,
231232 marginTop : `-${ pullDistance } px` ,
@@ -239,18 +240,17 @@ export const ScrollArea = observer(forwardRef<ScrollAreaHandles, IProps>(({
239240 ) : (
240241 < ArrowIcon />
241242 ) }
242- < span
243- className = { `text-sm font-medium transition-all duration-200 ${
244- isReadyToRefresh ? 'scale-105' : 'scale-100'
245- } `}
243+ < span
244+ className = { `text-sm font-medium transition-all duration-200 ${ isReadyToRefresh ? 'scale-105' : 'scale-100'
245+ } `}
246246 style = { { opacity : Math . max ( pullProgress , 0.6 ) } }
247247 >
248248 { refreshText }
249249 </ span >
250250 </ div >
251251 </ div >
252252 ) }
253-
253+
254254 { children }
255255 </ div >
256256 ) ;
0 commit comments