From 87699d6b3589d2c40ffdba5d9e455e1050c7f0b4 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Fri, 15 Sep 2023 12:35:37 +0300 Subject: [PATCH 1/8] feat: added FormControl input mask --- package-lock.json | 49 ++++++++++++++++++++++- package.json | 1 + src/Form/FormControl.jsx | 4 +- src/Form/form-control.mdx | 83 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e75f814d79..1f26b4587e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "react-colorful": "^5.6.1", "react-dropzone": "^14.2.1", "react-focus-on": "^3.5.4", + "react-imask": "^7.1.3", "react-loading-skeleton": "^3.1.0", "react-popper": "^2.2.5", "react-proptype-conditional-require": "^1.0.4", @@ -2118,6 +2119,23 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.22.15.tgz", + "integrity": "sha512-SAj8oKi8UogVi6eXQXKNPu8qZ78Yzy7zawrlTr0M+IuW/g8Qe9gVDhGcF9h1S69OyACpYoLxEzpjs1M15sI5wQ==", + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3/node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + }, "node_modules/@babel/standalone": { "version": "7.21.8", "dev": true, @@ -13854,9 +13872,10 @@ } }, "node_modules/core-js-pure": { - "version": "3.30.1", + "version": "3.32.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.32.2.tgz", + "integrity": "sha512-Y2rxThOuNywTjnX/PgA5vWM6CZ9QB9sz9oGeCixV8MqXZO70z/5SHzf9EeBrEBK0PN36DnEBBu9O/aGWzKuMZQ==", "hasInstallScript": true, - "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -21035,6 +21054,17 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/imask": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/imask/-/imask-7.1.3.tgz", + "integrity": "sha512-jZCqTI5Jgukhl2ff+znBQd8BiHOTlnFYCIgggzHYDdoJsHmSSWr1BaejcYBxsjy4ZIs8Rm0HhbOxQcobcdESRQ==", + "dependencies": { + "@babel/runtime-corejs3": "^7.22.6" + }, + "engines": { + "npm": ">=4.0.0" + } + }, "node_modules/immediate": { "version": "3.0.6", "license": "MIT" @@ -31620,6 +31650,21 @@ "react": ">=16.3.0" } }, + "node_modules/react-imask": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/react-imask/-/react-imask-7.1.3.tgz", + "integrity": "sha512-anCnzdkqpDzNwe7ot76kQSvmnz4Sw7AW/QFjjLh3B87HVNv9e2oHC+1m9hQKSIui2Tqm7w68ooMgDFsCQlDMyg==", + "dependencies": { + "imask": "^7.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "npm": ">=4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, "node_modules/react-intl": { "version": "5.25.1", "license": "BSD-3-Clause", diff --git a/package.json b/package.json index a72e74374e..057ac1b2ae 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "react-colorful": "^5.6.1", "react-dropzone": "^14.2.1", "react-focus-on": "^3.5.4", + "react-imask": "^7.1.3", "react-loading-skeleton": "^3.1.0", "react-popper": "^2.2.5", "react-proptype-conditional-require": "^1.0.4", diff --git a/src/Form/FormControl.jsx b/src/Form/FormControl.jsx index 9f017387e1..b167e42e32 100644 --- a/src/Form/FormControl.jsx +++ b/src/Form/FormControl.jsx @@ -2,6 +2,7 @@ import React, { useCallback, useEffect } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import RBFormControl from 'react-bootstrap/FormControl'; +import { IMaskInput } from 'react-imask'; import { useFormGroupContext } from './FormGroupContext'; import FormControlFeedback from './FormControlFeedback'; import FormControlDecoratorGroup from './FormControlDecoratorGroup'; @@ -17,6 +18,7 @@ const FormControl = React.forwardRef(({ floatingLabel, autoResize, onChange, + withMask, ...props }, ref) => { const { @@ -71,7 +73,7 @@ const FormControl = React.forwardRef(({ className={className} > { + const [value, setValue] = useState(''); + + return ( + + } + trailingElement={} + floatingLabel="What kind of cats?" + value={value} + onAccept={ + (value, unmaskedValue, mask) => console.log(unmaskedValue) + } + onChange={(e) => setValue(e.target.value)} + /> + + ); +} +``` + +## Input card number mask + +```jsx live +() => { + const [value, setValue] = useState(''); + console.log('============ value ===========', value); + return ( + + } + trailingElement={} + floatingLabel="What kind of cats?" + value={value} + onChange={(e) => setValue(e.target.value)} + /> + + ); +} +``` + +## Input date mask + +```jsx live +() => { + const [value, setValue] = useState(''); + console.log('============ value ===========', value); + return ( + + } + trailingElement={} + floatingLabel="What kind of cats?" + value={value} + onChange={(e) => setValue(e.target.value)} + /> + + ); +} +``` + +## Input Google-style OTP mask + +```jsx live +() => { + const [value, setValue] = useState(''); + console.log('============ value ===========', value); + return ( + + } + trailingElement={} + floatingLabel="What kind of cats?" + value={value} + onChange={(e) => setValue(e.target.value)} + /> + + ); +} +``` + ## Input types From 662c5e6d07132b4b304e1c65e12b7107d2679224 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Mon, 18 Sep 2023 12:33:43 +0300 Subject: [PATCH 2/8] feat: added code examples --- src/Form/FormControl.jsx | 14 ++- src/Form/form-control.mdx | 241 +++++++++++++++++++++++++------------- 2 files changed, 169 insertions(+), 86 deletions(-) diff --git a/src/Form/FormControl.jsx b/src/Form/FormControl.jsx index b167e42e32..9131077c2d 100644 --- a/src/Form/FormControl.jsx +++ b/src/Form/FormControl.jsx @@ -9,6 +9,8 @@ import FormControlDecoratorGroup from './FormControlDecoratorGroup'; import { callAllHandlers, useHasValue } from './fieldUtils'; +const DEFAULT_MASK_VALUE = '00-00-000'; + const FormControl = React.forwardRef(({ as, className, @@ -18,7 +20,8 @@ const FormControl = React.forwardRef(({ floatingLabel, autoResize, onChange, - withMask, + hasInputMask, + mask, ...props }, ref) => { const { @@ -73,7 +76,7 @@ const FormControl = React.forwardRef(({ className={className} > @@ -124,6 +128,10 @@ FormControl.propTypes = { isInvalid: PropTypes.bool, /** Only for `as="textarea"`. Specifies whether the input can be resized according to the height of content. */ autoResize: PropTypes.bool, + /** Specifies whether to use an input mask for the input. */ + hasInputMask: PropTypes.bool, + /** Specifies the input mask to be used if `hasInputMask` is set to `true`. */ + mask: PropTypes.string, }; FormControl.defaultProps = { @@ -142,6 +150,8 @@ FormControl.defaultProps = { isValid: undefined, isInvalid: undefined, autoResize: false, + hasInputMask: false, + mask: DEFAULT_MASK_VALUE, }; export default FormControl; diff --git a/src/Form/form-control.mdx b/src/Form/form-control.mdx index 6ecdde47d5..61cac13dea 100644 --- a/src/Form/form-control.mdx +++ b/src/Form/form-control.mdx @@ -43,90 +43,6 @@ or [select attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element } ``` -## Input phone mask - -```jsx live -() => { - const [value, setValue] = useState(''); - - return ( - - } - trailingElement={} - floatingLabel="What kind of cats?" - value={value} - onAccept={ - (value, unmaskedValue, mask) => console.log(unmaskedValue) - } - onChange={(e) => setValue(e.target.value)} - /> - - ); -} -``` - -## Input card number mask - -```jsx live -() => { - const [value, setValue] = useState(''); - console.log('============ value ===========', value); - return ( - - } - trailingElement={} - floatingLabel="What kind of cats?" - value={value} - onChange={(e) => setValue(e.target.value)} - /> - - ); -} -``` - -## Input date mask - -```jsx live -() => { - const [value, setValue] = useState(''); - console.log('============ value ===========', value); - return ( - - } - trailingElement={} - floatingLabel="What kind of cats?" - value={value} - onChange={(e) => setValue(e.target.value)} - /> - - ); -} -``` - -## Input Google-style OTP mask - -```jsx live -() => { - const [value, setValue] = useState(''); - console.log('============ value ===========', value); - return ( - - } - trailingElement={} - floatingLabel="What kind of cats?" - value={value} - onChange={(e) => setValue(e.target.value)} - /> - - ); -} -``` - - ## Input types ```jsx live @@ -246,6 +162,163 @@ or [select attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element } ``` +## Input masks +Paragon uses the [react-imask](https://www.npmjs.com/package/react-imask) library, which allows you to add masks of different types for inputs. +To create your own mask, you need to pass the required mask pattern (`+{1}(000)000-00-00`) to the `mask` property.
+See [react-imask](https://imask.js.org) for documentation on available props. + +```jsx live +() => { + {/* start example state */} + const [maskType, setMaskType] = useState('phone'); + {/* end example state */} + + const inputsWithMask = { + phone: ( + <> +

Phone

+ + } + floatingLabel="What is your phone number?" + /> + + + ), + creditCard: (<> +

Credit card

+ + } + floatingLabel="What is your credit card number?" + /> + + ), + date: (<> +

Date

+ + } + floatingLabel="What is your date of birth?" + /> + + ), + securePassword: (<> +

Secure password

+ + } + floatingLabel="What is your password?" + /> + + ), + OTPpassword: (<> +

OTP password

+ + } + floatingLabel="What is your OPT password?" + /> + + ), + price: ( + <> +

Course prise

+ + } + floatingLabel="What is the price of this course?" + /> + + + ), + }; + + const [value, setValue] = useState(''); + + const handleChange = (e) => setValue(e.target.value); + + return ( + <> + {/* start example form block */} + + {/* end example form block */} + + {inputsWithMask[maskType]} + + ); +} +``` + +## Input masks with clear value +`unmask` prop allows get and set value and unmasked value easily + +```jsx live +() => { + const [value, setValue] = useState(''); + + return ( + + } + trailingElement={} + floatingLabel="What kind of cats?" + value={value} + unmask + onChange={(e) => setValue(e.target.value)} + onAccept={ + (value) => console.log(value) + } + /> + + ); +} +``` + ## Textarea autoResize `autoResize` prop allows input to be resized according to the content height. From aa37c4fa8fad77e8a31b590f72793785b069e14d Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Mon, 18 Sep 2023 13:25:49 +0300 Subject: [PATCH 3/8] feat: added tests --- src/Form/form-control.mdx | 9 +++----- src/Form/tests/FormControl.test.jsx | 34 ++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/Form/form-control.mdx b/src/Form/form-control.mdx index 61cac13dea..6b3610a0b9 100644 --- a/src/Form/form-control.mdx +++ b/src/Form/form-control.mdx @@ -298,6 +298,7 @@ See [react-imask](https://imask.js.org) for documentation on available props. ```jsx live () => { const [value, setValue] = useState(''); + console.log(value); return ( @@ -306,13 +307,9 @@ See [react-imask](https://imask.js.org) for documentation on available props. mask="+{1}(000)000-00-00" leadingElement={} trailingElement={} - floatingLabel="What kind of cats?" + floatingLabel="What is your phone number?" value={value} - unmask - onChange={(e) => setValue(e.target.value)} - onAccept={ - (value) => console.log(value) - } + onAccept={(_, mask) => setValue(mask._unmaskedValue)} /> ); diff --git a/src/Form/tests/FormControl.test.jsx b/src/Form/tests/FormControl.test.jsx index 95044c3f75..ba936b1089 100644 --- a/src/Form/tests/FormControl.test.jsx +++ b/src/Form/tests/FormControl.test.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -8,6 +8,23 @@ const ref = { current: null, }; +// eslint-disable-next-line react/prop-types +function Component({ isClearValue }) { + const onChangeFunc = jest.fn(); + const [inputValue, setInputValue] = useState(''); + + return ( + setInputValue(e.target.value)} + onAccept={isClearValue ? onChangeFunc : (value) => setInputValue(value)} + data-testid="form-control-with-mask" + /> + ); +} + describe('FormControl', () => { it('textarea changes its height with autoResize prop', async () => { const useReferenceSpy = jest.spyOn(React, 'useRef').mockReturnValue(ref); @@ -31,4 +48,19 @@ describe('FormControl', () => { expect(onChangeFunc).toHaveBeenCalledTimes(inputText.length); expect(ref.current.style.height).toEqual(`${ref.current.scrollHeight + ref.current.offsetHeight}px`); }); + + it('should apply and accept input mask for phone numbers', () => { + render(); + + const input = screen.getByTestId('form-control-with-mask'); + fireEvent.change(input, { target: { value: '1234567890' } }); + expect(input.value).toBe('+1(234)567-89-0'); + }); + it('should be cleared from the mask elements value', () => { + render(); + + const input = screen.getByTestId('form-control-with-mask'); + fireEvent.change(input, { target: { value: '1234567890' } }); + expect(input.value).toBe('1234567890'); + }); }); From 98726d289afc57499ca74d92ac0d286afe377d57 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Mon, 18 Sep 2023 16:44:21 +0300 Subject: [PATCH 4/8] refactor: refactorng after review --- src/Form/FormControl.jsx | 16 +++------ src/Form/form-control.mdx | 54 ++++++++++++++--------------- src/Form/tests/FormControl.test.jsx | 15 ++++---- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/Form/FormControl.jsx b/src/Form/FormControl.jsx index 9131077c2d..0ec3977c05 100644 --- a/src/Form/FormControl.jsx +++ b/src/Form/FormControl.jsx @@ -9,8 +9,6 @@ import FormControlDecoratorGroup from './FormControlDecoratorGroup'; import { callAllHandlers, useHasValue } from './fieldUtils'; -const DEFAULT_MASK_VALUE = '00-00-000'; - const FormControl = React.forwardRef(({ as, className, @@ -21,7 +19,6 @@ const FormControl = React.forwardRef(({ autoResize, onChange, hasInputMask, - mask, ...props }, ref) => { const { @@ -76,7 +73,7 @@ const FormControl = React.forwardRef(({ className={className} > @@ -128,10 +125,8 @@ FormControl.propTypes = { isInvalid: PropTypes.bool, /** Only for `as="textarea"`. Specifies whether the input can be resized according to the height of content. */ autoResize: PropTypes.bool, - /** Specifies whether to use an input mask for the input. */ - hasInputMask: PropTypes.bool, - /** Specifies the input mask to be used if `hasInputMask` is set to `true`. */ - mask: PropTypes.string, + /** Specifies what format to use for the input mask. */ + hasInputMask: PropTypes.string, }; FormControl.defaultProps = { @@ -150,8 +145,7 @@ FormControl.defaultProps = { isValid: undefined, isInvalid: undefined, autoResize: false, - hasInputMask: false, - mask: DEFAULT_MASK_VALUE, + hasInputMask: undefined, }; export default FormControl; diff --git a/src/Form/form-control.mdx b/src/Form/form-control.mdx index 6b3610a0b9..ec8510670b 100644 --- a/src/Form/form-control.mdx +++ b/src/Form/form-control.mdx @@ -163,8 +163,9 @@ or [select attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element ``` ## Input masks -Paragon uses the [react-imask](https://www.npmjs.com/package/react-imask) library, which allows you to add masks of different types for inputs. -To create your own mask, you need to pass the required mask pattern (`+{1}(000)000-00-00`) to the `mask` property.
+Paragon uses the [react-imask](https://www.npmjs.com/package/react-imask) library, +which allows you to add masks of different types for inputs. +To create your own mask, you need to pass the required mask pattern (`+{1}(000)000-00-00`) to the `hasInputMask` property.
See [react-imask](https://imask.js.org) for documentation on available props. ```jsx live @@ -179,8 +180,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Phone

} @@ -193,8 +193,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Credit card

} @@ -206,8 +205,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Date

} @@ -219,8 +217,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Secure password

OTP password } @@ -253,8 +249,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Course prise

{ const [value, setValue] = useState(''); - console.log(value); return ( - - } - trailingElement={} - floatingLabel="What is your phone number?" - value={value} - onAccept={(_, mask) => setValue(mask._unmaskedValue)} - /> - + <> + + } + trailingElement={} + floatingLabel="What is your phone number?" + value={value} + // depending on prop above first argument is + // `value` if `unmask=false`, + // `unmaskedValue` if `unmask=true`, + // `typedValue` if `unmask='typed'` + onAccept={(_, mask) => setValue(mask._unmaskedValue)} + /> + + Unmasked value: {JSON.stringify(value)} + ); } ``` diff --git a/src/Form/tests/FormControl.test.jsx b/src/Form/tests/FormControl.test.jsx index ba936b1089..cf9c5bd5a9 100644 --- a/src/Form/tests/FormControl.test.jsx +++ b/src/Form/tests/FormControl.test.jsx @@ -1,5 +1,7 @@ import React, { useState } from 'react'; -import { render, screen } from '@testing-library/react'; +import { + render, screen, act, +} from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import FormControl from '../FormControl'; @@ -15,8 +17,7 @@ function Component({ isClearValue }) { return ( setInputValue(e.target.value)} onAccept={isClearValue ? onChangeFunc : (value) => setInputValue(value)} @@ -52,9 +53,11 @@ describe('FormControl', () => { it('should apply and accept input mask for phone numbers', () => { render(); - const input = screen.getByTestId('form-control-with-mask'); - fireEvent.change(input, { target: { value: '1234567890' } }); - expect(input.value).toBe('+1(234)567-89-0'); + act(() => { + const input = screen.getByTestId('form-control-with-mask'); + userEvent.type(input, '1234567890'); + expect(input.value).toBe('+1(234)567-89-0'); + }); }); it('should be cleared from the mask elements value', () => { render(); From c1c1a1eebd45c07979e020cdaae1654b3ac1fa64 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Wed, 20 Sep 2023 16:48:31 +0300 Subject: [PATCH 5/8] refactor: refactoring after review --- src/Form/FormControl.jsx | 10 +++++----- src/Form/form-control.mdx | 16 ++++++++-------- src/Form/tests/FormControl.test.jsx | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Form/FormControl.jsx b/src/Form/FormControl.jsx index 0ec3977c05..54fc69fca7 100644 --- a/src/Form/FormControl.jsx +++ b/src/Form/FormControl.jsx @@ -18,7 +18,7 @@ const FormControl = React.forwardRef(({ floatingLabel, autoResize, onChange, - hasInputMask, + inputMask, ...props }, ref) => { const { @@ -73,7 +73,7 @@ const FormControl = React.forwardRef(({ className={className} > @@ -126,7 +126,7 @@ FormControl.propTypes = { /** Only for `as="textarea"`. Specifies whether the input can be resized according to the height of content. */ autoResize: PropTypes.bool, /** Specifies what format to use for the input mask. */ - hasInputMask: PropTypes.string, + inputMask: PropTypes.string, }; FormControl.defaultProps = { @@ -145,7 +145,7 @@ FormControl.defaultProps = { isValid: undefined, isInvalid: undefined, autoResize: false, - hasInputMask: undefined, + inputMask: undefined, }; export default FormControl; diff --git a/src/Form/form-control.mdx b/src/Form/form-control.mdx index ec8510670b..7fb34b3c55 100644 --- a/src/Form/form-control.mdx +++ b/src/Form/form-control.mdx @@ -165,7 +165,7 @@ or [select attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element ## Input masks Paragon uses the [react-imask](https://www.npmjs.com/package/react-imask) library, which allows you to add masks of different types for inputs. -To create your own mask, you need to pass the required mask pattern (`+{1}(000)000-00-00`) to the `hasInputMask` property.
+To create your own mask, you need to pass the required mask pattern (`+{1}(000)000-00-00`) to the `inputMask` property.
See [react-imask](https://imask.js.org) for documentation on available props. ```jsx live @@ -180,7 +180,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Phone

} @@ -193,7 +193,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Credit card

} @@ -205,7 +205,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Date

} @@ -217,7 +217,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Secure password

