UNPKG

@open-iframe-resizer/react

Version:

Open-source modern iframe resizer component

244 lines (243 loc) 7.66 kB
"use client"; import { jsx as M } from "react/jsx-runtime"; import { forwardRef as k, useRef as O, useEffect as A, useCallback as H } from "react"; const S = () => typeof window < "u", D = () => window.self !== window.top, w = (e) => e instanceof HTMLIFrameElement, P = (e) => { window.document.readyState === "complete" ? e() : window.addEventListener("load", e); }, T = (e, t) => { t(), e.addEventListener("load", t); }, x = (e, t) => { var n, r; const i = ((n = e.contentWindow) == null ? void 0 : n.document.readyState) === "complete"; return e.src !== "about:blank" && ((r = e.contentWindow) == null ? void 0 : r.location.href) !== "about:blank" && i ? t() : e.addEventListener("load", t); }, C = () => ({ offsetSize: 0, checkOrigin: !0, enableLegacyLibSupport: !1 }), W = (e) => { try { return new URL(e.src).origin === window.location.origin; } catch { return !1; } }, B = (e) => { try { const t = new URL(e.src).origin; if (t !== "about:blank") return t; } catch { } return null; }, F = (e) => (Object.keys(e).forEach((t) => e[t] === void 0 && delete e[t]), e), z = (e) => { const { height: t, width: n } = e.getBoundingClientRect(); return { height: Math.ceil(t), width: Math.ceil(n) }; }, m = (e, t) => e ? t ? e.querySelector(t) : e.documentElement : null, L = (e, t) => { e && (t.bodyPadding && (e.body.style.padding = t.bodyPadding), t.bodyMargin && (e.body.style.margin = t.bodyMargin)); }, y = (e) => e <= 100 ? 100 : e <= 120 ? 1e3 : 1e4, q = () => "[iFrameSizer]ID:0:false:false:32:true:true::auto:::0:false:child:auto:true:::true:::false"; function N(e) { if (typeof e.data != "string" || !e.data.startsWith("[iFrameSizer]") || !e.data.endsWith("mutationObserver") && !e.data.endsWith("resizeObserver")) return null; const [t, n] = e.data.split(":"), r = +n; return r > 0 ? r : null; } const p = J(); let f = []; const U = (e, t) => { if (!S()) return []; const n = { ...C(), ...F(e ?? {}) }, r = j(t), i = $(n, r); return r.map((s) => { const o = { iframe: s, settings: n, interactionState: { isHovered: !1 }, initContext: { isInitialized: !1, retryAttempts: 0 } }, a = G(o, i); return f.push(o), { unsubscribe: () => { a(), f = f.filter((c) => c.iframe !== s); } }; }); }; function j(e) { return typeof e == "string" ? Array.from(document.querySelectorAll(e)).filter(w) : e ? w(e) ? [e] : [] : Array.from(document.getElementsByTagName("iframe")); } function $(e, t) { if (Array.isArray(e.checkOrigin)) return e.checkOrigin; if (!e.checkOrigin) return []; const n = []; for (const r of t) { const i = B(r); i && n.push(i); } return n; } function G(e, t) { const n = W(e.iframe) ? V(e) : K(e, t), r = _(e); return () => { n(), r(); }; } function K(e, t) { const { iframe: n, initContext: r, settings: { checkOrigin: i, enableLegacyLibSupport: s, targetElementSelector: o, bodyPadding: a, bodyMargin: c } } = e, d = (u) => { var v; const I = !i || t.includes(u.origin); if (!(n.contentWindow !== u.source || !I)) { if (((v = u.data) == null ? void 0 : v.type) === "iframe-resized") { const { height: l } = u.data; l && g({ newHeight: l, registeredElement: e }); return; } if (s) { const l = N(u); l !== null && g({ newHeight: l, registeredElement: e }); return; } } }; window.addEventListener("message", d); const h = s ? q() : { type: "iframe-child-init", targetElementSelector: o, bodyPadding: a, bodyMargin: c }, b = () => { T(n, () => { var u; return (u = n.contentWindow) == null ? void 0 : u.postMessage(h, "*"); }), r.retryAttempts++, r.retryTimeoutId = window.setTimeout(b, y(r.retryAttempts)); }; return b(), () => window.removeEventListener("message", d); } function V(e) { const { iframe: t, settings: n } = e, { targetElementSelector: r } = n; let i = 0; const s = () => { const o = m(t.contentDocument, r); if (!t.contentDocument || !o) return i++, setTimeout(s, y(i)); L(t.contentDocument, n), p().observe(o); }; return x(t, s), () => { const o = m(t.contentDocument, r); o && p().unobserve(o), t.removeEventListener("load", s); }; } function _({ iframe: e, interactionState: t }) { const n = () => { t.isHovered = !0; }, r = () => { t.isHovered = !1; }; return e.addEventListener("mouseenter", n), e.addEventListener("mouseleave", r), () => { e.removeEventListener("mouseenter", n), e.removeEventListener("mouseleave", r); }; } function J() { let e = null; return () => { if (!e) { const t = ({ target: n }) => { const r = f.find(({ iframe: c }) => c.contentDocument === n.ownerDocument); if (!r) return; const { iframe: i, settings: s } = r, o = m(i.contentDocument, s.targetElementSelector); if (!o) return; const { height: a } = z(o); a && g({ newHeight: a, registeredElement: r }); }; e = new ResizeObserver((n) => n.forEach(t)); } return e; }; } function g({ registeredElement: e, newHeight: t }) { var n; const { iframe: r, settings: i, interactionState: s, initContext: o } = e; if (o.isInitialized || (o.isInitialized = !0, clearTimeout(o.retryTimeoutId)), ((n = i.onBeforeIframeResize) == null ? void 0 : n.call(i, { iframe: r, settings: { ...i }, observedHeight: t })) === !1) return; const a = r.getBoundingClientRect(), c = t + i.offsetSize; if (r.style.height = `${c}px`, !i.onIframeResize) return; const d = { iframe: r, settings: { ...i }, interactionState: { ...s }, previousRenderState: { rect: a }, nextRenderState: { rect: r.getBoundingClientRect() } }; i.onIframeResize(d); } const Q = Y(); let E = !1; X(); function X() { !S() || !D() || window.addEventListener("message", (e) => { var t; ((t = e.data) == null ? void 0 : t.type) === "iframe-child-init" && P(() => R(e)); }); } function R(e, t = 0) { const { targetElementSelector: n, bodyPadding: r, bodyMargin: i } = e.data, s = m(document, n); if (E || window.parent !== e.source) return; if (!s) return setTimeout(() => R(e, t + 1), y(t)); L(document, { bodyMargin: i, bodyPadding: r }); const o = Q(); o.disconnect(), o.observe(s), E = !0; } function Y() { let e = null; return () => (e || (e = new ResizeObserver((t) => { if (!t[0].target) return; const { height: n, width: r } = z(t[0].target), i = { type: "iframe-resized", width: r, height: n }; window.parent.postMessage(i, "*"); })), e); } const Z = k((e, t) => { const n = O(null), { settings: r, iframeAttributes: i } = ee(e); A(() => { if (!n.current) return; const o = U(r, n.current); return () => o.forEach((a) => a.unsubscribe()); }, []); const s = H( (o) => { n.current = o, typeof t == "function" ? t(o) : t && (t.current = o); }, [t] ); return /* @__PURE__ */ M("iframe", { ...i, ref: s }); }); Z.displayName = "IframeResizer"; function ee(e) { const { offsetSize: t, enableLegacyLibSupport: n, checkOrigin: r, onIframeResize: i, onBeforeIframeResize: s, targetElementSelector: o, bodyMargin: a, bodyPadding: c, ...d } = e; return { iframeAttributes: d, settings: { offsetSize: t, enableLegacyLibSupport: n, checkOrigin: r, onIframeResize: i, onBeforeIframeResize: s, targetElementSelector: o, bodyMargin: a, bodyPadding: c } }; } export { Z as IframeResizer };