@accelerated-agency/visual-editor 0.2.9 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { create } from 'zustand';
4
4
  import { persist } from 'zustand/middleware';
5
5
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
6
  import { HexColorPicker } from 'react-colorful';
7
+ import 'bootstrap-icons/font/bootstrap-icons.css';
7
8
 
8
9
  var PERSIST_NAME_PREFIX = "conversion-editor-variations-v3-";
9
10
  function variationsPersistStorageName(experimentId) {
@@ -4833,6 +4834,7 @@ function PlatformVisualEditorV2({
4833
4834
  }) {
4834
4835
  const iframeRef = useRef(null);
4835
4836
  const [editorReady, setEditorReady] = useState(false);
4837
+ const [isSaving, setIsSaving] = useState(false);
4836
4838
  const [dirty, setDirty] = useState(false);
4837
4839
  const dirtyRef = useRef(false);
4838
4840
  const mutationSkipCountRef = useRef(0);
@@ -5020,5 +5022,344 @@ function PlatformVisualEditorV2({
5020
5022
  ) })
5021
5023
  ] });
5022
5024
  }
5025
+ var AI_EDITOR_CHANNEL = "ve-ai-editor";
5026
+ var AI_VIEWPORT_WIDTH = {
5027
+ desktop: "100%",
5028
+ tablet: "768px",
5029
+ mobile: "390px"
5030
+ };
5031
+ var AI_VIEWPORT_LABEL = {
5032
+ desktop: "1440px",
5033
+ tablet: "768px",
5034
+ mobile: "390px"
5035
+ };
5036
+ function fingerprint(value) {
5037
+ let hash = 5381;
5038
+ for (let index = 0; index < value.length; index += 1) {
5039
+ hash = hash * 33 ^ value.charCodeAt(index);
5040
+ }
5041
+ return (hash >>> 0).toString(36);
5042
+ }
5043
+ function PlatformAiEditor({
5044
+ embeddedGlobalKey = "__CONVERSION_EMBEDDED__",
5045
+ proxyBaseUrl = "",
5046
+ chatComponent,
5047
+ className = "fixed inset-0 z-[9999] flex flex-col bg-white",
5048
+ editorClassName = "flex-1 min-h-0",
5049
+ showHeader = true,
5050
+ title,
5051
+ status,
5052
+ tabs = [],
5053
+ activeTab = "AI Editor",
5054
+ error = null,
5055
+ showCloseButton = true,
5056
+ closeLabel = "Close",
5057
+ experiment,
5058
+ activeVariationId: controlledActiveVariationId,
5059
+ onClose,
5060
+ onTabChange,
5061
+ onDirtyChange,
5062
+ onEditorReady,
5063
+ onEditorUrlChanged,
5064
+ onSaveSuccess,
5065
+ onSaveError,
5066
+ onRequestSave,
5067
+ renderHeader,
5068
+ renderError,
5069
+ setActiveVariationId: controlledSetActiveVariationId
5070
+ }) {
5071
+ const iframeRef = useRef(null);
5072
+ const [localActiveVariationId, setLocalActiveVariationId] = useState(null);
5073
+ const [isSaving, setIsSaving] = useState(false);
5074
+ const [isIframeLoading, setIsIframeLoading] = useState(false);
5075
+ const [viewport, setViewport] = useState("desktop");
5076
+ useEffect(() => {
5077
+ window[embeddedGlobalKey] = true;
5078
+ return () => {
5079
+ delete window[embeddedGlobalKey];
5080
+ };
5081
+ }, [embeddedGlobalKey]);
5082
+ useEffect(() => {
5083
+ onDirtyChange?.(false);
5084
+ }, [onDirtyChange]);
5085
+ const variations = experiment?.variations ?? [];
5086
+ const activeVariationId = controlledActiveVariationId ?? localActiveVariationId;
5087
+ const setActiveVariationId = controlledSetActiveVariationId ?? setLocalActiveVariationId;
5088
+ useEffect(() => {
5089
+ if (!variations.length) {
5090
+ setActiveVariationId(null);
5091
+ return;
5092
+ }
5093
+ setActiveVariationId((current) => {
5094
+ if (current && variations.some((variation) => variation._id === current)) return current;
5095
+ const baseline = variations.find((variation) => variation.baseline);
5096
+ return baseline?._id ?? variations[0]._id;
5097
+ });
5098
+ }, [variations]);
5099
+ const activeVariation = useMemo(
5100
+ () => variations.find((variation) => variation._id === activeVariationId) ?? null,
5101
+ [variations, activeVariationId]
5102
+ );
5103
+ const effectiveCssCode = useMemo(() => {
5104
+ return (activeVariation?.csscode ?? "").trim();
5105
+ }, [activeVariation?.csscode]);
5106
+ const effectiveJsCode = useMemo(() => {
5107
+ return (activeVariation?.jscode ?? "").trim();
5108
+ }, [activeVariation?.jscode]);
5109
+ const cssFingerprint = useMemo(() => fingerprint(effectiveCssCode), [effectiveCssCode]);
5110
+ const jsFingerprint = useMemo(() => fingerprint(effectiveJsCode), [effectiveJsCode]);
5111
+ const hasAiCode = useMemo(
5112
+ () => Boolean(effectiveCssCode.trim() || effectiveJsCode.trim()),
5113
+ [effectiveCssCode, effectiveJsCode]
5114
+ );
5115
+ const iframeKey = useMemo(
5116
+ () => `ai-iframe-${activeVariationId ?? "default"}-${cssFingerprint}-${jsFingerprint}`,
5117
+ [activeVariationId, cssFingerprint, jsFingerprint]
5118
+ );
5119
+ const iframeWidth = AI_VIEWPORT_WIDTH[viewport];
5120
+ const editorSrc = useMemo(() => {
5121
+ const pageUrl = experiment?.pageUrl;
5122
+ if (!pageUrl) return "about:blank";
5123
+ const safeBaseUrl = normalizeProxyBaseUrl(proxyBaseUrl);
5124
+ const query = new URLSearchParams({
5125
+ password: experiment?.editorPassword ?? "",
5126
+ url: pageUrl
5127
+ }).toString();
5128
+ const previewPath = `/api/conversion-proxy?${query}`;
5129
+ return safeBaseUrl ? `${safeBaseUrl}${previewPath}` : previewPath;
5130
+ }, [proxyBaseUrl, experiment?.pageUrl, experiment?.editorPassword]);
5131
+ const postAiCodeToIframe = useCallback(() => {
5132
+ const targetWindow = iframeRef.current?.contentWindow;
5133
+ if (!targetWindow) return;
5134
+ targetWindow.postMessage(
5135
+ {
5136
+ channel: AI_EDITOR_CHANNEL,
5137
+ type: "apply-ai-code",
5138
+ payload: {
5139
+ cssCode: effectiveCssCode,
5140
+ jsCode: effectiveJsCode
5141
+ }
5142
+ },
5143
+ "*"
5144
+ );
5145
+ }, [effectiveCssCode, effectiveJsCode]);
5146
+ const parseProxyPayloadFromUrl = useCallback((rawUrl) => {
5147
+ if (!rawUrl) return null;
5148
+ try {
5149
+ const parsed = new URL(rawUrl, window.location.href);
5150
+ const url = parsed.searchParams.get("url") ?? void 0;
5151
+ const password = parsed.searchParams.get("password") ?? void 0;
5152
+ return { url, password };
5153
+ } catch {
5154
+ return null;
5155
+ }
5156
+ }, []);
5157
+ const applyAiCodeInIframe = useCallback(() => {
5158
+ postAiCodeToIframe();
5159
+ }, [postAiCodeToIframe]);
5160
+ useEffect(() => {
5161
+ applyAiCodeInIframe();
5162
+ }, [applyAiCodeInIframe]);
5163
+ useEffect(() => {
5164
+ if (!hasAiCode) {
5165
+ setIsIframeLoading(false);
5166
+ return;
5167
+ }
5168
+ setIsIframeLoading(true);
5169
+ const timeoutId = window.setTimeout(() => {
5170
+ setIsIframeLoading(false);
5171
+ }, 5e3);
5172
+ return () => window.clearTimeout(timeoutId);
5173
+ }, [hasAiCode, cssFingerprint, jsFingerprint, activeVariationId]);
5174
+ const handleIframeLoad = useCallback(() => {
5175
+ applyAiCodeInIframe();
5176
+ postAiCodeToIframe();
5177
+ const currentSrc = iframeRef.current?.src ?? null;
5178
+ const proxiedPayload = parseProxyPayloadFromUrl(currentSrc);
5179
+ if (proxiedPayload?.url || proxiedPayload?.password) {
5180
+ void onEditorUrlChanged?.(proxiedPayload);
5181
+ }
5182
+ onEditorReady?.();
5183
+ }, [
5184
+ applyAiCodeInIframe,
5185
+ postAiCodeToIframe,
5186
+ onEditorReady,
5187
+ onEditorUrlChanged,
5188
+ parseProxyPayloadFromUrl
5189
+ ]);
5190
+ useEffect(() => {
5191
+ const onMessage = (event) => {
5192
+ const msg = event.data;
5193
+ if (!msg || msg.channel !== AI_EDITOR_CHANNEL) return;
5194
+ if (msg.type === "ai-code-ready") {
5195
+ postAiCodeToIframe();
5196
+ return;
5197
+ }
5198
+ if (msg.type === "ai-url-changed") {
5199
+ const payload = msg.payload ?? {};
5200
+ void onEditorUrlChanged?.({
5201
+ url: payload.url,
5202
+ password: payload.password
5203
+ });
5204
+ return;
5205
+ }
5206
+ if (msg.type === "ai-code-applied") {
5207
+ setIsIframeLoading(false);
5208
+ }
5209
+ };
5210
+ window.addEventListener("message", onMessage);
5211
+ return () => window.removeEventListener("message", onMessage);
5212
+ }, [postAiCodeToIframe, onEditorUrlChanged]);
5213
+ const onTabClick = useCallback(
5214
+ (tab) => onTabChange?.(tab),
5215
+ [onTabChange]
5216
+ );
5217
+ const handleSave = useCallback(async () => {
5218
+ if (!onRequestSave || isSaving) return;
5219
+ const payload = {
5220
+ experimentId: experiment?.experimentId,
5221
+ variations,
5222
+ cssCode: effectiveCssCode,
5223
+ jsCode: effectiveJsCode,
5224
+ selectedVariationId: activeVariation?._id,
5225
+ selectedVariation: activeVariation ?? void 0
5226
+ };
5227
+ setIsSaving(true);
5228
+ try {
5229
+ await onRequestSave(payload);
5230
+ onSaveSuccess?.(payload);
5231
+ } catch (error2) {
5232
+ onSaveError?.(error2);
5233
+ } finally {
5234
+ setIsSaving(false);
5235
+ }
5236
+ }, [
5237
+ onRequestSave,
5238
+ isSaving,
5239
+ experiment?.experimentId,
5240
+ variations,
5241
+ effectiveCssCode,
5242
+ effectiveJsCode,
5243
+ activeVariation,
5244
+ onSaveSuccess,
5245
+ onSaveError
5246
+ ]);
5247
+ if (error) {
5248
+ if (renderError) return renderError(error);
5249
+ return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center bg-slate-50", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 text-center px-8", children: [
5250
+ /* @__PURE__ */ jsx("div", { className: "text-2xl text-red-300", children: "\u26A0" }),
5251
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-slate-700", children: "Something went wrong" }),
5252
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-red-400", children: error })
5253
+ ] }) });
5254
+ }
5255
+ return /* @__PURE__ */ jsxs("div", { className, children: [
5256
+ showHeader ? renderHeader?.({
5257
+ title: title ?? experiment?.name,
5258
+ status: status ?? experiment?.status,
5259
+ tabs,
5260
+ activeTab,
5261
+ onTabClick,
5262
+ onClose
5263
+ }) ?? /* @__PURE__ */ jsxs("div", { className: "h-12 border-b border-slate-200 bg-white flex items-center justify-between px-4 shadow-[0_1px_3px_rgba(0,0,0,0.04)] shrink-0", children: [
5264
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 min-w-0", children: [
5265
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-bold tracking-wide px-1.5 py-0.5 rounded bg-indigo-50 text-indigo-600 border border-indigo-100 shrink-0", children: "AI" }),
5266
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-sm text-slate-800 truncate", children: title ?? experiment?.name ?? "AI Editor" }),
5267
+ status ? /* @__PURE__ */ jsx("span", { className: "hidden sm:inline-flex text-[10px] px-2 py-0.5 rounded-full border border-slate-200 text-slate-500 font-medium bg-slate-50 capitalize", children: status }) : null
5268
+ ] }),
5269
+ tabs.length > 0 ? /* @__PURE__ */ jsx("div", { className: "hidden md:flex items-center gap-1 absolute left-1/2 -translate-x-1/2", children: tabs.map((tab) => /* @__PURE__ */ jsx(
5270
+ "button",
5271
+ {
5272
+ type: "button",
5273
+ onClick: () => onTabClick(tab),
5274
+ className: `text-[11px] font-semibold px-3 py-1 rounded-full border transition-all ${tab.label === activeTab ? "bg-indigo-600 text-white border-indigo-600 shadow-sm" : "bg-white text-slate-500 border-slate-200 hover:border-slate-300 hover:text-slate-700"}`,
5275
+ children: tab.label
5276
+ },
5277
+ tab.hash
5278
+ )) }) : null,
5279
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5280
+ /* @__PURE__ */ jsxs("div", { className: "h-8 px-3 rounded-md border border-slate-200 bg-white flex items-center gap-2 text-xs font-medium text-slate-700", children: [
5281
+ /* @__PURE__ */ jsx("span", { children: AI_VIEWPORT_LABEL[viewport] }),
5282
+ /* @__PURE__ */ jsx("i", { className: "bi bi-chevron-down text-[10px] text-slate-500" })
5283
+ ] }),
5284
+ /* @__PURE__ */ jsx("div", { className: "h-8 rounded-lg bg-slate-100 px-1 flex items-center gap-1", style: { backgroundColor: "#F0F0F0" }, children: [
5285
+ { key: "desktop", icon: "bi-display", title: "Desktop \u2014 full width" },
5286
+ { key: "tablet", icon: "bi-tablet", title: "Tablet \u2014 768px" },
5287
+ { key: "mobile", icon: "bi-phone", title: "Mobile \u2014 390px" }
5288
+ ].map((vp) => /* @__PURE__ */ jsx(
5289
+ "button",
5290
+ {
5291
+ type: "button",
5292
+ onClick: () => setViewport(vp.key),
5293
+ title: vp.title,
5294
+ className: `w-7 h-7 rounded-md border flex items-center justify-center transition-all ${viewport === vp.key ? "bg-white border-slate-300 text-slate-700 shadow-sm" : "bg-transparent border-transparent text-slate-500 hover:text-slate-700 hover:bg-white/70"}`,
5295
+ children: /* @__PURE__ */ jsx("i", { className: `bi ${vp.icon} text-[12px]` })
5296
+ },
5297
+ vp.key
5298
+ )) })
5299
+ ] }),
5300
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5301
+ variations.length > 0 ? /* @__PURE__ */ jsx(
5302
+ "select",
5303
+ {
5304
+ className: "h-8 max-w-[220px] rounded-md border border-slate-200 bg-white px-2 text-xs text-slate-700",
5305
+ value: activeVariationId ?? "",
5306
+ onChange: (event) => setActiveVariationId(event.target.value || null),
5307
+ "aria-label": "Select variation",
5308
+ children: variations.map((variation) => /* @__PURE__ */ jsx("option", { value: variation._id, children: variation.name }, variation._id))
5309
+ }
5310
+ ) : null,
5311
+ onRequestSave ? /* @__PURE__ */ jsx(
5312
+ "button",
5313
+ {
5314
+ type: "button",
5315
+ className: "text-[11px] font-medium px-3 py-1.5 rounded-md border border-indigo-200 text-indigo-700 bg-indigo-50 hover:bg-indigo-100 hover:border-indigo-300 transition-all disabled:opacity-60 disabled:cursor-not-allowed",
5316
+ onClick: () => void handleSave(),
5317
+ disabled: isSaving,
5318
+ children: isSaving ? "Saving..." : "Save"
5319
+ }
5320
+ ) : null,
5321
+ showCloseButton ? /* @__PURE__ */ jsx(
5322
+ "button",
5323
+ {
5324
+ type: "button",
5325
+ className: "text-[11px] font-medium px-3 py-1.5 rounded-md border border-slate-200 text-slate-600 hover:bg-slate-50 hover:border-slate-300 transition-all",
5326
+ onClick: () => onClose?.(),
5327
+ children: closeLabel
5328
+ }
5329
+ ) : null
5330
+ ] })
5331
+ ] }) : null,
5332
+ /* @__PURE__ */ jsxs("div", { className: `${editorClassName} relative`, children: [
5333
+ /* @__PURE__ */ jsx("div", { className: "w-full h-full bg-slate-100 overflow-auto flex justify-center items-start p-3", children: /* @__PURE__ */ jsx(
5334
+ "div",
5335
+ {
5336
+ className: "h-full bg-white border border-slate-200 shadow-sm overflow-hidden",
5337
+ style: {
5338
+ width: iframeWidth,
5339
+ minWidth: iframeWidth,
5340
+ maxWidth: "100%"
5341
+ },
5342
+ children: /* @__PURE__ */ jsx(
5343
+ "iframe",
5344
+ {
5345
+ ref: iframeRef,
5346
+ src: editorSrc,
5347
+ onLoad: handleIframeLoad,
5348
+ className: "w-full h-full border-0",
5349
+ title: "AI Editor Preview",
5350
+ allow: "same-origin"
5351
+ },
5352
+ iframeKey
5353
+ )
5354
+ }
5355
+ ) }),
5356
+ isIframeLoading ? /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-slate-100/95 backdrop-blur-[1px]", children: /* @__PURE__ */ jsxs("div", { className: "w-[560px] max-w-[88vw]", children: [
5357
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-center text-base font-semibold text-slate-700", children: "Loading changes..." }),
5358
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-full rounded-full border border-slate-300 bg-white/90 p-1 shadow-sm", children: /* @__PURE__ */ jsx("div", { className: "h-full w-full overflow-hidden rounded-full bg-slate-200", children: /* @__PURE__ */ jsx("div", { className: "h-full w-1/3 rounded-full bg-gradient-to-r from-emerald-300 via-sky-500 to-indigo-600 animate-pulse" }) }) })
5359
+ ] }) }) : null,
5360
+ chatComponent ?? null
5361
+ ] })
5362
+ ] });
5363
+ }
5023
5364
 
