UNPKG

react-native-animated-numbers

Version:
111 lines 3.94 kB
import React, { useCallback, useMemo, useRef } from 'react'; import { Text, View, Animated, Easing, StyleSheet } from 'react-native'; import usePrevious from '../hooks/usePrevious'; import { createNumberArrayWithComma, toAbsoluteInteger } from '../utils'; import { DEFAULT_FONT_VARIANT } from '../constants'; const AnimatedNumber = ({ animateToNumber: givenAnimateToNumber, fontStyle, animationDuration, includeComma, easing, containerStyle, fontVariant = DEFAULT_FONT_VARIANT, locale = 'en-US' }) => { const animationRef = useRef(null); const animateToNumber = toAbsoluteInteger(givenAnimateToNumber); const prevNumber = usePrevious(animateToNumber); const animateToNumberString = animateToNumber.toString(); const prevNumberString = prevNumber.toString(); const NUMBERS = useMemo(() => Array(10).fill(null).map((_, i) => i), []); const nextNumbersArr = useMemo(() => { return includeComma ? createNumberArrayWithComma(animateToNumberString, locale) : Array.from(animateToNumberString, Number); }, [animateToNumberString, includeComma, locale]); const prevNumbersArr = useMemo(() => { return includeComma ? createNumberArrayWithComma(prevNumberString, locale) : Array.from(prevNumberString, Number); }, [includeComma, prevNumberString, locale]); const [height, setHeight] = React.useState(0); const animations = useMemo(() => height === 0 ? [] : nextNumbersArr.map((__, index) => { const value = prevNumbersArr[index]; if (typeof value !== 'number') { return new Animated.Value(0); } const animationHeight = -1 * (height * value); return new Animated.Value(animationHeight); }), [nextNumbersArr, height, prevNumbersArr]); const setButtonLayout = useCallback(e => { setHeight(e.nativeEvent.layout.height); }, []); React.useEffect(() => { if (height === 0) return; if (animationRef.current) { animationRef.current.stop(); } const compositions = animations.reduce((acc, animation, index) => { const value = nextNumbersArr[index]; if (typeof value === 'number') { acc.push(Animated.timing(animation, { toValue: -1 * (height * value), duration: animationDuration || 1400, useNativeDriver: true, easing: easing || Easing.elastic(1.2) })); } return acc; }, []); animationRef.current = Animated.parallel(compositions); animationRef.current.start(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [animations, height]); return /*#__PURE__*/React.createElement(React.Fragment, null, height !== 0 && /*#__PURE__*/React.createElement(View, { style: StyleSheet.flatten([containerStyle, { flexDirection: 'row', height }]) }, animateToNumber < 0 && /*#__PURE__*/React.createElement(Text, { style: [fontStyle, { height }] }, "-"), nextNumbersArr.map((n, index) => { if (typeof n === 'string') { return /*#__PURE__*/React.createElement(Text, { key: index, style: [fontStyle, { height }] }, n); } return /*#__PURE__*/React.createElement(View, { key: index, style: { height, overflow: 'hidden' } }, /*#__PURE__*/React.createElement(Animated.View, { style: [{ transform: [{ translateY: animations[index] }] }] }, NUMBERS.map((number, i) => /*#__PURE__*/React.createElement(Text, { style: StyleSheet.flatten([fontStyle, { fontVariant, height }]), key: i }, number)))); })), /*#__PURE__*/React.createElement(View, { style: { opacity: 0, position: 'absolute' }, pointerEvents: "none" }, /*#__PURE__*/React.createElement(Text, { style: fontStyle, onLayout: setButtonLayout, numberOfLines: 1 }, animateToNumber))); }; export default AnimatedNumber; //# sourceMappingURL=AnimatedNumber.js.map