@ropav/styles 0.4.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.
Files changed (138) hide show
  1. package/README.md +10 -5
  2. package/dist/components/accordion.css +5 -5
  3. package/dist/components/alert-dialog.css +1 -1
  4. package/dist/components/alert.css +1 -1
  5. package/dist/components/autocomplete/autocomplete.styles.d.ts +33 -0
  6. package/dist/components/autocomplete/autocomplete.styles.d.ts.map +1 -1
  7. package/dist/components/autocomplete/autocomplete.styles.js +12 -0
  8. package/dist/components/autocomplete.css +31 -3
  9. package/dist/components/button-group.css +6 -6
  10. package/dist/components/button.css +7 -11
  11. package/dist/components/calendar-year-picker.css +1 -1
  12. package/dist/components/card.css +1 -1
  13. package/dist/components/color-input-group/color-input-group.styles.d.ts +27 -0
  14. package/dist/components/color-input-group/color-input-group.styles.d.ts.map +1 -1
  15. package/dist/components/color-input-group/color-input-group.styles.js +6 -0
  16. package/dist/components/color-input-group.css +21 -1
  17. package/dist/components/combo-box/combo-box.styles.d.ts +27 -0
  18. package/dist/components/combo-box/combo-box.styles.d.ts.map +1 -1
  19. package/dist/components/combo-box/combo-box.styles.js +17 -7
  20. package/dist/components/combo-box.css +21 -1
  21. package/dist/components/date-input-group/date-input-group.styles.d.ts +27 -0
  22. package/dist/components/date-input-group/date-input-group.styles.d.ts.map +1 -1
  23. package/dist/components/date-input-group/date-input-group.styles.js +6 -0
  24. package/dist/components/date-input-group.css +21 -1
  25. package/dist/components/dropdown.css +1 -1
  26. package/dist/components/index.css +4 -0
  27. package/dist/components/index.d.ts +4 -0
  28. package/dist/components/index.d.ts.map +1 -1
  29. package/dist/components/input/input.styles.d.ts +15 -0
  30. package/dist/components/input/input.styles.d.ts.map +1 -1
  31. package/dist/components/input/input.styles.js +6 -0
  32. package/dist/components/input-group/input-group.styles.d.ts +27 -0
  33. package/dist/components/input-group/input-group.styles.d.ts.map +1 -1
  34. package/dist/components/input-group/input-group.styles.js +6 -0
  35. package/dist/components/input-group.css +23 -1
  36. package/dist/components/input.css +13 -1
  37. package/dist/components/list-box/list-box.styles.d.ts +15 -0
  38. package/dist/components/list-box/list-box.styles.d.ts.map +1 -1
  39. package/dist/components/list-box/list-box.styles.js +15 -5
  40. package/dist/components/list-box-item.css +4 -2
  41. package/dist/components/list-box.css +19 -0
  42. package/dist/components/menu/menu.styles.d.ts +19 -1
  43. package/dist/components/menu/menu.styles.d.ts.map +1 -1
  44. package/dist/components/menu/menu.styles.js +9 -1
  45. package/dist/components/menu.css +19 -0
  46. package/dist/components/modal.css +1 -1
  47. package/dist/components/number-field/number-field.styles.d.ts +27 -0
  48. package/dist/components/number-field/number-field.styles.d.ts.map +1 -1
  49. package/dist/components/number-field/number-field.styles.js +6 -0
  50. package/dist/components/number-field.css +60 -1
  51. package/dist/components/pagination.css +6 -6
  52. package/dist/components/popover.css +15 -1
  53. package/dist/components/search-field/search-field.styles.d.ts +27 -0
  54. package/dist/components/search-field/search-field.styles.d.ts.map +1 -1
  55. package/dist/components/search-field/search-field.styles.js +6 -0
  56. package/dist/components/search-field.css +25 -1
  57. package/dist/components/segmented-control/index.d.ts +2 -0
  58. package/dist/components/segmented-control/index.d.ts.map +1 -0
  59. package/dist/components/segmented-control/index.js +2 -0
  60. package/dist/components/segmented-control/segmented-control.styles.d.ts +73 -0
  61. package/dist/components/segmented-control/segmented-control.styles.d.ts.map +1 -0
  62. package/dist/components/segmented-control/segmented-control.styles.js +27 -0
  63. package/dist/components/segmented-control.css +193 -0
  64. package/dist/components/select/select.styles.d.ts +33 -0
  65. package/dist/components/select/select.styles.d.ts.map +1 -1
  66. package/dist/components/select/select.styles.js +12 -0
  67. package/dist/components/select.css +31 -3
  68. package/dist/components/sidebar/index.d.ts +2 -0
  69. package/dist/components/sidebar/index.d.ts.map +1 -0
  70. package/dist/components/sidebar/index.js +2 -0
  71. package/dist/components/sidebar/sidebar.styles.d.ts +190 -0
  72. package/dist/components/sidebar/sidebar.styles.d.ts.map +1 -0
  73. package/dist/components/sidebar/sidebar.styles.js +52 -0
  74. package/dist/components/sidebar.css +510 -0
  75. package/dist/components/splitter/index.d.ts +2 -0
  76. package/dist/components/splitter/index.d.ts.map +1 -0
  77. package/dist/components/splitter/index.js +2 -0
  78. package/dist/components/splitter/splitter.styles.d.ts +61 -0
  79. package/dist/components/splitter/splitter.styles.d.ts.map +1 -0
  80. package/dist/components/splitter/splitter.styles.js +26 -0
  81. package/dist/components/splitter.css +241 -0
  82. package/dist/components/table.css +3 -3
  83. package/dist/components/tabs.css +2 -2
  84. package/dist/components/textarea/textarea.styles.d.ts +15 -0
  85. package/dist/components/textarea/textarea.styles.d.ts.map +1 -1
  86. package/dist/components/textarea/textarea.styles.js +6 -0
  87. package/dist/components/textarea.css +13 -1
  88. package/dist/components/toast.css +1 -1
  89. package/dist/components/toggle-button-group.css +7 -7
  90. package/dist/components/toggle-button.css +7 -11
  91. package/dist/components/toolbar.css +1 -1
  92. package/dist/components/tooltip.css +15 -2
  93. package/dist/components/virtualizer/index.d.ts +2 -0
  94. package/dist/components/virtualizer/index.d.ts.map +1 -0
  95. package/dist/components/virtualizer/index.js +2 -0
  96. package/dist/components/virtualizer/virtualizer.styles.d.ts +44 -0
  97. package/dist/components/virtualizer/virtualizer.styles.d.ts.map +1 -0
  98. package/dist/components/virtualizer/virtualizer.styles.js +15 -0
  99. package/dist/components/virtualizer.css +64 -0
  100. package/dist/index.js +5 -1
  101. package/dist/ropav.min.css +2 -2
  102. package/dist/themes/airbnb.css +5 -0
  103. package/dist/themes/all.css +1 -0
  104. package/dist/themes/coinbase.css +5 -0
  105. package/dist/themes/default.css +16 -4
  106. package/dist/themes/discord.css +5 -0
  107. package/dist/themes/hero.css +262 -0
  108. package/dist/themes/lavender.css +5 -0
  109. package/dist/themes/mint.css +5 -0
  110. package/dist/themes/netflix.css +5 -0
  111. package/dist/themes/rabbit.css +5 -0
  112. package/dist/themes/shared/theme.css +19 -2
  113. package/dist/themes/sky.css +5 -0
  114. package/dist/themes/spotify.css +5 -0
  115. package/dist/themes/uber.css +5 -0
  116. package/dist/utilities/index.css +27 -0
  117. package/package.json +1 -1
  118. package/src/components/autocomplete/autocomplete.styles.ts +12 -0
  119. package/src/components/color-input-group/color-input-group.styles.ts +10 -0
  120. package/src/components/combo-box/combo-box.styles.ts +12 -0
  121. package/src/components/date-input-group/date-input-group.styles.ts +10 -0
  122. package/src/components/index.ts +4 -0
  123. package/src/components/input/input.styles.ts +6 -0
  124. package/src/components/input-group/input-group.styles.ts +10 -0
  125. package/src/components/list-box/list-box.styles.ts +6 -0
  126. package/src/components/menu/menu.styles.ts +10 -0
  127. package/src/components/number-field/number-field.styles.ts +10 -0
  128. package/src/components/search-field/search-field.styles.ts +10 -0
  129. package/src/components/segmented-control/index.ts +1 -0
  130. package/src/components/segmented-control/segmented-control.styles.ts +37 -0
  131. package/src/components/select/select.styles.ts +12 -0
  132. package/src/components/sidebar/index.ts +1 -0
  133. package/src/components/sidebar/sidebar.styles.ts +94 -0
  134. package/src/components/splitter/index.ts +1 -0
  135. package/src/components/splitter/splitter.styles.ts +44 -0
  136. package/src/components/textarea/textarea.styles.ts +6 -0
  137. package/src/components/virtualizer/index.ts +1 -0
  138. package/src/components/virtualizer/virtualizer.styles.ts +15 -0
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./splitter.styles";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/splitter/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { splitterVariants } from "./splitter.styles.js";
2
+ export { splitterVariants };
@@ -0,0 +1,61 @@
1
+ import type { VariantProps } from "tailwind-variants";
2
+ export declare const splitterVariants: import("tailwind-variants").TVReturnType<{
3
+ orientation: {
4
+ horizontal: {
5
+ base: string;
6
+ handle: string;
7
+ handleGrip: string;
8
+ };
9
+ vertical: {
10
+ base: string;
11
+ handle: string;
12
+ handleGrip: string;
13
+ };
14
+ };
15
+ }, {
16
+ base: string;
17
+ handle: string;
18
+ handleGrip: string;
19
+ handleTarget: string;
20
+ panel: string;
21
+ }, undefined, {
22
+ orientation: {
23
+ horizontal: {
24
+ base: string;
25
+ handle: string;
26
+ handleGrip: string;
27
+ };
28
+ vertical: {
29
+ base: string;
30
+ handle: string;
31
+ handleGrip: string;
32
+ };
33
+ };
34
+ }, {
35
+ base: string;
36
+ handle: string;
37
+ handleGrip: string;
38
+ handleTarget: string;
39
+ panel: string;
40
+ }, import("tailwind-variants").TVReturnTypeLike<{
41
+ orientation: {
42
+ horizontal: {
43
+ base: string;
44
+ handle: string;
45
+ handleGrip: string;
46
+ };
47
+ vertical: {
48
+ base: string;
49
+ handle: string;
50
+ handleGrip: string;
51
+ };
52
+ };
53
+ }, {
54
+ base: string;
55
+ handle: string;
56
+ handleGrip: string;
57
+ handleTarget: string;
58
+ panel: string;
59
+ }>>;
60
+ export type SplitterVariants = VariantProps<typeof splitterVariants>;
61
+ //# sourceMappingURL=splitter.styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splitter.styles.d.ts","sourceRoot":"","sources":["../../../src/components/splitter/splitter.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAgBtD,eAAO,MAAM,gBAAgB;;QAavB,UAAU;YACR,IAAI;YACJ,MAAM;YACN,UAAU;;QAEZ,QAAQ;YACN,IAAI;YACJ,MAAM;YACN,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAIhB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { tv } from "tailwind-variants";
2
+ //#region src/components/splitter/splitter.styles.ts
3
+ const splitterVariants = tv({
4
+ defaultVariants: { orientation: "horizontal" },
5
+ slots: {
6
+ base: "splitter",
7
+ handle: "splitter__handle",
8
+ handleGrip: "splitter__handle-grip",
9
+ handleTarget: "splitter__handle-target",
10
+ panel: "splitter__panel"
11
+ },
12
+ variants: { orientation: {
13
+ horizontal: {
14
+ base: "splitter--horizontal",
15
+ handle: "splitter__handle--horizontal",
16
+ handleGrip: "splitter__handle-grip--horizontal"
17
+ },
18
+ vertical: {
19
+ base: "splitter--vertical",
20
+ handle: "splitter__handle--vertical",
21
+ handleGrip: "splitter__handle-grip--vertical"
22
+ }
23
+ } }
24
+ });
25
+ //#endregion
26
+ export { splitterVariants };