playbook_ui 13.31.0 → 13.32.0.pre.alpha.PBNTR405dropdownformfixesrails3301

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) 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_button/_button.scss +3 -3
  4. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +3 -2
  5. data/app/pb_kits/playbook/pb_caption/_caption_mixin.scss +1 -1
  6. data/app/pb_kits/playbook/pb_collapsible/__snapshots__/collapsible.test.js.snap +1 -1
  7. data/app/pb_kits/playbook/pb_dashboard/commonSettings.js +1 -1
  8. data/app/pb_kits/playbook/pb_dashboard/pbChartsDarkTheme.ts +1 -1
  9. data/app/pb_kits/playbook/pb_dashboard/pbChartsLightTheme.ts +1 -1
  10. data/app/pb_kits/playbook/pb_date_year_stacked/docs/_date_year_stacked_default.jsx +4 -1
  11. data/app/pb_kits/playbook/pb_draggable/context/index.tsx +15 -1
  12. data/app/pb_kits/playbook/pb_draggable/context/types.ts +5 -0
  13. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default.jsx +14 -19
  14. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default.md +5 -3
  15. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards.md +7 -3
  16. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list.md +3 -5
  17. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_selectable_list.md +3 -5
  18. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +12 -7
  19. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.html.erb +10 -0
  20. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.jsx +31 -0
  21. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_value.html.erb +10 -0
  22. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_value.jsx +31 -0
  23. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +4 -0
  24. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +3 -1
  25. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +4 -3
  26. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +13 -0
  27. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +1 -1
  28. data/app/pb_kits/playbook/pb_dropdown/index.js +95 -8
  29. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +9 -0
  30. data/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +109 -6
  31. data/app/pb_kits/playbook/pb_form_pill/_form_pill.test.jsx +53 -0
  32. data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +11 -2
  33. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_example.html.erb +5 -1
  34. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_example.jsx +1 -0
  35. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_size.html.erb +2 -0
  36. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_size.jsx +2 -0
  37. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_tag.html.erb +4 -1
  38. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_tag.jsx +3 -2
  39. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_user.html.erb +2 -0
  40. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_user.jsx +2 -0
  41. data/app/pb_kits/playbook/pb_form_pill/form_pill.html.erb +1 -1
  42. data/app/pb_kits/playbook/pb_form_pill/form_pill.rb +5 -1
  43. data/app/pb_kits/playbook/pb_icon/_icon.scss +210 -1
  44. data/app/pb_kits/playbook/pb_icon/_icon.tsx +100 -41
  45. data/app/pb_kits/playbook/pb_icon/icon.rb +33 -19
  46. data/app/pb_kits/playbook/pb_nav/_nav_item.test.js +2 -2
  47. data/app/pb_kits/playbook/pb_nav/docs/_tab_nav.html.erb +48 -0
  48. data/app/pb_kits/playbook/pb_nav/docs/_tab_nav.md +3 -0
  49. data/app/pb_kits/playbook/pb_nav/docs/example.yml +1 -0
  50. data/app/pb_kits/playbook/pb_nav/index.js +43 -0
  51. data/app/pb_kits/playbook/pb_nav/nav.rb +9 -0
  52. data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/MoreExtensionsDropdown.tsx +1 -1
  53. data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/ToolbarDropdown.tsx +1 -1
  54. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +8 -23
  55. data/app/pb_kits/playbook/pb_star_rating/_star_rating.scss +11 -2
  56. data/app/pb_kits/playbook/pb_star_rating/docs/_star_rating_interactive.html.erb +1 -0
  57. data/app/pb_kits/playbook/pb_star_rating/docs/example.yml +1 -1
  58. data/app/pb_kits/playbook/pb_star_rating/index.js +50 -0
  59. data/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb +25 -5
  60. data/app/pb_kits/playbook/pb_star_rating/star_rating.rb +6 -0
  61. data/app/pb_kits/playbook/pb_table/_table.tsx +1 -1
  62. data/app/pb_kits/playbook/pb_table/index.ts +4 -4
  63. data/app/pb_kits/playbook/pb_table/subcomponents/_table_body.tsx +1 -1
  64. data/app/pb_kits/playbook/pb_table/subcomponents/_table_cell.tsx +1 -1
  65. data/app/pb_kits/playbook/pb_table/subcomponents/_table_head.tsx +1 -1
  66. data/app/pb_kits/playbook/pb_table/subcomponents/_table_header.tsx +1 -1
  67. data/app/pb_kits/playbook/pb_table/subcomponents/_table_row.tsx +1 -1
  68. data/app/pb_kits/playbook/pb_table/table.test.js +2 -0
  69. data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +1 -1
  70. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_default.jsx +1 -1
  71. data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +45 -27
  72. data/app/pb_kits/playbook/pb_textarea/index.tsx +3 -3
  73. data/app/pb_kits/playbook/pb_time/_time.tsx +3 -3
  74. data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.tsx +1 -1
  75. data/app/pb_kits/playbook/pb_timeline/_item.tsx +1 -1
  76. data/app/pb_kits/playbook/pb_timeline/_timeline.tsx +1 -1
  77. data/app/pb_kits/playbook/pb_title_detail/_title_detail.tsx +10 -10
  78. data/app/pb_kits/playbook/pb_toggle/_toggle.tsx +1 -1
  79. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +2 -2
  80. data/app/pb_kits/playbook/pb_treemap_chart/_treemap_chart.tsx +1 -2
  81. data/app/pb_kits/playbook/pb_treemap_chart/treemapChart.test.js +2 -0
  82. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +3 -3
  83. data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.tsx +4 -4
  84. data/app/pb_kits/playbook/pb_typeahead/components/Control.tsx +11 -7
  85. data/app/pb_kits/playbook/pb_typeahead/components/IndicatorsContainer.tsx +8 -3
  86. data/app/pb_kits/playbook/pb_typeahead/components/MenuList.tsx +6 -1
  87. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +18 -19
  88. data/app/pb_kits/playbook/pb_typeahead/components/Option.tsx +6 -6
  89. data/app/pb_kits/playbook/pb_typeahead/components/Placeholder.tsx +6 -6
  90. data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +3 -3
  91. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_custom_menu_list.jsx +2 -0
  92. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_default.html.erb +22 -57
  93. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_pills_async.jsx +2 -2
  94. data/app/pb_kits/playbook/pb_typeahead/index.ts +31 -31
  95. data/app/pb_kits/playbook/pb_user/_user.tsx +1 -1
  96. data/app/pb_kits/playbook/pb_user_badge/_user_badge.tsx +6 -6
  97. data/app/pb_kits/playbook/pb_user_badge/badges/million-dollar.tsx +236 -235
  98. data/app/pb_kits/playbook/pb_user_badge/badges/veteran.tsx +1 -1
  99. data/app/pb_kits/playbook/pb_walkthrough/_walkthrough.tsx +68 -63
  100. data/app/pb_kits/playbook/pb_weekday_stacked/_weekday_stacked.tsx +2 -2
  101. data/app/pb_kits/playbook/playbook-rails.js +6 -0
  102. data/app/pb_kits/playbook/tokens/_titles.scss +4 -4
  103. data/app/pb_kits/playbook/tokens/_typography.scss +10 -10
  104. data/dist/menu.yml +566 -472
  105. data/dist/playbook-rails.js +7 -7
  106. data/dist/reset.css +1 -1
  107. data/lib/playbook/forms/builder/star_rating_field.rb +14 -0
  108. data/lib/playbook/forms/builder.rb +1 -0
  109. data/lib/playbook/version.rb +2 -2
  110. metadata +16 -6
  111. data/app/pb_kits/playbook/pb_icon/icon_aliases.json +0 -39
