phlex_kit 0.2.0

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 (405) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README.md +135 -0
  4. data/app/assets/stylesheets/phlex_kit/_tokens.css +91 -0
  5. data/app/assets/stylesheets/phlex_kit/phlex_kit.css +82 -0
  6. data/app/components/phlex_kit/accordion/accordion.css +14 -0
  7. data/app/components/phlex_kit/accordion/accordion.rb +10 -0
  8. data/app/components/phlex_kit/accordion/accordion_content.rb +8 -0
  9. data/app/components/phlex_kit/accordion/accordion_default_content.rb +6 -0
  10. data/app/components/phlex_kit/accordion/accordion_default_trigger.rb +12 -0
  11. data/app/components/phlex_kit/accordion/accordion_icon.rb +16 -0
  12. data/app/components/phlex_kit/accordion/accordion_item.rb +12 -0
  13. data/app/components/phlex_kit/accordion/accordion_trigger.rb +8 -0
  14. data/app/components/phlex_kit/alert/alert.css +32 -0
  15. data/app/components/phlex_kit/alert/alert.rb +37 -0
  16. data/app/components/phlex_kit/alert/alert_description.rb +12 -0
  17. data/app/components/phlex_kit/alert/alert_title.rb +12 -0
  18. data/app/components/phlex_kit/alert_dialog/alert_dialog.css +37 -0
  19. data/app/components/phlex_kit/alert_dialog/alert_dialog.rb +20 -0
  20. data/app/components/phlex_kit/alert_dialog/alert_dialog_action.rb +14 -0
  21. data/app/components/phlex_kit/alert_dialog/alert_dialog_cancel.rb +13 -0
  22. data/app/components/phlex_kit/alert_dialog/alert_dialog_content.rb +19 -0
  23. data/app/components/phlex_kit/alert_dialog/alert_dialog_description.rb +12 -0
  24. data/app/components/phlex_kit/alert_dialog/alert_dialog_footer.rb +12 -0
  25. data/app/components/phlex_kit/alert_dialog/alert_dialog_header.rb +12 -0
  26. data/app/components/phlex_kit/alert_dialog/alert_dialog_title.rb +12 -0
  27. data/app/components/phlex_kit/alert_dialog/alert_dialog_trigger.rb +12 -0
  28. data/app/components/phlex_kit/aspect_ratio/aspect_ratio.css +12 -0
  29. data/app/components/phlex_kit/aspect_ratio/aspect_ratio.rb +27 -0
  30. data/app/components/phlex_kit/attachment/attachment.css +62 -0
  31. data/app/components/phlex_kit/attachment/attachment.rb +16 -0
  32. data/app/components/phlex_kit/attachment/attachment_action.rb +24 -0
  33. data/app/components/phlex_kit/attachment/attachment_actions.rb +7 -0
  34. data/app/components/phlex_kit/attachment/attachment_content.rb +7 -0
  35. data/app/components/phlex_kit/attachment/attachment_description.rb +7 -0
  36. data/app/components/phlex_kit/attachment/attachment_media.rb +8 -0
  37. data/app/components/phlex_kit/attachment/attachment_title.rb +7 -0
  38. data/app/components/phlex_kit/avatar/avatar.css +35 -0
  39. data/app/components/phlex_kit/avatar/avatar.rb +25 -0
  40. data/app/components/phlex_kit/avatar/avatar_fallback.rb +13 -0
  41. data/app/components/phlex_kit/avatar/avatar_group.rb +7 -0
  42. data/app/components/phlex_kit/avatar/avatar_image.rb +24 -0
  43. data/app/components/phlex_kit/badge/badge.css +50 -0
  44. data/app/components/phlex_kit/badge/badge.rb +39 -0
  45. data/app/components/phlex_kit/breadcrumb/breadcrumb.css +18 -0
  46. data/app/components/phlex_kit/breadcrumb/breadcrumb.rb +8 -0
  47. data/app/components/phlex_kit/breadcrumb/breadcrumb_ellipsis.rb +15 -0
  48. data/app/components/phlex_kit/breadcrumb/breadcrumb_item.rb +6 -0
  49. data/app/components/phlex_kit/breadcrumb/breadcrumb_link.rb +9 -0
  50. data/app/components/phlex_kit/breadcrumb/breadcrumb_list.rb +6 -0
  51. data/app/components/phlex_kit/breadcrumb/breadcrumb_page.rb +8 -0
  52. data/app/components/phlex_kit/breadcrumb/breadcrumb_separator.rb +10 -0
  53. data/app/components/phlex_kit/bubble/bubble.css +32 -0
  54. data/app/components/phlex_kit/bubble/bubble.rb +17 -0
  55. data/app/components/phlex_kit/bubble/bubble_content.rb +11 -0
  56. data/app/components/phlex_kit/bubble/bubble_group.rb +6 -0
  57. data/app/components/phlex_kit/bubble/bubble_reactions.rb +12 -0
  58. data/app/components/phlex_kit/button/button.css +72 -0
  59. data/app/components/phlex_kit/button/button.rb +51 -0
  60. data/app/components/phlex_kit/button_group/button_group.css +8 -0
  61. data/app/components/phlex_kit/button_group/button_group.rb +14 -0
  62. data/app/components/phlex_kit/calendar/calendar.css +109 -0
  63. data/app/components/phlex_kit/calendar/calendar.rb +47 -0
  64. data/app/components/phlex_kit/calendar/calendar_body.rb +13 -0
  65. data/app/components/phlex_kit/calendar/calendar_days.rb +98 -0
  66. data/app/components/phlex_kit/calendar/calendar_header.rb +13 -0
  67. data/app/components/phlex_kit/calendar/calendar_next.rb +40 -0
  68. data/app/components/phlex_kit/calendar/calendar_prev.rb +40 -0
  69. data/app/components/phlex_kit/calendar/calendar_title.rb +19 -0
  70. data/app/components/phlex_kit/calendar/calendar_weekdays.rb +27 -0
  71. data/app/components/phlex_kit/card/card.css +15 -0
  72. data/app/components/phlex_kit/card/card.rb +29 -0
  73. data/app/components/phlex_kit/card/card_content.rb +12 -0
  74. data/app/components/phlex_kit/card/card_description.rb +12 -0
  75. data/app/components/phlex_kit/card/card_footer.rb +12 -0
  76. data/app/components/phlex_kit/card/card_header.rb +12 -0
  77. data/app/components/phlex_kit/card/card_title.rb +12 -0
  78. data/app/components/phlex_kit/carousel/carousel.css +41 -0
  79. data/app/components/phlex_kit/carousel/carousel.rb +37 -0
  80. data/app/components/phlex_kit/carousel/carousel_content.rb +16 -0
  81. data/app/components/phlex_kit/carousel/carousel_item.rb +17 -0
  82. data/app/components/phlex_kit/carousel/carousel_next.rb +39 -0
  83. data/app/components/phlex_kit/carousel/carousel_previous.rb +40 -0
  84. data/app/components/phlex_kit/chart/chart.css +9 -0
  85. data/app/components/phlex_kit/chart/chart.rb +31 -0
  86. data/app/components/phlex_kit/checkbox/checkbox.css +27 -0
  87. data/app/components/phlex_kit/checkbox/checkbox.rb +26 -0
  88. data/app/components/phlex_kit/clipboard/clipboard.css +8 -0
  89. data/app/components/phlex_kit/clipboard/clipboard.rb +19 -0
  90. data/app/components/phlex_kit/clipboard/clipboard_popover.rb +14 -0
  91. data/app/components/phlex_kit/clipboard/clipboard_source.rb +6 -0
  92. data/app/components/phlex_kit/clipboard/clipboard_trigger.rb +6 -0
  93. data/app/components/phlex_kit/codeblock/codeblock.css +7 -0
  94. data/app/components/phlex_kit/codeblock/codeblock.rb +23 -0
  95. data/app/components/phlex_kit/collapsible/collapsible.css +3 -0
  96. data/app/components/phlex_kit/collapsible/collapsible.rb +13 -0
  97. data/app/components/phlex_kit/collapsible/collapsible_content.rb +8 -0
  98. data/app/components/phlex_kit/collapsible/collapsible_trigger.rb +8 -0
  99. data/app/components/phlex_kit/combobox/combobox.css +310 -0
  100. data/app/components/phlex_kit/combobox/combobox.rb +33 -0
  101. data/app/components/phlex_kit/combobox/combobox_badge.rb +15 -0
  102. data/app/components/phlex_kit/combobox/combobox_badge_trigger.rb +55 -0
  103. data/app/components/phlex_kit/combobox/combobox_checkbox.rb +21 -0
  104. data/app/components/phlex_kit/combobox/combobox_clear_button.rb +39 -0
  105. data/app/components/phlex_kit/combobox/combobox_empty_state.rb +17 -0
  106. data/app/components/phlex_kit/combobox/combobox_input_trigger.rb +69 -0
  107. data/app/components/phlex_kit/combobox/combobox_item.rb +19 -0
  108. data/app/components/phlex_kit/combobox/combobox_item_indicator.rb +27 -0
  109. data/app/components/phlex_kit/combobox/combobox_list.rb +12 -0
  110. data/app/components/phlex_kit/combobox/combobox_list_group.rb +14 -0
  111. data/app/components/phlex_kit/combobox/combobox_popover.rb +27 -0
  112. data/app/components/phlex_kit/combobox/combobox_radio.rb +26 -0
  113. data/app/components/phlex_kit/combobox/combobox_search_input.rb +49 -0
  114. data/app/components/phlex_kit/combobox/combobox_toggle_all_checkbox.rb +21 -0
  115. data/app/components/phlex_kit/combobox/combobox_trigger.rb +48 -0
  116. data/app/components/phlex_kit/command/command.css +104 -0
  117. data/app/components/phlex_kit/command/command.rb +18 -0
  118. data/app/components/phlex_kit/command/command_dialog.rb +19 -0
  119. data/app/components/phlex_kit/command/command_dialog_content.rb +37 -0
  120. data/app/components/phlex_kit/command/command_dialog_trigger.rb +22 -0
  121. data/app/components/phlex_kit/command/command_empty.rb +17 -0
  122. data/app/components/phlex_kit/command/command_group.rb +32 -0
  123. data/app/components/phlex_kit/command/command_input.rb +56 -0
  124. data/app/components/phlex_kit/command/command_item.rb +22 -0
  125. data/app/components/phlex_kit/command/command_list.rb +12 -0
  126. data/app/components/phlex_kit/context_menu/context_menu.css +19 -0
  127. data/app/components/phlex_kit/context_menu/context_menu.rb +11 -0
  128. data/app/components/phlex_kit/context_menu/context_menu_content.rb +8 -0
  129. data/app/components/phlex_kit/context_menu/context_menu_item.rb +25 -0
  130. data/app/components/phlex_kit/context_menu/context_menu_label.rb +11 -0
  131. data/app/components/phlex_kit/context_menu/context_menu_separator.rb +8 -0
  132. data/app/components/phlex_kit/context_menu/context_menu_trigger.rb +8 -0
  133. data/app/components/phlex_kit/data_table/data_table.css +110 -0
  134. data/app/components/phlex_kit/data_table/data_table.rb +25 -0
  135. data/app/components/phlex_kit/data_table/data_table_bulk_actions.rb +15 -0
  136. data/app/components/phlex_kit/data_table/data_table_column_toggle.rb +61 -0
  137. data/app/components/phlex_kit/data_table/data_table_expand_toggle.rb +40 -0
  138. data/app/components/phlex_kit/data_table/data_table_form.rb +36 -0
  139. data/app/components/phlex_kit/data_table/data_table_kaminari_adapter.rb +17 -0
  140. data/app/components/phlex_kit/data_table/data_table_manual_adapter.rb +18 -0
  141. data/app/components/phlex_kit/data_table/data_table_pagination.rb +98 -0
  142. data/app/components/phlex_kit/data_table/data_table_pagination_bar.rb +13 -0
  143. data/app/components/phlex_kit/data_table/data_table_pagy_adapter.rb +17 -0
  144. data/app/components/phlex_kit/data_table/data_table_per_page_select.rb +29 -0
  145. data/app/components/phlex_kit/data_table/data_table_row_checkbox.rb +24 -0
  146. data/app/components/phlex_kit/data_table/data_table_search.rb +51 -0
  147. data/app/components/phlex_kit/data_table/data_table_select_all_checkbox.rb +19 -0
  148. data/app/components/phlex_kit/data_table/data_table_selection_summary.rb +19 -0
  149. data/app/components/phlex_kit/data_table/data_table_sort_head.rb +82 -0
  150. data/app/components/phlex_kit/data_table/data_table_toolbar.rb +13 -0
  151. data/app/components/phlex_kit/date_picker/date_picker.css +28 -0
  152. data/app/components/phlex_kit/date_picker/date_picker.rb +71 -0
  153. data/app/components/phlex_kit/dialog/dialog.css +32 -0
  154. data/app/components/phlex_kit/dialog/dialog.rb +14 -0
  155. data/app/components/phlex_kit/dialog/dialog_content.rb +21 -0
  156. data/app/components/phlex_kit/dialog/dialog_description.rb +6 -0
  157. data/app/components/phlex_kit/dialog/dialog_footer.rb +6 -0
  158. data/app/components/phlex_kit/dialog/dialog_header.rb +6 -0
  159. data/app/components/phlex_kit/dialog/dialog_middle.rb +6 -0
  160. data/app/components/phlex_kit/dialog/dialog_title.rb +6 -0
  161. data/app/components/phlex_kit/dialog/dialog_trigger.rb +8 -0
  162. data/app/components/phlex_kit/drawer/drawer.css +54 -0
  163. data/app/components/phlex_kit/drawer/drawer.rb +18 -0
  164. data/app/components/phlex_kit/drawer/drawer_close.rb +9 -0
  165. data/app/components/phlex_kit/drawer/drawer_content.rb +21 -0
  166. data/app/components/phlex_kit/drawer/drawer_description.rb +7 -0
  167. data/app/components/phlex_kit/drawer/drawer_footer.rb +7 -0
  168. data/app/components/phlex_kit/drawer/drawer_header.rb +7 -0
  169. data/app/components/phlex_kit/drawer/drawer_title.rb +7 -0
  170. data/app/components/phlex_kit/drawer/drawer_trigger.rb +9 -0
  171. data/app/components/phlex_kit/dropdown_menu/dropdown_menu.css +38 -0
  172. data/app/components/phlex_kit/dropdown_menu/dropdown_menu.rb +22 -0
  173. data/app/components/phlex_kit/dropdown_menu/dropdown_menu_content.rb +23 -0
  174. data/app/components/phlex_kit/dropdown_menu/dropdown_menu_item.rb +22 -0
  175. data/app/components/phlex_kit/dropdown_menu/dropdown_menu_label.rb +12 -0
  176. data/app/components/phlex_kit/dropdown_menu/dropdown_menu_separator.rb +12 -0
  177. data/app/components/phlex_kit/dropdown_menu/dropdown_menu_trigger.rb +15 -0
  178. data/app/components/phlex_kit/empty/empty.css +25 -0
  179. data/app/components/phlex_kit/empty/empty.rb +6 -0
  180. data/app/components/phlex_kit/empty/empty_content.rb +6 -0
  181. data/app/components/phlex_kit/empty/empty_description.rb +6 -0
  182. data/app/components/phlex_kit/empty/empty_header.rb +6 -0
  183. data/app/components/phlex_kit/empty/empty_media.rb +14 -0
  184. data/app/components/phlex_kit/empty/empty_title.rb +6 -0
  185. data/app/components/phlex_kit/form/form.css +15 -0
  186. data/app/components/phlex_kit/form/form.rb +27 -0
  187. data/app/components/phlex_kit/form_field/form_field.css +31 -0
  188. data/app/components/phlex_kit/form_field/form_field.rb +31 -0
  189. data/app/components/phlex_kit/form_field/form_field_error.rb +19 -0
  190. data/app/components/phlex_kit/form_field/form_field_hint.rb +13 -0
  191. data/app/components/phlex_kit/form_field/form_field_label.rb +13 -0
  192. data/app/components/phlex_kit/hover_card/hover_card.css +8 -0
  193. data/app/components/phlex_kit/hover_card/hover_card.rb +10 -0
  194. data/app/components/phlex_kit/hover_card/hover_card_content.rb +8 -0
  195. data/app/components/phlex_kit/hover_card/hover_card_trigger.rb +6 -0
  196. data/app/components/phlex_kit/input/input.css +29 -0
  197. data/app/components/phlex_kit/input/input.rb +34 -0
  198. data/app/components/phlex_kit/input_group/input_group.css +35 -0
  199. data/app/components/phlex_kit/input_group/input_group.rb +15 -0
  200. data/app/components/phlex_kit/input_group/input_group_addon.rb +16 -0
  201. data/app/components/phlex_kit/input_group/input_group_text.rb +7 -0
  202. data/app/components/phlex_kit/input_otp/input_otp.css +32 -0
  203. data/app/components/phlex_kit/input_otp/input_otp.rb +29 -0
  204. data/app/components/phlex_kit/input_otp/input_otp_group.rb +7 -0
  205. data/app/components/phlex_kit/input_otp/input_otp_separator.rb +7 -0
  206. data/app/components/phlex_kit/input_otp/input_otp_slot.rb +27 -0
  207. data/app/components/phlex_kit/item/item.css +32 -0
  208. data/app/components/phlex_kit/item/item.rb +18 -0
  209. data/app/components/phlex_kit/item/item_actions.rb +7 -0
  210. data/app/components/phlex_kit/item/item_content.rb +7 -0
  211. data/app/components/phlex_kit/item/item_description.rb +7 -0
  212. data/app/components/phlex_kit/item/item_group.rb +7 -0
  213. data/app/components/phlex_kit/item/item_media.rb +7 -0
  214. data/app/components/phlex_kit/item/item_title.rb +7 -0
  215. data/app/components/phlex_kit/kbd/kbd.css +17 -0
  216. data/app/components/phlex_kit/kbd/kbd.rb +14 -0
  217. data/app/components/phlex_kit/kbd/kbd_group.rb +12 -0
  218. data/app/components/phlex_kit/label/label.css +12 -0
  219. data/app/components/phlex_kit/label/label.rb +14 -0
  220. data/app/components/phlex_kit/link/link.css +6 -0
  221. data/app/components/phlex_kit/link/link.rb +47 -0
  222. data/app/components/phlex_kit/masked_input/masked_input.rb +12 -0
  223. data/app/components/phlex_kit/menubar/menubar.css +66 -0
  224. data/app/components/phlex_kit/menubar/menubar.rb +24 -0
  225. data/app/components/phlex_kit/menubar/menubar_content.rb +9 -0
  226. data/app/components/phlex_kit/menubar/menubar_item.rb +26 -0
  227. data/app/components/phlex_kit/menubar/menubar_menu.rb +9 -0
  228. data/app/components/phlex_kit/menubar/menubar_separator.rb +7 -0
  229. data/app/components/phlex_kit/menubar/menubar_trigger.rb +14 -0
  230. data/app/components/phlex_kit/message/message.css +20 -0
  231. data/app/components/phlex_kit/message/message.rb +14 -0
  232. data/app/components/phlex_kit/message/message_avatar.rb +6 -0
  233. data/app/components/phlex_kit/message/message_content.rb +6 -0
  234. data/app/components/phlex_kit/message/message_footer.rb +6 -0
  235. data/app/components/phlex_kit/message/message_group.rb +6 -0
  236. data/app/components/phlex_kit/message/message_header.rb +6 -0
  237. data/app/components/phlex_kit/message_scroller/message_scroller.css +2 -0
  238. data/app/components/phlex_kit/message_scroller/message_scroller.rb +11 -0
  239. data/app/components/phlex_kit/native_select/native_select.css +51 -0
  240. data/app/components/phlex_kit/native_select/native_select.rb +48 -0
  241. data/app/components/phlex_kit/native_select/native_select_group.rb +13 -0
  242. data/app/components/phlex_kit/native_select/native_select_icon.rb +32 -0
  243. data/app/components/phlex_kit/native_select/native_select_option.rb +14 -0
  244. data/app/components/phlex_kit/navigation_menu/navigation_menu.css +67 -0
  245. data/app/components/phlex_kit/navigation_menu/navigation_menu.rb +23 -0
  246. data/app/components/phlex_kit/navigation_menu/navigation_menu_content.rb +9 -0
  247. data/app/components/phlex_kit/navigation_menu/navigation_menu_item.rb +9 -0
  248. data/app/components/phlex_kit/navigation_menu/navigation_menu_link.rb +13 -0
  249. data/app/components/phlex_kit/navigation_menu/navigation_menu_list.rb +7 -0
  250. data/app/components/phlex_kit/navigation_menu/navigation_menu_trigger.rb +27 -0
  251. data/app/components/phlex_kit/pagination/pagination.css +5 -0
  252. data/app/components/phlex_kit/pagination/pagination.rb +10 -0
  253. data/app/components/phlex_kit/pagination/pagination_content.rb +6 -0
  254. data/app/components/phlex_kit/pagination/pagination_ellipsis.rb +17 -0
  255. data/app/components/phlex_kit/pagination/pagination_item.rb +14 -0
  256. data/app/components/phlex_kit/popover/popover.css +9 -0
  257. data/app/components/phlex_kit/popover/popover.rb +11 -0
  258. data/app/components/phlex_kit/popover/popover_content.rb +8 -0
  259. data/app/components/phlex_kit/popover/popover_trigger.rb +8 -0
  260. data/app/components/phlex_kit/progress/progress.css +17 -0
  261. data/app/components/phlex_kit/progress/progress.rb +25 -0
  262. data/app/components/phlex_kit/radio_button/radio_button.css +9 -0
  263. data/app/components/phlex_kit/radio_button/radio_button.rb +19 -0
  264. data/app/components/phlex_kit/radio_group/radio_group.css +3 -0
  265. data/app/components/phlex_kit/radio_group/radio_group.rb +14 -0
  266. data/app/components/phlex_kit/resizable/resizable.css +23 -0
  267. data/app/components/phlex_kit/resizable/resizable_handle.rb +21 -0
  268. data/app/components/phlex_kit/resizable/resizable_panel.rb +19 -0
  269. data/app/components/phlex_kit/resizable/resizable_panel_group.rb +26 -0
  270. data/app/components/phlex_kit/scroll_area/scroll_area.css +21 -0
  271. data/app/components/phlex_kit/scroll_area/scroll_area.rb +15 -0
  272. data/app/components/phlex_kit/select/select.css +80 -0
  273. data/app/components/phlex_kit/select/select.rb +43 -0
  274. data/app/components/phlex_kit/select/select_content.rb +24 -0
  275. data/app/components/phlex_kit/select/select_group.rb +13 -0
  276. data/app/components/phlex_kit/select/select_input.rb +23 -0
  277. data/app/components/phlex_kit/select/select_item.rb +52 -0
  278. data/app/components/phlex_kit/select/select_label.rb +13 -0
  279. data/app/components/phlex_kit/select/select_trigger.rb +42 -0
  280. data/app/components/phlex_kit/select/select_value.rb +21 -0
  281. data/app/components/phlex_kit/separator/separator.css +6 -0
  282. data/app/components/phlex_kit/separator/separator.rb +30 -0
  283. data/app/components/phlex_kit/sheet/sheet.css +17 -0
  284. data/app/components/phlex_kit/sheet/sheet.rb +14 -0
  285. data/app/components/phlex_kit/sheet/sheet_content.rb +25 -0
  286. data/app/components/phlex_kit/sheet/sheet_description.rb +6 -0
  287. data/app/components/phlex_kit/sheet/sheet_footer.rb +6 -0
  288. data/app/components/phlex_kit/sheet/sheet_header.rb +6 -0
  289. data/app/components/phlex_kit/sheet/sheet_middle.rb +6 -0
  290. data/app/components/phlex_kit/sheet/sheet_title.rb +6 -0
  291. data/app/components/phlex_kit/sheet/sheet_trigger.rb +6 -0
  292. data/app/components/phlex_kit/shortcut_key/shortcut_key.css +17 -0
  293. data/app/components/phlex_kit/shortcut_key/shortcut_key.rb +9 -0
  294. data/app/components/phlex_kit/sidebar/sidebar.css +42 -0
  295. data/app/components/phlex_kit/sidebar/sidebar.rb +19 -0
  296. data/app/components/phlex_kit/sidebar/sidebar_content.rb +12 -0
  297. data/app/components/phlex_kit/sidebar/sidebar_footer.rb +12 -0
  298. data/app/components/phlex_kit/sidebar/sidebar_group.rb +12 -0
  299. data/app/components/phlex_kit/sidebar/sidebar_header.rb +12 -0
  300. data/app/components/phlex_kit/sidebar/sidebar_inset.rb +14 -0
  301. data/app/components/phlex_kit/sidebar/sidebar_menu.rb +12 -0
  302. data/app/components/phlex_kit/sidebar/sidebar_menu_button.rb +17 -0
  303. data/app/components/phlex_kit/sidebar/sidebar_menu_item.rb +12 -0
  304. data/app/components/phlex_kit/sidebar/sidebar_wrapper.rb +13 -0
  305. data/app/components/phlex_kit/skeleton/skeleton.css +7 -0
  306. data/app/components/phlex_kit/skeleton/skeleton.rb +9 -0
  307. data/app/components/phlex_kit/slider/slider.css +52 -0
  308. data/app/components/phlex_kit/slider/slider.rb +39 -0
  309. data/app/components/phlex_kit/spinner/spinner.css +5 -0
  310. data/app/components/phlex_kit/spinner/spinner.rb +27 -0
  311. data/app/components/phlex_kit/stars/stars.css +4 -0
  312. data/app/components/phlex_kit/stars/stars.rb +19 -0
  313. data/app/components/phlex_kit/switch/switch.css +28 -0
  314. data/app/components/phlex_kit/switch/switch.rb +21 -0
  315. data/app/components/phlex_kit/table/table.css +24 -0
  316. data/app/components/phlex_kit/table/table.rb +35 -0
  317. data/app/components/phlex_kit/table/table_body.rb +12 -0
  318. data/app/components/phlex_kit/table/table_caption.rb +12 -0
  319. data/app/components/phlex_kit/table/table_cell.rb +12 -0
  320. data/app/components/phlex_kit/table/table_footer.rb +12 -0
  321. data/app/components/phlex_kit/table/table_head.rb +12 -0
  322. data/app/components/phlex_kit/table/table_header.rb +12 -0
  323. data/app/components/phlex_kit/table/table_row.rb +12 -0
  324. data/app/components/phlex_kit/tabs/tabs.css +13 -0
  325. data/app/components/phlex_kit/tabs/tabs.rb +13 -0
  326. data/app/components/phlex_kit/tabs/tabs_content.rb +11 -0
  327. data/app/components/phlex_kit/tabs/tabs_list.rb +6 -0
  328. data/app/components/phlex_kit/tabs/tabs_trigger.rb +17 -0
  329. data/app/components/phlex_kit/textarea/textarea.css +27 -0
  330. data/app/components/phlex_kit/textarea/textarea.rb +24 -0
  331. data/app/components/phlex_kit/theme_toggle/theme_toggle.rb +15 -0
  332. data/app/components/phlex_kit/toast/toast.css +163 -0
  333. data/app/components/phlex_kit/toast/toast.rb +21 -0
  334. data/app/components/phlex_kit/toast/toast_action.rb +19 -0
  335. data/app/components/phlex_kit/toast/toast_cancel.rb +18 -0
  336. data/app/components/phlex_kit/toast/toast_close.rb +35 -0
  337. data/app/components/phlex_kit/toast/toast_description.rb +13 -0
  338. data/app/components/phlex_kit/toast/toast_icon.rb +63 -0
  339. data/app/components/phlex_kit/toast/toast_item.rb +70 -0
  340. data/app/components/phlex_kit/toast/toast_region.rb +121 -0
  341. data/app/components/phlex_kit/toast/toast_title.rb +13 -0
  342. data/app/components/phlex_kit/toggle/toggle.css +16 -0
  343. data/app/components/phlex_kit/toggle/toggle.rb +59 -0
  344. data/app/components/phlex_kit/toggle_group/toggle_group.css +10 -0
  345. data/app/components/phlex_kit/toggle_group/toggle_group.rb +65 -0
  346. data/app/components/phlex_kit/toggle_group/toggle_group_item.rb +37 -0
  347. data/app/components/phlex_kit/tooltip/tooltip.css +28 -0
  348. data/app/components/phlex_kit/tooltip/tooltip.rb +15 -0
  349. data/app/components/phlex_kit/tooltip/tooltip_content.rb +12 -0
  350. data/app/components/phlex_kit/tooltip/tooltip_trigger.rb +13 -0
  351. data/app/components/phlex_kit/typography/blockquote.rb +12 -0
  352. data/app/components/phlex_kit/typography/heading.rb +38 -0
  353. data/app/components/phlex_kit/typography/inline_code.rb +13 -0
  354. data/app/components/phlex_kit/typography/inline_link.rb +15 -0
  355. data/app/components/phlex_kit/typography/text.rb +48 -0
  356. data/app/components/phlex_kit/typography/typography.css +50 -0
  357. data/app/javascript/phlex_kit/controllers/accordion_controller.js +59 -0
  358. data/app/javascript/phlex_kit/controllers/alert_dialog_controller.js +24 -0
  359. data/app/javascript/phlex_kit/controllers/avatar_controller.js +30 -0
  360. data/app/javascript/phlex_kit/controllers/calendar_controller.js +316 -0
  361. data/app/javascript/phlex_kit/controllers/calendar_input_controller.js +10 -0
  362. data/app/javascript/phlex_kit/controllers/carousel_controller.js +189 -0
  363. data/app/javascript/phlex_kit/controllers/chart_controller.js +135 -0
  364. data/app/javascript/phlex_kit/controllers/clipboard_controller.js +30 -0
  365. data/app/javascript/phlex_kit/controllers/collapsible_controller.js +14 -0
  366. data/app/javascript/phlex_kit/controllers/combobox_controller.js +303 -0
  367. data/app/javascript/phlex_kit/controllers/command_controller.js +161 -0
  368. data/app/javascript/phlex_kit/controllers/command_dialog_controller.js +37 -0
  369. data/app/javascript/phlex_kit/controllers/context_menu_controller.js +28 -0
  370. data/app/javascript/phlex_kit/controllers/data_table_column_visibility_controller.js +18 -0
  371. data/app/javascript/phlex_kit/controllers/data_table_controller.js +61 -0
  372. data/app/javascript/phlex_kit/controllers/data_table_search_controller.js +67 -0
  373. data/app/javascript/phlex_kit/controllers/dialog_controller.js +20 -0
  374. data/app/javascript/phlex_kit/controllers/dropdown_menu_controller.js +106 -0
  375. data/app/javascript/phlex_kit/controllers/form_field_controller.js +69 -0
  376. data/app/javascript/phlex_kit/controllers/hover_card_controller.js +11 -0
  377. data/app/javascript/phlex_kit/controllers/index.js +87 -0
  378. data/app/javascript/phlex_kit/controllers/input_otp_controller.js +66 -0
  379. data/app/javascript/phlex_kit/controllers/masked_input_controller.js +26 -0
  380. data/app/javascript/phlex_kit/controllers/menubar_controller.js +43 -0
  381. data/app/javascript/phlex_kit/controllers/message_scroller_controller.js +335 -0
  382. data/app/javascript/phlex_kit/controllers/popover_controller.js +12 -0
  383. data/app/javascript/phlex_kit/controllers/resizable_controller.js +42 -0
  384. data/app/javascript/phlex_kit/controllers/select_controller.js +141 -0
  385. data/app/javascript/phlex_kit/controllers/select_item_controller.js +14 -0
  386. data/app/javascript/phlex_kit/controllers/sheet_content_controller.js +6 -0
  387. data/app/javascript/phlex_kit/controllers/sheet_controller.js +10 -0
  388. data/app/javascript/phlex_kit/controllers/slider_controller.js +19 -0
  389. data/app/javascript/phlex_kit/controllers/tabs_controller.js +28 -0
  390. data/app/javascript/phlex_kit/controllers/theme_toggle_controller.js +22 -0
  391. data/app/javascript/phlex_kit/controllers/toast_controller.js +153 -0
  392. data/app/javascript/phlex_kit/controllers/toaster_controller.js +321 -0
  393. data/app/javascript/phlex_kit/controllers/toggle_controller.js +25 -0
  394. data/app/javascript/phlex_kit/controllers/toggle_group_controller.js +91 -0
  395. data/config/importmap.rb +7 -0
  396. data/lib/generators/phlex_kit/component/component_generator.rb +41 -0
  397. data/lib/generators/phlex_kit/install/install_generator.rb +51 -0
  398. data/lib/generators/phlex_kit/install/templates/phlex_kit.rb +11 -0
  399. data/lib/phlex_kit/base_component.rb +22 -0
  400. data/lib/phlex_kit/configuration.rb +46 -0
  401. data/lib/phlex_kit/engine.rb +50 -0
  402. data/lib/phlex_kit/propshaft_skip_source.rb +22 -0
  403. data/lib/phlex_kit/version.rb +5 -0
  404. data/lib/phlex_kit.rb +21 -0
  405. metadata +545 -0
