@adia-ai/web-components 0.8.39 → 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 (424) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/MIGRATION.md +1269 -3
  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-artifact/agent-artifact.css +1 -1
  21. package/components/agent-feedback-bar/agent-feedback-bar.a2ui.json +6 -5
  22. package/components/agent-feedback-bar/agent-feedback-bar.yaml +6 -2
  23. package/components/agent-questions/agent-questions.a2ui.json +1 -0
  24. package/components/agent-reasoning/agent-reasoning.a2ui.json +6 -5
  25. package/components/agent-reasoning/agent-reasoning.css +2 -2
  26. package/components/agent-reasoning/agent-reasoning.yaml +6 -2
  27. package/components/agent-suggestions/agent-suggestions.a2ui.json +11 -2
  28. package/components/agent-suggestions/agent-suggestions.class.js +2 -1
  29. package/components/agent-suggestions/agent-suggestions.d.ts +4 -4
  30. package/components/agent-suggestions/agent-suggestions.yaml +4 -2
  31. package/components/agent-trace/agent-trace.a2ui.json +6 -5
  32. package/components/agent-trace/agent-trace.css +3 -3
  33. package/components/agent-trace/agent-trace.yaml +6 -2
  34. package/components/alert/alert.a2ui.json +1 -0
  35. package/components/alert/alert.css +2 -2
  36. package/components/anchor-bar/anchor-bar.a2ui.json +1 -0
  37. package/components/aside/aside.a2ui.json +1 -0
  38. package/components/avatar/avatar-group.a2ui.json +7 -1
  39. package/components/avatar/avatar-group.yaml +1 -0
  40. package/components/avatar/avatar.a2ui.json +12 -11
  41. package/components/avatar/avatar.css +1 -1
  42. package/components/avatar/avatar.d.ts +1 -1
  43. package/components/avatar/avatar.yaml +4 -4
  44. package/components/badge/badge.a2ui.json +1 -0
  45. package/components/badge/badge.css +1 -1
  46. package/components/block/block.a2ui.json +1 -0
  47. package/components/blockquote/blockquote.a2ui.json +1 -0
  48. package/components/breadcrumb/breadcrumb.a2ui.json +1 -0
  49. package/components/button/button.a2ui.json +1 -3
  50. package/components/button/button.css +6 -5
  51. package/components/button/button.yaml +1 -3
  52. package/components/calendar-grid/calendar-grid.a2ui.json +1 -0
  53. package/components/calendar-grid/calendar-grid.class.js +2 -1
  54. package/components/calendar-picker/calendar-picker.a2ui.json +143 -24
  55. package/components/calendar-picker/calendar-picker.class.js +490 -197
  56. package/components/calendar-picker/calendar-picker.css +121 -172
  57. package/components/calendar-picker/calendar-picker.yaml +225 -47
  58. package/components/canvas/canvas.a2ui.json +6 -5
  59. package/components/canvas/canvas.d.ts +37 -0
  60. package/components/canvas/canvas.js +72 -3
  61. package/components/canvas/canvas.yaml +6 -2
  62. package/components/card/card.a2ui.json +25 -2
  63. package/components/card/card.class.js +3 -0
  64. package/components/card/card.css +34 -4
  65. package/components/card/card.d.ts +2 -2
  66. package/components/card/card.examples.md +3 -3
  67. package/components/card/card.yaml +28 -4
  68. package/components/chart/chart.a2ui.json +13 -8
  69. package/components/chart/chart.class.js +10 -10
  70. package/components/chart/chart.css +12 -10
  71. package/components/chart/chart.d.ts +2 -2
  72. package/components/chart/chart.yaml +8 -5
  73. package/components/chart-legend/chart-legend.a2ui.json +1 -0
  74. package/components/chat-thread/chat-input.a2ui.json +1 -0
  75. package/components/chat-thread/chat-thread.a2ui.json +10 -9
  76. package/components/chat-thread/chat-thread.css +1 -1
  77. package/components/chat-thread/chat-thread.yaml +13 -20
  78. package/components/check/check.a2ui.json +10 -9
  79. package/components/check/check.yaml +4 -4
  80. package/components/code/code.a2ui.json +1 -0
  81. package/components/code/code.css +6 -6
  82. package/components/col/col.a2ui.json +1 -0
  83. package/components/color-input/color-input.a2ui.json +1 -0
  84. package/components/color-picker/color-picker.a2ui.json +1 -0
  85. package/components/combobox/combobox.a2ui.json +3 -2
  86. package/components/combobox/combobox.css +2 -2
  87. package/components/combobox/combobox.yaml +2 -2
  88. package/components/command/command.a2ui.json +12 -10
  89. package/components/command/command.class.js +3 -2
  90. package/components/command/command.css +3 -3
  91. package/components/command/command.yaml +17 -4
  92. package/components/context-menu/context-menu.a2ui.json +1 -0
  93. package/components/date-range-picker/date-range-picker.a2ui.json +2 -1
  94. package/components/date-range-picker/date-range-picker.css +1 -1
  95. package/components/date-range-picker/date-range-picker.yaml +1 -1
  96. package/components/datetime-picker/datetime-picker.a2ui.json +15 -108
  97. package/components/datetime-picker/datetime-picker.class.js +37 -690
  98. package/components/datetime-picker/datetime-picker.css +11 -183
  99. package/components/datetime-picker/datetime-picker.d.ts +4 -5
  100. package/components/datetime-picker/datetime-picker.yaml +44 -135
  101. package/components/demo-toggle/demo-toggle.a2ui.json +1 -0
  102. package/components/demo-toggle/demo-toggle.css +1 -1
  103. package/components/description-list/description-list.a2ui.json +1 -0
  104. package/components/description-list/description-list.css +2 -2
  105. package/components/display-field/display-field.a2ui.json +1 -0
  106. package/components/display-field/display-field.css +3 -3
  107. package/components/divider/divider.a2ui.json +1 -0
  108. package/components/divider/divider.css +1 -1
  109. package/components/drawer/drawer.a2ui.json +1 -3
  110. package/components/drawer/drawer.css +3 -3
  111. package/components/drawer/drawer.yaml +0 -2
  112. package/components/drilldown/drilldown.a2ui.json +22 -20
  113. package/components/drilldown/drilldown.class.js +4 -3
  114. package/components/drilldown/drilldown.css +8 -8
  115. package/components/drilldown/drilldown.yaml +40 -9
  116. package/components/embed/embed.a2ui.json +6 -5
  117. package/components/embed/embed.yaml +2 -2
  118. package/components/empty-state/empty-state.a2ui.json +1 -0
  119. package/components/empty-state/empty-state.css +2 -2
  120. package/components/feed/feed-item.a2ui.json +25 -5
  121. package/components/feed/feed-item.yaml +28 -7
  122. package/components/feed/feed.a2ui.json +9 -2
  123. package/components/feed/feed.class.js +19 -12
  124. package/components/feed/feed.css +8 -8
  125. package/components/feed/feed.yaml +14 -1
  126. package/components/field/field.a2ui.json +1 -0
  127. package/components/field/field.css +1 -1
  128. package/components/field/field.examples.md +1 -1
  129. package/components/fields/fields.a2ui.json +1 -0
  130. package/components/fields/fields.examples.md +1 -1
  131. package/components/footer/footer.a2ui.json +1 -0
  132. package/components/frame/frame.a2ui.json +1 -0
  133. package/components/grid/grid.a2ui.json +1 -0
  134. package/components/header/header.a2ui.json +3 -2
  135. package/components/header/header.yaml +3 -3
  136. package/components/heatmap/heatmap.a2ui.json +2 -1
  137. package/components/heatmap/heatmap.class.js +1 -1
  138. package/components/heatmap/heatmap.css +6 -6
  139. package/components/heatmap/heatmap.yaml +1 -1
  140. package/components/icon/icon.a2ui.json +1 -0
  141. package/components/image/image.a2ui.json +28 -14
  142. package/components/image/image.class.js +38 -23
  143. package/components/image/image.css +18 -8
  144. package/components/image/image.d.ts +2 -2
  145. package/components/image/image.examples.md +3 -3
  146. package/components/image/image.yaml +23 -7
  147. package/components/inline-edit/inline-edit.a2ui.json +1 -0
  148. package/components/inline-message/inline-message.a2ui.json +3 -1
  149. package/components/inline-message/inline-message.class.js +3 -1
  150. package/components/inline-message/inline-message.css +1 -1
  151. package/components/inline-message/inline-message.d.ts +2 -2
  152. package/components/inline-message/inline-message.yaml +2 -1
  153. package/components/input/input.a2ui.json +66 -16
  154. package/components/input/input.class.js +64 -7
  155. package/components/input/input.css +19 -18
  156. package/components/input/input.d.ts +9 -4
  157. package/components/input/input.yaml +83 -10
  158. package/components/inspector/inspector.a2ui.json +1 -0
  159. package/components/integration-card/integration-card.a2ui.json +1 -0
  160. package/components/integration-card/integration-card.css +4 -4
  161. package/components/kbd/kbd.a2ui.json +1 -0
  162. package/components/kbd/kbd.css +1 -1
  163. package/components/link/link.a2ui.json +2 -1
  164. package/components/link/link.yaml +1 -1
  165. package/components/list/list-item.a2ui.json +9 -0
  166. package/components/list/list-item.yaml +12 -0
  167. package/components/list/list.a2ui.json +9 -3
  168. package/components/list/list.class.js +14 -1
  169. package/components/list/list.css +14 -3
  170. package/components/list/list.d.ts +7 -5
  171. package/components/list/list.yaml +16 -6
  172. package/components/list-window/list-window.a2ui.json +1 -0
  173. package/components/list-window/list-window.class.js +2 -1
  174. package/components/loading-overlay/loading-overlay.a2ui.json +1 -0
  175. package/components/mark/mark.a2ui.json +2 -1
  176. package/components/mark/mark.yaml +1 -1
  177. package/components/menu/menu-divider.a2ui.json +1 -0
  178. package/components/menu/menu-item.a2ui.json +3 -1
  179. package/components/menu/menu-item.yaml +6 -0
  180. package/components/menu/menu-label.a2ui.json +1 -0
  181. package/components/menu/menu.a2ui.json +3 -2
  182. package/components/menu/menu.class.js +2 -2
  183. package/components/menu/menu.d.ts +2 -2
  184. package/components/menu/menu.yaml +3 -3
  185. package/components/modal/modal.a2ui.json +1 -0
  186. package/components/nav/nav.a2ui.json +1 -0
  187. package/components/nav/nav.class.js +14 -3
  188. package/components/nav/nav.css +2 -2
  189. package/components/nav-group/nav-group.a2ui.json +1 -0
  190. package/components/nav-group/nav-group.class.js +3 -1
  191. package/components/nav-group/nav-group.css +3 -3
  192. package/components/nav-item/nav-item.a2ui.json +1 -0
  193. package/components/nav-item/nav-item.css +2 -2
  194. package/components/noodles/noodles.a2ui.json +1 -0
  195. package/components/noodles/noodles.class.js +5 -1
  196. package/components/number-format/number-format.a2ui.json +1 -0
  197. package/components/option-card/option-card.a2ui.json +1 -0
  198. package/components/option-card/option-card.css +1 -1
  199. package/components/otp-input/otp-input.a2ui.json +3 -2
  200. package/components/otp-input/otp-input.css +1 -1
  201. package/components/otp-input/otp-input.yaml +9 -2
  202. package/components/page/page.a2ui.json +13 -0
  203. package/components/page/page.css +2 -2
  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/pagination/pagination.css +1 -1
  209. package/components/pane/pane.a2ui.json +6 -0
  210. package/components/pane/pane.class.js +3 -3
  211. package/components/pane/pane.css +3 -3
  212. package/components/pane/pane.yaml +3 -0
  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.css +2 -2
  229. package/components/progress-row/progress-row.d.ts +2 -2
  230. package/components/progress-row/progress-row.examples.md +2 -14
  231. package/components/progress-row/progress-row.yaml +28 -36
  232. package/components/qr-code/qr-code.a2ui.json +13 -12
  233. package/components/qr-code/qr-code.class.js +7 -7
  234. package/components/qr-code/qr-code.css +1 -1
  235. package/components/qr-code/qr-code.d.ts +10 -7
  236. package/components/qr-code/qr-code.yaml +18 -12
  237. package/components/radio/radio.a2ui.json +8 -7
  238. package/components/radio/radio.class.js +8 -0
  239. package/components/radio/radio.yaml +3 -3
  240. package/components/radio-group/radio-group.a2ui.json +5 -3
  241. package/components/radio-group/radio-group.class.js +11 -0
  242. package/components/radio-group/radio-group.yaml +7 -1
  243. package/components/range/range.a2ui.json +6 -0
  244. package/components/range/range.class.js +2 -2
  245. package/components/range/range.css +3 -3
  246. package/components/range/range.yaml +3 -0
  247. package/components/rating/rating.a2ui.json +1 -0
  248. package/components/rating/rating.css +1 -1
  249. package/components/relative-time/relative-time.a2ui.json +1 -0
  250. package/components/richtext/richtext.a2ui.json +2 -1
  251. package/components/richtext/richtext.css +3 -3
  252. package/components/richtext/richtext.yaml +1 -1
  253. package/components/row/row.a2ui.json +1 -0
  254. package/components/search/search.a2ui.json +1 -0
  255. package/components/search/search.class.js +4 -1
  256. package/components/section/section.a2ui.json +1 -0
  257. package/components/segment/segment.a2ui.json +21 -10
  258. package/components/segment/segment.css +20 -4
  259. package/components/segment/segment.d.ts +2 -1
  260. package/components/segment/segment.yaml +20 -13
  261. package/components/segmented/segmented.a2ui.json +36 -7
  262. package/components/segmented/segmented.class.js +113 -22
  263. package/components/segmented/segmented.css +3 -0
  264. package/components/segmented/segmented.d.ts +3 -1
  265. package/components/segmented/segmented.yaml +80 -8
  266. package/components/select/select.a2ui.json +18 -13
  267. package/components/select/select.class.js +61 -37
  268. package/components/select/select.css +18 -16
  269. package/components/select/select.yaml +18 -7
  270. package/components/skeleton/skeleton.a2ui.json +8 -7
  271. package/components/skeleton/skeleton.class.js +8 -7
  272. package/components/skeleton/skeleton.css +21 -6
  273. package/components/skeleton/skeleton.d.ts +2 -2
  274. package/components/skeleton/skeleton.examples.md +2 -2
  275. package/components/skeleton/skeleton.yaml +3 -2
  276. package/components/skip-nav/skip-nav.a2ui.json +1 -0
  277. package/components/slider/slider.a2ui.json +6 -0
  278. package/components/slider/slider.class.js +20 -3
  279. package/components/slider/slider.css +2 -2
  280. package/components/slider/slider.yaml +3 -0
  281. package/components/spinner/spinner.a2ui.json +1 -0
  282. package/components/spinner/spinner.css +1 -1
  283. package/components/stack/stack.a2ui.json +1 -0
  284. package/components/stat/stat.a2ui.json +1 -0
  285. package/components/stat/stat.css +3 -3
  286. package/components/stat/stat.js +2 -2
  287. package/components/step-progress/step-progress.a2ui.json +1 -0
  288. package/components/step-progress/step-progress.css +1 -1
  289. package/components/step-progress/step-progress.yaml +1 -1
  290. package/components/stepper/stepper-item.a2ui.json +7 -3
  291. package/components/stepper/stepper-item.yaml +15 -5
  292. package/components/stepper/stepper.a2ui.json +5 -1
  293. package/components/stepper/stepper.class.js +31 -16
  294. package/components/stepper/stepper.css +2 -2
  295. package/components/stepper/stepper.d.ts +1 -1
  296. package/components/stepper/stepper.yaml +4 -2
  297. package/components/stream/stream.a2ui.json +1 -0
  298. package/components/swatch/swatch.a2ui.json +1 -0
  299. package/components/swatch/swatch.css +2 -2
  300. package/components/swiper/swiper.a2ui.json +1 -0
  301. package/components/swiper/swiper.class.js +5 -1
  302. package/components/switch/switch.a2ui.json +12 -11
  303. package/components/switch/switch.css +1 -1
  304. package/components/switch/switch.yaml +6 -6
  305. package/components/table/table.a2ui.json +1 -10
  306. package/components/table/table.class.js +18 -16
  307. package/components/table/table.css +17 -18
  308. package/components/table/table.d.ts +0 -2
  309. package/components/table/table.yaml +0 -9
  310. package/components/table-toolbar/table-toolbar.a2ui.json +1 -0
  311. package/components/table-toolbar/table-toolbar.class.js +38 -19
  312. package/components/table-toolbar/table-toolbar.css +2 -2
  313. package/components/tabs/tab.a2ui.json +9 -0
  314. package/components/tabs/tab.js +4 -0
  315. package/components/tabs/tab.yaml +15 -0
  316. package/components/tabs/tabs.a2ui.json +9 -4
  317. package/components/tabs/tabs.class.js +13 -1
  318. package/components/tabs/tabs.css +9 -1
  319. package/components/tabs/tabs.d.ts +2 -0
  320. package/components/tabs/tabs.yaml +9 -2
  321. package/components/tag/tag.a2ui.json +1 -0
  322. package/components/tag/tag.css +2 -2
  323. package/components/tags-input/tags-input.a2ui.json +22 -17
  324. package/components/tags-input/tags-input.class.js +13 -11
  325. package/components/tags-input/tags-input.css +11 -7
  326. package/components/tags-input/tags-input.d.ts +16 -7
  327. package/components/tags-input/tags-input.examples.md +2 -2
  328. package/components/tags-input/tags-input.yaml +25 -8
  329. package/components/text/text.a2ui.json +6 -5
  330. package/components/text/text.css +10 -5
  331. package/components/text/text.d.ts +2 -2
  332. package/components/text/text.yaml +9 -4
  333. package/components/textarea/textarea.a2ui.json +2 -1
  334. package/components/textarea/textarea.css +1 -1
  335. package/components/textarea/textarea.yaml +1 -1
  336. package/components/theme-provider/theme-provider.a2ui.json +2 -1
  337. package/components/theme-provider/theme-provider.d.ts +5 -3
  338. package/components/theme-provider/theme-provider.yaml +5 -3
  339. package/components/time-picker/time-picker.a2ui.json +1 -0
  340. package/components/time-picker/time-picker.class.js +4 -2
  341. package/components/time-picker/time-picker.css +1 -1
  342. package/components/timeline/timeline-item.a2ui.json +26 -3
  343. package/components/timeline/timeline-item.yaml +22 -7
  344. package/components/timeline/timeline.a2ui.json +4 -0
  345. package/components/timeline/timeline.class.js +29 -18
  346. package/components/timeline/timeline.css +4 -4
  347. package/components/timeline/timeline.d.ts +3 -3
  348. package/components/timeline/timeline.yaml +2 -0
  349. package/components/toast/toast.a2ui.json +10 -3
  350. package/components/toast/toast.yaml +20 -13
  351. package/components/toc/toc.a2ui.json +1 -0
  352. package/components/toc/toc.css +1 -1
  353. package/components/toggle-group/toggle-group.a2ui.json +7 -3
  354. package/components/toggle-group/toggle-group.class.js +43 -12
  355. package/components/toggle-group/toggle-group.css +7 -4
  356. package/components/toggle-group/toggle-group.d.ts +3 -4
  357. package/components/toggle-group/toggle-group.yaml +22 -16
  358. package/components/toggle-group/toggle-option.a2ui.json +8 -4
  359. package/components/toggle-group/toggle-option.yaml +15 -13
  360. package/components/toggle-scheme/toggle-scheme.a2ui.json +2 -1
  361. package/components/toggle-scheme/toggle-scheme.yaml +1 -1
  362. package/components/toolbar/toolbar-group.a2ui.json +1 -0
  363. package/components/toolbar/toolbar.a2ui.json +1 -0
  364. package/components/toolbar/toolbar.class.js +3 -0
  365. package/components/tooltip/tooltip.a2ui.json +1 -0
  366. package/components/tooltip/tooltip.css +1 -1
  367. package/components/tour/tour-step.a2ui.json +4 -0
  368. package/components/tour/tour-step.yaml +2 -0
  369. package/components/tour/tour.a2ui.json +4 -0
  370. package/components/tour/tour.css +2 -2
  371. package/components/tour/tour.yaml +2 -0
  372. package/components/tree/tree-item.a2ui.json +5 -0
  373. package/components/tree/tree-item.yaml +3 -0
  374. package/components/tree/tree.a2ui.json +4 -0
  375. package/components/tree/tree.class.js +2 -1
  376. package/components/tree/tree.css +1 -1
  377. package/components/tree/tree.yaml +2 -0
  378. package/components/upload/upload.a2ui.json +8 -1
  379. package/components/upload/upload.class.js +35 -5
  380. package/components/upload/upload.css +28 -0
  381. package/components/upload/upload.d.ts +16 -0
  382. package/components/upload/upload.yaml +27 -7
  383. package/components/visually-hidden/visually-hidden.a2ui.json +1 -0
  384. package/core/dom.d.ts +11 -0
  385. package/core/dom.js +34 -0
  386. package/core/form.js +7 -0
  387. package/core/index.d.ts +1 -0
  388. package/core/index.js +1 -0
  389. package/core/responsive.js +16 -4
  390. package/core/template.js +2 -1
  391. package/custom-elements.json +442 -502
  392. package/dist/host.min.css +1 -1
  393. package/dist/host.sheet.js +1 -1
  394. package/dist/theme-provider.min.js +5 -5
  395. package/dist/web-components.min.css +1 -1
  396. package/dist/web-components.min.js +91 -104
  397. package/dist/web-components.sheet.js +1 -1
  398. package/package.json +4 -2
  399. package/patterns/conversion-funnel/conversion-funnel.examples.html +15 -15
  400. package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
  401. package/patterns/inline-dialog/inline-dialog.html +4 -0
  402. package/patterns/timezone-selector/timezone-selector.examples.html +1 -1
  403. package/patterns/timezone-selector/timezone-selector.html +2 -2
  404. package/styles/api/text.css +7 -0
  405. package/styles/type/scale.css +6 -7
  406. package/traits/_catalog.json +129 -41
  407. package/traits/anchor-positioning/anchor-positioning.js +1 -0
  408. package/traits/announcer/announcer.js +1 -0
  409. package/traits/arrow-grid-nav/arrow-grid-nav.js +1 -0
  410. package/traits/attention-pulse/attention-pulse.js +1 -0
  411. package/traits/count-up/count-up.js +1 -0
  412. package/traits/define.js +78 -0
  413. package/traits/focus-restore/focus-restore.js +2 -1
  414. package/traits/haptic-feedback/haptic-feedback.js +1 -0
  415. package/traits/input-mask/input-mask.js +1 -0
  416. package/traits/intersection-observer/intersection-observer.js +1 -0
  417. package/traits/layout-animation/layout-animation.js +1 -0
  418. package/traits/noise-texture/noise-texture.js +1 -0
  419. package/traits/resize-observer/resize-observer.js +1 -0
  420. package/traits/scroll-progress/scroll-progress.js +1 -0
  421. package/traits/snap-to-grid/snap-to-grid.js +1 -0
  422. package/traits/sound-feedback/sound-feedback.js +1 -0
  423. package/traits/spring-animate/spring-animate.js +1 -0
  424. package/traits/validation/validation.js +1 -0
