poetry-ui 0.0.2

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 (442) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +6 -0
  3. data/CHANGELOG.md +3 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +87 -0
  6. data/THIRD_PARTY_NOTICES.md +201 -0
  7. data/app/components/poetry/ui/accordion/component.html.erb +3 -0
  8. data/app/components/poetry/ui/accordion/component.rb +197 -0
  9. data/app/components/poetry/ui/accordion/preview.rb +39 -0
  10. data/app/components/poetry/ui/accordion/style.rb +37 -0
  11. data/app/components/poetry/ui/alert/component.html.erb +6 -0
  12. data/app/components/poetry/ui/alert/component.rb +61 -0
  13. data/app/components/poetry/ui/alert/preview.rb +35 -0
  14. data/app/components/poetry/ui/alert/style.rb +24 -0
  15. data/app/components/poetry/ui/alert_dialog/component.html.erb +17 -0
  16. data/app/components/poetry/ui/alert_dialog/component.rb +208 -0
  17. data/app/components/poetry/ui/alert_dialog/preview.rb +48 -0
  18. data/app/components/poetry/ui/alert_dialog/style.rb +46 -0
  19. data/app/components/poetry/ui/aspect_ratio/component.rb +63 -0
  20. data/app/components/poetry/ui/aspect_ratio/preview.rb +29 -0
  21. data/app/components/poetry/ui/aspect_ratio/style.rb +13 -0
  22. data/app/components/poetry/ui/attachment/component.html.erb +13 -0
  23. data/app/components/poetry/ui/attachment/component.rb +139 -0
  24. data/app/components/poetry/ui/attachment/preview.rb +83 -0
  25. data/app/components/poetry/ui/attachment/style.rb +59 -0
  26. data/app/components/poetry/ui/autocomplete/component.html.erb +16 -0
  27. data/app/components/poetry/ui/autocomplete/component.rb +193 -0
  28. data/app/components/poetry/ui/autocomplete/preview.rb +39 -0
  29. data/app/components/poetry/ui/autocomplete/style.rb +18 -0
  30. data/app/components/poetry/ui/avatar/component.rb +103 -0
  31. data/app/components/poetry/ui/avatar/group_preview.html.erb +11 -0
  32. data/app/components/poetry/ui/avatar/preview.rb +50 -0
  33. data/app/components/poetry/ui/avatar/style.rb +34 -0
  34. data/app/components/poetry/ui/badge/component.rb +73 -0
  35. data/app/components/poetry/ui/badge/preview.rb +54 -0
  36. data/app/components/poetry/ui/badge/style.rb +35 -0
  37. data/app/components/poetry/ui/breadcrumb/component.html.erb +32 -0
  38. data/app/components/poetry/ui/breadcrumb/component.rb +102 -0
  39. data/app/components/poetry/ui/breadcrumb/dropdown_crumb_preview.html.erb +21 -0
  40. data/app/components/poetry/ui/breadcrumb/preview.rb +45 -0
  41. data/app/components/poetry/ui/breadcrumb/style.rb +25 -0
  42. data/app/components/poetry/ui/bubble/component.html.erb +4 -0
  43. data/app/components/poetry/ui/bubble/component.rb +106 -0
  44. data/app/components/poetry/ui/bubble/preview.rb +62 -0
  45. data/app/components/poetry/ui/bubble/style.rb +47 -0
  46. data/app/components/poetry/ui/button/component.html.erb +14 -0
  47. data/app/components/poetry/ui/button/component.rb +168 -0
  48. data/app/components/poetry/ui/button/preview.rb +94 -0
  49. data/app/components/poetry/ui/button/style.rb +41 -0
  50. data/app/components/poetry/ui/button_group/component.rb +70 -0
  51. data/app/components/poetry/ui/button_group/popup_triggers_preview.html.erb +21 -0
  52. data/app/components/poetry/ui/button_group/preview.rb +46 -0
  53. data/app/components/poetry/ui/button_group/style.rb +27 -0
  54. data/app/components/poetry/ui/button_group/text_prefix_preview.html.erb +7 -0
  55. data/app/components/poetry/ui/calendar/component.html.erb +72 -0
  56. data/app/components/poetry/ui/calendar/component.rb +366 -0
  57. data/app/components/poetry/ui/calendar/preview.rb +55 -0
  58. data/app/components/poetry/ui/calendar/style.rb +55 -0
  59. data/app/components/poetry/ui/card/component.html.erb +11 -0
  60. data/app/components/poetry/ui/card/component.rb +90 -0
  61. data/app/components/poetry/ui/card/preview.rb +29 -0
  62. data/app/components/poetry/ui/card/style.rb +23 -0
  63. data/app/components/poetry/ui/carousel/component.html.erb +17 -0
  64. data/app/components/poetry/ui/carousel/component.rb +179 -0
  65. data/app/components/poetry/ui/carousel/preview.rb +67 -0
  66. data/app/components/poetry/ui/carousel/style.rb +39 -0
  67. data/app/components/poetry/ui/checkbox/component.html.erb +22 -0
  68. data/app/components/poetry/ui/checkbox/component.rb +179 -0
  69. data/app/components/poetry/ui/checkbox/preview.rb +68 -0
  70. data/app/components/poetry/ui/checkbox/style.rb +28 -0
  71. data/app/components/poetry/ui/clipboard_text/component.html.erb +15 -0
  72. data/app/components/poetry/ui/clipboard_text/component.rb +154 -0
  73. data/app/components/poetry/ui/clipboard_text/preview.rb +24 -0
  74. data/app/components/poetry/ui/clipboard_text/style.rb +23 -0
  75. data/app/components/poetry/ui/code_block/component.html.erb +13 -0
  76. data/app/components/poetry/ui/code_block/component.rb +141 -0
  77. data/app/components/poetry/ui/code_block/preview.rb +40 -0
  78. data/app/components/poetry/ui/code_block/style.rb +38 -0
  79. data/app/components/poetry/ui/collapsible/component.html.erb +4 -0
  80. data/app/components/poetry/ui/collapsible/component.rb +134 -0
  81. data/app/components/poetry/ui/collapsible/preview.rb +24 -0
  82. data/app/components/poetry/ui/combobox/component.html.erb +49 -0
  83. data/app/components/poetry/ui/combobox/component.rb +1086 -0
  84. data/app/components/poetry/ui/combobox/preview.rb +164 -0
  85. data/app/components/poetry/ui/combobox/style.rb +148 -0
  86. data/app/components/poetry/ui/command/component.html.erb +20 -0
  87. data/app/components/poetry/ui/command/component.rb +526 -0
  88. data/app/components/poetry/ui/command/dialog_component.html.erb +14 -0
  89. data/app/components/poetry/ui/command/dialog_component.rb +206 -0
  90. data/app/components/poetry/ui/command/dialog_preview.rb +39 -0
  91. data/app/components/poetry/ui/command/preview.rb +121 -0
  92. data/app/components/poetry/ui/command/style.rb +78 -0
  93. data/app/components/poetry/ui/composable_trigger.rb +63 -0
  94. data/app/components/poetry/ui/context_menu/component.html.erb +6 -0
  95. data/app/components/poetry/ui/context_menu/component.rb +358 -0
  96. data/app/components/poetry/ui/context_menu/preview.rb +111 -0
  97. data/app/components/poetry/ui/context_menu/style.rb +59 -0
  98. data/app/components/poetry/ui/data_table/component.html.erb +78 -0
  99. data/app/components/poetry/ui/data_table/component.rb +277 -0
  100. data/app/components/poetry/ui/data_table/preview.rb +68 -0
  101. data/app/components/poetry/ui/data_table/state.rb +115 -0
  102. data/app/components/poetry/ui/data_table/style.rb +42 -0
  103. data/app/components/poetry/ui/date_field/component.html.erb +7 -0
  104. data/app/components/poetry/ui/date_field/component.rb +209 -0
  105. data/app/components/poetry/ui/date_field/preview.rb +42 -0
  106. data/app/components/poetry/ui/date_field/style.rb +35 -0
  107. data/app/components/poetry/ui/date_picker/component.html.erb +23 -0
  108. data/app/components/poetry/ui/date_picker/component.rb +242 -0
  109. data/app/components/poetry/ui/date_picker/preview.rb +31 -0
  110. data/app/components/poetry/ui/date_picker/style.rb +25 -0
  111. data/app/components/poetry/ui/deferred/component.html.erb +16 -0
  112. data/app/components/poetry/ui/deferred/component.rb +90 -0
  113. data/app/components/poetry/ui/deferred/preview.rb +24 -0
  114. data/app/components/poetry/ui/dialog/component.html.erb +21 -0
  115. data/app/components/poetry/ui/dialog/component.rb +194 -0
  116. data/app/components/poetry/ui/dialog/preview.rb +33 -0
  117. data/app/components/poetry/ui/dialog/style.rb +30 -0
  118. data/app/components/poetry/ui/drawer/component.html.erb +16 -0
  119. data/app/components/poetry/ui/drawer/component.rb +207 -0
  120. data/app/components/poetry/ui/drawer/preview.rb +69 -0
  121. data/app/components/poetry/ui/drawer/style.rb +105 -0
  122. data/app/components/poetry/ui/dropdown_menu/component.html.erb +6 -0
  123. data/app/components/poetry/ui/dropdown_menu/component.rb +350 -0
  124. data/app/components/poetry/ui/dropdown_menu/preview.rb +101 -0
  125. data/app/components/poetry/ui/dropdown_menu/style.rb +60 -0
  126. data/app/components/poetry/ui/empty/component.html.erb +10 -0
  127. data/app/components/poetry/ui/empty/component.rb +79 -0
  128. data/app/components/poetry/ui/empty/preview.rb +27 -0
  129. data/app/components/poetry/ui/empty/style.rb +27 -0
  130. data/app/components/poetry/ui/family_identity.rb +52 -0
  131. data/app/components/poetry/ui/field/component.html.erb +19 -0
  132. data/app/components/poetry/ui/field/component.rb +183 -0
  133. data/app/components/poetry/ui/field/preview.html.erb +30 -0
  134. data/app/components/poetry/ui/field/preview.rb +72 -0
  135. data/app/components/poetry/ui/field/style.rb +68 -0
  136. data/app/components/poetry/ui/field_group/component.rb +61 -0
  137. data/app/components/poetry/ui/field_group/preview.html.erb +30 -0
  138. data/app/components/poetry/ui/field_group/preview.rb +20 -0
  139. data/app/components/poetry/ui/field_group/style.rb +25 -0
  140. data/app/components/poetry/ui/field_separator/component.rb +70 -0
  141. data/app/components/poetry/ui/field_separator/preview.rb +18 -0
  142. data/app/components/poetry/ui/field_separator/style.rb +20 -0
  143. data/app/components/poetry/ui/fieldset/component.rb +90 -0
  144. data/app/components/poetry/ui/fieldset/preview.html.erb +22 -0
  145. data/app/components/poetry/ui/fieldset/preview.rb +25 -0
  146. data/app/components/poetry/ui/fieldset/style.rb +18 -0
  147. data/app/components/poetry/ui/file_input/component.html.erb +14 -0
  148. data/app/components/poetry/ui/file_input/component.rb +188 -0
  149. data/app/components/poetry/ui/file_input/preview.rb +30 -0
  150. data/app/components/poetry/ui/file_input/style.rb +35 -0
  151. data/app/components/poetry/ui/hover_card/component.html.erb +6 -0
  152. data/app/components/poetry/ui/hover_card/component.rb +201 -0
  153. data/app/components/poetry/ui/hover_card/preview.rb +60 -0
  154. data/app/components/poetry/ui/hover_card/style.rb +17 -0
  155. data/app/components/poetry/ui/icon/component.rb +127 -0
  156. data/app/components/poetry/ui/icon/preview.rb +21 -0
  157. data/app/components/poetry/ui/input/component.rb +80 -0
  158. data/app/components/poetry/ui/input/preview.rb +35 -0
  159. data/app/components/poetry/ui/input/style.rb +18 -0
  160. data/app/components/poetry/ui/input_group/button_preview.html.erb +12 -0
  161. data/app/components/poetry/ui/input_group/component.rb +69 -0
  162. data/app/components/poetry/ui/input_group/preview.rb +23 -0
  163. data/app/components/poetry/ui/input_group/search_preview.html.erb +13 -0
  164. data/app/components/poetry/ui/input_group/style.rb +40 -0
  165. data/app/components/poetry/ui/input_group/textarea_preview.html.erb +10 -0
  166. data/app/components/poetry/ui/input_group_field.rb +61 -0
  167. data/app/components/poetry/ui/input_otp/component.html.erb +25 -0
  168. data/app/components/poetry/ui/input_otp/component.rb +250 -0
  169. data/app/components/poetry/ui/input_otp/preview.rb +91 -0
  170. data/app/components/poetry/ui/input_otp/style.rb +36 -0
  171. data/app/components/poetry/ui/item/component.html.erb +13 -0
  172. data/app/components/poetry/ui/item/component.rb +99 -0
  173. data/app/components/poetry/ui/item/group_preview.html.erb +15 -0
  174. data/app/components/poetry/ui/item/preview.rb +52 -0
  175. data/app/components/poetry/ui/item/style.rb +45 -0
  176. data/app/components/poetry/ui/kbd/component.rb +47 -0
  177. data/app/components/poetry/ui/kbd/group_preview.html.erb +4 -0
  178. data/app/components/poetry/ui/kbd/preview.rb +23 -0
  179. data/app/components/poetry/ui/kbd/style.rb +13 -0
  180. data/app/components/poetry/ui/label/component.rb +46 -0
  181. data/app/components/poetry/ui/label/preview.html.erb +5 -0
  182. data/app/components/poetry/ui/label/preview.rb +16 -0
  183. data/app/components/poetry/ui/label/style.rb +13 -0
  184. data/app/components/poetry/ui/link/component.rb +62 -0
  185. data/app/components/poetry/ui/link/preview.rb +31 -0
  186. data/app/components/poetry/ui/link/style.rb +20 -0
  187. data/app/components/poetry/ui/marker/component.html.erb +4 -0
  188. data/app/components/poetry/ui/marker/component.rb +81 -0
  189. data/app/components/poetry/ui/marker/preview.rb +43 -0
  190. data/app/components/poetry/ui/marker/style.rb +24 -0
  191. data/app/components/poetry/ui/menubar/component.html.erb +3 -0
  192. data/app/components/poetry/ui/menubar/component.rb +493 -0
  193. data/app/components/poetry/ui/menubar/preview.rb +164 -0
  194. data/app/components/poetry/ui/menubar/style.rb +71 -0
  195. data/app/components/poetry/ui/menus.rb +386 -0
  196. data/app/components/poetry/ui/message/component.html.erb +8 -0
  197. data/app/components/poetry/ui/message/component.rb +64 -0
  198. data/app/components/poetry/ui/message/preview.rb +33 -0
  199. data/app/components/poetry/ui/message/style.rb +29 -0
  200. data/app/components/poetry/ui/message_scroller/component.html.erb +15 -0
  201. data/app/components/poetry/ui/message_scroller/component.rb +163 -0
  202. data/app/components/poetry/ui/message_scroller/preview.rb +33 -0
  203. data/app/components/poetry/ui/message_scroller/style.rb +39 -0
  204. data/app/components/poetry/ui/metadata_list/component.rb +88 -0
  205. data/app/components/poetry/ui/metadata_list/preview.rb +55 -0
  206. data/app/components/poetry/ui/metadata_list/style.rb +35 -0
  207. data/app/components/poetry/ui/meter/component.rb +117 -0
  208. data/app/components/poetry/ui/meter/preview.rb +28 -0
  209. data/app/components/poetry/ui/meter/style.rb +16 -0
  210. data/app/components/poetry/ui/native_select/component.rb +124 -0
  211. data/app/components/poetry/ui/native_select/labelled_preview.html.erb +7 -0
  212. data/app/components/poetry/ui/native_select/preview.rb +20 -0
  213. data/app/components/poetry/ui/native_select/style.rb +22 -0
  214. data/app/components/poetry/ui/navigation_menu/bar_preview.html.erb +14 -0
  215. data/app/components/poetry/ui/navigation_menu/component.html.erb +25 -0
  216. data/app/components/poetry/ui/navigation_menu/component.rb +254 -0
  217. data/app/components/poetry/ui/navigation_menu/preview.rb +20 -0
  218. data/app/components/poetry/ui/navigation_menu/style.rb +73 -0
  219. data/app/components/poetry/ui/navigation_menu/viewport_preview.html.erb +23 -0
  220. data/app/components/poetry/ui/number_field/component.html.erb +19 -0
  221. data/app/components/poetry/ui/number_field/component.rb +263 -0
  222. data/app/components/poetry/ui/number_field/preview.rb +66 -0
  223. data/app/components/poetry/ui/number_field/style.rb +14 -0
  224. data/app/components/poetry/ui/pagination/component.html.erb +40 -0
  225. data/app/components/poetry/ui/pagination/component.rb +182 -0
  226. data/app/components/poetry/ui/pagination/preview.rb +47 -0
  227. data/app/components/poetry/ui/pagination/style.rb +27 -0
  228. data/app/components/poetry/ui/popover/component.html.erb +17 -0
  229. data/app/components/poetry/ui/popover/component.rb +203 -0
  230. data/app/components/poetry/ui/popover/preview.html.erb +29 -0
  231. data/app/components/poetry/ui/popover/preview.rb +66 -0
  232. data/app/components/poetry/ui/popover/style.rb +26 -0
  233. data/app/components/poetry/ui/popper_consumer.rb +69 -0
  234. data/app/components/poetry/ui/progress/component.rb +95 -0
  235. data/app/components/poetry/ui/progress/preview.rb +22 -0
  236. data/app/components/poetry/ui/progress/style.rb +19 -0
  237. data/app/components/poetry/ui/questionnaire/component.html.erb +80 -0
  238. data/app/components/poetry/ui/questionnaire/component.rb +396 -0
  239. data/app/components/poetry/ui/questionnaire/preview.rb +99 -0
  240. data/app/components/poetry/ui/questionnaire/style.rb +53 -0
  241. data/app/components/poetry/ui/radio_group/component.html.erb +4 -0
  242. data/app/components/poetry/ui/radio_group/component.rb +323 -0
  243. data/app/components/poetry/ui/radio_group/preview.rb +109 -0
  244. data/app/components/poetry/ui/radio_group/style.rb +53 -0
  245. data/app/components/poetry/ui/resizable/component.html.erb +10 -0
  246. data/app/components/poetry/ui/resizable/component.rb +178 -0
  247. data/app/components/poetry/ui/resizable/preview.rb +42 -0
  248. data/app/components/poetry/ui/resizable/style.rb +30 -0
  249. data/app/components/poetry/ui/scroll_area/component.rb +76 -0
  250. data/app/components/poetry/ui/scroll_area/preview.rb +35 -0
  251. data/app/components/poetry/ui/scroll_area/style.rb +19 -0
  252. data/app/components/poetry/ui/search_field/component.html.erb +15 -0
  253. data/app/components/poetry/ui/search_field/component.rb +137 -0
  254. data/app/components/poetry/ui/search_field/preview.rb +23 -0
  255. data/app/components/poetry/ui/search_field/style.rb +18 -0
  256. data/app/components/poetry/ui/select/component.html.erb +15 -0
  257. data/app/components/poetry/ui/select/component.rb +639 -0
  258. data/app/components/poetry/ui/select/preview.rb +113 -0
  259. data/app/components/poetry/ui/select/style.rb +58 -0
  260. data/app/components/poetry/ui/sensitive_input/component.html.erb +29 -0
  261. data/app/components/poetry/ui/sensitive_input/component.rb +274 -0
  262. data/app/components/poetry/ui/sensitive_input/preview.rb +40 -0
  263. data/app/components/poetry/ui/sensitive_input/style.rb +49 -0
  264. data/app/components/poetry/ui/separator/component.rb +57 -0
  265. data/app/components/poetry/ui/separator/preview.rb +19 -0
  266. data/app/components/poetry/ui/separator/style.rb +15 -0
  267. data/app/components/poetry/ui/sheet/component.html.erb +21 -0
  268. data/app/components/poetry/ui/sheet/component.rb +97 -0
  269. data/app/components/poetry/ui/sheet/preview.rb +57 -0
  270. data/app/components/poetry/ui/sheet/style.rb +47 -0
  271. data/app/components/poetry/ui/sidebar/component.html.erb +20 -0
  272. data/app/components/poetry/ui/sidebar/component.rb +249 -0
  273. data/app/components/poetry/ui/sidebar/preview.rb +21 -0
  274. data/app/components/poetry/ui/sidebar/shell_preview.html.erb +47 -0
  275. data/app/components/poetry/ui/sidebar/style.rb +139 -0
  276. data/app/components/poetry/ui/skeleton/component.rb +39 -0
  277. data/app/components/poetry/ui/skeleton/preview.rb +22 -0
  278. data/app/components/poetry/ui/skeleton/style.rb +13 -0
  279. data/app/components/poetry/ui/slider/component.html.erb +13 -0
  280. data/app/components/poetry/ui/slider/component.rb +360 -0
  281. data/app/components/poetry/ui/slider/preview.rb +73 -0
  282. data/app/components/poetry/ui/slider/style.rb +55 -0
  283. data/app/components/poetry/ui/spinner/component.rb +58 -0
  284. data/app/components/poetry/ui/spinner/preview.rb +22 -0
  285. data/app/components/poetry/ui/spinner/style.rb +12 -0
  286. data/app/components/poetry/ui/stat/component.html.erb +13 -0
  287. data/app/components/poetry/ui/stat/component.rb +102 -0
  288. data/app/components/poetry/ui/stat/preview.rb +47 -0
  289. data/app/components/poetry/ui/stat/style.rb +29 -0
  290. data/app/components/poetry/ui/switch/component.html.erb +15 -0
  291. data/app/components/poetry/ui/switch/component.rb +136 -0
  292. data/app/components/poetry/ui/switch/preview.rb +66 -0
  293. data/app/components/poetry/ui/switch/style.rb +22 -0
  294. data/app/components/poetry/ui/table/component.html.erb +3 -0
  295. data/app/components/poetry/ui/table/component.rb +93 -0
  296. data/app/components/poetry/ui/table/preview.rb +96 -0
  297. data/app/components/poetry/ui/table/style.rb +26 -0
  298. data/app/components/poetry/ui/tabs/component.html.erb +10 -0
  299. data/app/components/poetry/ui/tabs/component.rb +253 -0
  300. data/app/components/poetry/ui/tabs/preview.rb +43 -0
  301. data/app/components/poetry/ui/tabs/style.rb +49 -0
  302. data/app/components/poetry/ui/tag_group/component.html.erb +8 -0
  303. data/app/components/poetry/ui/tag_group/component.rb +203 -0
  304. data/app/components/poetry/ui/tag_group/preview.rb +43 -0
  305. data/app/components/poetry/ui/tag_group/style.rb +29 -0
  306. data/app/components/poetry/ui/textarea/component.rb +64 -0
  307. data/app/components/poetry/ui/textarea/preview.rb +75 -0
  308. data/app/components/poetry/ui/textarea/style.rb +18 -0
  309. data/app/components/poetry/ui/time_field/component.html.erb +6 -0
  310. data/app/components/poetry/ui/time_field/component.rb +85 -0
  311. data/app/components/poetry/ui/time_field/preview.rb +40 -0
  312. data/app/components/poetry/ui/time_field/style.rb +30 -0
  313. data/app/components/poetry/ui/timeline/component.rb +134 -0
  314. data/app/components/poetry/ui/timeline/preview.rb +61 -0
  315. data/app/components/poetry/ui/timeline/style.rb +54 -0
  316. data/app/components/poetry/ui/toast/component.html.erb +24 -0
  317. data/app/components/poetry/ui/toast/component.rb +178 -0
  318. data/app/components/poetry/ui/toast/preview.rb +69 -0
  319. data/app/components/poetry/ui/toast/style.rb +33 -0
  320. data/app/components/poetry/ui/toast_trigger/addressed_preview.html.erb +12 -0
  321. data/app/components/poetry/ui/toast_trigger/component.html.erb +3 -0
  322. data/app/components/poetry/ui/toast_trigger/component.rb +82 -0
  323. data/app/components/poetry/ui/toast_trigger/default_preview.html.erb +11 -0
  324. data/app/components/poetry/ui/toast_trigger/preview.rb +19 -0
  325. data/app/components/poetry/ui/toaster/component.html.erb +1 -0
  326. data/app/components/poetry/ui/toaster/component.rb +99 -0
  327. data/app/components/poetry/ui/toaster/positions_preview.html.erb +24 -0
  328. data/app/components/poetry/ui/toaster/preview.rb +46 -0
  329. data/app/components/poetry/ui/toaster/stamp_preview.html.erb +15 -0
  330. data/app/components/poetry/ui/toaster/style.rb +26 -0
  331. data/app/components/poetry/ui/toggle/component.rb +120 -0
  332. data/app/components/poetry/ui/toggle/preview.rb +79 -0
  333. data/app/components/poetry/ui/toggle/style.rb +33 -0
  334. data/app/components/poetry/ui/toggle_group/component.html.erb +4 -0
  335. data/app/components/poetry/ui/toggle_group/component.rb +252 -0
  336. data/app/components/poetry/ui/toggle_group/preview.rb +143 -0
  337. data/app/components/poetry/ui/toggle_group/style.rb +33 -0
  338. data/app/components/poetry/ui/toolbar/component.rb +125 -0
  339. data/app/components/poetry/ui/toolbar/preview.rb +41 -0
  340. data/app/components/poetry/ui/toolbar/style.rb +20 -0
  341. data/app/components/poetry/ui/tooltip/component.html.erb +20 -0
  342. data/app/components/poetry/ui/tooltip/component.rb +185 -0
  343. data/app/components/poetry/ui/tooltip/preview.rb +74 -0
  344. data/app/components/poetry/ui/tooltip/previews/provider_row.html.erb +25 -0
  345. data/app/components/poetry/ui/tooltip/style.rb +24 -0
  346. data/app/components/poetry/ui/tree/component.html.erb +32 -0
  347. data/app/components/poetry/ui/tree/component.rb +233 -0
  348. data/app/components/poetry/ui/tree/preview.rb +55 -0
  349. data/app/components/poetry/ui/tree/style.rb +29 -0
  350. data/app/components/poetry/ui/typeset/component.rb +73 -0
  351. data/app/components/poetry/ui/typeset/preview.rb +45 -0
  352. data/app/components/poetry/ui/typeset/style.rb +15 -0
  353. data/app/controllers/poetry/ui/llms_controller.rb +28 -0
  354. data/app/helpers/poetry/ui/components_helper.rb +1794 -0
  355. data/app/helpers/poetry/ui/form_builder/type_inference.rb +117 -0
  356. data/app/helpers/poetry/ui/form_builder.rb +916 -0
  357. data/app/helpers/poetry/ui/optimistic_form_builder.rb +55 -0
  358. data/app/helpers/poetry/ui/toast_stream_actions.rb +27 -0
  359. data/config/component_descriptions.yml +96 -0
  360. data/config/component_registry.yml +12257 -0
  361. data/config/locales/en.yml +93 -0
  362. data/config/routes.rb +8 -0
  363. data/config/template_classes.txt +113 -0
  364. data/lib/generators/poetry/add/add_generator.rb +218 -0
  365. data/lib/generators/poetry/agent_rules/agent_rules_generator.rb +91 -0
  366. data/lib/generators/poetry/agents/agents_generator.rb +24 -0
  367. data/lib/generators/poetry/agents_section.rb +148 -0
  368. data/lib/generators/poetry/block/block_generator.rb +67 -0
  369. data/lib/generators/poetry/block/templates/action_bar.html.erb +45 -0
  370. data/lib/generators/poetry/block/templates/app_shell.html.erb +139 -0
  371. data/lib/generators/poetry/block/templates/data_index.html.erb +85 -0
  372. data/lib/generators/poetry/block/templates/destructive_panel.html.erb +26 -0
  373. data/lib/generators/poetry/block/templates/page_header.html.erb +25 -0
  374. data/lib/generators/poetry/block/templates/section_card.html.erb +42 -0
  375. data/lib/generators/poetry/block/templates/stepper.html.erb +79 -0
  376. data/lib/generators/poetry/block/templates/top_nav.html.erb +44 -0
  377. data/lib/generators/poetry/diff/diff_generator.rb +135 -0
  378. data/lib/generators/poetry/editor/editor_generator.rb +344 -0
  379. data/lib/generators/poetry/editor/templates/poetry-check-hook +81 -0
  380. data/lib/generators/poetry/install/install_generator.rb +364 -0
  381. data/lib/generators/poetry/pagination/pagination_generator.rb +76 -0
  382. data/lib/generators/poetry/pagination/templates/kaminari_paginator.html.erb +29 -0
  383. data/lib/generators/poetry/pagination/templates/poetry_link_renderer.rb +34 -0
  384. data/lib/generators/poetry/pagination/templates/poetry_pagy_helper.rb +28 -0
  385. data/lib/generators/poetry/recipes/agent_embed/app/javascript/controllers/agent_demo_controller.js +131 -0
  386. data/lib/generators/poetry/recipes/screen_data_index/app/controllers/orders_controller.rb +15 -0
  387. data/lib/generators/poetry/recipes/screen_data_index/app/views/orders/index.html.erb +7 -0
  388. data/lib/generators/poetry/recipes/screen_data_index/test/system/orders_index_test.rb +16 -0
  389. data/lib/generators/poetry/recipes/screen_settings/app/controllers/settings_controller.rb +14 -0
  390. data/lib/generators/poetry/recipes/screen_settings/app/views/settings/show.html.erb +9 -0
  391. data/lib/generators/poetry/recipes/screen_settings/test/system/settings_show_test.rb +16 -0
  392. data/lib/generators/poetry/scaffold_templates/scaffold_templates_generator.rb +60 -0
  393. data/lib/generators/poetry/scaffold_templates/templates/_form.html.erb.tt +77 -0
  394. data/lib/generators/poetry/scaffold_templates/templates/controller.rb.tt +78 -0
  395. data/lib/generators/poetry/scaffold_templates/templates/edit.html.erb.tt +14 -0
  396. data/lib/generators/poetry/scaffold_templates/templates/index.html.erb.tt +24 -0
  397. data/lib/generators/poetry/scaffold_templates/templates/new.html.erb.tt +11 -0
  398. data/lib/generators/poetry/scaffold_templates/templates/partial.html.erb.tt +13 -0
  399. data/lib/generators/poetry/scaffold_templates/templates/show.html.erb.tt +18 -0
  400. data/lib/generators/poetry/skill/skill_generator.rb +34 -0
  401. data/lib/generators/poetry/skill/templates/poetry-component/SKILL.md +58 -0
  402. data/lib/generators/poetry/skill/templates/poetry-component/references/anatomy.md +152 -0
  403. data/lib/generators/poetry/skill/templates/poetry-component/references/checklist.md +67 -0
  404. data/lib/generators/poetry/skill/templates/poetry-component/references/documentation.md +137 -0
  405. data/lib/generators/poetry/skill/templates/poetry-design/SKILL.md +56 -0
  406. data/lib/generators/poetry/skill/templates/poetry-design/references/audit.md +123 -0
  407. data/lib/generators/poetry/skill/templates/poetry-design/references/compose.md +73 -0
  408. data/lib/generators/poetry/skill/templates/poetry-design/references/figma.md +68 -0
  409. data/lib/generators/poetry/skill/templates/poetry-design/references/paper.md +56 -0
  410. data/lib/generators/poetry/skill/templates/poetry-design/references/study.md +47 -0
  411. data/lib/generators/poetry/skill/templates/poetry-design/references/theme.md +70 -0
  412. data/lib/generators/poetry/skills_section.rb +58 -0
  413. data/lib/poetry/ui/chat.rb +283 -0
  414. data/lib/poetry/ui/code_block_highlighter.rb +60 -0
  415. data/lib/poetry/ui/engine.rb +55 -0
  416. data/lib/poetry/ui/recipes.rb +157 -0
  417. data/lib/poetry/ui/testing/combobox.rb +167 -0
  418. data/lib/poetry/ui/testing/dialog.rb +73 -0
  419. data/lib/poetry/ui/testing/menu.rb +127 -0
  420. data/lib/poetry/ui/testing/registration.rb +58 -0
  421. data/lib/poetry/ui/testing/select.rb +147 -0
  422. data/lib/poetry/ui/testing/tester.rb +130 -0
  423. data/lib/poetry/ui/testing.rb +130 -0
  424. data/lib/poetry/ui/themes.rb +109 -0
  425. data/lib/poetry/ui/version.rb +8 -0
  426. data/lib/poetry/ui/webmcp.rb +91 -0
  427. data/lib/poetry/ui.rb +285 -0
  428. data/lib/poetry-ui.rb +5 -0
  429. data/lib/tasks/poetry/check.rake +73 -0
  430. data/lib/tasks/poetry/design.rake +293 -0
  431. data/lib/tasks/poetry/verify.rake +36 -0
  432. data/themes/default.css +1793 -0
  433. data/themes/luma.css +1764 -0
  434. data/themes/lyra.css +1768 -0
  435. data/themes/maia.css +1768 -0
  436. data/themes/mira.css +1760 -0
  437. data/themes/nova.css +1755 -0
  438. data/themes/rhea.css +1771 -0
  439. data/themes/sera.css +1757 -0
  440. data/themes/vega.css +1775 -0
  441. data/typeset/typeset.css +499 -0
  442. metadata +502 -0