5024
- export { EditorShell, PlatformVisualEditor, PlatformVisualEditorV2, ToastProvider, hydrateVariationsFromStorage, useToast, variationsPersistStorageName };
5365
+ export { EditorShell, PlatformAiEditor, PlatformVisualEditor, PlatformVisualEditorV2, ToastProvider, hydrateVariationsFromStorage, useToast, variationsPersistStorageName };
package/dist/vite.cjs CHANGED
@@ -12,6 +12,7 @@ var path__default = /*#__PURE__*/_interopDefault(path);
12
12
 
13
13
  // src/visualEditorProxyPlugin.ts
14
14
  var popupHideCss = `<style id="__ce_popup_hide">#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"],.klaviyo-form,.klaviyo-modal,.klaviyo-popup,[class*="klaviyo"],.privy-popup,.privy-flyout,[id*="privy"],#PopupSignupForm,.popup-signup,.newsletter-popup,.newsletter-modal,[class*="newsletter-popup"],[class*="newsletter-modal"],[id*="newsletter-popup"],.email-popup,.email-modal,[class*="email-popup"],[class*="email-modal"],.signup-popup,.signup-modal,[class*="signup-popup"],[class*="signup-modal"],.subscribe-popup,.subscribe-modal,[class*="subscribe-popup"],#mc_embed_signup,.mc-modal,.mc-banner,.mc-closeModal,.omniconvert-popup,[class*="omniconvert"],.optinmonster-popup,[id*="om-"][class*="campaign"],.sumo-overlay,.sumome-overlay,[class*="sumome"],.hustle-modal,.hustle-popup,[class*="hustle-"],.popup-overlay,.popup-modal,.modal-overlay,[class*="exit-intent"],[class*="exitintent"],.wheelio-popup,[class*="wheelio"],.spin-wheel-popup,.justuno-popup,[class*="justuno"],.wisepops,.wisepops-overlay,[class*="wisepops"],.elegantmodal,.elegant-popup,#zipify-popup,[class*="zipify"],.age-gate,.age-verification,.age-popup,[class*="age-gate"],[class*="age-verif"],[class*="popup-overlay"],[class*="modal-overlay"],[class*="popup-backdrop"]{display:none!important;visibility:hidden!important;opacity:0!important;pointer-events:none!important;height:0!important;overflow:hidden!important;}body.klaviyo-open,body.modal-open,body.popup-open,body.no-scroll,body.noscroll{overflow:auto!important;position:static!important;}</style>`;
