maverick-wave 5.17.0 → 5.20.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.
@@ -201,60 +201,117 @@
201
201
  }
202
202
  }
203
203
 
204
- @mixin navbar-off-canvas {
205
- position: fixed;
206
- top: 0;
207
- right: 0;
208
- --mw-navbar-drawer-width: 250px;
209
- width: var(--mw-navbar-drawer-width);
210
- height: 100dvh;
204
+ // The panel rides under the bar, not beside it. A drawer pinned to the right
205
+ // edge runs into the logo: 250px of panel against a 180px logo leaves 60px of
206
+ // overlap on a phone, and .mw-logo sits higher in the header's stacking
207
+ // context, so the logo prints on top of the menu. Under the bar there is
208
+ // nothing to collide with, at any logo width.
209
+ //
210
+ // position: absolute against the header and not fixed against the viewport:
211
+ // the header carries a backdrop-filter, which makes it the containing block
212
+ // for a fixed child anyway - at that point the anchoring is only nominally to
213
+ // the viewport, and every place the bar moves has to be undone by hand. Bound
214
+ // to the bar it simply travels with it.
215
+ @mixin navbar-top-sheet {
216
+ position: absolute;
217
+ top: 100%;
218
+ left: spacing('0');
219
+ right: spacing('0');
220
+ width: auto;
221
+ height: auto;
211
222
  background: var(--mw-header-background);
212
- border-left: 1px solid var(--mw-header-border);
223
+ backdrop-filter: blur(7px);
224
+ // Both edges: the panel covers the bar's own bottom border - top: 100%
225
+ // lands on the padding box, which is above it - so without one of its own
226
+ // the bar and the panel read as a single block of colour.
227
+ border-top: 1px solid var(--mw-header-border);
228
+ border-bottom: 1px solid var(--mw-header-border);
213
229
  box-shadow:
214
- -6px 0 12px var(--mw-shadow-near),
215
- -18px 0 40px var(--mw-shadow-far);
230
+ 0 6px 12px var(--mw-shadow-near),
231
+ 0 18px 40px var(--mw-shadow-far);
216
232
  z-index: z-index('header') + 3;
217
233
 
218
- transform: translateX(100%);
234
+ // Rolled out from under the bar rather than slid in. A slide needs a place
235
+ // to start, and the only direction with room is straight up through the
236
+ // header - which would take the panel behind its own stacking context root,
237
+ // where a child cannot go. The clip does the same thing visually and needs
238
+ // no z-index trick.
239
+ clip-path: inset(0 0 100% 0);
219
240
  visibility: hidden;
220
241
  transition:
221
- transform var(--mw-duration-base) var(--mw-ease-out),
242
+ clip-path var(--mw-duration-base) var(--mw-ease-out),
222
243
  visibility var(--mw-duration-base);
223
244
 
224
245
  .mw-navbar-list {
225
246
  display: flex;
226
247
  flex-direction: column;
227
248
  align-items: stretch;
228
- gap: spacing('1');
229
- height: 100%;
249
+ gap: spacing('0');
250
+ // The list is a flex item of the panel, so without this it shrinks to the
251
+ // width of its longest label and the rows end a third of the way across
252
+ width: 100%;
253
+ // Tall menus stay reachable without the panel growing past the screen
254
+ max-height: calc(100dvh - var(--mw-header-height));
230
255
  overflow-y: auto;
231
256
  // Keeps a rubber-band scroll inside the panel from moving the page
232
257
  overscroll-behavior: contain;
233
- padding: calc(
234
- var(--mw-header-height) + #{spacing('6')} +
235
- env(safe-area-inset-top, 0px)
236
- )
237
- spacing('4') calc(#{spacing('6')} + env(safe-area-inset-bottom, 0px));
258
+ // The gutter sits on the link, not here, so a row's hover and its tap
259
+ // target run the full width of the panel instead of stopping at the text
260
+ padding-bottom: env(safe-area-inset-bottom, 0px);
261
+
262
+ // From here a row fits, and a full-width band with four links stacked in
263
+ // its left corner is mostly empty band. Wrapping, because the count is
264
+ // the page's business, not the framework's.
265
+ @include media-up('sm') {
266
+ flex-direction: row;
267
+ flex-wrap: wrap;
268
+ align-items: center;
269
+ gap: spacing('2');
270
+ padding: spacing('3') var(--mw-container-gutter)
271
+ calc(#{spacing('3')} + env(safe-area-inset-bottom, 0px));
272
+ }
238
273
  }
239
274
 
240
275
  .mw-navbar-item {
241
276
  width: 100%;
242
277
  margin: spacing('0');
243
278
  opacity: 0;
244
- transform: translateX(12px);
279
+ transform: translateY(-8px);
280
+
281
+ // Rules between the rows, not around the block: a line above the first
282
+ // one would double the panel's own top border, one below the last would
283
+ // double its bottom.
284
+ + .mw-navbar-item .mw-navbar-link {
285
+ border-top: 1px solid var(--mw-header-border);
286
+ }
287
+
288
+ @include media-up('sm') {
289
+ width: auto;
290
+
291
+ + .mw-navbar-item .mw-navbar-link {
292
+ border-top: none;
293
+ }
294
+ }
245
295
  }
246
296
 
247
297
  .mw-navbar-link {
248
298
  display: flex;
249
299
  align-items: center;
250
- min-height: 48px;
300
+ min-height: 52px;
251
301
  width: 100%;
252
- padding: spacing('3') spacing('4');
253
- border-radius: radius('md');
254
- font-size: font-size('md');
302
+ padding: spacing('3') var(--mw-container-gutter);
303
+ border-radius: radius('none');
304
+ font-size: font-size('lg');
255
305
  text-align: left;
256
306
  color: var(--mw-header-text-color);
257
307
 
308
+ @include media-up('sm') {
309
+ min-height: 44px;
310
+ padding: spacing('3') spacing('4');
311
+ border-radius: radius('md');
312
+ font-size: font-size('md');
313
+ }
314
+
258
315
  // The sliding underline is a hover affordance and has no place on touch
259
316
  &::after {
260
317
  display: none;
@@ -274,16 +331,22 @@
274
331
  @include active() {
275
332
  color: var(--mw-header-navbar-list-active-color);
276
333
  background: var(--mw-primary-background);
334
+ // Marks the left edge of a stacked list. In a row the links are pills
335
+ // and the same rule would draw a stray tick inside each of them.
277
336
  box-shadow: inset 3px 0 0 var(--mw-header-navbar-list-active-color);
278
337
  font-weight: font-weight('medium');
338
+
339
+ @include media-up('sm') {
340
+ box-shadow: none;
341
+ }
279
342
  }
280
343
  }
281
344
 
282
345
  &.open {
283
- transform: translateX(0);
346
+ clip-path: inset(0 0 0 0);
284
347
  visibility: visible;
285
348
 
286
- // Items follow the panel in, slightly staggered
349
+ // Items follow the panel out, slightly staggered
287
350
  .mw-navbar-item {
288
351
  animation: mw-navbar-item-in var(--mw-duration-base) var(--mw-ease-out)
289
352
  forwards;
@@ -307,26 +370,29 @@
307
370
  }
308
371
  }
309
372
 
310
- @mixin navbar-scrim($navbar-selector) {
311
- body:has(#{$navbar-selector}.open) {
312
- overflow: hidden;
313
-
314
- &::after {
315
- content: '';
316
- position: fixed;
317
- inset: 0;
318
- background: var(--mw-overlay-background);
319
- backdrop-filter: blur(2px);
320
- z-index: z-index('header') - 1;
321
- animation: mw-navbar-scrim-in var(--mw-duration-base) var(--mw-ease-out);
322
- }
373
+ // One block for every navbar size, keyed off the class the script sets rather
374
+ // than off `:has()` and a breakpoint: the panel can only be open when the
375
+ // burger is on screen, and the burger is on screen only below its own
376
+ // breakpoint - so the state already carries what three media queries used to
377
+ // spell out.
378
+ body.mw-nav-open {
379
+ overflow: hidden;
380
+
381
+ &::after {
382
+ content: '';
383
+ position: fixed;
384
+ inset: 0;
385
+ background: var(--mw-overlay-background);
386
+ backdrop-filter: blur(2px);
387
+ z-index: z-index('header') - 1;
388
+ animation: mw-navbar-scrim-in var(--mw-duration-base) var(--mw-ease-out);
323
389
  }
324
390
  }
325
391
 
326
392
  @keyframes mw-navbar-item-in {
327
393
  to {
328
394
  opacity: 1;
329
- transform: translateX(0);
395
+ transform: translateY(0);
330
396
  }
331
397
  }
332
398
 
@@ -401,37 +467,24 @@
401
467
  // Auto-responsive behavior based on nav item count
402
468
  // Default behavior (1-3 items): collapse at md
403
469
  @include media-down('md') {
404
- @include navbar-off-canvas;
470
+ @include navbar-top-sheet;
405
471
  }
406
472
 
407
473
  // Medium (4-5 items): collapse at lg
408
474
  &.mw-navbar-medium {
409
475
  @include media-down('lg') {
410
- @include navbar-off-canvas;
476
+ @include navbar-top-sheet;
411
477
  }
412
478
  }
413
479
 
414
480
  // Large (6+ items): collapse at xl
415
481
  &.mw-navbar-large {
416
482
  @include media-down('xl') {
417
- @include navbar-off-canvas;
483
+ @include navbar-top-sheet;
418
484
  }
419
485
  }
420
486
  }
421
487
 
422
- // Every variant is collapsed at md, so the default selector covers them all
423
- @include media-down('md') {
424
- @include navbar-scrim('.mw-navbar');
425
- }
426
-
427
- @include media-down('lg') {
428
- @include navbar-scrim('.mw-navbar-medium');
429
- }
430
-
431
- @include media-down('xl') {
432
- @include navbar-scrim('.mw-navbar-large');
433
- }
434
-
435
488
  .mw-navbar {
436
489
  // Default (1-3 items): show burger at md
437
490
  @include media-down('md') {