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,152 @@
1
+ # Component anatomy - the canonical section order
2
+
3
+ Every poetry component class reads top to bottom in the same order.
4
+ The order is chosen so a reader meets the component the way an agent
5
+ consumes its contract: identity, vocabulary, surface, behavior,
6
+ arguments, structure, then implementation.
7
+
8
+ ## The order
9
+
10
+ | # | Section | Declares |
11
+ |---|---------|----------|
12
+ | 1 | Includes & class config | `include` / `extend`, `internal_component!`, `requires_content`, `delegate`, `with_collection_parameter` |
13
+ | 2 | Constants | vocabularies first (`VARIANTS`, `SIZES`, ...), then the agent contract (`AGENT_RULES`, `REQUIRES_ANY`, `SLOT_RENDERS`) |
14
+ | 3 | Slots | `renders_one` / `renders_many` |
15
+ | 4 | Stimulus | `use_stimulus do ... end` |
16
+ | 4b | Agent tools | `tool :name, executes:, ...` (interactive components; optional) |
17
+ | 5 | Styles & options | `style` declarations, then `option` declarations |
18
+ | 6 | Validations | `validates` / `validate` |
19
+ | 7 | Parts | `part` declarations |
20
+ | 8 | Lifecycle | `initialize`, `before_render`, `call` - in that order |
21
+ | 9 | Public methods | everything else callable from templates or callers |
22
+ | 10 | Private methods | under a single `private` |
23
+ | 11 | Nested classes | builder / internal classes, last |
24
+
25
+ ## Why this order
26
+
27
+ - **Constants come before the DSL calls that read them.** Ruby
28
+ evaluates the class body top to bottom; `style :variant, variants:
29
+ VARIANTS` needs `VARIANTS` already defined. Putting every constant in
30
+ one early section satisfies this everywhere at once.
31
+ - **The agent contract lives with the constants.** `AGENT_RULES`,
32
+ `REQUIRES_ANY`, and `SLOT_RENDERS` are data the machine surfaces
33
+ project; grouping them right after the vocabularies keeps the whole
34
+ published contract readable in one screen.
35
+ - **Slots before behavior, behavior before arguments.** What the
36
+ component holds (slots), how it acts (Stimulus), what it accepts
37
+ (styles, options, validations), what it renders (parts). Each section
38
+ answers the next question a reader has.
39
+ - **Lifecycle heads the public methods.** `initialize` is the first
40
+ public method anyone looks for; `before_render` and `call` follow it
41
+ so the render path reads as one block.
42
+
43
+ ## Hard rules
44
+
45
+ 1. **Never reorder declarations within a section.** Option, part, and
46
+ slot order is projected into the registry and the agent surface in
47
+ declaration order. Moving a whole section preserves it; shuffling
48
+ inside a section changes a machine surface.
49
+ 2. **One `private` keyword.** Everything below it is private; no
50
+ interleaving public and private methods.
51
+ 3. **Inner classes declare `internal_component!`** when they inherit
52
+ the component machinery but are not published components in their
53
+ own right.
54
+ 4. **Nested classes sit at the end of the class but above the
55
+ `private` divider.** A constant is never private-scoped, so placing
56
+ one below `private` is misleading (and linters flag it). A nested
57
+ class a class-body DSL call evaluates must stay above that call
58
+ instead.
59
+ 5. **`frozen_string_literal: true`** heads every file.
60
+
61
+ ## Skeleton
62
+
63
+ ```ruby
64
+ # frozen_string_literal: true
65
+
66
+ module MyApp
67
+ module Callout
68
+ # A bordered notice that frames one message and an optional action.
69
+ # Reaches for the semantic-role tokens, so every theme styles it
70
+ # without per-instance CSS.
71
+ #
72
+ # @example Basic usage
73
+ # render MyApp::Callout::Component.new(variant: :info) { "Saved." }
74
+ class Component < Poetry::Core::Component
75
+ requires_content "the message body"
76
+
77
+ VARIANTS = %i[info success warning danger].freeze
78
+
79
+ AGENT_RULES = [
80
+ "Use Callout for inline notices - never a hand-styled div.",
81
+ "Pick the variant by intent; danger is reserved for destructive outcomes."
82
+ ].freeze
83
+
84
+ renders_one :action
85
+
86
+ use_stimulus do
87
+ controller :callout do
88
+ target :dismiss
89
+ end
90
+ end
91
+
92
+ style :variant, default: :info, required: true, variants: VARIANTS
93
+
94
+ option :dismissible, :boolean, default: false
95
+
96
+ validates :variant, inclusion: { in: VARIANTS }
97
+
98
+ part "root", "The bordered container - variant state rides here",
99
+ states: { "data-variant" => { condition: "always", values: VARIANTS.map(&:to_s) } }
100
+ part "action", "Wrapper around the action slot"
101
+
102
+ def initialize(...)
103
+ super
104
+ end
105
+
106
+ def before_render
107
+ ensure_content!
108
+ end
109
+
110
+ def dismiss_label
111
+ t(".dismiss")
112
+ end
113
+
114
+ private
115
+
116
+ def css
117
+ # section-level styles resolved by the style DSL
118
+ end
119
+ end
120
+ end
121
+ end
122
+ ```
123
+
124
+ ## Agent tools (the operate surface)
125
+
126
+ Beside `use_stimulus`, an interactive component may declare the tools an
127
+ in-page agent (WebMCP, `document.modelContext`) can invoke on a rendered
128
+ instance. Each tool is MCP `Tool`-shaped and dispatches to one of the
129
+ component's OWN Stimulus actions, positionally in declared parameter order:
130
+
131
+ ```ruby
132
+ tool :set_value,
133
+ description: "Activate the tab whose value matches and show its panel.",
134
+ params: { value: { type: "string", required: true, description: "The tab's value." } },
135
+ executes: :set_value, # a declared controller action - validated at class load
136
+ mutating: true # read-only by default; the annotation says which
137
+ ```
138
+
139
+ Rules: declare `use_stimulus` first; keep `executes:` bare (`:open`) when a
140
+ subclass may re-controller the root (Sheet over Dialog) - it re-resolves per
141
+ class; descriptions are positive, single-purpose, at most 500 characters.
142
+ Override `webmcp_tool_definition(definition)` to refine a schema with what
143
+ only the rendered instance knows (Tabs adds its tab values as the enum).
144
+ Nothing registers until a call opts in: `poetry_tabs(webmcp: "sections")`.
145
+ The registry projects tools to llms-full.txt, `describe_component`, and the
146
+ docs page; `poetry:check` gates the opt-ins (`webmcp-without-tools`,
147
+ `webmcp-name`, `webmcp-duplicate-name`).
148
+
149
+ A component may not need every section - Button has no `use_stimulus`,
150
+ static components have no validations. Skip absent sections entirely;
151
+ never leave placeholder comments for them. The sections that are
152
+ present appear in this order.
@@ -0,0 +1,67 @@
1
+ # Component audit checklist
2
+
3
+ Run this against one component file at a time, top to bottom - the
4
+ checks are ordered so violations surface in file order. The audit has
5
+ two passes: structure, then documentation. It never changes behavior:
6
+ rendered output, projected surfaces, and test results are identical
7
+ before and after an audit fix, except where a projected string was
8
+ itself the finding.
9
+
10
+ ## Pass 1 - structure
11
+
12
+ - [ ] `# frozen_string_literal: true` heads the file.
13
+ - [ ] Sections present appear in canonical order: includes & class
14
+ config → constants → slots → stimulus → styles & options →
15
+ validations → parts → lifecycle → public methods → private
16
+ methods → nested classes. (Absent sections are skipped, not
17
+ stubbed.)
18
+ - [ ] Constants: vocabularies before the agent contract
19
+ (`AGENT_RULES`, `REQUIRES_ANY`, `SLOT_RENDERS`); every constant
20
+ above the first DSL call that reads it; all `.freeze`d.
21
+ - [ ] No declaration was reordered *within* its section - option,
22
+ part, and slot order projects in declaration order. Verify with
23
+ the diff, not by eye.
24
+ - [ ] Lifecycle methods (`initialize`, `before_render`, `call`) lead
25
+ the public methods, in that order.
26
+ - [ ] Exactly one `private` keyword; nothing public below it.
27
+ - [ ] Inner machinery classes declare `internal_component!`.
28
+ - [ ] Nested classes sit last in the class body, above the `private`
29
+ divider (constants are never private-scoped).
30
+
31
+ ## Pass 2 - documentation
32
+
33
+ - [ ] Class docblock: purpose in 1-3 sentences + at least one
34
+ `@example` (published components); `@api private` one-liner
35
+ (internal components).
36
+ - [ ] Public methods with non-obvious signatures carry `@param` /
37
+ `@return`; examples where usage isn't clear from the signature.
38
+ - [ ] Projected strings (part descriptions, agent rules, option
39
+ descriptions, `requires_content` hints) read consumer-facing:
40
+ concrete DOM reality, explicit conditions, imperative rules.
41
+ - [ ] No internal references anywhere in comments: no planning-doc or
42
+ decision-index citations, no milestone names, no links to
43
+ private notes. Reasoning is stated inline or removed.
44
+ - [ ] No other library named in any comment or string (notices file
45
+ excepted).
46
+ - [ ] No narration comments (restating the next line) and no
47
+ reviewer-addressed comments.
48
+ - [ ] Comment prose is complete sentences; abbreviations only if a
49
+ newcomer reads them cold.
50
+
51
+ ## Verification
52
+
53
+ - [ ] Full suite green.
54
+ - [ ] `git diff` shows only: comment changes, section moves, doc
55
+ strings intentionally rewritten. No logic lines changed.
56
+ - [ ] If a projected string changed: the registry / agent-surface /
57
+ check tests that assert on it were updated in the same change,
58
+ and the new text is an improvement for the consumer, not a
59
+ paraphrase.
60
+ - [ ] `yard doc` (or the gem's docs build) runs warning-clean on the
61
+ touched files.
62
+
63
+ ## Recording findings that are out of scope
64
+
65
+ Anything discovered that is *not* structure or documentation - a bug, a
66
+ missing validation, a contract gap - does not get fixed in an audit
67
+ pass. Record it separately and keep the audit diff clean.
@@ -0,0 +1,137 @@
1
+ # Documentation standard
2
+
3
+ poetry components carry two kinds of documentation, and they have
4
+ different readers. YARD comments serve the person or agent reading the
5
+ source; projected strings (part descriptions, agent rules, option
6
+ metadata) are published verbatim through the registry, the agent
7
+ surface, and the docs. Write each for its consumer.
8
+
9
+ ## The class docblock
10
+
11
+ Every published component class opens with a YARD docblock:
12
+
13
+ - **One to three sentences** on what it renders and when to reach for
14
+ it. Present tense, no history. This is the *reference lead* - a public
15
+ reader with zero codebase context must parse every word.
16
+ - Optionally ONE short paragraph of load-bearing behavior facts a USER
17
+ needs (keyboard behavior, required slots, form participation), written
18
+ to stand alone. Maintainer rationale is a different register: it lives
19
+ as a plain comment above the method it concerns, never in the class
20
+ docblock. Whole docblock ≤ 15 lines.
21
+ - **One `@example`** showing minimal usage through the helper or
22
+ `render`. Add a second example only when the primary axis (variant,
23
+ size, slots) isn't obvious from the first.
24
+ - Internal component classes (`internal_component!`) get a one-line
25
+ comment and `@api private` instead.
26
+
27
+ ```ruby
28
+ # Renders a dismissible inline notice with an optional action slot.
29
+ # Variants map to semantic intent, so themes restyle it wholesale.
30
+ #
31
+ # @example
32
+ # render MyApp::Callout::Component.new(variant: :success) { "Saved." }
33
+ class Component < Poetry::Core::Component
34
+ ```
35
+
36
+ ## Public methods
37
+
38
+ - YARD tags (`@param`, `@return`, `@example`) on every public method
39
+ whose signature or return isn't obvious from the name.
40
+ - Template-facing methods (`*_attributes`, `*_id`, `*_classes`, part
41
+ builders) and lifecycle overrides (`initialize`, `before_render`,
42
+ `call`) carry a one-line comment ending in `@api private` - they are
43
+ public for the template's sake, not the consumer's, and the doc set
44
+ hides them.
45
+ - Hand-written slot writers a caller uses (`with_*`) are real public
46
+ API: full docs, never `@api private`.
47
+ - Markdown markup; full sentences; wrap at the file's prevailing width.
48
+
49
+ ## Declaration docs
50
+
51
+ Every `option` and `style` carries a `doc:` string, and every
52
+ `renders_one`/`renders_many` carries one too - with `renders:` passing
53
+ the slot's lambda as a keyword so the doc reads first. (`slot_doc` is
54
+ the fallback for a doc declared away from its declaration, e.g. in a
55
+ different module.) That string is the declared surface's documentation everywhere at
56
+ once - the registry (option/style/slot descriptions), llms.txt and the
57
+ agent surface, the component page's API section, and the generated API
58
+ reference - with the machine facts (type, default, variants)
59
+ auto-appended, so the prose adds MEANING only:
60
+
61
+ - One sentence, two at most: the caller-visible effect and its
62
+ interactions ("Ignored unless `tag: :a`."), never the implementation
63
+ ("sets @foo").
64
+ - Never repeat the type, default, or variant list - the projections
65
+ carry those already.
66
+
67
+ ```ruby
68
+ option :loading, :boolean, default: false,
69
+ doc: "The no-JS loading state: aria-busy, a spinner, and the control disabled."
70
+
71
+ renders_one :leading, doc: "Optional leading visual, rendered inside the icon span."
72
+
73
+ renders_one :trigger,
74
+ doc: "The button that opens the dialog.",
75
+ renders: lambda { |**options, &block| ... }
76
+ ```
77
+
78
+ Constants that define the surface get one-liners too: vocabulary arrays
79
+ ("The closed vocabulary for the variant axis."), `AGENT_RULES`
80
+ ("Projected into the registry, llms.txt, and the agent surface.").
81
+
82
+ ## Private methods
83
+
84
+ Plain comments, and only where the *why* isn't visible in the code. A
85
+ private method whose name states its job needs no comment.
86
+
87
+ ## Projected strings
88
+
89
+ Part descriptions, agent rules, option and slot descriptions, and
90
+ `requires_content` hints are machine-published documentation:
91
+
92
+ - Write for the consumer who has never seen the source: name the DOM
93
+ reality ("the rendered control itself"), the condition ("loading: is
94
+ set"), the rule ("icon-only buttons MUST pass label:").
95
+ - No abbreviations that only make sense inside this codebase.
96
+ - Agent rules are imperatives: what to do, what never to do, one rule
97
+ per entry.
98
+
99
+ ## What comments never contain
100
+
101
+ Comments explain the component to its next reader. Reasoning stands on
102
+ its own - state the constraint, not where it came from:
103
+
104
+ - **No internal references**: planning documents, decision indexes,
105
+ milestone names, issue numbers, links into private notes. If the
106
+ reasoning matters, write the reasoning; the citation is noise to
107
+ every reader who isn't the author.
108
+ - **No other libraries**: naming another library belongs in
109
+ `THIRD_PARTY_NOTICES.md` when code was adapted, and nowhere
110
+ otherwise. "The base-contract rule: an icon-only control without an
111
+ accessible name never ships" carries the rule; attribution lives in
112
+ the notices file.
113
+ - **No narration**: nothing that restates what the next line does, and
114
+ nothing addressed to a reviewer ("this is correct because..."). A
115
+ comment earns its place by stating a constraint the code can't show.
116
+
117
+ ## YARD setup
118
+
119
+ Each gem carries a `.yardopts` (markdown markup, README as the index,
120
+ `--hide-api private`, previews and generator templates excluded,
121
+ CHANGELOG and notices as extra files) and loads the shared handler kit
122
+ (`poetry-core/yard/poetry_yard.rb`), which makes the declarative
123
+ surfaces - `class_methods do`, `option`/`style` readers, slot writers,
124
+ `part` anatomy - visible to the doc build.
125
+
126
+ Gates, from the gem root:
127
+
128
+ - `rake yard:verify` - fails on any warning (an unresolvable reference
129
+ or malformed tag is a review finding; structural warnings are
130
+ allowlisted in the task).
131
+ - `rake yard:coverage` - the ratchet: fails when the undocumented-object
132
+ count exceeds the committed `.yard_coverage` floor. After a
133
+ documentation pass, lower the floor with `rake yard:coverage:record`.
134
+
135
+ Previews are OUTSIDE the doc set: preview.rb comments are for gallery
136
+ authors (Lookbook tags like `@label`/`@!group` live there) and are never
137
+ published.
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: poetry-design
3
+ description: >-
4
+ Design guidance for building poetry UIs: theme selection, page
5
+ composition (macrostructure, hierarchy, containment, status color),
6
+ the visual audit of a finished screen, and studying a brand into a
7
+ DESIGN.md. Load this WHENEVER building, composing, or restyling a
8
+ page, screen, dashboard, or view with poetry - alongside the poetry
9
+ usage skill, before composing - not only when the task mentions
10
+ design.
11
+ ---
12
+
13
+ # poetry-design - the taste layer
14
+
15
+ poetry's catalog guarantees valid, accessible components; this skill covers
16
+ the decisions the catalog cannot make for you: which theme, what
17
+ macrostructure, whether the finished page reads well. Any task that builds
18
+ a PAGE is a design task - load this before composing, not after something
19
+ looks wrong. It works through tokens, variants, themes, and DESIGN.md -
20
+ **never per-instance CSS** (that reintroduces the drift the system exists
21
+ to prevent).
22
+
23
+ ## Verbs
24
+
25
+ - **theme** (`references/theme.md`) - pick or adapt one of the nine shipped
26
+ themes; wire a brand in through the DESIGN.md import door.
27
+ - **compose** (`references/compose.md`) - shape a page BEFORE building it:
28
+ macrostructure, hierarchy, framing, content realism. The checklist here
29
+ is distilled from judged head-to-head runs.
30
+ - **audit** (`references/audit.md`) - review a finished screen: run the
31
+ deterministic design-lint tier first, then the critique checklist for
32
+ what detectors cannot see.
33
+ - **study** (`references/study.md`) - extract a brand's design DNA into a
34
+ DESIGN.md poetry can import; `redesign` = keep the content, swap the
35
+ fingerprint.
36
+ - **figma** (`references/figma.md`) - bring a Figma design into poetry:
37
+ import its variables as an AA-gated theme, or translate a selection into
38
+ components across the Figma + poetry MCPs.
39
+ - **paper** (`references/paper.md`) - bring a paper.design canvas into
40
+ poetry: import its theme, or translate the canvas across the Paper +
41
+ poetry MCPs.
42
+
43
+ ## Working rules
44
+
45
+ - Deterministic first: run the linters before offering opinions - most slop
46
+ is mechanically detectable, and every rule names its fix.
47
+ - Express every fix through a token, variant, option, theme, or DESIGN.md
48
+ override. If a fix seems to need hand-written CSS, the real fix is a
49
+ different composition (or an upstream gap worth reporting). The one
50
+ sanctioned exception: a DECLARED `cn-*` override - host CSS restyling a
51
+ theme-owned class, recorded with a reason under `overrides:` in
52
+ config/poetry_components.yml after the user confirms intent
53
+ (`bin/rails poetry:design:overrides` reports drift). Never declare an
54
+ override to skip a fix.
55
+ - For component contracts (options, slots, variants), load the `poetry`
56
+ usage skill; this skill assumes you compose through it.
@@ -0,0 +1,123 @@
1
+ # audit - review a finished screen
2
+
3
+ Deterministic first, judgment second. Most AI-UI slop is mechanically
4
+ detectable; run the machines before offering opinions. And the machines
5
+ also run LAST: any edit the audit produces re-opens the gate - finish
6
+ with a clean `poetry:check` run AFTER the final edit, never before it.
7
+
8
+ ## Run the linters
9
+
10
+ - `bin/rails poetry:check` - the hard gate: unknown components, options,
11
+ variants, icon names, arity, wiring. Errors block; fix them first.
12
+ - `POETRY_CHECK_DESIGN=1 bin/rails poetry:check` - adds the design-slop
13
+ tier (warnings; the taste tier). `POETRY_CHECK_JSON=1` for machine
14
+ output; both accept a glob argument for one file.
15
+ - `bin/rails poetry:verify` - classes vs the compiled CSS (catches classes
16
+ that never compiled, i.e. styles silently not applying).
17
+
18
+ ## The design-lint rules (what each catches)
19
+
20
+ Every finding names its fix in the message. The 23 rules:
21
+
22
+ - `card-in-card` - a Card nested in a Card; flatten to one containment level.
23
+ - `icon-tile-over-heading` - the decorative icon-in-a-tile stacked above
24
+ every heading; the stock AI-UI tell.
25
+ - `wall-of-cards` - everything boxed identically; vary the surface or merge
26
+ regions.
27
+ - `off-scale-arbitrary` - `w-[347px]`-style values that sit off the scale;
28
+ use the scale spelling.
29
+ - `gradient-off-token` - gradients built from palette utilities instead of
30
+ tokens.
31
+ - `heading-skip` - h1 -> h3 ladder skips (remember Card titles default h3;
32
+ pass `title_tag:`).
33
+ - `mixed-status-weight` - solid and soft status pills mixed in one table;
34
+ keep one treatment family per surface.
35
+ - `center-everything` - body copy and controls center-aligned page-wide;
36
+ center is for empty states and heroes.
37
+ - `shadow-stack` - stacked/oversized shadows on nested surfaces.
38
+ - `type-scale-monotony` - all content text at one size; hierarchy needs a
39
+ scale (DOM tier - reads computed styles).
40
+ - `adjacent-same-surface` - sibling regions with identical surfaces and no
41
+ separation (DOM tier).
42
+ - `contrast-adjacent` - adjacent text failing contrast against its own
43
+ surface (DOM tier).
44
+ - `stock-theme-nudge` - the app still wears the stock look while a foreign
45
+ DESIGN.md is present (DOM tier).
46
+ - `em-dash-overuse` - five or more em dashes in the page copy; the LLM
47
+ prose tell. Rewrite most as periods, commas, or parentheses.
48
+ - `marketing-buzzword` - stock SaaS phrases ("streamline your",
49
+ "enterprise-grade"); say what the product concretely does.
50
+ - `aphoristic-cadence` - "Not a X. Y." / "No X. Just Y." constructions;
51
+ one lands, three read as generated copy.
52
+ - `numbered-section-markers` - sequential 01/02/03 editorial markers; cut
53
+ the numbers or vary the section anatomy.
54
+ - `repeated-section-kickers` - a tracked-caps kicker above every section
55
+ heading; keep at most one.
56
+ - `hero-eyebrow-chip` - a text eyebrow directly above the h1; fold it into
57
+ the heading or cut it (badge announcement pills are fine).
58
+ - `oversized-h1` - display-size type (text-7xl+) carrying 40+ characters;
59
+ shorten the headline or step the size down.
60
+
61
+ Motion floor (perception physics, theme-independent - they read the motion
62
+ utilities an element carries):
63
+
64
+ - `motion-ease-in` - a bare `ease-in` on a transition; ease-in decelerates
65
+ into rest, wrong for UI. Use `ease-out` for enters, `ease-in-out` for
66
+ moves (a state-scoped `data-closed:ease-in` exit is fine).
67
+ - `motion-duration-ceiling` - a UI transition over ~500ms (`duration-700`,
68
+ `duration-1000`, `duration-[800ms]`); past ~300ms UI reads as laggy.
69
+ - `motion-scale-from-zero` - an animated element resting at `scale-0`; it
70
+ erupts from nothing. Start from `scale-95` with opacity, not zero.
71
+
72
+ `transition-all` is a REPORT-ONLY advisory (`bin/rake design:motion`), not a
73
+ gate: it animates every property including layout, so prefer the specific
74
+ transition (`transition-colors`, `transition-[color,box-shadow]`,
75
+ `transition-transform`). poetry ships the upstream default, so re-timing it
76
+ is a design decision, surfaced rather than enforced.
77
+
78
+ ## Score it (deterministic)
79
+
80
+ When the audit needs a NUMBER - a PR gate, a before/after, a fleet
81
+ sweep - compute the adherence score from findings, never from a
82
+ subjective sense of overall quality (the spectrum-audit rule).
83
+
84
+ Severity weights, fixed:
85
+
86
+ - **Critical 10** - each `poetry:check` ERROR (unknown component/option/
87
+ variant/icon, arity, wiring, slot misuse). These also block outright.
88
+ - **High 5** - each `poetry:verify` failure (a class that never
89
+ compiled: styling silently not applying).
90
+ - **Medium 2** - each design-slop WARNING (`POETRY_CHECK_DESIGN=1`, the
91
+ twenty rules above).
92
+ - **Low 1** - each critique-checklist finding (the judgment items; name
93
+ the surface for every one you count).
94
+
95
+ Per category: `score = 100 - min(100, sum_of_weights)`. Overall
96
+ adherence = the weighted mean: contracts 40%, compiled styling 25%,
97
+ design slop 25%, critique 10%. Report all four category scores plus the
98
+ overall, each with its finding count - a score with no finding list is
99
+ not a score.
100
+
101
+ ## The critique checklist (what detectors cannot see)
102
+
103
+ Work the rendered page, not the source:
104
+
105
+ 1. **Squint test** - blur your eyes (or shrink the screenshot): does the
106
+ page still have a shape - regions, a focal point, a reading order? If
107
+ it goes uniform gray, hierarchy is missing.
108
+ 2. **One-decision test** - can you say in one sentence what this page most
109
+ wants the user to do? Is that the one filled-primary element?
110
+ 3. **Consistency sweep** - same state, same treatment; same gap rhythm per
111
+ region; aligned edges (one container width, not three).
112
+ 4. **Content honesty** - would a real user's data look like this? Plausible
113
+ distributions, realistic names/dates/amounts, an empty state where the
114
+ data could be empty.
115
+ 5. **Framing** - does the page's subject have breathing room? Does anything
116
+ sit naked at the viewport origin?
117
+
118
+ Report findings in the linters' voice: name the surface, name the fix, and
119
+ express every fix through a token, variant, option, theme, or DESIGN.md
120
+ override - never per-instance CSS. Host CSS already touching `cn-*` classes
121
+ is either a DECLARED override (listed by `bin/rails poetry:design:overrides`;
122
+ respect it - it is recorded design intent) or drift to flag, never silently
123
+ extend.
@@ -0,0 +1,73 @@
1
+ # compose - shape the page before building it
2
+
3
+ Write the shape down first (a sentence per region), then build. Screens
4
+ composed region-by-region from a stated shape consistently beat screens
5
+ grown element-by-element. The five mechanics below are distilled from
6
+ judged head-to-head runs - they are where composed pages win.
7
+
8
+ ## Step 1 is a tool call, not a decision
9
+
10
+ Route the brief through the poetry MCP `compose` tool FIRST (no MCP:
11
+ `bin/rails g poetry:block --list` + the `poetry` skill's
12
+ `references/blocks.md`). If it returns a block, START FROM THAT SOURCE and
13
+ edit in place - do not re-derive the layout from the checklist below.
14
+ Blocks arrive with the five mechanics already composed; a blank file
15
+ arrives with none of them, and reading this checklist does not transfer
16
+ them (measured: screens built from scratch after reading it composed no
17
+ better than screens built without it).
18
+
19
+ For a whole SCREEN, prefer the `build_page` tool over `compose`: it runs
20
+ the guided workflow (probe -> plan -> direct -> snippets -> verify), so the
21
+ page architecture (section order, the states a real screen handles, the
22
+ edge cases), the theme-derived direction, and the source all arrive in
23
+ order, and it finishes on the executable `check` gate. `compose` is the
24
+ single-step router build_page calls at its snippets step; reach for it
25
+ directly for a quick route or a lone component.
26
+
27
+ ## The five mechanics
28
+
29
+ 1. **Containment.** Give each functional region a boundary the eye can
30
+ find: a Card, a bordered `section`, a `bg-muted/50` band. A page of
31
+ floating fragments reads unfinished; a page of nested-cards-in-cards
32
+ reads like slop (the lint catches that direction). One level of
33
+ containment, used consistently.
34
+ 2. **Status color-coding.** Encode state with the status vocabulary
35
+ (Badge `success` / `warning` / `info` / `destructive`), consistently:
36
+ the same state always gets the same variant, and one treatment family
37
+ per surface - solid and soft pills never mix in one table.
38
+ 3. **Contextual framing.** A section that IS the page's subject keeps its
39
+ container and breathing room (`mx-auto max-w-* p-6`); a bare component
40
+ at the viewport origin reads cramped. Drop the wrapper only when
41
+ composing into an already-padded frame (an app shell's content area).
42
+ 4. **Page furniture.** Real screens have a header (title + description +
43
+ primary action), section headings, and end-of-list affordances
44
+ (pagination, a "view all" link). A component demo has none of them; a
45
+ page needs them.
46
+ 5. **Content realism.** Realistic data - names, amounts, dates, statuses in
47
+ plausible distributions (mostly-fulfilled with a few exceptions, not
48
+ one of each) - is part of the design. Lorem ipsum and ALL-states-once
49
+ both read as unfinished.
50
+
51
+ ## Hierarchy and density
52
+
53
+ - One primary action per view; everything else is `outline`, `ghost`, or a
54
+ link. Two filled primary buttons side-by-side is a hierarchy bug.
55
+ - Secondary copy goes `text-muted-foreground` at `text-sm` - contrast
56
+ carries hierarchy more cheaply than size.
57
+ - Respect the heading ladder (h1 -> h2 -> h3, no skips) - note Card titles
58
+ default to h3; pass `title_tag:` when the card sits higher in the page.
59
+ - Space on the built-in scale, consistently: one gap rhythm per region
60
+ (`space-y-4` / `gap-4` family), padding steps from the same scale.
61
+ - Destructive flows: tinted boundary + plain-language consequences in
62
+ AA-clean muted copy; the alert carries icon + title only (description
63
+ copy on the destructive tint fails AA).
64
+ - Rich navigation panels (title + description grids) want
65
+ `poetry_navigation_menu(viewport: true)` - the morphing-card mode that
66
+ keeps panel content contained.
67
+
68
+ ## Iterate against the render
69
+
70
+ Screenshot or render what you built and look at it before calling it done
71
+ - then run the audit pass (`references/audit.md`). The linters read both
72
+ ERB source and rendered HTML; what they can't see, the critique checklist
73
+ covers.
@@ -0,0 +1,68 @@
1
+ # figma - bring a Figma design into poetry
2
+
3
+ Two doors, independent. Take the first for a palette/theme handoff; the
4
+ second when a whole frame must become working components. Both translate
5
+ INTO poetry primitives and tokens - never transcribe Figma's absolute
6
+ positions, raw hex, or pixel gaps into markup.
7
+
8
+ ## Door 1: variables -> an AA-gated theme (no paywall, no MCP)
9
+
10
+ Figma variables become poetry token overrides through the same importer a
11
+ DESIGN.md uses, so imported swatches inherit poetry's contrast law.
12
+
13
+ 1. In Figma, export the variables as JSON with a free plugin - **Tokens
14
+ Studio** or **Design Tokens** (six7). These use the Plugin API, which
15
+ reads variables on every plan; the REST Variables API is Enterprise-only,
16
+ so do not rely on it.
17
+ 2. Run `bin/rails poetry:figma:import[variables.json]` (or
18
+ `poetry:design:import` - it detects `.json`).
19
+ 3. **Read the report.** The importer walks DTCG groups and modes, resolves
20
+ `{aliases}`, flattens `primary/DEFAULT` and `primary/foreground`, converts
21
+ hex / rgb / DTCG-object / oklch into poetry's OKLCH model, then measures
22
+ every touched pair against WCAG AA. A swatch that fails AA is **dropped
23
+ and reported with the nearest passing value** - never shipped. Anything
24
+ with no poetry role is dropped and listed too; the importer never guesses.
25
+ 4. It writes `app/assets/tailwind/poetry/design-overrides.css` and wires the
26
+ import. Rebuild CSS. `POETRY_DESIGN_FORCE=1` ships failing pairs on
27
+ purpose (rarely right); `POETRY_DESIGN_JSON=1` prints a machine report.
28
+
29
+ Names that do not match a poetry role (`color/brand/600`, say) are dropped,
30
+ not invented. Rename in Figma toward poetry's semantic roles (`background`,
31
+ `foreground`, `primary`, `muted-foreground`, `border`, ...) and re-run.
32
+
33
+ ## Door 2: a selection -> components (dual-MCP)
34
+
35
+ Needs the **Figma MCP** connected alongside the poetry MCP in one agent. The
36
+ remote server (`https://mcp.figma.com/mcp`) reads files by node id on all
37
+ plans; the live current-selection path (`get_variable_defs` in context)
38
+ wants the desktop app plus a Dev or Full seat. The server is in beta.
39
+
40
+ Flow:
41
+
42
+ 1. Read the design - `get_design_context` (React + Tailwind by default),
43
+ `get_variable_defs` (the tokens a selection uses), `get_screenshot` (keep
44
+ layout fidelity).
45
+ 2. Land the tokens first via Door 1 so Figma's variables line up with poetry
46
+ theme tokens; reconcile, do not duplicate.
47
+ 3. Translate, do not copy. Map each Figma node to the nearest poetry
48
+ primitive - consult `list_components` / `describe_component`; assemble
49
+ with `compose` / `build_page`, never hand-authored markup.
50
+ 4. Run poetry `check` LAST - a PASS verdict, not an eyeball.
51
+
52
+ Mapping guide:
53
+
54
+ - Auto-layout frame -> a poetry block or a page section (`compose` routes it).
55
+ - Component instance -> the nearest poetry component; its variant property ->
56
+ the poetry `variant` option, not a new class.
57
+ - Text -> component content / slots.
58
+ - Color, spacing, radius tokens -> poetry theme tokens (Door 1), never
59
+ per-instance CSS.
60
+
61
+ Optional: the Figma `create_design_system_rules` prompt writes a rule file
62
+ that teaches Figma's codegen agent poetry's conventions - point it here so
63
+ token names and helper calls come out right.
64
+
65
+ Code Connect (Dev Mode showing `poetry_button(...)` ERB) is possible through
66
+ `*.figma.ts` template files, but it needs an Org/Enterprise plan, a Dev/Full
67
+ seat, and a Figma UI kit poetry does not ship yet. Treat it as a later,
68
+ enterprise-tier path, not a prerequisite.