playbook_ui 12.29.0 → 12.30.0.pre.alpha.PLAY906multilevelselectedidsprop902

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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_icon/_icon.tsx +27 -1
  3. data/app/pb_kits/playbook/pb_icon/icon.html.erb +2 -0
  4. data/app/pb_kits/playbook/pb_icon/icon.rb +5 -0
  5. data/app/pb_kits/playbook/pb_icon_circle/_icon_circle.scss +5 -0
  6. data/app/pb_kits/playbook/pb_icon_circle/_icon_circle.tsx +5 -3
  7. data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_color.html.erb +13 -7
  8. data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_default.html.erb +1 -1
  9. data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_emoji.html.erb +16 -0
  10. data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_emoji.jsx +31 -0
  11. data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_emoji.md +1 -0
  12. data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_sizes.html.erb +5 -5
  13. data/app/pb_kits/playbook/pb_icon_circle/docs/_icon_circle_sizes.jsx +6 -0
  14. data/app/pb_kits/playbook/pb_icon_circle/docs/example.yml +3 -0
  15. data/app/pb_kits/playbook/pb_icon_circle/docs/index.js +1 -0
  16. data/app/pb_kits/playbook/pb_icon_circle/icon_circle.html.erb +1 -1
  17. data/app/pb_kits/playbook/pb_icon_circle/icon_circle.rb +2 -0
  18. data/app/pb_kits/playbook/pb_icon_circle/icon_circle.test.js +97 -0
  19. data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +56 -27
  20. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss +1 -2
  21. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +19 -31
  22. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.md +3 -1
  23. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb +7 -0
  24. data/app/pb_kits/playbook/pb_table/docs/_table_data_table.html.erb +0 -14
  25. data/app/pb_kits/playbook/pb_table/docs/_table_data_table.md +1 -0
  26. data/app/pb_kits/playbook/pb_table/styles/_structure.scss +12 -0
  27. data/app/pb_kits/playbook/utilities/globalProps.ts +9 -4
  28. data/app/pb_kits/playbook/utilities/test/globalProps/flexGrow.test.js +1 -1
  29. data/app/pb_kits/playbook/utilities/test/globalProps/flexShrink.test.js +1 -1
  30. data/dist/playbook-rails.js +6 -6
  31. data/lib/playbook/version.rb +2 -2
  32. metadata +12 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d6b07b61b7b29b66f8649816faa1c0cf9f658df0f80ca5c580541f384efe3e3
4
- data.tar.gz: af3e2140059844f20d5289e2d56ba87d26c0df0fc2061a271648a2b26d913171
3
+ metadata.gz: a8d8c8cd4aa096608acbf4eed675c36c238baa86d159aaefbc0f757084a5a4a4
4
+ data.tar.gz: 287dd12a2a579011dd57ae22d51ee874b1d3823647e3d95701a201507afb02e7
5
5
  SHA512:
6
- metadata.gz: e3154d4f0a1cbc50826fc27e321bb09debfa07735a91b31fe9c99a459b979585a349242bc2f88e12e3d149d8c87c378e1a99faa6872969af257f84df7c1ad1fc
7
- data.tar.gz: 5f8e5f58faaaaac3bdc5a97f09cbe21765f2159918d5047825589dbac05a7c71d7321874867d64963c71910f343a93b7298a38af00dcab42e4e50e09e918525e
6
+ metadata.gz: 18f3b68f512177e50e2146c9018e52535928c142d69f3e54b2c368d7655d1c638c5432d2e23ade2f4de5c41862a349dbf6b8325cd4d7cd9515ea0ea2b242a6fe
7
+ data.tar.gz: 2a44c4ecbf272b2ae90b49616048b8bbc6f7f641e0741dbdb26cfc92c5dce5b49724611c4b9aacb7f74017c89d1f891d2d54a148279322b80e54d455cb674738
@@ -93,10 +93,23 @@ const Icon = (props: IconProps) => {
93
93
  className
94
94
  )
95
95
 
96
+ const classesEmoji = classnames(
97
+ 'pb_icon_kit',
98
+ globalProps(props),
99
+ 'icon_circle_emoji',
100
+ className
101
+ )
102
+
96
103
  aria.label ? null : aria.label = `${icon} icon`
97
104
  const ariaProps: {[key: string]: any} = buildAriaProps(aria)
98
105
  const dataProps: {[key: string]: any} = buildDataProps(data)
99
106
 
