chore(ui): remove AnimatedTextCycle component
This commit is contained in:
parent
ea5262f7ed
commit
6fff7afabb
1 changed files with 0 additions and 112 deletions
|
|
@ -1,112 +0,0 @@
|
||||||
import * as React from "react";
|
|
||||||
import { useState, useEffect, useRef } from "react";
|
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
|
||||||
|
|
||||||
interface AnimatedTextCycleProps {
|
|
||||||
words: string[];
|
|
||||||
interval?: number;
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AnimatedTextCycle({
|
|
||||||
words,
|
|
||||||
interval = 5000,
|
|
||||||
className = "",
|
|
||||||
}: AnimatedTextCycleProps) {
|
|
||||||
const [currentIndex, setCurrentIndex] = useState(0);
|
|
||||||
const [width, setWidth] = useState("auto");
|
|
||||||
const measureRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
// Get the width of the current word
|
|
||||||
useEffect(() => {
|
|
||||||
if (measureRef.current) {
|
|
||||||
const elements = measureRef.current.children;
|
|
||||||
if (elements.length > currentIndex) {
|
|
||||||
// Add a small buffer (10px) to prevent text wrapping
|
|
||||||
const newWidth = elements[currentIndex].getBoundingClientRect().width;
|
|
||||||
setWidth(`${newWidth}px`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [currentIndex]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = setInterval(() => {
|
|
||||||
setCurrentIndex((prevIndex) => (prevIndex + 1) % words.length);
|
|
||||||
}, interval);
|
|
||||||
|
|
||||||
return () => clearInterval(timer);
|
|
||||||
}, [interval, words.length]);
|
|
||||||
|
|
||||||
// Container animation for the whole word
|
|
||||||
const containerVariants = {
|
|
||||||
hidden: {
|
|
||||||
y: -20,
|
|
||||||
opacity: 0,
|
|
||||||
filter: "blur(8px)"
|
|
||||||
},
|
|
||||||
visible: {
|
|
||||||
y: 0,
|
|
||||||
opacity: 1,
|
|
||||||
filter: "blur(0px)",
|
|
||||||
transition: {
|
|
||||||
duration: 0.4,
|
|
||||||
ease: "easeOut"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
exit: {
|
|
||||||
y: 20,
|
|
||||||
opacity: 0,
|
|
||||||
filter: "blur(8px)",
|
|
||||||
transition: {
|
|
||||||
duration: 0.3,
|
|
||||||
ease: "easeIn"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/* Hidden measurement div with all words rendered */}
|
|
||||||
<div
|
|
||||||
ref={measureRef}
|
|
||||||
aria-hidden="true"
|
|
||||||
className="absolute opacity-0 pointer-events-none"
|
|
||||||
style={{ visibility: "hidden" }}
|
|
||||||
>
|
|
||||||
{words.map((word, i) => (
|
|
||||||
<span key={i} className={`font-bold ${className}`}>
|
|
||||||
{word}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Visible animated word */}
|
|
||||||
<motion.span
|
|
||||||
className="relative inline-block"
|
|
||||||
animate={{
|
|
||||||
width,
|
|
||||||
transition: {
|
|
||||||
type: "spring",
|
|
||||||
stiffness: 150,
|
|
||||||
damping: 15,
|
|
||||||
mass: 1.2,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<AnimatePresence mode="wait" initial={false}>
|
|
||||||
<motion.span
|
|
||||||
key={currentIndex}
|
|
||||||
className={`inline-block font-bold ${className}`}
|
|
||||||
variants={containerVariants}
|
|
||||||
initial="hidden"
|
|
||||||
animate="visible"
|
|
||||||
exit="exit"
|
|
||||||
style={{ whiteSpace: "nowrap" }}
|
|
||||||
>
|
|
||||||
{words[currentIndex]}
|
|
||||||
</motion.span>
|
|
||||||
</AnimatePresence>
|
|
||||||
</motion.span>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue