react-pin-input
Version:
React component for PIN like input
134 lines (118 loc) • 3.18 kB
JSX
import React, { Component } from 'react';
import PropTypes from 'prop-types';
const styles = {
input: {
padding: 0,
margin: '0 2px',
textAlign: 'center',
border: '1px solid',
background: 'transparent',
width: '50px',
height: '50px',
},
inputFocus: {
outline: 'none',
boxShadow: 'none',
},
};
/**
*/
class PinItem extends Component {
constructor(props) {
super(props);
this.state = {
value: '',
focus: false,
};
this.onChange = this.onChange.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
}
onKeyDown(e) {
if (e.keyCode === 8 && (!this.state.value || !this.state.value.length)) {
this.props.onBackspace();
}
}
clear() {
this.setState({
value: ''
});
}
onChange(e) {
const value = this.validate(e.target.value);
if (this.state.value === value) return;
if (value.length < 2) {
this.setState({value});
// timeout is to make sure that clearing happens after value is set
// this is done beacause the setState callback was not triggering in react@15.2.4
setTimeout(() => {
this.props.onChange(value);
}, 0);
}
}
focus() {
this
.input
.focus();
}
onFocus(e) {
e.target.select();
this.setState({ focus: true });
}
onBlur() {
this.setState({ focus: false });
}
validate(value) {
if(this.props.validate) {
return this.props.validate(value);
}
if(this.props.type === 'numeric') {
const numCode = value.charCodeAt(0);
const isInteger = numCode >= '0'.charCodeAt(0) && numCode <= '9'.charCodeAt(0);
return isInteger ? value : '';
}
return value.toUpperCase();
}
render() {
const { focus, value } = this.state;
const { type, inputMode, inputStyle, inputFocusStyle } = this.props;
const inputType = this.props.type === 'numeric' ? 'tel' : (this.props.type || 'text');
return (<input
className='pincode-input-text'
onChange={ this.onChange }
onKeyDown={ this.onKeyDown }
maxLength='1'
autoComplete='off'
type={ this.props.secret ? 'password' : inputType }
pattern={ this.props.type === 'numeric' ? '[0-9]*' : '[A-Z0-9]*' }
ref={ n => (this.input = n) }
onFocus={ this.onFocus }
onBlur={ this.onBlur }
style={ Object.assign(
{},
styles.input,
inputStyle,
focus ? Object.assign({}, styles.inputFocus, inputFocusStyle) : {},
) }
value={ value }
/>);
}
}
PinItem.propTypes = {
onChange: PropTypes.func.isRequired,
onBackspace: PropTypes.func.isRequired,
secret: PropTypes.bool,
type: PropTypes.string,
inputMode: PropTypes.string,
validate: PropTypes.func,
inputStyle: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
inputFocusStyle: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};
PinItem.defaultProps = {
secret: false,
type: 'numeric',
inputMode: undefined,
validate: undefined,
};
export default PinItem;