shadcn_phlexcomponents 0.1.5 → 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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -0
  3. data/app/javascript/controllers/accordion_controller.ts +133 -0
  4. data/app/javascript/controllers/{avatar_controller.js → avatar_controller.ts} +4 -0
  5. data/app/javascript/controllers/checkbox_controller.ts +34 -0
  6. data/app/javascript/controllers/collapsible_controller.ts +45 -0
  7. data/app/javascript/controllers/combobox_controller.ts +145 -0
  8. data/app/javascript/controllers/command_controller.ts +129 -0
  9. data/app/javascript/controllers/command_root_controller.ts +355 -0
  10. data/app/javascript/controllers/date_picker_controller.ts +274 -0
  11. data/app/javascript/controllers/date_range_picker_controller.ts +243 -0
  12. data/app/javascript/controllers/dialog_controller.ts +113 -0
  13. data/app/javascript/controllers/dropdown_menu_controller.ts +133 -0
  14. data/app/javascript/controllers/dropdown_menu_root_controller.ts +234 -0
  15. data/app/javascript/controllers/dropdown_menu_sub_controller.ts +150 -0
  16. data/app/javascript/controllers/form_field_controller.ts +22 -0
  17. data/app/javascript/controllers/hover_card_controller.ts +93 -0
  18. data/app/javascript/controllers/{loading_button_controller.js → loading_button_controller.ts} +2 -2
  19. data/app/javascript/controllers/popover_controller.ts +141 -0
  20. data/app/javascript/controllers/progress_controller.ts +17 -0
  21. data/app/javascript/controllers/radio_group_controller.ts +106 -0
  22. data/app/javascript/controllers/select_controller.ts +200 -0
  23. data/app/javascript/controllers/{sidebar_controller.js → sidebar_controller.ts} +6 -2
  24. data/app/javascript/controllers/sidebar_trigger_controller.ts +21 -0
  25. data/app/javascript/controllers/slider_controller.ts +107 -0
  26. data/app/javascript/controllers/switch_controller.ts +30 -0
  27. data/app/javascript/controllers/tabs_controller.ts +79 -0
  28. data/app/javascript/controllers/{theme_switcher_controller.js → theme_switcher_controller.ts} +12 -9
  29. data/app/javascript/controllers/toast_container_controller.ts +62 -0
  30. data/app/javascript/controllers/toast_controller.ts +28 -0
  31. data/app/javascript/controllers/tooltip_controller.ts +98 -0
  32. data/app/javascript/shadcn_phlexcomponents.ts +57 -0
  33. data/app/javascript/utils.ts +437 -0
  34. data/app/stylesheets/date_picker.css +74 -0
  35. data/app/stylesheets/nouislider.css +173 -0
  36. data/app/stylesheets/tw-animate.css +486 -0
  37. data/lib/install/install_shadcn_phlexcomponents.rb +22 -9
  38. data/lib/shadcn_phlexcomponents/alias.rb +3 -1
  39. data/lib/shadcn_phlexcomponents/components/accordion.rb +129 -0
  40. data/lib/shadcn_phlexcomponents/components/alert.rb +59 -0
  41. data/lib/shadcn_phlexcomponents/components/alert_dialog.rb +276 -0
  42. data/lib/{components → shadcn_phlexcomponents/components}/aspect_ratio.rb +2 -2
  43. data/lib/shadcn_phlexcomponents/components/avatar.rb +63 -0
  44. data/lib/shadcn_phlexcomponents/components/badge.rb +35 -0
  45. data/lib/{components → shadcn_phlexcomponents/components}/base.rb +44 -7
  46. data/lib/shadcn_phlexcomponents/components/breadcrumb.rb +150 -0
  47. data/lib/shadcn_phlexcomponents/components/button.rb +49 -0
  48. data/lib/shadcn_phlexcomponents/components/card.rb +88 -0
  49. data/lib/{components → shadcn_phlexcomponents/components}/checkbox.rb +21 -17
  50. data/lib/{components → shadcn_phlexcomponents/components}/checkbox_group.rb +27 -16
  51. data/lib/shadcn_phlexcomponents/components/collapsible.rb +91 -0
  52. data/lib/shadcn_phlexcomponents/components/combobox.rb +398 -0
  53. data/lib/shadcn_phlexcomponents/components/command.rb +351 -0
  54. data/lib/shadcn_phlexcomponents/components/date_picker.rb +264 -0
  55. data/lib/shadcn_phlexcomponents/components/date_range_picker.rb +126 -0
  56. data/lib/shadcn_phlexcomponents/components/dialog.rb +234 -0
  57. data/lib/shadcn_phlexcomponents/components/dropdown_menu.rb +282 -0
  58. data/lib/shadcn_phlexcomponents/components/dropdown_menu_sub.rb +135 -0
  59. data/lib/shadcn_phlexcomponents/components/form/form_checkbox.rb +82 -0
  60. data/lib/shadcn_phlexcomponents/components/form/form_checkbox_group.rb +116 -0
  61. data/lib/shadcn_phlexcomponents/components/form/form_date_picker.rb +46 -0
  62. data/lib/shadcn_phlexcomponents/components/form/form_date_range_picker.rb +82 -0
  63. data/lib/{components → shadcn_phlexcomponents/components/form}/form_error.rb +7 -3
  64. data/lib/shadcn_phlexcomponents/components/form/form_helpers.rb +143 -0
  65. data/lib/shadcn_phlexcomponents/components/form/form_hint.rb +21 -0
  66. data/lib/{components → shadcn_phlexcomponents/components/form}/form_input.rb +3 -4
  67. data/lib/shadcn_phlexcomponents/components/form/form_radio_group.rb +106 -0
  68. data/lib/shadcn_phlexcomponents/components/form/form_select.rb +64 -0
  69. data/lib/shadcn_phlexcomponents/components/form/form_slider.rb +91 -0
  70. data/lib/shadcn_phlexcomponents/components/form/form_switch.rb +67 -0
  71. data/lib/shadcn_phlexcomponents/components/form/form_textarea.rb +59 -0
  72. data/lib/shadcn_phlexcomponents/components/form.rb +157 -0
  73. data/lib/shadcn_phlexcomponents/components/hover_card.rb +110 -0
  74. data/lib/shadcn_phlexcomponents/components/input.rb +31 -0
  75. data/lib/shadcn_phlexcomponents/components/label.rb +16 -0
  76. data/lib/{components → shadcn_phlexcomponents/components}/link.rb +10 -3
  77. data/lib/shadcn_phlexcomponents/components/loading_button.rb +28 -0
  78. data/lib/shadcn_phlexcomponents/components/pagination.rb +166 -0
  79. data/lib/shadcn_phlexcomponents/components/popover.rb +116 -0
  80. data/lib/{components → shadcn_phlexcomponents/components}/progress.rb +5 -5
  81. data/lib/shadcn_phlexcomponents/components/radio_group.rb +155 -0
  82. data/lib/shadcn_phlexcomponents/components/select.rb +421 -0
  83. data/lib/{components → shadcn_phlexcomponents/components}/separator.rb +9 -8
  84. data/lib/shadcn_phlexcomponents/components/sheet.rb +239 -0
  85. data/lib/{components → shadcn_phlexcomponents/components}/skeleton.rb +1 -1
  86. data/lib/shadcn_phlexcomponents/components/slider.rb +72 -0
  87. data/lib/shadcn_phlexcomponents/components/switch.rb +75 -0
  88. data/lib/shadcn_phlexcomponents/components/table.rb +140 -0
  89. data/lib/shadcn_phlexcomponents/components/tabs.rb +135 -0
  90. data/lib/shadcn_phlexcomponents/components/textarea.rb +24 -0
  91. data/lib/{components → shadcn_phlexcomponents/components}/theme_switcher.rb +2 -2
  92. data/lib/shadcn_phlexcomponents/components/toast.rb +153 -0
  93. data/lib/{components → shadcn_phlexcomponents/components}/toast_container.rb +24 -5
  94. data/lib/shadcn_phlexcomponents/components/tooltip.rb +131 -0
  95. data/lib/shadcn_phlexcomponents/initializers/shadcn_phlexcomponents.rb +25 -0
  96. data/lib/shadcn_phlexcomponents/version.rb +1 -1
  97. data/lib/tasks/install.rake +1 -1
  98. metadata +92 -168
  99. data/app/assets/tailwind/choices.css +0 -324
  100. data/app/assets/tailwind/tailwindcss-animate.css +0 -318
  101. data/app/assets/tailwind/vanilla-calendar-pro.css +0 -466
  102. data/app/javascript/controllers/accordion_controller.js +0 -133
  103. data/app/javascript/controllers/alert_dialog_controller.js +0 -157
  104. data/app/javascript/controllers/checkbox_controller.js +0 -28
  105. data/app/javascript/controllers/collapsible_controller.js +0 -35
  106. data/app/javascript/controllers/combobox_controller.js +0 -34
  107. data/app/javascript/controllers/date_picker_controller.js +0 -118
  108. data/app/javascript/controllers/date_range_picker_controller.js +0 -231
  109. data/app/javascript/controllers/dialog_controller.js +0 -159
  110. data/app/javascript/controllers/dropdown_menu_controller.js +0 -193
  111. data/app/javascript/controllers/hover_card_controller.js +0 -42
  112. data/app/javascript/controllers/popover_controller.js +0 -124
  113. data/app/javascript/controllers/progress_controller.js +0 -14
  114. data/app/javascript/controllers/radio_group_controller.js +0 -90
  115. data/app/javascript/controllers/select_controller.js +0 -294
  116. data/app/javascript/controllers/sheet_controller.js +0 -159
  117. data/app/javascript/controllers/sidebar_trigger_controller.js +0 -15
  118. data/app/javascript/controllers/switch_controller.js +0 -24
  119. data/app/javascript/controllers/tabs_controller.js +0 -73
  120. data/app/javascript/controllers/toast_container_controller.js +0 -22
  121. data/app/javascript/controllers/toast_controller.js +0 -45
  122. data/app/javascript/controllers/tooltip_controller.js +0 -41
  123. data/lib/components/accordion.rb +0 -38
  124. data/lib/components/accordion_content.rb +0 -30
  125. data/lib/components/accordion_item.rb +0 -26
  126. data/lib/components/accordion_trigger.rb +0 -45
  127. data/lib/components/alert.rb +0 -40
  128. data/lib/components/alert_description.rb +0 -11
  129. data/lib/components/alert_dialog.rb +0 -60
  130. data/lib/components/alert_dialog_action.rb +0 -22
  131. data/lib/components/alert_dialog_action_to.rb +0 -40
  132. data/lib/components/alert_dialog_cancel.rb +0 -22
  133. data/lib/components/alert_dialog_content.rb +0 -40
  134. data/lib/components/alert_dialog_description.rb +0 -22
  135. data/lib/components/alert_dialog_footer.rb +0 -11
  136. data/lib/components/alert_dialog_header.rb +0 -11
  137. data/lib/components/alert_dialog_title.rb +0 -22
  138. data/lib/components/alert_dialog_trigger.rb +0 -50
  139. data/lib/components/alert_title.rb +0 -11
  140. data/lib/components/avatar.rb +0 -31
  141. data/lib/components/avatar_fallback.rb +0 -21
  142. data/lib/components/avatar_image.rb +0 -19
  143. data/lib/components/badge.rb +0 -30
  144. data/lib/components/breadcrumb.rb +0 -51
  145. data/lib/components/breadcrumb_ellipsis.rb +0 -23
  146. data/lib/components/breadcrumb_item.rb +0 -11
  147. data/lib/components/breadcrumb_link.rb +0 -7
  148. data/lib/components/breadcrumb_page.rb +0 -21
  149. data/lib/components/breadcrumb_separator.rb +0 -26
  150. data/lib/components/button.rb +0 -53
  151. data/lib/components/card.rb +0 -31
  152. data/lib/components/card_content.rb +0 -11
  153. data/lib/components/card_description.rb +0 -11
  154. data/lib/components/card_footer.rb +0 -11
  155. data/lib/components/card_header.rb +0 -11
  156. data/lib/components/card_title.rb +0 -11
  157. data/lib/components/collapsible.rb +0 -31
  158. data/lib/components/collapsible_content.rb +0 -24
  159. data/lib/components/collapsible_trigger.rb +0 -50
  160. data/lib/components/combobox.rb +0 -57
  161. data/lib/components/combobox_item.rb +0 -9
  162. data/lib/components/date_picker.rb +0 -94
  163. data/lib/components/date_range_picker.rb +0 -113
  164. data/lib/components/dialog.rb +0 -52
  165. data/lib/components/dialog_close.rb +0 -42
  166. data/lib/components/dialog_content.rb +0 -54
  167. data/lib/components/dialog_description.rb +0 -22
  168. data/lib/components/dialog_footer.rb +0 -11
  169. data/lib/components/dialog_header.rb +0 -11
  170. data/lib/components/dialog_title.rb +0 -22
  171. data/lib/components/dialog_trigger.rb +0 -50
  172. data/lib/components/dropdown_menu.rb +0 -50
  173. data/lib/components/dropdown_menu_content.rb +0 -52
  174. data/lib/components/dropdown_menu_item.rb +0 -56
  175. data/lib/components/dropdown_menu_item_to.rb +0 -28
  176. data/lib/components/dropdown_menu_label.rb +0 -11
  177. data/lib/components/dropdown_menu_separator.rb +0 -20
  178. data/lib/components/dropdown_menu_trigger.rb +0 -57
  179. data/lib/components/form.rb +0 -59
  180. data/lib/components/form_hint.rb +0 -17
  181. data/lib/components/hover_card.rb +0 -33
  182. data/lib/components/hover_card_content.rb +0 -32
  183. data/lib/components/hover_card_trigger.rb +0 -44
  184. data/lib/components/input.rb +0 -32
  185. data/lib/components/label.rb +0 -14
  186. data/lib/components/loading_button.rb +0 -21
  187. data/lib/components/pagination.rb +0 -38
  188. data/lib/components/pagination_ellipsis.rb +0 -24
  189. data/lib/components/pagination_link.rb +0 -34
  190. data/lib/components/pagination_next.rb +0 -32
  191. data/lib/components/pagination_previous.rb +0 -32
  192. data/lib/components/popover.rb +0 -34
  193. data/lib/components/popover_content.rb +0 -40
  194. data/lib/components/popover_trigger.rb +0 -51
  195. data/lib/components/radio_group.rb +0 -62
  196. data/lib/components/radio_group_item.rb +0 -66
  197. data/lib/components/select.rb +0 -184
  198. data/lib/components/select_content.rb +0 -64
  199. data/lib/components/select_group.rb +0 -23
  200. data/lib/components/select_item.rb +0 -59
  201. data/lib/components/select_label.rb +0 -24
  202. data/lib/components/select_trigger.rb +0 -56
  203. data/lib/components/sheet.rb +0 -53
  204. data/lib/components/sheet_close.rb +0 -42
  205. data/lib/components/sheet_content.rb +0 -65
  206. data/lib/components/sheet_description.rb +0 -22
  207. data/lib/components/sheet_footer.rb +0 -11
  208. data/lib/components/sheet_header.rb +0 -11
  209. data/lib/components/sheet_title.rb +0 -22
  210. data/lib/components/sheet_trigger.rb +0 -50
  211. data/lib/components/sidebar.rb +0 -108
  212. data/lib/components/sidebar_container.rb +0 -11
  213. data/lib/components/sidebar_content.rb +0 -11
  214. data/lib/components/sidebar_footer.rb +0 -11
  215. data/lib/components/sidebar_group.rb +0 -11
  216. data/lib/components/sidebar_group_content.rb +0 -11
  217. data/lib/components/sidebar_group_label.rb +0 -16
  218. data/lib/components/sidebar_header.rb +0 -11
  219. data/lib/components/sidebar_inset.rb +0 -15
  220. data/lib/components/sidebar_menu.rb +0 -11
  221. data/lib/components/sidebar_menu_button.rb +0 -61
  222. data/lib/components/sidebar_menu_item.rb +0 -9
  223. data/lib/components/sidebar_menu_sub.rb +0 -14
  224. data/lib/components/sidebar_menu_sub_button.rb +0 -48
  225. data/lib/components/sidebar_menu_sub_item.rb +0 -9
  226. data/lib/components/sidebar_trigger.rb +0 -40
  227. data/lib/components/switch.rb +0 -66
  228. data/lib/components/table.rb +0 -75
  229. data/lib/components/table_body.rb +0 -11
  230. data/lib/components/table_caption.rb +0 -11
  231. data/lib/components/table_cell.rb +0 -11
  232. data/lib/components/table_footer.rb +0 -11
  233. data/lib/components/table_head.rb +0 -14
  234. data/lib/components/table_header.rb +0 -11
  235. data/lib/components/table_row.rb +0 -11
  236. data/lib/components/tabs.rb +0 -38
  237. data/lib/components/tabs_content.rb +0 -35
  238. data/lib/components/tabs_list.rb +0 -23
  239. data/lib/components/tabs_trigger.rb +0 -45
  240. data/lib/components/textarea.rb +0 -28
  241. data/lib/components/toast.rb +0 -101
  242. data/lib/components/toast_action.rb +0 -39
  243. data/lib/components/toast_action_to.rb +0 -28
  244. data/lib/components/toast_content.rb +0 -11
  245. data/lib/components/toast_description.rb +0 -11
  246. data/lib/components/toast_title.rb +0 -11
  247. data/lib/components/tooltip.rb +0 -34
  248. data/lib/components/tooltip_content.rb +0 -39
  249. data/lib/components/tooltip_trigger.rb +0 -48
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Accordion < Base
5
+ def initialize(value: nil, multiple: false, **attributes)
6
+ @multiple = multiple
7
+ @value = value.is_a?(Array) ? value : [value]
8
+ @aria_id = "accordion-#{SecureRandom.hex(5)}"
9
+ super(**attributes)
10
+ end
11
+
12
+ def item(**attributes, &)
13
+ AccordionItem(**attributes, &)
14
+ end
15
+
16
+ def trigger(**attributes, &)
17
+ AccordionTrigger(aria_id: @aria_id, **attributes, &)
18
+ end
19
+
20
+ def content(**attributes, &)
21
+ AccordionContent(aria_id: @aria_id, **attributes, &)
22
+ end
23
+
24
+ def default_attributes
25
+ {
26
+ data: {
27
+ multiple: @multiple.to_s,
28
+ controller: "accordion",
29
+ accordion_open_items_value: @value.compact.to_json,
30
+ },
31
+ }
32
+ end
33
+
34
+ def view_template(&)
35
+ div(**@attributes, &)
36
+ end
37
+ end
38
+
39
+ class AccordionItem < Base
40
+ class_variants(base: "border-b last:border-b-0")
41
+
42
+ def initialize(value:, **attributes)
43
+ @value = value
44
+ super(**attributes)
45
+ end
46
+
47
+ def default_attributes
48
+ {
49
+ data: {
50
+ value: @value,
51
+ accordion_target: "item",
52
+ },
53
+ }
54
+ end
55
+
56
+ def view_template(&)
57
+ div(**@attributes, &)
58
+ end
59
+ end
60
+
61
+ class AccordionTrigger < Base
62
+ class_variants(
63
+ base: <<~HEREDOC,
64
+ focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between
65
+ gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline
66
+ focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180
67
+ HEREDOC
68
+ )
69
+ def initialize(aria_id: nil, **attributes)
70
+ @aria_id = aria_id
71
+ super(**attributes)
72
+ end
73
+
74
+ def default_attributes
75
+ {
76
+ type: "button",
77
+ id: "#{@aria_id}-trigger",
78
+ aria: {
79
+ controls: "#{@aria_id}-content",
80
+ expanded: "false",
81
+ },
82
+ data: {
83
+ state: "closed",
84
+ action: <<~HEREDOC,
85
+ click->accordion#toggle
86
+ keydown.up->accordion#focusTrigger:prevent
87
+ keydown.down->accordion#focusTrigger:prevent
88
+ HEREDOC
89
+ },
90
+ }
91
+ end
92
+
93
+ def view_template(&)
94
+ h3(class: "flex") do
95
+ button(**@attributes) do
96
+ yield
97
+
98
+ icon("chevron-down", class: "text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200")
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ class AccordionContent < Base
105
+ class_variants(base: "pt-0 pb-4")
106
+
107
+ def initialize(aria_id: :nil, **attributes)
108
+ @aria_id = aria_id
109
+ super(**attributes)
110
+ end
111
+
112
+ def view_template(&)
113
+ div(
114
+ class: "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm",
115
+ id: "#{@aria_id}-content",
116
+ role: "region",
117
+ aria: {
118
+ labelledby: "#{@aria_id}-trigger",
119
+ },
120
+ data: {
121
+ state: "closed",
122
+ shadcn_phlexcomponents: "accordion-content-container",
123
+ },
124
+ ) do
125
+ div(**@attributes, &)
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Alert < Base
5
+ class_variants(
6
+ base: <<~HEREDOC,
7
+ relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr]
8
+ grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5
9
+ [&>svg]:text-current
10
+ HEREDOC
11
+ variants: {
12
+ variant: {
13
+ default: "bg-card text-card-foreground",
14
+ destructive: "text-destructive bg-card [&>svg]:text-current *:data-[shadcn-phlexcomponents=alert-description]:text-destructive/90",
15
+ },
16
+ },
17
+ defaults: {
18
+ variant: :default,
19
+ },
20
+ )
21
+
22
+ def initialize(variant: :default, **attributes)
23
+ @class_variants = { variant: variant }
24
+ super(**attributes)
25
+ end
26
+
27
+ def title(**attributes, &)
28
+ AlertTitle(**attributes, &)
29
+ end
30
+
31
+ def description(**attributes, &)
32
+ AlertDescription(**attributes, &)
33
+ end
34
+
35
+ def default_attributes
36
+ { role: "alert" }
37
+ end
38
+
39
+ def view_template(&)
40
+ div(**@attributes, &)
41
+ end
42
+ end
43
+
44
+ class AlertTitle < Base
45
+ class_variants(base: "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight")
46
+
47
+ def view_template(&)
48
+ div(**@attributes, &)
49
+ end
50
+ end
51
+
52
+ class AlertDescription < Base
53
+ class_variants(base: "text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed")
54
+
55
+ def view_template(&)
56
+ div(**@attributes, &)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,276 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class AlertDialog < Base
5
+ class_variants(base: "inline-block max-w-fit")
6
+
7
+ def initialize(open: false, **attributes)
8
+ @open = open
9
+ @aria_id = "alert-dialog-#{SecureRandom.hex(5)}"
10
+ super(**attributes)
11
+ end
12
+
13
+ def trigger(**attributes, &)
14
+ AlertDialogTrigger(aria_id: @aria_id, **attributes, &)
15
+ end
16
+
17
+ def content(**attributes, &)
18
+ AlertDialogContent(aria_id: @aria_id, **attributes, &)
19
+ end
20
+
21
+ def header(**attributes, &)
22
+ AlertDialogHeader(**attributes, &)
23
+ end
24
+
25
+ def title(**attributes, &)
26
+ AlertDialogTitle(aria_id: @aria_id, **attributes, &)
27
+ end
28
+
29
+ def description(**attributes, &)
30
+ AlertDialogDescription(aria_id: @aria_id, **attributes, &)
31
+ end
32
+
33
+ def footer(**attributes, &)
34
+ AlertDialogFooter(**attributes, &)
35
+ end
36
+
37
+ def cancel(**attributes, &)
38
+ AlertDialogCancel(**attributes, &)
39
+ end
40
+
41
+ def action(**attributes, &)
42
+ AlertDialogAction(**attributes, &)
43
+ end
44
+
45
+ def action_to(name = nil, options = nil, html_options = nil, &)
46
+ AlertDialogActionTo(name, options, html_options, &)
47
+ end
48
+
49
+ def default_attributes
50
+ {
51
+ data: {
52
+ controller: "dialog",
53
+ dialog_is_open_value: @open.to_s,
54
+ },
55
+ }
56
+ end
57
+
58
+ def view_template(&)
59
+ div(**@attributes, &)
60
+ end
61
+ end
62
+
63
+ class AlertDialogTrigger < Base
64
+ def initialize(as_child: false, aria_id: nil, **attributes)
65
+ @as_child = as_child
66
+ @aria_id = aria_id
67
+ super(**attributes)
68
+ end
69
+
70
+ def default_attributes
71
+ {
72
+ role: "button",
73
+ aria: {
74
+ haspopup: "dialog",
75
+ expanded: "false",
76
+ controls: "#{@aria_id}-content",
77
+ },
78
+ data: {
79
+ action: "click->dialog#open",
80
+ dialog_target: "trigger",
81
+ as_child: @as_child.to_s,
82
+ },
83
+ }
84
+ end
85
+
86
+ def view_template(&)
87
+ if @as_child
88
+ content = capture(&)
89
+ element = find_as_child(content.to_s)
90
+ vanish(&)
91
+ merged_attributes = merged_as_child_attributes(element, @attributes)
92
+
93
+ send(element.name, **merged_attributes) do
94
+ sanitize_as_child(element.children.to_s)
95
+ end
96
+ else
97
+ div(**@attributes, &)
98
+ end
99
+ end
100
+ end
101
+
102
+ class AlertDialogContent < Base
103
+ class_variants(
104
+ base: <<~HEREDOC,
105
+ bg-background data-[state=open]:animate-in data-[state=closed]:animate-out
106
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
107
+ data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)]
108
+ translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg
109
+ pointer-events-auto
110
+ HEREDOC
111
+ )
112
+
113
+ def initialize(aria_id: nil, **attributes)
114
+ @aria_id = aria_id
115
+ super(**attributes)
116
+ end
117
+
118
+ def default_attributes
119
+ {
120
+ id: "#{@aria_id}-content",
121
+ tabindex: -1,
122
+ role: "alertdialog",
123
+ aria: {
124
+ describedby: "#{@aria_id}-description",
125
+ labelledby: "#{@aria_id}-title",
126
+ },
127
+ data: {
128
+ state: "closed",
129
+ dialog_target: "content",
130
+ },
131
+ }
132
+ end
133
+
134
+ def view_template(&)
135
+ @class = @attributes.delete(:class)
136
+ div(class: "#{@class} hidden", **@attributes, &)
137
+ end
138
+ end
139
+
140
+ class AlertDialogHeader < Base
141
+ class_variants(base: "flex flex-col gap-2 text-center sm:text-left")
142
+
143
+ def view_template(&)
144
+ div(**@attributes, &)
145
+ end
146
+ end
147
+
148
+ class AlertDialogTitle < Base
149
+ class_variants(base: "text-lg font-semibold")
150
+
151
+ def initialize(aria_id: nil, **attributes)
152
+ @aria_id = aria_id
153
+ super(**attributes)
154
+ end
155
+
156
+ def default_attributes
157
+ {
158
+ id: "#{@aria_id}-title",
159
+ }
160
+ end
161
+
162
+ def view_template(&)
163
+ h2(**@attributes, &)
164
+ end
165
+ end
166
+
167
+ class AlertDialogDescription < Base
168
+ class_variants(base: "text-sm text-muted-foreground")
169
+
170
+ def initialize(aria_id: nil, **attributes)
171
+ @aria_id = aria_id
172
+ super(**attributes)
173
+ end
174
+
175
+ def default_attributes
176
+ {
177
+ id: "#{@aria_id}-description",
178
+ }
179
+ end
180
+
181
+ def view_template(&)
182
+ p(**@attributes, &)
183
+ end
184
+ end
185
+
186
+ class AlertDialogFooter < Base
187
+ class_variants(base: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end")
188
+
189
+ def view_template(&)
190
+ div(**@attributes, &)
191
+ end
192
+ end
193
+
194
+ class AlertDialogCancel < Base
195
+ def initialize(variant: :outline, size: :default, **attributes)
196
+ @variant = variant
197
+ @size = size
198
+ super(**attributes)
199
+ end
200
+
201
+ def default_attributes
202
+ {
203
+ data: {
204
+ action: "click->dialog#close",
205
+ },
206
+ }
207
+ end
208
+
209
+ def view_template(&)
210
+ Button(variant: @variant, size: @size, **@attributes, &)
211
+ end
212
+ end
213
+
214
+ class AlertDialogAction < Base
215
+ def initialize(variant: :default, size: :default, as_child: false, **attributes)
216
+ @variant = variant
217
+ @size = size
218
+ @as_child = as_child
219
+ super(**attributes)
220
+ end
221
+
222
+ def default_attributes
223
+ {
224
+ data: {
225
+ action: "click->dialog#close",
226
+ },
227
+ }
228
+ end
229
+
230
+ def class_variants(**args)
231
+ Button.new.class_variants(variant: @variant, size: @size, class: args[:class])
232
+ end
233
+
234
+ def view_template(&)
235
+ if @as_child
236
+ content = capture(&)
237
+ element = find_as_child(content.to_s)
238
+ vanish(&)
239
+ merged_attributes = merged_as_child_attributes(element, @attributes)
240
+
241
+ send(element.name, **merged_attributes) do
242
+ sanitize_as_child(element.children.to_s)
243
+ end
244
+ else
245
+ button(**@attributes, &)
246
+ end
247
+ end
248
+ end
249
+
250
+ class AlertDialogActionTo < AlertDialogAction
251
+ def initialize(name = nil, options = nil, html_options = nil)
252
+ @name = name
253
+ @options = options
254
+ @html_options = html_options
255
+ end
256
+
257
+ def view_template(&)
258
+ if block_given?
259
+ @html_options = @options
260
+ @options = @name
261
+ end
262
+
263
+ @html_options ||= {}
264
+ @variant = @html_options.delete(:variant) || :default
265
+ @size = @html_options.delete(:size) || :default
266
+ merge_default_attributes({})
267
+ @html_options = mix(@attributes, @html_options)
268
+
269
+ if block_given?
270
+ button_to(@options, @html_options, &)
271
+ else
272
+ button_to(@name, @options, @html_options)
273
+ end
274
+ end
275
+ end
276
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class AspectRatio < Base
5
- STYLES = "absolute inset-0"
5
+ class_variants(base: "absolute inset-0")
6
6
 
7
7
  def initialize(ratio: "1/1", **attributes)
8
8
  ratio_arr = ratio.split("/").map(&:to_f)
@@ -11,7 +11,7 @@ module ShadcnPhlexcomponents
11
11
  end
12
12
 
13
13
  def view_template(&)
14
- div(style: { position: "relative", width: "100%", "padding-bottom": "#{100 / @ratio}%" }) do
14
+ div(class: "relative w-full", style: { "padding-bottom": "#{100 / @ratio}%" }) do
15
15
  div(**@attributes, &)
16
16
  end
17
17
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Avatar < Base
5
+ class_variants(base: "relative flex size-8 shrink-0 overflow-hidden rounded-full")
6
+
7
+ def initialize(**attributes)
8
+ super(**attributes)
9
+ end
10
+
11
+ def image(**attributes, &)
12
+ AvatarImage(**attributes, &)
13
+ end
14
+
15
+ def fallback(**attributes, &)
16
+ AvatarFallback(**attributes, &)
17
+ end
18
+
19
+ def default_attributes
20
+ {
21
+ data: {
22
+ controller: "avatar",
23
+ },
24
+ }
25
+ end
26
+
27
+ def view_template(&)
28
+ span(**@attributes, &)
29
+ end
30
+ end
31
+
32
+ class AvatarImage < Base
33
+ class_variants(base: "aspect-square size-full")
34
+
35
+ def default_attributes
36
+ {
37
+ data: {
38
+ avatar_target: "image",
39
+ },
40
+ }
41
+ end
42
+
43
+ def view_template(&)
44
+ img(**@attributes, &)
45
+ end
46
+ end
47
+
48
+ class AvatarFallback < Base
49
+ class_variants(base: "bg-muted flex size-full items-center justify-center rounded-full")
50
+
51
+ def default_attributes
52
+ {
53
+ data: {
54
+ avatar_target: "fallback",
55
+ },
56
+ }
57
+ end
58
+
59
+ def view_template(&)
60
+ span(**@attributes, &)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Badge < Base
5
+ class_variants(
6
+ base: <<~HEREDOC,
7
+ inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium
8
+ w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none
9
+ focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]
10
+ aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive
11
+ transition-[color,box-shadow] overflow-hidden
12
+ HEREDOC
13
+ variants: {
14
+ variant: {
15
+ default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
16
+ secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
17
+ destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
18
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
19
+ },
20
+ },
21
+ defaults: {
22
+ variant: :default,
23
+ },
24
+ )
25
+
26
+ def initialize(variant: :default, **attributes)
27
+ @class_variants = { variant: variant }
28
+ super(**attributes)
29
+ end
30
+
31
+ def view_template(&)
32
+ span(**@attributes, &)
33
+ end
34
+ end
35
+ end
@@ -2,13 +2,12 @@
2
2
 
