maverick-wave 5.5.0 → 5.6.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.
@@ -20,13 +20,13 @@ or, in the framework repo, `npm run verify`.
20
20
 
21
21
  Load the one you need - do not read them all up front.
22
22
 
23
- | File | Content |
24
- | -------------------------- | ---------------------------------------------------------------------------------------------------------------- |
25
- | `references/layout.md` | Page skeleton, grid, container, section, page header, header/navbar, footer, spacing/flex/display/text utilities |
26
- | `references/components.md` | Every component: markup, variants, sizes, state classes |
27
- | `references/forms.md` | Inputs, select, textarea, checkbox, radio, toggle, slider, input group, `mw-field` pattern, validation |
28
- | `references/theming.md` | Token model, `color-mix` derivation, light/dark, SCSS configuration, cherry-picking single components |
29
- | `references/javascript.md` | What the shipped `main.js` does, why SPAs must not load it, what to implement instead |
23
+ | File | Content |
24
+ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
25
+ | `references/layout.md` | Page skeleton, grid, container, section, page header, header/navbar, footer, spacing/flex/display/text utilities |
26
+ | `references/components.md` | Every component: markup, variants, sizes, state classes |
27
+ | `references/forms.md` | Inputs, select, textarea, checkbox, radio, toggle, slider, input group, `mw-field` pattern, validation |
28
+ | `references/theming.md` | Token model, `color-mix` derivation, light/dark, site-wide variants, SCSS configuration, cherry-picking single components |
29
+ | `references/javascript.md` | What the shipped `main.js` does, why SPAs must not load it, what to implement instead |
30
30
 
31
31
  ## Examples
32
32
 
@@ -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.5.0/maverick-wave.min.css"
47
+ href="https://cdn.jsdelivr.net/npm/maverick-wave@5.6.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.5.0/maverick-wave.min.js"></script>
54
+ <script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.6.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 -
@@ -168,6 +168,8 @@ its own:
168
168
  declared before it.
169
169
 
170
170
  **Radius** (`mw-radius-none|xs|sm|md|lg|xl|2xl|full`): 0, 2, 5, 10, 15, 20, 30 px, 50%.
171
+ Every one of them is multiplied by `--mw-radius-scale` (default 1), so one number
172
+ squares the framework off or rounds it further; `none` and `full` pass through.
171
173
 
172
174
  **The surface signature.** Every panel-like component - card, panel, modal,
173
175
  accordion, tile, calendar, pagination, login box - shares one silhouette: sharp
@@ -175,7 +177,8 @@ accordion, tile, calendar, pagination, login box - shares one silhouette: sharp
175
177
  plus a 2px **corner accent** in the primary tone (`--mw-corner-accent`) sitting
176
178
  on the two round corners. It is not a class and not opt-in; the components carry
177
179
  it. `mw-corner-plain` drops the accent on a box too small to hold it - see
178
- `references/layout.md`.
180
+ `references/layout.md` - and `mw-corners-even` on `<html>` drops the whole
181
+ signature site-wide.
179
182
 
180
183
  **Elevation** (`mw-elevation-0` … `-5`, and `var(--mw-elevation-N)` inside SCSS).
181
184
  Two shadows per level - a tight contact layer plus a wide ambient one:
@@ -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.5.0/maverick-wave.min.css"
23
+ href="https://cdn.jsdelivr.net/npm/maverick-wave@5.6.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.5.0/maverick-wave.min.js"></script>
490
+ <script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.6.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.
@@ -192,6 +192,46 @@ void root.offsetHeight; // commit the new colours with transitions off
192
192
  root.classList.remove('mw-theme-switching');
