65 lines
1.2 KiB
TypeScript
65 lines
1.2 KiB
TypeScript
|
|
import { useLayoutEffect, useRef } from "react";
|
||
|
|
import gsap from "gsap";
|
||
|
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||
|
|
|
||
|
|
gsap.registerPlugin(ScrollTrigger);
|
||
|
|
|
||
|
|
interface ScrollRevealOptions {
|
||
|
|
y?: number;
|
||
|
|
x?: number;
|
||
|
|
duration?: number;
|
||
|
|
delay?: number;
|
||
|
|
stagger?: number;
|
||
|
|
start?: string;
|
||
|
|
ease?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useScrollReveal<T extends HTMLElement>(
|
||
|
|
options: ScrollRevealOptions = {}
|
||
|
|
) {
|
||
|
|
const ref = useRef<T>(null);
|
||
|
|
|
||
|
|
useLayoutEffect(() => {
|
||
|
|
const el = ref.current;
|
||
|
|
if (!el) return;
|
||
|
|
|
||
|
|
const {
|
||
|
|
y = 40,
|
||
|
|
x = 0,
|
||
|
|
duration = 0.8,
|
||
|
|
delay = 0,
|
||
|
|
stagger = 0.1,
|
||
|
|
start = "top 85%",
|
||
|
|
ease = "power3.out",
|
||
|
|
} = options;
|
||
|
|
|
||
|
|
const children = el.children.length > 0 ? el.children : [el];
|
||
|
|
|
||
|
|
gsap.set(children, { opacity: 0, y, x });
|
||
|
|
|
||
|
|
const tween = gsap.to(children, {
|
||
|
|
opacity: 1,
|
||
|
|
y: 0,
|
||
|
|
x: 0,
|
||
|
|
duration,
|
||
|
|
delay,
|
||
|
|
stagger,
|
||
|
|
ease,
|
||
|
|
scrollTrigger: {
|
||
|
|
trigger: el,
|
||
|
|
start,
|
||
|
|
toggleActions: "play none none none",
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
return () => {
|
||
|
|
tween.kill();
|
||
|
|
ScrollTrigger.getAll().forEach((st) => {
|
||
|
|
if (st.trigger === el) st.kill();
|
||
|
|
});
|
||
|
|
};
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return ref;
|
||
|
|
}
|