import React, { HTMLAttributes, useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { SilkeIframeContext, SilkeIframeContextModel } from './silke-iframe-context';
type SilkeIframePortalProps = Omit, 'sandbox'> & {
children: React.ReactNode;
/** Override default srcDoc */
srcDoc?: string;
autoResize?: boolean;
bodyStyle?: React.CSSProperties;
};
const DEFAULT_SRC_DOC =
'';
export function SilkeIframePortal({
bodyStyle,
children,
style,
srcDoc,
autoResize,
onLoad,
...rest
}: SilkeIframePortalProps) {
const iframeRef = useRef(null);
const [innerElement, setInnerElement] = useState();
const [context, setContext] = useState({});
const handleLoad: React.ReactEventHandler = useCallback((e) => {
const iframe = e.currentTarget;
const doc = iframe.contentDocument;
const win = iframe.contentWindow;
if (doc && win) {
const innerElement = doc.createElement('div');
doc.body.appendChild(innerElement);
setInnerElement(innerElement);
setContext({ doc, win });
}
onLoad?.(e);
}, []);
const body = context.doc?.body;
useEffect(() => {
if (body) {
Object.assign(body.style, bodyStyle);
}
}, [bodyStyle, body]);
useEffect(() => {
const iframe = iframeRef.current;
if (iframe && body && autoResize) {
const handleResize = () => {
const { height } = body.getBoundingClientRect();
iframe.style.height = `${height}px`;
};
const resizeObserver = new ResizeObserver(handleResize);
handleResize();
resizeObserver.observe(body);
return () => resizeObserver.disconnect();
}
}, [body, autoResize]);
return (
{innerElement && createPortal(children, innerElement)}
);
}