193
193
  ```
194
194
 
195
+ ## Site-wide variants
196
+
197
+ Eight classes on `<html>` and four custom properties retune the whole look
198
+ without a rebuild. They stack, and none of them need a class per element.
199
+
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-hover-static` | No hover travels - lifts, image zooms and slides go. Colour and border still respond |
206
+ | `mw-sections-plain` | The diagonal hatch behind `mw-section-alternate` collapses into the page colour |
207
+ | `mw-headings-caps` | `h1`-`h3` in capitals with 0.045em tracking |
208
+ | `mw-btn-pill` | `mw-btn` fully rounded. Form fields keep their own radius |
209
+ | `mw-media-mono` | Photos in `grayscale(1)` until their card, tile, gallery or slider is hovered |
210
+
211
+ | Property | Effect |
212
+ | ---------------------------- | -------------------------------------------------------------- |
213
+ | `--mw-radius-scale` | Multiplies the whole radius scale - `0` squares everything off |
214
+ | `--mw-font-family-heading` | Headline typeface; body copy is untouched |
215
+ | `--mw-container-width` | Where the content stops growing |
216
+ | `--mw-section-padding-block` | Air above and below each section |
217
+
218
+ **Writing your own.** A variant that retunes a _theme-bound_ token - anything in
219
+ the dark/light maps, elevation and shadow above all - cannot be written on
220
+ `:root` alone: `mw-theme-light` re-declares those on `<body>`, which shadows the
221
+ root value for the entire subtree and the switch does nothing in light mode.
222
+ Target both:
223
+
224
+ ```scss
225
+ :root.my-variant,
226
+ :root.my-variant .mw-theme-light {
227
+ --mw-elevation-2: none;
228
+ }
229
+ ```
230
+
231
+ The same trap the other way round: never copy a theme alias _into_ a token on
232
+ `:root` (`--mw-x: var(--mw-page-background)`), because up there it still holds
233
+ the dark value. Write that rule on the element instead.
234
+
195
235
  ## SCSS configuration
196
236
 
197
237
  Only `@use ... with (...)` works - a plain assignment before the `@use` has no
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.6.0] - 2026-09-12
10
+
11
+ ### Added
12
+
13
+ - showcase variants of some components / typography
14
+
9
15
  ## [5.5.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.5.0/maverick-wave.min.css"
45
+ href="https://cdn.jsdelivr.net/npm/maverick-wave@5.6.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.5.0/maverick-wave.min.js"></script>
50
+ <script src="https://cdn.jsdelivr.net/npm/maverick-wave@5.6.0/maverick-wave.min.js"></script>
51
51
  </body>
52
52
  </html>
53
53
  ```
@@ -345,6 +345,30 @@ layer of its own:
345
345
  <link rel="stylesheet" href="maverick-wave.min.css" />
346
346
  ```
347
347
 
348
+ ### Site-wide variants
349
+
350
+ Eight classes on `<html>` retune the whole look without touching markup or
351
+ rebuilding. They stack.
352
+
353
+ | Class | Effect |
354
+ | ------------------- | ----------------------------------------------------------------------- |
355
+ | `mw-corners-even` | Drops the surface signature - every panel becomes an evenly rounded box |
356
+ | `mw-accent-single` | One brand colour instead of two; `mw-btn-secondary` turns outline |
357
+ | `mw-shadows-flat` | Elevation 1-3 to `none`; dropdown and modal keep theirs |
358
+ | `mw-hover-static` | No hover travels - lifts and image zooms go, colour still responds |
359
+ | `mw-sections-plain` | The hatch behind `mw-section-alternate` collapses into the page colour |
360
+ | `mw-headings-caps` | `h1`-`h3` in capitals |
361
+ | `mw-btn-pill` | Fully rounded buttons; form fields keep their radius |
362
+ | `mw-media-mono` | Photos grey until hovered |
363
+
364
+ Four properties do the rest: `--mw-radius-scale` multiplies every radius (`0`
365
+ squares the framework off), `--mw-font-family-heading`, `--mw-container-width`
366
+ and `--mw-section-padding-block`.
367
+
368
+ A variant of your own that retunes a theme-bound token has to target
369
+ `:root.your-class` **and** `:root.your-class .mw-theme-light` - the light theme
370
+ re-declares those on `<body>` and would shadow a root-only value.
371
+
348
372
  ### SCSS Source
349
373
 
