@getvitops/generator 3.0.0 → 4.1.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 +385 -0
- package/assets/bricks/elements/color-scheme-toggle.php +3 -3
- package/assets/bricks/elements/multi-field.php +3 -3
- package/assets/css/patterns/consent.css +14 -3
- package/assets/css/patterns/sitenav.css +145 -79
- package/assets/css/patterns/tree.css +118 -8
- package/assets/js/consent.js +1 -1
- package/assets/js/elements.js +25 -25
- package/config.schema.json +178 -11
- package/dist/index.d.mts +491 -13
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1680 -46
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -17,10 +17,32 @@
|
|
|
17
17
|
* OR click (native `[open]` pins it). Top-level submenus drop below their item;
|
|
18
18
|
* deeper (megamenu) submenus fly out to the inline-end side.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* the
|
|
23
|
-
*
|
|
20
|
+
* The `<details>` is grid-placed at column 2 and the submenu `<ul>` is its SIBLING,
|
|
21
|
+
* a real grid child of the branch item — that is what lets the caret sit inline with
|
|
22
|
+
* the link while the submenu spans full width on its own row.
|
|
23
|
+
*
|
|
24
|
+
* ── TWO BRANCHES, NOT BASE-PLUS-OVERRIDE ──
|
|
25
|
+
*
|
|
26
|
+
* `@container` contributes ZERO specificity, so a rule inside the wide block competes
|
|
27
|
+
* at its bare selector weight. A bare `.sitenav--drawer-end .sitenav__panel` (0,2,0)
|
|
28
|
+
* therefore beat the wide block's `.sitenav__panel` (0,1,0) reset *in the wide state*:
|
|
29
|
+
* the promoted navbar shipped translated a full panel-width off-screen, and the
|
|
30
|
+
* accordion's `overflow: hidden` clipped away every third-level megamenu. Before the
|
|
31
|
+
* four per-breakpoint blocks were folded into one style query, those resets carried a
|
|
32
|
+
* `.sitenav--bp-*` class and won the tie on source order; folding them removed it.
|
|
33
|
+
*
|
|
34
|
+
* So the rule is: **a narrow-state rule that is MORE SPECIFIC than its wide-state
|
|
35
|
+
* counterpart lives inside `@container style(--_sitenav-wide: 0)`.** Rules at (0,1,0)
|
|
36
|
+
* — the panel's box, the lists, the links — stay unscoped, because that same work is
|
|
37
|
+
* what neutralises the UA `[popover]` sheet, which applies in BOTH states; scoping it
|
|
38
|
+
* would mean writing it twice. `src/css/state-branch.test.ts` asserts the invariant.
|
|
39
|
+
*
|
|
40
|
+
* Both branches read an INHERITED flag, so every part must live inside `.sitenav`,
|
|
41
|
+
* which declares it. Note the file mixes two unnamed query kinds that resolve against
|
|
42
|
+
* DIFFERENT containers: `style()` against the nearest ancestor ELEMENT (every element
|
|
43
|
+
* is a style container — no `container-type` needed, and it resolves for a panel
|
|
44
|
+
* promoted to the top layer), the `(min-width:)` queries below against `body`
|
|
45
|
+
* (layout.css). That asymmetry is why the flag has to be a custom property.
|
|
24
46
|
*
|
|
25
47
|
* Per-breakpoint depth caps come pre-resolved from PHP as item classes:
|
|
26
48
|
* `.sitenav__item--desktop-branch` — caret + submenu shown only ≥ breakpoint;
|
|
@@ -75,6 +97,19 @@
|
|
|
75
97
|
inset-block: 0;
|
|
76
98
|
inline-size: min(100dvw, var(--sitenav-drawer-size, 20rem));
|
|
77
99
|
max-inline-size: 100dvw;
|
|
100
|
+
|
|
101
|
+
/* The UA `[popover]` sheet supplies `margin: auto` and `height: fit-content`, and
|
|
102
|
+
neither was being undone — so `inset-block: 0` bought nothing and the "drawer"
|
|
103
|
+
rendered as a content-height card floating in the vertical centre, while at
|
|
104
|
+
width the auto margins absorbed the free space of any stretched `.sitenav`.
|
|
105
|
+
`drawer.css` resets margin for exactly this reason; this panel doesn't compose
|
|
106
|
+
it. Both live in the base block because the UA sheet applies in BOTH states:
|
|
107
|
+
against `position: fixed` + `inset-block: 0` an auto block-size stretches to
|
|
108
|
+
the drawer's full height, and against the wide branch's `position: static` the
|
|
109
|
+
same declaration sizes the navbar to its content. */
|
|
110
|
+
margin: 0;
|
|
111
|
+
block-size: auto;
|
|
112
|
+
|
|
78
113
|
padding: 1.5rem;
|
|
79
114
|
padding-block-start: 3.5rem; /* clearance for the close button */
|
|
80
115
|
background: var(--color-bg-surface);
|
|
@@ -106,30 +141,42 @@
|
|
|
106
141
|
}
|
|
107
142
|
}
|
|
108
143
|
|
|
109
|
-
/*
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
translate: 0 0;
|
|
123
|
-
}
|
|
124
|
-
@starting-style {
|
|
125
|
-
.sitenav--drawer-end .sitenav__panel:popover-open {
|
|
126
|
-
opacity: 0;
|
|
144
|
+
/* ── Drawer geometry + transition — NARROW ONLY ─────────────────────────────
|
|
145
|
+
Scoped rather than bare because these are (0,2,0)/(0,3,0) and would outrank the
|
|
146
|
+
wide block's (0,1,0) panel reset. `:popover-open` and the `@starting-style`
|
|
147
|
+
pair are one transition system with the edge modifiers, so they travel with
|
|
148
|
+
them: both are inert at width only by coincidence (the panel is always
|
|
149
|
+
displayed there, and their values happen to match the reset's), which is the
|
|
150
|
+
same shape of accident as the bug itself. ── */
|
|
151
|
+
@container style(--_sitenav-wide: 0) {
|
|
152
|
+
/* Slide from the chosen edge (default inline-end). The insets also undo the UA
|
|
153
|
+
`[popover] { inset: 0 }`; the wide branch does that job with `inset: auto`. */
|
|
154
|
+
.sitenav--drawer-end .sitenav__panel {
|
|
155
|
+
inset-inline-end: 0;
|
|
156
|
+
inset-inline-start: auto;
|
|
127
157
|
translate: 100% 0;
|
|
128
158
|
}
|
|
129
|
-
.sitenav--drawer-start .sitenav__panel
|
|
130
|
-
|
|
159
|
+
.sitenav--drawer-start .sitenav__panel {
|
|
160
|
+
inset-inline-start: 0;
|
|
161
|
+
inset-inline-end: auto;
|
|
131
162
|
translate: -100% 0;
|
|
132
163
|
}
|
|
164
|
+
|
|
165
|
+
.sitenav__panel:popover-open {
|
|
166
|
+
opacity: 1;
|
|
167
|
+
translate: 0 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@starting-style {
|
|
171
|
+
.sitenav--drawer-end .sitenav__panel:popover-open {
|
|
172
|
+
opacity: 0;
|
|
173
|
+
translate: 100% 0;
|
|
174
|
+
}
|
|
175
|
+
.sitenav--drawer-start .sitenav__panel:popover-open {
|
|
176
|
+
opacity: 0;
|
|
177
|
+
translate: -100% 0;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
133
180
|
}
|
|
134
181
|
|
|
135
182
|
/* ── Lists + links ─────────────────────────────────────────────────────────── */
|
|
@@ -167,31 +214,7 @@
|
|
|
167
214
|
font-style: italic;
|
|
168
215
|
}
|
|
169
216
|
|
|
170
|
-
/* ── Branch item —
|
|
171
|
-
The item is a grid: [link | caret] on row 1, the submenu spanning row 2. The
|
|
172
|
-
<details> holds only the caret <summary>; the submenu <ul> is its sibling and a
|
|
173
|
-
real grid child of the item. The row-2 track animates 0fr→1fr when the details is
|
|
174
|
-
open (the classic no-JS accordion, driven by `:has`), so the submenu pushes the
|
|
175
|
-
content below rather than overlaying it. */
|
|
176
|
-
.sitenav__item--branch {
|
|
177
|
-
display: grid;
|
|
178
|
-
grid-template-columns: 1fr auto;
|
|
179
|
-
grid-template-rows: auto 0fr;
|
|
180
|
-
align-items: center;
|
|
181
|
-
column-gap: 0.5rem;
|
|
182
|
-
transition: grid-template-rows 0.25s ease;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
.sitenav__item--branch > .split-link__link {
|
|
186
|
-
grid-column: 1;
|
|
187
|
-
grid-row: 1;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/* <details> is only the caret; keep its box out of the flow's height. */
|
|
191
|
-
.sitenav__disclosure {
|
|
192
|
-
grid-column: 2;
|
|
193
|
-
grid-row: 1;
|
|
194
|
-
}
|
|
217
|
+
/* ── Branch item — the two rules both presentations share ──────────────────── */
|
|
195
218
|
|
|
196
219
|
/* The <summary>. `.split-link__toggle` supplies the flush look, hover + focus, and
|
|
197
220
|
the caret transition; only the disclosure-marker reset is added here. */
|
|
@@ -204,31 +227,68 @@
|
|
|
204
227
|
}
|
|
205
228
|
}
|
|
206
229
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
/* Stretch to the row-2 track (not content-sized) so the 0fr collapsed state
|
|
211
|
-
actually clips to 0 — the item's own align-self must beat the grid's
|
|
212
|
-
`align-items: center`, or overflow:hidden has nothing to clip against. */
|
|
213
|
-
align-self: stretch;
|
|
214
|
-
min-block-size: 0;
|
|
215
|
-
overflow: hidden;
|
|
216
|
-
padding-inline-start: 1rem;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.sitenav__item--branch:has(> .sitenav__disclosure[open]) {
|
|
220
|
-
grid-template-rows: auto 1fr;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/* Caret flips while the disclosure is open (summary carries no aria-expanded). */
|
|
230
|
+
/* Caret flips while the disclosure is open (summary carries no aria-expanded).
|
|
231
|
+
Unscoped: at width the same native `[open]` pins a dropdown, so the flip is
|
|
232
|
+
wanted in both states. */
|
|
224
233
|
.sitenav__disclosure[open] > .sitenav__subtoggle .split-link__caret {
|
|
225
234
|
rotate: 180deg;
|
|
226
235
|
}
|
|
227
236
|
|
|
228
|
-
/*
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
/* ── Mobile accordion — NARROW ONLY ─────────────────────────────────────────
|
|
238
|
+
The item is a grid: [link | caret] on row 1, the submenu spanning row 2. The
|
|
239
|
+
<details> holds only the caret <summary>; the submenu <ul> is its sibling and a
|
|
240
|
+
real grid child of the item. The row-2 track animates 0fr→1fr when the details is
|
|
241
|
+
open (the classic no-JS accordion, driven by `:has`), so the submenu pushes the
|
|
242
|
+
content below rather than overlaying it.
|
|
243
|
+
|
|
244
|
+
Scoped because these selectors are (0,2,0)/(0,3,0). Most of what is in here is
|
|
245
|
+
inert at width anyway — grid placement on a flex item, `align-self` on an
|
|
246
|
+
absolutely positioned box, `min-block-size: 0` where `auto` already computes to
|
|
247
|
+
0 — but `overflow: hidden` and `padding-inline-start` are NOT, and leaking them
|
|
248
|
+
into the navbar is what clipped the megamenus. ── */
|
|
249
|
+
@container style(--_sitenav-wide: 0) {
|
|
250
|
+
.sitenav__item--branch {
|
|
251
|
+
display: grid;
|
|
252
|
+
grid-template-columns: 1fr auto;
|
|
253
|
+
grid-template-rows: auto 0fr;
|
|
254
|
+
align-items: center;
|
|
255
|
+
column-gap: 0.5rem;
|
|
256
|
+
transition: grid-template-rows 0.25s ease;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.sitenav__item--branch > .split-link__link {
|
|
260
|
+
grid-column: 1;
|
|
261
|
+
grid-row: 1;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* <details> is only the caret; keep its box out of the flow's height. */
|
|
265
|
+
.sitenav__disclosure {
|
|
266
|
+
grid-column: 2;
|
|
267
|
+
grid-row: 1;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.sitenav__item--branch > .sitenav__submenu {
|
|
271
|
+
grid-column: 1 / -1;
|
|
272
|
+
grid-row: 2;
|
|
273
|
+
/* Stretch to the row-2 track (not content-sized) so the 0fr collapsed state
|
|
274
|
+
actually clips to 0 — the item's own align-self must beat the grid's
|
|
275
|
+
`align-items: center`, or overflow:hidden has nothing to clip against. */
|
|
276
|
+
align-self: stretch;
|
|
277
|
+
min-block-size: 0;
|
|
278
|
+
overflow: hidden;
|
|
279
|
+
padding-inline-start: 1rem;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.sitenav__item--branch:has(> .sitenav__disclosure[open]) {
|
|
283
|
+
grid-template-rows: auto 1fr;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Depth cap (mobile side): a desktop-only branch shows just its parent link.
|
|
287
|
+
Scoped, so the wide branch needs no counter-rule — it simply stops applying. */
|
|
288
|
+
.sitenav__item--desktop-branch > .sitenav__disclosure,
|
|
289
|
+
.sitenav__item--desktop-branch > .sitenav__submenu {
|
|
290
|
+
display: none;
|
|
291
|
+
}
|
|
232
292
|
}
|
|
233
293
|
/* ── Desktop promotion.
|
|
234
294
|
*
|
|
@@ -310,8 +370,9 @@
|
|
|
310
370
|
position: relative;
|
|
311
371
|
display: flex;
|
|
312
372
|
align-items: center;
|
|
313
|
-
|
|
314
|
-
|
|
373
|
+
/* Restated, not inherited: this used to leak in from the accordion rule, which
|
|
374
|
+
is now narrow-scoped. Without it the caret hugs the link at width. */
|
|
375
|
+
column-gap: 0.5rem;
|
|
315
376
|
}
|
|
316
377
|
.sitenav__submenu {
|
|
317
378
|
position: absolute;
|
|
@@ -319,7 +380,6 @@
|
|
|
319
380
|
inset-inline-start: 0;
|
|
320
381
|
min-inline-size: 13rem;
|
|
321
382
|
padding: 0.5rem;
|
|
322
|
-
overflow: visible;
|
|
323
383
|
background: var(--color-bg-surface);
|
|
324
384
|
color: var(--color-text-surface);
|
|
325
385
|
border: var(--b-panel);
|
|
@@ -335,6 +395,12 @@
|
|
|
335
395
|
translate 0.15s ease,
|
|
336
396
|
visibility 0.15s allow-discrete;
|
|
337
397
|
}
|
|
398
|
+
/* Third level (megamenu) flies out to the inline-end side. Its containing block
|
|
399
|
+
is the inner `.sitenav__item--branch` (position: relative, above), which sits
|
|
400
|
+
INSIDE the parent submenu — so nothing between the two may clip. The
|
|
401
|
+
accordion's `overflow: hidden` used to leak in here at (0,2,0) and beat this
|
|
402
|
+
branch's (0,1,0) reset, and every megamenu was invisible at width. It is now
|
|
403
|
+
scoped to `style(--_sitenav-wide: 0)` and cannot. */
|
|
338
404
|
.sitenav__submenu .sitenav__item--branch > .sitenav__submenu {
|
|
339
405
|
inset-block-start: 0;
|
|
340
406
|
inset-inline-start: 100%;
|
|
@@ -348,12 +414,12 @@
|
|
|
348
414
|
pointer-events: auto;
|
|
349
415
|
translate: 0 0;
|
|
350
416
|
}
|
|
351
|
-
/*
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
417
|
+
/* Depth cap (desktop side): a mobile-only branch collapses to a plain link. Its
|
|
418
|
+
mirror — hiding a DESKTOP-only branch below the breakpoint — lives in the
|
|
419
|
+
narrow branch, so there is nothing to undo here. A `display: block`
|
|
420
|
+
counter-rule used to sit alongside this one and, at (0,2,0), beat the base
|
|
421
|
+
`.sitenav__submenu`'s `display: flex` (0,1,0) — costing every desktop-only
|
|
422
|
+
dropdown its column direction and gap. */
|
|
357
423
|
.sitenav__item--mobile-branch > .sitenav__disclosure,
|
|
358
424
|
.sitenav__item--mobile-branch > .sitenav__submenu {
|
|
359
425
|
display: none;
|
|
@@ -3,9 +3,38 @@
|
|
|
3
3
|
* Consumes the generated token cascade (src/css/generated/tokens.css).
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
/* An unregistered custom element is `display: inline`, and `<wc-tree>` wraps a
|
|
7
|
+
`<ul>` — a block child in an inline box, which forces an anonymous block and
|
|
8
|
+
leaves the element unable to take sizing or spacing. It must be block whether
|
|
9
|
+
or not `elements.js` ever loads, because the tag is in the SSR'd markup either
|
|
10
|
+
way. (Same gap exists on most other `wc-*` tags; see the note in
|
|
11
|
+
`src/js/elements.ts`.) */
|
|
12
|
+
wc-tree {
|
|
13
|
+
display: block;
|
|
14
|
+
}
|
|
15
|
+
|
|
6
16
|
/* ── Tree — hierarchical view over nested lists / <details> ───────────────── */
|
|
7
17
|
.tree {
|
|
8
18
|
--_p: var(--p-tree, var(--p-tree-group, var(--p-default)));
|
|
19
|
+
/* Resolved once here so the indent and the `--lines` elbow that must align to
|
|
20
|
+
it cannot disagree. Read through `--tree-indent` rather than assigning it, so
|
|
21
|
+
a consumer setting `--tree-indent` on an ancestor still wins — assigning the
|
|
22
|
+
default directly to `--tree-indent` on `.tree` would out-specify the hook and
|
|
23
|
+
silently ignore it. */
|
|
24
|
+
--_indent: var(--tree-indent, clamp(0.75rem, 2.5vw, 1.5rem));
|
|
25
|
+
|
|
26
|
+
/* The toggle column. A branch spends this on its chevron before its label; a
|
|
27
|
+
leaf has no chevron, so without compensation a leaf label sits one whole
|
|
28
|
+
column to the INLINE-START of its branch siblings and nothing at a given
|
|
29
|
+
depth lines up. Measured: 24px of misalignment at every level.
|
|
30
|
+
|
|
31
|
+
Two vars rather than one because they answer different questions —
|
|
32
|
+
`--_node-indent` is how wide the toggle column is, `--_leaf-indent` is what a
|
|
33
|
+
row without a toggle owes to sit in the same label column. Anything that
|
|
34
|
+
needs to align to the label (the description, a future `.tree__actions`
|
|
35
|
+
offset) reads `--_leaf-indent` rather than re-deriving the sum. */
|
|
36
|
+
--_node-indent: var(--tree-icon-size, 1.25rem);
|
|
37
|
+
--_leaf-indent: calc(var(--_node-indent) + var(--tree-gap, 0.25rem));
|
|
9
38
|
|
|
10
39
|
list-style: none;
|
|
11
40
|
margin: 0;
|
|
@@ -15,14 +44,49 @@
|
|
|
15
44
|
position: relative;
|
|
16
45
|
}
|
|
17
46
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
47
|
+
/* Nested list indent. Two shapes are supported: the item may BE the
|
|
48
|
+
`<details>`, or be an `<li>` wrapping one — the latter is what `<Tree />`
|
|
49
|
+
emits, because `<ul>`/`<li>` is what gives assistive tech list position and
|
|
50
|
+
depth. Keep both; the flat shape is the pattern's original contract.
|
|
51
|
+
|
|
52
|
+
Indent is ONE `--tree-indent` per level, not two. This used to set both
|
|
53
|
+
`margin-inline-start` and `padding-inline-start` to it, putting the guide
|
|
54
|
+
border between them and costing 2× per level — 3rem × 10 levels = 480px on
|
|
55
|
+
the config schema, which is wider than a 390px viewport, so the deepest
|
|
56
|
+
fields sat entirely off-screen. The border now hugs the parent's edge and
|
|
57
|
+
the padding alone carries the offset, which looks the same at one level and
|
|
58
|
+
stays on screen at ten.
|
|
59
|
+
|
|
60
|
+
Fluid, because a tree's depth is a property of the DATA and can't be known
|
|
61
|
+
when the pattern is written: `2ch`-ish on a narrow screen, the full step on
|
|
62
|
+
a wide one. Deep trees stay usable on a phone without flattening the
|
|
63
|
+
hierarchy visually on a desktop. */
|
|
64
|
+
.tree__item > .tree,
|
|
65
|
+
.tree__item > details > .tree {
|
|
66
|
+
/* Reset BOTH box axes before re-applying the one indent this level owes.
|
|
67
|
+
Two separate leaks compounded here, each adding ~16px per level and each
|
|
68
|
+
invisible in the CSS:
|
|
69
|
+
|
|
70
|
+
1. `.tree { padding: var(--_p) }` applies to every nested `.tree`, not just
|
|
71
|
+
the outermost, so the container padding was charged once per level — on
|
|
72
|
+
all four sides, narrowing from the end as well.
|
|
73
|
+
2. `patterns/details.css` gives every non-summary child of a `<details>`
|
|
74
|
+
`margin-inline: var(--_content-margin)`. Its selector is
|
|
75
|
+
`details, .details`, which under CSS nesting takes `:is()` specificity
|
|
76
|
+
(0-1-1), so `.tree { margin: 0 }` at 0-1-0 LOSES to it. A nested tree is
|
|
77
|
+
exactly such a child.
|
|
78
|
+
|
|
79
|
+
Measured before this: 41px per level against a 24px design, so a 9-deep
|
|
80
|
+
tree spent 382px on indent and left its deepest label 162px wide. */
|
|
81
|
+
margin-inline: 0;
|
|
82
|
+
padding: 0;
|
|
83
|
+
padding-inline-start: var(--_indent);
|
|
21
84
|
border-inline-start: 1px solid var(--color-bg-surface-muted);
|
|
22
85
|
}
|
|
23
86
|
|
|
24
87
|
.tree__content,
|
|
25
|
-
details.tree__item > summary
|
|
88
|
+
details.tree__item > summary,
|
|
89
|
+
.tree__item > details > summary {
|
|
26
90
|
display: flex;
|
|
27
91
|
align-items: center;
|
|
28
92
|
gap: var(--tree-gap, 0.25rem);
|
|
@@ -31,9 +95,13 @@
|
|
|
31
95
|
|
|
32
96
|
.tree__content {
|
|
33
97
|
cursor: default;
|
|
98
|
+
/* Sit in the same label column as a branch sibling, which spends this much on
|
|
99
|
+
its chevron. Without it a leaf reads as out-dented by one toggle width. */
|
|
100
|
+
padding-inline-start: var(--_leaf-indent);
|
|
34
101
|
}
|
|
35
102
|
|
|
36
|
-
details.tree__item > summary
|
|
103
|
+
details.tree__item > summary,
|
|
104
|
+
.tree__item > details > summary {
|
|
37
105
|
cursor: pointer;
|
|
38
106
|
list-style: none;
|
|
39
107
|
|
|
@@ -59,7 +127,8 @@
|
|
|
59
127
|
transition: transform 0.2s ease;
|
|
60
128
|
}
|
|
61
129
|
|
|
62
|
-
details.tree__item[open] > summary .tree__toggle
|
|
130
|
+
details.tree__item[open] > summary .tree__toggle,
|
|
131
|
+
.tree__item > details[open] > summary .tree__toggle {
|
|
63
132
|
transform: rotate(90deg);
|
|
64
133
|
}
|
|
65
134
|
|
|
@@ -111,10 +180,10 @@
|
|
|
111
180
|
&::before {
|
|
112
181
|
content: '';
|
|
113
182
|
position: absolute;
|
|
114
|
-
inset-inline-start: calc(-1 * var(--
|
|
183
|
+
inset-inline-start: calc(-1 * var(--_indent) + 0.5rem);
|
|
115
184
|
inset-block-start: 0;
|
|
116
185
|
block-size: 1rem;
|
|
117
|
-
inline-size: calc(var(--
|
|
186
|
+
inline-size: calc(var(--_indent) - 0.5rem);
|
|
118
187
|
border-inline-start: 1px solid var(--color-bg-surface-muted);
|
|
119
188
|
border-block-end: 1px solid var(--color-bg-surface-muted);
|
|
120
189
|
}
|
|
@@ -123,4 +192,45 @@
|
|
|
123
192
|
&.tree--lines > .tree__item::before {
|
|
124
193
|
display: none;
|
|
125
194
|
}
|
|
195
|
+
|
|
196
|
+
/* A node's own prose. `.tree__label` is `nowrap` + ellipsis for file-tree-style
|
|
197
|
+
single-line names, so a description can't live in it — it sits below the
|
|
198
|
+
summary row and wraps. Indented to the label, past the toggle. */
|
|
199
|
+
.tree__desc {
|
|
200
|
+
margin-block: 0.125rem 0.25rem;
|
|
201
|
+
margin-inline-start: var(--_leaf-indent);
|
|
202
|
+
color: var(--color-text-surface-muted);
|
|
203
|
+
text-wrap: pretty;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* ── Tree toolbar — generated by <wc-tree>, never authored ─────────────────── */
|
|
208
|
+
/*
|
|
209
|
+
* These controls only exist once the element upgrades, so they are styled but
|
|
210
|
+
* never present in a no-JS render. Kept out of the `.tree` block because the
|
|
211
|
+
* toolbar is a SIBLING of the tree, not a node in it — nesting it there would
|
|
212
|
+
* inherit `.tree`'s padding and the `.tree__item` positioning context.
|
|
213
|
+
*/
|
|
214
|
+
.tree__toolbar {
|
|
215
|
+
align-items: center;
|
|
216
|
+
margin-block-end: var(--p-tree, var(--p-tree-group, var(--p-default)));
|
|
217
|
+
|
|
218
|
+
/* The filter is wrapped in `.input-group` so forms.css styles it; the group is
|
|
219
|
+
what flexes, and the input fills it. */
|
|
220
|
+
.tree__filter-group {
|
|
221
|
+
flex: 1 1 12rem;
|
|
222
|
+
min-inline-size: 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.tree__filter {
|
|
226
|
+
inline-size: 100%;
|
|
227
|
+
min-inline-size: 0;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.tree__count {
|
|
231
|
+
color: var(--color-text-surface-muted);
|
|
232
|
+
/* Hold the row height whether or not a count is showing, so typing into the
|
|
233
|
+
filter doesn't reflow the tree by a line. */
|
|
234
|
+
min-inline-size: 6ch;
|
|
235
|
+
}
|
|
126
236
|
}
|
package/assets/js/consent.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=[`necessary`,`analytics`,`marketing`,`preferences`],t=`vitops_consent`,
|
|
1
|
+
const e=[`necessary`,`analytics`,`marketing`,`preferences`],t=`vitops:consent`,n=`vitops:consent-open`,r=`vitops_consent`,i=[`analytics`,`marketing`,`preferences`];function a(e){return{analytics:e,marketing:e,preferences:e}}function o(){return{ts:null,choices:a(null)}}function s(e,t){for(let n of e.split(`;`)){let e=n.trim();if(e.slice(0,t.length+1)===`${t}=`)return e.slice(t.length+1)}return null}function c(e){if(!e)return o();let t;try{t=JSON.parse(decodeURIComponent(e))}catch{return o()}if(typeof t!=`object`||!t)return o();let n=t;if(n.v!==2||typeof n.c!=`object`||n.c===null)return o();let r=n.c,s=a(null);for(let e of i){let t=r[e];typeof t==`boolean`&&(s[e]=t)}return{ts:typeof n.ts==`number`?n.ts:null,choices:s}}function l(e){let t={};for(let n of i){let r=e.choices[n];typeof r==`boolean`&&(t[n]=r)}return encodeURIComponent(JSON.stringify({v:2,ts:e.ts??0,c:t}))}function u(e,t){return t===`necessary`?!0:e.choices[t]===!0}function d(e,t){return t===`necessary`?!0:e.choices[t]!==null}function f(e,t){for(let n of t)if(!d(e,n))return!0;return!1}function p(e,t){return{ts:t,choices:a(e)}}function m(e,t,n){let r={...e.choices};for(let e of i){let n=t[e];typeof n==`boolean`&&(r[e]=n)}return{ts:n,choices:r}}function h(e,t){return i.filter(n=>u(e,n)&&!u(t,n))}function g(e){return`; path=/; max-age=15552000; SameSite=Lax${e?`; Secure`:``}`}const _=location.protocol===`https:`;let v=c(s(document.cookie,r));const y=new Set,b=new WeakSet,x=new Set,S=new Set,C=new Map;function w(e){S.has(e)||(S.add(e),R())}function T(){for(let[e,t]of C)if(d(v,e)){C.delete(e);for(let n of t)n(u(v,e))}}const E={idle:[],async:[],interaction:[]},D={idle:!1,async:!0,interaction:!1};function O(e){if(D[e])return;D[e]=!0;let t=E[e];E[e]=[];for(let e of t)e()}function k(e,t){D[e]?t():E[e].push(t)}function A(e){document.readyState===`complete`?e():addEventListener(`load`,e,{once:!0})}A(()=>{let e=globalThis.requestIdleCallback;e?e(()=>O(`idle`),{timeout:3e3}):setTimeout(()=>O(`idle`),1)});{let e=[`pointerdown`,`keydown`,`scroll`,`touchstart`],t=()=>{for(let n of e)removeEventListener(n,t);O(`interaction`)};for(let n of e)addEventListener(n,t,{once:!0,passive:!0});A(()=>setTimeout(()=>O(`interaction`),8e3))}const j=new Set([`type`,`src`,`data-vitops-tag`,`data-src`,`data-strategy`,`data-consent`,`data-consent-src`,`data-consent-cookies`]);function M(t){let n=t.getAttribute(`data-consent`);return e.includes(n??``)?n:`analytics`}function N(e){let t=e.textContent??``,n=e.getAttribute(`data-src`),r=t=>{let n=document.createElement(`script`);for(let{name:t,value:r}of Array.from(e.attributes))j.has(t)||n.setAttribute(t,r);t(n),e.parentNode?.insertBefore(n,e.nextSibling)};t.trim()&&r(e=>e.text=t),n&&r(e=>{e.async=!0,e.src=n})}function P(e){if(!b.has(e)){if(b.add(e),x.add(M(e)),e instanceof HTMLScriptElement)N(e);else{let t=e.getAttribute(`data-consent-src`);t&&e.setAttribute(`src`,t)}e.setAttribute(`data-vitops-activated`,``)}}function F(){let e=document.querySelectorAll(`script[data-vitops-tag]:not([data-vitops-activated]),[data-consent-src]:not([data-vitops-activated])`);for(let t of e){let e=t.getAttribute(`data-strategy`);k(e===`async`||e===`interaction`?e:`idle`,()=>{let e=M(t);u(v,e)?P(t):w(e)})}}function I(e){let t=new Set;for(let n of e)for(let e of document.querySelectorAll(`[data-consent="${n}"]`))for(let n of(e.getAttribute(`data-consent-cookies`)??``).split(`,`))n.trim()&&t.add(n.trim());if(!t.size)return;let n=document.cookie.split(`;`).map(e=>e.trim().split(`=`)[0]??``),r=location.hostname.split(`.`).slice(-2).join(`.`),i=[``,`; domain=${location.hostname}`,`; domain=.${r}`];for(let e of n)if([...t].some(t=>t.endsWith(`*`)?e.startsWith(t.slice(0,-1)):e===t))for(let t of i)document.cookie=`${e}=; path=/; max-age=0${t}`}function L(e,t){let n=h(v,e),i=v;v=e,t?document.cookie=`${r}=${l(e)}${g(_)}`:document.cookie=`${r}=; path=/; max-age=0`,R(),F(),n.length&&(I(n),n.some(e=>x.has(e)&&u(i,e))&&z.reloadOnRevoke&&location.reload())}function R(){T();for(let e of y)e(v);document.dispatchEvent(new CustomEvent(t,{detail:v}))}const z={categories:e,reloadOnRevoke:!0,get:()=>v,granted:e=>u(v,e),needed:()=>f(v,S),demanded:()=>e.filter(e=>S.has(e)),require(e){return w(e),u(v,e)},request(e){return w(e),d(v,e)?Promise.resolve(u(v,e)):new Promise(t=>{let n=C.get(e);n?n.push(t):C.set(e,[t])})},set:e=>L(m(v,e,Date.now()),!0),acceptAll:()=>L(p(!0,Date.now()),!0),rejectAll:()=>L(p(!1,Date.now()),!0),reset:()=>L(o(),!1),open:()=>document.dispatchEvent(new CustomEvent(n)),subscribe(e){return y.add(e),e(v),()=>void y.delete(e)}},B=window.vitopsConsent?.q;if(window.vitopsConsent=z,B)for(let[e,t]of B)t?z.request(e).then(t):z.require(e);document.addEventListener(`click`,e=>{e.target?.closest?.(`[data-consent-open]`)&&(e.preventDefault(),z.open())}),document.addEventListener(`astro:page-load`,F),F(),R();var V=class extends HTMLElement{#e;#t=`prompt`;#n=!1;get#r(){return window.vitopsConsent}get#i(){return this.querySelector(`[popover]`)}connectedCallback(){let e=this.#r;if(!e)return;let t=this.#i;t&&typeof t.showPopover!=`function`&&t.removeAttribute(`popover`),this.getAttribute(`reload-on-revoke`)===`false`&&(e.reloadOnRevoke=!1),this.addEventListener(`click`,this.#p),this.addEventListener(`submit`,this.#o),document.addEventListener(n,this.#a),this.#e=e.subscribe(()=>{this.#n&&this.#t===`settings`?this.#f():e.needed()?this.#u(`prompt`):this.#d()})}disconnectedCallback(){this.removeEventListener(`click`,this.#p),this.removeEventListener(`submit`,this.#o),document.removeEventListener(n,this.#a),this.#e?.()}#a=()=>this.#u(`settings`);#o=e=>e.preventDefault();#s(e){return this.querySelector(`[data-consent-row="${e}"]`)??this.#c(e)?.closest(`label`)??null}#c(e){return this.querySelector(`input[name="${e}"]`)}#l(e){let t=this.#r;if(!t)return[];if(e===`settings`){let e=i.filter(e=>this.#s(e));return e.length?e:[...i]}let n=t.get();return i.filter(e=>t.demanded().includes(e)&&!d(n,e))}#u(e){if(!this.#l(e).length)return;this.#t=e,this.#f(),this.hidden=!1,this.#n=!0;let t=this.#i;t?.isConnected&&!t.matches(`:popover-open`)&&t.showPopover()}#d(){this.#n=!1,this.#i?.hidePopover?.(),this.hidden=!0}#f(){let e=this.#r;if(!e)return;let t=this.#l(this.#t);for(let n of i){let r=this.#s(n);r&&(r.hidden=!t.includes(n));let i=this.#c(n);i&&(i.checked=e.granted(n))}this.#i?.classList.toggle(`consent--single`,t.length<2)}#p=e=>{let t=this.#r,n=e.target?.closest?.(`[data-consent-accept],[data-consent-reject],[data-consent-save]`);if(!t||!n)return;e.preventDefault();let r=this.#l(this.#t);n.hasAttribute(`data-consent-accept`)?t.set(this.#m(r,()=>!0)):n.hasAttribute(`data-consent-reject`)?t.set(this.#m(r,()=>!1)):t.set(this.#m(r,e=>this.#c(e)?.checked===!0)),this.#d()};#m(e,t){let n={};for(let r of e)n[r]=t(r);return n}};customElements.get(`wc-consent`)||customElements.define(`wc-consent`,V);export{e as CATEGORIES,t as CONSENT_EVENT,n as CONSENT_OPEN_EVENT,r as COOKIE_NAME,z as consent};
|