UNPKG

@viamedici-spc/configurator-framer-host

Version:

Provides a Web Component for host applications to embed a Framer based Viamedici SPC configurator.

181 lines (180 loc) 8.38 kB
function v(s) { var e = []; if (s.length === 0) return ""; if (typeof s[0] != "string") throw new TypeError("Url must be a string. Received " + s[0]); if (s[0].match(/^[^/:]+:\/*$/) && s.length > 1) { var o = s.shift(); s[0] = o + s[0]; } s[0].match(/^file:\/\/\//) ? s[0] = s[0].replace(/^([^/:]+):\/*/, "$1:///") : s[0] = s[0].replace(/^([^/:]+):\/*/, "$1://"); for (var t = 0; t < s.length; t++) { var r = s[t]; if (typeof r != "string") throw new TypeError("Url must be a string. Received " + r); r !== "" && (t > 0 && (r = r.replace(/^[\/]+/, "")), t < s.length - 1 ? r = r.replace(/[\/]+$/, "") : r = r.replace(/[\/]+$/, "/"), e.push(r)); } var n = e.join("/"); n = n.replace(/\/(\?|&|#[^!])/g, "$1"); var a = n.split("?"); return n = a.shift() + (a.length > 0 ? "?" : "") + a.join("&"), n; } function x() { var s; return typeof arguments[0] == "object" ? s = arguments[0] : s = [].slice.call(arguments), v(s); } const f = class l extends HTMLElement { constructor() { super(), this.src = null, this.proxyBaseUrl = l.proxyBaseUrl, this.hasConnected = !1; } static get observedAttributes() { return l.attributeNames; } connectedCallback() { this.hasConnected = !0, this.src && (console.log("[Configurator] Web Component connected -> reinitialize the configurator app."), this.bootstrapApp()); } attributeChangedCallback(e, o, t) { e === "src" && t !== o ? (this.src = t, this.hasConnected && this.isConnected && this.src && (console.log("[Configurator] The URL was changed -> reinitialize the configurator app."), this.bootstrapApp())) : e === "proxy-base-url" && t !== o && (this.proxyBaseUrl = t ?? l.proxyBaseUrl); } async bootstrapApp() { try { let e; try { const i = x(this.proxyBaseUrl, `?url=${this.src}`); e = await fetch(i); } catch (i) { console.error("[Configurator] Failed to bootstrap configurator app: Failed to load index.html.", i); return; } for (; this.firstChild; ) this.removeChild(this.firstChild); const o = await e.text(), t = new DOMParser().parseFromString(o, "text/html"), r = t.querySelector("style[data-framer-css-ssr-minified]") || t.querySelector("style[data-framer-css-ssr]"), n = t.querySelector("div#main"), a = t.querySelector('script[data-framer-bundle="main"]'), c = t.querySelector('script[type="importmap"][data-framer-importmap]'); if (!r || !r.textContent) { console.error("[Configurator] Failed to bootstrap configurator app: Could not find the style element."); return; } if (!n) { console.error("[Configurator] Failed to bootstrap configurator app: Could not find the main div."); return; } if (!a || !(a instanceof HTMLScriptElement)) { console.error("[Configurator] Failed to bootstrap configurator app: Could not find the main entry script."); return; } const y = r.textContent.split("}").filter((i) => { const d = i.trim(); return !// Remove some rules that may interfere too much with the host (d.startsWith("html,body,#main") || d.startsWith("h1,h2,h3,h4,h5,h6,p,figure") || d.startsWith("body,input,textarea,select,button")); }).map((i) => i.trim()).join(`} `), h = document.createElement("style"); for (const i of r.attributes) h.setAttribute(i.name, i.value); if (h.textContent = y, this.appendChild(h), this.appendChild(n.cloneNode()), c && c.textContent) { const i = document.createElement("script"); i.type = "importmap", i.textContent = c.textContent, this.appendChild(i); } if (a.src) { const i = document.createElement("script"); i.type = "module", i.src = a.src, i.setAttribute("async", ""), this.appendChild(i); } else if (a.textContent) { const i = document.createElement("script"); i.type = "module", i.textContent = a.textContent, this.appendChild(i); } else console.error("[Configurator] Script tag found, but no src or content available."); } catch (e) { console.error("[Configurator] Failed to bootstrap configurator app", e); } } }; f.proxyBaseUrl = "https://spc.cloud.ceventis.de/framer/host-proxy"; f.attributeNames = ["src", "proxy-base-url"]; let p = f; const m = class g extends HTMLElement { constructor() { super(), this.src = null, this.hasConnected = !1, this.iframe = null, this.autoHeightHandler = null, this.allowedOrigin = null; } static get observedAttributes() { return g.attributeNames; } connectedCallback() { this.hasConnected = !0, this.src && (console.log("[Configurator] Web Component connected -> reinitialize the configurator app."), this.bootstrapApp()); } disconnectedCallback() { this.removeAutoHeightSync(); } attributeChangedCallback(e, o, t) { e === "src" && t !== o && (this.src = t, this.hasConnected && this.isConnected && this.src && (console.log("[Configurator] The src was changed -> reinitialize the configurator app."), this.iframe ? this.iframe.src = this.src : this.bootstrapApp())); } bootstrapApp() { if (!this.src) { console.error("[Configurator] Cannot bootstrap iframe: src is missing."); return; } for (this.removeAutoHeightSync(); this.firstChild; ) this.removeChild(this.firstChild); this.iframe = document.createElement("iframe"), this.iframe.src = this.src; try { this.allowedOrigin = new URL(this.src).origin; } catch { console.warn("[Configurator] Invalid src URL provided, cannot derive allowed origin. Height synchronisation is disabled."), this.allowedOrigin = null; } this.iframe.width = "100%", this.iframe.height = "100%", this.iframe.style.border = "none", this.appendChild(this.iframe), this.getAttribute("no-auto-height") != null && this.getAttribute("no-auto-height") != "false" || this.useAutoHeightSync(); } useAutoHeightSync() { this.autoHeightHandler = (e) => { var o; this.allowedOrigin && e.origin !== this.allowedOrigin || ((o = e.data) == null ? void 0 : o.type) !== "spc.configurator.height" || typeof e.data.height != "number" || (console.log("[Configurator] Received new height from iFrame -> Apply", e.data.height), this.iframe.style.height = `${e.data.height + 10}px`); }, window.addEventListener("message", this.autoHeightHandler); } removeAutoHeightSync() { this.autoHeightHandler && (window.removeEventListener("message", this.autoHeightHandler), this.autoHeightHandler = null); } }; m.attributeNames = ["src", "no-auto-height"]; let b = m; const C = class u extends HTMLElement { constructor() { super(), this.child = null, this.isIsolated = !1; } static get observedAttributes() { return ["isolated", ...u.childAttributes]; } connectedCallback() { this.initialize(); } disconnectedCallback() { this.child && this.contains(this.child) && this.removeChild(this.child), this.child = null; } attributeChangedCallback(e, o, t) { if (e === "isolated") { const r = t !== null && t !== "false"; if (r !== this.isIsolated) { console.log("[Configurator] The isolation mode was changed -> reinitialize the configurator app."), this.isIsolated = r, this.initialize(); return; } } this.child && o !== t && (t === null ? this.child.removeAttribute(e) : this.child.setAttribute(e, t)); } initialize() { const e = this.getAttribute("isolated"); this.isIsolated = e !== null && e !== "false"; const o = this.isIsolated ? "spc-embedded-configurator-iframe" : "spc-embedded-configurator-native"; if (this.child && this.child.tagName.toLowerCase() === o) return; this.child && this.removeChild(this.child); const t = document.createElement(o); for (const { name: r, value: n } of Array.from(this.attributes)) u.childAttributes.some((a) => a === r) && n !== null && t.setAttribute(r, n); this.appendChild(t), this.child = t; } }; C.childAttributes = [...p.attributeNames, ...b.attributeNames]; let E = C; customElements.define("spc-embedded-configurator", E); customElements.define("spc-embedded-configurator-native", p); customElements.define("spc-embedded-configurator-iframe", b); export { p as EmbeddedConfiguratorNative, E as EmbeddedConfiguratorStrategy };