@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,106 @@
1
+ /* progress.css — ui-progress, the Display-class thin-rail progress bar (LLD-C1, feed-family.lld.md §2;
2
+ * SPEC-R2/R18/R19/R20; ADR-0112 cl.2). Two sectioned blocks:
3
+ *
4
+ * [1] TOKEN BLOCK — `:where(ui-progress)` declares `--ui-progress-*`: a DENSITY-INVARIANT thin rail
5
+ * thickness (the slider-rail precedent verbatim, slider.css:76-79 — a bar is a rail, NOT a
6
+ * `--md-sys-compact-*` widget box) + the whole-shape floor (SPEC-R18 AC1, the slider-dot collapse
7
+ * lesson) + track/fill color roles (track = `--md-sys-color-neutral-track`, the ADR-0059 solid-track
8
+ * role; fill = the primary role).
9
+ * [2] STYLES BLOCK — `@scope (ui-progress)` consumes ONLY `--ui-progress-*`.
10
+ *
11
+ * Display class (SPEC-R20): no [size]/[scale] control-band lookup, no `--md-sys-height-*`, no `h/2` centering
12
+ * law — the rail is a fixed px constant regardless of [density]/[scale] (SPEC-R18 AC3).
13
+ *
14
+ * RTL (SPEC-R2 AC3): the fill's `inset-inline-start` is a LOGICAL property — the determinate fill and the
15
+ * indeterminate sweep both mirror for free under `dir="rtl"`; no dedicated per-direction rule is needed.
16
+ *
17
+ * Motion (SPEC-R2 AC2): indeterminate animates `inset-inline-start` (a translating sweep). Under
18
+ * `prefers-reduced-motion: reduce` the sweep is replaced by a STATIONARY partial fill with a slow
19
+ * opacity pulse — no translation, no scaling — that stays visually distinct from any determinate state.
20
+ * The keyframes live at stylesheet TOP LEVEL (outside `@scope`) — scoped `@keyframes` name resolution is
21
+ * exactly the kind of engine variance the fleet doesn't need (LLD-C1); names are `ui-progress-*`-prefixed.
22
+ *
23
+ * Forced colors (SPEC-R19): a background-drawn fill vanishes under WHCM (the bar-chart lesson,
24
+ * bar-chart.css:101-107) — an explicit `forced-colors` block repoints the fill to `CanvasText` and keeps
25
+ * the track distinguishable (`Canvas` + a `CanvasText` border).
26
+ */
27
+
28
+ /* ════════════════ [1] TOKEN BLOCK — :where(ui-progress) declares --ui-progress-* ════════════════ */
29
+
30
+ :where(ui-progress) {
31
+ --ui-progress-track-size: 4px; /* thin rail — density-invariant constant (slider.css:76-79 kin) */
32
+ --ui-progress-min-inline-size: 8em; /* the whole-shape floor (SPEC-R18 AC1; the slider-dot lesson) */
33
+ --ui-progress-track-ink: var(--md-sys-color-neutral-track); /* the ADR-0059 solid-track role */
34
+ --ui-progress-fill-ink: var(--md-sys-color-primary);
35
+ }
36
+
37
+ /* ════════════════ [2] STYLES BLOCK — @scope (ui-progress) consumes ONLY --ui-progress-* ════════════════ */
38
+
39
+ @scope (ui-progress) {
40
+ :scope {
41
+ display: block;
42
+ min-inline-size: var(--ui-progress-min-inline-size);
43
+ }
44
+
45
+ :scope [data-part='track'] {
46
+ display: block;
47
+ position: relative;
48
+ overflow: hidden;
49
+ block-size: var(--ui-progress-track-size);
50
+ border-radius: calc(var(--ui-progress-track-size) / 2);
51
+ background: var(--ui-progress-track-ink);
52
+ }
53
+
54
+ :scope [data-part='fill'] {
55
+ position: absolute;
56
+ inset-block: 0;
57
+ inset-inline-start: 0;
58
+ inline-size: calc(var(--_pct, 0) * 1%);
59
+ background: var(--ui-progress-fill-ink);
60
+ border-radius: inherit;
61
+ }
62
+
63
+ :scope [data-part='fill'][data-indeterminate] {
64
+ /* the sweep (SPEC-R2 AC2) — a partial-width fill translating along the track */
65
+ inline-size: 40%;
66
+ animation: ui-progress-sweep 1.5s linear infinite;
67
+ }
68
+
69
+ @media (prefers-reduced-motion: reduce) {
70
+ :scope [data-part='fill'][data-indeterminate] {
71
+ /* stationary; opacity-only — no translation, no scaling (SPEC-R2 AC2) */
72
+ inset-inline-start: 30%;
73
+ animation: ui-progress-pulse 2s ease-in-out infinite;
74
+ }
75
+ }
76
+
77
+ @media (forced-colors: active) {
78
+ /* the bar-chart lesson (SPEC-R19) — a background-drawn fill otherwise vanishes */
79
+ :scope [data-part='fill'] {
80
+ background: CanvasText;
81
+ }
82
+ :scope [data-part='track'] {
83
+ background: Canvas;
84
+ border: 1px solid CanvasText;
85
+ }
86
+ }
87
+ }
88
+
89
+ @keyframes ui-progress-sweep {
90
+ from {
91
+ inset-inline-start: -40%;
92
+ }
93
+ to {
94
+ inset-inline-start: 100%;
95
+ }
96
+ }
97
+
98
+ @keyframes ui-progress-pulse {
99
+ 0%,
100
+ 100% {
101
+ opacity: 0.35;
102
+ }
103
+ 50% {
104
+ opacity: 1;
105
+ }
106
+ }
@@ -0,0 +1,28 @@
1
+ import { UIElement, type ReactiveProps } from '../../dom/index.js';
2
+ declare const props: {
3
+ current: import("../../index.js").PropConfig<number | null>;
4
+ max: import("../../index.js").PropConfig<number | null>;
5
+ label: {
6
+ reflect: true;
7
+ type: import("../../index.js").PropType<string>;
8
+ default: string;
9
+ attribute?: string | false;
10
+ };
11
+ };
12
+ export interface UIProgressElement extends ReactiveProps<typeof props> {
13
+ }
14
+ export declare class UIProgressElement extends UIElement {
15
+ #private;
16
+ static props: {
17
+ current: import("../../index.js").PropConfig<number | null>;
18
+ max: import("../../index.js").PropConfig<number | null>;
19
+ label: {
20
+ reflect: true;
21
+ type: import("../../index.js").PropType<string>;
22
+ default: string;
23
+ attribute?: string | false;
24
+ };
25
+ };
26
+ protected connected(): void;
27
+ }
28
+ export {};
@@ -0,0 +1,80 @@
1
+ // progress.ts — UIProgressElement, the Display-class thin-rail progress bar (LLD-C1, feed-family.lld.md
2
+ // §2; SPEC-R1/R2/R3/R18/R19/R20; ADR-0112 cl.2). Non-interactive, non-form-associated leaf: no events, no
3
+ // keyboard contract, no [size]/[scale] control geometry — a bar is a rail, not a widget box. Value model
4
+ // mirrors the native <progress> semantic: `value === null` (default) ⇒ INDETERMINATE, never a separate
5
+ // boolean to desync. `render()` stays the inherited no-op — the track/fill pair is built once in
6
+ // `connected()` (survives reconnect via the private field guard) and mutated per-change by two effects.
7
+ //
8
+ // Hardening (SPEC-R1's table) is a pure in-file pair — the math is two clamps, no separate module:
9
+ // `effectiveMax` floors a non-finite/≤0/malformed `max` to the ARIA default (100); `effectiveValue` maps
10
+ // an absent/non-finite `value` to `null` (indeterminate) and clamps a real value into [0, effectiveMax].
11
+ // No case throws — every input, however malformed, resolves to a paintable, announced state.
12
+ import { UIElement, prop } from "../../dom/index.js";
13
+ const props = {
14
+ current: prop.number(null), // null ⇒ indeterminate (the native <progress> semantic — no boolean to desync). Renamed from `value` (TKT-0069 item 1 ruling: `value` = the FACE form value, reserved — this rename spends real native-<progress> parity deliberately; the A2UI catalog keeps wire `value`, mapped in its bespoke factory)
15
+ max: prop.number(100), // the ARIA progressbar default — percent-natural for {value:42} with zero extra props
16
+ label: { ...prop.string(''), reflect: true }, // the accessible name (SPEC-R3); empty ⇒ no internals.ariaLabel
17
+ };
18
+ /** SPEC-R1: non-finite / ≤0 / malformed `max` floors to the ARIA progressbar default. */
19
+ function effectiveMax(max) {
20
+ return max !== null && Number.isFinite(max) && max > 0 ? max : 100;
21
+ }
22
+ /** SPEC-R1: absent/non-finite `value` ⇒ null (indeterminate); else clamped into [0, eMax]. */
23
+ function effectiveValue(value, eMax) {
24
+ return value === null || !Number.isFinite(value) ? null : Math.min(Math.max(value, 0), eMax);
25
+ }
26
+ // Module-memoized (SPEC-R3): the percent reading behind `ariaValueText`, default locale.
27
+ const percentFormat = new Intl.NumberFormat(undefined, { style: 'percent', maximumFractionDigits: 0 });
28
+ export class UIProgressElement extends UIElement {
29
+ static props = props;
30
+ #track = null;
31
+ #fill = null;
32
+ connected() {
33
+ // Built ONCE (LLD-C1) — a private-field guard so a reconnect (children survive removal/re-append)
34
+ // never mints a second track/fill pair.
35
+ if (!this.#track) {
36
+ this.#track = document.createElement('span');
37
+ this.#track.setAttribute('data-part', 'track');
38
+ this.#fill = document.createElement('span');
39
+ this.#fill.setAttribute('data-part', 'fill');
40
+ this.#track.append(this.#fill);
41
+ this.append(this.#track);
42
+ }
43
+ const fill = this.#fill;
44
+ // Mark effect (SPEC-R2): determinate ⇒ the fill's --_pct custom property; indeterminate ⇒
45
+ // data-indeterminate on the fill (an interior node, never a host attribute — CSS drives the sweep).
46
+ this.effect(() => {
47
+ const eMax = effectiveMax(this.max);
48
+ const eValue = effectiveValue(this.current, eMax);
49
+ if (eValue === null) {
50
+ fill.setAttribute('data-indeterminate', '');
51
+ fill.style.removeProperty('--_pct');
52
+ }
53
+ else {
54
+ fill.removeAttribute('data-indeterminate');
55
+ fill.style.setProperty('--_pct', String((eValue / eMax) * 100));
56
+ }
57
+ });
58
+ // ARIA effect (SPEC-R3): role=progressbar is ALWAYS set — status data, never silent (the chart
59
+ // inversion, ADR-0112 cl.2). Determinate publishes ariaValueNow/Text; indeterminate omits both while
60
+ // role/min/max persist — the ARIA-native indeterminate signal.
61
+ this.effect(() => {
62
+ const eMax = effectiveMax(this.max);
63
+ const eValue = effectiveValue(this.current, eMax);
64
+ this.internals.role = 'progressbar';
65
+ this.internals.ariaValueMin = '0';
66
+ this.internals.ariaValueMax = String(eMax);
67
+ if (eValue === null) {
68
+ this.internals.ariaValueNow = null;
69
+ this.internals.ariaValueText = null;
70
+ }
71
+ else {
72
+ this.internals.ariaValueNow = String(eValue);
73
+ this.internals.ariaValueText = percentFormat.format(eValue / eMax);
74
+ }
75
+ this.internals.ariaLabel = this.label || null;
76
+ });
77
+ }
78
+ }
79
+ if (!customElements.get('ui-progress'))
80
+ customElements.define('ui-progress', UIProgressElement); // idempotent self-define
@@ -0,0 +1,84 @@
1
+ /* radio-group.css — ui-radio-group, the radio-button container stylesheet (Wave 1 S3, ADR-0003).
2
+ *
3
+ * The container convention requires a .css even for a small layout footprint (process.md §4,
4
+ * container-family rule): every FACE component ships a stylesheet that at minimum carries the
5
+ * `:where(ui-{name})` token block and the `@scope (ui-{name})` block. The group has no visual surface of
6
+ * its own — its `ui-radio` children carry all visible affordances — but it DOES own its interior layout
7
+ * (ADR-0103); its forced-colors block stays minimal.
8
+ *
9
+ * ADR-0086 previously grew a "segmented" presentation variant here (a joined-button track + one shared
10
+ * moving highlight, keyed off `[variant='segmented']`). ADR-0095 supersedes that architecture: the segmented
11
+ * presentation is now the standalone `ui-segmented-control` (controls/segmented-control/segmented-control.css)
12
+ * — a hard cutover, no alias. This file is restored to its pre-ADR-0086 truth for presentation; ADR-0103
13
+ * then fills the token block's long-reserved seat with the group's OWN layout token (not a variant).
14
+ *
15
+ * ADR-0103 (the spacing pair): a value-owning group whose children must be its DIRECT children
16
+ * (radio-group.ts:194's `[...this.children].filter(...)`) cannot be fixed by composition — wrapping the
17
+ * radios in a `ui-column` would sever discovery. So the group owns the SAME flex structure the site used to
18
+ * hand-author per-page (component-preview.css, now deleted): a vertical stack by default,
19
+ * `[orientation='horizontal']` a wrapping row — with the gap re-based to the `--md-sys-space` ladder (`sm`) so it
20
+ * rides `[density]` for free, rather than the site's hard-coded `0.4rem`/`--md-sys-space-md` duplicates.
21
+ *
22
+ * Standalone stylesheet — linked via the component-styles barrel (s12, after radio.css); NEVER injected
23
+ * from radio-group.ts (behaviour-only `.ts`, no runtime style injection — plan §2).
24
+ */
25
+
26
+ /* ════════════ [1] TOKEN BLOCK — :where(ui-radio-group) (specificity 0,0,0) ════════════ */
27
+
28
+ :where(ui-radio-group) {
29
+ /* ADR-0103: the group's own interior gap, off the layout ladder (density-responsive for free) — the seat
30
+ this block's comment reserved ("future density/gap props without a cascade-order change"). Page authors
31
+ retune per-instance with one custom property (the ADR-0102 override freedom); no catalog `gap` enum yet
32
+ (a foreseen Lane B extension only if live evidence shows models need magnitude control). */
33
+ --ui-radio-group-gap: var(--md-sys-space-sm);
34
+
35
+ /* user-invalid (ADR-0051) — the danger border repoint reaching into each ui-radio child's own
36
+ ::before ring (the group has no visual surface of its own, see the file header). Appears only
37
+ AFTER the first interaction (the trackUserInvalid controller owns that timing; radio-group.ts
38
+ toggles :state(user-invalid) on the group host). */
39
+ --ui-radio-group-border-invalid: var(--md-sys-color-danger);
40
+ }
41
+
42
+ /* ════════════ [2] STYLES BLOCK — @scope (ui-radio-group) ════════════ */
43
+
44
+ @scope (ui-radio-group) {
45
+ /* ADR-0103: a vertical stack by default — the roving-focus axis (Arrow Up/Down, radio-group.ts's
46
+ `defaultOrientation()`) and the visual axis are now the SAME source of truth. No explicit block-size or
47
+ inline-size — the group sizes to its content; only the gap is opinionated. */
48
+ :scope {
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: var(--ui-radio-group-gap);
52
+ }
53
+
54
+ /* `[orientation='horizontal']` (reflected once at connect, radio-group.ts's connected()) switches to a
55
+ wrapping row — `flex-wrap: wrap` is graceful degradation in a cramped container (the ADR-0016 row-side
56
+ philosophy), and `align-items: center` keeps radios of differing label height on one visual baseline. */
57
+ :scope[orientation='horizontal'] {
58
+ flex-direction: row;
59
+ flex-wrap: wrap;
60
+ align-items: center;
61
+ }
62
+
63
+ /* Forced colors (WHCM) — no visual surface of its own: the ui-radio children carry their own
64
+ forced-color treatments. This block is present for fleet discipline (every FACE control's scope
65
+ includes a forced-colors rule). */
66
+ @media (forced-colors: active) {
67
+ :scope {
68
+ /* no group-level WHCM adjustments; the children carry their own forced-color rules */
69
+ forced-color-adjust: none;
70
+ }
71
+ }
72
+ }
73
+
74
+ /* ════════════ user-invalid (ADR-0051) — a cross-boundary reach into ui-radio's own paint ════════════
75
+ * The group carries no visual surface of its own (the [2] block above); the danger repoint must reach
76
+ * INTO each `ui-radio` child's own `::before` ring instead. A plain top-level compound selector,
77
+ * deliberately OUTSIDE `@scope` — the SAME technique segmented-control.css uses to reach `ui-segment`
78
+ * (its own file header explains why: this clears `ui-radio`'s own `@scope (ui-radio) { :scope::before }`
79
+ * rule ((0,1,1)) without `!important`, since `ui-radio-group:state(user-invalid) ui-radio::before` is
80
+ * (0,1,3)). Never co-occurs with `:state(checked)::before` in practice — `formValidity()` only reports
81
+ * `valueMissing` when NO radio is checked, so no specificity race with the checked-fill rule. */
82
+ ui-radio-group:state(user-invalid) ui-radio::before {
83
+ border-color: var(--ui-radio-group-border-invalid);
84
+ }
@@ -0,0 +1,152 @@
1
+ import { UIFormElement } from '../../dom/form.js';
2
+ import type { FormValue, ValidityResult } from '../../dom/form.js';
3
+ import { type ReactiveProps } from '../../dom/props.js';
4
+ import { type RovingOrientation } from '../../traits/roving-focus.js';
5
+ import { UIRadioElement } from './radio.js';
6
+ declare const groupProps: {
7
+ orientation: {
8
+ reflect: true;
9
+ type: import("../../index.js").PropType<"horizontal" | "vertical">;
10
+ default: "horizontal" | "vertical";
11
+ attribute?: string | false;
12
+ };
13
+ name: {
14
+ reflect: true;
15
+ type: import("../../index.js").PropType<string>;
16
+ default: string;
17
+ attribute?: string | false;
18
+ };
19
+ disabled: {
20
+ reflect: true;
21
+ type: import("../../index.js").PropType<boolean>;
22
+ default: boolean;
23
+ attribute?: string | false;
24
+ };
25
+ required: {
26
+ reflect: true;
27
+ type: import("../../index.js").PropType<boolean>;
28
+ default: boolean;
29
+ attribute?: string | false;
30
+ };
31
+ };
32
+ export interface UIRadioGroupElement extends ReactiveProps<typeof groupProps> {
33
+ }
34
+ export declare class UIRadioGroupElement extends UIFormElement {
35
+ #private;
36
+ static props: {
37
+ orientation: {
38
+ reflect: true;
39
+ type: import("../../index.js").PropType<"horizontal" | "vertical">;
40
+ default: "horizontal" | "vertical";
41
+ attribute?: string | false;
42
+ };
43
+ name: {
44
+ reflect: true;
45
+ type: import("../../index.js").PropType<string>;
46
+ default: string;
47
+ attribute?: string | false;
48
+ };
49
+ disabled: {
50
+ reflect: true;
51
+ type: import("../../index.js").PropType<boolean>;
52
+ default: boolean;
53
+ attribute?: string | false;
54
+ };
55
+ required: {
56
+ reflect: true;
57
+ type: import("../../index.js").PropType<boolean>;
58
+ default: boolean;
59
+ attribute?: string | false;
60
+ };
61
+ };
62
+ protected connected(): void;
63
+ /**
64
+ * The group's selected value — the checked `ui-radio` child's `value`, or `null` when none is
65
+ * selected. A public getter/setter pair delegating to the private `#selectedValue` signal (the
66
+ * `UICheckboxElement.indeterminate` precedent, checkbox.ts:39 — a plain accessor over a private
67
+ * signal, not a `prop.*`-declared attribute: the value is DERIVED from child radio state, so it
68
+ * has nothing of its own to reflect).
69
+ *
70
+ * The getter reads the signal directly — a reactive caller (e.g. inside `this.effect`) tracks it
71
+ * exactly like any other signal read.
72
+ *
73
+ * The setter is the PROGRAMMATIC path (e.g. a two-way data-bind write): it selects the child
74
+ * `ui-radio` whose `value` matches (unchecking all others) via `#applySelection` — the SAME state
75
+ * transition `#commit` drives for a user click/keyboard commit — but it does NOT emit `change`.
76
+ * This matches the fleet convention for a programmatic prop write on a value-bearing control
77
+ * (`UICheckboxElement.checked` / `UISelectElement.value` are directly settable and never
78
+ * self-emit on assignment; only the interaction-driven commit path — `#commit` here — emits).
79
+ *
80
+ * `null` clears the selection (unchecks every radio). A value matching NO child radio also CLEARS
81
+ * the selection, rather than a silent no-op — the native `HTMLSelectElement.value` precedent:
82
+ * assigning a `<select>`'s `.value` to a string with no matching `<option>` resolves
83
+ * `selectedIndex` to `-1` (the value reads back as `''`) instead of leaving the prior selection
84
+ * in place.
85
+ */
86
+ get value(): string | null;
87
+ set value(v: string | null);
88
+ /**
89
+ * ADR-0095 clause 1 — the CLASS-derived default roving-axis orientation, consulted by `connected()`'s
90
+ * resolve-once-and-reflect ONLY when no explicit `orientation` attribute is authored. This base returns
91
+ * `'vertical'` (today's shipped roving, unchanged). `UISegmentedControlElement` overrides this to
92
+ * `'horizontal'` — the ADR-0086 "variant=segmented ⇒ horizontal" default, now class-derived instead of
93
+ * variant-derived.
94
+ */
95
+ protected defaultOrientation(): RovingOrientation;
96
+ /**
97
+ * ADR-0095 clause 2 — a protected, no-op-in-the-base post-selection hook, fired from every
98
+ * selection-DEFINING event: the connect-time seed, every `#applySelection` (both `#commit`'s user-driven
99
+ * path AND the public `value` setter's programmatic path), and `formReset()`. This is the SAME seam
100
+ * ADR-0086's (now-retired) private `#writeIndexCount` fired from — moved here, as a protected hook,
101
+ * so `UISegmentedControlElement` can write its own `--ui-segmented-control-index`/`-count` moving-
102
+ * indicator state WITHOUT this base class knowing anything about segments or indicators. A no-op here
103
+ * costs nothing for the plain dot-group presentation.
104
+ */
105
+ protected selectionChanged(_radios: UIRadioElement[], _index: number): void;
106
+ /**
107
+ * The group's form value: the selected radio's `value`, or `null` when nothing is checked.
108
+ * Reads `#selectedValue.value` (a signal) so the UIFormElement base's scope-owned setFormValue
109
+ * effect re-runs automatically when selection changes.
110
+ */
111
+ protected formValue(): FormValue;
112
+ /**
113
+ * Validity: `required` + no selection → `valueMissing`. Reads `#selectedValue.value` so the
114
+ * UIFormElement base's setValidity effect re-runs when selection changes. An empty, required group
115
+ * stays invalid until a radio is committed; a non-required empty group is always valid.
116
+ */
117
+ protected formValidity(): ValidityResult;
118
+ /**
119
+ * Form reset — group-level coordination (bug-A fix). Each child radio is its OWN `UIFormElement`
120
+ * participant with its OWN `formResetCallback` (now fixed, indicator-element.ts) that silently restores
121
+ * ITS `checked` to ITS `defaultChecked` — but the GROUP owns a SEPARATE `#selectedValue` signal
122
+ * (`formValue()`/`formValidity()` above), which no radio's own reset can reach. Recompute it here from
123
+ * every child's `defaultChecked` (a stable, native-parity PUBLIC getter — see UIIndicatorElement) rather
124
+ * than each child's live `checked`: the platform resets the group and its radios as INDEPENDENT
125
+ * `UIFormElement`s, in an order this class must not assume (tree order suggests ancestor-first, i.e.
126
+ * this runs BEFORE the radios' own resets — reading live `checked` here would see PRE-reset values).
127
+ * `defaultChecked` sidesteps the ordering question entirely: it is a fixed snapshot from each radio's
128
+ * first connect, unaffected by reset order on either side. Silent — no `change` emitted (a reset is not
129
+ * a user commit; matches `#commit`'s own emit-on-user-action-only discipline).
130
+ *
131
+ * Bug fix (component-reviewer B4, blocking; ADR-0086, preserved verbatim by ADR-0095 clause 2): a reset
132
+ * must ALSO fire the post-selection hook (`selectionChanged`). The hook was previously (ADR-0086) a
133
+ * private `#writeIndexCount` written only at connect and in `#commit` — but a radio's own reset
134
+ * (`indicator-element.ts`) restores its `checked` OUTSIDE `#commit`, so without this the seam desyncs
135
+ * in a subclass that consumes it (e.g. `UISegmentedControlElement`'s moving indicator): the CSS
136
+ * `:not(:has(ui-radio[checked]))`-style gate correctly re-shows the indicator (the DOM `[checked]` is
137
+ * genuinely restored), but a STALE index would still park the moving fill on the pre-reset selection —
138
+ * a visible indicator/ink mismatch. Recomputed from `defaultChecked` for the same reset-order-
139
+ * independence reason as `#selectedValue` above (not live `checked`, which may not have reset yet on
140
+ * this radio's siblings). `findIndex` returns `-1` when no radio was ever default-checked; a consuming
141
+ * subclass's hook is expected to clamp that to `0` the same way ADR-0086's seam did — harmless, since a
142
+ * segmented indicator hides itself whenever nothing is `[checked]`.
143
+ */
144
+ protected formReset(): void;
145
+ protected disconnected(): void;
146
+ /** Feeds `FormConnectDetail.userInvalid` (ADR-0050) — the `trackUserInvalid` tracker IS the one
147
+ * timing source; this override just exposes its gate. Inherited by `UISegmentedControlElement`
148
+ * unchanged (it never overrides connected()/formReset(), so this base's wiring applies to its
149
+ * own internals directly). */
150
+ protected formUserInvalid(): boolean;
151
+ }
152
+ export {};