playbook_ui 9.3.0.alpha.inline3 → 9.3.0.pre.alpha.password.strength.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +1 -0
  3. data/app/pb_kits/playbook/data/menu.yml +1 -0
  4. data/app/pb_kits/playbook/index.js +4 -3
  5. data/app/pb_kits/playbook/pb_badge/_badge.jsx +1 -26
  6. data/app/pb_kits/playbook/pb_date_picker/_date_picker.jsx +1 -6
  7. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.js +0 -3
  8. data/app/pb_kits/playbook/pb_flex/_flex.jsx +3 -6
  9. data/app/pb_kits/playbook/pb_passphrase/_passphrase.jsx +205 -0
  10. data/app/pb_kits/playbook/pb_passphrase/_passphrase.scss +63 -0
  11. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_common.jsx +33 -0
  12. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_default.html.erb +3 -0
  13. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_default.jsx +31 -0
  14. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_default.md +1 -0
  15. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_input_props.html.erb +16 -0
  16. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_input_props.jsx +56 -0
  17. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_input_props.md +1 -0
  18. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.html.erb +10 -0
  19. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.jsx +68 -0
  20. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.md +9 -0
  21. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_strength_change.jsx +33 -0
  22. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_strength_change.md +3 -0
  23. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_tips.html.erb +26 -0
  24. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_tips.jsx +54 -0
  25. data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_tips.md +1 -0
  26. data/app/pb_kits/playbook/pb_passphrase/docs/example.yml +15 -0
  27. data/app/pb_kits/playbook/pb_passphrase/docs/index.js +6 -0
  28. data/app/pb_kits/playbook/pb_passphrase/passphrase.html.erb +1 -0
  29. data/app/pb_kits/playbook/pb_passphrase/passphrase.rb +41 -0
  30. data/app/pb_kits/playbook/pb_passphrase/passphrase.test.jsx +123 -0
  31. data/app/pb_kits/playbook/pb_passphrase/passwordStrength.js +55 -0
  32. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.jsx +3 -4
  33. data/app/pb_kits/playbook/pb_text_input/_text_input.jsx +0 -3
  34. data/app/pb_kits/playbook/pb_textarea/_textarea.jsx +0 -3
  35. data/app/pb_kits/playbook/pb_typeahead/_typeahead.jsx +1 -9
  36. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +0 -13
  37. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.jsx +11 -21
  38. data/app/pb_kits/playbook/pb_typeahead/components/Placeholder.jsx +4 -17
  39. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_default.jsx +0 -1
  40. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_pills.jsx +3 -8
  41. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +4 -4
  42. data/app/pb_kits/playbook/react_rails_kits.js +1 -0
  43. data/lib/playbook/version.rb +1 -1
  44. metadata +27 -4
  45. data/app/pb_kits/playbook/pb_typeahead/components/Input.jsx +0 -27
