maverick-wave 5.3.0 → 5.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/.claude/skills/mw-maverick-wave/SKILL.md +13 -4
- package/.claude/skills/mw-maverick-wave/examples/angular-services.md +91 -0
- package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +5 -4
- package/.claude/skills/mw-maverick-wave/references/components.md +7 -0
- package/.claude/skills/mw-maverick-wave/references/javascript.md +20 -2
- package/.claude/skills/mw-maverick-wave/references/layout.md +81 -10
- package/.claude/skills/mw-maverick-wave/references/theming.md +10 -0
- package/CHANGELOG.md +18 -0
- package/CLAUDE.md +1 -1
- package/README.md +3 -4
- package/index.html +291 -3
- package/maverick-wave.min.css +6 -4
- package/maverick-wave.min.js +1 -1
- package/package.json +2 -2
- package/scripts/verify.js +4 -7
- package/src/js/main.js +237 -11
- package/src/partials/documentation-container.html +4 -0
- package/src/partials/footer-container.html +3 -0
- package/src/partials/history-container.html +67 -0
- package/src/partials/home-container.html +2 -0
- package/src/partials/palette-container.html +142 -0
- package/src/partials/parallax-container.html +114 -0
- package/src/scss/abstracts/_mixins.scss +6 -5
- package/src/scss/abstracts/_variables.scss +4 -0
- package/src/scss/base/_base.scss +1 -0
- package/src/scss/base/_reset.scss +4 -1
- package/src/scss/components/_accordions.scss +31 -7
- package/src/scss/components/_toasts.scss +1 -1
- package/src/scss/form-elements/_slider.scss +5 -23
- package/src/scss/layout/_header-reveal.scss +133 -0
- package/src/scss/layout/_index.scss +4 -0
- package/src/scss/layout/_main.scss +17 -2
- package/src/scss/layout/_parallax.scss +178 -0
- package/src/scss/utilities/_reveal.scss +22 -0
- package/.impeccable/config.local.json +0 -5
- package/.impeccable/hook.cache.json +0 -75
|
@@ -44,14 +44,14 @@ Load the one you need - do not read them all up front.
|
|
|
44
44
|
```html
|
|
45
45
|
<link
|
|
46
46
|
rel="stylesheet"
|
|
47
|
-
href="https://cdn.jsdelivr.net/npm/maverick-wave@5.
|
|
47
|
+
href="https://cdn.jsdelivr.net/npm/maverick-wave@5.5.0/maverick-wave.min.css"
|
|
48
48
|
/>
|
|
49
49
|
<link
|
|
50
50
|
rel="stylesheet"
|
|
51
51
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
|
|
52
52
|
/>
|
|
53
53
|
...
|
|
54
|
-
<script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.
|
|
54
|
+
<script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.5.0/maverick-wave.min.js"></script>
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
Pin the version. The JS file is optional and only for server-rendered/static pages -
|
|
@@ -233,7 +233,8 @@ feature frame) ·
|
|
|
233
233
|
`-highlight`, `-static`, color variants) · `mw-empty-state` ·
|
|
234
234
|
`mw-spinner-border` / `mw-spinner-dots` / `mw-spinner-dual-ring` · `mw-skeleton`
|
|
235
235
|
|
|
236
|
-
**Navigation** `mw-header` + `mw-
|
|
236
|
+
**Navigation** `mw-header` (+ `mw-header-reveal`) + `mw-navbar` ·
|
|
237
|
+
`mw-breadcrumbs` · `mw-pagination` ·
|
|
237
238
|
`mw-dropdown` (+ `-menu`, `-item`, `-item-danger`, `-divider`, `-label`,
|
|
238
239
|
`-caret`, `-end`, `-up`) · `mw-lang-switch` (+ `-code`, `-name`, `-check`,
|
|
239
240
|
`inverted`) · `mw-flag` (+ 23 country codes) ·
|
|
@@ -252,7 +253,9 @@ feature frame) ·
|
|
|
252
253
|
|
|
253
254
|
**Layout** (`references/layout.md`) `mw-main` · `mw-container` · `mw-content` ·
|
|
254
255
|
`mw-section` (+ `mw-section-intro`) · `mw-page-header` · `mw-grid-*` ·
|
|
255
|
-
`mw-columns-2/3` · `mw-row-split` · `mw-hero` (+ `mw-scroll-hint`, `-end`) ·
|
|
256
|
+
`mw-columns-2/3` · `mw-row-split` · `mw-hero` (+ `mw-scroll-hint`, `-end`) ·
|
|
257
|
+
`mw-parallax` (+ `-media`, `-content`, `-dimmed`, `-sticky`, `-rise`,
|
|
258
|
+
`-pattern`) · `mw-footer`
|
|
256
259
|
|
|
257
260
|
**Utilities** (`references/layout.md`) `mw-sr-only` / `mw-sr-only-focusable` /
|
|
258
261
|
`mw-skip-link` · `mw-row-split` (+ `center`) · `mw-text-numeric` /
|
|
@@ -403,3 +406,9 @@ feature frame) ·
|
|
|
403
406
|
control height and works on an `<a>` and a `<button>` alike.
|
|
404
407
|
`mw-btn mw-btn-link` stays right where the link really is one of several
|
|
405
408
|
buttons and has to line up with them - a card's actions, a button bar.
|
|
409
|
+
29. **`mw-parallax-sticky` goes on the section, not on the hero.** Sticky pins
|
|
410
|
+
inside its parent, and the rule that lifts the page above the pinned picture
|
|
411
|
+
reaches that content as a _sibling_. Put the class on the hero itself and
|
|
412
|
+
nothing pins and nothing covers - no error, no effect, and the picture shows
|
|
413
|
+
through every transparent section below. `mw-parallax` and the
|
|
414
|
+
`mw-parallax-media` child stay where the image is: on the container.
|
|
@@ -369,3 +369,94 @@ about the class name.
|
|
|
369
369
|
|
|
370
370
|
`mw-progress-percent` only appends the `%` sign - the number comes from you, and
|
|
371
371
|
so does the width.
|
|
372
|
+
|
|
373
|
+
## Scroll reveal
|
|
374
|
+
|
|
375
|
+
`mw-reveal` runs on the browser's scroll timeline and needs nothing from you -
|
|
376
|
+
except in Firefox, which ships none, where the block appears without motion.
|
|
377
|
+
This directive is the Firefox half: it adds to the class, never replaces it.
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
import {
|
|
381
|
+
DestroyRef,
|
|
382
|
+
Directive,
|
|
383
|
+
ElementRef,
|
|
384
|
+
afterNextRender,
|
|
385
|
+
inject,
|
|
386
|
+
signal,
|
|
387
|
+
} from '@angular/core';
|
|
388
|
+
|
|
389
|
+
@Directive({
|
|
390
|
+
selector: '[mwReveal]',
|
|
391
|
+
host: {
|
|
392
|
+
'[class.mw-reveal-hidden]': "state() === 'hidden'",
|
|
393
|
+
'[class.mw-reveal-run]': "state() === 'run'",
|
|
394
|
+
'[style.animation-delay.ms]': 'delay()',
|
|
395
|
+
},
|
|
396
|
+
})
|
|
397
|
+
export class MwRevealDirective {
|
|
398
|
+
private readonly host =
|
|
399
|
+
inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;
|
|
400
|
+
|
|
401
|
+
protected readonly state = signal<'off' | 'hidden' | 'run'>('off');
|
|
402
|
+
protected readonly delay = signal(0);
|
|
403
|
+
|
|
404
|
+
constructor() {
|
|
405
|
+
const destroyRef = inject(DestroyRef);
|
|
406
|
+
|
|
407
|
+
afterNextRender(() => {
|
|
408
|
+
if (CSS.supports('animation-timeline', 'view()')) return;
|
|
409
|
+
if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
|
410
|
+
// Already on screen: past its entry range in a timeline browser too
|
|
411
|
+
if (this.host.getBoundingClientRect().top < innerHeight) return;
|
|
412
|
+
|
|
413
|
+
this.state.set('hidden');
|
|
414
|
+
|
|
415
|
+
const observer = new IntersectionObserver(
|
|
416
|
+
([entry]) => {
|
|
417
|
+
if (!entry.isIntersecting) return;
|
|
418
|
+
observer.disconnect();
|
|
419
|
+
this.delay.set(this.columnDelay());
|
|
420
|
+
this.state.set('run');
|
|
421
|
+
},
|
|
422
|
+
{ threshold: 0.15 }
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
observer.observe(this.host);
|
|
426
|
+
destroyRef.onDestroy(() => observer.disconnect());
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// The wave a grid draws in CSS, read back from the columns the browser
|
|
431
|
+
// rendered - one on a phone, so the stagger disappears with them.
|
|
432
|
+
private columnDelay(): number {
|
|
433
|
+
const grid = this.host.parentElement;
|
|
434
|
+
if (!grid?.classList.contains('mw-reveal-stagger')) return 0;
|
|
435
|
+
const columns =
|
|
436
|
+
getComputedStyle(grid).gridTemplateColumns.split(' ').length;
|
|
437
|
+
return ([...grid.children].indexOf(this.host) % columns) * 90;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
A single block carries `mw-reveal`, a grid carries `mw-reveal-stagger` and its
|
|
443
|
+
children carry nothing but the directive:
|
|
444
|
+
|
|
445
|
+
```html
|
|
446
|
+
<article class="mw-card mw-reveal" mwReveal>...</article>
|
|
447
|
+
|
|
448
|
+
<div class="mw-grid-4 mw-reveal-stagger">
|
|
449
|
+
@for (item of items(); track item.id) {
|
|
450
|
+
<article class="mw-card" mwReveal>...</article>
|
|
451
|
+
}
|
|
452
|
+
</div>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Unlike the shipped script this also covers what a route renders later - the
|
|
456
|
+
directive runs per element, not once per page.
|
|
457
|
+
|
|
458
|
+
`mw-header-reveal` and `mw-parallax` need the same treatment and the same
|
|
459
|
+
`CSS.supports` guard. The header is a class toggled past a scroll threshold; the
|
|
460
|
+
parallax writes `--mw-parallax-progress` (0 to 1) on each `mw-parallax-media`
|
|
461
|
+
from a `requestAnimationFrame` loop, reading every layer's rect before writing
|
|
462
|
+
to any of them.
|
|
@@ -20,7 +20,7 @@ accordion FAQ.
|
|
|
20
20
|
|
|
21
21
|
<link
|
|
22
22
|
rel="stylesheet"
|
|
23
|
-
href="https://cdn.jsdelivr.net/npm/maverick-wave@5.
|
|
23
|
+
href="https://cdn.jsdelivr.net/npm/maverick-wave@5.5.0/maverick-wave.min.css"
|
|
24
24
|
/>
|
|
25
25
|
<link
|
|
26
26
|
rel="stylesheet"
|
|
@@ -487,7 +487,7 @@ accordion FAQ.
|
|
|
487
487
|
<div class="mw-modal-backdrop" onclick="closeModal('demo')"></div>
|
|
488
488
|
</div>
|
|
489
489
|
|
|
490
|
-
<script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.
|
|
490
|
+
<script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.5.0/maverick-wave.min.js"></script>
|
|
491
491
|
<script>
|
|
492
492
|
// The only thing the shipped script does not cover: opening a modal.
|
|
493
493
|
// Closing works through .mw-modal-close, the backdrop is wired above.
|
|
@@ -523,8 +523,9 @@ accordion FAQ.
|
|
|
523
523
|
- `mw-reveal-stagger` goes on the grid (or `mw-columns-*`) and reveals every
|
|
524
524
|
child as it scrolls in, the second and third of each three a beat later.
|
|
525
525
|
`mw-reveal` on a single block reveals that block as one. Both are off under
|
|
526
|
-
`prefers-reduced-motion
|
|
527
|
-
|
|
526
|
+
`prefers-reduced-motion`. A page like this one loads the script, so Firefox -
|
|
527
|
+
which has no scroll timelines - runs the same entrance off an observer;
|
|
528
|
+
without the script the blocks stand in place, never invisible.
|
|
528
529
|
- `mw-offer` on a card pushes the price row to the bottom of the body, so the
|
|
529
530
|
prices in a row line up. The `mw-card-feature` frame around the middle plan
|
|
530
531
|
reaches 29px above its card - the `mw-mt-10` on the grid is that room.
|
|
@@ -536,6 +536,9 @@ still renders the same, for markup written before 4.12.
|
|
|
536
536
|
Open state = `mw-active` on header **and** content (bare `active` still works
|
|
537
537
|
but is deprecated). The icon rotates via the **header** state - putting the
|
|
538
538
|
class on the icon instead does nothing. Content taller than 500px scrolls.
|
|
539
|
+
The `mw-accordion-content-inner` wrapper is required and not decoration: the
|
|
540
|
+
panel opens by animating a grid row and that wrapper is the row, so content
|
|
541
|
+
placed straight into `mw-accordion-content` never collapses when closed.
|
|
539
542
|
Toggling is JS - see `references/javascript.md`; the shipped script keeps
|
|
540
543
|
`aria-expanded` in step when the header is a button.
|
|
541
544
|
|
|
@@ -699,6 +702,10 @@ The height lives in `--mw-announcement-height` and drives the anchor scroll
|
|
|
699
702
|
offset (`scroll-padding-top`) automatically - a taller ribbon raises the token
|
|
700
703
|
instead of fighting the offset.
|
|
701
704
|
|
|
705
|
+
On a page whose header carries `mw-header-reveal` the ribbon leaves and arrives
|
|
706
|
+
with it, without a class of its own - both cover the height of the pair, so they
|
|
707
|
+
come in as one block. See `references/layout.md`.
|
|
708
|
+
|
|
702
709
|
## Empty state
|
|
703
710
|
|
|
704
711
|
```html
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## What `maverick-wave.min.js` is
|
|
4
4
|
|
|
5
|
-
One vanilla IIFE, no dependencies, ~
|
|
5
|
+
One vanilla IIFE, no dependencies, ~23 kB. It queries the DOM **once** on
|
|
6
6
|
`DOMContentLoaded` and attaches listeners. There is no re-init API, no
|
|
7
7
|
`MutationObserver`, no exported module - it is built for a server-rendered or
|
|
8
8
|
static page.
|
|
@@ -32,6 +32,7 @@ classes are the entire contract.
|
|
|
32
32
|
| Modal | Click on `mw-modal-close` removes `mw-modal-open` from the overlay | `[class.mw-modal-open]="isOpen()"`; backdrop click closes. Opening is not in the script at all (the showcase has its own `openModal`) |
|
|
33
33
|
| Mobile nav | Toggles `open` on `mw-menu-btn` and `mw-navbar`, writes `aria-expanded` when the button is a `<button>`, closes on anchor click and on Escape (focus returns to the button) | One signal, bound to both; reset it on navigation end |
|
|
34
34
|
| Scroll spy | Sets `mw-active` on `mw-navbar-link` from the scroll position | Router-based: `routerLinkActive="mw-active"` |
|
|
35
|
+
| Anchor scrolling | Intercepts `a[href^="#"]` and runs its own eased scroll - duration scales with distance, capped at 1.4s, cancelled by wheel or touch. Lands on `scroll-padding-top`, moves focus to the target, writes the hash with `replaceState`, and measures a sticky target unpinned | The router; for in-page anchors `scrollIntoView({ behavior: 'smooth' })` or your own animation |
|
|
35
36
|
| Theme toggle | `localStorage['mw-theme']`, toggles `mw-theme-light` on `<body>` and `mw-active` on the toggle, wrapped in `mw-theme-switching` on `<html>` so the flip starts no transitions | A theme service - see `examples/angular-services.md` |
|
|
36
37
|
| Progress bar | `IntersectionObserver` sets `width` from `data-value` | Bind `[style.width.%]="value()"` on `mw-progress-fill` |
|
|
37
38
|
| Slider | On `input`, sets `--value` (track fill) and `data-value` (badge text) | Bind `[style.--value.%]` and `[attr.data-value]` |
|
|
@@ -43,9 +44,26 @@ classes are the entire contract.
|
|
|
43
44
|
| Calendar | Renders the month or week grid from `data-calendar="month | week"`, pages with `data-calendar-nav`, draws the status dots from `data-calendar-markers`, toggles `mw-selected`and emits`mw-calendar-select` | Render the cells from a signal and bind `mw-calendar-adjacent`, `mw-calendar-weekend`, `mw-calendar-today` and `mw-selected` yourself; none of the `data-calendar-*` attributes are needed |
|
|
44
45
|
| Localhost indicator | On a local hostname, prepends `mw-localhost-indicator-pulse` to the header when it carries `mw-localhost-indicator-activated` | Render the element conditionally |
|
|
45
46
|
| Header login button | Swaps the FontAwesome lock icon | Bind the icon class |
|
|
46
|
-
| Color swatches | Showcase-only (prints computed hex values)
|
|
47
|
+
| Color swatches | Showcase-only (prints computed hex values); exposes `window.mwRefreshColorSwatches` to read them again after a root colour changed | Not needed |
|
|
47
48
|
| Dropdown | Delegated to the document: closes the open `mw-dropdown` on Escape, on a click elsewhere and on a click on a `mw-dropdown-item`, and returns focus to the `summary` | The `<details>` does the opening, the keyboard and the state on its own. Rebuild only the two behaviours markup cannot express - or bind `[attr.open]` and keep them in the component |
|
|
48
49
|
| Language switcher | Keeps the trigger's flag and code in step with the chosen item, moves `mw-active` and `aria-current`, and fires `mw-language-change` (`detail: { lang, name }`) on the switcher | Bind the trigger from your locale signal and switch the language in your own i18n service; the menu itself is a `<details>` and needs nothing |
|
|
50
|
+
| Scroll reveal | Firefox only: an `IntersectionObserver` adds `mw-reveal-hidden` to what is still below the fold and swaps it for `mw-reveal-run` on entry, with an `animation-delay` per grid column | A directive per element - see `examples/angular-services.md` |
|
|
51
|
+
| Header reveal | Firefox only: toggles `mw-header-away` and `mw-announcement-away` past 270px of scroll, and adds the transition class one frame later so the bar does not slide away on load | The same two classes bound to a scroll signal, behind the same guard |
|
|
52
|
+
| Parallax | Firefox only: writes `--mw-parallax-progress` (0 to 1) on every `mw-parallax-media` from a `requestAnimationFrame` loop | The same, reading every layer's rect before writing to any of them |
|
|
53
|
+
|
|
54
|
+
## Scroll-driven animations
|
|
55
|
+
|
|
56
|
+
Four things ride the browser's own scroll timeline: `mw-reveal`,
|
|
57
|
+
`mw-header-reveal`, `mw-parallax` and the `mw-progress-fill` scrub. In Chrome,
|
|
58
|
+
Edge and Safari they need no script at all. Firefox ships no scroll timelines,
|
|
59
|
+
so there - and only there - the shipped JS stands in for them. Each one checks
|
|
60
|
+
`CSS.supports('animation-timeline', ...)` first and does nothing where the
|
|
61
|
+
browser has it.
|
|
62
|
+
|
|
63
|
+
Without the script Firefox loses the motion and nothing else: cards stand in
|
|
64
|
+
place, the picture holds still. The exception is `mw-header-reveal`, where the
|
|
65
|
+
bar then sits over the hero from the first paint - a layout difference, not a
|
|
66
|
+
missing effect.
|
|
49
67
|
|
|
50
68
|
## Modals and progress bars
|
|
51
69
|
|
|
@@ -133,6 +133,19 @@ same height as the login and burger buttons.
|
|
|
133
133
|
to configure dark-theme values to change it. The bar itself is the primary
|
|
134
134
|
darkened toward black, `$header-surface` (14%) - see `theming.md`.
|
|
135
135
|
|
|
136
|
+
**Reveal on scroll.** `mw-header-reveal` keeps the bar above the screen and
|
|
137
|
+
rides it in over the first 420px of scroll - for a page that opens on a
|
|
138
|
+
full-bleed hero and wants nothing on top of it. It animates `top` and not a
|
|
139
|
+
transform, because a transform on the header would make it the containing block
|
|
140
|
+
of the off-canvas drawer inside it, at every value including the resting one.
|
|
141
|
+
A fixed `mw-announcement` rides along without a class of its own - both cover
|
|
142
|
+
the height of the pair, so they arrive as one block rather than the ribbon
|
|
143
|
+
catching up. Focus inside either brings both back regardless of the scroll
|
|
144
|
+
position, so tabbing never lands on a link that is off screen (WCAG 2.4.11).
|
|
145
|
+
Under `prefers-reduced-motion` the bar is simply there, and so it is without
|
|
146
|
+
scroll timelines unless `maverick-wave.min.js` is on the page - in Firefox that
|
|
147
|
+
is what rides it in (`javascript.md`).
|
|
148
|
+
|
|
136
149
|
**Localhost indicator.** Put `mw-localhost-indicator-activated` on the header
|
|
137
150
|
and the shipped JS prepends a pulsing bar when the host is localhost/127.0.0.1/
|
|
138
151
|
192.168.\*. In a SPA, reimplement it: add a `<div class="mw-localhost-indicator-pulse">`
|
|
@@ -307,6 +320,61 @@ whose text is not centred either - and gives the hero its full height back.
|
|
|
307
320
|
Below `md` both variants sit in the corner, because the middle under the text
|
|
308
321
|
is taken on a phone. The bobbing stops under `prefers-reduced-motion`.
|
|
309
322
|
|
|
323
|
+
**Parallax** - `mw-parallax` on the container plus a `mw-parallax-media` child
|
|
324
|
+
moves the picture into its own layer. The container drops its own background and
|
|
325
|
+
the layer reads `--mw-hero-background`, so the image stays configured in one
|
|
326
|
+
place. Both modes run on the browser's scroll timeline, and on no
|
|
327
|
+
`background-attachment: fixed`, which iOS ignores. Firefox has neither timeline;
|
|
328
|
+
there the shipped JS moves the layers instead, and without it the picture simply
|
|
329
|
+
sits still (`javascript.md`).
|
|
330
|
+
|
|
331
|
+
```html
|
|
332
|
+
<header class="mw-header mw-header-reveal">...</header>
|
|
333
|
+
|
|
334
|
+
<main class="mw-main">
|
|
335
|
+
<section class="mw-section mw-parallax-sticky mw-parallax-rise">
|
|
336
|
+
<div class="mw-container mw-parallax">
|
|
337
|
+
<div class="mw-parallax-media"></div>
|
|
338
|
+
<div class="mw-parallax-media mw-parallax-pattern"></div>
|
|
339
|
+
<div class="mw-hero">...</div>
|
|
340
|
+
</div>
|
|
341
|
+
</section>
|
|
342
|
+
<section class="mw-section">...</section>
|
|
343
|
+
</main>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
On its own, `mw-parallax` drifts the picture against the scroll by
|
|
347
|
+
`--mw-parallax-depth` (`10vh`) - the layer overhangs the block by that much top
|
|
348
|
+
and bottom, so no edge is ever uncovered.
|
|
349
|
+
|
|
350
|
+
`mw-parallax-sticky` pins the block to the top of the screen and lets the page
|
|
351
|
+
ride up over it. It goes on the element the page content is a **sibling** of -
|
|
352
|
+
the section, not the hero - because everything after it is given
|
|
353
|
+
`--mw-page-background` and a layer above, or the pinned picture shows through
|
|
354
|
+
the transparent ones. Depth drops to `0` there: a pinned block does not travel
|
|
355
|
+
through the viewport, so its `view()` timeline stands still with it.
|
|
356
|
+
`mw-parallax-rise` puts it at `12vh` and runs the layer on the document's own
|
|
357
|
+
scroll instead - the picture lifts, the text stays put. That works out to the
|
|
358
|
+
same travel per scrolled pixel as a drifting band at `20vh`, which is measured
|
|
359
|
+
over a much longer range.
|
|
360
|
+
|
|
361
|
+
A second `mw-parallax-media` carrying `mw-parallax-pattern` puts a pattern over
|
|
362
|
+
the picture. It travels a third of the distance the layer below it does, and
|
|
363
|
+
that difference between the two is what reads as depth - one layer alone only
|
|
364
|
+
slides. It matters most over a gradient: the travel is vertical, so only an edge
|
|
365
|
+
across it - a rule, a grid, a hatch - ever shows the movement, and a gradient
|
|
366
|
+
has none. In a hero the layer reads `$mw-hero-pattern`, the way the picture
|
|
367
|
+
reads `$mw-hero-image`; anywhere else set `--mw-parallax-pattern-image` on it.
|
|
368
|
+
`--mw-parallax-pattern-depth` is the dial, `4vh` next to a risen hero.
|
|
369
|
+
|
|
370
|
+
Outside a hero the same classes build a standalone band: `mw-parallax`
|
|
371
|
+
(`min-height: 42vh`), `mw-parallax-media` as an `<img>` or a div with a
|
|
372
|
+
background image, `mw-parallax-content` for what sits on top, and
|
|
373
|
+
`mw-parallax-dimmed` to turn the picture down and the text light.
|
|
374
|
+
|
|
375
|
+
Without scroll timelines, or under `prefers-reduced-motion`, the picture stands
|
|
376
|
+
still and nothing else changes.
|
|
377
|
+
|
|
310
378
|
## Grid
|
|
311
379
|
|
|
312
380
|
All grid classes are `display: grid` with a preset gap (`mw-gap-*` overrides
|
|
@@ -402,19 +470,22 @@ with it; `mw-text-capitalize` is the plain transform.
|
|
|
402
470
|
uses. See the scale table in `SKILL.md`. Never hand-roll a `box-shadow`.
|
|
403
471
|
|
|
404
472
|
**Scroll entrance** - `mw-reveal` lets a block rise briefly as it scrolls into
|
|
405
|
-
view, driven by the browser's scroll timeline (`animation-timeline: view()`)
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
off, and a browser without scroll timelines
|
|
411
|
-
|
|
412
|
-
|
|
473
|
+
view, driven by the browser's scroll timeline (`animation-timeline: view()`).
|
|
474
|
+
The block stays hidden while it is still below the bottom edge and has arrived
|
|
475
|
+
three fifths of the way in - measured along its own entry, so it is never still
|
|
476
|
+
transparent once it stands in its place, whatever its height. A block taller
|
|
477
|
+
than the screen is capped at one viewport by the entry phase itself. Doubly guarded:
|
|
478
|
+
`prefers-reduced-motion` turns it off, and a browser without scroll timelines
|
|
479
|
+
renders the block in place instead of leaving it invisible. Firefox is that
|
|
480
|
+
browser - there the shipped JS runs the entrance off an `IntersectionObserver`,
|
|
481
|
+
so a page without the script keeps the block and loses only the motion
|
|
482
|
+
(`javascript.md`). Put it on section content, not on the section itself - a
|
|
483
|
+
screen-high band finishes its entrance before its content is halfway up.
|
|
413
484
|
|
|
414
485
|
A row of cards crosses the viewport edge together, so `mw-reveal` on each of
|
|
415
486
|
them rises as one slab. `mw-reveal-stagger` goes on the **grid** instead: every
|
|
416
|
-
child reveals, and each one in a row
|
|
417
|
-
a wave across the row. One class, nothing per card. On `mw-grid-2` to `mw-grid-5` and
|
|
487
|
+
child reveals, and each one in a row a tenth of that entry after the one
|
|
488
|
+
before it - a wave across the row. One class, nothing per card. On `mw-grid-2` to `mw-grid-5` and
|
|
418
489
|
their `-lg` variants the wave follows the actual columns at every breakpoint:
|
|
419
490
|
four steps in a four-column row, two once it has collapsed to two. Any other
|
|
420
491
|
container - `mw-columns-*`, a layout of your own - gets a fixed cycle of three.
|
|
@@ -9,6 +9,10 @@ borders, the theme's surface stack, the ink variant the dark theme needs. That i
|
|
|
9
9
|
the difference to pre-3.4.0, where derived values were baked in at compile time
|
|
10
10
|
and a palette switch meant setting 41 variables.
|
|
11
11
|
|
|
12
|
+
Writing those tokens on `<html>` at runtime is how a palette is swapped without
|
|
13
|
+
a reload. It repaints the same breadth the theme flip does and needs the same
|
|
14
|
+
guard against a page-wide interpolation - see **Light & dark** below.
|
|
15
|
+
|
|
12
16
|
Browser floor for that: `color-mix()` **and** `oklch(from ...)` - Chrome 119+,
|
|
13
17
|
Safari 16.4+, Firefox 128+. The same range is declared as `browserslist` in
|
|
14
18
|
`package.json`, so Autoprefixer and cssnano target exactly it.
|
|
@@ -226,6 +230,12 @@ effect, because the root colours are declared with `!default`.
|
|
|
226
230
|
// stronger, more saturated blue, higher is paler with more contrast
|
|
227
231
|
$header-active-tint: 25%,
|
|
228
232
|
$mw-hero-image: url('/assets/hero.jpg'),
|
|
233
|
+
// a pattern layer over it, for a hero that parallaxes - see mw-parallax-pattern
|
|
234
|
+
$mw-hero-pattern: repeating-linear-gradient(
|
|
235
|
+
to bottom,
|
|
236
|
+
rgb(255 255 255 / 5%) 0 1px,
|
|
237
|
+
transparent 1px 38px
|
|
238
|
+
),
|
|
229
239
|
// ink on that image - fixed, because the image is
|
|
230
240
|
$mw-hero-text-color: var(--mw-dark-text-color),
|
|
231
241
|
// per-theme treatment of that image - a filter, not an overlay, so the two
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,24 @@ Patch releases are only for test purposes - here I only document major and minor
|
|
|
6
6
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
7
7
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
8
8
|
|
|
9
|
+
## [5.5.0] - 2026-09-12
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- showcase themes
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- some firefox fixes
|
|
18
|
+
- scrolling
|
|
19
|
+
|
|
20
|
+
## [5.4.0] - 2026-09-11
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- parallax layout
|
|
25
|
+
- parallax hero with flexible header navbar
|
|
26
|
+
|
|
9
27
|
## [5.3.0] - 2026-09-11
|
|
10
28
|
|
|
11
29
|
### Fixed
|
package/CLAUDE.md
CHANGED
|
@@ -38,7 +38,7 @@ There are no test or lint scripts.
|
|
|
38
38
|
|
|
39
39
|
**JavaScript** (`src/js/main.js`) - Single file. All components auto-initialize on `DOMContentLoaded`. Includes: gallery and image sliders, theme toggle (persisted to localStorage, transitions suppressed during the flip), accordion, mobile nav, progress bar (IntersectionObserver), scroll spy, tabs (which also get their ARIA and arrow-key handling here), alerts/toasts, modals, range inputs, dropdowns, language switcher, checkbox lists, kanban board, calendar.
|
|
40
40
|
|
|
41
|
-
**HTML showcase** (`index.html` + `src/partials/`) - The top-level `index.html` uses `@@include()` syntax to pull in
|
|
41
|
+
**HTML showcase** (`index.html` + `src/partials/`) - The top-level `index.html` uses `@@include()` syntax to pull in 63 partials from `src/partials/`. These compile into `dist/index.html`.
|
|
42
42
|
|
|
43
43
|
## Naming Conventions
|
|
44
44
|
|
package/README.md
CHANGED
|
@@ -42,12 +42,12 @@ The result is a framework that balances utility with simplicity, offering develo
|
|
|
42
42
|
<title>My MaverickWave Project</title>
|
|
43
43
|
<link
|
|
44
44
|
rel="stylesheet"
|
|
45
|
-
href="https://cdn.jsdelivr.net/npm/maverick-wave@5.
|
|
45
|
+
href="https://cdn.jsdelivr.net/npm/maverick-wave@5.5.0/maverick-wave.min.css"
|
|
46
46
|
/>
|
|
47
47
|
</head>
|
|
48
48
|
<body>
|
|
49
49
|
<!-- Your content here -->
|
|
50
|
-
<script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.
|
|
50
|
+
<script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.5.0/maverick-wave.min.js"></script>
|
|
51
51
|
</body>
|
|
52
52
|
</html>
|
|
53
53
|
```
|
|
@@ -515,9 +515,8 @@ maverick-wave/
|
|
|
515
515
|
│ ├── utilities/ # Spacing, flex, display helpers
|
|
516
516
|
│ └── main.scss # SCSS entry point
|
|
517
517
|
├── .claude/
|
|
518
|
-
│ ├── commands/mw.md # Claude Code slash command (Angular quick reference)
|
|
519
518
|
│ └── skills/
|
|
520
|
-
│ └── maverick-wave/ # Claude Code skill: full usage guide + examples
|
|
519
|
+
│ └── mw-maverick-wave/ # Claude Code skill: full usage guide + examples
|
|
521
520
|
├── scripts/verify.js # Class and token consistency check (npm run verify)
|
|
522
521
|
├── .prettierrc.json # Prettier configuration
|
|
523
522
|
├── gulpfile.js # Gulp tasks configuration
|