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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d165b8e5ecbb24ef238be1c9472db2d19cdcb30079c85e2e839019547d5324fa
4
+ data.tar.gz: 89f8058734e7d2745b3ea96e32cea6845e721c4f2e28a8621bc7c4978183c510
5
+ SHA512:
6
+ metadata.gz: 2c1b8608a4175ae249ed98ecae2c0ffccbb1c8a5f07d9fea298bf29e39d0eee3f401f6accd822da8fb42cc194560690fa4ed72e389bd448e89d2f6f008f494de
7
+ data.tar.gz: 87773e1fa4628d51cdeef7d93684fe3c91d728fe77f80d3e093fbcfeb1d210d1e176d6fd0f3d89901bb7c2c4ffc67db04104fc44437a017ee7df8cd5d9ca3037
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aypex
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # PhlexKit
2
+
3
+ A [ruby_ui](https://ruby-ui.com)-style component kit for [Phlex](https://phlex.fun),
4
+ styled with **vanilla CSS + design tokens instead of Tailwind**, and built so
5
+ [phlex-reactive](https://github.com/mhenrixon/phlex-reactive) is an *optional,
6
+ per-component* integration — never a required dependency.
7
+
8
+ - **No build step.** Components ship as plain Ruby classes with co-located vanilla
9
+ CSS. No Tailwind, no Node, no PostCSS. Assets are precompiled-static in the gem.
10
+ - **Theme with CSS custom properties.** Every component reads `--pk-*` tokens via
11
+ `var()` + `color-mix()`. Redefine `:root` and the whole kit re-themes live —
12
+ including dark/light/system — with no rebuild.
13
+ - **Reactive when you want it.** Components pass `**attrs` straight through Phlex's
14
+ `mix`, so a phlex-reactive `**on(:event)` bundle composes onto the root element
15
+ with zero coupling. Non-reactive components never touch phlex-reactive.
16
+
17
+ ## Install
18
+
19
+ ```ruby
20
+ # Gemfile
21
+ gem "phlex_kit"
22
+ ```
23
+
24
+ ```bash
25
+ bundle install
26
+ bin/rails g phlex_kit:install
27
+ ```
28
+
29
+ The installer adds `@import url("phlex_kit/phlex_kit.css");` to your
30
+ `application.css`, drops `config/initializers/phlex_kit.rb`, and prints the
31
+ Stimulus wiring. That's it — no Tailwind config, no content globs.
32
+
33
+ ## Usage
34
+
35
+ ```ruby
36
+ render PhlexKit::Button.new(variant: :primary, size: :lg) { "Save changes" }
37
+
38
+ render PhlexKit::Card.new do
39
+ render PhlexKit::CardHeader.new do
40
+ render PhlexKit::CardTitle.new { "Team" }
41
+ end
42
+ render PhlexKit::CardContent.new { "…" }
43
+ end
44
+
45
+ render PhlexKit::Badge.new(variant: :success) { "Live" }
46
+ ```
47
+
48
+ Prefer revue-style `UI::Button`? Turn on the alias in the initializer:
49
+
50
+ ```ruby
51
+ PhlexKit.configure { |c| c.define_ui_alias = true } # UI == PhlexKit
52
+ ```
53
+
54
+ ## Theming
55
+
56
+ The gem ships a default dark/light/system token set (`_tokens.css`). Override any
57
+ token in your own stylesheet — your app's CSS sorts ahead of the gem's, so you win:
58
+
59
+ ```css
60
+ @import url("phlex_kit/phlex_kit.css");
61
+
62
+ :root {
63
+ --pk-brand: #3b5bdb;
64
+ --pk-radius: 6px;
65
+ }
66
+ ```
67
+
68
+ Want a completely custom palette? Delete the `_tokens` import line from your
69
+ manifest and define the `--pk-*` properties yourself. Every component has a
70
+ literal fallback in `var(--pk-*, …)`, so nothing breaks if a token is missing.
71
+
72
+ ## Interactive components (Stimulus)
73
+
74
+ Dialog, Dropdown, Select, and Avatar ship plain Stimulus controllers (no
75
+ phlex-reactive needed). Register them once in your Stimulus entrypoint:
76
+
77
+ ```js
78
+ import { registerPhlexKitControllers } from "phlex_kit/controllers"
79
+ registerPhlexKitControllers(application)
80
+ ```
81
+
82
+ ## phlex-reactive (optional)
83
+
84
+ For components that own server-state behavior (live counters, moderation queues,
85
+ cross-tab updates), add phlex-reactive and include its mixin in a component:
86
+
87
+ ```ruby
88
+ # Gemfile
89
+ gem "phlex-reactive"
90
+ ```
91
+
92
+ ```ruby
93
+ class MyCounter < PhlexKit::BaseComponent
94
+ include Phlex::Reactive::Component
95
+ action(:increment) { @count += 1 }
96
+ # view_template uses **on(:increment) on a button — it just flows through mix
97
+ end
98
+ ```
99
+
100
+ PhlexKit does **not** depend on phlex-reactive. `PhlexKit.reactive?` auto-detects
101
+ it; set `config.reactive` to force it on/off.
102
+
103
+ ## Ejecting components (shadcn-style)
104
+
105
+ Want to own and edit a component's source? Eject it into your app:
106
+
107
+ ```bash
108
+ bin/rails g phlex_kit:component button
109
+ ```
110
+
111
+ This copies `button.rb` + `button.css` into `app/components/phlex_kit/button/`
112
+ and wires its `@import`. Your copy shadows the gem's.
113
+
114
+ ## How the asset wiring works
115
+
116
+ Three engine initializers reproduce the pattern proven in production (revue):
117
+
118
+ 1. `app/components` and the stylesheet dir go on Propshaft's load path so CSS can
119
+ sit beside each `.rb`.
120
+ 2. Component folders are Zeitwerk-`collapse`d, so `button/button.rb` is
121
+ `PhlexKit::Button` (not `PhlexKit::Button::Button`) and `card/card_header.rb`
122
+ is `PhlexKit::CardHeader`.
123
+ 3. A private-method guard keeps Propshaft from serving Ruby source out of
124
+ `public/assets/` (covered by `test/assets/asset_load_path_test.rb`).
125
+
126
+ Only the `@import url("…")` form is fingerprinted by Propshaft — a bare
127
+ `@import "…"` ships un-digested and 404s. The manifest always uses `url()`.
128
+
129
+ ## Components
130
+
131
+ See [ROADMAP.md](ROADMAP.md) for the full inventory and porting status.
132
+
133
+ ## License
134
+
135
+ MIT.
@@ -0,0 +1,91 @@
1
+ /* Kit utilities used by the interactive controllers (Stimulus toggles these). */
2
+ .pk-hidden { display: none !important; }
3
+
4
+ /* Kit elements size predictably: width includes padding + border, so
5
+ `width: 100%` controls (inputs, triggers, option rows) never overflow their
6
+ container. Scoped to pk-* classes and their subtrees — the host's own box
7
+ model is untouched. */
8
+ [class^="pk-"], [class*=" pk-"],
9
+ [class^="pk-"] *, [class*=" pk-"] *,
10
+ [class^="pk-"] *::before, [class*=" pk-"] *::after { box-sizing: border-box; }
11
+
12
+ /* PhlexKit default theme tokens — shadcn/ui's current default (neutral)
13
+ palette, values lifted verbatim from ui.shadcn.com, mapped onto the --pk-*
14
+ names: bg ← background, surface ← card/popover, surface-2 ← muted,
15
+ accent ← accent (hover fills — darker than muted in dark mode),
16
+ input ← input (form-control borders), ring ← ring (focus ring color),
17
+ brand ← primary (monochrome), red ← destructive, chart-1..5 ← chart-1..5
18
+ (tailwind blue-300/500/600/700/800), radius ← 0.625rem (components derive
19
+ smaller/larger radii from it). This file is OPTIONAL — a host that wants
20
+ its own palette can skip importing it (see phlex_kit.css) and define the
21
+ --pk-* custom properties itself. Every component reads these via
22
+ var(--pk-*), so redefining :root after the import re-themes the whole kit
23
+ with no rebuild.
24
+
25
+ Dark is the default; light is opt-in via <html data-theme="light"> (set it
26
+ server-side to avoid a flash). "system" follows the OS via prefers-color-scheme.
27
+ Keep the two light token sets in sync. */
28
+ :root {
29
+ --pk-bg: #0a0a0a;
30
+ --pk-surface: #171717;
31
+ --pk-surface-2: #262626;
32
+ --pk-accent: #404040;
33
+ --pk-border: #ffffff1a;
34
+ --pk-input: #ffffff26;
35
+ --pk-ring: #737373;
36
+ --pk-text: #fafafa;
37
+ --pk-text-2: #d4d4d4;
38
+ --pk-muted: #a1a1a1;
39
+ --pk-brand: #e5e5e5;
40
+ --pk-brand-ink: #171717;
41
+ --pk-green: #22c55e;
42
+ --pk-amber: #f59e0b;
43
+ --pk-red: #ff6568;
44
+ --pk-chart-1: #93c5fd;
45
+ --pk-chart-2: #3b82f6;
46
+ --pk-chart-3: #2563eb;
47
+ --pk-chart-4: #1d4ed8;
48
+ --pk-chart-5: #1e40af;
49
+ --pk-radius: 0.625rem;
50
+ color-scheme: dark;
51
+ }
52
+
53
+ :root[data-theme="light"] {
54
+ --pk-bg: #ffffff;
55
+ --pk-surface: #ffffff;
56
+ --pk-surface-2: #f5f5f5;
57
+ --pk-accent: #f5f5f5;
58
+ --pk-border: #e5e5e5;
59
+ --pk-input: #e5e5e5;
60
+ --pk-ring: #a1a1a1;
61
+ --pk-text: #000000;
62
+ --pk-text-2: #404040;
63
+ --pk-muted: #737373;
64
+ --pk-brand: #000000;
65
+ --pk-brand-ink: #fafafa;
66
+ --pk-green: #16a34a;
67
+ --pk-amber: #d97706;
68
+ --pk-red: #e40014;
69
+ color-scheme: light;
70
+ }
71
+
72
+ @media (prefers-color-scheme: light) {
73
+ :root[data-theme="system"] {
74
+ --pk-bg: #ffffff;
75
+ --pk-surface: #ffffff;
76
+ --pk-surface-2: #f5f5f5;
77
+ --pk-accent: #f5f5f5;
78
+ --pk-border: #e5e5e5;
79
+ --pk-input: #e5e5e5;
80
+ --pk-ring: #a1a1a1;
81
+ --pk-text: #000000;
82
+ --pk-text-2: #404040;
83
+ --pk-muted: #737373;
84
+ --pk-brand: #000000;
85
+ --pk-brand-ink: #fafafa;
86
+ --pk-green: #16a34a;
87
+ --pk-amber: #d97706;
88
+ --pk-red: #e40014;
89
+ color-scheme: light;
90
+ }
91
+ }
@@ -0,0 +1,82 @@
1
+ /* PhlexKit manifest — the single stylesheet a host imports:
2
+
3
+ @import url("phlex_kit/phlex_kit.css"); in your application.css
4
+
5
+ Only the url() form is fingerprinted by Propshaft; a bare @import ships
6
+ un-digested and 404s. And Propshaft resolves bare url() paths RELATIVE TO
7
+ THIS FILE'S directory (phlex_kit/), so imports here must be written
8
+ relative — `_tokens.css`, `button/button.css` — never `phlex_kit/…`, which
9
+ would double the prefix and 404. Component CSS is co-located beside each
10
+ .rb and pulled in below. This file is regenerated when a component is added.
11
+
12
+ To bring your OWN theme, delete the _tokens import line and define the
13
+ --pk-* custom properties yourself. */
14
+ @import url("_tokens.css");
15
+ @import url("accordion/accordion.css");
16
+ @import url("alert/alert.css");
17
+ @import url("alert_dialog/alert_dialog.css");
18
+ @import url("aspect_ratio/aspect_ratio.css");
19
+ @import url("attachment/attachment.css");
20
+ @import url("avatar/avatar.css");
21
+ @import url("badge/badge.css");
22
+ @import url("breadcrumb/breadcrumb.css");
23
+ @import url("bubble/bubble.css");
24
+ @import url("button/button.css");
25
+ @import url("button_group/button_group.css");
26
+ @import url("calendar/calendar.css");
27
+ @import url("card/card.css");
28
+ @import url("carousel/carousel.css");
29
+ @import url("chart/chart.css");
30
+ @import url("checkbox/checkbox.css");
31
+ @import url("clipboard/clipboard.css");
32
+ @import url("codeblock/codeblock.css");
33
+ @import url("collapsible/collapsible.css");
34
+ @import url("combobox/combobox.css");
35
+ @import url("command/command.css");
36
+ @import url("context_menu/context_menu.css");
37
+ @import url("data_table/data_table.css");
38
+ @import url("date_picker/date_picker.css");
39
+ @import url("dialog/dialog.css");
40
+ @import url("drawer/drawer.css");
41
+ @import url("dropdown_menu/dropdown_menu.css");
42
+ @import url("empty/empty.css");
43
+ @import url("form/form.css");
44
+ @import url("form_field/form_field.css");
45
+ @import url("hover_card/hover_card.css");
46
+ @import url("input/input.css");
47
+ @import url("input_group/input_group.css");
48
+ @import url("input_otp/input_otp.css");
49
+ @import url("item/item.css");
50
+ @import url("kbd/kbd.css");
51
+ @import url("label/label.css");
52
+ @import url("link/link.css");
53
+ @import url("menubar/menubar.css");
54
+ @import url("message/message.css");
55
+ @import url("message_scroller/message_scroller.css");
56
+ @import url("native_select/native_select.css");
57
+ @import url("navigation_menu/navigation_menu.css");
58
+ @import url("pagination/pagination.css");
59
+ @import url("popover/popover.css");
60
+ @import url("progress/progress.css");
61
+ @import url("radio_button/radio_button.css");
62
+ @import url("radio_group/radio_group.css");
63
+ @import url("resizable/resizable.css");
64
+ @import url("scroll_area/scroll_area.css");
65
+ @import url("select/select.css");
66
+ @import url("separator/separator.css");
67
+ @import url("sheet/sheet.css");
68
+ @import url("shortcut_key/shortcut_key.css");
69
+ @import url("sidebar/sidebar.css");
70
+ @import url("skeleton/skeleton.css");
71
+ @import url("slider/slider.css");
72
+ @import url("spinner/spinner.css");
73
+ @import url("stars/stars.css");
74
+ @import url("switch/switch.css");
75
+ @import url("table/table.css");
76
+ @import url("tabs/tabs.css");
77
+ @import url("textarea/textarea.css");
78
+ @import url("toast/toast.css");
79
+ @import url("toggle/toggle.css");
80
+ @import url("toggle_group/toggle_group.css");
81
+ @import url("tooltip/tooltip.css");
82
+ @import url("typography/typography.css");
@@ -0,0 +1,14 @@
1
+ /* Co-located with accordion.rb. Theme tokens from the global stylesheet. */
2
+ .pk-accordion { width: 100%; }
3
+ .pk-accordion-item { border-bottom: 1px solid var(--pk-border); }
4
+ .pk-accordion-trigger {
5
+ width: 100%; display: flex; flex: 1; align-items: center; justify-content: space-between;
6
+ padding-block: 1rem; font-size: .875rem; font-weight: 500; text-align: left;
7
+ background: none; border: 0; cursor: pointer; color: inherit; transition: all .15s ease;
8
+ }
9
+ .pk-accordion-trigger:hover { text-decoration: underline; }
10
+ .pk-accordion-trigger-label { flex: 1; }
11
+ .pk-accordion-icon { display: inline-flex; opacity: .5; transition: transform .2s ease; }
12
+ .pk-accordion-icon svg { width: 1rem; height: 1rem; }
13
+ .pk-accordion-content { overflow-y: hidden; }
14
+ .pk-accordion-default-content { padding-bottom: 1rem; padding-top: 0; font-size: .875rem; }
@@ -0,0 +1,10 @@
1
+ module PhlexKit
2
+ # Vertically stacked, individually-collapsible sections. Ported from ruby_ui's
3
+ # RubyUI::Accordion. Compose Accordion > AccordionItem > (AccordionTrigger +
4
+ # AccordionContent). Animated open/close via the phlex-kit--accordion controller
5
+ # (native Web Animations API — no `motion` dependency).
6
+ class Accordion < BaseComponent
7
+ def initialize(**attrs) = (@attrs = attrs)
8
+ def view_template(&) = div(**mix({ class: "pk-accordion" }, @attrs), &)
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module PhlexKit
2
+ class AccordionContent < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&)
5
+ div(**mix({ class: "pk-accordion-content", data: { phlex_kit__accordion_target: "content", state: "closed" }, style: "height: 0px;", hidden: true }, @attrs), &)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ module PhlexKit
2
+ class AccordionDefaultContent < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&) = div(**mix({ class: "pk-accordion-default-content" }, @attrs), &)
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Convenience trigger: label on the left, chevron icon on the right.
3
+ class AccordionDefaultTrigger < BaseComponent
4
+ def initialize(**attrs) = (@attrs = attrs)
5
+ def view_template(&block)
6
+ button(**mix({ type: "button", class: "pk-accordion-trigger", data: { action: "click->phlex-kit--accordion#toggle" } }, @attrs)) do
7
+ span(class: "pk-accordion-trigger-label", &block)
8
+ render PhlexKit::AccordionIcon.new
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module PhlexKit
2
+ class AccordionIcon < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&block)
5
+ span(**mix({ class: "pk-accordion-icon", data: { phlex_kit__accordion_target: "icon" } }, @attrs)) do
6
+ if block
7
+ yield
8
+ else
9
+ svg(xmlns: "http://www.w3.org/2000/svg", viewbox: "0 0 20 20", fill: "currentColor") do |s|
10
+ s.path(fill_rule: "evenodd", clip_rule: "evenodd", d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z")
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ class AccordionItem < BaseComponent
3
+ def initialize(open: false, rotate_icon: 180, **attrs)
4
+ @open = open
5
+ @rotate_icon = rotate_icon
6
+ @attrs = attrs
7
+ end
8
+ def view_template(&)
9
+ div(**mix({ class: "pk-accordion-item", data: { controller: "phlex-kit--accordion", phlex_kit__accordion_open_value: @open, phlex_kit__accordion_rotate_icon_value: @rotate_icon } }, @attrs), &)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module PhlexKit
2
+ class AccordionTrigger < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&)
5
+ button(**mix({ type: "button", class: "pk-accordion-trigger", data: { action: "click->phlex-kit--accordion#toggle" } }, @attrs), &)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,32 @@
1
+ /* Co-located with alert.rb — UI::Alert (+ Title / Description). ruby_ui's
2
+ structure kept; Tailwind replaced with vanilla CSS on the palette tokens.
3
+ Geometry from ruby_ui (ring-1 ring-inset → border, rounded-lg, px-4 py-4,
4
+ text-sm). The variant tints reuse the flash colours (success/destructive/
5
+ warning) the admin already used. Theme tokens come from the global stylesheet. */
6
+ .pk-alert {
7
+ position: relative;
8
+ width: 100%;
9
+ border: 1px solid var(--pk-border);
10
+ border-radius: var(--pk-radius);
11
+ padding: .85rem 1rem;
12
+ font-size: .875rem;
13
+ background: color-mix(in oklab, var(--pk-surface) 60%, transparent);
14
+ color: var(--pk-text);
15
+ }
16
+ .pk-alert.success {
17
+ border-color: color-mix(in oklab, var(--pk-green) 40%, var(--pk-border));
18
+ background: color-mix(in oklab, var(--pk-green) 8%, transparent);
19
+ color: var(--pk-green);
20
+ }
21
+ .pk-alert.destructive {
22
+ border-color: color-mix(in oklab, var(--pk-red) 40%, var(--pk-border));
23
+ background: color-mix(in oklab, var(--pk-red) 8%, transparent);
24
+ color: var(--pk-red);
25
+ }
26
+ .pk-alert.warning {
27
+ border-color: color-mix(in oklab, var(--pk-amber) 40%, var(--pk-border));
28
+ background: color-mix(in oklab, var(--pk-amber) 8%, transparent);
29
+ color: var(--pk-amber);
30
+ }
31
+ .pk-alert-title { margin: 0 0 .25rem; font-weight: 500; line-height: 1.1; letter-spacing: -.01em; }
32
+ .pk-alert-description { font-size: .875rem; }
@@ -0,0 +1,37 @@
1
+ module PhlexKit
2
+ # Callout box, ported from ruby_ui's RubyUI::Alert. Presentational, no JS. A
3
+ # `variant:` selector (same shape as PhlexKit::Button) tints the box; compose with
4
+ # AlertTitle + AlertDescription:
5
+ #
6
+ # render PhlexKit::Alert.new(variant: :success) do
7
+ # render PhlexKit::AlertTitle.new { "Saved" }
8
+ # render PhlexKit::AlertDescription.new { "Your changes are live." }
9
+ # end
10
+ #
11
+ # ruby_ui's variants (nil / warning / success / destructive) map onto the
12
+ # palette tokens in vanilla CSS (alert.css). `VARIANTS.fetch` fails loud.
13
+ class Alert < BaseComponent
14
+ # variant => extra class appended after the base `ui-alert` (nil = neutral).
15
+ VARIANTS = {
16
+ default: nil,
17
+ warning: "warning",
18
+ success: "success",
19
+ destructive: "destructive"
20
+ }.freeze
21
+
22
+ def initialize(variant: :default, **attrs)
23
+ @variant = variant.to_sym
24
+ @attrs = attrs
25
+ end
26
+
27
+ def view_template(&block)
28
+ div(**mix({ class: classes }, @attrs), &block)
29
+ end
30
+
31
+ private
32
+
33
+ def classes
34
+ [ "pk-alert", VARIANTS.fetch(@variant) ].compact.join(" ")
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Body text of a PhlexKit::Alert. See alert.rb.
3
+ class AlertDescription < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ div(**mix({ class: "pk-alert-description" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Heading line of a PhlexKit::Alert. See alert.rb.
3
+ class AlertTitle < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ h5(**mix({ class: "pk-alert-title" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,37 @@
1
+ /* Co-located with alert_dialog.rb — UI::AlertDialog (+ Trigger / Content / Header
2
+ / Title / Description / Footer / Cancel / Action). ruby_ui's modal structure as
3
+ vanilla CSS on the palette tokens. Theme tokens come from the global stylesheet. */
4
+ .pk-alert-dialog { display: inline-block; }
5
+ .pk-alert-dialog-trigger { display: inline-block; }
6
+
7
+ .pk-alert-dialog-overlay {
8
+ position: fixed;
9
+ inset: 0;
10
+ z-index: 50;
11
+ background: rgba(0, 0, 0, .8);
12
+ backdrop-filter: blur(2px);
13
+ }
14
+ .pk-alert-dialog-panel {
15
+ position: fixed;
16
+ left: 50%;
17
+ top: 50%;
18
+ transform: translate(-50%, -50%);
19
+ z-index: 50;
20
+ display: flex;
21
+ flex-direction: column;
22
+ gap: 1rem;
23
+ width: calc(100% - 2rem);
24
+ max-width: 32rem;
25
+ max-height: 100vh;
26
+ overflow-y: auto;
27
+ border: 1px solid var(--pk-border);
28
+ border-radius: var(--pk-radius);
29
+ background: var(--pk-surface);
30
+ color: var(--pk-text);
31
+ padding: 1.5rem;
32
+ box-shadow: 0 10px 40px rgba(0, 0, 0, .5);
33
+ }
34
+ .pk-alert-dialog-header { display: flex; flex-direction: column; gap: .5rem; }
35
+ .pk-alert-dialog-title { margin: 0; font-size: 1.125rem; font-weight: 600; }
36
+ .pk-alert-dialog-description { margin: 0; font-size: .875rem; color: var(--pk-muted); }
37
+ .pk-alert-dialog-footer { display: flex; justify-content: flex-end; gap: .5rem; flex-wrap: wrap; }
@@ -0,0 +1,20 @@
1
+ module PhlexKit
2
+ # Modal confirm dialog, ported from ruby_ui's RubyUI::AlertDialog. Keeps the
3
+ # Stimulus controller: the trigger clones the (template) content into <body> as
4
+ # a modal; Cancel removes it. No floating-ui. Compose Trigger + Content
5
+ # (Header/Title/Description + Footer with Cancel + the destructive submit).
6
+ # Tailwind → vanilla `.pk-alert-dialog*` (alert_dialog.css).
7
+ class AlertDialog < BaseComponent
8
+ def initialize(open: false, **attrs)
9
+ @open = open
10
+ @attrs = attrs
11
+ end
12
+
13
+ def view_template(&block)
14
+ div(**mix({
15
+ class: "pk-alert-dialog",
16
+ data: { controller: "phlex-kit--alert-dialog", phlex_kit__alert_dialog_open_value: @open.to_s }
17
+ }, @attrs), &block)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module PhlexKit
2
+ # The confirm action in a PhlexKit::AlertDialog footer — a primary PhlexKit::Button. (For a
3
+ # non-GET destructive action, use a `button_to` in the footer instead, so it
4
+ # submits a real form.) See alert_dialog.rb.
5
+ class AlertDialogAction < BaseComponent
6
+ def initialize(**attrs)
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template(&block)
11
+ render PhlexKit::Button.new(variant: :primary, **@attrs, &block)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module PhlexKit
2
+ # The dismiss button in a PhlexKit::AlertDialog footer — an outline PhlexKit::Button wired to
3
+ # the controller's #dismiss (removes the modal). See alert_dialog.rb.
4
+ class AlertDialogCancel < BaseComponent
5
+ def initialize(**attrs)
6
+ @attrs = attrs
7
+ end
8
+
9
+ def view_template(&block)
10
+ render PhlexKit::Button.new(variant: :outline, data: { action: "click->phlex-kit--alert-dialog#dismiss" }, **@attrs, &block)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module PhlexKit
2
+ # The modal body, held in a <template> and cloned into <body> on open. The
3
+ # cloned div carries its own `phlex-kit--alert-dialog` controller so Cancel
4
+ # (#dismiss) can remove it. Holds Header + Footer. See alert_dialog.rb.
5
+ class AlertDialogContent < BaseComponent
6
+ def initialize(**attrs)
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template(&block)
11
+ template(**mix({ data: { phlex_kit__alert_dialog_target: "content" } }, @attrs)) do
12
+ div(data: { controller: "phlex-kit--alert-dialog" }) do
13
+ div(class: "pk-alert-dialog-overlay", "aria-hidden": "true")
14
+ div(role: "alertdialog", "aria-modal": "true", class: "pk-alert-dialog-panel", &block)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Body text of a PhlexKit::AlertDialog. See alert_dialog.rb.
3
+ class AlertDialogDescription < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ p(**mix({ class: "pk-alert-dialog-description" }, @attrs), &block)
10
+ end
11
+ end
12
+ end