@preprio/toolkit 0.5.0-rc.5 → 0.5.1-dom.0

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.
Files changed (53) hide show
  1. package/README.md +218 -226
  2. package/dist/astro/index.cjs +1 -1
  3. package/dist/astro/index.js +1 -1
  4. package/dist/auto.cjs +4572 -0
  5. package/dist/auto.d.cts +42 -0
  6. package/dist/auto.d.ts +42 -0
  7. package/dist/auto.js +105 -0
  8. package/dist/browser/auto.js +117 -0
  9. package/dist/chunk-5I5TQ3NO.js +74 -0
  10. package/dist/chunk-AZC4BZJI.js +447 -0
  11. package/dist/{chunk-TG6N3C22.js → chunk-IKOOXTPM.js} +1 -1
  12. package/dist/{chunk-3X55JL52.js → chunk-IOSO232M.js} +4 -2
  13. package/dist/{chunk-SBLZANL5.js → chunk-RRM5762S.js} +2 -71
  14. package/dist/chunk-SZTHSJUA.js +326 -0
  15. package/dist/{chunk-CMUFTCG3.js → chunk-TEB7M7EM.js} +0 -4
  16. package/dist/chunk-UK664KSV.js +6 -0
  17. package/dist/{chunk-74KY5EAM.js → chunk-ZFGVP2GW.js} +28 -447
  18. package/dist/html-live-DzmEG9wU.d.cts +42 -0
  19. package/dist/html-live-DzmEG9wU.d.ts +42 -0
  20. package/dist/index.cjs +177 -2
  21. package/dist/index.d.cts +31 -28
  22. package/dist/index.d.ts +31 -28
  23. package/dist/index.js +21 -154
  24. package/dist/{live-preview-H4643QYF.js → live-preview-IYAS7PYV.js} +3 -2
  25. package/dist/nextjs/components.cjs +1 -1
  26. package/dist/nextjs/components.d.cts +2 -1
  27. package/dist/nextjs/components.d.ts +2 -1
  28. package/dist/nextjs/components.js +6 -3
  29. package/dist/nextjs/index.cjs +1 -1
  30. package/dist/nextjs/index.d.cts +0 -2
  31. package/dist/nextjs/index.d.ts +0 -2
  32. package/dist/nextjs/index.js +1 -1
  33. package/dist/nextjs/live-action.js +5 -3
  34. package/dist/nextjs/live.cjs +1 -4
  35. package/dist/nextjs/live.d.cts +1 -3
  36. package/dist/nextjs/live.d.ts +1 -3
  37. package/dist/nextjs/live.js +2 -5
  38. package/dist/nuxt/index.cjs +1 -1
  39. package/dist/nuxt/index.js +1 -1
  40. package/dist/pixel-DwW7cXJm.d.cts +49 -0
  41. package/dist/pixel-DwW7cXJm.d.ts +49 -0
  42. package/dist/react/components.cjs +1 -1
  43. package/dist/react/components.js +1 -1
  44. package/dist/sveltekit/index.cjs +1 -1
  45. package/dist/sveltekit/index.js +1 -1
  46. package/dist/{pixel-CX422dCO.d.cts → types-DtMa_-f2.d.cts} +1 -49
  47. package/dist/{pixel-CX422dCO.d.ts → types-DtMa_-f2.d.ts} +1 -49
  48. package/package.json +12 -7
  49. package/dist/sveltekit/live-preview-O2ZTJNW4.js +0 -1520
  50. package/dist/sveltekit/live.cjs +0 -1731
  51. package/dist/sveltekit/live.d.cts +0 -59
  52. package/dist/sveltekit/live.d.ts +0 -59
  53. package/dist/sveltekit/live.js +0 -97
