@adia-ai/web-components 0.8.40 → 0.8.41

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 (378) hide show
  1. package/CHANGELOG.md +50 -3
  2. package/MIGRATION.md +1042 -16
  3. package/README.md +25 -30
  4. package/USAGE.md +26 -0
  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 +24 -2
  11. package/components/action-list/action-item.yaml +28 -3
  12. package/components/action-list/action-list.a2ui.json +6 -1
  13. package/components/action-list/action-list.class.js +52 -11
  14. package/components/action-list/action-list.css +43 -3
  15. package/components/action-list/action-list.d.ts +4 -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 +9 -4
  63. package/components/chart/chart.class.js +6 -6
  64. package/components/chart/chart.css +6 -4
  65. package/components/chart/chart.d.ts +1 -1
  66. package/components/chart/chart.yaml +5 -3
  67. package/components/chart-legend/chart-legend.a2ui.json +1 -0
  68. package/components/chat-thread/chat-input.a2ui.json +1 -0
  69. package/components/chat-thread/chat-thread.a2ui.json +10 -9
  70. package/components/chat-thread/chat-thread.yaml +13 -20
  71. package/components/check/check.a2ui.json +10 -9
  72. package/components/check/check.yaml +4 -4
  73. package/components/code/code.a2ui.json +1 -0
  74. package/components/col/col.a2ui.json +1 -0
  75. package/components/color-input/color-input.a2ui.json +1 -0
  76. package/components/color-picker/color-picker.a2ui.json +1 -0
  77. package/components/combobox/combobox.a2ui.json +3 -2
  78. package/components/combobox/combobox.yaml +2 -2
  79. package/components/command/command.a2ui.json +12 -10
  80. package/components/command/command.class.js +3 -2
  81. package/components/command/command.yaml +17 -4
  82. package/components/context-menu/context-menu.a2ui.json +1 -0
  83. package/components/date-range-picker/date-range-picker.a2ui.json +2 -1
  84. package/components/date-range-picker/date-range-picker.yaml +1 -1
  85. package/components/datetime-picker/datetime-picker.a2ui.json +15 -108
  86. package/components/datetime-picker/datetime-picker.class.js +37 -690
  87. package/components/datetime-picker/datetime-picker.css +11 -183
  88. package/components/datetime-picker/datetime-picker.d.ts +4 -5
  89. package/components/datetime-picker/datetime-picker.yaml +44 -135
  90. package/components/demo-toggle/demo-toggle.a2ui.json +1 -0
  91. package/components/demo-toggle/demo-toggle.css +1 -1
  92. package/components/description-list/description-list.a2ui.json +1 -0
  93. package/components/display-field/display-field.a2ui.json +1 -0
  94. package/components/divider/divider.a2ui.json +1 -0
  95. package/components/drawer/drawer.a2ui.json +1 -3
  96. package/components/drawer/drawer.css +1 -1
  97. package/components/drawer/drawer.yaml +0 -2
  98. package/components/drilldown/drilldown.a2ui.json +22 -20
  99. package/components/drilldown/drilldown.class.js +4 -3
  100. package/components/drilldown/drilldown.css +6 -6
  101. package/components/drilldown/drilldown.yaml +40 -9
  102. package/components/embed/embed.a2ui.json +6 -5
  103. package/components/embed/embed.yaml +2 -2
  104. package/components/empty-state/empty-state.a2ui.json +1 -0
  105. package/components/feed/feed-item.a2ui.json +25 -5
  106. package/components/feed/feed-item.yaml +28 -7
  107. package/components/feed/feed.a2ui.json +9 -2
  108. package/components/feed/feed.class.js +19 -12
  109. package/components/feed/feed.css +8 -8
  110. package/components/feed/feed.yaml +14 -1
  111. package/components/field/field.a2ui.json +1 -0
  112. package/components/field/field.examples.md +1 -1
  113. package/components/fields/fields.a2ui.json +1 -0
  114. package/components/fields/fields.examples.md +1 -1
  115. package/components/footer/footer.a2ui.json +1 -0
  116. package/components/frame/frame.a2ui.json +1 -0
  117. package/components/grid/grid.a2ui.json +1 -0
  118. package/components/header/header.a2ui.json +3 -2
  119. package/components/header/header.yaml +3 -3
  120. package/components/heatmap/heatmap.a2ui.json +2 -1
  121. package/components/heatmap/heatmap.class.js +1 -1
  122. package/components/heatmap/heatmap.css +4 -4
  123. package/components/heatmap/heatmap.yaml +1 -1
  124. package/components/icon/icon.a2ui.json +1 -0
  125. package/components/image/image.a2ui.json +28 -14
  126. package/components/image/image.class.js +38 -23
  127. package/components/image/image.css +18 -8
  128. package/components/image/image.d.ts +2 -2
  129. package/components/image/image.examples.md +3 -3
  130. package/components/image/image.yaml +23 -7
  131. package/components/inline-edit/inline-edit.a2ui.json +1 -0
  132. package/components/inline-message/inline-message.a2ui.json +3 -1
  133. package/components/inline-message/inline-message.class.js +3 -1
  134. package/components/inline-message/inline-message.d.ts +2 -2
  135. package/components/inline-message/inline-message.yaml +2 -1
  136. package/components/input/input.a2ui.json +66 -16
  137. package/components/input/input.class.js +64 -7
  138. package/components/input/input.css +14 -14
  139. package/components/input/input.d.ts +9 -4
  140. package/components/input/input.yaml +83 -10
  141. package/components/inspector/inspector.a2ui.json +1 -0
  142. package/components/integration-card/integration-card.a2ui.json +1 -0
  143. package/components/kbd/kbd.a2ui.json +1 -0
  144. package/components/link/link.a2ui.json +2 -1
  145. package/components/link/link.yaml +1 -1
  146. package/components/list/list-item.a2ui.json +9 -0
  147. package/components/list/list-item.yaml +12 -0
  148. package/components/list/list.a2ui.json +9 -3
  149. package/components/list/list.class.js +14 -1
  150. package/components/list/list.css +12 -1
  151. package/components/list/list.d.ts +7 -5
  152. package/components/list/list.yaml +16 -6
  153. package/components/list-window/list-window.a2ui.json +1 -0
  154. package/components/list-window/list-window.class.js +2 -1
  155. package/components/loading-overlay/loading-overlay.a2ui.json +1 -0
  156. package/components/mark/mark.a2ui.json +2 -1
  157. package/components/mark/mark.yaml +1 -1
  158. package/components/menu/menu-divider.a2ui.json +1 -0
  159. package/components/menu/menu-item.a2ui.json +3 -1
  160. package/components/menu/menu-item.yaml +6 -0
  161. package/components/menu/menu-label.a2ui.json +1 -0
  162. package/components/menu/menu.a2ui.json +3 -2
  163. package/components/menu/menu.class.js +2 -2
  164. package/components/menu/menu.d.ts +2 -2
  165. package/components/menu/menu.yaml +3 -3
  166. package/components/modal/modal.a2ui.json +1 -0
  167. package/components/nav/nav.a2ui.json +1 -0
  168. package/components/nav/nav.class.js +14 -3
  169. package/components/nav-group/nav-group.a2ui.json +1 -0
  170. package/components/nav-group/nav-group.class.js +3 -1
  171. package/components/nav-item/nav-item.a2ui.json +1 -0
  172. package/components/noodles/noodles.a2ui.json +1 -0
  173. package/components/noodles/noodles.class.js +5 -1
  174. package/components/number-format/number-format.a2ui.json +1 -0
  175. package/components/option-card/option-card.a2ui.json +1 -0
  176. package/components/otp-input/otp-input.a2ui.json +3 -2
  177. package/components/otp-input/otp-input.yaml +9 -2
  178. package/components/page/page.a2ui.json +13 -0
  179. package/components/page/page.d.ts +1 -1
  180. package/components/page/page.yaml +1 -0
  181. package/components/pagination/pagination.a2ui.json +1 -0
  182. package/components/pagination/pagination.class.js +3 -2
  183. package/components/pane/pane.a2ui.json +6 -0
  184. package/components/pane/pane.class.js +3 -3
  185. package/components/pane/pane.css +2 -2
  186. package/components/pane/pane.yaml +3 -0
  187. package/components/password-strength/password-strength.a2ui.json +1 -0
  188. package/components/pipeline-status/pipeline-status.a2ui.json +1 -0
  189. package/components/popover/popover.a2ui.json +7 -6
  190. package/components/popover/popover.class.js +2 -2
  191. package/components/popover/popover.d.ts +2 -2
  192. package/components/popover/popover.yaml +4 -4
  193. package/components/preview/preview.a2ui.json +1 -0
  194. package/components/preview/preview.class.js +5 -1
  195. package/components/progress/progress.a2ui.json +47 -24
  196. package/components/progress/progress.class.js +66 -11
  197. package/components/progress/progress.css +44 -26
  198. package/components/progress/progress.d.ts +7 -5
  199. package/components/progress/progress.examples.md +2 -2
  200. package/components/progress/progress.yaml +235 -53
  201. package/components/progress-row/progress-row.a2ui.json +16 -12
  202. package/components/progress-row/progress-row.d.ts +2 -2
  203. package/components/progress-row/progress-row.examples.md +2 -14
  204. package/components/progress-row/progress-row.yaml +28 -36
  205. package/components/qr-code/qr-code.a2ui.json +3 -2
  206. package/components/qr-code/qr-code.class.js +4 -4
  207. package/components/qr-code/qr-code.css +1 -1
  208. package/components/qr-code/qr-code.yaml +5 -3
  209. package/components/radio/radio.a2ui.json +8 -7
  210. package/components/radio/radio.class.js +8 -0
  211. package/components/radio/radio.yaml +3 -3
  212. package/components/radio-group/radio-group.a2ui.json +5 -3
  213. package/components/radio-group/radio-group.class.js +11 -0
  214. package/components/radio-group/radio-group.yaml +7 -1
  215. package/components/range/range.a2ui.json +6 -0
  216. package/components/range/range.class.js +2 -2
  217. package/components/range/range.css +2 -2
  218. package/components/range/range.yaml +3 -0
  219. package/components/rating/rating.a2ui.json +1 -0
  220. package/components/relative-time/relative-time.a2ui.json +1 -0
  221. package/components/richtext/richtext.a2ui.json +2 -1
  222. package/components/richtext/richtext.yaml +1 -1
  223. package/components/row/row.a2ui.json +1 -0
  224. package/components/search/search.a2ui.json +1 -0
  225. package/components/search/search.class.js +4 -1
  226. package/components/section/section.a2ui.json +1 -0
  227. package/components/segment/segment.a2ui.json +21 -10
  228. package/components/segment/segment.css +15 -0
  229. package/components/segment/segment.d.ts +2 -1
  230. package/components/segment/segment.yaml +20 -13
  231. package/components/segmented/segmented.a2ui.json +36 -7
  232. package/components/segmented/segmented.class.js +113 -22
  233. package/components/segmented/segmented.css +3 -0
  234. package/components/segmented/segmented.d.ts +3 -1
  235. package/components/segmented/segmented.yaml +80 -8
  236. package/components/select/select.a2ui.json +18 -13
  237. package/components/select/select.class.js +61 -37
  238. package/components/select/select.css +15 -13
  239. package/components/select/select.yaml +18 -7
  240. package/components/skeleton/skeleton.a2ui.json +8 -7
  241. package/components/skeleton/skeleton.class.js +8 -7
  242. package/components/skeleton/skeleton.css +21 -6
  243. package/components/skeleton/skeleton.d.ts +2 -2
  244. package/components/skeleton/skeleton.examples.md +2 -2
  245. package/components/skeleton/skeleton.yaml +3 -2
  246. package/components/skip-nav/skip-nav.a2ui.json +1 -0
  247. package/components/slider/slider.a2ui.json +6 -0
  248. package/components/slider/slider.class.js +20 -3
  249. package/components/slider/slider.css +2 -2
  250. package/components/slider/slider.yaml +3 -0
  251. package/components/spinner/spinner.a2ui.json +1 -0
  252. package/components/stack/stack.a2ui.json +1 -0
  253. package/components/stat/stat.a2ui.json +1 -0
  254. package/components/stat/stat.js +2 -2
  255. package/components/step-progress/step-progress.a2ui.json +1 -0
  256. package/components/step-progress/step-progress.yaml +1 -1
  257. package/components/stepper/stepper-item.a2ui.json +7 -3
  258. package/components/stepper/stepper-item.yaml +15 -5
  259. package/components/stepper/stepper.a2ui.json +5 -1
  260. package/components/stepper/stepper.class.js +31 -16
  261. package/components/stepper/stepper.d.ts +1 -1
  262. package/components/stepper/stepper.yaml +4 -2
  263. package/components/stream/stream.a2ui.json +1 -0
  264. package/components/swatch/swatch.a2ui.json +1 -0
  265. package/components/swiper/swiper.a2ui.json +1 -0
  266. package/components/swiper/swiper.class.js +5 -1
  267. package/components/switch/switch.a2ui.json +12 -11
  268. package/components/switch/switch.css +1 -1
  269. package/components/switch/switch.yaml +6 -6
  270. package/components/table/table.a2ui.json +1 -0
  271. package/components/table/table.class.js +14 -12
  272. package/components/table/table.css +11 -9
  273. package/components/table-toolbar/table-toolbar.a2ui.json +1 -0
  274. package/components/table-toolbar/table-toolbar.class.js +38 -19
  275. package/components/table-toolbar/table-toolbar.css +1 -1
  276. package/components/tabs/tab.a2ui.json +9 -0
  277. package/components/tabs/tab.js +4 -0
  278. package/components/tabs/tab.yaml +15 -0
  279. package/components/tabs/tabs.a2ui.json +9 -4
  280. package/components/tabs/tabs.class.js +13 -1
  281. package/components/tabs/tabs.css +8 -0
  282. package/components/tabs/tabs.d.ts +2 -0
  283. package/components/tabs/tabs.yaml +9 -2
  284. package/components/tag/tag.a2ui.json +1 -0
  285. package/components/tags-input/tags-input.a2ui.json +22 -17
  286. package/components/tags-input/tags-input.class.js +13 -11
  287. package/components/tags-input/tags-input.css +10 -6
  288. package/components/tags-input/tags-input.d.ts +16 -7
  289. package/components/tags-input/tags-input.examples.md +2 -2
  290. package/components/tags-input/tags-input.yaml +25 -8
  291. package/components/text/text.a2ui.json +6 -5
  292. package/components/text/text.css +10 -5
  293. package/components/text/text.d.ts +2 -2
  294. package/components/text/text.yaml +9 -4
  295. package/components/textarea/textarea.a2ui.json +2 -1
  296. package/components/textarea/textarea.yaml +1 -1
  297. package/components/theme-provider/theme-provider.a2ui.json +2 -1
  298. package/components/theme-provider/theme-provider.d.ts +5 -3
  299. package/components/theme-provider/theme-provider.yaml +5 -3
  300. package/components/time-picker/time-picker.a2ui.json +1 -0
  301. package/components/time-picker/time-picker.class.js +4 -2
  302. package/components/timeline/timeline-item.a2ui.json +26 -3
  303. package/components/timeline/timeline-item.yaml +22 -7
  304. package/components/timeline/timeline.a2ui.json +4 -0
  305. package/components/timeline/timeline.class.js +29 -18
  306. package/components/timeline/timeline.d.ts +3 -3
  307. package/components/timeline/timeline.yaml +2 -0
  308. package/components/toast/toast.a2ui.json +10 -3
  309. package/components/toast/toast.yaml +20 -13
  310. package/components/toc/toc.a2ui.json +1 -0
  311. package/components/toggle-group/toggle-group.a2ui.json +7 -3
  312. package/components/toggle-group/toggle-group.class.js +40 -1
  313. package/components/toggle-group/toggle-group.css +6 -1
  314. package/components/toggle-group/toggle-group.d.ts +2 -2
  315. package/components/toggle-group/toggle-group.yaml +21 -12
  316. package/components/toggle-group/toggle-option.a2ui.json +7 -3
  317. package/components/toggle-group/toggle-option.yaml +13 -7
  318. package/components/toggle-scheme/toggle-scheme.a2ui.json +2 -1
  319. package/components/toggle-scheme/toggle-scheme.yaml +1 -1
  320. package/components/toolbar/toolbar-group.a2ui.json +1 -0
  321. package/components/toolbar/toolbar.a2ui.json +1 -0
  322. package/components/toolbar/toolbar.class.js +3 -0
  323. package/components/tooltip/tooltip.a2ui.json +1 -0
  324. package/components/tour/tour-step.a2ui.json +4 -0
  325. package/components/tour/tour-step.yaml +2 -0
  326. package/components/tour/tour.a2ui.json +4 -0
  327. package/components/tour/tour.yaml +2 -0
  328. package/components/tree/tree-item.a2ui.json +5 -0
  329. package/components/tree/tree-item.yaml +3 -0
  330. package/components/tree/tree.a2ui.json +4 -0
  331. package/components/tree/tree.class.js +2 -1
  332. package/components/tree/tree.yaml +2 -0
  333. package/components/upload/upload.a2ui.json +8 -1
  334. package/components/upload/upload.class.js +35 -5
  335. package/components/upload/upload.css +28 -0
  336. package/components/upload/upload.d.ts +16 -0
  337. package/components/upload/upload.yaml +27 -7
  338. package/components/visually-hidden/visually-hidden.a2ui.json +1 -0
  339. package/core/dom.d.ts +11 -0
  340. package/core/dom.js +34 -0
  341. package/core/form.js +7 -0
  342. package/core/index.d.ts +1 -0
  343. package/core/index.js +1 -0
  344. package/core/responsive.js +16 -4
  345. package/core/template.js +2 -1
  346. package/custom-elements.json +437 -489
  347. package/dist/host.min.css +1 -1
  348. package/dist/host.sheet.js +1 -1
  349. package/dist/theme-provider.min.js +5 -5
  350. package/dist/web-components.min.css +1 -1
  351. package/dist/web-components.min.js +91 -104
  352. package/dist/web-components.sheet.js +1 -1
  353. package/package.json +4 -2
  354. package/patterns/conversion-funnel/conversion-funnel.examples.html +15 -15
  355. package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
  356. package/patterns/inline-dialog/inline-dialog.html +4 -0
  357. package/patterns/timezone-selector/timezone-selector.examples.html +1 -1
  358. package/patterns/timezone-selector/timezone-selector.html +2 -2
  359. package/styles/api/text.css +7 -0
  360. package/traits/_catalog.json +129 -41
  361. package/traits/anchor-positioning/anchor-positioning.js +1 -0
  362. package/traits/announcer/announcer.js +1 -0
  363. package/traits/arrow-grid-nav/arrow-grid-nav.js +1 -0
  364. package/traits/attention-pulse/attention-pulse.js +1 -0
  365. package/traits/count-up/count-up.js +1 -0
  366. package/traits/define.js +78 -0
  367. package/traits/focus-restore/focus-restore.js +2 -1
  368. package/traits/haptic-feedback/haptic-feedback.js +1 -0
  369. package/traits/input-mask/input-mask.js +1 -0
  370. package/traits/intersection-observer/intersection-observer.js +1 -0
  371. package/traits/layout-animation/layout-animation.js +1 -0
  372. package/traits/noise-texture/noise-texture.js +1 -0
  373. package/traits/resize-observer/resize-observer.js +1 -0
  374. package/traits/scroll-progress/scroll-progress.js +1 -0
  375. package/traits/snap-to-grid/snap-to-grid.js +1 -0
  376. package/traits/sound-feedback/sound-feedback.js +1 -0
  377. package/traits/spring-animate/spring-animate.js +1 -0
  378. package/traits/validation/validation.js +1 -0
