UNPKG

@uiw/react-iframe

Version:

This component allows you to wrap your entire React application or each component in an iFrame.

100 lines 3.54 kB
import _extends from "@babel/runtime/helpers/extends"; import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose"; var _excluded = ["children", "head", "initialContent", "src", "mountTarget"]; import { useCallback, useEffect, useState, forwardRef, useImperativeHandle, useMemo, useRef } from 'react'; import { createPortal } from 'react-dom'; import { FrameContext } from "./Context.js"; import { jsx as _jsx } from "react/jsx-runtime"; export { FrameContext, useFrame } from "./Context.js"; var IFrame = /*#__PURE__*/forwardRef((_ref, ref) => { var { children, head, initialContent, src, mountTarget } = _ref, other = _objectWithoutPropertiesLoose(_ref, _excluded); var [iframeLoaded, setIframeLoaded] = useState(false); var [mountNode, setMountNode] = useState(); var refContent = node => { if (node) { setMountNode(node); } }; useImperativeHandle(ref, () => mountNode, [mountNode]); var html = initialContent || "<!DOCTYPE html><html><head></head><body></body></html>"; var getDoc = () => mountNode ? mountNode.contentDocument : null; var getMountTarget = () => { var doc = getDoc(); if (mountTarget) { return doc == null ? void 0 : doc.querySelector(mountTarget); } return doc == null ? void 0 : doc.body; }; var evnRef = useRef(); var handleLoad = useCallback(evn => { evnRef.current = evn; /** * In certain situations on a cold cache DOMContentLoaded never gets called * fallback to an interval to check if that's the case */ var loadCheck = () => setInterval(() => handleLoad(evn), 500); clearInterval(loadCheck()); // Bail update as some browsers will trigger on both DOMContentLoaded & onLoad ala firefox if (!iframeLoaded) { setIframeLoaded(true); } }, [iframeLoaded]); useMemo(() => { if (!src && other.onLoad && iframeLoaded) { other.onLoad(evnRef.current); } }, [iframeLoaded]); useEffect(() => { if (mountNode && !src) { var _mountNode$contentWin; (_mountNode$contentWin = mountNode.contentWindow) == null || _mountNode$contentWin.addEventListener('DOMContentLoaded', handleLoad); } return () => { if (mountNode && !src) { var _mountNode$contentWin2; (_mountNode$contentWin2 = mountNode.contentWindow) == null || _mountNode$contentWin2.removeEventListener('DOMContentLoaded', handleLoad); } }; }, [mountNode, handleLoad]); var renderFrameContents = () => { var _getDoc; var doc = getDoc(); var header = (_getDoc = getDoc()) == null ? void 0 : _getDoc.head; var mountTarget = getMountTarget(); // @ts-ignore var win = (doc == null ? void 0 : doc.defaultView) || (doc == null ? void 0 : doc.parentView); var contents = /*#__PURE__*/_jsx(FrameContext.Provider, { value: { document: doc, window: win }, children: children }); return [header && head && /*#__PURE__*/createPortal(head, header), mountNode && mountTarget && /*#__PURE__*/createPortal(contents, mountTarget)]; }; var reProps = {}; if (src) { delete reProps.srcDoc; reProps.src = src; reProps.onLoad = other.onLoad; } else { reProps.srcDoc = html; } return /*#__PURE__*/_jsx("iframe", _extends({ title: other.title, ref: refContent }, other, { onLoad: handleLoad }, reProps, { children: iframeLoaded && renderFrameContents() })); }); IFrame.displayName = 'IFrame'; export default IFrame;