UNPKG

@proveanything/smartlinks

Version:

Official JavaScript/TypeScript SDK for the Smartlinks API

124 lines (123 loc) 4.84 kB
// iframe.ts // Utilities to communicate with parent window when running inside an iframe. // These helpers are optional and safe in non-browser / Node environments. // They build on the existing proxyMode infrastructure but can also be used standalone. let autoResizeTimer; let lastHeight = 0; let resizeOptions; let resizeObserver; let mutationObserver; function isBrowser() { return typeof window !== 'undefined' && typeof document !== 'undefined'; } function inIframe() { return isBrowser() && window.parent && window.parent !== window; } function postParentMessage(type, payload) { if (!inIframe()) return; try { window.parent.postMessage({ _smartlinksIframeMessage: true, type, payload }, '*'); } catch (_a) { // swallow errors silently } } /** Redirect parent window to a URL (if in iframe). */ export function redirectParent(url) { postParentMessage('smartlinks:redirect', { url }); } /** Request parent to adjust iframe height to current content height. */ export function sendHeight(height, extra) { if (!inIframe()) return; const h = height !== null && height !== void 0 ? height : document.documentElement.scrollHeight; postParentMessage((resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.messageType) || 'smartlinks:resize', Object.assign(Object.assign({ height: h }, resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.extra), extra)); } function measureHeight() { if (!isBrowser()) return 0; const doc = document.documentElement; // Use max of several properties for robustness return Math.max(doc.scrollHeight, doc.offsetHeight, doc.clientHeight, document.body ? document.body.scrollHeight : 0, document.body ? document.body.offsetHeight : 0); } function scheduleManualPolling() { var _a; if (!isBrowser()) return; clearInterval(autoResizeTimer); const interval = (_a = resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.intervalMs) !== null && _a !== void 0 ? _a : 100; autoResizeTimer = window.setInterval(() => { const h = measureHeight(); if ((resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.alwaysSend) || h !== lastHeight) { lastHeight = h; sendHeight(h); } }, interval); } function setupObservers() { if (!isBrowser()) return; // Prefer ResizeObserver for layout changes if (typeof ResizeObserver !== 'undefined') { resizeObserver = new ResizeObserver(() => { const h = measureHeight(); if ((resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.alwaysSend) || h !== lastHeight) { lastHeight = h; sendHeight(h); } }); resizeObserver.observe(document.body); } else { // Fallback: MutationObserver for DOM changes mutationObserver = new MutationObserver(() => { const h = measureHeight(); if ((resizeOptions === null || resizeOptions === void 0 ? void 0 : resizeOptions.alwaysSend) || h !== lastHeight) { lastHeight = h; sendHeight(h); } }); mutationObserver.observe(document.body, { childList: true, subtree: true, attributes: true }); // Manual polling as additional safeguard scheduleManualPolling(); } } /** Enable automatic height reporting to parent iframe. */ export function enableAutoIframeResize(options) { if (!inIframe()) return; resizeOptions = options || {}; lastHeight = measureHeight(); sendHeight(lastHeight); setupObservers(); if (!resizeObserver) { // If no ResizeObserver, MutationObserver is active and we also poll scheduleManualPolling(); } } /** Disable automatic height reporting. */ export function disableAutoIframeResize() { if (resizeObserver) resizeObserver.disconnect(); if (mutationObserver) mutationObserver.disconnect(); if (isBrowser()) clearInterval(autoResizeTimer); resizeObserver = undefined; mutationObserver = undefined; autoResizeTimer = undefined; resizeOptions = undefined; } /** Send a custom message to parent (browser-only). */ export function sendParentCustom(type, payload) { postParentMessage(type, payload); } /** Returns true if running inside an iframe (browser). */ export function isIframe() { return inIframe(); } /** Returns true if ResizeObserver is supported in current environment. */ export function supportsResizeObserver() { return typeof ResizeObserver !== 'undefined'; }