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

36 lines
985 B
TypeScript

"use client"
import { useEffect, useRef } from "react"
import { animate, useInView } from "motion/react"
/**
* Counts from 0 to `value` once it scrolls into view.
* The server renders the final number, so it is correct without JavaScript.
*/
export function CountUp({ value, className }: { value: number; className?: string }) {
const ref = useRef<HTMLSpanElement>(null)
const inView = useInView(ref, { once: true, margin: "0px 0px -15% 0px" })
useEffect(() => {
const el = ref.current
if (!el || window.matchMedia("(prefers-reduced-motion: reduce)").matches) return
if (!inView) {
el.textContent = "0"
return
}
const controls = animate(0, value, {
duration: 1.8,
ease: [0.16, 1, 0.3, 1],
onUpdate: (latest) => {
el.textContent = String(Math.round(latest))
},
})
return () => controls.stop()
}, [inView, value])
return (
<span ref={ref} className={className}>
{value}
</span>
)
}