playbook_ui 13.31.0 → 13.32.0.pre.alpha.PBNTR405dropdownformfixesrails3301

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 (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
@@ -8,16 +8,26 @@ const DOWN_ARROW_SELECTOR = "#dropdown_open_icon";
8
8
  const UP_ARROW_SELECTOR = "#dropdown_close_icon";
9
9
  const OPTION_SELECTOR = "[data-dropdown-option-label]";
10
10
  const CUSTOM_DISPLAY_SELECTOR = "[data-dropdown-custom-trigger]";
11
+ const DROPDOWN_TRIGGER_DISPLAY = "#dropdown_trigger_display";
12
+ const DROPDOWN_PLACEHOLDER = "[data-dropdown-placeholder]";
13
+ const DROPDOWN_INPUT = "#dropdown-selected-option";
11
14
 
12
15
  export default class PbDropdown extends PbEnhancedElement {
13
16
  static get selector() {
14
17
  return DROPDOWN_SELECTOR;
15
18
  }
16
19
 
20
+ get target() {
21
+ return this.element.parentNode.querySelector(CONTAINER_SELECTOR);
22
+ }
23
+
17
24
  connect() {
18
25
  this.keyboardHandler = new PbDropdownKeyboard(this);
26
+ this.setDefaultValue();
19
27
  this.bindEventListeners();
20
28
  this.updateArrowDisplay(false);
29
+ this.handleFormValidation();
30
+ this.handleFormReset();
21
31
  }
22
32
 
23
33
  bindEventListeners() {
@@ -37,10 +47,13 @@ export default class PbDropdown extends PbEnhancedElement {
37
47
 
38
48
  handleOptionClick(event) {
39
49
  const option = event.target.closest(OPTION_SELECTOR);
40
- const hiddenInput = this.element.querySelector("#dropdown-selected-option");
50
+ const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
51
+
41
52
  if (option) {
42
53
  const value = option.dataset.dropdownOptionLabel;
43
54
  hiddenInput.value = JSON.parse(value).id;
55
+ this.clearFormValidation(hiddenInput);
56
+
44
57
  this.onOptionSelected(value, option);
45
58
  }
46
59
  }
@@ -73,9 +86,7 @@ export default class PbDropdown extends PbEnhancedElement {
73
86
  }
74
87
 
75
88
  onOptionSelected(value, selectedOption) {
76
- const triggerElement = this.element.querySelector(
77
- "#dropdown_trigger_display"
78
- );
89
+ const triggerElement = this.element.querySelector(DROPDOWN_TRIGGER_DISPLAY);
79
90
  const customDisplayElement = this.element.querySelector(
80
91
  "#dropdown_trigger_custom_display"
81
92
  );
@@ -103,10 +114,6 @@ export default class PbDropdown extends PbEnhancedElement {
103
114
  selectedOption.classList.add("pb_dropdown_option_selected");
104
115
  }
105
116
 
106
- get target() {
107
- return this.element.parentNode.querySelector(CONTAINER_SELECTOR);
108
- }
109
-
110
117
  showElement(elem) {
111
118
  elem.classList.remove("close");
112
119
  elem.classList.add("open");
@@ -150,4 +157,84 @@ export default class PbDropdown extends PbEnhancedElement {
150
157
  upArrow.style.display = isOpen ? "inline-block" : "none";
151
158
  }
152
159
  }
160
+
161
+ handleFormValidation() {
162
+ const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
163
+
164
+ hiddenInput.addEventListener(
165
+ "invalid",
166
+ function (event) {
167
+ if (hiddenInput.hasAttribute("required") && hiddenInput.value === "") {
168
+ event.preventDefault();
169
+ hiddenInput.closest(".dropdown_wrapper").classList.add("error");
170
+ }
171
+ },
172
+ true
173
+ );
174
+ }
175
+
176
+ clearFormValidation(input) {
177
+ if (input.checkValidity()) {
178
+ const dropdownWrapperElement = input.closest(".dropdown_wrapper");
179
+ dropdownWrapperElement.classList.remove("error");
180
+
181
+ const errorLabelElement = dropdownWrapperElement.querySelector(
182
+ ".pb_body_kit_negative"
183
+ );
184
+ if (errorLabelElement) {
185
+ errorLabelElement.remove();
186
+ }
187
+ }
188
+ }
189
+
190
+ setDefaultValue() {
191
+ const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
192
+
193
+ if (hiddenInput.value) {
194
+ const defaultValue = JSON.parse(hiddenInput.value.replaceAll("=>", ":"));
195
+ const options = this.element.querySelectorAll(OPTION_SELECTOR);
196
+
197
+ options.forEach((option) => {
198
+ if (
199
+ defaultValue.id === JSON.parse(option.dataset.dropdownOptionLabel).id
200
+ ) {
201
+ option.classList.add("pb_dropdown_option_selected");
202
+ }
203
+ });
204
+
205
+ this.setTriggerElementText(defaultValue.label);
206
+
207
+ hiddenInput.value = defaultValue.id;
208
+ }
209
+ }
210
+
211
+ handleFormReset() {
212
+ const form = this.element.closest("form");
213
+
214
+ if (form) {
215
+ form.addEventListener("reset", () => {
216
+ this.resetDropdownValue();
217
+ });
218
+ }
219
+ }
220
+
221
+ resetDropdownValue() {
222
+ const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
223
+ const options = this.element.querySelectorAll(OPTION_SELECTOR);
224
+ options.forEach((option) => {
225
+ option.classList.remove("pb_dropdown_option_selected");
226
+ });
227
+
228
+ hiddenInput.value = "";
229
+
230
+ const defaultPlaceholder = this.element.querySelector(DROPDOWN_PLACEHOLDER);
231
+ this.setTriggerElementText(defaultPlaceholder.dataset.dropdownPlaceholder);
232
+ }
233
+
234
+ setTriggerElementText(text) {
235
+ const triggerElement = this.element.querySelector(DROPDOWN_TRIGGER_DISPLAY);
236
+ if (triggerElement) {
237
+ triggerElement.textContent = text;
238
+ }
239
+ }
153
240
  }
@@ -13,6 +13,14 @@
13
13
  ]
14
14
  %>
15
15
 
16
+ <%
17
+ example_dropdown_options = [
18
+ { label: 'United States', value: 'United States', id: 'us' },
19
+ { label: 'Canada', value: 'Canada', id: 'ca' },
20
+ { label: 'Pakistan', value: 'Pakistan', id: 'pk' },
21
+ ]
22
+ %>
23
+
16
24
  <%= pb_form_with(scope: :example, method: :get, url: "", validate: true) do |form| %>
17
25
  <%= form.text_field :example_text_field, props: { label: true, required: true } %>
18
26
  <%= form.phone_number_field :example_phone_number_field, props: { label: "Example phone field" } %>
@@ -22,6 +30,7 @@
22
30
  <%= form.password_field :example_password_field, props: { label: true, required: true } %>
23
31
  <%= form.url_field :example_url_field, props: { label: true, required: true } %>
24
32
  <%= form.text_area :example_text_area, props: { label: true, required: true } %>
33
+ <%= form.dropdown_field :example_dropdown, props: { label: true, options: example_dropdown_options, required: true } %>
25
34
  <%= form.select :example_select, [ ["Yes", 1], ["No", 2] ], props: { label: true, blank_selection: "Select One...", required: true } %>
26
35
  <%= form.collection_select :example_collection_select, example_collection, :value, :name, props: { label: true, blank_selection: "Select One...", required: true } %>
27
36
  <%= form.check_box :example_checkbox, props: { text: "Example Checkbox", label: true, required: true } %>
@@ -8,6 +8,7 @@ $selector: ".pb_form_pill";
8
8
  $pb_form_pill_height: 37px;
9
9
  $form_pill_colors: (
10
10
  primary: map-get($status_color_text, "primary"),
11
+ neutral: map-get($status_color_text, "neutral"),
11
12
  );
12
13
 
13
14
 
@@ -23,39 +24,76 @@ $form_pill_colors: (
23
24
  cursor: pointer;
24
25
  @each $color_name, $color_value in $form_pill_colors {
25
26
  &[class*=_#{$color_name}] {
26
- background-color: rgba($color_value, $opacity-1);
27
+ background-color: mix($color_value, $card_light, 10%);
28
+ @if ($color_name == "neutral") {
29
+ background-color: $white;
30
+ border: 1px solid $border_light;
31
+ }
27
32
  transition: background-color 0.2s ease;
28
33
  box-shadow: none;
29
34
  @media (hover:hover) {
30
35
  &:hover {
31
- background-color: rgba($color_value, $opacity-2);
36
+ background-color: mix($color_value, $card_light, 20%);
37
+ @if ($color_name == "neutral") {
38
+ background-color: mix($neutral, $card_light, 20%);
39
+ border: 1px solid $border_light;
40
+ }
41
+ }
42
+ &:active {
43
+ background-color: mix($color_value, $card_light, 30%);
44
+ @if ($color_name == "neutral") {
45
+ background-color: mix($neutral, $card_light, 30%);
46
+ }
32
47
  }
33
48
  }
34
49
  #{$selector}_text {
35
50
  color: $color_value;
51
+ @if ($color_name == "neutral") {
52
+ color: $text_lt_default;
53
+ }
36
54
  padding-left: $space-sm;
37
- padding-right: $space-sm/4;
55
+ padding-right: $space-sm/2;
38
56
  }
39
57
  #{$selector}_close {
40
58
  color: $color_value;
41
- padding-left: $space-sm/2;
59
+ padding-left: $space-sm/4;
42
60
  padding-right: $space-sm/4;
43
61
  display: flex;
44
62
  align-items: center;
45
- height: 100%;
63
+ // I had to temporarily change height to 27px so new hover state darker background forms a circle not an oval
64
+ // before size change (ticket 2 of 4) - change back to 100% when $pb_form_pill_height changed to 27px from 37px
65
+ height: 27px;
66
+ border-radius: 70px;
46
67
  cursor: pointer;
68
+ &:hover {
69
+ background-color: mix($color_value, $card_light, 40%);
70
+ @if ($color_name == "neutral") {
71
+ background-color: mix($neutral, $card_light, 60%);
72
+ }
73
+ }
47
74
  }
48
75
  #{$selector}_tag {
49
76
  color: $color_value;
50
77
  padding-left: $space-sm;
78
+ @if ($color_name == "neutral") {
79
+ color: $text_lt_default;
80
+ }
51
81
  }
52
82
  }
53
83
  }
84
+ &:focus {
85
+ outline: $primary solid 2px;
86
+ outline-offset: -1px;
87
+ }
88
+ &:focus-visible {
89
+ outline: $primary solid 2px;
90
+ outline-offset: -1px;
91
+ }
54
92
  &.small {
55
93
  height: fit-content;
56
94
  height: -moz-fit-content;
57
95
  .pb_form_pill_text, .pb_form_pill_close, .pb_form_pill_tag {
58
- font-size: 16px;
96
+ font-size: $font_base;
59
97
  font-weight: $regular;
60
98
  }
61
99
  .pb_form_pill_text, .pb_form_pill_tag {
@@ -70,6 +108,71 @@ $form_pill_colors: (
70
108
  &::before { line-height: 21px; }
71
109
  }
72
110
  }
111
+ &.dark {
112
+ @each $color_name, $color_value in $form_pill_colors {
113
+ // In dark mode, the base patterns below are needed for the next tickets for success, warning, error, info.
114
+ // Primary and Neutral are exceptions to the general rule in the handoff
115
+ &[class*=_#{$color_name}] {
116
+ // background-color: mix($color_value, $card_dark, 10%);
117
+ // .pb_form_pill_tag {
118
+ // color: $color_name;
119
+ // }
120
+ // .pb_form_pill_close {
121
+ // color: $color_name;
122
+ // &:hover {
123
+ // background-color: mix($color_value, $card_dark, 40%);
124
+ // }
125
+ // }
126
+ // &:hover {
127
+ // background-color: mix($color_value, $card_dark, 20%);
128
+ // }
129
+ // &:active {
130
+ // background-color: mix($color_value, $card_dark, 30%);
131
+ // }
132
+ @if ($color_name == "neutral") {
133
+ background-color: transparent;
134
+ border: 1px solid $border_dark;
135
+ .pb_form_pill_text, .pb_form_pill_tag {
136
+ color: $text_dk_default;
137
+ }
138
+ .pb_form_pill_close {
139
+ color: $text_dk_default;
140
+ &:hover {
141
+ background-color: mix($neutral, $card_dark, 40%);
142
+ }
143
+ }
144
+ &:hover {
145
+ background-color: mix($white, $card_dark, 10%);
146
+ }
147
+ &:active {
148
+ background-color: mix($white, $card_dark, 20%);
149
+ }
150
+ &:focus {
151
+ border: 1px solid $primary;
152
+ }
153
+ }
154
+ @if ($color_name == "primary") {
155
+ background-color: mix($active_dark, $card_dark, 10%);
156
+ .pb_form_pill_text, .pb_form_pill_tag {
157
+ color: $active_dark;
158
+ }
159
+ .pb_form_pill_close {
160
+ color: $active_dark;
161
+ &:hover {
162
+ background-color: mix($active_dark, $card_dark, 40%);
163
+ }
164
+ }
165
+ &:hover {
166
+ background-color: mix($active_dark, $card_dark, 20px);
167
+ }
168
+ &:active {
169
+ background-color: mix($active_dark, $card_dark, 30%);
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+
73
176
  &[class*=lowercase] {
74
177
  text-transform: lowercase;
75
178
  }
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { render, screen } from '../utilities/test-utils';
3
+ import FormPill from './_form_pill';
4
+
5
+ const testId = 'formpill';
6
+
7
+ test('should render classname', () => {
8
+ render(
9
+ <FormPill
10
+ data={{ testid: testId }}
11
+ text="test"
12
+ />
13
+ )
14
+
15
+ const kit = screen.getByTestId(testId)
16
+ expect(kit).toHaveClass('pb_form_pill_kit_primary none')
17
+ });
18
+
19
+ test('displays text content', () => {
20
+ render(
21
+ <FormPill
22
+ data={{ testid: testId }}
23
+ text="test"
24
+ />
25
+ )
26
+
27
+ const text = screen.getByText("test")
28
+ expect(text).toBeInTheDocument()
29
+ });
30
+
31
+ test('displays color variant', () => {
32
+ render(
33
+ <FormPill
34
+ color={"neutral"}
35
+ data={{ testid: testId }}
36
+ text={"test"}
37
+ />
38
+ )
39
+ const kit = screen.getByTestId(testId)
40
+ expect(kit).toHaveClass(`pb_form_pill_kit_neutral none`)
41
+ });
42
+
43
+ test('displays size variant', () => {
44
+ render(
45
+ <FormPill
46
+ data={{ testid: testId }}
47
+ size={"small"}
48
+ text={"test"}
49
+ />
50
+ )
51
+ const kit = screen.getByTestId('formpill')
52
+ expect(kit).toHaveClass(`pb_form_pill_kit_primary small none`)
53
+ });
@@ -5,7 +5,7 @@ import Title from '../pb_title/_title'
5
5
  import Icon from '../pb_icon/_icon'
6
6
  import Avatar from '../pb_avatar/_avatar'
7
7
  import { globalProps, GlobalProps } from '../utilities/globalProps'
8
- import { buildHtmlProps } from '../utilities/props'
8
+ import { buildDataProps, buildHtmlProps } from '../utilities/props'
9
9
 
10
10
  type FormPillProps = {
11
11
  className?: string,
@@ -18,6 +18,9 @@ type FormPillProps = {
18
18
  avatarUrl?: string,
19
19
  size?: string,
20
20
  textTransform?: 'none' | 'lowercase',
21
+ color?: "primary" | "neutral",
22
+ data?: {[key: string]: string},
23
+ tabIndex?: number,
21
24
  closeProps?: {
22
25
  onClick?: React.MouseEventHandler<HTMLSpanElement>,
23
26
  onMouseDown?: React.MouseEventHandler<HTMLSpanElement>,
@@ -36,20 +39,26 @@ const FormPill = (props: FormPillProps): React.ReactElement => {
36
39
  closeProps = {},
37
40
  size = '',
38
41
  textTransform = 'none',
42
+ color = "primary",
43
+ data = {},
44
+ tabIndex,
39
45
  } = props
40
46
  const css = classnames(
41
- `pb_form_pill_kit_${'primary'}`,
47
+ `pb_form_pill_kit_${color}`,
42
48
  globalProps(props),
43
49
  className,
44
50
  size === 'small' ? 'small' : null,
45
51
  textTransform,
46
52
  )
47
53
 
54
+ const dataProps = buildDataProps(data)
48
55
  const htmlProps = buildHtmlProps(htmlOptions)
49
56
 
50
57
  return (
51
58
  <div className={css}
52
59
  id={id}
60
+ tabIndex={tabIndex}
61
+ {...dataProps}
53
62
  {...htmlProps}
54
63
  >
55
64
  {name &&
@@ -1 +1,5 @@
1
- <%= pb_rails("form_pill", props: { text_transform: "lowercase" , text: "THIS IS A TAG" }) %>
1
+ <%= pb_rails("form_pill", props: {
2
+ text_transform: "lowercase" ,
3
+ text: "THIS IS A TAG",
4
+ tabindex: 0,
5
+ }) %>
@@ -6,6 +6,7 @@ const FormPillExample = (props) => {
6
6
  <div>
7
7
  <FormPill
8
8
  onClick={() => alert('Click!')}
9
+ tabIndex={0}
9
10
  text="THIS IS A TAG"
10
11
  textTransform="lowercase"
11
12
  {...props}
@@ -2,6 +2,7 @@
2
2
  name: "Anna Black",
3
3
  avatar_url: "https://randomuser.me/api/portraits/women/44.jpg",
4
4
  size: "small",
5
+ tabindex: 0,
5
6
  }) %>
6
7
 
7
8
  <br />
@@ -10,4 +11,5 @@
10
11
  <%= pb_rails("form_pill", props: {
11
12
  name: "Anna Black",
12
13
  size: "small",
14
+ tabindex: 0,
13
15
  }) %>
@@ -9,6 +9,7 @@ const FormPillSize = (props) => {
9
9
  avatarUrl="https://randomuser.me/api/portraits/women/44.jpg"
10
10
  name="Anna Black"
11
11
  size="small"
12
+ tabIndex={0}
12
13
  {...props}
13
14
  />
14
15
  <br />
@@ -16,6 +17,7 @@ const FormPillSize = (props) => {
16
17
  <FormPill
17
18
  name="Anna Black"
18
19
  size="small"
20
+ tabIndex={0}
19
21
  {...props}
20
22
  />
21
23
  </div>
@@ -1 +1,4 @@
1
- <%= pb_rails("form_pill", props: { text: "this is a tag" }) %>
1
+ <%= pb_rails("form_pill", props: {
2
+ text: "this is a tag",
3
+ tabindex: 0,
4
+ }) %>
@@ -6,8 +6,9 @@ const FormPillDefault = (props) => {
6
6
  <div>
7
7
  <FormPill
8
8
  onClick={() => {
9
- alert('Click!')
10
- }}
9
+ alert('Click!')
10
+ }}
11
+ tabIndex={0}
11
12
  text="this is a tag"
12
13
  {...props}
13
14
  />
@@ -1,6 +1,7 @@
1
1
  <%= pb_rails("form_pill", props: {
2
2
  name: "Anna Black",
3
3
  avatar_url: "https://randomuser.me/api/portraits/women/44.jpg",
4
+ tabindex: 0,
4
5
  }) %>
5
6
 
6
7
  <br />
@@ -8,4 +9,5 @@
8
9
 
9
10
  <%= pb_rails("form_pill", props: {
10
11
  name: "Anna Black",
12
+ tabindex: 0,
11
13
  }) %>
@@ -9,6 +9,7 @@ const FormPillDefault = (props) => {
9
9
  avatarUrl="https://randomuser.me/api/portraits/women/44.jpg"
10
10
  name="Anna Black"
11
11
  onClick={() => alert('Click!')}
12
+ tabIndex={0}
12
13
  {...props}
13
14
  />
14
15
  <br />
@@ -16,6 +17,7 @@ const FormPillDefault = (props) => {
16
17
  <FormPill
17
18
  name="Anna Black"
18
19
  onClick={() => alert('Click!')}
20
+ tabIndex={0}
19
21
  {...props}
20
22
  />
21
23
  </div>
@@ -1,4 +1,4 @@
1
- <%= content_tag(:div, id: object.id, data: object.data, class: object.classname + object.size_class, **combined_html_options) do %>
1
+ <%= content_tag(:div, id: object.id, data: object.data, class: object.classname + object.size_class, tabindex: object.tabindex, **combined_html_options) do %>
2
2
  <% if object.name.present? %>
3
3
  <%= pb_rails("avatar", props: { name: object.name, image_url: object.avatar_url, size: "xs" }) %>
4
4
  <%= pb_rails("title", props: { text: object.name, size: 4, classname: "pb_form_pill_text" }) %>
@@ -11,9 +11,13 @@ module Playbook
11
11
  prop :text_transform, type: Playbook::Props::Enum,
12
12
  values: %w[none lowercase],
13
13
  default: "none"
14
+ prop :color, type: Playbook::Props::Enum,
15
+ values: %w[primary neutral],
16
+ default: "primary"
17
+ prop :tabindex
14
18
 
15
19
  def classname
16
- generate_classname("pb_form_pill_kit", "primary", name, text, text_transform)
20
+ generate_classname("pb_form_pill_kit", color, name, text, text_transform)
17
21
  end
18
22
 
19
23
  def display_text