playbook_ui 13.25.0 β†’ 13.26.0.pre.alpha.jasoncypretpatch12816

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 (224) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/index.js +1 -0
  3. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +14 -0
  4. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +10 -14
  5. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.html.erb +33 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.md +24 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +5 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +2 -2
  9. data/app/pb_kits/playbook/pb_advanced_table/index.js +78 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/table_body.html.erb +5 -9
  11. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +4 -2
  12. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +2 -6
  13. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +5 -8
  14. data/app/pb_kits/playbook/pb_avatar/Utilities/GetPlacementPropsHelper.tsx +44 -0
  15. data/app/pb_kits/playbook/pb_avatar/_avatar.tsx +86 -21
  16. data/app/pb_kits/playbook/pb_avatar/avatar.html.erb +26 -3
  17. data/app/pb_kits/playbook/pb_avatar/avatar.rb +41 -0
  18. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_badge_component_overlay.html.erb +71 -0
  19. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_badge_component_overlay.jsx +77 -0
  20. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_circle_icon_component_overlay.html.erb +71 -0
  21. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_circle_icon_component_overlay.jsx +77 -0
  22. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_default.jsx +20 -0
  23. data/app/pb_kits/playbook/pb_avatar/docs/example.yml +4 -0
  24. data/app/pb_kits/playbook/pb_avatar/docs/index.js +2 -0
  25. data/app/pb_kits/playbook/pb_avatar_action_button/avatar_action_button.html.erb +1 -6
  26. data/app/pb_kits/playbook/pb_background/background.html.erb +2 -11
  27. data/app/pb_kits/playbook/pb_badge/badge.html.erb +1 -6
  28. data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.tsx +1 -1
  29. data/app/pb_kits/playbook/pb_body/_body.tsx +1 -1
  30. data/app/pb_kits/playbook/pb_body/body.html.erb +1 -6
  31. data/app/pb_kits/playbook/pb_bread_crumbs/bread_crumb_item.html.erb +1 -6
  32. data/app/pb_kits/playbook/pb_bread_crumbs/bread_crumbs.html.erb +2 -7
  33. data/app/pb_kits/playbook/pb_button/_button.scss +1 -1
  34. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +1 -0
  35. data/app/pb_kits/playbook/pb_button/button.html.erb +2 -3
  36. data/app/pb_kits/playbook/pb_button_toolbar/button_toolbar.html.erb +2 -7
  37. data/app/pb_kits/playbook/pb_caption/caption.html.erb +1 -6
  38. data/app/pb_kits/playbook/pb_card/card.html.erb +1 -7
  39. data/app/pb_kits/playbook/pb_card/card_body.html.erb +1 -6
  40. data/app/pb_kits/playbook/pb_card/card_header.html.erb +1 -6
  41. data/app/pb_kits/playbook/pb_checkbox/_checkbox.scss +49 -0
  42. data/app/pb_kits/playbook/pb_checkbox/_checkbox.tsx +3 -0
  43. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +1 -6
  44. data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +2 -1
  45. data/app/pb_kits/playbook/pb_checkbox/checkbox.test.js +14 -0
  46. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_disabled.html.erb +23 -0
  47. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_disabled.jsx +29 -0
  48. data/app/pb_kits/playbook/pb_checkbox/docs/example.yml +2 -0
  49. data/app/pb_kits/playbook/pb_checkbox/docs/index.js +1 -0
  50. data/app/pb_kits/playbook/pb_circle_icon_button/circle_icon_button.html.erb +1 -6
  51. data/app/pb_kits/playbook/pb_collapsible/collapsible.html.erb +1 -6
  52. data/app/pb_kits/playbook/pb_collapsible/collapsible_content.html.erb +1 -6
  53. data/app/pb_kits/playbook/pb_collapsible/collapsible_main.html.erb +1 -7
  54. data/app/pb_kits/playbook/pb_contact/contact.html.erb +1 -6
  55. data/app/pb_kits/playbook/pb_currency/currency.html.erb +1 -6
  56. data/app/pb_kits/playbook/pb_currency/docs/_currency_alignment_swift.md +43 -0
  57. data/app/pb_kits/playbook/pb_currency/docs/_currency_props_swift.md +12 -0
  58. data/app/pb_kits/playbook/pb_currency/docs/_currency_size_swift.md +31 -0
  59. data/app/pb_kits/playbook/pb_currency/docs/example.yml +5 -0
  60. data/app/pb_kits/playbook/pb_dashboard_value/dashboard_value.html.erb +1 -6
  61. data/app/pb_kits/playbook/pb_date/date.html.erb +1 -6
  62. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +2 -6
  63. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_change.md +3 -1
  64. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_on_close.md +3 -1
  65. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_range_limit.md +1 -1
  66. data/app/pb_kits/playbook/pb_date_range_inline/date_range_inline.html.erb +1 -5
  67. data/app/pb_kits/playbook/pb_date_range_stacked/date_range_stacked.html.erb +1 -5
  68. data/app/pb_kits/playbook/pb_date_range_stacked/docs/_date_range_stacked_default_swift.md +14 -0
  69. data/app/pb_kits/playbook/pb_date_range_stacked/docs/_date_range_stacked_props_swift.md +9 -0
  70. data/app/pb_kits/playbook/pb_date_range_stacked/docs/example.yml +4 -0
  71. data/app/pb_kits/playbook/pb_date_stacked/date_stacked.html.erb +1 -5
  72. data/app/pb_kits/playbook/pb_date_time/date_time.html.erb +1 -6
  73. data/app/pb_kits/playbook/pb_date_time_stacked/date_time_stacked.html.erb +1 -7
  74. data/app/pb_kits/playbook/pb_date_year_stacked/date_year_stacked.html.erb +1 -5
  75. data/app/pb_kits/playbook/pb_detail/detail.html.erb +1 -6
  76. data/app/pb_kits/playbook/pb_dialog/_dialog.scss +4 -2
  77. data/app/pb_kits/playbook/pb_dialog/dialog.html.erb +1 -6
  78. data/app/pb_kits/playbook/pb_dialog/dialog_body.html.erb +2 -7
  79. data/app/pb_kits/playbook/pb_dialog/dialog_footer.html.erb +1 -5
  80. data/app/pb_kits/playbook/pb_dialog/dialog_header.html.erb +2 -6
  81. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +100 -34
  82. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +93 -26
  83. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.jsx +4 -22
  84. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.md +1 -0
  85. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subcomponent_structure.jsx +42 -0
  86. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_subcomponent_structure.md +7 -0
  87. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete.jsx +84 -0
  88. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete.md +1 -0
  89. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete_and_custom_display.jsx +101 -0
  90. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete_and_custom_display.md +1 -0
  91. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.jsx +5 -3
  92. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.md +5 -0
  93. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_options.jsx +6 -9
  94. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_options.md +1 -0
  95. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_padding.jsx +48 -0
  96. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_padding.md +1 -0
  97. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_trigger.jsx +5 -5
  98. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_trigger.md +1 -0
  99. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_external_control.jsx +59 -0
  100. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_hook.jsx +72 -0
  101. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.jsx +39 -0
  102. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.md +1 -0
  103. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +7 -0
  104. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +7 -0
  105. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +200 -10
  106. data/app/pb_kits/playbook/pb_dropdown/hooks/useDropdown.tsx +2 -2
  107. data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +14 -9
  108. data/app/pb_kits/playbook/pb_dropdown/scss_partials/_dropdown_animation.scss +18 -0
  109. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +22 -8
  110. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +56 -29
  111. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +130 -68
  112. data/app/pb_kits/playbook/pb_dropdown/utilities/clickOutsideHelper.tsx +41 -0
  113. data/app/pb_kits/playbook/pb_dropdown/utilities/index.ts +2 -0
  114. data/app/pb_kits/playbook/pb_dropdown/utilities/subComponentHelper.tsx +9 -7
  115. data/app/pb_kits/playbook/pb_file_upload/file_upload.html.erb +1 -6
  116. data/app/pb_kits/playbook/pb_filter/filter.html.erb +1 -5
  117. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.html.erb +1 -6
  118. data/app/pb_kits/playbook/pb_flex/flex.html.erb +1 -5
  119. data/app/pb_kits/playbook/pb_flex/flex_item.html.erb +2 -6
  120. data/app/pb_kits/playbook/pb_form_group/form_group.html.erb +1 -6
  121. data/app/pb_kits/playbook/pb_form_pill/form_pill.html.erb +1 -1
  122. data/app/pb_kits/playbook/pb_hashtag/hashtag.html.erb +1 -6
  123. data/app/pb_kits/playbook/pb_highlight/highlight.html.erb +1 -5
  124. data/app/pb_kits/playbook/pb_home_address_street/home_address_street.html.erb +1 -5
  125. data/app/pb_kits/playbook/pb_icon_circle/icon_circle.html.erb +2 -7
  126. data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.html.erb +1 -6
  127. data/app/pb_kits/playbook/pb_icon_value/icon_value.html.erb +1 -6
  128. data/app/pb_kits/playbook/pb_label_pill/label_pill.html.erb +1 -6
  129. data/app/pb_kits/playbook/pb_label_value/label_value.html.erb +1 -6
  130. data/app/pb_kits/playbook/pb_layout/body.html.erb +1 -5
  131. data/app/pb_kits/playbook/pb_layout/footer.html.erb +1 -5
  132. data/app/pb_kits/playbook/pb_layout/header.html.erb +1 -5
  133. data/app/pb_kits/playbook/pb_layout/item.html.erb +1 -5
  134. data/app/pb_kits/playbook/pb_layout/layout.html.erb +1 -5
  135. data/app/pb_kits/playbook/pb_layout/sidebar.html.erb +1 -5
  136. data/app/pb_kits/playbook/pb_list/item.html.erb +2 -8
  137. data/app/pb_kits/playbook/pb_list/list.html.erb +2 -8
  138. data/app/pb_kits/playbook/pb_loading_inline/_loading_inline.tsx +3 -1
  139. data/app/pb_kits/playbook/pb_loading_inline/docs/_loading_inline_custom.html.erb +13 -0
  140. data/app/pb_kits/playbook/pb_loading_inline/docs/_loading_inline_custom.jsx +26 -0
  141. data/app/pb_kits/playbook/pb_loading_inline/docs/{_loading_inline_light.html.erb β†’ _loading_inline_default.html.erb} +2 -2
  142. data/app/pb_kits/playbook/pb_loading_inline/docs/{_loading_inline_light.jsx β†’ _loading_inline_default.jsx} +2 -2
  143. data/app/pb_kits/playbook/pb_loading_inline/docs/example.yml +4 -2
  144. data/app/pb_kits/playbook/pb_loading_inline/docs/index.js +2 -1
  145. data/app/pb_kits/playbook/pb_loading_inline/loading_inline.html.erb +2 -7
  146. data/app/pb_kits/playbook/pb_loading_inline/loading_inline.rb +1 -0
  147. data/app/pb_kits/playbook/pb_loading_inline/loading_inline.test.js +14 -0
  148. data/app/pb_kits/playbook/pb_message/message.html.erb +1 -6
  149. data/app/pb_kits/playbook/pb_message/message_mention.html.erb +1 -6
  150. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.html.erb +1 -6
  151. data/app/pb_kits/playbook/pb_multiple_users/multiple_users.html.erb +1 -6
  152. data/app/pb_kits/playbook/pb_multiple_users_stacked/multiple_users_stacked.html.erb +1 -6
  153. data/app/pb_kits/playbook/pb_nav/item.html.erb +3 -14
  154. data/app/pb_kits/playbook/pb_nav/nav.html.erb +1 -6
  155. data/app/pb_kits/playbook/pb_online_status/online_status.html.erb +2 -6
  156. data/app/pb_kits/playbook/pb_pagination/pagination.html.erb +1 -6
  157. data/app/pb_kits/playbook/pb_passphrase/passphrase.html.erb +1 -1
  158. data/app/pb_kits/playbook/pb_person/person.html.erb +7 -12
  159. data/app/pb_kits/playbook/pb_person_contact/person_contact.html.erb +1 -6
  160. data/app/pb_kits/playbook/pb_pill/pill.html.erb +1 -6
  161. data/app/pb_kits/playbook/pb_popover/popover.html.erb +1 -6
  162. data/app/pb_kits/playbook/pb_progress_pills/progress_pills.html.erb +2 -6
  163. data/app/pb_kits/playbook/pb_progress_simple/docs/_progress_simple_flex.html.erb +3 -0
  164. data/app/pb_kits/playbook/pb_progress_simple/docs/_progress_simple_flex.jsx +16 -0
  165. data/app/pb_kits/playbook/pb_progress_simple/docs/_progress_simple_flex.md +1 -0
  166. data/app/pb_kits/playbook/pb_progress_simple/docs/example.yml +2 -0
  167. data/app/pb_kits/playbook/pb_progress_simple/docs/index.js +1 -0
  168. data/app/pb_kits/playbook/pb_progress_simple/progress_simple.html.erb +3 -6
  169. data/app/pb_kits/playbook/pb_progress_simple/progress_simple.rb +1 -1
  170. data/app/pb_kits/playbook/pb_progress_step/progress_step.html.erb +1 -5
  171. data/app/pb_kits/playbook/pb_progress_step/progress_step_item.html.erb +1 -5
  172. data/app/pb_kits/playbook/pb_radio/_radio.scss +35 -0
  173. data/app/pb_kits/playbook/pb_radio/_radio.tsx +3 -0
  174. data/app/pb_kits/playbook/pb_radio/docs/_radio_alignment.jsx +4 -1
  175. data/app/pb_kits/playbook/pb_radio/docs/_radio_default.jsx +4 -1
  176. data/app/pb_kits/playbook/pb_radio/docs/_radio_disabled.html.erb +26 -0
  177. data/app/pb_kits/playbook/pb_radio/docs/_radio_disabled.jsx +31 -0
  178. data/app/pb_kits/playbook/pb_radio/docs/_radio_error.jsx +2 -1
  179. data/app/pb_kits/playbook/pb_radio/docs/example.yml +2 -0
  180. data/app/pb_kits/playbook/pb_radio/docs/index.js +1 -0
  181. data/app/pb_kits/playbook/pb_radio/radio.html.erb +2 -8
  182. data/app/pb_kits/playbook/pb_radio/radio.rb +5 -0
  183. data/app/pb_kits/playbook/pb_radio/radio.test.js +17 -0
  184. data/app/pb_kits/playbook/pb_section_separator/_section_separator.scss +6 -2
  185. data/app/pb_kits/playbook/pb_section_separator/_section_separator_mixin.scss +11 -1
  186. data/app/pb_kits/playbook/pb_section_separator/section_separator.html.erb +1 -6
  187. data/app/pb_kits/playbook/pb_select/select.html.erb +1 -5
  188. data/app/pb_kits/playbook/pb_selectable_card/selectable_card.html.erb +1 -5
  189. data/app/pb_kits/playbook/pb_selectable_card_icon/selectable_card_icon.html.erb +1 -4
  190. data/app/pb_kits/playbook/pb_selectable_icon/selectable_icon.html.erb +1 -5
  191. data/app/pb_kits/playbook/pb_selectable_list/selectable_list.html.erb +1 -6
  192. data/app/pb_kits/playbook/pb_selectable_list/selectable_list_item.html.erb +1 -6
  193. data/app/pb_kits/playbook/pb_source/source.html.erb +1 -5
  194. data/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb +1 -5
  195. data/app/pb_kits/playbook/pb_stat_change/stat_change.html.erb +1 -5
  196. data/app/pb_kits/playbook/pb_stat_value/stat_value.html.erb +1 -5
  197. data/app/pb_kits/playbook/pb_table/table.html.erb +2 -12
  198. data/app/pb_kits/playbook/pb_table/table_body.html.erb +6 -16
  199. data/app/pb_kits/playbook/pb_table/table_cell.html.erb +6 -16
  200. data/app/pb_kits/playbook/pb_table/table_head.html.erb +6 -16
  201. data/app/pb_kits/playbook/pb_table/table_header.html.erb +4 -13
  202. data/app/pb_kits/playbook/pb_table/table_row.html.erb +6 -16
  203. data/app/pb_kits/playbook/pb_textarea/textarea.html.erb +1 -5
  204. data/app/pb_kits/playbook/pb_time/time.html.erb +1 -5
  205. data/app/pb_kits/playbook/pb_time_range_inline/time_range_inline.html.erb +1 -5
  206. data/app/pb_kits/playbook/pb_time_stacked/time_stacked.html.erb +1 -5
  207. data/app/pb_kits/playbook/pb_timeline/item.html.erb +3 -7
  208. data/app/pb_kits/playbook/pb_timeline/timeline.html.erb +1 -5
  209. data/app/pb_kits/playbook/pb_timestamp/timestamp.html.erb +1 -6
  210. data/app/pb_kits/playbook/pb_title/title.html.erb +1 -6
  211. data/app/pb_kits/playbook/pb_title_count/title_count.html.erb +1 -6
  212. data/app/pb_kits/playbook/pb_title_detail/title_detail.html.erb +1 -5
  213. data/app/pb_kits/playbook/pb_toggle/toggle.html.erb +1 -6
  214. data/app/pb_kits/playbook/pb_tooltip/tooltip.html.erb +1 -5
  215. data/app/pb_kits/playbook/pb_user/user.html.erb +1 -6
  216. data/app/pb_kits/playbook/pb_user_badge/user_badge.html.erb +1 -6
  217. data/app/pb_kits/playbook/pb_weekday_stacked/weekday_stacked.html.erb +1 -6
  218. data/app/pb_kits/playbook/playbook-rails.js +3 -0
  219. data/dist/menu.yml +1 -1
  220. data/dist/playbook-rails.js +6 -6
  221. data/lib/playbook/kit_base.rb +1 -1
  222. data/lib/playbook/version.rb +2 -2
  223. metadata +48 -8
  224. data/app/pb_kits/playbook/pb_advanced_table/docs/_description.md +0 -1
