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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13859d3f8d731118151f55f115ddddc05fe056a20f5166cd74d373ac333d56c5
4
- data.tar.gz: 7bbbc053d7fe78a2f0052440b42e78d8a4cca82013cc0ae11166c1d75521b693
3
+ metadata.gz: 8f2f364f3ddeeb9deedacb265c4740dc30e2ee30674ffac2b201a83a7ab04dfe
4
+ data.tar.gz: 34ba1be5b7fb2c41b49c4942239f365ea13793e34ed1195894d5172ca5cfca61
5
5
  SHA512:
6
- metadata.gz: ba648346b0802233d2dba4a4bd932b0bfe039ee63667afc90efbef0f00a3d09671866783c6a8ace55e84f2ba6430ecd230f30241aa328a7d925db8cdeef684ef
7
- data.tar.gz: ded1c063a8f3b196bae5e4af2cc446411392dba688ec444b0e885fb03c0cf4703f7984d7e0a09722c345613e25033afbc92f447baa7ba9b93c265998d7503a8b
6
+ metadata.gz: d03d13b429587603b894ad28a093ac0e0ff27c47dda184f0f655ba017405e7fcf6b14c2f75907b6c57c47156639fb9c5eba0d232bcf535bfbde2ba8fca9d0dcf
7
+ data.tar.gz: 989a00fe0377210d658918ebf38ef93f49621a9c4bdfd6c87c87f8914d09aa7f40ec58eaa1a46ddaaef52aca55d30662bf63049c4638352ec8705d684e19777c
@@ -55,6 +55,7 @@
55
55
  @import 'pb_multiple_users_stacked/multiple_users_stacked';
56
56
  @import 'pb_nav/nav';
57
57
  @import 'pb_online_status/online_status';
58
+ @import 'pb_passphrase/passphrase';
58
59
  @import 'pb_person/person';
59
60
  @import 'pb_person_contact/person_contact';
60
61
  @import 'pb_pill/pill';
@@ -26,6 +26,7 @@ kits:
26
26
  - form
27
27
  - form_group
28
28
  - form_pill
29
+ - passphrase
29
30
  - radio
30
31
  - rich_text_editor
31
32
  - select
@@ -61,6 +61,7 @@ export MultipleUsersStacked from './pb_multiple_users_stacked/_multiple_users_st
61
61
  export Nav from './pb_nav/_nav.jsx'
62
62
  export NavItem from './pb_nav/_item.jsx'
63
63
  export OnlineStatus from './pb_online_status/_online_status.jsx'
64
+ export Passphrase from './pb_passphrase/_passphrase.jsx'
64
65
  export PbReactPopover from './pb_popover/_popover.jsx'
65
66
  export Person from './pb_person/_person.jsx'
66
67
  export PersonContact from './pb_person_contact/_person_contact.jsx'
@@ -84,13 +85,13 @@ export StatChange from './pb_stat_change/_stat_change.jsx'
84
85
  export StatValue from './pb_stat_value/_stat_value.jsx'
85
86
  export Table from './pb_table/_table.jsx'
86
87
  export TableRow from './pb_table/_table_row.jsx'
87
- export Textarea from './pb_textarea/_textarea.jsx'
88
88
  export TextInput from './pb_text_input/_text_input.jsx'
89
+ export Textarea from './pb_textarea/_textarea.jsx'
89
90
  export Time from './pb_time/_time.jsx'
90
- export Timeline from './pb_timeline/_timeline.jsx'
91
+ export TimeRangeInline from './pb_time_range_inline/_time_range_inline.jsx'
91
92
  export TimeStacked from './pb_time_stacked/_time_stacked.jsx'
93
+ export Timeline from './pb_timeline/_timeline.jsx'
92
94
  export Timestamp from './pb_timestamp/_timestamp.jsx'
93
- export TimeRangeInline from './pb_time_range_inline/_time_range_inline.jsx'
94
95
  export Title from './pb_title/_title.jsx'
95
96
  export TitleCount from './pb_title_count/_title_count.jsx'
96
97
  export TitleDetail from './pb_title_detail/_title_detail.jsx'