15
+ var consentAllowCss = `<style id="__ce_consent_allow">#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;overflow:visible!important;}</style>`;
15
16
  var AI_SYSTEM_PROMPT = `You are a CRO expert. Return JSON only with: hypothesis, mutations, summary. Keep 2-6 precise mutations and only valid selectors from snapshot.`;
16
17
  var BRIDGE_SCRIPT = `(function(){if(window.__CONVERSION_BRIDGE_LOADED__)return;window.__CONVERSION_BRIDGE_LOADED__=true;var CHANNEL='conversion-editor';var highlightEl=null;function send(payload){window.parent.postMessage({channel:CHANNEL,payload:payload},'*');}function qs(selector){try{return document.querySelector(selector);}catch(_){return null;}}function getSelector(el){if(!el||el.nodeType!==1)return'';if(el.id)return'#'+CSS.escape(el.id);var parts=[];var current=el;var depth=0;while(current&&current.nodeType===1&&depth<5){var part=current.tagName.toLowerCase();if(current.classList&&current.classList.length){part+='.'+Array.from(current.classList).slice(0,2).map(function(c){return CSS.escape(c);}).join('.');}var parent=current.parentElement;if(parent){var siblings=Array.from(parent.children).filter(function(s){return s.tagName===current.tagName;});if(siblings.length>1)part+=':nth-of-type('+(siblings.indexOf(current)+1)+')';}parts.unshift(part);current=parent;depth+=1;}return parts.join(' > ');}function payloadOf(el){var rect=el.getBoundingClientRect();var style=window.getComputedStyle(el);return{selector:getSelector(el),tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,500),computedStyles:{color:style.color,backgroundColor:style.backgroundColor,fontSize:style.fontSize,fontWeight:style.fontWeight,lineHeight:style.lineHeight,display:style.display},rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}function applyMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.value;break;case'setText':el.textContent=m.value;break;case'setHTML':el.innerHTML=m.value;break;case'setAttribute':if(m.property)el.setAttribute(m.property,m.value);break;case'hide':el.style.display='none';break;case'show':el.style.display='';break;case'insertHTML':if(m.position)el.insertAdjacentHTML(m.position,m.value||'');break;case'insertSection':if(m.position)el.insertAdjacentHTML(m.position,m.sectionHtml||m.value||'');break;case'reorderElement':if(!m.targetSelector)break;var target=qs(m.targetSelector);if(!target||!target.parentNode||!el.parentNode)break;if(m.insertPosition==='before')target.parentNode.insertBefore(el,target);else target.parentNode.insertBefore(el,target.nextSibling);break;default:break;}}function revertMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.previous||'';break;case'setText':el.textContent=m.previous||'';break;case'setHTML':el.innerHTML=m.previous||'';break;case'setAttribute':if(m.property){if(m.previous!=null)el.setAttribute(m.property,m.previous);else el.removeAttribute(m.property);}break;case'hide':case'show':el.style.display=m.previous||'';break;default:break;}}function captureSnapshot(){var elements=Array.from(document.querySelectorAll('h1,h2,h3,p,button,a,input,select,img,section,div')).slice(0,700).map(function(el){var rect=el.getBoundingClientRect();var cs=window.getComputedStyle(el);return{selector:getSelector(el),parentSelector:el.parentElement?getSelector(el.parentElement):null,tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,300),attributes:Array.from(el.attributes||[]).reduce(function(acc,a){acc[a.name]=a.value;return acc;},{}),computedStyles:{color:cs.color,backgroundColor:cs.backgroundColor,fontSize:cs.fontSize,fontWeight:cs.fontWeight,display:cs.display},childrenCount:el.children?el.children.length:0,aboveFold:rect.top<window.innerHeight,depth:(function(){var d=0,p=el.parentElement;while(p&&d<25){d++;p=p.parentElement;}return d;})()};});send({type:'snapshotCaptured',snapshot:{url:window.location.href,title:document.title,viewport:{width:window.innerWidth,height:window.innerHeight},elements:elements}});}function captureTree(){function toNode(el,depth){var rect=el.getBoundingClientRect();var tag=el.tagName.toLowerCase();var type='generic';if(tag==='section')type='section';else if(tag==='img')type='image';else if(tag==='a')type='link';else if(tag==='button')type='button';else if(tag==='form')type='form';else if(['p','h1','h2','h3','h4','h5','h6','span'].indexOf(tag)>=0)type='text';else if(['div','main','article','aside','header','footer','nav'].indexOf(tag)>=0)type='container';var children=Array.from(el.children||[]).slice(0,50).map(function(c){return toNode(c,depth+1);});return{id:getSelector(el),selector:getSelector(el),tagName:tag,label:(el.getAttribute('aria-label')||el.getAttribute('id')||el.className||tag).toString().slice(0,80),type:type,children:children,depth:depth,isAboveFold:rect.top<window.innerHeight,rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}send({type:'pageTreeCaptured',tree:[toNode(document.body,0)]});}window.addEventListener('message',function(e){var msg=e.data;if(!msg||msg.channel!==CHANNEL||!msg.payload)return;var p=msg.payload;switch(p.type){case'ping':send({type:'pong'});break;case'applyMutation':applyMutation(p.mutation);break;case'applyMutationBatch':(p.mutations||[]).forEach(applyMutation);break;case'revert':revertMutation(p.mutation);break;case'clearAllMutations':window.location.reload();break;case'captureSnapshot':captureSnapshot();break;case'validateSelectors':send({type:'selectorsValidated',results:(p.selectors||[]).map(function(s){var el=qs(s);return{selector:s,found:!!el,tagName:el?el.tagName.toLowerCase():null};})});break;case'scrollToElement':case'selectElement':var target=qs(p.selector);if(target){target.scrollIntoView({behavior:'smooth',block:'center'});send({type:'elementSelected',element:payloadOf(target)});}break;case'hoverElement':var h=qs(p.selector);if(h){if(highlightEl)highlightEl.style.outline='';h.style.outline='2px solid #3b82f6';highlightEl=h;}break;case'capturePageTree':captureTree();break;default:break;}});document.addEventListener('click',function(e){var el=e.target;if(!(el instanceof Element))return;send({type:'elementSelected',element:payloadOf(el)});},true);send({type:'bridgeReady'});})();`;
