"use client"; import { useEffect, useRef, useState } from "react"; import { gsap } from "gsap"; interface PageTransitionProps { isOpen: boolean; onComplete?: () => void; direction?: "reveal" | "unreveal"; } /* ------------------------------------------------------------------ 1. Path data – identical to the original demo ------------------------------------------------------------------ */ const paths = { step1: { unfilled: "M 0 100 V 100 Q 50 100 100 100 V 100 z", inBetween: { curve1: "M 0 100 V 50 Q 50 0 100 50 V 100 z", curve2: "M 0 100 V 50 Q 50 100 100 50 V 100 z", }, filled: "M 0 100 V 0 Q 50 0 100 0 V 100 z", }, step2: { filled: "M 0 0 V 100 Q 50 100 100 100 V 0 z", inBetween: { curve1: "M 0 0 V 50 Q 50 0 100 50 V 0 z", curve2: "M 0 0 V 50 Q 50 100 100 50 V 0 z", }, unfilled: "M 0 0 V 0 Q 50 0 100 0 V 0 z", }, }; export const PageTransition = ({ isOpen, onComplete, direction = "reveal", }: PageTransitionProps) => { const pathRef = useRef(null); const svgRef = useRef(null); // 👈 new ref for hiding const [animating, setAnimating] = useState(false); /* -------------------------------------------------------------- REVEAL – open second view -------------------------------------------------------------- */ const reveal = () => { if (animating) return; setAnimating(true); // 👇 Show overlay before animation starts gsap.set(svgRef.current, { display: "block" }); const tl = gsap.timeline({ onComplete: () => { setAnimating(false); onComplete?.(); // 👇 Hide overlay after animation completes gsap.set(svgRef.current, { display: "none" }); }, }); tl.set(pathRef.current, { attr: { d: paths.step1.unfilled } }) .to(pathRef.current, { duration: 0.8, ease: "power4.in", attr: { d: paths.step1.inBetween.curve1 }, }) .to(pathRef.current, { duration: 0.2, ease: "power1", attr: { d: paths.step1.filled }, onComplete: () => onComplete?.(), }) .set(pathRef.current, { attr: { d: paths.step2.filled } }) .to(pathRef.current, { duration: 0.2, ease: "sine.in", attr: { d: paths.step2.inBetween.curve1 }, }) .to(pathRef.current, { duration: 1, ease: "power4", attr: { d: paths.step2.unfilled }, }); }; /* -------------------------------------------------------------- UNREVEAL – back to first view -------------------------------------------------------------- */ const unreveal = () => { if (animating) return; setAnimating(true); // 👇 Show overlay before animation starts gsap.set(svgRef.current, { display: "block" }); const tl = gsap.timeline({ onComplete: () => { setAnimating(false); onComplete?.(); // 👇 Hide overlay after animation completes gsap.set(svgRef.current, { display: "none" }); }, }); tl.set(pathRef.current, { attr: { d: paths.step2.unfilled } }) .to(pathRef.current, { duration: 0.8, ease: "power4.in", attr: { d: paths.step2.inBetween.curve2 }, }) .to(pathRef.current, { duration: 0.2, ease: "power1", attr: { d: paths.step2.filled }, onComplete: () => onComplete?.(), }) .set(pathRef.current, { attr: { d: paths.step1.filled } }) .to(pathRef.current, { duration: 0.2, ease: "sine.in", attr: { d: paths.step1.inBetween.curve2 }, }) .to(pathRef.current, { duration: 1, ease: "power4", attr: { d: paths.step1.unfilled }, }); }; /* -------------------------------------------------------------- React to prop changes -------------------------------------------------------------- */ useEffect(() => { if (!isOpen) return; if (direction === "reveal") reveal(); else if (direction === "unreveal") unreveal(); }, [isOpen, direction]); return ( ); };