@slotted/styles 0.1.0-beta.5 → 0.1.0-beta.7
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/package.json +1 -1
- package/src/app-shell/app-shell.css +55 -6
- package/src/button/button.css +17 -2
- package/src/kbd/kbd.css +4 -0
- package/src/menu/menu.css +22 -0
- package/src/segmented-control/segmented-control.css +133 -54
- package/src/segmented-control/segmented-control.tokens.json +7 -11
- package/src/side-navigation/side-navigation.css +9 -2
- package/src/side-navigation/side-navigation.tokens.json +1 -0
- package/src/stat-card/stat-card.css +47 -47
- package/src/tabs/tabs.css +29 -16
- package/src/tabs/tabs.tokens.json +3 -0
package/package.json
CHANGED
|
@@ -82,6 +82,16 @@
|
|
|
82
82
|
/** The box a row's mark occupies: a control's own size, so the two agree. */
|
|
83
83
|
--_row-mark: var(--slotted-app-shell-row-mark-size, var(--slotted-control-height-md, 34px));
|
|
84
84
|
--_row-gap: var(--slotted-control-gap-md, 8px);
|
|
85
|
+
/**
|
|
86
|
+
* How far a focus ring drawn outside a control reaches past its box: the
|
|
87
|
+
* ring's width and its offset, 4px with the default theme. The three parts
|
|
88
|
+
* of the navigation column pad their inline sides by it, because the body
|
|
89
|
+
* scrolls and clips at its padding box, and a full-width control's ring
|
|
90
|
+
* stood outside that box on both sides.
|
|
91
|
+
*/
|
|
92
|
+
--_row-ring-inset: calc(
|
|
93
|
+
var(--slotted-focus-ring-width, 2px) + var(--slotted-focus-ring-offset, 2px)
|
|
94
|
+
);
|
|
85
95
|
|
|
86
96
|
/**
|
|
87
97
|
* A row's type. A list of destinations is text and not a control, so it
|
|
@@ -495,7 +505,19 @@
|
|
|
495
505
|
gap: var(--_row-gap);
|
|
496
506
|
min-block-size: var(--_rail-size);
|
|
497
507
|
min-inline-size: 0;
|
|
508
|
+
/**
|
|
509
|
+
* The gutter the body reserves, reserved here too. `scrollbar-gutter`
|
|
510
|
+
* applies to a scroll container only, and `hidden` is the overflow that
|
|
511
|
+
* makes one without a bar of its own: with classic scrollbars the body's
|
|
512
|
+
* content box ended one bar width (10px in Chrome) before the head's and
|
|
513
|
+
* the foot's. Nothing is clipped that was drawn before: the ring inset
|
|
514
|
+
* keeps a control's focus ring inside the padding box. The bar's width is
|
|
515
|
+
* the body's, or the gutter is the platform's full bar (15px in Chrome).
|
|
516
|
+
*/
|
|
517
|
+
overflow: hidden;
|
|
498
518
|
padding-block: var(--_row-inset);
|
|
519
|
+
scrollbar-gutter: stable;
|
|
520
|
+
scrollbar-width: thin;
|
|
499
521
|
}
|
|
500
522
|
/**
|
|
501
523
|
* The inset is the rows', not the region's: on the parts, a seam drawn by
|
|
@@ -505,7 +527,13 @@
|
|
|
505
527
|
[data-ui='app-shell']
|
|
506
528
|
> [data-part='nav']
|
|
507
529
|
> :is([data-part='nav-header'], [data-part='nav-body'], [data-part='nav-footer']) {
|
|
508
|
-
|
|
530
|
+
/**
|
|
531
|
+
* Published where it pads, beside the row geometry the root publishes:
|
|
532
|
+
* `side-navigation` reads it to keep its rows' box on the edge it had,
|
|
533
|
+
* and a row it reaches outside these parts reads nothing.
|
|
534
|
+
*/
|
|
535
|
+
--slotted-app-shell-row-ring-inset: var(--_row-ring-inset);
|
|
536
|
+
padding-inline: calc(var(--_nav-inset) + var(--_row-ring-inset));
|
|
509
537
|
}
|
|
510
538
|
/**
|
|
511
539
|
* The body scrolls the way `scroll-area` scrolls, and for the reasons written
|
|
@@ -1221,6 +1249,19 @@
|
|
|
1221
1249
|
border-start-end-radius: 0;
|
|
1222
1250
|
margin-inline-end: 0;
|
|
1223
1251
|
}
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* The seam re-read in each region's scope. `--_seam` declared on the root
|
|
1255
|
+
* holds the root's `--slotted-app-shell-border-color`, so the property written
|
|
1256
|
+
* on a region recoloured nothing. Declared again on every region, the chain
|
|
1257
|
+
* resolves where the region stands: a colour written there recolours the
|
|
1258
|
+
* seams the region and its parts draw, and `transparent` removes them. The
|
|
1259
|
+
* tone rules below state the same two declarations at a higher specificity.
|
|
1260
|
+
*/
|
|
1261
|
+
[data-ui='app-shell'] > [data-part] {
|
|
1262
|
+
--_rule: var(--slotted-app-shell-border-color, var(--slotted-border-subtle, ButtonBorder));
|
|
1263
|
+
--_seam: var(--_rule-width) solid var(--_rule);
|
|
1264
|
+
}
|
|
1224
1265
|
/* ── Separation by tone ──────────────────────────────────────────────── */
|
|
1225
1266
|
|
|
1226
1267
|
/**
|
|
@@ -1238,7 +1279,8 @@
|
|
|
1238
1279
|
* where it is declared, and a region carrying a scheme of its own must mix
|
|
1239
1280
|
* its own ink.
|
|
1240
1281
|
*/
|
|
1241
|
-
[data-ui='app-shell'][data-separation='tone']
|
|
1282
|
+
[data-ui='app-shell'][data-separation='tone'],
|
|
1283
|
+
[data-ui='app-shell'][data-separation='tone'] > [data-part] {
|
|
1242
1284
|
--_seam: none;
|
|
1243
1285
|
--_seam-width: 0px;
|
|
1244
1286
|
}
|
|
@@ -1365,7 +1407,7 @@
|
|
|
1365
1407
|
[data-ui='app-shell']
|
|
1366
1408
|
> [data-part='nav']:has(> [data-part='nav-rail'])
|
|
1367
1409
|
> :is([data-part='nav-header'], [data-part='nav-body'], [data-part='nav-footer']) {
|
|
1368
|
-
padding-inline-start: var(--_row-inset);
|
|
1410
|
+
padding-inline-start: calc(var(--_row-inset) + var(--_row-ring-inset));
|
|
1369
1411
|
transition: visibility var(--_duration) step-start;
|
|
1370
1412
|
}
|
|
1371
1413
|
[data-ui='app-shell'][data-nav-mode='inline'][data-open]
|
|
@@ -1400,7 +1442,8 @@
|
|
|
1400
1442
|
* a forced-colours rule of its own for.
|
|
1401
1443
|
*/
|
|
1402
1444
|
@media (forced-colors: active) {
|
|
1403
|
-
[data-ui='app-shell'][data-separation='tone']
|
|
1445
|
+
[data-ui='app-shell'][data-separation='tone'],
|
|
1446
|
+
[data-ui='app-shell'][data-separation='tone'] > [data-part] {
|
|
1404
1447
|
--_seam: var(--_rule-width) solid CanvasText;
|
|
1405
1448
|
--_seam-width: var(--_rule-width);
|
|
1406
1449
|
}
|
|
@@ -1501,8 +1544,12 @@
|
|
|
1501
1544
|
* mode at any width. The container query further down is the fallback for
|
|
1502
1545
|
* the frame before the binding has measured, and nothing else.
|
|
1503
1546
|
*/
|
|
1547
|
+
/* The rail holds the parts' ring inset on each side as well, so a control
|
|
1548
|
+
at the mark's size keeps its focus ring inside the body beside the gutter. */
|
|
1504
1549
|
[data-ui='app-shell'][data-nav-mode='inline'] > [data-part='nav'] {
|
|
1505
|
-
inline-size: calc(
|
|
1550
|
+
inline-size: calc(
|
|
1551
|
+
var(--_rail-size) + 2 * (var(--_nav-inset) + var(--_row-ring-inset)) + var(--_nav-edges)
|
|
1552
|
+
);
|
|
1506
1553
|
}
|
|
1507
1554
|
[data-ui='app-shell'][data-nav-mode='inline'][data-open] > [data-part='nav'] {
|
|
1508
1555
|
inline-size: var(--_nav-size);
|
|
@@ -1779,7 +1826,9 @@
|
|
|
1779
1826
|
*/
|
|
1780
1827
|
@container slotted-app-shell (inline-size >= 600px) {
|
|
1781
1828
|
[data-ui='app-shell']:not([data-nav-mode]) > [data-part='nav'] {
|
|
1782
|
-
inline-size: calc(
|
|
1829
|
+
inline-size: calc(
|
|
1830
|
+
var(--_rail-size) + 2 * (var(--_nav-inset) + var(--_row-ring-inset)) + var(--_nav-edges)
|
|
1831
|
+
);
|
|
1783
1832
|
}
|
|
1784
1833
|
[data-ui='app-shell']:not([data-nav-mode])[data-open] > [data-part='nav'] {
|
|
1785
1834
|
inline-size: var(--_nav-size);
|
package/src/button/button.css
CHANGED
|
@@ -625,14 +625,29 @@
|
|
|
625
625
|
position: relative;
|
|
626
626
|
}
|
|
627
627
|
|
|
628
|
-
[data-ui='button'] [data-part='start'] > *:not([data-part='indicator']),
|
|
629
|
-
[data-ui='button'] [data-part='end'] > *:not([data-part='indicator']),
|
|
628
|
+
[data-ui='button'] [data-part='start'] > *:not([data-part='indicator'], [data-ui='kbd']),
|
|
629
|
+
[data-ui='button'] [data-part='end'] > *:not([data-part='indicator'], [data-ui='kbd']),
|
|
630
630
|
[data-ui='button'] [data-part='icon'] > *:not([data-part='indicator']) {
|
|
631
631
|
block-size: 100%;
|
|
632
632
|
display: block;
|
|
633
633
|
inline-size: 100%;
|
|
634
634
|
}
|
|
635
635
|
|
|
636
|
+
/**
|
|
637
|
+
* A key in a slot is sized by its own family. The slot above is a glyph's
|
|
638
|
+
* box: it stated `display: block` on the key, which put the legend on a line
|
|
639
|
+
* box's baseline instead of the key's centre, sixteen pixels square, and the
|
|
640
|
+
* icon's font size, which `size="inherit"` read as the text's. Measured, a
|
|
641
|
+
* `Kbd` legend stood 1.5px above the label's centre and a `Shortcut` 1.5px
|
|
642
|
+
* below it. Here the slot takes the key's measure and the label's type, and
|
|
643
|
+
* the flex container centres the key on the label.
|
|
644
|
+
*/
|
|
645
|
+
[data-ui='button'] :is([data-part='start'], [data-part='end']):has(> [data-ui='kbd']) {
|
|
646
|
+
block-size: auto;
|
|
647
|
+
font-size: inherit;
|
|
648
|
+
inline-size: auto;
|
|
649
|
+
}
|
|
650
|
+
|
|
636
651
|
/**
|
|
637
652
|
* The label carries a wrapping line height of its own: the control's line
|
|
638
653
|
* height is 1, which centres a single line inside the box and crushes the
|
package/src/kbd/kbd.css
CHANGED
|
@@ -237,6 +237,10 @@
|
|
|
237
237
|
align-items: center;
|
|
238
238
|
direction: ltr;
|
|
239
239
|
display: inline-flex;
|
|
240
|
+
/* The root is a `kbd`: without these it keeps the user agent's monospace
|
|
241
|
+
face and its line box, which a key in the combination does not share. */
|
|
242
|
+
font-family: var(--slotted-kbd-font-family, var(--slotted-control-font-family, sans-serif));
|
|
243
|
+
line-height: 1;
|
|
240
244
|
/**
|
|
241
245
|
* A shortcut wider than its column wraps between caps and never inside
|
|
242
246
|
* one. The row gets taller; no instruction gets shorter.
|
package/src/menu/menu.css
CHANGED
|
@@ -290,6 +290,28 @@
|
|
|
290
290
|
visibility: hidden;
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
/**
|
|
294
|
+
* The surface as wide as its trigger: an account switcher at the foot of a
|
|
295
|
+
* sidebar, opened from a row the column's full width. The content takes the
|
|
296
|
+
* anchor's width as its size and its floor, as `popover`'s `width="anchor"`
|
|
297
|
+
* does, and the room the positioner reports caps both. The layer drops the
|
|
298
|
+
* family's floor and cap, which would hold it narrower or wider than the
|
|
299
|
+
* row. Opened above or below, the layer has no inline padding, so the
|
|
300
|
+
* content and the trigger share both edges.
|
|
301
|
+
*/
|
|
302
|
+
[data-ui='menu'][data-width='anchor'] {
|
|
303
|
+
max-inline-size: var(--slotted-positioner-available-width, 100vw);
|
|
304
|
+
min-inline-size: 0;
|
|
305
|
+
}
|
|
306
|
+
[data-ui='menu'][data-width='anchor'] > [data-part='content'] {
|
|
307
|
+
inline-size: var(--slotted-positioner-anchor-width, auto);
|
|
308
|
+
max-inline-size: var(--slotted-positioner-available-width, 100vw);
|
|
309
|
+
min-inline-size: min(
|
|
310
|
+
var(--slotted-positioner-anchor-width, 0px),
|
|
311
|
+
var(--slotted-positioner-available-width, 100vw)
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
293
315
|
[data-ui='menu'][data-size='sm'] {
|
|
294
316
|
--_item-padding: var(--slotted-control-padding-inline-sm, 0.625rem);
|
|
295
317
|
--_item-height: var(--slotted-control-height-sm, 30px);
|
|
@@ -59,6 +59,8 @@
|
|
|
59
59
|
--_inset: var(--slotted-segmented-control-inset, var(--slotted-space-1, 0.125rem));
|
|
60
60
|
/** What is left for a segment once the track has taken its edge and ring. */
|
|
61
61
|
--_inner: calc(var(--_height) - (var(--_inset) + var(--_border-width)) * 2);
|
|
62
|
+
/** The space between two segments: the ring's own step. */
|
|
63
|
+
--_spacing: var(--slotted-segmented-control-gap, var(--_inset));
|
|
62
64
|
/** The thumb's corner, kept concentric with the track's own. */
|
|
63
65
|
--_thumb-radius: max(calc(var(--_radius) - var(--_inset)), var(--slotted-radius-xs, 2px));
|
|
64
66
|
/**
|
|
@@ -69,15 +71,22 @@
|
|
|
69
71
|
*/
|
|
70
72
|
--_travel: var(--slotted-duration-medium);
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
/**
|
|
75
|
+
* A neutral track: the page's own ink at a low alpha rather than an opaque
|
|
76
|
+
* fill, so it darkens whatever it stands on — a surface, a sunken panel, a
|
|
77
|
+
* card header — by the same step, and reads as a recess in each. The edge
|
|
78
|
+
* keeps its width and is transparent by default, so the arithmetic below is
|
|
79
|
+
* the same with a theme's edge and without one. An accent track with an
|
|
80
|
+
* accent thumb edge was the first appearance: a coloured outline on a row
|
|
81
|
+
* of neutral controls read as an alert before it read as a choice.
|
|
82
|
+
*/
|
|
83
|
+
background: var(
|
|
84
|
+
--slotted-segmented-control-background,
|
|
85
|
+
color-mix(in oklab, var(--slotted-text, CanvasText) 6%, transparent)
|
|
86
|
+
);
|
|
87
|
+
border: var(--_border-width) solid var(--slotted-segmented-control-border-color, transparent);
|
|
79
88
|
border-radius: var(--_radius);
|
|
80
|
-
box-shadow: var(--slotted-segmented-control-shadow,
|
|
89
|
+
box-shadow: var(--slotted-segmented-control-shadow, none);
|
|
81
90
|
box-sizing: border-box;
|
|
82
91
|
display: inline-grid;
|
|
83
92
|
font-family: var(--slotted-control-font-family, system-ui, sans-serif);
|
|
@@ -87,8 +96,15 @@
|
|
|
87
96
|
* sized grid resolves every track to the largest content contribution, so
|
|
88
97
|
* the rule Carbon states — base the width on the longest label, and give
|
|
89
98
|
* every segment that width — falls out of the layout.
|
|
99
|
+
*
|
|
100
|
+
* The column carries the segment's floor, and the segment none of its own:
|
|
101
|
+
* a segment with a minimum inside a column that could shrink below it ran
|
|
102
|
+
* past its column in a narrow container, while the thumb, a column wide,
|
|
103
|
+
* did not — the thumb and its segment no longer matched, and the label
|
|
104
|
+
* overflowed the track.
|
|
90
105
|
*/
|
|
91
|
-
|
|
106
|
+
gap: var(--_spacing);
|
|
107
|
+
grid-auto-columns: minmax(max(var(--_inner), var(--slotted-target-min, 24px)), 1fr);
|
|
92
108
|
grid-auto-flow: column;
|
|
93
109
|
isolation: isolate;
|
|
94
110
|
min-inline-size: 0;
|
|
@@ -172,7 +188,10 @@
|
|
|
172
188
|
color: var(--slotted-segmented-control-color, var(--slotted-text, ButtonText));
|
|
173
189
|
cursor: pointer;
|
|
174
190
|
display: flex;
|
|
175
|
-
font-weight: var(
|
|
191
|
+
font-weight: var(
|
|
192
|
+
--slotted-segmented-control-font-weight,
|
|
193
|
+
var(--slotted-font-weight-medium, 500)
|
|
194
|
+
);
|
|
176
195
|
gap: var(--_gap);
|
|
177
196
|
justify-content: center;
|
|
178
197
|
letter-spacing: var(--slotted-control-letter-spacing, 0);
|
|
@@ -180,18 +199,34 @@
|
|
|
180
199
|
/**
|
|
181
200
|
* The thumb is shorter than the control it lives in, so at the smallest
|
|
182
201
|
* step and the tightest density it is eighteen pixels tall. The WCAG
|
|
183
|
-
* minimum is the floor across the segment, and the radio below
|
|
184
|
-
* track's own edge to meet it in the other axis.
|
|
202
|
+
* minimum is the column's floor across the segment, and the radio below
|
|
203
|
+
* reaches the track's own edge to meet it in the other axis.
|
|
185
204
|
*/
|
|
186
|
-
min-inline-size:
|
|
205
|
+
min-inline-size: 0;
|
|
187
206
|
padding-inline: var(--_padding-inline);
|
|
207
|
+
/**
|
|
208
|
+
* Positioned without a `z-index`: the segment paints after the thumb, which
|
|
209
|
+
* comes first in the DOM, so its words lie over the thumb, and its divider
|
|
210
|
+
* and its hover ground — pseudo-elements at `z-index: -1` — lie under it.
|
|
211
|
+
* A segment at `z-index: 1` lifted both over the thumb as well, and a thumb
|
|
212
|
+
* crossing a hovered segment or a divider lost part of its edge for the
|
|
213
|
+
* length of the slide.
|
|
214
|
+
*/
|
|
188
215
|
position: relative;
|
|
189
|
-
transition:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
216
|
+
transition: color var(--slotted-control-transition-duration)
|
|
217
|
+
var(--slotted-control-transition-easing);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** The hover and press ground, under the thumb; see the segment above. */
|
|
221
|
+
[data-ui='segmented-control'] [data-part='item']::after {
|
|
222
|
+
background: transparent;
|
|
223
|
+
border-radius: inherit;
|
|
224
|
+
content: '';
|
|
225
|
+
inset: 0;
|
|
226
|
+
position: absolute;
|
|
227
|
+
transition: background-color var(--slotted-control-transition-duration)
|
|
228
|
+
var(--slotted-control-transition-easing);
|
|
229
|
+
z-index: -1;
|
|
195
230
|
}
|
|
196
231
|
|
|
197
232
|
/* An empty label is no label: a binding that always renders the span must
|
|
@@ -205,27 +240,36 @@
|
|
|
205
240
|
}
|
|
206
241
|
|
|
207
242
|
/**
|
|
208
|
-
* ──
|
|
243
|
+
* ── Between two segments ──────────────────────────────────────────────
|
|
244
|
+
*
|
|
245
|
+
* Segments stand apart by the same step as the ring of track around them,
|
|
246
|
+
* so each one — its hover ground, the thumb on it — is a shape of its own
|
|
247
|
+
* on the track, and a rule in the middle of that room says the control is
|
|
248
|
+
* divided: a track of words with nothing between them reads as a sentence.
|
|
209
249
|
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
250
|
+
* The rule is centred in the gap rather than on a segment's edge, half the
|
|
251
|
+
* segment's height, rounded at its ends, in a light tint of the ink rather
|
|
252
|
+
* than an opaque border colour. It gives way wherever it would touch a
|
|
253
|
+
* shape: beside the thumb, and beside the segment under the pointer, whose
|
|
254
|
+
* ground would otherwise meet it. It lies under the thumb, so a thumb that
|
|
255
|
+
* crosses it while sliding passes over it.
|
|
216
256
|
*/
|
|
217
257
|
[data-ui='segmented-control'] [data-part='item'] + [data-part='item']::before {
|
|
218
258
|
/* No system colour behind it: an unthemed decoration disappears rather
|
|
219
259
|
than shouting, which is what `fallbacks.test.mjs` holds a pseudo-element
|
|
220
|
-
to.
|
|
221
|
-
|
|
222
|
-
|
|
260
|
+
to. In forced colours the thumb's own edge is what divides. */
|
|
261
|
+
background: var(
|
|
262
|
+
--slotted-segmented-control-divider-color,
|
|
263
|
+
color-mix(in oklab, var(--slotted-text) 14%, transparent)
|
|
264
|
+
);
|
|
265
|
+
border-radius: var(--slotted-radius-full, 9999px);
|
|
223
266
|
content: '';
|
|
224
267
|
inline-size: var(--_border-width);
|
|
225
|
-
inset-block:
|
|
226
|
-
inset-inline-start:
|
|
268
|
+
inset-block: 25%;
|
|
269
|
+
inset-inline-start: calc((var(--_spacing) + var(--_border-width)) / -2);
|
|
227
270
|
position: absolute;
|
|
228
271
|
transition: opacity var(--_travel) var(--slotted-easing-standard);
|
|
272
|
+
z-index: -1;
|
|
229
273
|
}
|
|
230
274
|
|
|
231
275
|
[data-ui='segmented-control'][data-part='root'][data-orientation='vertical']
|
|
@@ -233,13 +277,17 @@
|
|
|
233
277
|
+ [data-part='item']::before {
|
|
234
278
|
block-size: var(--_border-width);
|
|
235
279
|
inline-size: auto;
|
|
236
|
-
inset-block: auto;
|
|
237
|
-
inset-
|
|
238
|
-
inset-inline: 22%;
|
|
280
|
+
inset-block: calc((var(--_spacing) + var(--_border-width)) / -2) auto;
|
|
281
|
+
inset-inline: 25%;
|
|
239
282
|
}
|
|
240
283
|
|
|
241
284
|
[data-ui='segmented-control'] [data-part='item'][data-checked]::before,
|
|
242
|
-
[data-ui='segmented-control'] [data-part='item'][data-checked] + [data-part='item']::before
|
|
285
|
+
[data-ui='segmented-control'] [data-part='item'][data-checked] + [data-part='item']::before,
|
|
286
|
+
[data-ui='segmented-control'][data-part='root']:not([data-readonly])
|
|
287
|
+
[data-part='item']:hover:has([data-part='control']:enabled)::before,
|
|
288
|
+
[data-ui='segmented-control'][data-part='root']:not([data-readonly])
|
|
289
|
+
[data-part='item']:hover:has([data-part='control']:enabled)
|
|
290
|
+
+ [data-part='item']::before {
|
|
243
291
|
opacity: 0;
|
|
244
292
|
}
|
|
245
293
|
|
|
@@ -257,7 +305,9 @@
|
|
|
257
305
|
border-radius: inherit;
|
|
258
306
|
cursor: inherit;
|
|
259
307
|
inset-block: calc(-1 * (var(--_inset) + var(--_border-width)));
|
|
260
|
-
|
|
308
|
+
/* Half the space on each side, so the room between two segments is not a
|
|
309
|
+
place a press lands on nothing. */
|
|
310
|
+
inset-inline: calc(var(--_spacing) / -2);
|
|
261
311
|
margin: 0;
|
|
262
312
|
opacity: 0;
|
|
263
313
|
padding: 0;
|
|
@@ -277,7 +327,12 @@
|
|
|
277
327
|
* string stays whole in the DOM: truncation never removes content.
|
|
278
328
|
*/
|
|
279
329
|
[data-ui='segmented-control'] [data-part='label'] {
|
|
280
|
-
|
|
330
|
+
/* Clipped along the line only: `hidden` on a one-line box cut the
|
|
331
|
+
descenders and the accents above the cap height. A clipped box is not a
|
|
332
|
+
scroll container, so the flex minimum is given back by hand, or the words
|
|
333
|
+
would hold their full width and run into the next segment. */
|
|
334
|
+
min-inline-size: 0;
|
|
335
|
+
overflow-x: clip;
|
|
281
336
|
text-overflow: ellipsis;
|
|
282
337
|
white-space: nowrap;
|
|
283
338
|
}
|
|
@@ -307,20 +362,33 @@
|
|
|
307
362
|
* never seen — which is what Mantine does.
|
|
308
363
|
*/
|
|
309
364
|
[data-ui='segmented-control'] [data-part='indicator'] {
|
|
365
|
+
/* A raised surface with a hairline and the lightest elevation: the chosen
|
|
366
|
+
segment sits on the track rather than being painted into it. In a dark
|
|
367
|
+
scheme the raised surface is darker than the tinted track, and a thumb
|
|
368
|
+
darker than its track reads as a hole, so it takes a step of the ink. */
|
|
310
369
|
background: var(
|
|
311
370
|
--slotted-segmented-control-indicator-background,
|
|
312
|
-
|
|
371
|
+
light-dark(
|
|
372
|
+
var(--slotted-surface-raised, Canvas),
|
|
373
|
+
color-mix(
|
|
374
|
+
in oklab,
|
|
375
|
+
var(--slotted-text, CanvasText) 14%,
|
|
376
|
+
var(--slotted-surface-raised, Canvas)
|
|
377
|
+
)
|
|
378
|
+
)
|
|
313
379
|
);
|
|
314
380
|
block-size: calc(100% - var(--_inset) * 2);
|
|
315
381
|
border: var(--_border-width) solid
|
|
316
382
|
var(
|
|
317
383
|
--slotted-segmented-control-indicator-border-color,
|
|
318
|
-
var(--slotted-
|
|
384
|
+
color-mix(in oklab, var(--slotted-text, CanvasText) 10%, transparent)
|
|
319
385
|
);
|
|
320
386
|
border-radius: var(--_thumb-radius);
|
|
321
|
-
box-shadow: var(--slotted-control-shadow, none);
|
|
387
|
+
box-shadow: var(--slotted-segmented-control-indicator-shadow, var(--slotted-shadow-xs, none));
|
|
322
388
|
box-sizing: border-box;
|
|
323
|
-
inline-size: calc(
|
|
389
|
+
inline-size: calc(
|
|
390
|
+
(100% - var(--_inset) * 2 - var(--_spacing) * (var(--_count) - 1)) / var(--_count)
|
|
391
|
+
);
|
|
324
392
|
inset-block-start: var(--_inset);
|
|
325
393
|
inset-inline-start: var(--_inset);
|
|
326
394
|
pointer-events: none;
|
|
@@ -328,7 +396,7 @@
|
|
|
328
396
|
transition:
|
|
329
397
|
opacity var(--slotted-control-transition-duration) var(--slotted-easing-standard),
|
|
330
398
|
translate var(--_travel) var(--slotted-easing-standard);
|
|
331
|
-
translate: calc(var(--_index) * 100%);
|
|
399
|
+
translate: calc(var(--_index) * (100% + var(--_spacing)));
|
|
332
400
|
z-index: 0;
|
|
333
401
|
|
|
334
402
|
@starting-style {
|
|
@@ -337,14 +405,16 @@
|
|
|
337
405
|
}
|
|
338
406
|
|
|
339
407
|
[data-ui='segmented-control'] [data-part='indicator']:dir(rtl) {
|
|
340
|
-
translate: calc(var(--_index) * -100%);
|
|
408
|
+
translate: calc(var(--_index) * (-100% - var(--_spacing)));
|
|
341
409
|
}
|
|
342
410
|
|
|
343
411
|
[data-ui='segmented-control'][data-part='root'][data-orientation='vertical']
|
|
344
412
|
[data-part='indicator'] {
|
|
345
|
-
block-size: calc(
|
|
413
|
+
block-size: calc(
|
|
414
|
+
(100% - var(--_inset) * 2 - var(--_spacing) * (var(--_count) - 1)) / var(--_count)
|
|
415
|
+
);
|
|
346
416
|
inline-size: calc(100% - var(--_inset) * 2);
|
|
347
|
-
translate: 0 calc(var(--_index) * 100%);
|
|
417
|
+
translate: 0 calc(var(--_index) * (100% + var(--_spacing)));
|
|
348
418
|
}
|
|
349
419
|
|
|
350
420
|
/**
|
|
@@ -356,10 +426,7 @@
|
|
|
356
426
|
* beside it.
|
|
357
427
|
*/
|
|
358
428
|
[data-ui='segmented-control'] [data-part='item'][data-checked] {
|
|
359
|
-
color: var(
|
|
360
|
-
--slotted-segmented-control-checked-color,
|
|
361
|
-
var(--slotted-tone-accent-text, HighlightText)
|
|
362
|
-
);
|
|
429
|
+
color: var(--slotted-segmented-control-checked-color, var(--slotted-text, CanvasText));
|
|
363
430
|
}
|
|
364
431
|
|
|
365
432
|
/* ── Hover and press, held back for every stronger state ──────────────── */
|
|
@@ -376,10 +443,10 @@
|
|
|
376
443
|
[data-ui='segmented-control'][data-part='root']:not([data-readonly])
|
|
377
444
|
[data-part='item']:hover:not([data-disabled]):not([data-checked]):has(
|
|
378
445
|
[data-part='control']:enabled
|
|
379
|
-
) {
|
|
446
|
+
)::after {
|
|
380
447
|
background: var(
|
|
381
448
|
--slotted-segmented-control-hover-background,
|
|
382
|
-
var(--slotted-
|
|
449
|
+
color-mix(in oklab, var(--slotted-text) 5%, transparent)
|
|
383
450
|
);
|
|
384
451
|
}
|
|
385
452
|
|
|
@@ -391,10 +458,10 @@
|
|
|
391
458
|
[data-ui='segmented-control'][data-part='root']:not([data-readonly])
|
|
392
459
|
[data-part='item']:active:not([data-disabled]):not([data-checked]):has(
|
|
393
460
|
[data-part='control']:enabled
|
|
394
|
-
) {
|
|
461
|
+
)::after {
|
|
395
462
|
background: var(
|
|
396
463
|
--slotted-segmented-control-active-background,
|
|
397
|
-
var(--slotted-
|
|
464
|
+
color-mix(in oklab, var(--slotted-text) 9%, transparent)
|
|
398
465
|
);
|
|
399
466
|
transition-duration: var(--slotted-duration-instant);
|
|
400
467
|
}
|
|
@@ -544,7 +611,9 @@
|
|
|
544
611
|
[data-ui='segmented-control'][data-part='root'][data-variant='underline'] [data-part='indicator'],
|
|
545
612
|
[data-ui='segmented-control'][data-part='root'][data-variant='underline']
|
|
546
613
|
[data-part='item']
|
|
547
|
-
+ [data-part='item']::before
|
|
614
|
+
+ [data-part='item']::before,
|
|
615
|
+
[data-ui='segmented-control'][data-part='root'][data-variant='underline']
|
|
616
|
+
[data-part='item']::after {
|
|
548
617
|
display: none;
|
|
549
618
|
}
|
|
550
619
|
|
|
@@ -636,6 +705,16 @@
|
|
|
636
705
|
* ring belongs to a segment and leaves it alone.
|
|
637
706
|
*/
|
|
638
707
|
@media (forced-colors: active) {
|
|
708
|
+
/* The neutral track is a tint, and a tint flattens to Canvas: the edge
|
|
709
|
+
says where the control is, and the thumb's edge says which is chosen. */
|
|
710
|
+
[data-ui='segmented-control'][data-part='root']:not([data-variant='underline']) {
|
|
711
|
+
border-color: ButtonBorder;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
[data-ui='segmented-control'] [data-part='indicator'] {
|
|
715
|
+
border-color: Highlight;
|
|
716
|
+
}
|
|
717
|
+
|
|
639
718
|
[data-ui='segmented-control'][data-part='root'][data-invalid] {
|
|
640
719
|
outline: var(--_invalid-edge-width) solid CanvasText;
|
|
641
720
|
outline-offset: calc(-1 * (var(--_border-width) + var(--_invalid-edge-width)));
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
-
"--slotted-border-subtle",
|
|
3
2
|
"--slotted-border-width-thick",
|
|
4
|
-
"--slotted-control-border-color",
|
|
5
3
|
"--slotted-control-border-width",
|
|
6
4
|
"--slotted-control-font-family",
|
|
7
5
|
"--slotted-control-font-size-lg",
|
|
8
6
|
"--slotted-control-font-size-md",
|
|
9
7
|
"--slotted-control-font-size-sm",
|
|
10
|
-
"--slotted-control-font-weight",
|
|
11
8
|
"--slotted-control-gap-lg",
|
|
12
9
|
"--slotted-control-gap-md",
|
|
13
10
|
"--slotted-control-gap-sm",
|
|
@@ -24,8 +21,6 @@
|
|
|
24
21
|
"--slotted-control-padding-inline-md",
|
|
25
22
|
"--slotted-control-padding-inline-sm",
|
|
26
23
|
"--slotted-control-radius",
|
|
27
|
-
"--slotted-control-shadow",
|
|
28
|
-
"--slotted-control-surface",
|
|
29
24
|
"--slotted-control-transition-duration",
|
|
30
25
|
"--slotted-control-transition-easing",
|
|
31
26
|
"--slotted-disabled-background",
|
|
@@ -39,6 +34,7 @@
|
|
|
39
34
|
"--slotted-focus-ring-offset",
|
|
40
35
|
"--slotted-focus-ring-width",
|
|
41
36
|
"--slotted-font-weight-medium",
|
|
37
|
+
"--slotted-radius-full",
|
|
42
38
|
"--slotted-radius-xs",
|
|
43
39
|
"--slotted-segmented-control-active-background",
|
|
44
40
|
"--slotted-segmented-control-background",
|
|
@@ -49,9 +45,12 @@
|
|
|
49
45
|
"--slotted-segmented-control-disabled-color",
|
|
50
46
|
"--slotted-segmented-control-disabled-indicator-background",
|
|
51
47
|
"--slotted-segmented-control-divider-color",
|
|
48
|
+
"--slotted-segmented-control-font-weight",
|
|
49
|
+
"--slotted-segmented-control-gap",
|
|
52
50
|
"--slotted-segmented-control-hover-background",
|
|
53
51
|
"--slotted-segmented-control-indicator-background",
|
|
54
52
|
"--slotted-segmented-control-indicator-border-color",
|
|
53
|
+
"--slotted-segmented-control-indicator-shadow",
|
|
55
54
|
"--slotted-segmented-control-inset",
|
|
56
55
|
"--slotted-segmented-control-invalid-border-color",
|
|
57
56
|
"--slotted-segmented-control-invalid-edge-width",
|
|
@@ -61,15 +60,12 @@
|
|
|
61
60
|
"--slotted-segmented-control-underline-checked-color",
|
|
62
61
|
"--slotted-segmented-control-underline-color",
|
|
63
62
|
"--slotted-segmented-control-underline-gap",
|
|
63
|
+
"--slotted-shadow-xs",
|
|
64
64
|
"--slotted-space-1",
|
|
65
65
|
"--slotted-space-6",
|
|
66
|
+
"--slotted-surface-raised",
|
|
66
67
|
"--slotted-target-min",
|
|
67
68
|
"--slotted-text",
|
|
68
69
|
"--slotted-text-muted",
|
|
69
|
-
"--slotted-tone-
|
|
70
|
-
"--slotted-tone-accent-subtle-active",
|
|
71
|
-
"--slotted-tone-accent-text",
|
|
72
|
-
"--slotted-tone-danger-border",
|
|
73
|
-
"--slotted-tone-secondary-subtle-active",
|
|
74
|
-
"--slotted-tone-secondary-subtle-hover"
|
|
70
|
+
"--slotted-tone-danger-border"
|
|
75
71
|
]
|
|
@@ -48,6 +48,13 @@
|
|
|
48
48
|
* there is to give.
|
|
49
49
|
*/
|
|
50
50
|
--_standoff: min(var(--slotted-space-2, 0.25rem), var(--_inset));
|
|
51
|
+
/**
|
|
52
|
+
* The inline padding `app-shell`'s navigation parts add for an outward
|
|
53
|
+
* focus ring, read so a row's box keeps the edge it had there: the row
|
|
54
|
+
* reaches back into that padding, and its own ring is drawn inside. Nought
|
|
55
|
+
* outside those parts.
|
|
56
|
+
*/
|
|
57
|
+
--_ring-inset: var(--slotted-app-shell-row-ring-inset, 0px);
|
|
51
58
|
--_gap: var(--slotted-app-shell-row-gap, var(--slotted-control-gap-md, 8px));
|
|
52
59
|
--_font-size: var(--slotted-app-shell-row-font-size, var(--slotted-font-size-sm, 0.8125rem));
|
|
53
60
|
--_line-height: var(--slotted-app-shell-row-line-height, var(--slotted-line-height-sm, 1.45));
|
|
@@ -354,11 +361,11 @@
|
|
|
354
361
|
grid-template-columns: auto minmax(0, 1fr) auto auto;
|
|
355
362
|
grid-template-rows: auto auto;
|
|
356
363
|
margin-block: 0;
|
|
357
|
-
margin-inline: var(--_standoff);
|
|
364
|
+
margin-inline: calc(var(--_standoff) - var(--_ring-inset));
|
|
358
365
|
min-block-size: var(--_row-height);
|
|
359
366
|
min-inline-size: 0;
|
|
360
367
|
padding-block: 0;
|
|
361
|
-
padding-inline: calc(var(--_inset) - var(--_standoff));
|
|
368
|
+
padding-inline: calc(var(--_inset) - var(--_standoff) + var(--_ring-inset));
|
|
362
369
|
position: relative;
|
|
363
370
|
text-align: start;
|
|
364
371
|
text-decoration: none;
|
|
@@ -218,7 +218,7 @@
|
|
|
218
218
|
* number is broken only when it is wider than the card itself. A floor on
|
|
219
219
|
* the trend was tried and pushed the trend through the card's edge.
|
|
220
220
|
*/
|
|
221
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
221
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
222
222
|
:scope [data-part='body'] {
|
|
223
223
|
column-gap: var(--_trend-gap);
|
|
224
224
|
display: grid;
|
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
237
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
238
238
|
:scope[data-layout='stacked'] [data-part='body'] {
|
|
239
239
|
grid-template-areas:
|
|
240
240
|
'header'
|
|
@@ -254,14 +254,14 @@
|
|
|
254
254
|
* inline axis gives these regions no intrinsic width: the figure alone
|
|
255
255
|
* decides the column, and the text is cut or wrapped by the card's width.
|
|
256
256
|
*/
|
|
257
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
257
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
258
258
|
:scope [data-part='header'] {
|
|
259
259
|
contain: inline-size;
|
|
260
260
|
grid-area: header;
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
264
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
265
265
|
:scope [data-part='figure'] {
|
|
266
266
|
align-self: start;
|
|
267
267
|
grid-area: figure;
|
|
@@ -276,7 +276,7 @@
|
|
|
276
276
|
* width is the space a wide value left, which a query on the card cannot
|
|
277
277
|
* see.
|
|
278
278
|
*/
|
|
279
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
279
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
280
280
|
:scope [data-part='trend'] {
|
|
281
281
|
/* The marker's ring is the card's ground, not the page's. */
|
|
282
282
|
--slotted-sparkline-ring-color: var(--_surface);
|
|
@@ -291,21 +291,21 @@
|
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
@container stat-card-trend (max-width: 39px) {
|
|
294
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
294
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
295
295
|
:scope [data-part='trend'] > * {
|
|
296
296
|
visibility: hidden;
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
301
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
302
302
|
:scope[data-layout='stacked'] [data-part='trend'] {
|
|
303
303
|
align-self: end;
|
|
304
304
|
margin-block-start: var(--slotted-space-2, 0.25rem);
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
308
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
309
309
|
:scope [data-part='message'] {
|
|
310
310
|
contain: inline-size;
|
|
311
311
|
grid-area: message;
|
|
@@ -319,7 +319,7 @@
|
|
|
319
319
|
* (`docs/token-foundation.md`, rule 4).
|
|
320
320
|
*/
|
|
321
321
|
@container stat-card (max-width: 219px) {
|
|
322
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
322
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
323
323
|
:scope [data-part='body'] {
|
|
324
324
|
grid-template-areas:
|
|
325
325
|
'header'
|
|
@@ -331,14 +331,14 @@
|
|
|
331
331
|
}
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
334
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
335
335
|
:scope [data-part='trend'] {
|
|
336
336
|
align-self: end;
|
|
337
337
|
margin-block-start: var(--slotted-space-2, 0.25rem);
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
341
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
342
342
|
:scope [data-part='value'] {
|
|
343
343
|
font-size: var(--_value-size-narrow);
|
|
344
344
|
line-height: var(--_value-line-narrow);
|
|
@@ -346,7 +346,7 @@
|
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
/* The value steps down here, and so does the line its placeholder keeps. */
|
|
349
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
349
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
350
350
|
:scope[data-loading] [data-part='value'] {
|
|
351
351
|
min-block-size: calc(var(--_value-size-narrow) * var(--_value-line-narrow));
|
|
352
352
|
}
|
|
@@ -361,7 +361,7 @@
|
|
|
361
361
|
* them as part of the name, instead of floating them at the middle of the
|
|
362
362
|
* block.
|
|
363
363
|
*/
|
|
364
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
364
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
365
365
|
:scope [data-part='header'] {
|
|
366
366
|
align-items: baseline;
|
|
367
367
|
column-gap: var(--slotted-space-3, 0.375rem);
|
|
@@ -381,7 +381,7 @@
|
|
|
381
381
|
* proportion of the type rather than a scale step: it is a width of
|
|
382
382
|
* words, and it scales with them.
|
|
383
383
|
*/
|
|
384
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
384
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
385
385
|
:scope [data-part='label'] {
|
|
386
386
|
color: var(--_ink-muted);
|
|
387
387
|
flex: 1 1 0%;
|
|
@@ -394,7 +394,7 @@
|
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
397
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
398
398
|
:scope [data-part='status'] {
|
|
399
399
|
display: inline-flex;
|
|
400
400
|
flex: none;
|
|
@@ -404,7 +404,7 @@
|
|
|
404
404
|
/* The action takes the end of the header's first line and stays there
|
|
405
405
|
when the label wraps: it is the one thing on the card the reader presses,
|
|
406
406
|
and a corner is where a control is looked for. */
|
|
407
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
407
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
408
408
|
:scope [data-part='action'] {
|
|
409
409
|
flex: none;
|
|
410
410
|
/* The label's line, so a link here is as tall in the fallback face as in
|
|
@@ -420,13 +420,13 @@
|
|
|
420
420
|
part itself when `render` made it one — reaches
|
|
421
421
|
the comfortable size in both axes, and the header keeps its height. */
|
|
422
422
|
@media (pointer: coarse) {
|
|
423
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
423
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
424
424
|
:scope :is([data-part='action']:is(a, button), [data-part='action'] > :is(a, button)) {
|
|
425
425
|
position: relative;
|
|
426
426
|
}
|
|
427
427
|
}
|
|
428
428
|
|
|
429
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
429
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
430
430
|
:scope
|
|
431
431
|
:is([data-part='action']:is(a, button), [data-part='action'] > :is(a, button))::before {
|
|
432
432
|
content: '';
|
|
@@ -444,7 +444,7 @@
|
|
|
444
444
|
* so a delta that does not fit beside a wide number drops under it rather
|
|
445
445
|
* than pushing the number.
|
|
446
446
|
*/
|
|
447
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
447
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
448
448
|
:scope [data-part='figure'] {
|
|
449
449
|
align-items: baseline;
|
|
450
450
|
column-gap: var(--slotted-space-3, 0.375rem);
|
|
@@ -454,7 +454,7 @@
|
|
|
454
454
|
}
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
457
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
458
458
|
:scope [data-part='comparison'] {
|
|
459
459
|
contain: inline-size;
|
|
460
460
|
flex: 1 1 100%;
|
|
@@ -471,7 +471,7 @@
|
|
|
471
471
|
* to pull a large numeral's counters back together, and it is the same
|
|
472
472
|
* fraction at every size.
|
|
473
473
|
*/
|
|
474
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
474
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
475
475
|
:scope [data-part='value'] {
|
|
476
476
|
/* The figure and its unit are two flex items on one baseline — the text
|
|
477
477
|
node is an item of its own — so the gap spaces the unit from the digit
|
|
@@ -502,7 +502,7 @@
|
|
|
502
502
|
|
|
503
503
|
/* The unit is in the value's own line, a step down in size and weight, so
|
|
504
504
|
`$` and `%` read as annotation of the number rather than as digits. */
|
|
505
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
505
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
506
506
|
:scope [data-part='unit'] {
|
|
507
507
|
color: var(--_ink-muted);
|
|
508
508
|
font-size: var(--_delta-size);
|
|
@@ -517,7 +517,7 @@
|
|
|
517
517
|
* metrics, and the tone's text role already clears the reading ratio on
|
|
518
518
|
* the surface. It sits on the value's baseline.
|
|
519
519
|
*/
|
|
520
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
520
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
521
521
|
:scope [data-part='delta'] {
|
|
522
522
|
align-items: center;
|
|
523
523
|
color: var(--_tone-text);
|
|
@@ -535,37 +535,37 @@
|
|
|
535
535
|
}
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
538
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
539
539
|
:scope [data-part='delta'][data-tone='neutral'] {
|
|
540
540
|
--_tone-text: var(--_ink-muted);
|
|
541
541
|
}
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
544
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
545
545
|
:scope [data-part='delta'][data-tone='accent'] {
|
|
546
546
|
--_tone-text: var(--slotted-tone-accent-text);
|
|
547
547
|
}
|
|
548
548
|
}
|
|
549
549
|
|
|
550
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
550
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
551
551
|
:scope [data-part='delta'][data-tone='secondary'] {
|
|
552
552
|
--_tone-text: var(--slotted-tone-secondary-text);
|
|
553
553
|
}
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
556
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
557
557
|
:scope [data-part='delta'][data-tone='success'] {
|
|
558
558
|
--_tone-text: var(--slotted-tone-success-text);
|
|
559
559
|
}
|
|
560
560
|
}
|
|
561
561
|
|
|
562
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
562
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
563
563
|
:scope [data-part='delta'][data-tone='warning'] {
|
|
564
564
|
--_tone-text: var(--slotted-tone-warning-text);
|
|
565
565
|
}
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
568
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
569
569
|
:scope [data-part='delta'][data-tone='danger'] {
|
|
570
570
|
--_tone-text: var(--slotted-tone-danger-text);
|
|
571
571
|
}
|
|
@@ -579,7 +579,7 @@
|
|
|
579
579
|
* change draws `minus`. The binding renders the glyph inside the icon box;
|
|
580
580
|
* the part hands the box its size, and the box inherits the delta's ink.
|
|
581
581
|
*/
|
|
582
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
582
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
583
583
|
:scope [data-part='indicator'] {
|
|
584
584
|
--slotted-icon-size: var(--_indicator-size);
|
|
585
585
|
|
|
@@ -592,7 +592,7 @@
|
|
|
592
592
|
a rise becomes a fall. Time runs from the right in a right-to-left
|
|
593
593
|
document, so the rise points the other way there, as the sparkline beside
|
|
594
594
|
it does — the `directional` icon box the binding draws does that. */
|
|
595
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
595
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
596
596
|
:scope [data-part='delta'][data-trend='down'] [data-part='indicator'] > [data-ui='icon'] {
|
|
597
597
|
rotate: x 180deg;
|
|
598
598
|
}
|
|
@@ -600,7 +600,7 @@
|
|
|
600
600
|
|
|
601
601
|
/* ── Comparison: the prose under the figure ───────────────────────────── */
|
|
602
602
|
|
|
603
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
603
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
604
604
|
:scope [data-part='comparison'] {
|
|
605
605
|
color: var(--_ink-muted);
|
|
606
606
|
font-size: var(--_prose-size);
|
|
@@ -612,7 +612,7 @@
|
|
|
612
612
|
}
|
|
613
613
|
}
|
|
614
614
|
|
|
615
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
615
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
616
616
|
:scope [data-part='period'] {
|
|
617
617
|
color: var(--_ink-muted);
|
|
618
618
|
}
|
|
@@ -628,44 +628,44 @@
|
|
|
628
628
|
* — a card with no delta, or a metric with no valence, draws its trend in
|
|
629
629
|
* the theme's blue and not in grey.
|
|
630
630
|
*/
|
|
631
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
631
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
632
632
|
:scope [data-part='trend'] {
|
|
633
633
|
align-self: center;
|
|
634
634
|
display: flex;
|
|
635
635
|
}
|
|
636
636
|
}
|
|
637
637
|
|
|
638
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
638
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
639
639
|
:scope[data-tone='success'] [data-part='trend'] {
|
|
640
640
|
--slotted-sparkline-color: var(--slotted-tone-success-text);
|
|
641
641
|
}
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
644
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
645
645
|
:scope[data-tone='danger'] [data-part='trend'] {
|
|
646
646
|
--slotted-sparkline-color: var(--slotted-tone-danger-text);
|
|
647
647
|
}
|
|
648
648
|
}
|
|
649
649
|
|
|
650
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
650
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
651
651
|
:scope[data-tone='warning'] [data-part='trend'] {
|
|
652
652
|
--slotted-sparkline-color: var(--slotted-tone-warning-text);
|
|
653
653
|
}
|
|
654
654
|
}
|
|
655
655
|
|
|
656
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
656
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
657
657
|
:scope[data-tone='accent'] [data-part='trend'] {
|
|
658
658
|
--slotted-sparkline-color: var(--slotted-tone-accent-text);
|
|
659
659
|
}
|
|
660
660
|
}
|
|
661
661
|
|
|
662
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
662
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
663
663
|
:scope[data-tone='secondary'] [data-part='trend'] {
|
|
664
664
|
--slotted-sparkline-color: var(--slotted-tone-secondary-text);
|
|
665
665
|
}
|
|
666
666
|
}
|
|
667
667
|
|
|
668
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
668
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
669
669
|
:scope[data-fill='plain'] [data-part='trend'] {
|
|
670
670
|
--slotted-sparkline-ring-color: var(--slotted-surface-raised, Canvas);
|
|
671
671
|
}
|
|
@@ -673,7 +673,7 @@
|
|
|
673
673
|
|
|
674
674
|
/* ── Message: what stands in for a value that is missing or failed ────── */
|
|
675
675
|
|
|
676
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
676
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
677
677
|
:scope [data-part='message'] {
|
|
678
678
|
color: var(--_ink-muted);
|
|
679
679
|
font-size: var(--_prose-size);
|
|
@@ -684,7 +684,7 @@
|
|
|
684
684
|
}
|
|
685
685
|
}
|
|
686
686
|
|
|
687
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
687
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
688
688
|
:scope[data-status='error'] [data-part='message'] {
|
|
689
689
|
color: var(--slotted-tone-danger-text);
|
|
690
690
|
}
|
|
@@ -692,7 +692,7 @@
|
|
|
692
692
|
|
|
693
693
|
/* A value that is not there is a dash in the muted step, at the value's
|
|
694
694
|
own size, so the row keeps its height and its rhythm. */
|
|
695
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
695
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
696
696
|
:scope[data-status='empty'] [data-part='value'],
|
|
697
697
|
:scope[data-status='error'] [data-part='value'] {
|
|
698
698
|
color: var(--_ink-muted);
|
|
@@ -716,13 +716,13 @@
|
|
|
716
716
|
* arrived. The floor is one line of the value's own type, so the two states
|
|
717
717
|
* occupy the same box.
|
|
718
718
|
*/
|
|
719
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
719
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
720
720
|
:scope[data-loading] [data-part='value'] {
|
|
721
721
|
min-block-size: calc(var(--_value-size) * var(--_value-line));
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
724
|
|
|
725
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
725
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
726
726
|
:scope[data-loading] [data-part='trend'] {
|
|
727
727
|
--slotted-skeleton-block-size: var(
|
|
728
728
|
--slotted-sparkline-block-size,
|
|
@@ -731,7 +731,7 @@
|
|
|
731
731
|
}
|
|
732
732
|
}
|
|
733
733
|
|
|
734
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
734
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
735
735
|
:scope[data-loading][data-size='sm'] [data-part='trend'] {
|
|
736
736
|
--slotted-skeleton-block-size: var(
|
|
737
737
|
--slotted-sparkline-block-size-sm,
|
|
@@ -740,7 +740,7 @@
|
|
|
740
740
|
}
|
|
741
741
|
}
|
|
742
742
|
|
|
743
|
-
@scope ([data-ui='stat-card']) to ([data-ui]
|
|
743
|
+
@scope ([data-ui='stat-card']) to (:scope [data-ui] > *) {
|
|
744
744
|
:scope[data-loading][data-size='lg'] [data-part='trend'] {
|
|
745
745
|
--slotted-skeleton-block-size: var(
|
|
746
746
|
--slotted-sparkline-block-size-lg,
|
package/src/tabs/tabs.css
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
/**
|
|
51
51
|
* The marker: one bar the list draws under the selected tab, and the hover
|
|
52
52
|
* bar under the tab the pointer is on, in the same geometry — the tab's
|
|
53
|
-
* content box, a pill
|
|
53
|
+
* content box, a pill just above the list's edge. It is never thinner than the
|
|
54
54
|
* thick border width, the floor the high-contrast scheme keeps for a mark
|
|
55
55
|
* that carries state, and its thickness, its rounding and its inset are
|
|
56
56
|
* tokens of their own: tied to the thick border width, a theme could not
|
|
@@ -62,6 +62,13 @@
|
|
|
62
62
|
);
|
|
63
63
|
--_marker-radius: var(--slotted-tabs-marker-radius, var(--slotted-radius-full, 9999px));
|
|
64
64
|
--_marker-inset: var(--slotted-tabs-marker-inset, var(--_padding-inline));
|
|
65
|
+
/**
|
|
66
|
+
* The gap between the bars and the list's edge: the selected marker and the
|
|
67
|
+
* hover bar stand this far above the track, so the line reads as a line and
|
|
68
|
+
* the bar as a mark on it. An inset rather than a transform, because the
|
|
69
|
+
* marker's `translate` is its slide between tabs.
|
|
70
|
+
*/
|
|
71
|
+
--_marker-offset: var(--slotted-tabs-marker-offset, 1px);
|
|
65
72
|
--_track-color: var(--slotted-tabs-track-color, var(--slotted-border-subtle, ButtonBorder));
|
|
66
73
|
/**
|
|
67
74
|
* The length of the fade a scrolling list takes at an edge that has more
|
|
@@ -460,8 +467,8 @@
|
|
|
460
467
|
* `--slotted-tabs-marker-inset`, which defaults to the tab's own inline
|
|
461
468
|
* padding, and never the closing control: a tab followed by one gives up its
|
|
462
469
|
* end padding, so the end inset is nought there. Below the width of a short
|
|
463
|
-
* label it keeps a minimum length, centred on the content. It stands
|
|
464
|
-
* list's edge, over the track, and the axes are physical in this one rule
|
|
470
|
+
* label it keeps a minimum length, centred on the content. It stands
|
|
471
|
+
* `--slotted-tabs-marker-offset` above the list's edge, over the track, and the axes are physical in this one rule
|
|
465
472
|
* because the measurement is: the translate is from the list's left edge.
|
|
466
473
|
*/
|
|
467
474
|
[data-ui='tabs'] > :where([data-part='list']) > [data-part='marker'] {
|
|
@@ -475,7 +482,7 @@
|
|
|
475
482
|
block-size: var(--_marker-size);
|
|
476
483
|
border-radius: var(--_marker-radius);
|
|
477
484
|
inline-size: var(--_length);
|
|
478
|
-
inset-block-end: var(--_marker-lift, 0px);
|
|
485
|
+
inset-block-end: calc(var(--_marker-lift, 0px) + var(--_marker-offset));
|
|
479
486
|
left: 0;
|
|
480
487
|
pointer-events: none;
|
|
481
488
|
position: absolute;
|
|
@@ -500,20 +507,26 @@
|
|
|
500
507
|
}
|
|
501
508
|
|
|
502
509
|
/**
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
510
|
+
* It slides only when the selection moves: `data-moving` arrives with a
|
|
511
|
+
* position whose tab changed, and leaves with a re-measurement of the same
|
|
512
|
+
* tab, so the first position, a font arriving and a resized list place the
|
|
513
|
+
* bar without motion. The slide takes the medium duration on a curve that
|
|
514
|
+
* starts and ends slowly, `--slotted-tabs-marker-easing`: the control
|
|
515
|
+
* duration on the theme's decelerating curve covered a third of the
|
|
516
|
+
* distance in its first frame and read as a jump. Under reduced motion it
|
|
517
|
+
* jumps.
|
|
506
518
|
*/
|
|
507
|
-
[data-ui='tabs'] > :where([data-part='list']) > [data-part='marker'][data-
|
|
519
|
+
[data-ui='tabs'] > :where([data-part='list']) > [data-part='marker'][data-moving] {
|
|
520
|
+
--_marker-easing: var(--slotted-tabs-marker-easing, cubic-bezier(0.4, 0, 0.2, 1));
|
|
521
|
+
|
|
508
522
|
transition:
|
|
509
|
-
translate var(--slotted-
|
|
510
|
-
inline-size var(--slotted-
|
|
511
|
-
|
|
512
|
-
block-size var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
|
|
523
|
+
translate var(--slotted-duration-medium) var(--_marker-easing),
|
|
524
|
+
inline-size var(--slotted-duration-medium) var(--_marker-easing),
|
|
525
|
+
block-size var(--slotted-duration-medium) var(--_marker-easing);
|
|
513
526
|
}
|
|
514
527
|
|
|
515
528
|
@media (prefers-reduced-motion: reduce) {
|
|
516
|
-
[data-ui='tabs'] > :where([data-part='list']) > [data-part='marker'][data-
|
|
529
|
+
[data-ui='tabs'] > :where([data-part='list']) > [data-part='marker'][data-moving] {
|
|
517
530
|
transition: none;
|
|
518
531
|
}
|
|
519
532
|
}
|
|
@@ -532,7 +545,7 @@
|
|
|
532
545
|
block-size: var(--_marker-size);
|
|
533
546
|
border-radius: var(--_marker-radius);
|
|
534
547
|
content: '';
|
|
535
|
-
inset-block-end: calc(-
|
|
548
|
+
inset-block-end: calc(var(--_marker-offset) - var(--_track-reach, 0px));
|
|
536
549
|
inset-inline: var(--_marker-inset);
|
|
537
550
|
min-inline-size: var(--slotted-space-6, 1rem);
|
|
538
551
|
opacity: 0;
|
|
@@ -578,7 +591,7 @@
|
|
|
578
591
|
block-size: var(--_length);
|
|
579
592
|
inline-size: var(--_marker-size);
|
|
580
593
|
inset-block: 0 auto;
|
|
581
|
-
inset-inline: auto var(--_marker-lift, 0px);
|
|
594
|
+
inset-inline: auto calc(var(--_marker-lift, 0px) + var(--_marker-offset));
|
|
582
595
|
translate: 0
|
|
583
596
|
calc(var(--_indicator-start, 0px) + var(--_start-inset) + (var(--_span) - var(--_length)) / 2);
|
|
584
597
|
}
|
|
@@ -589,7 +602,7 @@
|
|
|
589
602
|
block-size: auto;
|
|
590
603
|
inline-size: var(--_marker-size);
|
|
591
604
|
inset-block: var(--_marker-inset);
|
|
592
|
-
inset-inline: auto calc(-
|
|
605
|
+
inset-inline: auto calc(var(--_marker-offset) - var(--_track-reach, 0px));
|
|
593
606
|
min-block-size: var(--slotted-space-6, 1rem);
|
|
594
607
|
min-inline-size: 0;
|
|
595
608
|
}
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"--slotted-disabled-background",
|
|
32
32
|
"--slotted-disabled-border",
|
|
33
33
|
"--slotted-disabled-foreground",
|
|
34
|
+
"--slotted-duration-medium",
|
|
34
35
|
"--slotted-duration-short",
|
|
35
36
|
"--slotted-easing-enter",
|
|
36
37
|
"--slotted-focus-ring-color",
|
|
@@ -65,7 +66,9 @@
|
|
|
65
66
|
"--slotted-tabs-hover-marker-opacity",
|
|
66
67
|
"--slotted-tabs-list-gap",
|
|
67
68
|
"--slotted-tabs-marker-color",
|
|
69
|
+
"--slotted-tabs-marker-easing",
|
|
68
70
|
"--slotted-tabs-marker-inset",
|
|
71
|
+
"--slotted-tabs-marker-offset",
|
|
69
72
|
"--slotted-tabs-marker-radius",
|
|
70
73
|
"--slotted-tabs-marker-size",
|
|
71
74
|
"--slotted-tabs-scroll-color",
|