17
18
  function buildVvvebEditorHtml() {
@@ -1223,6 +1224,10 @@ function setMode(mode) {
1223
1224
  if (mode === 'navigate') {
1224
1225
  setDragHandleActive(false);
1225
1226
  deselectElement();
1227
+ } else if (mode === 'editor') {
1228
+ // Re-bind interactions immediately when coming back from navigate mode.
1229
+ // This avoids waiting for delayed iframe readiness/load retries.
1230
+ syncIframeInteractions('mode-editor-toggle');
1226
1231
  }
1227
1232
  updateSelectionToolbar();
1228
1233
  }
@@ -2201,7 +2206,7 @@ function loadPage(proxyUrl) {
2201
2206
  resetIframeBindings();
2202
2207
  iframe.style.display = 'block';
2203
2208
  setIframePageLoadingUi(true);
2204
- iframe.src = proxyUrl;
2209
+ iframe.src = appendIframeReloadBust(proxyUrl);
2205
2210
  startIframeContentApplyWatcher(navGen);
2206
2211
  scheduleDomTreeRefresh();
2207
2212
  }
@@ -3041,7 +3046,7 @@ function renderDomTree(filterRaw) {
3041
3046
 
3042
3047
  function labelFor(el) {
3043
3048
  var tag = el.tagName.toLowerCase();
3044
- if (el.id) return tag + '#' + el.id.slice(0, 40);
3049
+ if (el.id != null && el.id !== '') return tag + '#' + String(el.id).slice(0, 40);
3045
3050
  var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
3046
3051
  if (cn) {
3047
3052
  var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
@@ -4225,18 +4230,28 @@ window.addEventListener('load', function() {
4225
4230
  var iframe = document.getElementById('iframeId');
4226
4231
  iframe.addEventListener('load', function() {
4227
4232
  if (!iframe.src || iframe.src === 'about:blank' || iframe.src === window.location.href) return;
4233
+ // New iframe navigation: always drop bindings tied to the previous document.
4234
+ resetIframeBindings();
4228
4235
  var doc = iframe.contentDocument;
4229
- if (!doc || !doc.body) return;
4236
+ if (!doc) {
4237
+ syncIframeInteractions('iframe-load-no-doc');
4238
+ return;
4239
+ }
4230
4240
  var docUrl = '';
4231
4241
  try { docUrl = String(doc.URL || ''); } catch(_) {}
4232
4242
  // Stale events: src may already be the proxy URL while the document is still
4233
- // about:blank (e.g. src cleared then reset to force reload).
4234
- if (docUrl === 'about:blank') return;
4235
- if (!iframeDocMatchesNavigatedSrc(iframe, doc)) return;
4243
+ // about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
4244
+ if (docUrl === 'about:blank') {
4245
+ syncIframeInteractions('iframe-load-about-blank');
4246
+ return;
4247
+ }
4236
4248
  attachIframeLoadingUntilComplete(iframe);
4237
- stopIframeContentApplyWatcher();
4238
- deselectElement();
4239
- applyActiveVariationHtml();
4249
+ if (doc.body && iframeDocMatchesNavigatedSrc(iframe, doc)) {
4250
+ stopIframeContentApplyWatcher();
4251
+ deselectElement();
4252
+ applyActiveVariationHtml();
4253
+ }
4254
+ // Always attempt sync; it has its own readiness checks + retry loop.
4240
4255
  syncIframeInteractions('iframe-load');
4241
4256
  });
4242
4257
 
@@ -4564,7 +4579,7 @@ function createVisualEditorMiddleware(options) {
4564
4579
  }
4565
4580
  html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
4566
4581
  const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4567
- const proxyBase = `/api/conversion-proxy?password=${encodeURIComponent(password)}&url=`;
4582
+ const proxyBase = `/api/conversion-proxy?__ve_reload=${Date.now()}&password=${encodeURIComponent(password)}&url=`;
4568
4583
  html = html.replace(
4569
4584
  new RegExp(`(href|action)="${escapedOrigin}(/[^"]*)"`, "g"),
4570
4585
  (match, attr, urlPath) => {
@@ -4577,6 +4592,7 @@ function createVisualEditorMiddleware(options) {
4577
4592
  );
4578
4593
  if (html.includes("</head>")) {
4579
4594
  html = html.replace("</head>", `${popupHideCss}
4595
+ ${consentAllowCss}
4580
4596
  </head>`);
4581
4597
  }
4582
4598
  html = html.replace(
@@ -4594,7 +4610,7 @@ var PROXY_PASSWORD=${JSON.stringify(password)};
4594
4610
  window.__CONVERSION_EDITOR_ACTIVE__=true;
4595
4611
  function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
4596
4612
  function toAbsolute(raw){if(isSkippable(raw))return raw;try{var base=raw.startsWith("/")||raw.startsWith("//")?TARGET_ORIGIN:TARGET_PAGE_URL;return new URL(raw,base).toString();}catch(_){return raw;}}
4597
- function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
4613
+ function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?__ve_reload="+Date.now()+"&password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
4598
4614
  var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
4599
4615
  var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
4600
4616
  function safeNavigate(raw,mode){var abs=toAbsolute(raw);var prox=toProxy(raw);if(!prox){try{console.warn("[conversion-proxy] redirect blocked",{mode:mode,requested:raw,resolved:abs,origin:TARGET_ORIGIN});}catch(_){}return false;}try{console.info("[conversion-proxy] redirect intercepted",{mode:mode,requested:raw,resolved:abs,proxied:prox});if(mode==="replace"&&nativeReplace){nativeReplace(prox);return true;}if(nativeAssign){nativeAssign(prox);return true;}window.location.href=prox;return true;}catch(err){try{console.warn("[conversion-proxy] redirect interception failed",{mode:mode,requested:raw,resolved:abs,proxied:prox,error:err&&err.message?err.message:String(err)});}catch(_){}return false;}}
@@ -4667,6 +4683,9 @@ if(window.fetch){
4667
4683
  }
4668
4684
  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);};}
4669
4685
  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);};}
4686
+ 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;u.searchParams.set("__ve_reload",String(Date.now()));return u.toString();}catch(_){return null;}}
4687
+ document.addEventListener("click",function(ev){try{var t=ev&&ev.target;if(!t||!t.closest)return;var a=t.closest("a[href]");if(!a)return;var href=a.getAttribute("href")||a.href;var bust=withReloadBust(href);if(bust)a.setAttribute("href",bust);}catch(_){}},true);
4688
+ document.addEventListener("submit",function(ev){try{var f=ev&&ev.target;if(!f||!f.getAttribute)return;var act=f.getAttribute("action")||"";var bust=withReloadBust(act);if(bust)f.setAttribute("action",bust);}catch(_){}},true);
4670
4689
  if(window.navigator&&window.navigator.serviceWorker&&typeof window.navigator.serviceWorker.register==="function"){window.navigator.serviceWorker.register=function(){return Promise.resolve({scope:"disabled-in-editor-proxy"});};}
4671
4690
  }catch(_){}})();</script>`;
4672
4691
  if (html.includes("</head>")) {
@@ -4675,6 +4694,101 @@ if(window.navigator&&window.navigator.serviceWorker&&typeof window.navigator.ser
4675
4694
  } else {
4676
4695
  html = runtimeProxyScript + html;
4677
4696
  }
4697
+ const aiBridgeRuntimeScript = `<script>(function(){try{
4698
+ var AI_CHANNEL="ve-ai-editor";
4699
+ var lastJs="";
4700
+ var aiSheet=null;
4701
+ var lastAiContainerIds=[];
4702
+ function extractAiContainerIds(source){
4703
+ try{
4704
+ var re=/ai-generated-container-[a-zA-Z0-9_-]+/g;
4705
+ var found=String(source||"").match(re)||[];
4706
+ var uniq=[];
4707
+ for(var i=0;i<found.length;i++){
4708
+ if(uniq.indexOf(found[i])===-1) uniq.push(found[i]);
4709
+ }
4710
+ return uniq;
4711
+ }catch(_){
4712
+ return [];
4713
+ }
4714
+ }
4715
+ function cleanupRemovedAiContainers(nextIds){
4716
+ try{
4717
+ for(var i=0;i<lastAiContainerIds.length;i++){
4718
+ var prevId=lastAiContainerIds[i];
4719
+ if(nextIds.indexOf(prevId)!==-1) continue;
4720
+ var el=document.getElementById(prevId);
4721
+ if(!el) continue;
4722
+ var marker=(el.getAttribute("data-ai-generated")||"").toLowerCase();
4723
+ if(marker==="true"||prevId.indexOf("ai-generated-container-")===0){
4724
+ if(el.parentNode) el.parentNode.removeChild(el);
4725
+ }
4726
+ }
4727
+ }catch(_){}
4728
+ }
4729
+ function getProxyPayload(){
4730
+ try{
4731
+ var u=new URL(window.location.href);
4732
+ return {
4733
+ url:u.searchParams.get("url")||undefined,
4734
+ password:u.searchParams.get("password")||undefined
4735
+ };
4736
+ }catch(_){
4737
+ return {};
4738
+ }
4739
+ }
4740
+ function applyAiCode(payload){
4741
+ try{
4742
+ var p=payload||{};
4743
+ var css=typeof p.cssCode==="string"?p.cssCode:"";
4744
+ var js=typeof p.jsCode==="string"?p.jsCode:"";
4745
+ var doc=document;
4746
+ if(typeof CSSStyleSheet!=="undefined"&&"adoptedStyleSheets" in doc){
4747
+ var sheets=doc.adoptedStyleSheets||[];
4748
+ if(css){
4749
+ if(!aiSheet) aiSheet=new CSSStyleSheet();
4750
+ aiSheet.replaceSync(css);
4751
+ if(sheets.indexOf(aiSheet)===-1){
4752
+ doc.adoptedStyleSheets=sheets.concat(aiSheet);
4753
+ }
4754
+ }else if(aiSheet&&sheets.indexOf(aiSheet)!==-1){
4755
+ doc.adoptedStyleSheets=sheets.filter(function(s){return s!==aiSheet;});
4756
+ }
4757
+ }
4758
+ if(js!==lastJs){
4759
+ var nextIds=extractAiContainerIds(js);
4760
+ cleanupRemovedAiContainers(nextIds);
4761
+ if(js) (new Function(js)).call(window);
4762
+ lastJs=js;
4763
+ lastAiContainerIds=nextIds;
4764
+ }
4765
+ try{
4766
+ doc.documentElement.setAttribute("data-ve-ai-applied","1");
4767
+ window.parent&&window.parent.postMessage({
4768
+ channel:AI_CHANNEL,
4769
+ type:"ai-code-applied",
4770
+ payload:{cssLen:css.length,jsLen:js.length}
4771
+ },"*");
4772
+ }catch(_){}
4773
+ }catch(_){}
4774
+ }
4775
+ window.addEventListener("message",function(ev){
4776
+ try{
4777
+ var d=ev&&ev.data;
4778
+ if(!d||d.channel!==AI_CHANNEL||d.type!=="apply-ai-code") return;
4779
+ applyAiCode(d.payload||{});
4780
+ }catch(_){}
4781
+ });
4782
+ try{
4783
+ if(window.parent){
4784
+ window.parent.postMessage({channel:AI_CHANNEL,type:"ai-code-ready"},"*");
4785
+ window.parent.postMessage({channel:AI_CHANNEL,type:"ai-url-changed",payload:getProxyPayload()},"*");
4786
+ }
4787
+ }catch(_){}
4788
+ }catch(_){}})();</script>`;
4789
+ html = html.includes("</head>") ? html.replace("</head>", `${aiBridgeRuntimeScript}
4790
+ </head>`) : `${aiBridgeRuntimeScript}
4791
+ ${html}`;
4678
4792
  const bridgeScript = `<script src="/bridge.js"></script>`;
4679
4793
  html = html.includes("</body>") ? html.replace("</body>", `${bridgeScript}
