@adia-ai/web-components 0.8.40 → 0.8.42

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 (410) hide show
  1. package/CHANGELOG.md +71 -3
  2. package/MIGRATION.md +1229 -16
  3. package/README.md +25 -30
  4. package/USAGE.md +30 -4
  5. package/bin/audit-template-children.mjs +556 -0
  6. package/components/accordion/accordion-item.a2ui.json +4 -0
  7. package/components/accordion/accordion-item.yaml +2 -0
  8. package/components/accordion/accordion.a2ui.json +4 -0
  9. package/components/accordion/accordion.yaml +2 -0
  10. package/components/action-list/action-item.a2ui.json +29 -2
  11. package/components/action-list/action-item.yaml +46 -3
  12. package/components/action-list/action-list.a2ui.json +6 -1
  13. package/components/action-list/action-list.class.js +114 -11
  14. package/components/action-list/action-list.css +43 -3
  15. package/components/action-list/action-list.d.ts +6 -2
  16. package/components/action-list/action-list.yaml +5 -0
  17. package/components/adia-mark/adia-mark.a2ui.json +1 -0
  18. package/components/adia-wordmark/adia-wordmark.a2ui.json +1 -0
  19. package/components/agent-artifact/agent-artifact.a2ui.json +1 -0
  20. package/components/agent-feedback-bar/agent-feedback-bar.a2ui.json +6 -5
  21. package/components/agent-feedback-bar/agent-feedback-bar.yaml +6 -2
  22. package/components/agent-questions/agent-questions.a2ui.json +1 -0
  23. package/components/agent-reasoning/agent-reasoning.a2ui.json +6 -5
  24. package/components/agent-reasoning/agent-reasoning.yaml +6 -2
  25. package/components/agent-suggestions/agent-suggestions.a2ui.json +11 -2
  26. package/components/agent-suggestions/agent-suggestions.class.js +2 -1
  27. package/components/agent-suggestions/agent-suggestions.d.ts +4 -4
  28. package/components/agent-suggestions/agent-suggestions.yaml +4 -2
  29. package/components/agent-trace/agent-trace.a2ui.json +6 -5
  30. package/components/agent-trace/agent-trace.yaml +6 -2
  31. package/components/alert/alert.a2ui.json +1 -0
  32. package/components/alert/alert.css +1 -1
  33. package/components/anchor-bar/anchor-bar.a2ui.json +1 -0
  34. package/components/aside/aside.a2ui.json +1 -0
  35. package/components/avatar/avatar-group.a2ui.json +7 -1
  36. package/components/avatar/avatar-group.yaml +1 -0
  37. package/components/avatar/avatar.a2ui.json +12 -11
  38. package/components/avatar/avatar.d.ts +1 -1
  39. package/components/avatar/avatar.yaml +4 -4
  40. package/components/badge/badge.a2ui.json +1 -0
  41. package/components/block/block.a2ui.json +1 -0
  42. package/components/blockquote/blockquote.a2ui.json +1 -0
  43. package/components/breadcrumb/breadcrumb.a2ui.json +1 -0
  44. package/components/button/button.a2ui.json +1 -3
  45. package/components/button/button.yaml +1 -3
  46. package/components/calendar-grid/calendar-grid.a2ui.json +1 -0
  47. package/components/calendar-grid/calendar-grid.class.js +2 -1
  48. package/components/calendar-picker/calendar-picker.a2ui.json +143 -24
  49. package/components/calendar-picker/calendar-picker.class.js +490 -197
  50. package/components/calendar-picker/calendar-picker.css +120 -171
  51. package/components/calendar-picker/calendar-picker.yaml +225 -47
  52. package/components/canvas/canvas.a2ui.json +6 -5
  53. package/components/canvas/canvas.d.ts +37 -0
  54. package/components/canvas/canvas.js +72 -3
  55. package/components/canvas/canvas.yaml +6 -2
  56. package/components/card/card.a2ui.json +25 -2
  57. package/components/card/card.class.js +3 -0
  58. package/components/card/card.css +31 -1
  59. package/components/card/card.d.ts +2 -2
  60. package/components/card/card.examples.md +3 -3
  61. package/components/card/card.yaml +28 -4
  62. package/components/chart/chart.a2ui.json +27 -7
  63. package/components/chart/chart.class.js +64 -22
  64. package/components/chart/chart.css +6 -4
  65. package/components/chart/chart.d.ts +10 -4
  66. package/components/chart/chart.yaml +40 -6
  67. package/components/chart-legend/chart-legend.a2ui.json +7 -1
  68. package/components/chart-legend/chart-legend.class.js +59 -6
  69. package/components/chart-legend/chart-legend.css +5 -2
  70. package/components/chart-legend/chart-legend.d.ts +3 -1
  71. package/components/chart-legend/chart-legend.yaml +15 -1
  72. package/components/chat-thread/chat-input.a2ui.json +1 -0
  73. package/components/chat-thread/chat-thread.a2ui.json +10 -9
  74. package/components/chat-thread/chat-thread.yaml +13 -20
  75. package/components/check/check.a2ui.json +10 -9
  76. package/components/check/check.yaml +4 -4
  77. package/components/code/code.a2ui.json +1 -0
  78. package/components/col/col.a2ui.json +1 -0
  79. package/components/color-area/color-area.a2ui.json +148 -0
  80. package/components/color-area/color-area.class.js +657 -0
  81. package/components/color-area/color-area.css +188 -0
  82. package/components/color-area/color-area.d.ts +66 -0
  83. package/components/color-area/color-area.examples.md +19 -0
  84. package/components/color-area/color-area.js +17 -0
  85. package/components/color-area/color-area.yaml +183 -0
  86. package/components/color-input/color-input.a2ui.json +6 -5
  87. package/components/color-input/color-input.class.js +9 -6
  88. package/components/color-input/color-input.css +1 -1
  89. package/components/color-input/color-input.js +2 -2
  90. package/components/color-input/color-input.yaml +14 -12
  91. package/components/color-picker/color-picker.a2ui.json +16 -12
  92. package/components/color-picker/color-picker.class.js +24 -633
  93. package/components/color-picker/color-picker.css +14 -182
  94. package/components/color-picker/color-picker.yaml +41 -41
  95. package/components/combobox/combobox.a2ui.json +3 -2
  96. package/components/combobox/combobox.yaml +2 -2
  97. package/components/command/command.a2ui.json +12 -10
  98. package/components/command/command.class.js +3 -2
  99. package/components/command/command.yaml +17 -4
  100. package/components/context-menu/context-menu.a2ui.json +1 -0
  101. package/components/date-range-picker/date-range-picker.a2ui.json +2 -1
  102. package/components/date-range-picker/date-range-picker.yaml +1 -1
  103. package/components/datetime-picker/datetime-picker.a2ui.json +15 -108
  104. package/components/datetime-picker/datetime-picker.class.js +37 -690
  105. package/components/datetime-picker/datetime-picker.css +11 -183
  106. package/components/datetime-picker/datetime-picker.d.ts +4 -5
  107. package/components/datetime-picker/datetime-picker.yaml +44 -135
  108. package/components/demo-toggle/demo-toggle.a2ui.json +1 -0
  109. package/components/demo-toggle/demo-toggle.css +1 -1
  110. package/components/description-list/description-list.a2ui.json +2 -1
  111. package/components/description-list/description-list.css +1 -1
  112. package/components/description-list/description-list.d.ts +1 -1
  113. package/components/description-list/description-list.yaml +1 -1
  114. package/components/display-field/display-field.a2ui.json +1 -0
  115. package/components/divider/divider.a2ui.json +1 -0
  116. package/components/drawer/drawer.a2ui.json +1 -3
  117. package/components/drawer/drawer.css +1 -1
  118. package/components/drawer/drawer.yaml +0 -2
  119. package/components/drilldown/drilldown.a2ui.json +22 -20
  120. package/components/drilldown/drilldown.class.js +4 -3
  121. package/components/drilldown/drilldown.css +6 -6
  122. package/components/drilldown/drilldown.yaml +40 -9
  123. package/components/embed/embed.a2ui.json +6 -5
  124. package/components/embed/embed.yaml +2 -2
  125. package/components/empty-state/empty-state.a2ui.json +1 -0
  126. package/components/feed/feed-item.a2ui.json +25 -5
  127. package/components/feed/feed-item.yaml +28 -7
  128. package/components/feed/feed.a2ui.json +9 -2
  129. package/components/feed/feed.class.js +19 -12
  130. package/components/feed/feed.css +8 -8
  131. package/components/feed/feed.yaml +14 -1
  132. package/components/field/field.a2ui.json +2 -1
  133. package/components/field/field.class.js +4 -1
  134. package/components/field/field.examples.md +1 -1
  135. package/components/field/field.yaml +1 -1
  136. package/components/fields/fields.a2ui.json +1 -0
  137. package/components/fields/fields.examples.md +1 -1
  138. package/components/footer/footer.a2ui.json +1 -0
  139. package/components/frame/frame.a2ui.json +1 -0
  140. package/components/grid/grid.a2ui.json +1 -0
  141. package/components/header/header.a2ui.json +3 -2
  142. package/components/header/header.yaml +3 -3
  143. package/components/heatmap/heatmap.a2ui.json +2 -1
  144. package/components/heatmap/heatmap.class.js +1 -1
  145. package/components/heatmap/heatmap.css +4 -4
  146. package/components/heatmap/heatmap.yaml +1 -1
  147. package/components/icon/icon.a2ui.json +1 -0
  148. package/components/image/image.a2ui.json +28 -14
  149. package/components/image/image.class.js +38 -23
  150. package/components/image/image.css +18 -8
  151. package/components/image/image.d.ts +2 -2
  152. package/components/image/image.examples.md +3 -3
  153. package/components/image/image.yaml +23 -7
  154. package/components/index.js +1 -0
  155. package/components/inline-edit/inline-edit.a2ui.json +1 -0
  156. package/components/inline-message/inline-message.a2ui.json +3 -1
  157. package/components/inline-message/inline-message.class.js +3 -1
  158. package/components/inline-message/inline-message.d.ts +2 -2
  159. package/components/inline-message/inline-message.yaml +2 -1
  160. package/components/input/input.a2ui.json +66 -16
  161. package/components/input/input.class.js +64 -7
  162. package/components/input/input.css +14 -14
  163. package/components/input/input.d.ts +9 -4
  164. package/components/input/input.yaml +83 -10
  165. package/components/inspector/inspector.a2ui.json +1 -0
  166. package/components/integration-card/integration-card.a2ui.json +1 -0
  167. package/components/integration-card/integration-card.examples.md +2 -1
  168. package/components/kbd/kbd.a2ui.json +1 -0
  169. package/components/link/link.a2ui.json +2 -1
  170. package/components/link/link.yaml +1 -1
  171. package/components/list/list-item.a2ui.json +9 -0
  172. package/components/list/list-item.yaml +12 -0
  173. package/components/list/list.a2ui.json +9 -3
  174. package/components/list/list.class.js +14 -1
  175. package/components/list/list.css +12 -1
  176. package/components/list/list.d.ts +7 -5
  177. package/components/list/list.yaml +16 -6
  178. package/components/list-window/list-window.a2ui.json +1 -0
  179. package/components/list-window/list-window.class.js +2 -1
  180. package/components/loading-overlay/loading-overlay.a2ui.json +1 -0
  181. package/components/mark/mark.a2ui.json +2 -1
  182. package/components/mark/mark.yaml +1 -1
  183. package/components/menu/menu-divider.a2ui.json +1 -0
  184. package/components/menu/menu-item.a2ui.json +11 -4
  185. package/components/menu/menu-item.yaml +30 -3
  186. package/components/menu/menu-label.a2ui.json +1 -0
  187. package/components/menu/menu.a2ui.json +3 -2
  188. package/components/menu/menu.class.js +36 -8
  189. package/components/menu/menu.d.ts +5 -3
  190. package/components/menu/menu.yaml +3 -3
  191. package/components/modal/modal.a2ui.json +1 -0
  192. package/components/nav/nav.a2ui.json +1 -0
  193. package/components/nav/nav.class.js +14 -3
  194. package/components/nav-group/nav-group.a2ui.json +1 -0
  195. package/components/nav-group/nav-group.class.js +3 -1
  196. package/components/nav-item/nav-item.a2ui.json +1 -0
  197. package/components/noodles/noodles.a2ui.json +1 -0
  198. package/components/noodles/noodles.class.js +5 -1
  199. package/components/number-format/number-format.a2ui.json +1 -0
  200. package/components/option-card/option-card.a2ui.json +1 -0
  201. package/components/otp-input/otp-input.a2ui.json +3 -2
  202. package/components/otp-input/otp-input.yaml +9 -2
  203. package/components/page/page.a2ui.json +13 -0
  204. package/components/page/page.d.ts +1 -1
  205. package/components/page/page.yaml +1 -0
  206. package/components/pagination/pagination.a2ui.json +1 -0
  207. package/components/pagination/pagination.class.js +3 -2
  208. package/components/pane/pane.a2ui.json +17 -1
  209. package/components/pane/pane.class.js +35 -6
  210. package/components/pane/pane.css +17 -12
  211. package/components/pane/pane.d.ts +10 -7
  212. package/components/pane/pane.yaml +18 -1
  213. package/components/password-strength/password-strength.a2ui.json +1 -0
  214. package/components/pipeline-status/pipeline-status.a2ui.json +1 -0
  215. package/components/popover/popover.a2ui.json +7 -6
  216. package/components/popover/popover.class.js +2 -2
  217. package/components/popover/popover.d.ts +2 -2
  218. package/components/popover/popover.yaml +4 -4
  219. package/components/preview/preview.a2ui.json +1 -0
  220. package/components/preview/preview.class.js +5 -1
  221. package/components/progress/progress.a2ui.json +47 -24
  222. package/components/progress/progress.class.js +66 -11
  223. package/components/progress/progress.css +44 -26
  224. package/components/progress/progress.d.ts +7 -5
  225. package/components/progress/progress.examples.md +2 -2
  226. package/components/progress/progress.yaml +235 -53
  227. package/components/progress-row/progress-row.a2ui.json +16 -12
  228. package/components/progress-row/progress-row.d.ts +2 -2
  229. package/components/progress-row/progress-row.examples.md +2 -14
  230. package/components/progress-row/progress-row.yaml +28 -36
  231. package/components/qr-code/qr-code.a2ui.json +3 -2
  232. package/components/qr-code/qr-code.class.js +4 -4
  233. package/components/qr-code/qr-code.css +1 -1
  234. package/components/qr-code/qr-code.yaml +5 -3
  235. package/components/radio/radio.a2ui.json +8 -7
  236. package/components/radio/radio.class.js +8 -0
  237. package/components/radio/radio.yaml +3 -3
  238. package/components/radio-group/radio-group.a2ui.json +5 -3
  239. package/components/radio-group/radio-group.class.js +11 -0
  240. package/components/radio-group/radio-group.yaml +7 -1
  241. package/components/range/range.a2ui.json +6 -0
  242. package/components/range/range.class.js +2 -2
  243. package/components/range/range.css +2 -2
  244. package/components/range/range.yaml +3 -0
  245. package/components/rating/rating.a2ui.json +1 -0
  246. package/components/relative-time/relative-time.a2ui.json +1 -0
  247. package/components/richtext/richtext.a2ui.json +2 -1
  248. package/components/richtext/richtext.yaml +1 -1
  249. package/components/row/row.a2ui.json +1 -0
  250. package/components/search/search.a2ui.json +1 -0
  251. package/components/search/search.class.js +4 -1
  252. package/components/section/section.a2ui.json +1 -0
  253. package/components/segment/segment.a2ui.json +21 -10
  254. package/components/segment/segment.css +15 -0
  255. package/components/segment/segment.d.ts +2 -1
  256. package/components/segment/segment.yaml +20 -13
  257. package/components/segmented/segmented.a2ui.json +36 -7
  258. package/components/segmented/segmented.class.js +113 -22
  259. package/components/segmented/segmented.css +3 -0
  260. package/components/segmented/segmented.d.ts +3 -1
  261. package/components/segmented/segmented.yaml +80 -8
  262. package/components/select/select.a2ui.json +18 -13
  263. package/components/select/select.class.js +61 -37
  264. package/components/select/select.css +15 -13
  265. package/components/select/select.yaml +18 -7
  266. package/components/skeleton/skeleton.a2ui.json +8 -7
  267. package/components/skeleton/skeleton.class.js +8 -7
  268. package/components/skeleton/skeleton.css +21 -6
  269. package/components/skeleton/skeleton.d.ts +2 -2
  270. package/components/skeleton/skeleton.examples.md +2 -2
  271. package/components/skeleton/skeleton.yaml +3 -2
  272. package/components/skip-nav/skip-nav.a2ui.json +1 -0
  273. package/components/slider/slider.a2ui.json +6 -0
  274. package/components/slider/slider.class.js +20 -3
  275. package/components/slider/slider.css +2 -2
  276. package/components/slider/slider.yaml +3 -0
  277. package/components/spinner/spinner.a2ui.json +1 -0
  278. package/components/stack/stack.a2ui.json +1 -0
  279. package/components/stat/stat.a2ui.json +1 -0
  280. package/components/stat/stat.js +2 -2
  281. package/components/step-progress/step-progress.a2ui.json +1 -0
  282. package/components/step-progress/step-progress.yaml +1 -1
  283. package/components/stepper/stepper-item.a2ui.json +7 -3
  284. package/components/stepper/stepper-item.yaml +15 -5
  285. package/components/stepper/stepper.a2ui.json +5 -1
  286. package/components/stepper/stepper.class.js +31 -16
  287. package/components/stepper/stepper.d.ts +1 -1
  288. package/components/stepper/stepper.yaml +4 -2
  289. package/components/stream/stream.a2ui.json +1 -0
  290. package/components/swatch/swatch.a2ui.json +1 -0
  291. package/components/swatch/swatch.yaml +1 -1
  292. package/components/swiper/swiper.a2ui.json +1 -0
  293. package/components/swiper/swiper.class.js +5 -1
  294. package/components/switch/switch.a2ui.json +12 -11
  295. package/components/switch/switch.css +1 -1
  296. package/components/switch/switch.yaml +6 -6
  297. package/components/table/table.a2ui.json +1 -0
  298. package/components/table/table.class.js +14 -12
  299. package/components/table/table.css +11 -9
  300. package/components/table-toolbar/table-toolbar.a2ui.json +1 -0
  301. package/components/table-toolbar/table-toolbar.class.js +53 -22
  302. package/components/table-toolbar/table-toolbar.css +1 -1
  303. package/components/tabs/tab.a2ui.json +9 -0
  304. package/components/tabs/tab.js +4 -0
  305. package/components/tabs/tab.yaml +15 -0
  306. package/components/tabs/tabs.a2ui.json +9 -4
  307. package/components/tabs/tabs.class.js +13 -1
  308. package/components/tabs/tabs.css +8 -0
  309. package/components/tabs/tabs.d.ts +2 -0
  310. package/components/tabs/tabs.yaml +9 -2
  311. package/components/tag/tag.a2ui.json +1 -0
  312. package/components/tags-input/tags-input.a2ui.json +22 -17
  313. package/components/tags-input/tags-input.class.js +13 -11
  314. package/components/tags-input/tags-input.css +10 -6
  315. package/components/tags-input/tags-input.d.ts +16 -7
  316. package/components/tags-input/tags-input.examples.md +2 -2
  317. package/components/tags-input/tags-input.yaml +25 -8
  318. package/components/text/text.a2ui.json +6 -5
  319. package/components/text/text.css +10 -5
  320. package/components/text/text.d.ts +2 -2
  321. package/components/text/text.yaml +9 -4
  322. package/components/textarea/textarea.a2ui.json +2 -1
  323. package/components/textarea/textarea.yaml +1 -1
  324. package/components/theme-provider/theme-provider.a2ui.json +2 -1
  325. package/components/theme-provider/theme-provider.d.ts +5 -3
  326. package/components/theme-provider/theme-provider.yaml +5 -3
  327. package/components/time-picker/time-picker.a2ui.json +1 -0
  328. package/components/time-picker/time-picker.class.js +4 -2
  329. package/components/timeline/timeline-item.a2ui.json +26 -3
  330. package/components/timeline/timeline-item.yaml +22 -7
  331. package/components/timeline/timeline.a2ui.json +4 -0
  332. package/components/timeline/timeline.class.js +29 -18
  333. package/components/timeline/timeline.d.ts +3 -3
  334. package/components/timeline/timeline.yaml +2 -0
  335. package/components/toast/toast.a2ui.json +10 -3
  336. package/components/toast/toast.yaml +20 -13
  337. package/components/toc/toc.a2ui.json +1 -0
  338. package/components/toggle-group/toggle-group.a2ui.json +7 -3
  339. package/components/toggle-group/toggle-group.class.js +40 -1
  340. package/components/toggle-group/toggle-group.css +6 -1
  341. package/components/toggle-group/toggle-group.d.ts +2 -2
  342. package/components/toggle-group/toggle-group.yaml +21 -12
  343. package/components/toggle-group/toggle-option.a2ui.json +7 -3
  344. package/components/toggle-group/toggle-option.yaml +13 -7
  345. package/components/toggle-scheme/toggle-scheme.a2ui.json +2 -1
  346. package/components/toggle-scheme/toggle-scheme.yaml +1 -1
  347. package/components/toolbar/toolbar-group.a2ui.json +1 -0
  348. package/components/toolbar/toolbar.a2ui.json +1 -0
  349. package/components/toolbar/toolbar.class.js +3 -0
  350. package/components/tooltip/tooltip.a2ui.json +1 -0
  351. package/components/tour/tour-step.a2ui.json +4 -0
  352. package/components/tour/tour-step.yaml +2 -0
  353. package/components/tour/tour.a2ui.json +4 -0
  354. package/components/tour/tour.yaml +2 -0
  355. package/components/tree/tree-item.a2ui.json +5 -0
  356. package/components/tree/tree-item.yaml +3 -0
  357. package/components/tree/tree.a2ui.json +4 -0
  358. package/components/tree/tree.class.js +2 -1
  359. package/components/tree/tree.yaml +2 -0
  360. package/components/upload/upload.a2ui.json +8 -1
  361. package/components/upload/upload.class.js +35 -5
  362. package/components/upload/upload.css +28 -0
  363. package/components/upload/upload.d.ts +16 -0
  364. package/components/upload/upload.yaml +27 -7
  365. package/components/visually-hidden/visually-hidden.a2ui.json +1 -0
  366. package/core/dom.d.ts +11 -0
  367. package/core/dom.js +34 -0
  368. package/core/form.js +7 -0
  369. package/core/icons.js +5 -0
  370. package/core/index.d.ts +1 -0
  371. package/core/index.js +1 -0
  372. package/core/responsive.js +16 -4
  373. package/core/template.js +2 -1
  374. package/custom-elements.json +710 -587
  375. package/dist/host.min.css +1 -1
  376. package/dist/host.sheet.js +1 -1
  377. package/dist/theme-provider.min.js +5 -5
  378. package/dist/web-components.min.css +1 -1
  379. package/dist/web-components.min.js +92 -105
  380. package/dist/web-components.sheet.js +1 -1
  381. package/index.d.ts +12 -1
  382. package/package.json +4 -2
  383. package/patterns/admin-shell/admin-shell.examples.html +2 -2
  384. package/patterns/conversion-funnel/conversion-funnel.examples.html +15 -15
  385. package/patterns/form-system/form-system.examples.html +1 -1
  386. package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
  387. package/patterns/inline-dialog/inline-dialog.html +4 -0
  388. package/patterns/timezone-selector/timezone-selector.examples.html +1 -1
  389. package/patterns/timezone-selector/timezone-selector.html +2 -2
  390. package/styles/api/text.css +7 -0
  391. package/styles/components.css +1 -0
  392. package/traits/_catalog.json +129 -41
  393. package/traits/anchor-positioning/anchor-positioning.js +1 -0
  394. package/traits/announcer/announcer.js +1 -0
  395. package/traits/arrow-grid-nav/arrow-grid-nav.js +1 -0
  396. package/traits/attention-pulse/attention-pulse.js +1 -0
  397. package/traits/count-up/count-up.js +1 -0
  398. package/traits/define.js +78 -0
  399. package/traits/focus-restore/focus-restore.js +2 -1
  400. package/traits/haptic-feedback/haptic-feedback.js +1 -0
  401. package/traits/input-mask/input-mask.js +1 -0
  402. package/traits/intersection-observer/intersection-observer.js +1 -0
  403. package/traits/layout-animation/layout-animation.js +1 -0
  404. package/traits/noise-texture/noise-texture.js +1 -0
  405. package/traits/resize-observer/resize-observer.js +1 -0
  406. package/traits/scroll-progress/scroll-progress.js +1 -0
  407. package/traits/snap-to-grid/snap-to-grid.js +1 -0
  408. package/traits/sound-feedback/sound-feedback.js +1 -0
  409. package/traits/spring-animate/spring-animate.js +1 -0
  410. package/traits/validation/validation.js +1 -0
