@adia-ai/web-components 0.0.26 → 0.0.27
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/components/agent-artifact/agent-artifact.a2ui.json +1 -1
- package/components/agent-artifact/agent-artifact.css +11 -0
- package/components/agent-artifact/agent-artifact.js +23 -2
- package/components/agent-artifact/agent-artifact.yaml +1 -1
- package/components/agent-reasoning/agent-reasoning.css +11 -0
- package/components/agent-reasoning/agent-reasoning.js +16 -0
- package/components/agent-trace/agent-trace.css +19 -0
- package/components/alert/alert.a2ui.json +10 -4
- package/components/alert/alert.css +13 -0
- package/components/alert/alert.js +1 -1
- package/components/alert/alert.yaml +21 -4
- package/components/badge/badge.a2ui.json +0 -2
- package/components/badge/badge.css +20 -0
- package/components/badge/badge.js +1 -1
- package/components/badge/badge.yaml +0 -2
- package/components/calendar-picker/calendar-picker.css +17 -0
- package/components/code/code.css +41 -0
- package/components/code/code.js +44 -3
- package/components/empty-state/empty-state.js +32 -21
- package/components/list/list.js +20 -16
- package/components/menu/menu.css +18 -0
- package/components/menu/menu.js +24 -10
- package/components/pane/pane.css +5 -0
- package/components/pipeline-status/pipeline-status.css +15 -1
- package/components/popover/popover.css +17 -0
- package/components/select/select.css +18 -0
- package/components/swiper/swiper.css +9 -0
- package/components/table/table.css +5 -0
- package/components/table/table.js +45 -1
- package/components/table-toolbar/table-toolbar.css +13 -0
- package/components/tag/tag.css +10 -0
- package/components/timeline/timeline.css +10 -3
- package/components/toast/toast.css +93 -48
- package/components/toast/toast.js +101 -22
- package/components/toolbar/toolbar.css +13 -0
- package/components/tooltip/tooltip.css +8 -0
- package/package.json +1 -1
- package/styles/colors/semantics.css +1 -1
package/components/menu/menu.css
CHANGED
|
@@ -38,6 +38,24 @@ menu-ui [data-menu-popover] {
|
|
|
38
38
|
font-family: inherit;
|
|
39
39
|
font-size: var(--a-ui-size);
|
|
40
40
|
color: var(--a-fg);
|
|
41
|
+
/* Fade + lift in on first paint via @starting-style. Plain `transition`
|
|
42
|
+
applies during exit too (display: none can't transition, but opacity
|
|
43
|
+
can — and the close path is JS-controlled so no exit anim is needed). */
|
|
44
|
+
opacity: 1;
|
|
45
|
+
translate: 0 0;
|
|
46
|
+
transition: opacity var(--a-duration-fast) var(--a-easing-out),
|
|
47
|
+
translate var(--a-duration-fast) var(--a-easing-out);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
menu-ui [data-menu-popover]:popover-open {
|
|
51
|
+
@starting-style {
|
|
52
|
+
opacity: 0;
|
|
53
|
+
translate: 0 -4px;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@media (prefers-reduced-motion: reduce) {
|
|
58
|
+
menu-ui [data-menu-popover] { transition: none; }
|
|
41
59
|
}
|
|
42
60
|
|
|
43
61
|
/* Safari 17.x bug: `:scope:hover` inside `@scope` doesn't match the scope
|
package/components/menu/menu.js
CHANGED
|
@@ -251,18 +251,30 @@ class AdiaMenuItem extends AdiaElement {
|
|
|
251
251
|
this.#syncAria();
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
// Mark slot elements we create so render() never deletes consumer-provided ones.
|
|
255
|
+
// See ADR-0010 (slot content is source of truth).
|
|
256
|
+
#stampMark(el) { el.dataset.menuItemStamped = '1'; return el; }
|
|
257
|
+
#wasStamped(el) { return el?.dataset?.menuItemStamped === '1'; }
|
|
258
|
+
|
|
259
|
+
#ownChild(selector) {
|
|
260
|
+
for (const ch of this.children) {
|
|
261
|
+
if (ch.matches(selector)) return ch;
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
254
266
|
#stamp() {
|
|
255
|
-
if (this
|
|
267
|
+
if (this.#ownChild('[slot="text"]')) return;
|
|
256
268
|
|
|
257
|
-
if (this.icon) {
|
|
258
|
-
const iconEl = document.createElement('icon-ui');
|
|
269
|
+
if (this.icon && !this.#ownChild('[slot="icon"]')) {
|
|
270
|
+
const iconEl = this.#stampMark(document.createElement('icon-ui'));
|
|
259
271
|
iconEl.setAttribute('slot', 'icon');
|
|
260
272
|
iconEl.setAttribute('name', this.icon);
|
|
261
273
|
this.appendChild(iconEl);
|
|
262
274
|
}
|
|
263
275
|
|
|
264
276
|
if (this.text) {
|
|
265
|
-
const span = document.createElement('span');
|
|
277
|
+
const span = this.#stampMark(document.createElement('span'));
|
|
266
278
|
span.setAttribute('slot', 'text');
|
|
267
279
|
span.textContent = this.text;
|
|
268
280
|
this.appendChild(span);
|
|
@@ -275,22 +287,24 @@ class AdiaMenuItem extends AdiaElement {
|
|
|
275
287
|
}
|
|
276
288
|
|
|
277
289
|
render() {
|
|
278
|
-
|
|
290
|
+
// Sync icon — only touch elements we stamped.
|
|
291
|
+
const iconEl = this.#ownChild('[slot="icon"]');
|
|
279
292
|
if (this.icon) {
|
|
280
293
|
if (iconEl) {
|
|
281
|
-
iconEl.setAttribute('name', this.icon);
|
|
294
|
+
if (this.#wasStamped(iconEl)) iconEl.setAttribute('name', this.icon);
|
|
282
295
|
} else {
|
|
283
|
-
const el = document.createElement('icon-ui');
|
|
296
|
+
const el = this.#stampMark(document.createElement('icon-ui'));
|
|
284
297
|
el.setAttribute('slot', 'icon');
|
|
285
298
|
el.setAttribute('name', this.icon);
|
|
286
299
|
this.prepend(el);
|
|
287
300
|
}
|
|
288
|
-
} else if (iconEl) {
|
|
301
|
+
} else if (this.#wasStamped(iconEl)) {
|
|
289
302
|
iconEl.remove();
|
|
290
303
|
}
|
|
291
304
|
|
|
292
|
-
|
|
293
|
-
|
|
305
|
+
// Sync text — only touch elements we stamped.
|
|
306
|
+
const textEl = this.#ownChild('[slot="text"]');
|
|
307
|
+
if (this.#wasStamped(textEl)) textEl.textContent = this.text;
|
|
294
308
|
|
|
295
309
|
this.#syncAria();
|
|
296
310
|
}
|
package/components/pane/pane.css
CHANGED
|
@@ -91,6 +91,11 @@
|
|
|
91
91
|
background: var(--pane-header-bg-hover);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
> header:focus-visible {
|
|
95
|
+
outline: none;
|
|
96
|
+
box-shadow: var(--a-focus-ring) inset;
|
|
97
|
+
}
|
|
98
|
+
|
|
94
99
|
/* Collapse indicator — stamped by JS as icon-ui */
|
|
95
100
|
> header > [slot="chevron"] {
|
|
96
101
|
--a-icon-size: var(--a-caret-size);
|
|
@@ -130,7 +130,21 @@
|
|
|
130
130
|
font-size: var(--pipeline-status-history-size);
|
|
131
131
|
color: var(--pipeline-status-history-fg);
|
|
132
132
|
user-select: none;
|
|
133
|
-
padding: var(--pipeline-status-history-pad-y)
|
|
133
|
+
padding: var(--pipeline-status-history-pad-y) var(--a-space-1);
|
|
134
|
+
margin-inline: calc(var(--a-space-1) * -1);
|
|
135
|
+
border-radius: var(--a-radius-sm);
|
|
136
|
+
transition: background var(--pipeline-status-duration) var(--pipeline-status-easing),
|
|
137
|
+
color var(--pipeline-status-duration) var(--pipeline-status-easing);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
[data-pipeline-history] summary:hover {
|
|
141
|
+
background: var(--a-bg-subtle);
|
|
142
|
+
color: var(--pipeline-status-label-fg);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
[data-pipeline-history] summary:focus-visible {
|
|
146
|
+
outline: none;
|
|
147
|
+
box-shadow: var(--a-focus-ring);
|
|
134
148
|
}
|
|
135
149
|
|
|
136
150
|
[data-pipeline-history] summary::marker {
|
|
@@ -47,6 +47,23 @@
|
|
|
47
47
|
color: var(--popover-fg);
|
|
48
48
|
max-height: calc(100vh - 3rem);
|
|
49
49
|
overflow-y: auto;
|
|
50
|
+
/* Fade + lift in on first paint. @starting-style is the initial frame
|
|
51
|
+
browsers paint before the popover transitions to its open state. */
|
|
52
|
+
opacity: 1;
|
|
53
|
+
translate: 0 0;
|
|
54
|
+
transition: opacity var(--a-duration-fast) var(--a-easing-out),
|
|
55
|
+
translate var(--a-duration-fast) var(--a-easing-out);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[slot="content"]:popover-open {
|
|
59
|
+
@starting-style {
|
|
60
|
+
opacity: 0;
|
|
61
|
+
translate: 0 -4px;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@media (prefers-reduced-motion: reduce) {
|
|
66
|
+
[slot="content"] { transition: none; }
|
|
50
67
|
}
|
|
51
68
|
|
|
52
69
|
/* Collapse default margins on the first/last block child so the
|
|
@@ -199,6 +199,24 @@ select-ui [slot="listbox"] {
|
|
|
199
199
|
|
|
200
200
|
/* Positioned by JS (#positionListbox) — fixed to viewport */
|
|
201
201
|
width: max-content;
|
|
202
|
+
|
|
203
|
+
/* Fade + lift in on first paint (popover top-layer cannot inherit
|
|
204
|
+
component tokens, so reference --a-* directly). */
|
|
205
|
+
opacity: 1;
|
|
206
|
+
translate: 0 0;
|
|
207
|
+
transition: opacity var(--a-duration-fast) var(--a-easing-out),
|
|
208
|
+
translate var(--a-duration-fast) var(--a-easing-out);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
select-ui [slot="listbox"]:popover-open {
|
|
212
|
+
@starting-style {
|
|
213
|
+
opacity: 0;
|
|
214
|
+
translate: 0 -4px;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@media (prefers-reduced-motion: reduce) {
|
|
219
|
+
select-ui [slot="listbox"] { transition: none; }
|
|
202
220
|
}
|
|
203
221
|
|
|
204
222
|
select-ui [role="option"] {
|
|
@@ -188,6 +188,15 @@
|
|
|
188
188
|
transform var(--swiper-duration) var(--swiper-easing);
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
:scope > [data-swiper-dots] > button:hover {
|
|
192
|
+
background: var(--swiper-dot-bg-active);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
:scope > [data-swiper-dots] > button:focus-visible {
|
|
196
|
+
outline: none;
|
|
197
|
+
box-shadow: var(--a-focus-ring);
|
|
198
|
+
}
|
|
199
|
+
|
|
191
200
|
:scope > [data-swiper-dots] > button[aria-current="true"] {
|
|
192
201
|
background: var(--swiper-dot-bg-active);
|
|
193
202
|
}
|
|
@@ -210,6 +210,9 @@
|
|
|
210
210
|
|
|
211
211
|
[data-body] [role="gridcell"] {
|
|
212
212
|
box-sizing: border-box;
|
|
213
|
+
display: flex;
|
|
214
|
+
align-items: center;
|
|
215
|
+
align-self: stretch;
|
|
213
216
|
padding: var(--table-py) var(--table-px);
|
|
214
217
|
border-bottom: 1px solid var(--table-border);
|
|
215
218
|
min-width: 0;
|
|
@@ -218,10 +221,12 @@
|
|
|
218
221
|
|
|
219
222
|
[data-align="right"] {
|
|
220
223
|
text-align: right;
|
|
224
|
+
justify-content: flex-end;
|
|
221
225
|
}
|
|
222
226
|
|
|
223
227
|
[data-align="center"] {
|
|
224
228
|
text-align: center;
|
|
229
|
+
justify-content: center;
|
|
225
230
|
}
|
|
226
231
|
|
|
227
232
|
/* ═══════ Row states ═══════ */
|
|
@@ -129,10 +129,54 @@ class AdiaTable extends AdiaElement {
|
|
|
129
129
|
|
|
130
130
|
get data() { return this.#data; }
|
|
131
131
|
|
|
132
|
-
// ── Public API:
|
|
132
|
+
// ── Public API: selection ──
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Indices of currently-selected rows, ascending.
|
|
136
|
+
* @returns {number[]}
|
|
137
|
+
*/
|
|
134
138
|
get selected() { return [...this.#selected].sort((a, b) => a - b); }
|
|
135
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Replace the selection set programmatically. Out-of-range indices are
|
|
142
|
+
* silently dropped. Pair with `selectable` mode; on a non-selectable
|
|
143
|
+
* table the indices are stored but not rendered as checked rows.
|
|
144
|
+
* @param {Iterable<number>} indices
|
|
145
|
+
*/
|
|
146
|
+
set selected(indices) {
|
|
147
|
+
this.#selected.clear();
|
|
148
|
+
if (indices) {
|
|
149
|
+
for (const i of indices) {
|
|
150
|
+
if (Number.isInteger(i) && i >= 0 && i < this.#data.length) {
|
|
151
|
+
this.#selected.add(i);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
this.#requestRender();
|
|
156
|
+
this.dispatchEvent(new CustomEvent('select', {
|
|
157
|
+
detail: { selected: this.selected },
|
|
158
|
+
bubbles: true,
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Empty the selection set. Equivalent to `el.selected = []` but doesn't
|
|
164
|
+
* require constructing an empty array; the most common selection-write
|
|
165
|
+
* call by far (after a "delete" or "archive" bulk action), so worth
|
|
166
|
+
* having a one-token verb form.
|
|
167
|
+
*/
|
|
168
|
+
clearSelection() {
|
|
169
|
+
if (this.#selected.size === 0) return;
|
|
170
|
+
this.#selected.clear();
|
|
171
|
+
this.#requestRender();
|
|
172
|
+
this.dispatchEvent(new CustomEvent('select', {
|
|
173
|
+
detail: { selected: [] },
|
|
174
|
+
bubbles: true,
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── Public API: read-only getters ──
|
|
179
|
+
|
|
136
180
|
get sortState() { return this.#sortState.map(s => ({ ...s })); }
|
|
137
181
|
|
|
138
182
|
// ── Public API: filters ──
|
|
@@ -156,6 +156,19 @@
|
|
|
156
156
|
display: flex;
|
|
157
157
|
flex-direction: column;
|
|
158
158
|
gap: var(--a-space-1);
|
|
159
|
+
/* Fade + lift in on first paint. */
|
|
160
|
+
opacity: 1;
|
|
161
|
+
translate: 0 0;
|
|
162
|
+
transition: opacity var(--a-duration-fast) var(--a-easing-out),
|
|
163
|
+
translate var(--a-duration-fast) var(--a-easing-out);
|
|
164
|
+
@starting-style {
|
|
165
|
+
opacity: 0;
|
|
166
|
+
translate: 0 -4px;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@media (prefers-reduced-motion: reduce) {
|
|
171
|
+
[data-toolbar-popover]:popover-open { transition: none; }
|
|
159
172
|
}
|
|
160
173
|
|
|
161
174
|
/* The popover head + empty hint are <text-ui variant="kicker"|caption">,
|
package/components/tag/tag.css
CHANGED
|
@@ -79,6 +79,16 @@ tag-ui[removable]:not([disabled]):hover {
|
|
|
79
79
|
--tag-fg: var(--a-danger-bg);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/* `default` is a semantic alias of the base — same tokens as the
|
|
83
|
+
unstyled `:scope`, declared explicitly so the yaml enum and the
|
|
84
|
+
CSS contract agree. Most consumers omit `variant` and inherit the
|
|
85
|
+
base; the explicit selector lets `<tag-ui variant="default">`
|
|
86
|
+
render identically without falling through to base. */
|
|
87
|
+
:scope[variant="default"] {
|
|
88
|
+
--tag-bg: var(--a-bg-muted);
|
|
89
|
+
--tag-fg: var(--a-fg);
|
|
90
|
+
}
|
|
91
|
+
|
|
82
92
|
/* Size handled by universal [size] attribute system. */
|
|
83
93
|
|
|
84
94
|
/* hover rule moved outside @scope — see Safari 17.x bug note at top. */
|
|
@@ -350,14 +350,22 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
|
|
|
350
350
|
top: calc((1.4em - 1em) / 2);
|
|
351
351
|
background: none;
|
|
352
352
|
border: none;
|
|
353
|
-
padding: 0 var(--timeline-item-toggle-px);
|
|
353
|
+
padding: var(--a-space-0-5) var(--timeline-item-toggle-px);
|
|
354
354
|
margin: 0;
|
|
355
355
|
cursor: pointer;
|
|
356
|
-
color:
|
|
356
|
+
color: var(--timeline-item-label-fg-muted, var(--a-fg-muted));
|
|
357
|
+
border-radius: var(--a-radius-sm);
|
|
357
358
|
display: inline-flex;
|
|
358
359
|
align-items: center;
|
|
359
360
|
justify-content: center;
|
|
360
361
|
line-height: 0;
|
|
362
|
+
transition: background var(--timeline-item-duration) var(--timeline-item-easing),
|
|
363
|
+
color var(--timeline-item-duration) var(--timeline-item-easing);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
:scope > [data-timeline-toggle]:hover {
|
|
367
|
+
background: var(--a-bg-subtle);
|
|
368
|
+
color: var(--timeline-item-label-fg, var(--a-fg));
|
|
361
369
|
}
|
|
362
370
|
|
|
363
371
|
/* Reserve room so the time isn't overlapped by the chevron */
|
|
@@ -368,7 +376,6 @@ agent-reasoning-ui timeline-ui:not([orientation="horizontal"]),
|
|
|
368
376
|
:scope > [data-timeline-toggle]:focus-visible {
|
|
369
377
|
outline: none;
|
|
370
378
|
box-shadow: var(--a-focus-ring);
|
|
371
|
-
border-radius: var(--a-radius-sm);
|
|
372
379
|
}
|
|
373
380
|
}
|
|
374
381
|
|
|
@@ -106,39 +106,60 @@ toast-ui[data-closing][position="top-left"] {
|
|
|
106
106
|
/* Enter / exit animation rules ([data-open] / [data-closing]) moved
|
|
107
107
|
outside @scope — see Safari 17.x bug note at top of file. */
|
|
108
108
|
|
|
109
|
-
/* ──
|
|
109
|
+
/* ── Variants ──
|
|
110
|
+
`--variant-muted` flips light↔dark with scheme, so the fg token
|
|
111
|
+
paired with it must do the same. Use `--a-{variant}-text` (the
|
|
112
|
+
light-dark scheme-aware token), NOT `--a-{variant}-text-strong`
|
|
113
|
+
(the latter is locked dark for warning + light for the others —
|
|
114
|
+
designed for solid `--variant-strong` fills, where the bg never
|
|
115
|
+
flips). Mirrors alert.css's variant wiring. */
|
|
110
116
|
|
|
111
117
|
:where(:scope),
|
|
112
118
|
:where(:scope[variant="info"]) {
|
|
113
|
-
--toast-bg:
|
|
114
|
-
--toast-fg:
|
|
119
|
+
--toast-bg: var(--a-info-muted);
|
|
120
|
+
--toast-fg: var(--a-info-text);
|
|
115
121
|
--toast-border: var(--a-info-border-subtle);
|
|
116
122
|
}
|
|
117
|
-
|
|
118
|
-
/* ── Variant: success ── */
|
|
119
|
-
|
|
120
123
|
:where(:scope[variant="success"]) {
|
|
121
|
-
--toast-bg:
|
|
122
|
-
--toast-fg:
|
|
124
|
+
--toast-bg: var(--a-success-muted);
|
|
125
|
+
--toast-fg: var(--a-success-text);
|
|
123
126
|
--toast-border: var(--a-success-border-subtle);
|
|
124
127
|
}
|
|
125
|
-
|
|
126
|
-
/* ── Variant: warning ── */
|
|
127
|
-
|
|
128
128
|
:where(:scope[variant="warning"]) {
|
|
129
|
-
--toast-bg:
|
|
130
|
-
--toast-fg:
|
|
129
|
+
--toast-bg: var(--a-warning-muted);
|
|
130
|
+
--toast-fg: var(--a-warning-text);
|
|
131
131
|
--toast-border: var(--a-warning-border-subtle);
|
|
132
132
|
}
|
|
133
|
-
|
|
134
|
-
/* ── Variant: danger ── */
|
|
135
|
-
|
|
136
133
|
:where(:scope[variant="danger"]) {
|
|
137
|
-
--toast-bg:
|
|
138
|
-
--toast-fg:
|
|
134
|
+
--toast-bg: var(--a-danger-muted);
|
|
135
|
+
--toast-fg: var(--a-danger-text);
|
|
139
136
|
--toast-border: var(--a-danger-border-subtle);
|
|
140
137
|
}
|
|
141
138
|
|
|
139
|
+
/* `primary` is the accent-filled variant — solid bg + on-accent text
|
|
140
|
+
for "branded" toasts (welcome banners, feature-launch nudges)
|
|
141
|
+
where the message should read as a brand stamp rather than tinted
|
|
142
|
+
status chrome. Tracks the same accent-strong source as button-ui's
|
|
143
|
+
primary; border picks up `--a-accent-border-subtle` since there's
|
|
144
|
+
no `--a-primary-border-subtle` token. */
|
|
145
|
+
:where(:scope[variant="primary"]) {
|
|
146
|
+
--toast-bg: var(--a-primary-bg);
|
|
147
|
+
--toast-fg: var(--a-primary-fg);
|
|
148
|
+
--toast-border: var(--a-accent-border-subtle);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* `muted` and `neutral` are semantic aliases of the base canvas
|
|
152
|
+
surface — same tokens as the unstyled `:scope`, declared explicitly
|
|
153
|
+
so the yaml enum and the CSS contract agree. Use cases: quiet
|
|
154
|
+
status nudges that shouldn't carry tonal weight (e.g. "Draft
|
|
155
|
+
saved" without success-green). Mirrors alert-ui's pattern. */
|
|
156
|
+
:where(:scope[variant="muted"]),
|
|
157
|
+
:where(:scope[variant="neutral"]) {
|
|
158
|
+
--toast-bg: var(--a-bg-subtle);
|
|
159
|
+
--toast-fg: var(--a-fg);
|
|
160
|
+
--toast-border: var(--a-border-subtle);
|
|
161
|
+
}
|
|
162
|
+
|
|
142
163
|
/* ── Message slot ── */
|
|
143
164
|
|
|
144
165
|
[slot="message"] {
|
|
@@ -146,25 +167,17 @@ toast-ui[data-closing][position="top-left"] {
|
|
|
146
167
|
min-width: 0;
|
|
147
168
|
}
|
|
148
169
|
|
|
149
|
-
/* ── Close button ──
|
|
150
|
-
|
|
170
|
+
/* ── Close button ──
|
|
171
|
+
A real <button-ui icon="x" variant="ghost" size="sm"> stamped by
|
|
172
|
+
toast.js — brings the system focus ring + hover transition + a
|
|
173
|
+
properly-sized icon-ui glyph. The `align-self: start` keeps the
|
|
174
|
+
button on the first line of multi-line toast bodies, matching the
|
|
175
|
+
alert-ui pattern. */
|
|
151
176
|
[slot="close"] {
|
|
152
|
-
background: none;
|
|
153
|
-
border: none;
|
|
154
|
-
font-size: 0.875rem;
|
|
155
|
-
color: currentColor;
|
|
156
|
-
cursor: pointer;
|
|
157
|
-
padding: 0;
|
|
158
|
-
line-height: 1;
|
|
159
|
-
opacity: 0.6;
|
|
160
177
|
flex-shrink: 0;
|
|
161
|
-
align-self:
|
|
162
|
-
|
|
163
|
-
transition: opacity var(--toast-close-duration) var(--toast-close-easing);
|
|
178
|
+
align-self: start;
|
|
179
|
+
color: currentColor;
|
|
164
180
|
}
|
|
165
|
-
[slot="close"]::after { content: '\00d7'; }
|
|
166
|
-
[slot="close"]:hover { opacity: 1; }
|
|
167
|
-
[slot="close"]:focus-visible { box-shadow: var(--toast-focus-ring); border-radius: var(--toast-focus-radius); }
|
|
168
181
|
|
|
169
182
|
/* Inside a container: drop fixed positioning */
|
|
170
183
|
[data-toast-container] > :scope {
|
|
@@ -176,37 +189,69 @@ toast-ui[data-closing][position="top-left"] {
|
|
|
176
189
|
}
|
|
177
190
|
}
|
|
178
191
|
|
|
179
|
-
/* ──
|
|
180
|
-
|
|
192
|
+
/* ── Toast lane container ──
|
|
193
|
+
Per-position singleton, attached to `document.body`. Promoted to the
|
|
194
|
+
browser's top-layer via the Popover API — `[popover="manual"]` on the
|
|
195
|
+
element + `showPopover()` on first post. The native popover stack
|
|
196
|
+
means multiple lanes (e.g. top-right + bottom-center) coexist
|
|
197
|
+
without z-index collisions, and the lane sits above ALL page chrome
|
|
198
|
+
(modals included, since both ride the top-layer in document order).
|
|
199
|
+
|
|
200
|
+
Reset the UA `[popover]` defaults (centred, white panel, border).
|
|
201
|
+
The lane is a transparent flex column anchored to a viewport corner;
|
|
202
|
+
the toast cards inside paint themselves. `pointer-events: none` on
|
|
203
|
+
the lane + `auto` on each toast lets clicks pass through empty
|
|
204
|
+
space between cards. */
|
|
181
205
|
[data-toast-container] {
|
|
182
206
|
position: fixed;
|
|
183
|
-
|
|
207
|
+
inset: unset;
|
|
208
|
+
margin: 0;
|
|
209
|
+
padding: 0;
|
|
210
|
+
border: none;
|
|
211
|
+
background: transparent;
|
|
212
|
+
overflow: visible;
|
|
213
|
+
width: max-content;
|
|
214
|
+
max-width: 100vw;
|
|
215
|
+
z-index: 9999; /* fallback for envs without Popover API */
|
|
184
216
|
display: flex;
|
|
185
|
-
flex-direction: column;
|
|
186
217
|
gap: var(--a-space-2);
|
|
187
218
|
pointer-events: none;
|
|
188
219
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
align-items: flex-end;
|
|
220
|
+
[data-toast-container]:popover-open {
|
|
221
|
+
/* Native top-layer; component-level z-index above is moot here but kept
|
|
222
|
+
for fallback. */
|
|
223
|
+
display: flex;
|
|
194
224
|
}
|
|
195
225
|
|
|
226
|
+
/* Top lanes — newest at top, columns flow downward. */
|
|
227
|
+
[data-toast-container="top-right"],
|
|
228
|
+
[data-toast-container="top-center"],
|
|
229
|
+
[data-toast-container="top-left"] {
|
|
230
|
+
top: var(--a-space-4);
|
|
231
|
+
flex-direction: column;
|
|
232
|
+
}
|
|
233
|
+
/* Bottom lanes — newest at bottom, columns reverse so post() lands at
|
|
234
|
+
the visually-newest position. */
|
|
235
|
+
[data-toast-container="bottom-right"],
|
|
236
|
+
[data-toast-container="bottom-center"],
|
|
196
237
|
[data-toast-container="bottom-left"] {
|
|
197
238
|
bottom: var(--a-space-4);
|
|
198
|
-
|
|
199
|
-
align-items: flex-start;
|
|
239
|
+
flex-direction: column-reverse;
|
|
200
240
|
}
|
|
201
241
|
|
|
242
|
+
[data-toast-container="bottom-right"],
|
|
202
243
|
[data-toast-container="top-right"] {
|
|
203
|
-
top: var(--a-space-4);
|
|
204
244
|
right: var(--a-space-4);
|
|
205
245
|
align-items: flex-end;
|
|
206
246
|
}
|
|
207
|
-
|
|
247
|
+
[data-toast-container="bottom-left"],
|
|
208
248
|
[data-toast-container="top-left"] {
|
|
209
|
-
top: var(--a-space-4);
|
|
210
249
|
left: var(--a-space-4);
|
|
211
250
|
align-items: flex-start;
|
|
212
251
|
}
|
|
252
|
+
[data-toast-container="top-center"],
|
|
253
|
+
[data-toast-container="bottom-center"] {
|
|
254
|
+
left: 50%;
|
|
255
|
+
transform: translateX(-50%);
|
|
256
|
+
align-items: center;
|
|
257
|
+
}
|