Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 1x 24x 24x 24x 29x 14x 24x 24x 24x 24x 8x 8x 2x 6x 24x 24x 8x 8x 8x 8x 8x 24x 10x 24x 15x 8x 15x 14x 8x 24x 8x 8x 8x 8x 8x 8x 24x 24x 3x 3x 3x 21x 24x 1x | import { useCallback, useEffect, useState, forwardRef, useImperativeHandle, useMemo, useRef } from 'react'; import { createPortal } from 'react-dom'; import { FrameContext } from './Context'; export { FrameContext, useFrame } from './Context'; export interface IFrameProps extends React.DetailedHTMLProps<React.IframeHTMLAttributes<HTMLIFrameElement>, HTMLIFrameElement> { /** * The `head` prop is a dom node that gets inserted before the children of the frame. */ head?: React.ReactNode; /** * The `initialContent` props is the initial html injected into frame. * It is only injected once, * but allows you to insert any html into the frame (e.g. a [`<head>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head) tag, [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script) tags, etc). * Note that it does not update if you change the prop. * * Defaults to `<!DOCTYPE html><html><head></head><body></body></html>` */ initialContent?: string; /** * The `mountTarget` attribute is a css selector (`#target`/`.target`) that specifies the child within the initial content of the iframe to be mounted. */ mountTarget?: string; } const IFrame = forwardRef<HTMLIFrameElement, IFrameProps>( ({ children, head, initialContent, src, mountTarget, ...other }, ref) => { const [iframeLoaded, setIframeLoaded] = useState(false); const [mountNode, setMountNode] = useState<HTMLIFrameElement>(); const refContent = (node: HTMLIFrameElement) => { if (node) { setMountNode(node); } }; useImperativeHandle(ref, () => mountNode!, [mountNode]); const html = initialContent || `<!DOCTYPE html><html><head></head><body></body></html>`; const getDoc = () => (mountNode ? mountNode.contentDocument : null); const getMountTarget = () => { const doc = getDoc(); if (mountTarget) { return doc?.querySelector(mountTarget); } return doc?.body; }; const evnRef = useRef<React.SyntheticEvent<HTMLIFrameElement, Event>>(); const handleLoad = useCallback<(evn: React.SyntheticEvent<HTMLIFrameElement, Event> | Event) => void>( (evn) => { evnRef.current = evn as React.SyntheticEvent<HTMLIFrameElement, Event>; /** * In certain situations on a cold cache DOMContentLoaded never gets called * fallback to an interval to check if that's the case */ const loadCheck = () => setInterval(() => handleLoad(evn), 500); clearInterval(loadCheck()); // Bail update as some browsers will trigger on both DOMContentLoaded & onLoad ala firefox Eif (!iframeLoaded) { setIframeLoaded(true); } }, [iframeLoaded], ); useMemo(() => { Iif (!src && other.onLoad && iframeLoaded) { other.onLoad(evnRef.current!); } }, [iframeLoaded]); useEffect(() => { if (mountNode && !src) { mountNode.contentWindow?.addEventListener('DOMContentLoaded', handleLoad); } return () => { if (mountNode && !src) { mountNode.contentWindow?.removeEventListener('DOMContentLoaded', handleLoad); } }; }, [mountNode, handleLoad]); const renderFrameContents = () => { const doc = getDoc(); const header = getDoc()?.head; const mountTarget = getMountTarget(); // @ts-ignore const win = doc?.defaultView || doc?.parentView; const contents = <FrameContext.Provider value={{ document: doc, window: win }}>{children}</FrameContext.Provider>; return [ header && head && createPortal(head, header), mountNode && mountTarget && createPortal(contents, mountTarget), ]; }; const reProps: IFrameProps = {}; if (src) { delete reProps.srcDoc; reProps.src = src; reProps.onLoad = other.onLoad; } else { reProps.srcDoc = html; } return ( <iframe title={other.title} ref={refContent} {...other} onLoad={handleLoad} {...reProps}> {iframeLoaded && renderFrameContents()} </iframe> ); }, ); IFrame.displayName = 'IFrame'; export default IFrame; |