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,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # The Item family - the generic list row.
6
+ module Item
7
+ # The Item - the generic list row (Empty's sibling): media, a
8
+ # title/description content column, and trailing actions, with
9
+ # variant (default/outline/muted) and density (default/sm/xs).
10
+ # Rows stack inside poetry_item_group (role=list) separated by
11
+ # poetry_item_separator. Renders as a div by default; pass tag: :a
12
+ # (+ href via passthrough) for a fully-clickable row.
13
+ #
14
+ # @example
15
+ # render Poetry::Ui::Item::Component.new(variant: :outline) do |item|
16
+ # item.with_title { "Backups" }
17
+ # item.with_description { "Nightly, retained 30 days" }
18
+ # end
19
+ class Component < Poetry::Core::Component
20
+ # The closed vocabulary for the variant axis.
21
+ VARIANTS = %i[default outline muted].freeze
22
+ # The closed vocabulary for the size (density) axis.
23
+ SIZES = %i[default sm xs].freeze
24
+ # The closed vocabulary for the media_variant axis.
25
+ MEDIA_VARIANTS = %i[default icon image].freeze
26
+
27
+ # Projected into the registry, llms.txt, and the agent surface.
28
+ AGENT_RULES = [
29
+ "Rows live inside poetry_item_group (role=list) and each row passes role: \"listitem\" - " \
30
+ "a role=list parent with roleless children fails aria-required-children.",
31
+ "Separate grouped rows with poetry_item_separator.",
32
+ "Compose with the slots (media/title/description/actions); loose content lands in the " \
33
+ "content column after the description.",
34
+ "media_variant: :icon for a glyph, :image for a thumbnail (sized/rounded automatically).",
35
+ "A clickable row is tag: :a with href: - never wrap an Item in a bare <a>."
36
+ ].freeze
37
+
38
+ renders_one :media, doc: "The leading media cell - a glyph or thumbnail (see media_variant)."
39
+ renders_one :title, doc: "The title row."
40
+ renders_one :description, doc: "The muted description line (clamps to two lines)."
41
+ renders_one :actions, doc: "The trailing actions cell - buttons, a menu, a switch."
42
+ renders_one :header, doc: "Full-width row above the media/content columns."
43
+ renders_one :footer, doc: "Full-width row below the media/content columns."
44
+
45
+ style :variant, default: :default, required: true, variants: VARIANTS,
46
+ doc: "The row's visual treatment - :outline boxes it, :muted recedes."
47
+ style :size, default: :default, required: true, variants: SIZES, doc: "The row's density."
48
+
49
+ option :tag, :symbol, default: :div,
50
+ doc: "The root element - tag: :a (href via passthrough) makes the whole row clickable."
51
+ option :media_variant, :symbol, default: :default,
52
+ doc: "The media treatment - :icon for a glyph, :image for a thumbnail."
53
+
54
+ validates :media_variant, inclusion: { in: MEDIA_VARIANTS }
55
+
56
+ part "item", "The row root (a div by default; tag: :a for a clickable row) - variant and " \
57
+ "density land here as data attributes",
58
+ states: {
59
+ "data-variant" => { condition: "the row's visual variant", values: VARIANTS.map(&:to_s) },
60
+ "data-size" => { condition: "the row's density", values: SIZES.map(&:to_s) }
61
+ }
62
+ part "item-media", "The leading media cell - sized and rounded by its variant",
63
+ states: {
64
+ "data-variant" => { condition: "the media treatment", values: MEDIA_VARIANTS.map(&:to_s) }
65
+ }
66
+ part "item-content", "The center column collecting title, description, and loose content"
67
+ part "item-title", "The title row"
68
+ part "item-description", "The muted description line"
69
+ part "item-header", "Full-width row above the media/content columns"
70
+ part "item-actions", "The trailing actions cell"
71
+ part "item-footer", "Full-width row below the media/content columns"
72
+
73
+ # Whether the center column renders (title, description, or loose content).
74
+ # @api private
75
+ def content_column?
76
+ title? || description? || content.present?
77
+ end
78
+
79
+ # The media cell's classes for the resolved media_variant.
80
+ # @api private
81
+ def media_classes
82
+ "#{css(:media)} #{css(:"media_#{media_variant}")}".strip
83
+ end
84
+
85
+ # The row root's attributes.
86
+ # @api private
87
+ def root_attributes
88
+ html_attributes.merge_if_not_set(
89
+ {
90
+ "data-slot" => "item", "data-variant" => variant, "data-size" => size
91
+ }.merge(component_data_attributes)
92
+ )
93
+ end
94
+
95
+ private :content_column?, :media_classes, :root_attributes
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,15 @@
1
+ <%# A grouped list: rows in poetry_item_group (role=list) - each row wears
2
+ role=listitem (upstream omits it and fails aria-required-children). %>
3
+ <div class="p-4">
4
+ <%= poetry_item_group do %>
5
+ <%= poetry_item(variant: :muted, size: :sm, role: "listitem") do |item| %>
6
+ <% item.with_title { "Invoices synced" } %>
7
+ <% item.with_description { "All invoices are up to date." } %>
8
+ <% end %>
9
+ <%= poetry_item_separator %>
10
+ <%= poetry_item(size: :sm, role: "listitem") do |item| %>
11
+ <% item.with_title { "Payment pending" } %>
12
+ <% item.with_description { "One transfer awaits confirmation." } %>
13
+ <% end %>
14
+ <% end %>
15
+ </div>
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Item
6
+ # The Item preview: a basic row, an outline row with an icon and
7
+ # actions, and the grouped list via the sidecar template.
8
+ class Preview < Poetry::Core::Preview::Base
9
+ def default
10
+ render_component do |item|
11
+ item.with_title { "Basic Item" }
12
+ item.with_description { "A simple item with title and description." }
13
+ end
14
+ end
15
+
16
+ # The full-width header/footer rows around the columns.
17
+ def with_header_and_footer
18
+ render_component do |item|
19
+ item.with_header { "Pinned" }
20
+ item.with_title { "Framed Item" }
21
+ item.with_description { "Header above, footer below." }
22
+ item.with_footer { "Updated 2 hours ago" }
23
+ end
24
+ end
25
+
26
+ def outline_with_icon_and_actions
27
+ render_component(variant: :outline, media_variant: :icon) do |item|
28
+ item.with_media { embed(Poetry::Ui::Icon::Component.new(name: :"badge-check")) }
29
+ item.with_title { "Your profile has been verified." }
30
+ item.with_actions do
31
+ embed(Poetry::Ui::Button::Component.new(size: :sm, variant: :outline).with_content("View"))
32
+ end
33
+ end
34
+ end
35
+
36
+ # The tightest row (sm lives in the group template below).
37
+ def size_xs
38
+ render_component(size: :xs) do |item|
39
+ item.with_title { "Cache cleared" }
40
+ item.with_description { "2 minutes ago" }
41
+ end
42
+ end
43
+
44
+ def group
45
+ # An explicit per-example template (a class-level preview.html.erb
46
+ # would shadow every other example - see Avatar's group note).
47
+ render_with_template(template: "poetry/ui/item/group_preview")
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Item
6
+ # Re-expressed through the cn-* theme layer. The media variants
7
+ # use upstream's cn-item-media-variant-* names. Upstream's unused
8
+ # group/item-group marker stays dropped (the compiled-CSS gate).
9
+ class Style < Poetry::Core::Style
10
+ base "cn-item group/item flex w-full flex-wrap items-center transition-colors " \
11
+ "duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] " \
12
+ "focus-visible:ring-ring/50 [a]:transition-colors"
13
+
14
+ variant :variant, {
15
+ default: "cn-item-variant-default",
16
+ outline: "cn-item-variant-outline",
17
+ muted: "cn-item-variant-muted"
18
+ }
19
+
20
+ variant :size, {
21
+ default: "cn-item-size-default",
22
+ sm: "cn-item-size-sm",
23
+ xs: "cn-item-size-xs"
24
+ }
25
+
26
+ element :media, "cn-item-media flex shrink-0 items-center justify-center " \
27
+ "[&_svg]:pointer-events-none"
28
+ element :media_default, "cn-item-media-variant-default"
29
+ element :media_icon, "cn-item-media-variant-icon"
30
+ element :media_image, "cn-item-media-variant-image"
31
+ element :content, "cn-item-content flex flex-1 flex-col [&+[data-slot=item-content]]:flex-none"
32
+ element :title, "cn-item-title line-clamp-1 flex w-fit items-center"
33
+ element :description, "cn-item-description line-clamp-2 font-normal [&>a]:underline " \
34
+ "[&>a]:underline-offset-4 [&>a:hover]:text-primary"
35
+ element :actions, "cn-item-actions flex items-center"
36
+ element :header, "cn-item-header flex basis-full items-center justify-between"
37
+ element :footer, "cn-item-footer flex basis-full items-center justify-between"
38
+
39
+ # The list wrapper + row separator (poetry_item_group / _separator).
40
+ element :group, "cn-item-group flex w-full flex-col"
41
+ element :separator, "cn-item-separator"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # The Kbd family - the keyboard-key chip.
6
+ module Kbd
7
+ # The Kbd - a real <kbd> element for a keyboard key or shortcut. The
8
+ # content is the key text (⌘, Ctrl, K); compose several for a chord.
9
+ #
10
+ # @example
11
+ # render Poetry::Ui::Kbd::Component.new { "Esc" }
12
+ class Component < Poetry::Core::Component
13
+ requires_content "the key text"
14
+
15
+ # Projected into the registry, llms.txt, and the agent surface.
16
+ AGENT_RULES = [
17
+ "Kbd renders a real <kbd> - the key text is the content block (⌘, Esc, Ctrl).",
18
+ "For a chord (⌘+K) render one Kbd per key inside an inline-flex row."
19
+ ].freeze
20
+
21
+ part "kbd", "The <kbd> element itself - the key text renders here"
22
+
23
+ # Enforces the required key text before render.
24
+ # @api private
25
+ def before_render
26
+ ensure_content!
27
+ end
28
+
29
+ # Renders the <kbd> element.
30
+ # @api private
31
+ def call
32
+ content_tag(:kbd, content, **root_attributes.to_attributes)
33
+ end
34
+
35
+ # The <kbd> element's attributes.
36
+ # @api private
37
+ def root_attributes
38
+ html_attributes.merge_if_not_set(
39
+ { "data-slot" => "kbd" }.merge(component_data_attributes)
40
+ )
41
+ end
42
+
43
+ private :root_attributes
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,4 @@
1
+ <%= poetry_kbd_group do %>
2
+ <%= poetry_kbd { "⌘" } %>
3
+ <%= poetry_kbd { "K" } %>
4
+ <% end %>
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Kbd
6
+ # The Kbd preview: single keys.
7
+ class Preview < Poetry::Core::Preview::Base
8
+ def default
9
+ render_component { "Esc" }
10
+ end
11
+
12
+ def command
13
+ render_component { "⌘" }
14
+ end
15
+
16
+ # A chord run in the themed group wrapper.
17
+ def group
18
+ render_with_template(template: "poetry/ui/kbd/group_preview")
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Kbd
6
+ # Re-expressed through the cn-* theme layer: the keyboard-key
7
+ # chip's look (incl. the tooltip inversion) rides themes/default.css.
8
+ class Style < Poetry::Core::Style
9
+ base "cn-kbd pointer-events-none inline-flex items-center justify-center select-none"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # A caption for a form control.
6
+ module Label
7
+ # A <label> for a form control, wired to it via for_id:. The
8
+ # caption is the content block.
9
+ #
10
+ # Omit for_id: when the label names a GROUP of controls rather
11
+ # than one element: a for= pointing at a non-control is inert, so
12
+ # in group mode the group names itself via aria-labelledby at this
13
+ # label's id instead.
14
+ #
15
+ # @example A label wired to its control
16
+ # render Poetry::Ui::Label::Component.new(for_id: "email").with_content("Email")
17
+ class Component < Poetry::Core::Component
18
+ # Projected into the registry, llms.txt, and the agent surface.
19
+ AGENT_RULES = [
20
+ "Every control gets a Label wired via for_id - placeholder text is never the label."
21
+ ].freeze
22
+
23
+ option :for_id, :string,
24
+ doc: "The id of the control this label names; omit it for a group label (the group then points at " \
25
+ "this label via aria-labelledby)."
26
+
27
+ part "label", "The <label> element itself - for= rides it (dropped in group mode, " \
28
+ "where the group names itself via aria-labelledby at this label's id)"
29
+
30
+ # @api private
31
+ def call
32
+ content_tag(:label, content, **root_attributes.to_attributes)
33
+ end
34
+
35
+ # @api private
36
+ def root_attributes
37
+ attrs = { "data-slot" => "label" }
38
+ attrs["for"] = for_id if for_id.present?
39
+ html_attributes.merge_if_not_set(attrs.merge(component_data_attributes))
40
+ end
41
+
42
+ private :root_attributes
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ <%# The Label preview pair: a label wired to a real control via for_id. %>
2
+ <div class="p-4">
3
+ <%= render component.with_content("Full name") %>
4
+ <%= render Poetry::Ui::Input::Component.new(name: "full_name", id: "label-full-name") %>
5
+ </div>
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Label
6
+ # The Label preview - always tied to a control via for_id (the
7
+ # component's whole contract), so the sidecar preview.html.erb renders
8
+ # the label/input pair.
9
+ class Preview < Poetry::Core::Preview::Base
10
+ def default
11
+ render_with(component: Component.new(for_id: "label-full-name"))
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Label
6
+ # Re-expressed through the cn-* theme layer.
7
+ class Style < Poetry::Core::Style
8
+ base "cn-label flex items-center select-none peer-disabled:cursor-not-allowed " \
9
+ "group-data-[disabled=true]:pointer-events-none"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # A navigation link.
6
+ module Link
7
+ # A themed navigation link - a real <a>. Links navigate; buttons
8
+ # act - reach for Button when the click performs an action.
9
+ # current: true marks the active nav item via aria-current, and
10
+ # external: true opens a new tab with the safe rel pairing.
11
+ #
12
+ # @example
13
+ # render Poetry::Ui::Link::Component.new(href: "/docs") { "Documentation" }
14
+ class Component < Poetry::Core::Component
15
+ # Projected into the registry, llms.txt, and the agent surface.
16
+ AGENT_RULES = [
17
+ "Use poetry_link for navigation - poetry_button for actions (never an <a> styled by hand).",
18
+ "Mark the active nav item with current: true (aria-current), never with a bespoke class.",
19
+ "external: true handles target/rel safely - never hand-write target=_blank."
20
+ ].freeze
21
+
22
+ style :underline, default: :hover, variants: %i[hover always none],
23
+ doc: "When the underline appears; :none suits links styled by their container."
24
+
25
+ option :href, :string, required: true, doc: "The destination URL."
26
+ option :external, :boolean, default: false,
27
+ doc: "Opens in a new tab with rel=\"noopener noreferrer\" - never hand-write " \
28
+ "target=_blank."
29
+ option :current, :boolean, default: false, doc: "Marks this link as the current page via aria-current=page."
30
+
31
+ part "link", "The rendered <a> - the whole component; current: marks it aria-current=page"
32
+
33
+ # An empty link would be a focusable, invisible <a> - the visible
34
+ # text is required.
35
+ requires_content "the visible link text"
36
+
37
+ # @api private
38
+ def before_render
39
+ ensure_content!
40
+ end
41
+
42
+ # @api private
43
+ def call
44
+ content_tag(:a, content, **root_attributes.to_attributes)
45
+ end
46
+
47
+ # @api private
48
+ def root_attributes
49
+ attrs = { "href" => href, "data-slot" => "link" }.merge(component_data_attributes)
50
+ attrs["aria-current"] = "page" if current
51
+ if external
52
+ attrs["target"] = "_blank"
53
+ attrs["rel"] = "noopener noreferrer"
54
+ end
55
+ html_attributes.merge_if_not_set(attrs)
56
+ end
57
+
58
+ private :root_attributes
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Link
6
+ # The Link preview: the default hover underline, the aria-current
7
+ # nav item, an external link, and both underline extremes.
8
+ class Preview < Poetry::Core::Preview::Base
9
+ def default
10
+ render_component(href: "#") { "Documentation" }
11
+ end
12
+
13
+ def current_nav_item
14
+ render_component(href: "#", current: true) { "Dashboard" }
15
+ end
16
+
17
+ def external
18
+ render_component(href: "https://example.com", external: true) { "API reference" }
19
+ end
20
+
21
+ def always_underlined
22
+ render_component(href: "#", underline: :always) { "Terms of service" }
23
+ end
24
+
25
+ def never_underlined
26
+ render_component(href: "#", underline: :none) { "Settings" }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Link
6
+ # Re-expressed through the cn-* theme layer. No upstream
7
+ # counterpart - the split follows the category rule:
8
+ # layout/behavior inline, color/decoration/focus ring themed.
9
+ class Style < Poetry::Core::Style
10
+ base "cn-link inline-flex items-center outline-none transition-colors"
11
+
12
+ variant :underline, {
13
+ hover: "cn-link-underline-hover",
14
+ always: "cn-link-underline-always",
15
+ none: "cn-link-underline-none"
16
+ }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,4 @@
1
+ <%= content_tag(tag, **root_attributes.to_attributes) do %>
2
+ <% if icon? %><span data-slot="marker-icon" aria-hidden="true" class="<%= css(:icon) %>"><%= icon %></span><% end %>
3
+ <span data-slot="marker-content" class="<%= css(:content) %>"><%= content %></span>
4
+ <% end %>
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # A transcript divider or inline status line for chat UIs.
6
+ module Marker
7
+ # A transcript divider or inline status line for chat UIs: date
8
+ # breaks, "3 new messages", an in-flight status. The label is real
9
+ # announced content - the decorative divider lines render around
10
+ # it, and the marker never takes a separator role. announce:
11
+ # :status turns it into a live status region for the single
12
+ # in-flight marker a transcript shows while streaming.
13
+ #
14
+ # @example
15
+ # render Poetry::Ui::Marker::Component.new(variant: :separator) { "Yesterday" }
16
+ class Component < Poetry::Core::Component
17
+ # The closed vocabulary for the variant axis.
18
+ VARIANTS = %i[default separator border].freeze
19
+ # The closed vocabulary for the announce axis.
20
+ ANNOUNCE = %i[none status].freeze
21
+
22
+ # Projected into the registry, llms.txt, and the agent surface.
23
+ AGENT_RULES = [
24
+ "The marker text is real announced content - never mark it aria-hidden or role=separator.",
25
+ "announce: :status is for the ONE in-flight marker (streaming status); static dividers never announce.",
26
+ "Icons ride the icon slot (decorative always): with_icon(name:) for a lucide glyph, " \
27
+ "with_icon { } for other media (a Spinner mid-run).",
28
+ "Use variant: :separator for date/section breaks; :border under pinned headers."
29
+ ].freeze
30
+
31
+ renders_one :icon,
32
+ doc: "Optional leading visual: name: renders an icon glyph; a block carries other media (a " \
33
+ "Spinner mid-run). Either way it sits in an aria-hidden cell and stays decorative - the " \
34
+ "marker root does the announcing.",
35
+ renders: lambda { |name: nil, **options, &block|
36
+ next Poetry::Ui::Icon::Component.new(name: name, **options) if name
37
+
38
+ content_tag(:span, &block)
39
+ }
40
+
41
+ style :variant, default: :default, required: true, variants: VARIANTS,
42
+ doc: "The divider treatment - :separator for date/section breaks, :border for a full-width " \
43
+ "rule under pinned headers."
44
+
45
+ option :tag, :symbol, default: :div, doc: "The root element's tag."
46
+ option :announce, :symbol, default: :none,
47
+ doc: "Makes the marker a live status region (role=status) for the one in-flight " \
48
+ "marker; static dividers never announce."
49
+
50
+ validates :announce, inclusion: { in: ANNOUNCE }
51
+
52
+ part "marker", "The divider/status root - the label is real announced content " \
53
+ "(role=status when announce: :status; never role=separator)",
54
+ states: {
55
+ "data-variant" => { condition: "always - the resolved variant",
56
+ values: VARIANTS.map(&:to_s) }
57
+ }
58
+ # "The label IS the information" - an empty marker renders a bare
59
+ # divider span pretending to inform.
60
+ requires_content "the marker label"
61
+
62
+ part "marker-icon", "Decorative icon wrapper (aria-hidden always)"
63
+ part "marker-content", "The label span - the marker text itself"
64
+
65
+ # @api private
66
+ def before_render
67
+ ensure_content!
68
+ end
69
+
70
+ # @api private
71
+ def root_attributes
72
+ attrs = { "data-slot" => "marker", "data-variant" => variant }.merge(component_data_attributes)
73
+ attrs["role"] = "status" if announce == :status
74
+ html_attributes.merge_if_not_set(attrs)
75
+ end
76
+
77
+ private :root_attributes
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Marker
6
+ # The Marker preview matrix.
7
+ class Preview < Poetry::Core::Preview::Base
8
+ def default
9
+ render_component { "Assistant is thinking" }
10
+ end
11
+
12
+ def separator
13
+ render_component(variant: :separator) { "Yesterday" }
14
+ end
15
+
16
+ def border
17
+ render_component(variant: :border) { "Earlier in this thread" }
18
+ end
19
+
20
+ def with_icon
21
+ render_component do |marker|
22
+ marker.with_icon(name: :sparkles)
23
+ "Generating a summary"
24
+ end
25
+ end
26
+
27
+ def announcing_status
28
+ render_component(announce: :status) { "Searching the web…" }
29
+ end
30
+
31
+ # The block icon path: other media in the decorative cell - the
32
+ # Spinner's own status role is hidden by the aria-hidden wrapper,
33
+ # the marker root announces.
34
+ def status_with_spinner
35
+ render_component(announce: :status) do |marker|
36
+ marker.with_icon { render(Spinner::Component.new) }
37
+ "Compacting conversation"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Marker
6
+ # Re-expressed through the cn-* theme layer. The separator
7
+ # lines stay ::before/::after pseudo-elements (AT never sees them) -
8
+ # now in the variant theme rule.
9
+ class Style < Poetry::Core::Style
10
+ base "cn-marker group/marker relative flex w-full items-center"
11
+
12
+ variant :variant, {
13
+ default: "",
14
+ separator: "cn-marker-variant-separator",
15
+ border: "cn-marker-variant-border"
16
+ }
17
+
18
+ element :icon, "cn-marker-icon shrink-0"
19
+
20
+ element :content, "cn-marker-content min-w-0 wrap-break-word"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ <%= content_tag(:div, **root_attributes.to_attributes) do %>
2
+ <% menus.each do |menu| %><%= menu %><% end %>
3
+ <% end %>