Created
January 7, 2021 10:03
-
-
Save thhmoc67/f6e4a32abd45ec1b692b46257dd2989b to your computer and use it in GitHub Desktop.
OTP component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import './styles.scss' | |
import { elem } from '_helpers/css' | |
/** | |
* @param {length} number - Default value is 4 | |
* @param {error} string - Default value is none | |
* @param {placeholder} string - Default value is none | |
* @param {onChange} function - Default value is none | |
*/ | |
class InputOTP extends React.Component { | |
state = { | |
value: ['', '', '', '', '', '', '', '', ''], | |
currentKey: false | |
} | |
componentDidMount() { | |
elem(`otp${0}`) && elem(`otp${0}`).focus() // when component shows up, first input is focussed | |
} | |
onChange = ({ index, event }) => { | |
const key = event.key | |
const targetValue = event.target.value | |
if (targetValue === '') { | |
this.changeValue(targetValue, index) | |
} else if (targetValue < 10 && targetValue !== ' ' && !isNaN(targetValue)) { | |
this.changeValue(targetValue, index) | |
} | |
} | |
changeValue = (value, index) => { | |
let newArr = this.state.value | |
newArr[index] = value | |
this.setState({ value: newArr }, () => this.changeIndex(index, newArr)) | |
} | |
changeIndex = (index, newArr) => { | |
const currentElement = elem(`otp${index}`) | |
const nextElement = elem(`otp${index + 1}`) | |
const prvElement = elem(`otp${index - 1}`) | |
if (currentElement.value === '') { | |
} else if ( | |
currentElement.value && | |
nextElement && | |
nextElement.value === '' | |
) { | |
nextElement.focus() | |
} | |
this.blur(newArr.join('')) | |
} | |
blur = (value) => { | |
this.props.onChange(value) | |
} | |
onKeyDown = ({ index, event }) => { | |
const currentElement = elem(`otp${index}`) | |
const nextElement = elem(`otp${index + 1}`) | |
const prvElement = elem(`otp${index - 1}`) | |
const key = event.key | |
switch (key) { | |
case 'Backspace': | |
if (prvElement && currentElement.value === '') { | |
prvElement && prvElement.focus() | |
} else { | |
} | |
break | |
case 'ArrowRight': | |
this.timeout(nextElement) | |
this.setState({ currentKey: false }) | |
break | |
case 'ArrowLeft': | |
this.timeout(prvElement) | |
this.setState({ currentKey: false }) | |
break | |
case ' ': | |
break | |
case 'ArrowUp': | |
case 'ArrowDown': | |
event.preventDefault() | |
break | |
default: | |
break | |
} | |
} | |
timeout = (element) => { | |
element && | |
setTimeout(() => { | |
const x = element.value | |
element.value = '' | |
element.value = x | |
element.focus() | |
}, 1) | |
} | |
render() { | |
const { length = 4, error, placeholder } = this.props | |
let input = [] | |
for (let i = 0; i < length; i++) { | |
input.push( | |
<input | |
type="number" | |
id={`otp${i}`} | |
key={`otp${i}`} | |
className={`input ${error ? 'errorBorder' : ''}`} | |
maxLength={1} | |
onChange={(event) => this.onChange({ index: i, event })} | |
value={this.state.value[i]} | |
// onKeyUp={event => this.onKeyUp({ index: i, event })} | |
onKeyDown={(event) => this.onKeyDown({ index: i, event })} | |
placeholder={placeholder || ''} | |
// placeholder={placeholder || '⬤'} | |
autoComplete={'off'} | |
/> | |
) | |
} | |
return ( | |
<div className="InputOTP"> | |
<div className="inputs">{input}</div> | |
{error && <div className="error">{error}</div>} | |
</div> | |
) | |
} | |
} | |
export default InputOTP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @import "~scss/base/globals"; | |
.InputOTP { | |
width: 100%; | |
.error { | |
padding-left: 2px; | |
font-size: 9px; | |
color: #cc001a; | |
} | |
.input { | |
width: 20px; | |
outline: 0; | |
border: 0; | |
border: 1px solid gray; | |
padding: 8px 0px 10px 0px; | |
width: 38px; | |
background-position: bottom; | |
background-size: 50px 1px; | |
background-repeat: repeat-x; | |
background-position-x: 35px; | |
margin: 5px; | |
display: inline-block; | |
// padding: 0 0 10px 0; | |
text-align: center; | |
} | |
.input:focus { | |
outline: none; | |
border: 0; | |
background-image: null; | |
border: 1px solid black; | |
} | |
.input::-webkit-input-placeholder { | |
/* Edge */ | |
color: rgba(0, 0, 0, 0.137); | |
font-size: 10px; | |
} | |
.input:-ms-input-placeholder { | |
/* Internet Explorer 10-11 */ | |
color: rgba(0, 0, 0, 0.137); | |
font-size: 10px; | |
} | |
.input::placeholder { | |
color: rgba(0, 0, 0, 0.137); | |
font-size: 10px; | |
line-height: normal; | |
} | |
input[type='number']::-webkit-outer-spin-button, | |
input[type='number']::-webkit-inner-spin-button { | |
-webkit-appearance: none; | |
margin: 0; | |
} | |
input[type='number'] { | |
-moz-appearance: textfield; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment