@agent-ui-kit/components 0.0.3

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 (271) hide show
  1. package/dist/base-styles.css +8 -0
  2. package/dist/component-styles.css +147 -0
  3. package/dist/controls/_base/index.d.ts +3 -0
  4. package/dist/controls/_base/index.js +9 -0
  5. package/dist/controls/_base/indicator-element.d.ts +132 -0
  6. package/dist/controls/_base/indicator-element.js +158 -0
  7. package/dist/controls/_base/listbox-element.d.ts +70 -0
  8. package/dist/controls/_base/listbox-element.js +74 -0
  9. package/dist/controls/_base/range-element.d.ts +120 -0
  10. package/dist/controls/_base/range-element.js +158 -0
  11. package/dist/controls/_surface/container-box.css +301 -0
  12. package/dist/controls/_surface/container.css +156 -0
  13. package/dist/controls/_token-surface/token-surface.d.ts +35 -0
  14. package/dist/controls/_token-surface/token-surface.js +97 -0
  15. package/dist/controls/attachment/attachment-meta.d.ts +8 -0
  16. package/dist/controls/attachment/attachment-meta.js +84 -0
  17. package/dist/controls/attachment/attachment.css +91 -0
  18. package/dist/controls/attachment/attachment.d.ts +40 -0
  19. package/dist/controls/attachment/attachment.js +70 -0
  20. package/dist/controls/avatar/avatar-initials.d.ts +4 -0
  21. package/dist/controls/avatar/avatar-initials.js +30 -0
  22. package/dist/controls/avatar/avatar.css +87 -0
  23. package/dist/controls/avatar/avatar.d.ts +40 -0
  24. package/dist/controls/avatar/avatar.js +77 -0
  25. package/dist/controls/badge/badge.css +175 -0
  26. package/dist/controls/badge/badge.d.ts +36 -0
  27. package/dist/controls/badge/badge.js +71 -0
  28. package/dist/controls/bar-chart/bar-chart.css +110 -0
  29. package/dist/controls/bar-chart/bar-chart.d.ts +26 -0
  30. package/dist/controls/bar-chart/bar-chart.js +80 -0
  31. package/dist/controls/bar-chart/bar-math.d.ts +31 -0
  32. package/dist/controls/bar-chart/bar-math.js +106 -0
  33. package/dist/controls/button/button.css +263 -0
  34. package/dist/controls/button/button.d.ts +61 -0
  35. package/dist/controls/button/button.js +115 -0
  36. package/dist/controls/calendar/calendar.css +495 -0
  37. package/dist/controls/calendar/calendar.d.ts +161 -0
  38. package/dist/controls/calendar/calendar.js +1004 -0
  39. package/dist/controls/card/card-content.d.ts +24 -0
  40. package/dist/controls/card/card-content.js +133 -0
  41. package/dist/controls/card/card-footer.d.ts +3 -0
  42. package/dist/controls/card/card-footer.js +16 -0
  43. package/dist/controls/card/card-header.d.ts +3 -0
  44. package/dist/controls/card/card-header.js +18 -0
  45. package/dist/controls/card/card.css +445 -0
  46. package/dist/controls/card/card.d.ts +51 -0
  47. package/dist/controls/card/card.js +61 -0
  48. package/dist/controls/checkbox/checkbox.css +204 -0
  49. package/dist/controls/checkbox/checkbox.d.ts +114 -0
  50. package/dist/controls/checkbox/checkbox.js +130 -0
  51. package/dist/controls/code/code.css +72 -0
  52. package/dist/controls/code/code.d.ts +23 -0
  53. package/dist/controls/code/code.js +40 -0
  54. package/dist/controls/color-picker/color-picker.css +209 -0
  55. package/dist/controls/color-picker/color-picker.d.ts +84 -0
  56. package/dist/controls/color-picker/color-picker.js +545 -0
  57. package/dist/controls/color-picker/color.d.ts +40 -0
  58. package/dist/controls/color-picker/color.js +159 -0
  59. package/dist/controls/column/column.css +151 -0
  60. package/dist/controls/column/column.d.ts +107 -0
  61. package/dist/controls/column/column.js +57 -0
  62. package/dist/controls/combo-box/combo-box.css +397 -0
  63. package/dist/controls/combo-box/combo-box.d.ts +133 -0
  64. package/dist/controls/combo-box/combo-box.js +680 -0
  65. package/dist/controls/command-modal/command-modal.css +226 -0
  66. package/dist/controls/command-modal/command-modal.d.ts +42 -0
  67. package/dist/controls/command-modal/command-modal.js +315 -0
  68. package/dist/controls/disclosure/disclosure.css +162 -0
  69. package/dist/controls/disclosure/disclosure.d.ts +37 -0
  70. package/dist/controls/disclosure/disclosure.js +207 -0
  71. package/dist/controls/field/field.css +140 -0
  72. package/dist/controls/field/field.d.ts +27 -0
  73. package/dist/controls/field/field.js +228 -0
  74. package/dist/controls/form-provider/form-provider.css +40 -0
  75. package/dist/controls/form-provider/form-provider.d.ts +42 -0
  76. package/dist/controls/form-provider/form-provider.js +105 -0
  77. package/dist/controls/grid/grid.css +72 -0
  78. package/dist/controls/grid/grid.d.ts +60 -0
  79. package/dist/controls/grid/grid.js +56 -0
  80. package/dist/controls/icon/icon.css +37 -0
  81. package/dist/controls/icon/icon.d.ts +25 -0
  82. package/dist/controls/icon/icon.js +55 -0
  83. package/dist/controls/index.d.ts +57 -0
  84. package/dist/controls/index.js +136 -0
  85. package/dist/controls/ladder/ladder.css +89 -0
  86. package/dist/controls/ladder/ladder.d.ts +27 -0
  87. package/dist/controls/ladder/ladder.js +78 -0
  88. package/dist/controls/list/list.css +118 -0
  89. package/dist/controls/list/list.d.ts +84 -0
  90. package/dist/controls/list/list.js +48 -0
  91. package/dist/controls/menu/menu.css +195 -0
  92. package/dist/controls/menu/menu.d.ts +44 -0
  93. package/dist/controls/menu/menu.js +248 -0
  94. package/dist/controls/modal/modal.css +99 -0
  95. package/dist/controls/modal/modal.d.ts +61 -0
  96. package/dist/controls/modal/modal.js +155 -0
  97. package/dist/controls/popover/popover.css +83 -0
  98. package/dist/controls/popover/popover.d.ts +44 -0
  99. package/dist/controls/popover/popover.js +164 -0
  100. package/dist/controls/progress/progress.css +106 -0
  101. package/dist/controls/progress/progress.d.ts +28 -0
  102. package/dist/controls/progress/progress.js +80 -0
  103. package/dist/controls/radio/radio-group.css +84 -0
  104. package/dist/controls/radio/radio-group.d.ts +152 -0
  105. package/dist/controls/radio/radio-group.js +350 -0
  106. package/dist/controls/radio/radio.css +219 -0
  107. package/dist/controls/radio/radio.d.ts +19 -0
  108. package/dist/controls/radio/radio.js +75 -0
  109. package/dist/controls/ramp/ramp.css +75 -0
  110. package/dist/controls/ramp/ramp.d.ts +29 -0
  111. package/dist/controls/ramp/ramp.js +72 -0
  112. package/dist/controls/row/row.css +152 -0
  113. package/dist/controls/row/row.d.ts +95 -0
  114. package/dist/controls/row/row.js +45 -0
  115. package/dist/controls/segment/segment.css +66 -0
  116. package/dist/controls/segment/segment.d.ts +3 -0
  117. package/dist/controls/segment/segment.js +26 -0
  118. package/dist/controls/segmented-control/segmented-control.css +189 -0
  119. package/dist/controls/segmented-control/segmented-control.d.ts +20 -0
  120. package/dist/controls/segmented-control/segmented-control.js +64 -0
  121. package/dist/controls/select/select.css +467 -0
  122. package/dist/controls/select/select.d.ts +147 -0
  123. package/dist/controls/select/select.js +538 -0
  124. package/dist/controls/slider/slider.css +231 -0
  125. package/dist/controls/slider/slider.d.ts +111 -0
  126. package/dist/controls/slider/slider.js +60 -0
  127. package/dist/controls/slider-multi/slider-multi.css +197 -0
  128. package/dist/controls/slider-multi/slider-multi.d.ts +149 -0
  129. package/dist/controls/slider-multi/slider-multi.js +380 -0
  130. package/dist/controls/sparkline/sparkline-math.d.ts +23 -0
  131. package/dist/controls/sparkline/sparkline-math.js +79 -0
  132. package/dist/controls/sparkline/sparkline.css +61 -0
  133. package/dist/controls/sparkline/sparkline.d.ts +27 -0
  134. package/dist/controls/sparkline/sparkline.js +74 -0
  135. package/dist/controls/split/constrain.d.ts +44 -0
  136. package/dist/controls/split/constrain.js +126 -0
  137. package/dist/controls/split/split-pane.css +63 -0
  138. package/dist/controls/split/split-pane.d.ts +49 -0
  139. package/dist/controls/split/split-pane.js +42 -0
  140. package/dist/controls/split/split.css +127 -0
  141. package/dist/controls/split/split.d.ts +42 -0
  142. package/dist/controls/split/split.js +364 -0
  143. package/dist/controls/stat/stat-model.d.ts +22 -0
  144. package/dist/controls/stat/stat-model.js +69 -0
  145. package/dist/controls/stat/stat.css +101 -0
  146. package/dist/controls/stat/stat.d.ts +30 -0
  147. package/dist/controls/stat/stat.js +73 -0
  148. package/dist/controls/status-stream/status-stream.css +151 -0
  149. package/dist/controls/status-stream/status-stream.d.ts +108 -0
  150. package/dist/controls/status-stream/status-stream.js +417 -0
  151. package/dist/controls/swatch/swatch.css +66 -0
  152. package/dist/controls/swatch/swatch.d.ts +28 -0
  153. package/dist/controls/swatch/swatch.js +74 -0
  154. package/dist/controls/swiper/swiper-item.css +17 -0
  155. package/dist/controls/swiper/swiper-item.d.ts +31 -0
  156. package/dist/controls/swiper/swiper-item.js +47 -0
  157. package/dist/controls/swiper/swiper-label.css +10 -0
  158. package/dist/controls/swiper/swiper-label.d.ts +4 -0
  159. package/dist/controls/swiper/swiper-label.js +20 -0
  160. package/dist/controls/swiper/swiper-paddles.css +26 -0
  161. package/dist/controls/swiper/swiper-paddles.d.ts +10 -0
  162. package/dist/controls/swiper/swiper-paddles.js +62 -0
  163. package/dist/controls/swiper/swiper-pagination.css +60 -0
  164. package/dist/controls/swiper/swiper-pagination.d.ts +31 -0
  165. package/dist/controls/swiper/swiper-pagination.js +78 -0
  166. package/dist/controls/swiper/swiper.css +153 -0
  167. package/dist/controls/swiper/swiper.d.ts +158 -0
  168. package/dist/controls/swiper/swiper.js +659 -0
  169. package/dist/controls/switch/switch.css +194 -0
  170. package/dist/controls/switch/switch.d.ts +5 -0
  171. package/dist/controls/switch/switch.js +18 -0
  172. package/dist/controls/table/table-model.d.ts +43 -0
  173. package/dist/controls/table/table-model.js +124 -0
  174. package/dist/controls/table/table.css +90 -0
  175. package/dist/controls/table/table.d.ts +29 -0
  176. package/dist/controls/table/table.js +178 -0
  177. package/dist/controls/tabs/tab-panel.d.ts +10 -0
  178. package/dist/controls/tabs/tab-panel.js +89 -0
  179. package/dist/controls/tabs/tab.d.ts +26 -0
  180. package/dist/controls/tabs/tab.js +67 -0
  181. package/dist/controls/tabs/tabs.css +181 -0
  182. package/dist/controls/tabs/tabs.d.ts +61 -0
  183. package/dist/controls/tabs/tabs.js +176 -0
  184. package/dist/controls/text/href.d.ts +26 -0
  185. package/dist/controls/text/href.js +48 -0
  186. package/dist/controls/text/text.css +328 -0
  187. package/dist/controls/text/text.d.ts +85 -0
  188. package/dist/controls/text/text.js +273 -0
  189. package/dist/controls/text-field/text-field.css +498 -0
  190. package/dist/controls/text-field/text-field.d.ts +226 -0
  191. package/dist/controls/text-field/text-field.js +905 -0
  192. package/dist/controls/textarea/textarea.css +251 -0
  193. package/dist/controls/textarea/textarea.d.ts +136 -0
  194. package/dist/controls/textarea/textarea.js +312 -0
  195. package/dist/controls/theme-provider/theme-provider.css +48 -0
  196. package/dist/controls/theme-provider/theme-provider.d.ts +59 -0
  197. package/dist/controls/theme-provider/theme-provider.js +40 -0
  198. package/dist/controls/timeline/timeline.css +33 -0
  199. package/dist/controls/timeline/timeline.d.ts +39 -0
  200. package/dist/controls/timeline/timeline.js +52 -0
  201. package/dist/controls/timeline-item/timeline-item.css +495 -0
  202. package/dist/controls/timeline-item/timeline-item.d.ts +79 -0
  203. package/dist/controls/timeline-item/timeline-item.js +360 -0
  204. package/dist/controls/toast/toast-region.css +56 -0
  205. package/dist/controls/toast/toast-region.d.ts +20 -0
  206. package/dist/controls/toast/toast-region.js +113 -0
  207. package/dist/controls/toast/toast.css +96 -0
  208. package/dist/controls/toast/toast.d.ts +28 -0
  209. package/dist/controls/toast/toast.js +191 -0
  210. package/dist/controls/toolbar/toolbar.css +125 -0
  211. package/dist/controls/toolbar/toolbar.d.ts +108 -0
  212. package/dist/controls/toolbar/toolbar.js +68 -0
  213. package/dist/controls/tooltip/tooltip.css +80 -0
  214. package/dist/controls/tooltip/tooltip.d.ts +57 -0
  215. package/dist/controls/tooltip/tooltip.js +205 -0
  216. package/dist/descriptor/component-descriptor.d.ts +112 -0
  217. package/dist/descriptor/component-descriptor.js +492 -0
  218. package/dist/descriptor/index.d.ts +1 -0
  219. package/dist/descriptor/index.js +5 -0
  220. package/dist/dom/container.d.ts +45 -0
  221. package/dist/dom/container.js +60 -0
  222. package/dist/dom/element.d.ts +98 -0
  223. package/dist/dom/element.js +221 -0
  224. package/dist/dom/form.d.ts +240 -0
  225. package/dist/dom/form.js +399 -0
  226. package/dist/dom/index.d.ts +10 -0
  227. package/dist/dom/index.js +31 -0
  228. package/dist/dom/props.d.ts +56 -0
  229. package/dist/dom/props.js +231 -0
  230. package/dist/dom/repeat.d.ts +10 -0
  231. package/dist/dom/repeat.js +202 -0
  232. package/dist/dom/template.d.ts +161 -0
  233. package/dist/dom/template.js +634 -0
  234. package/dist/dom/watch.d.ts +11 -0
  235. package/dist/dom/watch.js +82 -0
  236. package/dist/foundation-styles.css +9 -0
  237. package/dist/index.d.ts +2 -0
  238. package/dist/index.js +3 -0
  239. package/dist/reactive/graph.d.ts +65 -0
  240. package/dist/reactive/graph.js +310 -0
  241. package/dist/reactive/index.d.ts +3 -0
  242. package/dist/reactive/index.js +4 -0
  243. package/dist/reactive/scheduler.d.ts +13 -0
  244. package/dist/reactive/scheduler.js +49 -0
  245. package/dist/traits/area-drag.d.ts +12 -0
  246. package/dist/traits/area-drag.js +70 -0
  247. package/dist/traits/form-registry.d.ts +36 -0
  248. package/dist/traits/form-registry.js +108 -0
  249. package/dist/traits/index.d.ts +24 -0
  250. package/dist/traits/index.js +19 -0
  251. package/dist/traits/overlay.d.ts +50 -0
  252. package/dist/traits/overlay.js +277 -0
  253. package/dist/traits/pane-resize.d.ts +26 -0
  254. package/dist/traits/pane-resize.js +103 -0
  255. package/dist/traits/press-activation.d.ts +11 -0
  256. package/dist/traits/press-activation.js +55 -0
  257. package/dist/traits/roving-focus.d.ts +52 -0
  258. package/dist/traits/roving-focus.js +214 -0
  259. package/dist/traits/scroll-fade.d.ts +28 -0
  260. package/dist/traits/scroll-fade.js +120 -0
  261. package/dist/traits/selection-commit.d.ts +30 -0
  262. package/dist/traits/selection-commit.js +146 -0
  263. package/dist/traits/tabbable.d.ts +12 -0
  264. package/dist/traits/tabbable.js +59 -0
  265. package/dist/traits/track-user-invalid.d.ts +36 -0
  266. package/dist/traits/track-user-invalid.js +52 -0
  267. package/dist/traits/value-codec.d.ts +120 -0
  268. package/dist/traits/value-codec.js +497 -0
  269. package/dist/traits/value-drag.d.ts +18 -0
  270. package/dist/traits/value-drag.js +84 -0
  271. package/package.json +263 -0
