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,21 @@
1
+ module PhlexKit
2
+ # The text shown in a PhlexKit::SelectTrigger — the selected item's label (yielded
3
+ # block) or the `placeholder:` when nothing is chosen. The Stimulus controller
4
+ # rewrites this element's text on selection. See select.rb.
5
+ class SelectValue < BaseComponent
6
+ def initialize(placeholder: nil, **attrs)
7
+ @placeholder = placeholder
8
+ @attrs = attrs
9
+ end
10
+
11
+ def view_template(&block)
12
+ span(**mix({ class: "pk-select-value", data: { phlex_kit__select_target: "value" } }, @attrs)) do
13
+ if block
14
+ yield
15
+ elsif @placeholder
16
+ plain @placeholder
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ /* Co-located with separator.rb — UI::Separator. ruby_ui's Tailwind
2
+ (`shrink-0 bg-border` + `h-[1px] w-full` / `h-full w-[1px]`) as vanilla CSS on
3
+ the palette tokens. Theme tokens come from the global stylesheet. */
4
+ .pk-separator { flex-shrink: 0; background: var(--pk-border); border: 0; }
5
+ .pk-separator.horizontal { height: 1px; width: 100%; }
6
+ .pk-separator.vertical { height: 100%; width: 1px; }
@@ -0,0 +1,30 @@
1
+ module PhlexKit
2
+ # Visual/semantic divider, ported from ruby_ui's RubyUI::Separator. `as:` picks
3
+ # the element (div/hr), `orientation:` is horizontal (default) or vertical, and
4
+ # `decorative:` toggles the a11y role (none vs separator). Presentational; attrs
5
+ # pass through via `mix`. A bad orientation fails loud (ArgumentError), mirroring
6
+ # the kit's fail-loud selectors.
7
+ class Separator < BaseComponent
8
+ ORIENTATIONS = %i[horizontal vertical].freeze
9
+
10
+ def initialize(as: :div, orientation: :horizontal, decorative: true, **attrs)
11
+ @as = as
12
+ @orientation = orientation.to_sym
13
+ unless ORIENTATIONS.include?(@orientation)
14
+ raise ArgumentError, "Invalid orientation: #{orientation.inspect}"
15
+ end
16
+ @decorative = decorative
17
+ @attrs = attrs
18
+ end
19
+
20
+ def view_template(&block)
21
+ send(@as, **mix({ role: (@decorative ? "none" : "separator"), class: classes }, @attrs), &block)
22
+ end
23
+
24
+ private
25
+
26
+ def classes
27
+ [ "pk-separator", @orientation.to_s ].join(" ")
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ /* Co-located with sheet.rb. Theme tokens from the global stylesheet. */
2
+ .pk-sheet-trigger { display: inline-block; }
3
+ .pk-sheet-backdrop { position: fixed; inset: 0; z-index: 50; background: rgb(0 0 0 / .5); backdrop-filter: blur(2px); }
4
+ .pk-sheet-content {
5
+ position: fixed; z-index: 50; display: flex; flex-direction: column; gap: 1rem;
6
+ background: var(--pk-surface); color: var(--pk-text); padding: 1.5rem;
7
+ box-shadow: 0 10px 30px rgb(0 0 0 / .35); overflow: auto;
8
+ }
9
+ .pk-sheet-content.right { inset-block: 0; right: 0; height: 100%; width: min(24rem, 100%); border-left: 1px solid var(--pk-border); }
10
+ .pk-sheet-content.left { inset-block: 0; left: 0; height: 100%; width: min(24rem, 100%); border-right: 1px solid var(--pk-border); }
11
+ .pk-sheet-content.top { inset-inline: 0; top: 0; border-bottom: 1px solid var(--pk-border); }
12
+ .pk-sheet-content.bottom { inset-inline: 0; bottom: 0; border-top: 1px solid var(--pk-border); }
13
+ .pk-sheet-header { display: flex; flex-direction: column; gap: .375rem; }
14
+ .pk-sheet-footer { display: flex; flex-direction: column-reverse; gap: .5rem; }
15
+ .pk-sheet-title { font-size: 1.125rem; font-weight: 600; line-height: 1; letter-spacing: -.01em; }
16
+ .pk-sheet-description { font-size: .875rem; color: var(--pk-muted); }
17
+ .pk-sheet-middle { padding-block: 1rem; }
@@ -0,0 +1,14 @@
1
+ module PhlexKit
2
+ # Side panel (drawer). Ported from ruby_ui's RubyUI::Sheet. Compose Sheet >
3
+ # (SheetTrigger + SheetContent(side:) > SheetHeader/Title/Description/Footer).
4
+ # On open the content template is cloned into <body>. phlex-kit--sheet.
5
+ class Sheet < BaseComponent
6
+ def initialize(open: false, **attrs)
7
+ @open = open
8
+ @attrs = attrs
9
+ end
10
+ def view_template(&)
11
+ div(**mix({ data: { controller: "phlex-kit--sheet", phlex_kit__sheet_open_value: @open.to_s } }, @attrs), &)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ module PhlexKit
2
+ class SheetContent < BaseComponent
3
+ SIDES = { top: "top", right: "right", bottom: "bottom", left: "left" }.freeze
4
+ def initialize(side: :right, **attrs)
5
+ @side = side.to_sym
6
+ @attrs = attrs
7
+ end
8
+ def view_template(&block)
9
+ template(data: { phlex_kit__sheet_target: "content" }) do
10
+ div(data: { controller: "phlex-kit--sheet-content" }) do
11
+ div(class: "pk-sheet-backdrop", data: { action: "click->phlex-kit--sheet-content#close" })
12
+ div(**mix({ class: ["pk-sheet-content", SIDES.fetch(@side)].join(" ") }, @attrs)) do
13
+ block&.call
14
+ button(type: "button", class: "pk-overlay-close", data: { action: "click->phlex-kit--sheet-content#close" }) do
15
+ svg(width: "15", height: "15", viewbox: "0 0 15 15", fill: "none", xmlns: "http://www.w3.org/2000/svg") do |s|
16
+ s.path(fill_rule: "evenodd", clip_rule: "evenodd", fill: "currentColor", d: "M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z")
17
+ end
18
+ span(class: "pk-sr-only") { "Close" }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,6 @@
1
+ module PhlexKit
2
+ class SheetDescription < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&) = p(**mix({ class: "pk-sheet-description" }, @attrs), &)
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module PhlexKit
2
+ class SheetFooter < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&) = div(**mix({ class: "pk-sheet-footer" }, @attrs), &)
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module PhlexKit
2
+ class SheetHeader < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&) = div(**mix({ class: "pk-sheet-header" }, @attrs), &)
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module PhlexKit
2
+ class SheetMiddle < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&) = div(**mix({ class: "pk-sheet-middle" }, @attrs), &)
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module PhlexKit
2
+ class SheetTitle < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&) = h3(**mix({ class: "pk-sheet-title" }, @attrs), &)
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module PhlexKit
2
+ class SheetTrigger < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&) = div(**mix({ class: "pk-sheet-trigger", data: { action: "click->phlex-kit--sheet#open" } }, @attrs), &)
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ /* Co-located with shortcut_key.rb. Theme tokens from the global stylesheet. */
2
+ .pk-shortcut-key {
3
+ pointer-events: none;
4
+ user-select: none;
5
+ display: inline-flex;
6
+ height: 1.25rem;
7
+ align-items: center;
8
+ gap: .25rem;
9
+ border: 1px solid var(--pk-border);
10
+ border-radius: calc(var(--pk-radius) - 4px);
11
+ background: var(--pk-surface-2);
12
+ padding-inline: .375rem;
13
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
14
+ font-size: 10px;
15
+ font-weight: 500;
16
+ color: var(--pk-muted);
17
+ }
@@ -0,0 +1,9 @@
1
+ module PhlexKit
2
+ # Keyboard-shortcut hint, rendered as <kbd>. Ported from ruby_ui's
3
+ # RubyUI::ShortcutKey. Purely visual — wires no key handler.
4
+ class ShortcutKey < BaseComponent
5
+ def initialize(**attrs) = (@attrs = attrs)
6
+
7
+ def view_template(&) = kbd(**mix({ class: "pk-shortcut-key" }, @attrs), &)
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ /* Co-located with sidebar.rb — UI::Sidebar (+ Wrapper / Header / Content / Footer
2
+ / Group / Menu / MenuItem / MenuButton / Inset). ruby_ui's structure at
3
+ collapsible:none, Tailwind → vanilla CSS on the palette tokens. The collapsible/
4
+ offcanvas/icon modes (+ their Stimulus/cookie/Sheet) are deliberately not ported.
5
+ Theme tokens come from the global stylesheet. */
6
+ .pk-sidebar-wrapper { display: flex; min-height: 100dvh; width: 100%; }
7
+
8
+ .pk-sidebar {
9
+ display: flex;
10
+ flex-direction: column;
11
+ width: 14rem;
12
+ flex-shrink: 0;
13
+ background: var(--pk-surface);
14
+ border-right: 1px solid var(--pk-border);
15
+ }
16
+
17
+ .pk-sidebar-header { display: flex; flex-direction: column; gap: .5rem; padding: 1rem .75rem .25rem; }
18
+ .pk-sidebar-content { display: flex; flex-direction: column; gap: .25rem; flex: 1; min-height: 0; overflow: auto; padding: .5rem .75rem; }
19
+ .pk-sidebar-footer { display: flex; flex-direction: column; gap: .5rem; padding: .75rem; }
20
+ .pk-sidebar-group { display: flex; flex-direction: column; gap: .125rem; }
21
+
22
+ .pk-sidebar-menu { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .125rem; width: 100%; }
23
+ .pk-sidebar-menu-item { position: relative; }
24
+ .pk-sidebar-menu-button {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: .5rem;
28
+ width: 100%;
29
+ padding: .5rem .65rem;
30
+ border: 0;
31
+ border-radius: 8px;
32
+ background: transparent;
33
+ color: var(--pk-text);
34
+ font: inherit;
35
+ font-size: .9rem;
36
+ text-align: left;
37
+ cursor: pointer;
38
+ }
39
+ .pk-sidebar-menu-button:hover { background: var(--pk-accent); text-decoration: none; }
40
+ .pk-sidebar-menu-button[data-active="true"] { background: var(--pk-brand); color: var(--pk-brand-ink); font-weight: 600; }
41
+
42
+ .pk-sidebar-inset { flex: 1; min-width: 0; }
@@ -0,0 +1,19 @@
1
+ module PhlexKit
2
+ # Sidebar shell, ported from ruby_ui's RubyUI::Sidebar at `collapsible: :none`
3
+ # (the NonCollapsibleSidebar path): a static flex-column rail. Deliberately
4
+ # WITHOUT ruby_ui's collapsible/offcanvas Stimulus controller + cookie state +
5
+ # mobile Sheet (the admin sidebar is static) — those can be added later if a
6
+ # collapsible chrome is wanted. Compose with SidebarWrapper (the page root) +
7
+ # SidebarHeader / SidebarContent / SidebarMenu (+ Item / Button) / SidebarFooter,
8
+ # alongside a SidebarInset for the main content. Tailwind → vanilla `.pk-sidebar*`
9
+ # (sidebar.css).
10
+ class Sidebar < BaseComponent
11
+ def initialize(**attrs)
12
+ @attrs = attrs
13
+ end
14
+
15
+ def view_template(&block)
16
+ div(**mix({ class: "pk-sidebar" }, @attrs), &block)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Scrollable middle region of a PhlexKit::Sidebar (holds the nav menu). See sidebar.rb.
3
+ class SidebarContent < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ div(**mix({ class: "pk-sidebar-content" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Bottom region of a PhlexKit::Sidebar (user identity + sign out). See sidebar.rb.
3
+ class SidebarFooter < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ div(**mix({ class: "pk-sidebar-footer" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # A cluster of menu items within SidebarContent. See sidebar.rb.
3
+ class SidebarGroup < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ div(**mix({ class: "pk-sidebar-group" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Top region of a PhlexKit::Sidebar (brand + store switcher). See sidebar.rb.
3
+ class SidebarHeader < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ div(**mix({ class: "pk-sidebar-header" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module PhlexKit
2
+ # The main content region beside a PhlexKit::Sidebar (renders <main>, flex-1). Pass
3
+ # `class: "main"` to keep the app's existing content padding/typography.
4
+ # See sidebar.rb.
5
+ class SidebarInset < BaseComponent
6
+ def initialize(**attrs)
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template(&block)
11
+ main(**mix({ class: "pk-sidebar-inset" }, @attrs), &block)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # The nav list (<ul>) inside SidebarContent. See sidebar.rb.
3
+ class SidebarMenu < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ ul(**mix({ class: "pk-sidebar-menu" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module PhlexKit
2
+ # The interactive element of a SidebarMenuItem. `as:` is :button (default) or :a
3
+ # (pass `href:`); `active: true` marks the current page (drives the highlight via
4
+ # data-active — a named kwarg, not an attr, since `mix` would merge a repeated
5
+ # attribute rather than override). Attrs pass through via mix. See sidebar.rb.
6
+ class SidebarMenuButton < BaseComponent
7
+ def initialize(as: :button, active: false, **attrs)
8
+ @as = as
9
+ @active = active
10
+ @attrs = attrs
11
+ end
12
+
13
+ def view_template(&block)
14
+ send(@as, **mix({ class: "pk-sidebar-menu-button", "data-active": (@active ? "true" : "false") }, @attrs), &block)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # A single nav row (<li>) in a SidebarMenu. See sidebar.rb.
3
+ class SidebarMenuItem < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ li(**mix({ class: "pk-sidebar-menu-item" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module PhlexKit
2
+ # The page-level flex row that holds a PhlexKit::Sidebar + a PhlexKit::SidebarInset.
3
+ # See sidebar.rb.
4
+ class SidebarWrapper < BaseComponent
5
+ def initialize(**attrs)
6
+ @attrs = attrs
7
+ end
8
+
9
+ def view_template(&block)
10
+ div(**mix({ class: "pk-sidebar-wrapper" }, @attrs), &block)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ /* Co-located with skeleton.rb. Theme tokens come from the global stylesheet. */
2
+ .pk-skeleton {
3
+ border-radius: calc(var(--pk-radius) - 2px);
4
+ background: color-mix(in oklab, var(--pk-brand, #6c8cff) 10%, transparent);
5
+ animation: pk-pulse 1.5s cubic-bezier(.4, 0, .6, 1) infinite;
6
+ }
7
+ @keyframes pk-pulse { 50% { opacity: .5; } }
@@ -0,0 +1,9 @@
1
+ module PhlexKit
2
+ # Placeholder shimmer for loading content. Ported from ruby_ui's RubyUI::Skeleton
3
+ # (Tailwind `animate-pulse rounded-md bg-primary/10` → vanilla .pk-skeleton).
4
+ class Skeleton < BaseComponent
5
+ def initialize(**attrs) = (@attrs = attrs)
6
+
7
+ def view_template(&) = div(**mix({ class: "pk-skeleton" }, @attrs), &)
8
+ end
9
+ end
@@ -0,0 +1,52 @@
1
+ /* Co-located with slider.rb — UI::Slider, shadcn parity on a native range
2
+ input: muted track, primary filled portion (--pk-slider-progress, kept in
3
+ sync by the controller), round bordered thumb. */
4
+ .pk-slider {
5
+ appearance: none;
6
+ -webkit-appearance: none;
7
+ width: 100%;
8
+ height: 1rem;
9
+ margin: 0;
10
+ background: transparent;
11
+ cursor: pointer;
12
+ }
13
+ .pk-slider:focus-visible { outline: none; }
14
+ .pk-slider::-webkit-slider-runnable-track {
15
+ height: .375rem;
16
+ border-radius: 9999px;
17
+ background: linear-gradient(to right,
18
+ var(--pk-brand) var(--pk-slider-progress, 50%),
19
+ var(--pk-surface-2) var(--pk-slider-progress, 50%));
20
+ }
21
+ .pk-slider::-webkit-slider-thumb {
22
+ -webkit-appearance: none;
23
+ width: 1rem;
24
+ height: 1rem;
25
+ margin-top: -0.3125rem;
26
+ border-radius: 9999px;
27
+ border: 1px solid var(--pk-brand);
28
+ background: var(--pk-bg);
29
+ box-shadow: 0 1px 2px rgb(0 0 0 / .25);
30
+ transition: box-shadow .15s ease;
31
+ }
32
+ .pk-slider:focus-visible::-webkit-slider-thumb {
33
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--pk-ring) 50%, transparent);
34
+ }
35
+ .pk-slider::-moz-range-track {
36
+ height: .375rem;
37
+ border-radius: 9999px;
38
+ background: var(--pk-surface-2);
39
+ }
40
+ .pk-slider::-moz-range-progress {
41
+ height: .375rem;
42
+ border-radius: 9999px;
43
+ background: var(--pk-brand);
44
+ }
45
+ .pk-slider::-moz-range-thumb {
46
+ width: 1rem;
47
+ height: 1rem;
48
+ border-radius: 9999px;
49
+ border: 1px solid var(--pk-brand);
50
+ background: var(--pk-bg);
51
+ }
52
+ .pk-slider:disabled { opacity: .5; cursor: not-allowed; }
@@ -0,0 +1,39 @@
1
+ module PhlexKit
2
+ # Range slider, ported from shadcn/ui's Slider. Radix's slider is replaced
3
+ # with a styled native <input type="range"> (keyboard/touch/forms for free);
4
+ # the tiny phlex-kit--slider controller keeps the filled-track width in sync
5
+ # via a custom property. `.pk-slider` (slider.css).
6
+ class Slider < BaseComponent
7
+ def initialize(min: 0, max: 100, step: 1, value: nil, **attrs)
8
+ @min = min
9
+ @max = max
10
+ @step = step
11
+ @value = value || (@min + (@max - @min) / 2)
12
+ @attrs = attrs
13
+ end
14
+
15
+ def view_template
16
+ input(**mix({
17
+ type: :range,
18
+ min: @min,
19
+ max: @max,
20
+ step: @step,
21
+ value: @value,
22
+ class: "pk-slider",
23
+ style: "--pk-slider-progress: #{progress}%",
24
+ data: {
25
+ controller: "phlex-kit--slider",
26
+ action: "input->phlex-kit--slider#update"
27
+ }
28
+ }, @attrs))
29
+ end
30
+
31
+ private
32
+
33
+ def progress
34
+ span = (@max - @min).to_f
35
+ return 0 if span.zero?
36
+ (((@value.to_f - @min) / span) * 100).round(2)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ /* Co-located with spinner.rb — UI::Spinner (shadcn's spinning loader). */
2
+ .pk-spinner { width: 1rem; height: 1rem; animation: pk-spin 1s linear infinite; }
3
+ .pk-spinner.sm { width: .75rem; height: .75rem; }
4
+ .pk-spinner.lg { width: 1.5rem; height: 1.5rem; }
5
+ @keyframes pk-spin { to { transform: rotate(360deg); } }
@@ -0,0 +1,27 @@
1
+ module PhlexKit
2
+ # Loading spinner, ported from shadcn/ui's Spinner (a spinning loader icon;
3
+ # not in ruby_ui). Sizes via SIZES.fetch. `.pk-spinner` (spinner.css).
4
+ class Spinner < BaseComponent
5
+ SIZES = { sm: "sm", md: nil, lg: "lg" }.freeze
6
+
7
+ def initialize(size: :md, **attrs)
8
+ @size = size.to_sym
9
+ @attrs = attrs
10
+ end
11
+
12
+ def view_template
13
+ svg(**mix({
14
+ xmlns: "http://www.w3.org/2000/svg",
15
+ viewbox: "0 0 24 24",
16
+ fill: "none",
17
+ stroke: "currentColor",
18
+ "stroke-width": "2",
19
+ "stroke-linecap": "round",
20
+ "stroke-linejoin": "round",
21
+ class: [ "pk-spinner", SIZES.fetch(@size) ].compact.join(" "),
22
+ role: "status",
23
+ aria: { label: "Loading" }
24
+ }, @attrs)) { |s| s.path(d: "M21 12a9 9 0 1 1-6.219-8.56") }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ /* Co-located with stars.rb — UI::Stars. The gold rating glyphs; self-colours so
2
+ product cards / summaries get amber stars too (the old `.review .stars` rule
3
+ only coloured stars inside a review). Theme tokens come from the global stylesheet. */
4
+ .pk-stars { color: var(--pk-amber); letter-spacing: 1px; }
@@ -0,0 +1,19 @@
1
+ module PhlexKit
2
+ # Star rating (CUSTOM — ruby_ui has no rating component). Replaces the `stars`
3
+ # view helper: renders `rating` filled stars + the remainder empty, out of
4
+ # `max`. Presentational; attrs pass through via mix. Self-colours (amber) so it
5
+ # works anywhere, not just inside a review.
6
+ class Stars < BaseComponent
7
+ def initialize(rating:, max: 5, **attrs)
8
+ @rating = rating.to_i.clamp(0, max)
9
+ @max = max
10
+ @attrs = attrs
11
+ end
12
+
13
+ def view_template
14
+ span(**mix({ class: "pk-stars", title: "#{@rating}/#{@max}" }, @attrs)) do
15
+ plain(("★" * @rating) + ("☆" * (@max - @rating)))
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ /* Co-located with switch.rb. Theme tokens from the global stylesheet. */
2
+ .pk-switch {
3
+ display: inline-flex;
4
+ height: 1.5rem;
5
+ width: 2.75rem;
6
+ flex: none;
7
+ cursor: pointer;
8
+ align-items: center;
9
+ border: 2px solid transparent;
10
+ border-radius: 9999px;
11
+ background: var(--pk-border);
12
+ transition: background-color .15s ease;
13
+ }
14
+ .pk-switch:has(.pk-switch-input:checked) { background: var(--pk-brand); }
15
+ .pk-switch:has(.pk-switch-input:disabled) { cursor: not-allowed; opacity: .5; }
16
+ .pk-switch-input { display: none; }
17
+ .pk-switch-thumb {
18
+ pointer-events: none;
19
+ display: block;
20
+ height: 1.25rem;
21
+ width: 1.25rem;
22
+ border-radius: 9999px;
23
+ background: var(--pk-surface);
24
+ box-shadow: 0 1px 3px rgb(0 0 0 / .3);
25
+ transition: transform .15s ease;
26
+ transform: translateX(0);
27
+ }
28
+ .pk-switch:has(.pk-switch-input:checked) .pk-switch-thumb { transform: translateX(1.25rem); }
@@ -0,0 +1,21 @@
1
+ module PhlexKit
2
+ # On/off toggle rendered as a checkbox styled as a track+thumb. Ported from
3
+ # ruby_ui's RubyUI::Switch — pure CSS (`:has(:checked)`), no Stimulus. Emits an
4
+ # optional hidden field so an unchecked box still posts a value (Rails idiom).
5
+ class Switch < BaseComponent
6
+ def initialize(include_hidden: true, checked_value: "1", unchecked_value: "0", **attrs)
7
+ @include_hidden = include_hidden
8
+ @checked_value = checked_value
9
+ @unchecked_value = unchecked_value
10
+ @attrs = attrs
11
+ end
12
+
13
+ def view_template
14
+ label(**mix({ role: "switch", class: "pk-switch" }, {})) do
15
+ input(type: "hidden", name: @attrs[:name], value: @unchecked_value) if @include_hidden
16
+ input(**mix({ class: "pk-switch-input" }, @attrs).merge(type: "checkbox", value: @checked_value))
17
+ span(class: "pk-switch-thumb")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ /* Co-located with table.rb — UI::Table (+ Header/Body/Footer/Row/Head/Cell/
2
+ Caption). ruby_ui's structure kept; Tailwind replaced with vanilla CSS on the
3
+ palette tokens. Geometry from ruby_ui (text-sm, h-10 px-2 heads, p-2 cells,
4
+ row bottom-border + hover). Theme tokens come from the global stylesheet. */
5
+ .pk-table-wrapper { position: relative; width: 100%; overflow: auto; }
6
+ .pk-table { width: 100%; border-collapse: collapse; caption-side: bottom; font-size: .875rem; }
7
+
8
+ .pk-table-header .pk-table-row { border-bottom: 1px solid var(--pk-border); }
9
+ .pk-table-body .pk-table-row:last-child { border-bottom: 0; }
10
+ .pk-table-footer { border-top: 1px solid var(--pk-border); font-weight: 500; }
11
+
12
+ .pk-table-row { border-bottom: 1px solid var(--pk-border); transition: background-color .12s ease; }
13
+ .pk-table-row:hover { background: color-mix(in oklab, var(--pk-surface-2) 60%, transparent); }
14
+
15
+ .pk-table-head {
16
+ height: 2.5rem;
17
+ padding: 0 .5rem;
18
+ text-align: left;
19
+ vertical-align: middle;
20
+ font-weight: 500;
21
+ color: var(--pk-muted);
22
+ }
23
+ .pk-table-cell { padding: .5rem; vertical-align: middle; }
24
+ .pk-table-caption { margin-top: 1rem; font-size: .875rem; color: var(--pk-muted); }