@@ -1,4 +1,3 @@
1
- // Rails custom icon styles
2
1
  svg.pb_custom_icon {
3
2
  width: 1em;
4
3
  fill: currentColor;
@@ -10,3 +9,213 @@ svg.pb_custom_icon {
10
9
  .pb_icon_kit_emoji {
11
10
  font-family: monospace;
12
11
  }
12
+
13
+ $rotate-list: (90, 180, 270);
14
+
15
+ @keyframes pb_icon_spin {
16
+ 0% {
17
+ -webkit-transform: rotate(0);
18
+ transform: rotate(0);
19
+ }
20
+ 100% {
21
+ -webkit-transform: rotate(360deg);
22
+ transform: rotate(360deg);
23
+ }
24
+ };
25
+
26
+ svg {
27
+ &.pb_icon_kit,
28
+ &.pb_custom_icon{
29
+ @each $r in $rotate-list {
30
+ &.rotate_#{$r} {
31
+ transform: rotate(#{$r}deg);
32
+ }
33
+ }
34
+ &.flip_horizontal {
35
+ transform: scaleX(-1);
36
+ }
37
+ &.flip_vertical {
38
+ transform: scaleY(-1);
39
+ }
40
+ &.flip_horizontal.flip_vertical {
41
+ transform: scaleX(-1) scaleY(-1);
42
+ }
43
+ &.svg-inline--fa {
44
+ height: 1em;
45
+ overflow: visible;
46
+ vertical-align: -.125em
47
+ }
48
+ &.svg_inverse {
49
+ color: #fff;
50
+ }
51
+ &.svg_border {
52
+ border-color: #eee;
53
+ border-radius: .1em;
54
+ border-style: solid;
55
+ border-width: .08em;
56
+ padding: .2em .25em .15em;
57
+ }
58
+ &.svg_fw {
59
+ text-align: center;
60
+ width: 1.25em
61
+ }
62
+ &.svg_li {
63
+ left: calc(2em * -1);
64
+ position: absolute;
65
+ text-align: center;
66
+ width: 2em;
67
+ line-height: inherit
68
+ }
69
+ &.pull_left {
70
+ float: left;
71
+ margin-right: .3em;
72
+ }
73
+
74
+ &.pull_right {
75
+ float: right;
76
+ margin-left: .3em;
77
+ }
78
+ &.pulse {
79
+ animation-name: pb_icon_spin;
80
+ animation-direction: normal;
81
+ animation-duration: 1s;
82
+ animation-iteration-count: infinite;
83
+ animation-timing-function: steps(8);
84
+ }
85
+ &.spin {
86
+ animation-name: pb_icon_spin;
87
+ animation-delay: 0s;
88
+ animation-direction: normal;
89
+ animation-duration: 2s;
90
+ animation-iteration-count: infinite;
91
+ animation-timing-function: linear;
92
+ }
93
+
94
+ &.svg_xs {
95
+ font-size: 0.75em
96
+ }
97
+
98
+ &.svg_sm {
99
+ font-size: 0.875em
100
+ }
101
+
102
+ &.svg_lg {
103
+ font-size: 1.25em
104
+ }
105
+
106
+ &.svg_1x {
107
+ font-size: 1em
108
+ }
109
+
110
+ &.svg_2x {
111
+ font-size: 2em
112
+ }
113
+
114
+ &.svg_3x {
115
+ font-size: 3em
116
+ }
117
+
118
+ &.svg_4x {
119
+ font-size: 4em
120
+ }
121
+
122
+ &.svg_5x {
123
+ font-size: 5em
124
+ }
125
+
126
+ &.svg_6x {
127
+ font-size: 6em
128
+ }
129
+
130
+ &.svg_7x {
131
+ font-size: 7em
132
+ }
133
+
134
+ &.svg_8x {
135
+ font-size: 8em
136
+ }
137
+
138
+ &.svg_9x {
139
+ font-size: 9em
140
+ }
141
+
142
+ &.svg_10x {
143
+ font-size: 10em
144
+ }
145
+ &.fa-xs {
146
+ font-size: .75em;
147
+ line-height: .0833333337em;
148
+ vertical-align: .125em
149
+ }
150
+ &.fa-sm {
151
+ font-size: .875em;
152
+ line-height: .0714285718em;
153
+ vertical-align: .0535714295em
154
+ }
155
+ &.fa-lg {
156
+ font-size: 1.25em;
157
+ line-height: .05em;
158
+ vertical-align: -.075em
159
+ }
160
+ &.fa-pull-left {
161
+ float: left;
162
+ margin-right: .3em;
163
+ }
164
+
165
+ &.fa-pull-right {
166
+ float: right;
167
+ margin-left: .3em;
168
+ }
169
+ &.fa-li {
170
+ left: calc(2em * -1);
171
+ position: absolute;
172
+ text-align: center;
173
+ width: 2em;
174
+ line-height: inherit
175
+ }
176
+ &.svg-inline--fa.fa-li {
177
+ width: 2em;
178
+ top: .25em
179
+ }
180
+ &.svg-inline--fa.fa-fw {
181
+ width: 1.25em;
182
+ }
183
+ &.fa-fw {
184
+ text-align: center;
185
+ width: 1.25em
186
+ }
187
+ &.fa-layers {
188
+ display: inline-block;
189
+ height: 1em;
190
+ position: relative;
191
+ text-align: center;
192
+ vertical-align: -.125em;
193
+ width: 1em
194
+ }
195
+ &.fa-2x {
196
+ font-size: 2em
197
+ }
198
+ &.fa-3x {
199
+ font-size: 3em
200
+ }
201
+ &.fa-flip {
202
+ animation-name: fa-flip;
203
+ animation-delay: 0s;
204
+ animation-direction: normal;
205
+ animation-duration: 1s;
206
+ animation-iteration-count: infinite;
207
+ animation-timing-function: ease-in-out;
208
+ }
209
+ &.fa-spin {
210
+ animation-name: fa-spin;
211
+ animation-delay: 0s;
212
+ animation-direction: normal;
213
+ animation-duration: 2s;
214
+ animation-iteration-count: infinite;
215
+ animation-timing-function: linear;
216
+ }
217
+ &.fa-pulse {
218
+ animation: fa-spin 1s infinite linear;
219
+ }
220
+ }
221
+ }
@@ -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