@preprio/toolkit 0.4.3 → 0.5.0-rc.2
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 +8 -8
- package/dist/astro/index.cjs +1 -1
- package/dist/astro/index.js +1 -1
- package/dist/{chunk-H7VA7NGY.js → chunk-FLPNN3CV.js} +98 -14
- package/dist/index.cjs +118 -34
- package/dist/index.d.cts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +1 -1
- package/dist/nextjs/components.cjs +118 -34
- package/dist/nextjs/components.d.cts +1 -1
- package/dist/nextjs/components.d.ts +1 -1
- package/dist/nextjs/components.js +1 -1
- package/dist/nextjs/index.cjs +1 -1
- package/dist/nextjs/index.d.cts +8 -2
- package/dist/nextjs/index.d.ts +8 -2
- package/dist/nextjs/index.js +1 -1
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/{pixel-e1fUWl2Y.d.cts → pixel-B3oQNbZ3.d.cts} +8 -2
- package/dist/{pixel-e1fUWl2Y.d.ts → pixel-B3oQNbZ3.d.ts} +8 -2
- package/dist/react/components.cjs +118 -34
- package/dist/react/components.d.cts +8 -2
- package/dist/react/components.d.ts +8 -2
- package/dist/react/components.js +118 -34
- package/dist/sveltekit/index.cjs +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/package.json +1 -1
package/dist/react/components.js
CHANGED
|
@@ -267,9 +267,13 @@ function createElementCache(query, ttl = 1e3) {
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
// src/core/iframe-bridge.ts
|
|
270
|
+
var debug = createScopedLogger("iframe-bridge");
|
|
270
271
|
var EDITOR_BASE_DOMAIN = "prepr.io";
|
|
271
272
|
function isAllowedEditorOrigin(origin, allowed) {
|
|
272
|
-
if (allowed)
|
|
273
|
+
if (allowed) {
|
|
274
|
+
if (allowed.includes("*")) return origin !== "null";
|
|
275
|
+
return allowed.includes(origin);
|
|
276
|
+
}
|
|
273
277
|
let url;
|
|
274
278
|
try {
|
|
275
279
|
url = new URL(origin);
|
|
@@ -284,6 +288,7 @@ function isAllowedEditorOrigin(origin, allowed) {
|
|
|
284
288
|
}
|
|
285
289
|
function createIframeBridge(store, options = {}) {
|
|
286
290
|
const allowedOrigins = options.allowedEditorOrigins;
|
|
291
|
+
const onScrollToField = options.onScrollToField;
|
|
287
292
|
let parentOrigin = null;
|
|
288
293
|
const onKeyDown = (event) => {
|
|
289
294
|
const key = event.key.toLowerCase();
|
|
@@ -293,7 +298,10 @@ function createIframeBridge(store, options = {}) {
|
|
|
293
298
|
const onMessage = (evt) => {
|
|
294
299
|
const data = evt?.data;
|
|
295
300
|
if (data?.event === "prepr:initVE" && !parentOrigin) {
|
|
296
|
-
if (!isAllowedEditorOrigin(evt.origin, allowedOrigins))
|
|
301
|
+
if (!isAllowedEditorOrigin(evt.origin, allowedOrigins)) {
|
|
302
|
+
debug.warn("ignored editor handshake from origin", evt.origin);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
297
305
|
parentOrigin = evt.origin;
|
|
298
306
|
setTrustedParentOrigin(parentOrigin);
|
|
299
307
|
if (data.scrollPosition != null) {
|
|
@@ -307,6 +315,15 @@ function createIframeBridge(store, options = {}) {
|
|
|
307
315
|
const currentScrollY = window.scrollY || document.documentElement.scrollTop;
|
|
308
316
|
sendPreprEvent("getScrollPosition", { value: currentScrollY });
|
|
309
317
|
}
|
|
318
|
+
if (data?.event === "prepr:scrollToField") {
|
|
319
|
+
if (typeof data.field !== "string" || !data.field) return;
|
|
320
|
+
if (data.id !== void 0 && typeof data.id !== "string") return;
|
|
321
|
+
try {
|
|
322
|
+
onScrollToField?.({ field: data.field, id: data.id });
|
|
323
|
+
} catch (error) {
|
|
324
|
+
debug.warn("scrollToField handler failed", error);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
310
327
|
};
|
|
311
328
|
return {
|
|
312
329
|
start() {
|
|
@@ -331,7 +348,7 @@ import { vercelStegaSplit } from "@vercel/stega";
|
|
|
331
348
|
|
|
332
349
|
// src/core/stega/clean.ts
|
|
333
350
|
import { vercelStegaClean, vercelStegaDecode } from "@vercel/stega";
|
|
334
|
-
var
|
|
351
|
+
var debug2 = createScopedLogger("stega:clean");
|
|
335
352
|
function decodeStega(str) {
|
|
336
353
|
if (!str) return null;
|
|
337
354
|
try {
|
|
@@ -340,7 +357,7 @@ function decodeStega(str) {
|
|
|
340
357
|
return decoded;
|
|
341
358
|
}
|
|
342
359
|
} catch (error) {
|
|
343
|
-
|
|
360
|
+
debug2.log("error decoding stega data", error);
|
|
344
361
|
const match = str.match(/{"origin.*?}/);
|
|
345
362
|
if (match) {
|
|
346
363
|
try {
|
|
@@ -349,7 +366,7 @@ function decodeStega(str) {
|
|
|
349
366
|
return decodedMatch;
|
|
350
367
|
}
|
|
351
368
|
} catch (innerError) {
|
|
352
|
-
|
|
369
|
+
debug2.log("error decoding stega regex match", innerError);
|
|
353
370
|
}
|
|
354
371
|
}
|
|
355
372
|
}
|
|
@@ -385,14 +402,37 @@ function isRenderedElement(element) {
|
|
|
385
402
|
if (!style) return true;
|
|
386
403
|
return style.visibility !== "hidden" && style.display !== "none";
|
|
387
404
|
}
|
|
405
|
+
function parseEditHref(href) {
|
|
406
|
+
try {
|
|
407
|
+
const url = new URL(href, window.location.origin);
|
|
408
|
+
return {
|
|
409
|
+
id: url.pathname.split("/").pop() || void 0,
|
|
410
|
+
field: url.searchParams.get("field") || void 0,
|
|
411
|
+
locale: url.searchParams.get("locale") || void 0
|
|
412
|
+
};
|
|
413
|
+
} catch {
|
|
414
|
+
return {};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
function setOrRemove(element, name, value) {
|
|
418
|
+
if (value) {
|
|
419
|
+
element.setAttribute(name, value);
|
|
420
|
+
} else {
|
|
421
|
+
element.removeAttribute(name);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
388
424
|
function tagEncodedElement(element, decoded) {
|
|
389
425
|
element.setAttribute("data-prepr-encoded", "");
|
|
390
426
|
element.setAttribute("data-prepr-href", decoded.href);
|
|
391
427
|
element.setAttribute("data-prepr-origin", decoded.origin);
|
|
428
|
+
const { id, field, locale } = parseEditHref(decoded.href);
|
|
429
|
+
setOrRemove(element, "data-prepr-id", id);
|
|
430
|
+
setOrRemove(element, "data-prepr-field", field);
|
|
431
|
+
setOrRemove(element, "data-prepr-locale", locale);
|
|
392
432
|
}
|
|
393
433
|
|
|
394
434
|
// src/core/stega/auto-clean.ts
|
|
395
|
-
var
|
|
435
|
+
var debug3 = createScopedLogger("stega:auto-clean");
|
|
396
436
|
function createStegaAutoClean(options) {
|
|
397
437
|
const stripText = options?.enabled ?? true;
|
|
398
438
|
let observer = null;
|
|
@@ -435,7 +475,7 @@ function createStegaAutoClean(options) {
|
|
|
435
475
|
}
|
|
436
476
|
pendingHidden.add(textNode);
|
|
437
477
|
} catch (error) {
|
|
438
|
-
|
|
478
|
+
debug3.log("error cleaning text node", error);
|
|
439
479
|
}
|
|
440
480
|
return false;
|
|
441
481
|
}
|
|
@@ -521,7 +561,7 @@ function createStegaAutoClean(options) {
|
|
|
521
561
|
if (observer || typeof window === "undefined") return;
|
|
522
562
|
scanAndClean();
|
|
523
563
|
setupObserver();
|
|
524
|
-
|
|
564
|
+
debug3.log("stega auto-clean started");
|
|
525
565
|
}
|
|
526
566
|
function stop() {
|
|
527
567
|
if (debounceTimeout) {
|
|
@@ -535,13 +575,13 @@ function createStegaAutoClean(options) {
|
|
|
535
575
|
cleaned = /* @__PURE__ */ new WeakMap();
|
|
536
576
|
pendingHidden = /* @__PURE__ */ new Set();
|
|
537
577
|
pendingDirty = /* @__PURE__ */ new Set();
|
|
538
|
-
|
|
578
|
+
debug3.log("stega auto-clean stopped");
|
|
539
579
|
}
|
|
540
580
|
return { start, stop };
|
|
541
581
|
}
|
|
542
582
|
|
|
543
583
|
// src/core/stega/elements.ts
|
|
544
|
-
var
|
|
584
|
+
var debug4 = createScopedLogger("stega:elements");
|
|
545
585
|
var StegaElements = class {
|
|
546
586
|
constructor(decode = decodeStega) {
|
|
547
587
|
this.observer = null;
|
|
@@ -586,7 +626,7 @@ var StegaElements = class {
|
|
|
586
626
|
walkTextNodes(document.body, (textNode) => {
|
|
587
627
|
if (this.tagFromTextNode(textNode)) encodedCount++;
|
|
588
628
|
});
|
|
589
|
-
|
|
629
|
+
debug4.log("document scan complete, encoded", encodedCount, "elements");
|
|
590
630
|
this.elements = document.querySelectorAll("[data-prepr-encoded]");
|
|
591
631
|
}
|
|
592
632
|
/** `onUpdate` fires after each debounced batch, for refreshing derived state. */
|
|
@@ -642,6 +682,9 @@ var StegaElements = class {
|
|
|
642
682
|
element.removeAttribute("data-prepr-encoded");
|
|
643
683
|
element.removeAttribute("data-prepr-href");
|
|
644
684
|
element.removeAttribute("data-prepr-origin");
|
|
685
|
+
element.removeAttribute("data-prepr-id");
|
|
686
|
+
element.removeAttribute("data-prepr-field");
|
|
687
|
+
element.removeAttribute("data-prepr-locale");
|
|
645
688
|
element.classList.remove("prepr-overlay-active");
|
|
646
689
|
});
|
|
647
690
|
this.elements = void 0;
|
|
@@ -649,7 +692,7 @@ var StegaElements = class {
|
|
|
649
692
|
};
|
|
650
693
|
|
|
651
694
|
// src/core/stega/overlay.ts
|
|
652
|
-
var
|
|
695
|
+
var debug5 = createScopedLogger("stega:overlay");
|
|
653
696
|
var StegaOverlay = class {
|
|
654
697
|
constructor(onEdit) {
|
|
655
698
|
this.overlay = null;
|
|
@@ -694,7 +737,8 @@ var StegaOverlay = class {
|
|
|
694
737
|
const origin = element.getAttribute("data-prepr-origin");
|
|
695
738
|
const id = element.getAttribute("data-prepr-id") ?? void 0;
|
|
696
739
|
const field = element.getAttribute("data-prepr-field") ?? void 0;
|
|
697
|
-
|
|
740
|
+
const locale = element.getAttribute("data-prepr-locale") ?? void 0;
|
|
741
|
+
debug5.log("showing overlay", { href, origin });
|
|
698
742
|
const overlay = this.overlay;
|
|
699
743
|
overlay.style.display = "block";
|
|
700
744
|
overlay.style.top = `${rect.top + window.scrollY - 2}px`;
|
|
@@ -726,7 +770,7 @@ var StegaOverlay = class {
|
|
|
726
770
|
tooltip.style.left = `${left}px`;
|
|
727
771
|
});
|
|
728
772
|
tooltip.onclick = () => {
|
|
729
|
-
this.onEdit({ href, origin, id, field });
|
|
773
|
+
this.onEdit({ href, origin, id, field, locale });
|
|
730
774
|
};
|
|
731
775
|
}
|
|
732
776
|
this.currentElement = element;
|
|
@@ -766,7 +810,7 @@ var StegaOverlay = class {
|
|
|
766
810
|
};
|
|
767
811
|
|
|
768
812
|
// src/core/stega/proximity.ts
|
|
769
|
-
var
|
|
813
|
+
var debug6 = createScopedLogger("stega:proximity");
|
|
770
814
|
var StegaProximity = class {
|
|
771
815
|
constructor() {
|
|
772
816
|
this.highlighted = /* @__PURE__ */ new Set();
|
|
@@ -801,9 +845,9 @@ var StegaProximity = class {
|
|
|
801
845
|
);
|
|
802
846
|
const nodes = this.getEncodedElements();
|
|
803
847
|
nodes.forEach((el) => this.observer.observe(el));
|
|
804
|
-
|
|
848
|
+
debug6.log("observing", nodes.length, "encoded elements");
|
|
805
849
|
} catch (error) {
|
|
806
|
-
|
|
850
|
+
debug6.log("error setting up IntersectionObserver", error);
|
|
807
851
|
}
|
|
808
852
|
}
|
|
809
853
|
stopObserving() {
|
|
@@ -873,7 +917,7 @@ function removeStegaStyles() {
|
|
|
873
917
|
}
|
|
874
918
|
|
|
875
919
|
// src/core/stega/scan.ts
|
|
876
|
-
var
|
|
920
|
+
var debug7 = createScopedLogger("stega:scan");
|
|
877
921
|
var EDITOR_MODE_STYLES = "[data-prepr-encoded]{cursor:pointer}";
|
|
878
922
|
function createStegaController(opts) {
|
|
879
923
|
const tooltipEnabled = opts.tooltip ?? true;
|
|
@@ -906,12 +950,13 @@ function createStegaController(opts) {
|
|
|
906
950
|
href: encoded.getAttribute("data-prepr-href") ?? "",
|
|
907
951
|
origin: encoded.getAttribute("data-prepr-origin") ?? "",
|
|
908
952
|
id: encoded.getAttribute("data-prepr-id") ?? void 0,
|
|
909
|
-
field: encoded.getAttribute("data-prepr-field") ?? void 0
|
|
953
|
+
field: encoded.getAttribute("data-prepr-field") ?? void 0,
|
|
954
|
+
locale: encoded.getAttribute("data-prepr-locale") ?? void 0
|
|
910
955
|
});
|
|
911
956
|
};
|
|
912
957
|
const start = () => {
|
|
913
958
|
if (initialized) {
|
|
914
|
-
|
|
959
|
+
debug7.log("already initialized, skipping setup");
|
|
915
960
|
return;
|
|
916
961
|
}
|
|
917
962
|
if (!tooltipEnabled) {
|
|
@@ -921,7 +966,7 @@ function createStegaController(opts) {
|
|
|
921
966
|
});
|
|
922
967
|
document.addEventListener("click", handleClick, { capture: true });
|
|
923
968
|
initialized = true;
|
|
924
|
-
|
|
969
|
+
debug7.log("stega controller started (editor mode)");
|
|
925
970
|
return;
|
|
926
971
|
}
|
|
927
972
|
injectStegaStyles();
|
|
@@ -952,7 +997,7 @@ function createStegaController(opts) {
|
|
|
952
997
|
passive: true
|
|
953
998
|
});
|
|
954
999
|
initialized = true;
|
|
955
|
-
|
|
1000
|
+
debug7.log("stega controller started");
|
|
956
1001
|
};
|
|
957
1002
|
const stop = () => {
|
|
958
1003
|
if (!initialized) return;
|
|
@@ -961,7 +1006,7 @@ function createStegaController(opts) {
|
|
|
961
1006
|
elements.cleanup();
|
|
962
1007
|
removeStegaStyles();
|
|
963
1008
|
initialized = false;
|
|
964
|
-
|
|
1009
|
+
debug7.log("stega controller stopped (editor mode)");
|
|
965
1010
|
return;
|
|
966
1011
|
}
|
|
967
1012
|
if (throttledMouseMove) {
|
|
@@ -981,11 +1026,43 @@ function createStegaController(opts) {
|
|
|
981
1026
|
elements.cleanup();
|
|
982
1027
|
removeStegaStyles();
|
|
983
1028
|
initialized = false;
|
|
984
|
-
|
|
1029
|
+
debug7.log("stega controller stopped");
|
|
985
1030
|
};
|
|
986
1031
|
return { start, stop };
|
|
987
1032
|
}
|
|
988
1033
|
|
|
1034
|
+
// src/core/stega/scroll-to-field.ts
|
|
1035
|
+
var debug8 = createScopedLogger("stega:scroll");
|
|
1036
|
+
var FLASH_DURATION_MS = 1200;
|
|
1037
|
+
var flashTimeout = null;
|
|
1038
|
+
function scrollToField(request) {
|
|
1039
|
+
const { field, id } = request;
|
|
1040
|
+
if (!field) return false;
|
|
1041
|
+
const candidates = document.querySelectorAll(
|
|
1042
|
+
"[data-prepr-encoded]"
|
|
1043
|
+
);
|
|
1044
|
+
let target = null;
|
|
1045
|
+
for (const candidate of candidates) {
|
|
1046
|
+
if (candidate.getAttribute("data-prepr-field") !== field) continue;
|
|
1047
|
+
if (id && candidate.getAttribute("data-prepr-id") !== id) continue;
|
|
1048
|
+
target = candidate;
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1051
|
+
if (!target) {
|
|
1052
|
+
debug8.log("no element found for field", field);
|
|
1053
|
+
return false;
|
|
1054
|
+
}
|
|
1055
|
+
target.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
1056
|
+
if (flashTimeout) clearTimeout(flashTimeout);
|
|
1057
|
+
document.querySelectorAll(".prepr-overlay-active").forEach((el) => el.classList.remove("prepr-overlay-active"));
|
|
1058
|
+
target.classList.add("prepr-overlay-active");
|
|
1059
|
+
flashTimeout = setTimeout(() => {
|
|
1060
|
+
target.classList.remove("prepr-overlay-active");
|
|
1061
|
+
flashTimeout = null;
|
|
1062
|
+
}, FLASH_DURATION_MS);
|
|
1063
|
+
return true;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
989
1066
|
// src/core/store.ts
|
|
990
1067
|
var DEFAULT_STATE = {
|
|
991
1068
|
locale: "en",
|
|
@@ -2098,7 +2175,7 @@ function definePreprToolbar() {
|
|
|
2098
2175
|
}
|
|
2099
2176
|
|
|
2100
2177
|
// src/core/create-preview.ts
|
|
2101
|
-
var
|
|
2178
|
+
var debug9 = createScopedLogger("create-preview");
|
|
2102
2179
|
var controllerStores = /* @__PURE__ */ new WeakMap();
|
|
2103
2180
|
function defaultNavigation() {
|
|
2104
2181
|
return {
|
|
@@ -2140,7 +2217,7 @@ function createPreprPreview(opts = {}) {
|
|
|
2140
2217
|
const search = new URLSearchParams(window.location.search);
|
|
2141
2218
|
const hideBar = search.get(PARAM_HIDE_BAR) === "true";
|
|
2142
2219
|
if (hideBar) {
|
|
2143
|
-
|
|
2220
|
+
debug9.log(`${PARAM_HIDE_BAR}=true \u2014 no visible toolbar`);
|
|
2144
2221
|
}
|
|
2145
2222
|
const mountUi = (options?.ui ?? true) && !isIframe && !hideBar;
|
|
2146
2223
|
const locale = resolveLocale(options);
|
|
@@ -2176,18 +2253,17 @@ function createPreprPreview(opts = {}) {
|
|
|
2176
2253
|
tooltip: mountUi,
|
|
2177
2254
|
// In the editor, ask the parent to focus the field instead of opening a new
|
|
2178
2255
|
// tab. Standalone previews keep the window.open behaviour.
|
|
2179
|
-
onEdit: ({ href,
|
|
2256
|
+
onEdit: ({ href, id, field, locale: contentLocale }) => {
|
|
2180
2257
|
const safeHref = href ? safeEditUrl(href) : null;
|
|
2181
2258
|
if (href && !safeHref) {
|
|
2182
|
-
|
|
2259
|
+
debug9.warn("ignored edit request with unsupported href scheme");
|
|
2183
2260
|
return;
|
|
2184
2261
|
}
|
|
2185
2262
|
if (isIframe) {
|
|
2186
2263
|
sendPreprEvent("field_edit_requested", {
|
|
2187
|
-
href: safeHref ?? void 0,
|
|
2188
|
-
origin,
|
|
2189
2264
|
id,
|
|
2190
|
-
field
|
|
2265
|
+
field,
|
|
2266
|
+
locale: contentLocale
|
|
2191
2267
|
});
|
|
2192
2268
|
} else if (safeHref) {
|
|
2193
2269
|
window.open(safeHref, "_blank", "noopener,noreferrer");
|
|
@@ -2214,7 +2290,15 @@ function createPreprPreview(opts = {}) {
|
|
|
2214
2290
|
handleChange(before, state);
|
|
2215
2291
|
});
|
|
2216
2292
|
const bridge = createIframeBridge(store, {
|
|
2217
|
-
allowedEditorOrigins: options?.allowedEditorOrigins
|
|
2293
|
+
allowedEditorOrigins: options?.allowedEditorOrigins,
|
|
2294
|
+
// The editor selecting a field scrolls the matching element into view. The
|
|
2295
|
+
// lookup relies on the attributes the stega scan writes, so it finds
|
|
2296
|
+
// nothing until encoded content has been tagged.
|
|
2297
|
+
onScrollToField: ({ field, id }) => {
|
|
2298
|
+
if (!scrollToField({ field, id })) {
|
|
2299
|
+
debug9.log("no element on this page renders field", field);
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2218
2302
|
});
|
|
2219
2303
|
sendPreprEvent(
|
|
2220
2304
|
"getScrollPosition",
|
|
@@ -2234,7 +2318,7 @@ function createPreprPreview(opts = {}) {
|
|
|
2234
2318
|
bridge.stop();
|
|
2235
2319
|
}
|
|
2236
2320
|
el?.remove();
|
|
2237
|
-
|
|
2321
|
+
debug9.log("preview destroyed");
|
|
2238
2322
|
}
|
|
2239
2323
|
const controller = { destroy };
|
|
2240
2324
|
controllerStores.set(controller, store);
|
|
@@ -2242,7 +2326,7 @@ function createPreprPreview(opts = {}) {
|
|
|
2242
2326
|
}
|
|
2243
2327
|
|
|
2244
2328
|
// src/version.ts
|
|
2245
|
-
var VERSION = "0.
|
|
2329
|
+
var VERSION = "0.5.0-rc.2";
|
|
2246
2330
|
|
|
2247
2331
|
// src/core/pixel.ts
|
|
2248
2332
|
var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr.min.js";
|
package/dist/sveltekit/index.cjs
CHANGED
package/dist/sveltekit/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@preprio/toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0-rc.2",
|
|
4
4
|
"description": "Prepr personalization, A/B testing and preview toolkit for React, Next.js, Nuxt, Astro, SvelteKit and Express",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Prepr B.V. (https://prepr.io)",
|