@wwtdev/bsds-css 2.31.0 → 2.32.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.
@@ -1,16 +1,29 @@
1
1
  :root {
2
- --bs-vertical-nav-width: 9.875rem;
2
+ --bs-vertical-nav-width: 11.25rem;
3
3
  --bs-vertical-nav-narrow-width: 4.5rem;
4
+ --bs-vertical-nav-collapsed-width: 4.5rem;
5
+ /* Dynamic width set by the navigation component for page layout */
6
+ --bs-page-nav-width: 0px;
4
7
  }
5
8
 
6
- .bs-vertical-nav {
9
+ .bs-vertical-nav-wrapper {
7
10
  --active-color: rgba(255, 255, 255, 0.25);
8
11
  --bg-color: var(--bs-navy-base);
9
12
  --border-color: var(--bs-border-dark);
13
+ --text-color: var(--bs-white);
14
+ --link-color: var(--bs-white);
15
+ --link-hover-color: var(--bs-white);
16
+ --link-active-color: var(--bs-white);
17
+ --toggle-bg-color: var(--bg-color);
18
+ --toggle-color: var(--bs-white);
10
19
  --top-offset: 48px;
20
+ }
21
+
22
+ .bs-vertical-nav {
11
23
  -ms-overflow-style: none; /* Internet Explorer 10+ */
12
24
  background-color: var(--bg-color);
13
- color: var(--bs-white);
25
+ border-inline-end: 1px solid var(--border-color);
26
+ color: var(--text-color);
14
27
  display: flex;
15
28
  flex-direction: column;
16
29
  height: 100dvh;
@@ -26,7 +39,6 @@
26
39
  right: 0;
27
40
  scrollbar-width: none; /* Firefox */
28
41
  top: var(--top-offset);
29
- /* Slight delay for visibility to change prior to opacity */
30
42
  transition: opacity 200ms ease 10ms;
31
43
  visibility: hidden;
32
44
  width: auto;
@@ -38,23 +50,21 @@
38
50
  visibility: visible;
39
51
  }
40
52
 
41
- .dark .bs-vertical-nav {
53
+ .bs-vertical-nav:where([data-collapsible="true"]) {
54
+ transition: opacity 200ms ease 10ms, width 350ms cubic-bezier(0.4, 0, 0.2, 1);
55
+ }
56
+
57
+ .dark .bs-vertical-nav-wrapper {
42
58
  --active-color: rgba(255, 255, 255, 0.25);
43
59
  --bg-color: var(--bs-bg-base);
44
- --border-color: var(--bs-border-dark);
45
- border-right: 1px solid var(--bs-border-medium);
60
+ --border-color: var(--bs-border-medium);
46
61
  }
47
62
 
48
63
  @media (min-width: 1166px) {
49
64
  .bs-vertical-nav {
50
- border-right: 1px solid var(--bg-color);
51
65
  opacity: 1;
52
- padding-bottom: 1rem;
53
- padding-left: 0.5rem;
54
- padding-right: 0.5rem;
55
- padding-top: 1rem;
66
+ padding: 1rem;
56
67
  right: auto;
57
- transition: none;
58
68
  visibility: visible;
59
69
  width: var(--bs-vertical-nav-width);
60
70
  }
@@ -62,25 +72,81 @@
62
72
  .bs-vertical-nav:where([data-narrow="true"]) {
63
73
  width: var(--bs-vertical-nav-narrow-width);
64
74
  }
75
+
76
+ .bs-vertical-nav:where([data-collapsed="true"]) {
77
+ width: var(--bs-vertical-nav-collapsed-width);
78
+ }
65
79
  }
66
80
 
67
81
  .bs-vertical-nav::-webkit-scrollbar {
68
82
  display: none; /* Safari and Chrome */
69
83
  }
70
84
 
85
+ /* ===== Collapse Toggle Button ===== */
86
+ .bs-vertical-nav-toggle {
87
+ align-items: center;
88
+ background: var(--toggle-bg-color);
89
+ border: 1px solid var(--border-color);
90
+ border-radius: 100px;
91
+ color: var(--toggle-color);
92
+ cursor: pointer;
93
+ display: none; /* Hidden by default on mobile */
94
+ height: 24px;
95
+ width: 24px;
96
+ justify-content: center;
97
+ padding: 0;
98
+ position: fixed;
99
+ left: calc(var(--bs-vertical-nav-width) - 0.5rem);
100
+ pointer-events: auto; /* Ensure button is clickable */
101
+ top: calc(var(--top-offset) + 1.125rem); /* top-offset + 18px */
102
+ transition: left 300ms ease-out, opacity 100ms ease-out;
103
+ z-index: 1002; /* Above nav to prevent hover conflicts */
104
+ }
105
+
106
+ @media (min-width: 1166px) {
107
+ .bs-vertical-nav-toggle {
108
+ display: flex;
109
+ opacity: 1;
110
+ transition: left 300ms ease-out, opacity 100ms ease-out;
111
+ }
112
+
113
+ .bs-vertical-nav-toggle:where([data-collapsed="true"]) {
114
+ left: calc(var(--bs-vertical-nav-collapsed-width) - 0.5rem);
115
+ }
116
+
117
+ /* Adjust position for narrow variant when NOT collapsed */
118
+ .bs-vertical-nav-toggle:where([data-narrow="true"]:not([data-collapsed="true"])) {
119
+ left: calc(var(--bs-vertical-nav-narrow-width) - 0.5rem);
120
+ }
121
+ }
122
+
123
+ .bs-vertical-nav-toggle-icon {
124
+ height: 8px;
125
+ width: 8px;
126
+ color: inherit;
127
+ transition: transform 200ms var(--bs-transition-ease);
128
+ will-change: transform;
129
+ flex-shrink: 0;
130
+ }
131
+
71
132
  /* ===== Sections ===== */
72
133
  .bs-vertical-nav :where(.bs-vertical-nav-section) {
73
- border-top: 2px solid var(--border-color);
134
+ border-top: 1px solid var(--border-color);
74
135
  margin-top: 0.5rem;
75
136
  padding-top: 0.5rem;
76
137
  }
77
138
 
78
139
  @media (min-width: 1166px) {
79
140
  .bs-vertical-nav :where(.bs-vertical-nav-section) {
80
- margin-top: 0.25rem;
141
+ margin-top: 0.5rem;
81
142
  }
82
143
  }
83
144
 
145
+ /* Divider-only sections have no additional padding since no toggle button */
146
+ .bs-vertical-nav :where(.bs-vertical-nav-section[data-divider-only="true"]) {
147
+ padding-top: 0.5rem;
148
+ }
149
+
84
150
  /* Don't show border if the very first item is a section */
85
151
  .bs-vertical-nav :where(ul li:first-child) {
86
152
  border-top: none;
@@ -105,7 +171,7 @@
105
171
  @media (min-width: 1166px) {
106
172
  .bs-vertical-nav :where(.bs-vertical-nav-section-toggle) {
107
173
  /* nav width - nav left padding - nav right padding */
108
- width: calc(var(--bs-vertical-nav-width) - 0.5rem - 0.5rem);
174
+ width: calc(var(--bs-vertical-nav-width) - 1rem - 1rem);
109
175
  }
110
176
 
111
177
  .bs-vertical-nav :where(.bs-vertical-nav-section-toggle span:first-child) {
@@ -113,7 +179,7 @@
113
179
  text-align: start;
114
180
  text-overflow: ellipsis;
115
181
  /* nav width - nav left padding - nav right padding - link left padding - link right padding - caret width */
116
- width: calc(var(--bs-vertical-nav-width) - 0.5rem - 0.5rem - 0.75rem - 0.75rem - 0.75rem);
182
+ width: calc(var(--bs-vertical-nav-width) - 1rem - 1rem - 0.75rem - 0.75rem - 0.75rem);
117
183
  }
118
184
  }
119
185
 
@@ -140,66 +206,72 @@
140
206
  padding-left: 0;
141
207
  }
142
208
 
143
- @media (min-width: 1166px) {
144
- .bs-vertical-nav :where(ul) {
145
- gap: 0.25rem;
146
- }
147
- }
148
-
149
209
  /* ===== Nav List Items / Links */
150
210
  .bs-vertical-nav :where(ul li a) {
151
211
  align-items: center;
152
212
  border-radius: 4px;
213
+ color: var(--link-color);
153
214
  cursor: pointer;
154
215
  display: flex;
155
216
  font-size: 1rem;
156
217
  font-weight: 400;
157
218
  gap: 0.5rem;
158
219
  height: 100%;
159
- padding-bottom: 0.75rem;
160
- padding-left: 0.75rem;
161
- padding-right: 0.75rem;
162
- padding-top: 0.75rem;
163
- width: 100%;
220
+ padding: 0.5rem 0.75rem;
221
+ position: relative;
222
+ }
223
+
224
+ /* Narrow variant - text always visible on desktop (overrides collapsed state) */
225
+ @media (min-width: 1166px) {
226
+ .bs-vertical-nav:where([data-narrow="true"]) :where(ul li a > span:last-child) {
227
+ opacity: 1;
228
+ visibility: visible;
229
+ width: auto;
230
+ }
164
231
  }
165
232
 
166
233
  @media (min-width: 1166px) {
167
234
  .bs-vertical-nav :where(ul li a) {
168
235
  font-size: 0.875rem;
169
- padding-bottom: 0.5rem;
170
- padding-top: 0.5rem;
236
+ min-height: 2.5rem; /* Fixed minimum height to prevent height changes */
237
+ padding: 0.5rem 0.75rem; /* Explicit padding for consistency */
171
238
  /* nav width - nav left padding - nav right padding */
172
- width: calc(var(--bs-vertical-nav-width) - 0.5rem - 0.5rem);
239
+ width: calc(var(--bs-vertical-nav-width) - 1rem - 1rem);
240
+ }
241
+
242
+ /* Collapsed state width */
243
+ .bs-vertical-nav:where([data-collapsed="true"]) :where(ul li a) {
244
+ /* collapsed width - nav left padding - nav right padding */
245
+ width: calc(var(--bs-vertical-nav-collapsed-width) - 1rem - 1rem);
173
246
  }
174
247
 
175
248
  /* Text overflow - normal width - no icon */
176
249
  .bs-vertical-nav :where(ul li a:not(:has(.bs-vertical-nav-link-icon)) span:first-child) {
177
250
  overflow: hidden;
178
251
  text-overflow: ellipsis;
252
+ white-space: nowrap;
179
253
  /* nav width - nav left padding - nav right padding - link left padding - link right padding */
180
- width: calc(var(--bs-vertical-nav-width) - 0.5rem - 0.5rem - 0.75rem - 0.75rem);
254
+ width: calc(var(--bs-vertical-nav-width) - 1rem - 1rem - 0.75rem - 0.75rem);
181
255
  }
182
256
 
183
257
  /* Text overflow - normal width - with icon */
184
258
  .bs-vertical-nav :where(ul li a:has(.bs-vertical-nav-link-icon) span:nth-child(2)) {
185
259
  overflow: hidden;
186
260
  text-overflow: ellipsis;
261
+ white-space: nowrap;
187
262
  /* nav width - nav left padding - nav right padding - link left padding - link right padding - icon width - icon gap */
188
- width: calc(var(--bs-vertical-nav-width) - 0.5rem - 0.5rem - 0.75rem - 0.75rem - 0.875rem - 0.5rem);
263
+ width: calc(var(--bs-vertical-nav-width) - 1rem - 1rem - 0.75rem - 0.75rem - 1rem - 0.5rem);
189
264
  }
190
265
 
191
266
  .bs-vertical-nav:where([data-narrow="true"]) :where(ul li a) {
192
267
  flex-direction: column;
193
268
  font-size: 0.6875rem;
194
- gap: 0.25rem;
269
+ gap: 0.5rem; /* 8px - matches Figma */
195
270
  line-height: 1.3;
196
- padding-bottom: 0.75rem;
197
- padding-left: 0.25rem;
198
- padding-right: 0.25rem;
199
- padding-top: 0.75rem;
271
+ padding: 0.5rem 0.75rem; /* 8px 12px - matches Figma */
200
272
  text-align: center;
201
273
  /* nav width - nav left padding - nav right padding */
202
- width: calc(var(--bs-vertical-nav-narrow-width) - 0.5rem - 0.5rem);
274
+ width: calc(var(--bs-vertical-nav-narrow-width) - 1rem - 1rem);
203
275
  }
204
276
 
205
277
  /* Text overflow - narrow width */
@@ -207,37 +279,160 @@
207
279
  .bs-vertical-nav:where([data-narrow="true"]) :where(ul li a:has(.bs-vertical-nav-link-icon) span:nth-child(2)) {
208
280
  overflow: hidden;
209
281
  text-overflow: ellipsis;
282
+ white-space: nowrap;
210
283
  /* nav width - nav left padding - nav right padding - link left padding */
211
284
  width: calc(var(--bs-vertical-nav-narrow-width) - 0.5rem - 0.5rem);
212
285
  }
213
286
  }
214
287
 
288
+ .bs-vertical-nav-section:where([data-app-links="true"]) {
289
+ padding-top: 1rem;
290
+ }
291
+
292
+ .bs-vertical-nav-section:where([data-app-links="true"]) :where(ul li a) {
293
+ padding: 0.375rem 0.5rem;
294
+ font-size: 0.75rem;
295
+ font-weight: 600;
296
+ }
297
+
215
298
  .bs-vertical-nav :where(ul li a:hover) {
299
+ color: var(--link-hover-color);
216
300
  font-weight: 600;
217
301
  }
218
302
 
303
+ .bs-vertical-nav-section:where([data-app-links="true"]) :where(ul li a:hover) {
304
+ color: var(--bs-ink-blue);
305
+ }
306
+
219
307
  .bs-vertical-nav :where(ul li a[data-active="true"]) {
220
308
  background-color: var(--active-color);
309
+ color: var(--link-active-color);
221
310
  font-weight: 600;
311
+ transition: background-color 200ms ease-out;
222
312
  }
223
313
 
314
+ /* Icon sizing - mobile/default */
224
315
  .bs-vertical-nav :where(.bs-vertical-nav-link-icon) {
225
316
  height: 1rem;
226
317
  width: 1rem;
318
+ flex-shrink: 0; /* Prevent icon from shrinking */
227
319
  }
228
320
 
229
321
  @media (min-width: 1166px) {
230
- .bs-vertical-nav :where(.bs-vertical-nav-link-icon) {
322
+ /* Wide and collapsible variant icons - 14px */
323
+ .bs-vertical-nav:not([data-narrow="true"]) :where(.bs-vertical-nav-link-icon) {
231
324
  height: 0.875rem;
232
325
  width: 0.875rem;
233
326
  }
234
327
 
328
+ /* Narrow variant icons - 16px (inherits from base) */
235
329
  .bs-vertical-nav:where([data-narrow="true"]) :where(.bs-vertical-nav-link-icon) {
236
330
  height: 1rem;
237
331
  width: 1rem;
238
332
  }
239
333
  }
240
334
 
335
+ .bs-vertical-nav-section:where([data-app-links="true"]) .bs-vertical-nav-link-icon {
336
+ height: 1.5rem;
337
+ width: 1.5rem;
338
+ margin-left: 0;
339
+ }
340
+
341
+ /* Default: Show text on mobile */
342
+ .bs-vertical-nav :where(ul li a > span:last-child) {
343
+ opacity: 1;
344
+ visibility: visible;
345
+ width: auto;
346
+ }
347
+
348
+ /* Desktop: Show text when NOT collapsed */
349
+ @media (min-width: 1166px) {
350
+ .bs-vertical-nav:not([data-collapsed="true"]) :where(ul li a > span:last-child) {
351
+ opacity: 1;
352
+ visibility: visible;
353
+ width: auto;
354
+ /* Immediate visibility when appropriate */
355
+ transition: opacity 150ms ease, visibility 0ms linear;
356
+ }
357
+ }
358
+
359
+ /* Desktop: Hide text when collapsed */
360
+ @media (min-width: 1166px) {
361
+ .bs-vertical-nav:where([data-collapsed="true"]) :where(ul li a > span:last-child) {
362
+ opacity: 0;
363
+ visibility: hidden;
364
+ width: 0;
365
+ overflow: hidden;
366
+ white-space: nowrap;
367
+ /* Delay visibility to prevent flash during breakpoint transition */
368
+ transition: opacity 150ms ease, visibility 0ms linear 150ms;
369
+ }
370
+ }
371
+
372
+ /* Keep icons visible when collapsed */
373
+ .bs-vertical-nav:where([data-collapsed="true"]) :where(.bs-vertical-nav-link-icon) {
374
+ display: block;
375
+ }
376
+
377
+ /* Hide section toggle when collapsed */
378
+ .bs-vertical-nav:where([data-collapsed="true"]) :where(.bs-vertical-nav-section-toggle) {
379
+ display: none;
380
+ }
381
+
382
+ /* ===== Hover Expansion (CSS-only) ===== */
383
+ @media (min-width: 1166px) {
384
+ /* Expand nav on hover when collapsed and collapsible - but NOT when hovering the toggle button */
385
+ .bs-vertical-nav-wrapper:where(:hover:not(:has(.bs-vertical-nav-toggle:hover))) :where(.bs-vertical-nav[data-collapsed="true"][data-collapsible="true"]) {
386
+ width: var(--bs-vertical-nav-width);
387
+ }
388
+
389
+ /* Narrow variant should respect narrow width on hover */
390
+ .bs-vertical-nav-wrapper:where(:hover:not(:has(.bs-vertical-nav-toggle:hover))) :where(.bs-vertical-nav[data-collapsed="true"][data-narrow="true"]) {
391
+ width: var(--bs-vertical-nav-narrow-width);
392
+ }
393
+
394
+ /* Expand link widths on hover when collapsed */
395
+ .bs-vertical-nav-wrapper:where(:hover:not(:has(.bs-vertical-nav-toggle:hover))) :where(.bs-vertical-nav[data-collapsed="true"]) :where(ul li a) {
396
+ width: calc(var(--bs-vertical-nav-width) - 1rem - 1rem);
397
+ }
398
+
399
+ /* Narrow variant links should respect narrow width on hover */
400
+ .bs-vertical-nav-wrapper:where(:hover:not(:has(.bs-vertical-nav-toggle:hover))) :where(.bs-vertical-nav[data-collapsed="true"][data-narrow="true"]) :where(ul li a) {
401
+ width: calc(var(--bs-vertical-nav-narrow-width) - 0.5rem - 0.5rem);
402
+ }
403
+
404
+ /* Show text on hover when collapsed */
405
+ .bs-vertical-nav-wrapper:where(:hover:not(:has(.bs-vertical-nav-toggle:hover))) :where(.bs-vertical-nav[data-collapsed="true"]) :where(ul li a > span:last-child) {
406
+ opacity: 1;
407
+ visibility: visible;
408
+ width: auto;
409
+ overflow: visible;
410
+ }
411
+
412
+ /* Hide toggle button on hover when collapsed - but NOT when hovering the button itself */
413
+ .bs-vertical-nav-wrapper:where(:hover:not(:has(.bs-vertical-nav-toggle:hover))) :where(.bs-vertical-nav-toggle[data-collapsed="true"]) {
414
+ opacity: 0;
415
+ pointer-events: none; /* Prevent interaction when hidden */
416
+ }
417
+
418
+ /* Show section toggles on hover when collapsed */
419
+ .bs-vertical-nav-wrapper:where(:hover:not(:has(.bs-vertical-nav-toggle:hover))) :where(.bs-vertical-nav[data-collapsed="true"]) :where(.bs-vertical-nav-section-toggle) {
420
+ display: flex;
421
+ }
422
+ }
423
+
424
+ /* ===== Top Content ===== */
425
+ .bs-vertical-nav :where(.bs-vertical-nav-top-content) {
426
+ margin-bottom: 0.5rem;
427
+ padding: 0;
428
+ }
429
+
430
+ @media (min-width: 1166px) {
431
+ .bs-vertical-nav :where(.bs-vertical-nav-top-content) {
432
+ margin-bottom: 0.75rem;
433
+ }
434
+ }
435
+
241
436
  /* ===== End Items ===== */
242
437
  .bs-vertical-nav :where(.bs-vertical-nav-end-items) {
243
438
  display: flex;
@@ -246,12 +441,25 @@
246
441
  margin-top: auto;
247
442
  }
248
443
 
444
+ /* End items visibility for collapsible variant (desktop only) */
445
+ @media (min-width: 1166px) {
446
+ /* Hide end items when collapsible variant is collapsed */
447
+ .bs-vertical-nav:where([data-collapsible="true"][data-collapsed="true"]) :where(.bs-vertical-nav-end-items) {
448
+ display: none;
449
+ }
450
+
451
+ /* Show end items on hover when collapsible variant is collapsed */
452
+ .bs-vertical-nav-wrapper:where(:hover:not(:has(.bs-vertical-nav-toggle:hover))) :where(.bs-vertical-nav[data-collapsible="true"][data-collapsed="true"]) :where(.bs-vertical-nav-end-items) {
453
+ display: flex;
454
+ }
455
+ }
456
+
249
457
  .bs-vertical-nav :where(.bs-vertical-nav-end-items > *) {
250
- color: var(--bs-white);
458
+ color: var(--text-color);
251
459
  }
252
460
 
253
461
  .bs-vertical-nav :where(.bs-vertical-nav-end-items > *:not(button)) {
254
- color: var(--bs-white);
462
+ color: var(--text-color);
255
463
  padding-bottom: 0.5rem;
256
464
  padding-left: 0.75rem;
257
465
  padding-right: 0.75rem;
@@ -271,6 +479,14 @@
271
479
  margin-top: 0.5rem;
272
480
  }
273
481
 
482
+ /* Hide end items in narrow variant (all screen sizes) */
274
483
  .bs-vertical-nav:where([data-narrow="true"]) :where(.bs-vertical-nav-end-items) {
275
484
  display: none;
276
485
  }
486
+
487
+ /* ===== CSS-Only Page Layout Support ===== */
488
+ /* Apply to any element that needs to adjust for navigation width (e.g., headers, main content) */
489
+ .bs-header-with-nav {
490
+ margin-inline-start: var(--bs-page-nav-width);
491
+ transition: margin-inline-start 350ms cubic-bezier(0.4, 0, 0.2, 1);
492
+ }