├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── unit_and_lint.yml ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── .npmignore ├── .vscode └── settings.json ├── CHANGELOG.md ├── Example ├── app.json ├── babel.config.js ├── index.js ├── metro.config.js ├── package.json ├── src │ └── App.tsx ├── webpack.config.js └── yarn.lock ├── LICENCE ├── README.md ├── babel.config.js ├── docs └── API.md ├── package.json ├── src ├── OtpInput.tsx ├── __tests__ │ └── helpers.test.ts ├── helpers.tsx ├── index.tsx ├── reducer.ts └── types.tsx ├── tsconfig.build.json ├── tsconfig.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | dist/ 4 | lib/ 5 | Example/ 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | es6: true, 4 | browser: true, 5 | node: true, 6 | jest: true, 7 | }, 8 | 9 | settings: { 10 | react: { 11 | version: 'detect', 12 | }, 13 | 'import/core-modules': ['react-native-otp-inputs'], 14 | }, 15 | 16 | plugins: ['simple-import-sort'], 17 | extends: ['satya164', 'plugin:react-native/all'], 18 | 19 | rules: { 20 | 'babel/no-unused-expressions': 'off', 21 | 22 | 'import/extensions': 'off', 23 | 'import/named': 'off', 24 | 'import/no-unresolved': 'error', 25 | 'jest/consistent-test-it': ['error', { fn: 'test' }], 26 | 'jest/no-truthy-falsy': 'off', 27 | 'jest/expect-expect': ['error', { assertFunctionNames: ['expect', 'element'] }], 28 | 29 | 'simple-import-sort/exports': 'error', 30 | 'simple-import-sort/imports': [ 31 | 'error', 32 | { 33 | groups: [ 34 | // Side effect imports. 35 | ['^\\u0000'], 36 | // Packages. 37 | ['^@?\\w'], 38 | ['^../'], 39 | ['^./'], 40 | ], 41 | }, 42 | ], 43 | 'prettier/prettier': [ 44 | 'error', 45 | { 46 | bracketSpacing: true, 47 | bracketSameLine: false, 48 | printWidth: 100, 49 | semi: true, 50 | singleQuote: true, 51 | tabWidth: 2, 52 | trailingComma: 'all', 53 | useTabs: false, 54 | }, 55 | ], 56 | 57 | 'react/jsx-sort-props': ['error', { shorthandFirst: true }], 58 | 'react-hooks/exhaustive-deps': 'warn', 59 | 'react-hooks/rules-of-hooks': 'error', 60 | 'react-native/no-raw-text': 'off', 61 | 'react-native/no-color-literals': 'off', 62 | 'react/no-unused-prop-types': 'off', 63 | 64 | '@typescript-eslint/array-type': ['error', { default: 'generic', readonly: 'generic' }], 65 | }, 66 | globals: { 67 | __DEV__: true, 68 | jasmine: true, 69 | }, 70 | }; 71 | -------------------------------------------------------------------------------- /.github/workflows/unit_and_lint.yml: -------------------------------------------------------------------------------- 1 | name: JS Lint & Unit 2 | on: pull_request 3 | 4 | jobs: 5 | build: 6 | runs-on: ubuntu-latest 7 | 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-node@v1 11 | with: 12 | node-version: 14.x 13 | 14 | - name: Get yarn cache directory path 15 | id: yarn-cache-dir-path 16 | run: echo "::set-output name=dir::$(yarn cache dir)" 17 | - uses: actions/cache@v2 18 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 19 | with: 20 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 21 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 22 | restore-keys: | 23 | ${{ runner.os }}-yarn- 24 | 25 | - name: Install 26 | run: yarn install 27 | 28 | - name: Lint 29 | run: | 30 | yarn lint 31 | yarn typescript 32 | - name: Tests 33 | run: yarn test 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_store 3 | coverage/ 4 | *.log 5 | 6 | # generated by bob 7 | lib/ 8 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint && yarn typescript 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | Example/ 2 | jest/ 3 | coverage/ 4 | node_modules/ 5 | *.log 6 | README.md 7 | CHANGELOG.md 8 | LICENCE 9 | __tests__ 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "javascript.format.enable": false, 3 | "typescript.format.enable": false, 4 | "typescript.tsdk": "node_modules/typescript/lib", 5 | "editor.defaultFormatter": "esbenp.prettier-vscode", 6 | "[javascript]": { 7 | "editor.defaultFormatter": "esbenp.prettier-vscode" 8 | }, 9 | "editor.codeActionsOnSave": { 10 | "source.fixAll.eslint": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v7.0.0 (31/03/2021) 4 | 5 | `@react-native-community/clipboard` has been changed to `@react-native-clipboard/clipboard`. 6 | 7 | Now installation process should be: 8 | 9 | ```bash 10 | $ yarn add react-native-otp-inputs @react-native-clipboard/clipboard 11 | ``` 12 | 13 | ### BREAKING CHANGE 14 | 15 | ## v6.0.0 (04/07/2020) 16 | 17 | ### BREAKING CHANGE 18 | 19 | - `Clipboard` has been extracted from `react-native` core as part of [Lean Core](https://github.com/facebook/react-native/issues/23313). Now this module uses [Clipboard](https://github.com/react-native-clipboard/clipboard). Additional steps needed are: 20 | 21 | ```bash 22 | $ yarn add @react-native-community/clipboard 23 | $ npx pod-install 24 | ``` 25 | 26 | For android, the package will be linked automatically on build. 27 | 28 |
29 | For React Native version 0.59 or older 30 | 31 | ### React Native <= 0.59 32 | 33 | run the following command to link the package: 34 | 35 | ``` 36 | $ react-native link @react-native-community/clipboard 37 | ``` 38 | 39 | For iOS, make sure you install the pod file. 40 | 41 | ``` 42 | cd ios && pod install && cd .. 43 | ``` 44 | 45 | or you could follow the instructions to [manually link the project](https://reactnative.dev/docs/linking-libraries-ios#manual-linking) 46 | -------------------------------------------------------------------------------- /Example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-otp-inputs-example", 3 | "displayName": "OtpInputs Example", 4 | "expo": { 5 | "name": "react-native-otp-inputs-example", 6 | "slug": "react-native-otp-inputs-example", 7 | "description": "Example app for react-native-otp-inputs", 8 | "privacy": "public", 9 | "version": "1.0.0", 10 | "platforms": [ 11 | "ios", 12 | "android", 13 | "web" 14 | ], 15 | "ios": { 16 | "supportsTablet": true 17 | }, 18 | "assetBundlePatterns": [ 19 | "**/*" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example/babel.config.js: -------------------------------------------------------------------------------- 1 | const pak = require('../package.json'); 2 | 3 | const path = require('path'); 4 | 5 | module.exports = function (api) { 6 | api.cache(true); 7 | 8 | return { 9 | presets: ['babel-preset-expo'], 10 | plugins: [ 11 | [ 12 | 'module-resolver', 13 | { 14 | extensions: ['.tsx', '.ts', '.js', '.json'], 15 | alias: { 16 | // For development, we want to alias the library to the source 17 | [pak.name]: path.join(__dirname, '..', pak.source), 18 | }, 19 | }, 20 | ], 21 | ], 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /Example/index.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-unresolved 2 | import { registerRootComponent } from 'expo'; 3 | 4 | import App from './src/App'; 5 | 6 | // registerRootComponent calls AppRegistry.registerComponent('main', () => App); 7 | // It also ensures that whether you load the app in the Expo client or in a native build, 8 | // the environment is set up appropriately 9 | registerRootComponent(App); 10 | -------------------------------------------------------------------------------- /Example/metro.config.js: -------------------------------------------------------------------------------- 1 | const blacklist = require('metro-config/src/defaults/blacklist'); 2 | const escape = require('escape-string-regexp'); 3 | 4 | const pak = require('../package.json'); 5 | 6 | const path = require('path'); 7 | 8 | const root = path.resolve(__dirname, '..'); 9 | 10 | const modules = Object.keys({ 11 | ...pak.peerDependencies, 12 | }); 13 | 14 | module.exports = { 15 | projectRoot: __dirname, 16 | watchFolders: [root], 17 | 18 | // We need to make sure that only one version is loaded for peerDependencies 19 | // So we blacklist them at the root, and alias them to the versions in example's node_modules 20 | resolver: { 21 | blacklistRE: blacklist( 22 | modules.map( 23 | (m) => 24 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`), 25 | ), 26 | ), 27 | 28 | extraNodeModules: modules.reduce((acc, name) => { 29 | acc[name] = path.join(__dirname, 'node_modules', name); 30 | return acc; 31 | }, {}), 32 | }, 33 | 34 | transformer: { 35 | getTransformOptions: async () => ({ 36 | transform: { 37 | experimentalImportSupport: false, 38 | inlineRequires: true, 39 | }, 40 | }), 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /Example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-otp-inputs-example", 3 | "description": "Example app for react-native-otp-inputs", 4 | "version": "0.0.1", 5 | "private": true, 6 | "main": "index", 7 | "scripts": { 8 | "android": "expo start --android", 9 | "ios": "expo start --ios", 10 | "web": "expo start --web", 11 | "start": "expo start", 12 | "test": "jest" 13 | }, 14 | "dependencies": { 15 | "expo": "42.0.4", 16 | "react": "17.0.2", 17 | "react-dom": "17.0.2", 18 | "react-native": "0.66.0", 19 | "react-native-web": "0.17.5" 20 | }, 21 | "devDependencies": { 22 | "@babel/core": "7.15.8", 23 | "@babel/runtime": "7.15.4", 24 | "babel-plugin-module-resolver": "4.1.0", 25 | "babel-preset-expo": "8.4.1", 26 | "escape-string-regexp": "5.0.0", 27 | "expo-cli": "4.12.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Example/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { RefObject, useRef, useState } from 'react'; 2 | import { ScrollView, StyleSheet, Button } from 'react-native'; 3 | 4 | // @ts-ignore 5 | import OtpInputs from 'react-native-otp-inputs'; 6 | 7 | const App = () => { 8 | const otpRef: RefObject = useRef(); 9 | const [s, setS] = useState(true); 10 | const [fourDigit, setFourDigit] = useState(false); 11 | 12 | const focusOTP = () => { 13 | otpRef.current.focus(); 14 | }; 15 | 16 | const resetOTP = () => { 17 | otpRef.current.reset(); 18 | }; 19 | 20 | const toggle = () => { 21 | setFourDigit((fourDigit) => !fourDigit); 22 | }; 23 | 24 | const handleChange = (code: string) => { 25 | console.log('currentCodeReturned', code, s); 26 | setS((s) => !s); 27 | }; 28 | 29 | return ( 30 | 31 |