From 1a1e8d513f5b91e51c6ee331c6ef2d801fdce2a2 Mon Sep 17 00:00:00 2001 From: Yang Jiao <40701517+jiaoy14@users.noreply.github.com> Date: Thu, 23 Jul 2020 10:31:58 -0700 Subject: [PATCH] feat: add mask for pin-code (#3507) * add mask for pincode * test(vrt): update visual snapshots for 3151449 [skip ci] (#3508) Co-authored-by: UberOpenSourceBot * test(vrt): update visual snapshots for 3151449 [skip ci] (#3511) Co-authored-by: UberOpenSourceBot * add e2e test * fix typo * test(vrt): update visual snapshots for 5ec19bc [skip ci] (#3525) Co-authored-by: UberOpenSourceBot * modify styles * fix typo * modify docs * fix typo * fix typo * modify docs Co-authored-by: UberOpenSourceBot <33560951+UberOpenSourceBot@users.noreply.github.com> Co-authored-by: UberOpenSourceBot Co-authored-by: Chase Starr --- .../components/yard/config/pin-code.ts | 5 ++++ documentation-site/examples/pin-code/mask.js | 28 ++++++++++++++++++ documentation-site/examples/pin-code/mask.tsx | 27 +++++++++++++++++ .../pages/components/pin-code.mdx | 8 +++++ .../__tests__/pin-code-mask.scenario.js | 26 ++++++++++++++++ src/pin-code/__tests__/pin-code.e2e.js | 26 ++++++++++++++++ src/pin-code/default-props.js | 1 + src/pin-code/index.d.ts | 1 + src/pin-code/pin-code.js | 21 +++++++++++-- src/pin-code/stateful-pin-code-container.js | 1 + src/pin-code/types.js | 2 ++ .../pin-code-mask__dark-snap.png | Bin 0 -> 6256 bytes .../pin-code-mask__desktop-snap.png | Bin 0 -> 7831 bytes .../pin-code-mask__mobile-snap.png | Bin 0 -> 4997 bytes .../pin-code-mask__numberInput-snap.png | Bin 0 -> 8459 bytes vrt/config.js | 15 ++++++++++ 16 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 documentation-site/examples/pin-code/mask.js create mode 100644 documentation-site/examples/pin-code/mask.tsx create mode 100644 src/pin-code/__tests__/pin-code-mask.scenario.js create mode 100644 vrt/__image_snapshots__/pin-code-mask__dark-snap.png create mode 100644 vrt/__image_snapshots__/pin-code-mask__desktop-snap.png create mode 100644 vrt/__image_snapshots__/pin-code-mask__mobile-snap.png create mode 100644 vrt/__image_snapshots__/pin-code-mask__numberInput-snap.png diff --git a/documentation-site/components/yard/config/pin-code.ts b/documentation-site/components/yard/config/pin-code.ts index 48a50e2ce3..b7e3cb4560 100644 --- a/documentation-site/components/yard/config/pin-code.ts +++ b/documentation-site/components/yard/config/pin-code.ts @@ -47,6 +47,11 @@ const PincodeConfig: TConfig = { 'type', 'inputRef', ]), + mask: { + value: false, + type: PropTypes.Boolean, + description: 'Masks the pin code', + }, placeholder: { value: undefined, placeholder: 'x', diff --git a/documentation-site/examples/pin-code/mask.js b/documentation-site/examples/pin-code/mask.js new file mode 100644 index 0000000000..f962192f61 --- /dev/null +++ b/documentation-site/examples/pin-code/mask.js @@ -0,0 +1,28 @@ +// @flow +import React from 'react'; +import {PinCode} from 'baseui/pin-code'; + +export default () => { + const [valuesA, setValuesA] = React.useState(['', '', '', '']); + const [valuesB, setValuesB] = React.useState(['', '', '', '']); + + return ( + + { + setValuesA(values); + }} + /> +
+ { + setValuesB(values); + }} + /> +
+ ); +}; diff --git a/documentation-site/examples/pin-code/mask.tsx b/documentation-site/examples/pin-code/mask.tsx new file mode 100644 index 0000000000..aacc7b83d7 --- /dev/null +++ b/documentation-site/examples/pin-code/mask.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import {PinCode} from 'baseui/pin-code'; + +export default () => { + const [valuesA, setValuesA] = React.useState(['', '', '', '']); + const [valuesB, setValuesB] = React.useState(['', '', '', '']); + + return ( + + { + setValuesA(values); + }} + /> +
+ { + setValuesB(values); + }} + /> +
+ ); +}; diff --git a/documentation-site/pages/components/pin-code.mdx b/documentation-site/pages/components/pin-code.mdx index a2270864f7..579aadb47a 100644 --- a/documentation-site/pages/components/pin-code.mdx +++ b/documentation-site/pages/components/pin-code.mdx @@ -21,6 +21,7 @@ import PinCodeCompletion from 'examples/pin-code/completion.js'; import PinCodeOverride from 'examples/pin-code/override.js'; import PinCodeEvent from 'examples/pin-code/event.js'; import PinCodeStateful from 'examples/pin-code/stateful.js'; +import PinCodeMask from 'examples/pin-code/mask.js'; import * as PinCodeExports from 'baseui/pin-code/index.js'; import {StatefulPinCode} from 'baseui/pin-code/index.js'; @@ -89,6 +90,13 @@ You can control the size of the inputs with the `size` prop. If you donʼt like the default placeholder (`○`), you can change that too. Notice how each placeholder disappears when any of the inputs have focus. + + + + +You can add a default mask (`.`) by setting `mask=true`. +Prop `mask` also accepts `string` input as customized mask style. For example, you can get an asterisk mask by setting `mask='*'`. + diff --git a/src/pin-code/__tests__/pin-code-mask.scenario.js b/src/pin-code/__tests__/pin-code-mask.scenario.js new file mode 100644 index 0000000000..2f3af5254d --- /dev/null +++ b/src/pin-code/__tests__/pin-code-mask.scenario.js @@ -0,0 +1,26 @@ +/* +Copyright (c) 2018-2020 Uber Technologies, Inc. + +This source code is licensed under the MIT license found in the +LICENSE file in the root directory of this source tree. +*/ +// @flow + +import React from 'react'; + +import {StatefulPinCode} from '../index.js'; + +export default function Scenario() { + const [values, setValues] = React.useState(['', '', '', '']); + return ( +
+ setValues(values)} + clearOnEscape + mask="*" + /> +

