Skip to content

Commit

Permalink
feat: created otp input component
Browse files Browse the repository at this point in the history
  • Loading branch information
sachdevavaibhav committed May 11, 2024
1 parent 8a9bf6c commit f217e68
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 26 deletions.
7 changes: 6 additions & 1 deletion example/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import React from 'react';
import { PaperProvider } from 'react-native-paper';
import App from '../src/App';
export default function RootLayout() {
return <App />;
return (
<PaperProvider>
<App />
</PaperProvider>
);
}
2 changes: 2 additions & 0 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
"react-dom": "18.2.0",
"react-native": "0.74.1",
"react-native-gesture-handler": "~2.16.1",
"react-native-paper": "^5.12.3",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.1",
"react-native-screens": "3.31.1",
"react-native-vector-icons": "^10.1.0",
"react-native-web": "~0.19.10"
},
"devDependencies": {
Expand Down
28 changes: 15 additions & 13 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import * as React from 'react';

import { StyleSheet, View, Text } from 'react-native';
import { multiply } from 'react-native-paper-otp-input';
import { StyleSheet, View } from 'react-native';
import { ScrollView } from 'react-native';
import { PaperOtpInput } from 'react-native-paper-otp-input';

export default function App() {
const [result, setResult] = React.useState<number | undefined>();

React.useEffect(() => {
multiply(3, 7).then(setResult);
}, []);

return (
<View style={styles.container}>
<Text>Result: {result}</Text>
<ScrollView contentContainerStyle={styles.scrollViewContainer}>
<PaperOtpInput
autoFocus={false}
onPinReady={(pin) => {
console.log('Pin is ready:', pin);
}}
maxLength={4}
/>
</ScrollView>
</View>
);
}
Expand All @@ -23,9 +26,8 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
box: {
width: 60,
height: 60,
marginVertical: 20,
scrollViewContainer: {
flexGrow: 1,
justifyContent: 'center',
},
});
10 changes: 7 additions & 3 deletions example/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"extends": "../tsconfig",
"compilerOptions": {
// Avoid expo-cli auto-generating a tsconfig
}
"compilerOptions": {},
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts"
]
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@
},
"peerDependencies": {
"react": "*",
"react-native": "*"
"react-native": "*",
"react-native-paper": "*",
"react-native-safe-area-context": "*"
},
"workspaces": [
"example"
Expand Down
121 changes: 121 additions & 0 deletions src/components/OtpInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React from 'react';
import {
View,
StyleSheet,
Pressable,
TextInput as RNTextInput,
} from 'react-native';
import { TextInput, Text } from 'react-native-paper';

type OtpInputProps = {
maxLength: number;
autoFocus?: boolean;
onPinReady?: (pin: string) => void;
};

export default function OtpInput({
maxLength,
onPinReady,
autoFocus = true,
}: OtpInputProps) {
const [isInputBoxFocused, setIsInputBoxFocused] = React.useState(autoFocus);
const [otp, setOtp] = React.useState('');
const [isPinReady, setIsPinReady] = React.useState(false);
const ref = React.useRef<RNTextInput>(null);

React.useEffect(() => {
setIsPinReady(otp.length === maxLength);
return () => {
setIsPinReady(false);
};
}, [maxLength, otp, setIsPinReady]);

React.useEffect(() => {
if (isPinReady) {
onPinReady && onPinReady(otp);
}
}, [isPinReady, onPinReady, otp]);

const boxArray = new Array(maxLength).fill(0);
const handleOnPress = () => {
setIsInputBoxFocused(true);
ref?.current?.focus();
};

const handleOnBlur = () => {
setIsInputBoxFocused(false);
};
return (
<View style={styles.container}>
<TextInput
mode="outlined"
style={styles.textInput}
theme={{
roundness: 10,
}}
value={otp}
onChangeText={setOtp}
maxLength={maxLength}
ref={ref}
onBlur={handleOnBlur}
keyboardType="numeric"
autoFocus={autoFocus}
/>
<Pressable style={styles.otpContainer} onPress={handleOnPress}>
{boxArray.map((_, index) => {
const isCurrentValue = index === otp.length;
const isLastValue = index === maxLength - 1;
const isCodeComplete = otp.length === maxLength;

const isValueFocused =
isCurrentValue || (isLastValue && isCodeComplete);
return (
<View
key={index}
style={{
...styles.otpBox,
borderColor:
isInputBoxFocused && isValueFocused ? '#6200EE' : '#F6F6F6',
}}
>
<Text style={styles.otpText}>{otp[index] || ''}</Text>
</View>
);
})}
</Pressable>
</View>
);
}

const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 0,
},
textInput: {
position: 'absolute',
opacity: 0,
},
otpContainer: {
width: '100%',
flexDirection: 'row',
justifyContent: 'space-evenly',
},
otpBox: {
backgroundColor: '#F6F6F6',
borderWidth: 2,
borderRadius: 5,
padding: 12,
maxWidth: 45,
minWidth: 45,
maxHeight: 45,
minHeight: 45,
justifyContent: 'center',
},
otpText: {
fontSize: 15,
color: 'black',
textAlign: 'center',
},
});
6 changes: 3 additions & 3 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export function multiply(a: number, b: number): Promise<number> {
return Promise.resolve(a * b);
}
import PaperOtpInput from './components/OtpInput';

