@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,156 @@
|
|
|
1
|
+
/* container.css — the SHARED `UIContainerElement` surface seam (ADR-0015). The one stylesheet every
|
|
2
|
+
* container/layout `ui-*` element sits on; it is `@import`-ed FIRST (before any element sheet) by
|
|
3
|
+
* component-styles.css (wired in decomp s12). It owns NO per-element layout (display/flex/grid is each
|
|
4
|
+
* element's own `@scope` block) — only the cross-family surface. It does NOT establish query containers
|
|
5
|
+
* (ADR-0100 deleted the blanket `container-type: inline-size` this file used to set on the four layout
|
|
6
|
+
* primitives — see the seam's own banner below for why and where establishment moved).
|
|
7
|
+
*
|
|
8
|
+
* Role-purity (ADR-0008 / tokens.md): the CONSUMPTION (the two `background-*` declarations) reads ONLY the
|
|
9
|
+
* `--ui-container-*` seam — never a raw `--md-sys-color-*` role. The TOKEN repoints below (`--ui-container-bg:
|
|
10
|
+
* var(--md-sys-color-neutral-surface-high)`) are where the colour roles enter, exactly as button.css's `:where()`
|
|
11
|
+
* token block does — the `--md-sys-color-*` is confined to the variable-definition side, so a container holds zero
|
|
12
|
+
* colour opinion and forced-colors is handled in the role/system layer.
|
|
13
|
+
*
|
|
14
|
+
* Two surface axes (ADR-0015 cl.1–3), both signed `-3…3`, realized against the s1 token ladders:
|
|
15
|
+
* • elevation → the scheme-INVERTING base PLANE: a SOLID `--md-sys-color-neutral-surface-{lowest…highest}` step.
|
|
16
|
+
* • brightness → the scheme-CONSISTENT tonal shift. Two realizations (s1's AA-verified split):
|
|
17
|
+
* – SOLO (brightness set, elevation 0/unset): the SOLID `--md-sys-color-neutral-surface-{dimmest…brightest}`
|
|
18
|
+
* ladder is the base plane (no overlay) — ADR-0015 cl.1.
|
|
19
|
+
* – COMPOSITION (elevation≠0 AND brightness≠0): the elevation plane is the base, and brightness becomes
|
|
20
|
+
* a TRANSLUCENT wash (`--md-sys-color-neutral-tint-{step}`) composited alpha-over it — ADR-0015 cl.3 — so the
|
|
21
|
+
* `−m` wash sits over the `+n` plane and neither axis overwrites the other. (The tint roles exist
|
|
22
|
+
* ONLY for this case; s1 budgets their 14% alpha ceiling against the brightest dark elevation plane.)
|
|
23
|
+
* The single `--ui-container-bg`/`--ui-container-tint` consumption seam is fixed regardless (ADR-0015 cl.2);
|
|
24
|
+
* the SOLO/COMPOSITION choice is just which token each axis-state repoints to (source order below is
|
|
25
|
+
* load-bearing — elevation overrides the brightness base plane when both axes are set).
|
|
26
|
+
*
|
|
27
|
+
* Default (no axis set) = transparent: an UNSET container is unchanged (it passes its parent's surface
|
|
28
|
+
* through), so a bare layout primitive adds no plane. Container elements that want a default surface
|
|
29
|
+
* (card/modal) set `--ui-container-bg` in their OWN sheet (specificity wins over this `:where()`); tabs
|
|
30
|
+
* left this trio in ADR-0104 — a bare `<ui-tabs>` is transparent like every other container, and a plane
|
|
31
|
+
* is an asked-for intent via the shipped `elevation`/`brightness` axes.
|
|
32
|
+
*
|
|
33
|
+
* Standalone sheet — linked via the component-styles barrel, NEVER injected from container.ts (behaviour
|
|
34
|
+
* `.ts` holds no runtime style; plan §2). */
|
|
35
|
+
|
|
36
|
+
/* ════════════════ surface seam — the 8 surface-bearing container tags ════════════════ */
|
|
37
|
+
|
|
38
|
+
:where(ui-row, ui-column, ui-list, ui-grid, ui-card, ui-tabs, ui-modal, ui-toolbar) {
|
|
39
|
+
/* The role-pure seam, default = transparent (an unset container is unchanged — ADR-0015 cl.1). */
|
|
40
|
+
--ui-container-bg: transparent; /* the base plane */
|
|
41
|
+
--ui-container-tint: transparent; /* the tonal wash (composition only); 0 ⇒ no-op */
|
|
42
|
+
|
|
43
|
+
/* elevation=0 — the explicit neutral base. Placed FIRST so an active axis (a brightness ladder step below,
|
|
44
|
+
or an elevation step) overrides it; an unset container stays transparent (this rule needs the attribute). */
|
|
45
|
+
&[elevation='0'] {
|
|
46
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* brightness SOLO → the SOLID scheme-consistent ladder as the base plane (ADR-0015 cl.1). When elevation is
|
|
50
|
+
ALSO set, the elevation block below overrides this base (source order) and brightness moves to the wash. */
|
|
51
|
+
&[brightness='-3'] {
|
|
52
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-dimmest);
|
|
53
|
+
}
|
|
54
|
+
&[brightness='-2'] {
|
|
55
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-dimmer);
|
|
56
|
+
}
|
|
57
|
+
&[brightness='-1'] {
|
|
58
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-dim);
|
|
59
|
+
}
|
|
60
|
+
&[brightness='1'] {
|
|
61
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-bright);
|
|
62
|
+
}
|
|
63
|
+
&[brightness='2'] {
|
|
64
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-brighter);
|
|
65
|
+
}
|
|
66
|
+
&[brightness='3'] {
|
|
67
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-brightest);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* elevation → the SOLID scheme-inverting base plane (-3..3 → lowest…highest). After the brightness block,
|
|
71
|
+
so elevation WINS the base plane when both axes are set (equal specificity → later source wins). */
|
|
72
|
+
&[elevation='-3'] {
|
|
73
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-lowest);
|
|
74
|
+
}
|
|
75
|
+
&[elevation='-2'] {
|
|
76
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-lower);
|
|
77
|
+
}
|
|
78
|
+
&[elevation='-1'] {
|
|
79
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-low);
|
|
80
|
+
}
|
|
81
|
+
&[elevation='1'] {
|
|
82
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-high);
|
|
83
|
+
}
|
|
84
|
+
&[elevation='2'] {
|
|
85
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-higher);
|
|
86
|
+
}
|
|
87
|
+
&[elevation='3'] {
|
|
88
|
+
--ui-container-bg: var(--md-sys-color-neutral-surface-highest);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* COMPOSITION tonal WASH — brightness as a translucent overlay, ONLY when elevation is non-zero (s1: the
|
|
92
|
+
tint roles are composition-only). Composites alpha-over the elevation plane set above → the `−m` wash over
|
|
93
|
+
the `+n` plane (ADR-0015 cl.3). The `:is(non-zero elevation)` gate keeps SOLO brightness on the solid
|
|
94
|
+
ladder; the two-attribute selector (0,2,0) outranks the base-plane repoints, but it only sets the tint. */
|
|
95
|
+
&:is([elevation='-3'], [elevation='-2'], [elevation='-1'], [elevation='1'], [elevation='2'], [elevation='3']) {
|
|
96
|
+
&[brightness='-3'] {
|
|
97
|
+
--ui-container-tint: var(--md-sys-color-neutral-tint-dimmest);
|
|
98
|
+
}
|
|
99
|
+
&[brightness='-2'] {
|
|
100
|
+
--ui-container-tint: var(--md-sys-color-neutral-tint-dimmer);
|
|
101
|
+
}
|
|
102
|
+
&[brightness='-1'] {
|
|
103
|
+
--ui-container-tint: var(--md-sys-color-neutral-tint-dim);
|
|
104
|
+
}
|
|
105
|
+
&[brightness='1'] {
|
|
106
|
+
--ui-container-tint: var(--md-sys-color-neutral-tint-bright);
|
|
107
|
+
}
|
|
108
|
+
&[brightness='2'] {
|
|
109
|
+
--ui-container-tint: var(--md-sys-color-neutral-tint-brighter);
|
|
110
|
+
}
|
|
111
|
+
&[brightness='3'] {
|
|
112
|
+
--ui-container-tint: var(--md-sys-color-neutral-tint-brightest);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* The CONSUMPTION — role-pure, reads ONLY the `--ui-container-*` seam. The base plane is the solid
|
|
117
|
+
`background-color`; the tonal wash is a flat same-colour `background-image` gradient stacked ABOVE it, so
|
|
118
|
+
the two axes composite (ADR-0015 cl.3). `:where()` keeps these at specificity 0 so an element's own
|
|
119
|
+
`@scope` surface (card/tabs/modal) cleanly overrides. */
|
|
120
|
+
background-color: var(--ui-container-bg);
|
|
121
|
+
background-image: linear-gradient(var(--ui-container-tint), var(--ui-container-tint));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ════════════════ container-query seam — RE-HOMED to externally-sized boundaries (ADR-0100) ═════════════ */
|
|
125
|
+
|
|
126
|
+
/* NO blanket `container-type: inline-size` here — ADR-0100 DELETED it (it superseded ADR-0016 cl.4's
|
|
127
|
+
establishment sub-clause). `container-type: inline-size` applies inline-axis SIZE CONTAINMENT: the box's
|
|
128
|
+
intrinsic inline sizes compute AS IF IT HAD NO CONTENTS — the same anti-cycle rule that forbids an element
|
|
129
|
+
from size-querying itself. A layout primitive's sizing model is content-driven (shrink-wrap, no frame,
|
|
130
|
+
geometry.md Container/layout class), so an intrinsically-sized primitive CANNOT also be a query container:
|
|
131
|
+
making it one deterministically zeroes its own intrinsic size (a Row nested on a Row's main axis measured
|
|
132
|
+
0px; a contained primitive also contributes 0 intrinsic size through every content-sized ANCESTOR — the
|
|
133
|
+
pattern-dashboard-tiles cards crushed to ~36px chrome-only via their inner contained column). No selector
|
|
134
|
+
can repair this in place (the harm is non-local — safety is a whole-ancestor-chain property, invisible to
|
|
135
|
+
CSS), so establishment moves OFF the primitives entirely.
|
|
136
|
+
THE LAW (ADR-0100 cl.2): `container-type: inline-size` may be declared only on a box whose inline size is
|
|
137
|
+
EXTERNALLY determined — definite, stretched, or track-sized — never content-derived. The `@container` rules
|
|
138
|
+
in row.css/column.css keep their ADR-0096-gated selectors unchanged and now resolve, as they always
|
|
139
|
+
mechanically did, against the nearest ANCESTOR query container — one an externally-sized composition
|
|
140
|
+
boundary establishes (the A2UI mount surfaces: `site/lib/canvas-surface.css`'s `.canvas-surface`,
|
|
141
|
+
`site/lib/a2ui-gallery.css`'s `.seed-surface`, the various page `.surface` mounts, app-shell — ADR-0084 is
|
|
142
|
+
the shipped model case). `ui-grid`'s auto-fit/`minmax` responsiveness is track sizing, not a query, so it is
|
|
143
|
+
unaffected either way. */
|
|
144
|
+
|
|
145
|
+
/* ════════════════ forced-colors (WHCM) ════════════════ */
|
|
146
|
+
|
|
147
|
+
/* Keep the surface a system colour and drop the tonal wash. The colour ROLES already carry the WHCM mapping
|
|
148
|
+
in the token layer (tokens.md / s1 — the tint roles map to transparent under forced-colors), so this is
|
|
149
|
+
mostly belt-and-braces: it guarantees a container's surface survives as `Canvas` and the wash never paints
|
|
150
|
+
over system text. */
|
|
151
|
+
@media (forced-colors: active) {
|
|
152
|
+
:where(ui-row, ui-column, ui-list, ui-grid, ui-card, ui-tabs, ui-modal, ui-toolbar) {
|
|
153
|
+
background-color: Canvas;
|
|
154
|
+
background-image: none;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { PropConfig } from '../../dom/props.js';
|
|
2
|
+
/** One token-surface entry — a `ui-ramp` step or a `ui-ladder` tier (SPEC-R2 Definitions). */
|
|
3
|
+
export interface TokenEntry {
|
|
4
|
+
label: string;
|
|
5
|
+
value: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Harden an arbitrary input into the rendered entry set (SPEC-R7/R11): a non-array input yields `[]`; each
|
|
9
|
+
* entry survives only as a plain object with a `string` `label` AND a `string` `value` — drop, never coerce.
|
|
10
|
+
* Order is preserved (positional semantics — a duplicate-label row: both entries render, the list is
|
|
11
|
+
* positional, not keyed). The bar-chart `cleanData` construction, generalized to a string `value` (a color/
|
|
12
|
+
* length lane, not a number).
|
|
13
|
+
*/
|
|
14
|
+
export declare function cleanEntries(input: unknown): TokenEntry[];
|
|
15
|
+
/** The `steps`/`tiers` prop config — a fresh `PropConfig` each call (default `[]`, never a SHARED mutable array). */
|
|
16
|
+
export declare function tokenEntriesProp(): PropConfig<TokenEntry[]>;
|
|
17
|
+
/**
|
|
18
|
+
* The `--var` lane (SPEC-R2), value-NEUTRAL: a value beginning `--` routes through `var(<value>)`; any other
|
|
19
|
+
* string (a literal color/length, or `''`) is returned VERBATIM. Pure string routing — no resolution, no
|
|
20
|
+
* `getComputedStyle` (the browser resolves the returned expression wherever it lands; the readback is an
|
|
21
|
+
* ADR-0118 cl.2 foreseen extension, out of v1). Used by BOTH swatch/ramp's `background` and ladder's `--_mag`
|
|
22
|
+
* (LLD-C6) — the ONE transform, so a `--`-prefixed value never reaches a CSS property as a bare dashed-ident
|
|
23
|
+
* (`min(100%, --md-sys-height-md)` is invalid at computed-value time; `min(100%, var(--md-sys-height-md))` is what we want).
|
|
24
|
+
*/
|
|
25
|
+
export declare function cssValue(value: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* The length-router (SPEC-R11): true iff `value` is a resolvable CSS length — a `--var` counts (its own
|
|
28
|
+
* resolution is the browser's job, so any `--`-prefixed name is treated as renderable; ladder still routes it
|
|
29
|
+
* through `cssValue` before use). Uses `CSS.supports('inline-size', v)` when available (browser + modern
|
|
30
|
+
* jsdom) for a real platform-truth answer; falls back to the conservative unit regex above so the plain jsdom
|
|
31
|
+
* unit tests still bite when `CSS.supports` is absent. NOT a drop gate (SPEC-R11) — LLD-C6 uses this to ROUTE
|
|
32
|
+
* a non-length value to a zero-length bar (`0px`) while KEEPING the row + its printed value, matching swatch's
|
|
33
|
+
* invalid-color-keeps-the-datum (SPEC-R3) and ramp's invalid-color-keeps-the-cell (SPEC-R7).
|
|
34
|
+
*/
|
|
35
|
+
export declare function isRenderableLength(value: string): boolean;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// token-surface.ts — the shared value-lane helper for the token-surface family (ui-swatch/ui-ramp/ui-ladder;
|
|
2
|
+
// LLD-C1, token-surfaces.lld.md §2; SPEC-R2/R7/R11; ADR-0118 cl.2). DOM-free, unit-testable in plain Vitest —
|
|
3
|
+
// no color math, no getComputedStyle (the browser is the ONE resolver, ADR-0118 cl.2/3). A single shared folder,
|
|
4
|
+
// not three divergent copies (the `_base`/`_surface` precedent): all three controls bind the SAME value-lane
|
|
5
|
+
// contract, unlike the chart family's per-control math (bar-math.ts/sparkline math stay co-located there).
|
|
6
|
+
//
|
|
7
|
+
// Owns three things:
|
|
8
|
+
// 1. `cleanEntries`/`tokenEntriesProp` — the hardened `{label,value}[]` codec (the bar-chart `cleanData`/
|
|
9
|
+
// `barDataProp` construction, generalized: `from(null) = []`, malformed JSON → `[]`, never a throw).
|
|
10
|
+
// 2. `cssValue` — the value-NEUTRAL `--var` lane (SPEC-R2): a `--`-prefixed value routes through `var(<value>)`
|
|
11
|
+
// before it ever reaches a CSS property, so a bare dashed-ident (invalid at computed-value time inside
|
|
12
|
+
// `min(100%, …)`) never poisons ladder's `--_mag` or swatch/ramp's `background`.
|
|
13
|
+
// 3. `isRenderableLength` — the length ROUTER (SPEC-R11): NOT a drop gate — ladder uses it to decide whether a
|
|
14
|
+
// tier's value drives a real bar or a `0px` zero-bar, the row + printed value surviving either way (the
|
|
15
|
+
// unified no-silent-state rule, matching swatch's invalid-color-keeps-the-datum).
|
|
16
|
+
/**
|
|
17
|
+
* Harden an arbitrary input into the rendered entry set (SPEC-R7/R11): a non-array input yields `[]`; each
|
|
18
|
+
* entry survives only as a plain object with a `string` `label` AND a `string` `value` — drop, never coerce.
|
|
19
|
+
* Order is preserved (positional semantics — a duplicate-label row: both entries render, the list is
|
|
20
|
+
* positional, not keyed). The bar-chart `cleanData` construction, generalized to a string `value` (a color/
|
|
21
|
+
* length lane, not a number).
|
|
22
|
+
*/
|
|
23
|
+
export function cleanEntries(input) {
|
|
24
|
+
if (!Array.isArray(input))
|
|
25
|
+
return [];
|
|
26
|
+
const out = [];
|
|
27
|
+
for (const entry of input) {
|
|
28
|
+
if (entry !== null &&
|
|
29
|
+
typeof entry === 'object' &&
|
|
30
|
+
!Array.isArray(entry) &&
|
|
31
|
+
typeof entry.label === 'string' &&
|
|
32
|
+
typeof entry.value === 'string') {
|
|
33
|
+
const e = entry;
|
|
34
|
+
out.push({ label: e.label, value: e.value });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The safe `steps`/`tiers` codec (SPEC-R7/R11 row 1): `from(null)` (attribute absent/removed) → `[]`, NEVER
|
|
41
|
+
* `null`; malformed attribute JSON is caught and also falls back to `[]` — no throw ever reaches
|
|
42
|
+
* `attributeChangedCallback`. `dom/props.ts`'s generic `jsonType<T>()` is deliberately NOT used here — its bare
|
|
43
|
+
* `JSON.parse` throws on malformed attributes and maps a removed attribute to `null`, both of which the
|
|
44
|
+
* hardening rows forbid reaching the render path (the bar-chart `barDataProp` reasoning, restated for the
|
|
45
|
+
* token-surface family's string-valued entries).
|
|
46
|
+
*/
|
|
47
|
+
const tokenEntriesType = {
|
|
48
|
+
from(attr) {
|
|
49
|
+
if (attr === null)
|
|
50
|
+
return [];
|
|
51
|
+
try {
|
|
52
|
+
return cleanEntries(JSON.parse(attr));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
to(value) {
|
|
59
|
+
return JSON.stringify(value);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
/** The `steps`/`tiers` prop config — a fresh `PropConfig` each call (default `[]`, never a SHARED mutable array). */
|
|
63
|
+
export function tokenEntriesProp() {
|
|
64
|
+
return { type: tokenEntriesType, default: [] };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The `--var` lane (SPEC-R2), value-NEUTRAL: a value beginning `--` routes through `var(<value>)`; any other
|
|
68
|
+
* string (a literal color/length, or `''`) is returned VERBATIM. Pure string routing — no resolution, no
|
|
69
|
+
* `getComputedStyle` (the browser resolves the returned expression wherever it lands; the readback is an
|
|
70
|
+
* ADR-0118 cl.2 foreseen extension, out of v1). Used by BOTH swatch/ramp's `background` and ladder's `--_mag`
|
|
71
|
+
* (LLD-C6) — the ONE transform, so a `--`-prefixed value never reaches a CSS property as a bare dashed-ident
|
|
72
|
+
* (`min(100%, --md-sys-height-md)` is invalid at computed-value time; `min(100%, var(--md-sys-height-md))` is what we want).
|
|
73
|
+
*/
|
|
74
|
+
export function cssValue(value) {
|
|
75
|
+
return value.startsWith('--') ? `var(${value})` : value;
|
|
76
|
+
}
|
|
77
|
+
// A conservative CSS-length unit regex — the jsdom fallback when `CSS.supports` is unavailable (older jsdom
|
|
78
|
+
// builds no `CSS.supports`). Matches a signed/unsigned number (incl. a bare `0`, unitless per the CSS spec)
|
|
79
|
+
// followed by one of the standard absolute/relative length units, OR a bare `0`.
|
|
80
|
+
const LENGTH_RE = /^[+-]?\d*\.?\d+(px|em|rem|ex|ch|vw|vh|vmin|vmax|cm|mm|in|pt|pc|q|%)$|^0$/i;
|
|
81
|
+
/**
|
|
82
|
+
* The length-router (SPEC-R11): true iff `value` is a resolvable CSS length — a `--var` counts (its own
|
|
83
|
+
* resolution is the browser's job, so any `--`-prefixed name is treated as renderable; ladder still routes it
|
|
84
|
+
* through `cssValue` before use). Uses `CSS.supports('inline-size', v)` when available (browser + modern
|
|
85
|
+
* jsdom) for a real platform-truth answer; falls back to the conservative unit regex above so the plain jsdom
|
|
86
|
+
* unit tests still bite when `CSS.supports` is absent. NOT a drop gate (SPEC-R11) — LLD-C6 uses this to ROUTE
|
|
87
|
+
* a non-length value to a zero-length bar (`0px`) while KEEPING the row + its printed value, matching swatch's
|
|
88
|
+
* invalid-color-keeps-the-datum (SPEC-R3) and ramp's invalid-color-keeps-the-cell (SPEC-R7).
|
|
89
|
+
*/
|
|
90
|
+
export function isRenderableLength(value) {
|
|
91
|
+
if (value.startsWith('--'))
|
|
92
|
+
return true; // a --var's resolution is the browser's job (cssValue routes it)
|
|
93
|
+
if (typeof CSS !== 'undefined' && typeof CSS.supports === 'function') {
|
|
94
|
+
return CSS.supports('inline-size', value);
|
|
95
|
+
}
|
|
96
|
+
return LENGTH_RE.test(value.trim());
|
|
97
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IconName } from '@agent-ui-kit/icons';
|
|
2
|
+
export type FileCategory = 'image' | 'audio' | 'video' | 'pdf' | 'text' | 'archive' | 'data' | 'default';
|
|
3
|
+
/** SPEC-R9 AC1 — case-insensitive, `;`-parameter-stripped, TOTAL (unknown/empty → 'default'). */
|
|
4
|
+
export declare function fileCategory(mimeType: string): FileCategory;
|
|
5
|
+
export declare function categoryGlyph(c: FileCategory): IconName;
|
|
6
|
+
export declare function categoryLabel(c: FileCategory): string;
|
|
7
|
+
/** SPEC-R9 AC2 — null/non-finite/negative → null (cell absent). Decimal (1000-based) B/KB/MB/GB/TB steps. */
|
|
8
|
+
export declare function formatBytes(size: number | null): string | null;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// attachment-meta.ts — the pure, DOM-free math for `ui-attachment` (LLD-C4, feed-family.lld.md §4;
|
|
2
|
+
// SPEC-R8/R9; ADR-0112 cl.4). Plain functions over strings/numbers — no DOM, no signals, unit-testable
|
|
3
|
+
// without a browser (the stat-model.ts / sparkline-math.ts pure-core precedent).
|
|
4
|
+
//
|
|
5
|
+
// `fileCategory` (SPEC-R9 AC1): case-insensitive, `;`-parameter-stripped mimeType → one of eight
|
|
6
|
+
// categories. Exact/substring matches (`application/pdf`; the data-shaped types — json/xml/csv/
|
|
7
|
+
// spreadsheet) are checked BEFORE the broad `image/`·`audio/`·`video/`·`text/` prefixes, because
|
|
8
|
+
// `text/csv` is a data type, not a text type — an ordering the prefix pass alone cannot express. The
|
|
9
|
+
// archive set follows, then `default` — a TOTAL function, never throws, unknown/empty mime included.
|
|
10
|
+
//
|
|
11
|
+
// `categoryGlyph`/`categoryLabel` (LLD-C4): the fixed per-category icon-name and name-fallback maps.
|
|
12
|
+
//
|
|
13
|
+
// `formatBytes` (SPEC-R9 AC2): `size` (bytes) → a decimal (1000-based) B/KB/MB/GB/TB string via the
|
|
14
|
+
// module-memoized default-locale `Intl.NumberFormat` (≤ 1 fraction digit); `null`/non-finite/negative →
|
|
15
|
+
// `null` (the size cell is absent, never a fabricated "0 B" or "NaN B").
|
|
16
|
+
/** Data-shaped mimeTypes that are NOT read as their broad prefix (SPEC-R9 AC1: `text/csv` → data, not text). */
|
|
17
|
+
const DATA_EXACT = new Set(['application/json', 'application/xml', 'text/xml']);
|
|
18
|
+
/** A mimeType containing either substring is data-shaped (spreadsheet formats, any `csv` variant). */
|
|
19
|
+
const DATA_SUBSTRING = /spreadsheet|csv/;
|
|
20
|
+
/** Archive/compression formats (LLD-C4: zip|tar|gzip|x-7z|rar). */
|
|
21
|
+
const ARCHIVE_MATCH = /zip|tar|gzip|x-7z|rar/;
|
|
22
|
+
/** SPEC-R9 AC1 — case-insensitive, `;`-parameter-stripped, TOTAL (unknown/empty → 'default'). */
|
|
23
|
+
export function fileCategory(mimeType) {
|
|
24
|
+
const mime = mimeType.trim().split(';', 1)[0].trim().toLowerCase();
|
|
25
|
+
if (mime === '')
|
|
26
|
+
return 'default';
|
|
27
|
+
if (mime === 'application/pdf')
|
|
28
|
+
return 'pdf';
|
|
29
|
+
if (DATA_EXACT.has(mime) || DATA_SUBSTRING.test(mime))
|
|
30
|
+
return 'data';
|
|
31
|
+
if (mime.startsWith('image/'))
|
|
32
|
+
return 'image';
|
|
33
|
+
if (mime.startsWith('audio/'))
|
|
34
|
+
return 'audio';
|
|
35
|
+
if (mime.startsWith('video/'))
|
|
36
|
+
return 'video';
|
|
37
|
+
if (mime.startsWith('text/'))
|
|
38
|
+
return 'text';
|
|
39
|
+
if (ARCHIVE_MATCH.test(mime))
|
|
40
|
+
return 'archive';
|
|
41
|
+
return 'default';
|
|
42
|
+
}
|
|
43
|
+
/** The glyph name per category (all vendored, SPEC-N5 — LLD-C9's icons PREP slice). */
|
|
44
|
+
const CATEGORY_GLYPH = {
|
|
45
|
+
image: 'file-image',
|
|
46
|
+
audio: 'file-audio',
|
|
47
|
+
video: 'file-video',
|
|
48
|
+
pdf: 'file-pdf',
|
|
49
|
+
text: 'file-text',
|
|
50
|
+
archive: 'file-zip',
|
|
51
|
+
data: 'file-code',
|
|
52
|
+
default: 'file',
|
|
53
|
+
};
|
|
54
|
+
export function categoryGlyph(c) {
|
|
55
|
+
return CATEGORY_GLYPH[c];
|
|
56
|
+
}
|
|
57
|
+
/** The SPEC-R8 name fallback (never an empty title). */
|
|
58
|
+
const CATEGORY_LABEL = {
|
|
59
|
+
image: 'Image',
|
|
60
|
+
audio: 'Audio',
|
|
61
|
+
video: 'Video',
|
|
62
|
+
pdf: 'PDF document',
|
|
63
|
+
text: 'Text document',
|
|
64
|
+
archive: 'Archive',
|
|
65
|
+
data: 'Data file',
|
|
66
|
+
default: 'File',
|
|
67
|
+
};
|
|
68
|
+
export function categoryLabel(c) {
|
|
69
|
+
return CATEGORY_LABEL[c];
|
|
70
|
+
}
|
|
71
|
+
const UNITS = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
72
|
+
const byteFormat = new Intl.NumberFormat(undefined, { maximumFractionDigits: 1 }); // module-memoized
|
|
73
|
+
/** SPEC-R9 AC2 — null/non-finite/negative → null (cell absent). Decimal (1000-based) B/KB/MB/GB/TB steps. */
|
|
74
|
+
export function formatBytes(size) {
|
|
75
|
+
if (size === null || !Number.isFinite(size) || size < 0)
|
|
76
|
+
return null;
|
|
77
|
+
let value = size;
|
|
78
|
+
let unit = 0;
|
|
79
|
+
while (value >= 1000 && unit < UNITS.length - 1) {
|
|
80
|
+
value /= 1000;
|
|
81
|
+
unit++;
|
|
82
|
+
}
|
|
83
|
+
return `${byteFormat.format(value)} ${UNITS[unit]}`;
|
|
84
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/* attachment.css — ui-attachment, the Display-class FilePart-aligned file card (LLD-C5,
|
|
2
|
+
* feed-family.lld.md §4; SPEC-R9/R18/R19/R20; ADR-0112 cl.4, fork F4). Two sectioned blocks:
|
|
3
|
+
*
|
|
4
|
+
* [1] TOKEN BLOCK — `:where(ui-attachment)` declares --ui-attachment-* from the colour roles
|
|
5
|
+
* (--md-sys-color-{family}-{role}) + the content-icon register (--md-sys-icon-md, geometry.md's
|
|
6
|
+
* "Affordance vs content-icon" taxonomy — the glyph is a CONTENT icon, not an inline affordance,
|
|
7
|
+
* so it rides the icon ramp, never `= font`). Display class (SPEC-R20 AC2): no [size]/[scale]
|
|
8
|
+
* control-band lookup, no --md-sys-height-* consumption — the border/radius/floor are frame constants,
|
|
9
|
+
* the glyph is the fixed default icon-ramp tier (no ancestor [scale] repoint needed at v1).
|
|
10
|
+
* [2] STYLES BLOCK — `@scope (ui-attachment)` consumes ONLY --ui-attachment-*.
|
|
11
|
+
*
|
|
12
|
+
* Posture (fork F4): a compact card with its OWN bordered surface (--md-sys-shape-corner-base, the entry/container
|
|
13
|
+
* radius kin) — one-row anatomy glyph | name+meta, inline-grid + max-inline-size:100% so N-up in a
|
|
14
|
+
* Row(wrap) or as ui-list children both hold with zero extra code (composability, SPEC-R9).
|
|
15
|
+
*
|
|
16
|
+
* Whole-shape floor (SPEC-R18 AC1) — --ui-attachment-min-inline-size guards the slider-dot collapse shape
|
|
17
|
+
* in an unstyled flex row. Rhythm (gap/padding) rides the space ladder — density-responsive for free
|
|
18
|
+
* (SPEC-R18 AC3); the border/radius/floor stay frame constants, unaffected by [density].
|
|
19
|
+
*
|
|
20
|
+
* Truncation (SPEC-R9 AC3): the name cell is single-line ellipsis (the ADR-0106 CSS-only mechanism,
|
|
21
|
+
* cited — its home use here) — `min-inline-size: 0` on the body cell is what lets the name actually
|
|
22
|
+
* shrink to trigger it inside a grid track, not just the property alone.
|
|
23
|
+
*
|
|
24
|
+
* Forced colors (SPEC-R19): the card's border repoints to CanvasText (the boxed identity survives); the
|
|
25
|
+
* glyph is `<ui-icon>` (an inline SVG using currentColor by the icon adapter's own contract) and the name/
|
|
26
|
+
* meta are real text — both survive WHCM with no dedicated rule here.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/* ════════════════ [1] TOKEN BLOCK — :where(ui-attachment) declares --ui-attachment-* ════════════════ */
|
|
30
|
+
|
|
31
|
+
:where(ui-attachment) {
|
|
32
|
+
--ui-attachment-min-inline-size: 12em; /* the whole-shape floor (SPEC-R18 AC1) */
|
|
33
|
+
--ui-attachment-gap: var(--md-sys-space-sm);
|
|
34
|
+
--ui-attachment-pad-inline: var(--md-sys-space-sm);
|
|
35
|
+
--ui-attachment-pad-block: var(--md-sys-space-xs);
|
|
36
|
+
--ui-attachment-border: var(--md-sys-color-neutral-outline);
|
|
37
|
+
--ui-attachment-surface: transparent; /* rides the ambient plane; a page may lift it */
|
|
38
|
+
--ui-attachment-glyph: var(--md-sys-icon-md); /* content-icon register (geometry.md taxonomy), fixed tier — Display class, no [scale] row */
|
|
39
|
+
--ui-attachment-name-ink: var(--md-sys-color-neutral-on-surface);
|
|
40
|
+
--ui-attachment-meta-ink: var(--md-sys-color-neutral-on-surface-variant);
|
|
41
|
+
--ui-attachment-radius: var(--md-sys-shape-corner-base); /* TKT-0066 item 5 ruling: constants route through the own chain */
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* ════════════════ [2] STYLES BLOCK — @scope (ui-attachment) consumes ONLY --ui-attachment-* ════════════════ */
|
|
45
|
+
|
|
46
|
+
@scope (ui-attachment) {
|
|
47
|
+
:scope {
|
|
48
|
+
display: inline-grid;
|
|
49
|
+
grid-template-columns: auto 1fr;
|
|
50
|
+
align-items: center;
|
|
51
|
+
gap: var(--ui-attachment-gap);
|
|
52
|
+
padding-inline: var(--ui-attachment-pad-inline);
|
|
53
|
+
padding-block: var(--ui-attachment-pad-block);
|
|
54
|
+
border: 1px solid var(--ui-attachment-border);
|
|
55
|
+
border-radius: var(--ui-attachment-radius); /* the entry/container radius kin (F4) */
|
|
56
|
+
background: var(--ui-attachment-surface);
|
|
57
|
+
min-inline-size: var(--ui-attachment-min-inline-size);
|
|
58
|
+
max-inline-size: 100%; /* composability — never grows past its container (SPEC-R9 AC3) */
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
:scope [data-part='glyph'] {
|
|
62
|
+
font-size: var(--ui-attachment-glyph); /* <ui-icon> is a 1em box — this IS its size lever */
|
|
63
|
+
color: var(--ui-attachment-meta-ink);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:scope [data-part='body'] {
|
|
67
|
+
display: grid;
|
|
68
|
+
min-inline-size: 0; /* lets the name cell actually shrink to trigger the ellipsis truncation */
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
:scope [data-part='name'] {
|
|
72
|
+
color: var(--ui-attachment-name-ink);
|
|
73
|
+
white-space: nowrap;
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
text-overflow: ellipsis; /* ADR-0106 mechanism, cited — its home use */
|
|
76
|
+
font-size: var(--md-sys-typescale-body-medium-size);
|
|
77
|
+
line-height: var(--md-sys-typescale-body-medium-line-height);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
:scope [data-part='meta'] {
|
|
81
|
+
color: var(--ui-attachment-meta-ink);
|
|
82
|
+
font-size: var(--md-sys-typescale-body-small-size);
|
|
83
|
+
line-height: var(--md-sys-typescale-body-small-line-height);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@media (forced-colors: active) {
|
|
87
|
+
:scope {
|
|
88
|
+
border-color: CanvasText; /* the boxed identity survives; name/meta are real text, glyph is currentColor-based */
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { UIElement, type ReactiveProps } from '../../dom/index.js';
|
|
2
|
+
import '../icon/icon.js';
|
|
3
|
+
declare const props: {
|
|
4
|
+
filename: import("../../index.js").PropConfig<string>;
|
|
5
|
+
mimeType: {
|
|
6
|
+
attribute: string;
|
|
7
|
+
type: import("../../index.js").PropType<string>;
|
|
8
|
+
default: string;
|
|
9
|
+
reflect?: boolean;
|
|
10
|
+
};
|
|
11
|
+
sizeBytes: {
|
|
12
|
+
attribute: string;
|
|
13
|
+
type: import("../../index.js").PropType<number | null>;
|
|
14
|
+
default: number | null;
|
|
15
|
+
reflect?: boolean;
|
|
16
|
+
};
|
|
17
|
+
href: import("../../index.js").PropConfig<string>;
|
|
18
|
+
};
|
|
19
|
+
export interface UIAttachmentElement extends ReactiveProps<typeof props> {
|
|
20
|
+
}
|
|
21
|
+
export declare class UIAttachmentElement extends UIElement {
|
|
22
|
+
static props: {
|
|
23
|
+
filename: import("../../index.js").PropConfig<string>;
|
|
24
|
+
mimeType: {
|
|
25
|
+
attribute: string;
|
|
26
|
+
type: import("../../index.js").PropType<string>;
|
|
27
|
+
default: string;
|
|
28
|
+
reflect?: boolean;
|
|
29
|
+
};
|
|
30
|
+
sizeBytes: {
|
|
31
|
+
attribute: string;
|
|
32
|
+
type: import("../../index.js").PropType<number | null>;
|
|
33
|
+
default: number | null;
|
|
34
|
+
reflect?: boolean;
|
|
35
|
+
};
|
|
36
|
+
href: import("../../index.js").PropConfig<string>;
|
|
37
|
+
};
|
|
38
|
+
protected connected(): void;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// attachment.ts — UIAttachmentElement, the Display-class FilePart-aligned compact file card (LLD-C5,
|
|
2
|
+
// feed-family.lld.md §4; SPEC-R8/R9/R10; ADR-0112 cl.4, fork F4). Non-interactive, non-form-associated
|
|
3
|
+
// leaf (extends UIElement): no events, no keyboard contract, no `[size]`/`[scale]` control geometry
|
|
4
|
+
// (Display class, SPEC-R20). Component-built light DOM only — `render()` stays the inherited no-op.
|
|
5
|
+
//
|
|
6
|
+
// Anatomy (SPEC-R9/R10): a decorative `<ui-icon data-part="glyph">` (aria-hidden by the icon's OWN
|
|
7
|
+
// default — no label is ever set on it, so no attachment-side ARIA work is needed) followed by a
|
|
8
|
+
// `<span data-part="body">` holding the `name` cell (falls back to the file category's label — never an
|
|
9
|
+
// empty title, SPEC-R8 AC2) and, when a finite non-negative `sizeBytes` is present, a `meta` cell with the
|
|
10
|
+
// formatted byte string (absent, not empty, when `sizeBytes` is null/non-finite/negative). One render effect,
|
|
11
|
+
// whole-swap per change (the stat.ts / bar-chart posture — no interior state worth preserving on a
|
|
12
|
+
// four-node card). The host mints NO internals ARIA (SPEC-R10): the name/meta are real DOM text, the
|
|
13
|
+
// accessible datum; the glyph repeats what the name/mime already carry.
|
|
14
|
+
//
|
|
15
|
+
// SCOPE FENCE (feed-family build sequence, LLD §11 Wave M1-a vs M1-c): this file ships the METADATA
|
|
16
|
+
// SURFACE ONLY (LLD-C4/C5). The `href` prop exists now because SPEC-R8 mints it as one of the four
|
|
17
|
+
// wire-mirroring props, but its RENDERING leg — the name cell becoming a native `<a>` under the shared
|
|
18
|
+
// ADR-0114 gate (`controls/text/href.ts`'s `safeHref`/`LINK_REL`/`LINK_TARGET`, LLD-C6) — is DEFERRED to
|
|
19
|
+
// the M1-c wave (with-or-after that shared gate module is confirmed integrated fleet-wide). Until then
|
|
20
|
+
// `href` is inert: read into no effect, rendered nowhere. Do not wire `safeHref` here — that is LLD-C6's
|
|
21
|
+
// own slice, coordinated with the catalog wave (SPEC-R11 AC3's single-gate-module grep).
|
|
22
|
+
import { UIElement, prop } from "../../dom/index.js";
|
|
23
|
+
import "../icon/icon.js"; // side-effect: defines <ui-icon>, the glyph's declarative surface (the avatar/LLD-C5 sibling-control-import idiom)
|
|
24
|
+
import { categoryGlyph, categoryLabel, fileCategory, formatBytes } from "./attachment-meta.js";
|
|
25
|
+
const props = {
|
|
26
|
+
filename: prop.string(''), // optional on the A2aFilePart wire — empty falls back to the category label. Renamed from `name` (TKT-0069 item 1 ruling: `name` = the FORM name, reserved; the A2UI catalog keeps wire `name`, mapped in its bespoke factory)
|
|
27
|
+
// `attribute: 'mime-type'` is load-bearing, not stylistic: Element.setAttribute lowercases the name in
|
|
28
|
+
// an HTML document, so a camelCase observed-attribute name ('mimeType') would never match the always-
|
|
29
|
+
// lowercase real attribute and attributeChangedCallback would silently never fire (the fleet's existing
|
|
30
|
+
// multi-word props are either single-word or already reflect+kebab, e.g. slider-multi's valueLo/valueHi
|
|
31
|
+
// — this is the first non-reflected multi-word prop, so the same kebab discipline applies here too).
|
|
32
|
+
mimeType: { ...prop.string(''), attribute: 'mime-type' }, // drives the glyph + name fallback via fileCategory
|
|
33
|
+
// Named `sizeBytes`/`size-bytes`, NOT `size` (ADR-0112 Amendment 1): the fleet-wide law
|
|
34
|
+
// (family-coherence.test.ts's "a `size` attribute is always exactly [sm, md, lg]") reserves the literal
|
|
35
|
+
// name `size` for the widget-tier geometry enum every sized control shares — this is unrelated byte-count
|
|
36
|
+
// domain data (SPEC-R8), and reusing `size` would silently collide with that convention for any future
|
|
37
|
+
// reader/consumer. Same kebab-attribute discipline as `mimeType` above (multi-word, non-reflected).
|
|
38
|
+
sizeBytes: { ...prop.number(null), attribute: 'size-bytes' }, // bytes; NOT a wire field — embedder-supplied (SPEC-R8); null/non-finite/negative ⇒ no meta cell
|
|
39
|
+
// SPEC-R8's fourth wire-mirroring prop. Rendering leg DEFERRED — see the file header note (LLD-C6).
|
|
40
|
+
href: prop.string(''),
|
|
41
|
+
};
|
|
42
|
+
export class UIAttachmentElement extends UIElement {
|
|
43
|
+
static props = props;
|
|
44
|
+
connected() {
|
|
45
|
+
this.effect(() => {
|
|
46
|
+
const category = fileCategory(this.mimeType);
|
|
47
|
+
const title = this.filename || categoryLabel(category);
|
|
48
|
+
const size = formatBytes(this.sizeBytes);
|
|
49
|
+
const glyph = document.createElement('ui-icon');
|
|
50
|
+
glyph.setAttribute('data-part', 'glyph');
|
|
51
|
+
glyph.setAttribute('glyph', categoryGlyph(category));
|
|
52
|
+
// The name cell is a plain <span> in this pass — the LLD-C6 <a> leg is deferred (file header note).
|
|
53
|
+
const name = document.createElement('span');
|
|
54
|
+
name.setAttribute('data-part', 'name');
|
|
55
|
+
name.textContent = title;
|
|
56
|
+
const body = document.createElement('span');
|
|
57
|
+
body.setAttribute('data-part', 'body');
|
|
58
|
+
body.append(name);
|
|
59
|
+
if (size !== null) {
|
|
60
|
+
const meta = document.createElement('span');
|
|
61
|
+
meta.setAttribute('data-part', 'meta');
|
|
62
|
+
meta.textContent = size;
|
|
63
|
+
body.append(meta);
|
|
64
|
+
}
|
|
65
|
+
this.replaceChildren(glyph, body);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!customElements.get('ui-attachment'))
|
|
70
|
+
customElements.define('ui-attachment', UIAttachmentElement); // idempotent self-define
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** SPEC-R5: first grapheme of first word + first grapheme of last word (single word ⇒ one grapheme),
|
|
2
|
+
* locale-uppercased. Grapheme-safe via Intl.Segmenter('grapheme') with an Array.from code-point
|
|
3
|
+
* fallback (ledger §10.4). '' / whitespace-only ⇒ '' (the caller falls through to the glyph). */
|
|
4
|
+
export declare function initialsFrom(name: string): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// avatar-initials.ts — the pure, DOM-free initials derivation for ui-avatar (LLD-C2, feed-family.lld.md
|
|
2
|
+
// §3; SPEC-R5). A plain function over a string — no DOM, no signals, unit-testable without a browser
|
|
3
|
+
// (the stat-model.ts / attachment-meta.ts pure-core precedent).
|
|
4
|
+
//
|
|
5
|
+
// SPEC-R5: first grapheme of the first word + first grapheme of the last word (a single word yields one
|
|
6
|
+
// grapheme), locale-uppercased. Grapheme-safe via `Intl.Segmenter('grapheme')` with an `Array.from`
|
|
7
|
+
// code-point fallback for environments where Segmenter is unavailable (failure mode #4, the LLD ledger).
|
|
8
|
+
// '' / whitespace-only ⇒ '' — the caller (avatar.ts) falls through to the person-glyph link of the chain.
|
|
9
|
+
const segmenter = typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function'
|
|
10
|
+
? new Intl.Segmenter(undefined, { granularity: 'grapheme' })
|
|
11
|
+
: null;
|
|
12
|
+
/** The first grapheme cluster of a non-empty string (code-point-safe fallback when Segmenter is absent). */
|
|
13
|
+
function firstGrapheme(word) {
|
|
14
|
+
if (segmenter) {
|
|
15
|
+
const first = segmenter.segment(word)[Symbol.iterator]().next();
|
|
16
|
+
return first.done ? '' : first.value.segment;
|
|
17
|
+
}
|
|
18
|
+
return Array.from(word)[0] ?? '';
|
|
19
|
+
}
|
|
20
|
+
/** SPEC-R5: first grapheme of first word + first grapheme of last word (single word ⇒ one grapheme),
|
|
21
|
+
* locale-uppercased. Grapheme-safe via Intl.Segmenter('grapheme') with an Array.from code-point
|
|
22
|
+
* fallback (ledger §10.4). '' / whitespace-only ⇒ '' (the caller falls through to the glyph). */
|
|
23
|
+
export function initialsFrom(name) {
|
|
24
|
+
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
25
|
+
if (words.length === 0)
|
|
26
|
+
return '';
|
|
27
|
+
const first = firstGrapheme(words[0]);
|
|
28
|
+
const initials = words.length === 1 ? first : first + firstGrapheme(words[words.length - 1]);
|
|
29
|
+
return initials.toLocaleUpperCase();
|
|
30
|
+
}
|