@slotted/styles 0.0.0-stage → 0.1.0-beta.1
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/LICENSE +21 -0
- package/README.md +10 -2
- package/package.json +276 -3
- package/src/accordion/accordion.css +96 -0
- package/src/accordion/accordion.tokens.json +14 -0
- package/src/action-bar/action-bar.css +455 -0
- package/src/action-bar/action-bar.tokens.json +50 -0
- package/src/action-sheet/action-sheet.css +462 -0
- package/src/action-sheet/action-sheet.tokens.json +59 -0
- package/src/alert/alert.css +764 -0
- package/src/alert/alert.tokens.json +77 -0
- package/src/app-shell/app-shell.css +1899 -0
- package/src/app-shell/app-shell.tokens.json +88 -0
- package/src/aspect-ratio/aspect-ratio.css +131 -0
- package/src/aspect-ratio/aspect-ratio.tokens.json +1 -0
- package/src/attachment/attachment.css +906 -0
- package/src/attachment/attachment.tokens.json +85 -0
- package/src/avatar/avatar.css +598 -0
- package/src/avatar/avatar.tokens.json +64 -0
- package/src/avatar-group/avatar-group.css +268 -0
- package/src/avatar-group/avatar-group.tokens.json +16 -0
- package/src/badge/badge.css +462 -0
- package/src/badge/badge.tokens.json +58 -0
- package/src/breadcrumb/breadcrumb.css +441 -0
- package/src/breadcrumb/breadcrumb.tokens.json +50 -0
- package/src/button/button.css +754 -0
- package/src/button/button.tokens.json +72 -0
- package/src/button-group/button-group.css +455 -0
- package/src/button-group/button-group.tokens.json +11 -0
- package/src/calendar/calendar.css +846 -0
- package/src/calendar/calendar.tokens.json +67 -0
- package/src/card/card.css +602 -0
- package/src/card/card.tokens.json +68 -0
- package/src/carousel/carousel.css +860 -0
- package/src/carousel/carousel.tokens.json +62 -0
- package/src/cascader/cascader.css +1320 -0
- package/src/cascader/cascader.tokens.json +103 -0
- package/src/chart/chart.css +1473 -0
- package/src/chart/chart.tokens.json +107 -0
- package/src/checkbox/checkbox.css +1011 -0
- package/src/checkbox/checkbox.tokens.json +102 -0
- package/src/checkbox-group/checkbox-group.css +70 -0
- package/src/checkbox-group/checkbox-group.tokens.json +6 -0
- package/src/code-block/code-block.css +555 -0
- package/src/code-block/code-block.tokens.json +69 -0
- package/src/collapsible/collapsible.css +546 -0
- package/src/collapsible/collapsible.tokens.json +55 -0
- package/src/color-picker/color-picker.css +607 -0
- package/src/color-picker/color-picker.tokens.json +58 -0
- package/src/column-manager/column-manager.css +452 -0
- package/src/column-manager/column-manager.tokens.json +43 -0
- package/src/combobox/combobox.css +1048 -0
- package/src/combobox/combobox.tokens.json +112 -0
- package/src/command-palette/command-palette.css +1000 -0
- package/src/command-palette/command-palette.tokens.json +75 -0
- package/src/container/container.css +198 -0
- package/src/container/container.tokens.json +18 -0
- package/src/context-menu/context-menu.css +104 -0
- package/src/context-menu/context-menu.tokens.json +11 -0
- package/src/currency-field/currency-field.css +787 -0
- package/src/currency-field/currency-field.tokens.json +80 -0
- package/src/dashboard-grid/dashboard-grid.css +748 -0
- package/src/dashboard-grid/dashboard-grid.tokens.json +67 -0
- package/src/data-grid/data-grid.css +2484 -0
- package/src/data-grid/data-grid.tokens.json +100 -0
- package/src/data-list/data-list.css +455 -0
- package/src/data-list/data-list.tokens.json +35 -0
- package/src/date-field/date-field.css +560 -0
- package/src/date-field/date-field.tokens.json +80 -0
- package/src/date-picker/date-picker.css +420 -0
- package/src/date-picker/date-picker.tokens.json +49 -0
- package/src/date-range-picker/date-range-picker.css +983 -0
- package/src/date-range-picker/date-range-picker.tokens.json +109 -0
- package/src/datetime-field/datetime-field.css +850 -0
- package/src/datetime-field/datetime-field.tokens.json +91 -0
- package/src/datetime-picker/datetime-picker.css +843 -0
- package/src/datetime-picker/datetime-picker.tokens.json +78 -0
- package/src/datetime-range-picker/datetime-range-picker.css +1375 -0
- package/src/datetime-range-picker/datetime-range-picker.tokens.json +135 -0
- package/src/description-list/description-list.css +675 -0
- package/src/description-list/description-list.tokens.json +66 -0
- package/src/detail-panel/detail-panel.css +329 -0
- package/src/detail-panel/detail-panel.tokens.json +33 -0
- package/src/dialog/dialog.css +968 -0
- package/src/dialog/dialog.tokens.json +66 -0
- package/src/divider/divider.css +131 -0
- package/src/divider/divider.tokens.json +18 -0
- package/src/drawer/drawer.css +1303 -0
- package/src/drawer/drawer.tokens.json +75 -0
- package/src/entity-picker/entity-picker.css +1367 -0
- package/src/entity-picker/entity-picker.tokens.json +118 -0
- package/src/event-calendar/event-calendar.css +2148 -0
- package/src/event-calendar/event-calendar.tokens.json +87 -0
- package/src/field/field.css +707 -0
- package/src/field/field.tokens.json +58 -0
- package/src/field-group/field-group.css +226 -0
- package/src/field-group/field-group.tokens.json +33 -0
- package/src/filter-bar/filter-bar.css +1306 -0
- package/src/filter-bar/filter-bar.tokens.json +78 -0
- package/src/form/form.css +218 -0
- package/src/form/form.tokens.json +32 -0
- package/src/fullscreen/fullscreen.css +376 -0
- package/src/fullscreen/fullscreen.tokens.json +50 -0
- package/src/grid/grid.css +173 -0
- package/src/grid/grid.tokens.json +20 -0
- package/src/highlight/highlight.css +135 -0
- package/src/highlight/highlight.tokens.json +16 -0
- package/src/hover-card/hover-card.css +93 -0
- package/src/hover-card/hover-card.tokens.json +17 -0
- package/src/icon/icon.css +136 -0
- package/src/icon/icon.tokens.json +14 -0
- package/src/image/image.css +449 -0
- package/src/image/image.tokens.json +27 -0
- package/src/import-export-center/import-export-center.css +1175 -0
- package/src/import-export-center/import-export-center.tokens.json +84 -0
- package/src/inline/inline.css +149 -0
- package/src/inline/inline.tokens.json +14 -0
- package/src/inline-message/inline-message.css +396 -0
- package/src/inline-message/inline-message.tokens.json +19 -0
- package/src/kbd/kbd.css +490 -0
- package/src/kbd/kbd.tokens.json +40 -0
- package/src/link/link.css +237 -0
- package/src/link/link.tokens.json +25 -0
- package/src/list/list.css +240 -0
- package/src/list/list.tokens.json +42 -0
- package/src/list-item/list-item.css +937 -0
- package/src/list-item/list-item.tokens.json +114 -0
- package/src/listbox/listbox.css +674 -0
- package/src/listbox/listbox.tokens.json +72 -0
- package/src/loading-overlay/loading-overlay.css +730 -0
- package/src/loading-overlay/loading-overlay.tokens.json +48 -0
- package/src/markdown/markdown.css +168 -0
- package/src/markdown/markdown.tokens.json +18 -0
- package/src/menu/menu.css +817 -0
- package/src/menu/menu.tokens.json +78 -0
- package/src/menubar/menubar.css +170 -0
- package/src/menubar/menubar.tokens.json +32 -0
- package/src/message/message.css +1453 -0
- package/src/message/message.tokens.json +85 -0
- package/src/message-scroller/message-scroller.css +371 -0
- package/src/message-scroller/message-scroller.tokens.json +47 -0
- package/src/multi-select/multi-select.css +1427 -0
- package/src/multi-select/multi-select.tokens.json +114 -0
- package/src/navigation-menu/navigation-menu.css +1029 -0
- package/src/navigation-menu/navigation-menu.tokens.json +70 -0
- package/src/notification-center/notification-center.css +856 -0
- package/src/notification-center/notification-center.tokens.json +84 -0
- package/src/number-field/number-field.css +794 -0
- package/src/number-field/number-field.tokens.json +80 -0
- package/src/otp-input/otp-input.css +525 -0
- package/src/otp-input/otp-input.tokens.json +69 -0
- package/src/page/page.css +179 -0
- package/src/page/page.tokens.json +20 -0
- package/src/page-header/page-header.css +1181 -0
- package/src/page-header/page-header.tokens.json +71 -0
- package/src/pagination/pagination.css +500 -0
- package/src/pagination/pagination.tokens.json +56 -0
- package/src/popover/popover.css +526 -0
- package/src/popover/popover.tokens.json +60 -0
- package/src/progress-indicator/progress-indicator.css +1584 -0
- package/src/progress-indicator/progress-indicator.tokens.json +50 -0
- package/src/prompt-composer/prompt-composer.css +680 -0
- package/src/prompt-composer/prompt-composer.tokens.json +99 -0
- package/src/prose/prose.css +733 -0
- package/src/prose/prose.tokens.json +79 -0
- package/src/radio-group/radio-group.css +778 -0
- package/src/radio-group/radio-group.tokens.json +103 -0
- package/src/rating/rating.css +1071 -0
- package/src/rating/rating.tokens.json +88 -0
- package/src/result-state/result-state.css +980 -0
- package/src/result-state/result-state.tokens.json +63 -0
- package/src/runtime-properties.mjs +321 -0
- package/src/saved-views/saved-views.css +394 -0
- package/src/saved-views/saved-views.tokens.json +41 -0
- package/src/scroll-area/scroll-area.css +481 -0
- package/src/scroll-area/scroll-area.tokens.json +15 -0
- package/src/section/section.css +177 -0
- package/src/section/section.tokens.json +39 -0
- package/src/segmented-control/segmented-control.css +564 -0
- package/src/segmented-control/segmented-control.tokens.json +67 -0
- package/src/select/select.css +1593 -0
- package/src/select/select.tokens.json +110 -0
- package/src/side-navigation/side-navigation.css +1096 -0
- package/src/side-navigation/side-navigation.tokens.json +87 -0
- package/src/skeleton/skeleton.css +431 -0
- package/src/skeleton/skeleton.tokens.json +29 -0
- package/src/slider/slider.css +792 -0
- package/src/slider/slider.tokens.json +75 -0
- package/src/sparkline/sparkline.css +282 -0
- package/src/sparkline/sparkline.tokens.json +45 -0
- package/src/spinner/spinner.css +224 -0
- package/src/spinner/spinner.tokens.json +8 -0
- package/src/split-button/split-button.css +253 -0
- package/src/split-button/split-button.tokens.json +12 -0
- package/src/splitter/splitter.css +336 -0
- package/src/splitter/splitter.tokens.json +24 -0
- package/src/stack/stack.css +128 -0
- package/src/stack/stack.tokens.json +14 -0
- package/src/stat-card/stat-card.css +641 -0
- package/src/stat-card/stat-card.tokens.json +95 -0
- package/src/status-indicator/status-indicator.css +481 -0
- package/src/status-indicator/status-indicator.tokens.json +38 -0
- package/src/stepper/stepper.css +629 -0
- package/src/stepper/stepper.tokens.json +72 -0
- package/src/switch/switch.css +703 -0
- package/src/switch/switch.tokens.json +75 -0
- package/src/table/table.css +1482 -0
- package/src/table/table.tokens.json +69 -0
- package/src/table-of-contents/table-of-contents.css +533 -0
- package/src/table-of-contents/table-of-contents.tokens.json +53 -0
- package/src/tabs/tabs.css +998 -0
- package/src/tabs/tabs.tokens.json +82 -0
- package/src/tag/tag.css +768 -0
- package/src/tag/tag.tokens.json +85 -0
- package/src/tags-input/tags-input.css +757 -0
- package/src/tags-input/tags-input.tokens.json +84 -0
- package/src/text-field/text-field.css +900 -0
- package/src/text-field/text-field.tokens.json +87 -0
- package/src/textarea/textarea.css +365 -0
- package/src/textarea/textarea.tokens.json +59 -0
- package/src/time-field/time-field.css +719 -0
- package/src/time-field/time-field.tokens.json +86 -0
- package/src/time-picker/time-picker.css +665 -0
- package/src/time-picker/time-picker.tokens.json +66 -0
- package/src/time-range-picker/time-range-picker.css +1287 -0
- package/src/time-range-picker/time-range-picker.tokens.json +134 -0
- package/src/timeline/timeline.css +1596 -0
- package/src/timeline/timeline.tokens.json +96 -0
- package/src/toast/toast.css +943 -0
- package/src/toast/toast.tokens.json +90 -0
- package/src/toggle/toggle.css +290 -0
- package/src/toggle/toggle.tokens.json +54 -0
- package/src/toggle-group/toggle-group.css +463 -0
- package/src/toggle-group/toggle-group.tokens.json +54 -0
- package/src/toolbar/toolbar.css +434 -0
- package/src/toolbar/toolbar.tokens.json +49 -0
- package/src/tooltip/tooltip.css +368 -0
- package/src/tooltip/tooltip.tokens.json +39 -0
- package/src/top-navigation/top-navigation.css +1287 -0
- package/src/top-navigation/top-navigation.tokens.json +91 -0
- package/src/tour/tour.css +680 -0
- package/src/tour/tour.tokens.json +67 -0
- package/src/transfer/transfer.css +571 -0
- package/src/transfer/transfer.tokens.json +49 -0
- package/src/tree/tree.css +1000 -0
- package/src/tree/tree.tokens.json +80 -0
- package/src/typography/typography.css +211 -0
- package/src/typography/typography.tokens.json +31 -0
- package/src/upload/upload.css +1706 -0
- package/src/upload/upload.tokens.json +123 -0
- package/src/visually-hidden/visually-hidden.css +52 -0
- package/src/visually-hidden/visually-hidden.tokens.json +1 -0
- package/src/wizard/wizard.css +740 -0
- package/src/wizard/wizard.tokens.json +63 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
@layer slotted.components {
|
|
2
|
+
/**
|
|
3
|
+
* A scrollport, and the box that frames it.
|
|
4
|
+
*
|
|
5
|
+
* The scrollbar is the platform's. Radix, Base UI, Zag, Chakra and Mantine
|
|
6
|
+
* all hide the native bar — `scrollbar-width: none` plus a
|
|
7
|
+
* `::-webkit-scrollbar` rule — and redraw it from a thumb element kept in
|
|
8
|
+
* sync by a scroll listener and a `ResizeObserver`. That costs the trough
|
|
9
|
+
* click, the scrollbar context menu, the system's own overlay behaviour, and
|
|
10
|
+
* the correct bar before hydration or without JavaScript.
|
|
11
|
+
* `docs/component-features.md` §4 asks for the opposite in this family's own
|
|
12
|
+
* sentence, and `scrollbar-color` reached Baseline in December 2025, so the
|
|
13
|
+
* themed bar no longer needs a thumb of the library's own. What that costs is
|
|
14
|
+
* written in `specs/components/scroll-area/contract.json`, field `scrollbar`.
|
|
15
|
+
*
|
|
16
|
+
* There is no APG pattern. The keyboard is the platform's too: a focused
|
|
17
|
+
* scrollport answers the arrows, the page keys, `Home`, `End` and `Space` on
|
|
18
|
+
* its own. What the family adds is the tab stop that makes those reachable,
|
|
19
|
+
* and the name that tab stop owes — and both live in the bindings, because
|
|
20
|
+
* both are conditional on a measurement CSS cannot make.
|
|
21
|
+
*
|
|
22
|
+
* ── Why the frame and the scrollport are two elements ───────────────────
|
|
23
|
+
*
|
|
24
|
+
* They were one, and the first capture is what refused it. The affordance is
|
|
25
|
+
* a mask, and a mask applies to everything the element paints — its border
|
|
26
|
+
* included. A bounded region with a border round it is the commonest shape
|
|
27
|
+
* this family has, and the veil took the top and bottom of that border with
|
|
28
|
+
* the content: three boxes in one capture had a crisp border down both sides
|
|
29
|
+
* and no border at all across the ends, which reads as a rendering fault
|
|
30
|
+
* rather than as an affordance.
|
|
31
|
+
*
|
|
32
|
+
* Nothing can be excluded from a mask — `mask-clip` moves where the mask is
|
|
33
|
+
* painted and never what it covers — so the frame has to be on an element the
|
|
34
|
+
* mask is not on. `root` is that element: it holds the border, the radius and
|
|
35
|
+
* the maximum, and `viewport` inside it holds the scroll and the veil.
|
|
36
|
+
*/
|
|
37
|
+
[data-ui='scroll-area'] {
|
|
38
|
+
/**
|
|
39
|
+
* How far the veil reaches in from an edge that has content behind it.
|
|
40
|
+
*
|
|
41
|
+
* Capped against the box, which is the construction `splitter` already uses
|
|
42
|
+
* for its own gaps: a fixed reach is a fifth of a tall panel and a third of
|
|
43
|
+
* a short one, and at a third the affordance stops being a hint and starts
|
|
44
|
+
* being a hole. A percentage inside a gradient resolves against that
|
|
45
|
+
* gradient's own axis, so one declaration caps both.
|
|
46
|
+
*
|
|
47
|
+
* It does not vary by density, and that is a decision rather than an
|
|
48
|
+
* omission: nothing this family draws is a control, and the one thing it
|
|
49
|
+
* does draw is a veil over the consumer's own content. Scaling it with
|
|
50
|
+
* density would change how much content is hidden rather than how much
|
|
51
|
+
* space is used, and the content inside already answers density through the
|
|
52
|
+
* tokens its own families read.
|
|
53
|
+
*/
|
|
54
|
+
--_fade: min(var(--slotted-scroll-area-fade-size, var(--slotted-space-8, 1.5rem)), 20%);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The thumb takes the **strong** border step, which is the step the
|
|
58
|
+
* foundation holds to 3:1 against every surface a control can sit on — a
|
|
59
|
+
* scrollbar is a non-text element and that is its floor. The track takes
|
|
60
|
+
* the sunken surface, which is what a groove is: the page, one step back.
|
|
61
|
+
*/
|
|
62
|
+
--_thumb: var(--slotted-scroll-area-thumb-color, var(--slotted-border-strong, ButtonBorder));
|
|
63
|
+
--_track: var(--slotted-scroll-area-track-color, var(--slotted-surface-sunken, Canvas));
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* One cell, so the scrollport takes whatever the consumer gave the box and
|
|
67
|
+
* nothing more. `min-block-size: 0` on both is what lets it: a grid item's
|
|
68
|
+
* automatic minimum is its content, and without the override a scrollport
|
|
69
|
+
* inside a bounded box grows to its content and scrolls nothing.
|
|
70
|
+
*
|
|
71
|
+
* The family paints no frame of its own. A border, a radius and a ground
|
|
72
|
+
* are the consumer's, and they go here — on the element the mask is not on.
|
|
73
|
+
*/
|
|
74
|
+
display: grid;
|
|
75
|
+
box-sizing: border-box;
|
|
76
|
+
min-block-size: 0;
|
|
77
|
+
min-inline-size: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
[data-ui='scroll-area'] > [data-part='viewport'] {
|
|
81
|
+
/**
|
|
82
|
+
* One length per logical edge: the veil's reach where that end of the
|
|
83
|
+
* content is out of view, and nothing where it is showing.
|
|
84
|
+
*
|
|
85
|
+
* The resting value is the reach and the attribute *removes* it, because
|
|
86
|
+
* `data-at-block-start` says the reader can see that end — so the rule that
|
|
87
|
+
* paints is the plain one and the rule that clears is the qualified one,
|
|
88
|
+
* and no selector needs `:not()`.
|
|
89
|
+
*/
|
|
90
|
+
--_scroll-area-fade-block-start: var(--_fade);
|
|
91
|
+
--_scroll-area-fade-block-end: var(--_fade);
|
|
92
|
+
--_scroll-area-fade-inline-start: var(--_fade);
|
|
93
|
+
--_scroll-area-fade-inline-end: var(--_fade);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The same four, mapped to the axes a gradient can actually be given. CSS
|
|
97
|
+
* has no logical gradient direction and no logical `mask-position`, so the
|
|
98
|
+
* mapping is written here once instead of in four rules.
|
|
99
|
+
*/
|
|
100
|
+
--_fade-top: var(--_scroll-area-fade-block-start);
|
|
101
|
+
--_fade-bottom: var(--_scroll-area-fade-block-end);
|
|
102
|
+
--_fade-left: var(--_scroll-area-fade-inline-start);
|
|
103
|
+
--_fade-right: var(--_scroll-area-fade-inline-end);
|
|
104
|
+
|
|
105
|
+
box-sizing: border-box;
|
|
106
|
+
min-block-size: 0;
|
|
107
|
+
min-inline-size: 0;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The root is where a consumer's radius goes, and the scrollport is what
|
|
111
|
+
* clips: without this the content ran square into a rounded frame, and so
|
|
112
|
+
* did the veil.
|
|
113
|
+
*/
|
|
114
|
+
border-radius: inherit;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* `stable` rather than `auto` by default: content that jumps sideways the
|
|
118
|
+
* moment it grows past its box is the defect `scrollbar-gutter` was added
|
|
119
|
+
* for, and it is the one Mantine approximates with padding.
|
|
120
|
+
*/
|
|
121
|
+
scrollbar-gutter: stable;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* A bounded region whose last inch of scroll moves the page behind it is
|
|
125
|
+
* the other defect the platform named. `contain` is the default here and
|
|
126
|
+
* opt-in in Mantine; the remaining two values are the consumer's.
|
|
127
|
+
*/
|
|
128
|
+
overscroll-behavior: contain;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* `thin` rather than `auto`, and it is still the platform's bar: the trough
|
|
132
|
+
* click, the scrollbar context menu and the system's own behaviour all
|
|
133
|
+
* survive it. What it drops is the pair of stepper buttons Chrome draws on
|
|
134
|
+
* Linux and Windows once a scrollbar is themed at all — read in the first
|
|
135
|
+
* capture with a bar visible, they took thirty-two pixels off a hundred and
|
|
136
|
+
* seventy-six-pixel panel and read as a control from another decade beside
|
|
137
|
+
* the rest of the library. Every surveyed implementation draws its bar at
|
|
138
|
+
* about this width.
|
|
139
|
+
*
|
|
140
|
+
* A product that wants the system's full-width bar writes
|
|
141
|
+
* `scrollbar-width: auto` on the part; it is one declaration, and the
|
|
142
|
+
* reference page carries it.
|
|
143
|
+
*/
|
|
144
|
+
scrollbar-width: thin;
|
|
145
|
+
scrollbar-color: var(--_thumb) var(--_track);
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The veil, and the whole of the affordance.
|
|
149
|
+
*
|
|
150
|
+
* Four edges need more than the two pseudo-elements a box has, and a
|
|
151
|
+
* pseudo-element positioned inside a scrollport scrolls away with the
|
|
152
|
+
* content. A mask applies to the border box and stays.
|
|
153
|
+
*
|
|
154
|
+
* It is a mask rather than a gradient for the reason `table` wrote when it
|
|
155
|
+
* refused one: a gradient over the content has to be the colour of the
|
|
156
|
+
* ground beneath it, so it is wrong on every surface but one and in every
|
|
157
|
+
* scheme but one. A mask fades the content to transparent and needs no ink
|
|
158
|
+
* at all — `#000` here is alpha 1, not a colour decision.
|
|
159
|
+
*
|
|
160
|
+
* One layer per physical axis, each fading both of its ends, composed with
|
|
161
|
+
* `intersect` so the two alphas multiply at a corner.
|
|
162
|
+
*/
|
|
163
|
+
mask-image:
|
|
164
|
+
linear-gradient(
|
|
165
|
+
to bottom,
|
|
166
|
+
transparent 0,
|
|
167
|
+
#000 var(--_fade-top),
|
|
168
|
+
#000 calc(100% - var(--_fade-bottom)),
|
|
169
|
+
transparent 100%
|
|
170
|
+
),
|
|
171
|
+
linear-gradient(
|
|
172
|
+
to right,
|
|
173
|
+
transparent 0,
|
|
174
|
+
#000 var(--_fade-left),
|
|
175
|
+
#000 calc(100% - var(--_fade-right)),
|
|
176
|
+
transparent 100%
|
|
177
|
+
);
|
|
178
|
+
mask-composite: intersect;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The veil moves rather than appearing. A state change the eye has to
|
|
182
|
+
* follow carries a transition, and this one is the whole of the feedback
|
|
183
|
+
* that there is more behind an edge.
|
|
184
|
+
*
|
|
185
|
+
* `mask-image` is not an animatable property, so what transitions is the
|
|
186
|
+
* four lengths inside it: a registered custom property is interpolable, and
|
|
187
|
+
* `@property` is what registers one. The registrations are at the foot of
|
|
188
|
+
* this file, outside the cascade layer, where `@property` belongs.
|
|
189
|
+
*/
|
|
190
|
+
transition:
|
|
191
|
+
--_scroll-area-fade-block-start var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
192
|
+
--_scroll-area-fade-block-end var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
193
|
+
--_scroll-area-fade-inline-start var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
194
|
+
--_scroll-area-fade-inline-end var(--slotted-duration-short) var(--slotted-easing-standard);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The inline axis is the one the document can turn round, and a gradient
|
|
199
|
+
* cannot be given a logical direction. So the two physical lengths swap here
|
|
200
|
+
* and nowhere else: every other rule in this sheet states the logical edge,
|
|
201
|
+
* and the mapping is corrected once.
|
|
202
|
+
*
|
|
203
|
+
* `:dir()` rather than `[dir='rtl']`, because a document may be turned round
|
|
204
|
+
* by the `direction` property with no attribute to select on — and the
|
|
205
|
+
* attribute form would then paint the veil on the edge the reader can already
|
|
206
|
+
* see.
|
|
207
|
+
*/
|
|
208
|
+
[data-ui='scroll-area']:dir(rtl) > [data-part='viewport'] {
|
|
209
|
+
--_fade-left: var(--_scroll-area-fade-inline-end);
|
|
210
|
+
--_fade-right: var(--_scroll-area-fade-inline-start);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* ── Which axes scroll ──────────────────────────────────────────────────
|
|
215
|
+
*
|
|
216
|
+
* The physical pair is declared first and the logical pair after it. A
|
|
217
|
+
* browser that does not know `overflow-block` drops those two declarations
|
|
218
|
+
* and keeps the physical ones; a browser that does takes the later pair,
|
|
219
|
+
* which is the one that stays correct in a vertical writing mode. No
|
|
220
|
+
* `@supports` is needed for that — an unknown declaration is discarded at
|
|
221
|
+
* parse time and the cascade does the rest.
|
|
222
|
+
*/
|
|
223
|
+
[data-ui='scroll-area'][data-axis='block'] > [data-part='viewport'] {
|
|
224
|
+
overflow-x: hidden;
|
|
225
|
+
overflow-y: auto;
|
|
226
|
+
overflow-inline: hidden;
|
|
227
|
+
overflow-block: auto;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
[data-ui='scroll-area'][data-axis='inline'] > [data-part='viewport'] {
|
|
231
|
+
overflow-x: auto;
|
|
232
|
+
overflow-y: hidden;
|
|
233
|
+
overflow-inline: auto;
|
|
234
|
+
overflow-block: hidden;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
[data-ui='scroll-area'][data-axis='both'] > [data-part='viewport'] {
|
|
238
|
+
overflow: auto;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* `always` is `overflow: scroll`, which is the platform's own way of saying
|
|
243
|
+
* "reserve the bar whether or not it is needed". It is stated per axis so it
|
|
244
|
+
* does not turn a one-axis area into a two-axis one.
|
|
245
|
+
*/
|
|
246
|
+
[data-ui='scroll-area'][data-scrollbars='always'][data-axis='block'] > [data-part='viewport'] {
|
|
247
|
+
overflow-y: scroll;
|
|
248
|
+
overflow-block: scroll;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
[data-ui='scroll-area'][data-scrollbars='always'][data-axis='inline'] > [data-part='viewport'] {
|
|
252
|
+
overflow-x: scroll;
|
|
253
|
+
overflow-inline: scroll;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
[data-ui='scroll-area'][data-scrollbars='always'][data-axis='both'] > [data-part='viewport'] {
|
|
257
|
+
overflow: scroll;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* `none` removes the bar and nothing else: the content still scrolls by
|
|
262
|
+
* wheel, by touch, by keyboard and by `scrollTo`.
|
|
263
|
+
*
|
|
264
|
+
* `docs/component-features.md` §4 warns against it where the scrollbar is how
|
|
265
|
+
* the reader discovers there is more — which is why the veil is the default
|
|
266
|
+
* and why this value is worth having at all: an area with no bar and no veil
|
|
267
|
+
* says nothing.
|
|
268
|
+
*/
|
|
269
|
+
[data-ui='scroll-area'][data-scrollbars='none'] > [data-part='viewport'] {
|
|
270
|
+
scrollbar-width: none;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* `hover` paints the bar transparent until a pointer or the keyboard is
|
|
275
|
+
* inside. It is the CSS half of what Radix and Mantine spend a timer on, and
|
|
276
|
+
* the gutter stays reserved underneath so nothing moves when the bar appears.
|
|
277
|
+
*
|
|
278
|
+
* The `:not([data-disabled])` guard is the repository rule for every weak
|
|
279
|
+
* state — `packages/styles/src/states.test.mjs` — rather than a state this
|
|
280
|
+
* family holds: a scrollport is not a control and has no disabled form.
|
|
281
|
+
*/
|
|
282
|
+
[data-ui='scroll-area'][data-scrollbars='hover'] > [data-part='viewport'] {
|
|
283
|
+
scrollbar-color: transparent transparent;
|
|
284
|
+
transition:
|
|
285
|
+
scrollbar-color var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
286
|
+
--_scroll-area-fade-block-start var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
287
|
+
--_scroll-area-fade-block-end var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
288
|
+
--_scroll-area-fade-inline-start var(--slotted-duration-short) var(--slotted-easing-standard),
|
|
289
|
+
--_scroll-area-fade-inline-end var(--slotted-duration-short) var(--slotted-easing-standard);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
[data-ui='scroll-area'][data-scrollbars='hover']:not([data-disabled]):hover
|
|
293
|
+
> [data-part='viewport'],
|
|
294
|
+
[data-ui='scroll-area'][data-scrollbars='hover']:focus-within > [data-part='viewport'] {
|
|
295
|
+
scrollbar-color: var(--_thumb) var(--_track);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/* ── The gutter ────────────────────────────────────────────────────────── */
|
|
299
|
+
|
|
300
|
+
[data-ui='scroll-area'][data-gutter='auto'] > [data-part='viewport'] {
|
|
301
|
+
scrollbar-gutter: auto;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
[data-ui='scroll-area'][data-gutter='both-edges'] > [data-part='viewport'] {
|
|
305
|
+
scrollbar-gutter: stable both-edges;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/* ── Scroll chaining ───────────────────────────────────────────────────── */
|
|
309
|
+
|
|
310
|
+
[data-ui='scroll-area'][data-overscroll='auto'] > [data-part='viewport'] {
|
|
311
|
+
overscroll-behavior: auto;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
[data-ui='scroll-area'][data-overscroll='none'] > [data-part='viewport'] {
|
|
315
|
+
overscroll-behavior: none;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Chaining is held back only on the axes the area scrolls. An axis it does
|
|
320
|
+
* not scroll is still an axis of a scroll container — `overflow: hidden` is
|
|
321
|
+
* one — and under `contain` Chrome kept the page's wheel inside a one-line
|
|
322
|
+
* code block. These come after the two above, so a chosen `none` holds the
|
|
323
|
+
* scrolling axis and lets the other through.
|
|
324
|
+
*/
|
|
325
|
+
[data-ui='scroll-area'][data-axis='inline'] > [data-part='viewport'] {
|
|
326
|
+
overscroll-behavior-y: auto;
|
|
327
|
+
overscroll-behavior-block: auto;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
[data-ui='scroll-area'][data-axis='block'] > [data-part='viewport'] {
|
|
331
|
+
overscroll-behavior-x: auto;
|
|
332
|
+
overscroll-behavior-inline: auto;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* ── The veil, edge by edge ────────────────────────────────────────────── */
|
|
336
|
+
|
|
337
|
+
[data-ui='scroll-area'][data-at-block-start] > [data-part='viewport'] {
|
|
338
|
+
--_scroll-area-fade-block-start: 0px;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
[data-ui='scroll-area'][data-at-block-end] > [data-part='viewport'] {
|
|
342
|
+
--_scroll-area-fade-block-end: 0px;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
[data-ui='scroll-area'][data-at-inline-start] > [data-part='viewport'] {
|
|
346
|
+
--_scroll-area-fade-inline-start: 0px;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
[data-ui='scroll-area'][data-at-inline-end] > [data-part='viewport'] {
|
|
350
|
+
--_scroll-area-fade-inline-end: 0px;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* `end` veils only the edges there is more content *toward*. The start of a
|
|
355
|
+
* scroller holds what the reader has already passed, and a product that
|
|
356
|
+
* would rather not dim it says so here.
|
|
357
|
+
*/
|
|
358
|
+
[data-ui='scroll-area'][data-fade='end'] > [data-part='viewport'] {
|
|
359
|
+
--_scroll-area-fade-block-start: 0px;
|
|
360
|
+
--_scroll-area-fade-inline-start: 0px;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* No veil at all, and no mask either: a mask with nothing to hide still puts
|
|
365
|
+
* the element on its own compositing layer, and a long list pays for that on
|
|
366
|
+
* every frame.
|
|
367
|
+
*/
|
|
368
|
+
[data-ui='scroll-area'][data-fade='none'] > [data-part='viewport'],
|
|
369
|
+
/**
|
|
370
|
+
* A vertical writing mode turns the box, and a gradient cannot be given a
|
|
371
|
+
* logical direction. Rather than veil the wrong two edges, the family veils
|
|
372
|
+
* none: the four attributes stay correct, so a consumer who wants the
|
|
373
|
+
* affordance there draws it from them. The binding writes `data-sideways`
|
|
374
|
+
* because only script can read a writing mode.
|
|
375
|
+
*/
|
|
376
|
+
[data-ui='scroll-area'][data-sideways] > [data-part='viewport'] {
|
|
377
|
+
mask-image: none;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/* ── The inset that scrolls with the content ───────────────────────────── */
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Padding on a scrollport is not applied at the end edge of its scrollable
|
|
384
|
+
* overflow in every engine, so an inset that has to survive a scroll to the
|
|
385
|
+
* end goes on an element inside it. The part carries one by default — the
|
|
386
|
+
* step a card's own inset takes — because nearly every area wants one and a
|
|
387
|
+
* part that only held the consumer's padding would be a part nobody used.
|
|
388
|
+
* A consumer whose content carries its own inset renders no `content` at
|
|
389
|
+
* all, or sets the token to nought.
|
|
390
|
+
*
|
|
391
|
+
* `min-inline-size: fit-content` so a row wider than the scrollport widens
|
|
392
|
+
* this box with it, and the inset survives at the far end.
|
|
393
|
+
*/
|
|
394
|
+
[data-ui='scroll-area'] > [data-part='viewport'] > [data-part='content'] {
|
|
395
|
+
box-sizing: border-box;
|
|
396
|
+
min-inline-size: fit-content;
|
|
397
|
+
padding: var(--slotted-scroll-area-inset, var(--slotted-space-5, 0.75rem));
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* ── Focus ─────────────────────────────────────────────────────────────── */
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* The scrollport is what takes focus, and the **root** is what draws the ring.
|
|
404
|
+
*
|
|
405
|
+
* Drawn on the scrollport, the ring was cut: an outline is part of what the
|
|
406
|
+
* element paints, so the veil fades it exactly where the veil is — the
|
|
407
|
+
* capture showed a ring crisp down both sides and gone across the bottom,
|
|
408
|
+
* which is a focus indicator that disappears on the edge the reader is moving
|
|
409
|
+
* toward. A focus ring is the last thing that may be half-drawn.
|
|
410
|
+
*
|
|
411
|
+
* `:has()` rather than `:focus-within`, because a link inside the content is
|
|
412
|
+
* focus *within* the area and is not the area being focused.
|
|
413
|
+
*/
|
|
414
|
+
[data-ui='scroll-area']:has(> [data-part='viewport']:focus-visible) {
|
|
415
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
416
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/* ── Paper ─────────────────────────────────────────────────────────────── */
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* A printed page carries the whole content, not the slice that happened to
|
|
423
|
+
* be in view. None of the five surveyed implementations answers this, and
|
|
424
|
+
* `docs/component-features.md` §4 names printing in this family's own
|
|
425
|
+
* sentence.
|
|
426
|
+
*/
|
|
427
|
+
@media print {
|
|
428
|
+
[data-ui='scroll-area'],
|
|
429
|
+
[data-ui='scroll-area'] > [data-part='viewport'] {
|
|
430
|
+
max-block-size: none;
|
|
431
|
+
max-inline-size: none;
|
|
432
|
+
overflow: visible;
|
|
433
|
+
mask-image: none;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* The system owns the palette under forced colours, and a veil over system
|
|
439
|
+
* text is a legibility loss with nothing bought. The scrollbar goes back to
|
|
440
|
+
* the system's own, which is what `scrollbar-color: auto` means.
|
|
441
|
+
*/
|
|
442
|
+
@media (forced-colors: active) {
|
|
443
|
+
[data-ui='scroll-area'] > [data-part='viewport'] {
|
|
444
|
+
mask-image: none;
|
|
445
|
+
scrollbar-color: auto;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* The four lengths are registered so they interpolate. An unregistered custom
|
|
452
|
+
* property animates discretely — it would snap from nothing to the full reach —
|
|
453
|
+
* and `@property` is what gives one a type the browser can move through.
|
|
454
|
+
*
|
|
455
|
+
* These sit outside `@layer slotted.components` because `@property` is not a
|
|
456
|
+
* rule a cascade layer holds; it is a registration, and the layer would only
|
|
457
|
+
* hide it.
|
|
458
|
+
*/
|
|
459
|
+
@property --_scroll-area-fade-block-start {
|
|
460
|
+
syntax: '<length-percentage>';
|
|
461
|
+
inherits: false;
|
|
462
|
+
initial-value: 0px;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
@property --_scroll-area-fade-block-end {
|
|
466
|
+
syntax: '<length-percentage>';
|
|
467
|
+
inherits: false;
|
|
468
|
+
initial-value: 0px;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
@property --_scroll-area-fade-inline-start {
|
|
472
|
+
syntax: '<length-percentage>';
|
|
473
|
+
inherits: false;
|
|
474
|
+
initial-value: 0px;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
@property --_scroll-area-fade-inline-end {
|
|
478
|
+
syntax: '<length-percentage>';
|
|
479
|
+
inherits: false;
|
|
480
|
+
initial-value: 0px;
|
|
481
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[
|
|
2
|
+
"--slotted-border-strong",
|
|
3
|
+
"--slotted-duration-short",
|
|
4
|
+
"--slotted-easing-standard",
|
|
5
|
+
"--slotted-focus-ring-color",
|
|
6
|
+
"--slotted-focus-ring-offset",
|
|
7
|
+
"--slotted-focus-ring-width",
|
|
8
|
+
"--slotted-scroll-area-fade-size",
|
|
9
|
+
"--slotted-scroll-area-inset",
|
|
10
|
+
"--slotted-scroll-area-thumb-color",
|
|
11
|
+
"--slotted-scroll-area-track-color",
|
|
12
|
+
"--slotted-space-5",
|
|
13
|
+
"--slotted-space-8",
|
|
14
|
+
"--slotted-surface-sunken"
|
|
15
|
+
]
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
@layer slotted.components {
|
|
2
|
+
/**
|
|
3
|
+
* One unit of content inside a page: a header — eyebrow, heading,
|
|
4
|
+
* description, actions — and a body one outline step deeper.
|
|
5
|
+
*
|
|
6
|
+
* ┌──────────────────────────────────────┬──────────┐
|
|
7
|
+
* │ header ▸ title ▸ eyebrow │ actions │
|
|
8
|
+
* │ heading │ │
|
|
9
|
+
* │ description │ │
|
|
10
|
+
* ├──────────────────────────────────────┴──────────┤
|
|
11
|
+
* │ body │
|
|
12
|
+
* └─────────────────────────────────────────────────┘
|
|
13
|
+
*
|
|
14
|
+
* Every part is reached with a child combinator, because a section holds
|
|
15
|
+
* sections, and the families inside it — a card, a description-list — have
|
|
16
|
+
* a `header`, an `actions` and a `description` of their own.
|
|
17
|
+
*/
|
|
18
|
+
[data-ui='section'] {
|
|
19
|
+
--_gap: var(--slotted-section-gap, var(--slotted-space-5, 0.75rem));
|
|
20
|
+
--_text: var(--slotted-text, CanvasText);
|
|
21
|
+
--_muted: var(--slotted-text-muted, GrayText);
|
|
22
|
+
--_rule: var(--slotted-section-border, var(--slotted-border-subtle, ButtonBorder));
|
|
23
|
+
--_heading-size: var(--slotted-section-heading-size-md, var(--slotted-font-size-lg, 1rem));
|
|
24
|
+
--_heading-line-height: var(--slotted-line-height-lg, 1.5);
|
|
25
|
+
/**
|
|
26
|
+
* The ground a sticky header paints, so the content passing under it is
|
|
27
|
+
* covered rather than read through. The page states its own ground in
|
|
28
|
+
* `--slotted-page-ground`; outside a page, the surface.
|
|
29
|
+
*/
|
|
30
|
+
--_ground: var(--slotted-page-ground, var(--slotted-surface, Canvas));
|
|
31
|
+
|
|
32
|
+
color: var(--_text);
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
font-family: var(--slotted-font-family-sans, ui-sans-serif, system-ui, sans-serif);
|
|
36
|
+
gap: var(--_gap);
|
|
37
|
+
min-inline-size: 0;
|
|
38
|
+
/**
|
|
39
|
+
* A hash link to this section lands under the page's fixed chrome rather
|
|
40
|
+
* than behind it. Absent a page, nothing is subtracted.
|
|
41
|
+
*/
|
|
42
|
+
scroll-margin-block-start: var(--slotted-page-sticky-top, 0px);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
[data-ui='section'][data-size='sm'] {
|
|
46
|
+
--_heading-size: var(--slotted-section-heading-size-sm, var(--slotted-font-size-md, 0.875rem));
|
|
47
|
+
--_heading-line-height: var(--slotted-line-height-md, 1.5);
|
|
48
|
+
}
|
|
49
|
+
[data-ui='section'][data-size='lg'] {
|
|
50
|
+
--_heading-size: var(--slotted-section-heading-size-lg, var(--slotted-font-size-xl, 1.125rem));
|
|
51
|
+
--_heading-line-height: var(--slotted-line-height-xl, 1.45);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A surface and not a card: a raised ground, a subtle edge, the large
|
|
56
|
+
* radius, one step of inset, and no shadow, no hover, no action.
|
|
57
|
+
*/
|
|
58
|
+
[data-ui='section'][data-ground='surface'] {
|
|
59
|
+
--_ground: var(--slotted-section-surface, var(--slotted-surface-raised, Canvas));
|
|
60
|
+
/* Published, as a card's is, for the families that state a ground inside it. */
|
|
61
|
+
--slotted-ground: var(--_ground);
|
|
62
|
+
background-color: var(--_ground);
|
|
63
|
+
border: var(--slotted-border-width-thin, 1px) solid var(--_rule);
|
|
64
|
+
border-radius: var(--slotted-section-radius, var(--slotted-radius-lg, 8px));
|
|
65
|
+
padding: var(--slotted-section-inset, var(--slotted-space-6, 1rem));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* ── The header ──────────────────────────────────────────────────────── */
|
|
69
|
+
|
|
70
|
+
[data-ui='section'] > [data-part='header'] {
|
|
71
|
+
align-items: flex-start;
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-wrap: wrap;
|
|
74
|
+
gap: var(--slotted-space-3, 0.375rem) var(--slotted-space-6, 1rem);
|
|
75
|
+
min-inline-size: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
[data-ui='section'][data-divider] > [data-part='header'] {
|
|
79
|
+
border-block-end: var(--slotted-border-width-thin, 1px) solid var(--_rule);
|
|
80
|
+
padding-block-end: var(--slotted-space-4, 0.5rem);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Under the page chrome, and painted, so what scrolls under it is covered.
|
|
85
|
+
* The inset a surface section gives its header is kept by sticking the
|
|
86
|
+
* header at the same distance the surface's padding put it at.
|
|
87
|
+
*/
|
|
88
|
+
[data-ui='section'][data-sticky] > [data-part='header'] {
|
|
89
|
+
background-color: var(--_ground);
|
|
90
|
+
inset-block-start: var(--slotted-page-sticky-top, 0px);
|
|
91
|
+
/* Stuck, the header's text and buttons met the chrome's edge with no
|
|
92
|
+
air. The padding gives it, and the negative margin takes the same
|
|
93
|
+
distance back at rest, so the header stands where it stood; the ground
|
|
94
|
+
it paints there is the page's own, so nothing shows. */
|
|
95
|
+
margin-block-start: calc(-1 * var(--slotted-space-4, 0.5rem));
|
|
96
|
+
padding-block-start: var(--slotted-space-4, 0.5rem);
|
|
97
|
+
position: sticky;
|
|
98
|
+
z-index: var(--slotted-z-index-sticky, 100);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* A sticky header is chrome for what is under it, so the body republishes
|
|
103
|
+
* where the chrome ends: the page's own value, read once on the root under
|
|
104
|
+
* a name of its own, plus the header's measured height. A table's column
|
|
105
|
+
* header, a nested section's header or a consumer's sticky aside inside
|
|
106
|
+
* the body reads the same property and stops under this header rather
|
|
107
|
+
* than under the page's; nested layers add up, one section inside another.
|
|
108
|
+
* The alias on the root is what keeps the redefinition from referring to
|
|
109
|
+
* itself.
|
|
110
|
+
*/
|
|
111
|
+
[data-ui='section'][data-sticky] {
|
|
112
|
+
--_above: var(--slotted-page-sticky-top, 0px);
|
|
113
|
+
}
|
|
114
|
+
[data-ui='section'][data-sticky] > [data-part='body'] {
|
|
115
|
+
--slotted-page-sticky-top: calc(var(--_above) + var(--slotted-section-header-size, 0px));
|
|
116
|
+
--slotted-table-sticky-offset: var(--slotted-page-sticky-top);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
[data-ui='section'] > [data-part='header'] > [data-part='title'] {
|
|
120
|
+
display: flex;
|
|
121
|
+
flex: 1 1 16rem;
|
|
122
|
+
flex-direction: column;
|
|
123
|
+
gap: var(--slotted-space-1, 0.125rem);
|
|
124
|
+
min-inline-size: 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[data-ui='section'] > [data-part='header'] > [data-part='title'] > [data-part='eyebrow'] {
|
|
128
|
+
color: var(--_muted);
|
|
129
|
+
font-size: var(--slotted-font-size-xs, 0.75rem);
|
|
130
|
+
font-weight: var(--slotted-font-weight-semibold, 600);
|
|
131
|
+
letter-spacing: 0.06em;
|
|
132
|
+
line-height: var(--slotted-line-height-xs, 1.4);
|
|
133
|
+
text-transform: uppercase;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
[data-ui='section'] > [data-part='header'] > [data-part='title'] > [data-part='heading'] {
|
|
137
|
+
color: var(--_text);
|
|
138
|
+
font-family: var(
|
|
139
|
+
--slotted-font-family-heading,
|
|
140
|
+
var(--slotted-font-family-sans, ui-sans-serif, system-ui, sans-serif)
|
|
141
|
+
);
|
|
142
|
+
font-size: var(--_heading-size);
|
|
143
|
+
font-weight: var(--slotted-font-weight-semibold, 600);
|
|
144
|
+
letter-spacing: -0.01em;
|
|
145
|
+
line-height: var(--_heading-line-height);
|
|
146
|
+
margin: 0;
|
|
147
|
+
min-inline-size: 0;
|
|
148
|
+
overflow-wrap: anywhere;
|
|
149
|
+
text-wrap: pretty;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
[data-ui='section'] > [data-part='header'] > [data-part='title'] > [data-part='description'] {
|
|
153
|
+
color: var(--_muted);
|
|
154
|
+
font-size: var(--slotted-font-size-sm, 0.8125rem);
|
|
155
|
+
line-height: var(--slotted-line-height-sm, 1.45);
|
|
156
|
+
margin: 0;
|
|
157
|
+
max-inline-size: var(--slotted-section-description-measure, 70ch);
|
|
158
|
+
text-wrap: pretty;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
[data-ui='section'] > [data-part='header'] > [data-part='actions'] {
|
|
162
|
+
align-items: center;
|
|
163
|
+
display: flex;
|
|
164
|
+
flex: none;
|
|
165
|
+
gap: var(--slotted-control-gap-md, 8px);
|
|
166
|
+
margin-inline-start: auto;
|
|
167
|
+
}
|
|
168
|
+
[data-ui='section'] > [data-part='header'] > [data-part='actions']:empty {
|
|
169
|
+
display: none;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* ── The body ────────────────────────────────────────────────────────── */
|
|
173
|
+
|
|
174
|
+
[data-ui='section'] > [data-part='body'] {
|
|
175
|
+
min-inline-size: 0;
|
|
176
|
+
}
|
|
177
|
+
}
|