shadcn_view_component 0.3.3

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 (507) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +255 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +604 -0
  5. data/app/assets/stylesheets/shadcn-themes.css +1075 -0
  6. data/app/assets/stylesheets/shadcn.css +853 -0
  7. data/app/components/shadcn/accordion/component.rb +44 -0
  8. data/app/components/shadcn/accordion/content/component.rb +44 -0
  9. data/app/components/shadcn/accordion/item/component.rb +41 -0
  10. data/app/components/shadcn/accordion/preview.rb +16 -0
  11. data/app/components/shadcn/accordion/previews/default.html.erb +10 -0
  12. data/app/components/shadcn/accordion/previews/multiple.html.erb +13 -0
  13. data/app/components/shadcn/accordion/trigger/component.rb +52 -0
  14. data/app/components/shadcn/alert/component.rb +52 -0
  15. data/app/components/shadcn/alert/preview.rb +11 -0
  16. data/app/components/shadcn/alert/previews/default.html.erb +8 -0
  17. data/app/components/shadcn/alert.rb +17 -0
  18. data/app/components/shadcn/alert_dialog/action/component.rb +35 -0
  19. data/app/components/shadcn/alert_dialog/cancel/component.rb +16 -0
  20. data/app/components/shadcn/alert_dialog/component.rb +20 -0
  21. data/app/components/shadcn/alert_dialog/content/component.rb +55 -0
  22. data/app/components/shadcn/alert_dialog/header/component.rb +33 -0
  23. data/app/components/shadcn/alert_dialog/preview.rb +16 -0
  24. data/app/components/shadcn/alert_dialog/previews/default.html.erb +13 -0
  25. data/app/components/shadcn/alert_dialog/previews/small_with_media.html.erb +38 -0
  26. data/app/components/shadcn/alert_dialog.rb +32 -0
  27. data/app/components/shadcn/application_view_component.rb +225 -0
  28. data/app/components/shadcn/application_view_component_preview.rb +8 -0
  29. data/app/components/shadcn/aspect_ratio/component.rb +34 -0
  30. data/app/components/shadcn/aspect_ratio/preview.rb +16 -0
  31. data/app/components/shadcn/aspect_ratio/previews/default.html.erb +5 -0
  32. data/app/components/shadcn/aspect_ratio/previews/ratios.html.erb +12 -0
  33. data/app/components/shadcn/attachment/action/component.rb +19 -0
  34. data/app/components/shadcn/attachment/component.rb +76 -0
  35. data/app/components/shadcn/attachment/media/component.rb +56 -0
  36. data/app/components/shadcn/attachment/preview.rb +11 -0
  37. data/app/components/shadcn/attachment/previews/default.html.erb +80 -0
  38. data/app/components/shadcn/attachment/trigger/component.rb +31 -0
  39. data/app/components/shadcn/attachment.rb +42 -0
  40. data/app/components/shadcn/avatar/component.rb +43 -0
  41. data/app/components/shadcn/avatar/fallback/component.rb +23 -0
  42. data/app/components/shadcn/avatar/image/component.rb +20 -0
  43. data/app/components/shadcn/avatar/preview.rb +11 -0
  44. data/app/components/shadcn/avatar/previews/default.html.erb +13 -0
  45. data/app/components/shadcn/avatar.rb +32 -0
  46. data/app/components/shadcn/badge/component.rb +57 -0
  47. data/app/components/shadcn/badge/preview.rb +11 -0
  48. data/app/components/shadcn/badge/previews/default.html.erb +5 -0
  49. data/app/components/shadcn/breadcrumb/component.rb +15 -0
  50. data/app/components/shadcn/breadcrumb/ellipsis/component.rb +28 -0
  51. data/app/components/shadcn/breadcrumb/page/component.rb +25 -0
  52. data/app/components/shadcn/breadcrumb/preview.rb +16 -0
  53. data/app/components/shadcn/breadcrumb/previews/custom_separator.html.erb +17 -0
  54. data/app/components/shadcn/breadcrumb/previews/default.html.erb +15 -0
  55. data/app/components/shadcn/breadcrumb/separator/component.rb +31 -0
  56. data/app/components/shadcn/breadcrumb.rb +18 -0
  57. data/app/components/shadcn/bubble/component.rb +90 -0
  58. data/app/components/shadcn/bubble/preview.rb +16 -0
  59. data/app/components/shadcn/bubble/previews/alignment.html.erb +33 -0
  60. data/app/components/shadcn/bubble/previews/default.html.erb +22 -0
  61. data/app/components/shadcn/bubble/reactions/component.rb +54 -0
  62. data/app/components/shadcn/bubble.rb +24 -0
  63. data/app/components/shadcn/button/component.rb +85 -0
  64. data/app/components/shadcn/button/preview.rb +31 -0
  65. data/app/components/shadcn/button/previews/default.html.erb +8 -0
  66. data/app/components/shadcn/button/previews/sizes.html.erb +5 -0
  67. data/app/components/shadcn/button/previews/variants.html.erb +5 -0
  68. data/app/components/shadcn/button_group/component.rb +53 -0
  69. data/app/components/shadcn/button_group/preview.rb +15 -0
  70. data/app/components/shadcn/button_group/previews/default.html.erb +18 -0
  71. data/app/components/shadcn/button_group/previews/vertical.html.erb +5 -0
  72. data/app/components/shadcn/button_group/separator/component.rb +30 -0
  73. data/app/components/shadcn/button_group/text/component.rb +20 -0
  74. data/app/components/shadcn/calendar/component.rb +558 -0
  75. data/app/components/shadcn/calendar/month.rb +74 -0
  76. data/app/components/shadcn/calendar/preview.rb +64 -0
  77. data/app/components/shadcn/calendar/previews/booked.html.erb +18 -0
  78. data/app/components/shadcn/calendar/previews/custom_cell_size.html.erb +11 -0
  79. data/app/components/shadcn/calendar/previews/date_and_time.html.erb +31 -0
  80. data/app/components/shadcn/calendar/previews/default.html.erb +8 -0
  81. data/app/components/shadcn/calendar/previews/dropdown_caption.html.erb +11 -0
  82. data/app/components/shadcn/calendar/previews/in_a_form.html.erb +8 -0
  83. data/app/components/shadcn/calendar/previews/presets.html.erb +20 -0
  84. data/app/components/shadcn/calendar/previews/range.html.erb +10 -0
  85. data/app/components/shadcn/calendar/previews/week_numbers.html.erb +8 -0
  86. data/app/components/shadcn/card/component.rb +24 -0
  87. data/app/components/shadcn/card/header/component.rb +26 -0
  88. data/app/components/shadcn/card/preview.rb +16 -0
  89. data/app/components/shadcn/card/previews/default.html.erb +18 -0
  90. data/app/components/shadcn/card/previews/image.html.erb +37 -0
  91. data/app/components/shadcn/card.rb +21 -0
  92. data/app/components/shadcn/carousel/component.rb +61 -0
  93. data/app/components/shadcn/carousel/content/component.rb +86 -0
  94. data/app/components/shadcn/carousel/item/component.rb +42 -0
  95. data/app/components/shadcn/carousel/next/component.rb +59 -0
  96. data/app/components/shadcn/carousel/preview.rb +22 -0
  97. data/app/components/shadcn/carousel/previews/default.html.erb +22 -0
  98. data/app/components/shadcn/carousel/previews/sizes.html.erb +42 -0
  99. data/app/components/shadcn/carousel/previews/vertical.html.erb +27 -0
  100. data/app/components/shadcn/carousel/previous/component.rb +59 -0
  101. data/app/components/shadcn/chart/area/component.rb +43 -0
  102. data/app/components/shadcn/chart/bar/component.rb +75 -0
  103. data/app/components/shadcn/chart/cartesian/component.rb +152 -0
  104. data/app/components/shadcn/chart/component.rb +124 -0
  105. data/app/components/shadcn/chart/focusable.rb +38 -0
  106. data/app/components/shadcn/chart/legend/component.rb +55 -0
  107. data/app/components/shadcn/chart/line/component.rb +50 -0
  108. data/app/components/shadcn/chart/pie/component.rb +169 -0
  109. data/app/components/shadcn/chart/plot.rb +147 -0
  110. data/app/components/shadcn/chart/preview.rb +45 -0
  111. data/app/components/shadcn/chart/previews/area.html.erb +31 -0
  112. data/app/components/shadcn/chart/previews/bar.html.erb +32 -0
  113. data/app/components/shadcn/chart/previews/bar_stacked.html.erb +30 -0
  114. data/app/components/shadcn/chart/previews/default.html.erb +30 -0
  115. data/app/components/shadcn/chart/previews/donut.html.erb +16 -0
  116. data/app/components/shadcn/chart/previews/line.html.erb +30 -0
  117. data/app/components/shadcn/chart/previews/percentages.html.erb +17 -0
  118. data/app/components/shadcn/chart/table/component.rb +75 -0
  119. data/app/components/shadcn/chart/tooltip/component.rb +111 -0
  120. data/app/components/shadcn/checkbox/component.rb +109 -0
  121. data/app/components/shadcn/checkbox/preview.rb +16 -0
  122. data/app/components/shadcn/checkbox/previews/default.html.erb +14 -0
  123. data/app/components/shadcn/checkbox/previews/states.html.erb +23 -0
  124. data/app/components/shadcn/collapsible/component.rb +35 -0
  125. data/app/components/shadcn/collapsible/content/component.rb +20 -0
  126. data/app/components/shadcn/collapsible/preview.rb +11 -0
  127. data/app/components/shadcn/collapsible/previews/default.html.erb +9 -0
  128. data/app/components/shadcn/collapsible/trigger/component.rb +23 -0
  129. data/app/components/shadcn/combobox/chip/component.rb +60 -0
  130. data/app/components/shadcn/combobox/chip_input/component.rb +43 -0
  131. data/app/components/shadcn/combobox/chips/component.rb +54 -0
  132. data/app/components/shadcn/combobox/clear/component.rb +32 -0
  133. data/app/components/shadcn/combobox/component.rb +113 -0
  134. data/app/components/shadcn/combobox/content/component.rb +59 -0
  135. data/app/components/shadcn/combobox/empty/component.rb +23 -0
  136. data/app/components/shadcn/combobox/input/component.rb +85 -0
  137. data/app/components/shadcn/combobox/item/component.rb +69 -0
  138. data/app/components/shadcn/combobox/list/component.rb +27 -0
  139. data/app/components/shadcn/combobox/preview.rb +31 -0
  140. data/app/components/shadcn/combobox/previews/default.html.erb +20 -0
  141. data/app/components/shadcn/combobox/previews/grouped.html.erb +25 -0
  142. data/app/components/shadcn/combobox/previews/multiple.html.erb +28 -0
  143. data/app/components/shadcn/combobox/previews/with_clear.html.erb +16 -0
  144. data/app/components/shadcn/combobox/trigger/component.rb +54 -0
  145. data/app/components/shadcn/combobox.rb +16 -0
  146. data/app/components/shadcn/command/component.rb +67 -0
  147. data/app/components/shadcn/command/dialog/component.rb +72 -0
  148. data/app/components/shadcn/command/empty/component.rb +29 -0
  149. data/app/components/shadcn/command/group/component.rb +63 -0
  150. data/app/components/shadcn/command/input/component.rb +66 -0
  151. data/app/components/shadcn/command/item/component.rb +62 -0
  152. data/app/components/shadcn/command/list/component.rb +36 -0
  153. data/app/components/shadcn/command/preview.rb +26 -0
  154. data/app/components/shadcn/command/previews/default.html.erb +41 -0
  155. data/app/components/shadcn/command/previews/dialog.html.erb +33 -0
  156. data/app/components/shadcn/command/previews/ranking.html.erb +16 -0
  157. data/app/components/shadcn/command/separator/component.rb +33 -0
  158. data/app/components/shadcn/command.rb +14 -0
  159. data/app/components/shadcn/concerns/modal_root.rb +43 -0
  160. data/app/components/shadcn/concerns/submits_value.rb +81 -0
  161. data/app/components/shadcn/context_menu/component.rb +45 -0
  162. data/app/components/shadcn/context_menu/content/component.rb +40 -0
  163. data/app/components/shadcn/context_menu/preview.rb +16 -0
  164. data/app/components/shadcn/context_menu/previews/default.html.erb +34 -0
  165. data/app/components/shadcn/context_menu/previews/items.html.erb +35 -0
  166. data/app/components/shadcn/context_menu/sub/component.rb +47 -0
  167. data/app/components/shadcn/context_menu/sub_content/component.rb +31 -0
  168. data/app/components/shadcn/context_menu/trigger/component.rb +50 -0
  169. data/app/components/shadcn/context_menu.rb +43 -0
  170. data/app/components/shadcn/dialog/close/component.rb +20 -0
  171. data/app/components/shadcn/dialog/component.rb +20 -0
  172. data/app/components/shadcn/dialog/content/component.rb +78 -0
  173. data/app/components/shadcn/dialog/header/component.rb +23 -0
  174. data/app/components/shadcn/dialog/overlay/component.rb +28 -0
  175. data/app/components/shadcn/dialog/preview.rb +28 -0
  176. data/app/components/shadcn/dialog/previews/default.html.erb +17 -0
  177. data/app/components/shadcn/dialog/previews/inside_stacking_context.html.erb +25 -0
  178. data/app/components/shadcn/dialog/previews/no_close_button.html.erb +15 -0
  179. data/app/components/shadcn/dialog/previews/scrollable_content.html.erb +29 -0
  180. data/app/components/shadcn/dialog/trigger/component.rb +24 -0
  181. data/app/components/shadcn/dialog.rb +17 -0
  182. data/app/components/shadcn/drawer/component.rb +33 -0
  183. data/app/components/shadcn/drawer/content/component.rb +95 -0
  184. data/app/components/shadcn/drawer/header/component.rb +34 -0
  185. data/app/components/shadcn/drawer/preview.rb +29 -0
  186. data/app/components/shadcn/drawer/previews/default.html.erb +21 -0
  187. data/app/components/shadcn/drawer/previews/scrollable.html.erb +20 -0
  188. data/app/components/shadcn/drawer/previews/scrollable_side.html.erb +21 -0
  189. data/app/components/shadcn/drawer/previews/sides.html.erb +17 -0
  190. data/app/components/shadcn/drawer.rb +27 -0
  191. data/app/components/shadcn/dropdown_menu/checkbox_item/component.rb +61 -0
  192. data/app/components/shadcn/dropdown_menu/component.rb +48 -0
  193. data/app/components/shadcn/dropdown_menu/content/component.rb +49 -0
  194. data/app/components/shadcn/dropdown_menu/group/component.rb +16 -0
  195. data/app/components/shadcn/dropdown_menu/item/component.rb +50 -0
  196. data/app/components/shadcn/dropdown_menu/preview.rb +16 -0
  197. data/app/components/shadcn/dropdown_menu/previews/checkboxes_and_radio.html.erb +34 -0
  198. data/app/components/shadcn/dropdown_menu/previews/default.html.erb +23 -0
  199. data/app/components/shadcn/dropdown_menu/radio_group/component.rb +16 -0
  200. data/app/components/shadcn/dropdown_menu/radio_item/component.rb +63 -0
  201. data/app/components/shadcn/dropdown_menu/sub/component.rb +44 -0
  202. data/app/components/shadcn/dropdown_menu/sub_content/component.rb +45 -0
  203. data/app/components/shadcn/dropdown_menu/sub_trigger/component.rb +58 -0
  204. data/app/components/shadcn/dropdown_menu/trigger/component.rb +25 -0
  205. data/app/components/shadcn/dropdown_menu.rb +18 -0
  206. data/app/components/shadcn/empty/component.rb +17 -0
  207. data/app/components/shadcn/empty/media/component.rb +48 -0
  208. data/app/components/shadcn/empty/preview.rb +16 -0
  209. data/app/components/shadcn/empty/previews/default.html.erb +15 -0
  210. data/app/components/shadcn/empty/previews/media.html.erb +32 -0
  211. data/app/components/shadcn/empty.rb +26 -0
  212. data/app/components/shadcn/field/component.rb +61 -0
  213. data/app/components/shadcn/field/error/component.rb +49 -0
  214. data/app/components/shadcn/field/legend/component.rb +30 -0
  215. data/app/components/shadcn/field/preview.rb +17 -0
  216. data/app/components/shadcn/field/previews/default.html.erb +29 -0
  217. data/app/components/shadcn/field/previews/form_builder.html.erb +38 -0
  218. data/app/components/shadcn/field/separator/component.rb +35 -0
  219. data/app/components/shadcn/field.rb +44 -0
  220. data/app/components/shadcn/hover_card/component.rb +51 -0
  221. data/app/components/shadcn/hover_card/content/component.rb +45 -0
  222. data/app/components/shadcn/hover_card/preview.rb +16 -0
  223. data/app/components/shadcn/hover_card/previews/default.html.erb +36 -0
  224. data/app/components/shadcn/hover_card/previews/sides.html.erb +15 -0
  225. data/app/components/shadcn/hover_card/trigger/component.rb +33 -0
  226. data/app/components/shadcn/icon/component.rb +76 -0
  227. data/app/components/shadcn/icon.rb +43 -0
  228. data/app/components/shadcn/input/component.rb +26 -0
  229. data/app/components/shadcn/input/preview.rb +16 -0
  230. data/app/components/shadcn/input/previews/default.html.erb +5 -0
  231. data/app/components/shadcn/input/previews/states.html.erb +20 -0
  232. data/app/components/shadcn/input_group/addon/component.rb +65 -0
  233. data/app/components/shadcn/input_group/button/component.rb +40 -0
  234. data/app/components/shadcn/input_group/component.rb +43 -0
  235. data/app/components/shadcn/input_group/input/component.rb +25 -0
  236. data/app/components/shadcn/input_group/preview.rb +17 -0
  237. data/app/components/shadcn/input_group/previews/addons.html.erb +53 -0
  238. data/app/components/shadcn/input_group/previews/default.html.erb +25 -0
  239. data/app/components/shadcn/input_group/text/component.rb +20 -0
  240. data/app/components/shadcn/input_group/textarea/component.rb +21 -0
  241. data/app/components/shadcn/input_otp/component.rb +95 -0
  242. data/app/components/shadcn/input_otp/preview.rb +17 -0
  243. data/app/components/shadcn/input_otp/previews/default.html.erb +19 -0
  244. data/app/components/shadcn/input_otp/previews/variations.html.erb +33 -0
  245. data/app/components/shadcn/input_otp/separator/component.rb +21 -0
  246. data/app/components/shadcn/input_otp/slot/component.rb +60 -0
  247. data/app/components/shadcn/input_otp.rb +11 -0
  248. data/app/components/shadcn/item/component.rb +56 -0
  249. data/app/components/shadcn/item/group/component.rb +53 -0
  250. data/app/components/shadcn/item/media/component.rb +53 -0
  251. data/app/components/shadcn/item/preview.rb +20 -0
  252. data/app/components/shadcn/item/previews/default.html.erb +32 -0
  253. data/app/components/shadcn/item/previews/link.html.erb +39 -0
  254. data/app/components/shadcn/item/previews/outline.html.erb +8 -0
  255. data/app/components/shadcn/item/separator/component.rb +24 -0
  256. data/app/components/shadcn/item.rb +34 -0
  257. data/app/components/shadcn/kbd/component.rb +23 -0
  258. data/app/components/shadcn/kbd/group/component.rb +17 -0
  259. data/app/components/shadcn/kbd/preview.rb +11 -0
  260. data/app/components/shadcn/kbd/previews/default.html.erb +4 -0
  261. data/app/components/shadcn/label/component.rb +20 -0
  262. data/app/components/shadcn/label/preview.rb +11 -0
  263. data/app/components/shadcn/label/previews/default.html.erb +4 -0
  264. data/app/components/shadcn/marker/component.rb +46 -0
  265. data/app/components/shadcn/marker/icon/component.rb +23 -0
  266. data/app/components/shadcn/marker/preview.rb +17 -0
  267. data/app/components/shadcn/marker/previews/default.html.erb +18 -0
  268. data/app/components/shadcn/marker/previews/status.html.erb +32 -0
  269. data/app/components/shadcn/marker.rb +17 -0
  270. data/app/components/shadcn/menubar/component.rb +36 -0
  271. data/app/components/shadcn/menubar/content/component.rb +49 -0
  272. data/app/components/shadcn/menubar/menu/component.rb +39 -0
  273. data/app/components/shadcn/menubar/preview.rb +16 -0
  274. data/app/components/shadcn/menubar/previews/default.html.erb +52 -0
  275. data/app/components/shadcn/menubar/previews/items.html.erb +38 -0
  276. data/app/components/shadcn/menubar/sub/component.rb +43 -0
  277. data/app/components/shadcn/menubar/sub_content/component.rb +31 -0
  278. data/app/components/shadcn/menubar/sub_trigger/component.rb +31 -0
  279. data/app/components/shadcn/menubar/trigger/component.rb +41 -0
  280. data/app/components/shadcn/menubar.rb +47 -0
  281. data/app/components/shadcn/message/component.rb +33 -0
  282. data/app/components/shadcn/message/preview.rb +16 -0
  283. data/app/components/shadcn/message/previews/actions.html.erb +51 -0
  284. data/app/components/shadcn/message/previews/default.html.erb +35 -0
  285. data/app/components/shadcn/message.rb +35 -0
  286. data/app/components/shadcn/message_scroller/button/component.rb +78 -0
  287. data/app/components/shadcn/message_scroller/component.rb +59 -0
  288. data/app/components/shadcn/message_scroller/content/component.rb +50 -0
  289. data/app/components/shadcn/message_scroller/item/component.rb +45 -0
  290. data/app/components/shadcn/message_scroller/preview.rb +11 -0
  291. data/app/components/shadcn/message_scroller/previews/default.html.erb +72 -0
  292. data/app/components/shadcn/message_scroller/viewport/component.rb +41 -0
  293. data/app/components/shadcn/mode_switcher/component.rb +67 -0
  294. data/app/components/shadcn/mode_switcher/preview.rb +11 -0
  295. data/app/components/shadcn/mode_switcher/previews/default.html.erb +5 -0
  296. data/app/components/shadcn/mode_toggle/component.rb +75 -0
  297. data/app/components/shadcn/mode_toggle/preview.rb +11 -0
  298. data/app/components/shadcn/mode_toggle/previews/default.html.erb +20 -0
  299. data/app/components/shadcn/native_select/component.rb +59 -0
  300. data/app/components/shadcn/native_select/preview.rb +16 -0
  301. data/app/components/shadcn/native_select/previews/default.html.erb +9 -0
  302. data/app/components/shadcn/native_select/previews/groups.html.erb +26 -0
  303. data/app/components/shadcn/native_select.rb +16 -0
  304. data/app/components/shadcn/navigation_menu/component.rb +51 -0
  305. data/app/components/shadcn/navigation_menu/content/component.rb +58 -0
  306. data/app/components/shadcn/navigation_menu/preview.rb +11 -0
  307. data/app/components/shadcn/navigation_menu/previews/default.html.erb +49 -0
  308. data/app/components/shadcn/navigation_menu/trigger/component.rb +59 -0
  309. data/app/components/shadcn/navigation_menu.rb +28 -0
  310. data/app/components/shadcn/pagination/component.rb +19 -0
  311. data/app/components/shadcn/pagination/ellipsis/component.rb +28 -0
  312. data/app/components/shadcn/pagination/link/component.rb +37 -0
  313. data/app/components/shadcn/pagination/next/component.rb +31 -0
  314. data/app/components/shadcn/pagination/preview.rb +16 -0
  315. data/app/components/shadcn/pagination/previews/default.html.erb +18 -0
  316. data/app/components/shadcn/pagination/previews/simple.html.erb +39 -0
  317. data/app/components/shadcn/pagination/previous/component.rb +31 -0
  318. data/app/components/shadcn/pagination.rb +14 -0
  319. data/app/components/shadcn/parts.rb +38 -0
  320. data/app/components/shadcn/popover/anchor/component.rb +17 -0
  321. data/app/components/shadcn/popover/component.rb +42 -0
  322. data/app/components/shadcn/popover/content/component.rb +40 -0
  323. data/app/components/shadcn/popover/preview.rb +28 -0
  324. data/app/components/shadcn/popover/previews/align.html.erb +13 -0
  325. data/app/components/shadcn/popover/previews/default.html.erb +9 -0
  326. data/app/components/shadcn/popover/previews/inside_containing_block.html.erb +41 -0
  327. data/app/components/shadcn/popover/previews/inside_stacking_context.html.erb +30 -0
  328. data/app/components/shadcn/popover/trigger/component.rb +24 -0
  329. data/app/components/shadcn/popover.rb +16 -0
  330. data/app/components/shadcn/progress/component.rb +62 -0
  331. data/app/components/shadcn/progress/preview.rb +11 -0
  332. data/app/components/shadcn/progress/previews/default.html.erb +5 -0
  333. data/app/components/shadcn/radio_group/component.rb +51 -0
  334. data/app/components/shadcn/radio_group/item/component.rb +74 -0
  335. data/app/components/shadcn/radio_group/preview.rb +16 -0
  336. data/app/components/shadcn/radio_group/previews/default.html.erb +15 -0
  337. data/app/components/shadcn/radio_group/previews/states.html.erb +41 -0
  338. data/app/components/shadcn/resizable/component.rb +59 -0
  339. data/app/components/shadcn/resizable/handle/component.rb +70 -0
  340. data/app/components/shadcn/resizable/panel/component.rb +53 -0
  341. data/app/components/shadcn/resizable/preview.rb +23 -0
  342. data/app/components/shadcn/resizable/previews/default.html.erb +25 -0
  343. data/app/components/shadcn/resizable/previews/vertical.html.erb +19 -0
  344. data/app/components/shadcn/resizable/previews/with_handle.html.erb +17 -0
  345. data/app/components/shadcn/scroll_area/component.rb +84 -0
  346. data/app/components/shadcn/scroll_area/preview.rb +11 -0
  347. data/app/components/shadcn/scroll_area/previews/default.html.erb +36 -0
  348. data/app/components/shadcn/scroll_area/scrollbar/component.rb +72 -0
  349. data/app/components/shadcn/scroll_area/viewport/component.rb +70 -0
  350. data/app/components/shadcn/scroll_area.rb +14 -0
  351. data/app/components/shadcn/select/component.rb +67 -0
  352. data/app/components/shadcn/select/content/component.rb +157 -0
  353. data/app/components/shadcn/select/empty/component.rb +38 -0
  354. data/app/components/shadcn/select/group/component.rb +16 -0
  355. data/app/components/shadcn/select/item/component.rb +71 -0
  356. data/app/components/shadcn/select/list/component.rb +41 -0
  357. data/app/components/shadcn/select/preview.rb +24 -0
  358. data/app/components/shadcn/select/previews/default.html.erb +17 -0
  359. data/app/components/shadcn/select/previews/scrollable.html.erb +19 -0
  360. data/app/components/shadcn/select/previews/searchable.html.erb +18 -0
  361. data/app/components/shadcn/select/previews/states.html.erb +25 -0
  362. data/app/components/shadcn/select/search/component.rb +54 -0
  363. data/app/components/shadcn/select/trigger/component.rb +78 -0
  364. data/app/components/shadcn/select/value/component.rb +28 -0
  365. data/app/components/shadcn/select.rb +15 -0
  366. data/app/components/shadcn/separator/component.rb +41 -0
  367. data/app/components/shadcn/separator/preview.rb +11 -0
  368. data/app/components/shadcn/separator/previews/default.html.erb +9 -0
  369. data/app/components/shadcn/sheet/component.rb +16 -0
  370. data/app/components/shadcn/sheet/content/component.rb +98 -0
  371. data/app/components/shadcn/sheet/header/component.rb +23 -0
  372. data/app/components/shadcn/sheet/preview.rb +16 -0
  373. data/app/components/shadcn/sheet/previews/default.html.erb +16 -0
  374. data/app/components/shadcn/sheet/previews/no_close_button.html.erb +14 -0
  375. data/app/components/shadcn/sheet.rb +22 -0
  376. data/app/components/shadcn/sidebar/component.rb +232 -0
  377. data/app/components/shadcn/sidebar/input/component.rb +25 -0
  378. data/app/components/shadcn/sidebar/menu_action/component.rb +58 -0
  379. data/app/components/shadcn/sidebar/menu_button/component.rb +100 -0
  380. data/app/components/shadcn/sidebar/menu_skeleton/component.rb +51 -0
  381. data/app/components/shadcn/sidebar/menu_sub_button/component.rb +60 -0
  382. data/app/components/shadcn/sidebar/preview.rb +22 -0
  383. data/app/components/shadcn/sidebar/previews/default.html.erb +189 -0
  384. data/app/components/shadcn/sidebar/previews/floating.html.erb +39 -0
  385. data/app/components/shadcn/sidebar/previews/inset.html.erb +48 -0
  386. data/app/components/shadcn/sidebar/provider/component.rb +53 -0
  387. data/app/components/shadcn/sidebar/rail/component.rb +43 -0
  388. data/app/components/shadcn/sidebar/separator/component.rb +23 -0
  389. data/app/components/shadcn/sidebar/trigger/component.rb +39 -0
  390. data/app/components/shadcn/sidebar.rb +98 -0
  391. data/app/components/shadcn/skeleton/component.rb +14 -0
  392. data/app/components/shadcn/skeleton/preview.rb +11 -0
  393. data/app/components/shadcn/skeleton/previews/default.html.erb +7 -0
  394. data/app/components/shadcn/slider/component.rb +145 -0
  395. data/app/components/shadcn/slider/preview.rb +16 -0
  396. data/app/components/shadcn/slider/previews/default.html.erb +17 -0
  397. data/app/components/shadcn/slider/previews/vertical.html.erb +7 -0
  398. data/app/components/shadcn/slider/range/component.rb +51 -0
  399. data/app/components/shadcn/slider/thumb/component.rb +58 -0
  400. data/app/components/shadcn/slider/track/component.rb +32 -0
  401. data/app/components/shadcn/spinner/component.rb +21 -0
  402. data/app/components/shadcn/spinner/preview.rb +11 -0
  403. data/app/components/shadcn/spinner/previews/default.html.erb +7 -0
  404. data/app/components/shadcn/switch/component.rb +104 -0
  405. data/app/components/shadcn/switch/preview.rb +11 -0
  406. data/app/components/shadcn/switch/previews/default.html.erb +24 -0
  407. data/app/components/shadcn/table/component.rb +26 -0
  408. data/app/components/shadcn/table/preview.rb +16 -0
  409. data/app/components/shadcn/table/previews/default.html.erb +19 -0
  410. data/app/components/shadcn/table/previews/footer.html.erb +25 -0
  411. data/app/components/shadcn/table.rb +33 -0
  412. data/app/components/shadcn/tabs/component.rb +40 -0
  413. data/app/components/shadcn/tabs/content/component.rb +34 -0
  414. data/app/components/shadcn/tabs/list/component.rb +51 -0
  415. data/app/components/shadcn/tabs/preview.rb +16 -0
  416. data/app/components/shadcn/tabs/previews/default.html.erb +21 -0
  417. data/app/components/shadcn/tabs/previews/line.html.erb +23 -0
  418. data/app/components/shadcn/tabs/trigger/component.rb +66 -0
  419. data/app/components/shadcn/textarea/component.rb +24 -0
  420. data/app/components/shadcn/textarea/preview.rb +16 -0
  421. data/app/components/shadcn/textarea/previews/default.html.erb +3 -0
  422. data/app/components/shadcn/textarea/previews/states.html.erb +18 -0
  423. data/app/components/shadcn/theme_selector/component.rb +88 -0
  424. data/app/components/shadcn/theme_selector/preview.rb +17 -0
  425. data/app/components/shadcn/theme_selector/previews/all_themes.html.erb +20 -0
  426. data/app/components/shadcn/theme_selector/previews/default.html.erb +18 -0
  427. data/app/components/shadcn/toaster/component.rb +139 -0
  428. data/app/components/shadcn/toaster/preview.rb +16 -0
  429. data/app/components/shadcn/toaster/previews/default.html.erb +19 -0
  430. data/app/components/shadcn/toaster/previews/from_the_server.html.erb +15 -0
  431. data/app/components/shadcn/toaster/toast/component.rb +134 -0
  432. data/app/components/shadcn/toggle/component.rb +81 -0
  433. data/app/components/shadcn/toggle/preview.rb +11 -0
  434. data/app/components/shadcn/toggle/previews/default.html.erb +6 -0
  435. data/app/components/shadcn/toggle_group/component.rb +62 -0
  436. data/app/components/shadcn/toggle_group/item/component.rb +59 -0
  437. data/app/components/shadcn/toggle_group/preview.rb +16 -0
  438. data/app/components/shadcn/toggle_group/previews/default.html.erb +12 -0
  439. data/app/components/shadcn/toggle_group/previews/sizes.html.erb +37 -0
  440. data/app/components/shadcn/tooltip/component.rb +38 -0
  441. data/app/components/shadcn/tooltip/content/component.rb +62 -0
  442. data/app/components/shadcn/tooltip/preview.rb +21 -0
  443. data/app/components/shadcn/tooltip/previews/default.html.erb +4 -0
  444. data/app/components/shadcn/tooltip/previews/sides.html.erb +19 -0
  445. data/app/components/shadcn/tooltip/previews/with_keyboard_shortcut.html.erb +11 -0
  446. data/app/components/shadcn/tooltip/provider/component.rb +28 -0
  447. data/app/components/shadcn/tooltip/trigger/component.rb +25 -0
  448. data/app/helpers/shadcn_view_component/form_helper.rb +25 -0
  449. data/app/helpers/shadcn_view_component/theme_helper.rb +61 -0
  450. data/app/javascript/shadcn/animation.js +180 -0
  451. data/app/javascript/shadcn/command_score.js +110 -0
  452. data/app/javascript/shadcn/controllers/accordion_controller.js +127 -0
  453. data/app/javascript/shadcn/controllers/avatar_controller.js +32 -0
  454. data/app/javascript/shadcn/controllers/calendar_controller.js +633 -0
  455. data/app/javascript/shadcn/controllers/carousel_controller.js +139 -0
  456. data/app/javascript/shadcn/controllers/chart_controller.js +110 -0
  457. data/app/javascript/shadcn/controllers/checkbox_controller.js +61 -0
  458. data/app/javascript/shadcn/controllers/collapsible_controller.js +55 -0
  459. data/app/javascript/shadcn/controllers/combobox_controller.js +360 -0
  460. data/app/javascript/shadcn/controllers/command_controller.js +199 -0
  461. data/app/javascript/shadcn/controllers/dialog_controller.js +154 -0
  462. data/app/javascript/shadcn/controllers/drawer_controller.js +265 -0
  463. data/app/javascript/shadcn/controllers/dropdown_menu_controller.js +259 -0
  464. data/app/javascript/shadcn/controllers/hover_card_controller.js +85 -0
  465. data/app/javascript/shadcn/controllers/input_group_controller.js +17 -0
  466. data/app/javascript/shadcn/controllers/input_otp_controller.js +80 -0
  467. data/app/javascript/shadcn/controllers/menubar_controller.js +151 -0
  468. data/app/javascript/shadcn/controllers/message_scroller_controller.js +456 -0
  469. data/app/javascript/shadcn/controllers/navigation_menu_controller.js +211 -0
  470. data/app/javascript/shadcn/controllers/popover_controller.js +66 -0
  471. data/app/javascript/shadcn/controllers/radio_group_controller.js +69 -0
  472. data/app/javascript/shadcn/controllers/resizable_controller.js +167 -0
  473. data/app/javascript/shadcn/controllers/scroll_area_controller.js +253 -0
  474. data/app/javascript/shadcn/controllers/select_controller.js +320 -0
  475. data/app/javascript/shadcn/controllers/sidebar_controller.js +273 -0
  476. data/app/javascript/shadcn/controllers/slider_controller.js +230 -0
  477. data/app/javascript/shadcn/controllers/switch_controller.js +39 -0
  478. data/app/javascript/shadcn/controllers/tabs_controller.js +81 -0
  479. data/app/javascript/shadcn/controllers/theme_controller.js +67 -0
  480. data/app/javascript/shadcn/controllers/toaster_controller.js +281 -0
  481. data/app/javascript/shadcn/controllers/toggle_controller.js +24 -0
  482. data/app/javascript/shadcn/controllers/toggle_group_controller.js +73 -0
  483. data/app/javascript/shadcn/controllers/tooltip_controller.js +58 -0
  484. data/app/javascript/shadcn/direction.js +41 -0
  485. data/app/javascript/shadcn/dismiss.js +73 -0
  486. data/app/javascript/shadcn/floating.js +207 -0
  487. data/app/javascript/shadcn/focus.js +86 -0
  488. data/app/javascript/shadcn/id.js +14 -0
  489. data/app/javascript/shadcn/index.js +110 -0
  490. data/app/javascript/shadcn/popper.js +262 -0
  491. data/app/javascript/shadcn/scroll_geometry.js +267 -0
  492. data/app/javascript/shadcn/theme.js +161 -0
  493. data/app/javascript/shadcn/top_layer.js +59 -0
  494. data/app/javascript/shadcn/typeahead.js +99 -0
  495. data/config/importmap.rb +6 -0
  496. data/config/locales/en.yml +62 -0
  497. data/lib/generators/shadcn_view_component/install/install_generator.rb +149 -0
  498. data/lib/shadcn_view_component/engine.rb +73 -0
  499. data/lib/shadcn_view_component/form_builder.rb +264 -0
  500. data/lib/shadcn_view_component/icon_registry.rb +66 -0
  501. data/lib/shadcn_view_component/icons.rb +32 -0
  502. data/lib/shadcn_view_component/themes.rb +1065 -0
  503. data/lib/shadcn_view_component/version.rb +3 -0
  504. data/lib/shadcn_view_component.rb +82 -0
  505. data/lib/tasks/icons.rake +53 -0
  506. data/lib/tasks/themes.rake +171 -0
  507. metadata +608 -0
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Drawer
5
+ # Port of registry/new-york-v4/ui/drawer.tsx
6
+ #
7
+ # vaul's Drawer.Root wraps Radix's Dialog.Root, so the open/close half of
8
+ # this component *is* the dialog's and runs on `shadcn--dialog`: the focus
9
+ # trap, the scroll lock, Escape, the outside click and the exit animation
10
+ # are all already there and are not reimplemented. What vaul adds is the
11
+ # drag, and that is `shadcn--drawer`, on the content — the same arrangement
12
+ # the menubar has with the dropdown.
13
+ class Component < ApplicationViewComponent
14
+ include Concerns::ModalRoot
15
+
16
+ renders_one :trigger, "Shadcn::Drawer::Trigger::Component"
17
+ # `dialog_content` rather than `drawer_content`, which reads better here
18
+ # but would make this the one modal family out of four with its own name
19
+ # for the same slot — `ModalRoot` renders it, and Sheet and AlertDialog
20
+ # both call it that.
21
+ renders_one :dialog_content, "Shadcn::Drawer::Content::Component"
22
+
23
+ slot_name :drawer
24
+
25
+ # Two controllers on one element. `data-controller` is one of the
26
+ # attributes that *replaces* rather than concatenates, so the dialog's own
27
+ # string has to be repeated here rather than added to.
28
+ def element_attributes(**defaults)
29
+ super(**{ "data-controller" => "shadcn--dialog shadcn--drawer" }.merge(defaults))
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Drawer
5
+ module Content
6
+ # DrawerContent — renders its own overlay, as the TSX does, and the drag
7
+ # handle above the content.
8
+ #
9
+ # Unlike the Sheet, the four edges are *not* cva variants: upstream emits
10
+ # all four sets of classes at once and lets `data-vaul-drawer-direction`
11
+ # pick between them, so this element carries every one of them and the
12
+ # attribute does the choosing. That attribute name is vaul's, not ours —
13
+ # it is in the class strings this port has to reproduce byte for byte, so
14
+ # the markup has to speak it.
15
+ class Component < ApplicationViewComponent
16
+ DIRECTIONS = %i[top bottom left right].freeze
17
+
18
+ HANDLE_CLASSES = "mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full bg-muted " \
19
+ "group-data-[vaul-drawer-direction=bottom]/drawer-content:block"
20
+
21
+ renders_one :header, "Shadcn::Drawer::Header::Component"
22
+ renders_one :footer, "Shadcn::Drawer::Footer::Component"
23
+
24
+ slot_name :"drawer-content"
25
+
26
+ style do
27
+ base {
28
+ "group/drawer-content fixed z-50 flex h-auto flex-col bg-background " \
29
+ "data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 " \
30
+ "data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] " \
31
+ "data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b " \
32
+ "data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 " \
33
+ "data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] " \
34
+ "data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t " \
35
+ "data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 " \
36
+ "data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l " \
37
+ "data-[vaul-drawer-direction=right]:sm:max-w-sm " \
38
+ "data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 " \
39
+ "data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r " \
40
+ "data-[vaul-drawer-direction=left]:sm:max-w-sm"
41
+ }
42
+ end
43
+
44
+ attr_reader :direction
45
+
46
+ def initialize(direction: :bottom, **attributes)
47
+ @direction = DIRECTIONS.include?(direction&.to_sym) ? direction.to_sym : :bottom
48
+ super(**attributes)
49
+ end
50
+
51
+ def element_attributes(**defaults)
52
+ super(**{
53
+ role: "dialog",
54
+ "aria-modal" => "true",
55
+ tabindex: "-1",
56
+ "data-state" => "closed",
57
+ hidden: true,
58
+ "data-vaul-drawer" => "",
59
+ "data-vaul-drawer-direction" => direction,
60
+ # A constant, because this port has no snap points — and named
61
+ # rather than dropped because vaul's own selectors carry it, and the
62
+ # stylesheet reproduced in `shadcn.css` matches on it.
63
+ "data-vaul-snap-points" => "false",
64
+ "data-shadcn--dialog-target" => "content",
65
+ "data-shadcn--drawer-target" => "content",
66
+ "data-action" => "pointerdown->shadcn--drawer#press " \
67
+ "pointermove->shadcn--drawer#move " \
68
+ "pointerup->shadcn--drawer#release " \
69
+ "pointercancel->shadcn--drawer#release"
70
+ }.merge(defaults))
71
+ end
72
+
73
+ # shadcn wraps the overlay and the content in a DrawerPortal, which vaul
74
+ # relocates to `document.body`; here it stays put, as the dialog's does,
75
+ # and is `display: contents` so it adds no box of its own.
76
+ def call
77
+ tag.div("data-slot": "drawer-portal", style: CONTENTS_STYLE) do
78
+ safe_join([
79
+ render(Overlay::Component.new("data-vaul-overlay": "", "data-shadcn--drawer-target": "overlay")),
80
+ render_element(body: safe_join([ handle, header, content, footer ].compact))
81
+ ])
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ # Shown only when the drawer comes up from the bottom — the class does
88
+ # that, so it is rendered whatever the direction, exactly as upstream.
89
+ def handle
90
+ tag.div(class: HANDLE_CLASSES)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Drawer
5
+ module Header
6
+ # DrawerHeader — a slot for the title and the description, as the Sheet's
7
+ # and the Dialog's are.
8
+ #
9
+ # The two `group-data-*` classes read the direction off the *content*,
10
+ # which is why that attribute lives there rather than on the root shadcn
11
+ # takes it on: a header centres itself only when the drawer comes from an
12
+ # edge that makes it the top of the panel.
13
+ class Component < ApplicationViewComponent
14
+ renders_one :title, "Shadcn::Drawer::Title::Component"
15
+ renders_one :description, "Shadcn::Drawer::Description::Component"
16
+
17
+ slot_name :"drawer-header"
18
+
19
+ style do
20
+ base {
21
+ "flex flex-col gap-0.5 p-4 " \
22
+ "group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center " \
23
+ "group-data-[vaul-drawer-direction=top]/drawer-content:text-center " \
24
+ "md:gap-1.5 md:text-left"
25
+ }
26
+ end
27
+
28
+ def call
29
+ render_element(body: safe_join([ title, description, content ].compact))
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Drawer
5
+ class Preview < ApplicationViewComponentPreview
6
+ def default
7
+ render_with_template
8
+ end
9
+
10
+ # The other three edges, which the same class string serves — only the
11
+ # `data-vaul-drawer-direction` changes.
12
+ def sides
13
+ render_with_template
14
+ end
15
+
16
+ # A drawer taller than it can show, which is where the drag has to give
17
+ # way to the scroll.
18
+ def scrollable
19
+ render_with_template
20
+ end
21
+
22
+ # The same list, in a drawer that closes sideways — where the two gestures
23
+ # stop competing and the drag is let through whatever is scrolled.
24
+ def scrollable_side
25
+ render_with_template
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ <%# Upstream's own example: a bottom drawer with a header, a body and a footer.
2
+ The handle above the header is what says it can be dragged. %>
3
+ <%= render(Shadcn::Drawer::Component.new) do |d| %>
4
+ <% d.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { "Open drawer" } %>
5
+ <% d.with_dialog_content do |c| %>
6
+ <% c.with_header do |h| %>
7
+ <% h.with_title { "Move goal" } %>
8
+ <% h.with_description { "Set your daily activity goal." } %>
9
+ <% end %>
10
+ <div class="p-4 pb-0">
11
+ <p class="text-sm text-muted-foreground">
12
+ Drag this panel downwards, or throw it, and it closes. Drag it up and it
13
+ gives a little and comes back.
14
+ </p>
15
+ </div>
16
+ <% c.with_footer do %>
17
+ <%= render(Shadcn::Button::Component.new) { "Submit" } %>
18
+ <%= render(Shadcn::Drawer::Close::Component.new(class: Shadcn::Button::Component.variant_classes(variant: :outline))) { "Cancel" } %>
19
+ <% end %>
20
+ <% end %>
21
+ <% end %>
@@ -0,0 +1,20 @@
1
+ <%# The case the drag has to give way for: a list longer than the drawer. A
2
+ downward drag that starts part-way down the list scrolls it and must not
3
+ also throw the drawer away — which is what `shouldDrag` decides. %>
4
+ <%= render(Shadcn::Drawer::Component.new) do |d| %>
5
+ <% d.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { "Open a long drawer" } %>
6
+ <% d.with_dialog_content do |c| %>
7
+ <% c.with_header do |h| %>
8
+ <% h.with_title { "Recent activity" } %>
9
+ <% h.with_description { "Scroll the list; the drawer stays put." } %>
10
+ <% end %>
11
+ <div class="max-h-64 overflow-y-auto px-4">
12
+ <% 30.times do |i| %>
13
+ <div class="border-b py-3 text-sm last:border-b-0">Entry <%= i + 1 %></div>
14
+ <% end %>
15
+ </div>
16
+ <% c.with_footer do %>
17
+ <%= render(Shadcn::Drawer::Close::Component.new(class: Shadcn::Button::Component.variant_classes(variant: :outline))) { "Close" } %>
18
+ <% end %>
19
+ <% end %>
20
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <%# The same long list in a drawer that closes sideways. It is the case where
2
+ the two gestures stop competing: a vertical pull scrolls the list, and a
3
+ horizontal one can only mean the drawer, so `shouldDrag` lets it through
4
+ without asking what is scrolled. %>
5
+ <%= render(Shadcn::Drawer::Component.new) do |d| %>
6
+ <% d.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { "Open filters" } %>
7
+ <% d.with_dialog_content(direction: :right) do |c| %>
8
+ <% c.with_header do |h| %>
9
+ <% h.with_title { "Filters" } %>
10
+ <% h.with_description { "Scroll the list, or push the panel to the right." } %>
11
+ <% end %>
12
+ <div class="max-h-96 overflow-y-auto px-4">
13
+ <% 30.times do |i| %>
14
+ <div class="border-b py-3 text-sm last:border-b-0">Filter <%= i + 1 %></div>
15
+ <% end %>
16
+ </div>
17
+ <% c.with_footer do %>
18
+ <%= render(Shadcn::Drawer::Close::Component.new(class: Shadcn::Button::Component.variant_classes(variant: :outline))) { "Close" } %>
19
+ <% end %>
20
+ <% end %>
21
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <%# One class string serves all four edges; only the attribute changes. %>
2
+ <div class="flex items-center gap-2">
3
+ <% %i[bottom top left right].each do |direction| %>
4
+ <%= render(Shadcn::Drawer::Component.new) do |d| %>
5
+ <% d.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { direction.to_s.capitalize } %>
6
+ <% d.with_dialog_content(direction:) do |c| %>
7
+ <% c.with_header do |h| %>
8
+ <% h.with_title { "From the #{direction}" } %>
9
+ <% h.with_description { "Dragged towards that edge, it closes." } %>
10
+ <% end %>
11
+ <% c.with_footer do %>
12
+ <%= render(Shadcn::Drawer::Close::Component.new(class: Shadcn::Button::Component.variant_classes(variant: :outline))) { "Close" } %>
13
+ <% end %>
14
+ <% end %>
15
+ <% end %>
16
+ <% end %>
17
+ </div>
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ # The parts of the Drawer family that are just an element with a `data-slot`
5
+ # and a fixed set of classes. Anything with variants, slots or markup of its
6
+ # own keeps its own `component.rb`.
7
+ #
8
+ # Upstream builds this on **vaul**, not on Radix — but vaul is itself a Radix
9
+ # Dialog with a drag on top (`import * as DialogPrimitive from
10
+ # '@radix-ui/react-dialog'` is its third line), so the parts that are only
11
+ # markup come from the Dialog here for the same reason the Sheet's do.
12
+ module Drawer
13
+ extend Parts
14
+
15
+ part :close, slot: "drawer-close", from: Dialog::Close::Component
16
+
17
+ part :description, tag: :p, slot: "drawer-description", classes: "text-sm text-muted-foreground"
18
+
19
+ part :footer, slot: "drawer-footer", classes: "mt-auto flex flex-col gap-2 p-4"
20
+
21
+ part :overlay, slot: "drawer-overlay", from: Dialog::Overlay::Component
22
+
23
+ part :title, tag: :h2, slot: "drawer-title", classes: "font-semibold text-foreground"
24
+
25
+ part :trigger, slot: "drawer-trigger", from: Dialog::Trigger::Component
26
+ end
27
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module DropdownMenu
5
+ module CheckboxItem
6
+ # DropdownMenuCheckboxItem
7
+ class Component < ApplicationViewComponent
8
+ INDICATOR_CLASSES = "pointer-events-none absolute left-2 flex size-3.5 " \
9
+ "items-center justify-center"
10
+
11
+ slot_name :"dropdown-menu-checkbox-item"
12
+
13
+ style do
14
+ base {
15
+ "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 " \
16
+ "text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground " \
17
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50 " \
18
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
19
+ }
20
+ end
21
+
22
+ attr_reader :checked, :disabled
23
+
24
+ def initialize(checked: false, disabled: false, **attributes)
25
+ @checked = checked
26
+ @disabled = disabled
27
+ super(**attributes)
28
+ end
29
+
30
+ def element_attributes(**defaults)
31
+ super(**{
32
+ role: "menuitemcheckbox",
33
+ tabindex: "-1",
34
+ "aria-checked" => checked.to_s,
35
+ "data-state" => (checked ? "checked" : "unchecked"),
36
+ "data-disabled" => (true if disabled),
37
+ "data-shadcn--dropdown-menu-target" => "item",
38
+ "data-action" => "click->shadcn--dropdown-menu#select " \
39
+ "pointerenter->shadcn--dropdown-menu#pointerenter"
40
+ }.merge(defaults))
41
+ end
42
+
43
+ def call
44
+ render_element(body: safe_join([ indicator, content ]))
45
+ end
46
+
47
+ private
48
+
49
+ def indicator
50
+ tag.span(class: INDICATOR_CLASSES) do
51
+ tag.span(
52
+ render(Icon::Component.new("check", class: "size-4")),
53
+ "data-slot": "dropdown-menu-checkbox-item-indicator",
54
+ hidden: (true unless checked)
55
+ )
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module DropdownMenu
5
+ # Port of registry/new-york-v4/ui/dropdown-menu.tsx
6
+ class Component < ApplicationViewComponent
7
+ renders_one :trigger, "Shadcn::DropdownMenu::Trigger::Component"
8
+ renders_one :menu_content, "Shadcn::DropdownMenu::Content::Component"
9
+
10
+ slot_name :"dropdown-menu"
11
+
12
+ attr_reader :open, :side, :align, :side_offset, :align_offset, :loop
13
+
14
+ # `loop` is Radix's own prop, declared on MenuContentImpl and documented
15
+ # `@defaultValue false` (vendor/radix/ui/menu.tsx:363-368). It rides here
16
+ # rather than on Content for the same reason `side` and `align` do: one
17
+ # Stimulus controller owns the whole family, and the root is where it is
18
+ # attached.
19
+ def initialize(open: false, side: :bottom, align: :start, side_offset: 4,
20
+ align_offset: 0, loop: false, **attributes)
21
+ @open = open
22
+ @side = side&.to_sym || :bottom
23
+ @align = align&.to_sym || :start
24
+ @side_offset = side_offset
25
+ @align_offset = align_offset
26
+ @loop = loop
27
+ super(**attributes)
28
+ end
29
+
30
+ def element_attributes(**defaults)
31
+ super(**{
32
+ style: merged_style(CONTENTS_STYLE),
33
+ "data-controller" => "shadcn--dropdown-menu",
34
+ "data-shadcn--dropdown-menu-open-value" => open,
35
+ "data-shadcn--dropdown-menu-side-value" => side,
36
+ "data-shadcn--dropdown-menu-align-value" => align,
37
+ "data-shadcn--dropdown-menu-side-offset-value" => side_offset,
38
+ "data-shadcn--dropdown-menu-align-offset-value" => align_offset,
39
+ "data-shadcn--dropdown-menu-loop-value" => loop
40
+ }.merge(defaults))
41
+ end
42
+
43
+ def call
44
+ render_element(body: safe_join([ trigger, menu_content, content ].compact))
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module DropdownMenu
5
+ module Content
6
+ # DropdownMenuContent
7
+ class Component < ApplicationViewComponent
8
+ renders_many :items, "Shadcn::DropdownMenu::Item::Component"
9
+
10
+ slot_name :"dropdown-menu-content"
11
+
12
+ style do
13
+ base {
14
+ "z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] " \
15
+ "origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden " \
16
+ "overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground " \
17
+ "shadow-md data-[side=bottom]:slide-in-from-top-2 " \
18
+ "data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 " \
19
+ "data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out " \
20
+ "data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 " \
21
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 " \
22
+ "data-[state=open]:zoom-in-95"
23
+ }
24
+ end
25
+
26
+ def element_attributes(**defaults)
27
+ super(**{
28
+ role: "menu",
29
+ tabindex: "-1",
30
+ "aria-orientation" => "vertical",
31
+ "data-state" => "closed",
32
+ hidden: true,
33
+ "data-shadcn--dropdown-menu-target" => "content",
34
+ "data-action" => "keydown->shadcn--dropdown-menu#contentKeydown"
35
+ }.merge(defaults))
36
+ end
37
+
38
+ # shadcn wraps the content in a DropdownMenuPortal. Radix relocates it to
39
+ # `document.body`; here it stays put (see the Stimulus controller for
40
+ # why) and is `display: contents`, so it adds no box of its own.
41
+ def call
42
+ tag.div("data-slot": "dropdown-menu-portal", style: CONTENTS_STYLE) do
43
+ render_element(body: safe_join([ items, content ].flatten.compact))
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module DropdownMenu
5
+ module Group
6
+ # DropdownMenuGroup
7
+ class Component < ApplicationViewComponent
8
+ slot_name :"dropdown-menu-group"
9
+
10
+ def element_attributes(**defaults)
11
+ super(**{ role: "group" }.merge(defaults))
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module DropdownMenu
5
+ module Item
6
+ # DropdownMenuItem
7
+ class Component < ApplicationViewComponent
8
+ slot_name :"dropdown-menu-item"
9
+
10
+ style do
11
+ base {
12
+ "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm " \
13
+ "outline-hidden select-none focus:bg-accent focus:text-accent-foreground " \
14
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50 " \
15
+ "data-[inset]:pl-8 data-[variant=destructive]:text-destructive " \
16
+ "data-[variant=destructive]:focus:bg-destructive/10 " \
17
+ "data-[variant=destructive]:focus:text-destructive " \
18
+ "dark:data-[variant=destructive]:focus:bg-destructive/20 " \
19
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0 " \
20
+ "[&_svg:not([class*='size-'])]:size-4 " \
21
+ "[&_svg:not([class*='text-'])]:text-muted-foreground " \
22
+ "data-[variant=destructive]:*:[svg]:text-destructive!"
23
+ }
24
+ end
25
+
26
+ attr_reader :variant, :inset, :disabled
27
+
28
+ def initialize(variant: :default, inset: false, disabled: false, **attributes)
29
+ @variant = variant&.to_sym || :default
30
+ @inset = inset
31
+ @disabled = disabled
32
+ super(**attributes)
33
+ end
34
+
35
+ def element_attributes(**defaults)
36
+ super(**{
37
+ role: "menuitem",
38
+ tabindex: "-1",
39
+ "data-variant" => variant,
40
+ "data-inset" => (true if inset),
41
+ "data-disabled" => (true if disabled),
42
+ "data-shadcn--dropdown-menu-target" => "item",
43
+ "data-action" => "click->shadcn--dropdown-menu#select " \
44
+ "pointerenter->shadcn--dropdown-menu#pointerenter"
45
+ }.merge(defaults))
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module DropdownMenu
5
+ class Preview < ApplicationViewComponentPreview
6
+ def default
7
+ render_with_template
8
+ end
9
+
10
+ # Upstream's "Checkboxes", "Radio Group" and "Destructive".
11
+ def checkboxes_and_radio
12
+ render_with_template
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,34 @@
1
+ <%# Upstream's "Checkboxes", "Radio Group" and "Destructive", none of which the
2
+ default preview shows: it has the label, the items, the separators and the
3
+ shortcuts, and stops there.
4
+
5
+ A checkbox item keeps the menu open when chosen and a radio item replaces
6
+ whichever of its group was set — both are the menu's own behaviour rather
7
+ than markup, and both are the dropdown controller's. %>
8
+ <div class="flex items-center gap-2">
9
+ <%= render(Shadcn::DropdownMenu::Component.new) do |m| %>
10
+ <% m.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { "View" } %>
11
+ <% m.with_menu_content(class: "w-56") do %>
12
+ <%= render(Shadcn::DropdownMenu::Label::Component.new) { "Appearance" } %>
13
+ <%= render(Shadcn::DropdownMenu::Separator::Component.new) %>
14
+ <%= render(Shadcn::DropdownMenu::CheckboxItem::Component.new(checked: true)) { "Status bar" } %>
15
+ <%= render(Shadcn::DropdownMenu::CheckboxItem::Component.new) { "Activity bar" } %>
16
+ <%= render(Shadcn::DropdownMenu::CheckboxItem::Component.new(disabled: true)) { "Panel — not available" } %>
17
+ <% end %>
18
+ <% end %>
19
+
20
+ <%= render(Shadcn::DropdownMenu::Component.new) do |m| %>
21
+ <% m.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { "Panel position" } %>
22
+ <% m.with_menu_content(class: "w-56") do %>
23
+ <%= render(Shadcn::DropdownMenu::Label::Component.new) { "Position" } %>
24
+ <%= render(Shadcn::DropdownMenu::Separator::Component.new) %>
25
+ <%= render(Shadcn::DropdownMenu::RadioGroup::Component.new) do %>
26
+ <% %w[Top Bottom Right].each do |side| %>
27
+ <%= render(Shadcn::DropdownMenu::RadioItem::Component.new(value: side.downcase, checked: side == "Bottom")) { side } %>
28
+ <% end %>
29
+ <% end %>
30
+ <%= render(Shadcn::DropdownMenu::Separator::Component.new) %>
31
+ <%= render(Shadcn::DropdownMenu::Item::Component.new(variant: :destructive)) { "Reset layout" } %>
32
+ <% end %>
33
+ <% end %>
34
+ </div>
@@ -0,0 +1,23 @@
1
+ <%= render(Shadcn::DropdownMenu::Component.new) do |m| %>
2
+ <% m.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { "Open menu" } %>
3
+ <%# Items go in the block rather than through the `item` slot, so the label
4
+ and separators keep their place between them. %>
5
+ <% m.with_menu_content(class: "w-56") do %>
6
+ <%= render(Shadcn::DropdownMenu::Label::Component.new) { "My Account" } %>
7
+ <%= render(Shadcn::DropdownMenu::Separator::Component.new) %>
8
+ <%= render(Shadcn::DropdownMenu::Group::Component.new) do %>
9
+ <%= render(Shadcn::DropdownMenu::Item::Component.new) do %>
10
+ Profile
11
+ <%= render(Shadcn::DropdownMenu::Shortcut::Component.new) { "⌘P" } %>
12
+ <% end %>
13
+ <%= render(Shadcn::DropdownMenu::Item::Component.new) { "Billing" } %>
14
+ <%# "Settings" and "Support" share an initial on purpose: without two
15
+ entries starting with the same letter, a browser spec cannot tell
16
+ typeahead's repeat-cycling from always landing on the first match. %>
17
+ <%= render(Shadcn::DropdownMenu::Item::Component.new) { "Settings" } %>
18
+ <%= render(Shadcn::DropdownMenu::Item::Component.new) { "Support" } %>
19
+ <% end %>
20
+ <%= render(Shadcn::DropdownMenu::Separator::Component.new) %>
21
+ <%= render(Shadcn::DropdownMenu::Item::Component.new(variant: :destructive)) { "Log out" } %>
22
+ <% end %>
23
+ <% end %>
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module DropdownMenu
5
+ module RadioGroup
6
+ # DropdownMenuRadioGroup
7
+ class Component < ApplicationViewComponent
8
+ slot_name :"dropdown-menu-radio-group"
9
+
10
+ def element_attributes(**defaults)
11
+ super(**{ role: "group" }.merge(defaults))
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end