@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,204 @@
1
+ /* checkbox.css — ui-checkbox, the Indicator-class widget stylesheet (decomp S1 · ADR-0041 · ADR-0042).
2
+ *
3
+ * [1] TOKEN BLOCK — `:where(ui-checkbox)` (specificity 0,0,0) declares the --ui-checkbox-* chain from
4
+ * the colour roles (--md-sys-color-{family}-{role}) and the widget-box ramp (--md-sys-compact-{size}, ADR-0041).
5
+ * [size] repoints the box to the correct compact tier; [disabled] mutes to neutral roles.
6
+ * [2] STYLES BLOCK — `@scope (ui-checkbox)` consumes ONLY --ui-checkbox-*. The host is inline-flex
7
+ * (box + optional label text). ::before paints the square widget box (2px border + background fill).
8
+ * ::after paints the glyph (checkmark or indeterminate-dash), positioned absolutely within the box
9
+ * column so it centers on the box regardless of label-text height. :state(checked)/:state(indeterminate)
10
+ * drive the visual states; :focus-visible draws the shared fleet ring (ADR-0009); forced-colors maps to
11
+ * Highlight/HighlightText so the glyph always survives (CanvasText ink on Highlight fill; ADR-0009 ring
12
+ * free via --md-sys-color-focus-ring → Highlight from the token layer).
13
+ *
14
+ * Standalone stylesheet — linked via the host page / component-styles barrel (decomp s14); NEVER injected
15
+ * from checkbox.ts (behaviour-only `.ts`, no runtime style injection — plan §2).
16
+ */
17
+
18
+ /* ════════════════ [1] TOKEN BLOCK — :where(ui-checkbox) declares --ui-checkbox-* ════════════════ */
19
+
20
+ :where(ui-checkbox) {
21
+ /* Widget-box size — the compact-class square, per ADR-0041. Default size = md (16px at ui-md scale). */
22
+ --ui-checkbox-box: var(--md-sys-compact-md);
23
+
24
+ /* Colour channel: unchecked = neutral border on transparent; checked/indeterminate = primary fill + ink.
25
+ The border-color and bg-checked ride the same --md-sys-color-primary ladder step as button.css's solid variant
26
+ (the design-system's primary fill); the ink is the on-primary pair for readability (WCAG AA). */
27
+ --ui-checkbox-bg: transparent;
28
+ --ui-checkbox-border: var(--md-sys-color-neutral-high);
29
+ --ui-checkbox-bg-checked: var(--md-sys-color-primary);
30
+ --ui-checkbox-border-checked: var(--md-sys-color-primary);
31
+ --ui-checkbox-ink: var(--md-sys-color-primary-on-primary); /* checkmark / indeterminate-dash fill */
32
+
33
+ /* Label gap — the rhythm between the box and the optional label text (density-bearing, via --md-sys-gap-md). */
34
+ --ui-checkbox-gap: var(--md-sys-gap-md);
35
+
36
+ /* user-invalid (ADR-0051) — the danger border, appearing only AFTER the first interaction (the
37
+ trackUserInvalid controller owns that timing; checkbox.ts toggles :state(user-invalid)). The
38
+ text-field precedent, applied to the box's border channel. */
39
+ --ui-checkbox-border-invalid: var(--md-sys-color-danger);
40
+ }
41
+
42
+ /* [size] → widget-box tier (ADR-0041 clause 2: sm/md/lg at the default ui-md scale = 14/16/18 px). */
43
+ :where(ui-checkbox[size='sm']) {
44
+ --ui-checkbox-box: var(--md-sys-compact-sm);
45
+ --ui-checkbox-gap: var(--md-sys-gap-sm);
46
+ }
47
+ :where(ui-checkbox[size='lg']) {
48
+ --ui-checkbox-box: var(--md-sys-compact-lg);
49
+ --ui-checkbox-gap: var(--md-sys-gap-lg);
50
+ }
51
+
52
+ /* [disabled] → mute the border + fill to neutral roles. The state holds at idle: pointer-events:none (below)
53
+ prevents :hover from ever matching, so no path can lift the muted tokens. */
54
+ :where(ui-checkbox[disabled]) {
55
+ --ui-checkbox-border: var(--md-sys-color-neutral-surface-high);
56
+ --ui-checkbox-bg-checked: var(--md-sys-color-neutral-surface-high);
57
+ --ui-checkbox-border-checked: var(--md-sys-color-neutral-surface-high);
58
+ --ui-checkbox-ink: var(--md-sys-color-neutral-on-surface-variant);
59
+ }
60
+
61
+ /* ════════════════ [2] STYLES BLOCK — @scope (ui-checkbox) consumes ONLY --ui-checkbox-* ════════════════ */
62
+
63
+ @scope (ui-checkbox) {
64
+ :scope {
65
+ display: inline-flex;
66
+ align-items: center;
67
+ gap: var(--ui-checkbox-gap);
68
+ position: relative; /* containing block for the absolutely-positioned ::after glyph */
69
+ cursor: pointer;
70
+ -webkit-user-select: none; /* WebKit/Safari still requires the prefix; the label is a control surface, not selectable text */
71
+ user-select: none;
72
+ }
73
+
74
+ /* The visual box — first flex item (flex-shrink:0), the checkbox's physical affordance.
75
+ border + fill are the two state-PAINT properties that transition on check/uncheck. */
76
+ :scope::before {
77
+ content: '';
78
+ display: block;
79
+ flex-shrink: 0;
80
+ box-sizing: border-box;
81
+ inline-size: var(--ui-checkbox-box);
82
+ block-size: var(--ui-checkbox-box);
83
+ border: 2px solid var(--ui-checkbox-border);
84
+ border-radius: calc(var(--ui-checkbox-box) / 5); /* proportional slight rounding (~3px at 16px default) */
85
+ background-color: var(--ui-checkbox-bg);
86
+ /* State-PAINT transition only — geometry never animates (geometry.md). */
87
+ transition:
88
+ background-color var(--md-sys-motion-duration-fast) var(--md-sys-motion-easing-standard),
89
+ border-color var(--md-sys-motion-duration-fast) var(--md-sys-motion-easing-standard);
90
+ }
91
+
92
+ /* Checked: fill the box with the primary colour (border disappears into the fill). */
93
+ :scope:state(checked)::before {
94
+ background-color: var(--ui-checkbox-bg-checked);
95
+ border-color: var(--ui-checkbox-border-checked);
96
+ }
97
+
98
+ /* Indeterminate: same primary fill as checked (the dash glyph differentiates the two states visually). */
99
+ :scope:state(indeterminate)::before {
100
+ background-color: var(--ui-checkbox-bg-checked);
101
+ border-color: var(--ui-checkbox-border-checked);
102
+ }
103
+
104
+ /* Hover (TKT-0047) — border-color lift toward the checked colour, the radio.css precedent: same
105
+ Indicator-class idle shape (border + transparent bg), so the same mechanism ports directly. Invisible
106
+ while checked (the border already blends into the same-colour fill) — harmless, no state gate needed.
107
+ Disabled is pointer-inert (below), so :hover never matches it. Authored BEFORE the user-invalid rule
108
+ below (component-reviewer MINOR fix) — equal specificity (0,2,1) means source order decides which
109
+ wins on hover+user-invalid, and the danger signal must win (the text-field.css:205-208 precedent:
110
+ idle < hover < user-invalid, source-later). Placing hover here, ahead of user-invalid, is the fix. */
111
+ :scope:hover::before {
112
+ border-color: var(--ui-checkbox-border-checked);
113
+ }
114
+
115
+ /* user-invalid (ADR-0051) — the danger border, appearing only AFTER the first interaction. Cannot
116
+ co-occur with :state(checked) (valueMissing only fires when unchecked) — but it CAN co-occur with
117
+ :state(indeterminate) (required + indeterminate + unchecked IS valueMissing), AND with :hover (a user
118
+ hovering a required, still-unchecked box after an earlier blur). Equal specificity (0,2,1) with BOTH
119
+ the indeterminate rule above AND the hover rule immediately above it: SOURCE ORDER is load-bearing —
120
+ this rule must stay authored LAST among the three so the danger border always wins. */
121
+ :scope:state(user-invalid)::before {
122
+ border-color: var(--ui-checkbox-border-invalid);
123
+ }
124
+
125
+ /* Glyph base — absolutely positioned at the inline-start of the host, centered in the block direction.
126
+ The box (::before) is the first flex item whose inline-start IS the host's inline-start, so
127
+ inset-inline-start:0 aligns the glyph column with the box. inset-block-start:50% + translateY(-50%)
128
+ centers the glyph vertically relative to the host; because align-items:center makes the box flex-center
129
+ within the host, this equals the box's vertical center regardless of label-text height. No background
130
+ by default (the glyph is invisible in the unchecked state). */
131
+ :scope::after {
132
+ content: '';
133
+ position: absolute;
134
+ inset-inline-start: 0;
135
+ inset-block-start: 50%;
136
+ transform: translateY(-50%);
137
+ pointer-events: none;
138
+ }
139
+
140
+ /* Checkmark glyph — a clip-path polygon tick, the classic ✓ shape within [0,100%]×[0,100%] canvas.
141
+ Inset 20% from inline-start; sized 60%×55% of the box (the glyph bounding box). The :scope::after
142
+ base rule supplies position:absolute and the vertical centering (not repeated here). */
143
+ :scope:state(checked)::after {
144
+ background-color: var(--ui-checkbox-ink);
145
+ inset-inline-start: calc(var(--ui-checkbox-box) * 0.2);
146
+ inline-size: calc(var(--ui-checkbox-box) * 0.6);
147
+ block-size: calc(var(--ui-checkbox-box) * 0.55);
148
+ clip-path: polygon(14% 44%, 0% 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
149
+ }
150
+
151
+ /* Indeterminate dash — a thin horizontal bar centered within the box (2px tall, 60% wide, 20% inset). */
152
+ :scope:state(indeterminate)::after {
153
+ background-color: var(--ui-checkbox-ink);
154
+ inset-inline-start: calc(var(--ui-checkbox-box) * 0.2);
155
+ inline-size: calc(var(--ui-checkbox-box) * 0.6);
156
+ block-size: 2px;
157
+ border-radius: 1px;
158
+ }
159
+
160
+ /* Focus ring (ADR-0009) — the shared fleet ring: :focus-visible (keyboard-only) draws a layout-neutral
161
+ outline on the host. This encircles the whole control (box + label), the fleet standard. The ring
162
+ reads the fleet-wide --md-sys-color-focus-ring / --md-sys-state-focus-ring-* tokens (never a per-control repoint). */
163
+ :scope:focus-visible {
164
+ outline: var(--md-sys-state-focus-ring-width) solid var(--md-sys-color-focus-ring);
165
+ outline-offset: var(--md-sys-state-focus-ring-offset);
166
+ }
167
+
168
+ /* Motion (interaction-states standard) — zero the box transition under reduced motion. */
169
+ @media (prefers-reduced-motion: reduce) {
170
+ :scope::before {
171
+ transition: none;
172
+ }
173
+ }
174
+
175
+ /* Disabled — pointer-inert + cursor reset. The [disabled] token block already muted the colours;
176
+ pointer-events:none ensures :hover/:active never match (so the muted idle holds forever). */
177
+ :scope[disabled] {
178
+ pointer-events: none;
179
+ cursor: default;
180
+ }
181
+
182
+ /* Forced-colors — use system colours so the box and glyph are always visible in high-contrast modes.
183
+ Unchecked: ButtonText border on ButtonFace. Checked/indeterminate: Highlight fill with HighlightText
184
+ glyph (the system accent + its reading-pair, WCAG AA guaranteed by the OS). forced-color-adjust:none
185
+ preserves our explicit system-colour mappings so the browser does not re-override them. The :focus-visible
186
+ ring is free: --md-sys-color-focus-ring carries the token layer's Highlight mapping (ADR-0009) — no per-control rule. */
187
+ @media (forced-colors: active) {
188
+ :scope::before {
189
+ border-color: ButtonText;
190
+ background-color: ButtonFace;
191
+ }
192
+ :scope:state(checked)::before,
193
+ :scope:state(indeterminate)::before {
194
+ background-color: Highlight;
195
+ border-color: Highlight;
196
+ forced-color-adjust: none;
197
+ }
198
+ :scope:state(checked)::after,
199
+ :scope:state(indeterminate)::after {
200
+ background-color: HighlightText;
201
+ forced-color-adjust: none;
202
+ }
203
+ }
204
+ }
@@ -0,0 +1,114 @@
1
+ import { type ReactiveProps } from '../../dom/index.js';
2
+ import type { ValidityResult } from '../../dom/index.js';
3
+ import { UIIndicatorElement } from '../_base/indicator-element.js';
4
+ declare const checkboxProps: {
5
+ checked: {
6
+ reflect: true;
7
+ type: import("../../index.js").PropType<boolean>;
8
+ default: boolean;
9
+ attribute?: string | false;
10
+ };
11
+ value: {
12
+ reflect: true;
13
+ type: import("../../index.js").PropType<string>;
14
+ default: string;
15
+ attribute?: string | false;
16
+ };
17
+ size: {
18
+ reflect: true;
19
+ type: import("../../index.js").PropType<"sm" | "md" | "lg">;
20
+ default: "sm" | "md" | "lg";
21
+ attribute?: string | false;
22
+ };
23
+ name: {
24
+ reflect: true;
25
+ type: import("../../index.js").PropType<string>;
26
+ default: string;
27
+ attribute?: string | false;
28
+ };
29
+ disabled: {
30
+ reflect: true;
31
+ type: import("../../index.js").PropType<boolean>;
32
+ default: boolean;
33
+ attribute?: string | false;
34
+ };
35
+ required: {
36
+ reflect: true;
37
+ type: import("../../index.js").PropType<boolean>;
38
+ default: boolean;
39
+ attribute?: string | false;
40
+ };
41
+ };
42
+ export interface UICheckboxElement extends ReactiveProps<typeof checkboxProps> {
43
+ }
44
+ export declare class UICheckboxElement extends UIIndicatorElement {
45
+ #private;
46
+ static props: {
47
+ checked: {
48
+ reflect: true;
49
+ type: import("../../index.js").PropType<boolean>;
50
+ default: boolean;
51
+ attribute?: string | false;
52
+ };
53
+ value: {
54
+ reflect: true;
55
+ type: import("../../index.js").PropType<string>;
56
+ default: string;
57
+ attribute?: string | false;
58
+ };
59
+ size: {
60
+ reflect: true;
61
+ type: import("../../index.js").PropType<"sm" | "md" | "lg">;
62
+ default: "sm" | "md" | "lg";
63
+ attribute?: string | false;
64
+ };
65
+ name: {
66
+ reflect: true;
67
+ type: import("../../index.js").PropType<string>;
68
+ default: string;
69
+ attribute?: string | false;
70
+ };
71
+ disabled: {
72
+ reflect: true;
73
+ type: import("../../index.js").PropType<boolean>;
74
+ default: boolean;
75
+ attribute?: string | false;
76
+ };
77
+ required: {
78
+ reflect: true;
79
+ type: import("../../index.js").PropType<boolean>;
80
+ default: boolean;
81
+ attribute?: string | false;
82
+ };
83
+ };
84
+ static role: string;
85
+ get indeterminate(): boolean;
86
+ set indeterminate(v: boolean);
87
+ /**
88
+ * LLD-C1 extension: `required && !checked` → `valueMissing` (native `<input type=checkbox required>`
89
+ * parity — unlike ui-switch, whose required-ON semantics the fleet deliberately declined as an
90
+ * edge case, checkbox.md has always documented this constraint; this is the code catching up to
91
+ * that contract). `indeterminate` does not affect validity — a required checkbox is satisfied
92
+ * only by `checked=true`, matching the platform.
93
+ */
94
+ protected formValidity(): ValidityResult;
95
+ protected connected(): void;
96
+ /**
97
+ * Pre-toggle hook (LLD-C3): called by the base's click handler immediately before `checked` is flipped.
98
+ * Clears `indeterminate` so clicking an indeterminate checkbox first resolves the visual state and THEN
99
+ * toggles checked — platform checkbox parity (a click on ☐/☑/dash always produces ☑, never stays
100
+ * mixed on click; the next click is then ☑→☐).
101
+ */
102
+ protected beforeToggle(): void;
103
+ /**
104
+ * A reset must not leave a required-unchecked checkbox showing `:state(user-invalid)` until the
105
+ * user re-interacts (the text-field `formReset()` precedent) — `super.formReset()` restores
106
+ * `checked` ← `defaultChecked` (the base's own reset leg) first.
107
+ */
108
+ protected formReset(): void;
109
+ protected disconnected(): void;
110
+ /** Feeds `FormConnectDetail.userInvalid` (ADR-0050) — the `trackUserInvalid` tracker IS the one
111
+ * timing source; this override just exposes its gate. */
112
+ protected formUserInvalid(): boolean;
113
+ }
114
+ export {};
@@ -0,0 +1,130 @@
1
+ // checkbox.ts — UICheckboxElement, the Indicator-class tri-state checkbox (decomp S1 · ADR-0042 · ADR-0041).
2
+ // Light-DOM FACE form control — extends UIIndicatorElement which owns: the boolean form value (checked /
3
+ // value / size props), the checked-state machine + ARIA (LLD-C2), the pressActivation toggle (LLD-C3),
4
+ // and the widget-box geometry seam (LLD-C4). The leaf adds:
5
+ // • static role = 'checkbox' (sets internals.role on connect via the base's LLD-C2 wiring)
6
+ // • `indeterminate` property (property-only, NOT reflected, NOT submitted) — tri-state visual override:
7
+ // ariaChecked="mixed" + :state(indeterminate) when true; cleared on the next click/Space toggle.
8
+ // • self-define as `ui-checkbox`
9
+ //
10
+ // `size` is now in UIIndicatorElement.props (the shared widget-box axis — ADR-0041); checkbox inherits it
11
+ // via the base-props spread without a local override.
12
+ //
13
+ // No light-DOM parts: the box and glyph paint entirely in CSS via ::before/::after on the host.
14
+ // Zero-dep; controls → dom+traits inward only (✓); erasableSyntaxOnly ✓ (no enum/decorator).
15
+ import { signal } from "../../reactive/index.js";
16
+ import {} from "../../dom/index.js";
17
+ import { UIIndicatorElement } from "../_base/indicator-element.js";
18
+ import { trackUserInvalid } from "../../traits/track-user-invalid.js";
19
+ // `size` is inherited from UIIndicatorElement.props — the spread brings checked/value/size/name/disabled/
20
+ // required. No local additions. Each control owns its own `static props` (the UIFormElement.formProps
21
+ // precedent; ADR-0013 — static props cannot be inherited via the prototype chain).
22
+ const checkboxProps = {
23
+ ...UIIndicatorElement.props,
24
+ };
25
+ export class UICheckboxElement extends UIIndicatorElement {
26
+ static props = checkboxProps;
27
+ // LLD-C2 contract: the subclass declares the ARIA role; the base applies it via internals.role in connected().
28
+ static role = 'checkbox';
29
+ // `indeterminate` — property-only (NOT reflected, NOT submitted; checkbox-specific tri-state).
30
+ // Visual override: `ariaChecked="mixed"` when true; `checked` retains its boolean for the form value.
31
+ // Backed by a private signal so the supplemental indeterminate effect (below) re-runs on every change.
32
+ #indeterminate = signal(false);
33
+ get indeterminate() {
34
+ return this.#indeterminate.value;
35
+ }
36
+ set indeterminate(v) {
37
+ this.#indeterminate.value = v;
38
+ }
39
+ // The user-invalid TIMING controller (ADR-0051), created per connection (re-arms on reconnect;
40
+ // released on disconnect) — the text-field/select precedent.
41
+ #userInvalid = null;
42
+ /**
43
+ * LLD-C1 extension: `required && !checked` → `valueMissing` (native `<input type=checkbox required>`
44
+ * parity — unlike ui-switch, whose required-ON semantics the fleet deliberately declined as an
45
+ * edge case, checkbox.md has always documented this constraint; this is the code catching up to
46
+ * that contract). `indeterminate` does not affect validity — a required checkbox is satisfied
47
+ * only by `checked=true`, matching the platform.
48
+ */
49
+ formValidity() {
50
+ if (this.required && !this.checked) {
51
+ return { valid: false, flags: { valueMissing: true }, message: 'Please check this box if you want to proceed.' };
52
+ }
53
+ return { valid: true };
54
+ }
55
+ connected() {
56
+ super.connected(); // base wires: role · tabbable · Enter-guard · pressActivation · click-toggle ·
57
+ // checked effect (ariaChecked="true"/"false", :state(checked)) · ariaDisabled
58
+ // ADR-0051 — the user-invalid TIMING controller: gates the danger treatment until the first
59
+ // blur/change (host itself is the focusable element — the tabbable trait's tabindex rides the
60
+ // host directly, no internal part). Reflects :state(user-invalid) + internals.ariaInvalid.
61
+ const invalidController = trackUserInvalid(this, { invalid: () => !this.formValidity().valid });
62
+ this.#userInvalid = invalidController;
63
+ this.effect(() => {
64
+ if (invalidController.userInvalid()) {
65
+ this.internals.states?.add('user-invalid');
66
+ this.internals.ariaInvalid = 'true';
67
+ }
68
+ else {
69
+ this.internals.states?.delete('user-invalid');
70
+ this.internals.ariaInvalid = null;
71
+ }
72
+ });
73
+ // Supplemental indeterminate effect — runs AFTER the base's checked effect (registered second).
74
+ // Reads BOTH #indeterminate AND checked so it tracks both signals and wins on any change to either.
75
+ // When indeterminate=true: overrides ariaChecked to "mixed", adds :state(indeterminate), removes
76
+ // :state(checked). When indeterminate=false: restores the correct checked state (the base effect
77
+ // may not re-run for an indeterminate→false transition alone, so we re-apply here).
78
+ this.effect(() => {
79
+ const indeterminate = this.#indeterminate.value; // tracked
80
+ const checked = this.checked; // also tracked — ensures re-run on checked change too
81
+ const states = this.internals.states;
82
+ if (indeterminate) {
83
+ states?.add('indeterminate');
84
+ states?.delete('checked');
85
+ this.internals.ariaChecked = 'mixed';
86
+ }
87
+ else {
88
+ states?.delete('indeterminate');
89
+ if (checked) {
90
+ states?.add('checked');
91
+ this.internals.ariaChecked = 'true';
92
+ }
93
+ else {
94
+ states?.delete('checked');
95
+ this.internals.ariaChecked = 'false';
96
+ }
97
+ }
98
+ });
99
+ }
100
+ /**
101
+ * Pre-toggle hook (LLD-C3): called by the base's click handler immediately before `checked` is flipped.
102
+ * Clears `indeterminate` so clicking an indeterminate checkbox first resolves the visual state and THEN
103
+ * toggles checked — platform checkbox parity (a click on ☐/☑/dash always produces ☑, never stays
104
+ * mixed on click; the next click is then ☑→☐).
105
+ */
106
+ beforeToggle() {
107
+ if (this.#indeterminate.value)
108
+ this.#indeterminate.value = false;
109
+ }
110
+ /**
111
+ * A reset must not leave a required-unchecked checkbox showing `:state(user-invalid)` until the
112
+ * user re-interacts (the text-field `formReset()` precedent) — `super.formReset()` restores
113
+ * `checked` ← `defaultChecked` (the base's own reset leg) first.
114
+ */
115
+ formReset() {
116
+ super.formReset();
117
+ this.#userInvalid?.reset();
118
+ }
119
+ disconnected() {
120
+ this.#userInvalid?.release(); // idempotent — the listeners already die with the connection scope
121
+ this.#userInvalid = null;
122
+ }
123
+ /** Feeds `FormConnectDetail.userInvalid` (ADR-0050) — the `trackUserInvalid` tracker IS the one
124
+ * timing source; this override just exposes its gate. */
125
+ formUserInvalid() {
126
+ return this.#userInvalid?.userInvalid() ?? false;
127
+ }
128
+ }
129
+ if (!customElements.get('ui-checkbox'))
130
+ customElements.define('ui-checkbox', UICheckboxElement);
@@ -0,0 +1,72 @@
1
+ /* code.css — ui-code, the Display-class zero-machinery verbatim code leaf (LLD-C6,
2
+ * content-family.lld.md §3; content-family.spec.md SPEC-R2/R19/R20; ADR-0113 cl.2). Two clearly-SECTIONED
3
+ * blocks:
4
+ *
5
+ * [1] TOKEN BLOCK — `:where(ui-code)` (specificity 0,0,0) DECLARES the seven `--ui-code-*` component
6
+ * tokens: `--ui-code-font` (the minted `--md-sys-typeface-mono` constant), `--ui-code-size`/`-line-height` (the
7
+ * `--md-sys-typescale-body-medium-*` row — ADR-0113 cl.2, body-class metrics), `--ui-code-ink`
8
+ * (the AA-gated on-surface role), `--ui-code-surface` (the cross-family `--ui-container-bg` seam —
9
+ * ADR-0015 cl.2, the SAME seam ui-card's own default rides, card.css:59 — NOT a raw
10
+ * `-surface-container` role, which does not exist in tokens.css), `--ui-code-radius` (the fleet
11
+ * `--md-sys-shape-corner-base` referent), and `--ui-code-pad-inline`/`-pad-block` (density-INVARIANT frame
12
+ * quantities — ADR-0113 cl.2, not the `--md-sys-space-*` rhythm ladder).
13
+ * [2] STYLES BLOCK — `@scope (ui-code)` CONSUMES only `--ui-code-*`. The host itself IS the scroll box
14
+ * (host-as-content — no inner wrapper): `white-space: pre` preserves verbatim text,
15
+ * `overflow-x: auto` OWNS the component's own horizontal overflow (ADR-0102 Lane A — the component,
16
+ * never the page, absorbs a wide unbroken line), `max-inline-size: 100%` keeps the host from
17
+ * blowing out a flex/feed container. No `[size]`/`[scale]` rows (Display class, SPEC-R20) and no
18
+ * `[density]` legs (every quantity above is frame-class, density-invariant — ADR-0113 cl.2).
19
+ *
20
+ * Standalone stylesheet — linked via the host page / component-styles barrel (Phase 2); NEVER injected
21
+ * from code.ts (behaviour-only `.ts`, no runtime style injection — plan §2).
22
+ */
23
+
24
+ /* ════════════════ [1] TOKEN BLOCK — :where(ui-code) declares --ui-code-* ════════════════ */
25
+
26
+ :where(ui-code) {
27
+ --ui-code-font: var(--md-sys-typeface-mono); /* the minted mono constant — "for code blocks" */
28
+ --ui-code-size: var(--md-sys-typescale-body-medium-size); /* body-class metrics (ADR-0113 cl.2) */
29
+ --ui-code-line-height: var(--md-sys-typescale-body-medium-line-height);
30
+ --ui-code-ink: var(--md-sys-color-neutral-on-surface);
31
+ /* the cross-family surface seam (ADR-0015 cl.2) — NOT a raw `-surface-container` role (does not exist
32
+ in tokens.css). component-reviewer finding (2026-07-09): `--ui-container-bg` is a SEAM, never
33
+ self-seeded by the seam's own declaration — ui-card SEEDS its own default
34
+ (`--ui-container-bg: var(--md-sys-color-neutral-surface)`, card.css:59) and a bare `ui-code` with no
35
+ seeding ancestor was computing `transparent`, violating SPEC-R2's "component-owned surface" +
36
+ ADR-0102's CSS-less-consumer law. Fallback form: consume an ancestor's seeded value if present
37
+ (e.g. nested inside a `ui-card`, matching its plane), else seed the SAME default ui-card uses, so a
38
+ bare `ui-code` never renders transparent. */
39
+ --ui-code-surface: var(--ui-container-bg, var(--md-sys-color-neutral-surface));
40
+ --ui-code-radius: var(--md-sys-shape-corner-base); /* the fleet referent (entry/container class) */
41
+ --ui-code-pad-inline: 12px; /* density-INVARIANT frame quantities (ADR-0113 cl.2 — not rhythm) */
42
+ --ui-code-pad-block: 8px;
43
+ }
44
+
45
+ /* ════════════════ [2] STYLES BLOCK — @scope (ui-code) consumes ONLY --ui-code-* ════════════════ */
46
+
47
+ @scope (ui-code) {
48
+ :scope {
49
+ display: block;
50
+ font-family: var(--ui-code-font);
51
+ font-size: var(--ui-code-size);
52
+ line-height: var(--ui-code-line-height);
53
+ color: var(--ui-code-ink);
54
+ background: var(--ui-code-surface);
55
+ border-radius: var(--ui-code-radius);
56
+ padding: var(--ui-code-pad-block) var(--ui-code-pad-inline);
57
+ white-space: pre; /* verbatim — newlines/indentation live in the text nodes (SPEC-R2) */
58
+ overflow-x: auto; /* the component OWNS overflow (ADR-0102 Lane A) */
59
+ max-inline-size: 100%; /* never blows out a flex/feed container; the scroll box absorbs excess */
60
+ user-select: text;
61
+ tab-size: 4;
62
+ }
63
+
64
+ /* forced-colors — the surface keeps shape via the border when fills are forced away (SPEC-R19) */
65
+ @media (forced-colors: active) {
66
+ :scope {
67
+ color: CanvasText;
68
+ background: Canvas;
69
+ border: 1px solid CanvasText;
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,23 @@
1
+ import { UIElement, type ReactiveProps } from '../../dom/index.js';
2
+ declare const props: {
3
+ language: {
4
+ reflect: true;
5
+ type: import("../../index.js").PropType<string>;
6
+ default: string;
7
+ attribute?: string | false;
8
+ };
9
+ };
10
+ export interface UICodeElement extends ReactiveProps<typeof props> {
11
+ }
12
+ export declare class UICodeElement extends UIElement {
13
+ static props: {
14
+ language: {
15
+ reflect: true;
16
+ type: import("../../index.js").PropType<string>;
17
+ default: string;
18
+ attribute?: string | false;
19
+ };
20
+ };
21
+ protected connected(): void;
22
+ }
23
+ export {};
@@ -0,0 +1,40 @@
1
+ // code.ts — UICodeElement, the Display-class zero-machinery verbatim code leaf (LLD-C5,
2
+ // content-family.lld.md §3; content-family.spec.md SPEC-R1/R3/R5; ADR-0113 cl.2/fork F2).
3
+ //
4
+ // Content model — host-as-content (ADR-0006/ADR-0113 fork F2): the light-DOM text IS the code. There is
5
+ // NO `code` prop on the element and no `html\`\`` template — `render()` stays the inherited void. The
6
+ // catalog's bindable `Code.code` property maps to `textContent` (the `Text.text` lane, SPEC-R3): a bound
7
+ // write replaces plain text with plain text, so there is nothing to heal. Normative absences (SPEC-R1
8
+ // AC2, the ADR-0106 grep-able-absence precedent, applied here — this file must never NAME the platform
9
+ // child-mutation-watching API or a browser copy-affordance API, the same discipline text.ts holds for
10
+ // its own banned box-size-watching API): no DOM-mutation watcher of any kind, no stamp, no adoption code,
11
+ // no system copy-affordance hookup, no source-transforming pass of any kind — this file is the whole
12
+ // zero-machinery leaf.
13
+ //
14
+ // `language` (SPEC-R4) is a reflected, free-string, INERT metadata prop — no enum (nothing for the
15
+ // ADR-0098 static-enum lane to gate), no rendering effect, no dispatch to any rendering-transform
16
+ // consumer. It exists so model-emitted markdown-fence habits round-trip losslessly; a future consumer of
17
+ // this metadata is a named, fenced escape hatch (SPEC-R6), never built here.
18
+ //
19
+ // A11y (SPEC-R5): `internals.role = 'code'` — a CONSTANT, set once in connected() (the list.ts/bar-chart
20
+ // `role=list` precedent), never a host `role` attribute. Keyboard access to horizontal overflow rides the
21
+ // platform's focusable-scroller behaviour where it exists (code.css `overflow-x: auto`); this file mints
22
+ // no `tabindex` and no measurement machinery for it (the residual is named and accepted, SPEC-R5 AC2).
23
+ //
24
+ // Imports inward only (controls → dom): UIElement + prop from the dom barrel.
25
+ import { UIElement, prop } from "../../dom/index.js";
26
+ const props = {
27
+ // inert metadata (SPEC-R4) — no enum, no effect; reflects so the attribute round-trips a JS-set value
28
+ // too (the fleet reflect precedent) even though nothing in this file or code.css reads the attribute.
29
+ language: { ...prop.string(''), reflect: true },
30
+ };
31
+ export class UICodeElement extends UIElement {
32
+ static props = props;
33
+ connected() {
34
+ // The ONE internals line (SPEC-R5) — a constant semantic role, set directly (not inside an effect,
35
+ // nothing reactive depends on it); re-set on each connect (idempotent).
36
+ this.internals.role = 'code';
37
+ }
38
+ }
39
+ if (!customElements.get('ui-code'))
40
+ customElements.define('ui-code', UICodeElement); // idempotent self-define