playbook_ui 18.1.0 → 18.2.0.pre.alpha.PLAY3330requiredtypeaheadvalidationbug20501

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 (259) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +1 -4
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +9 -5
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TablePagination.tsx +28 -6
  5. data/app/pb_kits/playbook/pb_advanced_table/Components/VirtualizedTableView.tsx +6 -1
  6. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +26 -9
  7. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +2 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +137 -1
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination_section_separator.jsx +90 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination_section_separator.md +5 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pagination_with_props.md +2 -1
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +1 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +1 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +4 -4
  15. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +8 -3
  16. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +19 -6
  17. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +1 -1
  18. data/app/pb_kits/playbook/pb_background/_background.tsx +3 -1
  19. data/app/pb_kits/playbook/pb_background/kit.schema.json +1 -0
  20. data/app/pb_kits/playbook/pb_caption/_caption.tsx +3 -1
  21. data/app/pb_kits/playbook/pb_caption/kit.schema.json +1 -0
  22. data/app/pb_kits/playbook/pb_container/_container.tsx +3 -1
  23. data/app/pb_kits/playbook/pb_container/kit.schema.json +1 -0
  24. data/app/pb_kits/playbook/pb_currency/_currency.tsx +3 -1
  25. data/app/pb_kits/playbook/pb_currency/kit.schema.json +1 -0
  26. data/app/pb_kits/playbook/pb_dashboard_value/_dashboard_value.tsx +3 -1
  27. data/app/pb_kits/playbook/pb_dashboard_value/kit.schema.json +1 -0
  28. data/app/pb_kits/playbook/pb_date_picker/_date_picker.scss +4 -0
  29. data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +51 -49
  30. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +56 -56
  31. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_calendar_input_icon.scss +1 -1
  32. data/app/pb_kits/playbook/pb_detail/_detail.tsx +3 -1
  33. data/app/pb_kits/playbook/pb_detail/kit.schema.json +1 -0
  34. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +16 -0
  35. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +190 -29
  36. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_custom_content.html.erb +58 -0
  37. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_custom_content.md +10 -0
  38. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_initial_options.jsx +45 -0
  39. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_initial_options.md +9 -0
  40. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_loading.jsx +43 -0
  41. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_loading.md +9 -0
  42. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_multi_select.jsx +44 -0
  43. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_multi_select.md +5 -0
  44. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_multi_select_rails.html.erb +44 -0
  45. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_multi_select_rails.md +5 -0
  46. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_rich_results.jsx +64 -0
  47. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_rich_results.md +5 -0
  48. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_search.html.erb +43 -0
  49. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_async_search.md +55 -0
  50. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_controlled_selection.jsx +42 -0
  51. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_controlled_selection.md +5 -0
  52. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_external_search.jsx +58 -0
  53. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_external_search.md +9 -0
  54. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_no_options_text.html.erb +9 -0
  55. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_no_options_text.jsx +35 -0
  56. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_no_options_text_rails.md +3 -0
  57. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_no_options_text_react.md +3 -0
  58. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_custom.md +7 -2
  59. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_custom_rails.md +7 -2
  60. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_enable_time.html.erb +33 -0
  61. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_enable_time.jsx +42 -0
  62. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_quickpick_enable_time.md +24 -0
  63. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_highlight.jsx +101 -0
  64. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_highlight.md +3 -0
  65. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.json +174 -3
  66. data/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json +154 -2
  67. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +14 -0
  68. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +9 -0
  69. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +4 -1
  70. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +14 -0
  71. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +1344 -0
  72. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.html.erb +1 -1
  73. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.rb +1 -0
  74. data/app/pb_kits/playbook/pb_dropdown/dropdown_index.test.js +1153 -0
  75. data/app/pb_kits/playbook/pb_dropdown/hooks/useAsyncOptions.ts +179 -0
  76. data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +21 -19
  77. data/app/pb_kits/playbook/pb_dropdown/index.js +518 -79
  78. data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +5 -3
  79. data/app/pb_kits/playbook/pb_dropdown/kit.schema.json +78 -1
  80. data/app/pb_kits/playbook/pb_dropdown/quickpick/index.ts +60 -18
  81. data/app/pb_kits/playbook/pb_dropdown/quickpick_helper.rb +92 -3
  82. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +17 -3
  83. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +21 -7
  84. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +5 -2
  85. data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +9 -3
  86. data/app/pb_kits/playbook/pb_dropdown/utilities/index.ts +8 -1
  87. data/app/pb_kits/playbook/pb_dropdown/utilities/quickpickDateSync.ts +137 -0
  88. data/app/pb_kits/playbook/pb_filter/Filter/InteractiveFilter.tsx +1 -1
  89. data/app/pb_kits/playbook/pb_form/docs/_description_react.md +3 -0
  90. data/app/pb_kits/playbook/pb_form/docs/_form_default_values.jsx +898 -0
  91. data/app/pb_kits/playbook/pb_form/docs/_form_default_values_react.md +3 -0
  92. data/app/pb_kits/playbook/pb_form/docs/_form_defaults.jsx +879 -0
  93. data/app/pb_kits/playbook/pb_form/docs/_form_defaults_react.md +29 -0
  94. data/app/pb_kits/playbook/pb_form/docs/_form_loading.jsx +75 -0
  95. data/app/pb_kits/playbook/pb_form/docs/{_form_loading.md → _form_loading_rails.md} +1 -0
  96. data/app/pb_kits/playbook/pb_form/docs/_form_loading_react.md +1 -0
  97. data/app/pb_kits/playbook/pb_form/docs/_form_model_values.jsx +147 -0
  98. data/app/pb_kits/playbook/pb_form/docs/_form_model_values_react.md +16 -0
  99. data/app/pb_kits/playbook/pb_form/docs/_form_multi_column.jsx +164 -0
  100. data/app/pb_kits/playbook/pb_form/docs/_form_multi_column_react.md +3 -0
  101. data/app/pb_kits/playbook/pb_form/docs/_form_validation.html.erb +27 -4
  102. data/app/pb_kits/playbook/pb_form/docs/_form_validation.jsx +1057 -0
  103. data/app/pb_kits/playbook/pb_form/docs/{_form_validation.md → _form_validation_rails.md} +4 -4
  104. data/app/pb_kits/playbook/pb_form/docs/_form_validation_react.md +26 -0
  105. data/app/pb_kits/playbook/pb_form/docs/example.yml +7 -0
  106. data/app/pb_kits/playbook/pb_form/docs/snippets/validation_checkbox.txt +6 -1
  107. data/app/pb_kits/playbook/pb_form/docs/snippets/validation_dropdown.txt +6 -1
  108. data/app/pb_kits/playbook/pb_form/docs/snippets/validation_multi_level_select.txt +1 -0
  109. data/app/pb_kits/playbook/pb_form/docs/snippets/validation_multi_select.txt +1 -0
  110. data/app/pb_kits/playbook/pb_form/docs/snippets/validation_phone_number.txt +1 -0
  111. data/app/pb_kits/playbook/pb_form/docs/snippets/validation_star_rating.txt +6 -1
  112. data/app/pb_kits/playbook/pb_form/docs/snippets/validation_textarea.txt +5 -1
  113. data/app/pb_kits/playbook/pb_form/docs/snippets/validation_time_zone_select.txt +1 -0
  114. data/app/pb_kits/playbook/pb_form/pb_form_validation.js +52 -34
  115. data/app/pb_kits/playbook/pb_full_screen/_full_screen.scss +6 -1
  116. data/app/pb_kits/playbook/pb_full_screen/full_screen.test.jsx +19 -7
  117. data/app/pb_kits/playbook/pb_highlight/_highlight.tsx +3 -1
  118. data/app/pb_kits/playbook/pb_highlight/kit.schema.json +1 -0
  119. data/app/pb_kits/playbook/pb_icon_stat_value/_icon_stat_value.tsx +3 -1
  120. data/app/pb_kits/playbook/pb_icon_stat_value/kit.schema.json +1 -0
  121. data/app/pb_kits/playbook/pb_icon_value/_icon_value.tsx +3 -1
  122. data/app/pb_kits/playbook/pb_icon_value/kit.schema.json +1 -0
  123. data/app/pb_kits/playbook/pb_label_value/_label_value.tsx +3 -1
  124. data/app/pb_kits/playbook/pb_label_value/kit.schema.json +1 -0
  125. data/app/pb_kits/playbook/pb_legend/_legend.tsx +3 -1
  126. data/app/pb_kits/playbook/pb_legend/kit.schema.json +1 -0
  127. data/app/pb_kits/playbook/pb_lightbox/Header/_lightbox_header.tsx +1 -1
  128. data/app/pb_kits/playbook/pb_lightbox/lightbox.test.jsx +1 -1
  129. data/app/pb_kits/playbook/pb_map/docs/_map_default.jsx +1 -1
  130. data/app/pb_kits/playbook/pb_map/docs/_map_default.md +3 -3
  131. data/app/pb_kits/playbook/pb_map/docs/_map_with_custom_button.jsx +1 -1
  132. data/app/pb_kits/playbook/pb_map/docs/_map_with_plugin.jsx +1 -1
  133. data/app/pb_kits/playbook/pb_map/docs/_playground.json +3 -3
  134. data/app/pb_kits/playbook/pb_map/docs/_playground.overrides.json +3 -3
  135. data/app/pb_kits/playbook/pb_message/_message.tsx +3 -1
  136. data/app/pb_kits/playbook/pb_message/kit.schema.json +1 -0
  137. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +1 -0
  138. data/app/pb_kits/playbook/pb_multi_level_select/index.js +19 -4
  139. data/app/pb_kits/playbook/pb_multi_level_select/kit.schema.json +7 -0
  140. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.html.erb +4 -1
  141. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb +7 -3
  142. data/app/pb_kits/playbook/pb_multiple_users/_multiple_users.tsx +3 -1
  143. data/app/pb_kits/playbook/pb_multiple_users/kit.schema.json +1 -0
  144. data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.tsx +4 -2
  145. data/app/pb_kits/playbook/pb_multiple_users_stacked/kit.schema.json +1 -0
  146. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +10 -7
  147. data/app/pb_kits/playbook/pb_phone_number_input/docs/_playground.json +1 -0
  148. data/app/pb_kits/playbook/pb_phone_number_input/index.ts +7 -2
  149. data/app/pb_kits/playbook/pb_phone_number_input/kit.schema.json +8 -0
  150. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +5 -1
  151. data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.test.js +12 -0
  152. data/app/pb_kits/playbook/pb_progress_step/_progress_step_item.tsx +3 -1
  153. data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/MoreExtensionsDropdown.tsx +10 -3
  154. data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/Toolbar.tsx +16 -1
  155. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.json +2 -3
  156. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_playground.overrides.json +2 -3
  157. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_attributes.jsx +1 -5
  158. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_default.jsx +1 -5
  159. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_default.md +2 -3
  160. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_focus.jsx +1 -5
  161. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_height.jsx +3 -13
  162. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_inline.jsx +1 -5
  163. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_label.jsx +2 -3
  164. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_markdown_support.jsx +1 -2
  165. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_min_height.jsx +3 -13
  166. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_preview.jsx +1 -5
  167. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_required_indicator.jsx +1 -5
  168. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_simple.jsx +1 -5
  169. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_sticky.jsx +1 -5
  170. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_templates.jsx +1 -5
  171. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_more_extensions.jsx +3 -8
  172. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_more_extensions.md +1 -1
  173. data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_rails_default.md +2 -2
  174. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.test.js +2 -1
  175. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_advanced.test.js +7 -5
  176. data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor_rails.js +15 -4
  177. data/app/pb_kits/playbook/pb_select/_select.scss +2 -2
  178. data/app/pb_kits/playbook/pb_star_rating/index.js +8 -4
  179. data/app/pb_kits/playbook/pb_star_rating/kit.schema.json +7 -0
  180. data/app/pb_kits/playbook/pb_star_rating/star_rating.rb +6 -1
  181. data/app/pb_kits/playbook/pb_stat_value/_stat_value.tsx +3 -1
  182. data/app/pb_kits/playbook/pb_stat_value/kit.schema.json +1 -0
  183. data/app/pb_kits/playbook/pb_table/_table.tsx +70 -197
  184. data/app/pb_kits/playbook/pb_table/index.ts +53 -122
  185. data/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss +26 -3
  186. data/app/pb_kits/playbook/pb_table/styles/_vertical_border.scss +27 -8
  187. data/app/pb_kits/playbook/pb_table/utilities/stickyColumns.test.ts +266 -0
  188. data/app/pb_kits/playbook/pb_table/utilities/stickyColumns.ts +145 -0
  189. data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +1 -1
  190. data/app/pb_kits/playbook/pb_text_input/add_on.html.erb +2 -2
  191. data/app/pb_kits/playbook/pb_timeline/_item.tsx +3 -1
  192. data/app/pb_kits/playbook/pb_title_count/_title_count.tsx +3 -1
  193. data/app/pb_kits/playbook/pb_title_count/kit.schema.json +1 -0
  194. data/app/pb_kits/playbook/pb_title_detail/_title_detail.tsx +3 -1
  195. data/app/pb_kits/playbook/pb_title_detail/kit.schema.json +1 -0
  196. data/app/pb_kits/playbook/utilities/test/globalProps/onClick.test.js +327 -0
  197. data/dist/ai/all-schemas.json +277 -55
  198. data/dist/ai/forms.json +26 -20
  199. data/dist/ai/index.json +2 -2
  200. data/dist/ai/kits/background.schema.json +1 -0
  201. data/dist/ai/kits/button.schema.json +1 -1
  202. data/dist/ai/kits/caption.schema.json +1 -0
  203. data/dist/ai/kits/checkbox.schema.json +7 -5
  204. data/dist/ai/kits/container.schema.json +1 -0
  205. data/dist/ai/kits/currency.schema.json +1 -0
  206. data/dist/ai/kits/dashboard_value.schema.json +1 -0
  207. data/dist/ai/kits/date_picker.schema.json +4 -3
  208. data/dist/ai/kits/detail.schema.json +1 -0
  209. data/dist/ai/kits/dropdown.schema.json +160 -10
  210. data/dist/ai/kits/highlight.schema.json +1 -0
  211. data/dist/ai/kits/icon_stat_value.schema.json +1 -0
  212. data/dist/ai/kits/icon_value.schema.json +1 -0
  213. data/dist/ai/kits/label_value.schema.json +1 -0
  214. data/dist/ai/kits/legend.schema.json +1 -0
  215. data/dist/ai/kits/message.schema.json +1 -0
  216. data/dist/ai/kits/multi_level_select.schema.json +15 -6
  217. data/dist/ai/kits/multiple_users.schema.json +1 -0
  218. data/dist/ai/kits/multiple_users_stacked.schema.json +1 -0
  219. data/dist/ai/kits/phone_number_input.schema.json +18 -7
  220. data/dist/ai/kits/select.schema.json +25 -6
  221. data/dist/ai/kits/star_rating.schema.json +14 -5
  222. data/dist/ai/kits/stat_value.schema.json +1 -0
  223. data/dist/ai/kits/text_input.schema.json +4 -3
  224. data/dist/ai/kits/textarea.schema.json +4 -3
  225. data/dist/ai/kits/time_picker.schema.json +4 -3
  226. data/dist/ai/kits/title_count.schema.json +1 -0
  227. data/dist/ai/kits/title_detail.schema.json +1 -0
  228. data/dist/ai/kits/typeahead.schema.json +4 -3
  229. data/dist/ai/playgrounds/dropdown.json +1 -1
  230. data/dist/ai/playgrounds/index.json +1 -1
  231. data/dist/ai/playgrounds/map.json +1 -1
  232. data/dist/ai/playgrounds/rich_text_editor.json +1 -1
  233. data/dist/chunks/_pagination-BStnaG2D.js +1 -0
  234. data/dist/chunks/{_pb_line_graph-CUJ7NJIr.js → _pb_line_graph-DAoYQIoh.js} +1 -1
  235. data/dist/chunks/_tooltip-WptzLsCF.js +5 -0
  236. data/dist/chunks/_typeahead-DNfFwTns.js +1 -0
  237. data/dist/chunks/{globalProps-DDcpyjvz.js → globalProps-wXibGgWr.js} +1 -1
  238. data/dist/chunks/lib-BDUQ3wt0.js +29 -0
  239. data/dist/chunks/quickpickDateSync-DLDx4zce.js +1 -0
  240. data/dist/chunks/{time_picker_helper-B_FN8E9Y.js → time_picker_helper-Dc38LjqW.js} +1 -1
  241. data/dist/chunks/vendor.js +2 -2
  242. data/dist/menu.yml +1 -1
  243. data/dist/playbook-rails-react-bindings.js +1 -1
  244. data/dist/playbook-rails.js +1 -1
  245. data/dist/playbook.css +1 -1
  246. data/lib/playbook/forms/builder/checkbox_field.rb +1 -0
  247. data/lib/playbook/forms/builder/collection_select_field.rb +5 -1
  248. data/lib/playbook/forms/builder/select_field.rb +5 -1
  249. data/lib/playbook/version.rb +2 -2
  250. metadata +63 -16
  251. data/dist/chunks/_detail-CDUjsRrc.js +0 -5
  252. data/dist/chunks/_table-C9KHGQhb.js +0 -1
  253. data/dist/chunks/_typeahead-CfxZLhd3.js +0 -1
  254. data/dist/chunks/lib-D57mygNT.js +0 -29
  255. /data/app/pb_kits/playbook/pb_form/docs/{_description.md → _description_rails.md} +0 -0
  256. /data/app/pb_kits/playbook/pb_form/docs/{_form_default_values.md → _form_default_values_rails.md} +0 -0
  257. /data/app/pb_kits/playbook/pb_form/docs/{_form_defaults.md → _form_defaults_rails.md} +0 -0
  258. /data/app/pb_kits/playbook/pb_form/docs/{_form_model_values.md → _form_model_values_rails.md} +0 -0
  259. /data/app/pb_kits/playbook/pb_form/docs/{_form_multi_column.md → _form_multi_column_rails.md} +0 -0
