panel-web/packages/airo-ui/src/components/text-generate-effect.tsx
2025-08-06 00:38:29 -07:00

64 lines
1.4 KiB
TypeScript

'use client';
import { cn } from '@workspace/airo-ui/lib/utils';
import { motion, stagger, useAnimate } from 'framer-motion';
import { useEffect } from 'react';
export const TextGenerateEffect = ({
words,
className,
filter = true,
duration = 0.5,
}: {
words: string;
className?: string;
filter?: boolean;
duration?: number;
}) => {
const [scope, animate] = useAnimate();
const wordsArray = words.split(' ');
useEffect(() => {
animate(
'span',
{
opacity: 1,
filter: filter ? 'blur(0px)' : 'none',
},
{
duration: duration ? duration : 1,
delay: stagger(0.2),
},
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [scope.current]);
const renderWords = () => {
return (
<motion.div ref={scope}>
{wordsArray.map((word, idx) => {
return (
<motion.span
key={word + idx}
className='text-black opacity-0 dark:text-white'
style={{
filter: filter ? 'blur(10px)' : 'none',
}}
>
{word}{' '}
</motion.span>
);
})}
</motion.div>
);
};
return (
<div className={cn('font-bold', className)}>
<div className='mt-4'>
<div className='text-2xl leading-snug tracking-wide text-black dark:text-white'>
{renderWords()}
</div>
</div>
</div>
);
};