Browse Source

Add InputPassword

master
Loëck Vézien 7 years ago
parent
commit
166de1315c
No known key found for this signature in database GPG Key ID: CBCDCE384E853AC4
  1. 3
      package.json
  2. 118
      src/components/base/InputPassword/index.js
  3. 34
      src/components/base/InputPassword/stories.js
  4. 12
      src/icons/Eye.js
  5. 4
      static/i18n/en/password.yml
  6. 4
      yarn.lock

3
package.json

@ -95,7 +95,8 @@
"styled-components": "^3.2.5",
"styled-system": "^2.2.1",
"tippy.js": "^2.5.2",
"ws": "^5.1.1"
"ws": "^5.1.1",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@babel/core": "7.0.0-beta.42",

118
src/components/base/InputPassword/index.js

@ -0,0 +1,118 @@
// @flow
import React, { PureComponent } from 'react'
import styled from 'styled-components'
import { translate } from 'react-i18next'
import zxcvbn from 'zxcvbn'
import type { T } from 'types/common'
import debounce from 'lodash/debounce'
import noop from 'lodash/noop'
import Box from 'components/base/Box'
import Input from 'components/base/Input'
import IconEye from 'icons/Eye'
const InputRight = styled(Box).attrs({
color: 'grey',
justifyContent: 'center',
pr: 3,
})`
cursor: pointer;
`
const Strength = styled(Box).attrs({
bg: p => (p.activated ? (p.warning ? 'alertRed' : 'positiveGreen') : 'fog'),
grow: true,
})`
border-radius: 13px;
height: 4px;
`
const Warning = styled(Box).attrs({
alignItems: 'flex-end',
color: p => (p.passwordStrength <= 1 ? 'alertRed' : 'positiveGreen'),
ff: 'Open Sans|SemiBold',
fontSize: 3,
})``
const getPasswordStrength = (v: string) => zxcvbn(v).score
type State = {
inputType: 'text' | 'password',
passwordStrength: number,
}
type Props = {
maxLength: number,
onChange: Function,
t: T,
value: string,
}
class InputPassword extends PureComponent<Props, State> {
static defaultProps = {
onChange: noop,
value: '',
maxLength: 20,
}
state = {
passwordStrength: getPasswordStrength(this.props.value),
inputType: 'password',
}
toggleInputType = () =>
this.setState(prev => ({
inputType: prev.inputType === 'text' ? 'password' : 'text',
}))
debouncePasswordStrength = debounce(
v =>
this.setState({
passwordStrength: getPasswordStrength(v),
}),
150,
)
handleChange = (v: string) => {
const { onChange } = this.props
onChange(v)
this.debouncePasswordStrength(v)
}
render() {
const { t, maxLength } = this.props
const { passwordStrength, inputType } = this.state
return (
<Box flow={1}>
<Input
{...this.props}
type={inputType}
maxLength={maxLength}
onChange={this.handleChange}
renderRight={
<InputRight onClick={this.toggleInputType}>
<IconEye size={16} />
</InputRight>
}
/>
<Box flow={1} horizontal>
{[1, 2, 3, 4].map(v => (
<Strength key={v} warning={passwordStrength <= 1} activated={passwordStrength >= v} />
))}
</Box>
{passwordStrength > 0 && (
<Warning passwordStrength={passwordStrength}>
{t(`password:warning_${passwordStrength}`)}
</Warning>
)}
</Box>
)
}
}
export default translate()(InputPassword)

34
src/components/base/InputPassword/stories.js

@ -0,0 +1,34 @@
// @flow
import React, { Component } from 'react'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import InputPassword from 'components/base/InputPassword'
const stories = storiesOf('Components', module)
class Wrapper extends Component<any, any> {
state = {
value: 'p@ssw0rd!',
}
handleChange = value => {
action('onChange')(value)
this.setState({ value })
}
render() {
const { render } = this.props
const { value } = this.state
return render({
onChange: this.handleChange,
value,
})
}
}
stories.add('InputPassword', () => (
<Wrapper render={({ value, onChange }) => <InputPassword value={value} onChange={onChange} />} />
))

12
src/icons/Eye.js

@ -0,0 +1,12 @@
// @flow
import React from 'react'
export default ({ size, ...p }: { size: number }) => (
<svg viewBox="0 0 16 16" height={size} width={size} {...p}>
<path
fill="currentColor"
d="M2.502 8.393c.335.494.731.99 1.184 1.45C4.953 11.128 6.399 11.888 8 11.888s3.047-.76 4.314-2.047A10.368 10.368 0 0 0 13.751 8a10.368 10.368 0 0 0-1.437-1.842C11.047 4.87 9.601 4.11 8 4.11s-3.047.76-4.314 2.047A10.368 10.368 0 0 0 2.249 8c.073.12.158.253.253.393zm-1.44-.641a8.35 8.35 0 0 1 .46-.748c.37-.547.809-1.094 1.313-1.606C4.302 3.907 6.028 3 8 3s3.698.907 5.165 2.398c.504.512.942 1.059 1.313 1.606.225.33.378.591.46.748a.532.532 0 0 1 0 .496 8.35 8.35 0 0 1-.46.748 11.477 11.477 0 0 1-1.313 1.606C11.698 12.093 9.972 13 8 13s-3.698-.907-5.165-2.398a11.477 11.477 0 0 1-1.313-1.606 8.35 8.35 0 0 1-.46-.748.532.532 0 0 1 0-.496zM8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0-1a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"
/>
</svg>
)

4
static/i18n/en/password.yml

@ -0,0 +1,4 @@
warning_1: Warning 1
warning_2: Warning 2
warning_3: Warning 3
warning_4: Warning 4

4
yarn.lock

@ -13222,3 +13222,7 @@ yeoman-generator@^2.0.3:
text-table "^0.2.0"
through2 "^2.0.0"
yeoman-environment "^2.0.5"
zxcvbn@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/zxcvbn/-/zxcvbn-4.4.2.tgz#28ec17cf09743edcab056ddd8b1b06262cc73c30"

Loading…
Cancel
Save