package/MIGRATION.md CHANGED
@@ -41,7 +41,7 @@ Version cuts and migration scope:
41
41
  - **Recommended consumer migration:** if you were using `@adia-ai/web-modules/runtime/a2ui-root/a2ui-root.js` + `@adia-ai/web-components/components/canvas/canvas.js` for generative UI surfaces, collapse to a single `import '@adia-ai/web-modules/generative'`. Both old paths still work.
42
42
  - See [§ v0.6.7 section below](#migrating-to-adia-aiv067-2026-05-19).
43
43
 
44
- - **Upcoming (variant/color/tone convention cut)** — **BREAKING:** `accent` is retired as an enum value on `badge-ui` (`variant`), `tag-ui` (`variant`), and `button-ui` (`color`) — `primary` is the brand-emphasis value on badge/tag (identical rendering; pure rename). Badge-ui's `variant` becomes family-only: `variant="muted"` / `variant="neutral"` are removed — both map to `tone="muted"` (the fill-style axis they always belonged on). Badge's family-less `tone="muted"` also re-tokens to the `--md-sys-color-neutral-low` fill (a visibly stronger tint — no markup change). The same one-axis rule then reaches **alert-ui** (`variant="muted"` / `"neutral"` removed — they were exact aliases of the default, so just drop the attribute; zero visual change) and **mark-ui** (`variant="muted"` removed with no enum successor — a neutral highlight is now a `--mark-bg`/`--mark-fg` token override); neither gains a `tone` axis. `accent` on OTHER components (icon-ui, text-ui, chart-ui, …) is unchanged. Pre-1.0 PATCH cadence. See [§ Upcoming — variant/color/tone convention cut](#upcoming-variant-color-tone-convention-cut).
44
+ - **Shipped in `0.8.33` (variant/color/tone convention cut, ADR-0044)** — **BREAKING:** `accent` is retired as an enum value on `badge-ui` (`variant`), `tag-ui` (`variant`), and `button-ui` (`color`) — `primary` is the brand-emphasis value on badge/tag (identical rendering; pure rename). Badge-ui's `variant` becomes family-only: `variant="muted"` / `variant="neutral"` are removed — both map to `tone="muted"` (the fill-style axis they always belonged on). Badge's family-less `tone="muted"` also re-tokens to the `--md-sys-color-neutral-low` fill (a visibly stronger tint — no markup change). The same one-axis rule then reaches **alert-ui** (`variant="muted"` / `"neutral"` removed — they were exact aliases of the default, so just drop the attribute; zero visual change) and **mark-ui** (`variant="muted"` removed with no enum successor — a neutral highlight is now a `--mark-bg`/`--mark-fg` token override); neither gains a `tone` axis. `accent` on OTHER components (icon-ui, text-ui, chart-ui, …) is unchanged. See [§ Shipped in `0.8.33` — variant/color/tone convention cut](#upcoming-variant-color-tone-convention-cut).
45
45
 
46
46
  - **Upcoming (`<theme-provider>` cut)** — **BREAKING:** the token-theme attribute is renamed `data-theme` → `theme` repo-wide. Replace `<html data-theme="ocean">` → `<html theme="ocean">` and any `[data-theme="…"]` selectors → `[theme="…"]`. Mechanical: a word-boundary find-replace of `data-theme` → `theme` (preserve compound attrs like `data-theme-slug` / `data-themed`). Pre-1.0 PATCH cadence. Also new: the **`<theme-provider>`** element adopts the AdiaUI foundation into the document from anywhere (no `<head>` stylesheet link), with opt-in `theme="…"` (named preset) + `scale="verse|prose"` (typographic register) attributes that fetch their layer on demand.
47
47
  - **`theme` ≠ `scheme` — don't conflate the two axes.** This rename is purely the *theme* axis (a named preset: ocean / forest / slate / …). A light/dark *mode* is the orthogonal *scheme* axis — it belongs on `color-scheme` / `data-scheme`, **never** on `[theme]`. If you'd encoded a mode as `data-theme="dark"`, that was a category error: after the rename it is a no-op on *both* axes. Move it to the scheme axis — `<html style="color-scheme: dark">`, `data-scheme`, or `<toggle-scheme-ui>`. (Surfaced by color-app, 2026-06-07.)
@@ -54,13 +54,39 @@ Version cuts and migration scope:
54
54
 
55
55
  - **`0.8.37`** — PATCH lockstep cut. **BREAKING: the a2ui / gen-ui estate split (ADR-0048).** Six published package names (`a2ui-runtime`, `a2ui-compose`, `a2ui-corpus`, `a2ui-retrieval`, `a2ui-validator`, `a2ui-mcp`) are replaced by four (`a2ui`, `gen-ui`, `gen-ui-mcp`, `a2ui-protocol-mcp`). **A patch-shaped version number does not make this non-breaking** — every old name is renamed. One-cycle re-export shims bridge the gap; the cut AFTER `0.8.37` retires them. See [§ 0.8.37 — the a2ui / gen-ui estate split](#0837--the-a2ui--gen-ui-estate-split-adr-0048).
56
56
 
57
- - **Upcoming (`0.8.40` attribute-grammar reconciliation, ADR-0054)** — **BREAKING, no deprecation alias:** `table-ui[density]` converges onto the ambient global `[density]` attribute — the component-local `compact`/`standard`/`comfortable` enum is removed. Migration: `density="compact"` stays `density="compact"`; `density="standard"` → drop the attribute (unset is the default); `density="comfortable"` → `density="spacious"`. `chart-ui[radius]` renames to `chart-ui[corner-radius]` (same `Number`/`null` semantics, same `--a-radius` fallback) — a mechanical attribute-name rename, no value-shape change. `swatch-ui[color]` and `noodles-ui[color]` are ratified exceptions and are unaffected. See [§ Upcoming 0.8.40 attribute-grammar reconciliation](#upcoming-0840-attribute-grammar-reconciliation-adr-0054).
57
+ - **Shipped in `0.8.40` (attribute-grammar reconciliation, ADR-0054)** — **BREAKING, no deprecation alias:** `table-ui[density]` converges onto the ambient global `[density]` attribute — the component-local `compact`/`standard`/`comfortable` enum is removed. Migration: `density="compact"` stays `density="compact"`; `density="standard"` → drop the attribute (unset is the default); `density="comfortable"` → `density="spacious"`. `chart-ui[radius]` renames to `chart-ui[corner-radius]` (same `Number`/`null` semantics, same `--a-radius` fallback) — a mechanical attribute-name rename, no value-shape change. `swatch-ui[color]` and `noodles-ui[color]` are ratified exceptions and are unaffected. See [§ Shipped in `0.8.40` attribute-grammar reconciliation](#upcoming-0840-attribute-grammar-reconciliation-adr-0054).
58
58
 
59
- - **Upcoming (`qr-code-ui` quiet-zone rename, `0.8.40`)** — **BREAKING:** `<qr-code-ui>`'s reflected `[margin]` attribute is renamed `[quiet-zone]` (property `quietZone`) — same type, default (`4`), and reflection; only the name changes, per [ADR-0053](../../docs/adr/adr-0053-no-shadowing-global-attributes.md). `margin` on `qr-code-ui` now means the framework's **global** `[margin]` Scale attribute (box-model spacing), not the QR quiet zone — the two grammars silently collided on the same syntax with unrelated meanings. **No deprecation alias** — keeping `margin` as an alias would preserve the collision the rename exists to remove. Audit existing usages: `<qr-code-ui margin="4">` intending a quiet zone must become `<qr-code-ui quiet-zone="4">`. Ships in `0.8.40`. See [§ Upcoming — qr-code-ui quiet-zone rename](#upcoming--qr-code-ui-quiet-zone-rename-adr-0053).
59
+ - **Shipped in `0.8.40` (`qr-code-ui` quiet-zone rename)** — **BREAKING:** `<qr-code-ui>`'s reflected `[margin]` attribute is renamed `[quiet-zone]` (property `quietZone`) — same type, default (`4`), and reflection; only the name changes, per [ADR-0053](../../docs/ops/adr/adr-0053-no-shadowing-global-attributes.md). `margin` on `qr-code-ui` now means the framework's **global** `[margin]` Scale attribute (box-model spacing), not the QR quiet zone — the two grammars silently collided on the same syntax with unrelated meanings. **No deprecation alias** — keeping `margin` as an alias would preserve the collision the rename exists to remove. Audit existing usages: `<qr-code-ui margin="4">` intending a quiet zone must become `<qr-code-ui quiet-zone="4">`. Shipped in `0.8.40`. See [§ Shipped in `0.8.40` — qr-code-ui quiet-zone rename](#upcoming--qr-code-ui-quiet-zone-rename-adr-0053).
60
60
 
61
- - **Upcoming (leading-scale consolidation, `0.8.40`)** — **BREAKING, no aliases:** the legacy `--a-leading-*` token family is removed per [ADR-0052](../../docs/adr/adr-0052-leading-scale-consolidation.md) — `--a-font-leading-*` (+ new `--a-font-leading-none: 1` step) is now the single canonical leading scale. Value-nearest replacement table: `none→--a-font-leading-none` (1), `tight→--a-font-leading-snug` (1.2), `snug→--a-font-leading-normal` (1.35), `normal→--a-font-leading-relaxed` (1.5). The same gh#1298 sweep also tokenized every hardcoded `line-height`/`letter-spacing`/`font-weight` literal across `packages/web-components/components/*/*.css` (1.3 and 1.4 both → `--a-font-leading-normal`; 0.05em → `--a-font-tracking-wide`) and added a mechanized `npm run check:typography-tokens` gate. See [§ Upcoming — leading-scale consolidation](#upcoming--leading-scale-consolidation-adr-0052).
61
+ - **Shipped in `0.8.40` (leading-scale consolidation)** — **BREAKING, no aliases:** the legacy `--a-leading-*` token family is removed per [ADR-0052](../../docs/ops/adr/adr-0052-leading-scale-consolidation.md) — `--a-font-leading-*` (+ new `--a-font-leading-none: 1` step) is now the single canonical leading scale. Value-nearest replacement table: `none→--a-font-leading-none` (1), `tight→--a-font-leading-snug` (1.2), `snug→--a-font-leading-normal` (1.35), `normal→--a-font-leading-relaxed` (1.5). The same gh#1298 sweep also tokenized every hardcoded `line-height`/`letter-spacing`/`font-weight` literal across `packages/web-components/components/*/*.css` (1.3 and 1.4 both → `--a-font-leading-normal`; 0.05em → `--a-font-tracking-wide`) and added a mechanized `npm run check:typography-tokens` gate. See [§ Shipped in `0.8.40` — leading-scale consolidation](#upcoming--leading-scale-consolidation-adr-0052).
62
62
 
63
- - **Upcoming (`toggle-option-ui` drops `data-selected`, `0.8.40`)** — **BREAKING, no deprecation alias:** `<toggle-group-ui>`'s legacy `data-selected` parallel stamp on its `<toggle-option-ui>` children is removed per [ADR-0056](../../docs/adr/adr-0056-selection-item-selected-convention.md) — the declared, reflected `selected` prop (shipped additively in `0.8.39`) is now the only current-state surface, matching `<segment-ui>`'s convention. Migration: any `[data-selected]` CSS or script targeting `toggle-option-ui` moves to `[selected]`. See [§ Upcoming — `toggle-option-ui` drops the legacy `data-selected` stamp](#upcoming--toggle-option-ui-drops-the-legacy-data-selected-stamp-0840-adr-0056).
63
+ - **Shipped in `0.8.40` (`toggle-option-ui` drops `data-selected`)** — **BREAKING, no deprecation alias:** `<toggle-group-ui>`'s legacy `data-selected` parallel stamp on its `<toggle-option-ui>` children is removed per [ADR-0056](../../docs/ops/adr/adr-0056-selection-item-selected-convention.md) — the declared, reflected `selected` prop (shipped additively in `0.8.39`) is now the only current-state surface, matching `<segment-ui>`'s convention. Migration: any `[data-selected]` CSS or script targeting `toggle-option-ui` moves to `[selected]`. See [§ Shipped in `0.8.40` — `toggle-option-ui` drops the legacy `data-selected` stamp](#upcoming--toggle-option-ui-drops-the-legacy-data-selected-stamp-0840-adr-0056).
64
+
65
+ - **Shipped in `0.8.41` (`progress-ui` retires `variant`, gh#1370)** — **BREAKING, no deprecation alias:** `<progress-ui>`'s `variant` prop (`bar` | `spinner`) is removed — progress is bar-only now. The former `variant="spinner"` render mode (a Sanctioned Mode Attribute per the component-token-contract) is gone; `<spinner-ui>` owns circular loading indicators (`arc`/`ring`/`dots`/`knight`). Migration: `<progress-ui variant="spinner">` → `<spinner-ui>` (pick the closest `variant`; `arc` is the nearest visual match to the old spinner render). `<progress-ui variant="bar">` → drop the attribute (bar was already the default). Filed from the catalog-regularity audit's C2 finding (gh#1363) — a 2026-06 merge folded a standalone spinner into progress as `variant="spinner"`, then a richer standalone `spinner-ui` was re-added later, leaving two circular-loading answers in the catalog; this rider un-forks them. See [§ Shipped in `0.8.41` — `progress-ui` retires `variant`](#upcoming--progress-ui-retires-variant-090-gh1370).
66
+
67
+ - **Shipped in `0.8.41` (`input-ui` trims `type` enum, gh#1381)** — **BREAKING, no deprecation alias:** `<input-ui>`'s `type` enum drops `search`/`date`/`datetime-local`/`time`/`month`/`week`/`color` — none ever rendered a native affordance (all seven fell back to a plain contenteditable surface), so the enum was first-pass-VALID but functionally broken generation output. The implemented set is now exactly `text`/`email`/`password`/`number`/`tel`/`url`. Migration: `type="search"` → `<search-ui>`; `type="date"`/`"month"`/`"week"` → `<calendar-picker-ui>` (day granularity only — no dedicated month/week primitive exists); `type="datetime-local"` → `<datetime-picker-ui>`; `type="time"` → `<time-picker-ui>`; `type="color"` → `<color-input-ui>` (or `<color-picker-ui>` directly for a full-surface editor). Filed from the catalog-regularity audit's B10 finding (gh#1363). See [§ Shipped in `0.8.41` — `input-ui` trims `type` enum](#upcoming--input-ui-trims-type-enum-090-gh1381).
68
+
69
+ - **Shipped in `0.8.41` (web-modules `data-*` state converges to bare attributes, gh#1332)** — **BREAKING, no deprecation alias:** two web-modules' declared `states:` entries drop a private `data-*` stamp for a bare state attribute, per the data-* usage sweep's Category A disposition (ADR-0056's rule generalized past `toggle-option-ui`). `<integrations-page-ui>`'s `empty-search`/`empty-data` states (was `data-empty-search`/`data-empty-data`) and `<onboarding-checklist-ui>`'s `complete` state (was `data-complete`) now match their own sibling states' existing bare-attribute convention (`loading`, `collapsed`). Migration: any `[data-empty-search]`/`[data-empty-data]`/`[data-complete]` CSS or script targeting these two modules moves to `[empty-search]`/`[empty-data]`/`[complete]`. See [§ Shipped in `0.8.41` — web-modules data-* state converges to bare attributes](#upcoming--web-modules-data--state-converges-to-bare-attributes-090-gh1332).
70
+
71
+ - **Shipped in `0.8.41` (`action-item-ui` converges onto `menu-item-ui`'s row contract, gh#1374)** — **BREAKING, no deprecation alias, zero known consumer sites.** `<action-item-ui>` gains a `subtitle` prop + `text`/`subtitle`/`trailing` slot overrides, matching `<menu-item-ui>`'s row contract exactly. The unnamed default slot this row previously used for trailing content (kbd shortcut, badge, caret) is retired in favor of an explicit `slot="trailing"` — a monorepo-wide sweep at dispatch time found no consumer relying on it (every `<action-item-ui>` usage is self-closing/attribute-only). Migration: any external consumer slotting unnamed trailing content into `<action-item-ui>` adds `slot="trailing"` to that child. Filed from the catalog-regularity audit's C5 finding (gh#1363) — action-list's container-level "should this become a `list-ui` mode" question was decided as NO (kept as a separate component; see the ticket's Findings for rationale), leaving only this row-level convergence to ship. See [§ Shipped in `0.8.41` — `action-item-ui` converges onto `menu-item-ui`'s row contract](#upcoming--action-item-ui-converges-onto-menu-item-uis-row-contract-090-gh1374).
72
+
73
+ - **Shipped in `0.8.41` (global-attribute-shadowing collision sweep, gh#1335)** — **BREAKING, no deprecation aliases:** of the 16 pre-existing component-local attributes that shadowed the global attribute grammar (surfaced by the `check:attribute-shadowing` gate, ADR-0053/0054's own decision-4 gate), 14 are resolved here — 11 renamed/converged, 3 exempted (an ADR-ratified §11 pass-through, no code change) — plus a 17th collision this same ticket's own follow-up audit surfaced (`dashboard-layout-ui[gap]`, never in the gate's original 16 since its shape wasn't caught by the gate's type-only check), also renamed here, for **12 renames/conversions + 3 exemptions = 15 items resolved of 17 tracked**: `header-ui[padding]` → `[padded]`; `menu-ui`/`popover-ui[gap]` → `[offset]`; `skeleton-ui`/`image-ui[radius]` → `[corner-radius]`; `invoice-detail-ui`/`invoice-history-ui`/`dashboard-layout-ui[density]` converge onto `compact`/`spacious`/unset; `dashboard-layout-ui[gap]` → `[band-gap]`; `text-ui[weight]` `regular` → `normal`; `text-ui[text-align]` converges onto the global physical vocabulary (`start`/`end` → `left`/`right`; `justify` newly supported by the global `[text-align]` grammar too); `tags-input-ui[transform]` → `[normalize]`; `button-ui`/`toggle-scheme-ui`/`text-ui[color]` are newly §11-ratified exemptions (ADR-0044/ADR-0064 — these play the FAMILY axis, a different grammar from the generic descriptive `[color]`, not a foreign-value violation). `qr-code-ui[color]` and `icon-ui[weight]` were left open by this sweep (both genuine §11-exemption candidates with no ratifying ADR at the time, tracked in the gate's own `KNOWN_FINDINGS`) and are since ratified as §11 exemptions by ADR-0070 (gh#1500) — no code change, closing the ledger at 17 of 17. See [§ Shipped in `0.8.41` — global-attribute-shadowing collision sweep](#upcoming--global-attribute-shadowing-collision-sweep-090-gh1335).
74
+
75
+ - **Shipped in `0.8.41` (A2UI catalog `component:` collision — `AdminShell` / `UIChatThread`, gh#1427)** — **BREAKING for hand-authored/generated A2UI documents only — no DOM/JS API or tag-name change.** `admin-shell.yaml` and `embed-shell.yaml` both declared catalog identity `component: AppShell`, so alphabetical build traversal silently dropped `admin-shell`'s L0 catalog entry (embed-shell's fragment won). Fixed: `admin-shell`'s catalog identity is now `AdminShell` (its own established `registry.js` mapping); `embed-shell` keeps `AppShell`. The same build-time collision guard added to catch this also caught `chat-thread-ui`'s primitive yaml still declaring `component: ChatThread`, colliding with the chat web-module's own `ChatThread` — the primitive's catalog identity is now `UIChatThread`. A raw a2ui tree with `{"component": "AppShell"}` meaning the stable admin shell, or `{"component": "ChatThread"}` meaning the standalone primitive, needs updating; the HTML tags (`<admin-shell>`, `<chat-thread-ui>`) are unaffected. See [§ Shipped in `0.8.41` — A2UI catalog `component:` collision](#upcoming--a2ui-catalog-component-collision-adminshell--uichatthread-090-gh1427).
76
+
77
+ - **Shipped in `0.8.41` (`progress-row-ui` deprecated — absorbed into `progress-ui`, gh#1373)** — **Non-breaking, deprecation alias.** `<progress-ui>` gains `label` + `meta` props; a non-empty `label` activates the identical labeled-row layout `<progress-row-ui>` used to own (a new Sanctioned Mode Attribute per the component-token-contract). `<progress-row-ui>` keeps working unchanged (still composes `<progress-ui>` internally) but ships `status: deprecated` and is no longer taught to the A2UI catalog or generated for new work. Migration: `<progress-row-ui label="…" value="…" meta="…">` → `<progress-ui label="…" value="…" meta="…">` — attribute names are identical, a mechanical tag rename. `variant` (the color-family prop on the old component) has **no successor on `<progress-ui>`** — progress's `variant` prop was already retired bar-only in the gh#1370 C2 rider and stayed retired; recolor the fill via the `--progress-fill` token instead (`--progress-fill: var(--a-success-bg)` etc.), consistent with progress's existing token-only convention. Filed from the catalog-regularity audit's C4 finding (gh#1363) — progress's own canonical catalog example already put `label` on a `Progress` node, meaning generation copying that exemplar failed validation before this rider. See [§ Shipped in `0.8.41` — `progress-row-ui` deprecated](#upcoming--progress-row-ui-deprecated--absorbed-into-progress-ui-090-gh1373).
78
+ - **Shipped in `0.8.41` (`segmented-ui` gains `[multiple]`; `toggle-group-ui`/`toggle-option-ui` deprecated, gh#1369)** — **Additive, non-breaking + soft deprecation (no removal).** `<segmented-ui>` gains a `multiple: Boolean` axis (default `false`, positive polarity matching `select-ui[multiple]`): under `[multiple]`, `value` is a comma-separated set (same encoding `toggle-group-ui` and `select-ui[multiple]` already use), the sliding indicator is suppressed, each selected `<segment-ui>` carries its own background instead, and Space/Enter toggles a focused segment rather than arrow-move selecting it. `<toggle-group-ui>` + `<toggle-option-ui>` are marked `status: deprecated` and log a one-time `console.warn` — they keep working exactly as before, no behavior change. **Recommended migration:** `<toggle-group-ui value="…">` + `<toggle-option-ui>` children → `<segmented-ui multiple value="…">` + `<segment-ui>` children (value encoding is identical; `text`/`icon`/`disabled` map directly). Filed from the catalog-regularity audit's C1 finding (gh#1363) — the strongest-ranked consolidation candidate: `toggle-group-ui` already had a `single` mode prop making it segmented, and had zero corpus chunks vs. segmented/segment's 19 each, so multi-select intents retrieved nothing or mis-retrieved single-select chunks. See [§ Shipped in `0.8.41` — `segmented-ui` gains `[multiple]`](#upcoming--segmented-ui-gains-multiple-toggle-group-uitoggle-option-ui-deprecated-090-gh1369).
79
+
80
+ - **Shipped in `0.8.41` (`calendar-picker-ui` absorbs `datetime-picker-ui`, gh#1372)** — **Mostly additive + soft deprecation; two real breaking removals on `calendar-picker-ui` itself.** `<calendar-picker-ui>` gains a `precision` axis (`date`|`minute`|`second`, default `date` — unchanged for every existing consumer) plus `step`/`hour-cycle`/`locale` and the `input`/`open`/`close`/`invalid` events datetime mode needs. `<datetime-picker-ui>` is now `status: deprecated`, implemented as a thin `calendar-picker-ui` subclass (`precision="minute"` by default) — it keeps working unchanged; **recommended (non-breaking) migration:** `<datetime-picker-ui>` → `<calendar-picker-ui precision="minute">`. **Breaking, no deprecation alias:** `<calendar-picker-ui>`'s own `label` prop/slot are removed — wrap in `<field-ui label>` instead, matching every sibling picker (this was `calendar-picker-ui`'s own outlier); and `<datetime-picker-ui>`'s `--datetime-picker-*` CSS tokens are removed — styling now flows through `<calendar-picker-ui>`'s shared `--calendar-picker-*` tokens. Filed from the catalog-regularity audit's C3c/C3d findings (gh#1363). See [§ Shipped in `0.8.41` — `calendar-picker-ui` absorbs `datetime-picker-ui`](#upcoming--calendar-picker-ui-absorbs-datetime-picker-ui-behind-a-widened-precision-axis-090-gh1372).
81
+ - **Shipped in `0.8.41` (primitive-tier `data-*` state converges to bare attributes, gh#1332)** — **BREAKING, no deprecation alias.** The residual primitive-tier round of the [data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332) (Category A), following the web-modules round above: `<feed-item-ui>`'s `[data-open]`/`[data-closing]` states and its `[data-queued]` max-queue marker (stamped by the parent `<feed-ui>`'s post logic, carried on the item) converge to bare `[open]`/`[closing]`/`[queued]`; `<slider-ui>` and `<range-ui>`'s `[data-dragging]` converges to bare `[dragging]`; `<pane-ui>`'s `[data-resizing]` converges to bare `[resizing]` (matching admin-sidebar/chat-sidebar's own `[resizing]` convention from the web-modules round); `<chart-ui>`'s `[data-has-data]` converges to bare `[has-data]`; `<select-ui>`'s private `[data-multi-chips]` mirror is dropped outright — its 8 CSS selectors now key off the compound `[multiple]:not([summary-label])`, both already-declared reflected props, no bare successor attribute needed. See [§ Shipped in `0.8.41` — primitive-tier data-* state converges to bare attributes](#upcoming--primitive-tier-data--state-converges-to-bare-attributes-090-gh1332-2).
82
+
83
+ - **Shipped in `0.8.41` (`image-ui` load/error states declared + converge to bare attributes, gh#1464)** — **BREAKING, no deprecation alias.** The final residue of the [data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332), deferred out of the residual round above because it needed a new `states:` declaration rather than a bare mapping change: `<image-ui>`'s `[data-loaded]`/`[data-error]` were genuine undeclared host-level state (never yaml-declared at all) — now declared as `loaded`/`error` in `image.yaml`'s `states:` list with bare `attribute:` mappings, matching qr-code-ui's own converged `error` state. Migration: any `[data-loaded]`/`[data-error]` CSS or script targeting `image-ui` moves to `[loaded]`/`[error]`; `image-ui`'s unrelated `[data-overlay]` skeleton-proximity marker (gh#1362) is untouched. A repo-wide consumer sweep (`rg -nU 'data-loaded|data-error'`) found zero external consumers of image-ui's forms specifically, so no deprecation alias was kept. The same ticket also dispositioned the `data-msg-*` validation-message config family (`data-msg-required`/`pattern`/`minlength`/`maxlength`/`min`/`max`/`bad-input`) as **exempt, non-breaking, no migration** — it stays `data-*` by design (component-side config read by `core/form.js`'s shared mixin across 7+ components, not host-reflected state; see `primitive-authoring/references/yaml-contract.md`'s new `data-msg-*` section for the full rationale). See [§ Shipped in `0.8.41` — image-ui load/error states declared + converge to bare attributes](#upcoming--image-ui-loaderror-states-declared--converge-to-bare-attributes-090-gh1464).
84
+
85
+ - **Upcoming `0.9.0` (rename wave — `data-grid` / `data-resize`, docs/ops/plan/plan-090-rename-wave.md)** — **BREAKING at the 0.9.0 cut; a 0.8.x patch ships additive dual-read compat shims first (this entry), per the 2026-08-14 standing ruling that breaking renames never ship in a patch.** `admin-shell`'s consumer-authored 2/3-column content-layout helper `[data-grid]` / `[data-grid="3"]` renames to `[data-layout-grid]` / `[data-layout-grid="3"]` (sits with the `data-col`/`data-row`/`data-actions`/`data-spacer` form-layout-helper family it belongs to, outside every trait-owned root). The author-supplied drag-handle child of `<admin-sidebar>`/`<chat-sidebar>`/`<editor-sidebar>` `[data-resize]` renames to `[data-sidebar-resize]` (owner-scoped to the `*-sidebar` composite family, outside resize-observer's grandfathered `resize` root). Both attributes decorate plain light-DOM children the shells don't own (not a trait/component API), so only the name changes. **Now (0.8.x, additive):** both old and new names work — JS reads dual-query (new name first, falling back to old with a one-time `console.warn`), CSS selectors dual-select via `:is()`, and `adia-lint`'s SHELL-RESIZE rule accepts either name (advisory `DEPRECATED-LAYOUT-NAME` flags the old ones). **At the `0.9.0` cut:** the old names stop resolving — `[data-resize]` reverts to `<admin-sidebar>`'s existing "no handle found" author warning (the correct post-cut behavior, no new code needed) and `[data-grid]` simply no longer matches any CSS rule. Migration (published again, final, at the cut): `git grep -l 'data-resize' | xargs perl -pi -e 's/\bdata-resize\b(?!-)/data-sidebar-resize/g'` and `git grep -l 'data-grid' | xargs perl -pi -e 's/\bdata-grid\b(?!-)/data-layout-grid/g'` (negative lookahead protects trait-owned `data-resize-*`/`data-grid-*` names — unrelated grandfathered attributes, e.g. resize-observer's `data-resize-width`/`data-resize-observer-observed` and arrow-grid-nav's `data-grid-columns`/`mode`/`active-row`/`active-col`, which this wave never touches). Tracked: gh#1560 (this shim) → gh#1561 (in-repo consumer + docs migration) → gh#1562 (the 0.9.0 cut). Disjoint from, and coordinated with, gh#1377/gh#1563's ADR-0063 rename set (chart `hide-*`, `pane[side]`, `color-picker-ui` → `color-area-ui`, `menu-item-ui[subtitle]`) — same 0.9.0 cycle, separate PRs, no file overlap.
86
+
87
+ - **Upcoming `0.9.0` (ADR-0063 attribute-grammar addendum — chart `no-*`, `chart-legend[interactive]`, `pane[edge]`, `color-area-ui`, `menu-item[description]`, gh#1377/gh#1563)** — **BREAKING at the 0.9.0 cut; a 0.8.42 patch ships additive dual-read compat shims first (this entry), per the same 2026-08-14 standing ruling gh#1560's rename wave follows: breaking renames never ship in a patch.** Five identifiers converge onto ADR-0063's ratified spellings: `chart-ui[hideAverage|hideGrid|hideValues]` → `[noAverage|noGrid|noValues]` (same polarity, straight rename — `no-*` has 8-component/12-attribute plurality over `hide-*`'s 2/4); `chart-legend-ui[static]` (opt-out) → `[interactive]` (opt-in) — **the default itself is NOT flipped in 0.8.42**, `[interactive]` defaults `true` so omitting both attributes keeps today's behavior unchanged, the real default-inversion to `false` is deferred to the 0.9.0 cut per the ADR's own consumer-scan requirement (every `<chart-legend-ui>` tag needs review first); `pane-ui[side]` → `[edge]` (pane-only — `drawer-ui[side]` keeps its own name/vocabulary unchanged); `menu-item-ui[subtitle]` → `[description]` (prop only — the `subtitle` SLOT is a separate, deliberately unrenamed surface); and the tag/component rename `color-picker-ui`/`ColorPicker`/`UIColorPicker` → `color-area-ui`/`ColorArea`/`UIColorArea` (B11 — `-picker` is reserved for the outer trigger+popover composite shape; `color-picker-ui` was the sole violator, playing `calendar-grid-ui`'s inline-substrate role — mirrors the `datetime-picker-ui` → `calendar-picker-ui` alias shape from gh#1372). **Now (0.8.42, additive):** every old name/tag keeps working — each renamed attribute dual-reads (new name wins when both are present, the old name resolves with a one-time `console.warn` when it's the only one set, no warn either way otherwise) and `<color-picker-ui>` is a thin `UIColorArea` subclass (`status: deprecated`) rather than a removed tag. `<color-input-ui>`'s own `composes:` and internal substrate references move to `<color-area-ui>` (its own tag/name is unaffected — it was already correctly *not* named `-picker` despite playing the composite role). **At the `0.9.0` cut:** the old names/tag stop resolving and `chart-legend-ui[interactive]`'s default flips to `false`. Migration (mechanical, at the cut): `git grep -l 'hide-average\|hide-grid\|hide-values' | xargs perl -pi -e 's/\bhide-average\b/no-average/g; s/\bhide-grid\b/no-grid/g; s/\bhide-values\b/no-values/g'`; `git grep -l 'pane-ui' | xargs perl -pi -e 's/(<pane-ui\b[^>]*\b)side=/\1edge=/g'`; `git grep -l 'menu-item-ui' | xargs perl -pi -e 's/(<menu-item-ui\b[^>]*\b)subtitle=/\1description=/g'`; `git grep -rl 'color-picker-ui\|UIColorPicker' | xargs perl -pi -e 's/color-picker-ui/color-area-ui/g; s/UIColorPicker/UIColorArea/g'`; every `<chart-legend-ui>` tag (with or without `[static]`/`[interactive]`) needs a manual pass adding `[interactive]` where the old default was relied on. Filed from the catalog-regularity audit's B2/B3(noodles-only, non-breaking)/B5/B11 findings (gh#1363) via [ADR-0063](../../docs/ops/adr/adr-0063-attribute-grammar-addendum.md). **Rejected/deferred, not part of this dispatch's five items:** `action-item-ui[subtitle]` (a newly-surfaced sole outlier once menu-item converges — flagged for a human decision, not fixed here); `segmented-ui[multiple]`'s comma-separated value encoding (operator-sanctioned as-is); `toggle-group-ui[value]`'s comma-string violation (tracked by gh#1363's own toggle-group/segmented consolidation candidate); `drilldown-ui[static]`→`[no-slide-transition]`, `alert-ui[dismissible]`, `card-ui[outline]`, `agent-reasoning-ui[status="done"]`→`"completed"`, and `noodles-ui[port-size]`/`[show-ports]` duplicate-entry cleanup (all ADR-0063 decisions, but each is its own separately-scoped follow-up build, not gh#1563's five-item scope). Disjoint from, and coordinated with, gh#1560/gh#1561/gh#1562's `data-grid`/`data-resize` rename wave — same 0.9.0 cycle, separate PRs, no file overlap. See [§ Upcoming — ADR-0063 attribute-grammar addendum](#upcoming--adr-0063-attribute-grammar-addendum-chart-no--chart-legendinteractive-paneedge-color-area-ui-menu-itemdescription-090-gh1377gh1563).
88
+
89
+ - **Upcoming `0.9.0` (ADR-0063 convergence — `action-item-ui[description]`, gh#1571)** — **BREAKING at the 0.9.0 cut; an additive patch ships a dual-read compat shim first (this entry), per the same 2026-08-14 standing ruling gh#1560's rename wave and gh#1563's ADR-0063 addendum both follow: breaking renames never ship in a patch.** `action-item-ui[subtitle]` → `[description]` (prop only — the `subtitle` **slot** is a separate, deliberately unrenamed surface, exactly like `menu-item-ui`'s own gh#1563 shape). This closes the gap PR #1569 itself flagged as a rejected/deferred follow-up once `menu-item-ui` converged onto `description`: `action-item-ui` became the corpus's remaining sole `subtitle` outlier. **Now (additive):** both names work — `[description]` wins outright when present (no warning — this is intentional forward-compatible spelling, not a fallback); `[subtitle]` resolves with a one-time `console.warn` per class when it's the only one set; a post-mount `[subtitle]` update keeps mirroring into `[description]` until `[description]` is authored directly, at which point it wins permanently. **At the `0.9.0` cut:** `[subtitle]` stops resolving. Migration (mechanical, at the cut): `git grep -l '<action-item-ui\b' | xargs perl -pi -e 's/(<action-item-ui\b[^>]*\b)subtitle=/\1description=/g'`. See [§ Upcoming — `action-item-ui[description]` ADR-0063 convergence](#upcoming--action-item-uidescription-adr-0063-convergence-090-gh1571). **Rejected/deferred:** the 0.9.0 breaking removal itself — same "no breaking rename in a patch" standing ruling as every sibling entry above.
64
90
 
65
91
  Live demos and per-component docs at [ui-kit.exe.xyz/site/](https://ui-kit.exe.xyz/site/). The `adia-ui-migration` skill (in `.agents/skills/`) automates most of the mechanical sweeps in this guide.
66
92
 
@@ -73,7 +99,7 @@ cut renames six published packages. Nothing about the rename is patch-shaped
73
99
  except the number, which is an operator ruling (gh#1192, 2026-08-13) about
74
100
  release cadence, not a claim that your imports keep working forever.
75
101
 
76
- The split is by concept, ruled in `docs/adr/adr-0048-a2ui-gen-ui-estate-split.md`:
102
+ The split is by concept, ruled in `docs/ops/adr/adr-0048-a2ui-gen-ui-estate-split.md`:
77
103
 
78
104
  - **`@adia-ai/a2ui` — the protocol.** How one system renders gen-UI canvases
79
105
  in another system, safely: renderer, registry, streams, surface, wiring,
@@ -250,7 +276,8 @@ between a dependency and a peer:
250
276
 
251
277
  ---
252
278
 
253
- ## Upcoming — variant/color/tone convention cut
279
+ <a id="upcoming-variant-color-tone-convention-cut"></a>
280
+ ## Shipped in `0.8.33` — variant/color/tone convention cut (ADR-0044, gh#873/874/875/876/881)
254
281
 
255
282
  **One theme: every color-ish attribute owns exactly one axis.** `variant`/`tone` on badge & tag
256
283
  and `variant`/`color` on button now each carry either a *semantic family* or a *fill style*,
@@ -392,14 +419,15 @@ npm run check # in-repo consumers; downstream: your app's build + a visual pas
392
419
 
393
420
  ---
394
421
 
395
- ## Upcoming — `0.8.40` attribute-grammar reconciliation (ADR-0054)
422
+ <a id="upcoming-0840-attribute-grammar-reconciliation-adr-0054"></a>
423
+ ## Shipped in `0.8.40` — attribute-grammar reconciliation (ADR-0054)
396
424
 
397
- **BREAKING, no deprecation alias.** [ADR-0054](../../docs/adr/adr-0054-attribute-grammar-reconciliation.md)
425
+ **BREAKING, no deprecation alias.** [ADR-0054](../../docs/ops/adr/adr-0054-attribute-grammar-reconciliation.md)
398
426
  resolves two component-local attributes that shadowed the [global attribute
399
427
  grammar](../../.claude/docs/specs/attribute-api-system.md) with divergent vocabularies —
400
428
  `table-ui[density]` **converges** onto the global mechanism (it already did
401
429
  the job), `chart-ui[radius]` **renames** (a numeric px value is a genuinely
402
- different shape than the global preset enum). Per [ADR-0053](../../docs/adr/adr-0053-no-shadowing-global-attributes.md),
430
+ different shape than the global preset enum). Per [ADR-0053](../../docs/ops/adr/adr-0053-no-shadowing-global-attributes.md),
403
431
  neither collision is exempted — `swatch-ui[color]` / `noodles-ui[color]` are
404
432
  the only two ratified exceptions (documented in
405
433
  [§11 of attribute-api-system.md](../../.claude/docs/specs/attribute-api-system.md#11-global-attribute-exemption-list)),
@@ -469,7 +497,8 @@ npm run check
469
497
 
470
498
  ---
471
499
 
472
- ## Upcoming — qr-code-ui quiet-zone rename (ADR-0053)
500
+ <a id="upcoming--qr-code-ui-quiet-zone-rename-adr-0053"></a>
501
+ ## Shipped in `0.8.40` — qr-code-ui quiet-zone rename (ADR-0053)
473
502
 
474
503
  **BREAKING, ships in `0.8.40`.** `<qr-code-ui>`'s reflected `[margin]` attribute is
475
504
  renamed `[quiet-zone]` (property `quietZone`) — same `number` type, same default (`4`), same
@@ -480,7 +509,7 @@ grammar, inferable: `margin="4"` means the same thing on every element, resolvin
480
509
  Scale mechanism (`--a-margin`). `qr-code-ui` declared its own reflected `margin` meaning the QR
481
510
  "quiet zone" in grid cells. Both grammars accepted the identical syntax with no error surfaced,
482
511
  so an author reaching for `<qr-code-ui margin="4">` expecting global spacing silently got a
483
- quiet-zone resize instead, and vice versa. [ADR-0053](../../docs/adr/adr-0053-no-shadowing-global-attributes.md)
512
+ quiet-zone resize instead, and vice versa. [ADR-0053](../../docs/ops/adr/adr-0053-no-shadowing-global-attributes.md)
484
513
  rules that no component-local attribute may shadow a global one; this is the first instance
485
514
  resolved under that policy (gh#1299).
486
515
 
@@ -521,9 +550,10 @@ npm run check # in-repo consumers; downstream: your
521
550
 
522
551
  ---
523
552
 
524
- ## Upcoming — leading-scale consolidation (ADR-0052)
553
+ <a id="upcoming--leading-scale-consolidation-adr-0052"></a>
554
+ ## Shipped in `0.8.40` — leading-scale consolidation (ADR-0052)
525
555
 
526
- **BREAKING, no aliases, ships in `0.8.40`.** [ADR-0052](../../docs/adr/adr-0052-leading-scale-consolidation.md)
556
+ **BREAKING, no aliases, ships in `0.8.40`.** [ADR-0052](../../docs/ops/adr/adr-0052-leading-scale-consolidation.md)
527
557
  retires the legacy `--a-leading-*` family. `--a-font-leading-*` is now the
528
558
  single canonical line-height scale.
529
559
 
@@ -602,9 +632,10 @@ npm run check
602
632
 
603
633
  ---
604
634
 
605
- ## Upcoming — `toggle-option-ui` drops the legacy `data-selected` stamp (`0.8.40`, ADR-0056)
635
+ <a id="upcoming--toggle-option-ui-drops-the-legacy-data-selected-stamp-0840-adr-0056"></a>
636
+ ## Shipped in `0.8.40` — `toggle-option-ui` drops the legacy `data-selected` stamp (ADR-0056)
606
637
 
607
- **BREAKING, no deprecation alias.** [ADR-0056](../../docs/adr/adr-0056-selection-item-selected-convention.md)'s
638
+ **BREAKING, no deprecation alias.** [ADR-0056](../../docs/ops/adr/adr-0056-selection-item-selected-convention.md)'s
608
639
  breaking half removes `<toggle-group-ui>`'s legacy `data-selected` attribute
609
640
  stamp on its `<toggle-option-ui>` children. The declared, reflected `selected`
610
641
  prop (shipped additively in `0.8.39`) is now the *only* current-state surface
@@ -624,6 +655,1188 @@ npm run check
624
655
 
625
656
  ---
626
657
 
658
+ <a id="upcoming--progress-ui-retires-variant-090-gh1370"></a>
659
+ ## Shipped in `0.8.41` — `progress-ui` retires `variant` (gh#1370)
660
+
661
+ **BREAKING, no deprecation alias.** `<progress-ui>`'s `variant` prop
662
+ (`bar` | `spinner`) is removed — progress is bar-only. `<spinner-ui>`
663
+ owns circular loading indicators.
664
+
665
+ **Why:** `packages/web-components/MIGRATION.md:2125,2139` records the
666
+ original standalone spinner being merged INTO progress as
667
+ `variant="spinner"` in the old `@agent-ui-kit` → `@adia-ai` migration —
668
+ then a richer standalone `<spinner-ui>` (`arc`/`ring`/`dots`/`knight`,
669
+ `tone`, `paused`, `label`) was later re-added. Both shipped in the
670
+ catalog, so a "loading" intent had three valid answers instead of two
671
+ disjoint ones. Retiring the render mode from progress un-forks the
672
+ consolidation that was already undone once. Filed from the
673
+ catalog-regularity audit's C2 finding, [gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363).
674
+
675
+ **Migration:**
676
+
677
+ | Old | New |
678
+ |---|---|
679
+ | `<progress-ui variant="spinner">` | `<spinner-ui>` (`arc` is the closest visual match to the old rotating-arc spinner render; pick `ring`/`dots`/`knight` if the intent was different) |
680
+ | `<progress-ui variant="bar">` | drop the attribute — `bar` was already the default |
681
+ | `<progress-ui>` (no variant) | unchanged — already bar, already the default |
682
+
683
+ `<spinner-ui>` has no `value` prop — it is indeterminate-only. A
684
+ determinate use of `variant="spinner"` (if any existed) has no direct
685
+ spinner-ui equivalent; keep `<progress-ui>` and drop the `variant`
686
+ attribute instead (renders as a determinate bar).
687
+
688
+ **Find every affected consumer site with the repo's own scanner — not
689
+ ad-hoc grep** (a markup grep also fires on this very guide's worked
690
+ examples above, and misses double-quoted setters, multiline HTML
691
+ attributes, and whitespace variations around `=`):
692
+
693
+ ```bash
694
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
695
+ ```
696
+
697
+ `scripts/qa/contract-migration-scan.mjs` (gh#1405, shipped on `main`)
698
+ detects the `variant` removal from `progress.yaml` directly and
699
+ enumerates every markup consumer under `packages/`, `apps/`,
700
+ `playgrounds/`, `site/` — including corpus chunks — read from the two
701
+ git refs, so a dirty working tree never leaks into the report. Its own
702
+ tag-markup matching also fires on this guide's *shipped* copy
703
+ (`packages/web-components/MIGRATION.md`, which lives under `packages/`
704
+ and quotes `variant="spinner"` as a worked example above, not live
705
+ usage) — expect and disregard that one self-hit; any other reported
706
+ site is a real consumer to migrate. The scanner's markup-textual
707
+ matching does not cover JS `setAttribute()`/property-assignment call
708
+ sites (its own documented limitation) — grep those separately:
709
+
710
+ ```bash
711
+ git grep -rnE "setAttribute\('variant', *'(bar|spinner)'\)"
712
+ ```
713
+
714
+ Verify each hit's element is actually a `progress-ui` host before
715
+ rewriting — the same discipline as the variant/color/tone convention
716
+ cut's own sweep above.
717
+
718
+ ### Verify
719
+
720
+ ```bash
721
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref> # only the MIGRATION.md self-hit, no other sites
722
+ git grep -rnE "setAttribute\('variant', *'(bar|spinner)'\)" # review each hit manually
723
+ npm run check
724
+ ```
725
+
726
+ ---
727
+
728
+ <a id="upcoming--input-ui-trims-type-enum-090-gh1381"></a>
729
+ ## Shipped in `0.8.41` — `input-ui` trims `type` enum (gh#1381)
730
+
731
+ **BREAKING, no deprecation alias.** `<input-ui>`'s `type` enum is
732
+ trimmed to the six values it actually implements — `text` | `email` |
733
+ `password` | `number` | `tel` | `url`. `search`, `date`,
734
+ `datetime-local`, `time`, `month`, `week`, and `color` are removed.
735
+
736
+ **Why:** none of the seven removed values ever rendered a native
737
+ affordance — `input.class.js` only special-cases `password` (native
738
+ `<input>` for disc masking) and `number` (contenteditable + stepper
739
+ column); every other `type` value renders identically, a plain
740
+ contenteditable surface with no calendar, clock, swatch, or search
741
+ icon. `type="date"` was first-pass-VALID against the old enum but
742
+ functionally broken generation output — an LLM emitting it produces
743
+ markup that validates yet gives the user a bare text box where a date
744
+ picker was intended. Filed from the catalog-regularity audit's B10
745
+ finding, [gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363).
746
+
747
+ **Migration:**
748
+
749
+ | Old | New |
750
+ |---|---|
751
+ | `<input-ui type="search">` | `<search-ui>` (built-in magnifying-glass icon, clear button, debounced `search` event) |
752
+ | `<input-ui type="date">` | `<calendar-picker-ui>` (single-date, day granularity) |
753
+ | `<input-ui type="month">` / `type="week"` | `<calendar-picker-ui>` — no dedicated month/week-granularity primitive exists in the catalog; day granularity is the closest routed primitive |
754
+ | `<input-ui type="datetime-local">` | `<datetime-picker-ui>` |
755
+ | `<input-ui type="time">` | `<time-picker-ui>` |
756
+ | `<input-ui type="color">` | `<color-input-ui>` (compact form-row swatch + popover) — or `<color-picker-ui>` directly for a full-surface editor (Tokens-Studio-style canvas) |
757
+ | `<input-ui>` (no type, or `text`/`email`/`password`/`number`/`tel`/`url`) | unchanged |
758
+
759
+ The routed primitives are NOT drop-in attribute-compatible with
760
+ `input-ui` — each has its own prop surface (e.g. `time-picker-ui`
761
+ expects ISO `HH:mm`/`HH:mm:ss`, `calendar-picker-ui` expects ISO
762
+ `YYYY-MM-DD`, `color-input-ui` emits both `hex` and `oklch` views).
763
+ Re-check `name`/`value`/`required`/`disabled` against the target
764
+ primitive's own yaml rather than assuming a mechanical attribute
765
+ carry-over.
766
+
767
+ **The repo's own scanner does not catch this class of change** —
768
+ `scripts/qa/contract-migration-scan.mjs`'s diff detection is scoped to
769
+ a yaml losing a `props`/`tokens` key or its `tag:` field (its own
770
+ documented v1 scope); narrowing an existing prop's `enum:` list is
771
+ invisible to it, since the `type` prop key itself is untouched. Find
772
+ affected sites with the repo's established multiline-capable sweep
773
+ recipe instead (§14.5's precedent — `git grep` is line-based, so a
774
+ `[^>]*` character class cannot cross a newline and misses a multi-line
775
+ opening tag; `rg -nU` is required, quote-aware, tag-scoped, and
776
+ excludes the historical/generated surfaces that legitimately still
777
+ quote the old markup as a worked example — this guide's own table
778
+ above, its shipped copy, `CHANGELOG*.md`, `dist/`, and `.claude/docs/`
779
+ itself, which also covers the frozen `.claude/docs/specs/*.md`
780
+ planning records):
781
+
782
+ ```bash
783
+ rg -nU '<input-ui[^>]*type="(search|date|datetime-local|time|month|week|color)"' \
784
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
785
+ -g '!.claude/docs/**'
786
+ ```
787
+
788
+ Verify each hit's element is actually an `input-ui` host, then migrate
789
+ per the table above. The corpus harvest (`npm run harvest:chunks`)
790
+ independently re-validates every chunk against the updated catalog
791
+ schema and will name any consumer still using a removed `type` value
792
+ as a chunk-validation failure — run it after the yaml edit and before
793
+ opening a PR; it is a second, stricter check this scanner's own
794
+ limitation makes necessary for enum-narrowing changes, but it is NOT a
795
+ substitute for the sweep above — the harvest only validates chunks the
796
+ corpus actually harvests (annotated `data-chunk` regions), so a
797
+ non-harvested consumer (a component's own `.examples.html` demo, a
798
+ JS-composed internal template like `search.class.js`'s own former
799
+ `<input-ui type="search">` stamp) needs the direct sweep to be found at
800
+ all.
801
+
802
+ ### Verify
803
+
804
+ ```bash
805
+ rg -nU '<input-ui[^>]*type="(search|date|datetime-local|time|month|week|color)"' \
806
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
807
+ -g '!.claude/docs/**' # must be 0 hits (exit 1, rg's "no match" signal) after migrating real sites
808
+ npm run harvest:chunks # 0 catalog:input validation failures
809
+ npm run check
810
+ ```
811
+
812
+ ---
813
+
814
+ <a id="upcoming--web-modules-data--state-converges-to-bare-attributes-090-gh1332"></a>
815
+ ## Shipped in `0.8.41` — web-modules `data-*` state converges to bare attributes (gh#1332)
816
+
817
+ **BREAKING, no deprecation alias.** Two web-modules' declared `states:`
818
+ entries used a private `data-*` stamp where a sibling state on the SAME
819
+ component already used a bare state attribute — an inconsistency the
820
+ [data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332)
821
+ (Category A) generalizes ADR-0056's rule to catch: API-conceptual state a
822
+ consumer/generator can see in the yaml `states:` list belongs on a bare
823
+ attribute, never hidden behind `data-*`.
824
+
825
+ | Component | Old | New |
826
+ |---|---|---|
827
+ | `<integrations-page-ui>` | `[data-empty-search]` | `[empty-search]` |
828
+ | `<integrations-page-ui>` | `[data-empty-data]` | `[empty-data]` |
829
+ | `<onboarding-checklist-ui>` | `[data-complete]` | `[complete]` |
830
+
831
+ **Why:** `integrations-page-ui`'s `states:` list already declares
832
+ `loading` with `attribute: loading` (bare) right next to `empty-search`/
833
+ `empty-data`, which used `attribute: data-empty-search`/
834
+ `data-empty-data` — same kind of declared, documented state, two
835
+ different attribute grammars on one component. `onboarding-checklist-ui`
836
+ has the identical shape: `collapsed` and `dismissed` both reflect bare
837
+ attributes (`collapsed`, `hidden`) while `complete` alone used
838
+ `data-complete`. Neither was ever declared in the component's `props:`
839
+ section — both were computed, read-only states set directly via
840
+ `setAttribute`/`removeAttribute`, styling hooks in the same family as
841
+ `loading`/`collapsed`, just minted with the wrong prefix.
842
+
843
+ **Find every affected consumer site with the repo's own scanner, plus
844
+ the multiline-capable manual sweep** (established in the `input-ui`
845
+ `type`-enum rider above, and again at gh#1414/gh#1420) — a line-based
846
+ `git grep` misses multi-line opening tags, and a bracketed-selector-only
847
+ search misses a JS consumer reading the raw attribute name via
848
+ `getAttribute`/`setAttribute`/`hasAttribute`/`dataset`, not a CSS
849
+ selector:
850
+
851
+ ```bash
852
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
853
+ # contract-migration-scan's v1 scope is props:/tokens:/tag: — states: entries
854
+ # are outside it (no props/tag/token key is lost here), so treat its report
855
+ # as a first pass, not the full sweep for THIS migration; the rg sweep below
856
+ # is what actually covers it.
857
+ rg -nU '\[data-empty-search\]|\[data-empty-data\]|\[data-complete\]|data-empty-search|data-empty-data|data-complete' \
858
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
859
+ -g '!.claude/docs/**'
860
+ ```
861
+
862
+ The raw-name alternation catches `el.getAttribute('data-empty-search')` /
863
+ `el.dataset.emptySearch` (dataset reads reflect through the raw attribute
864
+ name in the DOM, not the camelCase JS property) alongside the bracketed
865
+ CSS-selector form; the bracketed alternation stays for a selector split
866
+ across a line the raw form's word boundary might otherwise merge with a
867
+ neighboring token. `integrations-page-ui`'s unrelated `data-empty-reason`
868
+ (an internal part-scoped value attribute, not this `states:` entry) is
869
+ intentionally excluded from both alternations — do not add it.
870
+
871
+ **Migrate each verified hit** — review before rewriting; the portable
872
+ form below avoids `sed -i`'s BSD-vs-GNU flag divergence (BSD `sed -i`
873
+ requires an explicit, even empty, backup-suffix argument; GNU `sed -i`
874
+ treats a bare backup-suffix argument as the script itself and errors —
875
+ the two are not drop-in compatible, so a script this guide hands to
876
+ `rg -l | xargs` for consumers on either platform needs a wrapper neither
877
+ flavor chokes on):
878
+
879
+ ```bash
880
+ rg -l '\[data-empty-search\]|\[data-empty-data\]|data-empty-search|data-empty-data' \
881
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' \
882
+ | xargs perl -pi -e 's/data-empty-search/empty-search/g; s/data-empty-data/empty-data/g'
883
+ rg -l '\[data-complete\]|data-complete' \
884
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' \
885
+ | xargs perl -pi -e 's/data-complete/complete/g'
886
+ ```
887
+
888
+ ### Verify
889
+
890
+ ```bash
891
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
892
+ rg -nU '\[data-empty-search\]|\[data-empty-data\]|\[data-complete\]|data-empty-search|data-empty-data|data-complete' \
893
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
894
+ -g '!.claude/docs/**' # must be 0 hits (exit 1, rg's "no match" signal) after migrating real sites
895
+ ```
896
+
897
+ <a id="upcoming--primitive-tier-data--state-converges-to-bare-attributes-090-gh1332-2"></a>
898
+ ## Shipped in `0.8.41` — primitive-tier `data-*` state converges to bare attributes (gh#1332-2)
899
+
900
+ **BREAKING, no deprecation alias.** The residual primitive-tier round of
901
+ the [data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332)
902
+ (Category A), covering the ~25 primitives left over after the web-modules
903
+ round above. Same rule: API-conceptual state a consumer/generator can see
904
+ in the yaml `states:` list belongs on a bare attribute, never hidden
905
+ behind `data-*`.
906
+
907
+ | Component | Old | New |
908
+ |---|---|---|
909
+ | `<feed-item-ui>` | `[data-open]` | `[open]` |
910
+ | `<feed-item-ui>` | `[data-closing]` | `[closing]` |
911
+ | `<feed-item-ui>` | `[data-queued]` | `[queued]` |
912
+ | `<slider-ui>` | `[data-dragging]` | `[dragging]` |
913
+ | `<range-ui>` | `[data-dragging]` | `[dragging]` |
914
+ | `<pane-ui>` | `[data-resizing]` | `[resizing]` |
915
+ | `<chart-ui>` | `[data-has-data]` | `[has-data]` |
916
+ | `<select-ui>` | `[data-multi-chips]` | *(removed — no successor; see below)* |
917
+ | `<qr-code-ui>` | `[data-error]` | `[error]` |
918
+ | `<table-ui>` | `[data-selected]` (body rows) | `[aria-selected="true"]` |
919
+ | `<pagination-ui>` | `[data-active]` (page buttons) | `[aria-current="page"]` |
920
+ | `<tags-input-ui>` | `[data-empty]` (inline input) | *(removed — key off the host's declared `:not([editing])` inverse)* |
921
+ | `<input-ui>` | `[data-number]` (field div) | *(removed — key off the declared, reflected host `[type="number"]`)* |
922
+
923
+ **Why:** `feed-item-ui`'s open/closing lifecycle and `feed-ui`'s
924
+ above-`[max]` queue marker, `slider-ui`/`range-ui`'s mid-drag flag,
925
+ `pane-ui`'s mid-resize flag, and `chart-ui`'s has-data flag were each set
926
+ directly via `this.setAttribute`/`removeAttribute` on the host with no
927
+ `props:`/`states:` declaration — private stamps for genuine, observable
928
+ lifecycle state. `pane-ui[resizing]` matches the bare `[resizing]`
929
+ convention `admin-sidebar-ui`/`chat-sidebar-ui` already carry (fixed in
930
+ the web-modules round above, PR #1438) rather than minting a new name.
931
+
932
+ `select-ui[data-multi-chips]` is different in kind: it was a pure
933
+ *derived* cache of two attributes ALREADY declared and reflected —
934
+ `[multiple]` and `[summary-label]` — so there is no successor attribute;
935
+ consumer CSS/JS keying off the private mirror should key off the compound
936
+ selector `[multiple]:not([summary-label])` (or the equivalent JS property
937
+ check) directly instead.
938
+
939
+ The residual-round entries follow the same two shapes. `qr-code-ui`'s
940
+ `error` state was already yaml-declared but mapped to `attribute:
941
+ data-error` — the mapping converged to bare `[error]` (the same shape as
942
+ the web-modules round's `integrations-page-ui` converge). `table-ui`'s
943
+ body-row `[data-selected]` and `pagination-ui`'s page-button
944
+ `[data-active]` were private duplicates of an ARIA attribute set on the
945
+ SAME element in the same code path (`aria-selected="true"` /
946
+ `aria-current="page"`) — the ARIA attribute alone now carries the state
947
+ (PR #1438's `admin-roster` `aria-checked` precedent). `tags-input-ui`'s
948
+ inline-input `[data-empty]` was the exact inverse of the host's declared
949
+ `[editing]` state, and `input-ui`'s `[data-number]` field marker was a
950
+ mirror of the declared, reflected `[type="number"]` — both dropped with
951
+ no successor, `select-ui`-style.
952
+
953
+ **Find every affected consumer site:**
954
+
955
+ ```bash
956
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
957
+ # props:/tokens:/tag: scope only — none of these are prop/tag/token
958
+ # changes (states: entries + one dropped private mirror), so treat this
959
+ # as a first pass; the rg sweep below is what actually covers it.
960
+ # Attribute forms (HTML/CSS/JS strings) — word-bounded so e.g. `data-opening`
961
+ # or another component's own `data-error` prose doesn't false-positive:
962
+ rg -nU 'data-(open|closing|queued|dragging|resizing|has-data|multi-chips|selected|active|empty|error|number)\b' \
963
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
964
+ -g '!.claude/docs/**' -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json'
965
+ # dataset.* property forms (JS) — the camelCase twins of the same attributes:
966
+ rg -nU 'dataset\.(open|closing|queued|dragging|resizing|hasData|multiChips|selected|active|empty|error|number)\b' \
967
+ -g '!**/dist/**' -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json'
968
+ ```
969
+
970
+ Review each hit before rewriting — `data-open`/`data-closing` also appear
971
+ verbatim on `modal-ui`/`drawer-ui`'s own INTERNAL `<dialog slot="dialog">`
972
+ anatomy child (never on those hosts, and unrelated to this migration —
973
+ those two already expose a real `open` prop; the private child-level
974
+ stamp is an animation-timing implementation detail, left as-is), and
975
+ `data-dragging` also appears on `swiper-ui`'s internal track child (same
976
+ shape, also left as-is). Only the eight HOST-level attributes in the
977
+ table above moved.
978
+
979
+ **Migrate each verified hit:**
980
+
981
+ ```bash
982
+ # Word-bounded exact tokens only (\b guards partial identifiers like
983
+ # `data-opening`), generated artifacts excluded (regenerate those with the
984
+ # repo's own commands afterwards — never rewrite them in place):
985
+ EXCL=(-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**'
986
+ -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json' -g '!site-a2ui/**'
987
+ -g '!**/corpus/chunks/**')
988
+ rg -l 'data-(open|closing|queued)\b' "${EXCL[@]}" \
989
+ -g '!**/components/modal/**' -g '!**/components/drawer/**' \
990
+ | xargs perl -pi -e 's/\bdata-open\b/open/g; s/\bdata-closing\b/closing/g; s/\bdata-queued\b/queued/g'
991
+ rg -l 'data-dragging\b' "${EXCL[@]}" -g '!**/components/swiper/**' \
992
+ | xargs perl -pi -e 's/\bdata-dragging\b/dragging/g'
993
+ rg -l 'data-resizing\b' "${EXCL[@]}" \
994
+ | xargs perl -pi -e 's/\bdata-resizing\b/resizing/g'
995
+ rg -l 'data-has-data\b' "${EXCL[@]}" \
996
+ | xargs perl -pi -e 's/\bdata-has-data\b/has-data/g'
997
+ rg -l 'data-error\b' "${EXCL[@]}" \
998
+ | xargs perl -pi -e 's/\bdata-error\b/error/g' # qr-code-ui sites only — review hits first, other components keep their own data-error
999
+ # table-ui [data-selected] → [aria-selected="true"], pagination-ui
1000
+ # [data-active] → [aria-current="page"], tags-input-ui [data-empty] →
1001
+ # :scope:not([editing]) …, input-ui [data-number] → [type="number"] …:
1002
+ # ARIA/compound successors — rewrite these selector-by-selector by hand,
1003
+ # there is no mechanical 1:1 attribute swap.
1004
+ # After all rewrites, regenerate derived artifacts:
1005
+ node scripts/build/components.mjs && node scripts/build/site-a2ui.mjs --stale && npm run harvest:chunks
1006
+ # [data-multi-chips] has no successor attribute — rewrite the selector/check
1007
+ # by hand to [multiple]:not([summary-label]) (CSS) or the equivalent
1008
+ # `el.multiple && !el.summaryLabel` (JS), there is no mechanical 1:1 swap.
1009
+ ```
1010
+
1011
+ ### Verify
1012
+
1013
+ ```bash
1014
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1015
+ rg -nU 'data-(open|closing|queued|dragging|resizing|has-data|multi-chips)\b|dataset\.(open|closing|queued|dragging|resizing|hasData|multiChips)\b' \
1016
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
1017
+ -g '!.claude/docs/**' -g '!**/components/modal/**' -g '!**/components/drawer/**' \
1018
+ -g '!**/components/swiper/**' -g '!*.a2ui.json' -g '!custom-elements.json' \
1019
+ -g '!catalog*.json' # must be 0 hits (exit 1) after migrating real sites
1020
+ # and, scoped to each owning component's consumers (other components keep
1021
+ # their own same-named markers): qr-code data-error / table data-selected /
1022
+ # pagination data-active / tags-input data-empty / input data-number, plus
1023
+ # dataset.{error,selected,active,empty,number} accesses on those elements.
1024
+ npm run check
1025
+ ```
1026
+
1027
+ `data-grid`/`data-resize` are explicitly OUT of this round — both are
1028
+ genuine, documented public APIs (admin-shell's 2/3-column layout helper;
1029
+ admin-sidebar/chat-sidebar/editor-sidebar's drag handle) that ADR-0060
1030
+ names as can't-move-without-a-migration this pass; they carry over to the
1031
+ `0.9.0` ADR-0053/0056 breaking-rename wave, not this ticket.
1032
+
1033
+ <a id="upcoming--image-ui-loaderror-states-declared--converge-to-bare-attributes-090-gh1464"></a>
1034
+ ## Shipped in `0.8.41` — image-ui load/error states declared + converge to bare attributes (gh#1464)
1035
+
1036
+ **BREAKING, no deprecation alias.** The final residue of the
1037
+ [data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332) —
1038
+ deferred out of the residual round above (PR #1463) because, unlike that
1039
+ round's entries, `image-ui`'s load/error attributes were never yaml-declared
1040
+ at all.
1041
+
1042
+ | Component | Old | New |
1043
+ |---|---|---|
1044
+ | `<image-ui>` | `[data-loaded]` | `[loaded]` |
1045
+ | `<image-ui>` | `[data-error]` | `[error]` |
1046
+
1047
+ **Why:** `image.class.js` set `data-loaded`/`data-error` directly via
1048
+ `this.setAttribute`/`removeAttribute` on the host with no `props:`/`states:`
1049
+ declaration — genuine, observable load-lifecycle state (the image's
1050
+ `load`/`error` events, including the gh#999 missed-load-race guard) hidden
1051
+ behind an undeclared private stamp. `image.yaml` now declares both as
1052
+ `states:` entries with bare `attribute:` mappings, matching `qr-code-ui`'s
1053
+ own `error` state (converged to bare `[error]` in the residual round
1054
+ above). `image-ui`'s unrelated `[data-overlay]` skeleton-proximity marker
1055
+ (gh#1362, an implementation-detail stamp on the composed `skeleton-ui`
1056
+ child, not a declared host state) is untouched.
1057
+
1058
+ **`data-msg-*` disposition (same ticket, non-breaking):** the
1059
+ validation-message config family (`data-msg-required`/`pattern`/
1060
+ `minlength`/`maxlength`/`min`/`max`/`bad-input`, read by `core/form.js`'s
1061
+ shared `UIFormElement` mixin across `input`/`select`/`tags-input`/`code`/
1062
+ `date-range-picker`/`datetime-picker`/`payment-method-form`) is **exempt** —
1063
+ it stays `data-*` with no yaml declaration and no attribute change. It is
1064
+ consumer-authored config the component only ever *reads* (never host-
1065
+ reflected state), and the read path is one shared mixin spanning 7+
1066
+ components with no single owning yaml SoT to declare it against. Full
1067
+ rationale: `primitive-authoring/references/yaml-contract.md`'s new
1068
+ `data-msg-*` section (ADR-0060 §Decision 3 routes this exact family here
1069
+ for its converge-or-ratify call). No consumer action needed for this half.
1070
+
1071
+ **Find every affected consumer site:**
1072
+
1073
+ ```bash
1074
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1075
+ # states: entry, not a prop/tag/token change — treat the scan as a first
1076
+ # pass; the rg sweep below is what actually covers it. Word-bounded so a
1077
+ # same-named marker on another component (qr-code-ui's own already-bare
1078
+ # `error`, canvas-ui/agent-reasoning-ui's own `data-error`) doesn't
1079
+ # false-positive — review each hit, only image-ui sites move:
1080
+ rg -nU 'data-(loaded|error)\b' \
1081
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
1082
+ -g '!.claude/docs/**' -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json'
1083
+ rg -nU 'dataset\.(loaded|error)\b' \
1084
+ -g '!**/dist/**' -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json'
1085
+ ```
1086
+
1087
+ **Migrate each verified `image-ui` hit:**
1088
+
1089
+ ```bash
1090
+ rg -l 'data-loaded\b' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' \
1091
+ -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json' \
1092
+ | xargs perl -pi -e 's/\bdata-loaded\b/loaded/g'
1093
+ # data-error: review hits first — qr-code-ui, canvas-ui, agent-reasoning-ui,
1094
+ # construct-canvas and error-shake keep their OWN data-error/data-error-*
1095
+ # markers unchanged; only image-ui sites move:
1096
+ rg -l 'data-error\b' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' \
1097
+ -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json' \
1098
+ -g '!**/components/qr-code/**' -g '!**/components/canvas/**' \
1099
+ -g '!**/components/agent-reasoning/**' -g '!**/traits/error-shake/**' \
1100
+ -g '!**/construct-canvas/**' \
1101
+ | xargs perl -pi -e 's/\bdata-error\b/error/g'
1102
+ node scripts/build/components.mjs && node scripts/build/site-a2ui.mjs --stale && npm run harvest:chunks
1103
+ ```
1104
+
1105
+ ### Verify
1106
+
1107
+ ```bash
1108
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1109
+ rg -nU 'data-(loaded|error)\b' -g '!*CHANGELOG*.md' -g '!**/dist/**' \
1110
+ -g '!*.examples.md' -g '!*MIGRATION*' -g '!.claude/docs/**' \
1111
+ -g '!**/components/qr-code/**' -g '!**/components/canvas/**' \
1112
+ -g '!**/components/agent-reasoning/**' -g '!**/traits/error-shake/**' \
1113
+ -g '!**/construct-canvas/**' -g '!*.a2ui.json' -g '!custom-elements.json' \
1114
+ -g '!catalog*.json' # must be 0 hits on image-ui specifically after migrating real sites
1115
+ npm run check
1116
+ ```
1117
+
1118
+ <a id="upcoming--action-item-ui-converges-onto-menu-item-uis-row-contract-090-gh1374"></a>
1119
+ ## Shipped in `0.8.41` — `action-item-ui` converges onto `menu-item-ui`'s row contract (gh#1374)
1120
+
1121
+ **BREAKING, no deprecation alias, zero known consumer sites.**
1122
+ `<action-item-ui>` (the child of `<action-list-ui>`) gains a `subtitle`
1123
+ prop and `text`/`subtitle`/`trailing` slot overrides, converging its row
1124
+ contract exactly onto `<menu-item-ui>`'s (icon/text/subtitle/value/
1125
+ variant/disabled props; icon/text/subtitle/trailing slot overrides). The
1126
+ `variant` enum (`default`/`danger`) already converged separately in
1127
+ [gh#1417](https://github.com/adiahealth/gen-ui-kit/pull/1417) (#1363 B6)
1128
+ and is unaffected here.
1129
+
1130
+ **Why:** the catalog-regularity audit's C5 finding
1131
+ ([gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363)) flagged
1132
+ `action-item-ui` as `menu-item-ui` minus `subtitle`, with no principled
1133
+ reason for the two row contracts to differ — action-items live inline in
1134
+ content surfaces, menu-items live inside `<menu-ui>` popovers, but the row
1135
+ anatomy itself (leading icon, label, optional secondary line, optional
1136
+ trailing shortcut/badge) is identical. Filed as
1137
+ [gh#1374](https://github.com/adiahealth/gen-ui-kit/issues/1374).
1138
+
1139
+ **Container-level decision (also C5):** whether `<list-ui>` should absorb
1140
+ `<action-list-ui>` as a fire-and-forget `action` mode was decided **NO** —
1141
+ the two are kept as separate components. `<list-ui selectable>` holds a
1142
+ persisted single selection (`selectedKey`/`aria-selected`, roving
1143
+ tabindex); `<action-list-ui>` always fires and never holds selection
1144
+ state — genuinely different interaction contracts, not one mode axis, and
1145
+ no existing implementation of an "action" mode exists on `list-ui` to
1146
+ converge onto (unlike the segmented/toggle-group case, C1, where the mode
1147
+ already existed under a different name). `list.yaml` and `action-list.yaml`
1148
+ each carry an a2ui rule cross-routing to the other so the decision is
1149
+ discoverable at generation time.
1150
+
1151
+ **Migration:**
1152
+
1153
+ | Old | New |
1154
+ |---|---|
1155
+ | `<action-item-ui icon="…" text="…" value="…">` | unchanged |
1156
+ | `<action-item-ui>` with an unnamed (default-slot) trailing child (e.g. a `<kbd>` shortcut hint) | add `slot="trailing"` to that child |
1157
+ | Anything reading `subtitle` | new, additive — no migration |
1158
+
1159
+ A monorepo-wide sweep at dispatch time (`rg -nU` across every
1160
+ `<action-item-ui>...</action-item-ui>` span, source + corpus chunks +
1161
+ examples, dist/generated excluded) found **zero** consumers with slotted
1162
+ children of any kind — every usage in this repo is
1163
+ self-closing/attribute-only. The default-slot retirement is therefore a
1164
+ contract change with no repo-internal migration to perform; it is
1165
+ documented here for any external consumer that had adopted the unnamed
1166
+ slot.
1167
+
1168
+ **Find every affected consumer site:**
1169
+
1170
+ ```bash
1171
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1172
+ rg -nU '<action-item-ui[^>]*>[\s\S]*?</action-item-ui>' \
1173
+ -g '!**/dist/**' -g '!*.a2ui.json' -g '!*MIGRATION*' -g '!.claude/docs/**'
1174
+ ```
1175
+
1176
+ Any non-self-closing `<action-item-ui>` hit with slotted content that
1177
+ isn't `slot="icon"` needs `slot="trailing"` added.
1178
+ <a id="upcoming--global-attribute-shadowing-collision-sweep-090-gh1335"></a>
1179
+ ## Shipped in `0.8.41` — global-attribute-shadowing collision sweep (gh#1335)
1180
+
1181
+ **BREAKING, no deprecation aliases.** gh#1327's build of the ADR-0053/0054
1182
+ `check:attribute-shadowing` gate surfaced 16 pre-existing component-local
1183
+ attributes that shadowed the global attribute grammar with divergent
1184
+ semantics — the same collision class ADR-0053/0054 fixed for
1185
+ `qr-code-ui[margin]`, `table-ui[density]`, and `chart-ui[radius]`, but never
1186
+ itself audited. gh#1335 also surfaced a 17th collision of its own, during
1187
+ this same build's follow-up audit (`dashboard-layout-ui[gap]` — never in the
1188
+ gate's original 16, since its shape wasn't caught by the gate's type-only
1189
+ check for the `gap`/`padding`/`margin` Scale roster). Of the 17 total tracked
1190
+ here, **15 are resolved** (12 renamed/converged — the original 11 plus the
1191
+ 17th — and 3 exempted); **2 remain open** (both from the original 16 — see
1192
+ below).
1193
+
1194
+ ### Renames / conversions (12 — 11 from the original 16 + the 17th collision)
1195
+
1196
+ | Component | Old | New | Notes |
1197
+ |---|---|---|---|
1198
+ | `header-ui` | `[padding]` (boolean) | `[padded]` | same boolean semantics; collided with the global Scale `[padding]`. |
1199
+ | `menu-ui` | `[gap]` (raw px) | `[offset]` | same numeric semantics; matches `popover-ui`'s own rename — both wrap the same `anchorPopover()` helper. |
1200
+ | `popover-ui` | `[gap]` (raw px) | `[offset]` | same numeric semantics; yaml already described it as "pixel offset". |
1201
+ | `skeleton-ui` | `[radius]` (enum) | `[corner-radius]` | same enum (`none/sm/md/lg/full`); mirrors `chart-ui`'s own `[corner-radius]` fix (ADR-0054). |
1202
+ | `image-ui` | `[radius]` (enum) | `[corner-radius]` | same enum (`sm/md/lg/full`); same rename as `skeleton-ui` above. |
1203
+ | `invoice-detail-ui` | `[density]` (`compact`/`standard`) | `[density]` (`compact`/`spacious`/unset) | `standard` retired (never a real forwarded state — the JS already treated it as unset); `spacious` gained for parity with the global grammar. |
1204
+ | `invoice-history-ui` | `[density]` (`compact`/`standard`/`comfortable`) | `[density]` (`compact`/`spacious`/unset) | `standard` retired, `comfortable` → `spacious` (a real behavioral remap, this component's `comfortable` genuinely meant the same as `spacious`). |
1205
+ | `dashboard-layout-ui` | `[density]` includes `comfortable` | `[density]` drops `comfortable` | **not** a `comfortable`→`spacious` remap — verified as dead code: `comfortable` set only `--a-density:1` with no gap-token override, functionally identical to the unset `""` state, not to `spacious` (`--a-density:1.15` + wider gap tokens). Converges onto `""` (the closest matching real behavior). |
1206
+ | `dashboard-layout-ui` | `[gap]` (numeric `1`-`6`) | `[band-gap]` | kept namespaced, not converged onto the global `[gap]` Scale — it sets a component-local token that never composed with the ambient `[size]`→`--a-gap` cascade, and covers a narrower range (1-6 vs. the global 0-16); a genuinely distinct, band-scoped concept. |
1207
+ | `text-ui` | `[weight]` includes `regular` | `[weight]` uses `normal` | spelling convergence onto the global Enum·semantic `[weight]` vocabulary. |
1208
+ | `text-ui` | `[text-align]` (`start`/`center`/`end`/`justify`) | `[text-align]` (`left`/`center`/`right`/`justify`) | converges onto the global physical vocabulary; `justify` is a genuine physical (non-directional) value and is now supported by the global `[text-align]` grammar itself (`packages/web-components/styles/api/text.css`), not just `text-ui`'s own local rule. |
1209
+ | `tags-input-ui` | `[transform]` (`lowercase`/`trim`/`strip-spaces`) | `[normalize]` | value-commit normalization is a different concept from the global CSS `[transform]` (uppercase/lowercase/capitalize/none display styling), not merely a colliding vocabulary. |
1210
+
1211
+ ### New §11 exemptions (3, no code change)
1212
+
1213
+ `button-ui[color]`, `toggle-scheme-ui[color]`, and `text-ui[color]` are
1214
+ newly ratified `.claude/docs/specs/attribute-api-system.md` §11 rows —
1215
+ `[color]` on these three plays the ADR-0044/ADR-0064 FAMILY axis (a
1216
+ different grammar from the generic descriptive `[color]` the rest of the
1217
+ catalog uses), not a foreign value against that generic vocabulary. No
1218
+ markup changes — these were always valid, just undocumented as deliberate.
1219
+
1220
+ ### Left open (2) — since ratified as §11 exemptions (ADR-0070, no code change)
1221
+
1222
+ Both were tracked in the gate's own `KNOWN_FINDINGS`, not fixed by this
1223
+ sweep — self-certifying an exemption with no ADR citation is exactly what
1224
+ §11's own contract forbids. ADR-0070 (gh#1500) has since ratified both as
1225
+ §11 rows, the same way ADR-0044/ADR-0064 closed the `[color]` rows above:
1226
+
1227
+ - **`qr-code-ui[color]`** — a free-form CSS color string, structurally
1228
+ identical to the ratified `swatch-ui`/`noodles-ui[color]` §11 exemption
1229
+ ("the component's entire subject is a color").
1230
+ - **`icon-ui[weight]`** — Phosphor icon-render-style vocabulary
1231
+ (`thin/light/regular/bold/fill/duotone`), a different concept entirely
1232
+ from font-weight — same "different concept" shape as the other ratified
1233
+ exemptions.
1234
+
1235
+ No markup changes — like the three ADR-0044/ADR-0064 exemptions, these were
1236
+ always valid, just undocumented as deliberate.
1237
+
1238
+ ### Migration
1239
+
1240
+ | Old | New |
1241
+ |---|---|
1242
+ | `<header-ui padding>` | `<header-ui padded>` |
1243
+ | `<menu-ui gap="N">` | `<menu-ui offset="N">` |
1244
+ | `<popover-ui gap="N">` | `<popover-ui offset="N">` |
1245
+ | `<skeleton-ui radius="X">` | `<skeleton-ui corner-radius="X">` |
1246
+ | `<image-ui radius="X">` | `<image-ui corner-radius="X">` |
1247
+ | `<invoice-detail-ui density="standard">` | drop the attribute (unset is the default) |
1248
+ | `<invoice-history-ui density="standard">` | drop the attribute |
1249
+ | `<invoice-history-ui density="comfortable">` | `<invoice-history-ui density="spacious">` |
1250
+ | `<dashboard-layout-ui density="comfortable">` | drop the attribute (was already behaviorally equivalent to unset) |
1251
+ | `<dashboard-layout-ui gap="N">` | `<dashboard-layout-ui band-gap="N">` |
1252
+ | `<text-ui weight="regular">` | `<text-ui weight="normal">` |
1253
+ | `<text-ui text-align="start">` | `<text-ui text-align="left">` |
1254
+ | `<text-ui text-align="end">` | `<text-ui text-align="right">` |
1255
+ | `<tags-input-ui transform="…">` | `<tags-input-ui normalize="…">` |
1256
+
1257
+ **Find every affected consumer site with the repo's own scanner — not
1258
+ ad-hoc grep:**
1259
+
1260
+ ```bash
1261
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1262
+ ```
1263
+
1264
+ The scanner's markup-textual matching does not cover JS
1265
+ `setAttribute()`/property-assignment call sites at all, or the
1266
+ enum-value-only renames (`weight="regular"→"normal"`,
1267
+ `text-align="start/end"→"left/right"`, `density="standard"/"comfortable"`) —
1268
+ the latter are value changes on an attribute whose NAME didn't change,
1269
+ outside the scanner's rename-detection shape. Sweep both classes with a
1270
+ tag-scoped `rg -nU`:
1271
+
1272
+ **Enum-value-only renames (markup):**
1273
+
1274
+ ```bash
1275
+ rg -nU '<text-ui[^>]*weight="regular"'
1276
+ rg -nU '<text-ui[^>]*text-align="(start|end)"'
1277
+ rg -nU '<(invoice-detail-ui|invoice-history-ui)[^>]*density="(standard|comfortable)"'
1278
+ rg -nU '<dashboard-layout-ui[^>]*density="comfortable"'
1279
+ ```
1280
+
1281
+ **JS `setAttribute()` / property-assignment call sites (for every renamed
1282
+ attribute — `padding`, `gap`, `radius`, `transform`, plus the enum-only
1283
+ renames above by attribute name):**
1284
+
1285
+ ```bash
1286
+ rg -nU "setAttribute\('(padding|gap|radius|transform)', *['\"]" -g '*.js' -g '*.ts'
1287
+ rg -nU '\.(padding|gap|radius|transform)\s*=' -g '*.js' -g '*.ts'
1288
+ rg -nU "setAttribute\('(weight|text-align|density)', *['\"](regular|start|end|standard|comfortable)['\"]" -g '*.js' -g '*.ts'
1289
+ ```
1290
+
1291
+ The `\.(padding|gap|radius|transform)\s*=` property-assignment pattern is
1292
+ necessarily broad (these are common English words used by unrelated
1293
+ objects/properties too) — review each hit's receiver is actually a
1294
+ `header-ui`/`menu-ui`/`popover-ui`/`skeleton-ui`/`image-ui`/
1295
+ `dashboard-layout-ui`/`tags-input-ui` element before rewriting, the same
1296
+ discipline the `progress-ui` migration entry's own `setAttribute()`
1297
+ sweep above already documents.
1298
+
1299
+ ### Verify
1300
+
1301
+ ```bash
1302
+ node scripts/build/components.mjs --verify # sidecars clean
1303
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1304
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1305
+ node scripts/audit/check-attribute-shadowing.mjs --strict # 0 untracked violations, exactly 2 known findings
1306
+ npm run check
1307
+ ```
1308
+
1309
+ ---
1310
+
1311
+
1312
+ <a id="upcoming--segmented-ui-gains-multiple-toggle-group-uitoggle-option-ui-deprecated-090-gh1369"></a>
1313
+ ## Shipped in `0.8.41` — `segmented-ui` gains `[multiple]`; `toggle-group-ui`/`toggle-option-ui` deprecated (gh#1369)
1314
+
1315
+ **Additive, non-breaking — plus a soft deprecation with no removal.**
1316
+ `<segmented-ui>` gains a `multiple: Boolean` axis (default `false`).
1317
+ `<toggle-group-ui>` and `<toggle-option-ui>` are marked
1318
+ `status: deprecated` and log a one-time `console.warn` on connect; **both
1319
+ keep working exactly as before** — this is a recommended migration, not
1320
+ a forced break.
1321
+
1322
+ **Why:** the catalog-regularity audit's C1 finding —
1323
+ [gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363), its
1324
+ top-ranked candidate. `<toggle-group-ui>` already carried a `single`
1325
+ mode prop that made it behave like segmented (`toggle-group.yaml`);
1326
+ four components played one concept. `toggle-group-ui`/`toggle-option-ui`
1327
+ had **zero** corpus chunk files (segmented/segment: 19 each), so
1328
+ multi-select intents (filter chips, day-of-week pickers) retrieved
1329
+ nothing for toggle-group or mis-retrieved single-select segmented
1330
+ chunks. Merging the multi-select axis into segmented gives multi-select
1331
+ intents the same 19-chunk retrieval mass single-select already has, and
1332
+ removes the Segmented-vs-ToggleGroup decision rule that was taught
1333
+ redundantly across four separate a2ui rules.
1334
+
1335
+ **New API:** under `[multiple]`, `<segmented-ui>`'s `value` becomes a
1336
+ comma-separated set of selected `<segment-ui>` values — the same
1337
+ encoding `<toggle-group-ui>` and `<select-ui multiple>` already use.
1338
+ The sliding indicator (single-select's animated pill) is suppressed;
1339
+ each selected segment carries its own background instead
1340
+ (`--segment-bg-selected`). Keyboard model changes under `[multiple]`
1341
+ only: arrow keys move focus without selecting (a checkbox-toolbar
1342
+ model, `role="group"` / children `role="checkbox"`), Space/Enter
1343
+ toggles the focused segment. Single-select (`[multiple]` absent) is
1344
+ byte-identical to before — radiogroup model, arrow-move selects,
1345
+ sliding indicator.
1346
+
1347
+ **Migration:**
1348
+
1349
+ | Old | New |
1350
+ |---|---|
1351
+ | `<toggle-group-ui value="bold,italic">` + `<toggle-option-ui value="bold" text="Bold" icon="…">` children | `<segmented-ui multiple value="bold,italic">` + `<segment-ui value="bold" text="Bold" icon="…">` children — `value`/`text`/`icon`/`disabled` map directly, same comma-separated `value` encoding |
1352
+ | `<toggle-group-ui single value="…">` (toggle-group's own single-select mode prop) | `<segmented-ui value="…">` (no `[multiple]`) — segmented's native single-select mode, not a mode flag on the multi-select component |
1353
+ | `toggle-option-ui[selected]` CSS | `segment-ui[selected]` under a `segmented-ui[multiple]` ancestor |
1354
+
1355
+ **Behavioral gap: `[single]`'s clear-on-reclick has no segmented-ui
1356
+ equivalent.** `<toggle-group-ui single>` clears its selection (empty
1357
+ `value`) when the already-selected option is activated again
1358
+ (`toggle-group.class.js`'s `#toggle()`: `if (selected.has(optVal))
1359
+ selected.clear()`). `<segmented-ui>` single-select does not — it's
1360
+ standard radiogroup semantics, exactly one segment stays selected once
1361
+ a value is set; clicking the already-selected segment again is a
1362
+ no-op. `allow-empty` does **not** cover this gap either — it only
1363
+ suppresses the connect-time self-select of the first segment when the
1364
+ initial `value` is falsy, it has no effect on later clicks. Most
1365
+ `[single]` consumers don't rely on the clear affordance (it wasn't
1366
+ advertised as the toggle-group contract's headline behavior) — audit
1367
+ before assuming it's needed.
1368
+
1369
+ **If a `[single]` consumer relies on the clear-on-reclick affordance**,
1370
+ the migration has no built-in replacement — wire it yourself, and the
1371
+ listener phase matters. `segmented-ui`'s own click handler runs on the
1372
+ **bubble** phase (registered in `connected()`); a same-phase consumer
1373
+ listener that reads `el.value` to decide "was this a re-click" is
1374
+ **registration-order-fragile**: a bubble listener attached AFTER
1375
+ `connected()` already ran (the realistic case —
1376
+ `document.querySelector('segmented-ui').addEventListener(...)` on an
1377
+ already-mounted page) reads `el.value` **after** segmented-ui's own
1378
+ handler already overwrote it with the just-clicked value, so the check
1379
+ is true on every click, not just re-clicks — it would incorrectly
1380
+ clear a selection of a *different* segment too. Snapshot the
1381
+ pre-click value in a **capture-phase** listener instead — capture
1382
+ always runs before bubble, independent of registration order — then
1383
+ apply the clear in a microtask so it lands after segmented-ui's own
1384
+ bubble handler (and its `change` dispatch) have already committed the
1385
+ reselect:
1386
+
1387
+ ```js
1388
+ el.addEventListener(
1389
+ 'click',
1390
+ (e) => {
1391
+ const seg = e.target.closest('segment-ui');
1392
+ if (!seg) return;
1393
+ const clickedValue = seg.value || seg.getAttribute('value') || '';
1394
+ const wasAlreadySelected = clickedValue === el.value; // pre-click snapshot
1395
+ if (wasAlreadySelected) {
1396
+ queueMicrotask(() => {
1397
+ el.value = '';
1398
+ // segmented-ui already dispatched one `change` for the reselect;
1399
+ // re-dispatch so consumers see the final (cleared) state too.
1400
+ el.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: '' } }));
1401
+ });
1402
+ }
1403
+ },
1404
+ { capture: true },
1405
+ );
1406
+ ```
1407
+
1408
+ **Find every affected consumer site with the repo's own scanner, plus
1409
+ the multiline-capable manual sweep** (established in the `input-ui`
1410
+ `type`-enum rider above, and again for this exact tag-rename shape at
1411
+ gh#1414) — a line-based `git grep` misses multi-line opening tags:
1412
+
1413
+ ```bash
1414
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1415
+ rg -nU '<toggle-group-ui[^>]*>|<toggle-option-ui[^>]*>' \
1416
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
1417
+ -g '!.claude/docs/**'
1418
+ ```
1419
+
1420
+ Both tags keep working — a positive hit is a candidate to migrate on
1421
+ your own schedule, not a broken build. Verify each hit's element is
1422
+ actually a `toggle-group-ui`/`toggle-option-ui` host before rewriting.
1423
+
1424
+ ### Verify
1425
+
1426
+ ```bash
1427
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1428
+ rg -nU '<toggle-group-ui[^>]*>|<toggle-option-ui[^>]*>' \
1429
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
1430
+ -g '!.claude/docs/**' # any hit is a migration candidate, not a failure — both tags still work
1431
+ npm run check
1432
+ ```
1433
+
1434
+ ---
1435
+
1436
+ <a id="upcoming--calendar-picker-ui-absorbs-datetime-picker-ui-behind-a-widened-precision-axis-090-gh1372"></a>
1437
+ ## Shipped in `0.8.41` — `calendar-picker-ui` absorbs `datetime-picker-ui` behind a widened `precision` axis (gh#1372)
1438
+
1439
+ **Mostly additive + soft deprecation; two real breaking removals on `calendar-picker-ui` itself.**
1440
+ `<calendar-picker-ui>` gains a `precision` axis (`date` | `minute` | `second`,
1441
+ default `date` — unchanged behavior for every existing consumer that never
1442
+ set it) plus the props/events it needs when a time pane is on:
1443
+ `step`/`hour-cycle`/`locale` (active only when `precision` isn't `date`),
1444
+ and the `input`/`open`/`close`/`invalid` events (previously only `change`
1445
+ existed). `<datetime-picker-ui>` is now marked `status: deprecated` and
1446
+ implemented as a thin `UICalendarPicker` subclass (`precision="minute"` by
1447
+ default) rather than an independent primitive — it keeps working
1448
+ unchanged. Filed from the catalog-regularity audit's C3c finding,
1449
+ [gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363) (C3d
1450
+ sibling-contract convergence folded into the same build).
1451
+
1452
+ **Why:** `datetime-picker-ui` was structurally `calendar-picker-ui` (a
1453
+ trigger + popover) plus a composed `<time-picker-ui>` pane — same
1454
+ `format`/`placement`/`open` contract, same ISO-string value shape both
1455
+ ways. Two near-identical implementations of the same trigger/popover/
1456
+ anchor/focus-trap machinery is exactly the maintenance-cost shape
1457
+ gh#1363 was auditing for, and `datetime-picker-ui` was still
1458
+ `status: experimental` with zero corpus chunks — "the cheap moment
1459
+ closes at stabilization." `calendar-picker-ui[precision]` also closes two
1460
+ sibling-contract gaps `calendar-picker-ui` had relative to its own
1461
+ siblings (`readonly` with real behavior, not just an inherited-but-unwired
1462
+ property; `name`/`min`/`max` documented `reflect: true`, matching what the
1463
+ class already did).
1464
+
1465
+ **Breaking removals on `calendar-picker-ui`:**
1466
+
1467
+ | Old | New |
1468
+ |---|---|
1469
+ | `<calendar-picker-ui label="…">` | `<field-ui label="…"><calendar-picker-ui></calendar-picker-ui></field-ui>` — matches every sibling picker (`date-range-picker-ui`, `datetime-picker-ui`, `time-picker-ui` never had a first-class `label`; this was `calendar-picker-ui`'s own outlier) |
1470
+ | `slot="label"` child on `<calendar-picker-ui>` | drop it — same rationale; the slot was never wired to any rendering either |
1471
+
1472
+ **Breaking token removals on `datetime-picker-ui`** (it owns no CSS custom
1473
+ properties of its own anymore — everything routes through
1474
+ `calendar-picker-ui`'s `--calendar-picker-*` tokens, which the two tags
1475
+ now share):
1476
+
1477
+ | Old token | New token |
1478
+ |---|---|
1479
+ | `--datetime-picker-popover-bg` | `--calendar-picker-popover-bg` |
1480
+ | `--datetime-picker-popover-border` | `--calendar-picker-popover-border` |
1481
+ | `--datetime-picker-popover-radius` | `--calendar-picker-popover-radius` |
1482
+ | `--datetime-picker-popover-shadow` | `--calendar-picker-popover-shadow` |
1483
+ | `--datetime-picker-popover-padding` | `--calendar-picker-popover-padding` |
1484
+ | `--datetime-picker-popover-gap` | `--calendar-picker-popover-gap` |
1485
+ | `--datetime-picker-divider` | `--calendar-picker-divider` |
1486
+ | `--datetime-picker-duration` | `--calendar-picker-duration` |
1487
+ | `--datetime-picker-easing` | `--calendar-picker-easing` |
1488
+ | `--datetime-picker-bg`, `--datetime-picker-fg` | *removed, no replacement* — the host paints no background of its own; text color inherits |
1489
+ | `--datetime-picker-trigger-min-width`, `--datetime-picker-px`, `--datetime-picker-py` | *removed, no replacement* — the trigger sizes to content; set width/padding via ordinary CSS on the host if a fixed size is wanted |
1490
+
1491
+ **Recommended migration (non-breaking, on your own schedule):**
1492
+ `<datetime-picker-ui name="…">` → `<calendar-picker-ui precision="minute" name="…">`
1493
+ (or `precision="second"` for the former second-precision mode) — every
1494
+ other attribute name is unchanged.
1495
+
1496
+ **Find every affected consumer site with the repo's own scanner:**
1497
+
1498
+ ```bash
1499
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref> \
1500
+ --roots packages,apps,playgrounds,site,site-a2ui
1501
+ ```
1502
+
1503
+ The `--roots` addition is required here — the scanner's own default roots
1504
+ miss `site-a2ui/` (ADR-0063's own consumer-scan note applies equally to
1505
+ this rider). The removed `label` prop/slot has no reported sites in this
1506
+ repo as of the fold landing; the `--datetime-picker-*` token findings are
1507
+ expected to fire on `datetime-picker.examples.html`'s own old→new
1508
+ reference table above (that's documentation explaining the rename, not a
1509
+ live override — disregard that one self-hit). `<datetime-picker-ui>` tag
1510
+ usage itself is a soft-deprecation candidate, not a scanner finding (the
1511
+ tag isn't removed):
1512
+
1513
+ ```bash
1514
+ rg -nU '<datetime-picker-ui\b[^>]*>' \
1515
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
1516
+ -g '!.claude/docs/**' # any hit is a migration candidate, not a failure — the tag still works
1517
+ ```
1518
+
1519
+ ### Verify
1520
+
1521
+ ```bash
1522
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref> --roots packages,apps,playgrounds,site,site-a2ui
1523
+ rg -nU '<calendar-picker-ui\b[^>]*\blabel=' -g '!.claude/docs/**' # must be 0
1524
+ npm run check
1525
+ ```
1526
+
1527
+ ---
1528
+
1529
+ <a id="upcoming--a2ui-catalog-component-collision-adminshell--uichatthread-090-gh1427"></a>
1530
+ ## Shipped in `0.8.41` — A2UI catalog `component:` collision: `AdminShell` / `UIChatThread` (gh#1427)
1531
+
1532
+ **BREAKING for hand-authored or generated A2UI documents only — no DOM/JS API
1533
+ change.** `<admin-shell>` and `<chat-thread-ui>` keep their existing tag
1534
+ names, props, and events unchanged. What changed is the **A2UI catalog's**
1535
+ internal `component:` identifier — the value that appears in a rendered
1536
+ a2ui JSON tree's `"component"` field and the L0 catalog's own top-level key.
1537
+
1538
+ **Why:** `packages/web-modules/shell/admin-shell/admin-shell.yaml` and
1539
+ `packages/web-modules/shell/embed-shell/embed-shell.yaml` both declared
1540
+ `component: AppShell`. `scripts/build/components.mjs` used that field as the
1541
+ catalog's own key with no collision check — alphabetical directory
1542
+ traversal processed `admin-shell` first, so `embed-shell`'s fragment
1543
+ silently overwrote it: the L0 catalog's `components.AppShell` entry held
1544
+ **embed-shell's** (experimental) contract, and `admin-shell` (stable, the
1545
+ more heavily used shell) had **no L0 catalog schema entry at all** — no
1546
+ build error, no warning. Fixed by giving `admin-shell` its own catalog
1547
+ identity, `AdminShell`, matching the existing `registry.js` mapping
1548
+ (`['AdminShell', 'admin-shell']`) that had already anticipated this;
1549
+ `embed-shell` keeps `AppShell` (its own established, intentional mapping).
1550
+ `scripts/build/components.mjs` also gained a build-time collision guard — a
1551
+ duplicate `component:` value across yaml SoTs now throws instead of
1552
+ silently overwriting, which caught a second, independent instance of the
1553
+ identical defect: `packages/web-components/components/chat-thread/
1554
+ chat-thread.yaml` (the primitive, tag `chat-thread-ui`) still declared
1555
+ `component: ChatThread`, colliding with the chat web-module's own
1556
+ `ChatThread` (tag `chat-thread`, `registry.js`'s `['ChatThread',
1557
+ 'chat-thread']` mapping). Renamed the primitive's catalog identity to
1558
+ `UIChatThread` (matching its own `name:` field), added the matching
1559
+ `registry.js` entry.
1560
+
1561
+ **Migration:**
1562
+
1563
+ | Old (a2ui JSON) | New (a2ui JSON) | HTML tag (unchanged) |
1564
+ |---|---|---|
1565
+ | `{"component": "AppShell", ...}` intending the **stable admin shell** | `{"component": "AdminShell", ...}` | `<admin-shell>` |
1566
+ | `{"component": "AppShell", ...}` intending the **experimental embed shell** | unchanged — still `{"component": "AppShell", ...}` | `<embed-shell>` |
1567
+ | `{"component": "ChatThread", ...}` intending the **primitive** scroll container (used OUTSIDE a `<chat-shell>`) | `{"component": "UIChatThread", ...}` | `<chat-thread-ui>` |
1568
+ | `{"component": "ChatThread", ...}` intending the **chat-shell module child** | unchanged — still `{"component": "ChatThread", ...}` | `<chat-thread>` |
1569
+
1570
+ Only a consumer that hand-authors or generates raw A2UI trees referencing
1571
+ these `component` values directly is affected — component authoring via
1572
+ the HTML tags themselves (`<admin-shell>`, `<chat-thread-ui>`) needs no
1573
+ change. Any pre-fix generation that produced `"component": "AppShell"`
1574
+ meaning admin-shell was already silently wrong (it validated against
1575
+ embed-shell's schema instead) — this migration corrects, not breaks, that
1576
+ path.
1577
+
1578
+ ### Verify
1579
+
1580
+ ```bash
1581
+ rg -nU '"component"\s*:\s*"(AppShell|ChatThread)"' \
1582
+ -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' -g '!**/corpus/chunks/**'
1583
+ npm run check
1584
+ ```
1585
+
1586
+ ---
1587
+
1588
+ <a id="upcoming--progress-row-ui-deprecated--absorbed-into-progress-ui-090-gh1373"></a>
1589
+ ## Shipped in `0.8.41` — `progress-row-ui` deprecated — absorbed into `progress-ui` (gh#1373)
1590
+
1591
+ **Non-breaking, deprecation alias.** `<progress-ui>` gains a `label` +
1592
+ `meta` prop pair. A non-empty `label` switches `<progress-ui>` into the
1593
+ same labeled-row layout `<progress-row-ui>` renders — label + bar +
1594
+ optional right-aligned `meta` text — a new Sanctioned Mode Attribute
1595
+ (`.claude/docs/specs/component-token-contract.md`'s Modes table).
1596
+ `<progress-row-ui>` itself is unchanged at the implementation level
1597
+ (still composes `<progress-ui>` internally, exact same runtime
1598
+ behavior) but ships `status: deprecated` (ADR-0057's vocabulary) — the
1599
+ site badges it, and the A2UI catalog no longer teaches or generates it.
1600
+
1601
+ **Why:** filed from the catalog-regularity audit's C4 finding
1602
+ ([gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363)) —
1603
+ `progress-row.yaml:10-15` is a thin label+meta wrapper over
1604
+ `progress-ui`, and the catalog already believed they were one
1605
+ component: `progress.yaml`'s own canonical `dashboard` example put
1606
+ `label` on a `Progress` node — a prop only `ProgressRow` had — meaning
1607
+ generation copying the catalog's own exemplar failed validation before
1608
+ this rider.
1609
+
1610
+ **Migration:**
1611
+
1612
+ | Old | New |
1613
+ |---|---|
1614
+ | `<progress-row-ui label="…" value="…" meta="…">` | `<progress-ui label="…" value="…" meta="…">` — attribute names unchanged, a mechanical tag rename |
1615
+ | `<progress-row-ui label="…">` (no meta) | `<progress-ui label="…">` |
1616
+ | `<progress-row-ui variant="success\|warning\|danger">` | **no successor** — see below |
1617
+ | `<progress-row-ui>` (unmodified) | keeps working; not required to migrate, but no longer the taught/generated shape |
1618
+
1619
+ **`variant` (the row's color-family prop) has no successor on
1620
+ `<progress-ui>`.** Progress's own `variant` prop was already retired
1621
+ bar-only in the C2 rider ([gh#1370](https://github.com/adiahealth/gen-ui-kit/issues/1370))
1622
+ and stays retired — this rider does not reopen it, since none of the
1623
+ repo's own authored consumers used `progress-row-ui[variant]` (a
1624
+ `qa:contract-migration-scan` + `rg` sweep of every real usage site
1625
+ found zero). To recolor the fill in row layout, override the
1626
+ `--progress-fill` token directly — `--progress-fill:
1627
+ var(--a-success-bg)`, `--progress-fill: var(--a-warning-bg)`, or
1628
+ `--progress-fill: var(--a-danger-bg)` — the same token-only convention
1629
+ progress's yaml has documented since before this change ("there is no
1630
+ variant-as-color, use the token").
1631
+
1632
+ **Find every affected consumer site:**
1633
+
1634
+ ```bash
1635
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1636
+ rg -nU '<progress-row-ui[^>]*>' \
1637
+ -g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
1638
+ -g '!.claude/docs/**'
1639
+ ```
1640
+
1641
+ The scanner's diff detection is scoped to a yaml losing a `props`/
1642
+ `tokens` key or its `tag:` field (its own documented v1 scope) — this
1643
+ change is additive on `progress.yaml` and non-breaking on
1644
+ `progress-row.yaml`, so expect it to report no contract break; the
1645
+ `rg` sweep is the one that finds real markup sites to migrate (not
1646
+ required — `progress-row-ui` keeps working — but recommended so new
1647
+ edits to a touched file land on the current shape).
1648
+
1649
+ ### Verify
1650
+
1651
+ ```bash
1652
+ npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
1653
+ npm run harvest:chunks # re-validates every chunk against the updated catalog
1654
+ npm run check
1655
+ ```
1656
+
1657
+ ---
1658
+
1659
+ ## Upcoming — ADR-0063 attribute-grammar addendum (chart no-*, chart-legend[interactive], pane[edge], color-area-ui, menu-item[description], 0.9.0, gh#1377/gh#1563)
1660
+
1661
+ **Shipped additively in `0.8.42`; BREAKING removal deferred to the `0.9.0`
1662
+ cut** — per the same 2026-08-14 standing ruling gh#1560's `data-grid`/
1663
+ `data-resize` rename wave follows: a breaking rename never ships in a
1664
+ patch. [ADR-0063](../../docs/ops/adr/adr-0063-attribute-grammar-addendum.md)
1665
+ ratified six decisions from the catalog-regularity audit
1666
+ ([gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363)); this
1667
+ entry covers the five identifiers gh#1563's own build scope named. (The
1668
+ sixth — `agent-reasoning-ui[status]`'s `done`→`completed` stage-terminal
1669
+ convergence — and the `alert`/`card`/`drilldown`/`noodles` decision-2
1670
+ items ship under their own separately-scoped follow-up tickets, not
1671
+ this one.)
1672
+
1673
+ ### What changed (additive, 0.8.42)
1674
+
1675
+ | Component | Old (deprecated, still works) | New (canonical) | Shape |
1676
+ |---|---|---|---|
1677
+ | `<chart-ui>` | `[hide-average]` | `[no-average]` | straight rename, same polarity |
1678
+ | `<chart-ui>` | `[hide-grid]` | `[no-grid]` | straight rename, same polarity |
1679
+ | `<chart-ui>` | `[hide-values]` | `[no-values]` | straight rename, same polarity |
1680
+ | `<chart-legend-ui>` | `[static]` (opt-out) | `[interactive]` (opt-in) | polarity flip — **default NOT yet flipped**, see below |
1681
+ | `<pane-ui>` | `[side]` | `[edge]` | straight rename, same type/default/enum (`drawer-ui[side]` is untouched — different component, different vocabulary) |
1682
+ | `<menu-item-ui>` | `[subtitle]` prop | `[description]` prop | straight rename — the `subtitle` **slot** is a separate surface, deliberately left unrenamed |
1683
+ | `<color-picker-ui>` (tag) | `color-picker-ui` / `ColorPicker` / `UIColorPicker` | `color-area-ui` / `ColorArea` / `UIColorArea` | tag/component/class rename (B11, picker-naming convention) — old tag is now a thin `UIColorArea` subclass, `status: deprecated` |
1684
+
1685
+ Every renamed attribute dual-reads: **new name wins** when both are
1686
+ present (no warning — this is intentional forward-compatible spelling,
1687
+ not a fallback); the **old name resolves** with a one-time
1688
+ `console.warn` per class when it's the only one set; neither present
1689
+ keeps today's default. `<color-picker-ui>` keeps rendering/behaving
1690
+ identically — it inherits every prop, event, and token from
1691
+ `<color-area-ui>` verbatim (mirrors the `<datetime-picker-ui>` →
1692
+ `<calendar-picker-ui>` alias shape from
1693
+ [gh#1372](https://github.com/adiahealth/gen-ui-kit/issues/1372)).
1694
+ `<color-input-ui>`'s own `composes:` list and internal substrate
1695
+ references move to `<color-area-ui>`; `<color-input-ui>`'s own tag/name
1696
+ is unaffected (it was already correctly *not* named `-picker` despite
1697
+ playing the outer trigger+popover composite role).
1698
+
1699
+ **`chart-legend-ui[interactive]`'s default is deliberately NOT flipped
1700
+ in this release.** `[interactive]` defaults `true` — a `<chart-legend-ui>`
1701
+ naming neither `[static]` nor `[interactive]` renders exactly as it
1702
+ does today (interactive `<button>`-role rows). The ADR's own
1703
+ "default-inversion" consumer-scan requirement — every `<chart-legend-ui>`
1704
+ tag, with or without either attribute, reviewed for whether omission
1705
+ was relying on the old default — is the 0.9.0 cut's own prerequisite,
1706
+ not this one's.
1707
+
1708
+ ### Migration (mechanical, recommended now / required at the 0.9.0 cut)
1709
+
1710
+ ```bash
1711
+ git grep -l 'hide-average\|hide-grid\|hide-values' -- packages apps playgrounds site site-a2ui \
1712
+ | xargs perl -pi -e 's/\bhide-average\b/no-average/g; s/\bhide-grid\b/no-grid/g; s/\bhide-values\b/no-values/g'
1713
+
1714
+ git grep -l '<pane-ui\b' -- packages apps playgrounds site site-a2ui \
1715
+ | xargs perl -pi -e 's/(<pane-ui\b[^>]*\b)side=/\1edge=/g'
1716
+
1717
+ git grep -l '<menu-item-ui\b' -- packages apps playgrounds site site-a2ui \
1718
+ | xargs perl -pi -e 's/(<menu-item-ui\b[^>]*\b)subtitle=/\1description=/g'
1719
+
1720
+ git grep -rl 'color-picker-ui\|UIColorPicker' -- packages apps playgrounds site site-a2ui \
1721
+ | xargs perl -pi -e 's/color-picker-ui/color-area-ui/g; s/UIColorPicker/UIColorArea/g'
1722
+ ```
1723
+
1724
+ Every `<chart-legend-ui>` tag additionally needs a manual (not
1725
+ mechanical) review pass: add `[interactive]` explicitly wherever the
1726
+ page relied on the current "interactive by default" behavior, ahead of
1727
+ the 0.9.0 default-inversion.
1728
+
1729
+ **Find every affected consumer site:**
1730
+
1731
+ ```bash
1732
+ npm run qa:contract-migration-scan -- --roots packages,apps,playgrounds,site,site-a2ui \
1733
+ --base <pre-upgrade-ref> --head <post-upgrade-ref>
1734
+ rg -nU 'hide-average|hide-grid|hide-values|<pane-ui\b[^>]*\bside=|<menu-item-ui\b[^>]*\bsubtitle=|color-picker-ui|UIColorPicker' \
1735
+ -g '!**/dist/**' -g '!**/*.a2ui.json' -g '!docs/adr/**'
1736
+ ```
1737
+
1738
+ `--roots packages,apps,playgrounds,site,site-a2ui` is required (not the
1739
+ scanner's own default) — `site-a2ui/` is a separate top-level directory
1740
+ the default roots miss entirely (ADR-0063's own consumer-scan
1741
+ mechanism section explains why).
1742
+
1743
+ ### Rejected / deferred (explicitly out of gh#1563's scope)
1744
+
1745
+ - `action-item-ui[subtitle]` — once `menu-item-ui` converges onto
1746
+ `description`, `action-item-ui` becomes the corpus's new sole
1747
+ `subtitle` outlier (the same shape of defect ADR-0063 just fixed for
1748
+ menu-item). Flagged as a discovered follow-up candidate for a human
1749
+ ticketing decision — not fixed in this dispatch.
1750
+ - `segmented-ui[multiple]`'s comma-separated value encoding — sanctioned
1751
+ as-is (operator ruling, gh#1563, 2026-08-17).
1752
+ - `toggle-group-ui[value]`'s comma-string violation — tracked by
1753
+ gh#1363's own `toggle-group`/`segmented` consolidation candidate, not
1754
+ duplicated here.
1755
+ - `drilldown-ui[static]` → `[no-slide-transition]`, `alert-ui[dismissible]`
1756
+ retirement, `card-ui[outline]` retirement,
1757
+ `agent-reasoning-ui[status="done"]` → `"completed"`, and
1758
+ `noodles-ui[port-size]`/`[show-ports]` duplicate-entry cleanup — all
1759
+ real ADR-0063 decisions, each its own separately-scoped follow-up
1760
+ build, not part of gh#1563's five-item scope.
1761
+ - `menu-item-ui`'s `subtitle` **slot** (distinct from the prop) — left
1762
+ unrenamed by design; renaming a slot is a different, unscoped surface.
1763
+
1764
+ ### Verify
1765
+
1766
+ ```bash
1767
+ npm run qa:contract-migration-scan -- --roots packages,apps,playgrounds,site,site-a2ui \
1768
+ --base <pre-upgrade-ref> --head <post-upgrade-ref>
1769
+ node scripts/build/components.mjs --verify
1770
+ npm run check
1771
+ ```
1772
+
1773
+ ---
1774
+
1775
+ ## Upcoming — `action-item-ui[description]` ADR-0063 convergence (0.9.0, gh#1571)
1776
+
1777
+ **Shipped additively; BREAKING removal deferred to the `0.9.0` cut** — per
1778
+ the same 2026-08-14 standing ruling gh#1560's `data-grid`/`data-resize`
1779
+ rename wave and gh#1563's ADR-0063 addendum both follow: a breaking rename
1780
+ never ships in a patch. This closes the gap [PR
1781
+ #1569](https://github.com/adiahealth/gen-ui-kit/pull/1569) itself flagged
1782
+ under its own "Rejected/deferred" section: once `<menu-item-ui>` converged
1783
+ its `subtitle` prop onto `description` ([ADR-0063](../../docs/ops/adr/adr-0063-attribute-grammar-addendum.md),
1784
+ gh#1563), `<action-item-ui>` became the corpus's remaining sole `subtitle`
1785
+ outlier — the same shape of defect ADR-0063 fixed for menu-item.
1786
+
1787
+ ### What changed (additive)
1788
+
1789
+ | Component | Old (deprecated, still works) | New (canonical) | Shape |
1790
+ |---|---|---|---|
1791
+ | `<action-item-ui>` | `[subtitle]` prop | `[description]` prop | straight rename — the `subtitle` **slot** is a separate surface, deliberately left unrenamed |
1792
+
1793
+ `[description]` wins outright when present (no warning — this is
1794
+ intentional forward-compatible spelling, not a fallback); `[subtitle]`
1795
+ resolves with a one-time `console.warn` per class when it's the only one
1796
+ set; neither present keeps today's default (empty string, no rendered
1797
+ subtitle row). Unlike `menu-item-ui`'s own gh#1563 shim (which only
1798
+ resolves once, at `connected()`), `action-item-ui`'s shim re-resolves on
1799
+ every render until `[description]` is authored directly, so a post-mount
1800
+ `[subtitle]` attribute update keeps propagating exactly as it did before
1801
+ this shim existed — once `[description]` is set directly (by attribute or
1802
+ property), it wins permanently and further `[subtitle]` churn is ignored.
1803
+
1804
+ ### Migration (mechanical, recommended now / required at the 0.9.0 cut)
1805
+
1806
+ ```bash
1807
+ git grep -l '<action-item-ui\b' -- packages apps playgrounds site site-a2ui \
1808
+ | xargs perl -pi -e 's/(<action-item-ui\b[^>]*\b)subtitle=/\1description=/g'
1809
+ ```
1810
+
1811
+ **Find every affected consumer site:**
1812
+
1813
+ ```bash
1814
+ npm run qa:contract-migration-scan -- --roots packages,apps,playgrounds,site,site-a2ui \
1815
+ --base <pre-upgrade-ref> --head <post-upgrade-ref>
1816
+ rg -nU '<action-item-ui\b[^>]*\bsubtitle=' \
1817
+ -g '!**/dist/**' -g '!**/*.a2ui.json' -g '!docs/adr/**'
1818
+ ```
1819
+
1820
+ ### Rejected / deferred
1821
+
1822
+ - The 0.9.0 breaking removal itself — deferred under the same "no breaking
1823
+ rename in a patch" 2026-08-14 standing ruling every sibling rename-wave
1824
+ entry in this guide follows.
1825
+ - `action-item-ui`'s `subtitle` **slot** (distinct from the prop) — left
1826
+ unrenamed by design, same as `menu-item-ui`'s own gh#1563 shape;
1827
+ renaming a slot is a different, unscoped surface.
1828
+
1829
+ ### Verify
1830
+
1831
+ ```bash
1832
+ npm run qa:contract-migration-scan -- --roots packages,apps,playgrounds,site,site-a2ui \
1833
+ --base <pre-upgrade-ref> --head <post-upgrade-ref>
1834
+ node scripts/build/components.mjs --verify
1835
+ npm run check
1836
+ ```
1837
+
1838
+ ---
1839
+
627
1840
  ## Migrating to `@adia-ai/*@v0.8.23` (2026-07-30)
628
1841
 
629
1842
  - **Removed: the `--a-font` alias** (pre-ADR-0035 name, DEPRECATED since the 0.8.x line). Any surviving `font-family: var(--a-font)` goes invalid-at-computed-value-time → `inherit` → UA **serif** — the visible symptom is Times-faced labels on an otherwise-correct page.