@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.
@@ -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
- * `.sitenav__disclosure` is `display: contents` so the `<summary>` (caret) and the
21
- * submenu `<ul>` participate directly in the branch item's grid — that is what lets
22
- * the caret sit inline with the link while the submenu spans full width on its own
23
- * row. Native `[open]` toggling is unaffected by `display: contents`.
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
- /* Slide from the chosen edge (default inline-end). */
110
- .sitenav--drawer-end .sitenav__panel {
111
- inset-inline-end: 0;
112
- inset-inline-start: auto;
113
- translate: 100% 0;
114
- }
115
- .sitenav--drawer-start .sitenav__panel {
116
- inset-inline-start: 0;
117
- inset-inline-end: auto;
118
- translate: -100% 0;
119
- }
120
- .sitenav__panel:popover-open {
121
- opacity: 1;
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:popover-open {
130
- opacity: 0;
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 — mobile accordion ────────────────────────────────────────
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
- .sitenav__item--branch > .sitenav__submenu {
208
- grid-column: 1 / -1;
209
- grid-row: 2;
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
- /* Depth cap (mobile side): a desktop-only branch shows just its parent link. */
229
- .sitenav__item--desktop-branch > .sitenav__disclosure,
230
- .sitenav__item--desktop-branch > .sitenav__submenu {
231
- display: none;
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
- grid-template-columns: none;
314
- grid-template-rows: none;
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
- /* depth caps flip at the breakpoint: desktop-only branches reveal their caret +
352
- dropdown; mobile-only branches collapse to a plain link. */
353
- .sitenav__item--desktop-branch > .sitenav__disclosure,
354
- .sitenav__item--desktop-branch > .sitenav__submenu {
355
- display: block;
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
- .tree__item > .tree {
19
- margin-inline-start: var(--tree-indent, 1.5rem);
20
- padding-inline-start: var(--tree-indent, 1.5rem);
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(--tree-indent, 1.5rem) + 0.5rem);
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(--tree-indent, 1.5rem) - 0.5rem);
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
  }
@@ -1 +1 @@
1
- const e=[`necessary`,`analytics`,`marketing`,`preferences`],t=`vitops_consent`,n=[`analytics`,`marketing`,`preferences`];function r(e){return{analytics:e,marketing:e,preferences:e}}function i(){return{decided:!1,ts:null,choices:r(!1)}}function a(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 o(e){if(!e)return i();let t;try{t=JSON.parse(decodeURIComponent(e))}catch{return i()}if(typeof t!=`object`||!t)return i();let a=t;if(a.v!==1||typeof a.c!=`object`||a.c===null)return i();let o=a.c,s=r(!1);for(let e of n)s[e]=o[e]===!0;return{decided:!0,ts:typeof a.ts==`number`?a.ts:null,choices:s}}function s(e){return encodeURIComponent(JSON.stringify({v:1,ts:e.ts??0,c:e.choices}))}function c(e,t){return t===`necessary`?!0:e.decided&&e.choices[t]===!0}function l(e,t){return{decided:!0,ts:t,choices:r(e)}}function u(e,t,r){let i={...e.choices};for(let e of n){let n=t[e];typeof n==`boolean`&&(i[e]=n)}return{decided:!0,ts:r,choices:i}}function d(e,t){return n.filter(n=>c(e,n)&&!c(t,n))}function f(e){return`; path=/; max-age=15552000; SameSite=Lax${e?`; Secure`:``}`}const p=`vitops:consent`,m=`vitops:consent-open`,h=location.protocol===`https:`;let g=o(a(document.cookie,t));const _=new Set,v=new WeakSet,y=new Set,b={idle:[],async:[],interaction:[]},x={idle:!1,async:!0,interaction:!1};function S(e){if(x[e])return;x[e]=!0;let t=b[e];b[e]=[];for(let e of t)e()}function C(e,t){x[e]?t():b[e].push(t)}function w(e){document.readyState===`complete`?e():addEventListener(`load`,e,{once:!0})}w(()=>{let e=globalThis.requestIdleCallback;e?e(()=>S(`idle`),{timeout:3e3}):setTimeout(()=>S(`idle`),1)});{let e=[`pointerdown`,`keydown`,`scroll`,`touchstart`],t=()=>{for(let n of e)removeEventListener(n,t);S(`interaction`)};for(let n of e)addEventListener(n,t,{once:!0,passive:!0});w(()=>setTimeout(()=>S(`interaction`),8e3))}const T=new Set([`type`,`src`,`data-vitops-tag`,`data-src`,`data-strategy`,`data-consent`,`data-consent-src`,`data-consent-cookies`]);function E(t){let n=t.getAttribute(`data-consent`);return e.includes(n??``)?n:`analytics`}function D(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))T.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 O(e){if(!v.has(e)){if(v.add(e),y.add(E(e)),e instanceof HTMLScriptElement)D(e);else{let t=e.getAttribute(`data-consent-src`);t&&e.setAttribute(`src`,t)}e.setAttribute(`data-vitops-activated`,``)}}function k(){let e=document.querySelectorAll(`script[data-vitops-tag]:not([data-vitops-activated]),[data-consent-src]:not([data-vitops-activated])`);for(let t of e){if(!c(g,E(t)))continue;let e=t.getAttribute(`data-strategy`);C(e===`async`||e===`interaction`?e:`idle`,()=>O(t))}}function A(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 j(e,n){let r=d(g,e),i=g;g=e,n?document.cookie=`${t}=${s(e)}${f(h)}`:document.cookie=`${t}=; path=/; max-age=0`,M(),k(),r.length&&(A(r),r.some(e=>y.has(e)&&c(i,e))&&N.reloadOnRevoke&&location.reload())}function M(){for(let e of _)e(g);document.dispatchEvent(new CustomEvent(p,{detail:g}))}const N={categories:e,reloadOnRevoke:!0,get:()=>g,granted:e=>c(g,e),needed:()=>!g.decided,set:e=>j(u(g,e,Date.now()),!0),acceptAll:()=>j(l(!0,Date.now()),!0),rejectAll:()=>j(l(!1,Date.now()),!0),reset:()=>j(i(),!1),open:()=>document.dispatchEvent(new CustomEvent(m)),subscribe(e){return _.add(e),e(g),()=>void _.delete(e)}};window.vitopsConsent=N,document.addEventListener(`click`,e=>{e.target?.closest?.(`[data-consent-open]`)&&(e.preventDefault(),N.open())}),document.addEventListener(`astro:page-load`,k),k(),M();const P=[`analytics`,`marketing`,`preferences`];var F=class extends HTMLElement{#e;get#t(){return window.vitopsConsent}get#n(){return this.querySelector(`[popover]`)}connectedCallback(){let e=this.#t;if(!e)return;let t=this.#n;t&&typeof t.showPopover!=`function`&&t.removeAttribute(`popover`),this.getAttribute(`reload-on-revoke`)===`false`&&(e.reloadOnRevoke=!1),this.addEventListener(`click`,this.#c),this.addEventListener(`submit`,this.#i),document.addEventListener(m,this.#r),this.#e=e.subscribe(()=>{e.needed()?this.#a():this.#o()})}disconnectedCallback(){this.removeEventListener(`click`,this.#c),this.removeEventListener(`submit`,this.#i),document.removeEventListener(m,this.#r),this.#e?.()}#r=()=>this.#a();#i=e=>e.preventDefault();#a(){this.#s(),this.hidden=!1;let e=this.#n;e?.isConnected&&!e.matches(`:popover-open`)&&e.showPopover()}#o(){this.#n?.hidePopover?.(),this.hidden=!0}#s(){let e=this.#t;if(e)for(let t of P){let n=this.querySelector(`input[name="${t}"]`);n&&(n.checked=e.granted(t))}}#c=e=>{let t=this.#t,n=e.target?.closest?.(`[data-consent-accept],[data-consent-reject],[data-consent-save]`);!t||!n||(e.preventDefault(),n.hasAttribute(`data-consent-accept`)?t.acceptAll():n.hasAttribute(`data-consent-reject`)?t.rejectAll():t.set(this.#l()),this.#o())};#l(){let e={};for(let t of P)e[t]=this.querySelector(`input[name="${t}"]`)?.checked===!0;return e}};customElements.get(`wc-consent`)||customElements.define(`wc-consent`,F);export{e as CATEGORIES,p as CONSENT_EVENT,m as CONSENT_OPEN_EVENT,t as COOKIE_NAME,N as 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};