playbook_ui 13.32.0 → 13.33.0.pre.alpha.PBNTR405dropdownformfixesrails3311

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 (92) 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 +9 -5
  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 +74 -17
  15. data/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +108 -5
  16. data/app/pb_kits/playbook/pb_form_pill/_form_pill.test.jsx +53 -0
  17. data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +11 -2
  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_size.html.erb +2 -0
  21. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_size.jsx +2 -0
  22. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_tag.html.erb +4 -1
  23. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_tag.jsx +3 -2
  24. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_user.html.erb +2 -0
  25. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_user.jsx +2 -0
  26. data/app/pb_kits/playbook/pb_form_pill/form_pill.html.erb +1 -1
  27. data/app/pb_kits/playbook/pb_form_pill/form_pill.rb +5 -1
  28. data/app/pb_kits/playbook/pb_icon/_icon.scss +210 -1
  29. data/app/pb_kits/playbook/pb_icon/_icon.tsx +100 -41
  30. data/app/pb_kits/playbook/pb_icon/icon.rb +33 -19
  31. data/app/pb_kits/playbook/pb_nav/_nav_item.test.js +2 -2
  32. data/app/pb_kits/playbook/pb_nav/docs/_tab_nav.html.erb +48 -0
  33. data/app/pb_kits/playbook/pb_nav/docs/_tab_nav.md +3 -0
  34. data/app/pb_kits/playbook/pb_nav/docs/example.yml +1 -0
  35. data/app/pb_kits/playbook/pb_nav/index.js +43 -0
  36. data/app/pb_kits/playbook/pb_nav/nav.rb +9 -0
  37. data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/MoreExtensionsDropdown.tsx +1 -1
  38. data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/ToolbarDropdown.tsx +1 -1
  39. data/app/pb_kits/playbook/pb_star_rating/_star_rating.scss +11 -2
  40. data/app/pb_kits/playbook/pb_star_rating/docs/_star_rating_interactive.html.erb +1 -0
  41. data/app/pb_kits/playbook/pb_star_rating/docs/example.yml +1 -1
  42. data/app/pb_kits/playbook/pb_star_rating/index.js +50 -0
  43. data/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb +25 -5
  44. data/app/pb_kits/playbook/pb_star_rating/star_rating.rb +6 -0
  45. data/app/pb_kits/playbook/pb_table/_table.tsx +1 -1
  46. data/app/pb_kits/playbook/pb_table/index.ts +4 -4
  47. data/app/pb_kits/playbook/pb_table/subcomponents/_table_body.tsx +1 -1
  48. data/app/pb_kits/playbook/pb_table/subcomponents/_table_cell.tsx +1 -1
  49. data/app/pb_kits/playbook/pb_table/subcomponents/_table_head.tsx +1 -1
  50. data/app/pb_kits/playbook/pb_table/subcomponents/_table_header.tsx +1 -1
  51. data/app/pb_kits/playbook/pb_table/subcomponents/_table_row.tsx +1 -1
  52. data/app/pb_kits/playbook/pb_table/table.test.js +2 -0
  53. data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +1 -1
  54. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_default.jsx +1 -1
  55. data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +45 -27
  56. data/app/pb_kits/playbook/pb_textarea/index.tsx +3 -3
  57. data/app/pb_kits/playbook/pb_time/_time.tsx +3 -3
  58. data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.tsx +1 -1
  59. data/app/pb_kits/playbook/pb_timeline/_item.tsx +1 -1
  60. data/app/pb_kits/playbook/pb_timeline/_timeline.tsx +1 -1
  61. data/app/pb_kits/playbook/pb_title_detail/_title_detail.tsx +10 -10
  62. data/app/pb_kits/playbook/pb_toggle/_toggle.tsx +1 -1
  63. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +2 -2
  64. data/app/pb_kits/playbook/pb_treemap_chart/_treemap_chart.tsx +1 -2
  65. data/app/pb_kits/playbook/pb_treemap_chart/treemapChart.test.js +2 -0
  66. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +3 -3
  67. data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.tsx +4 -4
  68. data/app/pb_kits/playbook/pb_typeahead/components/Control.tsx +11 -7
  69. data/app/pb_kits/playbook/pb_typeahead/components/IndicatorsContainer.tsx +8 -3
  70. data/app/pb_kits/playbook/pb_typeahead/components/MenuList.tsx +6 -1
  71. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +18 -19
  72. data/app/pb_kits/playbook/pb_typeahead/components/Option.tsx +6 -6
  73. data/app/pb_kits/playbook/pb_typeahead/components/Placeholder.tsx +6 -6
  74. data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +3 -3
  75. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_custom_menu_list.jsx +2 -0
  76. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_default.html.erb +22 -57
  77. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_pills_async.jsx +2 -2
  78. data/app/pb_kits/playbook/pb_typeahead/index.ts +31 -31
  79. data/app/pb_kits/playbook/pb_user/_user.tsx +1 -1
  80. data/app/pb_kits/playbook/pb_user_badge/_user_badge.tsx +6 -6
  81. data/app/pb_kits/playbook/pb_user_badge/badges/million-dollar.tsx +236 -235
  82. data/app/pb_kits/playbook/pb_user_badge/badges/veteran.tsx +1 -1
  83. data/app/pb_kits/playbook/pb_walkthrough/_walkthrough.tsx +68 -63
  84. data/app/pb_kits/playbook/pb_weekday_stacked/_weekday_stacked.tsx +2 -2
  85. data/app/pb_kits/playbook/playbook-rails.js +6 -0
  86. data/dist/menu.yml +1 -1
  87. data/dist/playbook-rails.js +7 -7
  88. data/lib/playbook/forms/builder/star_rating_field.rb +14 -0
  89. data/lib/playbook/forms/builder.rb +1 -0
  90. data/lib/playbook/version.rb +2 -2
  91. metadata +16 -6
  92. data/app/pb_kits/playbook/pb_icon/icon_aliases.json +0 -39
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15c98ab4c24f31f753052d92ce96169c82221a5a1b94a6d73f26f39605507324
4
- data.tar.gz: a132e4e59aafc142e919af50b3ced4622e9073e39c1e8d5183a4484a91a72e51
3
+ metadata.gz: 8fbda811742441cdb16b2651544b02a6053acfca38e070ef814ff1f2fcb1c27c
4
+ data.tar.gz: 159b81a126b1d13b8f64f2e16a53326dfbf21b1afd7118c469c95bf7e9524b5b
5
5
  SHA512:
