maverick-wave 5.7.0 → 5.8.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 +2 -2
- package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +2 -2
- package/.claude/skills/mw-maverick-wave/references/theming.md +24 -19
- package/CHANGELOG.md +6 -0
- package/README.md +10 -6
- package/index.html +70 -42
- package/maverick-wave.min.css +2 -2
- package/package.json +2 -2
- package/scripts/verify.js +11 -1
- package/src/partials/header-container.html +7 -5
- package/src/partials/palette-container.html +90 -20
- package/src/partials/utilities-container.html +17 -4
- package/src/scss/base/_base.scss +4 -0
- package/src/scss/base/_reset.scss +2 -0
- package/src/scss/utilities/_variants.scss +42 -0
|
@@ -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.8.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.8.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 -
|
|
@@ -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.8.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.8.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.
|
|
@@ -83,6 +83,7 @@ Safari 16.4+, Firefox 128+. The same range is declared as `browserslist` in
|
|
|
83
83
|
| `--mw-container-gutter`, `--mw-container-width` | Page gutter of `mw-container` (fluid `clamp(1rem, 4.2vw + 0.5rem, 4rem)`, never below the safe-area inset) and the width derived from it (`min(1200px, 100% - 2 * gutter)`) |
|
|
84
84
|
| `--mw-section-padding-block` | Top/bottom rhythm of `mw-section` (3.3rem, stepping down to 2.5rem below `md` and 1.75rem below `sm`) |
|
|
85
85
|
| `--mw-section-nav-height` | Height the sticky `mw-section-nav` reserves (3.7rem). Add it to `--mw-header-height` for the `scroll-margin-top` of anything the strip can cover |
|
|
86
|
+
| `--mw-root-font-size` | Percentage the whole rem scale is built on (`100%`). Type, spacing and control heights move with it; px breakpoints do not |
|
|
86
87
|
| `--mw-calendar-dot` | Colour of a single calendar dot - set it per dot or per cell; the `mw-calendar-dot-*` classes are presets for it |
|
|
87
88
|
| `--mw-scroll-hint-cover` | Colour the scroll hint on a tab bar fades into. Preset to the page, re-pointed to the card background inside `mw-card`, `mw-panel`, `mw-modal`, `mw-tile`, `mw-calendar` |
|
|
88
89
|
| `--mw-elevation-1` … `-5` | Every shadow in the framework. Two layers per level - contact plus ambient. Never write a `box-shadow` by hand: a hand-rolled one is the wrong colour in one of the two themes |
|
|
@@ -194,27 +195,31 @@ root.classList.remove('mw-theme-switching');
|
|
|
194
195
|
|
|
195
196
|
## Site-wide variants
|
|
196
197
|
|
|
197
|
-
|
|
198
|
+
Twelve classes on `<html>` and five custom properties retune the whole look
|
|
198
199
|
without a rebuild. They stack, and none of them need a class per element.
|
|
199
200
|
|
|
200
|
-
| Class | Effect
|
|
201
|
-
| ------------------- |
|
|
202
|
-
| `mw-corners-even` | Drops the surface signature - every card, panel and modal becomes an evenly rounded `radius('md')` box
|
|
203
|
-
| `mw-accent-single` | `--mw-secondary-color` follows the primary; `mw-btn-secondary` turns outline so the two stay apart
|
|
204
|
-
| `mw-shadows-flat` | Elevation 1-3 to `none`. The dropdown (4) and the modal (5) keep their shadow
|
|
205
|
-
| `mw-
|
|
206
|
-
| `mw-
|
|
207
|
-
| `mw-
|
|
208
|
-
| `mw-
|
|
209
|
-
| `mw-
|
|
210
|
-
| `mw-btn-
|
|
211
|
-
|
|
212
|
-
|
|
|
213
|
-
|
|
|
214
|
-
|
|
215
|
-
|
|
|
216
|
-
|
|
|
217
|
-
| `--mw-
|
|
201
|
+
| Class | Effect |
|
|
202
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
203
|
+
| `mw-corners-even` | Drops the surface signature - every card, panel and modal becomes an evenly rounded `radius('md')` box |
|
|
204
|
+
| `mw-accent-single` | `--mw-secondary-color` follows the primary; `mw-btn-secondary` turns outline so the two stay apart |
|
|
205
|
+
| `mw-shadows-flat` | Elevation 1-3 to `none`. The dropdown (4) and the modal (5) keep their shadow |
|
|
206
|
+
| `mw-surfaces-flush` | Card, panel and footer background drop to the page colour and the border is redrawn from the ink, because the old one is a neighbouring shade of a surface that is now the page |
|
|
207
|
+
| `mw-hover-static` | No hover travels - lifts, image zooms and slides go. Colour and border still respond |
|
|
208
|
+
| `mw-scroll-static` | No scroll entrance - `mw-reveal` and `mw-reveal-stagger` blocks sit where they land |
|
|
209
|
+
| `mw-sections-plain` | The diagonal hatch behind `mw-section-alternate` collapses into the page colour |
|
|
210
|
+
| `mw-headings-caps` | `h1`-`h3` in capitals with 0.045em tracking |
|
|
211
|
+
| `mw-btn-pill` | `mw-btn` fully rounded. Form fields keep their own radius |
|
|
212
|
+
| `mw-btn-square` | `mw-btn` to `border-radius: 0`. The other end of the same axis, and unlike `--mw-radius-scale: 0` it leaves the rest of the page rounded |
|
|
213
|
+
| `mw-btn-glass` | Filled buttons become tinted glass: translucent wash, vertical ramp, specular top edge. No `backdrop-filter` - it would trap a fixed-position tooltip inside the button |
|
|
214
|
+
| `mw-btn-tactile` | The four solid variants stand on a 3px edge mixed toward black and travel its full height on `:active`. Outline, ghost and link have no fill to darken and are untouched |
|
|
215
|
+
|
|
216
|
+
| Property | Effect |
|
|
217
|
+
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
218
|
+
| `--mw-radius-scale` | Multiplies the whole radius scale - `0` squares everything off |
|
|
219
|
+
| `--mw-root-font-size` | Percentage on `html`. The scale is rem, so type, padding and control heights move together; breakpoints are px and stay put |
|
|
220
|
+
| `--mw-font-family-heading` | Headline typeface; body copy is untouched |
|
|
221
|
+
| `--mw-container-width` | Where the content stops growing |
|
|
222
|
+
| `--mw-section-padding-block` | Air above and below each section |
|
|
218
223
|
|
|
219
224
|
**Writing your own.** A variant that retunes a _theme-bound_ token - anything in
|
|
220
225
|
the dark/light maps, elevation and shadow above all - cannot be written on
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@ 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.8.0] - 2026-09-12
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- some other showcase variants
|
|
14
|
+
|
|
9
15
|
## [5.7.0] - 2026-09-12
|
|
10
16
|
|
|
11
17
|
### Added
|
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.8.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.8.0/maverick-wave.min.js"></script>
|
|
51
51
|
</body>
|
|
52
52
|
</html>
|
|
53
53
|
```
|
|
@@ -347,7 +347,7 @@ layer of its own:
|
|
|
347
347
|
|
|
348
348
|
### Site-wide variants
|
|
349
349
|
|
|
350
|
-
|
|
350
|
+
Twelve classes on `<html>` retune the whole look without touching markup or
|
|
351
351
|
rebuilding. They stack.
|
|
352
352
|
|
|
353
353
|
| Class | Effect |
|
|
@@ -355,16 +355,20 @@ rebuilding. They stack.
|
|
|
355
355
|
| `mw-corners-even` | Drops the surface signature - every panel becomes an evenly rounded box |
|
|
356
356
|
| `mw-accent-single` | One brand colour instead of two; `mw-btn-secondary` turns outline |
|
|
357
357
|
| `mw-shadows-flat` | Elevation 1-3 to `none`; dropdown and modal keep theirs |
|
|
358
|
+
| `mw-surfaces-flush` | Cards, panels and footer on the page colour, held by their border |
|
|
358
359
|
| `mw-hover-static` | No hover travels - lifts and image zooms go, colour still responds |
|
|
359
360
|
| `mw-scroll-static` | No scroll entrance - `mw-reveal` blocks sit where they land |
|
|
360
361
|
| `mw-sections-plain` | The hatch behind `mw-section-alternate` collapses into the page colour |
|
|
361
362
|
| `mw-headings-caps` | `h1`-`h3` in capitals |
|
|
362
363
|
| `mw-btn-pill` | Fully rounded buttons; form fields keep their radius |
|
|
364
|
+
| `mw-btn-square` | Buttons cut to a hard corner while the page keeps its radius |
|
|
363
365
|
| `mw-btn-glass` | Filled buttons become a translucent wash with a lit top edge |
|
|
366
|
+
| `mw-btn-tactile` | Filled buttons stand on a darker edge and sink onto it when pressed |
|
|
364
367
|
|
|
365
|
-
|
|
366
|
-
squares the framework off), `--mw-font-
|
|
367
|
-
|
|
368
|
+
Five properties do the rest: `--mw-radius-scale` multiplies every radius (`0`
|
|
369
|
+
squares the framework off), `--mw-root-font-size` moves the whole rem scale,
|
|
370
|
+
plus `--mw-font-family-heading`, `--mw-container-width` and
|
|
371
|
+
`--mw-section-padding-block`.
|
|
368
372
|
|
|
369
373
|
A variant of your own that retunes a theme-bound token has to target
|
|
370
374
|
`:root.your-class` **and** `:root.your-class .mw-theme-light` - the light theme
|
package/index.html
CHANGED
|
@@ -124,40 +124,50 @@
|
|
|
124
124
|
|
|
125
125
|
/* Palette switcher, showcase only. The framework derives every tone from
|
|
126
126
|
the root colors, so the panel writes nothing but those. */
|
|
127
|
-
.palette-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
border
|
|
135
|
-
border:
|
|
127
|
+
.palette-toggle {
|
|
128
|
+
display: none;
|
|
129
|
+
align-items: center;
|
|
130
|
+
justify-content: center;
|
|
131
|
+
width: 50px;
|
|
132
|
+
height: 40px;
|
|
133
|
+
flex-shrink: 0;
|
|
134
|
+
border: none;
|
|
135
|
+
border-radius: calc(10px * var(--mw-radius-scale, 1));
|
|
136
136
|
background: var(--mw-primary-color);
|
|
137
137
|
color: var(--mw-primary-accent-text-color);
|
|
138
|
-
|
|
139
|
-
font-size: 1.25rem;
|
|
138
|
+
font-size: 1.1rem;
|
|
140
139
|
cursor: pointer;
|
|
141
140
|
transition: var(--mw-transition);
|
|
142
141
|
}
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
/* Below sm the panel would cover the very thing it is changing */
|
|
144
|
+
@media (min-width: 576px) {
|
|
145
|
+
.palette-toggle {
|
|
146
|
+
display: flex;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.palette-toggle:hover {
|
|
145
151
|
background: var(--mw-primary-color-hover);
|
|
146
152
|
}
|
|
147
153
|
|
|
148
|
-
.palette-
|
|
149
|
-
transform: scale(0.
|
|
154
|
+
.palette-toggle:active {
|
|
155
|
+
transform: scale(0.94);
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
.palette-panel {
|
|
153
159
|
position: fixed;
|
|
154
|
-
|
|
155
|
-
|
|
160
|
+
top: calc(var(--mw-header-height) + 8px);
|
|
161
|
+
/* Flush with the container edge, so it lines up with the button in the
|
|
162
|
+
header rather than sitting further out */
|
|
163
|
+
right: max(18px, calc((100% - var(--mw-container-width)) / 2));
|
|
156
164
|
z-index: 400;
|
|
157
|
-
|
|
165
|
+
/* Wide enough for three palettes in a row; the min() is for the narrow
|
|
166
|
+
end, where the panel would otherwise reach past the viewport */
|
|
167
|
+
width: min(440px, calc(100% - 24px));
|
|
158
168
|
/* The variant list makes the panel taller than a laptop in landscape -
|
|
159
|
-
|
|
160
|
-
max-height: calc(100dvh -
|
|
169
|
+
it takes what is left under the header and scrolls the rest */
|
|
170
|
+
max-height: calc(100dvh - var(--mw-header-height) - 24px);
|
|
161
171
|
overflow-y: auto;
|
|
162
172
|
overscroll-behavior: contain;
|
|
163
173
|
padding: 18px;
|
|
@@ -165,6 +175,26 @@
|
|
|
165
175
|
border: 1px solid var(--mw-border);
|
|
166
176
|
background: var(--mw-card-background);
|
|
167
177
|
box-shadow: var(--mw-elevation-5);
|
|
178
|
+
transform: translateY(0);
|
|
179
|
+
opacity: 1;
|
|
180
|
+
/* display is in the list so allow-discrete keeps the panel mounted
|
|
181
|
+
through the fade out - `hidden` is the state the script writes */
|
|
182
|
+
transition-property: opacity, transform, display;
|
|
183
|
+
transition-duration: var(--mw-duration-base);
|
|
184
|
+
transition-timing-function: var(--mw-ease-out);
|
|
185
|
+
transition-behavior: allow-discrete;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@starting-style {
|
|
189
|
+
.palette-panel {
|
|
190
|
+
opacity: 0;
|
|
191
|
+
transform: translateY(-12px);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.palette-panel[hidden] {
|
|
196
|
+
opacity: 0;
|
|
197
|
+
transform: translateY(-12px);
|
|
168
198
|
}
|
|
169
199
|
|
|
170
200
|
.palette-heading {
|
|
@@ -181,7 +211,7 @@
|
|
|
181
211
|
|
|
182
212
|
.palette-grid {
|
|
183
213
|
display: grid;
|
|
184
|
-
grid-template-columns:
|
|
214
|
+
grid-template-columns: repeat(3, 1fr);
|
|
185
215
|
gap: 6px;
|
|
186
216
|
}
|
|
187
217
|
|
|
@@ -291,7 +321,7 @@
|
|
|
291
321
|
|
|
292
322
|
.variant-row select {
|
|
293
323
|
flex-shrink: 0;
|
|
294
|
-
max-width:
|
|
324
|
+
max-width: 135px;
|
|
295
325
|
padding: 3px 6px;
|
|
296
326
|
font-size: 0.75rem;
|
|
297
327
|
color: var(--mw-text-color);
|
|
@@ -362,22 +392,6 @@
|
|
|
362
392
|
white-space: pre-wrap;
|
|
363
393
|
word-break: break-word;
|
|
364
394
|
}
|
|
365
|
-
|
|
366
|
-
@media (max-width: 480px) {
|
|
367
|
-
.palette-fab {
|
|
368
|
-
right: 12px;
|
|
369
|
-
bottom: 12px;
|
|
370
|
-
width: 46px;
|
|
371
|
-
height: 46px;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
.palette-panel {
|
|
375
|
-
right: 12px;
|
|
376
|
-
left: 12px;
|
|
377
|
-
bottom: 68px;
|
|
378
|
-
width: auto;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
395
|
</style>
|
|
382
396
|
|
|
383
397
|
<script src="maverick-wave.min.js?v={{VERSION}}"></script>
|
|
@@ -908,12 +922,12 @@
|
|
|
908
922
|
// root element repaints the page - bar, ink, borders and tints included.
|
|
909
923
|
// Nothing is persisted - a palette is for looking at, a reload is the way back.
|
|
910
924
|
document.addEventListener('DOMContentLoaded', () => {
|
|
911
|
-
const
|
|
925
|
+
const toggleBtn = document.getElementById('palette-toggle');
|
|
912
926
|
const panel = document.getElementById('palette-panel');
|
|
913
927
|
const primaryInput = document.getElementById('palette-primary');
|
|
914
928
|
const secondaryInput = document.getElementById('palette-secondary');
|
|
915
929
|
const items = [...document.querySelectorAll('.palette-item')];
|
|
916
|
-
if (!
|
|
930
|
+
if (!toggleBtn || !panel) return;
|
|
917
931
|
|
|
918
932
|
const root = document.documentElement;
|
|
919
933
|
|
|
@@ -1001,10 +1015,10 @@
|
|
|
1001
1015
|
|
|
1002
1016
|
const toggle = (open) => {
|
|
1003
1017
|
panel.hidden = !open;
|
|
1004
|
-
|
|
1018
|
+
toggleBtn.setAttribute('aria-expanded', String(open));
|
|
1005
1019
|
};
|
|
1006
1020
|
|
|
1007
|
-
|
|
1021
|
+
toggleBtn.addEventListener('click', (event) => {
|
|
1008
1022
|
event.stopPropagation();
|
|
1009
1023
|
toggle(panel.hidden);
|
|
1010
1024
|
});
|
|
@@ -1132,7 +1146,12 @@
|
|
|
1132
1146
|
|
|
1133
1147
|
controls.forEach((control) => {
|
|
1134
1148
|
if (control.type !== 'checkbox') {
|
|
1135
|
-
|
|
1149
|
+
// A select whose options are class names picks one of a set the
|
|
1150
|
+
// markup cannot hold at the same time - a shape is one or none
|
|
1151
|
+
if (!control.value) return;
|
|
1152
|
+
if (control.hasAttribute('data-variant-classes')) {
|
|
1153
|
+
classes.push(control.value);
|
|
1154
|
+
} else {
|
|
1136
1155
|
props.push(
|
|
1137
1156
|
` ${control.dataset.variantProp}: ${control.value};`
|
|
1138
1157
|
);
|
|
@@ -1164,11 +1183,17 @@
|
|
|
1164
1183
|
: 'Default setup - nothing to change.';
|
|
1165
1184
|
};
|
|
1166
1185
|
|
|
1186
|
+
const optionClasses = (control) =>
|
|
1187
|
+
[...control.options].map((option) => option.value).filter(Boolean);
|
|
1188
|
+
|
|
1167
1189
|
const apply = (control) => {
|
|
1168
1190
|
if (control.type === 'checkbox') {
|
|
1169
1191
|
const target = control.dataset.variantTarget;
|
|
1170
1192
|
const el = target ? document.querySelector(target) : root;
|
|
1171
1193
|
el?.classList.toggle(control.dataset.variantClass, isOn(control));
|
|
1194
|
+
} else if (control.hasAttribute('data-variant-classes')) {
|
|
1195
|
+
root.classList.remove(...optionClasses(control));
|
|
1196
|
+
if (control.value) root.classList.add(control.value);
|
|
1172
1197
|
} else if (control.value) {
|
|
1173
1198
|
root.style.setProperty(control.dataset.variantProp, control.value);
|
|
1174
1199
|
} else {
|
|
@@ -1214,6 +1239,9 @@
|
|
|
1214
1239
|
control.checked = control.hasAttribute('data-variant-invert')
|
|
1215
1240
|
? !on
|
|
1216
1241
|
: on;
|
|
1242
|
+
} else if (control.hasAttribute('data-variant-classes')) {
|
|
1243
|
+
control.value =
|
|
1244
|
+
optionClasses(control).find((name) => named.has(name)) ?? '';
|
|
1217
1245
|
} else {
|
|
1218
1246
|
control.value = props.get(control.dataset.variantProp) ?? '';
|
|
1219
1247
|
}
|