@@ -0,0 +1,110 @@
1
+ /* Co-located with data_table.rb — UI::DataTable. ruby_ui's structure + Stimulus
2
+ kept (turbo-frame shell, selection/bulk/expand controller, debounced search,
3
+ column-visibility dropdown); Tailwind replaced with vanilla CSS on the palette
4
+ tokens. The composed parts (Table, DropdownMenu, Input, Pagination, Checkbox,
5
+ NativeSelect) bring their own styles. Theme tokens come from the global
6
+ stylesheet. */
7
+ .pk-data-table {
8
+ width: 100%;
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: 1rem;
12
+ }
13
+
14
+ .pk-data-table-toolbar {
15
+ display: flex;
16
+ align-items: center;
17
+ justify-content: space-between;
18
+ gap: .5rem;
19
+ }
20
+
21
+ .pk-data-table-search { max-width: 24rem; flex: 1; }
22
+
23
+ /* "Columns" dropdown rows. */
24
+ .pk-data-table-column-toggle { position: relative; }
25
+ .pk-data-table-column-toggle-icon { width: 1rem; height: 1rem; margin-left: .25rem; }
26
+ .pk-data-table-column-option {
27
+ display: flex;
28
+ align-items: center;
29
+ gap: .5rem;
30
+ border-radius: calc(var(--pk-radius) - 4px);
31
+ padding: .375rem .5rem;
32
+ font-size: .875rem;
33
+ cursor: pointer;
34
+ }
35
+ .pk-data-table-column-option:hover { background: var(--pk-accent); }
36
+
37
+ /* Sortable header link. */
38
+ .pk-data-table-sort-head { color: var(--pk-text); white-space: nowrap; }
39
+ .pk-data-table-sort-link {
40
+ display: inline-flex;
41
+ align-items: center;
42
+ gap: .25rem;
43
+ color: inherit;
44
+ text-decoration: none;
45
+ transition: color .15s ease;
46
+ }
47
+ .pk-data-table-sort-link:hover { color: var(--pk-text); }
48
+ .pk-data-table-sort-icon { display: inline-block; width: .75rem; height: .75rem; }
49
+ .pk-data-table-sort-icon.unsorted { opacity: .3; }
50
+
51
+ /* Bulk actions cluster (revealed by the controller while rows are selected). */
52
+ .pk-data-table-bulk-actions {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: .5rem;
56
+ }
57
+
58
+ .pk-data-table-selection-summary {
59
+ font-size: .875rem;
60
+ color: var(--pk-muted);
61
+ }
62
+
63
+ /* Row-detail chevron. */
64
+ .pk-data-table-expand-toggle {
65
+ display: inline-flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+ width: 2rem;
69
+ height: 2rem;
70
+ padding: 0;
71
+ border: 0;
72
+ border-radius: calc(var(--pk-radius) - 2px);
73
+ background: transparent;
74
+ color: var(--pk-text);
75
+ cursor: pointer;
76
+ transition: background-color .15s ease;
77
+ }
78
+ .pk-data-table-expand-toggle:hover { background: var(--pk-accent); }
79
+ .pk-data-table-expand-toggle:focus-visible {
80
+ outline: none;
81
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--pk-ring) 50%, transparent);
82
+ }
83
+ .pk-data-table-expand-toggle svg {
84
+ width: 1rem;
85
+ height: 1rem;
86
+ transition: transform .15s ease;
87
+ }
88
+ .pk-data-table-expand-toggle[aria-expanded="true"] svg { transform: rotate(90deg); }
89
+
90
+ /* Footer bar. */
91
+ .pk-data-table-pagination-bar {
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: space-between;
95
+ gap: 1rem;
96
+ padding: .5rem 0;
97
+ }
98
+ .pk-data-table-pagination { margin: 0; width: auto; justify-content: flex-end; }
99
+ /* the per-page <select> sizes intrinsically; border-box needs it wider than
100
+ its longest option + chevron padding or the text clips */
101
+ .pk-data-table-per-page .pk-native-select-field { min-width: 4.5rem; }
102
+ .pk-data-table-page-disabled {
103
+ display: inline-flex;
104
+ align-items: center;
105
+ height: 2.25rem;
106
+ padding: 0 .75rem;
107
+ font-size: .875rem;
108
+ opacity: .5;
109
+ pointer-events: none;
110
+ }
@@ -0,0 +1,25 @@
1
+ module PhlexKit
2
+ # Data table, ported from ruby_ui's RubyUI::DataTable: a server-driven
3
+ # sortable/searchable table living in a <turbo-frame>, built on the kit's
4
+ # Table / DropdownMenu / Input / Pagination parts. Row selection, bulk-action
5
+ # visibility and row-detail expansion live in the phlex-kit--data-table
6
+ # controller; search debounce and column visibility in their own controllers.
7
+ # Compose DataTable(id:) > DataTableToolbar(DataTableSearch +
8
+ # DataTableColumnToggle) + Table(DataTableSortHead, DataTableRowCheckbox …) +
9
+ # DataTablePaginationBar(DataTableSelectionSummary + DataTablePerPageSelect +
10
+ # DataTablePagination). Tailwind → vanilla `.pk-data-table*` (data_table.css).
11
+ class DataTable < BaseComponent
12
+ register_element :turbo_frame, tag: "turbo-frame"
13
+
14
+ def initialize(id:, **attrs)
15
+ @id = id
16
+ @attrs = attrs
17
+ end
18
+
19
+ def view_template(&block)
20
+ turbo_frame(id: @id, target: "_top") do
21
+ div(**mix({ class: "pk-data-table", data: { controller: "phlex-kit--data-table" } }, @attrs), &block)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ module PhlexKit
2
+ # Action cluster revealed while rows are selected. See data_table.rb.
3
+ class DataTableBulkActions < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&)
9
+ div(**mix({
10
+ class: "pk-data-table-bulk-actions pk-hidden",
11
+ data: { phlex_kit__data_table_target: "bulkActions" }
12
+ }, @attrs), &)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,61 @@
1
+ module PhlexKit
2
+ # "Columns" dropdown of checkboxes toggling cells that carry a matching
3
+ # data-column attribute. `columns:` is an array of { key:, label: } hashes.
4
+ # See data_table.rb.
5
+ class DataTableColumnToggle < BaseComponent
6
+ def initialize(columns:, **attrs)
7
+ @columns = columns
8
+ @attrs = attrs
9
+ end
10
+
11
+ def view_template
12
+ div(**mix({
13
+ class: "pk-data-table-column-toggle",
14
+ data: { controller: "phlex-kit--data-table-column-visibility" }
15
+ }, @attrs)) do
16
+ render DropdownMenu.new do
17
+ render DropdownMenuTrigger.new do
18
+ render Button.new(variant: :outline, size: :sm) do
19
+ plain "Columns"
20
+ chevron_icon
21
+ end
22
+ end
23
+ render DropdownMenuContent.new do
24
+ @columns.each do |col|
25
+ label(class: "pk-data-table-column-option") do
26
+ input(
27
+ type: :checkbox,
28
+ checked: true,
29
+ class: "pk-checkbox",
30
+ data: {
31
+ column_key: col[:key].to_s,
32
+ action: "change->phlex-kit--data-table-column-visibility#toggle"
33
+ }
34
+ )
35
+ span { plain col[:label] }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def chevron_icon
46
+ svg(
47
+ xmlns: "http://www.w3.org/2000/svg",
48
+ width: "16",
49
+ height: "16",
50
+ viewbox: "0 0 24 24",
51
+ fill: "none",
52
+ stroke: "currentColor",
53
+ "stroke-width": "2",
54
+ "stroke-linecap": "round",
55
+ "stroke-linejoin": "round",
56
+ class: "pk-data-table-column-toggle-icon",
57
+ "aria-hidden": "true"
58
+ ) { |s| s.polyline(points: "6 9 12 15 18 9") }
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,40 @@
1
+ module PhlexKit
2
+ # Chevron button toggling a row-detail element (pass its id as `controls:`);
3
+ # the chevron rotates via [aria-expanded] CSS. See data_table.rb.
4
+ class DataTableExpandToggle < BaseComponent
5
+ def initialize(controls:, expanded: false, label: "Toggle row details", **attrs)
6
+ @controls = controls
7
+ @expanded = expanded
8
+ @label = label
9
+ @attrs = attrs
10
+ end
11
+
12
+ def view_template
13
+ button(**mix({
14
+ type: :button,
15
+ class: "pk-data-table-expand-toggle",
16
+ aria: { expanded: @expanded.to_s, controls: @controls, label: @label },
17
+ data: { action: "click->phlex-kit--data-table#toggleRowDetail" }
18
+ }, @attrs)) do
19
+ icon
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def icon
26
+ svg(
27
+ xmlns: "http://www.w3.org/2000/svg",
28
+ width: "16",
29
+ height: "16",
30
+ viewbox: "0 0 24 24",
31
+ fill: "none",
32
+ stroke: "currentColor",
33
+ "stroke-width": "2",
34
+ "stroke-linecap": "round",
35
+ "stroke-linejoin": "round",
36
+ "aria-hidden": "true"
37
+ ) { |s| s.polyline(points: "9 18 15 12 9 6") }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,36 @@
1
+ module PhlexKit
2
+ # POST form wrapping the table for bulk actions (row checkboxes submit
3
+ # through it). Includes the Rails CSRF token when a view context is around.
4
+ # See data_table.rb.
5
+ class DataTableForm < BaseComponent
6
+ def initialize(action: "", method: "post", id: nil, **attrs)
7
+ @action = action
8
+ @method = method
9
+ @id = id
10
+ @attrs = attrs
11
+ end
12
+
13
+ def view_template(&block)
14
+ form_attrs = { action: @action, method: @method }
15
+ form_attrs[:id] = @id if @id
16
+ form(**mix(form_attrs, @attrs)) do
17
+ input(type: :hidden, name: "authenticity_token", value: csrf_token)
18
+ yield if block
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def csrf_token
25
+ # In a Rails app, view_context provides a real CSRF token.
26
+ # Outside Rails (gem tests), fall back to a placeholder.
27
+ if respond_to?(:helpers, true) && helpers.respond_to?(:form_authenticity_token)
28
+ helpers.form_authenticity_token
29
+ elsif respond_to?(:view_context, true) && view_context.respond_to?(:form_authenticity_token)
30
+ view_context.form_authenticity_token
31
+ else
32
+ "csrf-token-placeholder"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ module PhlexKit
2
+ # Adapter exposing a Kaminari collection to PhlexKit::DataTablePagination (the
3
+ # gem is the host's dependency, not ours). Ported from ruby_ui.
4
+ class DataTableKaminariAdapter
5
+ def initialize(collection)
6
+ @collection = collection
7
+ end
8
+
9
+ def current_page = @collection.current_page
10
+
11
+ def total_pages = @collection.total_pages
12
+
13
+ def total_count = @collection.total_count
14
+
15
+ def per_page = @collection.limit_value
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module PhlexKit
2
+ # Adapter for plain page/per_page/total_count pagination (no gem). Not a
3
+ # component — just the current_page/total_pages interface
4
+ # PhlexKit::DataTablePagination consumes. Ported from ruby_ui.
5
+ class DataTableManualAdapter
6
+ attr_reader :current_page, :per_page, :total_count
7
+
8
+ def initialize(page:, per_page:, total_count:)
9
+ @current_page = page.to_i
10
+ @per_page = [ per_page.to_i, 1 ].max
11
+ @total_count = total_count.to_i
12
+ end
13
+
14
+ def total_pages
15
+ [ (@total_count.to_f / @per_page).ceil, 1 ].max
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,98 @@
1
+ module PhlexKit
2
+ # Windowed page navigation built on the kit's Pagination parts. Feed it a
3
+ # paginated collection via one of the adapters — `pagy:`, `kaminari:`, plain
4
+ # `page:`/`per_page:`/`total_count:`, or any `with:` object responding to
5
+ # current_page/total_pages. Renders nothing for a single page.
6
+ # See data_table.rb.
7
+ class DataTablePagination < BaseComponent
8
+ def initialize(with: nil, pagy: nil, kaminari: nil, page: nil, per_page: nil, total_count: nil, page_param: "page", path: "", query: {}, window: 1, prev_label: "<", next_label: ">", **attrs)
9
+ @adapter = resolve_adapter(with:, pagy:, kaminari:, page:, per_page:, total_count:)
10
+ @page_param = page_param
11
+ @path = path
12
+ @query = query.to_h.transform_keys(&:to_s)
13
+ @window = window
14
+ @prev_label = prev_label
15
+ @next_label = next_label
16
+ @attrs = attrs
17
+ end
18
+
19
+ def view_template
20
+ return if total <= 1
21
+
22
+ render Pagination.new(**mix({ class: "pk-data-table-pagination" }, @attrs)) do
23
+ render PaginationContent.new do
24
+ prev_item
25
+ number_items
26
+ next_item
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def resolve_adapter(with:, pagy:, kaminari:, page:, per_page:, total_count:)
34
+ return with if with
35
+ return DataTablePagyAdapter.new(pagy) if pagy
36
+ return DataTableKaminariAdapter.new(kaminari) if kaminari
37
+ if page && per_page && total_count
38
+ return DataTableManualAdapter.new(page:, per_page:, total_count:)
39
+ end
40
+ raise ArgumentError, "DataTablePagination requires one of: with:, pagy:, kaminari:, or page:+per_page:+total_count:"
41
+ end
42
+
43
+ def current = @adapter.current_page
44
+
45
+ def total = @adapter.total_pages
46
+
47
+ def page_href(p)
48
+ qs = build_query(@query.merge(@page_param => p.to_s))
49
+ qs.empty? ? @path : "#{@path}?#{qs}"
50
+ end
51
+
52
+ def build_query(hash)
53
+ hash.flat_map { |k, v|
54
+ Array(v).map { |val| "#{CGI.escape(k.to_s)}=#{CGI.escape(val.to_s)}" }
55
+ }.join("&")
56
+ end
57
+
58
+ def prev_item
59
+ if current <= 1
60
+ li do
61
+ span(class: "pk-data-table-page-disabled") { @prev_label }
62
+ end
63
+ else
64
+ render PaginationItem.new(href: page_href(current - 1)) { @prev_label }
65
+ end
66
+ end
67
+
68
+ def next_item
69
+ if current >= total
70
+ li do
71
+ span(class: "pk-data-table-page-disabled") { @next_label }
72
+ end
73
+ else
74
+ render PaginationItem.new(href: page_href(current + 1)) { @next_label }
75
+ end
76
+ end
77
+
78
+ def number_items
79
+ windowed_pages.each do |p|
80
+ if p == :gap
81
+ render PaginationEllipsis.new
82
+ else
83
+ render PaginationItem.new(href: page_href(p), active: p == current) { plain p.to_s }
84
+ end
85
+ end
86
+ end
87
+
88
+ def windowed_pages
89
+ return (1..total).to_a if total <= 7
90
+ pages = [ 1 ]
91
+ pages << :gap if current - @window > 2
92
+ ((current - @window)..(current + @window)).each { |p| pages << p if p > 1 && p < total }
93
+ pages << :gap if current + @window < total - 1
94
+ pages << total
95
+ pages
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,13 @@
1
+ module PhlexKit
2
+ # Footer row holding the selection summary, per-page select and pagination.
3
+ # See data_table.rb.
4
+ class DataTablePaginationBar < BaseComponent
5
+ def initialize(**attrs)
6
+ @attrs = attrs
7
+ end
8
+
9
+ def view_template(&)
10
+ div(**mix({ class: "pk-data-table-pagination-bar" }, @attrs), &)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module PhlexKit
2
+ # Adapter exposing a Pagy object to PhlexKit::DataTablePagination (the gem is
3
+ # the host's dependency, not ours). Ported from ruby_ui.
4
+ class DataTablePagyAdapter
5
+ def initialize(pagy)
6
+ @pagy = pagy
7
+ end
8
+
9
+ def current_page = @pagy.page
10
+
11
+ def total_pages = @pagy.pages
12
+
13
+ def total_count = @pagy.count
14
+
15
+ def per_page = @pagy.items
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ module PhlexKit
2
+ # Per-page NativeSelect in a GET form that self-submits on change (targeting
3
+ # the table's turbo-frame when `frame_id:` is given). See data_table.rb.
4
+ class DataTablePerPageSelect < BaseComponent
5
+ def initialize(path:, name: "per_page", value: nil, frame_id: nil, options: [ 5, 10, 25, 50 ], **attrs)
6
+ @path = path
7
+ @name = name
8
+ @value = value
9
+ @frame_id = frame_id
10
+ @options = options
11
+ @attrs = attrs
12
+ end
13
+
14
+ def view_template
15
+ form_attrs = { class: "pk-data-table-per-page", action: @path, method: "get" }
16
+ form_attrs[:data] = { turbo_frame: @frame_id } if @frame_id
17
+
18
+ form(**mix(form_attrs, @attrs)) do
19
+ render NativeSelect.new(name: @name, onchange: safe("this.form.requestSubmit()")) do
20
+ @options.each do |opt|
21
+ option_attrs = { value: opt.to_s }
22
+ option_attrs[:selected] = true if opt.to_s == @value.to_s
23
+ option(**option_attrs) { plain opt.to_s }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ module PhlexKit
2
+ # Per-row selection checkbox (a PhlexKit::Checkbox submitting `ids[]`).
3
+ # See data_table.rb.
4
+ class DataTableRowCheckbox < BaseComponent
5
+ def initialize(value:, name: "ids[]", label: nil, **attrs)
6
+ @value = value
7
+ @name = name
8
+ @label = label
9
+ @attrs = attrs
10
+ end
11
+
12
+ def view_template
13
+ render Checkbox.new(**mix({
14
+ name: @name,
15
+ value: @value,
16
+ aria: { label: @label || "Select row #{@value}" },
17
+ data: {
18
+ phlex_kit__data_table_target: "rowCheckbox",
19
+ action: "change->phlex-kit--data-table#toggleRow"
20
+ }
21
+ }, @attrs))
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,51 @@
1
+ module PhlexKit
2
+ # Debounced GET search form targeting the table's turbo-frame. Extra filter
3
+ # params survive via `preserved_params:` hidden inputs; focus/caret survive the
4
+ # frame swap (see the search controller). See data_table.rb.
5
+ class DataTableSearch < BaseComponent
6
+ def initialize(path:, name: "search", value: nil, frame_id: nil, placeholder: "Search...", debounce: 300, preserved_params: {}, **attrs)
7
+ @path = path
8
+ @name = name
9
+ @value = value
10
+ @frame_id = frame_id
11
+ @placeholder = placeholder
12
+ @debounce = debounce
13
+ @preserved_params = preserved_params
14
+ @attrs = attrs
15
+ end
16
+
17
+ def view_template
18
+ form(**mix({ class: "pk-data-table-search", method: "get", action: @path, data: form_data }, @attrs)) do
19
+ render Input.new(
20
+ type: :search,
21
+ name: @name,
22
+ value: @value,
23
+ placeholder: @placeholder,
24
+ autocomplete: "off"
25
+ )
26
+ @preserved_params.each do |k, v|
27
+ next if v.nil? || (v.respond_to?(:empty?) && v.empty?)
28
+ next if k.to_s == @name
29
+ input(type: :hidden, name: k.to_s, value: v.to_s)
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def debounce_enabled?
37
+ @debounce && @debounce.to_i > 0
38
+ end
39
+
40
+ def form_data
41
+ base = {}
42
+ base[:turbo_frame] = @frame_id if @frame_id
43
+ if debounce_enabled?
44
+ base[:controller] = "phlex-kit--data-table-search"
45
+ base[:"phlex-kit--data-table-search-delay-value"] = @debounce.to_i
46
+ base[:action] = "input->phlex-kit--data-table-search#submit"
47
+ end
48
+ base
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,19 @@
1
+ module PhlexKit
2
+ # Header checkbox selecting every DataTableRowCheckbox on the page (the
3
+ # controller sets indeterminate for partial selections). See data_table.rb.
4
+ class DataTableSelectAllCheckbox < BaseComponent
5
+ def initialize(**attrs)
6
+ @attrs = attrs
7
+ end
8
+
9
+ def view_template
10
+ render Checkbox.new(**mix({
11
+ aria: { label: "Select all" },
12
+ data: {
13
+ phlex_kit__data_table_target: "selectAll",
14
+ action: "change->phlex-kit--data-table#toggleAll"
15
+ }
16
+ }, @attrs))
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module PhlexKit
2
+ # "N of M row(s) selected." line, kept current by the controller.
3
+ # See data_table.rb.
4
+ class DataTableSelectionSummary < BaseComponent
5
+ def initialize(total_on_page: 0, **attrs)
6
+ @total_on_page = total_on_page
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template
11
+ div(**mix({
12
+ class: "pk-data-table-selection-summary",
13
+ data: { phlex_kit__data_table_target: "selectionSummary" }
14
+ }, @attrs)) do
15
+ plain "0 of #{@total_on_page} row(s) selected."
16
+ end
17
+ end
18
+ end
19
+ end