@@ -10,85 +10,15 @@ export type ScrollAreaScrollbarProps = ComponentPropsWithoutRef<'div'> & {
1010} ;
1111
1212const ScrollAreaScrollbar = forwardRef < ScrollAreaScrollbarElement , ScrollAreaScrollbarProps > ( ( { children, className = '' , orientation = 'vertical' , ...props } , ref ) => {
13- const { rootClass, handleScrollbarClick, scrollXThumbRef, scrollYThumbRef, type, scrollAreaViewportRef , rootRef } = useContext ( ScrollAreaContext ) ;
13+ const { rootClass, handleScrollbarClick, scrollXThumbRef, scrollYThumbRef, type, scrollbarVisible , overflow } = useContext ( ScrollAreaContext ) ;
1414
1515 const intervalRef = useRef < NodeJS . Timeout | null > ( null ) ;
1616 const isScrollingRef = useRef ( false ) ;
1717 const removeListenersRef = useRef < ( ( ) => void ) | null > ( null ) ;
1818 const [ isScrollingState , setIsScrollingState ] = React . useState ( false ) ;
1919 const mousePositionRef = useRef < number > ( 0 ) ;
2020
21- const [ visible , setVisible ] = React . useState ( type === 'always' ) ;
22- const [ isOverflowing , setIsOverflowing ] = React . useState ( false ) ;
23- const hideTimeoutRef = useRef < NodeJS . Timeout | null > ( null ) ;
24-
25- const show = React . useCallback ( ( ) => {
26- if ( type === 'scroll' || type === 'hover' ) {
27- setVisible ( true ) ;
28- if ( hideTimeoutRef . current ) clearTimeout ( hideTimeoutRef . current ) ;
29- hideTimeoutRef . current = setTimeout ( ( ) => {
30- setVisible ( false ) ;
31- } , 1000 ) ;
32- }
33- } , [ type ] ) ;
34-
35- // Handle scroll visibility
36- React . useEffect ( ( ) => {
37- if ( type === 'always' || type === 'auto' ) return ;
38- const viewport = scrollAreaViewportRef ?. current ;
39- if ( ! viewport ) return ;
40-
41- const handleViewportScroll = ( ) => show ( ) ;
42- viewport . addEventListener ( 'scroll' , handleViewportScroll ) ;
43- return ( ) => {
44- viewport . removeEventListener ( 'scroll' , handleViewportScroll ) ;
45- if ( hideTimeoutRef . current ) clearTimeout ( hideTimeoutRef . current ) ;
46- } ;
47- } , [ type , scrollAreaViewportRef , show ] ) ;
48-
49- // Handle hover visibility
50- React . useEffect ( ( ) => {
51- if ( type !== 'hover' ) return ;
52- const root = rootRef ?. current ;
53- if ( ! root ) return ;
54-
55- const handleMouseEnter = ( ) => {
56- if ( hideTimeoutRef . current ) clearTimeout ( hideTimeoutRef . current ) ;
57- setVisible ( true ) ;
58- } ;
59- const handleMouseLeave = ( ) => {
60- if ( hideTimeoutRef . current ) clearTimeout ( hideTimeoutRef . current ) ;
61- hideTimeoutRef . current = setTimeout ( ( ) => {
62- setVisible ( false ) ;
63- } , 500 ) ;
64- } ;
65-
66- root . addEventListener ( 'mouseenter' , handleMouseEnter ) ;
67- root . addEventListener ( 'mouseleave' , handleMouseLeave ) ;
68- return ( ) => {
69- root . removeEventListener ( 'mouseenter' , handleMouseEnter ) ;
70- root . removeEventListener ( 'mouseleave' , handleMouseLeave ) ;
71- } ;
72- } , [ type , rootRef ] ) ;
73-
74- // Overflow detection
75- React . useEffect ( ( ) => {
76- const viewport = scrollAreaViewportRef ?. current ;
77- if ( ! viewport ) return ;
78-
79- const checkOverflow = ( ) => {
80- const overflowing = orientation === 'vertical'
81- ? viewport . scrollHeight > viewport . clientHeight
82- : viewport . scrollWidth > viewport . clientWidth ;
83- setIsOverflowing ( overflowing ) ;
84- } ;
85-
86- checkOverflow ( ) ;
87- const ro = new ResizeObserver ( checkOverflow ) ;
88- ro . observe ( viewport ) ;
89- Array . from ( viewport . children ) . forEach ( c => ro . observe ( c ) ) ;
90- return ( ) => ro . disconnect ( ) ;
91- } , [ scrollAreaViewportRef , orientation ] ) ;
21+ const isOverflowing = orientation === 'vertical' ? overflow . y : overflow . x ;
9222
9323 // Determine whether the auto-scroll should continue based on mouse position
9424 const shouldContinueScrolling = React . useCallback ( ( mousePos : number ) : boolean => {
@@ -177,7 +107,10 @@ const ScrollAreaScrollbar = forwardRef<ScrollAreaScrollbarElement, ScrollAreaScr
177107 } ;
178108 } , [ isScrollingState , stopContinuousScroll ] ) ;
179109
180- const isVisible = type === 'always' || ( type === 'auto' && isOverflowing ) || ( isOverflowing && visible ) ;
110+ const isVisible =
111+ type === 'always'
112+ || ( type === 'auto' && isOverflowing )
113+ || ( isOverflowing && ( type === 'scroll' || type === 'hover' ) && scrollbarVisible ) ;
181114 const shouldKeepInDOM = isOverflowing || type === 'always' ;
182115
183116 return (
0 commit comments