@improba/page-builder 0.1.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.
package/dist/index.js ADDED
@@ -0,0 +1,4477 @@
1
+ var zn = Object.defineProperty;
2
+ var jn = (t, r, n) => r in t ? zn(t, r, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[r] = n;
3
+ var Dt = (t, r, n) => jn(t, typeof r != "symbol" ? r + "" : r, n);
4
+ import { defineComponent as G, computed as N, openBlock as x, createElementBlock as C, normalizeStyle as J, renderSlot as Ze, createBlock as Se, resolveDynamicComponent as Mt, createCommentVNode as Y, createElementVNode as S, inject as je, ref as R, onErrorCaptured as Hn, toDisplayString as z, resolveComponent as Wn, withCtx as Pt, normalizeProps as Un, guardReactiveProps as Kn, createSlots as Fn, renderList as ve, Fragment as he, watch as de, createVNode as Re, reactive as $n, toRefs as Gn, toRaw as qn, nextTick as ue, normalizeClass as _e, withDirectives as Yn, vModelText as Xn, useAttrs as dt, mergeProps as He, onMounted as Ot, onBeforeUnmount as dn, withModifiers as Et, render as Zt, h as Zn, onUnmounted as Jn, provide as qe } from "vue";
5
+ class cn extends Error {
6
+ constructor(n, e, o = {}) {
7
+ super(e);
8
+ Dt(this, "code");
9
+ Dt(this, "details");
10
+ this.name = "PageBuilderError", this.code = n, this.details = o.details ?? {}, this.cause = o.cause;
11
+ }
12
+ }
13
+ function Qn(t) {
14
+ return t instanceof cn;
15
+ }
16
+ function Z(t, r, n = {}) {
17
+ return new cn(t, r, n);
18
+ }
19
+ function Bt(t) {
20
+ return t instanceof Error ? t.message : String(t);
21
+ }
22
+ function Ue(t, r, n) {
23
+ const e = Qn(r) ? r : Z("UNKNOWN", Bt(r), {
24
+ cause: r,
25
+ details: n
26
+ }), o = n ? {
27
+ ...e.details,
28
+ ...n
29
+ } : e.details;
30
+ console.error(`[PageBuilder][${t}] ${e.message}`, {
31
+ code: e.code,
32
+ details: o,
33
+ cause: e.cause
34
+ });
35
+ }
36
+ const ie = /* @__PURE__ */ new Map();
37
+ function er() {
38
+ const t = [...ie.keys()];
39
+ return t.length > 0 ? t.join(", ") : "(none)";
40
+ }
41
+ function Je(t) {
42
+ return t.trim();
43
+ }
44
+ function Rt(t, r) {
45
+ return Z(
46
+ "DUPLICATE_COMPONENT",
47
+ r,
48
+ {
49
+ details: {
50
+ componentName: t
51
+ }
52
+ }
53
+ );
54
+ }
55
+ function zt(t, r) {
56
+ const n = Je(t.name), e = n === t.name ? t : { ...t, name: n };
57
+ if (!n)
58
+ throw Z(
59
+ "INVALID_PAGE_DATA",
60
+ `[PageBuilder] Cannot ${r} a component without a name.`
61
+ );
62
+ if (!e.component)
63
+ throw Z(
64
+ "INVALID_PAGE_DATA",
65
+ `[PageBuilder] Component "${n}" is missing a Vue component instance.`
66
+ );
67
+ return e;
68
+ }
69
+ function ll(t) {
70
+ const r = zt(t, "register"), n = r.name;
71
+ if (ie.has(n))
72
+ throw Rt(
73
+ n,
74
+ `[PageBuilder] Component "${n}" is already registered. Use replaceComponent() to override.`
75
+ );
76
+ ie.set(n, r);
77
+ }
78
+ function tr(t) {
79
+ const r = t.map(
80
+ (e) => zt(e, "register")
81
+ ), n = /* @__PURE__ */ new Set();
82
+ for (const e of r) {
83
+ if (n.has(e.name))
84
+ throw Rt(
85
+ e.name,
86
+ `[PageBuilder] Component "${e.name}" appears multiple times in the registration batch.`
87
+ );
88
+ if (n.add(e.name), ie.has(e.name))
89
+ throw Rt(
90
+ e.name,
91
+ `[PageBuilder] Component "${e.name}" is already registered. Use replaceComponent() to override.`
92
+ );
93
+ }
94
+ for (const e of r)
95
+ ie.set(e.name, e);
96
+ }
97
+ function sl(t) {
98
+ const r = zt(t, "replace"), n = r.name;
99
+ ie.set(n, r);
100
+ }
101
+ function dl(t) {
102
+ return ie.delete(Je(t));
103
+ }
104
+ function Le(t) {
105
+ return ie.get(Je(t));
106
+ }
107
+ function nr(t) {
108
+ const r = Je(t), n = ie.get(r);
109
+ if (!n)
110
+ throw Z(
111
+ "MISSING_COMPONENT",
112
+ `[PageBuilder] Component "${r}" is not registered. Available: ${er()}`,
113
+ {
114
+ details: {
115
+ componentName: r,
116
+ availableComponents: [...ie.keys()]
117
+ }
118
+ }
119
+ );
120
+ return n.component;
121
+ }
122
+ function cl() {
123
+ return [...ie.values()];
124
+ }
125
+ function rr() {
126
+ const t = /* @__PURE__ */ new Map();
127
+ for (const r of ie.values()) {
128
+ if (r.hidden) continue;
129
+ const n = t.get(r.category) ?? [];
130
+ n.push(r), t.set(r.category, n);
131
+ }
132
+ return t;
133
+ }
134
+ function ul(t) {
135
+ return ie.has(Je(t));
136
+ }
137
+ function fl() {
138
+ ie.clear();
139
+ }
140
+ const un = {
141
+ name: "PbColumn",
142
+ label: "Column",
143
+ description: "Vertical flex container for stacking components.",
144
+ category: "layout",
145
+ icon: "⬜",
146
+ component: {},
147
+ // self-reference set at registration
148
+ slots: [{ name: "default", label: "Content" }],
149
+ editableProps: [
150
+ { key: "gap", label: "Gap", type: "text", defaultValue: "16px" },
151
+ { key: "padding", label: "Padding", type: "text", defaultValue: "0" },
152
+ { key: "align", label: "Align Items", type: "select", defaultValue: "stretch", options: [
153
+ { label: "Stretch", value: "stretch" },
154
+ { label: "Start", value: "flex-start" },
155
+ { label: "Center", value: "center" },
156
+ { label: "End", value: "flex-end" }
157
+ ] }
158
+ ],
159
+ defaultProps: { gap: "16px", padding: "0", align: "stretch" }
160
+ }, or = /* @__PURE__ */ G({
161
+ __name: "PbColumn",
162
+ props: {
163
+ gap: { type: String, default: "16px" },
164
+ padding: { type: String, default: "0" },
165
+ align: { type: String, default: "stretch" }
166
+ },
167
+ setup(t, { expose: r }) {
168
+ r();
169
+ const n = t, e = N(() => ({
170
+ display: "flex",
171
+ flexDirection: "column",
172
+ gap: n.gap,
173
+ padding: n.padding,
174
+ alignItems: n.align,
175
+ width: "100%"
176
+ })), o = { builderOptions: un, props: n, style: e };
177
+ return Object.defineProperty(o, "__isScriptSetup", { enumerable: !1, value: !0 }), o;
178
+ }
179
+ }), q = (t, r) => {
180
+ const n = t.__vccOpts || t;
181
+ for (const [e, o] of r)
182
+ n[e] = o;
183
+ return n;
184
+ };
185
+ function ar(t, r, n, e, o, i) {
186
+ return x(), C(
187
+ "div",
188
+ {
189
+ style: J(e.style)
190
+ },
191
+ [
192
+ Ze(t.$slots, "default")
193
+ ],
194
+ 4
195
+ /* STYLE */
196
+ );
197
+ }
198
+ const ir = /* @__PURE__ */ q(or, [["render", ar], ["__file", "/app/src/built-in/PbColumn.vue"]]), fn = {
199
+ name: "PbRow",
200
+ label: "Row",
201
+ description: "Horizontal flex container for side-by-side components.",
202
+ category: "layout",
203
+ icon: "⬛",
204
+ component: {},
205
+ slots: [{ name: "default", label: "Content" }],
206
+ editableProps: [
207
+ { key: "gap", label: "Gap", type: "text", defaultValue: "16px" },
208
+ { key: "wrap", label: "Wrap", type: "boolean", defaultValue: !0 },
209
+ { key: "justify", label: "Justify", type: "select", defaultValue: "flex-start", options: [
210
+ { label: "Start", value: "flex-start" },
211
+ { label: "Center", value: "center" },
212
+ { label: "End", value: "flex-end" },
213
+ { label: "Space Between", value: "space-between" },
214
+ { label: "Space Around", value: "space-around" }
215
+ ] }
216
+ ],
217
+ defaultProps: { gap: "16px", wrap: !0, justify: "flex-start" }
218
+ }, lr = /* @__PURE__ */ G({
219
+ __name: "PbRow",
220
+ props: {
221
+ gap: { type: String, default: "16px" },
222
+ wrap: { type: Boolean, default: !0 },
223
+ justify: { type: String, default: "flex-start" }
224
+ },
225
+ setup(t, { expose: r }) {
226
+ r();
227
+ const n = t, e = N(() => ({
228
+ display: "flex",
229
+ flexDirection: "row",
230
+ gap: n.gap,
231
+ flexWrap: n.wrap ? "wrap" : "nowrap",
232
+ justifyContent: n.justify,
233
+ width: "100%"
234
+ })), o = { builderOptions: fn, props: n, style: e };
235
+ return Object.defineProperty(o, "__isScriptSetup", { enumerable: !1, value: !0 }), o;
236
+ }
237
+ });
238
+ function sr(t, r, n, e, o, i) {
239
+ return x(), C(
240
+ "div",
241
+ {
242
+ style: J(e.style)
243
+ },
244
+ [
245
+ Ze(t.$slots, "default")
246
+ ],
247
+ 4
248
+ /* STYLE */
249
+ );
250
+ }
251
+ const dr = /* @__PURE__ */ q(lr, [["render", sr], ["__file", "/app/src/built-in/PbRow.vue"]]), Jt = /* @__PURE__ */ new Set([
252
+ "div",
253
+ "p",
254
+ "span",
255
+ "h1",
256
+ "h2",
257
+ "h3",
258
+ "h4",
259
+ "h5",
260
+ "h6",
261
+ "section",
262
+ "article",
263
+ "blockquote"
264
+ ]), cr = /* @__PURE__ */ new Set([
265
+ "a",
266
+ "b",
267
+ "blockquote",
268
+ "br",
269
+ "code",
270
+ "div",
271
+ "em",
272
+ "h1",
273
+ "h2",
274
+ "h3",
275
+ "h4",
276
+ "h5",
277
+ "h6",
278
+ "i",
279
+ "li",
280
+ "ol",
281
+ "p",
282
+ "pre",
283
+ "s",
284
+ "span",
285
+ "strong",
286
+ "u",
287
+ "ul"
288
+ ]), ur = /* @__PURE__ */ new Set([
289
+ "base",
290
+ "embed",
291
+ "form",
292
+ "iframe",
293
+ "input",
294
+ "link",
295
+ "math",
296
+ "meta",
297
+ "noscript",
298
+ "object",
299
+ "script",
300
+ "style",
301
+ "svg",
302
+ "template",
303
+ "textarea"
304
+ ]), fr = /* @__PURE__ */ new Set(["_blank", "_parent", "_self", "_top"]), pr = /* @__PURE__ */ new Set(["nofollow", "noopener", "noreferrer", "sponsored", "ugc"]), mr = /^data:image\/(?:avif|bmp|gif|jpe?g|png|webp);base64,[a-z0-9+/=\s]+$/i;
305
+ function jt(t) {
306
+ return t.replace(/[\u0000-\u001F\u007F]/g, "");
307
+ }
308
+ function gr(t) {
309
+ return jt(t).replace(/\s+/g, "");
310
+ }
311
+ function pn(t) {
312
+ const r = t.toLowerCase().split(/\s+/).filter(Boolean).filter((n) => pr.has(n));
313
+ return Array.from(new Set(r)).join(" ");
314
+ }
315
+ function br(t) {
316
+ const r = pn(t ?? ""), n = new Set(r.split(/\s+/).filter(Boolean));
317
+ return n.add("noopener"), n.add("noreferrer"), Array.from(n).join(" ");
318
+ }
319
+ function vr() {
320
+ var t;
321
+ if (typeof document < "u" && typeof ((t = document.implementation) == null ? void 0 : t.createHTMLDocument) == "function")
322
+ return document.implementation.createHTMLDocument("");
323
+ if (typeof DOMParser < "u") {
324
+ const r = new DOMParser().parseFromString("<!doctype html><html><body></body></html>", "text/html");
325
+ if (r != null && r.body) return r;
326
+ }
327
+ return null;
328
+ }
329
+ function hr(t) {
330
+ return t.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
331
+ }
332
+ function _r(t, r) {
333
+ const n = r.tagName.toLowerCase();
334
+ for (const e of Array.from(t.attributes)) {
335
+ const o = e.name.toLowerCase(), i = jt(e.value).trim();
336
+ if (!(i.length === 0 || o.startsWith("on"))) {
337
+ if (o === "title") {
338
+ r.setAttribute("title", i);
339
+ continue;
340
+ }
341
+ if (n === "a") {
342
+ if (o === "href") {
343
+ const a = se(i, "link");
344
+ a.length > 0 && r.setAttribute("href", a);
345
+ continue;
346
+ }
347
+ if (o === "target") {
348
+ const a = i.toLowerCase();
349
+ fr.has(a) && r.setAttribute("target", a);
350
+ continue;
351
+ }
352
+ if (o === "rel") {
353
+ const a = pn(i);
354
+ a.length > 0 && r.setAttribute("rel", a);
355
+ }
356
+ }
357
+ }
358
+ }
359
+ n === "a" && r.getAttribute("target") === "_blank" && r.setAttribute("rel", br(r.getAttribute("rel")));
360
+ }
361
+ function At(t, r, n) {
362
+ for (const e of Array.from(t.childNodes)) {
363
+ if (e.nodeType === 3) {
364
+ r.appendChild(n.createTextNode(e.textContent ?? ""));
365
+ continue;
366
+ }
367
+ if (e.nodeType !== 1) continue;
368
+ const o = e, i = o.tagName.toLowerCase();
369
+ if (ur.has(i)) continue;
370
+ if (!cr.has(i)) {
371
+ const l = n.createDocumentFragment();
372
+ At(o, l, n), r.appendChild(l);
373
+ continue;
374
+ }
375
+ const a = n.createElement(i);
376
+ if (_r(o, a), At(o, a, n), i === "a" && !a.getAttribute("href")) {
377
+ const l = n.createDocumentFragment();
378
+ for (; a.firstChild; )
379
+ l.appendChild(a.firstChild);
380
+ r.appendChild(l);
381
+ continue;
382
+ }
383
+ r.appendChild(a);
384
+ }
385
+ }
386
+ function mn(t) {
387
+ const r = typeof t == "string" ? t : "";
388
+ if (r.length === 0) return "";
389
+ const n = vr();
390
+ if (!n) return hr(r);
391
+ const e = n.createElement("div");
392
+ e.innerHTML = r;
393
+ const o = n.createElement("div");
394
+ return At(e, o, n), o.innerHTML;
395
+ }
396
+ function gn(t, r = "div") {
397
+ const n = typeof r == "string" ? r.trim().toLowerCase() : "div", e = Jt.has(n) ? n : "div";
398
+ if (typeof t != "string") return e;
399
+ const o = t.trim().toLowerCase();
400
+ return Jt.has(o) ? o : e;
401
+ }
402
+ function se(t, r) {
403
+ const n = jt(t).trim();
404
+ if (n.length === 0) return "";
405
+ const e = gr(n).toLowerCase(), o = e.match(/^([a-z][a-z0-9+.-]*):/i), i = o == null ? void 0 : o[1];
406
+ return !i || i === "http" || i === "https" || r === "link" && (i === "mailto" || i === "tel") || r === "media" && i === "blob" || (r === "media" || r === "background") && i === "data" && mr.test(e) ? n : "";
407
+ }
408
+ const bn = {
409
+ name: "PbText",
410
+ label: "Text",
411
+ description: "A text block with HTML support.",
412
+ category: "content",
413
+ icon: "T",
414
+ component: {},
415
+ slots: [],
416
+ editableProps: [
417
+ { key: "content", label: "Content", type: "richtext", defaultValue: "<p>Enter text here</p>" },
418
+ { key: "tag", label: "HTML Tag", type: "select", defaultValue: "div", options: [
419
+ { label: "div", value: "div" },
420
+ { label: "p", value: "p" },
421
+ { label: "span", value: "span" },
422
+ { label: "h1", value: "h1" },
423
+ { label: "h2", value: "h2" },
424
+ { label: "h3", value: "h3" }
425
+ ] }
426
+ ],
427
+ defaultProps: { content: "<p>Enter text here</p>", tag: "div" }
428
+ }, yr = /* @__PURE__ */ G({
429
+ __name: "PbText",
430
+ props: {
431
+ content: { type: String, default: "" },
432
+ tag: { type: String, default: "div" }
433
+ },
434
+ setup(t, { expose: r }) {
435
+ r();
436
+ const n = t, e = N(() => gn(n.tag)), o = N(() => mn(n.content)), i = { builderOptions: bn, props: n, safeTag: e, safeHtmlContent: o };
437
+ return Object.defineProperty(i, "__isScriptSetup", { enumerable: !1, value: !0 }), i;
438
+ }
439
+ });
440
+ function wr(t, r, n, e, o, i) {
441
+ return x(), Se(Mt(e.safeTag), { innerHTML: e.safeHtmlContent }, null, 8, ["innerHTML"]);
442
+ }
443
+ const xr = /* @__PURE__ */ q(yr, [["render", wr], ["__file", "/app/src/built-in/PbText.vue"]]), vn = {
444
+ name: "PbImage",
445
+ label: "Image",
446
+ description: "Displays an image with optional alt text.",
447
+ category: "media",
448
+ icon: "🖼",
449
+ component: {},
450
+ slots: [],
451
+ editableProps: [
452
+ { key: "src", label: "Image URL", type: "image", required: !0 },
453
+ { key: "alt", label: "Alt Text", type: "text", defaultValue: "" },
454
+ { key: "width", label: "Width", type: "text", defaultValue: "100%" },
455
+ { key: "objectFit", label: "Object Fit", type: "select", defaultValue: "cover", options: [
456
+ { label: "Cover", value: "cover" },
457
+ { label: "Contain", value: "contain" },
458
+ { label: "Fill", value: "fill" },
459
+ { label: "None", value: "none" }
460
+ ] }
461
+ ],
462
+ defaultProps: { src: "", alt: "", width: "100%", objectFit: "cover" }
463
+ }, Ir = /* @__PURE__ */ G({
464
+ __name: "PbImage",
465
+ props: {
466
+ src: { type: String, required: !0 },
467
+ alt: { type: String, default: "" },
468
+ width: { type: String, default: "100%" },
469
+ objectFit: { type: String, default: "cover" }
470
+ },
471
+ setup(t, { expose: r }) {
472
+ r();
473
+ const n = t, e = N(() => ({
474
+ width: n.width,
475
+ objectFit: n.objectFit,
476
+ display: "block",
477
+ maxWidth: "100%"
478
+ })), o = N(() => se(n.src, "media")), i = { builderOptions: vn, props: n, style: e, safeSrc: o };
479
+ return Object.defineProperty(i, "__isScriptSetup", { enumerable: !1, value: !0 }), i;
480
+ }
481
+ }), Dr = ["src", "alt"];
482
+ function Nr(t, r, n, e, o, i) {
483
+ return e.safeSrc ? (x(), C("img", {
484
+ key: 0,
485
+ src: e.safeSrc,
486
+ alt: n.alt,
487
+ style: J(e.style),
488
+ loading: "lazy"
489
+ }, null, 12, Dr)) : Y("v-if", !0);
490
+ }
491
+ const Sr = /* @__PURE__ */ q(Ir, [["render", Nr], ["__file", "/app/src/built-in/PbImage.vue"]]), hn = {
492
+ name: "PbVideo",
493
+ label: "Vidéo",
494
+ description: "Affiche une vidéo avec URL, poster optionnel et options de lecture.",
495
+ category: "media",
496
+ icon: "🎬",
497
+ component: {},
498
+ slots: [],
499
+ editableProps: [
500
+ { key: "src", label: "URL de la vidéo", type: "url", required: !0 },
501
+ { key: "poster", label: "Image de couverture (poster)", type: "image" },
502
+ { key: "width", label: "Largeur", type: "text", defaultValue: "100%" },
503
+ { key: "controls", label: "Afficher les contrôles", type: "boolean", defaultValue: !0 },
504
+ { key: "autoplay", label: "Lecture automatique", type: "boolean", defaultValue: !1 },
505
+ { key: "muted", label: "Muet", type: "boolean", defaultValue: !1 },
506
+ { key: "loop", label: "Boucle", type: "boolean", defaultValue: !1 }
507
+ ],
508
+ defaultProps: {
509
+ src: "",
510
+ poster: "",
511
+ width: "100%",
512
+ controls: !0,
513
+ autoplay: !1,
514
+ muted: !1,
515
+ loop: !1
516
+ }
517
+ }, Tr = /* @__PURE__ */ G({
518
+ __name: "PbVideo",
519
+ props: {
520
+ src: { type: String, required: !0 },
521
+ poster: { type: String, required: !1, default: "" },
522
+ width: { type: String, required: !1, default: "100%" },
523
+ controls: { type: Boolean, required: !1, default: !0 },
524
+ autoplay: { type: Boolean, required: !1, default: !1 },
525
+ muted: { type: Boolean, required: !1, default: !1 },
526
+ loop: { type: Boolean, required: !1, default: !1 }
527
+ },
528
+ setup(t, { expose: r }) {
529
+ r();
530
+ const n = t, e = N(() => ({
531
+ width: n.width,
532
+ maxWidth: "100%",
533
+ display: "block"
534
+ })), o = N(() => se(n.src, "media")), i = N(
535
+ () => {
536
+ var l;
537
+ return (l = n.poster) != null && l.trim() ? se(n.poster, "media") : void 0;
538
+ }
539
+ ), a = { builderOptions: hn, props: n, style: e, safeSrc: o, safePoster: i };
540
+ return Object.defineProperty(a, "__isScriptSetup", { enumerable: !1, value: !0 }), a;
541
+ }
542
+ }), Cr = ["src", "poster", "controls", "autoplay", "muted", "loop"];
543
+ function kr(t, r, n, e, o, i) {
544
+ return e.safeSrc ? (x(), C("video", {
545
+ key: 0,
546
+ src: e.safeSrc,
547
+ poster: e.safePoster,
548
+ controls: n.controls,
549
+ autoplay: n.autoplay,
550
+ muted: n.muted,
551
+ loop: n.loop,
552
+ style: J(e.style),
553
+ playsinline: ""
554
+ }, null, 12, Cr)) : Y("v-if", !0);
555
+ }
556
+ const Pr = /* @__PURE__ */ q(Tr, [["render", kr], ["__file", "/app/src/built-in/PbVideo.vue"]]), _n = {
557
+ name: "PbSection",
558
+ label: "Section",
559
+ description: "A full-width section with optional background.",
560
+ category: "layout",
561
+ icon: "▬",
562
+ component: {},
563
+ slots: [{ name: "default", label: "Content" }],
564
+ editableProps: [
565
+ { key: "backgroundColor", label: "Background Color", type: "color", defaultValue: "transparent" },
566
+ { key: "backgroundImage", label: "Background Image", type: "image" },
567
+ { key: "padding", label: "Padding", type: "text", defaultValue: "48px 24px" },
568
+ { key: "maxWidth", label: "Max Content Width", type: "text", defaultValue: "1200px" }
569
+ ],
570
+ defaultProps: { backgroundColor: "transparent", padding: "48px 24px", maxWidth: "1200px" }
571
+ }, Er = /* @__PURE__ */ G({
572
+ __name: "PbSection",
573
+ props: {
574
+ backgroundColor: { type: String, default: "transparent" },
575
+ backgroundImage: { type: String, default: "" },
576
+ padding: { type: String, default: "48px 24px" },
577
+ maxWidth: { type: String, default: "1200px" }
578
+ },
579
+ setup(t, { expose: r }) {
580
+ r();
581
+ const n = t, e = N(() => se(n.backgroundImage, "background")), o = N(() => e.value ? `url("${e.value.replace(/["\\]/g, "\\$&")}")` : void 0), i = N(() => ({
582
+ width: "100%",
583
+ backgroundColor: n.backgroundColor,
584
+ backgroundImage: o.value,
585
+ backgroundSize: "cover",
586
+ backgroundPosition: "center",
587
+ padding: n.padding
588
+ })), a = N(() => ({
589
+ maxWidth: n.maxWidth,
590
+ margin: "0 auto",
591
+ width: "100%"
592
+ })), l = { builderOptions: _n, props: n, safeBackgroundImage: e, cssBackgroundImage: o, outerStyle: i, innerStyle: a };
593
+ return Object.defineProperty(l, "__isScriptSetup", { enumerable: !1, value: !0 }), l;
594
+ }
595
+ });
596
+ function Rr(t, r, n, e, o, i) {
597
+ return x(), C(
598
+ "section",
599
+ {
600
+ style: J(e.outerStyle)
601
+ },
602
+ [
603
+ S(
604
+ "div",
605
+ {
606
+ style: J(e.innerStyle)
607
+ },
608
+ [
609
+ Ze(t.$slots, "default")
610
+ ],
611
+ 4
612
+ /* STYLE */
613
+ )
614
+ ],
615
+ 4
616
+ /* STYLE */
617
+ );
618
+ }
619
+ const Ar = /* @__PURE__ */ q(Er, [["render", Rr], ["__file", "/app/src/built-in/PbSection.vue"]]), yn = {
620
+ name: "PbContainer",
621
+ label: "Container",
622
+ description: "A centered container with max width.",
623
+ category: "layout",
624
+ icon: "☐",
625
+ component: {},
626
+ slots: [{ name: "default", label: "Content" }],
627
+ editableProps: [
628
+ { key: "maxWidth", label: "Max Width", type: "text", defaultValue: "100%" },
629
+ { key: "padding", label: "Padding", type: "text", defaultValue: "0 24px" }
630
+ ],
631
+ defaultProps: { maxWidth: "100%", padding: "0 24px" }
632
+ }, Lr = /* @__PURE__ */ G({
633
+ __name: "PbContainer",
634
+ props: {
635
+ maxWidth: { type: String, default: "100%" },
636
+ padding: { type: String, default: "0 24px" }
637
+ },
638
+ setup(t, { expose: r }) {
639
+ r();
640
+ const n = t, e = N(() => ({
641
+ maxWidth: n.maxWidth,
642
+ margin: "0 auto",
643
+ padding: n.padding,
644
+ width: "100%",
645
+ boxSizing: "border-box"
646
+ })), o = { builderOptions: yn, props: n, style: e };
647
+ return Object.defineProperty(o, "__isScriptSetup", { enumerable: !1, value: !0 }), o;
648
+ }
649
+ });
650
+ function Vr(t, r, n, e, o, i) {
651
+ return x(), C(
652
+ "div",
653
+ {
654
+ style: J(e.style)
655
+ },
656
+ [
657
+ Ze(t.$slots, "default")
658
+ ],
659
+ 4
660
+ /* STYLE */
661
+ );
662
+ }
663
+ const Mr = /* @__PURE__ */ q(Lr, [["render", Vr], ["__file", "/app/src/built-in/PbContainer.vue"]]);
664
+ function Pe(t, r) {
665
+ return { ...t, component: r };
666
+ }
667
+ const Or = [
668
+ Pe(un, ir),
669
+ Pe(fn, dr),
670
+ Pe(bn, xr),
671
+ Pe(vn, Sr),
672
+ Pe(hn, Pr),
673
+ Pe(_n, Ar),
674
+ Pe(yn, Mr)
675
+ ], Br = /* @__PURE__ */ new Set(["draft", "published", "archived"]), Qt = 200, en = 5e3;
676
+ function Ye(t) {
677
+ return typeof t == "object" && t !== null && !Array.isArray(t);
678
+ }
679
+ function j(t, r, n) {
680
+ t.errors.push({ path: r, message: n });
681
+ }
682
+ function zr(t, r, n) {
683
+ if (t.tag === void 0) return;
684
+ if (typeof t.tag != "string" || t.tag.trim() === "") {
685
+ j(n, `${r}.tag`, "PbText props.tag must be a non-empty string.");
686
+ return;
687
+ }
688
+ const e = t.tag.trim().toLowerCase();
689
+ gn(t.tag) !== e && j(
690
+ n,
691
+ `${r}.tag`,
692
+ "PbText props.tag must be one of: div, p, span, h1, h2, h3, h4, h5, h6, section, article, blockquote."
693
+ );
694
+ }
695
+ function jr(t, r, n) {
696
+ if (typeof t.src != "string" || t.src.trim() === "") {
697
+ j(n, `${r}.src`, "PbImage props.src must be a non-empty string.");
698
+ return;
699
+ }
700
+ se(t.src, "media") === "" && j(n, `${r}.src`, "PbImage props.src contains an unsafe URL.");
701
+ }
702
+ function Hr(t, r, n) {
703
+ if (typeof t.src != "string" || t.src.trim() === "") {
704
+ j(n, `${r}.src`, "PbVideo props.src must be a non-empty string.");
705
+ return;
706
+ }
707
+ se(t.src, "media") === "" && j(n, `${r}.src`, "PbVideo props.src contains an unsafe URL.");
708
+ const e = t.poster;
709
+ e != null && e !== "" && (typeof e != "string" ? j(n, `${r}.poster`, "PbVideo props.poster must be a string.") : e.trim() !== "" && se(e, "media") === "" && j(n, `${r}.poster`, "PbVideo props.poster contains an unsafe URL."));
710
+ }
711
+ function Wr(t, r, n) {
712
+ const e = t.backgroundImage;
713
+ if (!(e == null || e === "")) {
714
+ if (typeof e != "string") {
715
+ j(n, `${r}.backgroundImage`, "PbSection props.backgroundImage must be a string.");
716
+ return;
717
+ }
718
+ e.trim() !== "" && se(e, "background") === "" && j(n, `${r}.backgroundImage`, "PbSection props.backgroundImage contains an unsafe URL.");
719
+ }
720
+ }
721
+ function Ur(t, r, n, e) {
722
+ if (t === "PbText") {
723
+ zr(r, n, e);
724
+ return;
725
+ }
726
+ if (t === "PbImage") {
727
+ jr(r, n, e);
728
+ return;
729
+ }
730
+ if (t === "PbVideo") {
731
+ Hr(r, n, e);
732
+ return;
733
+ }
734
+ t === "PbSection" && Wr(r, n, e);
735
+ }
736
+ function it(t, r, n, e = 0) {
737
+ if (e > Qt) {
738
+ n.depthGuardTriggered || (j(
739
+ n,
740
+ r,
741
+ `Maximum node depth (${String(Qt)}) exceeded during validation.`
742
+ ), n.depthGuardTriggered = !0);
743
+ return;
744
+ }
745
+ if (n.visitedNodeCount >= en) {
746
+ n.sizeGuardTriggered || (j(
747
+ n,
748
+ r,
749
+ `Maximum node count (${String(en)}) exceeded during validation.`
750
+ ), n.sizeGuardTriggered = !0);
751
+ return;
752
+ }
753
+ if (!Ye(t)) {
754
+ j(n, r, "Node must be an object.");
755
+ return;
756
+ }
757
+ if (n.seenNodes.has(t)) {
758
+ j(n, r, "Cycle detected in node tree.");
759
+ return;
760
+ }
761
+ n.seenNodes.add(t), n.visitedNodeCount++;
762
+ const o = t.id, i = t.name, a = t.slot, l = t.props, u = t.children, b = t.readonly;
763
+ if (!(typeof o == "number" && Number.isInteger(o)) || o <= 0 ? j(n, `${r}.id`, "id must be a positive integer.") : (n.seenIds.has(o) && j(n, `${r}.id`, `Duplicate node id "${o}" found.`), n.seenIds.add(o), o > n.maxObservedId && (n.maxObservedId = o)), (typeof i != "string" || i.trim() === "") && j(n, `${r}.name`, "name must be a non-empty string."), a === null || typeof a == "string" || j(n, `${r}.slot`, "slot must be a string or null."), Ye(l) ? typeof i == "string" && Ur(i, l, `${r}.props`, n) : j(n, `${r}.props`, "props must be an object."), !Array.isArray(u)) {
764
+ j(n, `${r}.children`, "children must be an array.");
765
+ return;
766
+ }
767
+ b === void 0 || typeof b == "boolean" || j(n, `${r}.readonly`, "readonly must be a boolean when provided.");
768
+ for (let v = 0; v < u.length && !n.sizeGuardTriggered; v++)
769
+ it(u[v], `${r}.children[${v}]`, n, e + 1);
770
+ }
771
+ function lt(t, r = "node") {
772
+ const n = {
773
+ errors: [],
774
+ seenIds: /* @__PURE__ */ new Set(),
775
+ seenNodes: /* @__PURE__ */ new WeakSet(),
776
+ maxObservedId: 0,
777
+ visitedNodeCount: 0,
778
+ depthGuardTriggered: !1,
779
+ sizeGuardTriggered: !1
780
+ };
781
+ return it(t, r, n), {
782
+ isValid: n.errors.length === 0,
783
+ errors: n.errors
784
+ };
785
+ }
786
+ function wn(t) {
787
+ const r = {
788
+ errors: [],
789
+ seenIds: /* @__PURE__ */ new Set(),
790
+ seenNodes: /* @__PURE__ */ new WeakSet(),
791
+ maxObservedId: 0,
792
+ visitedNodeCount: 0,
793
+ depthGuardTriggered: !1,
794
+ sizeGuardTriggered: !1
795
+ };
796
+ if (!Ye(t))
797
+ return j(r, "pageData", "pageData must be an object."), {
798
+ isValid: !1,
799
+ errors: r.errors
800
+ };
801
+ const { meta: n, content: e, layout: o, maxId: i, variables: a } = t;
802
+ if (Ye(n) ? ((typeof n.id != "string" || n.id.trim() === "") && j(r, "meta.id", "meta.id must be a non-empty string."), (typeof n.name != "string" || n.name.trim() === "") && j(r, "meta.name", "meta.name must be a non-empty string."), typeof n.url != "string" || n.url.trim() === "" ? j(r, "meta.url", "meta.url must be a non-empty string.") : se(n.url, "link") === "" && j(r, "meta.url", "meta.url contains an unsafe URL."), (typeof n.status != "string" || !Br.has(n.status)) && j(
803
+ r,
804
+ "meta.status",
805
+ "meta.status must be one of: draft, published, archived."
806
+ ), n.updatedAt === void 0 || typeof n.updatedAt == "string" || j(r, "meta.updatedAt", "meta.updatedAt must be a string when provided."), n.createdAt === void 0 || typeof n.createdAt == "string" || j(r, "meta.createdAt", "meta.createdAt must be a string when provided.")) : j(r, "meta", "meta must be an object."), it(e, "content", r), it(o, "layout", r), !(typeof i == "number" && Number.isInteger(i)) || i < 0 ? j(r, "maxId", "maxId must be a non-negative integer.") : i < r.maxObservedId && j(
807
+ r,
808
+ "maxId",
809
+ `maxId (${String(i)}) must be greater than or equal to the maximum node id (${String(r.maxObservedId)}).`
810
+ ), !Ye(a))
811
+ j(r, "variables", "variables must be an object.");
812
+ else
813
+ for (const [l, u] of Object.entries(a))
814
+ typeof u != "string" && j(r, `variables.${l}`, "Variable values must be strings.");
815
+ return {
816
+ isValid: r.errors.length === 0,
817
+ errors: r.errors
818
+ };
819
+ }
820
+ const Lt = "en", xn = {
821
+ en: {
822
+ "toolbar.undo.title": "Undo (Ctrl/Cmd+Z)",
823
+ "toolbar.undo.ariaLabel": "Undo",
824
+ "toolbar.redo.title": "Redo (Ctrl/Cmd+Y or Shift+Ctrl/Cmd+Z)",
825
+ "toolbar.redo.ariaLabel": "Redo",
826
+ "toolbar.save": "Save",
827
+ "toolbar.save.title": "Save (Ctrl/Cmd+S)",
828
+ "toolbar.save.ariaLabel": "Save page",
829
+ "toolbar.aria.toolbar": "Editor toolbar",
830
+ "toolbar.aria.historyControls": "History controls",
831
+ "toolbar.aria.viewportControls": "Viewport controls",
832
+ "toolbar.aria.saveControls": "Save controls",
833
+ "toolbar.aria.unsavedChanges": "Unsaved changes",
834
+ "toolbar.viewport.desktop": "Desktop",
835
+ "toolbar.viewport.tablet": "Tablet",
836
+ "toolbar.viewport.mobile": "Mobile",
837
+ "toolbar.viewport.custom": "Custom",
838
+ "toolbar.viewport.switchAriaLabel": "Switch viewport to {viewport}",
839
+ "toolbar.viewport.width.short": "W",
840
+ "toolbar.viewport.height.short": "H",
841
+ "toolbar.viewport.width.ariaLabel": "Custom viewport width",
842
+ "toolbar.viewport.height.ariaLabel": "Custom viewport height",
843
+ "leftDrawer.title": "Components",
844
+ "leftDrawer.aria.componentPalette": "Component palette",
845
+ "leftDrawer.toggle.ariaLabel": "Toggle component drawer",
846
+ "leftDrawer.section.components": "Components",
847
+ "leftDrawer.search.placeholder": "Search components...",
848
+ "leftDrawer.search.ariaLabel": "Search components",
849
+ "leftDrawer.category.ariaLabel": "{category} components",
850
+ "leftDrawer.component.dragAriaLabel": "Add or drag {label}",
851
+ "leftDrawer.empty": "No matching components",
852
+ "leftDrawer.section.tree": "Tree",
853
+ "leftDrawer.tree.toggle.ariaLabel": "Toggle node tree",
854
+ "rightDrawer.title": "Properties",
855
+ "rightDrawer.aria.componentProperties": "Component properties",
856
+ "rightDrawer.toggle.ariaLabel": "Toggle properties drawer",
857
+ "rightDrawer.section.properties": "Properties",
858
+ "rightDrawer.actions.duplicate": "Duplicate",
859
+ "rightDrawer.actions.duplicate.ariaLabel": "Duplicate selected component",
860
+ "rightDrawer.actions.delete": "Delete",
861
+ "rightDrawer.actions.delete.ariaLabel": "Delete selected component",
862
+ "rightDrawer.empty": "Select a component to edit its properties.",
863
+ "treePanel.ariaLabel": "Node tree",
864
+ "treePanel.readonly": "readonly",
865
+ "contextMenu.ariaLabel": "Node context menu",
866
+ "contextMenu.duplicate": "Duplicate",
867
+ "contextMenu.moveUp": "Move up",
868
+ "contextMenu.moveDown": "Move down",
869
+ "contextMenu.delete": "Delete",
870
+ "iframeCanvas.title": "Editor canvas",
871
+ "propBoolean.enabled": "Enabled",
872
+ "propBoolean.disabled": "Disabled",
873
+ "propSelect.noOptions": "No options",
874
+ "mediaPicker.input.placeholder": "https://example.com/image.jpg",
875
+ "mediaPicker.clear": "Clear",
876
+ "mediaPicker.upload": "Upload",
877
+ "mediaPicker.preview.alt": "Media preview",
878
+ "mediaPicker.empty": "Paste an image URL to preview.",
879
+ "richText.action.link": "Link",
880
+ "richText.action.bold": "Bold",
881
+ "richText.action.italic": "Italic",
882
+ "richText.action.unorderedList": "Bulleted list",
883
+ "richText.action.orderedList": "Numbered list",
884
+ "richText.aria.toolbar": "Rich text formatting toolbar",
885
+ "richText.aria.editor": "Rich text editor",
886
+ "richText.prompt.enterUrl": "Enter URL",
887
+ "richText.prompt.defaultUrl": "https://",
888
+ "pageBuilder.warning.invalidEditMode": "Invalid `pageData` for edit mode. Rendering in read mode."
889
+ }
890
+ };
891
+ function Kr(t, r) {
892
+ return r ? t.replace(/\{(\w+)\}/g, (n, e) => {
893
+ const o = r[e];
894
+ return o === void 0 ? n : String(o);
895
+ }) : t;
896
+ }
897
+ function Fr(...t) {
898
+ const r = {};
899
+ for (const n of t)
900
+ if (n)
901
+ for (const [e, o] of Object.entries(n))
902
+ r[e] = {
903
+ ...r[e] ?? {},
904
+ ...o
905
+ };
906
+ return r;
907
+ }
908
+ function $r(t) {
909
+ const r = t.fallbackLocale ?? "en", n = t.dictionary[t.locale] ?? {}, e = t.dictionary[r] ?? {}, o = n[t.key] ?? e[t.key] ?? t.key;
910
+ return Kr(o, t.params);
911
+ }
912
+ function In(t, r, n = "en") {
913
+ const e = typeof t == "function" ? t : () => t, o = typeof r == "function" ? r : () => r;
914
+ return (i, a) => $r({
915
+ locale: e(),
916
+ dictionary: o(),
917
+ key: i,
918
+ params: a,
919
+ fallbackLocale: n
920
+ });
921
+ }
922
+ const Dn = Symbol("pageBuilderI18nOptions"), Nn = Symbol("pageBuilderI18n"), Gr = {
923
+ locale: N(() => Lt),
924
+ t: In(Lt, xn)
925
+ };
926
+ function pe() {
927
+ return je(Nn, Gr);
928
+ }
929
+ function ct(t) {
930
+ return Array.isArray(t.children) ? t.children : [];
931
+ }
932
+ function Sn(t, r) {
933
+ const n = Number.isFinite(t) ? Math.trunc(t) : 0;
934
+ return Math.max(0, Math.min(n, r));
935
+ }
936
+ function qr(t) {
937
+ try {
938
+ return structuredClone(t);
939
+ } catch (r) {
940
+ throw Z(
941
+ "INVALID_NODE",
942
+ "[PageBuilder] Failed to clone node tree. Ensure the tree is serializable and acyclic.",
943
+ {
944
+ cause: r
945
+ }
946
+ );
947
+ }
948
+ }
949
+ function U(t, r) {
950
+ if (t.id === r) return t;
951
+ for (const n of ct(t)) {
952
+ const e = U(n, r);
953
+ if (e) return e;
954
+ }
955
+ }
956
+ function ae(t, r) {
957
+ const n = ct(t);
958
+ for (let e = 0; e < n.length; e++) {
959
+ if (n[e].id === r)
960
+ return { parent: t, index: e };
961
+ const o = ae(n[e], r);
962
+ if (o) return o;
963
+ }
964
+ }
965
+ function Yr(t, r) {
966
+ const n = ae(t, r);
967
+ if (n)
968
+ return n.parent.children.splice(n.index, 1)[0];
969
+ }
970
+ function Tn(t, r, n, e, o = "default") {
971
+ const i = U(t, r);
972
+ if (!i) return !1;
973
+ Array.isArray(i.children) || (i.children = []);
974
+ const a = Sn(e, i.children.length), l = { ...n, slot: o };
975
+ return i.children.splice(a, 0, l), !0;
976
+ }
977
+ function Xr(t, r, n, e, o = "default") {
978
+ const i = ae(t, r);
979
+ if (!i) return !1;
980
+ const a = ct(i.parent), [l] = a.splice(i.index, 1);
981
+ if (!l) return !1;
982
+ if (Tn(t, n, l, e, o)) return !0;
983
+ const b = Sn(i.index, a.length);
984
+ return a.splice(b, 0, l), !1;
985
+ }
986
+ function Zr(t, r, n = {}) {
987
+ return {
988
+ id: t,
989
+ name: r,
990
+ slot: n.slot ?? "default",
991
+ props: n.props ?? {},
992
+ children: n.children ?? [],
993
+ readonly: n.readonly
994
+ };
995
+ }
996
+ function Cn(t, r, n = 0) {
997
+ const e = /* @__PURE__ */ new WeakSet();
998
+ function o(i, a) {
999
+ if (e.has(i)) return !0;
1000
+ if (e.add(i), r(i, a) === !1) return !1;
1001
+ for (const l of ct(i))
1002
+ if (o(l, a + 1) === !1) return !1;
1003
+ return !0;
1004
+ }
1005
+ return o(t, n);
1006
+ }
1007
+ function pl(t) {
1008
+ let r = 0;
1009
+ return Cn(t, () => {
1010
+ r++;
1011
+ }), r;
1012
+ }
1013
+ function We(t) {
1014
+ let r = t.id;
1015
+ return Cn(t, (n) => {
1016
+ Number.isFinite(n.id) && n.id > r && (r = n.id);
1017
+ }), r;
1018
+ }
1019
+ function Jr(t, r) {
1020
+ if (!t || typeof t != "object" || Array.isArray(t))
1021
+ return {};
1022
+ const n = r && typeof r == "object" && !Array.isArray(r) ? r : {}, e = {};
1023
+ for (const [o, i] of Object.entries(t))
1024
+ typeof i == "string" ? e[o] = i.replace(/\{\{\s*(\w+)\s*\}\}/g, (a, l) => n[l] ?? `{{ ${l} }}`) : e[o] = i;
1025
+ return e;
1026
+ }
1027
+ const Qr = /* @__PURE__ */ G({
1028
+ __name: "ErrorBoundary",
1029
+ props: {
1030
+ fallbackMessage: { type: String, required: !1, default: "Something went wrong while rendering this section." },
1031
+ showDetailsInDev: { type: Boolean, required: !1, default: !1 },
1032
+ diagnosticContext: { type: String, required: !1, default: "ErrorBoundary" }
1033
+ },
1034
+ setup(t, { expose: r }) {
1035
+ r();
1036
+ const n = t, e = R(!1), o = R(null), i = R(""), a = N(() => n.showDetailsInDev), l = N(() => o.value ? o.value instanceof Error ? o.value.message : String(o.value) : ""), u = N(
1037
+ () => [l.value, i.value].filter((v) => !!v).join(`
1038
+ `)
1039
+ );
1040
+ Hn((v, I, d) => (e.value = !0, o.value = v, i.value = d, Ue(
1041
+ n.diagnosticContext,
1042
+ Z(
1043
+ "RENDER_FAILURE",
1044
+ `[PageBuilder] ${n.diagnosticContext} captured a render error: ${Bt(v)}`,
1045
+ {
1046
+ cause: v,
1047
+ details: {
1048
+ info: d
1049
+ }
1050
+ }
1051
+ )
1052
+ ), !1));
1053
+ const b = { props: n, hasError: e, capturedError: o, errorInfo: i, shouldShowDetails: a, errorDetails: l, errorDebugText: u };
1054
+ return Object.defineProperty(b, "__isScriptSetup", { enumerable: !1, value: !0 }), b;
1055
+ }
1056
+ }), eo = {
1057
+ key: 1,
1058
+ class: "ipb-error-boundary",
1059
+ role: "alert"
1060
+ }, to = { class: "ipb-error-boundary__message" }, no = {
1061
+ key: 0,
1062
+ class: "ipb-error-boundary__details"
1063
+ };
1064
+ function ro(t, r, n, e, o, i) {
1065
+ return e.hasError ? (x(), C("div", eo, [
1066
+ S(
1067
+ "p",
1068
+ to,
1069
+ z(n.fallbackMessage),
1070
+ 1
1071
+ /* TEXT */
1072
+ ),
1073
+ e.shouldShowDetails && e.errorDebugText ? (x(), C(
1074
+ "pre",
1075
+ no,
1076
+ " " + z(e.errorDebugText) + `
1077
+ `,
1078
+ 1
1079
+ /* TEXT */
1080
+ )) : Y("v-if", !0)
1081
+ ])) : Ze(t.$slots, "default", { key: 0 }, void 0, !0);
1082
+ }
1083
+ const kn = /* @__PURE__ */ q(Qr, [["render", ro], ["__scopeId", "data-v-c285f22f"], ["__file", "/app/src/components/shared/ErrorBoundary.vue"]]), oo = /* @__PURE__ */ G({
1084
+ __name: "NodeRenderer",
1085
+ props: {
1086
+ node: {
1087
+ type: Object,
1088
+ required: !0
1089
+ },
1090
+ variables: {
1091
+ type: Object,
1092
+ default: () => ({})
1093
+ },
1094
+ markNodes: {
1095
+ type: Boolean,
1096
+ default: !1
1097
+ }
1098
+ },
1099
+ setup(t, { expose: r }) {
1100
+ r();
1101
+ const n = t, e = /* @__PURE__ */ new Set();
1102
+ function o(c, m, p) {
1103
+ e.has(c) || (e.add(c), Ue("NodeRenderer", Z("RENDER_FAILURE", m, { details: p })));
1104
+ }
1105
+ function i(c) {
1106
+ if (typeof c != "object" || c === null || Array.isArray(c)) return !1;
1107
+ const m = c;
1108
+ return typeof m.id != "number" || !Number.isFinite(m.id) || typeof m.name != "string" || m.name.trim().length === 0 || !(m.slot === null || typeof m.slot == "string") || typeof m.props != "object" || m.props === null || Array.isArray(m.props) ? !1 : Array.isArray(m.children);
1109
+ }
1110
+ function a(c) {
1111
+ return !c || typeof c != "object" || Array.isArray(c) ? {} : Object.fromEntries(
1112
+ Object.entries(c).filter((m) => typeof m[1] == "string")
1113
+ );
1114
+ }
1115
+ const l = N(() => i(n.node) ? n.node : (o("invalid-node", "[PageBuilder] NodeRenderer received an invalid node payload.", {
1116
+ node: n.node
1117
+ }), null)), u = N(() => a(n.variables)), b = G({
1118
+ name: "NodeRenderCrash",
1119
+ props: {
1120
+ error: {
1121
+ type: null,
1122
+ required: !0
1123
+ }
1124
+ },
1125
+ setup(c) {
1126
+ return () => {
1127
+ throw c.error instanceof Error ? c.error : new Error(String(c.error));
1128
+ };
1129
+ }
1130
+ }), v = N(() => {
1131
+ if (!l.value)
1132
+ return {
1133
+ component: b,
1134
+ error: Z(
1135
+ "INVALID_NODE",
1136
+ "[PageBuilder] Cannot render node because its payload is invalid."
1137
+ )
1138
+ };
1139
+ try {
1140
+ return { component: nr(l.value.name), error: null };
1141
+ } catch (c) {
1142
+ return o(
1143
+ `missing-component:${l.value.name}`,
1144
+ `[PageBuilder] Component "${l.value.name}" could not be resolved.`,
1145
+ { nodeId: l.value.id }
1146
+ ), { component: b, error: c };
1147
+ }
1148
+ }), I = N(() => v.value.component), d = N(() => {
1149
+ if (v.value.error !== null)
1150
+ return { error: v.value.error };
1151
+ if (!l.value)
1152
+ return {
1153
+ error: Z(
1154
+ "INVALID_NODE",
1155
+ "[PageBuilder] Cannot render props for an invalid node payload."
1156
+ )
1157
+ };
1158
+ try {
1159
+ return Jr(l.value.props, u.value);
1160
+ } catch (c) {
1161
+ return o(
1162
+ `prop-interpolation:${l.value.id}`,
1163
+ `[PageBuilder] Failed to interpolate props for node "${l.value.name}".`,
1164
+ { nodeId: l.value.id }
1165
+ ), { error: c };
1166
+ }
1167
+ }), A = N(() => !n.markNodes || !l.value ? {} : {
1168
+ "data-ipb-node-id": String(l.value.id),
1169
+ "data-ipb-component": l.value.name
1170
+ }), k = N(() => ({
1171
+ ...d.value,
1172
+ ...A.value
1173
+ })), y = N(() => {
1174
+ const c = {};
1175
+ if (!l.value) return c;
1176
+ for (const m of l.value.children) {
1177
+ if (!i(m)) {
1178
+ o(
1179
+ `invalid-child:${l.value.id}`,
1180
+ `[PageBuilder] Ignoring invalid child node while rendering "${l.value.name}".`,
1181
+ { parentNodeId: l.value.id }
1182
+ );
1183
+ continue;
1184
+ }
1185
+ const p = m.slot ?? "default";
1186
+ c[p] || (c[p] = []), c[p].push(m);
1187
+ }
1188
+ return c;
1189
+ }), D = { props: n, reportedDiagnostics: e, reportOnce: o, isNodeObject: i, sanitizeVariables: a, safeNode: l, safeVariables: u, NodeRenderCrash: b, resolutionResult: v, resolvedComponent: I, resolvedProps: d, markerAttrs: A, renderedAttrs: k, slotGroups: y, ErrorBoundary: kn };
1190
+ return Object.defineProperty(D, "__isScriptSetup", { enumerable: !1, value: !0 }), D;
1191
+ }
1192
+ }), ao = {
1193
+ key: 0,
1194
+ class: "ipb-node-renderer__invalid",
1195
+ role: "alert"
1196
+ };
1197
+ function io(t, r, n, e, o, i) {
1198
+ const a = Wn("NodeRenderer", !0);
1199
+ return e.safeNode ? (x(), Se(e.ErrorBoundary, {
1200
+ key: 1,
1201
+ "fallback-message": "This block could not be rendered.",
1202
+ "show-details-in-dev": !0,
1203
+ "diagnostic-context": "NodeRenderer"
1204
+ }, {
1205
+ default: Pt(() => [
1206
+ (x(), Se(
1207
+ Mt(e.resolvedComponent),
1208
+ Un(Kn(e.renderedAttrs)),
1209
+ Fn({
1210
+ _: 2
1211
+ /* DYNAMIC */
1212
+ }, [
1213
+ ve(e.slotGroups, (l, u) => ({
1214
+ name: u,
1215
+ fn: Pt(() => [
1216
+ (x(!0), C(
1217
+ he,
1218
+ null,
1219
+ ve(l, (b) => (x(), Se(a, {
1220
+ key: b.id,
1221
+ node: b,
1222
+ variables: e.safeVariables,
1223
+ "mark-nodes": n.markNodes
1224
+ }, null, 8, ["node", "variables", "mark-nodes"]))),
1225
+ 128
1226
+ /* KEYED_FRAGMENT */
1227
+ ))
1228
+ ])
1229
+ }))
1230
+ ]),
1231
+ 1040
1232
+ /* FULL_PROPS, DYNAMIC_SLOTS */
1233
+ ))
1234
+ ]),
1235
+ _: 1
1236
+ /* STABLE */
1237
+ })) : (x(), C("div", ao, " This block is invalid and could not be rendered. "));
1238
+ }
1239
+ const Pn = /* @__PURE__ */ q(oo, [["render", io], ["__scopeId", "data-v-ea251e83"], ["__file", "/app/src/components/reader/NodeRenderer.vue"]]), lo = /* @__PURE__ */ G({
1240
+ __name: "PageReader",
1241
+ props: {
1242
+ pageData: {
1243
+ type: Object,
1244
+ required: !0
1245
+ }
1246
+ },
1247
+ setup(t, { expose: r }) {
1248
+ r();
1249
+ const n = t, e = N(() => wn(n.pageData)), o = N(() => lt(n.pageData.content, "content")), i = N(() => lt(n.pageData.layout, "layout")), a = /* @__PURE__ */ new Set();
1250
+ function l(d, A, k) {
1251
+ a.has(d) || (a.add(d), Ue("PageReader", Z("INVALID_PAGE_DATA", A, { details: k })));
1252
+ }
1253
+ de(
1254
+ e,
1255
+ (d) => {
1256
+ d.isValid || l(
1257
+ "invalid-page-data",
1258
+ "[PageReader] Invalid pageData payload detected. Rendering continues with degraded behavior.",
1259
+ { errors: d.errors }
1260
+ );
1261
+ },
1262
+ { immediate: !0 }
1263
+ );
1264
+ function u(d) {
1265
+ return typeof d == "object" && d !== null && !Array.isArray(d);
1266
+ }
1267
+ const b = N(() => {
1268
+ const d = n.pageData.variables;
1269
+ return !d || typeof d != "object" || Array.isArray(d) ? (l(
1270
+ "invalid-variables-shape",
1271
+ "[PageReader] Invalid variables payload. Falling back to an empty variable map."
1272
+ ), {}) : (Object.values(d).some((k) => typeof k != "string") && l(
1273
+ "invalid-variables-values",
1274
+ "[PageReader] Variables payload contains non-string values. Invalid entries were ignored."
1275
+ ), Object.fromEntries(
1276
+ Object.entries(d).filter((k) => typeof k[1] == "string")
1277
+ ));
1278
+ }), v = N(() => {
1279
+ if (!u(n.pageData.content) || !o.value.isValid)
1280
+ return l(
1281
+ "invalid-content",
1282
+ "[PageReader] Invalid content node. Nothing can be rendered.",
1283
+ { errors: o.value.errors }
1284
+ ), null;
1285
+ if (!u(n.pageData.layout) || !i.value.isValid)
1286
+ return l(
1287
+ "invalid-layout",
1288
+ "[PageReader] Invalid layout node. Falling back to content-only rendering.",
1289
+ { errors: i.value.errors }
1290
+ ), n.pageData.content;
1291
+ const d = {
1292
+ ...n.pageData.content,
1293
+ slot: n.pageData.content.slot ?? "default"
1294
+ }, A = Array.isArray(n.pageData.layout.children) ? n.pageData.layout.children : [];
1295
+ return {
1296
+ ...n.pageData.layout,
1297
+ children: [...A, d]
1298
+ };
1299
+ }), I = { props: n, pageValidationResult: e, contentValidationResult: o, layoutValidationResult: i, reportedDiagnostics: a, reportOnce: l, isNodeObject: u, safeVariables: b, readerRoot: v, NodeRenderer: Pn, ErrorBoundary: kn };
1300
+ return Object.defineProperty(I, "__isScriptSetup", { enumerable: !1, value: !0 }), I;
1301
+ }
1302
+ }), so = { class: "ipb-page-reader" }, co = {
1303
+ key: 1,
1304
+ class: "ipb-page-reader__invalid",
1305
+ role: "alert"
1306
+ };
1307
+ function uo(t, r, n, e, o, i) {
1308
+ return x(), C("div", so, [
1309
+ e.readerRoot ? (x(), Se(e.ErrorBoundary, {
1310
+ key: 0,
1311
+ "fallback-message": "This page could not be fully rendered.",
1312
+ "show-details-in-dev": !0,
1313
+ "diagnostic-context": "PageReader"
1314
+ }, {
1315
+ default: Pt(() => [
1316
+ Re(e.NodeRenderer, {
1317
+ node: e.readerRoot,
1318
+ variables: e.safeVariables
1319
+ }, null, 8, ["node", "variables"])
1320
+ ]),
1321
+ _: 1
1322
+ /* STABLE */
1323
+ })) : (x(), C("div", co, " This page data is invalid and cannot be rendered safely. "))
1324
+ ]);
1325
+ }
1326
+ const fo = /* @__PURE__ */ q(lo, [["render", uo], ["__scopeId", "data-v-2928bf3c"], ["__file", "/app/src/components/reader/PageReader.vue"]]), Xe = {
1327
+ desktop: { width: 1440, height: 900, label: "Desktop" },
1328
+ tablet: { width: 768, height: 1024, label: "Tablet" },
1329
+ mobile: { width: 375, height: 812, label: "Mobile" },
1330
+ custom: { width: 0, height: 0, label: "Custom" }
1331
+ }, po = Symbol("pageBuilder"), mo = Symbol("editor"), Ht = Symbol("nodeTree"), Wt = Symbol("dragDrop");
1332
+ function ce(t) {
1333
+ return typeof t == "object" && t !== null && !Array.isArray(t);
1334
+ }
1335
+ function go(t) {
1336
+ return typeof t == "number" && Number.isInteger(t) && t > 0;
1337
+ }
1338
+ function Vt(t) {
1339
+ return typeof t == "number" && Number.isInteger(t) && t >= 0;
1340
+ }
1341
+ function tn(t, r, n) {
1342
+ return {
1343
+ id: t,
1344
+ name: r,
1345
+ slot: n,
1346
+ props: {},
1347
+ children: []
1348
+ };
1349
+ }
1350
+ function Ae(t, r = /* @__PURE__ */ new WeakSet()) {
1351
+ return !ce(t) || r.has(t) || (r.add(t), !go(t.id)) || typeof t.name != "string" || t.name.trim().length === 0 || !(t.slot === null || typeof t.slot == "string") || !ce(t.props) || !Array.isArray(t.children) || typeof t.readonly < "u" && typeof t.readonly != "boolean" ? !1 : t.children.every((n) => Ae(n, r));
1352
+ }
1353
+ function bo(t) {
1354
+ if (!ce(t)) return {};
1355
+ const r = {};
1356
+ for (const [n, e] of Object.entries(t))
1357
+ typeof e == "string" && (r[n] = e);
1358
+ return r;
1359
+ }
1360
+ function vo(t) {
1361
+ const r = [], n = tn(1, "PbSection", null), e = tn(100, "PbContainer", null), o = ce(t) ? t : {};
1362
+ let i = n;
1363
+ Ae(o.content) ? i = structuredClone(o.content) : r.push("content node is invalid");
1364
+ let a = e;
1365
+ Ae(o.layout) ? a = structuredClone(o.layout) : r.push("layout node is invalid");
1366
+ const l = o.maxId, u = Math.max(We(i), We(a)), b = Vt(l), v = b ? Math.max(Math.trunc(l), u) : u;
1367
+ b || r.push("maxId is invalid");
1368
+ const I = bo(o.variables);
1369
+ ce(o.variables) || r.push("variables map is invalid");
1370
+ const d = ce(o.meta) ? o.meta : {};
1371
+ ce(o.meta) || r.push("meta object is invalid");
1372
+ const A = {
1373
+ meta: {
1374
+ id: typeof d.id == "string" ? d.id : "unknown-page",
1375
+ name: typeof d.name == "string" ? d.name : "Untitled page",
1376
+ url: typeof d.url == "string" ? d.url : "/",
1377
+ status: d.status === "draft" || d.status === "published" || d.status === "archived" ? d.status : "draft",
1378
+ updatedAt: typeof d.updatedAt == "string" ? d.updatedAt : void 0,
1379
+ createdAt: typeof d.createdAt == "string" ? d.createdAt : void 0
1380
+ },
1381
+ content: i,
1382
+ layout: a,
1383
+ maxId: v,
1384
+ variables: I
1385
+ };
1386
+ return r.length > 0 && Ue(
1387
+ "usePageBuilder.sanitizeInitialData",
1388
+ Z(
1389
+ "INVALID_PAGE_DATA",
1390
+ `[PageBuilder] Invalid page data detected. Falling back to safe defaults for: ${r.join(", ")}.`
1391
+ ),
1392
+ { issues: r }
1393
+ ), A;
1394
+ }
1395
+ function nn(t) {
1396
+ let r;
1397
+ try {
1398
+ r = JSON.parse(t);
1399
+ } catch (e) {
1400
+ throw Z(
1401
+ "INVALID_SNAPSHOT",
1402
+ "[PageBuilder] Snapshot JSON is invalid.",
1403
+ {
1404
+ cause: e,
1405
+ details: {
1406
+ snapshotPreview: t.slice(0, 200)
1407
+ }
1408
+ }
1409
+ );
1410
+ }
1411
+ if (!ce(r) || !Ae(r.content) || !Ae(r.layout) || !Vt(r.maxId))
1412
+ throw Z(
1413
+ "INVALID_SNAPSHOT",
1414
+ "[PageBuilder] Snapshot payload shape is invalid.",
1415
+ {
1416
+ details: {
1417
+ contentValid: ce(r) ? Ae(r.content) : !1,
1418
+ layoutValid: ce(r) ? Ae(r.layout) : !1,
1419
+ maxIdValid: ce(r) ? Vt(r.maxId) : !1
1420
+ }
1421
+ }
1422
+ );
1423
+ const n = Math.max(
1424
+ Math.trunc(r.maxId),
1425
+ We(r.content),
1426
+ We(r.layout)
1427
+ );
1428
+ return {
1429
+ content: r.content,
1430
+ layout: r.layout,
1431
+ maxId: n
1432
+ };
1433
+ }
1434
+ function ho(t) {
1435
+ const { initialData: r, mode: n = "read" } = t, e = vo(r), o = R(n), i = R(e.meta), a = R(e.content), l = R(e.layout), u = R(e.maxId), b = R(e.variables), v = R(!1), I = N(() => ({
1436
+ meta: i.value,
1437
+ content: a.value,
1438
+ layout: l.value,
1439
+ maxId: u.value,
1440
+ variables: b.value
1441
+ })), d = k({
1442
+ content: e.content,
1443
+ layout: e.layout
1444
+ });
1445
+ function A(L) {
1446
+ return JSON.stringify(L);
1447
+ }
1448
+ function k(L) {
1449
+ return JSON.stringify(L);
1450
+ }
1451
+ function y() {
1452
+ v.value = k({
1453
+ content: a.value,
1454
+ layout: l.value
1455
+ }) !== d;
1456
+ }
1457
+ function D(L) {
1458
+ o.value = L;
1459
+ }
1460
+ function c(L) {
1461
+ a.value = L, u.value = Math.max(u.value, We(L)), y();
1462
+ }
1463
+ function m(L) {
1464
+ l.value = L, u.value = Math.max(u.value, We(L)), y();
1465
+ }
1466
+ function p() {
1467
+ return u.value++, u.value;
1468
+ }
1469
+ function g() {
1470
+ return A({
1471
+ content: a.value,
1472
+ layout: l.value,
1473
+ maxId: u.value
1474
+ });
1475
+ }
1476
+ function E(L) {
1477
+ try {
1478
+ const P = nn(L);
1479
+ a.value = P.content, l.value = P.layout, u.value = P.maxId, y();
1480
+ } catch (P) {
1481
+ throw Z(
1482
+ "INVALID_SNAPSHOT",
1483
+ "[PageBuilder] Unable to restore snapshot.",
1484
+ {
1485
+ cause: P,
1486
+ details: {
1487
+ reason: Bt(P)
1488
+ }
1489
+ }
1490
+ );
1491
+ }
1492
+ }
1493
+ function O() {
1494
+ const L = nn(
1495
+ JSON.stringify({
1496
+ content: e.content,
1497
+ layout: e.layout,
1498
+ maxId: e.maxId
1499
+ })
1500
+ );
1501
+ a.value = structuredClone(L.content), l.value = structuredClone(L.layout), u.value = L.maxId, b.value = structuredClone(e.variables), v.value = !1;
1502
+ }
1503
+ return {
1504
+ mode: o,
1505
+ pageData: I,
1506
+ content: a,
1507
+ layout: l,
1508
+ maxId: u,
1509
+ variables: b,
1510
+ isDirty: v,
1511
+ setMode: D,
1512
+ updateContent: c,
1513
+ updateLayout: m,
1514
+ nextId: p,
1515
+ getSnapshot: g,
1516
+ restoreSnapshot: E,
1517
+ reset: O
1518
+ };
1519
+ }
1520
+ function _o(t = {}) {
1521
+ const { initialSnapshot: r, initialLabel: n = "Initial state" } = t, e = r ? [{ timestamp: Date.now(), label: n, snapshot: r }] : [];
1522
+ let o = r ?? null;
1523
+ const i = $n({
1524
+ selectedNodeId: null,
1525
+ hoveredNodeId: null,
1526
+ leftDrawerOpen: !0,
1527
+ rightDrawerOpen: !1,
1528
+ history: e,
1529
+ historyIndex: e.length > 0 ? 0 : -1,
1530
+ isDirty: !1,
1531
+ canvasScale: 1,
1532
+ viewport: "desktop"
1533
+ }), a = N(() => i.historyIndex > 0), l = N(() => i.historyIndex < i.history.length - 1);
1534
+ function u(m) {
1535
+ i.selectedNodeId = m, m !== null && (i.rightDrawerOpen = !0);
1536
+ }
1537
+ function b(m) {
1538
+ i.hoveredNodeId = m;
1539
+ }
1540
+ function v() {
1541
+ i.leftDrawerOpen = !i.leftDrawerOpen;
1542
+ }
1543
+ function I() {
1544
+ i.rightDrawerOpen = !i.rightDrawerOpen;
1545
+ }
1546
+ function d(m) {
1547
+ i.viewport = m;
1548
+ }
1549
+ function A() {
1550
+ var p;
1551
+ if (o === null || i.historyIndex < 0) {
1552
+ i.isDirty = !1;
1553
+ return;
1554
+ }
1555
+ const m = (p = i.history[i.historyIndex]) == null ? void 0 : p.snapshot;
1556
+ i.isDirty = m !== o;
1557
+ }
1558
+ function k(m, p = n) {
1559
+ o = m, i.history = [{ timestamp: Date.now(), label: p, snapshot: m }], i.historyIndex = 0, i.isDirty = !1;
1560
+ }
1561
+ function y(m, p) {
1562
+ var E;
1563
+ if (o === null) {
1564
+ k(p);
1565
+ return;
1566
+ }
1567
+ ((E = i.history[i.historyIndex]) == null ? void 0 : E.snapshot) !== p && (i.historyIndex < i.history.length - 1 && i.history.splice(i.historyIndex + 1), i.history.push({
1568
+ timestamp: Date.now(),
1569
+ label: m,
1570
+ snapshot: p
1571
+ }), i.historyIndex = i.history.length - 1, A());
1572
+ }
1573
+ function D() {
1574
+ var m;
1575
+ if (a.value)
1576
+ return i.historyIndex--, A(), (m = i.history[i.historyIndex]) == null ? void 0 : m.snapshot;
1577
+ }
1578
+ function c() {
1579
+ var m;
1580
+ if (l.value)
1581
+ return i.historyIndex++, A(), (m = i.history[i.historyIndex]) == null ? void 0 : m.snapshot;
1582
+ }
1583
+ return {
1584
+ ...Gn(i),
1585
+ canUndo: a,
1586
+ canRedo: l,
1587
+ selectNode: u,
1588
+ hoverNode: b,
1589
+ toggleLeftDrawer: v,
1590
+ toggleRightDrawer: I,
1591
+ setViewport: d,
1592
+ setHistoryBaseline: k,
1593
+ pushHistory: y,
1594
+ undo: D,
1595
+ redo: c
1596
+ };
1597
+ }
1598
+ function yo({ content: t, nextId: r, onUpdate: n, onSnapshot: e }) {
1599
+ function o(y, D) {
1600
+ const c = qn(t.value), m = JSON.stringify(c), p = qr(c);
1601
+ return D(p) === !1 || JSON.stringify(p) === m ? !1 : (n(p), e == null || e(y), !0);
1602
+ }
1603
+ function i(y, D, c, m = "default", p) {
1604
+ let g = null;
1605
+ return !o(`Add ${D}`, (O) => {
1606
+ if (!U(O, y)) return !1;
1607
+ g = r();
1608
+ const P = Zr(g, D, { slot: m, props: p });
1609
+ return Tn(O, y, P, c, m);
1610
+ }) || g === null ? null : g;
1611
+ }
1612
+ function a(y) {
1613
+ o("Delete node", (D) => {
1614
+ Yr(D, y);
1615
+ });
1616
+ }
1617
+ function l(y, D, c, m = "default") {
1618
+ o("Move node", (p) => Xr(p, y, D, c, m));
1619
+ }
1620
+ function u(y, D) {
1621
+ o("Update props", (c) => {
1622
+ const m = U(c, y);
1623
+ m && (m.props = { ...m.props, ...D });
1624
+ });
1625
+ }
1626
+ function b(y) {
1627
+ o("Duplicate node", (D) => {
1628
+ const c = U(D, y);
1629
+ if (!c) return;
1630
+ const m = ae(D, y);
1631
+ if (!m) return;
1632
+ const p = k(c);
1633
+ m.parent.children.splice(m.index + 1, 0, p);
1634
+ });
1635
+ }
1636
+ function v(y) {
1637
+ const D = U(t.value, y);
1638
+ if (!D || D.readonly) return !1;
1639
+ const c = ae(t.value, y);
1640
+ return c ? c.index > 0 : !1;
1641
+ }
1642
+ function I(y) {
1643
+ const D = U(t.value, y);
1644
+ if (!D || D.readonly) return !1;
1645
+ const c = ae(t.value, y);
1646
+ return c ? c.index < c.parent.children.length - 1 : !1;
1647
+ }
1648
+ function d(y) {
1649
+ v(y) && o("Move node up", (D) => {
1650
+ const c = ae(D, y);
1651
+ if (!c || c.index <= 0) return;
1652
+ const [m] = c.parent.children.splice(c.index, 1);
1653
+ c.parent.children.splice(c.index - 1, 0, m);
1654
+ });
1655
+ }
1656
+ function A(y) {
1657
+ I(y) && o("Move node down", (D) => {
1658
+ const c = ae(D, y);
1659
+ if (!c || c.index >= c.parent.children.length - 1) return;
1660
+ const [m] = c.parent.children.splice(c.index, 1);
1661
+ c.parent.children.splice(c.index + 1, 0, m);
1662
+ });
1663
+ }
1664
+ function k(y) {
1665
+ return {
1666
+ ...y,
1667
+ id: r(),
1668
+ props: { ...y.props },
1669
+ children: y.children.map((D) => k(D))
1670
+ };
1671
+ }
1672
+ return {
1673
+ addNode: i,
1674
+ deleteNode: a,
1675
+ moveNodeTo: l,
1676
+ updateNodeProps: u,
1677
+ duplicateNode: b,
1678
+ canMoveNodeUp: v,
1679
+ canMoveNodeDown: I,
1680
+ moveNodeUp: d,
1681
+ moveNodeDown: A
1682
+ };
1683
+ }
1684
+ const En = "default";
1685
+ function nt() {
1686
+ return {
1687
+ isDragging: !1,
1688
+ sourceNodeId: null,
1689
+ sourceComponentName: null,
1690
+ isNewComponent: !1,
1691
+ dropTargetId: null,
1692
+ dropIndex: 0,
1693
+ dropSlot: En
1694
+ };
1695
+ }
1696
+ function wo() {
1697
+ const t = R(nt());
1698
+ function r() {
1699
+ t.value = nt();
1700
+ }
1701
+ function n(l) {
1702
+ t.value = {
1703
+ ...nt(),
1704
+ isDragging: !0,
1705
+ sourceNodeId: l
1706
+ };
1707
+ }
1708
+ function e(l) {
1709
+ t.value = {
1710
+ ...nt(),
1711
+ isDragging: !0,
1712
+ sourceComponentName: l,
1713
+ isNewComponent: !0
1714
+ };
1715
+ }
1716
+ function o(l, u, b = En) {
1717
+ t.value.isDragging && (t.value.dropTargetId = l, t.value.dropIndex = u, t.value.dropSlot = b);
1718
+ }
1719
+ function i() {
1720
+ const l = { ...t.value };
1721
+ return r(), l;
1722
+ }
1723
+ function a() {
1724
+ r();
1725
+ }
1726
+ return {
1727
+ dragState: t,
1728
+ startDragExisting: n,
1729
+ startDragNew: e,
1730
+ updateDropTarget: o,
1731
+ endDrag: i,
1732
+ cancelDrag: a
1733
+ };
1734
+ }
1735
+ const Nt = 240, St = 320, Tt = 3840, Ct = 4320, xo = /* @__PURE__ */ G({
1736
+ __name: "EditorToolbar",
1737
+ props: {
1738
+ canUndo: { type: Boolean, default: !1 },
1739
+ canRedo: { type: Boolean, default: !1 },
1740
+ isDirty: { type: Boolean, default: !1 },
1741
+ viewport: { type: String, default: "desktop" },
1742
+ customViewportWidth: { type: Number, default: 1024 },
1743
+ customViewportHeight: { type: Number, default: 768 },
1744
+ activeViewportWidth: { type: Number, default: null },
1745
+ activeViewportHeight: { type: Number, default: null }
1746
+ },
1747
+ emits: ["undo", "redo", "save", "viewport-change", "custom-viewport-change"],
1748
+ setup(t, { expose: r, emit: n }) {
1749
+ r();
1750
+ const e = t, o = n, { t: i } = pe(), a = {
1751
+ desktop: "toolbar.viewport.desktop",
1752
+ tablet: "toolbar.viewport.tablet",
1753
+ mobile: "toolbar.viewport.mobile",
1754
+ custom: "toolbar.viewport.custom"
1755
+ }, l = ["desktop", "tablet", "mobile", "custom"], u = R(/* @__PURE__ */ new Map());
1756
+ function b(p) {
1757
+ return i(a[p]);
1758
+ }
1759
+ function v(p) {
1760
+ return i("toolbar.viewport.switchAriaLabel", { viewport: b(p) });
1761
+ }
1762
+ function I(p, g) {
1763
+ const E = g instanceof HTMLButtonElement ? g : g && "$el" in g && g.$el instanceof HTMLButtonElement ? g.$el : null;
1764
+ if (E) {
1765
+ u.value.set(p, E);
1766
+ return;
1767
+ }
1768
+ u.value.delete(p);
1769
+ }
1770
+ function d(p) {
1771
+ return l.indexOf(p);
1772
+ }
1773
+ function A(p) {
1774
+ var g;
1775
+ (g = u.value.get(p)) == null || g.focus();
1776
+ }
1777
+ function k(p, g) {
1778
+ const E = d(g);
1779
+ if (E < 0 || p.key !== "ArrowLeft" && p.key !== "ArrowRight" && p.key !== "ArrowUp" && p.key !== "ArrowDown" && p.key !== "Home" && p.key !== "End")
1780
+ return;
1781
+ p.preventDefault();
1782
+ let O = E;
1783
+ p.key === "ArrowLeft" || p.key === "ArrowUp" ? O = (E - 1 + l.length) % l.length : p.key === "ArrowRight" || p.key === "ArrowDown" ? O = (E + 1) % l.length : p.key === "Home" ? O = 0 : p.key === "End" && (O = l.length - 1);
1784
+ const L = l[O];
1785
+ o("viewport-change", L), ue(() => {
1786
+ A(L);
1787
+ });
1788
+ }
1789
+ function y(p, g, E) {
1790
+ return Math.max(g, Math.min(E, p));
1791
+ }
1792
+ function D(p) {
1793
+ if (!p.trim()) return null;
1794
+ const g = Number(p);
1795
+ return Number.isFinite(g) ? Math.round(g) : null;
1796
+ }
1797
+ function c(p, g) {
1798
+ const E = D(g);
1799
+ if (E === null) return;
1800
+ const O = y(p === "width" ? E : e.customViewportWidth, Nt, Tt), L = y(p === "height" ? E : e.customViewportHeight, St, Ct);
1801
+ o("custom-viewport-change", { width: O, height: L });
1802
+ }
1803
+ const m = { MIN_VIEWPORT_WIDTH: Nt, MIN_VIEWPORT_HEIGHT: St, MAX_VIEWPORT_WIDTH: Tt, MAX_VIEWPORT_HEIGHT: Ct, props: e, emit: o, t: i, VIEWPORT_LABEL_KEYS: a, VIEWPORT_ORDER: l, viewportButtonRefs: u, getViewportLabel: b, getViewportSwitchAriaLabel: v, setViewportButtonRef: I, getViewportIndex: d, focusViewportButton: A, handleViewportKeydown: k, clampViewportSize: y, parseViewportSize: D, updateCustomViewportSize: c, get VIEWPORT_PRESETS() {
1804
+ return Xe;
1805
+ } };
1806
+ return Object.defineProperty(m, "__isScriptSetup", { enumerable: !1, value: !0 }), m;
1807
+ }
1808
+ }), Io = ["aria-label"], Do = ["aria-label"], No = ["disabled", "aria-label", "title"], So = ["disabled", "aria-label", "title"], To = ["aria-label"], Co = ["title", "aria-label", "aria-pressed", "data-viewport-preset", "onClick", "onKeydown"], ko = {
1809
+ key: 0,
1810
+ class: "ipb-toolbar__custom-size"
1811
+ }, Po = { class: "ipb-toolbar__size-control" }, Eo = ["aria-label", "value"], Ro = { class: "ipb-toolbar__size-control" }, Ao = ["aria-label", "value"], Lo = {
1812
+ key: 1,
1813
+ class: "ipb-toolbar__viewport-size",
1814
+ "aria-live": "polite"
1815
+ }, Vo = ["aria-label"], Mo = ["aria-label"], Oo = ["aria-label", "title"];
1816
+ function Bo(t, r, n, e, o, i) {
1817
+ return x(), C("header", {
1818
+ class: "ipb-toolbar",
1819
+ role: "toolbar",
1820
+ "aria-label": e.t("toolbar.aria.toolbar")
1821
+ }, [
1822
+ S("div", {
1823
+ class: "ipb-toolbar__left",
1824
+ role: "group",
1825
+ "aria-label": e.t("toolbar.aria.historyControls")
1826
+ }, [
1827
+ S("button", {
1828
+ type: "button",
1829
+ class: "ipb-toolbar__btn",
1830
+ disabled: !n.canUndo,
1831
+ "aria-label": e.t("toolbar.undo.ariaLabel"),
1832
+ title: e.t("toolbar.undo.title"),
1833
+ "aria-keyshortcuts": "Control+Z Meta+Z",
1834
+ onClick: r[0] || (r[0] = (a) => t.$emit("undo"))
1835
+ }, " ↩ ", 8, No),
1836
+ S("button", {
1837
+ type: "button",
1838
+ class: "ipb-toolbar__btn",
1839
+ disabled: !n.canRedo,
1840
+ "aria-label": e.t("toolbar.redo.ariaLabel"),
1841
+ title: e.t("toolbar.redo.title"),
1842
+ "aria-keyshortcuts": "Control+Y Meta+Y Control+Shift+Z Meta+Shift+Z",
1843
+ onClick: r[1] || (r[1] = (a) => t.$emit("redo"))
1844
+ }, " ↪ ", 8, So)
1845
+ ], 8, Do),
1846
+ S("div", {
1847
+ class: "ipb-toolbar__center",
1848
+ role: "group",
1849
+ "aria-label": e.t("toolbar.aria.viewportControls")
1850
+ }, [
1851
+ (x(!0), C(
1852
+ he,
1853
+ null,
1854
+ ve(e.VIEWPORT_PRESETS, (a, l) => (x(), C("button", {
1855
+ key: l,
1856
+ ref_for: !0,
1857
+ ref: (u) => e.setViewportButtonRef(l, u),
1858
+ type: "button",
1859
+ class: _e(["ipb-toolbar__btn", { "ipb-toolbar__btn--active": n.viewport === l }]),
1860
+ title: e.getViewportLabel(l),
1861
+ "aria-label": e.getViewportSwitchAriaLabel(l),
1862
+ "aria-pressed": n.viewport === l ? "true" : "false",
1863
+ "data-viewport-preset": l,
1864
+ onClick: (u) => t.$emit("viewport-change", l),
1865
+ onKeydown: (u) => e.handleViewportKeydown(u, l)
1866
+ }, z(e.getViewportLabel(l)), 43, Co))),
1867
+ 128
1868
+ /* KEYED_FRAGMENT */
1869
+ )),
1870
+ n.viewport === "custom" ? (x(), C("div", ko, [
1871
+ S("label", Po, [
1872
+ S(
1873
+ "span",
1874
+ null,
1875
+ z(e.t("toolbar.viewport.width.short")),
1876
+ 1
1877
+ /* TEXT */
1878
+ ),
1879
+ S("input", {
1880
+ class: "ipb-toolbar__size-input",
1881
+ type: "number",
1882
+ inputmode: "numeric",
1883
+ "aria-label": e.t("toolbar.viewport.width.ariaLabel"),
1884
+ min: e.MIN_VIEWPORT_WIDTH,
1885
+ max: e.MAX_VIEWPORT_WIDTH,
1886
+ value: n.customViewportWidth,
1887
+ onInput: r[2] || (r[2] = (a) => e.updateCustomViewportSize("width", a.target.value))
1888
+ }, null, 40, Eo)
1889
+ ]),
1890
+ S("label", Ro, [
1891
+ S(
1892
+ "span",
1893
+ null,
1894
+ z(e.t("toolbar.viewport.height.short")),
1895
+ 1
1896
+ /* TEXT */
1897
+ ),
1898
+ S("input", {
1899
+ class: "ipb-toolbar__size-input",
1900
+ type: "number",
1901
+ inputmode: "numeric",
1902
+ "aria-label": e.t("toolbar.viewport.height.ariaLabel"),
1903
+ min: e.MIN_VIEWPORT_HEIGHT,
1904
+ max: e.MAX_VIEWPORT_HEIGHT,
1905
+ value: n.customViewportHeight,
1906
+ onInput: r[3] || (r[3] = (a) => e.updateCustomViewportSize("height", a.target.value))
1907
+ }, null, 40, Ao)
1908
+ ])
1909
+ ])) : Y("v-if", !0),
1910
+ n.activeViewportWidth !== null && n.activeViewportHeight !== null ? (x(), C(
1911
+ "span",
1912
+ Lo,
1913
+ z(n.activeViewportWidth) + "×" + z(n.activeViewportHeight),
1914
+ 1
1915
+ /* TEXT */
1916
+ )) : Y("v-if", !0)
1917
+ ], 8, To),
1918
+ S("div", {
1919
+ class: "ipb-toolbar__right",
1920
+ role: "group",
1921
+ "aria-label": e.t("toolbar.aria.saveControls")
1922
+ }, [
1923
+ n.isDirty ? (x(), C("span", {
1924
+ key: 0,
1925
+ class: "ipb-toolbar__dirty-indicator",
1926
+ role: "status",
1927
+ "aria-label": e.t("toolbar.aria.unsavedChanges")
1928
+ }, " ● ", 8, Mo)) : Y("v-if", !0),
1929
+ S("button", {
1930
+ type: "button",
1931
+ class: "ipb-toolbar__btn ipb-toolbar__btn--primary",
1932
+ "aria-label": e.t("toolbar.save.ariaLabel"),
1933
+ title: e.t("toolbar.save.title"),
1934
+ "aria-keyshortcuts": "Control+S Meta+S",
1935
+ onClick: r[4] || (r[4] = (a) => t.$emit("save"))
1936
+ }, z(e.t("toolbar.save")), 9, Oo)
1937
+ ], 8, Vo)
1938
+ ], 8, Io);
1939
+ }
1940
+ const zo = /* @__PURE__ */ q(xo, [["render", Bo], ["__scopeId", "data-v-fa6dcc09"], ["__file", "/app/src/components/editor/EditorToolbar.vue"]]);
1941
+ function jo(t, r) {
1942
+ const n = Le(t.name);
1943
+ return !n || n.slots.length === 0 ? [] : n.slots.filter((e) => {
1944
+ const o = e.allowedComponents;
1945
+ return !o || o.length === 0 || o.includes(r);
1946
+ });
1947
+ }
1948
+ function Ne(t, r, n) {
1949
+ const e = jo(t, n);
1950
+ if (e.length === 0) return null;
1951
+ if (r) {
1952
+ const i = e.find((a) => a.name === r);
1953
+ if (i) return i.name;
1954
+ }
1955
+ const o = e.find((i) => i.name === "default");
1956
+ return (o == null ? void 0 : o.name) ?? e[0].name;
1957
+ }
1958
+ function rt(t) {
1959
+ return Number.isFinite(t) ? Math.trunc(t) : 0;
1960
+ }
1961
+ function Ho(t) {
1962
+ return `ipb-node-${t}`;
1963
+ }
1964
+ function Wo(t, r = {}) {
1965
+ const n = r.createKey ?? ((i) => Ho(i.id)), e = [], o = [
1966
+ { node: t, depth: 0, parentId: null }
1967
+ ];
1968
+ for (; o.length > 0; ) {
1969
+ const i = o.pop();
1970
+ if (!i) break;
1971
+ const a = e.length;
1972
+ e.push({
1973
+ node: i.node,
1974
+ id: i.node.id,
1975
+ key: n(i.node),
1976
+ depth: i.depth,
1977
+ index: a,
1978
+ parentId: i.parentId
1979
+ });
1980
+ for (let l = i.node.children.length - 1; l >= 0; l--)
1981
+ o.push({
1982
+ node: i.node.children[l],
1983
+ depth: i.depth + 1,
1984
+ parentId: i.node.id
1985
+ });
1986
+ }
1987
+ return e;
1988
+ }
1989
+ function Uo(t, r, n, e = 0) {
1990
+ const o = Math.max(0, rt(t)), i = Math.max(0, rt(n)), a = Math.max(0, rt(e));
1991
+ if (o === 0 || i === 0)
1992
+ return { start: 0, end: 0, size: 0, total: o };
1993
+ const l = o - 1, u = Math.min(Math.max(rt(r), 0), l), b = Math.max(0, u - a), v = Math.min(o, u + i + a);
1994
+ return {
1995
+ start: b,
1996
+ end: v,
1997
+ size: Math.max(0, v - b),
1998
+ total: o
1999
+ };
2000
+ }
2001
+ function ml(t, r, n, e = 0) {
2002
+ const o = Uo(t.length, r, n, e);
2003
+ return {
2004
+ rows: t.slice(o.start, o.end),
2005
+ range: o
2006
+ };
2007
+ }
2008
+ function gl(t) {
2009
+ const r = [], n = /* @__PURE__ */ new Map(), e = /* @__PURE__ */ new Map();
2010
+ for (let o = 0; o < t.length; o++) {
2011
+ const i = t[o];
2012
+ r[o] = i.key, n.has(i.key) || n.set(i.key, o), e.has(i.id) || e.set(i.id, o);
2013
+ }
2014
+ return {
2015
+ keyByIndex: r,
2016
+ indexByKey: n,
2017
+ indexByNodeId: e
2018
+ };
2019
+ }
2020
+ const Ko = /* @__PURE__ */ G({
2021
+ __name: "TreePanel",
2022
+ props: {
2023
+ content: { type: Object, required: !0 },
2024
+ selectedNodeId: { type: Number, default: null }
2025
+ },
2026
+ emits: ["select"],
2027
+ setup(t, { expose: r, emit: n }) {
2028
+ r();
2029
+ const e = t, o = n, { t: i } = pe(), a = je(Ht, null), l = je(Wt, null), u = R(!1), b = R(null), v = R(null), I = N(() => e.content.id);
2030
+ function d(f, w, T = "on") {
2031
+ var fe, ye;
2032
+ const W = (ye = (fe = f.target) == null ? void 0 : fe.closest) == null ? void 0 : ye.call(fe, "[data-drop-zone]"), H = W == null ? void 0 : W.getAttribute("data-drop-zone");
2033
+ if (H === "above") return "above";
2034
+ if (H === "below") return "below";
2035
+ if (!w) return T;
2036
+ const K = w.getBoundingClientRect(), re = f.clientY - K.top, oe = K.height / 3;
2037
+ return re < oe ? "above" : re > 2 * oe ? "below" : "on";
2038
+ }
2039
+ function A(f, w) {
2040
+ const T = U(e.content, f);
2041
+ if (!T) return null;
2042
+ const W = T.slot ?? "default", H = ae(e.content, f);
2043
+ if (!H) {
2044
+ const re = e.content.id, oe = w === "above" ? 0 : e.content.children.length;
2045
+ return { parentId: re, index: oe, slot: "default" };
2046
+ }
2047
+ const K = w === "above" ? H.index : H.index + 1;
2048
+ return { parentId: H.parent.id, index: K, slot: W };
2049
+ }
2050
+ function k(f, w) {
2051
+ return f.id === w ? !0 : f.children.some((T) => k(T, w));
2052
+ }
2053
+ function y(f) {
2054
+ var w;
2055
+ return f.sourceComponentName ? f.sourceComponentName : f.sourceNodeId === null ? null : ((w = U(e.content, f.sourceNodeId)) == null ? void 0 : w.name) ?? null;
2056
+ }
2057
+ function D(f, w) {
2058
+ if (f.sourceNodeId === w) return !1;
2059
+ const T = y(f);
2060
+ if (!T) return !1;
2061
+ const W = U(e.content, w);
2062
+ if (!W || W.readonly) return !1;
2063
+ if (!f.isNewComponent && f.sourceNodeId !== null) {
2064
+ const H = U(e.content, f.sourceNodeId);
2065
+ if (!H || H.readonly || k(H, w)) return !1;
2066
+ }
2067
+ return Ne(W, "default", T) !== null;
2068
+ }
2069
+ function c(f, w, T) {
2070
+ const W = y(f);
2071
+ if (!W) return !1;
2072
+ const H = U(e.content, w);
2073
+ if (!H || H.readonly || Ne(H, T, W) === null) return !1;
2074
+ if (!f.isNewComponent && f.sourceNodeId !== null) {
2075
+ const K = U(e.content, f.sourceNodeId);
2076
+ if (!K || K.readonly || k(K, w)) return !1;
2077
+ }
2078
+ return !0;
2079
+ }
2080
+ const m = N(() => Wo(e.content).map((f) => ({
2081
+ id: f.id,
2082
+ key: f.key,
2083
+ name: f.node.name,
2084
+ depth: f.depth,
2085
+ readonly: !!f.node.readonly
2086
+ }))), p = R(/* @__PURE__ */ new Map());
2087
+ function g(f, w) {
2088
+ const T = w instanceof HTMLButtonElement ? w : w && "$el" in w && w.$el instanceof HTMLButtonElement ? w.$el : null;
2089
+ if (T) {
2090
+ p.value.set(f, T);
2091
+ return;
2092
+ }
2093
+ p.value.delete(f);
2094
+ }
2095
+ function E(f) {
2096
+ if (!(f instanceof HTMLElement)) return null;
2097
+ const w = f.dataset.nodeId;
2098
+ if (!w) return null;
2099
+ const T = Number(w);
2100
+ return Number.isInteger(T) ? T : null;
2101
+ }
2102
+ function O(f = !0) {
2103
+ if (m.value.length === 0) return -1;
2104
+ if (e.selectedNodeId !== null) {
2105
+ const w = m.value.findIndex((T) => T.id === e.selectedNodeId);
2106
+ if (w >= 0) return w;
2107
+ }
2108
+ return f ? 0 : -1;
2109
+ }
2110
+ function L(f) {
2111
+ var w;
2112
+ (w = p.value.get(f)) == null || w.focus();
2113
+ }
2114
+ function P(f) {
2115
+ const w = m.value[f];
2116
+ w && (o("select", w.id), ue(() => {
2117
+ L(w.id);
2118
+ }));
2119
+ }
2120
+ function F(f) {
2121
+ var T;
2122
+ const w = O();
2123
+ return ((T = m.value[w]) == null ? void 0 : T.id) === f;
2124
+ }
2125
+ const ee = N(() => !!(a && l)), te = (f) => !!(l != null && l.dragState.value.isDragging && b.value === f && v.value === "on"), ne = (f) => !!(l != null && l.dragState.value.isDragging && b.value === f && v.value === "above"), le = (f) => !!(l != null && l.dragState.value.isDragging && b.value === f && v.value === "below");
2126
+ function me(f) {
2127
+ return !ee.value || f.readonly ? !1 : f.id !== I.value;
2128
+ }
2129
+ function Te(f, w) {
2130
+ !l || !me(f) || (u.value = !1, l.startDragExisting(f.id), w.dataTransfer && (w.dataTransfer.effectAllowed = "move", w.dataTransfer.setData("application/x-ipb-node-id", String(f.id)), w.dataTransfer.setData("text/plain", String(f.id))));
2131
+ }
2132
+ function Ke(f, w) {
2133
+ if (!l || !l.dragState.value.isDragging) return;
2134
+ const T = l.dragState.value, W = d(w, p.value.get(f.id));
2135
+ if (W === "on") {
2136
+ if (!D(T, f.id)) return;
2137
+ w.preventDefault(), w.dataTransfer && (w.dataTransfer.dropEffect = T.isNewComponent ? "copy" : "move"), b.value = f.id, v.value = "on", l.updateDropTarget(f.id, 0, "default");
2138
+ return;
2139
+ }
2140
+ const H = A(f.id, W);
2141
+ !H || !c(T, H.parentId, H.slot) || (w.preventDefault(), w.dataTransfer && (w.dataTransfer.dropEffect = T.isNewComponent ? "copy" : "move"), b.value = f.id, v.value = W, l.updateDropTarget(H.parentId, H.index, H.slot));
2142
+ }
2143
+ function Fe(f, w) {
2144
+ var Ce, $e;
2145
+ if (w.preventDefault(), !a || !l || !l.dragState.value.isDragging) return;
2146
+ const T = l.dragState.value, H = (b.value === f.id && v.value ? v.value : null) ?? d(w, p.value.get(f.id), "on");
2147
+ if (H === "on") {
2148
+ const we = U(e.content, f.id);
2149
+ if (!we || !D(T, f.id)) {
2150
+ l.cancelDrag();
2151
+ return;
2152
+ }
2153
+ const xe = y(T), Oe = xe ? Ne(we, "default", xe) ?? "default" : "default";
2154
+ if (T.isNewComponent && T.sourceComponentName) {
2155
+ const Ge = (Ce = Le(T.sourceComponentName)) == null ? void 0 : Ce.defaultProps, Be = a.addNode(f.id, T.sourceComponentName, 0, Oe, Ge);
2156
+ u.value = !0, l.endDrag(), Be !== null && o("select", Be);
2157
+ return;
2158
+ }
2159
+ if (T.sourceNodeId === null) return;
2160
+ a.moveNodeTo(T.sourceNodeId, f.id, 0, Oe), u.value = !0, l.endDrag(), o("select", T.sourceNodeId);
2161
+ return;
2162
+ }
2163
+ const K = A(f.id, H);
2164
+ if (!K || !c(T, K.parentId, K.slot)) {
2165
+ l.cancelDrag();
2166
+ return;
2167
+ }
2168
+ const re = U(e.content, K.parentId), oe = y(T), fe = re && oe ? Ne(re, K.slot, oe) ?? K.slot : K.slot;
2169
+ if (T.isNewComponent && T.sourceComponentName) {
2170
+ const we = ($e = Le(T.sourceComponentName)) == null ? void 0 : $e.defaultProps, xe = a.addNode(
2171
+ K.parentId,
2172
+ T.sourceComponentName,
2173
+ K.index,
2174
+ fe,
2175
+ we
2176
+ );
2177
+ u.value = !0, l.endDrag(), xe !== null && o("select", xe);
2178
+ return;
2179
+ }
2180
+ if (T.sourceNodeId === null) return;
2181
+ let ye = K.index;
2182
+ const Me = ae(e.content, T.sourceNodeId);
2183
+ Me && Me.parent.id === K.parentId && Me.index < K.index && (ye = K.index - 1), a.moveNodeTo(T.sourceNodeId, K.parentId, ye, fe), u.value = !0, l.endDrag(), o("select", T.sourceNodeId);
2184
+ }
2185
+ function Ve() {
2186
+ b.value = null, v.value = null, !u.value && (l != null && l.dragState.value.isDragging) && l.cancelDrag();
2187
+ }
2188
+ function h(f) {
2189
+ if (m.value.length === 0) return;
2190
+ const w = E(f.target), T = w === null ? O() : m.value.findIndex((W) => W.id === w);
2191
+ if (!(T < 0)) {
2192
+ if (f.key === "ArrowDown") {
2193
+ f.preventDefault();
2194
+ const W = Math.min(m.value.length - 1, T + 1);
2195
+ P(W);
2196
+ return;
2197
+ }
2198
+ if (f.key === "ArrowUp") {
2199
+ f.preventDefault();
2200
+ const W = Math.max(0, T - 1);
2201
+ P(W);
2202
+ return;
2203
+ }
2204
+ if (f.key === "Home") {
2205
+ f.preventDefault(), P(0);
2206
+ return;
2207
+ }
2208
+ if (f.key === "End") {
2209
+ f.preventDefault(), P(m.value.length - 1);
2210
+ return;
2211
+ }
2212
+ (f.key === "Enter" || f.key === " ") && (f.preventDefault(), P(T));
2213
+ }
2214
+ }
2215
+ de(
2216
+ () => e.selectedNodeId,
2217
+ (f) => {
2218
+ f !== null && ue(() => {
2219
+ L(f);
2220
+ });
2221
+ }
2222
+ );
2223
+ const B = { props: e, emit: o, t: i, nodeTree: a, dragDrop: l, dropHandled: u, dropTargetRowId: b, dropZone: v, rootId: I, getDropZoneFromEvent: d, getSiblingDropTarget: A, isNodeInSubtree: k, getDraggedComponentName: y, isValidDropTarget: D, isValidSiblingDropTarget: c, rows: m, rowButtonRefs: p, setRowButtonRef: g, getRowIdFromEventTarget: E, getActiveRowIndex: O, focusRowById: L, selectRowByIndex: P, isRowTabStop: F, canDragDrop: ee, isDropTargetOn: te, isDropTargetAbove: ne, isDropTargetBelow: le, isRowDraggable: me, handleTreeDragStart: Te, handleTreeDragOver: Ke, handleTreeDrop: Fe, handleTreeDragEnd: Ve, handleTreeKeydown: h };
2224
+ return Object.defineProperty(B, "__isScriptSetup", { enumerable: !1, value: !0 }), B;
2225
+ }
2226
+ }), Fo = { class: "ipb-tree-panel" }, $o = ["aria-label"], Go = ["onDragover", "onDrop"], qo = {
2227
+ key: 0,
2228
+ class: "ipb-tree-panel__drop-line",
2229
+ "data-drop-zone": "above",
2230
+ "aria-hidden": "true"
2231
+ }, Yo = ["data-node-id", "draggable", "aria-selected", "aria-level", "aria-readonly", "tabindex", "onClick", "onDragstart"], Xo = { class: "ipb-tree-panel__name" }, Zo = { class: "ipb-tree-panel__id" }, Jo = {
2232
+ key: 0,
2233
+ class: "ipb-tree-panel__readonly"
2234
+ }, Qo = {
2235
+ key: 1,
2236
+ class: "ipb-tree-panel__drop-line",
2237
+ "data-drop-zone": "below",
2238
+ "aria-hidden": "true"
2239
+ };
2240
+ function ea(t, r, n, e, o, i) {
2241
+ return x(), C("div", Fo, [
2242
+ S("div", {
2243
+ class: "ipb-tree-panel__list",
2244
+ role: "tree",
2245
+ "aria-label": e.t("treePanel.ariaLabel"),
2246
+ onKeydown: e.handleTreeKeydown
2247
+ }, [
2248
+ (x(!0), C(
2249
+ he,
2250
+ null,
2251
+ ve(e.rows, (a) => (x(), C("div", {
2252
+ key: a.key,
2253
+ class: "ipb-tree-panel__row-wrapper",
2254
+ onDragover: (l) => e.handleTreeDragOver(a, l),
2255
+ onDrop: (l) => e.handleTreeDrop(a, l)
2256
+ }, [
2257
+ e.isDropTargetAbove(a.id) ? (x(), C("div", qo)) : Y("v-if", !0),
2258
+ S("button", {
2259
+ ref_for: !0,
2260
+ ref: (l) => e.setRowButtonRef(a.id, l),
2261
+ type: "button",
2262
+ class: _e(["ipb-tree-panel__item", {
2263
+ "ipb-tree-panel__item--selected": n.selectedNodeId === a.id,
2264
+ "ipb-tree-panel__item--readonly": a.readonly,
2265
+ "ipb-tree-panel__item--drop-target": e.isDropTargetOn(a.id),
2266
+ "ipb-tree-panel__item--draggable": e.isRowDraggable(a)
2267
+ }]),
2268
+ style: J({ paddingInlineStart: `${a.depth * 16 + 8}px` }),
2269
+ "data-node-id": a.id,
2270
+ draggable: e.isRowDraggable(a),
2271
+ role: "treeitem",
2272
+ "aria-selected": n.selectedNodeId === a.id ? "true" : "false",
2273
+ "aria-level": a.depth + 1,
2274
+ "aria-readonly": a.readonly ? "true" : "false",
2275
+ tabindex: e.isRowTabStop(a.id) ? 0 : -1,
2276
+ onClick: (l) => e.emit("select", a.id),
2277
+ onDragstart: (l) => e.handleTreeDragStart(a, l),
2278
+ onDragend: e.handleTreeDragEnd
2279
+ }, [
2280
+ S(
2281
+ "span",
2282
+ Xo,
2283
+ z(a.name),
2284
+ 1
2285
+ /* TEXT */
2286
+ ),
2287
+ S(
2288
+ "span",
2289
+ Zo,
2290
+ "#" + z(a.id),
2291
+ 1
2292
+ /* TEXT */
2293
+ ),
2294
+ a.readonly ? (x(), C(
2295
+ "span",
2296
+ Jo,
2297
+ z(e.t("treePanel.readonly")),
2298
+ 1
2299
+ /* TEXT */
2300
+ )) : Y("v-if", !0)
2301
+ ], 46, Yo),
2302
+ e.isDropTargetBelow(a.id) ? (x(), C("div", Qo)) : Y("v-if", !0)
2303
+ ], 40, Go))),
2304
+ 128
2305
+ /* KEYED_FRAGMENT */
2306
+ ))
2307
+ ], 40, $o)
2308
+ ]);
2309
+ }
2310
+ const ta = /* @__PURE__ */ q(Ko, [["render", ea], ["__scopeId", "data-v-3fdd09e6"], ["__file", "/app/src/components/editor/TreePanel.vue"]]), ze = "ipb-left-drawer-content", na = "ipb-left-drawer-tree-panel", ra = /* @__PURE__ */ G({
2311
+ __name: "LeftDrawer",
2312
+ props: {
2313
+ open: { type: Boolean, default: !0 },
2314
+ content: { type: Object, default: null },
2315
+ selectedNodeId: { type: Number, default: null }
2316
+ },
2317
+ emits: ["toggle", "dragStart", "dragEnd", "add", "select"],
2318
+ setup(t, { expose: r, emit: n }) {
2319
+ r();
2320
+ const e = t, o = n, i = N(() => rr()), { t: a } = pe(), l = R(""), u = R(!0), b = R(null), v = R(null), I = R(null), d = R(!1), A = N(() => {
2321
+ const P = l.value.trim().toLowerCase();
2322
+ if (!P)
2323
+ return i.value;
2324
+ const F = /* @__PURE__ */ new Map();
2325
+ for (const [ee, te] of i.value) {
2326
+ const ne = te.filter((le) => [le.name, le.label, le.description ?? "", ee, le.category].some((Te) => Te.toLowerCase().includes(P)));
2327
+ ne.length > 0 && F.set(ee, ne);
2328
+ }
2329
+ return F;
2330
+ });
2331
+ function k(P, F) {
2332
+ F.dataTransfer && (F.dataTransfer.effectAllowed = "copy", F.dataTransfer.setData("application/x-ipb-component", P), F.dataTransfer.setData("text/plain", P)), o("dragStart", P);
2333
+ }
2334
+ function y() {
2335
+ o("dragEnd");
2336
+ }
2337
+ function D(P) {
2338
+ o("add", P);
2339
+ }
2340
+ function c() {
2341
+ u.value = !u.value;
2342
+ }
2343
+ function m() {
2344
+ const P = b.value;
2345
+ return P ? P.querySelector(
2346
+ `#${ze} button:not([disabled]), #${ze} input:not([disabled]), #${ze} select:not([disabled]), #${ze} textarea:not([disabled]), #${ze} [tabindex]:not([tabindex="-1"])`
2347
+ ) : null;
2348
+ }
2349
+ function p() {
2350
+ var P, F;
2351
+ (P = I.value) == null || P.focus(), document.activeElement !== I.value && ((F = m()) == null || F.focus());
2352
+ }
2353
+ function g() {
2354
+ d.value = !e.open, o("toggle");
2355
+ }
2356
+ function E(P) {
2357
+ return a("leftDrawer.category.ariaLabel", { category: P });
2358
+ }
2359
+ function O(P) {
2360
+ return a("leftDrawer.component.dragAriaLabel", { label: P });
2361
+ }
2362
+ de(
2363
+ () => e.open,
2364
+ (P, F) => {
2365
+ var ee;
2366
+ if (P && !F && d.value && ue(() => {
2367
+ p();
2368
+ }), !P && F) {
2369
+ const te = document.activeElement;
2370
+ te instanceof HTMLElement && ((ee = b.value) != null && ee.contains(te)) && ue(() => {
2371
+ var ne;
2372
+ (ne = v.value) == null || ne.focus();
2373
+ });
2374
+ }
2375
+ P !== F && (d.value = !1);
2376
+ }
2377
+ );
2378
+ const L = { props: e, emit: o, categorizedComponents: i, t: a, searchQuery: l, treeOpen: u, DRAWER_CONTENT_ID: ze, TREE_PANEL_REGION_ID: na, drawerRef: b, drawerToggleRef: v, searchInputRef: I, focusContentOnNextOpen: d, filteredCategorizedComponents: A, handleDragStart: k, handleDragEnd: y, handleComponentAdd: D, toggleTree: c, getFirstFocusableDrawerControl: m, focusDrawerContent: p, handleDrawerToggle: g, getCategoryAriaLabel: E, getDragAriaLabel: O, TreePanel: ta };
2379
+ return Object.defineProperty(L, "__isScriptSetup", { enumerable: !1, value: !0 }), L;
2380
+ }
2381
+ }), oa = ["aria-label"], aa = { class: "ipb-left-drawer__header" }, ia = {
2382
+ class: "ipb-left-drawer__title",
2383
+ id: "ipb-left-drawer-title"
2384
+ }, la = ["aria-label", "aria-expanded"], sa = { class: "ipb-left-drawer__section" }, da = {
2385
+ class: "ipb-left-drawer__section-title",
2386
+ id: "ipb-left-drawer-components-title"
2387
+ }, ca = {
2388
+ class: "ipb-left-drawer__search",
2389
+ role: "search"
2390
+ }, ua = ["placeholder", "aria-label"], fa = { class: "ipb-left-drawer__category-title" }, pa = ["aria-label"], ma = ["title", "aria-label", "onClick", "onDragstart"], ga = {
2391
+ class: "ipb-left-drawer__component-icon",
2392
+ "aria-hidden": "true"
2393
+ }, ba = { class: "ipb-left-drawer__component-label" }, va = {
2394
+ key: 0,
2395
+ class: "ipb-left-drawer__empty"
2396
+ }, ha = {
2397
+ key: 0,
2398
+ class: "ipb-left-drawer__section ipb-left-drawer__section--tree"
2399
+ }, _a = { class: "ipb-left-drawer__section-header" }, ya = { class: "ipb-left-drawer__section-title" }, wa = ["aria-expanded", "aria-label"], xa = ["aria-label"];
2400
+ function Ia(t, r, n, e, o, i) {
2401
+ return x(), C("aside", {
2402
+ ref: "drawerRef",
2403
+ class: _e(["ipb-left-drawer", { "ipb-left-drawer--open": n.open }]),
2404
+ "aria-label": e.t("leftDrawer.aria.componentPalette"),
2405
+ role: "complementary"
2406
+ }, [
2407
+ S("div", aa, [
2408
+ S(
2409
+ "span",
2410
+ ia,
2411
+ z(e.t("leftDrawer.title")),
2412
+ 1
2413
+ /* TEXT */
2414
+ ),
2415
+ S("button", {
2416
+ ref: "drawerToggleRef",
2417
+ type: "button",
2418
+ class: "ipb-left-drawer__toggle",
2419
+ "aria-label": e.t("leftDrawer.toggle.ariaLabel"),
2420
+ "aria-expanded": n.open ? "true" : "false",
2421
+ "aria-controls": e.DRAWER_CONTENT_ID,
2422
+ onClick: e.handleDrawerToggle
2423
+ }, z(n.open ? "◀" : "▶"), 9, la)
2424
+ ]),
2425
+ n.open ? (x(), C("div", {
2426
+ key: 0,
2427
+ id: e.DRAWER_CONTENT_ID,
2428
+ class: "ipb-left-drawer__content",
2429
+ role: "region",
2430
+ "aria-labelledby": "ipb-left-drawer-title"
2431
+ }, [
2432
+ S("div", sa, [
2433
+ S(
2434
+ "h3",
2435
+ da,
2436
+ z(e.t("leftDrawer.section.components")),
2437
+ 1
2438
+ /* TEXT */
2439
+ ),
2440
+ S("div", ca, [
2441
+ Yn(S("input", {
2442
+ ref: "searchInputRef",
2443
+ "onUpdate:modelValue": r[0] || (r[0] = (a) => e.searchQuery = a),
2444
+ type: "search",
2445
+ class: "ipb-left-drawer__search-input",
2446
+ placeholder: e.t("leftDrawer.search.placeholder"),
2447
+ "aria-label": e.t("leftDrawer.search.ariaLabel")
2448
+ }, null, 8, ua), [
2449
+ [Xn, e.searchQuery]
2450
+ ])
2451
+ ]),
2452
+ (x(!0), C(
2453
+ he,
2454
+ null,
2455
+ ve(e.filteredCategorizedComponents, ([a, l]) => (x(), C("div", {
2456
+ key: a,
2457
+ class: "ipb-left-drawer__category"
2458
+ }, [
2459
+ S(
2460
+ "h4",
2461
+ fa,
2462
+ z(a),
2463
+ 1
2464
+ /* TEXT */
2465
+ ),
2466
+ S("div", {
2467
+ class: "ipb-left-drawer__component-list",
2468
+ role: "group",
2469
+ "aria-label": e.getCategoryAriaLabel(a)
2470
+ }, [
2471
+ (x(!0), C(
2472
+ he,
2473
+ null,
2474
+ ve(l, (u) => (x(), C("button", {
2475
+ key: u.name,
2476
+ type: "button",
2477
+ class: "ipb-left-drawer__component-item",
2478
+ draggable: "true",
2479
+ title: u.description,
2480
+ "aria-label": e.getDragAriaLabel(u.label),
2481
+ "aria-keyshortcuts": "Enter Space",
2482
+ onClick: (b) => e.handleComponentAdd(u.name),
2483
+ onDragstart: (b) => e.handleDragStart(u.name, b),
2484
+ onDragend: e.handleDragEnd
2485
+ }, [
2486
+ S(
2487
+ "span",
2488
+ ga,
2489
+ z(u.icon ?? "◻"),
2490
+ 1
2491
+ /* TEXT */
2492
+ ),
2493
+ S(
2494
+ "span",
2495
+ ba,
2496
+ z(u.label),
2497
+ 1
2498
+ /* TEXT */
2499
+ )
2500
+ ], 40, ma))),
2501
+ 128
2502
+ /* KEYED_FRAGMENT */
2503
+ ))
2504
+ ], 8, pa)
2505
+ ]))),
2506
+ 128
2507
+ /* KEYED_FRAGMENT */
2508
+ )),
2509
+ e.filteredCategorizedComponents.size === 0 ? (x(), C(
2510
+ "p",
2511
+ va,
2512
+ z(e.t("leftDrawer.empty")),
2513
+ 1
2514
+ /* TEXT */
2515
+ )) : Y("v-if", !0)
2516
+ ]),
2517
+ n.content ? (x(), C("div", ha, [
2518
+ S("div", _a, [
2519
+ S(
2520
+ "h3",
2521
+ ya,
2522
+ z(e.t("leftDrawer.section.tree")),
2523
+ 1
2524
+ /* TEXT */
2525
+ ),
2526
+ S("button", {
2527
+ type: "button",
2528
+ class: "ipb-left-drawer__section-toggle",
2529
+ "aria-expanded": e.treeOpen ? "true" : "false",
2530
+ "aria-controls": e.TREE_PANEL_REGION_ID,
2531
+ "aria-label": e.t("leftDrawer.tree.toggle.ariaLabel"),
2532
+ onClick: e.toggleTree
2533
+ }, z(e.treeOpen ? "−" : "+"), 9, wa)
2534
+ ]),
2535
+ e.treeOpen ? (x(), C("div", {
2536
+ key: 0,
2537
+ id: e.TREE_PANEL_REGION_ID,
2538
+ role: "region",
2539
+ "aria-label": e.t("treePanel.ariaLabel")
2540
+ }, [
2541
+ Re(e.TreePanel, {
2542
+ content: n.content,
2543
+ "selected-node-id": n.selectedNodeId,
2544
+ onSelect: r[1] || (r[1] = (a) => e.emit("select", a))
2545
+ }, null, 8, ["content", "selected-node-id"])
2546
+ ], 8, xa)) : Y("v-if", !0)
2547
+ ])) : Y("v-if", !0)
2548
+ ])) : Y("v-if", !0)
2549
+ ], 10, oa);
2550
+ }
2551
+ const Da = /* @__PURE__ */ q(ra, [["render", Ia], ["__scopeId", "data-v-32b2016a"], ["__file", "/app/src/components/editor/LeftDrawer.vue"]]), Na = /* @__PURE__ */ G({
2552
+ __name: "PropTextEditor",
2553
+ props: {
2554
+ modelValue: { type: [String, Number, Boolean], default: "" },
2555
+ placeholder: { type: String, default: "" }
2556
+ },
2557
+ emits: ["update:modelValue"],
2558
+ setup(t, { expose: r, emit: n }) {
2559
+ r();
2560
+ const e = t, o = n;
2561
+ function i(l) {
2562
+ o("update:modelValue", l.target.value);
2563
+ }
2564
+ const a = { props: e, emit: o, handleInput: i };
2565
+ return Object.defineProperty(a, "__isScriptSetup", { enumerable: !1, value: !0 }), a;
2566
+ }
2567
+ }), Sa = ["value", "placeholder"];
2568
+ function Ta(t, r, n, e, o, i) {
2569
+ return x(), C("input", {
2570
+ class: "ipb-prop-editor ipb-prop-editor--text",
2571
+ type: "text",
2572
+ value: String(e.props.modelValue ?? ""),
2573
+ placeholder: n.placeholder,
2574
+ onInput: e.handleInput
2575
+ }, null, 40, Sa);
2576
+ }
2577
+ const at = /* @__PURE__ */ q(Na, [["render", Ta], ["__scopeId", "data-v-85eee1e0"], ["__file", "/app/src/components/editor/prop-editors/PropTextEditor.vue"]]), Ca = /* @__PURE__ */ G({
2578
+ __name: "PropNumberEditor",
2579
+ props: {
2580
+ modelValue: { type: [String, Number], default: void 0 },
2581
+ min: { type: Number, default: void 0 },
2582
+ max: { type: Number, default: void 0 }
2583
+ },
2584
+ emits: ["update:modelValue"],
2585
+ setup(t, { expose: r, emit: n }) {
2586
+ r();
2587
+ const e = t, o = n, i = N(() => typeof e.modelValue == "number" ? String(e.modelValue) : typeof e.modelValue == "string" ? e.modelValue : "");
2588
+ function a(u) {
2589
+ const b = u.target.value.trim();
2590
+ if (b === "") {
2591
+ o("update:modelValue", void 0);
2592
+ return;
2593
+ }
2594
+ const v = Number(b);
2595
+ o("update:modelValue", Number.isNaN(v) ? void 0 : v);
2596
+ }
2597
+ const l = { props: e, emit: o, inputValue: i, handleInput: a };
2598
+ return Object.defineProperty(l, "__isScriptSetup", { enumerable: !1, value: !0 }), l;
2599
+ }
2600
+ }), ka = ["value", "min", "max"];
2601
+ function Pa(t, r, n, e, o, i) {
2602
+ return x(), C("input", {
2603
+ class: "ipb-prop-editor ipb-prop-editor--number",
2604
+ type: "number",
2605
+ value: e.inputValue,
2606
+ min: n.min,
2607
+ max: n.max,
2608
+ onInput: e.handleInput
2609
+ }, null, 40, ka);
2610
+ }
2611
+ const Ea = /* @__PURE__ */ q(Ca, [["render", Pa], ["__scopeId", "data-v-5ad594ed"], ["__file", "/app/src/components/editor/prop-editors/PropNumberEditor.vue"]]), Ra = /* @__PURE__ */ G({
2612
+ inheritAttrs: !1,
2613
+ __name: "PropBooleanEditor",
2614
+ props: {
2615
+ modelValue: { type: Boolean, default: !1 }
2616
+ },
2617
+ emits: ["update:modelValue"],
2618
+ setup(t, { expose: r, emit: n }) {
2619
+ r();
2620
+ const e = n;
2621
+ function o(b) {
2622
+ e("update:modelValue", b.target.checked);
2623
+ }
2624
+ const { t: i } = pe(), a = dt(), l = N(() => {
2625
+ const { class: b, style: v, ...I } = a;
2626
+ return I;
2627
+ }), u = { emit: e, handleChange: o, t: i, attrs: a, checkboxAttrs: l };
2628
+ return Object.defineProperty(u, "__isScriptSetup", { enumerable: !1, value: !0 }), u;
2629
+ }
2630
+ }), Aa = ["checked"];
2631
+ function La(t, r, n, e, o, i) {
2632
+ return x(), C(
2633
+ "label",
2634
+ {
2635
+ class: _e(["ipb-prop-editor ipb-prop-editor--boolean", e.attrs.class]),
2636
+ style: J(e.attrs.style)
2637
+ },
2638
+ [
2639
+ S("input", He(e.checkboxAttrs, {
2640
+ type: "checkbox",
2641
+ checked: n.modelValue,
2642
+ onChange: e.handleChange
2643
+ }), null, 16, Aa),
2644
+ S(
2645
+ "span",
2646
+ null,
2647
+ z(n.modelValue ? e.t("propBoolean.enabled") : e.t("propBoolean.disabled")),
2648
+ 1
2649
+ /* TEXT */
2650
+ )
2651
+ ],
2652
+ 6
2653
+ /* CLASS, STYLE */
2654
+ );
2655
+ }
2656
+ const Va = /* @__PURE__ */ q(Ra, [["render", La], ["__scopeId", "data-v-264db8de"], ["__file", "/app/src/components/editor/prop-editors/PropBooleanEditor.vue"]]), Ma = /* @__PURE__ */ G({
2657
+ __name: "PropSelectEditor",
2658
+ props: {
2659
+ modelValue: { type: [String, Number, Boolean], default: void 0 },
2660
+ options: {
2661
+ type: Array,
2662
+ default: () => []
2663
+ }
2664
+ },
2665
+ emits: ["update:modelValue"],
2666
+ setup(t, { expose: r, emit: n }) {
2667
+ r();
2668
+ const e = t, o = n, i = N(() => {
2669
+ if (!e.options || e.options.length === 0) return "";
2670
+ const b = e.options.findIndex((v) => v.value === e.modelValue);
2671
+ return b >= 0 ? String(b) : "0";
2672
+ });
2673
+ function a(b) {
2674
+ const v = b.target.value;
2675
+ if (v === "" || !e.options) {
2676
+ o("update:modelValue", void 0);
2677
+ return;
2678
+ }
2679
+ const I = e.options[Number(v)];
2680
+ o("update:modelValue", I == null ? void 0 : I.value);
2681
+ }
2682
+ const { t: l } = pe(), u = { props: e, emit: o, selectedIndex: i, handleChange: a, t: l };
2683
+ return Object.defineProperty(u, "__isScriptSetup", { enumerable: !1, value: !0 }), u;
2684
+ }
2685
+ }), Oa = ["value"], Ba = {
2686
+ key: 0,
2687
+ value: ""
2688
+ }, za = ["value"];
2689
+ function ja(t, r, n, e, o, i) {
2690
+ return x(), C("select", {
2691
+ class: "ipb-prop-editor ipb-prop-editor--select",
2692
+ value: e.selectedIndex,
2693
+ onChange: e.handleChange
2694
+ }, [
2695
+ !n.options || n.options.length === 0 ? (x(), C(
2696
+ "option",
2697
+ Ba,
2698
+ z(e.t("propSelect.noOptions")),
2699
+ 1
2700
+ /* TEXT */
2701
+ )) : Y("v-if", !0),
2702
+ (x(!0), C(
2703
+ he,
2704
+ null,
2705
+ ve(n.options ?? [], (a, l) => (x(), C("option", {
2706
+ key: `${a.label}-${l}`,
2707
+ value: String(l)
2708
+ }, z(a.label), 9, za))),
2709
+ 128
2710
+ /* KEYED_FRAGMENT */
2711
+ ))
2712
+ ], 40, Oa);
2713
+ }
2714
+ const Ha = /* @__PURE__ */ q(Ma, [["render", ja], ["__scopeId", "data-v-565c4e19"], ["__file", "/app/src/components/editor/prop-editors/PropSelectEditor.vue"]]), Wa = /* @__PURE__ */ G({
2715
+ inheritAttrs: !1,
2716
+ __name: "PropColorEditor",
2717
+ props: {
2718
+ modelValue: { type: String, default: "" }
2719
+ },
2720
+ emits: ["update:modelValue"],
2721
+ setup(t, { expose: r, emit: n }) {
2722
+ r();
2723
+ const e = t, o = n, i = N(() => {
2724
+ const I = e.modelValue.trim();
2725
+ return /^#[0-9a-fA-F]{6}$/.test(I) ? I : /^#[0-9a-fA-F]{3}$/.test(I) ? `#${I.slice(1).split("").map((A) => `${A}${A}`).join("")}` : "#000000";
2726
+ });
2727
+ function a(I) {
2728
+ o("update:modelValue", I.target.value);
2729
+ }
2730
+ function l(I) {
2731
+ o("update:modelValue", I.target.value);
2732
+ }
2733
+ const u = dt(), b = N(() => {
2734
+ const { class: I, style: d, ...A } = u;
2735
+ return A;
2736
+ }), v = { props: e, emit: o, pickerValue: i, handlePickerInput: a, handleTextInput: l, attrs: u, inputAttrs: b };
2737
+ return Object.defineProperty(v, "__isScriptSetup", { enumerable: !1, value: !0 }), v;
2738
+ }
2739
+ }), Ua = ["value"], Ka = ["value"];
2740
+ function Fa(t, r, n, e, o, i) {
2741
+ return x(), C(
2742
+ "div",
2743
+ {
2744
+ class: _e(["ipb-prop-editor ipb-prop-editor--color", e.attrs.class]),
2745
+ style: J(e.attrs.style)
2746
+ },
2747
+ [
2748
+ S("input", He(e.inputAttrs, {
2749
+ class: "ipb-prop-editor__picker",
2750
+ type: "color",
2751
+ value: e.pickerValue,
2752
+ onInput: e.handlePickerInput
2753
+ }), null, 16, Ua),
2754
+ S("input", He(e.inputAttrs, {
2755
+ class: "ipb-prop-editor__text",
2756
+ type: "text",
2757
+ value: n.modelValue,
2758
+ placeholder: "#000000",
2759
+ onInput: e.handleTextInput
2760
+ }), null, 16, Ka)
2761
+ ],
2762
+ 6
2763
+ /* CLASS, STYLE */
2764
+ );
2765
+ }
2766
+ const $a = /* @__PURE__ */ q(Wa, [["render", Fa], ["__scopeId", "data-v-57860a2c"], ["__file", "/app/src/components/editor/prop-editors/PropColorEditor.vue"]]), Ga = /* @__PURE__ */ G({
2767
+ inheritAttrs: !1,
2768
+ __name: "RichTextEditor",
2769
+ props: {
2770
+ modelValue: { type: String, default: "" },
2771
+ placeholder: { type: String, default: "Type text..." }
2772
+ },
2773
+ emits: ["update:modelValue"],
2774
+ setup(t, { expose: r, emit: n }) {
2775
+ r();
2776
+ const e = t, o = n, i = R(null), a = R("");
2777
+ function l(p) {
2778
+ return typeof p != "string" ? "" : mn(p);
2779
+ }
2780
+ function u(p) {
2781
+ const g = i.value;
2782
+ if (!g) return;
2783
+ const E = l(p);
2784
+ g.innerHTML !== E && (g.innerHTML = E), a.value = E;
2785
+ }
2786
+ function b() {
2787
+ const p = i.value;
2788
+ if (!p) return;
2789
+ const g = l(p.innerHTML);
2790
+ p.innerHTML !== g && (p.innerHTML = g), g !== a.value && (a.value = g, o("update:modelValue", g));
2791
+ }
2792
+ function v() {
2793
+ var p;
2794
+ (p = i.value) == null || p.focus();
2795
+ }
2796
+ function I(p, g) {
2797
+ typeof document.execCommand == "function" && document.execCommand(p, !1, g);
2798
+ }
2799
+ function d(p) {
2800
+ v(), I(p), b();
2801
+ }
2802
+ function A() {
2803
+ v();
2804
+ const p = window.prompt(k("richText.prompt.enterUrl"), k("richText.prompt.defaultUrl"));
2805
+ if (!p) return;
2806
+ const g = se(p, "link");
2807
+ g && (I("createLink", g), b());
2808
+ }
2809
+ Ot(() => {
2810
+ u(l(e.modelValue));
2811
+ }), de(
2812
+ () => e.modelValue,
2813
+ (p) => {
2814
+ u(l(p));
2815
+ }
2816
+ );
2817
+ const { t: k } = pe(), y = dt(), D = N(() => {
2818
+ const { class: p, style: g, ...E } = y;
2819
+ return E;
2820
+ }), c = N(() => {
2821
+ const p = y["aria-labelledby"], g = y["aria-label"];
2822
+ if (!(p || g))
2823
+ return k("richText.aria.editor");
2824
+ }), m = { props: e, emit: o, editorRef: i, lastEmittedValue: a, getSanitizedHtml: l, syncEditorHtml: u, emitCurrentHtml: b, focusEditor: v, executeCommand: I, runCommand: d, insertLink: A, t: k, attrs: y, contentAttrs: D, editorAriaLabel: c };
2825
+ return Object.defineProperty(m, "__isScriptSetup", { enumerable: !1, value: !0 }), m;
2826
+ }
2827
+ }), qa = ["aria-label"], Ya = ["aria-label", "title"], Xa = ["aria-label", "title"], Za = ["aria-label", "title"], Ja = ["aria-label", "title"], Qa = ["aria-label", "title"], ei = ["aria-label", "data-placeholder"];
2828
+ function ti(t, r, n, e, o, i) {
2829
+ return x(), C(
2830
+ "div",
2831
+ {
2832
+ class: _e(["ipb-richtext-editor", e.attrs.class]),
2833
+ style: J(e.attrs.style)
2834
+ },
2835
+ [
2836
+ S("div", {
2837
+ class: "ipb-richtext-editor__toolbar",
2838
+ role: "toolbar",
2839
+ "aria-label": e.t("richText.aria.toolbar")
2840
+ }, [
2841
+ S("button", {
2842
+ type: "button",
2843
+ "data-command": "bold",
2844
+ "aria-label": e.t("richText.action.bold"),
2845
+ title: e.t("richText.action.bold"),
2846
+ onClick: r[0] || (r[0] = (a) => e.runCommand("bold"))
2847
+ }, [...r[4] || (r[4] = [
2848
+ S(
2849
+ "strong",
2850
+ null,
2851
+ "B",
2852
+ -1
2853
+ /* CACHED */
2854
+ )
2855
+ ])], 8, Ya),
2856
+ S("button", {
2857
+ type: "button",
2858
+ "data-command": "italic",
2859
+ "aria-label": e.t("richText.action.italic"),
2860
+ title: e.t("richText.action.italic"),
2861
+ onClick: r[1] || (r[1] = (a) => e.runCommand("italic"))
2862
+ }, [...r[5] || (r[5] = [
2863
+ S(
2864
+ "em",
2865
+ null,
2866
+ "I",
2867
+ -1
2868
+ /* CACHED */
2869
+ )
2870
+ ])], 8, Xa),
2871
+ S("button", {
2872
+ type: "button",
2873
+ "data-command": "ul",
2874
+ "aria-label": e.t("richText.action.unorderedList"),
2875
+ title: e.t("richText.action.unorderedList"),
2876
+ onClick: r[2] || (r[2] = (a) => e.runCommand("insertUnorderedList"))
2877
+ }, " UL ", 8, Za),
2878
+ S("button", {
2879
+ type: "button",
2880
+ "data-command": "ol",
2881
+ "aria-label": e.t("richText.action.orderedList"),
2882
+ title: e.t("richText.action.orderedList"),
2883
+ onClick: r[3] || (r[3] = (a) => e.runCommand("insertOrderedList"))
2884
+ }, " OL ", 8, Ja),
2885
+ S("button", {
2886
+ type: "button",
2887
+ "data-command": "link",
2888
+ "aria-label": e.t("richText.action.link"),
2889
+ title: e.t("richText.action.link"),
2890
+ onClick: e.insertLink
2891
+ }, z(e.t("richText.action.link")), 9, Qa)
2892
+ ], 8, qa),
2893
+ S("div", He(e.contentAttrs, {
2894
+ ref: "editorRef",
2895
+ class: "ipb-richtext-editor__content",
2896
+ contenteditable: "true",
2897
+ role: "textbox",
2898
+ "aria-multiline": "true",
2899
+ "aria-label": e.editorAriaLabel,
2900
+ "data-placeholder": n.placeholder,
2901
+ onInput: e.emitCurrentHtml,
2902
+ onBlur: e.emitCurrentHtml
2903
+ }), null, 16, ei)
2904
+ ],
2905
+ 6
2906
+ /* CLASS, STYLE */
2907
+ );
2908
+ }
2909
+ const ni = /* @__PURE__ */ q(Ga, [["render", ti], ["__scopeId", "data-v-3bf126f9"], ["__file", "/app/src/components/editor/prop-editors/RichTextEditor.vue"]]), ri = /* @__PURE__ */ G({
2910
+ inheritAttrs: !1,
2911
+ __name: "MediaPicker",
2912
+ props: {
2913
+ modelValue: { type: String, default: "" }
2914
+ },
2915
+ emits: ["update:modelValue", "upload"],
2916
+ setup(t, { expose: r, emit: n }) {
2917
+ r();
2918
+ const e = t, o = n, i = N(() => e.modelValue.trim()), a = N(() => se(i.value, "media")), l = N(() => i.value.length > 0), u = N(() => a.value.length > 0);
2919
+ function b(D) {
2920
+ const c = D.target.value;
2921
+ o("update:modelValue", se(c, "media"));
2922
+ }
2923
+ function v() {
2924
+ o("update:modelValue", "");
2925
+ }
2926
+ function I() {
2927
+ o("upload");
2928
+ }
2929
+ const { t: d } = pe(), A = dt(), k = N(() => {
2930
+ const { class: D, style: c, ...m } = A;
2931
+ return m;
2932
+ }), y = { props: e, emit: o, rawValue: i, safePreviewUrl: a, hasValue: l, canPreview: u, handleInput: b, handleClear: v, handleUploadPlaceholder: I, t: d, attrs: A, inputAttrs: k };
2933
+ return Object.defineProperty(y, "__isScriptSetup", { enumerable: !1, value: !0 }), y;
2934
+ }
2935
+ }), oi = { class: "ipb-media-picker__controls" }, ai = ["value", "placeholder"], ii = ["disabled"], li = { class: "ipb-media-picker__preview" }, si = ["src", "alt"], di = {
2936
+ key: 1,
2937
+ class: "ipb-media-picker__empty"
2938
+ };
2939
+ function ci(t, r, n, e, o, i) {
2940
+ return x(), C(
2941
+ "div",
2942
+ {
2943
+ class: _e(["ipb-media-picker", e.attrs.class]),
2944
+ style: J(e.attrs.style)
2945
+ },
2946
+ [
2947
+ S("div", oi, [
2948
+ S("input", He(e.inputAttrs, {
2949
+ class: "ipb-media-picker__input",
2950
+ type: "url",
2951
+ value: n.modelValue,
2952
+ placeholder: e.t("mediaPicker.input.placeholder"),
2953
+ onInput: e.handleInput
2954
+ }), null, 16, ai),
2955
+ S("button", {
2956
+ class: "ipb-media-picker__btn",
2957
+ type: "button",
2958
+ disabled: !e.hasValue,
2959
+ onClick: e.handleClear
2960
+ }, z(e.t("mediaPicker.clear")), 9, ii),
2961
+ S(
2962
+ "button",
2963
+ {
2964
+ class: "ipb-media-picker__btn",
2965
+ type: "button",
2966
+ onClick: e.handleUploadPlaceholder
2967
+ },
2968
+ z(e.t("mediaPicker.upload")),
2969
+ 1
2970
+ /* TEXT */
2971
+ )
2972
+ ]),
2973
+ S("div", li, [
2974
+ e.hasValue && e.canPreview ? (x(), C("img", {
2975
+ key: 0,
2976
+ class: "ipb-media-picker__image",
2977
+ src: e.safePreviewUrl,
2978
+ alt: e.t("mediaPicker.preview.alt")
2979
+ }, null, 8, si)) : (x(), C(
2980
+ "p",
2981
+ di,
2982
+ z(e.t("mediaPicker.empty")),
2983
+ 1
2984
+ /* TEXT */
2985
+ ))
2986
+ ])
2987
+ ],
2988
+ 6
2989
+ /* CLASS, STYLE */
2990
+ );
2991
+ }
2992
+ const rn = /* @__PURE__ */ q(ri, [["render", ci], ["__scopeId", "data-v-68f678e9"], ["__file", "/app/src/components/editor/prop-editors/MediaPicker.vue"]]), ui = at, fi = {
2993
+ text: at,
2994
+ textarea: at,
2995
+ richtext: ni,
2996
+ number: Ea,
2997
+ boolean: Va,
2998
+ select: Ha,
2999
+ color: $a,
3000
+ image: rn,
3001
+ url: rn,
3002
+ json: at
3003
+ }, Ee = "ipb-right-drawer-content", pi = /* @__PURE__ */ G({
3004
+ __name: "RightDrawer",
3005
+ props: {
3006
+ open: { type: Boolean, default: !1 },
3007
+ selectedNodeId: { type: Number, default: null },
3008
+ content: { type: Object, required: !0 }
3009
+ },
3010
+ emits: ["toggle", "update-props", "delete", "duplicate"],
3011
+ setup(t, { expose: r, emit: n }) {
3012
+ r();
3013
+ const e = t, o = n, { t: i } = pe(), a = R(null), l = R(null), u = R(!1), b = N(() => e.selectedNodeId === null ? null : U(e.content, e.selectedNodeId) ?? null), v = N(() => b.value ? Le(b.value.name) ?? null : null);
3014
+ function I(g) {
3015
+ return b.value ? b.value.props[g.key] ?? g.defaultValue ?? "" : g.defaultValue ?? "";
3016
+ }
3017
+ function d(g) {
3018
+ return fi[g] ?? ui;
3019
+ }
3020
+ function A(g) {
3021
+ var O, L;
3022
+ const E = I(g);
3023
+ return g.type === "number" ? {
3024
+ modelValue: E,
3025
+ min: (O = g.validation) == null ? void 0 : O.min,
3026
+ max: (L = g.validation) == null ? void 0 : L.max
3027
+ } : g.type === "select" ? {
3028
+ modelValue: E,
3029
+ options: g.options ?? []
3030
+ } : g.type === "image" || g.type === "url" ? { modelValue: E } : g.type === "text" || g.type === "textarea" || g.type === "richtext" || g.type === "json" ? {
3031
+ modelValue: E,
3032
+ placeholder: g.label
3033
+ } : { modelValue: E };
3034
+ }
3035
+ function k(g, E) {
3036
+ b.value && o("update-props", b.value.id, { [g]: E });
3037
+ }
3038
+ function y(g) {
3039
+ return `ipb-right-drawer-prop-label-${g}`;
3040
+ }
3041
+ function D() {
3042
+ const g = a.value;
3043
+ return g ? g.querySelector(
3044
+ `#${Ee} input:not([disabled]), #${Ee} select:not([disabled]), #${Ee} textarea:not([disabled]), #${Ee} button:not([disabled]), #${Ee} [contenteditable]:not([contenteditable="false"]), #${Ee} [tabindex]:not([tabindex="-1"])`
3045
+ ) : null;
3046
+ }
3047
+ function c() {
3048
+ var g;
3049
+ (g = D()) == null || g.focus();
3050
+ }
3051
+ function m() {
3052
+ u.value = !e.open, o("toggle");
3053
+ }
3054
+ de(
3055
+ () => e.open,
3056
+ (g, E) => {
3057
+ var O;
3058
+ if (g && !E && u.value && ue(() => {
3059
+ c();
3060
+ }), !g && E) {
3061
+ const L = document.activeElement;
3062
+ L instanceof HTMLElement && ((O = a.value) != null && O.contains(L)) && ue(() => {
3063
+ var P;
3064
+ (P = l.value) == null || P.focus();
3065
+ });
3066
+ }
3067
+ g !== E && (u.value = !1);
3068
+ }
3069
+ );
3070
+ const p = { props: e, emit: o, t: i, drawerRef: a, drawerToggleRef: l, focusContentOnNextOpen: u, selectedNode: b, componentDef: v, getPropValue: I, getEditorComponent: d, getEditorBindings: A, handlePropUpdate: k, DRAWER_CONTENT_ID: Ee, getPropLabelId: y, getFirstFocusableContentControl: D, focusDrawerContent: c, handleDrawerToggle: m };
3071
+ return Object.defineProperty(p, "__isScriptSetup", { enumerable: !1, value: !0 }), p;
3072
+ }
3073
+ }), mi = ["aria-label"], gi = { class: "ipb-right-drawer__header" }, bi = {
3074
+ class: "ipb-right-drawer__title",
3075
+ id: "ipb-right-drawer-title"
3076
+ }, vi = ["aria-label", "aria-expanded"], hi = { class: "ipb-right-drawer__section" }, _i = { class: "ipb-right-drawer__section-title" }, yi = {
3077
+ key: 0,
3078
+ class: "ipb-right-drawer__description"
3079
+ }, wi = { class: "ipb-right-drawer__section" }, xi = { class: "ipb-right-drawer__section-subtitle" }, Ii = ["data-prop-key"], Di = ["id"], Ni = { class: "ipb-right-drawer__actions" }, Si = ["aria-label"], Ti = ["disabled", "aria-label"], Ci = {
3080
+ key: 1,
3081
+ class: "ipb-right-drawer__empty"
3082
+ };
3083
+ function ki(t, r, n, e, o, i) {
3084
+ return x(), C("aside", {
3085
+ ref: "drawerRef",
3086
+ class: _e(["ipb-right-drawer", { "ipb-right-drawer--open": n.open }]),
3087
+ role: "complementary",
3088
+ "aria-label": e.t("rightDrawer.aria.componentProperties")
3089
+ }, [
3090
+ S("div", gi, [
3091
+ S(
3092
+ "span",
3093
+ bi,
3094
+ z(e.t("rightDrawer.title")),
3095
+ 1
3096
+ /* TEXT */
3097
+ ),
3098
+ S("button", {
3099
+ ref: "drawerToggleRef",
3100
+ type: "button",
3101
+ class: "ipb-right-drawer__toggle",
3102
+ "aria-label": e.t("rightDrawer.toggle.ariaLabel"),
3103
+ "aria-expanded": n.open ? "true" : "false",
3104
+ "aria-controls": e.DRAWER_CONTENT_ID,
3105
+ onClick: e.handleDrawerToggle
3106
+ }, z(n.open ? "▶" : "◀"), 9, vi)
3107
+ ]),
3108
+ n.open && e.selectedNode && e.componentDef ? (x(), C("div", {
3109
+ key: 0,
3110
+ id: e.DRAWER_CONTENT_ID,
3111
+ class: "ipb-right-drawer__content",
3112
+ role: "region",
3113
+ "aria-labelledby": "ipb-right-drawer-title"
3114
+ }, [
3115
+ S("div", hi, [
3116
+ S(
3117
+ "h3",
3118
+ _i,
3119
+ z(e.componentDef.label),
3120
+ 1
3121
+ /* TEXT */
3122
+ ),
3123
+ e.componentDef.description ? (x(), C(
3124
+ "p",
3125
+ yi,
3126
+ z(e.componentDef.description),
3127
+ 1
3128
+ /* TEXT */
3129
+ )) : Y("v-if", !0)
3130
+ ]),
3131
+ S("div", wi, [
3132
+ S(
3133
+ "h4",
3134
+ xi,
3135
+ z(e.t("rightDrawer.section.properties")),
3136
+ 1
3137
+ /* TEXT */
3138
+ ),
3139
+ Y(" Property editors will be rendered here based on editableProps "),
3140
+ (x(!0), C(
3141
+ he,
3142
+ null,
3143
+ ve(e.componentDef.editableProps, (a) => (x(), C("div", {
3144
+ key: a.key,
3145
+ class: "ipb-right-drawer__prop",
3146
+ "data-prop-key": a.key
3147
+ }, [
3148
+ S("label", {
3149
+ id: e.getPropLabelId(a.key),
3150
+ class: "ipb-right-drawer__prop-label"
3151
+ }, z(a.label), 9, Di),
3152
+ (x(), Se(Mt(e.getEditorComponent(a.type)), He({ class: "ipb-right-drawer__prop-editor" }, { ref_for: !0 }, e.getEditorBindings(a), {
3153
+ "aria-labelledby": e.getPropLabelId(a.key),
3154
+ "onUpdate:modelValue": (l) => e.handlePropUpdate(a.key, l)
3155
+ }), null, 16, ["aria-labelledby", "onUpdate:modelValue"]))
3156
+ ], 8, Ii))),
3157
+ 128
3158
+ /* KEYED_FRAGMENT */
3159
+ ))
3160
+ ]),
3161
+ S("div", Ni, [
3162
+ S("button", {
3163
+ type: "button",
3164
+ class: "ipb-right-drawer__btn",
3165
+ "aria-label": e.t("rightDrawer.actions.duplicate.ariaLabel"),
3166
+ onClick: r[0] || (r[0] = (a) => e.emit("duplicate", e.selectedNode.id))
3167
+ }, z(e.t("rightDrawer.actions.duplicate")), 9, Si),
3168
+ S("button", {
3169
+ type: "button",
3170
+ class: "ipb-right-drawer__btn ipb-right-drawer__btn--danger",
3171
+ disabled: e.selectedNode.readonly,
3172
+ "aria-label": e.t("rightDrawer.actions.delete.ariaLabel"),
3173
+ onClick: r[1] || (r[1] = (a) => e.emit("delete", e.selectedNode.id))
3174
+ }, z(e.t("rightDrawer.actions.delete")), 9, Ti)
3175
+ ])
3176
+ ])) : n.open ? (x(), C("div", Ci, [
3177
+ S(
3178
+ "p",
3179
+ null,
3180
+ z(e.t("rightDrawer.empty")),
3181
+ 1
3182
+ /* TEXT */
3183
+ )
3184
+ ])) : Y("v-if", !0)
3185
+ ], 10, mi);
3186
+ }
3187
+ const Pi = /* @__PURE__ */ q(pi, [["render", ki], ["__scopeId", "data-v-77af2668"], ["__file", "/app/src/components/editor/RightDrawer.vue"]]), Rn = "@improba/page-builder/iframe-bridge", An = 1;
3188
+ function Ut(t, r, n) {
3189
+ return {
3190
+ namespace: Rn,
3191
+ version: An,
3192
+ sessionToken: n,
3193
+ channel: t,
3194
+ payload: r
3195
+ };
3196
+ }
3197
+ function Ei() {
3198
+ var t, r;
3199
+ if (typeof ((t = globalThis.crypto) == null ? void 0 : t.randomUUID) == "function")
3200
+ return globalThis.crypto.randomUUID();
3201
+ if (typeof ((r = globalThis.crypto) == null ? void 0 : r.getRandomValues) == "function") {
3202
+ const n = new Uint8Array(16);
3203
+ return globalThis.crypto.getRandomValues(n), Array.from(n, (e) => e.toString(16).padStart(2, "0")).join("");
3204
+ }
3205
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
3206
+ }
3207
+ function Ln(t) {
3208
+ return Ut("lifecycle", { state: "ready" }, t);
3209
+ }
3210
+ function Vn(t, r) {
3211
+ return Ut("pointer", t, r);
3212
+ }
3213
+ function Mn(t, r) {
3214
+ return Ut("keydown", t, r);
3215
+ }
3216
+ function st(t) {
3217
+ return !!t && typeof t == "object";
3218
+ }
3219
+ function Ri(t) {
3220
+ if (!st(t)) return null;
3221
+ const r = t.interaction, n = t.nodeId;
3222
+ if (r !== "hover" && r !== "select" && r !== "context" || n !== null && typeof n != "number" || typeof n == "number" && !Number.isInteger(n)) return null;
3223
+ const e = n;
3224
+ if (r === "context") {
3225
+ const o = t.clientX, i = t.clientY;
3226
+ return typeof o != "number" || typeof i != "number" ? null : { interaction: r, nodeId: e, clientX: o, clientY: i };
3227
+ }
3228
+ return { interaction: r, nodeId: e };
3229
+ }
3230
+ function Ai(t) {
3231
+ return !st(t) || typeof t.key != "string" || typeof t.code != "string" || typeof t.ctrlKey != "boolean" || typeof t.metaKey != "boolean" || typeof t.shiftKey != "boolean" || typeof t.altKey != "boolean" || typeof t.defaultPrevented != "boolean" || typeof t.isEditable != "boolean" ? null : {
3232
+ key: t.key,
3233
+ code: t.code,
3234
+ ctrlKey: t.ctrlKey,
3235
+ metaKey: t.metaKey,
3236
+ shiftKey: t.shiftKey,
3237
+ altKey: t.altKey,
3238
+ defaultPrevented: t.defaultPrevented,
3239
+ isEditable: t.isEditable
3240
+ };
3241
+ }
3242
+ function Li(t, r = {}) {
3243
+ if (!st(t) || t.namespace !== Rn || t.version !== An || t.channel !== "keydown" && t.channel !== "pointer" && t.channel !== "lifecycle") return null;
3244
+ const n = t.sessionToken, e = typeof n == "string" && n.length > 0;
3245
+ if (r.expectedSessionToken) {
3246
+ if (!e || n !== r.expectedSessionToken) return null;
3247
+ } else if (!e && !r.allowLegacyNoSessionToken)
3248
+ return null;
3249
+ const o = e ? n : "";
3250
+ if (t.channel === "lifecycle")
3251
+ return !st(t.payload) || t.payload.state !== "ready" ? null : Ln(o);
3252
+ if (t.channel === "pointer") {
3253
+ const a = Ri(t.payload);
3254
+ return a ? Vn(a, o) : null;
3255
+ }
3256
+ const i = Ai(t.payload);
3257
+ return i ? Mn(i, o) : null;
3258
+ }
3259
+ function Vi(t) {
3260
+ const r = (n) => {
3261
+ var o, i, a;
3262
+ if (n.source !== t.expectedSource || n.origin !== t.expectedOrigin) return;
3263
+ const e = Li(n.data, {
3264
+ expectedSessionToken: t.expectedSessionToken,
3265
+ allowLegacyNoSessionToken: t.allowLegacyNoSessionToken ?? !t.expectedSessionToken
3266
+ });
3267
+ if (e) {
3268
+ if (e.channel === "lifecycle") {
3269
+ (o = t.onReady) == null || o.call(t);
3270
+ return;
3271
+ }
3272
+ if (e.channel === "pointer") {
3273
+ (i = t.onPointer) == null || i.call(t, e.payload);
3274
+ return;
3275
+ }
3276
+ (a = t.onKeydown) == null || a.call(t, e.payload);
3277
+ }
3278
+ };
3279
+ return t.hostWindow.addEventListener("message", r), {
3280
+ dispose: () => {
3281
+ t.hostWindow.removeEventListener("message", r);
3282
+ }
3283
+ };
3284
+ }
3285
+ function Mi(t) {
3286
+ return {
3287
+ postReady: () => {
3288
+ t.targetWindow.postMessage(Ln(t.sessionToken), t.targetOrigin);
3289
+ },
3290
+ postPointer: (r) => {
3291
+ t.targetWindow.postMessage(
3292
+ Vn(r, t.sessionToken),
3293
+ t.targetOrigin
3294
+ );
3295
+ },
3296
+ postKeydown: (r) => {
3297
+ t.targetWindow.postMessage(
3298
+ Mn(r, t.sessionToken),
3299
+ t.targetOrigin
3300
+ );
3301
+ }
3302
+ };
3303
+ }
3304
+ function Oi(t) {
3305
+ if (t.defaultPrevented || t.isEditable) return !1;
3306
+ const r = t.ctrlKey || t.metaKey, n = t.key.toLowerCase(), e = t.code.toLowerCase();
3307
+ return r && (n === "z" || n === "y" || n === "s") ? !0 : (n === "delete" || n === "backspace" || e === "delete" || e === "backspace") && !t.ctrlKey && !t.metaKey && !t.altKey;
3308
+ }
3309
+ function Bi(t) {
3310
+ const r = (a) => {
3311
+ t.bridge.postPointer({
3312
+ interaction: "select",
3313
+ nodeId: t.resolveNodeId(a.target)
3314
+ });
3315
+ }, n = (a) => {
3316
+ t.bridge.postPointer({
3317
+ interaction: "hover",
3318
+ nodeId: t.resolveNodeId(a.target)
3319
+ });
3320
+ }, e = () => {
3321
+ t.bridge.postPointer({
3322
+ interaction: "hover",
3323
+ nodeId: null
3324
+ });
3325
+ }, o = (a) => {
3326
+ a.preventDefault(), t.bridge.postPointer({
3327
+ interaction: "context",
3328
+ nodeId: t.resolveNodeId(a.target),
3329
+ clientX: a.clientX,
3330
+ clientY: a.clientY
3331
+ });
3332
+ }, i = (a) => {
3333
+ const l = {
3334
+ key: a.key,
3335
+ code: a.code,
3336
+ ctrlKey: a.ctrlKey,
3337
+ metaKey: a.metaKey,
3338
+ shiftKey: a.shiftKey,
3339
+ altKey: a.altKey,
3340
+ defaultPrevented: a.defaultPrevented,
3341
+ isEditable: t.isEditableTarget(a.target) || t.isEditableTarget(t.frameDocument.activeElement)
3342
+ };
3343
+ Oi(l) && a.preventDefault(), t.bridge.postKeydown(l);
3344
+ };
3345
+ return t.contentRoot.addEventListener("click", r), t.contentRoot.addEventListener("mousemove", n), t.contentRoot.addEventListener("mouseleave", e), t.contentRoot.addEventListener("contextmenu", o), t.frameDocument.addEventListener("keydown", i), t.bridge.postReady(), () => {
3346
+ t.contentRoot.removeEventListener("click", r), t.contentRoot.removeEventListener("mousemove", n), t.contentRoot.removeEventListener("mouseleave", e), t.contentRoot.removeEventListener("contextmenu", o), t.frameDocument.removeEventListener("keydown", i);
3347
+ };
3348
+ }
3349
+ const zi = /* @__PURE__ */ G({
3350
+ __name: "NodeContextMenu",
3351
+ props: {
3352
+ open: { type: Boolean, default: !1 },
3353
+ x: { type: Number, default: 0 },
3354
+ y: { type: Number, default: 0 },
3355
+ canDelete: { type: Boolean, default: !0 },
3356
+ canMoveUp: { type: Boolean, default: !1 },
3357
+ canMoveDown: { type: Boolean, default: !1 }
3358
+ },
3359
+ emits: ["action", "close"],
3360
+ setup(t, { expose: r, emit: n }) {
3361
+ r();
3362
+ const e = t, o = n, { t: i } = pe(), a = N(() => ({
3363
+ top: `${e.y}px`,
3364
+ left: `${e.x}px`
3365
+ })), l = N(() => [
3366
+ { key: "duplicate", label: i("contextMenu.duplicate") },
3367
+ { key: "move-up", label: i("contextMenu.moveUp"), disabled: !e.canMoveUp },
3368
+ { key: "move-down", label: i("contextMenu.moveDown"), disabled: !e.canMoveDown },
3369
+ { key: "delete", label: i("contextMenu.delete"), danger: !0, disabled: !e.canDelete }
3370
+ ]);
3371
+ function u(c, m) {
3372
+ m || o("action", c);
3373
+ }
3374
+ const b = R(null), v = R(null);
3375
+ function I() {
3376
+ return b.value ? Array.from(b.value.querySelectorAll(".ipb-node-context-menu__item")).filter(
3377
+ (c) => !c.disabled
3378
+ ) : [];
3379
+ }
3380
+ function d() {
3381
+ const [c] = I();
3382
+ c == null || c.focus();
3383
+ }
3384
+ function A() {
3385
+ v.value instanceof HTMLElement && v.value.focus(), v.value = null;
3386
+ }
3387
+ function k(c) {
3388
+ var E, O, L, P;
3389
+ if (c.key === "Escape") {
3390
+ c.preventDefault(), o("close");
3391
+ return;
3392
+ }
3393
+ if (c.key === "Tab") {
3394
+ c.preventDefault(), o("close");
3395
+ return;
3396
+ }
3397
+ const m = I();
3398
+ if (m.length === 0) return;
3399
+ const p = document.activeElement instanceof HTMLButtonElement ? document.activeElement : null, g = p ? m.indexOf(p) : -1;
3400
+ if (c.key === "ArrowDown") {
3401
+ c.preventDefault();
3402
+ const F = g < 0 ? 0 : (g + 1) % m.length;
3403
+ (E = m[F]) == null || E.focus();
3404
+ return;
3405
+ }
3406
+ if (c.key === "ArrowUp") {
3407
+ c.preventDefault();
3408
+ const F = g < 0 ? m.length - 1 : (g - 1 + m.length) % m.length;
3409
+ (O = m[F]) == null || O.focus();
3410
+ return;
3411
+ }
3412
+ if (c.key === "Home") {
3413
+ c.preventDefault(), (L = m[0]) == null || L.focus();
3414
+ return;
3415
+ }
3416
+ c.key === "End" && (c.preventDefault(), (P = m[m.length - 1]) == null || P.focus());
3417
+ }
3418
+ function y(c) {
3419
+ var p;
3420
+ const m = c.relatedTarget;
3421
+ if (!(m instanceof Node)) {
3422
+ o("close");
3423
+ return;
3424
+ }
3425
+ (p = b.value) != null && p.contains(m) || o("close");
3426
+ }
3427
+ de(
3428
+ () => e.open,
3429
+ (c) => {
3430
+ if (c) {
3431
+ v.value = document.activeElement instanceof HTMLElement ? document.activeElement : null, ue(() => {
3432
+ d();
3433
+ });
3434
+ return;
3435
+ }
3436
+ A();
3437
+ },
3438
+ { immediate: !0 }
3439
+ ), dn(() => {
3440
+ A();
3441
+ });
3442
+ const D = { props: e, emit: o, t: i, menuStyle: a, menuItems: l, handleAction: u, menuRootRef: b, previousFocusedElement: v, getFocusableItems: I, focusFirstMenuItem: d, restorePreviousFocus: A, handleMenuKeydown: k, handleMenuFocusOut: y };
3443
+ return Object.defineProperty(D, "__isScriptSetup", { enumerable: !1, value: !0 }), D;
3444
+ }
3445
+ }), ji = ["aria-label"], Hi = ["disabled", "data-action", "aria-disabled", "onClick"];
3446
+ function Wi(t, r, n, e, o, i) {
3447
+ return n.open ? (x(), C("div", {
3448
+ key: 0,
3449
+ ref: "menuRootRef",
3450
+ class: "ipb-node-context-menu",
3451
+ style: J(e.menuStyle),
3452
+ role: "menu",
3453
+ "aria-label": e.t("contextMenu.ariaLabel"),
3454
+ "aria-orientation": "vertical",
3455
+ tabindex: "-1",
3456
+ onClick: r[0] || (r[0] = Et(() => {
3457
+ }, ["stop"])),
3458
+ onContextmenu: r[1] || (r[1] = Et(() => {
3459
+ }, ["prevent"])),
3460
+ onKeydown: e.handleMenuKeydown,
3461
+ onFocusout: e.handleMenuFocusOut
3462
+ }, [
3463
+ (x(!0), C(
3464
+ he,
3465
+ null,
3466
+ ve(e.menuItems, (a) => (x(), C("button", {
3467
+ key: a.key,
3468
+ type: "button",
3469
+ class: _e(["ipb-node-context-menu__item", { "ipb-node-context-menu__item--danger": a.danger }]),
3470
+ disabled: a.disabled,
3471
+ "data-action": a.key,
3472
+ role: "menuitem",
3473
+ "aria-disabled": a.disabled ? "true" : void 0,
3474
+ onClick: (l) => e.handleAction(a.key, a.disabled)
3475
+ }, z(a.label), 11, Hi))),
3476
+ 128
3477
+ /* KEYED_FRAGMENT */
3478
+ ))
3479
+ ], 44, ji)) : Y("v-if", !0);
3480
+ }
3481
+ const Ui = /* @__PURE__ */ q(zi, [["render", Wi], ["__scopeId", "data-v-89c3623e"], ["__file", "/app/src/components/editor/NodeContextMenu.vue"]]), ot = "ipb-iframe-canvas-content", kt = "ipb-iframe-canvas-base-style", on = 240, an = 320, Ki = /* @__PURE__ */ G({
3482
+ __name: "IframeCanvas",
3483
+ props: {
3484
+ content: { type: Object, required: !0 },
3485
+ variables: { type: Object, default: () => ({}) },
3486
+ selectedNodeId: { type: Number, default: null },
3487
+ hoveredNodeId: { type: Number, default: null },
3488
+ viewport: { type: String, default: "desktop" },
3489
+ viewportWidth: { type: Number, default: null },
3490
+ viewportHeight: { type: Number, default: null }
3491
+ },
3492
+ emits: ["select", "hover", "context-action", "iframe-keydown", "viewport-size-change"],
3493
+ setup(t, { expose: r, emit: n }) {
3494
+ r();
3495
+ const e = t, o = n, i = je(Ht, null), a = je(Wt, null), { t: l } = pe(), u = R(null), b = R(null), v = R(null), I = R(!1), d = R(null), A = R(null), k = R(null), y = R(null), D = R(null), c = R(null), m = R({ width: 0, height: 0 }), p = R(!1), g = R(null), E = R(null), O = R(null), L = R(!1), P = R(null), F = R(0), ee = R(0), te = R(!1), ne = R(!1), le = R(!1), me = N(() => {
3496
+ if (e.viewport === "custom")
3497
+ return {
3498
+ width: Math.max(on, Math.round(e.viewportWidth ?? Xe.desktop.width)),
3499
+ height: Math.max(an, Math.round(e.viewportHeight ?? Xe.desktop.height))
3500
+ };
3501
+ const s = Xe[e.viewport];
3502
+ return { width: s.width, height: s.height };
3503
+ }), Te = N(() => ({
3504
+ width: `min(100%, ${me.value.width}px)`,
3505
+ height: `${me.value.height}px`
3506
+ })), Ke = N(
3507
+ () => g.value ? {
3508
+ top: `${g.value.top}px`,
3509
+ left: `${g.value.left}px`,
3510
+ width: `${g.value.width}px`,
3511
+ height: `${g.value.height}px`
3512
+ } : null
3513
+ ), Fe = N(
3514
+ () => E.value && e.hoveredNodeId !== e.selectedNodeId ? {
3515
+ top: `${E.value.top}px`,
3516
+ left: `${E.value.left}px`,
3517
+ width: `${E.value.width}px`,
3518
+ height: `${E.value.height}px`
3519
+ } : null
3520
+ ), Ve = N(
3521
+ () => O.value ? {
3522
+ top: `${O.value.top}px`,
3523
+ left: `${O.value.left}px`,
3524
+ width: `${O.value.width}px`,
3525
+ height: `${O.value.height}px`
3526
+ } : null
3527
+ );
3528
+ function h(s) {
3529
+ return !s || typeof s != "object" ? !1 : s.nodeType === 1;
3530
+ }
3531
+ function B(s) {
3532
+ if (s === null) return null;
3533
+ const _ = Number(s);
3534
+ return Number.isInteger(_) ? _ : null;
3535
+ }
3536
+ function f(s) {
3537
+ if (!h(s)) return null;
3538
+ const _ = s.closest("[data-ipb-node-id]");
3539
+ return B((_ == null ? void 0 : _.getAttribute("data-ipb-node-id")) ?? null);
3540
+ }
3541
+ function w(s) {
3542
+ return s === null || !d.value ? null : d.value.querySelector(`[data-ipb-node-id="${s}"]`);
3543
+ }
3544
+ function T(s) {
3545
+ var $, Q;
3546
+ if (!s || !d.value) return null;
3547
+ const _ = s.getBoundingClientRect(), V = d.value.getBoundingClientRect(), M = (($ = k.value) == null ? void 0 : $.scrollY) ?? 0, X = ((Q = k.value) == null ? void 0 : Q.scrollX) ?? 0;
3548
+ return {
3549
+ top: _.top - V.top + M,
3550
+ left: _.left - V.left + X,
3551
+ width: _.width,
3552
+ height: _.height
3553
+ };
3554
+ }
3555
+ function W(s, _) {
3556
+ return Math.max(0, Math.min(s, _));
3557
+ }
3558
+ function H(s, _) {
3559
+ return s.id === _ ? !0 : s.children.some((V) => H(V, _));
3560
+ }
3561
+ function K(s) {
3562
+ var _;
3563
+ return s.sourceComponentName ? s.sourceComponentName : s.sourceNodeId === null ? null : ((_ = U(e.content, s.sourceNodeId)) == null ? void 0 : _.name) ?? null;
3564
+ }
3565
+ function re(s, _) {
3566
+ const V = K(_);
3567
+ if (!V) return null;
3568
+ const M = s === null ? null : U(e.content, s);
3569
+ if (M && !M.readonly) {
3570
+ const $ = Ne(M, "default", V);
3571
+ if ($)
3572
+ return {
3573
+ targetId: M.id,
3574
+ index: M.children.length,
3575
+ slot: $
3576
+ };
3577
+ }
3578
+ if (s !== null) {
3579
+ const $ = ae(e.content, s);
3580
+ if ($ && !$.parent.readonly) {
3581
+ const Q = $.parent.children[$.index], be = Ne($.parent, (Q == null ? void 0 : Q.slot) ?? "default", V);
3582
+ if (be)
3583
+ return {
3584
+ targetId: $.parent.id,
3585
+ index: $.index + 1,
3586
+ slot: be
3587
+ };
3588
+ }
3589
+ }
3590
+ if (e.content.readonly) return null;
3591
+ const X = Ne(e.content, "default", V);
3592
+ return X ? {
3593
+ targetId: e.content.id,
3594
+ index: e.content.children.length,
3595
+ slot: X
3596
+ } : null;
3597
+ }
3598
+ function oe(s, _, V, M) {
3599
+ const X = U(e.content, s), $ = ae(e.content, s), Q = U(e.content, _);
3600
+ if (!X || !$ || X.readonly) return { valid: !1 };
3601
+ if (!Q || Q.readonly) return { valid: !1 };
3602
+ if (s === _) return { valid: !1 };
3603
+ if (H(X, _)) return { valid: !1 };
3604
+ const be = Ne(Q, V, X.name);
3605
+ if (!be) return { valid: !1 };
3606
+ const Xt = Q.children.length;
3607
+ return $.parent.id === _ && $.index < M ? { valid: !0, index: W(M - 1, Xt), slot: be } : { valid: !0, index: W(M, Xt), slot: be };
3608
+ }
3609
+ function fe(s) {
3610
+ if (s.getElementById(kt)) return;
3611
+ const _ = s.createElement("style");
3612
+ _.id = kt, _.textContent = `
3613
+ html, body {
3614
+ margin: 0;
3615
+ padding: 0;
3616
+ min-height: 100%;
3617
+ overflow-x: hidden;
3618
+ }
3619
+
3620
+ body {
3621
+ background: #fff;
3622
+ }
3623
+
3624
+ #${ot} {
3625
+ position: relative;
3626
+ width: 100%;
3627
+ max-width: 100%;
3628
+ min-height: 100%;
3629
+ overflow-x: hidden;
3630
+ box-sizing: border-box;
3631
+ }
3632
+
3633
+ /* Minimum size for layout containers so empty columns/rows remain droppable in the editor */
3634
+ [data-ipb-component="PbColumn"] {
3635
+ min-width: 80px;
3636
+ min-height: 80px;
3637
+ }
3638
+ [data-ipb-component="PbRow"] {
3639
+ min-height: 80px;
3640
+ }
3641
+ `, s.head.appendChild(_);
3642
+ }
3643
+ function ye(s) {
3644
+ if (!s.body) return null;
3645
+ fe(s);
3646
+ let _ = s.getElementById(ot);
3647
+ return _ || (_ = s.createElement("div"), _.id = ot, s.body.innerHTML = "", s.body.appendChild(_)), _;
3648
+ }
3649
+ function Me() {
3650
+ d.value && Zt(
3651
+ Zn(Pn, {
3652
+ node: e.content,
3653
+ variables: e.variables,
3654
+ markNodes: !0
3655
+ }),
3656
+ d.value
3657
+ );
3658
+ }
3659
+ function Ce() {
3660
+ d.value && Zt(null, d.value);
3661
+ }
3662
+ function $e() {
3663
+ if (!d.value) return;
3664
+ d.value.querySelectorAll("[data-ipb-node-id]").forEach((_) => {
3665
+ const V = B(_.getAttribute("data-ipb-node-id")), M = V === null ? null : U(e.content, V);
3666
+ _.draggable = !!(M && !M.readonly && M.id !== e.content.id);
3667
+ });
3668
+ }
3669
+ function we() {
3670
+ g.value = T(w(e.selectedNodeId)), E.value = T(w(e.hoveredNodeId));
3671
+ const s = a ? a.dragState.value.dropTargetId : null;
3672
+ O.value = s === null ? null : T(w(s));
3673
+ }
3674
+ function xe() {
3675
+ return b.value ? {
3676
+ width: Math.round(b.value.clientWidth),
3677
+ height: Math.round(b.value.clientHeight)
3678
+ } : {
3679
+ width: 0,
3680
+ height: 0
3681
+ };
3682
+ }
3683
+ function Oe() {
3684
+ const s = xe();
3685
+ p.value && s.width === m.value.width && s.height === m.value.height || (m.value = s, p.value = !0, o("viewport-size-change", s));
3686
+ }
3687
+ function Ge() {
3688
+ we(), Oe();
3689
+ }
3690
+ function Be() {
3691
+ var s;
3692
+ (s = c.value) == null || s.disconnect(), c.value = null;
3693
+ }
3694
+ function Kt() {
3695
+ if (Be(), typeof ResizeObserver > "u" || !b.value || !d.value) return;
3696
+ const s = new ResizeObserver(() => {
3697
+ Ge();
3698
+ });
3699
+ s.observe(b.value), s.observe(d.value), c.value = s;
3700
+ }
3701
+ async function Ie() {
3702
+ await ue(), Me(), await ue(), $e(), we(), Oe();
3703
+ }
3704
+ function De() {
3705
+ O.value = null;
3706
+ }
3707
+ function ge() {
3708
+ L.value = !1, P.value = null;
3709
+ }
3710
+ function On() {
3711
+ ge(), o("select", null), o("hover", null);
3712
+ }
3713
+ function ut(s) {
3714
+ s.stopPropagation(), ge();
3715
+ const _ = f(s.target);
3716
+ o("select", _);
3717
+ }
3718
+ function ft(s) {
3719
+ const _ = f(s.target);
3720
+ _ !== e.hoveredNodeId && o("hover", _);
3721
+ }
3722
+ function pt() {
3723
+ o("hover", null);
3724
+ }
3725
+ function mt(s) {
3726
+ if (!a) return;
3727
+ const _ = f(s.target);
3728
+ if (_ === null) return;
3729
+ const V = U(e.content, _);
3730
+ if (!V || V.readonly || V.id === e.content.id) {
3731
+ s.preventDefault();
3732
+ return;
3733
+ }
3734
+ a.startDragExisting(_), s.dataTransfer && (s.dataTransfer.effectAllowed = "move", s.dataTransfer.setData("text/plain", String(_)));
3735
+ }
3736
+ function gt(s) {
3737
+ if (!a || !a.dragState.value.isDragging) return;
3738
+ const _ = f(s.target), V = re(_, a.dragState.value);
3739
+ if (!V) {
3740
+ De();
3741
+ return;
3742
+ }
3743
+ s.preventDefault(), a.updateDropTarget(V.targetId, V.index, V.slot), O.value = T(w(V.targetId)), s.dataTransfer && (s.dataTransfer.dropEffect = a.dragState.value.isNewComponent ? "copy" : "move");
3744
+ }
3745
+ function bt(s) {
3746
+ if (!d.value) return;
3747
+ const _ = s.relatedTarget;
3748
+ _ && typeof _ == "object" && "nodeType" in _ && d.value.contains(_) || De();
3749
+ }
3750
+ function vt(s) {
3751
+ var $;
3752
+ if (s.preventDefault(), !a || !i || !a.dragState.value.isDragging) {
3753
+ De();
3754
+ return;
3755
+ }
3756
+ const _ = f(s.target), V = re(_, a.dragState.value);
3757
+ if (!V) {
3758
+ a.cancelDrag(), De();
3759
+ return;
3760
+ }
3761
+ a.updateDropTarget(V.targetId, V.index, V.slot);
3762
+ const M = a.endDrag();
3763
+ if (De(), M.dropTargetId === null) return;
3764
+ if (M.isNewComponent && M.sourceComponentName) {
3765
+ const Q = ($ = Le(M.sourceComponentName)) == null ? void 0 : $.defaultProps, be = i.addNode(
3766
+ M.dropTargetId,
3767
+ M.sourceComponentName,
3768
+ M.dropIndex,
3769
+ M.dropSlot,
3770
+ Q
3771
+ );
3772
+ be !== null && o("select", be);
3773
+ return;
3774
+ }
3775
+ if (M.sourceNodeId === null) return;
3776
+ const X = oe(
3777
+ M.sourceNodeId,
3778
+ M.dropTargetId,
3779
+ M.dropSlot,
3780
+ M.dropIndex
3781
+ );
3782
+ X.valid && (i.moveNodeTo(
3783
+ M.sourceNodeId,
3784
+ M.dropTargetId,
3785
+ X.index,
3786
+ X.slot
3787
+ ), o("select", M.sourceNodeId));
3788
+ }
3789
+ function ht() {
3790
+ a != null && a.dragState.value.isDragging && a.cancelDrag(), De();
3791
+ }
3792
+ function _t(s) {
3793
+ const _ = U(e.content, s);
3794
+ if (_ != null && _.readonly) {
3795
+ te.value = !1, ne.value = !1, le.value = !1;
3796
+ return;
3797
+ }
3798
+ const V = ae(e.content, s);
3799
+ if (!V) {
3800
+ te.value = !1, ne.value = !1, le.value = !1;
3801
+ return;
3802
+ }
3803
+ te.value = !0, ne.value = V.index > 0, le.value = V.index < V.parent.children.length - 1;
3804
+ }
3805
+ function yt(s) {
3806
+ var $, Q;
3807
+ s.preventDefault(), s.stopPropagation();
3808
+ const _ = f(s.target);
3809
+ if (_ === null || !d.value) {
3810
+ ge();
3811
+ return;
3812
+ }
3813
+ const V = d.value.getBoundingClientRect(), M = (($ = k.value) == null ? void 0 : $.scrollY) ?? 0, X = ((Q = k.value) == null ? void 0 : Q.scrollX) ?? 0;
3814
+ F.value = s.clientX - V.left + X, ee.value = s.clientY - V.top + M, P.value = _, _t(_), L.value = !0, o("select", _);
3815
+ }
3816
+ function Bn(s) {
3817
+ P.value !== null && (o("context-action", { action: s, nodeId: P.value }), ge());
3818
+ }
3819
+ function Ft(s) {
3820
+ if (!h(s)) return !1;
3821
+ const _ = s.tagName.toLowerCase();
3822
+ return _ === "input" || _ === "textarea" || _ === "select" ? !0 : !!s.closest('[contenteditable]:not([contenteditable="false"])');
3823
+ }
3824
+ function $t(s) {
3825
+ var X, $;
3826
+ if (s.interaction === "hover") {
3827
+ s.nodeId !== e.hoveredNodeId && o("hover", s.nodeId);
3828
+ return;
3829
+ }
3830
+ if (s.interaction === "select") {
3831
+ ge(), o("select", s.nodeId);
3832
+ return;
3833
+ }
3834
+ if (s.interaction !== "context") return;
3835
+ if (s.nodeId === null || !d.value) {
3836
+ ge();
3837
+ return;
3838
+ }
3839
+ const _ = d.value.getBoundingClientRect(), V = ((X = k.value) == null ? void 0 : X.scrollY) ?? 0, M = (($ = k.value) == null ? void 0 : $.scrollX) ?? 0;
3840
+ F.value = s.clientX - _.left + M, ee.value = s.clientY - _.top + V, P.value = s.nodeId, _t(s.nodeId), L.value = !0, o("select", s.nodeId);
3841
+ }
3842
+ function Gt(s) {
3843
+ s.key === "Escape" && ge(), o("iframe-keydown", {
3844
+ ...s,
3845
+ // Preventing defaults from the parent is asynchronous in postMessage mode.
3846
+ preventDefault: () => {
3847
+ }
3848
+ });
3849
+ }
3850
+ function wt(s) {
3851
+ try {
3852
+ return s.location.origin;
3853
+ } catch {
3854
+ return window.location.origin;
3855
+ }
3856
+ }
3857
+ function xt() {
3858
+ var s, _;
3859
+ (s = y.value) == null || s.call(y), y.value = null, (_ = D.value) == null || _.call(D), D.value = null;
3860
+ }
3861
+ function qt() {
3862
+ const s = k.value, _ = A.value, V = d.value;
3863
+ if (!s || !_ || !V) return;
3864
+ xt();
3865
+ const M = Ei(), X = Vi({
3866
+ hostWindow: window,
3867
+ expectedSource: window,
3868
+ expectedOrigin: wt(window),
3869
+ expectedSessionToken: M,
3870
+ onReady: () => {
3871
+ Ie();
3872
+ },
3873
+ onPointer: $t,
3874
+ onKeydown: Gt
3875
+ }), $ = Mi({
3876
+ targetWindow: window,
3877
+ targetOrigin: wt(window),
3878
+ sessionToken: M
3879
+ });
3880
+ y.value = () => X.dispose(), D.value = Bi({
3881
+ frameDocument: _,
3882
+ contentRoot: V,
3883
+ bridge: $,
3884
+ resolveNodeId: f,
3885
+ isEditableTarget: Ft
3886
+ });
3887
+ }
3888
+ function ke() {
3889
+ Ge();
3890
+ }
3891
+ function Qe() {
3892
+ Be(), xt(), d.value && (d.value.removeEventListener("click", ut), d.value.removeEventListener("contextmenu", yt), d.value.removeEventListener("mousemove", ft), d.value.removeEventListener("mouseleave", pt), d.value.removeEventListener("dragstart", mt), d.value.removeEventListener("dragover", gt), d.value.removeEventListener("dragleave", bt), d.value.removeEventListener("drop", vt), d.value.removeEventListener("dragend", ht)), !I.value && k.value && (k.value.removeEventListener("scroll", ke), k.value.removeEventListener("resize", ke));
3893
+ }
3894
+ function It() {
3895
+ d.value && (I.value ? (d.value.addEventListener("click", ut), d.value.addEventListener("contextmenu", yt), d.value.addEventListener("mousemove", ft), d.value.addEventListener("mouseleave", pt)) : qt(), d.value.addEventListener("dragstart", mt), d.value.addEventListener("dragover", gt), d.value.addEventListener("dragleave", bt), d.value.addEventListener("drop", vt), d.value.addEventListener("dragend", ht), !I.value && k.value && (k.value.addEventListener("scroll", ke), k.value.addEventListener("resize", ke)), Kt());
3896
+ }
3897
+ function et() {
3898
+ I.value = !0, ue().then(() => {
3899
+ v.value && (Qe(), Ce(), A.value = null, k.value = null, d.value = v.value, It(), Ie());
3900
+ });
3901
+ }
3902
+ function tt() {
3903
+ const s = u.value;
3904
+ if (!s) {
3905
+ et();
3906
+ return;
3907
+ }
3908
+ const _ = s.contentDocument, V = s.contentWindow;
3909
+ if (!_ || !V) {
3910
+ et();
3911
+ return;
3912
+ }
3913
+ const M = ye(_);
3914
+ if (!M) {
3915
+ et();
3916
+ return;
3917
+ }
3918
+ Qe(), Ce(), I.value = !1, A.value = _, k.value = V, d.value = M, It(), Ie();
3919
+ }
3920
+ de(
3921
+ () => [e.selectedNodeId, e.hoveredNodeId],
3922
+ () => {
3923
+ Ie();
3924
+ },
3925
+ { immediate: !0 }
3926
+ ), de(
3927
+ () => [e.viewport, e.viewportWidth, e.viewportHeight],
3928
+ () => {
3929
+ Ie();
3930
+ }
3931
+ ), de(
3932
+ () => e.content,
3933
+ () => {
3934
+ P.value !== null && !U(e.content, P.value) && ge(), Ie();
3935
+ },
3936
+ { deep: !0 }
3937
+ ), de(
3938
+ () => e.variables,
3939
+ () => {
3940
+ Ie();
3941
+ },
3942
+ { deep: !0 }
3943
+ ), de(
3944
+ () => (a == null ? void 0 : a.dragState.value.isDragging) ?? !1,
3945
+ (s) => {
3946
+ s || De();
3947
+ }
3948
+ ), Ot(() => {
3949
+ var s;
3950
+ window.addEventListener("resize", ke), (s = u.value) == null || s.addEventListener("load", tt), tt();
3951
+ }), dn(() => {
3952
+ var s;
3953
+ window.removeEventListener("resize", ke), (s = u.value) == null || s.removeEventListener("load", tt), Qe(), Ce();
3954
+ });
3955
+ const Yt = { props: e, emit: o, IFRAME_CONTENT_ROOT_ID: ot, IFRAME_BASE_STYLE_ID: kt, MIN_VIEWPORT_WIDTH: on, MIN_VIEWPORT_HEIGHT: an, nodeTree: i, dragDrop: a, t: l, iframeRef: u, stageRef: b, fallbackContentRef: v, useFallbackDom: I, contentRef: d, iframeDocumentRef: A, iframeWindowRef: k, teardownBridgeParentRef: y, teardownBridgeDomRef: D, resizeObserverRef: c, currentViewportSize: m, hasViewportSizeReport: p, selectedRect: g, hoveredRect: E, dropRect: O, contextMenuOpen: L, contextMenuNodeId: P, contextMenuX: F, contextMenuY: ee, canDeleteFromMenu: te, canMoveUpFromMenu: ne, canMoveDownFromMenu: le, resolvedViewportDimensions: me, canvasStyle: Te, selectedOverlayStyle: Ke, hoveredOverlayStyle: Fe, dropOverlayStyle: Ve, isElementTarget: h, parseNodeId: B, getNodeIdFromEventTarget: f, findMarkedElement: w, getOverlayRect: T, clampIndex: W, isNodeInSubtree: H, getDraggedComponentName: K, resolveDropLocation: re, canMoveNode: oe, ensureIframeBaseStyle: fe, ensureIframeContentRoot: ye, renderIframeNodeTree: Me, unmountIframeNodeTree: Ce, syncDraggableMarkers: $e, syncOverlayRects: we, getStageViewportSize: xe, syncViewportSize: Oe, handleCanvasResize: Ge, disconnectResizeObserver: Be, setupResizeObserver: Kt, syncOverlayRectsAfterRender: Ie, clearDropTargetOverlay: De, hideContextMenu: ge, handleCanvasClick: On, handleContentClick: ut, handleContentMouseMove: ft, handleContentMouseLeave: pt, handleContentDragStart: mt, handleContentDragOver: gt, handleContentDragLeave: bt, handleContentDrop: vt, handleContentDragEnd: ht, updateContextMenuCapabilities: _t, handleContentContextMenu: yt, handleContextMenuAction: Bn, isEditableTarget: Ft, handleBridgePointer: $t, handleBridgeKeydown: Gt, getWindowOrigin: wt, teardownIframeBridge: xt, setupIframeBridge: qt, handleWindowResize: ke, teardownIframeListeners: Qe, setupIframeListeners: It, initializeFallbackContent: et, initializeIframeDocument: tt, NodeContextMenu: Ui };
3956
+ return Object.defineProperty(Yt, "__isScriptSetup", { enumerable: !1, value: !0 }), Yt;
3957
+ }
3958
+ }), Fi = {
3959
+ ref: "stageRef",
3960
+ class: "ipb-iframe-canvas__stage"
3961
+ }, $i = ["title"], Gi = {
3962
+ key: 1,
3963
+ ref: "fallbackContentRef",
3964
+ id: "ipb-iframe-canvas-content",
3965
+ class: "ipb-iframe-canvas__fallback"
3966
+ };
3967
+ function qi(t, r, n, e, o, i) {
3968
+ return x(), C(
3969
+ "main",
3970
+ {
3971
+ class: "ipb-canvas",
3972
+ onClick: e.handleCanvasClick,
3973
+ onContextmenu: Et(e.hideContextMenu, ["prevent"])
3974
+ },
3975
+ [
3976
+ S(
3977
+ "div",
3978
+ {
3979
+ class: "ipb-canvas__viewport",
3980
+ style: J(e.canvasStyle)
3981
+ },
3982
+ [
3983
+ S(
3984
+ "div",
3985
+ Fi,
3986
+ [
3987
+ e.useFallbackDom ? (x(), C(
3988
+ "div",
3989
+ Gi,
3990
+ null,
3991
+ 512
3992
+ /* NEED_PATCH */
3993
+ )) : (x(), C("iframe", {
3994
+ key: 0,
3995
+ ref: "iframeRef",
3996
+ class: "ipb-iframe-canvas__frame",
3997
+ title: e.t("iframeCanvas.title"),
3998
+ sandbox: "allow-same-origin"
3999
+ }, null, 8, $i)),
4000
+ e.dropOverlayStyle ? (x(), C(
4001
+ "div",
4002
+ {
4003
+ key: 2,
4004
+ class: "ipb-canvas__overlay ipb-canvas__overlay--drop",
4005
+ style: J(e.dropOverlayStyle)
4006
+ },
4007
+ null,
4008
+ 4
4009
+ /* STYLE */
4010
+ )) : Y("v-if", !0),
4011
+ e.hoveredOverlayStyle ? (x(), C(
4012
+ "div",
4013
+ {
4014
+ key: 3,
4015
+ class: "ipb-canvas__overlay ipb-canvas__overlay--hovered",
4016
+ style: J(e.hoveredOverlayStyle)
4017
+ },
4018
+ null,
4019
+ 4
4020
+ /* STYLE */
4021
+ )) : Y("v-if", !0),
4022
+ e.selectedOverlayStyle ? (x(), C(
4023
+ "div",
4024
+ {
4025
+ key: 4,
4026
+ class: "ipb-canvas__overlay ipb-canvas__overlay--selected",
4027
+ style: J(e.selectedOverlayStyle)
4028
+ },
4029
+ null,
4030
+ 4
4031
+ /* STYLE */
4032
+ )) : Y("v-if", !0),
4033
+ Re(e.NodeContextMenu, {
4034
+ open: e.contextMenuOpen,
4035
+ x: e.contextMenuX,
4036
+ y: e.contextMenuY,
4037
+ "can-delete": e.canDeleteFromMenu,
4038
+ "can-move-up": e.canMoveUpFromMenu,
4039
+ "can-move-down": e.canMoveDownFromMenu,
4040
+ onAction: e.handleContextMenuAction,
4041
+ onClose: e.hideContextMenu
4042
+ }, null, 8, ["open", "x", "y", "can-delete", "can-move-up", "can-move-down"])
4043
+ ],
4044
+ 512
4045
+ /* NEED_PATCH */
4046
+ )
4047
+ ],
4048
+ 4
4049
+ /* STYLE */
4050
+ )
4051
+ ],
4052
+ 32
4053
+ /* NEED_HYDRATION */
4054
+ );
4055
+ }
4056
+ const Yi = /* @__PURE__ */ q(Ki, [["render", qi], ["__scopeId", "data-v-11905b62"], ["__file", "/app/src/components/editor/IframeCanvas.vue"]]), Xi = /* @__PURE__ */ G({
4057
+ __name: "PageEditor",
4058
+ props: {
4059
+ pageData: {
4060
+ type: Object,
4061
+ required: !0
4062
+ }
4063
+ },
4064
+ emits: ["save", "change"],
4065
+ setup(t, { expose: r, emit: n }) {
4066
+ r();
4067
+ const e = t, o = n, i = ho({ initialData: e.pageData, mode: "edit" }), a = _o({ initialSnapshot: i.getSnapshot() }), l = wo(), u = yo({
4068
+ content: i.content,
4069
+ nextId: i.nextId,
4070
+ onUpdate: (h) => {
4071
+ i.updateContent(h), o("change", h);
4072
+ },
4073
+ onSnapshot: (h) => {
4074
+ a.pushHistory(h, i.getSnapshot());
4075
+ }
4076
+ }), b = R(1024), v = R(768), I = R(null), d = R(null);
4077
+ function A() {
4078
+ o("save", {
4079
+ content: i.content.value,
4080
+ layout: i.layout.value,
4081
+ maxId: i.maxId.value
4082
+ });
4083
+ }
4084
+ function k(h) {
4085
+ if (!h) return !1;
4086
+ try {
4087
+ i.restoreSnapshot(h);
4088
+ const B = a.selectedNodeId.value;
4089
+ return B !== null && !U(i.content.value, B) && a.selectNode(null), o("change", i.content.value), !0;
4090
+ } catch (B) {
4091
+ return Ue(
4092
+ "PageEditor.restoreSnapshotAndEmit",
4093
+ Z(
4094
+ "INVALID_SNAPSHOT",
4095
+ "[PageBuilder] Failed to apply history snapshot. Undo/redo step was skipped.",
4096
+ {
4097
+ cause: B,
4098
+ details: {
4099
+ snapshotPreview: h.slice(0, 200)
4100
+ }
4101
+ }
4102
+ )
4103
+ ), !1;
4104
+ }
4105
+ }
4106
+ function y() {
4107
+ k(a.undo());
4108
+ }
4109
+ function D() {
4110
+ k(a.redo());
4111
+ }
4112
+ function c(h) {
4113
+ const B = U(i.content.value, h);
4114
+ !B || B.readonly || u.deleteNode(h);
4115
+ }
4116
+ function m(h) {
4117
+ U(i.content.value, h) && u.duplicateNode(h);
4118
+ }
4119
+ function p(h) {
4120
+ const B = U(i.content.value, h);
4121
+ !B || B.readonly || u.canMoveNodeUp(h) && u.moveNodeUp(h);
4122
+ }
4123
+ function g(h) {
4124
+ const B = U(i.content.value, h);
4125
+ !B || B.readonly || u.canMoveNodeDown(h) && u.moveNodeDown(h);
4126
+ }
4127
+ function E(h) {
4128
+ if (h.action === "duplicate") {
4129
+ m(h.nodeId);
4130
+ return;
4131
+ }
4132
+ if (h.action === "delete") {
4133
+ c(h.nodeId);
4134
+ return;
4135
+ }
4136
+ if (h.action === "move-up") {
4137
+ p(h.nodeId);
4138
+ return;
4139
+ }
4140
+ h.action === "move-down" && g(h.nodeId);
4141
+ }
4142
+ function O(h) {
4143
+ if (!h || typeof h != "object" || !("nodeType" in h) || h.nodeType !== 1) return !1;
4144
+ const B = h, f = B.tagName.toLowerCase();
4145
+ return f === "input" || f === "textarea" || f === "select" ? !0 : !!B.closest('[contenteditable]:not([contenteditable="false"])');
4146
+ }
4147
+ function L() {
4148
+ const h = a.selectedNodeId.value;
4149
+ h !== null && c(h);
4150
+ }
4151
+ function P(h) {
4152
+ if (h.defaultPrevented || h.isEditable) return;
4153
+ const B = h.ctrlKey || h.metaKey, f = h.key.toLowerCase(), w = h.code.toLowerCase();
4154
+ if (B && f === "z") {
4155
+ h.preventDefault(), h.shiftKey ? D() : y();
4156
+ return;
4157
+ }
4158
+ if (B && f === "y") {
4159
+ h.preventDefault(), D();
4160
+ return;
4161
+ }
4162
+ if (B && f === "s") {
4163
+ h.preventDefault(), A();
4164
+ return;
4165
+ }
4166
+ (f === "delete" || f === "backspace" || w === "delete" || w === "backspace") && !h.ctrlKey && !h.metaKey && !h.altKey && (h.preventDefault(), L());
4167
+ }
4168
+ function F(h) {
4169
+ P({
4170
+ key: h.key,
4171
+ code: h.code,
4172
+ ctrlKey: h.ctrlKey,
4173
+ metaKey: h.metaKey,
4174
+ shiftKey: h.shiftKey,
4175
+ altKey: h.altKey,
4176
+ defaultPrevented: h.defaultPrevented,
4177
+ isEditable: O(h.target) || O(document.activeElement),
4178
+ preventDefault: () => h.preventDefault()
4179
+ });
4180
+ }
4181
+ function ee(h) {
4182
+ P(h);
4183
+ }
4184
+ function te(h) {
4185
+ const B = Xe[h];
4186
+ return h === "custom" ? {
4187
+ width: b.value,
4188
+ height: v.value
4189
+ } : {
4190
+ width: B.width,
4191
+ height: B.height
4192
+ };
4193
+ }
4194
+ function ne(h) {
4195
+ if (h === "custom" && a.viewport.value !== "custom")
4196
+ if (I.value !== null && d.value !== null)
4197
+ b.value = I.value, v.value = d.value;
4198
+ else {
4199
+ const B = te(a.viewport.value);
4200
+ b.value = B.width, v.value = B.height;
4201
+ }
4202
+ a.setViewport(h);
4203
+ }
4204
+ function le(h) {
4205
+ b.value = h.width, v.value = h.height, a.viewport.value !== "custom" && a.setViewport("custom");
4206
+ }
4207
+ function me(h) {
4208
+ I.value = h.width, d.value = h.height;
4209
+ }
4210
+ function Te(h) {
4211
+ l.startDragNew(h);
4212
+ }
4213
+ function Ke() {
4214
+ l.cancelDrag();
4215
+ }
4216
+ function Fe(h) {
4217
+ var re;
4218
+ const B = a.selectedNodeId.value, f = B !== null ? U(i.content.value, B) : void 0;
4219
+ let w = i.content.value.id, T = i.content.value.children.length, W = "default";
4220
+ if (B !== null && f) {
4221
+ const oe = ae(i.content.value, B);
4222
+ oe ? (w = oe.parent.id, T = oe.index + 1, W = f.slot ?? "default") : (w = f.id, T = f.children.length);
4223
+ }
4224
+ const H = (re = Le(h)) == null ? void 0 : re.defaultProps, K = u.addNode(w, h, T, W, H);
4225
+ K !== null && a.selectNode(K);
4226
+ }
4227
+ Ot(() => {
4228
+ window.addEventListener("keydown", F);
4229
+ }), Jn(() => {
4230
+ window.removeEventListener("keydown", F);
4231
+ }), qe(po, i), qe(mo, a), qe(Ht, u), qe(Wt, l);
4232
+ const Ve = { props: e, emit: o, pb: i, editor: a, dragDrop: l, nodeTree: u, customViewportWidth: b, customViewportHeight: v, activeViewportWidth: I, activeViewportHeight: d, handleSave: A, restoreSnapshotAndEmit: k, handleUndo: y, handleRedo: D, handleDeleteNode: c, handleDuplicateNode: m, handleMoveNodeUp: p, handleMoveNodeDown: g, handleNodeContextAction: E, isEditableTarget: O, handleDeleteSelected: L, handleShortcut: P, handleEditorKeydown: F, handleIframeKeydown: ee, getViewportDimensions: te, handleViewportChange: ne, handleCustomViewportChange: le, handleViewportSizeChange: me, handlePaletteDragStart: Te, handlePaletteDragEnd: Ke, handlePaletteAdd: Fe, EditorToolbar: zo, LeftDrawer: Da, RightDrawer: Pi, IframeCanvas: Yi };
4233
+ return Object.defineProperty(Ve, "__isScriptSetup", { enumerable: !1, value: !0 }), Ve;
4234
+ }
4235
+ }), Zi = { class: "ipb-page-editor" }, Ji = { class: "ipb-page-editor__body" };
4236
+ function Qi(t, r, n, e, o, i) {
4237
+ return x(), C("div", Zi, [
4238
+ Re(e.EditorToolbar, {
4239
+ "can-undo": e.editor.canUndo.value,
4240
+ "can-redo": e.editor.canRedo.value,
4241
+ "is-dirty": e.pb.isDirty.value,
4242
+ viewport: e.editor.viewport.value,
4243
+ "custom-viewport-width": e.customViewportWidth,
4244
+ "custom-viewport-height": e.customViewportHeight,
4245
+ "active-viewport-width": e.activeViewportWidth,
4246
+ "active-viewport-height": e.activeViewportHeight,
4247
+ onUndo: e.handleUndo,
4248
+ onRedo: e.handleRedo,
4249
+ onSave: e.handleSave,
4250
+ onViewportChange: e.handleViewportChange,
4251
+ onCustomViewportChange: e.handleCustomViewportChange
4252
+ }, null, 8, ["can-undo", "can-redo", "is-dirty", "viewport", "custom-viewport-width", "custom-viewport-height", "active-viewport-width", "active-viewport-height"]),
4253
+ S("div", Ji, [
4254
+ Re(e.LeftDrawer, {
4255
+ open: e.editor.leftDrawerOpen.value,
4256
+ content: e.pb.content.value,
4257
+ "selected-node-id": e.editor.selectedNodeId.value,
4258
+ onToggle: e.editor.toggleLeftDrawer,
4259
+ onSelect: e.editor.selectNode,
4260
+ onAdd: e.handlePaletteAdd,
4261
+ onDragStart: e.handlePaletteDragStart,
4262
+ onDragEnd: e.handlePaletteDragEnd
4263
+ }, null, 8, ["open", "content", "selected-node-id", "onToggle", "onSelect"]),
4264
+ Re(e.IframeCanvas, {
4265
+ content: e.pb.content.value,
4266
+ variables: e.pb.variables.value,
4267
+ "selected-node-id": e.editor.selectedNodeId.value,
4268
+ "hovered-node-id": e.editor.hoveredNodeId.value,
4269
+ viewport: e.editor.viewport.value,
4270
+ "viewport-width": e.editor.viewport.value === "custom" ? e.customViewportWidth : null,
4271
+ "viewport-height": e.editor.viewport.value === "custom" ? e.customViewportHeight : null,
4272
+ onSelect: e.editor.selectNode,
4273
+ onHover: e.editor.hoverNode,
4274
+ onContextAction: e.handleNodeContextAction,
4275
+ onIframeKeydown: e.handleIframeKeydown,
4276
+ onViewportSizeChange: e.handleViewportSizeChange
4277
+ }, null, 8, ["content", "variables", "selected-node-id", "hovered-node-id", "viewport", "viewport-width", "viewport-height", "onSelect", "onHover"]),
4278
+ Re(e.RightDrawer, {
4279
+ open: e.editor.rightDrawerOpen.value,
4280
+ "selected-node-id": e.editor.selectedNodeId.value,
4281
+ content: e.pb.content.value,
4282
+ onToggle: e.editor.toggleRightDrawer,
4283
+ onUpdateProps: e.nodeTree.updateNodeProps,
4284
+ onDelete: e.handleDeleteNode,
4285
+ onDuplicate: e.handleDuplicateNode
4286
+ }, null, 8, ["open", "selected-node-id", "content", "onToggle", "onUpdateProps"])
4287
+ ])
4288
+ ]);
4289
+ }
4290
+ const el = /* @__PURE__ */ q(Xi, [["render", Qi], ["__scopeId", "data-v-0589f51d"], ["__file", "/app/src/components/editor/PageEditor.vue"]]), tl = /* @__PURE__ */ G({
4291
+ __name: "PageBuilder",
4292
+ props: {
4293
+ pageData: {
4294
+ type: Object,
4295
+ required: !0
4296
+ },
4297
+ mode: {
4298
+ type: String,
4299
+ default: "read"
4300
+ },
4301
+ locale: {
4302
+ type: String,
4303
+ default: void 0
4304
+ },
4305
+ messages: {
4306
+ type: Object,
4307
+ default: void 0
4308
+ }
4309
+ },
4310
+ emits: ["save", "change"],
4311
+ setup(t, { expose: r }) {
4312
+ r();
4313
+ const n = t, e = /* @__PURE__ */ new Set();
4314
+ function o(y, D, c) {
4315
+ e.has(y) || (e.add(y), Ue("PageBuilder", Z("INVALID_PAGE_DATA", D, { details: c })));
4316
+ }
4317
+ const i = N(() => n.pageData), a = N(() => n.mode === "read" || n.mode === "edit" ? n.mode : (o(
4318
+ "invalid-mode",
4319
+ `[PageBuilder] Unknown mode "${String(n.mode)}". Falling back to "read".`,
4320
+ { mode: n.mode }
4321
+ ), "read")), l = N(() => wn(i.value)), u = N(() => {
4322
+ const y = lt(i.value.content, "content"), D = lt(i.value.layout, "layout");
4323
+ return y.isValid && D.isValid;
4324
+ }), b = N(() => a.value === "edit" && !u.value), v = je(Dn, null), I = N(() => n.locale ?? (v == null ? void 0 : v.locale) ?? Lt), d = N(
4325
+ () => Fr(xn, v == null ? void 0 : v.messages, n.messages)
4326
+ ), A = In(() => I.value, () => d.value);
4327
+ de(
4328
+ l,
4329
+ (y) => {
4330
+ y.isValid || o(
4331
+ "invalid-page-data",
4332
+ "[PageBuilder] Invalid pageData payload detected. Rendering continues with degraded behavior.",
4333
+ { errors: y.errors }
4334
+ );
4335
+ },
4336
+ { immediate: !0 }
4337
+ ), qe(Nn, {
4338
+ locale: I,
4339
+ t: A
4340
+ });
4341
+ const k = { props: n, reportedDiagnostics: e, reportOnce: o, pageData: i, mode: a, pageValidationResult: l, canRenderEditor: u, showEditModeFallback: b, pluginI18nOptions: v, resolvedLocale: I, mergedMessages: d, t: A, PageReader: fo, PageEditor: el };
4342
+ return Object.defineProperty(k, "__isScriptSetup", { enumerable: !1, value: !0 }), k;
4343
+ }
4344
+ }), nl = {
4345
+ key: 0,
4346
+ class: "ipb-page-builder__warning",
4347
+ role: "alert"
4348
+ };
4349
+ function rl(t, r, n, e, o, i) {
4350
+ return x(), C(
4351
+ he,
4352
+ null,
4353
+ [
4354
+ e.showEditModeFallback ? (x(), C(
4355
+ "div",
4356
+ nl,
4357
+ z(e.t("pageBuilder.warning.invalidEditMode")),
4358
+ 1
4359
+ /* TEXT */
4360
+ )) : Y("v-if", !0),
4361
+ e.mode === "read" || e.showEditModeFallback ? (x(), Se(e.PageReader, {
4362
+ key: 1,
4363
+ "page-data": e.pageData
4364
+ }, null, 8, ["page-data"])) : (x(), Se(e.PageEditor, {
4365
+ key: 2,
4366
+ "page-data": e.pageData,
4367
+ onSave: r[0] || (r[0] = (a) => t.$emit("save", a)),
4368
+ onChange: r[1] || (r[1] = (a) => t.$emit("change", a))
4369
+ }, null, 8, ["page-data"]))
4370
+ ],
4371
+ 64
4372
+ /* STABLE_FRAGMENT */
4373
+ );
4374
+ }
4375
+ const ol = /* @__PURE__ */ q(tl, [["render", rl], ["__scopeId", "data-v-4b06ebe0"], ["__file", "/app/src/components/PageBuilder.vue"]]), ln = /* @__PURE__ */ new WeakSet();
4376
+ function sn(t) {
4377
+ const r = [];
4378
+ for (const n of t) {
4379
+ const e = n.name.trim(), o = Le(e);
4380
+ if (!o) {
4381
+ r.push(n);
4382
+ continue;
4383
+ }
4384
+ if (o.component !== n.component)
4385
+ throw Z(
4386
+ "DUPLICATE_COMPONENT",
4387
+ `[PageBuilder] Component "${e}" is already registered with a different implementation.`,
4388
+ {
4389
+ details: {
4390
+ componentName: e
4391
+ }
4392
+ }
4393
+ );
4394
+ }
4395
+ r.length > 0 && tr(r);
4396
+ }
4397
+ const bl = {
4398
+ install(t, r = {}) {
4399
+ if (ln.has(t)) return;
4400
+ ln.add(t);
4401
+ const {
4402
+ components: n = [],
4403
+ registerBuiltIn: e = !0,
4404
+ globalName: o = "PageBuilder",
4405
+ locale: i,
4406
+ messages: a
4407
+ } = r;
4408
+ t.provide(Dn, { locale: i, messages: a }), e && sn(Or), n.length > 0 && sn(n), o !== !1 && t.component(o, ol);
4409
+ }
4410
+ }, vl = {
4411
+ type: Object
4412
+ };
4413
+ export {
4414
+ Lt as DEFAULT_LOCALE,
4415
+ Wt as DRAG_DROP_KEY,
4416
+ mo as EDITOR_KEY,
4417
+ Ht as NODE_TREE_KEY,
4418
+ Pn as NodeRenderer,
4419
+ po as PAGE_BUILDER_KEY,
4420
+ ol as PageBuilder,
4421
+ cn as PageBuilderError,
4422
+ bl as PageBuilderPlugin,
4423
+ el as PageEditor,
4424
+ fo as PageReader,
4425
+ ir as PbColumn,
4426
+ Mr as PbContainer,
4427
+ Sr as PbImage,
4428
+ dr as PbRow,
4429
+ Ar as PbSection,
4430
+ xr as PbText,
4431
+ Pr as PbVideo,
4432
+ Xe as VIEWPORT_PRESETS,
4433
+ vl as builderOptionsPropType,
4434
+ Or as builtInComponents,
4435
+ fl as clearRegistry,
4436
+ qr as cloneTree,
4437
+ Uo as computeWindowRange,
4438
+ pl as countNodes,
4439
+ Zr as createNode,
4440
+ Ho as createStableNodeKey,
4441
+ In as createTranslator,
4442
+ gl as createVirtualTreeIndexMaps,
4443
+ xn as defaultTranslations,
4444
+ U as findNodeById,
4445
+ ae as findParent,
4446
+ Wo as flattenTree,
4447
+ Le as getComponent,
4448
+ rr as getComponentsByCategory,
4449
+ We as getMaxId,
4450
+ cl as getRegisteredComponents,
4451
+ ul as hasComponent,
4452
+ Tn as insertNode,
4453
+ Jr as interpolateProps,
4454
+ Qn as isPageBuilderError,
4455
+ Fr as mergeTranslations,
4456
+ Xr as moveNode,
4457
+ gn as normalizeSafeHtmlTag,
4458
+ ll as registerComponent,
4459
+ tr as registerComponents,
4460
+ Yr as removeNode,
4461
+ sl as replaceComponent,
4462
+ nr as resolveComponent,
4463
+ mn as sanitizeRichTextHtml,
4464
+ se as sanitizeUrlByKind,
4465
+ ml as sliceWindow,
4466
+ $r as translate,
4467
+ dl as unregisterComponent,
4468
+ wo as useDragDrop,
4469
+ _o as useEditor,
4470
+ yo as useNodeTree,
4471
+ ho as usePageBuilder,
4472
+ pe as usePageBuilderI18n,
4473
+ lt as validateNode,
4474
+ wn as validatePageData,
4475
+ Cn as walkTree
4476
+ };
4477
+ //# sourceMappingURL=index.js.map