@@ -75,7 +75,7 @@
75
75
  "wrong": "<field-ui inline label=\"Email notifications\">\n <switch-ui></switch-ui>\n</field-ui>\n"
76
76
  }
77
77
  ],
78
- "category": "layout",
78
+ "category": "input",
79
79
  "composes": [],
80
80
  "events": {
81
81
  "change": {
@@ -93,25 +93,26 @@
93
93
  "switch"
94
94
  ],
95
95
  "name": "UISwitch",
96
- "related": [
97
- "Check",
98
- "Radio",
99
- "Field"
100
- ],
101
- "slots": {
96
+ "parts": {
102
97
  "hint": {
103
- "description": "Help text below the label"
98
+ "description": "Help text below the label — set via the `hint` attribute (template renders the span and wires aria-describedby); template-owned, not a light-DOM insertion point"
104
99
  },
105
100
  "label": {
106
- "description": "Label text beside the toggle"
101
+ "description": "Label text beside the toggle — set via the `label` attribute (template renders the span); template-owned, not a light-DOM insertion point (gh#1435, gh#1447)"
107
102
  },
108
103
  "thumb": {
109
- "description": "Sliding thumb indicator inside track"
104
+ "description": "Sliding thumb indicator inside track — template-owned anatomy part"
110
105
  },
111
106
  "track": {
112
- "description": "Toggle track container (holds thumb)"
107
+ "description": "Toggle track container (holds thumb) — template-owned anatomy part"
113
108
  }
114
109
  },
110
+ "related": [
111
+ "Check",
112
+ "Radio",
113
+ "Field"
114
+ ],
115
+ "slots": {},
115
116
  "states": [
116
117
  {
117
118
  "description": "Default, ready for interaction.",
@@ -113,7 +113,7 @@ switch-ui[checked] [slot="thumb"] {
113
113
  margin-top: var(--switch-hint-mt, var(--a-space-1));
114
114
  font-size: var(--switch-hint-size, var(--a-ui-xs));
115
115
  color: var(--switch-hint-fg, var(--a-fg-muted));
116
- line-height: var(--switch-hint-lh, 1.4);
116
+ line-height: var(--switch-hint-lh, var(--a-font-leading-normal));
117
117
  }
118
118
  /* The hint is documented (yaml + props table) as rendering BELOW the label,
119
119
  but the base `inline-flex` row laid the stamped `[slot="hint"]` out as a
@@ -3,7 +3,7 @@ name: UISwitch
3
3
  tag: switch-ui
4
4
  status: stable
5
5
  component: Switch
6
- category: layout
6
+ category: input
7
7
  version: 1
8
8
  description: |
9
9
  Toggle switch primitive — binary on/off control where the host IS
@@ -57,15 +57,15 @@ props:
57
57
  events:
58
58
  change:
59
59
  description: Fired when checked state changes
60
- slots:
60
+ parts:
61
61
  hint:
62
- description: Help text below the label
62
+ description: Help text below the label — set via the `hint` attribute (template renders the span and wires aria-describedby); template-owned, not a light-DOM insertion point
63
63
  label:
64
- description: Label text beside the toggle
64
+ description: Label text beside the toggle — set via the `label` attribute (template renders the span); template-owned, not a light-DOM insertion point (gh#1435, gh#1447)
65
65
  thumb:
66
- description: Sliding thumb indicator inside track
66
+ description: Sliding thumb indicator inside track — template-owned anatomy part
67
67
  track:
68
- description: Toggle track container (holds thumb)
68
+ description: Toggle track container (holds thumb) — template-owned anatomy part
69
69
  states:
70
70
  - name: idle
71
71
  description: Default, ready for interaction.
@@ -277,6 +277,7 @@
277
277
  "manage"
278
278
  ],
279
279
  "name": "UITable",
280
+ "parts": {},
280
281
  "related": [
281
282
  "button",
282
283
  "input",
@@ -56,6 +56,7 @@
56
56
 
57
57
  import { UIElement } from '../../core/element.js';
58
58
  import { cellTypes, sortFns } from './cell-types.js';
59
+ import { isNode } from '../../core/dom.js';
59
60
 
60
61
  // ── Helpers ──────────────────────────────────────────────────────────────────
61
62
 
@@ -683,7 +684,7 @@ export class UITable extends UIElement {
683
684
  detail.dataset.for = idx;
684
685
  if (this.expandRenderer) {
685
686
  const content = this.expandRenderer(this.#data[idx], idx);
686
- if (content instanceof Node) detail.appendChild(content);
687
+ if (isNode(content)) detail.appendChild(content);
687
688
  else detail.textContent = String(content);
688
689
  }
689
690
  }
@@ -784,7 +785,7 @@ export class UITable extends UIElement {
784
785
  // Resize handle
785
786
  if (col.resizable !== false) {
786
787
  const handle = document.createElement('div');
787
- handle.setAttribute('data-resize-handle', '');
788
+ handle.setAttribute('data-column-resize-handle', '');
788
789
  handle.dataset.resizeKey = col.key;
789
790
  cell.appendChild(handle);
790
791
  }
@@ -835,10 +836,8 @@ export class UITable extends UIElement {
835
836
  row.dataset.index = dataIndex;
836
837
 
837
838
  if (isSelected) {
838
- row.setAttribute('data-selected', '');
839
839
  row.setAttribute('aria-selected', 'true');
840
840
  } else {
841
- row.removeAttribute('data-selected');
842
841
  row.removeAttribute('aria-selected');
843
842
  }
844
843
 
@@ -887,7 +886,7 @@ export class UITable extends UIElement {
887
886
  // Render priority: column.render > column.format > cellType.render > text
888
887
  if (typeof col.render === 'function') {
889
888
  const result = col.render(value, data, cell, dataIndex);
890
- if (result instanceof Node) {
889
+ if (isNode(result)) {
891
890
  cell.replaceChildren(result);
892
891
  } else if (typeof result === 'string') {
893
892
  cell.innerHTML = result;
@@ -982,7 +981,7 @@ export class UITable extends UIElement {
982
981
  const widths = ['60%', '80%', '70%', '50%', '90%'];
983
982
  sk.setAttribute('width', widths[c % widths.length]);
984
983
  sk.setAttribute('height', '1em');
985
- sk.setAttribute('radius', 'sm');
984
+ sk.setAttribute('corner-radius', 'sm');
986
985
  cell.appendChild(sk);
987
986
  row.appendChild(cell);
988
987
  }
@@ -1270,7 +1269,7 @@ export class UITable extends UIElement {
1270
1269
  * pointer events cover mouse + touch + pen in one handler. */
1271
1270
  #onPointerdown = (e) => {
1272
1271
  if (e.button !== undefined && e.button !== 0) return; // primary button only
1273
- const handle = e.target.closest('[data-resize-handle]');
1272
+ const handle = e.target.closest('[data-column-resize-handle]');
1274
1273
  if (handle && this.contains(handle)) {
1275
1274
  e.preventDefault();
1276
1275
  this.#startResize(e, handle);
@@ -1308,7 +1307,7 @@ export class UITable extends UIElement {
1308
1307
  }
1309
1308
 
1310
1309
  // ── Resize handle mousedown is handled separately ──
1311
- const resizeHandle = target.closest('[data-resize-handle]');
1310
+ const resizeHandle = target.closest('[data-column-resize-handle]');
1312
1311
  if (resizeHandle && this.contains(resizeHandle)) {
1313
1312
  this.#startResize(e, resizeHandle);
1314
1313
  return;
@@ -1450,9 +1449,12 @@ export class UITable extends UIElement {
1450
1449
  const startWidth = headerCell ? headerCell.getBoundingClientRect().width : 100;
1451
1450
  const startX = e.clientX;
1452
1451
 
1453
- this.setAttribute('data-resizing', '');
1452
+ // Stamped on the HANDLE itself, not the table host — table.css's
1453
+ // `[data-column-resize-handle][data-resizing]` rule requires both
1454
+ // attributes on the same element (matching :hover's per-handle scope).
1455
+ handle.setAttribute('data-resizing', '');
1454
1456
 
1455
- this.#resizeState = { key, col, startX, startWidth };
1457
+ this.#resizeState = { key, col, startX, startWidth, handle };
1456
1458
 
1457
1459
  document.addEventListener('pointermove', this.#onResizeMove);
1458
1460
  document.addEventListener('pointerup', this.#onResizeEnd);
@@ -1475,12 +1477,12 @@ export class UITable extends UIElement {
1475
1477
 
1476
1478
  #onResizeEnd = (e) => {
1477
1479
  if (!this.#resizeState) return;
1478
- const { key } = this.#resizeState;
1480
+ const { key, handle } = this.#resizeState;
1479
1481
 
1480
1482
  document.removeEventListener('pointermove', this.#onResizeMove);
1481
1483
  document.removeEventListener('pointerup', this.#onResizeEnd);
1482
1484
 
1483
- this.removeAttribute('data-resizing');
1485
+ handle.removeAttribute('data-resizing');
1484
1486
 
1485
1487
  const width = this.#columnWidths.get(key);
1486
1488
  this.#resizeState = null;
@@ -419,10 +419,12 @@
419
419
 
420
420
  /* Selected row — must out-specify the base row rule `[data-body] >
421
421
  [role="row"]` (0,2,0) and the hover rule (0,2,1), or the highlight never
422
- paints. Scoping to `[data-body] > [role="row"][data-selected]` lifts it to
423
- (0,4,0). (The striped-even override below handles selected+striped, which
424
- is higher still.) */
425
- [data-body] > [role="row"][data-selected] {
422
+ paints. Scoping to `[data-body] > [role="row"][aria-selected="true"]` lifts
423
+ it to (0,4,0). (The striped-even override below handles selected+striped,
424
+ which is higher still.) Keys off `aria-selected` directly — no private
425
+ `[data-selected]` mirror (gh#1332 Category A; matches admin-roster's
426
+ `[aria-checked="true"]` precedent from PR #1438). */
427
+ [data-body] > [role="row"][aria-selected="true"] {
426
428
  background: var(--table-row-bg-selected);
427
429
  }
428
430
 
@@ -446,7 +448,7 @@
446
448
  /* Selected wins over the stripe — same (0,5,0) specificity as the striped-
447
449
  even rule above, placed AFTER it so source order resolves the tie in
448
450
  favor of selection (a selected row reads as selected regardless of stripe). */
449
- :scope[striped] [data-body] > [role="row"][data-selected] {
451
+ :scope[striped] [data-body] > [role="row"][aria-selected="true"] {
450
452
  background: var(--table-row-bg-selected);
451
453
  }
452
454
 
@@ -491,7 +493,7 @@
491
493
 
492
494
  /* ═══════ Resize handle ═══════ */
493
495
 
494
- [data-resize-handle] {
496
+ [data-column-resize-handle] {
495
497
  position: absolute;
496
498
  right: calc(-1 * var(--table-resize-width) / 2);
497
499
  top: 0;
@@ -508,13 +510,13 @@
508
510
  table's right edge (handle centered on the column boundary; the last
509
511
  column has no neighbor to resize against) and triggered a 2 px scrollbar
510
512
  overhang on every table even with nothing to scroll. */
511
- [role="row"] > [role="columnheader"]:last-child [data-resize-handle] {
513
+ [role="row"] > [role="columnheader"]:last-child [data-column-resize-handle] {
512
514
  display: none;
513
515
  z-index: 1;
514
516
  }
515
517
 
516
- [data-resize-handle]:hover,
517
- [data-resize-handle][data-resizing] {
518
+ [data-column-resize-handle]:hover,
519
+ [data-column-resize-handle][data-resizing] {
518
520
  background: var(--table-accent);
519
521
  }
520
522
 
@@ -121,6 +121,7 @@
121
121
  "records"
122
122
  ],
123
123
  "name": "UITableToolbar",
124
+ "parts": {},
124
125
  "related": [
125
126
  "table",
126
127
  "search",
@@ -270,7 +270,7 @@ export class UITableToolbar extends UIElement {
270
270
  title.appendChild(heading);
271
271
 
272
272
  const badge = document.createElement('badge-ui');
273
- badge.setAttribute('data-count-badge', '');
273
+ badge.setAttribute('data-toolbar-count-badge', '');
274
274
  badge.setAttribute('size', 'sm');
275
275
  badge.setAttribute('tone', 'muted');
276
276
  badge.hidden = true;
@@ -343,26 +343,45 @@ export class UITableToolbar extends UIElement {
343
343
 
344
344
  #updateTitle() {
345
345
  const heading = this.querySelector(':scope [data-heading]');
346
- if (!heading) return;
347
- if (this.text) {
348
- heading.textContent = this.text;
349
- heading.hidden = false;
350
- } else if (heading.textContent.trim()) {
351
- heading.hidden = false;
352
- } else {
353
- heading.hidden = true;
346
+ if (heading) {
347
+ if (this.text) {
348
+ heading.textContent = this.text;
349
+ heading.hidden = false;
350
+ } else if (heading.textContent.trim()) {
351
+ heading.hidden = false;
352
+ } else {
353
+ heading.hidden = true;
354
+ }
355
+ }
356
+
357
+ const badge = this.querySelector(':scope [data-toolbar-count-badge]');
358
+ if (badge) {
359
+ const explicit = this.count?.toString().trim();
360
+ const fallback = this.#target?.data?.length;
361
+ const value = explicit || (Number.isFinite(fallback) ? String(fallback) : '');
362
+ if (value) {
363
+ badge.setAttribute('text', value);
364
+ badge.hidden = false;
365
+ } else {
366
+ badge.hidden = true;
367
+ }
354
368
  }
355
369
 
356
- const badge = this.querySelector(':scope [data-count-badge]');
357
- if (!badge) return;
358
- const explicit = this.count?.toString().trim();
359
- const fallback = this.#target?.data?.length;
360
- const value = explicit || (Number.isFinite(fallback) ? String(fallback) : '');
361
- if (value) {
362
- badge.setAttribute('text', value);
363
- badge.hidden = false;
364
- } else {
365
- badge.hidden = true;
370
+ // The CLUSTER hides with its children, not just them (ADIA2-8897):
371
+ // `[data-title]` is `flex: 0 0 auto` in the toolbar row, so an
372
+ // empty-but-present cluster still consumes one `--table-toolbar-gap`
373
+ // (`--a-space-3`, 12px at d=1) and pushes `[data-controls]` off the leading
374
+ // edge of the table it labels the whole visible toolbar on the
375
+ // columns-only shape. Derived from the children's own hidden state so a
376
+ // third child of the cluster stays covered; matched down the stamped path
377
+ // because `#stamp` MOVES `[slot="actions"]` children into the same subtree
378
+ // and a consumer's own `data-title` must not be mistaken for the cluster.
379
+ // Both branches above are guarded, not early-returning, so a missing part
380
+ // can't strand the wrapper mid-state. `children` is array-LIKE (not
381
+ // guaranteed iterable) under the SSR shims, hence `Array.from`.
382
+ const title = this.querySelector(':scope > [data-toolbar] > [data-title]');
383
+ if (title) {
384
+ title.hidden = Array.from(title.children).every((child) => child.hidden);
366
385
  }
367
386
  }
368
387
 
@@ -85,7 +85,7 @@
85
85
  line-height: var(--a-font-leading-snug);
86
86
  }
87
87
 
88
- [data-count-badge][hidden] { display: none; }
88
+ [data-toolbar-count-badge][hidden] { display: none; }
89
89
 
90
90
  /* ═══════ Controls cluster ═══════ */
91
91
 
@@ -25,6 +25,11 @@
25
25
  "description": "Optional leading icon name (Phosphor) for the tab button.",
26
26
  "type": "string"
27
27
  },
28
+ "selected": {
29
+ "description": "Whether this tab's panel is the active one. Managed by the parent <tabs-ui> container — don't set directly; the parent's [value] is the single source of truth (ADR-0056).",
30
+ "type": "boolean",
31
+ "default": false
32
+ },
28
33
  "text": {
29
34
  "description": "Tab button label (rendered by parent <tabs-ui>).",
30
35
  "type": "string"
@@ -39,6 +44,9 @@
39
44
  ],
40
45
  "unevaluatedProperties": false,
41
46
  "x-adiaui": {
47
+ "allowedParents": [
48
+ "Tabs"
49
+ ],
42
50
  "anti_patterns": [],
43
51
  "category": "navigation",
44
52
  "composes": [],
@@ -51,6 +59,7 @@
51
59
  "tabs-child"
52
60
  ],
53
61
  "name": "UITab",
62
+ "parts": {},
54
63
  "related": [
55
64
  "Tabs",
56
65
  "Nav",
@@ -16,6 +16,10 @@ class UITab extends UIElement {
16
16
  value: { type: String, default: '', reflect: true },
17
17
  icon: { type: String, default: '', reflect: true },
18
18
  disabled: { type: Boolean, default: false, reflect: true },
19
+ // ADR-0056 (gh#1303, #1363 B7): declared reflected selection-item state,
20
+ // parent-managed — <tabs-ui> stamps this instead of a private data-*
21
+ // hook. Mirrors <segment-ui>'s [selected].
22
+ selected: { type: Boolean, default: false, reflect: true },
19
23
  };
20
24
 
21
25
  static template = () => null;
@@ -32,8 +32,18 @@ props:
32
32
  description: Whether the tab is selectable.
33
33
  type: boolean
34
34
  default: false
35
+ selected:
36
+ description: >-
37
+ Whether this tab's panel is the active one. Managed by the parent
38
+ <tabs-ui> container — don't set directly; the parent's [value] is
39
+ the single source of truth (ADR-0056).
40
+ type: boolean
41
+ default: false
42
+ reflect: true
35
43
 
36
44
  a2ui:
45
+ allowedParents:
46
+ - Tabs
37
47
  rules:
38
48
  - >-
39
49
  <tab-ui> only renders inside <tabs-ui>. Never use it standalone.
@@ -57,6 +67,11 @@ a2ui:
57
67
  non-selectable. Do not pair <tab-ui> with <button-ui> wrappers —
58
68
  the strip button is parent-rendered. Do not nest <tab-ui> inside
59
69
  another <tab-ui>.
70
+ - >-
71
+ [selected] reflects whether this tab's panel is active — it is
72
+ parent-managed (ADR-0056's selection-item convention, mirroring
73
+ <segment-ui>); author markup drives the parent's [value], never
74
+ [selected] directly.
60
75
 
61
76
  keywords:
62
77
  - tab
@@ -42,8 +42,11 @@
42
42
  ],
43
43
  "unevaluatedProperties": false,
44
44
  "x-adiaui": {
45
+ "allowedChildren": [
46
+ "Tab"
47
+ ],
45
48
  "anti_patterns": [],
46
- "category": "container",
49
+ "category": "navigation",
47
50
  "composes": [
48
51
  "icon-ui"
49
52
  ],
@@ -73,15 +76,17 @@
73
76
  "tab"
74
77
  ],
75
78
  "name": "UITabs",
79
+ "parts": {
80
+ "indicator": {
81
+ "description": "Auto-created sliding indicator element (line variant only) — template-owned anatomy part, not a light-DOM insertion point (gh#1454). Lazily created once via an internal-field guard (`!this.#indicator`), never adopted from a consumer-authored element."
82
+ }
83
+ },
76
84
  "related": [
77
85
  "tab"
78
86
  ],
79
87
  "slots": {
80
88
  "default": {
81
89
  "description": "Child tab-ui elements that form the tab strip"
82
- },
83
- "indicator": {
84
- "description": "Auto-created sliding indicator element (line variant only)"
85
90
  }
86
91
  },
87
92
  "states": [
@@ -25,6 +25,12 @@
25
25
  *
26
26
  * Keyboard:
27
27
  * ArrowLeft / ArrowRight to navigate tabs
28
+ *
29
+ * Selection state: the active <tab-ui>'s [selected] is a declared,
30
+ * reflected prop stamped by this parent — never a private data-* hook
31
+ * (ADR-0056, #1363 B7). The synthesized [slot="tab-button"] strip button
32
+ * (an internal render detail, not a declared primitive) keeps its own
33
+ * [data-active] + aria-selected — ARIA/internal wiring is unchanged.
28
34
  */
29
35
 
30
36
  import { UIElement, html } from '../../core/element.js';
@@ -143,14 +149,20 @@ export class UITabs extends UIElement {
143
149
  // Update sliding indicator
144
150
  this.#updateIndicator();
145
151
 
146
- // Sync tab content visibility
152
+ // Sync tab content visibility. [selected] is the declared, reflected
153
+ // API surface (ADR-0056, #1363 B7) — parent-managed, mirrors
154
+ // <segment-ui>. [hidden] stays the actual visibility driver (native
155
+ // a11y semantics independent of CSS) and is kept in lockstep with
156
+ // [selected] rather than replaced by it.
147
157
  for (const tab of tabs) {
148
158
  const tabVal = tab.value || tab.getAttribute('value') || '';
149
159
  const isActive = tabVal === this.value;
150
160
  if (isActive) {
161
+ tab.setAttribute('selected', '');
151
162
  tab.removeAttribute('hidden');
152
163
  tab.setAttribute('role', 'tabpanel');
153
164
  } else {
165
+ tab.removeAttribute('selected');
154
166
  tab.setAttribute('hidden', '');
155
167
  }
156
168
  }
@@ -172,8 +172,16 @@
172
172
  }
173
173
 
174
174
  /* ── Tab panels ── */
175
+ /* [selected] (ADR-0056, #1363 B7) is the declared state hook driving
176
+ visibility; [hidden] stays set in lockstep as the native a11y/no-CSS
177
+ fallback (tabs.class.js) — both selectors key off the same state, so
178
+ they never disagree. */
175
179
  tab-ui {
176
180
  box-sizing: border-box;
181
+ display: none;
182
+ }
183
+
184
+ tab-ui[selected] {
177
185
  display: block;
178
186
  }
179
187
 
@@ -40,6 +40,8 @@ export class UITab extends UIElement {
40
40
  disabled: boolean;
41
41
  /** Optional leading icon name (Phosphor) for the tab button. */
42
42
  icon: string;
43
+ /** Whether this tab's panel is the active one. Managed by the parent <tabs-ui> container — don't set directly; the parent's [value] is the single source of truth (ADR-0056). */
44
+ selected: boolean;
43
45
  /** Tab button label (rendered by parent <tabs-ui>). */
44
46
  text: string;
45
47
  /** Stable id for the tab. Parent uses this to coordinate active state. */
@@ -5,7 +5,7 @@ name: UITabs
5
5
  tag: tabs-ui
6
6
  status: stable
7
7
  component: Tabs
8
- category: container
8
+ category: navigation
9
9
  version: 1
10
10
  description: >-
11
11
  Tabbed panel switcher. Renders a button strip from child <tab-ui>
@@ -43,8 +43,13 @@ events:
43
43
  slots:
44
44
  default:
45
45
  description: Child tab-ui elements that form the tab strip
46
+ parts:
46
47
  indicator:
47
- description: Auto-created sliding indicator element (line variant only)
48
+ description: >-
49
+ Auto-created sliding indicator element (line variant only) —
50
+ template-owned anatomy part, not a light-DOM insertion point
51
+ (gh#1454). Lazily created once via an internal-field guard
52
+ (`!this.#indicator`), never adopted from a consumer-authored element.
48
53
  states:
49
54
  - name: idle
50
55
  description: Default, ready for interaction.
@@ -83,6 +88,8 @@ tokens:
83
88
  --tabs-radius:
84
89
  description: Override base border radius
85
90
  a2ui:
91
+ allowedChildren:
92
+ - Tab
86
93
  rules:
87
94
  - >-
88
95
  Decision rule: use <tabs-ui> when switching VIEWS within the same
@@ -112,6 +112,7 @@
112
112
  "pill"
113
113
  ],
114
114
  "name": "UITag",
115
+ "parts": {},
115
116
  "related": [
116
117
  "Badge",
117
118
  "NavGroup",
@@ -47,7 +47,7 @@
47
47
  "default": 0
48
48
  },
49
49
  "minLength": {
50
- "description": "Minimum per-token character count after `transform` is applied.",
50
+ "description": "Minimum per-token character count after `normalize` is applied.",
51
51
  "type": "number",
52
52
  "default": 1
53
53
  },
@@ -56,6 +56,17 @@
56
56
  "type": "string",
57
57
  "default": ""
58
58
  },
59
+ "normalize": {
60
+ "description": "Normalize tokens on commit, applied AFTER every candidate is\nalready trimmed of leading/trailing whitespace (unconditional,\nindependent of this attribute). `lowercase` lowercases, `trim`\nis then a no-op (the trim already happened), `strip-spaces`\nremoves all remaining interior whitespace, `\"\"` (default)\napplies no further normalization beyond that unconditional trim\n— case and interior spacing are preserved verbatim. Renamed\nfrom `[transform]` (gh#1335) — this is a value-commit\nnormalization step, a different concept from the global\nEnum·semantic `[transform]` (CSS text-transform display styling:\nuppercase/lowercase/capitalize/none), not merely a colliding\nvocabulary.",
61
+ "type": "string",
62
+ "enum": [
63
+ "",
64
+ "lowercase",
65
+ "trim",
66
+ "strip-spaces"
67
+ ],
68
+ "default": ""
69
+ },
59
70
  "pasteSplit": {
60
71
  "description": "Regex character-class fragment matched against pasted text to\nsplit it into multiple tokens. Default `,\\n` splits on commas\nand newlines. Use `\"\"` to disable paste-splitting entirely.",
61
72
  "type": "string",
@@ -85,17 +96,6 @@
85
96
  "description": "Optional autocomplete strings rendered in a popover below the\nfield. Suggestions are hints, not gates — the typed value still\nwins on commit. JS property only (array reflection skipped).",
86
97
  "$ref": "common_types.json#/$defs/DynamicStringList"
87
98
  },
88
- "transform": {
89
- "description": "Normalize tokens on commit. `lowercase` lowercases, `trim` strips\nleading + trailing whitespace, `strip-spaces` removes all\nwhitespace, `\"\"` (default) preserves the typed value.",
90
- "type": "string",
91
- "enum": [
92
- "",
93
- "lowercase",
94
- "trim",
95
- "strip-spaces"
96
- ],
97
- "default": ""
98
- },
99
99
  "unique": {
100
100
  "description": "Reject duplicate tokens silently (no `invalid` event for accidental dups).",
101
101
  "type": "boolean",
@@ -103,8 +103,12 @@
103
103
  },
104
104
  "validateFn": {
105
105
  "description": "Per-token validator. Sync `(value, index) => boolean` rejects\nfalse synchronously; async `(value, index) => Promise<boolean>`\nflips the host into `[validating]` while pending. JS property\nonly — not serializable in A2UI JSON; wire post-mount.",
106
- "type": "object",
107
- "default": null
106
+ "type": [
107
+ "object",
108
+ "null"
109
+ ],
110
+ "default": null,
111
+ "x-ts-type": "((value: string, index: number) => boolean | Promise<boolean>) | null"
108
112
  },
109
113
  "value": {
110
114
  "description": "Current token list (string array). Setting `.value = ['a','b']`\nreplaces the rendered chips. Reflection skipped — array values\ndo not round-trip through attribute strings.",
@@ -164,7 +168,7 @@
164
168
  "type": "boolean"
165
169
  },
166
170
  "value": {
167
- "description": "Candidate token text (post-transform).",
171
+ "description": "Candidate token text (post-normalize).",
168
172
  "type": "string"
169
173
  }
170
174
  }
@@ -195,12 +199,12 @@
195
199
  "examples": [
196
200
  {
197
201
  "description": "Label input with lowercase normalization + max 10 tags + 2 pre-committed values.",
198
- "a2ui": "[\n {\"id\": \"root\", \"component\": \"Card\", \"children\": [\"sec\"]},\n {\"id\": \"sec\", \"component\": \"Section\", \"children\": [\"field\"]},\n {\n \"id\": \"field\",\n \"component\": \"Field\",\n \"label\": \"Labels\",\n \"children\": [\"tags\"]\n },\n {\n \"id\": \"tags\",\n \"component\": \"TagsInput\",\n \"name\": \"labels\",\n \"placeholder\": \"Add a label, press Enter\",\n \"transform\": \"lowercase\",\n \"max\": 10,\n \"value\": [\"bug\", \"high-priority\"]\n }\n]",
202
+ "a2ui": "[\n {\"id\": \"root\", \"component\": \"Card\", \"children\": [\"sec\"]},\n {\"id\": \"sec\", \"component\": \"Section\", \"children\": [\"field\"]},\n {\n \"id\": \"field\",\n \"component\": \"Field\",\n \"label\": \"Labels\",\n \"children\": [\"tags\"]\n },\n {\n \"id\": \"tags\",\n \"component\": \"TagsInput\",\n \"name\": \"labels\",\n \"placeholder\": \"Add a label, press Enter\",\n \"normalize\": \"lowercase\",\n \"max\": 10,\n \"value\": [\"bug\", \"high-priority\"]\n }\n]",
199
203
  "name": "canonical-labels"
200
204
  },
201
205
  {
202
206
  "description": "Recipient picker with Enter-only commit (commas are legal in display names).",
203
- "a2ui": "[\n {\n \"id\": \"to\",\n \"component\": \"TagsInput\",\n \"name\": \"to\",\n \"placeholder\": \"Email…\",\n \"delimiter\": \"enter\",\n \"transform\": \"trim\"\n }\n]",
207
+ "a2ui": "[\n {\n \"id\": \"to\",\n \"component\": \"TagsInput\",\n \"name\": \"to\",\n \"placeholder\": \"Email…\",\n \"delimiter\": \"enter\",\n \"normalize\": \"trim\"\n }\n]",
204
208
  "name": "email-recipients"
205
209
  }
206
210
  ],
@@ -218,6 +222,7 @@
218
222
  "multi-value-input"
219
223
  ],
220
224
  "name": "UITagsInput",
225
+ "parts": {},
221
226
  "related": [
222
227
  "tag",
223
228
  "select",