@slotted/styles 0.0.0-stage → 0.1.0-beta.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/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,860 @@
|
|
|
1
|
+
@layer slotted.components {
|
|
2
|
+
/**
|
|
3
|
+
* A set of slides shown a page at a time, and the controls that move it.
|
|
4
|
+
*
|
|
5
|
+
* The root is a one-cell grid, and every control written as its direct child
|
|
6
|
+
* is placed in that cell over the viewport rather than positioned over it:
|
|
7
|
+
* the previous and next controls sit on the two ends of the axis, the bar
|
|
8
|
+
* at the foot. A control written inside `controls` takes the bar's row
|
|
9
|
+
* instead. Where a control stands is therefore where the consumer wrote it,
|
|
10
|
+
* and no prop restates it.
|
|
11
|
+
*
|
|
12
|
+
* ┌────────────────────────────────────────┐
|
|
13
|
+
* │ ◀ viewport ▶ │ arrows="inset"
|
|
14
|
+
* │ ● ━━ ● ● │ controls placement="overlay"
|
|
15
|
+
* └────────────────────────────────────────┘
|
|
16
|
+
* ⏸ ◀ ● ━━ ● ● ▶ 2 / 4 controls placement="below"
|
|
17
|
+
*/
|
|
18
|
+
[data-ui='carousel'] {
|
|
19
|
+
--_control-size: var(--slotted-control-height-md, 34px);
|
|
20
|
+
--_icon-size: var(--slotted-control-icon-size-md, 16px);
|
|
21
|
+
--_gap: var(--slotted-carousel-gap, var(--slotted-space-6, 1rem));
|
|
22
|
+
--_peek: var(--slotted-carousel-peek, 0px);
|
|
23
|
+
--_per-view: var(--slotted-carousel-slides-per-view, 1);
|
|
24
|
+
--_radius: var(--slotted-carousel-radius, var(--slotted-radius-lg, 8px));
|
|
25
|
+
/**
|
|
26
|
+
* How far an inset control stands from the viewport's edge: one step of
|
|
27
|
+
* air past the ring, so a focused control's ring never touches the edge it
|
|
28
|
+
* is drawn against.
|
|
29
|
+
*/
|
|
30
|
+
--_inset: var(--slotted-space-5, 0.75rem);
|
|
31
|
+
/**
|
|
32
|
+
* The scroll the engine animates runs on a critically damped spring whose
|
|
33
|
+
* stiffness is read from this duration in the viewport's computed style,
|
|
34
|
+
* so the theme's motion scale — and its collapse to an instant under
|
|
35
|
+
* reduced motion — reaches a movement no `transition` describes. At this
|
|
36
|
+
* duration less than one per cent of the way is left; the spring carries
|
|
37
|
+
* the speed of the hand that let go, which no easing curve can.
|
|
38
|
+
*/
|
|
39
|
+
--_scroll-duration: var(--slotted-carousel-duration, var(--slotted-duration-long));
|
|
40
|
+
/**
|
|
41
|
+
* A dot, and the bar the current dot stretches into. The bar is three dots
|
|
42
|
+
* long so it reads as a different shape, not a bigger dot: shape, not
|
|
43
|
+
* colour alone, says which page is shown (WCAG 1.4.1).
|
|
44
|
+
*/
|
|
45
|
+
--_dot: var(--slotted-space-4, 0.5rem);
|
|
46
|
+
--_dot-current: var(--slotted-space-8, 1.5rem);
|
|
47
|
+
--_dot-air: var(--slotted-space-3, 0.375rem);
|
|
48
|
+
--_line: var(--slotted-border-width-thick, 2px);
|
|
49
|
+
--_thumbnail: var(--slotted-carousel-thumbnail-size, var(--slotted-space-12, 4rem));
|
|
50
|
+
|
|
51
|
+
display: grid;
|
|
52
|
+
grid-template-columns: minmax(0, 1fr);
|
|
53
|
+
grid-template-rows: auto;
|
|
54
|
+
min-inline-size: 0;
|
|
55
|
+
row-gap: var(--slotted-carousel-controls-gap, var(--slotted-space-5, 0.75rem));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[data-ui='carousel'][data-size='sm'] {
|
|
59
|
+
--_control-size: var(--slotted-control-height-sm, 30px);
|
|
60
|
+
--_icon-size: var(--slotted-control-icon-size-sm, 14px);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
[data-ui='carousel'][data-size='lg'] {
|
|
64
|
+
--_control-size: var(--slotted-control-height-lg, 38px);
|
|
65
|
+
--_icon-size: var(--slotted-control-icon-size-lg, 18px);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Outside the viewport the two controls take columns of their own, so a row
|
|
70
|
+
* of cards keeps its whole width for cards and no arrow covers the first
|
|
71
|
+
* one's corner — ReUI's `-left-12`, measured at 48 pixels outside the
|
|
72
|
+
* viewport, without the absolute positioning that puts it outside the
|
|
73
|
+
* component's box.
|
|
74
|
+
*/
|
|
75
|
+
[data-ui='carousel'][data-arrows='outside'] {
|
|
76
|
+
column-gap: var(--slotted-space-4, 0.5rem);
|
|
77
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* ── The viewport ─────────────────────────────────────────────────────── */
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The scroller, and the one element the family moves. Touch, a trackpad and
|
|
84
|
+
* the keyboard scroll it natively and snap does the paging, so the family
|
|
85
|
+
* works before any script and a swipe is the platform's own swipe. The
|
|
86
|
+
* slides are grid columns sized from the slides-per-view count, so a
|
|
87
|
+
* container query that writes `--slotted-carousel-slides-per-view` changes
|
|
88
|
+
* the layout and the engine reads the new pages from it.
|
|
89
|
+
*/
|
|
90
|
+
[data-ui='carousel'] > [data-part='viewport'] {
|
|
91
|
+
/**
|
|
92
|
+
* The share of the row a slide takes, never below the slide's own floor:
|
|
93
|
+
* three cards per view at 240 pixels are 64-pixel cards, and the floor
|
|
94
|
+
* turns the same carousel into one card and the edge of the next. The
|
|
95
|
+
* engine reads the pages from the boxes, so the floor needs no script.
|
|
96
|
+
*/
|
|
97
|
+
--_track: max(
|
|
98
|
+
var(--slotted-carousel-slide-min-size, 0px),
|
|
99
|
+
calc((100% - (var(--_per-view) - 1) * var(--_gap)) / var(--_per-view))
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
border-radius: var(--_radius);
|
|
103
|
+
display: grid;
|
|
104
|
+
gap: var(--_gap);
|
|
105
|
+
grid-area: 1 / 1;
|
|
106
|
+
grid-auto-columns: var(--_track);
|
|
107
|
+
grid-auto-flow: column;
|
|
108
|
+
min-inline-size: 0;
|
|
109
|
+
outline: none;
|
|
110
|
+
overflow-x: auto;
|
|
111
|
+
overflow-y: hidden;
|
|
112
|
+
overscroll-behavior-inline: contain;
|
|
113
|
+
padding-inline: var(--_peek);
|
|
114
|
+
scroll-behavior: auto;
|
|
115
|
+
scroll-padding-inline: var(--_peek);
|
|
116
|
+
scroll-snap-type: x mandatory;
|
|
117
|
+
/**
|
|
118
|
+
* The scrollbar is not the affordance: the controls and the indicators
|
|
119
|
+
* are, and a scrollbar under a row of slides reads as a page that did not
|
|
120
|
+
* fit. The viewport stays scrollable by touch, trackpad and keyboard.
|
|
121
|
+
*/
|
|
122
|
+
scrollbar-width: none;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
[data-ui='carousel'][data-arrows='outside'] > [data-part='viewport'] {
|
|
126
|
+
grid-area: 1 / 2;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
[data-ui='carousel'] > [data-part='viewport']::-webkit-scrollbar {
|
|
130
|
+
display: none;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
[data-ui='carousel'] > [data-part='viewport']:focus-visible {
|
|
134
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
135
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* While the engine moves the scroll, and while a mouse drags it, snap is
|
|
140
|
+
* off: a snapping scroller pulls every intermediate position back to the
|
|
141
|
+
* nearest page. The engine writes `data-moving` in the same task as the
|
|
142
|
+
* movement — the root's `data-dragging` comes from a framework render a
|
|
143
|
+
* frame later, and the first frames of a drag were snapped back under the
|
|
144
|
+
* pointer. Both movements end exactly on a page, so snap returns without
|
|
145
|
+
* moving anything.
|
|
146
|
+
*/
|
|
147
|
+
[data-ui='carousel'] > [data-part='viewport'][data-moving] {
|
|
148
|
+
scroll-snap-type: none;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* A mouse can drag the row, and the cursor says so before the press. The
|
|
153
|
+
* rule is gated on a fine pointer: a finger drags the scroller natively and
|
|
154
|
+
* has no cursor to change.
|
|
155
|
+
*/
|
|
156
|
+
@media (hover: hover) and (pointer: fine) {
|
|
157
|
+
[data-ui='carousel'][data-draggable]:not([data-transition='fade']) > [data-part='viewport'] {
|
|
158
|
+
cursor: grab;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
[data-ui='carousel'][data-dragging] > [data-part='viewport'] {
|
|
163
|
+
cursor: grabbing;
|
|
164
|
+
user-select: none;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** A picture inside a draggable row would otherwise start the browser's own image drag. */
|
|
168
|
+
[data-ui='carousel'][data-draggable] > [data-part='viewport'] img {
|
|
169
|
+
-webkit-user-drag: none;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
[data-ui='carousel'][data-orientation='vertical'] > [data-part='viewport'] {
|
|
173
|
+
/**
|
|
174
|
+
* A column of slides needs a height to divide, and the content cannot
|
|
175
|
+
* give one: the tallest slide would make the viewport as tall as the
|
|
176
|
+
* column. Twenty rem is a card and a half at comfortable density.
|
|
177
|
+
*/
|
|
178
|
+
block-size: var(--slotted-carousel-viewport-size, 20rem);
|
|
179
|
+
grid-auto-columns: 100%;
|
|
180
|
+
grid-auto-flow: row;
|
|
181
|
+
grid-auto-rows: calc((100% - (var(--_per-view) - 1) * var(--_gap)) / var(--_per-view));
|
|
182
|
+
overflow-x: hidden;
|
|
183
|
+
overflow-y: auto;
|
|
184
|
+
overscroll-behavior-block: contain;
|
|
185
|
+
padding-block: var(--_peek);
|
|
186
|
+
padding-inline: 0;
|
|
187
|
+
scroll-padding-block: var(--_peek);
|
|
188
|
+
scroll-padding-inline: 0;
|
|
189
|
+
scroll-snap-type: y mandatory;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* ── The slides ───────────────────────────────────────────────────────── */
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* A scroller cannot go past its ends, so a drag that pulls past one moves
|
|
196
|
+
* the slides instead, by the distance the engine writes as
|
|
197
|
+
* `--slotted-carousel-overscroll` — less and less the further the hand
|
|
198
|
+
* goes — and springs it back to nothing on release.
|
|
199
|
+
*/
|
|
200
|
+
[data-ui='carousel'] > [data-part='viewport'] > [data-part='slide'] {
|
|
201
|
+
min-block-size: 0;
|
|
202
|
+
min-inline-size: 0;
|
|
203
|
+
position: relative;
|
|
204
|
+
scroll-snap-align: start;
|
|
205
|
+
translate: var(--slotted-carousel-overscroll, none);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
[data-ui='carousel'][data-align='center'] > [data-part='viewport'] > [data-part='slide'] {
|
|
209
|
+
scroll-snap-align: center;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Once the engine has read the pages, only a slide a page starts at is a
|
|
214
|
+
* snap point. Before that every slide is one, which is the right paging for
|
|
215
|
+
* a server response and for one slide per view.
|
|
216
|
+
*/
|
|
217
|
+
[data-ui='carousel'][data-measured]
|
|
218
|
+
> [data-part='viewport']
|
|
219
|
+
> [data-part='slide']:not([data-snap]) {
|
|
220
|
+
scroll-snap-align: none;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* ── Fade ───────────────────────────────────────────────────────────────
|
|
225
|
+
*
|
|
226
|
+
* The slides are stacked in one cell and only the current one is shown.
|
|
227
|
+
* The viewport does not scroll, so a finger's horizontal swipe is the
|
|
228
|
+
* family's and a vertical one stays the page's.
|
|
229
|
+
*
|
|
230
|
+
* The arriving slide fades in on the enter curve over the long step; the
|
|
231
|
+
* leaving one fades out on the exit curve over the medium step, so the exit
|
|
232
|
+
* is never slower than the enter. The two overlap for the medium step
|
|
233
|
+
* rather than following each other, which keeps the cell from going empty
|
|
234
|
+
* between them. `visibility` interpolates as visible while either end is,
|
|
235
|
+
* so it hides the leaving slide when its fade ends and nothing in it can be
|
|
236
|
+
* reached once it is gone.
|
|
237
|
+
*/
|
|
238
|
+
[data-ui='carousel'][data-transition='fade'] > [data-part='viewport'] {
|
|
239
|
+
grid-auto-columns: 100%;
|
|
240
|
+
grid-template-areas: 'stack';
|
|
241
|
+
overflow: hidden;
|
|
242
|
+
scroll-snap-type: none;
|
|
243
|
+
touch-action: pan-y;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
[data-ui='carousel'][data-transition='fade'] > [data-part='viewport'] > [data-part='slide'] {
|
|
247
|
+
grid-area: stack;
|
|
248
|
+
opacity: 0;
|
|
249
|
+
transition:
|
|
250
|
+
opacity var(--slotted-duration-medium) var(--slotted-easing-exit, ease-in),
|
|
251
|
+
visibility var(--slotted-duration-medium) linear;
|
|
252
|
+
visibility: hidden;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
[data-ui='carousel'][data-transition='fade']
|
|
256
|
+
> [data-part='viewport']
|
|
257
|
+
> [data-part='slide'][data-current] {
|
|
258
|
+
opacity: 1;
|
|
259
|
+
transition:
|
|
260
|
+
opacity var(--slotted-duration-long) var(--slotted-easing-enter, ease-out),
|
|
261
|
+
visibility var(--slotted-duration-long) linear;
|
|
262
|
+
visibility: visible;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* ── Previous, next and the rotation control ──────────────────────────── */
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* One round control for all three, on the raised surface with the control
|
|
269
|
+
* shadow, because the inset pair stands over a picture and has to read as
|
|
270
|
+
* a thing on top of it in both schemes. ReUI measures 28 pixels with a
|
|
271
|
+
* 16-pixel mark; the family takes the control scale, 34 at `md`, so the
|
|
272
|
+
* pair is a step larger than the dots and matches a toolbar's buttons.
|
|
273
|
+
*/
|
|
274
|
+
[data-ui='carousel'] [data-part='previous'],
|
|
275
|
+
[data-ui='carousel'] [data-part='next'],
|
|
276
|
+
[data-ui='carousel'] [data-part='autoplay'] {
|
|
277
|
+
--slotted-icon-size: var(--_icon-size);
|
|
278
|
+
|
|
279
|
+
align-items: center;
|
|
280
|
+
appearance: none;
|
|
281
|
+
background: var(--slotted-control-surface, Field);
|
|
282
|
+
block-size: var(--_control-size);
|
|
283
|
+
border: var(--slotted-control-border-width, 1px) solid
|
|
284
|
+
var(--slotted-control-border-color, ButtonBorder);
|
|
285
|
+
border-radius: var(--slotted-radius-full, 9999px);
|
|
286
|
+
box-shadow: var(--slotted-control-shadow, none);
|
|
287
|
+
color: var(--slotted-text, ButtonText);
|
|
288
|
+
cursor: pointer;
|
|
289
|
+
display: inline-flex;
|
|
290
|
+
flex: none;
|
|
291
|
+
inline-size: var(--_control-size);
|
|
292
|
+
justify-content: center;
|
|
293
|
+
margin: 0;
|
|
294
|
+
padding: 0;
|
|
295
|
+
transition:
|
|
296
|
+
background-color var(--slotted-control-transition-duration)
|
|
297
|
+
var(--slotted-control-transition-easing, ease),
|
|
298
|
+
border-color var(--slotted-control-transition-duration)
|
|
299
|
+
var(--slotted-control-transition-easing, ease),
|
|
300
|
+
box-shadow var(--slotted-control-transition-duration)
|
|
301
|
+
var(--slotted-control-transition-easing, ease),
|
|
302
|
+
color var(--slotted-control-transition-duration)
|
|
303
|
+
var(--slotted-control-transition-easing, ease),
|
|
304
|
+
scale var(--slotted-control-transition-duration)
|
|
305
|
+
var(--slotted-control-transition-easing, ease);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** Over the viewport, at the two ends of its axis. */
|
|
309
|
+
[data-ui='carousel'] > [data-part='previous'],
|
|
310
|
+
[data-ui='carousel'] > [data-part='next'] {
|
|
311
|
+
align-self: center;
|
|
312
|
+
grid-area: 1 / 1;
|
|
313
|
+
margin-inline: var(--_inset);
|
|
314
|
+
z-index: 1;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
[data-ui='carousel'] > [data-part='previous'] {
|
|
318
|
+
justify-self: start;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
[data-ui='carousel'] > [data-part='next'] {
|
|
322
|
+
justify-self: end;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
[data-ui='carousel'][data-arrows='outside'] > [data-part='previous'] {
|
|
326
|
+
grid-area: 1 / 1;
|
|
327
|
+
margin-inline: 0;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
[data-ui='carousel'][data-arrows='outside'] > [data-part='next'] {
|
|
331
|
+
grid-area: 1 / 3;
|
|
332
|
+
margin-inline: 0;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
[data-ui='carousel'][data-orientation='vertical'] > [data-part='previous'],
|
|
336
|
+
[data-ui='carousel'][data-orientation='vertical'] > [data-part='next'] {
|
|
337
|
+
justify-self: center;
|
|
338
|
+
margin-block: var(--_inset);
|
|
339
|
+
margin-inline: 0;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
[data-ui='carousel'][data-orientation='vertical'] > [data-part='previous'] {
|
|
343
|
+
align-self: start;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
[data-ui='carousel'][data-orientation='vertical'] > [data-part='next'] {
|
|
347
|
+
align-self: end;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* The chevron is drawn once, pointing along the reading direction, and the
|
|
352
|
+
* icon box mirrors it in a right-to-left document. Previous turns it round;
|
|
353
|
+
* a vertical carousel turns both a quarter so they point along the column.
|
|
354
|
+
*/
|
|
355
|
+
[data-ui='carousel'] [data-part='previous'] > [data-ui='icon'] {
|
|
356
|
+
rotate: 180deg;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
[data-ui='carousel'][data-orientation='vertical'] [data-part='previous'] > [data-ui='icon'] {
|
|
360
|
+
rotate: -90deg;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
[data-ui='carousel'][data-orientation='vertical'] [data-part='next'] > [data-ui='icon'] {
|
|
364
|
+
rotate: 90deg;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* A column does not run along the reading direction, so a right-to-left
|
|
369
|
+
* document leaves its arrows alone. The icon box mirrors before it turns,
|
|
370
|
+
* and a mirrored chevron turned a quarter points the other way along the
|
|
371
|
+
* column.
|
|
372
|
+
*/
|
|
373
|
+
[data-ui='carousel'][data-orientation='vertical']
|
|
374
|
+
:is([data-part='previous'], [data-part='next'])
|
|
375
|
+
> [data-ui='icon']:dir(rtl) {
|
|
376
|
+
scale: none;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
[data-ui='carousel'] [data-part='previous']:hover:not([data-disabled]):not(:disabled),
|
|
380
|
+
[data-ui='carousel'] [data-part='next']:hover:not([data-disabled]):not(:disabled),
|
|
381
|
+
[data-ui='carousel'] [data-part='autoplay']:hover:not([data-disabled]):not(:disabled) {
|
|
382
|
+
background: var(--slotted-tone-secondary-subtle-hover, ButtonFace);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* A press lands at once and releases at the control's pace. The round
|
|
387
|
+
* control shrinks by six per cent rather than dropping a hairline: a circle
|
|
388
|
+
* standing over a picture has no floor to be put down on, and a scale is
|
|
389
|
+
* the press that reads on a shape with no bottom edge.
|
|
390
|
+
*/
|
|
391
|
+
[data-ui='carousel'] [data-part='previous']:active:not([data-disabled]):not(:disabled),
|
|
392
|
+
[data-ui='carousel'] [data-part='next']:active:not([data-disabled]):not(:disabled),
|
|
393
|
+
[data-ui='carousel'] [data-part='autoplay']:active:not([data-disabled]):not(:disabled) {
|
|
394
|
+
background: var(--slotted-tone-secondary-subtle-active, ButtonFace);
|
|
395
|
+
box-shadow: none;
|
|
396
|
+
scale: 0.94;
|
|
397
|
+
transition-duration: var(--slotted-duration-instant);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
[data-ui='carousel'] [data-part='previous']:focus-visible,
|
|
401
|
+
[data-ui='carousel'] [data-part='next']:focus-visible,
|
|
402
|
+
[data-ui='carousel'] [data-part='autoplay']:focus-visible {
|
|
403
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
404
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* At an end without a loop the control stays where it is and stays
|
|
409
|
+
* focusable — `aria-disabled`, never `disabled`, so the focus it holds is
|
|
410
|
+
* not dropped onto the page — and says it has nowhere to go in the
|
|
411
|
+
* foundation's disabled ink, with its ground kept so it still reads as a
|
|
412
|
+
* control over a picture.
|
|
413
|
+
*/
|
|
414
|
+
[data-ui='carousel'] :is([data-part='previous'], [data-part='next'])[data-disabled] {
|
|
415
|
+
border-color: var(--slotted-disabled-border, GrayText);
|
|
416
|
+
box-shadow: none;
|
|
417
|
+
color: var(--slotted-disabled-foreground, GrayText);
|
|
418
|
+
cursor: default;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/* ── The bar ──────────────────────────────────────────────────────────── */
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* The bar wraps rather than overflows: five dots and a counter are 180
|
|
425
|
+
* pixels, and a carousel in a third of a dashboard is narrower than that.
|
|
426
|
+
* The counter drops under the dots, centred, before anything is clipped.
|
|
427
|
+
*/
|
|
428
|
+
[data-ui='carousel'] > [data-part='controls'] {
|
|
429
|
+
align-items: center;
|
|
430
|
+
display: flex;
|
|
431
|
+
flex-wrap: wrap;
|
|
432
|
+
gap: var(--slotted-space-4, 0.5rem);
|
|
433
|
+
grid-column: 1 / -1;
|
|
434
|
+
justify-content: center;
|
|
435
|
+
min-inline-size: 0;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
[data-ui='carousel'][data-arrows='outside'] > [data-part='controls'] {
|
|
439
|
+
grid-column: 2;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Over the picture, at its foot, on a pill of the raised surface. Solid
|
|
444
|
+
* rather than translucent: the dots are the one thing on the picture that
|
|
445
|
+
* has to read in every scheme, and a ground that lets the picture through
|
|
446
|
+
* gives the dots a different ground on every slide.
|
|
447
|
+
*/
|
|
448
|
+
[data-ui='carousel'] > [data-part='controls'][data-placement='overlay'] {
|
|
449
|
+
align-self: end;
|
|
450
|
+
background: var(--slotted-surface-raised, Canvas);
|
|
451
|
+
border-radius: var(--slotted-radius-full, 9999px);
|
|
452
|
+
box-shadow: var(--slotted-shadow-sm, none);
|
|
453
|
+
gap: var(--slotted-space-2, 0.25rem);
|
|
454
|
+
grid-area: 1 / 1;
|
|
455
|
+
justify-self: center;
|
|
456
|
+
margin-block-end: var(--_inset);
|
|
457
|
+
padding-block: var(--slotted-space-2, 0.25rem);
|
|
458
|
+
padding-inline: var(--slotted-space-3, 0.375rem);
|
|
459
|
+
z-index: 1;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Inside the pill the round controls give their frame to the pill: a
|
|
464
|
+
* bordered circle inside a bordered pill is two edges where one is enough.
|
|
465
|
+
* They take the height the foundation gives the inside of a control, so
|
|
466
|
+
* the pill is that height and a step of air either side of it.
|
|
467
|
+
*/
|
|
468
|
+
[data-ui='carousel']
|
|
469
|
+
> [data-part='controls'][data-placement='overlay']
|
|
470
|
+
> :is([data-part='previous'], [data-part='next'], [data-part='autoplay']) {
|
|
471
|
+
--_control-size: var(--slotted-control-inner-size-md, 24px);
|
|
472
|
+
|
|
473
|
+
background: transparent;
|
|
474
|
+
border-color: transparent;
|
|
475
|
+
box-shadow: none;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
[data-ui='carousel'][data-size='sm']
|
|
479
|
+
> [data-part='controls'][data-placement='overlay']
|
|
480
|
+
> :is([data-part='previous'], [data-part='next'], [data-part='autoplay']) {
|
|
481
|
+
--_control-size: var(--slotted-control-inner-size-sm, 22px);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
[data-ui='carousel'][data-size='lg']
|
|
485
|
+
> [data-part='controls'][data-placement='overlay']
|
|
486
|
+
> :is([data-part='previous'], [data-part='next'], [data-part='autoplay']) {
|
|
487
|
+
--_control-size: var(--slotted-control-inner-size-lg, 28px);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
[data-ui='carousel'][data-arrows='outside'] > [data-part='controls'][data-placement='overlay'] {
|
|
491
|
+
grid-area: 1 / 2;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
[data-ui='carousel'] > [data-part='controls'] > [data-part='indicators'][data-variant='line'] {
|
|
495
|
+
flex: 1 1 auto;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/* ── The indicators ───────────────────────────────────────────────────── */
|
|
499
|
+
|
|
500
|
+
[data-ui='carousel'] [data-part='indicators'] {
|
|
501
|
+
align-items: center;
|
|
502
|
+
display: flex;
|
|
503
|
+
/* A dot's box is twenty pixels; four between two boxes puts their centres twenty-four apart. */
|
|
504
|
+
gap: var(--slotted-space-2, 0.25rem);
|
|
505
|
+
justify-content: center;
|
|
506
|
+
min-inline-size: 0;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* A dot is eight pixels and the button around it is a 24-pixel row: the
|
|
511
|
+
* mark is drawn by the button's own `::before`, and the box is what the
|
|
512
|
+
* pointer hits. Two boxes side by side stand twenty-four pixels centre to
|
|
513
|
+
* centre, which is the spacing WCAG 2.2 SC 2.5.8 accepts for a target
|
|
514
|
+
* smaller than twenty-four.
|
|
515
|
+
*/
|
|
516
|
+
[data-ui='carousel'] [data-part='indicator'] {
|
|
517
|
+
appearance: none;
|
|
518
|
+
background: transparent;
|
|
519
|
+
block-size: var(--slotted-target-min, 24px);
|
|
520
|
+
border: 0;
|
|
521
|
+
border-radius: var(--slotted-radius-full, 9999px);
|
|
522
|
+
color: inherit;
|
|
523
|
+
cursor: pointer;
|
|
524
|
+
flex: none;
|
|
525
|
+
inline-size: calc(var(--_dot) + 2 * var(--_dot-air));
|
|
526
|
+
margin: 0;
|
|
527
|
+
padding: 0;
|
|
528
|
+
position: relative;
|
|
529
|
+
transition: inline-size var(--slotted-duration-medium) var(--slotted-easing-standard, ease);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
[data-ui='carousel'] [data-part='indicator'][data-current] {
|
|
533
|
+
inline-size: calc(var(--_dot-current) + 2 * var(--_dot-air));
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
[data-ui='carousel']
|
|
537
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
538
|
+
> [data-part='indicator']::before,
|
|
539
|
+
[data-ui='carousel']
|
|
540
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
541
|
+
> [data-part='indicator']::after {
|
|
542
|
+
block-size: var(--_dot);
|
|
543
|
+
border-radius: var(--slotted-radius-full, 9999px);
|
|
544
|
+
content: '';
|
|
545
|
+
inset-block-start: calc(50% - var(--_dot) / 2);
|
|
546
|
+
inset-inline: var(--_dot-air);
|
|
547
|
+
position: absolute;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* The resting dot is the line between two surfaces, which holds 3:1 on
|
|
552
|
+
* every surface a carousel stands on; the current one is the ink, and its
|
|
553
|
+
* shape already differs.
|
|
554
|
+
*/
|
|
555
|
+
[data-ui='carousel']
|
|
556
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
557
|
+
> [data-part='indicator']::before {
|
|
558
|
+
background: var(--slotted-border-strong, transparent);
|
|
559
|
+
transition: background-color var(--slotted-control-transition-duration)
|
|
560
|
+
var(--slotted-control-transition-easing, ease);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
[data-ui='carousel']
|
|
564
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
565
|
+
> [data-part='indicator']:hover:not([data-current]):not([data-disabled])::before {
|
|
566
|
+
background: var(--slotted-text-muted, transparent);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
[data-ui='carousel']
|
|
570
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
571
|
+
> [data-part='indicator']:active:not([data-current]):not([data-disabled])::before {
|
|
572
|
+
background: var(--slotted-text, transparent);
|
|
573
|
+
transition-duration: var(--slotted-duration-instant);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
[data-ui='carousel']
|
|
577
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
578
|
+
> [data-part='indicator'][data-current]::before {
|
|
579
|
+
background: var(--slotted-text, transparent);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* ── The time left ──────────────────────────────────────────────────────
|
|
584
|
+
*
|
|
585
|
+
* While the rotation runs the current mark becomes a track and fills with
|
|
586
|
+
* the ink over exactly the delay the timer was given, because it reads the
|
|
587
|
+
* same number: `--slotted-carousel-autoplay-delay`, written by the binding.
|
|
588
|
+
* Hover and a hidden document pause the timer, and `data-paused` freezes
|
|
589
|
+
* the fill at the same instant, so the picture and the timer never
|
|
590
|
+
* disagree. The fill grows its own inline size from the inline start, like
|
|
591
|
+
* `toast`'s countdown, so there is no origin to mirror.
|
|
592
|
+
*/
|
|
593
|
+
[data-ui='carousel'][data-playing]
|
|
594
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
595
|
+
> [data-part='indicator'][data-current]::before {
|
|
596
|
+
background: var(--slotted-border-strong, transparent);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
[data-ui='carousel'][data-playing]
|
|
600
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
601
|
+
> [data-part='indicator'][data-current]::after {
|
|
602
|
+
animation: slotted-carousel-countdown
|
|
603
|
+
var(--slotted-carousel-autoplay-delay, var(--slotted-duration-loop-slow)) linear forwards;
|
|
604
|
+
background: var(--slotted-text, transparent);
|
|
605
|
+
inset-inline-end: auto;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
[data-ui='carousel'][data-playing][data-paused]
|
|
609
|
+
[data-part='indicators']
|
|
610
|
+
> [data-part='indicator'][data-current]::after {
|
|
611
|
+
animation-play-state: paused;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/* From a dot rather than from nothing: a fill one pixel wide with round caps reads as a tick. */
|
|
615
|
+
@keyframes slotted-carousel-countdown {
|
|
616
|
+
from {
|
|
617
|
+
inline-size: var(--_dot);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
to {
|
|
621
|
+
inline-size: calc(100% - 2 * var(--_dot-air));
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Past eight pages a row of dots is a ruler nobody reads. The engine writes
|
|
627
|
+
* each dot's distance from the current one; two steps away a dot shrinks by
|
|
628
|
+
* a third, and beyond the window it collapses to nothing. A collapsed dot
|
|
629
|
+
* stays a tab in the arrow ring, and moving onto it makes it current, which
|
|
630
|
+
* brings the window to it.
|
|
631
|
+
*/
|
|
632
|
+
[data-ui='carousel']
|
|
633
|
+
[data-part='indicators'][data-adaptive]
|
|
634
|
+
> [data-part='indicator'][data-distance='2']::before {
|
|
635
|
+
scale: 0.66;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
[data-ui='carousel']
|
|
639
|
+
[data-part='indicators'][data-adaptive]
|
|
640
|
+
> [data-part='indicator'][data-distance='far'] {
|
|
641
|
+
inline-size: 0;
|
|
642
|
+
overflow: hidden;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* ── Line ───────────────────────────────────────────────────────────────
|
|
647
|
+
*
|
|
648
|
+
* Segments that share the row. The mark is a two-pixel rule rather than a
|
|
649
|
+
* dot, and the current one is the ink — the progress line ReUI's `blog-3`
|
|
650
|
+
* draws as a single pixel, at the thickness the foundation gives a marker.
|
|
651
|
+
*/
|
|
652
|
+
[data-ui='carousel'] [data-part='indicators'][data-variant='line'] {
|
|
653
|
+
gap: var(--slotted-space-2, 0.25rem);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
[data-ui='carousel'] [data-part='indicators'][data-variant='line'] > [data-part='indicator'],
|
|
657
|
+
[data-ui='carousel']
|
|
658
|
+
[data-part='indicators'][data-variant='line']
|
|
659
|
+
> [data-part='indicator'][data-current] {
|
|
660
|
+
flex: 1 1 0;
|
|
661
|
+
inline-size: auto;
|
|
662
|
+
min-inline-size: var(--slotted-target-min, 24px);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
[data-ui='carousel']
|
|
666
|
+
[data-part='indicators'][data-variant='line']
|
|
667
|
+
> [data-part='indicator']::before,
|
|
668
|
+
[data-ui='carousel']
|
|
669
|
+
[data-part='indicators'][data-variant='line']
|
|
670
|
+
> [data-part='indicator']::after {
|
|
671
|
+
block-size: var(--_line);
|
|
672
|
+
border-radius: var(--slotted-radius-full, 9999px);
|
|
673
|
+
inset-block-start: calc(50% - var(--_line) / 2);
|
|
674
|
+
inset-inline: 0;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
[data-ui='carousel'][data-playing]
|
|
678
|
+
[data-part='indicators'][data-variant='line']
|
|
679
|
+
> [data-part='indicator'][data-current]::after {
|
|
680
|
+
animation-name: slotted-carousel-countdown-line;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
@keyframes slotted-carousel-countdown-line {
|
|
684
|
+
from {
|
|
685
|
+
inline-size: 0;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
to {
|
|
689
|
+
inline-size: 100%;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* ── Thumbnails ─────────────────────────────────────────────────────────
|
|
695
|
+
*
|
|
696
|
+
* Each indicator holds the consumer's picture. The strip scrolls on its own
|
|
697
|
+
* when it holds more than it can show, and the engine keeps the current one
|
|
698
|
+
* in view. The resting pictures are held back so the current one is the
|
|
699
|
+
* brightest thing in the strip; the current one carries an inset ring of
|
|
700
|
+
* the ink, inside its own box, so the focus ring drawn outside it is never
|
|
701
|
+
* confused with it.
|
|
702
|
+
*/
|
|
703
|
+
[data-ui='carousel'] [data-part='indicators'][data-variant='thumbnails'] {
|
|
704
|
+
gap: var(--slotted-space-4, 0.5rem);
|
|
705
|
+
justify-content: flex-start;
|
|
706
|
+
overflow-x: auto;
|
|
707
|
+
overscroll-behavior-inline: contain;
|
|
708
|
+
/* Room for the focus ring, which the scroller would otherwise clip. */
|
|
709
|
+
padding: calc(var(--slotted-focus-ring-width, 2px) + var(--slotted-focus-ring-offset, 2px));
|
|
710
|
+
scrollbar-width: none;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
[data-ui='carousel']
|
|
714
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
715
|
+
> [data-part='indicator'],
|
|
716
|
+
[data-ui='carousel']
|
|
717
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
718
|
+
> [data-part='indicator'][data-current] {
|
|
719
|
+
block-size: var(--_thumbnail);
|
|
720
|
+
border-radius: var(--slotted-radius-md, 6px);
|
|
721
|
+
inline-size: var(--_thumbnail);
|
|
722
|
+
overflow: hidden;
|
|
723
|
+
transition: none;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
[data-ui='carousel']
|
|
727
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
728
|
+
> [data-part='indicator']
|
|
729
|
+
> * {
|
|
730
|
+
block-size: 100%;
|
|
731
|
+
display: block;
|
|
732
|
+
inline-size: 100%;
|
|
733
|
+
object-fit: cover;
|
|
734
|
+
opacity: 0.6;
|
|
735
|
+
transition: opacity var(--slotted-control-transition-duration)
|
|
736
|
+
var(--slotted-control-transition-easing, ease);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
[data-ui='carousel']
|
|
740
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
741
|
+
> [data-part='indicator']:hover:not([data-current]):not([data-disabled])
|
|
742
|
+
> * {
|
|
743
|
+
opacity: 0.85;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
[data-ui='carousel']
|
|
747
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
748
|
+
> [data-part='indicator'][data-current]
|
|
749
|
+
> * {
|
|
750
|
+
opacity: 1;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
[data-ui='carousel']
|
|
754
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
755
|
+
> [data-part='indicator']::after {
|
|
756
|
+
border-radius: inherit;
|
|
757
|
+
box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px)
|
|
758
|
+
var(--slotted-border-subtle, transparent);
|
|
759
|
+
content: '';
|
|
760
|
+
inset: 0;
|
|
761
|
+
pointer-events: none;
|
|
762
|
+
position: absolute;
|
|
763
|
+
transition: box-shadow var(--slotted-control-transition-duration)
|
|
764
|
+
var(--slotted-control-transition-easing, ease);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* The ring answers the pointer as well as the picture does: a step darker
|
|
769
|
+
* under hover, and the ink under the press, so the part itself carries the
|
|
770
|
+
* state and not only the picture inside it.
|
|
771
|
+
*/
|
|
772
|
+
[data-ui='carousel']
|
|
773
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
774
|
+
> [data-part='indicator']:hover:not([data-current]):not([data-disabled])::after {
|
|
775
|
+
box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px)
|
|
776
|
+
var(--slotted-border-strong, transparent);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
[data-ui='carousel']
|
|
780
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
781
|
+
> [data-part='indicator']:active:not([data-current]):not([data-disabled])::after {
|
|
782
|
+
box-shadow: inset 0 0 0 var(--slotted-border-width-thick, 2px)
|
|
783
|
+
var(--slotted-border-strong, transparent);
|
|
784
|
+
transition-duration: var(--slotted-duration-instant);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
[data-ui='carousel']
|
|
788
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
789
|
+
> [data-part='indicator'][data-current]::after {
|
|
790
|
+
box-shadow: inset 0 0 0 var(--slotted-border-width-thick, 2px) var(--slotted-text, transparent);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
[data-ui='carousel'] [data-part='indicator']:focus-visible {
|
|
794
|
+
outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
|
|
795
|
+
outline-offset: var(--slotted-focus-ring-offset, 2px);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* A dot on a line drawn inside a 24-pixel row would put the ring four
|
|
800
|
+
* pixels round a box much taller than the mark. The ring of a dot or a
|
|
801
|
+
* segment hugs the row instead, which is the box the pointer hits.
|
|
802
|
+
*/
|
|
803
|
+
[data-ui='carousel']
|
|
804
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
805
|
+
> [data-part='indicator']:focus-visible {
|
|
806
|
+
outline-offset: calc(var(--slotted-focus-ring-width, 2px) * -1);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/* ── The counter ──────────────────────────────────────────────────────── */
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Tabular figures, so "9 / 12" and "10 / 12" are the same width and the
|
|
813
|
+
* controls beside the counter do not move when the page changes.
|
|
814
|
+
*/
|
|
815
|
+
[data-ui='carousel'] [data-part='counter'] {
|
|
816
|
+
color: var(--slotted-text-muted, GrayText);
|
|
817
|
+
font-family: var(--slotted-font-family-sans, sans-serif);
|
|
818
|
+
font-size: var(--slotted-font-size-sm, 0.8125rem);
|
|
819
|
+
font-variant-numeric: tabular-nums;
|
|
820
|
+
line-height: var(--slotted-line-height-sm, 1.45);
|
|
821
|
+
/**
|
|
822
|
+
* "3 / 8" is a fraction and reads first-to-last in every script; left to
|
|
823
|
+
* the bidirectional algorithm in a right-to-left page the neutral slash
|
|
824
|
+
* turned it into "8 / 3".
|
|
825
|
+
*/
|
|
826
|
+
direction: ltr;
|
|
827
|
+
unicode-bidi: isolate;
|
|
828
|
+
white-space: nowrap;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* The marks are painted by pseudo-elements, and forced colours repaint a
|
|
833
|
+
* pseudo-element's ground as the page's and lose the mark. The theme has
|
|
834
|
+
* already mapped the tokens the marks read to system colours, so the rule
|
|
835
|
+
* only stops the repaint, and moves the current mark to the accent tone,
|
|
836
|
+
* which forced colours map to the highlight.
|
|
837
|
+
*/
|
|
838
|
+
@media (forced-colors: active) {
|
|
839
|
+
[data-ui='carousel'] [data-part='indicator']::before,
|
|
840
|
+
[data-ui='carousel'] [data-part='indicator']::after {
|
|
841
|
+
forced-color-adjust: none;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
[data-ui='carousel']
|
|
845
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
846
|
+
> [data-part='indicator'][data-current]::before,
|
|
847
|
+
[data-ui='carousel']
|
|
848
|
+
[data-part='indicators']:not([data-variant='thumbnails'])
|
|
849
|
+
> [data-part='indicator'][data-current]::after {
|
|
850
|
+
background: var(--slotted-tone-accent-solid, transparent);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
[data-ui='carousel']
|
|
854
|
+
[data-part='indicators'][data-variant='thumbnails']
|
|
855
|
+
> [data-part='indicator'][data-current]::after {
|
|
856
|
+
box-shadow: inset 0 0 0 var(--slotted-border-width-thick, 2px)
|
|
857
|
+
var(--slotted-tone-accent-solid, transparent);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|