@@ -0,0 +1,123 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+ import { Passphrase } from '../'
4
+
5
+ const testId = 'text-input1',
6
+ kitClass = 'pb_passphrase'
7
+
8
+ /* See these resources for more testing info:
9
+ - https://github.com/testing-library/jest-dom#usage for useage and examples
10
+ - https://jestjs.io/docs/en/using-matchers
11
+ */
12
+
13
+ test('returns namespaced class name', () => {
14
+ render(
15
+ <Passphrase
16
+ data={{ testid: testId }}
17
+ />
18
+ )
19
+
20
+ const kit = screen.getByTestId(testId)
21
+ expect(kit).toHaveClass(kitClass)
22
+ })
23
+
24
+ test('returns additional class name', () => {
25
+ render(
26
+ <Passphrase
27
+ className="additional_class"
28
+ data={{ testid: testId }}
29
+ />
30
+ )
31
+
32
+ const kit = screen.getByTestId(testId)
33
+ expect(kit).toHaveClass(`${kitClass} additional_class`)
34
+ })
35
+
36
+ test('returns dark class name', () => {
37
+ render(
38
+ <Passphrase
39
+ dark
40
+ data={{ testid: testId }}
41
+ />
42
+ )
43
+
44
+ const kit = screen.getByTestId(testId)
45
+ expect(kit).toHaveClass(`${kitClass} dark`)
46
+ })
47
+
48
+ test('passes input props to input element', () => {
49
+ render(
50
+ <Passphrase
51
+ data={{ testid: testId }}
52
+ inputProps={{
53
+ name: 'test-name',
54
+ id: 'test-input-id',
55
+ disabled: true,
56
+ }}
57
+ />
58
+ )
59
+
60
+ const kit = screen.getByTestId(testId)
61
+ const input = kit.getElementsByTagName('input')[0]
62
+ expect(input).toHaveAttribute('name', 'test-name')
63
+ expect(input).toHaveAttribute('id', 'test-input-id')
64
+ expect(input).toBeDisabled()
65
+ })
66
+
67
+ test('progress bar is invisible when value is empty', () => {
68
+ render(
69
+ <Passphrase
70
+ data={{ testid: testId }}
71
+ />
72
+ )
73
+
74
+ const kit = screen.getByTestId(testId)
75
+ expect(kit.querySelector('[class^=pb_progress_simple_wrapper]')).toHaveClass('progress-empty-input')
76
+ })
77
+
78
+ test('progress bar is visible when value is not empty', () => {
79
+ render(
80
+ <Passphrase
81
+ data={{ testid: testId }}
82
+ value="test_password_input"
83
+ />
84
+ )
85
+
86
+ const kit = screen.getByTestId(testId)
87
+ expect(kit.querySelector('[class^=pb_progress_simple_wrapper]')).not.toHaveClass('progress-empty-input')
88
+ })
89
+
90
+ test('no progress bar is show when confirmation is true', () => {
91
+ render(
92
+ <Passphrase
93
+ confirmation
94
+ data={{ testid: testId }}
95
+ />
96
+ )
97
+
98
+ const kit = screen.getByTestId(testId)
99
+ expect(kit.querySelector('[class^=pb_progress_simple_wrapper]')).toBeNull()
100
+ })
101
+
102
+ test('popover target shows when tips are given', () => {
103
+ render(
104
+ <Passphrase
105
+ data={{ testid: testId }}
106
+ tips={['some helpful tips']}
107
+ />
108
+ )
109
+
110
+ const kit = screen.getByTestId(testId)
111
+ expect(kit.querySelector('[class^=pb_popover_reference_wrapper]')).toBeDefined()
112
+ })
113
+
114
+ test('popover target does not show when tips are not given', () => {
115
+ render(
116
+ <Passphrase
117
+ data={{ testid: testId }}
118
+ />
119
+ )
120
+
121
+ const kit = screen.getByTestId(testId)
122
+ expect(kit.querySelector('[class^=pb_popover_reference_wrapper]')).toBeNull()
123
+ })
@@ -0,0 +1,55 @@
1
+ import zxcvbn from 'zxcvbn'
2
+
3
+ export const zxcvbnPasswordScore = (options) => {
4
+ const {
5
+ calculate = zxcvbn,
6
+ averageThreshold = 2,
7
+ strongThreshold = 3,
8
+ minLength = 12,
9
+ } = options
10
+
11
+ return {
12
+ minLength,
13
+ averageThreshold,
14
+ strongThreshold,
15
+ test: function (password = '', common = false) {
16
+ const feedbackValues = (str) => {
17
+ let percent, variant, text
18
+
19
+ if (password.length <= 0) {
20
+ percent = '0'
21
+ variant = 'negative'
22
+ text = '\u00A0' //nbsp to keep form from jumping when typing beings
23
+ } else if (common) {
24
+ percent = '25'
25
+ variant = 'negative'
26
+ text = 'This passphrase is too common'
27
+ } else if (password.length < this.minLength || str < this.averageThreshold) {
28
+ percent = '25'
29
+ variant = 'negative'
30
+ text = 'Too weak'
31
+ } else if (str < this.strongThreshold){
32
+ percent = '50'
33
+ variant = 'warning'
34
+ text = 'Almost there, keep going!'
35
+ } else if (str >= this.strongThreshold) {
36
+ percent = '100'
37
+ variant = 'positive'
38
+ text = 'Success! Strong passphrase'
39
+ }
40
+ return { percent, variant, text }
41
+ }
42
+
43
+ const result = calculate(password)
44
+
45
+ return (
46
+ {
47
+ suggestions: result.feedback.suggestions,
48
+ warning: result.feedback.warning,
49
+ strength: result.score,
50
+ ...feedbackValues(result.score),
51
+ }
52
+ )
53
+ },
54
+ }
55
+ }
@@ -1,6 +1,6 @@
1
1
  /* @flow */
2
2
 
3
- import React, { forwardRef, useEffect, useRef } from 'react'
3
+ import React, { useEffect, useRef } from 'react'
4
4
  import classnames from 'classnames'
5
5
  import useFocus from './useFocus.js'
6
6
  import Trix from 'trix'
@@ -22,7 +22,7 @@ type RichTextEditorProps = {
22
22
  value?: string,
23
23
  }
24
24
 
