├── .npmignore ├── tsconfig.build.json ├── babel.config.js ├── images ├── ios.gif └── android.gif ├── ExampleProject ├── assets │ ├── icon.png │ ├── favicon.png │ ├── splash.png │ └── adaptive-icon.png ├── tsconfig.json ├── .gitignore ├── babel.config.js ├── package.json ├── app.json ├── App.tsx └── metro.config.js ├── src ├── index.ts ├── constants │ └── index.ts ├── hooks │ └── usePrevious.ts ├── utils │ └── index.ts └── components │ └── AnimatedNumber.tsx ├── .prettierrc.js ├── .circleci └── config.yml ├── .eslintrc.js ├── tsconfig.json ├── LICENSE ├── package.json ├── README.md └── .gitignore /.npmignore: -------------------------------------------------------------------------------- 1 | ExampleProject 2 | images 3 | .circleci 4 | .git -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "exclude": ["ExampleProject"] 4 | } 5 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /images/ios.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyman333/react-native-animated-numbers/HEAD/images/ios.gif -------------------------------------------------------------------------------- /images/android.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyman333/react-native-animated-numbers/HEAD/images/android.gif -------------------------------------------------------------------------------- /ExampleProject/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyman333/react-native-animated-numbers/HEAD/ExampleProject/assets/icon.png -------------------------------------------------------------------------------- /ExampleProject/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyman333/react-native-animated-numbers/HEAD/ExampleProject/assets/favicon.png -------------------------------------------------------------------------------- /ExampleProject/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyman333/react-native-animated-numbers/HEAD/ExampleProject/assets/splash.png -------------------------------------------------------------------------------- /ExampleProject/assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heyman333/react-native-animated-numbers/HEAD/ExampleProject/assets/adaptive-icon.png -------------------------------------------------------------------------------- /ExampleProject/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig", 3 | "compilerOptions": { 4 | // Avoid expo-cli auto-generating a tsconfig 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/AnimatedNumber'; 2 | import AnimatedNumber from './components/AnimatedNumber'; 3 | 4 | export default AnimatedNumber; 5 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | quoteProps: "consistent", 3 | singleQuote: true, 4 | tabWidth: 2, 5 | trailingComma: "es5", 6 | useTabs: false, 7 | }; 8 | -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | import type { TextStyle } from 'react-native'; 2 | 3 | export const DEFAULT_FONT_VARIANT = [ 4 | 'tabular-nums', 5 | ] satisfies TextStyle['fontVariant']; 6 | -------------------------------------------------------------------------------- /src/hooks/usePrevious.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function usePrevious(value: number): number { 4 | const ref = React.useRef(value); 5 | 6 | React.useEffect(() => { 7 | ref.current = value; 8 | }); 9 | 10 | return ref.current; 11 | } 12 | 13 | export default usePrevious; 14 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | orbs: 3 | node: circleci/node@1.1.6 4 | jobs: 5 | build-and-lint: 6 | executor: 7 | name: node/default 8 | steps: 9 | - checkout 10 | - node/with-cache: 11 | steps: 12 | - run: yarn install 13 | - run: yarn lint 14 | workflows: 15 | build-and-test: 16 | jobs: 17 | - build-and-lint -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['@react-native', 'prettier'], 4 | rules: { 5 | 'prettier/prettier': [ 6 | 'error', 7 | { 8 | quoteProps: 'consistent', 9 | singleQuote: true, 10 | tabWidth: 2, 11 | trailingComma: 'es5', 12 | useTabs: false, 13 | }, 14 | ], 15 | 'react-native/no-inline-styles': 'off', 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /ExampleProject/.gitignore: -------------------------------------------------------------------------------- 1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # Expo 7 | .expo/ 8 | dist/ 9 | web-build/ 10 | 11 | # Native 12 | *.orig.* 13 | *.jks 14 | *.p8 15 | *.p12 16 | *.key 17 | *.mobileprovision 18 | 19 | # Metro 20 | .metro-health-check* 21 | 22 | # debug 23 | npm-debug.* 24 | yarn-debug.* 25 | yarn-error.* 26 | 27 | # macOS 28 | .DS_Store 29 | *.pem 30 | 31 | # local env files 32 | .env*.local 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | -------------------------------------------------------------------------------- /ExampleProject/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = function (api) { 5 | api.cache(true); 6 | 7 | return { 8 | presets: ['babel-preset-expo'], 9 | plugins: [ 10 | [ 11 | 'module-resolver', 12 | { 13 | extensions: ['.tsx', '.ts', '.js', '.json'], 14 | alias: { 15 | // For development, we want to alias the library to the source 16 | [pak.name]: path.join(__dirname, '..', pak.source), 17 | }, 18 | }, 19 | ], 20 | ], 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export function toAbsoluteInteger(num: number) { 2 | return Math.abs(Math.floor(num)); 3 | } 4 | 5 | export function createNumberArrayWithComma( 6 | numberString: string, 7 | locale: Intl.LocalesArgument = 'en-US' 8 | ): (number | ',')[] { 9 | // Convert the string to a number and use Intl.NumberFormat to format it 10 | const formattedString = new Intl.NumberFormat(locale).format( 11 | Number(numberString) 12 | ); 13 | 14 | // Split the formatted string into an array of numbers and commas 15 | const arr = Array.from(formattedString, (char) => 16 | char === ',' ? char : Number(char) 17 | ); 18 | 19 | return arr; 20 | } 21 | -------------------------------------------------------------------------------- /ExampleProject/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exampleproject", 3 | "version": "1.0.0", 4 | "main": "node_modules/expo/AppEntry.js", 5 | "scripts": { 6 | "start": "expo start", 7 | "android": "expo start --android", 8 | "ios": "expo start --ios", 9 | "web": "expo start --web" 10 | }, 11 | "dependencies": { 12 | "expo": "~50.0.14", 13 | "expo-status-bar": "~1.11.1", 14 | "react": "18.2.0", 15 | "react-native": "0.73.6" 16 | }, 17 | "devDependencies": { 18 | "@babel/core": "^7.20.0", 19 | "@types/react": "~18.2.45", 20 | "typescript": "^5.1.3", 21 | "babel-loader": "^8.1.0", 22 | "babel-plugin-module-resolver": "^5.0.0" 23 | }, 24 | "private": true 25 | } 26 | -------------------------------------------------------------------------------- /ExampleProject/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "ExampleProject", 4 | "slug": "ExampleProject", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "userInterfaceStyle": "light", 9 | "splash": { 10 | "image": "./assets/splash.png", 11 | "resizeMode": "contain", 12 | "backgroundColor": "#ffffff" 13 | }, 14 | "assetBundlePatterns": [ 15 | "**/*" 16 | ], 17 | "ios": { 18 | "supportsTablet": true 19 | }, 20 | "android": { 21 | "adaptiveIcon": { 22 | "foregroundImage": "./assets/adaptive-icon.png", 23 | "backgroundColor": "#ffffff" 24 | } 25 | }, 26 | "web": { 27 | "favicon": "./assets/favicon.png" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": ".", 4 | "paths": { 5 | "react-native-animated-numbers": ["./src/index"] 6 | }, 7 | "allowUnreachableCode": false, 8 | "allowUnusedLabels": false, 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "jsx": "react", 12 | "lib": ["esnext"], 13 | "outDir": "./lib", 14 | "module": "esnext", 15 | "moduleResolution": "node", 16 | "noFallthroughCasesInSwitch": true, 17 | "noImplicitReturns": true, 18 | "noImplicitUseStrict": false, 19 | "noStrictGenericChecks": false, 20 | "noUncheckedIndexedAccess": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "resolveJsonModule": true, 24 | "skipLibCheck": true, 25 | "strict": true, 26 | "target": "esnext", 27 | "verbatimModuleSyntax": true 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Yeongsu Han 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ExampleProject/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { SafeAreaView, Button, Easing } from 'react-native'; 3 | import AnimatedNumbers, { 4 | AnimatedNumberProps, 5 | } from 'react-native-animated-numbers'; 6 | 7 | const App = () => { 8 | const [animateToNumber, setAnimateToNumber] = React.useState(483); 9 | 10 | const increase = () => { 11 | setAnimateToNumber(animateToNumber + 391); 12 | }; 13 | 14 | const decrease = () => { 15 | setAnimateToNumber(animateToNumber - 311); 16 | }; 17 | 18 | return ( 19 | 22 | 28 |