4680
4794
  </body>`) : html + bridgeScript;
package/dist/vite.js CHANGED
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'url';
4
4
 
5
5
  // src/visualEditorProxyPlugin.ts
6
6
  var popupHideCss = `<style id="__ce_popup_hide">#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"],.klaviyo-form,.klaviyo-modal,.klaviyo-popup,[class*="klaviyo"],.privy-popup,.privy-flyout,[id*="privy"],#PopupSignupForm,.popup-signup,.newsletter-popup,.newsletter-modal,[class*="newsletter-popup"],[class*="newsletter-modal"],[id*="newsletter-popup"],.email-popup,.email-modal,[class*="email-popup"],[class*="email-modal"],.signup-popup,.signup-modal,[class*="signup-popup"],[class*="signup-modal"],.subscribe-popup,.subscribe-modal,[class*="subscribe-popup"],#mc_embed_signup,.mc-modal,.mc-banner,.mc-closeModal,.omniconvert-popup,[class*="omniconvert"],.optinmonster-popup,[id*="om-"][class*="campaign"],.sumo-overlay,.sumome-overlay,[class*="sumome"],.hustle-modal,.hustle-popup,[class*="hustle-"],.popup-overlay,.popup-modal,.modal-overlay,[class*="exit-intent"],[class*="exitintent"],.wheelio-popup,[class*="wheelio"],.spin-wheel-popup,.justuno-popup,[class*="justuno"],.wisepops,.wisepops-overlay,[class*="wisepops"],.elegantmodal,.elegant-popup,#zipify-popup,[class*="zipify"],.age-gate,.age-verification,.age-popup,[class*="age-gate"],[class*="age-verif"],[class*="popup-overlay"],[class*="modal-overlay"],[class*="popup-backdrop"]{display:none!important;visibility:hidden!important;opacity:0!important;pointer-events:none!important;height:0!important;overflow:hidden!important;}body.klaviyo-open,body.modal-open,body.popup-open,body.no-scroll,body.noscroll{overflow:auto!important;position:static!important;}</style>`;
