@@ -69,16 +69,26 @@ const MessageListFollow: FC<{ itemKeys: readonly string[] }> = ({ itemKeys }) =>
6969 // geometry (scroll events), and real manual-intent cancellation. No timers, frame loops,
7070 // debounce, polling, or Resize/Mutation observers are involved.
7171 useEffect ( ( ) => {
72- const root = actionRef . current ?. closest ( '[data-slot="message-scroller"]' )
72+ const root = actionRef . current ?. closest < HTMLElement > ( '[data-slot="message-scroller"]' )
7373 const viewport = root ?. querySelector < HTMLElement > ( '[data-slot="message-scroller-viewport"]' )
74- if ( ! viewport ) return
74+ if ( ! viewport || ! root ) return
7575
7676 const cancelAuthorization = ( ) => {
7777 authorizationRef . current = null
7878 }
7979 const onKeyDown = ( event : KeyboardEvent ) => {
8080 if ( NAV_SCROLL_KEYS . has ( event . key ) ) cancelAuthorization ( )
8181 }
82+ // Scrollbar drags cancel through one delegated listener on the constantly mounted
83+ // scroller root: the repository Radix ScrollBar only mounts on hover/scroll, so binding
84+ // the scrollbar element itself at mount would miss every later drag. Only pointerdowns
85+ // originating inside the repository scrollbar subtree cancel; every other pointer target
86+ // (messages, content, viewport, selection, clicks) leaves the authorization untouched.
87+ const onPointerDown = ( event : PointerEvent ) => {
88+ if ( ( event . target as HTMLElement | null ) ?. closest ( '[data-slot="scroll-area-scrollbar"]' ) ) {
89+ cancelAuthorization ( )
90+ }
91+ }
8292 const retargetIfAdvanced = ( ) => {
8393 const authorization = authorizationRef . current
8494 if ( ! authorization ) return
@@ -105,15 +115,14 @@ const MessageListFollow: FC<{ itemKeys: readonly string[] }> = ({ itemKeys }) =>
105115 viewport . addEventListener ( 'keydown' , onKeyDown )
106116 viewport . addEventListener ( 'scroll' , retargetIfAdvanced , { passive : true } )
107117 viewport . addEventListener ( 'scrollend' , onScrollEnd )
108- const scrollbar = root ?. querySelector ( '[data-slot="scroll-area-scrollbar"]' )
109- scrollbar ?. addEventListener ( 'pointerdown' , cancelAuthorization )
118+ root . addEventListener ( 'pointerdown' , onPointerDown )
110119 return ( ) => {
111120 viewport . removeEventListener ( 'wheel' , cancelAuthorization )
112121 viewport . removeEventListener ( 'touchmove' , cancelAuthorization )
113122 viewport . removeEventListener ( 'keydown' , onKeyDown )
114123 viewport . removeEventListener ( 'scroll' , retargetIfAdvanced )
115124 viewport . removeEventListener ( 'scrollend' , onScrollEnd )
116- scrollbar ? .removeEventListener ( 'pointerdown' , cancelAuthorization )
125+ root . removeEventListener ( 'pointerdown' , onPointerDown )
117126 }
118127 } , [ scrollToEnd ] )
119128
0 commit comments