Image and text animation

diwali
This commit is contained in:
2024-09-27 01:00:12 +05:30
parent 8d0a8903b4
commit 127e024374
19 changed files with 536 additions and 42 deletions

63
src/hooks/useInView.tsx Normal file
View File

@ -0,0 +1,63 @@
import { useState, useEffect, RefObject } from 'react';
interface UseInViewOptions {
threshold?: number | number[];
triggerOnce?: boolean;
}
const useInView = (
ref: RefObject<Element>,
options: UseInViewOptions = { threshold: 0.1, triggerOnce: true },
): boolean => {
const { threshold = 0.1, triggerOnce = true } = options;
const [isVisible, setIsVisible] = useState<boolean>(false);
// Validate threshold
const isValidThreshold =
typeof threshold === 'number'
? threshold >= 0 && threshold <= 1
: Array.isArray(threshold) && threshold.every((t) => t >= 0 && t <= 1);
if (!isValidThreshold) {
console.warn(
'Invalid threshold value passed to useInView. It should be between 0 and 1.',
);
}
useEffect(() => {
const element = ref.current;
if (!element) return;
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)',
);
if (prefersReducedMotion.matches) {
setIsVisible(true);
return;
}
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setIsVisible(true);
if (triggerOnce) {
observer.unobserve(entry.target);
}
}
});
},
{ threshold },
);
observer.observe(element);
return () => {
if (element) observer.unobserve(element);
};
}, [ref, threshold, triggerOnce]);
return isVisible;
};
export default useInView;