All files / src/components/ui/util CachedScroll.tsx

0% Statements 0/30
0% Branches 0/18
0% Functions 0/4
0% Lines 0/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74                                                                                                                                                   
import React, { useCallback, useEffect, useRef } from "react";
 
const scrollCache: Record<string, number> = {};
 
interface CachedScrollProps {
  children: React.ReactNode;
  cacheKey: string;
}
 
const CachedScroll = ({ children, cacheKey }: CachedScrollProps) => {
  const scrollRef = useRef<HTMLDivElement>(null);
  const isProgrammaticScroll = useRef(true);
  const isUserScrolling = useRef(false);
 
  const onScroll = useCallback(() => {
    Iif (isProgrammaticScroll.current) {
      isProgrammaticScroll.current = false;
      return;
    }
    Iif (scrollRef.current) {
      // Was user scroll so update cached scroll pos and cancel auto scrolling
      scrollCache[cacheKey] = scrollRef.current.scrollTop;
      isUserScrolling.current = true;
    }
  }, [cacheKey]);
 
  useEffect(() => {
    const checkScroll = () => {
      const savedScrollPosition = scrollCache[cacheKey];
      const savedPosition = savedScrollPosition ?? 0;
 
      Iif (scrollRef.current) {
        // If not reached saved pos yet
        Iif (
          !isUserScrolling.current &&
          scrollRef.current.scrollTop < savedPosition
        ) {
          // Only scroll if there is more scroll height available
          // to prevent clash with user initiated scroll events
          Iif (
            scrollRef.current.scrollTop <
            scrollRef.current.scrollHeight - scrollRef.current.clientHeight
          ) {
            isProgrammaticScroll.current = true;
            scrollRef.current.scrollTop = savedPosition;
          }
 
          requestAnimationFrame(checkScroll);
        }
      }
    };
 
    const savedScrollPosition = scrollCache[cacheKey];
    const savedPosition = savedScrollPosition ?? 0;
 
    Iif (savedPosition > 0 && scrollRef.current) {
      scrollRef.current.scrollTop = savedPosition;
      requestAnimationFrame(checkScroll);
    }
  }, [cacheKey]);
 
  return (
    <div
      ref={scrollRef}
      onScroll={onScroll}
      style={{ width: "100%", height: "100%", overflowY: "auto" }}
    >
      {children}
    </div>
  );
};
 
export default CachedScroll;