@preprio/toolkit 0.5.0-rc.2 → 0.5.0-rc.4
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 +209 -10
- package/dist/astro/index.cjs +1194 -1
- package/dist/astro/index.d.cts +47 -1
- package/dist/astro/index.d.ts +47 -1
- package/dist/astro/index.js +1197 -1
- package/dist/chunk-46ISDRHT.js +26 -0
- package/dist/chunk-74KY5EAM.js +1219 -0
- package/dist/chunk-AHBN6FQP.js +184 -0
- package/dist/{chunk-FLPNN3CV.js → chunk-PDNCNTDB.js} +1370 -623
- package/dist/chunk-S3VT4UWM.js +75 -0
- package/dist/chunk-TG6N3C22.js +246 -0
- package/dist/chunk-URXSDJOU.js +356 -0
- package/dist/index.cjs +3166 -392
- package/dist/index.d.cts +238 -4
- package/dist/index.d.ts +238 -4
- package/dist/index.js +189 -149
- package/dist/live-preview-H4643QYF.js +18 -0
- package/dist/nextjs/components.cjs +1522 -359
- package/dist/nextjs/components.d.cts +1 -1
- package/dist/nextjs/components.d.ts +1 -1
- package/dist/nextjs/components.js +4 -1
- package/dist/nextjs/index.cjs +1085 -6
- package/dist/nextjs/index.d.cts +73 -1
- package/dist/nextjs/index.d.ts +73 -1
- package/dist/nextjs/index.js +1079 -7
- package/dist/nextjs/live-action.cjs +285 -0
- package/dist/nextjs/live-action.d.cts +12 -0
- package/dist/nextjs/live-action.d.ts +12 -0
- package/dist/nextjs/live-action.js +68 -0
- package/dist/nextjs/live.cjs +1896 -0
- package/dist/nextjs/live.d.cts +52 -0
- package/dist/nextjs/live.d.ts +52 -0
- package/dist/nextjs/live.js +265 -0
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/nuxt/live-preview-O2ZTJNW4.js +1520 -0
- package/dist/nuxt/live.cjs +1720 -0
- package/dist/nuxt/live.d.cts +43 -0
- package/dist/nuxt/live.d.ts +43 -0
- package/dist/nuxt/live.js +94 -0
- package/dist/{pixel-B3oQNbZ3.d.cts → pixel-CX422dCO.d.cts} +10 -1
- package/dist/{pixel-B3oQNbZ3.d.ts → pixel-CX422dCO.d.ts} +10 -1
- package/dist/react/components.cjs +1522 -359
- package/dist/react/components.d.cts +9 -0
- package/dist/react/components.d.ts +9 -0
- package/dist/react/components.js +1522 -359
- package/dist/sveltekit/index.cjs +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/package.json +12 -1
- package/src/astro/PreprToolbar.astro +7 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// src/core/utils.ts
|
|
2
|
+
var trustedParentOrigin = null;
|
|
3
|
+
function setTrustedParentOrigin(origin) {
|
|
4
|
+
trustedParentOrigin = origin;
|
|
5
|
+
}
|
|
6
|
+
function getTrustedParentOrigin() {
|
|
7
|
+
return trustedParentOrigin;
|
|
8
|
+
}
|
|
9
|
+
function sendPreprEvent(event, data, options) {
|
|
10
|
+
if (typeof window !== "undefined") {
|
|
11
|
+
const message = {
|
|
12
|
+
name: "prepr_preview_bar",
|
|
13
|
+
event,
|
|
14
|
+
...data
|
|
15
|
+
};
|
|
16
|
+
window.dispatchEvent(
|
|
17
|
+
new CustomEvent("prepr_preview_bar", { detail: message })
|
|
18
|
+
);
|
|
19
|
+
if (window.parent && window.parent !== window) {
|
|
20
|
+
if (trustedParentOrigin) {
|
|
21
|
+
window.parent.postMessage(message, trustedParentOrigin);
|
|
22
|
+
} else if (options?.allowUntrustedTarget) {
|
|
23
|
+
window.parent.postMessage(message, "*");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
var DebugLogger = class {
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.options = {
|
|
31
|
+
prefix: "[Prepr]",
|
|
32
|
+
...options
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// A local `enabled` wins; otherwise defer to the global logger so scoped
|
|
36
|
+
// loggers created before initDebugLogger() still pick up the setting.
|
|
37
|
+
isEnabled() {
|
|
38
|
+
if (this.options.enabled !== void 0) {
|
|
39
|
+
return this.options.enabled;
|
|
40
|
+
}
|
|
41
|
+
return globalDebugLogger?.options?.enabled ?? false;
|
|
42
|
+
}
|
|
43
|
+
log(message, ...args) {
|
|
44
|
+
if (!this.isEnabled()) return;
|
|
45
|
+
const prefix = this.options.prefix;
|
|
46
|
+
console.log(`${prefix} ${message}`, ...args);
|
|
47
|
+
}
|
|
48
|
+
warn(message, ...args) {
|
|
49
|
+
if (!this.isEnabled()) return;
|
|
50
|
+
const prefix = this.options.prefix;
|
|
51
|
+
console.warn(`${prefix} ${message}`, ...args);
|
|
52
|
+
}
|
|
53
|
+
error(message, ...args) {
|
|
54
|
+
if (!this.isEnabled()) return;
|
|
55
|
+
const prefix = this.options.prefix;
|
|
56
|
+
console.error(`${prefix} ${message}`, ...args);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var globalDebugLogger = null;
|
|
60
|
+
function initDebugLogger(enabled = false) {
|
|
61
|
+
globalDebugLogger = new DebugLogger({ enabled });
|
|
62
|
+
}
|
|
63
|
+
function createScopedLogger(scopeName) {
|
|
64
|
+
return new DebugLogger({
|
|
65
|
+
prefix: `[Prepr][${scopeName}]`
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
setTrustedParentOrigin,
|
|
71
|
+
getTrustedParentOrigin,
|
|
72
|
+
sendPreprEvent,
|
|
73
|
+
initDebugLogger,
|
|
74
|
+
createScopedLogger
|
|
75
|
+
};
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isAllowedEditorOrigin
|
|
3
|
+
} from "./chunk-URXSDJOU.js";
|
|
4
|
+
import {
|
|
5
|
+
indexSnapshot,
|
|
6
|
+
isLiveFieldChange,
|
|
7
|
+
parseEditTarget,
|
|
8
|
+
parseListEntries,
|
|
9
|
+
patchSnapshot,
|
|
10
|
+
syncListSnapshot
|
|
11
|
+
} from "./chunk-74KY5EAM.js";
|
|
12
|
+
import {
|
|
13
|
+
createScopedLogger,
|
|
14
|
+
getTrustedParentOrigin,
|
|
15
|
+
sendPreprEvent
|
|
16
|
+
} from "./chunk-S3VT4UWM.js";
|
|
17
|
+
|
|
18
|
+
// src/core/live-preview/bridge-events.ts
|
|
19
|
+
var debug = createScopedLogger("live-preview:bridge");
|
|
20
|
+
function createLiveBridge(store, options = {}) {
|
|
21
|
+
let parentOrigin = null;
|
|
22
|
+
const onMessage = (evt) => {
|
|
23
|
+
const data = evt?.data;
|
|
24
|
+
if (data?.event === "prepr:initVE" && !parentOrigin) {
|
|
25
|
+
if (isAllowedEditorOrigin(evt.origin, options.allowedEditorOrigins?.())) {
|
|
26
|
+
parentOrigin = evt.origin;
|
|
27
|
+
} else {
|
|
28
|
+
debug.warn("ignored live preview handshake from origin", evt.origin);
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const trusted = parentOrigin ?? getTrustedParentOrigin();
|
|
33
|
+
if (!trusted || evt.origin !== trusted) return;
|
|
34
|
+
if (data?.event === "prepr:fieldChange") {
|
|
35
|
+
if (typeof data.itemId === "string" && typeof data.field === "string" && data.field && isLiveFieldChange(data.field, data.value)) {
|
|
36
|
+
const edit = parseEditTarget(data.edit);
|
|
37
|
+
if (edit) store.pushPatch(data.itemId, data.field, data.value, edit);
|
|
38
|
+
else store.pushPatch(data.itemId, data.field, data.value);
|
|
39
|
+
} else {
|
|
40
|
+
debug.log("dropped malformed fieldChange", data);
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (data?.event === "prepr:listChange") {
|
|
45
|
+
const list = parseListEntries(data.entries);
|
|
46
|
+
if (typeof data.itemId === "string" && typeof data.field === "string" && data.field && list) {
|
|
47
|
+
store.pushList(data.itemId, data.field, list);
|
|
48
|
+
} else {
|
|
49
|
+
debug.log("dropped malformed listChange", data);
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (data?.event === "prepr:itemChanged") {
|
|
54
|
+
if (typeof data.itemId === "string") {
|
|
55
|
+
store.invalidate(data.itemId);
|
|
56
|
+
} else {
|
|
57
|
+
debug.log("dropped malformed itemChanged", data);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
start() {
|
|
63
|
+
window.addEventListener("message", onMessage);
|
|
64
|
+
sendPreprEvent(
|
|
65
|
+
"live_ready",
|
|
66
|
+
options.strictMode?.() ? { strictMode: true } : void 0,
|
|
67
|
+
{ allowUntrustedTarget: true }
|
|
68
|
+
);
|
|
69
|
+
},
|
|
70
|
+
stop() {
|
|
71
|
+
window.removeEventListener("message", onMessage);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/core/live-preview/live-store.ts
|
|
77
|
+
var debug2 = createScopedLogger("live-preview");
|
|
78
|
+
var INVALIDATE_DEBOUNCE_MS = 150;
|
|
79
|
+
var MAX_LOG_ENTRIES = 500;
|
|
80
|
+
function withPatch(log, patch) {
|
|
81
|
+
let previous = -1;
|
|
82
|
+
for (let i = log.length - 1; i >= 0; i--) {
|
|
83
|
+
const p = log[i];
|
|
84
|
+
if (p.type === patch.type && p.itemId === patch.itemId && p.field === patch.field) {
|
|
85
|
+
previous = i;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (previous === -1) return [...log, patch];
|
|
90
|
+
const since = log.slice(previous + 1);
|
|
91
|
+
const listPrefix = `${patch.field}.`;
|
|
92
|
+
const dependsOnPosition = since.some(
|
|
93
|
+
(p) => p.type === "list" || patch.type === "list" && p.itemId === patch.itemId && p.field.startsWith(listPrefix)
|
|
94
|
+
);
|
|
95
|
+
if (dependsOnPosition) return [...log, patch];
|
|
96
|
+
return [...log.slice(0, previous), ...since, patch];
|
|
97
|
+
}
|
|
98
|
+
function createLiveStore(options = {}) {
|
|
99
|
+
const accepts = (patch) => options.accept ? options.accept(patch) : true;
|
|
100
|
+
const entries = /* @__PURE__ */ new Set();
|
|
101
|
+
const invalidateListeners = /* @__PURE__ */ new Set();
|
|
102
|
+
const pendingInvalidates = /* @__PURE__ */ new Map();
|
|
103
|
+
let defaultFetcher = null;
|
|
104
|
+
let log = [];
|
|
105
|
+
const logListeners = /* @__PURE__ */ new Set();
|
|
106
|
+
function record(patch) {
|
|
107
|
+
log = withPatch(log, patch).slice(-MAX_LOG_ENTRIES);
|
|
108
|
+
logListeners.forEach((fn) => fn(log));
|
|
109
|
+
}
|
|
110
|
+
function notify(entry) {
|
|
111
|
+
entry.listeners.forEach((fn) => fn());
|
|
112
|
+
}
|
|
113
|
+
async function refetch(entry) {
|
|
114
|
+
const fetcher = entry.opts.fetcher ?? defaultFetcher;
|
|
115
|
+
if (!fetcher || entry.opts.query == null) return;
|
|
116
|
+
const token = ++entry.fetchToken;
|
|
117
|
+
try {
|
|
118
|
+
const result = await fetcher(entry.opts.query, entry.opts.variables);
|
|
119
|
+
if (token !== entry.fetchToken || !entries.has(entry)) return;
|
|
120
|
+
entry.snapshot = result;
|
|
121
|
+
entry.index = indexSnapshot(result);
|
|
122
|
+
notify(entry);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
debug2.log("refetch failed, keeping previous snapshot", error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function runInvalidate(itemId) {
|
|
128
|
+
pendingInvalidates.delete(itemId);
|
|
129
|
+
invalidateListeners.forEach((fn) => fn(itemId));
|
|
130
|
+
for (const entry of entries) {
|
|
131
|
+
if (entry.index.has(itemId)) void refetch(entry);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
register(data, opts = {}) {
|
|
136
|
+
const entry = {
|
|
137
|
+
snapshot: data,
|
|
138
|
+
index: indexSnapshot(data),
|
|
139
|
+
opts,
|
|
140
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
141
|
+
fetchToken: 0
|
|
142
|
+
};
|
|
143
|
+
for (const patch of log) {
|
|
144
|
+
if (patch.type === "field") {
|
|
145
|
+
entry.snapshot = patchSnapshot(
|
|
146
|
+
entry.snapshot,
|
|
147
|
+
entry.index,
|
|
148
|
+
patch.itemId,
|
|
149
|
+
patch.field,
|
|
150
|
+
patch.value
|
|
151
|
+
);
|
|
152
|
+
} else {
|
|
153
|
+
const next = syncListSnapshot(
|
|
154
|
+
entry.snapshot,
|
|
155
|
+
entry.index,
|
|
156
|
+
patch.itemId,
|
|
157
|
+
patch.field,
|
|
158
|
+
patch.entries
|
|
159
|
+
);
|
|
160
|
+
if (next !== entry.snapshot) {
|
|
161
|
+
entry.snapshot = next;
|
|
162
|
+
entry.index = indexSnapshot(next);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
entries.add(entry);
|
|
167
|
+
return {
|
|
168
|
+
getSnapshot: () => entry.snapshot,
|
|
169
|
+
subscribe(fn) {
|
|
170
|
+
entry.listeners.add(fn);
|
|
171
|
+
return () => entry.listeners.delete(fn);
|
|
172
|
+
},
|
|
173
|
+
unregister() {
|
|
174
|
+
entry.listeners.clear();
|
|
175
|
+
entries.delete(entry);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
pushPatch(itemId, field, value, edit) {
|
|
180
|
+
const patch = edit ? { type: "field", itemId, field, value, edit } : { type: "field", itemId, field, value };
|
|
181
|
+
if (!accepts(patch)) return;
|
|
182
|
+
record(patch);
|
|
183
|
+
for (const entry of entries) {
|
|
184
|
+
const next = patchSnapshot(
|
|
185
|
+
entry.snapshot,
|
|
186
|
+
entry.index,
|
|
187
|
+
itemId,
|
|
188
|
+
field,
|
|
189
|
+
value
|
|
190
|
+
);
|
|
191
|
+
if (next !== entry.snapshot) {
|
|
192
|
+
entry.snapshot = next;
|
|
193
|
+
notify(entry);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
pushList(itemId, field, list) {
|
|
198
|
+
const patch = { type: "list", itemId, field, entries: list };
|
|
199
|
+
if (!accepts(patch)) return;
|
|
200
|
+
record(patch);
|
|
201
|
+
for (const entry of entries) {
|
|
202
|
+
const next = syncListSnapshot(
|
|
203
|
+
entry.snapshot,
|
|
204
|
+
entry.index,
|
|
205
|
+
itemId,
|
|
206
|
+
field,
|
|
207
|
+
list
|
|
208
|
+
);
|
|
209
|
+
if (next !== entry.snapshot) {
|
|
210
|
+
entry.snapshot = next;
|
|
211
|
+
entry.index = indexSnapshot(next);
|
|
212
|
+
notify(entry);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
invalidate(itemId) {
|
|
217
|
+
if (log.length) {
|
|
218
|
+
log = [];
|
|
219
|
+
logListeners.forEach((fn) => fn(log));
|
|
220
|
+
}
|
|
221
|
+
const pending = pendingInvalidates.get(itemId);
|
|
222
|
+
if (pending) clearTimeout(pending);
|
|
223
|
+
pendingInvalidates.set(
|
|
224
|
+
itemId,
|
|
225
|
+
setTimeout(() => runInvalidate(itemId), INVALIDATE_DEBOUNCE_MS)
|
|
226
|
+
);
|
|
227
|
+
},
|
|
228
|
+
setFetcher(fetcher) {
|
|
229
|
+
defaultFetcher = fetcher;
|
|
230
|
+
},
|
|
231
|
+
onInvalidate(fn) {
|
|
232
|
+
invalidateListeners.add(fn);
|
|
233
|
+
return () => invalidateListeners.delete(fn);
|
|
234
|
+
},
|
|
235
|
+
getLog: () => log,
|
|
236
|
+
onLogChange(fn) {
|
|
237
|
+
logListeners.add(fn);
|
|
238
|
+
return () => logListeners.delete(fn);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export {
|
|
244
|
+
createLiveBridge,
|
|
245
|
+
createLiveStore
|
|
246
|
+
};
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createScopedLogger,
|
|
3
|
+
sendPreprEvent,
|
|
4
|
+
setTrustedParentOrigin
|
|
5
|
+
} from "./chunk-S3VT4UWM.js";
|
|
6
|
+
|
|
7
|
+
// src/core/locales/de.json
|
|
8
|
+
var de_default = {
|
|
9
|
+
common: {
|
|
10
|
+
viewingAs: "Ansicht als:",
|
|
11
|
+
user: "Benutzer",
|
|
12
|
+
off: "Aus",
|
|
13
|
+
on: "An",
|
|
14
|
+
reset: "Zur\xFCcksetzen",
|
|
15
|
+
toolbar: "Symbolleiste"
|
|
16
|
+
},
|
|
17
|
+
adaptiveContent: {
|
|
18
|
+
adaptiveContent: "Adaptive Inhalte",
|
|
19
|
+
enablePreview: "Vorschaumodus",
|
|
20
|
+
segment: "Segment",
|
|
21
|
+
ABVariant: "A/B-Variante",
|
|
22
|
+
chooseSegment: "Segment w\xE4hlen",
|
|
23
|
+
searchSegments: "Segmente suchen",
|
|
24
|
+
none: "Keine Segmente",
|
|
25
|
+
allOtherUsers: "Alle anderen Benutzer",
|
|
26
|
+
offDescription: "Die Website als echter Benutzer ansehen (Cookies verwenden)",
|
|
27
|
+
onDescription: "Mit der Symbolleiste Segmente und A/B-Varianten simulieren"
|
|
28
|
+
},
|
|
29
|
+
editingTools: {
|
|
30
|
+
editingTools: "Bearbeitungswerkzeuge",
|
|
31
|
+
editMode: "Bearbeitungsmodus",
|
|
32
|
+
ariaCloseEditMode: "Bearbeitungsmodus schlie\xDFen"
|
|
33
|
+
},
|
|
34
|
+
visualEditor: {
|
|
35
|
+
edit: "Bearbeiten",
|
|
36
|
+
otherItem: "anderes Element",
|
|
37
|
+
linkedItem: "verkn\xFCpftes Element"
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/core/locales/en.json
|
|
42
|
+
var en_default = {
|
|
43
|
+
common: {
|
|
44
|
+
viewingAs: "Viewing as:",
|
|
45
|
+
user: "User",
|
|
46
|
+
off: "Off",
|
|
47
|
+
on: "On",
|
|
48
|
+
reset: "Reset",
|
|
49
|
+
toolbar: "Toolbar"
|
|
50
|
+
},
|
|
51
|
+
adaptiveContent: {
|
|
52
|
+
adaptiveContent: "Adaptive content",
|
|
53
|
+
enablePreview: "Preview mode",
|
|
54
|
+
segment: "Segment",
|
|
55
|
+
ABVariant: "A/B variant",
|
|
56
|
+
chooseSegment: "Choose segment",
|
|
57
|
+
searchSegments: "Search segments",
|
|
58
|
+
none: "No segments",
|
|
59
|
+
allOtherUsers: "All other users",
|
|
60
|
+
offDescription: "View the site as a real user (use cookies)",
|
|
61
|
+
onDescription: "Use the toolbar to simulate segments and A/B variants"
|
|
62
|
+
},
|
|
63
|
+
editingTools: {
|
|
64
|
+
editingTools: "Editing tools",
|
|
65
|
+
editMode: "Edit mode",
|
|
66
|
+
ariaCloseEditMode: "Close edit mode"
|
|
67
|
+
},
|
|
68
|
+
visualEditor: {
|
|
69
|
+
edit: "Edit",
|
|
70
|
+
otherItem: "other item",
|
|
71
|
+
linkedItem: "linked item"
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// src/core/locales/fr.json
|
|
76
|
+
var fr_default = {
|
|
77
|
+
common: {
|
|
78
|
+
viewingAs: "Affichage en tant que :",
|
|
79
|
+
user: "Utilisateur",
|
|
80
|
+
off: "D\xE9sactiv\xE9",
|
|
81
|
+
on: "Activ\xE9",
|
|
82
|
+
reset: "R\xE9initialiser",
|
|
83
|
+
toolbar: "Barre d'outils"
|
|
84
|
+
},
|
|
85
|
+
adaptiveContent: {
|
|
86
|
+
adaptiveContent: "Contenu adaptatif",
|
|
87
|
+
enablePreview: "Mode aper\xE7u",
|
|
88
|
+
segment: "Segment",
|
|
89
|
+
ABVariant: "Variante A/B",
|
|
90
|
+
chooseSegment: "Choisir un segment",
|
|
91
|
+
searchSegments: "Rechercher des segments",
|
|
92
|
+
none: "Aucun segment",
|
|
93
|
+
allOtherUsers: "Tous les autres utilisateurs",
|
|
94
|
+
offDescription: "Voir le site comme un vrai utilisateur (utiliser les cookies)",
|
|
95
|
+
onDescription: "Utilisez la barre d'outils pour simuler des segments et des variantes A/B"
|
|
96
|
+
},
|
|
97
|
+
editingTools: {
|
|
98
|
+
editingTools: "Outils d'\xE9dition",
|
|
99
|
+
editMode: "Mode \xE9dition",
|
|
100
|
+
ariaCloseEditMode: "Fermer le mode \xE9dition"
|
|
101
|
+
},
|
|
102
|
+
visualEditor: {
|
|
103
|
+
edit: "Modifier",
|
|
104
|
+
otherItem: "autre \xE9l\xE9ment",
|
|
105
|
+
linkedItem: "\xE9l\xE9ment li\xE9"
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// src/core/locales/nl.json
|
|
110
|
+
var nl_default = {
|
|
111
|
+
common: {
|
|
112
|
+
viewingAs: "Bekijken als:",
|
|
113
|
+
user: "Gebruiker",
|
|
114
|
+
off: "Uit",
|
|
115
|
+
on: "Aan",
|
|
116
|
+
reset: "Resetten",
|
|
117
|
+
toolbar: "Toolbar"
|
|
118
|
+
},
|
|
119
|
+
adaptiveContent: {
|
|
120
|
+
adaptiveContent: "Adaptieve inhoud",
|
|
121
|
+
enablePreview: "Preview modus",
|
|
122
|
+
segment: "Segment",
|
|
123
|
+
ABVariant: "A/B-variant",
|
|
124
|
+
chooseSegment: "Kies segment",
|
|
125
|
+
searchSegments: "Zoek segmenten",
|
|
126
|
+
none: "Geen segmenten",
|
|
127
|
+
allOtherUsers: "Alle andere gebruikers",
|
|
128
|
+
offDescription: "Bekijk de site als een echte gebruiker (gebruik cookies)",
|
|
129
|
+
onDescription: "Gebruik de werkbalk om segmenten en A/B-varianten te simuleren"
|
|
130
|
+
},
|
|
131
|
+
editingTools: {
|
|
132
|
+
editingTools: "Editing Tools",
|
|
133
|
+
editMode: "Edit mode",
|
|
134
|
+
ariaCloseEditMode: "Edit mode sluiten"
|
|
135
|
+
},
|
|
136
|
+
visualEditor: {
|
|
137
|
+
edit: "Bewerken",
|
|
138
|
+
otherItem: "ander item",
|
|
139
|
+
linkedItem: "gekoppeld item"
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// src/core/i18n.ts
|
|
144
|
+
var dictionaries = {
|
|
145
|
+
en: en_default,
|
|
146
|
+
nl: nl_default,
|
|
147
|
+
fr: fr_default,
|
|
148
|
+
de: de_default
|
|
149
|
+
};
|
|
150
|
+
var LOCALES = Object.keys(dictionaries);
|
|
151
|
+
function isLocale(value) {
|
|
152
|
+
return typeof value === "string" && value in dictionaries;
|
|
153
|
+
}
|
|
154
|
+
function getDict(locale) {
|
|
155
|
+
return isLocale(locale) ? dictionaries[locale] : dictionaries.en;
|
|
156
|
+
}
|
|
157
|
+
function getFromPath(obj, path) {
|
|
158
|
+
return path.split(".").reduce(
|
|
159
|
+
(acc, key) => acc && typeof acc === "object" ? acc[key] : void 0,
|
|
160
|
+
obj
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
function format(message, vars) {
|
|
164
|
+
if (!vars) return message;
|
|
165
|
+
return Object.keys(vars).reduce(
|
|
166
|
+
(acc, k) => acc.replace(new RegExp(`\\{${k}\\}`, "g"), String(vars[k])),
|
|
167
|
+
message
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
function t(key, locale, vars) {
|
|
171
|
+
const dict = getDict(locale);
|
|
172
|
+
const msg = getFromPath(dict, key);
|
|
173
|
+
if (typeof msg === "string") return format(msg, vars);
|
|
174
|
+
return key;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/core/iframe-bridge.ts
|
|
178
|
+
var debug = createScopedLogger("iframe-bridge");
|
|
179
|
+
var MAX_REFERENCES = 500;
|
|
180
|
+
var MAX_HREF_LENGTH = 8192;
|
|
181
|
+
var MAX_ASSETS = 500;
|
|
182
|
+
var MAX_ASSET_KEY_LENGTH = 2048;
|
|
183
|
+
var MAX_ASSET_FIELD_LENGTH = 512;
|
|
184
|
+
function parseIds(value) {
|
|
185
|
+
if (!Array.isArray(value)) return void 0;
|
|
186
|
+
return value.slice(0, MAX_REFERENCES).filter((id) => typeof id === "string" && id.length > 0);
|
|
187
|
+
}
|
|
188
|
+
function parseReferences(value) {
|
|
189
|
+
if (!Array.isArray(value)) return void 0;
|
|
190
|
+
const list = [];
|
|
191
|
+
for (const entry of value.slice(0, MAX_REFERENCES)) {
|
|
192
|
+
const id = entry?.id;
|
|
193
|
+
const field = entry?.field;
|
|
194
|
+
if (typeof id === "string" && id && typeof field === "string" && field) {
|
|
195
|
+
list.push({ id, field });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return list;
|
|
199
|
+
}
|
|
200
|
+
function boundedString(value, max) {
|
|
201
|
+
return typeof value === "string" && value && value.length <= max ? value : void 0;
|
|
202
|
+
}
|
|
203
|
+
function parseAssets(value) {
|
|
204
|
+
if (!Array.isArray(value)) return void 0;
|
|
205
|
+
const list = [];
|
|
206
|
+
for (const entry of value.slice(0, MAX_ASSETS)) {
|
|
207
|
+
if (!entry || typeof entry !== "object") continue;
|
|
208
|
+
const raw = entry;
|
|
209
|
+
const key = boundedString(raw.key, MAX_ASSET_KEY_LENGTH);
|
|
210
|
+
const field = boundedString(raw.field, MAX_ASSET_FIELD_LENGTH);
|
|
211
|
+
if (!key || !field) continue;
|
|
212
|
+
const entryId = boundedString(raw.entryId, MAX_ASSET_FIELD_LENGTH);
|
|
213
|
+
list.push(entryId ? { key, field, entryId } : { key, field });
|
|
214
|
+
}
|
|
215
|
+
return list;
|
|
216
|
+
}
|
|
217
|
+
var EDITOR_BASE_DOMAIN = "prepr.io";
|
|
218
|
+
function isAllowedEditorOrigin(origin, allowed) {
|
|
219
|
+
if (allowed) {
|
|
220
|
+
if (allowed.includes("*")) return origin !== "null";
|
|
221
|
+
return allowed.includes(origin);
|
|
222
|
+
}
|
|
223
|
+
let url;
|
|
224
|
+
try {
|
|
225
|
+
url = new URL(origin);
|
|
226
|
+
} catch {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
if (url.protocol !== "https:" || url.port !== "") return false;
|
|
230
|
+
const suffix = `.${EDITOR_BASE_DOMAIN}`;
|
|
231
|
+
if (!url.hostname.endsWith(suffix)) return false;
|
|
232
|
+
const label = url.hostname.slice(0, -suffix.length);
|
|
233
|
+
return label.length > 0 && !label.includes(".");
|
|
234
|
+
}
|
|
235
|
+
function createIframeBridge(store, options = {}) {
|
|
236
|
+
const allowedOrigins = options.allowedEditorOrigins;
|
|
237
|
+
const onScrollToField = options.onScrollToField;
|
|
238
|
+
const onHandshake = options.onHandshake;
|
|
239
|
+
const onReferences = options.onReferences;
|
|
240
|
+
const onAssets = options.onAssets;
|
|
241
|
+
const onAllowNavigation = options.onAllowNavigation;
|
|
242
|
+
let parentOrigin = null;
|
|
243
|
+
const onKeyDown = (event) => {
|
|
244
|
+
const key = event.key.toLowerCase();
|
|
245
|
+
const blocked = (event.ctrlKey || event.metaKey) && ["s", "p", "l"].includes(key);
|
|
246
|
+
if (blocked) event.preventDefault();
|
|
247
|
+
};
|
|
248
|
+
const onMessage = (evt) => {
|
|
249
|
+
const data = evt?.data;
|
|
250
|
+
if (data?.event === "prepr:initVE" && !parentOrigin) {
|
|
251
|
+
if (!isAllowedEditorOrigin(evt.origin, allowedOrigins)) {
|
|
252
|
+
debug.warn("ignored editor handshake from origin", evt.origin);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
parentOrigin = evt.origin;
|
|
256
|
+
setTrustedParentOrigin(parentOrigin);
|
|
257
|
+
if (data.scrollPosition != null) {
|
|
258
|
+
const top = data.scrollPosition;
|
|
259
|
+
setTimeout(() => window.scrollTo(0, top), 1);
|
|
260
|
+
}
|
|
261
|
+
store?.set({ previewMode: true, editMode: data.editMode ?? true });
|
|
262
|
+
const itemId = typeof data.itemId === "string" && data.itemId ? data.itemId : void 0;
|
|
263
|
+
const referencedIds = parseReferences(data.referencedIds);
|
|
264
|
+
const componentIds = parseIds(data.componentIds);
|
|
265
|
+
const uiLocale = isLocale(data.uiLocale) ? data.uiLocale : void 0;
|
|
266
|
+
const navigationGuard = data.navigationGuard === true;
|
|
267
|
+
const assets = parseAssets(data.assets);
|
|
268
|
+
try {
|
|
269
|
+
onHandshake?.({
|
|
270
|
+
...itemId && { itemId },
|
|
271
|
+
...referencedIds && { referencedIds },
|
|
272
|
+
...componentIds && { componentIds },
|
|
273
|
+
...uiLocale && { uiLocale },
|
|
274
|
+
...navigationGuard && { navigationGuard },
|
|
275
|
+
...assets && { assets }
|
|
276
|
+
});
|
|
277
|
+
} catch (error) {
|
|
278
|
+
debug.warn("handshake handler failed", error);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (!parentOrigin || evt.origin !== parentOrigin) return;
|
|
282
|
+
if (data?.event === "prepr:references") {
|
|
283
|
+
const assets = parseAssets(data.assets);
|
|
284
|
+
if (assets) {
|
|
285
|
+
try {
|
|
286
|
+
onAssets?.(assets);
|
|
287
|
+
} catch (error) {
|
|
288
|
+
debug.warn("assets handler failed", error);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const referencedIds = parseReferences(data.referencedIds);
|
|
292
|
+
if (!referencedIds) return;
|
|
293
|
+
try {
|
|
294
|
+
onReferences?.(referencedIds, parseIds(data.componentIds));
|
|
295
|
+
} catch (error) {
|
|
296
|
+
debug.warn("references handler failed", error);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (data?.event === "prepr:getScrollPosition") {
|
|
300
|
+
const currentScrollY = window.scrollY || document.documentElement.scrollTop;
|
|
301
|
+
sendPreprEvent("getScrollPosition", { value: currentScrollY });
|
|
302
|
+
}
|
|
303
|
+
if (data?.event === "prepr:scrollToField") {
|
|
304
|
+
if (typeof data.field !== "string" || !data.field) return;
|
|
305
|
+
if (data.id !== void 0 && typeof data.id !== "string") return;
|
|
306
|
+
const block = typeof data.block === "number" && Number.isInteger(data.block) ? data.block : void 0;
|
|
307
|
+
const entryId = typeof data.entryId === "string" && data.entryId ? data.entryId : void 0;
|
|
308
|
+
const fieldById = typeof data.fieldById === "string" && data.fieldById ? data.fieldById : void 0;
|
|
309
|
+
try {
|
|
310
|
+
onScrollToField?.({
|
|
311
|
+
field: data.field,
|
|
312
|
+
id: data.id,
|
|
313
|
+
block,
|
|
314
|
+
entryId,
|
|
315
|
+
fieldById
|
|
316
|
+
});
|
|
317
|
+
} catch (error) {
|
|
318
|
+
debug.warn("scrollToField handler failed", error);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (data?.event === "prepr:allowNavigation") {
|
|
322
|
+
const href = data.href;
|
|
323
|
+
if (typeof href !== "string" || !href || href.length > MAX_HREF_LENGTH) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
onAllowNavigation?.(href);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
debug.warn("allowNavigation handler failed", error);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
return {
|
|
334
|
+
start() {
|
|
335
|
+
const features = store?.get().features;
|
|
336
|
+
sendPreprEvent("loaded", features ? { features } : void 0, {
|
|
337
|
+
allowUntrustedTarget: true
|
|
338
|
+
});
|
|
339
|
+
window.addEventListener("keydown", onKeyDown);
|
|
340
|
+
window.addEventListener("message", onMessage);
|
|
341
|
+
},
|
|
342
|
+
stop() {
|
|
343
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
344
|
+
window.removeEventListener("message", onMessage);
|
|
345
|
+
parentOrigin = null;
|
|
346
|
+
setTrustedParentOrigin(null);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export {
|
|
352
|
+
isLocale,
|
|
353
|
+
t,
|
|
354
|
+
isAllowedEditorOrigin,
|
|
355
|
+
createIframeBridge
|
|
356
|
+
};
|