@improba/page-builder 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +26 -26
  2. package/dist/core.cjs +2 -0
  3. package/dist/core.cjs.map +1 -0
  4. package/dist/core.js +29 -0
  5. package/dist/core.js.map +1 -0
  6. package/dist/index-D79WbFRY.cjs +2 -0
  7. package/dist/index-D79WbFRY.cjs.map +1 -0
  8. package/dist/index-c6HOrx9r.js +523 -0
  9. package/dist/index-c6HOrx9r.js.map +1 -0
  10. package/dist/index.cjs +10 -5
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.js +2402 -3312
  13. package/dist/index.js.map +1 -1
  14. package/dist/style.css +1 -0
  15. package/dist/types/built-in/PbColumn.vue.d.ts +41 -0
  16. package/dist/types/built-in/PbContainer.vue.d.ts +32 -0
  17. package/dist/types/built-in/PbImage.vue.d.ts +42 -0
  18. package/dist/types/built-in/PbRow.vue.d.ts +41 -0
  19. package/dist/types/built-in/PbSection.vue.d.ts +50 -0
  20. package/dist/types/built-in/PbText.vue.d.ts +25 -0
  21. package/dist/types/built-in/PbVideo.vue.d.ts +27 -0
  22. package/dist/types/built-in/index.d.ts +10 -0
  23. package/dist/types/components/PageBuilder.vue.d.ts +50 -0
  24. package/dist/types/components/editor/EditorCanvas.vue.d.ts +67 -0
  25. package/dist/types/components/editor/EditorToolbar.vue.d.ts +97 -0
  26. package/dist/types/components/editor/IframeCanvas.vue.d.ts +102 -0
  27. package/dist/types/components/editor/LeftDrawer.vue.d.ts +46 -0
  28. package/dist/types/components/editor/NodeContextMenu.vue.d.ts +66 -0
  29. package/dist/types/components/editor/PageEditor.vue.d.ts +20 -0
  30. package/dist/types/components/editor/RightDrawer.vue.d.ts +43 -0
  31. package/dist/types/components/editor/TreePanel.vue.d.ts +28 -0
  32. package/dist/types/components/editor/prop-editors/MediaPicker.vue.d.ts +20 -0
  33. package/dist/types/components/editor/prop-editors/PropBooleanEditor.vue.d.ts +18 -0
  34. package/dist/types/components/editor/prop-editors/PropColorEditor.vue.d.ts +18 -0
  35. package/dist/types/components/editor/prop-editors/PropNumberEditor.vue.d.ts +36 -0
  36. package/dist/types/components/editor/prop-editors/PropSelectEditor.vue.d.ts +31 -0
  37. package/dist/types/components/editor/prop-editors/PropTextEditor.vue.d.ts +27 -0
  38. package/dist/types/components/editor/prop-editors/RichTextEditor.vue.d.ts +27 -0
  39. package/dist/types/components/editor/prop-editors/index.d.ts +29 -0
  40. package/dist/types/components/reader/NodeRenderer.vue.d.ts +33 -0
  41. package/dist/types/components/reader/PageReader.vue.d.ts +14 -0
  42. package/dist/types/components/shared/ErrorBoundary.vue.d.ts +21 -0
  43. package/dist/types/composables/use-drag-drop.d.ts +23 -0
  44. package/dist/types/composables/use-editor.d.ts +40 -0
  45. package/dist/types/composables/use-node-tree.d.ts +23 -0
  46. package/dist/types/composables/use-page-builder.d.ts +28 -0
  47. package/dist/types/core/drop-slot.d.ts +12 -0
  48. package/dist/types/core/errors.d.ts +14 -0
  49. package/dist/types/core/iframe-bridge.d.ts +85 -0
  50. package/dist/types/core/index.d.ts +18 -0
  51. package/dist/types/core/registry.d.ts +43 -0
  52. package/dist/types/core/sanitize.d.ts +3 -0
  53. package/dist/types/core/tree.d.ts +56 -0
  54. package/dist/types/core/validation.d.ts +10 -0
  55. package/dist/types/core/virtual-tree.d.ts +44 -0
  56. package/dist/types/i18n/context.d.ts +13 -0
  57. package/dist/types/i18n/index.d.ts +3 -0
  58. package/dist/types/i18n/messages.d.ts +3 -0
  59. package/dist/types/i18n/translator.d.ts +14 -0
  60. package/dist/types/index.d.ts +27 -0
  61. package/dist/types/plugin.d.ts +18 -0
  62. package/dist/types/types/component.d.ts +68 -0
  63. package/dist/types/types/editor.d.ts +54 -0
  64. package/dist/types/types/index.d.ts +6 -0
  65. package/dist/types/types/keys.d.ts +13 -0
  66. package/dist/types/types/node.d.ts +54 -0
  67. package/package.json +8 -3
  68. package/dist/index.css +0 -1
