contain-css-svelte 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Card.svelte +12 -0
- package/dist/controls/Button.svelte +12 -0
- package/dist/controls/ButtonLink.svelte +12 -0
- package/dist/controls/Checkbox.svelte +12 -0
- package/dist/controls/CircleButton.svelte +12 -0
- package/dist/controls/Input.svelte +12 -0
- package/dist/controls/RadioButton.svelte +12 -0
- package/dist/controls/Select.svelte +12 -0
- package/dist/controls/Slider.svelte +12 -0
- package/dist/controls/TabItem.svelte +12 -0
- package/dist/controls/Toggle.svelte +12 -0
- package/dist/dropdowns/DropdownMenu.svelte +12 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/layout/Accordion.svelte +12 -0
- package/dist/layout/Bar.svelte +12 -0
- package/dist/layout/ColumnContainer.svelte +12 -0
- package/dist/layout/Columns.svelte +12 -0
- package/dist/layout/Container.svelte +12 -0
- package/dist/layout/DataList.svelte +12 -0
- package/dist/layout/DataListItem.svelte +12 -0
- package/dist/layout/Fieldset.svelte +12 -0
- package/dist/layout/Form.svelte +12 -0
- package/dist/layout/FormItem.svelte +12 -0
- package/dist/layout/GridLayout.svelte +12 -0
- package/dist/layout/Hero.svelte +12 -0
- package/dist/layout/Inline.svelte +12 -0
- package/dist/layout/MenuList.svelte +12 -0
- package/dist/layout/Page.svelte +17 -1
- package/dist/layout/RowContainer.svelte +12 -0
- package/dist/layout/Sidebar.svelte +516 -57
- package/dist/layout/Sidebar.svelte.d.ts +24 -1
- package/dist/layout/SidebarContainer.svelte +172 -0
- package/dist/layout/SidebarContainer.svelte.d.ts +20 -0
- package/dist/layout/SplitPane.svelte +12 -0
- package/dist/layout/Stack.svelte +12 -0
- package/dist/layout/TabBar.svelte +12 -0
- package/dist/layout/Table.svelte +233 -151
- package/dist/layout/Tile.svelte +12 -0
- package/dist/misc/CodeInner.svelte +12 -0
- package/dist/misc/Progress.svelte +12 -0
- package/dist/misc/Tag.svelte +12 -0
- package/dist/overlays/Dialog.svelte +12 -0
- package/dist/overlays/Tooltip.svelte +12 -0
- package/dist/sass/_responsive.scss +15 -0
- package/dist/typography/TextLayout.svelte +12 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">import { elementProps } from "../util";
|
|
2
2
|
import { COLOR_VARS, TYPOGRAPHY_VARS, } from "../styleProps";
|
|
3
|
-
let { left, right, children, expandLabel = "Expand sidebar", collapseLabel = "Collapse sidebar", class: className, ...restProps } = $props();
|
|
3
|
+
let { left, right, children, overlay = false, open = $bindable(undefined), expandLabel = "Expand sidebar", collapseLabel = "Collapse sidebar", class: className, ...restProps } = $props();
|
|
4
4
|
/* The shorthands sidebar's own CSS backs, one group per mixin it
|
|
5
5
|
includes. The Props type is derived from this same array, so what the
|
|
6
6
|
component accepts and what it emits cannot drift apart. */
|
|
@@ -12,14 +12,22 @@ const el = $derived(elementProps(restProps, "sidebar", [
|
|
|
12
12
|
...SIDEBAR_VARS,
|
|
13
13
|
"width",
|
|
14
14
|
]));
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
/* One piece of state, two layouts. The wide rail and the compact sheet
|
|
16
|
+
disagree about what "untouched" should look like -- the rail starts open,
|
|
17
|
+
the sheet starts closed -- so `undefined` stands for "this layout's
|
|
18
|
+
default" and each layout resolves it its own way. The moment anything
|
|
19
|
+
(either built-in toggle, or a caller through `bind:open`) writes a
|
|
20
|
+
boolean, both layouts read that same boolean, which is what keeps
|
|
21
|
+
programmatic control and the internal toggles in sync. */
|
|
22
|
+
const expandedBar = $derived(open ?? true);
|
|
23
|
+
const expandedHamburger = $derived(open ?? false);
|
|
17
24
|
</script>
|
|
18
25
|
|
|
19
26
|
<aside
|
|
20
27
|
class={["sidebar", className]}
|
|
21
28
|
class:right
|
|
22
29
|
class:left
|
|
30
|
+
class:overlay
|
|
23
31
|
class:expandedHamburger
|
|
24
32
|
class:expandedBar
|
|
25
33
|
{...el}
|
|
@@ -28,19 +36,21 @@ let expandedBar = $state(true);
|
|
|
28
36
|
class:expander={!expandedHamburger}
|
|
29
37
|
class:close={expandedHamburger}
|
|
30
38
|
aria-label={expandedHamburger ? collapseLabel : expandLabel}
|
|
39
|
+
aria-expanded={expandedHamburger}
|
|
31
40
|
data-audit-action="toggle-sidebar-sheet"
|
|
32
|
-
onclick={() => (
|
|
41
|
+
onclick={() => (open = !expandedHamburger)}
|
|
33
42
|
></button>
|
|
34
43
|
<div class="content">
|
|
35
44
|
{@render children?.()}
|
|
36
45
|
</div>
|
|
37
46
|
<label class="edge-bar">
|
|
38
47
|
<button
|
|
39
|
-
onclick={() => (
|
|
48
|
+
onclick={() => (open = !expandedBar)}
|
|
40
49
|
class="expander"
|
|
41
50
|
class:expander={!expandedBar}
|
|
42
51
|
class:close={expandedBar}
|
|
43
|
-
aria-label={expandedBar ?
|
|
52
|
+
aria-label={expandedBar ? collapseLabel : expandLabel}
|
|
53
|
+
aria-expanded={expandedBar}
|
|
44
54
|
data-audit-action="toggle-sidebar-rail"
|
|
45
55
|
></button>
|
|
46
56
|
</label>
|
|
@@ -55,6 +65,18 @@ let expandedBar = $state(true);
|
|
|
55
65
|
day this mixin got added to a new component. Callers opt in with an actual
|
|
56
66
|
value. (Container does not use this mixin: it wants --gap/auto as its
|
|
57
67
|
defaults, which do not fit the "0 unless asked" contract here.) */
|
|
68
|
+
/* The width at or below which a Sidebar swaps its grab-bar rail for the sheet
|
|
69
|
+
affordance -- a floating button that opens a panel over the content.
|
|
70
|
+
|
|
71
|
+
Page has to agree with Sidebar about this, because Page is what floats the
|
|
72
|
+
aside out of flow and reserves the strip of padding the sheet button sits
|
|
73
|
+
in. They used to disagree: Sidebar switched at 512px and Page at 600px,
|
|
74
|
+
which left a band between 513 and 600 where Page had already lifted the
|
|
75
|
+
aside out of the layout while the Sidebar inside it was still showing a
|
|
76
|
+
rail -- a grab bar floating on top of the content, which is the affordance
|
|
77
|
+
we deliberately avoid everywhere else.
|
|
78
|
+
|
|
79
|
+
One definition, used by both, so they cannot drift again. */
|
|
58
80
|
/* Warning: because we define a fallback
|
|
59
81
|
media query, the media query can override the container
|
|
60
82
|
if we stack a bunch of these in a row and aren't thoughtful about the order.
|
|
@@ -294,38 +316,392 @@ aside .content:hover::-webkit-scrollbar-thumb:hover {
|
|
|
294
316
|
}
|
|
295
317
|
|
|
296
318
|
/* Expander doo-dad */
|
|
319
|
+
/* The sheet affordance: a floating panel you summon with a button and
|
|
320
|
+
dismiss when you are done with it.
|
|
321
|
+
|
|
322
|
+
Used by the compact layout, and by `overlay` at any width. Overlay wants
|
|
323
|
+
this rather than the rail: a panel that starts open on top of the content
|
|
324
|
+
is nonsense, and a grab-bar rail floating over the content is a strange
|
|
325
|
+
thing to ask anyone to grab. A button that opens a sheet is the
|
|
326
|
+
affordance people already know.
|
|
327
|
+
|
|
328
|
+
It keys on .expandedHamburger, which resolves `undefined` to false -- so
|
|
329
|
+
a sheet starts shut, where the rail starts open. That falls out of the
|
|
330
|
+
shared `open` state for free. */
|
|
297
331
|
/* Responsive sidebar... */
|
|
298
332
|
@container (min-width: 513px) {
|
|
299
|
-
/*
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
aside {
|
|
333
|
+
/* The rail layout. Everything here is scoped away from `overlay`, which
|
|
334
|
+
uses the sheet affordance at every width instead. */
|
|
335
|
+
aside:not(.overlay) {
|
|
303
336
|
transition: width var(--sidebar-transition);
|
|
304
337
|
position: relative;
|
|
305
338
|
height: 100%;
|
|
306
339
|
width: var(--grab-bar-width);
|
|
307
340
|
}
|
|
308
|
-
aside.expandedBar {
|
|
341
|
+
aside:not(.overlay).expandedBar {
|
|
309
342
|
width: calc(var(--sidebar-width) + var(--grab-bar-width));
|
|
310
343
|
}
|
|
311
|
-
aside .content {
|
|
344
|
+
aside:not(.overlay) .content {
|
|
312
345
|
transition: transform var(--sidebar-transition);
|
|
313
346
|
transform: translateX(-110%);
|
|
314
347
|
}
|
|
315
|
-
aside.right .content {
|
|
348
|
+
aside:not(.overlay).right .content {
|
|
316
349
|
transform: translateX(100%);
|
|
317
350
|
}
|
|
318
|
-
|
|
319
|
-
aside.expandedBar .content {
|
|
351
|
+
aside:not(.overlay).expandedBar .content {
|
|
320
352
|
transform: translateX(0);
|
|
321
353
|
position: absolute;
|
|
322
354
|
top: 0;
|
|
323
355
|
left: 0;
|
|
324
356
|
width: var(--sidebar-width);
|
|
325
357
|
}
|
|
326
|
-
aside.expandedBar.right .content {
|
|
358
|
+
aside:not(.overlay).expandedBar.right .content {
|
|
359
|
+
left: auto;
|
|
360
|
+
right: 0;
|
|
361
|
+
}
|
|
362
|
+
aside.overlay {
|
|
363
|
+
/* The sheet and its button are absolutely positioned, so the sidebar has
|
|
364
|
+
to be their containing block. Without this they resolve against
|
|
365
|
+
whatever positioned ancestor happens to be up the tree -- inside <Page>
|
|
366
|
+
that is Page's own aside and it looks fine, but drop a Sidebar into a
|
|
367
|
+
Card or a Container and the button escapes to the top-left of the page,
|
|
368
|
+
over unrelated content.
|
|
369
|
+
|
|
370
|
+
`overflow` has to be released in the same breath. Every child here is
|
|
371
|
+
out of flow, so the aside computes to zero height -- harmless while it
|
|
372
|
+
was not a containing block, but the moment it becomes one the inherited
|
|
373
|
+
`overflow: hidden` clips the button and the sheet away to nothing.
|
|
374
|
+
Nothing needs clipping here: the shut sheet is hidden by opacity and
|
|
375
|
+
pointer-events, not by the box. */
|
|
376
|
+
/* Sized here rather than on the button, because the panel needs them too
|
|
377
|
+
-- see the padding it reserves below. */
|
|
378
|
+
--_sidebar-expander-width: max(
|
|
379
|
+
var(--sidebar-icon-width, 0.65rem),
|
|
380
|
+
var(--icon-size, 32px)
|
|
381
|
+
);
|
|
382
|
+
--_sidebar-expander-height: max(
|
|
383
|
+
var(--sidebar-icon-height, 1rem),
|
|
384
|
+
var(--icon-size, 32px)
|
|
385
|
+
);
|
|
386
|
+
position: relative;
|
|
387
|
+
overflow: visible;
|
|
388
|
+
background: transparent;
|
|
389
|
+
width: calc(var(--gap) + max(var(--sidebar-icon-width, 0.65rem), var(--icon-size, 32px)));
|
|
390
|
+
flex: 0 0 auto;
|
|
391
|
+
/* Every child is out of flow, so the aside has no content to hold it
|
|
392
|
+
open and the base `height: 100%` resolves against an auto-height
|
|
393
|
+
parent -- which is to say, nothing. Stretch to the row instead, so the
|
|
394
|
+
aside is as tall as whatever it sits beside, and the open sheet's own
|
|
395
|
+
`height: 100%` has something real to measure against. */
|
|
396
|
+
height: auto;
|
|
397
|
+
align-self: stretch;
|
|
398
|
+
}
|
|
399
|
+
aside.overlay .edge-bar {
|
|
400
|
+
display: none;
|
|
401
|
+
}
|
|
402
|
+
aside.overlay.right, aside.overlay.left {
|
|
403
|
+
border-left: none;
|
|
404
|
+
border-right: none;
|
|
405
|
+
}
|
|
406
|
+
aside.overlay > .content {
|
|
407
|
+
position: absolute;
|
|
408
|
+
top: 0;
|
|
409
|
+
left: 0;
|
|
410
|
+
width: var(--sidebar-width);
|
|
411
|
+
z-index: 2;
|
|
412
|
+
transform: translateX(-100%);
|
|
413
|
+
opacity: 0;
|
|
414
|
+
background: transparent;
|
|
415
|
+
pointer-events: none;
|
|
416
|
+
transition: transform var(--sidebar-transition) ease-in-out, opacity var(--sidebar-transition) ease-in-out;
|
|
417
|
+
padding: var(--padding);
|
|
418
|
+
/* The close button floats over the panel's inner edge, so the panel has
|
|
419
|
+
to keep that strip clear or the first nav item sits underneath it.
|
|
420
|
+
|
|
421
|
+
Reserved on the inline axis, not the block one: a nav wants the full
|
|
422
|
+
height, and a blank band across the top of it to clear one button is
|
|
423
|
+
a poor trade. The cost is that the whole column is a button's width
|
|
424
|
+
narrower, even well below the button -- override
|
|
425
|
+
--sidebar-sheet-content-inset to 0 and set your own padding if you
|
|
426
|
+
would rather have the width back. */
|
|
427
|
+
padding-inline-end: var(--sidebar-sheet-content-inset, calc(var(--padding) + var(--_sidebar-expander-width)));
|
|
428
|
+
}
|
|
429
|
+
aside.overlay.left > .content {
|
|
430
|
+
border-right: var(--border-width) var(--border-style) var(--border-color);
|
|
431
|
+
}
|
|
432
|
+
aside.overlay {
|
|
433
|
+
/* A right-hand sheet slides out of the right edge, not the left -- and
|
|
434
|
+
its button lands on the panel's left edge, so the reserved strip
|
|
435
|
+
mirrors with it. */
|
|
436
|
+
}
|
|
437
|
+
aside.overlay.right > .content {
|
|
327
438
|
left: auto;
|
|
328
439
|
right: 0;
|
|
440
|
+
transform: translateX(100%);
|
|
441
|
+
border-left: var(--border-width) var(--border-style) var(--border-color);
|
|
442
|
+
padding-inline-end: var(--padding);
|
|
443
|
+
padding-inline-start: var(--sidebar-sheet-content-inset, calc(var(--padding) + var(--_sidebar-expander-width)));
|
|
444
|
+
}
|
|
445
|
+
aside.overlay.expandedHamburger > .content {
|
|
446
|
+
transform: translateX(0);
|
|
447
|
+
height: 100%;
|
|
448
|
+
opacity: 1;
|
|
449
|
+
pointer-events: all;
|
|
450
|
+
box-shadow: var(--sidebar-overlay-box-shadow, var(--overlay-box-shadow, 0 0 var(--space, 8px) rgba(127, 127, 127, 0.4)));
|
|
451
|
+
--link-bg: var(--sidebar-link-bg, var(--surface-link-bg, inherit));
|
|
452
|
+
--link-fg: var(--sidebar-link-fg, var(--surface-link-fg, inherit));
|
|
453
|
+
--_bg-mix-color: var(--sidebar-bg-mix-color, var(--surface-bg-mix-color, var(--bg-mix-color, transparent)));
|
|
454
|
+
--_bg-mix-amount: var(--sidebar-bg-mix-amount, var(--surface-bg-mix-amount, var(--bg-mix-amount, 0%)));
|
|
455
|
+
--_fg-mix-color: var(--sidebar-fg-mix-color, var(--surface-fg-mix-color, var(--fg-mix-color, transparent)));
|
|
456
|
+
--_fg-mix-amount: var(--sidebar-fg-mix-amount, var(--surface-fg-mix-amount, var(--fg-mix-amount, 0%)));
|
|
457
|
+
--_bg-base: var(--sidebar-bg, var(--surface-bg, var(--bg, unset)));
|
|
458
|
+
--_fg-base: var(--sidebar-fg, var(--surface-fg, var(--fg, unset)));
|
|
459
|
+
--_background-color: color-mix(
|
|
460
|
+
in srgb,
|
|
461
|
+
var(--_bg-base),
|
|
462
|
+
var(--_bg-mix-color) var(--_bg-mix-amount)
|
|
463
|
+
);
|
|
464
|
+
--_color: color-mix(
|
|
465
|
+
in srgb,
|
|
466
|
+
var(--_fg-base),
|
|
467
|
+
var(--_fg-mix-color) var(--_fg-mix-amount)
|
|
468
|
+
);
|
|
469
|
+
--muted-color: var(--muted-color-override, var(--_background-color));
|
|
470
|
+
--primary-text-fg: var(
|
|
471
|
+
--primary-text-fg-override,
|
|
472
|
+
color-mix(
|
|
473
|
+
in srgb,
|
|
474
|
+
var(--_color),
|
|
475
|
+
var(--primary-color)
|
|
476
|
+
var(--primary-text-amount, var(--text-amount, 50%))
|
|
477
|
+
)
|
|
478
|
+
);
|
|
479
|
+
--secondary-text-fg: var(
|
|
480
|
+
--secondary-text-fg-override,
|
|
481
|
+
color-mix(
|
|
482
|
+
in srgb,
|
|
483
|
+
var(--_color),
|
|
484
|
+
var(--secondary-color)
|
|
485
|
+
var(--secondary-text-amount, var(--text-amount, 50%))
|
|
486
|
+
)
|
|
487
|
+
);
|
|
488
|
+
--info-text-fg: var(
|
|
489
|
+
--info-text-fg-override,
|
|
490
|
+
color-mix(
|
|
491
|
+
in srgb,
|
|
492
|
+
var(--_color),
|
|
493
|
+
var(--info-color)
|
|
494
|
+
var(--info-text-amount, var(--text-amount, 50%))
|
|
495
|
+
)
|
|
496
|
+
);
|
|
497
|
+
--success-text-fg: var(
|
|
498
|
+
--success-text-fg-override,
|
|
499
|
+
color-mix(
|
|
500
|
+
in srgb,
|
|
501
|
+
var(--_color),
|
|
502
|
+
var(--success-color)
|
|
503
|
+
var(--success-text-amount, var(--text-amount, 50%))
|
|
504
|
+
)
|
|
505
|
+
);
|
|
506
|
+
--warning-text-fg: var(
|
|
507
|
+
--warning-text-fg-override,
|
|
508
|
+
color-mix(
|
|
509
|
+
in srgb,
|
|
510
|
+
var(--_color),
|
|
511
|
+
var(--warning-color)
|
|
512
|
+
var(--warning-text-amount, var(--text-amount, 50%))
|
|
513
|
+
)
|
|
514
|
+
);
|
|
515
|
+
--danger-text-fg: var(
|
|
516
|
+
--danger-text-fg-override,
|
|
517
|
+
color-mix(
|
|
518
|
+
in srgb,
|
|
519
|
+
var(--_color),
|
|
520
|
+
var(--danger-color)
|
|
521
|
+
var(--danger-text-amount, var(--text-amount, 50%))
|
|
522
|
+
)
|
|
523
|
+
);
|
|
524
|
+
--muted-text-fg: var(
|
|
525
|
+
--muted-text-fg-override,
|
|
526
|
+
color-mix(
|
|
527
|
+
in srgb,
|
|
528
|
+
var(--_color),
|
|
529
|
+
var(--muted-color)
|
|
530
|
+
var(--muted-text-amount, var(--text-amount, 50%))
|
|
531
|
+
)
|
|
532
|
+
);
|
|
533
|
+
background-color: var(--_background-color);
|
|
534
|
+
color: var(--_color);
|
|
535
|
+
}
|
|
536
|
+
aside.overlay > button {
|
|
537
|
+
transition: left var(--sidebar-transition);
|
|
538
|
+
transform: translateX(0);
|
|
539
|
+
z-index: 3;
|
|
540
|
+
position: absolute;
|
|
541
|
+
opacity: 1;
|
|
542
|
+
pointer-events: all;
|
|
543
|
+
display: block;
|
|
544
|
+
top: var(--padding);
|
|
545
|
+
left: 0;
|
|
546
|
+
border-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
547
|
+
border-top-left-radius: 0;
|
|
548
|
+
border-bottom-left-radius: 0;
|
|
549
|
+
border: var(--circle-button-border, var(--mini-button-border));
|
|
550
|
+
width: var(--_sidebar-expander-width);
|
|
551
|
+
height: var(--_sidebar-expander-height);
|
|
552
|
+
--link-bg: var(--circle-button-link-bg, var(--mini-button-link-bg, var(--button-link-bg, var(--control-link-bg, var(--secondary-link-bg, inherit)))));
|
|
553
|
+
--link-fg: var(--circle-button-link-fg, var(--mini-button-link-fg, var(--button-link-fg, var(--control-link-fg, var(--secondary-link-fg, inherit)))));
|
|
554
|
+
--_bg-mix-color: var(--circle-button-bg-mix-color, var(--mini-button-bg-mix-color, var(--button-bg-mix-color, var(--control-bg-mix-color, var(--secondary-bg-mix-color, var(--bg-mix-color, transparent))))));
|
|
555
|
+
--_bg-mix-amount: var(--circle-button-bg-mix-amount, var(--mini-button-bg-mix-amount, var(--button-bg-mix-amount, var(--control-bg-mix-amount, var(--secondary-bg-mix-amount, var(--bg-mix-amount, 0%))))));
|
|
556
|
+
--_fg-mix-color: var(--circle-button-fg-mix-color, var(--mini-button-fg-mix-color, var(--button-fg-mix-color, var(--control-fg-mix-color, var(--secondary-fg-mix-color, var(--fg-mix-color, transparent))))));
|
|
557
|
+
--_fg-mix-amount: var(--circle-button-fg-mix-amount, var(--mini-button-fg-mix-amount, var(--button-fg-mix-amount, var(--control-fg-mix-amount, var(--secondary-fg-mix-amount, var(--fg-mix-amount, 0%))))));
|
|
558
|
+
--_bg-base: var(--circle-button-bg, var(--mini-button-bg, var(--button-bg, var(--control-bg, var(--secondary-bg, var(--bg, unset))))));
|
|
559
|
+
--_fg-base: var(--circle-button-fg, var(--mini-button-fg, var(--button-fg, var(--control-fg, var(--secondary-fg, var(--fg, unset))))));
|
|
560
|
+
--_background-color: color-mix(
|
|
561
|
+
in srgb,
|
|
562
|
+
var(--_bg-base),
|
|
563
|
+
var(--_bg-mix-color) var(--_bg-mix-amount)
|
|
564
|
+
);
|
|
565
|
+
--_color: color-mix(
|
|
566
|
+
in srgb,
|
|
567
|
+
var(--_fg-base),
|
|
568
|
+
var(--_fg-mix-color) var(--_fg-mix-amount)
|
|
569
|
+
);
|
|
570
|
+
--muted-color: var(--muted-color-override, var(--_background-color));
|
|
571
|
+
--primary-text-fg: var(
|
|
572
|
+
--primary-text-fg-override,
|
|
573
|
+
color-mix(
|
|
574
|
+
in srgb,
|
|
575
|
+
var(--_color),
|
|
576
|
+
var(--primary-color)
|
|
577
|
+
var(--primary-text-amount, var(--text-amount, 50%))
|
|
578
|
+
)
|
|
579
|
+
);
|
|
580
|
+
--secondary-text-fg: var(
|
|
581
|
+
--secondary-text-fg-override,
|
|
582
|
+
color-mix(
|
|
583
|
+
in srgb,
|
|
584
|
+
var(--_color),
|
|
585
|
+
var(--secondary-color)
|
|
586
|
+
var(--secondary-text-amount, var(--text-amount, 50%))
|
|
587
|
+
)
|
|
588
|
+
);
|
|
589
|
+
--info-text-fg: var(
|
|
590
|
+
--info-text-fg-override,
|
|
591
|
+
color-mix(
|
|
592
|
+
in srgb,
|
|
593
|
+
var(--_color),
|
|
594
|
+
var(--info-color)
|
|
595
|
+
var(--info-text-amount, var(--text-amount, 50%))
|
|
596
|
+
)
|
|
597
|
+
);
|
|
598
|
+
--success-text-fg: var(
|
|
599
|
+
--success-text-fg-override,
|
|
600
|
+
color-mix(
|
|
601
|
+
in srgb,
|
|
602
|
+
var(--_color),
|
|
603
|
+
var(--success-color)
|
|
604
|
+
var(--success-text-amount, var(--text-amount, 50%))
|
|
605
|
+
)
|
|
606
|
+
);
|
|
607
|
+
--warning-text-fg: var(
|
|
608
|
+
--warning-text-fg-override,
|
|
609
|
+
color-mix(
|
|
610
|
+
in srgb,
|
|
611
|
+
var(--_color),
|
|
612
|
+
var(--warning-color)
|
|
613
|
+
var(--warning-text-amount, var(--text-amount, 50%))
|
|
614
|
+
)
|
|
615
|
+
);
|
|
616
|
+
--danger-text-fg: var(
|
|
617
|
+
--danger-text-fg-override,
|
|
618
|
+
color-mix(
|
|
619
|
+
in srgb,
|
|
620
|
+
var(--_color),
|
|
621
|
+
var(--danger-color)
|
|
622
|
+
var(--danger-text-amount, var(--text-amount, 50%))
|
|
623
|
+
)
|
|
624
|
+
);
|
|
625
|
+
--muted-text-fg: var(
|
|
626
|
+
--muted-text-fg-override,
|
|
627
|
+
color-mix(
|
|
628
|
+
in srgb,
|
|
629
|
+
var(--_color),
|
|
630
|
+
var(--muted-color)
|
|
631
|
+
var(--muted-text-amount, var(--text-amount, 50%))
|
|
632
|
+
)
|
|
633
|
+
);
|
|
634
|
+
background-color: var(--_background-color);
|
|
635
|
+
color: var(--_color);
|
|
636
|
+
cursor: var(--circle-button-cursor, var(--mini-button-cursor, var(--button-cursor, var(--control-cursor, var(--cursor, pointer)))));
|
|
637
|
+
transition: filter var(--circle-button-transition, var(--mini-button-transition, var(--button-transition, var(--control-transition, var(--transition, 300ms))))), background-color var(--circle-button-transition, var(--mini-button-transition, var(--button-transition, var(--control-transition, var(--transition, 300ms))))), border-color var(--circle-button-transition, var(--mini-button-transition, var(--button-transition, var(--control-transition, var(--transition, 300ms))))), box-shadow var(--circle-button-transition, var(--mini-button-transition, var(--button-transition, var(--control-transition, var(--transition, 300ms))))), transform var(--circle-button-transition, var(--mini-button-transition, var(--button-transition, var(--control-transition, var(--transition, 300ms)))));
|
|
638
|
+
}
|
|
639
|
+
aside.overlay > button:hover {
|
|
640
|
+
filter: var(--circle-button-hover-filter, var(--mini-button-hover-filter, var(--button-hover-filter, var(--control-hover-filter, var(--hover-filter, brightness(1.05))))));
|
|
641
|
+
transform: var(--circle-button-hover-transform, var(--mini-button-hover-transform, var(--button-hover-transform, var(--control-hover-transform, var(--hover-transform, none)))));
|
|
642
|
+
color: var(--_color);
|
|
643
|
+
background-color: color-mix(in oklch, var(--_background-color) var(--hover-base-color-percentage, 90%), var(--hover-color-mix, white) calc(100% - var(--hover-base-color-percentage, 90%)));
|
|
644
|
+
box-shadow: var(--circle-button-hover-box-shadow, var(--mini-button-hover-box-shadow, var(--button-hover-box-shadow, var(--control-hover-box-shadow, var(--hover-box-shadow, var(--_box-shadow, none))))));
|
|
645
|
+
}
|
|
646
|
+
aside.overlay > button:active {
|
|
647
|
+
filter: var(--circle-button-active-filter, var(--mini-button-active-filter, var(--button-active-filter, var(--control-active-filter, var(--active-filter, brightness(0.9))))));
|
|
648
|
+
transform: var(--circle-button-active-transform, var(--mini-button-active-transform, var(--button-active-transform, var(--control-active-transform, var(--active-transform, none)))));
|
|
649
|
+
background-color: color-mix(in oklch, var(--_background-color) var(--active-base-color-percentage, 90%), var(--active-color-mix, black) calc(100% - var(--active-base-color-percentage, 90%)));
|
|
650
|
+
box-shadow: var(--circle-button-active-box-shadow, var(--mini-button-active-box-shadow, var(--button-active-box-shadow, var(--control-active-box-shadow, var(--active-box-shadow, var(--_box-shadow, none))))));
|
|
651
|
+
}
|
|
652
|
+
aside.overlay > button:disabled {
|
|
653
|
+
cursor: var(--circle-button-disabled-cursor, var(--mini-button-disabled-cursor, var(--button-disabled-cursor, var(--control-disabled-cursor, var(--disabled-cursor, not-allowed)))));
|
|
654
|
+
transform: var(--circle-button-disabled-transform, var(--mini-button-disabled-transform, var(--button-disabled-transform, var(--control-disabled-transform, var(--disabled-transform, none)))));
|
|
655
|
+
filter: var(--circle-button-disabled-filter, var(--mini-button-disabled-filter, var(--button-disabled-filter, var(--control-disabled-filter, var(--disabled-filter, grayscale(0.5))))));
|
|
656
|
+
background-color: color-mix(in oklch, var(--_background-color) var(--disabled-base-color-percentage, 50%), var(--disabled-color-mix, gray) calc(100% - var(--disabled-base-color-percentage, 50%)));
|
|
657
|
+
box-shadow: var(--circle-button-disabled-box-shadow, var(--mini-button-disabled-box-shadow, var(--button-disabled-box-shadow, var(--control-disabled-box-shadow, var(--disabled-box-shadow, var(--_box-shadow, none))))));
|
|
658
|
+
}
|
|
659
|
+
aside.overlay > button:focus-visible {
|
|
660
|
+
outline: var(--focus-color, -webkit-focus-ring-color) auto 1px;
|
|
661
|
+
outline-offset: var(--focus-outline-offset, 2px);
|
|
662
|
+
box-shadow: var(--focus-ring-box-shadow, 0 0 0 3px var(--focus-shadow-color, rgba(100, 150, 250, 0.5)));
|
|
663
|
+
}
|
|
664
|
+
aside.overlay > button::after {
|
|
665
|
+
color: var(--circle-button-fg, var(--mini-button-fg, currentColor));
|
|
666
|
+
filter: var(--sidebar-mobile-icon-filter, none);
|
|
667
|
+
}
|
|
668
|
+
aside.overlay > button.close {
|
|
669
|
+
/* Flush inside the panel's inner edge. Adding --padding here pushed the
|
|
670
|
+
button a padding's worth further in, which left it straddling the
|
|
671
|
+
edge -- part of it hanging outside the panel -- while the content
|
|
672
|
+
inset below still reserved the full button width, so the gap between
|
|
673
|
+
the button and the first nav item came out wider than intended.
|
|
674
|
+
Either the button pops out of the panel or it sits inside it; this
|
|
675
|
+
sits inside it, and the inset is then exactly button + one gutter. */
|
|
676
|
+
left: calc(var(--sidebar-width) - var(--_sidebar-expander-width));
|
|
677
|
+
border-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
678
|
+
border-top-right-radius: 0;
|
|
679
|
+
border-bottom-right-radius: 0;
|
|
680
|
+
}
|
|
681
|
+
aside.overlay {
|
|
682
|
+
/* Everything above anchors the button to the left, which is right for a
|
|
683
|
+
left-hand sidebar and nonsense for a right-hand one: the sheet slides
|
|
684
|
+
out of the right edge, so the button has to hug that edge and then step
|
|
685
|
+
*inwards* -- leftwards -- by the panel's width when it opens. Anchored
|
|
686
|
+
from the left it stepped the other way, off the far side of the page
|
|
687
|
+
entirely, where it could not even be clicked. The flattened corners
|
|
688
|
+
mirror too, so the button still reads as attached to its own edge. */
|
|
689
|
+
}
|
|
690
|
+
aside.overlay.right > button {
|
|
691
|
+
left: auto;
|
|
692
|
+
right: 0;
|
|
693
|
+
border-top-left-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
694
|
+
border-bottom-left-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
695
|
+
border-top-right-radius: 0;
|
|
696
|
+
border-bottom-right-radius: 0;
|
|
697
|
+
}
|
|
698
|
+
aside.overlay.right > button.close {
|
|
699
|
+
left: auto;
|
|
700
|
+
right: calc(var(--sidebar-width) - var(--_sidebar-expander-width));
|
|
701
|
+
border-top-right-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
702
|
+
border-bottom-right-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
703
|
+
border-top-left-radius: 0;
|
|
704
|
+
border-bottom-left-radius: 0;
|
|
329
705
|
}
|
|
330
706
|
.edge-bar {
|
|
331
707
|
--link-bg: var(--grab-bar-link-bg, var(--sidebar-link-bg, var(--surface-link-bg, inherit)));
|
|
@@ -457,43 +833,101 @@ aside .content:hover::-webkit-scrollbar-thumb:hover {
|
|
|
457
833
|
aside:has(.edge-bar:hover) .content {
|
|
458
834
|
filter: var(--greyed-out-filter);
|
|
459
835
|
}
|
|
460
|
-
/* Hide
|
|
461
|
-
|
|
462
|
-
button {
|
|
836
|
+
/* Hide the sheet button in rail mode */
|
|
837
|
+
aside:not(.overlay) > button {
|
|
463
838
|
display: none;
|
|
464
839
|
}
|
|
465
840
|
}
|
|
466
841
|
@container (max-width: 512px) {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
842
|
+
aside {
|
|
843
|
+
/* The sheet and its button are absolutely positioned, so the sidebar has
|
|
844
|
+
to be their containing block. Without this they resolve against
|
|
845
|
+
whatever positioned ancestor happens to be up the tree -- inside <Page>
|
|
846
|
+
that is Page's own aside and it looks fine, but drop a Sidebar into a
|
|
847
|
+
Card or a Container and the button escapes to the top-left of the page,
|
|
848
|
+
over unrelated content.
|
|
849
|
+
|
|
850
|
+
`overflow` has to be released in the same breath. Every child here is
|
|
851
|
+
out of flow, so the aside computes to zero height -- harmless while it
|
|
852
|
+
was not a containing block, but the moment it becomes one the inherited
|
|
853
|
+
`overflow: hidden` clips the button and the sheet away to nothing.
|
|
854
|
+
Nothing needs clipping here: the shut sheet is hidden by opacity and
|
|
855
|
+
pointer-events, not by the box. */
|
|
856
|
+
/* Sized here rather than on the button, because the panel needs them too
|
|
857
|
+
-- see the padding it reserves below. */
|
|
858
|
+
--_sidebar-expander-width: max(
|
|
859
|
+
var(--sidebar-icon-width, 0.65rem),
|
|
860
|
+
var(--icon-size, 32px)
|
|
861
|
+
);
|
|
862
|
+
--_sidebar-expander-height: max(
|
|
863
|
+
var(--sidebar-icon-height, 1rem),
|
|
864
|
+
var(--icon-size, 32px)
|
|
865
|
+
);
|
|
866
|
+
position: relative;
|
|
867
|
+
overflow: visible;
|
|
471
868
|
background: transparent;
|
|
869
|
+
width: calc(var(--gap) + max(var(--sidebar-icon-width, 0.65rem), var(--icon-size, 32px)));
|
|
870
|
+
flex: 0 0 auto;
|
|
871
|
+
/* Every child is out of flow, so the aside has no content to hold it
|
|
872
|
+
open and the base `height: 100%` resolves against an auto-height
|
|
873
|
+
parent -- which is to say, nothing. Stretch to the row instead, so the
|
|
874
|
+
aside is as tall as whatever it sits beside, and the open sheet's own
|
|
875
|
+
`height: 100%` has something real to measure against. */
|
|
876
|
+
height: auto;
|
|
877
|
+
align-self: stretch;
|
|
878
|
+
}
|
|
879
|
+
aside .edge-bar {
|
|
880
|
+
display: none;
|
|
472
881
|
}
|
|
473
|
-
.right,
|
|
474
|
-
.left {
|
|
882
|
+
aside.right, aside.left {
|
|
475
883
|
border-left: none;
|
|
476
884
|
border-right: none;
|
|
477
885
|
}
|
|
478
886
|
aside > .content {
|
|
887
|
+
position: absolute;
|
|
888
|
+
top: 0;
|
|
889
|
+
left: 0;
|
|
890
|
+
width: var(--sidebar-width);
|
|
891
|
+
z-index: 2;
|
|
479
892
|
transform: translateX(-100%);
|
|
480
893
|
opacity: 0;
|
|
481
894
|
background: transparent;
|
|
482
895
|
pointer-events: none;
|
|
483
|
-
transition: transform var(--sidebar-transition) ease-in-out;
|
|
896
|
+
transition: transform var(--sidebar-transition) ease-in-out, opacity var(--sidebar-transition) ease-in-out;
|
|
484
897
|
padding: var(--padding);
|
|
898
|
+
/* The close button floats over the panel's inner edge, so the panel has
|
|
899
|
+
to keep that strip clear or the first nav item sits underneath it.
|
|
900
|
+
|
|
901
|
+
Reserved on the inline axis, not the block one: a nav wants the full
|
|
902
|
+
height, and a blank band across the top of it to clear one button is
|
|
903
|
+
a poor trade. The cost is that the whole column is a button's width
|
|
904
|
+
narrower, even well below the button -- override
|
|
905
|
+
--sidebar-sheet-content-inset to 0 and set your own padding if you
|
|
906
|
+
would rather have the width back. */
|
|
907
|
+
padding-inline-end: var(--sidebar-sheet-content-inset, calc(var(--padding) + var(--_sidebar-expander-width)));
|
|
485
908
|
}
|
|
486
909
|
aside.left > .content {
|
|
487
910
|
border-right: var(--border-width) var(--border-style) var(--border-color);
|
|
488
911
|
}
|
|
912
|
+
aside {
|
|
913
|
+
/* A right-hand sheet slides out of the right edge, not the left -- and
|
|
914
|
+
its button lands on the panel's left edge, so the reserved strip
|
|
915
|
+
mirrors with it. */
|
|
916
|
+
}
|
|
489
917
|
aside.right > .content {
|
|
918
|
+
left: auto;
|
|
919
|
+
right: 0;
|
|
920
|
+
transform: translateX(100%);
|
|
490
921
|
border-left: var(--border-width) var(--border-style) var(--border-color);
|
|
922
|
+
padding-inline-end: var(--padding);
|
|
923
|
+
padding-inline-start: var(--sidebar-sheet-content-inset, calc(var(--padding) + var(--_sidebar-expander-width)));
|
|
491
924
|
}
|
|
492
925
|
aside.expandedHamburger > .content {
|
|
493
926
|
transform: translateX(0);
|
|
494
927
|
height: 100%;
|
|
495
928
|
opacity: 1;
|
|
496
929
|
pointer-events: all;
|
|
930
|
+
box-shadow: var(--sidebar-overlay-box-shadow, var(--overlay-box-shadow, 0 0 var(--space, 8px) rgba(127, 127, 127, 0.4)));
|
|
497
931
|
--link-bg: var(--sidebar-link-bg, var(--surface-link-bg, inherit));
|
|
498
932
|
--link-fg: var(--sidebar-link-fg, var(--surface-link-fg, inherit));
|
|
499
933
|
--_bg-mix-color: var(--sidebar-bg-mix-color, var(--surface-bg-mix-color, var(--bg-mix-color, transparent)));
|
|
@@ -580,14 +1014,6 @@ aside .content:hover::-webkit-scrollbar-thumb:hover {
|
|
|
580
1014
|
color: var(--_color);
|
|
581
1015
|
}
|
|
582
1016
|
aside > button {
|
|
583
|
-
--_sidebar-expander-width: max(
|
|
584
|
-
var(--sidebar-icon-width, 0.65rem),
|
|
585
|
-
var(--icon-size, 32px)
|
|
586
|
-
);
|
|
587
|
-
--_sidebar-expander-height: max(
|
|
588
|
-
var(--sidebar-icon-height, 1rem),
|
|
589
|
-
var(--icon-size, 32px)
|
|
590
|
-
);
|
|
591
1017
|
transition: left var(--sidebar-transition);
|
|
592
1018
|
transform: translateX(0);
|
|
593
1019
|
z-index: 3;
|
|
@@ -595,7 +1021,6 @@ aside .content:hover::-webkit-scrollbar-thumb:hover {
|
|
|
595
1021
|
opacity: 1;
|
|
596
1022
|
pointer-events: all;
|
|
597
1023
|
display: block;
|
|
598
|
-
position: absolute;
|
|
599
1024
|
top: var(--padding);
|
|
600
1025
|
left: 0;
|
|
601
1026
|
border-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
@@ -721,28 +1146,42 @@ aside .content:hover::-webkit-scrollbar-thumb:hover {
|
|
|
721
1146
|
filter: var(--sidebar-mobile-icon-filter, none);
|
|
722
1147
|
}
|
|
723
1148
|
aside > button.close {
|
|
724
|
-
|
|
1149
|
+
/* Flush inside the panel's inner edge. Adding --padding here pushed the
|
|
1150
|
+
button a padding's worth further in, which left it straddling the
|
|
1151
|
+
edge -- part of it hanging outside the panel -- while the content
|
|
1152
|
+
inset below still reserved the full button width, so the gap between
|
|
1153
|
+
the button and the first nav item came out wider than intended.
|
|
1154
|
+
Either the button pops out of the panel or it sits inside it; this
|
|
1155
|
+
sits inside it, and the inset is then exactly button + one gutter. */
|
|
1156
|
+
left: calc(var(--sidebar-width) - var(--_sidebar-expander-width));
|
|
725
1157
|
border-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
726
1158
|
border-top-right-radius: 0;
|
|
727
1159
|
border-bottom-right-radius: 0;
|
|
728
1160
|
}
|
|
729
|
-
/* aside > button:hover {
|
|
730
|
-
background: var(--mini-button-hover-bg);
|
|
731
|
-
color: var(--mini-button-hover-fg);
|
|
732
|
-
} */
|
|
733
1161
|
aside {
|
|
734
|
-
|
|
735
|
-
|
|
1162
|
+
/* Everything above anchors the button to the left, which is right for a
|
|
1163
|
+
left-hand sidebar and nonsense for a right-hand one: the sheet slides
|
|
1164
|
+
out of the right edge, so the button has to hug that edge and then step
|
|
1165
|
+
*inwards* -- leftwards -- by the panel's width when it opens. Anchored
|
|
1166
|
+
from the left it stepped the other way, off the far side of the page
|
|
1167
|
+
entirely, where it could not even be clicked. The flattened corners
|
|
1168
|
+
mirror too, so the button still reads as attached to its own edge. */
|
|
736
1169
|
}
|
|
737
|
-
aside
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
1170
|
+
aside.right > button {
|
|
1171
|
+
left: auto;
|
|
1172
|
+
right: 0;
|
|
1173
|
+
border-top-left-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
1174
|
+
border-bottom-left-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
1175
|
+
border-top-right-radius: 0;
|
|
1176
|
+
border-bottom-right-radius: 0;
|
|
1177
|
+
}
|
|
1178
|
+
aside.right > button.close {
|
|
1179
|
+
left: auto;
|
|
1180
|
+
right: calc(var(--sidebar-width) - var(--_sidebar-expander-width));
|
|
1181
|
+
border-top-right-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
1182
|
+
border-bottom-right-radius: var(--circle-button-radius, var(--mini-button-radius, var(--button-radius, var(--radius, 50%))));
|
|
1183
|
+
border-top-left-radius: 0;
|
|
1184
|
+
border-bottom-left-radius: 0;
|
|
746
1185
|
}
|
|
747
1186
|
}
|
|
748
1187
|
button::after {
|
|
@@ -758,14 +1197,34 @@ button::after {
|
|
|
758
1197
|
line-height: 1;
|
|
759
1198
|
}
|
|
760
1199
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
1200
|
+
/* The rail and the sheet are different affordances and want different
|
|
1201
|
+
glyphs. The rail slides a panel out from the edge it sits on, so a
|
|
1202
|
+
chevron pointing that way says what will happen. The sheet is summoned
|
|
1203
|
+
from nowhere by a free-floating button, where the menu glyph is what
|
|
1204
|
+
people already recognize -- and it closes with an x, not a back-chevron,
|
|
1205
|
+
because there is no edge to slide back into.
|
|
1206
|
+
|
|
1207
|
+
Both still fall through --sidebar-expand / --sidebar-collapse, so setting
|
|
1208
|
+
those restyles every button at once and themes that swap in SVGs keep
|
|
1209
|
+
working unchanged. */
|
|
1210
|
+
.edge-bar button.expander::after {
|
|
1211
|
+
content: var(--grab-bar-expand, var(--sidebar-expand, "›"));
|
|
1212
|
+
background-image: var(--grab-bar-expand-image, var(--sidebar-expand-image, none));
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
.edge-bar button.close::after {
|
|
1216
|
+
content: var(--grab-bar-collapse, var(--sidebar-collapse, "‹"));
|
|
1217
|
+
background-image: var(--grab-bar-collapse-image, var(--sidebar-collapse-image, none));
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
aside > button.expander::after {
|
|
1221
|
+
content: var(--sidebar-sheet-expand, var(--sidebar-expand, "☰"));
|
|
1222
|
+
background-image: var(--sidebar-sheet-expand-image, var(--sidebar-expand-image, none));
|
|
764
1223
|
}
|
|
765
1224
|
|
|
766
|
-
button.close::after {
|
|
767
|
-
content: var(--sidebar-collapse, "
|
|
768
|
-
background-image: var(--sidebar-collapse-image, none);
|
|
1225
|
+
aside > button.close::after {
|
|
1226
|
+
content: var(--sidebar-sheet-collapse, var(--sidebar-collapse, "✕"));
|
|
1227
|
+
background-image: var(--sidebar-sheet-collapse-image, var(--sidebar-collapse-image, none));
|
|
769
1228
|
}
|
|
770
1229
|
|
|
771
1230
|
.right button::after {
|