@ropav/styles 0.3.0 → 0.5.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/README.md +160 -19
- package/dist/components/accordion.css +12 -5
- package/dist/components/alert-dialog.css +1 -1
- package/dist/components/alert.css +9 -1
- package/dist/components/autocomplete/autocomplete.styles.d.ts +33 -0
- package/dist/components/autocomplete/autocomplete.styles.d.ts.map +1 -1
- package/dist/components/autocomplete/autocomplete.styles.js +12 -0
- package/dist/components/autocomplete.css +39 -3
- package/dist/components/avatar.css +9 -0
- package/dist/components/badge.css +7 -0
- package/dist/components/button-group.css +6 -6
- package/dist/components/button.css +34 -11
- package/dist/components/calendar-year-picker.css +2 -1
- package/dist/components/calendar.css +8 -0
- package/dist/components/card.css +22 -1
- package/dist/components/chip.css +21 -0
- package/dist/components/close-button.css +8 -0
- package/dist/components/color-input-group/color-input-group.styles.d.ts +27 -0
- package/dist/components/color-input-group/color-input-group.styles.d.ts.map +1 -1
- package/dist/components/color-input-group/color-input-group.styles.js +6 -0
- package/dist/components/color-input-group.css +30 -1
- package/dist/components/color-swatch-picker.css +11 -0
- package/dist/components/combo-box/combo-box.styles.d.ts +27 -0
- package/dist/components/combo-box/combo-box.styles.d.ts.map +1 -1
- package/dist/components/combo-box/combo-box.styles.js +17 -7
- package/dist/components/combo-box.css +21 -1
- package/dist/components/date-input-group/date-input-group.styles.d.ts +27 -0
- package/dist/components/date-input-group/date-input-group.styles.d.ts.map +1 -1
- package/dist/components/date-input-group/date-input-group.styles.js +6 -0
- package/dist/components/date-input-group.css +30 -1
- package/dist/components/dropdown/dropdown.styles.d.ts.map +1 -1
- package/dist/components/dropdown/dropdown.styles.js +1 -1
- package/dist/components/dropdown.css +17 -12
- package/dist/components/index.css +4 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/input/input.styles.d.ts +15 -0
- package/dist/components/input/input.styles.d.ts.map +1 -1
- package/dist/components/input/input.styles.js +6 -0
- package/dist/components/input-group/input-group.styles.d.ts +27 -0
- package/dist/components/input-group/input-group.styles.d.ts.map +1 -1
- package/dist/components/input-group/input-group.styles.js +6 -0
- package/dist/components/input-group.css +32 -1
- package/dist/components/input.css +23 -1
- package/dist/components/list-box/list-box.styles.d.ts +15 -0
- package/dist/components/list-box/list-box.styles.d.ts.map +1 -1
- package/dist/components/list-box/list-box.styles.js +15 -5
- package/dist/components/list-box-item.css +4 -2
- package/dist/components/list-box.css +19 -0
- package/dist/components/menu/menu.styles.d.ts +19 -1
- package/dist/components/menu/menu.styles.d.ts.map +1 -1
- package/dist/components/menu/menu.styles.js +9 -1
- package/dist/components/menu.css +25 -0
- package/dist/components/meter.css +12 -0
- package/dist/components/modal.css +1 -1
- package/dist/components/number-field/number-field.styles.d.ts +27 -0
- package/dist/components/number-field/number-field.styles.d.ts.map +1 -1
- package/dist/components/number-field/number-field.styles.js +6 -0
- package/dist/components/number-field.css +68 -1
- package/dist/components/pagination.css +10 -6
- package/dist/components/popover.css +15 -1
- package/dist/components/progress-bar.css +12 -0
- package/dist/components/progress-circle.css +12 -0
- package/dist/components/radio.css +7 -0
- package/dist/components/range-calendar.css +28 -0
- package/dist/components/search-field/search-field.styles.d.ts +27 -0
- package/dist/components/search-field/search-field.styles.d.ts.map +1 -1
- package/dist/components/search-field/search-field.styles.js +6 -0
- package/dist/components/search-field.css +33 -1
- package/dist/components/segmented-control/index.d.ts +2 -0
- package/dist/components/segmented-control/index.d.ts.map +1 -0
- package/dist/components/segmented-control/index.js +2 -0
- package/dist/components/segmented-control/segmented-control.styles.d.ts +73 -0
- package/dist/components/segmented-control/segmented-control.styles.d.ts.map +1 -0
- package/dist/components/segmented-control/segmented-control.styles.js +27 -0
- package/dist/components/segmented-control.css +193 -0
- package/dist/components/select/select.styles.d.ts +33 -0
- package/dist/components/select/select.styles.d.ts.map +1 -1
- package/dist/components/select/select.styles.js +12 -0
- package/dist/components/select.css +40 -3
- package/dist/components/separator.css +18 -1
- package/dist/components/sidebar/index.d.ts +2 -0
- package/dist/components/sidebar/index.d.ts.map +1 -0
- package/dist/components/sidebar/index.js +2 -0
- package/dist/components/sidebar/sidebar.styles.d.ts +190 -0
- package/dist/components/sidebar/sidebar.styles.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar.styles.js +52 -0
- package/dist/components/sidebar.css +510 -0
- package/dist/components/skeleton.css +9 -0
- package/dist/components/slider.css +61 -0
- package/dist/components/splitter/index.d.ts +2 -0
- package/dist/components/splitter/index.d.ts.map +1 -0
- package/dist/components/splitter/index.js +2 -0
- package/dist/components/splitter/splitter.styles.d.ts +61 -0
- package/dist/components/splitter/splitter.styles.d.ts.map +1 -0
- package/dist/components/splitter/splitter.styles.js +26 -0
- package/dist/components/splitter.css +241 -0
- package/dist/components/surface.css +24 -0
- package/dist/components/switch.css +30 -0
- package/dist/components/table.css +11 -3
- package/dist/components/tabs.css +30 -2
- package/dist/components/tag.css +10 -0
- package/dist/components/textarea/textarea.styles.d.ts +15 -0
- package/dist/components/textarea/textarea.styles.d.ts.map +1 -1
- package/dist/components/textarea/textarea.styles.js +6 -0
- package/dist/components/textarea.css +23 -1
- package/dist/components/toast.css +1 -1
- package/dist/components/toggle-button-group.css +7 -7
- package/dist/components/toggle-button.css +17 -11
- package/dist/components/toolbar.css +8 -1
- package/dist/components/tooltip.css +15 -2
- package/dist/components/typography.css +21 -0
- package/dist/components/virtualizer/index.d.ts +2 -0
- package/dist/components/virtualizer/index.d.ts.map +1 -0
- package/dist/components/virtualizer/index.js +2 -0
- package/dist/components/virtualizer/virtualizer.styles.d.ts +44 -0
- package/dist/components/virtualizer/virtualizer.styles.d.ts.map +1 -0
- package/dist/components/virtualizer/virtualizer.styles.js +15 -0
- package/dist/components/virtualizer.css +64 -0
- package/dist/index.css +7 -2
- package/dist/index.js +5 -1
- package/dist/ropav.min.css +2 -2
- package/dist/themes/airbnb.css +231 -0
- package/dist/themes/all.css +17 -0
- package/dist/themes/coinbase.css +231 -0
- package/dist/themes/{default/variables.css → default.css} +28 -9
- package/dist/themes/discord.css +231 -0
- package/dist/themes/hero.css +262 -0
- package/dist/themes/lavender.css +231 -0
- package/dist/themes/mint.css +231 -0
- package/dist/themes/netflix.css +231 -0
- package/dist/themes/rabbit.css +231 -0
- package/dist/themes/shared/theme.css +19 -2
- package/dist/themes/sky.css +231 -0
- package/dist/themes/spotify.css +231 -0
- package/dist/themes/uber.css +231 -0
- package/dist/utilities/index.css +97 -0
- package/dist/variants/index.css +5 -15
- package/package.json +2 -3
- package/src/components/autocomplete/autocomplete.styles.ts +12 -0
- package/src/components/color-input-group/color-input-group.styles.ts +10 -0
- package/src/components/combo-box/combo-box.styles.ts +12 -0
- package/src/components/date-input-group/date-input-group.styles.ts +10 -0
- package/src/components/dropdown/dropdown.styles.ts +3 -1
- package/src/components/index.ts +4 -0
- package/src/components/input/input.styles.ts +6 -0
- package/src/components/input-group/input-group.styles.ts +10 -0
- package/src/components/list-box/list-box.styles.ts +6 -0
- package/src/components/menu/menu.styles.ts +10 -0
- package/src/components/number-field/number-field.styles.ts +10 -0
- package/src/components/search-field/search-field.styles.ts +10 -0
- package/src/components/segmented-control/index.ts +1 -0
- package/src/components/segmented-control/segmented-control.styles.ts +37 -0
- package/src/components/select/select.styles.ts +12 -0
- package/src/components/sidebar/index.ts +1 -0
- package/src/components/sidebar/sidebar.styles.ts +94 -0
- package/src/components/splitter/index.ts +1 -0
- package/src/components/splitter/splitter.styles.ts +44 -0
- package/src/components/textarea/textarea.styles.ts +6 -0
- package/src/components/virtualizer/index.ts +1 -0
- package/src/components/virtualizer/virtualizer.styles.ts +15 -0
- package/dist/themes/default/components/index.css +0 -6
- package/dist/themes/default/index.css +0 -8
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
/* Sidebar styles */
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* The side and the collapse mode are modifier classes rather than `[data-side]` /
|
|
5
|
+
* `[data-collapsible]` descendant selectors on the shell, for the reason `splitter.css` sets out
|
|
6
|
+
* at length: a selector reaching down from the root reaches into anything nested under it too.
|
|
7
|
+
* A sidebar rarely nests, but a sidebar's `Inset` holds a whole page — a settings pane with its
|
|
8
|
+
* own sidebar is an ordinary thing to build — and the inner panel would then resolve the outer
|
|
9
|
+
* one's side and lay its border down the wrong edge.
|
|
10
|
+
*
|
|
11
|
+
* The modifier also buys the Storybook forced-colors sweep, which collects `[class*='--']`. The
|
|
12
|
+
* transient half of the state stays on `data-*`: `data-collapsed` is what changes while you watch,
|
|
13
|
+
* so it belongs where a state key belongs and not in the class list.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
.sidebar {
|
|
17
|
+
/* The two widths the panel resolves between. Held on the shell rather than the panel so a caller
|
|
18
|
+
* retunes both from one place, and so a drag can write the expanded one to the same property the
|
|
19
|
+
* stylesheet reads. */
|
|
20
|
+
--sidebar-width: calc(var(--spacing) * 64);
|
|
21
|
+
--sidebar-width-icon: calc(var(--spacing) * 14);
|
|
22
|
+
/* The rail's line and the grab area around it, matching `splitter.css` — same hairline, same
|
|
23
|
+
* reasoning about a target no one can hit, same wait before it flares. */
|
|
24
|
+
--sidebar-rail-gutter: 1px;
|
|
25
|
+
--sidebar-rail-target: 15px;
|
|
26
|
+
--sidebar-highlight-delay: 500ms;
|
|
27
|
+
|
|
28
|
+
@apply isolate flex h-full w-full;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Reversing the row rather than reordering the parts: the shell's children are written panel,
|
|
32
|
+
* rail, inset in that order whichever side the sidebar is on, so the rail stays between the two
|
|
33
|
+
* either way and a caller's markup does not change with the prop. */
|
|
34
|
+
.sidebar--left {
|
|
35
|
+
@apply flex-row;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.sidebar--right {
|
|
39
|
+
@apply flex-row-reverse;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* ==========================================================================
|
|
43
|
+
Panel — the nav landmark
|
|
44
|
+
========================================================================== */
|
|
45
|
+
|
|
46
|
+
/* `min-h-0` for the same reason `.splitter__panel` has it: a flex item's automatic minimum is its
|
|
47
|
+
* content, so a long nav list would push the panel past the viewport instead of scrolling inside
|
|
48
|
+
* `.sidebar__content`. */
|
|
49
|
+
.sidebar__panel {
|
|
50
|
+
@apply relative flex min-h-0 shrink-0 grow-0 flex-col overflow-hidden bg-surface text-surface-foreground;
|
|
51
|
+
|
|
52
|
+
inline-size: var(--sidebar-width);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Transitions
|
|
56
|
+
* CRITICAL: motion-reduce must be AFTER transition for correct override specificity
|
|
57
|
+
*/
|
|
58
|
+
transition: inline-size 200ms var(--ease-out);
|
|
59
|
+
@apply motion-reduce:transition-none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Under the pointer the panel follows it exactly. Easing towards each frame's width instead makes
|
|
63
|
+
* the edge lag the cursor by the whole duration, which reads as the panel chasing the drag rather
|
|
64
|
+
* than being dragged. */
|
|
65
|
+
.sidebar__panel[data-resizing="true"] {
|
|
66
|
+
transition: none;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* The separating line is a border rather than a background, so it is one of the few things Forced
|
|
70
|
+
* Colors Mode recolours instead of flattening — no restatement needed here. */
|
|
71
|
+
.sidebar__panel--left {
|
|
72
|
+
@apply border-e border-separator/50;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.sidebar__panel--right {
|
|
76
|
+
@apply border-s border-separator/50;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Collapsing to icons is the default, so the width it collapses to lives on the mode that has one
|
|
80
|
+
* and `--none` is the empty rule. */
|
|
81
|
+
.sidebar__panel--icon[data-collapsed="true"] {
|
|
82
|
+
inline-size: var(--sidebar-width-icon);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Nothing left to divide once the panel is gone, and a hairline standing alone at the edge of the
|
|
86
|
+
* page reads as a rendering fault.
|
|
87
|
+
*
|
|
88
|
+
* The fill goes with it, and that is a declaration rather than a change: a box zero wide with no
|
|
89
|
+
* border paints no background either way. Saying so is what keeps the Storybook forced-colors
|
|
90
|
+
* sweep honest — it reads this panel as one that painted a surface and then lost it to the mode,
|
|
91
|
+
* where in truth there was never anything on screen to lose. */
|
|
92
|
+
.sidebar__panel--offcanvas[data-collapsed="true"] {
|
|
93
|
+
@apply border-0 bg-transparent;
|
|
94
|
+
|
|
95
|
+
inline-size: 0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.sidebar__panel--none {
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Inside a drawer the panel is no longer the surface — the dialog is, and it paints, sizes and
|
|
102
|
+
* slides itself. The panel gives all three up and becomes the column that fills what it was handed.
|
|
103
|
+
* Last of the panel's modifiers, so it beats the widths above at equal specificity. */
|
|
104
|
+
.sidebar__panel--drawer {
|
|
105
|
+
@apply size-full border-0 bg-transparent;
|
|
106
|
+
|
|
107
|
+
inline-size: auto;
|
|
108
|
+
transition: none;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ==========================================================================
|
|
112
|
+
Header, content, footer
|
|
113
|
+
========================================================================== */
|
|
114
|
+
|
|
115
|
+
.sidebar__header {
|
|
116
|
+
@apply flex shrink-0 flex-col gap-2 p-2;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* The scroll region. `overflow-x-hidden` because the panel narrows around its contents during the
|
|
120
|
+
* collapse transition, and without it every frame of that transition would flash a scrollbar.
|
|
121
|
+
*
|
|
122
|
+
* `scroll-padding` is what makes the fade safe rather than merely pretty. Focus scrolls an item to
|
|
123
|
+
* the nearest edge, which is exactly where the fade is, so a keyboard user tabbing down the nav
|
|
124
|
+
* would land on item after item with its focus ring faded out. The padding moves that landing
|
|
125
|
+
* point clear of the fade. Sized from the same property the fade is, so retuning one moves both. */
|
|
126
|
+
.sidebar__content {
|
|
127
|
+
@apply flex min-h-0 flex-1 flex-col gap-1 overflow-x-hidden overflow-y-auto p-2;
|
|
128
|
+
|
|
129
|
+
scroll-padding-block: var(--scroll-shadow-size, 0px);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Two classes to beat one: `scroll-shadow.css` is imported under Layout, long after this file under
|
|
133
|
+
* Navigation, so `.scroll-shadow--vertical`'s `scrollbar` wins at equal specificity and the nav
|
|
134
|
+
* would grow a full-width scrollbar the moment it became a shadow container. */
|
|
135
|
+
.sidebar__content.scroll-shadow {
|
|
136
|
+
@apply scrollbar-thin;
|
|
137
|
+
|
|
138
|
+
/* The fade is a `mask-image` over the rows, which in Forced Colors Mode means system-coloured
|
|
139
|
+
* text dissolving into the background. That mode is chosen by people who need the opposite of
|
|
140
|
+
* subtlety, so the affordance is dropped rather than softened — the scrollbar still says the
|
|
141
|
+
* region scrolls. */
|
|
142
|
+
@media (forced-colors: active) {
|
|
143
|
+
mask-image: none;
|
|
144
|
+
-webkit-mask-image: none;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.sidebar__footer {
|
|
149
|
+
@apply flex shrink-0 flex-col gap-2 p-2;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* ==========================================================================
|
|
153
|
+
Groups
|
|
154
|
+
========================================================================== */
|
|
155
|
+
|
|
156
|
+
.sidebar__group {
|
|
157
|
+
@apply flex w-full min-w-0 flex-col gap-0.5;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* Matches `.header`, which is the same muted label above the same kind of list. */
|
|
161
|
+
.sidebar__group-label {
|
|
162
|
+
@apply w-full truncate px-2 pt-1.5 pb-1 text-start text-xs font-medium text-muted;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* `sr-only` rather than `hidden`: the label is what tells a screen reader which group an item
|
|
166
|
+
* belongs to, and a collapsed sidebar is still being read. Taking it out of flow also takes it out
|
|
167
|
+
* of the group's `gap`, so the icons close up rather than leaving a hole where the label was. */
|
|
168
|
+
.sidebar__group-label[data-collapsed="true"] {
|
|
169
|
+
@apply sr-only;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Spacing only, and no width of its own. `separator.css` is imported under Layout, after this file
|
|
173
|
+
* under Navigation, so its `w-full` wins at equal specificity and nothing here can take it back —
|
|
174
|
+
* tailwind-merge cannot help either, because the width lives inside a BEM rule rather than in the
|
|
175
|
+
* class string. It needs no taking back: the rule runs the width of the content's padding box,
|
|
176
|
+
* which is exactly the box every item beside it already fills. */
|
|
177
|
+
.sidebar__separator {
|
|
178
|
+
@apply my-1;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* ==========================================================================
|
|
182
|
+
Nav item
|
|
183
|
+
========================================================================== */
|
|
184
|
+
|
|
185
|
+
.sidebar__item {
|
|
186
|
+
@apply relative flex min-h-9 w-full min-w-0 items-center justify-start gap-2 rounded-component px-2 text-sm font-medium text-foreground no-underline outline-none no-highlight;
|
|
187
|
+
|
|
188
|
+
/* Cursor */
|
|
189
|
+
cursor: var(--cursor-interactive);
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Transitions
|
|
193
|
+
* CRITICAL: motion-reduce must be AFTER transition for correct override specificity
|
|
194
|
+
*/
|
|
195
|
+
transition:
|
|
196
|
+
background-color 150ms var(--ease-out),
|
|
197
|
+
color 150ms var(--ease-out);
|
|
198
|
+
@apply motion-reduce:transition-none;
|
|
199
|
+
|
|
200
|
+
/* Hover state */
|
|
201
|
+
@media (hover: hover) {
|
|
202
|
+
&:hover,
|
|
203
|
+
&[data-hovered="true"] {
|
|
204
|
+
@apply bg-default;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* Focus visible state (keyboard focus only) */
|
|
209
|
+
&:focus-visible,
|
|
210
|
+
&[data-focus-visible="true"] {
|
|
211
|
+
@apply status-focused;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Pressed state */
|
|
215
|
+
&:active,
|
|
216
|
+
&[data-pressed="true"] {
|
|
217
|
+
@apply bg-default;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* The current page. Its whole job is to be the one item that stands out, so the mode flattening
|
|
221
|
+
* the fill onto the page would take exactly the distinction away — hence `forced-selected`,
|
|
222
|
+
* which is what the rest of the library reaches for to say "this one". */
|
|
223
|
+
&[data-current="true"] {
|
|
224
|
+
@apply bg-accent-soft text-accent-soft-foreground;
|
|
225
|
+
|
|
226
|
+
@apply forced-selected;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* Disabled state */
|
|
230
|
+
&[data-disabled="true"] {
|
|
231
|
+
@apply status-disabled;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Collapsed to the rail there is only the icon left to place, so it takes the centre and gives
|
|
235
|
+
* up the padding that was holding a label beside it. */
|
|
236
|
+
&[data-collapsed="true"] {
|
|
237
|
+
@apply justify-center px-0;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.sidebar__item-icon {
|
|
242
|
+
@apply flex size-4 shrink-0 items-center justify-center;
|
|
243
|
+
|
|
244
|
+
svg {
|
|
245
|
+
@apply size-4;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.sidebar__item-label {
|
|
250
|
+
@apply min-w-0 flex-1 truncate text-start;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Hidden the same way the group label is, and for the same reason — this *is* the item's
|
|
254
|
+
* accessible name. */
|
|
255
|
+
.sidebar__item-label[data-collapsed="true"] {
|
|
256
|
+
@apply sr-only;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.sidebar__item-trailing {
|
|
260
|
+
@apply flex shrink-0 items-center;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.sidebar__item-trailing[data-collapsed="true"] {
|
|
264
|
+
@apply hidden;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* The tooltip's own trigger is `inline-block`, and inside the nav's column that would shrink the
|
|
268
|
+
* item it wraps down to its contents. An item is a full-width row and has to stay one whether or
|
|
269
|
+
* not it has a tooltip hanging off it. */
|
|
270
|
+
.sidebar__item-tooltip {
|
|
271
|
+
@apply block w-full;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* ==========================================================================
|
|
275
|
+
Nested items
|
|
276
|
+
========================================================================== */
|
|
277
|
+
|
|
278
|
+
/* Points along the row while the children are shut and turns to point down at them once they are
|
|
279
|
+
* showing — a quarter turn, not the half turn `disclosure.css` uses.
|
|
280
|
+
*
|
|
281
|
+
* The difference is deliberate. A disclosure's indicator sits beside a heading and only has to say
|
|
282
|
+
* open or shut; this one sits at the end of a nav row and has a direction to mean, so the shut
|
|
283
|
+
* state points the way the rows will come from. `rtl` turns it the other way for the same reason
|
|
284
|
+
* it is `ms-auto` and not `ml-auto`. */
|
|
285
|
+
.sidebar__item-indicator {
|
|
286
|
+
@apply ms-auto size-3.5 shrink-0 -rotate-90 text-muted rtl:rotate-90;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Transitions
|
|
290
|
+
*/
|
|
291
|
+
@apply transition duration-250 motion-reduce:transition-none;
|
|
292
|
+
|
|
293
|
+
&[data-expanded="true"] {
|
|
294
|
+
@apply rotate-0;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/* Nothing left to point at once the sidebar is a rail: the children are not rendered there at all,
|
|
299
|
+
* and a chevron promising something that never opens is worse than no chevron. */
|
|
300
|
+
.sidebar__item-indicator[data-collapsed="true"] {
|
|
301
|
+
@apply hidden;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/* The rows under a nav item, indented and gathered by a line down the gutter they share. One border
|
|
305
|
+
* on the container rather than one per row, so the line runs unbroken from the first child to the
|
|
306
|
+
* last however many there are. */
|
|
307
|
+
.sidebar__sub-menu {
|
|
308
|
+
/* The row's own inline padding plus half its icon, which lands the line on the icon's centre.
|
|
309
|
+
* Written from those two rather than as the number they come to, so retuning either moves the
|
|
310
|
+
* line with it instead of leaving it a few pixels off. */
|
|
311
|
+
--sidebar-sub-indent: calc(var(--spacing) * 2 + calc(var(--spacing) * 4) / 2);
|
|
312
|
+
|
|
313
|
+
@apply flex min-w-0 flex-col gap-0.5 border-s border-separator;
|
|
314
|
+
|
|
315
|
+
margin-inline-start: var(--sidebar-sub-indent);
|
|
316
|
+
padding-inline-start: calc(var(--spacing) * 2);
|
|
317
|
+
|
|
318
|
+
/* A border is one of the few things Forced Colors Mode recolours rather than flattens, so the
|
|
319
|
+
* line survives on its own — but only while it has a colour left to recolour. */
|
|
320
|
+
@media (forced-colors: active) {
|
|
321
|
+
border-inline-start-color: CanvasText;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/*
|
|
326
|
+
* The collapse is a JS contract, not a CSS one: `useDisclosurePanel` writes both the height and the
|
|
327
|
+
* `hidden` attribute, and nothing in any stylesheet ever sets `--disclosure-panel-height`. The
|
|
328
|
+
* variable keeps that composable's name rather than taking a sidebar one, because the composable is
|
|
329
|
+
* what fills it in — a `--sidebar-sub-menu-height` here would stay empty forever.
|
|
330
|
+
*
|
|
331
|
+
* Held apart from the base because a submenu that is always open has nobody writing the variable,
|
|
332
|
+
* and `height: var(--disclosure-panel-height)` with nothing behind it would leave the rows sitting
|
|
333
|
+
* under an `opacity: 0` that never lifts.
|
|
334
|
+
*/
|
|
335
|
+
.sidebar__sub-menu--collapsible {
|
|
336
|
+
opacity: 0;
|
|
337
|
+
height: var(--disclosure-panel-height);
|
|
338
|
+
overflow: clip;
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Transitions
|
|
342
|
+
* CRITICAL: motion-reduce must be AFTER transition for correct override specificity
|
|
343
|
+
*/
|
|
344
|
+
transition:
|
|
345
|
+
height 200ms var(--ease-out-quad),
|
|
346
|
+
opacity 200ms var(--ease-out);
|
|
347
|
+
@apply motion-reduce:transition-none;
|
|
348
|
+
|
|
349
|
+
&[data-expanded="true"] {
|
|
350
|
+
will-change: height, opacity;
|
|
351
|
+
opacity: 1;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/* A child row carries no icon, so it gives up the gap that was holding one and drops to the weight
|
|
356
|
+
* of what it is — a destination under a heading rather than another heading. */
|
|
357
|
+
.sidebar__item--sub {
|
|
358
|
+
@apply gap-0 font-normal;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* ==========================================================================
|
|
362
|
+
Inset — the content beside the sidebar
|
|
363
|
+
========================================================================== */
|
|
364
|
+
|
|
365
|
+
/* `min-w-0` for the reason `.splitter__panel` documents: without it a wide table inside the inset
|
|
366
|
+
* sets a floor under the whole shell and the sidebar can never be given its width back. */
|
|
367
|
+
.sidebar__inset {
|
|
368
|
+
@apply relative flex min-w-0 flex-1 flex-col overflow-hidden bg-background;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/* ==========================================================================
|
|
372
|
+
Rail — the edge strip
|
|
373
|
+
========================================================================== */
|
|
374
|
+
|
|
375
|
+
/* Built like `.splitter__handle`, down to the `::after`: the flex item is the gutter and paints
|
|
376
|
+
* nothing, so the line can thicken on hover without the gutter changing width and shifting the
|
|
377
|
+
* whole page by a pixel. */
|
|
378
|
+
.sidebar__rail {
|
|
379
|
+
@apply relative z-10 flex shrink-0 grow-0 items-center justify-center self-stretch;
|
|
380
|
+
@apply bg-transparent outline-none select-none no-highlight;
|
|
381
|
+
|
|
382
|
+
/* The gesture is ours; the browser must not also pan or scroll from a drag on this. */
|
|
383
|
+
@apply touch-none;
|
|
384
|
+
|
|
385
|
+
inline-size: var(--sidebar-rail-gutter);
|
|
386
|
+
cursor: var(--cursor-interactive);
|
|
387
|
+
|
|
388
|
+
&::after {
|
|
389
|
+
@apply pointer-events-none absolute inset-y-0 rounded-sm bg-separator content-[''];
|
|
390
|
+
|
|
391
|
+
inline-size: var(--sidebar-rail-gutter);
|
|
392
|
+
|
|
393
|
+
/* Flattened to `Canvas` the line stops existing rather than weakening — the whole part *is*
|
|
394
|
+
* its background, the trap `separator.css` and `splitter.css` both restate their colour for. */
|
|
395
|
+
@media (forced-colors: active) {
|
|
396
|
+
background-color: CanvasText;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Transitions
|
|
401
|
+
* CRITICAL: motion-reduce must be AFTER transition for correct override specificity
|
|
402
|
+
*/
|
|
403
|
+
transition:
|
|
404
|
+
background-color 150ms var(--ease-out),
|
|
405
|
+
inline-size 150ms var(--ease-out);
|
|
406
|
+
@apply motion-reduce:transition-none;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
&:hover::after,
|
|
410
|
+
&[data-hovered="true"]::after,
|
|
411
|
+
&[data-dragging="true"]::after {
|
|
412
|
+
@apply bg-accent;
|
|
413
|
+
|
|
414
|
+
inline-size: calc(var(--sidebar-rail-gutter) * 2);
|
|
415
|
+
|
|
416
|
+
/* `bg-separator` and `bg-accent` both flatten to `Canvas`, so without this the resting and
|
|
417
|
+
* active states are byte-identical under the mode. */
|
|
418
|
+
@media (forced-colors: active) {
|
|
419
|
+
background-color: Highlight;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* Delayed on the way in and immediate on the way out. A grab area many times the width of the
|
|
424
|
+
* line is one a pointer crosses on its way to the page, and a rail that flares at every crossing
|
|
425
|
+
* reads as a twitch rather than an invitation. */
|
|
426
|
+
&:hover::after,
|
|
427
|
+
&[data-hovered="true"]::after {
|
|
428
|
+
transition-delay: var(--sidebar-highlight-delay);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/* A drag under way is not in question, so it skips the wait. Last, because a drag usually starts
|
|
432
|
+
* from a hover and has to win. */
|
|
433
|
+
&[data-dragging="true"]::after {
|
|
434
|
+
transition-delay: 0ms;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
&:focus-visible,
|
|
438
|
+
&[data-focus-visible="true"] {
|
|
439
|
+
@apply status-focused;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
&[data-disabled="true"] {
|
|
443
|
+
@apply status-disabled;
|
|
444
|
+
|
|
445
|
+
/* `status-disabled` reaches `color` and `border-color`, and the line is neither. */
|
|
446
|
+
&::after {
|
|
447
|
+
@media (forced-colors: active) {
|
|
448
|
+
background-color: GrayText;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* Only a rail that resizes says so with the cursor. One that merely toggles is a button, and
|
|
455
|
+
* `--cursor-interactive` on the base rule already covers it. */
|
|
456
|
+
.sidebar__rail--resizable {
|
|
457
|
+
@apply cursor-col-resize;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/* The invisible hit area, overhanging the hairline on both sides. A negative `inset` rather than a
|
|
461
|
+
* transparent border, because Forced Colors Mode turns a transparent border-color opaque and every
|
|
462
|
+
* rail would render as a solid block. */
|
|
463
|
+
.sidebar__rail-target {
|
|
464
|
+
@apply absolute inset-0 bg-transparent;
|
|
465
|
+
|
|
466
|
+
inset-inline: calc((var(--sidebar-rail-target) - var(--sidebar-rail-gutter)) / -2);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/* ==========================================================================
|
|
470
|
+
Trigger
|
|
471
|
+
========================================================================== */
|
|
472
|
+
|
|
473
|
+
.sidebar__trigger {
|
|
474
|
+
@apply inline-flex size-8 shrink-0 items-center justify-center rounded-component bg-transparent text-muted outline-none select-none no-highlight;
|
|
475
|
+
|
|
476
|
+
/* Cursor */
|
|
477
|
+
cursor: var(--cursor-interactive);
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Transitions
|
|
481
|
+
* CRITICAL: motion-reduce must be AFTER transition for correct override specificity
|
|
482
|
+
*/
|
|
483
|
+
transition:
|
|
484
|
+
background-color 150ms var(--ease-out),
|
|
485
|
+
color 150ms var(--ease-out);
|
|
486
|
+
@apply motion-reduce:transition-none;
|
|
487
|
+
|
|
488
|
+
svg {
|
|
489
|
+
@apply size-4;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/* Hover state */
|
|
493
|
+
@media (hover: hover) {
|
|
494
|
+
&:hover,
|
|
495
|
+
&[data-hovered="true"] {
|
|
496
|
+
@apply bg-default text-foreground;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/* Focus visible state (keyboard focus only) */
|
|
501
|
+
&:focus-visible,
|
|
502
|
+
&[data-focus-visible="true"] {
|
|
503
|
+
@apply status-focused;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/* Disabled state */
|
|
507
|
+
&[data-disabled="true"] {
|
|
508
|
+
@apply status-disabled;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
.skeleton {
|
|
2
2
|
@apply pointer-events-none relative overflow-hidden rounded-sm bg-surface-tertiary/70;
|
|
3
|
+
|
|
4
|
+
/* Forced Colors Mode flattens the fill to `Canvas` - the same colour as the page behind it -
|
|
5
|
+
* and drops the shimmer gradient outright, so the placeholder disappears entirely. An inset
|
|
6
|
+
* outline is what is left to say something is loading here, and unlike a border it costs no
|
|
7
|
+
* layout. */
|
|
8
|
+
@media (forced-colors: active) {
|
|
9
|
+
outline: 1px solid GrayText;
|
|
10
|
+
outline-offset: -1px;
|
|
11
|
+
}
|
|
3
12
|
}
|
|
4
13
|
|
|
5
14
|
/* TODO: Skeleton with parent are not visible */
|
|
@@ -24,16 +24,37 @@
|
|
|
24
24
|
@apply relative rounded-xl bg-default;
|
|
25
25
|
|
|
26
26
|
grid-area: track;
|
|
27
|
+
|
|
28
|
+
/* Forced Colors Mode flattens the bar to `Canvas`, the colour of the page behind it, so
|
|
29
|
+
* the track stops existing - hence the edge. The spacer borders are dealt with per
|
|
30
|
+
* orientation below, which is where they are set. */
|
|
31
|
+
@media (forced-colors: active) {
|
|
32
|
+
background-color: Canvas;
|
|
33
|
+
outline: 1px solid CanvasText;
|
|
34
|
+
outline-offset: -1px;
|
|
35
|
+
}
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
.slider__fill {
|
|
30
39
|
@apply pointer-events-none absolute bg-accent;
|
|
40
|
+
|
|
41
|
+
/* The only thing showing how far along the value is */
|
|
42
|
+
@media (forced-colors: active) {
|
|
43
|
+
background-color: Highlight;
|
|
44
|
+
}
|
|
31
45
|
}
|
|
32
46
|
|
|
33
47
|
.slider__thumb {
|
|
34
48
|
/* Flex container for centering pseudo-elements */
|
|
35
49
|
@apply absolute flex cursor-grab items-center justify-center rounded-xl bg-accent no-highlight;
|
|
36
50
|
|
|
51
|
+
/* The wrapper is the fill colour in ordinary use, which hides it against the fill. Flattened
|
|
52
|
+
* to `Canvas` it would punch a hole through the fill instead, so it steps back and lets
|
|
53
|
+
* `::after` - the knob you actually see - carry the control. */
|
|
54
|
+
@media (forced-colors: active) {
|
|
55
|
+
background-color: transparent;
|
|
56
|
+
}
|
|
57
|
+
|
|
37
58
|
/**
|
|
38
59
|
* Transitions
|
|
39
60
|
* CRITICAL: motion-reduce must be AFTER transition for correct override specificity
|
|
@@ -49,6 +70,15 @@
|
|
|
49
70
|
@apply relative z-10 rounded-lg bg-accent-foreground text-black shadow-field;
|
|
50
71
|
content: "";
|
|
51
72
|
|
|
73
|
+
/* Both the knob's fill and the shadow that separates it from the track are gone under
|
|
74
|
+
* forced colors. `Canvas` inside a `CanvasText` ring reads against the bare track on one
|
|
75
|
+
* side and the `Highlight` fill on the other, which no single flat colour manages. */
|
|
76
|
+
@media (forced-colors: active) {
|
|
77
|
+
background-color: Canvas;
|
|
78
|
+
outline: 2px solid CanvasText;
|
|
79
|
+
outline-offset: -2px;
|
|
80
|
+
}
|
|
81
|
+
|
|
52
82
|
/**
|
|
53
83
|
* Transitions
|
|
54
84
|
*/
|
|
@@ -96,12 +126,29 @@
|
|
|
96
126
|
/* Thumb width is 1.5rem (24px), so half is 0.75rem (12px) */
|
|
97
127
|
@apply border-x-[0.75rem] border-x-transparent;
|
|
98
128
|
|
|
129
|
+
/* A transparent border-color is one of the few things forced colors turns *opaque*, so
|
|
130
|
+
* without this the two spacers render as solid blocks at either end of the track. */
|
|
131
|
+
@media (forced-colors: active) {
|
|
132
|
+
border-inline-start-color: Canvas;
|
|
133
|
+
border-inline-end-color: Canvas;
|
|
134
|
+
}
|
|
135
|
+
|
|
99
136
|
&[data-fill-start="true"] {
|
|
100
137
|
@apply border-s-accent;
|
|
138
|
+
|
|
139
|
+
/* Carries the fill past the spacer to the end of the bar, so it has to be the fill
|
|
140
|
+
* colour rather than the `Canvas` the base rule neutralises the spacers with. */
|
|
141
|
+
@media (forced-colors: active) {
|
|
142
|
+
border-inline-start-color: Highlight;
|
|
143
|
+
}
|
|
101
144
|
}
|
|
102
145
|
|
|
103
146
|
&[data-fill-end="true"] {
|
|
104
147
|
@apply border-e-accent;
|
|
148
|
+
|
|
149
|
+
@media (forced-colors: active) {
|
|
150
|
+
border-inline-end-color: Highlight;
|
|
151
|
+
}
|
|
105
152
|
}
|
|
106
153
|
}
|
|
107
154
|
|
|
@@ -150,12 +197,26 @@
|
|
|
150
197
|
@apply border-y-[0.75rem] border-y-transparent;
|
|
151
198
|
justify-self: center;
|
|
152
199
|
|
|
200
|
+
/* Same as the horizontal spacers - opaque without this */
|
|
201
|
+
@media (forced-colors: active) {
|
|
202
|
+
border-top-color: Canvas;
|
|
203
|
+
border-bottom-color: Canvas;
|
|
204
|
+
}
|
|
205
|
+
|
|
153
206
|
&[data-fill-start="true"] {
|
|
154
207
|
@apply border-b-accent;
|
|
208
|
+
|
|
209
|
+
@media (forced-colors: active) {
|
|
210
|
+
border-bottom-color: Highlight;
|
|
211
|
+
}
|
|
155
212
|
}
|
|
156
213
|
|
|
157
214
|
&[data-fill-end="true"] {
|
|
158
215
|
@apply border-t-accent;
|
|
216
|
+
|
|
217
|
+
@media (forced-colors: active) {
|
|
218
|
+
border-top-color: Highlight;
|
|
219
|
+
}
|
|
159
220
|
}
|
|
160
221
|
}
|
|
161
222
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/splitter/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
|