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,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class DateRangePicker < Base
5
+ class_variants(base: "w-full")
6
+
7
+ def initialize(
8
+ name: nil,
9
+ value: nil,
10
+ id: nil,
11
+ format: "DD/MM/YYYY",
12
+ select_only: false,
13
+ placeholder: nil,
14
+ disabled: false,
15
+ options: {},
16
+ mask: true,
17
+ **attributes
18
+ )
19
+ if name && !name.is_a?(Array)
20
+ raise ArgumentError, "Expected an array for \"name\", got #{name.class}"
21
+ end
22
+
23
+ if value && !value.is_a?(Array)
24
+ raise ArgumentError, "Expected an array for \"value\", got #{value.class}"
25
+ end
26
+
27
+ @name = name ? name[0] : nil
28
+ @end_name = name ? name[1] : nil
29
+ @value = (value ? value[0] : nil)&.utc&.iso8601
30
+ @end_value = (value ? value[1] : nil)&.utc&.iso8601
31
+ @id = id
32
+ @format = format
33
+ @select_only = select_only
34
+ @placeholder = placeholder
35
+ @disabled = disabled
36
+ @mask = mask
37
+ @aria_id = "date-range-picker-#{SecureRandom.hex(5)}"
38
+ @date_picker_styles = DatePicker.date_picker_styles
39
+ @options = options.merge(styles: @date_picker_styles[:calendar])
40
+ super(**attributes)
41
+ end
42
+
43
+ def default_attributes
44
+ {
45
+ data: {
46
+ controller: "date-range-picker",
47
+ value: @value,
48
+ end_value: @end_value,
49
+ format: @format,
50
+ options: @options.to_json,
51
+ mask: @mask.to_s,
52
+ },
53
+ }
54
+ end
55
+
56
+ def view_template(&)
57
+ div(**@attributes) do
58
+ input(
59
+ type: :hidden,
60
+ name: @name,
61
+ value: @value,
62
+ data: { date_range_picker_target: "hiddenInput" },
63
+ )
64
+
65
+ input(
66
+ type: :hidden,
67
+ name: @end_name,
68
+ value: @end_value,
69
+ data: { date_range_picker_target: "endHiddenInput" },
70
+ )
71
+
72
+ if @select_only
73
+ # For select_only date picker, id is passed to button so that clicking on its
74
+ # label will trigger the popover to appear
75
+ DateRangePickerTrigger(
76
+ disabled: @disabled,
77
+ aria_id: @aria_id,
78
+ select_only: @select_only,
79
+ id: @id,
80
+ placeholder: @placeholder,
81
+ )
82
+ else
83
+ div(
84
+ class: @date_picker_styles[:input_container],
85
+ data: { date_range_picker_target: "inputContainer", disabled: @disabled },
86
+ ) do
87
+ input(
88
+ id: @id,
89
+ placeholder: @placeholder || "#{@format} - #{@format}",
90
+ type: :text,
91
+ class: @date_picker_styles[:input],
92
+ disabled: @disabled,
93
+ data: {
94
+ date_range_picker_target: "input",
95
+ action: "input->date-range-picker#inputDate
96
+ blur->date-range-picker#inputBlur
97
+ focus->date-range-picker#setContainerFocus",
98
+ },
99
+ )
100
+
101
+ DateRangePickerTrigger(
102
+ disabled: @disabled,
103
+ aria_id: @aria_id,
104
+ select_only: @select_only,
105
+ placeholder: @placeholder,
106
+ )
107
+ end
108
+ end
109
+
110
+ DateRangePickerContent(aria_id: @aria_id)
111
+ end
112
+ end
113
+ end
114
+
115
+ class DateRangePickerTrigger < DatePickerTrigger
116
+ def stimulus_controller_name
117
+ "date-range-picker"
118
+ end
119
+ end
120
+
121
+ class DateRangePickerContent < DatePickerContent
122
+ def stimulus_controller_name
123
+ "date-range-picker"
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class Dialog < Base
5
+ class_variants(base: "inline-block max-w-fit")
6
+
7
+ def initialize(open: false, **attributes)
8
+ @open = open
9
+ @aria_id = "dialog-#{SecureRandom.hex(5)}"
10
+ super(**attributes)
11
+ end
12
+
13
+ def trigger(**attributes, &)
14
+ DialogTrigger(aria_id: @aria_id, **attributes, &)
15
+ end
16
+
17
+ def content(**attributes, &)
18
+ DialogContent(aria_id: @aria_id, **attributes, &)
19
+ end
20
+
21
+ def header(**attributes, &)
22
+ DialogHeader(**attributes, &)
23
+ end
24
+
25
+ def title(**attributes, &)
26
+ DialogTitle(aria_id: @aria_id, **attributes, &)
27
+ end
28
+
29
+ def description(**attributes, &)
30
+ DialogDescription(aria_id: @aria_id, **attributes, &)
31
+ end
32
+
33
+ def footer(**attributes, &)
34
+ DialogFooter(**attributes, &)
35
+ end
36
+
37
+ def close(**attributes, &)
38
+ DialogClose(**attributes, &)
39
+ end
40
+
41
+ def default_attributes
42
+ {
43
+ data: {
44
+ controller: "dialog",
45
+ dialog_is_open_value: @open.to_s,
46
+ },
47
+ }
48
+ end
49
+
50
+ def view_template(&)
51
+ div(**@attributes, &)
52
+ end
53
+ end
54
+
55
+ class DialogTrigger < Base
56
+ def initialize(as_child: false, aria_id: nil, **attributes)
57
+ @as_child = as_child
58
+ @aria_id = aria_id
59
+ super(**attributes)
60
+ end
61
+
62
+ def default_attributes
63
+ {
64
+ role: "button",
65
+ aria: {
66
+ haspopup: "dialog",
67
+ expanded: "false",
68
+ controls: "#{@aria_id}-content",
69
+ },
70
+ data: {
71
+ action: "click->dialog#open",
72
+ dialog_target: "trigger",
73
+ as_child: @as_child.to_s,
74
+ },
75
+ }
76
+ end
77
+
78
+ def view_template(&)
79
+ if @as_child
80
+ content = capture(&)
81
+ element = find_as_child(content.to_s)
82
+ vanish(&)
83
+ merged_attributes = merged_as_child_attributes(element, @attributes)
84
+
85
+ send(element.name, **merged_attributes) do
86
+ sanitize_as_child(element.children.to_s)
87
+ end
88
+ else
89
+ div(**@attributes, &)
90
+ end
91
+ end
92
+ end
93
+
94
+ class DialogContent < Base
95
+ class_variants(
96
+ base: <<~HEREDOC,
97
+ bg-background data-[state=open]:animate-in data-[state=closed]:animate-out
98
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
99
+ data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)]
100
+ translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg
101
+ pointer-events-auto
102
+ HEREDOC
103
+ )
104
+
105
+ def initialize(aria_id: nil, **attributes)
106
+ @aria_id = aria_id
107
+ super(**attributes)
108
+ end
109
+
110
+ def default_attributes
111
+ {
112
+ id: "#{@aria_id}-content",
113
+ tabindex: -1,
114
+ role: "dialog",
115
+ aria: {
116
+ describedby: "#{@aria_id}-description",
117
+ labelledby: "#{@aria_id}-title",
118
+ },
119
+ data: {
120
+ dialog_target: "content",
121
+ state: "closed",
122
+ action: "dialog:click:outside->dialog#close",
123
+ },
124
+ }
125
+ end
126
+
127
+ def view_template(&)
128
+ @class = @attributes.delete(:class)
129
+ div(class: "#{@class} hidden", **@attributes) do
130
+ yield
131
+
132
+ button(
133
+ class: <<~HEREDOC,
134
+ ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground
135
+ absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2
136
+ focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none
137
+ [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4
138
+ HEREDOC
139
+ data: {
140
+ action: "click->dialog#close",
141
+ },
142
+ ) do
143
+ icon("x", class: "size-4")
144
+ span(class: "sr-only") { "close" }
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ class DialogHeader < Base
151
+ class_variants(base: "flex flex-col gap-2 text-center sm:text-left")
152
+
153
+ def view_template(&)
154
+ div(**@attributes, &)
155
+ end
156
+ end
157
+
158
+ class DialogTitle < Base
159
+ class_variants(base: "text-lg leading-none font-semibold")
160
+
161
+ def initialize(aria_id: nil, **attributes)
162
+ @aria_id = aria_id
163
+ super(**attributes)
164
+ end
165
+
166
+ def default_attributes
167
+ {
168
+ id: "#{@aria_id}-title",
169
+ }
170
+ end
171
+
172
+ def view_template(&)
173
+ h2(**@attributes, &)
174
+ end
175
+ end
176
+
177
+ class DialogDescription < Base
178
+ class_variants(base: "text-muted-foreground text-sm")
179
+
180
+ def initialize(aria_id: nil, **attributes)
181
+ @aria_id = aria_id
182
+ super(**attributes)
183
+ end
184
+
185
+ def default_attributes
186
+ {
187
+ id: "#{@aria_id}-description",
188
+ }
189
+ end
190
+
191
+ def view_template(&)
192
+ p(**@attributes, &)
193
+ end
194
+ end
195
+
196
+ class DialogFooter < Base
197
+ class_variants(base: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end")
198
+
199
+ def view_template(&)
200
+ div(**@attributes, &)
201
+ end
202
+ end
203
+
204
+ class DialogClose < Base
205
+ def initialize(as_child: false, **attributes)
206
+ @as_child = as_child
207
+ super(**attributes)
208
+ end
209
+
210
+ def default_attributes
211
+ {
212
+ role: "button",
213
+ data: {
214
+ action: "click->dialog#close",
215
+ },
216
+ }
217
+ end
218
+
219
+ def view_template(&)
220
+ if @as_child
221
+ content = capture(&)
222
+ element = find_as_child(content.to_s)
223
+ vanish(&)
224
+ merged_attributes = merged_as_child_attributes(element, @attributes)
225
+
226
+ send(element.name, **merged_attributes) do
227
+ sanitize_as_child(element.children.to_s)
228
+ end
229
+ else
230
+ div(**@attributes, &)
231
+ end
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,282 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShadcnPhlexcomponents
4
+ class DropdownMenu < Base
5
+ class_variants(base: "inline-block max-w-fit")
6
+
7
+ def initialize(open: false, **attributes)
8
+ @aria_id = "dropdown-menu-#{SecureRandom.hex(5)}"
9
+ @open = open
10
+ super(**attributes)
11
+ end
12
+
13
+ def trigger(**attributes, &)
14
+ DropdownMenuTrigger(aria_id: @aria_id, **attributes, &)
15
+ end
16
+
17
+ def content(**attributes, &)
18
+ DropdownMenuContent(aria_id: @aria_id, side: @side, **attributes, &)
19
+ end
20
+
21
+ def label(**attributes, &)
22
+ DropdownMenuLabel(**attributes, &)
23
+ end
24
+
25
+ def item(**attributes, &)
26
+ DropdownMenuItem(**attributes, &)
27
+ end
28
+
29
+ def item_to(name = nil, options = nil, html_options = nil, &)
30
+ DropdownMenuItemTo(name, options, html_options, &)
31
+ end
32
+
33
+ def separator(**attributes, &)
34
+ DropdownMenuSeparator(**attributes, &)
35
+ end
36
+
37
+ def sub(**attributes, &)
38
+ DropdownMenuSub(aria_id: "#{@aria_id}-sub-#{SecureRandom.hex(5)}", **attributes, &)
39
+ end
40
+
41
+ def group(**attributes, &)
42
+ DropdownMenuGroup(**attributes, &)
43
+ end
44
+
45
+ def default_attributes
46
+ {
47
+ data: {
48
+ controller: "dropdown-menu",
49
+ dropdown_menu_is_open_value: @open.to_s,
50
+ },
51
+ }
52
+ end
53
+
54
+ def view_template(&)
55
+ div(**@attributes, &)
56
+ end
57
+ end
58
+
59
+ class DropdownMenuTrigger < Base
60
+ def initialize(as_child: false, aria_id: nil, **attributes)
61
+ @as_child = as_child
62
+ @aria_id = aria_id
63
+ super(**attributes)
64
+ end
65
+
66
+ def view_template(&)
67
+ if @as_child
68
+ content = capture(&)
69
+ element = find_as_child(content.to_s)
70
+ vanish(&)
71
+ merged_attributes = merged_as_child_attributes(element, @attributes)
72
+
73
+ send(element.name, **merged_attributes) do
74
+ sanitize_as_child(element.children.to_s)
75
+ end
76
+ else
77
+ div(**@attributes, &)
78
+ end
79
+ end
80
+
81
+ def default_attributes
82
+ {
83
+ id: "#{@aria_id}-trigger",
84
+ role: "button",
85
+ aria: {
86
+ haspopup: "menu",
87
+ expanded: false,
88
+ controls: "#{@aria_id}-content",
89
+ },
90
+ data: {
91
+ state: "closed",
92
+ as_child: @as_child.to_s,
93
+ dropdown_menu_target: "trigger",
94
+ action: <<~HEREDOC,
95
+ click->dropdown-menu#toggle
96
+ keydown.space->dropdown-menu#open
97
+ keydown.enter->dropdown-menu#open
98
+ keydown.down->dropdown-menu#open:prevent
99
+ HEREDOC
100
+ },
101
+ }
102
+ end
103
+ end
104
+
105
+ class DropdownMenuContent < Base
106
+ class_variants(
107
+ base: <<~HEREDOC,
108
+ bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out
109
+ data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
110
+ data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2
111
+ data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50
112
+ max-h-(--radix-popper-available-height) min-w-[8rem] origin-(--radix-popper-transform-origin)
113
+ overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md pointer-events-auto outline-none
114
+ HEREDOC
115
+ )
116
+
117
+ def initialize(side: :bottom, align: :center, aria_id: nil, **attributes)
118
+ @side = side
119
+ @align = align
120
+ @aria_id = aria_id
121
+ super(**attributes)
122
+ end
123
+
124
+ def view_template(&)
125
+ div(
126
+ class: "hidden fixed top-0 left-0 w-max z-50",
127
+ data: { dropdown_menu_target: "contentContainer" },
128
+ ) do
129
+ div(**@attributes, &)
130
+ end
131
+ end
132
+
133
+ def default_attributes
134
+ {
135
+ id: "#{@aria_id}-content",
136
+ tabindex: -1,
137
+ role: "menu",
138
+ aria: {
139
+ labelledby: "#{@aria_id}-trigger",
140
+ orientation: "vertical",
141
+ },
142
+ data: {
143
+ state: "closed",
144
+ side: @side,
145
+ align: @align,
146
+ dropdown_menu_target: "content",
147
+ action: <<~HEREDOC,
148
+ dropdown-menu:click:outside->dropdown-menu#clickOutside
149
+ keydown.up->dropdown-menu#focusItemByIndex:prevent:self
150
+ keydown.down->dropdown-menu#focusItemByIndex:prevent:self
151
+ HEREDOC
152
+ },
153
+ }
154
+ end
155
+ end
156
+
157
+ class DropdownMenuLabel < Base
158
+ class_variants(base: "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8")
159
+
160
+ def view_template(&)
161
+ div(**@attributes, &)
162
+ end
163
+ end
164
+
165
+ class DropdownMenuItem < Base
166
+ class_variants(
167
+ base: <<~HEREDOC,
168
+ focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive
169
+ data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20
170
+ data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive
171
+ [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2
172
+ rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none
173
+ data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0
174
+ [&_svg:not([class*='size-'])]:size-4
175
+ HEREDOC
176
+ )
177
+
178
+ def initialize(as_child: false, variant: :default, disabled: false, **attributes)
179
+ @variant = variant
180
+ @as_child = as_child
181
+ @disabled = disabled
182
+ super(**attributes)
183
+ end
184
+
185
+ def view_template(&)
186
+ if @as_child
187
+ content = capture(&)
188
+ element = find_as_child(content.to_s)
189
+ vanish(&)
190
+ merged_attributes = merged_as_child_attributes(element, @attributes)
191
+
192
+ send(element.name, **merged_attributes) do
193
+ sanitize_as_child(element.children.to_s)
194
+ end
195
+ else
196
+ div(**@attributes, &)
197
+ end
198
+ end
199
+
200
+ def default_attributes
201
+ {
202
+ role: "menuitem",
203
+ tabindex: -1,
204
+ data: {
205
+ variant: @variant,
206
+ disabled: @disabled,
207
+ dropdown_menu_target: "item",
208
+ action: <<~HEREDOC,
209
+ click->dropdown-menu#select
210
+ mouseover->dropdown-menu#focusItem
211
+ keydown.up->dropdown-menu#focusItem:prevent
212
+ keydown.down->dropdown-menu#focusItem:prevent
213
+ focus->dropdown-menu#onItemFocus
214
+ blur->dropdown-menu#onItemBlur
215
+ keydown.enter->dropdown-menu#select:prevent
216
+ keydown.space->dropdown-menu#select:prevent
217
+ mouseout->dropdown-menu#focusContent
218
+ HEREDOC
219
+
220
+ },
221
+ }
222
+ end
223
+ end
224
+
225
+ class DropdownMenuItemTo < DropdownMenuItem
226
+ def initialize(name = nil, options = nil, html_options = nil)
227
+ @name = name
228
+ @options = options
229
+ @html_options = html_options
230
+ end
231
+
232
+ def class_variants(**args)
233
+ DropdownMenuItem.new.class_variants(class: "w-full #{args[:class]}")
234
+ end
235
+
236
+ def view_template(&)
237
+ if block_given?
238
+ @html_options = @options
239
+ @options = @name
240
+ end
241
+
242
+ @html_options ||= {}
243
+ @variant = @html_options.delete(:variant) || :default
244
+ @disabled = @html_options[:disabled]
245
+ merge_default_attributes({})
246
+ @html_options = mix(@attributes, @html_options)
247
+
248
+ if block_given?
249
+ button_to(@options, @html_options, &)
250
+ else
251
+ button_to(@name, @options, @html_options)
252
+ end
253
+ end
254
+ end
255
+
256
+ class DropdownMenuSeparator < Base
257
+ class_variants(base: "bg-border -mx-1 my-1 h-px")
258
+
259
+ def view_template(&)
260
+ div(**@attributes, &)
261
+ end
262
+
263
+ def default_attributes
264
+ {
265
+ role: "separator",
266
+ aria: {
267
+ orientation: "horizontal",
268
+ },
269
+ }
270
+ end
271
+ end
272
+
273
+ class DropdownMenuGroup < Base
274
+ def default_attributes
275
+ { role: "group" }
276
+ end
277
+
278
+ def view_template(&)
279
+ div(**@attributes, &)
280
+ end
281
+ end
282
+ end