6
- metadata.gz: 51ae3a858325d45b791b217debbff7ac11d9304ced1606a1f037af3329345d293582583ef31c9298143f5e5befa1ff203a90e6a751f127f5ab600eb363c54146
7
- data.tar.gz: c154c881d29dcccecdcfd90638eb619b48747fd2f172f3b136c9ba30686e8bd7e726e6265b06e65e4348df5a9f8d1f6e1d98d79fcfcac334721fd2d9703c6fb9
6
+ metadata.gz: dc57caefdde9638b830c0ad6a010c8e0ada6cd7fd2d72b7b134271ed86de9e3bb7a45a351690afea6950b8c7e8733d3063fac7436e0d1bdc7cdc82074c219289
7
+ data.tar.gz: ddce620575e43112f59837ad5a39d4efbda50072d4c48e3c171b37d8774605ee84770cdcd8c200ef0bb3018dee8b6e8fa10c1a30d58dbbccefa30e1e131158c2
@@ -1,2 +1,6 @@
1
1
  The `customOptions` prop provides comprehensive access to additional [Highcharts options](https://api.highcharts.com/highcharts/) that are not explicitly defined as props.
2
2
  It's important to note that certain options may require specific script imports to function properly.
3
+
4
+ Note: If you are having trouble getting any Highcharts options to work, please match the formatting of our [staticOptions](https://github.com/powerhome/playbook/blob/master/playbook/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx#L85-L141). For example, `yAxis` will need to be wrapped with square brackets.
5
+
6
+ You may also need to override any of the [defaults](https://github.com/powerhome/playbook/blob/master/playbook/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx#L45-L73) in order to get that options to work.
@@ -28,7 +28,7 @@ exports[`html structure is correct 1`] = `
28
28
  style="vertical-align: middle; color: rgb(193, 205, 214);"
29
29
  >
30
30
  <i
31
- class="pb_icon_kit far fa-fw fa-lg fa-chevron-down"
31
+ class="pb_icon_kit far fa-lg fa-fw fa-lg fa-chevron-down"
32
32
  />
33
33
  <span
34
34
  aria-label="chevron-down icon"
@@ -22,10 +22,12 @@ import {
22
22
  type DropdownProps = {
23
23
  aria?: { [key: string]: string };
24
24
  autocomplete?: boolean;
25
+ blankSelection?: string;
25
26
  children?: React.ReactChild[] | React.ReactChild | React.ReactElement[];
26
27
  className?: string;
27
28
  dark?: boolean;
28
29
  data?: { [key: string]: string };
30
+ defaultValue?: GenericObject;
29
31
  error?: string;
30
32
  htmlOptions?: { [key: string]: string | number | boolean | (() => void) },
31
33
  id?: string;
@@ -40,10 +42,12 @@ const Dropdown = (props: DropdownProps) => {
40
42
  const {
41
43
  aria = {},
42
44
  autocomplete = false,
45
+ blankSelection = '',
43
46
  children,
44
47
  className,
45
48
  dark = false,
46
49
  data = {},
50
+ defaultValue = {},
47
51
  error,
48
52
  htmlOptions = {},
49
53
  id,
@@ -66,7 +70,7 @@ const Dropdown = (props: DropdownProps) => {
66
70
  const [isDropDownClosed, setIsDropDownClosed, toggleDropdown] = useDropdown(isClosed);
67
71
 
68
72
  const [filterItem, setFilterItem] = useState("");
69
- const [selected, setSelected] = useState<GenericObject>({});
73
+ const [selected, setSelected] = useState<GenericObject>(defaultValue);
70
74
  const [isInputFocused, setIsInputFocused] = useState(false);
71
75
  const [hasTriggerSubcomponent, setHasTriggerSubcomponent] = useState(true);
72
76
  const [hasContainerSubcomponent, setHasContainerSubcomponent] =
@@ -116,11 +120,12 @@ const Dropdown = (props: DropdownProps) => {
116
120
  setIsDropDownClosed(isClosed)
117
121
  }, [isClosed])
118
122
 
119
- const filteredOptions = options?.filter((option: GenericObject) => {
123
+ const blankSelectionOption: GenericObject = blankSelection ? [{ label: blankSelection, value: "" }] : [];
124
+ const optionsWithBlankSelection = blankSelectionOption.concat(options);
125
+ const filteredOptions = optionsWithBlankSelection?.filter((option: GenericObject) => {
120
126
  const label = typeof option.label === 'string' ? option.label.toLowerCase() : option.label;
121
127
  return String(label).toLowerCase().includes(filterItem.toLowerCase());
122
- }
123
- );
128
+ });
124
129
 
125
130
  // For keyboard accessibility: Set focus within dropdown to selected item if it exists
126
131
  useEffect(() => {
@@ -194,7 +199,7 @@ const Dropdown = (props: DropdownProps) => {
194
199
  inputWrapperRef,
195
200
  isDropDownClosed,
196
201
  isInputFocused,
197
- options,
202
+ optionsWithBlankSelection,
198
203
  selected,
199
204
  setFocusedOptionIndex,
200
205
  setIsDropDownClosed,
@@ -233,8 +238,8 @@ const Dropdown = (props: DropdownProps) => {
233
238
  <>
234
239
  <DropdownTrigger />
235
240
  <DropdownContainer>
236
- {options &&
237
- options?.map((option: GenericObject) => (
241
+ {optionsWithBlankSelection &&
242
+ optionsWithBlankSelection?.map((option: GenericObject) => (
238
243
  <Dropdown.Option key={option.id}
239
244
  option={option}
240
245
  />
@@ -0,0 +1,10 @@
1
+ <%
2
+ options = [
3
+ { label: 'United States', value: 'United States', id: 'us' },
4
+ { label: 'Canada', value: 'Canada', id: 'ca' },
5
+ { label: 'Pakistan', value: 'Pakistan', id: 'pk' },
6
+ ]
7
+
8
+ %>
9
+
10
+ <%= pb_rails("dropdown", props: { blank_selection: "Select One...", options: options }) %>
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+ import { Dropdown } from '../../'
3
+
4
+ const DropdownBlankSelection = (props) => {
5
+ const options = [
6
+ {
7
+ label: "United States",
8
+ value: "United States",
9
+ },
10
+ {
11
+ label: "Canada",
12
+ value: "Canada",
13
+ },
14
+ {
15
+ label: "Pakistan",
16
+ value: "Pakistan",
17
+ }
18
+ ];
19
+
20
+ return (
21
+ <>
22
+ <Dropdown
23
+ blankSelection="Select one..."
24
+ options={options}
25
+ {...props}
26
+ />
27
+ </>
28
+ )
29
+ }
30
+
31
+ export default DropdownBlankSelection
@@ -0,0 +1,10 @@
1
+ <%
2
+ options = [
3
+ { label: 'United States', value: 'United States', id: 'us' },
4
+ { label: 'Canada', value: 'Canada', id: 'ca' },
5
+ { label: 'Pakistan', value: 'Pakistan', id: 'pk' },
6
+ ]
7
+
8
+ %>
9
+
10
+ <%= pb_rails("dropdown", props: {options: options, default_value: options.last}) %>
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+ import { Dropdown } from '../../'
3
+
4
+ const DropdownDefaultValue = (props) => {
5
+ const options = [
6
+ {
7
+ label: "United States",
8
+ value: "United States",
9
+ },
10
+ {
11
+ label: "Canada",
12
+ value: "Canada",
13
+ },
14
+ {
15
+ label: "Pakistan",
16
+ value: "Pakistan",
17
+ }
18
+ ];
19
+
20
+ return (
21
+ <>
22
+ <Dropdown
23
+ defaultValue={options[2]}
24
+ options={options}
25
+ {...props}
26
+ />
27
+ </>
28
+ )
29
+ }
30
+
31
+ export default DropdownDefaultValue
@@ -8,6 +8,8 @@ examples:
8
8
  - dropdown_with_custom_trigger_rails: Custom Trigger
9
9
  - dropdown_with_custom_padding: Custom Option Padding
10
10
  - dropdown_error: Dropdown with Error
11
+ - dropdown_default_value: Default Value
12
+ - dropdown_blank_selection: Blank Selection
11
13
 
12
14
  react:
13
15
  - dropdown_default: Default
@@ -18,6 +20,8 @@ examples:
18
20
  - dropdown_with_custom_trigger: Custom Trigger
19
21
  - dropdown_with_custom_padding: Custom Option Padding
20
22
  - dropdown_error: Dropdown with Error
23
+ - dropdown_default_value: Default Value
24
+ - dropdown_blank_selection: Blank Selection
21
25
  # - dropdown_with_autocomplete: Autocomplete
22
26
  # - dropdown_with_autocomplete_and_custom_display: Autocomplete with Custom Display
23
27
  # - dropdown_with_external_control: useDropdown Hook
@@ -9,4 +9,6 @@ export { default as DropdownWithLabel } from './_dropdown_with_label.jsx'
9
9
  export { default as DropdownWithExternalControl } from './_dropdown_with_external_control.jsx'
10
10
  export { default as DropdownWithHook } from './_dropdown_with_hook.jsx'
11
11
  export { default as DropdownSubcomponentStructure } from './_dropdown_subcomponent_structure.jsx'
12
- export { default as DropdownError } from './_dropdown_error.jsx'
12
+ export { default as DropdownError } from './_dropdown_error.jsx'
13
+ export { default as DropdownDefaultValue } from './_dropdown_default_value.jsx'
14
+ export { default as DropdownBlankSelection } from './_dropdown_blank_selection.jsx'
@@ -8,17 +8,21 @@
8
8
  <%= pb_rails("caption", props: {text: object.label, margin_bottom:"xs"}) %>
9
9
  <% end %>
10
10
  <div class="dropdown_wrapper<%= error_class %>" style="position: relative">
11
- <input type="hidden" name="<%= object.name %>" id="dropdown-selected-option" value="" />
12
- <input id="dropdown-form-validation" name="<%= object.name %>_form_validation" value="" style="display: none" <%= object.required ? "required" : ""%> />
13
-
11
+ <input
12
+ data-default-value="<%= input_default_value %>"
13
+ id="dropdown-selected-option"
14
+ name="<%= object.name %>"
15
+ style="display: none"
16
+ <%= object.required ? "required" : ""%>
17
+ />
14
18
  <% if content.present? %>
15
19
  <%= content.presence %>
16
20
  <%= pb_rails("body", props: { status: "negative", text: object.error }) %>
17
21
  <% else %>
18
22
  <%= pb_rails("dropdown/dropdown_trigger") %>
19
23
  <%= pb_rails("dropdown/dropdown_container") do %>
20
- <% if object.options.present? %>
21
- <% object.options.each do |option| %>
24
+ <% if options_with_blank.present? %>
25
+ <% options_with_blank.each do |option| %>
22
26
  <%= pb_rails("dropdown/dropdown_option", props: {option: option}) %>
23
27
  <% end %>
24
28
  <% end %>
@@ -10,6 +10,9 @@ module Playbook
10
10
  prop :error, type: Playbook::Props::String
11
11
  prop :required, type: Playbook::Props::Boolean,
12
12
  default: false
13
+ prop :default_value
14
+ prop :blank_selection, type: Playbook::Props::String,
15
+ default: ""
13
16
 
14
17
  def data
15
18
  Hash(prop(:data)).merge(pb_dropdown: true)
@@ -24,6 +27,14 @@ module Playbook
24
27
  def error_class
25
28
  error.present? ? " error" : ""
26
29
  end
30
+
31
+ def input_default_value
32
+ default_value.present? ? default_value.transform_keys(&:to_s)["id"] : ""
33
+ end
34
+
35
+ def options_with_blank
36
+ blank_selection.present? ? [{ id: "", value: "", label: blank_selection }] + options : options
37
+ end
27
38
  end
28
39
  end
29
40
  end
@@ -11,7 +11,7 @@ module Playbook
11
11
  prop :custom_display
12
12
 
13
13
  def data
14
- Hash(prop(:data)).merge(dropdown_trigger: true)
14
+ Hash(prop(:data)).merge(dropdown_trigger: true, dropdown_placeholder: default_display_placeholder)
15
15
  end
16
16
 
17
17
  def classname
@@ -8,7 +8,9 @@ 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 INPUT_FORM_VALIDATION = "#dropdown-form-validation";
11
+ const DROPDOWN_TRIGGER_DISPLAY = "#dropdown_trigger_display";
12
+ const DROPDOWN_PLACEHOLDER = "[data-dropdown-placeholder]";
13
+ const DROPDOWN_INPUT = "#dropdown-selected-option";
12
14
 
13
15
  export default class PbDropdown extends PbEnhancedElement {
14
16
  static get selector() {
@@ -21,9 +23,11 @@ export default class PbDropdown extends PbEnhancedElement {
21
23
 
22
24
  connect() {
23
25
  this.keyboardHandler = new PbDropdownKeyboard(this);
26
+ this.setDefaultValue();
24
27
  this.bindEventListeners();
25
28
  this.updateArrowDisplay(false);
26
29
  this.handleFormValidation();
30
+ this.handleFormReset();
27
31
  }
28
32
 
29
33
  bindEventListeners() {
@@ -43,14 +47,13 @@ export default class PbDropdown extends PbEnhancedElement {
43
47
 
44
48
  handleOptionClick(event) {
45
49
  const option = event.target.closest(OPTION_SELECTOR);
46
- const hiddenInput = this.element.querySelector("#dropdown-selected-option");
47
- const inputFormValidation = this.element.querySelector(INPUT_FORM_VALIDATION);
50
+ const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
48
51
 
49
52
  if (option) {
50
53
  const value = option.dataset.dropdownOptionLabel;
51
54
  hiddenInput.value = JSON.parse(value).id;
52
- inputFormValidation.value = JSON.parse(value).id;
53
- this.clearFormValidation(inputFormValidation);
55
+ this.clearFormValidation(hiddenInput);
56
+
54
57
  this.onOptionSelected(value, option);
55
58
  }
56
59
  }
@@ -83,9 +86,7 @@ export default class PbDropdown extends PbEnhancedElement {
83
86
  }
84
87
 
85
88
  onOptionSelected(value, selectedOption) {
86
- const triggerElement = this.element.querySelector(
87
- "#dropdown_trigger_display"
88
- );
89
+ const triggerElement = this.element.querySelector(DROPDOWN_TRIGGER_DISPLAY);
89
90
  const customDisplayElement = this.element.querySelector(
90
91
  "#dropdown_trigger_custom_display"
91
92
  );
@@ -158,14 +159,18 @@ export default class PbDropdown extends PbEnhancedElement {
158
159
  }
159
160
 
160
161
  handleFormValidation() {
161
- const inputFormValidation = this.element.querySelector(INPUT_FORM_VALIDATION);
162
-
163
- inputFormValidation.addEventListener("invalid", function (event) {
164
- if (inputFormValidation.hasAttribute("required") && inputFormValidation.value === "") {
165
- event.preventDefault();
166
- inputFormValidation.closest(".dropdown_wrapper").classList.add("error");
167
- }
168
- }, true);
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
+ );
169
174
  }
170
175
 
171
176
  clearFormValidation(input) {
@@ -173,10 +178,62 @@ export default class PbDropdown extends PbEnhancedElement {
173
178
  const dropdownWrapperElement = input.closest(".dropdown_wrapper");
174
179
  dropdownWrapperElement.classList.remove("error");
175
180
 
176
- const errorLabelElement = dropdownWrapperElement.querySelector(".pb_body_kit_negative");
181
+ const errorLabelElement = dropdownWrapperElement.querySelector(
182
+ ".pb_body_kit_negative"
183
+ );
177
184
  if (errorLabelElement) {
178
185
  errorLabelElement.remove();
179
186
  }
180
187
  }
181
188
  }
189
+
190
+ setDefaultValue() {
191
+ const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
192
+ const options = this.element.querySelectorAll(OPTION_SELECTOR);
193
+
194
+ const defaultValue = hiddenInput.dataset.defaultValue || "";
195
+ hiddenInput.value = defaultValue;
196
+
197
+ if (defaultValue) {
198
+ const selectedOption = Array.from(options).find((option) => {
199
+ return (
200
+ JSON.parse(option.dataset.dropdownOptionLabel).id === defaultValue
201
+ );
202
+ });
203
+ selectedOption.classList.add("pb_dropdown_option_selected");
204
+ this.setTriggerElementText(
205
+ JSON.parse(selectedOption.dataset.dropdownOptionLabel).label
206
+ );
207
+ }
208
+ }
209
+
210
+ handleFormReset() {
211
+ const form = this.element.closest("form");
212
+
213
+ if (form) {
214
+ form.addEventListener("reset", () => {
215
+ this.resetDropdownValue();
216
+ });
217
+ }
218
+ }
219
+
220
+ resetDropdownValue() {
221
+ const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
222
+ const options = this.element.querySelectorAll(OPTION_SELECTOR);
223
+ options.forEach((option) => {
224
+ option.classList.remove("pb_dropdown_option_selected");
225
+ });
226
+
227
+ hiddenInput.value = "";
228
+
229
+ const defaultPlaceholder = this.element.querySelector(DROPDOWN_PLACEHOLDER);
230
+ this.setTriggerElementText(defaultPlaceholder.dataset.dropdownPlaceholder);
231
+ }
232
+
233
+ setTriggerElementText(text) {
234
+ const triggerElement = this.element.querySelector(DROPDOWN_TRIGGER_DISPLAY);
235
+ if (triggerElement) {
236
+ triggerElement.textContent = text;
237
+ }
238
+ }
182
239
  }
@@ -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,34 +24,71 @@ $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;
@@ -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 &&