@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,8 @@
1
+ /* base-styles.css — the DOCUMENT BASE barrel (the foundation-styles.css pattern): the foundational theme
2
+ * any host page loads to get the document basics — typeface (--md-sys-typeface-sans), body leading, ambient
3
+ * surface/ink, font rendering — from @agent-ui-kit/shared's base.css. Load AFTER foundation-styles.css (base
4
+ * consumes the roles/constants foundation declares) and BEFORE page-local sheets. A page composing the
5
+ * docs shell does NOT need this (the shell's _page.css sets its own document rule); a SHELL-LESS page
6
+ * (agent-admin-app.html is the shape) does, or it renders in the UA serif.
7
+ */
8
+ @import '@agent-ui-kit/shared/base.css';
@@ -0,0 +1,147 @@
1
+ /* component-styles.css — the per-component stylesheet barrel (ADR-0003). Aggregates every FACE control's
2
+ * single `{name}.css` (each = a `:where(ui-{name})` token block + an `@scope (ui-{name})` styles block).
3
+ * A host page links this AFTER foundation-styles.css so the foundation (the `--md-sys-color-*` colour roles + the
4
+ * `--ui-{height,font,gap,space}-*` ramp + `--md-sys-shape-corner-base`) is already declared when a control's `:where()`
5
+ * block reads it. Exposed as the package `./component-styles.css` export. Pure CSS — NEVER injected from a
6
+ * control's `.ts` (behaviour-only `.ts`, no runtime style injection — plan §2). Grows one `@import` per control.
7
+ *
8
+ * DO NOT REORDER — the imports are append-only in control-addition order. Each control's sheet is fully
9
+ * self-scoped (a `:where(ui-{name})` token block + an `@scope (ui-{name})` styles block), so the controls do
10
+ * not interact across the cascade; the stable order keeps any future shared/global rule deterministic. New
11
+ * controls APPEND after the last import.
12
+ *
13
+ * THE ONE SHARED SEAM (decomp s12): `_surface/container.css` is NOT a control sheet — it is the cross-family
14
+ * surface mapping (the `--ui-container-bg`/`-tint` consumption seam, ADR-0015) that the whole G9
15
+ * container/layout family sits on. It is imported FIRST, before any element sheet, so its `:where()` surface
16
+ * tokens are declared when a container element's own `@scope` block consumes them. It does NOT establish
17
+ * `container-type` on any element (ADR-0100 deleted that blanket rule — a layout primitive is never a size
18
+ * query container by default; establishment now belongs to externally-sized composition boundaries, e.g. an
19
+ * A2UI mount surface or app-shell). The container element sheets follow it in a stable, annotated order (also
20
+ * do-not-reorder).
21
+ */
22
+ @import './controls/_surface/container.css';
23
+ /* The shared container BOX-MODEL (margin inset + sticky-region pattern) — a surface opts in with [data-box].
24
+ * After the surface PAINT layer above, before any element sheet (so an element's @scope can override it). */
25
+ @import './controls/_surface/container-box.css';
26
+
27
+ /* form controls (G5/G6) */
28
+ @import './controls/button/button.css';
29
+ @import './controls/text-field/text-field.css';
30
+
31
+ /* display controls (ADR-0025) */
32
+ @import './controls/text/text.css';
33
+
34
+ /* the icon adapter's declarative consumer (ADR-0065/0066) */
35
+ @import './controls/icon/icon.css';
36
+
37
+ /* Indicator controls — Wave 1 (ADR-0041/0042: widget-box geometry + UIIndicatorElement base) */
38
+ @import './controls/checkbox/checkbox.css';
39
+ @import './controls/switch/switch.css';
40
+ @import './controls/radio/radio.css';
41
+ @import './controls/radio/radio-group.css';
42
+
43
+ /* Range controls — Wave 2 (ADR-0042 Range half): single + dual-thumb slider. */
44
+ @import './controls/slider/slider.css';
45
+ @import './controls/slider-multi/slider-multi.css';
46
+
47
+ /* Pattern controls — ADR-0095 (supersedes ADR-0086's ui-radio-group[variant='segmented'], hard cutover):
48
+ * the standalone segmented control. segment.css FIRST (the leaf, no dot to suppress — its own base layout +
49
+ * focus ring), segmented-control.css SECOND (the host's compound selectors consume ui-segment by tag). */
50
+ @import './controls/segment/segment.css';
51
+ @import './controls/segmented-control/segmented-control.css';
52
+
53
+ /* G9 container / layout family — each sheet consumes the shared `_surface/container.css` seam above. */
54
+ @import './controls/row/row.css';
55
+ @import './controls/column/column.css';
56
+ @import './controls/list/list.css';
57
+ @import './controls/grid/grid.css';
58
+ @import './controls/card/card.css';
59
+ @import './controls/tabs/tabs.css';
60
+ @import './controls/modal/modal.css';
61
+
62
+ /* Overlay controls — Wave 4 (ADR-0043): each is self-scoped (a `:where(ui-{name})` token block + an
63
+ * `@scope (ui-{name})` styles block); the popup panels are Container/surface, the triggers Control-class. */
64
+ @import './controls/popover/popover.css';
65
+ @import './controls/tooltip/tooltip.css';
66
+ @import './controls/menu/menu.css';
67
+ @import './controls/select/select.css';
68
+ @import './controls/combo-box/combo-box.css';
69
+
70
+ /* Picker controls — Wave 5B (ADR-0048): standalone month-grid date picker. */
71
+ @import './controls/calendar/calendar.css';
72
+
73
+ /* Coordination controls — G7 (ADR-0050/ADR-0051): the label/description/error wrapper + the aggregation
74
+ * provider. form-provider.css declares no --ui-form-provider-* tokens (LLD-C8 — pure coordination, no paint). */
75
+ @import './controls/field/field.css';
76
+ @import './controls/form-provider/form-provider.css';
77
+
78
+ /* Coordination/carrier controls — ADR-0117: the fleet's second pure UIElement coordination primitive.
79
+ * theme-provider.css declares no --ui-theme-provider-* tokens (SPEC-R6 — pure coordination, no paint). */
80
+ @import './controls/theme-provider/theme-provider.css';
81
+
82
+ /* Chart family — Wave M1 (ADR-0107, chart-family.lld.md LLD-C8): Display-class, axis-free chart marks. */
83
+ @import './controls/sparkline/sparkline.css';
84
+ @import './controls/bar-chart/bar-chart.css';
85
+
86
+ /* Report family — Wave M1 (ADR-0111, report-family.lld.md LLD-C10): the native table, the metric tile,
87
+ * and the compact-realm intent badge. All Display-class, non-interactive, non-form-associated leaves. */
88
+ @import './controls/table/table.css';
89
+ @import './controls/stat/stat.css';
90
+ @import './controls/badge/badge.css';
91
+
92
+ /* Content family — Wave M1 (ADR-0113, content-family.lld.md LLD-C11): the zero-machinery code leaf and
93
+ * the native details/summary disclosure. (The ui-text hyperlink extension lives in text/text.css, above.) */
94
+ @import './controls/code/code.css';
95
+ @import './controls/disclosure/disclosure.css';
96
+
97
+ /* ADR-0124 — the ui-swiper family: a CSS-native scroll-snap carousel (swiper-family.lld.md). Five files —
98
+ * swiper.css is the PRIMARY sheet (declares the family --ui-swiper-* token table + the host's own anatomy)
99
+ * and MUST load before the four leaf sheets, which consume that prefix (the family-root rule, ADR-0124
100
+ * Consequences). */
101
+ @import './controls/swiper/swiper.css';
102
+ @import './controls/swiper/swiper-item.css';
103
+ @import './controls/swiper/swiper-pagination.css';
104
+ @import './controls/swiper/swiper-paddles.css';
105
+ @import './controls/swiper/swiper-label.css';
106
+
107
+ /* Token-surface family — M1 (ADR-0118, token-surfaces.lld.md LLD-C9): show-never-edit color/dimension
108
+ * primitives (swatch/ramp/ladder). All Display-class, non-interactive, non-form-associated leaves. */
109
+ @import './controls/swatch/swatch.css';
110
+ @import './controls/ramp/ramp.css';
111
+ @import './controls/ladder/ladder.css';
112
+
113
+ /* Feed family — Wave M1 (ADR-0112, feed-family.lld.md LLD-C11): agent-activity primitives — the thin-rail
114
+ * progress bar, the compact identity mark, the FilePart-aligned file card, and the toast pair (a fixed
115
+ * notification card + its top-layer stacking host). */
116
+ @import './controls/progress/progress.css';
117
+ @import './controls/avatar/avatar.css';
118
+ @import './controls/attachment/attachment.css';
119
+ @import './controls/toast/toast.css';
120
+ @import './controls/toast/toast-region.css';
121
+
122
+ /* M4 Phase 1 — the split primitive (ADR-0120 cl.2, app-surfaces-m4.lld.md LLD-C5): ui-split (the
123
+ * separator/divider geometry) + ui-split-pane (the axis-oblique pane geometry it drives via a JS seam). */
124
+ @import './controls/split/split.css';
125
+ @import './controls/split/split-pane.css';
126
+
127
+ /* ADR-0121 — ui-toolbar, a Pattern-class action bar (host-as-flex + role=toolbar + roving focus, decoupled
128
+ * from selection; posture via the existing elevation/brightness surface axis, no positioning machine). */
129
+ @import './controls/toolbar/toolbar.css';
130
+
131
+ /* ADR-0122 — the timeline family: the shared marker-system rail row (ui-timeline-item), its durable
132
+ * authored-children host (ui-timeline), and its live imperatively-fed sibling (ui-status-stream). */
133
+ @import './controls/timeline-item/timeline-item.css';
134
+ @import './controls/timeline/timeline.css';
135
+ @import './controls/status-stream/status-stream.css';
136
+
137
+ /* ADR-0125 — ui-command-modal, the CMD-K command palette (command-modal.lld.md): nests ui-modal for the
138
+ * surface (already imported above) and paints only its own search/list/status/empty parts. */
139
+ @import './controls/command-modal/command-modal.css';
140
+
141
+ /* ADR-0123 — ui-color-picker, the OKLCH-internal 2-axis color-input control (color-picker.lld.md): the
142
+ * pad + channel-row/readout geometry; composes ui-slider/ui-text-field/ui-swatch (already imported above). */
143
+ @import './controls/color-picker/color-picker.css';
144
+
145
+ /* ADR-0134 — ui-textarea, the multi-line FACE sibling of ui-text-field (a SEPARATE geometry law, not the
146
+ * single-line (scale×size)→§1-row lookup text-field.css uses — see textarea.css's own header). */
147
+ @import './controls/textarea/textarea.css';
@@ -0,0 +1,3 @@
1
+ export { UIIndicatorElement } from './indicator-element.js';
2
+ export { UIRangeElement } from './range-element.js';
3
+ export { UIListboxElement } from './listbox-element.js';
@@ -0,0 +1,9 @@
1
+ // controls/_base/ — the shared control-base sub-layer (analogous to _surface/ for layout primitives).
2
+ // Exports the abstract bases leaf controls extend; NOT re-exported from the top-level controls/index.ts
3
+ // (the ui-* family barrel) — only the leaf controls that extend these classes are the public surface.
4
+ //
5
+ // Import these in leaf control files:
6
+ // import { UIIndicatorElement } from '../_base/index.ts' // (from controls/{name}/)
7
+ export { UIIndicatorElement } from "./indicator-element.js";
8
+ export { UIRangeElement } from "./range-element.js";
9
+ export { UIListboxElement } from "./listbox-element.js";
@@ -0,0 +1,132 @@
1
+ import { UIFormElement, type ReactiveProps } from '../../dom/index.js';
2
+ import type { FormValue } from '../../dom/index.js';
3
+ declare const indicatorProps: {
4
+ checked: {
5
+ reflect: true;
6
+ type: import("../../index.js").PropType<boolean>;
7
+ default: boolean;
8
+ attribute?: string | false;
9
+ };
10
+ value: {
11
+ reflect: true;
12
+ type: import("../../index.js").PropType<string>;
13
+ default: string;
14
+ attribute?: string | false;
15
+ };
16
+ size: {
17
+ reflect: true;
18
+ type: import("../../index.js").PropType<"sm" | "md" | "lg">;
19
+ default: "sm" | "md" | "lg";
20
+ attribute?: string | false;
21
+ };
22
+ name: {
23
+ reflect: true;
24
+ type: import("../../index.js").PropType<string>;
25
+ default: string;
26
+ attribute?: string | false;
27
+ };
28
+ disabled: {
29
+ reflect: true;
30
+ type: import("../../index.js").PropType<boolean>;
31
+ default: boolean;
32
+ attribute?: string | false;
33
+ };
34
+ required: {
35
+ reflect: true;
36
+ type: import("../../index.js").PropType<boolean>;
37
+ default: boolean;
38
+ attribute?: string | false;
39
+ };
40
+ };
41
+ export interface UIIndicatorElement extends ReactiveProps<typeof indicatorProps> {
42
+ }
43
+ export declare class UIIndicatorElement extends UIFormElement {
44
+ #private;
45
+ static props: {
46
+ checked: {
47
+ reflect: true;
48
+ type: import("../../index.js").PropType<boolean>;
49
+ default: boolean;
50
+ attribute?: string | false;
51
+ };
52
+ value: {
53
+ reflect: true;
54
+ type: import("../../index.js").PropType<string>;
55
+ default: string;
56
+ attribute?: string | false;
57
+ };
58
+ size: {
59
+ reflect: true;
60
+ type: import("../../index.js").PropType<"sm" | "md" | "lg">;
61
+ default: "sm" | "md" | "lg";
62
+ attribute?: string | false;
63
+ };
64
+ name: {
65
+ reflect: true;
66
+ type: import("../../index.js").PropType<string>;
67
+ default: string;
68
+ attribute?: string | false;
69
+ };
70
+ disabled: {
71
+ reflect: true;
72
+ type: import("../../index.js").PropType<boolean>;
73
+ default: boolean;
74
+ attribute?: string | false;
75
+ };
76
+ required: {
77
+ reflect: true;
78
+ type: import("../../index.js").PropType<boolean>;
79
+ default: boolean;
80
+ attribute?: string | false;
81
+ };
82
+ };
83
+ /**
84
+ * LLD-C2: the ARIA role this indicator carries — declared by each leaf subclass (LLD-C2).
85
+ * `'checkbox'` / `'switch'` / `'radio'`; the base sets `internals.role` from it in `connected()`.
86
+ */
87
+ static role: string;
88
+ /**
89
+ * LLD-C1: platform checkbox semantics — unchecked submits nothing; checked submits `this.value`.
90
+ */
91
+ protected formValue(): FormValue;
92
+ /**
93
+ * The reset baseline — native `HTMLInputElement.defaultChecked` parity: a PUBLIC, read-only reflection
94
+ * of the checked state this control was upgraded/connected with (see `#defaultChecked` above). Exposed
95
+ * so a coordinating ancestor (`ui-radio-group`) can recompute ITS OWN post-reset state from every
96
+ * child's default WITHOUT depending on `formResetCallback` invocation order between the group and its
97
+ * radios (both are separate `UIFormElement` participants the platform resets independently) — reading
98
+ * this getter is stable regardless of whether the group's or the radio's own reset runs first.
99
+ */
100
+ get defaultChecked(): boolean;
101
+ protected connected(): void;
102
+ /**
103
+ * LLD-C3: pre-toggle hook — called immediately before `this.checked` is flipped in the click handler.
104
+ * The base is a no-op. `UICheckboxElement` overrides this to clear `indeterminate` (so clicking an
105
+ * indeterminate checkbox clears the indeterminate visual and then toggles checked — platform parity).
106
+ * Switch and radio are binary; they do not override this.
107
+ */
108
+ protected beforeToggle(): void;
109
+ /**
110
+ * LLD-C5: grouping hook — the radio subclass overrides this to wire roving-focus + exclusive
111
+ * selection within a name-scoped group. Called from `connected()` after all base wiring is in place.
112
+ * Checkbox/switch leave it a no-op.
113
+ */
114
+ protected grouped(): void;
115
+ /**
116
+ * Form reset → checked ← `defaultChecked` (native `<input type=checkbox/radio>.defaultChecked` parity;
117
+ * the bug-A fix — this was missing entirely, so every Indicator control ignored BOTH reset paths:
118
+ * native `form.reset()` and a form-less provider's direct `formResetCallback()` call). Silent — no
119
+ * `input`/`change` emitted, matching text-field's own `formReset()` (a reset is not a user edit).
120
+ * `indeterminate` (checkbox-only) is untouched here — a reset restores the boolean `checked` value;
121
+ * native `<input type=checkbox>` does not reset `indeterminate` either (it is never form-serialized and
122
+ * carries no default of its own).
123
+ *
124
+ * A `ui-radio` inside a `ui-radio-group`: this restores THIS radio's own visual `checked` correctly, but
125
+ * the GROUP is a SEPARATE `UIFormElement` participant with its OWN `#selectedValue` signal — this reset
126
+ * alone cannot update it (no click/change event fires). `UIRadioGroupElement` carries its own
127
+ * `formReset()` override (radio-group.ts) that recomputes `#selectedValue` from every child's
128
+ * `defaultChecked` getter (above) — stable regardless of which of the two resets the platform runs first.
129
+ */
130
+ protected formReset(): void;
131
+ }
132
+ export {};
@@ -0,0 +1,158 @@
1
+ // indicator-element.ts — UIIndicatorElement, the shared base for the Indicator class
2
+ // (ui-checkbox · ui-switch · ui-radio). indicator-element.lld.md.
3
+ //
4
+ // Owns: the boolean form value (LLD-C1), the checked-state machine + ARIA (LLD-C2), the toggle via
5
+ // pressActivation + click (LLD-C3), and the widget-box geometry seam (LLD-C4, CSS in the subclass).
6
+ // The subclass declares `static role` (LLD-C2), the glyph in its `.css` (LLD-C4), and (radio) the
7
+ // group wiring via `grouped()` (LLD-C5).
8
+ //
9
+ // `indeterminate` is deliberately NOT in the base — it is checkbox-specific tri-state (checkbox overrides
10
+ // `beforeToggle()` to clear it and runs its own supplemental effect). Switch and radio are binary; they
11
+ // should not carry an indeterminate property at all.
12
+ //
13
+ // Layer: controls/_base/ — imports dom + traits (inward-only ✓).
14
+ // Inward-only ✓ (controls ← traits ← dom ← reactive).
15
+ import { UIFormElement, prop } from "../../dom/index.js";
16
+ import { tabbable } from "../../traits/tabbable.js";
17
+ import { pressActivation } from "../../traits/press-activation.js";
18
+ const indicatorProps = {
19
+ ...UIFormElement.formProps,
20
+ // LLD-C1: the boolean form value; reflected so `[checked]` drives CSS + is observable as an attribute.
21
+ checked: { ...prop.boolean(false), reflect: true },
22
+ // LLD-C1: the submitted string when checked (HTML checkbox semantics, default 'on'); reflected.
23
+ value: { ...prop.string('on'), reflect: true },
24
+ // LLD-C4: the widget-box size axis — selects --md-sys-compact-{size} via [size] in the leaf's CSS (ADR-0041).
25
+ // All Indicator controls share this axis; each leaf's stylesheet rewires the token.
26
+ size: { ...prop.enum(['sm', 'md', 'lg'], 'md'), reflect: true },
27
+ };
28
+ export class UIIndicatorElement extends UIFormElement {
29
+ static props = indicatorProps;
30
+ /**
31
+ * LLD-C2: the ARIA role this indicator carries — declared by each leaf subclass (LLD-C2).
32
+ * `'checkbox'` / `'switch'` / `'radio'`; the base sets `internals.role` from it in `connected()`.
33
+ */
34
+ static role = '';
35
+ // LLD-C3: suppress the next click when it originated from an Enter keydown.
36
+ // Platform parity: Enter does NOT toggle a checkbox; but pressActivation fires host.click() on Enter,
37
+ // so a keydown guard registered BEFORE pressActivation marks the pending Enter-click for suppression.
38
+ #suppressNextClick = false;
39
+ // The native-parity reset baseline — `defaultChecked` (LLD-C1 extended, the bug-A fix). Captured ONCE
40
+ // at the FIRST connect (guarded — a later reconnect must not re-snapshot an already-toggled value; the
41
+ // text-field `#defaultValue`/`#defaultCaptured` precedent). Reading `this.checked` here is equivalent to
42
+ // reading the `checked` ATTRIBUTE (native `<input type=checkbox>.defaultChecked` parity): `checked`
43
+ // REFLECTS (props.ts's outbound reflect fires synchronously on every property write, including the
44
+ // ADR-0005 property-wins upgrade replay), so `this.hasAttribute('checked') === this.checked` holds at
45
+ // every point `connected()` can observe it — reading the resolved prop is equivalent and avoids
46
+ // re-parsing the attribute string.
47
+ #defaultChecked = false;
48
+ #defaultCaptured = false;
49
+ /**
50
+ * LLD-C1: platform checkbox semantics — unchecked submits nothing; checked submits `this.value`.
51
+ */
52
+ formValue() {
53
+ return this.checked ? this.value : null;
54
+ }
55
+ /**
56
+ * The reset baseline — native `HTMLInputElement.defaultChecked` parity: a PUBLIC, read-only reflection
57
+ * of the checked state this control was upgraded/connected with (see `#defaultChecked` above). Exposed
58
+ * so a coordinating ancestor (`ui-radio-group`) can recompute ITS OWN post-reset state from every
59
+ * child's default WITHOUT depending on `formResetCallback` invocation order between the group and its
60
+ * radios (both are separate `UIFormElement` participants the platform resets independently) — reading
61
+ * this getter is stable regardless of whether the group's or the radio's own reset runs first.
62
+ */
63
+ get defaultChecked() {
64
+ return this.#defaultChecked;
65
+ }
66
+ connected() {
67
+ // Seed the reset baseline ONCE from the checked state at first connect (see `#defaultChecked` above).
68
+ if (!this.#defaultCaptured) {
69
+ this.#defaultChecked = this.checked;
70
+ this.#defaultCaptured = true;
71
+ }
72
+ const ctor = this.constructor;
73
+ // LLD-C2: set the ARIA role from the subclass's static declaration. Never a host attribute (FACE).
74
+ this.internals.role = ctor.role;
75
+ // LLD-C3: tabbable — tabindex=0 while enabled, removed from the tab order while disabled (ADR-0010).
76
+ tabbable(this, { disabled: () => this.effectiveDisabled() });
77
+ // LLD-C3: Enter suppressor — must register BEFORE pressActivation so this keydown handler runs
78
+ // first. pressActivation fires host.click() on Enter keydown; that synthetic click is suppressed
79
+ // in the click handler below. Disabled-guarded: pressActivation also early-returns while disabled,
80
+ // so a disabled-Enter must not arm the flag (else the next enabled mouse-click would be swallowed).
81
+ this.listen(this, 'keydown', (event) => {
82
+ if (!this.effectiveDisabled() && event.key === 'Enter') {
83
+ this.#suppressNextClick = true;
84
+ }
85
+ });
86
+ // LLD-C3: pressActivation — Space activates on keyup; Enter fires host.click() (suppressed below).
87
+ pressActivation(this, { disabled: () => this.effectiveDisabled() });
88
+ // LLD-C3: click → toggle checked (mouse clicks + Space-activated synthetic clicks; Enter suppressed).
89
+ // `beforeToggle()` is called first so subclasses can hook in pre-toggle side effects (checkbox clears
90
+ // its `indeterminate` here; switch/radio leave it a no-op via the base implementation).
91
+ this.listen(this, 'click', () => {
92
+ if (this.#suppressNextClick) {
93
+ this.#suppressNextClick = false;
94
+ return; // Enter-click: no toggle (platform checkbox parity)
95
+ }
96
+ if (this.effectiveDisabled())
97
+ return;
98
+ this.beforeToggle();
99
+ this.checked = !this.checked;
100
+ this.emit('input');
101
+ this.emit('change');
102
+ });
103
+ // LLD-C2: checked-state effect — reactive on `checked`, publishes:
104
+ // · custom state :state(checked) (CustomStateSet, absent in jsdom)
105
+ // · internals.ariaChecked ("true" / "false") — the jsdom-accessible ARIA proxy.
106
+ // NOTE: `indeterminate` is NOT tracked here — checkbox adds its own supplemental effect (which runs
107
+ // after this one) to override ariaChecked="mixed" and :state(indeterminate) when needed.
108
+ this.effect(() => {
109
+ const checked = this.checked;
110
+ const states = this.internals.states; // CustomStateSet; absent in jsdom (optional-chained below)
111
+ if (checked) {
112
+ states?.add('checked');
113
+ this.internals.ariaChecked = 'true';
114
+ }
115
+ else {
116
+ states?.delete('checked');
117
+ this.internals.ariaChecked = 'false';
118
+ }
119
+ });
120
+ // LLD-C3: ariaDisabled mirrors effectiveDisabled() — reactive, scope-owned (same form as button.ts).
121
+ this.effect(() => {
122
+ this.internals.ariaDisabled = this.effectiveDisabled() ? 'true' : null;
123
+ });
124
+ // LLD-C5: delegate to the subclass's group wiring (radio overrides; checkbox/switch leave it no-op).
125
+ this.grouped();
126
+ }
127
+ /**
128
+ * LLD-C3: pre-toggle hook — called immediately before `this.checked` is flipped in the click handler.
129
+ * The base is a no-op. `UICheckboxElement` overrides this to clear `indeterminate` (so clicking an
130
+ * indeterminate checkbox clears the indeterminate visual and then toggles checked — platform parity).
131
+ * Switch and radio are binary; they do not override this.
132
+ */
133
+ beforeToggle() { }
134
+ /**
135
+ * LLD-C5: grouping hook — the radio subclass overrides this to wire roving-focus + exclusive
136
+ * selection within a name-scoped group. Called from `connected()` after all base wiring is in place.
137
+ * Checkbox/switch leave it a no-op.
138
+ */
139
+ grouped() { }
140
+ /**
141
+ * Form reset → checked ← `defaultChecked` (native `<input type=checkbox/radio>.defaultChecked` parity;
142
+ * the bug-A fix — this was missing entirely, so every Indicator control ignored BOTH reset paths:
143
+ * native `form.reset()` and a form-less provider's direct `formResetCallback()` call). Silent — no
144
+ * `input`/`change` emitted, matching text-field's own `formReset()` (a reset is not a user edit).
145
+ * `indeterminate` (checkbox-only) is untouched here — a reset restores the boolean `checked` value;
146
+ * native `<input type=checkbox>` does not reset `indeterminate` either (it is never form-serialized and
147
+ * carries no default of its own).
148
+ *
149
+ * A `ui-radio` inside a `ui-radio-group`: this restores THIS radio's own visual `checked` correctly, but
150
+ * the GROUP is a SEPARATE `UIFormElement` participant with its OWN `#selectedValue` signal — this reset
151
+ * alone cannot update it (no click/change event fires). `UIRadioGroupElement` carries its own
152
+ * `formReset()` override (radio-group.ts) that recomputes `#selectedValue` from every child's
153
+ * `defaultChecked` getter (above) — stable regardless of which of the two resets the platform runs first.
154
+ */
155
+ formReset() {
156
+ this.checked = this.#defaultChecked;
157
+ }
158
+ }
@@ -0,0 +1,70 @@
1
+ import { UIFormElement, type ReactiveProps } from '../../dom/index.js';
2
+ import type { FormValue, ValidityResult } from '../../dom/index.js';
3
+ declare const listboxProps: {
4
+ multiple: {
5
+ reflect: true;
6
+ type: import("../../index.js").PropType<boolean>;
7
+ default: boolean;
8
+ attribute?: string | false;
9
+ };
10
+ name: {
11
+ reflect: true;
12
+ type: import("../../index.js").PropType<string>;
13
+ default: string;
14
+ attribute?: string | false;
15
+ };
16
+ disabled: {
17
+ reflect: true;
18
+ type: import("../../index.js").PropType<boolean>;
19
+ default: boolean;
20
+ attribute?: string | false;
21
+ };
22
+ required: {
23
+ reflect: true;
24
+ type: import("../../index.js").PropType<boolean>;
25
+ default: boolean;
26
+ attribute?: string | false;
27
+ };
28
+ };
29
+ export interface UIListboxElement extends ReactiveProps<typeof listboxProps> {
30
+ }
31
+ export declare class UIListboxElement extends UIFormElement {
32
+ #private;
33
+ static props: {
34
+ multiple: {
35
+ reflect: true;
36
+ type: import("../../index.js").PropType<boolean>;
37
+ default: boolean;
38
+ attribute?: string | false;
39
+ };
40
+ name: {
41
+ reflect: true;
42
+ type: import("../../index.js").PropType<string>;
43
+ default: string;
44
+ attribute?: string | false;
45
+ };
46
+ disabled: {
47
+ reflect: true;
48
+ type: import("../../index.js").PropType<boolean>;
49
+ default: boolean;
50
+ attribute?: string | false;
51
+ };
52
+ required: {
53
+ reflect: true;
54
+ type: import("../../index.js").PropType<boolean>;
55
+ default: boolean;
56
+ attribute?: string | false;
57
+ };
58
+ };
59
+ /**
60
+ * LLD-C3: the selected option's `value` attribute (single mode), or a newline-joined list
61
+ * (multi mode), or `null` when nothing is selected.
62
+ */
63
+ protected formValue(): FormValue;
64
+ /**
65
+ * LLD-C3: `required` + nothing selected → `{ valid: false, flags: { valueMissing: true } }`.
66
+ */
67
+ protected formValidity(): ValidityResult;
68
+ protected connected(): void;
69
+ }
70
+ export {};
@@ -0,0 +1,74 @@
1
+ // listbox-element.ts — UIListboxElement, the form-associated listbox base
2
+ // (ui-listbox · ui-select options popup · ui-combo-box options popup). listbox-roving LLD-C3.
3
+ //
4
+ // Owns: `role=listbox` (via internals), the form value (the selected option's `value` string, or
5
+ // a `\n`-joined list for multi), `required` → `valueMissing`, and the wiring of `rovingFocus` +
6
+ // `selectionCommit` over its `[role=option]` children.
7
+ //
8
+ // The options are light-DOM children (`ui-option` or `<li role=option>`); the host carries no role
9
+ // attribute (FACE internals). ui-menu is NOT this class — it is a plain UIElement + rovingFocus
10
+ // (no form value; role=menu; LLD-C4 in listbox-roving.lld.md).
11
+ //
12
+ // Layer: controls/_base/ — imports dom + traits (inward-only ✓).
13
+ // Inward-only ✓ (controls ← traits ← dom ← reactive).
14
+ import { signal } from "../../reactive/index.js";
15
+ import { UIFormElement, prop } from "../../dom/index.js";
16
+ import { rovingFocus } from "../../traits/roving-focus.js";
17
+ import { selectionCommit } from "../../traits/selection-commit.js";
18
+ const listboxProps = {
19
+ ...UIFormElement.formProps,
20
+ // multi-select: a Set of selected keys vs. at most one. Reflected so `[multiple]` drives CSS.
21
+ multiple: { ...prop.boolean(false), reflect: true },
22
+ };
23
+ export class UIListboxElement extends UIFormElement {
24
+ static props = listboxProps;
25
+ // LLD-C3: the committed selection, updated by selectionCommit's `onSelect` callback.
26
+ // Single mode: a string key ('' = nothing selected).
27
+ // Multi mode: a ReadonlySet<string> (empty Set = nothing selected).
28
+ // Both empty cases return null from formValue(). The codec is value-agnostic — formValue() /
29
+ // formValidity() handle both union arms uniformly.
30
+ #selection = signal('');
31
+ /**
32
+ * LLD-C3: the selected option's `value` attribute (single mode), or a newline-joined list
33
+ * (multi mode), or `null` when nothing is selected.
34
+ */
35
+ formValue() {
36
+ const sel = this.#selection.value;
37
+ if (typeof sel === 'string')
38
+ return sel === '' ? null : sel;
39
+ if (sel.size === 0)
40
+ return null;
41
+ return [...sel].join('\n');
42
+ }
43
+ /**
44
+ * LLD-C3: `required` + nothing selected → `{ valid: false, flags: { valueMissing: true } }`.
45
+ */
46
+ formValidity() {
47
+ const sel = this.#selection.value;
48
+ const empty = typeof sel === 'string' ? sel === '' : sel.size === 0;
49
+ if (this.required && empty) {
50
+ return { valid: false, flags: { valueMissing: true }, message: 'Please select an option.' };
51
+ }
52
+ return { valid: true };
53
+ }
54
+ connected() {
55
+ // LLD-C3: set ARIA role via internals — never a host attribute (FACE).
56
+ this.internals.role = 'listbox';
57
+ // LLD-C3: live accessor for [role=option] children (re-read per event for dynamic item sets).
58
+ const items = () => [...this.querySelectorAll('[role=option]')];
59
+ // LLD-C3: key extractor — the option's `value` attribute ('' = no key, skipped by selectionCommit).
60
+ const keyOf = (el) => el.getAttribute('value') ?? '';
61
+ // LLD-C3: roving-focus over the option set (vertical orientation, looping, type-ahead on by default).
62
+ rovingFocus(this, { items });
63
+ // LLD-C3: selection-commit — mode from the `multiple` prop at connect time; onSelect updates
64
+ // #selection, which drives formValue() + formValidity() reactively via the UIFormElement effects.
65
+ selectionCommit(this, {
66
+ mode: this.multiple ? 'multi' : 'single',
67
+ items,
68
+ keyOf,
69
+ onSelect: (selection) => {
70
+ this.#selection.value = selection;
71
+ },
72
+ });
73
+ }
74
+ }