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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1468abb19e4ac525eed445f416c38c07658000bf453c5a0b874be54c64ecdb3
4
- data.tar.gz: b74c0cb81586fcb391013b1f6d46414a36dc98196fbec2d933359b978fee1483
3
+ metadata.gz: 73dae18aff8f323e035348eead47c0a135a2e639eff5ef2d915e0f43ede1e5ed
4
+ data.tar.gz: b5db0c63a610c78a17762f84420fef70c1362bf29246a475a1283b509a14f4d8
5
5
  SHA512:
6
- metadata.gz: 4e2bb9dad3c8d08921eea44a7e9a3d8ec5832bbcce47f81b75c65fc0bd7eda0218ce328b9820f4bd530a2fb28233816bfdf404762700cb48ab98aee2c16d4308
7
- data.tar.gz: 2c4fb8680f9f5e13e9462bc1ec206edf07a773739c7c282b32d7ed1c279ac3ab0ed42d4da46829328010f4e33159823325188e99941e8d144807384be861f794
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
- {...ariaProps}
139
- {...dataProps}
140
- className={css}
141
- href={link}
142
- id={id}
143
- rel={target !== 'child' ? 'noreferrer' : null}
144
- role="link"
145
- tabIndex={tabIndex}
146
- target={getTargetAttribute()}
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
- {...ariaProps}
155
- {...dataProps}
156
- className={css}
157
- disabled={disabled}
158
- form={form}
159
- id={id}
160
- onClick={onClick}
161
- role="button"
162
- tabIndex={tabIndex}
163
- type={htmlType}
164
- value={value}
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: "&#127881;", 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="&#127881;"
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("click", (event) => {
24
+ dialogElement.addEventListener("mousedown", (event) => {
25
25
  const dialogParentDataset = dialogElement.parentElement.dataset
26
26
  if (dialogParentDataset.overlayClick === "overlay_close") return
27
27
 
28
- const clickedOutsideDialogBox = event.target.classList.contains("pb_dialog_rails")
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 (clickedOutsideDialogBox) {
34
+ if (clickedOutsideDialogModal) {
31
35
  dialogElement.close()
32
- event.stopPropagation()
33
36
  }
34
37
  })
35
38
  })
@@ -6,3 +6,7 @@ svg.pb_custom_icon {
6
6
  fill: currentColor;
7
7
  }
8
8
  }
9
+
10
+ .pb_icon_kit_emoji {
11
+ font-family: monospace;
12
+ }
@@ -95,9 +95,8 @@ const Icon = (props: IconProps) => {
95
95
  )
96
96
 
97
97
  const classesEmoji = classnames(
98
- 'pb_icon_kit',
98
+ 'pb_icon_kit_emoji',
99
99
  globalProps(props),
100
- 'icon_circle_emoji',
101
100
  className
102
101
  )
103
102
 
@@ -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="pb_icon_kit icon_circle_emoji"><%= object.icon.html_safe %></span>
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,