@@ -0,0 +1,21 @@
1
+ <%= content_tag(:div, **root_attributes.to_attributes) do %>
2
+ <%= trigger %>
3
+ <%= content_tag(:dialog, **Poetry::Core::HTML::Attributes.new(dialog_attributes).to_attributes) do %>
4
+ <div data-slot="sheet-header" class="<%= css(:header) %>">
5
+ <h2 id="<%= title_id %>" data-slot="sheet-title" class="<%= css(:title) %>"><%= title %></h2>
6
+ <% if description? %>
7
+ <p id="<%= description_id %>" data-slot="sheet-description" class="<%= css(:description) %>"><%= description %></p>
8
+ <% end %>
9
+ </div>
10
+ <%= content %>
11
+ <% if footer? %><div data-slot="sheet-footer" class="<%= css(:footer) %>"><%= footer %></div><% end %>
12
+ <% if show_close_button %>
13
+ <%= render Poetry::Ui::Button::Component.new(variant: :ghost, size: :"icon-sm",
14
+ label: t("poetry.sheet.close"),
15
+ class: css(:close),
16
+ data: { slot: "sheet-close", action: close_action }) do %>
17
+ <%= render Poetry::Ui::Icon::Component.new(name: :x) %>
18
+ <% end %>
19
+ <% end %>
20
+ <% end %>
21
+ <% end %>
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # A modal panel that slides in from a screen edge.
6
+ module Sheet
7
+ # A modal panel that slides in from a screen edge - navigation on
8
+ # the left, detail/edit panels on the right, pickers on the bottom.
9
+ # A re-skinned Dialog, so everything hard is INHERITED: the native
10
+ # <dialog> + showModal() platform behavior (focus trap, Esc, top
11
+ # layer, focus return), the data-open/data-closed pair, backdrop
12
+ # dismissal, scroll lock, dismissible:, show_close_button:, and the
13
+ # required title. The deltas: the side style (edge-anchored margins
14
+ # replace the parent's centering) and the slide-in animation.
15
+ #
16
+ # @example
17
+ # render Poetry::Ui::Sheet::Component.new(side: :right) do |sheet|
18
+ # sheet.with_trigger { "Edit profile" }
19
+ # sheet.with_title { "Edit profile" }
20
+ # "Sheet body"
21
+ # end
22
+ class Component < Dialog::Component
23
+ # The closed vocabulary for the side style axis.
24
+ SIDES = %i[top right bottom left].freeze
25
+
26
+ # Projected into the registry, llms.txt, and the agent surface.
27
+ AGENT_RULES = [
28
+ "Open sheets with with_trigger(...) - never a hand-wired button.",
29
+ "with_title is REQUIRED (the accessible name) - the inherited Dialog rule.",
30
+ "Pick side by content: navigation left, detail/edit right, pickers bottom.",
31
+ "Do not put must-not-lose confirmations in a Sheet - that is AlertDialog.",
32
+ "Do not rebuild a centered Dialog with a Sheet; use Dialog."
33
+ ].freeze
34
+
35
+ # The Sheet gets its OWN controller - the dialog machinery plus
36
+ # the presence-hold close (the closed slide-out finishes before
37
+ # the panel hides).
38
+ # Redeclaring both elements REPLACES Dialog's :dialog controller
39
+ # wholesale (replace-on-redeclare); the inherited trigger lambda and
40
+ # close_action late-bind here through stimulus_action.
41
+ use_stimulus do
42
+ on :root do
43
+ controller :sheet do
44
+ register
45
+ value :dismissible
46
+ end
47
+ end
48
+ on :content do
49
+ controller :sheet do
50
+ target :dialog
51
+ action :close, on: :cancel
52
+ action :backdrop_close, on: :click
53
+ end
54
+ end
55
+ on :trigger do
56
+ controller(:sheet) { action :open }
57
+ end
58
+ on :close do
59
+ controller(:sheet) { action :close }
60
+ end
61
+ end
62
+
63
+ style :side, default: :right, required: true, variants: SIDES,
64
+ doc: "The edge the sheet slides in from - a physical direction (right stays right in RTL)."
65
+
66
+ part "sheet", "Root wrapper around the trigger and the <dialog> element"
67
+ part "sheet-content", "The <dialog> panel, anchored to a screen edge - the slide " \
68
+ "animation and the open state ride here",
69
+ states: {
70
+ "data-open" => "panel is open (the controller flips the pair at runtime)",
71
+ "data-closed" => "panel is closed or animating out (the server-rendered state; " \
72
+ "the presence-hold close rides the closed slide-out)",
73
+ "data-side" => { condition: "always - the edge the sheet slides in from",
74
+ values: SIDES.map(&:to_s) }
75
+ }
76
+ part "sheet-header", "Title block at the top of the panel"
77
+ part "sheet-title", "The heading - the sheet's accessible name (required slot)"
78
+ part "sheet-description", "Muted copy under the title, wired to aria-describedby"
79
+ part "sheet-footer", "Action row pinned to the bottom of the panel"
80
+
81
+ private
82
+
83
+ # The Sheet deltas on the inherited panel: the side's edge classes
84
+ # (the resolver applies variants only at the dictionary root; the
85
+ # Sheet's visual root IS the :content element, so the side branch
86
+ # merges in here) and the data-side stamp.
87
+ def panel_classes
88
+ [Style.side(side), content_class]
89
+ end
90
+
91
+ def panel_stamps
92
+ { "data-side" => side }
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Sheet
6
+ # The Sheet preview: one example per edge (previews render CLOSED,
7
+ # the trigger page - the Dialog convention).
8
+ class Preview < Poetry::Core::Preview::Base
9
+ # side: :right - the detail/edit panel default.
10
+ def default
11
+ side_example(:right)
12
+ end
13
+
14
+ def left
15
+ side_example(:left)
16
+ end
17
+
18
+ def top
19
+ side_example(:top)
20
+ end
21
+
22
+ def bottom
23
+ side_example(:bottom)
24
+ end
25
+
26
+ # The canonical Sheet recipe: an edit form beside the page context,
27
+ # footer actions pinned to the edge by mt-auto.
28
+ def form
29
+ render_component(side: :right) do |sheet|
30
+ sheet.with_trigger(variant: :outline) { "Edit profile" }
31
+ sheet.with_title { "Edit profile" }
32
+ sheet.with_description { "Make changes to your profile here. Click save when you're done." }
33
+ sheet.with_footer do
34
+ embed(Poetry::Ui::Button::Component.new(type: :submit).with_content("Save changes"))
35
+ end
36
+ embed(Poetry::Ui::Label::Component.new(for_id: "sheet-demo-name").with_content("Name")) +
37
+ embed(Poetry::Ui::Input::Component.new(name: "name", value: "Pedro Duarte", id: "sheet-demo-name"))
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def side_example(side)
44
+ render_component(side: side) do |sheet|
45
+ sheet.with_trigger(variant: :outline) { "Open #{side} sheet" }
46
+ sheet.with_title { "Slide from the #{side}" }
47
+ sheet.with_description { "A Dialog that stays visually adjacent to the page." }
48
+ sheet.with_footer do
49
+ embed(Poetry::Ui::Button::Component.new.with_content("Apply"))
50
+ end
51
+ "Sheet body content."
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Sheet
6
+ # Style dictionary for the Sheet family, on the native-dialog spine.
7
+ # m-0 and the per-side auto margins live in the theme TOGETHER (the
8
+ # side margins must beat m-0, which they only can from the same
9
+ # layer); the UA display guard stays inline.
10
+ class Style < Poetry::Core::Style
11
+ # open:flex, NOT flex: a bare display class would defeat the UA's
12
+ # dialog:not([open]) { display: none }.
13
+ # w-full rides the theme so the sides' w-3/4 beats it in-layer.
14
+ # No `relative`: the top layer discards it and the UA reasserts
15
+ # `absolute`, which pins the sheet to the DOCUMENT edge (it scrolls
16
+ # off-screen when opened below the fold). The UA `:modal` rule keeps
17
+ # it viewport-fixed, so the side auto-margins pin it to the viewport
18
+ # edge as intended.
19
+ element :content, "cn-sheet-content open:flex flex-col"
20
+
21
+ # The side branches ride cn-sheet-side-* theme rules (margins,
22
+ # edge borders, sizes, slide animations). Applied to :content by
23
+ # the component via Style.side - the resolver renders variants only
24
+ # at the dictionary root, and the Sheet's root wrapper is
25
+ # non-visual.
26
+ variant :side, {
27
+ top: "cn-sheet-side-top",
28
+ right: "cn-sheet-side-right",
29
+ bottom: "cn-sheet-side-bottom",
30
+ left: "cn-sheet-side-left"
31
+ }
32
+
33
+ element :header, "cn-sheet-header flex flex-col"
34
+ element :title, "cn-sheet-title"
35
+ element :description, "cn-sheet-description"
36
+ # mt-auto pins the footer to the bottom edge.
37
+ element :footer, "cn-sheet-footer mt-auto flex flex-col"
38
+ element :close, "cn-sheet-close"
39
+
40
+ # The side's edge classes for the <dialog> element.
41
+ def self.side(value)
42
+ resolver.variants.fetch(:side).fetch(value.to_sym)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,20 @@
1
+ <%= content_tag(:div, **root_attributes.to_attributes) do %>
2
+ <%= content_tag(:div, peer_attributes) do %>
3
+ <div data-slot="sidebar-gap" class="<%= gap_classes %>"></div>
4
+ <div data-slot="sidebar-container" data-side="<%= side %>" class="<%= container_classes %>">
5
+ <div data-slot="sidebar-inner" class="<%= css(:inner) %>" <%= tag.attributes(**stimulus_attributes_for(:inner)) %>><%= nav %></div>
6
+ </div>
7
+ <% end %>
8
+ <%# The mobile sheet (DOM-move): rendered EMPTY; the controller
9
+ adopts the nav children on open and returns them on close. %>
10
+ <%= content_tag(:dialog, **mobile_dialog_attributes) do %>
11
+ <div class="sr-only">
12
+ <h2 id="<%= mobile_title_id %>">Sidebar</h2>
13
+ <p>Displays the mobile sidebar.</p>
14
+ </div>
15
+ <div data-slot="sidebar-mobile-inner" class="<%= css(:mobile_inner) %>" <%= tag.attributes(**stimulus_attributes_for(:mobile_inner)) %>></div>
16
+ <% end %>
17
+ <% if inset? %>
18
+ <main data-slot="sidebar-inset" class="<%= css(:inset) %>"><%= inset %></main>
19
+ <% end %>
20
+ <% end %>
@@ -0,0 +1,249 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # The app-shell frame: collapsible navigation column plus content inset.
6
+ module Sidebar
7
+ # The app-shell frame: a collapsible navigation column plus the main
8
+ # content inset. Reach for it as the outermost layout of an
9
+ # application screen. The collapse is pure CSS off data-state; the
10
+ # controller flips the attribute, persists the sidebar_state cookie,
11
+ # and binds Cmd/Ctrl+B. Server-first: pass open: from the cookie
12
+ # (cookies[:sidebar_state] != "false") so the first paint matches the
13
+ # user's last choice with no flash. Below the md breakpoint the
14
+ # column becomes a slide-in sheet.
15
+ #
16
+ # @example App shell wired to the persisted cookie
17
+ # <%= poetry_sidebar(open: cookies[:sidebar_state] != "false", collapsible: :icon) do |shell| %>
18
+ # <% shell.with_nav do %>
19
+ # <%= poetry_sidebar_group do %>...menu...<% end %>
20
+ # <% end %>
21
+ # <% shell.with_inset do %>
22
+ # <%= poetry_sidebar_trigger %>
23
+ # <main>...page...</main>
24
+ # <% end %>
25
+ # <% end %>
26
+ class Component < Poetry::Core::Component
27
+ # The closed vocabulary for the side axis.
28
+ SIDES = %i[left right].freeze
29
+ # The closed vocabulary for the column-treatment axis.
30
+ VARIANTS = %i[sidebar floating inset].freeze
31
+ # The closed vocabulary for the collapse-mode axis.
32
+ COLLAPSIBLE = %i[offcanvas icon none].freeze
33
+
34
+ # The expanded column width.
35
+ WIDTH = "16rem"
36
+ # The collapsed icon-rail width.
37
+ WIDTH_ICON = "3rem"
38
+ # The mobile sheet's panel width.
39
+ WIDTH_MOBILE = "18rem"
40
+
41
+ # Projected into the registry, llms.txt, and the agent surface.
42
+ AGENT_RULES = [
43
+ "Wrap the WHOLE shell: with_nav is the sidebar column, with_inset is the page area " \
44
+ "(the trigger lives in the inset).",
45
+ "Read the persisted state server-side - open: cookies[:sidebar_state] != \"false\" - so the " \
46
+ "first paint has no collapse flash.",
47
+ "collapsible: :icon keeps icon rails visible when collapsed; :offcanvas slides it fully away; " \
48
+ ":none is a static column.",
49
+ "Menu entries are poetry_sidebar_menu_button(href:) links (active: marks the current route) - " \
50
+ "navigation navigates."
51
+ ].freeze
52
+
53
+ # The same facts the before_render raise enforces, stated statically
54
+ # so static checks can flag a missing nav without rendering.
55
+ REQUIRED_SLOTS = { nav: "the sidebar column" }.freeze
56
+
57
+ renders_one :nav, doc: "The sidebar column's content (required) - groups, menus, header/footer."
58
+ renders_one :inset, doc: "The page area beside the column - rendered as the <main> inset."
59
+
60
+ use_stimulus do
61
+ on :root do
62
+ controller :sidebar do
63
+ register
64
+ value :open
65
+ value :collapsible
66
+ end
67
+ end
68
+ on :peer do
69
+ controller(:sidebar) { target :sidebar }
70
+ end
71
+ on :inner do
72
+ controller(:sidebar) { target :inner }
73
+ end
74
+ # The mobile sheet <dialog>: the Dialog-family cancel/backdrop
75
+ # pair under sidebar-namespaced action names.
76
+ on :mobile do
77
+ controller :sidebar do
78
+ target :mobile_dialog
79
+ action :close_mobile, on: :cancel
80
+ action :mobile_backdrop_close, on: :click
81
+ end
82
+ end
83
+ on :mobile_inner do
84
+ controller(:sidebar) { target :mobile_inner }
85
+ end
86
+ # Rendered by the poetry_sidebar_trigger / poetry_sidebar_rail
87
+ # helpers (helper-side strings; declared here so the contract
88
+ # covers the whole family surface).
89
+ on :trigger do
90
+ controller(:sidebar) { action :toggle, on: :click }
91
+ end
92
+ end
93
+
94
+ option :open, :boolean, default: true,
95
+ doc: "The expanded/collapsed state at first paint - feed it from the persisted " \
96
+ "cookie so there is no collapse flash."
97
+ option :side, :symbol, default: :left, doc: "Which edge the column hangs on."
98
+ option :variant, :symbol, default: :sidebar,
99
+ doc: "The column treatment: flush column, floating card, or inset panel."
100
+ option :collapsible, :symbol, default: :offcanvas,
101
+ doc: "What collapsing does: slide fully away, shrink to an icon rail, or :none " \
102
+ "for a static column."
103
+
104
+ validates :side, inclusion: { in: SIDES }
105
+ validates :variant, inclusion: { in: VARIANTS }
106
+ validates :collapsible, inclusion: { in: COLLAPSIBLE }
107
+
108
+ part "sidebar-wrapper", "The provider shell around the column, the mobile dialog, and the inset",
109
+ vars: {
110
+ "--sidebar-width" => "the expanded column width (16rem) - the gap/container geometry reads it",
111
+ "--sidebar-width-icon" => "the collapsed icon-rail width (3rem)"
112
+ }
113
+ part "sidebar", "The desktop state peer - the collapse state lives here and the pure-CSS " \
114
+ "group-data chrome keys on it",
115
+ states: {
116
+ "data-state" => "expanded or collapsed - the controller flips it and persists the cookie",
117
+ "data-collapsible" => { condition: "the collapse mode WHILE collapsed (empty while expanded " \
118
+ "- source parity)",
119
+ values: %w[offcanvas icon none] },
120
+ "data-variant" => { condition: "the column treatment", values: %w[sidebar floating inset] },
121
+ "data-side" => { condition: "which edge the column hangs on", values: %w[left right] }
122
+ }
123
+ part "sidebar-gap", "The in-flow width ghost that pushes the inset over - its width animates " \
124
+ "on collapse"
125
+ part "sidebar-container", "The fixed-position column itself",
126
+ states: {
127
+ "data-side" => { condition: "which edge it pins to", values: %w[left right] }
128
+ }
129
+ part "sidebar-inner", "The flex column receiving the nav slot - the mobile mode adopts its " \
130
+ "children from here"
131
+ part "sidebar-mobile", "The mobile sheet <dialog> (below md) - server-rendered empty; the " \
132
+ "controller adopts the nav children on open",
133
+ states: {
134
+ "data-open" => "sheet is open (presence flips the pair at runtime)",
135
+ "data-closed" => "sheet is closed (the server-rendered state)",
136
+ "data-mobile" => "always \"true\" - the mobile-mode marker",
137
+ "data-side" => { condition: "which edge the sheet slides from", values: %w[left right] },
138
+ "data-sidebar" => "always \"sidebar\" - the suite-wide sub-part marker"
139
+ },
140
+ vars: {
141
+ "--sidebar-width" => "overridden inline to the mobile sheet width (18rem)"
142
+ }
143
+ part "sidebar-mobile-inner", "The adoption container the nav children move into while the " \
144
+ "sheet is open"
145
+ part "sidebar-inset", "The <main> page area beside the column"
146
+ part "sidebar-header", "Top block of the column (with_nav content)"
147
+ part "sidebar-footer", "Bottom block of the column"
148
+ part "sidebar-content", "The scrollable middle of the column"
149
+ part "sidebar-group", "One titled section inside the content"
150
+ part "sidebar-group-label", "The section heading - fades and collapses away in icon mode"
151
+ part "sidebar-menu", "The <ul> of menu items inside a group"
152
+ part "sidebar-menu-item", "One <li> menu row (the group/menu-item hover scope)"
153
+ part "sidebar-menu-button", "The row's link (href:) or button - the navigation entry itself",
154
+ states: {
155
+ "data-active" => "the current route (active: - links also get aria-current=page)",
156
+ "data-open" => "when the button is a collapsible's trigger - the disclosure state the " \
157
+ "collapsible controller flips",
158
+ "data-size" => "the row size variant (default, sm, or lg) - the action/badge tops key on it",
159
+ "data-variant" => { condition: "always - the treatment", values: %w[default outline] }
160
+ }
161
+ part "sidebar-menu-action", "The item-corner action button, absolutely positioned in the row",
162
+ states: {
163
+ "data-sidebar" => "always \"menu-action\" - the suite-wide sub-part marker"
164
+ }
165
+ part "sidebar-menu-badge", "The trailing count/status chrome in the row corner - " \
166
+ "pointer-transparent",
167
+ states: {
168
+ "data-sidebar" => "always \"menu-badge\" - the suite-wide sub-part marker"
169
+ }
170
+
171
+ # @api private
172
+ def before_render
173
+ raise ArgumentError, "Sidebar requires with_nav (the sidebar column)" unless nav?
174
+ end
175
+
176
+ # @api private
177
+ def data_state
178
+ open ? "expanded" : "collapsed"
179
+ end
180
+
181
+ # data-collapsible carries the mode only WHILE collapsed - the
182
+ # expanded peer has an empty data-collapsible.
183
+ # @api private
184
+ def data_collapsible
185
+ open ? "" : collapsible.to_s
186
+ end
187
+
188
+ # @api private
189
+ def inset_variant?
190
+ %i[floating inset].include?(variant)
191
+ end
192
+
193
+ # @api private
194
+ def root_attributes
195
+ html_attributes.merge_if_not_set(
196
+ {
197
+ "data-slot" => "sidebar-wrapper",
198
+ "style" => "--sidebar-width: #{WIDTH}; --sidebar-width-icon: #{WIDTH_ICON};",
199
+ "class" => css(:wrapper)
200
+ }.merge(stimulus_attributes_for(:root)).merge(component_data_attributes)
201
+ )
202
+ end
203
+
204
+ # @api private
205
+ def peer_attributes
206
+ {
207
+ "data-slot" => "sidebar", "class" => css(:peer),
208
+ "data-state" => data_state, "data-collapsible" => data_collapsible,
209
+ "data-variant" => variant, "data-side" => side
210
+ }.merge(stimulus_attributes_for(:peer))
211
+ end
212
+
213
+ # @api private
214
+ def gap_classes
215
+ inset_variant? ? "#{css(:gap)} #{css(:gap_inset)}" : css(:gap)
216
+ end
217
+
218
+ # @api private
219
+ def container_classes
220
+ inset_variant? ? "#{css(:container)} #{css(:container_inset)}" : css(:container)
221
+ end
222
+
223
+ # The mobile sheet <dialog> (DOM-move): server-rendered
224
+ # EMPTY - the controller adopts the nav children on open. Skinned
225
+ # with the Sheet's presence classes off the sidebar dictionary;
226
+ # md:hidden keeps it out of the desktop layout wholesale.
227
+ # @api private
228
+ def mobile_dialog_attributes
229
+ attrs = {
230
+ "data-slot" => "sidebar-mobile", "data-sidebar" => "sidebar",
231
+ "data-mobile" => "true", "data-side" => side, "data-closed" => "",
232
+ "class" => "#{css(:mobile)} #{Style.mobile_side(side)}",
233
+ "style" => "--sidebar-width: #{WIDTH_MOBILE};",
234
+ "aria-labelledby" => mobile_title_id
235
+ }
236
+ attrs.merge(stimulus_attributes_for(:mobile))
237
+ end
238
+
239
+ # @api private
240
+ def mobile_title_id
241
+ @mobile_title_id ||= poetry_instance_id("poetry-sidebar-mobile")
242
+ end
243
+
244
+ private :data_state, :data_collapsible, :inset_variant?, :root_attributes, :peer_attributes, :gap_classes
245
+ private :container_classes, :mobile_dialog_attributes, :mobile_title_id
246
+ end
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Sidebar
6
+ # The Sidebar preview: the app shell in the icon-collapsible and
7
+ # offcanvas modes (the sidecar template composes the full nav + inset,
8
+ # since it is a helper-heavy structure).
9
+ class Preview < Poetry::Core::Preview::Base
10
+ def default
11
+ render_with_template(template: "poetry/ui/sidebar/shell_preview", locals: { collapsible: :icon })
12
+ end
13
+
14
+ def offcanvas_collapsed
15
+ render_with_template(template: "poetry/ui/sidebar/shell_preview",
16
+ locals: { collapsible: :offcanvas, open: false })
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ <%# The app shell: a grouped nav column + a page inset with the trigger. %>
2
+ <% open = local_assigns.fetch(:open, true) %>
3
+ <div class="h-96 overflow-hidden rounded-lg border">
4
+ <%= poetry_sidebar(collapsible: collapsible, open: open) do |shell| %>
5
+ <% shell.with_nav do %>
6
+ <%= poetry_sidebar_header do %>
7
+ <div class="flex items-center gap-2 px-2 py-1 text-sm font-semibold">Acme Inc</div>
8
+ <% end %>
9
+ <%= poetry_sidebar_content do %>
10
+ <%= poetry_sidebar_group do %>
11
+ <%= poetry_sidebar_group_label { "Platform" } %>
12
+ <%= poetry_sidebar_menu do %>
13
+ <%= poetry_sidebar_menu_item do %>
14
+ <%= poetry_sidebar_menu_button(href: "#", active: true) do %>
15
+ <%= poetry_icon(name: :"layout-dashboard") %><span>Dashboard</span>
16
+ <% end %>
17
+ <% end %>
18
+ <%= poetry_sidebar_menu_item do %>
19
+ <%= poetry_sidebar_menu_button(href: "#") do %>
20
+ <%= poetry_icon(name: :inbox) %><span>Inbox</span>
21
+ <% end %>
22
+ <%= poetry_sidebar_menu_badge do %>12<% end %>
23
+ <% end %>
24
+ <%= poetry_sidebar_menu_item do %>
25
+ <%= poetry_sidebar_menu_button(href: "#") do %>
26
+ <%= poetry_icon(name: :settings) %><span>Settings</span>
27
+ <% end %>
28
+ <%= poetry_sidebar_menu_action(label: "Settings options") do %>
29
+ <%= poetry_icon(name: :"ellipsis") %>
30
+ <% end %>
31
+ <% end %>
32
+ <% end %>
33
+ <% end %>
34
+ <% end %>
35
+ <%= poetry_sidebar_footer do %>
36
+ <div class="px-2 py-1 text-xs text-muted-foreground">v1.0.0</div>
37
+ <% end %>
38
+ <% end %>
39
+ <% shell.with_inset do %>
40
+ <div class="flex items-center gap-2 border-b p-3">
41
+ <%= poetry_sidebar_trigger %>
42
+ <span class="text-sm font-medium">Dashboard</span>
43
+ </div>
44
+ <div class="p-4 text-sm text-muted-foreground">Main content area.</div>
45
+ <% end %>
46
+ <% end %>
47
+ </div>