├── .gitignore ├── LICENSE.md ├── README.md ├── package.json ├── rollup.config.js ├── use-masked-input.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | *.tmp 4 | .DS_Store 5 | use-masked-input.cjs.js 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | LICENSE BSD-3-Clause 2 | 3 | Copyright 2019 UXtemple Ltd 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its contributors 16 | may be used to endorse or promote products derived from this software without 17 | specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # useMaskedInput 2 | 3 | A React hook to mask an input using [text-mask](https://github.com/text-mask/text-mask). 4 | 5 | This component needs React 16.8 or greater because it uses hooks. 6 | 7 | ## Installation 8 | 9 | With NPM: 10 | ``` 11 | npm install @viewstools/use-masked-input 12 | ``` 13 | 14 | With Yarn: 15 | ``` 16 | yarn add @viewstools/use-masked-input 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```js 22 | import React, { useRef } from 'react' 23 | import useMaskedInput from '@viewstools/use-masked-input' 24 | 25 | let PhoneInput = props => { 26 | let input = useRef(null) 27 | 28 | let onChange = useMaskedInput({ 29 | input, 30 | mask: ['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/], 31 | onChange: props.onChange, 32 | }) 33 | 34 | return 35 | } 36 | 37 | export default PhoneInput 38 | ``` 39 | 40 | `useMaskedInput` takes an object as its parameter and returns an `onChange` 41 | function you need to pass onto your input as a prop. The hook will manage the value of the input. 42 | 43 | Here are the possible configuration values: 44 | - `input`. *Required*. A reference created by `React.createRef` or `useRef` to the `input` element rendered by React. 45 | - `mask`. *Required*. An array or a function that defines how the user input is going to be masked. [See more](https://github.com/text-mask/text-mask/blob/master/componentDocumentation.md#mask). 46 | - `onChange`. A function to be called when the input changes. 47 | - `guide`. A boolean that tells the component whether to be in guide or no guide mode. [See more](https://github.com/text-mask/text-mask/blob/master/componentDocumentation.md#guide). 48 | - `keepCharPositions`. A boolean that when true, adding or deleting characters affects won't affect the position of other characters, if false, it pushes them. _Defaults to `false`_. [See more](https://github.com/text-mask/text-mask/blob/master/componentDocumentation.md#keepcharpositions). 49 | - `pipe`. A function to modify the conformed value before it is displayed on the screen. [See more](https://github.com/text-mask/text-mask/blob/master/componentDocumentation.md#pipe). 50 | - `placeholderChar`. A string representing the fillable spot in the mask. Defaults to an underscore (`_`). [See more](https://github.com/text-mask/text-mask/blob/master/componentDocumentation.md#placeholderchar). 51 | - `showMask`. A boolean that tells the component to display the mask as a placeholder in place of the regular placeholder when the input element value is empty. _Defaults to `false`_. [See more](https://github.com/text-mask/text-mask/blob/master/componentDocumentation.md#showmask). 52 | - `value`. A string with the value. Defaults to ``. 53 | ``` 54 | 55 | ## Known issues 56 | [There are some known issues on text-mask](https://github.com/text-mask/text-mask/blob/master/componentDocumentation.md#known-issues). 57 | 58 | ### Supported types 59 | Please note that Text Mask supports input type of text, tel, url, password, and search. Due to a limitation in browser API, other input types, such as email or number, cannot be supported. However, it is normal to let the user enter an email or a number in an input type text combined the appropriate input mask. 60 | 61 | License BSD-Clause-3 62 | 63 | by UXtemple 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@viewstools/use-masked-input", 3 | "description": "A React hook to mask an input using text-mask.", 4 | "version": "2.0.1", 5 | "main": "use-masked-input.cjs.js", 6 | "private": false, 7 | "license": "BSD-3-Clause", 8 | "author": "Darío Javier Cravero ", 9 | "bugs": { 10 | "url": "https://github.com/viewstools/use-masked-input/issues" 11 | }, 12 | "homepage": "https://github.com/viewstools/use-masked-input#readme", 13 | "scripts": { 14 | "prepare": "rollup --config rollup.config.js" 15 | }, 16 | "devDependencies": { 17 | "rollup": "^1.2.3" 18 | }, 19 | "peerDependencies": { 20 | "react": "^16.8.3" 21 | }, 22 | "dependencies": { 23 | "text-mask-core": "^5.1.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | input: 'use-masked-input.js', 3 | output: { 4 | file: 'use-masked-input.cjs.js', 5 | format: 'cjs', 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /use-masked-input.js: -------------------------------------------------------------------------------- 1 | import { createTextMaskInputElement } from 'text-mask-core' 2 | import { useLayoutEffect, useRef } from 'react' 3 | 4 | export default function useMaskedInput({ 5 | guide, 6 | input, 7 | keepCharPositions, 8 | mask, 9 | onChange, 10 | pipe, 11 | placeholderChar, 12 | showMask, 13 | value = '', 14 | }) { 15 | let textMask = useRef() 16 | 17 | function init() { 18 | if (!input.current) return 19 | 20 | textMask.current = createTextMaskInputElement({ 21 | guide, 22 | inputElement: input.current, 23 | keepCharPositions, 24 | mask, 25 | pipe, 26 | placeholderChar, 27 | showMask, 28 | }) 29 | 30 | textMask.current.update(value) 31 | } 32 | 33 | useLayoutEffect(init, [ 34 | guide, 35 | keepCharPositions, 36 | mask, 37 | pipe, 38 | placeholderChar, 39 | showMask, 40 | ]) 41 | 42 | useLayoutEffect(() => { 43 | if (value === input.current.value) return 44 | 45 | init() 46 | }, [value]) 47 | 48 | return event => { 49 | if (textMask.current) { 50 | textMask.current.update() 51 | } 52 | 53 | if (typeof onChange === 'function') { 54 | onChange(event) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/estree@0.0.39": 6 | version "0.0.39" 7 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" 8 | integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== 9 | 10 | "@types/node@*": 11 | version "11.9.5" 12 | resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.5.tgz#011eece9d3f839a806b63973e228f85967b79ed3" 13 | integrity sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q== 14 | 15 | acorn@^6.1.0: 16 | version "6.1.0" 17 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.0.tgz#b0a3be31752c97a0f7013c5f4903b71a05db6818" 18 | integrity sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw== 19 | 20 | rollup@^1.2.3: 21 | version "1.2.3" 22 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.2.3.tgz#450bbbd9d3c2c9a17d23c9165cab7a659f91095a" 23 | integrity sha512-hTWFogj/Z077imG9XRM1i43ffarWNToDgsqkU62eJRX4rJE213/c8+gUIf4xacfzytl0sjJZfCzzPQfZN7oIQg== 24 | dependencies: 25 | "@types/estree" "0.0.39" 26 | "@types/node" "*" 27 | acorn "^6.1.0" 28 | 29 | text-mask-core@^5.1.2: 30 | version "5.1.2" 31 | resolved "https://registry.yarnpkg.com/text-mask-core/-/text-mask-core-5.1.2.tgz#80dd5ebe04825757e46619e691407a9f8b3c1b6f" 32 | integrity sha1-gN1evgSCV1fkZhnmkUB6n4s8G28= 33 | --------------------------------------------------------------------------------