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,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module ContextMenu
5
+ module Content
6
+ # The panel. Its own class string rather than the dropdown's, for one
7
+ # reason worth stating: the two differ only in which `--radix-*` custom
8
+ # properties they read, and those are the properties `popper.js` writes
9
+ # under the controller's `prefix`. Sharing the string would leave the
10
+ # menu reading variables nothing sets.
11
+ class Component < ApplicationViewComponent
12
+ slot_name :"context-menu-content"
13
+
14
+ style do
15
+ base {
16
+ "z-50 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] " \
17
+ "origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden " \
18
+ "overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground " \
19
+ "shadow-md data-[side=bottom]:slide-in-from-top-2 " \
20
+ "data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 " \
21
+ "data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out " \
22
+ "data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 " \
23
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 " \
24
+ "data-[state=open]:zoom-in-95"
25
+ }
26
+ end
27
+
28
+ def element_attributes(**defaults)
29
+ super(**{
30
+ role: "menu",
31
+ hidden: true,
32
+ "data-state" => "closed",
33
+ "data-shadcn--dropdown-menu-target" => "content",
34
+ "data-action" => "keydown->shadcn--dropdown-menu#contentKeydown"
35
+ }.merge(defaults))
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module ContextMenu
5
+ class Preview < ApplicationViewComponentPreview
6
+ def default
7
+ render_with_template
8
+ end
9
+
10
+ # Upstream's "Radio", "Destructive", "Icons" and "Groups".
11
+ def items
12
+ render_with_template
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,34 @@
1
+ <%# Right-click the dashed area. The trigger has no classes of its own upstream
2
+ — it is a region rather than a control — so the border here is the caller's,
3
+ which is the only way to see where the region is.
4
+
5
+ Everything below the trigger is the dropdown menu's, restamped: same items,
6
+ same submenu, same checkbox and radio behaviour, same controller. %>
7
+ <div class="flex h-72 items-start justify-center pt-6">
8
+ <%= render(Shadcn::ContextMenu::Component.new) do |menu| %>
9
+ <% menu.with_trigger(class: "flex h-40 w-72 items-center justify-center rounded-md border border-dashed text-sm") do %>
10
+ Right-click here
11
+ <% end %>
12
+ <% menu.with_menu_content(class: "w-52") do %>
13
+ <%= render(Shadcn::ContextMenu::Item::Component.new) do %>
14
+ Back
15
+ <%= render(Shadcn::ContextMenu::Shortcut::Component.new) { "⌘[" } %>
16
+ <% end %>
17
+ <%= render(Shadcn::ContextMenu::Item::Component.new(disabled: true)) do %>
18
+ Forward
19
+ <%= render(Shadcn::ContextMenu::Shortcut::Component.new) { "⌘]" } %>
20
+ <% end %>
21
+ <%= render(Shadcn::ContextMenu::Separator::Component.new) %>
22
+ <%= render(Shadcn::ContextMenu::Sub::Component.new) do |sub| %>
23
+ <% sub.with_trigger { "More tools" } %>
24
+ <% sub.with_menu_content do %>
25
+ <%= render(Shadcn::ContextMenu::Item::Component.new) { "Save page" } %>
26
+ <%= render(Shadcn::ContextMenu::Item::Component.new) { "Create shortcut" } %>
27
+ <% end %>
28
+ <% end %>
29
+ <%= render(Shadcn::ContextMenu::Separator::Component.new) %>
30
+ <%= render(Shadcn::ContextMenu::CheckboxItem::Component.new(checked: true)) { "Show bookmarks" } %>
31
+ <%= render(Shadcn::ContextMenu::CheckboxItem::Component.new) { "Show full URLs" } %>
32
+ <% end %>
33
+ <% end %>
34
+ </div>
@@ -0,0 +1,35 @@
1
+ <%# Upstream's "Radio", "Destructive", "Icons" and "Groups": the four kinds of
2
+ item the default preview leaves out, which has the plain items, a submenu,
3
+ the shortcuts and the checkboxes.
4
+
5
+ All four are the dropdown's — this family declares no controller of its own
6
+ — so what is worth seeing here is that a right-click reaches them at all. %>
7
+ <%= render(Shadcn::ContextMenu::Component.new) do |menu| %>
8
+ <% menu.with_trigger(class: "flex h-40 items-center justify-center rounded-md border border-dashed text-sm text-muted-foreground") do %>
9
+ Right-click here
10
+ <% end %>
11
+ <% menu.with_menu_content(class: "w-52") do %>
12
+ <%= render(Shadcn::ContextMenu::Group::Component.new) do %>
13
+ <%= render(Shadcn::ContextMenu::Label::Component.new) { "Sort by" } %>
14
+ <%= render(Shadcn::ContextMenu::RadioGroup::Component.new) do %>
15
+ <% %w[Name Size Modified].each do |option| %>
16
+ <%= render(Shadcn::ContextMenu::RadioItem::Component.new(value: option.downcase, checked: option == "Name")) { option } %>
17
+ <% end %>
18
+ <% end %>
19
+ <% end %>
20
+ <%= render(Shadcn::ContextMenu::Separator::Component.new) %>
21
+ <%= render(Shadcn::ContextMenu::Item::Component.new) do %>
22
+ <%= render(Shadcn::Icon::Component.new("search")) %>
23
+ Find in folder
24
+ <% end %>
25
+ <%= render(Shadcn::ContextMenu::Item::Component.new) do %>
26
+ <%= render(Shadcn::Icon::Component.new("check")) %>
27
+ Select all
28
+ <% end %>
29
+ <%= render(Shadcn::ContextMenu::Separator::Component.new) %>
30
+ <%= render(Shadcn::ContextMenu::Item::Component.new(variant: :destructive)) do %>
31
+ <%= render(Shadcn::Icon::Component.new("x")) %>
32
+ Move to bin
33
+ <% end %>
34
+ <% end %>
35
+ <% end %>
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module ContextMenu
5
+ module Sub
6
+ # A nested menu. Written out rather than subclassed: ViewComponent refuses
7
+ # to redeclare an inherited slot, and this one has to hold *this* family's
8
+ # sub-content — which differs from the dropdown's in the only way that
9
+ # matters here, the `--radix-*` properties it reads.
10
+ #
11
+ # Another `shadcn--dropdown-menu` controller, carrying the prefix so
12
+ # `popper.js` writes the properties that content looks for.
13
+ class Component < ApplicationViewComponent
14
+ renders_one :trigger, "Shadcn::ContextMenu::SubTrigger::Component"
15
+ renders_one :menu_content, "Shadcn::ContextMenu::SubContent::Component"
16
+
17
+ slot_name :"context-menu-sub"
18
+
19
+ attr_reader :open, :side, :align, :side_offset
20
+
21
+ def initialize(open: false, side: :right, align: :start, side_offset: 0, **attributes)
22
+ @open = open
23
+ @side = side&.to_sym || :right
24
+ @align = align&.to_sym || :start
25
+ @side_offset = side_offset
26
+ super(**attributes)
27
+ end
28
+
29
+ def element_attributes(**defaults)
30
+ super(**{
31
+ style: merged_style(CONTENTS_STYLE),
32
+ "data-controller" => "shadcn--dropdown-menu",
33
+ "data-shadcn--dropdown-menu-prefix-value" => "context-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
+ }.merge(defaults))
39
+ end
40
+
41
+ def call
42
+ render_element(body: safe_join([ trigger, menu_content, content ].compact))
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module ContextMenu
5
+ module SubContent
6
+ # Its own class string rather than the dropdown's, and the reason is the
7
+ # one thing `parity_spec` cannot see: the two differ only in which
8
+ # `--radix-*` custom properties they read, and those are what `popper.js`
9
+ # writes under the controller's prefix. Inheriting the dropdown's would
10
+ # leave a context submenu reading variables nothing sets — and parity
11
+ # would still pass, because it asks whether a token appears anywhere in
12
+ # the family, not whether it appears on the right element.
13
+ class Component < Shadcn::DropdownMenu::SubContent::Component
14
+ slot_name :"context-menu-sub-content"
15
+
16
+ style do
17
+ base {
18
+ "z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) " \
19
+ "overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground " \
20
+ "shadow-lg data-[side=bottom]:slide-in-from-top-2 " \
21
+ "data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 " \
22
+ "data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out " \
23
+ "data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 " \
24
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 " \
25
+ "data-[state=open]:zoom-in-95"
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module ContextMenu
5
+ module Trigger
6
+ # The area you right-click. Upstream gives it no classes at all
7
+ # (context-menu.tsx:19) — it is a region, not a control, and what it looks
8
+ # like is the caller's business.
9
+ #
10
+ # A `<span>`, which is Radix's (`Primitive.span`, context-menu.tsx:151) and
11
+ # not a detail: a `<div>` would be block where this is inline, so the same
12
+ # markup would lay out differently. Measured on the live demo before it
13
+ # was believed.
14
+ #
15
+ # `-webkit-touch-callout: none` is Radix's too, and is the only reason a
16
+ # long press on iOS does not raise the system menu over this one.
17
+ #
18
+ # No `aria-haspopup` and no `role`: there is no keyboard route to a
19
+ # context menu, and claiming one would promise something that does not
20
+ # exist. Radix does not add either.
21
+ class Component < ApplicationViewComponent
22
+ default_tag :span
23
+ slot_name :"context-menu-trigger"
24
+
25
+ attr_reader :disabled
26
+
27
+ def initialize(disabled: false, **attributes)
28
+ @disabled = disabled
29
+ super(**attributes)
30
+ end
31
+
32
+ def element_attributes(**defaults)
33
+ attributes = {
34
+ style: merged_style("-webkit-touch-callout: none;"),
35
+ "data-state" => "closed",
36
+ "data-disabled" => (disabled.presence && ""),
37
+ "data-shadcn--dropdown-menu-target" => "trigger"
38
+ }.compact
39
+
40
+ # A disabled trigger hands the gesture back to the browser rather than
41
+ # swallowing it, which is Radix's own choice (`:158-161`): a region
42
+ # that does nothing should not also take away the menu you expected.
43
+ attributes["data-action"] = "contextmenu->shadcn--dropdown-menu#openAtPointer" unless disabled
44
+
45
+ super(**attributes.merge(defaults))
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ # The ContextMenu family.
5
+ #
6
+ # Measured against `dropdown-menu.tsx`: the two files declare the same fifteen
7
+ # slots, and eleven of them carry byte-identical class strings once the
8
+ # prefix is normalised. So most of this family *is* the dropdown's, restamped
9
+ # — the same relationship `Sheet` has with `Dialog` here, and the reason both
10
+ # are driven by one controller rather than two.
11
+ #
12
+ # The four that differ: `label` gains `text-foreground`; `content` reads
13
+ # `--radix-context-menu-*` rather than `--radix-dropdown-menu-*`; `sub-trigger`
14
+ # spells the chevron's size through its own `[&_svg…]:size-4` instead of on
15
+ # the icon; and `trigger` is the area you right-click rather than a button.
16
+ module ContextMenu
17
+ extend Parts
18
+
19
+ part :label, slot: "context-menu-label",
20
+ classes: "px-2 py-1.5 text-sm font-medium text-foreground data-[inset]:pl-8"
21
+
22
+ part :separator, slot: "context-menu-separator", classes: "-mx-1 my-1 h-px bg-border"
23
+
24
+ part :shortcut, tag: :span, slot: "context-menu-shortcut",
25
+ classes: "ml-auto text-xs tracking-widest text-muted-foreground"
26
+
27
+ part :group, slot: "context-menu-group", from: DropdownMenu::Group::Component
28
+
29
+ part :radio_group, slot: "context-menu-radio-group",
30
+ from: DropdownMenu::RadioGroup::Component
31
+
32
+ part :item, slot: "context-menu-item", from: DropdownMenu::Item::Component
33
+
34
+ part :checkbox_item, slot: "context-menu-checkbox-item",
35
+ from: DropdownMenu::CheckboxItem::Component
36
+
37
+ part :radio_item, slot: "context-menu-radio-item",
38
+ from: DropdownMenu::RadioItem::Component
39
+
40
+ part :sub_trigger, slot: "context-menu-sub-trigger",
41
+ from: DropdownMenu::SubTrigger::Component
42
+ end
43
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Dialog
5
+ module Close
6
+ # DialogClose
7
+ class Component < ApplicationViewComponent
8
+ default_tag :button
9
+ slot_name :"dialog-close"
10
+
11
+ def element_attributes(**defaults)
12
+ super(**{
13
+ type: "button",
14
+ "data-action" => "shadcn--dialog#close"
15
+ }.merge(defaults))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Dialog
5
+ # Port of registry/new-york-v4/ui/dialog.tsx
6
+ #
7
+ # Radix's Dialog.Root is a context provider and renders no DOM. Stimulus
8
+ # needs an element to attach to, so the root is a `display: contents`
9
+ # wrapper — invisible to layout, and it gives shadcn's `data-slot="dialog"`
10
+ # somewhere to live.
11
+ class Component < ApplicationViewComponent
12
+ include Concerns::ModalRoot
13
+
14
+ renders_one :trigger, "Shadcn::Dialog::Trigger::Component"
15
+ renders_one :dialog_content, "Shadcn::Dialog::Content::Component"
16
+
17
+ slot_name :dialog
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Dialog
5
+ module Content
6
+ # DialogContent — renders its own overlay, as the TSX does, and the
7
+ # dismiss button in the corner unless asked not to.
8
+ class Component < ApplicationViewComponent
9
+ CLOSE_CLASSES = "absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background " \
10
+ "transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring " \
11
+ "focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none " \
12
+ "data-[state=open]:bg-accent data-[state=open]:text-muted-foreground " \
13
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0 " \
14
+ "[&_svg:not([class*='size-'])]:size-4"
15
+
16
+ renders_one :header, "Shadcn::Dialog::Header::Component"
17
+ renders_one :footer, "Shadcn::Dialog::Footer::Component"
18
+
19
+ slot_name :"dialog-content"
20
+
21
+ style do
22
+ base {
23
+ "fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] " \
24
+ "translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 " \
25
+ "shadow-lg duration-200 outline-none data-[state=closed]:animate-out " \
26
+ "data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 " \
27
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 " \
28
+ "data-[state=open]:zoom-in-95 sm:max-w-lg"
29
+ }
30
+ end
31
+
32
+ attr_reader :show_close_button
33
+
34
+ def initialize(show_close_button: true, **attributes)
35
+ @show_close_button = show_close_button
36
+ super(**attributes)
37
+ end
38
+
39
+ def element_attributes(**defaults)
40
+ super(**{
41
+ role: "dialog",
42
+ "aria-modal" => "true",
43
+ tabindex: "-1",
44
+ "data-state" => "closed",
45
+ hidden: true,
46
+ "data-shadcn--dialog-target" => "content"
47
+ }.merge(defaults))
48
+ end
49
+
50
+ # shadcn wraps the overlay and the content in a DialogPortal. Radix
51
+ # relocates that element to `document.body`; here it stays put (see
52
+ # the `shadcn--dialog` controller for why) and is `display: contents`,
53
+ # so it adds no box of its own.
54
+ def call
55
+ tag.div("data-slot": "dialog-portal", style: CONTENTS_STYLE) do
56
+ safe_join([
57
+ render(Overlay::Component.new),
58
+ render_element(body: safe_join([ header, content, footer, close_button ].compact))
59
+ ])
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def close_button
66
+ return unless show_close_button
67
+
68
+ render(Close::Component.new(class: CLOSE_CLASSES)) do
69
+ safe_join([
70
+ render(Icon::Component.new("x")),
71
+ tag.span(shadcn_t("dialog.close"), class: "sr-only")
72
+ ])
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Dialog
5
+ module Header
6
+ # DialogHeader
7
+ class Component < ApplicationViewComponent
8
+ renders_one :title, "Shadcn::Dialog::Title::Component"
9
+ renders_one :description, "Shadcn::Dialog::Description::Component"
10
+
11
+ slot_name :"dialog-header"
12
+
13
+ style do
14
+ base { "flex flex-col gap-2 text-center sm:text-left" }
15
+ end
16
+
17
+ def call
18
+ render_element(body: safe_join([ title, description, content ].compact))
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Dialog
5
+ module Overlay
6
+ # DialogOverlay
7
+ class Component < ApplicationViewComponent
8
+ slot_name :"dialog-overlay"
9
+
10
+ style do
11
+ base {
12
+ "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out " \
13
+ "data-[state=closed]:fade-out-0 data-[state=open]:animate-in " \
14
+ "data-[state=open]:fade-in-0"
15
+ }
16
+ end
17
+
18
+ def element_attributes(**defaults)
19
+ super(**{
20
+ "data-state" => "closed",
21
+ hidden: true,
22
+ "data-shadcn--dialog-target" => "overlay"
23
+ }.merge(defaults))
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Dialog
5
+ class Preview < ApplicationViewComponentPreview
6
+ def default
7
+ render_with_template
8
+ end
9
+
10
+ # The case the layering has to survive: a modal opened from inside an
11
+ # ancestor that creates a stacking context.
12
+ def inside_stacking_context
13
+ render_with_template
14
+ end
15
+
16
+ # Upstream's "No Close Button": the corner dismiss left out.
17
+ def no_close_button
18
+ render_with_template
19
+ end
20
+
21
+ # Upstream's "Scrollable Content": a body that scrolls under a header and
22
+ # footer that do not.
23
+ def scrollable_content
24
+ render_with_template
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ <%= render(Shadcn::Dialog::Component.new) do |d| %>
2
+ <% d.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { "Edit profile" } %>
3
+ <% d.with_dialog_content do |c| %>
4
+ <% c.with_header do |h| %>
5
+ <% h.with_title { "Edit profile" } %>
6
+ <% h.with_description { "Make changes to your profile here. Click save when you are done." } %>
7
+ <% end %>
8
+ <div class="flex flex-col gap-4">
9
+ <%= render(Shadcn::Label::Component.new(for: "dlg-name")) { "Name" } %>
10
+ <%= render(Shadcn::Input::Component.new(id: "dlg-name", value: "Pedro Duarte")) %>
11
+ </div>
12
+ <% c.with_footer do %>
13
+ <%= render(Shadcn::Dialog::Close::Component.new(class: Shadcn::Button::Component.variant_classes(variant: :outline))) { "Cancel" } %>
14
+ <%= render(Shadcn::Button::Component.new) { "Save changes" } %>
15
+ <% end %>
16
+ <% end %>
17
+ <% end %>
@@ -0,0 +1,25 @@
1
+ <%# A modal opened from inside a stacking context — a "Delete" button in a
2
+ sticky toolbar, say. The overlay and the content are separate fixed
3
+ elements, so both have to reach the top layer, and in that order. %>
4
+
5
+ <div class="relative z-10 flex items-center gap-3 rounded-lg border bg-card p-4"
6
+ data-testid="stacking-header">
7
+ <span class="text-sm text-muted-foreground">A toolbar at z-10</span>
8
+
9
+ <%= render(Shadcn::Dialog::Component.new) do |dialog| %>
10
+ <% dialog.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) do %>
11
+ Open dialog
12
+ <% end %>
13
+ <% dialog.with_dialog_content do |content| %>
14
+ <% content.with_header do |header| %>
15
+ <% header.with_title { "Am I on top?" } %>
16
+ <% header.with_description { "If the panel below covers this, the modal lost to a stacking context." } %>
17
+ <% end %>
18
+ <% end %>
19
+ <% end %>
20
+ </div>
21
+
22
+ <div class="relative z-20 mt-2 h-96 rounded-lg border bg-muted p-4"
23
+ data-testid="stacking-sibling">
24
+ <span class="text-sm font-medium">A sibling at z-20</span>
25
+ </div>
@@ -0,0 +1,15 @@
1
+ <%# Upstream's "No Close Button": the corner dismiss is left out, so the only
2
+ ways out are the footer, Escape and a click outside. %>
3
+ <%= render(Shadcn::Dialog::Component.new) do |d| %>
4
+ <% d.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { "Open" } %>
5
+ <% d.with_dialog_content(show_close_button: false) do |c| %>
6
+ <% c.with_header do |h| %>
7
+ <% h.with_title { "Terms of service" } %>
8
+ <% h.with_description { "You have to answer before this closes from inside." } %>
9
+ <% end %>
10
+ <% c.with_footer do %>
11
+ <%= render(Shadcn::Dialog::Close::Component.new(class: Shadcn::Button::Component.variant_classes(variant: :outline))) { "Decline" } %>
12
+ <%= render(Shadcn::Button::Component.new) { "Accept" } %>
13
+ <% end %>
14
+ <% end %>
15
+ <% end %>
@@ -0,0 +1,29 @@
1
+ <%# Upstream's "Scrollable Content": the body scrolls and the header and footer
2
+ stay put, which is what a dialog taller than the viewport has to do.
3
+
4
+ Two classes carry it, and the first version of this preview had neither, so
5
+ the panel simply grew past its own `max-h` and pushed its footer off the
6
+ screen. The content is a grid, so the rows have to be told which one gives —
7
+ `grid-rows-[auto_1fr_auto]` — and a grid item's `min-height` is `auto`,
8
+ which means it refuses to shrink below its content until `min-h-0` says it
9
+ may. Neither is upstream's markup: they are what a caller has to add, and
10
+ that is what this preview is for. %>
11
+ <%= render(Shadcn::Dialog::Component.new) do |d| %>
12
+ <% d.with_trigger(class: Shadcn::Button::Component.variant_classes(variant: :outline)) { "Open a long dialog" } %>
13
+ <% d.with_dialog_content(class: "grid max-h-[80vh] grid-rows-[auto_1fr_auto] gap-0 p-0") do |c| %>
14
+ <% c.with_header(class: "border-b p-6") do |h| %>
15
+ <% h.with_title { "Release notes" } %>
16
+ <% h.with_description { "Everything that changed in this version." } %>
17
+ <% end %>
18
+ <div class="min-h-0 overflow-y-auto px-6 py-4">
19
+ <% 20.times do |i| %>
20
+ <p class="border-b py-3 text-sm text-muted-foreground last:border-b-0">
21
+ Change <%= i + 1 %> — a line long enough to make the body worth scrolling.
22
+ </p>
23
+ <% end %>
24
+ </div>
25
+ <% c.with_footer(class: "border-t p-6") do %>
26
+ <%= render(Shadcn::Dialog::Close::Component.new(class: Shadcn::Button::Component.variant_classes(variant: :outline))) { "Close" } %>
27
+ <% end %>
28
+ <% end %>
29
+ <% end %>
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ module Dialog
5
+ module Trigger
6
+ # DialogTrigger
7
+ class Component < ApplicationViewComponent
8
+ default_tag :button
9
+ slot_name :"dialog-trigger"
10
+
11
+ def element_attributes(**defaults)
12
+ super(**{
13
+ type: "button",
14
+ "aria-haspopup" => "dialog",
15
+ "aria-expanded" => "false",
16
+ "data-state" => "closed",
17
+ "data-shadcn--dialog-target" => "trigger",
18
+ "data-action" => "shadcn--dialog#open"
19
+ }.merge(defaults))
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shadcn
4
+ # The parts of the Dialog family that are just an element with a
5
+ # `data-slot` and a fixed set of classes. Anything with variants, slots or
6
+ # markup of its own keeps its own `component.rb`.
7
+ module Dialog
8
+ extend Parts
9
+
10
+ part :description, tag: :p, slot: "dialog-description", classes: "text-sm text-muted-foreground"
11
+
12
+ part :footer, slot: "dialog-footer",
13
+ classes: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"
14
+
15
+ part :title, tag: :h2, slot: "dialog-title", classes: "text-lg leading-none font-semibold"
16
+ end
17
+ end