@@ -15,7 +15,11 @@ import { useReviewDraftsStore } from "../reviewDraftsStore";
1515import { REVIEW_HOST , type ReviewHost } from "../reviewHost" ;
1616import { useReviewNavigationStore } from "../reviewNavigationStore" ;
1717import type { ReviewListItem , ReviewShellProps } from "../reviewShellParts" ;
18- import { isFileViewed } from "../reviewShellParts" ;
18+ import {
19+ findActiveScrollKey ,
20+ findRenderedScrollAnchor ,
21+ isFileViewed ,
22+ } from "../reviewShellParts" ;
1923import { ReviewViewedContext } from "../reviewViewedContext" ;
2024import { useReviewViewedStore } from "../reviewViewedStore" ;
2125import { PendingReviewBar } from "./PendingReviewBar" ;
@@ -127,8 +131,10 @@ export function ReviewShell({
127131 const reviewHost = useService < ReviewHost > ( REVIEW_HOST ) ;
128132 const taskId = task . id ;
129133 const listRef = useRef < VListHandle | null > ( null ) ;
134+ const listContainerRef = useRef < HTMLDivElement | null > ( null ) ;
130135 const lastActiveRef = useRef < string | null > ( null ) ;
131- const navigationLockedRef = useRef ( false ) ;
136+ const pendingNavigationRef = useRef < string | null > ( null ) ;
137+ const navigationFrameRef = useRef < number | null > ( null ) ;
132138
133139 const workerFactory = useCallback (
134140 ( ) => reviewHost . diffWorkerFactory ( ) ,
@@ -203,6 +209,9 @@ export function ReviewShell({
203209
204210 useEffect ( ( ) => {
205211 return ( ) => {
212+ if ( navigationFrameRef . current !== null ) {
213+ cancelAnimationFrame ( navigationFrameRef . current ) ;
214+ }
206215 clearTask ( taskId ) ;
207216 useReviewDraftsStore . getState ( ) . clearDrafts ( taskId ) ;
208217 } ;
@@ -217,14 +226,37 @@ export function ReviewShell({
217226 const viewed =
218227 currentSignature !== undefined &&
219228 isFileViewed ( viewedRecord [ scrollRequest ] , currentSignature ) ;
220- navigationLockedRef . current = true ;
229+ if ( navigationFrameRef . current !== null ) {
230+ cancelAnimationFrame ( navigationFrameRef . current ) ;
231+ }
232+ pendingNavigationRef . current = scrollRequest ;
221233 if ( ! viewed ) onUncollapseFile ?.( scrollRequest ) ;
222- requestAnimationFrame ( ( ) => {
234+
235+ const scrollToAnchor = ( remainingAttempts : number ) => {
223236 listRef . current ?. scrollToIndex ( targetIndex , { align : "start" } ) ;
224- lastActiveRef . current = scrollRequest ;
225- setActiveFilePath ( taskId , scrollRequest ) ;
226- clearScrollRequest ( taskId ) ;
227- } ) ;
237+ navigationFrameRef . current = requestAnimationFrame ( ( ) => {
238+ const root = listContainerRef . current ;
239+ const anchor = root
240+ ? findRenderedScrollAnchor ( root , scrollRequest )
241+ : null ;
242+
243+ if ( ! anchor && remainingAttempts > 0 ) {
244+ scrollToAnchor ( remainingAttempts - 1 ) ;
245+ return ;
246+ }
247+
248+ anchor ?. scrollIntoView ( { block : "start" , inline : "nearest" } ) ;
249+ lastActiveRef . current = scrollRequest ;
250+ setActiveFilePath ( taskId , scrollRequest ) ;
251+ clearScrollRequest ( taskId ) ;
252+ navigationFrameRef . current = requestAnimationFrame ( ( ) => {
253+ pendingNavigationRef . current = null ;
254+ navigationFrameRef . current = null ;
255+ } ) ;
256+ } ) ;
257+ } ;
258+
259+ scrollToAnchor ( 5 ) ;
228260 } , [
229261 clearScrollRequest ,
230262 currentSignatures ,
@@ -236,24 +268,17 @@ export function ReviewShell({
236268 viewedRecord ,
237269 ] ) ;
238270
239- const handleScroll = useCallback (
240- ( offset : number ) => {
241- if ( navigationLockedRef . current ) return ;
242- const handle = listRef . current ;
243- if ( ! handle ) return ;
244- const index = handle . findItemIndex ( offset ) ;
245- const item = items [ index ] ;
246- const scrollKey = item ?. scrollKey ;
247- if ( ! scrollKey || scrollKey === lastActiveRef . current ) return ;
248- lastActiveRef . current = scrollKey ;
249- setActiveFilePath ( taskId , scrollKey ) ;
250- } ,
251- [ items , setActiveFilePath , taskId ] ,
252- ) ;
253-
254- const handleUserScrollIntent = useCallback ( ( ) => {
255- navigationLockedRef . current = false ;
256- } , [ ] ) ;
271+ const handleScroll = useCallback ( ( ) => {
272+ if ( pendingNavigationRef . current !== null ) return ;
273+ const scrollRoot = listContainerRef . current ?. querySelector < HTMLElement > (
274+ ".pierre-scroll-root" ,
275+ ) ;
276+ if ( ! scrollRoot ) return ;
277+ const scrollKey = findActiveScrollKey ( scrollRoot ) ;
278+ if ( ! scrollKey || scrollKey === lastActiveRef . current ) return ;
279+ lastActiveRef . current = scrollKey ;
280+ setActiveFilePath ( taskId , scrollKey ) ;
281+ } , [ setActiveFilePath , taskId ] ) ;
257282
258283 const renderItem = useCallback (
259284 ( item : ReviewListItem ) => (
@@ -314,11 +339,9 @@ export function ReviewShell({
314339 />
315340 < Flex className = "min-h-0 flex-1" >
316341 < Flex
342+ ref = { listContainerRef }
317343 direction = "column"
318344 className = "min-w-0 flex-1"
319- onPointerDownCapture = { handleUserScrollIntent }
320- onWheelCapture = { handleUserScrollIntent }
321- onKeyDownCapture = { handleUserScrollIntent }
322345 >
323346 { isLoading ? (
324347 < Flex
0 commit comments