@threadlabs/looma 0.26.1 → 0.26.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/components/ui-avatar/ui-avatar.html +6 -1
- package/components/ui-badge/ui-badge.html +101 -12
- package/components/ui-container/ui-container.html +11 -0
- package/components/ui-icon-button/ui-icon-button.html +58 -12
- package/components/ui-list-item/ui-list-item.html +13 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/styles/ui-avatar.css +4 -0
- package/styles/ui-badge.css +107 -8
- package/styles/ui-container.css +8 -0
- package/styles/ui-icon-button.css +62 -12
- package/styles/ui-list-item.css +12 -0
- package/vanilla/UiBadge.d.ts +3 -3
- package/vanilla/UiBadge.js +1 -1
- package/vanilla/UiContainer.d.ts +1 -0
- package/vanilla/UiContainer.js +5 -5
- package/vanilla/UiIconButton.d.ts +1 -0
- package/vanilla/UiIconButton.js +4 -4
- package/vanilla/UiListItem.d.ts +1 -0
- package/vanilla/UiListItem.js +6 -6
- package/vue/UiAvatar.vue +6 -1
- package/vue/UiBadge.d.ts +9 -9
- package/vue/UiBadge.vue +123 -21
- package/vue/UiCard.d.ts +1 -1
- package/vue/UiContainer.d.ts +9 -0
- package/vue/UiContainer.vue +27 -1
- package/vue/UiIconButton.d.ts +9 -0
- package/vue/UiIconButton.vue +95 -12
- package/vue/UiListItem.d.ts +9 -0
- package/vue/UiListItem.vue +31 -0
- package/vue/UiPopover.d.ts +1 -1
- package/vue/UiScrollArea.d.ts +1 -1
- package/vue/UiTooltip.d.ts +1 -1
- package/vue/chunks/UiAvatar.js +2 -2
- package/vue/chunks/UiBadge.js +13 -7
- package/vue/chunks/UiContainer.js +23 -1
- package/vue/chunks/UiIconButton.js +25 -1
- package/vue/chunks/UiListItem.js +26 -2
- package/vue/components.css +319 -147
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
<prop name="size" type="keyword" values="xs, sm, md" default="md"
|
|
17
17
|
>md is 2.5rem, for a person on their own (a profile, a comment); sm is 1.75rem with smaller initials, for a row of people in a toolbar or header; xs is
|
|
18
18
|
1.25rem with small initials, for a person named inline in a line of small text.</prop>
|
|
19
|
-
<prop name="shape" type="keyword" values="circle, square" default="circle"
|
|
19
|
+
<prop name="shape" type="keyword" values="circle, square" default="circle"
|
|
20
|
+
>Circle by default, with a shallow shadow; square uses the theme's medium radius.</prop>
|
|
20
21
|
<prop name="decorative" type="boolean" default="false">Hides the avatar from assistive technology when adjacent text already identifies the person.</prop>
|
|
21
22
|
<prop name="active" type="boolean" default="false"
|
|
22
23
|
>Marks the person as active now, such as editing the same page: a fine accent ring around the avatar. The ring is not announced, so say what it means in alt
|
|
@@ -96,6 +97,10 @@
|
|
|
96
97
|
border-color: var(--ui-avatar-border, var(--ui-border-strong));
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
:host([shape="circle"]) {
|
|
101
|
+
box-shadow: var(--ui-shadow-sm);
|
|
102
|
+
}
|
|
103
|
+
|
|
99
104
|
:host([shape="square"]) {
|
|
100
105
|
border-radius: var(--ui-avatar-radius, var(--ui-radius-md));
|
|
101
106
|
}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
<template component="ui-badge">
|
|
2
2
|
<defs>
|
|
3
|
-
<prop name="variant" type="keyword" values="solid, subtle, outline" default="subtle"
|
|
3
|
+
<prop name="variant" type="keyword" values="solid, subtle, outline, inverse" default="subtle"
|
|
4
4
|
>Emphasis. subtle sets toned text over a soft wash; solid fills with the tone and uses contrasting text; outline keeps the surface with a toned edge.
|
|
5
|
-
|
|
5
|
+
inverse uses a translucent contrasting surface and toned ink for a count or label on a filled control of that tone. Neutral looks the same in solid and
|
|
6
|
+
subtle. When space is constrained, the label truncates with an ellipsis while its full text remains available.</prop>
|
|
6
7
|
<prop name="tone" type="keyword" values="neutral, accent, info, success, warning, danger" default="neutral"
|
|
7
8
|
>Which colour the badge speaks in. neutral is a quiet grey for plain labels; accent draws the eye in the accent colour; info, success, warning, and danger
|
|
8
9
|
mark a status, so match the tone to what the badge says. For a category rather than a status, set the --ui-badge-color hook on the badge instead: any CSS
|
|
9
10
|
colour, which overrides the tone.</prop>
|
|
10
|
-
<prop name="shape" type="keyword" values="pill, tag, dot, square" default="pill"
|
|
11
|
+
<prop name="shape" type="keyword" values="pill, tag, dot, square, circle" default="pill"
|
|
11
12
|
>Silhouette. pill is rounded at both ends; tag is a pointed label. dot is a compact circular signal with visually hidden text: include a state label, or set
|
|
12
13
|
aria-hidden when the surrounding control already names that state. square is a fixed rounded square for an icon or single glyph beside a heading; hide a
|
|
13
|
-
decorative icon when adjacent words name it
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
decorative icon when adjacent words name it. circle frames a visible glyph, icon or short bounded count in a fixed circle, centered in both
|
|
15
|
+
directions.</prop>
|
|
16
|
+
<prop name="size" type="keyword" values="xs, md, lg" default="md"
|
|
17
|
+
>Scale. xs is compact; md is the usual text badge; lg adds room to fixed marks while retaining the usual text size. A square is 24px at xs, 32px at md and
|
|
18
|
+
40px at lg. A circle is 16px at xs, 24px at md and 32px at lg; use lg for short counts such as 30 or 99+.</prop>
|
|
16
19
|
</defs>
|
|
17
20
|
<span>
|
|
18
21
|
<span class="icon" aria-hidden="true"><slot name="icon"></slot></span>
|
|
@@ -28,6 +31,10 @@
|
|
|
28
31
|
syntax: "*";
|
|
29
32
|
inherits: false;
|
|
30
33
|
}
|
|
34
|
+
@property --ui-badge-circle-size {
|
|
35
|
+
syntax: "*";
|
|
36
|
+
inherits: false;
|
|
37
|
+
}
|
|
31
38
|
@property --ui-badge-dot-size {
|
|
32
39
|
syntax: "*";
|
|
33
40
|
inherits: false;
|
|
@@ -152,25 +159,26 @@
|
|
|
152
159
|
text-box-trim: none;
|
|
153
160
|
}
|
|
154
161
|
|
|
155
|
-
/*
|
|
156
|
-
|
|
162
|
+
/* Center the capital/baseline text box, while clipping only inline overflow for ellipsis.
|
|
163
|
+
Vertical ink remains visible so trimming never cuts off ascenders or descenders. */
|
|
157
164
|
@supports (text-box-trim: trim-both) {
|
|
158
165
|
:host {
|
|
159
166
|
display: inline-block;
|
|
160
167
|
min-block-size: var(--ui-badge-min-block-size, 1.5rem);
|
|
161
168
|
text-align: center;
|
|
162
169
|
align-content: center;
|
|
163
|
-
text-box-trim:
|
|
164
|
-
text-box-edge: text;
|
|
170
|
+
text-box-trim: none;
|
|
165
171
|
}
|
|
166
172
|
:host:has(.icon:not(:empty)),
|
|
167
173
|
:host:has(.label svg) {
|
|
168
174
|
display: inline-flex;
|
|
169
175
|
text-box-trim: none;
|
|
170
176
|
}
|
|
171
|
-
|
|
177
|
+
.label:not(:has(svg)) {
|
|
172
178
|
text-box-trim: trim-both;
|
|
173
|
-
text-box-edge:
|
|
179
|
+
text-box-edge: cap alphabetic;
|
|
180
|
+
overflow-x: clip;
|
|
181
|
+
overflow-y: visible;
|
|
174
182
|
}
|
|
175
183
|
}
|
|
176
184
|
|
|
@@ -251,6 +259,29 @@
|
|
|
251
259
|
--_badge-color-text: color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-surface-default));
|
|
252
260
|
}
|
|
253
261
|
|
|
262
|
+
/* A translucent inverse surface picks up its filled control's tone. Deepen the tone ink
|
|
263
|
+
toward the theme text to retain contrast against that composed surface. */
|
|
264
|
+
:host([variant="inverse"]) {
|
|
265
|
+
--_badge-color-surface: color-mix(in srgb, color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-surface-default)) 88%, transparent);
|
|
266
|
+
--_badge-color-border: var(--_badge-color-surface);
|
|
267
|
+
--_badge-color-text: color-mix(in srgb, var(--_badge-color-ink) 85%, var(--ui-text-primary));
|
|
268
|
+
--_badge-outline-surface: var(--ui-badge-surface, var(--_badge-color-surface, color-mix(in srgb, var(--_badge-text) 88%, transparent)));
|
|
269
|
+
border-color: var(--ui-badge-border, var(--_badge-color-border, color-mix(in srgb, var(--_badge-text) 88%, transparent)));
|
|
270
|
+
color: var(--ui-badge-text, var(--_badge-color-text, color-mix(in srgb, var(--_badge-surface) 85%, var(--ui-text-primary))));
|
|
271
|
+
/* Paint each translucent layer once, including the border, without a bright double-painted ring. */
|
|
272
|
+
background-clip: padding-box;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
:host([variant="inverse"][shape="circle"]) {
|
|
276
|
+
box-shadow: var(--ui-shadow-sm);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* Neutral reverses a subtle surface/ink pair rather than a strong tone. Keep its original
|
|
280
|
+
surface ink: moving it toward dark-theme primary text would reduce overlay contrast. */
|
|
281
|
+
:host([variant="inverse"][tone="neutral"]) {
|
|
282
|
+
color: var(--ui-badge-text, var(--_badge-color-text, var(--_badge-surface)));
|
|
283
|
+
}
|
|
284
|
+
|
|
254
285
|
:host([variant="outline"]) {
|
|
255
286
|
--_badge-surface: var(--ui-surface-default);
|
|
256
287
|
--_badge-border: var(--ui-border-strong);
|
|
@@ -304,6 +335,10 @@
|
|
|
304
335
|
--_badge-square-size: var(--ui-badge-square-size, calc(var(--ui-space-3) * 2));
|
|
305
336
|
}
|
|
306
337
|
|
|
338
|
+
:host([shape="square"][size="lg"]) {
|
|
339
|
+
--_badge-square-size: var(--ui-badge-square-size, calc(var(--ui-space-4) * 2 + var(--ui-space-2)));
|
|
340
|
+
}
|
|
341
|
+
|
|
307
342
|
:host([shape="square"]) .label {
|
|
308
343
|
display: inline-flex;
|
|
309
344
|
align-items: center;
|
|
@@ -318,6 +353,56 @@
|
|
|
318
353
|
display: none;
|
|
319
354
|
}
|
|
320
355
|
|
|
356
|
+
/* A visible glyph needs fixed geometry, unlike a content-sized pill or a hidden-label dot. */
|
|
357
|
+
:host([shape="circle"]) {
|
|
358
|
+
--_badge-circle-size: var(--ui-badge-circle-size, calc(var(--ui-space-3) * 2));
|
|
359
|
+
display: inline-flex;
|
|
360
|
+
flex: none;
|
|
361
|
+
inline-size: var(--_badge-circle-size);
|
|
362
|
+
block-size: var(--_badge-circle-size);
|
|
363
|
+
min-inline-size: var(--_badge-circle-size);
|
|
364
|
+
min-block-size: var(--_badge-circle-size);
|
|
365
|
+
padding: 0;
|
|
366
|
+
border-radius: var(--ui-radius-round);
|
|
367
|
+
text-box-trim: none;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
:host([shape="circle"][size="xs"]) {
|
|
371
|
+
--_badge-circle-size: var(--ui-badge-circle-size, var(--ui-space-4));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
:host([shape="circle"][size="lg"]) {
|
|
375
|
+
--_badge-circle-size: var(--ui-badge-circle-size, calc(var(--ui-space-4) * 2));
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
:host([shape="circle"]) .label {
|
|
379
|
+
display: inline-flex;
|
|
380
|
+
align-items: center;
|
|
381
|
+
justify-content: center;
|
|
382
|
+
line-height: 1;
|
|
383
|
+
text-box-trim: none;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
:host([shape="circle"]) .label :slotted(svg) {
|
|
387
|
+
margin-inline-end: 0;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
:host([shape="circle"]) .label:empty {
|
|
391
|
+
display: none;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/* Center capital and numeral ink, rather than the font's ascent/descent line box.
|
|
395
|
+
Icon labels retain flex geometry; untrimmed browsers keep that fallback too. */
|
|
396
|
+
@supports (text-box-trim: trim-both) {
|
|
397
|
+
:host([shape="circle"]) .label:not(:has(svg)),
|
|
398
|
+
:host([shape="square"]) .label:not(:has(svg)) {
|
|
399
|
+
display: block;
|
|
400
|
+
text-box-trim: trim-both;
|
|
401
|
+
text-box-edge: cap alphabetic;
|
|
402
|
+
overflow: visible;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
321
406
|
/* A dot uses the badge's tone recipe; only its silhouette and visible label change. */
|
|
322
407
|
:host([shape="dot"]) {
|
|
323
408
|
position: relative;
|
|
@@ -365,6 +450,10 @@
|
|
|
365
450
|
pointer-events: none;
|
|
366
451
|
}
|
|
367
452
|
|
|
453
|
+
:host([shape="tag"][variant="inverse"]) {
|
|
454
|
+
background: var(--ui-badge-border, var(--_badge-color-border, var(--_badge-text)));
|
|
455
|
+
}
|
|
456
|
+
|
|
368
457
|
:host([shape="tag"]):dir(rtl) {
|
|
369
458
|
padding-inline-end: var(--ui-badge-padding-inline, var(--ui-space-2));
|
|
370
459
|
padding-inline-start: calc(var(--ui-badge-padding-inline, var(--ui-space-2)) + var(--_badge-point));
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<template component="ui-container">
|
|
2
2
|
<defs>
|
|
3
|
+
<prop name="fill" type="boolean" default="false"
|
|
4
|
+
>Keeps the readable width while filling available layout space. Uses a flex column so scrolling children can shrink inside a bounded flex or grid parent.
|
|
5
|
+
Omit it to keep the usual block layout.</prop>
|
|
3
6
|
<prop name="measure" type="keyword" values="narrow, wide"
|
|
4
7
|
>The container's maximum width, in characters of the current font: narrow is 45ch, wide is 80ch, and unset is 65ch, a comfortable reading line. The
|
|
5
8
|
container centres itself when its parent is wider. The --ui-container-measure custom property, set on the container itself, overrides it; set on an
|
|
@@ -32,6 +35,14 @@
|
|
|
32
35
|
:host([measure="narrow"]) {
|
|
33
36
|
--_container-measure: 45ch;
|
|
34
37
|
}
|
|
38
|
+
:host([fill]) {
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
display: flex;
|
|
41
|
+
flex-direction: column;
|
|
42
|
+
flex: 1;
|
|
43
|
+
min-inline-size: 0;
|
|
44
|
+
min-block-size: 0;
|
|
45
|
+
}
|
|
35
46
|
:host([measure="wide"]) {
|
|
36
47
|
--_container-measure: 80ch;
|
|
37
48
|
}
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
<prop name="variant" type="keyword" values="ghost, outline, solid" default="ghost"
|
|
18
18
|
>Emphasis. ghost shows only the icon until it is hovered, for toolbars and dense rows; outline adds a border on the default surface; solid fills with the
|
|
19
19
|
accent colour, for the one primary action in a group.</prop>
|
|
20
|
+
<prop name="tone" type="keyword" values="accent, neutral"
|
|
21
|
+
>Colour for every variant. When omitted, ghost and outline keep their neutral appearance and solid keeps its accent fill. Set accent for a coloured action
|
|
22
|
+
or neutral for a quiet one. Native aria-pressed="true" keeps an outline toggle visibly pressed; the consumer owns that state.</prop>
|
|
20
23
|
<prop name="anticipatory" type="boolean" default="false"
|
|
21
24
|
>Keeps the button out of sight until it is wanted: at rest a fine pointer sees only a small guide dot, and the button appears on hover, on focus, or when
|
|
22
25
|
the pointer comes near inside a ui-affordance-scope. Touch devices and the solid variant always show it.</prop>
|
|
@@ -121,6 +124,21 @@
|
|
|
121
124
|
color: var(--ui-text-secondary);
|
|
122
125
|
}
|
|
123
126
|
|
|
127
|
+
:host([tone="accent"]) {
|
|
128
|
+
--_icon-button-border: var(--ui-accent-solid);
|
|
129
|
+
--_icon-button-hover-border: var(--ui-accent-hover);
|
|
130
|
+
--_icon-button-text: var(--ui-accent-subtle-text, var(--ui-accent-solid));
|
|
131
|
+
--_icon-button-outline-surface: color-mix(in srgb, var(--ui-accent-solid) 5%, var(--ui-surface-default));
|
|
132
|
+
color: var(--_icon-button-text);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Omitted tone retains the existing accent solid; explicit neutral is additive. */
|
|
136
|
+
:host([tone="neutral"]) {
|
|
137
|
+
--_icon-button-solid-surface: var(--ui-text-primary);
|
|
138
|
+
--_icon-button-solid-hover-surface: var(--ui-text-primary);
|
|
139
|
+
--_icon-button-solid-text: var(--ui-surface-default);
|
|
140
|
+
}
|
|
141
|
+
|
|
124
142
|
:host([anticipatory]) {
|
|
125
143
|
position: relative;
|
|
126
144
|
}
|
|
@@ -153,13 +171,13 @@
|
|
|
153
171
|
}
|
|
154
172
|
|
|
155
173
|
@media (hover: hover) and (pointer: fine) {
|
|
156
|
-
:host([anticipatory]):not(:host([variant="solid"]), :host([loading]), :host([pending]), :disabled, [data-ui-proximity="near"], :hover, :focus-visible) {
|
|
174
|
+
:host([anticipatory]):not(:host([variant="solid"]), :host([loading]), :host([pending]), :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible) {
|
|
157
175
|
border-color: transparent;
|
|
158
176
|
background-color: transparent;
|
|
159
177
|
box-shadow: none;
|
|
160
178
|
}
|
|
161
179
|
|
|
162
|
-
:host([anticipatory]):not(:host([variant="solid"]), :host([loading]), :host([pending]), :disabled, [data-ui-proximity="near"], :hover, :focus-visible)
|
|
180
|
+
:host([anticipatory]):not(:host([variant="solid"]), :host([loading]), :host([pending]), :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)
|
|
163
181
|
.content {
|
|
164
182
|
opacity: 0;
|
|
165
183
|
transform: scale(0.65);
|
|
@@ -167,7 +185,7 @@
|
|
|
167
185
|
}
|
|
168
186
|
}
|
|
169
187
|
|
|
170
|
-
:host([anticipatory]):is(:host([variant="solid"]), [data-ui-proximity="near"], :hover, :focus-visible)::before {
|
|
188
|
+
:host([anticipatory]):is(:host([variant="solid"]), [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)::before {
|
|
171
189
|
opacity: 0;
|
|
172
190
|
}
|
|
173
191
|
|
|
@@ -277,17 +295,17 @@
|
|
|
277
295
|
}
|
|
278
296
|
|
|
279
297
|
:host([variant="outline"]) {
|
|
280
|
-
border-color: var(--ui-icon-button-border, var(--ui-control-border, var(--ui-border-strong)));
|
|
281
|
-
background-color: var(--ui-icon-button-outline-surface, var(--ui-surface-default));
|
|
298
|
+
border-color: var(--ui-icon-button-border, var(--_icon-button-border, var(--ui-control-border, var(--ui-border-strong))));
|
|
299
|
+
background-color: var(--ui-icon-button-outline-surface, var(--_icon-button-outline-surface, var(--ui-surface-default)));
|
|
282
300
|
background-image: var(--ui-raised-highlight);
|
|
283
|
-
color: var(--ui-icon-button-outline-text, var(--ui-text-primary));
|
|
301
|
+
color: var(--ui-icon-button-outline-text, var(--_icon-button-text, var(--ui-text-primary)));
|
|
284
302
|
box-shadow: var(--ui-raised);
|
|
285
303
|
}
|
|
286
304
|
|
|
287
305
|
:host([variant="solid"]) {
|
|
288
|
-
background-color: var(--ui-icon-button-solid-surface, var(--ui-accent-solid));
|
|
306
|
+
background-color: var(--ui-icon-button-solid-surface, var(--_icon-button-solid-surface, var(--ui-accent-solid)));
|
|
289
307
|
background-image: var(--ui-raised-highlight);
|
|
290
|
-
color: var(--ui-icon-button-solid-text, var(--ui-text-on-accent));
|
|
308
|
+
color: var(--ui-icon-button-solid-text, var(--_icon-button-solid-text, var(--ui-text-on-accent)));
|
|
291
309
|
box-shadow: var(
|
|
292
310
|
--ui-icon-button-solid-shadow,
|
|
293
311
|
0 1px 2px color-mix(in srgb, var(--ui-accent-solid) 18%, transparent)
|
|
@@ -297,20 +315,32 @@
|
|
|
297
315
|
:host:hover:enabled:not([aria-disabled="true"]) {
|
|
298
316
|
/* Derived from the text colour so the ghost hover shows on any background. */
|
|
299
317
|
background-color: var(--ui-icon-button-hover-surface, color-mix(in srgb, currentColor 8%, transparent));
|
|
300
|
-
color: var(--ui-icon-button-hover-text, var(--ui-text-primary));
|
|
318
|
+
color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
|
|
301
319
|
}
|
|
302
320
|
|
|
303
321
|
:host([variant="outline"]):hover:enabled:not([aria-disabled="true"]) {
|
|
304
|
-
border-color: var(--ui-icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border)));
|
|
322
|
+
border-color: var(--ui-icon-button-hover-border, var(--_icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border))));
|
|
305
323
|
}
|
|
306
324
|
|
|
307
325
|
:host([variant="solid"]):hover:enabled:not([aria-disabled="true"]) {
|
|
308
|
-
background-color: var(--ui-icon-button-solid-hover-surface, var(--ui-accent-hover));
|
|
326
|
+
background-color: var(--ui-icon-button-solid-hover-surface, var(--_icon-button-solid-hover-surface, var(--ui-accent-hover)));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
:host([variant="solid"][tone="accent"]):hover:enabled:not([aria-disabled="true"]),
|
|
330
|
+
:host([variant="solid"][tone="neutral"]):hover:enabled:not([aria-disabled="true"]) {
|
|
331
|
+
color: var(--ui-icon-button-solid-text, var(--_icon-button-solid-text, var(--ui-text-on-accent)));
|
|
309
332
|
}
|
|
310
333
|
|
|
311
334
|
:host([variant="ghost"])[aria-expanded="true"]:enabled:not([aria-disabled="true"]) {
|
|
312
335
|
background-color: var(--ui-icon-button-active-surface, color-mix(in srgb, currentColor 16%, transparent));
|
|
313
|
-
color: var(--ui-icon-button-hover-text, var(--ui-text-primary));
|
|
336
|
+
color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
|
|
337
|
+
box-shadow: var(--ui-pressed);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/* Native toggle state persists after pointer release, including during loading. */
|
|
341
|
+
:host([variant="outline"])[aria-pressed="true"]:enabled {
|
|
342
|
+
background-color: var(--ui-icon-button-active-surface, color-mix(in srgb, currentColor 12%, var(--ui-surface-default)));
|
|
343
|
+
background-image: none;
|
|
314
344
|
box-shadow: var(--ui-pressed);
|
|
315
345
|
}
|
|
316
346
|
|
|
@@ -343,6 +373,22 @@
|
|
|
343
373
|
box-shadow: var(--ui-focus-halo);
|
|
344
374
|
}
|
|
345
375
|
|
|
376
|
+
:host([variant="outline"])[aria-pressed="true"]:enabled:focus-visible {
|
|
377
|
+
box-shadow:
|
|
378
|
+
var(--ui-pressed),
|
|
379
|
+
var(--ui-focus-halo);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
@media (forced-colors: active) {
|
|
383
|
+
:host([variant="outline"])[aria-pressed="true"]:enabled {
|
|
384
|
+
outline: var(--ui-focus-width) solid Highlight;
|
|
385
|
+
outline-offset: calc(-2 * var(--ui-focus-width));
|
|
386
|
+
}
|
|
387
|
+
:host([variant="outline"])[aria-pressed="true"]:enabled:focus-visible {
|
|
388
|
+
outline-offset: var(--ui-focus-width);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
346
392
|
/* Disabled is a flat neutral control, independent of the active variant's tone. */
|
|
347
393
|
:host:disabled {
|
|
348
394
|
border-color: var(--ui-disabled-border);
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
combining them with a leading control.</prop>
|
|
9
9
|
<prop name="wrap" type="boolean" default="false"
|
|
10
10
|
>Lets the title and description wrap so explanatory text stays readable on narrow screens. Omit it for the default equal-height, one-line rows.</prop>
|
|
11
|
+
<prop name="align" type="keyword" values="center, title" default="center"
|
|
12
|
+
>Where the leading and trailing regions sit vertically. center aligns them with the whole row. title aligns them with the first title line, keeping an
|
|
13
|
+
identifying icon beside its name when the title or description wraps. Taller controls retain their natural height.</prop>
|
|
11
14
|
<prop name="current" type="boolean" default="false"
|
|
12
15
|
>Marks the item as the current one, such as the site you are in: it takes the selected surface and aria-current="true", which assistive technology
|
|
13
16
|
announces. Set it on one item at a time.</prop>
|
|
@@ -158,6 +161,16 @@
|
|
|
158
161
|
line-height: var(--ui-line-height-tight);
|
|
159
162
|
}
|
|
160
163
|
|
|
164
|
+
/* Keep identity and disclosure marks beside the first line, even with a long description. */
|
|
165
|
+
:host([align="title"]) {
|
|
166
|
+
align-items: flex-start;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
:host([align="title"]) .leading,
|
|
170
|
+
:host([align="title"]) .trailing {
|
|
171
|
+
min-block-size: calc(var(--ui-font-size-md) * var(--ui-line-height-tight));
|
|
172
|
+
}
|
|
173
|
+
|
|
161
174
|
.description {
|
|
162
175
|
color: var(--ui-text-muted);
|
|
163
176
|
font-size: var(--ui-font-size-sm);
|