104 lines
2.8 KiB
TypeScript
104 lines
2.8 KiB
TypeScript
import { useEffect, useRef, RefObject } from 'react';
|
|
import { gsap } from 'gsap';
|
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
|
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
|
|
interface ScrollAnimationOptions {
|
|
trigger?: RefObject<HTMLElement>;
|
|
start?: string;
|
|
end?: string;
|
|
scrub?: boolean | number;
|
|
markers?: boolean;
|
|
}
|
|
|
|
export const useScrollFadeIn = (
|
|
ref: RefObject<HTMLElement>,
|
|
options: ScrollAnimationOptions = {}
|
|
) => {
|
|
useEffect(() => {
|
|
const element = ref.current;
|
|
if (!element) return;
|
|
|
|
gsap.fromTo(
|
|
element,
|
|
{ opacity: 0, y: 60 },
|
|
{
|
|
opacity: 1,
|
|
y: 0,
|
|
duration: 1,
|
|
ease: 'power3.out',
|
|
scrollTrigger: {
|
|
trigger: options.trigger?.current || element,
|
|
start: options.start || 'top 85%',
|
|
end: options.end || 'top 20%',
|
|
toggleActions: 'play none none reverse',
|
|
},
|
|
}
|
|
);
|
|
|
|
return () => {
|
|
ScrollTrigger.getAll().forEach((trigger) => trigger.kill());
|
|
};
|
|
}, [ref, options]);
|
|
};
|
|
|
|
export const useParallax = (
|
|
ref: RefObject<HTMLElement>,
|
|
speed: number = 0.5
|
|
) => {
|
|
useEffect(() => {
|
|
const element = ref.current;
|
|
if (!element) return;
|
|
|
|
gsap.to(element, {
|
|
yPercent: -50 * speed,
|
|
ease: 'none',
|
|
scrollTrigger: {
|
|
trigger: element,
|
|
start: 'top bottom',
|
|
end: 'bottom top',
|
|
scrub: true,
|
|
},
|
|
});
|
|
|
|
return () => {
|
|
ScrollTrigger.getAll().forEach((trigger) => trigger.kill());
|
|
};
|
|
}, [ref, speed]);
|
|
};
|
|
|
|
export const useStaggerReveal = (
|
|
containerRef: RefObject<HTMLElement>,
|
|
childSelector: string,
|
|
options: ScrollAnimationOptions = {}
|
|
) => {
|
|
useEffect(() => {
|
|
const container = containerRef.current;
|
|
if (!container) return;
|
|
|
|
const children = container.querySelectorAll(childSelector);
|
|
|
|
gsap.fromTo(
|
|
children,
|
|
{ opacity: 0, y: 40 },
|
|
{
|
|
opacity: 1,
|
|
y: 0,
|
|
duration: 0.8,
|
|
stagger: 0.15,
|
|
ease: 'power2.out',
|
|
scrollTrigger: {
|
|
trigger: container,
|
|
start: options.start || 'top 80%',
|
|
toggleActions: 'play none none reverse',
|
|
},
|
|
}
|
|
);
|
|
|
|
return () => {
|
|
ScrollTrigger.getAll().forEach((trigger) => trigger.kill());
|
|
};
|
|
}, [containerRef, childSelector, options]);
|
|
};
|