@@ -0,0 +1,523 @@
1
+ var E = Object.defineProperty;
2
+ var z = (r, t, e) => t in r ? E(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
3
+ var h = (r, t, e) => z(r, typeof t != "symbol" ? t + "" : t, e);
4
+ class S extends Error {
5
+ constructor(e, n, s = {}) {
6
+ super(n);
7
+ h(this, "code");
8
+ h(this, "details");
9
+ this.name = "PageBuilderError", this.code = e, this.details = s.details ?? {}, this.cause = s.cause;
10
+ }
11
+ }
12
+ function Z(r) {
13
+ return r instanceof S;
14
+ }
15
+ function _(r, t, e = {}) {
16
+ return new S(r, t, e);
17
+ }
18
+ function ee(r) {
19
+ return r instanceof Error ? r.message : String(r);
20
+ }
21
+ function te(r, t, e) {
22
+ }
23
+ const I = /* @__PURE__ */ new Set([
24
+ "div",
25
+ "p",
26
+ "span",
27
+ "h1",
28
+ "h2",
29
+ "h3",
30
+ "h4",
31
+ "h5",
32
+ "h6",
33
+ "section",
34
+ "article",
35
+ "blockquote"
36
+ ]), $ = /* @__PURE__ */ new Set([
37
+ "a",
38
+ "b",
39
+ "blockquote",
40
+ "br",
41
+ "code",
42
+ "div",
43
+ "em",
44
+ "h1",
45
+ "h2",
46
+ "h3",
47
+ "h4",
48
+ "h5",
49
+ "h6",
50
+ "i",
51
+ "li",
52
+ "ol",
53
+ "p",
54
+ "pre",
55
+ "s",
56
+ "span",
57
+ "strong",
58
+ "u",
59
+ "ul"
60
+ ]), L = /* @__PURE__ */ new Set([
61
+ "base",
62
+ "embed",
63
+ "form",
64
+ "iframe",
65
+ "input",
66
+ "link",
67
+ "math",
68
+ "meta",
69
+ "noscript",
70
+ "object",
71
+ "script",
72
+ "style",
73
+ "svg",
74
+ "template",
75
+ "textarea"
76
+ ]), M = /* @__PURE__ */ new Set(["_blank", "_parent", "_self", "_top"]), x = /* @__PURE__ */ new Set(["nofollow", "noopener", "noreferrer", "sponsored", "ugc"]), R = /^data:image\/(?:avif|bmp|gif|jpe?g|png|webp);base64,[a-z0-9+/=\s]+$/i;
77
+ function A(r) {
78
+ return r.replace(/[\u0000-\u001F\u007F]/g, "");
79
+ }
80
+ function D(r) {
81
+ return A(r).replace(/\s+/g, "");
82
+ }
83
+ function P(r) {
84
+ const t = r.toLowerCase().split(/\s+/).filter(Boolean).filter((e) => x.has(e));
85
+ return Array.from(new Set(t)).join(" ");
86
+ }
87
+ function O(r) {
88
+ const t = P(r ?? ""), e = new Set(t.split(/\s+/).filter(Boolean));
89
+ return e.add("noopener"), e.add("noreferrer"), Array.from(e).join(" ");
90
+ }
91
+ function j() {
92
+ var r;
93
+ if (typeof document < "u" && typeof ((r = document.implementation) == null ? void 0 : r.createHTMLDocument) == "function")
94
+ return document.implementation.createHTMLDocument("");
95
+ if (typeof DOMParser < "u") {
96
+ const t = new DOMParser().parseFromString("<!doctype html><html><body></body></html>", "text/html");
97
+ if (t != null && t.body) return t;
98
+ }
99
+ return null;
100
+ }
101
+ function F(r) {
102
+ return r.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
103
+ }
104
+ function V(r, t) {
105
+ const e = t.tagName.toLowerCase();
106
+ for (const n of Array.from(r.attributes)) {
107
+ const s = n.name.toLowerCase(), i = A(n.value).trim();
108
+ if (!(i.length === 0 || s.startsWith("on"))) {
109
+ if (s === "title") {
110
+ t.setAttribute("title", i);
111
+ continue;
112
+ }
113
+ if (e === "a") {
114
+ if (s === "href") {
115
+ const a = f(i, "link");
116
+ a.length > 0 && t.setAttribute("href", a);
117
+ continue;
118
+ }
119
+ if (s === "target") {
120
+ const a = i.toLowerCase();
121
+ M.has(a) && t.setAttribute("target", a);
122
+ continue;
123
+ }
124
+ if (s === "rel") {
125
+ const a = P(i);
126
+ a.length > 0 && t.setAttribute("rel", a);
127
+ }
128
+ }
129
+ }
130
+ }
131
+ e === "a" && t.getAttribute("target") === "_blank" && t.setAttribute("rel", O(t.getAttribute("rel")));
132
+ }
133
+ function y(r, t, e) {
134
+ for (const n of Array.from(r.childNodes)) {
135
+ if (n.nodeType === 3) {
136
+ t.appendChild(e.createTextNode(n.textContent ?? ""));
137
+ continue;
138
+ }
139
+ if (n.nodeType !== 1) continue;
140
+ const s = n, i = s.tagName.toLowerCase();
141
+ if (L.has(i)) continue;
142
+ if (!$.has(i)) {
143
+ const d = e.createDocumentFragment();
144
+ y(s, d, e), t.appendChild(d);
145
+ continue;
146
+ }
147
+ const a = e.createElement(i);
148
+ if (V(s, a), y(s, a, e), i === "a" && !a.getAttribute("href")) {
149
+ const d = e.createDocumentFragment();
150
+ for (; a.firstChild; )
151
+ d.appendChild(a.firstChild);
152
+ t.appendChild(d);
153
+ continue;
154
+ }
155
+ t.appendChild(a);
156
+ }
157
+ }
158
+ function re(r) {
159
+ const t = typeof r == "string" ? r : "";
160
+ if (t.length === 0) return "";
161
+ const e = j();
162
+ if (!e) return F(t);
163
+ const n = e.createElement("div");
164
+ n.innerHTML = t;
165
+ const s = e.createElement("div");
166
+ return y(n, s, e), s.innerHTML;
167
+ }
168
+ function G(r, t = "div") {
169
+ const e = typeof t == "string" ? t.trim().toLowerCase() : "div", n = I.has(e) ? e : "div";
170
+ if (typeof r != "string") return n;
171
+ const s = r.trim().toLowerCase();
172
+ return I.has(s) ? s : n;
173
+ }
174
+ function f(r, t) {
175
+ const e = A(r).trim();
176
+ if (e.length === 0) return "";
177
+ const n = D(e).toLowerCase(), s = n.match(/^([a-z][a-z0-9+.-]*):/i), i = s == null ? void 0 : s[1];
178
+ return !i || i === "http" || i === "https" || t === "link" && (i === "mailto" || i === "tel") || t === "media" && i === "blob" || (t === "media" || t === "background") && i === "data" && R.test(n) ? e : "";
179
+ }
180
+ const B = /* @__PURE__ */ new Set(["draft", "published", "archived"]), w = 200, N = 5e3;
181
+ function m(r) {
182
+ return typeof r == "object" && r !== null && !Array.isArray(r);
183
+ }
184
+ function o(r, t, e) {
185
+ r.errors.push({ path: t, message: e });
186
+ }
187
+ function H(r, t, e) {
188
+ if (r.tag === void 0) return;
189
+ if (typeof r.tag != "string" || r.tag.trim() === "") {
190
+ o(e, `${t}.tag`, "PbText props.tag must be a non-empty string.");
191
+ return;
192
+ }
193
+ const n = r.tag.trim().toLowerCase();
194
+ G(r.tag) !== n && o(
195
+ e,
196
+ `${t}.tag`,
197
+ "PbText props.tag must be one of: div, p, span, h1, h2, h3, h4, h5, h6, section, article, blockquote."
198
+ );
199
+ }
200
+ function K(r, t, e) {
201
+ if (typeof r.src != "string" || r.src.trim() === "") {
202
+ o(e, `${t}.src`, "PbImage props.src must be a non-empty string.");
203
+ return;
204
+ }
205
+ f(r.src, "media") === "" && o(e, `${t}.src`, "PbImage props.src contains an unsafe URL.");
206
+ }
207
+ function U(r, t, e) {
208
+ if (typeof r.src != "string" || r.src.trim() === "") {
209
+ o(e, `${t}.src`, "PbVideo props.src must be a non-empty string.");
210
+ return;
211
+ }
212
+ f(r.src, "media") === "" && o(e, `${t}.src`, "PbVideo props.src contains an unsafe URL.");
213
+ const n = r.poster;
214
+ n != null && n !== "" && (typeof n != "string" ? o(e, `${t}.poster`, "PbVideo props.poster must be a string.") : n.trim() !== "" && f(n, "media") === "" && o(e, `${t}.poster`, "PbVideo props.poster contains an unsafe URL."));
215
+ }
216
+ function W(r, t, e) {
217
+ const n = r.backgroundImage;
218
+ if (!(n == null || n === "")) {
219
+ if (typeof n != "string") {
220
+ o(e, `${t}.backgroundImage`, "PbSection props.backgroundImage must be a string.");
221
+ return;
222
+ }
223
+ n.trim() !== "" && f(n, "background") === "" && o(e, `${t}.backgroundImage`, "PbSection props.backgroundImage contains an unsafe URL.");
224
+ }
225
+ }
226
+ function q(r, t, e, n) {
227
+ if (r === "PbText") {
228
+ H(t, e, n);
229
+ return;
230
+ }
231
+ if (r === "PbImage") {
232
+ K(t, e, n);
233
+ return;
234
+ }
235
+ if (r === "PbVideo") {
236
+ U(t, e, n);
237
+ return;
238
+ }
239
+ r === "PbSection" && W(t, e, n);
240
+ }
241
+ function p(r, t, e, n = 0) {
242
+ if (n > w) {
243
+ e.depthGuardTriggered || (o(
244
+ e,
245
+ t,
246
+ `Maximum node depth (${String(w)}) exceeded during validation.`
247
+ ), e.depthGuardTriggered = !0);
248
+ return;
249
+ }
250
+ if (e.visitedNodeCount >= N) {
251
+ e.sizeGuardTriggered || (o(
252
+ e,
253
+ t,
254
+ `Maximum node count (${String(N)}) exceeded during validation.`
255
+ ), e.sizeGuardTriggered = !0);
256
+ return;
257
+ }
258
+ if (!m(r)) {
259
+ o(e, t, "Node must be an object.");
260
+ return;
261
+ }
262
+ if (e.seenNodes.has(r)) {
263
+ o(e, t, "Cycle detected in node tree.");
264
+ return;
265
+ }
266
+ e.seenNodes.add(r), e.visitedNodeCount++;
267
+ const s = r.id, i = r.name, a = r.slot, d = r.props, u = r.children, c = r.readonly;
268
+ if (!(typeof s == "number" && Number.isInteger(s)) || s <= 0 ? o(e, `${t}.id`, "id must be a positive integer.") : (e.seenIds.has(s) && o(e, `${t}.id`, `Duplicate node id "${s}" found.`), e.seenIds.add(s), s > e.maxObservedId && (e.maxObservedId = s)), (typeof i != "string" || i.trim() === "") && o(e, `${t}.name`, "name must be a non-empty string."), a === null || typeof a == "string" || o(e, `${t}.slot`, "slot must be a string or null."), m(d) ? typeof i == "string" && q(i, d, `${t}.props`, e) : o(e, `${t}.props`, "props must be an object."), !Array.isArray(u)) {
269
+ o(e, `${t}.children`, "children must be an array.");
270
+ return;
271
+ }
272
+ c === void 0 || typeof c == "boolean" || o(e, `${t}.readonly`, "readonly must be a boolean when provided.");
273
+ for (let l = 0; l < u.length && !e.sizeGuardTriggered; l++)
274
+ p(u[l], `${t}.children[${l}]`, e, n + 1);
275
+ }
276
+ function ne(r, t = "node") {
277
+ const e = {
278
+ errors: [],
279
+ seenIds: /* @__PURE__ */ new Set(),
280
+ seenNodes: /* @__PURE__ */ new WeakSet(),
281
+ maxObservedId: 0,
282
+ visitedNodeCount: 0,
283
+ depthGuardTriggered: !1,
284
+ sizeGuardTriggered: !1
285
+ };
286
+ return p(r, t, e), {
287
+ isValid: e.errors.length === 0,
288
+ errors: e.errors
289
+ };
290
+ }
291
+ function ie(r) {
292
+ const t = {
293
+ errors: [],
294
+ seenIds: /* @__PURE__ */ new Set(),
295
+ seenNodes: /* @__PURE__ */ new WeakSet(),
296
+ maxObservedId: 0,
297
+ visitedNodeCount: 0,
298
+ depthGuardTriggered: !1,
299
+ sizeGuardTriggered: !1
300
+ };
301
+ if (!m(r))
302
+ return o(t, "pageData", "pageData must be an object."), {
303
+ isValid: !1,
304
+ errors: t.errors
305
+ };
306
+ const { meta: e, content: n, layout: s, maxId: i, variables: a } = r;
307
+ if (m(e) ? ((typeof e.id != "string" || e.id.trim() === "") && o(t, "meta.id", "meta.id must be a non-empty string."), (typeof e.name != "string" || e.name.trim() === "") && o(t, "meta.name", "meta.name must be a non-empty string."), typeof e.url != "string" || e.url.trim() === "" ? o(t, "meta.url", "meta.url must be a non-empty string.") : f(e.url, "link") === "" && o(t, "meta.url", "meta.url contains an unsafe URL."), (typeof e.status != "string" || !B.has(e.status)) && o(
308
+ t,
309
+ "meta.status",
310
+ "meta.status must be one of: draft, published, archived."
311
+ ), e.updatedAt === void 0 || typeof e.updatedAt == "string" || o(t, "meta.updatedAt", "meta.updatedAt must be a string when provided."), e.createdAt === void 0 || typeof e.createdAt == "string" || o(t, "meta.createdAt", "meta.createdAt must be a string when provided.")) : o(t, "meta", "meta must be an object."), p(n, "content", t), p(s, "layout", t), !(typeof i == "number" && Number.isInteger(i)) || i < 0 ? o(t, "maxId", "maxId must be a non-negative integer.") : i < t.maxObservedId && o(
312
+ t,
313
+ "maxId",
314
+ `maxId (${String(i)}) must be greater than or equal to the maximum node id (${String(t.maxObservedId)}).`
315
+ ), !m(a))
316
+ o(t, "variables", "variables must be an object.");
317
+ else
318
+ for (const [d, u] of Object.entries(a))
319
+ typeof u != "string" && o(t, `variables.${d}`, "Variable values must be strings.");
320
+ return {
321
+ isValid: t.errors.length === 0,
322
+ errors: t.errors
323
+ };
324
+ }
325
+ function b(r) {
326
+ return Array.isArray(r.children) ? r.children : [];
327
+ }
328
+ function k(r, t) {
329
+ const e = Number.isFinite(r) ? Math.trunc(r) : 0;
330
+ return Math.max(0, Math.min(e, t));
331
+ }
332
+ function se(r) {
333
+ try {
334
+ return structuredClone(r);
335
+ } catch (t) {
336
+ throw _(
337
+ "INVALID_NODE",
338
+ "[PageBuilder] Failed to clone node tree. Ensure the tree is serializable and acyclic.",
339
+ {
340
+ cause: t
341
+ }
342
+ );
343
+ }
344
+ }
345
+ function C(r, t) {
346
+ if (r.id === t) return r;
347
+ for (const e of b(r)) {
348
+ const n = C(e, t);
349
+ if (n) return n;
350
+ }
351
+ }
352
+ function T(r, t) {
353
+ const e = b(r);
354
+ for (let n = 0; n < e.length; n++) {
355
+ if (e[n].id === t)
356
+ return { parent: r, index: n };
357
+ const s = T(e[n], t);
358
+ if (s) return s;
359
+ }
360
+ }
361
+ function ae(r, t) {
362
+ const e = T(r, t);
363
+ if (e)
364
+ return e.parent.children.splice(e.index, 1)[0];
365
+ }
366
+ function X(r, t, e, n, s = "default") {
367
+ const i = C(r, t);
368
+ if (!i) return !1;
369
+ Array.isArray(i.children) || (i.children = []);
370
+ const a = k(n, i.children.length), d = { ...e, slot: s };
371
+ return i.children.splice(a, 0, d), !0;
372
+ }
373
+ function oe(r, t, e, n, s = "default") {
374
+ const i = T(r, t);
375
+ if (!i) return !1;
376
+ const a = b(i.parent), [d] = a.splice(i.index, 1);
377
+ if (!d) return !1;
378
+ if (X(r, e, d, n, s)) return !0;
379
+ const c = k(i.index, a.length);
380
+ return a.splice(c, 0, d), !1;
381
+ }
382
+ function de(r, t, e = {}) {
383
+ return {
384
+ id: r,
385
+ name: t,
386
+ slot: e.slot ?? "default",
387
+ props: e.props ?? {},
388
+ children: e.children ?? [],
389
+ readonly: e.readonly
390
+ };
391
+ }
392
+ function v(r, t, e = 0) {
393
+ const n = /* @__PURE__ */ new WeakSet();
394
+ function s(i, a) {
395
+ if (n.has(i)) return !0;
396
+ if (n.add(i), t(i, a) === !1) return !1;
397
+ for (const d of b(i))
398
+ if (s(d, a + 1) === !1) return !1;
399
+ return !0;
400
+ }
401
+ return s(r, e);
402
+ }
403
+ function ue(r) {
404
+ let t = 0;
405
+ return v(r, () => {
406
+ t++;
407
+ }), t;
408
+ }
409
+ function ce(r) {
410
+ let t = r.id;
411
+ return v(r, (e) => {
412
+ Number.isFinite(e.id) && e.id > t && (t = e.id);
413
+ }), t;
414
+ }
415
+ function le(r, t) {
416
+ if (!r || typeof r != "object" || Array.isArray(r))
417
+ return {};
418
+ const e = t && typeof t == "object" && !Array.isArray(t) ? t : {}, n = {};
419
+ for (const [s, i] of Object.entries(r))
420
+ typeof i == "string" ? n[s] = i.replace(/\{\{\s*(\w+)\s*\}\}/g, (a, d) => e[d] ?? `{{ ${d} }}`) : n[s] = i;
421
+ return n;
422
+ }
423
+ function fe(r) {
424
+ const t = [];
425
+ return v(r, (e) => {
426
+ if (e.props.content && typeof e.props.content == "string") {
427
+ const n = e.props.content.replace(/<[^>]*>/g, "");
428
+ n.trim() && t.push(n.trim());
429
+ }
430
+ }), t.join(" ").replace(/\s+/g, " ").trim();
431
+ }
432
+ function g(r) {
433
+ return Number.isFinite(r) ? Math.trunc(r) : 0;
434
+ }
435
+ function Y(r) {
436
+ return `ipb-node-${r}`;
437
+ }
438
+ function me(r, t = {}) {
439
+ const e = t.createKey ?? ((i) => Y(i.id)), n = [], s = [
440
+ { node: r, depth: 0, parentId: null }
441
+ ];
442
+ for (; s.length > 0; ) {
443
+ const i = s.pop();
444
+ if (!i) break;
445
+ const a = n.length;
446
+ n.push({
447
+ node: i.node,
448
+ id: i.node.id,
449
+ key: e(i.node),
450
+ depth: i.depth,
451
+ index: a,
452
+ parentId: i.parentId
453
+ });
454
+ for (let d = i.node.children.length - 1; d >= 0; d--)
455
+ s.push({
456
+ node: i.node.children[d],
457
+ depth: i.depth + 1,
458
+ parentId: i.node.id
459
+ });
460
+ }
461
+ return n;
462
+ }
463
+ function J(r, t, e, n = 0) {
464
+ const s = Math.max(0, g(r)), i = Math.max(0, g(e)), a = Math.max(0, g(n));
465
+ if (s === 0 || i === 0)
466
+ return { start: 0, end: 0, size: 0, total: s };
467
+ const d = s - 1, u = Math.min(Math.max(g(t), 0), d), c = Math.max(0, u - a), l = Math.min(s, u + i + a);
468
+ return {
469
+ start: c,
470
+ end: l,
471
+ size: Math.max(0, l - c),
472
+ total: s
473
+ };
474
+ }
475
+ function ge(r, t, e, n = 0) {
476
+ const s = J(r.length, t, e, n);
477
+ return {
478
+ rows: r.slice(s.start, s.end),
479
+ range: s
480
+ };
481
+ }
482
+ function pe(r) {
483
+ const t = [], e = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
484
+ for (let s = 0; s < r.length; s++) {
485
+ const i = r[s];
486
+ t[s] = i.key, e.has(i.key) || e.set(i.key, s), n.has(i.id) || n.set(i.id, s);
487
+ }
488
+ return {
489
+ keyByIndex: t,
490
+ indexByKey: e,
491
+ indexByNodeId: n
492
+ };
493
+ }
494
+ export {
495
+ S as P,
496
+ f as a,
497
+ ne as b,
498
+ _ as c,
499
+ T as d,
500
+ se as e,
501
+ C as f,
502
+ ce as g,
503
+ de as h,
504
+ le as i,
505
+ X as j,
506
+ ae as k,
507
+ me as l,
508
+ oe as m,
509
+ G as n,
510
+ J as o,
511
+ ue as p,
512
+ Y as q,
513
+ te as r,
514
+ re as s,
515
+ ee as t,
516
+ pe as u,
517
+ ie as v,
518
+ fe as w,
519
+ Z as x,
520
+ ge as y,
521
+ v as z
522
+ };
523
+ //# sourceMappingURL=index-c6HOrx9r.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-c6HOrx9r.js","sources":["../src/core/errors.ts","../src/core/sanitize.ts","../src/core/validation.ts","../src/core/tree.ts","../src/core/virtual-tree.ts"],"sourcesContent":["export type PageBuilderErrorCode =\n | 'INVALID_PAGE_DATA'\n | 'INVALID_NODE'\n | 'INVALID_SNAPSHOT'\n | 'MISSING_COMPONENT'\n | 'DUPLICATE_COMPONENT'\n | 'RENDER_FAILURE'\n | 'UNKNOWN';\n\nexport interface PageBuilderErrorOptions {\n details?: Record<string, unknown>;\n cause?: unknown;\n}\n\nexport class PageBuilderError extends Error {\n readonly code: PageBuilderErrorCode;\n readonly details: Record<string, unknown>;\n\n constructor(code: PageBuilderErrorCode, message: string, options: PageBuilderErrorOptions = {}) {\n super(message);\n this.name = 'PageBuilderError';\n this.code = code;\n this.details = options.details ?? {};\n this.cause = options.cause;\n }\n}\n\nexport function isPageBuilderError(error: unknown): error is PageBuilderError {\n return error instanceof PageBuilderError;\n}\n\nexport function createPageBuilderError(\n code: PageBuilderErrorCode,\n message: string,\n options: PageBuilderErrorOptions = {},\n): PageBuilderError {\n return new PageBuilderError(code, message, options);\n}\n\nexport function toErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\nexport function reportDevDiagnostic(\n context: string,\n error: unknown,\n details?: Record<string, unknown>,\n): void {\n if (!import.meta.env.DEV) return;\n const normalized = isPageBuilderError(error)\n ? error\n : createPageBuilderError('UNKNOWN', toErrorMessage(error), {\n cause: error,\n details,\n });\n\n const mergedDetails = details\n ? {\n ...normalized.details,\n ...details,\n }\n : normalized.details;\n\n console.error(`[PageBuilder][${context}] ${normalized.message}`, {\n code: normalized.code,\n details: mergedDetails,\n cause: normalized.cause,\n });\n}\n","const SAFE_TEXT_CONTAINER_TAGS = new Set([\n 'div',\n 'p',\n 'span',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'section',\n 'article',\n 'blockquote',\n]);\n\nconst SAFE_RICH_TEXT_TAGS = new Set([\n 'a',\n 'b',\n 'blockquote',\n 'br',\n 'code',\n 'div',\n 'em',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'i',\n 'li',\n 'ol',\n 'p',\n 'pre',\n 's',\n 'span',\n 'strong',\n 'u',\n 'ul',\n]);\n\nconst DROP_ENTIRELY_TAGS = new Set([\n 'base',\n 'embed',\n 'form',\n 'iframe',\n 'input',\n 'link',\n 'math',\n 'meta',\n 'noscript',\n 'object',\n 'script',\n 'style',\n 'svg',\n 'template',\n 'textarea',\n]);\n\nconst SAFE_LINK_TARGETS = new Set(['_blank', '_parent', '_self', '_top']);\nconst SAFE_LINK_REL_TOKENS = new Set(['nofollow', 'noopener', 'noreferrer', 'sponsored', 'ugc']);\nconst SAFE_DATA_IMAGE_URL_PATTERN = /^data:image\\/(?:avif|bmp|gif|jpe?g|png|webp);base64,[a-z0-9+/=\\s]+$/i;\n\nfunction stripControlCharacters(value: string): string {\n return value.replace(/[\\u0000-\\u001F\\u007F]/g, '');\n}\n\nfunction normalizeProtocolProbe(value: string): string {\n return stripControlCharacters(value).replace(/\\s+/g, '');\n}\n\nfunction sanitizeLinkRel(rel: string): string {\n const safeTokens = rel\n .toLowerCase()\n .split(/\\s+/)\n .filter(Boolean)\n .filter((token) => SAFE_LINK_REL_TOKENS.has(token));\n return Array.from(new Set(safeTokens)).join(' ');\n}\n\nfunction withSafeBlankTargetRel(existingRel: string | null): string {\n const safeRel = sanitizeLinkRel(existingRel ?? '');\n const relTokens = new Set(safeRel.split(/\\s+/).filter(Boolean));\n relTokens.add('noopener');\n relTokens.add('noreferrer');\n return Array.from(relTokens).join(' ');\n}\n\nfunction createSanitizationDocument(): Document | null {\n if (\n typeof document !== 'undefined'\n && typeof document.implementation?.createHTMLDocument === 'function'\n ) {\n return document.implementation.createHTMLDocument('');\n }\n\n if (typeof DOMParser !== 'undefined') {\n const parsed = new DOMParser().parseFromString('<!doctype html><html><body></body></html>', 'text/html');\n if (parsed?.body) return parsed;\n }\n\n return null;\n}\n\nfunction escapeHtml(rawHtml: string): string {\n return rawHtml\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;');\n}\n\nfunction sanitizeRichTextAttributes(source: Element, target: HTMLElement): void {\n const tagName = target.tagName.toLowerCase();\n\n for (const attribute of Array.from(source.attributes)) {\n const attrName = attribute.name.toLowerCase();\n const attrValue = stripControlCharacters(attribute.value).trim();\n\n if (attrValue.length === 0 || attrName.startsWith('on')) continue;\n\n if (attrName === 'title') {\n target.setAttribute('title', attrValue);\n continue;\n }\n\n if (tagName !== 'a') continue;\n\n if (attrName === 'href') {\n const sanitizedHref = sanitizeUrlByKind(attrValue, 'link');\n if (sanitizedHref.length > 0) target.setAttribute('href', sanitizedHref);\n continue;\n }\n\n if (attrName === 'target') {\n const normalizedTarget = attrValue.toLowerCase();\n if (SAFE_LINK_TARGETS.has(normalizedTarget)) {\n target.setAttribute('target', normalizedTarget);\n }\n continue;\n }\n\n if (attrName === 'rel') {\n const sanitizedRel = sanitizeLinkRel(attrValue);\n if (sanitizedRel.length > 0) target.setAttribute('rel', sanitizedRel);\n }\n }\n\n if (tagName === 'a' && target.getAttribute('target') === '_blank') {\n target.setAttribute('rel', withSafeBlankTargetRel(target.getAttribute('rel')));\n }\n}\n\nfunction sanitizeRichTextChildren(source: ParentNode, target: ParentNode, doc: Document): void {\n for (const node of Array.from(source.childNodes)) {\n if (node.nodeType === 3) {\n target.appendChild(doc.createTextNode(node.textContent ?? ''));\n continue;\n }\n\n if (node.nodeType !== 1) continue;\n\n const sourceElement = node as Element;\n const sourceTagName = sourceElement.tagName.toLowerCase();\n\n if (DROP_ENTIRELY_TAGS.has(sourceTagName)) continue;\n\n if (!SAFE_RICH_TEXT_TAGS.has(sourceTagName)) {\n const unwrappedChildren = doc.createDocumentFragment();\n sanitizeRichTextChildren(sourceElement, unwrappedChildren, doc);\n target.appendChild(unwrappedChildren);\n continue;\n }\n\n const sanitizedElement = doc.createElement(sourceTagName);\n sanitizeRichTextAttributes(sourceElement, sanitizedElement);\n sanitizeRichTextChildren(sourceElement, sanitizedElement, doc);\n\n if (sourceTagName === 'a' && !sanitizedElement.getAttribute('href')) {\n const safeChildren = doc.createDocumentFragment();\n while (sanitizedElement.firstChild) {\n safeChildren.appendChild(sanitizedElement.firstChild);\n }\n target.appendChild(safeChildren);\n continue;\n }\n\n target.appendChild(sanitizedElement);\n }\n}\n\nexport function sanitizeRichTextHtml(html: string): string {\n const rawHtml = typeof html === 'string' ? html : '';\n if (rawHtml.length === 0) return '';\n\n const doc = createSanitizationDocument();\n if (!doc) return escapeHtml(rawHtml);\n\n const source = doc.createElement('div');\n source.innerHTML = rawHtml;\n\n const output = doc.createElement('div');\n sanitizeRichTextChildren(source, output, doc);\n return output.innerHTML;\n}\n\nexport function normalizeSafeHtmlTag(tag: unknown, fallback = 'div'): string {\n const normalizedFallback = typeof fallback === 'string' ? fallback.trim().toLowerCase() : 'div';\n const safeFallback = SAFE_TEXT_CONTAINER_TAGS.has(normalizedFallback) ? normalizedFallback : 'div';\n if (typeof tag !== 'string') return safeFallback;\n\n const normalizedTag = tag.trim().toLowerCase();\n if (!SAFE_TEXT_CONTAINER_TAGS.has(normalizedTag)) return safeFallback;\n return normalizedTag;\n}\n\nexport function sanitizeUrlByKind(url: string, kind: 'link' | 'media' | 'background'): string {\n const sanitizedInput = stripControlCharacters(url).trim();\n if (sanitizedInput.length === 0) return '';\n\n const protocolProbe = normalizeProtocolProbe(sanitizedInput).toLowerCase();\n const schemeMatch = protocolProbe.match(/^([a-z][a-z0-9+.-]*):/i);\n const scheme = schemeMatch?.[1];\n\n if (!scheme) return sanitizedInput;\n\n if (scheme === 'http' || scheme === 'https') return sanitizedInput;\n\n if (kind === 'link' && (scheme === 'mailto' || scheme === 'tel')) {\n return sanitizedInput;\n }\n\n if (kind === 'media' && scheme === 'blob') {\n return sanitizedInput;\n }\n\n if ((kind === 'media' || kind === 'background') && scheme === 'data') {\n return SAFE_DATA_IMAGE_URL_PATTERN.test(protocolProbe) ? sanitizedInput : '';\n }\n\n return '';\n}\n","import type { INode, IPageData, IPageMeta } from '@/types/node';\nimport { normalizeSafeHtmlTag, sanitizeUrlByKind } from '@/core/sanitize';\n\nexport interface IValidationError {\n path: string;\n message: string;\n}\n\nexport interface IValidationResult {\n isValid: boolean;\n errors: IValidationError[];\n}\n\ninterface IValidationContext {\n errors: IValidationError[];\n seenIds: Set<number>;\n seenNodes: WeakSet<object>;\n maxObservedId: number;\n visitedNodeCount: number;\n depthGuardTriggered: boolean;\n sizeGuardTriggered: boolean;\n}\n\nconst PAGE_STATUSES = new Set<IPageMeta['status']>(['draft', 'published', 'archived']);\nconst MAX_VALIDATION_DEPTH = 200;\nconst MAX_VALIDATION_NODE_COUNT = 5000;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction addError(context: IValidationContext, path: string, message: string): void {\n context.errors.push({ path, message });\n}\n\nfunction validatePbTextProps(\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n if (props.tag === undefined) return;\n\n if (typeof props.tag !== 'string' || props.tag.trim() === '') {\n addError(context, `${path}.tag`, 'PbText props.tag must be a non-empty string.');\n return;\n }\n\n const normalizedTag = props.tag.trim().toLowerCase();\n if (normalizeSafeHtmlTag(props.tag) !== normalizedTag) {\n addError(\n context,\n `${path}.tag`,\n 'PbText props.tag must be one of: div, p, span, h1, h2, h3, h4, h5, h6, section, article, blockquote.',\n );\n }\n}\n\nfunction validatePbImageProps(\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n if (typeof props.src !== 'string' || props.src.trim() === '') {\n addError(context, `${path}.src`, 'PbImage props.src must be a non-empty string.');\n return;\n }\n\n if (sanitizeUrlByKind(props.src, 'media') === '') {\n addError(context, `${path}.src`, 'PbImage props.src contains an unsafe URL.');\n }\n}\n\nfunction validatePbVideoProps(\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n if (typeof props.src !== 'string' || props.src.trim() === '') {\n addError(context, `${path}.src`, 'PbVideo props.src must be a non-empty string.');\n return;\n }\n\n if (sanitizeUrlByKind(props.src, 'media') === '') {\n addError(context, `${path}.src`, 'PbVideo props.src contains an unsafe URL.');\n }\n\n const poster = props.poster;\n if (poster !== undefined && poster !== null && poster !== '') {\n if (typeof poster !== 'string') {\n addError(context, `${path}.poster`, 'PbVideo props.poster must be a string.');\n } else if (poster.trim() !== '' && sanitizeUrlByKind(poster, 'media') === '') {\n addError(context, `${path}.poster`, 'PbVideo props.poster contains an unsafe URL.');\n }\n }\n}\n\nfunction validatePbSectionProps(\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n const backgroundImage = props.backgroundImage;\n if (backgroundImage === undefined || backgroundImage === null || backgroundImage === '') return;\n\n if (typeof backgroundImage !== 'string') {\n addError(context, `${path}.backgroundImage`, 'PbSection props.backgroundImage must be a string.');\n return;\n }\n\n if (backgroundImage.trim() !== '' && sanitizeUrlByKind(backgroundImage, 'background') === '') {\n addError(context, `${path}.backgroundImage`, 'PbSection props.backgroundImage contains an unsafe URL.');\n }\n}\n\nfunction validateKnownComponentPropsInto(\n name: string,\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n if (name === 'PbText') {\n validatePbTextProps(props, path, context);\n return;\n }\n\n if (name === 'PbImage') {\n validatePbImageProps(props, path, context);\n return;\n }\n\n if (name === 'PbVideo') {\n validatePbVideoProps(props, path, context);\n return;\n }\n\n if (name === 'PbSection') {\n validatePbSectionProps(props, path, context);\n }\n}\n\nfunction validateNodeInto(node: unknown, path: string, context: IValidationContext, depth = 0): void {\n if (depth > MAX_VALIDATION_DEPTH) {\n if (!context.depthGuardTriggered) {\n addError(\n context,\n path,\n `Maximum node depth (${String(MAX_VALIDATION_DEPTH)}) exceeded during validation.`,\n );\n context.depthGuardTriggered = true;\n }\n return;\n }\n\n if (context.visitedNodeCount >= MAX_VALIDATION_NODE_COUNT) {\n if (!context.sizeGuardTriggered) {\n addError(\n context,\n path,\n `Maximum node count (${String(MAX_VALIDATION_NODE_COUNT)}) exceeded during validation.`,\n );\n context.sizeGuardTriggered = true;\n }\n return;\n }\n\n if (!isRecord(node)) {\n addError(context, path, 'Node must be an object.');\n return;\n }\n\n if (context.seenNodes.has(node)) {\n addError(context, path, 'Cycle detected in node tree.');\n return;\n }\n context.seenNodes.add(node);\n context.visitedNodeCount++;\n\n const id = node.id;\n const name = node.name;\n const slot = node.slot;\n const props = node.props;\n const children = node.children;\n const readonly = node.readonly;\n\n if (!(typeof id === 'number' && Number.isInteger(id)) || id <= 0) {\n addError(context, `${path}.id`, 'id must be a positive integer.');\n } else {\n if (context.seenIds.has(id)) {\n addError(context, `${path}.id`, `Duplicate node id \"${id}\" found.`);\n }\n context.seenIds.add(id);\n if (id > context.maxObservedId) context.maxObservedId = id;\n }\n\n if (typeof name !== 'string' || name.trim() === '') {\n addError(context, `${path}.name`, 'name must be a non-empty string.');\n }\n\n if (!(slot === null || typeof slot === 'string')) {\n addError(context, `${path}.slot`, 'slot must be a string or null.');\n }\n\n if (!isRecord(props)) {\n addError(context, `${path}.props`, 'props must be an object.');\n } else if (typeof name === 'string') {\n validateKnownComponentPropsInto(name, props, `${path}.props`, context);\n }\n\n if (!Array.isArray(children)) {\n addError(context, `${path}.children`, 'children must be an array.');\n return;\n }\n\n if (!(readonly === undefined || typeof readonly === 'boolean')) {\n addError(context, `${path}.readonly`, 'readonly must be a boolean when provided.');\n }\n\n for (let index = 0; index < children.length; index++) {\n if (context.sizeGuardTriggered) break;\n validateNodeInto(children[index], `${path}.children[${index}]`, context, depth + 1);\n }\n}\n\nexport function validateNode(node: unknown, path = 'node'): IValidationResult {\n const context: IValidationContext = {\n errors: [],\n seenIds: new Set<number>(),\n seenNodes: new WeakSet<object>(),\n maxObservedId: 0,\n visitedNodeCount: 0,\n depthGuardTriggered: false,\n sizeGuardTriggered: false,\n };\n\n validateNodeInto(node, path, context);\n\n return {\n isValid: context.errors.length === 0,\n errors: context.errors,\n };\n}\n\nexport function validatePageData(pageData: unknown): IValidationResult {\n const context: IValidationContext = {\n errors: [],\n seenIds: new Set<number>(),\n seenNodes: new WeakSet<object>(),\n maxObservedId: 0,\n visitedNodeCount: 0,\n depthGuardTriggered: false,\n sizeGuardTriggered: false,\n };\n\n if (!isRecord(pageData)) {\n addError(context, 'pageData', 'pageData must be an object.');\n return {\n isValid: false,\n errors: context.errors,\n };\n }\n\n const { meta, content, layout, maxId, variables } = pageData;\n\n if (!isRecord(meta)) {\n addError(context, 'meta', 'meta must be an object.');\n } else {\n if (typeof meta.id !== 'string' || meta.id.trim() === '') {\n addError(context, 'meta.id', 'meta.id must be a non-empty string.');\n }\n if (typeof meta.name !== 'string' || meta.name.trim() === '') {\n addError(context, 'meta.name', 'meta.name must be a non-empty string.');\n }\n if (typeof meta.url !== 'string' || meta.url.trim() === '') {\n addError(context, 'meta.url', 'meta.url must be a non-empty string.');\n } else if (sanitizeUrlByKind(meta.url, 'link') === '') {\n addError(context, 'meta.url', 'meta.url contains an unsafe URL.');\n }\n if (typeof meta.status !== 'string' || !PAGE_STATUSES.has(meta.status as IPageMeta['status'])) {\n addError(\n context,\n 'meta.status',\n 'meta.status must be one of: draft, published, archived.',\n );\n }\n if (!(meta.updatedAt === undefined || typeof meta.updatedAt === 'string')) {\n addError(context, 'meta.updatedAt', 'meta.updatedAt must be a string when provided.');\n }\n if (!(meta.createdAt === undefined || typeof meta.createdAt === 'string')) {\n addError(context, 'meta.createdAt', 'meta.createdAt must be a string when provided.');\n }\n }\n\n validateNodeInto(content, 'content', context);\n validateNodeInto(layout, 'layout', context);\n\n if (!(typeof maxId === 'number' && Number.isInteger(maxId)) || maxId < 0) {\n addError(context, 'maxId', 'maxId must be a non-negative integer.');\n } else if (maxId < context.maxObservedId) {\n addError(\n context,\n 'maxId',\n `maxId (${String(maxId)}) must be greater than or equal to the maximum node id (${String(context.maxObservedId)}).`,\n );\n }\n\n if (!isRecord(variables)) {\n addError(context, 'variables', 'variables must be an object.');\n } else {\n for (const [key, value] of Object.entries(variables)) {\n if (typeof value !== 'string') {\n addError(context, `variables.${key}`, 'Variable values must be strings.');\n }\n }\n }\n\n return {\n isValid: context.errors.length === 0,\n errors: context.errors,\n };\n}\n","import type { INode } from '@/types/node';\nimport { createPageBuilderError } from '@/core/errors';\n\nfunction getChildren(node: INode): INode[] {\n return Array.isArray(node.children) ? node.children : [];\n}\n\nfunction clampIndex(index: number, length: number): number {\n const normalized = Number.isFinite(index) ? Math.trunc(index) : 0;\n return Math.max(0, Math.min(normalized, length));\n}\n\n/**\n * Deep clone a node tree using structured clone.\n */\nexport function cloneTree(node: INode): INode {\n try {\n return structuredClone(node);\n } catch (error) {\n throw createPageBuilderError(\n 'INVALID_NODE',\n '[PageBuilder] Failed to clone node tree. Ensure the tree is serializable and acyclic.',\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Find a node by ID in the tree. Returns undefined if not found.\n */\nexport function findNodeById(root: INode, id: number): INode | undefined {\n if (root.id === id) return root;\n for (const child of getChildren(root)) {\n const found = findNodeById(child, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/**\n * Find the parent of a node by the child's ID.\n * Returns the parent node and the child's index, or undefined.\n */\nexport function findParent(\n root: INode,\n childId: number,\n): { parent: INode; index: number } | undefined {\n const children = getChildren(root);\n for (let i = 0; i < children.length; i++) {\n if (children[i].id === childId) {\n return { parent: root, index: i };\n }\n const found = findParent(children[i], childId);\n if (found) return found;\n }\n return undefined;\n}\n\n/**\n * Remove a node by ID from the tree. Returns the removed node or undefined.\n */\nexport function removeNode(root: INode, id: number): INode | undefined {\n const result = findParent(root, id);\n if (!result) return undefined;\n return result.parent.children.splice(result.index, 1)[0];\n}\n\n/**\n * Insert a node as a child of a target node at a specific index and slot.\n */\nexport function insertNode(\n root: INode,\n parentId: number,\n node: INode,\n index: number,\n slot: string = 'default',\n): boolean {\n const parent = findNodeById(root, parentId);\n if (!parent) return false;\n if (!Array.isArray(parent.children)) {\n parent.children = [];\n }\n\n const targetIndex = clampIndex(index, parent.children.length);\n const insertedNode = { ...node, slot };\n parent.children.splice(targetIndex, 0, insertedNode);\n return true;\n}\n\n/**\n * Move a node within the tree to a new parent at a specific index.\n */\nexport function moveNode(\n root: INode,\n nodeId: number,\n newParentId: number,\n index: number,\n slot: string = 'default',\n): boolean {\n const sourceParentResult = findParent(root, nodeId);\n if (!sourceParentResult) return false;\n\n const sourceChildren = getChildren(sourceParentResult.parent);\n const [node] = sourceChildren.splice(sourceParentResult.index, 1);\n if (!node) return false;\n\n const moved = insertNode(root, newParentId, node, index, slot);\n if (moved) return true;\n\n // Roll back on failure so the caller never loses nodes due to invalid moves.\n const rollbackIndex = clampIndex(sourceParentResult.index, sourceChildren.length);\n sourceChildren.splice(rollbackIndex, 0, node);\n return false;\n}\n\n/**\n * Create a new node with default values and a given ID.\n */\nexport function createNode(\n id: number,\n name: string,\n options: Partial<Pick<INode, 'slot' | 'props' | 'children' | 'readonly'>> = {},\n): INode {\n return {\n id,\n name,\n slot: options.slot ?? 'default',\n props: options.props ?? {},\n children: options.children ?? [],\n readonly: options.readonly,\n };\n}\n\n/**\n * Walk the tree depth-first and call visitor for each node.\n * Return `false` from visitor to stop the entire traversal (not just the subtree).\n */\nexport function walkTree(root: INode, visitor: (node: INode, depth: number) => boolean | void, depth = 0): boolean {\n const visited = new WeakSet<object>();\n\n function visitNode(node: INode, currentDepth: number): boolean {\n if (visited.has(node as object)) return true;\n visited.add(node as object);\n\n if (visitor(node, currentDepth) === false) return false;\n for (const child of getChildren(node)) {\n if (visitNode(child, currentDepth + 1) === false) return false;\n }\n return true;\n }\n\n return visitNode(root, depth);\n}\n\n/**\n * Count the total number of nodes in the tree.\n */\nexport function countNodes(root: INode): number {\n let count = 0;\n walkTree(root, () => { count++; });\n return count;\n}\n\n/**\n * Get the maximum ID in the tree.\n */\nexport function getMaxId(root: INode): number {\n let max = root.id;\n walkTree(root, (node) => {\n if (Number.isFinite(node.id) && node.id > max) max = node.id;\n });\n return max;\n}\n\n/**\n * Interpolate template variables in node props.\n * Replaces `{{ VAR }}` patterns with values from the variables map.\n */\nexport function interpolateProps(\n props: Record<string, unknown>,\n variables: Record<string, string>,\n): Record<string, unknown> {\n if (!props || typeof props !== 'object' || Array.isArray(props)) {\n return {};\n }\n\n const safeVariables =\n variables && typeof variables === 'object' && !Array.isArray(variables) ? variables : {};\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props)) {\n if (typeof value === 'string') {\n result[key] = value.replace(/\\{\\{\\s*(\\w+)\\s*\\}\\}/g, (_, varName: string) => {\n return safeVariables[varName] ?? `{{ ${varName} }}`;\n });\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\n/**\n * Extract plain text from a node tree by collecting text content\n * from PbText (and similar) components and stripping HTML tags.\n */\nexport function extractPlainText(node: INode): string {\n const texts: string[] = [];\n walkTree(node, (n) => {\n if (n.props.content && typeof n.props.content === 'string') {\n const stripped = n.props.content.replace(/<[^>]*>/g, '');\n if (stripped.trim()) texts.push(stripped.trim());\n }\n });\n return texts.join(' ').replace(/\\s+/g, ' ').trim();\n}\n","import type { INode } from '@/types/node';\n\nexport interface IVirtualTreeRow {\n node: INode;\n id: number;\n key: string;\n depth: number;\n index: number;\n parentId: number | null;\n}\n\nexport interface IVirtualWindowRange {\n start: number;\n end: number;\n size: number;\n total: number;\n}\n\nexport interface IVirtualTreeIndexMaps {\n keyByIndex: string[];\n indexByKey: Map<string, number>;\n indexByNodeId: Map<number, number>;\n}\n\nexport interface IFlattenTreeOptions {\n createKey?: (node: INode) => string;\n}\n\nfunction toSafeInteger(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.trunc(value);\n}\n\nexport function createStableNodeKey(nodeId: number): string {\n return `ipb-node-${nodeId}`;\n}\n\n/**\n * Flatten a node tree in depth-first pre-order with depth metadata.\n * Uses an iterative stack to avoid recursion depth issues on large trees.\n */\nexport function flattenTree(root: INode, options: IFlattenTreeOptions = {}): IVirtualTreeRow[] {\n const createKey = options.createKey ?? ((node: INode) => createStableNodeKey(node.id));\n const rows: IVirtualTreeRow[] = [];\n const stack: Array<{ node: INode; depth: number; parentId: number | null }> = [\n { node: root, depth: 0, parentId: null },\n ];\n\n while (stack.length > 0) {\n const current = stack.pop();\n if (!current) break;\n\n const index = rows.length;\n rows.push({\n node: current.node,\n id: current.node.id,\n key: createKey(current.node),\n depth: current.depth,\n index,\n parentId: current.parentId,\n });\n\n for (let i = current.node.children.length - 1; i >= 0; i--) {\n stack.push({\n node: current.node.children[i],\n depth: current.depth + 1,\n parentId: current.node.id,\n });\n }\n }\n\n return rows;\n}\n\n/**\n * Compute a clamped window range over a flat list.\n */\nexport function computeWindowRange(\n total: number,\n startIndex: number,\n windowSize: number,\n overscan = 0,\n): IVirtualWindowRange {\n const safeTotal = Math.max(0, toSafeInteger(total));\n const safeWindowSize = Math.max(0, toSafeInteger(windowSize));\n const safeOverscan = Math.max(0, toSafeInteger(overscan));\n\n if (safeTotal === 0 || safeWindowSize === 0) {\n return { start: 0, end: 0, size: 0, total: safeTotal };\n }\n\n const maxStart = safeTotal - 1;\n const safeStartIndex = Math.min(Math.max(toSafeInteger(startIndex), 0), maxStart);\n const start = Math.max(0, safeStartIndex - safeOverscan);\n const end = Math.min(safeTotal, safeStartIndex + safeWindowSize + safeOverscan);\n\n return {\n start,\n end,\n size: Math.max(0, end - start),\n total: safeTotal,\n };\n}\n\n/**\n * Slice a list using a computed virtual window.\n */\nexport function sliceWindow<T>(\n rows: readonly T[],\n startIndex: number,\n windowSize: number,\n overscan = 0,\n): { rows: T[]; range: IVirtualWindowRange } {\n const range = computeWindowRange(rows.length, startIndex, windowSize, overscan);\n return {\n rows: rows.slice(range.start, range.end),\n range,\n };\n}\n\n/**\n * Build stable key/index lookup maps from flattened tree rows.\n */\nexport function createVirtualTreeIndexMaps(rows: readonly IVirtualTreeRow[]): IVirtualTreeIndexMaps {\n const keyByIndex: string[] = [];\n const indexByKey = new Map<string, number>();\n const indexByNodeId = new Map<number, number>();\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n keyByIndex[i] = row.key;\n\n if (!indexByKey.has(row.key)) {\n indexByKey.set(row.key, i);\n }\n\n if (!indexByNodeId.has(row.id)) {\n indexByNodeId.set(row.id, i);\n }\n }\n\n return {\n keyByIndex,\n indexByKey,\n indexByNodeId,\n };\n}\n"],"names":["PageBuilderError","code","message","options","__publicField","isPageBuilderError","error","createPageBuilderError","toErrorMessage","reportDevDiagnostic","context","details","SAFE_TEXT_CONTAINER_TAGS","SAFE_RICH_TEXT_TAGS","DROP_ENTIRELY_TAGS","SAFE_LINK_TARGETS","SAFE_LINK_REL_TOKENS","SAFE_DATA_IMAGE_URL_PATTERN","stripControlCharacters","value","normalizeProtocolProbe","sanitizeLinkRel","rel","safeTokens","token","withSafeBlankTargetRel","existingRel","safeRel","relTokens","createSanitizationDocument","_a","parsed","escapeHtml","rawHtml","sanitizeRichTextAttributes","source","target","tagName","attribute","attrName","attrValue","sanitizedHref","sanitizeUrlByKind","normalizedTarget","sanitizedRel","sanitizeRichTextChildren","doc","node","sourceElement","sourceTagName","unwrappedChildren","sanitizedElement","safeChildren","sanitizeRichTextHtml","html","output","normalizeSafeHtmlTag","tag","fallback","normalizedFallback","safeFallback","normalizedTag","url","kind","sanitizedInput","protocolProbe","schemeMatch","scheme","PAGE_STATUSES","MAX_VALIDATION_DEPTH","MAX_VALIDATION_NODE_COUNT","isRecord","addError","path","validatePbTextProps","props","validatePbImageProps","validatePbVideoProps","poster","validatePbSectionProps","backgroundImage","validateKnownComponentPropsInto","name","validateNodeInto","depth","id","slot","children","readonly","index","validateNode","validatePageData","pageData","meta","content","layout","maxId","variables","key","getChildren","clampIndex","length","normalized","cloneTree","findNodeById","root","child","found","findParent","childId","i","removeNode","result","insertNode","parentId","parent","targetIndex","insertedNode","moveNode","nodeId","newParentId","sourceParentResult","sourceChildren","rollbackIndex","createNode","walkTree","visitor","visited","visitNode","currentDepth","countNodes","count","getMaxId","max","interpolateProps","safeVariables","_","varName","extractPlainText","texts","n","stripped","toSafeInteger","createStableNodeKey","flattenTree","createKey","rows","stack","current","computeWindowRange","total","startIndex","windowSize","overscan","safeTotal","safeWindowSize","safeOverscan","maxStart","safeStartIndex","start","end","sliceWindow","range","createVirtualTreeIndexMaps","keyByIndex","indexByKey","indexByNodeId","row"],"mappings":"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"}