3
3
  module ShadcnPhlexcomponents
4
4
  class Base < Phlex::HTML
5
- # Include any helpers you want to be available across all components
5
+ include ClassVariants::Helper
6
6
  include Phlex::Rails::Helpers::Sanitize
7
7
  include Phlex::Rails::Helpers::LinkTo
8
8
  include Phlex::Rails::Helpers::ButtonTo
9
9
 
10
10
  TAILWIND_MERGER = ::TailwindMerge::Merger.new.freeze
11
- STYLES = ""
12
11
 
13
12
  SANITIZER_ALLOWED_TAGS = (Rails::HTML::SafeListSanitizer.allowed_tags.to_a +
14
13
  ["svg", "path", "polygon", "polyline", "circle", "ellipse", "rect", "line", "use", "defs", "g"]).freeze
@@ -33,11 +32,29 @@ module ShadcnPhlexcomponents
33
32
  "stroke-linecap",
34
33
  "aria-hidden",
35
34
  "class",
35
+ "x1",
36
+ "x2",
37
+ "y1",
38
+ "y2",
36
39
  ]).freeze
37
40
 
38
41
  def initialize(**attributes)
42
+ merge_default_attributes(attributes)
43
+ end
44
+
45
+ def merge_default_attributes(attributes)
39
46
  @attributes = mix(default_attributes, attributes)
