mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
62 lines
1.7 KiB
TypeScript
62 lines
1.7 KiB
TypeScript
import { useState, useEffect } from 'react'
|
|
|
|
type Props = {
|
|
children: any
|
|
duration?: number
|
|
triggerAnimOnScroll?: boolean
|
|
referenceElId?: string
|
|
}
|
|
|
|
const easeOutQuad = (t: number) => t * (2 - t)
|
|
const frameDuration = 1000 / 60
|
|
|
|
const CountUp = (props: Props) => {
|
|
const { children, duration = 2000, triggerAnimOnScroll = false, referenceElId = '' } = props
|
|
const countTo = parseInt(children, 10)
|
|
const [count, setCount] = useState<number>(0)
|
|
const [animTriggered, setAnimTriggered] = useState<boolean>(false)
|
|
|
|
useEffect(() => {
|
|
let frame = 0
|
|
const totalFrames = Math.round(duration / frameDuration)
|
|
|
|
async function handleScroll() {
|
|
const reference = document.getElementById(referenceElId)
|
|
if (reference && !animTriggered) {
|
|
const yOffset = reference.getBoundingClientRect().top - window.innerHeight + 20
|
|
if (yOffset <= 0) {
|
|
setAnimTriggered(true)
|
|
setCount(0)
|
|
const counter = setInterval(() => {
|
|
frame++
|
|
const progress = easeOutQuad(frame / totalFrames)
|
|
setCount(countTo * progress)
|
|
|
|
if (frame === totalFrames) clearInterval(counter)
|
|
}, frameDuration)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (triggerAnimOnScroll) {
|
|
window.addEventListener('scroll', handleScroll, { passive: true })
|
|
} else {
|
|
const counter = setInterval(() => {
|
|
frame++
|
|
const progress = easeOutQuad(frame / totalFrames)
|
|
setCount(countTo * progress)
|
|
|
|
if (frame === totalFrames) clearInterval(counter)
|
|
}, frameDuration)
|
|
}
|
|
|
|
return () => {
|
|
if (triggerAnimOnScroll) window.removeEventListener('scroll', handleScroll)
|
|
}
|
|
}, [animTriggered])
|
|
|
|
return <span>{Math.floor(count)}</span>
|
|
}
|
|
|
|
export default CountUp
|