package/dist/auto.cjs ADDED
@@ -0,0 +1,4572 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/auto.ts
21
+ var auto_exports = {};
22
+ __export(auto_exports, {
23
+ startPreprAuto: () => startPreprAuto
24
+ });
25
+ module.exports = __toCommonJS(auto_exports);
26
+
27
+ // src/core/constants.ts
28
+ var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
29
+ var COOKIE_TOOLBAR_OPEN = "Prepr-Toolbar-Open";
30
+ var COOKIE_SEGMENT = "Prepr-Segments";
31
+ var COOKIE_VARIANT = "Prepr-ABtesting";
32
+ var PARAM_SEGMENT = "prepr_preview_segment";
33
+ var PARAM_VARIANT = "prepr_preview_ab";
34
+ var PARAM_HIDE_BAR = "prepr_hide_bar";
35
+ var ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
36
+ var HEADER_LIVE_RENDER = "x-prepr-live";
37
+
38
+ // src/core/cookies.ts
39
+ function getCookie(name) {
40
+ if (typeof document === "undefined") return null;
41
+ const match = document.cookie.split("; ").find((row) => row.startsWith(`${name}=`));
42
+ if (!match) return null;
43
+ const value = match.slice(name.length + 1);
44
+ return decodeURIComponent(value);
45
+ }
46
+ function setCookie(name, value, options = {}) {
47
+ if (typeof document === "undefined") return;
48
+ const { maxAge, path = "/", sameSite, secure } = options;
49
+ let cookie = `${name}=${encodeURIComponent(value)};path=${path}`;
50
+ if (typeof maxAge === "number") {
51
+ cookie += `;max-age=${maxAge}`;
52
+ }
53
+ if (sameSite) {
54
+ cookie += `;samesite=${sameSite}`;
55
+ }
56
+ if (secure) {
57
+ cookie += ";secure";
58
+ }
59
+ document.cookie = cookie;
60
+ }
61
+ function removeCookie(name, path = "/", options = {}) {
62
+ if (typeof document === "undefined") return;
63
+ const { sameSite, secure } = options;
64
+ let cookie = `${name}=;path=${path};expires=Thu, 01 Jan 1970 00:00:00 GMT`;
65
+ if (sameSite) {
66
+ cookie += `;samesite=${sameSite}`;
67
+ }
68
+ if (secure) {
69
+ cookie += ";secure";
70
+ }
71
+ document.cookie = cookie;
72
+ }
73
+ function crossSiteCookieOptions() {
74
+ if (typeof window === "undefined" || !window.isSecureContext) return {};
75
+ return { sameSite: "None", secure: true };
76
+ }
77
+
78
+ // src/core/features.ts
79
+ function isEnabled(config) {
80
+ if (typeof config === "boolean") return config;
81
+ return config?.enabled ?? true;
82
+ }
83
+ function resolveFeatures(features) {
84
+ return {
85
+ segments: isEnabled(features?.segments),
86
+ abTesting: isEnabled(features?.abTesting),
87
+ editMode: isEnabled(features?.editMode)
88
+ };
89
+ }
90
+ var ALL_FEATURES_ENABLED = Object.freeze({
91
+ segments: true,
92
+ abTesting: true,
93
+ editMode: true
94
+ });
95
+
96
+ // src/core/locales/de.json
97
+ var de_default = {
98
+ common: {
99
+ viewingAs: "Ansicht als:",
100
+ user: "Benutzer",
101
+ off: "Aus",
102
+ on: "An",
103
+ reset: "Zur\xFCcksetzen",
104
+ toolbar: "Symbolleiste"
105
+ },
106
+ adaptiveContent: {
107
+ adaptiveContent: "Adaptive Inhalte",
108
+ enablePreview: "Vorschaumodus",
109
+ segment: "Segment",
110
+ ABVariant: "A/B-Variante",
111
+ chooseSegment: "Segment w\xE4hlen",
112
+ searchSegments: "Segmente suchen",
113
+ none: "Keine Segmente",
114
+ allOtherUsers: "Alle anderen Benutzer",
115
+ offDescription: "Die Website als echter Benutzer ansehen (Cookies verwenden)",
116
+ onDescription: "Mit der Symbolleiste Segmente und A/B-Varianten simulieren"
117
+ },
118
+ editingTools: {
119
+ editingTools: "Bearbeitungswerkzeuge",
120
+ editMode: "Bearbeitungsmodus",
121
+ ariaCloseEditMode: "Bearbeitungsmodus schlie\xDFen"
122
+ },
123
+ visualEditor: {
124
+ edit: "Bearbeiten",
125
+ otherItem: "anderes Element",
126
+ linkedItem: "verkn\xFCpftes Element"
127
+ }
128
+ };
129
+
130
+ // src/core/locales/en.json
131
+ var en_default = {
132
+ common: {
133
+ viewingAs: "Viewing as:",
134
+ user: "User",
135
+ off: "Off",
136
+ on: "On",
137
+ reset: "Reset",
138
+ toolbar: "Toolbar"
139
+ },
140
+ adaptiveContent: {
141
+ adaptiveContent: "Adaptive content",
142
+ enablePreview: "Preview mode",
143
+ segment: "Segment",
144
+ ABVariant: "A/B variant",
145
+ chooseSegment: "Choose segment",
146
+ searchSegments: "Search segments",
147
+ none: "No segments",
148
+ allOtherUsers: "All other users",
149
+ offDescription: "View the site as a real user (use cookies)",
150
+ onDescription: "Use the toolbar to simulate segments and A/B variants"
151
+ },
152
+ editingTools: {
153
+ editingTools: "Editing tools",
154
+ editMode: "Edit mode",
155
+ ariaCloseEditMode: "Close edit mode"
156
+ },
157
+ visualEditor: {
158
+ edit: "Edit",
159
+ otherItem: "other item",
160
+ linkedItem: "linked item"
161
+ }
162
+ };
163
+
164
+ // src/core/locales/fr.json
165
+ var fr_default = {
166
+ common: {
167
+ viewingAs: "Affichage en tant que :",
168
+ user: "Utilisateur",
169
+ off: "D\xE9sactiv\xE9",
170
+ on: "Activ\xE9",
171
+ reset: "R\xE9initialiser",
172
+ toolbar: "Barre d'outils"
173
+ },
174
+ adaptiveContent: {
175
+ adaptiveContent: "Contenu adaptatif",
176
+ enablePreview: "Mode aper\xE7u",
177
+ segment: "Segment",
178
+ ABVariant: "Variante A/B",
179
+ chooseSegment: "Choisir un segment",
180
+ searchSegments: "Rechercher des segments",
181
+ none: "Aucun segment",
182
+ allOtherUsers: "Tous les autres utilisateurs",
183
+ offDescription: "Voir le site comme un vrai utilisateur (utiliser les cookies)",
184
+ onDescription: "Utilisez la barre d'outils pour simuler des segments et des variantes A/B"
185
+ },
186
+ editingTools: {
187
+ editingTools: "Outils d'\xE9dition",
188
+ editMode: "Mode \xE9dition",
189
+ ariaCloseEditMode: "Fermer le mode \xE9dition"
190
+ },
191
+ visualEditor: {
192
+ edit: "Modifier",
193
+ otherItem: "autre \xE9l\xE9ment",
194
+ linkedItem: "\xE9l\xE9ment li\xE9"
195
+ }
196
+ };
197
+
198
+ // src/core/locales/nl.json
199
+ var nl_default = {
200
+ common: {
201
+ viewingAs: "Bekijken als:",
202
+ user: "Gebruiker",
203
+ off: "Uit",
204
+ on: "Aan",
205
+ reset: "Resetten",
206
+ toolbar: "Toolbar"
207
+ },
208
+ adaptiveContent: {
209
+ adaptiveContent: "Adaptieve inhoud",
210
+ enablePreview: "Preview modus",
211
+ segment: "Segment",
212
+ ABVariant: "A/B-variant",
213
+ chooseSegment: "Kies segment",
214
+ searchSegments: "Zoek segmenten",
215
+ none: "Geen segmenten",
216
+ allOtherUsers: "Alle andere gebruikers",
217
+ offDescription: "Bekijk de site als een echte gebruiker (gebruik cookies)",
218
+ onDescription: "Gebruik de werkbalk om segmenten en A/B-varianten te simuleren"
219
+ },
220
+ editingTools: {
221
+ editingTools: "Editing Tools",
222
+ editMode: "Edit mode",
223
+ ariaCloseEditMode: "Edit mode sluiten"
224
+ },
225
+ visualEditor: {
226
+ edit: "Bewerken",
227
+ otherItem: "ander item",
228
+ linkedItem: "gekoppeld item"
229
+ }
230
+ };
231
+
232
+ // src/core/i18n.ts
233
+ var dictionaries = {
234
+ en: en_default,
235
+ nl: nl_default,
236
+ fr: fr_default,
237
+ de: de_default
238
+ };
239
+ var LOCALES = Object.keys(dictionaries);
240
+ function isLocale(value) {
241
+ return typeof value === "string" && value in dictionaries;
242
+ }
243
+ function getDict(locale) {
244
+ return isLocale(locale) ? dictionaries[locale] : dictionaries.en;
245
+ }
246
+ function getFromPath(obj, path) {
247
+ return path.split(".").reduce(
248
+ (acc, key) => acc && typeof acc === "object" ? acc[key] : void 0,
249
+ obj
250
+ );
251
+ }
252
+ function format(message, vars) {
253
+ if (!vars) return message;
254
+ return Object.keys(vars).reduce(
255
+ (acc, k2) => acc.replace(new RegExp(`\\{${k2}\\}`, "g"), String(vars[k2])),
256
+ message
257
+ );
258
+ }
259
+ function t(key, locale, vars) {
260
+ const dict = getDict(locale);
261
+ const msg = getFromPath(dict, key);
262
+ if (typeof msg === "string") return format(msg, vars);
263
+ return key;
264
+ }
265
+
266
+ // src/core/utils.ts
267
+ var trustedParentOrigin = null;
268
+ function setTrustedParentOrigin(origin) {
269
+ trustedParentOrigin = origin;
270
+ }
271
+ function getTrustedParentOrigin() {
272
+ return trustedParentOrigin;
273
+ }
274
+ function sendPreprEvent(event, data, options) {
275
+ if (typeof window !== "undefined") {
276
+ const message = {
277
+ name: "prepr_preview_bar",
278
+ event,
279
+ ...data
280
+ };
281
+ window.dispatchEvent(
282
+ new CustomEvent("prepr_preview_bar", { detail: message })
283
+ );
284
+ if (window.parent && window.parent !== window) {
285
+ if (trustedParentOrigin) {
286
+ window.parent.postMessage(message, trustedParentOrigin);
287
+ } else if (options?.allowUntrustedTarget) {
288
+ window.parent.postMessage(message, "*");
289
+ }
290
+ }
291
+ }
292
+ }
293
+ var DebugLogger = class {
294
+ constructor(options) {
295
+ this.options = {
296
+ prefix: "[Prepr]",
297
+ ...options
298
+ };
299
+ }
300
+ // A local `enabled` wins; otherwise defer to the global logger so scoped
301
+ // loggers created before initDebugLogger() still pick up the setting.
302
+ isEnabled() {
303
+ if (this.options.enabled !== void 0) {
304
+ return this.options.enabled;
305
+ }
306
+ return globalDebugLogger?.options?.enabled ?? false;
307
+ }
308
+ log(message, ...args) {
309
+ if (!this.isEnabled()) return;
310
+ const prefix = this.options.prefix;
311
+ console.log(`${prefix} ${message}`, ...args);
312
+ }
313
+ warn(message, ...args) {
314
+ if (!this.isEnabled()) return;
315
+ const prefix = this.options.prefix;
316
+ console.warn(`${prefix} ${message}`, ...args);
317
+ }
318
+ error(message, ...args) {
319
+ if (!this.isEnabled()) return;
320
+ const prefix = this.options.prefix;
321
+ console.error(`${prefix} ${message}`, ...args);
322
+ }
323
+ };
324
+ var globalDebugLogger = null;
325
+ function initDebugLogger(enabled = false) {
326
+ globalDebugLogger = new DebugLogger({ enabled });
327
+ }
328
+ function createScopedLogger(scopeName) {
329
+ return new DebugLogger({
330
+ prefix: `[Prepr][${scopeName}]`
331
+ });
332
+ }
333
+
334
+ // src/core/iframe-bridge.ts
335
+ var debug = createScopedLogger("iframe-bridge");
336
+ var MAX_REFERENCES = 500;
337
+ var MAX_HREF_LENGTH = 8192;
338
+ var MAX_ASSETS = 500;
339
+ var MAX_ASSET_KEY_LENGTH = 2048;
340
+ var MAX_ASSET_FIELD_LENGTH = 512;
341
+ function parseIds(value) {
342
+ if (!Array.isArray(value)) return void 0;
343
+ return value.slice(0, MAX_REFERENCES).filter((id) => typeof id === "string" && id.length > 0);
344
+ }
345
+ function parseReferences(value) {
346
+ if (!Array.isArray(value)) return void 0;
347
+ const list = [];
348
+ for (const entry of value.slice(0, MAX_REFERENCES)) {
349
+ const id = entry?.id;
350
+ const field = entry?.field;
351
+ if (typeof id === "string" && id && typeof field === "string" && field) {
352
+ list.push({ id, field });
353
+ }
354
+ }
355
+ return list;
356
+ }
357
+ function boundedString(value, max) {
358
+ return typeof value === "string" && value && value.length <= max ? value : void 0;
359
+ }
360
+ function parseAssets(value) {
361
+ if (!Array.isArray(value)) return void 0;
362
+ const list = [];
363
+ for (const entry of value.slice(0, MAX_ASSETS)) {
364
+ if (!entry || typeof entry !== "object") continue;
365
+ const raw = entry;
366
+ const key = boundedString(raw.key, MAX_ASSET_KEY_LENGTH);
367
+ const field = boundedString(raw.field, MAX_ASSET_FIELD_LENGTH);
368
+ if (!key || !field) continue;
369
+ const entryId = boundedString(raw.entryId, MAX_ASSET_FIELD_LENGTH);
370
+ list.push(entryId ? { key, field, entryId } : { key, field });
371
+ }
372
+ return list;
373
+ }
374
+ var EDITOR_BASE_DOMAIN = "prepr.io";
375
+ function isAllowedEditorOrigin(origin, allowed) {
376
+ if (allowed) {
377
+ if (allowed.includes("*")) return origin !== "null";
378
+ return allowed.includes(origin);
379
+ }
380
+ let url;
381
+ try {
382
+ url = new URL(origin);
383
+ } catch {
384
+ return false;
385
+ }
386
+ if (url.protocol !== "https:" || url.port !== "") return false;
387
+ const suffix = `.${EDITOR_BASE_DOMAIN}`;
388
+ if (!url.hostname.endsWith(suffix)) return false;
389
+ const label = url.hostname.slice(0, -suffix.length);
390
+ return label.length > 0 && !label.includes(".");
391
+ }
392
+ function createIframeBridge(store, options = {}) {
393
+ const allowedOrigins = options.allowedEditorOrigins;
394
+ const onScrollToField = options.onScrollToField;
395
+ const onHandshake = options.onHandshake;
396
+ const onReferences = options.onReferences;
397
+ const onAssets = options.onAssets;
398
+ const onAllowNavigation = options.onAllowNavigation;
399
+ let parentOrigin = null;
400
+ const onKeyDown = (event) => {
401
+ const key = event.key.toLowerCase();
402
+ const blocked = (event.ctrlKey || event.metaKey) && ["s", "p", "l"].includes(key);
403
+ if (blocked) event.preventDefault();
404
+ };
405
+ const onMessage = (evt) => {
406
+ const data = evt?.data;
407
+ if (data?.event === "prepr:initVE" && !parentOrigin) {
408
+ if (!isAllowedEditorOrigin(evt.origin, allowedOrigins)) {
409
+ debug.warn("ignored editor handshake from origin", evt.origin);
410
+ return;
411
+ }
412
+ parentOrigin = evt.origin;
413
+ setTrustedParentOrigin(parentOrigin);
414
+ if (data.scrollPosition != null) {
415
+ const top = data.scrollPosition;
416
+ setTimeout(() => window.scrollTo(0, top), 1);
417
+ }
418
+ store?.set({ previewMode: true, editMode: data.editMode ?? true });
419
+ const itemId = typeof data.itemId === "string" && data.itemId ? data.itemId : void 0;
420
+ const referencedIds = parseReferences(data.referencedIds);
421
+ const componentIds = parseIds(data.componentIds);
422
+ const uiLocale = isLocale(data.uiLocale) ? data.uiLocale : void 0;
423
+ const navigationGuard = data.navigationGuard === true;
424
+ const assets = parseAssets(data.assets);
425
+ try {
426
+ onHandshake?.({
427
+ ...itemId && { itemId },
428
+ ...referencedIds && { referencedIds },
429
+ ...componentIds && { componentIds },
430
+ ...uiLocale && { uiLocale },
431
+ ...navigationGuard && { navigationGuard },
432
+ ...assets && { assets }
433
+ });
434
+ } catch (error) {
435
+ debug.warn("handshake handler failed", error);
436
+ }
437
+ }
438
+ if (!parentOrigin || evt.origin !== parentOrigin) return;
439
+ if (data?.event === "prepr:references") {
440
+ const assets = parseAssets(data.assets);
441
+ if (assets) {
442
+ try {
443
+ onAssets?.(assets);
444
+ } catch (error) {
445
+ debug.warn("assets handler failed", error);
446
+ }
447
+ }
448
+ const referencedIds = parseReferences(data.referencedIds);
449
+ if (!referencedIds) return;
450
+ try {
451
+ onReferences?.(referencedIds, parseIds(data.componentIds));
452
+ } catch (error) {
453
+ debug.warn("references handler failed", error);
454
+ }
455
+ }
456
+ if (data?.event === "prepr:getScrollPosition") {
457
+ const currentScrollY = window.scrollY || document.documentElement.scrollTop;
458
+ sendPreprEvent("getScrollPosition", { value: currentScrollY });
459
+ }
460
+ if (data?.event === "prepr:scrollToField") {
461
+ if (typeof data.field !== "string" || !data.field) return;
462
+ if (data.id !== void 0 && typeof data.id !== "string") return;
463
+ const block = typeof data.block === "number" && Number.isInteger(data.block) ? data.block : void 0;
464
+ const entryId = typeof data.entryId === "string" && data.entryId ? data.entryId : void 0;
465
+ const fieldById = typeof data.fieldById === "string" && data.fieldById ? data.fieldById : void 0;
466
+ try {
467
+ onScrollToField?.({
468
+ field: data.field,
469
+ id: data.id,
470
+ block,
471
+ entryId,
472
+ fieldById
473
+ });
474
+ } catch (error) {
475
+ debug.warn("scrollToField handler failed", error);
476
+ }
477
+ }
478
+ if (data?.event === "prepr:allowNavigation") {
479
+ const href = data.href;
480
+ if (typeof href !== "string" || !href || href.length > MAX_HREF_LENGTH) {
481
+ return;
482
+ }
483
+ try {
484
+ onAllowNavigation?.(href);
485
+ } catch (error) {
486
+ debug.warn("allowNavigation handler failed", error);
487
+ }
488
+ }
489
+ };
490
+ return {
491
+ start() {
492
+ const features = store?.get().features;
493
+ sendPreprEvent("loaded", features ? { features } : void 0, {
494
+ allowUntrustedTarget: true
495
+ });
496
+ window.addEventListener("keydown", onKeyDown);
497
+ window.addEventListener("message", onMessage);
498
+ },
499
+ stop() {
500
+ window.removeEventListener("keydown", onKeyDown);
501
+ window.removeEventListener("message", onMessage);
502
+ parentOrigin = null;
503
+ setTrustedParentOrigin(null);
504
+ }
505
+ };
506
+ }
507
+
508
+ // src/core/stega/auto-clean.ts
509
+ var import_stega2 = require("@vercel/stega");
510
+
511
+ // src/core/stega/clean.ts
512
+ var import_stega = require("@vercel/stega");
513
+ var debug2 = createScopedLogger("stega:clean");
514
+ function decodeStega(str) {
515
+ if (!str) return null;
516
+ try {
517
+ const decoded = (0, import_stega.vercelStegaDecode)(str);
518
+ if (decoded?.href) {
519
+ return decoded;
520
+ }
521
+ } catch (error) {
522
+ debug2.log("error decoding stega data", error);
523
+ const match = str.match(/{"origin.*?}/);
524
+ if (match) {
525
+ try {
526
+ const decodedMatch = (0, import_stega.vercelStegaDecode)(match[0]);
527
+ if (decodedMatch?.href) {
528
+ return decodedMatch;
529
+ }
530
+ } catch (innerError) {
531
+ debug2.log("error decoding stega regex match", innerError);
532
+ }
533
+ }
534
+ }
535
+ return null;
536
+ }
537
+
538
+ // src/core/stega/dom.ts
539
+ var IGNORED_ANCESTORS = "script, style, noscript";
540
+ function isIgnoredTextNode(node) {
541
+ if (node.parentElement?.closest(IGNORED_ANCESTORS)) return true;
542
+ return !node.textContent?.trim();
543
+ }
544
+ function walkTextNodes(root, visit) {
545
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
546
+ acceptNode: (node2) => isIgnoredTextNode(node2) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT
547
+ });
548
+ let node;
549
+ while (node = walker.nextNode()) {
550
+ visit(node);
551
+ }
552
+ }
553
+ function resolveEditTarget(node) {
554
+ const parent = node.parentElement;
555
+ if (!parent) return null;
556
+ const editTarget = parent.closest("[data-prepr-edit-target]");
557
+ if (editTarget) return editTarget;
558
+ return isRenderedElement(parent) ? parent : null;
559
+ }
560
+ function isRenderedElement(element) {
561
+ if (element.hidden) return false;
562
+ if (element.getClientRects().length === 0) return false;
563
+ const style = element.ownerDocument.defaultView?.getComputedStyle(element);
564
+ if (!style) return true;
565
+ return style.visibility !== "hidden" && style.display !== "none";
566
+ }
567
+ function parseEditHref(href) {
568
+ try {
569
+ const url = new URL(href, window.location.origin);
570
+ return {
571
+ id: url.pathname.split("/").pop() || void 0,
572
+ field: url.searchParams.get("field") || void 0,
573
+ locale: url.searchParams.get("locale") || void 0
574
+ };
575
+ } catch {
576
+ return {};
577
+ }
578
+ }
579
+ function setOrRemove(element, name, value) {
580
+ if (value) {
581
+ element.setAttribute(name, value);
582
+ } else {
583
+ element.removeAttribute(name);
584
+ }
585
+ }
586
+ function tagEncodedElement(element, decoded) {
587
+ element.setAttribute("data-prepr-encoded", "");
588
+ element.setAttribute("data-prepr-href", decoded.href);
589
+ element.setAttribute("data-prepr-origin", decoded.origin);
590
+ const { id, field, locale } = parseEditHref(decoded.href);
591
+ setOrRemove(element, "data-prepr-id", id);
592
+ const fieldHint = element.getAttribute("data-prepr-edit-target")?.trim() || void 0;
593
+ setOrRemove(element, "data-prepr-field", field ?? fieldHint);
594
+ setOrRemove(element, "data-prepr-locale", locale);
595
+ }
596
+ function readEditPayload(element) {
597
+ return {
598
+ href: element.getAttribute("data-prepr-href") ?? "",
599
+ origin: element.getAttribute("data-prepr-origin") ?? "",
600
+ id: element.getAttribute("data-prepr-id") ?? void 0,
601
+ field: element.getAttribute("data-prepr-field") ?? void 0,
602
+ locale: element.getAttribute("data-prepr-locale") ?? void 0,
603
+ entryId: element.getAttribute("data-prepr-entry-id") || void 0
604
+ };
605
+ }
606
+
607
+ // src/core/stega/auto-clean.ts
608
+ var debug3 = createScopedLogger("stega:auto-clean");
609
+ var cleanedNodes = /* @__PURE__ */ new WeakMap();
610
+ function createStegaAutoClean(options) {
611
+ const stripText = options?.enabled ?? true;
612
+ let observer = null;
613
+ let processing = false;
614
+ let pendingHidden = /* @__PURE__ */ new Set();
615
+ let pendingDirty = /* @__PURE__ */ new Set();
616
+ let debounceTimeout = null;
617
+ function cleanTextNode(textNode) {
618
+ if (isIgnoredTextNode(textNode)) return false;
619
+ const textContent = textNode.textContent;
620
+ const info = cleanedNodes.get(textNode);
621
+ const settled = stripText ? info?.cleaned : info?.original;
622
+ if (info && textContent === settled) {
623
+ if (!info.decoded) return false;
624
+ const shown = resolveEditTarget(textNode);
625
+ if (!shown) {
626
+ pendingHidden.add(textNode);
627
+ return false;
628
+ }
629
+ pendingHidden.delete(textNode);
630
+ if (shown.hasAttribute("data-prepr-encoded")) return false;
631
+ tagEncodedElement(shown, info.decoded);
632
+ return true;
633
+ }
634
+ try {
635
+ const { cleaned: stripped, encoded } = (0, import_stega2.vercelStegaSplit)(textContent);
636
+ if (!encoded || stripped === textContent) return false;
637
+ const decoded = decodeStega(textContent);
638
+ if (!decoded?.href && !stripText) return false;
639
+ cleanedNodes.set(textNode, {
640
+ original: textContent,
641
+ cleaned: stripped,
642
+ decoded: decoded?.href ? decoded : null
643
+ });
644
+ if (stripText) textNode.textContent = stripped;
645
+ if (!decoded?.href) return false;
646
+ const target = resolveEditTarget(textNode);
647
+ if (target) {
648
+ pendingHidden.delete(textNode);
649
+ tagEncodedElement(target, decoded);
650
+ return true;
651
+ }
652
+ pendingHidden.add(textNode);
653
+ } catch (error) {
654
+ debug3.log("error cleaning text node", error);
655
+ }
656
+ return false;
657
+ }
658
+ function scanAndClean() {
659
+ processing = true;
660
+ walkTextNodes(document.body, cleanTextNode);
661
+ if (stripText) {
662
+ const title = (0, import_stega2.vercelStegaSplit)(document.title);
663
+ if (title.encoded) document.title = title.cleaned;
664
+ }
665
+ processing = false;
666
+ }
667
+ function collectAffected(mutations) {
668
+ const affected = /* @__PURE__ */ new Set();
669
+ mutations.forEach((mutation) => {
670
+ if (mutation.type === "childList") {
671
+ mutation.addedNodes.forEach((node) => {
672
+ if (node.nodeType === Node.TEXT_NODE) {
673
+ affected.add(node);
674
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
675
+ walkTextNodes(node, (textNode) => affected.add(textNode));
676
+ }
677
+ });
678
+ }
679
+ if (mutation.type === "characterData" && mutation.target.nodeType === Node.TEXT_NODE) {
680
+ const textNode = mutation.target;
681
+ const info = cleanedNodes.get(textNode);
682
+ const text = textNode.textContent ?? "";
683
+ const settled = stripText ? info?.cleaned : info?.original;
684
+ if (text !== settled && (0, import_stega2.vercelStegaSplit)(text).encoded) {
685
+ affected.add(textNode);
686
+ }
687
+ }
688
+ });
689
+ return affected;
690
+ }
691
+ function retryPendingHidden() {
692
+ if (pendingHidden.size === 0) return;
693
+ processing = true;
694
+ [...pendingHidden].forEach((textNode) => {
695
+ if (!textNode.isConnected) {
696
+ pendingHidden.delete(textNode);
697
+ return;
698
+ }
699
+ cleanTextNode(textNode);
700
+ });
701
+ processing = false;
702
+ }
703
+ function handleMutations(mutations) {
704
+ if (processing) return;
705
+ const affected = collectAffected(mutations);
706
+ if (affected.size === 0) {
707
+ retryPendingHidden();
708
+ return;
709
+ }
710
+ affected.forEach((textNode) => pendingDirty.add(textNode));
711
+ if (debounceTimeout) clearTimeout(debounceTimeout);
712
+ debounceTimeout = setTimeout(() => {
713
+ debounceTimeout = null;
714
+ processing = true;
715
+ const batch = [...pendingDirty];
716
+ pendingDirty.clear();
717
+ batch.forEach((textNode) => {
718
+ if (textNode.isConnected) cleanTextNode(textNode);
719
+ });
720
+ processing = false;
721
+ retryPendingHidden();
722
+ }, 50);
723
+ }
724
+ let resizeTimeout = null;
725
+ function handleResize() {
726
+ if (pendingHidden.size === 0 || resizeTimeout) return;
727
+ resizeTimeout = setTimeout(() => {
728
+ resizeTimeout = null;
729
+ retryPendingHidden();
730
+ }, 100);
731
+ }
732
+ function setupObserver() {
733
+ window.addEventListener("resize", handleResize, { passive: true });
734
+ observer = new MutationObserver(handleMutations);
735
+ observer.observe(document.body, {
736
+ childList: true,
737
+ subtree: true,
738
+ characterData: true,
739
+ // A dropdown opening only toggles a class or inline style; without these
740
+ // the nodes it reveals are never revisited and stay untagged.
741
+ attributes: true,
742
+ attributeFilter: ["class", "style", "hidden", "open", "aria-expanded"]
743
+ });
744
+ }
745
+ function start() {
746
+ if (observer || typeof window === "undefined") return;
747
+ scanAndClean();
748
+ setupObserver();
749
+ debug3.log("stega auto-clean started");
750
+ }
751
+ function stop() {
752
+ if (debounceTimeout) {
753
+ clearTimeout(debounceTimeout);
754
+ debounceTimeout = null;
755
+ }
756
+ if (resizeTimeout) {
757
+ clearTimeout(resizeTimeout);
758
+ resizeTimeout = null;
759
+ }
760
+ if (observer) {
761
+ observer.disconnect();
762
+ observer = null;
763
+ window.removeEventListener("resize", handleResize);
764
+ }
765
+ pendingHidden = /* @__PURE__ */ new Set();
766
+ pendingDirty = /* @__PURE__ */ new Set();
767
+ debug3.log("stega auto-clean stopped");
768
+ }
769
+ return { start, stop };
770
+ }
771
+
772
+ // src/core/visual-editor/overlay.ts
773
+ var HOST_TAG = "prepr-visual-editor";
774
+ var SCROLL_SETTLE_MS = 120;
775
+ var LABEL_SPACE_PX = 22;
776
+ var BOX_PADDING_PX = 3;
777
+ var LABEL_MARGIN_PX = 4;
778
+ var PROBE_POINTS = [
779
+ [0.5, 0.5],
780
+ [0.15, 0.2],
781
+ [0.85, 0.2],
782
+ [0.15, 0.8],
783
+ [0.85, 0.8]
784
+ ];
785
+ function overlapsBox(area, rect) {
786
+ return area.left < rect.right + BOX_PADDING_PX && area.right > rect.left - BOX_PADDING_PX && area.top < rect.bottom + BOX_PADDING_PX && area.bottom > rect.top - BOX_PADDING_PX;
787
+ }
788
+ function overlaps(a2, b2) {
789
+ return a2.left < b2.right && b2.left < a2.right && a2.top < b2.bottom && b2.top < a2.bottom;
790
+ }
791
+ function coverOf(hit, target, x2, y2) {
792
+ let cover = hit.getBoundingClientRect();
793
+ for (let el = hit.parentElement; el && !el.contains(target) && el !== document.body; el = el.parentElement) {
794
+ const r2 = el.getBoundingClientRect();
795
+ if (x2 < r2.left || x2 >= r2.right || y2 < r2.top || y2 >= r2.bottom) break;
796
+ cover = r2;
797
+ }
798
+ return cover;
799
+ }
800
+ function mergeAreas(areas) {
801
+ const merged = areas.slice();
802
+ for (let i2 = 0; i2 < merged.length; i2++) {
803
+ for (let j2 = i2 + 1; j2 < merged.length; j2++) {
804
+ if (!overlaps(merged[i2], merged[j2])) continue;
805
+ merged[i2] = {
806
+ left: Math.min(merged[i2].left, merged[j2].left),
807
+ top: Math.min(merged[i2].top, merged[j2].top),
808
+ right: Math.max(merged[i2].right, merged[j2].right),
809
+ bottom: Math.max(merged[i2].bottom, merged[j2].bottom)
810
+ };
811
+ merged.splice(j2, 1);
812
+ j2 = i2;
813
+ }
814
+ }
815
+ return merged;
816
+ }
817
+ function findCovers(target, rect) {
818
+ const width = window.innerWidth;
819
+ const height = window.innerHeight;
820
+ const covers = [];
821
+ const seen = /* @__PURE__ */ new Set();
822
+ let probed = false;
823
+ let reached = false;
824
+ for (const [fx, fy] of PROBE_POINTS) {
825
+ const x2 = rect.left + rect.width * fx;
826
+ const y2 = rect.top + rect.height * fy;
827
+ if (x2 < 0 || y2 < 0 || x2 >= width || y2 >= height) continue;
828
+ probed = true;
829
+ const hit = document.elementFromPoint(x2, y2);
830
+ if (!hit || hit === target || target.contains(hit)) {
831
+ reached = true;
832
+ continue;
833
+ }
834
+ if (seen.has(hit)) continue;
835
+ seen.add(hit);
836
+ if (covers.some(
837
+ (c2) => x2 >= c2.left && x2 < c2.right && y2 >= c2.top && y2 < c2.bottom
838
+ )) {
839
+ continue;
840
+ }
841
+ covers.push(coverOf(hit, target, x2, y2));
842
+ }
843
+ if (!probed) return [];
844
+ return reached ? mergeAreas(covers) : null;
845
+ }
846
+ function clipPath(x2, y2, covers) {
847
+ const far = 1e5;
848
+ const points = [
849
+ `${-far}px ${-far}px`,
850
+ `${far}px ${-far}px`,
851
+ `${far}px ${far}px`,
852
+ `${-far}px ${far}px`,
853
+ `${-far}px ${-far}px`
854
+ ];
855
+ for (const c2 of covers) {
856
+ const l2 = c2.left - x2;
857
+ const t3 = c2.top - y2;
858
+ const r2 = c2.right - x2;
859
+ const b2 = c2.bottom - y2;
860
+ points.push(
861
+ `${l2}px ${t3}px`,
862
+ `${r2}px ${t3}px`,
863
+ `${r2}px ${b2}px`,
864
+ `${l2}px ${b2}px`,
865
+ `${l2}px ${t3}px`,
866
+ `${-far}px ${-far}px`
867
+ );
868
+ }
869
+ return `polygon(evenodd, ${points.join(", ")})`;
870
+ }
871
+ var STYLES = `
872
+ :host {
873
+ all: initial;
874
+ position: fixed;
875
+ inset: 0;
876
+ pointer-events: none;
877
+ z-index: 2147483646;
878
+ contain: strict;
879
+ }
880
+ .box {
881
+ position: absolute;
882
+ top: 0;
883
+ left: 0;
884
+ box-sizing: border-box;
885
+ border-radius: 6px;
886
+ opacity: 0;
887
+ will-change: transform, width, height;
888
+ transition:
889
+ transform 180ms cubic-bezier(0.2, 0.8, 0.2, 1),
890
+ width 180ms cubic-bezier(0.2, 0.8, 0.2, 1),
891
+ height 180ms cubic-bezier(0.2, 0.8, 0.2, 1),
892
+ opacity 140ms ease;
893
+ }
894
+ .box[data-visible] { opacity: 1; }
895
+ .box[data-instant], :host([data-scrolling]) .box {
896
+ transition: opacity 140ms ease;
897
+ }
898
+ .hover {
899
+ border: 1.5px solid rgba(79, 70, 229, 0.9);
900
+ background: rgba(79, 70, 229, 0.06);
901
+ }
902
+ .selected {
903
+ border: 2px solid #4f46e5;
904
+ box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.18);
905
+ }
906
+ .label {
907
+ position: absolute;
908
+ left: -2px;
909
+ bottom: 100%;
910
+ margin-bottom: 4px;
911
+ padding: 3px 7px;
912
+ border-radius: 5px;
913
+ background: #4f46e5;
914
+ color: #fff;
915
+ font: 500 11px/1.3 ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
916
+ letter-spacing: 0.01em;
917
+ white-space: nowrap;
918
+ display: flex;
919
+ max-width: 240px;
920
+ box-shadow: 0 1px 3px rgba(15, 23, 42, 0.25);
921
+ }
922
+ .text {
923
+ min-width: 0;
924
+ overflow: hidden;
925
+ text-overflow: ellipsis;
926
+ }
927
+ .hover .label { background: rgba(79, 70, 229, 0.92); }
928
+ /* Content of another item than the one open in the editor: still clickable,
929
+ but visibly not part of the item being edited. */
930
+ .hover[data-item-kind='other'] {
931
+ border: 1.5px dashed #a5b4fc;
932
+ background: rgba(100, 116, 139, 0.05);
933
+ }
934
+ .hover[data-item-kind='other'] .label { background: #64748b; }
935
+ .hover[data-item-kind='referenced'] {
936
+ border: 1.5px solid #a5b4fc;
937
+ background: rgba(79, 70, 229, 0.03);
938
+ }
939
+ .hover[data-item-kind='referenced'] .label { background: #818cf8; }
940
+ .box[data-label-covered] .label { visibility: hidden; }
941
+ .box[data-label-inside] .label {
942
+ bottom: auto;
943
+ top: 2px;
944
+ left: 2px;
945
+ margin: 0;
946
+ }
947
+ /* A clickable hover label (edit mode on the live site). Only while shown, so
948
+ a fading box never leaves an invisible click target behind. */
949
+ :host([data-label-action]) .hover[data-visible] .label {
950
+ pointer-events: auto;
951
+ cursor: pointer;
952
+ }
953
+ :host([data-label-action]) .hover .label::after {
954
+ content: '\\2197';
955
+ margin-left: 5px;
956
+ }
957
+ :host([data-label-action]) .hover .label:hover { background: #4338ca; }
958
+ /* Bridges the gap between the label and its element, so the pointer can
959
+ travel from one to the other without the hover ending on the way. */
960
+ :host([data-label-action]) .hover .label::before {
961
+ content: '';
962
+ position: absolute;
963
+ left: 0;
964
+ right: 0;
965
+ top: 100%;
966
+ height: ${LABEL_MARGIN_PX + BOX_PADDING_PX + 2}px;
967
+ }
968
+ @media (prefers-reduced-motion: reduce) {
969
+ .box { transition: opacity 80ms linear; }
970
+ }
971
+ `;
972
+ var VisualEditorOverlay = class {
973
+ constructor(options = {}) {
974
+ this.host = null;
975
+ this.hoverBox = null;
976
+ this.selectedBox = null;
977
+ this.frame = null;
978
+ this.scrollTimeout = null;
979
+ this.resizeObserver = null;
980
+ this.onLabelClick = options.onLabelClick;
981
+ }
982
+ mount() {
983
+ if (this.host) return;
984
+ const host = document.createElement(HOST_TAG);
985
+ const shadow = host.attachShadow({ mode: "open" });
986
+ const style = document.createElement("style");
987
+ style.textContent = STYLES;
988
+ shadow.appendChild(style);
989
+ this.hoverBox = this.createBox(shadow, "hover");
990
+ this.selectedBox = this.createBox(shadow, "selected");
991
+ const onLabelClick = this.onLabelClick;
992
+ if (onLabelClick) {
993
+ host.setAttribute("data-label-action", "");
994
+ const hoverBox = this.hoverBox;
995
+ hoverBox.label.addEventListener("click", () => {
996
+ if (hoverBox.target) onLabelClick(hoverBox.target);
997
+ });
998
+ }
999
+ document.documentElement.appendChild(host);
1000
+ this.host = host;
1001
+ if (typeof ResizeObserver !== "undefined") {
1002
+ this.resizeObserver = new ResizeObserver(() => this.schedule());
1003
+ }
1004
+ }
1005
+ unmount() {
1006
+ if (this.frame !== null) cancelAnimationFrame(this.frame);
1007
+ if (this.scrollTimeout) clearTimeout(this.scrollTimeout);
1008
+ this.frame = null;
1009
+ this.scrollTimeout = null;
1010
+ this.resizeObserver?.disconnect();
1011
+ this.resizeObserver = null;
1012
+ this.host?.remove();
1013
+ this.host = null;
1014
+ this.hoverBox = null;
1015
+ this.selectedBox = null;
1016
+ }
1017
+ /**
1018
+ * Whether a pointer event target is this chrome: events from inside the
1019
+ * shadow root reach the page retargeted to its host.
1020
+ */
1021
+ owns(node) {
1022
+ return node !== null && node === this.host;
1023
+ }
1024
+ getHoverTarget() {
1025
+ return this.hoverBox?.target ?? null;
1026
+ }
1027
+ getSelectedTarget() {
1028
+ return this.selectedBox?.target ?? null;
1029
+ }
1030
+ setHover(target, label, options = {}) {
1031
+ if (target) {
1032
+ this.hoverBox?.root.setAttribute(
1033
+ "data-item-kind",
1034
+ options.kind ?? "current"
1035
+ );
1036
+ }
1037
+ this.retarget(this.hoverBox, target, label);
1038
+ }
1039
+ setSelected(target, label) {
1040
+ this.retarget(this.selectedBox, target, label);
1041
+ }
1042
+ /** Call on every scroll; positions follow in the next frame, untransitioned. */
1043
+ onScroll() {
1044
+ if (!this.host) return;
1045
+ this.host.setAttribute("data-scrolling", "");
1046
+ if (this.scrollTimeout) clearTimeout(this.scrollTimeout);
1047
+ this.scrollTimeout = setTimeout(() => {
1048
+ this.host?.removeAttribute("data-scrolling");
1049
+ this.scrollTimeout = null;
1050
+ }, SCROLL_SETTLE_MS);
1051
+ this.schedule();
1052
+ }
1053
+ /** Re-measure both boxes in the next animation frame. */
1054
+ schedule() {
1055
+ if (this.frame !== null || !this.host) return;
1056
+ this.frame = requestAnimationFrame(() => {
1057
+ this.frame = null;
1058
+ this.render();
1059
+ });
1060
+ }
1061
+ createBox(shadow, kind) {
1062
+ const root = document.createElement("div");
1063
+ root.className = `box ${kind}`;
1064
+ const label = document.createElement("div");
1065
+ label.className = "label";
1066
+ const text = document.createElement("span");
1067
+ text.className = "text";
1068
+ label.appendChild(text);
1069
+ root.appendChild(label);
1070
+ shadow.appendChild(root);
1071
+ return { root, label, text, target: null };
1072
+ }
1073
+ retarget(box, target, label) {
1074
+ if (!box || box.target === target) return;
1075
+ const previous = box.target;
1076
+ if (previous) this.resizeObserver?.unobserve(previous);
1077
+ box.target = target;
1078
+ if (target) {
1079
+ this.resizeObserver?.observe(target);
1080
+ box.text.textContent = label;
1081
+ if (!box.root.hasAttribute("data-visible")) {
1082
+ box.root.setAttribute("data-instant", "");
1083
+ }
1084
+ }
1085
+ this.schedule();
1086
+ }
1087
+ render() {
1088
+ const hover = this.hoverBox ? this.measure(this.hoverBox) : null;
1089
+ const selected = this.selectedBox ? this.measure(this.selectedBox) : null;
1090
+ if (this.hoverBox) this.paint(this.hoverBox, hover, selected);
1091
+ if (this.selectedBox) this.paint(this.selectedBox, selected, hover);
1092
+ }
1093
+ measure(box) {
1094
+ const target = box.target;
1095
+ if (!target) return null;
1096
+ if (!target.isConnected) {
1097
+ this.resizeObserver?.unobserve(target);
1098
+ box.target = null;
1099
+ return null;
1100
+ }
1101
+ const rect = target.getBoundingClientRect();
1102
+ if (rect.width === 0 && rect.height === 0) return null;
1103
+ const covers = findCovers(target, rect);
1104
+ if (!covers) return null;
1105
+ return {
1106
+ rect,
1107
+ covers,
1108
+ labelWidth: covers.length ? box.label.offsetWidth : 0,
1109
+ labelHeight: covers.length ? box.label.offsetHeight : 0
1110
+ };
1111
+ }
1112
+ paint(box, measurement, other = null) {
1113
+ const root = box.root;
1114
+ if (!measurement) {
1115
+ root.removeAttribute("data-visible");
1116
+ return;
1117
+ }
1118
+ const { rect, covers } = measurement;
1119
+ const x2 = rect.left - BOX_PADDING_PX;
1120
+ const y2 = rect.top - BOX_PADDING_PX;
1121
+ const labelAbove = {
1122
+ left: x2 - 2,
1123
+ top: y2 - LABEL_SPACE_PX,
1124
+ right: x2 - 2 + (measurement.labelWidth || Math.min(240, rect.width)),
1125
+ bottom: y2
1126
+ };
1127
+ const labelInside = y2 < LABEL_SPACE_PX || other !== null && other.rect !== rect && overlapsBox(labelAbove, other.rect);
1128
+ root.style.transform = `translate3d(${x2}px, ${y2}px, 0)`;
1129
+ root.style.width = `${rect.width + BOX_PADDING_PX * 2}px`;
1130
+ root.style.height = `${rect.height + BOX_PADDING_PX * 2}px`;
1131
+ root.toggleAttribute("data-label-inside", labelInside);
1132
+ root.style.clipPath = covers.length ? clipPath(x2, y2, covers) : "";
1133
+ const labelLeft = labelInside ? x2 + 2 : x2 - 2;
1134
+ const labelTop = labelInside ? y2 + 2 : y2 - LABEL_MARGIN_PX - measurement.labelHeight;
1135
+ const label = {
1136
+ left: labelLeft,
1137
+ top: labelTop,
1138
+ right: labelLeft + measurement.labelWidth,
1139
+ bottom: labelTop + measurement.labelHeight
1140
+ };
1141
+ root.toggleAttribute(
1142
+ "data-label-covered",
1143
+ covers.some((c2) => overlaps(c2, label))
1144
+ );
1145
+ if (root.hasAttribute("data-instant")) {
1146
+ root.setAttribute("data-visible", "");
1147
+ requestAnimationFrame(() => root.removeAttribute("data-instant"));
1148
+ return;
1149
+ }
1150
+ root.setAttribute("data-visible", "");
1151
+ }
1152
+ };
1153
+
1154
+ // src/core/visual-editor/field-path.ts
1155
+ var INDEX_SEGMENT = /^\d+$/;
1156
+ var WORD_SEPARATORS = /[_-]+/g;
1157
+ function normalizeFieldPath(path) {
1158
+ return path.split(".").map(
1159
+ (segment) => INDEX_SEGMENT.test(segment) ? String(Number.parseInt(segment, 10)) : segment
1160
+ ).join(".");
1161
+ }
1162
+ var GENERIC_LEAVES = /* @__PURE__ */ new Set(["value", "text", "body", "content", "label"]);
1163
+ function humanize(name) {
1164
+ const words = name.replace(WORD_SEPARATORS, " ").trim();
1165
+ return words.charAt(0).toUpperCase() + words.slice(1);
1166
+ }
1167
+ function fieldLabel(path, locale = "en") {
1168
+ if (!path) return t("visualEditor.edit", locale);
1169
+ const segments = path.split(".").filter((s2) => s2 && s2 !== "items" && !INDEX_SEGMENT.test(s2));
1170
+ const name = segments[segments.length - 1];
1171
+ if (!name) return t("visualEditor.edit", locale);
1172
+ const parent = segments[segments.length - 2];
1173
+ if (parent && GENERIC_LEAVES.has(name)) {
1174
+ return `${humanize(parent)} \u203A ${humanize(name)}`;
1175
+ }
1176
+ return humanize(name);
1177
+ }
1178
+ function findFieldElement(lookup) {
1179
+ if (!lookup.field) return null;
1180
+ const candidates = document.querySelectorAll(
1181
+ "[data-prepr-encoded]"
1182
+ );
1183
+ if (lookup.entryId) {
1184
+ for (const candidate of candidates) {
1185
+ if (candidate.getAttribute("data-prepr-entry-id") === lookup.entryId) {
1186
+ return candidate;
1187
+ }
1188
+ }
1189
+ }
1190
+ for (const path of [lookup.field, lookup.fieldById]) {
1191
+ if (!path) continue;
1192
+ const wanted = normalizeFieldPath(path);
1193
+ for (const candidate of candidates) {
1194
+ const field = candidate.getAttribute("data-prepr-field");
1195
+ if (!field || normalizeFieldPath(field) !== wanted) continue;
1196
+ if (lookup.id && candidate.getAttribute("data-prepr-id") !== lookup.id) {
1197
+ continue;
1198
+ }
1199
+ return candidate;
1200
+ }
1201
+ }
1202
+ return null;
1203
+ }
1204
+
1205
+ // src/core/stega/elements.ts
1206
+ var debug4 = createScopedLogger("stega:elements");
1207
+ var StegaElements = class {
1208
+ constructor(decode = decodeStega) {
1209
+ this.observer = null;
1210
+ this.decode = decode;
1211
+ }
1212
+ getElements() {
1213
+ if (!this.elements) {
1214
+ this.elements = document.querySelectorAll("[data-prepr-encoded]");
1215
+ }
1216
+ return this.elements;
1217
+ }
1218
+ /** Returns true only when this tags an element that wasn't tagged before. */
1219
+ tagFromTextNode(node) {
1220
+ const decoded = this.decode(node.textContent);
1221
+ if (!decoded?.href) return false;
1222
+ const target = resolveEditTarget(node);
1223
+ if (!target || target.hasAttribute("data-prepr-encoded")) return false;
1224
+ tagEncodedElement(target, decoded);
1225
+ return true;
1226
+ }
1227
+ scanNode(node) {
1228
+ if (node.nodeType === Node.TEXT_NODE) {
1229
+ if (isIgnoredTextNode(node)) return;
1230
+ this.tagFromTextNode(node);
1231
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
1232
+ node.childNodes.forEach((child) => this.scanNode(child));
1233
+ }
1234
+ }
1235
+ /**
1236
+ * `skipIfTagged` reuses whatever the auto-clean pass already tagged instead
1237
+ * of re-walking the body.
1238
+ */
1239
+ scanDocument(skipIfTagged = false) {
1240
+ if (skipIfTagged) {
1241
+ const existing = document.querySelectorAll("[data-prepr-encoded]");
1242
+ if (existing.length > 0) {
1243
+ this.elements = existing;
1244
+ return;
1245
+ }
1246
+ }
1247
+ let encodedCount = 0;
1248
+ walkTextNodes(document.body, (textNode) => {
1249
+ if (this.tagFromTextNode(textNode)) encodedCount++;
1250
+ });
1251
+ debug4.log("document scan complete, encoded", encodedCount, "elements");
1252
+ this.elements = document.querySelectorAll("[data-prepr-encoded]");
1253
+ }
1254
+ /** `onUpdate` fires after each debounced batch, for refreshing derived state. */
1255
+ setupMutationObserver(onUpdate) {
1256
+ if (this.observer) {
1257
+ this.observer.disconnect();
1258
+ }
1259
+ let pending = [];
1260
+ let debounceTimeout = null;
1261
+ const processMutations = () => {
1262
+ const addedNodes = /* @__PURE__ */ new Set();
1263
+ pending.forEach((mutation) => {
1264
+ mutation.addedNodes.forEach((node) => addedNodes.add(node));
1265
+ if (mutation.type === "characterData") {
1266
+ addedNodes.add(mutation.target);
1267
+ }
1268
+ if (mutation.type === "attributes") {
1269
+ addedNodes.add(mutation.target);
1270
+ }
1271
+ });
1272
+ addedNodes.forEach((node) => {
1273
+ if (node.isConnected) this.scanNode(node);
1274
+ });
1275
+ pending = [];
1276
+ this.elements = document.querySelectorAll("[data-prepr-encoded]");
1277
+ onUpdate?.();
1278
+ };
1279
+ this.observer = new MutationObserver((mutations) => {
1280
+ pending.push(...mutations);
1281
+ if (debounceTimeout) clearTimeout(debounceTimeout);
1282
+ debounceTimeout = setTimeout(processMutations, 100);
1283
+ });
1284
+ this.observer.observe(document.body, {
1285
+ childList: true,
1286
+ subtree: true,
1287
+ characterData: true,
1288
+ // Reveal-on-class/style (dropdowns, accordions) changes no text and adds
1289
+ // no nodes, but does change what is hoverable and needs a rescan.
1290
+ attributes: true,
1291
+ attributeFilter: ["class", "style", "hidden", "open", "aria-expanded"]
1292
+ });
1293
+ }
1294
+ /**
1295
+ * Stops watching for new content. Tags stay on their elements: the page's
1296
+ * stega characters are stripped once they are read, so a tag removed here
1297
+ * could never be rebuilt when edit mode is turned back on.
1298
+ */
1299
+ disconnect() {
1300
+ if (this.observer) {
1301
+ this.observer.disconnect();
1302
+ this.observer = null;
1303
+ }
1304
+ this.elements = void 0;
1305
+ }
1306
+ };
1307
+
1308
+ // src/core/stega/stega.generated.ts
1309
+ var STEGA_STYLES = '@property --prepr-presence{syntax:"<number>";inherits:true;initial-value:1}[data-prepr-encoded]{outline:1px dashed rgba(79,70,229,calc(.3 * var(--prepr-presence,1)));outline-offset:2px}';
1310
+
1311
+ // src/core/stega/styles.ts
1312
+ var STEGA_STYLE_MARKER = "data-prepr-stega";
1313
+ function injectStegaStyles(css = STEGA_STYLES) {
1314
+ const existing = document.querySelector(
1315
+ `style[${STEGA_STYLE_MARKER}]`
1316
+ );
1317
+ if (existing) return existing;
1318
+ const style = document.createElement("style");
1319
+ style.setAttribute(STEGA_STYLE_MARKER, "");
1320
+ style.textContent = css;
1321
+ document.head.appendChild(style);
1322
+ return style;
1323
+ }
1324
+ function removeStegaStyles() {
1325
+ document.querySelectorAll(`style[${STEGA_STYLE_MARKER}]`).forEach((node) => node.parentNode?.removeChild(node));
1326
+ }
1327
+
1328
+ // src/core/stega/scan.ts
1329
+ var debug5 = createScopedLogger("stega:scan");
1330
+ var ENCODED_SELECTOR = "[data-prepr-encoded]";
1331
+ var PRESENCE_FADE_MS = 400;
1332
+ var EDITOR_MODE_STYLES = "[data-prepr-encoded]{cursor:pointer}";
1333
+ function fadeInPresence() {
1334
+ const root = document.documentElement;
1335
+ if (typeof root.animate !== "function") return;
1336
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return;
1337
+ root.animate(
1338
+ { "--prepr-presence": ["0", "1"] },
1339
+ { duration: PRESENCE_FADE_MS, easing: "ease-out" }
1340
+ );
1341
+ }
1342
+ function createStegaController(opts) {
1343
+ const tooltipEnabled = opts.tooltip ?? true;
1344
+ const locale = opts.locale ?? "en";
1345
+ const elements = new StegaElements();
1346
+ const overlay = new VisualEditorOverlay({
1347
+ onLabelClick: (target) => opts.onEdit(readEditPayload(target))
1348
+ });
1349
+ let initialized = false;
1350
+ let pointerFrame = null;
1351
+ let pointerTarget = null;
1352
+ let pointerX = 0;
1353
+ let pointerY = 0;
1354
+ let hitTestPending = false;
1355
+ const updateHover = () => {
1356
+ pointerFrame = null;
1357
+ if (hitTestPending) {
1358
+ hitTestPending = false;
1359
+ pointerTarget = document.elementFromPoint(pointerX, pointerY);
1360
+ }
1361
+ if (overlay.owns(pointerTarget)) return;
1362
+ const encoded = pointerTarget instanceof Element ? pointerTarget.closest(ENCODED_SELECTOR) : null;
1363
+ overlay.setHover(
1364
+ encoded,
1365
+ encoded ? fieldLabel(encoded.getAttribute("data-prepr-field"), locale) : ""
1366
+ );
1367
+ };
1368
+ const scheduleHover = () => {
1369
+ if (pointerFrame === null) {
1370
+ pointerFrame = requestAnimationFrame(updateHover);
1371
+ }
1372
+ };
1373
+ const handlePointer = (e2) => {
1374
+ pointerTarget = e2.target;
1375
+ pointerX = e2.clientX;
1376
+ pointerY = e2.clientY;
1377
+ hitTestPending = false;
1378
+ scheduleHover();
1379
+ };
1380
+ const handlePointerLeave = () => {
1381
+ pointerTarget = null;
1382
+ hitTestPending = false;
1383
+ overlay.setHover(null, "");
1384
+ };
1385
+ const handleScroll = () => {
1386
+ overlay.onScroll();
1387
+ if (pointerTarget === null) return;
1388
+ hitTestPending = true;
1389
+ scheduleHover();
1390
+ };
1391
+ const handleResize = () => overlay.schedule();
1392
+ const handleClick = (e2) => {
1393
+ const target = e2.target;
1394
+ const encoded = target?.closest(ENCODED_SELECTOR);
1395
+ if (!encoded) return;
1396
+ e2.preventDefault();
1397
+ e2.stopPropagation();
1398
+ opts.onEdit(readEditPayload(encoded));
1399
+ };
1400
+ const start = () => {
1401
+ if (initialized) {
1402
+ debug5.log("already initialized, skipping setup");
1403
+ return;
1404
+ }
1405
+ if (!tooltipEnabled) {
1406
+ injectStegaStyles(EDITOR_MODE_STYLES);
1407
+ elements.scanDocument(true);
1408
+ elements.setupMutationObserver(() => {
1409
+ });
1410
+ document.addEventListener("click", handleClick, { capture: true });
1411
+ initialized = true;
1412
+ debug5.log("stega controller started (headless)");
1413
+ return;
1414
+ }
1415
+ injectStegaStyles();
1416
+ fadeInPresence();
1417
+ overlay.mount();
1418
+ elements.scanDocument(true);
1419
+ elements.setupMutationObserver(() => {
1420
+ if (pointerTarget === null) return;
1421
+ hitTestPending = true;
1422
+ scheduleHover();
1423
+ });
1424
+ document.addEventListener("pointermove", handlePointer, { passive: true });
1425
+ document.addEventListener("pointerdown", handlePointer, { passive: true });
1426
+ document.documentElement.addEventListener(
1427
+ "pointerleave",
1428
+ handlePointerLeave
1429
+ );
1430
+ window.addEventListener("scroll", handleScroll, {
1431
+ capture: true,
1432
+ passive: true
1433
+ });
1434
+ window.addEventListener("resize", handleResize, { passive: true });
1435
+ initialized = true;
1436
+ debug5.log("stega controller started");
1437
+ };
1438
+ const stop = () => {
1439
+ if (!initialized) return;
1440
+ initialized = false;
1441
+ if (!tooltipEnabled) {
1442
+ document.removeEventListener("click", handleClick, { capture: true });
1443
+ elements.disconnect();
1444
+ removeStegaStyles();
1445
+ debug5.log("stega controller stopped (headless)");
1446
+ return;
1447
+ }
1448
+ if (pointerFrame !== null) cancelAnimationFrame(pointerFrame);
1449
+ pointerFrame = null;
1450
+ pointerTarget = null;
1451
+ hitTestPending = false;
1452
+ document.removeEventListener("pointermove", handlePointer);
1453
+ document.removeEventListener("pointerdown", handlePointer);
1454
+ document.documentElement.removeEventListener(
1455
+ "pointerleave",
1456
+ handlePointerLeave
1457
+ );
1458
+ window.removeEventListener("scroll", handleScroll, { capture: true });
1459
+ window.removeEventListener("resize", handleResize);
1460
+ overlay.unmount();
1461
+ elements.disconnect();
1462
+ removeStegaStyles();
1463
+ debug5.log("stega controller stopped");
1464
+ };
1465
+ return { start, stop };
1466
+ }
1467
+
1468
+ // src/core/stega/scroll-to-field.ts
1469
+ var debug6 = createScopedLogger("stega:scroll");
1470
+ var FLASH_DURATION_MS = 1200;
1471
+ var flashTimeout = null;
1472
+ function scrollToField(request) {
1473
+ const { field, id } = request;
1474
+ if (!field) return false;
1475
+ const candidates = document.querySelectorAll(
1476
+ "[data-prepr-encoded]"
1477
+ );
1478
+ let target = null;
1479
+ for (const candidate of candidates) {
1480
+ if (candidate.getAttribute("data-prepr-field") !== field) continue;
1481
+ if (id && candidate.getAttribute("data-prepr-id") !== id) continue;
1482
+ target = candidate;
1483
+ break;
1484
+ }
1485
+ if (!target) {
1486
+ debug6.log("no element found for field", field);
1487
+ return false;
1488
+ }
1489
+ target.scrollIntoView({ behavior: "smooth", block: "center" });
1490
+ if (flashTimeout) clearTimeout(flashTimeout);
1491
+ document.querySelectorAll(".prepr-overlay-active").forEach((el) => el.classList.remove("prepr-overlay-active"));
1492
+ target.classList.add("prepr-overlay-active");
1493
+ flashTimeout = setTimeout(() => {
1494
+ target.classList.remove("prepr-overlay-active");
1495
+ flashTimeout = null;
1496
+ }, FLASH_DURATION_MS);
1497
+ return true;
1498
+ }
1499
+
1500
+ // src/core/store.ts
1501
+ var DEFAULT_STATE = {
1502
+ locale: "en",
1503
+ segments: [],
1504
+ selectedSegment: null,
1505
+ selectedVariant: null,
1506
+ editMode: false,
1507
+ previewMode: false,
1508
+ toolbarOpen: false,
1509
+ isIframe: false,
1510
+ features: ALL_FEATURES_ENABLED
1511
+ };
1512
+ function createToolbarStore(initial = {}) {
1513
+ let state = { ...DEFAULT_STATE, ...initial };
1514
+ const listeners = /* @__PURE__ */ new Set();
1515
+ function get() {
1516
+ return state;
1517
+ }
1518
+ function set(patch) {
1519
+ const keys = Object.keys(patch);
1520
+ const hasChange = keys.some((key) => patch[key] !== state[key]);
1521
+ if (!hasChange) return;
1522
+ state = { ...state, ...patch };
1523
+ for (const listener of listeners) {
1524
+ listener(state);
1525
+ }
1526
+ }
1527
+ function subscribe(fn) {
1528
+ listeners.add(fn);
1529
+ return () => {
1530
+ listeners.delete(fn);
1531
+ };
1532
+ }
1533
+ return { get, set, subscribe };
1534
+ }
1535
+
1536
+ // src/core/toolbar-change-handler.ts
1537
+ function cookieOpts() {
1538
+ return {
1539
+ maxAge: ONE_YEAR_SECONDS,
1540
+ path: "/",
1541
+ ...crossSiteCookieOptions()
1542
+ };
1543
+ }
1544
+ function createChangeHandler(deps) {
1545
+ const { store, stega, features, editingEnabled } = deps;
1546
+ function updateParams(patch) {
1547
+ const [path, existing] = splitPath(deps.currentPath());
1548
+ const params = new URLSearchParams(existing);
1549
+ for (const [name, value] of Object.entries(patch)) {
1550
+ if (value === null) {
1551
+ params.delete(name);
1552
+ } else {
1553
+ params.set(name, value);
1554
+ }
1555
+ }
1556
+ const query = params.toString();
1557
+ deps.navigate(query ? `${path}?${query}` : path);
1558
+ }
1559
+ return function handleChange(before, after) {
1560
+ const paramPatch = {};
1561
+ if (features.segments && before.selectedSegment !== after.selectedSegment) {
1562
+ if (after.selectedSegment === null) {
1563
+ removeCookie(COOKIE_SEGMENT, "/", crossSiteCookieOptions());
1564
+ } else {
1565
+ setCookie(COOKIE_SEGMENT, after.selectedSegment, cookieOpts());
1566
+ }
1567
+ paramPatch[PARAM_SEGMENT] = after.selectedSegment;
1568
+ sendPreprEvent("segment_changed", {
1569
+ segment: after.selectedSegment ?? void 0
1570
+ });
1571
+ }
1572
+ if (features.abTesting && before.selectedVariant !== after.selectedVariant) {
1573
+ if (after.selectedVariant === null) {
1574
+ removeCookie(COOKIE_VARIANT, "/", crossSiteCookieOptions());
1575
+ } else {
1576
+ setCookie(COOKIE_VARIANT, after.selectedVariant, cookieOpts());
1577
+ }
1578
+ paramPatch[PARAM_VARIANT] = after.selectedVariant;
1579
+ sendPreprEvent("variant_changed", {
1580
+ variant: after.selectedVariant ?? void 0
1581
+ });
1582
+ }
1583
+ if (Object.keys(paramPatch).length > 0) {
1584
+ updateParams(paramPatch);
1585
+ }
1586
+ if (before.editMode !== after.editMode) {
1587
+ if (after.editMode && editingEnabled) {
1588
+ stega.start();
1589
+ } else {
1590
+ stega.stop();
1591
+ }
1592
+ sendPreprEvent("edit_mode_toggled", { editMode: after.editMode });
1593
+ }
1594
+ if (before.previewMode !== after.previewMode) {
1595
+ const coupled = {};
1596
+ if (!after.previewMode && after.editMode) {
1597
+ coupled.editMode = false;
1598
+ }
1599
+ if (after.toolbarOpen) {
1600
+ coupled.toolbarOpen = false;
1601
+ }
1602
+ if (Object.keys(coupled).length > 0) {
1603
+ store.set(coupled);
1604
+ }
1605
+ setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), cookieOpts());
1606
+ setCookie(COOKIE_TOOLBAR_OPEN, "false", cookieOpts());
1607
+ sendPreprEvent("preview_mode_toggled", {
1608
+ previewMode: after.previewMode
1609
+ });
1610
+ if (!after.isIframe) {
1611
+ const [path, existing] = splitPath(deps.currentPath());
1612
+ const params = new URLSearchParams(existing);
1613
+ if (params.has(PARAM_SEGMENT) || params.has(PARAM_VARIANT)) {
1614
+ params.delete(PARAM_SEGMENT);
1615
+ params.delete(PARAM_VARIANT);
1616
+ const query = params.toString();
1617
+ deps.navigate(query ? `${path}?${query}` : path);
1618
+ } else {
1619
+ deps.reload();
1620
+ }
1621
+ }
1622
+ }
1623
+ if (before.toolbarOpen !== after.toolbarOpen) {
1624
+ setCookie(COOKIE_TOOLBAR_OPEN, String(after.toolbarOpen), cookieOpts());
1625
+ }
1626
+ };
1627
+ }
1628
+ function splitPath(full) {
1629
+ const index = full.indexOf("?");
1630
+ if (index === -1) return [full, ""];
1631
+ return [full.slice(0, index), full.slice(index + 1)];
1632
+ }
1633
+
1634
+ // ../../node_modules/.pnpm/preact@10.29.7/node_modules/preact/dist/preact.mjs
1635
+ var n;
1636
+ var l;
1637
+ var u;
1638
+ var t2;
1639
+ var i;
1640
+ var r;
1641
+ var o;
1642
+ var e;
1643
+ var f;
1644
+ var c;
1645
+ var a;
1646
+ var s;
1647
+ var h;
1648
+ var p;
1649
+ var v;
1650
+ var y;
1651
+ var d = {};
1652
+ var w = [];
1653
+ var _ = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;
1654
+ var g = Array.isArray;
1655
+ function m(n2, l2) {
1656
+ for (var u3 in l2) n2[u3] = l2[u3];
1657
+ return n2;
1658
+ }
1659
+ function b(n2) {
1660
+ n2 && n2.parentNode && n2.parentNode.removeChild(n2);
1661
+ }
1662
+ function k(l2, u3, t3) {
1663
+ var i2, r2, o2, e2 = {};
1664
+ for (o2 in u3) "key" == o2 ? i2 = u3[o2] : "ref" == o2 ? r2 = u3[o2] : e2[o2] = u3[o2];
1665
+ if (arguments.length > 2 && (e2.children = arguments.length > 3 ? n.call(arguments, 2) : t3), "function" == typeof l2 && null != l2.defaultProps) for (o2 in l2.defaultProps) void 0 === e2[o2] && (e2[o2] = l2.defaultProps[o2]);
1666
+ return x(l2, e2, i2, r2, null);
1667
+ }
1668
+ function x(n2, t3, i2, r2, o2) {
1669
+ var e2 = { type: n2, props: t3, key: i2, ref: r2, __k: null, __: null, __b: 0, __e: null, __c: null, constructor: void 0, __v: null == o2 ? ++u : o2, __i: -1, __u: 0 };
1670
+ return null == o2 && null != l.vnode && l.vnode(e2), e2;
1671
+ }
1672
+ function S(n2) {
1673
+ return n2.children;
1674
+ }
1675
+ function C(n2, l2) {
1676
+ this.props = n2, this.context = l2;
1677
+ }
1678
+ function $(n2, l2) {
1679
+ if (null == l2) return n2.__ ? $(n2.__, n2.__i + 1) : null;
1680
+ for (var u3; l2 < n2.__k.length; l2++) if (null != (u3 = n2.__k[l2]) && null != u3.__e) return u3.__e;
1681
+ return "function" == typeof n2.type ? $(n2) : null;
1682
+ }
1683
+ function I(n2) {
1684
+ if (n2.__P && n2.__d) {
1685
+ var u3 = n2.__v, t3 = u3.__e, i2 = [], r2 = [], o2 = m({}, u3);
1686
+ o2.__v = u3.__v + 1, l.vnode && l.vnode(o2), q(n2.__P, o2, u3, n2.__n, n2.__P.namespaceURI, 32 & u3.__u ? [t3] : null, i2, null == t3 ? $(u3) : t3, !!(32 & u3.__u), r2), o2.__v = u3.__v, o2.__.__k[o2.__i] = o2, D(i2, o2, r2), u3.__e = u3.__ = null, o2.__e != t3 && P(o2);
1687
+ }
1688
+ }
1689
+ function P(n2) {
1690
+ if (null != (n2 = n2.__) && null != n2.__c) return n2.__e = n2.__c.base = null, n2.__k.some(function(l2) {
1691
+ if (null != l2 && null != l2.__e) return n2.__e = n2.__c.base = l2.__e;
1692
+ }), P(n2);
1693
+ }
1694
+ function A(n2) {
1695
+ (!n2.__d && (n2.__d = true) && i.push(n2) && !H.__r++ || r != l.debounceRendering) && ((r = l.debounceRendering) || o)(H);
1696
+ }
1697
+ function H() {
1698
+ try {
1699
+ for (var n2, l2 = 1; i.length; ) i.length > l2 && i.sort(e), n2 = i.shift(), l2 = i.length, I(n2);
1700
+ } finally {
1701
+ i.length = H.__r = 0;
1702
+ }
1703
+ }
1704
+ function L(n2, l2, u3, t3, i2, r2, o2, e2, f3, c2, a2) {
1705
+ var s2, h2, p2, v2, y2, _2, g2, m2 = t3 && t3.__k || w, b2 = l2.length;
1706
+ for (f3 = T(u3, l2, m2, f3, b2), s2 = 0; s2 < b2; s2++) null != (p2 = u3.__k[s2]) && (h2 = -1 != p2.__i && m2[p2.__i] || d, p2.__i = s2, _2 = q(n2, p2, h2, i2, r2, o2, e2, f3, c2, a2), v2 = p2.__e, p2.ref && h2.ref != p2.ref && (h2.ref && J(h2.ref, null, p2), a2.push(p2.ref, p2.__c || v2, p2)), null == y2 && null != v2 && (y2 = v2), (g2 = !!(4 & p2.__u)) || h2.__k === p2.__k ? (f3 = j(p2, f3, n2, g2), g2 && h2.__e && (h2.__e = null)) : "function" == typeof p2.type && void 0 !== _2 ? f3 = _2 : v2 && (f3 = v2.nextSibling), p2.__u &= -7);
1707
+ return u3.__e = y2, f3;
1708
+ }
1709
+ function T(n2, l2, u3, t3, i2) {
1710
+ var r2, o2, e2, f3, c2, a2 = u3.length, s2 = a2, h2 = 0;
1711
+ for (n2.__k = new Array(i2), r2 = 0; r2 < i2; r2++) null != (o2 = l2[r2]) && "boolean" != typeof o2 && "function" != typeof o2 ? ("string" == typeof o2 || "number" == typeof o2 || "bigint" == typeof o2 || o2.constructor == String ? o2 = n2.__k[r2] = x(null, o2, null, null, null) : g(o2) ? o2 = n2.__k[r2] = x(S, { children: o2 }, null, null, null) : void 0 === o2.constructor && o2.__b > 0 ? o2 = n2.__k[r2] = x(o2.type, o2.props, o2.key, o2.ref ? o2.ref : null, o2.__v) : n2.__k[r2] = o2, f3 = r2 + h2, o2.__ = n2, o2.__b = n2.__b + 1, e2 = null, -1 != (c2 = o2.__i = O(o2, u3, f3, s2)) && (s2--, (e2 = u3[c2]) && (e2.__u |= 2)), null == e2 || null == e2.__v ? (-1 == c2 && (i2 > a2 ? h2-- : i2 < a2 && h2++), "function" != typeof o2.type && (o2.__u |= 4)) : c2 != f3 && (c2 == f3 - 1 ? h2-- : c2 == f3 + 1 ? h2++ : (c2 > f3 ? h2-- : h2++, o2.__u |= 4))) : n2.__k[r2] = null;
1712
+ if (s2) for (r2 = 0; r2 < a2; r2++) null != (e2 = u3[r2]) && 0 == (2 & e2.__u) && (e2.__e == t3 && (t3 = $(e2)), K(e2, e2));
1713
+ return t3;
1714
+ }
1715
+ function j(n2, l2, u3, t3) {
1716
+ var i2, r2;
1717
+ if ("function" == typeof n2.type) {
1718
+ for (i2 = n2.__k, r2 = 0; i2 && r2 < i2.length; r2++) i2[r2] && (i2[r2].__ = n2, l2 = j(i2[r2], l2, u3, t3));
1719
+ return l2;
1720
+ }
1721
+ n2.__e != l2 && (t3 && (l2 && n2.type && !l2.parentNode && (l2 = $(n2)), u3.insertBefore(n2.__e, l2 || null)), l2 = n2.__e);
1722
+ do {
1723
+ l2 = l2 && l2.nextSibling;
1724
+ } while (null != l2 && 8 == l2.nodeType);
1725
+ return l2;
1726
+ }
1727
+ function O(n2, l2, u3, t3) {
1728
+ var i2, r2, o2, e2 = n2.key, f3 = n2.type, c2 = l2[u3], a2 = null != c2 && 0 == (2 & c2.__u);
1729
+ if (null === c2 && null == e2 || a2 && e2 == c2.key && f3 == c2.type) return u3;
1730
+ if (t3 > (a2 ? 1 : 0)) {
1731
+ for (i2 = u3 - 1, r2 = u3 + 1; i2 >= 0 || r2 < l2.length; ) if (null != (c2 = l2[o2 = i2 >= 0 ? i2-- : r2++]) && 0 == (2 & c2.__u) && e2 == c2.key && f3 == c2.type) return o2;
1732
+ }
1733
+ return -1;
1734
+ }
1735
+ function z(n2, l2, u3) {
1736
+ "-" == l2[0] ? n2.setProperty(l2, null == u3 ? "" : u3) : n2[l2] = null == u3 ? "" : "number" != typeof u3 || _.test(l2) ? u3 : u3 + "px";
1737
+ }
1738
+ function N(n2, l2, u3, t3, i2) {
1739
+ var r2, o2;
1740
+ n: if ("style" == l2) if ("string" == typeof u3) n2.style.cssText = u3;
1741
+ else {
1742
+ if ("string" == typeof t3 && (n2.style.cssText = t3 = ""), t3) for (l2 in t3) u3 && l2 in u3 || z(n2.style, l2, "");
1743
+ if (u3) for (l2 in u3) t3 && u3[l2] == t3[l2] || z(n2.style, l2, u3[l2]);
1744
+ }
1745
+ else if ("o" == l2[0] && "n" == l2[1]) r2 = l2 != (l2 = l2.replace(s, "$1")), o2 = l2.toLowerCase(), l2 = o2 in n2 || "onFocusOut" == l2 || "onFocusIn" == l2 ? o2.slice(2) : l2.slice(2), n2.l || (n2.l = {}), n2.l[l2 + r2] = u3, u3 ? t3 ? u3[a] = t3[a] : (u3[a] = h, n2.addEventListener(l2, r2 ? v : p, r2)) : n2.removeEventListener(l2, r2 ? v : p, r2);
1746
+ else {
1747
+ if ("http://www.w3.org/2000/svg" == i2) l2 = l2.replace(/xlink(H|:h)/, "h").replace(/sName$/, "s");
1748
+ else if ("width" != l2 && "height" != l2 && "href" != l2 && "list" != l2 && "form" != l2 && "tabIndex" != l2 && "download" != l2 && "rowSpan" != l2 && "colSpan" != l2 && "role" != l2 && "popover" != l2 && l2 in n2) try {
1749
+ n2[l2] = null == u3 ? "" : u3;
1750
+ break n;
1751
+ } catch (n3) {
1752
+ }
1753
+ "function" == typeof u3 || (null == u3 || false === u3 && "-" != l2[4] ? n2.removeAttribute(l2) : n2.setAttribute(l2, "popover" == l2 && 1 == u3 ? "" : u3));
1754
+ }
1755
+ }
1756
+ function V(n2) {
1757
+ return function(u3) {
1758
+ if (this.l) {
1759
+ var t3 = this.l[u3.type + n2];
1760
+ if (null == u3[c]) u3[c] = h++;
1761
+ else if (u3[c] < t3[a]) return;
1762
+ return t3(l.event ? l.event(u3) : u3);
1763
+ }
1764
+ };
1765
+ }
1766
+ function q(n2, u3, t3, i2, r2, o2, e2, f3, c2, a2) {
1767
+ var s2, h2, p2, v2, y2, d2, _2, k2, x2, M, $2, I2, P2, A2, H2, T2, j2 = u3.type;
1768
+ if (void 0 !== u3.constructor) return null;
1769
+ 128 & t3.__u && (c2 = !!(32 & t3.__u), o2 = [f3 = u3.__e = t3.__e]), (s2 = l.__b) && s2(u3);
1770
+ n: if ("function" == typeof j2) {
1771
+ h2 = e2.length;
1772
+ try {
1773
+ if (x2 = u3.props, M = j2.prototype && j2.prototype.render, $2 = (s2 = j2.contextType) && i2[s2.__c], I2 = s2 ? $2 ? $2.props.value : s2.__ : i2, t3.__c ? k2 = (p2 = u3.__c = t3.__c).__ = p2.__E : (M ? u3.__c = p2 = new j2(x2, I2) : (u3.__c = p2 = new C(x2, I2), p2.constructor = j2, p2.render = Q), $2 && $2.sub(p2), p2.state || (p2.state = {}), p2.__n = i2, v2 = p2.__d = true, p2.__h = [], p2._sb = []), M && null == p2.__s && (p2.__s = p2.state), M && null != j2.getDerivedStateFromProps && (p2.__s == p2.state && (p2.__s = m({}, p2.__s)), m(p2.__s, j2.getDerivedStateFromProps(x2, p2.__s))), y2 = p2.props, d2 = p2.state, p2.__v = u3, v2) M && null == j2.getDerivedStateFromProps && null != p2.componentWillMount && p2.componentWillMount(), M && null != p2.componentDidMount && p2.__h.push(p2.componentDidMount);
1774
+ else {
1775
+ if (M && null == j2.getDerivedStateFromProps && x2 !== y2 && null != p2.componentWillReceiveProps && p2.componentWillReceiveProps(x2, I2), u3.__v == t3.__v || !p2.__e && null != p2.shouldComponentUpdate && false === p2.shouldComponentUpdate(x2, p2.__s, I2)) {
1776
+ u3.__v != t3.__v && (p2.props = x2, p2.state = p2.__s, p2.__d = false), u3.__e = t3.__e, u3.__k = t3.__k, u3.__k.some(function(n3) {
1777
+ n3 && (n3.__ = u3);
1778
+ }), w.push.apply(p2.__h, p2._sb), p2._sb = [], p2.__h.length && e2.push(p2);
1779
+ break n;
1780
+ }
1781
+ null != p2.componentWillUpdate && p2.componentWillUpdate(x2, p2.__s, I2), M && null != p2.componentDidUpdate && p2.__h.push(function() {
1782
+ p2.componentDidUpdate(y2, d2, _2);
1783
+ });
1784
+ }
1785
+ if (p2.context = I2, p2.props = x2, p2.__P = n2, p2.__e = false, P2 = l.__r, A2 = 0, M) p2.state = p2.__s, p2.__d = false, P2 && P2(u3), s2 = p2.render(p2.props, p2.state, p2.context), w.push.apply(p2.__h, p2._sb), p2._sb = [];
1786
+ else do {
1787
+ p2.__d = false, P2 && P2(u3), s2 = p2.render(p2.props, p2.state, p2.context), p2.state = p2.__s;
1788
+ } while (p2.__d && ++A2 < 25);
1789
+ p2.state = p2.__s, null != p2.getChildContext && (i2 = m(m({}, i2), p2.getChildContext())), M && !v2 && null != p2.getSnapshotBeforeUpdate && (_2 = p2.getSnapshotBeforeUpdate(y2, d2)), H2 = null != s2 && s2.type === S && null == s2.key ? E(s2.props.children) : s2, f3 = L(n2, g(H2) ? H2 : [H2], u3, t3, i2, r2, o2, e2, f3, c2, a2), p2.base = u3.__e, u3.__u &= -161, p2.__h.length && e2.push(p2), k2 && (p2.__E = p2.__ = null);
1790
+ } catch (n3) {
1791
+ if (e2.length = h2, u3.__v = null, c2 || null != o2) {
1792
+ if (n3.then) {
1793
+ for (u3.__u |= c2 ? 160 : 128; f3 && 8 == f3.nodeType && f3.nextSibling; ) f3 = f3.nextSibling;
1794
+ null != o2 && (o2[o2.indexOf(f3)] = null), u3.__e = f3;
1795
+ } else if (null != o2) for (T2 = o2.length; T2--; ) b(o2[T2]);
1796
+ } else u3.__e = t3.__e;
1797
+ null == u3.__k && (u3.__k = t3.__k || []), n3.then || B(u3), l.__e(n3, u3, t3);
1798
+ }
1799
+ } else null == o2 && u3.__v == t3.__v ? (u3.__k = t3.__k, u3.__e = t3.__e) : f3 = u3.__e = G(t3.__e, u3, t3, i2, r2, o2, e2, c2, a2);
1800
+ return (s2 = l.diffed) && s2(u3), 128 & u3.__u ? void 0 : f3;
1801
+ }
1802
+ function B(n2) {
1803
+ n2 && (n2.__c && (n2.__c.__e = true), n2.__k && n2.__k.some(B));
1804
+ }
1805
+ function D(n2, u3, t3) {
1806
+ for (var i2 = 0; i2 < t3.length; i2++) J(t3[i2], t3[++i2], t3[++i2]);
1807
+ l.__c && l.__c(u3, n2), n2.some(function(u4) {
1808
+ try {
1809
+ n2 = u4.__h, u4.__h = [], n2.some(function(n3) {
1810
+ n3.call(u4);
1811
+ });
1812
+ } catch (n3) {
1813
+ l.__e(n3, u4.__v);
1814
+ }
1815
+ });
1816
+ }
1817
+ function E(n2) {
1818
+ return "object" != typeof n2 || null == n2 || n2.__b > 0 ? n2 : g(n2) ? n2.map(E) : void 0 !== n2.constructor ? null : m({}, n2);
1819
+ }
1820
+ function G(u3, t3, i2, r2, o2, e2, f3, c2, a2) {
1821
+ var s2, h2, p2, v2, y2, w2, _2, m2 = i2.props || d, k2 = t3.props, x2 = t3.type;
1822
+ if ("svg" == x2 ? o2 = "http://www.w3.org/2000/svg" : "math" == x2 ? o2 = "http://www.w3.org/1998/Math/MathML" : o2 || (o2 = "http://www.w3.org/1999/xhtml"), null != e2) {
1823
+ for (s2 = 0; s2 < e2.length; s2++) if ((y2 = e2[s2]) && "setAttribute" in y2 == !!x2 && (x2 ? y2.localName == x2 : 3 == y2.nodeType)) {
1824
+ u3 = y2, e2[s2] = null;
1825
+ break;
1826
+ }
1827
+ }
1828
+ if (null == u3) {
1829
+ if (null == x2) return document.createTextNode(k2);
1830
+ u3 = document.createElementNS(o2, x2, k2.is && k2), c2 && (l.__m && l.__m(t3, e2), c2 = false), e2 = null;
1831
+ }
1832
+ if (null == x2) m2 === k2 || c2 && u3.data == k2 || (u3.data = k2);
1833
+ else {
1834
+ if (e2 = "textarea" == x2 && null != k2.defaultValue ? null : e2 && n.call(u3.childNodes), !c2 && null != e2) for (m2 = {}, s2 = 0; s2 < u3.attributes.length; s2++) m2[(y2 = u3.attributes[s2]).name] = y2.value;
1835
+ for (s2 in m2) y2 = m2[s2], "dangerouslySetInnerHTML" == s2 ? p2 = y2 : "children" == s2 || s2 in k2 || "value" == s2 && "defaultValue" in k2 || "checked" == s2 && "defaultChecked" in k2 || N(u3, s2, null, y2, o2);
1836
+ for (s2 in k2) y2 = k2[s2], "children" == s2 ? v2 = y2 : "dangerouslySetInnerHTML" == s2 ? h2 = y2 : "value" == s2 ? w2 = y2 : "checked" == s2 ? _2 = y2 : c2 && "function" != typeof y2 || m2[s2] === y2 || N(u3, s2, y2, m2[s2], o2);
1837
+ if (h2) c2 || p2 && (h2.__html == p2.__html || h2.__html == u3.innerHTML) || (u3.innerHTML = h2.__html), t3.__k = [];
1838
+ else if (p2 && (u3.innerHTML = ""), L("template" == t3.type ? u3.content : u3, g(v2) ? v2 : [v2], t3, i2, r2, "foreignObject" == x2 ? "http://www.w3.org/1999/xhtml" : o2, e2, f3, e2 ? e2[0] : i2.__k && $(i2, 0), c2, a2), null != e2) for (s2 = e2.length; s2--; ) b(e2[s2]);
1839
+ c2 && "textarea" != x2 || (s2 = "value", "progress" == x2 && null == w2 ? u3.removeAttribute("value") : null != w2 && (w2 !== u3[s2] || "progress" == x2 && !w2 || "option" == x2 && w2 != m2[s2]) && N(u3, s2, w2, m2[s2], o2), s2 = "checked", null != _2 && _2 != u3[s2] && N(u3, s2, _2, m2[s2], o2));
1840
+ }
1841
+ return u3;
1842
+ }
1843
+ function J(n2, u3, t3) {
1844
+ try {
1845
+ if ("function" == typeof n2) {
1846
+ var i2 = "function" == typeof n2.__u;
1847
+ i2 && n2.__u(), i2 && null == u3 || (n2.__u = n2(u3));
1848
+ } else n2.current = u3;
1849
+ } catch (n3) {
1850
+ l.__e(n3, t3);
1851
+ }
1852
+ }
1853
+ function K(n2, u3, t3) {
1854
+ var i2, r2;
1855
+ if (l.unmount && l.unmount(n2), (i2 = n2.ref) && (i2.current && i2.current != n2.__e || J(i2, null, u3)), null != (i2 = n2.__c)) {
1856
+ if (i2.componentWillUnmount) try {
1857
+ i2.componentWillUnmount();
1858
+ } catch (n3) {
1859
+ l.__e(n3, u3);
1860
+ }
1861
+ i2.base = i2.__P = i2.__n = null;
1862
+ }
1863
+ if (i2 = n2.__k) for (r2 = 0; r2 < i2.length; r2++) i2[r2] && K(i2[r2], u3, t3 || "function" != typeof n2.type);
1864
+ t3 || b(n2.__e), n2.__c = n2.__ = n2.__e = void 0;
1865
+ }
1866
+ function Q(n2, l2, u3) {
1867
+ return this.constructor(n2, u3);
1868
+ }
1869
+ function R(u3, t3, i2) {
1870
+ var r2, o2, e2, f3;
1871
+ t3 == document && (t3 = document.documentElement), l.__ && l.__(u3, t3), o2 = (r2 = "function" == typeof i2) ? null : i2 && i2.__k || t3.__k, e2 = [], f3 = [], q(t3, u3 = (!r2 && i2 || t3).__k = k(S, null, [u3]), o2 || d, d, t3.namespaceURI, !r2 && i2 ? [i2] : o2 ? null : t3.firstChild ? n.call(t3.childNodes) : null, e2, !r2 && i2 ? i2 : o2 ? o2.__e : t3.firstChild, r2, f3), D(e2, u3, f3), u3.props.children = null;
1872
+ }
1873
+ n = w.slice, l = { __e: function(n2, l2, u3, t3) {
1874
+ for (var i2, r2, o2; l2 = l2.__; ) if ((i2 = l2.__c) && !i2.__) try {
1875
+ if ((r2 = i2.constructor) && null != r2.getDerivedStateFromError && (i2.setState(r2.getDerivedStateFromError(n2)), o2 = i2.__d), null != i2.componentDidCatch && (i2.componentDidCatch(n2, t3 || {}), o2 = i2.__d), o2) return i2.__E = i2;
1876
+ } catch (l3) {
1877
+ n2 = l3;
1878
+ }
1879
+ throw n2;
1880
+ } }, u = 0, t2 = function(n2) {
1881
+ return null != n2 && void 0 === n2.constructor;
1882
+ }, C.prototype.setState = function(n2, l2) {
1883
+ var u3;
1884
+ u3 = null != this.__s && this.__s != this.state ? this.__s : this.__s = m({}, this.state), "function" == typeof n2 && (n2 = n2(m({}, u3), this.props)), n2 && m(u3, n2), null != n2 && this.__v && (l2 && this._sb.push(l2), A(this));
1885
+ }, C.prototype.forceUpdate = function(n2) {
1886
+ this.__v && (this.__e = true, n2 && this.__h.push(n2), A(this));
1887
+ }, C.prototype.render = S, i = [], o = "function" == typeof Promise ? Promise.prototype.then.bind(Promise.resolve()) : setTimeout, e = function(n2, l2) {
1888
+ return n2.__v.__b - l2.__v.__b;
1889
+ }, H.__r = 0, f = Math.random().toString(8), c = "__d" + f, a = "__a" + f, s = /(PointerCapture)$|Capture$/i, h = 0, p = V(false), v = V(true), y = 0;
1890
+
1891
+ // src/core/ui/icons.ts
1892
+ var LOGO_SVG = `<svg width="102" height="28" viewBox="0 0 102 28" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1893
+ <path d="M39.2674 2.19699C39.2757 2.18321 39.2839 2.16943 39.291 2.15528L39.2939 2.15057L39.2935 2.1502C39.3379 2.06208 39.3633 1.96308 39.3633 1.85754C39.3633 1.62109 39.2374 1.41474 39.0507 1.30231C39.0485 1.30014 39.0467 1.29651 39.0446 1.29578C35.1089 -0.88088 29.8537 -0.36627 26.3741 3.2632C24.4207 5.3006 23.4231 7.92116 23.3716 10.5544H23.3684V20.893C23.3684 21.2495 23.6538 21.5389 24.0058 21.5389H26.98C27.332 21.5389 27.6174 21.2495 27.6174 20.893V10.7698H27.6192C27.6192 9.14658 28.2169 7.52187 29.4209 6.26599C31.5699 4.02478 34.7423 3.8565 36.9299 5.03659C36.9367 5.04058 36.9439 5.04384 36.9507 5.04747C36.9557 5.05001 36.9607 5.05254 36.9657 5.05508H36.9664C37.0494 5.09497 37.1417 5.11782 37.2393 5.11782C37.4879 5.11782 37.7032 4.97276 37.808 4.76206L39.2674 2.19699Z" fill="#4338CA"/>
1894
+ <path d="M10.6216 0.000244141C4.75551 0.000244141 0 4.82177 0 10.7693V27.3543C0 27.7108 0.285079 28.0002 0.637405 28.0002H3.61161C3.96358 28.0002 4.24902 27.7108 4.24902 27.3543V19.3853C6.02424 20.7373 8.23084 21.5388 10.622 21.5388C16.4878 21.5388 21.244 16.7173 21.244 10.7697C21.2437 4.82177 16.4878 0.000244141 10.6216 0.000244141ZM10.6216 17.2311C7.10196 17.2311 4.24866 14.3382 4.24866 10.7693C4.24866 7.20079 7.10196 4.30788 10.6216 4.30788C14.1413 4.30788 16.995 7.20079 16.995 10.7693C16.995 14.3379 14.1413 17.2311 10.6216 17.2311Z" fill="#4338CA"/>
1895
+ <path d="M73.259 0C67.3932 0 62.6373 4.82152 62.6373 10.7691V27.3541C62.6373 27.7106 62.9228 28 63.2747 28H66.2489C66.6009 28 66.8863 27.7106 66.8863 27.3541V19.3854C68.6616 20.7374 70.8682 21.5389 73.2593 21.5389C79.1251 21.5389 83.8813 16.7174 83.8813 10.7698C83.881 4.82152 79.1248 0 73.259 0ZM73.259 17.2309C69.7393 17.2309 66.886 14.338 66.886 10.7691C66.886 7.20055 69.7393 4.30764 73.259 4.30764C76.7783 4.30764 79.632 7.20055 79.632 10.7691C79.632 14.3376 76.7783 17.2309 73.259 17.2309Z" fill="#4338CA"/>
1896
+ <path d="M60.439 10.9845C60.439 5.03657 55.6827 0 49.817 0C43.9508 0 39.1953 4.82152 39.1953 10.7691C39.1953 16.7167 43.9508 21.5382 49.817 21.5382C53.1374 21.5382 55.8763 19.9954 57.5939 18.1031C57.5939 18.1031 57.5942 18.1027 57.5946 18.1024C57.596 18.1009 57.5975 18.0995 57.5985 18.098C57.7112 17.9812 57.7806 17.822 57.7806 17.6461C57.7806 17.4601 57.7026 17.2929 57.5785 17.1751V17.1743L57.5696 17.1671C57.5535 17.1522 57.5367 17.1384 57.5188 17.1254L55.2464 15.2501C55.1344 15.1503 54.9877 15.0891 54.8264 15.0891C54.6261 15.0891 54.4476 15.183 54.331 15.3291C53.3216 16.3707 51.7256 17.2309 49.8166 17.2309C46.2969 17.2309 43.4436 14.338 43.4436 10.7691C43.4436 7.20055 46.2969 4.30764 49.8166 4.30764C52.5909 4.30764 54.9505 6.10605 55.8255 8.61527H50.3474C49.9954 8.61527 49.71 8.90467 49.71 9.26152V12.277C49.71 12.6339 49.9954 12.9233 50.3474 12.9233H59.5884C59.6059 12.9233 59.6227 12.9218 59.6399 12.9207C59.6571 12.9222 59.6742 12.9233 59.6914 12.9233C59.9743 12.9233 60.214 12.7361 60.2973 12.4772L60.3045 12.4783C60.308 12.4551 60.3116 12.4326 60.3152 12.4097C60.3199 12.3876 60.3234 12.3655 60.3256 12.3427C60.4003 11.861 60.439 11.5172 60.439 10.9845Z" fill="#4338CA"/>
1897
+ <path d="M101.928 2.15406L101.931 2.14934L101.93 2.14898C101.974 2.06085 102 1.96185 102 1.85632C102 1.61987 101.874 1.41351 101.687 1.30109C101.685 1.29891 101.683 1.29529 101.681 1.29456C97.7455 -0.882101 92.4903 -0.367491 89.0107 3.26198C87.0573 5.29938 86.0597 7.91993 86.0082 10.5532H86.005V20.8918C86.005 21.2483 86.2904 21.5377 86.6424 21.5377H89.6166C89.9686 21.5377 90.254 21.2483 90.254 20.8918V10.7686H90.2555C90.2555 9.14535 90.8532 7.52065 92.0571 6.26477C94.2062 4.02355 97.3785 3.85528 99.5662 5.03537C99.573 5.03936 99.5801 5.04262 99.5869 5.04624C99.5919 5.04878 99.5969 5.05132 99.6019 5.05386H99.6027C99.6856 5.09375 99.7779 5.11696 99.8756 5.11696C100.124 5.11696 100.339 4.9719 100.444 4.7612L101.905 2.19685C101.913 2.18235 101.92 2.16856 101.928 2.15406Z" fill="#4338CA"/>
1898
+ </svg>`;
1899
+ var TOGGLE_ICON_SVG = `<svg width="16" height="16" viewBox="1.05 0 16 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1900
+ <path d="M9.05365 0C5.71033 0 3 2.75516 3 6.15377V15.6309C3 15.8346 3.16248 16 3.36328 16H5.05838C5.25898 16 5.42166 15.8346 5.42166 15.6309V11.0772C6.43342 11.8498 7.69104 12.3077 9.05385 12.3077C12.397 12.3077 15.1077 9.55259 15.1077 6.15397C15.1075 2.75516 12.397 0 9.05365 0ZM9.05365 9.84623C7.04766 9.84623 5.42146 8.19314 5.42146 6.15377C5.42146 4.1146 7.04766 2.46151 9.05365 2.46151C11.0596 2.46151 12.686 4.1146 12.686 6.15377C12.686 8.19293 11.0596 9.84623 9.05365 9.84623Z" fill="currentColor"/>
1901
+ </svg>`;
1902
+ var ROTATE_ICON_SVG = `<svg width="15" height="14" viewBox="0 0 15 14" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1903
+ <path d="M3.37109 5.80078C3.20703 6.26562 2.6875 6.51172 2.25 6.34766C1.78516 6.18359 1.53906 5.69141 1.70312 5.22656C2.00391 4.37891 2.49609 3.58594 3.15234 2.92969C5.55859 0.550781 9.41406 0.550781 11.8203 2.92969L12.2852 3.42188V2C12.2852 1.53516 12.6953 1.125 13.1602 1.125C13.6523 1.125 14.0352 1.53516 14.0352 2V5.5C14.0352 5.99219 13.6523 6.375 13.1602 6.375H9.6875C9.19531 6.375 8.8125 5.99219 8.8125 5.5C8.8125 5.03516 9.19531 4.625 9.6875 4.625H11.0547L10.5898 4.16016C8.86719 2.46484 6.10547 2.46484 4.38281 4.16016C3.91797 4.65234 3.5625 5.19922 3.37109 5.80078ZM1.56641 8.17969C1.59375 8.15234 1.64844 8.15234 1.67578 8.15234C1.73047 8.15234 1.75781 8.125 1.8125 8.125H5.3125C5.77734 8.125 6.1875 8.53516 6.1875 9C6.1875 9.49219 5.77734 9.875 5.3125 9.875H3.91797L4.38281 10.3672C6.10547 12.0625 8.86719 12.0625 10.5898 10.3672C11.0547 9.875 11.4102 9.32812 11.6016 8.72656C11.7656 8.26172 12.2852 8.01562 12.7227 8.17969C13.1875 8.34375 13.4336 8.83594 13.2695 9.30078C12.9688 10.1484 12.4766 10.9141 11.8203 11.5977C9.41406 13.9766 5.55859 13.9766 3.15234 11.5977L2.6875 11.1055V12.5C2.6875 12.9922 2.27734 13.375 1.8125 13.375C1.32031 13.375 0.9375 12.9922 0.9375 12.5V9.02734C0.9375 8.97266 0.9375 8.91797 0.9375 8.89062C0.9375 8.83594 0.9375 8.80859 0.964844 8.78125C0.992188 8.64453 1.07422 8.50781 1.18359 8.39844C1.29297 8.28906 1.42969 8.20703 1.56641 8.17969Z" fill="currentColor"/>
1904
+ </svg>`;
1905
+ var SORT_DOWN_ICON_SVG = `<svg width="9" height="6" viewBox="0 0 9 6" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1906
+ <path d="M5.24274 5.36865C4.91462 5.72412 4.3404 5.72412 4.01227 5.36865L0.512273 1.86865C0.266179 1.62256 0.184148 1.23975 0.320867 0.911621C0.457586 0.583496 0.785711 0.364746 1.14118 0.364746H8.14118C8.46931 0.364746 8.79743 0.583496 8.93415 0.911621C9.07087 1.23975 8.98884 1.62256 8.74274 1.86865L5.24274 5.36865Z" fill="currentColor"/>
1907
+ </svg>`;
1908
+ var XMARK_ICON_SVG = `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1909
+ <path d="M4.22 4.22a.75.75 0 0 1 1.06 0L8 6.94l2.72-2.72a.75.75 0 1 1 1.06 1.06L9.06 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L8 9.06l-2.72 2.72a.75.75 0 1 1-1.06-1.06L6.94 8 4.22 5.28a.75.75 0 0 1 0-1.06z" fill="currentColor"/>
1910
+ </svg>`;
1911
+ var CLOSE_ICON_SVG = `<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
1912
+ <path d="M8.17578 1.07031C8.41016 0.816406 8.82031 0.816406 9.05469 1.07031C9.30859 1.30469 9.30859 1.71484 9.05469 1.94922L5.75391 5.25L9.05469 8.57031C9.30859 8.80469 9.30859 9.21484 9.05469 9.44922C8.82031 9.70312 8.41016 9.70312 8.17578 9.44922L4.875 6.14844L1.55469 9.44922C1.32031 9.70312 0.910156 9.70312 0.675781 9.44922C0.421875 9.21484 0.421875 8.80469 0.675781 8.57031L3.97656 5.25L0.675781 1.94922C0.421875 1.71484 0.421875 1.30469 0.675781 1.07031C0.910156 0.816406 1.32031 0.816406 1.55469 1.07031L4.875 4.37109L8.17578 1.07031Z" fill="currentColor"/>
1913
+ </svg>`;
1914
+
1915
+ // src/core/ui/toolbar.generated.ts
1916
+ var TOOLBAR_CSS = ":host{--prepr-primary:#4338ca;--prepr-bg:#eef2ff;--prepr-text:#1f2937;--prepr-radius:8px;--prepr-shadow:0px 0px 40px 0px #1f29373d;--prepr-z-index:10000;--prepr-primary-50:#eef2ff;--prepr-primary-100:#e0e7ff;--prepr-primary-800:#3730a3;--prepr-indigo-600:#4f46e5;--prepr-indigo-50:#eef2ff;--prepr-indigo-700:#4338ca;--prepr-secondary-400:#fb923c;--prepr-secondary-500:#f97316;--prepr-gray-100:#f3f4f6;--prepr-gray-200:#e5e7eb;--prepr-gray-300:#d1d5db;--prepr-gray-400:#9ca3af;--prepr-gray-500:#6b7280;--prepr-gray-700:#374151;--prepr-gray-800:#1f2937;--prepr-gray-900:#111827;--prepr-shadow-sm:0px 0px 12px 0px #c3c3c3cc;color:var(--prepr-text);box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5}:host *,:host :before,:host :after,*,:before,:after{box-sizing:border-box}button{font-family:inherit;font-size:inherit;margin:0}.prepr-regular-text{font-size:.875rem;font-weight:500;line-height:1.5}.prepr-backdrop{z-index:calc(var(--prepr-z-index) - 1);opacity:0;pointer-events:none;background:#0000001a;transition:opacity .2s ease-in-out;position:fixed;top:0;bottom:0;left:0;right:0}.prepr-backdrop[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-container{z-index:var(--prepr-z-index);justify-content:flex-end;align-items:center;display:flex;position:fixed;top:calc(50% - 64px);right:0}.prepr-toggle-holder{padding:.5rem}.prepr-toggle{cursor:pointer;background:var(--prepr-primary);color:#fff;border:none;border-radius:9999px;justify-content:center;align-items:center;width:2.25rem;height:2.25rem;display:flex}.prepr-toggle>span{display:flex}.prepr-toggle svg{color:#fff}.prepr-panel{z-index:var(--prepr-z-index);opacity:0;pointer-events:none;justify-content:flex-end;padding:.75rem;transition:opacity .2s ease-in-out;display:flex;position:fixed;top:50%;right:0;transform:translateY(-50%)}.prepr-panel[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-content{box-shadow:var(--prepr-shadow);border-radius:var(--prepr-radius);background:var(--prepr-bg);flex-direction:column;gap:2.5rem;width:100%;padding:1.5rem;display:flex}@media (min-width:640px){.prepr-panel{margin-right:4rem;padding:0}.prepr-content{width:502px;padding:2.5rem}}.prepr-header{justify-content:space-between;align-items:center;gap:.5rem;display:flex}.prepr-header-left{align-items:flex-start;gap:.75rem;display:flex}.prepr-badge{background:var(--prepr-primary-100);height:1.5rem;color:var(--prepr-primary);border-radius:4px;align-items:center;padding:.25rem .75rem;font-size:.875rem;display:flex}.prepr-header-close{cursor:pointer;background:var(--prepr-primary-100);width:2rem;height:2rem;color:var(--prepr-gray-700);border:none;border-radius:6px;justify-content:center;align-items:center;display:flex}.prepr-section{flex-direction:column;gap:.5rem;display:flex}.prepr-section-label{color:var(--prepr-gray-400);font-size:.875rem}.prepr-row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.5rem 1.5rem;display:flex}.prepr-row-title{color:var(--prepr-gray-800);margin:0;font-size:1rem;font-weight:600}.prepr-radiogroup{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);background:#fff;align-items:center;gap:.25rem;height:2.5rem;padding:.25rem;display:flex}.prepr-radiogroup[data-disabled=true]{cursor:not-allowed;opacity:.5}.prepr-radiogroup[data-disabled=true] .prepr-radio{pointer-events:none}.prepr-radio{cursor:pointer;white-space:nowrap;text-align:center;height:2rem;color:var(--prepr-gray-900);background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:.5rem 1.125rem;font-size:.875rem;font-weight:500;transition:all .2s ease-in-out;display:flex}.prepr-radio[data-checked=true]{background:var(--prepr-indigo-600);color:#fff;box-shadow:var(--prepr-shadow-sm)}.prepr-radio[data-checked=true][data-off=true]{background:var(--prepr-gray-800);color:#fff}.prepr-radio-variant{width:82px}.prepr-listbox{position:relative}.prepr-segment-button{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);width:240px;height:2.5rem;color:var(--prepr-gray-500);cursor:pointer;background:#fff;flex-shrink:0;align-items:center;gap:.5rem;padding:0 .5rem;font-size:.875rem;font-weight:500;display:flex;overflow:hidden}@media (min-width:768px){.prepr-segment-button{padding:0 1rem}}.prepr-segment-button:disabled{cursor:not-allowed;background:var(--prepr-gray-200);color:var(--prepr-gray-400)}.prepr-segment-button[aria-expanded=true]{border-bottom-color:#fff;border-bottom-right-radius:0;border-bottom-left-radius:0}.prepr-segment-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-segment-caret{color:var(--prepr-gray-800);display:flex}.prepr-options{z-index:calc(var(--prepr-z-index) + 1);border-left:1px solid var(--prepr-gray-300);border-right:1px solid var(--prepr-gray-300);border-bottom:1px solid var(--prepr-gray-300);-ms-overflow-style:none;scrollbar-width:none;background:#fff;border-radius:0 0 6px 6px;width:240px;max-height:300px;margin:0;padding:0;list-style:none;position:absolute;top:100%;left:0;overflow-y:auto;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-options::-webkit-scrollbar{display:none}.prepr-options[hidden]{display:none}.prepr-option-search{background:#fff;padding:.5rem;position:-webkit-sticky;position:sticky;top:0}.prepr-segment-search{border:1px solid var(--prepr-gray-300);border-radius:var(--prepr-radius);width:100%;height:2rem;font:inherit;color:var(--prepr-gray-900);box-sizing:border-box;background:#fff;padding:0 .5rem;font-size:.875rem}@media (pointer:coarse){.prepr-segment-search{font-size:16px}}.prepr-segment-search::placeholder{color:var(--prepr-gray-400)}.prepr-segment-search:focus{border-color:var(--prepr-gray-400);outline:none}.prepr-option{cursor:pointer;width:100%;color:var(--prepr-gray-900);background:#fff;align-items:center;padding:.5rem 1rem;font-size:.875rem;font-weight:500;display:flex}.prepr-option:hover{background:var(--prepr-gray-100)}.prepr-option[aria-selected=true]{background:var(--prepr-indigo-50);color:var(--prepr-indigo-700)}.prepr-option-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-reset{background:var(--prepr-secondary-400);color:#fff;cursor:pointer;border:none;border-radius:6px;justify-content:center;align-items:center;gap:.5rem;width:100%;height:2.5rem;padding:.5rem .75rem;font-size:.875rem;font-weight:500;display:flex}.prepr-reset:hover:not(:disabled){background:var(--prepr-secondary-500)}.prepr-reset:disabled{background:var(--prepr-gray-400);color:var(--prepr-gray-500);cursor:not-allowed}@media (min-width:768px){.prepr-reset{width:108px}}.prepr-indicators{z-index:var(--prepr-z-index);gap:.75rem;display:flex;position:fixed;bottom:1.5rem;right:1.5rem}.prepr-status-pill{background:var(--prepr-primary);color:#fff;cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-status-pill[data-interactive=false]{cursor:default;opacity:1;color:#fff}.prepr-status-pill[data-interactive=true]:hover{background:var(--prepr-primary-800)}.prepr-status-pill[hidden]{display:none}.prepr-status-viewing{color:#fff9;font-size:10px}.prepr-status-segment{text-overflow:ellipsis;white-space:nowrap;max-width:120px;display:inline-block;overflow:hidden}.prepr-status-variant{text-overflow:ellipsis;white-space:nowrap;background:#fff3;border-radius:4px;max-width:80px;padding:0 .5rem;display:inline-block;overflow:hidden}.prepr-status-x{color:#fff;width:.75rem;height:.75rem}.prepr-close-edit-pill{background:var(--prepr-primary-50);color:var(--prepr-gray-800);cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-close-edit-pill:hover{background:var(--prepr-primary-100)}.prepr-close-edit-pill[hidden]{display:none}.prepr-close-edit-x{width:1rem;height:1rem;color:var(--prepr-gray-500);transition:color .15s}.prepr-close-edit-pill:hover .prepr-close-edit-x{color:var(--prepr-gray-700)}.prepr-tip{z-index:calc(var(--prepr-z-index) + 2);overflow-wrap:break-word;background:var(--prepr-gray-900);color:#fff;pointer-events:none;border-radius:6px;width:auto;max-width:min(420px,100vw - 16px);padding:.5rem .75rem;font-size:.75rem;font-weight:500;position:fixed;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-tip-arrow{border-left:6px solid #0000;border-right:6px solid #0000;border-top:6px solid var(--prepr-gray-900);width:0;height:0;position:absolute;top:100%;transform:translate(-50%)}[hidden]{display:none!important}@keyframes prepr-fade-in{0%{opacity:0}to{opacity:1}}";
1917
+
1918
+ // ../../node_modules/.pnpm/preact@10.29.7/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
1919
+ var f2 = 0;
1920
+ function u2(e2, t3, n2, o2, i2, u3) {
1921
+ t3 || (t3 = {});
1922
+ var a2, c2, p2 = t3;
1923
+ if ("ref" in p2) for (c2 in p2 = {}, t3) "ref" == c2 ? a2 = t3[c2] : p2[c2] = t3[c2];
1924
+ var l2 = { type: e2, props: p2, key: n2, ref: a2, __k: null, __: null, __b: 0, __e: null, __c: null, constructor: void 0, __v: --f2, __i: -1, __u: 0, __source: i2, __self: u3 };
1925
+ if ("function" == typeof e2 && (a2 = e2.defaultProps)) for (c2 in a2) void 0 === p2[c2] && (p2[c2] = a2[c2]);
1926
+ return l.vnode && l.vnode(l2), l2;
1927
+ }
1928
+
1929
+ // src/core/ui/panel.tsx
1930
+ function RawSvg({
1931
+ svg,
1932
+ className
1933
+ }) {
1934
+ return /* @__PURE__ */ u2(
1935
+ "span",
1936
+ {
1937
+ className,
1938
+ dangerouslySetInnerHTML: { __html: svg }
1939
+ }
1940
+ );
1941
+ }
1942
+ function Header({ t: t3, onClose }) {
1943
+ return /* @__PURE__ */ u2("div", { class: "prepr-header", children: [
1944
+ /* @__PURE__ */ u2("div", { class: "prepr-header-left", children: [
1945
+ /* @__PURE__ */ u2(RawSvg, { svg: LOGO_SVG }),
1946
+ /* @__PURE__ */ u2("div", { class: "prepr-badge", "data-prepr": "badge", children: t3("common.toolbar") })
1947
+ ] }),
1948
+ /* @__PURE__ */ u2(
1949
+ "button",
1950
+ {
1951
+ type: "button",
1952
+ class: "prepr-header-close",
1953
+ "data-prepr": "close",
1954
+ "aria-label": t3("common.toolbar"),
1955
+ onClick: onClose,
1956
+ children: /* @__PURE__ */ u2(RawSvg, { svg: CLOSE_ICON_SVG })
1957
+ }
1958
+ )
1959
+ ] });
1960
+ }
1961
+ function PreviewSelector({
1962
+ state,
1963
+ t: t3,
1964
+ handlers
1965
+ }) {
1966
+ const value = String(state.previewMode);
1967
+ const options = [
1968
+ {
1969
+ v: false,
1970
+ label: t3("common.off"),
1971
+ off: true,
1972
+ tooltipKey: "adaptiveContent.offDescription"
1973
+ },
1974
+ {
1975
+ v: true,
1976
+ label: t3("common.on"),
1977
+ tooltipKey: "adaptiveContent.onDescription"
1978
+ }
1979
+ ];
1980
+ return /* @__PURE__ */ u2("div", { class: "prepr-radiogroup", role: "radiogroup", "data-prepr": "preview-group", children: options.map((opt) => {
1981
+ const checked = value === String(opt.v);
1982
+ return /* @__PURE__ */ u2(
1983
+ "button",
1984
+ {
1985
+ type: "button",
1986
+ class: "prepr-radio",
1987
+ "data-prepr": "preview-mode",
1988
+ "data-value": String(opt.v),
1989
+ "data-off": opt.off ? "true" : void 0,
1990
+ role: "radio",
1991
+ "data-checked": String(checked),
1992
+ "aria-checked": checked,
1993
+ "data-tooltip-key": opt.tooltipKey,
1994
+ onClick: () => handlers.onPreviewMode(opt.v),
1995
+ onMouseEnter: (e2) => handlers.onPreviewTooltipEnter(e2.currentTarget),
1996
+ onMouseLeave: () => handlers.onPreviewTooltipLeave(),
1997
+ onFocus: (e2) => handlers.onPreviewTooltipEnter(e2.currentTarget),
1998
+ onBlur: () => handlers.onPreviewTooltipLeave(),
1999
+ children: opt.label
2000
+ }
2001
+ );
2002
+ }) });
2003
+ }
2004
+ function SegmentListbox({
2005
+ state,
2006
+ t: t3,
2007
+ listboxOpen,
2008
+ segmentFilter,
2009
+ handlers
2010
+ }) {
2011
+ const segments = state.segments;
2012
+ const hasSegments = segments.length > 0;
2013
+ const filter = segmentFilter.trim().toLowerCase();
2014
+ const visibleSegments = filter ? segments.filter((s2) => s2.name.toLowerCase().includes(filter)) : segments;
2015
+ let label;
2016
+ if (!hasSegments) {
2017
+ label = t3("adaptiveContent.none");
2018
+ } else if (state.selectedSegment === null) {
2019
+ label = t3("adaptiveContent.chooseSegment");
2020
+ } else {
2021
+ const seg = segments.find((s2) => s2._id === state.selectedSegment);
2022
+ label = seg ? seg.name : t3("adaptiveContent.chooseSegment");
2023
+ }
2024
+ const disabled = !hasSegments || !state.previewMode;
2025
+ return /* @__PURE__ */ u2("div", { class: "prepr-listbox", children: [
2026
+ /* @__PURE__ */ u2(
2027
+ "button",
2028
+ {
2029
+ type: "button",
2030
+ class: "prepr-segment-button",
2031
+ "data-prepr": "segment-button",
2032
+ "aria-haspopup": "listbox",
2033
+ "aria-expanded": listboxOpen,
2034
+ disabled,
2035
+ onClick: () => handlers.onSegmentButtonClick(),
2036
+ onKeyDown: (e2) => handlers.onSegmentButtonKeydown(e2),
2037
+ children: [
2038
+ /* @__PURE__ */ u2("span", { class: "prepr-segment-label", "data-prepr": "segment-button-label", children: label }),
2039
+ /* @__PURE__ */ u2("span", { class: "prepr-segment-caret", children: /* @__PURE__ */ u2(RawSvg, { svg: SORT_DOWN_ICON_SVG }) })
2040
+ ]
2041
+ }
2042
+ ),
2043
+ /* @__PURE__ */ u2(
2044
+ "ul",
2045
+ {
2046
+ class: "prepr-options",
2047
+ "data-prepr": "options",
2048
+ role: "listbox",
2049
+ hidden: !listboxOpen,
2050
+ onKeyDown: (e2) => handlers.onOptionsKeydown(e2),
2051
+ children: [
2052
+ /* @__PURE__ */ u2("li", { class: "prepr-option-search", role: "none", children: /* @__PURE__ */ u2(
2053
+ "input",
2054
+ {
2055
+ type: "text",
2056
+ class: "prepr-segment-search",
2057
+ "data-prepr": "segment-search",
2058
+ placeholder: t3("adaptiveContent.searchSegments"),
2059
+ value: segmentFilter,
2060
+ onInput: (e2) => handlers.onSegmentFilterInput(
2061
+ e2.currentTarget.value
2062
+ )
2063
+ }
2064
+ ) }),
2065
+ visibleSegments.map((seg) => /* @__PURE__ */ u2(
2066
+ SegmentOption,
2067
+ {
2068
+ seg,
2069
+ selected: seg._id === state.selectedSegment,
2070
+ onChoose: handlers.onChooseSegment
2071
+ },
2072
+ seg._id
2073
+ ))
2074
+ ]
2075
+ }
2076
+ )
2077
+ ] });
2078
+ }
2079
+ function SegmentOption({
2080
+ seg,
2081
+ selected,
2082
+ onChoose
2083
+ }) {
2084
+ return /* @__PURE__ */ u2(
2085
+ "li",
2086
+ {
2087
+ class: "prepr-option",
2088
+ role: "option",
2089
+ "data-value": seg._id,
2090
+ tabIndex: -1,
2091
+ "aria-selected": selected,
2092
+ onClick: () => onChoose(seg._id),
2093
+ children: /* @__PURE__ */ u2("span", { class: "prepr-option-label", children: seg.name })
2094
+ }
2095
+ );
2096
+ }
2097
+ function VariantSelector({
2098
+ state,
2099
+ handlers
2100
+ }) {
2101
+ const variantValue = state.selectedVariant === "B" ? "B" : "A";
2102
+ const values = ["A", "B"];
2103
+ return /* @__PURE__ */ u2(
2104
+ "div",
2105
+ {
2106
+ class: "prepr-radiogroup",
2107
+ role: "radiogroup",
2108
+ "data-prepr": "variant-group",
2109
+ "data-disabled": String(!state.previewMode),
2110
+ children: values.map((v2) => {
2111
+ const checked = variantValue === v2;
2112
+ return /* @__PURE__ */ u2(
2113
+ "button",
2114
+ {
2115
+ type: "button",
2116
+ class: "prepr-radio prepr-radio-variant",
2117
+ "data-prepr": "variant",
2118
+ "data-value": v2,
2119
+ role: "radio",
2120
+ "data-checked": String(checked),
2121
+ "aria-checked": checked,
2122
+ onClick: () => handlers.onVariant(v2),
2123
+ children: v2
2124
+ }
2125
+ );
2126
+ })
2127
+ }
2128
+ );
2129
+ }
2130
+ function EditModeSelector({
2131
+ state,
2132
+ t: t3,
2133
+ handlers
2134
+ }) {
2135
+ const value = String(state.editMode);
2136
+ const options = [
2137
+ { v: false, label: t3("common.off"), off: true },
2138
+ { v: true, label: t3("common.on") }
2139
+ ];
2140
+ return /* @__PURE__ */ u2("div", { class: "prepr-radiogroup", role: "radiogroup", "data-prepr": "edit-group", children: options.map((opt) => {
2141
+ const checked = value === String(opt.v);
2142
+ return /* @__PURE__ */ u2(
2143
+ "button",
2144
+ {
2145
+ type: "button",
2146
+ class: "prepr-radio",
2147
+ "data-prepr": "edit-mode",
2148
+ "data-value": String(opt.v),
2149
+ "data-off": opt.off ? "true" : void 0,
2150
+ role: "radio",
2151
+ "data-checked": String(checked),
2152
+ "aria-checked": checked,
2153
+ onClick: () => handlers.onEditMode(opt.v),
2154
+ children: opt.label
2155
+ }
2156
+ );
2157
+ }) });
2158
+ }
2159
+ function StatusPill({
2160
+ state,
2161
+ t: t3,
2162
+ handlers
2163
+ }) {
2164
+ const { features } = state;
2165
+ const defaultSegmentName = state.segments.find((s2) => s2._id === "all_other_users")?.name ?? t3("adaptiveContent.allOtherUsers");
2166
+ let segmentLabel;
2167
+ if (!state.previewMode || !features.segments) {
2168
+ segmentLabel = t3("common.user");
2169
+ } else if (state.selectedSegment !== null) {
2170
+ const seg = state.segments.find((s2) => s2._id === state.selectedSegment);
2171
+ segmentLabel = seg ? seg.name : defaultSegmentName;
2172
+ } else {
2173
+ segmentLabel = defaultSegmentName;
2174
+ }
2175
+ const dirty = features.segments && state.selectedSegment !== null || features.abTesting && state.selectedVariant === "B";
2176
+ const interactive = !state.previewMode || dirty;
2177
+ return /* @__PURE__ */ u2(
2178
+ "button",
2179
+ {
2180
+ type: "button",
2181
+ class: "prepr-status-pill",
2182
+ "data-prepr": "status-pill",
2183
+ "data-interactive": String(interactive),
2184
+ hidden: state.isIframe,
2185
+ disabled: !interactive,
2186
+ onClick: () => handlers.onStatusPill(),
2187
+ children: [
2188
+ /* @__PURE__ */ u2("span", { class: "prepr-status-viewing", "data-prepr": "status-viewing", children: t3("common.viewingAs") }),
2189
+ /* @__PURE__ */ u2("span", { class: "prepr-status-segment", "data-prepr": "status-segment", children: segmentLabel }),
2190
+ /* @__PURE__ */ u2(
2191
+ "span",
2192
+ {
2193
+ class: "prepr-status-variant",
2194
+ "data-prepr": "status-variant",
2195
+ hidden: !features.abTesting || !state.previewMode,
2196
+ children: state.selectedVariant === "B" ? "B" : "A"
2197
+ }
2198
+ ),
2199
+ /* @__PURE__ */ u2(
2200
+ "span",
2201
+ {
2202
+ class: "prepr-status-x",
2203
+ "data-prepr": "status-x",
2204
+ hidden: !state.previewMode || !dirty,
2205
+ children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG })
2206
+ }
2207
+ )
2208
+ ]
2209
+ }
2210
+ );
2211
+ }
2212
+ function CloseEditPill({
2213
+ state,
2214
+ t: t3,
2215
+ handlers
2216
+ }) {
2217
+ return /* @__PURE__ */ u2(
2218
+ "button",
2219
+ {
2220
+ type: "button",
2221
+ class: "prepr-close-edit-pill",
2222
+ "data-prepr": "close-edit-pill",
2223
+ "aria-label": t3("editingTools.ariaCloseEditMode"),
2224
+ hidden: !state.features.editMode || !state.editMode || state.isIframe,
2225
+ onClick: () => handlers.onCloseEditPill(),
2226
+ children: [
2227
+ /* @__PURE__ */ u2("span", { "data-prepr": "close-edit-label", children: t3("editingTools.editMode") }),
2228
+ /* @__PURE__ */ u2("span", { class: "prepr-close-edit-x", children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG }) })
2229
+ ]
2230
+ }
2231
+ );
2232
+ }
2233
+ function Panel({
2234
+ state,
2235
+ t: t3,
2236
+ listboxOpen,
2237
+ segmentFilter,
2238
+ handlers
2239
+ }) {
2240
+ const { features } = state;
2241
+ const hasPersonalization = features.segments && state.selectedSegment !== null || features.abTesting && state.selectedVariant !== null;
2242
+ const showAdaptive = features.segments || features.abTesting;
2243
+ return /* @__PURE__ */ u2(S, { children: [
2244
+ /* @__PURE__ */ u2(
2245
+ "style",
2246
+ {
2247
+ dangerouslySetInnerHTML: { __html: TOOLBAR_CSS }
2248
+ }
2249
+ ),
2250
+ /* @__PURE__ */ u2(
2251
+ "div",
2252
+ {
2253
+ class: "prepr-backdrop",
2254
+ "data-prepr": "backdrop",
2255
+ "data-open": String(state.toolbarOpen)
2256
+ }
2257
+ ),
2258
+ /* @__PURE__ */ u2("div", { class: "prepr-container", children: /* @__PURE__ */ u2("div", { class: "prepr-toggle-holder", children: /* @__PURE__ */ u2(
2259
+ "button",
2260
+ {
2261
+ type: "button",
2262
+ class: "prepr-toggle",
2263
+ "data-prepr": "toggle",
2264
+ "aria-label": t3("common.toolbar"),
2265
+ onClick: () => handlers.onToggle(),
2266
+ children: /* @__PURE__ */ u2(RawSvg, { svg: TOGGLE_ICON_SVG })
2267
+ }
2268
+ ) }) }),
2269
+ /* @__PURE__ */ u2(
2270
+ "div",
2271
+ {
2272
+ class: "prepr-panel",
2273
+ "data-prepr": "panel",
2274
+ "data-open": String(state.toolbarOpen),
2275
+ children: /* @__PURE__ */ u2(
2276
+ "div",
2277
+ {
2278
+ class: "prepr-content",
2279
+ "data-prepr": "content",
2280
+ role: "dialog",
2281
+ "aria-label": t3("common.toolbar"),
2282
+ children: [
2283
+ /* @__PURE__ */ u2(Header, { t: t3, onClose: handlers.onClose }),
2284
+ showAdaptive && /* @__PURE__ */ u2("div", { class: "prepr-section", "data-prepr": "section-adaptive", children: [
2285
+ /* @__PURE__ */ u2("span", { class: "prepr-section-label", "data-prepr": "adaptive-label", children: t3("adaptiveContent.adaptiveContent") }),
2286
+ /* @__PURE__ */ u2("div", { class: "prepr-row", children: [
2287
+ /* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "preview-label", children: t3("adaptiveContent.enablePreview") }),
2288
+ /* @__PURE__ */ u2(PreviewSelector, { state, t: t3, handlers })
2289
+ ] }),
2290
+ features.segments && /* @__PURE__ */ u2("div", { class: "prepr-row", children: [
2291
+ /* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "segment-label", children: t3("adaptiveContent.segment") }),
2292
+ /* @__PURE__ */ u2(
2293
+ SegmentListbox,
2294
+ {
2295
+ state,
2296
+ t: t3,
2297
+ listboxOpen,
2298
+ segmentFilter,
2299
+ handlers
2300
+ }
2301
+ )
2302
+ ] }),
2303
+ features.abTesting && /* @__PURE__ */ u2("div", { class: "prepr-row", children: [
2304
+ /* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "variant-label", children: t3("adaptiveContent.ABVariant") }),
2305
+ /* @__PURE__ */ u2(VariantSelector, { state, handlers })
2306
+ ] })
2307
+ ] }),
2308
+ features.editMode && /* @__PURE__ */ u2("div", { class: "prepr-section", "data-prepr": "section-editing", children: [
2309
+ /* @__PURE__ */ u2("span", { class: "prepr-section-label", "data-prepr": "editing-label", children: t3("editingTools.editingTools") }),
2310
+ /* @__PURE__ */ u2("div", { class: "prepr-row", children: [
2311
+ /* @__PURE__ */ u2("h2", { class: "prepr-row-title", "data-prepr": "edit-label", children: t3("editingTools.editMode") }),
2312
+ /* @__PURE__ */ u2(EditModeSelector, { state, t: t3, handlers })
2313
+ ] })
2314
+ ] }),
2315
+ /* @__PURE__ */ u2(
2316
+ "button",
2317
+ {
2318
+ type: "button",
2319
+ class: "prepr-reset",
2320
+ "data-prepr": "reset",
2321
+ disabled: !hasPersonalization,
2322
+ onClick: () => handlers.onReset(),
2323
+ children: [
2324
+ /* @__PURE__ */ u2(RawSvg, { svg: ROTATE_ICON_SVG }),
2325
+ /* @__PURE__ */ u2("span", { "data-prepr": "reset-label", children: t3("common.reset") })
2326
+ ]
2327
+ }
2328
+ )
2329
+ ]
2330
+ }
2331
+ )
2332
+ }
2333
+ ),
2334
+ /* @__PURE__ */ u2("div", { class: "prepr-indicators", children: [
2335
+ /* @__PURE__ */ u2(StatusPill, { state, t: t3, handlers }),
2336
+ /* @__PURE__ */ u2(CloseEditPill, { state, t: t3, handlers })
2337
+ ] }),
2338
+ /* @__PURE__ */ u2("div", { class: "prepr-tip", "data-prepr": "tooltip", role: "tooltip", hidden: true, children: [
2339
+ /* @__PURE__ */ u2("span", { "data-prepr": "tooltip-text" }),
2340
+ /* @__PURE__ */ u2("span", { class: "prepr-tip-arrow", "data-prepr": "tooltip-arrow" })
2341
+ ] })
2342
+ ] });
2343
+ }
2344
+
2345
+ // src/core/ui/toolbar-element.ts
2346
+ var TAG_NAME = "prepr-toolbar";
2347
+ var HTMLElementBase = typeof HTMLElement === "undefined" ? class {
2348
+ } : HTMLElement;
2349
+ var PreprToolbarElement = class extends HTMLElementBase {
2350
+ constructor() {
2351
+ super(...arguments);
2352
+ this.store = null;
2353
+ this.t = (key) => key;
2354
+ this.unsubscribe = null;
2355
+ this.listboxOpen = false;
2356
+ this.segmentFilter = "";
2357
+ this.handlers = {
2358
+ onToggle: () => this.set({ toolbarOpen: !this.state.toolbarOpen }),
2359
+ onClose: () => this.set({ toolbarOpen: false }),
2360
+ onPreviewMode: (value) => this.set({ previewMode: value }),
2361
+ onEditMode: (value) => {
2362
+ if (!this.state.features.editMode) return;
2363
+ this.set({ editMode: value });
2364
+ },
2365
+ onVariant: (value) => {
2366
+ if (!this.state.features.abTesting) return;
2367
+ if (!this.state.previewMode) return;
2368
+ this.set({ selectedVariant: value });
2369
+ },
2370
+ // Reset contract: segment to none, variant to 'A' — NOT null, since the
2371
+ // resulting `variant_changed` must carry 'A' on the wire — edit mode off.
2372
+ // Disabled features are left untouched: their state is already inert and
2373
+ // writing it would emit events for a feature the consumer turned off.
2374
+ onReset: () => this.set(this.resetPatch({ editMode: false })),
2375
+ onStatusPill: () => {
2376
+ if (!this.state.previewMode) {
2377
+ this.set({ previewMode: true });
2378
+ return;
2379
+ }
2380
+ const patch = this.resetPatch();
2381
+ const dirty = "selectedSegment" in patch && this.state.selectedSegment !== null || "selectedVariant" in patch && this.state.selectedVariant !== "A";
2382
+ if (dirty) this.set(patch);
2383
+ },
2384
+ onCloseEditPill: () => this.set({ editMode: false }),
2385
+ onSegmentButtonClick: () => this.toggleListbox(!this.listboxOpen),
2386
+ onSegmentButtonKeydown: (e2) => this.onListboxKeydown(e2),
2387
+ onOptionsKeydown: (e2) => this.onListboxKeydown(e2),
2388
+ onChooseSegment: (id) => this.chooseSegment(id),
2389
+ onSegmentFilterInput: (value) => {
2390
+ this.segmentFilter = value;
2391
+ this.renderPanel(this.state);
2392
+ },
2393
+ onPreviewTooltipEnter: (el) => this.showTooltip(el),
2394
+ onPreviewTooltipLeave: () => this.hideTooltip()
2395
+ };
2396
+ this.onDocumentMouseDown = (event) => {
2397
+ if (!this.listboxOpen) return;
2398
+ const button = this.segmentButton();
2399
+ const options = this.optionsList();
2400
+ if (!button || !options) return;
2401
+ const path = event.composedPath();
2402
+ if (!path.includes(button) && !path.includes(options)) {
2403
+ this.toggleListbox(false);
2404
+ }
2405
+ };
2406
+ }
2407
+ /** Idempotent: calling connect twice re-wires to the (possibly new) store. */
2408
+ connect(store, t3) {
2409
+ this.store = store;
2410
+ this.t = t3;
2411
+ if (!this.shadowRoot) {
2412
+ this.attachShadow({ mode: "open" });
2413
+ }
2414
+ this.unsubscribe?.();
2415
+ this.unsubscribe = store.subscribe((state) => this.renderPanel(state));
2416
+ document.removeEventListener("mousedown", this.onDocumentMouseDown);
2417
+ document.addEventListener("mousedown", this.onDocumentMouseDown);
2418
+ this.renderPanel(store.get());
2419
+ }
2420
+ disconnectedCallback() {
2421
+ this.unsubscribe?.();
2422
+ this.unsubscribe = null;
2423
+ document.removeEventListener("mousedown", this.onDocumentMouseDown);
2424
+ }
2425
+ // --------------------------------------------------------------- rendering
2426
+ get state() {
2427
+ return this.store.get();
2428
+ }
2429
+ set(patch) {
2430
+ this.store?.set(patch);
2431
+ }
2432
+ /** Reset patch covering only the enabled personalization features. */
2433
+ resetPatch(base = {}) {
2434
+ const { features } = this.state;
2435
+ const patch = { ...base };
2436
+ if (features.segments) patch.selectedSegment = null;
2437
+ if (features.abTesting) patch.selectedVariant = "A";
2438
+ return patch;
2439
+ }
2440
+ // Synchronous: Preact's top-level render() mutates the DOM before returning.
2441
+ renderPanel(state) {
2442
+ const root = this.shadowRoot;
2443
+ if (!root) return;
2444
+ R(
2445
+ k(Panel, {
2446
+ state,
2447
+ t: this.t,
2448
+ listboxOpen: this.listboxOpen,
2449
+ segmentFilter: this.segmentFilter,
2450
+ handlers: this.handlers
2451
+ }),
2452
+ root
2453
+ );
2454
+ }
2455
+ // ---------------------------------------------------------------- tooltip
2456
+ tip() {
2457
+ return this.shadowRoot?.querySelector('[data-prepr="tooltip"]') ?? null;
2458
+ }
2459
+ /**
2460
+ * Show the tooltip for a trigger carrying `data-tooltip-key`. Applied
2461
+ * imperatively rather than through the Preact tree: hover/focus never write
2462
+ * to the store, so no re-render can clobber it in between. Positioning is
2463
+ * centered above the trigger, clamped to the viewport with 8px padding,
2464
+ * arrow tracking the trigger center.
2465
+ */
2466
+ showTooltip(trigger) {
2467
+ const tooltip = this.tip();
2468
+ if (!tooltip) return;
2469
+ const textEl = tooltip.querySelector(
2470
+ '[data-prepr="tooltip-text"]'
2471
+ );
2472
+ const arrowEl = tooltip.querySelector(
2473
+ '[data-prepr="tooltip-arrow"]'
2474
+ );
2475
+ const key = trigger.getAttribute("data-tooltip-key");
2476
+ if (!key || !textEl || !arrowEl) return;
2477
+ textEl.textContent = this.t(key);
2478
+ tooltip.hidden = false;
2479
+ const padding = 8;
2480
+ const tip = tooltip.getBoundingClientRect();
2481
+ const tri = trigger.getBoundingClientRect();
2482
+ const centerX = tri.left + tri.width / 2;
2483
+ const spaceAbove = tri.top - padding;
2484
+ const spaceBelow = window.innerHeight - tri.bottom - padding;
2485
+ const placeTop = tip.height + padding <= spaceAbove || tip.height + padding > spaceBelow;
2486
+ const top = placeTop ? tri.top - tip.height - 8 : tri.bottom + 8;
2487
+ let left = centerX - tip.width / 2;
2488
+ if (left < padding) left = padding;
2489
+ if (left + tip.width > window.innerWidth - padding) {
2490
+ left = window.innerWidth - padding - tip.width;
2491
+ }
2492
+ const arrowX = Math.max(10, Math.min(centerX - left, tip.width - 10));
2493
+ tooltip.style.top = `${top}px`;
2494
+ tooltip.style.left = `${left}px`;
2495
+ arrowEl.style.left = `${arrowX}px`;
2496
+ }
2497
+ hideTooltip() {
2498
+ const tooltip = this.tip();
2499
+ if (tooltip) tooltip.hidden = true;
2500
+ }
2501
+ // ------------------------------------------------------- listbox controller
2502
+ segmentButton() {
2503
+ return this.shadowRoot?.querySelector(
2504
+ '[data-prepr="segment-button"]'
2505
+ ) ?? null;
2506
+ }
2507
+ optionsList() {
2508
+ return this.shadowRoot?.querySelector('[data-prepr="options"]') ?? null;
2509
+ }
2510
+ onListboxKeydown(event) {
2511
+ const e2 = event;
2512
+ const options = this.optionEls();
2513
+ const inSearch = e2.target?.getAttribute?.("data-prepr") === "segment-search";
2514
+ if (inSearch && e2.key === " ") return;
2515
+ if (options.length === 0 && e2.key !== "Escape") return;
2516
+ switch (e2.key) {
2517
+ case "Enter":
2518
+ case " ": {
2519
+ e2.preventDefault();
2520
+ if (!this.listboxOpen) {
2521
+ this.toggleListbox(true);
2522
+ } else {
2523
+ const active = this.activeOptionIndex();
2524
+ if (active >= 0) this.chooseSegment(options[active].dataset.value);
2525
+ }
2526
+ break;
2527
+ }
2528
+ case "Escape": {
2529
+ e2.preventDefault();
2530
+ this.toggleListbox(false);
2531
+ this.segmentButton()?.focus();
2532
+ break;
2533
+ }
2534
+ case "ArrowDown": {
2535
+ e2.preventDefault();
2536
+ if (!this.listboxOpen) this.toggleListbox(true);
2537
+ this.moveActiveOption(1);
2538
+ break;
2539
+ }
2540
+ case "ArrowUp": {
2541
+ e2.preventDefault();
2542
+ if (!this.listboxOpen) this.toggleListbox(true);
2543
+ this.moveActiveOption(-1);
2544
+ break;
2545
+ }
2546
+ default:
2547
+ break;
2548
+ }
2549
+ }
2550
+ optionEls() {
2551
+ const options = this.optionsList();
2552
+ if (!options) return [];
2553
+ return Array.from(options.querySelectorAll('[role="option"]'));
2554
+ }
2555
+ activeOptionIndex() {
2556
+ return this.optionEls().findIndex(
2557
+ (el) => el.getAttribute("data-active") === "true"
2558
+ );
2559
+ }
2560
+ moveActiveOption(delta) {
2561
+ const options = this.optionEls();
2562
+ if (options.length === 0) return;
2563
+ let index = this.activeOptionIndex();
2564
+ index = index < 0 ? 0 : (index + delta + options.length) % options.length;
2565
+ options.forEach(
2566
+ (el, i2) => el.setAttribute("data-active", String(i2 === index))
2567
+ );
2568
+ options[index].focus();
2569
+ }
2570
+ // Open state is view-only, so it lives on the element rather than the store.
2571
+ // Active-option attributes and focus are set after the synchronous re-render.
2572
+ toggleListbox(open) {
2573
+ const button = this.segmentButton();
2574
+ if (button?.disabled) return;
2575
+ this.listboxOpen = open;
2576
+ this.segmentFilter = "";
2577
+ this.renderPanel(this.state);
2578
+ if (open) {
2579
+ const options = this.optionEls();
2580
+ const selectedIndex = options.findIndex(
2581
+ (el) => el.getAttribute("aria-selected") === "true"
2582
+ );
2583
+ const activeIndex = selectedIndex >= 0 ? selectedIndex : 0;
2584
+ options.forEach(
2585
+ (el, i2) => el.setAttribute("data-active", String(i2 === activeIndex))
2586
+ );
2587
+ this.searchInput()?.focus();
2588
+ }
2589
+ }
2590
+ searchInput() {
2591
+ return this.shadowRoot?.querySelector(
2592
+ '[data-prepr="segment-search"]'
2593
+ ) ?? null;
2594
+ }
2595
+ chooseSegment(id) {
2596
+ if (!this.state.features.segments) return;
2597
+ this.listboxOpen = false;
2598
+ this.segmentFilter = "";
2599
+ this.set({ selectedSegment: id });
2600
+ this.renderPanel(this.state);
2601
+ this.segmentButton()?.focus();
2602
+ }
2603
+ };
2604
+ function definePreprToolbar() {
2605
+ if (typeof customElements === "undefined") return;
2606
+ if (!customElements.get(TAG_NAME)) {
2607
+ customElements.define(TAG_NAME, PreprToolbarElement);
2608
+ }
2609
+ }
2610
+
2611
+ // src/core/visual-editor/asset-images.ts
2612
+ var MAX_URL_LENGTH = 4096;
2613
+ var MIN_KEY_SEGMENTS = 2;
2614
+ var TRANSFORM_OPTION = /^[a-z]{1,3}_[\w.-]*$/i;
2615
+ var FORMAT_PLACEHOLDER = "{format}";
2616
+ var PROXY_PARAMS = ["url", "href", "src", "image"];
2617
+ var ABSOLUTE_HTTP = /^https?:\/\//i;
2618
+ var SOURCE_URL_ATTRIBUTES = ["src", "data-src"];
2619
+ var SOURCE_SET_ATTRIBUTES = ["srcset", "data-srcset"];
2620
+ var ASSET_ATTR = "data-prepr-asset";
2621
+ var ASSET_SOURCE_ATTRIBUTES = [
2622
+ ...SOURCE_URL_ATTRIBUTES,
2623
+ ...SOURCE_SET_ATTRIBUTES
2624
+ ];
2625
+ var TAG_ATTRIBUTES = [
2626
+ "data-prepr-encoded",
2627
+ "data-prepr-id",
2628
+ "data-prepr-field",
2629
+ "data-prepr-entry-id",
2630
+ ASSET_ATTR
2631
+ ];
2632
+ function decodeSegment(segment) {
2633
+ try {
2634
+ return decodeURIComponent(segment);
2635
+ } catch {
2636
+ return segment;
2637
+ }
2638
+ }
2639
+ function isTransformSegment(segment) {
2640
+ return segment === FORMAT_PLACEHOLDER || segment.split(",").every((option) => TRANSFORM_OPTION.test(option));
2641
+ }
2642
+ function assetKey(url, depth = 0) {
2643
+ if (!url || url.length > MAX_URL_LENGTH) return null;
2644
+ let parsed;
2645
+ try {
2646
+ parsed = new URL(url, "https://base.invalid");
2647
+ } catch {
2648
+ return null;
2649
+ }
2650
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
2651
+ if (depth === 0) {
2652
+ for (const name of PROXY_PARAMS) {
2653
+ const inner = parsed.searchParams.get(name);
2654
+ if (inner && ABSOLUTE_HTTP.test(inner)) return assetKey(inner, 1);
2655
+ }
2656
+ }
2657
+ const segments = parsed.pathname.split("/").filter(Boolean).map(decodeSegment);
2658
+ const file = segments.pop();
2659
+ if (!file) return null;
2660
+ const kept = segments.filter((segment) => !isTransformSegment(segment));
2661
+ kept.push(file);
2662
+ return kept.length >= MIN_KEY_SEGMENTS ? kept.join("/") : null;
2663
+ }
2664
+ function srcsetUrls(srcset) {
2665
+ const urls = [];
2666
+ let expectUrl = true;
2667
+ for (const token of srcset.split(/\s+/)) {
2668
+ if (!token) continue;
2669
+ if (!expectUrl) {
2670
+ const comma = token.indexOf(",");
2671
+ if (comma === -1) continue;
2672
+ expectUrl = true;
2673
+ const rest = token.slice(comma + 1);
2674
+ if (!rest) continue;
2675
+ urls.push(rest.replace(/,+$/, ""));
2676
+ expectUrl = rest.endsWith(",");
2677
+ continue;
2678
+ }
2679
+ const url = token.replace(/^,+|,+$/g, "");
2680
+ if (url) urls.push(url);
2681
+ expectUrl = token.endsWith(",");
2682
+ }
2683
+ return urls;
2684
+ }
2685
+ function createAssetIndex(assets) {
2686
+ const index = /* @__PURE__ */ new Map();
2687
+ for (const asset of assets) {
2688
+ const key = assetKey(asset.key);
2689
+ if (key && !index.has(key)) index.set(key, asset);
2690
+ }
2691
+ return index;
2692
+ }
2693
+ function urlsOf(img) {
2694
+ const urls = [];
2695
+ const collect = (el) => {
2696
+ for (const name of SOURCE_URL_ATTRIBUTES) {
2697
+ const value = el.getAttribute(name);
2698
+ if (value) urls.push(value);
2699
+ }
2700
+ for (const name of SOURCE_SET_ATTRIBUTES) {
2701
+ const value = el.getAttribute(name);
2702
+ if (value) urls.push(...srcsetUrls(value));
2703
+ }
2704
+ };
2705
+ collect(img);
2706
+ const picture = img.parentElement;
2707
+ if (picture?.tagName === "PICTURE") {
2708
+ for (const source of picture.children) {
2709
+ if (source.tagName === "SOURCE") collect(source);
2710
+ }
2711
+ }
2712
+ return urls;
2713
+ }
2714
+ function matchAsset(img, index, keys) {
2715
+ for (const url of urlsOf(img)) {
2716
+ let key = keys.get(url);
2717
+ if (key === void 0) {
2718
+ key = assetKey(url);
2719
+ keys.set(url, key);
2720
+ }
2721
+ const asset = key ? index.get(key) : void 0;
2722
+ if (asset) return asset;
2723
+ }
2724
+ return void 0;
2725
+ }
2726
+ function setIfChanged(el, name, value) {
2727
+ if (value === null) {
2728
+ if (el.hasAttribute(name)) el.removeAttribute(name);
2729
+ } else if (el.getAttribute(name) !== value) {
2730
+ el.setAttribute(name, value);
2731
+ }
2732
+ }
2733
+ function untagAssetImage(img) {
2734
+ for (const name of TAG_ATTRIBUTES) img.removeAttribute(name);
2735
+ }
2736
+ function tagAssetImages(index, itemId, keys) {
2737
+ for (const img of document.getElementsByTagName("img")) {
2738
+ const ours = img.hasAttribute(ASSET_ATTR);
2739
+ if (!ours && img.hasAttribute("data-prepr-encoded")) continue;
2740
+ const asset = index.size ? matchAsset(img, index, keys) : void 0;
2741
+ if (!asset) {
2742
+ if (ours) untagAssetImage(img);
2743
+ continue;
2744
+ }
2745
+ setIfChanged(img, "data-prepr-encoded", "");
2746
+ setIfChanged(img, ASSET_ATTR, "");
2747
+ setIfChanged(img, "data-prepr-id", itemId);
2748
+ setIfChanged(img, "data-prepr-field", asset.field);
2749
+ setIfChanged(img, "data-prepr-entry-id", asset.entryId ?? null);
2750
+ }
2751
+ }
2752
+ function untagAssetImages() {
2753
+ document.querySelectorAll(`img[${ASSET_ATTR}]`).forEach(untagAssetImage);
2754
+ }
2755
+
2756
+ // src/core/visual-editor/navigation-guard.ts
2757
+ var debug7 = createScopedLogger("navigation-guard");
2758
+ var trimSlash = (path) => path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
2759
+ function resolve(url) {
2760
+ try {
2761
+ return new URL(url, document.baseURI);
2762
+ } catch {
2763
+ return null;
2764
+ }
2765
+ }
2766
+ function leavesPage(url) {
2767
+ if (url.protocol !== "http:" && url.protocol !== "https:") return false;
2768
+ const here = window.location;
2769
+ return url.origin !== here.origin || trimSlash(url.pathname) !== trimSlash(here.pathname);
2770
+ }
2771
+ function leavingLinkHref(target) {
2772
+ if (!(target instanceof Element)) return null;
2773
+ const link = target.closest("a[href]");
2774
+ if (!link || link.hasAttribute("download")) return null;
2775
+ const linkTarget = link.getAttribute("target");
2776
+ if (linkTarget && linkTarget !== "_self") return null;
2777
+ const href = link.getAttribute("href") ?? "";
2778
+ if (href.startsWith("#")) return null;
2779
+ const url = resolve(href);
2780
+ return url && leavesPage(url) ? url.href : null;
2781
+ }
2782
+ function submitterAttr(submitter, attr) {
2783
+ if (!submitter?.hasAttribute(attr)) return null;
2784
+ if (attr === "formaction") return submitter.formAction;
2785
+ if (attr === "formmethod") return submitter.formMethod;
2786
+ return submitter.formTarget;
2787
+ }
2788
+ function submissionUrl(form, submitter) {
2789
+ const method = (submitterAttr(submitter, "formmethod") ?? form.method).toLowerCase();
2790
+ if (method === "dialog") return null;
2791
+ const target = submitterAttr(submitter, "formtarget") ?? form.target;
2792
+ if (target && target !== "_self") return null;
2793
+ const url = resolve(
2794
+ submitterAttr(submitter, "formaction") ?? (form.action || location.href)
2795
+ );
2796
+ if (!url) return null;
2797
+ if (method === "get") {
2798
+ let data;
2799
+ try {
2800
+ data = new FormData(form, submitter);
2801
+ } catch {
2802
+ data = new FormData(form);
2803
+ }
2804
+ const query = new URLSearchParams();
2805
+ data.forEach((value, key) => {
2806
+ query.append(key, typeof value === "string" ? value : value.name);
2807
+ });
2808
+ url.search = query.toString();
2809
+ }
2810
+ return url;
2811
+ }
2812
+ function createNavigationGuard(opts) {
2813
+ let active = false;
2814
+ let permitted = null;
2815
+ let pendingForm = null;
2816
+ let originalPush = null;
2817
+ let guardedPush = null;
2818
+ const isPermitted = (url) => permitted === url.href;
2819
+ const guarding = () => active && opts.showsEditedContent();
2820
+ const report = (href) => {
2821
+ debug7.log("blocked navigation to", href);
2822
+ opts.onBlocked(href);
2823
+ };
2824
+ const onSubmit = (e2) => {
2825
+ if (e2.defaultPrevented || !(e2.target instanceof HTMLFormElement)) return;
2826
+ if (!guarding()) return;
2827
+ const submitter = e2.submitter ?? null;
2828
+ const url = submissionUrl(e2.target, submitter);
2829
+ if (!url || !leavesPage(url) || isPermitted(url)) return;
2830
+ e2.preventDefault();
2831
+ pendingForm = { form: e2.target, submitter, href: url.href };
2832
+ report(url.href);
2833
+ };
2834
+ const onNavigate = (event) => {
2835
+ const e2 = event;
2836
+ if (e2.navigationType === "traverse" || e2.navigationType === "reload") {
2837
+ return;
2838
+ }
2839
+ if (!e2.cancelable || e2.hashChange || e2.downloadRequest !== null) return;
2840
+ if (!guarding()) return;
2841
+ if (e2.navigationType === "replace" && e2.destination.sameDocument) return;
2842
+ const url = resolve(e2.destination.url);
2843
+ if (!url || !leavesPage(url) || isPermitted(url)) return;
2844
+ e2.preventDefault();
2845
+ report(url.href);
2846
+ if (e2.destination.sameDocument) window.location.reload();
2847
+ };
2848
+ const navigation = () => window.navigation;
2849
+ function installPushGuard() {
2850
+ const original = history.pushState;
2851
+ const guard = function(data, unused, url) {
2852
+ if (guarding() && guardedPush === guard && url != null) {
2853
+ const target = resolve(url);
2854
+ if (target && leavesPage(target) && !isPermitted(target)) {
2855
+ report(target.href);
2856
+ window.location.reload();
2857
+ return;
2858
+ }
2859
+ }
2860
+ return original.call(this, data, unused, url);
2861
+ };
2862
+ originalPush = original;
2863
+ guardedPush = guard;
2864
+ history.pushState = guard;
2865
+ }
2866
+ function uninstallPushGuard() {
2867
+ if (history.pushState === guardedPush && originalPush) {
2868
+ history.pushState = originalPush;
2869
+ }
2870
+ originalPush = null;
2871
+ guardedPush = null;
2872
+ }
2873
+ return {
2874
+ start() {
2875
+ if (active) return;
2876
+ active = true;
2877
+ installPushGuard();
2878
+ window.addEventListener("submit", onSubmit);
2879
+ navigation()?.addEventListener("navigate", onNavigate);
2880
+ },
2881
+ stop() {
2882
+ if (!active) return;
2883
+ active = false;
2884
+ uninstallPushGuard();
2885
+ window.removeEventListener("submit", onSubmit);
2886
+ navigation()?.removeEventListener("navigate", onNavigate);
2887
+ pendingForm = null;
2888
+ },
2889
+ isActive: guarding,
2890
+ block(href) {
2891
+ report(href);
2892
+ },
2893
+ permit(href) {
2894
+ permitted = resolve(href)?.href ?? null;
2895
+ },
2896
+ allow(href) {
2897
+ const url = resolve(href);
2898
+ if (!url || url.protocol !== "http:" && url.protocol !== "https:") {
2899
+ debug7.warn("ignored navigation to unsupported URL");
2900
+ return;
2901
+ }
2902
+ permitted = url.href;
2903
+ const form = pendingForm;
2904
+ pendingForm = null;
2905
+ if (form && form.href === url.href && form.form.isConnected) {
2906
+ try {
2907
+ form.form.requestSubmit(form.submitter ?? void 0);
2908
+ } catch {
2909
+ form.form.requestSubmit();
2910
+ }
2911
+ return;
2912
+ }
2913
+ window.location.assign(url.href);
2914
+ }
2915
+ };
2916
+ }
2917
+
2918
+ // src/core/visual-editor/index.ts
2919
+ var debug8 = createScopedLogger("visual-editor");
2920
+ var ENCODED_SELECTOR2 = "[data-prepr-encoded]";
2921
+ var REFERENCE_ATTR = "data-prepr-reference";
2922
+ var REFERENCE_SELECTOR = `[${REFERENCE_ATTR}]`;
2923
+ var CURSOR_STYLE_MARKER = "data-prepr-visual-editor";
2924
+ var CURSOR_STYLES = `${ENCODED_SELECTOR2}{cursor:pointer}html[data-prepr-ve-suspended] ${ENCODED_SELECTOR2}{cursor:auto}`;
2925
+ var SUSPENDED_ATTR = "data-prepr-ve-suspended";
2926
+ var FIND_RETRY_MS = 150;
2927
+ var FIND_RETRIES = 6;
2928
+ var MAX_CACHED_KEYS = 2e3;
2929
+ var LAYOUT_MUTATIONS = {
2930
+ childList: true,
2931
+ subtree: true,
2932
+ characterData: true,
2933
+ attributes: true,
2934
+ attributeFilter: [
2935
+ "class",
2936
+ "style",
2937
+ "hidden",
2938
+ "open",
2939
+ "data-prepr-encoded",
2940
+ // An image swapped by a carousel or lazy loader can show another asset.
2941
+ ...ASSET_SOURCE_ATTRIBUTES
2942
+ ]
2943
+ };
2944
+ function scrollIntoFrame(el) {
2945
+ const rect = el.getBoundingClientRect();
2946
+ const offset = Math.max(0, (window.innerHeight - rect.height) / 2);
2947
+ window.scrollTo({
2948
+ top: Math.max(0, window.scrollY + rect.top - offset),
2949
+ behavior: "smooth"
2950
+ });
2951
+ }
2952
+ var isVisible = (el) => typeof el.checkVisibility === "function" ? el.checkVisibility() : el.getClientRects().length > 0;
2953
+ function createVisualEditor(opts) {
2954
+ const overlay = new VisualEditorOverlay();
2955
+ let running = false;
2956
+ let currentItemId = null;
2957
+ let locale = opts.locale ?? "en";
2958
+ let suspended = false;
2959
+ let pointerFrame = null;
2960
+ let lastPointerTarget = null;
2961
+ let lastPointerX = 0;
2962
+ let lastPointerY = 0;
2963
+ let mutationFrame = null;
2964
+ let mutationObserver = null;
2965
+ let selection = null;
2966
+ let findTimeout = null;
2967
+ let settlePendingFind = null;
2968
+ let guardEnabled = false;
2969
+ let assetIndex = /* @__PURE__ */ new Map();
2970
+ const assetKeys = /* @__PURE__ */ new Map();
2971
+ const guard = createNavigationGuard({
2972
+ onBlocked: (href) => opts.onNavigationBlocked?.(href),
2973
+ showsEditedContent: () => showsEditedContent()
2974
+ });
2975
+ const encodedFrom = (node) => node instanceof Element ? node.closest(ENCODED_SELECTOR2) : null;
2976
+ const labelFor = (el) => fieldLabel(el.getAttribute("data-prepr-field"), locale);
2977
+ let references = null;
2978
+ let ownComponents = /* @__PURE__ */ new Set();
2979
+ const isCurrentItem = (el) => {
2980
+ if (currentItemId === null) return true;
2981
+ const id = el.getAttribute("data-prepr-id");
2982
+ return !id || id === currentItemId || ownComponents.has(id);
2983
+ };
2984
+ const showsEditedContent = () => {
2985
+ for (const el of document.querySelectorAll(ENCODED_SELECTOR2)) {
2986
+ if (isCurrentItem(el) && isVisible(el)) return true;
2987
+ }
2988
+ return false;
2989
+ };
2990
+ const linkedIdOf = (el) => {
2991
+ if (!references) return null;
2992
+ const id = el.getAttribute("data-prepr-id") ?? "";
2993
+ if (references.has(id)) return id;
2994
+ let container = el.closest(REFERENCE_SELECTOR);
2995
+ while (container) {
2996
+ const linked = container.getAttribute(REFERENCE_ATTR) ?? "";
2997
+ if (references.has(linked)) return linked;
2998
+ container = container.parentElement?.closest(REFERENCE_SELECTOR) ?? null;
2999
+ }
3000
+ return null;
3001
+ };
3002
+ const itemKind = (el) => {
3003
+ if (isCurrentItem(el)) return "current";
3004
+ if (!references) return "other";
3005
+ return linkedIdOf(el) ? "referenced" : null;
3006
+ };
3007
+ const referenceFieldOf = (el) => {
3008
+ const linked = linkedIdOf(el);
3009
+ return linked ? references?.get(linked) : void 0;
3010
+ };
3011
+ const hoverLabel = (el, kind) => {
3012
+ if (kind === "other") {
3013
+ return `${labelFor(el)} \xB7 ${t("visualEditor.otherItem", locale)}`;
3014
+ }
3015
+ if (kind === "referenced") {
3016
+ const via = referenceFieldOf(el);
3017
+ const prefix = via ? `${fieldLabel(via, locale)} \u203A ` : "";
3018
+ return `${prefix}${labelFor(el)} \xB7 ${t("visualEditor.linkedItem", locale)}`;
3019
+ }
3020
+ return labelFor(el);
3021
+ };
3022
+ const setSuspended = (value) => {
3023
+ if (suspended === value) return;
3024
+ suspended = value;
3025
+ document.documentElement.toggleAttribute(SUSPENDED_ATTR, value);
3026
+ if (value) overlay.setHover(null, "");
3027
+ };
3028
+ const updateHover = () => {
3029
+ pointerFrame = null;
3030
+ overlay.schedule();
3031
+ if (suspended) return;
3032
+ const encoded = encodedFrom(lastPointerTarget);
3033
+ const target = encoded === overlay.getSelectedTarget() ? null : encoded;
3034
+ if (!target) {
3035
+ overlay.setHover(null, "");
3036
+ return;
3037
+ }
3038
+ const kind = itemKind(target);
3039
+ if (!kind) {
3040
+ overlay.setHover(null, "");
3041
+ return;
3042
+ }
3043
+ overlay.setHover(target, hoverLabel(target, kind), { kind });
3044
+ };
3045
+ const handlePointerMove = (e2) => {
3046
+ setSuspended(e2.altKey);
3047
+ lastPointerTarget = e2.target;
3048
+ lastPointerX = e2.clientX;
3049
+ lastPointerY = e2.clientY;
3050
+ if (pointerFrame === null) {
3051
+ pointerFrame = requestAnimationFrame(updateHover);
3052
+ }
3053
+ };
3054
+ const handlePointerLeave = () => {
3055
+ lastPointerTarget = null;
3056
+ overlay.setHover(null, "");
3057
+ };
3058
+ const handleClick = (e2) => {
3059
+ if (e2.altKey) {
3060
+ const href = leavingLinkHref(e2.target);
3061
+ if (href && guard.isActive()) guard.permit(href);
3062
+ return;
3063
+ }
3064
+ const encoded = encodedFrom(e2.target);
3065
+ const kind = encoded ? itemKind(encoded) : null;
3066
+ if (!encoded || !kind) {
3067
+ clearSelection();
3068
+ if (e2.ctrlKey || e2.metaKey || e2.shiftKey || !showsEditedContent()) return;
3069
+ const href = leavingLinkHref(e2.target);
3070
+ if (!href) return;
3071
+ e2.preventDefault();
3072
+ if (guard.isActive()) {
3073
+ e2.stopPropagation();
3074
+ guard.block(href);
3075
+ }
3076
+ return;
3077
+ }
3078
+ e2.preventDefault();
3079
+ e2.stopPropagation();
3080
+ const item = listItemIn(encoded, e2.target);
3081
+ if (kind === "current")
3082
+ select(item?.element ?? encoded, encoded, item?.index);
3083
+ const referenceField = kind === "referenced" ? referenceFieldOf(encoded) : void 0;
3084
+ const linkedId = kind === "referenced" ? linkedIdOf(encoded) : null;
3085
+ opts.onEdit({
3086
+ ...readEditPayload(encoded),
3087
+ ...linkedId && { id: linkedId },
3088
+ ...item && { block: item.index },
3089
+ ...referenceField && { referenceField }
3090
+ });
3091
+ };
3092
+ const handleKey = (e2) => {
3093
+ if (e2.key === "Alt") setSuspended(e2.type === "keydown");
3094
+ if (e2.type === "keydown" && e2.key === "Escape") {
3095
+ clearSelection();
3096
+ }
3097
+ };
3098
+ const handleBlur = () => setSuspended(false);
3099
+ const handleScroll = () => overlay.onScroll();
3100
+ const handleResize = () => overlay.schedule();
3101
+ const handleSettled = () => overlay.schedule();
3102
+ function listItemIn(encoded, target) {
3103
+ if (!(target instanceof Element)) return null;
3104
+ const li = target.closest("li");
3105
+ if (!li || !encoded.contains(li) || !li.parentElement) return null;
3106
+ const items = Array.from(li.parentElement.children).filter(
3107
+ (child) => child.tagName === "LI"
3108
+ );
3109
+ return { element: li, index: items.indexOf(li) };
3110
+ }
3111
+ function nthListItem(encoded, block) {
3112
+ const list = encoded.querySelector("ul, ol");
3113
+ if (!list) return null;
3114
+ const items = Array.from(list.children).filter(
3115
+ (child) => child.tagName === "LI"
3116
+ );
3117
+ return items[block] ?? null;
3118
+ }
3119
+ function select(el, field, block) {
3120
+ const entryId = field.getAttribute("data-prepr-entry-id");
3121
+ selection = {
3122
+ lookup: {
3123
+ field: field.getAttribute("data-prepr-field") ?? "",
3124
+ id: field.getAttribute("data-prepr-id") ?? void 0,
3125
+ ...entryId && { entryId },
3126
+ ...block !== void 0 && { block }
3127
+ },
3128
+ label: field
3129
+ };
3130
+ overlay.setSelected(el, labelFor(field));
3131
+ if (overlay.getHoverTarget() === el) overlay.setHover(null, "");
3132
+ }
3133
+ function clearSelection() {
3134
+ selection = null;
3135
+ overlay.setSelected(null, "");
3136
+ }
3137
+ function reselect() {
3138
+ if (!selection) return;
3139
+ const current = overlay.getSelectedTarget();
3140
+ if (current?.isConnected && selection.label.isConnected) return;
3141
+ const found = findFieldElement(selection.lookup);
3142
+ if (!found || !isCurrentItem(found)) {
3143
+ overlay.setSelected(null, "");
3144
+ return;
3145
+ }
3146
+ const { block } = selection.lookup;
3147
+ const el = block !== void 0 ? nthListItem(found, block) ?? found : found;
3148
+ select(el, found, block);
3149
+ }
3150
+ function tagAssets() {
3151
+ if (assetKeys.size > MAX_CACHED_KEYS) assetKeys.clear();
3152
+ tagAssetImages(assetIndex, currentItemId, assetKeys);
3153
+ }
3154
+ const handleLayoutFrame = () => {
3155
+ mutationFrame = null;
3156
+ if (assetIndex.size) tagAssets();
3157
+ reselect();
3158
+ const hovered = overlay.getHoverTarget();
3159
+ if (hovered && !hovered.isConnected) {
3160
+ lastPointerTarget = document.elementFromPoint(lastPointerX, lastPointerY);
3161
+ updateHover();
3162
+ return;
3163
+ }
3164
+ overlay.schedule();
3165
+ };
3166
+ const handleMutations = () => {
3167
+ if (mutationFrame !== null) return;
3168
+ if (!selection && !overlay.getHoverTarget() && !assetIndex.size) return;
3169
+ mutationFrame = requestAnimationFrame(handleLayoutFrame);
3170
+ };
3171
+ function injectCursorStyles() {
3172
+ if (document.querySelector(`style[${CURSOR_STYLE_MARKER}]`)) return;
3173
+ const style = document.createElement("style");
3174
+ style.setAttribute(CURSOR_STYLE_MARKER, "");
3175
+ style.textContent = CURSOR_STYLES;
3176
+ document.head.appendChild(style);
3177
+ }
3178
+ function start() {
3179
+ if (running) return;
3180
+ running = true;
3181
+ overlay.mount();
3182
+ injectCursorStyles();
3183
+ document.addEventListener("pointermove", handlePointerMove, {
3184
+ passive: true
3185
+ });
3186
+ document.documentElement.addEventListener(
3187
+ "pointerleave",
3188
+ handlePointerLeave
3189
+ );
3190
+ document.addEventListener("click", handleClick, { capture: true });
3191
+ window.addEventListener("keydown", handleKey);
3192
+ window.addEventListener("keyup", handleKey);
3193
+ window.addEventListener("blur", handleBlur);
3194
+ window.addEventListener("scroll", handleScroll, {
3195
+ capture: true,
3196
+ passive: true
3197
+ });
3198
+ window.addEventListener("resize", handleResize, { passive: true });
3199
+ document.addEventListener("transitionend", handleSettled, {
3200
+ capture: true,
3201
+ passive: true
3202
+ });
3203
+ document.addEventListener("animationend", handleSettled, {
3204
+ capture: true,
3205
+ passive: true
3206
+ });
3207
+ mutationObserver = new MutationObserver(handleMutations);
3208
+ mutationObserver.observe(document.body, LAYOUT_MUTATIONS);
3209
+ if (assetIndex.size) tagAssets();
3210
+ syncGuard();
3211
+ debug8.log("visual editor started");
3212
+ }
3213
+ function stop() {
3214
+ if (!running) return;
3215
+ running = false;
3216
+ if (pointerFrame !== null) cancelAnimationFrame(pointerFrame);
3217
+ if (mutationFrame !== null) cancelAnimationFrame(mutationFrame);
3218
+ mutationObserver?.disconnect();
3219
+ mutationObserver = null;
3220
+ cancelFind();
3221
+ pointerFrame = null;
3222
+ mutationFrame = null;
3223
+ selection = null;
3224
+ lastPointerTarget = null;
3225
+ setSuspended(false);
3226
+ document.removeEventListener("pointermove", handlePointerMove);
3227
+ document.documentElement.removeEventListener(
3228
+ "pointerleave",
3229
+ handlePointerLeave
3230
+ );
3231
+ document.removeEventListener("click", handleClick, { capture: true });
3232
+ window.removeEventListener("keydown", handleKey);
3233
+ window.removeEventListener("keyup", handleKey);
3234
+ window.removeEventListener("blur", handleBlur);
3235
+ window.removeEventListener("scroll", handleScroll, { capture: true });
3236
+ window.removeEventListener("resize", handleResize);
3237
+ document.removeEventListener("transitionend", handleSettled, {
3238
+ capture: true
3239
+ });
3240
+ document.removeEventListener("animationend", handleSettled, {
3241
+ capture: true
3242
+ });
3243
+ document.querySelectorAll(`style[${CURSOR_STYLE_MARKER}]`).forEach((node) => node.remove());
3244
+ overlay.unmount();
3245
+ untagAssetImages();
3246
+ guard.stop();
3247
+ debug8.log("visual editor stopped");
3248
+ }
3249
+ function cancelFind() {
3250
+ if (findTimeout) clearTimeout(findTimeout);
3251
+ findTimeout = null;
3252
+ settlePendingFind?.();
3253
+ settlePendingFind = null;
3254
+ }
3255
+ function focusField(lookup) {
3256
+ cancelFind();
3257
+ return new Promise((resolve2) => {
3258
+ let attempt = 0;
3259
+ const finish = (found) => {
3260
+ settlePendingFind = null;
3261
+ resolve2(found);
3262
+ };
3263
+ settlePendingFind = () => resolve2(false);
3264
+ const tryFind = () => {
3265
+ findTimeout = null;
3266
+ const found = findFieldElement(lookup);
3267
+ if (found) {
3268
+ const el = lookup.block !== void 0 ? nthListItem(found, lookup.block) ?? found : found;
3269
+ scrollIntoFrame(el);
3270
+ if (running && isCurrentItem(found)) select(el, found, lookup.block);
3271
+ finish(true);
3272
+ return;
3273
+ }
3274
+ if (++attempt >= FIND_RETRIES) {
3275
+ debug8.log("no element renders field", lookup.field);
3276
+ finish(false);
3277
+ return;
3278
+ }
3279
+ findTimeout = setTimeout(tryFind, FIND_RETRY_MS);
3280
+ };
3281
+ tryFind();
3282
+ });
3283
+ }
3284
+ function setCurrentItem(itemId, referenceList, componentIds) {
3285
+ currentItemId = itemId;
3286
+ if (referenceList) setReferences(referenceList, componentIds);
3287
+ else if (componentIds) ownComponents = new Set(componentIds);
3288
+ if (running && assetIndex.size) tagAssets();
3289
+ const selected = overlay.getSelectedTarget();
3290
+ const owner = selected ? encodedFrom(selected) : null;
3291
+ if (owner && !isCurrentItem(owner)) clearSelection();
3292
+ }
3293
+ function setAssets(assets) {
3294
+ const hadAssets = assetIndex.size > 0;
3295
+ assetIndex = createAssetIndex(assets);
3296
+ if (running && (hadAssets || assetIndex.size)) tagAssets();
3297
+ }
3298
+ function setReferences(referenceList, componentIds) {
3299
+ if (componentIds) ownComponents = new Set(componentIds);
3300
+ references = /* @__PURE__ */ new Map();
3301
+ for (const { id, field } of referenceList) {
3302
+ if (!references.has(id)) references.set(id, field);
3303
+ }
3304
+ }
3305
+ function setLocale(value) {
3306
+ locale = value;
3307
+ }
3308
+ function syncGuard() {
3309
+ if (running && guardEnabled) guard.start();
3310
+ else guard.stop();
3311
+ }
3312
+ function setNavigationGuard(enabled) {
3313
+ guardEnabled = enabled;
3314
+ syncGuard();
3315
+ }
3316
+ return {
3317
+ start,
3318
+ stop,
3319
+ setCurrentItem,
3320
+ setReferences,
3321
+ setAssets,
3322
+ setLocale,
3323
+ focusField,
3324
+ setNavigationGuard,
3325
+ allowNavigation: (href) => guard.allow(href)
3326
+ };
3327
+ }
3328
+
3329
+ // src/core/create-preview.ts
3330
+ var debug9 = createScopedLogger("create-preview");
3331
+ var controllerStores = /* @__PURE__ */ new WeakMap();
3332
+ function defaultNavigation() {
3333
+ return {
3334
+ navigate: (url) => window.location.assign(url),
3335
+ currentPath: () => window.location.pathname + window.location.search
3336
+ };
3337
+ }
3338
+ function safeEditUrl(href) {
3339
+ try {
3340
+ const url = new URL(href, window.location.href);
3341
+ return url.protocol === "https:" || url.protocol === "http:" ? url.href : null;
3342
+ } catch {
3343
+ return null;
3344
+ }
3345
+ }
3346
+ function buildSegments(data) {
3347
+ return [{ _id: "all_other_users", name: "All other users" }, ...data];
3348
+ }
3349
+ function resolveLocale(options) {
3350
+ const explicit = options?.locale;
3351
+ if (isLocale(explicit)) return explicit;
3352
+ if (typeof navigator !== "undefined") {
3353
+ const candidates = Array.isArray(navigator.languages) && navigator.languages.length ? navigator.languages : [navigator.language];
3354
+ const match = candidates.filter(Boolean).map((l2) => l2.toLowerCase().split("-")[0]).find(isLocale);
3355
+ if (match) return match;
3356
+ }
3357
+ return "en";
3358
+ }
3359
+ function createPreprPreview(opts = {}) {
3360
+ const { props, options } = opts;
3361
+ const navigation = opts.navigation ?? defaultNavigation();
3362
+ initDebugLogger(options?.debug ?? false);
3363
+ const noop = () => ({ destroy: () => {
3364
+ } });
3365
+ if (typeof window === "undefined" || typeof document === "undefined") {
3366
+ return noop();
3367
+ }
3368
+ const isIframe = window.parent !== window;
3369
+ const search = new URLSearchParams(window.location.search);
3370
+ const hideBar = search.get(PARAM_HIDE_BAR) === "true";
3371
+ if (hideBar) {
3372
+ debug9.log(`${PARAM_HIDE_BAR}=true \u2014 no visible toolbar`);
3373
+ }
3374
+ const mountUi = (options?.ui ?? true) && !isIframe && !hideBar;
3375
+ const locale = resolveLocale(options);
3376
+ const features = resolveFeatures(options?.features);
3377
+ const previewMode = getCookie(COOKIE_PREVIEW_MODE) === "true";
3378
+ const toolbarOpen = getCookie(COOKIE_TOOLBAR_OPEN) === "true";
3379
+ const cookieSegment = features.segments ? getCookie(COOKIE_SEGMENT) : null;
3380
+ const cookieVariant = features.abTesting ? getCookie(COOKIE_VARIANT) : null;
3381
+ const rawVariant = features.abTesting ? props?.activeVariant ?? cookieVariant : null;
3382
+ const selectedVariant = rawVariant === "A" || rawVariant === "B" ? rawVariant : null;
3383
+ const store = createToolbarStore({
3384
+ locale,
3385
+ features,
3386
+ segments: features.segments ? buildSegments(props?.segments ?? props?.data ?? []) : [],
3387
+ selectedSegment: features.segments ? props?.activeSegment ?? cookieSegment ?? null : null,
3388
+ selectedVariant,
3389
+ previewMode,
3390
+ toolbarOpen,
3391
+ isIframe
3392
+ });
3393
+ let el = null;
3394
+ if (mountUi) {
3395
+ definePreprToolbar();
3396
+ el = document.createElement("prepr-toolbar");
3397
+ document.body.appendChild(el);
3398
+ el.connect(store, (key) => t(key, locale));
3399
+ }
3400
+ const editingEnabled = features.editMode || isIframe;
3401
+ const onEdit = ({
3402
+ href,
3403
+ id,
3404
+ field,
3405
+ locale: contentLocale,
3406
+ block,
3407
+ entryId,
3408
+ referenceField
3409
+ }) => {
3410
+ const safeHref = href ? safeEditUrl(href) : null;
3411
+ if (href && !safeHref) {
3412
+ debug9.warn("ignored edit request with unsupported href scheme");
3413
+ return;
3414
+ }
3415
+ if (isIframe) {
3416
+ sendPreprEvent("field_edit_requested", {
3417
+ id,
3418
+ field,
3419
+ locale: contentLocale,
3420
+ ...block !== void 0 && { block },
3421
+ ...entryId && { entryId },
3422
+ ...referenceField && { referenceField }
3423
+ });
3424
+ } else if (safeHref) {
3425
+ window.open(safeHref, "_blank", "noopener,noreferrer");
3426
+ }
3427
+ };
3428
+ const visualEditor = isIframe ? createVisualEditor({
3429
+ onEdit,
3430
+ locale,
3431
+ onNavigationBlocked: (href) => sendPreprEvent("navigation_blocked", { href })
3432
+ }) : null;
3433
+ const stega = visualEditor ?? createStegaController({
3434
+ // The edit-mode marks and hover label are chrome, so they follow the
3435
+ // same decision as the bar: unwanted in a headless preview that asked
3436
+ // for no UI.
3437
+ tooltip: mountUi,
3438
+ onEdit,
3439
+ locale
3440
+ });
3441
+ const autoClean = createStegaAutoClean({
3442
+ enabled: options?.autoClean
3443
+ });
3444
+ autoClean.start();
3445
+ const handleChange = createChangeHandler({
3446
+ store,
3447
+ features,
3448
+ editingEnabled,
3449
+ navigate: (url) => navigation.navigate(url),
3450
+ currentPath: () => navigation.currentPath(),
3451
+ reload: navigation.reload ?? (() => window.location.reload()),
3452
+ stega
3453
+ });
3454
+ let prev = store.get();
3455
+ const unsubscribe = store.subscribe((state) => {
3456
+ const before = prev;
3457
+ prev = state;
3458
+ handleChange(before, state);
3459
+ });
3460
+ const bridge = createIframeBridge(store, {
3461
+ allowedEditorOrigins: options?.allowedEditorOrigins,
3462
+ onHandshake: ({
3463
+ itemId,
3464
+ referencedIds,
3465
+ componentIds,
3466
+ uiLocale,
3467
+ navigationGuard,
3468
+ assets
3469
+ }) => {
3470
+ if (uiLocale) visualEditor?.setLocale(uiLocale);
3471
+ visualEditor?.setCurrentItem(itemId ?? null, referencedIds, componentIds);
3472
+ visualEditor?.setNavigationGuard(navigationGuard === true);
3473
+ if (assets) visualEditor?.setAssets(assets);
3474
+ },
3475
+ onAssets: (assets) => visualEditor?.setAssets(assets),
3476
+ onAllowNavigation: (href) => visualEditor?.allowNavigation(href),
3477
+ onReferences: (referencedIds, componentIds) => visualEditor?.setReferences(referencedIds, componentIds),
3478
+ // The editor selecting a field scrolls the matching element into view. The
3479
+ // lookup relies on the attributes the stega scan writes, so it finds
3480
+ // nothing until encoded content has been tagged.
3481
+ onScrollToField: ({ field, id, block, entryId, fieldById }) => {
3482
+ if (visualEditor) {
3483
+ void visualEditor.focusField({ field, id, block, entryId, fieldById });
3484
+ return;
3485
+ }
3486
+ if (!scrollToField({ field, id })) {
3487
+ debug9.log("no element on this page renders field", field);
3488
+ }
3489
+ }
3490
+ });
3491
+ sendPreprEvent(
3492
+ "getScrollPosition",
3493
+ { value: 0 },
3494
+ {
3495
+ allowUntrustedTarget: true
3496
+ }
3497
+ );
3498
+ if (isIframe) {
3499
+ bridge.start();
3500
+ }
3501
+ function destroy() {
3502
+ unsubscribe();
3503
+ stega.stop();
3504
+ autoClean.stop();
3505
+ if (isIframe) {
3506
+ bridge.stop();
3507
+ }
3508
+ el?.remove();
3509
+ debug9.log("preview destroyed");
3510
+ }
3511
+ const controller = { destroy };
3512
+ controllerStores.set(controller, store);
3513
+ return controller;
3514
+ }
3515
+
3516
+ // src/core/live-preview/validate.ts
3517
+ function isScalar(v2) {
3518
+ return typeof v2 === "string" || typeof v2 === "number" || typeof v2 === "boolean";
3519
+ }
3520
+ var MAX_DEPTH = 3;
3521
+ var MAX_ENTRIES = 50;
3522
+ var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
3523
+ var SAFE_URL = /^https?:\/\//i;
3524
+ var URL_KEY = /^(?:url|href|src|link)$|(?:_url|Url)$/;
3525
+ var URL_IGNORED_ANYWHERE = /[\t\n\r]/g;
3526
+ var SCRIPT_SCHEME = /^(?:javascript|vbscript|data):/i;
3527
+ function isSafeLinkValue(value) {
3528
+ const stripped = value.replace(URL_IGNORED_ANYWHERE, "");
3529
+ let start = 0;
3530
+ while (start < stripped.length && stripped.charCodeAt(start) <= 32) start++;
3531
+ return !SCRIPT_SCHEME.test(stripped.slice(start));
3532
+ }
3533
+ function isUrlKey(key) {
3534
+ return URL_KEY.test(key);
3535
+ }
3536
+ function isSafeKeyValue(key, value) {
3537
+ if (typeof value !== "string") return true;
3538
+ if (key === "url") return SAFE_URL.test(value);
3539
+ return !isUrlKey(key) || isSafeLinkValue(value);
3540
+ }
3541
+ function isLiveValue(v2, depth = 0) {
3542
+ if (v2 === null || isScalar(v2)) return true;
3543
+ if (depth >= MAX_DEPTH) return false;
3544
+ if (Array.isArray(v2)) {
3545
+ return depth === 0 && v2.length <= MAX_ENTRIES && v2.every((entry) => isPlainRecord(entry) && isLiveValue(entry, depth + 1));
3546
+ }
3547
+ if (!isPlainRecord(v2)) return false;
3548
+ const keys = Object.keys(v2);
3549
+ if (keys.length > MAX_ENTRIES) return false;
3550
+ return keys.every((key) => {
3551
+ if (FORBIDDEN_KEYS.has(key)) return false;
3552
+ const value = v2[key];
3553
+ if (!isSafeKeyValue(key, value)) return false;
3554
+ return !Array.isArray(value) && isLiveValue(value, depth + 1);
3555
+ });
3556
+ }
3557
+ function isLiveFieldChange(field, value) {
3558
+ if (!isLiveValue(value)) return false;
3559
+ const name = field.slice(field.lastIndexOf(".") + 1);
3560
+ return typeof value !== "string" || !isUrlKey(name) || isSafeLinkValue(value);
3561
+ }
3562
+ var MAX_LIST_ENTRIES = 200;
3563
+ function parseListEntries(value) {
3564
+ if (!Array.isArray(value) || value.length > MAX_LIST_ENTRIES) return null;
3565
+ const list = [];
3566
+ for (const raw of value) {
3567
+ if (!isPlainRecord(raw) || typeof raw._id !== "string" || !raw._id) {
3568
+ return null;
3569
+ }
3570
+ const entry = { _id: raw._id };
3571
+ if (typeof raw.__typename === "string") entry.__typename = raw.__typename;
3572
+ if (typeof raw.body === "string") entry.body = raw.body;
3573
+ if (typeof raw.format === "string" || raw.format === null) {
3574
+ entry.format = raw.format;
3575
+ }
3576
+ if (typeof raw.typeName === "string" && raw.typeName.length <= 200) {
3577
+ entry.typeName = raw.typeName;
3578
+ }
3579
+ if (raw.fields !== void 0) {
3580
+ if (!isPlainRecord(raw.fields) || !isFieldValue(raw.fields, 0)) {
3581
+ return null;
3582
+ }
3583
+ entry.fields = raw.fields;
3584
+ }
3585
+ list.push(entry);
3586
+ }
3587
+ return list;
3588
+ }
3589
+ function isPlainRecord(v2) {
3590
+ return v2 !== null && typeof v2 === "object" && Object.getPrototypeOf(v2) === Object.prototype;
3591
+ }
3592
+ var MAX_FIELD_DEPTH = 6;
3593
+ var MAX_FIELD_KEYS = 100;
3594
+ function isFieldValue(v2, depth) {
3595
+ if (v2 === null || isScalar(v2)) return true;
3596
+ if (depth >= MAX_FIELD_DEPTH) return false;
3597
+ if (Array.isArray(v2)) {
3598
+ return v2.length <= MAX_ENTRIES && v2.every(
3599
+ (entry) => isScalar(entry) || isPlainRecord(entry) && isFieldValue(entry, depth + 1)
3600
+ );
3601
+ }
3602
+ if (!isPlainRecord(v2)) return false;
3603
+ const keys = Object.keys(v2);
3604
+ if (keys.length > MAX_FIELD_KEYS) return false;
3605
+ return keys.every((key) => {
3606
+ if (FORBIDDEN_KEYS.has(key)) return false;
3607
+ const value = v2[key];
3608
+ if (!isSafeKeyValue(key, value)) return false;
3609
+ return isFieldValue(value, depth + 1);
3610
+ });
3611
+ }
3612
+ var MAX_EDIT_LENGTH = 1e3;
3613
+ function parseEditTarget(raw) {
3614
+ if (!isPlainRecord(raw)) return void 0;
3615
+ const { item, field } = raw;
3616
+ if (typeof item !== "string" || !item || item.length > MAX_EDIT_LENGTH) {
3617
+ return void 0;
3618
+ }
3619
+ if (typeof field !== "string" || !field || field.length > MAX_EDIT_LENGTH) {
3620
+ return void 0;
3621
+ }
3622
+ return { item, field };
3623
+ }
3624
+
3625
+ // src/core/live-preview/bridge-events.ts
3626
+ var debug10 = createScopedLogger("live-preview:bridge");
3627
+ function createLiveBridge(store, options = {}) {
3628
+ let parentOrigin = null;
3629
+ const onMessage = (evt) => {
3630
+ const data = evt?.data;
3631
+ if (data?.event === "prepr:initVE" && !parentOrigin) {
3632
+ if (isAllowedEditorOrigin(evt.origin, options.allowedEditorOrigins?.())) {
3633
+ parentOrigin = evt.origin;
3634
+ } else {
3635
+ debug10.warn("ignored live preview handshake from origin", evt.origin);
3636
+ }
3637
+ return;
3638
+ }
3639
+ const trusted = parentOrigin ?? getTrustedParentOrigin();
3640
+ if (!trusted || evt.origin !== trusted) return;
3641
+ if (data?.event === "prepr:fieldChange") {
3642
+ if (typeof data.itemId === "string" && typeof data.field === "string" && data.field && isLiveFieldChange(data.field, data.value)) {
3643
+ const edit = parseEditTarget(data.edit);
3644
+ if (edit) store.pushPatch(data.itemId, data.field, data.value, edit);
3645
+ else store.pushPatch(data.itemId, data.field, data.value);
3646
+ } else {
3647
+ debug10.log("dropped malformed fieldChange", data);
3648
+ }
3649
+ return;
3650
+ }
3651
+ if (data?.event === "prepr:listChange") {
3652
+ const list = parseListEntries(data.entries);
3653
+ if (typeof data.itemId === "string" && typeof data.field === "string" && data.field && list) {
3654
+ store.pushList(data.itemId, data.field, list);
3655
+ } else {
3656
+ debug10.log("dropped malformed listChange", data);
3657
+ }
3658
+ return;
3659
+ }
3660
+ if (data?.event === "prepr:itemChanged") {
3661
+ if (typeof data.itemId === "string") {
3662
+ store.invalidate(data.itemId);
3663
+ } else {
3664
+ debug10.log("dropped malformed itemChanged", data);
3665
+ }
3666
+ }
3667
+ };
3668
+ return {
3669
+ start() {
3670
+ window.addEventListener("message", onMessage);
3671
+ sendPreprEvent(
3672
+ "live_ready",
3673
+ options.strictMode?.() ? { strictMode: true } : void 0,
3674
+ { allowUntrustedTarget: true }
3675
+ );
3676
+ },
3677
+ stop() {
3678
+ window.removeEventListener("message", onMessage);
3679
+ }
3680
+ };
3681
+ }
3682
+
3683
+ // src/core/live-preview/dom-patch.ts
3684
+ var INDEX_SEGMENT2 = /^\d+$/;
3685
+ var LIVE_ATTRIBUTE = "data-prepr-live";
3686
+ function fieldKey(path) {
3687
+ return path.split(".").filter((segment) => segment && segment !== "items").map(
3688
+ (segment) => INDEX_SEGMENT2.test(segment) ? String(Number.parseInt(segment, 10)) : segment
3689
+ ).join(".");
3690
+ }
3691
+ function patchTargets(patch) {
3692
+ if (patch.type !== "field") return [];
3693
+ const targets = [{ item: patch.itemId, field: patch.field }];
3694
+ if (patch.edit) targets.unshift(patch.edit);
3695
+ return targets;
3696
+ }
3697
+ function matchingElements(candidates, item, field) {
3698
+ const wanted = fieldKey(field);
3699
+ return candidates.filter((element) => {
3700
+ if (element.getAttribute("data-prepr-id") !== item) return false;
3701
+ const tagged = element.getAttribute("data-prepr-field");
3702
+ return tagged !== null && fieldKey(tagged) === wanted;
3703
+ });
3704
+ }
3705
+ var DROPPED_ELEMENTS = /* @__PURE__ */ new Set([
3706
+ "SCRIPT",
3707
+ "STYLE",
3708
+ "IFRAME",
3709
+ "OBJECT",
3710
+ "EMBED",
3711
+ "TEMPLATE",
3712
+ "NOSCRIPT",
3713
+ "SVG",
3714
+ "MATH",
3715
+ "LINK",
3716
+ "META",
3717
+ "BASE",
3718
+ "FORM",
3719
+ "INPUT",
3720
+ "BUTTON",
3721
+ "TEXTAREA",
3722
+ "SELECT"
3723
+ ]);
3724
+ var ALLOWED_ELEMENTS = /* @__PURE__ */ new Set([
3725
+ "A",
3726
+ "ABBR",
3727
+ "B",
3728
+ "BLOCKQUOTE",
3729
+ "BR",
3730
+ "CODE",
3731
+ "DEL",
3732
+ "DIV",
3733
+ "EM",
3734
+ "H1",
3735
+ "H2",
3736
+ "H3",
3737
+ "H4",
3738
+ "H5",
3739
+ "H6",
3740
+ "HR",
3741
+ "I",
3742
+ "INS",
3743
+ "LI",
3744
+ "MARK",
3745
+ "OL",
3746
+ "P",
3747
+ "PRE",
3748
+ "S",
3749
+ "SMALL",
3750
+ "SPAN",
3751
+ "STRONG",
3752
+ "SUB",
3753
+ "SUP",
3754
+ "TABLE",
3755
+ "TBODY",
3756
+ "TD",
3757
+ "TH",
3758
+ "THEAD",
3759
+ "TR",
3760
+ "U",
3761
+ "UL"
3762
+ ]);
3763
+ var SAFE_HREF = /^(?:https?:|mailto:|tel:|\/|#|\.{0,2}\/|[^:]*$)/i;
3764
+ function sanitizeRichText(html) {
3765
+ const template = document.createElement("template");
3766
+ template.innerHTML = html;
3767
+ const out = document.createDocumentFragment();
3768
+ const copy = (source, target) => {
3769
+ for (const child of Array.from(source.childNodes)) {
3770
+ if (child.nodeType === Node.TEXT_NODE) {
3771
+ target.appendChild(document.createTextNode(child.textContent ?? ""));
3772
+ continue;
3773
+ }
3774
+ if (child.nodeType !== Node.ELEMENT_NODE) continue;
3775
+ const element = child;
3776
+ const tag = element.tagName.toUpperCase();
3777
+ if (DROPPED_ELEMENTS.has(tag)) continue;
3778
+ if (!ALLOWED_ELEMENTS.has(tag)) {
3779
+ copy(element, target);
3780
+ continue;
3781
+ }
3782
+ const clean = document.createElement(tag.toLowerCase());
3783
+ if (tag === "A") {
3784
+ const href = element.getAttribute("href")?.trim();
3785
+ if (href && SAFE_HREF.test(href.replace(/[\t\n\r]/g, ""))) {
3786
+ clean.setAttribute("href", href);
3787
+ }
3788
+ if (element.getAttribute("target") === "_blank") {
3789
+ clean.setAttribute("target", "_blank");
3790
+ clean.setAttribute("rel", "noopener noreferrer");
3791
+ }
3792
+ }
3793
+ copy(element, clean);
3794
+ target.appendChild(clean);
3795
+ }
3796
+ };
3797
+ copy(template.content, out);
3798
+ return out;
3799
+ }
3800
+ var RICH_TEXT = /^\s*<[a-z!/]/i;
3801
+ function writeText(element, text) {
3802
+ if (!element.children.length) {
3803
+ if (element.textContent !== text) element.textContent = text;
3804
+ return true;
3805
+ }
3806
+ for (const node of Array.from(element.childNodes)) {
3807
+ const current = node.textContent ?? "";
3808
+ if (node.nodeType !== Node.TEXT_NODE || !current.trim()) continue;
3809
+ const next = current.match(/^\s*/)[0] + text + current.match(/\s*$/)[0];
3810
+ if (current !== next) node.textContent = next;
3811
+ return true;
3812
+ }
3813
+ return false;
3814
+ }
3815
+ function applyPatchLogToDom(log, root = document) {
3816
+ const candidates = Array.from(
3817
+ root.querySelectorAll("[data-prepr-encoded]")
3818
+ );
3819
+ let applied = 0;
3820
+ let skipped = 0;
3821
+ for (const patch of log) {
3822
+ if (patch.type !== "field" || typeof patch.value !== "string") {
3823
+ skipped++;
3824
+ continue;
3825
+ }
3826
+ let elements = [];
3827
+ for (const { item, field } of patchTargets(patch)) {
3828
+ elements = matchingElements(candidates, item, field);
3829
+ if (elements.length) break;
3830
+ }
3831
+ let written = false;
3832
+ for (const element of elements) {
3833
+ const mode = element.closest(`[${LIVE_ATTRIBUTE}]`)?.getAttribute(LIVE_ATTRIBUTE);
3834
+ if (mode === "off") continue;
3835
+ if (mode === "html") {
3836
+ element.replaceChildren(sanitizeRichText(patch.value));
3837
+ written = true;
3838
+ } else if (RICH_TEXT.test(patch.value)) {
3839
+ continue;
3840
+ } else if (writeText(element, patch.value)) {
3841
+ written = true;
3842
+ }
3843
+ }
3844
+ if (written) applied++;
3845
+ else skipped++;
3846
+ }
3847
+ return { applied, skipped };
3848
+ }
3849
+
3850
+ // src/core/live-preview/index-snapshot.ts
3851
+ var debug11 = createScopedLogger("live-preview");
3852
+ function indexSnapshot(data) {
3853
+ const index = /* @__PURE__ */ new Map();
3854
+ const visited = /* @__PURE__ */ new WeakSet();
3855
+ const path = [];
3856
+ function walk(node) {
3857
+ if (node === null || typeof node !== "object") return;
3858
+ if (visited.has(node)) return;
3859
+ visited.add(node);
3860
+ if (Array.isArray(node)) {
3861
+ for (let i2 = 0; i2 < node.length; i2++) {
3862
+ path.push(i2);
3863
+ walk(node[i2]);
3864
+ path.pop();
3865
+ }
3866
+ return;
3867
+ }
3868
+ const record = node;
3869
+ if (typeof record._id === "string") {
3870
+ const paths = index.get(record._id);
3871
+ if (paths) paths.push([...path]);
3872
+ else index.set(record._id, [[...path]]);
3873
+ } else if (typeof record.__typename === "string") {
3874
+ debug11.log("item without _id will not live-update", {
3875
+ __typename: record.__typename
3876
+ });
3877
+ }
3878
+ for (const key in record) {
3879
+ if (!Object.prototype.hasOwnProperty.call(record, key)) continue;
3880
+ path.push(key);
3881
+ walk(record[key]);
3882
+ path.pop();
3883
+ }
3884
+ }
3885
+ walk(data);
3886
+ return index;
3887
+ }
3888
+
3889
+ // src/core/live-preview/patch.ts
3890
+ var import_stega5 = require("@vercel/stega");
3891
+
3892
+ // src/core/live-preview/field-name.ts
3893
+ var UPPERCASE_BOUNDARY = /(.)(?=[A-Z])/g;
3894
+ function graphqlFieldName(apiId) {
3895
+ return apiId.replace(UPPERCASE_BOUNDARY, "$1_").toLowerCase();
3896
+ }
3897
+ function fieldKeyIn(record, apiId) {
3898
+ if (Object.prototype.hasOwnProperty.call(record, apiId)) return apiId;
3899
+ const name = graphqlFieldName(apiId);
3900
+ return Object.prototype.hasOwnProperty.call(record, name) ? name : void 0;
3901
+ }
3902
+ var TEXT_BODY_FIELDS = [
3903
+ { name: "body", plain: false },
3904
+ { name: "html", plain: false },
3905
+ { name: "text", plain: true }
3906
+ ];
3907
+ var TAG_PATTERN = /<[^>]+>/g;
3908
+ function plainTextFromHtml(html) {
3909
+ return html.replace(TAG_PATTERN, "");
3910
+ }
3911
+ function isTextEntry(record) {
3912
+ const typename = record.__typename;
3913
+ if (typeof typename === "string") return typename === "Text";
3914
+ return "html" in record || "text" in record && "format" in record;
3915
+ }
3916
+
3917
+ // src/core/live-preview/patch.ts
3918
+ var INDEX_SEGMENT3 = /^\d+$/;
3919
+ var FORBIDDEN_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
3920
+ function isPlainObject(value) {
3921
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3922
+ }
3923
+ function mergeObject(current, incoming) {
3924
+ let changed = false;
3925
+ const next = { ...current };
3926
+ for (const key of Object.keys(current)) {
3927
+ if (!(key in incoming) || incoming[key] === void 0) continue;
3928
+ const value = isPlainObject(current[key]) && isPlainObject(incoming[key]) ? mergeObject(current[key], incoming[key]) : incoming[key];
3929
+ if (value !== current[key]) {
3930
+ next[key] = value;
3931
+ changed = true;
3932
+ }
3933
+ }
3934
+ return changed ? next : current;
3935
+ }
3936
+ function shapeLike(template, incoming) {
3937
+ const out = {};
3938
+ for (const key of Object.keys(template)) {
3939
+ const value = incoming[key];
3940
+ out[key] = value === void 0 ? null : isPlainObject(template[key]) && isPlainObject(value) ? shapeLike(template[key], value) : value;
3941
+ }
3942
+ return out;
3943
+ }
3944
+ function mergeStructured(current, incoming) {
3945
+ if (incoming === null || Array.isArray(incoming) && !incoming.length) {
3946
+ if (Array.isArray(current)) return current.length ? [] : current;
3947
+ return null;
3948
+ }
3949
+ const list = Array.isArray(incoming) ? incoming : [incoming];
3950
+ if (current === null || current === void 0) return incoming;
3951
+ if (Array.isArray(current)) {
3952
+ const template = current.find(isPlainObject);
3953
+ return list.map((entry) => {
3954
+ const match = current.find(
3955
+ (c2) => isPlainObject(c2) && c2._id !== void 0 && c2._id === entry._id
3956
+ );
3957
+ if (isPlainObject(match)) return mergeObject(match, entry);
3958
+ return isPlainObject(template) ? shapeLike(template, entry) : entry;
3959
+ });
3960
+ }
3961
+ if (isPlainObject(current)) return mergeObject(current, list[0]);
3962
+ return current;
3963
+ }
3964
+ function isPatchable(current) {
3965
+ return current === null || typeof current === "string" || typeof current === "number" || typeof current === "boolean";
3966
+ }
3967
+ function cloneNode(node) {
3968
+ return Array.isArray(node) ? [...node] : { ...node };
3969
+ }
3970
+ function patchSnapshot(snapshot, index, itemId, field, value) {
3971
+ const paths = index.get(itemId);
3972
+ if (!paths?.length) return snapshot;
3973
+ let root = snapshot;
3974
+ let changed = false;
3975
+ const markChanged = () => {
3976
+ changed = true;
3977
+ };
3978
+ for (const path of paths) {
3979
+ for (const [target, targetValue] of expandTextBody(
3980
+ root,
3981
+ path,
3982
+ field,
3983
+ value
3984
+ )) {
3985
+ root = patchAtPath(root, path, target, targetValue, markChanged);
3986
+ }
3987
+ }
3988
+ return changed ? root : snapshot;
3989
+ }
3990
+ function expandTextBody(root, path, field, value) {
3991
+ const segments = field.split(".");
3992
+ if (segments[segments.length - 1] !== "body" || typeof value !== "string") {
3993
+ return [[field, value]];
3994
+ }
3995
+ let node = root;
3996
+ for (const step of path) {
3997
+ node = node[step];
3998
+ }
3999
+ for (const segment of segments.slice(0, -1)) {
4000
+ if (node === null || typeof node !== "object") return [[field, value]];
4001
+ const record2 = node;
4002
+ node = INDEX_SEGMENT3.test(segment) ? record2[Number(segment)] : record2[fieldKeyIn(record2, segment) ?? segment];
4003
+ }
4004
+ if (node === null || typeof node !== "object" || Array.isArray(node)) {
4005
+ return [[field, value]];
4006
+ }
4007
+ const record = node;
4008
+ if (!isTextEntry(record)) return [[field, value]];
4009
+ const prefix = segments.slice(0, -1);
4010
+ const writes = [];
4011
+ for (const { name, plain } of TEXT_BODY_FIELDS) {
4012
+ if (!(name in record)) continue;
4013
+ writes.push([
4014
+ [...prefix, name].join("."),
4015
+ plain ? plainTextFromHtml(value) : value
4016
+ ]);
4017
+ }
4018
+ return writes.length ? writes : [[field, value]];
4019
+ }
4020
+ function patchAtPath(root, path, field, value, markChanged) {
4021
+ const segments = field.split(".");
4022
+ if (segments.some((s2) => FORBIDDEN_SEGMENTS.has(s2))) return root;
4023
+ let node = root;
4024
+ for (const step of path) {
4025
+ node = node[step];
4026
+ }
4027
+ const fullPath = [...path];
4028
+ for (const segment of segments) {
4029
+ let step = segment;
4030
+ if (INDEX_SEGMENT3.test(segment)) {
4031
+ step = Number(segment);
4032
+ } else if (node !== null && typeof node === "object") {
4033
+ step = fieldKeyIn(node, segment) ?? segment;
4034
+ }
4035
+ fullPath.push(step);
4036
+ node = node !== null && typeof node === "object" ? node[step] : void 0;
4037
+ }
4038
+ return writeAtPath(root, fullPath, value, markChanged);
4039
+ }
4040
+ function writeAtPath(root, fullPath, value, markChanged = () => {
4041
+ }) {
4042
+ if (!fullPath.length) return root;
4043
+ if (fullPath.some((s2) => FORBIDDEN_SEGMENTS.has(String(s2)))) return root;
4044
+ const last = fullPath.length - 1;
4045
+ let node = root;
4046
+ for (let i2 = 0; i2 < last; i2++) {
4047
+ if (node === null || typeof node !== "object") return root;
4048
+ node = node[fullPath[i2]];
4049
+ }
4050
+ if (node === null || typeof node !== "object") return root;
4051
+ const container = node;
4052
+ const key = fullPath[last];
4053
+ if (!(key in container)) return root;
4054
+ let next;
4055
+ if (value === null || typeof value === "object") {
4056
+ next = mergeStructured(container[key], value);
4057
+ } else if (!isPatchable(container[key])) {
4058
+ return root;
4059
+ } else {
4060
+ next = keepEditLink(container[key], value);
4061
+ }
4062
+ if (container[key] === next) return root;
4063
+ const newRoot = cloneNode(root);
4064
+ let cursor = newRoot;
4065
+ for (let i2 = 0; i2 < last; i2++) {
4066
+ const child = cloneNode(cursor[fullPath[i2]]);
4067
+ cursor[fullPath[i2]] = child;
4068
+ cursor = child;
4069
+ }
4070
+ cursor[key] = next;
4071
+ markChanged();
4072
+ return newRoot;
4073
+ }
4074
+ function listKeysOf(entry) {
4075
+ if (!isPlainObject(entry)) return [];
4076
+ const keys = [];
4077
+ if (typeof entry._id === "string") keys.push(entry._id);
4078
+ const first = Array.isArray(entry.items) ? entry.items[0] : null;
4079
+ if (isPlainObject(first) && typeof first._id === "string") {
4080
+ keys.push(first._id);
4081
+ }
4082
+ return keys;
4083
+ }
4084
+ function buildText(entry, template) {
4085
+ const body = typeof entry.body === "string" ? entry.body : "";
4086
+ const full = {
4087
+ __typename: "Text",
4088
+ _id: entry._id,
4089
+ body,
4090
+ html: body,
4091
+ text: plainTextFromHtml(body),
4092
+ format: entry.format ?? null
4093
+ };
4094
+ if (!template) return full;
4095
+ const out = {};
4096
+ for (const key of Object.keys(template)) {
4097
+ out[key] = key in full ? full[key] : null;
4098
+ }
4099
+ return out;
4100
+ }
4101
+ function syncList(current, entries, build) {
4102
+ if (current === null || current === void 0) {
4103
+ const built = syncList([], entries, build);
4104
+ return built.length ? built : current;
4105
+ }
4106
+ if (!Array.isArray(current)) return current;
4107
+ const byKey = /* @__PURE__ */ new Map();
4108
+ const templates = /* @__PURE__ */ new Map();
4109
+ for (const c2 of current) {
4110
+ for (const key of listKeysOf(c2)) byKey.set(key, c2);
4111
+ if (isPlainObject(c2) && typeof c2.__typename === "string") {
4112
+ if (!templates.has(c2.__typename)) templates.set(c2.__typename, c2);
4113
+ }
4114
+ }
4115
+ if (!entries.length) return current.length ? [] : current;
4116
+ if (current.length && !byKey.size) return current;
4117
+ if (current.length && !entries.some((e2) => byKey.has(e2._id))) return current;
4118
+ const next = [];
4119
+ for (const entry of entries) {
4120
+ const existing = byKey.get(entry._id);
4121
+ const built = existing === void 0 && entry.fields ? build?.(entry) : void 0;
4122
+ if (existing !== void 0) {
4123
+ next.push(existing);
4124
+ } else if (built) {
4125
+ next.push(built);
4126
+ } else if (entry.__typename === "Text") {
4127
+ next.push(buildText(entry, templates.get("Text")));
4128
+ }
4129
+ }
4130
+ const same = next.length === current.length && next.every((n2, i2) => n2 === current[i2]);
4131
+ return same ? current : next;
4132
+ }
4133
+ function syncListSnapshot(snapshot, index, itemId, field, entries) {
4134
+ const paths = index.get(itemId);
4135
+ if (!paths?.length) return snapshot;
4136
+ const fieldPath = field.split(".");
4137
+ if (fieldPath.some((s2) => FORBIDDEN_SEGMENTS.has(s2))) return snapshot;
4138
+ let root = snapshot;
4139
+ for (const path of paths) {
4140
+ root = syncListAtPath(root, [...path, ...fieldPath], entries);
4141
+ }
4142
+ return root;
4143
+ }
4144
+ function syncListAtPath(root, fullPath, entries, build) {
4145
+ if (!fullPath.length) return root;
4146
+ if (fullPath.some((s2) => FORBIDDEN_SEGMENTS.has(String(s2)))) return root;
4147
+ let node = root;
4148
+ for (const key of fullPath) {
4149
+ node = node !== null && typeof node === "object" ? node[key] : void 0;
4150
+ }
4151
+ const next = syncList(node, entries, build);
4152
+ if (next === node) return root;
4153
+ const newRoot = cloneNode(root);
4154
+ let cursor = newRoot;
4155
+ for (let i2 = 0; i2 < fullPath.length - 1; i2++) {
4156
+ const child = cloneNode(cursor[fullPath[i2]]);
4157
+ cursor[fullPath[i2]] = child;
4158
+ cursor = child;
4159
+ }
4160
+ cursor[fullPath[fullPath.length - 1]] = next;
4161
+ return newRoot;
4162
+ }
4163
+ function keepEditLink(current, value) {
4164
+ if (typeof current !== "string" || typeof value !== "string") return value;
4165
+ const { encoded } = (0, import_stega5.vercelStegaSplit)(current);
4166
+ if (!encoded || (0, import_stega5.vercelStegaSplit)(value).encoded) return value;
4167
+ return value + encoded;
4168
+ }
4169
+
4170
+ // src/core/live-preview/live-store.ts
4171
+ var debug12 = createScopedLogger("live-preview");
4172
+ var INVALIDATE_DEBOUNCE_MS = 150;
4173
+ var MAX_LOG_ENTRIES = 500;
4174
+ function withPatch(log, patch) {
4175
+ let previous = -1;
4176
+ for (let i2 = log.length - 1; i2 >= 0; i2--) {
4177
+ const p2 = log[i2];
4178
+ if (p2.type === patch.type && p2.itemId === patch.itemId && p2.field === patch.field) {
4179
+ previous = i2;
4180
+ break;
4181
+ }
4182
+ }
4183
+ if (previous === -1) return [...log, patch];
4184
+ const since = log.slice(previous + 1);
4185
+ const listPrefix = `${patch.field}.`;
4186
+ const dependsOnPosition = since.some(
4187
+ (p2) => p2.type === "list" || patch.type === "list" && p2.itemId === patch.itemId && p2.field.startsWith(listPrefix)
4188
+ );
4189
+ if (dependsOnPosition) return [...log, patch];
4190
+ return [...log.slice(0, previous), ...since, patch];
4191
+ }
4192
+ function createLiveStore(options = {}) {
4193
+ const accepts = (patch) => options.accept ? options.accept(patch) : true;
4194
+ const entries = /* @__PURE__ */ new Set();
4195
+ const invalidateListeners = /* @__PURE__ */ new Set();
4196
+ const pendingInvalidates = /* @__PURE__ */ new Map();
4197
+ let defaultFetcher = null;
4198
+ let log = [];
4199
+ const logListeners = /* @__PURE__ */ new Set();
4200
+ function record(patch) {
4201
+ log = withPatch(log, patch).slice(-MAX_LOG_ENTRIES);
4202
+ logListeners.forEach((fn) => fn(log));
4203
+ }
4204
+ function notify(entry) {
4205
+ entry.listeners.forEach((fn) => fn());
4206
+ }
4207
+ async function refetch(entry) {
4208
+ const fetcher = entry.opts.fetcher ?? defaultFetcher;
4209
+ if (!fetcher || entry.opts.query == null) return;
4210
+ const token = ++entry.fetchToken;
4211
+ try {
4212
+ const result = await fetcher(entry.opts.query, entry.opts.variables);
4213
+ if (token !== entry.fetchToken || !entries.has(entry)) return;
4214
+ entry.snapshot = result;
4215
+ entry.index = indexSnapshot(result);
4216
+ notify(entry);
4217
+ } catch (error) {
4218
+ debug12.log("refetch failed, keeping previous snapshot", error);
4219
+ }
4220
+ }
4221
+ function runInvalidate(itemId) {
4222
+ pendingInvalidates.delete(itemId);
4223
+ invalidateListeners.forEach((fn) => fn(itemId));
4224
+ for (const entry of entries) {
4225
+ if (entry.index.has(itemId)) void refetch(entry);
4226
+ }
4227
+ }
4228
+ return {
4229
+ register(data, opts = {}) {
4230
+ const entry = {
4231
+ snapshot: data,
4232
+ index: indexSnapshot(data),
4233
+ opts,
4234
+ listeners: /* @__PURE__ */ new Set(),
4235
+ fetchToken: 0
4236
+ };
4237
+ for (const patch of log) {
4238
+ if (patch.type === "field") {
4239
+ entry.snapshot = patchSnapshot(
4240
+ entry.snapshot,
4241
+ entry.index,
4242
+ patch.itemId,
4243
+ patch.field,
4244
+ patch.value
4245
+ );
4246
+ } else {
4247
+ const next = syncListSnapshot(
4248
+ entry.snapshot,
4249
+ entry.index,
4250
+ patch.itemId,
4251
+ patch.field,
4252
+ patch.entries
4253
+ );
4254
+ if (next !== entry.snapshot) {
4255
+ entry.snapshot = next;
4256
+ entry.index = indexSnapshot(next);
4257
+ }
4258
+ }
4259
+ }
4260
+ entries.add(entry);
4261
+ return {
4262
+ getSnapshot: () => entry.snapshot,
4263
+ subscribe(fn) {
4264
+ entry.listeners.add(fn);
4265
+ return () => entry.listeners.delete(fn);
4266
+ },
4267
+ unregister() {
4268
+ entry.listeners.clear();
4269
+ entries.delete(entry);
4270
+ }
4271
+ };
4272
+ },
4273
+ pushPatch(itemId, field, value, edit) {
4274
+ const patch = edit ? { type: "field", itemId, field, value, edit } : { type: "field", itemId, field, value };
4275
+ if (!accepts(patch)) return;
4276
+ record(patch);
4277
+ for (const entry of entries) {
4278
+ const next = patchSnapshot(
4279
+ entry.snapshot,
4280
+ entry.index,
4281
+ itemId,
4282
+ field,
4283
+ value
4284
+ );
4285
+ if (next !== entry.snapshot) {
4286
+ entry.snapshot = next;
4287
+ notify(entry);
4288
+ }
4289
+ }
4290
+ },
4291
+ pushList(itemId, field, list) {
4292
+ const patch = { type: "list", itemId, field, entries: list };
4293
+ if (!accepts(patch)) return;
4294
+ record(patch);
4295
+ for (const entry of entries) {
4296
+ const next = syncListSnapshot(
4297
+ entry.snapshot,
4298
+ entry.index,
4299
+ itemId,
4300
+ field,
4301
+ list
4302
+ );
4303
+ if (next !== entry.snapshot) {
4304
+ entry.snapshot = next;
4305
+ entry.index = indexSnapshot(next);
4306
+ notify(entry);
4307
+ }
4308
+ }
4309
+ },
4310
+ invalidate(itemId) {
4311
+ if (log.length) {
4312
+ log = [];
4313
+ logListeners.forEach((fn) => fn(log));
4314
+ }
4315
+ const pending = pendingInvalidates.get(itemId);
4316
+ if (pending) clearTimeout(pending);
4317
+ pendingInvalidates.set(
4318
+ itemId,
4319
+ setTimeout(() => runInvalidate(itemId), INVALIDATE_DEBOUNCE_MS)
4320
+ );
4321
+ },
4322
+ setFetcher(fetcher) {
4323
+ defaultFetcher = fetcher;
4324
+ },
4325
+ onInvalidate(fn) {
4326
+ invalidateListeners.add(fn);
4327
+ return () => invalidateListeners.delete(fn);
4328
+ },
4329
+ getLog: () => log,
4330
+ onLogChange(fn) {
4331
+ logListeners.add(fn);
4332
+ return () => logListeners.delete(fn);
4333
+ }
4334
+ };
4335
+ }
4336
+
4337
+ // src/core/live-preview/morph.ts
4338
+ function morphElement(current, next) {
4339
+ syncAttributes(current, next);
4340
+ morphChildren(current, next);
4341
+ }
4342
+ var SKIP_ATTR = "data-prepr-morph-skip";
4343
+ var RUNTIME_ATTR_PREFIXES = ["data-prepr-"];
4344
+ function isRuntimeAttribute(name) {
4345
+ return RUNTIME_ATTR_PREFIXES.some((prefix) => name.startsWith(prefix));
4346
+ }
4347
+ function syncAttributes(current, next) {
4348
+ for (const { name } of Array.from(current.attributes)) {
4349
+ if (!next.hasAttribute(name) && !isRuntimeAttribute(name)) {
4350
+ current.removeAttribute(name);
4351
+ }
4352
+ }
4353
+ for (const { name, value } of Array.from(next.attributes)) {
4354
+ if (current.getAttribute(name) !== value) current.setAttribute(name, value);
4355
+ }
4356
+ }
4357
+ function isSkipped(node) {
4358
+ return node.nodeType === Node.ELEMENT_NODE && (node.hasAttribute(SKIP_ATTR) || node.localName === "prepr-toolbar");
4359
+ }
4360
+ function sameKind(a2, b2) {
4361
+ if (a2.nodeType !== b2.nodeType) return false;
4362
+ if (a2.nodeType !== Node.ELEMENT_NODE) return true;
4363
+ const ea = a2;
4364
+ const eb = b2;
4365
+ return ea.localName === eb.localName && ea.id === eb.id;
4366
+ }
4367
+ function morphChildren(current, next) {
4368
+ const wanted = Array.from(next.childNodes).filter((n2) => !isSkipped(n2));
4369
+ const existing = Array.from(current.childNodes).filter((n2) => !isSkipped(n2));
4370
+ wanted.forEach((target, i2) => {
4371
+ const node = existing[i2];
4372
+ if (node && sameKind(node, target)) {
4373
+ if (node.nodeType === Node.ELEMENT_NODE) {
4374
+ const element = node;
4375
+ if (element.localName === "script") return;
4376
+ if (element.localName === "astro-island" && !element.isEqualNode(target)) {
4377
+ element.replaceWith(adopt(target, current));
4378
+ return;
4379
+ }
4380
+ morphElement(element, target);
4381
+ } else if (node.nodeValue !== target.nodeValue) {
4382
+ node.nodeValue = target.nodeValue;
4383
+ }
4384
+ return;
4385
+ }
4386
+ const replacement = adopt(target, current);
4387
+ if (node) node.replaceWith(replacement);
4388
+ else current.appendChild(replacement);
4389
+ });
4390
+ for (const extra of existing.slice(wanted.length)) extra.remove();
4391
+ }
4392
+ function adopt(node, parent) {
4393
+ const copy = parent.ownerDocument.importNode(node, true);
4394
+ if (copy.nodeType === Node.ELEMENT_NODE) {
4395
+ const element = copy;
4396
+ const scripts = element.localName === "script" ? [element] : Array.from(element.querySelectorAll("script"));
4397
+ scripts.forEach((s2) => s2.setAttribute("data-prepr-morphed", ""));
4398
+ }
4399
+ return copy;
4400
+ }
4401
+
4402
+ // src/core/live-preview/html-live.ts
4403
+ var debug13 = createScopedLogger("live-preview:html");
4404
+ var COMPLETE_DOCUMENT = /<\/html>\s*$/i;
4405
+ var SYNC_DEBOUNCE_MS = 150;
4406
+ function startHtmlLivePreview(options = {}) {
4407
+ if (typeof window === "undefined" || window.self === window.top) {
4408
+ return { stop() {
4409
+ } };
4410
+ }
4411
+ const store = createLiveStore();
4412
+ const bridge = createLiveBridge(store, {
4413
+ allowedEditorOrigins: () => options.allowedEditorOrigins,
4414
+ strictMode: () => options.strictMode
4415
+ });
4416
+ bridge.start();
4417
+ let timer = null;
4418
+ let inFlight = false;
4419
+ let pending = null;
4420
+ let stopped = false;
4421
+ const render = async (log) => {
4422
+ inFlight = true;
4423
+ try {
4424
+ const response = await fetch(window.location.href, {
4425
+ method: log.length ? "POST" : "GET",
4426
+ headers: log.length ? { "Content-Type": "application/json", [HEADER_LIVE_RENDER]: "1" } : {},
4427
+ body: log.length ? JSON.stringify({ log }) : void 0,
4428
+ credentials: "same-origin",
4429
+ cache: "no-store"
4430
+ });
4431
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
4432
+ const html = await response.text();
4433
+ if (stopped) return;
4434
+ if (!COMPLETE_DOCUMENT.test(html)) {
4435
+ throw new Error("incomplete page; a component failed to render");
4436
+ }
4437
+ const next = new DOMParser().parseFromString(html, "text/html");
4438
+ if (next.title && next.title !== document.title)
4439
+ document.title = next.title;
4440
+ morphElement(document.body, next.body);
4441
+ } catch (error) {
4442
+ debug13.log("re-render failed", error);
4443
+ } finally {
4444
+ inFlight = false;
4445
+ }
4446
+ if (pending && !stopped) {
4447
+ const queued = pending;
4448
+ pending = null;
4449
+ void render(queued);
4450
+ }
4451
+ };
4452
+ const schedule = (log) => {
4453
+ if (timer) clearTimeout(timer);
4454
+ timer = setTimeout(() => {
4455
+ timer = null;
4456
+ if (inFlight) pending = log;
4457
+ else void render(log);
4458
+ }, SYNC_DEBOUNCE_MS);
4459
+ };
4460
+ const apply = options.apply ?? "server";
4461
+ const offLog = store.onLogChange((log) => {
4462
+ if (!log.length) return;
4463
+ if (apply === "server") {
4464
+ schedule(log);
4465
+ return;
4466
+ }
4467
+ applyPatchLogToDom(log);
4468
+ });
4469
+ const offInvalidate = store.onInvalidate(() => schedule([]));
4470
+ return {
4471
+ stop() {
4472
+ stopped = true;
4473
+ if (timer) clearTimeout(timer);
4474
+ offLog();
4475
+ offInvalidate();
4476
+ bridge.stop();
4477
+ }
4478
+ };
4479
+ }
4480
+
4481
+ // src/core/auto-start.ts
4482
+ var debug14 = createScopedLogger("auto");
4483
+ var PAYLOAD_SELECTOR = "script[data-prepr-toolbar-props]";
4484
+ function readPayload() {
4485
+ const element = document.querySelector(PAYLOAD_SELECTOR);
4486
+ if (!element?.textContent) return null;
4487
+ try {
4488
+ const payload = JSON.parse(element.textContent);
4489
+ return payload && typeof payload === "object" ? payload : null;
4490
+ } catch {
4491
+ debug14.warn("could not read the toolbar props");
4492
+ return null;
4493
+ }
4494
+ }
4495
+ function startPreprAuto() {
4496
+ if (typeof window === "undefined" || typeof document === "undefined") {
4497
+ return () => {
4498
+ };
4499
+ }
4500
+ const first = readPayload();
4501
+ if (!first) return () => {
4502
+ };
4503
+ const inEditor = window.self !== window.top;
4504
+ let payload = first;
4505
+ let preview = null;
4506
+ let live = null;
4507
+ let body = document.body;
4508
+ const start = () => {
4509
+ preview = createPreprPreview({
4510
+ props: payload.props,
4511
+ options: payload.options
4512
+ });
4513
+ body = document.body;
4514
+ watchBody();
4515
+ };
4516
+ if (payload.live !== false) {
4517
+ live = startHtmlLivePreview({
4518
+ allowedEditorOrigins: payload.options?.allowedEditorOrigins,
4519
+ strictMode: payload.options?.strictMode,
4520
+ apply: payload.live ?? "dom"
4521
+ });
4522
+ }
4523
+ const restart = () => {
4524
+ if (inEditor) {
4525
+ window.location.reload();
4526
+ return;
4527
+ }
4528
+ debug14.log("page swapped; starting the preview again");
4529
+ preview?.destroy();
4530
+ payload = readPayload() ?? payload;
4531
+ start();
4532
+ };
4533
+ const htmlObserver = new MutationObserver(() => {
4534
+ if (document.body && document.body !== body) restart();
4535
+ });
4536
+ htmlObserver.observe(document.documentElement, { childList: true });
4537
+ let bodyObserver = null;
4538
+ function watchBody() {
4539
+ bodyObserver?.disconnect();
4540
+ const toolbar = body.querySelector(":scope > prepr-toolbar");
4541
+ if (!toolbar) return;
4542
+ bodyObserver = new MutationObserver(() => {
4543
+ if (!toolbar.isConnected) restart();
4544
+ });
4545
+ bodyObserver.observe(body, { childList: true });
4546
+ }
4547
+ start();
4548
+ return () => {
4549
+ htmlObserver.disconnect();
4550
+ bodyObserver?.disconnect();
4551
+ preview?.destroy();
4552
+ live?.stop();
4553
+ };
4554
+ }
4555
+
4556
+ // src/auto.ts
4557
+ function boot() {
4558
+ if (window.__preprAutoStarted) return;
4559
+ window.__preprAutoStarted = true;
4560
+ startPreprAuto();
4561
+ }
4562
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
4563
+ if (document.readyState === "loading") {
4564
+ document.addEventListener("DOMContentLoaded", boot, { once: true });
4565
+ } else {
4566
+ boot();
4567
+ }
4568
+ }
4569
+ // Annotate the CommonJS export names for ESM import in node:
4570
+ 0 && (module.exports = {
4571
+ startPreprAuto
4572
+ });