350
374
  For full control, clone the repository and integrate `src/scss/main.scss` into your Sass build (Dart Sass required). MaverickWave uses modern `@use`/`@forward` syntax. Pass your overrides through `with`:
package/index.html CHANGED
@@ -151,7 +151,12 @@
151
151
  right: 18px;
152
152
  bottom: 82px;
153
153
  z-index: 400;
154
- width: 300px;
154
+ width: 360px;
155
+ /* The variant list makes the panel taller than a laptop in landscape -
156
+ the top of it would be behind the browser chrome without this */
157
+ max-height: calc(100dvh - 120px);
158
+ overflow-y: auto;
159
+ overscroll-behavior: contain;
155
160
  padding: 18px;
156
161
  border-radius: 12px;
157
162
  border: 1px solid var(--mw-border);
@@ -241,7 +246,111 @@
241
246
  cursor: pointer;
242
247
  }
243
248
 
244
- @media (max-width: 576px) {
249
+ /* Single accent means the secondary picker writes a token nothing reads any
250
+ more - left live it is a knob that does nothing */
251
+ :root.mw-accent-single .palette-field:has(#palette-secondary) {
252
+ opacity: 0.4;
253
+ pointer-events: none;
254
+ }
255
+
256
+ .palette-heading-split {
257
+ margin-top: 18px;
258
+ padding-top: 14px;
259
+ border-top: 1px solid var(--mw-border);
260
+ }
261
+
262
+ .variant-row {
263
+ display: flex;
264
+ align-items: center;
265
+ justify-content: space-between;
266
+ gap: 12px;
267
+ padding-block: 9px;
268
+ font-size: 0.8rem;
269
+ color: var(--mw-text-color);
270
+ cursor: pointer;
271
+ }
272
+
273
+ .variant-label {
274
+ display: flex;
275
+ flex-direction: column;
276
+ gap: 2px;
277
+ }
278
+
279
+ .variant-label small {
280
+ font-size: 0.68rem;
281
+ line-height: 1.35;
282
+ color: var(--mw-text-muted-color);
283
+ }
284
+
285
+ .variant-row + .variant-row {
286
+ border-top: 1px solid var(--mw-border);
287
+ }
288
+
289
+ .variant-row select {
290
+ flex-shrink: 0;
291
+ max-width: 110px;
292
+ padding: 3px 6px;
293
+ font-size: 0.75rem;
294
+ color: var(--mw-text-color);
295
+ border: 1px solid var(--mw-border);
296
+ border-radius: 6px;
297
+ background: transparent;
298
+ cursor: pointer;
299
+ }
300
+
301
+ /* Drawn by hand rather than reusing mw-toggle: a framework switch would
302
+ reshape itself along with the variants it is there to control */
303
+ .variant-row input[type='checkbox'] {
304
+ appearance: none;
305
+ flex-shrink: 0;
306
+ position: relative;
307
+ width: 34px;
308
+ height: 18px;
309
+ margin: 0;
310
+ border: 1px solid var(--mw-border);
311
+ border-radius: 9px;
312
+ background: var(--mw-gray-background);
313
+ cursor: pointer;
314
+ transition: var(--mw-transition);
315
+ }
316
+
317
+ .variant-row input[type='checkbox']::after {
318
+ content: '';
319
+ position: absolute;
320
+ top: 2px;
321
+ left: 2px;
322
+ width: 12px;
323
+ height: 12px;
324
+ border-radius: 50%;
325
+ background: var(--mw-text-muted-color);
326
+ transition: var(--mw-transition);
327
+ }
328
+
329
+ .variant-row input[type='checkbox']:checked {
330
+ background: var(--mw-primary-color);
331
+ border-color: var(--mw-primary-color);
332
+ }
333
+
334
+ .variant-row input[type='checkbox']:checked::after {
335
+ left: 18px;
336
+ background: var(--mw-primary-accent-text-color);
337
+ }
338
+
339
+ .variant-setup {
340
+ margin-top: 14px;
341
+ padding: 10px;
342
+ border-radius: 8px;
343
+ border: 1px solid var(--mw-border);
344
+ background: var(--mw-gray-background);
345
+ color: var(--mw-text-muted-color);
346
+ font-family: var(--mw-font-family-mono);
347
+ font-size: 0.68rem;
348
+ line-height: 1.5;
349
+ white-space: pre-wrap;
350
+ word-break: break-word;
351
+ }
352
+
353
+ @media (max-width: 480px) {
245
354
  .palette-fab {
246
355
  right: 12px;
247
356
  bottom: 12px;
@@ -886,6 +995,88 @@
886
995
  });
887
996
  });
