@getvitops/core 8.2.0-alpha.0 → 8.3.0-alpha.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.
@@ -425,3 +425,265 @@
425
425
  display: none;
426
426
  }
427
427
  }
428
+
429
+ /* ── Tiers (`<SiteNav>`'s optional `primary-mobile` / `primary-mega` menus) ──────
430
+ Each tier is its own `<nav>` in a `.sitenav-tier` wrapper, and a wrapper is
431
+ `display: none` outside its container-width window — so exactly one tier is ever
432
+ in the accessibility tree. Same container as the `--bp-*` flag above (the nearest
433
+ ancestor `container-type`, `body` per layout.css), so the hand-over width and the
434
+ drawer→navbar flip can never disagree. One pair per breakpoint; `sitenav.ts`'s
435
+ `VISIBILITY_CLASSES` lists them and `sitenav.test.ts` checks each is defined here. */
436
+ @container (width < 30rem) {
437
+ .sitenav-tier--from-sm {
438
+ display: none;
439
+ }
440
+ }
441
+ @container (width >= 30rem) {
442
+ .sitenav-tier--below-sm {
443
+ display: none;
444
+ }
445
+ }
446
+ @container (width < 48rem) {
447
+ .sitenav-tier--from-md {
448
+ display: none;
449
+ }
450
+ }
451
+ @container (width >= 48rem) {
452
+ .sitenav-tier--below-md {
453
+ display: none;
454
+ }
455
+ }
456
+ @container (width < 64rem) {
457
+ .sitenav-tier--from-lg {
458
+ display: none;
459
+ }
460
+ }
461
+ @container (width >= 64rem) {
462
+ .sitenav-tier--below-lg {
463
+ display: none;
464
+ }
465
+ }
466
+ @container (width < 80rem) {
467
+ .sitenav-tier--from-xl {
468
+ display: none;
469
+ }
470
+ }
471
+ @container (width >= 80rem) {
472
+ .sitenav-tier--below-xl {
473
+ display: none;
474
+ }
475
+ }
476
+
477
+ /* ── Item description (EmDash `titleAttr` convention — see SiteNav.astro) ───── */
478
+ .sitenav__link--described {
479
+ flex-direction: column;
480
+ align-items: flex-start;
481
+ gap: 0.125rem;
482
+ }
483
+
484
+ .sitenav__desc {
485
+ font-size: 0.875em;
486
+ opacity: 0.75;
487
+ font-weight: normal;
488
+ }
489
+
490
+ /* The current page. Text-weight + a non-colour cue, so it survives forced-colors. */
491
+ .sitenav__link[aria-current='page'] {
492
+ font-weight: 600;
493
+ text-decoration: underline;
494
+ text-underline-offset: 0.25em;
495
+ }
496
+
497
+ /* ── Mega variant — WIDE ONLY ───────────────────────────────────────────────
498
+ Top-level submenus become full-width panels of columns under the nav row. The
499
+ branch item stops being the positioning context so the panel anchors to
500
+ `.sitenav--mega` instead. Inside the wide branch, with the same reasoning as the
501
+ rest of the file: a rule here competes at its bare selector weight. */
502
+ @container style(--_sitenav-wide: 1) {
503
+ .sitenav--mega {
504
+ position: relative;
505
+ }
506
+ .sitenav--mega .sitenav__list > .sitenav__item--branch {
507
+ position: static;
508
+ }
509
+ .sitenav--mega .sitenav__list > .sitenav__item--branch > .sitenav__submenu {
510
+ inset-inline: 0;
511
+ inline-size: 100%;
512
+ flex-direction: row;
513
+ flex-wrap: wrap;
514
+ align-items: flex-start;
515
+ gap: 1.5rem;
516
+ padding: 1.5rem;
517
+ }
518
+ /* Third level is a column inside the panel, not a fly-out. */
519
+ .sitenav--mega .sitenav__submenu .sitenav__item--branch {
520
+ position: static;
521
+ display: block;
522
+ }
523
+ .sitenav--mega .sitenav__submenu .sitenav__item--branch > .sitenav__submenu {
524
+ position: static;
525
+ opacity: 1;
526
+ visibility: visible;
527
+ pointer-events: auto;
528
+ translate: none;
529
+ box-shadow: none;
530
+ border: none;
531
+ padding: 0.25rem 0 0;
532
+ min-inline-size: 0;
533
+ }
534
+ .sitenav--mega .sitenav__submenu .sitenav__disclosure {
535
+ display: none;
536
+ }
537
+ }
538
+
539
+ /* ── In-page menu (`vitops.nav` block) ─────────────────────────────────────────
540
+ *
541
+ * A menu read in the body of a page — a site map, a section's links, footer-style columns —
542
+ * as plain nested lists. No disclosure and no drawer: that is the header's job (`.sitenav`).
543
+ *
544
+ * <nav aria-label="Services"><ul class="navlist navlist--columns">
545
+ * <li class="navlist__item"><a class="navlist__link">…</a><ul class="navlist__sub">…</ul></li>
546
+ *
547
+ * Modifiers: `--inline` (one wrapping row) and `--columns` (an auto-fit grid, each top-level
548
+ * item a column with its sub-links beneath it). */
549
+ .navlist,
550
+ .navlist__sub {
551
+ list-style: none;
552
+ margin: 0;
553
+ padding: 0;
554
+ display: flex;
555
+ flex-direction: column;
556
+ gap: 0.25rem;
557
+ }
558
+
559
+ /* The rhythm utility's `li + li` margin is the flow's job; the list's own gap does it here. */
560
+ .navlist__item {
561
+ margin: 0;
562
+ }
563
+
564
+ .navlist__sub {
565
+ margin-block-start: 0.25rem;
566
+ padding-inline-start: 1rem;
567
+ }
568
+
569
+ .navlist__link {
570
+ color: inherit;
571
+ text-decoration: underline;
572
+ text-underline-offset: 0.2em;
573
+ padding-block: 0.25rem;
574
+ border-radius: var(--br-control, 0.25rem);
575
+
576
+ &:focus-visible {
577
+ outline: 2px solid var(--sitenav-focus-color, var(--color-border-focus));
578
+ outline-offset: 2px;
579
+ }
580
+
581
+ &[aria-current='page'] {
582
+ font-weight: 600;
583
+ }
584
+ }
585
+
586
+ .navlist__label {
587
+ font-weight: 600;
588
+ }
589
+
590
+ .navlist--inline {
591
+ flex-direction: row;
592
+ flex-wrap: wrap;
593
+ gap: 0.25rem 1.25rem;
594
+ }
595
+
596
+ .navlist--columns {
597
+ display: grid;
598
+ grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
599
+ gap: 1.5rem;
600
+
601
+ > .navlist__item > :is(.navlist__link, .navlist__label) {
602
+ font-weight: 600;
603
+ }
604
+
605
+ > .navlist__item > .navlist__sub {
606
+ padding-inline-start: 0;
607
+ }
608
+ }
609
+
610
+ @media (forced-colors: active) {
611
+ .navlist__link:focus-visible {
612
+ outline-color: Highlight;
613
+ }
614
+ }
615
+
616
+ /* ── Footer (`<SiteFooter>`) ───────────────────────────────────────────────── */
617
+ .sitefooter {
618
+ margin-block-start: var(--space-2xl, 3rem);
619
+ display: flex;
620
+ flex-direction: column;
621
+ gap: 1rem;
622
+ padding-block: var(--space-l, 2rem);
623
+ border-block-start: 1px solid var(--color-border-neutral, currentColor);
624
+ }
625
+
626
+ .sitefooter__nav {
627
+ display: flex;
628
+ flex-wrap: wrap;
629
+ gap: 1rem 3rem;
630
+ justify-content: space-between;
631
+ }
632
+
633
+ .sitefooter__list {
634
+ list-style: none;
635
+ margin: 0;
636
+ padding: 0;
637
+ display: flex;
638
+ flex-wrap: wrap;
639
+ gap: 0.25rem 1.25rem;
640
+ }
641
+
642
+ .sitefooter__link {
643
+ color: inherit;
644
+ text-decoration: underline;
645
+ text-underline-offset: 0.2em;
646
+ padding-block: 0.25rem;
647
+ border-radius: var(--br-control, 0.25rem);
648
+
649
+ &:focus-visible {
650
+ outline: 2px solid var(--sitenav-focus-color, var(--color-border-focus));
651
+ outline-offset: 2px;
652
+ }
653
+
654
+ &[aria-current='page'] {
655
+ font-weight: 600;
656
+ }
657
+ }
658
+
659
+ .sitefooter__copy {
660
+ margin: 0;
661
+ font-size: 0.875em;
662
+ opacity: 0.8;
663
+ }
664
+
665
+ /* ── Motion + forced colours (both site-nav and footer) ────────────────────── */
666
+ @media (prefers-reduced-motion: reduce) {
667
+ .sitenav__panel,
668
+ .sitenav__panel::backdrop,
669
+ .sitenav__submenu,
670
+ .sitenav__item--branch {
671
+ transition: none;
672
+ }
673
+ }
674
+
675
+ @media (forced-colors: active) {
676
+ .sitenav__link:focus-visible,
677
+ .sitenav__toggle:focus-visible,
678
+ .sitenav__close:focus-visible,
679
+ .sitefooter__link:focus-visible {
680
+ outline-color: Highlight;
681
+ }
682
+ .sitenav__panel,
683
+ .sitenav__submenu {
684
+ border: 1px solid CanvasText;
685
+ }
686
+ .sitenav__link[aria-current='page'] {
687
+ text-decoration-thickness: 2px;
688
+ }
689
+ }
@@ -210,3 +210,14 @@
210
210
  }