@@ -1,31 +1,38 @@
1
- import React, { useState, useRef, useEffect, ReactElement } from "react";
1
+ import React, { useState, useRef, useEffect } from "react";
2
2
  import classnames from "classnames";
3
- import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
3
+ import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
4
4
  import { globalProps } from "../utilities/globalProps";
5
+ import { GenericObject } from "../types";
5
6
 
6
7
  import Body from "../pb_body/_body";
8
+ import Caption from "../pb_caption/_caption";
7
9
 
8
10
  import DropdownContainer from "./subcomponents/DropdownContainer";
11
+ import DropdownContext from "./context";
9
12
  import DropdownOption from "./subcomponents/DropdownOption";
10
13
  import DropdownTrigger from "./subcomponents/DropdownTrigger";
11
- import DropdownContext from "./context";
12
14
  import useDropdown from "./hooks/useDropdown";
13
15
 
14
16
  import {
15
17
  separateChildComponents,
16
18
  prepareSubcomponents,
17
- } from "./utilities/subComponentHelper";
18
- import { GenericObject } from "../types";
19
+ handleClickOutside,
20
+ } from "./utilities";
19
21
 
20
22
  type DropdownProps = {
21
23
  aria?: { [key: string]: string };
22
24
  autocomplete?: boolean;
25
+ children?: React.ReactChild[] | React.ReactChild | React.ReactElement[];
23
26
  className?: string;
27
+ dark?: boolean;
24
28
  data?: { [key: string]: string };
29
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
25
30
  id?: string;
26
- children?: React.ReactChild[] | React.ReactChild | ReactElement[];
27
- options: GenericObject;
31
+ isClosed?: boolean;
32
+ label?: string;
28
33
  onSelect?: (arg: GenericObject) => null;
34
+ options: GenericObject;
35
+ triggerRef?: any;
29
36
  };