888
997
 
998
+ // just for the showcase: the variant switches. Each one is a class on <html>
999
+ // or a single custom property, never a walk over the DOM - markup that
1000
+ // arrives later (a modal, a toast, a kanban card) is covered by the same
1001
+ // class that was already set. The readout at the bottom of the panel is the
1002
+ // whole setup a project would carry to get the look it is currently seeing.
1003
+ document.addEventListener('DOMContentLoaded', () => {
1004
+ const list = document.getElementById('variant-list');
1005
+ const setup = document.getElementById('variant-setup');
1006
+ if (!list || !setup) return;
1007
+
1008
+ const root = document.documentElement;
1009
+ const controls = [...list.querySelectorAll('input, select')];
1010
+
1011
+ const isOn = (input) =>
1012
+ input.hasAttribute('data-variant-invert')
1013
+ ? !input.checked
1014
+ : input.checked;
1015
+
1016
+ const render = () => {
1017
+ const classes = [];
1018
+ const notes = [];
1019
+ const props = [];
1020
+
1021
+ controls.forEach((control) => {
1022
+ if (control.type !== 'checkbox') {
1023
+ if (control.value) {
1024
+ props.push(
1025
+ ` ${control.dataset.variantProp}: ${control.value};`
1026
+ );
1027
+ }
1028
+ return;
1029
+ }
1030
+
1031
+ // A targeted class is one the markup already ships, so its absence is
1032
+ // the deviation worth naming - the rest are classes to add
1033
+ const target = control.dataset.variantTarget;
1034
+ if (target) {
1035
+ if (!isOn(control)) {
1036
+ notes.push(target + ': no ' + control.dataset.variantClass);
1037
+ }
1038
+ } else if (isOn(control)) {
1039
+ classes.push(control.dataset.variantClass);
1040
+ }
1041
+ });
1042
+
1043
+ const lines = [];
1044
+ if (classes.length) {
1045
+ lines.push('html class="' + classes.join(' ') + '"');
1046
+ }
1047
+ lines.push(...notes);
1048
+ if (props.length) lines.push(':root {', ...props, '}');
1049
+
1050
+ setup.textContent = lines.length
1051
+ ? lines.join('\n')
1052
+ : 'Default setup - nothing to change.';
1053
+ };
1054
+
1055
+ const apply = (control) => {
1056
+ if (control.type === 'checkbox') {
1057
+ const target = control.dataset.variantTarget;
1058
+ const el = target ? document.querySelector(target) : root;
1059
+ el?.classList.toggle(control.dataset.variantClass, isOn(control));
1060
+ } else if (control.value) {
1061
+ root.style.setProperty(control.dataset.variantProp, control.value);
1062
+ } else {
1063
+ root.style.removeProperty(control.dataset.variantProp);
1064
+ }
1065
+ };
1066
+
1067
+ controls.forEach((control) =>
1068
+ control.addEventListener('change', () => {
1069
+ apply(control);
1070
+ render();
1071
+ })
1072
+ );
1073
+
1074
+ // Applied on load too, so a browser that restored a checked box after a
1075
+ // reload does not leave the page and the panel disagreeing
1076
+ controls.forEach(apply);
1077
+ render();
1078
+ });
1079
+
889
1080
  // for the modals - the framework handles both shapes, div and <dialog>
890
1081
  const openModal = window.mwOpenModal;
891
1082
  const closeModal = window.mwCloseModal;