@@ -0,0 +1,101 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import Avatar from '../../pb_avatar/_avatar'
4
+ import Body from '../../pb_body/_body'
5
+ import Dropdown from '../../pb_dropdown/_dropdown'
6
+ import Flex from '../../pb_flex/_flex'
7
+ import FlexItem from '../../pb_flex/_flex_item'
8
+ import Title from '../../pb_title/_title'
9
+
10
+ const USERS = [
11
+ {
12
+ label: "Wade Winningham",
13
+ title: "Nitro Principal Developer",
14
+ territory: "PHL",
15
+ value: "wadeWinningham",
16
+ },
17
+ {
18
+ label: "Carlos Lima",
19
+ title: "Nitro Developer",
20
+ territory: "PHL",
21
+ value: "carlosLima",
22
+ },
23
+ {
24
+ label: "Stephen Marshall",
25
+ title: "Senior Nitro Developer",
26
+ territory: "PHL",
27
+ value: "stephenMarshall",
28
+ },
29
+ {
30
+ label: "Jasper Furniss",
31
+ title: "Lead User Experience Engineer",
32
+ territory: "PHL",
33
+ value: "jasperFurniss",
34
+ },
35
+ ]
36
+
37
+ const escapeRegExp = (value = "") => (
38
+ value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
39
+ )
40
+
41
+ const highlighted = (text, searchInput) => {
42
+ if (!searchInput) return text
43
+
44
+ const regex = new RegExp(`(${escapeRegExp(searchInput)})`, 'gi')
45
+
46
+ return text.split(regex).map((part, index) => (
47
+ part.toLowerCase() === searchInput.toLowerCase()
48
+ ? <mark key={`${part}-${index}`}>{part}</mark>
49
+ : <React.Fragment key={`${part}-${index}`}>{part}</React.Fragment>
50
+ ))
51
+ }
52
+
53
+ const loadUsers = (searchInput) => {
54
+ const normalizedInput = searchInput.toLowerCase()
55
+
56
+ return Promise.resolve(USERS.filter(({ label, title }) => (
57
+ `${label} ${title}`.toLowerCase().includes(normalizedInput)
58
+ )))
59
+ }
60
+
61
+ const DropdownWithHighlight = (props) => {
62
+ const [searchInput, setSearchInput] = useState("")
63
+
64
+ const renderUser = ({ label, territory, title }) => (
65
+ <Flex>
66
+ <FlexItem>
67
+ <Avatar
68
+ marginRight="sm"
69
+ name={label}
70
+ size="sm"
71
+ />
72
+ </FlexItem>
73
+ <FlexItem>
74
+ <Title size={4}>
75
+ {highlighted(label, searchInput)}
76
+ </Title>
77
+ <Body color="light">
78
+ {highlighted(title, searchInput)}{" • "}
79
+ {territory}
80
+ </Body>
81
+ </FlexItem>
82
+ </Flex>
83
+ )
84
+
85
+ return (
86
+ <Dropdown
87
+ async
88
+ autocomplete
89
+ defaultOptions={USERS}
90
+ label="Users"
91
+ loadOptions={loadUsers}
92
+ onInputChange={(input) => setSearchInput(input)}
93
+ onSelect={() => setSearchInput("")}
94
+ placeholder="Search users"
95
+ renderOption={renderUser}
96
+ {...props}
97
+ />
98
+ )
99
+ }
100
+
101
+ export default DropdownWithHighlight
@@ -0,0 +1,3 @@
1
+ Use `onInputChange` to track the current search and `renderOption` to customize each option row. Split each field by the search input, then render matching text inside `<mark>` so users can quickly see why a result matched.
2
+
3
+ This example uses `loadOptions` to search both the user's name and title.
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "template": "<Dropdown{{props}} />",
3
- "propTargets": {},
3
+ "propTargets": {
4
+ "searchbar": "Container.props",
5
+ "options": "Options.data"
6
+ },
4
7
  "defaults": {
8
+ "async": false,
5
9
  "autocomplete": false,
6
10
  "blankSelection": "",
7
11
  "clearable": true,
@@ -84,6 +88,20 @@
84
88
  "placeholder": "Select a country"
85
89
  },
