shadcn_phlexcomponents 0.1.9 → 0.1.11

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 (246) hide show
  1. checksums.yaml +4 -4
  2. data/app/javascript/controllers/accordion_controller.ts +133 -0
  3. data/app/javascript/controllers/{avatar_controller.js → avatar_controller.ts} +4 -0
  4. data/app/javascript/controllers/checkbox_controller.ts +34 -0
  5. data/app/javascript/controllers/collapsible_controller.ts +45 -0
  6. data/app/javascript/controllers/combobox_controller.ts +145 -0
  7. data/app/javascript/controllers/command_controller.ts +129 -0
  8. data/app/javascript/controllers/command_root_controller.ts +355 -0
  9. data/app/javascript/controllers/date_picker_controller.ts +274 -0
  10. data/app/javascript/controllers/date_range_picker_controller.ts +243 -0
  11. data/app/javascript/controllers/dialog_controller.ts +113 -0
  12. data/app/javascript/controllers/dropdown_menu_controller.ts +133 -0
  13. data/app/javascript/controllers/dropdown_menu_root_controller.ts +234 -0
  14. data/app/javascript/controllers/dropdown_menu_sub_controller.ts +150 -0
  15. data/app/javascript/controllers/{form_field_controller.js → form_field_controller.ts} +4 -6
  16. data/app/javascript/controllers/hover_card_controller.ts +93 -0
  17. data/app/javascript/controllers/{loading_button_controller.js → loading_button_controller.ts} +2 -2
  18. data/app/javascript/controllers/popover_controller.ts +141 -0
  19. data/app/javascript/controllers/progress_controller.ts +17 -0
  20. data/app/javascript/controllers/radio_group_controller.ts +106 -0
  21. data/app/javascript/controllers/select_controller.ts +200 -0
  22. data/app/javascript/controllers/{sidebar_controller.js → sidebar_controller.ts} +6 -2
  23. data/app/javascript/controllers/sidebar_trigger_controller.ts +21 -0
  24. data/app/javascript/controllers/slider_controller.ts +107 -0
  25. data/app/javascript/controllers/switch_controller.ts +30 -0
  26. data/app/javascript/controllers/tabs_controller.ts +79 -0
  27. data/app/javascript/controllers/{theme_switcher_controller.js → theme_switcher_controller.ts} +12 -9
  28. data/app/javascript/controllers/toast_container_controller.ts +62 -0
  29. data/app/javascript/controllers/toast_controller.ts +28 -0
  30. data/app/javascript/controllers/tooltip_controller.ts +98 -0
  31. data/app/javascript/{shadcn_phlexcomponents.js → shadcn_phlexcomponents.ts} +6 -2
  32. data/app/javascript/utils.ts +437 -0
  33. data/app/stylesheets/date_picker.css +16 -154
  34. data/app/stylesheets/nouislider.css +173 -0
  35. data/app/stylesheets/tw-animate.css +486 -0
  36. data/lib/install/install_shadcn_phlexcomponents.rb +16 -3
  37. data/lib/shadcn_phlexcomponents/alias.rb +3 -1
  38. data/lib/shadcn_phlexcomponents/components/accordion.rb +129 -0
  39. data/lib/shadcn_phlexcomponents/components/alert.rb +59 -0
  40. data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +276 -0
  41. data/lib/shadcn_phlexcomponents/components/{aspect_ratio/aspect_ratio.rb → aspect_ratio.rb} +2 -2
  42. data/lib/shadcn_phlexcomponents/components/avatar.rb +63 -0
  43. data/lib/shadcn_phlexcomponents/components/badge.rb +35 -0
  44. data/lib/shadcn_phlexcomponents/components/base.rb +34 -7
  45. data/lib/shadcn_phlexcomponents/components/breadcrumb.rb +150 -0
  46. data/lib/shadcn_phlexcomponents/components/button.rb +49 -0
  47. data/lib/shadcn_phlexcomponents/components/card.rb +88 -0
  48. data/lib/shadcn_phlexcomponents/components/{checkbox/checkbox.rb → checkbox.rb} +18 -14
  49. data/lib/shadcn_phlexcomponents/components/{checkbox_group/checkbox_group.rb → checkbox_group.rb} +7 -8
  50. data/lib/shadcn_phlexcomponents/components/collapsible.rb +91 -0
  51. data/lib/shadcn_phlexcomponents/components/combobox.rb +398 -0
  52. data/lib/shadcn_phlexcomponents/components/command.rb +351 -0
  53. data/lib/shadcn_phlexcomponents/components/date_picker.rb +264 -0
  54. data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +126 -0
  55. data/lib/shadcn_phlexcomponents/components/dialog.rb +234 -0
  56. data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +282 -0
  57. data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +135 -0
  58. data/lib/shadcn_phlexcomponents/components/form/form_checkbox.rb +6 -7
  59. data/lib/shadcn_phlexcomponents/components/form/form_checkbox_group.rb +2 -2
  60. data/lib/shadcn_phlexcomponents/components/form/form_date_picker.rb +3 -4
  61. data/lib/shadcn_phlexcomponents/components/form/form_date_range_picker.rb +27 -41
  62. data/lib/shadcn_phlexcomponents/components/form/form_error.rb +1 -1
  63. data/lib/shadcn_phlexcomponents/components/form/form_helpers.rb +43 -8
  64. data/lib/shadcn_phlexcomponents/components/form/form_hint.rb +1 -1
  65. data/lib/shadcn_phlexcomponents/components/form/form_input.rb +3 -4
  66. data/lib/shadcn_phlexcomponents/components/form/form_radio_group.rb +4 -5
  67. data/lib/shadcn_phlexcomponents/components/form/form_select.rb +3 -4
  68. data/lib/shadcn_phlexcomponents/components/form/form_slider.rb +91 -0
  69. data/lib/shadcn_phlexcomponents/components/form/form_switch.rb +7 -6
  70. data/lib/shadcn_phlexcomponents/components/form/form_textarea.rb +3 -4
  71. data/lib/shadcn_phlexcomponents/components/{form/form.rb → form.rb} +22 -4
  72. data/lib/shadcn_phlexcomponents/components/hover_card.rb +110 -0
  73. data/lib/shadcn_phlexcomponents/components/input.rb +31 -0
  74. data/lib/shadcn_phlexcomponents/components/label.rb +16 -0
  75. data/lib/shadcn_phlexcomponents/components/{link/link.rb → link.rb} +10 -3
  76. data/lib/shadcn_phlexcomponents/components/{loading_button/loading_button.rb → loading_button.rb} +9 -2
  77. data/lib/shadcn_phlexcomponents/components/pagination.rb +166 -0
  78. data/lib/shadcn_phlexcomponents/components/popover.rb +116 -0
  79. data/lib/shadcn_phlexcomponents/components/{progress/progress.rb → progress.rb} +4 -4
  80. data/lib/shadcn_phlexcomponents/components/radio_group.rb +155 -0
  81. data/lib/shadcn_phlexcomponents/components/select.rb +421 -0
  82. data/lib/shadcn_phlexcomponents/components/{separator/separator.rb → separator.rb} +9 -8
  83. data/lib/shadcn_phlexcomponents/components/sheet.rb +239 -0
  84. data/lib/shadcn_phlexcomponents/components/{skeleton/skeleton.rb → skeleton.rb} +1 -1
  85. data/lib/shadcn_phlexcomponents/components/slider.rb +72 -0
  86. data/lib/shadcn_phlexcomponents/components/switch.rb +75 -0
  87. data/lib/shadcn_phlexcomponents/components/table.rb +140 -0
  88. data/lib/shadcn_phlexcomponents/components/tabs.rb +135 -0
  89. data/lib/shadcn_phlexcomponents/components/textarea.rb +24 -0
  90. data/lib/shadcn_phlexcomponents/components/toast.rb +153 -0
  91. data/lib/shadcn_phlexcomponents/components/{toast/toast_container.rb → toast_container.rb} +23 -4
  92. data/lib/shadcn_phlexcomponents/components/tooltip.rb +131 -0
  93. data/lib/shadcn_phlexcomponents/initializers/shadcn_phlexcomponents.rb +25 -0
  94. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  95. data/lib/tasks/install.rake +1 -1
  96. metadata +78 -167
  97. data/app/javascript/controllers/accordion_controller.js +0 -124
  98. data/app/javascript/controllers/alert_dialog_controller.js +0 -21
  99. data/app/javascript/controllers/checkbox_controller.js +0 -28
  100. data/app/javascript/controllers/collapsible_controller.js +0 -35
  101. data/app/javascript/controllers/combobox_controller.js +0 -54
  102. data/app/javascript/controllers/date_picker_controller.js +0 -253
  103. data/app/javascript/controllers/date_range_picker_controller.js +0 -344
  104. data/app/javascript/controllers/dialog_controller.js +0 -114
  105. data/app/javascript/controllers/dropdown_menu_controller.js +0 -171
  106. data/app/javascript/controllers/hover_card_controller.js +0 -21
  107. data/app/javascript/controllers/popover_controller.js +0 -113
  108. data/app/javascript/controllers/progress_controller.js +0 -14
  109. data/app/javascript/controllers/radio_group_controller.js +0 -90
  110. data/app/javascript/controllers/select_controller.js +0 -274
  111. data/app/javascript/controllers/sidebar_trigger_controller.js +0 -15
  112. data/app/javascript/controllers/switch_controller.js +0 -24
  113. data/app/javascript/controllers/tabs_controller.js +0 -73
  114. data/app/javascript/controllers/toast_container_controller.js +0 -22
  115. data/app/javascript/controllers/toast_controller.js +0 -45
  116. data/app/javascript/controllers/tooltip_controller.js +0 -40
  117. data/app/javascript/utils.js +0 -184
  118. data/app/stylesheets/choices.css +0 -324
  119. data/app/stylesheets/tailwindcss-animate.css +0 -318
  120. data/lib/shadcn_phlexcomponents/components/accordion/accordion.rb +0 -38
  121. data/lib/shadcn_phlexcomponents/components/accordion/accordion_content.rb +0 -30
  122. data/lib/shadcn_phlexcomponents/components/accordion/accordion_item.rb +0 -26
  123. data/lib/shadcn_phlexcomponents/components/accordion/accordion_trigger.rb +0 -46
  124. data/lib/shadcn_phlexcomponents/components/alert/alert.rb +0 -40
  125. data/lib/shadcn_phlexcomponents/components/alert/alert_description.rb +0 -11
  126. data/lib/shadcn_phlexcomponents/components/alert/alert_title.rb +0 -11
  127. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog.rb +0 -60
  128. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_action.rb +0 -22
  129. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_action_to.rb +0 -40
  130. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_cancel.rb +0 -22
  131. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_content.rb +0 -40
  132. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_description.rb +0 -22
  133. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_footer.rb +0 -11
  134. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_header.rb +0 -11
  135. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_title.rb +0 -22
  136. data/lib/shadcn_phlexcomponents/components/alert_dialog/alert_dialog_trigger.rb +0 -50
  137. data/lib/shadcn_phlexcomponents/components/avatar/avatar.rb +0 -31
  138. data/lib/shadcn_phlexcomponents/components/avatar/avatar_fallback.rb +0 -21
  139. data/lib/shadcn_phlexcomponents/components/avatar/avatar_image.rb +0 -19
  140. data/lib/shadcn_phlexcomponents/components/badge/badge.rb +0 -30
  141. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb.rb +0 -53
  142. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_ellipsis.rb +0 -23
  143. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_item.rb +0 -11
  144. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_link.rb +0 -7
  145. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_page.rb +0 -21
  146. data/lib/shadcn_phlexcomponents/components/breadcrumb/breadcrumb_separator.rb +0 -26
  147. data/lib/shadcn_phlexcomponents/components/button/button.rb +0 -53
  148. data/lib/shadcn_phlexcomponents/components/card/card.rb +0 -31
  149. data/lib/shadcn_phlexcomponents/components/card/card_content.rb +0 -11
  150. data/lib/shadcn_phlexcomponents/components/card/card_description.rb +0 -11
  151. data/lib/shadcn_phlexcomponents/components/card/card_footer.rb +0 -11
  152. data/lib/shadcn_phlexcomponents/components/card/card_header.rb +0 -11
  153. data/lib/shadcn_phlexcomponents/components/card/card_title.rb +0 -11
  154. data/lib/shadcn_phlexcomponents/components/collapsible/collapsible.rb +0 -31
  155. data/lib/shadcn_phlexcomponents/components/collapsible/collapsible_content.rb +0 -24
  156. data/lib/shadcn_phlexcomponents/components/collapsible/collapsible_trigger.rb +0 -50
  157. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker.rb +0 -87
  158. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker_content.rb +0 -45
  159. data/lib/shadcn_phlexcomponents/components/date_picker/date_picker_trigger.rb +0 -64
  160. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker.rb +0 -105
  161. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker_content.rb +0 -9
  162. data/lib/shadcn_phlexcomponents/components/date_range_picker/date_range_picker_trigger.rb +0 -9
  163. data/lib/shadcn_phlexcomponents/components/dialog/dialog.rb +0 -52
  164. data/lib/shadcn_phlexcomponents/components/dialog/dialog_close.rb +0 -42
  165. data/lib/shadcn_phlexcomponents/components/dialog/dialog_content.rb +0 -54
  166. data/lib/shadcn_phlexcomponents/components/dialog/dialog_description.rb +0 -22
  167. data/lib/shadcn_phlexcomponents/components/dialog/dialog_footer.rb +0 -11
  168. data/lib/shadcn_phlexcomponents/components/dialog/dialog_header.rb +0 -11
  169. data/lib/shadcn_phlexcomponents/components/dialog/dialog_title.rb +0 -22
  170. data/lib/shadcn_phlexcomponents/components/dialog/dialog_trigger.rb +0 -50
  171. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu.rb +0 -50
  172. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_content.rb +0 -52
  173. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_item.rb +0 -56
  174. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_item_to.rb +0 -28
  175. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_label.rb +0 -11
  176. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_separator.rb +0 -20
  177. data/lib/shadcn_phlexcomponents/components/dropdown_menu/dropdown_menu_trigger.rb +0 -57
  178. data/lib/shadcn_phlexcomponents/components/hover_card/hover_card.rb +0 -33
  179. data/lib/shadcn_phlexcomponents/components/hover_card/hover_card_content.rb +0 -32
  180. data/lib/shadcn_phlexcomponents/components/hover_card/hover_card_trigger.rb +0 -44
  181. data/lib/shadcn_phlexcomponents/components/input/input.rb +0 -32
  182. data/lib/shadcn_phlexcomponents/components/label/label.rb +0 -14
  183. data/lib/shadcn_phlexcomponents/components/pagination/pagination.rb +0 -38
  184. data/lib/shadcn_phlexcomponents/components/pagination/pagination_ellipsis.rb +0 -24
  185. data/lib/shadcn_phlexcomponents/components/pagination/pagination_link.rb +0 -34
  186. data/lib/shadcn_phlexcomponents/components/pagination/pagination_next.rb +0 -32
  187. data/lib/shadcn_phlexcomponents/components/pagination/pagination_previous.rb +0 -32
  188. data/lib/shadcn_phlexcomponents/components/popover/popover.rb +0 -34
  189. data/lib/shadcn_phlexcomponents/components/popover/popover_content.rb +0 -40
  190. data/lib/shadcn_phlexcomponents/components/popover/popover_trigger.rb +0 -50
  191. data/lib/shadcn_phlexcomponents/components/radio_group/radio_group.rb +0 -88
  192. data/lib/shadcn_phlexcomponents/components/radio_group/radio_group_item.rb +0 -66
  193. data/lib/shadcn_phlexcomponents/components/select/select.rb +0 -194
  194. data/lib/shadcn_phlexcomponents/components/select/select_content.rb +0 -64
  195. data/lib/shadcn_phlexcomponents/components/select/select_group.rb +0 -23
  196. data/lib/shadcn_phlexcomponents/components/select/select_item.rb +0 -59
  197. data/lib/shadcn_phlexcomponents/components/select/select_label.rb +0 -24
  198. data/lib/shadcn_phlexcomponents/components/select/select_trigger.rb +0 -56
  199. data/lib/shadcn_phlexcomponents/components/sheet/sheet.rb +0 -53
  200. data/lib/shadcn_phlexcomponents/components/sheet/sheet_close.rb +0 -42
  201. data/lib/shadcn_phlexcomponents/components/sheet/sheet_content.rb +0 -65
  202. data/lib/shadcn_phlexcomponents/components/sheet/sheet_description.rb +0 -22
  203. data/lib/shadcn_phlexcomponents/components/sheet/sheet_footer.rb +0 -11
  204. data/lib/shadcn_phlexcomponents/components/sheet/sheet_header.rb +0 -11
  205. data/lib/shadcn_phlexcomponents/components/sheet/sheet_title.rb +0 -22
  206. data/lib/shadcn_phlexcomponents/components/sheet/sheet_trigger.rb +0 -50
  207. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar.rb +0 -108
  208. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_container.rb +0 -11
  209. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_content.rb +0 -11
  210. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_footer.rb +0 -11
  211. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_group.rb +0 -11
  212. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_group_content.rb +0 -11
  213. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_group_label.rb +0 -16
  214. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_header.rb +0 -11
  215. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_inset.rb +0 -15
  216. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu.rb +0 -11
  217. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_button.rb +0 -61
  218. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_item.rb +0 -9
  219. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_sub.rb +0 -14
  220. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_sub_button.rb +0 -48
  221. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_menu_sub_item.rb +0 -9
  222. data/lib/shadcn_phlexcomponents/components/sidebar/sidebar_trigger.rb +0 -40
  223. data/lib/shadcn_phlexcomponents/components/switch/switch.rb +0 -66
  224. data/lib/shadcn_phlexcomponents/components/table/table.rb +0 -75
  225. data/lib/shadcn_phlexcomponents/components/table/table_body.rb +0 -11
  226. data/lib/shadcn_phlexcomponents/components/table/table_caption.rb +0 -11
  227. data/lib/shadcn_phlexcomponents/components/table/table_cell.rb +0 -11
  228. data/lib/shadcn_phlexcomponents/components/table/table_footer.rb +0 -11
  229. data/lib/shadcn_phlexcomponents/components/table/table_head.rb +0 -14
  230. data/lib/shadcn_phlexcomponents/components/table/table_header.rb +0 -11
  231. data/lib/shadcn_phlexcomponents/components/table/table_row.rb +0 -11
  232. data/lib/shadcn_phlexcomponents/components/tabs/tabs.rb +0 -38
  233. data/lib/shadcn_phlexcomponents/components/tabs/tabs_content.rb +0 -35
  234. data/lib/shadcn_phlexcomponents/components/tabs/tabs_list.rb +0 -23
  235. data/lib/shadcn_phlexcomponents/components/tabs/tabs_trigger.rb +0 -45
  236. data/lib/shadcn_phlexcomponents/components/textarea/textarea.rb +0 -29
  237. data/lib/shadcn_phlexcomponents/components/toast/toast.rb +0 -101
  238. data/lib/shadcn_phlexcomponents/components/toast/toast_action.rb +0 -39
  239. data/lib/shadcn_phlexcomponents/components/toast/toast_action_to.rb +0 -28
  240. data/lib/shadcn_phlexcomponents/components/toast/toast_content.rb +0 -11
  241. data/lib/shadcn_phlexcomponents/components/toast/toast_description.rb +0 -11
  242. data/lib/shadcn_phlexcomponents/components/toast/toast_title.rb +0 -11
  243. data/lib/shadcn_phlexcomponents/components/tooltip/tooltip.rb +0 -34
  244. data/lib/shadcn_phlexcomponents/components/tooltip/tooltip_content.rb +0 -39
  245. data/lib/shadcn_phlexcomponents/components/tooltip/tooltip_trigger.rb +0 -48
  246. /data/lib/shadcn_phlexcomponents/components/{theme_switcher/theme_switcher.rb → theme_switcher.rb} +0 -0
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class RadioGroup < Base
5
+ class_variants(base: "grid gap-3 outline-none")
6
+
7
+ def initialize(name: nil, value: nil, dir: "ltr", include_hidden: true, **attributes)
8
+ @name = name
9
+ @value = value
10
+ @dir = dir
11
+ @include_hidden = include_hidden
12
+ super(**attributes)
13
+ end
14
+
15
+ def label(**attributes)
16
+ @label_attributes = attributes
17
+ nil
18
+ end
19
+
20
+ def radio(**attributes)
21
+ @radio_attributes = attributes
22
+ nil
23
+ end
24
+
25
+ def item(name: nil, value: nil, checked: false, **attributes)
26
+ RadioGroupItem(name: name || @name, value: value, checked: checked || @value == value, **attributes)
27
+ end
28
+
29
+ def items(collection, value_method:, text_method:, container_class: nil, disabled_items: nil, id_prefix: nil, &)
30
+ vanish(&)
31
+
32
+ container_class = TAILWIND_MERGER.merge("flex items-center gap-3 #{container_class}")
33
+
34
+ if collection.first&.is_a?(Hash)
35
+ collection = convert_collection_hash_to_struct(collection, value_method: value_method, text_method: text_method)
36
+ end
37
+
38
+ collection.each do |item|
39
+ value = item.public_send(value_method)
40
+ text = item.public_send(text_method)
41
+ id = if id_prefix
42
+ "#{id_prefix.parameterize.underscore}_#{value}"
43
+ else
44
+ "#{@name.parameterize.underscore}_#{value}"
45
+ end
46
+
47
+ div(class: container_class) do
48
+ RadioGroupItem(
49
+ name: @name,
50
+ value: value,
51
+ checked: @value == value,
52
+ id: id,
53
+ disabled: item_disabled?(disabled_items, value),
54
+ **@radio_attributes,
55
+ )
56
+ Label(for: id, **@label_attributes) { text }
57
+ end
58
+ end
59
+
60
+ nil
61
+ end
62
+
63
+ def default_attributes
64
+ {
65
+ role: "radiogroup",
66
+ dir: @dir,
67
+ aria: {
68
+ required: false,
69
+ },
70
+ data: {
71
+ controller: "radio-group",
72
+ radio_group_selected_value: @value,
73
+ },
74
+ }
75
+ end
76
+
77
+ def view_template(&)
78
+ div(**@attributes) do
79
+ if @include_hidden
80
+ input(type: "hidden", name: @name, autocomplete: "off")
81
+ end
82
+
83
+ yield
84
+ end
85
+ end
86
+ end
87
+
88
+ class RadioGroupItem < Base
89
+ class_variants(
90
+ base: <<~HEREDOC,
91
+ border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20
92
+ dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4
93
+ shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px]
94
+ disabled:cursor-not-allowed disabled:opacity-50 relative
95
+ HEREDOC
96
+ )
97
+
98
+ def initialize(name: nil, value: nil, checked: false, **attributes)
99
+ @value = value
100
+ @name = name
101
+ @checked = checked
102
+ super(**attributes)
103
+ end
104
+
105
+ def view_template(&)
106
+ button(**@attributes) do
107
+ span(
108
+ class: "relative flex items-center justify-center",
109
+ data: {
110
+ radio_group_target: "indicator",
111
+ },
112
+ ) do
113
+ icon("circle", class: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2")
114
+ end
115
+
116
+ input(
117
+ type: "radio",
118
+ value: @value,
119
+ class: "-translate-x-full pointer-events-none absolute top-0 left-0 size-4 opacity-0",
120
+ name: @name,
121
+ tabindex: -1,
122
+ checked: @checked,
123
+ aria: { hidden: "true" },
124
+ data: {
125
+ radio_group_target: "input",
126
+ },
127
+ )
128
+ end
129
+ end
130
+
131
+ def default_attributes
132
+ {
133
+ type: "button",
134
+ tabindex: -1,
135
+ role: "radio",
136
+ aria: {
137
+ checked: @checked.to_s,
138
+ },
139
+ data: {
140
+ checked: @checked.to_s,
141
+ value: @value,
142
+ radio_group_target: "item",
143
+ action: <<~HEREDOC,
144
+ click->radio-group#select
145
+ keydown.right->radio-group#selectItem:prevent
146
+ keydown.down->radio-group#selectItem:prevent
147
+ keydown.up->radio-group#selectItem:prevent
148
+ keydown.left->radio-group#selectItem:prevent
149
+ keydown.enter->radio-group#preventDefault
150
+ HEREDOC
151
+ },
152
+ }
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,421 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ NATIVE_OPTION_STYLES = "bg-popover text-popover-foreground"
5
+
6
+ class Select < Base
7
+ def initialize(
8
+ id: nil,
9
+ name: nil,
10
+ value: nil,
11
+ placeholder: nil,
12
+ native: false,
13
+ dir: "ltr",
14
+ include_blank: false,
15
+ disabled: false,
16
+ **attributes
17
+ )
18
+ @id = id
19
+ @name = name
20
+ @value = value
21
+ @placeholder = placeholder
22
+ @native = native
23
+ @dir = dir
24
+ @include_blank = include_blank
25
+ @disabled = disabled
26
+ @aria_id = "select-#{SecureRandom.hex(5)}"
27
+ super(**attributes)
28
+ end
29
+
30
+ def class_variants(**args)
31
+ if @native
32
+ Input.new.class_variants(class: "appearance-none #{args[:class]}")
33
+ else
34
+ TAILWIND_MERGER.merge("w-full #{args[:class]}")
35
+ end
36
+ end
37
+
38
+ def trigger(**attributes)
39
+ SelectTrigger(
40
+ id: @id,
41
+ aria_id: @aria_id,
42
+ dir: @dir,
43
+ value: @value,
44
+ placeholder: @placeholder,
45
+ disabled: @disabled,
46
+ **attributes,
47
+ )
48
+ end
49
+
50
+ def content(**attributes, &)
51
+ SelectContent(
52
+ aria_id: @aria_id, dir: @dir, include_blank: @include_blank, native: @native, **attributes, &
53
+ )
54
+ end
55
+
56
+ def item(**attributes, &)
57
+ SelectItem(aria_id: @aria_id, **attributes, &)
58
+ end
59
+
60
+ def label(**attributes, &)
61
+ SelectLabel(**attributes, &)
62
+ end
63
+
64
+ def group(**attributes, &)
65
+ SelectGroup(aria_id: @aria_id, **attributes, &)
66
+ end
67
+
68
+ def items(collection, value_method:, text_method:, disabled_items: nil, &)
69
+ vanish(&)
70
+
71
+ if collection.first&.is_a?(Hash)
72
+ collection = convert_collection_hash_to_struct(collection, value_method: value_method, text_method: text_method)
73
+ end
74
+
75
+ SelectTrigger(
76
+ id: @id,
77
+ aria_id: @aria_id,
78
+ dir: @dir,
79
+ value: @value,
80
+ placeholder: @placeholder,
81
+ disabled: @disabled,
82
+ )
83
+
84
+ SelectContent(aria_id: @aria_id, dir: @dir, include_blank: @include_blank, native: @native) do
85
+ collection.each do |item|
86
+ value = item.public_send(value_method)
87
+ text = item.public_send(text_method)
88
+
89
+ SelectItem(value: value, aria_id: @aria_id, disabled: item_disabled?(disabled_items, value)) { text }
90
+ end
91
+ end
92
+ end
93
+
94
+ def view_template(&)
95
+ content = capture(&)
96
+ element = Nokogiri::HTML.fragment(content.to_s)
97
+ content_element = element.css('[data-select-target="content"]')
98
+
99
+ if @native
100
+ div(class: "relative") do
101
+ select(**@attributes) do
102
+ if @placeholder || @include_blank
103
+ option(value: "", class: NATIVE_OPTION_STYLES) { @placeholder }
104
+ end
105
+
106
+ build_native_options(content_element)
107
+ end
108
+
109
+ icon("chevron-down", class: "size-4 absolute opacity-50 top-1/2 -translate-y-1/2 right-3 pointer-events-none")
110
+ end
111
+ else
112
+ div(**@attributes) do
113
+ yield
114
+
115
+ select(
116
+ name: @name,
117
+ disabled: @disabled,
118
+ class: "sr-only",
119
+ tabindex: -1,
120
+ data: {
121
+ select_target: "select",
122
+ },
123
+ ) do
124
+ option(value: "")
125
+ build_native_options(content_element)
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ def default_attributes
132
+ if @native
133
+ {
134
+ id: @id,
135
+ name: @name,
136
+ disabled: @disabled,
137
+ }
138
+ else
139
+ {
140
+ data: {
141
+ aria_id: @aria_id,
142
+ controller: "select",
143
+ select_selected_value: @value,
144
+ },
145
+ }
146
+ end
147
+ end
148
+
149
+ def build_native_options(content_element)
150
+ content_element.children.each do |content_child|
151
+ next if content_child.is_a?(Nokogiri::XML::Text) || content_child.is_a?(Nokogiri::XML::Comment)
152
+
153
+ if content_child.attributes["data-select-target"]&.value == "group"
154
+ group_label = content_child.at_css('[data-select-target="label"]')&.text
155
+
156
+ optgroup(label: group_label, class: NATIVE_OPTION_STYLES) do
157
+ content_child.css('[data-select-target="item"]').each do |i|
158
+ option(
159
+ value: i.attributes["data-value"].value,
160
+ class: NATIVE_OPTION_STYLES,
161
+ selected: i.attributes["data-value"].value == @value,
162
+ disabled: i.attributes["data-disabled"]&.value == "",
163
+ ) do
164
+ i.text
165
+ end
166
+ end
167
+ end
168
+ elsif content_child.attributes["data-select-target"]&.value == "item"
169
+
170
+ option(
171
+ value: content_child.attributes["data-value"].value,
172
+ class: NATIVE_OPTION_STYLES,
173
+ selected: content_child.attributes["data-value"].value == @value,
174
+ disabled: content_child.attributes["data-disabled"]&.value == "",
175
+ ) do
176
+ content_child.text
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ class SelectTrigger < Base
184
+ class_variants(
185
+ base: <<~HEREDOC,
186
+ border-input [&_svg:not([class*='text-'])]:text-muted-foreground
187
+ focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40
188
+ aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex items-center
189
+ justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs
190
+ transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50
191
+ data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[select-target=triggerText]:line-clamp-1#{" "}
192
+ *:data-[select-target=triggerText]:flex *:data-[select-target=triggerText]:items-center *:data-[select-target=triggerText]:gap-2
193
+ [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4
194
+ data-[placeholder]:data-[has-value=false]:text-muted-foreground w-full
195
+ HEREDOC
196
+ )
197
+
198
+ def initialize(id: nil, value: nil, placeholder: nil, dir: "ltr", aria_id: nil, **attributes)
199
+ @id = id
200
+ @value = value
201
+ @placeholder = placeholder
202
+ @dir = dir
203
+ @aria_id = aria_id
204
+ super(**attributes)
205
+ end
206
+
207
+ def view_template
208
+ button(**@attributes) do
209
+ span(class: "pointer-events-none", data: { select_target: "triggerText" }) do
210
+ @value || @placeholder
211
+ end
212
+
213
+ icon("chevron-down", class: "size-4 opacity-50 text-foreground")
214
+ end
215
+ end
216
+
217
+ def default_attributes
218
+ {
219
+ type: "button",
220
+ id: @id,
221
+ dir: @dir,
222
+ role: "combobox",
223
+ aria: {
224
+ autocomplete: "none",
225
+ expanded: false,
226
+ controls: "#{@aria_id}-content",
227
+ },
228
+ data: {
229
+ placeholder: @placeholder,
230
+ has_value: @value.present?.to_s,
231
+ action: <<~HEREDOC,
232
+ click->select#toggle
233
+ keydown.space->select#open
234
+ keydown.enter->select#open
235
+ keydown.down->select#open:prevent
236
+ HEREDOC
237
+ select_target: "trigger",
238
+ },
239
+ }
240
+ end
241
+ end
242
+
243
+ class SelectContent < Base
244
+ class_variants(
245
+ base: <<~HEREDOC,
246
+ bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out
247
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
248
+ data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
249
+ data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50
250
+ max-h-(--radix-popper-available-height) min-w-[8rem] origin-(--radix-popper-transform-origin)
251
+ overflow-x-hidden overflow-y-auto rounded-md border shadow-md p-1 pointer-events-auto outline-none
252
+ HEREDOC
253
+ )
254
+
255
+ def initialize(include_blank: false, native: false, dir: "ltr", side: :bottom, align: :center, aria_id: nil, **attributes)
256
+ @include_blank = include_blank
257
+ @native = native
258
+ @dir = dir
259
+ @side = side
260
+ @align = align
261
+ @aria_id = aria_id
262
+ super(**attributes)
263
+ end
264
+
265
+ def view_template(&)
266
+ div(
267
+ class: "hidden fixed top-0 left-0 w-max z-50",
268
+ data: { select_target: "contentContainer" },
269
+ ) do
270
+ div(**@attributes) do
271
+ if @include_blank && !@native
272
+ SelectItem(aria_id: @aria_id, value: "", class: "h-8", hide_icon: true) do
273
+ @include_blank.is_a?(String) ? @include_blank : ""
274
+ end
275
+ end
276
+
277
+ yield
278
+ end
279
+ end
280
+ end
281
+
282
+ def default_attributes
283
+ {
284
+ id: "#{@aria_id}-content",
285
+ dir: @dir,
286
+ tabindex: -1,
287
+ role: "listbox",
288
+ aria: {
289
+ labelledby: "#{@aria_id}-trigger",
290
+ orientation: "vertical",
291
+ },
292
+ data: {
293
+ side: @side,
294
+ align: @align,
295
+ state: "closed",
296
+ select_target: "content",
297
+ action: <<~HEREDOC,
298
+ select:click:outside->select#clickOutside
299
+ keydown.up->select#focusItemByIndex:prevent:self
300
+ keydown.down->select#focusItemByIndex:prevent:self
301
+ HEREDOC
302
+ },
303
+ }
304
+ end
305
+ end
306
+
307
+ class SelectLabel < Base
308
+ class_variants(
309
+ base: "text-muted-foreground px-2 py-1.5 text-xs",
310
+ )
311
+
312
+ def initialize(**attributes)
313
+ super(**attributes)
314
+ end
315
+
316
+ def view_template(&)
317
+ div(**@attributes, &)
318
+ end
319
+
320
+ def default_attributes
321
+ {
322
+ data: {
323
+ select_target: "label",
324
+ },
325
+ }
326
+ end
327
+ end
328
+
329
+ class SelectItem < Base
330
+ class_variants(
331
+ base: <<~HEREDOC,
332
+ focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground
333
+ relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm
334
+ outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50
335
+ [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4
336
+ *:[span]:last:items-center *:[span]:last:gap-2 group/item
337
+ HEREDOC
338
+ )
339
+
340
+ def initialize(value: nil, disabled: false, aria_id: nil, **attributes)
341
+ @value = value
342
+ @disabled = disabled
343
+ @aria_id = aria_id
344
+ @aria_labelledby = "#{@aria_id}-#{@value.dasherize.parameterize}"
345
+ super(**attributes)
346
+ end
347
+
348
+ def view_template(&)
349
+ div(**@attributes) do
350
+ span(id: @aria_labelledby, &)
351
+
352
+ span(class: "absolute right-2 h-3.5 w-3.5 items-center hidden justify-center
353
+ group-aria-[selected=true]/item:flex group-data-[value='']/item:hidden") do
354
+ icon("check", class: "size-4")
355
+ end
356
+ end
357
+ end
358
+
359
+ def default_attributes
360
+ {
361
+ role: "option",
362
+ tabindex: -1,
363
+ aria: {
364
+ selected: false,
365
+ labelledby: @aria_labelledby,
366
+ },
367
+ data: {
368
+ disabled: @disabled,
369
+ value: @value,
370
+ action: <<~HEREDOC,
371
+ click->select#select
372
+ mouseover->select#focusItem
373
+ keydown.up->select#focusItem:prevent
374
+ keydown.down->select#focusItem:prevent
375
+ focus->select#onItemFocus
376
+ blur->select#onItemBlur
377
+ keydown.enter->select#select:prevent
378
+ keydown.space->select#select:prevent
379
+ mouseout->select#focusContent
380
+ HEREDOC
381
+ select_target: "item",
382
+ },
383
+ }
384
+ end
385
+ end
386
+
387
+ class SelectGroup < Base
388
+ def initialize(aria_id: nil, **attributes)
389
+ @aria_id = aria_id
390
+ super(**attributes)
391
+ end
392
+
393
+ def view_template(&)
394
+ div(**@attributes, &)
395
+ end
396
+
397
+ def default_attributes
398
+ {
399
+ role: "group",
400
+ aria: {
401
+ labelledby: "#{@aria_id}-group-#{SecureRandom.hex(5)}",
402
+ },
403
+ data: {
404
+ select_target: "group",
405
+ },
406
+ }
407
+ end
408
+ end
409
+
410
+ class SelectSeparator < Base
411
+ class_variants(base: "bg-border pointer-events-none -mx-1 my-1 h-px")
412
+
413
+ def view_template(&)
414
+ div(**@attributes, &)
415
+ end
416
+
417
+ def default_attributes
418
+ { aria: { hidden: "true" } }
419
+ end
420
+ end
421
+ end
@@ -2,23 +2,24 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class Separator < Base
5
- ORIENTATIONS = {
6
- horizontal: "shrink-0 bg-border h-[1px] w-full",
7
- vertical: "shrink-0 bg-border h-full w-[1px]",
8
- }.freeze
5
+ class_variants(
6
+ base: <<~HEREDOC,
7
+ bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full
8
+ data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px
9
+ HEREDOC
10
+ )
9
11
 
10
12
  def initialize(orientation: :horizontal, **attributes)
11
13
  @orientation = orientation
12
14
  super(**attributes)
13
15
  end
14
16
 
15
- def default_styles
16
- ORIENTATIONS[@orientation].to_s
17
- end
18
-
19
17
  def default_attributes
20
18
  {
21
19
  role: "none",
20
+ data: {
21
+ orientation: @orientation,
22
+ },
22
23
  }
23
24
  end
24
25