@preprio/toolkit 0.5.0-rc.2 → 0.6.0-alpha.1
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 +415 -27
- package/dist/astro/chunk-O7N6GPAH.js +173 -0
- package/dist/astro/graphql.cjs +1030 -0
- package/dist/astro/graphql.d.cts +305 -0
- package/dist/astro/graphql.d.ts +305 -0
- package/dist/astro/graphql.js +936 -0
- package/dist/astro/index-XT_z-RYT.d.cts +130 -0
- package/dist/astro/index-XT_z-RYT.d.ts +130 -0
- package/dist/astro/index.cjs +14 -1
- package/dist/astro/index.d.cts +1 -120
- package/dist/astro/index.d.ts +1 -120
- package/dist/astro/index.js +15 -153
- package/dist/chunk-3JLWZQ37.js +179 -0
- package/dist/chunk-3NCEVJJ3.js +10 -0
- package/dist/chunk-S5RWVMDJ.js +148 -0
- package/dist/chunk-TBKSBXGH.js +452 -0
- package/dist/{chunk-FLPNN3CV.js → chunk-VI6QZTBM.js} +73 -276
- package/dist/chunk-YWIKKWBR.js +26 -0
- package/dist/graphql/codegen.cjs +510 -0
- package/dist/graphql/codegen.d.cts +23 -0
- package/dist/graphql/codegen.d.ts +23 -0
- package/dist/graphql/codegen.js +99 -0
- package/dist/graphql.cjs +941 -0
- package/dist/graphql.d.cts +305 -0
- package/dist/graphql.d.ts +305 -0
- package/dist/graphql.js +419 -0
- package/dist/index.cjs +76 -119
- package/dist/index.d.cts +12 -64
- package/dist/index.d.ts +12 -64
- package/dist/index.js +27 -167
- package/dist/nextjs/chunk-BQ6IGSH6.js +231 -0
- package/dist/nextjs/components.cjs +190 -122
- package/dist/nextjs/components.d.cts +33 -2
- package/dist/nextjs/components.d.ts +33 -2
- package/dist/nextjs/components.js +133 -4
- package/dist/nextjs/graphql.cjs +1362 -0
- package/dist/nextjs/graphql.d.cts +435 -0
- package/dist/nextjs/graphql.d.ts +435 -0
- package/dist/nextjs/graphql.js +1261 -0
- package/dist/nextjs/index.cjs +126 -6
- package/dist/nextjs/index.d.cts +53 -147
- package/dist/nextjs/index.d.ts +53 -147
- package/dist/nextjs/index.js +113 -203
- package/dist/nextjs/server-CjpELYvq.d.cts +156 -0
- package/dist/nextjs/server-CjpELYvq.d.ts +156 -0
- package/dist/nuxt/chunk-IQDSBPDN.js +417 -0
- package/dist/nuxt/graphql.cjs +1037 -0
- package/dist/nuxt/graphql.d.cts +302 -0
- package/dist/nuxt/graphql.d.ts +302 -0
- package/dist/nuxt/graphql.js +937 -0
- package/dist/nuxt/index.cjs +14 -1
- package/dist/nuxt/index.d.cts +3 -148
- package/dist/nuxt/index.d.ts +3 -148
- package/dist/nuxt/index.js +15 -391
- package/dist/nuxt/server-8v6OHbsw.d.cts +158 -0
- package/dist/nuxt/server-8v6OHbsw.d.ts +158 -0
- package/dist/pixel-DwW7cXJm.d.cts +49 -0
- package/dist/pixel-DwW7cXJm.d.ts +49 -0
- package/dist/react/components.cjs +88 -120
- package/dist/react/components.d.cts +2 -8
- package/dist/react/components.d.ts +2 -8
- package/dist/react/components.js +88 -120
- package/dist/server-Brr1UgtW.d.ts +59 -0
- package/dist/server-DJuS3YU0.d.cts +59 -0
- package/dist/sveltekit/chunk-OKYZ6HPH.js +413 -0
- package/dist/sveltekit/graphql.cjs +1043 -0
- package/dist/sveltekit/graphql.d.cts +307 -0
- package/dist/sveltekit/graphql.d.ts +307 -0
- package/dist/sveltekit/graphql.js +943 -0
- package/dist/sveltekit/index.cjs +14 -1
- package/dist/sveltekit/index.d.cts +3 -88
- package/dist/sveltekit/index.d.ts +3 -88
- package/dist/sveltekit/index.js +15 -387
- package/dist/sveltekit/server-CO847mEV.d.cts +98 -0
- package/dist/sveltekit/server-CO847mEV.d.ts +98 -0
- package/dist/{pixel-B3oQNbZ3.d.cts → types-BYH9XqmN.d.cts} +4 -58
- package/dist/{pixel-B3oQNbZ3.d.ts → types-BYH9XqmN.d.ts} +4 -58
- package/package.json +36 -1
|
@@ -21,8 +21,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
// src/nextjs/components.ts
|
|
22
22
|
var components_exports = {};
|
|
23
23
|
__export(components_exports, {
|
|
24
|
+
PreprAbSwitch: () => PreprAbSwitch,
|
|
24
25
|
PreprToolbar: () => PreprToolbar,
|
|
25
|
-
PreprTrackingPixel: () => PreprTrackingPixel
|
|
26
|
+
PreprTrackingPixel: () => PreprTrackingPixel,
|
|
27
|
+
PreprVariantTracking: () => PreprVariantTracking
|
|
26
28
|
});
|
|
27
29
|
module.exports = __toCommonJS(components_exports);
|
|
28
30
|
var import_navigation = require("next/navigation");
|
|
@@ -292,13 +294,9 @@ function createElementCache(query, ttl = 1e3) {
|
|
|
292
294
|
}
|
|
293
295
|
|
|
294
296
|
// src/core/iframe-bridge.ts
|
|
295
|
-
var debug = createScopedLogger("iframe-bridge");
|
|
296
297
|
var EDITOR_BASE_DOMAIN = "prepr.io";
|
|
297
298
|
function isAllowedEditorOrigin(origin, allowed) {
|
|
298
|
-
if (allowed)
|
|
299
|
-
if (allowed.includes("*")) return origin !== "null";
|
|
300
|
-
return allowed.includes(origin);
|
|
301
|
-
}
|
|
299
|
+
if (allowed) return allowed.includes(origin);
|
|
302
300
|
let url;
|
|
303
301
|
try {
|
|
304
302
|
url = new URL(origin);
|
|
@@ -313,7 +311,6 @@ function isAllowedEditorOrigin(origin, allowed) {
|
|
|
313
311
|
}
|
|
314
312
|
function createIframeBridge(store, options = {}) {
|
|
315
313
|
const allowedOrigins = options.allowedEditorOrigins;
|
|
316
|
-
const onScrollToField = options.onScrollToField;
|
|
317
314
|
let parentOrigin = null;
|
|
318
315
|
const onKeyDown = (event) => {
|
|
319
316
|
const key = event.key.toLowerCase();
|
|
@@ -323,10 +320,7 @@ function createIframeBridge(store, options = {}) {
|
|
|
323
320
|
const onMessage = (evt) => {
|
|
324
321
|
const data = evt?.data;
|
|
325
322
|
if (data?.event === "prepr:initVE" && !parentOrigin) {
|
|
326
|
-
if (!isAllowedEditorOrigin(evt.origin, allowedOrigins))
|
|
327
|
-
debug.warn("ignored editor handshake from origin", evt.origin);
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
323
|
+
if (!isAllowedEditorOrigin(evt.origin, allowedOrigins)) return;
|
|
330
324
|
parentOrigin = evt.origin;
|
|
331
325
|
setTrustedParentOrigin(parentOrigin);
|
|
332
326
|
if (data.scrollPosition != null) {
|
|
@@ -340,15 +334,6 @@ function createIframeBridge(store, options = {}) {
|
|
|
340
334
|
const currentScrollY = window.scrollY || document.documentElement.scrollTop;
|
|
341
335
|
sendPreprEvent("getScrollPosition", { value: currentScrollY });
|
|
342
336
|
}
|
|
343
|
-
if (data?.event === "prepr:scrollToField") {
|
|
344
|
-
if (typeof data.field !== "string" || !data.field) return;
|
|
345
|
-
if (data.id !== void 0 && typeof data.id !== "string") return;
|
|
346
|
-
try {
|
|
347
|
-
onScrollToField?.({ field: data.field, id: data.id });
|
|
348
|
-
} catch (error) {
|
|
349
|
-
debug.warn("scrollToField handler failed", error);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
337
|
};
|
|
353
338
|
return {
|
|
354
339
|
start() {
|
|
@@ -373,7 +358,7 @@ var import_stega2 = require("@vercel/stega");
|
|
|
373
358
|
|
|
374
359
|
// src/core/stega/clean.ts
|
|
375
360
|
var import_stega = require("@vercel/stega");
|
|
376
|
-
var
|
|
361
|
+
var debug = createScopedLogger("stega:clean");
|
|
377
362
|
function decodeStega(str) {
|
|
378
363
|
if (!str) return null;
|
|
379
364
|
try {
|
|
@@ -382,7 +367,7 @@ function decodeStega(str) {
|
|
|
382
367
|
return decoded;
|
|
383
368
|
}
|
|
384
369
|
} catch (error) {
|
|
385
|
-
|
|
370
|
+
debug.log("error decoding stega data", error);
|
|
386
371
|
const match = str.match(/{"origin.*?}/);
|
|
387
372
|
if (match) {
|
|
388
373
|
try {
|
|
@@ -391,7 +376,7 @@ function decodeStega(str) {
|
|
|
391
376
|
return decodedMatch;
|
|
392
377
|
}
|
|
393
378
|
} catch (innerError) {
|
|
394
|
-
|
|
379
|
+
debug.log("error decoding stega regex match", innerError);
|
|
395
380
|
}
|
|
396
381
|
}
|
|
397
382
|
}
|
|
@@ -427,37 +412,15 @@ function isRenderedElement(element) {
|
|
|
427
412
|
if (!style) return true;
|
|
428
413
|
return style.visibility !== "hidden" && style.display !== "none";
|
|
429
414
|
}
|
|
430
|
-
function parseEditHref(href) {
|
|
431
|
-
try {
|
|
432
|
-
const url = new URL(href, window.location.origin);
|
|
433
|
-
return {
|
|
434
|
-
id: url.pathname.split("/").pop() || void 0,
|
|
435
|
-
field: url.searchParams.get("field") || void 0,
|
|
436
|
-
locale: url.searchParams.get("locale") || void 0
|
|
437
|
-
};
|
|
438
|
-
} catch {
|
|
439
|
-
return {};
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
function setOrRemove(element, name, value) {
|
|
443
|
-
if (value) {
|
|
444
|
-
element.setAttribute(name, value);
|
|
445
|
-
} else {
|
|
446
|
-
element.removeAttribute(name);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
415
|
function tagEncodedElement(element, decoded) {
|
|
450
416
|
element.setAttribute("data-prepr-encoded", "");
|
|
451
417
|
element.setAttribute("data-prepr-href", decoded.href);
|
|
452
418
|
element.setAttribute("data-prepr-origin", decoded.origin);
|
|
453
|
-
const { id, field, locale } = parseEditHref(decoded.href);
|
|
454
|
-
setOrRemove(element, "data-prepr-id", id);
|
|
455
|
-
setOrRemove(element, "data-prepr-field", field);
|
|
456
|
-
setOrRemove(element, "data-prepr-locale", locale);
|
|
457
419
|
}
|
|
458
420
|
|
|
459
421
|
// src/core/stega/auto-clean.ts
|
|
460
|
-
var
|
|
422
|
+
var debug2 = createScopedLogger("stega:auto-clean");
|
|
423
|
+
var HYDRATION_RETRY_MS = 100;
|
|
461
424
|
function createStegaAutoClean(options) {
|
|
462
425
|
const stripText = options?.enabled ?? true;
|
|
463
426
|
let observer = null;
|
|
@@ -466,8 +429,29 @@ function createStegaAutoClean(options) {
|
|
|
466
429
|
let pendingHidden = /* @__PURE__ */ new Set();
|
|
467
430
|
let pendingDirty = /* @__PURE__ */ new Set();
|
|
468
431
|
let debounceTimeout = null;
|
|
432
|
+
const isHydrated = options?.isHydrated;
|
|
433
|
+
let pendingHydration = /* @__PURE__ */ new Set();
|
|
434
|
+
let hydrationTimeout = null;
|
|
435
|
+
function retryPendingHydration() {
|
|
436
|
+
hydrationTimeout = null;
|
|
437
|
+
processing = true;
|
|
438
|
+
const batch = [...pendingHydration];
|
|
439
|
+
pendingHydration.clear();
|
|
440
|
+
batch.forEach((textNode) => {
|
|
441
|
+
if (textNode.isConnected) cleanTextNode(textNode);
|
|
442
|
+
});
|
|
443
|
+
processing = false;
|
|
444
|
+
}
|
|
469
445
|
function cleanTextNode(textNode) {
|
|
470
446
|
if (isIgnoredTextNode(textNode)) return false;
|
|
447
|
+
if (isHydrated && !isHydrated(textNode)) {
|
|
448
|
+
pendingHydration.add(textNode);
|
|
449
|
+
hydrationTimeout ?? (hydrationTimeout = setTimeout(
|
|
450
|
+
retryPendingHydration,
|
|
451
|
+
HYDRATION_RETRY_MS
|
|
452
|
+
));
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
471
455
|
const textContent = textNode.textContent;
|
|
472
456
|
const info = cleaned.get(textNode);
|
|
473
457
|
const settled = stripText ? info?.cleaned : info?.original;
|
|
@@ -500,7 +484,7 @@ function createStegaAutoClean(options) {
|
|
|
500
484
|
}
|
|
501
485
|
pendingHidden.add(textNode);
|
|
502
486
|
} catch (error) {
|
|
503
|
-
|
|
487
|
+
debug2.log("error cleaning text node", error);
|
|
504
488
|
}
|
|
505
489
|
return false;
|
|
506
490
|
}
|
|
@@ -586,13 +570,17 @@ function createStegaAutoClean(options) {
|
|
|
586
570
|
if (observer || typeof window === "undefined") return;
|
|
587
571
|
scanAndClean();
|
|
588
572
|
setupObserver();
|
|
589
|
-
|
|
573
|
+
debug2.log("stega auto-clean started");
|
|
590
574
|
}
|
|
591
575
|
function stop() {
|
|
592
576
|
if (debounceTimeout) {
|
|
593
577
|
clearTimeout(debounceTimeout);
|
|
594
578
|
debounceTimeout = null;
|
|
595
579
|
}
|
|
580
|
+
if (hydrationTimeout) {
|
|
581
|
+
clearTimeout(hydrationTimeout);
|
|
582
|
+
hydrationTimeout = null;
|
|
583
|
+
}
|
|
596
584
|
if (observer) {
|
|
597
585
|
observer.disconnect();
|
|
598
586
|
observer = null;
|
|
@@ -600,13 +588,14 @@ function createStegaAutoClean(options) {
|
|
|
600
588
|
cleaned = /* @__PURE__ */ new WeakMap();
|
|
601
589
|
pendingHidden = /* @__PURE__ */ new Set();
|
|
602
590
|
pendingDirty = /* @__PURE__ */ new Set();
|
|
603
|
-
|
|
591
|
+
pendingHydration = /* @__PURE__ */ new Set();
|
|
592
|
+
debug2.log("stega auto-clean stopped");
|
|
604
593
|
}
|
|
605
594
|
return { start, stop };
|
|
606
595
|
}
|
|
607
596
|
|
|
608
597
|
// src/core/stega/elements.ts
|
|
609
|
-
var
|
|
598
|
+
var debug3 = createScopedLogger("stega:elements");
|
|
610
599
|
var StegaElements = class {
|
|
611
600
|
constructor(decode = decodeStega) {
|
|
612
601
|
this.observer = null;
|
|
@@ -651,7 +640,7 @@ var StegaElements = class {
|
|
|
651
640
|
walkTextNodes(document.body, (textNode) => {
|
|
652
641
|
if (this.tagFromTextNode(textNode)) encodedCount++;
|
|
653
642
|
});
|
|
654
|
-
|
|
643
|
+
debug3.log("document scan complete, encoded", encodedCount, "elements");
|
|
655
644
|
this.elements = document.querySelectorAll("[data-prepr-encoded]");
|
|
656
645
|
}
|
|
657
646
|
/** `onUpdate` fires after each debounced batch, for refreshing derived state. */
|
|
@@ -707,9 +696,6 @@ var StegaElements = class {
|
|
|
707
696
|
element.removeAttribute("data-prepr-encoded");
|
|
708
697
|
element.removeAttribute("data-prepr-href");
|
|
709
698
|
element.removeAttribute("data-prepr-origin");
|
|
710
|
-
element.removeAttribute("data-prepr-id");
|
|
711
|
-
element.removeAttribute("data-prepr-field");
|
|
712
|
-
element.removeAttribute("data-prepr-locale");
|
|
713
699
|
element.classList.remove("prepr-overlay-active");
|
|
714
700
|
});
|
|
715
701
|
this.elements = void 0;
|
|
@@ -717,7 +703,7 @@ var StegaElements = class {
|
|
|
717
703
|
};
|
|
718
704
|
|
|
719
705
|
// src/core/stega/overlay.ts
|
|
720
|
-
var
|
|
706
|
+
var debug4 = createScopedLogger("stega:overlay");
|
|
721
707
|
var StegaOverlay = class {
|
|
722
708
|
constructor(onEdit) {
|
|
723
709
|
this.overlay = null;
|
|
@@ -762,8 +748,7 @@ var StegaOverlay = class {
|
|
|
762
748
|
const origin = element.getAttribute("data-prepr-origin");
|
|
763
749
|
const id = element.getAttribute("data-prepr-id") ?? void 0;
|
|
764
750
|
const field = element.getAttribute("data-prepr-field") ?? void 0;
|
|
765
|
-
|
|
766
|
-
debug5.log("showing overlay", { href, origin });
|
|
751
|
+
debug4.log("showing overlay", { href, origin });
|
|
767
752
|
const overlay = this.overlay;
|
|
768
753
|
overlay.style.display = "block";
|
|
769
754
|
overlay.style.top = `${rect.top + window.scrollY - 2}px`;
|
|
@@ -795,7 +780,7 @@ var StegaOverlay = class {
|
|
|
795
780
|
tooltip.style.left = `${left}px`;
|
|
796
781
|
});
|
|
797
782
|
tooltip.onclick = () => {
|
|
798
|
-
this.onEdit({ href, origin, id, field
|
|
783
|
+
this.onEdit({ href, origin, id, field });
|
|
799
784
|
};
|
|
800
785
|
}
|
|
801
786
|
this.currentElement = element;
|
|
@@ -835,7 +820,7 @@ var StegaOverlay = class {
|
|
|
835
820
|
};
|
|
836
821
|
|
|
837
822
|
// src/core/stega/proximity.ts
|
|
838
|
-
var
|
|
823
|
+
var debug5 = createScopedLogger("stega:proximity");
|
|
839
824
|
var StegaProximity = class {
|
|
840
825
|
constructor() {
|
|
841
826
|
this.highlighted = /* @__PURE__ */ new Set();
|
|
@@ -870,9 +855,9 @@ var StegaProximity = class {
|
|
|
870
855
|
);
|
|
871
856
|
const nodes = this.getEncodedElements();
|
|
872
857
|
nodes.forEach((el) => this.observer.observe(el));
|
|
873
|
-
|
|
858
|
+
debug5.log("observing", nodes.length, "encoded elements");
|
|
874
859
|
} catch (error) {
|
|
875
|
-
|
|
860
|
+
debug5.log("error setting up IntersectionObserver", error);
|
|
876
861
|
}
|
|
877
862
|
}
|
|
878
863
|
stopObserving() {
|
|
@@ -942,7 +927,7 @@ function removeStegaStyles() {
|
|
|
942
927
|
}
|
|
943
928
|
|
|
944
929
|
// src/core/stega/scan.ts
|
|
945
|
-
var
|
|
930
|
+
var debug6 = createScopedLogger("stega:scan");
|
|
946
931
|
var EDITOR_MODE_STYLES = "[data-prepr-encoded]{cursor:pointer}";
|
|
947
932
|
function createStegaController(opts) {
|
|
948
933
|
const tooltipEnabled = opts.tooltip ?? true;
|
|
@@ -975,13 +960,12 @@ function createStegaController(opts) {
|
|
|
975
960
|
href: encoded.getAttribute("data-prepr-href") ?? "",
|
|
976
961
|
origin: encoded.getAttribute("data-prepr-origin") ?? "",
|
|
977
962
|
id: encoded.getAttribute("data-prepr-id") ?? void 0,
|
|
978
|
-
field: encoded.getAttribute("data-prepr-field") ?? void 0
|
|
979
|
-
locale: encoded.getAttribute("data-prepr-locale") ?? void 0
|
|
963
|
+
field: encoded.getAttribute("data-prepr-field") ?? void 0
|
|
980
964
|
});
|
|
981
965
|
};
|
|
982
966
|
const start = () => {
|
|
983
967
|
if (initialized) {
|
|
984
|
-
|
|
968
|
+
debug6.log("already initialized, skipping setup");
|
|
985
969
|
return;
|
|
986
970
|
}
|
|
987
971
|
if (!tooltipEnabled) {
|
|
@@ -991,7 +975,7 @@ function createStegaController(opts) {
|
|
|
991
975
|
});
|
|
992
976
|
document.addEventListener("click", handleClick, { capture: true });
|
|
993
977
|
initialized = true;
|
|
994
|
-
|
|
978
|
+
debug6.log("stega controller started (editor mode)");
|
|
995
979
|
return;
|
|
996
980
|
}
|
|
997
981
|
injectStegaStyles();
|
|
@@ -1022,7 +1006,7 @@ function createStegaController(opts) {
|
|
|
1022
1006
|
passive: true
|
|
1023
1007
|
});
|
|
1024
1008
|
initialized = true;
|
|
1025
|
-
|
|
1009
|
+
debug6.log("stega controller started");
|
|
1026
1010
|
};
|
|
1027
1011
|
const stop = () => {
|
|
1028
1012
|
if (!initialized) return;
|
|
@@ -1031,7 +1015,7 @@ function createStegaController(opts) {
|
|
|
1031
1015
|
elements.cleanup();
|
|
1032
1016
|
removeStegaStyles();
|
|
1033
1017
|
initialized = false;
|
|
1034
|
-
|
|
1018
|
+
debug6.log("stega controller stopped (editor mode)");
|
|
1035
1019
|
return;
|
|
1036
1020
|
}
|
|
1037
1021
|
if (throttledMouseMove) {
|
|
@@ -1051,43 +1035,11 @@ function createStegaController(opts) {
|
|
|
1051
1035
|
elements.cleanup();
|
|
1052
1036
|
removeStegaStyles();
|
|
1053
1037
|
initialized = false;
|
|
1054
|
-
|
|
1038
|
+
debug6.log("stega controller stopped");
|
|
1055
1039
|
};
|
|
1056
1040
|
return { start, stop };
|
|
1057
1041
|
}
|
|
1058
1042
|
|
|
1059
|
-
// src/core/stega/scroll-to-field.ts
|
|
1060
|
-
var debug8 = createScopedLogger("stega:scroll");
|
|
1061
|
-
var FLASH_DURATION_MS = 1200;
|
|
1062
|
-
var flashTimeout = null;
|
|
1063
|
-
function scrollToField(request) {
|
|
1064
|
-
const { field, id } = request;
|
|
1065
|
-
if (!field) return false;
|
|
1066
|
-
const candidates = document.querySelectorAll(
|
|
1067
|
-
"[data-prepr-encoded]"
|
|
1068
|
-
);
|
|
1069
|
-
let target = null;
|
|
1070
|
-
for (const candidate of candidates) {
|
|
1071
|
-
if (candidate.getAttribute("data-prepr-field") !== field) continue;
|
|
1072
|
-
if (id && candidate.getAttribute("data-prepr-id") !== id) continue;
|
|
1073
|
-
target = candidate;
|
|
1074
|
-
break;
|
|
1075
|
-
}
|
|
1076
|
-
if (!target) {
|
|
1077
|
-
debug8.log("no element found for field", field);
|
|
1078
|
-
return false;
|
|
1079
|
-
}
|
|
1080
|
-
target.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
1081
|
-
if (flashTimeout) clearTimeout(flashTimeout);
|
|
1082
|
-
document.querySelectorAll(".prepr-overlay-active").forEach((el) => el.classList.remove("prepr-overlay-active"));
|
|
1083
|
-
target.classList.add("prepr-overlay-active");
|
|
1084
|
-
flashTimeout = setTimeout(() => {
|
|
1085
|
-
target.classList.remove("prepr-overlay-active");
|
|
1086
|
-
flashTimeout = null;
|
|
1087
|
-
}, FLASH_DURATION_MS);
|
|
1088
|
-
return true;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
1043
|
// src/core/store.ts
|
|
1092
1044
|
var DEFAULT_STATE = {
|
|
1093
1045
|
locale: "en",
|
|
@@ -2200,7 +2152,7 @@ function definePreprToolbar() {
|
|
|
2200
2152
|
}
|
|
2201
2153
|
|
|
2202
2154
|
// src/core/create-preview.ts
|
|
2203
|
-
var
|
|
2155
|
+
var debug7 = createScopedLogger("create-preview");
|
|
2204
2156
|
var controllerStores = /* @__PURE__ */ new WeakMap();
|
|
2205
2157
|
function defaultNavigation() {
|
|
2206
2158
|
return {
|
|
@@ -2242,7 +2194,7 @@ function createPreprPreview(opts = {}) {
|
|
|
2242
2194
|
const search = new URLSearchParams(window.location.search);
|
|
2243
2195
|
const hideBar = search.get(PARAM_HIDE_BAR) === "true";
|
|
2244
2196
|
if (hideBar) {
|
|
2245
|
-
|
|
2197
|
+
debug7.log(`${PARAM_HIDE_BAR}=true \u2014 no visible toolbar`);
|
|
2246
2198
|
}
|
|
2247
2199
|
const mountUi = (options?.ui ?? true) && !isIframe && !hideBar;
|
|
2248
2200
|
const locale = resolveLocale(options);
|
|
@@ -2278,17 +2230,18 @@ function createPreprPreview(opts = {}) {
|
|
|
2278
2230
|
tooltip: mountUi,
|
|
2279
2231
|
// In the editor, ask the parent to focus the field instead of opening a new
|
|
2280
2232
|
// tab. Standalone previews keep the window.open behaviour.
|
|
2281
|
-
onEdit: ({ href, id, field
|
|
2233
|
+
onEdit: ({ href, origin, id, field }) => {
|
|
2282
2234
|
const safeHref = href ? safeEditUrl(href) : null;
|
|
2283
2235
|
if (href && !safeHref) {
|
|
2284
|
-
|
|
2236
|
+
debug7.warn("ignored edit request with unsupported href scheme");
|
|
2285
2237
|
return;
|
|
2286
2238
|
}
|
|
2287
2239
|
if (isIframe) {
|
|
2288
2240
|
sendPreprEvent("field_edit_requested", {
|
|
2241
|
+
href: safeHref ?? void 0,
|
|
2242
|
+
origin,
|
|
2289
2243
|
id,
|
|
2290
|
-
field
|
|
2291
|
-
locale: contentLocale
|
|
2244
|
+
field
|
|
2292
2245
|
});
|
|
2293
2246
|
} else if (safeHref) {
|
|
2294
2247
|
window.open(safeHref, "_blank", "noopener,noreferrer");
|
|
@@ -2296,7 +2249,8 @@ function createPreprPreview(opts = {}) {
|
|
|
2296
2249
|
}
|
|
2297
2250
|
});
|
|
2298
2251
|
const autoClean = createStegaAutoClean({
|
|
2299
|
-
enabled: options?.autoClean
|
|
2252
|
+
enabled: options?.autoClean,
|
|
2253
|
+
isHydrated: opts.isHydrated
|
|
2300
2254
|
});
|
|
2301
2255
|
autoClean.start();
|
|
2302
2256
|
const handleChange = createChangeHandler({
|
|
@@ -2315,15 +2269,7 @@ function createPreprPreview(opts = {}) {
|
|
|
2315
2269
|
handleChange(before, state);
|
|
2316
2270
|
});
|
|
2317
2271
|
const bridge = createIframeBridge(store, {
|
|
2318
|
-
allowedEditorOrigins: options?.allowedEditorOrigins
|
|
2319
|
-
// The editor selecting a field scrolls the matching element into view. The
|
|
2320
|
-
// lookup relies on the attributes the stega scan writes, so it finds
|
|
2321
|
-
// nothing until encoded content has been tagged.
|
|
2322
|
-
onScrollToField: ({ field, id }) => {
|
|
2323
|
-
if (!scrollToField({ field, id })) {
|
|
2324
|
-
debug9.log("no element on this page renders field", field);
|
|
2325
|
-
}
|
|
2326
|
-
}
|
|
2272
|
+
allowedEditorOrigins: options?.allowedEditorOrigins
|
|
2327
2273
|
});
|
|
2328
2274
|
sendPreprEvent(
|
|
2329
2275
|
"getScrollPosition",
|
|
@@ -2343,18 +2289,101 @@ function createPreprPreview(opts = {}) {
|
|
|
2343
2289
|
bridge.stop();
|
|
2344
2290
|
}
|
|
2345
2291
|
el?.remove();
|
|
2346
|
-
|
|
2292
|
+
debug7.log("preview destroyed");
|
|
2347
2293
|
}
|
|
2348
2294
|
const controller = { destroy };
|
|
2349
2295
|
controllerStores.set(controller, store);
|
|
2350
2296
|
return controller;
|
|
2351
2297
|
}
|
|
2352
2298
|
|
|
2299
|
+
// src/react/hydration.ts
|
|
2300
|
+
var PROPS_KEY_PREFIX = "__reactProps$";
|
|
2301
|
+
function reactProps(element) {
|
|
2302
|
+
for (const key of Object.keys(element)) {
|
|
2303
|
+
if (key.startsWith(PROPS_KEY_PREFIX)) {
|
|
2304
|
+
return element[key];
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
return void 0;
|
|
2308
|
+
}
|
|
2309
|
+
function isReactHydrated(text) {
|
|
2310
|
+
for (let el = text.parentElement; el; el = el.parentElement) {
|
|
2311
|
+
const props = reactProps(el);
|
|
2312
|
+
if (!props) continue;
|
|
2313
|
+
return el === text.parentElement || props.dangerouslySetInnerHTML != null;
|
|
2314
|
+
}
|
|
2315
|
+
return true;
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
// src/nextjs/ab-switch.ts
|
|
2319
|
+
function applyPreprAbBucket() {
|
|
2320
|
+
const match = document.cookie.match(/(?:^|; )prepr_ab_bucket=([AB])(?:;|$)/);
|
|
2321
|
+
const bucket = match ? match[1] : "A";
|
|
2322
|
+
const state = window;
|
|
2323
|
+
if (state.__preprAbBucket === bucket) return;
|
|
2324
|
+
state.__preprAbBucket = bucket;
|
|
2325
|
+
const css = bucket === "A" ? "" : '[data-prepr-ab="A"]{display:none!important}[data-prepr-ab="' + bucket + '"]{display:contents!important}';
|
|
2326
|
+
try {
|
|
2327
|
+
if (!state.__preprAbSheet) {
|
|
2328
|
+
const sheet = new CSSStyleSheet();
|
|
2329
|
+
document.adoptedStyleSheets = document.adoptedStyleSheets.concat(sheet);
|
|
2330
|
+
state.__preprAbSheet = sheet;
|
|
2331
|
+
}
|
|
2332
|
+
state.__preprAbSheet.replaceSync(css);
|
|
2333
|
+
} catch {
|
|
2334
|
+
if (!state.__preprAbSheet) {
|
|
2335
|
+
state.__preprAbSheet = document.createElement("style");
|
|
2336
|
+
document.head.appendChild(state.__preprAbSheet);
|
|
2337
|
+
}
|
|
2338
|
+
state.__preprAbSheet.textContent = css;
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
function applyPreprDecisions() {
|
|
2342
|
+
const match = document.cookie.match(/(?:^|; )prepr_decisions=([^;]*)/);
|
|
2343
|
+
let raw;
|
|
2344
|
+
try {
|
|
2345
|
+
raw = match ? decodeURIComponent(match[1]) : "";
|
|
2346
|
+
} catch {
|
|
2347
|
+
raw = "";
|
|
2348
|
+
}
|
|
2349
|
+
const state = window;
|
|
2350
|
+
if (state.__preprDecisions === raw) return;
|
|
2351
|
+
state.__preprDecisions = raw;
|
|
2352
|
+
const id = /^[\w-]+$/;
|
|
2353
|
+
let css = "";
|
|
2354
|
+
raw.split("~").forEach((pair) => {
|
|
2355
|
+
const at = pair.indexOf(":");
|
|
2356
|
+
const group = pair.slice(0, at);
|
|
2357
|
+
if (at < 1 || !id.test(group)) return;
|
|
2358
|
+
const selector = '[data-prepr-group="' + group + '"]';
|
|
2359
|
+
css += selector + "{display:none!important}";
|
|
2360
|
+
pair.slice(at + 1).split("|").forEach((variant) => {
|
|
2361
|
+
if (id.test(variant)) {
|
|
2362
|
+
css += selector + '[data-prepr-variant="' + variant + '"]{display:contents!important}';
|
|
2363
|
+
}
|
|
2364
|
+
});
|
|
2365
|
+
});
|
|
2366
|
+
try {
|
|
2367
|
+
if (!state.__preprDecisionSheet) {
|
|
2368
|
+
const sheet = new CSSStyleSheet();
|
|
2369
|
+
document.adoptedStyleSheets = document.adoptedStyleSheets.concat(sheet);
|
|
2370
|
+
state.__preprDecisionSheet = sheet;
|
|
2371
|
+
}
|
|
2372
|
+
state.__preprDecisionSheet.replaceSync(css);
|
|
2373
|
+
} catch {
|
|
2374
|
+
if (!state.__preprDecisionSheet) {
|
|
2375
|
+
state.__preprDecisionSheet = document.createElement("style");
|
|
2376
|
+
document.head.appendChild(state.__preprDecisionSheet);
|
|
2377
|
+
}
|
|
2378
|
+
state.__preprDecisionSheet.textContent = css;
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2353
2382
|
// src/react/components.ts
|
|
2354
2383
|
var import_react = require("react");
|
|
2355
2384
|
|
|
2356
2385
|
// src/version.ts
|
|
2357
|
-
var VERSION = "0.
|
|
2386
|
+
var VERSION = "0.6.0-alpha.1";
|
|
2358
2387
|
|
|
2359
2388
|
// src/core/pixel.ts
|
|
2360
2389
|
var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr.min.js";
|
|
@@ -2422,14 +2451,53 @@ function PreprToolbar({
|
|
|
2422
2451
|
navigation: {
|
|
2423
2452
|
navigate: (url) => router.push(url),
|
|
2424
2453
|
currentPath: () => pathnameRef.current + window.location.search
|
|
2425
|
-
}
|
|
2454
|
+
},
|
|
2455
|
+
isHydrated: isReactHydrated
|
|
2426
2456
|
});
|
|
2427
2457
|
return () => toolbar.destroy();
|
|
2428
2458
|
}, []);
|
|
2429
2459
|
return null;
|
|
2430
2460
|
}
|
|
2461
|
+
function PreprAbSwitch() {
|
|
2462
|
+
(0, import_react2.useLayoutEffect)(() => {
|
|
2463
|
+
applyPreprAbBucket();
|
|
2464
|
+
applyPreprDecisions();
|
|
2465
|
+
});
|
|
2466
|
+
return null;
|
|
2467
|
+
}
|
|
2468
|
+
var VARIANT_KEY_ATTRIBUTE = "data-prepr-variant-key";
|
|
2469
|
+
function PreprVariantTracking({
|
|
2470
|
+
variantKeys,
|
|
2471
|
+
ab,
|
|
2472
|
+
children
|
|
2473
|
+
}) {
|
|
2474
|
+
const ref = (0, import_react2.useRef)(null);
|
|
2475
|
+
const keys = variantKeys.join(" ");
|
|
2476
|
+
(0, import_react2.useLayoutEffect)(() => {
|
|
2477
|
+
const elements = [...ref.current?.children ?? []];
|
|
2478
|
+
const list = keys.split(" ");
|
|
2479
|
+
const pairs = elements.length === list.length ? elements.map((element, i2) => [element, list[i2]]) : elements.slice(0, 1).map((element) => [element, list[0]]);
|
|
2480
|
+
const tagged = pairs.filter(([element, key]) => {
|
|
2481
|
+
if (element.hasAttribute(VARIANT_KEY_ATTRIBUTE)) return false;
|
|
2482
|
+
element.setAttribute(VARIANT_KEY_ATTRIBUTE, key);
|
|
2483
|
+
return true;
|
|
2484
|
+
});
|
|
2485
|
+
return () => {
|
|
2486
|
+
for (const [element] of tagged) {
|
|
2487
|
+
element.removeAttribute(VARIANT_KEY_ATTRIBUTE);
|
|
2488
|
+
}
|
|
2489
|
+
};
|
|
2490
|
+
}, [keys]);
|
|
2491
|
+
return (0, import_react2.createElement)(
|
|
2492
|
+
"div",
|
|
2493
|
+
ab === void 0 ? { ref, style: { display: "contents" } } : { ref, "data-prepr-ab": ab },
|
|
2494
|
+
children
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
2431
2497
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2432
2498
|
0 && (module.exports = {
|
|
2499
|
+
PreprAbSwitch,
|
|
2433
2500
|
PreprToolbar,
|
|
2434
|
-
PreprTrackingPixel
|
|
2501
|
+
PreprTrackingPixel,
|
|
2502
|
+
PreprVariantTracking
|
|
2435
2503
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactNode, ReactElement } from 'react';
|
|
2
|
+
import { k as PreprToolbarComponentProps } from '../types-BYH9XqmN.cjs';
|
|
3
|
+
import { P as PreprPixelConfig } from '../pixel-DwW7cXJm.cjs';
|
|
2
4
|
|
|
3
5
|
interface PreprTrackingPixelProps {
|
|
4
6
|
/** Prepr tracking/access token. */
|
|
@@ -20,5 +22,34 @@ declare function PreprTrackingPixel({ id, config, }: PreprTrackingPixelProps): n
|
|
|
20
22
|
* `createPreprPreview` mounts imperatively.
|
|
21
23
|
*/
|
|
22
24
|
declare function PreprToolbar({ options, ...props }: PreprToolbarComponentProps): null;
|
|
25
|
+
/**
|
|
26
|
+
* Applies the visitor's A/B bucket, and the segment variants decided in the
|
|
27
|
+
* proxy, after client-side navigation. A full page
|
|
28
|
+
* load is covered by the inline script `PreprStack` renders, but React does
|
|
29
|
+
* not run inline scripts that arrive with a client-side navigation; a layout
|
|
30
|
+
* effect still runs before the browser paints the new page. Rendered by
|
|
31
|
+
* `PreprStack`; you do not need it yourself.
|
|
32
|
+
*/
|
|
33
|
+
declare function PreprAbSwitch(): null;
|
|
34
|
+
/**
|
|
35
|
+
* Wraps one rendered variant and, once hydrated, puts the variant keys on the
|
|
36
|
+
* elements inside, where Prepr's tracking pixel counts impressions and the
|
|
37
|
+
* clicks of any `data-prepr-variant-event` element in them. The wrapper itself
|
|
38
|
+
* takes no box (`display: contents`), and the pixel only counts an element it
|
|
39
|
+
* can see scroll into view, so the keys belong on the sections. The pixel
|
|
40
|
+
* watches for attributes added after load.
|
|
41
|
+
*
|
|
42
|
+
* A variant can hold several items, each with its own key. When the wrapper
|
|
43
|
+
* holds one element per key they are paired in order; otherwise only the
|
|
44
|
+
* first element is tagged, with the first key. An element that already
|
|
45
|
+
* carries a variant key is left alone. Rendered by `PreprStack` with
|
|
46
|
+
* `trackVariants`; you do not need it yourself.
|
|
47
|
+
*/
|
|
48
|
+
declare function PreprVariantTracking({ variantKeys, ab, children, }: {
|
|
49
|
+
variantKeys: string[];
|
|
50
|
+
/** The A/B bucket wrapper this also serves as; its CSS decides `display`. */
|
|
51
|
+
ab?: string;
|
|
52
|
+
children?: ReactNode;
|
|
53
|
+
}): ReactElement;
|
|
23
54
|
|
|
24
|
-
export { PreprToolbar, PreprTrackingPixel, type PreprTrackingPixelProps };
|
|
55
|
+
export { PreprAbSwitch, PreprToolbar, PreprTrackingPixel, type PreprTrackingPixelProps, PreprVariantTracking };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactNode, ReactElement } from 'react';
|
|
2
|
+
import { k as PreprToolbarComponentProps } from '../types-BYH9XqmN.js';
|
|
3
|
+
import { P as PreprPixelConfig } from '../pixel-DwW7cXJm.js';
|
|
2
4
|
|
|
3
5
|
interface PreprTrackingPixelProps {
|
|
4
6
|
/** Prepr tracking/access token. */
|
|
@@ -20,5 +22,34 @@ declare function PreprTrackingPixel({ id, config, }: PreprTrackingPixelProps): n
|
|
|
20
22
|
* `createPreprPreview` mounts imperatively.
|
|
21
23
|
*/
|
|
22
24
|
declare function PreprToolbar({ options, ...props }: PreprToolbarComponentProps): null;
|
|
25
|
+
/**
|
|
26
|
+
* Applies the visitor's A/B bucket, and the segment variants decided in the
|
|
27
|
+
* proxy, after client-side navigation. A full page
|
|
28
|
+
* load is covered by the inline script `PreprStack` renders, but React does
|
|
29
|
+
* not run inline scripts that arrive with a client-side navigation; a layout
|
|
30
|
+
* effect still runs before the browser paints the new page. Rendered by
|
|
31
|
+
* `PreprStack`; you do not need it yourself.
|
|
32
|
+
*/
|
|
33
|
+
declare function PreprAbSwitch(): null;
|
|
34
|
+
/**
|
|
35
|
+
* Wraps one rendered variant and, once hydrated, puts the variant keys on the
|
|
36
|
+
* elements inside, where Prepr's tracking pixel counts impressions and the
|
|
37
|
+
* clicks of any `data-prepr-variant-event` element in them. The wrapper itself
|
|
38
|
+
* takes no box (`display: contents`), and the pixel only counts an element it
|
|
39
|
+
* can see scroll into view, so the keys belong on the sections. The pixel
|
|
40
|
+
* watches for attributes added after load.
|
|
41
|
+
*
|
|
42
|
+
* A variant can hold several items, each with its own key. When the wrapper
|
|
43
|
+
* holds one element per key they are paired in order; otherwise only the
|
|
44
|
+
* first element is tagged, with the first key. An element that already
|
|
45
|
+
* carries a variant key is left alone. Rendered by `PreprStack` with
|
|
46
|
+
* `trackVariants`; you do not need it yourself.
|
|
47
|
+
*/
|
|
48
|
+
declare function PreprVariantTracking({ variantKeys, ab, children, }: {
|
|
49
|
+
variantKeys: string[];
|
|
50
|
+
/** The A/B bucket wrapper this also serves as; its CSS decides `display`. */
|
|
51
|
+
ab?: string;
|
|
52
|
+
children?: ReactNode;
|
|
53
|
+
}): ReactElement;
|
|
23
54
|
|
|
24
|
-
export { PreprToolbar, PreprTrackingPixel, type PreprTrackingPixelProps };
|
|
55
|
+
export { PreprAbSwitch, PreprToolbar, PreprTrackingPixel, type PreprTrackingPixelProps, PreprVariantTracking };
|