password:{values.join(' ')}

+
+ ); +} diff --git a/src/pin-code/__tests__/pin-code.e2e.js b/src/pin-code/__tests__/pin-code.e2e.js index 3e99417539..6293c2f058 100644 --- a/src/pin-code/__tests__/pin-code.e2e.js +++ b/src/pin-code/__tests__/pin-code.e2e.js @@ -13,6 +13,7 @@ const {mount, analyzeAccessibility} = require('../../../e2e/helpers'); const selectors = { input: 'input', + pinCodeValue: 'p[data-testid="pinCodeValue"]', }; function findActiveElement(page) { @@ -104,3 +105,28 @@ describe('PinCode', () => { expect(await page.evaluate(el => el.value, input)).toBe('3'); }); }); + +describe('PinCodeMask', () => { + beforeEach(async () => { + await mount(page, 'pin-code-mask'); + await page.waitFor(selectors.input); + }); + + it('successfully masks', async () => { + const inputs = await page.$$(selectors.input); + await page.focus(selectors.input); + await page.keyboard.press('1'); + await page.keyboard.press('2'); + await page.keyboard.press('3'); + await page.keyboard.press('4'); + expect(await page.evaluate(el => el.value, inputs[0])).toBe('*'); + expect(await page.evaluate(el => el.value, inputs[1])).toBe('*'); + expect(await page.evaluate(el => el.value, inputs[2])).toBe('*'); + expect(await page.evaluate(el => el.value, inputs[3])).toBe('*'); + + const pinCodeValue = await page.$(selectors.pinCodeValue); + expect(await page.evaluate(el => el.textContent, pinCodeValue)).toBe( + 'password:1 2 3 4 ', + ); + }); +}); diff --git a/src/pin-code/default-props.js b/src/pin-code/default-props.js index f10e3cbb74..0a852e52a0 100644 --- a/src/pin-code/default-props.js +++ b/src/pin-code/default-props.js @@ -26,6 +26,7 @@ const defaultProps = { size: SIZE.default, manageFocus: true, values: ['', '', '', ''], + mask: false, }; export default defaultProps; diff --git a/src/pin-code/index.d.ts b/src/pin-code/index.d.ts index 5644e6b017..372356e971 100644 --- a/src/pin-code/index.d.ts +++ b/src/pin-code/index.d.ts @@ -17,6 +17,7 @@ export type PinCodeProps = Omit & { overrides?: PinCodeOverrides; values: string[]; manageFocus?: boolean; + mask?: boolean | string; onChange: (args: { values: string[]; event: React.FormEvent; diff --git a/src/pin-code/pin-code.js b/src/pin-code/pin-code.js index 3374ebff17..b3160d731e 100644 --- a/src/pin-code/pin-code.js +++ b/src/pin-code/pin-code.js @@ -34,6 +34,14 @@ export default class PinCode extends React.Component { } } + getMaskStyle(i: number) { + if (this.props.values[i] !== '' && typeof this.props.mask === 'string') { + return this.props.mask; + } else { + return this.props.values[i]; + } + } + render() { const [Root, rootProps] = getOverrides( this.props.overrides.Root, @@ -45,7 +53,15 @@ export default class PinCode extends React.Component { ); const baseOverrides = { Root: {component: StyledInputOverrideRoot}, - Input: {component: StyledInputOverrideInput}, + Input: { + component: StyledInputOverrideInput, + props: { + type: + typeof this.props.mask === 'boolean' && this.props.mask + ? 'password' + : 'text', + }, + }, }; // $FlowFixMe inputProps.overrides = mergeOverrides(baseOverrides, inputProps.overrides); @@ -128,8 +144,7 @@ export default class PinCode extends React.Component { positive={this.props.positive} required={this.props.required} size={this.props.size} - type="text" - value={this.props.values[i]} + value={this.getMaskStyle(i)} {...inputProps} /> ); diff --git a/src/pin-code/stateful-pin-code-container.js b/src/pin-code/stateful-pin-code-container.js index d9d6ea287d..db570b5d2b 100644 --- a/src/pin-code/stateful-pin-code-container.js +++ b/src/pin-code/stateful-pin-code-container.js @@ -61,6 +61,7 @@ export default class StatefulPinCodeContainer extends React.Component< manageFocus: this.props.manageFocus, values: this.state.values, onChange: this.handleChange, + mask: this.props.mask, }); } } diff --git a/src/pin-code/types.js b/src/pin-code/types.js index 1d5bc5e2ea..26315a1622 100644 --- a/src/pin-code/types.js +++ b/src/pin-code/types.js @@ -49,6 +49,8 @@ export type PropsT = { manageFocus: boolean, /** An array of values respective to each pin code input. */ values: string[], + /** Mask for pin code. Default is no mask. Set it true then mask is ".". Also accept string input as customized mask style. */ + mask: boolean | string, }; // Stateful stuff below diff --git a/vrt/__image_snapshots__/pin-code-mask__dark-snap.png b/vrt/__image_snapshots__/pin-code-mask__dark-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..d29dc8721563ba6f181ab91524ef3a83abf8ca29 GIT binary patch literal 6256 zcmeAS@N?(olHy`uVBq!ia0y~yVA;UHz^uT*1{5)VFq;WTF%}28J29*~C-ahlK|;&Z z#WAE}&fB}T*;8&awLLTqRFYWaD#E)`gjG4}_xE$_gSovw3hSt-)tPpwDP}zrIdt!h zlXCmX+19^f!e>T)Shsv{WxA1c@)>rZ$qX*KbHA{H7!S%>bU^eaBB*n6r3uBw#a-1h zvzPnN|M#u<_pN{TzcT`L-#Y+uuYwnsw{?e%9FStNCff$H(XQ zO6&NceV5WEQg&!Xs{rK|o@{ezBZr-?i zxAoVlVyEnW1C=)%on?{`ySJ(|Coiv0-G5%s_Wb*OH*>ySPk;UT_2YYcs~>-SeEjj@ zcK+bF?8G;lK{iC}Ia$Y?U0Mp(!p<+(Q~v(mUuC`?!(->povZlq;o*+z@9!caBWJ#f z;!d7l3)FGo;|!gIyL&2&ZR-Ekym|lr|EDwe?%k^Zx@kw@<6|M$qa=R6VFs$}JD$Rr zotvBc=FJX>~sl}*yR(`xN+f}&C9mI`Aw(ElYm&@eE4u-MTNz= zIhMu;&x#%1w;!(T_3?iBOBy&&I*Q{09x;?euK*{9z<1-SE?e|-6Sn+>{ z+5Gdze}8{}{O#@S$8X)bb>r?`+26l^C!5XgFX zZ2KXap8yJ(32LL%Xb_C1g3*jHS{95Jhod#ZXl*!J8;;h7qqX5^Z8%yRj@E{wwc%)O pI9eNy)`p|C;b?70ur~Y_?>Q+Z=FCo3LttPrc)I$ztaD0e0svl*)Z+jE literal 0 HcmV?d00001 diff --git a/vrt/__image_snapshots__/pin-code-mask__desktop-snap.png b/vrt/__image_snapshots__/pin-code-mask__desktop-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..fd419cda0df2dfd547a0a9c380f49a44f0634c4c GIT binary patch literal 7831 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 { + const inputSelector = 'input'; + await page.focus(inputSelector); + await page.keyboard.press('1'); + await page.keyboard.press('2'); + await page.keyboard.press('3'); + await page.keyboard.press('4'); + }, + }, + ], + }, 'progress-steps': { interactions: [ {