css-is-awesome 1.4.0 → 1.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.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +24 -0
- package/README.md +5 -3
- package/css-is-awesome.instructions.md +9 -4
- package/package.json +1 -1
- package/public/theme.css +210 -0
- package/public/themes/boilerplate/theme.css +10 -0
- package/public/themes/cupertino/theme.css +10 -0
- package/public/themes/cupertino-dark/theme.css +10 -0
- package/public/themes/cupertino-light/theme.css +10 -0
- package/public/themes/glass/theme.css +10 -0
- package/public/themes/glass-dark/theme.css +10 -0
- package/public/themes/glass-light/theme.css +10 -0
- package/public/themes/graphite/theme.css +10 -0
- package/public/themes/graphite-dark/theme.css +10 -0
- package/public/themes/graphite-light/theme.css +10 -0
- package/public/themes/press/theme.css +10 -0
- package/public/themes/press-dark/theme.css +10 -0
- package/public/themes/press-light/theme.css +10 -0
- package/public/themes/prism/theme.css +10 -0
- package/public/themes/prism-dark/theme.css +10 -0
- package/public/themes/prism-light/theme.css +10 -0
- package/public/themes/sketchbook/theme.css +10 -0
- package/public/themes/sketchbook-dark/theme.css +10 -0
- package/public/themes/terminal/theme.css +10 -0
- package/public/themes/terminal-dark/theme.css +10 -0
- package/public/themes/terminal-light/theme.css +10 -0
- package/scss/components/_navigation.scss +83 -0
- package/scss/recipes/bottom-nav.md +184 -0
- package/scss/recipes/combobox.md +9 -0
- package/scss/recipes/dialog.md +21 -0
- package/scss/recipes/mobile-nav.md +3 -0
- package/scss/themes/boilerplate.scss +11 -0
- package/scss/themes/cupertino-dark.scss +11 -0
- package/scss/themes/cupertino-light.scss +11 -0
- package/scss/themes/cupertino.scss +11 -0
- package/scss/themes/glass-dark.scss +11 -0
- package/scss/themes/glass-light.scss +11 -0
- package/scss/themes/glass.scss +11 -0
- package/scss/themes/graphite-dark.scss +11 -0
- package/scss/themes/graphite-light.scss +11 -0
- package/scss/themes/graphite.scss +11 -0
- package/scss/themes/press-dark.scss +11 -0
- package/scss/themes/press-light.scss +11 -0
- package/scss/themes/press.scss +11 -0
- package/scss/themes/prism-dark.scss +11 -0
- package/scss/themes/prism-light.scss +11 -0
- package/scss/themes/prism.scss +11 -0
- package/scss/themes/sketchbook-dark.scss +11 -0
- package/scss/themes/sketchbook.scss +11 -0
- package/scss/themes/terminal-dark.scss +11 -0
- package/scss/themes/terminal-light.scss +11 -0
- package/scss/themes/terminal.scss +11 -0
|
@@ -169,6 +169,16 @@
|
|
|
169
169
|
--space-7: 3rem; /* major gap */
|
|
170
170
|
--space-8: 4rem; /* page section */
|
|
171
171
|
--space-9: 6rem; /* hero rhythm */
|
|
172
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
173
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
174
|
+
--space-xs: var(--space-1);
|
|
175
|
+
--space-sm: var(--space-2);
|
|
176
|
+
--space-md: var(--space-4);
|
|
177
|
+
--space-lg: var(--space-5);
|
|
178
|
+
--space-xl: var(--space-6);
|
|
179
|
+
--space-2xl: var(--space-7);
|
|
180
|
+
--space-3xl: var(--space-8);
|
|
181
|
+
--space-4xl: var(--space-9);
|
|
172
182
|
/* Radius alias — Press is editorial, xl stays tight (6px) */
|
|
173
183
|
--radius-sm: var(--r-sm);
|
|
174
184
|
--radius-md: var(--r-md);
|
|
@@ -197,6 +197,16 @@
|
|
|
197
197
|
--space-7: 3rem; /* major gap */
|
|
198
198
|
--space-8: 4rem; /* page section */
|
|
199
199
|
--space-9: 6rem; /* hero rhythm */
|
|
200
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
201
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
202
|
+
--space-xs: var(--space-1);
|
|
203
|
+
--space-sm: var(--space-2);
|
|
204
|
+
--space-md: var(--space-4);
|
|
205
|
+
--space-lg: var(--space-5);
|
|
206
|
+
--space-xl: var(--space-6);
|
|
207
|
+
--space-2xl: var(--space-7);
|
|
208
|
+
--space-3xl: var(--space-8);
|
|
209
|
+
--space-4xl: var(--space-9);
|
|
200
210
|
/* Radius alias — mirrors --r-* with standard names so
|
|
201
211
|
`m.radius(size)` in the library finds --radius-<size>.
|
|
202
212
|
Press is editorial and angular: xl stays tight (4px). */
|
|
@@ -134,6 +134,16 @@
|
|
|
134
134
|
--space-7: 3rem; /* major gap */
|
|
135
135
|
--space-8: 4rem; /* page section */
|
|
136
136
|
--space-9: 6rem; /* hero rhythm */
|
|
137
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
138
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
139
|
+
--space-xs: var(--space-1);
|
|
140
|
+
--space-sm: var(--space-2);
|
|
141
|
+
--space-md: var(--space-4);
|
|
142
|
+
--space-lg: var(--space-5);
|
|
143
|
+
--space-xl: var(--space-6);
|
|
144
|
+
--space-2xl: var(--space-7);
|
|
145
|
+
--space-3xl: var(--space-8);
|
|
146
|
+
--space-4xl: var(--space-9);
|
|
137
147
|
--radius-sm: var(--r-sm);
|
|
138
148
|
--radius-md: var(--r-md);
|
|
139
149
|
--radius-lg: var(--r-lg);
|
|
@@ -157,6 +157,16 @@
|
|
|
157
157
|
--space-7: 3rem; /* major gap */
|
|
158
158
|
--space-8: 4rem; /* page section */
|
|
159
159
|
--space-9: 6rem; /* hero rhythm */
|
|
160
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
161
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
162
|
+
--space-xs: var(--space-1);
|
|
163
|
+
--space-sm: var(--space-2);
|
|
164
|
+
--space-md: var(--space-4);
|
|
165
|
+
--space-lg: var(--space-5);
|
|
166
|
+
--space-xl: var(--space-6);
|
|
167
|
+
--space-2xl: var(--space-7);
|
|
168
|
+
--space-3xl: var(--space-8);
|
|
169
|
+
--space-4xl: var(--space-9);
|
|
160
170
|
/* Radius alias */
|
|
161
171
|
--radius-sm: var(--r-sm);
|
|
162
172
|
--radius-md: var(--r-md);
|
|
@@ -160,6 +160,16 @@
|
|
|
160
160
|
--space-7: 3rem; /* major gap */
|
|
161
161
|
--space-8: 4rem; /* page section */
|
|
162
162
|
--space-9: 6rem; /* hero rhythm */
|
|
163
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
164
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
165
|
+
--space-xs: var(--space-1);
|
|
166
|
+
--space-sm: var(--space-2);
|
|
167
|
+
--space-md: var(--space-4);
|
|
168
|
+
--space-lg: var(--space-5);
|
|
169
|
+
--space-xl: var(--space-6);
|
|
170
|
+
--space-2xl: var(--space-7);
|
|
171
|
+
--space-3xl: var(--space-8);
|
|
172
|
+
--space-4xl: var(--space-9);
|
|
163
173
|
/* Radius alias */
|
|
164
174
|
--radius-sm: var(--r-sm);
|
|
165
175
|
--radius-md: var(--r-md);
|
|
@@ -134,6 +134,16 @@
|
|
|
134
134
|
--space-7: 3rem; /* major gap */
|
|
135
135
|
--space-8: 4rem; /* page section */
|
|
136
136
|
--space-9: 6rem; /* hero rhythm */
|
|
137
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
138
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
139
|
+
--space-xs: var(--space-1);
|
|
140
|
+
--space-sm: var(--space-2);
|
|
141
|
+
--space-md: var(--space-4);
|
|
142
|
+
--space-lg: var(--space-5);
|
|
143
|
+
--space-xl: var(--space-6);
|
|
144
|
+
--space-2xl: var(--space-7);
|
|
145
|
+
--space-3xl: var(--space-8);
|
|
146
|
+
--space-4xl: var(--space-9);
|
|
137
147
|
--radius-sm: var(--r-sm);
|
|
138
148
|
--radius-md: var(--r-md);
|
|
139
149
|
--radius-lg: var(--r-lg);
|
|
@@ -173,6 +173,16 @@
|
|
|
173
173
|
--space-7: 3rem; /* major gap */
|
|
174
174
|
--space-8: 4rem; /* page section */
|
|
175
175
|
--space-9: 6rem; /* hero rhythm */
|
|
176
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
177
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
178
|
+
--space-xs: var(--space-1);
|
|
179
|
+
--space-sm: var(--space-2);
|
|
180
|
+
--space-md: var(--space-4);
|
|
181
|
+
--space-lg: var(--space-5);
|
|
182
|
+
--space-xl: var(--space-6);
|
|
183
|
+
--space-2xl: var(--space-7);
|
|
184
|
+
--space-3xl: var(--space-8);
|
|
185
|
+
--space-4xl: var(--space-9);
|
|
176
186
|
/* Radius alias */
|
|
177
187
|
--radius-sm: var(--r-sm);
|
|
178
188
|
--radius-md: var(--r-md);
|
|
@@ -135,6 +135,16 @@
|
|
|
135
135
|
--space-7: 3rem; /* major gap */
|
|
136
136
|
--space-8: 4rem; /* page section */
|
|
137
137
|
--space-9: 6rem; /* hero rhythm */
|
|
138
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
139
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
140
|
+
--space-xs: var(--space-1);
|
|
141
|
+
--space-sm: var(--space-2);
|
|
142
|
+
--space-md: var(--space-4);
|
|
143
|
+
--space-lg: var(--space-5);
|
|
144
|
+
--space-xl: var(--space-6);
|
|
145
|
+
--space-2xl: var(--space-7);
|
|
146
|
+
--space-3xl: var(--space-8);
|
|
147
|
+
--space-4xl: var(--space-9);
|
|
138
148
|
--radius-sm: 0;
|
|
139
149
|
--radius-md: 0;
|
|
140
150
|
--radius-lg: 0;
|
|
@@ -196,6 +196,16 @@
|
|
|
196
196
|
--space-7: 3rem; /* major gap */
|
|
197
197
|
--space-8: 4rem; /* page section */
|
|
198
198
|
--space-9: 6rem; /* hero rhythm */
|
|
199
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
200
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
201
|
+
--space-xs: var(--space-1);
|
|
202
|
+
--space-sm: var(--space-2);
|
|
203
|
+
--space-md: var(--space-4);
|
|
204
|
+
--space-lg: var(--space-5);
|
|
205
|
+
--space-xl: var(--space-6);
|
|
206
|
+
--space-2xl: var(--space-7);
|
|
207
|
+
--space-3xl: var(--space-8);
|
|
208
|
+
--space-4xl: var(--space-9);
|
|
199
209
|
/* Radius alias — CRT has hard pixel corners, so every slot is 0 */
|
|
200
210
|
--radius-sm: 0;
|
|
201
211
|
--radius-md: 0;
|
|
@@ -134,6 +134,16 @@
|
|
|
134
134
|
--space-7: 3rem; /* major gap */
|
|
135
135
|
--space-8: 4rem; /* page section */
|
|
136
136
|
--space-9: 6rem; /* hero rhythm */
|
|
137
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
138
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
139
|
+
--space-xs: var(--space-1);
|
|
140
|
+
--space-sm: var(--space-2);
|
|
141
|
+
--space-md: var(--space-4);
|
|
142
|
+
--space-lg: var(--space-5);
|
|
143
|
+
--space-xl: var(--space-6);
|
|
144
|
+
--space-2xl: var(--space-7);
|
|
145
|
+
--space-3xl: var(--space-8);
|
|
146
|
+
--space-4xl: var(--space-9);
|
|
137
147
|
--radius-sm: 0;
|
|
138
148
|
--radius-md: 0;
|
|
139
149
|
--radius-lg: 0;
|
|
@@ -320,3 +320,86 @@
|
|
|
320
320
|
transition: none;
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
|
+
|
|
324
|
+
// ----------------------------------------------------------------------------
|
|
325
|
+
// SHEET — bottom drawer with rounded shoulders; the mobile-app panel.
|
|
326
|
+
// ----------------------------------------------------------------------------
|
|
327
|
+
// A preset of drawer($side: bottom): slides up from the bottom edge,
|
|
328
|
+
// caps its height so the page stays visible behind it (dvh survives
|
|
329
|
+
// mobile URL-bar resizing), rounds the top corners, and pads for the
|
|
330
|
+
// home-indicator safe area. Same zero-JS popover mechanics as drawer.
|
|
331
|
+
//
|
|
332
|
+
// Usage:
|
|
333
|
+
// .docs-sheet { @include sheet; }
|
|
334
|
+
// <section id="docs-sheet" class="docs-sheet" popover aria-label="Docs">…</section>
|
|
335
|
+
|
|
336
|
+
@mixin sheet(
|
|
337
|
+
$size: auto,
|
|
338
|
+
$max: 72dvh,
|
|
339
|
+
$bg: surface-default,
|
|
340
|
+
$backdrop: rgba(0, 0, 0, 0.4),
|
|
341
|
+
$p: 5,
|
|
342
|
+
$r: xl
|
|
343
|
+
) {
|
|
344
|
+
@include drawer($side: bottom, $size: $size, $bg: $bg, $backdrop: $backdrop, $p: $p);
|
|
345
|
+
max-block-size: $max;
|
|
346
|
+
border-start-start-radius: m.radius($r);
|
|
347
|
+
border-start-end-radius: m.radius($r);
|
|
348
|
+
padding-block-end: calc(#{m.space($p)} + env(safe-area-inset-bottom));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// ----------------------------------------------------------------------------
|
|
352
|
+
// DOCK — fixed bottom bar; the mobile-app layout's navigation.
|
|
353
|
+
// ----------------------------------------------------------------------------
|
|
354
|
+
// The pattern the cia docs site runs on phones: a thumb-reach bar whose
|
|
355
|
+
// slots open popover sheets (pair dock-item buttons with sheet() panels
|
|
356
|
+
// via popovertarget — the browser manages aria-expanded, Esc, and light
|
|
357
|
+
// dismiss; zero JavaScript). CSS Grid gives every slot an equal track.
|
|
358
|
+
//
|
|
359
|
+
// Usage:
|
|
360
|
+
// .dock { @include dock(3); }
|
|
361
|
+
// .dock button { @include dock-item; }
|
|
362
|
+
// <nav class="dock" aria-label="Quick menu">
|
|
363
|
+
// <button popovertarget="docs-sheet">Docs</button>
|
|
364
|
+
// …
|
|
365
|
+
// </nav>
|
|
366
|
+
|
|
367
|
+
@mixin dock($slots: 3, $bg: surface-default) {
|
|
368
|
+
@include m.print-hidden;
|
|
369
|
+
position: fixed;
|
|
370
|
+
inset-inline: 0;
|
|
371
|
+
inset-block-end: 0;
|
|
372
|
+
z-index: m.z(fixed);
|
|
373
|
+
display: grid;
|
|
374
|
+
grid-template-columns: repeat($slots, minmax(0, 1fr));
|
|
375
|
+
background: m.color($bg);
|
|
376
|
+
border-block-start: 1px solid m.color(border-default);
|
|
377
|
+
padding-block-end: env(safe-area-inset-bottom);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
@mixin dock-item($accent: action-primary-default) {
|
|
381
|
+
@include m.button-reset;
|
|
382
|
+
@include m.focus-ring;
|
|
383
|
+
cursor: pointer;
|
|
384
|
+
display: grid;
|
|
385
|
+
justify-items: center;
|
|
386
|
+
align-content: center;
|
|
387
|
+
gap: m.space(1);
|
|
388
|
+
min-height: 3.5rem; /* 56px — comfortable thumb target */
|
|
389
|
+
padding: m.space(1) m.space(2);
|
|
390
|
+
color: m.color(text-secondary);
|
|
391
|
+
@include m.font(medium, 1);
|
|
392
|
+
@include m.transition(color, background-color);
|
|
393
|
+
|
|
394
|
+
> svg {
|
|
395
|
+
width: 1.35em;
|
|
396
|
+
height: 1.35em;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Semantic state lives in ARIA: the browser sets aria-expanded on
|
|
400
|
+
// popovertarget invokers; aria-current marks a routed slot.
|
|
401
|
+
&[aria-expanded="true"],
|
|
402
|
+
&[aria-current] {
|
|
403
|
+
color: m.color($accent);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bottom-nav
|
|
3
|
+
description: Mobile-app layout — a fixed bottom dock whose slots open slide-up sheets, zero JavaScript on the Popover API.
|
|
4
|
+
category: navigation
|
|
5
|
+
complexity: medium
|
|
6
|
+
cia-version: ">=1.5.0"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Use this when
|
|
10
|
+
|
|
11
|
+
Your page is a **tool** on mobile — docs with a section tree, a dashboard, an
|
|
12
|
+
editor — and navigation belongs in thumb reach, app-style, instead of behind a
|
|
13
|
+
top hamburger. This is the layout the cia docs site itself runs on phones.
|
|
14
|
+
For simple site navigation (a menu of links), use the `mobile-nav` recipe's
|
|
15
|
+
drawer instead.
|
|
16
|
+
|
|
17
|
+
## Structure (raw HTML)
|
|
18
|
+
|
|
19
|
+
A fixed bottom dock of buttons, each pointing at its own sheet via
|
|
20
|
+
`popovertarget`. The browser manages open state, Esc, and light dismiss.
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<div data-cia-recipe="bottom-nav">
|
|
24
|
+
<!-- slide-up sheets — one per dock slot -->
|
|
25
|
+
<section id="nav-sheet" class="app-sheet" popover aria-label="Navigation">
|
|
26
|
+
<nav data-slot="nav">…section links…</nav>
|
|
27
|
+
</section>
|
|
28
|
+
<section id="tools-sheet" class="app-sheet" popover aria-label="Tools">
|
|
29
|
+
<div data-slot="tools">…controls…</div>
|
|
30
|
+
</section>
|
|
31
|
+
|
|
32
|
+
<!-- the dock -->
|
|
33
|
+
<nav class="app-dock" aria-label="Quick menu">
|
|
34
|
+
<button popovertarget="nav-sheet">Menu</button>
|
|
35
|
+
<button popovertarget="tools-sheet">Tools</button>
|
|
36
|
+
<a href="/search" aria-current="false">Search</a>
|
|
37
|
+
</nav>
|
|
38
|
+
</div>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Styling (cia mixins)
|
|
42
|
+
|
|
43
|
+
```scss
|
|
44
|
+
// AppDock.module.scss — component stylesheet, so import the zero-emit barrel.
|
|
45
|
+
@use 'css-is-awesome/api' as cia;
|
|
46
|
+
|
|
47
|
+
.app-dock {
|
|
48
|
+
// Hide above the mobile breakpoint — desktop has the full chrome.
|
|
49
|
+
display: none;
|
|
50
|
+
|
|
51
|
+
@include cia.media-down(lg) {
|
|
52
|
+
@include cia.dock(3); // CSS Grid: one equal track per slot
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
.app-dock button,
|
|
56
|
+
.app-dock a {
|
|
57
|
+
@include cia.dock-item; // 56px thumb targets, ARIA-driven accent
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.app-sheet {
|
|
61
|
+
@include cia.media-down(lg) {
|
|
62
|
+
@include cia.sheet; // bottom drawer, 72dvh cap, rounded shoulders
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Give the page's scrollable content bottom padding so the fixed dock never
|
|
68
|
+
covers the last lines: `padding-block-end: calc(6rem + env(safe-area-inset-bottom))`
|
|
69
|
+
on the content region of your page layout.
|
|
70
|
+
|
|
71
|
+
## Interactivity
|
|
72
|
+
|
|
73
|
+
**Zero JavaScript.** Each dock button is a `popovertarget` invoker for its
|
|
74
|
+
sheet; the browser keeps `aria-expanded` in sync (which is what lights the
|
|
75
|
+
active slot via `cia.dock-item`), closes on Esc or outside tap, and stacks
|
|
76
|
+
the sheet in the top layer above the dock. Opening one sheet auto-closes
|
|
77
|
+
another (`popover="auto"` is exclusive). The slide-up animation rides
|
|
78
|
+
`@starting-style` and degrades to an instant open on older engines.
|
|
79
|
+
Popover is Baseline 2024 (Chrome 114, Firefox 125, Safari 17).
|
|
80
|
+
|
|
81
|
+
## A11y checklist
|
|
82
|
+
|
|
83
|
+
- [ ] The dock is a `<nav>` with an `aria-label`, discoverable as a landmark
|
|
84
|
+
([WAI-ARIA APG: Landmark regions](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/))
|
|
85
|
+
- [ ] Every slot is a real `<button>` (sheet openers) or `<a>` (route links)
|
|
86
|
+
with a visible text label — icons alone don't name a control
|
|
87
|
+
([WCAG 4.1.2 Name, Role, Value](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html))
|
|
88
|
+
- [ ] `aria-expanded` reflects each sheet's state — browser-managed for
|
|
89
|
+
`popovertarget` invokers; verify with an inspector
|
|
90
|
+
([WAI-ARIA APG: Disclosure pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/))
|
|
91
|
+
- [ ] Sheets carry `aria-label`s describing their content
|
|
92
|
+
([WCAG 2.4.6 Headings and Labels](https://www.w3.org/WAI/WCAG22/Understanding/headings-and-labels.html))
|
|
93
|
+
- [ ] Esc closes the open sheet and focus returns to its dock button (native
|
|
94
|
+
popover behavior — verify if you've added scripts)
|
|
95
|
+
([WAI-ARIA APG: Dialog (Modal) keyboard](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/))
|
|
96
|
+
- [ ] Slots are ≥ 44px targets; `cia.dock-item` defaults to 56px
|
|
97
|
+
([WCAG 2.5.8 Target Size (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html))
|
|
98
|
+
- [ ] Reduced motion honored — the sheet's slide disables under
|
|
99
|
+
`prefers-reduced-motion` (baked into `cia.drawer`)
|
|
100
|
+
([WCAG 2.3.3 Animation from Interactions](https://www.w3.org/WAI/WCAG22/Understanding/animation-from-interactions.html))
|
|
101
|
+
|
|
102
|
+
## Framework examples
|
|
103
|
+
|
|
104
|
+
### React
|
|
105
|
+
|
|
106
|
+
```jsx
|
|
107
|
+
export function AppDock() {
|
|
108
|
+
return (
|
|
109
|
+
<>
|
|
110
|
+
<section id="nav-sheet" className={styles.appSheet} popover="auto" aria-label="Navigation">
|
|
111
|
+
<nav>…</nav>
|
|
112
|
+
</section>
|
|
113
|
+
<nav className={styles.appDock} aria-label="Quick menu">
|
|
114
|
+
<button popoverTarget="nav-sheet">Menu</button>
|
|
115
|
+
</nav>
|
|
116
|
+
</>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
// React 19 forwards popover / popoverTarget as attributes — still no JS of yours.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Vue
|
|
123
|
+
|
|
124
|
+
```vue
|
|
125
|
+
<template>
|
|
126
|
+
<section id="nav-sheet" class="app-sheet" popover aria-label="Navigation">
|
|
127
|
+
<nav>…</nav>
|
|
128
|
+
</section>
|
|
129
|
+
<nav class="app-dock" aria-label="Quick menu">
|
|
130
|
+
<button popovertarget="nav-sheet">Menu</button>
|
|
131
|
+
</nav>
|
|
132
|
+
</template>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Svelte
|
|
136
|
+
|
|
137
|
+
```svelte
|
|
138
|
+
<section id="nav-sheet" class="app-sheet" popover aria-label="Navigation">
|
|
139
|
+
<nav>…</nav>
|
|
140
|
+
</section>
|
|
141
|
+
<nav class="app-dock" aria-label="Quick menu">
|
|
142
|
+
<button popovertarget="nav-sheet">Menu</button>
|
|
143
|
+
</nav>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Vanilla (Web Component)
|
|
147
|
+
|
|
148
|
+
```html
|
|
149
|
+
<!-- The pattern IS vanilla HTML — the popover attributes are the whole
|
|
150
|
+
mechanism. Drop the Structure markup in as-is. -->
|
|
151
|
+
<script type="module">
|
|
152
|
+
// Intentionally empty. Optional nicety: close the open sheet when a
|
|
153
|
+
// same-page link inside it is tapped —
|
|
154
|
+
// sheet.querySelectorAll('a[href^="#"]').forEach(a =>
|
|
155
|
+
// a.addEventListener('click', () => sheet.hidePopover()));
|
|
156
|
+
</script>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Variants
|
|
160
|
+
|
|
161
|
+
- **Mixed dock**: route links (`<a aria-current="page">`) and sheet openers
|
|
162
|
+
(`<button popovertarget>`) share the dock; `cia.dock-item` lights either
|
|
163
|
+
via its ARIA state.
|
|
164
|
+
- **Two-slot / five-slot**: pass the count — `cia.dock(5)` — and the grid
|
|
165
|
+
redistributes; keep it ≤5 so labels stay readable.
|
|
166
|
+
|
|
167
|
+
## Pitfalls
|
|
168
|
+
|
|
169
|
+
- **`popover` hides sheets everywhere**, including desktop. If a sheet's
|
|
170
|
+
content should exist in desktop chrome instead (a sidebar, say), render it
|
|
171
|
+
twice — desktop region + mobile sheet — or move the node with CSS only.
|
|
172
|
+
- **Padding under the dock**: forgetting the content's bottom padding hides
|
|
173
|
+
the page's last lines behind the bar (see Styling).
|
|
174
|
+
- **Don't z-index against the sheets** — popovers live in the top layer; the
|
|
175
|
+
dock's `z-index` only matters against page content.
|
|
176
|
+
- The dock is `position: fixed` — inside a transformed ancestor it will pin
|
|
177
|
+
to that ancestor, not the viewport. Keep it at the page level.
|
|
178
|
+
|
|
179
|
+
## Related recipes
|
|
180
|
+
|
|
181
|
+
- `mobile-nav` — hamburger + drawer for plain site navigation (the "flex
|
|
182
|
+
layout": one fluid shell that reshapes with the screen; this recipe is
|
|
183
|
+
the "app layout").
|
|
184
|
+
- `dialog` — modal overlays on native `<dialog>`.
|
package/scss/recipes/combobox.md
CHANGED
|
@@ -501,6 +501,15 @@ Committed values render as removable chips before the input; the input clears af
|
|
|
501
501
|
- **`<datalist>` styling is a dead end.** No browser lets you style the native popup. Don't burn time on it — if the design needs styled options, that's the signal to move to the custom variant.
|
|
502
502
|
- **Filtering resets the active index.** After re-filtering, old indices point at different options. Reset `active` to `-1` on every `input` event (all examples above do).
|
|
503
503
|
- **Scroll the active option into view** when the list overflows: `option.scrollIntoView({ block: "nearest" })` after moving the active index — omitted from the examples for brevity, needed in production with long lists.
|
|
504
|
+
- **Phones: cap the listbox, thumb-size the options.** The `max-block-size: 16rem; overflow-y: auto` in the Styling section is what keeps a long list from running past the bottom of a small viewport — don't delete it when trimming. And `cia.dropdown-item` is padded for pointers (≥24px, the WCAG minimum); at touch widths, bump options to a comfortable 44px thumb target:
|
|
505
|
+
|
|
506
|
+
```scss
|
|
507
|
+
[role="option"] {
|
|
508
|
+
@include cia.media-down(md) {
|
|
509
|
+
min-block-size: 44px;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
```
|
|
504
513
|
|
|
505
514
|
## Related recipes
|
|
506
515
|
|
package/scss/recipes/dialog.md
CHANGED
|
@@ -251,6 +251,26 @@ Override `.my-dialog` with `inset-inline-end: 0; margin-inline: auto 0; block-si
|
|
|
251
251
|
|
|
252
252
|
cia's built-in keyframes are small entrance nudges, so a full-width drawer needs its own `@keyframes`. If an 8px slide is enough, skip the custom keyframe and use `@include cia.animate(slide-left);` — it reads the same duration/easing tokens and handles `prefers-reduced-motion` for you.
|
|
253
253
|
|
|
254
|
+
### Bottom sheet on phones
|
|
255
|
+
|
|
256
|
+
At phone widths a centered modal can feel cramped; the mobile-app convention is a bottom sheet. `cia.sheet` gives `<dialog>` the sheet's **box styling** — full-width at the bottom edge, 72dvh height cap, rounded shoulders, home-indicator safe-area padding — but its slide-up motion is built for `[popover]` elements: both the entry transition and the closed-state off-screen offset key on `:popover-open`, which a `<dialog>` never matches. So on `<dialog>` you must reset that offset for the `[open]` state, and the sheet opens in place instead of sliding:
|
|
257
|
+
|
|
258
|
+
```scss
|
|
259
|
+
.my-dialog {
|
|
260
|
+
@include cia.modal;
|
|
261
|
+
|
|
262
|
+
@include cia.media-down(md) {
|
|
263
|
+
@include cia.sheet; // box styles only on <dialog> — see note above
|
|
264
|
+
|
|
265
|
+
&[open] {
|
|
266
|
+
translate: 0 0; // undo the sheet's :popover-open-keyed offset
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
If the slide-up entrance matters to you, use a `[popover]` element with the `bottom-nav` recipe's sheet pattern instead of `<dialog>` — you trade `.showModal()`'s focus trap for light dismiss and the full animation.
|
|
273
|
+
|
|
254
274
|
## Pitfalls
|
|
255
275
|
|
|
256
276
|
- **Form inside dialog with another method:** Setting `<form method="get">` etc. inside a `<dialog>` breaks the native close-on-submit. Either nest a separate `<form method="dialog">` around the close buttons OR handle submission explicitly with `event.preventDefault()` + `dialogEl.close()`.
|
|
@@ -261,5 +281,6 @@ cia's built-in keyframes are small entrance nudges, so a full-width drawer needs
|
|
|
261
281
|
## Related recipes
|
|
262
282
|
|
|
263
283
|
- [`bare-tags`](./_bare-tags.scss) — base bare `<dialog>` styling that applies if you skip a custom class name
|
|
284
|
+
- `bottom-nav` — slide-up sheets on `[popover]` with the full animation; the alternative named in the bottom-sheet variant above
|
|
264
285
|
- (planned v1.1) `command-palette.md` — Cmd+K palette built on `<dialog>` + combobox pattern
|
|
265
286
|
- (planned v1.1) `toast.md` — non-modal transient notifications (`[popover]` based)
|
|
@@ -226,6 +226,9 @@ standalone mixin, so state can come from `:checked` instead of
|
|
|
226
226
|
|
|
227
227
|
## Related recipes
|
|
228
228
|
|
|
229
|
+
- `bottom-nav` — bottom dock + slide-up sheets for pages that are tools on
|
|
230
|
+
mobile (the "app layout"; this recipe is the "flex layout": one fluid
|
|
231
|
+
shell that reshapes with the screen).
|
|
229
232
|
- `dialog` — modal overlays for content (native `<dialog>`, same zero-JS
|
|
230
233
|
philosophy).
|
|
231
234
|
- `combobox` — another browser-native disclosure pattern.
|
|
@@ -172,6 +172,17 @@
|
|
|
172
172
|
--space-8: 4rem; /* page section */
|
|
173
173
|
--space-9: 6rem; /* hero rhythm */
|
|
174
174
|
|
|
175
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
176
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
177
|
+
--space-xs: var(--space-1);
|
|
178
|
+
--space-sm: var(--space-2);
|
|
179
|
+
--space-md: var(--space-4);
|
|
180
|
+
--space-lg: var(--space-5);
|
|
181
|
+
--space-xl: var(--space-6);
|
|
182
|
+
--space-2xl: var(--space-7);
|
|
183
|
+
--space-3xl: var(--space-8);
|
|
184
|
+
--space-4xl: var(--space-9);
|
|
185
|
+
|
|
175
186
|
--radius-sm: var(--r-sm); --radius-md: var(--r-md); --radius-lg: var(--r-lg);
|
|
176
187
|
--radius-xl: 12px; --radius-full: 9999px;
|
|
177
188
|
--font-primary: var(--font-sans);
|
|
@@ -201,6 +201,17 @@
|
|
|
201
201
|
--space-8: 4rem; /* page section */
|
|
202
202
|
--space-9: 6rem; /* hero rhythm */
|
|
203
203
|
|
|
204
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
205
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
206
|
+
--space-xs: var(--space-1);
|
|
207
|
+
--space-sm: var(--space-2);
|
|
208
|
+
--space-md: var(--space-4);
|
|
209
|
+
--space-lg: var(--space-5);
|
|
210
|
+
--space-xl: var(--space-6);
|
|
211
|
+
--space-2xl: var(--space-7);
|
|
212
|
+
--space-3xl: var(--space-8);
|
|
213
|
+
--space-4xl: var(--space-9);
|
|
214
|
+
|
|
204
215
|
|
|
205
216
|
|
|
206
217
|
|
|
@@ -219,6 +219,17 @@
|
|
|
219
219
|
--space-8: 4rem; /* page section */
|
|
220
220
|
--space-9: 6rem; /* hero rhythm */
|
|
221
221
|
|
|
222
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
223
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
224
|
+
--space-xs: var(--space-1);
|
|
225
|
+
--space-sm: var(--space-2);
|
|
226
|
+
--space-md: var(--space-4);
|
|
227
|
+
--space-lg: var(--space-5);
|
|
228
|
+
--space-xl: var(--space-6);
|
|
229
|
+
--space-2xl: var(--space-7);
|
|
230
|
+
--space-3xl: var(--space-8);
|
|
231
|
+
--space-4xl: var(--space-9);
|
|
232
|
+
|
|
222
233
|
|
|
223
234
|
|
|
224
235
|
|
|
@@ -177,6 +177,17 @@
|
|
|
177
177
|
--space-8: 4rem; /* page section */
|
|
178
178
|
--space-9: 6rem; /* hero rhythm */
|
|
179
179
|
|
|
180
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
181
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
182
|
+
--space-xs: var(--space-1);
|
|
183
|
+
--space-sm: var(--space-2);
|
|
184
|
+
--space-md: var(--space-4);
|
|
185
|
+
--space-lg: var(--space-5);
|
|
186
|
+
--space-xl: var(--space-6);
|
|
187
|
+
--space-2xl: var(--space-7);
|
|
188
|
+
--space-3xl: var(--space-8);
|
|
189
|
+
--space-4xl: var(--space-9);
|
|
190
|
+
|
|
180
191
|
--radius-sm: var(--r-sm); --radius-md: var(--r-md); --radius-lg: var(--r-lg);
|
|
181
192
|
--radius-xl: 0.75rem; --radius-full: 9999px;
|
|
182
193
|
--font-primary: var(--font-sans);
|
|
@@ -211,6 +211,17 @@
|
|
|
211
211
|
--space-8: 4rem; /* page section */
|
|
212
212
|
--space-9: 6rem; /* hero rhythm */
|
|
213
213
|
|
|
214
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
215
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
216
|
+
--space-xs: var(--space-1);
|
|
217
|
+
--space-sm: var(--space-2);
|
|
218
|
+
--space-md: var(--space-4);
|
|
219
|
+
--space-lg: var(--space-5);
|
|
220
|
+
--space-xl: var(--space-6);
|
|
221
|
+
--space-2xl: var(--space-7);
|
|
222
|
+
--space-3xl: var(--space-8);
|
|
223
|
+
--space-4xl: var(--space-9);
|
|
224
|
+
|
|
214
225
|
|
|
215
226
|
|
|
216
227
|
|
|
@@ -238,6 +238,17 @@
|
|
|
238
238
|
--space-8: 4rem; /* page section */
|
|
239
239
|
--space-9: 6rem; /* hero rhythm */
|
|
240
240
|
|
|
241
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
242
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
243
|
+
--space-xs: var(--space-1);
|
|
244
|
+
--space-sm: var(--space-2);
|
|
245
|
+
--space-md: var(--space-4);
|
|
246
|
+
--space-lg: var(--space-5);
|
|
247
|
+
--space-xl: var(--space-6);
|
|
248
|
+
--space-2xl: var(--space-7);
|
|
249
|
+
--space-3xl: var(--space-8);
|
|
250
|
+
--space-4xl: var(--space-9);
|
|
251
|
+
|
|
241
252
|
|
|
242
253
|
|
|
243
254
|
|
package/scss/themes/glass.scss
CHANGED
|
@@ -211,6 +211,17 @@
|
|
|
211
211
|
--space-8: 4rem; /* page section */
|
|
212
212
|
--space-9: 6rem; /* hero rhythm */
|
|
213
213
|
|
|
214
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
215
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
216
|
+
--space-xs: var(--space-1);
|
|
217
|
+
--space-sm: var(--space-2);
|
|
218
|
+
--space-md: var(--space-4);
|
|
219
|
+
--space-lg: var(--space-5);
|
|
220
|
+
--space-xl: var(--space-6);
|
|
221
|
+
--space-2xl: var(--space-7);
|
|
222
|
+
--space-3xl: var(--space-8);
|
|
223
|
+
--space-4xl: var(--space-9);
|
|
224
|
+
|
|
214
225
|
--radius-sm: var(--r-sm); --radius-md: var(--r-md); --radius-lg: var(--r-lg);
|
|
215
226
|
--radius-xl: 0.75rem; --radius-full: 9999px;
|
|
216
227
|
--font-primary: var(--font-sans);
|
|
@@ -232,6 +232,17 @@
|
|
|
232
232
|
--space-8: 4rem; /* page section */
|
|
233
233
|
--space-9: 6rem; /* hero rhythm */
|
|
234
234
|
|
|
235
|
+
/* T-shirt aliases - var() references into this theme's numbered scale,
|
|
236
|
+
so re-tuning a numbered step re-tunes its alias automatically. */
|
|
237
|
+
--space-xs: var(--space-1);
|
|
238
|
+
--space-sm: var(--space-2);
|
|
239
|
+
--space-md: var(--space-4);
|
|
240
|
+
--space-lg: var(--space-5);
|
|
241
|
+
--space-xl: var(--space-6);
|
|
242
|
+
--space-2xl: var(--space-7);
|
|
243
|
+
--space-3xl: var(--space-8);
|
|
244
|
+
--space-4xl: var(--space-9);
|
|
245
|
+
|
|
235
246
|
|
|
236
247
|
|
|
237
248
|
|