@adia-ai/web-components 0.6.49 → 0.7.0
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/CHANGELOG.md +128 -0
- package/components/action-list/action-list.css +1 -1
- package/components/agent-artifact/agent-artifact.class.js +10 -10
- package/components/agent-artifact/agent-artifact.css +1 -1
- package/components/agent-reasoning/agent-reasoning.class.js +52 -1
- package/components/agent-reasoning/agent-reasoning.css +49 -22
- package/components/agent-trace/agent-trace.css +10 -10
- package/components/agent-trace/agent-trace.js +3 -3
- package/components/alert/alert.class.js +8 -1
- package/components/alert/alert.css +13 -1
- package/components/avatar/avatar.a2ui.json +2 -14
- package/components/avatar/avatar.class.js +3 -15
- package/components/avatar/avatar.d.ts +2 -4
- package/components/avatar/avatar.yaml +1 -18
- package/components/breadcrumb/breadcrumb.css +4 -1
- package/components/button/button.a2ui.json +3 -0
- package/components/button/button.css +14 -3
- package/components/button/button.yaml +5 -0
- package/components/calendar-grid/calendar-grid.css +1 -1
- package/components/calendar-picker/calendar-picker.css +5 -2
- package/components/chart/chart.a2ui.json +0 -18
- package/components/chart/chart.class.js +8 -50
- package/components/chart/chart.css +1 -15
- package/components/chart/chart.d.ts +0 -4
- package/components/chart/chart.yaml +0 -24
- package/components/color-input/color-input.css +4 -1
- package/components/combobox/combobox.class.js +11 -0
- package/components/combobox/combobox.css +8 -0
- package/components/date-range-picker/date-range-picker.class.js +5 -1
- package/components/date-range-picker/date-range-picker.css +12 -2
- package/components/datetime-picker/datetime-picker.class.js +3 -0
- package/components/datetime-picker/datetime-picker.css +16 -2
- package/components/empty-state/empty-state.css +11 -4
- package/components/field/field.css +17 -6
- package/components/grid/grid.a2ui.json +5 -0
- package/components/grid/grid.class.js +16 -6
- package/components/grid/grid.css +17 -3
- package/components/grid/grid.d.ts +2 -0
- package/components/grid/grid.yaml +9 -0
- package/components/heatmap/heatmap.class.js +9 -3
- package/components/heatmap/heatmap.css +19 -2
- package/components/image/image.css +4 -1
- package/components/input/input.css +1 -1
- package/components/integration-card/integration-card.class.js +31 -7
- package/components/integration-card/integration-card.test.js +12 -1
- package/components/kbd/kbd.a2ui.json +3 -2
- package/components/kbd/kbd.css +7 -4
- package/components/kbd/kbd.d.ts +2 -2
- package/components/kbd/kbd.yaml +2 -1
- package/components/list/list.class.js +8 -1
- package/components/menu/menu.css +4 -1
- package/components/modal/modal.class.js +10 -1
- package/components/modal/modal.css +9 -0
- package/components/option-card/option-card.a2ui.json +3 -0
- package/components/option-card/option-card.css +44 -19
- package/components/option-card/option-card.yaml +5 -0
- package/components/otp-input/otp-input.css +25 -10
- package/components/page/page.css +64 -11
- package/components/pagination/pagination.class.js +1 -1
- package/components/pagination/pagination.css +9 -1
- package/components/pane/pane.a2ui.json +3 -0
- package/components/pane/pane.class.js +7 -6
- package/components/pane/pane.css +5 -5
- package/components/pane/pane.yaml +6 -0
- package/components/pipeline-status/pipeline-status.css +6 -0
- package/components/popover/popover.css +12 -1
- package/components/preview/preview.css +30 -3
- package/components/progress-row/progress-row.css +3 -1
- package/components/qr-code/qr-code.css +4 -1
- package/components/segmented/segmented.css +4 -1
- package/components/select/select.a2ui.json +1 -1
- package/components/select/select.class.js +63 -7
- package/components/select/select.css +18 -0
- package/components/select/select.yaml +9 -2
- package/components/stack/stack.a2ui.json +12 -1
- package/components/stack/stack.d.ts +2 -2
- package/components/stack/stack.yaml +13 -1
- package/components/stat/stat.a2ui.json +5 -0
- package/components/stat/stat.css +55 -0
- package/components/stat/stat.d.ts +2 -0
- package/components/stat/stat.js +4 -0
- package/components/stat/stat.yaml +9 -0
- package/components/swiper/swiper.class.js +14 -6
- package/components/switch/switch.css +13 -0
- package/components/table/table.a2ui.json +2 -2
- package/components/table/table.css +13 -1
- package/components/table/table.yaml +2 -2
- package/components/time-picker/time-picker.css +4 -1
- package/components/timeline/timeline.class.js +3 -3
- package/components/timeline/timeline.css +23 -5
- package/components/toggle-group/toggle-group.css +4 -1
- package/components/toggle-scheme/toggle-scheme.css +4 -1
- package/components/tree/tree-item.a2ui.json +6 -0
- package/components/tree/tree-item.yaml +13 -1
- package/components/tree/tree.a2ui.json +3 -3
- package/components/tree/tree.class.js +24 -9
- package/components/tree/tree.css +8 -8
- package/components/tree/tree.test.js +52 -0
- package/components/tree/tree.yaml +4 -4
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +84 -84
- package/package.json +3 -3
- package/styles/api/layout.css +7 -0
- package/styles/api/text.css +9 -5
- package/styles/index.css +11 -2
- package/styles/prose.css +8 -0
- package/styles/resets.css +5 -5
- package/styles/themes.css +8 -1
- package/styles/tokens.css +3 -3
- package/styles/type/elements.css +73 -0
- package/styles/type/roles.css +14 -49
- package/styles/type/scale.css +0 -5
- package/styles/typography.css +3 -3
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
@scope (otp-input-ui) {
|
|
2
2
|
:where(:scope) {
|
|
3
3
|
/* ── Tokens ── */
|
|
4
|
-
|
|
4
|
+
/* Digit boxes grow to fill the row, capped at ~1.75× the base control size
|
|
5
|
+
(~52px) so they read as comfortable single-digit boxes. Radius is the
|
|
6
|
+
plain --a-radius-lg token (no min()/clamp expression — radius patterns
|
|
7
|
+
stay simple). Scales with [size] + density (relative to --a-size). */
|
|
8
|
+
--otp-input-size-default: calc(var(--a-size) * 1.75);
|
|
5
9
|
--otp-input-gap-default: var(--a-space-2);
|
|
6
|
-
--otp-input-radius-default: var(--a-radius-
|
|
10
|
+
--otp-input-radius-default: var(--a-radius-lg);
|
|
7
11
|
--otp-input-border-default: var(--a-ui-border);
|
|
8
12
|
--otp-input-border-hover-default: var(--a-ui-border-hover);
|
|
9
13
|
--otp-input-border-focus-default: var(--a-accent);
|
|
@@ -24,15 +28,27 @@
|
|
|
24
28
|
/* ── Base ── */
|
|
25
29
|
box-sizing: border-box;
|
|
26
30
|
display: flex;
|
|
27
|
-
justify-content:
|
|
31
|
+
justify-content: center;
|
|
28
32
|
gap: var(--otp-input-gap, var(--otp-input-gap-default));
|
|
33
|
+
/* Fill the container (a block-level control per ADR-0037) so the digit
|
|
34
|
+
boxes grow to use the available width instead of sitting content-width
|
|
35
|
+
on the left. Boxes flex to fill up to their cap; once capped (very wide
|
|
36
|
+
container) the group centers rather than packing left. (bug-37 follow-up) */
|
|
37
|
+
width: 100%;
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
/* ── Digit inputs ── */
|
|
41
|
+
/* Boxes grow equally to fill the row (flex), staying square (aspect-ratio)
|
|
42
|
+
and capped at --otp-input-size so they read as digit boxes — not huge on a
|
|
43
|
+
wide container, not cramped on a narrow one. The cap keeps --a-radius-md
|
|
44
|
+
proportional (a rounded square, ~25-30%), which is the whole point of the
|
|
45
|
+
bug-37 sizing. */
|
|
32
46
|
[slot="digit"] {
|
|
33
47
|
box-sizing: border-box;
|
|
34
|
-
|
|
35
|
-
|
|
48
|
+
flex: 1 1 0;
|
|
49
|
+
min-width: 0;
|
|
50
|
+
max-width: var(--otp-input-size, var(--otp-input-size-default));
|
|
51
|
+
aspect-ratio: 1;
|
|
36
52
|
text-align: center;
|
|
37
53
|
border: 1px solid var(--otp-input-border, var(--otp-input-border-default));
|
|
38
54
|
border-radius: var(--otp-input-radius, var(--otp-input-radius-default));
|
|
@@ -67,12 +83,11 @@
|
|
|
67
83
|
:scope[disabled] [slot="digit"] {
|
|
68
84
|
background: var(--otp-input-bg-disabled, var(--otp-input-bg-disabled-default));
|
|
69
85
|
color: var(--otp-input-fg-disabled, var(--otp-input-fg-disabled-default));
|
|
70
|
-
/*
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
border-
|
|
86
|
+
/* Native dashed border — it follows the box's border-radius (a rounded
|
|
87
|
+
dashed square, matching the enabled state). An SVG border-image would
|
|
88
|
+
give more uniform dashes but is clipped to a SQUARE — it ignores
|
|
89
|
+
border-radius — so the disabled corners wouldn't round. */
|
|
74
90
|
border: 1px dashed var(--otp-input-border-disabled, var(--otp-input-border-disabled-default));
|
|
75
|
-
border-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28' preserveAspectRatio='none'><rect x='0.5' y='0.5' width='27' height='27' fill='none' stroke='%23999' stroke-width='1' stroke-dasharray='8 6'/></svg>") 1 repeat;
|
|
76
91
|
cursor: not-allowed;
|
|
77
92
|
}
|
|
78
93
|
}
|
package/components/page/page.css
CHANGED
|
@@ -9,6 +9,15 @@
|
|
|
9
9
|
/* ── Padding default (when [padding] is set without a value) ── */
|
|
10
10
|
--page-padding-default: var(--a-space-6);
|
|
11
11
|
|
|
12
|
+
/* ── Region rhythm — vertical gap between header / section / footer,
|
|
13
|
+
mirroring card-ui's section inset. The page [padding] supplies the
|
|
14
|
+
outer frame; this is the inter-region spacing. ── */
|
|
15
|
+
--page-inset-default: var(--a-space-5);
|
|
16
|
+
|
|
17
|
+
/* ── Padded-region sub-surface (a section[padding] inside the page) ── */
|
|
18
|
+
--page-region-bg-default: var(--a-bg-subtle);
|
|
19
|
+
--page-region-radius-default: var(--a-radius-md);
|
|
20
|
+
|
|
12
21
|
/* ── Surfaces ── */
|
|
13
22
|
--page-bg-default: var(--a-canvas-0);
|
|
14
23
|
--page-fg-default: var(--a-fg);
|
|
@@ -23,6 +32,9 @@
|
|
|
23
32
|
box-sizing: border-box;
|
|
24
33
|
display: block;
|
|
25
34
|
width: 100%;
|
|
35
|
+
/* --page-pad carries the resolved [padding] value so the sticky header can
|
|
36
|
+
bleed back over it (card-ui pattern) — see the sticky-header rule. */
|
|
37
|
+
padding: var(--page-pad, 0);
|
|
26
38
|
background: var(--page-bg, var(--page-bg-default));
|
|
27
39
|
color: var(--page-fg, var(--page-fg-default));
|
|
28
40
|
}
|
|
@@ -33,17 +45,47 @@
|
|
|
33
45
|
:scope[max-width="wide"] { max-width: var(--page-max-width-wide, var(--page-max-width-wide-default)); margin-inline: auto; }
|
|
34
46
|
:scope[max-width="full"] { max-width: var(--page-max-width-full, var(--page-max-width-full-default)); }
|
|
35
47
|
|
|
36
|
-
/* ── Padding scale (mirrors --a-space-N) ── */
|
|
37
|
-
:scope[padding=""] {
|
|
38
|
-
:scope[padding="0"] {
|
|
39
|
-
:scope[padding="1"] {
|
|
40
|
-
:scope[padding="2"] {
|
|
41
|
-
:scope[padding="3"] {
|
|
42
|
-
:scope[padding="4"] {
|
|
43
|
-
:scope[padding="5"] {
|
|
44
|
-
:scope[padding="6"] {
|
|
45
|
-
:scope[padding="7"] {
|
|
46
|
-
:scope[padding="8"] {
|
|
48
|
+
/* ── Padding scale (mirrors --a-space-N) — sets --page-pad, applied above ── */
|
|
49
|
+
:scope[padding=""] { --page-pad: var(--page-padding-default); }
|
|
50
|
+
:scope[padding="0"] { --page-pad: 0; }
|
|
51
|
+
:scope[padding="1"] { --page-pad: var(--a-space-1); }
|
|
52
|
+
:scope[padding="2"] { --page-pad: var(--a-space-2); }
|
|
53
|
+
:scope[padding="3"] { --page-pad: var(--a-space-3); }
|
|
54
|
+
:scope[padding="4"] { --page-pad: var(--a-space-4); }
|
|
55
|
+
:scope[padding="5"] { --page-pad: var(--a-space-5); }
|
|
56
|
+
:scope[padding="6"] { --page-pad: var(--a-space-6); }
|
|
57
|
+
:scope[padding="7"] { --page-pad: var(--a-space-7); }
|
|
58
|
+
:scope[padding="8"] { --page-pad: var(--a-space-8); }
|
|
59
|
+
|
|
60
|
+
/* ═══════ Region model — header / section / footer ═══════
|
|
61
|
+
Mirrors card-ui's section model, adapted to the page's [padding] frame:
|
|
62
|
+
the page [padding] is the OUTER inset; these rules add the vertical
|
|
63
|
+
rhythm BETWEEN regions plus the [bleed] / [padding] modifiers. The
|
|
64
|
+
page's own @scope styling the slot primitives is what the docs promise
|
|
65
|
+
([<header>] / [<section>] / [<footer>] and their -ui variants). */
|
|
66
|
+
|
|
67
|
+
/* Vertical rhythm: every region after the first picks up a top margin so
|
|
68
|
+
header → body → footer breathe consistently (the first region hugs the
|
|
69
|
+
padding edge). */
|
|
70
|
+
:scope > :where(header, header-ui, section, section-ui, footer, footer-ui)
|
|
71
|
+
~ :where(header, header-ui, section, section-ui, footer, footer-ui) {
|
|
72
|
+
margin-block-start: var(--page-inset, var(--page-inset-default));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* [bleed] — edge-to-edge region: cancel the page's inline [padding] so
|
|
76
|
+
full-width content (hero, banner, table, chart) reaches the page edges.
|
|
77
|
+
Resolves to 0 (no-op) when the page has no padding. */
|
|
78
|
+
:scope > :where(header, header-ui, section, section-ui, footer, footer-ui)[bleed] {
|
|
79
|
+
margin-inline: calc(-1 * var(--page-pad, 0));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* [padding] on a region — a padded sub-surface with its own background +
|
|
83
|
+
radius, like card-ui's section[padding]. */
|
|
84
|
+
:scope > :where(section, section-ui)[padding] {
|
|
85
|
+
padding: var(--page-inset, var(--page-inset-default));
|
|
86
|
+
background: var(--page-region-bg, var(--page-region-bg-default));
|
|
87
|
+
border-radius: var(--page-region-radius, var(--page-region-radius-default));
|
|
88
|
+
}
|
|
47
89
|
|
|
48
90
|
/* ── Scroll container ── */
|
|
49
91
|
:scope[scroll] {
|
|
@@ -53,11 +95,22 @@
|
|
|
53
95
|
}
|
|
54
96
|
|
|
55
97
|
/* ── Sticky-header support ── */
|
|
98
|
+
/* Drop the page's TOP padding when the header is sticky — that gap is where
|
|
99
|
+
scrolling content used to peek ABOVE the pinned header. The header then
|
|
100
|
+
sits flush at the scroll-container top and supplies its own top spacing
|
|
101
|
+
(padding-block below). */
|
|
102
|
+
:scope[sticky-header] { padding-top: 0; }
|
|
56
103
|
:scope[sticky-header] > :where(header, header-ui) {
|
|
57
104
|
position: sticky;
|
|
58
105
|
top: 0;
|
|
59
106
|
z-index: 1;
|
|
60
107
|
background: var(--page-sticky-bg, var(--page-sticky-bg-default));
|
|
108
|
+
/* Bleed horizontally over the page's inline [padding] so the opaque band
|
|
109
|
+
spans the full scroll width, then re-inset the content so it stays
|
|
110
|
+
aligned with the body. Vertical = its own breathing room. Card-ui
|
|
111
|
+
header pattern. (No negative margin-top — that breaks position:sticky.) */
|
|
112
|
+
margin-inline: calc(-1 * var(--page-pad, 0));
|
|
113
|
+
padding: var(--a-space-3) var(--page-pad, 0);
|
|
61
114
|
transition: border-color var(--a-duration-fast) var(--a-easing), box-shadow var(--a-duration-fast) var(--a-easing);
|
|
62
115
|
}
|
|
63
116
|
|
|
@@ -37,7 +37,7 @@ export class UIPagination extends UIElement {
|
|
|
37
37
|
size: { type: String, default: 'md', reflect: true },
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
// Phosphor icons stamped by this primitive (prev/next
|
|
40
|
+
// Phosphor icons stamped by this primitive (prev/next carets inside
|
|
41
41
|
// the nested <button-ui>). Audited by check-required-icons.mjs.
|
|
42
42
|
static requiredIcons = ['caret-left', 'caret-right'];
|
|
43
43
|
|
|
@@ -23,9 +23,12 @@
|
|
|
23
23
|
:scope {
|
|
24
24
|
/* ── Base ── */
|
|
25
25
|
box-sizing: border-box;
|
|
26
|
-
display:
|
|
26
|
+
display: flex;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/* Display convention (ADR-0037): block-level by default; [inline] opts back to inline-level. */
|
|
30
|
+
:scope[inline] { display: inline-flex; }
|
|
31
|
+
|
|
29
32
|
/* ── Nav container ── */
|
|
30
33
|
[slot="nav"] {
|
|
31
34
|
display: flex;
|
|
@@ -66,5 +69,10 @@
|
|
|
66
69
|
aspect-ratio 1 here for the bordered-cell look). */
|
|
67
70
|
:scope[variant="button"] [slot="nav"] button-ui {
|
|
68
71
|
aspect-ratio: 1;
|
|
72
|
+
/* 1:1 cells inherit button-ui's --a-radius-md (~13px), which on a square
|
|
73
|
+
cell is ~37% of the side → a circle, not the "square 1:1 bordered button"
|
|
74
|
+
the variant promises. Tighten to -sm so the bordered cells read as rounded
|
|
75
|
+
squares. Same square+large-radius trap as otp-input (bug-37 / bug-39). */
|
|
76
|
+
--button-radius: var(--a-radius-sm);
|
|
69
77
|
}
|
|
70
78
|
}
|
|
@@ -82,6 +82,9 @@
|
|
|
82
82
|
"text-area"
|
|
83
83
|
],
|
|
84
84
|
"slots": {
|
|
85
|
+
"caret": {
|
|
86
|
+
"description": "Collapse caret inside the header. Auto-stamped as `<icon-ui slot=\"caret\" name=\"caret-right\">` (rotates on `[collapsed]`). Supply your own `slot=\"caret\"` child in the header to customize — adopt-or-stamp honors a declarative caret instead of stamping."
|
|
87
|
+
},
|
|
85
88
|
"header": {
|
|
86
89
|
"description": "Auto-created header element with label text and toggle arrow"
|
|
87
90
|
}
|
|
@@ -100,12 +100,13 @@ export class UIPane extends UIElement {
|
|
|
100
100
|
header.setAttribute('tabindex', '0');
|
|
101
101
|
header.setAttribute('aria-expanded', String(!this.collapsed));
|
|
102
102
|
|
|
103
|
-
// Stamp
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
// Stamp the caret icon if not present (adopt-or-stamp: a declarative
|
|
104
|
+
// [slot="caret"] child is honored, else we stamp the default).
|
|
105
|
+
if (!header.querySelector('[slot="caret"]')) {
|
|
106
|
+
const caret = document.createElement('icon-ui');
|
|
107
|
+
caret.setAttribute('slot', 'caret');
|
|
108
|
+
caret.setAttribute('name', 'caret-right');
|
|
109
|
+
header.append(caret);
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
}
|
package/components/pane/pane.css
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
/* ── Header interaction ── */
|
|
31
31
|
--pane-header-bg-hover-default: var(--a-bg-subtle);
|
|
32
|
-
--pane-
|
|
32
|
+
--pane-caret-fg-default: var(--a-fg-muted);
|
|
33
33
|
|
|
34
34
|
/* ── Section header ── */
|
|
35
35
|
--pane-section-header-weight-default: var(--a-weight-medium);
|
|
@@ -107,17 +107,17 @@
|
|
|
107
107
|
box-shadow: var(--a-focus-ring) inset;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
/* Collapse indicator — stamped by JS as icon-ui */
|
|
111
|
-
& > header > [slot="
|
|
110
|
+
/* Collapse indicator (caret) — stamped by JS as icon-ui */
|
|
111
|
+
& > header > [slot="caret"] {
|
|
112
112
|
--a-icon-size: var(--a-caret-size);
|
|
113
113
|
flex-shrink: 0;
|
|
114
114
|
margin-inline-start: auto;
|
|
115
|
-
color: var(--pane-
|
|
115
|
+
color: var(--pane-caret-fg, var(--pane-caret-fg-default));
|
|
116
116
|
transition: transform var(--pane-duration, var(--pane-duration-default)) var(--pane-easing, var(--pane-easing-default));
|
|
117
117
|
transform: rotate(90deg);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
:scope[collapsed] > header > [slot="
|
|
120
|
+
:scope[collapsed] > header > [slot="caret"] {
|
|
121
121
|
transform: rotate(0deg);
|
|
122
122
|
}
|
|
123
123
|
|
|
@@ -62,6 +62,12 @@ events:
|
|
|
62
62
|
slots:
|
|
63
63
|
header:
|
|
64
64
|
description: Auto-created header element with label text and toggle arrow
|
|
65
|
+
caret:
|
|
66
|
+
description: >-
|
|
67
|
+
Collapse caret inside the header. Auto-stamped as
|
|
68
|
+
`<icon-ui slot="caret" name="caret-right">` (rotates on `[collapsed]`).
|
|
69
|
+
Supply your own `slot="caret"` child in the header to customize —
|
|
70
|
+
adopt-or-stamp honors a declarative caret instead of stamping.
|
|
65
71
|
states:
|
|
66
72
|
- name: idle
|
|
67
73
|
description: Default, ready for interaction.
|
|
@@ -96,11 +96,17 @@
|
|
|
96
96
|
transition: background var(--pipeline-status-duration, var(--pipeline-status-duration-default)) var(--pipeline-status-easing, var(--pipeline-status-easing-default));
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/* State colors: the -active (accent) / -complete (success) dot-bg tokens were
|
|
100
|
+
defined but never applied — these rules only set animation, so every dot
|
|
101
|
+
stayed the default gray (--a-border). Now active dots read accent + pulse,
|
|
102
|
+
complete dots read success. (bug-40 — "use color more") */
|
|
99
103
|
[data-pipeline-dot="active"] {
|
|
104
|
+
background: var(--pipeline-status-dot-bg-active, var(--pipeline-status-dot-bg-active-default));
|
|
100
105
|
animation: pipeline-pulse var(--pipeline-status-pulse-duration, var(--pipeline-status-pulse-duration-default)) var(--pipeline-status-pulse-easing, var(--pipeline-status-pulse-easing-default)) infinite;
|
|
101
106
|
}
|
|
102
107
|
|
|
103
108
|
[data-pipeline-dot="complete"] {
|
|
109
|
+
background: var(--pipeline-status-dot-bg-complete, var(--pipeline-status-dot-bg-complete-default));
|
|
104
110
|
animation: none;
|
|
105
111
|
}
|
|
106
112
|
|
|
@@ -14,10 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
:scope {
|
|
16
16
|
box-sizing: border-box;
|
|
17
|
-
display:
|
|
17
|
+
display: flex;
|
|
18
18
|
position: relative;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/* Display convention (ADR-0037): block-level by default; [inline] opts back to inline-level. */
|
|
22
|
+
:scope[inline] { display: inline-flex; }
|
|
23
|
+
|
|
21
24
|
[slot="trigger"] {
|
|
22
25
|
display: inline-flex;
|
|
23
26
|
}
|
|
@@ -81,6 +84,14 @@
|
|
|
81
84
|
box-shadow: var(--popover-shadow, var(--popover-shadow-default));
|
|
82
85
|
}
|
|
83
86
|
|
|
87
|
+
/* Prose margin reset on the content's edge children — a slotted <p> / <h*>
|
|
88
|
+
carries the UA stylesheet's margin-block (~1em), which lands inside the
|
|
89
|
+
panel padding and adds asymmetric top/bottom space (a single-line <p> looked
|
|
90
|
+
like it had a stray bottom margin). Zero the leading/trailing margins so the
|
|
91
|
+
panel padding alone frames the content. (bug — Popover single-line space) */
|
|
92
|
+
[slot="content"] > :first-child { margin-block-start: 0; }
|
|
93
|
+
[slot="content"] > :last-child { margin-block-end: 0; }
|
|
94
|
+
|
|
84
95
|
[slot="content"]:popover-open {
|
|
85
96
|
@starting-style {
|
|
86
97
|
opacity: 0;
|
|
@@ -39,16 +39,42 @@
|
|
|
39
39
|
by the frame's overflow:hidden. Most demos fit (the component's overflow
|
|
40
40
|
check stacks split→full-width first), so the scrollbar only appears when a
|
|
41
41
|
demo is genuinely wider than the docs column. */
|
|
42
|
+
/* Column flow is the default: each example stacks in DOM order and fills the
|
|
43
|
+
stage width (align-items: stretch), so block-level demos (progress / bars /
|
|
44
|
+
accordion / cards / pages …) read at full width without a per-component
|
|
45
|
+
list. Text-flow atoms (button / badge / tag / …) opt back to content-width
|
|
46
|
+
via align-self below. (bug-46 — replaces the old flex-row + :only-child
|
|
47
|
+
block-flow hack, which only filled single-child demos.) */
|
|
42
48
|
[data-preview-render] {
|
|
43
49
|
display: flex;
|
|
44
|
-
flex-
|
|
45
|
-
align-items:
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
align-items: stretch;
|
|
46
52
|
gap: var(--preview-render-gap, var(--preview-render-gap-default));
|
|
47
53
|
padding: var(--preview-render-pad, var(--preview-render-pad-default));
|
|
48
54
|
background: var(--preview-render-bg, var(--preview-render-bg-default));
|
|
49
55
|
overflow-x: auto;
|
|
50
56
|
}
|
|
51
|
-
|
|
57
|
+
/* Lone text-flow atoms shouldn't span the whole stage — keep them
|
|
58
|
+
content-width + leading-aligned (the ADR-0037 inline-display set). */
|
|
59
|
+
[data-preview-render] > :is(button-ui, badge-ui, tag-ui, chip-ui, kbd-ui, icon-ui, swatch-ui, spinner-ui, switch-ui, avatar-ui) {
|
|
60
|
+
align-self: start;
|
|
61
|
+
}
|
|
62
|
+
/* Form-field demos collapse to content-width as flex items in the render
|
|
63
|
+
cell — a placeholder-only combobox shrank to a ~52px "Sel…" stub — so
|
|
64
|
+
stretch form controls to the cell width with width:100%.
|
|
65
|
+
• <field-ui> is a full-width form ROW: let it fill the whole stage,
|
|
66
|
+
NO measure cap. The prior 28rem cap read as "not using available
|
|
67
|
+
space" on wide single-block demos (bug-55 follow-up).
|
|
68
|
+
• Bare atomic controls (input/select/…) keep the 28rem measure cap so
|
|
69
|
+
a lone control doesn't sprawl into an unrealistic bar on a wide stage.
|
|
70
|
+
Non-form demos (buttons, badges, etc.) are untouched — content-width. */
|
|
71
|
+
[data-preview-render] field-ui {
|
|
72
|
+
width: 100%;
|
|
73
|
+
}
|
|
74
|
+
[data-preview-render] > :is(input-ui, select-ui, combobox-ui, textarea-ui, tags-input-ui, color-input-ui) {
|
|
75
|
+
width: 100%;
|
|
76
|
+
max-width: 28rem;
|
|
77
|
+
}
|
|
52
78
|
/* Code pane — divider line between panes; flatten the nested code-ui
|
|
53
79
|
chrome so the preview frame owns the outer border + radius. */
|
|
54
80
|
[data-preview-code] {
|
|
@@ -151,6 +177,7 @@
|
|
|
151
177
|
color: var(--a-fg-muted);
|
|
152
178
|
background: var(--a-bg-muted);
|
|
153
179
|
padding: 0.125rem 0.375rem;
|
|
180
|
+
margin-bottom: 0.5rem;
|
|
154
181
|
border-radius: var(--a-radius-sm);
|
|
155
182
|
}
|
|
156
183
|
/* Narrow: collapse each row to stacked render-over-code. */
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
@scope (progress-row-ui) {
|
|
2
2
|
:where(:scope) {
|
|
3
3
|
/* ── Tokens ── */
|
|
4
|
-
|
|
4
|
+
/* Row-gap between the label/meta row and the bar. Bumped --a-space-1 →
|
|
5
|
+
--a-space-2 so the bar isn't crammed under the label. (bug-42) */
|
|
6
|
+
--progress-row-gap-default: var(--a-space-2);
|
|
5
7
|
--progress-row-column-gap-default: var(--a-space-2);
|
|
6
8
|
--progress-row-label-size-default: var(--a-ui-size);
|
|
7
9
|
--progress-row-label-fg-default: var(--a-fg);
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
:scope {
|
|
12
12
|
box-sizing: border-box;
|
|
13
|
-
display:
|
|
13
|
+
display: block;
|
|
14
14
|
/* The SVG itself carries explicit width/height; this is a fallback
|
|
15
15
|
for cases where the SVG hasn't stamped yet (empty value/matrix). */
|
|
16
16
|
line-height: 0;
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
background: var(--qr-code-bg, var(--qr-code-bg-default));
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/* Display convention (ADR-0037): block-level by default; [inline] opts back to inline-level. */
|
|
22
|
+
:scope[inline] { display: inline-block; }
|
|
23
|
+
|
|
21
24
|
:scope svg {
|
|
22
25
|
display: block;
|
|
23
26
|
/* Width / height come from the explicit SVG attributes set by JS
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
:scope {
|
|
29
29
|
/* ── Base ── */
|
|
30
30
|
box-sizing: border-box;
|
|
31
|
-
display:
|
|
31
|
+
display: grid;
|
|
32
32
|
grid-auto-flow: column;
|
|
33
33
|
grid-auto-columns: 1fr;
|
|
34
34
|
align-items: stretch;
|
|
@@ -55,6 +55,9 @@
|
|
|
55
55
|
border-radius: var(--segmented-radius, var(--segmented-radius-default));
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/* Display convention (ADR-0037): block-level by default; [inline] opts back to inline-level. */
|
|
59
|
+
:scope[inline] { display: inline-grid; }
|
|
60
|
+
|
|
58
61
|
/* -- Indicator (hidden until first selection) -- */
|
|
59
62
|
:scope > [data-indicator] {
|
|
60
63
|
display: none;
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"default": false
|
|
108
108
|
},
|
|
109
109
|
"options": {
|
|
110
|
-
"description": "Option list. Array of {value, label, disabled?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children.",
|
|
110
|
+
"description": "Option list. Array of {value, label, disabled?, icon?, avatar?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children. Per-option icon/avatar render in the list AND reflect in the trigger's selected state.",
|
|
111
111
|
"type": "array",
|
|
112
112
|
"default": []
|
|
113
113
|
},
|
|
@@ -71,6 +71,7 @@ export class UISelect extends UIFormElement {
|
|
|
71
71
|
static template = () => null;
|
|
72
72
|
|
|
73
73
|
#options = [];
|
|
74
|
+
#ownTrigger = false; // true when WE stamped the trigger (vs a consumer-custom one)
|
|
74
75
|
#listbox = null;
|
|
75
76
|
#anchorCleanup = null;
|
|
76
77
|
#query = '';
|
|
@@ -386,14 +387,18 @@ export class UISelect extends UIFormElement {
|
|
|
386
387
|
|
|
387
388
|
// Stamp default trigger if none provided
|
|
388
389
|
if (!this.querySelector('[slot="trigger"]')) {
|
|
390
|
+
this.#ownTrigger = true;
|
|
389
391
|
// Detach listbox before innerHTML wipe so it isn't destroyed
|
|
390
392
|
const lb = this.#listbox;
|
|
391
393
|
if (lb?.parentNode === this) this.removeChild(lb);
|
|
392
394
|
|
|
395
|
+
// Initial leading reflects the host [avatar]/[icon]; #syncLeading() then
|
|
396
|
+
// reconciles it to the SELECTED option's icon/avatar on every render. The
|
|
397
|
+
// `data-select-leading` marker scopes that reconciliation to our element.
|
|
393
398
|
const leading = this.avatar
|
|
394
|
-
? `<img slot="leading" src="${this.avatar}" alt="" />`
|
|
399
|
+
? `<img slot="leading" data-select-leading src="${escapeHTML(this.avatar)}" alt="" />`
|
|
395
400
|
: this.icon
|
|
396
|
-
? `<icon-ui slot="leading" name="${this.icon}"></icon-ui>`
|
|
401
|
+
? `<icon-ui slot="leading" data-select-leading name="${escapeHTML(this.icon)}"></icon-ui>`
|
|
397
402
|
: '';
|
|
398
403
|
const displayMarkup = this.searchable
|
|
399
404
|
? `<input slot="display" type="text" role="combobox" aria-autocomplete="list" autocomplete="off" placeholder="${escapeHTML(this.placeholder || '')}" value="${escapeHTML(this.#displayText() === this.placeholder ? '' : this.#displayText())}" />`
|
|
@@ -470,6 +475,9 @@ export class UISelect extends UIFormElement {
|
|
|
470
475
|
}
|
|
471
476
|
}
|
|
472
477
|
|
|
478
|
+
// Reflect the selected option's icon/avatar in the trigger leading.
|
|
479
|
+
this.#syncLeading();
|
|
480
|
+
|
|
473
481
|
// SPEC-040 — stamp / reconcile chips + "+N more" pill on every render.
|
|
474
482
|
if (this.multiple) this.#stampChips();
|
|
475
483
|
// Show clear-all only in multi-select mode when [clearable] + chips present.
|
|
@@ -548,12 +556,12 @@ export class UISelect extends UIFormElement {
|
|
|
548
556
|
if (child.tagName === 'OPTGROUP') {
|
|
549
557
|
const group = { label: child.label || child.getAttribute('label') || '', options: [] };
|
|
550
558
|
for (const opt of child.querySelectorAll('option')) {
|
|
551
|
-
group.options.push({ value: opt.value, label: opt.textContent.trim(), disabled: opt.disabled });
|
|
559
|
+
group.options.push({ value: opt.value, label: opt.textContent.trim(), disabled: opt.disabled, icon: opt.getAttribute('icon') || '', avatar: opt.getAttribute('avatar') || '' });
|
|
552
560
|
if (opt.hasAttribute('selected')) preSelectedArr.push(opt.value);
|
|
553
561
|
}
|
|
554
562
|
this.#options.push(group);
|
|
555
563
|
} else if (child.tagName === 'OPTION') {
|
|
556
|
-
this.#options.push({ value: child.value, label: child.textContent.trim(), disabled: child.disabled });
|
|
564
|
+
this.#options.push({ value: child.value, label: child.textContent.trim(), disabled: child.disabled, icon: child.getAttribute('icon') || '', avatar: child.getAttribute('avatar') || '' });
|
|
557
565
|
if (child.hasAttribute('selected')) preSelectedArr.push(child.value);
|
|
558
566
|
} else if (
|
|
559
567
|
// §225: skip [slot="display"] / [slot="listbox"] / [slot="action"] etc. — these are
|
|
@@ -614,6 +622,52 @@ export class UISelect extends UIFormElement {
|
|
|
614
622
|
|
|
615
623
|
get options() { return this.#options; }
|
|
616
624
|
|
|
625
|
+
// Per-option leading markup: avatar (img) beats icon (icon-ui). Shared by
|
|
626
|
+
// the listbox rows AND the trigger (resolved against the selected option).
|
|
627
|
+
static #optionLeadHTML(opt) {
|
|
628
|
+
if (!opt) return '';
|
|
629
|
+
if (opt.avatar) return `<img data-option-avatar src="${escapeHTML(opt.avatar)}" alt="" />`;
|
|
630
|
+
if (opt.icon) return `<icon-ui name="${escapeHTML(opt.icon)}"></icon-ui>`;
|
|
631
|
+
return '';
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Reflect the SELECTED option's icon/avatar in the trigger's leading slot.
|
|
636
|
+
* Single-select only (multi-select shows chips). Falls back to the host
|
|
637
|
+
* [avatar]/[icon] when the selected option carries neither. Only manages the
|
|
638
|
+
* leading WE stamped (`[data-select-leading]`) — a consumer-custom trigger
|
|
639
|
+
* owns its own leading.
|
|
640
|
+
*/
|
|
641
|
+
#syncLeading() {
|
|
642
|
+
if (this.multiple || !this.#ownTrigger) return;
|
|
643
|
+
const trigger = this.querySelector('[slot="trigger"]');
|
|
644
|
+
if (!trigger) return;
|
|
645
|
+
const flat = this.#options.flatMap((o) => o.options || [o]);
|
|
646
|
+
const sel = flat.find((o) => !o.header && !o.separator && o.value === this.value);
|
|
647
|
+
const avatar = (sel && sel.avatar) || this.avatar || '';
|
|
648
|
+
const icon = (sel && sel.icon) || this.icon || '';
|
|
649
|
+
const existing = trigger.querySelector(':scope > [data-select-leading]');
|
|
650
|
+
let html = '';
|
|
651
|
+
if (avatar) html = `<img slot="leading" data-select-leading src="${escapeHTML(avatar)}" alt="" />`;
|
|
652
|
+
else if (icon) html = `<icon-ui slot="leading" data-select-leading name="${escapeHTML(icon)}"></icon-ui>`;
|
|
653
|
+
if (!html) { existing?.remove(); return; }
|
|
654
|
+
const tmp = document.createElement('template');
|
|
655
|
+
tmp.innerHTML = html;
|
|
656
|
+
const next = tmp.content.firstElementChild;
|
|
657
|
+
if (!existing) {
|
|
658
|
+
trigger.insertBefore(next, trigger.firstChild);
|
|
659
|
+
} else if (existing.tagName === next.tagName) {
|
|
660
|
+
// Same element type — update the changing attribute in place.
|
|
661
|
+
if (next.tagName === 'IMG') {
|
|
662
|
+
if (existing.getAttribute('src') !== next.getAttribute('src')) existing.setAttribute('src', next.getAttribute('src'));
|
|
663
|
+
} else if (existing.getAttribute('name') !== next.getAttribute('name')) {
|
|
664
|
+
existing.setAttribute('name', next.getAttribute('name'));
|
|
665
|
+
}
|
|
666
|
+
} else {
|
|
667
|
+
existing.replaceWith(next); // icon ↔ avatar switch
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
617
671
|
#renderOptions() {
|
|
618
672
|
if (!this.#listbox) return;
|
|
619
673
|
this.#listbox.innerHTML = '';
|
|
@@ -653,6 +707,8 @@ export class UISelect extends UIFormElement {
|
|
|
653
707
|
// SPEC-040 — multi-select option rows render a leading checkbox
|
|
654
708
|
// indicator (CSS-driven via [data-multi-option]); the `check` icon
|
|
655
709
|
// shows when aria-selected="true".
|
|
710
|
+
// Per-option leading glyph — avatar (img) wins over icon (icon-ui).
|
|
711
|
+
const lead = UISelect.#optionLeadHTML(opt);
|
|
656
712
|
if (this.multiple) {
|
|
657
713
|
el.setAttribute('data-multi-option', '');
|
|
658
714
|
const box = document.createElement('span');
|
|
@@ -661,11 +717,11 @@ export class UISelect extends UIFormElement {
|
|
|
661
717
|
el.appendChild(box);
|
|
662
718
|
const label = document.createElement('span');
|
|
663
719
|
label.setAttribute('data-option-label', '');
|
|
664
|
-
if (
|
|
720
|
+
if (lead) label.innerHTML = `${lead}${escapeHTML(opt.label)}`;
|
|
665
721
|
else label.textContent = opt.label;
|
|
666
722
|
el.appendChild(label);
|
|
667
|
-
} else if (
|
|
668
|
-
el.innerHTML =
|
|
723
|
+
} else if (lead) {
|
|
724
|
+
el.innerHTML = `${lead}${escapeHTML(opt.label)}`;
|
|
669
725
|
} else {
|
|
670
726
|
el.textContent = opt.label;
|
|
671
727
|
}
|
|
@@ -191,6 +191,11 @@
|
|
|
191
191
|
:scope[data-multi-chips] [slot="trigger"] {
|
|
192
192
|
flex-wrap: wrap;
|
|
193
193
|
align-items: center;
|
|
194
|
+
/* Pack chips left with a small gap — override the base trigger's
|
|
195
|
+
`space-between` (which is for the single-select content↔caret split),
|
|
196
|
+
otherwise the chips spread across the full trigger width. The display
|
|
197
|
+
slot flex-grows (below) to push the caret to the trailing edge. */
|
|
198
|
+
justify-content: flex-start;
|
|
194
199
|
gap: var(--a-space-1);
|
|
195
200
|
/* min-height tracks single-row height when empty; flex-wrap allows
|
|
196
201
|
it to grow as chips overflow. */
|
|
@@ -290,6 +295,8 @@ select-ui [slot="listbox"]:popover-open {
|
|
|
290
295
|
}
|
|
291
296
|
|
|
292
297
|
select-ui [role="option"] {
|
|
298
|
+
display: flex;
|
|
299
|
+
align-items: center;
|
|
293
300
|
padding: var(--a-space-1) var(--a-ui-px);
|
|
294
301
|
border-radius: var(--a-radius-sm);
|
|
295
302
|
white-space: nowrap;
|
|
@@ -325,6 +332,17 @@ select-ui [role="option"] icon-ui {
|
|
|
325
332
|
vertical-align: -0.125em;
|
|
326
333
|
}
|
|
327
334
|
|
|
335
|
+
/* Option with avatar — small inline image (matches the trigger leading
|
|
336
|
+
avatar radius), sized to the option line-height. */
|
|
337
|
+
select-ui [role="option"] img[data-option-avatar] {
|
|
338
|
+
width: var(--a-ui-size);
|
|
339
|
+
height: var(--a-ui-size);
|
|
340
|
+
border-radius: var(--select-leading-radius, var(--select-leading-radius-default));
|
|
341
|
+
object-fit: cover;
|
|
342
|
+
margin-inline-end: var(--a-space-1);
|
|
343
|
+
vertical-align: -0.2em;
|
|
344
|
+
}
|
|
345
|
+
|
|
328
346
|
/* Separator */
|
|
329
347
|
select-ui [data-separator] {
|
|
330
348
|
height: 1px;
|
|
@@ -23,7 +23,7 @@ description: |
|
|
|
23
23
|
# Per ADR-0027 — primitives that programmatically create other primitives
|
|
24
24
|
# do NOT auto-import them. Consumer (or demo shell) must explicitly import.
|
|
25
25
|
composes:
|
|
26
|
-
- icon-ui #
|
|
26
|
+
- icon-ui # caret + option-row affixes (created in render)
|
|
27
27
|
- tag-ui # multi-select chip per selected option in the trigger
|
|
28
28
|
props:
|
|
29
29
|
name:
|
|
@@ -151,7 +151,7 @@ props:
|
|
|
151
151
|
default: false
|
|
152
152
|
reflect: true
|
|
153
153
|
options:
|
|
154
|
-
description: "Option list. Array of {value, label, disabled?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children."
|
|
154
|
+
description: "Option list. Array of {value, label, disabled?, icon?, avatar?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children. Per-option icon/avatar render in the list AND reflect in the trigger's selected state."
|
|
155
155
|
type: array
|
|
156
156
|
default: []
|
|
157
157
|
pattern:
|
|
@@ -249,6 +249,13 @@ a2ui:
|
|
|
249
249
|
tag names are silently ignored (per §225 v0.5.9) and warned once
|
|
250
250
|
at runtime. Or set `.options` programmatically as an array of
|
|
251
251
|
`{value, label, disabled?}` (grouped form: `{label, options:[…]}`).
|
|
252
|
+
- >-
|
|
253
|
+
Per-option visuals: give each <option> an `icon` (Phosphor name) or
|
|
254
|
+
`avatar` (image URL) — `<option value="light" icon="sun">`. Each row
|
|
255
|
+
renders its glyph in the list AND the trigger reflects the SELECTED
|
|
256
|
+
option's icon/avatar (theme pickers, assignee/account switchers).
|
|
257
|
+
`avatar` wins over `icon`; a host-level [icon]/[avatar] is the
|
|
258
|
+
fallback when the selected option carries neither.
|
|
252
259
|
- >-
|
|
253
260
|
For dynamic option lists rendered inside <editor-shell>, set the
|
|
254
261
|
JSON via the [data-options] attribute — <editor-shell>'s
|