playbook_ui 9.1.0 → 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_highlight/_highlight.jsx +1 -1
  6. data/app/pb_kits/playbook/pb_highlight/highlight.html.erb +3 -1
  7. data/app/pb_kits/playbook/pb_icon_stat_value/_icon_stat_value.jsx +3 -0
  8. data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.html.erb +1 -0
  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_progress_pills/_progress_pills.jsx +1 -1
  33. data/app/pb_kits/playbook/pb_progress_pills/docs/_description.md +3 -1
  34. data/app/pb_kits/playbook/pb_progress_pills/docs/_progress_pills_default.html.erb +1 -1
  35. data/app/pb_kits/playbook/pb_progress_pills/docs/_progress_pills_default.jsx +1 -0
  36. data/app/pb_kits/playbook/pb_progress_pills/docs/_progress_pills_status.html.erb +1 -1
  37. data/app/pb_kits/playbook/pb_progress_pills/docs/_progress_pills_status.jsx +1 -0
  38. data/app/pb_kits/playbook/pb_progress_pills/progress_pills.html.erb +1 -1
  39. data/app/pb_kits/playbook/pb_progress_pills/progress_pills.rb +5 -0
  40. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.scss +6 -0
  41. data/app/pb_kits/playbook/pb_stat_value/_stat_value.jsx +2 -0
  42. data/app/pb_kits/playbook/pb_stat_value/stat_value.html.erb +2 -0
  43. data/app/pb_kits/playbook/react_rails_kits.js +1 -0
  44. data/lib/playbook/version.rb +1 -1
  45. metadata +59 -36
