@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,80 @@
1
+ // bar-chart.ts — UIBarChartElement, the Display-class magnitude-comparison bar list (LLD-C5,
2
+ // chart-family.lld.md §3; chart-family.spec.md SPEC-R5…R8; ADR-0107 cl.1-5, fork F2). BEHAVIOUR + props +
3
+ // list-semantics ARIA + the component-built rows + self-define ONLY; the zero-baseline PROPORTION math
4
+ // lives in bar-math.ts (DOM-free, unit-testable) and the CSS grid/token geometry lives in bar-chart.css.
5
+ //
6
+ // The name stays `ui-bar-chart`/`BarChart` even though v1 renders the horizontal bar-LIST model (ADR-0107
7
+ // fork F2, SPEC-R5) — models know "BarChart"; the descriptor documents the deviation honestly.
8
+ //
9
+ // A chart is data, not decoration (ADR-0107 cl.4): the host carries `role=list` via `ElementInternals`
10
+ // (the `ui-list` precedent, `list.ts:50`) — never a host attribute — named by `label` when non-empty
11
+ // (SPEC-R8). Each rendered row is a real `role=listitem` element whose text content is `{label} {printed
12
+ // value}`; the visual bar (track + fill) is `aria-hidden` — the printed value is the accessible datum, the
13
+ // bar itself repeats it in the length channel only, never the sole carrier (ADR-0057).
14
+ //
15
+ // Content model — component-built rows, NOT host-as-grid: `data` is display-only, whole-array derived
16
+ // state (no positional reconcile — LLD-C5's deliberate NOT-ADR-0024 call, LLD §7 row 7: these are inert
17
+ // text rows with no focus/selection worth reconciling), so `render()` stays the inherited no-op and the
18
+ // rows effect rebuilds the full light-DOM child list on every `data` change via `replaceChildren`. The
19
+ // fill's geometry rides two row-scoped custom properties set imperatively (`--_bar-start`/`--_bar-length`,
20
+ // a non-`--ui-*` namespace — the slider/slider-multi `--value-pct` precedent) so bar-chart.css owns every
21
+ // paint decision and this file never writes a `width`.
22
+ //
23
+ // Imports inward only (controls → dom): UIElement + prop + the typed-schema helpers from the dom barrel;
24
+ // the pure math from the co-located bar-math.ts (the ADR-0065 pure-core split, ADR-0107 cl.3/cl.7).
25
+ import { UIElement, prop } from "../../dom/index.js";
26
+ import { barDataProp, barRows, cleanData } from "./bar-math.js";
27
+ const props = {
28
+ data: barDataProp, // { label: string; value: number }[] · safe JSON codec (bar-math.ts) · default []
29
+ label: { ...prop.string(''), reflect: true }, // the list's accessible name — SPEC-R8: unlabeled is legal, never a silent state
30
+ };
31
+ export class UIBarChartElement extends UIElement {
32
+ static props = props;
33
+ connected() {
34
+ // List semantics (SPEC-R8, the `ui-list` precedent) — a constant semantic role, set directly (not
35
+ // inside an effect); re-set on each connect (idempotent).
36
+ this.internals.role = 'list';
37
+ // The label effect — `label` names the list when non-empty; an unlabeled list is legal (SPEC-R8 AC —
38
+ // the host stays `role=list` regardless, never aria-hidden, never a silent state).
39
+ this.effect(() => {
40
+ this.internals.ariaLabel = this.label || null;
41
+ });
42
+ // The rows effect (SPEC-R6/R7): whole-array derived state — every `data` change rebuilds the full
43
+ // light-DOM row list via one `replaceChildren` (display-only rows hold no focus/selection state worth
44
+ // a positional reconcile — LLD-C5's deliberate NOT-ADR-0024 call). `cleanData` runs again here (not
45
+ // just inside the codec), so a PROPERTY write of garbage never reaches the math either (the SPEC-R3
46
+ // AC2 sibling rule the codec alone cannot cover — the codec only guards the ATTRIBUTE path).
47
+ this.effect(() => {
48
+ const rows = barRows(cleanData(this.data));
49
+ this.replaceChildren(...rows.map((row) => this.#rowNode(row)));
50
+ });
51
+ }
52
+ /**
53
+ * Build one component-owned row: `label · track(aria-hidden) > fill · value` (LLD-C5's markup). The
54
+ * fill's geometry rides two row-scoped custom properties — bar-chart.css owns every paint decision, this
55
+ * method never writes a `width`. AT reading (SPEC-R8 AC1): the listitem's text content is
56
+ * `{label} {printed value}` (the two text spans); the track subtree is aria-hidden and text-free.
57
+ */
58
+ #rowNode(row) {
59
+ const item = document.createElement('div');
60
+ item.setAttribute('role', 'listitem');
61
+ const label = document.createElement('span');
62
+ label.setAttribute('data-part', 'label');
63
+ label.textContent = row.label;
64
+ const fill = document.createElement('span');
65
+ fill.setAttribute('data-part', 'fill');
66
+ fill.style.setProperty('--_bar-start', String(row.startPct));
67
+ fill.style.setProperty('--_bar-length', String(row.lengthPct));
68
+ const track = document.createElement('span');
69
+ track.setAttribute('data-part', 'track');
70
+ track.setAttribute('aria-hidden', 'true');
71
+ track.appendChild(fill);
72
+ const value = document.createElement('span');
73
+ value.setAttribute('data-part', 'value');
74
+ value.textContent = row.text;
75
+ item.append(label, track, value);
76
+ return item;
77
+ }
78
+ }
79
+ if (!customElements.get('ui-bar-chart'))
80
+ customElements.define('ui-bar-chart', UIBarChartElement); // idempotent self-define
@@ -0,0 +1,31 @@
1
+ import type { PropConfig } from '../../dom/props.js';
2
+ /** One bar-chart datum — the A2UI-emittable shape (SPEC-R5): `{ label: string; value: number }`. */
3
+ export interface BarDatum {
4
+ label: string;
5
+ value: number;
6
+ }
7
+ /** A rendered row: the datum plus its printed text + zero-baseline geometry (each 0..100, a percentage). */
8
+ export interface BarRow extends BarDatum {
9
+ /** The locale-formatted printed value (Intl.NumberFormat, default locale; sign preserved). */
10
+ text: string;
11
+ /** Fill inset from the track's inline-start, 0..100 (%). */
12
+ startPct: number;
13
+ /** Fill length, 0..100 (%). */
14
+ lengthPct: number;
15
+ }
16
+ /**
17
+ * Harden an arbitrary input into the rendered datum set (SPEC-R7): a non-array input yields `[]`; each
18
+ * entry survives only as a plain object with a `string` `label` and a finite `number` `value` — drop,
19
+ * never coerce (a stringly `"42"` value, a missing label, `NaN`/`Infinity` all drop the entry). Order is
20
+ * preserved — the rendered list is positional, not keyed (SPEC-R7's duplicate-label row: both rows render).
21
+ */
22
+ export declare function cleanData(input: unknown): BarDatum[];
23
+ /**
24
+ * The zero-baseline diverging bar math (SPEC-R6 + LLD-C4): `lo = min(0, …values)`, `hi = max(0, …values)`,
25
+ * `span = hi − lo`. Empty input is an early `[]` (the codec/hardening boundary handles absence — this
26
+ * function is never asked to normalize zero rows). `span === 0` (the all-zero case) ⇒ every row is
27
+ * `startPct = lengthPct = 0`. Else `zeroPct = (−lo / span) · 100` is the ONE shared origin every row
28
+ * measures from; `lengthPct = |v| / span · 100`; `startPct = v ≥ 0 ? zeroPct : zeroPct − lengthPct`.
29
+ */
30
+ export declare function barRows(data: readonly BarDatum[]): BarRow[];
31
+ export declare const barDataProp: PropConfig<BarDatum[]>;
@@ -0,0 +1,106 @@
1
+ // bar-math.ts — the pure, DOM-free bar-chart math (LLD-C4, chart-family.lld.md §3). No DOM, no host,
2
+ // unit-testable in plain Node/Vitest. Owns three things:
3
+ //
4
+ // 1. Input hardening (`cleanData`, SPEC-R7): a non-array input is `[]`; an entry survives only as a
5
+ // plain object carrying a `string` `label` and a finite `number` `value` — dropped, never coerced.
6
+ // Order is preserved (positional semantics — SPEC-R7's duplicate-label row: the list is positional,
7
+ // not keyed).
8
+ // 2. The zero-baseline diverging bar math (`barRows`, SPEC-R6): `lo = min(0, …values)`,
9
+ // `hi = max(0, …values)`, `span = hi − lo`. `span === 0` (the all-zero case; the empty case is an
10
+ // early return) ⇒ every row is zero-length — the printed `0`s carry the reading. Else
11
+ // `zeroPct = (−lo / span) · 100` (the ONE shared origin every row measures from — SPEC-R6 AC2);
12
+ // `lengthPct = |v| / span · 100`; `startPct = v ≥ 0 ? zeroPct : zeroPct − lengthPct`. All-positive ⇒
13
+ // `lo = 0`, bars measure from the inline-start edge (SPEC-R7 rows 3/4); all-negative ⇒ `hi = 0`, the
14
+ // zero point sits at the track's inline-end (SPEC-R7 row 7); mixed sign ⇒ every bar shares the one
15
+ // `zeroPct` (SPEC-R6 AC2). Every printed value rides a module-memoized default-locale
16
+ // `Intl.NumberFormat` — sign preserved for free (no special-casing negative text).
17
+ // 3. `barDataProp`, the safe `data` codec (SPEC-R7 row 1/2): `from(null)` (attribute absent/removed) is
18
+ // `[]`, NEVER `null`; malformed attribute JSON is caught and also falls back to `[]` — no throw ever
19
+ // reaches `attributeChangedCallback`. `dom/props.ts`'s generic `jsonType<T>()` is deliberately NOT
20
+ // used here — its bare `JSON.parse` throws on malformed attributes and maps a removed attribute to
21
+ // `null` (props.ts:73-82), both of which SPEC-R7 forbids reaching the render path. This is the exact
22
+ // reasoning LLD-C1 (sparkline's `sparklineValuesProp`) states for its own codec — the two controls
23
+ // share the construction (chart-family.lld.md §3 LLD-C4: "same construction as LLD-C1's").
24
+ /**
25
+ * Harden an arbitrary input into the rendered datum set (SPEC-R7): a non-array input yields `[]`; each
26
+ * entry survives only as a plain object with a `string` `label` and a finite `number` `value` — drop,
27
+ * never coerce (a stringly `"42"` value, a missing label, `NaN`/`Infinity` all drop the entry). Order is
28
+ * preserved — the rendered list is positional, not keyed (SPEC-R7's duplicate-label row: both rows render).
29
+ */
30
+ export function cleanData(input) {
31
+ if (!Array.isArray(input))
32
+ return [];
33
+ const out = [];
34
+ for (const entry of input) {
35
+ if (entry !== null &&
36
+ typeof entry === 'object' &&
37
+ !Array.isArray(entry) &&
38
+ typeof entry.label === 'string' &&
39
+ typeof entry.value === 'number' &&
40
+ Number.isFinite(entry.value)) {
41
+ const e = entry;
42
+ out.push({ label: e.label, value: e.value });
43
+ }
44
+ }
45
+ return out;
46
+ }
47
+ /** Module-memoized default-locale formatter — the exact numbers `barRows` prints (SPEC-R6/R4's sibling rule). */
48
+ const numberFormat = new Intl.NumberFormat();
49
+ /**
50
+ * The zero-baseline diverging bar math (SPEC-R6 + LLD-C4): `lo = min(0, …values)`, `hi = max(0, …values)`,
51
+ * `span = hi − lo`. Empty input is an early `[]` (the codec/hardening boundary handles absence — this
52
+ * function is never asked to normalize zero rows). `span === 0` (the all-zero case) ⇒ every row is
53
+ * `startPct = lengthPct = 0`. Else `zeroPct = (−lo / span) · 100` is the ONE shared origin every row
54
+ * measures from; `lengthPct = |v| / span · 100`; `startPct = v ≥ 0 ? zeroPct : zeroPct − lengthPct`.
55
+ */
56
+ export function barRows(data) {
57
+ if (data.length === 0)
58
+ return [];
59
+ let lo = 0;
60
+ let hi = 0;
61
+ for (const d of data) {
62
+ if (d.value < lo)
63
+ lo = d.value;
64
+ if (d.value > hi)
65
+ hi = d.value;
66
+ }
67
+ const span = hi - lo;
68
+ // `lo === 0` short-circuits to a literal `0` rather than `(-0 / span) * 100` — IEEE754 would otherwise
69
+ // hand back a NEGATIVE zero (`-0`) for the common all-positive case, which is numerically identical but
70
+ // needlessly surprising downstream (e.g. a strict `Object.is`-based equality check on the row's startPct).
71
+ const zeroPct = span === 0 || lo === 0 ? 0 : (-lo / span) * 100;
72
+ return data.map((d) => {
73
+ const text = numberFormat.format(d.value);
74
+ if (span === 0)
75
+ return { ...d, text, startPct: 0, lengthPct: 0 };
76
+ const lengthPct = (Math.abs(d.value) / span) * 100;
77
+ const startPct = d.value >= 0 ? zeroPct : zeroPct - lengthPct;
78
+ return { ...d, text, startPct, lengthPct };
79
+ });
80
+ }
81
+ /**
82
+ * The safe `data` codec (SPEC-R7 row 1/2): `from(null)` (the attribute absent/removed) → `[]`, never
83
+ * `null`; malformed attribute JSON is caught and also falls back to `[]` — no throw ever reaches
84
+ * `attributeChangedCallback`. Every parsed value (well-formed or not) is run through `cleanData`, so the
85
+ * property never carries a raw, un-hardened array — the codec and the SPEC-R7/case-3 property-write guard
86
+ * (bar-chart.ts's rows effect calls `cleanData(this.data)` again) share the one hardening function.
87
+ */
88
+ const barDataType = {
89
+ from(attr) {
90
+ if (attr === null)
91
+ return [];
92
+ try {
93
+ return cleanData(JSON.parse(attr));
94
+ }
95
+ catch {
96
+ return [];
97
+ }
98
+ },
99
+ to(value) {
100
+ return JSON.stringify(value);
101
+ },
102
+ };
103
+ export const barDataProp = {
104
+ type: barDataType,
105
+ default: [],
106
+ };
@@ -0,0 +1,263 @@
1
+ /* button.css — ui-button, the single-file component stylesheet (ADR-0003). Two clearly-SECTIONED blocks:
2
+ *
3
+ * [1] TOKEN BLOCK — `:where(ui-button)` (specificity 0,0,0) DECLARES the `--ui-button-*` chain from the
4
+ * colour roles (`--md-sys-color-{family}-{role}`; default family = primary) and the dimensional ramp
5
+ * (`--ui-{height,font,gap}-{size}` from `@agent-ui-kit/shared/dimensions.css`). `[variant]` repoints the
6
+ * colour channels (solid=filled · soft=tonal · ghost=text), declaring per-state `-bg-hover`/`-bg-active`
7
+ * from a ROLE-LADDER step (never a `color-mix` — colour opinions live in the token layer; ADR-0008);
8
+ * `[size]` repoints the geometry.
9
+ * [2] STYLES BLOCK — `@scope (ui-button)` CONSUMES only `--ui-button-*` for its OWN tokens. Geometry per
10
+ * references/geometry.md (the law): `block-size` off the ramp, `padding-block: 0`. Anatomy per ADR-0006
11
+ * (extended by ADR-0012): host-as-grid with OPTIONAL leading `[slot=leading]` AND trailing `[slot=trailing]`
12
+ * adornment slots via presence-driven `:has()` — placement is POSITION-driven (the slot), glyph size is
13
+ * ROLE-driven (`[data-role]`: icon = frame `--ui-button-icon`, caret = rhythm `--ui-button-glyph` = font).
14
+ * Interaction states (ADR-0008): `:hover`/`:active` repoint `background` from the per-state tokens;
15
+ * `:focus-visible` draws the SHARED focus ring (ADR-0009 — the fleet `--md-sys-color-focus-ring`/`--md-sys-state-focus-ring-*`,
16
+ * keyboard-only, layout-neutral `outline`). Forced-colors keeps the ink/border (the ring survives via the
17
+ * token layer's `--md-sys-color-focus-ring → Highlight` mapping). The reflected `disabled` attribute makes the host inert.
18
+ *
19
+ * Standalone stylesheet — linked via the host page / component-styles barrel (Phase 2); NEVER injected from
20
+ * button.ts (behaviour-only `.ts`, no runtime style injection — plan §2).
21
+ */
22
+
23
+ /* ════════════════ [1] TOKEN BLOCK — :where(ui-button) declares --ui-button-* ════════════════ */
24
+
25
+ :where(ui-button) {
26
+ /* Colour channel (default family = primary). solid = filled (accent bg, on-accent ink). Per-state bg from
27
+ the DEDICATED interaction roles (--md-sys-color-primary · -hover · -active) — distinct steps in BOTH schemes, a role
28
+ step NOT a color-mix (ADR-0008 + its tok-states amendment that split the LIGHT --md-sys-color-primary-650 collapse). */
29
+ --ui-button-bg: var(--md-sys-color-primary);
30
+ --ui-button-bg-hover: var(--md-sys-color-primary-hover);
31
+ --ui-button-bg-active: var(--md-sys-color-primary-active);
32
+ --ui-button-ink: var(--md-sys-color-primary-on-primary);
33
+ --ui-button-border: transparent;
34
+
35
+ /* Geometry — off the s6 dimensional ramp (default size = md). [size] repoints below. */
36
+ --ui-button-height: var(--md-sys-height-md);
37
+ --ui-button-font: var(--md-sys-font-md);
38
+ --ui-button-gap: var(--md-sys-gap-md);
39
+ --ui-button-icon: var(--md-sys-icon-md); /* content-icon = the shared §1-SET icon table (ADR-0035 4a hoist, dimensions.css), per-[scale]-tier; was pow(scale,0.58) */
40
+ --ui-button-glyph: var(--ui-button-font); /* inline-affordance (caret) ramp = font (--ui-glyph-ratio 1, §4.1) */
41
+ }
42
+
43
+ /* variant → colour roles (the channel pattern, tokens.md). Per-state bg steps the matching ladder:
44
+ soft = CONTAINER ladder (-container-low · -container · -container-high); ghost = TEXT (transparent idle,
45
+ a low container WASH on hover/active — ADR-0008's ghost wash). No color-mix; every value is a role. */
46
+ :where(ui-button[variant='soft']) {
47
+ --ui-button-bg: var(--md-sys-color-primary-container-low);
48
+ --ui-button-bg-hover: var(--md-sys-color-primary-container);
49
+ --ui-button-bg-active: var(--md-sys-color-primary-container-high);
50
+ --ui-button-ink: var(--md-sys-color-primary-high); /* accent label ink — reads as a primary-family action, not neutral text */
51
+ }
52
+ :where(ui-button[variant='ghost']) {
53
+ --ui-button-bg: transparent;
54
+ --ui-button-bg-hover: var(--md-sys-color-primary-container-low);
55
+ --ui-button-bg-active: var(--md-sys-color-primary-container);
56
+ --ui-button-ink: var(--md-sys-color-primary-high); /* accent label ink (same as soft) — the transparent/wash variant still reads as primary */
57
+ }
58
+
59
+ /* size → dimensional ramp */
60
+ :where(ui-button[size='sm']) {
61
+ --ui-button-height: var(--md-sys-height-sm);
62
+ --ui-button-font: var(--md-sys-font-sm);
63
+ --ui-button-gap: var(--md-sys-gap-sm);
64
+ --ui-button-icon: var(--md-sys-icon-sm); /* §1-SET icon table (ADR-0035) */
65
+ }
66
+ :where(ui-button[size='lg']) {
67
+ --ui-button-height: var(--md-sys-height-lg);
68
+ --ui-button-font: var(--md-sys-font-lg);
69
+ --ui-button-gap: var(--md-sys-gap-lg);
70
+ --ui-button-icon: var(--md-sys-icon-lg); /* §1-SET icon table (ADR-0035) */
71
+ }
72
+
73
+ /* disabled → muted neutral roles (overrides the family). HOLDS at idle: -bg-hover/-bg-active repoint to the
74
+ same muted neutral so no path lifts (and :hover/:active never match — the styles block makes the host
75
+ pointer-inert; ADR-0008). */
76
+ :where(ui-button[disabled]) {
77
+ --ui-button-bg: var(--md-sys-color-neutral-surface-high);
78
+ --ui-button-bg-hover: var(--md-sys-color-neutral-surface-high);
79
+ --ui-button-bg-active: var(--md-sys-color-neutral-surface-high);
80
+ --ui-button-ink: var(--md-sys-color-neutral-on-surface-variant);
81
+ }
82
+
83
+ /* ════════════════ [2] STYLES BLOCK — @scope (ui-button) consumes ONLY --ui-button-* ════════════════ */
84
+
85
+ @scope (ui-button) {
86
+ :scope {
87
+ display: inline-grid;
88
+ grid-template-columns: 1fr; /* bare label — slotless */
89
+ align-items: center;
90
+ box-sizing: border-box;
91
+
92
+ block-size: var(--ui-button-height); /* the vertical lever — geometry.md */
93
+ padding-block: 0; /* NEVER block-padding */
94
+ padding-inline: calc(var(--ui-button-height) / 2); /* slotless edge = h/2 */
95
+ min-inline-size: var(--ui-button-height); /* frame: icon-only ≈ square */
96
+
97
+ font-size: var(--ui-button-font);
98
+ line-height: var(--md-sys-control-line-height); /* single-line control standard — ADR-0036; tight line box centered in the fixed frame */
99
+ white-space: nowrap; /* a control label NEVER wraps (Kim, 2026-07-08 — the gallery toolbar's two-line
100
+ "More actions"); the ADR-0036 single-line frame assumes one line, so wrapping
101
+ was always an overflow of the control's own contract. Inherits into the label
102
+ wrapper below for free — ellipsis-on-constraint is completed there (ADR-0133). */
103
+ background: var(--ui-button-bg);
104
+ color: var(--ui-button-ink);
105
+ border: 1px solid var(--ui-button-border);
106
+ border-radius: calc(var(--ui-button-height) / 2); /* pill radius = h/2 */
107
+ cursor: pointer;
108
+ -webkit-user-select: none; /* WebKit/Safari still needs the prefix — the label is a control surface, not selectable text */
109
+ user-select: none;
110
+ }
111
+
112
+ /* The label wrapper (ADR-0133) — the real element button.ts adopts the label region into, so
113
+ `text-overflow` has a real box to attach to (anonymous grid text has none). `white-space: nowrap`
114
+ already lives on `:scope` above and inherits here for free — only the two CLIPPING properties are
115
+ needed. `min-inline-size: 0` overrides the grid item's default `min-width: auto` (its content's
116
+ intrinsic size), which would otherwise refuse to shrink below the label's full width and defeat the
117
+ clip — the one addition ADR-0106's block-level two-leg pattern never needed, host-as-grid's own. */
118
+ :scope > [data-part='label'] {
119
+ overflow: hidden;
120
+ text-overflow: ellipsis;
121
+ min-inline-size: 0;
122
+ }
123
+
124
+ /* Anatomy (ADR-0006, extended by ADR-0012): host-as-grid with three POSITION regions — an OPTIONAL leading
125
+ [slot=leading] adornment, the LABEL (the default/unnamed children — the accessible name), and an OPTIONAL
126
+ trailing [slot=trailing] adornment — each presence-driven via :has(). Five structures:
127
+ [label] · [leading | label] · [label | trailing] · [leading | label | trailing] · [icon-only, no label]
128
+ (the last is an explicit author opt-in, `[icon-only]` — CSS cannot detect an empty/text-node label on its
129
+ own; see the `:scope[icon-only]` rule below, geometry.md "icon-only (no label) → square"). Each adornment
130
+ gets a square, icon-sized CELL with edge-pad ½(h−icon); a bare (slotless) edge stays h/2; the column-gap is
131
+ the one density-bearing quantity (gap = font/2 × density).
132
+ POSITION (the slot) PLACES; ROLE (`data-role` on the node — icon · caret now, tag · badge later) SIZES the
133
+ glyph (ADR-0012 / geometry-sizing-spec §1.4, §4.6 — frame ∝ height vs rhythm ∝ font). Adornments are
134
+ decorative (aria-hidden); popup/disclosure meaning belongs on the host via ARIA (ElementInternals). */
135
+
136
+ /* The CELL — both adornment slots get the SAME square, icon-sized cell (border-box, so a role's inset stays
137
+ WITHIN the icon-sized cell). The cell stays icon-sized for BOTH roles → the grid column is icon-wide and
138
+ the centering law (slot edge-pad ½(h−icon)) holds whichever role sits in it. */
139
+ :scope > [slot='leading'],
140
+ :scope > [slot='trailing'] {
141
+ inline-size: var(--ui-button-icon);
142
+ block-size: var(--ui-button-icon); /* the square slot, icon-sized — the CELL */
143
+ box-sizing: border-box; /* padding insets the glyph WITHIN the icon-sized cell (the caret centering) */
144
+ }
145
+
146
+ /* ROLE = glyph size (the "position places, role sizes" split). The CELL above stays icon-sized for both
147
+ roles; only the GLYPH inside differs by role:
148
+ • icon — a content icon (FRAME family) FILLS the icon-sized cell (= --ui-button-icon).
149
+ • caret — an inline affordance (RHYTHM family) is sized to the FONT (--ui-button-glyph = font) and
150
+ CENTERED in the icon-sized cell by a ½(icon−font) inset, so its glyph lands at the EMERGENT ½(h−font)
151
+ edge — never --ui-ind (an inline affordance at icon size is the named oversize "button caret" bug,
152
+ geometry.md §"Affordance vs content-icon"; locked by the BTN-CARET probe). */
153
+ :scope > [data-role='icon'] {
154
+ padding: 0; /* fills its icon-sized cell */
155
+ }
156
+ :scope > [data-role='caret'] {
157
+ padding: calc((var(--ui-button-icon) - var(--ui-button-glyph)) / 2); /* inset the font glyph, centered in the icon cell */
158
+ }
159
+
160
+ /* [leading | label] (no trailing): auto 1fr — leading slot edge ½(h−icon), trailing label edge h/2.
161
+ :not([icon-only]) — the icon-only structure below is the mutually-exclusive fifth anatomy. */
162
+ :scope:has(> [slot='leading']):not(:has(> [slot='trailing'])):not([icon-only]) {
163
+ grid-template-columns: auto 1fr;
164
+ column-gap: var(--ui-button-gap);
165
+ padding-inline-start: calc((var(--ui-button-height) - var(--ui-button-icon)) / 2);
166
+ padding-inline-end: calc(var(--ui-button-height) / 2);
167
+ }
168
+
169
+ /* [label | trailing] (no leading): 1fr auto — leading label edge h/2, trailing slot edge ½(h−icon).
170
+ :not([icon-only]) — same exclusion. */
171
+ :scope:has(> [slot='trailing']):not(:has(> [slot='leading'])):not([icon-only]) {
172
+ grid-template-columns: 1fr auto;
173
+ column-gap: var(--ui-button-gap);
174
+ padding-inline-start: calc(var(--ui-button-height) / 2);
175
+ padding-inline-end: calc((var(--ui-button-height) - var(--ui-button-icon)) / 2);
176
+ }
177
+
178
+ /* [leading | label | trailing]: auto 1fr auto — both adornment edges ½(h−icon), one gap rhythm on each
179
+ side. :not([icon-only]) — same exclusion. */
180
+ :scope:has(> [slot='leading']):has(> [slot='trailing']):not([icon-only]) {
181
+ grid-template-columns: auto 1fr auto;
182
+ column-gap: var(--ui-button-gap);
183
+ padding-inline-start: calc((var(--ui-button-height) - var(--ui-button-icon)) / 2);
184
+ padding-inline-end: calc((var(--ui-button-height) - var(--ui-button-icon)) / 2);
185
+ }
186
+
187
+ /* [icon-only] (no label): the geometry law's FIFTH structure (geometry.md "icon-only (no label) →
188
+ square") — a real slotted adornment with no label content at all. CSS cannot detect an empty/
189
+ text-node label on its own (`:has()` only matches elements, so a bare text-node label is invisible
190
+ to it), so this is an explicit author opt-in (the reflected `icon-only` attribute, button.ts).
191
+ `inline-size` is set EXPLICITLY (mirroring `block-size` exactly) rather than left intrinsic: under
192
+ `box-sizing: border-box` an EXPLICIT size makes border eat into the content box on BOTH axes
193
+ identically, giving a byte-exact square regardless of border width. A literal ½(h−icon) PADDING
194
+ would instead let intrinsic sizing add the border ON TOP of content+padding (no reinterpretation
195
+ without an explicit size to reinterpret), overshooting the square by the border width — the bug
196
+ this structure closes. `justify-content: center` centers the single icon-sized column the SAME way
197
+ the pre-existing `align-items: center` (base :scope rule) already centers it on the block axis — no
198
+ literal padding needed; the border cancels out of the maths, so the rendered inset still lands at
199
+ the law's ½(h−icon), measured from the outer edge. No column-gap (no label track to gap against).
200
+ Assumes a single adornment (leading OR trailing, not both) — the documented icon-only pattern. */
201
+ :scope[icon-only] {
202
+ grid-template-columns: auto;
203
+ inline-size: var(--ui-button-height);
204
+ padding-inline: 0;
205
+ justify-content: center;
206
+ }
207
+
208
+ /* Interaction states (ADR-0008) — repoint ONLY `background`, from the per-state ladder tokens (the geometry
209
+ law is untouched). Disabled holds at idle: the disabled host is pointer-inert (below), so :hover/:active
210
+ never match it. */
211
+ :scope:hover {
212
+ background: var(--ui-button-bg-hover);
213
+ }
214
+ :scope:active {
215
+ background: var(--ui-button-bg-active);
216
+ }
217
+
218
+ /* Focus ring (ADR-0009) — the SHARED fleet ring: `:focus-visible` (KEYBOARD-only, no ring on a mouse click)
219
+ draws a layout-neutral `outline` from the shared tokens. These are the ONE deliberate exception to the
220
+ "consume only --ui-button-*" rule: a focus ring is a fleet constant (read directly, NOT repointed through
221
+ the component chain) so every control draws the identical ring. `outline`/`outline-offset` do not
222
+ participate in box geometry — the geometry law stays intact. (Disabled is removed from the tab order by
223
+ the tabbable trait, so a disabled host never draws the ring.) */
224
+ :scope:focus-visible {
225
+ outline: var(--md-sys-state-focus-ring-width) solid var(--md-sys-color-focus-ring);
226
+ outline-offset: var(--md-sys-state-focus-ring-offset);
227
+ }
228
+
229
+ /* Motion (ADR-0008 / interaction-states standard) — transition the state-PAINT properties ONLY
230
+ (background/colour/border colour), enumerated (never `transition: all`). Geometry is NEVER transitioned: a
231
+ [scale]/[size]/[density] change must SNAP — animating the --ui ramp fights the sizing law (geometry.md) and
232
+ reads as jank — and the keyboard focus ring stays instant (outline is omitted from the list). The rule is
233
+ gated behind the :state(ready) custom state, set in button.ts ONE FRAME PAST first paint, so the upgrade/
234
+ first-paint styling snaps in and only SUBSEQUENT hover/active/variant changes animate (no first-render flash). */
235
+ :scope:state(ready) {
236
+ transition:
237
+ background-color var(--md-sys-motion-duration-fast) var(--md-sys-motion-easing-standard),
238
+ color var(--md-sys-motion-duration-fast) var(--md-sys-motion-easing-standard),
239
+ border-color var(--md-sys-motion-duration-fast) var(--md-sys-motion-easing-standard);
240
+ }
241
+ @media (prefers-reduced-motion: reduce) {
242
+ :scope:state(ready) {
243
+ transition: none; /* accessibility (non-negotiable) — reduced motion zeroes the state transitions */
244
+ }
245
+ }
246
+
247
+ /* disabled host — pointer-inert (the reflected `disabled` attribute); makes :hover/:active inert so the
248
+ state overlay holds at idle */
249
+ :scope:is([disabled]) {
250
+ pointer-events: none;
251
+ cursor: default;
252
+ }
253
+
254
+ /* forced-colors — keep the ink + border visible (the label/outline must not vanish). The focus ring
255
+ survives for free: `--md-sys-color-focus-ring` carries the token layer's `→ Highlight` WHCM mapping, so the
256
+ `:focus-visible` outline above resolves to the system focus colour with no per-control rule. */
257
+ @media (forced-colors: active) {
258
+ :scope {
259
+ color: ButtonText;
260
+ border-color: ButtonText;
261
+ }
262
+ }
263
+ }
@@ -0,0 +1,61 @@
1
+ import { UIElement, type ReactiveProps } from '../../dom/index.js';
2
+ declare const props: {
3
+ variant: {
4
+ reflect: true;
5
+ type: import("../../index.js").PropType<"solid" | "soft" | "ghost">;
6
+ default: "solid" | "soft" | "ghost";
7
+ attribute?: string | false;
8
+ };
9
+ size: {
10
+ reflect: true;
11
+ type: import("../../index.js").PropType<"sm" | "md" | "lg">;
12
+ default: "sm" | "md" | "lg";
13
+ attribute?: string | false;
14
+ };
15
+ disabled: {
16
+ reflect: true;
17
+ type: import("../../index.js").PropType<boolean>;
18
+ default: boolean;
19
+ attribute?: string | false;
20
+ };
21
+ iconOnly: {
22
+ reflect: true;
23
+ attribute: string;
24
+ type: import("../../index.js").PropType<boolean>;
25
+ default: boolean;
26
+ };
27
+ };
28
+ export interface UIButtonElement extends ReactiveProps<typeof props> {
29
+ }
30
+ export declare class UIButtonElement extends UIElement {
31
+ #private;
32
+ static props: {
33
+ variant: {
34
+ reflect: true;
35
+ type: import("../../index.js").PropType<"solid" | "soft" | "ghost">;
36
+ default: "solid" | "soft" | "ghost";
37
+ attribute?: string | false;
38
+ };
39
+ size: {
40
+ reflect: true;
41
+ type: import("../../index.js").PropType<"sm" | "md" | "lg">;
42
+ default: "sm" | "md" | "lg";
43
+ attribute?: string | false;
44
+ };
45
+ disabled: {
46
+ reflect: true;
47
+ type: import("../../index.js").PropType<boolean>;
48
+ default: boolean;
49
+ attribute?: string | false;
50
+ };
51
+ iconOnly: {
52
+ reflect: true;
53
+ attribute: string;
54
+ type: import("../../index.js").PropType<boolean>;
55
+ default: boolean;
56
+ };
57
+ };
58
+ protected connected(): void;
59
+ protected disconnected(): void;
60
+ }
61
+ export {};