/** * Vibn preview element picker — load inside the previewed app (same or cross-origin). * Parent verifies event.origin; iframe may postMessage with targetOrigin '*'. */ (function () { var NS = "vibn-preview"; var enabled = false; var overlay = null; var lastEl = null; function esc(s) { if (typeof CSS !== "undefined" && CSS.escape) return CSS.escape(s); return String(s).replace(/[^a-zA-Z0-9_-]/g, "\\$&"); } function shortSelector(el) { if (!el || el.nodeType !== 1) return "(unknown)"; if (el.id) return "#" + esc(el.id); var parts = []; var cur = el; var depth = 0; while (cur && cur.nodeType === 1 && depth < 6) { var tag = cur.tagName.toLowerCase(); var cls = cur.className && typeof cur.className === "string" ? cur.className.trim().split(/\s+/).slice(0, 2).join(".") : ""; parts.unshift(cls ? tag + "." + cls.split(".").map(esc).join(".") : tag); cur = cur.parentElement; depth++; } return parts.join(" > "); } function snippetText(el, max) { max = max || 120; var t = (el.innerText || "").trim().replace(/\s+/g, " "); return t.length > max ? t.slice(0, max - 1) + "…" : t; } function outerSnip(el, max) { max = max || 400; try { var html = el.outerHTML || ""; return html.length > max ? html.slice(0, max - 1) + "…" : html; } catch (e) { return ""; } } function ensureOverlay() { if (overlay) return overlay; overlay = document.createElement("div"); overlay.setAttribute("data-vibn-overlay", "1"); overlay.style.cssText = "pointer-events:none;position:fixed;z-index:2147483646;box-sizing:border-box;border:2px solid #4f46e5;border-radius:6px;background:rgba(79,70,229,0.12);display:none;transition:top .05s,left .05s,width .05s,height .05s;"; document.documentElement.appendChild(overlay); return overlay; } function hideOverlay() { if (overlay) overlay.style.display = "none"; lastEl = null; } function moveOverlay(el) { if (!el || el.nodeType !== 1 || el === overlay || el.contains(overlay)) { hideOverlay(); return; } lastEl = el; var r = el.getBoundingClientRect(); var o = ensureOverlay(); o.style.display = "block"; o.style.top = r.top + "px"; o.style.left = r.left + "px"; o.style.width = r.width + "px"; o.style.height = r.height + "px"; } window.addEventListener( "message", function (ev) { var d = ev.data; if (!d || d.source !== NS) return; if (d.type === "CMD") { enabled = d.cmd === "enable-select"; document.body.style.cursor = enabled ? "crosshair" : ""; if (!enabled) hideOverlay(); } }, false, ); document.addEventListener( "mousemove", function (e) { if (!enabled) return; var el = document.elementFromPoint(e.clientX, e.clientY); if (!el || el === overlay || (overlay && overlay.contains(el))) return; moveOverlay(el); }, true, ); document.addEventListener( "click", function (e) { if (!enabled) return; e.preventDefault(); e.stopPropagation(); if (e.stopImmediatePropagation) e.stopImmediatePropagation(); var el = lastEl || document.elementFromPoint(e.clientX, e.clientY); if (!el || el === overlay) return; var payload = { selector: shortSelector(el), tagName: el.tagName.toLowerCase(), textSnippet: snippetText(el, 200), outerHtmlSnippet: outerSnip(el, 500), }; enabled = false; document.body.style.cursor = ""; hideOverlay(); window.parent.postMessage({ source: NS, type: "PICK", payload: payload }, "*"); }, true, ); window.addEventListener( "scroll", function () { if (enabled && lastEl) moveOverlay(lastEl); }, true, ); try { window.parent.postMessage( { source: NS, type: "BRIDGE_READY", payload: { origin: window.location.origin } }, "*", ); } catch (e) { /* ignore */ } })();