playbook_ui 18.2.0 → 18.3.0.pre.alpha.PLAY3342advancedtablereactmulticolumnselectablerow21082

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 (466) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/CollapsibleTrail.tsx +8 -1
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +39 -8
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +62 -2
  5. data/app/pb_kits/playbook/pb_advanced_table/Components/VirtualizedTableView.tsx +24 -4
  6. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +105 -66
  7. data/app/pb_kits/playbook/pb_advanced_table/Utilities/RowUtils.ts +29 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +83 -5
  9. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +3 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.html.erb +1 -1
  11. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +8 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +1100 -1
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.jsx +1 -1
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.md +5 -2
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.md +3 -1
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi_select_all.jsx +82 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi_select_all.md +3 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md +3 -1
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_group_separators.jsx +67 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_group_separators.md +7 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_group_separators_rails.html.erb +78 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_group_separators_rails.md +3 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows.jsx +177 -58
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_playground.json +17 -2
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/_playground.overrides.json +8 -1
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_mock_data_group_separators.json +328 -0
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +3 -0
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -0
  29. data/app/pb_kits/playbook/pb_advanced_table/index.js +39 -2
  30. data/app/pb_kits/playbook/pb_advanced_table/kit.schema.json +44 -16
  31. data/app/pb_kits/playbook/pb_advanced_table/table_body.html.erb +2 -2
  32. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +53 -23
  33. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +1 -1
  34. data/app/pb_kits/playbook/pb_advanced_table/table_row.html.erb +1 -1
  35. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +2 -0
  36. data/app/pb_kits/playbook/pb_avatar/_avatar.tsx +3 -1
  37. data/app/pb_kits/playbook/pb_avatar/kit.schema.json +23 -10
  38. data/app/pb_kits/playbook/pb_background/docs/_playground.json +1 -0
  39. data/app/pb_kits/playbook/pb_background/kit.schema.json +10 -3
  40. data/app/pb_kits/playbook/pb_badge/docs/_playground.json +2 -0
  41. data/app/pb_kits/playbook/pb_badge/kit.schema.json +27 -13
  42. data/app/pb_kits/playbook/pb_body/docs/_playground.json +3 -3
  43. data/app/pb_kits/playbook/pb_body/kit.schema.json +14 -5
  44. data/app/pb_kits/playbook/pb_button/_button.tsx +3 -1
  45. data/app/pb_kits/playbook/pb_button/button.rb +3 -0
  46. data/app/pb_kits/playbook/pb_button/button.test.js +154 -0
  47. data/app/pb_kits/playbook/pb_button/docs/_button_options_rails.md +5 -0
  48. data/app/pb_kits/playbook/pb_button/docs/_button_options_react.md +9 -0
  49. data/app/pb_kits/playbook/pb_button/docs/_playground.json +4 -2
  50. data/app/pb_kits/playbook/pb_button/docs/_playground.overrides.json +1 -1
  51. data/app/pb_kits/playbook/pb_button/docs/example.yml +1 -1
  52. data/app/pb_kits/playbook/pb_button/kit.schema.json +31 -27
  53. data/app/pb_kits/playbook/pb_caption/kit.schema.json +17 -7
  54. data/app/pb_kits/playbook/pb_card/docs/_playground.json +1 -0
  55. data/app/pb_kits/playbook/pb_card/kit.schema.json +2 -1
  56. data/app/pb_kits/playbook/pb_checkbox/docs/_playground.json +6 -1
  57. data/app/pb_kits/playbook/pb_checkbox/kit.schema.json +10 -5
  58. data/app/pb_kits/playbook/pb_collapsible/child_kits/CollapsibleMain.tsx +4 -4
  59. data/app/pb_kits/playbook/pb_collapsible/collapsible.test.js +81 -2
  60. data/app/pb_kits/playbook/pb_contact/_contact.tsx +4 -1
  61. data/app/pb_kits/playbook/pb_contact/docs/_playground.json +1 -0
  62. data/app/pb_kits/playbook/pb_contact/kit.schema.json +3 -1
  63. data/app/pb_kits/playbook/pb_copy_button/docs/_playground.json +5 -1
  64. data/app/pb_kits/playbook/pb_copy_button/kit.schema.json +10 -5
  65. data/app/pb_kits/playbook/pb_currency/docs/_playground.json +1 -1
  66. data/app/pb_kits/playbook/pb_currency/kit.schema.json +6 -2
  67. data/app/pb_kits/playbook/pb_dashboard_value/docs/_playground.json +2 -2
  68. data/app/pb_kits/playbook/pb_dashboard_value/kit.schema.json +4 -2
  69. data/app/pb_kits/playbook/pb_date/_date.tsx +3 -1
  70. data/app/pb_kits/playbook/pb_date/date.test.js +1 -1
  71. data/app/pb_kits/playbook/pb_date/docs/_playground.json +1 -0
  72. data/app/pb_kits/playbook/pb_date/kit.schema.json +17 -7
  73. data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +4 -0
  74. data/app/pb_kits/playbook/pb_date_picker/docs/_playground.json +4 -1
  75. data/app/pb_kits/playbook/pb_date_picker/kit.schema.json +32 -14
  76. data/app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.tsx +3 -1
  77. data/app/pb_kits/playbook/pb_date_range_inline/docs/_playground.json +1 -0
  78. data/app/pb_kits/playbook/pb_date_range_inline/kit.schema.json +3 -1
  79. data/app/pb_kits/playbook/pb_date_range_stacked/_date_range_stacked.tsx +3 -1
  80. data/app/pb_kits/playbook/pb_date_range_stacked/kit.schema.json +1 -0
  81. data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.tsx +4 -1
  82. data/app/pb_kits/playbook/pb_date_stacked/date_stacked.test.js +1 -0
  83. data/app/pb_kits/playbook/pb_date_stacked/kit.schema.json +1 -0
  84. data/app/pb_kits/playbook/pb_date_time/_date_time.tsx +3 -1
  85. data/app/pb_kits/playbook/pb_date_time/dateTime.test.js +1 -0
  86. data/app/pb_kits/playbook/pb_date_time/docs/_playground.json +2 -1
  87. data/app/pb_kits/playbook/pb_date_time/kit.schema.json +3 -1
  88. data/app/pb_kits/playbook/pb_date_time_stacked/_date_time_stacked.tsx +2 -1
  89. data/app/pb_kits/playbook/pb_date_time_stacked/docs/_playground.json +1 -0
  90. data/app/pb_kits/playbook/pb_date_time_stacked/kit.schema.json +3 -1
  91. data/app/pb_kits/playbook/pb_date_year_stacked/_date_year_stacked.tsx +3 -1
  92. data/app/pb_kits/playbook/pb_date_year_stacked/date_year_stacked.test.js +1 -0
  93. data/app/pb_kits/playbook/pb_date_year_stacked/kit.schema.json +1 -0
  94. data/app/pb_kits/playbook/pb_detail/docs/_playground.json +2 -1
  95. data/app/pb_kits/playbook/pb_detail/kit.schema.json +2 -1
  96. data/app/pb_kits/playbook/pb_dialog/docs/_playground.json +1 -1
  97. data/app/pb_kits/playbook/pb_dialog/kit.schema.json +22 -9
  98. data/app/pb_kits/playbook/pb_distribution_bar/docs/_playground.json +2 -2
  99. data/app/pb_kits/playbook/pb_distribution_bar/kit.schema.json +2 -1
  100. data/app/pb_kits/playbook/pb_draggable/utilities/touchDrag.ts +10 -0
  101. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +112 -0
  102. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +121 -15
  103. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills.html.erb +51 -0
  104. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills.jsx +62 -0
  105. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills_rails.md +9 -0
  106. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills_react.md +9 -0
  107. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_form.jsx +50 -0
  108. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_form_react.md +9 -0
  109. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_option_creation.html.erb +16 -0
  110. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_option_creation.jsx +27 -0
  111. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_option_creation_rails.md +9 -0
  112. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_option_creation_react.md +9 -0
  113. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.json +39 -3
  114. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json +13 -2
  115. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +5 -0
  116. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +4 -1
  117. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +2 -2
  118. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +24 -1
  119. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +235 -1
  120. data/app/pb_kits/playbook/pb_dropdown/dropdown_creation.test.jsx +414 -0
  121. data/app/pb_kits/playbook/pb_dropdown/dropdown_form.test.jsx +173 -0
  122. data/app/pb_kits/playbook/pb_dropdown/dropdown_index.test.js +545 -0
  123. data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +22 -5
  124. data/app/pb_kits/playbook/pb_dropdown/index.js +260 -37
  125. data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +3 -1
  126. data/app/pb_kits/playbook/pb_dropdown/kit.schema.json +59 -9
  127. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +43 -25
  128. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownFormFields.tsx +83 -0
  129. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +13 -5
  130. data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +336 -31
  131. data/app/pb_kits/playbook/pb_dropdown/utilities/optionCreation.ts +21 -0
  132. data/app/pb_kits/playbook/pb_dropdown/utilities/pillReorder.js +281 -0
  133. data/app/pb_kits/playbook/pb_dropdown/utilities/quickpickDateSync.test.ts +24 -0
  134. data/app/pb_kits/playbook/pb_dropdown/utilities/usePillDropIndicator.ts +144 -0
  135. data/app/pb_kits/playbook/pb_empty_state/docs/_playground.json +1 -1
  136. data/app/pb_kits/playbook/pb_empty_state/kit.schema.json +2 -1
  137. data/app/pb_kits/playbook/pb_file_upload/docs/_playground.json +3 -2
  138. data/app/pb_kits/playbook/pb_file_upload/kit.schema.json +8 -3
  139. data/app/pb_kits/playbook/pb_filter/Filter/SortMenu.tsx +8 -1
  140. data/app/pb_kits/playbook/pb_filter/docs/_filter_one_click.html.erb +38 -0
  141. data/app/pb_kits/playbook/pb_filter/docs/_filter_one_click.jsx +69 -0
  142. data/app/pb_kits/playbook/pb_filter/docs/_filter_one_click.md +1 -0
  143. data/app/pb_kits/playbook/pb_filter/docs/example.yml +2 -0
  144. data/app/pb_kits/playbook/pb_filter/docs/index.js +2 -1
  145. data/app/pb_kits/playbook/pb_filter/filter.html.erb +4 -4
  146. data/app/pb_kits/playbook/pb_filter/filter.rb +28 -0
  147. data/app/pb_kits/playbook/pb_filter/filter.test.js +41 -0
  148. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_playground.json +4 -4
  149. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.test.js +1 -2
  150. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/kit.schema.json +6 -3
  151. data/app/pb_kits/playbook/pb_flex/docs/_playground.json +3 -0
  152. data/app/pb_kits/playbook/pb_flex/kit.schema.json +27 -12
  153. data/app/pb_kits/playbook/pb_form/docs/_description_react.md +3 -0
  154. data/app/pb_kits/playbook/pb_form/docs/_form_default_values.jsx +898 -0
  155. data/app/pb_kits/playbook/pb_form/docs/_form_default_values_react.md +3 -0
  156. data/app/pb_kits/playbook/pb_form/docs/_form_defaults.jsx +879 -0
  157. data/app/pb_kits/playbook/pb_form/docs/_form_defaults_react.md +29 -0
  158. data/app/pb_kits/playbook/pb_form/docs/_form_loading.jsx +75 -0
  159. data/app/pb_kits/playbook/pb_form/docs/{_form_loading.md → _form_loading_rails.md} +1 -0
  160. data/app/pb_kits/playbook/pb_form/docs/_form_loading_react.md +1 -0
  161. data/app/pb_kits/playbook/pb_form/docs/_form_model_values.jsx +147 -0
  162. data/app/pb_kits/playbook/pb_form/docs/_form_model_values_react.md +16 -0
  163. data/app/pb_kits/playbook/pb_form/docs/_form_multi_column.jsx +164 -0
  164. data/app/pb_kits/playbook/pb_form/docs/_form_multi_column_react.md +3 -0
  165. data/app/pb_kits/playbook/pb_form/docs/_form_validation.jsx +1057 -0
  166. data/app/pb_kits/playbook/pb_form/docs/_form_validation_react.md +26 -0
  167. data/app/pb_kits/playbook/pb_form/docs/example.yml +7 -0
  168. data/app/pb_kits/playbook/pb_form/form.rb +1 -1
  169. data/app/pb_kits/playbook/pb_form/kit.schema.json +1 -6
  170. data/app/pb_kits/playbook/pb_form/pb_form_validation.js +1 -0
  171. data/app/pb_kits/playbook/pb_form_group/_form_group.scss +1 -4
  172. data/app/pb_kits/playbook/pb_form_pill/docs/_playground.json +3 -0
  173. data/app/pb_kits/playbook/pb_form_pill/kit.schema.json +6 -3
  174. data/app/pb_kits/playbook/pb_full_screen/_full_screen.scss +6 -0
  175. data/app/pb_kits/playbook/pb_full_screen/_full_screen.tsx +11 -2
  176. data/app/pb_kits/playbook/pb_full_screen/docs/_full_screen_advanced_table_sticky_header.jsx +73 -0
  177. data/app/pb_kits/playbook/pb_full_screen/docs/_full_screen_advanced_table_sticky_header.md +1 -0
  178. data/app/pb_kits/playbook/pb_full_screen/docs/_playground.json +3 -3
  179. data/app/pb_kits/playbook/pb_full_screen/docs/example.yml +1 -0
  180. data/app/pb_kits/playbook/pb_full_screen/docs/index.js +1 -0
  181. data/app/pb_kits/playbook/pb_full_screen/full_screen.test.jsx +4 -2
  182. data/app/pb_kits/playbook/pb_full_screen/kit.schema.json +8 -4
  183. data/app/pb_kits/playbook/pb_hashtag/docs/_playground.json +2 -2
  184. data/app/pb_kits/playbook/pb_hashtag/kit.schema.json +2 -1
  185. data/app/pb_kits/playbook/pb_highlight/kit.schema.json +2 -1
  186. data/app/pb_kits/playbook/pb_icon/_icon.tsx +6 -1
  187. data/app/pb_kits/playbook/pb_icon/docs/_playground.json +2 -2
  188. data/app/pb_kits/playbook/pb_icon/kit.schema.json +31 -13
  189. data/app/pb_kits/playbook/pb_icon_circle/_icon_circle.tsx +3 -1
  190. data/app/pb_kits/playbook/pb_icon_circle/docs/_playground.json +2 -2
  191. data/app/pb_kits/playbook/pb_icon_circle/kit.schema.json +3 -1
  192. data/app/pb_kits/playbook/pb_icon_stat_value/docs/_playground.json +3 -2
  193. data/app/pb_kits/playbook/pb_icon_stat_value/kit.schema.json +4 -2
  194. data/app/pb_kits/playbook/pb_image/_image.tsx +5 -3
  195. data/app/pb_kits/playbook/pb_image/docs/_playground.json +27 -27
  196. data/app/pb_kits/playbook/pb_image/kit.schema.json +57 -24
  197. data/app/pb_kits/playbook/pb_label_pill/_label_pill.tsx +3 -1
  198. data/app/pb_kits/playbook/pb_label_pill/kit.schema.json +1 -0
  199. data/app/pb_kits/playbook/pb_label_value/docs/_playground.json +2 -2
  200. data/app/pb_kits/playbook/pb_label_value/kit.schema.json +2 -1
  201. data/app/pb_kits/playbook/pb_layout/docs/_playground.json +2 -2
  202. data/app/pb_kits/playbook/pb_layout/kit.schema.json +43 -20
  203. data/app/pb_kits/playbook/pb_legend/_legend.tsx +3 -1
  204. data/app/pb_kits/playbook/pb_legend/docs/_playground.json +2 -2
  205. data/app/pb_kits/playbook/pb_legend/kit.schema.json +3 -1
  206. data/app/pb_kits/playbook/pb_lightbox/_lightbox.tsx +2 -2
  207. data/app/pb_kits/playbook/pb_lightbox/kit.schema.json +84 -0
  208. data/app/pb_kits/playbook/pb_link/docs/_playground.json +6 -3
  209. data/app/pb_kits/playbook/pb_link/kit.schema.json +14 -6
  210. data/app/pb_kits/playbook/pb_list/_list_item.tsx +6 -3
  211. data/app/pb_kits/playbook/pb_list/docs/_playground.json +2 -2
  212. data/app/pb_kits/playbook/pb_list/kit.schema.json +2 -1
  213. data/app/pb_kits/playbook/pb_loading_inline/docs/_playground.json +0 -1
  214. data/app/pb_kits/playbook/pb_loading_inline/kit.schema.json +4 -1
  215. data/app/pb_kits/playbook/pb_map/docs/_map_default.md +22 -3
  216. data/app/pb_kits/playbook/pb_map/kit.schema.json +4 -6
  217. data/app/pb_kits/playbook/pb_message/kit.schema.json +2 -1
  218. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +4 -1
  219. data/app/pb_kits/playbook/pb_multiple_users/docs/_playground.json +2 -1
  220. data/app/pb_kits/playbook/pb_multiple_users/kit.schema.json +19 -11
  221. data/app/pb_kits/playbook/pb_multiple_users_stacked/docs/_playground.json +1 -0
  222. data/app/pb_kits/playbook/pb_multiple_users_stacked/kit.schema.json +2 -1
  223. data/app/pb_kits/playbook/pb_nav/_nav_item.test.js +17 -0
  224. data/app/pb_kits/playbook/pb_nav/docs/_playground.json +2 -0
  225. data/app/pb_kits/playbook/pb_nav/kit.schema.json +4 -2
  226. data/app/pb_kits/playbook/pb_online_status/_online_status.tsx +3 -1
  227. data/app/pb_kits/playbook/pb_online_status/kit.schema.json +1 -0
  228. data/app/pb_kits/playbook/pb_overlay/docs/_playground.json +3 -3
  229. data/app/pb_kits/playbook/pb_overlay/kit.schema.json +22 -12
  230. data/app/pb_kits/playbook/pb_pagination/kit.schema.json +6 -3
  231. data/app/pb_kits/playbook/pb_passphrase/docs/_playground.json +6 -4
  232. data/app/pb_kits/playbook/pb_passphrase/kit.schema.json +10 -5
  233. data/app/pb_kits/playbook/pb_pb_bar_graph/pbbargraph.test.jsx +1 -2
  234. data/app/pb_kits/playbook/pb_pb_circle_chart/pb_circle_chart.test.jsx +1 -2
  235. data/app/pb_kits/playbook/pb_pb_gauge_chart/kit.schema.json +2 -1
  236. data/app/pb_kits/playbook/pb_pb_gauge_chart/pb_gauge_chart.test.jsx +1 -2
  237. data/app/pb_kits/playbook/pb_pb_line_graph/pb_line_graph.test.jsx +1 -2
  238. data/app/pb_kits/playbook/pb_person/_person.tsx +3 -1
  239. data/app/pb_kits/playbook/pb_person/kit.schema.json +1 -0
  240. data/app/pb_kits/playbook/pb_person_contact/docs/_playground.json +3 -3
  241. data/app/pb_kits/playbook/pb_person_contact/kit.schema.json +2 -1
  242. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +3 -7
  243. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.html.erb +1 -1
  244. data/app/pb_kits/playbook/pb_phone_number_input/docs/_playground.json +3 -0
  245. data/app/pb_kits/playbook/pb_phone_number_input/img/flags.webp +0 -0
  246. data/app/pb_kits/playbook/pb_phone_number_input/img/flags@2x.webp +0 -0
  247. data/app/pb_kits/playbook/pb_phone_number_input/img/globe.webp +0 -0
  248. data/app/pb_kits/playbook/pb_phone_number_input/img/globe@2x.webp +0 -0
  249. data/app/pb_kits/playbook/pb_phone_number_input/intlTelInput.scss +13 -6
  250. data/app/pb_kits/playbook/pb_phone_number_input/kit.schema.json +6 -3
  251. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input_assets.test.js +61 -0
  252. data/app/pb_kits/playbook/pb_pill/_pill.tsx +3 -1
  253. data/app/pb_kits/playbook/pb_pill/kit.schema.json +1 -0
  254. data/app/pb_kits/playbook/pb_popover/docs/_playground.json +1 -2
  255. data/app/pb_kits/playbook/pb_popover/index.ts +47 -8
  256. data/app/pb_kits/playbook/pb_popover/kit.schema.json +18 -9
  257. data/app/pb_kits/playbook/pb_popover/popover_index.test.js +456 -0
  258. data/app/pb_kits/playbook/pb_progress_pills/docs/_playground.json +1 -0
  259. data/app/pb_kits/playbook/pb_progress_pills/kit.schema.json +2 -1
  260. data/app/pb_kits/playbook/pb_progress_simple/docs/_playground.json +3 -2
  261. data/app/pb_kits/playbook/pb_progress_simple/kit.schema.json +4 -2
  262. data/app/pb_kits/playbook/pb_progress_step/_progress_step_item.tsx +3 -1
  263. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.json +10 -3
  264. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.overrides.json +1 -1
  265. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_required_indicator.md +2 -2
  266. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_default.md +3 -4
  267. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_extensions.md +1 -1
  268. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_markdown_support.md +1 -1
  269. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_required_indicator.html.erb +9 -0
  270. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_required_indicator.md +3 -0
  271. data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +1 -0
  272. data/app/pb_kits/playbook/pb_rich_text_editor/kit.schema.json +18 -9
  273. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.html.erb +3 -7
  274. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_rails.js +26 -21
  275. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_rails.test.js +85 -1
  276. data/app/pb_kits/playbook/pb_selectable_card/docs/_playground.json +1 -0
  277. data/app/pb_kits/playbook/pb_selectable_card/kit.schema.json +4 -2
  278. data/app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.scss +0 -9
  279. data/app/pb_kits/playbook/pb_selectable_card_icon/docs/_playground.json +1 -0
  280. data/app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_custom.jsx +1 -1
  281. data/app/pb_kits/playbook/pb_selectable_card_icon/kit.schema.json +2 -1
  282. data/app/pb_kits/playbook/pb_selectable_icon/_selectable_icon.scss +0 -7
  283. data/app/pb_kits/playbook/pb_source/_source.tsx +3 -1
  284. data/app/pb_kits/playbook/pb_source/docs/_playground.json +1 -0
  285. data/app/pb_kits/playbook/pb_source/kit.schema.json +3 -1
  286. data/app/pb_kits/playbook/pb_source/source.rb +1 -1
  287. data/app/pb_kits/playbook/pb_star_rating/docs/_playground.json +1 -0
  288. data/app/pb_kits/playbook/pb_star_rating/kit.schema.json +15 -7
  289. data/app/pb_kits/playbook/pb_stat_change/_stat_change.tsx +3 -1
  290. data/app/pb_kits/playbook/pb_stat_change/docs/_playground.json +1 -0
  291. data/app/pb_kits/playbook/pb_stat_change/kit.schema.json +3 -1
  292. data/app/pb_kits/playbook/pb_stat_value/docs/_playground.json +3 -1
  293. data/app/pb_kits/playbook/pb_stat_value/kit.schema.json +2 -1
  294. data/app/pb_kits/playbook/pb_table/docs/_playground.json +5 -1
  295. data/app/pb_kits/playbook/pb_table/kit.schema.json +28 -11
  296. data/app/pb_kits/playbook/pb_text_input/docs/_playground.json +3 -0
  297. data/app/pb_kits/playbook/pb_text_input/kit.schema.json +22 -9
  298. data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +4 -1
  299. data/app/pb_kits/playbook/pb_time/kit.schema.json +13 -5
  300. data/app/pb_kits/playbook/pb_time_picker/docs/_playground.json +1 -0
  301. data/app/pb_kits/playbook/pb_time_picker/kit.schema.json +2 -1
  302. data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.tsx +3 -1
  303. data/app/pb_kits/playbook/pb_time_range_inline/kit.schema.json +13 -5
  304. data/app/pb_kits/playbook/pb_time_stacked/_time_stacked.tsx +3 -1
  305. data/app/pb_kits/playbook/pb_time_stacked/kit.schema.json +1 -0
  306. data/app/pb_kits/playbook/pb_timeline/_item.tsx +3 -1
  307. data/app/pb_kits/playbook/pb_timestamp/_timestamp.tsx +3 -1
  308. data/app/pb_kits/playbook/pb_timestamp/kit.schema.json +1 -0
  309. data/app/pb_kits/playbook/pb_timestamp/timestamp.test.js +1 -0
  310. data/app/pb_kits/playbook/pb_title/kit.schema.json +23 -10
  311. data/app/pb_kits/playbook/pb_title_count/docs/_playground.json +1 -0
  312. data/app/pb_kits/playbook/pb_title_count/kit.schema.json +2 -1
  313. data/app/pb_kits/playbook/pb_tooltip/docs/_playground.json +5 -1
  314. data/app/pb_kits/playbook/pb_tooltip/kit.schema.json +10 -5
  315. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +73 -0
  316. data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +285 -12
  317. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +22 -14
  318. data/app/pb_kits/playbook/pb_typeahead/components/PillRenderer.tsx +15 -11
  319. data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +29 -30
  320. data/app/pb_kits/playbook/pb_typeahead/components/usePillDropIndicator.ts +155 -0
  321. data/app/pb_kits/playbook/pb_typeahead/docs/_playground.json +5 -5
  322. data/app/pb_kits/playbook/pb_typeahead/docs/_playground.overrides.json +2 -2
  323. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills.html.erb +0 -1
  324. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills.jsx +0 -1
  325. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills_rails.md +3 -3
  326. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills_react.md +7 -0
  327. data/app/pb_kits/playbook/pb_typeahead/kit.schema.json +3 -3
  328. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -3
  329. data/app/pb_kits/playbook/pb_user/_user.tsx +3 -1
  330. data/app/pb_kits/playbook/pb_user/docs/_playground.json +3 -1
  331. data/app/pb_kits/playbook/pb_user/kit.schema.json +20 -9
  332. data/app/pb_kits/playbook/pb_user_badge/_user_badge.tsx +3 -1
  333. data/app/pb_kits/playbook/pb_user_badge/kit.schema.json +1 -0
  334. data/app/pb_kits/playbook/pb_weekday_stacked/_weekday_stacked.tsx +3 -1
  335. data/app/pb_kits/playbook/pb_weekday_stacked/docs/_playground.json +1 -0
  336. data/app/pb_kits/playbook/pb_weekday_stacked/kit.schema.json +3 -1
  337. data/app/pb_kits/playbook/pb_weekday_stacked/weekday_stacked.test.jsx +1 -0
  338. data/app/pb_kits/playbook/utilities/test/globalProps/onClick.test.js +471 -0
  339. data/app/pb_kits/playbook/utilities/test-utils.js +0 -1
  340. data/dist/ai/all-schemas.json +986 -388
  341. data/dist/ai/external-dependencies.json +1 -1
  342. data/dist/ai/forms.json +2 -2
  343. data/dist/ai/index.json +11 -3
  344. data/dist/ai/kits/advanced_table.schema.json +44 -16
  345. data/dist/ai/kits/avatar.schema.json +22 -9
  346. data/dist/ai/kits/background.schema.json +10 -3
  347. data/dist/ai/kits/badge.schema.json +26 -12
  348. data/dist/ai/kits/body.schema.json +14 -5
  349. data/dist/ai/kits/button.schema.json +29 -25
  350. data/dist/ai/kits/caption.schema.json +17 -7
  351. data/dist/ai/kits/card.schema.json +2 -1
  352. data/dist/ai/kits/checkbox.schema.json +10 -5
  353. data/dist/ai/kits/contact.schema.json +3 -1
  354. data/dist/ai/kits/copy_button.schema.json +10 -5
  355. data/dist/ai/kits/currency.schema.json +6 -2
  356. data/dist/ai/kits/dashboard_value.schema.json +4 -2
  357. data/dist/ai/kits/date.schema.json +16 -6
  358. data/dist/ai/kits/date_picker.schema.json +31 -13
  359. data/dist/ai/kits/date_range_inline.schema.json +3 -1
  360. data/dist/ai/kits/date_range_stacked.schema.json +1 -0
  361. data/dist/ai/kits/date_stacked.schema.json +1 -0
  362. data/dist/ai/kits/date_time.schema.json +3 -1
  363. data/dist/ai/kits/date_time_stacked.schema.json +3 -1
  364. data/dist/ai/kits/date_year_stacked.schema.json +1 -0
  365. data/dist/ai/kits/detail.schema.json +2 -1
  366. data/dist/ai/kits/dialog.schema.json +22 -9
  367. data/dist/ai/kits/distribution_bar.schema.json +2 -1
  368. data/dist/ai/kits/dropdown.schema.json +98 -18
  369. data/dist/ai/kits/empty_state.schema.json +2 -1
  370. data/dist/ai/kits/file_upload.schema.json +8 -3
  371. data/dist/ai/kits/fixed_confirmation_toast.schema.json +6 -3
  372. data/dist/ai/kits/flex.schema.json +27 -12
  373. data/dist/ai/kits/form.schema.json +1 -6
  374. data/dist/ai/kits/form_pill.schema.json +6 -3
  375. data/dist/ai/kits/full_screen.schema.json +8 -4
  376. data/dist/ai/kits/hashtag.schema.json +2 -1
  377. data/dist/ai/kits/highlight.schema.json +2 -1
  378. data/dist/ai/kits/icon.schema.json +31 -13
  379. data/dist/ai/kits/icon_circle.schema.json +3 -1
  380. data/dist/ai/kits/icon_stat_value.schema.json +4 -2
  381. data/dist/ai/kits/image.schema.json +57 -24
  382. data/dist/ai/kits/label_pill.schema.json +1 -0
  383. data/dist/ai/kits/label_value.schema.json +2 -1
  384. data/dist/ai/kits/layout.schema.json +43 -20
  385. data/dist/ai/kits/legend.schema.json +3 -1
  386. data/dist/ai/kits/lightbox.schema.json +86 -0
  387. data/dist/ai/kits/link.schema.json +14 -6
  388. data/dist/ai/kits/list.schema.json +2 -1
  389. data/dist/ai/kits/loading_inline.schema.json +4 -1
  390. data/dist/ai/kits/map.schema.json +4 -7
  391. data/dist/ai/kits/message.schema.json +2 -1
  392. data/dist/ai/kits/multiple_users.schema.json +19 -11
  393. data/dist/ai/kits/multiple_users_stacked.schema.json +2 -1
  394. data/dist/ai/kits/nav.schema.json +4 -2
  395. data/dist/ai/kits/online_status.schema.json +1 -0
  396. data/dist/ai/kits/overlay.schema.json +22 -12
  397. data/dist/ai/kits/pagination.schema.json +6 -3
  398. data/dist/ai/kits/passphrase.schema.json +10 -5
  399. data/dist/ai/kits/pb_gauge_chart.schema.json +2 -1
  400. data/dist/ai/kits/person.schema.json +1 -0
  401. data/dist/ai/kits/person_contact.schema.json +2 -1
  402. data/dist/ai/kits/phone_number_input.schema.json +6 -3
  403. data/dist/ai/kits/pill.schema.json +1 -0
  404. data/dist/ai/kits/popover.schema.json +17 -8
  405. data/dist/ai/kits/progress_pills.schema.json +2 -1
  406. data/dist/ai/kits/progress_simple.schema.json +4 -2
  407. data/dist/ai/kits/rich_text_editor.schema.json +19 -10
  408. data/dist/ai/kits/selectable_card.schema.json +4 -2
  409. data/dist/ai/kits/selectable_card_icon.schema.json +2 -1
  410. data/dist/ai/kits/source.schema.json +3 -1
  411. data/dist/ai/kits/star_rating.schema.json +15 -7
  412. data/dist/ai/kits/stat_change.schema.json +3 -1
  413. data/dist/ai/kits/stat_value.schema.json +2 -1
  414. data/dist/ai/kits/table.schema.json +28 -11
  415. data/dist/ai/kits/text_input.schema.json +22 -9
  416. data/dist/ai/kits/time.schema.json +12 -4
  417. data/dist/ai/kits/time_picker.schema.json +2 -1
  418. data/dist/ai/kits/time_range_inline.schema.json +13 -5
  419. data/dist/ai/kits/time_stacked.schema.json +1 -0
  420. data/dist/ai/kits/timestamp.schema.json +1 -0
  421. data/dist/ai/kits/title.schema.json +23 -10
  422. data/dist/ai/kits/title_count.schema.json +2 -1
  423. data/dist/ai/kits/tooltip.schema.json +10 -5
  424. data/dist/ai/kits/typeahead.schema.json +3 -3
  425. data/dist/ai/kits/user.schema.json +20 -9
  426. data/dist/ai/kits/user_badge.schema.json +1 -0
  427. data/dist/ai/kits/weekday_stacked.schema.json +3 -1
  428. data/dist/ai/playgrounds/advanced_table.json +1 -1
  429. data/dist/ai/playgrounds/dropdown.json +1 -1
  430. data/dist/ai/playgrounds/index.json +1 -1
  431. data/dist/ai/playgrounds/rich_text_editor.json +1 -1
  432. data/dist/ai/playgrounds/typeahead.json +1 -1
  433. data/dist/ai/visual-index.json +1 -1
  434. data/dist/chunks/_pagination-DZ0eQuH2.js +1 -0
  435. data/dist/chunks/{_pb_line_graph-Du7xE9vl.js → _pb_line_graph-DyvH5Zj1.js} +1 -1
  436. data/dist/chunks/{_detail-Bsvl694i.js → _tooltip-CFbtqu-E.js} +2 -2
  437. data/dist/chunks/_typeahead-CkiAf8zx.js +1 -0
  438. data/dist/chunks/{globalProps-B120NbSJ.js → globalProps-xfGTpdLP.js} +1 -1
  439. data/dist/chunks/index-4jrZjexD.js +1 -0
  440. data/dist/chunks/index-BAy61y8S.js +1 -0
  441. data/dist/chunks/index-Cb_SDipk.js +1 -0
  442. data/dist/chunks/index-D3RdsDp7.js +1 -0
  443. data/dist/chunks/index-D8PZIesy.js +1 -0
  444. data/dist/chunks/index-DIoc-aua.js +1 -0
  445. data/dist/chunks/index-qex65UMn.js +1 -0
  446. data/dist/chunks/lib-Cu_i0y0k.js +29 -0
  447. data/dist/chunks/{time_picker_helper-CYGg0UQ0.js → time_picker_helper-B82MORju.js} +1 -1
  448. data/dist/chunks/vendor.js +2 -2
  449. data/dist/menu.yml +3 -3
  450. data/dist/playbook-rails-react-bindings.js +1 -1
  451. data/dist/playbook-rails.js +1 -1
  452. data/dist/playbook.css +1 -1
  453. data/lib/playbook/changelog_generator.rb +47 -21
  454. data/lib/playbook/connect_message_generator.rb +15 -2
  455. data/lib/playbook/version.rb +2 -2
  456. metadata +99 -23
  457. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills.md +0 -7
  458. data/dist/chunks/_table-Bf6LGyL9.js +0 -1
  459. data/dist/chunks/_typeahead-w6S5Vx4b.js +0 -1
  460. data/dist/chunks/lib-Buo6zHEw.js +0 -29
  461. /data/app/pb_kits/playbook/pb_form/docs/{_description.md → _description_rails.md} +0 -0
  462. /data/app/pb_kits/playbook/pb_form/docs/{_form_default_values.md → _form_default_values_rails.md} +0 -0
  463. /data/app/pb_kits/playbook/pb_form/docs/{_form_defaults.md → _form_defaults_rails.md} +0 -0
  464. /data/app/pb_kits/playbook/pb_form/docs/{_form_model_values.md → _form_model_values_rails.md} +0 -0
  465. /data/app/pb_kits/playbook/pb_form/docs/{_form_multi_column.md → _form_multi_column_rails.md} +0 -0
  466. /data/app/pb_kits/playbook/pb_form/docs/{_form_validation.md → _form_validation_rails.md} +0 -0