107
+ const isValidEmoji = (emoji: string) => {
108
+ // Using regular expression to check if the string is a valid emoji/emoji Unicode
109
+ const emojiRegex = /^(\p{Emoji}|\uFE0F)+$/u;
110
+ return emojiRegex.test(emoji);
111
+ };
112
+
100
113
  // Add a conditional here to show only the SVG if custom
101
114
  const displaySVG = (customIcon: any) => {
102
115
  if (customIcon)
@@ -111,6 +124,19 @@ const Icon = (props: IconProps) => {
111
124
  }
112
125
  </>
113
126
  )
127
+ else if (isValidEmoji(icon))
128
+ return (
129
+ <>
130
+ <span
131
+ {...dataProps}
132
+ className={classesEmoji}
133
+ id={id}
134
+ >
135
+ {icon}
136
+ </span>
137
+ </>
138
+ )
139
+
114
140
  else
115
141
  return (
116
142
  <>
@@ -134,4 +160,4 @@ const Icon = (props: IconProps) => {
134
160
  )
135
161
  }
136
162
 
137
- export default Icon
163
+ export default Icon
@@ -1,5 +1,7 @@
1
1
  <% if object.custom_icon %>
2
2
  <%= object.render_svg(object.custom_icon) %>
3
+ <% elsif object.valid_emoji(object.icon) %>
4
+ <span class="pb_icon_kit icon_circle_emoji"><%= object.icon.html_safe %></span>
3
5
  <% else %>
