playbook_ui 18.2.0 → 18.3.0.pre.alpha.forwardrefwarnings20879

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 (232) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +1 -1
  3. data/app/pb_kits/playbook/pb_avatar/_avatar.tsx +3 -1
  4. data/app/pb_kits/playbook/pb_avatar/kit.schema.json +1 -0
  5. data/app/pb_kits/playbook/pb_collapsible/collapsible.test.js +1 -2
  6. data/app/pb_kits/playbook/pb_contact/_contact.tsx +4 -1
  7. data/app/pb_kits/playbook/pb_contact/kit.schema.json +1 -0
  8. data/app/pb_kits/playbook/pb_date/_date.tsx +3 -1
  9. data/app/pb_kits/playbook/pb_date/date.test.js +1 -1
  10. data/app/pb_kits/playbook/pb_date/kit.schema.json +1 -0
  11. data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +4 -0
  12. data/app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.tsx +3 -1
  13. data/app/pb_kits/playbook/pb_date_range_inline/kit.schema.json +1 -0
  14. data/app/pb_kits/playbook/pb_date_range_stacked/_date_range_stacked.tsx +3 -1
  15. data/app/pb_kits/playbook/pb_date_range_stacked/kit.schema.json +1 -0
  16. data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.tsx +4 -1
  17. data/app/pb_kits/playbook/pb_date_stacked/date_stacked.test.js +1 -0
  18. data/app/pb_kits/playbook/pb_date_stacked/kit.schema.json +1 -0
  19. data/app/pb_kits/playbook/pb_date_time/_date_time.tsx +3 -1
  20. data/app/pb_kits/playbook/pb_date_time/dateTime.test.js +1 -0
  21. data/app/pb_kits/playbook/pb_date_time/kit.schema.json +1 -0
  22. data/app/pb_kits/playbook/pb_date_time_stacked/_date_time_stacked.tsx +2 -1
  23. data/app/pb_kits/playbook/pb_date_time_stacked/kit.schema.json +1 -0
  24. data/app/pb_kits/playbook/pb_date_year_stacked/_date_year_stacked.tsx +3 -1
  25. data/app/pb_kits/playbook/pb_date_year_stacked/date_year_stacked.test.js +1 -0
  26. data/app/pb_kits/playbook/pb_date_year_stacked/kit.schema.json +1 -0
  27. data/app/pb_kits/playbook/pb_draggable/utilities/touchDrag.ts +10 -0
  28. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +112 -0
  29. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +121 -15
  30. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills.html.erb +51 -0
  31. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills.jsx +62 -0
  32. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills_rails.md +9 -0
  33. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_draggable_pills_react.md +9 -0
  34. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_form.jsx +50 -0
  35. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_form_react.md +9 -0
  36. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_option_creation.html.erb +16 -0
  37. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_option_creation.jsx +27 -0
  38. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_option_creation_rails.md +9 -0
  39. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_option_creation_react.md +9 -0
  40. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.json +33 -2
  41. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json +13 -2
  42. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +5 -0
  43. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +4 -1
  44. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +2 -2
  45. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +24 -1
  46. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +235 -1
  47. data/app/pb_kits/playbook/pb_dropdown/dropdown_creation.test.jsx +414 -0
  48. data/app/pb_kits/playbook/pb_dropdown/dropdown_form.test.jsx +173 -0
  49. data/app/pb_kits/playbook/pb_dropdown/dropdown_index.test.js +545 -0
  50. data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +22 -5
  51. data/app/pb_kits/playbook/pb_dropdown/index.js +260 -37
  52. data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +3 -1
  53. data/app/pb_kits/playbook/pb_dropdown/kit.schema.json +42 -2
  54. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +43 -25
  55. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownFormFields.tsx +83 -0
  56. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +13 -5
  57. data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +336 -31
  58. data/app/pb_kits/playbook/pb_dropdown/utilities/optionCreation.ts +21 -0
  59. data/app/pb_kits/playbook/pb_dropdown/utilities/pillReorder.js +281 -0
  60. data/app/pb_kits/playbook/pb_dropdown/utilities/quickpickDateSync.test.ts +24 -0
  61. data/app/pb_kits/playbook/pb_dropdown/utilities/usePillDropIndicator.ts +144 -0
  62. data/app/pb_kits/playbook/pb_filter/Filter/SortMenu.tsx +8 -1
  63. data/app/pb_kits/playbook/pb_filter/docs/_filter_one_click.html.erb +38 -0
  64. data/app/pb_kits/playbook/pb_filter/docs/_filter_one_click.jsx +69 -0
  65. data/app/pb_kits/playbook/pb_filter/docs/_filter_one_click.md +1 -0
  66. data/app/pb_kits/playbook/pb_filter/docs/example.yml +2 -0
  67. data/app/pb_kits/playbook/pb_filter/docs/index.js +2 -1
  68. data/app/pb_kits/playbook/pb_filter/filter.html.erb +4 -4
  69. data/app/pb_kits/playbook/pb_filter/filter.rb +28 -0
  70. data/app/pb_kits/playbook/pb_filter/filter.test.js +41 -0
  71. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.test.js +1 -2
  72. data/app/pb_kits/playbook/pb_form/docs/_description_react.md +3 -0
  73. data/app/pb_kits/playbook/pb_form/docs/_form_default_values.jsx +898 -0
  74. data/app/pb_kits/playbook/pb_form/docs/_form_default_values_react.md +3 -0
  75. data/app/pb_kits/playbook/pb_form/docs/_form_defaults.jsx +879 -0
  76. data/app/pb_kits/playbook/pb_form/docs/_form_defaults_react.md +29 -0
  77. data/app/pb_kits/playbook/pb_form/docs/_form_loading.jsx +75 -0
  78. data/app/pb_kits/playbook/pb_form/docs/{_form_loading.md → _form_loading_rails.md} +1 -0
  79. data/app/pb_kits/playbook/pb_form/docs/_form_loading_react.md +1 -0
  80. data/app/pb_kits/playbook/pb_form/docs/_form_model_values.jsx +147 -0
  81. data/app/pb_kits/playbook/pb_form/docs/_form_model_values_react.md +16 -0
  82. data/app/pb_kits/playbook/pb_form/docs/_form_multi_column.jsx +164 -0
  83. data/app/pb_kits/playbook/pb_form/docs/_form_multi_column_react.md +3 -0
  84. data/app/pb_kits/playbook/pb_form/docs/_form_validation.jsx +1057 -0
  85. data/app/pb_kits/playbook/pb_form/docs/_form_validation_react.md +26 -0
  86. data/app/pb_kits/playbook/pb_form/docs/example.yml +7 -0
  87. data/app/pb_kits/playbook/pb_form/pb_form_validation.js +1 -0
  88. data/app/pb_kits/playbook/pb_form_group/_form_group.scss +1 -4
  89. data/app/pb_kits/playbook/pb_full_screen/_full_screen.scss +6 -0
  90. data/app/pb_kits/playbook/pb_full_screen/_full_screen.tsx +11 -2
  91. data/app/pb_kits/playbook/pb_full_screen/docs/_full_screen_advanced_table_sticky_header.jsx +73 -0
  92. data/app/pb_kits/playbook/pb_full_screen/docs/_full_screen_advanced_table_sticky_header.md +1 -0
  93. data/app/pb_kits/playbook/pb_full_screen/docs/example.yml +1 -0
  94. data/app/pb_kits/playbook/pb_full_screen/docs/index.js +1 -0
  95. data/app/pb_kits/playbook/pb_full_screen/full_screen.test.jsx +4 -2
  96. data/app/pb_kits/playbook/pb_image/_image.tsx +3 -1
  97. data/app/pb_kits/playbook/pb_image/kit.schema.json +1 -0
  98. data/app/pb_kits/playbook/pb_label_pill/_label_pill.tsx +3 -1
  99. data/app/pb_kits/playbook/pb_label_pill/kit.schema.json +1 -0
  100. data/app/pb_kits/playbook/pb_legend/_legend.tsx +3 -1
  101. data/app/pb_kits/playbook/pb_legend/kit.schema.json +1 -0
  102. data/app/pb_kits/playbook/pb_list/_list_item.tsx +6 -3
  103. data/app/pb_kits/playbook/pb_map/docs/_map_default.md +22 -3
  104. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +4 -1
  105. data/app/pb_kits/playbook/pb_online_status/_online_status.tsx +3 -1
  106. data/app/pb_kits/playbook/pb_online_status/kit.schema.json +1 -0
  107. data/app/pb_kits/playbook/pb_pb_bar_graph/pbbargraph.test.jsx +1 -2
  108. data/app/pb_kits/playbook/pb_pb_circle_chart/pb_circle_chart.test.jsx +1 -2
  109. data/app/pb_kits/playbook/pb_pb_gauge_chart/pb_gauge_chart.test.jsx +1 -2
  110. data/app/pb_kits/playbook/pb_pb_line_graph/pb_line_graph.test.jsx +1 -2
  111. data/app/pb_kits/playbook/pb_person/_person.tsx +3 -1
  112. data/app/pb_kits/playbook/pb_person/kit.schema.json +1 -0
  113. data/app/pb_kits/playbook/pb_pill/_pill.tsx +3 -1
  114. data/app/pb_kits/playbook/pb_pill/kit.schema.json +1 -0
  115. data/app/pb_kits/playbook/pb_progress_step/_progress_step_item.tsx +3 -1
  116. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.json +1 -1
  117. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.overrides.json +1 -1
  118. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_required_indicator.md +2 -2
  119. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_default.md +3 -4
  120. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_extensions.md +1 -1
  121. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_markdown_support.md +1 -1
  122. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_required_indicator.html.erb +9 -0
  123. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_required_indicator.md +3 -0
  124. data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +1 -0
  125. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.html.erb +3 -7
  126. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_rails.js +26 -21
  127. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_rails.test.js +85 -1
  128. data/app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.scss +0 -9
  129. data/app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_custom.jsx +1 -1
  130. data/app/pb_kits/playbook/pb_selectable_icon/_selectable_icon.scss +0 -7
  131. data/app/pb_kits/playbook/pb_source/_source.tsx +3 -1
  132. data/app/pb_kits/playbook/pb_source/kit.schema.json +1 -0
  133. data/app/pb_kits/playbook/pb_source/source.rb +1 -1
  134. data/app/pb_kits/playbook/pb_stat_change/_stat_change.tsx +3 -1
  135. data/app/pb_kits/playbook/pb_stat_change/kit.schema.json +1 -0
  136. data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +4 -1
  137. data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.tsx +3 -1
  138. data/app/pb_kits/playbook/pb_time_range_inline/kit.schema.json +1 -0
  139. data/app/pb_kits/playbook/pb_time_stacked/_time_stacked.tsx +3 -1
  140. data/app/pb_kits/playbook/pb_time_stacked/kit.schema.json +1 -0
  141. data/app/pb_kits/playbook/pb_timeline/_item.tsx +3 -1
  142. data/app/pb_kits/playbook/pb_timestamp/_timestamp.tsx +3 -1
  143. data/app/pb_kits/playbook/pb_timestamp/kit.schema.json +1 -0
  144. data/app/pb_kits/playbook/pb_timestamp/timestamp.test.js +1 -0
  145. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +73 -0
  146. data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +285 -12
  147. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +22 -14
  148. data/app/pb_kits/playbook/pb_typeahead/components/PillRenderer.tsx +15 -11
  149. data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +29 -30
  150. data/app/pb_kits/playbook/pb_typeahead/components/usePillDropIndicator.ts +155 -0
  151. data/app/pb_kits/playbook/pb_typeahead/docs/_playground.json +5 -5
  152. data/app/pb_kits/playbook/pb_typeahead/docs/_playground.overrides.json +2 -2
  153. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills.html.erb +0 -1
  154. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills.jsx +0 -1
  155. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills_rails.md +3 -3
  156. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills_react.md +7 -0
  157. data/app/pb_kits/playbook/pb_typeahead/kit.schema.json +3 -3
  158. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -3
  159. data/app/pb_kits/playbook/pb_user/_user.tsx +3 -1
  160. data/app/pb_kits/playbook/pb_user/kit.schema.json +1 -0
  161. data/app/pb_kits/playbook/pb_user_badge/_user_badge.tsx +3 -1
  162. data/app/pb_kits/playbook/pb_user_badge/kit.schema.json +1 -0
  163. data/app/pb_kits/playbook/pb_weekday_stacked/_weekday_stacked.tsx +3 -1
  164. data/app/pb_kits/playbook/pb_weekday_stacked/kit.schema.json +1 -0
  165. data/app/pb_kits/playbook/pb_weekday_stacked/weekday_stacked.test.jsx +1 -0
  166. data/app/pb_kits/playbook/utilities/test/globalProps/onClick.test.js +302 -0
  167. data/app/pb_kits/playbook/utilities/test-utils.js +0 -1
  168. data/dist/ai/all-schemas.json +108 -15
  169. data/dist/ai/external-dependencies.json +1 -1
  170. data/dist/ai/forms.json +2 -2
  171. data/dist/ai/index.json +3 -3
  172. data/dist/ai/kits/avatar.schema.json +1 -0
  173. data/dist/ai/kits/contact.schema.json +1 -0
  174. data/dist/ai/kits/date.schema.json +1 -0
  175. data/dist/ai/kits/date_range_inline.schema.json +1 -0
  176. data/dist/ai/kits/date_range_stacked.schema.json +1 -0
  177. data/dist/ai/kits/date_stacked.schema.json +1 -0
  178. data/dist/ai/kits/date_time.schema.json +1 -0
  179. data/dist/ai/kits/date_time_stacked.schema.json +1 -0
  180. data/dist/ai/kits/date_year_stacked.schema.json +1 -0
  181. data/dist/ai/kits/dropdown.schema.json +81 -11
  182. data/dist/ai/kits/image.schema.json +1 -0
  183. data/dist/ai/kits/label_pill.schema.json +1 -0
  184. data/dist/ai/kits/legend.schema.json +1 -0
  185. data/dist/ai/kits/online_status.schema.json +1 -0
  186. data/dist/ai/kits/person.schema.json +1 -0
  187. data/dist/ai/kits/pill.schema.json +1 -0
  188. data/dist/ai/kits/rich_text_editor.schema.json +1 -1
  189. data/dist/ai/kits/source.schema.json +1 -0
  190. data/dist/ai/kits/stat_change.schema.json +1 -0
  191. data/dist/ai/kits/time_range_inline.schema.json +1 -0
  192. data/dist/ai/kits/time_stacked.schema.json +1 -0
  193. data/dist/ai/kits/timestamp.schema.json +1 -0
  194. data/dist/ai/kits/typeahead.schema.json +3 -3
  195. data/dist/ai/kits/user.schema.json +1 -0
  196. data/dist/ai/kits/user_badge.schema.json +1 -0
  197. data/dist/ai/kits/weekday_stacked.schema.json +1 -0
  198. data/dist/ai/playgrounds/dropdown.json +1 -1
  199. data/dist/ai/playgrounds/index.json +1 -1
  200. data/dist/ai/playgrounds/rich_text_editor.json +1 -1
  201. data/dist/ai/playgrounds/typeahead.json +1 -1
  202. data/dist/chunks/_pagination-CARbC_IN.js +1 -0
  203. data/dist/chunks/{_pb_line_graph-Du7xE9vl.js → _pb_line_graph-BKwbOeqo.js} +1 -1
  204. data/dist/chunks/{_detail-Bsvl694i.js → _tooltip-UkcgcThO.js} +2 -2
  205. data/dist/chunks/_typeahead-D_li2Zx8.js +1 -0
  206. data/dist/chunks/{globalProps-B120NbSJ.js → globalProps-BivjwRew.js} +1 -1
  207. data/dist/chunks/index-4jrZjexD.js +1 -0
  208. data/dist/chunks/index-BAy61y8S.js +1 -0
  209. data/dist/chunks/index-Cb_SDipk.js +1 -0
  210. data/dist/chunks/index-D3RdsDp7.js +1 -0
  211. data/dist/chunks/index-D8PZIesy.js +1 -0
  212. data/dist/chunks/index-DIoc-aua.js +1 -0
  213. data/dist/chunks/index-qex65UMn.js +1 -0
  214. data/dist/chunks/lib-C50eCpoN.js +29 -0
  215. data/dist/chunks/{time_picker_helper-CYGg0UQ0.js → time_picker_helper-DfKvHCJu.js} +1 -1
  216. data/dist/chunks/vendor.js +2 -2
  217. data/dist/menu.yml +1 -1
  218. data/dist/playbook-rails-react-bindings.js +1 -1
  219. data/dist/playbook-rails.js +1 -1
  220. data/dist/playbook.css +1 -1
  221. data/lib/playbook/version.rb +2 -2
  222. metadata +80 -21
  223. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_draggable_pills.md +0 -7
  224. data/dist/chunks/_table-Bf6LGyL9.js +0 -1
  225. data/dist/chunks/_typeahead-w6S5Vx4b.js +0 -1
  226. data/dist/chunks/lib-Buo6zHEw.js +0 -29
  227. /data/app/pb_kits/playbook/pb_form/docs/{_description.md → _description_rails.md} +0 -0
  228. /data/app/pb_kits/playbook/pb_form/docs/{_form_default_values.md → _form_default_values_rails.md} +0 -0
  229. /data/app/pb_kits/playbook/pb_form/docs/{_form_defaults.md → _form_defaults_rails.md} +0 -0
  230. /data/app/pb_kits/playbook/pb_form/docs/{_form_model_values.md → _form_model_values_rails.md} +0 -0
  231. /data/app/pb_kits/playbook/pb_form/docs/{_form_multi_column.md → _form_multi_column_rails.md} +0 -0
  232. /data/app/pb_kits/playbook/pb_form/docs/{_form_validation.md → _form_validation_rails.md} +0 -0
