fix: typescript error

This commit is contained in:
lloydzhou 2024-08-21 11:54:48 +08:00
parent b0e9a542ba
commit 4b9697e336
2 changed files with 86 additions and 77 deletions

View File

@ -23,84 +23,89 @@ import { Path, ApiPath, REPO_URL } from "@/app/constant";
import { Loading } from "./home"; import { Loading } from "./home";
import styles from "./artifacts.module.scss"; import styles from "./artifacts.module.scss";
export const HTMLPreview = forwardRef< type HTMLPreviewProps = {
{ code: string;
reload: () => void; autoHeight?: boolean;
}, height?: number | string;
{ onLoad?: (title?: string) => void;
code: string; };
autoHeight?: boolean;
height?: number | string;
onLoad?: (title?: string) => void;
}
>(function HTMLPreview(props, ref) {
const iframeRef = useRef<HTMLIFrameElement>(null);
const [frameId, setFrameId] = useState<string>(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(() => { export type HTMLPreviewHander = {
const handleMessage = (e: any) => { reload: () => void;
const { id, height, title } = e.data; };
setTitle(title);
if (id == frameId) { export const HTMLPreview = forwardRef<HTMLPreviewHander, HTMLPreviewProps>(
setIframeHeight(height); function HTMLPreview(props, ref) {
const iframeRef = useRef<HTMLIFrameElement>(null);
const [frameId, setFrameId] = useState<string>(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) {
setIframeHeight(height);
}
};
window.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
};
}, [frameId]);
useImperativeHandle(ref, () => ({
reload: () => {
setFrameId(nanoid());
},
}));
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]);
const srcDoc = useMemo(() => {
const script = `<script>new ResizeObserver((entries) => parent.postMessage({id: '${frameId}', height: entries[0].target.clientHeight}, '*')).observe(document.body)</script>`;
if (props.code.includes("</head>")) {
props.code.replace("</head>", "</head>" + script);
}
return props.code + script;
}, [props.code, frameId]);
const handleOnLoad = () => {
if (props?.onLoad) {
props.onLoad(title);
} }
}; };
window.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
};
}, [frameId]);
useImperativeHandle(ref, () => ({ return (
reload: () => { <iframe
setFrameId(nanoid()); className={styles["artifacts-iframe"]}
}, key={frameId}
})); ref={iframeRef}
sandbox="allow-forms allow-modals allow-scripts"
const height = useMemo(() => { style={{ height }}
if (!props.autoHeight) return props.height || 600; srcDoc={srcDoc}
if (typeof props.height === "string") { onLoad={handleOnLoad}
return props.height; />
} );
const parentHeight = props.height || 600; },
return iframeHeight + 40 > parentHeight ? parentHeight : iframeHeight + 40; );
}, [props.autoHeight, props.height, iframeHeight]);
const srcDoc = useMemo(() => {
const script = `<script>new ResizeObserver((entries) => parent.postMessage({id: '${frameId}', height: entries[0].target.clientHeight}, '*')).observe(document.body)</script>`;
if (props.code.includes("</head>")) {
props.code.replace("</head>", "</head>" + script);
}
return props.code + script;
}, [props.code, frameId]);
const handleOnLoad = () => {
if (props?.onLoad) {
props.onLoad(title);
}
};
return (
<iframe
className={styles["artifacts-iframe"]}
key={frameId}
ref={iframeRef}
sandbox="allow-forms allow-modals allow-scripts"
style={{ height }}
srcDoc={srcDoc}
onLoad={handleOnLoad}
/>
);
});
export function ArtifactsShareButton({ export function ArtifactsShareButton({
getCode, getCode,
@ -203,7 +208,7 @@ export function Artifacts() {
const [code, setCode] = useState(""); const [code, setCode] = useState("");
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [fileName, setFileName] = useState(""); const [fileName, setFileName] = useState("");
const previewRef = useRef<typeof HTMLPreview>(null); const previewRef = useRef<HTMLPreviewHander>(null);
useEffect(() => { useEffect(() => {
if (id) { if (id) {

View File

@ -14,7 +14,11 @@ import ReloadButtonIcon from "../icons/reload.svg";
import React from "react"; import React from "react";
import { useDebouncedCallback } from "use-debounce"; import { useDebouncedCallback } from "use-debounce";
import { showImageModal, FullScreen } from "./ui-lib"; import { showImageModal, FullScreen } from "./ui-lib";
import { ArtifactsShareButton, HTMLPreview } from "./artifacts"; import {
ArtifactsShareButton,
HTMLPreview,
HTMLPreviewHander,
} from "./artifacts";
import { Plugin } from "../constant"; import { Plugin } from "../constant";
import { useChatStore } from "../store"; import { useChatStore } from "../store";
import { IconButton } from "./button"; import { IconButton } from "./button";
@ -67,7 +71,7 @@ export function Mermaid(props: { code: string }) {
export function PreCode(props: { children: any }) { export function PreCode(props: { children: any }) {
const ref = useRef<HTMLPreElement>(null); const ref = useRef<HTMLPreElement>(null);
const previewRef = useRef<typeof HTMLPreview>(null); const previewRef = useRef<HTMLPreviewHander>(null);
const [mermaidCode, setMermaidCode] = useState(""); const [mermaidCode, setMermaidCode] = useState("");
const [htmlCode, setHtmlCode] = useState(""); const [htmlCode, setHtmlCode] = useState("");
const { height } = useWindowSize(); const { height } = useWindowSize();