@zohofinance/commerce 1.1.0 → 2.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.
@@ -0,0 +1,1303 @@
1
+ (function(global) {
2
+ 'use strict';
3
+
4
+ if (global.parent === global) {
5
+ return;
6
+ }
7
+
8
+ if (global.__sbBridgeActive) {
9
+ return;
10
+ }
11
+ global.__sbBridgeActive = true;
12
+
13
+ let PARENT_SRC = 'sb-parent';
14
+ let BRIDGE_SRC = 'sb-bridge';
15
+ let BADGE_H = 32;
16
+ let OFFSET = 5;
17
+
18
+ let selectedEl = null;
19
+ let hoveredEl = null;
20
+ let canShowAddIcons = false;
21
+ let addAboveClicked = null;
22
+ let badgeInfo = null; // { svgHtml, svgClass, name }
23
+ let svgs = {};
24
+ let _bodyObserver = null;
25
+ let i18n = {
26
+ blocks: 'Blocks',
27
+ extensions: 'Extensions',
28
+ loading: 'Loading…',
29
+ noExtensions: 'No extensions found'
30
+ };
31
+
32
+ let overlayEl = null;
33
+ let hoverEl = null;
34
+ let actionPanelEl = null;
35
+ let nameBadgeEl = null;
36
+ let addTopEl = null;
37
+ let addBottomEl = null;
38
+ let blocksListEl = null;
39
+ let resizeObs = null;
40
+
41
+ let fetchPatched = false;
42
+
43
+ let previewModeEnabled = false;
44
+ let previewPagePatterns = [];
45
+ let previewClickHandler = null;
46
+
47
+ function readSessionValue(key) {
48
+ try {
49
+ let value = global.sessionStorage.getItem(key);
50
+ return value;
51
+ } catch(_e) {
52
+ return '';
53
+ }
54
+ }
55
+
56
+ function writeSessionValue(key, value) {
57
+ try {
58
+ global.sessionStorage.setItem(key, String(value));
59
+ } catch(_e) {
60
+ return null;
61
+ }
62
+ }
63
+
64
+ function send(type, payload) {
65
+ let msg = { source: BRIDGE_SRC, type };
66
+ if (payload) {
67
+ for (let k in payload) {
68
+ if (Object.prototype.hasOwnProperty.call(payload, k)) {
69
+ msg[k] = payload[k];
70
+ }
71
+ }
72
+ }
73
+ try {
74
+ global.parent.postMessage(msg, '*');
75
+ } catch(e) {
76
+ // no operation
77
+ }
78
+ }
79
+
80
+ // ─── DOM helpers ──────────────────────────────────────────────────────────
81
+ function getAttrs(el) {
82
+ if (!el) {
83
+ return {};
84
+ }
85
+ let raw = el.getAttribute && el.getAttribute('data-zcommerce-component');
86
+ if (!raw) {
87
+ return {};
88
+ }
89
+ try {
90
+ let p = JSON.parse(raw);
91
+ return {
92
+ dataid: p.id,
93
+ sectionid: p['data-zcommerce-section-id'],
94
+ name: p['data-zcommerce-component-name'],
95
+ key: p['data-zcommerce-component-key'],
96
+ jsonType: p['data-zcommerce-json-type'],
97
+ blockPath: p['data-zcommerce-block-path']
98
+ };
99
+ } catch(e) {
100
+ return {};
101
+ }
102
+ }
103
+
104
+ function isSection(dataid) {
105
+ return dataid && /^section_/.test(dataid);
106
+ }
107
+
108
+ function getSectionKey(sectionid, blockPath) {
109
+ if (blockPath) {
110
+ let dot = blockPath.indexOf('.');
111
+ return dot === -1 ? blockPath : blockPath.slice(0, dot);
112
+ }
113
+ return (sectionid || '').replace('section_', '');
114
+ }
115
+
116
+ function isCustomSection(name) {
117
+ return typeof name === 'string' && name.indexOf('custom_section_') === 0;
118
+ }
119
+
120
+ // "sectionKey.blockKey1.blockKey2" → "sectionKey.blockKey1" (or undefined for direct section blocks)
121
+ function getParentBlockPath(blockPath) {
122
+ if (!blockPath) {
123
+ return undefined;
124
+ }
125
+ let firstDot = blockPath.indexOf('.');
126
+ if (firstDot === -1) {
127
+ return undefined;
128
+ }
129
+ let rest = blockPath.slice(firstDot + 1);
130
+ if (rest.indexOf('.') === -1) {
131
+ return undefined;
132
+ } // only one block key — parent is section
133
+ let lastDot = blockPath.lastIndexOf('.');
134
+ return blockPath.slice(0, lastDot);
135
+ }
136
+
137
+ function buildPagePatterns(pages) {
138
+ return (pages || []).filter(function(p) {
139
+ return p.url;
140
+ }).map(function(p) {
141
+ let hasParam = /\{[^}]+\}/.test(p.url);
142
+ let pattern = p.url.replace(/\{[^}]+\}/g, '([^/?#]+)');
143
+ return { key: p.key, regex: new RegExp(`^${pattern}(?:[/?#]|$)`), hasParam };
144
+ });
145
+ }
146
+
147
+ function matchPreviewPage(pathname) {
148
+ for (let i = 0; i < previewPagePatterns.length; i++) {
149
+ let pat = previewPagePatterns[i];
150
+ let m = pathname.match(pat.regex);
151
+ if (m) {
152
+ return { key: pat.key, value: pat.hasParam ? m[1] || '' : '' };
153
+ }
154
+ }
155
+ return null;
156
+ }
157
+
158
+ function enterPreviewMode(pages) {
159
+ previewModeEnabled = true;
160
+ previewPagePatterns = buildPagePatterns(pages);
161
+ [overlayEl, hoverEl, nameBadgeEl, addTopEl, addBottomEl, blocksListEl, actionPanelEl].forEach(function(el) {
162
+ if (el) {
163
+ el.style.display = 'none';
164
+ }
165
+ });
166
+ selectedEl = null;
167
+ hoveredEl = null;
168
+ document.removeEventListener('click', onClick);
169
+ document.removeEventListener('mousemove', onMouseMove);
170
+ document.removeEventListener('keydown', onKeyDown);
171
+ previewClickHandler = function(e) {
172
+ let anchor = e.target.closest('a[href]');
173
+ if (!anchor) {
174
+ return;
175
+ }
176
+ let href = anchor.getAttribute('href');
177
+ if (!href
178
+ || href.startsWith('#')
179
+ || href.startsWith('javascript:')
180
+ || href.startsWith('mailto:')
181
+ || href.startsWith('tel:')) {
182
+ return;
183
+ }
184
+ let url;
185
+ try {
186
+ url = new URL(href);
187
+ if (url.origin !== global.location.origin) {
188
+ let storefrontOrigin = global._zcStorefrontDomain;
189
+ if (storefrontOrigin && url.origin === storefrontOrigin) {
190
+ url = new URL(url.pathname + url.search + url.hash, global.location.origin);
191
+ } else {
192
+ e.preventDefault();
193
+ return;
194
+ }
195
+ }
196
+ } catch(_e) {
197
+ try {
198
+ url = new URL(href, global.location.href);
199
+ } catch(_e2) {
200
+ e.preventDefault();
201
+ return;
202
+ }
203
+ }
204
+ let matched = matchPreviewPage(url.pathname);
205
+ if (!matched) {
206
+ e.preventDefault();
207
+ return;
208
+ }
209
+ e.preventDefault();
210
+ send('PAGE_NAVIGATE', { pageKey: matched.key, pageValue: matched.value });
211
+ };
212
+ document.addEventListener('click', previewClickHandler, true);
213
+ }
214
+
215
+ function exitPreviewMode() {
216
+ previewModeEnabled = false;
217
+ previewPagePatterns = [];
218
+ if (previewClickHandler) {
219
+ document.removeEventListener('click', previewClickHandler, true);
220
+ previewClickHandler = null;
221
+ }
222
+ document.addEventListener('click', onClick);
223
+ document.addEventListener('mousemove', onMouseMove);
224
+ document.addEventListener('keydown', onKeyDown);
225
+ }
226
+
227
+ function patchFetch() {
228
+ if (fetchPatched) {
229
+ return;
230
+ }
231
+ fetchPatched = true;
232
+ let originalFetch = global.fetch;
233
+ global.fetch = function(input, init) {
234
+ let isRequest = input instanceof Request;
235
+ let rawUrl = isRequest ? input.url : String(input);
236
+
237
+ let url, isRelative;
238
+ try {
239
+ url = new URL(rawUrl);
240
+ isRelative = false;
241
+ } catch(_e) {
242
+ isRelative = true;
243
+ try {
244
+ url = new URL(rawUrl, global.location.origin);
245
+ } catch(_e2) {
246
+ return originalFetch.call(this, input, init);
247
+ }
248
+ }
249
+
250
+ let storefrontOrigin = readSessionValue('_zcStorefrontDomain', '');
251
+ if (!isRelative && !(storefrontOrigin && url.origin === storefrontOrigin)) {
252
+ return originalFetch.call(this, input, init);
253
+ }
254
+
255
+ if (!isRelative) {
256
+ url = new URL(url.pathname + url.search + url.hash, global.location.origin);
257
+ }
258
+
259
+ let rawFetchParams = readSessionValue('_zcFetchExtraParams', '');
260
+ if (!rawFetchParams) {
261
+ return {};
262
+ }
263
+ let params = JSON.parse(rawFetchParams);
264
+ Object.keys(params).forEach(function(k) {
265
+ if (params[k] !== null && params[k] !== undefined) {
266
+ url.searchParams.set(k, String(params[k]));
267
+ }
268
+ });
269
+
270
+ let finalInput = isRequest ? new Request(url.toString(), input) : url.toString();
271
+ return originalFetch.call(this, finalInput, init);
272
+ };
273
+ }
274
+
275
+ function getElementById(id) {
276
+ let el = document.querySelector(`[data-zcommerce-component*='"data-zcommerce-component-key":"${id}"']`);
277
+ if (el) {
278
+ return el;
279
+ }
280
+ // CLI (dev mode) prefixes section keys with "section_"
281
+ el = document.querySelector(`[data-zcommerce-component*='"data-zcommerce-component-key":"section_${id}"']`);
282
+ if (el) {
283
+ return el;
284
+ }
285
+ el = document.querySelector(`[data-zcommerce-component*='"id":"${id}"']`);
286
+ if (el) {
287
+ return el;
288
+ }
289
+ return document.querySelector(`[data-zcommerce-component*='"id":"section_${id}"']`);
290
+ }
291
+
292
+ var NON_VISUAL_TAGS = { style: true, script: true, link: true, meta: true, noscript: true };
293
+ function getEffectiveEl(el) {
294
+ if (!el || global.getComputedStyle(el).display !== 'contents') {
295
+ return el;
296
+ }
297
+ for (var i = 0; i < el.children.length; i++) {
298
+ var child = el.children[i];
299
+ if (!NON_VISUAL_TAGS[child.tagName.toLowerCase()]) {
300
+ return child;
301
+ }
302
+ }
303
+ return el;
304
+ }
305
+
306
+ function updateOverlayPos(targetEl, overlay) {
307
+ if (targetEl && overlay) {
308
+ let effectiveEl = getEffectiveEl(targetEl);
309
+ let r = effectiveEl.getBoundingClientRect();
310
+ let off = effectiveEl.tagName.toLowerCase() === 'section' ? 0 : OFFSET;
311
+ let sx = global.scrollX !== undefined ? global.scrollX : global.pageXOffset;
312
+ let sy = global.scrollY !== undefined ? global.scrollY : global.pageYOffset;
313
+ Object.assign(overlay.style, {
314
+ display: 'block',
315
+ width: `${r.width + off * 2}px`,
316
+ height: `${r.height + off * 2}px`,
317
+ transform: `translate(${r.left + sx - off}px, ${r.top + sy - off}px)`
318
+ });
319
+ }
320
+ if (selectedEl && canShowAddIcons) {
321
+ addTopEl.style.display = 'flex';
322
+ addBottomEl.style.display = 'flex';
323
+ let sr = overlayEl.getBoundingClientRect();
324
+ let sx2 = global.scrollX !== undefined ? global.scrollX : global.pageXOffset;
325
+ let sy2 = global.scrollY !== undefined ? global.scrollY : global.pageYOffset;
326
+ let tx = sr.right - (selectedEl.offsetWidth / 2) - (addTopEl.offsetWidth / 2) + sx2;
327
+ let ty = sr.top - (addTopEl.offsetHeight / 2) + sy2;
328
+ Object.assign(addTopEl.style, {
329
+ alignItems: 'center',
330
+ justifyContent: 'center',
331
+ transform: `translate(${tx}px, ${ty}px)`,
332
+ borderRadius: '5px'
333
+ });
334
+ Object.assign(addBottomEl.style, {
335
+ alignItems: 'center',
336
+ justifyContent: 'center',
337
+ transform: `translate(${tx}px, ${sr.bottom - (addBottomEl.offsetHeight / 2) + sy2}px)`,
338
+ borderRadius: '5px'
339
+ });
340
+ } else {
341
+ addTopEl.style.display = 'none';
342
+ addBottomEl.style.display = 'none';
343
+ }
344
+ if (!targetEl && overlay) {
345
+ overlay.style.display = 'none';
346
+ }
347
+ }
348
+
349
+ function updateBadgePos() {
350
+ if (!selectedEl && !hoveredEl) {
351
+ nameBadgeEl.style.display = 'none';
352
+ return;
353
+ }
354
+ let refEl = hoveredEl ? hoverEl : overlayEl;
355
+ let srcEl = hoveredEl ? hoveredEl : selectedEl;
356
+ let rect = refEl.getBoundingClientRect();
357
+ let vpH = global.innerHeight || document.documentElement.clientHeight;
358
+ if (rect.bottom < 0 || rect.top > vpH) {
359
+ nameBadgeEl.style.display = 'none';
360
+ return;
361
+ }
362
+
363
+ if (badgeInfo) {
364
+ nameBadgeEl.innerHTML = (badgeInfo.svgHtml || '') + (badgeInfo.name || '');
365
+ let svgEl = nameBadgeEl.querySelector('svg');
366
+ if (svgEl && badgeInfo.svgClass) {
367
+ badgeInfo.svgClass.split(' ').forEach(function(c) {
368
+ if (c) {
369
+ svgEl.classList.add(c);
370
+ }
371
+ });
372
+ }
373
+ } else {
374
+ let a = getAttrs(srcEl);
375
+ nameBadgeEl.textContent = a.name || '';
376
+ }
377
+
378
+ let sx = global.scrollX !== undefined ? global.scrollX : global.pageXOffset;
379
+ let sy = global.scrollY !== undefined ? global.scrollY : global.pageYOffset;
380
+ let lp = rect.left + sx + 10;
381
+ let tp, brStyle;
382
+
383
+ if (rect.top >= 0 && rect.top >= BADGE_H) {
384
+ tp = rect.top + sy - BADGE_H;
385
+ brStyle = { borderTopLeftRadius: '4px', borderTopRightRadius: '4px', borderBottomLeftRadius: '0', borderBottomRightRadius: '0' };
386
+ } else if (rect.top >= 0) {
387
+ tp = rect.top + sy;
388
+ brStyle = { borderTopLeftRadius: '0', borderTopRightRadius: '0', borderBottomLeftRadius: '4px', borderBottomRightRadius: '4px' };
389
+ } else {
390
+ nameBadgeEl.style.display = 'none';
391
+ return;
392
+ }
393
+
394
+ Object.assign(nameBadgeEl.style, {
395
+ display: 'flex',
396
+ alignItems: 'center',
397
+ justifyContent: 'center',
398
+ transform: `translate(${lp}px, ${tp + 1}px)`
399
+ }, brStyle);
400
+
401
+ if (srcEl === selectedEl && canShowAddIcons) {
402
+ let addRect = addTopEl.getBoundingClientRect();
403
+ if (lp + nameBadgeEl.offsetWidth + OFFSET > addRect.left + sx) {
404
+ nameBadgeEl.style.display = 'none';
405
+ }
406
+ }
407
+ }
408
+
409
+ function updatePanelPos() {
410
+ if (!selectedEl) {
411
+ actionPanelEl.style.display = 'none';
412
+ return;
413
+ }
414
+ let rect = overlayEl.getBoundingClientRect();
415
+ let sx = global.scrollX !== undefined ? global.scrollX : global.pageXOffset;
416
+ let sy = global.scrollY !== undefined ? global.scrollY : global.pageYOffset;
417
+ let vpH = global.innerHeight || document.documentElement.clientHeight;
418
+ let vpW = global.innerWidth || document.documentElement.clientWidth;
419
+
420
+ if (rect.bottom < 0 || rect.top > vpH) {
421
+ actionPanelEl.style.display = 'none';
422
+ return;
423
+ }
424
+
425
+ actionPanelEl.style.display = 'flex';
426
+ let editBtn = actionPanelEl.querySelector('#action-edit-custom-code-btn');
427
+ if (editBtn) {
428
+ let atd = getAttrs(selectedEl);
429
+ let skey = (atd.dataid || '').replace('section_', '');
430
+ editBtn.style.display = isSection(atd.dataid) && isCustomSection(skey) ? 'flex' : 'none';
431
+ }
432
+
433
+ let pw = actionPanelEl.offsetWidth;
434
+ let ph = actionPanelEl.offsetHeight;
435
+ let topR = addTopEl.getBoundingClientRect();
436
+ let botR = addBottomEl.getBoundingClientRect();
437
+ let lp = rect.right + sx - pw - OFFSET;
438
+ let aboveAddSection = false;
439
+
440
+ if (lp - 10 < botR.right + sx) {
441
+ lp = botR.right + sx + 10;
442
+ }
443
+ if (lp - 10 < topR.right + sx) {
444
+ lp = topR.right + sx + 10;
445
+ }
446
+ if (lp + pw > vpW + sx) {
447
+ lp = rect.right + sx - pw - OFFSET;
448
+ aboveAddSection = true;
449
+ }
450
+
451
+ let tp;
452
+ let hasBottomRoom = rect.bottom > 0 && rect.bottom + ph + 10 <= vpH;
453
+ let hasTopRoom = rect.top > 0 && rect.top > ph + 10;
454
+
455
+ if (hasBottomRoom) {
456
+ tp = rect.bottom + OFFSET + sy;
457
+ if (aboveAddSection) {
458
+ tp = botR.bottom + OFFSET + sy;
459
+ }
460
+ } else if (hasTopRoom) {
461
+ tp = rect.top + sy - ph - OFFSET;
462
+ if (aboveAddSection) {
463
+ tp = topR.top - ph - OFFSET + sy;
464
+ }
465
+ } else if (rect.top >= 0) {
466
+ tp = rect.top + sy + OFFSET;
467
+ if (aboveAddSection) {
468
+ tp = topR.bottom + OFFSET + sy;
469
+ }
470
+ } else {
471
+ actionPanelEl.style.display = 'none';
472
+ return;
473
+ }
474
+
475
+ Object.assign(actionPanelEl.style, { display: 'flex', transform: `translate(${lp}px, ${tp}px)` });
476
+ }
477
+
478
+ function updateBlocksListPos() {
479
+ if (blocksListEl.style.display === 'none') {
480
+ return;
481
+ }
482
+ let sx = global.scrollX !== undefined ? global.scrollX : global.pageXOffset;
483
+ let sy = global.scrollY !== undefined ? global.scrollY : global.pageYOffset;
484
+ let vpH = global.innerHeight || document.documentElement.clientHeight;
485
+ let vpW = global.innerWidth || document.documentElement.clientWidth;
486
+ let topR = addTopEl.getBoundingClientRect();
487
+ let botR = addBottomEl.getBoundingClientRect();
488
+ let px, py;
489
+
490
+ if (addAboveClicked) {
491
+ px = topR.right + sx + 10;
492
+ if (px + blocksListEl.offsetWidth > vpW) {
493
+ px = topR.left + sx - blocksListEl.offsetWidth - 10;
494
+ }
495
+ py = topR.bottom + sy - blocksListEl.offsetHeight;
496
+ if (py < 0) {
497
+ py = topR.top + sy;
498
+ }
499
+ } else {
500
+ px = botR.left + sx - blocksListEl.offsetWidth - 10;
501
+ if (px < 0) {
502
+ px = botR.right + sx + 10;
503
+ }
504
+ py = botR.top + sy;
505
+ if (py + blocksListEl.offsetHeight > vpH) {
506
+ py = botR.bottom + sy - blocksListEl.offsetHeight;
507
+ }
508
+ }
509
+ Object.assign(blocksListEl.style, { transform: `translate(${px}px, ${py}px)` });
510
+ }
511
+
512
+ function syncAll() {
513
+ updateOverlayPos(selectedEl, overlayEl);
514
+ updateOverlayPos(hoveredEl, hoverEl);
515
+ updateBlocksListPos();
516
+ updateBadgePos();
517
+ updatePanelPos();
518
+ }
519
+
520
+ // ─── Selection helpers ────────────────────────────────────────────────────
521
+ function doHover(el) {
522
+ let style = global.getComputedStyle(el);
523
+ if (style.display !== 'none' && el !== selectedEl) {
524
+ hoveredEl = el;
525
+ badgeInfo = null;
526
+ requestAnimationFrame(syncAll);
527
+ updateBadgePos();
528
+ updatePanelPos();
529
+ send('COMPONENT_HOVERED', getAttrs(el));
530
+ } else {
531
+ doUnhover();
532
+ }
533
+ }
534
+
535
+ function doUnhover() {
536
+ hoveredEl = null;
537
+ updateOverlayPos(hoveredEl, hoverEl);
538
+ updateBadgePos();
539
+ updatePanelPos();
540
+ }
541
+
542
+ function doSelect(el, fromCanvas) {
543
+ if (selectedEl) {
544
+ resizeObs.unobserve(selectedEl);
545
+ }
546
+ selectedEl = el;
547
+ badgeInfo = null;
548
+ canShowAddIcons = false;
549
+ resizeObs.observe(selectedEl);
550
+ doUnhover();
551
+ requestAnimationFrame(syncAll);
552
+ updateBadgePos();
553
+ updatePanelPos();
554
+ let attrs = getAttrs(el);
555
+ attrs.isSelectFromCanvas = !!fromCanvas;
556
+ attrs.childrenCount = el.children ? el.children.length : 0;
557
+ send('COMPONENT_SELECTED', attrs);
558
+ scrollIntoView(el);
559
+ closeBlocksList();
560
+ }
561
+
562
+ function doUnselect() {
563
+ if (selectedEl) {
564
+ resizeObs.unobserve(selectedEl);
565
+ }
566
+ selectedEl = null;
567
+ updateOverlayPos(selectedEl, overlayEl);
568
+ updateBadgePos();
569
+ updatePanelPos();
570
+ }
571
+
572
+ function scrollIntoView(el) {
573
+ let effectiveEl = getEffectiveEl(el);
574
+ let r = effectiveEl.getBoundingClientRect();
575
+ let vpH = global.innerHeight || document.documentElement.clientHeight;
576
+ let inView = r.top >= 0 && r.bottom <= vpH;
577
+ if (!inView) {
578
+ effectiveEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
579
+ }
580
+ }
581
+
582
+ function attachOverlays() {
583
+ [overlayEl, hoverEl, nameBadgeEl, addTopEl, addBottomEl, blocksListEl, actionPanelEl].forEach(function(el) {
584
+ if (el) {
585
+ document.body.appendChild(el);
586
+ }
587
+ });
588
+ }
589
+
590
+ function dropStaleSelection() {
591
+ if (selectedEl && !document.body.contains(selectedEl)) {
592
+ if (resizeObs) {
593
+ resizeObs.unobserve(selectedEl);
594
+ }
595
+ selectedEl = null;
596
+ }
597
+ if (hoveredEl && !document.body.contains(hoveredEl)) {
598
+ hoveredEl = null;
599
+ }
600
+ }
601
+
602
+ function replaceElement(id, html) {
603
+ let parser = new DOMParser();
604
+ let newEl = parser.parseFromString(html, 'text/html').body.firstElementChild;
605
+ let oldEl = getElementById(id);
606
+ if (oldEl && newEl) {
607
+ // Selection/hover may live inside the subtree we are about to discard.
608
+ if (selectedEl && oldEl.contains(selectedEl)) {
609
+ doUnselect();
610
+ }
611
+ if (hoveredEl && oldEl.contains(hoveredEl)) {
612
+ doUnhover();
613
+ }
614
+ oldEl.innerHTML = newEl.innerHTML;
615
+ dispatchPageLoad();
616
+ }
617
+ }
618
+
619
+ function insertElement(id, html, position) {
620
+ let parser = new DOMParser();
621
+ let newEl = parser.parseFromString(html, 'text/html').body.firstElementChild;
622
+ if (!newEl) {
623
+ return;
624
+ }
625
+ let refEl = getElementById(id);
626
+ let parent = refEl && refEl.parentElement;
627
+ if (!parent) {
628
+ return;
629
+ }
630
+ if (position === 'before') {
631
+ parent.insertBefore(newEl, refEl);
632
+ } else if (position === 'after') {
633
+ let next = refEl.nextSibling;
634
+ next ? parent.insertBefore(newEl, next) : parent.appendChild(newEl);
635
+ } else {
636
+ parent.appendChild(newEl);
637
+ }
638
+ doSelect(newEl, false);
639
+ dispatchPageLoad();
640
+ }
641
+
642
+ function changePosition(movingId, refId, shouldSelect) {
643
+ let movingEl = getElementById(movingId);
644
+ let par = movingEl && movingEl.parentElement;
645
+ if (par && movingEl) {
646
+ par.removeChild(movingEl);
647
+ if (refId) {
648
+ let refEl = getElementById(refId);
649
+ refEl ? par.insertBefore(movingEl, refEl) : par.appendChild(movingEl);
650
+ } else {
651
+ par.appendChild(movingEl);
652
+ }
653
+ }
654
+ if (shouldSelect !== false && movingEl) {
655
+ doSelect(movingEl, false);
656
+ }
657
+ }
658
+
659
+ function syncOrder(orderedKeys, draggedKey) {
660
+ if (!orderedKeys || !orderedKeys.length) {
661
+ return;
662
+ }
663
+ let elements = orderedKeys.map(getElementById).filter(Boolean);
664
+ if (elements.length !== orderedKeys.length) {
665
+ return;
666
+ }
667
+ let par = elements[0].parentElement;
668
+ if (!par || !elements.every(function(el) {
669
+ return el.parentElement === par;
670
+ })) {
671
+ return;
672
+ }
673
+
674
+ let prefersReduced = global.matchMedia('(prefers-reduced-motion: reduce)').matches;
675
+
676
+ function relToParent(el) {
677
+ let er = el.getBoundingClientRect();
678
+ let pr = par.getBoundingClientRect();
679
+ return { x: er.left - pr.left, y: er.top - pr.top };
680
+ }
681
+
682
+ let firstPos = elements.map(relToParent);
683
+ let frag = document.createDocumentFragment();
684
+ elements.forEach(function(el) {
685
+ frag.appendChild(el);
686
+ });
687
+ par.appendChild(frag);
688
+
689
+ if (draggedKey) {
690
+ let dEl = getElementById(draggedKey);
691
+ if (dEl) {
692
+ dEl.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' });
693
+ }
694
+ }
695
+
696
+ let lastPos = elements.map(relToParent);
697
+ syncAll();
698
+
699
+ if (!prefersReduced) {
700
+ elements.forEach(function(el, i) {
701
+ let dx = firstPos[i].x - lastPos[i].x;
702
+ let dy = firstPos[i].y - lastPos[i].y;
703
+ if (Math.abs(dx) < 0.5 && Math.abs(dy) < 0.5) {
704
+ return;
705
+ }
706
+ el.style.transition = 'none';
707
+ el.style.transform = `translate(${dx}px, ${dy}px)`;
708
+ requestAnimationFrame(function() {
709
+ el.style.transition = 'transform 0.22s cubic-bezier(0.25, 0.8, 0.25, 1)';
710
+ el.style.transform = '';
711
+ function onEnd(e) {
712
+ if (e.propertyName !== 'transform') {
713
+ return;
714
+ }
715
+ el.removeEventListener('transitionend', onEnd);
716
+ el.style.transition = '';
717
+ el.style.transform = '';
718
+ syncAll();
719
+ }
720
+ el.addEventListener('transitionend', onEnd);
721
+ });
722
+ });
723
+ }
724
+
725
+ if (draggedKey) {
726
+ requestAnimationFrame(function() {
727
+ requestAnimationFrame(syncAll);
728
+ });
729
+ if (!prefersReduced) {
730
+ global.setTimeout(syncAll, 260);
731
+ }
732
+ }
733
+ }
734
+
735
+ function dispatchPageLoad() {
736
+ document.dispatchEvent(new Event('DOMContentLoaded', { bubbles: true, cancelable: false }));
737
+ global.dispatchEvent(new Event('load', { bubbles: false, cancelable: false }));
738
+ }
739
+
740
+ function closeBlocksList() {
741
+ if (!blocksListEl) {
742
+ return;
743
+ }
744
+ blocksListEl.style.display = 'none';
745
+ }
746
+
747
+ function openBlocksList(blocks, addAbove, blockOrder, fromButtons, hasExtensions) {
748
+ if (!blocksListEl) {
749
+ return;
750
+ }
751
+ let alreadyOpen = blocksListEl.style.display !== 'none';
752
+ let directionChanged = fromButtons && (addAboveClicked !== addAbove);
753
+
754
+ if (!alreadyOpen || directionChanged) {
755
+ addAboveClicked = addAbove;
756
+ if (!selectedEl || !blocks) {
757
+ return;
758
+ }
759
+
760
+ let attrs = getAttrs(selectedEl);
761
+ let sId = getSectionKey(attrs.sectionid, attrs.blockPath);
762
+ let parentBP = getParentBlockPath(attrs.blockPath);
763
+
764
+ blocksListEl.innerHTML = '';
765
+ if (hasExtensions) {
766
+ buildBlocksWithTabs(blocks, addAbove, sId, attrs.jsonType, attrs.key, parentBP);
767
+ } else {
768
+ blocks.forEach(function(b) {
769
+ blocksListEl.appendChild(makeBlockBtn(b, sId, attrs.jsonType, attrs.key, addAbove, parentBP));
770
+ });
771
+ }
772
+ blocksListEl.style.display = 'flex';
773
+ updateBlocksListPos();
774
+ } else {
775
+ closeBlocksList();
776
+ }
777
+ }
778
+
779
+ function makeBlockBtn(block, sectionId, jsonType, key, addAbove, blockPath) {
780
+ let btn = document.createElement('button');
781
+ btn.innerHTML = (block.svgHtml || '') + (block.display_name || '');
782
+ let svgEl = btn.querySelector('svg');
783
+ if (svgEl && block.svgClass) {
784
+ block.svgClass.split(' ').forEach(function(c) {
785
+ if (c) {
786
+ svgEl.classList.add(c);
787
+ }
788
+ });
789
+ }
790
+ btn.classList.add('storefront-available-blocks-button');
791
+ btn.addEventListener('click', function() {
792
+ send('ADD_BLOCK', { blockName: block.block_name, sectionId, jsonType, key, addAbove, blockPath });
793
+ closeBlocksList();
794
+ });
795
+ return btn;
796
+ }
797
+
798
+ function buildBlocksWithTabs(blocks, addAbove, sectionId, jsonType, key, blockPath) {
799
+ let header = document.createElement('div');
800
+ header.className = 'storefront-bl-header';
801
+ let blocksTab = document.createElement('button');
802
+ blocksTab.type = 'button';
803
+ blocksTab.className = 'storefront-bl-tab active';
804
+ blocksTab.textContent = i18n.blocks;
805
+ let extTab = document.createElement('button');
806
+ extTab.type = 'button';
807
+ extTab.className = 'storefront-bl-tab';
808
+ extTab.textContent = i18n.extensions;
809
+
810
+ let scroll = document.createElement('div');
811
+ scroll.className = 'storefront-bl-scroll';
812
+ blocksListEl._scrollEl = scroll;
813
+ blocksListEl._sectionId = sectionId;
814
+ blocksListEl._jsonType = jsonType;
815
+ blocksListEl._blockPath = blockPath;
816
+
817
+ function fillBlocks() {
818
+ scroll.innerHTML = '';
819
+ let inner = document.createElement('div');
820
+ inner.className = 'storefront-bl-blocks-inner';
821
+ blocks.forEach(function(b) {
822
+ inner.appendChild(makeBlockBtn(b, sectionId, jsonType, key, addAbove, blockPath));
823
+ });
824
+ scroll.appendChild(inner);
825
+ }
826
+
827
+ function fillExtensions() {
828
+ scroll.innerHTML = '';
829
+ let loadEl = document.createElement('div');
830
+ loadEl.className = 'storefront-bl-msg';
831
+ loadEl.textContent = i18n.loading;
832
+ scroll.appendChild(loadEl);
833
+ send('GET_EXTENSIONS', {
834
+ sectionId, jsonType, blockPath
835
+ });
836
+ }
837
+
838
+ blocksTab.addEventListener('click', function(e) {
839
+ e.stopPropagation();
840
+ blocksTab.classList.add('active');
841
+ extTab.classList.remove('active');
842
+ fillBlocks();
843
+ });
844
+ extTab.addEventListener('click', function(e) {
845
+ e.stopPropagation();
846
+ extTab.classList.add('active');
847
+ blocksTab.classList.remove('active');
848
+ fillExtensions();
849
+ });
850
+
851
+ header.append(blocksTab, extTab);
852
+ fillBlocks();
853
+ blocksListEl.append(header, scroll);
854
+ }
855
+
856
+ function rebuildActionPanel() {
857
+ if (actionPanelEl) {
858
+ actionPanelEl.remove();
859
+ }
860
+ actionPanelEl = document.createElement('div');
861
+ actionPanelEl.classList.add('storefront-editor-action-panel');
862
+ actionPanelEl.style.display = 'none';
863
+
864
+ function makeBtn(id, svgKey, extraClass) {
865
+ let btn = document.createElement('button');
866
+ btn.id = id;
867
+ btn.innerHTML = svgs[svgKey] || '';
868
+ btn.classList.add('action-panel-button');
869
+ if (extraClass) {
870
+ btn.classList.add(extraClass);
871
+ }
872
+ let svgEl = btn.querySelector('svg');
873
+ if (svgEl) {
874
+ svgEl.classList.add('action-panel-svg');
875
+ }
876
+ return btn;
877
+ }
878
+
879
+ let copyBtn = makeBtn('action-copy-btn', 'copy');
880
+ let toggleBtn = makeBtn('action-toggle-btn', 'eye');
881
+ let editBtn = makeBtn('action-edit-custom-code-btn', 'edit');
882
+ editBtn.style.display = 'none';
883
+ let delBtn = makeBtn('action-delete-btn', 'delete', 'delete-button');
884
+ let upBtn = makeBtn('action-move-up-btn', 'editor-arrow-up');
885
+ let downBtn = makeBtn('action-move-down-btn', 'editor-arrow-down');
886
+
887
+ function sendAction(type) {
888
+ if (!selectedEl) {
889
+ return;
890
+ }
891
+ send(type, getAttrs(selectedEl));
892
+ }
893
+
894
+ copyBtn.addEventListener('click', function(e) {
895
+ e.stopPropagation();
896
+ sendAction('ACTION_COPY');
897
+ });
898
+ toggleBtn.addEventListener('click', function(e) {
899
+ e.stopPropagation();
900
+ sendAction('ACTION_TOGGLE');
901
+ });
902
+ editBtn.addEventListener('click', function(e) {
903
+ e.stopPropagation();
904
+ if (!selectedEl) {
905
+ return;
906
+ }
907
+ let a = getAttrs(selectedEl);
908
+ send('ACTION_EDIT_CUSTOM_CODE', { sectionKey: (a.dataid || '').replace('section_', ''), jsonType: a.jsonType });
909
+ });
910
+ delBtn.addEventListener('click', function(e) {
911
+ e.stopPropagation();
912
+ sendAction('ACTION_DELETE');
913
+ });
914
+ upBtn.addEventListener('click', function(e) {
915
+ e.stopPropagation();
916
+ sendAction('ACTION_MOVE_UP');
917
+ });
918
+ downBtn.addEventListener('click', function(e) {
919
+ e.stopPropagation();
920
+ sendAction('ACTION_MOVE_DOWN');
921
+ });
922
+
923
+ actionPanelEl.append(copyBtn, toggleBtn, editBtn, upBtn, downBtn, delBtn);
924
+ document.body.appendChild(actionPanelEl);
925
+ }
926
+
927
+ function onMouseMove(e) {
928
+ requestAnimationFrame(function() {
929
+ if (!addBottomEl || !addTopEl) {
930
+ return;
931
+ }
932
+ let { target } = e;
933
+ let compEl = target.closest('[data-zcommerce-component], [data-zcommerce-block-path]');
934
+ if (!compEl && !addBottomEl.matches(':hover') && !addTopEl.matches(':hover')) {
935
+ doUnhover();
936
+ return;
937
+ }
938
+ if (compEl && hoveredEl !== compEl) {
939
+ doHover(compEl);
940
+ }
941
+ });
942
+ }
943
+
944
+ function onClick(e) {
945
+ e.preventDefault();
946
+ e.stopPropagation();
947
+ let compEl = e.target.closest('[data-zcommerce-component]');
948
+ if (compEl) {
949
+ doSelect(compEl, true);
950
+ }
951
+ }
952
+
953
+ function onScroll() {
954
+ requestAnimationFrame(syncAll);
955
+ }
956
+ function onResize() {
957
+ requestAnimationFrame(syncAll);
958
+ }
959
+
960
+ function onKeyDown(e) {
961
+ let active = document.activeElement;
962
+ if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.isContentEditable)) {
963
+ return;
964
+ }
965
+ send('KEYDOWN', { key: e.key, ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey });
966
+ }
967
+
968
+ function onAddTop() {
969
+ if (!selectedEl) {
970
+ return;
971
+ }
972
+ send('ADD_SECTION_TOP_CLICKED', getAttrs(selectedEl));
973
+ }
974
+
975
+ function onAddBottom() {
976
+ if (!selectedEl) {
977
+ return;
978
+ }
979
+ let attrs = getAttrs(selectedEl);
980
+ let next = selectedEl.nextElementSibling;
981
+ let nextSibKey = null;
982
+ while (next) {
983
+ if (next.hasAttribute('data-zcommerce-component') || next.hasAttribute('data-zcommerce-block-path')) {
984
+ let na = getAttrs(next);
985
+ nextSibKey = na.jsonType === attrs.jsonType ? na.key : null;
986
+ break;
987
+ }
988
+ next = next.nextElementSibling;
989
+ }
990
+ send('ADD_SECTION_BOTTOM_CLICKED', { dataid: attrs.dataid, sectionid: attrs.sectionid, jsonType: attrs.jsonType, key: attrs.key, blockPath: attrs.blockPath, nextSiblingKey: nextSibKey });
991
+ }
992
+
993
+ function onMessage(e) {
994
+ let msg = e.data;
995
+ if (!msg || msg.source !== PARENT_SRC) {
996
+ return;
997
+ }
998
+ let { type } = msg;
999
+
1000
+ if (type === 'INIT') {
1001
+ if (msg.svgs) {
1002
+ svgs = msg.svgs;
1003
+ }
1004
+ if (msg.i18n) {
1005
+ Object.assign(i18n, msg.i18n);
1006
+ }
1007
+ if (msg.storefrontDomain) {
1008
+ global._zcStorefrontDomain = msg.storefrontDomain;
1009
+ writeSessionValue('_zcStorefrontDomain', msg.storefrontDomain);
1010
+ }
1011
+ if (msg.fetchParams) {
1012
+ writeSessionValue('_zcFetchExtraParams', JSON.stringify(msg.fetchParams));
1013
+ }
1014
+ if (msg.previewMode) {
1015
+ enterPreviewMode(msg.allowedPages || []);
1016
+ } else if (previewModeEnabled) {
1017
+ exitPreviewMode();
1018
+ }
1019
+ rebuildActionPanel();
1020
+ if (svgs['thick-plus']) {
1021
+ addTopEl.innerHTML = svgs['thick-plus'];
1022
+ addBottomEl.innerHTML = svgs['thick-plus'];
1023
+ }
1024
+ send('READY', {});
1025
+
1026
+ } else if (type === 'SET_BADGE_INFO') {
1027
+ badgeInfo = { svgHtml: msg.svgHtml, svgClass: msg.svgClass, name: msg.name };
1028
+ updateBadgePos();
1029
+
1030
+ } else if (type === 'SET_CAN_SHOW_ADD_ICONS') {
1031
+ canShowAddIcons = !!msg.canShow;
1032
+ updateOverlayPos(selectedEl, overlayEl);
1033
+ updateBadgePos();
1034
+
1035
+ } else if (type === 'SELECT_BY_ID') {
1036
+ let el = getElementById(msg.id);
1037
+ if (el) {
1038
+ doSelect(el, false);
1039
+ }
1040
+
1041
+ } else if (type === 'UNSELECT') {
1042
+ doUnselect();
1043
+
1044
+ } else if (type === 'UNHOVER') {
1045
+ doUnhover();
1046
+
1047
+ } else if (type === 'SET_INNER_HTML') {
1048
+ let targetEl = getElementById(msg.id);
1049
+ if (targetEl) {
1050
+ targetEl.innerHTML = msg.html;
1051
+ }
1052
+
1053
+ } else if (type === 'REPLACE_HTML') {
1054
+ let parser = new DOMParser();
1055
+ let newDoc = parser.parseFromString(msg.html || '', 'text/html');
1056
+ document.head.innerHTML = newDoc.head.innerHTML; // scripts in innerHTML are inert — bridge unaffected
1057
+ injectStyles(); // bridge styles were wiped by head swap; re-inject them
1058
+ document.body.innerHTML = newDoc.body.innerHTML;
1059
+ attachOverlays();
1060
+ doUnselect();
1061
+ doUnhover();
1062
+ dispatchPageLoad();
1063
+
1064
+ } else if (type === 'REPLACE_ELEMENT') {
1065
+ replaceElement(msg.id, msg.html);
1066
+
1067
+ } else if (type === 'INSERT_ELEMENT') {
1068
+ insertElement(msg.id, msg.html, msg.position || 'before');
1069
+
1070
+ } else if (type === 'DELETE_SECTION') {
1071
+ let delEl = getElementById(msg.id);
1072
+ if (delEl) {
1073
+ delEl.remove();
1074
+ dropStaleSelection();
1075
+ }
1076
+
1077
+ } else if (type === 'CHANGE_POSITION') {
1078
+ changePosition(msg.movingId, msg.refId, msg.isSelect);
1079
+
1080
+ } else if (type === 'SYNC_ORDER') {
1081
+ syncOrder(msg.orderedKeys, msg.draggedSectionKey);
1082
+
1083
+ } else if (type === 'TOGGLE_SECTION') {
1084
+ let toggledEl = getElementById(msg.id);
1085
+ if (toggledEl) {
1086
+ toggledEl.style.display = msg.isHidden ? 'none' : '';
1087
+ }
1088
+
1089
+ } else if (type === 'SCROLL_TO') {
1090
+ let scrollEl = getElementById(msg.id);
1091
+ if (scrollEl) {
1092
+ let reduced = global.matchMedia('(prefers-reduced-motion: reduce)').matches;
1093
+ scrollEl.scrollIntoView({ behavior: reduced ? 'auto' : 'smooth', block: 'center', inline: 'nearest' });
1094
+ }
1095
+
1096
+ } else if (type === 'DISPATCH_PAGE_LOAD') {
1097
+ dispatchPageLoad();
1098
+
1099
+ } else if (type === 'TOGGLE_BLOCKS_LIST') {
1100
+ openBlocksList(msg.available_blocks, msg.addAbove, msg.block_order || [], msg.fromAddButtons, msg.hasExtensions);
1101
+
1102
+ } else if (type === 'SET_EXTENSIONS') {
1103
+ let scroll = blocksListEl._scrollEl;
1104
+ if (!scroll) {
1105
+ return;
1106
+ }
1107
+ scroll.innerHTML = '';
1108
+ let exts = msg.extensions || [];
1109
+ if (!exts.length) {
1110
+ let emptyEl = document.createElement('div');
1111
+ emptyEl.className = 'storefront-bl-msg';
1112
+ emptyEl.textContent = i18n.noExtensions;
1113
+ scroll.appendChild(emptyEl);
1114
+ } else {
1115
+ let sId2 = blocksListEl._sectionId;
1116
+ let jt = blocksListEl._jsonType;
1117
+ let bp = blocksListEl._blockPath;
1118
+ exts.forEach(function(ext) {
1119
+ let btn = document.createElement('button');
1120
+ btn.type = 'button';
1121
+ btn.classList.add('storefront-available-blocks-button');
1122
+ btn.textContent = ext.name || '';
1123
+ btn.addEventListener('click', function() {
1124
+ if (!ext.storefront_extension_id || !ext.block_json) {
1125
+ return;
1126
+ }
1127
+ send('ADD_EXTENSION', { extensionId: ext.storefront_extension_id, extensionJson: ext.block_json, sectionId: sId2, jsonType: jt, blockPath: bp });
1128
+ closeBlocksList();
1129
+ });
1130
+ scroll.appendChild(btn);
1131
+ });
1132
+ }
1133
+
1134
+ } else if (type === 'GET_IMAGE_ASPECT_RATIO') {
1135
+ let img = null;
1136
+ try {
1137
+ img = document.querySelector(`img[src="${msg.imageSrc}"]`);
1138
+ } catch(err) {
1139
+ img = null;
1140
+ }
1141
+ if (!img) {
1142
+ img = selectedEl;
1143
+ }
1144
+ let ratio = img ? img.clientWidth / img.clientHeight : 1;
1145
+ send('IMAGE_ASPECT_RATIO', { requestId: msg.requestId, ratio });
1146
+
1147
+ } else if (type === 'SYNC_OVERLAYS') {
1148
+ syncAll();
1149
+
1150
+ } else if (type === 'ENTER_PREVIEW') {
1151
+ enterPreviewMode(msg.allowedPages);
1152
+
1153
+ } else if (type === 'EXIT_PREVIEW') {
1154
+ exitPreviewMode();
1155
+ }
1156
+ }
1157
+
1158
+ function injectStyles() {
1159
+ let existing = document.getElementById('__sb-bridge-styles');
1160
+ if (existing) {
1161
+ existing.remove();
1162
+ }
1163
+ let style = document.createElement('style');
1164
+ style.id = '__sb-bridge-styles';
1165
+ style.textContent = [
1166
+ '.storefront-overlay-element,.storefront-hover-element{position:absolute;border:2px solid #1b6de0;z-index:99997;pointer-events:none;display:none;border-radius:10px;top:0;left:0}',
1167
+ '.storefront-hover-element{border-style:dashed;background-color:rgba(27,109,224,.1)}',
1168
+ '.storefront-name-badge{position:absolute;display:none;z-index:99999;background-color:#1b6de0;color:#fff;padding:6px 12px;font-size:13px;font-weight:500;font-family:sans-serif;white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,.15);height:32px;top:0;left:0}',
1169
+ '.storefront-name-badge svg{height:14px;width:14px;margin-right:5px}',
1170
+ '.storefront-name-badge .color-with-fill path,.storefront-name-badge .color-with-fill rect,.storefront-name-badge .color-with-fill circle{fill:#fff}',
1171
+ '.storefront-name-badge .color-with-stroke path,.storefront-name-badge .color-with-stroke rect,.storefront-name-badge .color-with-stroke circle{stroke:#fff}',
1172
+ '.storefront-add-section{cursor:pointer;position:absolute;display:none;z-index:99998;background-color:#14253e;color:#fff;font-size:11px;font-weight:500;padding:5px;top:0;left:0}',
1173
+ '.storefront-add-section svg{fill:#fff;width:12px;height:12px}',
1174
+ '.storefront-available-blocks-list{cursor:default;position:absolute;display:none;z-index:100000;background-color:#fff;flex-direction:column;padding:5px;border-radius:6px;box-shadow:0 2px 8px rgba(0,0,0,.15);min-width:220px;max-height:300px;top:0;left:0}',
1175
+ '.storefront-bl-header{display:flex;justify-content:space-between;background-color:#f2f2f9;border-radius:6px;padding:4px;gap:4px;flex-shrink:0;margin-bottom:4px}',
1176
+ '.storefront-bl-tab{flex:1;border:1px solid transparent;border-radius:8px;background:transparent;color:#454c67;font-size:13px;font-weight:400;font-family:sans-serif;padding:8px 6px;cursor:pointer}',
1177
+ '.storefront-bl-tab.active{background-color:#fff;color:#202432;border-color:#eeeded}',
1178
+ '.storefront-bl-scroll{display:flex;flex-direction:column;overflow-y:auto;max-height:220px;flex:1;min-height:80px;gap:2px}',
1179
+ '.storefront-bl-msg{color:#6c757d;font-size:13px;padding:12px 8px;text-align:center;font-family:sans-serif}',
1180
+ '.storefront-available-blocks-button{padding:5px;border-radius:6px;font-size:13px;font-weight:300;font-family:sans-serif;width:100%;min-width:70px;text-align:start;display:flex;align-items:center}',
1181
+ '.storefront-available-blocks-button svg{height:14px;width:14px;margin-right:5px;fill:none}',
1182
+ '.storefront-available-blocks-button:hover{background-color:#558BF3;color:#fff}',
1183
+ '.storefront-available-blocks-button:hover .color-with-fill path,.storefront-available-blocks-button:hover .color-with-fill rect,.storefront-available-blocks-button:hover .color-with-fill circle{fill:#fff}',
1184
+ '.storefront-available-blocks-button:hover .color-with-stroke path,.storefront-available-blocks-button:hover .color-with-stroke rect,.storefront-available-blocks-button:hover .color-with-stroke circle{stroke:#fff}',
1185
+ '.storefront-editor-action-panel{position:absolute;display:flex;z-index:100000;background-color:#fff;border:1px solid #dfdfed;border-radius:7px;padding:8px 0;flex-direction:row;align-items:center;box-shadow:0 3px 8px 0 rgba(0,0,0,.24);top:0;left:0}',
1186
+ '.action-panel-button{background:transparent;cursor:pointer;padding:0 8px;display:flex;align-items:center;justify-content:center;transition:background-color .2s,border-radius .2s;border-right:1px solid #dfdfed}',
1187
+ '.action-panel-button:hover .action-panel-svg{fill:#1b6de0}',
1188
+ '.action-panel-button.delete-button{border:0}',
1189
+ '.action-panel-button.delete-button .action-panel-svg{fill:#dc3545}',
1190
+ '.action-panel-button.delete-button:hover .action-panel-svg{fill:#c72121}',
1191
+ '.action-panel-svg{width:18px;height:18px;fill:#58627f;transition:fill .2s}'
1192
+ ].join('\n');
1193
+ document.head.appendChild(style);
1194
+ }
1195
+
1196
+ function mount() {
1197
+ patchFetch();
1198
+ injectStyles();
1199
+
1200
+ overlayEl = document.createElement('div');
1201
+ overlayEl.className = 'storefront-overlay-element';
1202
+ hoverEl = document.createElement('div');
1203
+ hoverEl.className = 'storefront-hover-element';
1204
+ nameBadgeEl = document.createElement('div');
1205
+ nameBadgeEl.className = 'storefront-name-badge';
1206
+ addTopEl = document.createElement('div');
1207
+ addTopEl.className = 'storefront-add-section';
1208
+ addBottomEl = document.createElement('div');
1209
+ addBottomEl.className = 'storefront-add-section';
1210
+ blocksListEl = document.createElement('div');
1211
+ blocksListEl.className = 'storefront-available-blocks-list';
1212
+ blocksListEl.style.display = 'none';
1213
+
1214
+ attachOverlays();
1215
+
1216
+ _bodyObserver = new MutationObserver(function() {
1217
+ let detached = [overlayEl, hoverEl, nameBadgeEl, addTopEl, addBottomEl, blocksListEl, actionPanelEl]
1218
+ .some(function(el) {
1219
+ return el && !document.body.contains(el);
1220
+ });
1221
+ if (detached) {
1222
+ attachOverlays();
1223
+ dropStaleSelection();
1224
+ syncAll();
1225
+ }
1226
+ });
1227
+ _bodyObserver.observe(document.body, { childList: true });
1228
+
1229
+ actionPanelEl = document.createElement('div');
1230
+ actionPanelEl.classList.add('storefront-editor-action-panel');
1231
+ actionPanelEl.style.display = 'none';
1232
+ document.body.appendChild(actionPanelEl);
1233
+
1234
+ resizeObs = new ResizeObserver(syncAll);
1235
+
1236
+ addTopEl.addEventListener('click', onAddTop);
1237
+ addBottomEl.addEventListener('click', onAddBottom);
1238
+ if (!previewModeEnabled) {
1239
+ document.addEventListener('mousemove', onMouseMove);
1240
+ document.addEventListener('click', onClick);
1241
+ document.addEventListener('keydown', onKeyDown);
1242
+ global.addEventListener('scroll', onScroll);
1243
+ global.addEventListener('resize', onResize);
1244
+ }
1245
+ global.addEventListener('message', onMessage);
1246
+
1247
+ send('BRIDGE_MOUNTED', {});
1248
+ }
1249
+
1250
+ function unmount() {
1251
+ document.removeEventListener('mousemove', onMouseMove);
1252
+ document.removeEventListener('click', onClick);
1253
+ document.removeEventListener('keydown', onKeyDown);
1254
+ global.removeEventListener('scroll', onScroll);
1255
+ global.removeEventListener('resize', onResize);
1256
+ global.removeEventListener('message', onMessage);
1257
+
1258
+ if (addTopEl) {
1259
+ addTopEl.removeEventListener('click', onAddTop);
1260
+ }
1261
+ if (addBottomEl) {
1262
+ addBottomEl.removeEventListener('click', onAddBottom);
1263
+ }
1264
+
1265
+ if (_bodyObserver) {
1266
+ _bodyObserver.disconnect();
1267
+ _bodyObserver = null;
1268
+ }
1269
+ if (resizeObs) {
1270
+ resizeObs.disconnect();
1271
+ resizeObs = null;
1272
+ }
1273
+
1274
+ [overlayEl, hoverEl, actionPanelEl, nameBadgeEl, addTopEl, addBottomEl, blocksListEl].forEach(function(el) {
1275
+ if (el && el.parentNode) {
1276
+ el.parentNode.removeChild(el);
1277
+ }
1278
+ });
1279
+
1280
+ let styleEl = document.getElementById('__sb-bridge-styles');
1281
+ if (styleEl) {
1282
+ styleEl.remove();
1283
+ }
1284
+
1285
+ global.__sbBridgeActive = false;
1286
+ }
1287
+
1288
+ try {
1289
+ global.parent.postMessage({ source: 'sb-bridge', type: 'BRIDGE_SCRIPT_STARTED' }, '*');
1290
+ } catch(e) {
1291
+ // no operation
1292
+ }
1293
+
1294
+ global.addEventListener('pagehide', unmount, { once: true });
1295
+ global.addEventListener('beforeunload', unmount, { once: true });
1296
+
1297
+ if (document.readyState === 'loading') {
1298
+ document.addEventListener('DOMContentLoaded', mount, { once: true });
1299
+ } else {
1300
+ mount();
1301
+ }
1302
+
1303
+ })(window);