playbook_ui 9.4.0.pre.alpha1 → 9.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/_playbook.scss +1 -0
- data/app/pb_kits/playbook/data/menu.yml +1 -0
- data/app/pb_kits/playbook/index.js +4 -3
- data/app/pb_kits/playbook/pb_checkbox/_checkbox.jsx +2 -1
- data/app/pb_kits/playbook/pb_checkbox/_checkbox.scss +3 -2
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.jsx +67 -9
- data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.jsx +11 -45
- data/app/pb_kits/playbook/pb_date_stacked/date_stacked.html.erb +6 -17
- data/app/pb_kits/playbook/pb_date_stacked/date_stacked.rb +5 -12
- data/app/pb_kits/playbook/pb_date_stacked/docs/example.yml +1 -3
- data/app/pb_kits/playbook/pb_date_stacked/docs/index.js +0 -1
- data/app/pb_kits/playbook/pb_date_time_stacked/_date_time_stacked.jsx +16 -32
- data/app/pb_kits/playbook/pb_date_time_stacked/_date_time_stacked.scss +4 -23
- data/app/pb_kits/playbook/pb_date_time_stacked/date_time_stacked.html.erb +8 -12
- data/app/pb_kits/playbook/pb_date_time_stacked/date_time_stacked.rb +2 -9
- data/app/pb_kits/playbook/pb_date_time_stacked/docs/_date_time_stacked_default.html.erb +1 -8
- data/app/pb_kits/playbook/pb_date_time_stacked/docs/_date_time_stacked_default.jsx +1 -19
- data/app/pb_kits/playbook/pb_dialog/dialog.test.jsx +1 -1
- data/app/pb_kits/playbook/pb_flex/_flex.jsx +1 -6
- data/app/pb_kits/playbook/pb_icon/_icon.jsx +20 -5
- data/app/pb_kits/playbook/pb_icon/icon.html.erb +4 -2
- data/app/pb_kits/playbook/pb_loading_inline/_loading_inline.jsx +1 -0
- data/app/pb_kits/playbook/pb_loading_inline/loading_inline.html.erb +1 -1
- data/app/pb_kits/playbook/pb_nav/_item.jsx +0 -2
- data/app/pb_kits/playbook/pb_nav/item.html.erb +2 -2
- data/app/pb_kits/playbook/pb_passphrase/_passphrase.jsx +205 -0
- data/app/pb_kits/playbook/pb_passphrase/_passphrase.scss +73 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_common.jsx +33 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_default.html.erb +3 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_default.jsx +31 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_default.md +1 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_input_props.html.erb +16 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_input_props.jsx +56 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_input_props.md +1 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.html.erb +10 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.jsx +68 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.md +9 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_strength_change.jsx +33 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_strength_change.md +3 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_tips.html.erb +26 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_tips.jsx +54 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_tips.md +1 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/example.yml +15 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/index.js +6 -0
- data/app/pb_kits/playbook/pb_passphrase/passphrase.html.erb +1 -0
- data/app/pb_kits/playbook/pb_passphrase/passphrase.rb +36 -0
- data/app/pb_kits/playbook/pb_passphrase/passphrase.test.jsx +123 -0
- data/app/pb_kits/playbook/pb_passphrase/passwordStrength.js +55 -0
- data/app/pb_kits/playbook/pb_section_separator/_section_separator.jsx +3 -7
- data/app/pb_kits/playbook/pb_time_stacked/time_stacked.html.erb +2 -2
- data/app/pb_kits/playbook/react_rails_kits.js +1 -0
- data/lib/playbook/version.rb +1 -1
- metadata +27 -7
- data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_bold.html.erb +0 -5
- data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_bold.jsx +0 -38
- data/app/pb_kits/playbook/pb_date_time_stacked/date_time_stacked.test.js +0 -35
@@ -1,17 +1,13 @@
|
|
1
1
|
<%= content_tag(:div,
|
2
2
|
id: object.id,
|
3
3
|
data: object.data,
|
4
|
-
class: object.classname
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
<%= pb_rails("body", props: {classname: "flex-item"}) do %>
|
9
|
-
<%= pb_rails("date_stacked", props: { date: object.date_time_value, size: "sm", align: "right", bold: true, dark: object.dark }) %>
|
4
|
+
class: object.classname) do %>
|
5
|
+
<%= pb_rails("flex", props: { orientation: "row", vertical: "center" }) do %>
|
6
|
+
<%= pb_rails("flex/flex_item") do %>
|
7
|
+
<%= pb_rails("date_stacked", props: { align: "right", date: object.date, reverse: true, size: "sm", dark: object.dark }) %>
|
10
8
|
<% end %>
|
11
|
-
<%= pb_rails("
|
12
|
-
|
13
|
-
<%= pb_rails("time_stacked", props: { time: object.date_time_value, dark: object.dark, timezone: object.timezone }) %>
|
9
|
+
<%= pb_rails("flex/flex_item") do %>
|
10
|
+
<%= pb_rails("time_stacked", props: { classname: "pb_date_time_stacked_kit", time: object.date, tag: "caption" }) %>
|
14
11
|
<% end %>
|
15
|
-
|
16
|
-
|
17
|
-
<% end %>
|
12
|
+
<% end %>
|
13
|
+
<% end %>
|
@@ -3,17 +3,10 @@
|
|
3
3
|
module Playbook
|
4
4
|
module PbDateTimeStacked
|
5
5
|
class DateTimeStacked < Playbook::KitBase
|
6
|
-
prop :date,
|
7
|
-
prop :date_time, type: Playbook::Props::Date,
|
6
|
+
prop :date, type: Playbook::Props::Date,
|
8
7
|
default: ::DateTime.current
|
9
8
|
prop :dark, type: Playbook::Props::Boolean,
|
10
9
|
default: false
|
11
|
-
prop :timezone, type: Playbook::Props::String,
|
12
|
-
default: "America/New_York"
|
13
|
-
|
14
|
-
def date_time_value
|
15
|
-
date || date_time
|
16
|
-
end
|
17
10
|
end
|
18
11
|
end
|
19
|
-
end
|
12
|
+
end
|
@@ -1,8 +1 @@
|
|
1
|
-
<%= pb_rails("date_time_stacked"
|
2
|
-
<br>
|
3
|
-
<%= pb_rails("date_time_stacked", props: { date_time: Date.new(2018, 03, 20) }) %>
|
4
|
-
<br>
|
5
|
-
<%= pb_rails("date_time_stacked", props: { date_time: DateTime.now, timezone: "Asia/Tokyo" }) %>
|
6
|
-
<br>
|
7
|
-
<%= pb_rails("date_time_stacked", props: { date_time: DateTime.now, timezone: "America/Denver" }) %>
|
8
|
-
|
1
|
+
<%= pb_rails("date_time_stacked") %>
|
@@ -4,28 +4,10 @@ import { DateTimeStacked } from '../../'
|
|
4
4
|
const DateTimeStackedDefault = (props) => (
|
5
5
|
<div>
|
6
6
|
<DateTimeStacked
|
7
|
-
|
7
|
+
date={new Date()}
|
8
8
|
{...props}
|
9
9
|
/>
|
10
|
-
<br />
|
11
|
-
<DateTimeStacked
|
12
|
-
datetime={new Date()}
|
13
|
-
timeZone="Asia/Tokyo"
|
14
|
-
|
15
|
-
{...props}
|
16
|
-
/>
|
17
|
-
<br />
|
18
|
-
<DateTimeStacked
|
19
|
-
datetime={new Date()}
|
20
|
-
timeZone="America/Denver"
|
21
|
-
|
22
|
-
{...props}
|
23
|
-
/>
|
24
|
-
|
25
10
|
</div>
|
26
11
|
)
|
27
12
|
|
28
13
|
export default DateTimeStackedDefault
|
29
|
-
|
30
|
-
// *Development Note* - We are reviewing this kit for a potential name change due to naming collisions when `new Date()` is used.
|
31
|
-
// To avoid this bug, please use name spacing as shown in the code examples. ie `import { Date as AliasedComponentName } from '../../'
|
@@ -2,12 +2,11 @@
|
|
2
2
|
|
3
3
|
import React from 'react'
|
4
4
|
import classnames from 'classnames'
|
5
|
-
import { buildCss
|
5
|
+
import { buildCss } from '../utilities/props'
|
6
6
|
import { globalProps } from '../utilities/globalProps.js'
|
7
7
|
type FlexProps = {
|
8
8
|
children: array<React.ReactNode> | React.ReactNode,
|
9
9
|
className?: string,
|
10
|
-
data?: object,
|
11
10
|
horizontal?: "left" | "center" | "right" | "stretch" | "none",
|
12
11
|
justify?: "start" | "center" | "end" | "around" | "between" | "evenly" | "none",
|
13
12
|
id?: string,
|
@@ -28,7 +27,6 @@ const Flex = (props: FlexProps) => {
|
|
28
27
|
align = 'none',
|
29
28
|
children,
|
30
29
|
className,
|
31
|
-
data = {},
|
32
30
|
inline = false,
|
33
31
|
horizontal = 'left',
|
34
32
|
justify = 'none',
|
@@ -53,8 +51,6 @@ const Flex = (props: FlexProps) => {
|
|
53
51
|
const columnGapClass = columnGap !== 'none' ? `columnGap_${columnGap}` : ''
|
54
52
|
const wrapClass = wrap === true ? 'wrap' : ''
|
55
53
|
const reverseClass = reverse === true ? 'reverse' : ''
|
56
|
-
const dataProps = buildDataProps(data)
|
57
|
-
|
58
54
|
return (
|
59
55
|
<div
|
60
56
|
className={classnames(
|
@@ -74,7 +70,6 @@ const Flex = (props: FlexProps) => {
|
|
74
70
|
globalProps(props),
|
75
71
|
className
|
76
72
|
)}
|
77
|
-
{...dataProps}
|
78
73
|
>
|
79
74
|
{children}
|
80
75
|
</div>
|
@@ -2,12 +2,14 @@
|
|
2
2
|
|
3
3
|
import React from 'react'
|
4
4
|
import classnames from 'classnames'
|
5
|
+
import { buildAriaProps, buildDataProps } from '../utilities/props'
|
5
6
|
import { globalProps } from '../utilities/globalProps.js'
|
6
7
|
|
7
8
|
type IconProps = {
|
8
|
-
aria?:
|
9
|
+
aria?: object,
|
9
10
|
border?: boolean,
|
10
11
|
className?: string,
|
12
|
+
data?: object,
|
11
13
|
fixedWidth?: boolean,
|
12
14
|
flip?: "horizontal" | "vertical" | "both" | "none",
|
13
15
|
icon: string,
|
@@ -41,8 +43,10 @@ const flipMap = {
|
|
41
43
|
|
42
44
|
const Icon = (props: IconProps) => {
|
43
45
|
const {
|
46
|
+
aria = {},
|
44
47
|
border = false,
|
45
48
|
className,
|
49
|
+
data = {},
|
46
50
|
fixedWidth = true,
|
47
51
|
flip = false,
|
48
52
|
icon,
|
@@ -75,11 +79,22 @@ const Icon = (props: IconProps) => {
|
|
75
79
|
className
|
76
80
|
)
|
77
81
|
|
82
|
+
aria.label ? null : aria.label = `${icon} icon`
|
83
|
+
const ariaProps = buildAriaProps(aria)
|
84
|
+
const dataProps = buildDataProps(data)
|
85
|
+
|
78
86
|
return (
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
87
|
+
<>
|
88
|
+
<i
|
89
|
+
{...dataProps}
|
90
|
+
className={classes}
|
91
|
+
id={id}
|
92
|
+
/>
|
93
|
+
<span
|
94
|
+
{...ariaProps}
|
95
|
+
hidden
|
96
|
+
/>
|
97
|
+
</>
|
83
98
|
)
|
84
99
|
}
|
85
100
|
|
@@ -4,6 +4,6 @@
|
|
4
4
|
class: object.classname) do %>
|
5
5
|
|
6
6
|
<%= pb_rails("body", props: { color: "light", dark: object.dark }) do %>
|
7
|
-
<%= pb_rails("icon", props: { fixed_width: true, icon: "spinner", pulse: true }) %> Loading
|
7
|
+
<%= pb_rails("icon", props: { aria: { label: "loading icon" }, fixed_width: true, icon: "spinner", pulse: true }) %> Loading
|
8
8
|
<% end %>
|
9
9
|
<% end %>
|
@@ -75,7 +75,6 @@ const NavItem = (props: NavItemProps) => {
|
|
75
75
|
key={iconLeft}
|
76
76
|
>
|
77
77
|
<Icon
|
78
|
-
aria={{ label: iconLeft }}
|
79
78
|
className="pb_nav_list_item_icon_left"
|
80
79
|
fixedWidth
|
81
80
|
icon={iconLeft}
|
@@ -91,7 +90,6 @@ const NavItem = (props: NavItemProps) => {
|
|
91
90
|
key={iconRight}
|
92
91
|
>
|
93
92
|
<Icon
|
94
|
-
aria={{ label: iconRight }}
|
95
93
|
className="pb_nav_list_item_icon_right"
|
96
94
|
fixedWidth
|
97
95
|
icon={iconRight}
|
@@ -9,13 +9,13 @@
|
|
9
9
|
<%= pb_rails("image", props: { url: object.image_url, classname: "pb_nav_img_wrapper" }) %>
|
10
10
|
<% end %>
|
11
11
|
<% if object.icon_left %>
|
12
|
-
<%= pb_rails("icon", props: {
|
12
|
+
<%= pb_rails("icon", props: { icon: object.icon_left, classname: "pb_nav_list_item_icon_left", fixed_width: true}) %>
|
13
13
|
<% end %>
|
14
14
|
<span class="pb_nav_list_item_text">
|
15
15
|
<%= object.text %><%= content.presence %>
|
16
16
|
</span>
|
17
17
|
<% if object.icon_right %>
|
18
|
-
<%= pb_rails("icon", props: {
|
18
|
+
<%= pb_rails("icon", props: { icon: object.icon_right, classname: "pb_nav_list_item_icon_right", fixed_width: true}) %>
|
19
19
|
<% end %>
|
20
20
|
<% end %>
|
21
21
|
<% end %>
|
@@ -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 { zxcvbnPasswordScore } from './passwordStrength.js'
|
9
|
+
import { Body, Caption, Flex, Icon, PbReactPopover, ProgressSimple, TextInput } from '../'
|
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
|