211
211
  }
212
212
  }
213
+
214
+ /*
215
+ * Pre-upgrade display for the two elements that live in this partial — see the note on
216
+ * `wc-entries` in table.css. Both are a framed block of content (two panes; two images),
217
+ * and `wc-image-compare`'s upgraded `:host` is already `display: block`, so declaring it
218
+ * here removes the layout shift when it registers. `wc-split-panel` has no `:host` display
219
+ * at all, so this also fixes it after upgrade.
220
+ */
221
+ :where(wc-split-panel, wc-image-compare) {
222
+ display: block;
223
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Stats — a row of headline figures ("11 hrs/week", "82%") and, as `.stats--tiles`, a
3
+ * grid of labelled tiles with a group, a delta and a state (the generic kernel of a
4
+ * dashboard mock: "Open jobs 24 +3 this week").
5
+ *
6
+ * The figure is the `.counter` pattern, so the count-up is `<wc-counter>`'s; this
7
+ * partial only lays the figures out. With no JS and no CSS each figure is plain text
8
+ * beside its label.
9
+ *
10
+ * `data-state` on a tile (`up` / `down`) drives the delta's colour through the semantic
11
+ * roles, so "good" and "bad" follow the site's own success/danger rather than a hard-coded
12
+ * green and red. The delta's words stay in the text: colour is never the only carrier.
13
+ */
14
+ .stats {
15
+ display: grid;
16
+ gap: var(--stats-gap, 1.5rem);
17
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--stats-min, 12rem)), 1fr));
18
+ margin: 0;
19
+ padding: 0;
20
+ list-style: none;
21
+
22
+ .stats__item {
23
+ display: grid;
24
+ gap: 0.25rem;
25
+ align-content: start;
26
+ margin: 0;
27
+ }
28
+
29
+ .stats__figure,
30
+ .stats__label,
31
+ .stats__group,
32
+ .stats__delta {
33
+ margin: 0;
34
+ }
35
+
36
+ .stats__figure {
37
+ color: var(--tone-fg, inherit);
38
+ font-variant-numeric: tabular-nums;
39
+ }
40
+
41
+ .stats__group {
42
+ text-transform: uppercase;
43
+ letter-spacing: 0.05em;
44
+ opacity: 0.8;
45
+ }
46
+
47
+ .stats__item[data-state='up'] .stats__delta {
48
+ color: var(--color-text-success, inherit);
49
+ }
50
+
51
+ .stats__item[data-state='down'] .stats__delta {
52
+ color: var(--color-text-danger, inherit);
53
+ }
54
+
55
+ &.stats--tiles .stats__item {
56
+ padding: var(--stats-tile-padding, 1rem 1.25rem);
57
+ border: var(--b-card, var(--b-card-group, var(--b-default)));
58
+ border-radius: var(--br-card, var(--br-card-group, var(--br-default)));
59
+ background-color: var(--tone-bg, transparent);
60
+ }
61
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Steps — an ordered sequence ("getting started is simple") with a connector line
3
+ * running through the numbered markers.
4
+ *
5
+ * It is an `<ol>`, so the order is semantic and announced with no CSS. The number is a
6
+ * CSS counter and the connector a pseudo-element on each item; without this stylesheet
7
+ * the list is simply a numbered list. Vertical by default, side by side with `--row`
8
+ * once the container has room.
9
+ *
10
+ * The marker takes its fill from `.tone` (`--tone-solid` / `--tone-on-solid`), so one
11
+ * `tone` field recolours the whole sequence.
12
+ */
13
+ .steps {
14
+ --_marker: var(--steps-marker-size, 2.5rem);
15
+ --_line: var(--steps-line-width, 2px);
16
+ --_gap: var(--steps-gap, 1.5rem);
17
+
18
+ display: grid;
19
+ gap: var(--_gap);
20
+ margin: 0;
21
+ padding: 0;
22
+ list-style: none;
23
+ counter-reset: step;
24
+
25
+ .steps__item {
26
+ position: relative;
27
+ display: grid;
28
+ grid-template-columns: var(--_marker) minmax(0, 1fr);
29
+ column-gap: 1rem;
30
+ align-items: start;
31
+ counter-increment: step;
32
+ }
33
+
34
+ /* The marker. */
35
+ .steps__item::before {
36
+ content: counter(step);
37
+ display: grid;
38
+ place-items: center;
39
+ inline-size: var(--_marker);
40
+ block-size: var(--_marker);
41
+ border-radius: 50%;
42
+ font-weight: 700;
43
+ background-color: var(--tone-solid, currentColor);
44
+ color: var(--tone-on-solid, Canvas);
45
+ position: relative;
46
+ z-index: 1;
47
+ }
48
+
49
+ /* The connector: from this marker down to the next. */
50
+ .steps__item:not(:last-child)::after {
51
+ content: '';
52
+ position: absolute;
53
+ inset-inline-start: calc(var(--_marker) / 2 - var(--_line) / 2);
54
+ inset-block-start: var(--_marker);
55
+ inset-block-end: calc(var(--_gap) * -1);
56
+ inline-size: var(--_line);
57
+ background-color: var(--tone-border, currentColor);
58
+ opacity: 0.4;
59
+ }
60
+
61
+ .steps__body {
62
+ display: grid;
63
+ gap: 0.25rem;
64
+ grid-column: 2;
65
+ min-inline-size: 0;
66
+ }
67
+
68
+ .steps__title,
69
+ .steps__text {
70
+ margin: 0;
71
+ }
72
+ }
73
+
74
+ /* Side by side once there is room: the marker sits above its text and the line runs across. */
75
+ @container (min-width: 48rem) {
76
+ .steps.steps--row {
77
+ grid-auto-flow: column;
78
+ grid-auto-columns: minmax(0, 1fr);
79
+
80
+ .steps__item {
81
+ grid-template-columns: minmax(0, 1fr);
82
+ row-gap: 0.75rem;
83
+ }
84
+
85
+ .steps__body {
86
+ grid-column: 1;
87
+ }
88
+
89
+ .steps__item:not(:last-child)::after {
90
+ inset-inline-start: var(--_marker);
91
+ inset-inline-end: calc(var(--_gap) * -1);
92
+ inset-block-start: calc(var(--_marker) / 2 - var(--_line) / 2);
93
+ inset-block-end: auto;
94
+ inline-size: auto;
95
+ block-size: var(--_line);
96
+ }
97
+ }
98
+ }
@@ -104,3 +104,13 @@ table,
104
104
  min-inline-size: var(--table-min-inline-size, 100%);
