import { useEffect, useRef, useState } from "react"; import { SLOT_WIDTH } from "~/components/scoring/BracketTreeView"; interface AnimState { fromPage: number; toPage: number; dir: "left" | "right"; phase: "sliding" | "settling"; } export function useRoundTransition(maxPage: number, defaultPage: number) { const [page, setPage] = useState(defaultPage); const [anim, setAnim] = useState(null); const stripRef = useRef(null); useEffect(() => { if (!anim || anim.phase !== "sliding" || !stripRef.current) return; const el = stripRef.current; const finalX = anim.dir === "right" ? -SLOT_WIDTH : 0; const raf = requestAnimationFrame(() => { el.style.transition = "transform 200ms ease"; el.style.transform = `translateX(${finalX}px)`; }); return () => cancelAnimationFrame(raf); }, [anim]); useEffect(() => { if (!anim || anim.phase !== "settling") return; const timer = setTimeout(() => setAnim(null), 520); return () => clearTimeout(timer); }, [anim]); const navigate = (newPage: number) => { if (anim || newPage < 0 || newPage > maxPage) return; setAnim({ fromPage: page, toPage: newPage, dir: newPage > page ? "right" : "left", phase: "sliding" }); }; const handleTransitionEnd = () => { if (!anim || anim.phase !== "sliding") return; if (stripRef.current) { stripRef.current.style.transition = "none"; stripRef.current.style.transform = "translateX(0)"; } setPage(anim.toPage); setAnim((prev) => (prev ? { ...prev, phase: "settling" } : null)); }; return { page, anim, stripRef, navigate, handleTransitionEnd }; }