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,26 @@
1
+ module PhlexKit
2
+ # Single-select input inside a PhlexKit::ComboboxItem — selecting one closes the
3
+ # popover. Also wired as a phlex-kit--form-field input so live validation works
4
+ # when the combobox sits inside a PhlexKit::FormField. See combobox.rb.
5
+ class ComboboxRadio < BaseComponent
6
+ def initialize(**attrs)
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template
11
+ input(**mix({
12
+ type: :radio,
13
+ class: "pk-combobox-radio",
14
+ data: {
15
+ phlex_kit__combobox_target: "input",
16
+ phlex_kit__form_field_target: "input",
17
+ action: [
18
+ "phlex-kit--combobox#inputChanged",
19
+ "input->phlex-kit--form-field#onInput",
20
+ "invalid->phlex-kit--form-field#onInvalid"
21
+ ].join(" ")
22
+ }
23
+ }, @attrs))
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,49 @@
1
+ module PhlexKit
2
+ # Filter input at the top of a PhlexKit::ComboboxPopover (magnifier icon +
3
+ # borderless search field). Filtering happens client-side against each item's
4
+ # text (or data-text). See combobox.rb.
5
+ class ComboboxSearchInput < BaseComponent
6
+ def initialize(placeholder:, **attrs)
7
+ @placeholder = placeholder
8
+ @attrs = attrs
9
+ end
10
+
11
+ def view_template
12
+ div(class: "pk-combobox-search") do
13
+ icon
14
+ input(**mix({
15
+ type: :search,
16
+ role: "searchbox",
17
+ autocorrect: "off",
18
+ autocomplete: "off",
19
+ spellcheck: "false",
20
+ placeholder: @placeholder,
21
+ class: "pk-combobox-search-input",
22
+ data: {
23
+ phlex_kit__combobox_target: "searchInput",
24
+ action: "keyup->phlex-kit--combobox#filterItems search->phlex-kit--combobox#filterItems"
25
+ }
26
+ }, @attrs))
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def icon
33
+ svg(
34
+ xmlns: "http://www.w3.org/2000/svg",
35
+ viewbox: "0 0 24 24",
36
+ fill: "none",
37
+ stroke: "currentColor",
38
+ "stroke-width": "2",
39
+ "stroke-linecap": "round",
40
+ "stroke-linejoin": "round",
41
+ class: "pk-combobox-search-icon",
42
+ "aria-hidden": "true"
43
+ ) do |s|
44
+ s.circle(cx: "11", cy: "11", r: "8")
45
+ s.path(d: "m21 21-4.3-4.3")
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,21 @@
1
+ module PhlexKit
2
+ # "Select all" checkbox for a multi-select combobox — wrap it in a
3
+ # PhlexKit::ComboboxItem above the list. Hidden while a filter term is active.
4
+ # See combobox.rb.
5
+ class ComboboxToggleAllCheckbox < BaseComponent
6
+ def initialize(**attrs)
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template
11
+ input(**mix({
12
+ type: :checkbox,
13
+ class: "pk-combobox-checkbox",
14
+ data: {
15
+ phlex_kit__combobox_target: "toggleAll",
16
+ action: "change->phlex-kit--combobox#toggleAllItems"
17
+ }
18
+ }, @attrs))
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,48 @@
1
+ module PhlexKit
2
+ # The closed-state button for PhlexKit::Combobox — shows the placeholder until the
3
+ # controller writes the selected item text (or "N <term>") into the content
4
+ # span. See combobox.rb.
5
+ class ComboboxTrigger < BaseComponent
6
+ def initialize(placeholder: "", **attrs)
7
+ @placeholder = placeholder
8
+ @attrs = attrs
9
+ end
10
+
11
+ def view_template
12
+ button(**mix({
13
+ type: :button,
14
+ class: "pk-combobox-trigger",
15
+ aria: { haspopup: "listbox", expanded: "false" },
16
+ data: {
17
+ placeholder: @placeholder,
18
+ phlex_kit__combobox_target: "trigger",
19
+ action: "phlex-kit--combobox#togglePopover"
20
+ }
21
+ }, @attrs)) do
22
+ span(class: "pk-combobox-trigger-content", data: { phlex_kit__combobox_target: "triggerContent" }) do
23
+ @placeholder
24
+ end
25
+ icon
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def icon
32
+ svg(
33
+ xmlns: "http://www.w3.org/2000/svg",
34
+ viewbox: "0 0 24 24",
35
+ fill: "none",
36
+ stroke: "currentColor",
37
+ "stroke-width": "2",
38
+ "stroke-linecap": "round",
39
+ "stroke-linejoin": "round",
40
+ class: "pk-combobox-trigger-icon",
41
+ "aria-hidden": "true"
42
+ ) do |s|
43
+ s.path(d: "m7 15 5 5 5-5")
44
+ s.path(d: "m7 9 5-5 5 5")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,104 @@
1
+ /* Co-located with command.rb — UI::Command (+ CommandDialog overlay). ruby_ui's
2
+ structure kept (template cloned into <body>, custom backdrop + centered panel,
3
+ like the shipped sheet); fuse.js replaced with a substring filter in the
4
+ controller, Tailwind with vanilla CSS on the palette tokens. Geometry from
5
+ ruby_ui (h-10 input, p-1 groups, px-2 py-1.5 rows, divide-y list). Theme
6
+ tokens come from the global stylesheet. */
7
+ .pk-command-dialog-trigger { display: inline-block; }
8
+
9
+ /* Backdrop of the cloned overlay. */
10
+ .pk-command-overlay {
11
+ position: fixed;
12
+ inset: 0;
13
+ z-index: 50;
14
+ pointer-events: auto;
15
+ background: color-mix(in oklab, var(--pk-bg) 80%, transparent);
16
+ backdrop-filter: blur(4px);
17
+ }
18
+
19
+ /* Centered palette panel. */
20
+ .pk-command-dialog {
21
+ position: fixed;
22
+ left: 50%;
23
+ top: 50%;
24
+ transform: translate(-50%, -50%);
25
+ z-index: 50;
26
+ pointer-events: auto;
27
+ display: grid;
28
+ gap: 1rem;
29
+ width: 100%;
30
+ max-width: 32rem;
31
+ border: 1px solid var(--pk-border);
32
+ border-radius: var(--pk-radius);
33
+ background: var(--pk-surface);
34
+ color: var(--pk-text);
35
+ box-shadow: 0 10px 30px rgb(0 0 0 / .35);
36
+ }
37
+ .pk-command-dialog.xs { max-width: 24rem; }
38
+ .pk-command-dialog.sm { max-width: 28rem; }
39
+ .pk-command-dialog.lg { max-width: 42rem; }
40
+ .pk-command-dialog.xl { max-width: 56rem; }
41
+ .pk-command-dialog.full { max-width: 100%; }
42
+
43
+ /* Search row. */
44
+ .pk-command-input-row {
45
+ display: flex;
46
+ align-items: center;
47
+ padding: 0 .75rem;
48
+ border-bottom: 1px solid var(--pk-border);
49
+ }
50
+ .pk-command-input-icon { flex: none; width: 1rem; height: 1rem; margin-right: .375rem; }
51
+ .pk-command-input {
52
+ width: 100%;
53
+ height: 2.5rem;
54
+ padding: .75rem 0;
55
+ border: none;
56
+ outline: none;
57
+ background: transparent;
58
+ color: var(--pk-text);
59
+ font: inherit;
60
+ font-size: .875rem;
61
+ }
62
+ .pk-command-input::placeholder { color: var(--pk-muted); }
63
+ .pk-command-input:disabled { cursor: not-allowed; opacity: .5; }
64
+
65
+ /* Groups, divided. */
66
+ .pk-command-list > * + * { border-top: 1px solid var(--pk-border); }
67
+ .pk-command-group {
68
+ overflow: hidden;
69
+ padding: .25rem;
70
+ color: var(--pk-text);
71
+ }
72
+ .pk-command-group [group-heading] {
73
+ padding: .375rem .5rem;
74
+ font-size: .75rem;
75
+ font-weight: 500;
76
+ color: var(--pk-muted);
77
+ }
78
+
79
+ /* One result row. */
80
+ .pk-command-item {
81
+ position: relative;
82
+ display: flex;
83
+ align-items: center;
84
+ gap: .5rem;
85
+ border-radius: calc(var(--pk-radius) - 4px);
86
+ padding: .375rem .5rem;
87
+ font-size: .875rem;
88
+ color: var(--pk-text);
89
+ text-decoration: none;
90
+ cursor: pointer;
91
+ user-select: none;
92
+ outline: none;
93
+ transition: background-color .12s ease;
94
+ }
95
+ .pk-command-item:hover,
96
+ .pk-command-item[aria-selected="true"] { background: var(--pk-accent); }
97
+ .pk-command-item[data-disabled] { pointer-events: none; opacity: .5; }
98
+
99
+ /* Filter empty state (hidden/shown by the controller). */
100
+ .pk-command-empty {
101
+ padding: 1.5rem 0;
102
+ text-align: center;
103
+ font-size: .875rem;
104
+ }
@@ -0,0 +1,18 @@
1
+ module PhlexKit
2
+ # Command palette, ported from ruby_ui's RubyUI::Command. The palette body:
3
+ # CommandInput + CommandList(CommandGroup > CommandItem) + CommandEmpty.
4
+ # Normally composed inside CommandDialog/CommandDialogContent, whose cloned
5
+ # wrapper carries the phlex-kit--command controller (matching ruby_ui); for an
6
+ # inline palette add `data: { controller: "phlex-kit--command" }` yourself.
7
+ # Upstream's fuse.js fuzzy search is replaced with a dependency-free substring
8
+ # match in the controller. Tailwind → vanilla `.pk-command*` (command.css).
9
+ class Command < BaseComponent
10
+ def initialize(**attrs)
11
+ @attrs = attrs
12
+ end
13
+
14
+ def view_template(&)
15
+ div(**mix({ class: "pk-command" }, @attrs), &)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ module PhlexKit
2
+ # Wrapper wiring a CommandDialogTrigger to its CommandDialogContent. The
3
+ # outlet selector finds the live palette instance (if already open) so a
4
+ # second trigger press just refocuses the input. See command.rb.
5
+ class CommandDialog < BaseComponent
6
+ def initialize(**attrs)
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template(&)
11
+ div(**mix({
12
+ data: {
13
+ controller: "phlex-kit--command-dialog",
14
+ phlex_kit__command_dialog_phlex_kit__command_outlet: "[data-phlex-kit--command-dialog-instance]"
15
+ }
16
+ }, @attrs), &)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,37 @@
1
+ module PhlexKit
2
+ # A <template> holding the palette overlay. Like PhlexKit::SheetContent, the
3
+ # phlex-kit--command-dialog controller clones it into <body> on open; the
4
+ # cloned wrapper carries the phlex-kit--command controller (+ the instance
5
+ # marker the outlet selector finds), a click/esc-dismiss backdrop, and the
6
+ # centered panel. See command.rb.
7
+ class CommandDialogContent < BaseComponent
8
+ SIZES = { xs: "xs", sm: "sm", md: nil, lg: "lg", xl: "xl", full: "full" }.freeze
9
+
10
+ def initialize(size: :md, **attrs)
11
+ @size = size.to_sym
12
+ @attrs = attrs
13
+ end
14
+
15
+ def view_template(&block)
16
+ template(data: { phlex_kit__command_dialog_target: "content" }) do
17
+ div(data: { controller: "phlex-kit--command", phlex_kit__command_dialog_instance: true }) do
18
+ backdrop
19
+ div(**mix({ class: panel_classes, data: { state: "open" } }, @attrs), &block)
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def panel_classes
27
+ [ "pk-command-dialog", SIZES.fetch(@size) ].compact.join(" ")
28
+ end
29
+
30
+ def backdrop
31
+ div(
32
+ class: "pk-command-overlay",
33
+ data: { state: "open", action: "click->phlex-kit--command#dismiss keydown.esc@window->phlex-kit--command#dismiss" }
34
+ )
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ module PhlexKit
2
+ # Opens the command palette on click and on ctrl/cmd+K (override with
3
+ # `keybindings:`). Wrap a PhlexKit::Button or any clickable. See command.rb.
4
+ class CommandDialogTrigger < BaseComponent
5
+ DEFAULT_KEYBINDINGS = [
6
+ "keydown.ctrl+k@window",
7
+ "keydown.meta+k@window"
8
+ ].freeze
9
+
10
+ def initialize(keybindings: DEFAULT_KEYBINDINGS, **attrs)
11
+ @keybindings = keybindings.map { |kb| "#{kb}->phlex-kit--command-dialog#open" }
12
+ @attrs = attrs
13
+ end
14
+
15
+ def view_template(&)
16
+ div(**mix({
17
+ class: "pk-command-dialog-trigger",
18
+ data: { action: [ "click->phlex-kit--command-dialog#open", *@keybindings ].join(" ") }
19
+ }, @attrs), &)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ module PhlexKit
2
+ # "No results" row — hidden by the controller until a filter matches nothing.
3
+ # See command.rb.
4
+ class CommandEmpty < BaseComponent
5
+ def initialize(**attrs)
6
+ @attrs = attrs
7
+ end
8
+
9
+ def view_template(&)
10
+ div(**mix({
11
+ class: "pk-command-empty",
12
+ role: "presentation",
13
+ data: { phlex_kit__command_target: "empty" }
14
+ }, @attrs), &)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ module PhlexKit
2
+ # Titled group of CommandItems. Hidden by the controller when filtering leaves
3
+ # it empty. The heading keeps ruby_ui's [group-heading] attribute (styled via
4
+ # the attribute selector in command.css). See command.rb.
5
+ class CommandGroup < BaseComponent
6
+ def initialize(title: nil, **attrs)
7
+ @title = title
8
+ @attrs = attrs
9
+ end
10
+
11
+ def view_template(&block)
12
+ div(**mix({
13
+ class: "pk-command-group",
14
+ role: "presentation",
15
+ data: { value: @title, phlex_kit__command_target: "group" }
16
+ }, @attrs)) do
17
+ render_header if @title
18
+ render_items(&block)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def render_header
25
+ div(group_heading: @title) { @title }
26
+ end
27
+
28
+ def render_items(&)
29
+ div(group_items: "", role: "group", &)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,56 @@
1
+ module PhlexKit
2
+ # Search field at the top of a PhlexKit::Command — filters the items as you
3
+ # type, arrows/enter drive selection, esc dismisses. See command.rb.
4
+ class CommandInput < BaseComponent
5
+ def initialize(placeholder: "Type a command or search...", **attrs)
6
+ @placeholder = placeholder
7
+ @attrs = attrs
8
+ end
9
+
10
+ def view_template
11
+ div(class: "pk-command-input-row") do
12
+ search_icon
13
+ input(**mix({
14
+ type: :text,
15
+ class: "pk-command-input",
16
+ placeholder: @placeholder,
17
+ autocomplete: "off",
18
+ autocorrect: "off",
19
+ spellcheck: "false",
20
+ autofocus: true,
21
+ role: "combobox",
22
+ value: "",
23
+ aria: { autocomplete: "list", expanded: "true" },
24
+ data: {
25
+ phlex_kit__command_target: "input",
26
+ action: [
27
+ "input->phlex-kit--command#filter",
28
+ "keydown.down->phlex-kit--command#handleKeydown",
29
+ "keydown.up->phlex-kit--command#handleKeydown",
30
+ "keydown.enter->phlex-kit--command#handleKeydown",
31
+ "keydown.esc->phlex-kit--command#dismiss"
32
+ ].join(" ")
33
+ }
34
+ }, @attrs))
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def search_icon
41
+ svg(
42
+ xmlns: "http://www.w3.org/2000/svg",
43
+ viewbox: "0 0 20 20",
44
+ fill: "currentColor",
45
+ class: "pk-command-input-icon",
46
+ "aria-hidden": "true"
47
+ ) do |s|
48
+ s.path(
49
+ fill_rule: "evenodd",
50
+ d: "M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z",
51
+ clip_rule: "evenodd"
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,22 @@
1
+ module PhlexKit
2
+ # One palette result — an <a> (pass `href:`) filtered by `value:`, activated
3
+ # by click or enter. aria-selected is toggled by keyboard navigation.
4
+ # See command.rb.
5
+ class CommandItem < BaseComponent
6
+ def initialize(value:, text: "", href: "#", **attrs)
7
+ @value = value
8
+ @text = text
9
+ @href = href
10
+ @attrs = attrs
11
+ end
12
+
13
+ def view_template(&)
14
+ a(**mix({
15
+ class: "pk-command-item",
16
+ href: @href,
17
+ role: "option",
18
+ data: { phlex_kit__command_target: "item", value: @value, text: @text }
19
+ }, @attrs), &)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ module PhlexKit
2
+ # Container for CommandGroups, with dividers between them. See command.rb.
3
+ class CommandList < BaseComponent
4
+ def initialize(**attrs)
5
+ @attrs = attrs
6
+ end
7
+
8
+ def view_template(&)
9
+ div(**mix({ class: "pk-command-list" }, @attrs), &)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ /* Co-located with context_menu.rb. CSS-positioned at the cursor. Tokens global. */
2
+ .pk-context-menu { position: relative; }
3
+ .pk-context-menu-content {
4
+ position: absolute; z-index: 50; min-width: 8rem; overflow: hidden;
5
+ border: 1px solid var(--pk-border); border-radius: calc(var(--pk-radius) - 2px); background: var(--pk-surface);
6
+ color: var(--pk-text); padding: .25rem; box-shadow: 0 8px 24px rgb(0 0 0 / .3); outline: none;
7
+ }
8
+ .pk-context-menu-item {
9
+ position: relative; display: flex; cursor: pointer; user-select: none; align-items: center;
10
+ border-radius: .125rem; padding: .375rem .5rem .375rem 2rem; font-size: .875rem;
11
+ color: inherit; text-decoration: none; outline: none;
12
+ }
13
+ .pk-context-menu-item:hover, .pk-context-menu-item:focus { background: var(--pk-accent); color: var(--pk-text); }
14
+ .pk-context-menu-item[data-disabled="true"] { pointer-events: none; opacity: .5; }
15
+ .pk-context-menu-check { position: absolute; left: .5rem; display: inline-flex; height: .875rem; width: .875rem; align-items: center; justify-content: center; }
16
+ .pk-context-menu-shortcut { margin-left: auto; font-size: .75rem; letter-spacing: .1em; color: var(--pk-muted); }
17
+ .pk-context-menu-label { padding: .375rem .5rem; font-size: .875rem; font-weight: 600; color: var(--pk-text); }
18
+ .pk-context-menu-label.inset { padding-left: 2rem; }
19
+ .pk-context-menu-separator { height: 1px; margin: .25rem -.25rem; background: var(--pk-border); }
@@ -0,0 +1,11 @@
1
+ module PhlexKit
2
+ # Right-click menu, positioned at the cursor with CSS. Ported from ruby_ui's
3
+ # RubyUI::ContextMenu. Compose ContextMenu > (ContextMenuTrigger +
4
+ # ContextMenuContent > ContextMenuItem/Label/Separator). phlex-kit--context-menu.
5
+ class ContextMenu < BaseComponent
6
+ def initialize(**attrs) = (@attrs = attrs)
7
+ def view_template(&)
8
+ div(**mix({ class: "pk-context-menu", data: { controller: "phlex-kit--context-menu" } }, @attrs), &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module PhlexKit
2
+ class ContextMenuContent < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&)
5
+ div(**mix({ class: "pk-context-menu-content pk-hidden", role: "menu", tabindex: "-1", aria: { orientation: "vertical" }, data: { phlex_kit__context_menu_target: "content", state: "closed" } }, @attrs), &)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ module PhlexKit
2
+ class ContextMenuItem < BaseComponent
3
+ def initialize(href: "#", checked: false, shortcut: nil, disabled: false, **attrs)
4
+ @href = href
5
+ @checked = checked
6
+ @shortcut = shortcut
7
+ @disabled = disabled
8
+ @attrs = attrs
9
+ end
10
+ def view_template(&block)
11
+ a(**mix({ href: @href, role: "menuitem", tabindex: "-1", class: "pk-context-menu-item",
12
+ data: { action: "click->phlex-kit--context-menu#close", phlex_kit__context_menu_target: "menuItem", disabled: @disabled } }, @attrs)) do
13
+ if @checked
14
+ span(class: "pk-context-menu-check") 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.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z")
17
+ end
18
+ end
19
+ end
20
+ yield
21
+ span(class: "pk-context-menu-shortcut") { @shortcut } if @shortcut
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ module PhlexKit
2
+ class ContextMenuLabel < BaseComponent
3
+ def initialize(inset: false, **attrs)
4
+ @inset = inset
5
+ @attrs = attrs
6
+ end
7
+ def view_template(&)
8
+ div(**mix({ class: ["pk-context-menu-label", (@inset ? "inset" : nil)].compact.join(" ") }, @attrs), &)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module PhlexKit
2
+ class ContextMenuSeparator < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template
5
+ div(**mix({ role: "separator", class: "pk-context-menu-separator", aria: { orientation: "horizontal" } }, @attrs))
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module PhlexKit
2
+ class ContextMenuTrigger < BaseComponent
3
+ def initialize(**attrs) = (@attrs = attrs)
4
+ def view_template(&)
5
+ div(**mix({ class: "pk-context-menu-trigger", data: { phlex_kit__context_menu_target: "trigger", action: "contextmenu->phlex-kit--context-menu#open" } }, @attrs), &)
6
+ end
7
+ end
8
+ end