@@ -28,7 +28,7 @@ const Highlight = (props: HighlightProps) => {
28
28
  autoEscape
29
29
  data={data}
30
30
  highlightClassName={classnames(globalProps(props), className)}
31
- highlightTag="span"
31
+ highlightTag="mark"
32
32
  id={id}
33
33
  searchWords={highlightedText}
34
34
  textToHighlight={text || children}
@@ -2,5 +2,7 @@
2
2
  id: object.id,
3
3
  data: object.data,
4
4
  class: object.classname) do %>
5
- <%= content.presence || object.text %>
5
+ <mark>
6
+ <%= content.presence || object.text %>
7
+ </mark>
6
8
  <% end %>
@@ -52,6 +52,7 @@ const IconStatValue = (props: IconStatValueProps) => {
52
52
  return (
53
53
  <Title
54
54
  size={1}
55
+ tag="span"
55
56
  text={`${value}`}
56
57
  />
57
58
  )
@@ -59,6 +60,7 @@ const IconStatValue = (props: IconStatValueProps) => {
59
60
  return (
60
61
  <Title
61
62
  size={2}
63
+ tag="span"
62
64
  text={`${value}`}
63
65
  />
64
66
  )
@@ -66,6 +68,7 @@ const IconStatValue = (props: IconStatValueProps) => {
66
68
  return (
67
69
  <Title
68
70
  size={3}
71
+ tag="span"
69
72
  text={`${value}`}
70
73
  />
71
74
  )
@@ -12,6 +12,7 @@
12
12
  <div>
13
13
  <%= pb_rails("flex", props: { vertical: "bottom" }) do %>
14
14
  <%= pb_rails "title", props: {
15
+ tag: "span",
15
16
  text: object.value_string,
16
17
  size: object.title_size } %>
17
18
  &nbsp;
@@ -0,0 +1,205 @@
1
+
2
+ /* @flow */
3
+
4
+ import React, { useCallback, useEffect, useMemo, useState } from 'react'
5
+ import classnames from 'classnames'
6
+ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
7
+ import { globalProps } from '../utilities/globalProps.js'
8
+ import { Body, Caption, Flex, Icon, PbReactPopover, ProgressSimple, TextInput } from '../'
9
+ import { zxcvbnPasswordScore } from './passwordStrength.js'
10
+
11
+ type PassphraseProps = {
12
+ aria?: object,
13
+ averageThreshold?: number,
14
+ common?: boolean,
15
+ confirmation?: boolean,
16
+ className?: string,
17
+ data?: object,
18
+ dark?: boolean,
19
+ id?: string,
20
+ inputProps?: {},
21
+ label?: string,
22
+ minLength?: number,
23
+ onChange: (String) => void,
24
+ showTipsBelow?: 'always' | 'xs' | 'sm' | 'md' | 'lg' | 'xl',
25
+ onStrengthChange?: (number) => void,
26
+ strongThreshold?: number,
27
+ tips?: Array<string>,
28
+ uncontrolled?: boolean,
29
+ value: string,
30
+ }
31
+
32
+ const Passphrase = (props: PassphraseProps) => {
33
+ const {
34
+ aria = {},
35
+ averageThreshold = 2,
36
+ className,
37
+ common = false,
38
+ confirmation = false,
39
+ dark = false,
40
+ data = {},
41
+ id,
42
+ inputProps = {},
43
+ label = confirmation ? 'Confirm Passphrase' : 'Passphrase',
44
+ minLength,
45
+ onChange = () => {},
46
+ showTipsBelow = 'always',
47
+ onStrengthChange,
48
+ strongThreshold = 3,
49
+ tips = [],
50
+ uncontrolled = false,
51
+ value = '',
52
+ } = props
53
+
54
+ const [uncontrolledValue, setUncontrolledValue] = useState('')
55
+
56
+ const handleChange = useCallback(
57
+ (e) => uncontrolled ? setUncontrolledValue(e.target.value) : onChange(e),
58
+ [uncontrolled, onChange]
59
+ )
60
+
61
+ const displayValue = useMemo(
62
+ () => (uncontrolled ? uncontrolledValue : value),
63
+ [value, uncontrolledValue, uncontrolled],
64
+ )
65
+
66
+ const [showPopover, setShowPopover] = useState(false)
67
+ const toggleShowPopover = () => setShowPopover(!showPopover)
68
+ const [showPassphrase, setShowPassphrase] = useState(false)
69
+ const toggleShowPassphrase = () => setShowPassphrase(!showPassphrase)
70
+
71
+ const ariaProps = buildAriaProps(aria)
72
+ const dataProps = buildDataProps(data)
73
+ const classes = classnames(buildCss('pb_passphrase'), globalProps(props), className)
74
+
75
+ const calculator = useMemo(
76
+ () => confirmation ? { test: () => ({}) } : zxcvbnPasswordScore({ averageThreshold, strongThreshold, minLength }),
77
+ [averageThreshold, confirmation, strongThreshold, minLength]
78
+ )
79
+
80
+ const { percent: progressPercent, variant: progressVariant, text: strengthLabel, strength } = calculator.test(displayValue, common)
81
+
82
+ useEffect(() => {
83
+ if (typeof onStrengthChange === 'function') {
84
+ onStrengthChange(strength)
85
+ }
86
+ }, [strength])
87
+
88
+ const tipClass = classnames(
89
+ (dark ? 'dark' : null),
90
+ (showTipsBelow === 'always' ? null : `show-below-${showTipsBelow}`),
91
+ )
92
+
93
+ const popoverReference = (
94
+ <a
95
+ className={tipClass}
96
+ onClick={toggleShowPopover}
97
+ >
98
+ <Icon
99
+ dark={dark}
100
+ icon="info-circle"
101
+ size="xs"
102
+ variant="link"
103
+ />
104
+ </a>
105
+ )
106
+
107
+ return (
108
+ <div
109
+ {...ariaProps}
110
+ {...dataProps}
111
+ className={classes}
112
+ id={id}
113
+ >
114
+ <label>
115
+ <Flex align="baseline">
116
+ <Caption
117
+ className="passphrase-label"
118
+ text={label}
119
+ />
120
+ <If condition={tips.length > 0 && !confirmation}>
121
+ <PbReactPopover
122
+ placement="right"
123
+ reference={popoverReference}
124
+ show={showPopover}
125
+ >
126
+ <Flex
127
+ align="center"
128
+ orientation="column"
129
+ >
130
+ <Caption
131
+ marginBottom="xs"
132
+ text="Tips for a good passphrase"
133
+ />
134
+ <div>
135
+ {
136
+ tips.map((tip, i) => (
137
+ <Caption
138
+ key={i}
139
+ marginBottom="xs"
140
+ size="xs"
141
+ >
142
+ <Icon
143
+ icon="shield-check"
144
+ marginRight="xs"
145
+ />
146
+ {tip}
147
+ </Caption>
148
+ ))
149
+ }
150
+ </div>
151
+ </Flex>
152
+ </PbReactPopover>
153
+ </If>
154
+ </Flex>
155
+ <div className="passphrase-text-input-wrapper">
156
+ <TextInput
157
+ className="passphrase-text-input"
158
+ dark={dark}
159
+ marginBottom="xs"
160
+ onChange={handleChange}
161
+ placeholder="Enter a passphrase..."
162
+ type={showPassphrase ? 'text' : 'password'}
163
+ value={displayValue}
164
+ {...inputProps}
165
+ />
166
+ <span
167
+ className="show-passphrase-icon"
168
+ dark={dark}
169
+ onClick={toggleShowPassphrase}
170
+ >
171
+ <Body
172
+ className={showPassphrase ? 'hide-icon' : ''}
173
+ color="light"
174
+ dark={dark}
175
+ >
176
+ <Icon icon="eye-slash" />
177
+ </Body>
178
+ <Body
179
+ className={showPassphrase ? '' : 'hide-icon'}
180
+ color="light"
181
+ dark={dark}
182
+ >
183
+ <Icon icon="eye" />
184
+ </Body>
185
+ </span>
186
+ </div>
187
+ </label>
188
+ <If condition={!confirmation}>
189
+ <ProgressSimple
190
+ className={displayValue.length === 0 ? 'progress-empty-input' : null}
191
+ dark={dark}
192
+ percent={progressPercent}
193
+ variant={progressVariant}
194
+ />
195
+ <Caption
196
+ dark={dark}
197
+ size="xs"
198
+ text={strengthLabel}
199
+ />
200
+ </If>
201
+ </div>
202
+ )
203
+ }
204
+
205
+ export default Passphrase
@@ -0,0 +1,63 @@
1
+ @import "../tokens/colors";
2
+ @import "../tokens/spacing";
3
+ @import "../tokens/screen_sizes";
4
+
5
+ .pb_passphrase {
6
+ margin-bottom: $space_sm;
7
+
8
+ a.dark {
9
+ color: $white;
10
+ }
11
+
12
+ a {
13
+
14
+ &[class*=show-below-] {
15
+ display: none;
16
+ }
17
+ @each $breakpoint_name, $breakpoint in $breakpoints {
18
+ &.show-below-#{$breakpoint_name} {
19
+ @include break_at($breakpoint) {
20
+ display: inline;
21
+ }
22
+ }
23
+ }
24
+ }
25
+
26
+ .passphrase-label{
27
+ margin-right: 4px;
28
+ }
29
+
30
+ .passphrase-text-input-wrapper {
31
+ position: relative;
32
+
33
+ .pb_text_input_kit_label {
34
+ margin-bottom: 4px;
35
+ }
36
+
37
+ .passphrase-text-input input{
38
+ padding-right: 42px;
39
+ }
40
+
41
+ .passphrase-text-input .text_input_wrapper {
42
+ margin-bottom: 0;
43
+ }
44
+
45
+ .show-passphrase-icon {
46
+ position: absolute;
47
+ right: 11px;
48
+ top: 11px;
49
+
50
+ .hide-icon {
51
+ display: none;
52
+ }
53
+ }
54
+ }
55
+
56
+ .pb_progress_simple_wrapper, .pb_progress_simple_wrapper_dark {
57
+ margin-bottom: 4px;
58
+
59
+ &.progress-empty-input {
60
+ visibility: hidden;
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,33 @@
1
+ import React, { useState } from 'react'
2
+ import { Body, Passphrase } from '../../'
3
+
4
+ const PassphraseCommon = (props) => {
5
+ const [input, setInput] = useState('')
6
+
7
+ const handleChange = (e) => setInput(e.target.value)
8
+
9
+ const COMMON_PASSPHRASES = ['passphrase', 'apple', 'password', 'p@55w0rd']
10
+
11
+ const commonCheck = (passphrase) => {
12
+ if (COMMON_PASSPHRASES.includes(passphrase))
13
+ return true
14
+ return false
15
+ }
16
+
17
+ return (
18
+ <>
19
+ <div>
20
+ <Body text={`Try typing any of the following: ${COMMON_PASSPHRASES.join(' ')}`} />
21
+ <br />
22
+ <Passphrase
23
+ common={commonCheck(input)}
24
+ onChange={handleChange}
25
+ value={input}
26
+ {...props}
27
+ />
28
+ </div>
29
+ </>
30
+ )
31
+ }
32
+
33
+ export default PassphraseCommon
@@ -0,0 +1,3 @@
1
+ <%= pb_rails("passphrase") %>
2
+
3
+ <%= pb_rails("passphrase", props: { confirmation: true}) %>
@@ -0,0 +1,31 @@
1
+ import React, { useState } from 'react'
2
+ import { Passphrase } from '../../'
3
+
4
+ const PassphraseDefault = (props) => {
5
+ const [input, setInput] = useState('')
6
+ const handleChange = (e) => setInput(e.target.value)
7
+
8
+ const [confoInput, setConfoInput] = useState('')
9
+ const handleConfoChange = (e) => setConfoInput(e.target.value)
10
+
11
+ return (
12
+ <>
13
+ <div>
14
+ <Passphrase
15
+ onChange={handleChange}
16
+ value={input}
17
+ {...props}
18
+ />
19
+ <Passphrase
20
+ confirmation
21
+ onChange={handleConfoChange}
22
+ value={confoInput}
23
+ {...props}
24
+ />
25
+ <span>{input === confoInput ? 'They match!' : 'They don\'t match!'}</span>
26
+ </div>
27
+ </>
28
+ )
29
+ }
30
+
31
+ export default PassphraseDefault