@gfazioli/mantine-text-animate
Version:
The TextAnimate component allows you to animate text with various effects.
113 lines (109 loc) • 3.24 kB
JavaScript
'use client';
;
var React = require('react');
function useRotatingText(options) {
const { values, animate = true, interval = 3e3, onCycle } = options;
const { speed = 1 } = options;
const [currentIndex, setCurrentIndex] = React.useState(0);
const [isTransitioning, setIsTransitioning] = React.useState(false);
const [isActive, setIsActive] = React.useState(animate);
const timerRef = React.useRef(null);
const fallbackTimerRef = React.useRef(null);
const onCycleRef = React.useRef(onCycle);
onCycleRef.current = onCycle;
const nextIndex = (currentIndex + 1) % values.length;
const safeSpeed = Math.max(0.1, speed || 1);
const transitionDuration = 500 / safeSpeed;
const completeTransition = React.useCallback(() => {
if (fallbackTimerRef.current) {
clearTimeout(fallbackTimerRef.current);
fallbackTimerRef.current = null;
}
setCurrentIndex((prev) => {
const next = (prev + 1) % values.length;
onCycleRef.current?.(next);
return next;
});
setIsTransitioning(false);
}, [values.length]);
React.useEffect(() => {
if (!isActive || values.length <= 1 || isTransitioning) {
return;
}
timerRef.current = setTimeout(() => {
setIsTransitioning(true);
}, interval);
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, [isActive, currentIndex, interval, values.length, isTransitioning]);
React.useEffect(() => {
if (!isTransitioning) {
return;
}
fallbackTimerRef.current = setTimeout(completeTransition, transitionDuration + 50);
return () => {
if (fallbackTimerRef.current) {
clearTimeout(fallbackTimerRef.current);
}
};
}, [isTransitioning, transitionDuration, completeTransition]);
const prevAnimateRef = React.useRef(animate);
React.useEffect(() => {
if (animate && !prevAnimateRef.current) {
setIsActive(true);
}
if (!animate && prevAnimateRef.current) {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
setIsActive(false);
setIsTransitioning(false);
}
prevAnimateRef.current = animate;
}, [animate]);
React.useEffect(() => {
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
if (fallbackTimerRef.current) {
clearTimeout(fallbackTimerRef.current);
}
};
}, []);
const onTransitionEnd = React.useCallback(() => {
completeTransition();
}, [completeTransition]);
const start = React.useCallback(() => {
setIsActive(true);
}, []);
const stop = React.useCallback(() => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
setIsActive(false);
}, []);
const reset = React.useCallback(() => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
setCurrentIndex(0);
setIsTransitioning(false);
}, []);
return {
currentIndex,
currentText: values[currentIndex] ?? "",
nextIndex,
nextText: values[nextIndex] ?? "",
isTransitioning,
onTransitionEnd,
start,
stop,
reset
};
}
exports.useRotatingText = useRotatingText;
//# sourceMappingURL=use-rotating-text.cjs.map