25
- const RichTextEditor = (props: RichTextEditorProps, ref: React.ElementRef<"input">) => {
25
+ const RichTextEditor = (props: RichTextEditorProps) => {
26
26
  const {
27
27
  aria = {},
28
28
  className,
@@ -120,7 +120,6 @@ const RichTextEditor = (props: RichTextEditorProps, ref: React.ElementRef<"input
120
120
  <input
121
121
  id={id}
122
122
  name={name}
123
- ref={ref}
124
123
  type="hidden"
125
124
  value={value}
126
125
  />
@@ -134,4 +133,4 @@ const RichTextEditor = (props: RichTextEditorProps, ref: React.ElementRef<"input
134
133
  )
135
134
  }
136
135
 
137
- export default forwardRef(RichTextEditor)
136
+ export default RichTextEditor
@@ -19,7 +19,6 @@ type TextInputProps = {
19
19
  id?: string,
20
20
  name: string,
21
21
  label: string,
22
- onBlur: (String) => void,
23
22
  onChange: (String) => void,
24
23
  placeholder: string,
25
24
  required?: boolean,
@@ -42,7 +41,6 @@ const TextInput = (
42
41
  id,
43
42
  name,
44
43
  label,
45
- onBlur = () => {},
46
44
  onChange = () => {},
47
45
  placeholder,
48
46
  required,
@@ -81,7 +79,6 @@ const TextInput = (
81
79
  disabled={disabled}
82
80
  id={id}
83
81
  name={name}
84
- onBlur={onBlur}
85
82
  onChange={onChange}
86
83
  placeholder={placeholder}
87
84
  ref={ref}
@@ -24,7 +24,6 @@ type TextareaProps = {
24
24
  required?: boolean,
25
25
  rows?: number,
26
26
  resize: 'none' | 'both' | 'horizontal' | 'vertical' | 'auto',
27
- onBlur?: InputCallback<HTMLTextAreaElement>,
28
27
  onChange?: InputCallback<HTMLTextAreaElement>,
29
28
  }
30
29
 
@@ -38,7 +37,6 @@ const Textarea = ({
38
37
  label,
39
38
  maxCharacters,
40
39
  name,
41
- onBlur = () => {},
42
40
  onChange = () => {},
43
41
  placeholder,
44
42
  required,
@@ -77,7 +75,6 @@ const Textarea = ({
77
75
  className="pb_textarea_kit"
78
76
  disabled={disabled}
79
77
  name={name}
80
- onBlur={onBlur}
81
78
  onChange={onChange}
82
79
  placeholder={placeholder}
83
80
  ref={ref}
@@ -3,14 +3,12 @@
3
3
  import React from 'react'
4
4
  import Select from 'react-select'
5
5
  import AsyncSelect from 'react-select/async'
6
- import CreateableSelect from 'react-select/creatable'
7
6
  import { get } from 'lodash'
8
7
  import { globalProps } from '../utilities/globalProps.js'
9
8
 
10
9
  import Control from './components/Control'
11
10
  import ClearIndicator from './components/ClearIndicator'
12
11
  import IndicatorsContainer from './components/IndicatorsContainer'
13
- // import Input from './components/Input'
14
12
  import MenuList from './components/MenuList'
15
13
  import MultiValue from './components/MultiValue'
16
14
  import Option from './components/Option'
@@ -28,7 +26,6 @@ import { noop } from '../utilities/props'
28
26
 
29
27
  type Props = {
30
28
  async?: boolean,
31
- createable?: boolean,
32
29
  dark?: boolean,
33
30
  label?: string,
34
31
  loadOptions?: noop | string,
@@ -44,14 +41,12 @@ type Props = {
44
41
 
45
42
  const Typeahead = (props: Props) => {
46
43
  const selectProps = {
47
- badges: false,
48
44
  cacheOptions: true,
49
45
  components: {
50
46
  Control,
51
47
  ClearIndicator,
52
48
  IndicatorsContainer,
53
49
  IndicatorSeparator: null,
54
- // Input,
55
50
  MenuList,
56
51
  MultiValue,
57
52
  Option,
@@ -63,8 +58,6 @@ const Typeahead = (props: Props) => {
63
58
  isClearable: true,
64
59
  isSearchable: true,
65
60
  name,
66
- onCreate: () => {},
67
- plusIcon: false,
68
61
  ...props,
69
62
  }
70
63
 
@@ -72,8 +65,7 @@ const Typeahead = (props: Props) => {
72
65
  if (typeof(props.getOptionLabel) === 'string') selectProps.getOptionLabel = get(window, props.getOptionLabel)
73
66
  if (typeof(props.getOptionValue) === 'string') selectProps.getOptionValue = get(window, props.getOptionValue)
74
67
 
75
- let Tag = props.async ? AsyncSelect : Select
76
- if (props.createable) Tag = CreateableSelect
68
+ const Tag = props.async ? AsyncSelect : Select
77
69
 
78
70
  const handleOnChange = (data, { action, option, removedValue }) => {
79
71
  if (action === 'select-option') {
@@ -154,17 +154,4 @@
154
154
  box-sizing: border-box;
155
155
  }
156
156
  }
157
- .placeholder+.input-wrapper .typeahead-plus-icon {
158
- display: none;
159
- }
160
- .typeahead-kit-select__control--is-focused .typeahead-plus-icon {
161
- display: none;
162
- }
163
- .typeahead-plus-icon {
164
- color: $text_lt_lighter;
165
- }
166
- [class^=pb_badge_kit] span {
167
- line-height: 16.5px;
168
- letter-spacing: normal;
169
- }
170
157
  }
@@ -3,7 +3,7 @@
3
3
  import React from 'react'
4
4
  import { components } from 'react-select'
5
5
 
6
- import { Badge, FormPill } from '../../'
6
+ import { FormPill } from '../../'
7
7
 
8
8
  type Props = {
9
9
  data: object,
@@ -15,7 +15,6 @@ type Props = {
15
15
  const MultiValue = (props: Props) => {
16
16
  const { removeProps } = props
17
17
  const { imageUrl, label } = props.data
18
- const { badges } = props.selectProps
19
18
 
20
19
  const formPillProps = {
21
20
  marginRight: 'xs',
@@ -29,28 +28,19 @@ const MultiValue = (props: Props) => {
29
28
  className="text_input_multivalue_container"
30
29
  {...props}
31
30
  >
32
- <If condition={badges}>
33
- <Badge
31
+ <If condition={imageUrl}>
32
+ <FormPill
33
+ avatarUrl={imageUrl}
34
34
  closeProps={removeProps}
35
- removeIcon
36
- text={label}
37
- variant="primary"
35
+ marginRight="xs"
36
+ name={label}
38
37
  />
39
38
  <Else />
40
- <If condition={imageUrl}>
41
- <FormPill
42
- avatarUrl={imageUrl}
43
- closeProps={removeProps}
44
- marginRight="xs"
45
- name={label}
46
- />
47
- <Else />
48
- <FormPill
49
- closeProps={removeProps}
50
- marginRight="xs"
51
- text={label}
52
- />
53
- </If>
39
+ <FormPill
40
+ closeProps={removeProps}
41
+ marginRight="xs"
42
+ text={label}
43
+ />
54
44
  </If>
55
45
  </components.MultiValueContainer>
56
46
  )
@@ -1,26 +1,13 @@
1
1
  /* @flow */
2
2
 
3
3
  import React from 'react'
4
- import { Flex, Icon } from '../../'
5
4
  import { components } from 'react-select'
6
5
 
7
6
  const Placeholder = (props: any) => (
8
- <>
9
- <Flex
10
- align="center"
11
- className="placeholder"
12
- >
13
- <components.IndicatorsContainer
14
- {...props}
15
- />
16
- <If condition={props.selectProps.plusIcon}>
17
- <Icon
18
- className="typeahead-plus-icon"
19
- icon="plus"
20
- />
21
- </If>
22
- </Flex>
23
- </>
7
+ <components.IndicatorsContainer
8
+ className="placeholder"
9
+ {...props}
10
+ />
24
11
  )
25
12
 
26
13
  export default Placeholder
@@ -13,7 +13,6 @@ const options = [
13
13
  const TypeaheadDefault = (props) => {
14
14
  return (
15
15
  <Typeahead
16
- // badges
17
16
  label="Colors"
18
17
  options={options}
19
18
  {...props}
@@ -3,7 +3,7 @@
3
3
  import React from 'react'
4
4
  import { Typeahead } from '../..'
5
5
 
6
- const initOptions = [
6
+ const options = [
7
7
  { label: 'Windows', value: '#FFA500' },
8
8
  { label: 'Siding', value: '#FF0000' },
9
9
  { label: 'Doors', value: '#00FF00' },
@@ -11,18 +11,13 @@ const initOptions = [
11
11
  ]
12
12
 
13
13
  const TypeaheadWithPills = (props) => {
14
- // const [values, setValues] = useState([])
15
14
  return (
16
15
  <>
17
16
  <Typeahead
18
- badges
19
- createable
20
17
  isMulti
21
18
  label="Colors"
22
- // onChange={(value) => console.log(value)}
23
- options={initOptions}
24
- placeholder="Placeholder"
25
- plusIcon
19
+ options={options}
20
+ placeholder=""
26
21
  {...props}
27
22
  />
28
23
  </>