@getvitops/generator 2.1.0 → 3.0.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/CHANGELOG.md +174 -0
- package/assets/bricks/elements/copy-button.php +3 -3
- package/assets/bricks/elements/multi-field.php +3 -3
- package/assets/css/animation.css +90 -0
- package/assets/css/global.css +10 -0
- package/assets/css/index.css +5 -0
- package/assets/css/layout-utilities.css +46 -0
- package/assets/css/layout.css +87 -2
- package/assets/css/patterns/anchor-link.css +36 -0
- package/assets/css/patterns/code.css +24 -0
- package/assets/css/patterns/details.css +28 -16
- package/assets/css/patterns/dialog.css +13 -31
- package/assets/css/patterns/drawer.css +27 -66
- package/assets/css/patterns/dropdown.css +15 -1
- package/assets/css/patterns/lightbox.css +3 -3
- package/assets/css/patterns/marquee.css +33 -5
- package/assets/css/patterns/nav.css +27 -79
- package/assets/css/patterns/navbar.css +86 -0
- package/assets/css/patterns/navshell.css +383 -0
- package/assets/css/patterns/popover.css +56 -8
- package/assets/css/patterns/scroll-target.css +18 -4
- package/assets/css/patterns/sitenav.css +117 -338
- package/assets/css/patterns/split-link.css +3 -3
- package/assets/js/elements.js +3 -3
- package/{site.schema.json → config.schema.json} +2300 -2283
- package/dist/index.d.mts +882 -415
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3284 -3095
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Navbar — a horizontal row of links, with alignment.
|
|
3
|
+
*
|
|
4
|
+
* <nav class="navbar navbar--end">
|
|
5
|
+
* <a class="link" href="/guides">Guides</a>
|
|
6
|
+
* <a class="link" href="/reference">Reference</a>
|
|
7
|
+
* </nav>
|
|
8
|
+
*
|
|
9
|
+
* Extracted from patterns/nav.css, where `.navbar` already lived but only as the
|
|
10
|
+
* horizontal half of that file's drawer⇄navbar pair — it could not be used on
|
|
11
|
+
* its own, and it had no way to say where the links should sit. It is a
|
|
12
|
+
* primitive now, so `sitenav` (and anything else that needs a link row at width)
|
|
13
|
+
* composes it instead of restating `display: flex` and a gap.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately NOT a `.cluster`: a cluster wraps and is content-agnostic; a
|
|
16
|
+
* navbar is a single row of navigation that stays a row, and carries the
|
|
17
|
+
* alignment vocabulary a nav actually needs.
|
|
18
|
+
*/
|
|
19
|
+
.navbar {
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
gap: var(--navbar-gap, 2rem);
|
|
23
|
+
|
|
24
|
+
/* Links stay on one line — a navbar that wraps mid-row reads as broken chrome.
|
|
25
|
+
Above its breakpoint `sitenav` is what decides there is room; below it, the
|
|
26
|
+
drawer is the answer, not a wrapped bar. */
|
|
27
|
+
flex-wrap: nowrap;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* ── Alignment. `--start` is the default and exists so the intent can be stated
|
|
31
|
+
rather than inferred from its absence. ── */
|
|
32
|
+
.navbar--start {
|
|
33
|
+
justify-content: flex-start;
|
|
34
|
+
}
|
|
35
|
+
.navbar--center {
|
|
36
|
+
justify-content: center;
|
|
37
|
+
}
|
|
38
|
+
.navbar--end {
|
|
39
|
+
justify-content: flex-end;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Push everything after this element to the far edge — the usual "brand on the
|
|
44
|
+
* left, links on the right" split, without a wrapper element per side.
|
|
45
|
+
*/
|
|
46
|
+
.navbar__spacer {
|
|
47
|
+
margin-inline-start: auto;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.navbar--sticky,
|
|
51
|
+
/* The pre-extraction spelling. Kept so an existing consumer's markup keeps
|
|
52
|
+
working; prefer `.navbar--sticky`. */
|
|
53
|
+
.navbar-sticky {
|
|
54
|
+
position: sticky;
|
|
55
|
+
inset-block-start: var(--navbar-sticky-offset, 0);
|
|
56
|
+
z-index: var(--z-tier-sticky);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ── Legacy composition: nav.css's `.nav-*` parts inside a navbar. Kept with the
|
|
60
|
+
pattern they belong to so nav.css can be retired as one piece. ── */
|
|
61
|
+
.navbar {
|
|
62
|
+
nav {
|
|
63
|
+
flex: 1;
|
|
64
|
+
flex-direction: row;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.nav-items {
|
|
68
|
+
flex: 1;
|
|
69
|
+
flex-direction: row;
|
|
70
|
+
gap: 2.25rem;
|
|
71
|
+
border-bottom: none;
|
|
72
|
+
padding-bottom: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.nav-actions {
|
|
76
|
+
flex-direction: row;
|
|
77
|
+
gap: 2.25rem;
|
|
78
|
+
border-top: none;
|
|
79
|
+
padding-top: 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.nav-header {
|
|
83
|
+
border-bottom: none;
|
|
84
|
+
padding-bottom: 0;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Navshell — a navigation ASIDE beside main content at width, collapsing to a
|
|
3
|
+
* toggle + drawer below it. One markup tree, two presentations, no JS beyond the
|
|
4
|
+
* Popover polyfill.
|
|
5
|
+
*
|
|
6
|
+
* <div class="navshell navshell--bp-md">
|
|
7
|
+
* <div class="navshell__bar">
|
|
8
|
+
* <button class="navshell__toggle" popovertarget="site-nav">Menu</button>
|
|
9
|
+
* </div>
|
|
10
|
+
* <div id="site-nav" popover class="navshell__panel drawer drawer--left">
|
|
11
|
+
* <button class="navshell__close" popovertarget="site-nav" popovertargetaction="hide">×</button>
|
|
12
|
+
* <nav class="navshell__nav" aria-label="Documentation"> … </nav>
|
|
13
|
+
* </div>
|
|
14
|
+
* <div class="navshell__main"> … </div>
|
|
15
|
+
* </div>
|
|
16
|
+
*
|
|
17
|
+
* It NESTS — that is the point, and it is what `.toc-layout` (which this
|
|
18
|
+
* supersedes) could not do. A docs page is a site nav wrapping a page nav:
|
|
19
|
+
* the outer promotes to two columns at `md`, the inner waits for `lg`, and
|
|
20
|
+
* neither needs to know about the other.
|
|
21
|
+
*
|
|
22
|
+
* The mobile panel composes `.drawer`, so this file declares NO animation and no
|
|
23
|
+
* `::backdrop`: the edge modifier states the slide direction, the top-layer
|
|
24
|
+
* driver in animation.css runs it both ways, and popover.css owns the scrim.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
.navshell {
|
|
28
|
+
/* RESET FIRST — these two must sit above the breakpoint blocks, and EVERY
|
|
29
|
+
root must re-declare them.
|
|
30
|
+
Both custom properties inherit, and this pattern is built to nest. Without
|
|
31
|
+
the reset, an outer instance already past ITS breakpoint hands its flag and
|
|
32
|
+
column template down to an inner instance that is still narrow, and the
|
|
33
|
+
inner one renders its desktop layout early. Re-declaring on every root
|
|
34
|
+
severs the inheritance at each instance boundary.
|
|
35
|
+
`.navshell--bp-*` and `.navshell` are the same specificity, so ORDER is what
|
|
36
|
+
lets the breakpoint blocks win. */
|
|
37
|
+
--_navshell-wide: 0;
|
|
38
|
+
--_navshell-cols: minmax(0, 1fr);
|
|
39
|
+
|
|
40
|
+
display: grid;
|
|
41
|
+
grid-template-columns: var(--_navshell-cols);
|
|
42
|
+
align-items: start;
|
|
43
|
+
|
|
44
|
+
/* Stacked, `gap` is the space between the toggle row and the content — a
|
|
45
|
+
different job from the space between two columns, and the column value is
|
|
46
|
+
far too big for it. `--navshell-gap` is applied in the breakpoint blocks
|
|
47
|
+
instead, which is also the only place it CAN be: the desktop style query
|
|
48
|
+
below cannot reach `.navshell` itself, because a style query resolves
|
|
49
|
+
against an ancestor container and never the declaring element. */
|
|
50
|
+
gap: var(--navshell-stack-gap, 0.75rem);
|
|
51
|
+
|
|
52
|
+
/* Resolved once here, read as `--_navshell-size` below, so the fallback chain
|
|
53
|
+
is stated in one place instead of eight. `--width-nav` is the design
|
|
54
|
+
system's own token (layout.css, beside --width-measure/-breakout/-spotlight);
|
|
55
|
+
the literal is only a last resort for navshell.css used without it. */
|
|
56
|
+
--_navshell-size: var(--navshell-size, var(--width-nav, 16rem));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ── Promotion thresholds. Four blocks, but each is two lines: they only raise a
|
|
60
|
+
FLAG. The desktop ruleset itself is written once, below. (Contrast
|
|
61
|
+
patterns/sitenav.css, which repeats a ~60-line block per breakpoint and whose
|
|
62
|
+
own header says "CSS has no mixins — edit them together".)
|
|
63
|
+
|
|
64
|
+
`minmax(0, 1fr)` for the content column, never a bare `1fr`: a `1fr` track's
|
|
65
|
+
automatic minimum is min-content, so one wide <pre> pushes the grid past the
|
|
66
|
+
viewport. That is the bug this pattern was written to end.
|
|
67
|
+
|
|
68
|
+
`--navshell-size` carries an inline fallback rather than being registered with
|
|
69
|
+
`@property { inherits: false }`, which is what this wanted. A registered
|
|
70
|
+
property's `initial-value` must be computationally independent, and `16rem`
|
|
71
|
+
depends on the root font-size — so Chrome rejects the whole rule and the
|
|
72
|
+
variable resolves to nothing, which takes `--_navshell-cols` and then
|
|
73
|
+
`grid-template-columns` down with it (measured: the shell silently fell back
|
|
74
|
+
to auto columns). `0`/`0%` initial values, like the two registrations in
|
|
75
|
+
animation.css, are fine; lengths in rem are not.
|
|
76
|
+
|
|
77
|
+
The cost is that `--navshell-size` INHERITS, so an inner instance adopts an
|
|
78
|
+
outer instance's width unless it sets its own. NavShell.astro always emits it
|
|
79
|
+
for exactly this reason. ── */
|
|
80
|
+
@container (min-width: 30rem) {
|
|
81
|
+
.navshell--bp-sm {
|
|
82
|
+
--_navshell-wide: 1;
|
|
83
|
+
gap: var(--navshell-gap, 3rem);
|
|
84
|
+
--_navshell-cols: var(--_navshell-size) minmax(0, 1fr);
|
|
85
|
+
}
|
|
86
|
+
.navshell--bp-sm.navshell--end {
|
|
87
|
+
--_navshell-cols: minmax(0, 1fr) var(--_navshell-size);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
@container (min-width: 48rem) {
|
|
91
|
+
.navshell--bp-md {
|
|
92
|
+
--_navshell-wide: 1;
|
|
93
|
+
gap: var(--navshell-gap, 3rem);
|
|
94
|
+
--_navshell-cols: var(--_navshell-size) minmax(0, 1fr);
|
|
95
|
+
}
|
|
96
|
+
.navshell--bp-md.navshell--end {
|
|
97
|
+
--_navshell-cols: minmax(0, 1fr) var(--_navshell-size);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
@container (min-width: 64rem) {
|
|
101
|
+
.navshell--bp-lg {
|
|
102
|
+
--_navshell-wide: 1;
|
|
103
|
+
gap: var(--navshell-gap, 3rem);
|
|
104
|
+
--_navshell-cols: var(--_navshell-size) minmax(0, 1fr);
|
|
105
|
+
}
|
|
106
|
+
.navshell--bp-lg.navshell--end {
|
|
107
|
+
--_navshell-cols: minmax(0, 1fr) var(--_navshell-size);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
@container (min-width: 80rem) {
|
|
111
|
+
.navshell--bp-xl {
|
|
112
|
+
--_navshell-wide: 1;
|
|
113
|
+
gap: var(--navshell-gap, 3rem);
|
|
114
|
+
--_navshell-cols: var(--_navshell-size) minmax(0, 1fr);
|
|
115
|
+
}
|
|
116
|
+
.navshell--bp-xl.navshell--end {
|
|
117
|
+
--_navshell-cols: minmax(0, 1fr) var(--_navshell-size);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* ── Mobile chrome ────────────────────────────────────────────────────────── */
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The in-shell toggle row.
|
|
125
|
+
*
|
|
126
|
+
* Sticky by default, but BOTH knobs are variables, because two nested instances
|
|
127
|
+
* both sticking to `--top-offset` land exactly on top of each other — which is
|
|
128
|
+
* what happens on a docs page with a site nav and an on-this-page nav. Three
|
|
129
|
+
* ways out, in order of preference:
|
|
130
|
+
*
|
|
131
|
+
* 1. Put the outer toggle in the site header instead (`.navshell-toggle`
|
|
132
|
+
* below), leaving one in-flow bar and no conflict. This is the Starlight
|
|
133
|
+
* arrangement and the reason the standalone toggle exists.
|
|
134
|
+
* 2. Stack them: `--navshell-bar-offset: calc(var(--top-offset) + 2.5rem)` on
|
|
135
|
+
* the inner instance.
|
|
136
|
+
* 3. Opt out: `--navshell-bar-position: static`.
|
|
137
|
+
*/
|
|
138
|
+
.navshell__bar {
|
|
139
|
+
position: var(--navshell-bar-position, sticky);
|
|
140
|
+
inset-block-start: var(--navshell-bar-offset, var(--top-offset, 0px));
|
|
141
|
+
z-index: var(--navshell-bar-z, var(--z-tier-sticky));
|
|
142
|
+
display: flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
gap: var(--navshell-bar-gap, 0.5rem);
|
|
145
|
+
background: var(--navshell-bar-background, none);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.navshell-toggle,
|
|
149
|
+
.navshell__toggle,
|
|
150
|
+
.navshell__close {
|
|
151
|
+
display: inline-flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: center;
|
|
154
|
+
gap: 0.5rem;
|
|
155
|
+
padding: 0.5rem;
|
|
156
|
+
background: transparent;
|
|
157
|
+
border: none;
|
|
158
|
+
color: inherit;
|
|
159
|
+
font: inherit;
|
|
160
|
+
cursor: pointer;
|
|
161
|
+
border-radius: var(--br-control, 0.375rem);
|
|
162
|
+
|
|
163
|
+
&:hover {
|
|
164
|
+
background: var(--color-bg-surface-muted);
|
|
165
|
+
}
|
|
166
|
+
&:focus-visible {
|
|
167
|
+
outline: 2px solid var(--navshell-focus-color, var(--color-border-focus));
|
|
168
|
+
outline-offset: 2px;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.navshell__close {
|
|
173
|
+
position: absolute;
|
|
174
|
+
inset-block-start: 0.75rem;
|
|
175
|
+
inset-inline-end: 0.75rem;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A toggle that lives OUTSIDE the shell — in a site header, a navbar, anywhere.
|
|
180
|
+
* `popovertarget` is an id reference, so the HTML works from any position; what
|
|
181
|
+
* it can't inherit is the shell's own "am I wide?" flag, because a style query
|
|
182
|
+
* resolves against an ancestor container and the header is not inside
|
|
183
|
+
* `.navshell`. So it carries its own breakpoint, and the two must agree:
|
|
184
|
+
* `.navshell--bp-md` pairs with `.navshell-toggle--bp-md`.
|
|
185
|
+
*
|
|
186
|
+
* Four two-line blocks rather than one, for the same reason the promotion
|
|
187
|
+
* thresholds are four: the threshold is the one thing that genuinely differs.
|
|
188
|
+
*/
|
|
189
|
+
@container (min-width: 30rem) {
|
|
190
|
+
.navshell-toggle--bp-sm {
|
|
191
|
+
display: none;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
@container (min-width: 48rem) {
|
|
195
|
+
.navshell-toggle--bp-md {
|
|
196
|
+
display: none;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
@container (min-width: 64rem) {
|
|
200
|
+
.navshell-toggle--bp-lg {
|
|
201
|
+
display: none;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
@container (min-width: 80rem) {
|
|
205
|
+
.navshell-toggle--bp-xl {
|
|
206
|
+
display: none;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* The panel. Pair with `.drawer` + an edge modifier in markup; everything about
|
|
212
|
+
* how it slides in and dims the page behind is theirs.
|
|
213
|
+
*
|
|
214
|
+
* What IS here is only what a drawer doesn't already know. Size COMPOSES via the
|
|
215
|
+
* drawer's own knob rather than re-declaring `inline-size`: `.drawer` states it
|
|
216
|
+
* under `&, &.drawer--left`, which is (0,2,0) once the edge modifier is on the
|
|
217
|
+
* element, so a (0,1,0) `.navshell__panel { inline-size: … }` silently lost and
|
|
218
|
+
* the panel came out at the drawer's 280px default.
|
|
219
|
+
*
|
|
220
|
+
* The scrolling half IS the "mobile menu doesn't fill the viewport" bug: the
|
|
221
|
+
* hand-rolled version this replaces was `position: absolute; inset-inline: 0`
|
|
222
|
+
* with no block-size, no overflow, no overscroll containment and no stacking — a
|
|
223
|
+
* strip of links pinned under the header that scrolled the article behind it.
|
|
224
|
+
* The drawer supplies the full-height box; these two make it usable.
|
|
225
|
+
*
|
|
226
|
+
* `overscroll-behavior: contain` rather than a scroll lock: the panel is in the
|
|
227
|
+
* top layer so stacking is already correct, and what actually went wrong was
|
|
228
|
+
* scroll CHAINING. A real scroll lock needs `showModal()` or JS, and this is a
|
|
229
|
+
* no-JS pattern.
|
|
230
|
+
*/
|
|
231
|
+
.navshell__panel {
|
|
232
|
+
--drawer-max-inline-size: var(--navshell-drawer-size, 20rem);
|
|
233
|
+
|
|
234
|
+
overflow-y: auto;
|
|
235
|
+
overscroll-behavior: contain;
|
|
236
|
+
padding: var(--navshell-panel-padding, 1.5rem);
|
|
237
|
+
/* Clearance for the absolutely-positioned close button. */
|
|
238
|
+
padding-block-start: 3.5rem;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.navshell__main {
|
|
242
|
+
/* Flex/grid items floor at min-content; without this the content column is
|
|
243
|
+
held open by its widest <pre> instead of scrolling it. */
|
|
244
|
+
min-inline-size: 0;
|
|
245
|
+
|
|
246
|
+
/* What makes NESTING measure the right thing.
|
|
247
|
+
The promotion thresholds are unnamed `@container (min-width: …)` queries, so
|
|
248
|
+
they resolve against the nearest ancestor with a `container-type` — which,
|
|
249
|
+
for everything in this framework, is `body`. A shell nested inside another
|
|
250
|
+
shell's content column would therefore promote on the VIEWPORT's width while
|
|
251
|
+
sitting in a fraction of it, and go two-column inside a 460px column (seen
|
|
252
|
+
on the Patterns page demo).
|
|
253
|
+
Declaring the content column a container gives an inner shell its parent's
|
|
254
|
+
actual width to measure. It also means ordinary responsive utilities inside
|
|
255
|
+
the column resolve against the column, which is what an unnamed container
|
|
256
|
+
query is supposed to mean. `@container body (…)` queries are unaffected —
|
|
257
|
+
they name their container. */
|
|
258
|
+
container-type: inline-size;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* ── The nav itself ───────────────────────────────────────────────────────── */
|
|
262
|
+
|
|
263
|
+
.navshell__nav {
|
|
264
|
+
display: flex;
|
|
265
|
+
flex-direction: column;
|
|
266
|
+
gap: 0.25rem;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.navshell__link {
|
|
270
|
+
display: block;
|
|
271
|
+
padding: 0.375rem 0.75rem;
|
|
272
|
+
border-radius: var(--br-control, 0.375rem);
|
|
273
|
+
text-decoration: none;
|
|
274
|
+
color: inherit;
|
|
275
|
+
|
|
276
|
+
&:hover {
|
|
277
|
+
background: var(--color-bg-surface-muted);
|
|
278
|
+
}
|
|
279
|
+
&:focus-visible {
|
|
280
|
+
outline: 2px solid var(--navshell-focus-color, var(--color-border-focus));
|
|
281
|
+
outline-offset: 2px;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* Nesting depth for a table-of-contents nav, from `data-depth` rather than an
|
|
286
|
+
inline style on every item. */
|
|
287
|
+
.navshell__link[data-depth='2'] {
|
|
288
|
+
padding-inline-start: 1.75rem;
|
|
289
|
+
}
|
|
290
|
+
.navshell__link[data-depth='3'] {
|
|
291
|
+
padding-inline-start: 2.75rem;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Current item. TWO rules, deliberately not one selector list: `:target-current`
|
|
296
|
+
* is unknown to engines that haven't shipped `scroll-target-group`, and one
|
|
297
|
+
* unknown selector invalidates the WHOLE list — the `[aria-current]` half, which
|
|
298
|
+
* every engine understands, would go down with it.
|
|
299
|
+
*/
|
|
300
|
+
.navshell__link[aria-current] {
|
|
301
|
+
font-weight: 600;
|
|
302
|
+
color: var(--navshell-current-color, var(--color-text-brand-primary));
|
|
303
|
+
}
|
|
304
|
+
.navshell__link:target-current {
|
|
305
|
+
font-weight: 600;
|
|
306
|
+
color: var(--navshell-current-color, var(--color-text-brand-primary));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* ── Desktop. ONE block, because the thresholds above only set a flag.
|
|
310
|
+
*
|
|
311
|
+
* Two consequences worth stating:
|
|
312
|
+
*
|
|
313
|
+
* · `.navshell` itself is unreachable from here — a style query resolves against
|
|
314
|
+
* an ANCESTOR container, never the declaring element. That is why the root's
|
|
315
|
+
* own columns come from `--_navshell-cols` above and are restated nowhere.
|
|
316
|
+
* · Scoping is automatic, and it is what makes nesting work. A nested instance's
|
|
317
|
+
* panel resolves this query against the INNER root (its nearest ancestor
|
|
318
|
+
* container), which re-declared `--_navshell-wide: 0`. So an outer nav at `md`
|
|
319
|
+
* and an inner nav at `lg` promote independently, with no `>` combinators and
|
|
320
|
+
* no `.navshell--bp-*` prefix on every inner selector.
|
|
321
|
+
* ── */
|
|
322
|
+
@container style(--_navshell-wide: 1) {
|
|
323
|
+
.navshell__bar,
|
|
324
|
+
.navshell__close {
|
|
325
|
+
display: none;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/* `.navshell__panel.drawer`, not `.navshell__panel`.
|
|
329
|
+
The drawer states its box under `&, &.drawer--left`, which is (0,2,0) once
|
|
330
|
+
the edge modifier is on the element — so a (0,1,0) selector here lost every
|
|
331
|
+
conflicting declaration and the panel kept its DRAWER geometry at desktop:
|
|
332
|
+
320px wide inside a 224px column (a 48px overlap into the content, visible
|
|
333
|
+
as the panel's scrollbar sitting inside the prose) and `block-size: 100dvh`
|
|
334
|
+
instead of `auto`. This compound is (0,2,0) and wins on source order, since
|
|
335
|
+
navshell.css imports after drawer.css. */
|
|
336
|
+
.navshell__panel.drawer {
|
|
337
|
+
/* `[popover]` is UA `display: none` while closed, and the polyfill agrees.
|
|
338
|
+
`!important` for the same reason patterns/sitenav.css needs it: at this
|
|
339
|
+
width the toggle is gone, so nothing can ever re-hide the panel. */
|
|
340
|
+
display: block !important;
|
|
341
|
+
|
|
342
|
+
position: sticky;
|
|
343
|
+
inset-block-start: var(--_navshell-stick, calc(var(--top-offset, 0px) + 1rem));
|
|
344
|
+
inset-inline: auto;
|
|
345
|
+
inline-size: auto;
|
|
346
|
+
max-inline-size: none;
|
|
347
|
+
block-size: auto;
|
|
348
|
+
max-block-size: calc(
|
|
349
|
+
100dvb - var(--_navshell-stick, calc(var(--top-offset, 0px) + 1rem)) - 1rem
|
|
350
|
+
);
|
|
351
|
+
padding: 0;
|
|
352
|
+
overscroll-behavior: auto;
|
|
353
|
+
|
|
354
|
+
/* Undo the drawer's panel surface — at this width it is part of the page,
|
|
355
|
+
not something floating over it. */
|
|
356
|
+
background: none;
|
|
357
|
+
color: inherit;
|
|
358
|
+
border: none;
|
|
359
|
+
box-shadow: none;
|
|
360
|
+
z-index: auto;
|
|
361
|
+
translate: none;
|
|
362
|
+
opacity: 1;
|
|
363
|
+
|
|
364
|
+
grid-column: 1;
|
|
365
|
+
grid-row: 1;
|
|
366
|
+
}
|
|
367
|
+
.navshell__panel::backdrop {
|
|
368
|
+
display: none;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.navshell__main {
|
|
372
|
+
grid-column: 2;
|
|
373
|
+
grid-row: 1;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/* The only rules that need to know which side they're on. */
|
|
377
|
+
.navshell--end > .navshell__panel {
|
|
378
|
+
grid-column: 2;
|
|
379
|
+
}
|
|
380
|
+
.navshell--end > .navshell__main {
|
|
381
|
+
grid-column: 1;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
@@ -28,22 +28,70 @@
|
|
|
28
28
|
inset: auto;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Open/closed behaviour, at real specificity so a component's own rules can't
|
|
33
|
+
* accidentally reveal a closed popover.
|
|
34
|
+
*
|
|
35
|
+
* This block used to also carry `&:popover-open { opacity: 1 }` and an
|
|
36
|
+
* `@starting-style { opacity: 0 }`. Both are gone, and must not come back:
|
|
37
|
+
* nothing here declared a `transition`, so they never animated anything on their
|
|
38
|
+
* own — but `[popover]:popover-open` is (0,1,0) and this partial is imported
|
|
39
|
+
* AFTER animation.css, so that rule outranked `.transition`'s
|
|
40
|
+
* `opacity: var(--t-opacity, …)` at equal specificity and pinned every top-layer
|
|
41
|
+
* fade to 1. The `open-<fx>` driver cannot work while it exists.
|
|
42
|
+
*/
|
|
31
43
|
[popover] {
|
|
32
|
-
&:popover-open {
|
|
33
|
-
opacity: 1;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
44
|
&:not(:popover-open):not([open]) {
|
|
37
45
|
display: none;
|
|
38
46
|
}
|
|
47
|
+
}
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
/**
|
|
50
|
+
* The scrim — one definition for every top-layer element.
|
|
51
|
+
*
|
|
52
|
+
* This used to be restated in seven partials (dialog, drawer, dropdown,
|
|
53
|
+
* lightbox, nav, sitenav, split-link — 18 `::backdrop` blocks between them),
|
|
54
|
+
* each inventing its own colour, blur and transition. They are now one rule with
|
|
55
|
+
* two knobs.
|
|
56
|
+
*
|
|
57
|
+
* `:where()` for the same reason the visual reset above uses it: this partial is
|
|
58
|
+
* imported after drawer.css and dialog.css, so at plain specificity it would
|
|
59
|
+
* beat their own `::backdrop` rules. At zero specificity any pattern still wins.
|
|
60
|
+
*
|
|
61
|
+
* `overlay`/`display` transition with `allow-discrete` so the scrim fades OUT
|
|
62
|
+
* too — without them the backdrop vanishes the instant the popover closes while
|
|
63
|
+
* the panel is still animating away.
|
|
64
|
+
*/
|
|
65
|
+
:where([popover], dialog)::backdrop {
|
|
66
|
+
background-color: var(--scrim, rgb(0 0 0 / 25%));
|
|
67
|
+
backdrop-filter: var(--scrim-filter, none);
|
|
68
|
+
transition:
|
|
69
|
+
background-color var(--scrim-duration, 0.3s),
|
|
70
|
+
overlay var(--scrim-duration, 0.3s) allow-discrete,
|
|
71
|
+
display var(--scrim-duration, 0.3s) allow-discrete;
|
|
72
|
+
}
|
|
73
|
+
:where([popover], dialog):not(:popover-open):not([open])::backdrop {
|
|
74
|
+
background-color: transparent;
|
|
75
|
+
}
|
|
76
|
+
@starting-style {
|
|
77
|
+
:where([popover], dialog):is(:popover-open, [open])::backdrop {
|
|
78
|
+
background-color: transparent;
|
|
44
79
|
}
|
|
45
80
|
}
|
|
46
81
|
|
|
82
|
+
/**
|
|
83
|
+
* No scrim — a panel you work *alongside* rather than through, where the page
|
|
84
|
+
* behind must stay legible (a live editor, an inspector). Pair with
|
|
85
|
+
* `popover="manual"`: an `auto` popover light-dismisses on the first outside
|
|
86
|
+
* click, which is exactly the interaction a modeless panel exists to allow.
|
|
87
|
+
* `.drawer--modeless` is the historical name and stays as an alias.
|
|
88
|
+
*/
|
|
89
|
+
.no-scrim::backdrop,
|
|
90
|
+
.drawer--modeless::backdrop {
|
|
91
|
+
background-color: transparent;
|
|
92
|
+
backdrop-filter: none;
|
|
93
|
+
}
|
|
94
|
+
|
|
47
95
|
.popover-anchor {
|
|
48
96
|
anchor-name: --popover-anchor;
|
|
49
97
|
position: relative;
|
|
@@ -14,8 +14,15 @@
|
|
|
14
14
|
color: var(--scroll-target-inactive-color, currentColor);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/* `.is-current`
|
|
18
|
-
|
|
17
|
+
/* `.is-current` is a MANUAL hook, mirroring `:target-current` for anything that
|
|
18
|
+
sets it itself.
|
|
19
|
+
|
|
20
|
+
It previously claimed to be "the JS scroll-spy fallback (deferred.ts)". There
|
|
21
|
+
is no such code — nothing in the repo sets `.is-current`, and deferred.ts has
|
|
22
|
+
no scroll-spy. Highlighting is therefore `:target-current` only, which today
|
|
23
|
+
means Chrome; other engines get no highlight until they ship
|
|
24
|
+
`scroll-target-group`, which is a deliberate choice, not an oversight. Set
|
|
25
|
+
`.is-current` yourself if you need it sooner. */
|
|
19
26
|
.scroll-target-group a:target-current,
|
|
20
27
|
.scroll-target-group a.is-current {
|
|
21
28
|
color: var(--scroll-target-active-color, var(--color-bg-brand-primary-solid));
|
|
@@ -67,12 +74,19 @@
|
|
|
67
74
|
}
|
|
68
75
|
}
|
|
69
76
|
|
|
77
|
+
/* Superseded by `.navshell` (patterns/navshell.css), which is this plus a mobile
|
|
78
|
+
toggle, a parametric breakpoint, an inline-end variant and the ability to
|
|
79
|
+
nest. Kept because it ships in a published major; prefer `.navshell` for new
|
|
80
|
+
work. */
|
|
70
81
|
.toc-layout {
|
|
71
82
|
display: grid;
|
|
72
|
-
grid-template-columns: 1fr;
|
|
83
|
+
grid-template-columns: minmax(0, 1fr);
|
|
73
84
|
|
|
74
85
|
@container body (inline-size >= 64rem) {
|
|
75
|
-
|
|
86
|
+
/* minmax(0, 1fr), never a bare `1fr`: a `1fr` track's automatic minimum is
|
|
87
|
+
min-content, so one wide <pre> or long token in the content column blows
|
|
88
|
+
the grid out and the page scrolls sideways. */
|
|
89
|
+
grid-template-columns: 16rem minmax(0, 1fr);
|
|
76
90
|
gap: var(--gutter, 2rem);
|
|
77
91
|
}
|
|
78
92
|
}
|