import React, { useEffect, useRef } from 'react' import { Animated, StyleSheet, Text, TextStyle, View } from 'react-native' import { typeScale } from 'src/styles/fonts' interface Props { value: string | number typeScaleName?: keyof typeof typeScale animationDuration?: number disableAnimation?: boolean testID?: string } interface TickTextProps { textStyle: TextStyle value: string } interface TickProps { startValue: number endValue: number animationDuration: number textHeight: number textStyle: TextStyle } const numberRange = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] function TickText({ value, textStyle }: TickTextProps) { return ( {value} ) } function Tick({ startValue, endValue, textStyle, textHeight, animationDuration }: TickProps) { const animatedValue = useRef(new Animated.Value(startValue * textHeight * -1)) const transformStyle = { transform: [{ translateY: animatedValue.current }] } const duration = animationDuration ?? 1300 useEffect(() => { if (animatedValue.current) { Animated.timing(animatedValue.current, { toValue: endValue * textHeight * -1, duration, useNativeDriver: true, }).start() } }, [endValue]) return ( {numberRange.map((number, index) => { return })} ) } export default function NumberTicker({ value, typeScaleName = 'displaySmall', animationDuration = 1300, disableAnimation = false, testID, }: Props) { const textStyle = typeScale[typeScaleName] const textHeight = textStyle.lineHeight const finalValueArray = value.toString().split('') // For the startValueArray, map over each character in the finalValueArray to // replace digits with random digits, do not change non-digit characters (e.g. // decimal separator) const startValueArray = finalValueArray.map((char) => { return char.match(/\d/) ? Math.floor(Math.random() * 10).toString() : char }) return ( {finalValueArray.map((value, index) => { // If the character is not a digit, render it as a static text element if (!value.match(/\d/)) { return } const endValue = parseInt(value, 10) const startValue = parseInt(startValueArray[index], 10) return ( ) })} ) } const styles = StyleSheet.create({ container: { overflow: 'hidden', flexDirection: 'row', // This negative gap is a hack to bring the numbers closer together, // otherwise they feel unnatural and far apart gap: -2, }, tickerText: { textAlign: 'center', }, })