4
6
  <%= content_tag(:i, nil,
5
7
  id: object.id,
@@ -38,6 +38,11 @@ module Playbook
38
38
  prop :spin, type: Playbook::Props::Boolean,
39
39
  default: false
40
40
 
41
+ def valid_emoji(icon)
42
+ emoji_regex = /\p{Emoji}/
43
+ emoji_regex.match?(icon)
44
+ end
45
+
41
46
  def classname
42
47
  generate_classname(
43
48
  "pb_icon_kit",
@@ -20,6 +20,11 @@ $pb_icon_circle_sizes: (
20
20
  object-fit: cover;
21
21
  overflow: hidden;
22
22
  position: relative;
23
+ // font-family set to sans-serif ONLY for emojis.
24
+ //Needed to fix misalignment issue caused by Proxima font
25
+ .icon_circle_emoji {
26
+ font-family: monospace;
27
+ }
23
28
 
24
29
  i,
25
30
  svg {
@@ -32,6 +32,7 @@ const IconCircle = (props: IconCircleProps) => {
32
32
  const dataProps = buildDataProps(data)
33
33
  const classes = classnames(buildCss('pb_icon_circle_kit', size, variant), globalProps(props), className)
34
34
 
35
+
35
36
  return (
36
37
  <div
37
38
  {...ariaProps}
@@ -39,12 +40,13 @@ const IconCircle = (props: IconCircleProps) => {
39
40
  className={classes}
40
41
  id={id}
41
42
  >
42
- <Icon
43
+ <Icon
43
44
  dark={dark}
44
45
  icon={icon}
45
- />
46
+ />
47
+
46
48
  </div>
47
49
  )
48
50
  }
49
51
 
50
- export default IconCircle
52
+ export default IconCircle
@@ -1,35 +1,41 @@
1
1
  <%= pb_rails("icon_circle", props: {
2
- icon: "comment",
2
+ icon: "rocket",
3
3
  variant: "royal",
4
4
  size: "sm"
5
5
  }) %>
6
+ <br />
6
7
  <%= pb_rails("icon_circle", props: {
7
- icon: "archive",
8
+ icon: "rocket",
8
9
  variant: "orange",
9
10
  size: "sm"
10
11
  }) %>
12
+ <br />
11
13
  <%= pb_rails("icon_circle", props: {
12
- icon: "arrow-alt-right",
14
+ icon: "rocket",
13
15
  variant: "purple",
14
16
  size: "sm"
15
17
  }) %>
18
+ <br />
16
19
  <%= pb_rails("icon_circle", props: {
17
- icon: "cloud",
20
+ icon: "rocket",
18
21
  variant: "teal",
19
22
  size: "sm"
20
23
  }) %>
24
+ <br />
21
25
  <%= pb_rails("icon_circle", props: {
22
- icon: "award",
26
+ icon: "rocket",
23
27
  variant: "red",
24
28
  size: "sm"
25
29
  }) %>
30
+ <br />
26
31
  <%= pb_rails("icon_circle", props: {
27
- icon: "bolt",
32
+ icon: "rocket",
28
33
  variant: "yellow",
29
34
  size: "sm"
30
35
  }) %>
36
+ <br />
31
37
  <%= pb_rails("icon_circle", props: {
32
- icon: "calendar",
38
+ icon: "rocket",
33
39
  variant: "green",
34
40
  size: "sm"
35
41
  }) %>
@@ -1,3 +1,3 @@
1
1
  <%= pb_rails("icon_circle", props: {
2
- icon: "user"
2
+ icon: "rocket"
3
3
  }) %>
@@ -0,0 +1,16 @@
1
+ <%= pb_rails("icon_circle", props: {
2
+ icon: "😁",
3
+ size:"sm"
4
+ }) %>
5
+ <br />
6
+ <%= pb_rails("icon_circle", props: {
7
+ icon: "&#128525;",
8
+ size:"md",
9
+ variant: "red"
10
+ }) %>
11
+ <br />
12
+ <%= pb_rails("icon_circle", props: {
13
+ icon: '&#x1F389;',
14
+ size: "lg",
15
+ variant: "teal"
16
+ }) %>
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+
3
+ import IconCircle from '../_icon_circle'
4
+
5
+ const IconCircleEmoji = (props) => {
6
+ return (
7
+ <div>
8
+ <IconCircle
9
+ icon="😁"
10
+ size="sm"
11
+ {...props}
12
+ />
13
+ <br/>
14
+ <IconCircle
15
+ icon="&#128525;"
16
+ size="md"
17
+ variant="red"
18
+ {...props}
19
+ />
20
+ <br/>
21
+ <IconCircle
22
+ icon="&#x1F389;"
23
+ size="lg"
24
+ variant="teal"
25
+ {...props}
26
+ />
27
+ </div>
28
+ )
29
+ }
30
+
31
+ export default IconCircleEmoji
@@ -0,0 +1 @@
1
+ The Icon Circle also allows you to pass in an HTML emoji in place of an icon if needed. To do so, pass any emoji or its hexa/decimal ref (see [here](https://www.w3schools.com/charsets/ref_emoji.asp)) as a string to the `icon` prop as shown in the code snippet below.
@@ -1,24 +1,24 @@
1
1
  <%= pb_rails("icon_circle", props: {
2
- icon: "comment",
2
+ icon: "rocket",
3
3
  size: "xs"
4
4
  }) %>
5
5
  <br />
6
6
  <%= pb_rails("icon_circle", props: {
7
- icon: "comment",
7
+ icon: "rocket",
8
8
  size: "sm"
9
9
  }) %>
10
10
  <br />
11
11
  <%= pb_rails("icon_circle", props: {
12
- icon: "comment",
12
+ icon: "rocket",
13
13
  size: "md"
14
14
  }) %>
15
15
  <br />
16
16
  <%= pb_rails("icon_circle", props: {
17
- icon: "comment",
17
+ icon: "rocket",
18
18
  size: "lg"
19
19
  }) %>
20
20
  <br />
21
21
  <%= pb_rails("icon_circle", props: {
22
- icon: "comment",
22
+ icon: "rocket",
23
23
  size: "xl"
24
24
  }) %>
@@ -4,6 +4,12 @@ import { IconCircle } from '../..'
4
4
  const IconCircleSizes = (props) => {
5
5
  return (
6
6
  <div>
7
+ <IconCircle
8
+ icon="rocket"
9
+ size="xs"
10
+ {...props}
11
+ />
12
+ <br />
7
13
  <IconCircle
8
14
  icon="rocket"
9
15
  size="sm"
@@ -4,8 +4,11 @@ examples:
4
4
  - icon_circle_default: Default
5
5
  - icon_circle_sizes: Size
6
6
  - icon_circle_color: Color
7
+ - icon_circle_emoji: With Emoji
8
+
7
9
 
8
10
  react:
9
11
  - icon_circle_default: Default
10
12
  - icon_circle_sizes: Size
11
13
  - icon_circle_color: Color
14
+ - icon_circle_emoji: With Emoji
@@ -1,3 +1,4 @@
1
1
  export { default as IconCircleColor } from './_icon_circle_color.jsx'
2
2
  export { default as IconCircleDefault } from './_icon_circle_default.jsx'
3
3
  export { default as IconCircleSizes } from './_icon_circle_sizes.jsx'
4
+ export { default as IconCircleEmoji } from './_icon_circle_emoji.jsx'
@@ -3,5 +3,5 @@
3
3
  class: object.classname,
4
4
  data: object.data,
5
5
  id: object.id) do %>
6
- <%= pb_rails("icon", props: { dark: object.dark, icon: object.icon, fixed_width: true }) %>
6
+ <%= pb_rails("icon", props: { dark: object.dark, icon: object.icon, fixed_width: true }) %>
7
7
  <% end %>
@@ -4,6 +4,8 @@ module Playbook
4
4
  module PbIconCircle
5
5
  class IconCircle < Playbook::KitBase
6
6
  prop :icon, required: true
7
+ prop :emoji, type: Playbook::Props::String,
8
+ default: ""
7
9
  prop :size, type: Playbook::Props::Enum,
8
10
  values: %w[xs sm md base lg xl],
9
11
  default: "md"
@@ -0,0 +1,97 @@
1
+ import React from 'react'
2
+ import { render, screen, cleanup } from '../utilities/test-utils'
3
+
4
+ import IconCircle from './_icon_circle'
5
+
6
+ const testId = "icon-circle-kit"
7
+
8
+ describe("IconCircle Kit", () => {
9
+ test("renders classname", () => {
10
+ render(
11
+ <IconCircle
12
+ data={{ testid: testId }}
13
+ icon="user"
14
+ size="md"
15
+ />
16
+ )
17
+
18
+ const kit = screen.getByTestId(testId)
19
+ expect(kit).toHaveClass("pb_icon_circle_kit_md_default")
20
+ })
21
+
22
+ test("renders icon", () => {
23
+ render(
24
+ <IconCircle
25
+ data={{ testid: testId }}
26
+ icon="user"
27
+ size="md"
28
+ />
29
+ )
30
+
31
+ const kit = screen.getByTestId(testId)
32
+ const icon = kit.querySelector('.pb_icon_kit')
33
+ expect(icon).toBeInTheDocument()
34
+ })
35
+
36
+ test("renders emoji", () => {
37
+ render(
38
+ <IconCircle
39
+ data={{ testid: testId }}
40
+ icon="&#128525;"
41
+ size="md"
42
+ />
43
+ )
44
+
45
+ const kit = screen.getByTestId(testId)
46
+ expect(kit).toHaveTextContent("😍")
47
+ })
48
+
49
+ test('displays color variants', () => {
50
+ [
51
+ "default",
52
+ "royal",
53
+ "blue",
54
+ "purple",
55
+ "teal",
56
+ "red",
57
+ "yellow",
58
+ "green"
59
+ ].forEach((colorVariant) => {
60
+ render(
61
+ <IconCircle
62
+ data={{ testid: testId }}
63
+ icon="rocket"
64
+ size="sm"
65
+ variant={colorVariant}
66
+ />
67
+ )
68
+ const kit = screen.getByTestId(testId)
69
+ expect(kit).toHaveClass(`pb_icon_circle_kit_sm_${colorVariant}`)
70
+
71
+ cleanup()
72
+ })
73
+ })
74
+
75
+ test('displays size as expected', () => {
76
+ [
77
+ "xs",
78
+ "sm",
79
+ "md",
80
+ "lg",
81
+ "xl"
82
+ ].forEach((sizeVariant) => {
83
+ render(
84
+ <IconCircle
85
+ data={{ testid: testId }}
86
+ icon="rocket"
87
+ size={sizeVariant}
88
+ />
89
+ )
90
+ const kit = screen.getByTestId(testId)
91
+ expect(kit).toHaveClass(`pb_icon_circle_kit_${sizeVariant}_default`)
92
+
93
+ cleanup()
94
+ })
95
+ })
96
+
97
+ })
@@ -6,11 +6,11 @@ export const getAncestorsOfUnchecked = (
6
6
  if (item.parent_id) {
7
7
  const ancestor = filterFormattedDataById(data, item.parent_id);
8
8
  ancestor[0].checked = false;
9
- ancestor[0].parent_id && getAncestorsOfUnchecked(data, ancestor[0])
9
+ ancestor[0].parent_id && getAncestorsOfUnchecked(data, ancestor[0]);
10
10
  }
11
11
  return data;
12
12
  };
13
-
13
+
14
14
  //function is going over formattedData and returning all objects that match the
15
15
  //id of the clicked item from the dropdown
16
16
  export const filterFormattedDataById = (
@@ -20,9 +20,9 @@ export const filterFormattedDataById = (
20
20
  const matched: { [key: string]: any }[] = [];
21
21
  const recursiveSearch = (data: { [key: string]: any }[], term: string) => {
22
22
  for (const item of data) {
23
- if (item.id.toLowerCase() === (term.toLowerCase())) {
23
+ if (item.id.toLowerCase() === term.toLowerCase()) {
24
24
  matched.push(item);
25
- return
25
+ return;
26
26
  }
27
27
 
28
28
  if (item.children && item.children.length > 0) {
@@ -75,24 +75,29 @@ export const getCheckedItems = (
75
75
  });
76
76
  return checkedItems;
77
77
  };
78
-
79
- export const getDefaultCheckedItems = (treeData:{ [key: string]: any }[]) => {
78
+
79
+ export const getDefaultCheckedItems = (treeData: { [key: string]: any }[]) => {
80
80
  const checkedDefault: { [key: string]: any }[] = [];
81
81
 
82
- const traverseTree = (items:{ [key: string]: any }[]) => {
82
+ const traverseTree = (items: { [key: string]: any }[]) => {
83
83
  if (!Array.isArray(items)) {
84
84
  return;
85
85
  }
86
- items.forEach((item:{ [key: string]: any }) => {
86
+ items.forEach((item: { [key: string]: any }) => {
87
87
  if (item.checked) {
88
88
  if (item.children && item.children.length > 0) {
89
- const uncheckedChildren = item.children.filter((child:{ [key: string]: any }) => !child.checked);
89
+ const uncheckedChildren = item.children.filter(
90
+ (child: { [key: string]: any }) => !child.checked
91
+ );
90
92
  if (uncheckedChildren.length === 0) {
91
93
  checkedDefault.push(item);
92
94
  return;
93
95
  }
94
96
  } else {
95
- const parent = items.find((parentItem:{ [key: string]: any }) => parentItem.id === item.parentId);
97
+ const parent = items.find(
98
+ (parentItem: { [key: string]: any }) =>
99
+ parentItem.id === item.parentId
100
+ );
96
101
  if (!parent || !parent.checked) {
97
102
  checkedDefault.push(item);
98
103
  }
@@ -112,23 +117,47 @@ export const getDefaultCheckedItems = (treeData:{ [key: string]: any }[]) => {
112
117
 
113
118
  export const recursiveCheckParent = (
114
119
  item: { [key: string]: any },
115
- data:any
120
+ data: any
116
121
  ) => {
117
122
  if (item.parent_id !== null) {
118
- const parent = filterFormattedDataById(data, item.parent_id);
119
- const allChildrenChecked = parent[0].children.every(
120
- (child: { [key: string]: any }) => child.checked
121
- );
122
- if (allChildrenChecked) {
123
- parent[0].checked = true;
124
- const parentHasParent = parent[0].parent_id !== null;
125
- if (parentHasParent) {
126
- recursiveCheckParent(
127
- parent[0],
128
- data
129
- );
123
+ const parent = filterFormattedDataById(data, item.parent_id);
124
+ const allChildrenChecked = parent[0].children.every(
125
+ (child: { [key: string]: any }) => child.checked
126
+ );
127
+ if (allChildrenChecked) {
128
+ parent[0].checked = true;
129
+ const parentHasParent = parent[0].parent_id !== null;
130
+ if (parentHasParent) {
131
+ recursiveCheckParent(parent[0], data);
132
+ }
133
+ }
134
+ }
135
+ return data;
136
+ };
137
+
138
+ export const getExpandedItems = (treeData: { [key: string]: string }[]) => {
139
+ let expandedItems: any[] = [];
140
+
141
+ const traverse = (items: string | any[], ancestors: any[] = []) => {
142
+ for (let i = 0; i < items.length; i++) {
143
+ const item = items[i];
144
+ const itemAncestors = [...ancestors, item];
145
+
146
+ if (item.expanded) {
147
+ expandedItems.push(item.id);
148
+ }
149
+ if (Array.isArray(item.children)) {
150
+ const hasCheckedChildren = item.children.some(
151
+ (child: { [key: string]: string }) => child.checked
152
+ );
153
+ if (hasCheckedChildren) {
154
+ expandedItems.push(...itemAncestors.map((ancestor) => ancestor.id));
155
+ }
156
+ traverse(item.children, itemAncestors);
157
+ }
130
158
  }
131
- }
132
- }
133
- return data;
134
- }
159
+ };
160
+
161
+ traverse(treeData);
162
+ return expandedItems;
163
+ };
@@ -23,7 +23,7 @@
23
23
  .input_wrapper {
24
24
  background-color: $white;
25
25
  cursor: pointer;
26
- padding: $space_xs + 4 $space_sm;
26
+ padding: $space_xs + 1 $space_sm;
27
27
  border: 1px solid #e4e8f0;
28
28
  border-radius: $border_rad_heavier;
29
29
  display: flex;
@@ -36,7 +36,6 @@
36
36
  input {
37
37
  border: none;
38
38
  font-family: $font_family_base;
39
- padding: $space_xs;
40
39
  &:focus {
41
40
  outline: none;
42
41
  }