7
+ var consentAllowCss = `<style id="__ce_consent_allow">#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;overflow:visible!important;}</style>`;
7
8
  var AI_SYSTEM_PROMPT = `You are a CRO expert. Return JSON only with: hypothesis, mutations, summary. Keep 2-6 precise mutations and only valid selectors from snapshot.`;
8
9
  var BRIDGE_SCRIPT = `(function(){if(window.__CONVERSION_BRIDGE_LOADED__)return;window.__CONVERSION_BRIDGE_LOADED__=true;var CHANNEL='conversion-editor';var highlightEl=null;function send(payload){window.parent.postMessage({channel:CHANNEL,payload:payload},'*');}function qs(selector){try{return document.querySelector(selector);}catch(_){return null;}}function getSelector(el){if(!el||el.nodeType!==1)return'';if(el.id)return'#'+CSS.escape(el.id);var parts=[];var current=el;var depth=0;while(current&&current.nodeType===1&&depth<5){var part=current.tagName.toLowerCase();if(current.classList&&current.classList.length){part+='.'+Array.from(current.classList).slice(0,2).map(function(c){return CSS.escape(c);}).join('.');}var parent=current.parentElement;if(parent){var siblings=Array.from(parent.children).filter(function(s){return s.tagName===current.tagName;});if(siblings.length>1)part+=':nth-of-type('+(siblings.indexOf(current)+1)+')';}parts.unshift(part);current=parent;depth+=1;}return parts.join(' > ');}function payloadOf(el){var rect=el.getBoundingClientRect();var style=window.getComputedStyle(el);return{selector:getSelector(el),tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,500),computedStyles:{color:style.color,backgroundColor:style.backgroundColor,fontSize:style.fontSize,fontWeight:style.fontWeight,lineHeight:style.lineHeight,display:style.display},rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}function applyMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.value;break;case'setText':el.textContent=m.value;break;case'setHTML':el.innerHTML=m.value;break;case'setAttribute':if(m.property)el.setAttribute(m.property,m.value);break;case'hide':el.style.display='none';break;case'show':el.style.display='';break;case'insertHTML':if(m.position)el.insertAdjacentHTML(m.position,m.value||'');break;case'insertSection':if(m.position)el.insertAdjacentHTML(m.position,m.sectionHtml||m.value||'');break;case'reorderElement':if(!m.targetSelector)break;var target=qs(m.targetSelector);if(!target||!target.parentNode||!el.parentNode)break;if(m.insertPosition==='before')target.parentNode.insertBefore(el,target);else target.parentNode.insertBefore(el,target.nextSibling);break;default:break;}}function revertMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.previous||'';break;case'setText':el.textContent=m.previous||'';break;case'setHTML':el.innerHTML=m.previous||'';break;case'setAttribute':if(m.property){if(m.previous!=null)el.setAttribute(m.property,m.previous);else el.removeAttribute(m.property);}break;case'hide':case'show':el.style.display=m.previous||'';break;default:break;}}function captureSnapshot(){var elements=Array.from(document.querySelectorAll('h1,h2,h3,p,button,a,input,select,img,section,div')).slice(0,700).map(function(el){var rect=el.getBoundingClientRect();var cs=window.getComputedStyle(el);return{selector:getSelector(el),parentSelector:el.parentElement?getSelector(el.parentElement):null,tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,300),attributes:Array.from(el.attributes||[]).reduce(function(acc,a){acc[a.name]=a.value;return acc;},{}),computedStyles:{color:cs.color,backgroundColor:cs.backgroundColor,fontSize:cs.fontSize,fontWeight:cs.fontWeight,display:cs.display},childrenCount:el.children?el.children.length:0,aboveFold:rect.top<window.innerHeight,depth:(function(){var d=0,p=el.parentElement;while(p&&d<25){d++;p=p.parentElement;}return d;})()};});send({type:'snapshotCaptured',snapshot:{url:window.location.href,title:document.title,viewport:{width:window.innerWidth,height:window.innerHeight},elements:elements}});}function captureTree(){function toNode(el,depth){var rect=el.getBoundingClientRect();var tag=el.tagName.toLowerCase();var type='generic';if(tag==='section')type='section';else if(tag==='img')type='image';else if(tag==='a')type='link';else if(tag==='button')type='button';else if(tag==='form')type='form';else if(['p','h1','h2','h3','h4','h5','h6','span'].indexOf(tag)>=0)type='text';else if(['div','main','article','aside','header','footer','nav'].indexOf(tag)>=0)type='container';var children=Array.from(el.children||[]).slice(0,50).map(function(c){return toNode(c,depth+1);});return{id:getSelector(el),selector:getSelector(el),tagName:tag,label:(el.getAttribute('aria-label')||el.getAttribute('id')||el.className||tag).toString().slice(0,80),type:type,children:children,depth:depth,isAboveFold:rect.top<window.innerHeight,rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}send({type:'pageTreeCaptured',tree:[toNode(document.body,0)]});}window.addEventListener('message',function(e){var msg=e.data;if(!msg||msg.channel!==CHANNEL||!msg.payload)return;var p=msg.payload;switch(p.type){case'ping':send({type:'pong'});break;case'applyMutation':applyMutation(p.mutation);break;case'applyMutationBatch':(p.mutations||[]).forEach(applyMutation);break;case'revert':revertMutation(p.mutation);break;case'clearAllMutations':window.location.reload();break;case'captureSnapshot':captureSnapshot();break;case'validateSelectors':send({type:'selectorsValidated',results:(p.selectors||[]).map(function(s){var el=qs(s);return{selector:s,found:!!el,tagName:el?el.tagName.toLowerCase():null};})});break;case'scrollToElement':case'selectElement':var target=qs(p.selector);if(target){target.scrollIntoView({behavior:'smooth',block:'center'});send({type:'elementSelected',element:payloadOf(target)});}break;case'hoverElement':var h=qs(p.selector);if(h){if(highlightEl)highlightEl.style.outline='';h.style.outline='2px solid #3b82f6';highlightEl=h;}break;case'capturePageTree':captureTree();break;default:break;}});document.addEventListener('click',function(e){var el=e.target;if(!(el instanceof Element))return;send({type:'elementSelected',element:payloadOf(el)});},true);send({type:'bridgeReady'});})();`;
