59 lines
		
	
	
	
		
			1.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			59 lines
		
	
	
	
		
			1.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { useEffect, useState } from 'react';
 | |
| 
 | |
| import { animated, useSpring, config } from '@react-spring/web';
 | |
| 
 | |
| import { reduceMotion } from '../initial_state';
 | |
| 
 | |
| import { ShortNumber } from './short_number';
 | |
| 
 | |
| interface Props {
 | |
|   value: number;
 | |
| }
 | |
| export const AnimatedNumber: React.FC<Props> = ({ value }) => {
 | |
|   const [previousValue, setPreviousValue] = useState(value);
 | |
|   const direction = value > previousValue ? -1 : 1;
 | |
| 
 | |
|   const [styles, api] = useSpring(
 | |
|     () => ({
 | |
|       from: { transform: `translateY(${100 * direction}%)` },
 | |
|       to: { transform: 'translateY(0%)' },
 | |
|       onRest() {
 | |
|         setPreviousValue(value);
 | |
|       },
 | |
|       config: { ...config.gentle, duration: 200 },
 | |
|       immediate: true, // This ensures that the animation is not played when the component is first rendered
 | |
|     }),
 | |
|     [value, previousValue],
 | |
|   );
 | |
| 
 | |
|   // When the value changes, start the animation
 | |
|   useEffect(() => {
 | |
|     if (value !== previousValue) {
 | |
|       void api.start({ reset: true });
 | |
|     }
 | |
|   }, [api, previousValue, value]);
 | |
| 
 | |
|   if (reduceMotion) {
 | |
|     return <ShortNumber value={value} />;
 | |
|   }
 | |
| 
 | |
|   return (
 | |
|     <span className='animated-number'>
 | |
|       <animated.span style={styles}>
 | |
|         <ShortNumber value={value} />
 | |
|       </animated.span>
 | |
|       {value !== previousValue && (
 | |
|         <animated.span
 | |
|           style={{
 | |
|             ...styles,
 | |
|             position: 'absolute',
 | |
|             top: `${-100 * direction}%`, // Adds extra space on top of translateY
 | |
|           }}
 | |
|           role='presentation'
 | |
|         >
 | |
|           <ShortNumber value={previousValue} />
 | |
|         </animated.span>
 | |
|       )}
 | |
|     </span>
 | |
|   );
 | |
| };
 |