Skip to content

Commit

Permalink
feat: add mask for pin-code (uber#3507)
Browse files Browse the repository at this point in the history
* add mask for pincode

* test(vrt): update visual snapshots for 3151449 [skip ci] (uber#3508)

Co-authored-by: UberOpenSourceBot <[email protected]>

* test(vrt): update visual snapshots for 3151449 [skip ci] (uber#3511)

Co-authored-by: UberOpenSourceBot <[email protected]>

* add e2e test

* fix typo

* test(vrt): update visual snapshots for 5ec19bc [skip ci] (uber#3525)

Co-authored-by: UberOpenSourceBot <[email protected]>

* modify styles

* fix typo

* modify docs

* fix typo

* fix typo

* modify docs

Co-authored-by: UberOpenSourceBot <[email protected]>
Co-authored-by: UberOpenSourceBot <[email protected]>
Co-authored-by: Chase Starr <[email protected]>
  • Loading branch information
4 people authored Jul 23, 2020
1 parent 5ac4dd9 commit 1a1e8d5
Show file tree
Hide file tree
Showing 16 changed files with 158 additions and 3 deletions.
5 changes: 5 additions & 0 deletions documentation-site/components/yard/config/pin-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
28 changes: 28 additions & 0 deletions documentation-site/examples/pin-code/mask.js
Original file line number Diff line number Diff line change
@@ -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 (
<React.Fragment>
<PinCode
mask
values={valuesA}
onChange={({values}) => {
setValuesA(values);
}}
/>
<br />
<PinCode
mask="*"
values={valuesB}
onChange={({values}) => {
setValuesB(values);
}}
/>
</React.Fragment>
);
};
27 changes: 27 additions & 0 deletions documentation-site/examples/pin-code/mask.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<React.Fragment>
<PinCode
mask
values={valuesA}
onChange={({values}) => {
setValuesA(values);
}}
/>
<br />
<PinCode
mask="*"
values={valuesB}
onChange={({values}) => {
setValuesB(values);
}}
/>
</React.Fragment>
);
};
8 changes: 8 additions & 0 deletions documentation-site/pages/components/pin-code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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.

<Example title="Adding mask" path="pin-code/mask.js">
<PinCodeMask />
</Example>

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='*'`.

<Example title="Disable focus management" path="pin-code/no-tab.js">
<PinCodeNoTab />
</Example>
Expand Down
26 changes: 26 additions & 0 deletions src/pin-code/__tests__/pin-code-mask.scenario.js
Original file line number Diff line number Diff line change
@@ -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 (
<div>
<StatefulPinCode
values={values}
onChange={({values}) => setValues(values)}
clearOnEscape
mask="*"
/>
<p data-testid="pinCodeValue">password:{values.join(' ')} </p>
</div>
);
}
26 changes: 26 additions & 0 deletions src/pin-code/__tests__/pin-code.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {mount, analyzeAccessibility} = require('../../../e2e/helpers');

const selectors = {
input: 'input',
pinCodeValue: 'p[data-testid="pinCodeValue"]',
};

function findActiveElement(page) {
Expand Down Expand Up @@ -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 ',
);
});
});
1 change: 1 addition & 0 deletions src/pin-code/default-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const defaultProps = {
size: SIZE.default,
manageFocus: true,
values: ['', '', '', ''],
mask: false,
};

export default defaultProps;
1 change: 1 addition & 0 deletions src/pin-code/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type PinCodeProps = Omit<InputProps, 'onChange' | 'value'> & {
overrides?: PinCodeOverrides;
values: string[];
manageFocus?: boolean;
mask?: boolean | string;
onChange: (args: {
values: string[];
event: React.FormEvent<HTMLInputElement>;
Expand Down
21 changes: 18 additions & 3 deletions src/pin-code/pin-code.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ export default class PinCode extends React.Component<PropsT, StateT> {
}
}

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,
Expand All @@ -45,7 +53,15 @@ export default class PinCode extends React.Component<PropsT, StateT> {
);
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);
Expand Down Expand Up @@ -128,8 +144,7 @@ export default class PinCode extends React.Component<PropsT, StateT> {
positive={this.props.positive}
required={this.props.required}
size={this.props.size}
type="text"
value={this.props.values[i]}
value={this.getMaskStyle(i)}
{...inputProps}
/>
);
Expand Down
1 change: 1 addition & 0 deletions src/pin-code/stateful-pin-code-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
}
}
2 changes: 2 additions & 0 deletions src/pin-code/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions vrt/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,21 @@ const config = {
},
],
},
'pin-code-mask': {
interactions: [
{
name: 'numberInput',
behavior: async page => {
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: [
{
Expand Down

0 comments on commit 1a1e8d5

Please sign in to comment.