From 321f6f2bcf59302f87bd395d5478135086d15530 Mon Sep 17 00:00:00 2001 From: Alexey Fedorov1 Date: Thu, 8 Feb 2018 15:49:59 +0300 Subject: [PATCH 1/3] Preventing paste in disabled state --- .gitignore | 1 + CHANGES.md | 4 ++++ package.json | 2 +- src/index.js | 3 ++- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e51faa6..55238c1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /umd npm-debug.log* package-lock.json +/.vscode diff --git a/CHANGES.md b/CHANGES.md index c7a2410..1e250dd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,7 @@ +## 4.0.2 / 2018-02-08 + +* Prevent paste in disabled state + ## 4.0.1 / 2018-01-26 🇦🇺 * Fix auto-fill scenarios by using data from `onChange` events [[#112](https://github.com/insin/react-maskedinput/pull/112)] diff --git a/package.json b/package.json index 635086f..aa110b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-maskedinput", - "version": "4.0.1", + "version": "4.0.2", "description": "Masked React component", "main": "lib/index.js", "module": "es/index.js", diff --git a/src/index.js b/src/index.js index 80ebb94..f45102e 100644 --- a/src/index.js +++ b/src/index.js @@ -206,11 +206,12 @@ class MaskedInput extends React.Component { _onPaste = (e) => { // console.log('onPaste', JSON.stringify(getSelection(this.input)), e.clipboardData.getData('Text'), e.target.value) + const {disabled} = this.props e.preventDefault() this._updateMaskSelection() // getData value needed for IE also works in FF & Chrome - if (this.mask.paste(e.clipboardData.getData('Text'))) { + if (!disabled && this.mask.paste(e.clipboardData.getData('Text'))) { e.target.value = this.mask.getValue() // Timeout needed for IE setTimeout(() => this._updateInputSelection(), 0) From 2da6e87f53aa090399cfece8ec572d3af5e8cf7e Mon Sep 17 00:00:00 2001 From: Alexey Fedorov1 Date: Thu, 19 Apr 2018 22:06:11 +0300 Subject: [PATCH 2/3] Adding on onBadInput callback support --- src/index.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index f45102e..12d46c1 100644 --- a/src/index.js +++ b/src/index.js @@ -60,7 +60,8 @@ class MaskedInput extends React.Component { mask: PropTypes.string.isRequired, formatCharacters: PropTypes.object, - placeholderChar: PropTypes.string + placeholderChar: PropTypes.string, + onBadInput: PropTypes.func, } static defaultProps = { @@ -202,6 +203,9 @@ class MaskedInput extends React.Component { this.props.onChange(e) } } + else { + this._fireBadInput() + } } _onPaste = (e) => { @@ -244,6 +248,13 @@ class MaskedInput extends React.Component { } } + _fireBadInput () { + const {onBadInput} = this.props + if (typeof onBadInput === 'function') { + onBadInput() + } + } + focus() { this.input.focus() } From cf80922344eabc6f731e90a7417e6e6d27b4511d Mon Sep 17 00:00:00 2001 From: Alexey Fedorov Date: Mon, 30 Apr 2018 16:07:36 +0300 Subject: [PATCH 3/3] Adding Readme doc and demo for onBadInput, changing base React.Component to PureComponent --- README.md | 4 ++++ demo/src/index.js | 25 ++++++++++++++++++++++--- demo/src/style.css | 5 +++++ src/index.js | 9 ++++++--- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7ed1291..46cca07 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,10 @@ A default `placeholder` will be generated from the mask's pattern, but you can p By default, the rendered ``'s `size` will be the length of the pattern, but you can pass a `size` prop to override this. +### `onBadInput` : `() => void` + +A callback which will be called any time the user inputs or pastes invalid character(s).**** + ### Other props Any other props passed in will be passed as props to the rendered ``, except for the following, which are managed by the component: diff --git a/demo/src/index.js b/demo/src/index.js index 54a38d6..f9e7ddf 100644 --- a/demo/src/index.js +++ b/demo/src/index.js @@ -1,7 +1,7 @@ import './style.css' import React from 'react' -import {render} from 'react-dom' +import {render, findDOMNode} from 'react-dom' import MaskedInput from '../../src' @@ -12,7 +12,7 @@ const PATTERNS = [ '1 1', ] -class App extends React.Component { +class App extends React.PureComponent { state = { card: '', expiry: '', @@ -43,6 +43,24 @@ class App extends React.Component { } } + _onBadInput = () => { + if (this.timerId) { + return; + } + this.inputCardNode.classList.add('is-invalid'); + this.timerId = setTimeout(() => { + delete this.timerId; + this.inputCardNode.classList.remove('is-invalid'); + }, 400); + }; + + componentWillUnmount() { + if (this.timerId) { + clearTimeout(this.timerId); + delete this.timerId; + } + }; + render() { return

@@ -51,7 +69,8 @@ class App extends React.Component {

A React component which creates a masked <input/>

- + this.inputCardNode = findDOMNode(input)} onBadInput={this._onBadInput} />

You can even externally update the card state like a standard input element:

diff --git a/demo/src/style.css b/demo/src/style.css index 0c54f0c..5e6dc8a 100644 --- a/demo/src/style.css +++ b/demo/src/style.css @@ -39,3 +39,8 @@ input { footer { text-align: center; } +.is-invalid { + outline-color: #efa2a9; + -webkit-transition: outline-color 0.2s; + transition: outline-color 0.2s; +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index 12d46c1..4cbef01 100644 --- a/src/index.js +++ b/src/index.js @@ -55,12 +55,15 @@ function setSelection(el, selection) { catch (e) { /* not focused or not visible */ } } -class MaskedInput extends React.Component { +class MaskedInput extends React.PureComponent { static propTypes = { mask: PropTypes.string.isRequired, - + onChange: PropTypes.func, formatCharacters: PropTypes.object, placeholderChar: PropTypes.string, + value: PropTypes.any, + placeholder: PropTypes.string, + size: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), onBadInput: PropTypes.func, } @@ -270,7 +273,7 @@ class MaskedInput extends React.Component { let eventHandlers = this._getEventHandlers() let { size = maxLength, placeholder = this.mask.emptyValue } = this.props - let { placeholderChar, formatCharacters, ...cleanedProps } = this.props // eslint-disable-line no-unused-vars + let { placeholderChar, formatCharacters, onBadInput, ...cleanedProps } = this.props // eslint-disable-line no-unused-vars let inputProps = { ...cleanedProps, ...eventHandlers, ref, maxLength, value, size, placeholder } return }