Files
upage-git/app/components/editor/EditorRender.tsx
2025-09-24 17:02:44 +08:00

95 lines
2.7 KiB
TypeScript

import { forwardRef, useRef } from 'react';
import Frame from 'react-frame-component';
export interface EditorRenderProps {
onMount: (iframe: HTMLIFrameElement | null) => void;
children?: React.ReactNode;
}
/**
* 使用 HTML 来渲染编辑器。并在 HTML 有所变化时,调用更新函数。
* 为了保证纯净性,此函数将只考虑渲染 HTML 以及更新,与外部的所有交互无关。
*/
export const EditorRender = forwardRef<HTMLDivElement, EditorRenderProps>(({ onMount, children }, ref) => {
const frameRef = useRef<HTMLIFrameElement | null>(null);
// 初始化的 HTML 内容,如果有 HTML 所需的一些外部资源,可以在这里添加。但需要注意的是,导出时,需要将这些资源也导出。
const initialContent = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html, body {
margin: 0;
height: 100%;
width: 100%;
}
iframe {
border: none;
}
.page-iframe {
align-items: center;
display: flex;
height: 100%;
justify-content: center;
width: 100%;
}
</style>
</head>
<body>
<div id="editor-content"></div>
</body>
</html>
`;
return (
<div className="editor-render w-full h-full relative">
<Frame
ref={frameRef}
initialContent={initialContent}
mountTarget="#editor-content"
height="100%"
width="100%"
className="w-full h-full"
style={{ border: 'none', margin: 0, padding: 0 }}
contentDidMount={() => {
onMount(frameRef.current);
}}
sandbox="allow-scripts allow-same-origin allow-downloads allow-popups allow-top-navigation-by-user-activation allow-top-navigation-to-custom-protocols"
head={
<>
<style>
{`
*:focus-visible {
outline: none;
}
#editor-content, .frame-content {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
display: block;
}
.editor-editing {
outline: 2px dashed #3b82f6 !important;
outline-offset: -2px;
min-height: 1em;
position: relative;
}
`}
</style>
</>
}
>
<div ref={ref} style={{ width: '100%', height: '100%', margin: 0, padding: 0 }}>
{children}
</div>
</Frame>
</div>
);
});