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,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # Removable-chip collections.
6
+ module TagGroup
7
+ # A collection of removable chips - recipients, filters, labels.
8
+ # The group is one Tab stop with grid semantics: arrow keys move
9
+ # between tags, Delete/Backspace removes the focused tag, each
10
+ # chip's remove button removes exactly its own, and focus recovers
11
+ # to a neighbor after a removal. With name: the group is a form
12
+ # value - one hidden name[] input submits per tag. Removal is
13
+ # cancelable via the poetry:tag-group:remove event, so a server
14
+ # (Turbo) re-render can own it instead.
15
+ #
16
+ # label: is required - it names the grid for assistive tech. Tags
17
+ # here are removal-only: toggling fixed choices is ToggleGroup,
18
+ # picking from options is Combobox multiple.
19
+ #
20
+ # @example Removable recipients that submit as recipients[]
21
+ # render Poetry::Ui::TagGroup::Component.new(label: "Recipients", name: "recipients") do |group|
22
+ # group.with_tag(value: "ada", label: "Ada")
23
+ # group.with_tag(value: "grace", label: "Grace")
24
+ # end
25
+ class Component < Poetry::Core::Component
26
+ # Projected into the registry, llms.txt, and the agent surface.
27
+ AGENT_RULES = [
28
+ "Removable chips are a TagGroup - never hand-rolled badges with x buttons; removal " \
29
+ "keyboard (Delete/Backspace), focus recovery, and the live region ride the controller.",
30
+ "label: is REQUIRED (the grid's accessible name, rendered as a caption span).",
31
+ "name: turns the group into a form value - one hidden <name>[] input per tag " \
32
+ "submits; removing a tag removes its input.",
33
+ "Removal is cancelable: listen for poetry:tag-group:remove and preventDefault to " \
34
+ "own the removal server-side (Turbo re-render).",
35
+ "Choosing from options is Combobox multiple; toggling fixed choices is ToggleGroup - " \
36
+ "a TagGroup holds items that exist until removed."
37
+ ].freeze
38
+
39
+ renders_many :tags,
40
+ doc: "Declares one chip. value: is its identity (and form value); label: is the accessible " \
41
+ "name and the visible text when no block is given; removable: false drops the remove " \
42
+ "button.",
43
+ renders: lambda { |value:, label: nil, disabled: false, removable: true, **options, &block|
44
+ tag_row(value: value, label: label, disabled: disabled, removable: removable, **options, &block)
45
+ }
46
+
47
+ # Both controllers declare on the grid element: roving-focus owns
48
+ # the arrow keys, with the group's own keydown (removal keys)
49
+ # layered on the same event.
50
+ use_stimulus do
51
+ on :grid do
52
+ controller :tag_group do
53
+ register
54
+ action :keydown, on: :keydown
55
+ end
56
+ controller :roving_focus do
57
+ register
58
+ value :orientation, :horizontal
59
+ value :loop, true
60
+ action :keydown, on: :keydown
61
+ end
62
+ end
63
+ on :remove do
64
+ controller(:tag_group) { action :remove, on: :click }
65
+ end
66
+ end
67
+
68
+ option :name, :string, doc: "Makes the group a form value: one hidden <name>[] input submits per tag."
69
+ option :label, :string, required: true, doc: "The grid's accessible name, rendered as a caption span. Required."
70
+ option :described_by, :string,
71
+ doc: "Space-separated hint/error ids for the GRID (the labelled element) - a raw aria-describedby in " \
72
+ "html_attributes would land on the outer wrapper div, unassociated for AT."
73
+
74
+ part "tag-group", "The labelled wrapper - caption span + grid stack here"
75
+ part "tag-group-label", "The caption span (label:), wired via aria-labelledby (a grid " \
76
+ "is not a labelable form control - never a <label>)"
77
+ part "tag-group-grid", "The tag collection (role=grid; role=group + the tab stop when " \
78
+ "empty) - roving focus, removal keys, and the focus-scoped " \
79
+ "live region ride here",
80
+ states: {
81
+ "data-empty" => "no tags remain (controller-kept after removals)"
82
+ }
83
+ part "tag-group-tag", "One chip (role=row > gridcell): content, the remove button, " \
84
+ "and - in form mode - the hidden name[] input",
85
+ states: {
86
+ "data-disabled" => "the tag is disabled (skipped by arrows and removal)",
87
+ "data-value" => { condition: "always - the tag's value (the remove event's " \
88
+ "detail and the hidden input's value)" }
89
+ }
90
+ part "tag-group-remove", "The per-tag remove button - tabbable (Tab steps from the " \
91
+ "row into it), removes exactly its own tag"
92
+
93
+ # @api private
94
+ def before_render
95
+ raise ArgumentError, "TagGroup requires label: (the grid's accessible name)" if label.blank?
96
+ end
97
+
98
+ # One instance id (ladder: caller id -> key -> random); every
99
+ # inner id derives from it - so a keyed group's label AND rows are
100
+ # all morph-stable, and rows never touch a group-level allocator.
101
+ # @api private
102
+ def instance_id
103
+ @instance_id ||= poetry_instance_id("poetry-tag-group")
104
+ end
105
+
106
+ # @api private
107
+ def label_id
108
+ "#{instance_id}-label"
109
+ end
110
+
111
+ # @api private
112
+ def root_attributes
113
+ html_attributes.merge_if_not_set(
114
+ { "data-slot" => "tag-group", "class" => css }.merge(component_data_attributes)
115
+ )
116
+ end
117
+
118
+ # @api private
119
+ def grid_attributes
120
+ attrs = {
121
+ "role" => tags.any? ? "grid" : "group",
122
+ "data-slot" => "tag-group-grid",
123
+ "class" => css(:grid),
124
+ "aria-labelledby" => label_id,
125
+ **(described_by.present? ? { "aria-describedby" => described_by } : {}),
126
+ # Polite only while focus is within (controller-flipped): SRs
127
+ # hear tags added mid-work without spam from elsewhere.
128
+ "aria-live" => "off",
129
+ "aria-atomic" => "false",
130
+ "aria-relevant" => "additions"
131
+ }
132
+ attrs["data-empty"] = "" if tags.none?
133
+ attrs["tabindex"] = "0" if tags.none?
134
+ attrs.merge(stimulus_attributes_for(:grid))
135
+ end
136
+
137
+ # Built here (not in the template) so the slot lambda can compose
138
+ # the full row - content, remove button, hidden input - around the
139
+ # consumer's block.
140
+ # @api private
141
+ def tag_row(value:, label:, disabled:, removable:, **options, &block)
142
+ # Rows are the reorderable collection: identity derives from
143
+ # value: (the collection contract - unique within the group),
144
+ # namespaced under the group's instance id so two groups with
145
+ # the same tag values never collide.
146
+ row_id = options[:id].presence ||
147
+ "#{instance_id}-tag-#{Poetry::Core::StableId.key_token(value) || SecureRandom.hex(8)}"
148
+ attrs = {
149
+ "id" => row_id, "role" => "row", "data-slot" => "tag-group-tag",
150
+ "data-value" => value, "data-poetry-collection-item" => "",
151
+ "aria-label" => label || value.to_s,
152
+ "tabindex" => "-1", "class" => css(:tag)
153
+ }
154
+ attrs["data-disabled"] = "" if disabled
155
+
156
+ # Caller options ride along (they were silently discarded before);
157
+ # data-value is RESERVED - the row's collection identity comes
158
+ # from value:, any caller spelling loses.
159
+ options.delete(:"data-value")
160
+ options.delete("data-value")
161
+ merged = Poetry::Core::HTML::Attributes.merged(attrs, options.except(:id))
162
+ merged["data-value"] = value
163
+
164
+ content_tag(:div, merged) do
165
+ content_tag(:span, { "role" => "gridcell", "class" => css(:cell) }) do
166
+ safe_join([
167
+ # label: doubles as the visible content when no block is
168
+ # given (the builder's model-array path renders text-only).
169
+ block ? capture(&block) : label.to_s,
170
+ (remove_button(row_id, disabled: disabled) if removable),
171
+ (hidden_input(value) if name.present?)
172
+ ].compact)
173
+ end
174
+ end
175
+ end
176
+
177
+ private
178
+
179
+ def remove_button(row_id, disabled:)
180
+ button_id = "#{row_id}-remove"
181
+ attrs = {
182
+ "type" => "button", "id" => button_id,
183
+ "data-slot" => "tag-group-remove", "class" => css(:remove),
184
+ # labelledby chains button -> row: "Remove, <tag name>".
185
+ "aria-label" => t("poetry.tag_group.remove"),
186
+ "aria-labelledby" => "#{button_id} #{row_id}"
187
+ }
188
+ attrs["disabled"] = "" if disabled
189
+
190
+ content_tag(:button, attrs.merge(stimulus_attributes_for(:remove))) do
191
+ render(Icon::Component.new(name: :x))
192
+ end
193
+ end
194
+
195
+ def hidden_input(value)
196
+ tag.input(type: "hidden", name: "#{name}[]", value: value)
197
+ end
198
+
199
+ private :instance_id, :label_id, :root_attributes, :grid_attributes, :tag_row
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module TagGroup
6
+ class Preview < Poetry::Core::Preview::Base
7
+ def default
8
+ render_component(label: "Topics") do |group|
9
+ group.with_tag(value: "rails") { "Rails" }
10
+ group.with_tag(value: "hotwire") { "Hotwire" }
11
+ group.with_tag(value: "ruby") { "Ruby" }
12
+ end
13
+ end
14
+
15
+ # Form mode: one hidden topics[] input per tag submits; removing a
16
+ # tag removes its input.
17
+ def as_form_value
18
+ render_component(name: "post[topics]", label: "Topics") do |group|
19
+ group.with_tag(value: "news") { "News" }
20
+ group.with_tag(value: "release") { "Release" }
21
+ end
22
+ end
23
+
24
+ def with_disabled
25
+ render_component(label: "Filters") do |group|
26
+ group.with_tag(value: "status") { "Status: open" }
27
+ group.with_tag(value: "locked", disabled: true) { "Locked" }
28
+ group.with_tag(value: "assignee") { "Assignee: me" }
29
+ end
30
+ end
31
+
32
+ # removable: false - display-only chips keep grid navigation but
33
+ # no removal affordance.
34
+ def without_removal
35
+ render_component(label: "Capabilities") do |group|
36
+ group.with_tag(value: "read", removable: false) { "Read" }
37
+ group.with_tag(value: "write", removable: false) { "Write" }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module TagGroup
6
+ # Utility-only (the Separator/Spinner rule): chips wear the secondary
7
+ # badge treatment in structural utilities on semantic tokens - no
8
+ # upstream cn hook exists for a tag group; data-slot selectors are
9
+ # the restyle seam. The grid carries a focus ring for its empty-state
10
+ # tab-stop role.
11
+ class Style < Poetry::Core::Style
12
+ base "flex w-fit flex-col gap-1.5"
13
+
14
+ element :label, "text-sm font-medium"
15
+ element :grid, "flex flex-wrap items-center gap-1.5 rounded-md outline-none " \
16
+ "focus-visible:ring-[3px] focus-visible:ring-ring/50"
17
+ element :tag, "inline-flex items-center gap-1 rounded-md border border-transparent " \
18
+ "bg-secondary px-2 py-0.5 text-xs font-medium text-secondary-foreground " \
19
+ "outline-none focus-visible:border-ring focus-visible:ring-[3px] " \
20
+ "focus-visible:ring-ring/50 " \
21
+ "data-disabled:pointer-events-none data-disabled:opacity-50"
22
+ element :cell, "contents"
23
+ element :remove, "-mr-0.5 inline-flex size-3.5 items-center justify-center rounded-sm " \
24
+ "opacity-60 outline-none hover:opacity-100 " \
25
+ "focus-visible:ring-2 focus-visible:ring-ring/50 [&_svg]:size-3"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # Multiline free-text inputs.
6
+ module Textarea
7
+ # A multiline free-text input: the native <textarea> with the
8
+ # library's styling and zero JS. It auto-grows with its content via
9
+ # CSS (the field-sizing-content property); browsers without support
10
+ # keep the rows:/minimum-height sizing plus the native resize
11
+ # handle. Label pairing, description wiring, and error state flow
12
+ # in from the Field/FormBuilder layer - use Input for single-line
13
+ # text.
14
+ #
15
+ # @example A free-text field
16
+ # render Poetry::Ui::Textarea::Component.new(name: "bio", rows: 4,
17
+ # placeholder: "Tell us about yourself")
18
+ class Component < Poetry::Core::Component
19
+ # Projected into the registry, llms.txt, and the agent surface.
20
+ AGENT_RULES = [
21
+ "Wire through Field/FormBuilder (control_attributes) - never hand-write the aria plumbing.",
22
+ "Placeholder is NOT a label - pair with Label/Field always.",
23
+ "Use Textarea for free text; Input for single-line; do not bolt a JS autosizer on " \
24
+ "(auto-grow is CSS).",
25
+ "Do not set native required - required flows as aria-required via Field."
26
+ ].freeze
27
+
28
+ option :name, :string, doc: "The submitted field name."
29
+ option :value, :string, doc: "The initial text, rendered as the element's content."
30
+ option :placeholder, :string, doc: "Hint text shown while empty - never a substitute for a label."
31
+ option :rows, :integer,
32
+ doc: "The initial visual rows - the minimum height under CSS auto-grow, and the fixed size in " \
33
+ "browsers without it."
34
+ option :disabled, :boolean, default: false, doc: "Disables the control and forwards to the native element."
35
+ option :invalid, :boolean, default: false,
36
+ doc: "Marks the field errored (aria-invalid + the destructive ring); set by " \
37
+ "Field/FormBuilder from model errors."
38
+
39
+ part "textarea", "The <textarea> element itself - value renders as content; " \
40
+ "auto-grow is the field-sizing-content CSS property, zero JS"
41
+
42
+ # @api private
43
+ def call
44
+ # value as CONTENT (escaped by content_tag - the </textarea>
45
+ # injection surface).
46
+ content_tag(:textarea, value, **root_attributes.to_attributes)
47
+ end
48
+
49
+ # @api private
50
+ def root_attributes
51
+ attrs = { "data-slot" => "textarea" }.merge(component_data_attributes)
52
+ attrs["name"] = name if name.present?
53
+ attrs["placeholder"] = placeholder if placeholder.present?
54
+ attrs["rows"] = rows if rows.present?
55
+ attrs["disabled"] = true if disabled
56
+ attrs["aria-invalid"] = true if invalid
57
+ html_attributes.merge_if_not_set(attrs)
58
+ end
59
+
60
+ private :root_attributes
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Textarea
6
+ # The Textarea preview matrix: the five ported examples (demo,
7
+ # disabled, with-label, with-text, with-button) plus the invalid
8
+ # state and long auto-grown content.
9
+ class Preview < Poetry::Core::Preview::Base
10
+ # @!group States
11
+
12
+ def default
13
+ render_component(placeholder: "Type your message here.")
14
+ end
15
+
16
+ def disabled
17
+ render_component(placeholder: "Type your message here.", disabled: true)
18
+ end
19
+
20
+ def invalid
21
+ render_component(placeholder: "Type your message here.", invalid: true,
22
+ value: "too short")
23
+ end
24
+
25
+ # field-sizing-content auto-grows with the content (Chromium);
26
+ # elsewhere: min-h-16 + the native resize handle.
27
+ def auto_grown
28
+ render_component("aria-label": "Notes", value: "Paragraph one.\n\nParagraph two keeps pushing the height - " \
29
+ "no JS autosizer, the CSS does it.\n\nParagraph three.")
30
+ end
31
+
32
+ def taller_start
33
+ render_component(rows: 8, placeholder: "Starts eight rows tall.")
34
+ end
35
+
36
+ # @!endgroup
37
+
38
+ # @!group Recipes
39
+
40
+ # textarea-with-label parity (Label pairs by for=).
41
+ def with_label
42
+ render_component(Field::Component.new(id: "preview-message", label_text: "Your message")) do
43
+ embed(Component.new(name: "message", placeholder: "Type your message here.",
44
+ id: "preview-message"))
45
+ end
46
+ end
47
+
48
+ # textarea-with-text parity: the hint wires via describedby.
49
+ def with_hint
50
+ field = Field::Component.new(
51
+ id: "preview-bio", label_text: "Bio",
52
+ hint: "Your message will be copied to the support team."
53
+ )
54
+ render_component(field) do
55
+ embed(Component.new(name: "bio", placeholder: "Tell us about yourself",
56
+ **field.control_attributes.transform_keys(&:to_sym)))
57
+ end
58
+ end
59
+
60
+ # Model-error rendering: aria-invalid + error-before-hint.
61
+ def with_error
62
+ field = Field::Component.new(
63
+ id: "preview-report", label_text: "Report",
64
+ hint: "Markdown is supported.", error: "can't be blank", required: true
65
+ )
66
+ render_component(field) do
67
+ embed(Component.new(name: "report", **field.control_attributes.transform_keys(&:to_sym)))
68
+ end
69
+ end
70
+
71
+ # @!endgroup
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module Textarea
6
+ # Re-expressed through the cn-* theme layer. The one behavioral
7
+ # novelty stays inline: field-sizing-content is CSS-only auto-grow
8
+ # (Chromium-first; other engines fall back to min-h-16 + the native
9
+ # resize handle - graceful, no polyfill, no JS autosizer ever).
10
+ # Placeholder color rides the theme (the rhea AA hold - see
11
+ # the Input dictionary note).
12
+ class Style < Poetry::Core::Style
13
+ base "cn-textarea flex field-sizing-content min-h-16 w-full outline-none " \
14
+ "disabled:cursor-not-allowed disabled:opacity-50"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ <%# DateField's template verbatim: native input visible (and THE form
2
+ value) until the controller builds segments into the group. %>
3
+ <%= content_tag(:div, **root_attributes.to_attributes) do %>
4
+ <%= content_tag(:span, "", **Poetry::Core::HTML::Attributes.new(group_attributes).to_attributes) %>
5
+ <%= tag.input(**input_attributes.to_attributes) %>
6
+ <% end %>
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ # Segmented time-of-day editors.
6
+ module TimeField
7
+ # A segmented time editor: hour, minute, and - with seconds: -
8
+ # second segments, each typed or stepped independently. The form
9
+ # value is a native <input type=time> submitting HH:MM[:SS], and
10
+ # without JS that native input simply renders, so the field always
11
+ # works. The user's locale decides 12- vs 24-hour editing (an
12
+ # AM/PM segment appears exactly when the locale is twelve-hour);
13
+ # hour_cycle: pins it explicitly.
14
+ #
15
+ # A TimeField is a DateField specialized to time-of-day - segments
16
+ # share the date-field-* part vocabulary.
17
+ #
18
+ # @example
19
+ # render Poetry::Ui::TimeField::Component.new(
20
+ # name: "starts_at", label: "Start time", value: "09:30"
21
+ # )
22
+ class Component < DateField::Component
23
+ # Projected into the registry, llms.txt, and the agent surface.
24
+ AGENT_RULES = [
25
+ "Time entry is a TimeField (poetry_time_field / form.time_field) - never a masked " \
26
+ "Input or a pair of selects; params[<name>] is HH:MM (HH:MM:SS with seconds:).",
27
+ "12- vs 24-hour follows the user's locale automatically (the dayPeriod segment " \
28
+ "appears only under twelve-hour cycles); hour_cycle: pins it when a product must.",
29
+ "For a date AND a time, compose a DateField and a TimeField side by side - there " \
30
+ "is no datetime component by design."
31
+ ].freeze
32
+
33
+ # EXTENDS DateField's root declaration (extend: true merges into
34
+ # the inherited element) - same date-field controller, two more
35
+ # values; group/input inherit untouched.
36
+ use_stimulus do
37
+ on :root, extend: true do
38
+ controller :date_field do
39
+ value :seconds, true, if: :seconds
40
+ value :hour_cycle, if: -> { hour_cycle.present? }
41
+ end
42
+ end
43
+ end
44
+
45
+ option :seconds, :boolean, default: false, doc: "Adds the seconds segment; the wire format becomes HH:MM:SS."
46
+ option :hour_cycle, :string, doc: "Pins the hour cycle (h12/h23/h11/h24) instead of the locale's."
47
+
48
+ part "time-field", "Root - the controller and the enhanced/disabled surface ride " \
49
+ "here (segments inside share the date-field-* vocabulary)",
50
+ states: {
51
+ "data-enhanced" => "the controller connected and built segments (no JS = the " \
52
+ "native input, visible and styled)",
53
+ "data-disabled" => "disabled: is set",
54
+ "data-invalid" => "invalid: is set (the group wears the destructive ring)"
55
+ }
56
+ part "time-field-group", "The bordered segment row - hidden until enhancement, then " \
57
+ "the editing surface (cn-input chrome, focus-within ring)",
58
+ states: {
59
+ "data-disabled" => "disabled: is set (chrome dims, pointer events off)",
60
+ "data-invalid" => "invalid: is set (destructive border + ring)"
61
+ }
62
+ part "time-field-input", "The native <input type=time> - THE form value in both " \
63
+ "modes; tabindex -1 + aria-hidden once segments exist"
64
+
65
+ private
66
+
67
+ def input_type
68
+ "time"
69
+ end
70
+
71
+ def slot_prefix
72
+ "time-field"
73
+ end
74
+
75
+ def iso(candidate)
76
+ candidate.respond_to?(:strftime) ? candidate.strftime("%H:%M#{":%S" if seconds}") : candidate.to_s
77
+ end
78
+
79
+ def placeholder_iso
80
+ placeholder_value.present? ? iso(placeholder_value) : "12:00#{":00" if seconds}"
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module TimeField
6
+ # The TimeField preview: empty and valued fields, seconds, a pinned
7
+ # 24-hour cycle, disabled, and a pinned locale.
8
+ class Preview < Poetry::Core::Preview::Base
9
+ # Empty: hour/minute placeholders (plus AM/PM under twelve-hour
10
+ # locales) once enhanced; the styled native input before that.
11
+ def default
12
+ render_component(name: "meeting[at]", label: "Start time")
13
+ end
14
+
15
+ def with_value
16
+ render_component(name: "meeting[at]", value: "13:05", label: "Start time")
17
+ end
18
+
19
+ def with_seconds
20
+ render_component(name: "job[cutoff]", value: "09:30:15", seconds: true, label: "Cutoff")
21
+ end
22
+
23
+ # A pinned 24-hour cycle regardless of the page locale.
24
+ def twenty_four_hour
25
+ render_component(name: "shift[start]", value: "21:15", hour_cycle: "h23", label: "Shift start")
26
+ end
27
+
28
+ def disabled
29
+ render_component(name: "meeting[at]", value: "13:05", disabled: true, label: "Start time")
30
+ end
31
+
32
+ # locale: pins the cycle AND the dayPeriod/label language instead
33
+ # of following the page locale.
34
+ def localized
35
+ render_component(name: "termin[um]", value: "14:30", locale: "de-DE", label: "Uhrzeit")
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module Ui
5
+ module TimeField
6
+ # DateField's style verbatim (one segment engine, two components) -
7
+ # including the group/date-field marker name, which the enhanced-
8
+ # input selector keys on. See date_field/style.rb for the rationale.
9
+ class Style < Poetry::Core::Style
10
+ base "group/date-field flex w-full flex-col"
11
+
12
+ element :group,
13
+ "cn-input hidden w-fit min-w-0 select-none items-center tabular-nums " \
14
+ "group-data-[enhanced]/date-field:flex " \
15
+ "focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 " \
16
+ "data-invalid:border-destructive data-invalid:ring-destructive/20 " \
17
+ "dark:data-invalid:ring-destructive/40 " \
18
+ "data-disabled:pointer-events-none data-disabled:opacity-50 " \
19
+ "[&_[data-slot=date-field-segment]]:rounded-sm " \
20
+ "[&_[data-slot=date-field-segment]]:px-0.5 " \
21
+ "[&_[data-slot=date-field-segment]]:outline-none " \
22
+ "[&_[data-slot=date-field-segment]:focus]:bg-accent " \
23
+ "[&_[data-slot=date-field-segment]:focus]:text-accent-foreground " \
24
+ "[&_[data-slot=date-field-segment][data-placeholder]]:text-muted-foreground " \
25
+ "[&_[data-slot=date-field-literal]]:text-muted-foreground"
26
+ element :input, "group-data-[enhanced]/date-field:sr-only"
27
+ end
28
+ end
29
+ end
30
+ end