Untitled

 avatar
unknown
jsx
5 months ago
1.3 kB
4
Indexable
import { useEffect, useRef, useState } from "react";
import styled from "styled-components";

const ScUiButton = styled.span`
  display: inline-block;
  vertical-align: bottom;

  &:after {
    display: block;
    height: 0;
    padding-right: 0.5ch;
    overflow: hidden;
    font-style: normal;
    visibility: hidden;
    opacity: 0;
    content: attr(data-title);
    pointer-events: none;
  }
`;

const easeOutQuad = (x) => 1 - (1 - x) * (1 - x);

export default function CountUp({ children, duration = 2000 }) {
  const [count, setCount] = useState(0);
  const countTo = parseInt(children, 10);
  const frame = useRef(0);

  useEffect(() => {
    setTimeout(() => {
      const startTime = performance.now();

      const tick = (currentTime) => {
        const timeElapsed = currentTime - startTime;
        const progress = Math.min(timeElapsed / duration, 1);
        const easedProgress = easeOutQuad(progress);
        setCount(countTo * easedProgress);

        if (progress < 1) {
          frame.current = requestAnimationFrame(tick);
        }
      };

      frame.current = requestAnimationFrame(tick);
    }, 500);

    return () => cancelAnimationFrame(frame.current);
  }, [countTo, duration]);

  return <ScUiButton data-title={children}>{Math.floor(count)}</ScUiButton>;
}
Editor is loading...
Leave a Comment