57 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			57 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import React, { useCallback, useState } from 'react';
 | |
| import ShortNumber from './short_number';
 | |
| import { TransitionMotion, spring } from 'react-motion';
 | |
| import { reduceMotion } from '../initial_state';
 | |
| 
 | |
| const obfuscatedCount = (count: number) => {
 | |
|   if (count < 0) {
 | |
|     return 0;
 | |
|   } else if (count <= 1) {
 | |
|     return count;
 | |
|   } else {
 | |
|     return '1+';
 | |
|   }
 | |
| };
 | |
| 
 | |
| type Props = {
 | |
|   value: number;
 | |
|   obfuscate?: boolean;
 | |
| }
 | |
| export const AnimatedNumber: React.FC<Props> = ({
 | |
|   value,
 | |
|   obfuscate,
 | |
| })=> {
 | |
|   const [previousValue, setPreviousValue] = useState(value);
 | |
|   const [direction, setDirection] = useState<1|-1>(1);
 | |
| 
 | |
|   if (previousValue !== value) {
 | |
|     setPreviousValue(value);
 | |
|     setDirection(value > previousValue ? 1 : -1);
 | |
|   }
 | |
| 
 | |
|   const willEnter = useCallback(() => ({ y: -1 * direction }), [direction]);
 | |
|   const willLeave = useCallback(() => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }), [direction]);
 | |
| 
 | |
|   if (reduceMotion) {
 | |
|     return obfuscate ? <>{obfuscatedCount(value)}</> : <ShortNumber value={value} />;
 | |
|   }
 | |
| 
 | |
|   const styles = [{
 | |
|     key: `${value}`,
 | |
|     data: value,
 | |
|     style: { y: spring(0, { damping: 35, stiffness: 400 }) },
 | |
|   }];
 | |
| 
 | |
|   return (
 | |
|     <TransitionMotion styles={styles} willEnter={willEnter} willLeave={willLeave}>
 | |
|       {items => (
 | |
|         <span className='animated-number'>
 | |
|           {items.map(({ key, data, style }) => (
 | |
|             <span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}</span>
 | |
|           ))}
 | |
|         </span>
 | |
|       )}
 | |
|     </TransitionMotion>
 | |
|   );
 | |
| };
 |