30
37
 
31
38
  const Dropdown = (props: DropdownProps) => {
@@ -34,49 +41,66 @@ const Dropdown = (props: DropdownProps) => {
34
41
  autocomplete = false,
35
42
  children,
36
43
  className,
44
+ dark = false,
37
45
  data = {},
46
+ htmlOptions = {},
38
47
  id,
39
- options,
48
+ isClosed = true,
49
+ label,
40
50
  onSelect,
51
+ options,
52
+ triggerRef
41
53
  } = props;
42
54
 
43
55
  const ariaProps = buildAriaProps(aria);
44
56
  const dataProps = buildDataProps(data);
57
+ const htmlProps = buildHtmlProps(htmlOptions);
45
58
  const classes = classnames(
46
59
  buildCss("pb_dropdown"),
47
60
  globalProps(props),
48
61
  className
49
62
  );
50
63
 
51
- const [isDropDownClosed, setIsDropDownClosed, toggleDropdown] = useDropdown();
64
+ const [isDropDownClosed, setIsDropDownClosed, toggleDropdown] = useDropdown(isClosed);
52
65
 
53
66
  const [filterItem, setFilterItem] = useState("");
54
- const [selected, setSelected] = useState({});
67
+ const [selected, setSelected] = useState<GenericObject>({});
55
68
  const [isInputFocused, setIsInputFocused] = useState(false);
56
69
  const [hasTriggerSubcomponent, setHasTriggerSubcomponent] = useState(true);
57
70
  const [hasContainerSubcomponent, setHasContainerSubcomponent] =
58
71
  useState(true);
59
-
60
72
  //state for keyboard events
61
73
  const [focusedOptionIndex, setFocusedOptionIndex] = useState(-1);
62
74
 
63
75
  const dropdownRef = useRef(null);
64
76
  const inputRef = useRef(null);
77
+ const inputWrapperRef = useRef(null);
78
+ const dropdownContainerRef = useRef(null);
65
79
 
66
80
  const { trigger, container, otherChildren } =
67
81
  separateChildComponents(children);
68
82
 
69
- // useEffect to handle clicks outside the dropdown
70
83
  useEffect(() => {
71
- const handleClickOutside = (e: MouseEvent) => {
72
- if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
73
- setIsDropDownClosed(true);
74
- setIsInputFocused(false);
84
+ // Set the parent element of the trigger to relative to allow for absolute positioning of the dropdown
85
+ //Only needed for when useDropdown hook used with external trigger
86
+ if (triggerRef?.current) {
87
+ const parentElement = triggerRef.current.parentNode;
88
+ if (parentElement) {
89
+ parentElement.style.position = 'relative';
75
90
  }
76
- };
77
- window.addEventListener("click", handleClickOutside);
91
+ }
92
+ // Handle clicks outside the dropdown
93
+ const handleClick = handleClickOutside({
94
+ inputWrapperRef,
95
+ dropdownContainerRef,
96
+ setIsDropDownClosed,
97
+ setFocusedOptionIndex,
98
+ setIsInputFocused,
99
+ });
100
+
101
+ window.addEventListener("click", handleClick);
78
102
  return () => {
79
- window.removeEventListener("click", handleClickOutside);
103
+ window.removeEventListener("click", handleClick);
80
104
  };
81
105
  }, []);
82
106
 
@@ -85,6 +109,30 @@ const Dropdown = (props: DropdownProps) => {
85
109
  setHasContainerSubcomponent(!!container);
86
110
  }, []);
