playbook_ui 12.33.1 → 12.34.0.pre.alpha.fixdialogcloseevents1003
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_button/_button.scss +32 -0
- data/app/pb_kits/playbook/pb_button/_button.tsx +78 -26
- data/app/pb_kits/playbook/pb_button/button.html.erb +17 -0
- data/app/pb_kits/playbook/pb_button/button.rb +18 -2
- data/app/pb_kits/playbook/pb_button/docs/_button_reaction.html.erb +30 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_reaction.jsx +47 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_reaction.md +3 -0
- data/app/pb_kits/playbook/pb_button/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_button/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_dialog/dialogHelper.js +7 -4
- data/app/pb_kits/playbook/pb_icon/_icon.scss +4 -0
- data/app/pb_kits/playbook/pb_icon/_icon.tsx +1 -2
- data/app/pb_kits/playbook/pb_icon/icon.html.erb +1 -1
- data/dist/playbook-rails.js +6 -6
- data/lib/playbook/version.rb +2 -2
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73dae18aff8f323e035348eead47c0a135a2e639eff5ef2d915e0f43ede1e5ed
|
4
|
+
data.tar.gz: b5db0c63a610c78a17762f84420fef70c1362bf29246a475a1283b509a14f4d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3532bdf137816d68b2f4a09ceab812d18b976e86584caf5e9ed1e24de762efd4c058c61803db2eb87afb9b89afeb0a6b2c038aa9640f88855761fe941ab85ab8
|
7
|
+
data.tar.gz: dbb59a43fe72b66d70d82baaacc07296b61b50ef66dcea38b6cc1544f42040453c3d43c96b41cddedf849cefc9b8cf4b3dd0afc6b76e4ace1025f6ab7f61f5ee
|
@@ -1,5 +1,9 @@
|
|
1
1
|
@import "./button_mixins";
|
2
2
|
@import "../tokens/colors";
|
3
|
+
@import "../tokens/border_radius";
|
4
|
+
@import "../tokens/colors";
|
5
|
+
@import "../tokens/spacing";
|
6
|
+
@import "../tokens/typography";
|
3
7
|
|
4
8
|
$pb_button_sizes: (
|
5
9
|
"sm": 0.75rem,
|
@@ -30,6 +34,34 @@ $pb_button_sizes: (
|
|
30
34
|
&[class*=_link] {
|
31
35
|
@include pb_button_link;
|
32
36
|
}
|
37
|
+
&[class*=_reaction] {
|
38
|
+
background-color: $card_light;
|
39
|
+
min-width: 40px;
|
40
|
+
border-radius: $border_radius_rounded;
|
41
|
+
border: 1px solid $border_light;
|
42
|
+
color: $text_lt_light;
|
43
|
+
padding: ($space_xxs - 2) $space_xs;
|
44
|
+
min-height: $space_md + 4;
|
45
|
+
|
46
|
+
.pb_icon_kit_emoji, .pb_icon_kit {
|
47
|
+
font-size: $font_base;
|
48
|
+
}
|
49
|
+
&:hover {
|
50
|
+
background-color: $bg_light;
|
51
|
+
}
|
52
|
+
&.active {
|
53
|
+
border-color:transparent;
|
54
|
+
box-shadow: 0px 0px 0 2px $primary_action;
|
55
|
+
&:hover {
|
56
|
+
background-color: rgba($primary, 0.03);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
&.reaction_default {
|
62
|
+
padding: ($space_xxs + 1) ($space_sm - 4);
|
63
|
+
color: $text_lt_lighter;
|
64
|
+
}
|
33
65
|
|
34
66
|
// Disabled =================
|
35
67
|
&[class*=_disabled] {
|
@@ -4,6 +4,8 @@ import { buildAriaProps, buildDataProps } from '../utilities/props'
|
|
4
4
|
import { GlobalProps, globalProps } from '../utilities/globalProps'
|
5
5
|
|
6
6
|
import Icon from '../pb_icon/_icon'
|
7
|
+
import Caption from "../pb_caption/_caption"
|
8
|
+
import Flex from "../pb_flex/_flex"
|
7
9
|
|
8
10
|
type EventHandler = (React.MouseEventHandler<HTMLElement>)
|
9
11
|
|
@@ -11,11 +13,13 @@ type ButtonPropTypes = {
|
|
11
13
|
aria?: { [key: string]: string },
|
12
14
|
children?: React.ReactChild[] | React.ReactChild,
|
13
15
|
className?: string | string[],
|
16
|
+
count?: number,
|
14
17
|
data?: { [key: string]: string },
|
15
18
|
disabled?: boolean,
|
16
19
|
fixedWidth?: boolean,
|
17
20
|
form?: string,
|
18
21
|
fullWidth?: boolean,
|
22
|
+
highlight?: boolean,
|
19
23
|
icon?: string,
|
20
24
|
iconRight?: boolean,
|
21
25
|
id?: string,
|
@@ -30,14 +34,22 @@ type ButtonPropTypes = {
|
|
30
34
|
type?: 'inline' | null,
|
31
35
|
htmlType?: 'submit' | 'reset' | 'button' | undefined,
|
32
36
|
value?: string | null,
|
33
|
-
variant?: 'primary' | 'secondary' | 'link',
|
37
|
+
variant?: 'primary' | 'secondary' | 'link'| 'reaction',
|
34
38
|
wrapperClass?: string,
|
35
39
|
} & GlobalProps
|
36
40
|
|
41
|
+
const isValidEmoji = (emoji: string) => {
|
42
|
+
// Using regular expression to check if the string is a valid emoji/emoji Unicode
|
43
|
+
const emojiRegex = /^(\p{Emoji}|\uFE0F)+$/u;
|
44
|
+
return emojiRegex.test(emoji);
|
45
|
+
};
|
46
|
+
|
37
47
|
const buttonClassName = (props: ButtonPropTypes) => {
|
38
48
|
const {
|
39
49
|
disabled = false,
|
40
50
|
fullWidth = false,
|
51
|
+
highlight,
|
52
|
+
icon,
|
41
53
|
loading = false,
|
42
54
|
type = 'inline',
|
43
55
|
variant = 'primary',
|
@@ -52,6 +64,8 @@ const buttonClassName = (props: ButtonPropTypes) => {
|
|
52
64
|
className += disabled ? '_disabled' : '_enabled'
|
53
65
|
className += loading ? '_loading' : ''
|
54
66
|
className += `${size !== null ? ` size_${size}` : ''}`
|
67
|
+
className += `${variant === 'reaction' && !isValidEmoji(icon) ? ` reaction_default` : ''}`
|
68
|
+
className += `${variant === 'reaction' && highlight ? ` active` : ''}`
|
55
69
|
|
56
70
|
return className
|
57
71
|
}
|
@@ -61,6 +75,7 @@ const Button = (props: ButtonPropTypes) => {
|
|
61
75
|
aria = {},
|
62
76
|
children,
|
63
77
|
className,
|
78
|
+
count,
|
64
79
|
data = {},
|
65
80
|
disabled,
|
66
81
|
icon = null,
|
@@ -75,6 +90,7 @@ const Button = (props: ButtonPropTypes) => {
|
|
75
90
|
text,
|
76
91
|
htmlType = 'button',
|
77
92
|
value,
|
93
|
+
variant,
|
78
94
|
form = null
|
79
95
|
} = props
|
80
96
|
|
@@ -131,41 +147,77 @@ const Button = (props: ButtonPropTypes) => {
|
|
131
147
|
return null
|
132
148
|
}
|
133
149
|
|
134
|
-
const displayButton = () => {
|
135
|
-
if (link)
|
150
|
+
const displayButton = () => {
|
151
|
+
if (link) {
|
136
152
|
return (
|
137
153
|
<a
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
154
|
+
{...ariaProps}
|
155
|
+
{...dataProps}
|
156
|
+
className={css}
|
157
|
+
href={link}
|
158
|
+
id={id}
|
159
|
+
rel={target !== "child" ? "noreferrer" : null}
|
160
|
+
role="link"
|
161
|
+
tabIndex={tabIndex}
|
162
|
+
target={getTargetAttribute()}
|
147
163
|
>
|
148
164
|
{ifLoading()}
|
149
165
|
</a>
|
150
|
-
)
|
151
|
-
else
|
166
|
+
);
|
167
|
+
} else if (variant === "reaction") {
|
152
168
|
return (
|
153
169
|
<button
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
170
|
+
{...ariaProps}
|
171
|
+
{...dataProps}
|
172
|
+
className={css}
|
173
|
+
disabled={disabled}
|
174
|
+
form={form}
|
175
|
+
id={id}
|
176
|
+
onClick={onClick}
|
177
|
+
role="button"
|
178
|
+
tabIndex={tabIndex}
|
179
|
+
type={htmlType}
|
180
|
+
value={value}
|
181
|
+
>
|
182
|
+
{icon && isValidEmoji(icon) && (
|
183
|
+
<Flex align='center'>
|
184
|
+
<Icon icon={icon} />
|
185
|
+
{count && (
|
186
|
+
<Caption paddingLeft="xxs" size="xs">
|
187
|
+
{count}
|
188
|
+
</Caption>
|
189
|
+
)}
|
190
|
+
</Flex>
|
191
|
+
)
|
192
|
+
}
|
193
|
+
{
|
194
|
+
!isValidEmoji(icon) && (
|
195
|
+
<Icon icon={icon ? icon : "face-smile-plus"} />
|
196
|
+
)
|
197
|
+
}
|
198
|
+
|
199
|
+
|
200
|
+
</button>
|
201
|
+
);
|
202
|
+
} else {
|
203
|
+
return (
|
204
|
+
<button
|
205
|
+
{...ariaProps}
|
206
|
+
{...dataProps}
|
207
|
+
className={css}
|
208
|
+
disabled={disabled}
|
209
|
+
form={form}
|
210
|
+
id={id}
|
211
|
+
onClick={onClick}
|
212
|
+
role="button"
|
213
|
+
tabIndex={tabIndex}
|
214
|
+
type={htmlType}
|
215
|
+
value={value}
|
165
216
|
>
|
166
217
|
{ifLoading()}
|
167
218
|
</button>
|
168
|
-
)
|
219
|
+
);
|
220
|
+
}
|
169
221
|
}
|
170
222
|
|
171
223
|
return (
|
@@ -1,5 +1,21 @@
|
|
1
1
|
<%= content_tag(object.tag,
|
2
2
|
object.tag == "button" ? object.options : object.link_options) do %>
|
3
|
+
<% if object.variant === "reaction" %>
|
4
|
+
<% if icon && object.valid_emoji(object.icon) %>
|
5
|
+
<%= pb_rails("flex", props:{ align: "center" }) do %>
|
6
|
+
<%= pb_rails("icon", props: { icon: "#{icon}"}) %>
|
7
|
+
<% if object.count %>
|
8
|
+
<%= pb_rails("caption", props: { text: "#{count}", size: "xs", padding_left:"xxs" }) %>
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
<% elsif !object.valid_emoji(object.icon) %>
|
12
|
+
<% if object.icon %>
|
13
|
+
<%= pb_rails("icon", props: { icon: "#{icon}" }) %>
|
14
|
+
<% else %>
|
15
|
+
<%= pb_rails("icon", props: { icon: "face-smile-plus" }) %>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
18
|
+
<% else %>
|
3
19
|
<% if object.icon && !object.icon_right %>
|
4
20
|
<span>
|
5
21
|
<%= pb_rails("icon", props: { icon: "#{icon}", fixed_width: true, margin_right: "xs" }) %>
|
@@ -12,5 +28,6 @@
|
|
12
28
|
<%= pb_rails("icon", props: { icon: "#{icon}", fixed_width: true, margin_left: "xs" }) %>
|
13
29
|
</span>
|
14
30
|
<% end %>
|
31
|
+
<% end %>
|
15
32
|
|
16
33
|
<% end %>
|
@@ -16,8 +16,11 @@ module Playbook
|
|
16
16
|
prop :new_window, type: Playbook::Props::Boolean,
|
17
17
|
default: false
|
18
18
|
prop :variant, type: Playbook::Props::Enum,
|
19
|
-
values: %w[primary secondary link],
|
19
|
+
values: %w[primary secondary link reaction],
|
20
20
|
default: "primary"
|
21
|
+
prop :count, type: Playbook::Props::Number
|
22
|
+
prop :highlight, type: Playbook::Props::Boolean,
|
23
|
+
default: false
|
21
24
|
prop :target
|
22
25
|
prop :text
|
23
26
|
prop :type
|
@@ -63,9 +66,14 @@ module Playbook
|
|
63
66
|
link ? "a" : "button"
|
64
67
|
end
|
65
68
|
|
69
|
+
def valid_emoji(icon)
|
70
|
+
emoji_regex = /\p{Emoji}/
|
71
|
+
emoji_regex.match?(icon)
|
72
|
+
end
|
73
|
+
|
66
74
|
def classname
|
67
75
|
button_class = generate_classname("pb_button_kit", variant, full_width_class, disabled_class, loading_class)
|
68
|
-
button_class + size_class
|
76
|
+
button_class + size_class + default_reaction_class + highlight_active
|
69
77
|
end
|
70
78
|
|
71
79
|
private
|
@@ -85,6 +93,14 @@ module Playbook
|
|
85
93
|
def size_class
|
86
94
|
size ? " size_#{size}" : ""
|
87
95
|
end
|
96
|
+
|
97
|
+
def default_reaction_class
|
98
|
+
variant === "reaction" && !object.valid_emoji(object.icon) ? " reaction_default" : ""
|
99
|
+
end
|
100
|
+
|
101
|
+
def highlight_active
|
102
|
+
variant === "reaction" && object.highlight ? " active" : ""
|
103
|
+
end
|
88
104
|
end
|
89
105
|
end
|
90
106
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<%= pb_rails("button", props: { count: 153, highlight: false, icon: "🎉", classname: "count", id: "reaction-button-highlight", variant: "reaction" }) %>
|
2
|
+
<%= pb_rails("button", props: { count: 5, icon: "😍", variant: "reaction", margin_left: "lg" }) %>
|
3
|
+
<%= pb_rails("button", props: { variant: "reaction", margin_left: "lg" }) %>
|
4
|
+
<%= pb_rails("button", props: { icon: "user", variant: "reaction", margin_left: "lg" }) %>
|
5
|
+
|
6
|
+
|
7
|
+
<script>
|
8
|
+
function renderButtonReaction() {
|
9
|
+
|
10
|
+
let highlightActive = false;
|
11
|
+
|
12
|
+
function toggleHighlight() {
|
13
|
+
let reactionCount = 153;
|
14
|
+
console.log("toggleHighlight", highlightActive)
|
15
|
+
highlightActive = !highlightActive;
|
16
|
+
const innerCountElement = document.querySelector(".count .pb_caption_kit_xs.pl_xxs")
|
17
|
+
const firstButton = document.getElementById("reaction-button-highlight")
|
18
|
+
firstButton.classList.add(highlightActive && "active")
|
19
|
+
firstButton.classList.remove(!highlightActive && "active")
|
20
|
+
innerCountElement.innerHTML = highlightActive ? reactionCount + 1 : reactionCount;
|
21
|
+
console.log("element", innerCountElement)
|
22
|
+
}
|
23
|
+
|
24
|
+
const button1 = document.getElementById("reaction-button-highlight")
|
25
|
+
button1.addEventListener("click", toggleHighlight);
|
26
|
+
|
27
|
+
}
|
28
|
+
renderButtonReaction();
|
29
|
+
</script>
|
30
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import React, {useState} from "react"
|
2
|
+
import { Button } from "../../"
|
3
|
+
|
4
|
+
const ButtonReaction = (props) => {
|
5
|
+
|
6
|
+
const [highlightActive, setHighlightActive] =useState(false)
|
7
|
+
const reactionCount = 153
|
8
|
+
|
9
|
+
return (
|
10
|
+
<div>
|
11
|
+
<Button
|
12
|
+
count={highlightActive ? (reactionCount + 1) : reactionCount}
|
13
|
+
highlight = {highlightActive}
|
14
|
+
icon="🎉"
|
15
|
+
onClick={()=> setHighlightActive(!highlightActive)}
|
16
|
+
tabIndex={0}
|
17
|
+
variant="reaction"
|
18
|
+
{...props}
|
19
|
+
/>
|
20
|
+
<Button
|
21
|
+
count={5}
|
22
|
+
icon="😍"
|
23
|
+
marginLeft='lg'
|
24
|
+
tabIndex={0}
|
25
|
+
variant="reaction"
|
26
|
+
{...props}
|
27
|
+
/>
|
28
|
+
<Button
|
29
|
+
marginLeft='lg'
|
30
|
+
tabIndex={0}
|
31
|
+
variant="reaction"
|
32
|
+
{...props}
|
33
|
+
/>
|
34
|
+
<Button
|
35
|
+
icon="user"
|
36
|
+
marginLeft='lg'
|
37
|
+
tabIndex={0}
|
38
|
+
variant="reaction"
|
39
|
+
{...props}
|
40
|
+
/>
|
41
|
+
|
42
|
+
|
43
|
+
</div>
|
44
|
+
)
|
45
|
+
}
|
46
|
+
|
47
|
+
export default ButtonReaction
|
@@ -0,0 +1,3 @@
|
|
1
|
+
The `reaction` variant accepts any HTML Emoji or it's hexa/decimal ref (see [here](https://www.w3schools.com/charsets/ref_emoji.asp)) as a string within the `icon` prop. If nothing is passed to the icon prop, the default reaction button will be displayed as seen in the third example. The default reaction button will also be rendered if a Fontawesome icon (not an Emoji) is passed to the `icon` prop of a `reaction` variant, but the default "smiley +" icon will be replaced with the named icon.
|
2
|
+
|
3
|
+
Reaction buttons also accept two additional (optional) props: `count`, which accepts a number (i.e., a count of reactions) to be displayed next to the Emoji; and `highlight`, which is a boolean that if true, displays the 'active' state for the button. Click the first reaction button to see this in action!
|
@@ -1,6 +1,7 @@
|
|
1
1
|
examples:
|
2
2
|
rails:
|
3
3
|
- button_default: Button Variants
|
4
|
+
- button_reaction: Reaction Button
|
4
5
|
- button_full_width: Button Full Width
|
5
6
|
- button_link: Button Links
|
6
7
|
- button_loading: Button Loading
|
@@ -13,6 +14,7 @@ examples:
|
|
13
14
|
|
14
15
|
react:
|
15
16
|
- button_default: Button Variants
|
17
|
+
- button_reaction: Reaction Button
|
16
18
|
- button_full_width: Button Full Width
|
17
19
|
- button_link: Button Links
|
18
20
|
- button_loading: Button Loading
|
@@ -8,4 +8,5 @@ export { default as ButtonAccessibility } from './_button_accessibility.jsx'
|
|
8
8
|
export { default as ButtonOptions } from './_button_options.jsx'
|
9
9
|
export { default as ButtonSize } from './_button_size.jsx'
|
10
10
|
export { default as ButtonForm } from './_button_form.jsx'
|
11
|
-
export { default as ButtonHover } from './_button_hover.jsx'
|
11
|
+
export { default as ButtonHover } from './_button_hover.jsx'
|
12
|
+
export {default as ButtonReaction } from './_button_reaction.jsx'
|
@@ -21,15 +21,18 @@ const dialogHelper = () => {
|
|
21
21
|
|
22
22
|
// Close dialog box on outside click
|
23
23
|
dialogs.forEach((dialogElement) => {
|
24
|
-
dialogElement.addEventListener("
|
24
|
+
dialogElement.addEventListener("mousedown", (event) => {
|
25
25
|
const dialogParentDataset = dialogElement.parentElement.dataset
|
26
26
|
if (dialogParentDataset.overlayClick === "overlay_close") return
|
27
27
|
|
28
|
-
const
|
28
|
+
const dialogModal = event.target.getBoundingClientRect()
|
29
|
+
const clickedOutsideDialogModal = dialogModal.left > event.clientX ||
|
30
|
+
dialogModal.right < event.clientX ||
|
31
|
+
dialogModal.top > event.clientY ||
|
32
|
+
dialogModal.bottom < event.clientY
|
29
33
|
|
30
|
-
if (
|
34
|
+
if (clickedOutsideDialogModal) {
|
31
35
|
dialogElement.close()
|
32
|
-
event.stopPropagation()
|
33
36
|
}
|
34
37
|
})
|
35
38
|
})
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<% if object.custom_icon %>
|
2
2
|
<%= object.render_svg(object.custom_icon) %>
|
3
3
|
<% elsif object.valid_emoji(object.icon) %>
|
4
|
-
<span class="
|
4
|
+
<span class="pb_icon_kit_emoji"><%= object.icon.html_safe %></span>
|
5
5
|
<% else %>
|
6
6
|
<%= content_tag(:i, nil,
|
7
7
|
id: object.id,
|