45 lines · 1.6 KB · TypeScript
RawDownload
import { useEffect, useRef, useState } from "react"; const TICK_INTERVAL_MS = 120;const FADE_OUT_DELAY_MS = 220;const SEED_PERCENT = 4;const ASYMPTOTE_PERCENT = 90;const APPROACH_FACTOR = 0.08;const MIN_INCREMENT = 0.5; /** * Indeterminate progress simulator for the preview chrome's loading bar. * Animates 0 → 90% asymptotically while `loading` is true, snaps to 100% * on release, then resets after a short pause. * * Uses a ref to thread the latest progress through interval ticks without * needing `loading` to retrigger the effect, which sidesteps the stale- * closure pitfalls of reading `progress` directly. */export function useLoadingProgress(loading: boolean): number {  const [progress, setProgress] = useState(0);  const progressRef = useRef(0);  progressRef.current = progress;   useEffect(() => {    if (!loading) {      if (progressRef.current === 0) return;      setProgress(100);      const timer = window.setTimeout(() => setProgress(0), FADE_OUT_DELAY_MS);      return () => window.clearTimeout(timer);    }     setProgress((value) => (value > 0 && value < 95 ? value : SEED_PERCENT));    const interval = window.setInterval(() => {      const current = progressRef.current;      if (current >= ASYMPTOTE_PERCENT) return;      const remaining = ASYMPTOTE_PERCENT - current;      const increment = Math.max(MIN_INCREMENT, remaining * APPROACH_FACTOR);      setProgress(Math.min(ASYMPTOTE_PERCENT, current + increment));    }, TICK_INTERVAL_MS);     return () => window.clearInterval(interval);  }, [loading]);   return progress;}