export { PaperOtpInput };
74 changes: 69 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,18 @@ __metadata:
languageName: node
linkType: hard

"@callstack/react-theme-provider@npm:^3.0.9":
version: 3.0.9
resolution: "@callstack/react-theme-provider@npm:3.0.9"
dependencies:
deepmerge: ^3.2.0
hoist-non-react-statics: ^3.3.0
peerDependencies:
react: ">=16.3.0"
checksum: f888ef0b8f993d393a9d49864f75b04b5cf7259e72f290ec570fc5e314315f75c979b03b391243a72578ab55db4ffcdd4dc9dc1a2f8ec2b516cabb958971a85e
languageName: node
linkType: hard

"@commitlint/cli@npm:^17.8.1":
version: 17.8.1
resolution: "@commitlint/cli@npm:17.8.1"
Expand Down Expand Up @@ -6263,7 +6275,7 @@ __metadata:
languageName: node
linkType: hard

"color-convert@npm:^1.9.0":
"color-convert@npm:^1.9.0, color-convert@npm:^1.9.3":
version: 1.9.3
resolution: "color-convert@npm:1.9.3"
dependencies:
Expand Down Expand Up @@ -6295,7 +6307,7 @@ __metadata:
languageName: node
linkType: hard

"color-string@npm:^1.9.0":
"color-string@npm:^1.6.0, color-string@npm:^1.9.0":
version: 1.9.1
resolution: "color-string@npm:1.9.1"
dependencies:
Expand All @@ -6305,6 +6317,16 @@ __metadata:
languageName: node
linkType: hard

"color@npm:^3.1.2":
version: 3.2.1
resolution: "color@npm:3.2.1"
dependencies:
color-convert: ^1.9.3
color-string: ^1.6.0
checksum: f81220e8b774d35865c2561be921f5652117638dcda7ca4029262046e37fc2444ac7bbfdd110cf1fd9c074a4ee5eda8f85944ffbdda26186b602dd9bb05f6400
languageName: node
linkType: hard

"color@npm:^4.2.3":
version: 4.2.3
resolution: "color@npm:4.2.3"
Expand Down Expand Up @@ -7381,6 +7403,13 @@ __metadata:
languageName: node
linkType: hard

"deepmerge@npm:^3.2.0":
version: 3.3.0
resolution: "deepmerge@npm:3.3.0"
checksum: 4322195389e0170a0443c07b36add19b90249802c4b47b96265fdc5f5d8beddf491d5e50cbc5bfd65f85ccf76598173083863c202f5463b3b667aca8be75d5ac
languageName: node
linkType: hard

"deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.0":
version: 4.3.1
resolution: "deepmerge@npm:4.3.1"
Expand Down Expand Up @@ -15460,9 +15489,11 @@ __metadata:
react-dom: 18.2.0
react-native: 0.74.1
react-native-gesture-handler: ~2.16.1
react-native-paper: ^5.12.3
react-native-reanimated: ~3.10.1
react-native-safe-area-context: 4.10.1
react-native-screens: 3.31.1
react-native-vector-icons: ^10.1.0
react-native-web: ~0.19.10
languageName: unknown
linkType: soft
Expand All @@ -15487,6 +15518,8 @@ __metadata:
react: 18.2.0
react-native: 0.74.1
react-native-builder-bob: ^0.20.0
react-native-paper: ^5.12.3
react-native-safe-area-context: ^4.10.1
release-it: ^15.0.0
typescript: ^5.2.2
peerDependencies:
Expand All @@ -15495,6 +15528,22 @@ __metadata:
languageName: unknown
linkType: soft

"react-native-paper@npm:^5.12.3":
version: 5.12.3
resolution: "react-native-paper@npm:5.12.3"
dependencies:
"@callstack/react-theme-provider": ^3.0.9
color: ^3.1.2
use-latest-callback: ^0.1.5
peerDependencies:
react: "*"
react-native: "*"
react-native-safe-area-context: "*"
react-native-vector-icons: "*"
checksum: 927a8948d220fb59cb4dae2f12f3b4dc2173b9cd42e38dc74a0f25584a69978555a260c140db973f8401f7fef394dee3ec42c90b6134deeb3aa462291fd0ce5f
languageName: node
linkType: hard

"react-native-reanimated@npm:~3.10.1":
version: 3.10.1
resolution: "react-native-reanimated@npm:3.10.1"
Expand All @@ -15515,7 +15564,7 @@ __metadata:
languageName: node
linkType: hard

"react-native-safe-area-context@npm:4.10.1":
"react-native-safe-area-context@npm:4.10.1, react-native-safe-area-context@npm:^4.10.1":
version: 4.10.1
resolution: "react-native-safe-area-context@npm:4.10.1"
peerDependencies:
Expand All @@ -15538,6 +15587,21 @@ __metadata:
languageName: node
linkType: hard

"react-native-vector-icons@npm:^10.1.0":
version: 10.1.0
resolution: "react-native-vector-icons@npm:10.1.0"
dependencies:
prop-types: ^15.7.2
yargs: ^16.1.1
bin:
fa-upgrade.sh: bin/fa-upgrade.sh
fa5-upgrade: bin/fa5-upgrade.sh
fa6-upgrade: bin/fa6-upgrade.sh
generate-icon: bin/generate-icon.js
checksum: c1e1d7c7ccc110e99caaed4d57324d5331dfa91817183350d2fd4df16d2302e7363da1f7a2b87011da3936b77aac3a7bf8ee11844dd8786b8b7dbc6553494866
languageName: node
linkType: hard

"react-native-web@npm:~0.19.10":
version: 0.19.11
resolution: "react-native-web@npm:0.19.11"
Expand Down Expand Up @@ -18371,7 +18435,7 @@ __metadata:
languageName: node
linkType: hard

"use-latest-callback@npm:^0.1.9":
"use-latest-callback@npm:^0.1.5, use-latest-callback@npm:^0.1.9":
version: 0.1.9
resolution: "use-latest-callback@npm:0.1.9"
peerDependencies:
Expand Down Expand Up @@ -19215,7 +19279,7 @@ __metadata:
languageName: node
linkType: hard

"yargs@npm:^16.2.0":
"yargs@npm:^16.1.1, yargs@npm:^16.2.0":
version: 16.2.0
resolution: "yargs@npm:16.2.0"
dependencies:
Expand Down

0 comments on commit f217e68

Please sign in to comment.