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
@@ -0,0 +1,1057 @@
1
+ import React, { useEffect, useRef, useState } from "react"
2
+ import { Controller, useForm } from "react-hook-form"
3
+
4
+ import Body from "../../pb_body/_body"
5
+ import Button from "../../pb_button/_button"
6
+ import Caption from "../../pb_caption/_caption"
7
+ import Card from "../../pb_card/_card"
8
+ import Checkbox from "../../pb_checkbox/_checkbox"
9
+ import DatePicker from "../../pb_date_picker/_date_picker"
10
+ import Dropdown from "../../pb_dropdown/_dropdown"
11
+ import Flex from "../../pb_flex/_flex"
12
+ import MultiLevelSelect from "../../pb_multi_level_select/_multi_level_select"
13
+ import PhoneNumberInput from "../../pb_phone_number_input/_phone_number_input"
14
+ import Pill from "../../pb_pill/_pill"
15
+ import Select from "../../pb_select/_select"
16
+ import StarRating from "../../pb_star_rating/_star_rating"
17
+ import Textarea from "../../pb_textarea/_textarea"
18
+ import TextInput from "../../pb_text_input/_text_input"
19
+ import TimePicker from "../../pb_time_picker/_time_picker"
20
+ import Typeahead from "../../pb_typeahead/_typeahead"
21
+
22
+ const INPUT_TYPES = [
23
+ { key: "checkbox", label: "Checkbox" },
24
+ { key: "date_picker", label: "Date Picker" },
25
+ { key: "dropdown", label: "Dropdown: Default" },
26
+ { key: "multi_select", label: "Dropdown: Multi Select" },
27
+ { key: "multi_level_select", label: "Multi Level Select" },
28
+ { key: "phone_number", label: "Phone Number" },
29
+ { key: "select", label: "Select: Default" },
30
+ { key: "star_rating", label: "Star Rating" },
31
+ { key: "text_field", label: "Text Input: Default" },
32
+ { key: "email_field", label: "Text Input: Email" },
33
+ { key: "number_field", label: "Text Input: Number" },
34
+ { key: "password_field", label: "Text Input: Password" },
35
+ { key: "search_field", label: "Text Input: Search" },
36
+ { key: "url_field", label: "Text Input: URL" },
37
+ { key: "textarea", label: "Textarea" },
38
+ { key: "time_picker", label: "Time Picker" },
39
+ { key: "typeahead_default", label: "Typeahead: Default" },
40
+ { key: "typeahead", label: "Typeahead: Multi" },
41
+ ]
42
+
43
+ const DEFAULT_SELECTED_KEY = "text_field"
44
+ const REQUIRED_MESSAGE = "Please fill out this field."
45
+
46
+ const COLOR_SELECT_OPTIONS = [
47
+ { text: "Red", value: "red" },
48
+ { text: "Blue", value: "blue" },
49
+ { text: "Green", value: "green" },
50
+ ]
51
+
52
+ const COUNTRY_OPTIONS = [
53
+ { id: "us-val", label: "United States", value: "United States" },
54
+ { id: "ca-val", label: "Canada", value: "Canada" },
55
+ { id: "pk-val", label: "Pakistan", value: "Pakistan" },
56
+ ]
57
+
58
+ const TYPEAHEAD_COLOR_OPTIONS = [
59
+ { label: "Orange", value: "#FFA500" },
60
+ { label: "Red", value: "#FF0000" },
61
+ { label: "Green", value: "#00FF00" },
62
+ { label: "Blue", value: "#0000FF" },
63
+ ]
64
+
65
+ const DEPARTMENT_TREE_DATA = [
66
+ {
67
+ children: [
68
+ {
69
+ children: [
70
+ { id: "validation-102", label: "Talent Acquisition", value: "talentAcquisition" },
71
+ { id: "validation-103", label: "People Experience", value: "peopleExperience" },
72
+ ],
73
+ id: "validation-101",
74
+ label: "People",
75
+ value: "people",
76
+ },
77
+ {
78
+ children: [
79
+ { id: "validation-105", label: "Customer Service", value: "customerService" },
80
+ { id: "validation-106", label: "Energy", value: "energy" },
81
+ ],
82
+ id: "validation-104",
83
+ label: "Contact Center",
84
+ value: "contactCenter",
85
+ },
86
+ ],
87
+ expanded: true,
88
+ id: "validation-100",
89
+ label: "Power Home Remodeling",
90
+ value: "powerHomeRemodeling",
91
+ },
92
+ ]
93
+
94
+ const requireSelection = (message) => ({
95
+ validate: (value) => {
96
+ if (Array.isArray(value)) return value.length > 0 || message
97
+ if (value && typeof value === "object") {
98
+ return Boolean(value.id || value.value || value.label) || message
99
+ }
100
+ return (value !== undefined && value !== null && value !== "") || message
101
+ },
102
+ })
103
+
104
+ // Recursively locate a node by its `id` so onSubmit can translate stored ids
105
+ // back into the human-readable `value`s (matches FormDefaults behavior).
106
+ const findNodeById = (nodes, id) => {
107
+ for (const node of nodes) {
108
+ if (node.id === id) return node
109
+ if (node.children) {
110
+ const found = findNodeById(node.children, id)
111
+ if (found) return found
112
+ }
113
+ }
114
+ return null
115
+ }
116
+
117
+ // Map each field name to its toggle key so onSubmit can filter out fields
118
+ // whose pill has been deselected.
119
+ const FIELD_TO_INPUT_KEY = {
120
+ newsletter: "checkbox",
121
+ startDate: "date_picker",
122
+ country: "dropdown",
123
+ countries: "multi_select",
124
+ department: "multi_level_select",
125
+ phone: "phone_number",
126
+ favoriteColor: "select",
127
+ rating: "star_rating",
128
+ fullName: "text_field",
129
+ email: "email_field",
130
+ quantity: "number_field",
131
+ password: "password_field",
132
+ projectNumber: "search_field",
133
+ website: "url_field",
134
+ bio: "textarea",
135
+ startTime: "time_picker",
136
+ favoriteColorSearch: "typeahead_default",
137
+ favoriteColors: "typeahead",
138
+ }
139
+
140
+ // Only interactive StarRating needs the reset: it keeps its own useState and
141
+ // ignores `rating`, so a stored rating would submit while the control looks
142
+ // empty after remount — and the required rule would then pass for a blank-
143
+ // looking control. Other toggle-remounted kits (TimePicker, DatePicker,
144
+ // Dropdown, Typeahead) rehydrate from their `defaultX` / `value` props.
145
+ const RESET_ON_DESELECT = {
146
+ star_rating: "rating",
147
+ }
148
+
149
+ const CODE_SNIPPETS = {
150
+ checkbox: `<Controller
151
+ control={control}
152
+ name="newsletter"
153
+ render={({ field, fieldState }) => (
154
+ <>
155
+ <Checkbox
156
+ checked={!!field.value}
157
+ error={!!fieldState.error}
158
+ onChange={(event) => field.onChange(event.target.checked)}
159
+ requiredIndicator
160
+ text="Subscribe to newsletter"
161
+ />
162
+ {fieldState.error && <Body status="negative" text={fieldState.error.message} />}
163
+ </>
164
+ )}
165
+ rules={{ validate: (value) => value === true || "${REQUIRED_MESSAGE}" }}
166
+ />`,
167
+ date_picker: `<Controller
168
+ control={control}
169
+ name="startDate"
170
+ render={({ field, fieldState }) => (
171
+ <DatePicker
172
+ allowInput
173
+ defaultDate={field.value}
174
+ error={fieldState.error?.message}
175
+ initializeOnce
176
+ key={\`date-\${resetKey}\`}
177
+ label="Start Date"
178
+ onChange={(dateStr) => field.onChange(dateStr)}
179
+ pickerId="form-validation-start-date"
180
+ requiredIndicator
181
+ />
182
+ )}
183
+ rules={{ required: "Start date is required" }}
184
+ />`,
185
+ dropdown: `<Controller
186
+ control={control}
187
+ name="country"
188
+ render={({ field, fieldState }) => (
189
+ <Dropdown
190
+ error={fieldState.error?.message}
191
+ key={\`dropdown-\${resetKey}\`}
192
+ label="Country"
193
+ onChange={(event) => field.onChange(event.target.value)}
194
+ options={countryOptions}
195
+ requiredIndicator
196
+ value={field.value}
197
+ />
198
+ )}
199
+ rules={requireSelection("${REQUIRED_MESSAGE}")}
200
+ />`,
201
+ email_field: `<Controller
202
+ control={control}
203
+ name="email"
204
+ render={({ field, fieldState }) => (
205
+ <TextInput
206
+ error={fieldState.error?.message}
207
+ label="Email"
208
+ onChange={(event) => field.onChange(event.target.value)}
209
+ required
210
+ requiredIndicator
211
+ type="email"
212
+ value={field.value}
213
+ />
214
+ )}
215
+ rules={{ required: "Email is required" }}
216
+ />`,
217
+ multi_level_select: `<Controller
218
+ control={control}
219
+ name="department"
220
+ render={({ field, fieldState }) => (
221
+ <MultiLevelSelect
222
+ error={fieldState.error?.message}
223
+ id="mls-validation"
224
+ label="Department"
225
+ onChange={(event) =>
226
+ field.onChange(event.target.value.map((item) => item.id))
227
+ }
228
+ requiredIndicator
229
+ selectedIds={field.value}
230
+ treeData={departmentTreeData}
231
+ />
232
+ )}
233
+ rules={requireSelection("${REQUIRED_MESSAGE}")}
234
+ />`,
235
+ multi_select: `<Controller
236
+ control={control}
237
+ name="countries"
238
+ render={({ field, fieldState }) => (
239
+ <Dropdown
240
+ error={fieldState.error?.message}
241
+ key={\`multi-select-\${resetKey}\`}
242
+ label="Countries"
243
+ multiSelect
244
+ onChange={(event) => field.onChange(event.target.value)}
245
+ options={countryOptions}
246
+ requiredIndicator
247
+ value={field.value}
248
+ />
249
+ )}
250
+ rules={requireSelection("${REQUIRED_MESSAGE}")}
251
+ />`,
252
+ number_field: `<Controller
253
+ control={control}
254
+ name="quantity"
255
+ render={({ field, fieldState }) => (
256
+ <TextInput
257
+ error={fieldState.error?.message}
258
+ label="Quantity"
259
+ onChange={(event) => field.onChange(event.target.value)}
260
+ required
261
+ requiredIndicator
262
+ type="number"
263
+ value={field.value}
264
+ />
265
+ )}
266
+ rules={{ required: "Quantity is required" }}
267
+ />`,
268
+ password_field: `<Controller
269
+ control={control}
270
+ name="password"
271
+ render={({ field, fieldState }) => (
272
+ <TextInput
273
+ error={fieldState.error?.message}
274
+ label="Password"
275
+ onChange={(event) => field.onChange(event.target.value)}
276
+ required
277
+ requiredIndicator
278
+ type="password"
279
+ value={field.value}
280
+ />
281
+ )}
282
+ rules={{ required: "Password is required" }}
283
+ />`,
284
+ phone_number: `<Controller
285
+ control={control}
286
+ name="phone"
287
+ render={({ field, fieldState }) => (
288
+ <PhoneNumberInput
289
+ error={fieldState.error?.message}
290
+ initialCountry="us"
291
+ key={\`phone-\${resetKey}\`}
292
+ label="Phone Number"
293
+ onChange={(data) => field.onChange(data?.number || "")}
294
+ ref={phoneNumberRef}
295
+ required
296
+ requiredIndicator
297
+ />
298
+ )}
299
+ rules={{ validate: () => phoneNumberRef.current?.validate() ?? true }}
300
+ />`,
301
+ search_field: `<Controller
302
+ control={control}
303
+ name="projectNumber"
304
+ render={({ field, fieldState }) => (
305
+ <TextInput
306
+ error={fieldState.error?.message}
307
+ label="Project Number"
308
+ onChange={(event) => field.onChange(event.target.value)}
309
+ required
310
+ requiredIndicator
311
+ type="search"
312
+ value={field.value}
313
+ />
314
+ )}
315
+ rules={{
316
+ required: "Please enter a valid project number (example: 33-12345).",
317
+ pattern: {
318
+ value: /^[0-9]{2}-[0-9]{5}$/,
319
+ message: "Please enter a valid project number (example: 33-12345).",
320
+ },
321
+ }}
322
+ />`,
323
+ select: `<Controller
324
+ control={control}
325
+ name="favoriteColor"
326
+ render={({ field, fieldState }) => (
327
+ <Select
328
+ blankSelection="Select one..."
329
+ error={fieldState.error?.message}
330
+ key={\`select-\${resetKey}\`}
331
+ label="Favorite Color"
332
+ onChange={(event) => field.onChange(event.target.value)}
333
+ options={colorSelectOptions}
334
+ required
335
+ requiredIndicator
336
+ value={field.value}
337
+ />
338
+ )}
339
+ rules={{ required: "Please select a color" }}
340
+ />`,
341
+ star_rating: `// NOTE: resetField("rating") runs from an effect when this pill is
342
+ // deselected, because interactive StarRating keeps its own state and ignores
343
+ // the rating prop on remount. Without it, the required rule can pass for a
344
+ // control that looks blank.
345
+ <Controller
346
+ control={control}
347
+ name="rating"
348
+ render={({ field, fieldState }) => (
349
+ <>
350
+ <StarRating
351
+ key={\`rating-\${resetKey}\`}
352
+ label="Rating"
353
+ onClick={(value) => field.onChange(value)}
354
+ rating={field.value || 0}
355
+ variant="interactive"
356
+ />
357
+ {fieldState.error && <Body status="negative" text={fieldState.error.message} />}
358
+ </>
359
+ )}
360
+ rules={{ validate: (value) => Number(value) > 0 || "${REQUIRED_MESSAGE}" }}
361
+ />`,
362
+ text_field: `<Controller
363
+ control={control}
364
+ name="fullName"
365
+ render={({ field, fieldState }) => (
366
+ <TextInput
367
+ error={fieldState.error?.message}
368
+ label="Full Name"
369
+ onChange={(event) => field.onChange(event.target.value)}
370
+ required
371
+ requiredIndicator
372
+ value={field.value}
373
+ />
374
+ )}
375
+ rules={{ required: "Full name is required" }}
376
+ />`,
377
+ textarea: `<Controller
378
+ control={control}
379
+ name="bio"
380
+ render={({ field, fieldState }) => (
381
+ <Textarea
382
+ error={fieldState.error?.message}
383
+ label="Bio"
384
+ onChange={(event) => field.onChange(event.target.value)}
385
+ required
386
+ requiredIndicator
387
+ value={field.value}
388
+ />
389
+ )}
390
+ rules={{ required: "${REQUIRED_MESSAGE}" }}
391
+ />`,
392
+ time_picker: `// NOTE: TimePicker rehydrates from defaultTime={field.value} on remount, so
393
+ // no reset is needed when the pill is turned off and back on.
394
+ <Controller
395
+ control={control}
396
+ name="startTime"
397
+ render={({ field, fieldState }) => (
398
+ <TimePicker
399
+ defaultTime={field.value}
400
+ error={fieldState.error?.message}
401
+ key={\`time-\${resetKey}\`}
402
+ label="Start Time"
403
+ onChange={(time) => field.onChange(time)}
404
+ required
405
+ requiredIndicator
406
+ />
407
+ )}
408
+ rules={{ required: "Start time is required" }}
409
+ />`,
410
+ typeahead: `<Controller
411
+ control={control}
412
+ name="favoriteColors"
413
+ render={({ field: { onChange: handleChange, value }, fieldState }) => (
414
+ <Typeahead
415
+ error={fieldState.error?.message}
416
+ isMulti
417
+ label="Favorite Color"
418
+ onChange={handleChange}
419
+ options={typeaheadColorOptions}
420
+ pills
421
+ placeholder="Search for a color"
422
+ requiredIndicator
423
+ value={value}
424
+ />
425
+ )}
426
+ rules={requireSelection("Please select a color")}
427
+ />`,
428
+ typeahead_default: `<Controller
429
+ control={control}
430
+ name="favoriteColorSearch"
431
+ render={({ field: { onChange: handleChange, value }, fieldState }) => (
432
+ <Typeahead
433
+ error={fieldState.error?.message}
434
+ label="Favorite Color"
435
+ onChange={handleChange}
436
+ options={typeaheadColorOptions}
437
+ placeholder="Search for a color"
438
+ requiredIndicator
439
+ value={value}
440
+ />
441
+ )}
442
+ rules={requireSelection("Please select a color")}
443
+ />`,
444
+ url_field: `<Controller
445
+ control={control}
446
+ name="website"
447
+ render={({ field, fieldState }) => (
448
+ <TextInput
449
+ error={fieldState.error?.message}
450
+ label="Website"
451
+ onChange={(event) => field.onChange(event.target.value)}
452
+ required
453
+ requiredIndicator
454
+ type="url"
455
+ value={field.value}
456
+ />
457
+ )}
458
+ rules={{ required: "Website is required" }}
459
+ />`,
460
+ }
461
+
462
+ const FORM_OPEN = `const { control, handleSubmit, formState: { errors } } = useForm()
463
+
464
+ <form noValidate onSubmit={handleSubmit(onSubmit)}>`
465
+ const FORM_CLOSE = ` <Button htmlType="submit" text="Submit" />
466
+ <Button htmlType="button" onClick={onReset} text="Cancel" variant="secondary" />
467
+ </form>`
468
+
469
+ const FormValidation = () => {
470
+ const [selectedKeys, setSelectedKeys] = useState([DEFAULT_SELECTED_KEY])
471
+ const [submittedData, setSubmittedData] = useState(null)
472
+ const [resetKey, setResetKey] = useState(0)
473
+ const phoneNumberRef = useRef(null)
474
+ const {
475
+ control,
476
+ handleSubmit,
477
+ reset,
478
+ resetField,
479
+ getValues,
480
+ } = useForm({
481
+ defaultValues: {
482
+ bio: "",
483
+ department: [],
484
+ email: "",
485
+ favoriteColor: "",
486
+ favoriteColors: [],
487
+ favoriteColorSearch: null,
488
+ fullName: "",
489
+ password: "",
490
+ projectNumber: "",
491
+ quantity: "",
492
+ rating: 0,
493
+ website: "",
494
+ },
495
+ })
496
+
497
+ const isSelected = (key) => selectedKeys.includes(key)
498
+
499
+ // When a pill is turned off for a control that can't rehydrate on remount,
500
+ // clear its stored value so the next mount and the submitted payload agree
501
+ // (and so required rules can't pass for a control that looks blank).
502
+ useEffect(() => {
503
+ Object.entries(RESET_ON_DESELECT).forEach(([inputKey, fieldName]) => {
504
+ const stillSelected = selectedKeys.includes(inputKey)
505
+ const hasValue = getValues(fieldName) !== undefined && getValues(fieldName) !== null
506
+ if (!stillSelected && hasValue) resetField(fieldName)
507
+ })
508
+ }, [selectedKeys, getValues, resetField])
509
+
510
+ const toggleKey = (key) => {
511
+ setSelectedKeys((current) => {
512
+ if (!current.includes(key)) return [...current, key]
513
+ return current.length > 1 ? current.filter((selected) => selected !== key) : current
514
+ })
515
+ }
516
+
517
+ const handlePillKeyDown = (event, key) => {
518
+ if (event.key !== "Enter" && event.key !== " ") return
519
+ event.preventDefault()
520
+ toggleKey(key)
521
+ }
522
+
523
+ const onSubmit = (data) => {
524
+ // Dropdown stores the selected option node (or array of nodes for multi),
525
+ // and MultiLevelSelect stores selected ids. Translate each back into the
526
+ // human-readable `value`s so the submitted payload is primitives, not
527
+ // kit-internal shapes.
528
+ const normalized = {
529
+ ...data,
530
+ country:
531
+ data.country && typeof data.country === "object"
532
+ ? data.country.value ?? data.country.label
533
+ : data.country,
534
+ countries: Array.isArray(data.countries)
535
+ ? data.countries.map((node) =>
536
+ node && typeof node === "object" ? node.value ?? node.label : node
537
+ )
538
+ : data.countries,
539
+ department: Array.isArray(data.department)
540
+ ? data.department.map((id) => findNodeById(DEPARTMENT_TREE_DATA, id)?.value ?? id)
541
+ : data.department,
542
+ }
543
+
544
+ // Fields that are deselected stay mounted (we removed shouldUnregister)
545
+ // so we filter them out here rather than letting RHF drop their values.
546
+ const filtered = Object.fromEntries(
547
+ Object.entries(normalized).filter(([fieldName]) => {
548
+ const inputKey = FIELD_TO_INPUT_KEY[fieldName]
549
+ return inputKey ? isSelected(inputKey) : true
550
+ })
551
+ )
552
+ setSubmittedData(filtered)
553
+ }
554
+
555
+ const onReset = () => {
556
+ reset()
557
+ setResetKey((current) => current + 1)
558
+ setSubmittedData(null)
559
+ }
560
+
561
+ const codePreview = [FORM_OPEN]
562
+ .concat(INPUT_TYPES.filter((inputType) => isSelected(inputType.key)).map((inputType) => CODE_SNIPPETS[inputType.key]))
563
+ .concat([FORM_CLOSE])
564
+ .join("\n\n")
565
+
566
+ return (
567
+ <div>
568
+ <Body color="light"
569
+ marginBottom="xs"
570
+ text="Select one or more inputs to add them to the form."
571
+ />
572
+ <Flex gap="xs"
573
+ marginBottom="md"
574
+ wrap
575
+ >
576
+ {INPUT_TYPES.map((inputType) => (
577
+ <Pill
578
+ htmlOptions={{
579
+ onClick: () => toggleKey(inputType.key),
580
+ onKeyDown: (event) => handlePillKeyDown(event, inputType.key),
581
+ role: "button",
582
+ style: { cursor: "pointer" },
583
+ tabIndex: 0,
584
+ }}
585
+ key={inputType.key}
586
+ text={inputType.label}
587
+ textTransform="none"
588
+ variant={isSelected(inputType.key) ? "primary" : "neutral"}
589
+ />
590
+ ))}
591
+ </Flex>
592
+
593
+ <Flex align="stretch"
594
+ gap="md"
595
+ wrap
596
+ >
597
+ <Flex
598
+ align="stretch"
599
+ htmlOptions={{ style: { flex: "2 1" } }}
600
+ orientation="column"
601
+ >
602
+ <Card
603
+ htmlOptions={{ style: { minWidth: 0 } }}
604
+ padding="md"
605
+ shadow="deep"
606
+ >
607
+ <form noValidate
608
+ onSubmit={handleSubmit(onSubmit)}
609
+ >
610
+ {isSelected("checkbox") && (
611
+ <Controller
612
+ control={control}
613
+ name="newsletter"
614
+ render={({ field, fieldState }) => (
615
+ <>
616
+ <Checkbox
617
+ checked={!!field.value}
618
+ error={!!fieldState.error}
619
+ marginBottom="sm"
620
+ onChange={(event) => field.onChange(event.target.checked)}
621
+ requiredIndicator
622
+ text="Subscribe to newsletter"
623
+ />
624
+ {fieldState.error && (
625
+ <Body
626
+ marginBottom="sm"
627
+ status="negative"
628
+ text={fieldState.error.message}
629
+ />
630
+ )}
631
+ </>
632
+ )}
633
+ rules={{ validate: (value) => value === true || REQUIRED_MESSAGE }}
634
+ />
635
+ )}
636
+
637
+ {isSelected("date_picker") && (
638
+ <Controller
639
+ control={control}
640
+ name="startDate"
641
+ render={({ field, fieldState }) => (
642
+ <DatePicker
643
+ allowInput
644
+ defaultDate={field.value}
645
+ error={fieldState.error?.message}
646
+ initializeOnce
647
+ key={`date-${resetKey}`}
648
+ label="Start Date"
649
+ marginBottom="sm"
650
+ onChange={(dateStr) => field.onChange(dateStr)}
651
+ pickerId="form-validation-start-date"
652
+ requiredIndicator
653
+ />
654
+ )}
655
+ rules={{ required: "Start date is required" }}
656
+ />
657
+ )}
658
+
659
+ {isSelected("dropdown") && (
660
+ <Controller
661
+ control={control}
662
+ name="country"
663
+ render={({ field, fieldState }) => (
664
+ <Dropdown
665
+ error={fieldState.error?.message}
666
+ key={`dropdown-${resetKey}`}
667
+ label="Country"
668
+ marginBottom="sm"
669
+ onChange={(event) => field.onChange(event.target.value)}
670
+ options={COUNTRY_OPTIONS}
671
+ requiredIndicator
672
+ value={field.value}
673
+ />
674
+ )}
675
+ rules={requireSelection(REQUIRED_MESSAGE)}
676
+ />
677
+ )}
678
+
679
+ {isSelected("multi_select") && (
680
+ <Controller
681
+ control={control}
682
+ name="countries"
683
+ render={({ field, fieldState }) => (
684
+ <Dropdown
685
+ error={fieldState.error?.message}
686
+ key={`multi-select-${resetKey}`}
687
+ label="Countries"
688
+ marginBottom="sm"
689
+ multiSelect
690
+ onChange={(event) => field.onChange(event.target.value)}
691
+ options={COUNTRY_OPTIONS}
692
+ requiredIndicator
693
+ value={field.value}
694
+ />
695
+ )}
696
+ rules={requireSelection(REQUIRED_MESSAGE)}
697
+ />
698
+ )}
699
+
700
+ {isSelected("multi_level_select") && (
701
+ <Controller
702
+ control={control}
703
+ name="department"
704
+ render={({ field, fieldState }) => (
705
+ <MultiLevelSelect
706
+ error={fieldState.error?.message}
707
+ id="mls-validation"
708
+ label="Department"
709
+ marginBottom="sm"
710
+ onChange={(event) =>
711
+ field.onChange(event.target.value.map((item) => item.id))
712
+ }
713
+ requiredIndicator
714
+ selectedIds={field.value}
715
+ treeData={DEPARTMENT_TREE_DATA}
716
+ />
717
+ )}
718
+ rules={requireSelection(REQUIRED_MESSAGE)}
719
+ />
720
+ )}
721
+
722
+ {isSelected("phone_number") && (
723
+ <Controller
724
+ control={control}
725
+ name="phone"
726
+ render={({ field, fieldState }) => (
727
+ <PhoneNumberInput
728
+ error={fieldState.error?.message}
729
+ initialCountry="us"
730
+ key={`phone-${resetKey}`}
731
+ label="Phone Number"
732
+ onChange={(data) => field.onChange(data?.number || "")}
733
+ ref={phoneNumberRef}
734
+ required
735
+ requiredIndicator
736
+ />
737
+ )}
738
+ rules={{ validate: () => phoneNumberRef.current?.validate() ?? true }}
739
+ />
740
+ )}
741
+
742
+ {isSelected("select") && (
743
+ <Controller
744
+ control={control}
745
+ name="favoriteColor"
746
+ render={({ field, fieldState }) => (
747
+ <Select
748
+ blankSelection="Select one..."
749
+ error={fieldState.error?.message}
750
+ key={`select-${resetKey}`}
751
+ label="Favorite Color"
752
+ marginBottom="sm"
753
+ onChange={(event) => field.onChange(event.target.value)}
754
+ options={COLOR_SELECT_OPTIONS}
755
+ required
756
+ requiredIndicator
757
+ value={field.value}
758
+ />
759
+ )}
760
+ rules={{ required: "Please select a color" }}
761
+ />
762
+ )}
763
+
764
+ {isSelected("star_rating") && (
765
+ <Controller
766
+ control={control}
767
+ name="rating"
768
+ render={({ field, fieldState }) => (
769
+ <>
770
+ <StarRating
771
+ key={`rating-${resetKey}`}
772
+ label="Rating"
773
+ marginBottom="sm"
774
+ onClick={(value) => field.onChange(value)}
775
+ rating={field.value || 0}
776
+ variant="interactive"
777
+ />
778
+ {fieldState.error && (
779
+ <Body
780
+ marginBottom="sm"
781
+ status="negative"
782
+ text={fieldState.error.message}
783
+ />
784
+ )}
785
+ </>
786
+ )}
787
+ rules={{ validate: (value) => Number(value) > 0 || REQUIRED_MESSAGE }}
788
+ />
789
+ )}
790
+
791
+ {isSelected("text_field") && (
792
+ <Controller
793
+ control={control}
794
+ name="fullName"
795
+ render={({ field, fieldState }) => (
796
+ <TextInput
797
+ error={fieldState.error?.message}
798
+ label="Full Name"
799
+ marginBottom="sm"
800
+ onChange={(event) => field.onChange(event.target.value)}
801
+ required
802
+ requiredIndicator
803
+ value={field.value}
804
+ />
805
+ )}
806
+ rules={{ required: "Full name is required" }}
807
+ />
808
+ )}
809
+
810
+ {isSelected("email_field") && (
811
+ <Controller
812
+ control={control}
813
+ name="email"
814
+ render={({ field, fieldState }) => (
815
+ <TextInput
816
+ error={fieldState.error?.message}
817
+ label="Email"
818
+ marginBottom="sm"
819
+ onChange={(event) => field.onChange(event.target.value)}
820
+ required
821
+ requiredIndicator
822
+ type="email"
823
+ value={field.value}
824
+ />
825
+ )}
826
+ rules={{ required: "Email is required" }}
827
+ />
828
+ )}
829
+
830
+ {isSelected("number_field") && (
831
+ <Controller
832
+ control={control}
833
+ name="quantity"
834
+ render={({ field, fieldState }) => (
835
+ <TextInput
836
+ error={fieldState.error?.message}
837
+ label="Quantity"
838
+ marginBottom="sm"
839
+ onChange={(event) => field.onChange(event.target.value)}
840
+ required
841
+ requiredIndicator
842
+ type="number"
843
+ value={field.value}
844
+ />
845
+ )}
846
+ rules={{ required: "Quantity is required" }}
847
+ />
848
+ )}
849
+
850
+ {isSelected("password_field") && (
851
+ <Controller
852
+ control={control}
853
+ name="password"
854
+ render={({ field, fieldState }) => (
855
+ <TextInput
856
+ error={fieldState.error?.message}
857
+ label="Password"
858
+ marginBottom="sm"
859
+ onChange={(event) => field.onChange(event.target.value)}
860
+ required
861
+ requiredIndicator
862
+ type="password"
863
+ value={field.value}
864
+ />
865
+ )}
866
+ rules={{ required: "Password is required" }}
867
+ />
868
+ )}
869
+
870
+ {isSelected("search_field") && (
871
+ <Controller
872
+ control={control}
873
+ name="projectNumber"
874
+ render={({ field, fieldState }) => (
875
+ <TextInput
876
+ error={fieldState.error?.message}
877
+ label="Project Number"
878
+ marginBottom="sm"
879
+ onChange={(event) => field.onChange(event.target.value)}
880
+ required
881
+ requiredIndicator
882
+ type="search"
883
+ value={field.value}
884
+ />
885
+ )}
886
+ rules={{
887
+ pattern: {
888
+ message: "Please enter a valid project number (example: 33-12345).",
889
+ value: /^[0-9]{2}-[0-9]{5}$/,
890
+ },
891
+ required: "Please enter a valid project number (example: 33-12345).",
892
+ }}
893
+ />
894
+ )}
895
+
896
+ {isSelected("url_field") && (
897
+ <Controller
898
+ control={control}
899
+ name="website"
900
+ render={({ field, fieldState }) => (
901
+ <TextInput
902
+ error={fieldState.error?.message}
903
+ label="Website"
904
+ marginBottom="sm"
905
+ onChange={(event) => field.onChange(event.target.value)}
906
+ required
907
+ requiredIndicator
908
+ type="url"
909
+ value={field.value}
910
+ />
911
+ )}
912
+ rules={{ required: "Website is required" }}
913
+ />
914
+ )}
915
+
916
+ {isSelected("textarea") && (
917
+ <Controller
918
+ control={control}
919
+ name="bio"
920
+ render={({ field, fieldState }) => (
921
+ <Textarea
922
+ error={fieldState.error?.message}
923
+ label="Bio"
924
+ marginBottom="sm"
925
+ onChange={(event) => field.onChange(event.target.value)}
926
+ required
927
+ requiredIndicator
928
+ value={field.value}
929
+ />
930
+ )}
931
+ rules={{ required: REQUIRED_MESSAGE }}
932
+ />
933
+ )}
934
+
935
+ {isSelected("time_picker") && (
936
+ <Controller
937
+ control={control}
938
+ name="startTime"
939
+ render={({ field, fieldState }) => (
940
+ <TimePicker
941
+ defaultTime={field.value}
942
+ error={fieldState.error?.message}
943
+ key={`time-${resetKey}`}
944
+ label="Start Time"
945
+ marginBottom="sm"
946
+ onChange={(time) => field.onChange(time)}
947
+ required
948
+ requiredIndicator
949
+ />
950
+ )}
951
+ rules={{ required: "Start time is required" }}
952
+ />
953
+ )}
954
+
955
+ {isSelected("typeahead_default") && (
956
+ <Controller
957
+ control={control}
958
+ name="favoriteColorSearch"
959
+ render={({ field: { onChange: handleChange, value }, fieldState }) => (
960
+ <Typeahead
961
+ error={fieldState.error?.message}
962
+ label="Favorite Color"
963
+ marginBottom="sm"
964
+ onChange={handleChange}
965
+ options={TYPEAHEAD_COLOR_OPTIONS}
966
+ placeholder="Search for a color"
967
+ requiredIndicator
968
+ value={value}
969
+ />
970
+ )}
971
+ rules={requireSelection("Please select a color")}
972
+ />
973
+ )}
974
+
975
+ {isSelected("typeahead") && (
976
+ <Controller
977
+ control={control}
978
+ name="favoriteColors"
979
+ render={({ field: { onChange: handleChange, value }, fieldState }) => (
980
+ <Typeahead
981
+ error={fieldState.error?.message}
982
+ isMulti
983
+ label="Favorite Color"
984
+ marginBottom="sm"
985
+ onChange={handleChange}
986
+ options={TYPEAHEAD_COLOR_OPTIONS}
987
+ pills
988
+ placeholder="Search for a color"
989
+ requiredIndicator
990
+ value={value}
991
+ />
992
+ )}
993
+ rules={requireSelection("Please select a color")}
994
+ />
995
+ )}
996
+
997
+ <Flex gap="xs"
998
+ marginTop="sm"
999
+ >
1000
+ <Button htmlType="submit"
1001
+ text="Submit"
1002
+ />
1003
+ <Button
1004
+ htmlType="button"
1005
+ onClick={onReset}
1006
+ text="Cancel"
1007
+ variant="secondary"
1008
+ />
1009
+ </Flex>
1010
+ </form>
1011
+ </Card>
1012
+ </Flex>
1013
+
1014
+ <Flex
1015
+ align="stretch"
1016
+ htmlOptions={{ style: { flex: "1 1" } }}
1017
+ orientation="column"
1018
+ >
1019
+ <Caption marginBottom="xs"
1020
+ text="Submitted Form Data"
1021
+ />
1022
+ <Card background="light"
1023
+ padding="md"
1024
+ >
1025
+ {submittedData ? (
1026
+ <pre style={{ fontSize: "12px", lineHeight: 1.5, margin: 0, overflow: "auto", whiteSpace: "pre-wrap" }}>
1027
+ {JSON.stringify(submittedData, null, 2)}
1028
+ </pre>
1029
+ ) : (
1030
+ <Body color="light"
1031
+ text="No data submitted yet."
1032
+ />
1033
+ )}
1034
+ </Card>
1035
+ </Flex>
1036
+ </Flex>
1037
+
1038
+ <Body
1039
+ color="light"
1040
+ marginBottom="sm"
1041
+ marginTop="sm"
1042
+ text="Submit an empty form to see error states. A valid form shows its data on the right."
1043
+ />
1044
+
1045
+ <Card background="dark"
1046
+ dark
1047
+ padding="none"
1048
+ >
1049
+ <pre style={{ fontSize: "12px", lineHeight: 1.5, margin: 0, overflow: "auto", padding: "16px", whiteSpace: "pre" }}>
1050
+ {codePreview}
1051
+ </pre>
1052
+ </Card>
1053
+ </div>
1054
+ )
1055
+ }
1056
+
1057
+ export default FormValidation