@adia-ai/web-components 0.0.21 → 0.0.23
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/README.md +1 -1
- package/components/action-list/action-list.css +13 -4
- package/components/agent-reasoning/agent-reasoning.js +6 -3
- package/components/alert/alert.css +19 -15
- package/components/alert/alert.js +8 -13
- package/components/avatar/avatar.css +8 -9
- package/components/button/button.css +27 -24
- package/components/card/card.css +1 -0
- package/components/check/check.css +15 -10
- package/components/col/col.css +3 -0
- package/components/description-list/description-list.css +9 -9
- package/components/grid/grid.css +6 -1
- package/components/input/input.css +15 -4
- package/components/list/list.css +8 -0
- package/components/menu/menu.css +22 -11
- package/components/modal/modal.js +40 -4
- package/components/option-card/option-card.css +9 -5
- package/components/progress/progress.css +8 -0
- package/components/progress-row/progress-row.js +9 -0
- package/components/radio/radio.css +13 -9
- package/components/rating/rating.css +7 -4
- package/components/richtext/richtext.css +138 -0
- package/components/row/row.css +7 -1
- package/components/segment/segment.css +8 -5
- package/components/select/select.css +4 -1
- package/components/stack/stack.css +3 -0
- package/components/stepper/stepper.css +12 -4
- package/components/stepper/stepper.js +7 -7
- package/components/swiper/swiper.css +10 -0
- package/components/swiper/swiper.js +77 -0
- package/components/switch/switch.css +15 -9
- package/components/tag/tag.css +7 -4
- package/components/toggle-group/toggle-group.css +9 -4
- package/package.json +1 -1
- package/patterns/app-nav/app-nav.js +13 -0
- package/patterns/app-nav-item/app-nav-item.css +15 -9
- package/patterns/section-nav-item/section-nav-item.css +13 -2
- package/styles/colors/semantics.css +5 -5
- package/styles/prose.css +5 -5
- package/styles/tokens.css +57 -0
package/README.md
CHANGED
|
@@ -199,7 +199,7 @@ the `streams` registry export from `core/data-stream.js`.
|
|
|
199
199
|
|
|
200
200
|
Implementation: `core/data-stream.js` (~360 lines). Full
|
|
201
201
|
attribute table + live demos:
|
|
202
|
-
[`/site/components/chart#data-stream`](
|
|
202
|
+
[`/site/components/chart#data-stream`](../../site/pages/components/chart/index.html).
|
|
203
203
|
|
|
204
204
|
## Build
|
|
205
205
|
|
|
@@ -14,6 +14,19 @@
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/* Safari 17.x bug: `:scope:hover` inside `@scope` doesn't match the scope
|
|
18
|
+
root. Plain selector outside the @scope works. `:focus-visible` matches
|
|
19
|
+
correctly inside @scope, so the combined `:hover, :focus-visible` rules
|
|
20
|
+
are split — `:hover` moves out, `:focus-visible` stays. See
|
|
21
|
+
docs/BROWSER-COMPAT.md §3a. */
|
|
22
|
+
action-item-ui:hover {
|
|
23
|
+
background: var(--action-item-bg-hover);
|
|
24
|
+
color: var(--action-item-fg-hover);
|
|
25
|
+
}
|
|
26
|
+
action-item-ui:hover [slot="icon"] {
|
|
27
|
+
color: var(--action-item-icon-fg-hover);
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
@scope (action-item-ui) {
|
|
18
31
|
:where(:scope) {
|
|
19
32
|
/* Reuse menu-item visual language for consistency */
|
|
@@ -59,12 +72,9 @@
|
|
|
59
72
|
color var(--action-item-duration) var(--action-item-easing);
|
|
60
73
|
}
|
|
61
74
|
|
|
62
|
-
:scope:hover,
|
|
63
75
|
:scope:focus-visible {
|
|
64
76
|
background: var(--action-item-bg-hover);
|
|
65
77
|
color: var(--action-item-fg-hover);
|
|
66
|
-
}
|
|
67
|
-
:scope:focus-visible {
|
|
68
78
|
box-shadow: var(--action-item-focus-ring);
|
|
69
79
|
}
|
|
70
80
|
|
|
@@ -75,7 +85,6 @@
|
|
|
75
85
|
color: var(--action-item-icon-fg);
|
|
76
86
|
transition: color var(--action-item-duration) var(--action-item-easing);
|
|
77
87
|
}
|
|
78
|
-
:scope:hover [slot="icon"],
|
|
79
88
|
:scope:focus-visible [slot="icon"] {
|
|
80
89
|
color: var(--action-item-icon-fg-hover);
|
|
81
90
|
}
|
|
@@ -371,9 +371,12 @@ class AdiaAgentReasoning extends AdiaElement {
|
|
|
371
371
|
#makeStepItem(step) {
|
|
372
372
|
const item = document.createElement('timeline-item-ui');
|
|
373
373
|
item.setAttribute('text', step.label || '');
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
374
|
+
// Map step.status → canonical timeline-item-ui [status] enum.
|
|
375
|
+
// The legacy [completed]/[active]/[error] Booleans were removed
|
|
376
|
+
// in the Phase 6 cut (2026-04-27); only [status] is honoured.
|
|
377
|
+
if (step.status === 'done') item.setAttribute('status', 'completed');
|
|
378
|
+
if (step.status === 'error') item.setAttribute('status', 'error');
|
|
379
|
+
if (step.status === 'active') { item.setAttribute('status', 'active'); item.setAttribute('spinner', ''); }
|
|
377
380
|
|
|
378
381
|
const duration = step.durationLabel
|
|
379
382
|
|| (step.duration != null ? formatDuration(step.duration) : '');
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
--alert-fg: var(--a-fg);
|
|
6
6
|
--alert-border: var(--a-border-subtle);
|
|
7
7
|
--alert-icon-fg: var(--a-fg-muted);
|
|
8
|
-
--alert-close-fg: var(--a-fg-muted);
|
|
9
|
-
--alert-close-fg-hover: var(--a-fg);
|
|
10
8
|
|
|
11
9
|
/* ── Layout ── */
|
|
12
10
|
--alert-radius: var(--a-radius-md);
|
|
@@ -15,19 +13,25 @@
|
|
|
15
13
|
--alert-gap: var(--a-space-2);
|
|
16
14
|
|
|
17
15
|
/* ── Typography ── */
|
|
18
|
-
--alert-font:
|
|
16
|
+
--alert-font: var(--a-ui-size);
|
|
17
|
+
--alert-line-height: var(--a-ui-line-height, 1.5);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
:scope {
|
|
22
21
|
/* ── Base ── */
|
|
23
22
|
box-sizing: border-box;
|
|
24
23
|
display: flex;
|
|
25
|
-
align-items:
|
|
24
|
+
/* `align-items: start` so the leading icon and close button anchor
|
|
25
|
+
to the top — keeps the icon visually paired with the first line of
|
|
26
|
+
text on multi-line alerts. The leading slot's own height = body
|
|
27
|
+
line-height (below) means the icon optically centers on line 1. */
|
|
28
|
+
align-items: start;
|
|
26
29
|
gap: var(--alert-gap);
|
|
27
30
|
padding: var(--alert-py) var(--alert-px);
|
|
28
31
|
border: 1px solid var(--alert-border);
|
|
29
32
|
border-radius: var(--alert-radius);
|
|
30
33
|
font-size: var(--alert-font);
|
|
34
|
+
line-height: var(--alert-line-height);
|
|
31
35
|
color: var(--alert-fg);
|
|
32
36
|
background: var(--alert-bg);
|
|
33
37
|
}
|
|
@@ -65,6 +69,11 @@
|
|
|
65
69
|
:scope [slot="leading"] {
|
|
66
70
|
flex-shrink: 0;
|
|
67
71
|
color: var(--alert-icon-fg);
|
|
72
|
+
/* Box height = one line of body so the icon optical-centers on the
|
|
73
|
+
first line under `align-items: start`. */
|
|
74
|
+
display: inline-flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
min-height: calc(var(--alert-font) * var(--alert-line-height));
|
|
68
77
|
/* `ensure()` appends the leading-slot icon to the host, which
|
|
69
78
|
puts it after any consumer-provided content in DOM order.
|
|
70
79
|
Force it to the visual lead via flex `order` so the icon
|
|
@@ -77,17 +86,12 @@
|
|
|
77
86
|
min-width: 0;
|
|
78
87
|
}
|
|
79
88
|
|
|
89
|
+
/* Close button is a `<button-ui icon="x" variant="ghost" size="sm">`
|
|
90
|
+
stamped by alert.js — it brings its own focus ring, hover state,
|
|
91
|
+
and transitions. Box height matches the leading slot so X and icon
|
|
92
|
+
sit on the same first-line baseline. */
|
|
80
93
|
:scope [slot="close"] {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
cursor: pointer;
|
|
84
|
-
color: var(--alert-close-fg);
|
|
85
|
-
padding: 0;
|
|
86
|
-
line-height: 1;
|
|
87
|
-
font-size: 1rem;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
:scope [slot="close"]:hover {
|
|
91
|
-
color: var(--alert-close-fg-hover);
|
|
94
|
+
flex-shrink: 0;
|
|
95
|
+
min-height: calc(var(--alert-font) * var(--alert-line-height));
|
|
92
96
|
}
|
|
93
97
|
}
|
|
@@ -24,22 +24,19 @@ class AdiaAlert extends AdiaElement {
|
|
|
24
24
|
static parts = {
|
|
25
25
|
leading: '<icon-ui slot="leading"></icon-ui>',
|
|
26
26
|
content: '<span slot="content"></span>',
|
|
27
|
-
|
|
27
|
+
/* Close affordance is a real button-ui \u2014 inherits the system focus
|
|
28
|
+
ring, hover transition, and icon sizing automatically. Listen for
|
|
29
|
+
the canonical `press` event (button-ui dispatches on click + Enter
|
|
30
|
+
+ Space, no extra keydown wiring needed). */
|
|
31
|
+
close: '<button-ui slot="close" icon="x" variant="ghost" size="sm" aria-label="Close"></button-ui>',
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
static template = () => null;
|
|
31
35
|
|
|
32
|
-
#
|
|
36
|
+
#onPress = (e) => {
|
|
33
37
|
if (e.target.closest('[slot="close"]')) this.#close();
|
|
34
38
|
};
|
|
35
39
|
|
|
36
|
-
#onKeydown = (e) => {
|
|
37
|
-
if (e.target.closest('[slot="close"]') && (e.key === 'Enter' || e.key === ' ')) {
|
|
38
|
-
e.preventDefault();
|
|
39
|
-
this.#close();
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
40
|
connected() {
|
|
44
41
|
this.#updateRole();
|
|
45
42
|
|
|
@@ -48,13 +45,11 @@ class AdiaAlert extends AdiaElement {
|
|
|
48
45
|
this.ensure('content');
|
|
49
46
|
if (this.closable) this.ensure('close');
|
|
50
47
|
|
|
51
|
-
this.addEventListener('
|
|
52
|
-
this.addEventListener('keydown', this.#onKeydown);
|
|
48
|
+
this.addEventListener('press', this.#onPress);
|
|
53
49
|
}
|
|
54
50
|
|
|
55
51
|
disconnected() {
|
|
56
|
-
this.removeEventListener('
|
|
57
|
-
this.removeEventListener('keydown', this.#onKeydown);
|
|
52
|
+
this.removeEventListener('press', this.#onPress);
|
|
58
53
|
}
|
|
59
54
|
|
|
60
55
|
render() {
|
|
@@ -74,6 +74,14 @@
|
|
|
74
74
|
AVATAR-GROUP-N — Overlapping avatar stack with +N overflow
|
|
75
75
|
═══════════════════════════════════════════════════════════════ */
|
|
76
76
|
|
|
77
|
+
/* Safari 17.x bug: `:scope:hover` inside `@scope` doesn't match the scope
|
|
78
|
+
root. Plain selector outside the @scope works. The two `:scope:hover`
|
|
79
|
+
rules combine into one rule list outside. See docs/BROWSER-COMPAT.md §3a. */
|
|
80
|
+
avatar-group-ui:hover > avatar-ui:not(:first-child),
|
|
81
|
+
avatar-group-ui:hover > [slot="overflow"] {
|
|
82
|
+
margin-inline-start: var(--avatar-group-spread);
|
|
83
|
+
}
|
|
84
|
+
|
|
77
85
|
@scope (avatar-group-ui) {
|
|
78
86
|
:where(:scope) {
|
|
79
87
|
/* ── Layout ── */
|
|
@@ -123,11 +131,6 @@
|
|
|
123
131
|
z-index: 99;
|
|
124
132
|
}
|
|
125
133
|
|
|
126
|
-
/* Group hover: spread apart */
|
|
127
|
-
:scope:hover > avatar-ui:not(:first-child) {
|
|
128
|
-
margin-inline-start: var(--avatar-group-spread);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
134
|
/* Overflow counter */
|
|
132
135
|
[slot="overflow"] {
|
|
133
136
|
display: inline-flex;
|
|
@@ -147,10 +150,6 @@
|
|
|
147
150
|
transition: margin var(--avatar-group-duration) var(--avatar-group-easing);
|
|
148
151
|
}
|
|
149
152
|
|
|
150
|
-
:scope:hover > [slot="overflow"] {
|
|
151
|
-
margin-inline-start: var(--avatar-group-spread);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
153
|
/* Size variants — adjust counter + overlap */
|
|
155
154
|
:scope[size="xs"] { --avatar-group-counter-size: 1.25rem; --avatar-group-overlap: -0.3rem; }
|
|
156
155
|
:scope[size="sm"] { --avatar-group-counter-size: 1.75rem; --avatar-group-overlap: -0.4rem; }
|
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
/* Safari 17.x bug: `:scope[attr]:hover` inside `@scope` doesn't match the
|
|
2
|
+
scope root. Plain selectors outside the @scope work — custom-property
|
|
3
|
+
tokens still resolve via inheritance. Specificity (0,1,1 / 0,2,1) is
|
|
4
|
+
preserved. See docs/BROWSER-COMPAT.md §3a. */
|
|
5
|
+
button-ui:not([disabled]):hover,
|
|
6
|
+
button-ui[variant="primary"]:not([disabled]):hover {
|
|
7
|
+
--button-bg: var(--button-bg-hover);
|
|
8
|
+
--button-fg: var(--button-fg-hover);
|
|
9
|
+
--button-border: var(--button-border-hover);
|
|
10
|
+
}
|
|
11
|
+
button-ui[variant="ghost"]:not([disabled]):hover {
|
|
12
|
+
--button-bg: var(--button-bg-ghost-hover);
|
|
13
|
+
--button-fg: var(--button-fg-ghost-hover);
|
|
14
|
+
--button-border: var(--button-border-ghost-hover);
|
|
15
|
+
}
|
|
16
|
+
button-ui[variant="outline"]:not([disabled]):hover {
|
|
17
|
+
--button-fg: var(--button-fg-hover);
|
|
18
|
+
--button-border: var(--button-border-hover);
|
|
19
|
+
}
|
|
20
|
+
button-ui[color="danger"]:not([disabled]):hover {
|
|
21
|
+
--button-bg: var(--button-bg-hover);
|
|
22
|
+
--button-fg: var(--button-fg-hover);
|
|
23
|
+
--button-border: var(--button-border-hover);
|
|
24
|
+
}
|
|
25
|
+
|
|
1
26
|
@scope (button-ui) {
|
|
2
27
|
:where(:scope) {
|
|
3
28
|
--button-bg: var(--a-ui-bg);
|
|
@@ -136,30 +161,8 @@
|
|
|
136
161
|
--button-fg: var(--a-warning-fg);
|
|
137
162
|
}
|
|
138
163
|
|
|
139
|
-
/*
|
|
140
|
-
|
|
141
|
-
:scope[variant="primary"]:not([disabled]):hover {
|
|
142
|
-
--button-bg: var(--button-bg-hover);
|
|
143
|
-
--button-fg: var(--button-fg-hover);
|
|
144
|
-
--button-border: var(--button-border-hover);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
:scope[variant="ghost"]:not([disabled]):hover {
|
|
148
|
-
--button-bg: var(--button-bg-ghost-hover);
|
|
149
|
-
--button-fg: var(--button-fg-ghost-hover);
|
|
150
|
-
--button-border: var(--button-border-ghost-hover);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
:scope[variant="outline"]:not([disabled]):hover {
|
|
154
|
-
--button-fg: var(--button-fg-hover);
|
|
155
|
-
--button-border: var(--button-border-hover);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
:scope[color="danger"]:not([disabled]):hover {
|
|
159
|
-
--button-bg: var(--button-bg-hover);
|
|
160
|
-
--button-fg: var(--button-fg-hover);
|
|
161
|
-
--button-border: var(--button-border-hover);
|
|
162
|
-
}
|
|
164
|
+
/* Hover rules moved outside @scope — see Safari 17.x bug note at
|
|
165
|
+
top of file. */
|
|
163
166
|
|
|
164
167
|
/* Size is handled by the universal [size] attribute system
|
|
165
168
|
which sets --a-size, --a-ui-px, --a-ui-size.
|
package/components/card/card.css
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/* Safari 17.x bug: `:scope*:hover` inside `@scope` doesn't match the
|
|
2
|
+
scope root. The `:scope:hover [slot="box"]` shape — `:hover` on the
|
|
3
|
+
scope root, descendant selector — is also affected; the entire selector
|
|
4
|
+
moves out together. See docs/BROWSER-COMPAT.md §3a. */
|
|
5
|
+
check-ui:not([disabled]):hover [slot="box"] {
|
|
6
|
+
border-color: var(--check-border-hover);
|
|
7
|
+
background: var(--check-bg-hover);
|
|
8
|
+
}
|
|
9
|
+
check-ui[checked]:not([disabled]):hover [slot="box"],
|
|
10
|
+
check-ui[indeterminate]:not([disabled]):hover [slot="box"] {
|
|
11
|
+
background: var(--check-bg-checked-hover);
|
|
12
|
+
border-color: var(--check-bg-checked-hover);
|
|
13
|
+
}
|
|
14
|
+
|
|
1
15
|
@scope (check-ui) {
|
|
2
16
|
:where(:scope) {
|
|
3
17
|
/* ── Tokens ── (size scales with universal [size] attribute via --a-toggle-size) */
|
|
@@ -83,10 +97,7 @@
|
|
|
83
97
|
background: var(--_dash-bg);
|
|
84
98
|
}
|
|
85
99
|
|
|
86
|
-
|
|
87
|
-
border-color: var(--check-border-hover);
|
|
88
|
-
background: var(--check-bg-hover);
|
|
89
|
-
}
|
|
100
|
+
/* hover rules moved outside @scope — see Safari 17.x bug note at top. */
|
|
90
101
|
|
|
91
102
|
/* Checked — CSS border checkmark */
|
|
92
103
|
:scope[checked] [slot="box"],
|
|
@@ -110,12 +121,6 @@
|
|
|
110
121
|
--_icon-h: calc(var(--check-size) * 0.12);
|
|
111
122
|
}
|
|
112
123
|
|
|
113
|
-
:scope[checked]:not([disabled]):hover [slot="box"],
|
|
114
|
-
:scope[indeterminate]:not([disabled]):hover [slot="box"] {
|
|
115
|
-
background: var(--check-bg-checked-hover);
|
|
116
|
-
border-color: var(--check-bg-checked-hover);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
124
|
/* Label */
|
|
120
125
|
:scope[label]::after { content: attr(label); }
|
|
121
126
|
|
package/components/col/col.css
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
gap: var(--col-gap);
|
|
13
13
|
justify-content: var(--col-justify);
|
|
14
14
|
align-items: var(--col-align);
|
|
15
|
+
/* Universal [padding] / [margin] opt-in — see tokens.css for scale. */
|
|
16
|
+
padding: var(--a-padding, 0);
|
|
17
|
+
margin: var(--a-margin, 0);
|
|
15
18
|
/* Neutralize legacy UA rule that maps HTML `align=` attr to `text-align`.
|
|
16
19
|
Our [align="center"] sets flex cross-axis alignment, not text alignment. */
|
|
17
20
|
text-align: inherit;
|
|
@@ -17,19 +17,15 @@
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
:scope {
|
|
20
|
-
/* ── Base ── */
|
|
20
|
+
/* ── Base ── stacked layout (term above desc, single column). */
|
|
21
21
|
box-sizing: border-box;
|
|
22
22
|
display: grid;
|
|
23
|
+
grid-template-columns: 1fr;
|
|
23
24
|
gap: var(--description-list-gap-row) var(--description-list-gap-column);
|
|
24
25
|
margin: 0;
|
|
25
26
|
padding: 0;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
/* Default stacked: term above desc. Each pair in its own implicit row. */
|
|
29
|
-
:scope {
|
|
30
|
-
grid-template-columns: 1fr;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
29
|
[data-dl-term],
|
|
34
30
|
dt {
|
|
35
31
|
margin: 0;
|
|
@@ -48,9 +44,13 @@
|
|
|
48
44
|
line-height: 1.4;
|
|
49
45
|
}
|
|
50
46
|
|
|
51
|
-
/*
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
/* Pair separator: extra margin under each non-last dd so DD→DT (between
|
|
48
|
+
pairs) reads as a wider gap than DT→DD (within a pair). Match anything
|
|
49
|
+
that isn't `[layout="inline"]` so the default case (no attribute set —
|
|
50
|
+
`layout` defaults to "stacked" but only reflects when explicitly set)
|
|
51
|
+
and the explicit `[layout="stacked"]` both get the same rhythm. */
|
|
52
|
+
:scope:not([layout="inline"]) [data-dl-desc]:not(:last-child),
|
|
53
|
+
:scope:not([layout="inline"]) dd:not(:last-child) {
|
|
54
54
|
margin-bottom: var(--description-list-gap-row);
|
|
55
55
|
}
|
|
56
56
|
|
package/components/grid/grid.css
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
@scope (grid-ui) {
|
|
2
2
|
:where(:scope) {
|
|
3
|
-
|
|
3
|
+
/* Read `--a-gap` so the universal `[gap="N"]` rules (tokens.css)
|
|
4
|
+
reach the grid; defaults to `--a-gap-md` at :root. */
|
|
5
|
+
--grid-gap: var(--a-gap);
|
|
4
6
|
--grid-column-gap: var(--grid-gap);
|
|
5
7
|
--grid-row-gap: var(--grid-gap);
|
|
6
8
|
}
|
|
@@ -13,6 +15,9 @@
|
|
|
13
15
|
grid-auto-columns: 1fr;
|
|
14
16
|
column-gap: var(--grid-column-gap);
|
|
15
17
|
row-gap: var(--grid-row-gap);
|
|
18
|
+
/* Universal [padding] / [margin] opt-in — see tokens.css for scale. */
|
|
19
|
+
padding: var(--a-padding, 0);
|
|
20
|
+
margin: var(--a-margin, 0);
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
/* Explicit column count — switches to template mode */
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/* Safari 17.x bug: `:scope[attr]:hover` inside `@scope` doesn't match the
|
|
2
|
+
scope root. Plain selector outside works. See docs/BROWSER-COMPAT.md §3a. */
|
|
3
|
+
input-ui[variant="ghost"]:hover {
|
|
4
|
+
--input-bg: var(--a-bg-muted);
|
|
5
|
+
}
|
|
6
|
+
|
|
1
7
|
@scope (input-ui) {
|
|
2
8
|
:where(:scope) {
|
|
3
9
|
/* ── Tokens (wired to --a-ui-*) ── */
|
|
@@ -69,7 +75,13 @@
|
|
|
69
75
|
baseline centered regardless of line-height. */
|
|
70
76
|
line-height: 1.4;
|
|
71
77
|
cursor: text;
|
|
72
|
-
|
|
78
|
+
/* Cover every property the hover / focus / invalid states change so
|
|
79
|
+
the field doesn't half-snap (border slides, but bg/colour/ring snap). */
|
|
80
|
+
transition:
|
|
81
|
+
background var(--input-duration) var(--input-easing),
|
|
82
|
+
border-color var(--input-duration) var(--input-easing),
|
|
83
|
+
color var(--input-duration) var(--input-easing),
|
|
84
|
+
box-shadow var(--input-duration) var(--input-easing);
|
|
73
85
|
}
|
|
74
86
|
:scope:not([disabled]) [slot="field"]:hover {
|
|
75
87
|
background: var(--input-bg-hover);
|
|
@@ -170,7 +182,6 @@
|
|
|
170
182
|
--input-border: transparent;
|
|
171
183
|
--input-border-hover: transparent;
|
|
172
184
|
}
|
|
173
|
-
:scope[variant="ghost"]:hover
|
|
174
|
-
|
|
175
|
-
}
|
|
185
|
+
/* :scope[variant="ghost"]:hover moved outside @scope — see Safari
|
|
186
|
+
17.x bug note at top of file. */
|
|
176
187
|
}
|
package/components/list/list.css
CHANGED
|
@@ -57,6 +57,14 @@
|
|
|
57
57
|
border-inline-start: 2px solid transparent;
|
|
58
58
|
padding-inline-start: var(--a-space-2);
|
|
59
59
|
outline: none;
|
|
60
|
+
transition:
|
|
61
|
+
background var(--a-duration-fast) var(--a-easing),
|
|
62
|
+
color var(--a-duration-fast) var(--a-easing),
|
|
63
|
+
border-color var(--a-duration-fast) var(--a-easing);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:scope[selectable] > [role="listitem"]:hover {
|
|
67
|
+
background: var(--a-bg-hover);
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
:scope[selectable] > [role="listitem"][aria-selected="true"] {
|
package/components/menu/menu.css
CHANGED
|
@@ -40,6 +40,28 @@ menu-ui [data-menu-popover] {
|
|
|
40
40
|
color: var(--a-fg);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/* Safari 17.x bug: `:scope:hover` inside `@scope` doesn't match the scope
|
|
44
|
+
root. Plain selectors outside the @scope work. `:focus-visible` matches
|
|
45
|
+
correctly inside @scope, so the combined `:hover, :focus-visible` rule
|
|
46
|
+
is split — `:hover` moves out, `:focus-visible` stays. The
|
|
47
|
+
`:scope[variant="danger"]:hover` rules also move (same bug shape). See
|
|
48
|
+
docs/BROWSER-COMPAT.md §3a. */
|
|
49
|
+
menu-item-ui:hover {
|
|
50
|
+
--menu-item-bg: var(--menu-item-bg-hover);
|
|
51
|
+
--menu-item-fg: var(--menu-item-fg-hover);
|
|
52
|
+
outline: none;
|
|
53
|
+
}
|
|
54
|
+
menu-item-ui:hover [slot="icon"] {
|
|
55
|
+
color: var(--menu-item-icon-fg-hover);
|
|
56
|
+
}
|
|
57
|
+
menu-item-ui[variant="danger"]:hover {
|
|
58
|
+
--menu-item-bg: var(--menu-item-danger-bg);
|
|
59
|
+
--menu-item-fg: var(--menu-item-danger-fg);
|
|
60
|
+
}
|
|
61
|
+
menu-item-ui[variant="danger"]:hover [slot="icon"] {
|
|
62
|
+
color: var(--menu-item-danger-fg);
|
|
63
|
+
}
|
|
64
|
+
|
|
43
65
|
@scope (menu-item-ui) {
|
|
44
66
|
:where(:scope) {
|
|
45
67
|
/* ── Layout ── */
|
|
@@ -84,7 +106,6 @@ menu-ui [data-menu-popover] {
|
|
|
84
106
|
color var(--menu-item-duration) var(--menu-item-easing);
|
|
85
107
|
}
|
|
86
108
|
|
|
87
|
-
:scope:hover,
|
|
88
109
|
:scope:focus-visible {
|
|
89
110
|
--menu-item-bg: var(--menu-item-bg-hover);
|
|
90
111
|
--menu-item-fg: var(--menu-item-fg-hover);
|
|
@@ -98,9 +119,6 @@ menu-ui [data-menu-popover] {
|
|
|
98
119
|
color: var(--menu-item-icon-fg);
|
|
99
120
|
transition: color var(--menu-item-duration) var(--menu-item-easing);
|
|
100
121
|
}
|
|
101
|
-
:scope:hover [slot="icon"] {
|
|
102
|
-
color: var(--menu-item-icon-fg-hover);
|
|
103
|
-
}
|
|
104
122
|
|
|
105
123
|
/* Text */
|
|
106
124
|
[slot="text"] {
|
|
@@ -112,16 +130,9 @@ menu-ui [data-menu-popover] {
|
|
|
112
130
|
:scope[variant="danger"] {
|
|
113
131
|
--menu-item-fg: var(--a-danger-bg);
|
|
114
132
|
}
|
|
115
|
-
:scope[variant="danger"]:hover {
|
|
116
|
-
--menu-item-bg: var(--menu-item-danger-bg);
|
|
117
|
-
--menu-item-fg: var(--menu-item-danger-fg);
|
|
118
|
-
}
|
|
119
133
|
:scope[variant="danger"] [slot="icon"] {
|
|
120
134
|
color: var(--menu-item-danger-fg);
|
|
121
135
|
}
|
|
122
|
-
:scope[variant="danger"]:hover [slot="icon"] {
|
|
123
|
-
color: var(--menu-item-danger-fg);
|
|
124
|
-
}
|
|
125
136
|
|
|
126
137
|
/* ── Disabled ── */
|
|
127
138
|
:scope[disabled] {
|
|
@@ -143,11 +143,47 @@ class AdiaModal extends AdiaElement {
|
|
|
143
143
|
this.drop('close');
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
// Body — accept bare `<section>` tags, explicit `[slot="body"]`, OR
|
|
147
|
+
// unslotted light-DOM children (so `<modal-ui><p>…</p></modal-ui>` works
|
|
148
|
+
// with no markup ceremony). Mirrors drawer-ui's authoring contract.
|
|
149
|
+
const authorBody = [...this.children].find(c =>
|
|
150
|
+
c.getAttribute('slot') === 'body' || (!c.getAttribute('slot') && c.localName === 'section')
|
|
151
|
+
);
|
|
152
|
+
const looseChildren = [...this.children].filter(c =>
|
|
153
|
+
!c.getAttribute('slot') && c.localName !== 'section' && c.localName !== 'dialog' && c.localName !== 'footer'
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
let body;
|
|
157
|
+
if (authorBody) {
|
|
158
|
+
if (authorBody.getAttribute('slot') !== 'body') authorBody.setAttribute('slot', 'body');
|
|
159
|
+
if (authorBody.parentElement !== panel) panel.appendChild(authorBody);
|
|
160
|
+
panel.querySelector(':scope > [slot="body"][data-stamped]')?.remove();
|
|
161
|
+
body = authorBody;
|
|
162
|
+
} else {
|
|
163
|
+
body = this.ensure('body');
|
|
164
|
+
body.setAttribute('data-stamped', '');
|
|
165
|
+
if (body.parentElement !== panel) panel.appendChild(body);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Migrate any remaining unslotted light-DOM children into the body so
|
|
169
|
+
// `<modal-ui><p>…</p></modal-ui>` lands in the visible region.
|
|
170
|
+
for (const child of looseChildren) {
|
|
171
|
+
if (child !== body) body.appendChild(child);
|
|
172
|
+
}
|
|
148
173
|
|
|
149
|
-
|
|
150
|
-
|
|
174
|
+
// Footer — opt-in via [slot="footer"] or bare <footer> tag (card-ui style).
|
|
175
|
+
const userFooter = [...this.children].find(c =>
|
|
176
|
+
c.getAttribute('slot') === 'footer' || (!c.getAttribute('slot') && c.localName === 'footer')
|
|
177
|
+
);
|
|
178
|
+
if (userFooter) {
|
|
179
|
+
if (userFooter.getAttribute('slot') !== 'footer') userFooter.setAttribute('slot', 'footer');
|
|
180
|
+
if (userFooter.parentElement !== panel) panel.appendChild(userFooter);
|
|
181
|
+
panel.querySelector(':scope > [slot="footer"][data-stamped]')?.remove();
|
|
182
|
+
} else {
|
|
183
|
+
const footer = this.ensure('footer');
|
|
184
|
+
footer.setAttribute('data-stamped', '');
|
|
185
|
+
if (footer.parentElement !== panel) panel.appendChild(footer);
|
|
186
|
+
}
|
|
151
187
|
|
|
152
188
|
// Sync open state
|
|
153
189
|
if (this.open && !dialog.open) {
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/* Safari 17.x bug: `:scope:not(...):hover` inside `@scope` doesn't match
|
|
2
|
+
the scope root. Plain selector outside works. See
|
|
3
|
+
docs/BROWSER-COMPAT.md §3a. */
|
|
4
|
+
option-card-ui:not([checked]):not([disabled]):hover {
|
|
5
|
+
background: var(--option-card-bg-hover);
|
|
6
|
+
border-color: var(--option-card-border-hover);
|
|
7
|
+
}
|
|
8
|
+
|
|
1
9
|
@scope (option-card-ui) {
|
|
2
10
|
:where(:scope) {
|
|
3
11
|
/* ── Container ── */
|
|
@@ -138,11 +146,7 @@
|
|
|
138
146
|
display: block;
|
|
139
147
|
}
|
|
140
148
|
|
|
141
|
-
/*
|
|
142
|
-
:scope:not([checked]):not([disabled]):hover {
|
|
143
|
-
background: var(--option-card-bg-hover);
|
|
144
|
-
border-color: var(--option-card-border-hover);
|
|
145
|
-
}
|
|
149
|
+
/* hover rule moved outside @scope — see Safari 17.x bug note at top. */
|
|
146
150
|
|
|
147
151
|
/* ── State: checked — accent border + tinted bg + filled radio.
|
|
148
152
|
The indicator becomes an accent disc with a centered dot of
|
|
@@ -37,6 +37,14 @@
|
|
|
37
37
|
border-radius: var(--progress-radius);
|
|
38
38
|
background: var(--progress-fill);
|
|
39
39
|
transition: width var(--progress-duration) var(--progress-easing);
|
|
40
|
+
|
|
41
|
+
/* Enter animation: paint the fill at 0 on first frame, then transition
|
|
42
|
+
to the inline width set by JS — so a freshly-mounted determinate bar
|
|
43
|
+
animates 0 → value rather than snapping in (or, in some cascades,
|
|
44
|
+
briefly painting at the indeterminate width:100% before settling). */
|
|
45
|
+
@starting-style {
|
|
46
|
+
width: 0;
|
|
47
|
+
}
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
/* Indeterminate bar shimmer */
|
|
@@ -53,6 +53,15 @@ class AdiaProgressRow extends AdiaElement {
|
|
|
53
53
|
this.#progressEl = this.querySelector(':scope > progress-ui');
|
|
54
54
|
if (!this.#progressEl) {
|
|
55
55
|
this.#progressEl = document.createElement('progress-ui');
|
|
56
|
+
// Pre-set value BEFORE append so progress-ui's first paint is
|
|
57
|
+
// determinate at the target value — `@starting-style { width: 0 }`
|
|
58
|
+
// in progress.css then transitions 0 → value on mount. Without this,
|
|
59
|
+
// the bar mounts indeterminate (width: 100% from the shimmer rule),
|
|
60
|
+
// and `render()` setting value: N triggers a backwards 100% → N
|
|
61
|
+
// animation, which reads as the bar shrinking right-to-left.
|
|
62
|
+
if (this.value != null && this.value >= 0) {
|
|
63
|
+
this.#progressEl.setAttribute('value', String(this.value));
|
|
64
|
+
}
|
|
56
65
|
this.appendChild(this.#progressEl);
|
|
57
66
|
}
|
|
58
67
|
}
|