86
90
  "groups": [
91
+ {
92
+ "name": "async search",
93
+ "props": [
94
+ "async",
95
+ "loadOptions",
96
+ "defaultOptions",
97
+ "cacheOptions",
98
+ "loading",
99
+ "onInputChange",
100
+ "renderOption",
101
+ "value",
102
+ "searchbar"
103
+ ]
104
+ },
87
105
  {
88
106
  "name": "Content",
89
107
  "props": [
@@ -137,6 +155,26 @@
137
155
  }
138
156
  ],
139
157
  "presets": [
158
+ {
159
+ "name": "Async search",
160
+ "structureMode": "async",
161
+ "props": {}
162
+ },
163
+ {
164
+ "name": "Rich results and selection",
165
+ "structureMode": "rich",
166
+ "props": {}
167
+ },
168
+ {
169
+ "name": "Controlled selection",
170
+ "structureMode": "controlled",
171
+ "props": {}
172
+ },
173
+ {
174
+ "name": "External search",
175
+ "structureMode": "external",
176
+ "props": {}
177
+ },
140
178
  {
141
179
  "name": "Default trigger",
142
180
  "props": {
@@ -280,6 +318,21 @@
280
318
  }
281
319
  ],
282
320
  "conditionals": {
321
+ "loadOptions": {
322
+ "requires": "async"
323
+ },
324
+ "defaultOptions": {
325
+ "requires": "async"
326
+ },
327
+ "cacheOptions": {
328
+ "requires": "async"
329
+ },
330
+ "loading": {
331
+ "requires": "async"
332
+ },
333
+ "searchbar": {
334
+ "structureMode": "async"
335
+ },
283
336
  "requiredIndicator": {
284
337
  "requires": "label"
285
338
  },
@@ -308,6 +361,23 @@
308
361
  }
309
362
  },
310
363
  "hints": {
364
+ "async_search_info": {
365
+ "when": {
366
+ "async": true
367
+ },
368
+ "message": "Async examples search the public DummyJSON sample-user API. Try Emily or Michael, or an unmatched term for the empty state. defaultOptions preloads results; cacheOptions reuses successful searches. Use the Async search structure with autocomplete off and searchbar on to search inside the menu.",
369
+ "type": "info"
370
+ },
371
+ "external_search_info": {
372
+ "presetName": "External search",
373
+ "message": "The wrapper owns a 250ms debounce, a three-character minimum, request cancellation, options, and loading. onInputChange reports input/clear; onSelect receives the complete option. Inspect the generated code for the integration.",
374
+ "type": "info"
375
+ },
376
+ "rich_results_info": {
377
+ "presetName": "Rich results and selection",
378
+ "message": "renderOption customizes results; the existing Trigger customDisplay renders selected company details. The selected option shown below retains custom company data.",
379
+ "type": "info"
380
+ },
311
381
  "quickpick_scope": {
312
382
  "when": {
313
383
  "variant": "quickpick"
@@ -324,7 +394,8 @@
324
394
  },
325
395
  "autocomplete_info": {
326
396
  "when": {
327
- "autocomplete": true
397
+ "autocomplete": true,
398
+ "async": false
328
399
  },
329
400
  "message": "Autocomplete filters the provided options list in place. It works especially well with longer option sets.",
330
401
  "type": "info"
@@ -362,14 +433,114 @@
362
433
  "template": "<Dropdown options={options}{{props}} />",
363
434
  "children": ""
364
435
  },
436
+ "async": {
437
+ "label": "Async search",
438
+ "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger />\n <Dropdown.Container{{Container.props}} />\n</Dropdown>",
439
+ "children": "",
440
+ "props": {
441
+ "async": true,
442
+ "autocomplete": true,
443
+ "options": [],
444
+ "label": "User",
445
+ "placeholder": "Try Emily or Michael",
446
+ "loadOptions": "loadUsers",
447
+ "defaultOptions": true,
448
+ "cacheOptions": true
449
+ },
450
+ "wrapper": "const loadUsers = (term) => fetch(`https://dummyjson.com/users/search?${new URLSearchParams({ q: term, limit: '10', select: 'firstName,lastName,company' })}`, { credentials: 'omit' })\n .then((response) => {\n if (!response.ok) throw new Error('Search failed')\n return response.json()\n })\n .then(({ users }) => users.map((user) => ({\n ...user,\n label: `${user.firstName} ${user.lastName}`,\n value: user.id,\n })));\n\n{{component}}"
451
+ },
452
+ "rich": {
453
+ "label": "Rich async results",
454
+ "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger customDisplay={selected && <Detail text={companyDetail(selected)} />} />\n <Dropdown.Container{{Container.props}} />\n</Dropdown>",
455
+ "children": "",
456
+ "props": {
457
+ "async": true,
458
+ "autocomplete": true,
459
+ "options": [],
460
+ "label": "User",
461
+ "placeholder": "Try Emily or Michael",
462
+ "loadOptions": "loadUsers",
463
+ "renderOption": "renderUser",
464
+ "onSelect": "setSelected",
465
+ "value": {
466
+ "__playgroundCode": "selected"
467
+ }
468
+ },
469
+ "externalImports": [
470
+ "import React, { useState } from 'react'"
471
+ ],
472
+ "wrapper": "const loadUsers = (term) => fetch(`https://dummyjson.com/users/search?${new URLSearchParams({ q: term, limit: '10', select: 'firstName,lastName,company' })}`, { credentials: 'omit' })\n .then((response) => {\n if (!response.ok) throw new Error('Search failed')\n return response.json()\n })\n .then(({ users }) => users.map((user) => ({\n ...user,\n label: `${user.firstName} ${user.lastName}`,\n value: user.id,\n })))\n\nconst companyDetail = (user) => [user.company?.title, user.company?.department].filter(Boolean).join(' · ')\n\nconst renderUser = (user) => (\n <div>\n <Body text={user.label} />\n <Detail text={companyDetail(user)} />\n </div>\n)\n\nconst RichDropdownPlayground = () => {\n const [selected, setSelected] = useState(null)\n return (\n <>\n {{component}}\n <Detail text={selected ? JSON.stringify(selected) : \"Select a user to inspect the complete option object.\"} />\n </>\n )\n};\n\n<RichDropdownPlayground />"
473
+ },
474
+ "controlled": {
475
+ "label": "Controlled selection",
476
+ "template": "<Dropdown options={options}{{props}} />",
477
+ "children": "",
478
+ "props": {
479
+ "multiSelect": true,
480
+ "label": "Countries",
481
+ "value": {
482
+ "__playgroundCode": "selected"
483
+ },
484
+ "onSelect": "setSelected"
485
+ },
486
+ "externalImports": [
487
+ "import React, { useState } from 'react'"
488
+ ],
489
+ "wrapper": "const ControlledDropdownPlayground = () => {\n const [selected, setSelected] = useState([])\n return (\n <>\n {{component}}\n <Flex gap=\"xs\" marginTop=\"sm\">\n <Button text=\"Select all enabled\" onClick={() => setSelected(options.filter((option) => !option.disabled))} />\n <Button text=\"Clear\" variant=\"secondary\" onClick={() => setSelected([])} />\n </Flex>\n </>\n )\n};\n\n<ControlledDropdownPlayground />"
490
+ },
491
+ "external": {
492
+ "label": "External async search",
493
+ "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger />\n <Dropdown.Container{{Container.props}} />\n</Dropdown>",
494
+ "children": "",
495
+ "props": {
496
+ "async": true,
497
+ "autocomplete": true,
498
+ "options": [],
499
+ "label": "User",
500
+ "placeholder": "Type at least 3 characters",
501
+ "loading": {
502
+ "__playgroundCode": "loading"
503
+ },
504
+ "value": {
505
+ "__playgroundCode": "selected"
506
+ },
507
+ "onInputChange": "(text, { reason }) => setQuery(reason === 'input' ? text : '')",
508
+ "onSelect": "(option) => { setSelected(option); setQuery('') }"
509
+ },
510
+ "externalImports": [
511
+ "import React, { useEffect, useState } from 'react'"
512
+ ],
513
+ "wrapper": "const ExternalDropdownPlayground = () => {\n const [query, setQuery] = useState('')\n const [options, setOptions] = useState([])\n const [loading, setLoading] = useState(false)\n const [selected, setSelected] = useState(null)\n\n useEffect(() => {\n const controller = new AbortController()\n setOptions([])\n setLoading(false)\n if (query.length < 3) return () => controller.abort()\n setLoading(true)\n const timer = setTimeout(() => {\n const params = new URLSearchParams({ q: query, limit: '10', select: 'firstName,lastName' })\n fetch(`https://dummyjson.com/users/search?${params}`, { signal: controller.signal, credentials: 'omit' })\n .then((response) => {\n if (!response.ok) throw new Error('Search failed')\n return response.json()\n })\n .then(({ users }) => {\n if (!controller.signal.aborted) setOptions(users.map((user) => ({\n ...user,\n label: `${user.firstName} ${user.lastName}`,\n value: user.id,\n })))\n })\n .catch(() => { if (!controller.signal.aborted) setOptions([]) })\n .finally(() => { if (!controller.signal.aborted) setLoading(false) })\n }, 250)\n return () => { clearTimeout(timer); controller.abort() }\n }, [query])\n\n return ({{component}})\n};\n\n<ExternalDropdownPlayground />"
514
+ },
365
515
  "subcomponents": {
366
516
  "label": "With Subcomponents",
367
- "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger />\n <Dropdown.Container>\n {options.map((option) => (\n <Dropdown.Option key={option.id} option={option} />\n ))}\n </Dropdown.Container>\n</Dropdown>",
517
+ "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger />\n <Dropdown.Container{{Container.props}}>\n {options.map((option) => (\n <Dropdown.Option key={option.id} option={option} />\n ))}\n </Dropdown.Container>\n</Dropdown>",
368
518
  "children": ""
369
519
  }
370
520
  }
371
521
  },
522
+ "editableFunctionProps": [
523
+ "loadOptions",
524
+ "renderOption",
525
+ "onInputChange",
526
+ "onSelect"
527
+ ],
372
528
  "customProps": {
529
+ "loadOptions": {
530
+ "type": "function",
531
+ "platforms": [
532
+ "react"
533
+ ],
534
+ "description": "Promise or callback loader. Receives the search term; return options with id, label, and value plus any custom data."
535
+ },
536
+ "searchbar": {
537
+ "type": "boolean",
538
+ "default": false,
539
+ "platforms": [
540
+ "react"
541
+ ],
542
+ "description": "Show a search input inside Dropdown.Container. Turn autocomplete off to try this mode."
543
+ },
373
544
  "options": {
374
545
  "type": "array",
375
546
  "platforms": [
@@ -7,14 +7,110 @@
7
7
  "template": "<Dropdown options={options}{{props}} />",
8
8
  "children": ""
9
9
  },
10
+ "async": {
11
+ "label": "Async search",
12
+ "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger />\n <Dropdown.Container{{Container.props}} />\n</Dropdown>",
13
+ "children": "",
14
+ "props": {
15
+ "async": true,
16
+ "autocomplete": true,
17
+ "options": [],
18
+ "label": "User",
19
+ "placeholder": "Try Emily or Michael",
20
+ "loadOptions": "loadUsers",
21
+ "defaultOptions": true,
22
+ "cacheOptions": true
23
+ },
24
+ "wrapper": "const loadUsers = (term) => fetch(`https://dummyjson.com/users/search?${new URLSearchParams({ q: term, limit: '10', select: 'firstName,lastName,company' })}`, { credentials: 'omit' })\n .then((response) => {\n if (!response.ok) throw new Error('Search failed')\n return response.json()\n })\n .then(({ users }) => users.map((user) => ({\n ...user,\n label: `${user.firstName} ${user.lastName}`,\n value: user.id,\n })));\n\n{{component}}"
25
+ },
26
+ "rich": {
27
+ "label": "Rich async results",
28
+ "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger customDisplay={selected && <Detail text={companyDetail(selected)} />} />\n <Dropdown.Container{{Container.props}} />\n</Dropdown>",
29
+ "children": "",
30
+ "props": {
31
+ "async": true,
32
+ "autocomplete": true,
33
+ "options": [],
34
+ "label": "User",
35
+ "placeholder": "Try Emily or Michael",
36
+ "loadOptions": "loadUsers",
37
+ "renderOption": "renderUser",
38
+ "onSelect": "setSelected",
39
+ "value": {
40
+ "__playgroundCode": "selected"
41
+ }
42
+ },
43
+ "externalImports": [
44
+ "import React, { useState } from 'react'"
45
+ ],
46
+ "wrapper": "const loadUsers = (term) => fetch(`https://dummyjson.com/users/search?${new URLSearchParams({ q: term, limit: '10', select: 'firstName,lastName,company' })}`, { credentials: 'omit' })\n .then((response) => {\n if (!response.ok) throw new Error('Search failed')\n return response.json()\n })\n .then(({ users }) => users.map((user) => ({\n ...user,\n label: `${user.firstName} ${user.lastName}`,\n value: user.id,\n })))\n\nconst companyDetail = (user) => [user.company?.title, user.company?.department].filter(Boolean).join(' \u00b7 ')\n\nconst renderUser = (user) => (\n <div>\n <Body text={user.label} />\n <Detail text={companyDetail(user)} />\n </div>\n)\n\nconst RichDropdownPlayground = () => {\n const [selected, setSelected] = useState(null)\n return (\n <>\n {{component}}\n <Detail text={selected ? JSON.stringify(selected) : \"Select a user to inspect the complete option object.\"} />\n </>\n )\n};\n\n<RichDropdownPlayground />"
47
+ },
48
+ "controlled": {
49
+ "label": "Controlled selection",
50
+ "template": "<Dropdown options={options}{{props}} />",
51
+ "children": "",
52
+ "props": {
53
+ "multiSelect": true,
54
+ "label": "Countries",
55
+ "value": {
56
+ "__playgroundCode": "selected"
57
+ },
58
+ "onSelect": "setSelected"
59
+ },
60
+ "externalImports": [
61
+ "import React, { useState } from 'react'"
62
+ ],
63
+ "wrapper": "const ControlledDropdownPlayground = () => {\n const [selected, setSelected] = useState([])\n return (\n <>\n {{component}}\n <Flex gap=\"xs\" marginTop=\"sm\">\n <Button text=\"Select all enabled\" onClick={() => setSelected(options.filter((option) => !option.disabled))} />\n <Button text=\"Clear\" variant=\"secondary\" onClick={() => setSelected([])} />\n </Flex>\n </>\n )\n};\n\n<ControlledDropdownPlayground />"
64
+ },
65
+ "external": {
66
+ "label": "External async search",
67
+ "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger />\n <Dropdown.Container{{Container.props}} />\n</Dropdown>",
68
+ "children": "",
69
+ "props": {
70
+ "async": true,
71
+ "autocomplete": true,
72
+ "options": [],
73
+ "label": "User",
74
+ "placeholder": "Type at least 3 characters",
75
+ "loading": {
76
+ "__playgroundCode": "loading"
77
+ },
78
+ "value": {
79
+ "__playgroundCode": "selected"
80
+ },
81
+ "onInputChange": "(text, { reason }) => setQuery(reason === 'input' ? text : '')",
82
+ "onSelect": "(option) => { setSelected(option); setQuery('') }"
83
+ },
84
+ "externalImports": [
85
+ "import React, { useEffect, useState } from 'react'"
86
+ ],
87
+ "wrapper": "const ExternalDropdownPlayground = () => {\n const [query, setQuery] = useState('')\n const [options, setOptions] = useState([])\n const [loading, setLoading] = useState(false)\n const [selected, setSelected] = useState(null)\n\n useEffect(() => {\n const controller = new AbortController()\n setOptions([])\n setLoading(false)\n if (query.length < 3) return () => controller.abort()\n setLoading(true)\n const timer = setTimeout(() => {\n const params = new URLSearchParams({ q: query, limit: '10', select: 'firstName,lastName' })\n fetch(`https://dummyjson.com/users/search?${params}`, { signal: controller.signal, credentials: 'omit' })\n .then((response) => {\n if (!response.ok) throw new Error('Search failed')\n return response.json()\n })\n .then(({ users }) => {\n if (!controller.signal.aborted) setOptions(users.map((user) => ({\n ...user,\n label: `${user.firstName} ${user.lastName}`,\n value: user.id,\n })))\n })\n .catch(() => { if (!controller.signal.aborted) setOptions([]) })\n .finally(() => { if (!controller.signal.aborted) setLoading(false) })\n }, 250)\n return () => { clearTimeout(timer); controller.abort() }\n }, [query])\n\n return ({{component}})\n};\n\n<ExternalDropdownPlayground />"
88
+ },
10
89
  "subcomponents": {
11
90
  "label": "With Subcomponents",
12
- "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger />\n <Dropdown.Container>\n {options.map((option) => (\n <Dropdown.Option key={option.id} option={option} />\n ))}\n </Dropdown.Container>\n</Dropdown>",
91
+ "template": "<Dropdown options={options}{{props}}>\n <Dropdown.Trigger />\n <Dropdown.Container{{Container.props}}>\n {options.map((option) => (\n <Dropdown.Option key={option.id} option={option} />\n ))}\n </Dropdown.Container>\n</Dropdown>",
13
92
  "children": ""
14
93
  }
15
94
  }
16
95
  },
96
+ "editableFunctionProps": ["loadOptions", "renderOption", "onInputChange", "onSelect"],
97
+ "propTargets": { "searchbar": "Container.props", "options": "Options.data" },
17
98
  "customProps": {
99
+ "loadOptions": {
100
+ "type": "function",
101
+ "platforms": [
102
+ "react"
103
+ ],
104
+ "description": "Promise or callback loader. Receives the search term; return options with id, label, and value plus any custom data."
105
+ },
106
+ "searchbar": {
107
+ "type": "boolean",
108
+ "default": false,
109
+ "platforms": [
110
+ "react"
111
+ ],
112
+ "description": "Show a search input inside Dropdown.Container. Turn autocomplete off to try this mode."
113
+ },
18
114
  "options": {
19
115
  "type": "array",
20
116
  "platforms": ["react", "rails"],
@@ -66,6 +162,20 @@
66
162
  "variant": "default"
67
163
  },
68
164
  "groups": [
165
+ {
166
+ "name": "async search",
167
+ "props": [
168
+ "async",
169
+ "loadOptions",
170
+ "defaultOptions",
171
+ "cacheOptions",
172
+ "loading",
173
+ "onInputChange",
174
+ "renderOption",
175
+ "value",
176
+ "searchbar"
177
+ ]
178
+ },
69
179
  {
70
180
  "name": "Content",
71
181
  "props": [
@@ -116,6 +226,26 @@
116
226
  }
117
227
  ],
118
228
  "presets": [
229
+ {
230
+ "name": "Async search",
231
+ "structureMode": "async",
232
+ "props": {}
233
+ },
234
+ {
235
+ "name": "Rich results and selection",
236
+ "structureMode": "rich",
237
+ "props": {}
238
+ },
239
+ {
240
+ "name": "Controlled selection",
241
+ "structureMode": "controlled",
242
+ "props": {}
243
+ },
244
+ {
245
+ "name": "External search",
246
+ "structureMode": "external",
247
+ "props": {}
248
+ },
119
249
  {
120
250
  "name": "Default trigger",
121
251
  "props": {
@@ -244,6 +374,11 @@
244
374
  }
245
375
  ],
246
376
  "conditionals": {
377
+ "loadOptions": { "requires": "async" },
378
+ "defaultOptions": { "requires": "async" },
379
+ "cacheOptions": { "requires": "async" },
380
+ "loading": { "requires": "async" },
381
+ "searchbar": { "structureMode": "async" },
247
382
  "requiredIndicator": { "requires": "label" },
248
383
  "formPillProps": { "requires": "multiSelect" },
249
384
  "rangeEndsToday": { "requires": { "variant": "quickpick" } },
@@ -252,6 +387,23 @@
252
387
  "customQuickPickDates": { "requires": { "variant": "quickpick" } }
253
388
  },
254
389
  "hints": {
390
+ "async_search_info": {
391
+ "when": {
392
+ "async": true
393
+ },
394
+ "message": "Async examples search the public DummyJSON sample-user API. Try Emily or Michael, or an unmatched term for the empty state. defaultOptions preloads results; cacheOptions reuses successful searches. Use the Async search structure with autocomplete off and searchbar on to search inside the menu.",
395
+ "type": "info"
396
+ },
397
+ "external_search_info": {
398
+ "presetName": "External search",
399
+ "message": "The wrapper owns a 250ms debounce, a three-character minimum, request cancellation, options, and loading. onInputChange reports input/clear; onSelect receives the complete option. Inspect the generated code for the integration.",
400
+ "type": "info"
401
+ },
402
+ "rich_results_info": {
403
+ "presetName": "Rich results and selection",
404
+ "message": "renderOption customizes results; the existing Trigger customDisplay renders selected company details. The selected option shown below retains custom company data.",
405
+ "type": "info"
406
+ },
255
407
  "quickpick_scope": {
256
408
  "when": { "variant": "quickpick" },
257
409
  "message": "Quick pick uses preset date-range options. Use customQuickPickDates to replace or extend them, and pair controlsStartId / controlsEndId with DatePicker when you need synced date inputs.",
@@ -263,7 +415,7 @@
263
415
  "type": "info"
264
416
  },
265
417
  "autocomplete_info": {
266
- "when": { "autocomplete": true },
418
+ "when": { "autocomplete": true, "async": false },
267
419
  "message": "Autocomplete filters the provided options list in place. It works especially well with longer option sets.",
268
420
  "type": "info"
269
421
  },
@@ -25,6 +25,7 @@ examples:
25
25
  - dropdown_default_value_with_autocomplete: Default Value with Autocomplete
26
26
  - dropdown_blank_selection: Blank Selection
27
27
  - dropdown_with_placeholder: Placeholder
28
+ - dropdown_no_options_text: No Options Text
28
29
  - dropdown_separators_hidden: Separators Hidden
29
30
  - dropdown_with_clearable: Clearable
30
31
  - dropdown_with_constrain_height_rails: Constrain Height
@@ -35,6 +36,7 @@ examples:
35
36
  - dropdown_quickpick_custom_rails: Quick Pick Variant (Custom Quick Pick Dates)
36
37
  - dropdown_quickpick_with_date_pickers_rails: Quick Pick with Date Pickers
37
38
  - dropdown_quickpick_with_date_pickers_default_rails: Quick Pick with Date Pickers (Default Value)
39
+ - dropdown_quickpick_enable_time: Quick Pick with Date Pickers (Enable Time)
38
40
  - dropdown_required_indicator: Required Indicator
39
41
  - dropdown_disabled: Disabled Input
40
42
  - dropdown_grouped_options: Grouped Options
@@ -42,10 +44,14 @@ examples:
42
44
  - dropdown_dynamic_options: Dynamic Options
43
45
  - dropdown_dynamic_options_with_autocomplete: Dynamic Options with Autocomplete
44
46
  - dropdown_dynamic_options_with_multi_select: Dynamic Options with Multi Select
47
+ - dropdown_async_search: Async Search
48
+ - dropdown_async_multi_select_rails: Async Multi Select
49
+ - dropdown_async_custom_content: Async Search with Custom Content
45
50
 
46
51
  react:
47
52
  - dropdown_default: Default
48
53
  - dropdown_with_autocomplete: Autocomplete
54
+ - dropdown_with_highlight: With Highlight
49
55
  - dropdown_multi_select: Multi Select
50
56
  - dropdown_multi_select_with_autocomplete: Multi Select with Autocomplete
51
57
  - dropdown_multi_select_display: Multi Select with Form Pill Props
@@ -70,6 +76,7 @@ examples:
70
76
  - dropdown_default_value_with_autocomplete: Default Value with Autocomplete
71
77
  - dropdown_blank_selection: Blank Selection
72
78
  - dropdown_with_placeholder: Placeholder
79
+ - dropdown_no_options_text: No Options Text
73
80
  - dropdown_clear_selection: Clear Selection
74
81
  - dropdown_with_clearable: Clearable
75
82
  - dropdown_with_constrain_height: Constrain Height
@@ -81,9 +88,16 @@ examples:
81
88
  - dropdown_quickpick_default_dates: Quick Pick Variant (Default Dates)
82
89
  - dropdown_quickpick_custom: Quick Pick Variant (Custom Quick Pick Dates)
83
90
  - dropdown_quickpick_with_date_pickers: Quick Pick Variant with Date Pickers
91
+ - dropdown_quickpick_enable_time: Quick Pick with Date Pickers (Enable Time)
84
92
  - dropdown_required_indicator: Required Indicator
85
93
  - dropdown_disabled: Disabled Input
86
94
  - dropdown_grouped_options: Grouped Options
87
95
  - dropdown_react_hook: React Hook
88
96
  - dropdown_multi_select_react_hook: React Hook Multi Select
97
+ - dropdown_controlled_selection: Controlled Selection
98
+ - dropdown_async_loading: Async Search
99
+ - dropdown_async_multi_select: Async Multi Select
100
+ - dropdown_async_rich_results: Async Search with Custom Content
101
+ - dropdown_async_initial_options: Async Initial Results and Caching
102
+ - dropdown_external_search: External Search
89
103
 
@@ -40,3 +40,12 @@ export { default as DropdownCustomDisplayDisabledOption } from "./_dropdown_cust
40
40
  export { default as DropdownDisabled } from "./_dropdown_disabled.jsx";
41
41
  export { default as DropdownGroupedOptions } from "./_dropdown_grouped_options.jsx";
42
42
  export { default as DropdownDefaultValueWithAutocomplete } from './_dropdown_default_value_with_autocomplete.jsx'
43
+ export { default as DropdownNoOptionsText } from './_dropdown_no_options_text.jsx'
44
+ export { default as DropdownControlledSelection } from './_dropdown_controlled_selection.jsx'
45
+ export { default as DropdownAsyncLoading } from './_dropdown_async_loading.jsx'
46
+ export { default as DropdownAsyncMultiSelect } from './_dropdown_async_multi_select.jsx'
47
+ export { default as DropdownAsyncRichResults } from './_dropdown_async_rich_results.jsx'
48
+ export { default as DropdownAsyncInitialOptions } from './_dropdown_async_initial_options.jsx'
49
+ export { default as DropdownExternalSearch } from './_dropdown_external_search.jsx'
50
+ export { default as DropdownQuickpickEnableTime } from './_dropdown_quickpick_enable_time.jsx'
51
+ export { default as DropdownWithHighlight } from './_dropdown_with_highlight.jsx'
@@ -15,6 +15,9 @@
15
15
  <% if input_default_value.present? %>
16
16
  data-default-value="<%= input_default_value %>"
17
17
  <% end %>
18
+ <% if object.validation_message.present? %>
19
+ data-message="<%= object.validation_message %>"
20
+ <% end %>
18
21
  data-dropdown-selected-option
19
22
  name="<%= object.name %><%= '[]' if object.multi_select %>"
20
23
  style="display: none"
@@ -32,7 +35,7 @@
32
35
  <% end %>
33
36
  <% else %>
34
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 }) %>
35
- <%= pb_rails("dropdown/dropdown_container", props: { searchbar: object.searchbar, constrain_height: object.constrain_height, disabled: object.disabled }) do %>
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 %>
36
39
  <% if options_with_blank.present? %>
37
40
  <% options_with_blank.each do |option| %>
38
41
  <%= pb_rails("dropdown/dropdown_option", props: {option: option}) %>