@preprio/toolkit 0.6.0-alpha.6 → 0.6.0-alpha.8
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/README.md +138 -52
- package/dist/astro/{chunk-MWRA3732.js → chunk-R2YPGDVU.js} +1 -1
- package/dist/astro/graphql.cjs +58 -10
- package/dist/astro/graphql.d.cts +33 -38
- package/dist/astro/graphql.d.ts +33 -38
- package/dist/astro/graphql.js +59 -11
- package/dist/astro/index.cjs +1 -1
- package/dist/astro/index.js +1 -1
- package/dist/{chunk-Y7DWVOOY.js → chunk-2QGUP7VQ.js} +1 -1
- package/dist/{chunk-NSQOGI5K.js → chunk-ATPB7GEC.js} +1 -1
- package/dist/{chunk-W6AVX6FI.js → chunk-OY7OKO6Q.js} +52 -5
- package/dist/{chunk-OQGEL4TV.js → chunk-T7ESBVBI.js} +1 -1
- package/dist/graphql/codegen.cjs +51 -4
- package/dist/graphql/codegen.js +3 -3
- package/dist/graphql.cjs +89 -10
- package/dist/graphql.d.cts +69 -39
- package/dist/graphql.d.ts +69 -39
- package/dist/graphql.js +38 -9
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/nextjs/{chunk-PIQF5ZI5.js → chunk-O2SBSBDG.js} +58 -53
- package/dist/nextjs/components.cjs +205 -236
- package/dist/nextjs/components.d.cts +27 -22
- package/dist/nextjs/components.d.ts +27 -22
- package/dist/nextjs/components.js +198 -231
- package/dist/nextjs/graphql.cjs +418 -508
- package/dist/nextjs/graphql.d.cts +131 -135
- package/dist/nextjs/graphql.d.ts +131 -135
- package/dist/nextjs/graphql.js +353 -455
- package/dist/nextjs/index.cjs +114 -54
- package/dist/nextjs/index.d.cts +59 -33
- package/dist/nextjs/index.d.ts +59 -33
- package/dist/nextjs/index.js +108 -5
- package/dist/nuxt/{chunk-PF6GVWHV.js → chunk-SX3MSVPK.js} +1 -1
- package/dist/nuxt/graphql.cjs +58 -10
- package/dist/nuxt/graphql.d.cts +33 -38
- package/dist/nuxt/graphql.d.ts +33 -38
- package/dist/nuxt/graphql.js +59 -11
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/react/components.cjs +1 -1
- package/dist/react/components.js +1 -1
- package/dist/sveltekit/{chunk-5K7HWMIF.js → chunk-UOASSHZO.js} +1 -1
- package/dist/sveltekit/graphql.cjs +58 -10
- package/dist/sveltekit/graphql.d.cts +33 -38
- package/dist/sveltekit/graphql.d.ts +33 -38
- package/dist/sveltekit/graphql.js +59 -11
- package/dist/sveltekit/index.cjs +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactNode, ReactElement } from 'react';
|
|
2
2
|
import { k as PreprToolbarComponentProps } from '../types-BYH9XqmN.cjs';
|
|
3
3
|
import { P as PreprPixelConfig } from '../pixel-DwW7cXJm.cjs';
|
|
4
4
|
|
|
@@ -23,24 +23,31 @@ declare function PreprTrackingPixel({ id, config, }: PreprTrackingPixelProps): n
|
|
|
23
23
|
*/
|
|
24
24
|
declare function PreprToolbar({ options, ...props }: PreprToolbarComponentProps): null;
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
26
|
+
* Gets each client-side navigation's decision in before the click: when the
|
|
27
|
+
* visitor hovers over a same-site link (or presses it, on touch devices), it
|
|
28
|
+
* asks `createPreprProxy` which variants they get on that page. Clicks are
|
|
29
|
+
* never held: the new page paints with those variants when the answer is in,
|
|
30
|
+
* and keeps its personalized sections hidden until then otherwise. Pages
|
|
31
|
+
* without personalization answer with no groups and are not asked again for
|
|
32
|
+
* an hour.
|
|
33
|
+
*
|
|
34
|
+
* Mount it once in the root layout, so links on pages without a
|
|
35
|
+
* `PreprStack` are covered too. Links to other sites and links that open a
|
|
36
|
+
* new tab or download are left alone.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* <PreprPersonalizationSwitch />
|
|
31
40
|
*/
|
|
32
|
-
declare function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
declare function PreprPersonalizationSwitch({ refresh, freshFor, }: PreprPersonalizationSwitchProps): ReactElement | null;
|
|
41
|
+
declare function PreprPersonalizationSwitch(): null;
|
|
42
|
+
/**
|
|
43
|
+
* Applies this page view's decision to the variant wrappers of the
|
|
44
|
+
* `PreprStack` it is rendered by, before the page paints when the decision is
|
|
45
|
+
* already in: asked for on hover, or kept from an earlier view of the page.
|
|
46
|
+
* Back and Forward show the page as this tab last showed it. Any other view
|
|
47
|
+
* keeps its personalized sections hidden until the decision request answers.
|
|
48
|
+
* Rendered by `PreprStack`; you do not need it yourself.
|
|
49
|
+
*/
|
|
50
|
+
declare function PreprDecisionApplier(): null;
|
|
44
51
|
/**
|
|
45
52
|
* Wraps one rendered variant and, once hydrated, puts the variant keys on the
|
|
46
53
|
* elements inside, where Prepr's tracking pixel counts impressions and the
|
|
@@ -55,11 +62,9 @@ declare function PreprPersonalizationSwitch({ refresh, freshFor, }: PreprPersona
|
|
|
55
62
|
* carries a variant key is left alone. Rendered by `PreprStack` with
|
|
56
63
|
* `trackVariants`; you do not need it yourself.
|
|
57
64
|
*/
|
|
58
|
-
declare function PreprVariantTracking({ variantKeys,
|
|
65
|
+
declare function PreprVariantTracking({ variantKeys, children, }: {
|
|
59
66
|
variantKeys: string[];
|
|
60
|
-
/** The A/B bucket wrapper this also serves as; its CSS decides `display`. */
|
|
61
|
-
ab?: string;
|
|
62
67
|
children?: ReactNode;
|
|
63
68
|
}): ReactElement;
|
|
64
69
|
|
|
65
|
-
export {
|
|
70
|
+
export { PreprDecisionApplier, PreprPersonalizationSwitch, PreprToolbar, PreprTrackingPixel, type PreprTrackingPixelProps, PreprVariantTracking };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactNode, ReactElement } from 'react';
|
|
2
2
|
import { k as PreprToolbarComponentProps } from '../types-BYH9XqmN.js';
|
|
3
3
|
import { P as PreprPixelConfig } from '../pixel-DwW7cXJm.js';
|
|
4
4
|
|
|
@@ -23,24 +23,31 @@ declare function PreprTrackingPixel({ id, config, }: PreprTrackingPixelProps): n
|
|
|
23
23
|
*/
|
|
24
24
|
declare function PreprToolbar({ options, ...props }: PreprToolbarComponentProps): null;
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
26
|
+
* Gets each client-side navigation's decision in before the click: when the
|
|
27
|
+
* visitor hovers over a same-site link (or presses it, on touch devices), it
|
|
28
|
+
* asks `createPreprProxy` which variants they get on that page. Clicks are
|
|
29
|
+
* never held: the new page paints with those variants when the answer is in,
|
|
30
|
+
* and keeps its personalized sections hidden until then otherwise. Pages
|
|
31
|
+
* without personalization answer with no groups and are not asked again for
|
|
32
|
+
* an hour.
|
|
33
|
+
*
|
|
34
|
+
* Mount it once in the root layout, so links on pages without a
|
|
35
|
+
* `PreprStack` are covered too. Links to other sites and links that open a
|
|
36
|
+
* new tab or download are left alone.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* <PreprPersonalizationSwitch />
|
|
31
40
|
*/
|
|
32
|
-
declare function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
declare function PreprPersonalizationSwitch({ refresh, freshFor, }: PreprPersonalizationSwitchProps): ReactElement | null;
|
|
41
|
+
declare function PreprPersonalizationSwitch(): null;
|
|
42
|
+
/**
|
|
43
|
+
* Applies this page view's decision to the variant wrappers of the
|
|
44
|
+
* `PreprStack` it is rendered by, before the page paints when the decision is
|
|
45
|
+
* already in: asked for on hover, or kept from an earlier view of the page.
|
|
46
|
+
* Back and Forward show the page as this tab last showed it. Any other view
|
|
47
|
+
* keeps its personalized sections hidden until the decision request answers.
|
|
48
|
+
* Rendered by `PreprStack`; you do not need it yourself.
|
|
49
|
+
*/
|
|
50
|
+
declare function PreprDecisionApplier(): null;
|
|
44
51
|
/**
|
|
45
52
|
* Wraps one rendered variant and, once hydrated, puts the variant keys on the
|
|
46
53
|
* elements inside, where Prepr's tracking pixel counts impressions and the
|
|
@@ -55,11 +62,9 @@ declare function PreprPersonalizationSwitch({ refresh, freshFor, }: PreprPersona
|
|
|
55
62
|
* carries a variant key is left alone. Rendered by `PreprStack` with
|
|
56
63
|
* `trackVariants`; you do not need it yourself.
|
|
57
64
|
*/
|
|
58
|
-
declare function PreprVariantTracking({ variantKeys,
|
|
65
|
+
declare function PreprVariantTracking({ variantKeys, children, }: {
|
|
59
66
|
variantKeys: string[];
|
|
60
|
-
/** The A/B bucket wrapper this also serves as; its CSS decides `display`. */
|
|
61
|
-
ab?: string;
|
|
62
67
|
children?: ReactNode;
|
|
63
68
|
}): ReactElement;
|
|
64
69
|
|
|
65
|
-
export {
|
|
70
|
+
export { PreprDecisionApplier, PreprPersonalizationSwitch, PreprToolbar, PreprTrackingPixel, type PreprTrackingPixelProps, PreprVariantTracking };
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createPreprPreview,
|
|
4
4
|
loadTrackingPixel
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-2QGUP7VQ.js";
|
|
6
6
|
import "../chunk-S5RWVMDJ.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-ATPB7GEC.js";
|
|
8
8
|
|
|
9
9
|
// src/nextjs/components.ts
|
|
10
10
|
import { usePathname, useRouter } from "next/navigation";
|
|
@@ -12,9 +12,7 @@ import {
|
|
|
12
12
|
createElement,
|
|
13
13
|
useEffect as useEffect2,
|
|
14
14
|
useLayoutEffect,
|
|
15
|
-
useRef
|
|
16
|
-
useState,
|
|
17
|
-
Suspense
|
|
15
|
+
useRef
|
|
18
16
|
} from "react";
|
|
19
17
|
|
|
20
18
|
// src/react/hydration.ts
|
|
@@ -36,197 +34,99 @@ function isReactHydrated(text) {
|
|
|
36
34
|
return true;
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
// src/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
(raw ?? "").split("|").map((pair) => {
|
|
64
|
-
const split = pair.lastIndexOf("~");
|
|
65
|
-
const at = Number(split < 0 ? "" : pair.slice(split + 1));
|
|
66
|
-
return {
|
|
67
|
-
path: split < 0 ? pair : pair.slice(0, split),
|
|
68
|
-
at: Number.isFinite(at) && at > 0 ? Math.floor(at) : 0
|
|
69
|
-
};
|
|
70
|
-
})
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// src/core/refresh-scheduler.ts
|
|
75
|
-
var VIEW_DELAYS_MS = [3e3, 1e4];
|
|
76
|
-
var INTENT_MIN_AGE_MS = 2e3;
|
|
77
|
-
var INTENT_EVENTS = ["pointerover", "focusin", "touchstart"];
|
|
78
|
-
var LISTENER = { capture: true, passive: true };
|
|
79
|
-
var COOKIE_PATTERN = new RegExp(`(?:^|; )${PREPR_REFRESH_COOKIE}=([^;]*)`);
|
|
80
|
-
var UNSUPPORTED_KEY = "prepr_refresh_unsupported";
|
|
81
|
-
function readEntries() {
|
|
82
|
-
const match = document.cookie.match(COOKIE_PATTERN);
|
|
83
|
-
try {
|
|
84
|
-
return parseRefresh(match ? decodeURIComponent(match[1]) : void 0);
|
|
85
|
-
} catch {
|
|
86
|
-
return [];
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
function unsupported() {
|
|
90
|
-
try {
|
|
91
|
-
return sessionStorage.getItem(UNSUPPORTED_KEY) === "1";
|
|
92
|
-
} catch {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function createPreprRefreshScheduler(options = {}) {
|
|
97
|
-
const freshFor = options.freshFor ?? 1e4;
|
|
98
|
-
let timers = [];
|
|
99
|
-
let inFlight = false;
|
|
100
|
-
let stopped = unsupported();
|
|
101
|
-
function refresh() {
|
|
102
|
-
if (inFlight || stopped) return;
|
|
103
|
-
const paths = readEntries().map((entry) => entry.path);
|
|
104
|
-
if (paths.length === 0) return;
|
|
105
|
-
inFlight = true;
|
|
106
|
-
const controller = new AbortController();
|
|
107
|
-
fetch(location.pathname, {
|
|
108
|
-
headers: { [PREPR_REFRESH_HEADER]: paths.join("|") },
|
|
109
|
-
cache: "no-store",
|
|
110
|
-
credentials: "same-origin",
|
|
111
|
-
signal: controller.signal
|
|
112
|
-
}).then((response) => {
|
|
113
|
-
if (response.status === 204) return;
|
|
114
|
-
stopped = true;
|
|
115
|
-
controller.abort();
|
|
116
|
-
try {
|
|
117
|
-
sessionStorage.setItem(UNSUPPORTED_KEY, "1");
|
|
118
|
-
} catch {
|
|
119
|
-
}
|
|
120
|
-
}).catch(() => void 0).finally(() => {
|
|
121
|
-
inFlight = false;
|
|
37
|
+
// src/nextjs/decision-switch.ts
|
|
38
|
+
function applyPreprDecisions(decision) {
|
|
39
|
+
const state = window;
|
|
40
|
+
const key = location.pathname + location.search;
|
|
41
|
+
if (decision !== void 0) state.__preprDecision = { key, value: decision };
|
|
42
|
+
const current = state.__preprDecision;
|
|
43
|
+
if (!current || current.key !== key) return false;
|
|
44
|
+
document.querySelectorAll("[data-prepr-decision]").forEach((marker) => {
|
|
45
|
+
marker.setAttribute("data-prepr-decided", "");
|
|
46
|
+
});
|
|
47
|
+
const defaults = current.value === "*";
|
|
48
|
+
const chosen = {};
|
|
49
|
+
current.value.split("~").forEach((pair) => {
|
|
50
|
+
const colon = pair.indexOf(":");
|
|
51
|
+
if (colon > 0)
|
|
52
|
+
chosen[pair.slice(0, colon)] = pair.slice(colon + 1).split("|");
|
|
53
|
+
});
|
|
54
|
+
document.querySelectorAll("[data-prepr-v]").forEach((element) => {
|
|
55
|
+
const nested = element.hasAttribute("data-prepr-nested");
|
|
56
|
+
const show = defaults ? element.hasAttribute("data-prepr-default") : (element.getAttribute("data-prepr-v") || "").split(" ").every((token) => {
|
|
57
|
+
const colon = token.indexOf(":");
|
|
58
|
+
const variant = token.slice(colon + 1);
|
|
59
|
+
const variants = chosen[token.slice(0, colon)];
|
|
60
|
+
return !!variants && (nested ? variants[0] === variant : variants.indexOf(variant) >= 0);
|
|
122
61
|
});
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
62
|
+
if (show) element.setAttribute("data-prepr-show", "");
|
|
63
|
+
else element.removeAttribute("data-prepr-show");
|
|
64
|
+
});
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
function requestPreprDecision(key, options = {}) {
|
|
68
|
+
const fresh = 1e4;
|
|
69
|
+
const keep = 18e5;
|
|
70
|
+
const keepStatic = 36e5;
|
|
71
|
+
const state = window;
|
|
72
|
+
const asking = state.__preprAsking = state.__preprAsking || {};
|
|
73
|
+
const read = () => {
|
|
128
74
|
try {
|
|
129
|
-
|
|
75
|
+
const all = JSON.parse(sessionStorage.getItem("prepr_decisions") || "{}");
|
|
76
|
+
return all && typeof all === "object" ? all : {};
|
|
130
77
|
} catch {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (url.origin !== location.origin) return;
|
|
134
|
-
const entry = readEntries().find((e) => e.path === url.pathname);
|
|
135
|
-
if (entry && !isFresh(entry.at, INTENT_MIN_AGE_MS)) refresh();
|
|
136
|
-
}
|
|
137
|
-
function onVisibility() {
|
|
138
|
-
if (document.visibilityState === "visible" && readEntries().some((entry) => !isFresh(entry.at, freshFor))) {
|
|
139
|
-
refresh();
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
for (const type of INTENT_EVENTS) {
|
|
143
|
-
document.addEventListener(type, onIntent, LISTENER);
|
|
144
|
-
}
|
|
145
|
-
document.addEventListener("visibilitychange", onVisibility, {
|
|
146
|
-
passive: true
|
|
147
|
-
});
|
|
148
|
-
return {
|
|
149
|
-
view() {
|
|
150
|
-
timers.forEach(clearTimeout);
|
|
151
|
-
timers = VIEW_DELAYS_MS.map((delay) => setTimeout(refresh, delay));
|
|
152
|
-
},
|
|
153
|
-
stop() {
|
|
154
|
-
timers.forEach(clearTimeout);
|
|
155
|
-
timers = [];
|
|
156
|
-
for (const type of INTENT_EVENTS) {
|
|
157
|
-
document.removeEventListener(type, onIntent, LISTENER);
|
|
158
|
-
}
|
|
159
|
-
document.removeEventListener("visibilitychange", onVisibility);
|
|
78
|
+
return {};
|
|
160
79
|
}
|
|
161
80
|
};
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
81
|
+
const ask = () => {
|
|
82
|
+
if (!asking[key]) {
|
|
83
|
+
asking[key] = fetch(key, {
|
|
84
|
+
headers: { "Prepr-Decide": "1" },
|
|
85
|
+
cache: "no-store",
|
|
86
|
+
credentials: "same-origin",
|
|
87
|
+
// The proxy gives up on Prepr after its own `timeoutMs`; this only
|
|
88
|
+
// covers a proxy that never answers.
|
|
89
|
+
signal: AbortSignal.timeout ? AbortSignal.timeout(6e3) : void 0
|
|
90
|
+
}).then((response) => response.ok ? response.text() : "*").catch(() => "*").then((answer) => {
|
|
91
|
+
delete asking[key];
|
|
92
|
+
try {
|
|
93
|
+
const all = read();
|
|
94
|
+
const at = Date.now();
|
|
95
|
+
Object.keys(all).forEach((stored) => {
|
|
96
|
+
const entry = all[stored];
|
|
97
|
+
if (!(entry && typeof entry.at === "number" && at - entry.at < keepStatic))
|
|
98
|
+
delete all[stored];
|
|
99
|
+
});
|
|
100
|
+
const kept = all[key];
|
|
101
|
+
if (answer !== "*" || !kept || kept.value === "*")
|
|
102
|
+
all[key] = { value: answer, at };
|
|
103
|
+
sessionStorage.setItem("prepr_decisions", JSON.stringify(all));
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
return answer;
|
|
107
|
+
});
|
|
177
108
|
}
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
109
|
+
return asking[key];
|
|
110
|
+
};
|
|
111
|
+
const last = read()[key];
|
|
112
|
+
const age = last && typeof last.at === "number" ? Date.now() - last.at : -1;
|
|
113
|
+
const value = last && typeof last.value === "string" ? last.value : null;
|
|
114
|
+
if (value !== null && !(value === "" && options.personalized) && age >= 0 && age < (value === "*" ? fresh : value === "" ? keepStatic : keep)) {
|
|
115
|
+
if (value !== "" && age >= fresh) {
|
|
116
|
+
ask().then((answer) => {
|
|
117
|
+
if (answer !== "*" && answer !== value && options.onChange)
|
|
118
|
+
options.onChange(answer);
|
|
119
|
+
});
|
|
183
120
|
}
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
function applyPreprDecisions(view) {
|
|
188
|
-
const viewState = window;
|
|
189
|
-
const current = view === void 0 ? location.pathname + location.search : view;
|
|
190
|
-
if (viewState.__preprDecisionsView === current) return;
|
|
191
|
-
viewState.__preprDecisionsView = current;
|
|
192
|
-
const match = document.cookie.match(/(?:^|; )prepr_decisions=([^;]*)/);
|
|
193
|
-
let raw;
|
|
194
|
-
try {
|
|
195
|
-
raw = match ? decodeURIComponent(match[1]) : "";
|
|
196
|
-
} catch {
|
|
197
|
-
raw = "";
|
|
121
|
+
return { result: value, value: Promise.resolve(value) };
|
|
198
122
|
}
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
raw.split("~").forEach((pair) => {
|
|
205
|
-
const at = pair.indexOf(":");
|
|
206
|
-
const group = pair.slice(0, at);
|
|
207
|
-
if (at < 1 || !id.test(group)) return;
|
|
208
|
-
const selector = '[data-prepr-group="' + group + '"]';
|
|
209
|
-
css += selector + "{display:none!important}";
|
|
210
|
-
pair.slice(at + 1).split("|").forEach((variant) => {
|
|
211
|
-
if (id.test(variant)) {
|
|
212
|
-
css += selector + '[data-prepr-variant="' + variant + '"]{display:contents!important}';
|
|
213
|
-
}
|
|
214
|
-
});
|
|
123
|
+
const pending = {
|
|
124
|
+
value: ask()
|
|
125
|
+
};
|
|
126
|
+
pending.value.then((answer) => {
|
|
127
|
+
pending.result = answer;
|
|
215
128
|
});
|
|
216
|
-
|
|
217
|
-
if (!state.__preprDecisionSheet) {
|
|
218
|
-
const sheet = new CSSStyleSheet();
|
|
219
|
-
document.adoptedStyleSheets = document.adoptedStyleSheets.concat(sheet);
|
|
220
|
-
state.__preprDecisionSheet = sheet;
|
|
221
|
-
}
|
|
222
|
-
state.__preprDecisionSheet.replaceSync(css);
|
|
223
|
-
} catch {
|
|
224
|
-
if (!state.__preprDecisionSheet) {
|
|
225
|
-
state.__preprDecisionSheet = document.createElement("style");
|
|
226
|
-
document.head.appendChild(state.__preprDecisionSheet);
|
|
227
|
-
}
|
|
228
|
-
state.__preprDecisionSheet.textContent = css;
|
|
229
|
-
}
|
|
129
|
+
return pending;
|
|
230
130
|
}
|
|
231
131
|
|
|
232
132
|
// src/react/components.ts
|
|
@@ -264,62 +164,124 @@ function PreprToolbar({
|
|
|
264
164
|
}, []);
|
|
265
165
|
return null;
|
|
266
166
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
167
|
+
var shown = /* @__PURE__ */ new Map();
|
|
168
|
+
var historyStep = false;
|
|
169
|
+
var onPopState = () => {
|
|
170
|
+
historyStep = true;
|
|
171
|
+
};
|
|
172
|
+
function requestDecision(key, personalized = false) {
|
|
173
|
+
return requestPreprDecision(key, {
|
|
174
|
+
personalized,
|
|
175
|
+
onChange: (value) => {
|
|
176
|
+
if (location.pathname + location.search !== key) return;
|
|
177
|
+
applyPreprDecisions(value);
|
|
178
|
+
shown.set(key, value);
|
|
179
|
+
}
|
|
270
180
|
});
|
|
271
|
-
return null;
|
|
272
181
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
182
|
+
function linkTarget(event) {
|
|
183
|
+
const anchor = event.target?.closest?.("a[href]");
|
|
184
|
+
if (!(anchor instanceof HTMLAnchorElement)) return null;
|
|
185
|
+
if (anchor.target && anchor.target !== "_self" || anchor.hasAttribute("download")) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const url = new URL(anchor.href, location.href);
|
|
189
|
+
const key = url.pathname + url.search;
|
|
190
|
+
if (url.origin !== location.origin || key === location.pathname + location.search) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
return key;
|
|
194
|
+
}
|
|
195
|
+
var HOVER_DELAY_MS = 65;
|
|
196
|
+
var hovering = null;
|
|
197
|
+
function onPointerOver(event) {
|
|
198
|
+
if (event.pointerType !== "mouse") return;
|
|
199
|
+
const key = linkTarget(event);
|
|
200
|
+
if (hovering?.key === key) return;
|
|
201
|
+
if (hovering) clearTimeout(hovering.timer);
|
|
202
|
+
hovering = key ? { key, timer: setTimeout(() => requestDecision(key), HOVER_DELAY_MS) } : null;
|
|
203
|
+
}
|
|
204
|
+
function onPointerDown(event) {
|
|
205
|
+
if (event.button !== 0) return;
|
|
206
|
+
const key = linkTarget(event);
|
|
207
|
+
if (key) requestDecision(key);
|
|
208
|
+
}
|
|
209
|
+
var listeners = 0;
|
|
210
|
+
function useDecisionRequests() {
|
|
288
211
|
useEffect2(() => {
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
|
|
212
|
+
if (listeners++ === 0) {
|
|
213
|
+
window.addEventListener("pointerover", onPointerOver, { passive: true });
|
|
214
|
+
window.addEventListener("pointerdown", onPointerDown, {
|
|
215
|
+
capture: true,
|
|
216
|
+
passive: true
|
|
217
|
+
});
|
|
218
|
+
window.addEventListener("popstate", onPopState);
|
|
219
|
+
}
|
|
292
220
|
return () => {
|
|
293
|
-
|
|
294
|
-
|
|
221
|
+
if (--listeners === 0) {
|
|
222
|
+
window.removeEventListener("pointerover", onPointerOver);
|
|
223
|
+
window.removeEventListener("pointerdown", onPointerDown, true);
|
|
224
|
+
window.removeEventListener("popstate", onPopState);
|
|
225
|
+
}
|
|
295
226
|
};
|
|
296
|
-
}, [
|
|
297
|
-
return scheduler ? createElement(
|
|
298
|
-
Suspense,
|
|
299
|
-
{ fallback: null },
|
|
300
|
-
createElement(ViewCounter, { scheduler })
|
|
301
|
-
) : null;
|
|
227
|
+
}, []);
|
|
302
228
|
}
|
|
303
|
-
function
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
229
|
+
function PreprPersonalizationSwitch() {
|
|
230
|
+
useDecisionRequests();
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
function PreprDecisionApplier() {
|
|
234
|
+
useDecisionRequests();
|
|
235
|
+
useLayoutEffect(() => {
|
|
236
|
+
const key = location.pathname + location.search;
|
|
237
|
+
const remember = () => {
|
|
238
|
+
const state = window.__preprDecision;
|
|
239
|
+
if (state) shown.set(key, state.value);
|
|
240
|
+
};
|
|
241
|
+
const previous = historyStep ? shown.get(key) : void 0;
|
|
242
|
+
historyStep = false;
|
|
243
|
+
if (applyPreprDecisions(previous)) {
|
|
244
|
+
remember();
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const pending = requestDecision(key, true);
|
|
248
|
+
if (pending.result !== void 0) {
|
|
249
|
+
applyPreprDecisions(pending.result);
|
|
250
|
+
remember();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
let live = true;
|
|
254
|
+
void pending.value.then((value) => {
|
|
255
|
+
if (live && location.pathname + location.search === key) {
|
|
256
|
+
applyPreprDecisions(value);
|
|
257
|
+
remember();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
return () => {
|
|
261
|
+
live = false;
|
|
262
|
+
};
|
|
263
|
+
});
|
|
310
264
|
return null;
|
|
311
265
|
}
|
|
312
266
|
var VARIANT_KEY_ATTRIBUTE = "data-prepr-variant-key";
|
|
313
267
|
function PreprVariantTracking({
|
|
314
268
|
variantKeys,
|
|
315
|
-
ab,
|
|
316
269
|
children
|
|
317
270
|
}) {
|
|
318
271
|
const ref = useRef(null);
|
|
319
272
|
const keys = variantKeys.join(" ");
|
|
320
273
|
useLayoutEffect(() => {
|
|
321
274
|
let tagged = [];
|
|
322
|
-
const
|
|
275
|
+
const wrapper = ref.current?.closest("[data-prepr-v]");
|
|
276
|
+
const shown2 = () => !wrapper || wrapper.hasAttribute("data-prepr-show");
|
|
277
|
+
const untag = () => {
|
|
278
|
+
for (const [element] of tagged)
|
|
279
|
+
element.removeAttribute(VARIANT_KEY_ATTRIBUTE);
|
|
280
|
+
tagged = [];
|
|
281
|
+
};
|
|
282
|
+
const tag = () => {
|
|
283
|
+
if (!shown2()) return untag();
|
|
284
|
+
if (tagged.length > 0) return;
|
|
323
285
|
const elements = [...ref.current?.children ?? []];
|
|
324
286
|
const list = keys.split(" ");
|
|
325
287
|
const pairs = elements.length === list.length ? elements.map((element, i) => [element, list[i]]) : elements.slice(0, 1).map((element) => [element, list[0]]);
|
|
@@ -328,22 +290,27 @@ function PreprVariantTracking({
|
|
|
328
290
|
element.setAttribute(VARIANT_KEY_ATTRIBUTE, key);
|
|
329
291
|
return true;
|
|
330
292
|
});
|
|
293
|
+
};
|
|
294
|
+
const timer = setTimeout(tag);
|
|
295
|
+
const observer = wrapper && new MutationObserver(tag);
|
|
296
|
+
observer?.observe(wrapper, {
|
|
297
|
+
attributes: true,
|
|
298
|
+
attributeFilter: ["data-prepr-show"]
|
|
331
299
|
});
|
|
332
300
|
return () => {
|
|
333
301
|
clearTimeout(timer);
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
302
|
+
observer?.disconnect();
|
|
303
|
+
untag();
|
|
337
304
|
};
|
|
338
305
|
}, [keys]);
|
|
339
306
|
return createElement(
|
|
340
307
|
"div",
|
|
341
|
-
|
|
308
|
+
{ ref, style: { display: "contents" } },
|
|
342
309
|
children
|
|
343
310
|
);
|
|
344
311
|
}
|
|
345
312
|
export {
|
|
346
|
-
|
|
313
|
+
PreprDecisionApplier,
|
|
347
314
|
PreprPersonalizationSwitch,
|
|
348
315
|
PreprToolbar,
|
|
349
316
|
PreprTrackingPixel,
|