playbook_ui 14.19.0 β†’ 14.20.0.pre.alpha.PLAY2127dropdowncloseonselectionpropreact8006

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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +11 -1
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +175 -16
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +56 -25
  5. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +23 -13
  6. data/app/pb_kits/playbook/pb_advanced_table/Utilities/VisibilityTree.ts +47 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +14 -10
  8. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +7 -2
  9. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +16 -8
  10. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +9 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.md +6 -2
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.jsx +57 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.md +4 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.jsx +62 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.md +1 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.jsx +82 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.md +1 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.jsx +66 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md +3 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +1 -1
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions_rails.html.erb +137 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_actions_rails.md +3 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header_rails.html.erb +40 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_header_rails.md +1 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +6 -0
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +5 -1
  27. data/app/pb_kits/playbook/pb_advanced_table/index.js +155 -12
  28. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/advanced_table_sticky_mixin.scss +1 -0
  29. data/app/pb_kits/playbook/pb_advanced_table/table_action_bar.html.erb +23 -0
  30. data/app/pb_kits/playbook/pb_advanced_table/table_action_bar.rb +19 -0
  31. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +4 -0
  32. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +4 -11
  33. data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +10 -6
  34. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.html.erb +2 -48
  35. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate_rails.md +1 -0
  36. data/app/pb_kits/playbook/pb_checkbox/index.js +56 -0
  37. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +1 -1
  38. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +86 -19
  39. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_close_on_select.jsx +42 -0
  40. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_close_on_select.md +1 -0
  41. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.html.erb +31 -0
  42. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.md +5 -0
  43. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.jsx +56 -0
  44. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.md +3 -0
  45. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.jsx +58 -0
  46. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.md +3 -0
  47. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.html.erb +20 -0
  48. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.md +1 -0
  49. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.html.erb +19 -0
  50. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.md +3 -0
  51. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.html.erb +20 -0
  52. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.jsx +57 -0
  53. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.md +1 -0
  54. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.html.erb +50 -0
  55. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.jsx +105 -0
  56. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.html.erb +22 -0
  57. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.jsx +67 -0
  58. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.jsx +11 -0
  59. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.md +1 -1
  60. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.html.erb +33 -2
  61. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.md +3 -1
  62. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +13 -1
  63. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +6 -0
  64. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +3 -3
  65. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +16 -2
  66. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +108 -2
  67. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +34 -13
  68. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +3 -1
  69. data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +0 -6
  70. data/app/pb_kits/playbook/pb_dropdown/index.js +359 -29
  71. data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +39 -12
  72. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +2 -2
  73. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +26 -18
  74. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +97 -20
  75. data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +58 -0
  76. data/app/pb_kits/playbook/pb_file_upload/_file_upload.scss +13 -0
  77. data/app/pb_kits/playbook/pb_file_upload/_file_upload.tsx +11 -1
  78. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.html.erb +1 -0
  79. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.jsx +41 -0
  80. data/app/pb_kits/playbook/pb_file_upload/docs/example.yml +2 -0
  81. data/app/pb_kits/playbook/pb_file_upload/docs/index.js +1 -0
  82. data/app/pb_kits/playbook/pb_file_upload/file_upload.html.erb +1 -0
  83. data/app/pb_kits/playbook/pb_file_upload/file_upload.rb +7 -1
  84. data/app/pb_kits/playbook/pb_file_upload/fileupload.test.js +18 -0
  85. data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +1 -0
  86. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -0
  87. data/app/pb_kits/playbook/pb_form_group/_error_state_mixin.scss +2 -2
  88. data/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +19 -12
  89. data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.tsx +13 -7
  90. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +2 -2
  91. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_color.html.erb +11 -11
  92. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_color.jsx +11 -11
  93. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.html.erb +11 -11
  94. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +11 -11
  95. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.html.erb +11 -11
  96. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.jsx +11 -11
  97. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.html.erb +11 -11
  98. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.jsx +11 -11
  99. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.html.erb +11 -11
  100. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.jsx +11 -11
  101. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.html.erb +11 -11
  102. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.jsx +11 -11
  103. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.html.erb +11 -11
  104. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.jsx +11 -11
  105. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_error.html.erb +11 -11
  106. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_error.jsx +11 -11
  107. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.html.erb +11 -11
  108. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.jsx +11 -11
  109. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_react_hook.jsx +11 -11
  110. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_reset.html.erb +11 -11
  111. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.html.erb +11 -11
  112. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.jsx +11 -11
  113. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids.html.erb +11 -11
  114. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids.md +2 -0
  115. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids_react.jsx +11 -11
  116. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids_react.md +3 -1
  117. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single.html.erb +22 -22
  118. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single.jsx +22 -22
  119. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single_children_only.html.erb +22 -22
  120. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single_children_only.jsx +22 -22
  121. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx +11 -11
  122. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +11 -11
  123. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_form.html.erb +11 -11
  124. data/app/pb_kits/playbook/pb_person/_person.tsx +12 -2
  125. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +9 -9
  126. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +4 -0
  127. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_exclude_countries.html.erb +4 -0
  128. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_exclude_countries.jsx +15 -0
  129. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_exclude_countries.md +1 -0
  130. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_only_countries.jsx +1 -1
  131. data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +4 -3
  132. data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +1 -0
  133. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +3 -0
  134. data/app/pb_kits/playbook/pb_section_separator/_section_separator.tsx +2 -2
  135. data/app/pb_kits/playbook/pb_select/docs/_select_custom_select_subheaders.html.erb +12 -0
  136. data/app/pb_kits/playbook/pb_select/docs/_select_custom_select_subheaders.jsx +31 -0
  137. data/app/pb_kits/playbook/pb_select/docs/_select_custom_select_subheaders.md +1 -0
  138. data/app/pb_kits/playbook/pb_select/docs/example.yml +2 -0
  139. data/app/pb_kits/playbook/pb_select/docs/index.js +1 -0
  140. data/app/pb_kits/playbook/pb_table/docs/_table_with_selectable_rows.html.erb +3 -51
  141. data/app/pb_kits/playbook/pb_text_input/_text_input.scss +4 -2
  142. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +73 -3
  143. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.jsx +23 -0
  144. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.md +1 -0
  145. data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +1 -0
  146. data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
  147. data/dist/chunks/_typeahead-CRW6dJbW.js +22 -0
  148. data/dist/chunks/_weekday_stacked-fRmhq4xQ.js +45 -0
  149. data/dist/chunks/lazysizes-B7xYodB-.js +1 -0
  150. data/dist/chunks/lib-D5R1BjUn.js +29 -0
  151. data/dist/chunks/{pb_form_validation-BioH7DWv.js β†’ pb_form_validation-BZ2AVAi_.js} +1 -1
  152. data/dist/chunks/vendor.js +1 -1
  153. data/dist/menu.yml +1 -1
  154. data/dist/playbook-doc.js +2 -2
  155. data/dist/playbook-rails-react-bindings.js +1 -1
  156. data/dist/playbook-rails.js +1 -1
  157. data/dist/playbook.css +1 -1
  158. data/lib/playbook/kit_base.rb +3 -3
  159. data/lib/playbook/version.rb +2 -2
  160. metadata +54 -8
  161. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.html.erb +0 -10
  162. data/dist/chunks/_typeahead-D62OcwsT.js +0 -22
  163. data/dist/chunks/_weekday_stacked-Ceh9N0ow.js +0 -45
  164. data/dist/chunks/lazysizes-DHz07jlL.js +0 -1
  165. data/dist/chunks/lib-CeKZrPmu.js +0 -29
