diff --git a/src/features/players/components/player-stats-table.tsx b/src/features/players/components/player-stats-table.tsx index cebcd6c..6d07136 100644 --- a/src/features/players/components/player-stats-table.tsx +++ b/src/features/players/components/player-stats-table.tsx @@ -116,6 +116,9 @@ const PlayerListItem = memo(({ stat, onPlayerClick, mmr, onRegisterViewport, onU viewport: { WebkitOverflowScrolling: 'touch', scrollBehavior: 'auto', + willChange: 'scroll-position', + transform: 'translateZ(0)', + backfaceVisibility: 'hidden', }, }} > @@ -150,33 +153,48 @@ const PlayerStatsTable = () => { const viewportsRef = useRef>(new Set()); const scrollHandlersRef = useRef void>>(new Map()); - const isSyncingRef = useRef(false); + const scrollLeaderRef = useRef(null); + const scrollTimeoutRef = useRef(null); const handleRegisterViewport = useCallback((viewport: HTMLDivElement) => { viewportsRef.current.add(viewport); + const handleScrollStart = () => { + scrollLeaderRef.current = viewport; + }; + const handleScroll = (e: Event) => { const target = e.target as HTMLDivElement; - // Prevent infinite loops - if (isSyncingRef.current) { + if (scrollLeaderRef.current !== target) { return; } - isSyncingRef.current = true; const scrollLeft = target.scrollLeft; - // Synchronize all other viewports immediately viewportsRef.current.forEach((vp) => { if (vp !== target) { - vp.scrollLeft = scrollLeft; + if (Math.abs(vp.scrollLeft - scrollLeft) > 0.5) { + const wasLeader = scrollLeaderRef.current; + scrollLeaderRef.current = null; + vp.scrollLeft = scrollLeft; + scrollLeaderRef.current = wasLeader; + } } }); - isSyncingRef.current = false; + if (scrollTimeoutRef.current) { + clearTimeout(scrollTimeoutRef.current); + } + scrollTimeoutRef.current = window.setTimeout(() => { + scrollLeaderRef.current = null; + }, 150); }; + viewport.addEventListener('touchstart', handleScrollStart, { passive: true }); + viewport.addEventListener('mousedown', handleScrollStart, { passive: true }); viewport.addEventListener('scroll', handleScroll, { passive: true }); + scrollHandlersRef.current.set(viewport, handleScroll); }, []); @@ -186,6 +204,8 @@ const PlayerStatsTable = () => { const handler = scrollHandlersRef.current.get(viewport); if (handler) { viewport.removeEventListener('scroll', handler); + viewport.removeEventListener('touchstart', handler); + viewport.removeEventListener('mousedown', handler); scrollHandlersRef.current.delete(viewport); } }, []);