@@ -198,7 +198,11 @@
198
198
  "closeOnClick",
199
199
  "constrainHeight",
200
200
  "isClosed",
201
- "requiredIndicator"
201
+ "enableFormSupport",
202
+ "requiredIndicator",
203
+ "required",
204
+ "validationMessage",
205
+ "allowOptionCreation"
202
206
  ]
203
207
  },
204
208
  {
@@ -215,6 +219,9 @@
215
219
  "props": [
216
220
  "separators",
217
221
  "formPillProps",
222
+ "enablePillReorder",
223
+ "externalDragHandle",
224
+ "showPillIndex",
218
225
  "activeStyle",
219
226
  "dark",
220
227
  "disabled"
@@ -226,6 +233,7 @@
226
233
  }
227
234
  ],
228
235
  "presets": [
236
+ { "name": "Create tags", "props": { "allowOptionCreation": true, "multiSelect": true, "name": "tags[]", "label": "Tags" } },
229
237
  {
230
238
  "name": "Async search",
231
239
  "structureMode": "async",
@@ -381,6 +389,9 @@
381
389
  "searchbar": { "structureMode": "async" },
382
390
  "requiredIndicator": { "requires": "label" },
383
391
  "formPillProps": { "requires": "multiSelect" },
392
+ "enablePillReorder": { "requires": "multiSelect" },
393
+ "externalDragHandle": { "requires": "enablePillReorder" },
394
+ "showPillIndex": { "requires": "multiSelect" },
384
395
  "rangeEndsToday": { "requires": { "variant": "quickpick" } },
385
396
  "controlsStartId": { "requires": { "variant": "quickpick" } },
386
397
  "controlsEndId": { "requires": { "variant": "quickpick" } },
@@ -411,7 +422,7 @@
411
422
  },
412
423
  "multi_options": {
413
424
  "when": { "multiSelect": true },
414
- "message": "Multi-select returns arrays of selected options. Use formPillProps to adjust the selected-pill appearance and clearable to let users reset the selection.",
425
+ "message": "Multi-select returns arrays of selected options. Use formPillProps to adjust the selected-pill appearance and clearable to let users reset the selection. Opt into enablePillReorder to drag pills into a new priority order.",
415
426
  "type": "info"
416
427
  },
417
428
  "autocomplete_info": {
@@ -47,6 +47,8 @@ examples:
47
47
  - dropdown_async_search: Async Search
48
48
  - dropdown_async_multi_select_rails: Async Multi Select
49
49
  - dropdown_async_custom_content: Async Search with Custom Content
50
+ - dropdown_option_creation: Allow Option Creation
51
+ - dropdown_draggable_pills: Draggable Pills
50
52
 
51
53
  react:
52
54
  - dropdown_default: Default
@@ -100,4 +102,7 @@ examples:
100
102
  - dropdown_async_rich_results: Async Search with Custom Content
101
103
  - dropdown_async_initial_options: Async Initial Results and Caching
102
104
  - dropdown_external_search: External Search
105
+ - dropdown_option_creation: Allow Option Creation
106
+ - dropdown_draggable_pills: Draggable Pills
107
+ - dropdown_form: Enable Form Support
103
108
 
@@ -47,5 +47,8 @@ export { default as DropdownAsyncMultiSelect } from './_dropdown_async_multi_sel
47
47
  export { default as DropdownAsyncRichResults } from './_dropdown_async_rich_results.jsx'
48
48
  export { default as DropdownAsyncInitialOptions } from './_dropdown_async_initial_options.jsx'
49
49
  export { default as DropdownExternalSearch } from './_dropdown_external_search.jsx'
50
+ export { default as DropdownForm } from "./_dropdown_form.jsx"
51
+ export { default as DropdownOptionCreation } from "./_dropdown_option_creation.jsx"
50
52
  export { default as DropdownQuickpickEnableTime } from './_dropdown_quickpick_enable_time.jsx'
51
- export { default as DropdownWithHighlight } from './_dropdown_with_highlight.jsx'
53
+ export { default as DropdownWithHighlight } from './_dropdown_with_highlight.jsx'
54
+ export { default as DropdownDraggablePills } from './_dropdown_draggable_pills.jsx'
@@ -19,7 +19,7 @@
19
19
  data-message="<%= object.validation_message %>"
20
20
  <% end %>
21
21
  data-dropdown-selected-option
22
- name="<%= object.name %><%= '[]' if object.multi_select %>"
22
+ name="<%= object.input_name %>"
23
23
  style="display: none"
24
24
  <%= object.disabled ? "disabled" : ""%>
25
25
  <%= object.required ? "required" : ""%>
@@ -34,7 +34,7 @@
34
34
  <%= pb_rails("body", props: { status: "negative", text: object.error, id: object.error_id, aria: { atomic: "true", live: "polite" }, html_options: { role: "alert" }, dark: object.dark }) %>
35
35
  <% end %>
36
36
  <% else %>
37
- <%= pb_rails("dropdown/dropdown_trigger", props: { autocomplete: object.autocomplete, disabled: object.disabled, multi_select: object.multi_select, placeholder: object.placeholder, select_id: object.select_id, label: object.label, error_id: object.error_id, error: object.error }) %>
37
+ <%= pb_rails("dropdown/dropdown_trigger", props: { autocomplete: object.autocomplete_enabled?, disabled: object.disabled, multi_select: object.multi_select, placeholder: object.placeholder, select_id: object.select_id, label: object.label, error_id: object.error_id, error: object.error }) %>
38
38
  <%= pb_rails("dropdown/dropdown_container", props: { searchbar: object.searchbar, constrain_height: object.constrain_height, disabled: object.disabled, no_options_text: object.no_options_text }) do %>
39
39
  <% if options_with_blank.present? %>
40
40
  <% options_with_blank.each do |option| %>
@@ -29,6 +29,8 @@ module Playbook
29
29
  default: true
30
30
  prop :autocomplete, type: Playbook::Props::Boolean,
31
31
  default: false
32
+ prop :allow_option_creation, type: Playbook::Props::Boolean,
33
+ default: false
32
34
  prop :async, type: Playbook::Props::Boolean, default: false
33
35
  prop :active_style, type: Playbook::Props::HashProp,
34
36
  default: {}
@@ -75,11 +77,18 @@ module Playbook
75
77
  default: true
76
78
  prop :options_event_type, type: Playbook::Props::String,
77
79
  default: ""
80
+ prop :enable_pill_reorder, type: Playbook::Props::Boolean,
81
+ default: false
82
+ prop :external_drag_handle, type: Playbook::Props::Boolean,
83
+ default: false
84
+ prop :show_pill_index, type: Playbook::Props::Boolean,
85
+ default: false
78
86
 
79
87
  def data
80
88
  Hash(prop(:data)).merge(
81
89
  pb_dropdown: true,
82
90
  pb_dropdown_async: async ? true : nil,
91
+ pb_dropdown_allow_option_creation: allow_option_creation && variant != "quickpick" ? true : nil,
83
92
  pb_dropdown_active_style: active_style.present? ? active_style.to_json : nil,
84
93
  pb_dropdown_default_value: async && default_value.present? ? default_value.to_json : nil,
85
94
  pb_dropdown_search_term_minimum_length: async ? search_term_minimum_length : nil,
@@ -99,7 +108,10 @@ module Playbook
99
108
  pb_dropdown_options_by_context: options_by_context.present? ? options_by_context.to_json : nil,
100
109
  pb_dropdown_context_selector: context_selector.presence,
101
110
  pb_dropdown_clear_on_context_change: clear_on_context_change,
102
- options_event_type: options_event_type.presence
111
+ options_event_type: options_event_type.presence,
112
+ pb_dropdown_enable_pill_reorder: multi_select && enable_pill_reorder ? true : nil,
113
+ pb_dropdown_external_drag_handle: multi_select && enable_pill_reorder && external_drag_handle ? true : nil,
114
+ pb_dropdown_show_pill_index: multi_select && show_pill_index ? true : nil
103
115
  ).compact
104
116
  end
105
117
 
@@ -113,6 +125,17 @@ module Playbook
113
125
  id.presence || (label.present? ? label.downcase.gsub(/\s+/, "_").gsub(/[^a-z0-9_]/, "") : nil)
114
126
  end
115
127
 
128
+ def autocomplete_enabled?
129
+ autocomplete || (allow_option_creation && variant != "quickpick")
130
+ end
131
+
132
+ def input_name
133
+ return name unless multi_select
134
+ return name if name.present? && name.end_with?("[]")
135
+
136
+ "#{name}[]"
137
+ end
138
+
116
139
  def error_id
117
140
  error.present? ? "#{select_id || 'dropdown_trigger'}-error" : nil
118
141
  end
@@ -903,11 +903,12 @@ describe("quickpick Last Month range when current month is shorter than the prev
903
903
  }
904
904
 
905
905
  beforeEach(() => {
906
+ jest.useFakeTimers()
906
907
  jest.setSystemTime(new Date(2026, 3, 15, 12, 0, 0))
907
908
  })
908
909
 
909
910
  afterEach(() => {
910
- jest.setSystemTime()
911
+ jest.useRealTimers()
911
912
  })
912
913
 
913
914
  test("selecting Last Month matches DateTime previous-month range (full March when today is in April)", async () => {
@@ -2387,6 +2388,45 @@ describe('async Dropdown empty menu', () => {
2387
2388
  });
2388
2389
 
2389
2390
 
2391
+ describe('autocomplete query after selection', () => {
2392
+ test.each([undefined, false])('plain uncontrolled autocomplete clears with allowOptionCreation=%s', (allowOptionCreation) => {
2393
+ const onSelect = jest.fn();
2394
+ render(<Dropdown allowOptionCreation={allowOptionCreation}
2395
+ autocomplete
2396
+ onSelect={onSelect}
2397
+ options={options}
2398
+ />);
2399
+ const input = screen.getByRole('textbox');
2400
+ fireEvent.click(input);
2401
+ fireEvent.change(input, { target: { value: 'Can' } });
2402
+ fireEvent.click(screen.getByText('Canada'));
2403
+
2404
+ expect(input).toHaveValue('');
2405
+ expect(onSelect).toHaveBeenCalledWith(options[1]);
2406
+ });
2407
+
2408
+ test.each(['creation', 'async', 'controlled'])('%s autocomplete retains the selected label', (mode) => {
2409
+ const Example = () => {
2410
+ const [value, setValue] = useState(null);
2411
+ return (
2412
+ <Dropdown allowOptionCreation={mode === 'creation'}
2413
+ async={mode === 'async'}
2414
+ autocomplete
2415
+ onSelect={setValue}
2416
+ options={options}
2417
+ {...(mode === 'controlled' ? { value } : {})}
2418
+ />
2419
+ );
2420
+ };
2421
+ render(<Example />);
2422
+ const input = screen.getByRole('textbox');
2423
+ fireEvent.click(input);
2424
+ fireEvent.change(input, { target: { value: 'Can' } });
2425
+ fireEvent.click(screen.getByText('Canada'));
2426
+ expect(input).toHaveValue('Canada');
2427
+ });
2428
+ });
2429
+
2390
2430
  describe('autocomplete selection replacement', () => {
2391
2431
  beforeEach(() => jest.useFakeTimers());
2392
2432
  afterEach(() => { jest.clearAllTimers(); jest.useRealTimers(); });
@@ -2543,3 +2583,197 @@ describe('autocomplete selection replacement', () => {
2543
2583
  expect(onSelect).not.toHaveBeenCalled();
2544
2584
  });
2545
2585
  });
2586
+
2587
+ describe("enablePillReorder", () => {
2588
+ test("false does not render drag handles or draggable items", () => {
2589
+ render(
2590
+ <Dropdown
2591
+ data={{ testid: testId }}
2592
+ defaultValue={[options[0], options[1]]}
2593
+ enablePillReorder={false}
2594
+ multiSelect
2595
+ options={options}
2596
+ />
2597
+ )
2598
+
2599
+ const kit = screen.getByTestId(testId)
2600
+ expect(kit.querySelector(".pb_dropdown_external_drag_handle")).not.toBeInTheDocument()
2601
+ expect(kit.querySelector(".pb_draggable_item")).not.toBeInTheDocument()
2602
+ })
2603
+
2604
+ test("renders in-pill grip icons and numbered pills", () => {
2605
+ render(
2606
+ <Dropdown
2607
+ data={{ testid: testId }}
2608
+ defaultValue={[options[0], options[1], options[2]]}
2609
+ enablePillReorder
2610
+ multiSelect
2611
+ options={options}
2612
+ showPillIndex
2613
+ />
2614
+ )
2615
+
2616
+ const kit = screen.getByTestId(testId)
2617
+ const pills = kit.querySelectorAll(".pb_form_pill_kit_icon.pb_form_pill_primary")
2618
+
2619
+ expect(kit.querySelector(".pb_dropdown_external_drag_handle")).not.toBeInTheDocument()
2620
+ expect(kit.querySelectorAll(".pb_form_pill_kit_icon .pb_form_pill_icon").length).toBe(3)
2621
+ expect(pills.length).toBe(3)
2622
+ expect(pills[0]).toHaveTextContent("1. United States")
2623
+ expect(pills[1]).toHaveTextContent("2. Canada")
2624
+ expect(pills[2]).toHaveTextContent("3. Pakistan")
2625
+ })
2626
+
2627
+ test("keyboard reorder moves pill position", () => {
2628
+ const handleChange = jest.fn()
2629
+
2630
+ render(
2631
+ <Dropdown
2632
+ data={{ testid: testId }}
2633
+ enablePillReorder
2634
+ multiSelect
2635
+ onChange={handleChange}
2636
+ options={options}
2637
+ showPillIndex
2638
+ value={[options[0], options[1], options[2]]}
2639
+ />
2640
+ )
2641
+
2642
+ const kit = screen.getByTestId(testId)
2643
+ const pills = kit.querySelectorAll(".pb_form_pill_kit_icon.pb_form_pill_primary")
2644
+
2645
+ pills[1].focus()
2646
+ fireEvent.keyDown(pills[1], { key: "ArrowLeft" })
2647
+
2648
+ expect(handleChange).toHaveBeenCalled()
2649
+ const reorderedValue = handleChange.mock.calls[0][0].target.value
2650
+ expect(reorderedValue[0].label).toBe("Canada")
2651
+ expect(reorderedValue[1].label).toBe("United States")
2652
+ })
2653
+
2654
+ test("remove still works when enablePillReorder is true", () => {
2655
+ const handleChange = jest.fn()
2656
+
2657
+ render(
2658
+ <Dropdown
2659
+ data={{ testid: testId }}
2660
+ enablePillReorder
2661
+ multiSelect
2662
+ onChange={handleChange}
2663
+ options={options}
2664
+ value={[options[0], options[1]]}
2665
+ />
2666
+ )
2667
+
2668
+ const kit = screen.getByTestId(testId)
2669
+ const removeButton = kit.querySelector(".pb_form_pill_close")
2670
+
2671
+ fireEvent.click(removeButton)
2672
+
2673
+ expect(handleChange).toHaveBeenCalled()
2674
+ expect(handleChange.mock.calls[0][0].target.value.length).toBe(1)
2675
+ })
2676
+
2677
+ test("externalDragHandle true renders external grip handles", () => {
2678
+ render(
2679
+ <Dropdown
2680
+ data={{ testid: testId }}
2681
+ enablePillReorder
2682
+ externalDragHandle
2683
+ multiSelect
2684
+ options={options}
2685
+ value={[options[0], options[1]]}
2686
+ />
2687
+ )
2688
+
2689
+ const kit = screen.getByTestId(testId)
2690
+ expect(kit.querySelectorAll(".pb_dropdown_external_drag_handle").length).toBe(2)
2691
+ expect(kit.querySelectorAll(".pb_form_pill_kit_icon .pb_form_pill_icon").length).toBe(0)
2692
+ })
2693
+
2694
+ test("dragging a pill shows a ghost and drop line, then commits on drop", () => {
2695
+ const handleChange = jest.fn()
2696
+ const originalElementFromPoint = document.elementFromPoint
2697
+
2698
+ render(
2699
+ <Dropdown
2700
+ data={{ testid: testId }}
2701
+ enablePillReorder
2702
+ multiSelect
2703
+ onChange={handleChange}
2704
+ options={options}
2705
+ value={[options[0], options[1], options[2]]}
2706
+ />
2707
+ )
2708
+
2709
+ const kit = screen.getByTestId(testId)
2710
+ const draggableItems = kit.querySelectorAll(".pb_draggable_item")
2711
+ draggableItems.forEach((item, index) => {
2712
+ item.getBoundingClientRect = () => ({
2713
+ left: index * 100,
2714
+ right: index * 100 + 100,
2715
+ width: 100,
2716
+ top: 0,
2717
+ bottom: 30,
2718
+ height: 30,
2719
+ })
2720
+ })
2721
+ document.elementFromPoint = (x) => (
2722
+ draggableItems[Math.min(Math.floor(x / 100), draggableItems.length - 1)] || null
2723
+ )
2724
+
2725
+ fireEvent.mouseDown(draggableItems[0], { button: 0, clientX: 10, clientY: 10 })
2726
+ fireEvent.mouseMove(document, { clientX: 30, clientY: 10 })
2727
+ fireEvent.mouseMove(document, { clientX: 280, clientY: 10 })
2728
+
2729
+ expect(document.querySelector(".pb_dropdown_pill_drag_preview")).toBeInTheDocument()
2730
+ expect(draggableItems[2]).toHaveClass("pb_dropdown_drop_after")
2731
+
2732
+ fireEvent.mouseUp(document, { clientX: 280, clientY: 10 })
2733
+
2734
+ expect(document.querySelector(".pb_dropdown_pill_drag_preview")).not.toBeInTheDocument()
2735
+ expect(handleChange).toHaveBeenCalled()
2736
+ expect(handleChange.mock.calls[0][0].target.value.map((item) => item.label)).toEqual([
2737
+ "Canada",
2738
+ "Pakistan",
2739
+ "United States",
2740
+ ])
2741
+
2742
+ document.elementFromPoint = originalElementFromPoint
2743
+ })
2744
+
2745
+ test("single-select is unaffected by enablePillReorder", () => {
2746
+ render(
2747
+ <Dropdown
2748
+ data={{ testid: testId }}
2749
+ defaultValue={options[0]}
2750
+ enablePillReorder
2751
+ options={options}
2752
+ showPillIndex
2753
+ />
2754
+ )
2755
+
2756
+ const kit = screen.getByTestId(testId)
2757
+ expect(kit.querySelector(".pb_draggable_item")).not.toBeInTheDocument()
2758
+ expect(kit.querySelector(".pb_form_pill_kit")).not.toBeInTheDocument()
2759
+ })
2760
+
2761
+ test("works with multiSelect and autocomplete", () => {
2762
+ render(
2763
+ <Dropdown
2764
+ autocomplete
2765
+ data={{ testid: testId }}
2766
+ enablePillReorder
2767
+ multiSelect
2768
+ options={options}
2769
+ showPillIndex
2770
+ value={[options[0], options[1]]}
2771
+ />
2772
+ )
2773
+
2774
+ const kit = screen.getByTestId(testId)
2775
+ expect(kit.querySelector(".dropdown_input")).toBeInTheDocument()
2776
+ expect(kit.querySelectorAll(".pb_draggable_item").length).toBe(2)
2777
+ expect(kit.querySelectorAll(".pb_form_pill_kit_icon")[0]).toHaveTextContent("1. United States")
2778
+ })
2779
+ })