@@ -0,0 +1,189 @@
1
+ /* segmented-control.css — ui-segmented-control, the joined-button single-select control stylesheet.
2
+ *
3
+ * ADR-0095 (authored from ADR-0092 §Alternatives-1; supersedes ADR-0086's `ui-radio-group[variant=
4
+ * 'segmented']` — a hard cutover, no alias). Every computed value ADR-0086's Acceptance enumerated carries
5
+ * over UNCHANGED, re-keyed onto the new tag/tokens: equal 1fr cells, `100%/count` indicator sizing,
6
+ * `transform`-only placement, `--md-sys-motion-duration-fast` + reduced-motion jump, the Control-height ramp with `h/2`
7
+ * inline pad and `line-height:1`, hover/active washes, `Highlight`/`HighlightText` forced-colors inversion.
8
+ * Since "segmented" IS this control's whole identity (not a variant gate), every selector below is
9
+ * UNCONDITIONAL — no `[variant='segmented']` qualifier anywhere (the ADR-0086 architecture's one CSS
10
+ * simplification: the tag itself is now the gate).
11
+ *
12
+ * Two sectioned blocks (ADR-0003):
13
+ * [1] TOKEN BLOCK — `:where(ui-segmented-control)` declares `--ui-segmented-control-*` (sole declarer,
14
+ * the family-coherence naming law) from the Pattern-class Control-height ramp + colour roles.
15
+ * [2] STYLES BLOCK — plain (non-`:where`) compound selectors — `ui-segmented-control` /
16
+ * `ui-segmented-control ui-segment` — deliberately OUTSIDE `@scope`, so their specificity
17
+ * ((0,1,0) / (0,1,1) / (0,1,2) for the `::before` pseudo-element forms) cleanly clears `ui-segment`'s
18
+ * own `@scope (ui-segment) { :scope … }` rules ((0,1,0) / (0,1,1)) without `!important` (the ADR-0086
19
+ * clause 2 mechanism, ported verbatim).
20
+ *
21
+ * Standalone stylesheet — linked via the component-styles barrel; NEVER injected from segmented-control.ts
22
+ * (behaviour-only `.ts`, no runtime style injection — plan §2). The `--ui-segmented-control-index`/`-count`
23
+ * custom properties consumed below are the ONE exception: reactive STATE written by segmented-control.ts
24
+ * (the `--value-pct` seam, range-element.ts:111), not injected style RULES.
25
+ */
26
+
27
+ /* ════════════ [1] TOKEN BLOCK — :where(ui-segmented-control) (specificity 0,0,0) ════════════ */
28
+
29
+ :where(ui-segmented-control) {
30
+ /* Geometry — the Pattern-class CONTROL-height ramp (geometry.md's `segmented-control` example,
31
+ geometry.md:133), NOT the Indicator's compact/widget ramp (ADR-0041, unused here). v1 ships the single
32
+ `md` register; an ancestor [scale] re-tables the row for free (ADR-0038). */
33
+ --ui-segmented-control-segment-height: var(--md-sys-height-md);
34
+ --ui-segmented-control-segment-font: var(--md-sys-font-md);
35
+
36
+ /* The outer rounded track (segments carry NO divider borders — Kim's ruling, see the styles block). */
37
+ --ui-segmented-control-track: var(--md-sys-color-neutral-outline);
38
+ --ui-segmented-control-radius: var(--md-sys-shape-corner-base);
39
+
40
+ /* The shared moving indicator's fill — the AA-safe accent role minted for the calendar (ADR-0048/0058),
41
+ reused here as the strongest fill-presence non-color signal (ADR-0057). */
42
+ --ui-segmented-control-fill: var(--md-sys-color-primary-selected);
43
+
44
+ /* Ink — selected (on the moving fill) vs unselected (text-channel neutral). */
45
+ --ui-segmented-control-ink-selected: var(--md-sys-color-primary-on-primary);
46
+ --ui-segmented-control-ink: var(--md-sys-color-neutral-on-surface-variant);
47
+
48
+ /* Unselected interaction washes — the text-channel hover/active ladder; the selected segment never reads
49
+ these (its fill is the stable moving indicator, not a hover affordance). */
50
+ --ui-segmented-control-bg-hover: var(--md-sys-color-primary-container-low);
51
+ --ui-segmented-control-bg-active: var(--md-sys-color-primary-container);
52
+
53
+ /* user-invalid (ADR-0051, inherited unchanged from UIRadioGroupElement — see segmented-control.ts's
54
+ header) — the danger track-border repoint. Appears only AFTER the first interaction (the
55
+ trackUserInvalid controller owns that timing; radio-group.ts's connected() toggles
56
+ :state(user-invalid) on this control's own internals). */
57
+ --ui-segmented-control-border-invalid: var(--md-sys-color-danger);
58
+ }
59
+
60
+ /* ═══════════ [2] STYLES — plain compound selectors (deliberately NOT :where/@scope) ═══════════ */
61
+
62
+ /* The track — display:grid, equal cells, orientation-driven main axis. `position:relative` hosts the
63
+ shared `::before` indicator; NO `overflow:hidden` (would clip the focus ring). */
64
+ ui-segmented-control {
65
+ display: grid;
66
+ position: relative;
67
+ box-sizing: border-box;
68
+ border: 1px solid var(--ui-segmented-control-track);
69
+ border-radius: var(--ui-segmented-control-radius);
70
+ }
71
+
72
+ /* user-invalid (ADR-0051) — the danger border, appearing only AFTER the first interaction. Unlike
73
+ ui-radio-group (no visual surface of its own), this control owns its own track border directly. */
74
+ ui-segmented-control:state(user-invalid) {
75
+ border-color: var(--ui-segmented-control-border-invalid);
76
+ }
77
+
78
+ /* Orientation-driven main axis. `repeat(var(--count), 1fr)` is NOT usable — repeat()'s count must be a
79
+ literal integer — so the count-agnostic auto-flow / auto-track mechanism is the grounded path. */
80
+ ui-segmented-control[orientation='horizontal'] {
81
+ grid-auto-flow: column;
82
+ grid-auto-columns: 1fr;
83
+ }
84
+ ui-segmented-control[orientation='vertical'] {
85
+ grid-auto-rows: 1fr;
86
+ }
87
+
88
+ /* The shared moving indicator — ONE artifact (the host's own `::before`), never a per-segment background.
89
+ Sized to one cell via `--ui-segmented-control-count`; POSITIONED via `transform` (never grid-track
90
+ placement — grid-column/row snap, transform animates). Hidden until a selection exists. */
91
+ ui-segmented-control::before {
92
+ content: '';
93
+ position: absolute;
94
+ z-index: 0; /* behind the segment text + focus ring (z-index:1 below) */
95
+ inset-block-start: 0;
96
+ inset-inline-start: 0;
97
+ background: var(--ui-segmented-control-fill);
98
+ border-radius: calc(var(--ui-segmented-control-radius) - 1px); /* the inner radius; ends align to the track */
99
+ transition: transform var(--md-sys-motion-duration-fast) var(--md-sys-motion-easing-standard); /* consumed, not hardcoded */
100
+ }
101
+ @media (prefers-reduced-motion: reduce) {
102
+ ui-segmented-control::before {
103
+ transition: none; /* the indicator jumps instead of sliding */
104
+ }
105
+ }
106
+ ui-segmented-control[orientation='horizontal']::before {
107
+ inline-size: calc(100% / var(--ui-segmented-control-count, 1));
108
+ block-size: 100%;
109
+ transform: translateX(calc(var(--ui-segmented-control-index, 0) * 100%));
110
+ }
111
+ ui-segmented-control[orientation='vertical']::before {
112
+ inline-size: 100%;
113
+ block-size: calc(100% / var(--ui-segmented-control-count, 1));
114
+ transform: translateY(calc(var(--ui-segmented-control-index, 0) * 100%));
115
+ }
116
+ /* No segment checked → hide the indicator entirely (it appears instantly on the first selection and only
117
+ slides between subsequent ones). */
118
+ ui-segmented-control:not(:has(ui-segment[checked]))::before {
119
+ opacity: 0;
120
+ }
121
+
122
+ /* Each `ui-segment` becomes a centered, full-cell segment button (its own base layout — display:inline-flex/
123
+ centering/cursor — lives in segment.css; this compound selector adds the GROUP-owned sizing). `z-index:1`
124
+ (+ the host's own `position:relative` stacking context) keeps the label + focus ring painting ABOVE the
125
+ moving indicator. */
126
+ ui-segmented-control ui-segment {
127
+ position: relative;
128
+ z-index: 1;
129
+ box-sizing: border-box;
130
+
131
+ block-size: var(--ui-segmented-control-segment-height); /* Control-height ramp */
132
+ padding-block: 0; /* block-size is the vertical lever */
133
+ padding-inline: calc(var(--ui-segmented-control-segment-height) / 2); /* slotless-edge pad, geometry.md */
134
+ font-size: var(--ui-segmented-control-segment-font);
135
+ line-height: var(--md-sys-control-line-height); /* single-line control standard, ADR-0036 */
136
+ color: var(--ui-segmented-control-ink);
137
+ }
138
+
139
+ /* NO inter-segment dividers — Kim's ruling (2026-07-09): the outer track + the moving fill + the hover
140
+ washes already carry the segmentation; vertical divider lines between segments are visual noise. The
141
+ original collapsed-divider rules (a shared 1px border-inline/block-start per non-first segment) were
142
+ removed here; segments carry NO borders of their own, and a regression guard in
143
+ segmented-control.browser.test.ts pins the zero-divider rendering in both orientations. */
144
+
145
+ /* Selected ink — the checked segment's label sits on the moving fill. The plain `[checked]` attribute
146
+ selector alone is sufficient (no paired `:state(checked)`, unlike radio.css's own dot rule): `checked`
147
+ reflects via its own reflected prop (indicator-element.ts:24, `reflect:true`) in lockstep with the
148
+ `:state(checked)` custom state a sibling reactive effect publishes off the same `checked` write
149
+ (indicator-element.ts:125–135) — both track one source, so `[checked]` is always current, AND (unlike
150
+ `:state()`) it also works under jsdom, where CustomStateSet is absent. */
151
+ ui-segmented-control ui-segment:is([checked]) {
152
+ color: var(--ui-segmented-control-ink-selected);
153
+ }
154
+
155
+ /* Interaction states — the TEXT-channel wash on UNSELECTED segments only; a checked segment cannot toggle
156
+ off, so the selected segment's fill holds (it never reads the hover/active tokens). */
157
+ ui-segmented-control ui-segment:not([checked]):hover {
158
+ background: var(--ui-segmented-control-bg-hover);
159
+ }
160
+ ui-segmented-control ui-segment:not([checked]):active {
161
+ background: var(--ui-segmented-control-bg-active);
162
+ }
163
+
164
+ /* Disabled — holds at idle (matches segment.css's own disabled pointer-inertness + the group's disabled
165
+ change-swallow, radio-group.ts): the hover/active washes are suppressed entirely. */
166
+ ui-segmented-control[disabled] ui-segment:hover,
167
+ ui-segmented-control[disabled] ui-segment:active {
168
+ background: transparent;
169
+ }
170
+
171
+ /* Forced colors (WHCM) — the indicator inverts to Highlight/HighlightText; the frame, dividers, and
172
+ unselected ink hold at ButtonText. `transform` still applies under forced-colors (the indicator still
173
+ POSITIONS on the right segment; only its fill/ink invert). */
174
+ @media (forced-colors: active) {
175
+ ui-segmented-control {
176
+ border-color: ButtonText;
177
+ }
178
+ ui-segmented-control::before {
179
+ forced-color-adjust: none;
180
+ background: Highlight;
181
+ }
182
+ ui-segmented-control ui-segment {
183
+ forced-color-adjust: none;
184
+ color: ButtonText;
185
+ }
186
+ ui-segmented-control ui-segment:is([checked]) {
187
+ color: HighlightText;
188
+ }
189
+ }
@@ -0,0 +1,20 @@
1
+ import { UIRadioGroupElement } from '../radio/radio-group.js';
2
+ import { UIRadioElement } from '../radio/radio.js';
3
+ import type { RovingOrientation } from '../../traits/roving-focus.js';
4
+ import '../segment/segment.js';
5
+ export declare class UISegmentedControlElement extends UIRadioGroupElement {
6
+ /**
7
+ * ADR-0095 clause 1 — the class-derived default: a segmented control defaults to a HORIZONTAL row (the
8
+ * ADR-0086 "variant=segmented ⇒ horizontal" default, now class-derived instead of variant-derived). An
9
+ * author-set `orientation` attribute still wins (resolved by the PARENT's `connected()`).
10
+ */
11
+ protected defaultOrientation(): RovingOrientation;
12
+ /**
13
+ * ADR-0095 clause 2 — the moving-indicator state seam. Writes the selected index + segment count as host
14
+ * CUSTOM PROPERTIES (the `--value-pct` precedent, range-element.ts:111 / slider-multi.ts:196–197 —
15
+ * reactive STATE, never a stylesheet injection), read by `segmented-control.css`'s `::before` to size +
16
+ * translate the shared moving fill. `index < 0` (nothing selected) writes `0` — the indicator itself is
17
+ * hidden by CSS whenever no segment is `[checked]`, so the fallback position is irrelevant while hidden.
18
+ */
19
+ protected selectionChanged(radios: UIRadioElement[], index: number): void;
20
+ }
@@ -0,0 +1,64 @@
1
+ // segmented-control.ts — UISegmentedControlElement, the standalone joined-button single-select control
2
+ // (ADR-0095, authored from ADR-0092 §Alternatives-1; supersedes ADR-0086's
3
+ // `ui-radio-group[variant='segmented']` — a hard cutover, no alias).
4
+ //
5
+ // Extends UIRadioGroupElement DIRECTLY (~30 lines, per the ADR's own estimate): 100% of the single-select
6
+ // BEHAVIOR — exclusivity, roving focus, selection-follows-focus, the group form value + required→
7
+ // valueMissing validity, reset-coherence — lives once in the parent (radio-group.ts). This subclass buys
8
+ // only the tag IDENTITY (the T3 ruling's entire point) plus the two things ADR-0095 names as genuinely
9
+ // class-derived, both riding PROTECTED hooks the parent exposes for exactly this reuse:
10
+ //
11
+ // · `defaultOrientation()` (ADR-0095 clause 1) — this control defaults to a HORIZONTAL row (the parent
12
+ // base class defaults to 'vertical'). Resolved once at connect by the PARENT's `connected()`: an
13
+ // author-set `orientation` attribute still wins.
14
+ // · `selectionChanged(radios, index)` (ADR-0095 clause 2) — the moving-indicator state seam, renamed
15
+ // from ADR-0086's retired `--ui-radio-group-index`/`-count` to `--ui-segmented-control-index`/`-count`
16
+ // (the naming law: `--ui-{name}-*` is owned by the tag it's keyed to). Fired by the PARENT from all
17
+ // three sites its own doc comment names — connect (seed), every selection-apply (`#commit` AND the
18
+ // public `value` setter), and `formReset()` — so the seam tracks commit AND reset (the ADR-0086
19
+ // amendment this class inherits by construction: the call sites did not move).
20
+ //
21
+ // `#radios()` on the parent walks `instanceof UIRadioElement`, which `UISegmentElement` (below) satisfies
22
+ // by construction — no override needed for the group to find its own children. `role='radiogroup'` /
23
+ // `role='radio'`, roving-tabindex, `data-radio-group` group-detection: all INHERITED unchanged.
24
+ //
25
+ // `ui-segment extends UIRadioElement` (ADR-0095 clause 3, `controls/segment/segment.ts`): the naming win T3
26
+ // is about — a `ui-radio` child inside `<ui-segmented-control>` would leak "radio" into every consumer's
27
+ // markup. `radio.css`'s `@scope (ui-radio)` rules simply don't match the new tag (a feature — `ui-segment`
28
+ // needs no dot to suppress); it authors its own small CSS. `ui-segment` lives in its OWN sibling folder,
29
+ // NOT this one — the family-coherence naming trip-wire (`name === folder || name.startsWith(folder + '-')`,
30
+ // family-coherence.test.ts A4) accepts `radio-group` inside `radio/` (a real prefix match) but rejects
31
+ // `segment` inside `segmented-control/` (no prefix relationship: "segment" is not a prefix of "segmented-
32
+ // control", nor is "segmented-control-" a prefix of "segment") — a real constraint the radio/radio-group
33
+ // precedent's two-descriptors-one-folder shape cannot generalize to. `segmented-control.ts` imports
34
+ // `segment.ts` as a side effect below (the `ui-card`/`ui-tabs` compound precedent: a parent that REQUIRES
35
+ // its own sub-tag self-defines it too), so importing this ONE public entry self-defines both tags.
36
+ //
37
+ // Layer: controls/ — imports dom + controls/radio + controls/segment (inward-only ✓).
38
+ import { UIRadioGroupElement } from "../radio/radio-group.js";
39
+ import { UIRadioElement } from "../radio/radio.js";
40
+ import "../segment/segment.js"; // self-defines ui-segment — a segmented control is meaningless without it
41
+ export class UISegmentedControlElement extends UIRadioGroupElement {
42
+ /**
43
+ * ADR-0095 clause 1 — the class-derived default: a segmented control defaults to a HORIZONTAL row (the
44
+ * ADR-0086 "variant=segmented ⇒ horizontal" default, now class-derived instead of variant-derived). An
45
+ * author-set `orientation` attribute still wins (resolved by the PARENT's `connected()`).
46
+ */
47
+ defaultOrientation() {
48
+ return 'horizontal';
49
+ }
50
+ /**
51
+ * ADR-0095 clause 2 — the moving-indicator state seam. Writes the selected index + segment count as host
52
+ * CUSTOM PROPERTIES (the `--value-pct` precedent, range-element.ts:111 / slider-multi.ts:196–197 —
53
+ * reactive STATE, never a stylesheet injection), read by `segmented-control.css`'s `::before` to size +
54
+ * translate the shared moving fill. `index < 0` (nothing selected) writes `0` — the indicator itself is
55
+ * hidden by CSS whenever no segment is `[checked]`, so the fallback position is irrelevant while hidden.
56
+ */
57
+ selectionChanged(radios, index) {
58
+ this.style.setProperty('--ui-segmented-control-index', String(Math.max(0, index)));
59
+ this.style.setProperty('--ui-segmented-control-count', String(radios.length));
60
+ }
61
+ }
62
+ if (!customElements.get('ui-segmented-control')) {
63
+ customElements.define('ui-segmented-control', UISegmentedControlElement);
64
+ }