@bagelink/blox 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +844 -0
  3. package/components/base/Button.vue +140 -0
  4. package/components/base/Container.vue +64 -0
  5. package/components/base/Image.vue +75 -0
  6. package/components/base/Spacer.vue +33 -0
  7. package/components/base/Text.vue +37 -0
  8. package/components/base/Title.vue +55 -0
  9. package/components/index.ts +20 -0
  10. package/config/baseComponents.ts +342 -0
  11. package/core/communication.ts +140 -0
  12. package/core/registry.ts +108 -0
  13. package/core/renderer.ts +217 -0
  14. package/core/types.ts +148 -0
  15. package/dist/blox.css +296 -0
  16. package/dist/components/base/Button.vue.d.ts +26 -0
  17. package/dist/components/base/Button.vue.d.ts.map +1 -0
  18. package/dist/components/base/Container.vue.d.ts +37 -0
  19. package/dist/components/base/Container.vue.d.ts.map +1 -0
  20. package/dist/components/base/Image.vue.d.ts +26 -0
  21. package/dist/components/base/Image.vue.d.ts.map +1 -0
  22. package/dist/components/base/Spacer.vue.d.ts +16 -0
  23. package/dist/components/base/Spacer.vue.d.ts.map +1 -0
  24. package/dist/components/base/Text.vue.d.ts +13 -0
  25. package/dist/components/base/Text.vue.d.ts.map +1 -0
  26. package/dist/components/base/Title.vue.d.ts +14 -0
  27. package/dist/components/base/Title.vue.d.ts.map +1 -0
  28. package/dist/components/index.d.ts +18 -0
  29. package/dist/components/index.d.ts.map +1 -0
  30. package/dist/config/baseComponents.d.ts +39 -0
  31. package/dist/config/baseComponents.d.ts.map +1 -0
  32. package/dist/core/communication.d.ts +44 -0
  33. package/dist/core/communication.d.ts.map +1 -0
  34. package/dist/core/registry.d.ts +56 -0
  35. package/dist/core/registry.d.ts.map +1 -0
  36. package/dist/core/renderer.d.ts +27 -0
  37. package/dist/core/renderer.d.ts.map +1 -0
  38. package/dist/core/types.d.ts +105 -0
  39. package/dist/core/types.d.ts.map +1 -0
  40. package/dist/index.cjs +1305 -0
  41. package/dist/index.d.ts +16 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.mjs +1260 -0
  44. package/dist/setup.d.ts +24 -0
  45. package/dist/setup.d.ts.map +1 -0
  46. package/dist/utils/normalizer.d.ts +18 -0
  47. package/dist/utils/normalizer.d.ts.map +1 -0
  48. package/dist/utils/styles.d.ts +13 -0
  49. package/dist/utils/styles.d.ts.map +1 -0
  50. package/dist/views/ExternalPreview.vue.d.ts +12 -0
  51. package/dist/views/ExternalPreview.vue.d.ts.map +1 -0
  52. package/dist/views/RenderPage.vue.d.ts +10 -0
  53. package/dist/views/RenderPage.vue.d.ts.map +1 -0
  54. package/dist/vite.config.d.ts +3 -0
  55. package/dist/vite.config.d.ts.map +1 -0
  56. package/index.ts +27 -0
  57. package/package.json +94 -0
  58. package/setup.ts +56 -0
  59. package/utils/normalizer.ts +74 -0
  60. package/utils/styles.ts +228 -0
  61. package/views/ExternalPreview.vue +420 -0
  62. package/views/RenderPage.vue +127 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,1305 @@
