UNPKG

react-stagger-text

Version:

A React TS component for creating staggered text animation by word or letters, when in viewport

98 lines (93 loc) 4.21 kB
'use client'; (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react/jsx-runtime'), require('react')) : typeof define === 'function' && define.amd ? define(['react/jsx-runtime', 'react'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.StaggerText = factory(global.jsxRuntime, global.React)); })(this, (function (jsxRuntime, react) { 'use strict'; 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))) })); }; return StaggerText; }));