hotschpotsh/Pottery-website/hooks/useScrollAnimations.ts

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]);
};