9
10
  function buildVvvebEditorHtml() {
@@ -1215,6 +1216,10 @@ function setMode(mode) {
1215
1216
  if (mode === 'navigate') {
1216
1217
  setDragHandleActive(false);
1217
1218
  deselectElement();
1219
+ } else if (mode === 'editor') {
1220
+ // Re-bind interactions immediately when coming back from navigate mode.
1221
+ // This avoids waiting for delayed iframe readiness/load retries.
1222
+ syncIframeInteractions('mode-editor-toggle');
1218
1223
  }
1219
1224
  updateSelectionToolbar();
1220
1225
  }
@@ -2193,7 +2198,7 @@ function loadPage(proxyUrl) {
2193
2198
  resetIframeBindings();
2194
2199
  iframe.style.display = 'block';
2195
2200
  setIframePageLoadingUi(true);
2196
- iframe.src = proxyUrl;
2201
+ iframe.src = appendIframeReloadBust(proxyUrl);
2197
2202
  startIframeContentApplyWatcher(navGen);
2198
2203
  scheduleDomTreeRefresh();
2199
2204
  }
@@ -3033,7 +3038,7 @@ function renderDomTree(filterRaw) {
3033
3038
 
3034
3039
  function labelFor(el) {
3035
3040
  var tag = el.tagName.toLowerCase();
3036
- if (el.id) return tag + '#' + el.id.slice(0, 40);
3041
+ if (el.id != null && el.id !== '') return tag + '#' + String(el.id).slice(0, 40);
3037
3042
  var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
3038
3043
  if (cn) {
3039
3044
  var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
@@ -4217,18 +4222,28 @@ window.addEventListener('load', function() {
4217
4222
  var iframe = document.getElementById('iframeId');
4218
4223
  iframe.addEventListener('load', function() {
4219
4224
  if (!iframe.src || iframe.src === 'about:blank' || iframe.src === window.location.href) return;
4225
+ // New iframe navigation: always drop bindings tied to the previous document.
4226
+ resetIframeBindings();
4220
4227
  var doc = iframe.contentDocument;
4221
- if (!doc || !doc.body) return;
4228
+ if (!doc) {
4229
+ syncIframeInteractions('iframe-load-no-doc');
4230
+ return;
4231
+ }
4222
4232
  var docUrl = '';
4223
4233
  try { docUrl = String(doc.URL || ''); } catch(_) {}
4224
4234
  // Stale events: src may already be the proxy URL while the document is still
4225
- // about:blank (e.g. src cleared then reset to force reload).
4226
- if (docUrl === 'about:blank') return;
4227
- if (!iframeDocMatchesNavigatedSrc(iframe, doc)) return;
4235
+ // about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
4236
+ if (docUrl === 'about:blank') {
4237
+ syncIframeInteractions('iframe-load-about-blank');
4238
+ return;
4239
+ }
4228
4240
  attachIframeLoadingUntilComplete(iframe);
4229
- stopIframeContentApplyWatcher();
4230
- deselectElement();
4231
- applyActiveVariationHtml();
4241
+ if (doc.body && iframeDocMatchesNavigatedSrc(iframe, doc)) {
4242
+ stopIframeContentApplyWatcher();
4243
+ deselectElement();
4244
+ applyActiveVariationHtml();
4245
+ }
4246
+ // Always attempt sync; it has its own readiness checks + retry loop.
4232
4247
  syncIframeInteractions('iframe-load');
4233
4248
  });
4234
4249
 
@@ -4556,7 +4571,7 @@ function createVisualEditorMiddleware(options) {
4556
4571
  }
4557
4572
  html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
4558
4573
  const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4559
- const proxyBase = `/api/conversion-proxy?password=${encodeURIComponent(password)}&url=`;
4574
+ const proxyBase = `/api/conversion-proxy?__ve_reload=${Date.now()}&password=${encodeURIComponent(password)}&url=`;
4560
4575
  html = html.replace(
4561
4576
  new RegExp(`(href|action)="${escapedOrigin}(/[^"]*)"`, "g"),
4562
4577
  (match, attr, urlPath) => {
@@ -4569,6 +4584,7 @@ function createVisualEditorMiddleware(options) {
4569
4584
  );
4570
4585
  if (html.includes("</head>")) {
4571
4586
  html = html.replace("</head>", `${popupHideCss}
4587
+ ${consentAllowCss}
4572
4588
  </head>`);
4573
4589
  }
4574
4590
  html = html.replace(
@@ -4586,7 +4602,7 @@ var PROXY_PASSWORD=${JSON.stringify(password)};
4586
4602
  window.__CONVERSION_EDITOR_ACTIVE__=true;
4587
4603
  function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
4588
4604
  function toAbsolute(raw){if(isSkippable(raw))return raw;try{var base=raw.startsWith("/")||raw.startsWith("//")?TARGET_ORIGIN:TARGET_PAGE_URL;return new URL(raw,base).toString();}catch(_){return raw;}}
4589
- function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
4605
+ function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?__ve_reload="+Date.now()+"&password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
4590
4606
  var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
4591
4607
  var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
4592
4608
  function safeNavigate(raw,mode){var abs=toAbsolute(raw);var prox=toProxy(raw);if(!prox){try{console.warn("[conversion-proxy] redirect blocked",{mode:mode,requested:raw,resolved:abs,origin:TARGET_ORIGIN});}catch(_){}return false;}try{console.info("[conversion-proxy] redirect intercepted",{mode:mode,requested:raw,resolved:abs,proxied:prox});if(mode==="replace"&&nativeReplace){nativeReplace(prox);return true;}if(nativeAssign){nativeAssign(prox);return true;}window.location.href=prox;return true;}catch(err){try{console.warn("[conversion-proxy] redirect interception failed",{mode:mode,requested:raw,resolved:abs,proxied:prox,error:err&&err.message?err.message:String(err)});}catch(_){}return false;}}
@@ -4659,6 +4675,9 @@ if(window.fetch){
4659
4675
  }
4660
4676
  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);};}
4661
4677
  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);};}
4678
+ 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;u.searchParams.set("__ve_reload",String(Date.now()));return u.toString();}catch(_){return null;}}
4679
+ document.addEventListener("click",function(ev){try{var t=ev&&ev.target;if(!t||!t.closest)return;var a=t.closest("a[href]");if(!a)return;var href=a.getAttribute("href")||a.href;var bust=withReloadBust(href);if(bust)a.setAttribute("href",bust);}catch(_){}},true);
4680
+ document.addEventListener("submit",function(ev){try{var f=ev&&ev.target;if(!f||!f.getAttribute)return;var act=f.getAttribute("action")||"";var bust=withReloadBust(act);if(bust)f.setAttribute("action",bust);}catch(_){}},true);
4662
4681
  if(window.navigator&&window.navigator.serviceWorker&&typeof window.navigator.serviceWorker.register==="function"){window.navigator.serviceWorker.register=function(){return Promise.resolve({scope:"disabled-in-editor-proxy"});};}
4663
4682
  }catch(_){}})();</script>`;
4664
4683
  if (html.includes("</head>")) {
@@ -4667,6 +4686,101 @@ if(window.navigator&&window.navigator.serviceWorker&&typeof window.navigator.ser
4667
4686
  } else {
4668
4687
  html = runtimeProxyScript + html;
4669
4688
  }
4689
+ const aiBridgeRuntimeScript = `<script>(function(){try{
4690
+ var AI_CHANNEL="ve-ai-editor";
4691
+ var lastJs="";
4692
+ var aiSheet=null;
4693
+ var lastAiContainerIds=[];
4694
+ function extractAiContainerIds(source){
4695
+ try{
4696
+ var re=/ai-generated-container-[a-zA-Z0-9_-]+/g;
4697
+ var found=String(source||"").match(re)||[];
4698
+ var uniq=[];
4699
+ for(var i=0;i<found.length;i++){
4700
+ if(uniq.indexOf(found[i])===-1) uniq.push(found[i]);
4701
+ }
4702
+ return uniq;
4703
+ }catch(_){
4704
+ return [];
4705
+ }
4706
+ }
4707
+ function cleanupRemovedAiContainers(nextIds){
4708
+ try{
4709
+ for(var i=0;i<lastAiContainerIds.length;i++){
4710
+ var prevId=lastAiContainerIds[i];
4711
+ if(nextIds.indexOf(prevId)!==-1) continue;
4712
+ var el=document.getElementById(prevId);
4713
+ if(!el) continue;
4714
+ var marker=(el.getAttribute("data-ai-generated")||"").toLowerCase();
4715
+ if(marker==="true"||prevId.indexOf("ai-generated-container-")===0){
4716
+ if(el.parentNode) el.parentNode.removeChild(el);
4717
+ }
4718
+ }
4719
+ }catch(_){}
4720
+ }
4721
+ function getProxyPayload(){
4722
+ try{
4723
+ var u=new URL(window.location.href);
4724
+ return {
4725
+ url:u.searchParams.get("url")||undefined,
4726
+ password:u.searchParams.get("password")||undefined
4727
+ };
4728
+ }catch(_){
4729
+ return {};
4730
+ }
4731
+ }
4732
+ function applyAiCode(payload){
4733
+ try{
4734
+ var p=payload||{};
4735
+ var css=typeof p.cssCode==="string"?p.cssCode:"";
4736
+ var js=typeof p.jsCode==="string"?p.jsCode:"";
4737
+ var doc=document;
4738
+ if(typeof CSSStyleSheet!=="undefined"&&"adoptedStyleSheets" in doc){
4739
+ var sheets=doc.adoptedStyleSheets||[];
4740
+ if(css){
4741
+ if(!aiSheet) aiSheet=new CSSStyleSheet();
4742
+ aiSheet.replaceSync(css);
4743
+ if(sheets.indexOf(aiSheet)===-1){
4744
+ doc.adoptedStyleSheets=sheets.concat(aiSheet);
4745
+ }
4746
+ }else if(aiSheet&&sheets.indexOf(aiSheet)!==-1){
4747
+ doc.adoptedStyleSheets=sheets.filter(function(s){return s!==aiSheet;});
4748
+ }
4749
+ }
4750
+ if(js!==lastJs){
4751
+ var nextIds=extractAiContainerIds(js);
4752
+ cleanupRemovedAiContainers(nextIds);
4753
+ if(js) (new Function(js)).call(window);
4754
+ lastJs=js;
4755
+ lastAiContainerIds=nextIds;
4756
+ }
4757
+ try{
4758
+ doc.documentElement.setAttribute("data-ve-ai-applied","1");
4759
+ window.parent&&window.parent.postMessage({
4760
+ channel:AI_CHANNEL,
4761
+ type:"ai-code-applied",
4762
+ payload:{cssLen:css.length,jsLen:js.length}
4763
+ },"*");
4764
+ }catch(_){}
4765
+ }catch(_){}
4766
+ }
4767
+ window.addEventListener("message",function(ev){
4768
+ try{
4769
+ var d=ev&&ev.data;
4770
+ if(!d||d.channel!==AI_CHANNEL||d.type!=="apply-ai-code") return;
4771
+ applyAiCode(d.payload||{});
4772
+ }catch(_){}
4773
+ });
4774
+ try{
4775
+ if(window.parent){
4776
+ window.parent.postMessage({channel:AI_CHANNEL,type:"ai-code-ready"},"*");
4777
+ window.parent.postMessage({channel:AI_CHANNEL,type:"ai-url-changed",payload:getProxyPayload()},"*");
4778
+ }
4779
+ }catch(_){}
4780
+ }catch(_){}})();</script>`;
4781
+ html = html.includes("</head>") ? html.replace("</head>", `${aiBridgeRuntimeScript}
4782
+ </head>`) : `${aiBridgeRuntimeScript}
4783
+ ${html}`;
4670
4784
  const bridgeScript = `<script src="/bridge.js"></script>`;
4671
4785
  html = html.includes("</body>") ? html.replace("</body>", `${bridgeScript}
4672
4786
  </body>`) : html + bridgeScript;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@accelerated-agency/visual-editor",
3
- "version": "0.2.9",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "description": "Conversion visual editor as a reusable React package",
6
6
  "type": "module",
@@ -32,6 +32,7 @@
32
32
  "react-dom": ">=18"
33
33
  },
34
34
  "dependencies": {
35
+ "bootstrap-icons": "^1.13.1",
35
36
  "lucide-react": "^0.562.0",
36
37
  "react-colorful": "^5.6.1",
37
38
  "zustand": "^5.0.7"