You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
3.3 KiB

3 years ago
import React from 'react'
import PropTypes from 'prop-types'
import createTextMaskInputElement
from '../../core/src/createTextMaskInputElement'
import {isNil} from '../../core/src/utilities'
export default class MaskedInput extends React.PureComponent {
constructor(...args) {
super(...args)
this.setRef = this.setRef.bind(this)
this.onBlur = this.onBlur.bind(this)
this.onChange = this.onChange.bind(this)
}
setRef(inputElement) {
this.inputElement = inputElement
}
initTextMask() {
const {props, props: {value}} = this
this.textMaskInputElement = createTextMaskInputElement({
inputElement: this.inputElement,
...props,
})
this.textMaskInputElement.update(value)
}
componentDidMount() {
this.initTextMask()
}
componentDidUpdate(prevProps) {
// Getting props affecting value
const {value, pipe, mask, guide, placeholderChar, showMask} = this.props
// Сalculate that settings was changed:
// - `pipe` converting to string, to compare function content
// - `mask` converting to string, to compare values or function content
// - `keepCharPositions` exludes, because it affect only cursor position
const settings = {guide, placeholderChar, showMask}
const isPipeChanged = typeof pipe === 'function' && typeof prevProps.pipe === 'function' ?
pipe.toString() !== prevProps.pipe.toString() :
isNil(pipe) && !isNil(prevProps.pipe) || !isNil(pipe) && isNil(prevProps.pipe)
const isMaskChanged = mask.toString() !== prevProps.mask.toString()
const isSettingChanged =
Object.keys(settings).some(prop => settings[prop] !== prevProps[prop]) ||
isMaskChanged ||
isPipeChanged
// Сalculate that value was changed
const isValueChanged = value !== this.inputElement.value
// Check value and settings to prevent duplicating update() call
if (isValueChanged || isSettingChanged) {
this.initTextMask()
}
}
render() {
const {render, ...props} = this.props
delete props.mask
delete props.guide
delete props.pipe
delete props.placeholderChar
delete props.keepCharPositions
delete props.value
delete props.onBlur
delete props.onChange
delete props.showMask
return render(this.setRef, {
onBlur: this.onBlur,
onChange: this.onChange,
defaultValue: this.props.value,
...props,
})
}
onChange(event) {
this.textMaskInputElement.update()
if (typeof this.props.onChange === 'function') {
this.props.onChange(event)
}
}
onBlur(event) {
if (typeof this.props.onBlur === 'function') {
this.props.onBlur(event)
}
}
}
MaskedInput.propTypes = {
mask: PropTypes.oneOfType([
PropTypes.array,
PropTypes.func,
PropTypes.bool,
PropTypes.shape({
mask: PropTypes.oneOfType([PropTypes.array, PropTypes.func]),
pipe: PropTypes.func,
}),
]).isRequired,
guide: PropTypes.bool,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
pipe: PropTypes.func,
placeholderChar: PropTypes.string,
keepCharPositions: PropTypes.bool,
showMask: PropTypes.bool,
}
MaskedInput.defaultProps = {
render: (ref, props) => <input ref={ref} {...props} />
}
export {default as conformToMask} from '../../core/src/conformToMask.js'