OTP password } @@ -249,7 +249,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Course prise

} trailingElement={} floatingLabel="What is your phone number?" diff --git a/src/Form/tests/FormControl.test.jsx b/src/Form/tests/FormControl.test.jsx index cf9c5bd5a9..41d8e4d63f 100644 --- a/src/Form/tests/FormControl.test.jsx +++ b/src/Form/tests/FormControl.test.jsx @@ -17,7 +17,7 @@ function Component({ isClearValue }) { return ( setInputValue(e.target.value)} onAccept={isClearValue ? onChangeFunc : (value) => setInputValue(value)} From e565967e2237fe454240c4529e306d078d883769 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Fri, 20 Oct 2023 12:34:30 +0300 Subject: [PATCH 6/8] refactor: refactoring after rebase --- src/Form/tests/FormControl.test.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Form/tests/FormControl.test.jsx b/src/Form/tests/FormControl.test.jsx index 41d8e4d63f..7ee86fb640 100644 --- a/src/Form/tests/FormControl.test.jsx +++ b/src/Form/tests/FormControl.test.jsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { - render, screen, act, + render, screen, act, fireEvent, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; From e06aa95344c7866579def23c2550827c777b851d Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Tue, 21 Nov 2023 16:04:39 +0200 Subject: [PATCH 7/8] refactor: refactoring after review --- src/Form/form-control.mdx | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/Form/form-control.mdx b/src/Form/form-control.mdx index 7fb34b3c55..47c4d8b7a2 100644 --- a/src/Form/form-control.mdx +++ b/src/Form/form-control.mdx @@ -165,7 +165,7 @@ or [select attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element ## Input masks Paragon uses the [react-imask](https://www.npmjs.com/package/react-imask) library, which allows you to add masks of different types for inputs. -To create your own mask, you need to pass the required mask pattern (`+{1}(000)000-00-00`) to the `inputMask` property.
+To create your own mask, you need to pass the required mask pattern (`+{1} (000) 000-0000`) to the `inputMask` property.
See [react-imask](https://imask.js.org) for documentation on available props. ```jsx live @@ -180,7 +180,7 @@ See [react-imask](https://imask.js.org) for documentation on available props.

Phone

} @@ -201,18 +201,6 @@ See [react-imask](https://imask.js.org) for documentation on available props. /> ), - date: (<> -

Date

- - } - floatingLabel="What is your date of birth?" - /> - - ), securePassword: (<>

Secure password

@@ -246,7 +234,7 @@ See [react-imask](https://imask.js.org) for documentation on available props. ), price: ( <> -

Course prise

+

Course priсe

} trailingElement={} floatingLabel="What is your phone number?" From d6dc0e331586aa37956dd6529caaefca0e8d0147 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Wed, 22 Nov 2023 13:39:20 +0200 Subject: [PATCH 8/8] refactor: package override @testing-library/dom --- package-lock.json | 29 ++++--------------- package.json | 5 +++- src/DataTable/tests/TableActions.test.jsx | 9 +++--- src/Form/tests/FormControl.test.jsx | 34 ++++++++++++----------- 4 files changed, 33 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1f26b4587e..7fbf62c4b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7441,15 +7441,15 @@ } }, "node_modules/@testing-library/dom": { - "version": "9.0.1", + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.3.tgz", + "integrity": "sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==", "dev": true, - "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", + "aria-query": "5.1.3", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", @@ -7587,28 +7587,11 @@ } } }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "8.20.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@testing-library/user-event": { "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5" }, diff --git a/package.json b/package.json index 057ac1b2ae..4a5f154e38 100644 --- a/package.json +++ b/package.json @@ -191,5 +191,8 @@ "www", "icons", "dependent-usage-analyzer" - ] + ], + "overrides": { + "@testing-library/dom": "9.3.3" + } } diff --git a/src/DataTable/tests/TableActions.test.jsx b/src/DataTable/tests/TableActions.test.jsx index 0edbc36c5f..2c87632146 100644 --- a/src/DataTable/tests/TableActions.test.jsx +++ b/src/DataTable/tests/TableActions.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import classNames from 'classnames'; import TableActions from '../TableActions'; @@ -216,9 +216,10 @@ describe('', () => { expect(overflowToggle).toBeInTheDocument(); userEvent.click(overflowToggle); - - const buttons = screen.getAllByRole('button'); - expect(buttons.length).toBeGreaterThan(1); + waitFor(() => { + const buttons = screen.getAllByRole('button'); + expect(buttons.length).toBeGreaterThan(1); + }); }); it('renders the correct alt text for the dropdown', () => { diff --git a/src/Form/tests/FormControl.test.jsx b/src/Form/tests/FormControl.test.jsx index 7ee86fb640..3388013bd6 100644 --- a/src/Form/tests/FormControl.test.jsx +++ b/src/Form/tests/FormControl.test.jsx @@ -1,7 +1,5 @@ import React, { useState } from 'react'; -import { - render, screen, act, fireEvent, -} from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import FormControl from '../FormControl'; @@ -10,24 +8,27 @@ const ref = { current: null, }; +let unmaskedInputValue; + // eslint-disable-next-line react/prop-types function Component({ isClearValue }) { - const onChangeFunc = jest.fn(); const [inputValue, setInputValue] = useState(''); + unmaskedInputValue = inputValue; return ( setInputValue(e.target.value)} - onAccept={isClearValue ? onChangeFunc : (value) => setInputValue(value)} + onChange={(e) => (!isClearValue ? setInputValue(e.target.value) : null)} + /* eslint-disable-next-line no-underscore-dangle */ + onAccept={(_, mask) => (isClearValue ? setInputValue(mask._unmaskedValue) : null)} data-testid="form-control-with-mask" /> ); } describe('FormControl', () => { - it('textarea changes its height with autoResize prop', async () => { + it('textarea changes its height with autoResize prop', () => { const useReferenceSpy = jest.spyOn(React, 'useRef').mockReturnValue(ref); const onChangeFunc = jest.fn(); const inputText = 'new text'; @@ -44,7 +45,7 @@ describe('FormControl', () => { expect(useReferenceSpy).toHaveBeenCalledTimes(1); expect(ref.current.style.height).toBe('0px'); - await userEvent.type(textarea, inputText); + userEvent.type(textarea, inputText); expect(onChangeFunc).toHaveBeenCalledTimes(inputText.length); expect(ref.current.style.height).toEqual(`${ref.current.scrollHeight + ref.current.offsetHeight}px`); @@ -53,17 +54,18 @@ describe('FormControl', () => { it('should apply and accept input mask for phone numbers', () => { render(); - act(() => { - const input = screen.getByTestId('form-control-with-mask'); - userEvent.type(input, '1234567890'); - expect(input.value).toBe('+1(234)567-89-0'); - }); + const input = screen.getByTestId('form-control-with-mask'); + userEvent.type(input, '5555555555'); + expect(input.value).toBe('+1 (555) 555-5555'); }); + it('should be cleared from the mask elements value', () => { render(); const input = screen.getByTestId('form-control-with-mask'); - fireEvent.change(input, { target: { value: '1234567890' } }); - expect(input.value).toBe('1234567890'); + userEvent.type(input, '5555555555'); + + expect(input.value).toBe('+1 (555) 555-5555'); + expect(unmaskedInputValue).toBe('15555555555'); }); });