@@ -270,8 +270,6 @@ export const SessionFloatingTOC = React.memo(function SessionFloatingTOC(props:
270270 const wheelAccRef = useRef ( 0 )
271271 const [ clickedIdx , setClickedIdx ] = useState < number | null > ( null )
272272 const scrollTimeoutRef = useRef < ReturnType < typeof setTimeout > | null > ( null )
273- const dragRef = useRef < { startY : number ; startIdx : number } | null > ( null )
274- const dragIdxRef = useRef < number | null > ( null )
275273
276274 /* Compute fractional index from main content scroll position */
277275 useEffect ( ( ) => {
@@ -292,21 +290,19 @@ export const SessionFloatingTOC = React.memo(function SessionFloatingTOC(props:
292290 }
293291 }
294292
295- const scrollY = container . scrollTop
296- const viewportMid = scrollY + container . clientHeight * 0.3
297-
298- let frac = 0
299- for ( let i = 0 ; i < positions . length - 1 ; i ++ ) {
300- if ( viewportMid >= positions [ i ] && viewportMid < positions [ i + 1 ] ) {
301- const range = positions [ i + 1 ] - positions [ i ]
302- frac = range > 0 ? i + ( viewportMid - positions [ i ] ) / range : i
293+ /* Active = last entry whose heading is at or above the viewport reference point.
294+ Each entry "owns" the range from its heading down to the next entry's heading.
295+ Reference = viewport top + small offset so once a heading scrolls past the
296+ top area the indicator switches to it. */
297+ const refPoint = container . scrollTop + 100
298+ let activeIdx = 0
299+ for ( let i = positions . length - 1 ; i >= 0 ; i -- ) {
300+ if ( refPoint >= positions [ i ] ) {
301+ activeIdx = i
303302 break
304303 }
305- if ( i === positions . length - 2 && viewportMid >= positions [ i + 1 ] ) {
306- frac = positions . length - 1
307- }
308304 }
309- setFractionalIndex ( frac )
305+ setFractionalIndex ( activeIdx )
310306 }
311307
312308 const onScroll = ( ) => {
@@ -356,33 +352,6 @@ export const SessionFloatingTOC = React.memo(function SessionFloatingTOC(props:
356352 }
357353 } , [ visualFractionalIndex , clickedIdx , entries , contentScrollRef ] )
358354
359- /* iOS picker drag: pointer down/move/up on strip to scroll through entries */
360- const handleDragStart = useCallback ( ( e : React . PointerEvent ) => {
361- const idx = clickedIdx ?? Math . round ( fractionalIndex )
362- dragRef . current = { startY : e . clientY , startIdx : idx }
363- dragIdxRef . current = idx
364- ; ( e . currentTarget as HTMLElement ) . setPointerCapture ( e . pointerId )
365- } , [ clickedIdx , fractionalIndex ] )
366-
367- const handleDragMove = useCallback ( ( e : React . PointerEvent ) => {
368- if ( ! dragRef . current ) return
369- const deltaY = e . clientY - dragRef . current . startY
370- if ( Math . abs ( deltaY ) < 5 ) return
371- const step = TOC_BAR_HEIGHT + TOC_BAR_GAP
372- const deltaIdx = Math . round ( - deltaY / step )
373- const newIdx = Math . max ( 0 , Math . min ( entries . length - 1 , dragRef . current . startIdx + deltaIdx ) )
374- if ( entries [ newIdx ] && newIdx !== dragIdxRef . current ) {
375- dragIdxRef . current = newIdx
376- setClickedIdx ( newIdx )
377- scrollContentToEntry ( entries [ newIdx ] , contentScrollRef )
378- }
379- } , [ entries , contentScrollRef ] )
380-
381- const handleDragEnd = useCallback ( ( ) => {
382- dragRef . current = null
383- dragIdxRef . current = null
384- } , [ ] )
385-
386355 if ( entries . length < 2 ) return null
387356
388357 const rowStep = TOC_BAR_HEIGHT + TOC_BAR_GAP
@@ -413,9 +382,6 @@ export const SessionFloatingTOC = React.memo(function SessionFloatingTOC(props:
413382 onMouseEnter = { ( ) => setIsHoveringStrip ( true ) }
414383 onMouseLeave = { ( ) => { setIsHoveringStrip ( false ) ; setHoveredIdx ( null ) } }
415384 onWheel = { handleWheel }
416- onPointerDown = { handleDragStart }
417- onPointerMove = { handleDragMove }
418- onPointerUp = { handleDragEnd }
419385 style = { {
420386 position : "fixed" ,
421387 right : 0 ,
@@ -440,7 +406,7 @@ export const SessionFloatingTOC = React.memo(function SessionFloatingTOC(props:
440406 boxShadow : stripShadow ,
441407 backdropFilter : "blur(16px)" ,
442408 WebkitBackdropFilter : "blur(16px)" ,
443- opacity : isHoveringStrip ? 1 : 0.5 ,
409+ opacity : isHoveringStrip ? 1 : 0 ,
444410 transition : "opacity 0.3s ease" ,
445411 pointerEvents : "none" ,
446412 } }
0 commit comments