since3-website/modules/landingPage/ui/components/scroll-statement.tsx
2026-09-25 00:45:33 +02:00

68 lines
1.3 KiB
TypeScript

"use client"
import { useRef } from "react"
import {
motion,
useReducedMotion,
useScroll,
useTransform,
type MotionValue,
} from "motion/react"
import { cn } from "@/lib/utils"
function Word({
children,
progress,
range,
}: {
children: string
progress: MotionValue<number>
range: [number, number]
}) {
const opacity = useTransform(progress, range, [0.14, 1])
return (
<motion.span style={{ opacity }} className="inline">
{children}{" "}
</motion.span>
)
}
/** A statement whose words light up one after another while scrolling. */
export function ScrollStatement({
text,
className,
}: {
text: string
className?: string
}) {
const ref = useRef<HTMLParagraphElement>(null)
const reduced = useReducedMotion()
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start 0.85", "end 0.5"],
})
const words = text.split(" ")
if (reduced) {
return (
<p ref={ref} className={className}>
{text}
</p>
)
}
return (
<p ref={ref} className={cn(className)}>
{words.map((word, index) => (
<Word
key={index}
progress={scrollYProgress}
range={[index / words.length, (index + 1) / words.length]}
>
{word}
</Word>
))}
</p>
)
}