@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,159 @@
1
+ // color.ts — pure OKLCH↔sRGB numerics + gamut mapping + the colorCodecOptions codec factory (LLD-C3,
2
+ // color-picker.lld.md · ADR-0123 cl.2/cl.7 / SPEC-R3). Promoted from the adia `color-picker.class.js`
3
+ // prior art (Björn Ottosson's OKLCH↔sRGB constants + its binary-search gamut map) — NEVER ported: no
4
+ // app-specific generation-constraint math (maxChroma/minL/hueDriftMax/baseHue stay out of the fleet API,
5
+ // ADR-0123 Alternatives).
6
+ //
7
+ // Import-free (no DOM) — unit-testable without a DOM and reusable by the `type=color` text-field leg
8
+ // (SPEC-R3 AC5).
9
+ export const MAX_CHROMA = 0.4;
10
+ // ── OKLCH ↔ sRGB conversion (Björn Ottosson's constants) ────────────────────────────────────────
11
+ function oklchToOklab(L, C, H) {
12
+ const hRad = (H * Math.PI) / 180;
13
+ return { L, a: C * Math.cos(hRad), b: C * Math.sin(hRad) };
14
+ }
15
+ function oklabToLinearSrgb(L, a, b) {
16
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
17
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
18
+ const s_ = L - 0.0894841775 * a - 1.291485548 * b;
19
+ const l = l_ * l_ * l_;
20
+ const m = m_ * m_ * m_;
21
+ const s = s_ * s_ * s_;
22
+ return [
23
+ 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
24
+ -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
25
+ -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,
26
+ ];
27
+ }
28
+ function linearToSrgb(c) {
29
+ return c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
30
+ }
31
+ function srgbToLinear(c) {
32
+ return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
33
+ }
34
+ /** Convert an OKLCH triple to sRGB (0–1, clamped) — no gamut mapping applied. */
35
+ export function oklchToRgb(L, C, H) {
36
+ const { a, b } = oklchToOklab(L, C, H);
37
+ const [lr, lg, lb] = oklabToLinearSrgb(L, a, b);
38
+ return [
39
+ Math.max(0, Math.min(1, linearToSrgb(lr))),
40
+ Math.max(0, Math.min(1, linearToSrgb(lg))),
41
+ Math.max(0, Math.min(1, linearToSrgb(lb))),
42
+ ];
43
+ }
44
+ /** Format sRGB (0–1 channels) as a `#rrggbb` hex string. */
45
+ export function rgbToHex(r, g, b) {
46
+ const h = (c) => Math.round(c * 255).toString(16).padStart(2, '0');
47
+ return `#${h(r)}${h(g)}${h(b)}`;
48
+ }
49
+ /** Convert an OKLCH triple directly to a `#rrggbb` hex string (no gamut mapping — call gamutMapChroma first). */
50
+ export function oklchToHex(L, C, H) {
51
+ const [r, g, b] = oklchToRgb(L, C, H);
52
+ return rgbToHex(r, g, b);
53
+ }
54
+ /** Parse a `#rgb`/`#rrggbb` hex string to an OKLCH triple. Assumes a well-formed 3/6-digit hex (validated by the caller). */
55
+ export function hexToOklch(hex) {
56
+ let h = hex.replace('#', '');
57
+ if (h.length === 3)
58
+ h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
59
+ const r = srgbToLinear(parseInt(h.slice(0, 2), 16) / 255);
60
+ const g = srgbToLinear(parseInt(h.slice(2, 4), 16) / 255);
61
+ const b = srgbToLinear(parseInt(h.slice(4, 6), 16) / 255);
62
+ const l_ = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
63
+ const m_ = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
64
+ const s_ = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
65
+ const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
66
+ const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
67
+ const bv = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
68
+ const C = Math.sqrt(a * a + bv * bv);
69
+ let H = (Math.atan2(bv, a) * 180) / Math.PI;
70
+ if (H < 0)
71
+ H += 360;
72
+ return { L, C, H };
73
+ }
74
+ // ── Gamut mapping (binary-search chroma reduction, the adia mechanism) ──────────────────────────
75
+ function isInGamut(r, g, b) {
76
+ const e = 0.001;
77
+ return r >= -e && r <= 1 + e && g >= -e && g <= 1 + e && b >= -e && b <= 1 + e;
78
+ }
79
+ /**
80
+ * Reduce chroma until the OKLCH triple falls inside the sRGB gamut (8-iteration binary search — a
81
+ * ~MAX_CHROMA/256 chroma resolution, imperceptible and deterministic; the adia constant, LLD §12 risk).
82
+ * A no-op (returns `C` unchanged) when the triple is already in-gamut.
83
+ */
84
+ export function gamutMapChroma(L, C, H) {
85
+ const { a, b } = oklchToOklab(L, C, H);
86
+ const [lr, lg, lb] = oklabToLinearSrgb(L, a, b);
87
+ if (isInGamut(linearToSrgb(lr), linearToSrgb(lg), linearToSrgb(lb)))
88
+ return C;
89
+ let lo = 0;
90
+ let hi = C;
91
+ for (let i = 0; i < 8; i++) {
92
+ const mid = (lo + hi) / 2;
93
+ const { a: ma, b: mb } = oklchToOklab(L, mid, H);
94
+ const [mr, mg, mbb] = oklabToLinearSrgb(L, ma, mb);
95
+ if (isInGamut(linearToSrgb(mr), linearToSrgb(mg), linearToSrgb(mbb)))
96
+ lo = mid;
97
+ else
98
+ hi = mid;
99
+ }
100
+ return lo;
101
+ }
102
+ // ── Parsing helpers ──────────────────────────────────────────────────────────────────────────────
103
+ const HEX_RE = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
104
+ // Accepts numeric, percent, `NaN`, and `none` (CSS Color 4 "powerless") channels — the adia lenient parser.
105
+ const OKLCH_RE = /^oklch\(\s*([\d.]+%?|NaN|none)\s+([\d.]+%?|NaN|none)\s+([\d.]+|NaN|none)\s*\)$/i;
106
+ // CSS Color 4 percentage reference ranges for oklch(): L 100% → 1; C 100% → this fleet's MAX_CHROMA
107
+ // (0.4, the adia convention — chroma has no fixed real-world ceiling, so the spec leaves the 100%
108
+ // reference implementation-defined). H never takes a percentage (an angle) — OKLCH_RE's third group
109
+ // has no `%?`, so this function is never called with isL semantics for hue.
110
+ function parseOklchChannel(s, isL) {
111
+ if (s === 'none' || /^NaN$/i.test(s))
112
+ return 0;
113
+ if (s.endsWith('%'))
114
+ return (+s.slice(0, -1) / 100) * (isL ? 1 : MAX_CHROMA);
115
+ return +s;
116
+ }
117
+ /** Parse any accepted color syntax (`#rgb`/`#rrggbb`/`oklch(L C H)`) into an OKLCH triple, or `null` if unparseable. */
118
+ export function parseColor(input) {
119
+ const trimmed = input.trim();
120
+ if (HEX_RE.test(trimmed))
121
+ return hexToOklch(trimmed);
122
+ const m = OKLCH_RE.exec(trimmed);
123
+ if (m) {
124
+ return {
125
+ L: parseOklchChannel(m[1], true),
126
+ C: parseOklchChannel(m[2], false),
127
+ H: parseOklchChannel(m[3], false),
128
+ };
129
+ }
130
+ return null;
131
+ }
132
+ /** Serialize an OKLCH triple through `format` — gamut-mapped sRGB hex for `'hex'`, authored-chroma `oklch(L C H)` for `'oklch'`. */
133
+ export function serializeColor(oklch, format) {
134
+ if (format === 'oklch') {
135
+ return `oklch(${oklch.L.toFixed(2)} ${oklch.C.toFixed(3)} ${Math.round(oklch.H)})`;
136
+ }
137
+ const mappedC = gamutMapChroma(oklch.L, oklch.C, oklch.H);
138
+ return oklchToHex(oklch.L, mappedC, oklch.H);
139
+ }
140
+ /**
141
+ * The color-codec dialect factory (LLD-C3): `parse(display) → canonical | null` accepts any recognized
142
+ * syntax and re-serializes into the requested `format`; `format(canonical) → canonical` re-normalizes
143
+ * (idempotent — parses then re-serializes in the same format). Pure — no DOM (SPEC-R3 AC5); reused as
144
+ * plain functions by the standalone control AND wired through the `valueCodec` trait by the `type=color`
145
+ * text-field leg (LLD-C9).
146
+ */
147
+ export function colorCodecOptions(format) {
148
+ return {
149
+ parse(display) {
150
+ const oklch = parseColor(display);
151
+ return oklch ? serializeColor(oklch, format) : null;
152
+ },
153
+ format(value) {
154
+ const oklch = parseColor(value);
155
+ return oklch ? serializeColor(oklch, format) : value;
156
+ },
157
+ errorMessage: 'Please enter a valid color.',
158
+ };
159
+ }
@@ -0,0 +1,151 @@
1
+ /* column.css — ui-column, the single-file component stylesheet (ADR-0003). The vertical layout primitive —
2
+ * `ui-row`'s sibling with the main axis flipped to the block axis. Two clearly-SECTIONED blocks:
3
+ *
4
+ * [1] TOKEN BLOCK — `:where(ui-column)` (specificity 0,0,0) DECLARES the `--ui-column-*` flex chain from the
5
+ * shared layout grammar: the four reflected `flexProps` attributes (`align`/`justify`/`gap`/`wrap`) are
6
+ * mapped 1:1 onto a CSS flex value (the literal-union → CSS-keyword repoint, ADR-0016 cl.1). `gap` reads
7
+ * the density-responsive `--md-sys-space-*` ladder (ADR-0015 cl.4), NEVER a control dimension. The defaults
8
+ * are the `flexProps` defaults (align=start, justify=start, gap=none, wrap=nowrap); each non-default
9
+ * attribute value repoints its token.
10
+ * [2] STYLES BLOCK — `@scope (ui-column)` CONSUMES the `--ui-column-*` flex tokens, plus the opt-in
11
+ * `:scope[stretch]` sizing escape-hatch (`width: stretch` — a fill-available fallback cascade that
12
+ * can't be tokenized). `display: flex` with `flex-direction: column` — the tag's IDENTITY (the main
13
+ * axis is the block axis; not a prop, ADR-0016 cl.2). A `@container inline-size` reflow rule, GATED on
14
+ * `:scope[reflow='auto']` (ADR-0096), mirrors `ui-row` (which stacks to a column under a NARROW container)
15
+ * with the axis flipped: under a WIDE container a column opted into `reflow="auto"` spreads its children
16
+ * into a row — the canonical "switcher". `reflow` defaults to `locked` (column.ts), so a bare `ui-column`
17
+ * never matches the rule (ADR-0005: a default is never reflected as an attribute) — reflowing on the
18
+ * container's width with NO breakpoint props (ADR-0016 cl.4) is now opt-in, not unconditional. The column
19
+ * establishes NO query container of its own (ADR-0100 — it is intrinsically sized, so it can never
20
+ * safely be one); the rule resolves against the nearest EXTERNALLY-SIZED ancestor boundary instead.
21
+ * NO control height (geometry.md Container/layout class — block-size is content-driven; spacing rides
22
+ * `--md-sys-space` × `[density]`, never `--md-sys-height-*`). A forced-colors block drops any tonal wash.
23
+ *
24
+ * The SURFACE (elevation/brightness → `--ui-container-bg`/`-tint`) is painted by the shared
25
+ * controls/_surface/container.css on `:where(…, ui-column, …)`; this sheet holds ZERO colour opinion (no raw
26
+ * `--md-sys-color-*` role anywhere — role-purity, ADR-0008). Standalone stylesheet — linked via the component-styles
27
+ * barrel (wired in s12); NEVER injected from column.ts (behaviour-only `.ts` — plan §2).
28
+ */
29
+
30
+ /* ════════════════ [1] TOKEN BLOCK — :where(ui-column) declares --ui-column-* ════════════════ */
31
+
32
+ :where(ui-column) {
33
+ /* The flex grammar, defaulted to the column-specific defaults (ADR-0030: align defaults to stretch — the
34
+ direction-appropriate cross-axis default for a column; flexProps.align default stays start for row).
35
+ Each maps 1:1 onto a CSS flex property consumed in the @scope block; the [attr] selectors below
36
+ repoint the NON-DEFAULT keywords. A default is NOT reflected as an attribute (ADR-0005), so the base
37
+ token carries the default value — the prop default and the CSS base token must match. */
38
+ --ui-column-align: stretch; /* align (cross axis = inline) → align-items: stretch (ADR-0030 flip start→stretch) */
39
+ --ui-column-justify: start; /* justify (main axis = block) → justify-content; box-alignment start (ADR-0039) */
40
+ --ui-column-gap: var(--md-sys-space-none); /* gap → the density-responsive --md-sys-space ladder (ADR-0015 cl.4) */
41
+ --ui-column-wrap: nowrap; /* wrap → flex-wrap (boolean presence repoints below) */
42
+ }
43
+
44
+ /* align → align-items (stretch = the new default above; start is now a non-default needing its own repoint).
45
+ ADR-0030: `start` gains a repoint rule; the now-redundant `stretch` rule is removed (stretch = the base).
46
+ `center` is NOT allowed on ui-column (Kim's directive — it dropped from column.ts's align enum): NO
47
+ [align='center'] repoint exists, so a stray `align="center"` attribute has no effect and the column stays
48
+ at its `stretch` base (children fill the width). Only start/end/baseline are the non-default repoints. */
49
+ :where(ui-column[align='start']) {
50
+ --ui-column-align: start; /* start is a non-default: the [align='start'] repoint (box-alignment start — ADR-0039) */
51
+ }
52
+ :where(ui-column[align='end']) {
53
+ --ui-column-align: end; /* box-alignment end (ADR-0039) */
54
+ }
55
+ :where(ui-column[align='baseline']) {
56
+ --ui-column-align: baseline;
57
+ }
58
+
59
+ /* justify → justify-content (between/around/evenly → space-*; start is the box-alignment default — ADR-0039) */
60
+ :where(ui-column[justify='center']) {
61
+ --ui-column-justify: center;
62
+ }
63
+ :where(ui-column[justify='end']) {
64
+ --ui-column-justify: end; /* box-alignment end (ADR-0039) */
65
+ }
66
+ :where(ui-column[justify='between']) {
67
+ --ui-column-justify: space-between;
68
+ }
69
+ :where(ui-column[justify='around']) {
70
+ --ui-column-justify: space-around;
71
+ }
72
+ :where(ui-column[justify='evenly']) {
73
+ --ui-column-justify: space-evenly;
74
+ }
75
+
76
+ /* gap → the --md-sys-space ladder (none = the var(--md-sys-space-none) default above). The step vocabulary mirrors the
77
+ flexProps `gap` union 1:1; --md-sys-space-* carries var(--md-sys-density), so the gap responds to a subtree [density]. */
78
+ :where(ui-column[gap='xs']) {
79
+ --ui-column-gap: var(--md-sys-space-xs);
80
+ }
81
+ :where(ui-column[gap='sm']) {
82
+ --ui-column-gap: var(--md-sys-space-sm);
83
+ }
84
+ :where(ui-column[gap='md']) {
85
+ --ui-column-gap: var(--md-sys-space-md);
86
+ }
87
+ :where(ui-column[gap='lg']) {
88
+ --ui-column-gap: var(--md-sys-space-lg);
89
+ }
90
+ :where(ui-column[gap='xl']) {
91
+ --ui-column-gap: var(--md-sys-space-xl);
92
+ }
93
+ :where(ui-column[gap='2xl']) {
94
+ --ui-column-gap: var(--md-sys-space-2xl);
95
+ }
96
+
97
+ /* wrap → flex-wrap (boolean presence: the reflected `wrap` attribute is present ⇒ wrap onto multiple lines) */
98
+ :where(ui-column[wrap]) {
99
+ --ui-column-wrap: wrap;
100
+ }
101
+
102
+ /* ════════════════ [2] STYLES BLOCK — @scope (ui-column) consumes ONLY --ui-column-* ════════════════ */
103
+
104
+ @scope (ui-column) {
105
+ :scope {
106
+ display: flex;
107
+ flex-direction: column; /* the tag's IDENTITY — the main axis is the block axis (ADR-0016 cl.2), not a prop */
108
+ align-items: var(--ui-column-align);
109
+ justify-content: var(--ui-column-justify);
110
+ gap: var(--ui-column-gap);
111
+ flex-wrap: var(--ui-column-wrap);
112
+ box-sizing: border-box;
113
+ /* NO control height — a layout primitive (geometry.md Container/layout class): block-size is content-driven,
114
+ spacing rides --md-sys-space × [density]. It never reads --md-sys-height-* (that is the control band's lever). */
115
+ }
116
+
117
+ /* stretch → the host FILLS its parent's available inline size (`width: stretch`). Opt-in, default off — a
118
+ column shrink-wraps to content otherwise. Used on a ROOT layout box (e.g. the A2UI canvas root) so it
119
+ fills its artboard instead of shrink-wrapping. The three declarations are a fill-available fallback
120
+ cascade — the LAST valid one wins per engine (unprefixed `stretch` is modern CSS; `-webkit-fill-available`
121
+ / `-moz-available` cover older WebKit / Firefox), so it fills cross-engine. A single custom-prop token
122
+ can't hold this cascade, so this is the one sizing rule the styles block owns directly. */
123
+ :scope[stretch] {
124
+ width: -webkit-fill-available;
125
+ width: -moz-available;
126
+ width: stretch;
127
+ }
128
+
129
+ /* Container-query intrinsic responsiveness (ADR-0016 cl.4), PROP-GATED by `reflow` (ADR-0096) — mirrors ui-row
130
+ (which stacks to a column under a NARROW container) with the axis flipped: when the nearest EXTERNALLY-SIZED
131
+ ancestor boundary (ADR-0100 — NOT the column itself; an intrinsically-sized primitive can never safely
132
+ establish `container-type: inline-size`, see container.css's banner) is WIDE, a column with `reflow="auto"`
133
+ spreads its children into a row — the canonical "switcher". The selector
134
+ is `:scope[reflow='auto']`, NOT bare `:scope`: a default value is never reflected as an attribute (ADR-0005),
135
+ so an unadorned `ui-column` can never match this rule — locked by construction. `reflow` defaults to `locked`
136
+ (column.ts) so the switch is OPT-IN, reachable from the catalog alone (ADR-0096 cl.1/2/4). Reflows on the
137
+ container's width, NOT the viewport (no breakpoint props); the cross-engine smoke resizes the wrapper. */
138
+ @container (min-width: 30rem) {
139
+ :scope[reflow='auto'] {
140
+ flex-direction: row;
141
+ }
142
+ }
143
+
144
+ /* forced-colors (WHCM) — the surface survives as a system colour via the shared container.css role layer; this
145
+ belt-and-braces block guarantees no tonal wash paints over system text on the layout box. */
146
+ @media (forced-colors: active) {
147
+ :scope {
148
+ background-image: none;
149
+ }
150
+ }
151
+ }
@@ -0,0 +1,107 @@
1
+ import { UIContainerElement } from '../../dom/container.js';
2
+ import type { ReactiveProps } from '../../dom/index.js';
3
+ declare const props: {
4
+ align: {
5
+ reflect: true;
6
+ type: import("../../index.js").PropType<"end" | "start" | "stretch" | "baseline">;
7
+ default: "end" | "start" | "stretch" | "baseline";
8
+ attribute?: string | false;
9
+ };
10
+ stretch: {
11
+ reflect: true;
12
+ type: import("../../index.js").PropType<boolean>;
13
+ default: boolean;
14
+ attribute?: string | false;
15
+ };
16
+ reflow: {
17
+ reflect: true;
18
+ type: import("../../index.js").PropType<"auto" | "locked">;
19
+ default: "auto" | "locked";
20
+ attribute?: string | false;
21
+ };
22
+ justify: {
23
+ reflect: true;
24
+ type: import("../../index.js").PropType<"end" | "start" | "center" | "between" | "around" | "evenly">;
25
+ default: "end" | "start" | "center" | "between" | "around" | "evenly";
26
+ attribute?: string | false;
27
+ };
28
+ gap: {
29
+ reflect: true;
30
+ type: import("../../index.js").PropType<"none" | "sm" | "md" | "lg" | "xs" | "xl" | "2xl">;
31
+ default: "none" | "sm" | "md" | "lg" | "xs" | "xl" | "2xl";
32
+ attribute?: string | false;
33
+ };
34
+ wrap: {
35
+ reflect: true;
36
+ type: import("../../index.js").PropType<boolean>;
37
+ default: boolean;
38
+ attribute?: string | false;
39
+ };
40
+ elevation: {
41
+ reflect: true;
42
+ type: import("../../index.js").PropType<"0" | "1" | "2" | "3" | "-3" | "-2" | "-1">;
43
+ default: "0" | "1" | "2" | "3" | "-3" | "-2" | "-1";
44
+ attribute?: string | false;
45
+ };
46
+ brightness: {
47
+ reflect: true;
48
+ type: import("../../index.js").PropType<"0" | "1" | "2" | "3" | "-3" | "-2" | "-1">;
49
+ default: "0" | "1" | "2" | "3" | "-3" | "-2" | "-1";
50
+ attribute?: string | false;
51
+ };
52
+ };
53
+ export interface UIColumnElement extends ReactiveProps<typeof props> {
54
+ }
55
+ export declare class UIColumnElement extends UIContainerElement {
56
+ static props: {
57
+ align: {
58
+ reflect: true;
59
+ type: import("../../index.js").PropType<"end" | "start" | "stretch" | "baseline">;
60
+ default: "end" | "start" | "stretch" | "baseline";
61
+ attribute?: string | false;
62
+ };
63
+ stretch: {
64
+ reflect: true;
65
+ type: import("../../index.js").PropType<boolean>;
66
+ default: boolean;
67
+ attribute?: string | false;
68
+ };
69
+ reflow: {
70
+ reflect: true;
71
+ type: import("../../index.js").PropType<"auto" | "locked">;
72
+ default: "auto" | "locked";
73
+ attribute?: string | false;
74
+ };
75
+ justify: {
76
+ reflect: true;
77
+ type: import("../../index.js").PropType<"end" | "start" | "center" | "between" | "around" | "evenly">;
78
+ default: "end" | "start" | "center" | "between" | "around" | "evenly";
79
+ attribute?: string | false;
80
+ };
81
+ gap: {
82
+ reflect: true;
83
+ type: import("../../index.js").PropType<"none" | "sm" | "md" | "lg" | "xs" | "xl" | "2xl">;
84
+ default: "none" | "sm" | "md" | "lg" | "xs" | "xl" | "2xl";
85
+ attribute?: string | false;
86
+ };
87
+ wrap: {
88
+ reflect: true;
89
+ type: import("../../index.js").PropType<boolean>;
90
+ default: boolean;
91
+ attribute?: string | false;
92
+ };
93
+ elevation: {
94
+ reflect: true;
95
+ type: import("../../index.js").PropType<"0" | "1" | "2" | "3" | "-3" | "-2" | "-1">;
96
+ default: "0" | "1" | "2" | "3" | "-3" | "-2" | "-1";
97
+ attribute?: string | false;
98
+ };
99
+ brightness: {
100
+ reflect: true;
101
+ type: import("../../index.js").PropType<"0" | "1" | "2" | "3" | "-3" | "-2" | "-1">;
102
+ default: "0" | "1" | "2" | "3" | "-3" | "-2" | "-1";
103
+ attribute?: string | false;
104
+ };
105
+ };
106
+ }
107
+ export {};
@@ -0,0 +1,57 @@
1
+ // column.ts — UIColumnElement, the vertical A2UI layout primitive (goals.md §G9 / ADR-0016; decomp
2
+ // g9-containers slice s4). BEHAVIOUR + props + self-define ONLY.
3
+ //
4
+ // `ui-column` is `ui-row`'s SIBLING with the main axis flipped to the block axis (`flex-direction: column`).
5
+ // The direction is the element's IDENTITY — the tag names the main axis, A2UI-faithfully (ADR-0016 cl.2) — so
6
+ // it is NOT a prop; an agent picks a column vs. a row by component type. The element carries no flex CSS in
7
+ // TypeScript: it spreads the shared `surfaceProps`/`flexProps` (the one layout grammar, four consumers — the
8
+ // ADR-0013 no-prototype-merge spread the base exposes) into its own `static props`, and column.css maps the
9
+ // reflected attributes 1:1 onto the CSS flex properties with the column axis (the role-pure repoint).
10
+ //
11
+ // A pure STRUCTURAL container (ADR-0016): it extends `UIElement` via the `UIContainerElement` surface base, is
12
+ // NOT form-associated (no value/validity), and contributes NO ARIA semantics — like a `<div>`, it sets no
13
+ // `role` (neither a host attribute nor `internals.role`); meaning rides the children it lays out. `render()`
14
+ // stays the inherited VOID so the user's light-DOM children flow through untouched (host-as-grid / -as-flex).
15
+ // There is no interaction state, no keyboard, no motion gate — a layout box has none. The surface
16
+ // (elevation/brightness) is painted by the shared controls/_surface/container.css; column.css owns only layout.
17
+ //
18
+ // Imports inward only (`controls → dom`): the surface base from `../../dom/container.ts`, the prop-authoring
19
+ // TYPES from the `../../dom` barrel. `UIContainerElement` is not re-exported by the dom barrel until the s12
20
+ // packaging slice, so it is imported from its module path directly.
21
+ import { UIContainerElement } from "../../dom/container.js";
22
+ import { prop } from "../../dom/index.js";
23
+ // The whole public surface = the two shared spreadable sets, folded into this element's own `static props`
24
+ // (surfaceProps then flexProps — the canonical consumer order; no re-declaration of the grammar, ADR-0016 cl.1).
25
+ // • surfaceProps — elevation/brightness (the two signed surface axes, ADR-0015)
26
+ // • flexProps — align/justify/gap/wrap (the shared A2UI layout grammar, ADR-0016)
27
+ // ADR-0030: the cross-axis `align` default is `stretch` (direction-appropriate — column's cross axis is
28
+ // inline/width; children should fill the width by default). Kim's directive: `center` is NOT allowed on
29
+ // ui-column — a column can only center children by shrink-wrapping them, which defeats the fill-width
30
+ // default and is an anti-pattern for the stacked-content the tag exists to lay out. So the shared 5-member
31
+ // `flexProps.align` enum is NARROWED here to the 4-member `[stretch, start, end, baseline]` (center dropped)
32
+ // — a COLUMN-LOCAL restriction; ui-row/ui-grid/ui-list keep the full grammar. `stretch` LEADS the array so
33
+ // it is both the default AND the invalid-value snap target (enumType.from falls to values[0]) — an
34
+ // `align="center"` attribute snaps the prop back to `stretch`, and column.css drops its `[align='center']`
35
+ // repoint so even a raw attribute cannot center.
36
+ const props = {
37
+ ...UIContainerElement.surfaceProps,
38
+ ...UIContainerElement.flexProps,
39
+ align: { ...prop.enum(['stretch', 'start', 'end', 'baseline'], 'stretch'), reflect: true }, // narrowed: center removed (Kim); stretch-first = default + snap target
40
+ // stretch → the host fills its parent's available inline size (`width: stretch`). A column shrink-wraps to
41
+ // content by default; as a ROOT layout box it should FILL its parent instead. Column-LOCAL sizing opt-in
42
+ // (deliberately NOT folded into the shared `flexProps` grammar — row/grid/list are unaffected): the A2UI
43
+ // canvas sets it on a root `ui-column` so the surface fills the artboard. Boolean presence, default off.
44
+ stretch: { ...prop.boolean(false), reflect: true },
45
+ // reflow → gates the ADR-0016 cl.4 container-query direction switch (ADR-0096). Element-local, deliberately
46
+ // NOT folded into the shared `flexProps` (the ADR-0075 `stretch` precedent — `ui-list` has no `@container`
47
+ // rule and `ui-grid`'s auto-fit IS its own responsiveness, so both stay untouched). `locked` LEADS the array
48
+ // so it is both ui-column's default AND the invalid-value snap target — the column default FLIPS to `locked`
49
+ // (ADR-0096 cl.2): the wide→row switch fired unconditionally and unpreventably for the catalog's prop-only
50
+ // consumer, contradicting the tag's own cl.2 identity. `auto` opts back into the ADR-0016 cl.4 switch.
51
+ reflow: { ...prop.enum(['locked', 'auto'], 'locked'), reflect: true },
52
+ };
53
+ export class UIColumnElement extends UIContainerElement {
54
+ static props = props;
55
+ }
56
+ if (!customElements.get('ui-column'))
57
+ customElements.define('ui-column', UIColumnElement);