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,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # A streaming-aware chat transcript scroller.
6
+ module MessageScroller
7
+ # A scrollable chat transcript that follows the newest message
8
+ # while streaming, releases when the reader scrolls up, and offers
9
+ # a jump-to-latest button. Without JavaScript it is a plain
10
+ # scrollable region, fully readable.
11
+ #
12
+ # The content element is the Turbo Stream append target (stable
13
+ # dom id "<id>-messages"); rows are poetry_message_scroller_item
14
+ # wrappers keyed by message id. History prepends keep the reading
15
+ # position; a row rendered with anchor: true becomes the held
16
+ # reading line.
17
+ #
18
+ # @example A chat transcript
19
+ # render Poetry::Ui::MessageScroller::Component.new(id: "chat") do
20
+ # # poetry_message_scroller_item rows
21
+ # end
22
+ class Component < Poetry::Core::Component
23
+ # The closed vocabulary for the default_scroll_position axis.
24
+ SCROLL_POSITIONS = %i[start end last-anchor].freeze
25
+
26
+ # Projected into the registry, llms.txt, and the agent surface.
27
+ AGENT_RULES = [
28
+ "Stream by UPDATING a row's text (morph/replace) - appending nodes per token re-announces the row to AT.",
29
+ "Rows are poetry_message_scroller_item(id: message.id) - the id is how anchoring and Streams find them.",
30
+ "Append new turns with a Turbo Stream targeting the content element's dom id.",
31
+ "History loads PREPEND into the content element - the controller preserves the reading position.",
32
+ "Never nest a second scroll container inside the viewport."
33
+ ].freeze
34
+
35
+ use_stimulus do
36
+ on :root do
37
+ controller :message_scroller do
38
+ register
39
+ value :auto_scroll
40
+ value :default_scroll_position
41
+ value :preserve_scroll_on_prepend
42
+ value :track_visibility
43
+ end
44
+ end
45
+ on :viewport do
46
+ controller(:message_scroller) { target :viewport }
47
+ end
48
+ on :content do
49
+ controller(:message_scroller) { target :content }
50
+ end
51
+ on :spacer do
52
+ controller(:message_scroller) { target :spacer }
53
+ end
54
+ # The jump affordance: a bare descriptor (element-default click)
55
+ # plus the button target, forwarded into Button kwargs.
56
+ on :jump_button do
57
+ controller :message_scroller do
58
+ target :button
59
+ action :scroll_to_end
60
+ end
61
+ end
62
+ end
63
+
64
+ option :id, :string, required: true,
65
+ doc: "The transcript's stable identifier - the content element renders dom id " \
66
+ "\"<id>-messages\" for Turbo Streams to target."
67
+ option :auto_scroll, :boolean, default: true,
68
+ doc: "Follows the newest message while the reader sits at the bottom; " \
69
+ "scrolling up releases the follow."
70
+ option :default_scroll_position, :symbol, default: :end,
71
+ doc: "Where the viewport lands on connect: the newest message " \
72
+ "(:end), the oldest (:start), or the last anchor: true row " \
73
+ "(:\"last-anchor\")."
74
+ option :preserve_scroll_on_prepend, :boolean, default: true,
75
+ doc: "Keeps the reading position stable when history prepends " \
76
+ "into the content element."
77
+ option :track_visibility, :boolean, default: false,
78
+ doc: "Opt-in observation of which rows are on screen - emits a " \
79
+ "visibility event as the visible set changes."
80
+ option :jump_button, :boolean, default: true,
81
+ doc: "Renders the floating jump-to-latest button (shown once the reader " \
82
+ "leaves the bottom)."
83
+
84
+ validates :default_scroll_position, inclusion: { in: SCROLL_POSITIONS }
85
+
86
+ part "message-scroller", "The transcript root the controller drives - runtime " \
87
+ "scroll state is mirrored here",
88
+ states: {
89
+ "data-mode" => { condition: "always once connected - the 4-state machine",
90
+ values: %w[following-bottom free-scrolling
91
+ anchored-to-message settling-jump] },
92
+ "data-scrollable" => "overflow exists - carries which edges have room " \
93
+ "(start, end, or both as a space-separated pair)",
94
+ "data-autoscrolling" => "a programmatic scroll is settling - the " \
95
+ "follow-bottom release is suppressed while set"
96
+ }
97
+ part "message-scroller-viewport", "The native scroll region (role=region, " \
98
+ "focusable) - the controller mirrors the same " \
99
+ "runtime attributes here",
100
+ states: {
101
+ "data-scrollable" => "overflow exists - the same edge tokens as the root",
102
+ "data-autoscrolling" => "a programmatic scroll is settling"
103
+ }
104
+ part "message-scroller-content", "The row container and Turbo Stream append target " \
105
+ "(stable dom id <id>-messages); role=log announces " \
106
+ "additions"
107
+ part "message-scroller-item", "One transcript row (poetry_message_scroller_item) - " \
108
+ "the id is how anchoring and Streams find it",
109
+ states: {
110
+ "data-message-id" => "always - the row's message id",
111
+ "data-scroll-anchor" => "anchor: true - the turn the controller holds at " \
112
+ "the reading line"
113
+ }
114
+ part "message-scroller-spacer", "Tail spacer faking scroll room below a short " \
115
+ "anchored turn - hidden at height 0"
116
+
117
+ # @api private
118
+ def root_attributes
119
+ html_attributes.merge_if_not_set(
120
+ { "data-slot" => "message-scroller" }
121
+ .merge(stimulus_attributes_for(:root))
122
+ .merge(component_data_attributes)
123
+ )
124
+ end
125
+
126
+ # @api private
127
+ def viewport_attributes
128
+ {
129
+ "class" => css(:viewport), "data-slot" => "message-scroller-viewport",
130
+ "role" => "region", "tabindex" => "0",
131
+ "aria-label" => t("poetry.message_scroller.region")
132
+ }.merge(stimulus_attributes_for(:viewport))
133
+ end
134
+
135
+ # @api private
136
+ def content_attributes
137
+ {
138
+ "id" => "#{id}-messages", "class" => css(:content),
139
+ "data-slot" => "message-scroller-content",
140
+ "role" => "log", "aria-relevant" => "additions"
141
+ }.merge(stimulus_attributes_for(:content))
142
+ end
143
+
144
+ # @api private
145
+ def spacer_attributes
146
+ { "data-slot" => "message-scroller-spacer", "aria-hidden" => "true", "hidden" => true }
147
+ .merge(stimulus_attributes_for(:spacer))
148
+ end
149
+
150
+ # @api private
151
+ def button_attributes
152
+ {
153
+ class: css(:button),
154
+ data: { slot: "message-scroller-button", direction: "end", active: "false" },
155
+ tabindex: "-1"
156
+ }.merge(stimulus_attributes_for(:jump_button))
157
+ end
158
+
159
+ private :root_attributes, :viewport_attributes, :content_attributes, :spacer_attributes, :button_attributes
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module MessageScroller
6
+ # The MessageScroller preview - a bounded transcript frame (the
7
+ # geometry behaviors need the browser loop; previews cover markup).
8
+ class Preview < Poetry::Core::Preview::Base
9
+ def default
10
+ render_component(id: "demo", class: "h-80 rounded-lg border") do
11
+ safe_join(Array.new(12) { |i| item("m#{i}") { row(i) } })
12
+ end
13
+ end
14
+
15
+ def without_jump_button
16
+ render_component(id: "plain", jump_button: false, class: "h-60 rounded-lg border") do
17
+ item("only") { row(0) }
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def item(id, &)
24
+ tag.div(class: Style.css(:item), data: { slot: "message-scroller-item", "message-id": id }, &)
25
+ end
26
+
27
+ def row(index)
28
+ tag.div("Message #{index + 1}", class: "rounded-xl bg-muted px-3 py-2 w-fit")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module MessageScroller
6
+ # Re-expressed through the cn-* theme layer - minimally: the
7
+ # 4-state scroll machine's whole surface is machinery (viewport
8
+ # containment/scrollbar choreography, row content-visibility, the
9
+ # jump button's show/hide translate dance - upstream keeps every one
10
+ # of those inline too). Only the row rhythm is design: gap-8 rides
11
+ # .cn-message-scroller-content.
12
+ class Style < Poetry::Core::Style
13
+ # Source also stamps a group/message-scroller named-group marker;
14
+ # dropped until a dictionary consumer references it - an unconsumed
15
+ # named group never reaches the compiled CSS, and the verify gate
16
+ # (rightly) rejects classes no build can produce.
17
+ base "relative flex size-full min-h-0 flex-col overflow-hidden group/message-scroller"
18
+
19
+ element :viewport, "size-full min-h-0 min-w-0 scroll-fade-b scrollbar-thin scrollbar-gutter-stable " \
20
+ "overflow-y-auto overscroll-contain contain-content data-autoscrolling:scrollbar-none"
21
+
22
+ element :content, "cn-message-scroller-content flex h-max min-h-full flex-col"
23
+
24
+ element :item, "min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]"
25
+
26
+ element :button, "absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground " \
27
+ "transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground " \
28
+ "data-[active=false]:pointer-events-none data-[active=false]:scale-95 " \
29
+ "data-[active=false]:opacity-0 data-[active=false]:duration-400 " \
30
+ "data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] " \
31
+ "data-[active=true]:translate-y-0 data-[active=true]:scale-100 " \
32
+ "data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] " \
33
+ "data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full " \
34
+ "data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full " \
35
+ "rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # Labeled facts about one record, as a description list.
6
+ module MetadataList
7
+ # Labeled facts about one record - a real description list (<dl>)
8
+ # for detail pages, in one or more columns, with each label above
9
+ # its value (vertical) or beside it (horizontal). Values compose
10
+ # freely: text, a Badge, a Link, a Timestamp.
11
+ #
12
+ # @example A record's fact sheet
13
+ # render Poetry::Ui::MetadataList::Component.new(columns: :two) do |list|
14
+ # list.with_item(label: "Status") { "Active" }
15
+ # list.with_item(label: "Owner") { "Ada Lovelace" }
16
+ # end
17
+ class Component < Poetry::Core::Component
18
+ # Projected into the registry, llms.txt, and the agent surface.
19
+ AGENT_RULES = [
20
+ "Record facts on a detail page belong in a MetadataList - never a hand-rolled grid of " \
21
+ "label/value divs (this is the <dl> the page owes its readers).",
22
+ "Each with_item takes label: and the value as its block - values compose freely " \
23
+ "(text, a Badge, a Link, a Timestamp).",
24
+ "columns: :two / :three spread the facts on wide viewports; orientation: :horizontal " \
25
+ "puts labels beside values (the classic key/value sheet) - pick one per surface.",
26
+ "For editable facts pair each value with its edit affordance inside the item block; " \
27
+ "the list itself stays read-only vocabulary."
28
+ ].freeze
29
+
30
+ # Slots the component cannot render without; static checks read this without rendering.
31
+ REQUIRED_SLOTS = { item: "at least one item (label: plus the value block)" }.freeze
32
+
33
+ renders_many :items,
34
+ doc: "The facts. Each takes label: (the fact's name, the <dt>) and the value as its block (the " \
35
+ "<dd>).",
36
+ renders: lambda { |label:, **options, &block|
37
+ # class: merges through the dictionary (caller classes win on
38
+ # conflicts) - a plain hash merge would REPLACE css(:item).
39
+ item_class = css(:item, class: options.delete(:class))
40
+ content_tag(:div, { "data-slot" => "metadata-list-item", class: item_class }.merge(options)) do
41
+ safe_join([
42
+ content_tag(:dt, label, "data-slot" => "metadata-list-label", class: css(:label)),
43
+ content_tag(:dd, { "data-slot" => "metadata-list-value", class: css(:value) },
44
+ &block)
45
+ ])
46
+ end
47
+ }
48
+
49
+ style :orientation, default: :vertical, variants: %i[vertical horizontal],
50
+ doc: "Label placement - above the value, or beside it for the classic key/value sheet."
51
+ style :columns, default: :one, variants: %i[one two three],
52
+ doc: "How many columns the facts spread across on wide viewports."
53
+
54
+ part "metadata-list", "The <dl> root - the record's fact sheet",
55
+ states: {
56
+ "data-orientation" => { condition: "always - label placement",
57
+ values: %w[vertical horizontal] },
58
+ "data-columns" => { condition: "always - the column count word",
59
+ values: %w[one two three] }
60
+ }
61
+ part "metadata-list-item", "One fact group (a <div> holding its <dt>/<dd> pair)"
62
+ part "metadata-list-label", "The fact's name (<dt>) - muted, small"
63
+ part "metadata-list-value", "The fact's value (<dd>) - composes text, badges, links"
64
+
65
+ # Enforces the required item slot.
66
+ # @api private
67
+ def before_render
68
+ raise ArgumentError, "MetadataList requires at least one with_item" unless items?
69
+ end
70
+
71
+ # @api private
72
+ def call
73
+ content_tag(:dl, safe_join(items.map(&:to_s)), **root_attributes.to_attributes)
74
+ end
75
+
76
+ # @api private
77
+ def root_attributes
78
+ html_attributes.merge_if_not_set(
79
+ { "data-slot" => "metadata-list", "data-orientation" => orientation,
80
+ "data-columns" => columns }.merge(component_data_attributes)
81
+ )
82
+ end
83
+
84
+ private :root_attributes
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module MetadataList
6
+ class Preview < Poetry::Core::Preview::Base
7
+ def default
8
+ render_component do |list|
9
+ list.with_item(label: "Status") { "Active" }
10
+ list.with_item(label: "Owner") { "Ada Lovelace" }
11
+ list.with_item(label: "Created") { "June 12, 2026" }
12
+ end
13
+ end
14
+
15
+ def two_columns
16
+ render_component(columns: :two) do |list|
17
+ list.with_item(label: "Invoice") { "INV-0042" }
18
+ list.with_item(label: "Amount") { "$1,250.00" }
19
+ list.with_item(label: "Due") { "July 31, 2026" }
20
+ list.with_item(label: "Method") { "ACH transfer" }
21
+ end
22
+ end
23
+
24
+ def horizontal
25
+ render_component(orientation: :horizontal) do |list|
26
+ list.with_item(label: "Environment") { "production" }
27
+ list.with_item(label: "Region") { "us-east-1" }
28
+ list.with_item(label: "Version") { "2.14.0" }
29
+ end
30
+ end
31
+
32
+ def three_columns
33
+ render_component(columns: :three) do |list|
34
+ list.with_item(label: "CPU") { "42%" }
35
+ list.with_item(label: "Memory") { "3.1 GB" }
36
+ list.with_item(label: "Disk") { "58%" }
37
+ list.with_item(label: "Region") { "us-east-1" }
38
+ list.with_item(label: "Uptime") { "14 days" }
39
+ list.with_item(label: "Status") { "Healthy" }
40
+ end
41
+ end
42
+
43
+ # Values compose: a status Badge inside the <dd>.
44
+ def composed_values
45
+ render_component(columns: :two) do |list|
46
+ list.with_item(label: "Status") do
47
+ embed(Poetry::Ui::Badge::Component.new(variant: :success).with_content("Fulfilled"))
48
+ end
49
+ list.with_item(label: "Tracking") { "1Z 999 AA1 01" }
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module MetadataList
6
+ # Utility-only (the Separator/Spinner rule): no upstream cn hook
7
+ # exists for a description list, so the surface is structural
8
+ # utilities on semantic tokens; data-slot selectors are the restyle
9
+ # seam. The horizontal orientation restyles the ITEMS from the root
10
+ # (a root descendant utility outranks the item's own class), so one
11
+ # attribute flip re-lays the whole sheet.
12
+ class Style < Poetry::Core::Style
13
+ base "grid gap-x-8 gap-y-4"
14
+
15
+ variant :columns, {
16
+ one: "grid-cols-1",
17
+ two: "grid-cols-1 sm:grid-cols-2",
18
+ three: "grid-cols-1 sm:grid-cols-3"
19
+ }
20
+
21
+ variant :orientation, {
22
+ vertical: "",
23
+ horizontal: "[&_[data-slot=metadata-list-item]]:grid " \
24
+ "[&_[data-slot=metadata-list-item]]:grid-cols-[minmax(0,8rem)_1fr] " \
25
+ "[&_[data-slot=metadata-list-item]]:items-baseline " \
26
+ "[&_[data-slot=metadata-list-item]]:gap-x-4"
27
+ }
28
+
29
+ element :item, "flex min-w-0 flex-col gap-1"
30
+ element :label, "text-sm text-muted-foreground"
31
+ element :value, "min-w-0 text-sm font-medium break-words"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # A quantity within a known range.
6
+ module Meter
7
+ # A QUANTITY within a known range - battery, disk usage, seats
8
+ # taken, password strength - never the progress of an operation
9
+ # over time (that is Progress; a meter has no indeterminate
10
+ # state). Renders role=meter with a visible caption (label:), a
11
+ # readout, and a filled track; visually it shares Progress's
12
+ # chrome, so themes style both together.
13
+ #
14
+ # @example
15
+ # render Poetry::Ui::Meter::Component.new(value: 62, label: "Storage used")
16
+ class Component < Poetry::Core::Component
17
+ # Projected into the registry, llms.txt, and the agent surface.
18
+ AGENT_RULES = [
19
+ "A quantity within a range is a Meter (disk, seats, strength); an operation's " \
20
+ "completion over time is Progress. There is NO indeterminate meter - unknown " \
21
+ "duration means Spinner.",
22
+ "label: is REQUIRED - the meter's accessible name and visible caption.",
23
+ "value_text: replaces the visible readout verbatim (\"3 of 4 seats\"); without it " \
24
+ "the readout shows the percentage of the RANGE. No aria-valuetext - ARIA 1.2 " \
25
+ "deprecated it on role=meter; aria-valuenow carries the value."
26
+ ].freeze
27
+
28
+ option :value, :integer, required: true, doc: "The measured quantity, clamped into min:..max:."
29
+ option :min, :integer, default: 0, doc: "The range's lower bound."
30
+ option :max, :integer, default: 100, doc: "The range's upper bound - must exceed min:."
31
+ option :label, :string, required: true, doc: "The meter's accessible name and visible caption."
32
+ option :value_text, :string,
33
+ doc: "Verbatim human-readable value (\"3 of 4 seats\") replacing the percentage readout. Visible " \
34
+ "readout only - ARIA 1.2 deprecated aria-valuetext on role=meter, so aria-valuenow carries the " \
35
+ "value."
36
+ option :show_value, :boolean, default: true, doc: "Set false to hide the visible readout."
37
+
38
+ part "meter", "Root (role=meter, aria-value*, and the accessible name); label, " \
39
+ "readout, and track stack here"
40
+ part "meter-label", "The visible caption span (label:)"
41
+ part "meter-value", "The readout - value_text: verbatim, else the range percentage; " \
42
+ "renders unless show_value: false"
43
+ part "meter-track", "The full-width rail (Progress's cn chrome)"
44
+ part "meter-indicator", "The filled bar - inline width percentage of the range"
45
+
46
+ # Enforces the required label and a coherent range.
47
+ # @api private
48
+ def before_render
49
+ raise ArgumentError, "Meter requires label: (the meter's accessible name)" if label.blank?
50
+ raise ArgumentError, "Meter max: must exceed min:" unless max > min
51
+ end
52
+
53
+ # @api private
54
+ def call
55
+ content_tag(:div, root_attributes.to_attributes) do
56
+ safe_join([label_part, value_part, track].compact)
57
+ end
58
+ end
59
+
60
+ # The fraction of the RANGE - (value - min)/(max - min), never the
61
+ # raw value.
62
+ # @api private
63
+ def percent
64
+ ((clamped - min).to_f / (max - min) * 100).clamp(0, 100)
65
+ end
66
+
67
+ # @api private
68
+ def readout
69
+ value_text.presence || "#{percent.round}%"
70
+ end
71
+
72
+ # The role is the single token "meter" - a two-token fallback
73
+ # ("meter progressbar") makes checkers treat the element as generic
74
+ # and flag every aria-value* attribute.
75
+ # @api private
76
+ def root_attributes
77
+ html_attributes.merge_if_not_set(
78
+ {
79
+ "data-slot" => "meter", "role" => "meter",
80
+ # No aria-valuetext: ARIA 1.2 deprecated it on role=meter -
81
+ # the visible readout carries the human string, aria-valuenow
82
+ # the value.
83
+ "aria-valuemin" => min, "aria-valuemax" => max, "aria-valuenow" => clamped,
84
+ "aria-label" => label
85
+ }.merge(component_data_attributes)
86
+ )
87
+ end
88
+
89
+ private
90
+
91
+ def clamped
92
+ value.clamp(min, max)
93
+ end
94
+
95
+ def label_part
96
+ content_tag(:span, label, "data-slot" => "meter-label", class: Progress::Style.css(:label))
97
+ end
98
+
99
+ def value_part
100
+ return unless show_value
101
+
102
+ content_tag(:span, readout, "data-slot" => "meter-value", class: Progress::Style.css(:value))
103
+ end
104
+
105
+ def track
106
+ content_tag(:div, "data-slot" => "meter-track", class: Progress::Style.css(:track)) do
107
+ content_tag(:div, nil, "data-slot" => "meter-indicator",
108
+ class: Progress::Style.css(:indicator),
109
+ style: "width: #{percent.round(4)}%")
110
+ end
111
+ end
112
+
113
+ private :percent, :readout, :root_attributes
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Meter
6
+ class Preview < Poetry::Core::Preview::Base
7
+ def default
8
+ render_component(value: 62, label: "Storage used")
9
+ end
10
+
11
+ # value_text: replaces the readout AND aria-valuetext verbatim.
12
+ def with_value_text
13
+ render_component(value: 3, max: 4, label: "Seats", value_text: "3 of 4 seats")
14
+ end
15
+
16
+ # A non-zero minimum: the readout is the fraction of the RANGE.
17
+ def with_range
18
+ render_component(value: 210, min: 100, max: 300, label: "Battery voltage",
19
+ value_text: "210 V")
20
+ end
21
+
22
+ def without_readout
23
+ render_component(value: 45, label: "Password strength", show_value: false)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Meter
6
+ # Progress's chrome verbatim (the NumberField composition precedent):
7
+ # the template calls Progress::Style.css for track/indicator/label/
8
+ # value, so the themes' cn-progress-* rules dress meters too - zero
9
+ # new theme CSS, and a theme that restyles progress restyles meters
10
+ # with it. The root only stacks.
11
+ class Style < Poetry::Core::Style
12
+ base "flex flex-wrap gap-3"
13
+ end
14
+ end
15
+ end
16
+ end