'use client' import { useGSAP } from '@gsap/react' import gsap from 'gsap' import { SplitText } from 'gsap/SplitText' import { ScrollTrigger, GSDevTools } from 'gsap/all' import { createContext, useCallback, useContext, useEffect, useRef, type ReactNode } from 'react' gsap.registerPlugin(useGSAP) gsap.registerPlugin(ScrollTrigger) gsap.registerPlugin(SplitText) gsap.registerPlugin(GSDevTools) const GsapContext = createContext<{ addAnimation: ( animation: gsap.core.TimelineChild, position: gsap.Position ) => void, resetTimeline: () => void, resumeTimeline: () => void, getScroller: () => Element | Window | null } | null>(null) export function useGsapContext() { return useContext(GsapContext) } export const useTimeLine = (dep:any,all?:boolean) => { const gsapContext = useGsapContext() useEffect(() => { if (dep instanceof Array && all) { let acc = true; let allDepsSatisfied = dep.reduce((p,c) => c !== undefined && p ,acc ) if (allDepsSatisfied) { gsapContext?.resumeTimeline() } } else { if (dep) { gsapContext?.resumeTimeline() } } },[dep]) useEffect(() => { return () => { gsapContext?.resetTimeline() } },[]) } export default function GsapProvider({ children }: { children: ReactNode }) { const tl = useRef(null) const scrollerRef = useRef(null) const getScroller = useCallback(() => { // const cached = scrollerRef.current // if (!cached || (cached instanceof Element && !document.contains(cached))) { let scrollers = document.querySelectorAll('[data-slot="scroll-area-viewport"]') if (scrollers.length < 1) { scrollerRef.current = window } else { let scrollerArray = Array.from(scrollers.values()).sort((a,b) => { const s1 = a as HTMLDivElement; const s2 = b as HTMLDivElement; // using bitwise not (~~) to coerce NaN values to 0 const aPriority = ~~Number(s1.dataset?.scrollerPriority) const bPriority = ~~Number(s2.dataset?.scrollerPriority) return aPriority - bPriority; }) let prioScroller = scrollerArray.pop(); scrollerRef.current = prioScroller || window; } // } return scrollerRef.current }, []) useGSAP(() => { if (!tl.current) { tl.current = gsap.timeline({ paused: true, id:'mainTimeline', onComplete: ()=>{ console.log('timeline revert') gsap.getById('mainTimeline')?.revert() } }) } return () => { console.log("gsap cleanup") } }) const addAnimation = useCallback((animation: gsap.core.TimelineChild, position: gsap.Position) => { console.log("add animation to:", position, tl.current !== undefined) tl.current?.add(animation, position); },[]) const resetTimeline = useCallback(() => { tl.current?.kill() tl.current?.revert() ScrollTrigger.getAll().forEach(st => st.kill()) tl.current = gsap.timeline({paused:true}) },[]) const resumeTimeline = useCallback(() => { console.log("resuming timeline:",tl.current) tl.current?.resume() },[]) return ( {children} ) }