UNPKG

phx-react

Version:

PHX REACT

59 lines 2.88 kB
import React, { useEffect, useRef } from 'react'; const easeOutExpo = (t) => (t === 1 ? 1 : 1 - Math.pow(2, -10 * t)); export const PHXMiniProgressBar = ({ percent, isCompleted, className }) => { const barRef = useRef(null); const rafRef = useRef(null); const startTimeRef = useRef(null); const startValueRef = useRef(0); useEffect(() => { if (percent == null) { if (barRef.current) { barRef.current.style.transform = 'translateX(-100%)'; } startValueRef.current = 0; return; } const target = Math.max(0, Math.min(100, Number(percent))); const duration = 1200; startValueRef.current = startValueRef.current || 0; const animate = (now) => { if (!startTimeRef.current) startTimeRef.current = now; const elapsed = now - startTimeRef.current; const progress = Math.min(elapsed / duration, 1); const eased = easeOutExpo(progress); const current = startValueRef.current + (target - startValueRef.current) * eased; if (barRef.current) { barRef.current.style.transform = `translateX(${current - 100}%)`; } if (progress < 1) { rafRef.current = requestAnimationFrame(animate); } else { if (barRef.current) { barRef.current.style.transform = `translateX(${target - 100}%)`; } startValueRef.current = target; startTimeRef.current = null; } }; rafRef.current = requestAnimationFrame(animate); return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); rafRef.current = null; }; }, [percent]); const displayPercent = percent == null ? '--' : `${Math.round(Number(percent))}%`; return (React.createElement("div", { className: 'flex justify-start items-center pr-4' }, React.createElement("div", { className: 'flex items-center gap-3' }, React.createElement("div", { className: `flex-1 w-[91px] ${className}` }, React.createElement("div", { className: 'h-2 bg-gray-200 rounded-full overflow-hidden relative' }, React.createElement("div", { ref: barRef, className: `absolute inset-y-0 left-0 ${isCompleted ? 'bg-green-600' : 'bg-gray-900'} transition-colors duration-300`, style: { transform: 'translateX(-100%)', width: '100%', } }))), React.createElement("span", { className: 'text-sm font-medium text-left text-gray-500 w-[32px] tabular-nums' }, displayPercent)))); }; export default PHXMiniProgressBar; //# sourceMappingURL=MiniProgressBar.js.map