playbook_ui 13.32.0 → 13.33.0.pre.alpha.PLAY1454formpillicons3309

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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_bar_graph/docs/_bar_graph_custom.md +4 -0
  3. data/app/pb_kits/playbook/pb_collapsible/__snapshots__/collapsible.test.js.snap +1 -1
  4. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +12 -7
  5. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.html.erb +10 -0
  6. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.jsx +31 -0
  7. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_value.html.erb +10 -0
  8. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_value.jsx +31 -0
  9. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +4 -0
  10. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +3 -1
  11. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +4 -4
  12. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +11 -0
  13. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +1 -1
  14. data/app/pb_kits/playbook/pb_dropdown/index.js +54 -3
  15. data/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +112 -5
  16. data/app/pb_kits/playbook/pb_form_pill/_form_pill.test.jsx +64 -0
  17. data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +62 -18
  18. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_example.html.erb +5 -1
  19. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_example.jsx +1 -0
  20. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_icon.html.erb +5 -0
  21. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_icon.jsx +19 -0
  22. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_size.html.erb +2 -0
  23. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_size.jsx +2 -0
  24. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_tag.html.erb +4 -1
  25. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_tag.jsx +3 -2
  26. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_user.html.erb +2 -0
  27. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_user.jsx +2 -0
  28. data/app/pb_kits/playbook/pb_form_pill/docs/example.yml +2 -1
  29. data/app/pb_kits/playbook/pb_form_pill/docs/index.js +1 -1
  30. data/app/pb_kits/playbook/pb_form_pill/form_pill.html.erb +17 -10
  31. data/app/pb_kits/playbook/pb_form_pill/form_pill.rb +10 -1
  32. data/app/pb_kits/playbook/pb_icon/_icon.scss +210 -1
  33. data/app/pb_kits/playbook/pb_icon/_icon.tsx +100 -41
  34. data/app/pb_kits/playbook/pb_icon/icon.rb +33 -19
  35. data/app/pb_kits/playbook/pb_nav/_nav_item.test.js +2 -2
  36. data/app/pb_kits/playbook/pb_nav/docs/_tab_nav.html.erb +48 -0
  37. data/app/pb_kits/playbook/pb_nav/docs/_tab_nav.md +3 -0
  38. data/app/pb_kits/playbook/pb_nav/docs/example.yml +1 -0
  39. data/app/pb_kits/playbook/pb_nav/index.js +43 -0
  40. data/app/pb_kits/playbook/pb_nav/nav.rb +9 -0
  41. data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/MoreExtensionsDropdown.tsx +1 -1
  42. data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/ToolbarDropdown.tsx +1 -1
  43. data/app/pb_kits/playbook/pb_star_rating/_star_rating.scss +11 -2
  44. data/app/pb_kits/playbook/pb_star_rating/docs/_star_rating_interactive.html.erb +1 -0
  45. data/app/pb_kits/playbook/pb_star_rating/docs/example.yml +1 -1
  46. data/app/pb_kits/playbook/pb_star_rating/index.js +50 -0
  47. data/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb +25 -5
  48. data/app/pb_kits/playbook/pb_star_rating/star_rating.rb +6 -0
  49. data/app/pb_kits/playbook/pb_table/_table.tsx +1 -1
  50. data/app/pb_kits/playbook/pb_table/index.ts +4 -4
  51. data/app/pb_kits/playbook/pb_table/subcomponents/_table_body.tsx +1 -1
  52. data/app/pb_kits/playbook/pb_table/subcomponents/_table_cell.tsx +1 -1
  53. data/app/pb_kits/playbook/pb_table/subcomponents/_table_head.tsx +1 -1
  54. data/app/pb_kits/playbook/pb_table/subcomponents/_table_header.tsx +1 -1
  55. data/app/pb_kits/playbook/pb_table/subcomponents/_table_row.tsx +1 -1
  56. data/app/pb_kits/playbook/pb_table/table.test.js +2 -0
  57. data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +1 -1
  58. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_default.jsx +1 -1
  59. data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +45 -27
  60. data/app/pb_kits/playbook/pb_textarea/index.tsx +3 -3
  61. data/app/pb_kits/playbook/pb_time/_time.tsx +3 -3
  62. data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.tsx +1 -1
  63. data/app/pb_kits/playbook/pb_timeline/_item.tsx +1 -1
  64. data/app/pb_kits/playbook/pb_timeline/_timeline.tsx +1 -1
  65. data/app/pb_kits/playbook/pb_title_detail/_title_detail.tsx +10 -10
  66. data/app/pb_kits/playbook/pb_toggle/_toggle.tsx +1 -1
  67. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +2 -2
  68. data/app/pb_kits/playbook/pb_treemap_chart/_treemap_chart.tsx +1 -2
  69. data/app/pb_kits/playbook/pb_treemap_chart/treemapChart.test.js +2 -0
  70. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +3 -3
  71. data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.tsx +4 -4
  72. data/app/pb_kits/playbook/pb_typeahead/components/Control.tsx +11 -7
  73. data/app/pb_kits/playbook/pb_typeahead/components/IndicatorsContainer.tsx +8 -3
  74. data/app/pb_kits/playbook/pb_typeahead/components/MenuList.tsx +6 -1
  75. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +18 -19
  76. data/app/pb_kits/playbook/pb_typeahead/components/Option.tsx +6 -6
  77. data/app/pb_kits/playbook/pb_typeahead/components/Placeholder.tsx +6 -6
  78. data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +3 -3
  79. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_custom_menu_list.jsx +2 -0
  80. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_default.html.erb +22 -57
  81. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_pills_async.jsx +2 -2
  82. data/app/pb_kits/playbook/pb_typeahead/index.ts +31 -31
  83. data/app/pb_kits/playbook/pb_user/_user.tsx +1 -1
  84. data/app/pb_kits/playbook/pb_user_badge/_user_badge.tsx +6 -6
  85. data/app/pb_kits/playbook/pb_user_badge/badges/million-dollar.tsx +236 -235
  86. data/app/pb_kits/playbook/pb_user_badge/badges/veteran.tsx +1 -1
  87. data/app/pb_kits/playbook/pb_walkthrough/_walkthrough.tsx +68 -63
  88. data/app/pb_kits/playbook/pb_weekday_stacked/_weekday_stacked.tsx +2 -2
  89. data/app/pb_kits/playbook/playbook-rails.js +6 -0
  90. data/dist/menu.yml +1 -1
  91. data/dist/playbook-rails.js +7 -7
  92. data/lib/playbook/forms/builder/star_rating_field.rb +14 -0
  93. data/lib/playbook/forms/builder.rb +1 -0
  94. data/lib/playbook/version.rb +2 -2
  95. metadata +18 -6
  96. data/app/pb_kits/playbook/pb_icon/icon_aliases.json +0 -39
@@ -3,7 +3,6 @@ import classnames from 'classnames'
3
3
  import { buildAriaProps, buildDataProps, buildHtmlProps } from '../utilities/props'
4
4
  import { GlobalProps, globalProps } from '../utilities/globalProps'
5
5
  import { isValidEmoji } from '../utilities/validEmojiChecker'
6
- import aliasesJson from './icon_aliases.json'
7
6
 
8
7
  export type IconSizes = "lg"
9
8
  | "xs"
@@ -41,24 +40,75 @@ type IconProps = {
41
40
  spin?: boolean,
42
41
  } & GlobalProps
43
42
 
44
- type AliasType = string | string[];
45
-
46
- interface Aliases {
47
- [key: string]: AliasType;
43
+ const flipMap = {
44
+ fa: {
45
+ horizontal: 'fa-flip-horizontal',
46
+ vertical: 'fa-flip-vertical',
47
+ both: 'fa-flip-horizontal fa-flip-vertical',
48
+ none: ''
49
+ },
50
+ svg: {
51
+ horizontal: 'flip_horizontal',
52
+ vertical: 'flip_vertical',
53
+ both: 'flip_horizontal flip_vertical',
54
+ none: ''
55
+ }
48
56
  }
49
-
50
- interface AliasesJson {
51
- aliases: Aliases;
57
+ const pulseMap = {
58
+ fa: 'fa-pulse',
59
+ svg: 'pulse'
60
+ }
61
+ const spinMap = {
62
+ fa: 'fa-spin',
63
+ svg: 'spin'
64
+ }
65
+ const rotateMap = {
66
+ fa: {
67
+ 90: 'fa-rotate-90',
68
+ 180: 'fa-rotate-180',
69
+ 270: 'fa-rotate-270'
70
+ },
71
+ svg: {
72
+ 90: 'rotate_90',
73
+ 180: 'rotate_180',
74
+ 270: 'rotate_270'
75
+ }
52
76
  }
53
77
 
54
- const aliases: AliasesJson = aliasesJson;
55
-
78
+ const sizeMap = {
79
+ fa: {
80
+ "lg": "fa-lg",
81
+ "xs": "fa-xs",
82
+ "sm": "fa-sm",
83
+ "1x": "fa-1x",
84
+ "2x": "fa-2x",
85
+ "3x": "fa-3x",
86
+ "4x": "fa-4x",
87
+ "5x": "fa-5x",
88
+ "6x": "fa-6x",
89
+ "7x": "fa-7x",
90
+ "8x": "fa-8x",
91
+ "9x": "fa-9x",
92
+ "10x": "fa-10x",
93
+ "": ""
94
+ },
95
+ svg: {
96
+ "lg": "svg_lg",
97
+ "xs": "svg_xs",
98
+ "sm": "svg_sm",
99
+ "1x": "svg_1x",
100
+ "2x": "svg_2x",
101
+ "3x": "svg_3x",
102
+ "4x": "svg_4x",
103
+ "5x": "svg_5x",
104
+ "6x": "svg_6x",
105
+ "7x": "svg_7x",
106
+ "8x": "svg_8x",
107
+ "9x": "svg_9x",
108
+ "10x": "svg_10x",
109
+ "": ""
110
+ }
56
111
 
57
- const flipMap = {
58
- horizontal: 'fa-flip-horizontal',
59
- vertical: 'fa-flip-vertical',
60
- both: 'fa-flip-horizontal fa-flip-vertical',
61
- none: ""
62
112
  }
63
113
 
64
114
  declare global {
@@ -66,22 +116,6 @@ declare global {
66
116
  var PB_ICONS: {[key: string]: React.FunctionComponent<any>}
67
117
  }
68
118
 
69
- // Resolve alias function
70
- const resolveAlias = (icon: string): string => {
71
- const alias = aliases.aliases[icon];
72
-
73
- if (alias) {
74
- if (Array.isArray(alias)) {
75
- return alias[0];
76
- } else {
77
- return alias;
78
- }
79
- }
80
-
81
- return icon;
82
- };
83
-
84
-
85
119
  const Icon = (props: IconProps) => {
86
120
  const {
87
121
  aria = {},
@@ -104,8 +138,7 @@ const Icon = (props: IconProps) => {
104
138
  spin = false,
105
139
  } = props
106
140
 
107
- const resolvedIcon = resolveAlias(icon as string)
108
- let iconElement: ReactSVGElement | null = typeof(resolvedIcon) === "object" ? resolvedIcon : null
141
+ let iconElement: ReactSVGElement | null = typeof(icon) === "object" ? icon : null
109
142
 
110
143
  const faClasses = {
111
144
  'fa-border': border,
@@ -121,32 +154,58 @@ const Icon = (props: IconProps) => {
121
154
 
122
155
  if (!customIcon && !iconElement) {
123
156
  const PowerIcon: React.FunctionComponent<any> | undefined =
124
- window.PB_ICONS ? window.PB_ICONS[resolvedIcon as string] : null
157
+ window.PB_ICONS ? window.PB_ICONS[icon as string] : null
125
158
 
126
159
  if (PowerIcon) {
127
160
  iconElement = <PowerIcon /> as ReactSVGElement
128
161
  } else {
129
- faClasses[`fa-${resolvedIcon}`] = resolvedIcon as string
162
+ faClasses[`fa-${icon}`] = icon as string
130
163
  }
131
164
  }
132
165
 
133
- const classes = classnames(
134
- flipMap[flip],
166
+ const isFA = !iconElement && !customIcon
167
+
168
+ let classes = classnames(
135
169
  (!iconElement && !customIcon) ? 'pb_icon_kit' : '',
136
170
  (iconElement || customIcon) ? 'pb_custom_icon' : fontStyle,
137
171
  iconElement ? 'svg-inline--fa' : '',
138
- faClasses,
139
172
  globalProps(props),
140
173
  className
141
174
  )
142
175
 
176
+ const transformClasses = classnames(
177
+ flip ? flipMap[isFA ? 'fa' : 'svg'][flip] : null,
178
+ pulse ? pulseMap[isFA ? 'fa' : 'svg'] : null,
179
+ rotation ? rotateMap[isFA ? 'fa' : 'svg'][rotation] : null,
180
+ spin ? spinMap[isFA ? 'fa' : 'svg'] : null,
181
+ size ? sizeMap[isFA ? 'fa' : 'svg'][size] : null,
182
+ border ? isFA ? 'fa-border' : 'svg_border' : null,
183
+ fixedWidth ? isFA ? 'fa-fw' : 'svg_fw' : null,
184
+ inverse ? isFA ? 'fa-inverse' : 'svg_inverse' : null,
185
+ listItem ? isFA ? 'fa-li' : 'svg_li' : null,
186
+ pull ? isFA ? `fa-pull-${pull}` : `pull_${pull}` : null,
187
+ )
188
+ classes += ` ${transformClasses}`
189
+
190
+ if (isFA) {
191
+ const faClassList = {
192
+ 'fa-border': border,
193
+ 'fa-inverse': inverse,
194
+ 'fa-li': listItem,
195
+ [`fa-${size}`]: size,
196
+ [`fa-pull-${pull}`]: pull,
197
+ }
198
+ faClassList[`fa-${icon}`] = icon as string
199
+ classes += ` ${classnames(faClassList)}`
200
+ }
201
+
143
202
  const classesEmoji = classnames(
144
203
  'pb_icon_kit_emoji',
145
204
  globalProps(props),
146
205
  className
147
206
  )
148
207
 
149
- aria.label ? null : aria.label = `${resolvedIcon} icon`
208
+ aria.label ? null : aria.label = `${icon} icon`
150
209
  const ariaProps: {[key: string]: any} = buildAriaProps(aria)
151
210
  const dataProps: {[key: string]: any} = buildDataProps(data)
152
211
  const htmlProps = buildHtmlProps(htmlOptions)
@@ -168,7 +227,7 @@ const Icon = (props: IconProps) => {
168
227
  }
169
228
  </>
170
229
  )
171
- else if (isValidEmoji(resolvedIcon as string))
230
+ else if (isValidEmoji(icon as string))
172
231
  return (
173
232
  <>
174
233
  <span
@@ -177,7 +236,7 @@ const Icon = (props: IconProps) => {
177
236
  className={classesEmoji}
178
237
  id={id}
179
238
  >
180
- {resolvedIcon}
239
+ {icon}
181
240
  </span>
182
241
  </>
183
242
  )
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Style/HashLikeCase
4
-
5
3
  require "open-uri"
6
4
  require "json"
7
5
 
@@ -39,8 +37,6 @@ module Playbook
39
37
  prop :spin, type: Playbook::Props::Boolean,
40
38
  default: false
41
39
 
42
- ALIASES = JSON.parse(File.read(Playbook::Engine.root.join("app/pb_kits/playbook/pb_icon/icon_aliases.json")))["aliases"].freeze
43
-
44
40
  def valid_emoji?
45
41
  emoji_regex = /\p{Emoji}/
46
42
  emoji_regex.match?(icon)
@@ -82,6 +78,14 @@ module Playbook
82
78
  )
83
79
  end
84
80
 
81
+ def icon_alias_map
82
+ return unless Rails.application.config.respond_to?(:icon_alias_path)
83
+
84
+ base_path = Rails.application.config.icon_alias_path
85
+ json = File.read(Rails.root.join(base_path))
86
+ JSON.parse(json)["aliases"].freeze
87
+ end
88
+
85
89
  def asset_path
86
90
  return unless Rails.application.config.respond_to?(:icon_path)
87
91
 
@@ -111,7 +115,9 @@ module Playbook
111
115
  private
112
116
 
113
117
  def resolve_alias(icon)
114
- aliases = ALIASES[icon]
118
+ return icon unless icon_alias_map
119
+
120
+ aliases = icon_alias_map[icon]
115
121
  return icon unless aliases
116
122
 
117
123
  if aliases.is_a?(Array)
@@ -131,11 +137,13 @@ module Playbook
131
137
  end
132
138
 
133
139
  def border_class
134
- border ? "fa-border" : nil
140
+ prefix = is_svg? ? "svg_border" : "fa-border"
141
+ border ? prefix : nil
135
142
  end
136
143
 
137
144
  def fixed_width_class
138
- fixed_width ? "fa-fw" : nil
145
+ prefix = is_svg? ? "svg_fw" : "fa-fw"
146
+ fixed_width ? prefix : nil
139
147
  end
140
148
 
141
149
  def icon_class
@@ -143,38 +151,45 @@ module Playbook
143
151
  end
144
152
 
145
153
  def inverse_class
146
- inverse ? "fa-inverse" : nil
154
+ class_name = is_svg? ? "svg_inverse" : "fa-inverse"
155
+ inverse ? class_name : nil
147
156
  end
148
157
 
149
158
  def list_item_class
150
- list_item ? "fa-li" : nil
159
+ class_name = is_svg? ? "svg_li" : "fa-li"
160
+ list_item ? class_name : nil
151
161
  end
152
162
 
153
163
  def flip_class
164
+ prefix = is_svg? ? "flip_" : "fa-flip-"
154
165
  case flip
155
166
  when "horizontal"
156
- "fa-flip-horizontal"
167
+ "#{prefix}horizontal"
157
168
  when "vertical"
158
- "fa-flip-vertical"
169
+ "#{prefix}vertical"
159
170
  when "both"
160
- "fa-flip-horizontal fa-flip-vertical"
171
+ "#{prefix}horizontal #{prefix}vertical"
161
172
  end
162
173
  end
163
174
 
164
175
  def pull_class
165
- pull ? "fa-pull-#{pull}" : nil
176
+ class_name = is_svg? ? "pull_#{pull}" : "fa-pull-#{pull}"
177
+ pull ? class_name : nil
166
178
  end
167
179
 
168
180
  def pulse_class
169
- pulse ? "fa-pulse" : nil
181
+ class_name = is_svg? ? "pulse" : "fa-pulse"
182
+ pulse ? class_name : nil
170
183
  end
171
184
 
172
185
  def rotation_class
173
- rotation ? "fa-rotate-#{rotation}" : nil
186
+ class_name = is_svg? ? "rotate_#{rotation}" : "fa-rotate-#{rotation}"
187
+ rotation ? class_name : nil
174
188
  end
175
189
 
176
190
  def size_class
177
- size ? "fa-#{size}" : nil
191
+ class_name = is_svg? ? "svg_#{size}" : "fa-#{size}"
192
+ size ? class_name : nil
178
193
  end
179
194
 
180
195
  def font_style_class
@@ -182,10 +197,9 @@ module Playbook
182
197
  end
183
198
 
184
199
  def spin_class
185
- spin ? "fa-spin" : nil
200
+ class_name = is_svg? ? "spin" : "fa-spin"
201
+ spin ? class_name : nil
186
202
  end
187
203
  end
188
204
  end
189
205
  end
190
-
191
- # rubocop:enable Style/HashLikeCase
@@ -95,11 +95,11 @@ test('should not have a left border', () => {
95
95
  test('should have a right icon', () => {
96
96
  render(<NavDefault iconRight="angle-down" />)
97
97
  const kit = screen.getByTestId(itemTestId)
98
- expect(kit).toContainHTML('<i class="pb_icon_kit far fa-fw fa-angle-down pb_nav_list_item_icon_right" />')
98
+ expect(kit).toContainHTML('<i class="pb_icon_kit far pb_nav_list_item_icon_right fa-fw fa-angle-down" />')
99
99
  })
100
100
 
101
101
  test('should have a left icon', () => {
102
102
  render(<NavDefault iconLeft="users-class" />)
103
103
  const kit = screen.getByTestId(itemTestId)
104
- expect(kit).toContainHTML('<i class="pb_icon_kit far fa-fw fa-users-class pb_nav_list_item_icon_left" />')
104
+ expect(kit).toContainHTML('<i class="pb_icon_kit far pb_nav_list_item_icon_left fa-fw fa-users-class" />')
105
105
  })
@@ -0,0 +1,48 @@
1
+ <%= pb_rails("nav", props: { orientation: "horizontal", tabbing: true, padding_bottom: "sm" }) do %>
2
+ <%= pb_rails("nav/item", props: { text: "About", active: true, data: { pb_tab_target: "about" }, cursor: "pointer" }) %>
3
+ <%= pb_rails("nav/item", props: { text: "Case Studies", data: { pb_tab_target: "case_studies" }, cursor: "pointer" }) %>
4
+ <%= pb_rails("nav/item", props: { text: "Service", data: { pb_tab_target: "service" }, cursor: "pointer" }) %>
5
+ <%= pb_rails("nav/item", props: { text: "Contacts", data: { pb_tab_target: "contacts" }, cursor: "pointer" }) %>
6
+ <% end %>
7
+
8
+ <div id="about">
9
+ <%= pb_rails("body", props: { text: "This is about!" }) %>
10
+ </div>
11
+
12
+ <div id="case_studies">
13
+ <%= pb_rails("body", props: { text: "This is case studies!" }) %>
14
+ </div>
15
+
16
+ <div id="service">
17
+ <%= pb_rails("body", props: { text: "This is service!" }) %>
18
+ </div>
19
+
20
+ <div id="contacts">
21
+ <%= pb_rails("body", props: { text: "This is contacts!" }) %>
22
+ </div>
23
+
24
+ <script>
25
+ // The script in the code snippet below is for demonstrating the active state and NOT needed for the kit to function.
26
+ // The active prop can be used to highlight this active state.
27
+ const navItemClass = "pb_nav_list_kit_item"
28
+ const navItemActiveClass = "pb_nav_list_kit_item_active"
29
+ const dataNavItems = "[data-pb-tab-target]"
30
+
31
+ const navItemTabs = document.querySelectorAll(dataNavItems)
32
+ navItemTabs.forEach(navItemTab => {
33
+ navItemTab.addEventListener("click", event => {
34
+ const navItemTabs = document.querySelectorAll(dataNavItems)
35
+ navItemTabs.forEach(navItemTab => {
36
+ if (navItemTab === event.target.closest(dataNavItems)) {
37
+ navItemTab.classList.add(navItemActiveClass)
38
+ navItemTab.classList.remove(navItemClass)
39
+ } else {
40
+ if (navItemTab.classList.contains(navItemActiveClass)) {
41
+ navItemTab.classList.remove(navItemActiveClass)
42
+ navItemTab.classList.add(navItemClass)
43
+ }
44
+ }
45
+ })
46
+ })
47
+ })
48
+ </script>
@@ -0,0 +1,3 @@
1
+ The Nav kit can also be used to create dynamic tabbing. To do so, use the boolean `tabbing` prop as shown here.
2
+
3
+ All divs you want to use as tabs MUST have an id attached to them. To link the tab to the nav, use the required data attribute `pb_tab_target` on each nav/item and pass it the id of the tab you want linked to that specific nav/item. See code example below to see this in action.
@@ -19,6 +19,7 @@ examples:
19
19
  - block_nav: Block
20
20
  - block_no_title_nav: Without Title
21
21
  - new_tab: Open in a New Tab
22
+ - tab_nav: Tab Nav
22
23
 
23
24
  react:
24
25
  - default_nav: Default
@@ -0,0 +1,43 @@
1
+ import PbEnhancedElement from '../pb_enhanced_element'
2
+
3
+ const NAV_SELECTOR = '[data-pb-nav-tab]'
4
+ const NAV_ITEM_SELECTOR = '[data-pb-tab-target]'
5
+
6
+ export default class PbNav extends PbEnhancedElement {
7
+ static get selector() {
8
+ return NAV_SELECTOR
9
+ }
10
+
11
+ connect() {
12
+ this.hideAndAddEventListeners()
13
+ }
14
+
15
+ hideAndAddEventListeners() {
16
+ const navItems = this.element.querySelectorAll(NAV_ITEM_SELECTOR)
17
+ navItems.forEach((navItem) => {
18
+ if (!navItem.className.includes('active')) {
19
+ this.changeContentDisplay(navItem.dataset.pbTabTarget, 'none')
20
+ }
21
+
22
+ navItem.addEventListener('click', event => this.handleNavItemClick(event))
23
+ })
24
+ }
25
+
26
+ handleNavItemClick(event) {
27
+ event.preventDefault()
28
+ const navItem = event.target.closest(NAV_ITEM_SELECTOR)
29
+ this.changeContentDisplay(navItem.dataset.pbTabTarget, 'block')
30
+
31
+ const navItems = this.element.querySelectorAll(NAV_ITEM_SELECTOR)
32
+ navItems.forEach((navItemSelected) => {
33
+ if (navItem !== navItemSelected) {
34
+ this.changeContentDisplay(navItemSelected.dataset.pbTabTarget, 'none')
35
+ }
36
+ })
37
+ }
38
+
39
+ changeContentDisplay(contentId, display) {
40
+ const content = document.getElementById(contentId)
41
+ content.style.display = display
42
+ }
43
+ }
@@ -13,11 +13,20 @@ module Playbook
13
13
  default: "normal"
14
14
  prop :highlight, type: Playbook::Props::Boolean, default: true
15
15
  prop :borderless, type: Playbook::Props::Boolean, default: false
16
+ prop :tabbing, type: Playbook::Props::Boolean, default: false
16
17
 
17
18
  def classname
18
19
  generate_classname("pb_nav_list", variant, orientation, highlight_class, borderless_class)
19
20
  end
20
21
 
22
+ def data
23
+ if tabbing
24
+ Hash(prop(:data)).merge(pb_nav_tab: true)
25
+ else
26
+ prop(:data)
27
+ end
28
+ end
29
+
21
30
  def highlight_class
22
31
  highlight ? "highlight" : nil
23
32
  end
@@ -10,7 +10,7 @@ const MoreExtensionsDropdown = ({extensions}: any) => {
10
10
  const [showPopover, setShowPopover] = useState(false)
11
11
 
12
12
  const handleTogglePopover = () => {
13
- setShowPopover(true)
13
+ setShowPopover(!showPopover)
14
14
  }
15
15
 
16
16
  const handlePopoverClose = (shouldClosePopover: boolean) => {
@@ -67,7 +67,7 @@ const toolbarDropdownItems = [
67
67
 
68
68
 
69
69
  const handleTogglePopover = () => {
70
- setShowPopover(true)
70
+ setShowPopover(!showPopover)
71
71
  }
72
72
 
73
73
  const handlePopoverClose = (shouldClosePopover: boolean) => {
@@ -48,8 +48,8 @@
48
48
 
49
49
 
50
50
  $star-styles: (
51
- yellow_star: (color: #F9BB00),
52
- primary_star: (color: #0056CF),
51
+ yellow_star: (color: $yellow),
52
+ primary_star: (color: $royal),
53
53
  suble_star_light: (color: $text_lt_default),
54
54
  suble_star_dark: (color: $text_dk_default),
55
55
  empty_star_dark: (color: $border_dark),
@@ -111,4 +111,13 @@
111
111
  }
112
112
  }
113
113
  }
114
+ .yellow-star-selected {
115
+ color: $yellow;
116
+ }
117
+ .primary-star-selected {
118
+ color: $royal
119
+ }
120
+ .suble-star-selected {
121
+ color: $text_lt_default;
122
+ }
114
123
  }
@@ -0,0 +1 @@
1
+ <%= pb_rails("star_rating", props: { padding_bottom: "xs", variant: "interactive" }) %>
@@ -13,4 +13,4 @@ examples:
13
13
  - star_rating_background_options: Background Options
14
14
  - star_rating_hide: Layout Options
15
15
  - star_rating_number_config: Number Config
16
- - star_rating_size_options: Size Options
16
+ - star_rating_size_options: Size Options
@@ -0,0 +1,50 @@
1
+ import PbEnhancedElement from "../pb_enhanced_element";
2
+
3
+ const STAR_RATING_SELECTOR = "[data-pb-star-rating]";
4
+ const STAR_RATING_INPUT_ID = "star-rating-input";
5
+
6
+ export default class PbStarRating extends PbEnhancedElement {
7
+ static get selector() {
8
+ return STAR_RATING_SELECTOR;
9
+ }
10
+
11
+ connect() {
12
+ this.element.addEventListener("click", (event) => {
13
+ const clickedStarId = event.currentTarget.id;
14
+ this.updateStarColors(clickedStarId);
15
+ this.updateHiddenInputValue(clickedStarId);
16
+ });
17
+ }
18
+
19
+ updateStarColors(clickedStarId) {
20
+ const allStars = document.querySelectorAll(STAR_RATING_SELECTOR);
21
+
22
+ allStars.forEach(star => {
23
+ const starId = star.id;
24
+ const icon = star.querySelector(".interactive-star-icon");
25
+
26
+ if (icon) {
27
+ if (starId <= clickedStarId) {
28
+ if (star.classList.contains("yellow_star")) {
29
+ icon.classList.add("yellow-star-selected");
30
+ } else if (star.classList.contains("primary_star")) {
31
+ icon.classList.add("primary-star-selected");
32
+ } else if (star.classList.contains("suble_star_light")) {
33
+ icon.classList.add("suble-star-selected");
34
+ } else {
35
+ icon.classList.add("yellow-star-selected");
36
+ }
37
+ } else {
38
+ icon.classList.remove("yellow-star-selected", "primary-star-selected", "suble-star-selected");
39
+ }
40
+ }
41
+ });
42
+ }
43
+
44
+ updateHiddenInputValue(value) {
45
+ const hiddenInput = document.getElementById(STAR_RATING_INPUT_ID);
46
+ if (hiddenInput) {
47
+ hiddenInput.value = value;
48
+ }
49
+ }
50
+ }
@@ -28,13 +28,33 @@
28
28
  <% end %>
29
29
  <% end %>
30
30
  <%= pb_rails("flex", props: { }) do %>
31
- <% object.star_count.times do %>
32
- <%= pb_rails("icon", props: { classname: "#{star_color} pb_star_#{size}" , custom_icon: Playbook::Engine.root.join(star_svg_path) } ) %>
33
- <% end %>
34
- <% object.empty_stars.times do %>
35
- <%= pb_rails("icon", props: { classname: "#{background_star_color} pb_star_#{size}", custom_icon: Playbook::Engine.root.join(background_star_path) } ) %>
31
+
32
+ <% if object.variant == "display" %>
33
+
34
+ <% object.star_count.times do %>
35
+ <%= pb_rails("icon", props: { classname: "#{star_color} pb_star_#{size}" , custom_icon: Playbook::Engine.root.join(star_svg_path) } ) %>
36
+ <% end %>
37
+ <% object.empty_stars.times do %>
38
+ <%= pb_rails("icon", props: { classname: "#{background_star_color} pb_star_#{size}", custom_icon: Playbook::Engine.root.join(background_star_path) } ) %>
39
+ <% end %>
40
+
41
+ <% else %>
42
+ <%= pb_rails("flex", props: { orientation: "column" }) do %>
43
+ <% if object.label.present? %>
44
+ <%= pb_rails("caption", props: {text: object.label, margin_bottom:"xs"}) %>
45
+ <% end %>
46
+ <input type="hidden" id="star-rating-input" value="" name="<%= object.name %>"/>
47
+ <%= pb_rails("flex", props: { orientation: "row" }) do %>
48
+ <% object.denominator.times do |index| %>
49
+ <div data-pb-star-rating id="<%= index + 1 %>" class="<%= star_color %>">
50
+ <%= pb_rails("icon", props: { classname: "#{background_star_color} pb_star_#{size} interactive-star-icon", custom_icon: Playbook::Engine.root.join(background_star_path)} ) %>
51
+ </div>
52
+ <% end %>
53
+ <% end %>
54
+ <% end %>
36
55
  <% end %>
37
56
  <% end %>
57
+
38
58
  <% if layout_option == "onestar" %>
39
59
  <%= content_tag(:div, class: "pb_star_rating_number_#{size}") do %>
40
60
  <% case object.size %>
@@ -25,6 +25,12 @@ module Playbook
25
25
  values: %w[fill outline],
26
26
  default: "fill"
27
27
 
28
+ prop :variant, type: Playbook::Props::Enum,
29
+ values: %w[display interactive],
30
+ default: "display"
31
+ prop :label, type: Playbook::Props::String
32
+ prop :name, type: Playbook::Props::String
33
+
28
34
  def one_decimal_rating
29
35
  rating.to_f.round(1)
30
36
  end
@@ -33,7 +33,7 @@ type TableProps = {
33
33
  verticalBorder?: boolean,
34
34
  } & GlobalProps
35
35
 
36
- const Table = (props: TableProps) => {
36
+ const Table = (props: TableProps): React.ReactElement => {
37
37
  const {
38
38
  aria = {},
39
39
  children,
@@ -1,19 +1,19 @@
1
1
  import PbEnhancedElement from '../pb_enhanced_element'
2
2
 
3
3
  export default class PbTable extends PbEnhancedElement {
4
- static get selector() {
4
+ static get selector(): string {
5
5
  return '.table-responsive-collapse'
6
6
  }
7
7
 
8
- connect() {
8
+ connect(): void {
9
9
  const tables = document.querySelectorAll('.table-responsive-collapse');
10
10
 
11
11
  // Each Table
12
12
  [].forEach.call(tables, (table: HTMLTableElement) => {
13
13
  // Header Titles
14
- let headers: string[] = [];
14
+ const headers: string[] = [];
15
15
  [].forEach.call(table.querySelectorAll('th'), (header: HTMLTableCellElement) => {
16
- let colSpan = header.colSpan
16
+ const colSpan = header.colSpan
17
17
  for (let i = 0; i < colSpan; i++) {
18
18
  headers.push(header.textContent.replace(/\r?\n|\r/, ''));
19
19
  }