1
+ let vue = require("vue");
2
+ var _hoisted_1$4 = [
3
+ "href",
4
+ "target",
5
+ "rel"
6
+ ];
7
+ var Button_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
8
+ __name: "Button",
9
+ props: {
10
+ btnTxt: { default: "Click Me" },
11
+ btnUrl: { default: "#" },
12
+ btnTarget: { default: "_self" },
13
+ variant: { default: "primary" },
14
+ size: { default: "md" },
15
+ align: { default: "left" },
16
+ fullWidth: {
17
+ type: Boolean,
18
+ default: false
19
+ },
20
+ isMobile: { type: Boolean }
21
+ },
22
+ setup(__props) {
23
+ const props = __props;
24
+ function handleClick(e) {
25
+ console.log("Button clicked:", props.btnTxt);
26
+ }
27
+ return (_ctx, _cache) => {
28
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", { class: (0, vue.normalizeClass)(`button-wrapper align-${_ctx.align}`) }, [(0, vue.createElementVNode)("a", {
29
+ href: _ctx.btnUrl,
30
+ target: _ctx.btnTarget,
31
+ rel: _ctx.btnTarget === "_blank" ? "noopener noreferrer" : void 0,
32
+ class: (0, vue.normalizeClass)(["btn", [
33
+ `btn-${_ctx.variant}`,
34
+ `btn-${_ctx.size}`,
35
+ { "btn-full-width": _ctx.fullWidth }
36
+ ]]),
37
+ onClick: handleClick
38
+ }, (0, vue.toDisplayString)(_ctx.btnTxt), 11, _hoisted_1$4)], 2);
39
+ };
40
+ }
41
+ });
42
+ var __plugin_vue_export_helper_default = (sfc, props) => {
43
+ const target = sfc.__vccOpts || sfc;
44
+ for (const [key, val] of props) target[key] = val;
45
+ return target;
46
+ };
47
+ var Button_default = /* @__PURE__ */ __plugin_vue_export_helper_default(Button_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-04e758bb"]]);
48
+ var Container_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
49
+ __name: "Container",
50
+ props: {
51
+ maxWidth: { default: 1200 },
52
+ padding: { default: 20 },
53
+ gap: { default: 16 },
54
+ layout: { default: "vertical" },
55
+ columns: { default: 3 },
56
+ isMobile: { type: Boolean }
57
+ },
58
+ setup(__props) {
59
+ (0, vue.useCssVars)((_ctx) => ({ "6936d1aa": _ctx.columns }));
60
+ const props = __props;
61
+ const containerStyle = {
62
+ maxWidth: typeof props.maxWidth === "number" ? `${props.maxWidth}px` : props.maxWidth,
63
+ padding: typeof props.padding === "number" ? `${props.padding}px` : props.padding,
64
+ gap: `${props.gap}px`
65
+ };
66
+ return (_ctx, _cache) => {
67
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
68
+ class: (0, vue.normalizeClass)(["container", [`layout-${_ctx.layout}`]]),
69
+ style: containerStyle
70
+ }, [(0, vue.renderSlot)(_ctx.$slots, "default", {}, void 0, true)], 2);
71
+ };
72
+ }
73
+ });
74
+ var Container_default = /* @__PURE__ */ __plugin_vue_export_helper_default(Container_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-144084df"]]);
75
+ var _hoisted_1$3 = { class: "image-wrapper" };
76
+ var _hoisted_2$2 = [
77
+ "href",
78
+ "target",
79
+ "rel"
80
+ ];
81
+ var _hoisted_3$2 = ["src", "alt"];
82
+ var _hoisted_4$2 = ["src", "alt"];
83
+ var _hoisted_5$1 = {
84
+ key: 2,
85
+ class: "image-caption"
86
+ };
87
+ var Image_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
88
+ __name: "Image",
89
+ props: {
90
+ src: { default: "" },
91
+ alt: { default: "" },
92
+ caption: { default: "" },
93
+ link: { default: "" },
94
+ linkTarget: { default: "_self" },
95
+ objectFit: { default: "cover" },
96
+ aspectRatio: { default: "auto" },
97
+ isMobile: { type: Boolean }
98
+ },
99
+ setup(__props) {
100
+ const props = __props;
101
+ const imageStyle = {
102
+ objectFit: props.objectFit,
103
+ aspectRatio: props.aspectRatio
104
+ };
105
+ return (_ctx, _cache) => {
106
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("figure", _hoisted_1$3, [_ctx.link ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("a", {
107
+ key: 0,
108
+ href: _ctx.link,
109
+ target: _ctx.linkTarget,
110
+ rel: _ctx.linkTarget === "_blank" ? "noopener noreferrer" : void 0,
111
+ class: "image-link"
112
+ }, [(0, vue.createElementVNode)("img", {
113
+ src: _ctx.src,
114
+ alt: _ctx.alt,
115
+ style: imageStyle,
116
+ class: "image"
117
+ }, null, 8, _hoisted_3$2)], 8, _hoisted_2$2)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", {
118
+ key: 1,
119
+ src: _ctx.src,
120
+ alt: _ctx.alt,
121
+ style: imageStyle,
122
+ class: "image"
123
+ }, null, 8, _hoisted_4$2)), _ctx.caption ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("figcaption", _hoisted_5$1, (0, vue.toDisplayString)(_ctx.caption), 1)) : (0, vue.createCommentVNode)("", true)]);
124
+ };
125
+ }
126
+ });
127
+ var Image_default = /* @__PURE__ */ __plugin_vue_export_helper_default(Image_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-dcfd7570"]]);
128
+ var Spacer_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
129
+ __name: "Spacer",
130
+ props: {
131
+ height: { default: 40 },
132
+ heightMobile: { default: void 0 },
133
+ isMobile: { type: Boolean }
134
+ },
135
+ setup(__props) {
136
+ const props = __props;
137
+ function computedHeight() {
138
+ const h = props.isMobile && props.heightMobile ? props.heightMobile : props.height;
139
+ return typeof h === "number" ? `${h}px` : h;
140
+ }
141
+ return (_ctx, _cache) => {
142
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
143
+ class: "spacer",
144
+ style: (0, vue.normalizeStyle)({ height: computedHeight() })
145
+ }, null, 4);
146
+ };
147
+ }
148
+ });
149
+ var Spacer_default = /* @__PURE__ */ __plugin_vue_export_helper_default(Spacer_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-73a7e941"]]);
150
+ var Text_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
151
+ __name: "Text",
152
+ props: {
153
+ content: { default: "" },
154
+ tag: { default: "div" },
155
+ align: { default: "left" }
156
+ },
157
+ setup(__props) {
158
+ return (_ctx, _cache) => {
159
+ return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(_ctx.tag), {
160
+ class: (0, vue.normalizeClass)(`text-align-${_ctx.align}`),
161
+ innerHTML: _ctx.content
162
+ }, null, 8, ["class", "innerHTML"]);
163
+ };
164
+ }
165
+ });
166
+ var Text_default = /* @__PURE__ */ __plugin_vue_export_helper_default(Text_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-a6173468"]]);
167
+ var _hoisted_1$2 = {
168
+ key: 1,
169
+ class: "subtitle"
170
+ };
171
+ var Title_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
172
+ __name: "Title",
173
+ props: {
174
+ title: { default: "" },
175
+ subTitle: { default: "" },
176
+ tag: { default: "h2" },
177
+ align: { default: "left" }
178
+ },
179
+ setup(__props) {
180
+ return (_ctx, _cache) => {
181
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", { class: (0, vue.normalizeClass)(`title-wrapper text-align-${_ctx.align}`) }, [_ctx.title ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(_ctx.tag), {
182
+ key: 0,
183
+ class: "title"
184
+ }, {
185
+ default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)(_ctx.title), 1)]),
186
+ _: 1
187
+ })) : (0, vue.createCommentVNode)("", true), _ctx.subTitle ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_1$2, (0, vue.toDisplayString)(_ctx.subTitle), 1)) : (0, vue.createCommentVNode)("", true)], 2);
188
+ };
189
+ }
190
+ });
191
+ var Title_default = /* @__PURE__ */ __plugin_vue_export_helper_default(Title_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-ae0634d1"]]);
192
+ const baseComponentConfigs = [
193
+ {
194
+ id: "Text",
195
+ label: "Text",
196
+ icon: "text_fields",
197
+ order: 10,
198
+ component: Text_default,
199
+ content: [{
200
+ type: "richtext",
201
+ key: "content",
202
+ label: "Content",
203
+ defaultValue: "<p>Enter your text here...</p>",
204
+ height: 200
205
+ }],
206
+ settings: [{
207
+ type: "select",
208
+ key: "tag",
209
+ label: "HTML Tag",
210
+ defaultValue: "div",
211
+ options: [
212
+ {
213
+ label: "Div",
214
+ value: "div"
215
+ },
216
+ {
217
+ label: "Paragraph",
218
+ value: "p"
219
+ },
220
+ {
221
+ label: "Span",
222
+ value: "span"
223
+ },
224
+ {
225
+ label: "Article",
226
+ value: "article"
227
+ },
228
+ {
229
+ label: "Section",
230
+ value: "section"
231
+ }
232
+ ]
233
+ }, {
234
+ type: "select",
235
+ key: "align",
236
+ label: "Text Alignment",
237
+ defaultValue: "left",
238
+ options: [
239
+ {
240
+ label: "Left",
241
+ value: "left"
242
+ },
243
+ {
244
+ label: "Center",
245
+ value: "center"
246
+ },
247
+ {
248
+ label: "Right",
249
+ value: "right"
250
+ },
251
+ {
252
+ label: "Justify",
253
+ value: "justify"
254
+ }
255
+ ]
256
+ }]
257
+ },
258
+ {
259
+ id: "Title",
260
+ label: "Title",
261
+ icon: "title",
262
+ order: 5,
263
+ component: Title_default,
264
+ content: [{
265
+ type: "text",
266
+ key: "title",
267
+ label: "Title",
268
+ defaultValue: "Your Title Here"
269
+ }, {
270
+ type: "text",
271
+ key: "subtitle",
272
+ label: "Subtitle",
273
+ defaultValue: ""
274
+ }],
275
+ settings: [
276
+ {
277
+ type: "select",
278
+ key: "tag",
279
+ label: "Heading Tag",
280
+ defaultValue: "h2",
281
+ options: [
282
+ {
283
+ label: "H1",
284
+ value: "h1"
285
+ },
286
+ {
287
+ label: "H2",
288
+ value: "h2"
289
+ },
290
+ {
291
+ label: "H3",
292
+ value: "h3"
293
+ },
294
+ {
295
+ label: "H4",
296
+ value: "h4"
297
+ },
298
+ {
299
+ label: "H5",
300
+ value: "h5"
301
+ },
302
+ {
303
+ label: "H6",
304
+ value: "h6"
305
+ }
306
+ ]
307
+ },
308
+ {
309
+ type: "select",
310
+ key: "align",
311
+ label: "Text Alignment",
312
+ defaultValue: "center",
313
+ options: [
314
+ {
315
+ label: "Left",
316
+ value: "left"
317
+ },
318
+ {
319
+ label: "Center",
320
+ value: "center"
321
+ },
322
+ {
323
+ label: "Right",
324
+ value: "right"
325
+ }
326
+ ]
327
+ },
328
+ {
329
+ type: "number",
330
+ key: "size",
331
+ label: "Font Size (px)",
332
+ defaultValue: 32
333
+ }
334
+ ]
335
+ },
336
+ {
337
+ id: "Button",
338
+ label: "Button",
339
+ icon: "smart_button",
340
+ order: 15,
341
+ component: Button_default,
342
+ content: [{
343
+ type: "text",
344
+ key: "btnTxt",
345
+ label: "Button Text",
346
+ defaultValue: "Click Me"
347
+ }, {
348
+ type: "text",
349
+ key: "btnUrl",
350
+ label: "Button URL",
351
+ defaultValue: "#"
352
+ }],
353
+ settings: [
354
+ {
355
+ type: "select",
356
+ key: "variant",
357
+ label: "Button Style",
358
+ defaultValue: "primary",
359
+ options: [
360
+ {
361
+ label: "Primary",
362
+ value: "primary"
363
+ },
364
+ {
365
+ label: "Secondary",
366
+ value: "secondary"
367
+ },
368
+ {
369
+ label: "Outline",
370
+ value: "outline"
371
+ },
372
+ {
373
+ label: "Ghost",
374
+ value: "ghost"
375
+ }
376
+ ]
377
+ },
378
+ {
379
+ type: "select",
380
+ key: "size",
381
+ label: "Size",
382
+ defaultValue: "md",
383
+ options: [
384
+ {
385
+ label: "Small",
386
+ value: "sm"
387
+ },
388
+ {
389
+ label: "Medium",
390
+ value: "md"
391
+ },
392
+ {
393
+ label: "Large",
394
+ value: "lg"
395
+ }
396
+ ]
397
+ },
398
+ {
399
+ type: "select",
400
+ key: "align",
401
+ label: "Alignment",
402
+ defaultValue: "left",
403
+ options: [
404
+ {
405
+ label: "Left",
406
+ value: "left"
407
+ },
408
+ {
409
+ label: "Center",
410
+ value: "center"
411
+ },
412
+ {
413
+ label: "Right",
414
+ value: "right"
415
+ }
416
+ ]
417
+ },
418
+ {
419
+ type: "checkbox",
420
+ key: "fullWidth",
421
+ label: "Full Width",
422
+ defaultValue: false
423
+ },
424
+ {
425
+ type: "select",
426
+ key: "btnTarget",
427
+ label: "Link Target",
428
+ defaultValue: "_self",
429
+ options: [{
430
+ label: "Same Window",
431
+ value: "_self"
432
+ }, {
433
+ label: "New Window",
434
+ value: "_blank"
435
+ }]
436
+ }
437
+ ]
438
+ },
439
+ {
440
+ id: "Image",
441
+ label: "Image",
442
+ icon: "image",
443
+ order: 20,
444
+ component: Image_default,
445
+ content: [{
446
+ type: "upload",
447
+ key: "src",
448
+ label: "Image",
449
+ defaultValue: "",
450
+ height: 200
451
+ }, {
452
+ type: "text",
453
+ key: "alt",
454
+ label: "Alt Text",
455
+ defaultValue: ""
456
+ }],
457
+ settings: [
458
+ {
459
+ type: "select",
460
+ key: "objectFit",
461
+ label: "Object Fit",
462
+ defaultValue: "cover",
463
+ options: [
464
+ {
465
+ label: "Cover",
466
+ value: "cover"
467
+ },
468
+ {
469
+ label: "Contain",
470
+ value: "contain"
471
+ },
472
+ {
473
+ label: "Fill",
474
+ value: "fill"
475
+ },
476
+ {
477
+ label: "None",
478
+ value: "none"
479
+ },
480
+ {
481
+ label: "Scale Down",
482
+ value: "scale-down"
483
+ }
484
+ ]
485
+ },
486
+ {
487
+ type: "number",
488
+ key: "maxWidth",
489
+ label: "Max Width (px)",
490
+ defaultValue: null
491
+ },
492
+ {
493
+ type: "number",
494
+ key: "height",
495
+ label: "Height (px)",
496
+ defaultValue: null
497
+ },
498
+ {
499
+ type: "select",
500
+ key: "align",
501
+ label: "Alignment",
502
+ defaultValue: "center",
503
+ options: [
504
+ {
505
+ label: "Left",
506
+ value: "left"
507
+ },
508
+ {
509
+ label: "Center",
510
+ value: "center"
511
+ },
512
+ {
513
+ label: "Right",
514
+ value: "right"
515
+ }
516
+ ]
517
+ }
518
+ ]
519
+ },
520
+ {
521
+ id: "Spacer",
522
+ label: "Spacer",
523
+ icon: "height",
524
+ order: 25,
525
+ component: Spacer_default,
526
+ content: [],
527
+ settings: [{
528
+ type: "number",
529
+ key: "height",
530
+ label: "Height (px)",
531
+ defaultValue: 40
532
+ }]
533
+ },
534
+ {
535
+ id: "Container",
536
+ label: "Container",
537
+ icon: "view_module",
538
+ order: 30,
539
+ component: Container_default,
540
+ content: [{
541
+ type: "richtext",
542
+ key: "content",
543
+ label: "Content",
544
+ defaultValue: "<p>Container content...</p>",
545
+ height: 200
546
+ }],
547
+ settings: [{
548
+ type: "select",
549
+ key: "maxWidth",
550
+ label: "Max Width",
551
+ defaultValue: "lg",
552
+ options: [
553
+ {
554
+ label: "Small (640px)",
555
+ value: "sm"
556
+ },
557
+ {
558
+ label: "Medium (768px)",
559
+ value: "md"
560
+ },
561
+ {
562
+ label: "Large (1024px)",
563
+ value: "lg"
564
+ },
565
+ {
566
+ label: "Extra Large (1280px)",
567
+ value: "xl"
568
+ },
569
+ {
570
+ label: "Full Width",
571
+ value: "full"
572
+ }
573
+ ]
574
+ }, {
575
+ type: "checkbox",
576
+ key: "centered",
577
+ label: "Center Content",
578
+ defaultValue: true
579
+ }]
580
+ }
581
+ ];
582
+ function getBaseComponentConfigs() {
583
+ return baseComponentConfigs;
584
+ }
585
+ function getBaseComponentConfig(id) {
586
+ return baseComponentConfigs.find((config) => config.id === id);
587
+ }
588
+ var CommunicationBridge = class {
589
+ origin;
590
+ targetWindow;
591
+ handlers;
592
+ boundMessageHandler;
593
+ constructor(config) {
594
+ this.origin = config.origin;
595
+ this.targetWindow = config.targetWindow || window.parent;
596
+ this.handlers = /* @__PURE__ */ new Map();
597
+ this.boundMessageHandler = this.handleMessage.bind(this);
598
+ window.addEventListener("message", this.boundMessageHandler);
599
+ console.log(`🌉 Communication bridge initialized for origin: ${this.origin}`);
600
+ }
601
+ handleMessage(event) {
602
+ if (this.origin !== "*" && event.origin !== this.origin) {
603
+ console.warn(`⚠️ Rejected message from unauthorized origin: ${event.origin}`);
604
+ return;
605
+ }
606
+ const { type, message, data, isMobile } = event.data;
607
+ if (!type) return;
608
+ console.log(`📨 Received message: ${type}`, {
609
+ message,
610
+ data,
611
+ isMobile
612
+ });
613
+ const typeHandlers = this.handlers.get(type);
614
+ if (typeHandlers) typeHandlers.forEach((handler) => {
615
+ try {
616
+ handler({
617
+ type,
618
+ message,
619
+ data,
620
+ isMobile
621
+ });
622
+ } catch (error) {
623
+ console.error(`Error in handler for ${type}:`, error);
624
+ }
625
+ });
626
+ const globalHandlers = this.handlers.get("*");
627
+ if (globalHandlers) globalHandlers.forEach((handler) => {
628
+ try {
629
+ handler({
630
+ type,
631
+ message,
632
+ data,
633
+ isMobile
634
+ });
635
+ } catch (error) {
636
+ console.error("Error in global handler:", error);
637
+ }
638
+ });
639
+ }
640
+ on(type, handler) {
641
+ if (!this.handlers.has(type)) this.handlers.set(type, /* @__PURE__ */ new Set());
642
+ this.handlers.get(type).add(handler);
643
+ return () => {
644
+ this.off(type, handler);
645
+ };
646
+ }
647
+ off(type, handler) {
648
+ const typeHandlers = this.handlers.get(type);
649
+ if (typeHandlers) typeHandlers.delete(handler);
650
+ }
651
+ send(type, message, data) {
652
+ const payload = {
653
+ type,
654
+ message,
655
+ data
656
+ };
657
+ this.targetWindow.postMessage(payload, this.origin === "*" ? "*" : this.origin);
658
+ console.log(`📤 Sent message: ${type}`, payload);
659
+ }
660
+ destroy() {
661
+ window.removeEventListener("message", this.boundMessageHandler);
662
+ this.handlers.clear();
663
+ console.log("🧹 Communication bridge destroyed");
664
+ }
665
+ };
666
+ function createCommunicationBridge(config) {
667
+ return new CommunicationBridge(config);
668
+ }
669
+ function sendMessage(type, message, targetWindow = window.parent, origin = "*") {
670
+ const payload = {
671
+ type,
672
+ message
673
+ };
674
+ targetWindow.postMessage(payload, origin);
675
+ }
676
+ var registry = {};
677
+ function registerComponent(type, component) {
678
+ if (registry[type]) console.warn(`Component "${type}" is already registered. Overwriting...`);
679
+ registry[type] = component;
680
+ console.log(`✅ Registered component: ${type}`);
681
+ }
682
+ function registerComponents(components) {
683
+ Object.entries(components).forEach(([type, component]) => {
684
+ registerComponent(type, component);
685
+ });
686
+ }
687
+ function getComponent(type) {
688
+ return registry[type];
689
+ }
690
+ function hasComponent(type) {
691
+ return type in registry;
692
+ }
693
+ function getAllComponents() {
694
+ return { ...registry };
695
+ }
696
+ function unregisterComponent(type) {
697
+ delete registry[type];
698
+ console.log(`❌ Unregistered component: ${type}`);
699
+ }
700
+ function clearRegistry() {
701
+ Object.keys(registry).forEach((key) => delete registry[key]);
702
+ console.log("🗑️ Registry cleared");
703
+ }
704
+ function getRegisteredTypes() {
705
+ return Object.keys(registry);
706
+ }
707
+ function createNamespacedRegistry(namespace) {
708
+ const namespacedRegistry = {};
709
+ return {
710
+ register: (type, component) => {
711
+ const key = `${namespace}:${type}`;
712
+ namespacedRegistry[key] = component;
713
+ registry[key] = component;
714
+ },
715
+ get: (type) => {
716
+ return namespacedRegistry[`${namespace}:${type}`];
717
+ },
718
+ getAll: () => ({ ...namespacedRegistry })
719
+ };
720
+ }
721
+ function generateBlockStyles(data, isMobile = false) {
722
+ const styles = {};
723
+ function toNumber(v) {
724
+ if (v === void 0 || v === null || v === "") return null;
725
+ const n = Number(v);
726
+ return Number.isNaN(n) ? null : n;
727
+ }
728
+ function getValue(desktopKey, mobileKey) {
729
+ if (isMobile && data[mobileKey] !== void 0 && data[mobileKey] !== null) return data[mobileKey];
730
+ return data[desktopKey];
731
+ }
732
+ const mTop = toNumber(getValue("marginTop", "marginTopMobile"));
733
+ const mBottom = toNumber(getValue("marginBottom", "marginBottomMobile"));
734
+ const pad = toNumber(getValue("padding", "paddingMobile"));
735
+ if (mTop !== null) {
736
+ styles["margin-top"] = `${mTop}rem`;
737
+ styles["--margin-top"] = `${mTop}rem`;
738
+ } else styles["--margin-top"] = "0rem";
739
+ if (mBottom !== null) {
740
+ styles["margin-bottom"] = `${mBottom}rem`;
741
+ styles["--margin-bottom"] = `${mBottom}rem`;
742
+ } else styles["--margin-bottom"] = "0rem";
743
+ if (pad !== null) {
744
+ styles.padding = `${pad}rem`;
745
+ styles["--block-padding"] = `${pad}rem`;
746
+ }
747
+ const wDesktop = toNumber(data.width);
748
+ const wMobile = toNumber(data.widthMobile);
749
+ const wPercentDesktop = toNumber(data.widthPercent) || 96;
750
+ const wPercentMobile = toNumber(data.widthPercentMobile) || wPercentDesktop;
751
+ const fullWidthDesktop = data.fullWidth;
752
+ styles["--max-width-desktop"] = wDesktop !== null ? `${wDesktop}px` : "800px";
753
+ styles["--max-width-mobile"] = wMobile !== null ? `${wMobile}px` : wDesktop !== null ? `${wDesktop}px` : "800px";
754
+ styles["--width-percent-desktop"] = `${wPercentDesktop}%`;
755
+ styles["--width-percent-mobile"] = `${wPercentMobile}%`;
756
+ if (!(fullWidthDesktop === true || fullWidthDesktop === "true") && wDesktop !== null) {
757
+ styles["margin-left"] = "auto";
758
+ styles["margin-right"] = "auto";
759
+ }
760
+ const borderW = toNumber(getValue("borderWidth", "borderWidthMobile"));
761
+ if (borderW !== null && borderW > 0) {
762
+ styles["border-width"] = `${borderW}px`;
763
+ styles["border-style"] = getValue("borderStyle", "borderStyleMobile") || "solid";
764
+ const borderColor = getValue("borderColor", "borderColorMobile");
765
+ if (borderColor) styles["border-color"] = borderColor;
766
+ }
767
+ const isCenter = getValue("center", "centerMobile");
768
+ if (isCenter === true || isCenter === "true") styles["text-align"] = "center";
769
+ const borderR = toNumber(getValue("borderRadius", "borderRadiusMobile"));
770
+ if (borderR !== null) styles["border-radius"] = `${borderR}px`;
771
+ const bgColorDesktop = data.backgroundColor;
772
+ const bgColorMobile = data.backgroundColorMobile;
773
+ const textColorDesktop = data.textColor;
774
+ const { textColorMobile } = data;
775
+ if (bgColorDesktop) styles["--bg-color-desktop"] = bgColorDesktop;
776
+ if (bgColorMobile) styles["--bg-color-mobile"] = bgColorMobile;
777
+ if (textColorDesktop) styles["--text-color-desktop"] = textColorDesktop;
778
+ if (textColorMobile) styles["--text-color-mobile"] = textColorMobile;
779
+ const shadowMap = {
780
+ none: "none",
781
+ sm: "0 0 10px 0 rgba(0, 0, 0, 0.05)",
782
+ md: "0 0 20px 0 rgba(0, 0, 0, 0.15)",
783
+ lg: "0 0 30px 0 rgba(0, 0, 0, 0.15)",
784
+ xl: "0 0 40px 0 rgba(0, 0, 0, 0.5)",
785
+ custom: "0 4px 6px -1px rgba(0, 0, 0, 0.15)"
786
+ };
787
+ const shadowType = getValue("shadowType", "shadowTypeMobile");
788
+ if (shadowType && shadowType !== "none") styles["box-shadow"] = shadowMap[shadowType] || shadowMap.md;
789
+ const z = toNumber(getValue("zIndex", "zIndexMobile"));
790
+ if (z !== null && z > 0) {
791
+ styles.position = "relative";
792
+ styles["z-index"] = z.toString();
793
+ }
794
+ if (!isMobile && data.showDesktop === false) styles.display = "none";
795
+ else if (isMobile && data.showMobile === false) styles.display = "none";
796
+ const fontFamilyDesktop = data.fontFamily;
797
+ const { fontFamilyMobile } = data;
798
+ if (isMobile && fontFamilyMobile && fontFamilyMobile.trim() !== "") styles["font-family"] = `"${fontFamilyMobile}", sans-serif`;
799
+ else if (fontFamilyDesktop && fontFamilyDesktop.trim() !== "") styles["font-family"] = `"${fontFamilyDesktop}", sans-serif`;
800
+ if (data.customCSS) try {
801
+ data.customCSS.split(";").filter((rule) => rule.trim()).map((rule) => rule.trim().split(":")).filter((parts) => parts.length === 2).forEach(([property, value]) => {
802
+ const prop = property.trim();
803
+ const val = value.trim();
804
+ if (prop && val) styles[prop] = val;
805
+ });
806
+ } catch (e) {
807
+ console.warn("Invalid custom CSS:", data.customCSS);
808
+ }
809
+ return styles;
810
+ }
811
+ function getResponsiveClasses(data) {
812
+ const classes = ["blox-block", "responsive-colors"];
813
+ const effectiveDesktopFullWidth = Boolean(data.fullWidth);
814
+ const effectiveMobileFullWidth = data.fullWidthMobile !== null ? Boolean(data.fullWidthMobile) : effectiveDesktopFullWidth;
815
+ if (effectiveDesktopFullWidth) classes.push("full-width-desktop");
816
+ if (effectiveMobileFullWidth) classes.push("full-width-mobile");
817
+ return classes;
818
+ }
819
+ function getResponsiveCSS() {
820
+ return `
821
+ /* Blox Responsive System */
822
+ .responsive-colors {
823
+ color: var(--text-color-desktop, inherit);
824
+ background-color: var(--bg-color-desktop, transparent);
825
+ margin-inline: auto;
826
+ max-width: var(--max-width-desktop, 800px);
827
+ width: var(--width-percent-desktop, 96%);
828
+ }
829
+
830
+ .responsive-colors.full-width-desktop {
831
+ width: 100% !important;
832
+ max-width: none !important;
833
+ }
834
+
835
+ @media (max-width: 910px) {
836
+ .responsive-colors {
837
+ color: var(--text-color-mobile, var(--text-color-desktop, inherit));
838
+ background-color: var(--bg-color-mobile, var(--bg-color-desktop, transparent));
839
+ max-width: var(--max-width-mobile, var(--max-width-desktop, 800px));
840
+ width: var(--width-percent-mobile, var(--width-percent-desktop, 96%));
841
+ }
842
+
843
+ .responsive-colors.full-width-mobile {
844
+ width: 100% !important;
845
+ max-width: none !important;
846
+ }
847
+ }
848
+ `;
849
+ }
850
+ function injectResponsiveCSS() {
851
+ if (document.getElementById("blox-responsive-css")) return;
852
+ const style = document.createElement("style");
853
+ style.id = "blox-responsive-css";
854
+ style.textContent = getResponsiveCSS();
855
+ document.head.appendChild(style);
856
+ }
857
+ function injectCode(code, target) {
858
+ if (!code) return;
859
+ const element = document.querySelector(target);
860
+ if (element) {
861
+ const div = document.createElement("div");
862
+ div.innerHTML = code;
863
+ element.appendChild(div);
864
+ }
865
+ }
866
+ var loadedFonts = /* @__PURE__ */ new Set();
867
+ function loadGoogleFont(fontName) {
868
+ if (!fontName || loadedFonts.has(fontName)) return Promise.resolve();
869
+ return new Promise((resolve, reject) => {
870
+ const fontUrl = `https://fonts.googleapis.com/css2?family=${fontName.trim().replace(/\s+/g, "+")}:wght@400;500;600;700&display=swap`;
871
+ const linkElement = document.createElement("link");
872
+ linkElement.rel = "stylesheet";
873
+ linkElement.href = fontUrl;
874
+ linkElement.setAttribute("data-font-name", fontName);
875
+ linkElement.onload = () => {
876
+ console.log(`✅ Font loaded: ${fontName}`);
877
+ loadedFonts.add(fontName);
878
+ resolve();
879
+ };
880
+ linkElement.onerror = () => {
881
+ console.error(`❌ Failed to load font: ${fontName}`);
882
+ reject(/* @__PURE__ */ new Error(`Failed to load font: ${fontName}`));
883
+ };
884
+ document.head.appendChild(linkElement);
885
+ });
886
+ }
887
+ async function loadComponentFonts(components) {
888
+ const fontsToLoad = /* @__PURE__ */ new Set();
889
+ components.forEach((comp) => {
890
+ if (comp.data?.fontFamily) fontsToLoad.add(comp.data.fontFamily);
891
+ if (comp.data?.fontFamilyMobile) fontsToLoad.add(comp.data.fontFamilyMobile);
892
+ });
893
+ await Promise.all(Array.from(fontsToLoad).map((font) => loadGoogleFont(font)));
894
+ }
895
+ function applyGlobalFont(fontName) {
896
+ if (!fontName) return;
897
+ const existingStyle = document.getElementById("blox-global-font");
898
+ if (existingStyle) existingStyle.remove();
899
+ const style = document.createElement("style");
900
+ style.id = "blox-global-font";
901
+ style.textContent = `
902
+ body {
903
+ font-family: "${fontName}", sans-serif;
904
+ }
905
+ .blox-page-wrapper {
906
+ font-family: "${fontName}", sans-serif !important;
907
+ }
908
+ .blox-page-wrapper * {
909
+ font-family: inherit;
910
+ }
911
+ `;
912
+ document.head.appendChild(style);
913
+ loadGoogleFont(fontName);
914
+ }
915
+ function applyPageSettings(pageData) {
916
+ const { pageSettings } = pageData;
917
+ if (!pageSettings) return;
918
+ if (pageSettings.pageLanguage) document.documentElement.lang = pageSettings.pageLanguage;
919
+ if (pageSettings.pageDirection) {
920
+ document.documentElement.dir = pageSettings.pageDirection;
921
+ document.body.dir = pageSettings.pageDirection;
922
+ }
923
+ if (pageSettings.selectedGoogleFont) applyGlobalFont(pageSettings.selectedGoogleFont);
924
+ injectCode(pageSettings.additionalHeadCode, "head");
925
+ injectCode(pageSettings.additionalBodyCode, "body");
926
+ if (pageSettings.customFavicon) {
927
+ let faviconLink = document.querySelector("link[rel=\"icon\"]");
928
+ if (!faviconLink) {
929
+ faviconLink = document.createElement("link");
930
+ faviconLink.rel = "icon";
931
+ document.head.appendChild(faviconLink);
932
+ }
933
+ faviconLink.href = pageSettings.customFavicon;
934
+ }
935
+ applyMetaTags(pageSettings);
936
+ }
937
+ function applyMetaTags(settings) {
938
+ if (settings.customOgImage) updateOrCreateMeta("og:image", settings.customOgImage, "property");
939
+ if (settings.customKeywords) updateOrCreateMeta("keywords", settings.customKeywords);
940
+ if (settings.customRobotsMeta) updateOrCreateMeta("robots", settings.customRobotsMeta);
941
+ }
942
+ function updateOrCreateMeta(name, content, attribute = "name") {
943
+ const selector = `meta[${attribute}="${name}"]`;
944
+ let metaTag = document.querySelector(selector);
945
+ if (!metaTag) {
946
+ metaTag = document.createElement("meta");
947
+ metaTag.setAttribute(attribute, name);
948
+ document.head.appendChild(metaTag);
949
+ }
950
+ metaTag.content = content;
951
+ }
952
+ async function initializePage(pageData) {
953
+ injectResponsiveCSS();
954
+ applyPageSettings(pageData);
955
+ await loadComponentFonts(pageData.components);
956
+ injectCode(pageData.header_code, "head");
957
+ injectCode(pageData.body_code, "body");
958
+ }
959
+ function registerBaseComponents() {
960
+ const componentMap = {};
961
+ baseComponentConfigs.forEach((config) => {
962
+ componentMap[config.id] = config.component;
963
+ });
964
+ registerComponents(componentMap);
965
+ console.log("✅ Registered base components:", Object.keys(componentMap));
966
+ }
967
+ function getAllComponentConfigs(customConfigs = []) {
968
+ return [...baseComponentConfigs, ...customConfigs];
969
+ }
970
+ function normalizeComponentData(data) {
971
+ const normalized = {};
972
+ const stringFields = [
973
+ "title",
974
+ "subTitle",
975
+ "btnTxt",
976
+ "tag",
977
+ "customId",
978
+ "height",
979
+ "url",
980
+ "href"
981
+ ];
982
+ for (const [key, value] of Object.entries(data)) if (typeof value === "string") if (value === "true") normalized[key] = true;
983
+ else if (value === "false") normalized[key] = false;
984
+ else if (!Number.isNaN(Number(value)) && value !== "" && !stringFields.includes(key)) normalized[key] = Number(value);
985
+ else normalized[key] = value;
986
+ else normalized[key] = value;
987
+ if (!normalized.items) normalized.items = [];
988
+ if (normalized.height !== void 0 && typeof normalized.height === "number") normalized.height = String(normalized.height);
989
+ if (normalized.height === "auto") delete normalized.height;
990
+ return normalized;
991
+ }
992
+ function deepClone(obj) {
993
+ return JSON.parse(JSON.stringify(obj));
994
+ }
995
+ function deepMerge(target, source) {
996
+ const result = { ...target };
997
+ for (const key in source) if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) result[key] = deepMerge(result[key] || {}, source[key]);
998
+ else result[key] = source[key];
999
+ return result;
1000
+ }
1001
+ var _hoisted_1$1 = { class: "blox-page-wrapper" };
1002
+ var _hoisted_2$1 = {
1003
+ key: 0,
1004
+ class: "blox-loading"
1005
+ };
1006
+ var _hoisted_3$1 = {
1007
+ key: 1,
1008
+ class: "blox-empty-state"
1009
+ };
1010
+ var _hoisted_4$1 = {
1011
+ key: 2,
1012
+ class: "blox-empty-preview"
1013
+ };
1014
+ var _hoisted_5 = [
1015
+ "data-block-id",
1016
+ "onClick",
1017
+ "onMouseenter",
1018
+ "onFocus"
1019
+ ];
1020
+ var _hoisted_6 = {
1021
+ key: 0,
1022
+ class: "blox-block-label"
1023
+ };
1024
+ var _hoisted_7 = { key: 0 };
1025
+ var _hoisted_8 = ["id"];
1026
+ var _hoisted_9 = {
1027
+ key: 1,
1028
+ class: "blox-missing-component"
1029
+ };
1030
+ var _hoisted_10 = ["onClick"];
1031
+ var ExternalPreview_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
1032
+ __name: "ExternalPreview",
1033
+ props: {
1034
+ origin: { default: "*" },
1035
+ initialPageData: {},
1036
+ componentConfigs: { default: () => [] }
1037
+ },
1038
+ setup(__props) {
1039
+ const props = __props;
1040
+ const components = (0, vue.ref)([]);
1041
+ const highlightID = (0, vue.ref)("");
1042
+ const selectedID = (0, vue.ref)("");
1043
+ const isMobile = (0, vue.ref)(false);
1044
+ const previewMode = (0, vue.ref)(false);
1045
+ const linksDisabled = (0, vue.ref)(false);
1046
+ const loading = (0, vue.ref)(true);
1047
+ const updateCounter = (0, vue.ref)(0);
1048
+ let bridge = null;
1049
+ const registeredComponents = getAllComponents();
1050
+ const getBlockStyles = (0, vue.computed)(() => {
1051
+ updateCounter.value;
1052
+ return (data, mobile = false) => generateBlockStyles(data, mobile);
1053
+ });
1054
+ function setFocus(id, emit = false) {
1055
+ selectedID.value = id;
1056
+ highlightID.value = id;
1057
+ document.querySelector(`[data-block-id="${id}"]`)?.scrollIntoView({
1058
+ behavior: "smooth",
1059
+ block: "center"
1060
+ });
1061
+ if (emit && bridge) bridge.send("focus", id);
1062
+ }
1063
+ function setHighlight(id, emit = false) {
1064
+ highlightID.value = id;
1065
+ if (emit && bridge) bridge.send("highlight", id);
1066
+ }
1067
+ function keyboardHandler(event) {
1068
+ if (previewMode.value) return;
1069
+ if (event.key === "ArrowDown") {
1070
+ const next = components.value.findIndex((comp) => comp.id === highlightID.value) + 1;
1071
+ if (next < components.value.length) setFocus(components.value[next].id, true);
1072
+ } else if (event.key === "ArrowUp") {
1073
+ const prev = components.value.findIndex((comp) => comp.id === highlightID.value) - 1;
1074
+ if (prev >= 0) setFocus(components.value[prev].id, true);
1075
+ } else if (event.key === "Enter") {
1076
+ if (bridge) bridge.send("focus", highlightID.value);
1077
+ } else if (event.key === "Escape") {
1078
+ setHighlight("");
1079
+ selectedID.value = "";
1080
+ } else if (event.key === "Delete") {
1081
+ if (bridge) bridge.send("delete", highlightID.value);
1082
+ }
1083
+ }
1084
+ function clickHandler(event) {
1085
+ if (!linksDisabled.value) return;
1086
+ let element = event.target;
1087
+ while (element) {
1088
+ if (element.tagName === "A" && element.getAttribute("href")) if (!(element.classList.contains("btn") || element.classList.contains("button") || element.getAttribute("role") === "button")) {
1089
+ event.preventDefault();
1090
+ event.stopPropagation();
1091
+ return false;
1092
+ } else {
1093
+ event.preventDefault();
1094
+ return false;
1095
+ }
1096
+ element = element.parentElement;
1097
+ }
1098
+ }
1099
+ function setupBridge() {
1100
+ bridge = createCommunicationBridge({
1101
+ origin: props.origin,
1102
+ targetWindow: window.parent
1103
+ });
1104
+ bridge.on("update", ({ message, data, isMobile: mobile }) => {
1105
+ const componentData = message?.data || data;
1106
+ const mobileMode = message?.isMobile !== void 0 ? message.isMobile : mobile;
1107
+ if (componentData) {
1108
+ components.value = [...componentData];
1109
+ updateCounter.value++;
1110
+ console.log("📦 Updated components:", components.value.length);
1111
+ }
1112
+ if (mobileMode !== void 0) {
1113
+ isMobile.value = mobileMode;
1114
+ console.log("📱 Mobile mode:", mobileMode);
1115
+ }
1116
+ loading.value = false;
1117
+ });
1118
+ bridge.on("highlight", ({ message }) => {
1119
+ setHighlight(message);
1120
+ });
1121
+ bridge.on("focus", ({ message }) => {
1122
+ setFocus(message);
1123
+ });
1124
+ bridge.on("preview", ({ message }) => {
1125
+ previewMode.value = message;
1126
+ if (previewMode.value) {
1127
+ document.body.classList.add("blox-preview-mode");
1128
+ document.body.classList.remove("blox-edit-mode");
1129
+ } else {
1130
+ document.body.classList.remove("blox-preview-mode");
1131
+ document.body.classList.add("blox-edit-mode");
1132
+ }
1133
+ });
1134
+ bridge.on("disableLinks", ({ message }) => {
1135
+ linksDisabled.value = message;
1136
+ });
1137
+ const registeredTypes = Object.keys(registeredComponents);
1138
+ const configsToSend = props.componentConfigs.map((config) => ({
1139
+ id: config.id,
1140
+ label: config.label,
1141
+ icon: config.icon,
1142
+ img: config.img,
1143
+ order: config.order || 999,
1144
+ content: config.content || [],
1145
+ settings: config.settings || []
1146
+ }));
1147
+ bridge.send("ready", {
1148
+ registeredTypes,
1149
+ componentConfigs: configsToSend
1150
+ });
1151
+ console.log("📤 Sent component configurations:", configsToSend);
1152
+ }
1153
+ (0, vue.onMounted)(async () => {
1154
+ console.log("🚀 External Preview mounted");
1155
+ console.log("📦 Registered components:", Object.keys(registeredComponents));
1156
+ setupBridge();
1157
+ window.addEventListener("keydown", keyboardHandler);
1158
+ document.addEventListener("click", clickHandler, true);
1159
+ document.body.classList.add("blox-edit-mode");
1160
+ if (props.initialPageData) {
1161
+ await initializePage(props.initialPageData);
1162
+ components.value = props.initialPageData.components;
1163
+ loading.value = false;
1164
+ }
1165
+ });
1166
+ (0, vue.onUnmounted)(() => {
1167
+ if (bridge) bridge.destroy();
1168
+ window.removeEventListener("keydown", keyboardHandler);
1169
+ document.removeEventListener("click", clickHandler, true);
1170
+ document.body.classList.remove("blox-preview-mode", "blox-edit-mode");
1171
+ });
1172
+ return (_ctx, _cache) => {
1173
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$1, [loading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2$1, _cache[0] || (_cache[0] = [(0, vue.createElementVNode)("p", null, "Loading preview...", -1)]))) : !components.value.length && !previewMode.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_3$1, _cache[1] || (_cache[1] = [(0, vue.createElementVNode)("p", null, "No blocks yet. Add a block from the editor to get started!", -1)]))) : !components.value.length && previewMode.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_4$1)) : (0, vue.createCommentVNode)("", true), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(components.value, (comp) => {
1174
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
1175
+ key: comp.id,
1176
+ class: (0, vue.normalizeClass)(["blox-block-wrapper", {
1177
+ "blox-highlight": !previewMode.value && highlightID.value === comp.id,
1178
+ "blox-selected": !previewMode.value && selectedID.value === comp.id
1179
+ }]),
1180
+ "data-block-id": comp.id,
1181
+ onClick: ($event) => !previewMode.value ? setFocus(comp.id, true) : null,
1182
+ onMouseenter: ($event) => !previewMode.value ? setHighlight(comp.id, true) : null,
1183
+ onFocus: ($event) => !previewMode.value ? setHighlight(comp.id, true) : null
1184
+ }, [
1185
+ !previewMode.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_6, [(0, vue.createTextVNode)((0, vue.toDisplayString)(comp.type) + " ", 1), comp.data?.title ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_7, " | " + (0, vue.toDisplayString)(comp.data.title), 1)) : (0, vue.createCommentVNode)("", true)])) : (0, vue.createCommentVNode)("", true),
1186
+ ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
1187
+ id: comp.data.customId,
1188
+ key: `${comp.id}-${updateCounter.value}`,
1189
+ style: (0, vue.normalizeStyle)(getBlockStyles.value(comp.data, isMobile.value)),
1190
+ class: (0, vue.normalizeClass)((0, vue.unref)(getResponsiveClasses)(comp.data))
1191
+ }, [(0, vue.unref)(registeredComponents)[comp.type] ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(registeredComponents)[comp.type]), (0, vue.mergeProps)({
1192
+ key: 0,
1193
+ ref_for: true
1194
+ }, {
1195
+ ...(0, vue.unref)(normalizeComponentData)(comp.data),
1196
+ isMobile: isMobile.value
1197
+ }), null, 16)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_9, " ⚠️ Component not registered: " + (0, vue.toDisplayString)(comp.type), 1))], 14, _hoisted_8)),
1198
+ !previewMode.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
1199
+ key: 1,
1200
+ class: "blox-block-overlay",
1201
+ onClick: (0, vue.withModifiers)(($event) => setFocus(comp.id, true), ["self"])
1202
+ }, null, 8, _hoisted_10)) : (0, vue.createCommentVNode)("", true)
1203
+ ], 42, _hoisted_5);
1204
+ }), 128))]);
1205
+ };
1206
+ }
1207
+ });
1208
+ var ExternalPreview_default = /* @__PURE__ */ __plugin_vue_export_helper_default(ExternalPreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-8110f424"]]);
1209
+ var _hoisted_1 = { class: "blox-page-wrapper" };
1210
+ var _hoisted_2 = {
1211
+ key: 0,
1212
+ class: "blox-loading"
1213
+ };
1214
+ var _hoisted_3 = ["id"];
1215
+ var _hoisted_4 = {
1216
+ key: 1,
1217
+ class: "blox-missing-component"
1218
+ };
1219
+ var RenderPage_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ (0, vue.defineComponent)({
1220
+ __name: "RenderPage",
1221
+ props: {
1222
+ pageData: {},
1223
+ mobileBreakpoint: { default: 910 }
1224
+ },
1225
+ setup(__props) {
1226
+ const props = __props;
1227
+ const isMobile = (0, vue.ref)(false);
1228
+ const loading = (0, vue.ref)(true);
1229
+ const updateCounter = (0, vue.ref)(0);
1230
+ const registeredComponents = getAllComponents();
1231
+ const getBlockStyles = (0, vue.computed)(() => {
1232
+ updateCounter.value;
1233
+ return (data, mobile = false) => generateBlockStyles(data, mobile);
1234
+ });
1235
+ function updateMobileStatus() {
1236
+ const wasMobile = isMobile.value;
1237
+ isMobile.value = window.innerWidth <= props.mobileBreakpoint;
1238
+ if (wasMobile !== isMobile.value) updateCounter.value++;
1239
+ }
1240
+ (0, vue.onMounted)(async () => {
1241
+ console.log("🚀 Render Page mounted");
1242
+ console.log("📦 Registered components:", Object.keys(registeredComponents));
1243
+ await initializePage(props.pageData);
1244
+ updateMobileStatus();
1245
+ window.addEventListener("resize", updateMobileStatus);
1246
+ loading.value = false;
1247
+ });
1248
+ return (_ctx, _cache) => {
1249
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1, [loading.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2, _cache[0] || (_cache[0] = [(0, vue.createElementVNode)("p", null, "Loading...", -1)]))) : ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, (0, vue.renderList)(_ctx.pageData.components, (comp) => {
1250
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
1251
+ key: `${comp.id}-${updateCounter.value}`,
1252
+ id: comp.data.customId,
1253
+ style: (0, vue.normalizeStyle)(getBlockStyles.value(comp.data, isMobile.value)),
1254
+ class: (0, vue.normalizeClass)((0, vue.unref)(getResponsiveClasses)(comp.data))
1255
+ }, [(0, vue.unref)(registeredComponents)[comp.type] ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)((0, vue.unref)(registeredComponents)[comp.type]), (0, vue.mergeProps)({
1256
+ key: 0,
1257
+ ref_for: true
1258
+ }, {
1259
+ ...(0, vue.unref)(normalizeComponentData)(comp.data),
1260
+ isMobile: isMobile.value
1261
+ }), null, 16)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_4, " Component not found: " + (0, vue.toDisplayString)(comp.type), 1))], 14, _hoisted_3);
1262
+ }), 128))]);
1263
+ };
1264
+ }
1265
+ });
1266
+ var RenderPage_default = /* @__PURE__ */ __plugin_vue_export_helper_default(RenderPage_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-1a340b1b"]]);
1267
+ exports.Button = Button_default;
1268
+ exports.CommunicationBridge = CommunicationBridge;
1269
+ exports.Container = Container_default;
1270
+ exports.ExternalPreview = ExternalPreview_default;
1271
+ exports.Image = Image_default;
1272
+ exports.RenderPage = RenderPage_default;
1273
+ exports.Spacer = Spacer_default;
1274
+ exports.Text = Text_default;
1275
+ exports.Title = Title_default;
1276
+ exports.applyGlobalFont = applyGlobalFont;
1277
+ exports.applyPageSettings = applyPageSettings;
1278
+ exports.baseComponentConfigs = baseComponentConfigs;
1279
+ exports.clearRegistry = clearRegistry;
1280
+ exports.createCommunicationBridge = createCommunicationBridge;
1281
+ exports.createNamespacedRegistry = createNamespacedRegistry;
1282
+ exports.deepClone = deepClone;
1283
+ exports.deepMerge = deepMerge;
1284
+ exports.generateBlockStyles = generateBlockStyles;
1285
+ exports.getAllComponentConfigs = getAllComponentConfigs;
1286
+ exports.getAllComponents = getAllComponents;
1287
+ exports.getBaseComponentConfig = getBaseComponentConfig;
1288
+ exports.getBaseComponentConfigs = getBaseComponentConfigs;
1289
+ exports.getComponent = getComponent;
1290
+ exports.getRegisteredTypes = getRegisteredTypes;
1291
+ exports.getResponsiveCSS = getResponsiveCSS;
1292
+ exports.getResponsiveClasses = getResponsiveClasses;
1293
+ exports.hasComponent = hasComponent;
1294
+ exports.initializePage = initializePage;
1295
+ exports.injectCode = injectCode;
1296
+ exports.injectResponsiveCSS = injectResponsiveCSS;
1297
+ exports.loadComponentFonts = loadComponentFonts;
1298
+ exports.loadGoogleFont = loadGoogleFont;
1299
+ exports.normalizeComponentData = normalizeComponentData;
1300
+ exports.registerBaseComponents = registerBaseComponents;
1301
+ exports.registerComponent = registerComponent;
1302
+ exports.registerComponents = registerComponents;
1303
+ exports.registry = registry;
1304
+ exports.sendMessage = sendMessage;
1305
+ exports.unregisterComponent = unregisterComponent;