diff --git a/app/components/artifacts.tsx b/app/components/artifacts.tsx index 326891e736a..e1132804a37 100644 --- a/app/components/artifacts.tsx +++ b/app/components/artifacts.tsx @@ -1,4 +1,11 @@ -import { useEffect, useState, useRef, useMemo } from "react"; +import { + useEffect, + useState, + useRef, + useMemo, + forwardRef, + useImperativeHandle, +} from "react"; import { useParams } from "react-router"; import { useWindowSize } from "@/app/utils"; import { IconButton } from "./button"; @@ -8,6 +15,7 @@ import CopyIcon from "../icons/copy.svg"; import DownloadIcon from "../icons/download.svg"; import GithubIcon from "../icons/github.svg"; import LoadingButtonIcon from "../icons/loading.svg"; +import ReloadButtonIcon from "../icons/reload.svg"; import Locale from "../locales"; import { Modal, showToast } from "./ui-lib"; import { copyToClipboard, downloadAs } from "../utils"; @@ -15,73 +23,89 @@ import { Path, ApiPath, REPO_URL } from "@/app/constant"; import { Loading } from "./home"; import styles from "./artifacts.module.scss"; -export function HTMLPreview(props: { +type HTMLPreviewProps = { code: string; autoHeight?: boolean; height?: number | string; onLoad?: (title?: string) => void; -}) { - const ref = useRef(null); - const frameId = useRef(nanoid()); - const [iframeHeight, setIframeHeight] = useState(600); - const [title, setTitle] = useState(""); - /* - * https://stackoverflow.com/questions/19739001/what-is-the-difference-between-srcdoc-and-src-datatext-html-in-an - * 1. using srcdoc - * 2. using src with dataurl: - * easy to share - * length limit (Data URIs cannot be larger than 32,768 characters.) - */ +}; - useEffect(() => { - const handleMessage = (e: any) => { - const { id, height, title } = e.data; - setTitle(title); - if (id == frameId.current) { - setIframeHeight(height); - } - }; - window.addEventListener("message", handleMessage); - return () => { - window.removeEventListener("message", handleMessage); - }; - }, []); +export type HTMLPreviewHander = { + reload: () => void; +}; - const height = useMemo(() => { - if (!props.autoHeight) return props.height || 600; - if (typeof props.height === "string") { - return props.height; - } - const parentHeight = props.height || 600; - return iframeHeight + 40 > parentHeight ? parentHeight : iframeHeight + 40; - }, [props.autoHeight, props.height, iframeHeight]); +export const HTMLPreview = forwardRef( + function HTMLPreview(props, ref) { + const iframeRef = useRef(null); + const [frameId, setFrameId] = useState(nanoid()); + const [iframeHeight, setIframeHeight] = useState(600); + const [title, setTitle] = useState(""); + /* + * https://stackoverflow.com/questions/19739001/what-is-the-difference-between-srcdoc-and-src-datatext-html-in-an + * 1. using srcdoc + * 2. using src with dataurl: + * easy to share + * length limit (Data URIs cannot be larger than 32,768 characters.) + */ - const srcDoc = useMemo(() => { - const script = ``; - if (props.code.includes("")) { - props.code.replace("", "" + script); - } - return props.code + script; - }, [props.code]); + useEffect(() => { + const handleMessage = (e: any) => { + const { id, height, title } = e.data; + setTitle(title); + if (id == frameId) { + setIframeHeight(height); + } + }; + window.addEventListener("message", handleMessage); + return () => { + window.removeEventListener("message", handleMessage); + }; + }, [frameId]); - const handleOnLoad = () => { - if (props?.onLoad) { - props.onLoad(title); - } - }; + useImperativeHandle(ref, () => ({ + reload: () => { + setFrameId(nanoid()); + }, + })); - return ( -