everydayserieswebsite/components/ui/text-generate-effect.tsx
2025-02-16 19:49:16 +05:30

70 lines
1.7 KiB
TypeScript

"use client";
import { useEffect } from "react";
import { motion, stagger, useAnimate, useInView } from "framer-motion";
import { cn } from "@/lib/utils";
import { useRef } from "react";
export const TextGenerateEffect = ({
words,
className,
filter = true,
duration = 1,
}: {
words: string;
className?: string;
filter?: boolean;
duration?: number;
}) => {
const [scope, animate] = useAnimate();
const containerRef = useRef(null);
const isInView = useInView(containerRef, { once: true });
let wordsArray = words.split(" ");
useEffect(() => {
if (isInView) {
animate(
"span",
{
opacity: 1,
filter: filter ? "blur(0px)" : "none",
},
{
duration: duration ? duration : 1,
delay: stagger(0.2),
ease: "easeOut", // added an ease for smoother animation
}
);
}
}, [isInView, scope.current, animate, filter, duration]);
const renderWords = () => {
return (
<>
{wordsArray.map((word, idx) => {
return (
<motion.span
key={word + idx}
className="text-gray-500 opacity-0 font-normal text-3xl italic"
style={{
filter: filter ? "blur(10px)" : "none",
}}
>
{word}{" "}
</motion.span>
);
})}
</>
);
};
return (
<div className={cn("font-bold", className)} ref={containerRef}>
<div className="mt-4">
<motion.div ref={scope} className=" dark:text-white text-black text-2xl leading-snug tracking-wide">
{renderWords()}
</motion.div>
</div>
</div>
);
};