105
105
  }
106
106
  }
107
+
108
+ /*
109
+ * Before upgrade (or with elements.js absent) an unregistered custom element is
110
+ * `display: inline`, forming an inline box around block content. The default-view
111
+ * `<h3>` + `<dl>` pairs are block content, as is the table the element builds.
112
+ * Zero specificity, so any consumer rule wins.
113
+ */
114
+ :where(wc-entries) {
115
+ display: block;
116
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Tone — one convention for "colour this block", shared by every block that colours
3
+ * anything (section, callout, stats, steps, cards `panel`, hero).
4
+ *
5
+ * A block never names a colour class. Class names cannot be built from a field value
6
+ * (Tailwind only sees literals), so a renderer sets custom properties on the element
7
+ * and `.tone` reads them:
8
+ *
9
+ * --tone-bg a tint of the role (`--color-bg-<role>-muted`)
10
+ * --tone-fg its readable text (`--color-text-<role>`)
11
+ * --tone-border its boundary (`--color-border-<role>`)
12
+ * --tone-solid / --tone-on-solid the filled variant and its computed foreground
13
+ *
14
+ * Each is a `var()` chain — the role, then its semantic fallbacks, then `neutral` — so a
15
+ * tone a site never defined degrades to a neutral surface instead of to nothing.
16
+ * `@getvitops/emdash`'s `resolveTone()` writes the chains. Unset, `.tone` is inert.
17
+ *
18
+ * `.tone--tint` is the default; `--solid` fills with the role's solid and its `on` colour.
19
+ */
20
+ .tone {
21
+ --_bg: var(--tone-bg, transparent);
22
+ --_fg: var(--tone-fg, inherit);
23
+
24
+ background-color: var(--_bg);
25
+ color: var(--_fg);
26
+ border-color: var(--tone-border, currentColor);
27
+
28
+ &.tone--solid {
29
+ background-color: var(--tone-solid, var(--_bg));
30
+ color: var(--tone-on-solid, var(--_fg));
31
+ }
32
+ }
33
+
34
+ /* An accent run inside a heading (`<em class="accent">`): colour, not italics. */
35
+ .accent {
36
+ font-style: normal;
37
+ color: var(--accent-color, var(--color-text-ui-accent, currentColor));
38
+ }
package/dist/consent.js CHANGED
@@ -1 +1 @@
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`||e.choices[t]===!0}function d(e,t){return t===`necessary`||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=/* @__PURE__ */ new Set,b=/* @__PURE__ */ new WeakSet,x=/* @__PURE__ */ new Set,S=/* @__PURE__ */ new Set,C=/* @__PURE__ */ new Map,w=/* @__PURE__ */ new Set;function T(e){w.has(e)||(w.add(e),queueMicrotask(()=>{document.querySelector(`wc-consent`)||console.warn(`[vitops] something requested the "${e}" consent category, but this page has no <wc-consent> element to ask with — so the request can never be granted and whatever waited on it will not run. Render <CookieConsent /> on every page that gates anything.`)}))}function E(e){S.has(e)||(S.add(e),T(e),B())}function D(){for(let[e,t]of C)if(d(v,e)){C.delete(e);for(let n of t)n(u(v,e))}}const O={idle:[],async:[],interaction:[]},k={idle:!1,async:!0,interaction:!1};function A(e){if(k[e])return;k[e]=!0;let t=O[e];O[e]=[];for(let e of t)e()}function j(e,t){k[e]?t():O[e].push(t)}function M(e){document.readyState===`complete`?e():addEventListener(`load`,e,{once:!0})}M(()=>{let e=globalThis.requestIdleCallback;e?e(()=>A(`idle`),{timeout:3e3}):setTimeout(()=>A(`idle`),1)});{let e=[`pointerdown`,`keydown`,`scroll`,`touchstart`],t=()=>{for(let n of e)removeEventListener(n,t);A(`interaction`)};for(let n of e)addEventListener(n,t,{once:!0,passive:!0});M(()=>setTimeout(()=>A(`interaction`),8e3))}const N=/* @__PURE__ */ new Set([`type`,`src`,`data-vitops-tag`,`data-src`,`data-strategy`,`data-consent`,`data-consent-src`,`data-consent-cookies`]);function P(t){let n=t.getAttribute(`data-consent`);return e.includes(n??``)?n:`analytics`}function F(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))N.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 I(e){if(!b.has(e)){if(b.add(e),x.add(P(e)),e instanceof HTMLScriptElement)F(e);else{let t=e.getAttribute(`data-consent-src`);t&&e.setAttribute(`src`,t)}e.setAttribute(`data-vitops-activated`,``)}}function L(){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`);j(e===`async`||e===`interaction`?e:`idle`,()=>{let e=P(t);u(v,e)?I(t):E(e)})}}function R(e){let t=/* @__PURE__ */ 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 z(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`,B(),L(),n.length&&(R(n),n.some(e=>x.has(e)&&u(i,e))&&V.reloadOnRevoke&&location.reload())}function B(){D();for(let e of y)e(v);document.dispatchEvent(new CustomEvent(t,{detail:v}))}const V={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 E(e),u(v,e)},request(e){return E(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=>z(m(v,e,Date.now()),!0),acceptAll:()=>z(p(!0,Date.now()),!0),rejectAll:()=>z(p(!1,Date.now()),!0),reset:()=>z(o(),!1),open:()=>document.dispatchEvent(new CustomEvent(n)),subscribe(e){return y.add(e),e(v),()=>void y.delete(e)}},H=window.vitopsConsent?.q;if(window.vitopsConsent=V,H)for(let[e,t]of H)t?V.request(e).then(t):V.require(e);document.addEventListener(`click`,e=>{e.target?.closest?.(`[data-consent-open]`)&&(e.preventDefault(),V.open())}),document.addEventListener(`astro:page-load`,L),L(),B();var U=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`,U);export{e as CATEGORIES,t as CONSENT_EVENT,n as CONSENT_OPEN_EVENT,r as COOKIE_NAME,V 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`||e.choices[t]===!0}function d(e,t){return t===`necessary`||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=/* @__PURE__ */ new Set,b=/* @__PURE__ */ new WeakSet,x=/* @__PURE__ */ new Set,S=/* @__PURE__ */ new Set,C=/* @__PURE__ */ new Map,w=/* @__PURE__ */ new Set;function T(e){w.has(e)||(w.add(e),queueMicrotask(()=>{document.querySelector(`wc-consent`)||console.warn(`[vitops] something requested the "${e}" consent category, but this page has no <wc-consent> element to ask with — so the request can never be granted and whatever waited on it will not run. Render <CookieConsent /> on every page that gates anything.`)}))}function E(e){S.has(e)||(S.add(e),T(e),B())}function D(){for(let[e,t]of C)if(d(v,e)){C.delete(e);for(let n of t)n(u(v,e))}}const O={idle:[],async:[],interaction:[]},k={idle:!1,async:!0,interaction:!1};function A(e){if(k[e])return;k[e]=!0;let t=O[e];O[e]=[];for(let e of t)e()}function j(e,t){k[e]?t():O[e].push(t)}function M(e){document.readyState===`complete`?e():addEventListener(`load`,e,{once:!0})}M(()=>{let e=globalThis.requestIdleCallback;e?e(()=>A(`idle`),{timeout:3e3}):setTimeout(()=>A(`idle`),1)});{let e=[`pointerdown`,`keydown`,`scroll`,`touchstart`],t=()=>{for(let n of e)removeEventListener(n,t);A(`interaction`)};for(let n of e)addEventListener(n,t,{once:!0,passive:!0});M(()=>setTimeout(()=>A(`interaction`),8e3))}const N=/* @__PURE__ */ new Set([`type`,`src`,`data-vitops-tag`,`data-src`,`data-strategy`,`data-consent`,`data-consent-src`,`data-consent-cookies`]);function P(t){let n=t.getAttribute(`data-consent`);return e.includes(n??``)?n:`analytics`}function F(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))N.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 I(e){if(!b.has(e)){if(b.add(e),x.add(P(e)),e instanceof HTMLScriptElement)F(e);else{let t=e.getAttribute(`data-consent-src`);t&&e.setAttribute(`src`,t)}e.setAttribute(`data-vitops-activated`,``)}}function L(){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`);j(e===`async`||e===`interaction`?e:`idle`,()=>{let e=P(t);u(v,e)?I(t):E(e)})}}function R(e){let t=/* @__PURE__ */ 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 z(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`,B(),L(),n.length&&(R(n),n.some(e=>x.has(e)&&u(i,e))&&V.reloadOnRevoke&&location.reload())}function B(){D();for(let e of y)e(v);document.dispatchEvent(new CustomEvent(t,{detail:v}))}const V={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 E(e),u(v,e)},request(e){return E(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=>z(m(v,e,Date.now()),!0),acceptAll:()=>z(p(!0,Date.now()),!0),rejectAll:()=>z(p(!1,Date.now()),!0),reset:()=>z(o(),!1),open:()=>document.dispatchEvent(new CustomEvent(n)),subscribe(e){return y.add(e),e(v),()=>void y.delete(e)}},H=window.vitopsConsent?.q;if(window.vitopsConsent=V,H)for(let[e,t]of H)t?V.request(e).then(t):V.require(e);document.addEventListener(`click`,e=>{e.target?.closest?.(`[data-consent-open]`)&&(e.preventDefault(),V.open())}),document.addEventListener(`astro:page-load`,L),L(),B();var U=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.#m),this.addEventListener(`submit`,this.#o),document.addEventListener(n,this.#a),this.#e=e.subscribe(()=>{this.#n&&this.#t===`settings`?this.#p():e.needed()?this.#u(`prompt`):this.#f()})}disconnectedCallback(){this.removeEventListener(`click`,this.#m),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.#p(),this.hidden=!1,this.#n=!0;let t=this.#i;t?.isConnected&&!t.matches(`:popover-open`)&&t.showPopover(),e===`settings`&&t&&(this.#d=document.activeElement instanceof HTMLElement?document.activeElement:null,t.tabIndex=-1,t.focus({preventScroll:!0}))}#d=null;#f(){this.#n=!1,this.#i?.hidePopover?.(),this.hidden=!0;let e=this.#d;this.#d=null,e?.isConnected&&e.focus({preventScroll:!0})}#p(){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)}#m=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.#h(r,()=>!0)):n.hasAttribute(`data-consent-reject`)?t.set(this.#h(r,()=>!1)):t.set(this.#h(r,e=>this.#c(e)?.checked===!0)),this.#f()};#h(e,t){let n={};for(let r of e)n[r]=t(r);return n}};customElements.get(`wc-consent`)||customElements.define(`wc-consent`,U);export{e as CATEGORIES,t as CONSENT_EVENT,n as CONSENT_OPEN_EVENT,r as COOKIE_NAME,V as consent};