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,72 @@
1
+ /* Co-located with button.rb — UI::Button. ruby_ui's Tailwind replaced with
2
+ vanilla CSS on the palette tokens, at full variant/size parity. Geometry from
3
+ ruby_ui (inline-flex centred, rounded-md, h-9 default, font-medium, focus ring,
4
+ filled variants). Theme tokens come from the global stylesheet. */
5
+ .pk-button {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ justify-content: center;
9
+ white-space: nowrap;
10
+ gap: .375rem;
11
+ height: 2rem;
12
+ padding: .25rem .625rem;
13
+ border: 1px solid transparent;
14
+ border-radius: var(--pk-radius);
15
+ font: inherit;
16
+ font-size: .875rem;
17
+ font-weight: 500;
18
+ cursor: pointer;
19
+ transition: background-color .15s ease, color .15s ease, border-color .15s ease, box-shadow .15s ease;
20
+ }
21
+ .pk-button:focus-visible {
22
+ outline: none;
23
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--pk-ring) 50%, transparent);
24
+ }
25
+ .pk-button:disabled, .pk-button[disabled], .pk-button[aria-disabled="true"] {
26
+ pointer-events: none;
27
+ opacity: .5;
28
+ }
29
+
30
+ /* Sizes (md is the base above). */
31
+ .pk-button.sm { height: 1.75rem; padding: .25rem .5rem; font-size: .75rem; }
32
+ .pk-button.lg { height: 2.5rem; padding: .375rem 1rem; font-size: .875rem; }
33
+ .pk-button.xl { height: 3rem; padding: .625rem 1.5rem; font-size: 1rem; }
34
+
35
+ /* Icon-only square buttons. */
36
+ .pk-button.icon { width: 2rem; padding: 0; }
37
+ .pk-button.icon.sm { width: 1.75rem; }
38
+ .pk-button.icon.lg { width: 2.5rem; }
39
+ .pk-button.icon.xl { width: 3rem; }
40
+
41
+ /* Variants. */
42
+ .pk-button.primary {
43
+ background: var(--pk-brand);
44
+ color: var(--pk-brand-ink);
45
+ border-color: var(--pk-brand);
46
+ }
47
+ .pk-button.primary:hover { background: color-mix(in oklab, var(--pk-brand) 90%, transparent); border-color: transparent; }
48
+
49
+ .pk-button.secondary { background: var(--pk-surface-2); color: var(--pk-text); }
50
+ .pk-button.secondary:hover { background: color-mix(in oklab, var(--pk-surface-2) 80%, transparent); }
51
+
52
+ .pk-button.destructive {
53
+ background: var(--pk-red);
54
+ color: var(--pk-brand-ink);
55
+ border-color: var(--pk-red);
56
+ }
57
+ .pk-button.destructive:hover { background: color-mix(in oklab, var(--pk-red) 88%, black); }
58
+
59
+ .pk-button.outline { background: color-mix(in oklab, var(--pk-input) 30%, transparent); color: var(--pk-text); border-color: var(--pk-input); }
60
+ .pk-button.outline:hover { background: var(--pk-accent); }
61
+
62
+ .pk-button.ghost { background: transparent; border-color: transparent; color: var(--pk-text); }
63
+ .pk-button.ghost:hover { background: var(--pk-accent); }
64
+
65
+ .pk-button.link {
66
+ height: auto;
67
+ padding: 0;
68
+ background: transparent;
69
+ border-color: transparent;
70
+ color: var(--pk-brand);
71
+ }
72
+ .pk-button.link:hover { text-decoration: underline; }
@@ -0,0 +1,51 @@
1
+ module PhlexKit
2
+ # Button, ported from ruby_ui's RubyUI::Button (https://ruby-ui.com) to full
3
+ # variant/size parity. Renders a <button>; the `mix` pass-through means a
4
+ # caller's `class:` augments ours and a phlex-reactive `**on(:event)` bundle
5
+ # flows straight onto the element:
6
+ #
7
+ # render PhlexKit::Button.new(variant: :primary, **on(:publish)) { "Approve" }
8
+ #
9
+ # For a button-styled link, put the classes on an <a> directly
10
+ # (`class: "pk-button outline sm"`) — that's ruby_ui's Link approach.
11
+ #
12
+ # Variants/sizes mirror ruby_ui; Tailwind is replaced with vanilla `.pk-button`
13
+ # CSS (button.css). `VARIANTS.fetch`/`SIZES.fetch` fail loud on a bad value.
14
+ class Button < BaseComponent
15
+ # variant => modifier class. Default is :primary (the filled brand button),
16
+ # matching ruby_ui.
17
+ VARIANTS = {
18
+ primary: "primary",
19
+ secondary: "secondary",
20
+ destructive: "destructive",
21
+ outline: "outline",
22
+ ghost: "ghost",
23
+ link: "link"
24
+ }.freeze
25
+
26
+ SIZES = {
27
+ sm: "sm",
28
+ md: nil,
29
+ lg: "lg",
30
+ xl: "xl"
31
+ }.freeze
32
+
33
+ def initialize(variant: :primary, size: :md, type: :button, icon: false, **attrs)
34
+ @variant = variant.to_sym
35
+ @size = size.to_sym
36
+ @type = type
37
+ @icon = icon
38
+ @attrs = attrs
39
+ end
40
+
41
+ def view_template(&block)
42
+ button(**mix({ type: @type, class: classes }, @attrs), &block)
43
+ end
44
+
45
+ private
46
+
47
+ def classes
48
+ [ "pk-button", VARIANTS.fetch(@variant), SIZES.fetch(@size), ("icon" if @icon) ].compact.join(" ")
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,8 @@
1
+ /* Co-located with button_group.rb — UI::ButtonGroup, shadcn parity: children
2
+ join into one segmented control (shared borders, inner corners squared). */
3
+ .pk-button-group { display: inline-flex; align-items: stretch; }
4
+ .pk-button-group > * { border-radius: 0; }
5
+ .pk-button-group > *:not(:first-child) { margin-left: -1px; }
6
+ .pk-button-group > *:first-child { border-top-left-radius: var(--pk-radius); border-bottom-left-radius: var(--pk-radius); }
7
+ .pk-button-group > *:last-child { border-top-right-radius: var(--pk-radius); border-bottom-right-radius: var(--pk-radius); }
8
+ .pk-button-group > *:focus-visible { position: relative; z-index: 1; }
@@ -0,0 +1,14 @@
1
+ module PhlexKit
2
+ # Joined row of buttons, ported from shadcn/ui's ButtonGroup: children lose
3
+ # their inner corners/double borders and read as one segmented control.
4
+ # `.pk-button-group` (button_group.css).
5
+ class ButtonGroup < BaseComponent
6
+ def initialize(**attrs)
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template(&)
11
+ div(**mix({ class: "pk-button-group", role: "group" }, @attrs), &)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,109 @@
1
+ /* Co-located with calendar.rb — UI::Calendar. ruby_ui's structure + Stimulus
2
+ kept (the controller renders week rows from <template>s; its Mustache
3
+ dependency replaced with a tiny interpolator); Tailwind replaced with vanilla
4
+ CSS on the palette tokens. Geometry from ruby_ui (p-3 card, h-7 nav buttons,
5
+ 2rem day cells, flex week rows). Theme tokens come from the global
6
+ stylesheet. */
7
+ .pk-calendar {
8
+ display: inline-flex;
9
+ flex-direction: column;
10
+ gap: 1rem;
11
+ padding: .75rem;
12
+ }
13
+
14
+ .pk-calendar-header {
15
+ position: relative;
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: center;
19
+ padding-top: .25rem;
20
+ }
21
+ .pk-calendar-title { font-size: .875rem; font-weight: 500; }
22
+
23
+ .pk-calendar-prev, .pk-calendar-next {
24
+ position: absolute;
25
+ display: inline-flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ width: 1.75rem;
29
+ height: 1.75rem;
30
+ padding: 0;
31
+ border: 1px solid var(--pk-input);
32
+ border-radius: calc(var(--pk-radius) - 2px);
33
+ background: transparent;
34
+ color: var(--pk-text);
35
+ cursor: pointer;
36
+ opacity: .5;
37
+ transition: background-color .15s ease, opacity .15s ease;
38
+ }
39
+ .pk-calendar-prev { left: .25rem; }
40
+ .pk-calendar-next { right: .25rem; }
41
+ .pk-calendar-prev:hover, .pk-calendar-next:hover { background: var(--pk-accent); opacity: 1; }
42
+ .pk-calendar-prev:focus-visible, .pk-calendar-next:focus-visible {
43
+ outline: none;
44
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--pk-ring) 50%, transparent);
45
+ }
46
+ .pk-calendar-prev:disabled, .pk-calendar-next:disabled { pointer-events: none; opacity: .5; }
47
+ .pk-calendar-prev svg, .pk-calendar-next svg { width: 1rem; height: 1rem; }
48
+
49
+ /* Rows are flex (the controller emits <tr class="pk-calendar-week">). */
50
+ .pk-calendar-weekdays-row { display: flex; }
51
+ .pk-calendar-week { display: flex; width: 100%; margin-top: .5rem; }
52
+ .pk-calendar-weekday {
53
+ width: 2rem;
54
+ border-radius: calc(var(--pk-radius) - 2px);
55
+ font-size: .8rem;
56
+ font-weight: 400;
57
+ color: var(--pk-muted);
58
+ }
59
+
60
+ .pk-calendar-cell {
61
+ position: relative;
62
+ padding: 0;
63
+ text-align: center;
64
+ font-size: .875rem;
65
+ }
66
+ .pk-calendar-cell:has([aria-selected]) {
67
+ background: var(--pk-accent);
68
+ border-radius: calc(var(--pk-radius) - 2px);
69
+ }
70
+ .pk-calendar-cell:focus-within { position: relative; z-index: 20; }
71
+
72
+ /* Day button states (base = current month). */
73
+ .pk-calendar-day {
74
+ display: inline-flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ width: 2rem;
78
+ height: 2rem;
79
+ padding: 0;
80
+ border: 0;
81
+ border-radius: calc(var(--pk-radius) - 2px);
82
+ background: transparent;
83
+ color: var(--pk-text);
84
+ font: inherit;
85
+ font-size: .875rem;
86
+ font-weight: 400;
87
+ cursor: pointer;
88
+ transition: background-color .15s ease, color .15s ease;
89
+ }
90
+ .pk-calendar-day:hover { background: var(--pk-accent); }
91
+ .pk-calendar-day:focus-visible {
92
+ outline: none;
93
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--pk-ring) 50%, transparent);
94
+ }
95
+ .pk-calendar-day.other { color: var(--pk-muted); }
96
+ .pk-calendar-day.today { background: var(--pk-accent); }
97
+ .pk-calendar-day.selected {
98
+ background: var(--pk-brand);
99
+ color: var(--pk-brand-ink);
100
+ }
101
+ .pk-calendar-day.selected:hover, .pk-calendar-day.selected:focus { background: var(--pk-brand); }
102
+ .pk-calendar-day.disabled,
103
+ .pk-calendar-day:disabled {
104
+ pointer-events: none;
105
+ cursor: not-allowed;
106
+ background: transparent;
107
+ color: var(--pk-muted);
108
+ opacity: .5;
109
+ }
@@ -0,0 +1,47 @@
1
+ module PhlexKit
2
+ # Calendar (month grid with day selection), ported from ruby_ui's
3
+ # RubyUI::Calendar. Renders the header (title + prev/next), the <table> the
4
+ # phlex-kit--calendar controller fills, and the <template>s it clones per day
5
+ # state (upstream's Mustache dependency is replaced with a tiny {{key}}
6
+ # interpolator in the controller). Pass `input_id:` a CSS selector (e.g.
7
+ # "#due-date") to push the picked date into a phlex-kit--calendar-input outlet —
8
+ # that's how PhlexKit::DatePicker binds it to an Input. Tailwind → vanilla
9
+ # `.pk-calendar*` (calendar.css).
10
+ class Calendar < BaseComponent
11
+ def initialize(selected_date: nil, min_date: nil, input_id: nil, date_format: "yyyy-MM-dd", **attrs)
12
+ @selected_date = selected_date
13
+ @min_date = min_date
14
+ @input_id = input_id
15
+ @date_format = date_format
16
+ @attrs = attrs
17
+ end
18
+
19
+ def view_template
20
+ div(**mix(calendar_attrs, @attrs)) do
21
+ render CalendarHeader.new do
22
+ render CalendarTitle.new
23
+ render CalendarPrev.new
24
+ render CalendarNext.new
25
+ end
26
+ render CalendarBody.new # Where the calendar is rendered (Weekdays and Days)
27
+ render CalendarWeekdays.new # Template for the weekdays
28
+ render CalendarDays.new # Templates for the day states
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def calendar_attrs
35
+ {
36
+ class: "pk-calendar",
37
+ data: {
38
+ controller: "phlex-kit--calendar",
39
+ phlex_kit__calendar_selected_date_value: @selected_date&.to_s,
40
+ phlex_kit__calendar_min_date_value: @min_date&.to_s,
41
+ phlex_kit__calendar_format_value: @date_format,
42
+ phlex_kit__calendar_phlex_kit__calendar_input_outlet: @input_id
43
+ }
44
+ }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,13 @@
1
+ module PhlexKit
2
+ # The <table> the controller renders the weekday header + day grid into.
3
+ # See calendar.rb.
4
+ class CalendarBody < BaseComponent
5
+ def initialize(**attrs)
6
+ @attrs = attrs
7
+ end
8
+
9
+ def view_template
10
+ table(**mix({ class: "pk-calendar-body", data: { phlex_kit__calendar_target: "calendar" } }, @attrs))
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,98 @@
1
+ module PhlexKit
2
+ # <template>s for the five day states (disabled / selected / today / current
3
+ # month / other month). The controller picks one per day and interpolates
4
+ # {{day}} / {{dayDate}}. See calendar.rb.
5
+ class CalendarDays < BaseComponent
6
+ def initialize(**attrs)
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template
11
+ render_disabled_date_template
12
+ render_selected_date_template
13
+ render_today_date_template
14
+ render_current_month_date_template
15
+ render_other_month_date_template
16
+ end
17
+
18
+ private
19
+
20
+ def render_disabled_date_template
21
+ date_template("disabledDateTemplate") do
22
+ button(
23
+ data_day: "{{day}}",
24
+ name: "day",
25
+ class: "pk-calendar-day disabled",
26
+ disabled: true,
27
+ role: "gridcell",
28
+ tabindex: "-1",
29
+ type: "button",
30
+ aria_disabled: "true"
31
+ ) { "{{dayDate}}" }
32
+ end
33
+ end
34
+
35
+ def render_selected_date_template
36
+ date_template("selectedDateTemplate") do
37
+ button(
38
+ data_day: "{{day}}",
39
+ data_action: "click->phlex-kit--calendar#selectDay",
40
+ name: "day",
41
+ class: "pk-calendar-day selected",
42
+ role: "gridcell",
43
+ tabindex: "0",
44
+ type: "button",
45
+ aria_selected: "true"
46
+ ) { "{{dayDate}}" }
47
+ end
48
+ end
49
+
50
+ def render_today_date_template
51
+ date_template("todayDateTemplate") do
52
+ button(
53
+ data_day: "{{day}}",
54
+ data_action: "click->phlex-kit--calendar#selectDay",
55
+ name: "day",
56
+ class: "pk-calendar-day today",
57
+ role: "gridcell",
58
+ tabindex: "-1",
59
+ type: "button"
60
+ ) { "{{dayDate}}" }
61
+ end
62
+ end
63
+
64
+ def render_current_month_date_template
65
+ date_template("currentMonthDateTemplate") do
66
+ button(
67
+ data_day: "{{day}}",
68
+ data_action: "click->phlex-kit--calendar#selectDay",
69
+ name: "day",
70
+ class: "pk-calendar-day",
71
+ role: "gridcell",
72
+ tabindex: "-1",
73
+ type: "button"
74
+ ) { "{{dayDate}}" }
75
+ end
76
+ end
77
+
78
+ def render_other_month_date_template
79
+ date_template("otherMonthDateTemplate") do
80
+ button(
81
+ data_day: "{{day}}",
82
+ data_action: "click->phlex-kit--calendar#selectDay",
83
+ name: "day",
84
+ class: "pk-calendar-day other",
85
+ role: "gridcell",
86
+ tabindex: "-1",
87
+ type: "button"
88
+ ) { "{{dayDate}}" }
89
+ end
90
+ end
91
+
92
+ def date_template(target, &block)
93
+ template(data: { phlex_kit__calendar_target: target }) do
94
+ td(class: "pk-calendar-cell", role: "presentation", &block)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,13 @@
1
+ module PhlexKit
2
+ # Header row of a PhlexKit::Calendar — centers the CalendarTitle, with
3
+ # CalendarPrev/CalendarNext pinned to its edges. See calendar.rb.
4
+ class CalendarHeader < BaseComponent
5
+ def initialize(**attrs)
6
+ @attrs = attrs
7
+ end
8
+
9
+ def view_template(&)
10
+ div(**mix({ class: "pk-calendar-header" }, @attrs), &)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,40 @@
1
+ module PhlexKit
2
+ # Next-month button, pinned to the header's right edge. See calendar.rb.
3
+ class CalendarNext < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template
9
+ button(**mix({
10
+ type: :button,
11
+ name: "next-month",
12
+ class: "pk-calendar-next",
13
+ aria: { label: "Go to next month" },
14
+ data: { action: "click->phlex-kit--calendar#nextMonth" }
15
+ }, @attrs)) do
16
+ icon
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def icon
23
+ svg(
24
+ xmlns: "http://www.w3.org/2000/svg",
25
+ width: "15",
26
+ height: "15",
27
+ viewbox: "0 0 15 15",
28
+ fill: "none",
29
+ "aria-hidden": "true"
30
+ ) do |s|
31
+ s.path(
32
+ d: "M6.1584 3.13508C6.35985 2.94621 6.67627 2.95642 6.86514 3.15788L10.6151 7.15788C10.7954 7.3502 10.7954 7.64949 10.6151 7.84182L6.86514 11.8418C6.67627 12.0433 6.35985 12.0535 6.1584 11.8646C5.95694 11.6757 5.94673 11.3593 6.1356 11.1579L9.565 7.49985L6.1356 3.84182C5.94673 3.64036 5.95694 3.32394 6.1584 3.13508Z",
33
+ fill: "currentColor",
34
+ fill_rule: "evenodd",
35
+ clip_rule: "evenodd"
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ module PhlexKit
2
+ # Previous-month button, pinned to the header's left edge. See calendar.rb.
3
+ class CalendarPrev < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template
9
+ button(**mix({
10
+ type: :button,
11
+ name: "previous-month",
12
+ class: "pk-calendar-prev",
13
+ aria: { label: "Go to previous month" },
14
+ data: { action: "click->phlex-kit--calendar#prevMonth" }
15
+ }, @attrs)) do
16
+ icon
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def icon
23
+ svg(
24
+ xmlns: "http://www.w3.org/2000/svg",
25
+ width: "15",
26
+ height: "15",
27
+ viewbox: "0 0 15 15",
28
+ fill: "none",
29
+ "aria-hidden": "true"
30
+ ) do |s|
31
+ s.path(
32
+ d: "M8.84182 3.13514C9.04327 3.32401 9.05348 3.64042 8.86462 3.84188L5.43521 7.49991L8.86462 11.1579C9.05348 11.3594 9.04327 11.6758 8.84182 11.8647C8.64036 12.0535 8.32394 12.0433 8.13508 11.8419L4.38508 7.84188C4.20477 7.64955 4.20477 7.35027 4.38508 7.15794L8.13508 3.15794C8.32394 2.95648 8.64036 2.94628 8.84182 3.13514Z",
33
+ fill: "currentColor",
34
+ fill_rule: "evenodd",
35
+ clip_rule: "evenodd"
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ module PhlexKit
2
+ # "Month Year" heading — rewritten by the controller as you navigate.
3
+ # See calendar.rb.
4
+ class CalendarTitle < BaseComponent
5
+ def initialize(default: "Month Year", **attrs)
6
+ @default = default
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template
11
+ div(**mix({
12
+ class: "pk-calendar-title",
13
+ role: "presentation",
14
+ aria: { live: "polite" },
15
+ data: { phlex_kit__calendar_target: "title" }
16
+ }, @attrs)) { @default }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module PhlexKit
2
+ # <template> for the weekday header row, cloned into the CalendarBody on every
3
+ # render. See calendar.rb.
4
+ class CalendarWeekdays < BaseComponent
5
+ DAYS = %w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday].freeze
6
+
7
+ def initialize(**attrs)
8
+ @attrs = attrs
9
+ end
10
+
11
+ def view_template
12
+ template(data: { phlex_kit__calendar_target: "weekdaysTemplate" }) do
13
+ thead(**@attrs) do
14
+ tr(class: "pk-calendar-weekdays-row") do
15
+ DAYS.each { |day| render_day(day) }
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def render_day(day)
24
+ th(scope: "col", class: "pk-calendar-weekday", aria: { label: day }) { day[0..1] }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ /* Co-located with card.rb — the UI::Card container kit (Card + Header / Title /
2
+ Description / Content / Footer). Namespaced .pk-card* to avoid colliding with
3
+ the dashboard stat-tile .card in application.css. Theme tokens come from the
4
+ global stylesheet; translated from ruby_ui's Tailwind:
5
+ rounded-xl border bg-background shadow → border + radius + surface
6
+ flex flex-col space-y-1.5 p-6 → header column + gap + pad
7
+ font-semibold leading-none tracking-tight → title
8
+ text-sm text-muted-foreground → description
9
+ p-6 pt-0 / items-center p-6 pt-0 → content / footer (top pad sits in header) */
10
+ .pk-card { background: var(--pk-surface); border: 1px solid var(--pk-border); border-radius: .75rem; box-shadow: 0 1px 3px rgba(0, 0, 0, .3); }
11
+ .pk-card-header { display: flex; flex-direction: column; gap: .375rem; padding: 1.5rem; }
12
+ .pk-card-title { margin: 0; font-weight: 600; line-height: 1.1; letter-spacing: -.01em; }
13
+ .pk-card-description { margin: 0; font-size: .85rem; color: var(--pk-muted); }
14
+ .pk-card-content { padding: 0 1.5rem 1.5rem; }
15
+ .pk-card-footer { display: flex; align-items: center; gap: .5rem; padding: 0 1.5rem 1.5rem; }
@@ -0,0 +1,29 @@
1
+ module PhlexKit
2
+ # Container card kit, ported from ruby_ui's Card (https://ruby-ui.com). Six
3
+ # presentational parts — Card + CardHeader / CardTitle / CardDescription /
4
+ # CardContent / CardFooter — each wrapping its children in an element with a
5
+ # base class and passing arbitrary attrs straight through via `mix` (so a
6
+ # caller `class:` augments rather than clobbers, exactly like PhlexKit::Button).
7
+ #
8
+ # Styles are namespaced `.pk-card*` in card.css rather than `.card`: this app
9
+ # already uses `.card` for the dashboard stat tiles (application.css), which are
10
+ # a different, padded component. Compose the parts:
11
+ #
12
+ # render PhlexKit::Card.new do
13
+ # render PhlexKit::CardHeader.new do
14
+ # render PhlexKit::CardTitle.new { "Title" }
15
+ # render PhlexKit::CardDescription.new { "Subtitle" }
16
+ # end
17
+ # render PhlexKit::CardContent.new { "…" }
18
+ # render PhlexKit::CardFooter.new { render PhlexKit::Button.new { "Action" } }
19
+ # end
20
+ class Card < BaseComponent
21
+ def initialize(**attrs)
22
+ @attrs = attrs
23
+ end
24
+
25
+ def view_template(&block)
26
+ div(**mix({ class: "pk-card" }, @attrs), &block)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Body region of a PhlexKit::Card. See card.rb.
3
+ class CardContent < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ div(**mix({ class: "pk-card-content" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Muted subtitle under a PhlexKit::CardTitle — a <p>. See card.rb.
3
+ class CardDescription < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ p(**mix({ class: "pk-card-description" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Footer region of a PhlexKit::Card — typically a row of PhlexKit::Buttons. See card.rb.
3
+ class CardFooter < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ div(**mix({ class: "pk-card-footer" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Header region of PhlexKit::Card — stacks a CardTitle + CardDescription. See card.rb.
3
+ class CardHeader < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ div(**mix({ class: "pk-card-header" }, @attrs), &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Title line of a PhlexKit::Card header — an <h3>. See card.rb.
3
+ class CardTitle < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&block)
9
+ h3(**mix({ class: "pk-card-title" }, @attrs), &block)
10
+ end
11
+ end
12
+ end