@@ -52,6 +52,7 @@
52
52
  "section"
53
53
  ],
54
54
  "name": "UISection",
55
+ "parts": {},
55
56
  "related": [
56
57
  "avatar",
57
58
  "input",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://adiaui.dev/a2ui/v0_9/components/Segment.json",
4
4
  "title": "Segment",
5
- "description": "Individual segment child of <segmented-ui> — carries the [value],\n[text], optional [icon], and [selected] state for one option in\na horizontal segmented selector. Distinct from <tab-ui> (a view\nswitcher's child) and <option> (native option for <select-ui>).\nUse segment-ui only as a direct child of <segmented-ui>; never\nstandalone.\n",
5
+ "description": "Individual segment child of <segmented-ui> — carries the [value],\n[text], optional [icon], and [selected] state for one option in\na horizontal segmented selector, single- or multi-select\n(<segmented-ui multiple>, gh#1369). Distinct from <tab-ui> (a view\nswitcher's child) and <option> (native option for <select-ui>).\nUse segment-ui only as a direct child of <segmented-ui>; never\nstandalone.\n",
6
6
  "type": "object",
7
7
  "allOf": [
8
8
  {
@@ -47,6 +47,9 @@
47
47
  ],
48
48
  "unevaluatedProperties": false,
49
49
  "x-adiaui": {
50
+ "allowedParents": [
51
+ "Segmented"
52
+ ],
50
53
  "anti_patterns": [],
51
54
  "category": "navigation",
52
55
  "composes": [
@@ -56,36 +59,39 @@
56
59
  "examples": [
57
60
  {
58
61
  "description": "Segmented control with 3 segment options for tab-like switching.",
59
- "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"SegmentedControl\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"text\": \"Overview\",\n \"active\": true\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"text\": \"Features\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"text\": \"Pricing\"\n }\n]",
62
+ "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"text\": \"Overview\",\n \"selected\": true\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"text\": \"Features\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"text\": \"Pricing\"\n }\n]",
60
63
  "name": "segmented-control"
61
64
  },
62
65
  {
63
66
  "description": "Three segments inside a segmented control for view switching.",
64
- "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"SegmentedControl\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"overview\",\n \"text\": \"Overview\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"features\",\n \"text\": \"Features\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"pricing\",\n \"text\": \"Pricing\"\n }\n]",
67
+ "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"overview\",\n \"text\": \"Overview\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"features\",\n \"text\": \"Features\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"pricing\",\n \"text\": \"Pricing\"\n }\n]",
65
68
  "name": "basic"
66
69
  },
67
70
  {
68
71
  "description": "Segmented control showing four time-range segments labeled via text attribute.",
69
- "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"SegmentedControl\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\",\n \"s4\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"d\",\n \"text\": \"Daily\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"w\",\n \"text\": \"Weekly\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"m\",\n \"text\": \"Monthly\"\n },\n {\n \"id\": \"s4\",\n \"component\": \"Segment\",\n \"value\": \"y\",\n \"text\": \"Yearly\"\n }\n]",
72
+ "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\",\n \"s4\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"d\",\n \"text\": \"Daily\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"w\",\n \"text\": \"Weekly\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"m\",\n \"text\": \"Monthly\"\n },\n {\n \"id\": \"s4\",\n \"component\": \"Segment\",\n \"value\": \"y\",\n \"text\": \"Yearly\"\n }\n]",
70
73
  "name": "text"
71
74
  },
72
75
  {
73
76
  "description": "Segmented control with one disabled segment that cannot be selected.",
74
- "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"SegmentedControl\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"free\",\n \"text\": \"Free\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"pro\",\n \"text\": \"Pro\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"enterprise\",\n \"text\": \"Enterprise\",\n \"disabled\": true\n }\n]",
77
+ "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"free\",\n \"text\": \"Free\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"pro\",\n \"text\": \"Pro\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"enterprise\",\n \"text\": \"Enterprise\",\n \"disabled\": true\n }\n]",
75
78
  "name": "disabled"
76
79
  },
77
80
  {
78
81
  "description": "Segmented control with icon+text segments for view-mode toggles (list, grid, board).",
79
- "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"SegmentedControl\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"list\",\n \"text\": \"List\",\n \"icon\": \"list\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"grid\",\n \"text\": \"Grid\",\n \"icon\": \"squares-four\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"board\",\n \"text\": \"Board\",\n \"icon\": \"kanban\"\n }\n]",
82
+ "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"list\",\n \"text\": \"List\",\n \"icon\": \"list\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"grid\",\n \"text\": \"Grid\",\n \"icon\": \"squares-four\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"board\",\n \"text\": \"Board\",\n \"icon\": \"kanban\"\n }\n]",
80
83
  "name": "icons"
81
84
  }
82
85
  ],
83
86
  "keywords": [
84
- "segment"
87
+ "segment",
88
+ "toggle-option"
85
89
  ],
86
90
  "name": "UISegment",
91
+ "parts": {},
87
92
  "related": [
88
- "segmented-control"
93
+ "segmented-control",
94
+ "ToggleOption"
89
95
  ],
90
96
  "slots": {},
91
97
  "states": [
@@ -104,11 +110,16 @@
104
110
  "segment": [
105
111
  "segment-button",
106
112
  "segmented-option",
107
- "option-button"
113
+ "option-button",
114
+ "toggle-option"
108
115
  ]
109
116
  },
110
117
  "tag": "segment-ui",
111
- "tokens": {},
118
+ "tokens": {
119
+ "--segment-bg-selected": {
120
+ "description": "Background color of a selected segment under the parent's [multiple] mode (no sliding indicator in that mode)."
121
+ }
122
+ },
112
123
  "traits": [],
113
124
  "version": 1
114
125
  }
@@ -8,6 +8,16 @@ segment-ui[selected] {
8
8
  color: var(--segment-fg-selected);
9
9
  }
10
10
 
11
+ /* [multiple] (gh#1369, #1363 C1): the parent segmented-ui[multiple] never
12
+ creates a sliding indicator (segmented.class.js render()), so each
13
+ selected segment paints its own background instead — mirrors the
14
+ deprecated toggle-option-ui[selected] treatment it replaces. Scoped to
15
+ the multiple ancestor so single-select's indicator-driven look is
16
+ unchanged. */
17
+ segmented-ui[multiple] > segment-ui[selected] {
18
+ background: var(--segment-bg-selected);
19
+ }
20
+
11
21
  @scope (segment-ui) {
12
22
  :where(:scope) {
13
23
  /* ── Layout ── */
@@ -23,15 +33,21 @@ segment-ui[selected] {
23
33
  `line-height: 1` is deliberate, but the label's ::after clips to its
24
34
  own line box, so inheriting 1 makes half-leading negative and shears
25
35
  descenders (g/j/p/q/y, parentheses) by ~0.93px at the default size —
26
- gh#906. Snug (1.3) contains the font's content box at every [size];
27
- mirrors --button-label-line-height. */
28
- --segment-label-line-height: var(--a-leading-snug);
36
+ gh#906. Normal (1.35) contains the font's content box at every
37
+ [size]; mirrors --button-label-line-height. Value-nearest migration
38
+ from the retired --a-leading-snug (1.3) — ADR-0052. */
39
+ --segment-label-line-height: var(--a-font-leading-normal);
29
40
 
30
41
  /* ── Colors ── */
31
42
  --segment-fg: var(--a-ui-text-subtle);
32
43
  --segment-fg-hover: var(--a-ui-text-hover);
33
44
  --segment-fg-selected: var(--a-chrome-dark);
34
45
  --segment-fg-disabled: var(--a-ui-text-disabled);
46
+ /* [multiple] only — see the moved-out selector above (Safari 17.x bug
47
+ note at top of file). Same default the deprecated
48
+ toggle-option-ui[selected] background used, for visual continuity
49
+ across the merge (gh#1369). */
50
+ --segment-bg-selected: var(--md-sys-color-primary-container);
35
51
 
36
52
  /* ── Transition ── */
37
53
  --segment-duration: var(--a-duration-fast);
@@ -60,7 +76,7 @@ segment-ui[selected] {
60
76
  font-family: var(--segment-font-family);
61
77
  font-size: var(--segment-font-size);
62
78
  font-weight: var(--segment-font-weight);
63
- line-height: 1;
79
+ line-height: var(--a-font-leading-none);
64
80
  color: var(--segment-fg);
65
81
  white-space: nowrap;
66
82
  overflow: hidden;
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * `<segment-ui>` — Individual segment child of <segmented-ui> — carries the [value],
3
3
  [text], optional [icon], and [selected] state for one option in
4
- a horizontal segmented selector. Distinct from <tab-ui> (a view
4
+ a horizontal segmented selector, single- or multi-select
5
+ (<segmented-ui multiple>, gh#1369). Distinct from <tab-ui> (a view
5
6
  switcher's child) and <option> (native option for <select-ui>).
6
7
  Use segment-ui only as a direct child of <segmented-ui>; never
7
8
  standalone.
@@ -10,7 +10,8 @@ version: 1
10
10
  description: |
11
11
  Individual segment child of <segmented-ui> — carries the [value],
12
12
  [text], optional [icon], and [selected] state for one option in
13
- a horizontal segmented selector. Distinct from <tab-ui> (a view
13
+ a horizontal segmented selector, single- or multi-select
14
+ (<segmented-ui multiple>, gh#1369). Distinct from <tab-ui> (a view
14
15
  switcher's child) and <option> (native option for <select-ui>).
15
16
  Use segment-ui only as a direct child of <segmented-ui>; never
16
17
  standalone.
@@ -51,14 +52,18 @@ states:
51
52
  description: Non-interactive; dimmed.
52
53
  attribute: disabled
53
54
  traits: []
54
- tokens: {}
55
+ tokens:
56
+ --segment-bg-selected:
57
+ description: Background color of a selected segment under the parent's [multiple] mode (no sliding indicator in that mode).
55
58
  a2ui:
59
+ allowedParents:
60
+ - Segmented
56
61
  rules:
57
- - rule: 'Child of <segmented-ui> — one selectable option button in a single-select group.'
62
+ - rule: 'Child of <segmented-ui> — one selectable option button; the parent''s [multiple] axis decides single- or multi-select, segment-ui itself is unchanged either way.'
58
63
  reason: 'Cluster contract.'
59
- - rule: 'Different from <toggle-option-ui> (which is multi-select inside <toggle-group-ui>).'
60
- reason: 'Single vs multi-select sibling distinction.'
61
- - rule: 'Selected state managed by parent <segmented-ui> via active attribute; do not set selected directly on segment.'
64
+ - rule: '<toggle-option-ui> (deprecated, gh#1369) is the same concept — use segment-ui inside <segmented-ui multiple> instead.'
65
+ reason: 'Deprecation redirect.'
66
+ - rule: 'Selected state managed by the parent <segmented-ui> it syncs the selected attribute onto every child whose value is in its own value (single value, or the [multiple] comma-separated set); do not set selected directly on segment.'
62
67
  reason: 'Parent owns selection state.'
63
68
  anti_patterns: []
64
69
  examples:
@@ -68,7 +73,7 @@ examples:
68
73
  [
69
74
  {
70
75
  "id": "root",
71
- "component": "SegmentedControl",
76
+ "component": "Segmented",
72
77
  "children": [
73
78
  "s1",
74
79
  "s2",
@@ -79,7 +84,7 @@ examples:
79
84
  "id": "s1",
80
85
  "component": "Segment",
81
86
  "text": "Overview",
82
- "active": true
87
+ "selected": true
83
88
  },
84
89
  {
85
90
  "id": "s2",
@@ -98,7 +103,7 @@ examples:
98
103
  [
99
104
  {
100
105
  "id": "root",
101
- "component": "SegmentedControl",
106
+ "component": "Segmented",
102
107
  "children": [
103
108
  "s1",
104
109
  "s2",
@@ -130,7 +135,7 @@ examples:
130
135
  [
131
136
  {
132
137
  "id": "root",
133
- "component": "SegmentedControl",
138
+ "component": "Segmented",
134
139
  "children": [
135
140
  "s1",
136
141
  "s2",
@@ -169,7 +174,7 @@ examples:
169
174
  [
170
175
  {
171
176
  "id": "root",
172
- "component": "SegmentedControl",
177
+ "component": "Segmented",
173
178
  "children": [
174
179
  "s1",
175
180
  "s2",
@@ -202,7 +207,7 @@ examples:
202
207
  [
203
208
  {
204
209
  "id": "root",
205
- "component": "SegmentedControl",
210
+ "component": "Segmented",
206
211
  "children": [
207
212
  "s1",
208
213
  "s2",
@@ -233,7 +238,9 @@ examples:
233
238
  ]
234
239
  keywords:
235
240
  - segment
241
+ - toggle-option
236
242
  synonyms:
237
- segment: [segment-button, segmented-option, option-button]
243
+ segment: [segment-button, segmented-option, option-button, toggle-option]
238
244
  related:
239
245
  - segmented-control
246
+ - ToggleOption
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://adiaui.dev/a2ui/v0_9/components/Segmented.json",
4
4
  "title": "Segmented",
5
- "description": "Single-select toggle group with an animated sliding indicator. Children must be segment-ui elements.",
5
+ "description": "Toggle group with an animated sliding indicator (single-select) or independently-toggleable segments (multi-select via [multiple]). Children must be segment-ui elements.",
6
6
  "type": "object",
7
7
  "allOf": [
8
8
  {
@@ -14,15 +14,20 @@
14
14
  ],
15
15
  "properties": {
16
16
  "allowEmpty": {
17
- "description": "Suppresses the connect-time self-select of the first enabled segment when value is falsy. Without it, an empty value silently selects the first segment; with it, a falsy value renders every segment unselected until a real value arrives — for path-bound consumers whose bound value can be a genuine empty state.",
17
+ "description": "Suppresses the connect-time self-select of the first enabled segment when value is falsy. Without it, an empty value silently selects the first segment; with it, a falsy value renders every segment unselected until a real value arrives — for path-bound consumers whose bound value can be a genuine empty state. No effect under [multiple] — multi-select never self-selects (empty value already means \"nothing chosen\").",
18
18
  "type": "boolean",
19
19
  "default": false
20
20
  },
21
21
  "component": {
22
22
  "const": "Segmented"
23
23
  },
24
+ "multiple": {
25
+ "description": "Enables multi-select — value becomes a comma-separated set, the sliding indicator is suppressed (each selected segment carries its own background instead), and Space/Enter toggles a focused segment instead of arrow-move selecting it. Positive polarity, matching select-ui[multiple]. Absorbs the role of the deprecated <toggle-group-ui> + <toggle-option-ui> pair (gh#1369, #1363 C1). Unlike <toggle-group-ui single>, re-clicking an already-selected segment does NOT clear the selection — segmented-ui's single-select is standard radiogroup semantics (always exactly one selected once a value is set).",
26
+ "type": "boolean",
27
+ "default": false
28
+ },
24
29
  "value": {
25
- "description": "Value of the currently selected segment.",
30
+ "description": "Value of the currently selected segment. Under [multiple], a comma-separated set of selected values (same encoding as select-ui[multiple]).",
26
31
  "type": "string",
27
32
  "default": ""
28
33
  }
@@ -32,6 +37,9 @@
32
37
  ],
33
38
  "unevaluatedProperties": false,
34
39
  "x-adiaui": {
40
+ "allowedChildren": [
41
+ "Segment"
42
+ ],
35
43
  "anti_patterns": [],
36
44
  "category": "navigation",
37
45
  "composes": [],
@@ -45,6 +53,11 @@
45
53
  "description": "Segmented control with three segment-ui children for view switching.",
46
54
  "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Card\",\n \"children\": [\n \"sec\"\n ]\n },\n {\n \"id\": \"sec\",\n \"component\": \"Section\",\n \"children\": [\n \"comp\"\n ]\n },\n {\n \"id\": \"comp\",\n \"component\": \"Segmented\",\n \"value\": \"daily\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"daily\",\n \"text\": \"Daily\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"weekly\",\n \"text\": \"Weekly\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"monthly\",\n \"text\": \"Monthly\"\n }\n]",
47
55
  "name": "basic-segmented"
56
+ },
57
+ {
58
+ "description": "Multi-select segmented control (gh#1369) for filter chips — [multiple] set, value is a comma-separated set of active segments.",
59
+ "a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Card\",\n \"children\": [\n \"sec\"\n ]\n },\n {\n \"id\": \"sec\",\n \"component\": \"Section\",\n \"children\": [\n \"comp\"\n ]\n },\n {\n \"id\": \"comp\",\n \"component\": \"Segmented\",\n \"multiple\": true,\n \"value\": \"bold,italic\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"bold\",\n \"text\": \"Bold\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"italic\",\n \"text\": \"Italic\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"underline\",\n \"text\": \"Underline\"\n }\n]",
60
+ "name": "multi-select-filter-chips"
48
61
  }
49
62
  ],
50
63
  "keywords": [
@@ -55,21 +68,27 @@
55
68
  "switch",
56
69
  "tab",
57
70
  "tabs",
58
- "button-group"
71
+ "button-group",
72
+ "filter",
73
+ "multi-select",
74
+ "filter-chips"
59
75
  ],
60
76
  "name": "UISegmented",
77
+ "parts": {
78
+ "indicator": {
79
+ "description": "Auto-created sliding indicator element prepended on first render — template-owned anatomy part, not a light-DOM insertion point (gh#1454). Lazily created once via an internal-field guard, never adopted from a consumer-authored element."
80
+ }
81
+ },
61
82
  "related": [
62
83
  "Segment",
63
84
  "ToggleGroup",
85
+ "ToggleOption",
64
86
  "Tabs",
65
87
  "Radio"
66
88
  ],
67
89
  "slots": {
68
90
  "default": {
69
91
  "description": "Child segment-ui elements that form the toggle group. Children MUST be segment-ui — bare segment tags render text but are silently ignored for the sliding indicator and role/aria-checked state."
70
- },
71
- "indicator": {
72
- "description": "Auto-created sliding indicator element prepended on first render."
73
92
  }
74
93
  },
75
94
  "states": [
@@ -85,6 +104,16 @@
85
104
  "button",
86
105
  "segmented"
87
106
  ],
107
+ "filter": [
108
+ "segmented",
109
+ "toggle-group",
110
+ "filter-chips"
111
+ ],
112
+ "multi-select": [
113
+ "segmented",
114
+ "toggle-group",
115
+ "select"
116
+ ],
88
117
  "options": [
89
118
  "settings",
90
119
  "radio",
@@ -18,8 +18,19 @@
18
18
  * <segment-ui value="tab3" text="Tab 3"></segment-ui>
19
19
  * </segmented-ui>
20
20
  *
21
- * Mutually exclusive toggle group with animated indicator pill.
22
- * Indicator uses CSS transform (GPU-accelerated).
21
+ * Mutually exclusive (single-select) toggle group with animated indicator
22
+ * pill. Indicator uses CSS transform (GPU-accelerated).
23
+ *
24
+ * <segmented-ui multiple value="bold,italic">
25
+ * <segment-ui value="bold" text="B"></segment-ui>
26
+ * <segment-ui value="italic" text="I"></segment-ui>
27
+ * </segmented-ui>
28
+ *
29
+ * [multiple] (gh#1369, #1363 C1): multi-select mode — `value` is a
30
+ * comma-separated set, no sliding indicator (each selected segment carries
31
+ * its own background instead), Space/Enter toggles instead of arrow-move.
32
+ * Absorbs <toggle-group-ui>/<toggle-option-ui>'s role, which are deprecated
33
+ * in favor of this axis.
23
34
  */
24
35
 
25
36
  import { UIFormElement } from '../../core/form.js';
@@ -28,6 +39,13 @@ import '../segment/segment.js';
28
39
  export class UISegmented extends UIFormElement {
29
40
  static properties = {
30
41
  ...UIFormElement.properties,
42
+ // gh#1369 (#1363 C1): multi-select axis, positive polarity matching
43
+ // <select-ui multiple> — not toggle-group's inverted `single`. Under
44
+ // [multiple], `value` becomes a comma-separated set (same encoding
45
+ // toggle-group-ui and select-ui[multiple] already use); the sliding
46
+ // indicator is suppressed and each selected segment carries its own
47
+ // background instead (segment.css).
48
+ multiple: { type: Boolean, default: false, reflect: true },
31
49
  value: { type: String, default: '', reflect: true },
32
50
  // gh#693: absent (default false) preserves the original self-select
33
51
  // behavior below. A path-bound consumer whose bound value can be a
@@ -55,7 +73,7 @@ export class UISegmented extends UIFormElement {
55
73
 
56
74
  connected() {
57
75
  super.connected();
58
- this.setAttribute('role', 'radiogroup');
76
+ this.setAttribute('role', this.multiple ? 'group' : 'radiogroup');
59
77
 
60
78
  if (!this.#bound) {
61
79
  this.#bound = true;
@@ -65,8 +83,10 @@ export class UISegmented extends UIFormElement {
65
83
 
66
84
  // Default to first segment if no value — unless allow-empty opts out
67
85
  // (a falsy path-bound value must render as truly empty, not silently
68
- // pick one, gh#693).
69
- if (!this.value && !this.allowEmpty) {
86
+ // pick one, gh#693). Multi-select never self-selects: an empty
87
+ // [multiple] value legitimately means "nothing chosen yet", the same
88
+ // default toggle-group-ui always had.
89
+ if (!this.multiple && !this.value && !this.allowEmpty) {
70
90
  const first = this.querySelector('segment-ui:not([disabled])');
71
91
  if (first) this.value = first.value || first.getAttribute('value') || '';
72
92
  }
@@ -112,7 +132,19 @@ export class UISegmented extends UIFormElement {
112
132
  return this.#segments.filter(s => !s.disabled);
113
133
  }
114
134
 
135
+ // [multiple] value encoding — comma-separated, matching toggle-group-ui
136
+ // and select-ui[multiple] (gh#1369).
137
+ get #valueSet() {
138
+ return new Set(this.value ? this.value.split(',').map(v => v.trim()).filter(Boolean) : []);
139
+ }
140
+
115
141
  render() {
142
+ // gh#1369 review: connected() only sets the host role ONCE — if
143
+ // `multiple` flips after connect, that one-shot value goes stale while
144
+ // children's roles (below) already update reactively every render.
145
+ // Keep the host role synchronized here too, every render.
146
+ this.setAttribute('role', this.multiple ? 'group' : 'radiogroup');
147
+
116
148
  // FEEDBACK-23: flag a non-<segment-ui> direct child once per element.
117
149
  // Runs before the empty-guard so an all-bare-<segment> group still warns.
118
150
  if (!UISegmented.#warnedNonSegment.has(this)) {
@@ -137,11 +169,14 @@ export class UISegmented extends UIFormElement {
137
169
  const segs = this.#segments;
138
170
  if (!segs.length) return;
139
171
 
140
- // Sync selection state
172
+ // Sync selection state — [multiple] checks Set membership (comma-
173
+ // separated value), single-select checks direct string equality.
174
+ const selectedSet = this.multiple ? this.#valueSet : null;
141
175
  let anyActive = false;
142
176
  for (const seg of segs) {
143
177
  const segVal = seg.value || seg.getAttribute('value') || '';
144
- const isActive = segVal === this.value;
178
+ const isActive = this.multiple ? selectedSet.has(segVal) : segVal === this.value;
179
+ seg.setAttribute('role', this.multiple ? 'checkbox' : 'radio');
145
180
  if (isActive) {
146
181
  seg.setAttribute('selected', '');
147
182
  anyActive = true;
@@ -152,6 +187,8 @@ export class UISegmented extends UIFormElement {
152
187
  }
153
188
  // allow-empty's "nothing selected" state must still be keyboard
154
189
  // reachable — mirrors list-ui's roving-tabindex fallback (list.class.js).
190
+ // [multiple] can legitimately have nothing selected at all times, same
191
+ // fallback applies.
155
192
  if (!anyActive) {
156
193
  const firstEnabled = segs.find((s) => !s.disabled);
157
194
  firstEnabled?.setAttribute('tabindex', '0');
@@ -159,10 +196,33 @@ export class UISegmented extends UIFormElement {
159
196
 
160
197
  if (this.label) this.setAttribute('aria-label', this.label);
161
198
 
199
+ // Sliding indicator is a single-select-only affordance — exactly one
200
+ // pill can slide to exactly one position. [multiple] relies on each
201
+ // segment's own [selected] background instead (segment.css).
202
+ // #updateIndicator itself guards on `this.multiple` (gh#1369 review) —
203
+ // call it unconditionally so this is the one call site, same as every
204
+ // other caller (ResizeObserver, document.fonts.ready).
162
205
  this.#updateIndicator(segs);
163
206
  }
164
207
 
165
208
  #updateIndicator(segs) {
209
+ // gh#1369 review: render() only skips this call in [multiple] mode —
210
+ // the ResizeObserver (connected()) and document.fonts.ready callbacks
211
+ // call #updateIndicator directly and asynchronously, bypassing that
212
+ // guard entirely. Without a guard HERE, a multiple-mode instance with
213
+ // exactly one segment selected (this.value has no comma, so it can
214
+ // exactly match a segment's own value) can grow a spurious sliding
215
+ // indicator after a late resize or font-load event. Guard the method
216
+ // itself so every call site — sync or async — is covered.
217
+ if (this.multiple) {
218
+ for (const stale of this.querySelectorAll(':scope > [data-indicator]')) {
219
+ stale.remove();
220
+ }
221
+ this.#indicator = null;
222
+ this.removeAttribute('data-indicator-ready');
223
+ return;
224
+ }
225
+
166
226
  const selectedIdx = segs.findIndex(s => (s.value || s.getAttribute('value') || '') === this.value);
167
227
 
168
228
  if (selectedIdx < 0) {
@@ -205,7 +265,18 @@ export class UISegmented extends UIFormElement {
205
265
 
206
266
  #select(seg) {
207
267
  if (seg.disabled) return;
208
- this.value = seg.value;
268
+ const segVal = seg.value || seg.getAttribute('value') || '';
269
+
270
+ if (this.multiple) {
271
+ if (!segVal) return;
272
+ const selected = this.#valueSet;
273
+ if (selected.has(segVal)) selected.delete(segVal);
274
+ else selected.add(segVal);
275
+ this.value = [...selected].join(',');
276
+ } else {
277
+ this.value = segVal;
278
+ }
279
+
209
280
  this.syncValue();
210
281
  this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
211
282
  }
@@ -215,26 +286,46 @@ export class UISegmented extends UIFormElement {
215
286
  if (seg && this.contains(seg)) this.#select(seg);
216
287
  };
217
288
 
289
+ // Shared roving-focus navigation — Home/End/Arrow keys move focus among
290
+ // enabled segments. Selection semantics diverge below: single-select is
291
+ // a radiogroup (arrow-move selects, native radio behavior); [multiple]
292
+ // is a checkbox toolbar (arrow-move only focuses, Space/Enter toggles).
293
+ #nextFocusTarget(current, key) {
294
+ const segs = this.#enabledSegments;
295
+ const idx = segs.indexOf(current);
296
+ if (idx < 0) return null; // current isn't an enabled segment — nothing to do
297
+ switch (key) {
298
+ case 'ArrowRight': case 'ArrowDown':
299
+ return segs[idx < segs.length - 1 ? idx + 1 : 0];
300
+ case 'ArrowLeft': case 'ArrowUp':
301
+ return segs[idx > 0 ? idx - 1 : segs.length - 1];
302
+ case 'Home': return segs[0];
303
+ case 'End': return segs[segs.length - 1];
304
+ default: return null; // key not handled
305
+ }
306
+ }
307
+
218
308
  #handleKeydown = (e) => {
219
309
  const target = e.target;
220
310
  if (target.tagName !== 'SEGMENT-UI') return;
221
- const segs = this.#enabledSegments;
222
- const idx = segs.indexOf(target);
223
- if (idx < 0) return;
224
311
 
225
- let next;
226
- switch (e.key) {
227
- case 'ArrowRight': case 'ArrowDown':
228
- next = idx < segs.length - 1 ? idx + 1 : 0; break;
229
- case 'ArrowLeft': case 'ArrowUp':
230
- next = idx > 0 ? idx - 1 : segs.length - 1; break;
231
- case 'Home': next = 0; break;
232
- case 'End': next = segs.length - 1; break;
233
- default: return;
312
+ if (this.multiple) {
313
+ if (e.key === 'Enter' || e.key === ' ') {
314
+ e.preventDefault();
315
+ this.#select(target);
316
+ return;
317
+ }
318
+ const next = this.#nextFocusTarget(target, e.key);
319
+ if (!next) return;
320
+ e.preventDefault();
321
+ next.focus();
322
+ return;
234
323
  }
235
324
 
325
+ const next = this.#nextFocusTarget(target, e.key);
326
+ if (!next) return;
236
327
  e.preventDefault();
237
- segs[next].focus();
238
- this.#select(segs[next]);
328
+ next.focus();
329
+ this.#select(next);
239
330
  };
240
331
  }
@@ -68,6 +68,9 @@
68
68
  display: none;
69
69
  }
70
70
 
71
+ /* [multiple] never sets data-indicator-ready (segmented.class.js render())
72
+ — the indicator span is never created/prepended in multi-select mode,
73
+ so it stays display:none via the rule above. */
71
74
  :scope[data-indicator-ready] > [data-indicator] {
72
75
  display: block;
73
76
  position: absolute;
@@ -12,8 +12,10 @@ export interface SegmentedChangeEventDetail<V extends string = string> {
12
12
  export type SegmentedChangeEvent<V extends string = string> = CustomEvent<SegmentedChangeEventDetail<V>>;
13
13
 
14
14
  export class UISegmented extends UIFormElement {
15
- /** Selected segment's value. */
15
+ /** Selected segment's value. Under `multiple`, a comma-separated set. */
16
16
  value: string;
17
+ /** Enables multi-select — comma-separated `value`, no sliding indicator, Space/Enter toggles (gh#1369). */
18
+ multiple: boolean;
17
19
 
18
20
  addEventListener<K extends keyof HTMLElementEventMap>(
19
21
  type: K,