@@ -0,0 +1 @@
1
+ Use the `confirmation` prop to only include the label and show/hide icon.
@@ -0,0 +1,16 @@
1
+ <%= pb_rails("passphrase", props: {
2
+ input_props: {
3
+ disabled: true,
4
+ id: "my-disabled-passphrase",
5
+ name: "my-disabled-field",
6
+ },
7
+ label: "Input props passed directly to input kit"
8
+ }) %>
9
+
10
+ <%= pb_rails("passphrase", props: {
11
+ input_props: {
12
+ id: "my-custome-id",
13
+ name: "my-value-name",
14
+ },
15
+ label: "Set name, id, etc for use in forms"
16
+ }) %>
@@ -0,0 +1,56 @@
1
+ import React, { useState } from 'react'
2
+ import { Passphrase } from '../../'
3
+
4
+ const PassphraseInputProps = (props) => {
5
+ const [input, setInput] = useState('')
6
+
7
+ const handleChange = (e) => setInput(e.target.value)
8
+
9
+ return (
10
+ <>
11
+ <div>
12
+ <Passphrase
13
+ inputProps={{
14
+ name: 'my-disabled-field',
15
+ id: 'my-value-id',
16
+ disabled: true,
17
+ }}
18
+ label="Pass props directly to input kit"
19
+ onChange={handleChange}
20
+ value={input}
21
+ {...props}
22
+ />
23
+ <Passphrase
24
+ inputProps={{
25
+ children: (
26
+ <input
27
+ onChange={handleChange}
28
+ type="password"
29
+ value={input}
30
+ />),
31
+ }}
32
+ label="Custom input"
33
+ onChange={handleChange}
34
+ value={input}
35
+ {...props}
36
+ />
37
+ <Passphrase
38
+ inputProps={{ name: 'my-value-name', id: 'my-value-id' }}
39
+ label="Set name and ID for use in form libraries"
40
+ onChange={handleChange}
41
+ value={input}
42
+ {...props}
43
+ />
44
+ <Passphrase
45
+ confirmation
46
+ inputProps={{ name: 'my-value-confirmation-name', id: 'my-value-confirmation-id' }}
47
+ onChange={handleChange}
48
+ value={input}
49
+ {...props}
50
+ />
51
+ </div>
52
+ </>
53
+ )
54
+ }
55
+
56
+ export default PassphraseInputProps
@@ -0,0 +1 @@
1
+ `inputProps` is passed directly to an underlying Text Input kit. See the specific docs <a href="/kits/text_input/react" target="_blank">here</a> for more details.
@@ -0,0 +1,10 @@
1
+
2
+ <%= pb_rails("passphrase", props: { label: "Default Settings"}) %>
3
+
4
+ <%= pb_rails("passphrase", props: { label: "Min length = 5", min_length: 5}) %>
5
+
6
+ <%= pb_rails("passphrase", props: { label: "Min length = 30", min_length: 30}) %>
7
+
8
+ <%= pb_rails("passphrase", props: { average_threshold: 1, label: "Average Threshold = 1"}) %>
9
+
10
+ <%= pb_rails("passphrase", props: { label: "Strong Threshold = 4", strong_threshold: 4}) %>
@@ -0,0 +1,68 @@
1
+ import React, { useState } from 'react'
2
+ import { Body, Passphrase, TextInput } from '../../'
3
+
4
+ const PassphraseMeterSettings = (props) => {
5
+ const [input, setInput] = useState('')
6
+
7
+ const handleChange = (e) => setInput(e.target.value)
8
+
9
+ const [strength, setStrength] = useState(0)
10
+ const handleStrengthChange = (str) => setStrength(str)
11
+ return (
12
+ <>
13
+ <div>
14
+ <Body>
15
+ {'These examples will all share the same input value. Type in any of the inputs to see how the strength meter changes in response to different settings.'}
16
+ </Body>
17
+ <br />
18
+ <TextInput
19
+ disabled
20
+ label="Calculated Strength"
21
+ readOnly
22
+ value={strength}
23
+ />
24
+
25
+ <Passphrase
26
+ label="Default settings"
27
+ onChange={handleChange}
28
+ onStrengthChange={handleStrengthChange}
29
+ value={input}
30
+ {...props}
31
+ />
32
+
33
+ <Passphrase
34
+ label="Min length = 5"
35
+ minLength={5}
36
+ onChange={handleChange}
37
+ value={input}
38
+ {...props}
39
+ />
40
+ <Passphrase
41
+ label="Min length = 30"
42
+ minLength={30}
43
+ onChange={handleChange}
44
+ value={input}
45
+ {...props}
46
+ />
47
+
48
+ <Passphrase
49
+ averageThreshold={1}
50
+ label="Average threshold = 1"
51
+ onChange={handleChange}
52
+ value={input}
53
+ {...props}
54
+ />
55
+
56
+ <Passphrase
57
+ label="Strong Threshold = 4"
58
+ onChange={handleChange}
59
+ strongThreshold={4}
60
+ value={input}
61
+ {...props}
62
+ />
63
+ </div>
64
+ </>
65
+ )
66
+ }
67
+
68
+ export default PassphraseMeterSettings
@@ -0,0 +1,9 @@
1
+ By default, the minimum length is 12 and the strength meter will show a strength of 1 if not met. Notice the bar won't change from red until the minimum is met
2
+ Use the `minLength` prop to adjust.
3
+
4
+
5
+ The meter also response to `averageThreshold` and `strongTreshold` props. `averageThresold` defaults to 2, and `strongThreshold` defaults to 3.
6
+ This means that the bar will turn yellow when the strength of the passphrase is calculated to be 2 on a 0-4 scale, and green when 3.
7
+
8
+ Adjust these props to tune the sensitivity of the bar.
9
+ Note: minimum length trumps strength and will set the bar to a red color, despite whatever strength is calculated.
@@ -0,0 +1,33 @@
1
+ import React, { useState } from 'react'
2
+ import { Passphrase, TextInput } from '../../'
3
+
4
+ const PassphraseStrengthChange = (props) => {
5
+ const [input, setInput] = useState('')
6
+
7
+ const handleChange = (e) => setInput(e.target.value)
8
+
9
+ const [strength, setStrength] = useState(0)
10
+ const handleStrengthChange = (str) => setStrength(str)
11
+
12
+ return (
13
+ <>
14
+ <div>
15
+ <Passphrase
16
+ label="Passphrase"
17
+ onChange={handleChange}
18
+ onStrengthChange={handleStrengthChange}
19
+ value={input}
20
+ {...props}
21
+ />
22
+ <TextInput
23
+ disabled
24
+ label="Passphrase Strength"
25
+ readOnly
26
+ value={strength}
27
+ />
28
+ </div>
29
+ </>
30
+ )
31
+ }
32
+
33
+ export default PassphraseStrengthChange
@@ -0,0 +1,3 @@
1
+ As the strength of the entered passphrase changes, the optional `onStrengthChange` callback is called with the new strength value. This exposes the calculated strength.
2
+
3
+ Strength is calculated on a 0-4 scale by the <a href="https://github.com/dropbox/zxcvbn" target="_blank"> Zxcvbn package</a>
@@ -0,0 +1,26 @@
1
+ <%= pb_rails("passphrase", props: {
2
+ label: "Pass an array of strings to the tips prop",
3
+ tips: ['And the info icon will appear.', 'Each string will be displayed as its own tip'],
4
+ }) %>
5
+
6
+ <%= pb_rails("passphrase", props: {
7
+ label: "Omit the prop to hide the icon"
8
+ }) %>
9
+
10
+ <%= pb_rails("passphrase", props: {
11
+ label: "Only show tips at small screen size",
12
+ show_tips_below: "sm",
13
+ tips: ['Make the password longer', 'Type more things', 'Use something else'],
14
+ }) %>
15
+
16
+ <%= pb_rails("passphrase", props: {
17
+ label: "Only show tips at medium screen size",
18
+ show_tips_below: "md",
19
+ tips: ['Make the password longer', 'Type more things', 'Use something else'],
20
+ }) %>
21
+
22
+ <%= pb_rails("passphrase", props: {
23
+ label: "Only show tips at large screen size",
24
+ show_tips_below: "lg",
25
+ tips: ['Make the password longer', 'Type more things', 'Use something else'],
26
+ }) %>
@@ -0,0 +1,54 @@
1
+ import React, { useState } from 'react'
2
+ import { Passphrase } from '../../'
3
+
4
+ const PassphraseTips = (props) => {
5
+ const [input, setInput] = useState('')
6
+
7
+ const handleChange = (e) => setInput(e.target.value)
8
+
9
+ return (
10
+ <>
11
+ <div>
12
+ <Passphrase
13
+ label="Pass an array of strings to the tips prop"
14
+ onChange={handleChange}
15
+ tips={['And the info icon will appear.', 'Each string will be displayed as its own tip']}
16
+ value={input}
17
+ {...props}
18
+ />
19
+ <Passphrase
20
+ label="Omit the prop to hide the icon"
21
+ onChange={handleChange}
22
+ value={input}
23
+ {...props}
24
+ />
25
+ <Passphrase
26
+ label="Only show tips at small screen size"
27
+ onChange={handleChange}
28
+ showTipsBelow="xs"
29
+ tips={['Make the password longer', 'Type more things', 'Use something else']}
30
+ value={input}
31
+ {...props}
32
+ />
33
+ <Passphrase
34
+ label="Only show tips at medium screen size"
35
+ onChange={handleChange}
36
+ showTipsBelow="md"
37
+ tips={['Make the password longer', 'Type more things', 'Use something else']}
38
+ value={input}
39
+ {...props}
40
+ />
41
+ <Passphrase
42
+ label="Only show tips at large screen size"
43
+ onChange={handleChange}
44
+ showTipsBelow="lg"
45
+ tips={['Make the password longer', 'Type more things', 'Use something else']}
46
+ value={input}
47
+ {...props}
48
+ />
49
+ </div>
50
+ </>
51
+ )
52
+ }
53
+
54
+ export default PassphraseTips
@@ -0,0 +1 @@
1
+ `showTipsBelow`(react) / `show_tips_below`(rails) takes 'xs', 'sm', 'md', 'lg', 'xl' and only show the tips below the given screen size. Similar to the <a href="/kits/table/react" target="_blank">responsive table breakpoints.</a> Omit this prop to always show.
@@ -0,0 +1,15 @@
1
+ examples:
2
+
3
+ rails:
4
+ - passphrase_default: Default
5
+ - passphrase_meter_settings: Meter Settings
6
+ - passphrase_input_props: Input Props
7
+ - passphrase_tips: Tips
8
+
9
+ react:
10
+ - passphrase_default: Default
11
+ - passphrase_meter_settings: Meter Settings
12
+ - passphrase_input_props: Input Props
13
+ - passphrase_tips: Tips
14
+ - passphrase_strength_change: Strength Change
15
+ - passphrase_common: Common Passphrases
@@ -0,0 +1,6 @@
1
+ export { default as PassphraseDefault } from './_passphrase_default.jsx'
2
+ export { default as PassphraseMeterSettings } from './_passphrase_meter_settings'
3
+ export { default as PassphraseInputProps } from './_passphrase_input_props'
4
+ export { default as PassphraseTips } from './_passphrase_tips'
5
+ export { default as PassphraseStrengthChange } from './_passphrase_strength_change'
6
+ export { default as PassphraseCommon } from './_passphrase_common'
@@ -0,0 +1 @@
1
+ <%= react_component('Passphrase', object.passphrase_options) %>
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbPassphrase
5
+ class Passphrase < Playbook::KitBase
6
+ prop :average_threshold
7
+ prop :confirmation, type: Playbook::Props::Boolean, default: false
8
+ prop :input_props, type: Playbook::Props::Hash, default: {}
9
+ prop :label
10
+ prop :min_length
11
+ prop :show_tips_below
12
+ prop :strong_threshold
13
+ prop :tips, type: Playbook::Props::Array, default: []
14
+
15
+ # prop :on_strength_change
16
+ # might not need these?
17
+ # prop :common
18
+ # prop :on_change
19
+
20
+ def classname
21
+ generate_classname("pb_passphrase")
22
+ end
23
+
24
+ def passphrase_options
25
+ {
26
+ dark: dark,
27
+ id: id,
28
+ averageThreshold: average_threshold,
29
+ confirmation: confirmation,
30
+ inputProps: input_props,
31
+ label: label,
32
+ minLength: min_length,
33
+ showTipsBelow: show_tips_below,
34
+ strongThreshold: strong_threshold,
35
+ tips: tips,
36
+ uncontrolled: true,
37
+ }.compact
38
+ end
39
+ end
40
+ end
41
+ end
@@ -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
+ })