@accelerated-agency/visual-editor 0.4.4 → 0.4.6

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 (3) hide show
  1. package/dist/vite.cjs +491 -24
  2. package/dist/vite.js +491 -24
  3. package/package.json +1 -1
package/dist/vite.cjs CHANGED
@@ -146,7 +146,9 @@ async function getScraperProxyClient() {
146
146
  })();
147
147
  return scraperProxyClientPromise;
148
148
  }
149
- var iframeAlwaysShowCss = `<style id="__ce_force_show">#CybotCookiebotDialog,#CybotCookiebotDialogBodyUnderlay,#onetrust-consent-sdk,#onetrust-banner-sdk,.cc-window,.cc-banner,.cc-overlay,#cookie-notice,#cookie-banner,#cookie-consent,.cookie-notice,.cookie-banner,.cookie-consent,.cookie-popup,.cookie-bar,.cookie-message,.cookie-alert,.gdpr-banner,.gdpr-consent,.gdpr-popup,.gdpr-overlay,#gdpr-consent,#gdpr-banner,.consent-banner,.consent-popup,.consent-overlay,#consent-banner,#consent-popup,[class*="cookie-consent"],[class*="cookie-banner"],[class*="cookie-notice"],[class*="CookieConsent"],[class*="CookieBanner"],[id*="cookie-consent"],[id*="cookie-banner"],[id*="cookie-notice"],[aria-label*="cookie" i],[aria-label*="consent" i],.klaro,.klaro .cookie-modal,#usercentrics-root,.trustarc-banner,#truste-consent-track,#hs-eu-cookie-confirmation,.osano-cm-window,.osano-cm-dialog,.evidon-banner,#_evidon_banner,.js-cookie-consent,.cookie-disclaimer,.shopify-section-cookies,#shopify-section-cookies,#shopify-pc__banner,#shopify-pc__modal,.privacy-banner,.privacy-popup,[data-testid="cookie-banner"],[data-testid="consent-banner"],.amgdprcookie-bar-container,[data-amcookie-js="bar"],.amgdprjs-bar-template,.amgdprcookie-modal-container,.amgdprcookie-modal-overlay,#cmplz-cookiebanner-container,.cmplz-cookiebanner,#iubenda-cs-banner,.iubenda-cs-container,#qc-cmp2-container,.qc-cmp2-consent-info,#didomi-host,.didomi-popup-container,.didomi-notice,#termly-code-snippet-support,[class*="termly"],[class*="gdprcookie"],[class*="amgdpr"],[id*="gdpr-cookie"],[class*="cookie-modal"],[id*="cookie-modal"],[class*="cookieConsent"],[id*="cookieConsent"]{display:revert!important;visibility:visible!important;opacity:1!important;pointer-events:auto!important;height:auto!important;max-height:none!important;overflow:visible!important;}</style>`;
149
+ var iframeAlwaysShowCss = `<style id="__ce_force_show">
150
+
151
+ </style>`;
150
152
  var iframeAlwaysShowCssGuardScript = `<script id="__ce_force_show_guard">(function(){try{
151
153
  function ensureForceShowStyleLast(){
152
154
  var style=document.getElementById("__ce_force_show");
@@ -280,8 +282,97 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
280
282
  .tb-viewport #dev-label{font-size:14px;font-weight:500;color:##404040;min-width:auto;background:none;border:none;padding:0;overflow:visible;white-space:nowrap;text-overflow:clip;border-radius:0;max-width:none}
281
283
  .tb-viewport i{font-size:9px;color:##404040}
282
284
  /* Device toggle buttons */
285
+ .tb-dev-wrap{position:relative;display:flex;align-items:center}
283
286
  .tb-dev-btns{display:flex;align-items:center;gap:1px;padding:8px 4px;background:#F0F0F0;border-radius:7px; height: 30px;width: 116px;}
284
287
  .tb-dev-3btns{display:flex;align-items:center;gap:2px;padding:8px 4px;background:#F0F0F0;border-radius:7px; height: 30px;width: 100px;}
288
+ .tb-dev-menu{
289
+ position:absolute;top:calc(100% + 8px);right:0;z-index:12040;display:none;
290
+ width:264px;background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:4px 4px;
291
+ box-shadow:0 12px 28px rgba(2,6,23,.18);color:#27272a
292
+ }
293
+ .tb-dev-menu.open{display:block}
294
+ .tb-dev-menu .hd{font-size:12px;font-weight:600;color:#3f3f46;margin-bottom:10px}
295
+ .tb-dev-menu .row{display:flex;align-items:center;gap:8px;}
296
+ .tb-dev-menu .row.height-width-row .row{
297
+ flex-direction: column;
298
+ align-items: flex-start;
299
+ }
300
+ .tb-dev-menu .row.height-width-row label{
301
+ color: var(--content-subtle, #737373);
302
+ font-size: 12px;
303
+ font-style: normal;
304
+ font-weight: 500;
305
+ line-height: 14px; /* 116.667% */
306
+ }
307
+ .tb-dev-menu > .row{
308
+ padding: 4px 12px;
309
+ }
310
+ .tb-dev-menu label{ flex-shrink: 0;
311
+ overflow: hidden;
312
+ color: var(--base-surface, #646465);
313
+ font-size: var(--font-size-sm, 14px);
314
+ font-style: normal;
315
+ font-weight: 500;
316
+ line-height: var(--font-leading-4, 16px);
317
+ white-space: nowrap;
318
+ min-width: fit-content;}
319
+ .tb-dev-menu input{
320
+ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1px 1px 0 rgba(0, 0, 0, 0.01);
321
+ width:100%;height:30px;border-radius:6px;
322
+ padding:0 8px;
323
+ font-size:12px;
324
+ color:#18181b;
325
+ background:#fff;
326
+ outline:none;
327
+ color:#404040;
328
+ border-color:transparent;
329
+ }
330
+ .tb-dev-menu input#dev-zoom-level{
331
+ max-width: fit-content;
332
+ margin-left: auto;
333
+ }
334
+ .tb-dev-menu input:focus{
335
+ border-color:#1A1A1A;
336
+ box-shadow:0 0 0 2px rgba(99,102,241,.14)
337
+ }
338
+ .tb-dev-menu .row-split > *{flex:1}
339
+ .tb-dev-menu .panel-toggle label{width:100%}
340
+ .tb-dev-menu .panel-toggle-label{
341
+ overflow:hidden;
342
+ color:var(--content-subtle, #737373);
343
+ text-overflow:ellipsis;
344
+ font-size:var(--font-size-sm, 14px);
345
+ font-style:normal;
346
+ font-weight:500;
347
+ line-height:var(--font-leading-4, 16px);
348
+ white-space:nowrap;
349
+ cursor:pointer;
350
+ }
351
+ .tb-dev-menu .vp-presets{
352
+ margin-top:8px;padding-top:8px;border-top:1px dashed #ececf0;
353
+ display:flex;flex-direction:column;gap:2px
354
+ }
355
+ .tb-dev-menu .vp-preset-btn{
356
+ border:none;background:transparent;text-align:left;cursor:pointer;
357
+ border-radius:6px;
358
+ padding:8px 12px;
359
+ color: var(--content-subtle, #737373);
360
+ text-overflow: ellipsis;
361
+ font-size: var(--font-size-sm, 14px);
362
+ font-style: normal;
363
+ font-weight: 500;
364
+ line-height: var(--font-leading-4, 16px);
365
+ }
366
+ .tb-dev-menu .vp-preset-btn:hover,.tb-dev-menu .vp-preset-btn.active{background:#f4f4f5}
367
+ .tb-dev-menu .ft{
368
+ margin-top:10px;padding-top:8px;border-top:1px solid #ececf0;
369
+ display:flex;justify-content:flex-end
370
+ }
371
+ .tb-dev-menu .apply-btn{
372
+ border:1px solid #d4d4d8;background:#f8fafc;color:#111827;border-radius:6px;
373
+ height:30px;padding:0 10px;font-size:12px;font-weight:600;cursor:pointer
374
+ }
375
+ .tb-dev-menu .apply-btn:hover{background:#eef2ff;border-color:#a5b4fc}
285
376
  /* Dark icon buttons */
286
377
  .tb-dk-btn{width:28px;height:28px;background:transparent;border:none;border-radius:5px;cursor:pointer;color:#71717a;display:flex;align-items:center;justify-content:center;font-size:13px;transition:all .12s;flex-shrink:0}
287
378
  .tb-dk-btn:hover{color:#e4e4e7;background:rgba(255,255,255,.07)}
@@ -416,7 +507,10 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
416
507
  .dt-ico{width:16px;flex-shrink:0;text-align:center;color:var(--text-3);font-size:12px}
417
508
  .dt-lbl{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,monospace;font-size:10px}
418
509
  .dt-muted{padding:16px 12px;text-align:center;color:var(--text-3);font-size:11px;line-height:1.4}
419
-
510
+ #section-components-panel{
511
+ max-height: 50%;
512
+ overflow-y: auto;
513
+ }
420
514
  /* \u2500\u2500 Right panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
421
515
  #right-panel{
422
516
  width:252px;background:var(--bg);border-left:1px solid var(--border);
@@ -440,7 +534,12 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
440
534
  /* \u2500\u2500 Device frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
441
535
  #device-frame{
442
536
  width:100%;min-height:100%;display:flex;align-items:stretch;
443
- justify-content:center;transition:max-width .3s ease
537
+ justify-content:center;transform-origin:top center;
538
+ transition:max-width .3s ease,width .2s ease,height .2s ease
539
+ }
540
+ #device-frame.desktop{
541
+ max-width:1440px;
542
+ box-shadow:0 0 0 1px var(--border),0 4px 24px rgba(0,0,0,.08)
444
543
  }
445
544
  #device-frame.tablet{
446
545
  max-width:768px;
@@ -540,6 +639,17 @@ html,body{height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFo
540
639
  flex:1;padding:8px 2px;text-align:center;font-size:10px;color:var(--text-3);
541
640
  cursor:pointer;border-bottom:2px solid transparent;transition:all .15s;font-weight:600;line-height:1.15
542
641
  }
642
+ .lp-tab.close-section-components-panel{
643
+ padding: 4px 10px;
644
+ background: #000;
645
+ display: flex;
646
+ max-width: fit-content;
647
+ align-items: center;
648
+ justify-content: center;
649
+ border-radius: 2px;
650
+ margin: 2px;
651
+ color: #fff;
652
+ }
543
653
  .lp-tab:hover{color:var(--text-2)}
544
654
  .lp-tab.active{color:var(--accent-txt);border-bottom-color:var(--accent)}
545
655
  .future-hidden{display:none!important}
@@ -841,10 +951,8 @@ select.pr-inp{cursor:pointer;background:#fff}
841
951
  </head>
842
952
  <body class="mode-editor">
843
953
  <div id="app">
844
-
845
954
  <!-- \u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->
846
955
  <div id="toolbar">
847
-
848
956
  <!-- Left: Logo + Breadcrumb -->
849
957
  <div class="tb-left">
850
958
  <span class="tb-logo">\u2733</span>
@@ -862,11 +970,45 @@ select.pr-inp{cursor:pointer;background:#fff}
862
970
  <span id="dev-label">1440px</span>
863
971
  <i class="bi bi-chevron-down"></i>
864
972
  </div>
865
- <div class="tb-dev-btns">
866
- <button class="tb-dk-btn active" id="dev-desktop" onclick="setDevice('desktop')" title="Desktop \u2014 full width"><i class="bi bi-display"></i></button>
867
- <button class="tb-dk-btn" id="dev-tablet" onclick="setDevice('tablet')" title="Tablet \u2014 768px"><i class="bi bi-tablet"></i></button>
868
- <button class="tb-dk-btn" id="dev-mobile" onclick="setDevice('mobile')" title="Mobile \u2014 390px"><i class="bi bi-phone"></i></button>
869
- <button class="tb-dk-btn" title="More options"><i class="bi bi-three-dots"></i></button>
973
+ <div class="tb-dev-wrap">
974
+ <div class="tb-dev-btns">
975
+ <button class="tb-dk-btn active" id="dev-desktop" onclick="setDevice('desktop')" title="Desktop \u2014 1440x1024"><i class="bi bi-display"></i></button>
976
+ <button class="tb-dk-btn" id="dev-tablet" onclick="setDevice('tablet')" title="Tablet \u2014 768x1024"><i class="bi bi-tablet"></i></button>
977
+ <button class="tb-dk-btn" id="dev-mobile" onclick="setDevice('mobile')" title="Mobile \u2014 390x844"><i class="bi bi-phone"></i></button>
978
+ <button class="tb-dk-btn" id="dev-more-btn" title="More options"><i class="bi bi-three-dots"></i></button>
979
+ </div>
980
+ <div id="dev-more-menu" class="tb-dev-menu" aria-hidden="true">
981
+ <div class="row row-zoom">
982
+ <label for="dev-zoom-level">Zoom</label>
983
+ <input id="dev-zoom-level" type="number" min="25" max="200" step="5" value="100" />
984
+ </div>
985
+ <div class="row row-split row-width height-width-row">
986
+ <div class="row" style="margin:0">
987
+ <label for="dev-custom-width">Width</label>
988
+ <input id="dev-custom-width" type="number" min="240" max="3840" step="1" value="1440" />
989
+ </div>
990
+ <div class="row row-height" style="margin:0">
991
+ <label for="dev-custom-height">Height</label>
992
+ <input id="dev-custom-height" type="number" min="320" max="3840" step="1" value="1024" />
993
+ </div>
994
+ </div>
995
+ <div class="row panel-toggle">
996
+ <label id="left-panel-toggle-label" class="panel-toggle-label">Collapse left panel</label>
997
+ </div>
998
+
999
+ <div class="vp-presets" id="dev-preset-list" aria-label="Device presets">
1000
+ <button type="button" class="vp-preset-btn" data-preset="desktop">Desktop</button>
1001
+ <button type="button" class="vp-preset-btn" data-preset="mobile">iPhone 13</button>
1002
+ <button type="button" class="vp-preset-btn" data-preset="galaxy-s22">Galaxy S22</button>
1003
+ <button type="button" class="vp-preset-btn" data-preset="tablet">iPad</button>
1004
+ <button type="button" class="vp-preset-btn" data-preset="galaxy-j1">Galaxy J1</button>
1005
+ <button type="button" class="vp-preset-btn" data-preset="iphone-7">iPhone 7</button>
1006
+ <button type="button" class="vp-preset-btn" data-preset="responsive">Responsive</button>
1007
+ </div>
1008
+ <div class="ft">
1009
+ <button type="button" class="apply-btn" id="dev-apply-btn">Apply</button>
1010
+ </div>
1011
+ </div>
870
1012
  </div>
871
1013
  <button class="tb-dk-btn" id="btn-undo" title="Undo (\u2318Z)"><i class="bi bi-arrow-counterclockwise"></i></button>
872
1014
  <button class="tb-dk-btn" id="btn-redo" title="Redo (\u2318\u21E7Z)" style="display:none"><i class="bi bi-arrow-clockwise"></i></button>
@@ -1003,7 +1145,7 @@ select.pr-inp{cursor:pointer;background:#fff}
1003
1145
  </div>
1004
1146
 
1005
1147
  <!-- Device frame containing the editing iframe -->
1006
- <div id="device-frame">
1148
+ <div id="device-frame" class="desktop">
1007
1149
  <iframe id="iframeId" name="iframeId" allowfullscreen></iframe>
1008
1150
  </div>
1009
1151
 
@@ -1016,6 +1158,7 @@ select.pr-inp{cursor:pointer;background:#fff}
1016
1158
  <div class="section-components-tabs">
1017
1159
  <div class="lp-tab" onclick="switchSectionComponentsTab('components')">Components</div>
1018
1160
  <div class="lp-tab" onclick="switchSectionComponentsTab('sections')">Sections</div>
1161
+ <div class="lp-tab close-section-components-panel" onclick="toggleSectionComponentsPanel()"> Close</div>
1019
1162
  </div>
1020
1163
  <div class="lp-body">
1021
1164
  <div id="tab-components" class="tab-pane"></div>
@@ -1373,6 +1516,11 @@ var isDirty = false;
1373
1516
  var vvvebReady = false;
1374
1517
  var currentMode = 'editor';
1375
1518
  var currentDevice = 'desktop';
1519
+ var leftPanelCollapsed = false;
1520
+ var viewportPreset = 'desktop';
1521
+ var viewportWidth = 1440;
1522
+ var viewportHeight = 1024;
1523
+ var viewportZoom = 1;
1376
1524
  var selectedEl = null;
1377
1525
  /** Stable selector fingerprint for resilient selection recovery after DOM churn. */
1378
1526
  var selectedElFingerprint = '';
@@ -1625,15 +1773,202 @@ function setMode(mode) {
1625
1773
  }
1626
1774
 
1627
1775
  // \u2500\u2500 Device toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1628
- var DEVICE_LABELS = { desktop: '1440px', tablet: '768px', mobile: '390px' };
1776
+ var DEVICE_PRESETS = {
1777
+ desktop: { label: 'Desktop', width: 1440, height: 1024, device: 'desktop' },
1778
+ tablet: { label: 'iPad', width: 768, height: 1024, device: 'tablet' },
1779
+ mobile: { label: 'iPhone 13', width: 390, height: 844, device: 'mobile' },
1780
+ 'galaxy-s22': { label: 'Galaxy S22', width: 360, height: 780, device: 'mobile' },
1781
+ 'iphone-7': { label: 'iPhone 7', width: 375, height: 667, device: 'mobile' },
1782
+ 'galaxy-j1': { label: 'Galaxy J1', width: 360, height: 640, device: 'mobile' },
1783
+ responsive: { label: 'Responsive', width: 1280, height: 800, device: 'desktop' },
1784
+ };
1785
+
1786
+ function clampViewportNumber(v, fallback, min, max) {
1787
+ var n = parseInt(v, 10);
1788
+ if (!Number.isFinite(n)) return fallback;
1789
+ return Math.max(min, Math.min(max, n));
1790
+ }
1791
+
1792
+ function getViewportFitZoom() {
1793
+ var panel = document.getElementById('iframe-panel');
1794
+ var available = panel ? Math.max(260, panel.clientWidth - 24) : viewportWidth;
1795
+ if (!viewportWidth || viewportWidth <= 0) return 1;
1796
+ return Math.min(1, available / viewportWidth);
1797
+ }
1798
+
1799
+ function getAppliedViewportZoom() {
1800
+ var z = Number(viewportZoom);
1801
+ if (!Number.isFinite(z) || z <= 0) z = 1;
1802
+ z = Math.max(0.25, Math.min(2, z));
1803
+ return Math.min(z, getViewportFitZoom());
1804
+ }
1805
+
1806
+ function updateViewportLabel() {
1807
+ var lbl = document.getElementById('dev-label');
1808
+ if (!lbl) return;
1809
+ var zoomPct = Math.round(getAppliedViewportZoom() * 100);
1810
+ lbl.textContent = viewportWidth + 'x' + viewportHeight + ' \xB7 ' + zoomPct + '%';
1811
+ }
1812
+
1813
+ function syncViewportMenuControls() {
1814
+ var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
1815
+ var widthInp = document.getElementById('dev-custom-width');
1816
+ var heightInp = document.getElementById('dev-custom-height');
1817
+ var zoomInp = document.getElementById('dev-zoom-level');
1818
+ if (presetButtons && presetButtons.length) {
1819
+ for (var i = 0; i < presetButtons.length; i++) {
1820
+ var key = presetButtons[i].getAttribute('data-preset') || '';
1821
+ presetButtons[i].classList.toggle('active', key === viewportPreset);
1822
+ }
1823
+ }
1824
+ if (widthInp) widthInp.value = String(viewportWidth);
1825
+ if (heightInp) heightInp.value = String(viewportHeight);
1826
+ if (zoomInp) zoomInp.value = String(Math.round(getAppliedViewportZoom() * 100));
1827
+ }
1828
+
1829
+ function applyViewportFrame() {
1830
+ var frame = document.getElementById('device-frame');
1831
+ var iframe = document.getElementById('iframeId');
1832
+ if (!frame) return;
1833
+ frame.className = currentDevice;
1834
+ frame.style.width = viewportWidth + 'px';
1835
+ frame.style.height = viewportHeight + 'px';
1836
+ frame.style.maxWidth = 'none';
1837
+ frame.style.zoom = String(getAppliedViewportZoom());
1838
+ if (iframe) {
1839
+ iframe.style.height = viewportHeight + 'px';
1840
+ iframe.style.minHeight = viewportHeight + 'px';
1841
+ }
1842
+ updateViewportLabel();
1843
+ syncViewportMenuControls();
1844
+ if (selectedEl && currentMode === 'editor') requestAnimationFrame(function() { positionSelectionToolbar(); });
1845
+ }
1846
+
1847
+ function setViewportPreset(presetKey) {
1848
+ var preset = DEVICE_PRESETS[presetKey];
1849
+ if (!preset) return;
1850
+ viewportPreset = presetKey;
1851
+ viewportWidth = preset.width;
1852
+ viewportHeight = preset.height;
1853
+ currentDevice = preset.device || 'desktop';
1854
+ ['desktop','tablet','mobile'].forEach(function(d) {
1855
+ document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
1856
+ });
1857
+ applyViewportFrame();
1858
+ }
1859
+
1629
1860
  function setDevice(device) {
1861
+ viewportPreset = device;
1630
1862
  currentDevice = device;
1631
- var frame = document.getElementById('device-frame');
1632
- frame.className = device === 'desktop' ? '' : device;
1863
+ var preset = DEVICE_PRESETS[device] || DEVICE_PRESETS.desktop;
1864
+ viewportWidth = preset.width;
1865
+ viewportHeight = preset.height;
1633
1866
  ['desktop','tablet','mobile'].forEach(function(d) {
1634
1867
  document.getElementById('dev-' + d).classList.toggle('active', d === device);
1635
1868
  });
1636
- document.getElementById('dev-label').textContent = DEVICE_LABELS[device] || device;
1869
+ applyViewportFrame();
1870
+ }
1871
+
1872
+ function setViewportCustomFromInputs() {
1873
+ var widthInp = document.getElementById('dev-custom-width');
1874
+ var heightInp = document.getElementById('dev-custom-height');
1875
+ var zoomInp = document.getElementById('dev-zoom-level');
1876
+ viewportWidth = clampViewportNumber(widthInp ? widthInp.value : '', viewportWidth, 240, 3840);
1877
+ viewportHeight = clampViewportNumber(heightInp ? heightInp.value : '', viewportHeight, 320, 3840);
1878
+ var z = clampViewportNumber(zoomInp ? zoomInp.value : '', Math.round(getAppliedViewportZoom() * 100), 25, 200);
1879
+ viewportZoom = z / 100;
1880
+ viewportPreset = 'custom';
1881
+ currentDevice = viewportWidth <= 480 ? 'mobile' : (viewportWidth <= 1024 ? 'tablet' : 'desktop');
1882
+ ['desktop','tablet','mobile'].forEach(function(d) {
1883
+ document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
1884
+ });
1885
+ applyViewportFrame();
1886
+ }
1887
+
1888
+ function closeViewportMenu() {
1889
+ var menu = document.getElementById('dev-more-menu');
1890
+ if (!menu) return;
1891
+ menu.classList.remove('open');
1892
+ menu.setAttribute('aria-hidden', 'true');
1893
+ }
1894
+
1895
+ function toggleViewportMenu() {
1896
+ var menu = document.getElementById('dev-more-menu');
1897
+ if (!menu) return;
1898
+ var shouldOpen = !menu.classList.contains('open');
1899
+ menu.classList.toggle('open', shouldOpen);
1900
+ menu.setAttribute('aria-hidden', shouldOpen ? 'false' : 'true');
1901
+ }
1902
+
1903
+ function bindViewportControls() {
1904
+ var btn = document.getElementById('dev-more-btn');
1905
+ var menu = document.getElementById('dev-more-menu');
1906
+ var leftPanelToggleLabel = document.getElementById('left-panel-toggle-label');
1907
+ var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
1908
+ var applyBtn = document.getElementById('dev-apply-btn');
1909
+ var zoomInp = document.getElementById('dev-zoom-level');
1910
+ var viewportBtn = document.querySelector('.tb-viewport');
1911
+ function updateLeftPanelToggleLabel() {
1912
+ if (!leftPanelToggleLabel) return;
1913
+ leftPanelToggleLabel.textContent = leftPanelCollapsed ? 'Expand left panel' : 'Collapse left panel';
1914
+ }
1915
+ function setLeftPanelCollapsed(collapsed) {
1916
+ var panel = document.getElementById('left-panel');
1917
+ leftPanelCollapsed = !!collapsed;
1918
+ if (panel) panel.style.display = leftPanelCollapsed ? 'none' : '';
1919
+ updateLeftPanelToggleLabel();
1920
+ applyViewportFrame();
1921
+ }
1922
+ if (leftPanelToggleLabel) {
1923
+ leftPanelToggleLabel.addEventListener('click', function(e) {
1924
+ e.preventDefault();
1925
+ e.stopPropagation();
1926
+ setLeftPanelCollapsed(!leftPanelCollapsed);
1927
+ });
1928
+ }
1929
+ if (btn) btn.addEventListener('click', function(e) {
1930
+ e.preventDefault();
1931
+ e.stopPropagation();
1932
+ toggleViewportMenu();
1933
+ });
1934
+ if (viewportBtn) viewportBtn.addEventListener('click', function(e) {
1935
+ e.preventDefault();
1936
+ e.stopPropagation();
1937
+ toggleViewportMenu();
1938
+ });
1939
+ if (applyBtn) applyBtn.addEventListener('click', function(e) {
1940
+ e.preventDefault();
1941
+ setViewportCustomFromInputs();
1942
+ closeViewportMenu();
1943
+ });
1944
+ if (zoomInp) {
1945
+ zoomInp.addEventListener('change', function() {
1946
+ var z = clampViewportNumber(zoomInp.value, Math.round(getAppliedViewportZoom() * 100), 25, 200);
1947
+ viewportZoom = z / 100;
1948
+ applyViewportFrame();
1949
+ });
1950
+ }
1951
+ if (presetButtons && presetButtons.length) {
1952
+ for (var i = 0; i < presetButtons.length; i++) {
1953
+ presetButtons[i].addEventListener('click', function(e) {
1954
+ e.preventDefault();
1955
+ var key = this.getAttribute('data-preset');
1956
+ if (!key) return;
1957
+ setViewportPreset(key);
1958
+ });
1959
+ }
1960
+ }
1961
+ document.addEventListener('click', function(e) {
1962
+ if (!menu || !menu.classList.contains('open')) return;
1963
+ if (menu.contains(e.target) || (btn && btn.contains(e.target)) || (viewportBtn && viewportBtn.contains(e.target))) return;
1964
+ closeViewportMenu();
1965
+ });
1966
+ document.addEventListener('keydown', function(e) {
1967
+ if (e.key === 'Escape') closeViewportMenu();
1968
+ });
1969
+ window.addEventListener('resize', function() { applyViewportFrame(); });
1970
+ updateLeftPanelToggleLabel();
1971
+ applyViewportFrame();
1637
1972
  }
1638
1973
 
1639
1974
  // \u2500\u2500 Left panel tab switch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
@@ -1795,9 +2130,60 @@ function getOriginalValue(inputId, el) {
1795
2130
  }
1796
2131
  }
1797
2132
 
2133
+ var PX_DEFAULT_INPUT_IDS = {
2134
+ 'pp-mt': true, 'pp-mr': true, 'pp-mb': true, 'pp-ml': true,
2135
+ 'pp-pt': true, 'pp-pr': true, 'pp-pb': true, 'pp-pl': true,
2136
+ };
2137
+
2138
+ var PX_DEFAULT_CSS_PROPS = {
2139
+ 'margin-top': true, 'margin-right': true, 'margin-bottom': true, 'margin-left': true,
2140
+ 'padding-top': true, 'padding-right': true, 'padding-bottom': true, 'padding-left': true,
2141
+ };
2142
+
2143
+ function normalizeCssValueForProperty(prop, value) {
2144
+ var p = prop == null ? '' : String(prop).trim();
2145
+ var pKebab = p
2146
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
2147
+ .replace(/_/g, '-')
2148
+ .replace(/!important/gi, '')
2149
+ .replace(/[^a-zA-Z-]/g, '')
2150
+ .toLowerCase();
2151
+ var raw = value == null ? '' : String(value).trim();
2152
+ var rawClean = raw.replace(/[\u200B\u200C\u200D\uFEFF]/g, '').trim();
2153
+ var numericCandidate = rawClean.replace(/[, ]+/g, '');
2154
+ var isSpacingProp = /^(?:margin|padding)(?:-(?:top|right|bottom|left))?$/.test(pKebab);
2155
+ if (!pKebab || !rawClean) return rawClean;
2156
+ var numericValue = Number(numericCandidate);
2157
+ var shouldAddPx =
2158
+ isSpacingProp &&
2159
+ numericCandidate !== '' &&
2160
+ Number.isFinite(numericValue) &&
2161
+ /^[-+]?(?:[0-9]+(?:[.][0-9]+)?|[.][0-9]+)$/.test(numericCandidate);
2162
+ var out = shouldAddPx ? numericCandidate + 'px' : rawClean;
2163
+ return out;
2164
+ }
2165
+
2166
+ function normalizeChainSetRowUnits(row) {
2167
+ if (!row) return row;
2168
+ if (normalizeChangesetType(row) === 'style') {
2169
+ row.value = normalizeCssValueForProperty(row.property || row.cssProp, row.value);
2170
+ }
2171
+ return row;
2172
+ }
2173
+
2174
+ function normalizeLoggedValue(inputId, value) {
2175
+ var raw = value == null ? '' : String(value).trim();
2176
+ if (!raw) return raw;
2177
+ if (PX_DEFAULT_INPUT_IDS[inputId] && /^-?d+(?:.d+)?$/.test(raw)) {
2178
+ return raw + 'px';
2179
+ }
2180
+ return raw;
2181
+ }
2182
+
1798
2183
  function logChange(selector, inputId, value, targetEl, originalValue) {
1799
2184
  var meta = PROP_META[inputId];
1800
2185
  if (!meta) return;
2186
+ value = normalizeLoggedValue(inputId, value);
1801
2187
  var key = selector + '||' + inputId;
1802
2188
  // Skip trivially empty / reset values \u2014 remove from log if present
1803
2189
  if (value === '' || value === 'none' || value === 'auto' || value === 'normal') {
@@ -2496,9 +2882,24 @@ function pickActiveVariationIdForLoad(data, variationsArr, prevMemoryId, allowPr
2496
2882
  return fallback;
2497
2883
  }
2498
2884
 
2885
+ function updateExperimentNameLabel(data) {
2886
+ var el = document.getElementById('tb-exp-name');
2887
+ if (!el) return;
2888
+ var name = '';
2889
+ try {
2890
+ name = data && data.name != null ? String(data.name).trim() : '';
2891
+ } catch(_) {
2892
+ name = '';
2893
+ }
2894
+ if (!name) name = 'Visual Editor';
2895
+ el.textContent = name;
2896
+ el.title = name;
2897
+ }
2898
+
2499
2899
  // \u2500\u2500 Experiment loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
2500
2900
  function handleLoadExperiment(data) {
2501
2901
  clearPendingGranularChangesets();
2902
+ updateExperimentNameLabel(data);
2502
2903
  var prevKey = experimentData
2503
2904
  ? String(experimentData.experimentId || '') + '|' + String(experimentData.pageUrl || '')
2504
2905
  : '';
@@ -3140,7 +3541,13 @@ function removeSessionStructuralRowByTimestamp(varId, ts) {
3140
3541
  function stateChangeToChainSet(c) {
3141
3542
  if (!c || !c.selector) return null;
3142
3543
  if (c.cssProp) {
3143
- return { selector: c.selector, type: 'style', property: c.cssProp, value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
3544
+ return {
3545
+ selector: c.selector,
3546
+ type: 'style',
3547
+ property: c.cssProp,
3548
+ value: normalizeCssValueForProperty(c.cssProp, c.value),
3549
+ vveTs: c.vveTs || nextHistoryTimestamp()
3550
+ };
3144
3551
  }
3145
3552
  switch (c.inputId) {
3146
3553
  case 'pp-text':
@@ -3312,7 +3719,7 @@ function buildPersistentStyleRulesForActiveVariation() {
3312
3719
  if (value == null || value === '') return;
3313
3720
  var sel = sanitizeSelectorForMatch(String(selector)) || String(selector);
3314
3721
  var pr = String(prop).trim();
3315
- var val = String(value).trim();
3722
+ var val = normalizeCssValueForProperty(pr, value);
3316
3723
  if (!sel || !pr || !val) return;
3317
3724
  var k = sel + '__vve_sep__' + pr;
3318
3725
  if (!map[k]) order.push(k);
@@ -3350,7 +3757,8 @@ function buildPersistentStyleRulesForActiveVariation() {
3350
3757
  var lines = [];
3351
3758
  for (var oi = 0; oi < order.length; oi++) {
3352
3759
  var row = map[order[oi]];
3353
- lines.push(row.selector + ' { ' + row.property + ': ' + row.value + ' !important; }');
3760
+ var outVal = normalizeCssValueForProperty(row.property, row.value);
3761
+ lines.push(row.selector + ' { ' + row.property + ': ' + outVal + ' !important; }');
3354
3762
  }
3355
3763
  return lines.join('\\n');
3356
3764
  }
@@ -3501,7 +3909,9 @@ function buildPersistedChainSetsForVariation(v) {
3501
3909
  var row = stateChangeToChainSet(sourceStateChanges[si]);
3502
3910
  if (row) overlay.push(row);
3503
3911
  }
3504
- return mergeGranularChainSets(mergeGranularChainSets(base, sessionExtra), overlay);
3912
+ var merged = mergeGranularChainSets(mergeGranularChainSets(base, sessionExtra), overlay);
3913
+ for (var mi = 0; mi < merged.length; mi++) normalizeChainSetRowUnits(merged[mi]);
3914
+ return merged;
3505
3915
  }
3506
3916
 
3507
3917
  /**
@@ -5403,6 +5813,7 @@ function registerCROSections() {
5403
5813
 
5404
5814
  window.addEventListener('load', function() {
5405
5815
  registerCROSections();
5816
+ bindViewportControls();
5406
5817
  switchSectionComponentsTab(currentSectionComponentsTab);
5407
5818
  renderElementsTree(document.getElementById('comp-search').value);
5408
5819
  vvvebReady = true;
@@ -5779,6 +6190,10 @@ function createVisualEditorMiddleware(options) {
5779
6190
  };
5780
6191
  const upstreamFetch = async (input, init = {}) => {
5781
6192
  if (conversionProxyBaseUrlForRequest) {
6193
+ const method2 = String(init?.method || "GET").toUpperCase();
6194
+ if (method2 !== "GET" && method2 !== "HEAD") {
6195
+ return directFetch(input, init);
6196
+ }
5782
6197
  return workerRawFetch(input, init);
5783
6198
  }
5784
6199
  const primary = await scraperFetch(input, init);
@@ -6110,8 +6525,60 @@ ${runtimePreflightScript}
6110
6525
  var TARGET_ORIGIN=${JSON.stringify(origin)};
6111
6526
  var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
6112
6527
  var EMPTY_JSON_DATA="data:application/json;charset=utf-8,%7B%7D";
6113
- function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#")||raw.startsWith("http")||raw.startsWith("//");}
6114
- function toAbsoluteOriginUrl(raw){if(isSkippable(raw))return raw;try{var base=raw.startsWith("/")?TARGET_ORIGIN:TARGET_PAGE_URL;var abs=new URL(raw,base);if(abs.origin!==TARGET_ORIGIN)return raw;return abs.toString();}catch(_){return raw;}}
6528
+ var _proxyCtx=(function(){try{return new URL(window.location.href);}catch(_){return null;}})();
6529
+ var PROXY_ROOT="/api/conversion-proxy";
6530
+ var PROXY_PASSWORD=_proxyCtx?_proxyCtx.searchParams.get("password")||"":"";
6531
+ var PROXY_BASE_URL=_proxyCtx?_proxyCtx.searchParams.get("conversionProxyBaseUrl")||"":"";
6532
+ var PROXY_TRACKING_MARKERS=_proxyCtx?_proxyCtx.searchParams.get("trackingMarkers")||"":"";
6533
+ var PROXY_STRICT_FREEZE=_proxyCtx?_proxyCtx.searchParams.get("strictObserverFreeze")||"":"";
6534
+ var PROXY_UPSTREAM_MODE=_proxyCtx?_proxyCtx.searchParams.get("proxy")||"":"";
6535
+ var EDITOR_ORIGIN=(function(){try{return String(window.location.origin||"");}catch(_){return "";}})();
6536
+ var EDITOR_HOST_KEY=(function(){try{var u=new URL(EDITOR_ORIGIN);return (u.hostname||"").toLowerCase()+":"+(u.port||"");}catch(_){return "";}})();
6537
+ function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
6538
+ function isEditorHostUrl(u){
6539
+ try{
6540
+ if(!u) return false;
6541
+ var hostKey=(u.hostname||"").toLowerCase()+":"+(u.port||"");
6542
+ if(EDITOR_HOST_KEY&&hostKey===EDITOR_HOST_KEY) return true;
6543
+ // localhost aliases for same dev server port
6544
+ var host=(u.hostname||"").toLowerCase();
6545
+ var editorHost=EDITOR_HOST_KEY.split(":")[0]||"";
6546
+ var samePort=(u.port||"")===(EDITOR_HOST_KEY.split(":")[1]||"");
6547
+ var localAlias=(host==="localhost"||host==="127.0.0.1"||host==="[::1]");
6548
+ var editorLocalAlias=(editorHost==="localhost"||editorHost==="127.0.0.1"||editorHost==="[::1]");
6549
+ return samePort&&localAlias&&editorLocalAlias;
6550
+ }catch(_){
6551
+ return false;
6552
+ }
6553
+ }
6554
+ function toProxyNetworkUrl(raw){
6555
+ if(isSkippable(raw))return raw;
6556
+ try{
6557
+ var base=raw.startsWith("/")?TARGET_ORIGIN:TARGET_PAGE_URL;
6558
+ var abs=new URL(raw,base);
6559
+ // Some embedded scripts build absolute requests against editor origin
6560
+ // (e.g. https://localhost:4001/api/unstable/graphql.json). Remap those
6561
+ // paths to target origin first, then proxy as usual.
6562
+ if(EDITOR_ORIGIN&&isEditorHostUrl(abs)){
6563
+ var p=abs.pathname||"";
6564
+ var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;
6565
+ if(!isRootProxyPath){
6566
+ abs=new URL((abs.pathname||"/")+(abs.search||"")+(abs.hash||""),TARGET_ORIGIN);
6567
+ }
6568
+ }
6569
+ if(abs.origin!==TARGET_ORIGIN)return raw;
6570
+ var prox=new URL(PROXY_ROOT,window.location.origin);
6571
+ prox.searchParams.set("password",PROXY_PASSWORD||"");
6572
+ prox.searchParams.set("url",abs.toString());
6573
+ if(PROXY_BASE_URL)prox.searchParams.set("conversionProxyBaseUrl",PROXY_BASE_URL);
6574
+ if(PROXY_TRACKING_MARKERS)prox.searchParams.set("trackingMarkers",PROXY_TRACKING_MARKERS);
6575
+ if(PROXY_STRICT_FREEZE)prox.searchParams.set("strictObserverFreeze",PROXY_STRICT_FREEZE);
6576
+ if(PROXY_UPSTREAM_MODE)prox.searchParams.set("proxy",PROXY_UPSTREAM_MODE);
6577
+ return prox.toString();
6578
+ }catch(_){
6579
+ return raw;
6580
+ }
6581
+ }
6115
6582
  function resolveUrl(s){try{return new URL(s,window.location.href);}catch(_){return null;}}
6116
6583
  function isNestedMalformedProxy(u){if(!u)return false;var p=u.pathname||"";if(p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0)return false;return p.indexOf("api/conversion-proxy")!==-1;}
6117
6584
  function skipNestedProxyNetwork(s){var u=typeof s==="string"?resolveUrl(s):null;return u&&isNestedMalformedProxy(u);}
@@ -6124,9 +6591,9 @@ if(window.fetch){
6124
6591
  var rawUrl=typeof input==="string"?input:(input&&input.url?String(input.url):"");
6125
6592
  if(rawUrl&&skipNestedProxyNetwork(rawUrl))return emptyJsonFetchResponse();
6126
6593
  if(typeof input==="string"){
6127
- input=toAbsoluteOriginUrl(input);
6594
+ input=toProxyNetworkUrl(input);
6128
6595
  }else if(input&&input.url){
6129
- var next=toAbsoluteOriginUrl(input.url);
6596
+ var next=toProxyNetworkUrl(input.url);
6130
6597
  if(next!==input.url){input=new Request(next,input);}
6131
6598
  }
6132
6599
  afterUrl=typeof input==="string"?input:(input&&input.url?String(input.url):"");
@@ -6160,7 +6627,7 @@ if(window.fetch){
6160
6627
  });
6161
6628
  };
6162
6629
  }
6163
- if(window.XMLHttpRequest&&window.XMLHttpRequest.prototype&&window.XMLHttpRequest.prototype.open){var _open=window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open=function(method,url){try{var u=resolveUrl(String(url));if(u&&isNestedMalformedProxy(u)){arguments[1]=EMPTY_JSON_DATA;}else{arguments[1]=toAbsoluteOriginUrl(url);}}catch(_){}return _open.apply(this,arguments);};}
6630
+ if(window.XMLHttpRequest&&window.XMLHttpRequest.prototype&&window.XMLHttpRequest.prototype.open){var _open=window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open=function(method,url){try{var u=resolveUrl(String(url));if(u&&isNestedMalformedProxy(u)){arguments[1]=EMPTY_JSON_DATA;}else{arguments[1]=toProxyNetworkUrl(url);}}catch(_){}return _open.apply(this,arguments);};}
6164
6631
  if(window.navigator&&typeof window.navigator.sendBeacon==="function"){var _beacon=window.navigator.sendBeacon.bind(window.navigator);window.navigator.sendBeacon=function(url,data){try{if(skipNestedProxyNetwork(String(url)))return true;}catch(_){}return _beacon(url,data);};}
6165
6632
  function withReloadBust(urlRaw){try{var u=resolveUrl(String(urlRaw||""));if(!u)return null;var p=u.pathname||"";var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;if(!isRootProxyPath)return null;return u.toString();}catch(_){return null;}}
6166
6633
  document.addEventListener("click",function(ev){try{var t=ev&&ev.target;if(!t||!t.closest)return;var a=t.closest("a[href]");if(a){var href=a.getAttribute("href")||a.href||"";var hasModifier=!!(ev.metaKey||ev.ctrlKey||ev.shiftKey||ev.altKey);var targetAttr=(a.getAttribute("target")||"").toLowerCase();var isNewTab=targetAttr==="_blank";var isDownload=!!a.getAttribute("download");if(hasModifier||isNewTab||isDownload)return;var prox=toProxy(href);if(!prox)return;a.setAttribute("href",prox);if(ev&&typeof ev.preventDefault==="function")ev.preventDefault();safeNavigate(href,"assign");return;}var summary=t.closest("summary[data-link]");if(summary&&summary.getAttribute){var raw=summary.getAttribute("data-link")||"";if(raw){var prox2=toProxy(raw);if(prox2){summary.setAttribute("data-link",prox2);if(ev&&typeof ev.preventDefault==="function")ev.preventDefault();safeNavigate(raw,"assign");}}}}catch(_){}},true);