@@ -1,4 +1,4 @@
1
- import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from "react";
1
+ import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle, useMemo } from "react";
2
2
  import classnames from "classnames";
3
3
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
4
4
  import { globalProps } from "../utilities/globalProps";
@@ -25,6 +25,8 @@ type DropdownProps = {
25
25
  blankSelection?: string;
26
26
  children?: React.ReactChild[] | React.ReactChild | React.ReactElement[];
27
27
  className?: string;
28
+ closeOnSelection?: boolean;
29
+ formPillProps?: GenericObject;
28
30
  dark?: boolean;
29
31
  data?: { [key: string]: string };
30
32
  defaultValue?: GenericObject;
@@ -33,6 +35,7 @@ type DropdownProps = {
33
35
  id?: string;
34
36
  isClosed?: boolean;
35
37
  label?: string;
38
+ multiSelect?: boolean;
36
39
  onSelect?: (arg: GenericObject) => null;
37
40
  options: GenericObject;
38
41
  separators?: boolean;
@@ -53,6 +56,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
53
56
  blankSelection = '',
54
57
  children,
55
58
  className,
59
+ closeOnSelection = true,
56
60
  dark = false,
57
61
  data = {},
58
62
  defaultValue = {},
@@ -61,6 +65,8 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
61
65
  id,
62
66
  isClosed = true,
63
67
  label,
68
+ multiSelect = false,
69
+ formPillProps,
64
70
  onSelect,
65
71
  options,
66
72
  separators = true,
@@ -80,7 +86,20 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
80
86
  const [isDropDownClosed, setIsDropDownClosed, toggleDropdown] = useDropdown(isClosed);
81
87
 
82
88
  const [filterItem, setFilterItem] = useState("");
83
- const [selected, setSelected] = useState<GenericObject>(defaultValue);
89
+ const initialSelected = useMemo(() => {
90
+ if (multiSelect) {
91
+ if (Array.isArray(defaultValue)) return defaultValue;
92
+ return defaultValue && Object.keys(defaultValue).length
93
+ ? [defaultValue]
94
+ : [];
95
+ }
96
+ return defaultValue || {};
97
+ }, [multiSelect, defaultValue]);
98
+
99
+ const [selected, setSelected] = useState<GenericObject | GenericObject[]>(
100
+ initialSelected
101
+ );
102
+
84
103
  const [isInputFocused, setIsInputFocused] = useState(false);
85
104
  const [hasTriggerSubcomponent, setHasTriggerSubcomponent] = useState(true);
86
105
  const [hasContainerSubcomponent, setHasContainerSubcomponent] =
@@ -93,6 +112,12 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
93
112
  const inputWrapperRef = useRef(null);
94
113
  const dropdownContainerRef = useRef(null);
95
114
 
115
+ const selectedArray = Array.isArray(selected)
116
+ ? selected
117
+ : selected && Object.keys(selected).length
118
+ ? [selected]
119
+ : [];
120
+
96
121
  const { trigger, container, otherChildren } =
97
122
  separateChildComponents(children);
98
123
 
@@ -124,16 +149,23 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
124
149
 
125
150
  const blankSelectionOption: GenericObject = blankSelection ? [{ label: blankSelection, value: "" }] : [];
126
151
  const optionsWithBlankSelection = blankSelectionOption.concat(options);
127
- const filteredOptions = optionsWithBlankSelection?.filter((option: GenericObject) => {
128
- const label = typeof option.label === 'string' ? option.label.toLowerCase() : option.label;
129
- return String(label).toLowerCase().includes(filterItem.toLowerCase());
130
- });
152
+
153
+ const availableOptions = useMemo(()=> {
154
+ if (!multiSelect) return optionsWithBlankSelection;
155
+ return optionsWithBlankSelection.filter((option: GenericObject) => !selectedArray.some((sel) => sel.label === option.label));
156
+ }, [optionsWithBlankSelection, selectedArray, multiSelect]);
157
+
158
+ const filteredOptions = useMemo(() => {
159
+ return availableOptions.filter((opt: GenericObject) =>
160
+ String(opt.label).toLowerCase().includes(filterItem.toLowerCase())
161
+ );
162
+ }, [availableOptions, filterItem]);
131
163
 
132
164
  // For keyboard accessibility: Set focus within dropdown to selected item if it exists
133
165
  useEffect(() => {
134
166
  if (!isDropDownClosed) {
135
167
  let newIndex = 0;
136
- if (selected && selected?.label) {
168
+ if (selected && !Array.isArray(selected) && selected.label) {
137
169
  const selectedIndex = filteredOptions.findIndex((option: GenericObject) => option.label === selected.label);
138
170
  if (selectedIndex >= 0) {
139
171
  newIndex = selectedIndex;
@@ -149,12 +181,33 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
149
181
  setIsDropDownClosed(false);
150
182
  };
151
183
 
152
- const handleOptionClick = (selectedItem: GenericObject) => {
153
- setSelected(selectedItem);
154
- setFilterItem("");
155
- setIsDropDownClosed(true);
156
- onSelect && onSelect(selectedItem);
157
- };
184
+
185
+ const handleOptionClick = (clickedItem: GenericObject) => {
186
+ if (multiSelect) {
187
+ setSelected((prev) => {
188
+ const list = prev as GenericObject[];
189
+ const exists = list.find((option) => option.value === clickedItem.value);
190
+ const next = exists
191
+ ? list.filter((option) => option.value !== clickedItem.value)
192
+ : [...list, clickedItem];
193
+ onSelect && onSelect(next);
194
+ return next;
195
+ });
196
+ setFilterItem("");
197
+ // Only close dropdown if closeOnSelection is true
198
+ if (closeOnSelection) {
199
+ setIsDropDownClosed(true);
200
+ }
201
+ } else {
202
+ setSelected(clickedItem);
203
+ setFilterItem("");
204
+ onSelect && onSelect(clickedItem);
205
+ // Only close dropdown if closeOnSelection is true
206
+ if (closeOnSelection) {
207
+ setIsDropDownClosed(true);
208
+ }
209
+ }
210
+ };
158
211
 
159
212
  const handleWrapperClick = () => {
160
213
  autocomplete && inputRef?.current?.focus();
@@ -162,9 +215,14 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
162
215
  };
163
216
 
164
217
  const handleBackspace = () => {
218
+ if (multiSelect) {
219
+ setSelected([]);
220
+ onSelect && onSelect([]);
221
+ } else {
165
222
  setSelected({});
166
223
  onSelect && onSelect(null);
167
224
  setFocusedOptionIndex(-1);
225
+ }
168
226
  };
169
227
 
170
228
  const componentsToRender = prepareSubcomponents({
@@ -178,12 +236,17 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
178
236
  });
179
237
 
180
238
  useImperativeHandle(ref, () => ({
181
- clearSelected: () => {
182
- setSelected({});
183
- setFilterItem("");
184
- setIsDropDownClosed(true);
185
- onSelect && onSelect(null);
186
- },
239
+ clearSelected: () => {
240
+ if (multiSelect) {
241
+ setSelected([]);
242
+ onSelect && onSelect([]);
243
+ } else {
244
+ setSelected({});
245
+ onSelect && onSelect(null);
246
+ }
247
+ setFilterItem("");
248
+ setIsDropDownClosed(true);
249
+ },
187
250
  }));
188
251
 
189
252
  return (
@@ -197,10 +260,12 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
197
260
  <DropdownContext.Provider
198
261
  value={{
199
262
  autocomplete,
263
+ closeOnSelection,
200
264
  dropdownContainerRef,
201
265
  filteredOptions,
202
266
  filterItem,
203
267
  focusedOptionIndex,
268
+ formPillProps,
204
269
  handleBackspace,
205
270
  handleChange,
206
271
  handleOptionClick,
@@ -209,6 +274,8 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
209
274
  inputWrapperRef,
210
275
  isDropDownClosed,
211
276
  isInputFocused,
277
+ multiSelect,
278
+ onSelect,
212
279
  optionsWithBlankSelection,
213
280
  selected,
214
281
  setFocusedOptionIndex,
@@ -0,0 +1,42 @@
1
+ import React from 'react'
2
+ import Dropdown from '../../pb_dropdown/_dropdown'
3
+
4
+ const DropdownCloseOnSelect = (props) => {
5
+
6
+ const options = [
7
+ {
8
+ label: "United States",
9
+ value: "United States",
10
+ },
11
+ {
12
+ label: "Canada",
13
+ value: "Canada",
14
+ },
15
+ {
16
+ label: "Pakistan",
17
+ value: "Pakistan",
18
+ }
19
+ ];
20
+
21
+
22
+ return (
23
+ <div>
24
+ <Dropdown
25
+ closeOnSelection={false}
26
+ label="Default"
27
+ options={options}
28
+ {...props}
29
+ />
30
+ <br />
31
+ <Dropdown
32
+ closeOnSelection={false}
33
+ label="Multi Select"
34
+ multiSelect
35
+ options={options}
36
+ {...props}
37
+ />
38
+ </div>
39
+ )
40
+ }
41
+
42
+ export default DropdownCloseOnSelect
@@ -0,0 +1 @@
1
+ By default, the dropdown menu will close when a selection is made. You can prevent this behavior by using the `closeOnSelection` prop, which will leave the menu open after a selection is made when set to 'false'.
@@ -0,0 +1,31 @@
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
+ <%
11
+ options2 = [
12
+ { label: 'India', value: 'India', id: 'in' },
13
+ { label: 'Mexico', value: 'Mexico', id: 'mx' },
14
+ { label: 'Brazil', value: 'Brazil', id: 'br' },
15
+ { label: 'Argentina', value: 'Argentina', id: 'ar' },
16
+ { label: 'Colombia', value: 'Colombia', id: 'co' },
17
+ { label: 'Chile', value: 'Chile', id: 'cl' },
18
+ { label: 'Peru', value: 'Peru', id: 'pe' },
19
+ ]
20
+
21
+ %>
22
+
23
+ <%= pb_rails("dropdown", props: {options: options}) %>
24
+
25
+ <script>
26
+ document.addEventListener("pb:dropdown:selected", (e) => {
27
+ const option = e.detail;
28
+ const dropdown = e.target;
29
+ console.log("Selected option:", option);
30
+ })
31
+ </script>
@@ -0,0 +1,5 @@
1
+ This kit's `options` prop requires an array of objects, each of which will be used as the selectable options within the dropdown. Each option object can support any number of key-value pairs, but each MUST contain `label`, `value` and `id`.
2
+
3
+ The kit also comes with a custom event called "pb:dropdown:selected" which updates dynamically with the selection as it changes. See code snippet to see this in action.
4
+
5
+ In addition, a data attribute called `data-option-selected` with the selection is also rendered on the parent dropdown div.
@@ -0,0 +1,56 @@
1
+ import React from 'react'
2
+ import Dropdown from '../../pb_dropdown/_dropdown'
3
+
4
+ const DropdownMultiSelect = (props) => {
5
+
6
+ const options = [
7
+ {
8
+ label: "United States",
9
+ value: "United States",
10
+ },
11
+ {
12
+ label: "United Kingdom",
13
+ value: "United Kingdom",
14
+ },
15
+ {
16
+ label: "Canada",
17
+ value: "Canada",
18
+ },
19
+ {
20
+ label: "Pakistan",
21
+ value: "Pakistan",
22
+ },
23
+ {
24
+ label: "India",
25
+ value: "India",
26
+ },
27
+ {
28
+ label: "Australia",
29
+ value: "Australia",
30
+ },
31
+ {
32
+ label: "New Zealand",
33
+ value: "New Zealand",
34
+ },
35
+ {
36
+ label: "Italy",
37
+ value: "Italy",
38
+ },
39
+ {
40
+ label: "Spain",
41
+ value: "Spain",
42
+ }
43
+ ];
44
+
45
+ return (
46
+ <div>
47
+ <Dropdown
48
+ multiSelect
49
+ options={options}
50
+ {...props}
51
+ />
52
+ </div>
53
+ )
54
+ }
55
+
56
+ export default DropdownMultiSelect
@@ -0,0 +1,3 @@
1
+ `multiSelect` is a boolean prop that if set to true will allow for multiple options to be selected from the Dropdown.
2
+
3
+ `multiSelect` is set to false by default.
@@ -0,0 +1,58 @@
1
+ import React from 'react'
2
+ import Dropdown from '../../pb_dropdown/_dropdown'
3
+
4
+ const DropdownMultiSelectDisplay = (props) => {
5
+
6
+ const options = [
7
+ {
8
+ label: "United States",
9
+ value: "United States",
10
+ },
11
+ {
12
+ label: "United Kingdom",
13
+ value: "United Kingdom",
14
+ },
15
+ {
16
+ label: "Canada",
17
+ value: "Canada",
18
+ },
19
+ {
20
+ label: "Pakistan",
21
+ value: "Pakistan",
22
+ },
23
+ {
24
+ label: "India",
25
+ value: "India",
26
+ },
27
+ {
28
+ label: "Australia",
29
+ value: "Australia",
30
+ },
31
+ {
32
+ label: "New Zealand",
33
+ value: "New Zealand",
34
+ },
35
+ {
36
+ label: "Italy",
37
+ value: "Italy",
38
+ },
39
+ {
40
+ label: "Spain",
41
+ value: "Spain",
42
+ }
43
+ ];
44
+
45
+
46
+ return (
47
+ <div>
48
+ <Dropdown
49
+ formPillProps={{size:"small", color:"neutral"}}
50
+ multiSelect
51
+ options={options}
52
+ {...props}
53
+ />
54
+ </div>
55
+ )
56
+ }
57
+
58
+ export default DropdownMultiSelectDisplay
@@ -0,0 +1,3 @@
1
+ By default, the `multiSelect` prop will render selected options as the default FormPill. `FormPillProps` however can be used to customize these Pills with any props that exist for the FormPill.
2
+
3
+ This prop must be an object that contains valid FormPill props. For a full list of FormPill props, see [here](https://playbook.powerapp.cloud/kits/form_pill/react).
@@ -0,0 +1,20 @@
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
+ { label: 'India', value: 'India', id: 'in' },
7
+ { label: 'United Kingdom', value: 'United Kingdom', id: 'uk' },
8
+ { label: 'Australia', value: 'Australia', id: 'au' },
9
+ { label: 'New Zealand', value: 'New Zealand', id: 'nz' },
10
+ { label: 'Germany', value: 'Germany', id: 'de' },
11
+ { label: 'France', value: 'France', id: 'fr' },
12
+ { label: 'Italy', value: 'Italy', id: 'it' },
13
+ ]
14
+ %>
15
+
16
+ <%= pb_rails("dropdown", props: {
17
+ options: options,
18
+ multi_select: true,
19
+ form_pill_props: { size:"small", color:"neutral" },
20
+ }) %>
@@ -0,0 +1 @@
1
+ By default, the `multi_select` prop will render selected options as the default form_pill. `form_pill_props` however can be used to customize these Pills with props that exist for the form_pill. Currently, only the '[color](https://playbook.powerapp.cloud/kits/form_pill/rails#form-pill-colors)' and '[size](https://playbook.powerapp.cloud/kits/form_pill/rails#form-pill-size)' props are supported as shown here.
@@ -0,0 +1,19 @@
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
+ { label: 'India', value: 'India', id: 'in' },
7
+ { label: 'United Kingdom', value: 'United Kingdom', id: 'uk' },
8
+ { label: 'Australia', value: 'Australia', id: 'au' },
9
+ { label: 'New Zealand', value: 'New Zealand', id: 'nz' },
10
+ { label: 'Germany', value: 'Germany', id: 'de' },
11
+ { label: 'France', value: 'France', id: 'fr' },
12
+ { label: 'Italy', value: 'Italy', id: 'it' },
13
+ ]
14
+ %>
15
+
16
+ <%= pb_rails("dropdown", props: {
17
+ options: options,
18
+ multi_select: true,
19
+ }) %>
@@ -0,0 +1,3 @@
1
+ `multi_select` is a boolean prop that if set to true will allow for multiple options to be selected from the Dropdown.
2
+
3
+ `multi_select` is set to false by default.
@@ -0,0 +1,20 @@
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
+ { label: 'India', value: 'India', id: 'in' },
7
+ { label: 'United Kingdom', value: 'United Kingdom', id: 'uk' },
8
+ { label: 'Australia', value: 'Australia', id: 'au' },
9
+ { label: 'New Zealand', value: 'New Zealand', id: 'nz' },
10
+ { label: 'Germany', value: 'Germany', id: 'de' },
11
+ { label: 'France', value: 'France', id: 'fr' },
12
+ { label: 'Italy', value: 'Italy', id: 'it' },
13
+ ]
14
+ %>
15
+
16
+ <%= pb_rails("dropdown", props: {
17
+ autocomplete: true,
18
+ options: options,
19
+ multi_select: true,
20
+ }) %>
@@ -0,0 +1,57 @@
1
+ import React from 'react'
2
+ import Dropdown from '../../pb_dropdown/_dropdown'
3
+
4
+ const DropdownMultiSelectWithAutocomplete = (props) => {
5
+
6
+ const options = [
7
+ {
8
+ label: "United States",
9
+ value: "United States",
10
+ },
11
+ {
12
+ label: "United Kingdom",
13
+ value: "United Kingdom",
14
+ },
15
+ {
16
+ label: "Canada",
17
+ value: "Canada",
18
+ },
19
+ {
20
+ label: "Pakistan",
21
+ value: "Pakistan",
22
+ },
23
+ {
24
+ label: "India",
25
+ value: "India",
26
+ },
27
+ {
28
+ label: "Australia",
29
+ value: "Australia",
30
+ },
31
+ {
32
+ label: "New Zealand",
33
+ value: "New Zealand",
34
+ },
35
+ {
36
+ label: "Italy",
37
+ value: "Italy",
38
+ },
39
+ {
40
+ label: "Spain",
41
+ value: "Spain",
42
+ }
43
+ ];
44
+
45
+ return (
46
+ <div>
47
+ <Dropdown
48
+ autocomplete
49
+ multiSelect
50
+ options={options}
51
+ {...props}
52
+ />
53
+ </div>
54
+ )
55
+ }
56
+
57
+ export default DropdownMultiSelectWithAutocomplete
@@ -0,0 +1 @@
1
+ `multiSelect` can also be used with the `autocomplete` functionality.
@@ -0,0 +1,50 @@
1
+ <%
2
+ options = [
3
+ {
4
+ label: "United States",
5
+ value: "United States",
6
+ areaCode: "+1",
7
+ icon: "πŸ‡ΊπŸ‡Έ",
8
+ id: "us"
9
+ },
10
+ {
11
+ label: "Canada",
12
+ value: "Canada",
13
+ areaCode: "+1",
14
+ icon: "πŸ‡¨πŸ‡¦",
15
+ id: "ca"
16
+ },
17
+ {
18
+ label: "Pakistan",
19
+ value: "Pakistan",
20
+ areaCode: "+92",
21
+ icon: "πŸ‡΅πŸ‡°",
22
+ id: "pk"
23
+ }
24
+ ]
25
+
26
+ %>
27
+
28
+ <%= pb_rails("dropdown", props: { options: options, multi_select: true }) do %>
29
+ <%= pb_rails("dropdown/dropdown_trigger", props:{ multi_select: true }) %>
30
+ <%= pb_rails("dropdown/dropdown_container") do %>
31
+ <% options.each do |option| %>
32
+ <%= pb_rails("dropdown/dropdown_option", props: {option: option}) do %>
33
+ <%= pb_rails("flex", props: {
34
+ align: "center",
35
+ justify: "between",
36
+ }) do %>
37
+ <%= pb_rails("flex/flex_item") do %>
38
+ <%= pb_rails("flex") do %>
39
+ <%= pb_rails("icon", props: {icon: option[:icon]}) %>
40
+ <%= pb_rails("body", props: {text: option[:label], padding_left:"xs"}) %>
41
+ <% end %>
42
+ <% end %>
43
+ <%= pb_rails("flex/flex_item") do %>
44
+ <%= pb_rails("body", props: {color:"light", text: option[:areaCode]}) %>
45
+ <% end %>
46
+ <% end %>
47
+ <% end %>
48
+ <% end %>
49
+ <% end %>
50
+ <% end %>