@preprio/toolkit 0.4.3 → 0.5.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +416 -23
- package/dist/astro/index.cjs +1290 -1
- package/dist/astro/index.d.cts +47 -1
- package/dist/astro/index.d.ts +47 -1
- package/dist/astro/index.js +1297 -1
- package/dist/chunk-F46GJS6Y.js +26 -0
- package/dist/{chunk-H7VA7NGY.js → chunk-IDEC77LZ.js} +1480 -621
- package/dist/chunk-IPMB32AZ.js +246 -0
- package/dist/chunk-KD3GK6TO.js +1221 -0
- package/dist/chunk-S3VT4UWM.js +75 -0
- package/dist/chunk-TBBU3LDD.js +184 -0
- package/dist/chunk-URXSDJOU.js +356 -0
- package/dist/codegen/index.cjs +82 -0
- package/dist/codegen/index.d.cts +70 -0
- package/dist/codegen/index.d.ts +70 -0
- package/dist/codegen/index.js +64 -0
- package/dist/index.cjs +3412 -409
- package/dist/index.d.cts +287 -5
- package/dist/index.d.ts +287 -5
- package/dist/index.js +307 -144
- package/dist/live-preview-DLXGXRE5.js +18 -0
- package/dist/nextjs/components.cjs +1662 -388
- package/dist/nextjs/components.d.cts +1 -1
- package/dist/nextjs/components.d.ts +1 -1
- package/dist/nextjs/components.js +4 -1
- package/dist/nextjs/index.cjs +1181 -6
- package/dist/nextjs/index.d.cts +83 -3
- package/dist/nextjs/index.d.ts +83 -3
- package/dist/nextjs/index.js +1179 -7
- package/dist/nextjs/live-action.cjs +285 -0
- package/dist/nextjs/live-action.d.cts +12 -0
- package/dist/nextjs/live-action.d.ts +12 -0
- package/dist/nextjs/live-action.js +68 -0
- package/dist/nextjs/live.cjs +1899 -0
- package/dist/nextjs/live.d.cts +54 -0
- package/dist/nextjs/live.d.ts +54 -0
- package/dist/nextjs/live.js +268 -0
- package/dist/nuxt/chunk-BWPGO25E.js +340 -0
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/nuxt/live-preview-2RCU35W5.js +1189 -0
- package/dist/nuxt/live.cjs +1816 -0
- package/dist/nuxt/live.d.cts +43 -0
- package/dist/nuxt/live.d.ts +43 -0
- package/dist/nuxt/live.js +198 -0
- package/dist/{pixel-e1fUWl2Y.d.cts → pixel-CX422dCO.d.cts} +18 -3
- package/dist/{pixel-e1fUWl2Y.d.ts → pixel-CX422dCO.d.ts} +18 -3
- package/dist/react/components.cjs +1662 -388
- package/dist/react/components.d.cts +17 -2
- package/dist/react/components.d.ts +17 -2
- package/dist/react/components.js +1662 -388
- package/dist/sveltekit/chunk-BWPGO25E.js +340 -0
- package/dist/sveltekit/index.cjs +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/dist/sveltekit/live-preview-2RCU35W5.js +1189 -0
- package/dist/sveltekit/live.cjs +1830 -0
- package/dist/sveltekit/live.d.cts +59 -0
- package/dist/sveltekit/live.d.ts +59 -0
- package/dist/sveltekit/live.js +204 -0
- package/package.json +37 -11
- package/src/astro/PreprToolbar.astro +7 -1
|
@@ -1,133 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
var ALL_FEATURES_ENABLED = Object.freeze({
|
|
17
|
-
segments: true,
|
|
18
|
-
abTesting: true,
|
|
19
|
-
editMode: true
|
|
20
|
-
});
|
|
1
|
+
import {
|
|
2
|
+
ALL_FEATURES_ENABLED,
|
|
3
|
+
VERSION,
|
|
4
|
+
resolveFeatures
|
|
5
|
+
} from "./chunk-F46GJS6Y.js";
|
|
6
|
+
import {
|
|
7
|
+
createIframeBridge,
|
|
8
|
+
isLocale,
|
|
9
|
+
t
|
|
10
|
+
} from "./chunk-URXSDJOU.js";
|
|
11
|
+
import {
|
|
12
|
+
createScopedLogger,
|
|
13
|
+
initDebugLogger,
|
|
14
|
+
sendPreprEvent
|
|
15
|
+
} from "./chunk-S3VT4UWM.js";
|
|
21
16
|
|
|
22
17
|
// src/core/stega/clean.ts
|
|
23
18
|
import { vercelStegaClean, vercelStegaDecode } from "@vercel/stega";
|
|
24
|
-
|
|
25
|
-
// src/core/utils.ts
|
|
26
|
-
var trustedParentOrigin = null;
|
|
27
|
-
function setTrustedParentOrigin(origin) {
|
|
28
|
-
trustedParentOrigin = origin;
|
|
29
|
-
}
|
|
30
|
-
function sendPreprEvent(event, data, options) {
|
|
31
|
-
if (typeof window !== "undefined") {
|
|
32
|
-
const message = {
|
|
33
|
-
name: "prepr_preview_bar",
|
|
34
|
-
event,
|
|
35
|
-
...data
|
|
36
|
-
};
|
|
37
|
-
window.dispatchEvent(
|
|
38
|
-
new CustomEvent("prepr_preview_bar", { detail: message })
|
|
39
|
-
);
|
|
40
|
-
if (window.parent && window.parent !== window) {
|
|
41
|
-
if (trustedParentOrigin) {
|
|
42
|
-
window.parent.postMessage(message, trustedParentOrigin);
|
|
43
|
-
} else if (options?.allowUntrustedTarget) {
|
|
44
|
-
window.parent.postMessage(message, "*");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
var DebugLogger = class {
|
|
50
|
-
constructor(options) {
|
|
51
|
-
this.options = {
|
|
52
|
-
prefix: "[Prepr]",
|
|
53
|
-
...options
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
// A local `enabled` wins; otherwise defer to the global logger so scoped
|
|
57
|
-
// loggers created before initDebugLogger() still pick up the setting.
|
|
58
|
-
isEnabled() {
|
|
59
|
-
if (this.options.enabled !== void 0) {
|
|
60
|
-
return this.options.enabled;
|
|
61
|
-
}
|
|
62
|
-
return globalDebugLogger?.options?.enabled ?? false;
|
|
63
|
-
}
|
|
64
|
-
log(message, ...args) {
|
|
65
|
-
if (!this.isEnabled()) return;
|
|
66
|
-
const prefix = this.options.prefix;
|
|
67
|
-
console.log(`${prefix} ${message}`, ...args);
|
|
68
|
-
}
|
|
69
|
-
warn(message, ...args) {
|
|
70
|
-
if (!this.isEnabled()) return;
|
|
71
|
-
const prefix = this.options.prefix;
|
|
72
|
-
console.warn(`${prefix} ${message}`, ...args);
|
|
73
|
-
}
|
|
74
|
-
error(message, ...args) {
|
|
75
|
-
if (!this.isEnabled()) return;
|
|
76
|
-
const prefix = this.options.prefix;
|
|
77
|
-
console.error(`${prefix} ${message}`, ...args);
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
var globalDebugLogger = null;
|
|
81
|
-
function initDebugLogger(enabled = false) {
|
|
82
|
-
globalDebugLogger = new DebugLogger({ enabled });
|
|
83
|
-
}
|
|
84
|
-
function createScopedLogger(scopeName) {
|
|
85
|
-
return new DebugLogger({
|
|
86
|
-
prefix: `[Prepr][${scopeName}]`
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
function throttle(func, delay) {
|
|
90
|
-
let timeoutId = null;
|
|
91
|
-
let lastExecTime = 0;
|
|
92
|
-
const throttledFunc = ((...args) => {
|
|
93
|
-
const currentTime = Date.now();
|
|
94
|
-
const timeSinceLastExec = currentTime - lastExecTime;
|
|
95
|
-
if (timeSinceLastExec >= delay) {
|
|
96
|
-
func(...args);
|
|
97
|
-
lastExecTime = currentTime;
|
|
98
|
-
} else {
|
|
99
|
-
if (timeoutId) {
|
|
100
|
-
clearTimeout(timeoutId);
|
|
101
|
-
}
|
|
102
|
-
timeoutId = setTimeout(() => {
|
|
103
|
-
func(...args);
|
|
104
|
-
lastExecTime = Date.now();
|
|
105
|
-
timeoutId = null;
|
|
106
|
-
}, delay - timeSinceLastExec);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
throttledFunc.cancel = () => {
|
|
110
|
-
if (timeoutId) {
|
|
111
|
-
clearTimeout(timeoutId);
|
|
112
|
-
timeoutId = null;
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
return throttledFunc;
|
|
116
|
-
}
|
|
117
|
-
function createElementCache(query, ttl = 1e3) {
|
|
118
|
-
let cache = null;
|
|
119
|
-
let lastCacheTime = 0;
|
|
120
|
-
return () => {
|
|
121
|
-
const now = Date.now();
|
|
122
|
-
if (!cache || now - lastCacheTime > ttl) {
|
|
123
|
-
cache = document.querySelectorAll(query);
|
|
124
|
-
lastCacheTime = now;
|
|
125
|
-
}
|
|
126
|
-
return cache;
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// src/core/stega/clean.ts
|
|
131
19
|
var debug = createScopedLogger("stega:clean");
|
|
132
20
|
function stegaClean(text) {
|
|
133
21
|
if (!text) return text;
|
|
@@ -157,8 +45,442 @@ function decodeStega(str) {
|
|
|
157
45
|
return null;
|
|
158
46
|
}
|
|
159
47
|
|
|
48
|
+
// src/core/visual-editor/overlay.ts
|
|
49
|
+
var HOST_TAG = "prepr-visual-editor";
|
|
50
|
+
var SCROLL_SETTLE_MS = 120;
|
|
51
|
+
var LABEL_SPACE_PX = 22;
|
|
52
|
+
var BOX_PADDING_PX = 3;
|
|
53
|
+
var LABEL_MARGIN_PX = 4;
|
|
54
|
+
var PROBE_POINTS = [
|
|
55
|
+
[0.5, 0.5],
|
|
56
|
+
[0.15, 0.2],
|
|
57
|
+
[0.85, 0.2],
|
|
58
|
+
[0.15, 0.8],
|
|
59
|
+
[0.85, 0.8]
|
|
60
|
+
];
|
|
61
|
+
function overlapsBox(area, rect) {
|
|
62
|
+
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;
|
|
63
|
+
}
|
|
64
|
+
function overlaps(a2, b2) {
|
|
65
|
+
return a2.left < b2.right && b2.left < a2.right && a2.top < b2.bottom && b2.top < a2.bottom;
|
|
66
|
+
}
|
|
67
|
+
function coverOf(hit, target, x2, y2) {
|
|
68
|
+
let cover = hit.getBoundingClientRect();
|
|
69
|
+
for (let el = hit.parentElement; el && !el.contains(target) && el !== document.body; el = el.parentElement) {
|
|
70
|
+
const r2 = el.getBoundingClientRect();
|
|
71
|
+
if (x2 < r2.left || x2 >= r2.right || y2 < r2.top || y2 >= r2.bottom) break;
|
|
72
|
+
cover = r2;
|
|
73
|
+
}
|
|
74
|
+
return cover;
|
|
75
|
+
}
|
|
76
|
+
function mergeAreas(areas) {
|
|
77
|
+
const merged = areas.slice();
|
|
78
|
+
for (let i2 = 0; i2 < merged.length; i2++) {
|
|
79
|
+
for (let j2 = i2 + 1; j2 < merged.length; j2++) {
|
|
80
|
+
if (!overlaps(merged[i2], merged[j2])) continue;
|
|
81
|
+
merged[i2] = {
|
|
82
|
+
left: Math.min(merged[i2].left, merged[j2].left),
|
|
83
|
+
top: Math.min(merged[i2].top, merged[j2].top),
|
|
84
|
+
right: Math.max(merged[i2].right, merged[j2].right),
|
|
85
|
+
bottom: Math.max(merged[i2].bottom, merged[j2].bottom)
|
|
86
|
+
};
|
|
87
|
+
merged.splice(j2, 1);
|
|
88
|
+
j2 = i2;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return merged;
|
|
92
|
+
}
|
|
93
|
+
function findCovers(target, rect) {
|
|
94
|
+
const width = window.innerWidth;
|
|
95
|
+
const height = window.innerHeight;
|
|
96
|
+
const covers = [];
|
|
97
|
+
const seen = /* @__PURE__ */ new Set();
|
|
98
|
+
let probed = false;
|
|
99
|
+
let reached = false;
|
|
100
|
+
for (const [fx, fy] of PROBE_POINTS) {
|
|
101
|
+
const x2 = rect.left + rect.width * fx;
|
|
102
|
+
const y2 = rect.top + rect.height * fy;
|
|
103
|
+
if (x2 < 0 || y2 < 0 || x2 >= width || y2 >= height) continue;
|
|
104
|
+
probed = true;
|
|
105
|
+
const hit = document.elementFromPoint(x2, y2);
|
|
106
|
+
if (!hit || hit === target || target.contains(hit)) {
|
|
107
|
+
reached = true;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (seen.has(hit)) continue;
|
|
111
|
+
seen.add(hit);
|
|
112
|
+
if (covers.some(
|
|
113
|
+
(c2) => x2 >= c2.left && x2 < c2.right && y2 >= c2.top && y2 < c2.bottom
|
|
114
|
+
)) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
covers.push(coverOf(hit, target, x2, y2));
|
|
118
|
+
}
|
|
119
|
+
if (!probed) return [];
|
|
120
|
+
return reached ? mergeAreas(covers) : null;
|
|
121
|
+
}
|
|
122
|
+
function clipPath(x2, y2, covers) {
|
|
123
|
+
const far = 1e5;
|
|
124
|
+
const points = [
|
|
125
|
+
`${-far}px ${-far}px`,
|
|
126
|
+
`${far}px ${-far}px`,
|
|
127
|
+
`${far}px ${far}px`,
|
|
128
|
+
`${-far}px ${far}px`,
|
|
129
|
+
`${-far}px ${-far}px`
|
|
130
|
+
];
|
|
131
|
+
for (const c2 of covers) {
|
|
132
|
+
const l2 = c2.left - x2;
|
|
133
|
+
const t3 = c2.top - y2;
|
|
134
|
+
const r2 = c2.right - x2;
|
|
135
|
+
const b2 = c2.bottom - y2;
|
|
136
|
+
points.push(
|
|
137
|
+
`${l2}px ${t3}px`,
|
|
138
|
+
`${r2}px ${t3}px`,
|
|
139
|
+
`${r2}px ${b2}px`,
|
|
140
|
+
`${l2}px ${b2}px`,
|
|
141
|
+
`${l2}px ${t3}px`,
|
|
142
|
+
`${-far}px ${-far}px`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return `polygon(evenodd, ${points.join(", ")})`;
|
|
146
|
+
}
|
|
147
|
+
var STYLES = `
|
|
148
|
+
:host {
|
|
149
|
+
all: initial;
|
|
150
|
+
position: fixed;
|
|
151
|
+
inset: 0;
|
|
152
|
+
pointer-events: none;
|
|
153
|
+
z-index: 2147483646;
|
|
154
|
+
contain: strict;
|
|
155
|
+
}
|
|
156
|
+
.box {
|
|
157
|
+
position: absolute;
|
|
158
|
+
top: 0;
|
|
159
|
+
left: 0;
|
|
160
|
+
box-sizing: border-box;
|
|
161
|
+
border-radius: 6px;
|
|
162
|
+
opacity: 0;
|
|
163
|
+
will-change: transform, width, height;
|
|
164
|
+
transition:
|
|
165
|
+
transform 180ms cubic-bezier(0.2, 0.8, 0.2, 1),
|
|
166
|
+
width 180ms cubic-bezier(0.2, 0.8, 0.2, 1),
|
|
167
|
+
height 180ms cubic-bezier(0.2, 0.8, 0.2, 1),
|
|
168
|
+
opacity 140ms ease;
|
|
169
|
+
}
|
|
170
|
+
.box[data-visible] { opacity: 1; }
|
|
171
|
+
.box[data-instant], :host([data-scrolling]) .box {
|
|
172
|
+
transition: opacity 140ms ease;
|
|
173
|
+
}
|
|
174
|
+
.hover {
|
|
175
|
+
border: 1.5px solid rgba(79, 70, 229, 0.9);
|
|
176
|
+
background: rgba(79, 70, 229, 0.06);
|
|
177
|
+
}
|
|
178
|
+
.selected {
|
|
179
|
+
border: 2px solid #4f46e5;
|
|
180
|
+
box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.18);
|
|
181
|
+
}
|
|
182
|
+
.label {
|
|
183
|
+
position: absolute;
|
|
184
|
+
left: -2px;
|
|
185
|
+
bottom: 100%;
|
|
186
|
+
margin-bottom: 4px;
|
|
187
|
+
padding: 3px 7px;
|
|
188
|
+
border-radius: 5px;
|
|
189
|
+
background: #4f46e5;
|
|
190
|
+
color: #fff;
|
|
191
|
+
font: 500 11px/1.3 ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
192
|
+
letter-spacing: 0.01em;
|
|
193
|
+
white-space: nowrap;
|
|
194
|
+
display: flex;
|
|
195
|
+
max-width: 240px;
|
|
196
|
+
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.25);
|
|
197
|
+
}
|
|
198
|
+
.text {
|
|
199
|
+
min-width: 0;
|
|
200
|
+
overflow: hidden;
|
|
201
|
+
text-overflow: ellipsis;
|
|
202
|
+
}
|
|
203
|
+
.hover .label { background: rgba(79, 70, 229, 0.92); }
|
|
204
|
+
/* Content of another item than the one open in the editor: still clickable,
|
|
205
|
+
but visibly not part of the item being edited. */
|
|
206
|
+
.hover[data-item-kind='other'] {
|
|
207
|
+
border: 1.5px dashed #a5b4fc;
|
|
208
|
+
background: rgba(100, 116, 139, 0.05);
|
|
209
|
+
}
|
|
210
|
+
.hover[data-item-kind='other'] .label { background: #64748b; }
|
|
211
|
+
.hover[data-item-kind='referenced'] {
|
|
212
|
+
border: 1.5px solid #a5b4fc;
|
|
213
|
+
background: rgba(79, 70, 229, 0.03);
|
|
214
|
+
}
|
|
215
|
+
.hover[data-item-kind='referenced'] .label { background: #818cf8; }
|
|
216
|
+
.box[data-label-covered] .label { visibility: hidden; }
|
|
217
|
+
.box[data-label-inside] .label {
|
|
218
|
+
bottom: auto;
|
|
219
|
+
top: 2px;
|
|
220
|
+
left: 2px;
|
|
221
|
+
margin: 0;
|
|
222
|
+
}
|
|
223
|
+
/* A clickable hover label (edit mode on the live site). Only while shown, so
|
|
224
|
+
a fading box never leaves an invisible click target behind. */
|
|
225
|
+
:host([data-label-action]) .hover[data-visible] .label {
|
|
226
|
+
pointer-events: auto;
|
|
227
|
+
cursor: pointer;
|
|
228
|
+
}
|
|
229
|
+
:host([data-label-action]) .hover .label::after {
|
|
230
|
+
content: '\\2197';
|
|
231
|
+
margin-left: 5px;
|
|
232
|
+
}
|
|
233
|
+
:host([data-label-action]) .hover .label:hover { background: #4338ca; }
|
|
234
|
+
/* Bridges the gap between the label and its element, so the pointer can
|
|
235
|
+
travel from one to the other without the hover ending on the way. */
|
|
236
|
+
:host([data-label-action]) .hover .label::before {
|
|
237
|
+
content: '';
|
|
238
|
+
position: absolute;
|
|
239
|
+
left: 0;
|
|
240
|
+
right: 0;
|
|
241
|
+
top: 100%;
|
|
242
|
+
height: ${LABEL_MARGIN_PX + BOX_PADDING_PX + 2}px;
|
|
243
|
+
}
|
|
244
|
+
@media (prefers-reduced-motion: reduce) {
|
|
245
|
+
.box { transition: opacity 80ms linear; }
|
|
246
|
+
}
|
|
247
|
+
`;
|
|
248
|
+
var VisualEditorOverlay = class {
|
|
249
|
+
constructor(options = {}) {
|
|
250
|
+
this.host = null;
|
|
251
|
+
this.hoverBox = null;
|
|
252
|
+
this.selectedBox = null;
|
|
253
|
+
this.frame = null;
|
|
254
|
+
this.scrollTimeout = null;
|
|
255
|
+
this.resizeObserver = null;
|
|
256
|
+
this.onLabelClick = options.onLabelClick;
|
|
257
|
+
}
|
|
258
|
+
mount() {
|
|
259
|
+
if (this.host) return;
|
|
260
|
+
const host = document.createElement(HOST_TAG);
|
|
261
|
+
const shadow = host.attachShadow({ mode: "open" });
|
|
262
|
+
const style = document.createElement("style");
|
|
263
|
+
style.textContent = STYLES;
|
|
264
|
+
shadow.appendChild(style);
|
|
265
|
+
this.hoverBox = this.createBox(shadow, "hover");
|
|
266
|
+
this.selectedBox = this.createBox(shadow, "selected");
|
|
267
|
+
const onLabelClick = this.onLabelClick;
|
|
268
|
+
if (onLabelClick) {
|
|
269
|
+
host.setAttribute("data-label-action", "");
|
|
270
|
+
const hoverBox = this.hoverBox;
|
|
271
|
+
hoverBox.label.addEventListener("click", () => {
|
|
272
|
+
if (hoverBox.target) onLabelClick(hoverBox.target);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
document.documentElement.appendChild(host);
|
|
276
|
+
this.host = host;
|
|
277
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
278
|
+
this.resizeObserver = new ResizeObserver(() => this.schedule());
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
unmount() {
|
|
282
|
+
if (this.frame !== null) cancelAnimationFrame(this.frame);
|
|
283
|
+
if (this.scrollTimeout) clearTimeout(this.scrollTimeout);
|
|
284
|
+
this.frame = null;
|
|
285
|
+
this.scrollTimeout = null;
|
|
286
|
+
this.resizeObserver?.disconnect();
|
|
287
|
+
this.resizeObserver = null;
|
|
288
|
+
this.host?.remove();
|
|
289
|
+
this.host = null;
|
|
290
|
+
this.hoverBox = null;
|
|
291
|
+
this.selectedBox = null;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Whether a pointer event target is this chrome: events from inside the
|
|
295
|
+
* shadow root reach the page retargeted to its host.
|
|
296
|
+
*/
|
|
297
|
+
owns(node) {
|
|
298
|
+
return node !== null && node === this.host;
|
|
299
|
+
}
|
|
300
|
+
getHoverTarget() {
|
|
301
|
+
return this.hoverBox?.target ?? null;
|
|
302
|
+
}
|
|
303
|
+
getSelectedTarget() {
|
|
304
|
+
return this.selectedBox?.target ?? null;
|
|
305
|
+
}
|
|
306
|
+
setHover(target, label, options = {}) {
|
|
307
|
+
if (target) {
|
|
308
|
+
this.hoverBox?.root.setAttribute(
|
|
309
|
+
"data-item-kind",
|
|
310
|
+
options.kind ?? "current"
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
this.retarget(this.hoverBox, target, label);
|
|
314
|
+
}
|
|
315
|
+
setSelected(target, label) {
|
|
316
|
+
this.retarget(this.selectedBox, target, label);
|
|
317
|
+
}
|
|
318
|
+
/** Call on every scroll; positions follow in the next frame, untransitioned. */
|
|
319
|
+
onScroll() {
|
|
320
|
+
if (!this.host) return;
|
|
321
|
+
this.host.setAttribute("data-scrolling", "");
|
|
322
|
+
if (this.scrollTimeout) clearTimeout(this.scrollTimeout);
|
|
323
|
+
this.scrollTimeout = setTimeout(() => {
|
|
324
|
+
this.host?.removeAttribute("data-scrolling");
|
|
325
|
+
this.scrollTimeout = null;
|
|
326
|
+
}, SCROLL_SETTLE_MS);
|
|
327
|
+
this.schedule();
|
|
328
|
+
}
|
|
329
|
+
/** Re-measure both boxes in the next animation frame. */
|
|
330
|
+
schedule() {
|
|
331
|
+
if (this.frame !== null || !this.host) return;
|
|
332
|
+
this.frame = requestAnimationFrame(() => {
|
|
333
|
+
this.frame = null;
|
|
334
|
+
this.render();
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
createBox(shadow, kind) {
|
|
338
|
+
const root = document.createElement("div");
|
|
339
|
+
root.className = `box ${kind}`;
|
|
340
|
+
const label = document.createElement("div");
|
|
341
|
+
label.className = "label";
|
|
342
|
+
const text = document.createElement("span");
|
|
343
|
+
text.className = "text";
|
|
344
|
+
label.appendChild(text);
|
|
345
|
+
root.appendChild(label);
|
|
346
|
+
shadow.appendChild(root);
|
|
347
|
+
return { root, label, text, target: null };
|
|
348
|
+
}
|
|
349
|
+
retarget(box, target, label) {
|
|
350
|
+
if (!box || box.target === target) return;
|
|
351
|
+
const previous = box.target;
|
|
352
|
+
if (previous) this.resizeObserver?.unobserve(previous);
|
|
353
|
+
box.target = target;
|
|
354
|
+
if (target) {
|
|
355
|
+
this.resizeObserver?.observe(target);
|
|
356
|
+
box.text.textContent = label;
|
|
357
|
+
if (!box.root.hasAttribute("data-visible")) {
|
|
358
|
+
box.root.setAttribute("data-instant", "");
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
this.schedule();
|
|
362
|
+
}
|
|
363
|
+
render() {
|
|
364
|
+
const hover = this.hoverBox ? this.measure(this.hoverBox) : null;
|
|
365
|
+
const selected = this.selectedBox ? this.measure(this.selectedBox) : null;
|
|
366
|
+
if (this.hoverBox) this.paint(this.hoverBox, hover, selected);
|
|
367
|
+
if (this.selectedBox) this.paint(this.selectedBox, selected, hover);
|
|
368
|
+
}
|
|
369
|
+
measure(box) {
|
|
370
|
+
const target = box.target;
|
|
371
|
+
if (!target) return null;
|
|
372
|
+
if (!target.isConnected) {
|
|
373
|
+
this.resizeObserver?.unobserve(target);
|
|
374
|
+
box.target = null;
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
const rect = target.getBoundingClientRect();
|
|
378
|
+
if (rect.width === 0 && rect.height === 0) return null;
|
|
379
|
+
const covers = findCovers(target, rect);
|
|
380
|
+
if (!covers) return null;
|
|
381
|
+
return {
|
|
382
|
+
rect,
|
|
383
|
+
covers,
|
|
384
|
+
labelWidth: covers.length ? box.label.offsetWidth : 0,
|
|
385
|
+
labelHeight: covers.length ? box.label.offsetHeight : 0
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
paint(box, measurement, other = null) {
|
|
389
|
+
const root = box.root;
|
|
390
|
+
if (!measurement) {
|
|
391
|
+
root.removeAttribute("data-visible");
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const { rect, covers } = measurement;
|
|
395
|
+
const x2 = rect.left - BOX_PADDING_PX;
|
|
396
|
+
const y2 = rect.top - BOX_PADDING_PX;
|
|
397
|
+
const labelAbove = {
|
|
398
|
+
left: x2 - 2,
|
|
399
|
+
top: y2 - LABEL_SPACE_PX,
|
|
400
|
+
right: x2 - 2 + (measurement.labelWidth || Math.min(240, rect.width)),
|
|
401
|
+
bottom: y2
|
|
402
|
+
};
|
|
403
|
+
const labelInside = y2 < LABEL_SPACE_PX || other !== null && other.rect !== rect && overlapsBox(labelAbove, other.rect);
|
|
404
|
+
root.style.transform = `translate3d(${x2}px, ${y2}px, 0)`;
|
|
405
|
+
root.style.width = `${rect.width + BOX_PADDING_PX * 2}px`;
|
|
406
|
+
root.style.height = `${rect.height + BOX_PADDING_PX * 2}px`;
|
|
407
|
+
root.toggleAttribute("data-label-inside", labelInside);
|
|
408
|
+
root.style.clipPath = covers.length ? clipPath(x2, y2, covers) : "";
|
|
409
|
+
const labelLeft = labelInside ? x2 + 2 : x2 - 2;
|
|
410
|
+
const labelTop = labelInside ? y2 + 2 : y2 - LABEL_MARGIN_PX - measurement.labelHeight;
|
|
411
|
+
const label = {
|
|
412
|
+
left: labelLeft,
|
|
413
|
+
top: labelTop,
|
|
414
|
+
right: labelLeft + measurement.labelWidth,
|
|
415
|
+
bottom: labelTop + measurement.labelHeight
|
|
416
|
+
};
|
|
417
|
+
root.toggleAttribute(
|
|
418
|
+
"data-label-covered",
|
|
419
|
+
covers.some((c2) => overlaps(c2, label))
|
|
420
|
+
);
|
|
421
|
+
if (root.hasAttribute("data-instant")) {
|
|
422
|
+
root.setAttribute("data-visible", "");
|
|
423
|
+
requestAnimationFrame(() => root.removeAttribute("data-instant"));
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
root.setAttribute("data-visible", "");
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
// src/core/visual-editor/field-path.ts
|
|
431
|
+
var INDEX_SEGMENT = /^\d+$/;
|
|
432
|
+
var WORD_SEPARATORS = /[_-]+/g;
|
|
433
|
+
function normalizeFieldPath(path) {
|
|
434
|
+
return path.split(".").map(
|
|
435
|
+
(segment) => INDEX_SEGMENT.test(segment) ? String(Number.parseInt(segment, 10)) : segment
|
|
436
|
+
).join(".");
|
|
437
|
+
}
|
|
438
|
+
var GENERIC_LEAVES = /* @__PURE__ */ new Set(["value", "text", "body", "content", "label"]);
|
|
439
|
+
function humanize(name) {
|
|
440
|
+
const words = name.replace(WORD_SEPARATORS, " ").trim();
|
|
441
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
442
|
+
}
|
|
443
|
+
function fieldLabel(path, locale = "en") {
|
|
444
|
+
if (!path) return t("visualEditor.edit", locale);
|
|
445
|
+
const segments = path.split(".").filter((s2) => s2 && s2 !== "items" && !INDEX_SEGMENT.test(s2));
|
|
446
|
+
const name = segments[segments.length - 1];
|
|
447
|
+
if (!name) return t("visualEditor.edit", locale);
|
|
448
|
+
const parent = segments[segments.length - 2];
|
|
449
|
+
if (parent && GENERIC_LEAVES.has(name)) {
|
|
450
|
+
return `${humanize(parent)} \u203A ${humanize(name)}`;
|
|
451
|
+
}
|
|
452
|
+
return humanize(name);
|
|
453
|
+
}
|
|
454
|
+
function findFieldElement(lookup) {
|
|
455
|
+
if (!lookup.field) return null;
|
|
456
|
+
const candidates = document.querySelectorAll(
|
|
457
|
+
"[data-prepr-encoded]"
|
|
458
|
+
);
|
|
459
|
+
if (lookup.entryId) {
|
|
460
|
+
for (const candidate of candidates) {
|
|
461
|
+
if (candidate.getAttribute("data-prepr-entry-id") === lookup.entryId) {
|
|
462
|
+
return candidate;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
for (const path of [lookup.field, lookup.fieldById]) {
|
|
467
|
+
if (!path) continue;
|
|
468
|
+
const wanted = normalizeFieldPath(path);
|
|
469
|
+
for (const candidate of candidates) {
|
|
470
|
+
const field = candidate.getAttribute("data-prepr-field");
|
|
471
|
+
if (!field || normalizeFieldPath(field) !== wanted) continue;
|
|
472
|
+
if (lookup.id && candidate.getAttribute("data-prepr-id") !== lookup.id) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
return candidate;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
|
|
160
481
|
// src/core/stega/dom.ts
|
|
161
482
|
var IGNORED_ANCESTORS = "script, style, noscript";
|
|
483
|
+
var AUTO_ENTRY_ATTR = "data-prepr-entry-auto";
|
|
162
484
|
function isIgnoredTextNode(node) {
|
|
163
485
|
if (node.parentElement?.closest(IGNORED_ANCESTORS)) return true;
|
|
164
486
|
return !node.textContent?.trim();
|
|
@@ -186,10 +508,56 @@ function isRenderedElement(element) {
|
|
|
186
508
|
if (!style) return true;
|
|
187
509
|
return style.visibility !== "hidden" && style.display !== "none";
|
|
188
510
|
}
|
|
511
|
+
function parseEditHref(href) {
|
|
512
|
+
try {
|
|
513
|
+
const url = new URL(href, window.location.origin);
|
|
514
|
+
return {
|
|
515
|
+
id: url.pathname.split("/").pop() || void 0,
|
|
516
|
+
field: url.searchParams.get("field") || void 0,
|
|
517
|
+
locale: url.searchParams.get("locale") || void 0,
|
|
518
|
+
// Added by the toolkit's `annotateEditLinks`, not by Prepr.
|
|
519
|
+
entry: url.searchParams.get("entry") || void 0
|
|
520
|
+
};
|
|
521
|
+
} catch {
|
|
522
|
+
return {};
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function setOrRemove(element, name, value) {
|
|
526
|
+
if (value) {
|
|
527
|
+
element.setAttribute(name, value);
|
|
528
|
+
} else {
|
|
529
|
+
element.removeAttribute(name);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
189
532
|
function tagEncodedElement(element, decoded) {
|
|
533
|
+
if (isSiteTagged(element)) return false;
|
|
190
534
|
element.setAttribute("data-prepr-encoded", "");
|
|
191
535
|
element.setAttribute("data-prepr-href", decoded.href);
|
|
192
536
|
element.setAttribute("data-prepr-origin", decoded.origin);
|
|
537
|
+
const { id, field, locale, entry } = parseEditHref(decoded.href);
|
|
538
|
+
setOrRemove(element, "data-prepr-id", id);
|
|
539
|
+
const fieldHint = element.getAttribute("data-prepr-edit-target")?.trim() || void 0;
|
|
540
|
+
setOrRemove(element, "data-prepr-field", field ?? fieldHint);
|
|
541
|
+
setOrRemove(element, "data-prepr-locale", locale);
|
|
542
|
+
const siteEntry = element.hasAttribute("data-prepr-entry-id") && !element.hasAttribute(AUTO_ENTRY_ATTR);
|
|
543
|
+
if (!siteEntry) {
|
|
544
|
+
setOrRemove(element, "data-prepr-entry-id", entry);
|
|
545
|
+
setOrRemove(element, AUTO_ENTRY_ATTR, entry && "true");
|
|
546
|
+
}
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
function isSiteTagged(element) {
|
|
550
|
+
return element.hasAttribute("data-prepr-encoded") && !element.hasAttribute("data-prepr-href");
|
|
551
|
+
}
|
|
552
|
+
function readEditPayload(element) {
|
|
553
|
+
return {
|
|
554
|
+
href: element.getAttribute("data-prepr-href") ?? "",
|
|
555
|
+
origin: element.getAttribute("data-prepr-origin") ?? "",
|
|
556
|
+
id: element.getAttribute("data-prepr-id") ?? void 0,
|
|
557
|
+
field: element.getAttribute("data-prepr-field") ?? void 0,
|
|
558
|
+
locale: element.getAttribute("data-prepr-locale") ?? void 0,
|
|
559
|
+
entryId: element.getAttribute("data-prepr-entry-id") || void 0
|
|
560
|
+
};
|
|
193
561
|
}
|
|
194
562
|
|
|
195
563
|
// src/core/stega/elements.ts
|
|
@@ -281,231 +649,22 @@ var StegaElements = class {
|
|
|
281
649
|
attributeFilter: ["class", "style", "hidden", "open", "aria-expanded"]
|
|
282
650
|
});
|
|
283
651
|
}
|
|
284
|
-
/**
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
652
|
+
/**
|
|
653
|
+
* Stops watching for new content. Tags stay on their elements: the page's
|
|
654
|
+
* stega characters are stripped once they are read, so a tag removed here
|
|
655
|
+
* could never be rebuilt when edit mode is turned back on.
|
|
656
|
+
*/
|
|
657
|
+
disconnect() {
|
|
289
658
|
if (this.observer) {
|
|
290
659
|
this.observer.disconnect();
|
|
291
660
|
this.observer = null;
|
|
292
661
|
}
|
|
293
|
-
document.querySelectorAll("[data-prepr-encoded]").forEach((element) => {
|
|
294
|
-
element.removeAttribute("data-prepr-encoded");
|
|
295
|
-
element.removeAttribute("data-prepr-href");
|
|
296
|
-
element.removeAttribute("data-prepr-origin");
|
|
297
|
-
element.classList.remove("prepr-overlay-active");
|
|
298
|
-
});
|
|
299
662
|
this.elements = void 0;
|
|
300
663
|
}
|
|
301
664
|
};
|
|
302
665
|
|
|
303
|
-
// src/core/stega/overlay.ts
|
|
304
|
-
var debug3 = createScopedLogger("stega:overlay");
|
|
305
|
-
var StegaOverlay = class {
|
|
306
|
-
constructor(onEdit) {
|
|
307
|
-
this.overlay = null;
|
|
308
|
-
this.tooltip = null;
|
|
309
|
-
this.hideTimeout = null;
|
|
310
|
-
this.currentElement = null;
|
|
311
|
-
this.onEdit = onEdit;
|
|
312
|
-
}
|
|
313
|
-
create() {
|
|
314
|
-
const overlay = document.createElement("div");
|
|
315
|
-
overlay.className = "prepr-overlay";
|
|
316
|
-
overlay.style.display = "none";
|
|
317
|
-
const tooltip = document.createElement("div");
|
|
318
|
-
tooltip.className = "prepr-tooltip";
|
|
319
|
-
tooltip.style.display = "none";
|
|
320
|
-
document.body.appendChild(overlay);
|
|
321
|
-
document.body.appendChild(tooltip);
|
|
322
|
-
this.overlay = overlay;
|
|
323
|
-
this.tooltip = tooltip;
|
|
324
|
-
return { overlay, tooltip };
|
|
325
|
-
}
|
|
326
|
-
getTooltip() {
|
|
327
|
-
return this.tooltip;
|
|
328
|
-
}
|
|
329
|
-
hasCurrentElement() {
|
|
330
|
-
return this.currentElement !== null;
|
|
331
|
-
}
|
|
332
|
-
clearHideTimeout() {
|
|
333
|
-
if (this.hideTimeout) {
|
|
334
|
-
clearTimeout(this.hideTimeout);
|
|
335
|
-
this.hideTimeout = null;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
show(element) {
|
|
339
|
-
if (!this.overlay || !this.tooltip) return;
|
|
340
|
-
this.clearHideTimeout();
|
|
341
|
-
if (this.currentElement && this.currentElement !== element) {
|
|
342
|
-
this.currentElement.classList.remove("prepr-overlay-active");
|
|
343
|
-
}
|
|
344
|
-
const rect = element.getBoundingClientRect();
|
|
345
|
-
const href = element.getAttribute("data-prepr-href");
|
|
346
|
-
const origin = element.getAttribute("data-prepr-origin");
|
|
347
|
-
const id = element.getAttribute("data-prepr-id") ?? void 0;
|
|
348
|
-
const field = element.getAttribute("data-prepr-field") ?? void 0;
|
|
349
|
-
debug3.log("showing overlay", { href, origin });
|
|
350
|
-
const overlay = this.overlay;
|
|
351
|
-
overlay.style.display = "block";
|
|
352
|
-
overlay.style.top = `${rect.top + window.scrollY - 2}px`;
|
|
353
|
-
overlay.style.left = `${rect.left + window.scrollX - 4}px`;
|
|
354
|
-
overlay.style.width = `${rect.width + 8}px`;
|
|
355
|
-
overlay.style.height = `${rect.height + 4}px`;
|
|
356
|
-
const tooltip = this.tooltip;
|
|
357
|
-
if (href && origin) {
|
|
358
|
-
const MIN_WIDTH_FOR_TEXT = 80;
|
|
359
|
-
const isCompact = rect.width < MIN_WIDTH_FOR_TEXT;
|
|
360
|
-
tooltip.textContent = isCompact ? "\u2197" : `${origin} \u2197`;
|
|
361
|
-
tooltip.style.display = "block";
|
|
362
|
-
tooltip.style.minWidth = isCompact ? "auto" : "80px";
|
|
363
|
-
requestAnimationFrame(() => {
|
|
364
|
-
let top = rect.top + window.scrollY - tooltip.clientHeight - 2;
|
|
365
|
-
let left = rect.right + 4 - tooltip.clientWidth;
|
|
366
|
-
const minTop = window.scrollY + 4;
|
|
367
|
-
const maxTop = window.scrollY + window.innerHeight - tooltip.clientHeight - 4;
|
|
368
|
-
const minLeft = window.scrollX + 4;
|
|
369
|
-
const maxLeft = window.scrollX + window.innerWidth - tooltip.clientWidth - 4;
|
|
370
|
-
const below = top < minTop;
|
|
371
|
-
if (below) {
|
|
372
|
-
top = rect.bottom + window.scrollY + 2;
|
|
373
|
-
}
|
|
374
|
-
top = Math.max(minTop, Math.min(top, maxTop));
|
|
375
|
-
left = Math.max(minLeft, Math.min(left, maxLeft));
|
|
376
|
-
tooltip.dataset.preprPlacement = below ? "below" : "above";
|
|
377
|
-
tooltip.style.top = `${top}px`;
|
|
378
|
-
tooltip.style.left = `${left}px`;
|
|
379
|
-
});
|
|
380
|
-
tooltip.onclick = () => {
|
|
381
|
-
this.onEdit({ href, origin, id, field });
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
this.currentElement = element;
|
|
385
|
-
element.classList.add("prepr-overlay-active");
|
|
386
|
-
}
|
|
387
|
-
hideImmediate() {
|
|
388
|
-
this.clearHideTimeout();
|
|
389
|
-
if (this.overlay) this.overlay.style.display = "none";
|
|
390
|
-
if (this.tooltip) this.tooltip.style.display = "none";
|
|
391
|
-
if (this.currentElement) {
|
|
392
|
-
this.currentElement.classList.remove("prepr-overlay-active");
|
|
393
|
-
this.currentElement = null;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
hide() {
|
|
397
|
-
if (!this.overlay || !this.tooltip) return;
|
|
398
|
-
this.clearHideTimeout();
|
|
399
|
-
this.hideTimeout = setTimeout(() => this.hideImmediate(), 100);
|
|
400
|
-
}
|
|
401
|
-
cleanup() {
|
|
402
|
-
this.clearHideTimeout();
|
|
403
|
-
if (this.overlay) {
|
|
404
|
-
this.overlay.style.display = "none";
|
|
405
|
-
this.overlay.parentNode?.removeChild(this.overlay);
|
|
406
|
-
this.overlay = null;
|
|
407
|
-
}
|
|
408
|
-
if (this.tooltip) {
|
|
409
|
-
this.tooltip.style.display = "none";
|
|
410
|
-
this.tooltip.parentNode?.removeChild(this.tooltip);
|
|
411
|
-
this.tooltip = null;
|
|
412
|
-
}
|
|
413
|
-
if (this.currentElement) {
|
|
414
|
-
this.currentElement.classList.remove("prepr-overlay-active");
|
|
415
|
-
this.currentElement = null;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
|
|
420
|
-
// src/core/stega/proximity.ts
|
|
421
|
-
var debug4 = createScopedLogger("stega:proximity");
|
|
422
|
-
var StegaProximity = class {
|
|
423
|
-
constructor() {
|
|
424
|
-
this.highlighted = /* @__PURE__ */ new Set();
|
|
425
|
-
this.visible = /* @__PURE__ */ new Set();
|
|
426
|
-
this.observer = null;
|
|
427
|
-
this.getEncodedElements = createElementCache(
|
|
428
|
-
"[data-prepr-encoded]",
|
|
429
|
-
200
|
|
430
|
-
);
|
|
431
|
-
}
|
|
432
|
-
/** Call after the encoded element set changes — rebuilds the observer. */
|
|
433
|
-
refreshObserving() {
|
|
434
|
-
try {
|
|
435
|
-
if (typeof IntersectionObserver === "undefined") return;
|
|
436
|
-
if (this.observer) {
|
|
437
|
-
this.observer.disconnect();
|
|
438
|
-
this.observer = null;
|
|
439
|
-
}
|
|
440
|
-
this.visible = /* @__PURE__ */ new Set();
|
|
441
|
-
this.observer = new IntersectionObserver(
|
|
442
|
-
(entries) => {
|
|
443
|
-
entries.forEach((entry) => {
|
|
444
|
-
const el = entry.target;
|
|
445
|
-
if (entry.isIntersecting) {
|
|
446
|
-
this.visible.add(el);
|
|
447
|
-
} else {
|
|
448
|
-
this.visible.delete(el);
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
},
|
|
452
|
-
{ root: null, rootMargin: "0px", threshold: 0 }
|
|
453
|
-
);
|
|
454
|
-
const nodes = this.getEncodedElements();
|
|
455
|
-
nodes.forEach((el) => this.observer.observe(el));
|
|
456
|
-
debug4.log("observing", nodes.length, "encoded elements");
|
|
457
|
-
} catch (error) {
|
|
458
|
-
debug4.log("error setting up IntersectionObserver", error);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
stopObserving() {
|
|
462
|
-
if (this.observer) {
|
|
463
|
-
this.observer.disconnect();
|
|
464
|
-
this.observer = null;
|
|
465
|
-
this.visible.clear();
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
updateElementGradients(cursorX, cursorY) {
|
|
469
|
-
const candidates = this.visible.size > 0 ? Array.from(this.visible) : Array.from(this.getEncodedElements());
|
|
470
|
-
const newHighlighted = /* @__PURE__ */ new Set();
|
|
471
|
-
candidates.forEach((element) => {
|
|
472
|
-
const rect = element.getBoundingClientRect();
|
|
473
|
-
const distance = Math.min(
|
|
474
|
-
Math.abs(cursorX - rect.left),
|
|
475
|
-
Math.abs(cursorX - rect.right),
|
|
476
|
-
Math.abs(cursorY - rect.top),
|
|
477
|
-
Math.abs(cursorY - rect.bottom)
|
|
478
|
-
);
|
|
479
|
-
if (distance < 150) {
|
|
480
|
-
const relativeX = cursorX - rect.left;
|
|
481
|
-
const relativeY = cursorY - rect.top;
|
|
482
|
-
element.style.setProperty("--cursor-x", `${relativeX}px`);
|
|
483
|
-
element.style.setProperty("--cursor-y", `${relativeY}px`);
|
|
484
|
-
const baseGradientSize = Math.max(
|
|
485
|
-
150,
|
|
486
|
-
Math.max(rect.width, rect.height) * 1.1
|
|
487
|
-
);
|
|
488
|
-
const distanceScale = Math.max(0, (400 - distance) / 400);
|
|
489
|
-
const gradientSize = baseGradientSize * distanceScale;
|
|
490
|
-
element.style.setProperty("--gradient-size", `${gradientSize}px`);
|
|
491
|
-
element.classList.add("prepr-proximity-highlight");
|
|
492
|
-
newHighlighted.add(element);
|
|
493
|
-
} else {
|
|
494
|
-
element.classList.remove("prepr-proximity-highlight");
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
this.highlighted = newHighlighted;
|
|
498
|
-
}
|
|
499
|
-
clearAllHighlights() {
|
|
500
|
-
this.highlighted.forEach(
|
|
501
|
-
(element) => element.classList.remove("prepr-proximity-highlight")
|
|
502
|
-
);
|
|
503
|
-
this.highlighted.clear();
|
|
504
|
-
}
|
|
505
|
-
};
|
|
506
|
-
|
|
507
666
|
// src/core/stega/stega.generated.ts
|
|
508
|
-
var STEGA_STYLES = '
|
|
667
|
+
var STEGA_STYLES = '@property --prepr-presence{syntax:"<number>";inherits:true;initial-value:1}[data-prepr-encoded]{outline:1px dashed rgb(79 70 229/calc(.3 * var(--prepr-presence,1)));outline-offset:2px}';
|
|
509
668
|
|
|
510
669
|
// src/core/stega/styles.ts
|
|
511
670
|
var STEGA_STYLE_MARKER = "data-prepr-stega";
|
|
@@ -525,45 +684,80 @@ function removeStegaStyles() {
|
|
|
525
684
|
}
|
|
526
685
|
|
|
527
686
|
// src/core/stega/scan.ts
|
|
528
|
-
var
|
|
687
|
+
var debug3 = createScopedLogger("stega:scan");
|
|
688
|
+
var ENCODED_SELECTOR = "[data-prepr-encoded]";
|
|
689
|
+
var PRESENCE_FADE_MS = 400;
|
|
529
690
|
var EDITOR_MODE_STYLES = "[data-prepr-encoded]{cursor:pointer}";
|
|
691
|
+
function fadeInPresence() {
|
|
692
|
+
const root = document.documentElement;
|
|
693
|
+
if (typeof root.animate !== "function") return;
|
|
694
|
+
if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return;
|
|
695
|
+
root.animate(
|
|
696
|
+
{ "--prepr-presence": ["0", "1"] },
|
|
697
|
+
{ duration: PRESENCE_FADE_MS, easing: "ease-out" }
|
|
698
|
+
);
|
|
699
|
+
}
|
|
530
700
|
function createStegaController(opts) {
|
|
531
701
|
const tooltipEnabled = opts.tooltip ?? true;
|
|
532
|
-
const
|
|
533
|
-
const proximity = new StegaProximity();
|
|
702
|
+
const locale = opts.locale ?? "en";
|
|
534
703
|
const elements = new StegaElements();
|
|
704
|
+
const overlay = new VisualEditorOverlay({
|
|
705
|
+
onLabelClick: (target) => opts.onEdit(readEditPayload(target))
|
|
706
|
+
});
|
|
535
707
|
let initialized = false;
|
|
536
|
-
let
|
|
537
|
-
|
|
538
|
-
|
|
708
|
+
let pointerFrame = null;
|
|
709
|
+
let pointerTarget = null;
|
|
710
|
+
let pointerX = 0;
|
|
711
|
+
let pointerY = 0;
|
|
712
|
+
let hitTestPending = false;
|
|
713
|
+
const updateHover = () => {
|
|
714
|
+
pointerFrame = null;
|
|
715
|
+
if (hitTestPending) {
|
|
716
|
+
hitTestPending = false;
|
|
717
|
+
pointerTarget = document.elementFromPoint(pointerX, pointerY);
|
|
718
|
+
}
|
|
719
|
+
if (overlay.owns(pointerTarget)) return;
|
|
720
|
+
const encoded = pointerTarget instanceof Element ? pointerTarget.closest(ENCODED_SELECTOR) : null;
|
|
721
|
+
overlay.setHover(
|
|
722
|
+
encoded,
|
|
723
|
+
encoded ? fieldLabel(encoded.getAttribute("data-prepr-field"), locale) : ""
|
|
724
|
+
);
|
|
539
725
|
};
|
|
540
|
-
const
|
|
541
|
-
if (
|
|
542
|
-
|
|
726
|
+
const scheduleHover = () => {
|
|
727
|
+
if (pointerFrame === null) {
|
|
728
|
+
pointerFrame = requestAnimationFrame(updateHover);
|
|
543
729
|
}
|
|
544
730
|
};
|
|
731
|
+
const handlePointer = (e2) => {
|
|
732
|
+
pointerTarget = e2.target;
|
|
733
|
+
pointerX = e2.clientX;
|
|
734
|
+
pointerY = e2.clientY;
|
|
735
|
+
hitTestPending = false;
|
|
736
|
+
scheduleHover();
|
|
737
|
+
};
|
|
738
|
+
const handlePointerLeave = () => {
|
|
739
|
+
pointerTarget = null;
|
|
740
|
+
hitTestPending = false;
|
|
741
|
+
overlay.setHover(null, "");
|
|
742
|
+
};
|
|
545
743
|
const handleScroll = () => {
|
|
546
|
-
overlay.
|
|
547
|
-
|
|
744
|
+
overlay.onScroll();
|
|
745
|
+
if (pointerTarget === null) return;
|
|
746
|
+
hitTestPending = true;
|
|
747
|
+
scheduleHover();
|
|
548
748
|
};
|
|
749
|
+
const handleResize = () => overlay.schedule();
|
|
549
750
|
const handleClick = (e2) => {
|
|
550
751
|
const target = e2.target;
|
|
551
|
-
const encoded = target?.closest(
|
|
552
|
-
"[data-prepr-encoded]"
|
|
553
|
-
);
|
|
752
|
+
const encoded = target?.closest(ENCODED_SELECTOR);
|
|
554
753
|
if (!encoded) return;
|
|
555
754
|
e2.preventDefault();
|
|
556
755
|
e2.stopPropagation();
|
|
557
|
-
opts.onEdit(
|
|
558
|
-
href: encoded.getAttribute("data-prepr-href") ?? "",
|
|
559
|
-
origin: encoded.getAttribute("data-prepr-origin") ?? "",
|
|
560
|
-
id: encoded.getAttribute("data-prepr-id") ?? void 0,
|
|
561
|
-
field: encoded.getAttribute("data-prepr-field") ?? void 0
|
|
562
|
-
});
|
|
756
|
+
opts.onEdit(readEditPayload(encoded));
|
|
563
757
|
};
|
|
564
758
|
const start = () => {
|
|
565
759
|
if (initialized) {
|
|
566
|
-
|
|
760
|
+
debug3.log("already initialized, skipping setup");
|
|
567
761
|
return;
|
|
568
762
|
}
|
|
569
763
|
if (!tooltipEnabled) {
|
|
@@ -573,102 +767,95 @@ function createStegaController(opts) {
|
|
|
573
767
|
});
|
|
574
768
|
document.addEventListener("click", handleClick, { capture: true });
|
|
575
769
|
initialized = true;
|
|
576
|
-
|
|
770
|
+
debug3.log("stega controller started (headless)");
|
|
577
771
|
return;
|
|
578
772
|
}
|
|
579
773
|
injectStegaStyles();
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
tooltip.addEventListener("mouseleave", handleTooltipMouseLeave);
|
|
774
|
+
fadeInPresence();
|
|
775
|
+
overlay.mount();
|
|
583
776
|
elements.scanDocument(true);
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
const target = mouseEvent.target;
|
|
589
|
-
if (!target) return;
|
|
590
|
-
if (target.closest(".prepr-tooltip")) return;
|
|
591
|
-
proximity.updateElementGradients(mouseEvent.clientX, mouseEvent.clientY);
|
|
592
|
-
const encoded = target.closest("[data-prepr-encoded]");
|
|
593
|
-
if (encoded) {
|
|
594
|
-
overlay.show(encoded);
|
|
595
|
-
} else {
|
|
596
|
-
overlay.hide();
|
|
597
|
-
}
|
|
598
|
-
}, 16);
|
|
599
|
-
document.addEventListener("mousemove", throttledMouseMove, {
|
|
600
|
-
passive: true
|
|
777
|
+
elements.setupMutationObserver(() => {
|
|
778
|
+
if (pointerTarget === null) return;
|
|
779
|
+
hitTestPending = true;
|
|
780
|
+
scheduleHover();
|
|
601
781
|
});
|
|
782
|
+
document.addEventListener("pointermove", handlePointer, { passive: true });
|
|
783
|
+
document.addEventListener("pointerdown", handlePointer, { passive: true });
|
|
784
|
+
document.documentElement.addEventListener(
|
|
785
|
+
"pointerleave",
|
|
786
|
+
handlePointerLeave
|
|
787
|
+
);
|
|
602
788
|
window.addEventListener("scroll", handleScroll, {
|
|
603
789
|
capture: true,
|
|
604
790
|
passive: true
|
|
605
791
|
});
|
|
792
|
+
window.addEventListener("resize", handleResize, { passive: true });
|
|
606
793
|
initialized = true;
|
|
607
|
-
|
|
794
|
+
debug3.log("stega controller started");
|
|
608
795
|
};
|
|
609
796
|
const stop = () => {
|
|
610
797
|
if (!initialized) return;
|
|
798
|
+
initialized = false;
|
|
611
799
|
if (!tooltipEnabled) {
|
|
612
800
|
document.removeEventListener("click", handleClick, { capture: true });
|
|
613
|
-
elements.
|
|
801
|
+
elements.disconnect();
|
|
614
802
|
removeStegaStyles();
|
|
615
|
-
|
|
616
|
-
debug5.log("stega controller stopped (editor mode)");
|
|
803
|
+
debug3.log("stega controller stopped (headless)");
|
|
617
804
|
return;
|
|
618
805
|
}
|
|
619
|
-
if (
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
806
|
+
if (pointerFrame !== null) cancelAnimationFrame(pointerFrame);
|
|
807
|
+
pointerFrame = null;
|
|
808
|
+
pointerTarget = null;
|
|
809
|
+
hitTestPending = false;
|
|
810
|
+
document.removeEventListener("pointermove", handlePointer);
|
|
811
|
+
document.removeEventListener("pointerdown", handlePointer);
|
|
812
|
+
document.documentElement.removeEventListener(
|
|
813
|
+
"pointerleave",
|
|
814
|
+
handlePointerLeave
|
|
815
|
+
);
|
|
624
816
|
window.removeEventListener("scroll", handleScroll, { capture: true });
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
tooltip.removeEventListener("mouseleave", handleTooltipMouseLeave);
|
|
629
|
-
}
|
|
630
|
-
overlay.cleanup();
|
|
631
|
-
proximity.clearAllHighlights();
|
|
632
|
-
proximity.stopObserving();
|
|
633
|
-
elements.cleanup();
|
|
817
|
+
window.removeEventListener("resize", handleResize);
|
|
818
|
+
overlay.unmount();
|
|
819
|
+
elements.disconnect();
|
|
634
820
|
removeStegaStyles();
|
|
635
|
-
|
|
636
|
-
debug5.log("stega controller stopped");
|
|
821
|
+
debug3.log("stega controller stopped");
|
|
637
822
|
};
|
|
638
823
|
return { start, stop };
|
|
639
824
|
}
|
|
640
825
|
|
|
641
826
|
// src/core/stega/auto-clean.ts
|
|
642
827
|
import { vercelStegaSplit } from "@vercel/stega";
|
|
643
|
-
var
|
|
828
|
+
var debug4 = createScopedLogger("stega:auto-clean");
|
|
829
|
+
var cleanedNodes = /* @__PURE__ */ new WeakMap();
|
|
644
830
|
function createStegaAutoClean(options) {
|
|
645
831
|
const stripText = options?.enabled ?? true;
|
|
646
832
|
let observer = null;
|
|
647
833
|
let processing = false;
|
|
648
|
-
let cleaned = /* @__PURE__ */ new WeakMap();
|
|
649
834
|
let pendingHidden = /* @__PURE__ */ new Set();
|
|
650
835
|
let pendingDirty = /* @__PURE__ */ new Set();
|
|
651
836
|
let debounceTimeout = null;
|
|
652
837
|
function cleanTextNode(textNode) {
|
|
653
838
|
if (isIgnoredTextNode(textNode)) return false;
|
|
654
839
|
const textContent = textNode.textContent;
|
|
655
|
-
const info =
|
|
840
|
+
const info = cleanedNodes.get(textNode);
|
|
656
841
|
const settled = stripText ? info?.cleaned : info?.original;
|
|
657
842
|
if (info && textContent === settled) {
|
|
658
843
|
if (!info.decoded) return false;
|
|
659
844
|
const shown = resolveEditTarget(textNode);
|
|
660
|
-
if (!shown)
|
|
845
|
+
if (!shown) {
|
|
846
|
+
pendingHidden.add(textNode);
|
|
847
|
+
return false;
|
|
848
|
+
}
|
|
661
849
|
pendingHidden.delete(textNode);
|
|
662
850
|
if (shown.hasAttribute("data-prepr-encoded")) return false;
|
|
663
|
-
tagEncodedElement(shown, info.decoded);
|
|
664
|
-
return true;
|
|
851
|
+
return tagEncodedElement(shown, info.decoded);
|
|
665
852
|
}
|
|
666
853
|
try {
|
|
667
854
|
const { cleaned: stripped, encoded } = vercelStegaSplit(textContent);
|
|
668
855
|
if (!encoded || stripped === textContent) return false;
|
|
669
856
|
const decoded = decodeStega(textContent);
|
|
670
857
|
if (!decoded?.href && !stripText) return false;
|
|
671
|
-
|
|
858
|
+
cleanedNodes.set(textNode, {
|
|
672
859
|
original: textContent,
|
|
673
860
|
cleaned: stripped,
|
|
674
861
|
decoded: decoded?.href ? decoded : null
|
|
@@ -678,12 +865,11 @@ function createStegaAutoClean(options) {
|
|
|
678
865
|
const target = resolveEditTarget(textNode);
|
|
679
866
|
if (target) {
|
|
680
867
|
pendingHidden.delete(textNode);
|
|
681
|
-
tagEncodedElement(target, decoded);
|
|
682
|
-
return true;
|
|
868
|
+
return tagEncodedElement(target, decoded);
|
|
683
869
|
}
|
|
684
870
|
pendingHidden.add(textNode);
|
|
685
871
|
} catch (error) {
|
|
686
|
-
|
|
872
|
+
debug4.log("error cleaning text node", error);
|
|
687
873
|
}
|
|
688
874
|
return false;
|
|
689
875
|
}
|
|
@@ -710,7 +896,7 @@ function createStegaAutoClean(options) {
|
|
|
710
896
|
}
|
|
711
897
|
if (mutation.type === "characterData" && mutation.target.nodeType === Node.TEXT_NODE) {
|
|
712
898
|
const textNode = mutation.target;
|
|
713
|
-
const info =
|
|
899
|
+
const info = cleanedNodes.get(textNode);
|
|
714
900
|
const text = textNode.textContent ?? "";
|
|
715
901
|
const settled = stripText ? info?.cleaned : info?.original;
|
|
716
902
|
if (text !== settled && vercelStegaSplit(text).encoded) {
|
|
@@ -753,7 +939,16 @@ function createStegaAutoClean(options) {
|
|
|
753
939
|
retryPendingHidden();
|
|
754
940
|
}, 50);
|
|
755
941
|
}
|
|
942
|
+
let resizeTimeout = null;
|
|
943
|
+
function handleResize() {
|
|
944
|
+
if (pendingHidden.size === 0 || resizeTimeout) return;
|
|
945
|
+
resizeTimeout = setTimeout(() => {
|
|
946
|
+
resizeTimeout = null;
|
|
947
|
+
retryPendingHidden();
|
|
948
|
+
}, 100);
|
|
949
|
+
}
|
|
756
950
|
function setupObserver() {
|
|
951
|
+
window.addEventListener("resize", handleResize, { passive: true });
|
|
757
952
|
observer = new MutationObserver(handleMutations);
|
|
758
953
|
observer.observe(document.body, {
|
|
759
954
|
childList: true,
|
|
@@ -769,25 +964,61 @@ function createStegaAutoClean(options) {
|
|
|
769
964
|
if (observer || typeof window === "undefined") return;
|
|
770
965
|
scanAndClean();
|
|
771
966
|
setupObserver();
|
|
772
|
-
|
|
967
|
+
debug4.log("stega auto-clean started");
|
|
773
968
|
}
|
|
774
969
|
function stop() {
|
|
775
970
|
if (debounceTimeout) {
|
|
776
971
|
clearTimeout(debounceTimeout);
|
|
777
972
|
debounceTimeout = null;
|
|
778
973
|
}
|
|
974
|
+
if (resizeTimeout) {
|
|
975
|
+
clearTimeout(resizeTimeout);
|
|
976
|
+
resizeTimeout = null;
|
|
977
|
+
}
|
|
779
978
|
if (observer) {
|
|
780
979
|
observer.disconnect();
|
|
781
980
|
observer = null;
|
|
981
|
+
window.removeEventListener("resize", handleResize);
|
|
782
982
|
}
|
|
783
|
-
cleaned = /* @__PURE__ */ new WeakMap();
|
|
784
983
|
pendingHidden = /* @__PURE__ */ new Set();
|
|
785
984
|
pendingDirty = /* @__PURE__ */ new Set();
|
|
786
|
-
|
|
985
|
+
debug4.log("stega auto-clean stopped");
|
|
787
986
|
}
|
|
788
987
|
return { start, stop };
|
|
789
988
|
}
|
|
790
989
|
|
|
990
|
+
// src/core/stega/scroll-to-field.ts
|
|
991
|
+
var debug5 = createScopedLogger("stega:scroll");
|
|
992
|
+
var FLASH_DURATION_MS = 1200;
|
|
993
|
+
var flashTimeout = null;
|
|
994
|
+
function scrollToField(request) {
|
|
995
|
+
const { field, id } = request;
|
|
996
|
+
if (!field) return false;
|
|
997
|
+
const candidates = document.querySelectorAll(
|
|
998
|
+
"[data-prepr-encoded]"
|
|
999
|
+
);
|
|
1000
|
+
let target = null;
|
|
1001
|
+
for (const candidate of candidates) {
|
|
1002
|
+
if (candidate.getAttribute("data-prepr-field") !== field) continue;
|
|
1003
|
+
if (id && candidate.getAttribute("data-prepr-id") !== id) continue;
|
|
1004
|
+
target = candidate;
|
|
1005
|
+
break;
|
|
1006
|
+
}
|
|
1007
|
+
if (!target) {
|
|
1008
|
+
debug5.log("no element found for field", field);
|
|
1009
|
+
return false;
|
|
1010
|
+
}
|
|
1011
|
+
target.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
1012
|
+
if (flashTimeout) clearTimeout(flashTimeout);
|
|
1013
|
+
document.querySelectorAll(".prepr-overlay-active").forEach((el) => el.classList.remove("prepr-overlay-active"));
|
|
1014
|
+
target.classList.add("prepr-overlay-active");
|
|
1015
|
+
flashTimeout = setTimeout(() => {
|
|
1016
|
+
target.classList.remove("prepr-overlay-active");
|
|
1017
|
+
flashTimeout = null;
|
|
1018
|
+
}, FLASH_DURATION_MS);
|
|
1019
|
+
return true;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
791
1022
|
// src/core/store.ts
|
|
792
1023
|
var DEFAULT_STATE = {
|
|
793
1024
|
locale: "en",
|
|
@@ -824,11 +1055,11 @@ function createToolbarStore(initial = {}) {
|
|
|
824
1055
|
return { get, set, subscribe };
|
|
825
1056
|
}
|
|
826
1057
|
|
|
827
|
-
// ../../node_modules/.pnpm/preact@10.29.
|
|
1058
|
+
// ../../node_modules/.pnpm/preact@10.29.8/node_modules/preact/dist/preact.mjs
|
|
828
1059
|
var n;
|
|
829
1060
|
var l;
|
|
830
1061
|
var u;
|
|
831
|
-
var
|
|
1062
|
+
var t2;
|
|
832
1063
|
var i;
|
|
833
1064
|
var r;
|
|
834
1065
|
var o;
|
|
@@ -895,8 +1126,8 @@ function H() {
|
|
|
895
1126
|
}
|
|
896
1127
|
}
|
|
897
1128
|
function L(n2, l2, u3, t3, i2, r2, o2, e2, f3, c2, a2) {
|
|
898
|
-
var s2, h2, p2, v2, y2, _2, g2
|
|
899
|
-
for (f3 = T(u3, l2,
|
|
1129
|
+
var s2, h2, p2, v2, y2, _2, g2 = t3 && t3.__k || w, m2 = l2.length;
|
|
1130
|
+
for (f3 = T(u3, l2, g2, f3, m2), s2 = 0; s2 < m2; s2++) null != (p2 = u3.__k[s2]) && (h2 = -1 != p2.__i && g2[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), 4 & p2.__u ? (f3 = j(p2, f3, n2), h2.__e && (h2.__e = null)) : "function" == typeof p2.type && void 0 !== _2 ? f3 = _2 : v2 && (f3 = v2.nextSibling), p2.__u &= -7);
|
|
900
1131
|
return u3.__e = y2, f3;
|
|
901
1132
|
}
|
|
902
1133
|
function T(n2, l2, u3, t3, i2) {
|
|
@@ -905,13 +1136,13 @@ function T(n2, l2, u3, t3, i2) {
|
|
|
905
1136
|
if (s2) for (r2 = 0; r2 < a2; r2++) null != (e2 = u3[r2]) && 0 == (2 & e2.__u) && (e2.__e == t3 && (t3 = $(e2)), K(e2, e2));
|
|
906
1137
|
return t3;
|
|
907
1138
|
}
|
|
908
|
-
function j(n2, l2, u3
|
|
909
|
-
var
|
|
1139
|
+
function j(n2, l2, u3) {
|
|
1140
|
+
var t3, i2;
|
|
910
1141
|
if ("function" == typeof n2.type) {
|
|
911
|
-
for (
|
|
1142
|
+
for (t3 = n2.__k, i2 = 0; t3 && i2 < t3.length; i2++) t3[i2] && (t3[i2].__ = n2, l2 = j(t3[i2], l2, u3));
|
|
912
1143
|
return l2;
|
|
913
1144
|
}
|
|
914
|
-
n2.__e != l2 && (
|
|
1145
|
+
n2.__e != l2 && (l2 && n2.type && !l2.parentNode && (l2 = $(n2)), l2 = u3.insertBefore(n2.__e, l2 || null));
|
|
915
1146
|
do {
|
|
916
1147
|
l2 = l2 && l2.nextSibling;
|
|
917
1148
|
} while (null != l2 && 8 == l2.nodeType);
|
|
@@ -957,35 +1188,35 @@ function V(n2) {
|
|
|
957
1188
|
};
|
|
958
1189
|
}
|
|
959
1190
|
function q(n2, u3, t3, i2, r2, o2, e2, f3, c2, a2) {
|
|
960
|
-
var s2, h2, p2, v2, y2, d2, _2, k2, x2, M,
|
|
1191
|
+
var s2, h2, p2, v2, y2, d2, _2, k2, x2, M, I2, P2, A2, H2, T2, j2, F = u3.type;
|
|
961
1192
|
if (void 0 !== u3.constructor) return null;
|
|
962
1193
|
128 & t3.__u && (c2 = !!(32 & t3.__u), o2 = [f3 = u3.__e = t3.__e]), (s2 = l.__b) && s2(u3);
|
|
963
|
-
n: if ("function" == typeof
|
|
1194
|
+
n: if ("function" == typeof F) {
|
|
964
1195
|
h2 = e2.length;
|
|
965
1196
|
try {
|
|
966
|
-
if (x2 = u3.props, M =
|
|
1197
|
+
if (x2 = u3.props, M = F.prototype && F.prototype.render, I2 = (s2 = F.contextType) && i2[s2.__c], P2 = s2 ? I2 ? I2.props.value : s2.__ : i2, t3.__c ? k2 = (p2 = u3.__c = t3.__c).__ = p2.__E : (M ? u3.__c = p2 = new F(x2, P2) : (u3.__c = p2 = new C(x2, P2), p2.constructor = F, p2.render = Q), I2 && I2.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 != F.getDerivedStateFromProps && (p2.__s == p2.state && (p2.__s = m({}, p2.__s)), m(p2.__s, F.getDerivedStateFromProps(x2, p2.__s))), y2 = p2.props, d2 = p2.state, p2.__v = u3, v2) M && null == F.getDerivedStateFromProps && null != p2.componentWillMount && p2.componentWillMount(), M && null != p2.componentDidMount && p2.__h.push(p2.componentDidMount);
|
|
967
1198
|
else {
|
|
968
|
-
if (M && null ==
|
|
1199
|
+
if (M && null == F.getDerivedStateFromProps && x2 !== y2 && null != p2.componentWillReceiveProps && p2.componentWillReceiveProps(x2, P2), u3.__v == t3.__v || !p2.__e && null != p2.shouldComponentUpdate && false === p2.shouldComponentUpdate(x2, p2.__s, P2)) {
|
|
969
1200
|
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) {
|
|
970
1201
|
n3 && (n3.__ = u3);
|
|
971
|
-
}), w.push.apply(p2.__h, p2._sb), p2._sb = [], p2.__h.length && e2.push(p2);
|
|
1202
|
+
}), w.push.apply(p2.__h, p2._sb), p2._sb = [], p2.__h.length && e2.push(p2), f3 = $(t3);
|
|
972
1203
|
break n;
|
|
973
1204
|
}
|
|
974
|
-
null != p2.componentWillUpdate && p2.componentWillUpdate(x2, p2.__s,
|
|
1205
|
+
null != p2.componentWillUpdate && p2.componentWillUpdate(x2, p2.__s, P2), M && null != p2.componentDidUpdate && p2.__h.push(function() {
|
|
975
1206
|
p2.componentDidUpdate(y2, d2, _2);
|
|
976
1207
|
});
|
|
977
1208
|
}
|
|
978
|
-
if (p2.context =
|
|
1209
|
+
if (p2.context = P2, p2.props = x2, p2.__P = n2, p2.__e = false, A2 = l.__r, H2 = 0, M) p2.state = p2.__s, p2.__d = false, A2 && A2(u3), s2 = p2.render(p2.props, p2.state, p2.context), w.push.apply(p2.__h, p2._sb), p2._sb = [];
|
|
979
1210
|
else do {
|
|
980
|
-
p2.__d = false,
|
|
981
|
-
} while (p2.__d && ++
|
|
982
|
-
p2.state = p2.__s, null != p2.getChildContext && (i2 = m(m({}, i2), p2.getChildContext())), M && !v2 && null != p2.getSnapshotBeforeUpdate && (_2 = p2.getSnapshotBeforeUpdate(y2, d2)),
|
|
1211
|
+
p2.__d = false, A2 && A2(u3), s2 = p2.render(p2.props, p2.state, p2.context), p2.state = p2.__s;
|
|
1212
|
+
} while (p2.__d && ++H2 < 25);
|
|
1213
|
+
p2.state = p2.__s, null != p2.getChildContext && (i2 = m(m({}, i2), p2.getChildContext())), M && !v2 && null != p2.getSnapshotBeforeUpdate && (_2 = p2.getSnapshotBeforeUpdate(y2, d2)), T2 = null != s2 && s2.type === S && null == s2.key ? E(s2.props.children) : s2, f3 = L(n2, g(T2) ? T2 : [T2], 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);
|
|
983
1214
|
} catch (n3) {
|
|
984
1215
|
if (e2.length = h2, u3.__v = null, c2 || null != o2) {
|
|
985
1216
|
if (n3.then) {
|
|
986
1217
|
for (u3.__u |= c2 ? 160 : 128; f3 && 8 == f3.nodeType && f3.nextSibling; ) f3 = f3.nextSibling;
|
|
987
1218
|
null != o2 && (o2[o2.indexOf(f3)] = null), u3.__e = f3;
|
|
988
|
-
} else if (null != o2) for (
|
|
1219
|
+
} else if (null != o2) for (j2 = o2.length; j2--; ) b(o2[j2]);
|
|
989
1220
|
} else u3.__e = t3.__e;
|
|
990
1221
|
null == u3.__k && (u3.__k = t3.__k || []), n3.then || B(u3), l.__e(n3, u3, t3);
|
|
991
1222
|
}
|
|
@@ -1070,7 +1301,7 @@ n = w.slice, l = { __e: function(n2, l2, u3, t3) {
|
|
|
1070
1301
|
n2 = l3;
|
|
1071
1302
|
}
|
|
1072
1303
|
throw n2;
|
|
1073
|
-
} }, u = 0,
|
|
1304
|
+
} }, u = 0, t2 = function(n2) {
|
|
1074
1305
|
return null != n2 && void 0 === n2.constructor;
|
|
1075
1306
|
}, C.prototype.setState = function(n2, l2) {
|
|
1076
1307
|
var u3;
|
|
@@ -1106,9 +1337,9 @@ var CLOSE_ICON_SVG = `<svg width="10" height="10" viewBox="0 0 10 10" fill="none
|
|
|
1106
1337
|
</svg>`;
|
|
1107
1338
|
|
|
1108
1339
|
// src/core/ui/toolbar.generated.ts
|
|
1109
|
-
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
|
|
1340
|
+
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: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}}";
|
|
1110
1341
|
|
|
1111
|
-
// ../../node_modules/.pnpm/preact@10.29.
|
|
1342
|
+
// ../../node_modules/.pnpm/preact@10.29.8/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
|
|
1112
1343
|
var f2 = 0;
|
|
1113
1344
|
function u2(e2, t3, n2, o2, i2, u3) {
|
|
1114
1345
|
t3 || (t3 = {});
|
|
@@ -1812,6 +2043,7 @@ var PARAM_SEGMENT = "prepr_preview_segment";
|
|
|
1812
2043
|
var PARAM_VARIANT = "prepr_preview_ab";
|
|
1813
2044
|
var PARAM_HIDE_BAR = "prepr_hide_bar";
|
|
1814
2045
|
var ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
|
|
2046
|
+
var HEADER_LIVE_RENDER = "x-prepr-live";
|
|
1815
2047
|
|
|
1816
2048
|
// src/core/cookies.ts
|
|
1817
2049
|
function getCookie(name) {
|
|
@@ -1853,156 +2085,6 @@ function crossSiteCookieOptions() {
|
|
|
1853
2085
|
return { sameSite: "None", secure: true };
|
|
1854
2086
|
}
|
|
1855
2087
|
|
|
1856
|
-
// src/core/locales/en.json
|
|
1857
|
-
var en_default = {
|
|
1858
|
-
common: {
|
|
1859
|
-
viewingAs: "Viewing as:",
|
|
1860
|
-
user: "User",
|
|
1861
|
-
off: "Off",
|
|
1862
|
-
on: "On",
|
|
1863
|
-
reset: "Reset",
|
|
1864
|
-
toolbar: "Toolbar"
|
|
1865
|
-
},
|
|
1866
|
-
adaptiveContent: {
|
|
1867
|
-
adaptiveContent: "Adaptive content",
|
|
1868
|
-
enablePreview: "Preview mode",
|
|
1869
|
-
segment: "Segment",
|
|
1870
|
-
ABVariant: "A/B variant",
|
|
1871
|
-
chooseSegment: "Choose segment",
|
|
1872
|
-
searchSegments: "Search segments",
|
|
1873
|
-
none: "No segments",
|
|
1874
|
-
allOtherUsers: "All other users",
|
|
1875
|
-
offDescription: "View the site as a real user (use cookies)",
|
|
1876
|
-
onDescription: "Use the toolbar to simulate segments and A/B variants"
|
|
1877
|
-
},
|
|
1878
|
-
editingTools: {
|
|
1879
|
-
editingTools: "Editing tools",
|
|
1880
|
-
editMode: "Edit mode",
|
|
1881
|
-
ariaCloseEditMode: "Close edit mode"
|
|
1882
|
-
}
|
|
1883
|
-
};
|
|
1884
|
-
|
|
1885
|
-
// src/core/locales/nl.json
|
|
1886
|
-
var nl_default = {
|
|
1887
|
-
common: {
|
|
1888
|
-
viewingAs: "Bekijken als:",
|
|
1889
|
-
user: "Gebruiker",
|
|
1890
|
-
off: "Uit",
|
|
1891
|
-
on: "Aan",
|
|
1892
|
-
reset: "Resetten",
|
|
1893
|
-
toolbar: "Toolbar"
|
|
1894
|
-
},
|
|
1895
|
-
adaptiveContent: {
|
|
1896
|
-
adaptiveContent: "Adaptieve inhoud",
|
|
1897
|
-
enablePreview: "Preview modus",
|
|
1898
|
-
segment: "Segment",
|
|
1899
|
-
ABVariant: "A/B-variant",
|
|
1900
|
-
chooseSegment: "Kies segment",
|
|
1901
|
-
searchSegments: "Zoek segmenten",
|
|
1902
|
-
none: "Geen segmenten",
|
|
1903
|
-
allOtherUsers: "Alle andere gebruikers",
|
|
1904
|
-
offDescription: "Bekijk de site als een echte gebruiker (gebruik cookies)",
|
|
1905
|
-
onDescription: "Gebruik de werkbalk om segmenten en A/B-varianten te simuleren"
|
|
1906
|
-
},
|
|
1907
|
-
editingTools: {
|
|
1908
|
-
editingTools: "Editing Tools",
|
|
1909
|
-
editMode: "Edit mode",
|
|
1910
|
-
ariaCloseEditMode: "Edit mode sluiten"
|
|
1911
|
-
}
|
|
1912
|
-
};
|
|
1913
|
-
|
|
1914
|
-
// src/core/i18n.ts
|
|
1915
|
-
var dictionaries = {
|
|
1916
|
-
en: en_default,
|
|
1917
|
-
nl: nl_default
|
|
1918
|
-
};
|
|
1919
|
-
var LOCALES = Object.keys(dictionaries);
|
|
1920
|
-
function isLocale(value) {
|
|
1921
|
-
return typeof value === "string" && value in dictionaries;
|
|
1922
|
-
}
|
|
1923
|
-
function getDict(locale) {
|
|
1924
|
-
return isLocale(locale) ? dictionaries[locale] : dictionaries.en;
|
|
1925
|
-
}
|
|
1926
|
-
function getFromPath(obj, path) {
|
|
1927
|
-
return path.split(".").reduce(
|
|
1928
|
-
(acc, key) => acc && typeof acc === "object" ? acc[key] : void 0,
|
|
1929
|
-
obj
|
|
1930
|
-
);
|
|
1931
|
-
}
|
|
1932
|
-
function format(message, vars) {
|
|
1933
|
-
if (!vars) return message;
|
|
1934
|
-
return Object.keys(vars).reduce(
|
|
1935
|
-
(acc, k2) => acc.replace(new RegExp(`\\{${k2}\\}`, "g"), String(vars[k2])),
|
|
1936
|
-
message
|
|
1937
|
-
);
|
|
1938
|
-
}
|
|
1939
|
-
function t2(key, locale, vars) {
|
|
1940
|
-
const dict = getDict(locale);
|
|
1941
|
-
const msg = getFromPath(dict, key);
|
|
1942
|
-
if (typeof msg === "string") return format(msg, vars);
|
|
1943
|
-
return key;
|
|
1944
|
-
}
|
|
1945
|
-
|
|
1946
|
-
// src/core/iframe-bridge.ts
|
|
1947
|
-
var EDITOR_BASE_DOMAIN = "prepr.io";
|
|
1948
|
-
function isAllowedEditorOrigin(origin, allowed) {
|
|
1949
|
-
if (allowed) return allowed.includes(origin);
|
|
1950
|
-
let url;
|
|
1951
|
-
try {
|
|
1952
|
-
url = new URL(origin);
|
|
1953
|
-
} catch {
|
|
1954
|
-
return false;
|
|
1955
|
-
}
|
|
1956
|
-
if (url.protocol !== "https:" || url.port !== "") return false;
|
|
1957
|
-
const suffix = `.${EDITOR_BASE_DOMAIN}`;
|
|
1958
|
-
if (!url.hostname.endsWith(suffix)) return false;
|
|
1959
|
-
const label = url.hostname.slice(0, -suffix.length);
|
|
1960
|
-
return label.length > 0 && !label.includes(".");
|
|
1961
|
-
}
|
|
1962
|
-
function createIframeBridge(store, options = {}) {
|
|
1963
|
-
const allowedOrigins = options.allowedEditorOrigins;
|
|
1964
|
-
let parentOrigin = null;
|
|
1965
|
-
const onKeyDown = (event) => {
|
|
1966
|
-
const key = event.key.toLowerCase();
|
|
1967
|
-
const blocked = (event.ctrlKey || event.metaKey) && ["s", "p", "l"].includes(key);
|
|
1968
|
-
if (blocked) event.preventDefault();
|
|
1969
|
-
};
|
|
1970
|
-
const onMessage = (evt) => {
|
|
1971
|
-
const data = evt?.data;
|
|
1972
|
-
if (data?.event === "prepr:initVE" && !parentOrigin) {
|
|
1973
|
-
if (!isAllowedEditorOrigin(evt.origin, allowedOrigins)) return;
|
|
1974
|
-
parentOrigin = evt.origin;
|
|
1975
|
-
setTrustedParentOrigin(parentOrigin);
|
|
1976
|
-
if (data.scrollPosition != null) {
|
|
1977
|
-
const top = data.scrollPosition;
|
|
1978
|
-
setTimeout(() => window.scrollTo(0, top), 1);
|
|
1979
|
-
}
|
|
1980
|
-
store?.set({ previewMode: true, editMode: data.editMode ?? true });
|
|
1981
|
-
}
|
|
1982
|
-
if (!parentOrigin || evt.origin !== parentOrigin) return;
|
|
1983
|
-
if (data?.event === "prepr:getScrollPosition") {
|
|
1984
|
-
const currentScrollY = window.scrollY || document.documentElement.scrollTop;
|
|
1985
|
-
sendPreprEvent("getScrollPosition", { value: currentScrollY });
|
|
1986
|
-
}
|
|
1987
|
-
};
|
|
1988
|
-
return {
|
|
1989
|
-
start() {
|
|
1990
|
-
const features = store?.get().features;
|
|
1991
|
-
sendPreprEvent("loaded", features ? { features } : void 0, {
|
|
1992
|
-
allowUntrustedTarget: true
|
|
1993
|
-
});
|
|
1994
|
-
window.addEventListener("keydown", onKeyDown);
|
|
1995
|
-
window.addEventListener("message", onMessage);
|
|
1996
|
-
},
|
|
1997
|
-
stop() {
|
|
1998
|
-
window.removeEventListener("keydown", onKeyDown);
|
|
1999
|
-
window.removeEventListener("message", onMessage);
|
|
2000
|
-
parentOrigin = null;
|
|
2001
|
-
setTrustedParentOrigin(null);
|
|
2002
|
-
}
|
|
2003
|
-
};
|
|
2004
|
-
}
|
|
2005
|
-
|
|
2006
2088
|
// src/core/toolbar-change-handler.ts
|
|
2007
2089
|
function cookieOpts() {
|
|
2008
2090
|
return {
|
|
@@ -2101,8 +2183,742 @@ function splitPath(full) {
|
|
|
2101
2183
|
return [full.slice(0, index), full.slice(index + 1)];
|
|
2102
2184
|
}
|
|
2103
2185
|
|
|
2186
|
+
// src/core/visual-editor/asset-images.ts
|
|
2187
|
+
var MAX_URL_LENGTH = 4096;
|
|
2188
|
+
var MIN_KEY_SEGMENTS = 2;
|
|
2189
|
+
var TRANSFORM_OPTION = /^[a-z]{1,3}_[\w.-]*$/i;
|
|
2190
|
+
var FORMAT_PLACEHOLDER = "{format}";
|
|
2191
|
+
var PROXY_PARAMS = ["url", "href", "src", "image"];
|
|
2192
|
+
var ABSOLUTE_HTTP = /^https?:\/\//i;
|
|
2193
|
+
var SOURCE_URL_ATTRIBUTES = ["src", "data-src"];
|
|
2194
|
+
var SOURCE_SET_ATTRIBUTES = ["srcset", "data-srcset"];
|
|
2195
|
+
var ASSET_ATTR = "data-prepr-asset";
|
|
2196
|
+
var ASSET_SOURCE_ATTRIBUTES = [
|
|
2197
|
+
...SOURCE_URL_ATTRIBUTES,
|
|
2198
|
+
...SOURCE_SET_ATTRIBUTES
|
|
2199
|
+
];
|
|
2200
|
+
var TAG_ATTRIBUTES = [
|
|
2201
|
+
"data-prepr-encoded",
|
|
2202
|
+
"data-prepr-id",
|
|
2203
|
+
"data-prepr-field",
|
|
2204
|
+
"data-prepr-entry-id",
|
|
2205
|
+
ASSET_ATTR
|
|
2206
|
+
];
|
|
2207
|
+
function decodeSegment(segment) {
|
|
2208
|
+
try {
|
|
2209
|
+
return decodeURIComponent(segment);
|
|
2210
|
+
} catch {
|
|
2211
|
+
return segment;
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
function isTransformSegment(segment) {
|
|
2215
|
+
return segment === FORMAT_PLACEHOLDER || segment.split(",").every((option) => TRANSFORM_OPTION.test(option));
|
|
2216
|
+
}
|
|
2217
|
+
function assetKey(url, depth = 0) {
|
|
2218
|
+
if (!url || url.length > MAX_URL_LENGTH) return null;
|
|
2219
|
+
let parsed;
|
|
2220
|
+
try {
|
|
2221
|
+
parsed = new URL(url, "https://base.invalid");
|
|
2222
|
+
} catch {
|
|
2223
|
+
return null;
|
|
2224
|
+
}
|
|
2225
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
|
|
2226
|
+
if (depth === 0) {
|
|
2227
|
+
for (const name of PROXY_PARAMS) {
|
|
2228
|
+
const inner = parsed.searchParams.get(name);
|
|
2229
|
+
if (inner && ABSOLUTE_HTTP.test(inner)) return assetKey(inner, 1);
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
const segments = parsed.pathname.split("/").filter(Boolean).map(decodeSegment);
|
|
2233
|
+
const file = segments.pop();
|
|
2234
|
+
if (!file) return null;
|
|
2235
|
+
const kept = segments.filter((segment) => !isTransformSegment(segment));
|
|
2236
|
+
kept.push(file);
|
|
2237
|
+
return kept.length >= MIN_KEY_SEGMENTS ? kept.join("/") : null;
|
|
2238
|
+
}
|
|
2239
|
+
function srcsetUrls(srcset) {
|
|
2240
|
+
const urls = [];
|
|
2241
|
+
let expectUrl = true;
|
|
2242
|
+
for (const token of srcset.split(/\s+/)) {
|
|
2243
|
+
if (!token) continue;
|
|
2244
|
+
if (!expectUrl) {
|
|
2245
|
+
const comma = token.indexOf(",");
|
|
2246
|
+
if (comma === -1) continue;
|
|
2247
|
+
expectUrl = true;
|
|
2248
|
+
const rest = token.slice(comma + 1);
|
|
2249
|
+
if (!rest) continue;
|
|
2250
|
+
urls.push(rest.replace(/,+$/, ""));
|
|
2251
|
+
expectUrl = rest.endsWith(",");
|
|
2252
|
+
continue;
|
|
2253
|
+
}
|
|
2254
|
+
const url = token.replace(/^,+|,+$/g, "");
|
|
2255
|
+
if (url) urls.push(url);
|
|
2256
|
+
expectUrl = token.endsWith(",");
|
|
2257
|
+
}
|
|
2258
|
+
return urls;
|
|
2259
|
+
}
|
|
2260
|
+
function createAssetIndex(assets) {
|
|
2261
|
+
const index = /* @__PURE__ */ new Map();
|
|
2262
|
+
for (const asset of assets) {
|
|
2263
|
+
const key = assetKey(asset.key);
|
|
2264
|
+
if (key && !index.has(key)) index.set(key, asset);
|
|
2265
|
+
}
|
|
2266
|
+
return index;
|
|
2267
|
+
}
|
|
2268
|
+
function urlsOf(img) {
|
|
2269
|
+
const urls = [];
|
|
2270
|
+
const collect = (el) => {
|
|
2271
|
+
for (const name of SOURCE_URL_ATTRIBUTES) {
|
|
2272
|
+
const value = el.getAttribute(name);
|
|
2273
|
+
if (value) urls.push(value);
|
|
2274
|
+
}
|
|
2275
|
+
for (const name of SOURCE_SET_ATTRIBUTES) {
|
|
2276
|
+
const value = el.getAttribute(name);
|
|
2277
|
+
if (value) urls.push(...srcsetUrls(value));
|
|
2278
|
+
}
|
|
2279
|
+
};
|
|
2280
|
+
collect(img);
|
|
2281
|
+
const picture = img.parentElement;
|
|
2282
|
+
if (picture?.tagName === "PICTURE") {
|
|
2283
|
+
for (const source of picture.children) {
|
|
2284
|
+
if (source.tagName === "SOURCE") collect(source);
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
return urls;
|
|
2288
|
+
}
|
|
2289
|
+
function matchAsset(img, index, keys) {
|
|
2290
|
+
for (const url of urlsOf(img)) {
|
|
2291
|
+
let key = keys.get(url);
|
|
2292
|
+
if (key === void 0) {
|
|
2293
|
+
key = assetKey(url);
|
|
2294
|
+
keys.set(url, key);
|
|
2295
|
+
}
|
|
2296
|
+
const asset = key ? index.get(key) : void 0;
|
|
2297
|
+
if (asset) return asset;
|
|
2298
|
+
}
|
|
2299
|
+
return void 0;
|
|
2300
|
+
}
|
|
2301
|
+
function setIfChanged(el, name, value) {
|
|
2302
|
+
if (value === null) {
|
|
2303
|
+
if (el.hasAttribute(name)) el.removeAttribute(name);
|
|
2304
|
+
} else if (el.getAttribute(name) !== value) {
|
|
2305
|
+
el.setAttribute(name, value);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
function untagAssetImage(img) {
|
|
2309
|
+
for (const name of TAG_ATTRIBUTES) img.removeAttribute(name);
|
|
2310
|
+
}
|
|
2311
|
+
var TEXT_FIELD_SELECTOR = `[data-prepr-encoded]:not([${ASSET_ATTR}])`;
|
|
2312
|
+
function besideOtherItem(img, isCurrentItem) {
|
|
2313
|
+
for (let block = img.parentElement; block && block !== document.body; block = block.parentElement) {
|
|
2314
|
+
const texts = block.querySelectorAll(TEXT_FIELD_SELECTOR);
|
|
2315
|
+
if (texts.length === 0) continue;
|
|
2316
|
+
for (const text of texts) {
|
|
2317
|
+
if (isCurrentItem(text)) return false;
|
|
2318
|
+
}
|
|
2319
|
+
return true;
|
|
2320
|
+
}
|
|
2321
|
+
return false;
|
|
2322
|
+
}
|
|
2323
|
+
function tagAssetImages(index, itemId, keys, options = {}) {
|
|
2324
|
+
const { isCurrentItem } = options;
|
|
2325
|
+
for (const img of document.getElementsByTagName("img")) {
|
|
2326
|
+
const ours = img.hasAttribute(ASSET_ATTR);
|
|
2327
|
+
if (!ours && img.hasAttribute("data-prepr-encoded")) continue;
|
|
2328
|
+
const match = index.size ? matchAsset(img, index, keys) : void 0;
|
|
2329
|
+
const asset = match && isCurrentItem && besideOtherItem(img, isCurrentItem) ? void 0 : match;
|
|
2330
|
+
if (!asset) {
|
|
2331
|
+
if (ours) untagAssetImage(img);
|
|
2332
|
+
continue;
|
|
2333
|
+
}
|
|
2334
|
+
setIfChanged(img, "data-prepr-encoded", "");
|
|
2335
|
+
setIfChanged(img, ASSET_ATTR, "");
|
|
2336
|
+
setIfChanged(img, "data-prepr-id", itemId);
|
|
2337
|
+
setIfChanged(img, "data-prepr-field", asset.field);
|
|
2338
|
+
setIfChanged(img, "data-prepr-entry-id", asset.entryId ?? null);
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
function untagAssetImages() {
|
|
2342
|
+
document.querySelectorAll(`img[${ASSET_ATTR}]`).forEach(untagAssetImage);
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2345
|
+
// src/core/visual-editor/navigation-guard.ts
|
|
2346
|
+
var debug6 = createScopedLogger("navigation-guard");
|
|
2347
|
+
var trimSlash = (path) => path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
2348
|
+
function resolve(url) {
|
|
2349
|
+
try {
|
|
2350
|
+
return new URL(url, document.baseURI);
|
|
2351
|
+
} catch {
|
|
2352
|
+
return null;
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
function leavesPage(url) {
|
|
2356
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
2357
|
+
const here = window.location;
|
|
2358
|
+
return url.origin !== here.origin || trimSlash(url.pathname) !== trimSlash(here.pathname);
|
|
2359
|
+
}
|
|
2360
|
+
function leavingLinkHref(target) {
|
|
2361
|
+
if (!(target instanceof Element)) return null;
|
|
2362
|
+
const link = target.closest("a[href]");
|
|
2363
|
+
if (!link || link.hasAttribute("download")) return null;
|
|
2364
|
+
const linkTarget = link.getAttribute("target");
|
|
2365
|
+
if (linkTarget && linkTarget !== "_self") return null;
|
|
2366
|
+
const href = link.getAttribute("href") ?? "";
|
|
2367
|
+
if (href.startsWith("#")) return null;
|
|
2368
|
+
const url = resolve(href);
|
|
2369
|
+
return url && leavesPage(url) ? url.href : null;
|
|
2370
|
+
}
|
|
2371
|
+
function submitterAttr(submitter, attr) {
|
|
2372
|
+
if (!submitter?.hasAttribute(attr)) return null;
|
|
2373
|
+
if (attr === "formaction") return submitter.formAction;
|
|
2374
|
+
if (attr === "formmethod") return submitter.formMethod;
|
|
2375
|
+
return submitter.formTarget;
|
|
2376
|
+
}
|
|
2377
|
+
function submissionUrl(form, submitter) {
|
|
2378
|
+
const method = (submitterAttr(submitter, "formmethod") ?? form.method).toLowerCase();
|
|
2379
|
+
if (method === "dialog") return null;
|
|
2380
|
+
const target = submitterAttr(submitter, "formtarget") ?? form.target;
|
|
2381
|
+
if (target && target !== "_self") return null;
|
|
2382
|
+
const url = resolve(
|
|
2383
|
+
submitterAttr(submitter, "formaction") ?? (form.action || location.href)
|
|
2384
|
+
);
|
|
2385
|
+
if (!url) return null;
|
|
2386
|
+
if (method === "get") {
|
|
2387
|
+
let data;
|
|
2388
|
+
try {
|
|
2389
|
+
data = new FormData(form, submitter);
|
|
2390
|
+
} catch {
|
|
2391
|
+
data = new FormData(form);
|
|
2392
|
+
}
|
|
2393
|
+
const query = new URLSearchParams();
|
|
2394
|
+
data.forEach((value, key) => {
|
|
2395
|
+
query.append(key, typeof value === "string" ? value : value.name);
|
|
2396
|
+
});
|
|
2397
|
+
url.search = query.toString();
|
|
2398
|
+
}
|
|
2399
|
+
return url;
|
|
2400
|
+
}
|
|
2401
|
+
function createNavigationGuard(opts) {
|
|
2402
|
+
let active = false;
|
|
2403
|
+
let permitted = null;
|
|
2404
|
+
let pendingForm = null;
|
|
2405
|
+
let originalPush = null;
|
|
2406
|
+
let guardedPush = null;
|
|
2407
|
+
const isPermitted = (url) => permitted === url.href;
|
|
2408
|
+
const guarding = () => active && opts.showsEditedContent();
|
|
2409
|
+
const report = (href) => {
|
|
2410
|
+
debug6.log("blocked navigation to", href);
|
|
2411
|
+
opts.onBlocked(href);
|
|
2412
|
+
};
|
|
2413
|
+
const onSubmit = (e2) => {
|
|
2414
|
+
if (e2.defaultPrevented || !(e2.target instanceof HTMLFormElement)) return;
|
|
2415
|
+
if (!guarding()) return;
|
|
2416
|
+
const submitter = e2.submitter ?? null;
|
|
2417
|
+
const url = submissionUrl(e2.target, submitter);
|
|
2418
|
+
if (!url || !leavesPage(url) || isPermitted(url)) return;
|
|
2419
|
+
e2.preventDefault();
|
|
2420
|
+
pendingForm = { form: e2.target, submitter, href: url.href };
|
|
2421
|
+
report(url.href);
|
|
2422
|
+
};
|
|
2423
|
+
const onNavigate = (event) => {
|
|
2424
|
+
const e2 = event;
|
|
2425
|
+
if (e2.navigationType === "traverse" || e2.navigationType === "reload") {
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
if (!e2.cancelable || e2.hashChange || e2.downloadRequest !== null) return;
|
|
2429
|
+
if (!guarding()) return;
|
|
2430
|
+
if (e2.navigationType === "replace" && e2.destination.sameDocument) return;
|
|
2431
|
+
const url = resolve(e2.destination.url);
|
|
2432
|
+
if (!url || !leavesPage(url) || isPermitted(url)) return;
|
|
2433
|
+
e2.preventDefault();
|
|
2434
|
+
report(url.href);
|
|
2435
|
+
if (e2.destination.sameDocument) window.location.reload();
|
|
2436
|
+
};
|
|
2437
|
+
const navigation = () => window.navigation;
|
|
2438
|
+
function installPushGuard() {
|
|
2439
|
+
const original = history.pushState;
|
|
2440
|
+
const guard = function(data, unused, url) {
|
|
2441
|
+
if (guarding() && guardedPush === guard && url != null) {
|
|
2442
|
+
const target = resolve(url);
|
|
2443
|
+
if (target && leavesPage(target) && !isPermitted(target)) {
|
|
2444
|
+
report(target.href);
|
|
2445
|
+
window.location.reload();
|
|
2446
|
+
return;
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
return original.call(this, data, unused, url);
|
|
2450
|
+
};
|
|
2451
|
+
originalPush = original;
|
|
2452
|
+
guardedPush = guard;
|
|
2453
|
+
history.pushState = guard;
|
|
2454
|
+
}
|
|
2455
|
+
function uninstallPushGuard() {
|
|
2456
|
+
if (history.pushState === guardedPush && originalPush) {
|
|
2457
|
+
history.pushState = originalPush;
|
|
2458
|
+
}
|
|
2459
|
+
originalPush = null;
|
|
2460
|
+
guardedPush = null;
|
|
2461
|
+
}
|
|
2462
|
+
return {
|
|
2463
|
+
start() {
|
|
2464
|
+
if (active) return;
|
|
2465
|
+
active = true;
|
|
2466
|
+
installPushGuard();
|
|
2467
|
+
window.addEventListener("submit", onSubmit);
|
|
2468
|
+
navigation()?.addEventListener("navigate", onNavigate);
|
|
2469
|
+
},
|
|
2470
|
+
stop() {
|
|
2471
|
+
if (!active) return;
|
|
2472
|
+
active = false;
|
|
2473
|
+
uninstallPushGuard();
|
|
2474
|
+
window.removeEventListener("submit", onSubmit);
|
|
2475
|
+
navigation()?.removeEventListener("navigate", onNavigate);
|
|
2476
|
+
pendingForm = null;
|
|
2477
|
+
},
|
|
2478
|
+
isActive: guarding,
|
|
2479
|
+
block(href) {
|
|
2480
|
+
report(href);
|
|
2481
|
+
},
|
|
2482
|
+
permit(href) {
|
|
2483
|
+
permitted = resolve(href)?.href ?? null;
|
|
2484
|
+
},
|
|
2485
|
+
allow(href) {
|
|
2486
|
+
const url = resolve(href);
|
|
2487
|
+
if (!url || url.protocol !== "http:" && url.protocol !== "https:") {
|
|
2488
|
+
debug6.warn("ignored navigation to unsupported URL");
|
|
2489
|
+
return;
|
|
2490
|
+
}
|
|
2491
|
+
permitted = url.href;
|
|
2492
|
+
const form = pendingForm;
|
|
2493
|
+
pendingForm = null;
|
|
2494
|
+
if (form && form.href === url.href && form.form.isConnected) {
|
|
2495
|
+
try {
|
|
2496
|
+
form.form.requestSubmit(form.submitter ?? void 0);
|
|
2497
|
+
} catch {
|
|
2498
|
+
form.form.requestSubmit();
|
|
2499
|
+
}
|
|
2500
|
+
return;
|
|
2501
|
+
}
|
|
2502
|
+
window.location.assign(url.href);
|
|
2503
|
+
}
|
|
2504
|
+
};
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
// src/core/visual-editor/index.ts
|
|
2508
|
+
var debug7 = createScopedLogger("visual-editor");
|
|
2509
|
+
var ENCODED_SELECTOR2 = "[data-prepr-encoded]";
|
|
2510
|
+
var REFERENCE_ATTR = "data-prepr-reference";
|
|
2511
|
+
var REFERENCE_SELECTOR = `[${REFERENCE_ATTR}]`;
|
|
2512
|
+
var CURSOR_STYLE_MARKER = "data-prepr-visual-editor";
|
|
2513
|
+
var CURSOR_STYLES = `${ENCODED_SELECTOR2}{cursor:pointer}html[data-prepr-ve-suspended] ${ENCODED_SELECTOR2}{cursor:auto}`;
|
|
2514
|
+
var SUSPENDED_ATTR = "data-prepr-ve-suspended";
|
|
2515
|
+
var FIND_RETRY_MS = 150;
|
|
2516
|
+
var FIND_RETRIES = 6;
|
|
2517
|
+
var MAX_CACHED_KEYS = 2e3;
|
|
2518
|
+
var LAYOUT_MUTATIONS = {
|
|
2519
|
+
childList: true,
|
|
2520
|
+
subtree: true,
|
|
2521
|
+
characterData: true,
|
|
2522
|
+
attributes: true,
|
|
2523
|
+
attributeFilter: [
|
|
2524
|
+
"class",
|
|
2525
|
+
"style",
|
|
2526
|
+
"hidden",
|
|
2527
|
+
"open",
|
|
2528
|
+
"data-prepr-encoded",
|
|
2529
|
+
// An image swapped by a carousel or lazy loader can show another asset.
|
|
2530
|
+
...ASSET_SOURCE_ATTRIBUTES
|
|
2531
|
+
]
|
|
2532
|
+
};
|
|
2533
|
+
function scrollIntoFrame(el) {
|
|
2534
|
+
const rect = el.getBoundingClientRect();
|
|
2535
|
+
const offset = Math.max(0, (window.innerHeight - rect.height) / 2);
|
|
2536
|
+
window.scrollTo({
|
|
2537
|
+
top: Math.max(0, window.scrollY + rect.top - offset),
|
|
2538
|
+
behavior: "smooth"
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
var isVisible = (el) => typeof el.checkVisibility === "function" ? el.checkVisibility() : el.getClientRects().length > 0;
|
|
2542
|
+
function createVisualEditor(opts) {
|
|
2543
|
+
const overlay = new VisualEditorOverlay();
|
|
2544
|
+
let running = false;
|
|
2545
|
+
let currentItemId = null;
|
|
2546
|
+
let locale = opts.locale ?? "en";
|
|
2547
|
+
let suspended = false;
|
|
2548
|
+
let pointerFrame = null;
|
|
2549
|
+
let lastPointerTarget = null;
|
|
2550
|
+
let lastPointerX = 0;
|
|
2551
|
+
let lastPointerY = 0;
|
|
2552
|
+
let mutationFrame = null;
|
|
2553
|
+
let mutationObserver = null;
|
|
2554
|
+
let selection = null;
|
|
2555
|
+
let findTimeout = null;
|
|
2556
|
+
let settlePendingFind = null;
|
|
2557
|
+
let guardEnabled = false;
|
|
2558
|
+
let assetIndex = /* @__PURE__ */ new Map();
|
|
2559
|
+
const assetKeys = /* @__PURE__ */ new Map();
|
|
2560
|
+
const guard = createNavigationGuard({
|
|
2561
|
+
onBlocked: (href) => opts.onNavigationBlocked?.(href),
|
|
2562
|
+
showsEditedContent: () => showsEditedContent()
|
|
2563
|
+
});
|
|
2564
|
+
const encodedFrom = (node) => node instanceof Element ? node.closest(ENCODED_SELECTOR2) : null;
|
|
2565
|
+
const labelFor = (el) => fieldLabel(el.getAttribute("data-prepr-field"), locale);
|
|
2566
|
+
let references = null;
|
|
2567
|
+
let ownComponents = /* @__PURE__ */ new Set();
|
|
2568
|
+
const isCurrentItem = (el) => {
|
|
2569
|
+
if (currentItemId === null) return true;
|
|
2570
|
+
const id = el.getAttribute("data-prepr-id");
|
|
2571
|
+
return !id || id === currentItemId || ownComponents.has(id);
|
|
2572
|
+
};
|
|
2573
|
+
const showsEditedContent = () => {
|
|
2574
|
+
for (const el of document.querySelectorAll(ENCODED_SELECTOR2)) {
|
|
2575
|
+
if (isCurrentItem(el) && isVisible(el)) return true;
|
|
2576
|
+
}
|
|
2577
|
+
return false;
|
|
2578
|
+
};
|
|
2579
|
+
const linkedIdOf = (el) => {
|
|
2580
|
+
if (!references) return null;
|
|
2581
|
+
const id = el.getAttribute("data-prepr-id") ?? "";
|
|
2582
|
+
if (references.has(id)) return id;
|
|
2583
|
+
let container = el.closest(REFERENCE_SELECTOR);
|
|
2584
|
+
while (container) {
|
|
2585
|
+
const linked = container.getAttribute(REFERENCE_ATTR) ?? "";
|
|
2586
|
+
if (references.has(linked)) return linked;
|
|
2587
|
+
container = container.parentElement?.closest(REFERENCE_SELECTOR) ?? null;
|
|
2588
|
+
}
|
|
2589
|
+
return null;
|
|
2590
|
+
};
|
|
2591
|
+
const itemKind = (el) => {
|
|
2592
|
+
if (isCurrentItem(el)) return "current";
|
|
2593
|
+
if (!references) return "other";
|
|
2594
|
+
return linkedIdOf(el) ? "referenced" : null;
|
|
2595
|
+
};
|
|
2596
|
+
const referenceFieldOf = (el) => {
|
|
2597
|
+
const linked = linkedIdOf(el);
|
|
2598
|
+
return linked ? references?.get(linked) : void 0;
|
|
2599
|
+
};
|
|
2600
|
+
const hoverLabel = (el, kind) => {
|
|
2601
|
+
if (kind === "other") {
|
|
2602
|
+
return `${labelFor(el)} \xB7 ${t("visualEditor.otherItem", locale)}`;
|
|
2603
|
+
}
|
|
2604
|
+
if (kind === "referenced") {
|
|
2605
|
+
const via = referenceFieldOf(el);
|
|
2606
|
+
const prefix = via ? `${fieldLabel(via, locale)} \u203A ` : "";
|
|
2607
|
+
return `${prefix}${labelFor(el)} \xB7 ${t("visualEditor.linkedItem", locale)}`;
|
|
2608
|
+
}
|
|
2609
|
+
return labelFor(el);
|
|
2610
|
+
};
|
|
2611
|
+
const setSuspended = (value) => {
|
|
2612
|
+
if (suspended === value) return;
|
|
2613
|
+
suspended = value;
|
|
2614
|
+
document.documentElement.toggleAttribute(SUSPENDED_ATTR, value);
|
|
2615
|
+
if (value) overlay.setHover(null, "");
|
|
2616
|
+
};
|
|
2617
|
+
const updateHover = () => {
|
|
2618
|
+
pointerFrame = null;
|
|
2619
|
+
overlay.schedule();
|
|
2620
|
+
if (suspended) return;
|
|
2621
|
+
const encoded = encodedFrom(lastPointerTarget);
|
|
2622
|
+
const target = encoded === overlay.getSelectedTarget() ? null : encoded;
|
|
2623
|
+
if (!target) {
|
|
2624
|
+
overlay.setHover(null, "");
|
|
2625
|
+
return;
|
|
2626
|
+
}
|
|
2627
|
+
const kind = itemKind(target);
|
|
2628
|
+
if (!kind) {
|
|
2629
|
+
overlay.setHover(null, "");
|
|
2630
|
+
return;
|
|
2631
|
+
}
|
|
2632
|
+
overlay.setHover(target, hoverLabel(target, kind), { kind });
|
|
2633
|
+
};
|
|
2634
|
+
const handlePointerMove = (e2) => {
|
|
2635
|
+
setSuspended(e2.altKey);
|
|
2636
|
+
lastPointerTarget = e2.target;
|
|
2637
|
+
lastPointerX = e2.clientX;
|
|
2638
|
+
lastPointerY = e2.clientY;
|
|
2639
|
+
if (pointerFrame === null) {
|
|
2640
|
+
pointerFrame = requestAnimationFrame(updateHover);
|
|
2641
|
+
}
|
|
2642
|
+
};
|
|
2643
|
+
const handlePointerLeave = () => {
|
|
2644
|
+
lastPointerTarget = null;
|
|
2645
|
+
overlay.setHover(null, "");
|
|
2646
|
+
};
|
|
2647
|
+
const handleClick = (e2) => {
|
|
2648
|
+
if (e2.altKey) {
|
|
2649
|
+
const href = leavingLinkHref(e2.target);
|
|
2650
|
+
if (href && guard.isActive()) guard.permit(href);
|
|
2651
|
+
return;
|
|
2652
|
+
}
|
|
2653
|
+
const encoded = encodedFrom(e2.target);
|
|
2654
|
+
const kind = encoded ? itemKind(encoded) : null;
|
|
2655
|
+
if (!encoded || !kind) {
|
|
2656
|
+
clearSelection();
|
|
2657
|
+
if (e2.ctrlKey || e2.metaKey || e2.shiftKey || !showsEditedContent()) return;
|
|
2658
|
+
const href = leavingLinkHref(e2.target);
|
|
2659
|
+
if (!href) return;
|
|
2660
|
+
e2.preventDefault();
|
|
2661
|
+
if (guard.isActive()) {
|
|
2662
|
+
e2.stopPropagation();
|
|
2663
|
+
guard.block(href);
|
|
2664
|
+
}
|
|
2665
|
+
return;
|
|
2666
|
+
}
|
|
2667
|
+
e2.preventDefault();
|
|
2668
|
+
e2.stopPropagation();
|
|
2669
|
+
const item = listItemIn(encoded, e2.target);
|
|
2670
|
+
if (kind === "current")
|
|
2671
|
+
select(item?.element ?? encoded, encoded, item?.index);
|
|
2672
|
+
const referenceField = kind === "referenced" ? referenceFieldOf(encoded) : void 0;
|
|
2673
|
+
const linkedId = kind === "referenced" ? linkedIdOf(encoded) : null;
|
|
2674
|
+
opts.onEdit({
|
|
2675
|
+
...readEditPayload(encoded),
|
|
2676
|
+
...linkedId && { id: linkedId },
|
|
2677
|
+
...item && { block: item.index },
|
|
2678
|
+
...referenceField && { referenceField }
|
|
2679
|
+
});
|
|
2680
|
+
};
|
|
2681
|
+
const handleKey = (e2) => {
|
|
2682
|
+
if (e2.key === "Alt") setSuspended(e2.type === "keydown");
|
|
2683
|
+
if (e2.type === "keydown" && e2.key === "Escape") {
|
|
2684
|
+
clearSelection();
|
|
2685
|
+
}
|
|
2686
|
+
};
|
|
2687
|
+
const handleBlur = () => setSuspended(false);
|
|
2688
|
+
const handleScroll = () => overlay.onScroll();
|
|
2689
|
+
const handleResize = () => overlay.schedule();
|
|
2690
|
+
const handleSettled = () => overlay.schedule();
|
|
2691
|
+
function listItemIn(encoded, target) {
|
|
2692
|
+
if (!(target instanceof Element)) return null;
|
|
2693
|
+
const li = target.closest("li");
|
|
2694
|
+
if (!li || !encoded.contains(li) || !li.parentElement) return null;
|
|
2695
|
+
const items = Array.from(li.parentElement.children).filter(
|
|
2696
|
+
(child) => child.tagName === "LI"
|
|
2697
|
+
);
|
|
2698
|
+
return { element: li, index: items.indexOf(li) };
|
|
2699
|
+
}
|
|
2700
|
+
function nthListItem(encoded, block) {
|
|
2701
|
+
const list = encoded.querySelector("ul, ol");
|
|
2702
|
+
if (!list) return null;
|
|
2703
|
+
const items = Array.from(list.children).filter(
|
|
2704
|
+
(child) => child.tagName === "LI"
|
|
2705
|
+
);
|
|
2706
|
+
return items[block] ?? null;
|
|
2707
|
+
}
|
|
2708
|
+
function select(el, field, block) {
|
|
2709
|
+
const entryId = field.getAttribute("data-prepr-entry-id");
|
|
2710
|
+
selection = {
|
|
2711
|
+
lookup: {
|
|
2712
|
+
field: field.getAttribute("data-prepr-field") ?? "",
|
|
2713
|
+
id: field.getAttribute("data-prepr-id") ?? void 0,
|
|
2714
|
+
...entryId && { entryId },
|
|
2715
|
+
...block !== void 0 && { block }
|
|
2716
|
+
},
|
|
2717
|
+
label: field
|
|
2718
|
+
};
|
|
2719
|
+
overlay.setSelected(el, labelFor(field));
|
|
2720
|
+
if (overlay.getHoverTarget() === el) overlay.setHover(null, "");
|
|
2721
|
+
}
|
|
2722
|
+
function clearSelection() {
|
|
2723
|
+
selection = null;
|
|
2724
|
+
overlay.setSelected(null, "");
|
|
2725
|
+
}
|
|
2726
|
+
function reselect() {
|
|
2727
|
+
if (!selection) return;
|
|
2728
|
+
const current = overlay.getSelectedTarget();
|
|
2729
|
+
if (current?.isConnected && selection.label.isConnected) return;
|
|
2730
|
+
const found = findFieldElement(selection.lookup);
|
|
2731
|
+
if (!found || !isCurrentItem(found)) {
|
|
2732
|
+
overlay.setSelected(null, "");
|
|
2733
|
+
return;
|
|
2734
|
+
}
|
|
2735
|
+
const { block } = selection.lookup;
|
|
2736
|
+
const el = block !== void 0 ? nthListItem(found, block) ?? found : found;
|
|
2737
|
+
select(el, found, block);
|
|
2738
|
+
}
|
|
2739
|
+
function tagAssets() {
|
|
2740
|
+
if (assetKeys.size > MAX_CACHED_KEYS) assetKeys.clear();
|
|
2741
|
+
tagAssetImages(assetIndex, currentItemId, assetKeys, {
|
|
2742
|
+
isCurrentItem: (el) => isCurrentItem(el)
|
|
2743
|
+
});
|
|
2744
|
+
}
|
|
2745
|
+
const handleLayoutFrame = () => {
|
|
2746
|
+
mutationFrame = null;
|
|
2747
|
+
if (assetIndex.size) tagAssets();
|
|
2748
|
+
reselect();
|
|
2749
|
+
const hovered = overlay.getHoverTarget();
|
|
2750
|
+
if (hovered && !hovered.isConnected) {
|
|
2751
|
+
lastPointerTarget = document.elementFromPoint(lastPointerX, lastPointerY);
|
|
2752
|
+
updateHover();
|
|
2753
|
+
return;
|
|
2754
|
+
}
|
|
2755
|
+
overlay.schedule();
|
|
2756
|
+
};
|
|
2757
|
+
const handleMutations = () => {
|
|
2758
|
+
if (mutationFrame !== null) return;
|
|
2759
|
+
if (!selection && !overlay.getHoverTarget() && !assetIndex.size) return;
|
|
2760
|
+
mutationFrame = requestAnimationFrame(handleLayoutFrame);
|
|
2761
|
+
};
|
|
2762
|
+
function injectCursorStyles() {
|
|
2763
|
+
if (document.querySelector(`style[${CURSOR_STYLE_MARKER}]`)) return;
|
|
2764
|
+
const style = document.createElement("style");
|
|
2765
|
+
style.setAttribute(CURSOR_STYLE_MARKER, "");
|
|
2766
|
+
style.textContent = CURSOR_STYLES;
|
|
2767
|
+
document.head.appendChild(style);
|
|
2768
|
+
}
|
|
2769
|
+
function start() {
|
|
2770
|
+
if (running) return;
|
|
2771
|
+
running = true;
|
|
2772
|
+
overlay.mount();
|
|
2773
|
+
injectCursorStyles();
|
|
2774
|
+
document.addEventListener("pointermove", handlePointerMove, {
|
|
2775
|
+
passive: true
|
|
2776
|
+
});
|
|
2777
|
+
document.documentElement.addEventListener(
|
|
2778
|
+
"pointerleave",
|
|
2779
|
+
handlePointerLeave
|
|
2780
|
+
);
|
|
2781
|
+
document.addEventListener("click", handleClick, { capture: true });
|
|
2782
|
+
window.addEventListener("keydown", handleKey);
|
|
2783
|
+
window.addEventListener("keyup", handleKey);
|
|
2784
|
+
window.addEventListener("blur", handleBlur);
|
|
2785
|
+
window.addEventListener("scroll", handleScroll, {
|
|
2786
|
+
capture: true,
|
|
2787
|
+
passive: true
|
|
2788
|
+
});
|
|
2789
|
+
window.addEventListener("resize", handleResize, { passive: true });
|
|
2790
|
+
document.addEventListener("transitionend", handleSettled, {
|
|
2791
|
+
capture: true,
|
|
2792
|
+
passive: true
|
|
2793
|
+
});
|
|
2794
|
+
document.addEventListener("animationend", handleSettled, {
|
|
2795
|
+
capture: true,
|
|
2796
|
+
passive: true
|
|
2797
|
+
});
|
|
2798
|
+
mutationObserver = new MutationObserver(handleMutations);
|
|
2799
|
+
mutationObserver.observe(document.body, LAYOUT_MUTATIONS);
|
|
2800
|
+
if (assetIndex.size) tagAssets();
|
|
2801
|
+
syncGuard();
|
|
2802
|
+
debug7.log("visual editor started");
|
|
2803
|
+
}
|
|
2804
|
+
function stop() {
|
|
2805
|
+
if (!running) return;
|
|
2806
|
+
running = false;
|
|
2807
|
+
if (pointerFrame !== null) cancelAnimationFrame(pointerFrame);
|
|
2808
|
+
if (mutationFrame !== null) cancelAnimationFrame(mutationFrame);
|
|
2809
|
+
mutationObserver?.disconnect();
|
|
2810
|
+
mutationObserver = null;
|
|
2811
|
+
cancelFind();
|
|
2812
|
+
pointerFrame = null;
|
|
2813
|
+
mutationFrame = null;
|
|
2814
|
+
selection = null;
|
|
2815
|
+
lastPointerTarget = null;
|
|
2816
|
+
setSuspended(false);
|
|
2817
|
+
document.removeEventListener("pointermove", handlePointerMove);
|
|
2818
|
+
document.documentElement.removeEventListener(
|
|
2819
|
+
"pointerleave",
|
|
2820
|
+
handlePointerLeave
|
|
2821
|
+
);
|
|
2822
|
+
document.removeEventListener("click", handleClick, { capture: true });
|
|
2823
|
+
window.removeEventListener("keydown", handleKey);
|
|
2824
|
+
window.removeEventListener("keyup", handleKey);
|
|
2825
|
+
window.removeEventListener("blur", handleBlur);
|
|
2826
|
+
window.removeEventListener("scroll", handleScroll, { capture: true });
|
|
2827
|
+
window.removeEventListener("resize", handleResize);
|
|
2828
|
+
document.removeEventListener("transitionend", handleSettled, {
|
|
2829
|
+
capture: true
|
|
2830
|
+
});
|
|
2831
|
+
document.removeEventListener("animationend", handleSettled, {
|
|
2832
|
+
capture: true
|
|
2833
|
+
});
|
|
2834
|
+
document.querySelectorAll(`style[${CURSOR_STYLE_MARKER}]`).forEach((node) => node.remove());
|
|
2835
|
+
overlay.unmount();
|
|
2836
|
+
untagAssetImages();
|
|
2837
|
+
guard.stop();
|
|
2838
|
+
debug7.log("visual editor stopped");
|
|
2839
|
+
}
|
|
2840
|
+
function cancelFind() {
|
|
2841
|
+
if (findTimeout) clearTimeout(findTimeout);
|
|
2842
|
+
findTimeout = null;
|
|
2843
|
+
settlePendingFind?.();
|
|
2844
|
+
settlePendingFind = null;
|
|
2845
|
+
}
|
|
2846
|
+
function focusField(lookup) {
|
|
2847
|
+
cancelFind();
|
|
2848
|
+
return new Promise((resolve2) => {
|
|
2849
|
+
let attempt = 0;
|
|
2850
|
+
const finish = (found) => {
|
|
2851
|
+
settlePendingFind = null;
|
|
2852
|
+
resolve2(found);
|
|
2853
|
+
};
|
|
2854
|
+
settlePendingFind = () => resolve2(false);
|
|
2855
|
+
const tryFind = () => {
|
|
2856
|
+
findTimeout = null;
|
|
2857
|
+
const found = findFieldElement(lookup);
|
|
2858
|
+
if (found) {
|
|
2859
|
+
const el = lookup.block !== void 0 ? nthListItem(found, lookup.block) ?? found : found;
|
|
2860
|
+
scrollIntoFrame(el);
|
|
2861
|
+
if (running && isCurrentItem(found)) select(el, found, lookup.block);
|
|
2862
|
+
finish(true);
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
if (++attempt >= FIND_RETRIES) {
|
|
2866
|
+
debug7.log("no element renders field", lookup.field);
|
|
2867
|
+
finish(false);
|
|
2868
|
+
return;
|
|
2869
|
+
}
|
|
2870
|
+
findTimeout = setTimeout(tryFind, FIND_RETRY_MS);
|
|
2871
|
+
};
|
|
2872
|
+
tryFind();
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
function setCurrentItem(itemId, referenceList, componentIds) {
|
|
2876
|
+
currentItemId = itemId;
|
|
2877
|
+
if (referenceList) setReferences(referenceList, componentIds);
|
|
2878
|
+
else if (componentIds) ownComponents = new Set(componentIds);
|
|
2879
|
+
if (running && assetIndex.size) tagAssets();
|
|
2880
|
+
const selected = overlay.getSelectedTarget();
|
|
2881
|
+
const owner = selected ? encodedFrom(selected) : null;
|
|
2882
|
+
if (owner && !isCurrentItem(owner)) clearSelection();
|
|
2883
|
+
}
|
|
2884
|
+
function setAssets(assets) {
|
|
2885
|
+
const hadAssets = assetIndex.size > 0;
|
|
2886
|
+
assetIndex = createAssetIndex(assets);
|
|
2887
|
+
if (running && (hadAssets || assetIndex.size)) tagAssets();
|
|
2888
|
+
}
|
|
2889
|
+
function setReferences(referenceList, componentIds) {
|
|
2890
|
+
if (componentIds) ownComponents = new Set(componentIds);
|
|
2891
|
+
references = /* @__PURE__ */ new Map();
|
|
2892
|
+
for (const { id, field } of referenceList) {
|
|
2893
|
+
if (!references.has(id)) references.set(id, field);
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
function setLocale(value) {
|
|
2897
|
+
locale = value;
|
|
2898
|
+
}
|
|
2899
|
+
function syncGuard() {
|
|
2900
|
+
if (running && guardEnabled) guard.start();
|
|
2901
|
+
else guard.stop();
|
|
2902
|
+
}
|
|
2903
|
+
function setNavigationGuard(enabled) {
|
|
2904
|
+
guardEnabled = enabled;
|
|
2905
|
+
syncGuard();
|
|
2906
|
+
}
|
|
2907
|
+
return {
|
|
2908
|
+
start,
|
|
2909
|
+
stop,
|
|
2910
|
+
setCurrentItem,
|
|
2911
|
+
setReferences,
|
|
2912
|
+
setAssets,
|
|
2913
|
+
setLocale,
|
|
2914
|
+
focusField,
|
|
2915
|
+
setNavigationGuard,
|
|
2916
|
+
allowNavigation: (href) => guard.allow(href)
|
|
2917
|
+
};
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2104
2920
|
// src/core/create-preview.ts
|
|
2105
|
-
var
|
|
2921
|
+
var debug8 = createScopedLogger("create-preview");
|
|
2106
2922
|
var controllerStores = /* @__PURE__ */ new WeakMap();
|
|
2107
2923
|
function defaultNavigation() {
|
|
2108
2924
|
return {
|
|
@@ -2144,7 +2960,7 @@ function createPreprPreview(opts = {}) {
|
|
|
2144
2960
|
const search = new URLSearchParams(window.location.search);
|
|
2145
2961
|
const hideBar = search.get(PARAM_HIDE_BAR) === "true";
|
|
2146
2962
|
if (hideBar) {
|
|
2147
|
-
|
|
2963
|
+
debug8.log(`${PARAM_HIDE_BAR}=true \u2014 no visible toolbar`);
|
|
2148
2964
|
}
|
|
2149
2965
|
const mountUi = (options?.ui ?? true) && !isIframe && !hideBar;
|
|
2150
2966
|
const locale = resolveLocale(options);
|
|
@@ -2170,33 +2986,48 @@ function createPreprPreview(opts = {}) {
|
|
|
2170
2986
|
definePreprToolbar();
|
|
2171
2987
|
el = document.createElement("prepr-toolbar");
|
|
2172
2988
|
document.body.appendChild(el);
|
|
2173
|
-
el.connect(store, (key) =>
|
|
2989
|
+
el.connect(store, (key) => t(key, locale));
|
|
2174
2990
|
}
|
|
2175
2991
|
const editingEnabled = features.editMode || isIframe;
|
|
2176
|
-
const
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
}
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
}
|
|
2992
|
+
const onEdit = ({
|
|
2993
|
+
href,
|
|
2994
|
+
id,
|
|
2995
|
+
field,
|
|
2996
|
+
locale: contentLocale,
|
|
2997
|
+
block,
|
|
2998
|
+
entryId,
|
|
2999
|
+
referenceField
|
|
3000
|
+
}) => {
|
|
3001
|
+
const safeHref = href ? safeEditUrl(href) : null;
|
|
3002
|
+
if (href && !safeHref) {
|
|
3003
|
+
debug8.warn("ignored edit request with unsupported href scheme");
|
|
3004
|
+
return;
|
|
3005
|
+
}
|
|
3006
|
+
if (isIframe) {
|
|
3007
|
+
sendPreprEvent("field_edit_requested", {
|
|
3008
|
+
id,
|
|
3009
|
+
field,
|
|
3010
|
+
locale: contentLocale,
|
|
3011
|
+
...block !== void 0 && { block },
|
|
3012
|
+
...entryId && { entryId },
|
|
3013
|
+
...referenceField && { referenceField }
|
|
3014
|
+
});
|
|
3015
|
+
} else if (safeHref) {
|
|
3016
|
+
window.open(safeHref, "_blank", "noopener,noreferrer");
|
|
2199
3017
|
}
|
|
3018
|
+
};
|
|
3019
|
+
const visualEditor = isIframe ? createVisualEditor({
|
|
3020
|
+
onEdit,
|
|
3021
|
+
locale,
|
|
3022
|
+
onNavigationBlocked: (href) => sendPreprEvent("navigation_blocked", { href })
|
|
3023
|
+
}) : null;
|
|
3024
|
+
const stega = visualEditor ?? createStegaController({
|
|
3025
|
+
// The edit-mode marks and hover label are chrome, so they follow the
|
|
3026
|
+
// same decision as the bar: unwanted in a headless preview that asked
|
|
3027
|
+
// for no UI.
|
|
3028
|
+
tooltip: mountUi,
|
|
3029
|
+
onEdit,
|
|
3030
|
+
locale
|
|
2200
3031
|
});
|
|
2201
3032
|
const autoClean = createStegaAutoClean({
|
|
2202
3033
|
enabled: options?.autoClean
|
|
@@ -2218,7 +3049,35 @@ function createPreprPreview(opts = {}) {
|
|
|
2218
3049
|
handleChange(before, state);
|
|
2219
3050
|
});
|
|
2220
3051
|
const bridge = createIframeBridge(store, {
|
|
2221
|
-
allowedEditorOrigins: options?.allowedEditorOrigins
|
|
3052
|
+
allowedEditorOrigins: options?.allowedEditorOrigins,
|
|
3053
|
+
onHandshake: ({
|
|
3054
|
+
itemId,
|
|
3055
|
+
referencedIds,
|
|
3056
|
+
componentIds,
|
|
3057
|
+
uiLocale,
|
|
3058
|
+
navigationGuard,
|
|
3059
|
+
assets
|
|
3060
|
+
}) => {
|
|
3061
|
+
if (uiLocale) visualEditor?.setLocale(uiLocale);
|
|
3062
|
+
visualEditor?.setCurrentItem(itemId ?? null, referencedIds, componentIds);
|
|
3063
|
+
visualEditor?.setNavigationGuard(navigationGuard === true);
|
|
3064
|
+
if (assets) visualEditor?.setAssets(assets);
|
|
3065
|
+
},
|
|
3066
|
+
onAssets: (assets) => visualEditor?.setAssets(assets),
|
|
3067
|
+
onAllowNavigation: (href) => visualEditor?.allowNavigation(href),
|
|
3068
|
+
onReferences: (referencedIds, componentIds) => visualEditor?.setReferences(referencedIds, componentIds),
|
|
3069
|
+
// The editor selecting a field scrolls the matching element into view. The
|
|
3070
|
+
// lookup relies on the attributes the stega scan writes, so it finds
|
|
3071
|
+
// nothing until encoded content has been tagged.
|
|
3072
|
+
onScrollToField: ({ field, id, block, entryId, fieldById }) => {
|
|
3073
|
+
if (visualEditor) {
|
|
3074
|
+
void visualEditor.focusField({ field, id, block, entryId, fieldById });
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
if (!scrollToField({ field, id })) {
|
|
3078
|
+
debug8.log("no element on this page renders field", field);
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
2222
3081
|
});
|
|
2223
3082
|
sendPreprEvent(
|
|
2224
3083
|
"getScrollPosition",
|
|
@@ -2238,7 +3097,7 @@ function createPreprPreview(opts = {}) {
|
|
|
2238
3097
|
bridge.stop();
|
|
2239
3098
|
}
|
|
2240
3099
|
el?.remove();
|
|
2241
|
-
|
|
3100
|
+
debug8.log("preview destroyed");
|
|
2242
3101
|
}
|
|
2243
3102
|
const controller = { destroy };
|
|
2244
3103
|
controllerStores.set(controller, store);
|
|
@@ -2311,8 +3170,6 @@ function setTrackingParam(key, value) {
|
|
|
2311
3170
|
}
|
|
2312
3171
|
|
|
2313
3172
|
export {
|
|
2314
|
-
VERSION,
|
|
2315
|
-
resolveFeatures,
|
|
2316
3173
|
COOKIE_PREVIEW_MODE,
|
|
2317
3174
|
COOKIE_SEGMENT,
|
|
2318
3175
|
COOKIE_VARIANT,
|
|
@@ -2322,7 +3179,9 @@ export {
|
|
|
2322
3179
|
PARAM_VARIANT,
|
|
2323
3180
|
PARAM_HIDE_BAR,
|
|
2324
3181
|
ONE_YEAR_SECONDS,
|
|
3182
|
+
HEADER_LIVE_RENDER,
|
|
2325
3183
|
stegaClean,
|
|
3184
|
+
decodeStega,
|
|
2326
3185
|
createToolbarStore,
|
|
2327
3186
|
PreprToolbarElement,
|
|
2328
3187
|
definePreprToolbar,
|