@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.
- package/dist/base-styles.css +8 -0
- package/dist/component-styles.css +147 -0
- package/dist/controls/_base/index.d.ts +3 -0
- package/dist/controls/_base/index.js +9 -0
- package/dist/controls/_base/indicator-element.d.ts +132 -0
- package/dist/controls/_base/indicator-element.js +158 -0
- package/dist/controls/_base/listbox-element.d.ts +70 -0
- package/dist/controls/_base/listbox-element.js +74 -0
- package/dist/controls/_base/range-element.d.ts +120 -0
- package/dist/controls/_base/range-element.js +158 -0
- package/dist/controls/_surface/container-box.css +301 -0
- package/dist/controls/_surface/container.css +156 -0
- package/dist/controls/_token-surface/token-surface.d.ts +35 -0
- package/dist/controls/_token-surface/token-surface.js +97 -0
- package/dist/controls/attachment/attachment-meta.d.ts +8 -0
- package/dist/controls/attachment/attachment-meta.js +84 -0
- package/dist/controls/attachment/attachment.css +91 -0
- package/dist/controls/attachment/attachment.d.ts +40 -0
- package/dist/controls/attachment/attachment.js +70 -0
- package/dist/controls/avatar/avatar-initials.d.ts +4 -0
- package/dist/controls/avatar/avatar-initials.js +30 -0
- package/dist/controls/avatar/avatar.css +87 -0
- package/dist/controls/avatar/avatar.d.ts +40 -0
- package/dist/controls/avatar/avatar.js +77 -0
- package/dist/controls/badge/badge.css +175 -0
- package/dist/controls/badge/badge.d.ts +36 -0
- package/dist/controls/badge/badge.js +71 -0
- package/dist/controls/bar-chart/bar-chart.css +110 -0
- package/dist/controls/bar-chart/bar-chart.d.ts +26 -0
- package/dist/controls/bar-chart/bar-chart.js +80 -0
- package/dist/controls/bar-chart/bar-math.d.ts +31 -0
- package/dist/controls/bar-chart/bar-math.js +106 -0
- package/dist/controls/button/button.css +263 -0
- package/dist/controls/button/button.d.ts +61 -0
- package/dist/controls/button/button.js +115 -0
- package/dist/controls/calendar/calendar.css +495 -0
- package/dist/controls/calendar/calendar.d.ts +161 -0
- package/dist/controls/calendar/calendar.js +1004 -0
- package/dist/controls/card/card-content.d.ts +24 -0
- package/dist/controls/card/card-content.js +133 -0
- package/dist/controls/card/card-footer.d.ts +3 -0
- package/dist/controls/card/card-footer.js +16 -0
- package/dist/controls/card/card-header.d.ts +3 -0
- package/dist/controls/card/card-header.js +18 -0
- package/dist/controls/card/card.css +445 -0
- package/dist/controls/card/card.d.ts +51 -0
- package/dist/controls/card/card.js +61 -0
- package/dist/controls/checkbox/checkbox.css +204 -0
- package/dist/controls/checkbox/checkbox.d.ts +114 -0
- package/dist/controls/checkbox/checkbox.js +130 -0
- package/dist/controls/code/code.css +72 -0
- package/dist/controls/code/code.d.ts +23 -0
- package/dist/controls/code/code.js +40 -0
- package/dist/controls/color-picker/color-picker.css +209 -0
- package/dist/controls/color-picker/color-picker.d.ts +84 -0
- package/dist/controls/color-picker/color-picker.js +545 -0
- package/dist/controls/color-picker/color.d.ts +40 -0
- package/dist/controls/color-picker/color.js +159 -0
- package/dist/controls/column/column.css +151 -0
- package/dist/controls/column/column.d.ts +107 -0
- package/dist/controls/column/column.js +57 -0
- package/dist/controls/combo-box/combo-box.css +397 -0
- package/dist/controls/combo-box/combo-box.d.ts +133 -0
- package/dist/controls/combo-box/combo-box.js +680 -0
- package/dist/controls/command-modal/command-modal.css +226 -0
- package/dist/controls/command-modal/command-modal.d.ts +42 -0
- package/dist/controls/command-modal/command-modal.js +315 -0
- package/dist/controls/disclosure/disclosure.css +162 -0
- package/dist/controls/disclosure/disclosure.d.ts +37 -0
- package/dist/controls/disclosure/disclosure.js +207 -0
- package/dist/controls/field/field.css +140 -0
- package/dist/controls/field/field.d.ts +27 -0
- package/dist/controls/field/field.js +228 -0
- package/dist/controls/form-provider/form-provider.css +40 -0
- package/dist/controls/form-provider/form-provider.d.ts +42 -0
- package/dist/controls/form-provider/form-provider.js +105 -0
- package/dist/controls/grid/grid.css +72 -0
- package/dist/controls/grid/grid.d.ts +60 -0
- package/dist/controls/grid/grid.js +56 -0
- package/dist/controls/icon/icon.css +37 -0
- package/dist/controls/icon/icon.d.ts +25 -0
- package/dist/controls/icon/icon.js +55 -0
- package/dist/controls/index.d.ts +57 -0
- package/dist/controls/index.js +136 -0
- package/dist/controls/ladder/ladder.css +89 -0
- package/dist/controls/ladder/ladder.d.ts +27 -0
- package/dist/controls/ladder/ladder.js +78 -0
- package/dist/controls/list/list.css +118 -0
- package/dist/controls/list/list.d.ts +84 -0
- package/dist/controls/list/list.js +48 -0
- package/dist/controls/menu/menu.css +195 -0
- package/dist/controls/menu/menu.d.ts +44 -0
- package/dist/controls/menu/menu.js +248 -0
- package/dist/controls/modal/modal.css +99 -0
- package/dist/controls/modal/modal.d.ts +61 -0
- package/dist/controls/modal/modal.js +155 -0
- package/dist/controls/popover/popover.css +83 -0
- package/dist/controls/popover/popover.d.ts +44 -0
- package/dist/controls/popover/popover.js +164 -0
- package/dist/controls/progress/progress.css +106 -0
- package/dist/controls/progress/progress.d.ts +28 -0
- package/dist/controls/progress/progress.js +80 -0
- package/dist/controls/radio/radio-group.css +84 -0
- package/dist/controls/radio/radio-group.d.ts +152 -0
- package/dist/controls/radio/radio-group.js +350 -0
- package/dist/controls/radio/radio.css +219 -0
- package/dist/controls/radio/radio.d.ts +19 -0
- package/dist/controls/radio/radio.js +75 -0
- package/dist/controls/ramp/ramp.css +75 -0
- package/dist/controls/ramp/ramp.d.ts +29 -0
- package/dist/controls/ramp/ramp.js +72 -0
- package/dist/controls/row/row.css +152 -0
- package/dist/controls/row/row.d.ts +95 -0
- package/dist/controls/row/row.js +45 -0
- package/dist/controls/segment/segment.css +66 -0
- package/dist/controls/segment/segment.d.ts +3 -0
- package/dist/controls/segment/segment.js +26 -0
- package/dist/controls/segmented-control/segmented-control.css +189 -0
- package/dist/controls/segmented-control/segmented-control.d.ts +20 -0
- package/dist/controls/segmented-control/segmented-control.js +64 -0
- package/dist/controls/select/select.css +467 -0
- package/dist/controls/select/select.d.ts +147 -0
- package/dist/controls/select/select.js +538 -0
- package/dist/controls/slider/slider.css +231 -0
- package/dist/controls/slider/slider.d.ts +111 -0
- package/dist/controls/slider/slider.js +60 -0
- package/dist/controls/slider-multi/slider-multi.css +197 -0
- package/dist/controls/slider-multi/slider-multi.d.ts +149 -0
- package/dist/controls/slider-multi/slider-multi.js +380 -0
- package/dist/controls/sparkline/sparkline-math.d.ts +23 -0
- package/dist/controls/sparkline/sparkline-math.js +79 -0
- package/dist/controls/sparkline/sparkline.css +61 -0
- package/dist/controls/sparkline/sparkline.d.ts +27 -0
- package/dist/controls/sparkline/sparkline.js +74 -0
- package/dist/controls/split/constrain.d.ts +44 -0
- package/dist/controls/split/constrain.js +126 -0
- package/dist/controls/split/split-pane.css +63 -0
- package/dist/controls/split/split-pane.d.ts +49 -0
- package/dist/controls/split/split-pane.js +42 -0
- package/dist/controls/split/split.css +127 -0
- package/dist/controls/split/split.d.ts +42 -0
- package/dist/controls/split/split.js +364 -0
- package/dist/controls/stat/stat-model.d.ts +22 -0
- package/dist/controls/stat/stat-model.js +69 -0
- package/dist/controls/stat/stat.css +101 -0
- package/dist/controls/stat/stat.d.ts +30 -0
- package/dist/controls/stat/stat.js +73 -0
- package/dist/controls/status-stream/status-stream.css +151 -0
- package/dist/controls/status-stream/status-stream.d.ts +108 -0
- package/dist/controls/status-stream/status-stream.js +417 -0
- package/dist/controls/swatch/swatch.css +66 -0
- package/dist/controls/swatch/swatch.d.ts +28 -0
- package/dist/controls/swatch/swatch.js +74 -0
- package/dist/controls/swiper/swiper-item.css +17 -0
- package/dist/controls/swiper/swiper-item.d.ts +31 -0
- package/dist/controls/swiper/swiper-item.js +47 -0
- package/dist/controls/swiper/swiper-label.css +10 -0
- package/dist/controls/swiper/swiper-label.d.ts +4 -0
- package/dist/controls/swiper/swiper-label.js +20 -0
- package/dist/controls/swiper/swiper-paddles.css +26 -0
- package/dist/controls/swiper/swiper-paddles.d.ts +10 -0
- package/dist/controls/swiper/swiper-paddles.js +62 -0
- package/dist/controls/swiper/swiper-pagination.css +60 -0
- package/dist/controls/swiper/swiper-pagination.d.ts +31 -0
- package/dist/controls/swiper/swiper-pagination.js +78 -0
- package/dist/controls/swiper/swiper.css +153 -0
- package/dist/controls/swiper/swiper.d.ts +158 -0
- package/dist/controls/swiper/swiper.js +659 -0
- package/dist/controls/switch/switch.css +194 -0
- package/dist/controls/switch/switch.d.ts +5 -0
- package/dist/controls/switch/switch.js +18 -0
- package/dist/controls/table/table-model.d.ts +43 -0
- package/dist/controls/table/table-model.js +124 -0
- package/dist/controls/table/table.css +90 -0
- package/dist/controls/table/table.d.ts +29 -0
- package/dist/controls/table/table.js +178 -0
- package/dist/controls/tabs/tab-panel.d.ts +10 -0
- package/dist/controls/tabs/tab-panel.js +89 -0
- package/dist/controls/tabs/tab.d.ts +26 -0
- package/dist/controls/tabs/tab.js +67 -0
- package/dist/controls/tabs/tabs.css +181 -0
- package/dist/controls/tabs/tabs.d.ts +61 -0
- package/dist/controls/tabs/tabs.js +176 -0
- package/dist/controls/text/href.d.ts +26 -0
- package/dist/controls/text/href.js +48 -0
- package/dist/controls/text/text.css +328 -0
- package/dist/controls/text/text.d.ts +85 -0
- package/dist/controls/text/text.js +273 -0
- package/dist/controls/text-field/text-field.css +498 -0
- package/dist/controls/text-field/text-field.d.ts +226 -0
- package/dist/controls/text-field/text-field.js +905 -0
- package/dist/controls/textarea/textarea.css +251 -0
- package/dist/controls/textarea/textarea.d.ts +136 -0
- package/dist/controls/textarea/textarea.js +312 -0
- package/dist/controls/theme-provider/theme-provider.css +48 -0
- package/dist/controls/theme-provider/theme-provider.d.ts +59 -0
- package/dist/controls/theme-provider/theme-provider.js +40 -0
- package/dist/controls/timeline/timeline.css +33 -0
- package/dist/controls/timeline/timeline.d.ts +39 -0
- package/dist/controls/timeline/timeline.js +52 -0
- package/dist/controls/timeline-item/timeline-item.css +495 -0
- package/dist/controls/timeline-item/timeline-item.d.ts +79 -0
- package/dist/controls/timeline-item/timeline-item.js +360 -0
- package/dist/controls/toast/toast-region.css +56 -0
- package/dist/controls/toast/toast-region.d.ts +20 -0
- package/dist/controls/toast/toast-region.js +113 -0
- package/dist/controls/toast/toast.css +96 -0
- package/dist/controls/toast/toast.d.ts +28 -0
- package/dist/controls/toast/toast.js +191 -0
- package/dist/controls/toolbar/toolbar.css +125 -0
- package/dist/controls/toolbar/toolbar.d.ts +108 -0
- package/dist/controls/toolbar/toolbar.js +68 -0
- package/dist/controls/tooltip/tooltip.css +80 -0
- package/dist/controls/tooltip/tooltip.d.ts +57 -0
- package/dist/controls/tooltip/tooltip.js +205 -0
- package/dist/descriptor/component-descriptor.d.ts +112 -0
- package/dist/descriptor/component-descriptor.js +492 -0
- package/dist/descriptor/index.d.ts +1 -0
- package/dist/descriptor/index.js +5 -0
- package/dist/dom/container.d.ts +45 -0
- package/dist/dom/container.js +60 -0
- package/dist/dom/element.d.ts +98 -0
- package/dist/dom/element.js +221 -0
- package/dist/dom/form.d.ts +240 -0
- package/dist/dom/form.js +399 -0
- package/dist/dom/index.d.ts +10 -0
- package/dist/dom/index.js +31 -0
- package/dist/dom/props.d.ts +56 -0
- package/dist/dom/props.js +231 -0
- package/dist/dom/repeat.d.ts +10 -0
- package/dist/dom/repeat.js +202 -0
- package/dist/dom/template.d.ts +161 -0
- package/dist/dom/template.js +634 -0
- package/dist/dom/watch.d.ts +11 -0
- package/dist/dom/watch.js +82 -0
- package/dist/foundation-styles.css +9 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/reactive/graph.d.ts +65 -0
- package/dist/reactive/graph.js +310 -0
- package/dist/reactive/index.d.ts +3 -0
- package/dist/reactive/index.js +4 -0
- package/dist/reactive/scheduler.d.ts +13 -0
- package/dist/reactive/scheduler.js +49 -0
- package/dist/traits/area-drag.d.ts +12 -0
- package/dist/traits/area-drag.js +70 -0
- package/dist/traits/form-registry.d.ts +36 -0
- package/dist/traits/form-registry.js +108 -0
- package/dist/traits/index.d.ts +24 -0
- package/dist/traits/index.js +19 -0
- package/dist/traits/overlay.d.ts +50 -0
- package/dist/traits/overlay.js +277 -0
- package/dist/traits/pane-resize.d.ts +26 -0
- package/dist/traits/pane-resize.js +103 -0
- package/dist/traits/press-activation.d.ts +11 -0
- package/dist/traits/press-activation.js +55 -0
- package/dist/traits/roving-focus.d.ts +52 -0
- package/dist/traits/roving-focus.js +214 -0
- package/dist/traits/scroll-fade.d.ts +28 -0
- package/dist/traits/scroll-fade.js +120 -0
- package/dist/traits/selection-commit.d.ts +30 -0
- package/dist/traits/selection-commit.js +146 -0
- package/dist/traits/tabbable.d.ts +12 -0
- package/dist/traits/tabbable.js +59 -0
- package/dist/traits/track-user-invalid.d.ts +36 -0
- package/dist/traits/track-user-invalid.js +52 -0
- package/dist/traits/value-codec.d.ts +120 -0
- package/dist/traits/value-codec.js +497 -0
- package/dist/traits/value-drag.d.ts +18 -0
- package/dist/traits/value-drag.js +84 -0
- 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
|