react-stagger-text
Version:
A React TS component for creating staggered text animation by word or letters, when in viewport
95 lines (90 loc) • 3.5 kB
JavaScript
'use client';
;
var jsxRuntime = require('react/jsx-runtime');
var react = require('react');
const useIO = (callback, options = {}, shouldObserve = true) => {
const targetRef = react.useRef(null);
const observerRef = react.useRef(undefined);
react.useEffect(() => {
if (shouldObserve) {
const observer = new IntersectionObserver(callback, options);
observerRef.current = observer;
const currentTarget = targetRef.current;
if (currentTarget) {
observer.observe(currentTarget);
}
return () => {
if (currentTarget) {
observer.unobserve(currentTarget);
}
};
}
}, [callback, options, shouldObserve]);
return [targetRef, observerRef.current];
};
const StaggerText = ({ startTreshold = 0.1, shouldStart = true, staggerType = 'word', startDelay = 0, staggerDuration = 0.5, staggerDelay = 0.05, staggerEasing = 'ease-in', hasInlineBlockWrapper = false, onStaggerComplete, children }) => {
const [animate, setAnimate] = react.useState(false);
//const [completedTransitions, setCompletedTransitions] = useState(0)
const callback = (entries) => {
if (entries[0].isIntersecting) {
setTimeout(() => {
setAnimate(true);
}, startDelay);
if (observer) {
observer.disconnect();
}
}
};
const options = {
threshold: startTreshold
};
const [textRef, observer] = useIO(callback, options, shouldStart);
// const handleTransitionEnd = () => {
// setCompletedTransitions((prevCount) => prevCount + 1)
// if (completedTransitions === spans.length - 1) {
// if (onStaggerComplete) {
// onStaggerComplete()
// }
// }
// }
// const handleTransitionEnd = () => {
// setCompletedTransitions((prevCount) => {
// const newCount = prevCount + 1
// if (newCount === spans.length) {
// if (onStaggerComplete) {
// onStaggerComplete()
// }
// }
// return newCount
// })
// }
const handleTransitionEnd = (i) => {
if (i === spans.length - 1 && onStaggerComplete) {
onStaggerComplete();
}
};
// function getSpans(input: string): string[] {
// return staggerType == 'word' ? input.split(' ') : [...input]
// }
function getSpans(input) {
if (staggerType === 'word') {
return input.split(' ');
}
else if (staggerType === 'letter') {
return [...input];
}
else {
// Handle other cases if needed
return [];
}
}
const spans = getSpans(children);
return (jsxRuntime.jsx("span", { ref: textRef, style: hasInlineBlockWrapper ? { display: 'inline-block' } : {}, children: spans.map((item, i) => (jsxRuntime.jsx("span", { className: "stagger__item", style: {
transitionDelay: `${i * staggerDelay}s`,
transitionProperty: 'opacity',
transitionDuration: `${staggerDuration}s`,
transitionTimingFunction: staggerEasing,
opacity: animate ? 1 : 0
}, onTransitionEnd: () => handleTransitionEnd(i), children: item + (staggerType === 'word' && i < spans.length - 1 ? ' ' : '') }, 'span-' + i))) }));
};
module.exports = StaggerText;