@@ -4,8 +4,10 @@ import { components } from 'react-select'
4
4
  import Body from '../../pb_body/_body'
5
5
  import Draggable from '../../pb_draggable/_draggable'
6
6
  import { DraggableContext, DraggableProvider } from '../../pb_draggable/context'
7
+ import { noop } from '../../utilities/object'
7
8
  import { SelectValueType } from '../_typeahead'
8
9
  import PillRenderer from './PillRenderer'
10
+ import usePillDropIndicator from './usePillDropIndicator'
9
11
 
10
12
  type ValueContainerProps = {
11
13
  children: React.ReactNode | React.ReactNode[]
@@ -23,17 +25,9 @@ const isPillReorderActive = (selectProps: Record<string, unknown> | undefined):
23
25
  )
24
26
  }
25
27
 
26
- const mapDraggableItemsToValue = (
27
- items: Array<{ id: string }>,
28
- value: SelectValueType[],
29
- ): SelectValueType[] => {
30
- return items
31
- .map((item) => value.find((entry) => entry.value === item.id))
32
- .filter((entry): entry is SelectValueType => Boolean(entry))
33
- }
34
-
35
28
  type DraggablePillListProps = {
36
29
  onRemove: (item: SelectValueType) => void
30
+ pendingReorderRef: React.MutableRefObject<SelectValueType[] | null>
37
31
  selectProps: Record<string, unknown>
38
32
  setValue: (value: SelectValueType[], action: string) => void
39
33
  value: SelectValueType[]
@@ -45,11 +39,11 @@ const isPillCloseTarget = (target: EventTarget | null): boolean => {
45
39
 
46
40
  const shouldBlockPillMouseDown = (
47
41
  target: EventTarget | null,
48
- pillDragHandle: boolean,
42
+ externalDragHandle: boolean,
49
43
  ): boolean => {
50
44
  if (isPillCloseTarget(target)) return false
51
45
 
52
- if (pillDragHandle) {
46
+ if (externalDragHandle) {
53
47
  return Boolean(
54
48
  (target as HTMLElement | null)?.closest(
55
49
  '.pb_typeahead_pill_drag_handle, .pb_draggable_handle',
@@ -64,20 +58,26 @@ const shouldBlockPillMouseDown = (
64
58
 
65
59
  const DraggablePillList = ({
66
60
  onRemove,
61
+ pendingReorderRef,
67
62
  selectProps,
68
63
  setValue,
69
64
  value,
70
65
  }: DraggablePillListProps) => {
71
- const { items, isDragging } = DraggableContext()
72
- const orderedValues = isDragging
73
- ? mapDraggableItemsToValue(items, value)
74
- : value
66
+ // Context `isDragging` is the active dragId string (empty when idle).
67
+ const { isDragging: dragId } = DraggableContext()
68
+ // Pills hold their place while dragging; the drop line previews the new position.
69
+ const dropTarget = usePillDropIndicator(dragId, value, pendingReorderRef)
70
+
71
+ const getDropLineClassName = (index: number): string | undefined => {
72
+ if (dropTarget?.index !== index) return undefined
73
+ return dropTarget.after ? 'pb_typeahead_drop_after' : 'pb_typeahead_drop_before'
74
+ }
75
75
 
76
76
  const handleKeyboardReorder = (index: number, direction: 'left' | 'right') => {
77
77
  const newIndex = direction === 'left' ? index - 1 : index + 1
78
- if (newIndex < 0 || newIndex >= orderedValues.length) return
78
+ if (newIndex < 0 || newIndex >= value.length) return
79
79
 
80
- const reordered = [...orderedValues]
80
+ const reordered = [...value]
81
81
  const [movedItem] = reordered.splice(index, 1)
82
82
  reordered.splice(newIndex, 0, movedItem)
83
83
  setValue(reordered, 'set-value')
@@ -89,27 +89,29 @@ const DraggablePillList = ({
89
89
  container="typeahead-pills"
90
90
  tag="div"
91
91
  >
92
- {orderedValues.map((item, index) => (
92
+ {value.map((item, index) => (
93
93
  <Draggable.Item
94
+ className={getDropLineClassName(index)}
94
95
  container="typeahead-pills"
95
96
  dragId={item.value}
96
- handlePointerDrag={Boolean((selectProps as any)?.pillDragHandle)}
97
+ handlePointerDrag={Boolean((selectProps as any)?.externalDragHandle)}
97
98
  key={item.value}
98
- pointerDrag={!(selectProps as any)?.pillDragHandle}
99
+ pointerDrag={!(selectProps as any)?.externalDragHandle}
99
100
  tag="span"
100
101
  >
101
102
  <PillRenderer
102
103
  dark={(selectProps as any)?.dark}
103
104
  data={item}
105
+ externalDragHandle={(selectProps as any)?.externalDragHandle}
104
106
  index={index}
105
107
  multiKit={(selectProps as any)?.multiKit}
106
108
  onKeyboardReorder={(direction) => handleKeyboardReorder(index, direction)}
107
109
  onRemove={() => onRemove(item)}
108
110
  pillColor={(selectProps as any)?.pillColor}
109
- pillDragHandle={(selectProps as any)?.pillDragHandle}
110
111
  selectProps={selectProps}
112
+ showDragIcon={!selectProps.externalDragHandle}
111
113
  showPillIndex={(selectProps as any)?.showPillIndex}
112
- totalCount={orderedValues.length}
114
+ totalCount={value.length}
113
115
  truncate={(selectProps as any)?.truncate}
114
116
  wrapped={(selectProps as any)?.wrapped}
115
117
  />
@@ -169,20 +171,17 @@ const DraggablePillsStrip = React.memo(function DraggablePillsStrip({
169
171
  pendingReorderRef.current = null
170
172
  }, [setValue])
171
173
 
172
- const handleReorder = useCallback((items: Array<{ id: string }>) => {
173
- pendingReorderRef.current = mapDraggableItemsToValue(items, getValueRef.current())
174
- }, [])
175
-
176
174
  return (
177
175
  <DraggableProvider
178
176
  dropZone={{ type: 'ghost' }}
179
177
  initialItems={initialItems}
180
178
  onDragEnd={commitReorder}
181
179
  onDrop={commitReorder}
182
- onReorder={handleReorder}
180
+ onReorder={noop}
183
181
  >
184
182
  <DraggablePillList
185
183
  onRemove={onRemove}
184
+ pendingReorderRef={pendingReorderRef}
186
185
  selectProps={selectProps}
187
186
  setValue={setValue}
188
187
  value={value}
@@ -204,20 +203,20 @@ const ValueContainer = (props: ValueContainerProps | any): React.ReactElement =>
204
203
  setValue(newValue, 'remove-value')
205
204
  }, [getValue, setValue])
206
205
 
207
- const pillDragHandle = Boolean((selectProps as any)?.pillDragHandle)
206
+ const externalDragHandle = Boolean((selectProps as any)?.externalDragHandle)
208
207
 
209
208
  const valueContainerInnerProps = useMemo(() => ({
210
209
  ...innerProps,
211
210
  // Bubble phase only — capture-phase stopPropagation blocks mousedown from
212
211
  // reaching pill drag listeners.
213
212
  onMouseDown: (event: React.MouseEvent) => {
214
- if (shouldBlockPillMouseDown(event.target, pillDragHandle)) {
213
+ if (shouldBlockPillMouseDown(event.target, externalDragHandle)) {
215
214
  event.stopPropagation()
216
215
  return
217
216
  }
218
217
  innerProps?.onMouseDown?.(event)
219
218
  },
220
- }), [innerProps, pillDragHandle])
219
+ }), [innerProps, externalDragHandle])
221
220
 
222
221
  if (isPillReorderActive(selectProps) && hasValue) {
223
222
  return (
@@ -0,0 +1,155 @@
1
+ import React, { useEffect, useState } from 'react'
2
+
3
+ import { SelectValueType } from '../_typeahead'
4
+
5
+ export type PillDropTarget = {
6
+ after: boolean
7
+ index: number
8
+ }
9
+
10
+ // Vertical reach (px) above/below a pill row that still targets a drop position in that row.
11
+ // Use Infinity to target the nearest row from anywhere on the page.
12
+ const ROW_TOLERANCE = 80
13
+
14
+ // Pointer position while a button is down / touch is active. The drop-indicator effect mounts
15
+ // after React commits dragId, so the threshold-crossing move is already gone — seed from this.
16
+ let lastPointer: { x: number, y: number } | null = null
17
+ let pointerTrackingInstalled = false
18
+
19
+ const ensurePointerTracking = () => {
20
+ if (pointerTrackingInstalled || typeof document === 'undefined') return
21
+ pointerTrackingInstalled = true
22
+
23
+ document.addEventListener('mousemove', (event: MouseEvent) => {
24
+ if (event.buttons === 0) return
25
+ lastPointer = { x: event.clientX, y: event.clientY }
26
+ }, true)
27
+
28
+ document.addEventListener('touchmove', (event: TouchEvent) => {
29
+ const touch = event.touches[0]
30
+ if (touch) lastPointer = { x: touch.clientX, y: touch.clientY }
31
+ }, { capture: true, passive: true })
32
+ }
33
+
34
+ const getVerticalDistance = (rect: DOMRect, y: number): number => (
35
+ Math.max(rect.top - y, y - rect.bottom, 0)
36
+ )
37
+
38
+ // Finds the drop position from the pointer: the nearest pill row (within ROW_TOLERANCE),
39
+ // then the gap in that row. Left of a row targets its first pill; right of it (e.g. over
40
+ // the input) targets after its last pill.
41
+ const getDropTarget = (pills: Element[], x: number, y: number): PillDropTarget | null => {
42
+ if (pills.length === 0) return null
43
+
44
+ const rects = pills.map((pill) => pill.getBoundingClientRect())
45
+ const nearestRect = rects.reduce((nearest, rect) => (
46
+ getVerticalDistance(rect, y) < getVerticalDistance(nearest, y) ? rect : nearest
47
+ ))
48
+ if (getVerticalDistance(nearestRect, y) > ROW_TOLERANCE) return null
49
+
50
+ const rowIndexes = rects
51
+ .map((rect, index) => ({ index, rect }))
52
+ .filter(({ rect }) => rect.top < nearestRect.bottom && rect.bottom > nearestRect.top)
53
+ .map(({ index }) => index)
54
+
55
+ const pillAfterPointer = rowIndexes.find((index) => x < rects[index].left + rects[index].width / 2)
56
+ if (pillAfterPointer !== undefined) {
57
+ return { after: false, index: pillAfterPointer }
58
+ }
59
+
60
+ return { after: true, index: rowIndexes[rowIndexes.length - 1] }
61
+ }
62
+
63
+ // While a pill is dragged, a ghost copy follows the pointer and the targeted pill gets a
64
+ // before/after drop line. Targeting the pill's current spot shows no line and commits nothing.
65
+ const usePillDropIndicator = (
66
+ dragId: string,
67
+ value: SelectValueType[],
68
+ pendingReorderRef: React.MutableRefObject<SelectValueType[] | null>,
69
+ ): PillDropTarget | null => {
70
+ const [dropTarget, setDropTarget] = useState<PillDropTarget | null>(null)
71
+
72
+ useEffect(() => {
73
+ ensurePointerTracking()
74
+ }, [])
75
+
76
+ useEffect(() => {
77
+ // Only one pill can be dragged at a time, so the dragging item is unique on the page
78
+ const source = document.querySelector<HTMLElement>('.pb_typeahead_draggable_pills .is_dragging')
79
+ if (!dragId || !source?.parentElement) return undefined
80
+
81
+ const pills = Array.from(source.parentElement.children)
82
+ const sourceIndex = value.findIndex((item) => item.value === dragId)
83
+ if (sourceIndex < 0 || pills.length === 0) return undefined
84
+
85
+ const sourceRect = source.getBoundingClientRect()
86
+
87
+ const ghost = source.cloneNode(true) as HTMLElement
88
+ ghost.className = 'pb_typeahead_pill_drag_preview'
89
+ ghost.setAttribute('inert', '')
90
+ ghost.style.left = `${sourceRect.left}px`
91
+ ghost.style.top = `${sourceRect.top}px`
92
+ ghost.style.width = `${sourceRect.width}px`
93
+ document.body.appendChild(ghost)
94
+
95
+ // Anchor to the pill center — not the first mousemove we hear. The effect mounts
96
+ // after React commits the drag, so a late first-move origin leaves the ghost
97
+ // permanently offset when the pointer moved quickly before listeners attached.
98
+ const pointerOrigin = {
99
+ x: sourceRect.left + sourceRect.width / 2,
100
+ y: sourceRect.top + sourceRect.height / 2,
101
+ }
102
+ pendingReorderRef.current = null
103
+
104
+ const handlePointerMove = (x: number, y: number) => {
105
+ ghost.style.translate = `${x - pointerOrigin.x}px ${y - pointerOrigin.y}px`
106
+
107
+ const target = getDropTarget(pills, x, y)
108
+ const targetSlot = target ? target.index + Number(target.after) : -1
109
+ const isCurrentPosition = targetSlot === sourceIndex || targetSlot === sourceIndex + 1
110
+
111
+ if (!target || isCurrentPosition) {
112
+ pendingReorderRef.current = null
113
+ setDropTarget(null)
114
+ return
115
+ }
116
+
117
+ const reordered = value.filter((item) => item.value !== dragId)
118
+ reordered.splice(targetSlot > sourceIndex ? targetSlot - 1 : targetSlot, 0, value[sourceIndex])
119
+ pendingReorderRef.current = reordered
120
+
121
+ setDropTarget((current) => {
122
+ const isSameTarget = current?.index === target.index && current.after === target.after
123
+ return isSameTarget ? current : target
124
+ })
125
+ }
126
+
127
+ const handleMouseMove = (event: MouseEvent) => {
128
+ handlePointerMove(event.clientX, event.clientY)
129
+ }
130
+
131
+ const handleTouchMove = (event: TouchEvent) => {
132
+ const touch = event.touches[0]
133
+ if (touch) handlePointerMove(touch.clientX, touch.clientY)
134
+ }
135
+
136
+ document.addEventListener('mousemove', handleMouseMove)
137
+ document.addEventListener('touchmove', handleTouchMove, { passive: true })
138
+
139
+ // Apply the pointer position from the move that started the drag (already fired).
140
+ if (lastPointer) {
141
+ handlePointerMove(lastPointer.x, lastPointer.y)
142
+ }
143
+
144
+ return () => {
145
+ document.removeEventListener('mousemove', handleMouseMove)
146
+ document.removeEventListener('touchmove', handleTouchMove)
147
+ ghost.remove()
148
+ setDropTarget(null)
149
+ }
150
+ }, [dragId, pendingReorderRef, value])
151
+
152
+ return dropTarget
153
+ }
154
+
155
+ export default usePillDropIndicator
@@ -14,8 +14,8 @@
14
14
  "clearOnContextChange": true,
15
15
  "preserveSearchInput": false,
16
16
  "enablePillReorder": false,
17
- "showPillIndex": false,
18
- "pillDragHandle": true
17
+ "externalDragHandle": false,
18
+ "showPillIndex": false
19
19
  },
20
20
  "groups": [
21
21
  {
@@ -65,8 +65,8 @@
65
65
  "dark",
66
66
  "marginBottom",
67
67
  "enablePillReorder",
68
- "showPillIndex",
69
- "pillDragHandle"
68
+ "externalDragHandle",
69
+ "showPillIndex"
70
70
  ]
71
71
  }
72
72
  ],
@@ -264,7 +264,7 @@
264
264
  "showPillIndex": {
265
265
  "requires": "isMulti"
266
266
  },
267
- "pillDragHandle": {
267
+ "externalDragHandle": {
268
268
  "requires": "isMulti"
269
269
  }
270
270
  },
@@ -49,7 +49,7 @@
49
49
  },
50
50
  {
51
51
  "name": "Appearance",
52
- "props": ["components", "dark", "marginBottom", "enablePillReorder", "showPillIndex", "pillDragHandle"]
52
+ "props": ["components", "dark", "marginBottom", "enablePillReorder", "externalDragHandle", "showPillIndex"]
53
53
  }
54
54
  ],
55
55
  "presets": [
@@ -162,7 +162,7 @@
162
162
  "clearOnContextChange": { "requires": "searchContextSelector" },
163
163
  "enablePillReorder": { "requires": "isMulti" },
164
164
  "showPillIndex": { "requires": "isMulti" },
165
- "pillDragHandle": { "requires": "isMulti" }
165
+ "externalDragHandle": { "requires": "isMulti" }
166
166
  },
167
167
  "hints": {
168
168
  "default": {
@@ -13,7 +13,6 @@
13
13
  id: "typeahead-draggable-pills-example",
14
14
  default_options: [options[0], options[1], options[2]],
15
15
  enable_pill_reorder: true,
16
- pill_drag_handle: false,
17
16
  show_pill_index: true,
18
17
  is_multi: true,
19
18
  label: "Services",
@@ -49,7 +49,6 @@ const TypeaheadDraggablePills = (props) => {
49
49
  showPillIndex
50
50
  value={value}
51
51
  {...props}
52
- pillDragHandle={false}
53
52
  />
54
53
 
55
54
  <Body
@@ -1,7 +1,7 @@
1
- Use `enable_pill_reorder: true` with `show_pill_index: true` to let users drag selected pills into a new order. Set `pill_drag_handle: false` to hide the grip icon and drag the whole pill instead.
1
+ Use `enable_pill_reorder: true` with `show_pill_index: true` to let users drag selected pills into a new order. By default, each pill shows a grip icon and can be dragged from anywhere on the pill. Set `external_drag_handle: true` to use an external grip handle instead.
2
2
 
3
- Order is committed on drop.
3
+ While dragging, pills stay in place, a ghost follows the pointer, and a blue line marks where the pill will land. Order is committed on drop.
4
4
 
5
5
  The `pb-typeahead-kit-{id}-result-option-reorder` custom event receives the reordered value array.
6
6
 
7
- Keyboard reorder: focus a pill, then press Control+Shift+ArrowLeft or Control+Shift+ArrowRight to move it one position.
7
+ Keyboard reorder: focus a pill, then press ArrowLeft or ArrowRight to move it one position.
@@ -0,0 +1,7 @@
1
+ Use `enablePillReorder` to let users drag selected pills into a new order. Pair with `showPillIndex` to display numbered prefixes that update automatically after reorder.
2
+
3
+ By default, each pill shows a grip icon and can be dragged from anywhere on the pill. Set `externalDragHandle` to `true` to use an external grip handle instead (drag only from the handle).
4
+
5
+ While dragging, pills stay in place, a ghost follows the pointer, and a blue line marks where the pill will land. Order is committed on drop. The `onChange` callback and `pb-typeahead-kit-{id}-result-option-reorder` custom event both receive the reordered value array.
6
+
7
+ Keyboard reorder: focus a pill, then press ArrowLeft or ArrowRight to move it one position.
@@ -222,7 +222,7 @@
222
222
  ],
223
223
  "default": false
224
224
  },
225
- "showPillIndex": {
225
+ "externalDragHandle": {
226
226
  "type": "boolean",
227
227
  "platforms": [
228
228
  "react",
@@ -230,13 +230,13 @@
230
230
  ],
231
231
  "default": false
232
232
  },
233
- "pillDragHandle": {
233
+ "showPillIndex": {
234
234
  "type": "boolean",
235
235
  "platforms": [
236
236
  "react",
237
237
  "rails"
238
238
  ],
239
- "default": true
239
+ "default": false
240
240
  },
241
241
  "styles": {
242
242
  "type": "TypeaheadStylesConfig",
@@ -66,10 +66,10 @@ module Playbook
66
66
  default: false
67
67
  prop :enable_pill_reorder, type: Playbook::Props::Boolean,
68
68
  default: false
69
+ prop :external_drag_handle, type: Playbook::Props::Boolean,
70
+ default: false
69
71
  prop :show_pill_index, type: Playbook::Props::Boolean,
70
72
  default: false
71
- prop :pill_drag_handle, type: Playbook::Props::Boolean,
72
- default: true
73
73
  def classname
74
74
  default_margin_bottom = margin_bottom.present? ? "" : " mb_sm"
75
75
  generate_classname("pb_typeahead_kit") + default_margin_bottom
@@ -125,8 +125,8 @@ module Playbook
125
125
  preserveSearchInput: preserve_search_input,
126
126
  createable: createable,
127
127
  enablePillReorder: enable_pill_reorder,
128
+ externalDragHandle: external_drag_handle,
128
129
  showPillIndex: show_pill_index,
129
- pillDragHandle: pill_drag_handle,
130
130
  }
131
131
 
132
132
  base_options[:getOptionLabel] = get_option_label if get_option_label.present?
@@ -3,6 +3,7 @@ import classnames from 'classnames'
3
3
 
4
4
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
5
  import { GlobalProps, globalProps } from '../utilities/globalProps'
6
+ import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
6
7
 
7
8
  import Avatar from '../pb_avatar/_avatar'
8
9
  import Body from '../pb_body/_body'
@@ -30,7 +31,7 @@ type UserProps = {
30
31
  territory?: string,
31
32
  title?: string,
32
33
  titleStyle?: "title" | "body" | "caption" | "detail",
33
- } & GlobalProps
34
+ } & GlobalProps & GlobalEventProps
34
35
 
35
36
  const User = (props: UserProps): React.ReactElement => {
36
37
  const {
@@ -142,6 +143,7 @@ const User = (props: UserProps): React.ReactElement => {
142
143
  {...ariaProps}
143
144
  {...dataProps}
144
145
  {...htmlProps}
146
+ {...globalEventProps(props)}
145
147
  className={classes}
146
148
  id={id}
147
149
  >
@@ -5,13 +5,15 @@
5
5
  "align": "left",
6
6
  "avatar": true,
7
7
  "bold": true,
8
+ "dark": false,
8
9
  "avatarGrayscale": false,
9
10
  "nameStyle": "title",
10
11
  "orientation": "horizontal",
11
12
  "size": "md",
13
+ "territory": "",
14
+ "title": "Engineer",
12
15
  "titleStyle": "body",
13
16
  "name": "Anna Black",
14
- "title": "Engineer",
15
17
  "subtitle": "Product team",
16
18
  "avatarUrl": "https://randomuser.me/api/portraits/women/44.jpg"
17
19
  },
@@ -47,7 +47,8 @@
47
47
  "type": "boolean",
48
48
  "platforms": [
49
49
  "react"
50
- ]
50
+ ],
51
+ "default": false
51
52
  },
52
53
  "avatarGrayscale": {
53
54
  "type": "boolean",
@@ -115,14 +116,16 @@
115
116
  "platforms": [
116
117
  "react",
117
118
  "rails"
118
- ]
119
+ ],
120
+ "default": ""
119
121
  },
120
122
  "title": {
121
123
  "type": "string",
122
124
  "platforms": [
123
125
  "react",
124
126
  "rails"
125
- ]
127
+ ],
128
+ "default": ""
126
129
  },
127
130
  "titleStyle": {
128
131
  "type": "enum",
@@ -130,16 +133,24 @@
130
133
  "react",
131
134
  "rails"
132
135
  ],
133
- "values": [
134
- "title",
135
- "body",
136
- "caption",
137
- "detail"
138
- ],
136
+ "values": {
137
+ "react": [
138
+ "title",
139
+ "body",
140
+ "caption",
141
+ "detail"
142
+ ],
143
+ "rails": [
144
+ "body",
145
+ "caption",
146
+ "detail"
147
+ ]
148
+ },
139
149
  "default": "body"
140
150
  }
141
151
  },
142
152
  "globalProps": true,
153
+ "globalEventProps": true,
143
154
  "usage": {
144
155
  "react": {
145
156
  "import": "import { User } from 'playbook-ui'",
@@ -2,6 +2,7 @@ import React 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'
5
+ import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
5
6
  import Veteran from './badges/veteran'
6
7
  import MillionDollar from './badges/million-dollar';
7
8
 
@@ -13,7 +14,7 @@ type UserBadgeProps = {
13
14
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
14
15
  id?: string,
15
16
  size?: "sm" | "md" | "lg",
16
- }
17
+ } & GlobalEventProps
17
18
 
18
19
  const UserBadge = (props: UserBadgeProps): React.ReactElement => {
19
20
  const {
@@ -41,6 +42,7 @@ const UserBadge = (props: UserBadgeProps): React.ReactElement => {
41
42
  {...ariaProps}
42
43
  {...dataProps}
43
44
  {...htmlProps}
45
+ {...globalEventProps(props)}
44
46
  className={classes}
45
47
  id={id}
46
48
  >
@@ -34,6 +34,7 @@
34
34
  }
35
35
  },
36
36
  "globalProps": true,
37
+ "globalEventProps": true,
37
38
  "usage": {
38
39
  "react": {
39
40
  "import": "import { UserBadge } from 'playbook-ui'",
@@ -1,6 +1,7 @@
1
1
  import React from 'react'
2
2
  import classnames from 'classnames'
3
3
  import { globalProps } from '../utilities/globalProps'
4
+ import { GlobalEventProps, globalEventProps } from '../utilities/globalEventProps'
4
5
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
6
 
6
7
  import Caption from '../pb_caption/_caption'
@@ -19,7 +20,7 @@ type WeekdayStackedProps = {
19
20
  id?: string,
20
21
  variant?: "day_only" | "month_day" | "expanded",
21
22
  compact?: boolean,
22
- }
23
+ } & GlobalEventProps
23
24
 
24
25
  const getDayOfWeek = (value: Date, compact: boolean) => {
25
26
  if (compact) {
@@ -66,6 +67,7 @@ const WeekdayStacked = (props: WeekdayStackedProps): React.ReactElement => {
66
67
  {...ariaProps}
67
68
  {...dataProps}
68
69
  {...htmlProps}
70
+ {...globalEventProps(props)}
69
71
  className={classes}
70
72
  id={id}
71
73
  >
@@ -3,6 +3,7 @@
3
3
  "propTargets": {},
4
4
  "defaults": {
5
5
  "align": "left",
6
+ "dark": false,
6
7
  "variant": "month_day",
7
8
  "compact": false
8
9
  },
@@ -24,7 +24,8 @@
24
24
  "type": "boolean",
25
25
  "platforms": [
26
26
  "react"
27
- ]
27
+ ],
28
+ "default": false
28
29
  },
29
30
  "date": {
30
31
  "type": "Date",
@@ -56,6 +57,7 @@
56
57
  }
57
58
  },
58
59
  "globalProps": true,
60
+ "globalEventProps": true,
59
61
  "usage": {
60
62
  "react": {
61
63
  "import": "import { WeekdayStacked } from 'playbook-ui'",
@@ -4,6 +4,7 @@ import { render, screen } from "../utilities/test-utils";
4
4
  import WeekdayStacked from "./_weekday_stacked";
5
5
 
6
6
  const TEST_DATE = "01/01/2020 00:00:000 GMT-0500";
7
+ jest.useFakeTimers();
7
8
  jest.setSystemTime(new Date(TEST_DATE));
8
9
  const testId = "weekdaystacked-kit";
9
10
  const realDate = Date;