40
- @attributes[:class] = TAILWIND_MERGER.merge("#{default_styles} #{@attributes[:class]}")
47
+ @attributes = mix(@attributes, {
48
+ data: {
49
+ shadcn_phlexcomponents: self.class.name.demodulize.underscore.dasherize,
50
+ },
51
+ })
52
+
53
+ @attributes[:class] = class_variants(class: @attributes[:class], **@class_variants&.compact)
54
+
55
+ if @attributes[:class].blank?
56
+ @attributes.delete(:class)
57
+ end
41
58
  end
42
59
 
43
60
  if Rails.env.development?
@@ -51,10 +68,6 @@ module ShadcnPhlexcomponents
51
68
  {}
52
69
  end
53
70
 
54
- def default_styles
55
- self.class::STYLES
56
- end
57
-
58
71
  def nokogiri_attributes_to_hash(element)
59
72
  hash = {}
60
73
 
@@ -86,6 +99,20 @@ module ShadcnPhlexcomponents
86
99
  element
87
100
  end
88
101
 
102
+ def merged_as_child_attributes(element, component_attributes)
103
+ element_attributes = nokogiri_attributes_to_hash(element)
104
+ merged_attributes = mix(component_attributes, element_attributes)
105
+ merged_attributes[:class] = TAILWIND_MERGER.merge("#{component_attributes[:class]} #{element_attributes[:class]}")
106
+
107
+ # some components are divs that have role="button",
108
+ # we should remove it if the child element is a button
109
+ if component_attributes[:role].present? && component_attributes[:role].to_sym == :button && element.name == "button"
110
+ merged_attributes.delete(:role)
111
+ end
112
+
113
+ merged_attributes
114
+ end
115
+
89
116
  # https://github.com/heyvito/lucide-rails/blob/master/lib/lucide-rails/rails_helper.rb
90
117
  def icon(named, **options)
91
118
  options = options.with_indifferent_access
@@ -104,5 +131,15 @@ module ShadcnPhlexcomponents
104
131
  struct
105
132
  end
106
133
  end
134
+
135
+ def item_disabled?(disabled, value)
136
+ if disabled.is_a?(String)
137
+ value == disabled
138
+ elsif disabled.is_a?(Array)
139
+ disabled.include?(value)
140
+ else
141
+ disabled
142
+ end
143
+ end
107
144
  end
108
145
  end