Files
Verso/libraries/ai/components/ai-elements/shimmer.tsx
T
8024fe2c58 [web] Add AI workbench to alpha users (#29417)
Co-authored-by: Alf Eaton <alf.eaton@overleaf.com>
GitOrigin-RevId: 79bb329932b1e6fcc88f648bca9cc4bee215cd41
2025-11-11 09:06:08 +00:00

65 lines
1.5 KiB
TypeScript

'use client'
import { cn } from '../../utils'
import { motion } from 'motion/react'
import {
type CSSProperties,
type ElementType,
type JSX,
memo,
useMemo,
} from 'react'
export type TextShimmerProps = {
children: string
as?: ElementType
className?: string
duration?: number
spread?: number
}
const ShimmerComponent = ({
children,
as: Component = 'p',
className,
duration = 2,
spread = 2,
}: TextShimmerProps) => {
const MotionComponent = motion.create(
Component as keyof JSX.IntrinsicElements
)
const dynamicSpread = useMemo(
() => (children?.length ?? 0) * spread,
[children, spread]
)
return (
<MotionComponent
animate={{ backgroundPosition: '0% center' }}
className={cn(
'relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent',
'[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]',
className
)}
initial={{ backgroundPosition: '100% center' }}
style={
{
'--spread': `${dynamicSpread}px`,
backgroundImage:
'var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))',
} as CSSProperties
}
transition={{
repeat: Number.POSITIVE_INFINITY,
duration,
ease: 'linear',
}}
>
{children}
</MotionComponent>
)
}
export const Shimmer = memo(ShimmerComponent)