@preprio/toolkit 0.1.0-beta.6 → 0.2.0-beta.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 +85 -12
- package/dist/astro/index.cjs +37 -15
- package/dist/astro/index.d.cts +38 -8
- package/dist/astro/index.d.ts +38 -8
- package/dist/astro/index.js +37 -15
- package/dist/{chunk-NLQIRN5O.js → chunk-6OOGNVJ4.js} +83 -41
- package/dist/index.cjs +102 -55
- package/dist/index.d.cts +59 -16
- package/dist/index.d.ts +59 -16
- package/dist/index.js +22 -16
- package/dist/nextjs/components.cjs +87 -42
- package/dist/nextjs/components.d.cts +3 -3
- package/dist/nextjs/components.d.ts +3 -3
- package/dist/nextjs/components.js +8 -4
- package/dist/nextjs/index.cjs +37 -15
- package/dist/nextjs/index.d.cts +46 -16
- package/dist/nextjs/index.d.ts +46 -16
- package/dist/nextjs/index.js +37 -15
- package/dist/nuxt/index.cjs +37 -15
- package/dist/nuxt/index.d.cts +62 -32
- package/dist/nuxt/index.d.ts +62 -32
- package/dist/nuxt/index.js +37 -15
- package/dist/{pixel-DVSJQC0K.d.cts → pixel-763p7m6A.d.cts} +64 -1
- package/dist/{pixel-DVSJQC0K.d.ts → pixel-763p7m6A.d.ts} +64 -1
- package/dist/sveltekit/index.cjs +37 -15
- package/dist/sveltekit/index.d.cts +62 -32
- package/dist/sveltekit/index.d.ts +62 -32
- package/dist/sveltekit/index.js +37 -15
- package/package.json +1 -1
- package/src/astro/PreprToolbar.astro +16 -10
- package/src/nuxt/PreprToolbar.vue +10 -8
- package/src/sveltekit/PreprToolbar.svelte +11 -4
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
// src/core/features.ts
|
|
2
|
+
function isEnabled(config) {
|
|
3
|
+
if (typeof config === "boolean") return config;
|
|
4
|
+
return config?.enabled ?? true;
|
|
5
|
+
}
|
|
6
|
+
function resolveFeatures(features) {
|
|
7
|
+
return {
|
|
8
|
+
segments: isEnabled(features?.segments),
|
|
9
|
+
abTesting: isEnabled(features?.abTesting),
|
|
10
|
+
editMode: isEnabled(features?.editMode)
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
var ALL_FEATURES_ENABLED = Object.freeze({
|
|
14
|
+
segments: true,
|
|
15
|
+
abTesting: true,
|
|
16
|
+
editMode: true
|
|
17
|
+
});
|
|
18
|
+
|
|
1
19
|
// src/core/stega/clean.ts
|
|
2
20
|
import { vercelStegaClean, vercelStegaDecode } from "@vercel/stega";
|
|
3
21
|
|
|
@@ -706,7 +724,8 @@ var DEFAULT_STATE = {
|
|
|
706
724
|
editMode: false,
|
|
707
725
|
previewMode: false,
|
|
708
726
|
toolbarOpen: false,
|
|
709
|
-
isIframe: false
|
|
727
|
+
isIframe: false,
|
|
728
|
+
features: ALL_FEATURES_ENABLED
|
|
710
729
|
};
|
|
711
730
|
function createToolbarStore(initial = {}) {
|
|
712
731
|
let state = { ...DEFAULT_STATE, ...initial };
|
|
@@ -1259,9 +1278,10 @@ function StatusPill({
|
|
|
1259
1278
|
t: t3,
|
|
1260
1279
|
handlers
|
|
1261
1280
|
}) {
|
|
1281
|
+
const { features } = state;
|
|
1262
1282
|
const defaultSegmentName = state.segments.find((s2) => s2._id === "all_other_users")?.name ?? t3("adaptiveContent.allOtherUsers");
|
|
1263
1283
|
let segmentLabel;
|
|
1264
|
-
if (!state.previewMode) {
|
|
1284
|
+
if (!state.previewMode || !features.segments) {
|
|
1265
1285
|
segmentLabel = t3("common.user");
|
|
1266
1286
|
} else if (state.selectedSegment !== null) {
|
|
1267
1287
|
const seg = state.segments.find((s2) => s2._id === state.selectedSegment);
|
|
@@ -1285,7 +1305,7 @@ function StatusPill({
|
|
|
1285
1305
|
{
|
|
1286
1306
|
class: "prepr-status-variant",
|
|
1287
1307
|
"data-prepr": "status-variant",
|
|
1288
|
-
hidden: !state.previewMode,
|
|
1308
|
+
hidden: !features.abTesting || !state.previewMode,
|
|
1289
1309
|
children: state.selectedVariant === "B" ? "B" : "A"
|
|
1290
1310
|
}
|
|
1291
1311
|
),
|
|
@@ -1294,7 +1314,7 @@ function StatusPill({
|
|
|
1294
1314
|
{
|
|
1295
1315
|
class: "prepr-status-x",
|
|
1296
1316
|
"data-prepr": "status-x",
|
|
1297
|
-
hidden: !state.previewMode || state.selectedSegment === null,
|
|
1317
|
+
hidden: !features.segments || !state.previewMode || state.selectedSegment === null,
|
|
1298
1318
|
children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG })
|
|
1299
1319
|
}
|
|
1300
1320
|
)
|
|
@@ -1314,7 +1334,7 @@ function CloseEditPill({
|
|
|
1314
1334
|
class: "prepr-close-edit-pill",
|
|
1315
1335
|
"data-prepr": "close-edit-pill",
|
|
1316
1336
|
"aria-label": t3("editingTools.ariaCloseEditMode"),
|
|
1317
|
-
hidden: !state.editMode || state.isIframe,
|
|
1337
|
+
hidden: !state.features.editMode || !state.editMode || state.isIframe,
|
|
1318
1338
|
onClick: () => handlers.onCloseEditPill(),
|
|
1319
1339
|
children: [
|
|
1320
1340
|
/* @__PURE__ */ u2("span", { "data-prepr": "close-edit-label", children: t3("editingTools.editMode") }),
|
|
@@ -1330,7 +1350,9 @@ function Panel({
|
|
|
1330
1350
|
segmentFilter,
|
|
1331
1351
|
handlers
|
|
1332
1352
|
}) {
|
|
1333
|
-
const
|
|
1353
|
+
const { features } = state;
|
|
1354
|
+
const hasPersonalization = features.segments && state.selectedSegment !== null || features.abTesting && state.selectedVariant !== null;
|
|
1355
|
+
const showAdaptive = features.segments || features.abTesting;
|
|
1334
1356
|
return /* @__PURE__ */ u2(S, { children: [
|
|
1335
1357
|
/* @__PURE__ */ u2(
|
|
1336
1358
|
"style",
|
|
@@ -1373,12 +1395,12 @@ function Panel({
|
|
|
1373
1395
|
children: [
|
|
1374
1396
|
/* @__PURE__ */ u2(Header, { t: t3, onClose: handlers.onClose }),
|
|
1375
1397
|
/* @__PURE__ */ u2("div", { class: "prepr-section", "data-prepr": "section-adaptive", children: [
|
|
1376
|
-
/* @__PURE__ */ u2("span", { class: "prepr-section-label", "data-prepr": "adaptive-label", children: t3("adaptiveContent.adaptiveContent") }),
|
|
1398
|
+
/* @__PURE__ */ u2("span", { class: "prepr-section-label", "data-prepr": "adaptive-label", children: showAdaptive ? t3("adaptiveContent.adaptiveContent") : t3("adaptiveContent.enablePreview") }),
|
|
1377
1399
|
/* @__PURE__ */ u2("div", { class: "prepr-row", children: [
|
|
1378
1400
|
/* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "preview-label", children: t3("adaptiveContent.enablePreview") }),
|
|
1379
1401
|
/* @__PURE__ */ u2(PreviewSelector, { state, t: t3, handlers })
|
|
1380
1402
|
] }),
|
|
1381
|
-
/* @__PURE__ */ u2("div", { class: "prepr-row", children: [
|
|
1403
|
+
features.segments && /* @__PURE__ */ u2("div", { class: "prepr-row", children: [
|
|
1382
1404
|
/* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "segment-label", children: t3("adaptiveContent.segment") }),
|
|
1383
1405
|
/* @__PURE__ */ u2(
|
|
1384
1406
|
SegmentListbox,
|
|
@@ -1391,12 +1413,12 @@ function Panel({
|
|
|
1391
1413
|
}
|
|
1392
1414
|
)
|
|
1393
1415
|
] }),
|
|
1394
|
-
/* @__PURE__ */ u2("div", { class: "prepr-row", children: [
|
|
1416
|
+
features.abTesting && /* @__PURE__ */ u2("div", { class: "prepr-row", children: [
|
|
1395
1417
|
/* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "variant-label", children: t3("adaptiveContent.ABVariant") }),
|
|
1396
1418
|
/* @__PURE__ */ u2(VariantSelector, { state, handlers })
|
|
1397
1419
|
] })
|
|
1398
1420
|
] }),
|
|
1399
|
-
/* @__PURE__ */ u2("div", { class: "prepr-section", "data-prepr": "section-editing", children: [
|
|
1421
|
+
features.editMode && /* @__PURE__ */ u2("div", { class: "prepr-section", "data-prepr": "section-editing", children: [
|
|
1400
1422
|
/* @__PURE__ */ u2("span", { class: "prepr-section-label", "data-prepr": "editing-label", children: t3("editingTools.editingTools") }),
|
|
1401
1423
|
/* @__PURE__ */ u2("div", { class: "prepr-row", children: [
|
|
1402
1424
|
/* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "edit-label", children: t3("editingTools.editMode") }),
|
|
@@ -1449,26 +1471,28 @@ var PreprToolbarElement = class extends HTMLElementBase {
|
|
|
1449
1471
|
onToggle: () => this.set({ toolbarOpen: !this.state.toolbarOpen }),
|
|
1450
1472
|
onClose: () => this.set({ toolbarOpen: false }),
|
|
1451
1473
|
onPreviewMode: (value) => this.set({ previewMode: value }),
|
|
1452
|
-
onEditMode: (value) =>
|
|
1474
|
+
onEditMode: (value) => {
|
|
1475
|
+
if (!this.state.features.editMode) return;
|
|
1476
|
+
this.set({ editMode: value });
|
|
1477
|
+
},
|
|
1453
1478
|
onVariant: (value) => {
|
|
1479
|
+
if (!this.state.features.abTesting) return;
|
|
1454
1480
|
if (!this.state.previewMode) return;
|
|
1455
1481
|
this.set({ selectedVariant: value });
|
|
1456
1482
|
},
|
|
1457
1483
|
// Reset contract: segment to none, variant to 'A' — NOT null, since the
|
|
1458
1484
|
// resulting `variant_changed` must carry 'A' on the wire — edit mode off.
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
editMode: false
|
|
1463
|
-
}),
|
|
1485
|
+
// Disabled features are left untouched: their state is already inert and
|
|
1486
|
+
// writing it would emit events for a feature the consumer turned off.
|
|
1487
|
+
onReset: () => this.set(this.resetPatch({ editMode: false })),
|
|
1464
1488
|
onStatusPill: () => {
|
|
1465
1489
|
if (!this.state.previewMode) {
|
|
1466
1490
|
this.set({ previewMode: true });
|
|
1467
1491
|
return;
|
|
1468
1492
|
}
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1493
|
+
const patch = this.resetPatch();
|
|
1494
|
+
const dirty = "selectedSegment" in patch && this.state.selectedSegment !== null || "selectedVariant" in patch && this.state.selectedVariant !== "A";
|
|
1495
|
+
if (dirty) this.set(patch);
|
|
1472
1496
|
},
|
|
1473
1497
|
onCloseEditPill: () => this.set({ editMode: false }),
|
|
1474
1498
|
onSegmentButtonClick: () => this.toggleListbox(!this.listboxOpen),
|
|
@@ -1518,6 +1542,14 @@ var PreprToolbarElement = class extends HTMLElementBase {
|
|
|
1518
1542
|
set(patch) {
|
|
1519
1543
|
this.store?.set(patch);
|
|
1520
1544
|
}
|
|
1545
|
+
/** Reset patch covering only the enabled personalization features. */
|
|
1546
|
+
resetPatch(base = {}) {
|
|
1547
|
+
const { features } = this.state;
|
|
1548
|
+
const patch = { ...base };
|
|
1549
|
+
if (features.segments) patch.selectedSegment = null;
|
|
1550
|
+
if (features.abTesting) patch.selectedVariant = "A";
|
|
1551
|
+
return patch;
|
|
1552
|
+
}
|
|
1521
1553
|
// Synchronous: Preact's top-level render() mutates the DOM before returning.
|
|
1522
1554
|
renderPanel(state) {
|
|
1523
1555
|
const root = this.shadowRoot;
|
|
@@ -1676,6 +1708,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
|
|
|
1676
1708
|
) ?? null;
|
|
1677
1709
|
}
|
|
1678
1710
|
chooseSegment(id) {
|
|
1711
|
+
if (!this.state.features.segments) return;
|
|
1679
1712
|
this.listboxOpen = false;
|
|
1680
1713
|
this.segmentFilter = "";
|
|
1681
1714
|
this.set({ selectedSegment: id });
|
|
@@ -1866,7 +1899,7 @@ function createIframeBridge(store, options = {}) {
|
|
|
1866
1899
|
const top = data.scrollPosition;
|
|
1867
1900
|
setTimeout(() => window.scrollTo(0, top), 1);
|
|
1868
1901
|
}
|
|
1869
|
-
store
|
|
1902
|
+
store?.set({ previewMode: true, editMode: data.editMode ?? true });
|
|
1870
1903
|
}
|
|
1871
1904
|
if (!parentOrigin || evt.origin !== parentOrigin) return;
|
|
1872
1905
|
if (data?.event === "prepr:getScrollPosition") {
|
|
@@ -1898,7 +1931,7 @@ function cookieOpts() {
|
|
|
1898
1931
|
};
|
|
1899
1932
|
}
|
|
1900
1933
|
function createChangeHandler(deps) {
|
|
1901
|
-
const { store, stega, syncAutoClean } = deps;
|
|
1934
|
+
const { store, stega, syncAutoClean, features, editingEnabled } = deps;
|
|
1902
1935
|
function updateParams(patch) {
|
|
1903
1936
|
const [path, existing] = splitPath(deps.currentPath());
|
|
1904
1937
|
const params = new URLSearchParams(existing);
|
|
@@ -1914,7 +1947,7 @@ function createChangeHandler(deps) {
|
|
|
1914
1947
|
}
|
|
1915
1948
|
return function handleChange(before, after) {
|
|
1916
1949
|
const paramPatch = {};
|
|
1917
|
-
if (before.selectedSegment !== after.selectedSegment) {
|
|
1950
|
+
if (features.segments && before.selectedSegment !== after.selectedSegment) {
|
|
1918
1951
|
if (after.selectedSegment === null) {
|
|
1919
1952
|
removeCookie(COOKIE_SEGMENT, "/", crossSiteCookieOptions());
|
|
1920
1953
|
} else {
|
|
@@ -1925,7 +1958,7 @@ function createChangeHandler(deps) {
|
|
|
1925
1958
|
segment: after.selectedSegment ?? void 0
|
|
1926
1959
|
});
|
|
1927
1960
|
}
|
|
1928
|
-
if (before.selectedVariant !== after.selectedVariant) {
|
|
1961
|
+
if (features.abTesting && before.selectedVariant !== after.selectedVariant) {
|
|
1929
1962
|
if (after.selectedVariant === null) {
|
|
1930
1963
|
removeCookie(COOKIE_VARIANT, "/", crossSiteCookieOptions());
|
|
1931
1964
|
} else {
|
|
@@ -1940,7 +1973,7 @@ function createChangeHandler(deps) {
|
|
|
1940
1973
|
updateParams(paramPatch);
|
|
1941
1974
|
}
|
|
1942
1975
|
if (before.editMode !== after.editMode) {
|
|
1943
|
-
if (after.editMode) {
|
|
1976
|
+
if (after.editMode && editingEnabled) {
|
|
1944
1977
|
stega.start();
|
|
1945
1978
|
} else {
|
|
1946
1979
|
stega.stop();
|
|
@@ -1984,8 +2017,8 @@ function splitPath(full) {
|
|
|
1984
2017
|
return [full.slice(0, index), full.slice(index + 1)];
|
|
1985
2018
|
}
|
|
1986
2019
|
|
|
1987
|
-
// src/core/create-
|
|
1988
|
-
var debug7 = createScopedLogger("create-
|
|
2020
|
+
// src/core/create-preview.ts
|
|
2021
|
+
var debug7 = createScopedLogger("create-preview");
|
|
1989
2022
|
var controllerStores = /* @__PURE__ */ new WeakMap();
|
|
1990
2023
|
function defaultNavigation() {
|
|
1991
2024
|
return {
|
|
@@ -2006,7 +2039,7 @@ function resolveLocale(options) {
|
|
|
2006
2039
|
}
|
|
2007
2040
|
return "en";
|
|
2008
2041
|
}
|
|
2009
|
-
function
|
|
2042
|
+
function createPreprPreview(opts = {}) {
|
|
2010
2043
|
const { props, options } = opts;
|
|
2011
2044
|
const navigation = opts.navigation ?? defaultNavigation();
|
|
2012
2045
|
initDebugLogger(options?.debug ?? false);
|
|
@@ -2019,36 +2052,40 @@ function createPreprToolbar(opts) {
|
|
|
2019
2052
|
const search = new URLSearchParams(window.location.search);
|
|
2020
2053
|
const hideBar = search.get(PARAM_HIDE_BAR) === "true";
|
|
2021
2054
|
if (hideBar) {
|
|
2022
|
-
debug7.log(`${PARAM_HIDE_BAR}=true \u2014
|
|
2023
|
-
return noop();
|
|
2055
|
+
debug7.log(`${PARAM_HIDE_BAR}=true \u2014 no visible toolbar`);
|
|
2024
2056
|
}
|
|
2057
|
+
const mountUi = (options?.ui ?? true) && !isIframe && !hideBar;
|
|
2025
2058
|
const locale = resolveLocale(options);
|
|
2059
|
+
const features = resolveFeatures(options?.features);
|
|
2026
2060
|
const previewMode = getCookie(COOKIE_PREVIEW_MODE) === "true";
|
|
2027
2061
|
const toolbarOpen = getCookie(COOKIE_TOOLBAR_OPEN) === "true";
|
|
2028
|
-
const cookieSegment = getCookie(COOKIE_SEGMENT);
|
|
2029
|
-
const cookieVariant = getCookie(COOKIE_VARIANT);
|
|
2030
|
-
const rawVariant = props
|
|
2062
|
+
const cookieSegment = features.segments ? getCookie(COOKIE_SEGMENT) : null;
|
|
2063
|
+
const cookieVariant = features.abTesting ? getCookie(COOKIE_VARIANT) : null;
|
|
2064
|
+
const rawVariant = features.abTesting ? props?.activeVariant ?? cookieVariant : null;
|
|
2031
2065
|
const selectedVariant = rawVariant === "A" || rawVariant === "B" ? rawVariant : null;
|
|
2032
2066
|
const store = createToolbarStore({
|
|
2033
2067
|
locale,
|
|
2034
|
-
|
|
2035
|
-
|
|
2068
|
+
features,
|
|
2069
|
+
segments: features.segments ? buildSegments(props?.segments ?? props?.data ?? []) : [],
|
|
2070
|
+
selectedSegment: features.segments ? props?.activeSegment ?? cookieSegment ?? null : null,
|
|
2036
2071
|
selectedVariant,
|
|
2037
2072
|
previewMode,
|
|
2038
2073
|
toolbarOpen,
|
|
2039
2074
|
isIframe
|
|
2040
2075
|
});
|
|
2041
2076
|
let el = null;
|
|
2042
|
-
if (
|
|
2077
|
+
if (mountUi) {
|
|
2043
2078
|
definePreprToolbar();
|
|
2044
2079
|
el = document.createElement("prepr-toolbar");
|
|
2045
2080
|
document.body.appendChild(el);
|
|
2046
2081
|
el.connect(store, (key) => t2(key, locale));
|
|
2047
2082
|
}
|
|
2083
|
+
const editingEnabled = features.editMode || isIframe;
|
|
2048
2084
|
const stega = createStegaController({
|
|
2049
|
-
// The CMS deep-link tooltip is
|
|
2050
|
-
//
|
|
2051
|
-
|
|
2085
|
+
// The CMS deep-link tooltip is chrome, so it follows the same decision as
|
|
2086
|
+
// the bar: noise inside the editor (clicking the element itself requests
|
|
2087
|
+
// the edit there), and unwanted in a headless preview that asked for no UI.
|
|
2088
|
+
tooltip: mountUi,
|
|
2052
2089
|
// In the editor, ask the parent to focus the field instead of opening a new
|
|
2053
2090
|
// tab. Standalone previews keep the window.open behaviour.
|
|
2054
2091
|
onEdit: ({ href, origin, id, field }) => {
|
|
@@ -2072,6 +2109,8 @@ function createPreprToolbar(opts) {
|
|
|
2072
2109
|
}
|
|
2073
2110
|
const handleChange = createChangeHandler({
|
|
2074
2111
|
store,
|
|
2112
|
+
features,
|
|
2113
|
+
editingEnabled,
|
|
2075
2114
|
navigate: (url) => navigation.navigate(url),
|
|
2076
2115
|
currentPath: () => navigation.currentPath(),
|
|
2077
2116
|
reload: navigation.reload ?? (() => window.location.reload()),
|
|
@@ -2085,7 +2124,9 @@ function createPreprToolbar(opts) {
|
|
|
2085
2124
|
handleChange(before, state);
|
|
2086
2125
|
});
|
|
2087
2126
|
syncAutoClean(store.get().previewMode);
|
|
2088
|
-
const bridge = createIframeBridge(store
|
|
2127
|
+
const bridge = createIframeBridge(store, {
|
|
2128
|
+
allowedEditorOrigins: options?.allowedEditorOrigins
|
|
2129
|
+
});
|
|
2089
2130
|
sendPreprEvent("getScrollPosition", { value: 0 }, {
|
|
2090
2131
|
allowUntrustedTarget: true
|
|
2091
2132
|
});
|
|
@@ -2100,7 +2141,7 @@ function createPreprToolbar(opts) {
|
|
|
2100
2141
|
bridge.stop();
|
|
2101
2142
|
}
|
|
2102
2143
|
el?.remove();
|
|
2103
|
-
debug7.log("
|
|
2144
|
+
debug7.log("preview destroyed");
|
|
2104
2145
|
}
|
|
2105
2146
|
const controller = { destroy };
|
|
2106
2147
|
controllerStores.set(controller, store);
|
|
@@ -2172,6 +2213,7 @@ function setTrackingParam(key, value) {
|
|
|
2172
2213
|
}
|
|
2173
2214
|
|
|
2174
2215
|
export {
|
|
2216
|
+
resolveFeatures,
|
|
2175
2217
|
COOKIE_PREVIEW_MODE,
|
|
2176
2218
|
COOKIE_SEGMENT,
|
|
2177
2219
|
COOKIE_VARIANT,
|
|
@@ -2185,7 +2227,7 @@ export {
|
|
|
2185
2227
|
createToolbarStore,
|
|
2186
2228
|
PreprToolbarElement,
|
|
2187
2229
|
definePreprToolbar,
|
|
2188
|
-
|
|
2230
|
+
createPreprPreview,
|
|
2189
2231
|
loadTrackingPixel,
|
|
2190
2232
|
trackEvent,
|
|
2191
2233
|
setTrackingParam
|