coders-club / src /hooks /useScrollAnimation.ts
kumar-aditya's picture
Upload 108 files
a7b8df9 verified
import { useEffect, useRef, useState } from 'react';
import { useInView } from 'framer-motion';
interface UseScrollAnimationOptions {
threshold?: number;
rootMargin?: string;
triggerOnce?: boolean;
delay?: number;
}
export const useScrollAnimation = (options: UseScrollAnimationOptions = {}) => {
const ref = useRef(null);
const isInView = useInView(ref, {
threshold: options.threshold || 0.1,
margin: options.rootMargin || '-100px 0px',
once: options.triggerOnce !== false,
});
const [hasAnimated, setHasAnimated] = useState(false);
useEffect(() => {
if (isInView && !hasAnimated) {
if (options.delay) {
setTimeout(() => setHasAnimated(true), options.delay);
} else {
setHasAnimated(true);
}
}
}, [isInView, hasAnimated, options.delay]);
return {
ref,
inView: isInView,
hasAnimated: hasAnimated || isInView,
};
};
export const useStaggeredAnimation = (itemCount: number, delay: number = 100) => {
const [visibleItems, setVisibleItems] = useState<number[]>([]);
const { ref, inView } = useScrollAnimation();
useEffect(() => {
if (inView) {
const timeouts: NodeJS.Timeout[] = [];
for (let i = 0; i < itemCount; i++) {
const timeout = setTimeout(() => {
setVisibleItems(prev => [...prev, i]);
}, i * delay);
timeouts.push(timeout);
}
return () => {
timeouts.forEach(timeout => clearTimeout(timeout));
};
}
}, [inView, itemCount, delay]);
return {
ref,
visibleItems,
inView,
};
};
// Hook for parallax effects
export const useParallax = (speed: number = 0.5) => {
const [offset, setOffset] = useState(0);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleScroll = () => {
if (ref.current) {
const rect = ref.current.getBoundingClientRect();
const scrolled = window.pageYOffset;
const rate = scrolled * speed;
setOffset(rate);
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [speed]);
return {
ref,
offset,
};
};