87
111
 
112
+ // dropdown to toggle with external control
113
+ useEffect(()=> {
114
+ setIsDropDownClosed(isClosed)
115
+ },[isClosed])
116
+
117
+ const filteredOptions = options?.filter((option: GenericObject) =>
118
+ option.label.toLowerCase().includes(filterItem.toLowerCase())
119
+ );
120
+
121
+ // For keyboard accessibility: Set focus within dropdown to selected item if it exists
122
+ useEffect(() => {
123
+ if (!isDropDownClosed) {
124
+ let newIndex = 0;
125
+ if (selected && selected?.label) {
126
+ const selectedIndex = filteredOptions.findIndex((option: GenericObject) => option.label === selected.label);
127
+ if (selectedIndex >= 0) {
128
+ newIndex = selectedIndex;
129
+ }
130
+ }
131
+ setFocusedOptionIndex(newIndex);
132
+ }
133
+ }, [isDropDownClosed]);
134
+
135
+
88
136
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
89
137
  setFilterItem(e.target.value);
90
138
  setIsDropDownClosed(false);
@@ -94,7 +142,7 @@ const Dropdown = (props: DropdownProps) => {
94
142
  setSelected(selectedItem);
95
143
  setFilterItem("");
96
144
  setIsDropDownClosed(true);
97
- onSelect(selectedItem);
145
+ onSelect && onSelect(selectedItem);
98
146
  };
