37 lines
888 B
TypeScript
37 lines
888 B
TypeScript
'use client';
|
|
|
|
import React, { useEffect, useRef, useState } from 'react';
|
|
import { useInView, animate } from 'framer-motion';
|
|
|
|
interface CounterProps {
|
|
value: number;
|
|
className?: string;
|
|
}
|
|
|
|
export const Counter = ({ value, className = '' }: CounterProps) => {
|
|
const ref = useRef(null);
|
|
const isInView = useInView(ref, { once: true, margin: "-50px" });
|
|
const [displayValue, setDisplayValue] = useState(0);
|
|
|
|
useEffect(() => {
|
|
if (isInView) {
|
|
const controls = animate(0, value, {
|
|
type: "spring",
|
|
stiffness: 50,
|
|
damping: 20,
|
|
mass: 1,
|
|
onUpdate: (latest) => {
|
|
setDisplayValue(Math.round(latest));
|
|
}
|
|
});
|
|
return () => controls.stop();
|
|
}
|
|
}, [isInView, value]);
|
|
|
|
return (
|
|
<span ref={ref} className={className}>
|
|
{displayValue < 10 ? `0${displayValue}` : displayValue}
|
|
</span>
|
|
);
|
|
};
|