/* eslint-disable react-hooks-extra/no-direct-set-state-in-use-effect */ import type { FC } from 'react' import { useCallback, useEffect, useRef, useState } from 'react' import { cn } from '@/utils/classnames' type IndicatorButtonProps = { index: number selectedIndex: number isNextSlide: boolean autoplayDelay: number resetKey: number isPaused?: boolean onClick: () => void } const PROGRESS_MAX = 100 const DEGREES_PER_PERCENT = 3.6 export const IndicatorButton: FC = ({ index, selectedIndex, isNextSlide, autoplayDelay, resetKey, isPaused = false, onClick, }) => { const [progress, setProgress] = useState(0) const frameIdRef = useRef(undefined) const startTimeRef = useRef(0) const isActive = index === selectedIndex const shouldAnimate = !document.hidden && !isPaused useEffect(() => { if (!isNextSlide) { setProgress(0) if (frameIdRef.current) cancelAnimationFrame(frameIdRef.current) return } setProgress(0) startTimeRef.current = Date.now() const animate = () => { if (!document.hidden && !isPaused) { const elapsed = Date.now() - startTimeRef.current const newProgress = Math.min((elapsed / autoplayDelay) * PROGRESS_MAX, PROGRESS_MAX) setProgress(newProgress) if (newProgress < PROGRESS_MAX) frameIdRef.current = requestAnimationFrame(animate) } else { frameIdRef.current = requestAnimationFrame(animate) } } if (shouldAnimate) frameIdRef.current = requestAnimationFrame(animate) return () => { if (frameIdRef.current) cancelAnimationFrame(frameIdRef.current) } }, [isNextSlide, autoplayDelay, resetKey, isPaused]) const handleClick = useCallback((e: React.MouseEvent) => { e.stopPropagation() onClick() }, [onClick]) const progressDegrees = progress * DEGREES_PER_PERCENT return ( ) }