99
147
 
100
148
  const handleWrapperClick = () => {
@@ -104,14 +152,10 @@ const Dropdown = (props: DropdownProps) => {
104
152
 
105
153
  const handleBackspace = () => {
106
154
  setSelected({});
107
- onSelect(null);
155
+ onSelect && onSelect(null);
108
156
  setFocusedOptionIndex(-1);
109
157
  };
110
158
 
111
- const filteredOptions = options?.filter((option: GenericObject) =>
112
- option.label.toLowerCase().includes(filterItem.toLowerCase())
113
- );
114
-
115
159
  const componentsToRender = prepareSubcomponents({
116
160
  children,
117
161
  hasTriggerSubcomponent,
@@ -119,17 +163,22 @@ const Dropdown = (props: DropdownProps) => {
119
163
  trigger,
120
164
  container,
121
165
  otherChildren,
166
+ dark
122
167
  });
123
168
 
169
+
124
170
  return (
125
171
  <div {...ariaProps}
126
172
  {...dataProps}
173
+ {...htmlProps}
127
174
  className={classes}
128
175
  id={id}
176
+ style={triggerRef ? { position: "absolute"} : { position: "relative"}}
129
177
  >
130
178
  <DropdownContext.Provider
131
179
  value={{
132
180
  autocomplete,
181
+ dropdownContainerRef,
133
182
  filteredOptions,
134
183
  filterItem,
135
184
  focusedOptionIndex,
@@ -138,6 +187,7 @@ const Dropdown = (props: DropdownProps) => {
138
187
  handleOptionClick,
139
188
  handleWrapperClick,
140
189
  inputRef,
190
+ inputWrapperRef,
141
191
  isDropDownClosed,
142
192
  isInputFocused,
143
193
  options,
@@ -147,9 +197,26 @@ const Dropdown = (props: DropdownProps) => {
147
197
  setIsInputFocused,
148
198
  setSelected,
149
199
  toggleDropdown,
200
+ triggerRef
150
201
  }}
151
202
  >
203
+ {label &&
204
+ <Caption
205
+ dark={dark}
206
+ marginBottom="xs"
207
+ text={label}
208
+ />
209
+ }
152
210
  <div className="dropdown_wrapper"
211
+ onBlur={() => {
212
+ // Debounce to delay the execution to prevent jumpiness in Focus state
213
+ setTimeout(() => {
214
+ if (!dropdownRef.current.contains(document.activeElement)) {
215
+ setIsInputFocused(false);
216
+ }
217
+ }, 0);
218
+ }}
219
+ onFocus={() => setIsInputFocused(true)}
153
220
  ref={dropdownRef}
154
221
  >
155
222
  {children ? (
@@ -176,7 +243,7 @@ const Dropdown = (props: DropdownProps) => {
176
243
  </div>
177
244
  </DropdownContext.Provider>
178
245
  </div>
179
- );
246
+ )
180
247
  };
181
248
 
182
249
  Dropdown.Option = DropdownOption;
@@ -1,31 +1,20 @@
1
- import React, { useState } from 'react'
1
+ import React from 'react'
2
2
  import { Dropdown } from '../../'
3
3
 
4
4
  const DropdownDefault = (props) => {
5
- // eslint-disable-next-line no-unused-vars
6
- const [selectedOption, setSelectedOption] = useState();
7
5
 
8
6
  const options = [
9
7
  {
10
8
  label: "United States",
11
9
  value: "United States",
12
- areaCode: "+1",
13
- icon: "πŸ‡ΊπŸ‡Έ",
14
- id: "United-states"
15
10
  },
16
11
  {
17
- label: "Ukraine",
18
- value: "Ukraine",
19
- areaCode: "+380",
20
- icon: "πŸ‡ΊπŸ‡¦",
21
- id: "ukraine"
12
+ label: "Canada",
13
+ value: "Canada",
22
14
  },
23
15
  {
24
16
  label: "Pakistan",
25
17
  value: "Pakistan",
26
- areaCode: "+92",
27
- icon: "πŸ‡΅πŸ‡°",
28
- id: "pakistan"
29
18
  }
30
19
  ];
31
20
 
@@ -33,16 +22,9 @@ const [selectedOption, setSelectedOption] = useState();
33
22
  return (
34
23
  <div>
35
24
  <Dropdown
36
- onSelect={(selectedItem) => setSelectedOption(selectedItem)}
37
25
  options={options}
38
26
  {...props}
39
- >
40
- {options.map((option) => (
41
- <Dropdown.Option key={option.id}
42
- option={option}
43
- />
44
- ))}
45
- </Dropdown>
27
+ />
46
28
  </div>
47
29
  )
48
30
  }
@@ -0,0 +1 @@
1
+ The Dropdown kit accepts an `options` array and renders each object from that array as a selectable option within a dropdown container. `options` is a required prop and must be an array of objects. Each object can contain as many key/value pairs as needed but MUST contain 'label' and 'value' as the only required items within each object.
@@ -0,0 +1,42 @@
1
+ import React from 'react'
2
+ import { Dropdown } from '../..'
3
+
4
+ const DropdownSubcomponentStructure = (props) => {
5
+
6
+
7
+ const options = [
8
+ {
9
+ label: "United States",
10
+ value: "United States",
11
+ },
12
+ {
13
+ label: "Canada",
14
+ value: "Canada",
15
+ },
16
+ {
17
+ label: "Pakistan",
18
+ value: "Pakistan",
19
+ }
20
+ ];
21
+
22
+
23
+ return (
24
+ <div>
25
+ <Dropdown
26
+ options={options}
27
+ {...props}
28
+ >
29
+ <Dropdown.Trigger/>
30
+ <Dropdown.Container>
31
+ {options.map((option) => (
32
+ <Dropdown.Option key={option.id}
33
+ option={option}
34
+ />
35
+ ))}
36
+ </Dropdown.Container>
37
+ </Dropdown>
38
+ </div>
39
+ )
40
+ }
41
+
42
+ export default DropdownSubcomponentStructure
@@ -0,0 +1,7 @@
1
+ The dropdown comes with the following subcomponents that can be used to achieve various levels of customization:
2
+
3
+ `Dropdown. Trigger`
4
+ `Dropdown.Container`
5
+ `Dropdown.Option`
6
+
7
+ See the code snippet below for a visual on how to use the kit with subcomponents. Each subcomponent allows for GlobalProps in addition to any subcomponent specfic props.
@@ -0,0 +1,84 @@
1
+ import React from 'react'
2
+ import { Dropdown, User, Badge, FlexItem } from '../..'
3
+
4
+ const DropdownWithAutocomplete = (props) => {
5
+
6
+ const options = [
7
+ {
8
+ label: "Jasper Furniss",
9
+ value: "Jasper Furniss",
10
+ territory: "PHL",
11
+ title: "Senior UX Engineer",
12
+ id: "jasper-furniss",
13
+ status: "Offline"
14
+ },
15
+ {
16
+ label: "Ramon Ruiz",
17
+ value: "Ramon Ruiz",
18
+ territory: "PHL",
19
+ title: "Senior UX Desinger",
20
+ id: "ramon-ruiz",
21
+ status: "Away"
22
+ },
23
+ {
24
+ label: "Jason Cypret",
25
+ value: "Jason Cypret",
26
+ territory: "PHL",
27
+ title: "VP of User Experience",
28
+ id: "jason-cypret",
29
+ status: "Online"
30
+ },
31
+ {
32
+ label: "Courtney Long",
33
+ value: "Courtney Long",
34
+ territory: "PHL",
35
+ title: "UX Design Mentor",
36
+ id: "courtney-long",
37
+ status: "Online"
38
+ }
39
+ ];
40
+
41
+
42
+ return (
43
+ <div>
44
+ <Dropdown autocomplete
45
+ options={options}
46
+ {...props}
47
+ >
48
+ {options.map((option) => (
49
+ <Dropdown.Option key={option.id}
50
+ option={option}
51
+ >
52
+ <>
53
+ <FlexItem>
54
+ <User
55
+ align="left"
56
+ avatar
57
+ name={option.label}
58
+ orientation="horizontal"
59
+ territory={option.territory}
60
+ title={option.title}
61
+ />
62
+ </FlexItem>
63
+ <FlexItem>
64
+ <Badge
65
+ rounded
66
+ text={option.status}
67
+ variant={`${
68
+ option.status === "Offline"
69
+ ? "neutral"
70
+ : option.status === "Online"
71
+ ? "success"
72
+ : "warning"
73
+ }`}
74
+ />
75
+ </FlexItem>
76
+ </>
77
+ </Dropdown.Option>
78
+ ))}
79
+ </Dropdown>
80
+ </div>
81
+ )
82
+ }
83
+
84
+ export default DropdownWithAutocomplete
@@ -0,0 +1 @@
1
+ The `autocomplete` prop can be used to add autocomplete or typeahead functionality to the Dropdown's default Trigger. This prop is set to 'false' by default.
@@ -0,0 +1,101 @@
1
+ import React, { useState } from 'react'
2
+ import { Dropdown, User, Badge, FlexItem, Avatar } from '../..'
3
+
4
+ const DropdownWithAutocompleteAndCustomDisplay = (props) => {
5
+ const [selectedOption, setSelectedOption] = useState();
6
+
7
+ const options = [
8
+ {
9
+ label: "Jasper Furniss",
10
+ value: "Jasper Furniss",
11
+ territory: "PHL",
12
+ title: "Senior UX Engineer",
13
+ id: "jasper-furniss",
14
+ status: "Offline"
15
+ },
16
+ {
17
+ label: "Ramon Ruiz",
18
+ value: "Ramon Ruiz",
19
+ territory: "PHL",
20
+ title: "Senior UX Desinger",
21
+ id: "ramon-ruiz",
22
+ status: "Away"
23
+ },
24
+ {
25
+ label: "Jason Cypret",
26
+ value: "Jason Cypret",
27
+ territory: "PHL",
28
+ title: "VP of User Experience",
29
+ id: "jason-cypret",
30
+ status: "Online"
31
+ },
32
+ {
33
+ label: "Courtney Long",
34
+ value: "Courtney Long",
35
+ territory: "PHL",
36
+ title: "UX Design Mentor",
37
+ id: "courtney-long",
38
+ status: "Online"
39
+ }
40
+ ];
41
+
42
+ const CustomDisplay = () => {
43
+ return (
44
+ <>
45
+ {
46
+ selectedOption && (
47
+ <Avatar
48
+ name={selectedOption.label}
49
+ size="xs"
50
+ />
51
+ )
52
+ }
53
+ </>
54
+ )
55
+ };
56
+
57
+ return (
58
+ <div>
59
+ <Dropdown autocomplete
60
+ onSelect={(selectedItem) => setSelectedOption(selectedItem)}
61
+ options={options}
62
+ {...props}
63
+ >
64
+ <Dropdown.Trigger customDisplay={<CustomDisplay/>} />
65
+ {options.map((option) => (
66
+ <Dropdown.Option key={option.id}
67
+ option={option}
68
+ >
69
+ <>
70
+ <FlexItem>
71
+ <User
72
+ align="left"
73
+ avatar
74
+ name={option.label}
75
+ orientation="horizontal"
76
+ territory={option.territory}
77
+ title={option.title}
78
+ />
79
+ </FlexItem>
80
+ <FlexItem>
81
+ <Badge
82
+ rounded
83
+ text={option.status}
84
+ variant={`${
85
+ option.status === "Offline"
86
+ ? "neutral"
87
+ : option.status === "Online"
88
+ ? "success"
89
+ : "warning"
90
+ }`}
91
+ />
92
+ </FlexItem>
93
+ </>
94
+ </Dropdown.Option>
95
+ ))}
96
+ </Dropdown>
97
+ </div>
98
+ )
99
+ }
100
+
101
+ export default DropdownWithAutocompleteAndCustomDisplay
@@ -0,0 +1 @@
1
+ `autocomplete` prop can also be used in conjunction with the `customDisplay` prop.
@@ -39,7 +39,7 @@ const DropdownWithCustomDisplay = (props) => {
39
39
  }
40
40
  ];
41
41
 
42
- const customDisplay = () => {
42
+ const CustomDisplay = () => {
43
43
  return (
44
44
  <>
45
45
  {
@@ -62,7 +62,9 @@ const DropdownWithCustomDisplay = (props) => {
62
62
  options={options}
63
63
  {...props}
64
64
  >
65
- <Dropdown.Trigger customDisplay={customDisplay()}/>
65
+ <Dropdown.Trigger customDisplay={<CustomDisplay/>}
66
+ placeholder="Select a User"
67
+ />
66
68
  {options.map((option) => (
67
69
  <Dropdown.Option key={option.id}
68
70
  option={option}
@@ -79,7 +81,7 @@ const DropdownWithCustomDisplay = (props) => {
79
81
  />
80
82
  </FlexItem>
81
83
  <FlexItem>
82
- <Badge
84
+ <Badge dark
83
85
  rounded
84
86
  text={option.status}
85
87
  variant={`${
@@ -0,0 +1,5 @@
1
+ The `customDisplay` prop can be used to customize the display of the selected item by allowing devs to pass in a component that will be rendered to the left of the default text-based display. In this example the Avatar kit is being used.
2
+
3
+ The `placeholder` prop can also be used to customize the placeholder text for the default Trigger.
4
+
5
+ The `onSelect` prop is a function that gives the dev one argument: the selected option. In this example we are using the `onSelect` to set a state with the selected option and using it to customize the `customDisplay`.
@@ -1,9 +1,7 @@
1
- import React, { useState } from 'react'
1
+ import React from 'react'
2
2
  import { Dropdown, Icon, Body, FlexItem, Flex } from '../..'
3
3
 
4
4
  const DropdownWithCustomOptions = (props) => {
5
- // eslint-disable-next-line no-unused-vars
6
- const [selectedOption, setSelectedOption] = useState();
7
5
 
8
6
  const options = [
9
7
  {
@@ -14,11 +12,11 @@ const DropdownWithCustomOptions = (props) => {
14
12
  id: "United-states"
15
13
  },
16
14
  {
17
- label: "Ukraine",
18
- value: "Ukraine",
19
- areaCode: "+380",
20
- icon: "πŸ‡ΊπŸ‡¦",
21
- id: "ukraine"
15
+ label: "Canada",
16
+ value: "Canada",
17
+ areaCode: "+1",
18
+ icon: "πŸ‡¨πŸ‡¦",
19
+ id: "canada"
22
20
  },
23
21
  {
24
22
  label: "Pakistan",
@@ -33,7 +31,6 @@ const DropdownWithCustomOptions = (props) => {
33
31
  return (
34
32
  <div>
35
33
  <Dropdown
36
- onSelect={(selectedItem) => setSelectedOption(selectedItem)}
37
34
  options={options}
38
35
  {...props}
39
36
  >
@@ -0,0 +1 @@
1
+ The Dropdown also allows for custom options that can be passed in as children to the `Dropdown.Option` subcomponent. If no children are passed to `Dropdown.Option`, the kit will render each option as text within a Body kit by default.
@@ -0,0 +1,48 @@
1
+ import React from 'react'
2
+ import { Dropdown } from '../..'
3
+
4
+ const DropdownWithCustomPadding = (props) => {
5
+
6
+ const options = [
7
+ {
8
+ label: "United States",
9
+ value: "United States",
10
+ areaCode: "+1",
11
+ icon: "πŸ‡ΊπŸ‡Έ",
12
+ id: "United-states"
13
+ },
14
+ {
15
+ label: "Canada",
16
+ value: "Canada",
17
+ areaCode: "+1",
18
+ icon: "πŸ‡¨πŸ‡¦",
19
+ id: "canada"
20
+ },
21
+ {
22
+ label: "Pakistan",
23
+ value: "Pakistan",
24
+ areaCode: "+92",
25
+ icon: "πŸ‡΅πŸ‡°",
26
+ id: "pakistan"
27
+ }
28
+ ];
29
+
30
+
31
+ return (
32
+ <div>
33
+ <Dropdown
34
+ options={options}
35
+ {...props}
36
+ >
37
+ {options.map((option) => (
38
+ <Dropdown.Option key={option.id}
39
+ option={option}
40
+ padding="sm"
41
+ />
42
+ ))}
43
+ </Dropdown>
44
+ </div>
45
+ )
46
+ }
47
+
48
+ export default DropdownWithCustomPadding
@@ -0,0 +1 @@
1
+ By default, the padding on each option in the dropdown is set to `xs`. The `padding` Global Props however can be used to override this default. In this example, we are setting padding to `sm`.
@@ -14,11 +14,11 @@ const [selectedOption, setSelectedOption] = useState();
14
14
  id: "United-states"
15
15
  },
16
16
  {
17
- label: "Ukraine",
18
- value: "Ukraine",
19
- areaCode: "+380",
20
- icon: "πŸ‡ΊπŸ‡¦",
21
- id: "ukraine"
17
+ label: "Canada",
18
+ value: "Canada",
19
+ areaCode: "+1",
20
+ icon: "πŸ‡¨πŸ‡¦",
21
+ id: "canada"
22
22
  },
23
23
  {
24
24
  label: "Pakistan",