markdown-flow-ui 0.1.104-alpha.4 → 0.1.104-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/index.cjs5.js +1 -1
- package/dist/_virtual/index.cjs6.js +1 -1
- package/dist/_virtual/index.es5.js +4 -4
- package/dist/_virtual/index.es6.js +4 -4
- package/dist/components/ContentRender/IframeSandbox.cjs.js +9 -2
- package/dist/components/ContentRender/IframeSandbox.cjs.js.map +1 -1
- package/dist/components/ContentRender/IframeSandbox.es.js +161 -157
- package/dist/components/ContentRender/IframeSandbox.es.js.map +1 -1
- package/dist/node_modules/hast-util-to-jsx-runtime/lib/index.cjs.js +1 -1
- package/dist/node_modules/hast-util-to-jsx-runtime/lib/index.es.js +1 -1
- package/dist/node_modules/unified/lib/index.cjs.js +1 -1
- package/dist/node_modules/unified/lib/index.es.js +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./_commonjsHelpers.cjs.js"),
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./_commonjsHelpers.cjs.js"),t=require("../node_modules/extend/index.cjs.js");var r=t.__require();const o=e.getDefaultExportFromCjs(r);exports.default=o;
|
|
2
2
|
//# sourceMappingURL=index.cjs5.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./_commonjsHelpers.cjs.js"),
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./_commonjsHelpers.cjs.js"),r=require("../node_modules/style-to-js/cjs/index.cjs.js");var t=r.__require();const o=e.getDefaultExportFromCjs(t);exports.default=o;
|
|
2
2
|
//# sourceMappingURL=index.cjs6.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { getDefaultExportFromCjs as
|
|
2
|
-
import { __require as
|
|
3
|
-
var t =
|
|
4
|
-
const a = /* @__PURE__ */
|
|
1
|
+
import { getDefaultExportFromCjs as e } from "./_commonjsHelpers.es.js";
|
|
2
|
+
import { __require as r } from "../node_modules/extend/index.es.js";
|
|
3
|
+
var t = r();
|
|
4
|
+
const a = /* @__PURE__ */ e(t);
|
|
5
5
|
export {
|
|
6
6
|
a as default
|
|
7
7
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { getDefaultExportFromCjs as
|
|
2
|
-
import { __require as
|
|
3
|
-
var t =
|
|
4
|
-
const a = /* @__PURE__ */
|
|
1
|
+
import { getDefaultExportFromCjs as r } from "./_commonjsHelpers.es.js";
|
|
2
|
+
import { __require as o } from "../node_modules/style-to-js/cjs/index.es.js";
|
|
3
|
+
var t = o();
|
|
4
|
+
const a = /* @__PURE__ */ r(t);
|
|
5
5
|
export {
|
|
6
6
|
a as default
|
|
7
7
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const E=require("../../_virtual/jsx-runtime.cjs.js"),t=require("react"),
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const E=require("../../_virtual/jsx-runtime.cjs.js"),t=require("react"),ye=require("react-dom/client"),Te=require("./SandboxApp.cjs.js"),Ae=require("./ContentRender.cjs.js"),b=require("./utils/iframe-viewport-height.cjs.js"),be=require("../../lib/sandboxInteraction.cjs.js");let Y=null;const je=()=>(Y||(Y=Promise.resolve().then(()=>require("./blackboard-vendor.cjs.js")).then(c=>c.injectBlackboardLibraries)),Y),Fe=/<img\b[^>]*>/i,Ie=180,Ne=240,Oe=c=>c.split(/\s+/).filter(Boolean).map(s=>{const i=s.split(":");return i[i.length-1]!=="h-screen"&&i[i.length-1]!=="min-h-screen"?s:(i[i.length-1]="h-full",i.join(":"))}).join(" "),_e=(c,s)=>!s||!c.trim()?c:c.replace(/^(\s*<[a-zA-Z][\w:-]*)(\s[^>]*?)?>/,(i,I,R="")=>{const h=R.match(/\bclass\s*=\s*(["'])([^"']*)\1/i);if(!h)return i;const N=Oe(h[2]);return N===h[2]?i:`${I}${R.replace(h[0],`class=${h[1]}${N}${h[1]}`)}>`}),Ve=({content:c,type:s,className:i,styleLoadingText:I,scriptLoadingText:R,fullScreenButtonText:h,hideFullScreen:N=!1,mode:d="content",replaceRootScreenHeightWithFull:pe=!1})=>{const k=t.useRef(null),p=t.useRef(null),P=t.useRef(null),S=t.useRef(()=>{}),[we,He]=t.useState(480),[Z,J]=t.useState(0),[q,K]=t.useState(0),Q=t.useRef(0),[ee,xe]=t.useState(0),[B,Ee]=t.useState(!1),Re=s==="sandbox",m=d==="blackboard",v=m&&s==="sandbox",w=v&&pe,L=t.useRef(""),O=t.useMemo(()=>s==="sandbox"?c:"",[c,s]),r=t.useMemo(()=>_e(O,w),[O,w]),te=t.useMemo(()=>w?b.inspectViewportHeightFromHtmlRootString(O):b.EMPTY_ROOT_HEIGHT_META,[O,w]),ne=t.useMemo(()=>w&&te.hasFullViewportHeight,[te.hasFullViewportHeight,w]),[_,re]=t.useState(r),oe=t.useRef(r),$=t.useRef(r),M=t.useRef(null),C=t.useRef(null),se=t.useRef(null),H=t.useCallback(n=>{if(typeof window>"u")return;const e=Date.now();e-Q.current<Ne||(Q.current=e,window.postMessage({source:be.SANDBOX_INTERACTION_MESSAGE_SOURCE,type:be.SANDBOX_INTERACTION_MESSAGE_TYPE,eventType:n},window.location.origin))},[]),z=()=>{M.current!==null&&(window.clearTimeout(M.current),M.current=null)},Se=()=>{C.current!==null&&(window.cancelAnimationFrame(C.current),C.current=null)};t.useEffect(()=>()=>{z(),Se()},[]),t.useEffect(()=>{const n=oe.current;oe.current=r;const e=!!n&&r.length>n.length&&r.startsWith(n),l=Fe.test(r);if(!(e&&l)){z(),$.current=r,re(r);return}$.current=r,z(),M.current=window.setTimeout(()=>{re($.current),M.current=null},Ie)},[r]);const V=t.useMemo(()=>v?b.inspectViewportHeightFromHtmlRootString(_).viewportHeightCss:null,[_,v]);t.useEffect(()=>{se.current=V},[V]);const ie=!!V,y=m&&s==="sandbox"?ne?"100%":V??`${we}px`:void 0;t.useEffect(()=>{if(d!=="blackboard"){L.current=r;return}const n=L.current;!(n&&r.startsWith(n))&&n&&xe(l=>l+1),L.current=r},[d,r]),t.useEffect(()=>{const n=p.current;if(!n)return;const e=n.contentDocument;if(!e)return;e.open(),e.write(`<!DOCTYPE html>
|
|
2
2
|
<html${d==="blackboard"?' style="height: 100%;"':""}>
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
@@ -9,10 +9,17 @@
|
|
|
9
9
|
${d==="blackboard"?"html, body, #root { height: 100%; }":""}
|
|
10
10
|
html, body { margin: 0; padding: 0; overflow: auto; }
|
|
11
11
|
*, *::before, *::after { box-sizing: border-box; }
|
|
12
|
+
html.measuring-height, html.measuring-height body,
|
|
13
|
+
html.measuring-height #root, html.measuring-height .sandbox-wrapper {
|
|
14
|
+
height: auto !important; min-height: 0 !important;
|
|
15
|
+
}
|
|
16
|
+
html.measuring-height * {
|
|
17
|
+
min-height: 0 !important;
|
|
18
|
+
}
|
|
12
19
|
</style>
|
|
13
20
|
</head>
|
|
14
21
|
<body>
|
|
15
22
|
<div id="root"></div>
|
|
16
23
|
</body>
|
|
17
|
-
</html>`),e.close(),e.documentElement.setAttribute("data-theme","light"),e.documentElement.style.colorScheme="light",e.body?.style.setProperty("color-scheme","light");const
|
|
24
|
+
</html>`),e.close(),e.documentElement.setAttribute("data-theme","light"),e.documentElement.style.colorScheme="light",e.body?.style.setProperty("color-scheme","light");const l=m&&s==="sandbox",W=()=>H("pointerdown"),le=()=>H("mousedown"),ue=()=>H("touchstart");l&&(e.addEventListener("pointerdown",W,!0),e.addEventListener("mousedown",le,!0),e.addEventListener("touchstart",ue,!0));const x=e.getElementById("root");if(!x)return;const ae=ye.createRoot(x);P.current=ae;let T=!1;const he=o=>({heightAttrValue:o.getAttribute("height"),styleAttrValue:o.getAttribute("style"),classAttrValue:o.getAttribute("class")}),de=o=>{const f=Array.from(o.children);return f.length===1?f[0]:null},Ce=()=>{if(!v||!p.current||!e.body)return null;const o=p.current.ownerDocument?.documentElement?.clientHeight||window.innerHeight,f=se.current,D=f?b.parseExplicitHeight(f,o):null;if(D!==null)return Math.ceil(D);const a=e.body.querySelector(".sandbox-wrapper")?.firstElementChild;if(!a)return null;const u=Array.from(a.children),g=u.length===1?u[0]:null,j=b.inspectViewportHeightFromNodeChain(g,{getNode:he,getSingleChild:de}).viewportHeightCss;if(j){const ge=b.parseExplicitHeight(j,o);if(ge!==null)return Math.ceil(ge)}const F=b.resolveExplicitHeightFromNodeChain(g,o,{getNode:he,getSingleChild:de});return F!==null?Math.ceil(F):null},G=()=>{if(!p.current||!e.body)return;if(!m){e.documentElement.classList.add("measuring-height");const a=e.body.scrollHeight,u=e.documentElement?.scrollHeight||0,g=x?.scrollHeight||0,fe=Math.max(a,u,g);e.documentElement.classList.remove("measuring-height"),J(j=>{const F=Math.max(200,Math.ceil(fe));return j===F?j:F});return}const o=e.body.scrollHeight,f=e.documentElement?.scrollHeight||0,D=x?.scrollHeight||0,X=Math.max(o,f,D);if(v){const a=Ce(),u=Math.max(200,a??Math.ceil(X));He(g=>g===u?g:u)}J(a=>{const u=Math.max(200,Math.ceil(X));return a===u?a:u})},A=()=>{requestAnimationFrame(()=>{T||G()})};S.current=A,G(),A(),Re&&je().then(o=>{T||(o(e),requestAnimationFrame(()=>{T||A()}))}).catch(()=>{T||A()});const U=new ResizeObserver(()=>G());U.observe(e.body),x&&U.observe(x);const me=new MutationObserver(()=>{A()});return me.observe(e.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["style","class"]}),()=>{T=!0,U.disconnect(),me.disconnect(),l&&(e.removeEventListener("pointerdown",W,!0),e.removeEventListener("mousedown",le,!0),e.removeEventListener("touchstart",ue,!0)),setTimeout(()=>{ae.unmount(),P.current=null,S.current=()=>{}},0)}},[]),t.useEffect(()=>{const n=()=>{Ee(!!document.fullscreenElement)};return document.addEventListener("fullscreenchange",n),()=>document.removeEventListener("fullscreenchange",n)},[]),t.useEffect(()=>{const n=k.current;if(!n)return;const e=new ResizeObserver(l=>{K(l[0]?.contentRect.width??n.clientWidth)});return e.observe(n),K(n.clientWidth),()=>e.disconnect()},[]);const ce=t.useMemo(()=>{if(m||q===0||B)return;const n=Math.round(q*9/16);return{height:Math.max(n,Z)}},[m,q,Z,B]),ve=()=>{const n=k.current||p.current;if(n){if(document.fullscreenElement){document.exitFullscreen().catch(()=>{});return}n.requestFullscreen&&n.requestFullscreen().catch(()=>{})}};t.useEffect(()=>{const n=P.current;if(!n)return;n.render(E.jsxRuntimeExports.jsx(Te.default,{html:_,styleLoadingText:I,scriptLoadingText:R,resetToken:ee,hasRootVhHeight:ie,mode:d,stretchRootHeight:ne})),C.current=window.requestAnimationFrame(()=>{S.current?.(),C.current=null});const e=setTimeout(()=>S.current?.(),100),l=setTimeout(()=>S.current?.(),500);return()=>{clearTimeout(e),clearTimeout(l)}},[_,I,R,ee,d]);const Me=["w-full relative content-render-iframe-sandbox",m?"h-full overflow-auto flex flex-col":ce?"overflow-hidden flex items-center justify-center":"aspect-[16/9] overflow-hidden flex items-center justify-center"].filter(Boolean).join(" ");return E.jsxRuntimeExports.jsxs("div",{ref:k,"data-root-vh":ie?"true":"false",className:Me,style:y?{height:y,minHeight:y}:ce,children:[!N&&E.jsxRuntimeExports.jsx("button",{type:"button",onClick:ve,className:"absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer",children:B?"退出全屏":h||"全屏浏览"}),d==="blackboard"&&s==="markdown"?E.jsxRuntimeExports.jsx("div",{onMouseDown:()=>H("mousedown"),onPointerDown:()=>H("pointerdown"),onTouchStart:()=>H("touchstart"),children:E.jsxRuntimeExports.jsx(Ae.default,{content:c})}):E.jsxRuntimeExports.jsx("iframe",{ref:p,sandbox:"allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox",allow:"fullscreen",allowFullScreen:!0,className:[i,"w-full h-full mx-auto my-auto block"].filter(Boolean).join(" "),style:{height:y??"100%",minHeight:y,margin:"auto"}})]})};exports.default=Ve;
|
|
18
25
|
//# sourceMappingURL=IframeSandbox.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeSandbox.cjs.js","sources":["../../../src/components/ContentRender/IframeSandbox.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport SandboxApp from \"./SandboxApp\";\nimport ContentRender from \"./ContentRender\";\nimport {\n EMPTY_ROOT_HEIGHT_META,\n inspectViewportHeightFromHtmlRootString,\n inspectViewportHeightFromNodeChain,\n parseExplicitHeight,\n resolveExplicitHeightFromNodeChain,\n} from \"./utils/iframe-viewport-height\";\nimport {\n SANDBOX_INTERACTION_MESSAGE_SOURCE,\n SANDBOX_INTERACTION_MESSAGE_TYPE,\n} from \"../../lib/sandboxInteraction\";\n\ntype InjectBlackboardLibraries =\n typeof import(\"./blackboard-vendor\").injectBlackboardLibraries;\n\n// Cache the sandbox vendor loader so every iframe reuses the same preload request.\nlet blackboardVendorPromise: Promise<InjectBlackboardLibraries> | null = null;\n\nconst loadBlackboardVendor = () => {\n if (!blackboardVendorPromise) {\n blackboardVendorPromise = import(\"./blackboard-vendor\").then(\n (m) => m.injectBlackboardLibraries\n );\n }\n\n return blackboardVendorPromise;\n};\n\nconst COMPLETE_IMAGE_TAG_PATTERN = /<img\\b[^>]*>/i;\nconst POST_IMAGE_STREAM_DEBOUNCE_MS = 180;\nconst SANDBOX_INTERACTION_THROTTLE_MS = 240;\n\nexport interface IframeSandboxProps {\n content: string;\n className?: string;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n hideFullScreen?: boolean;\n mode?: \"content\" | \"blackboard\";\n type: \"sandbox\" | \"markdown\";\n replaceRootScreenHeightWithFull?: boolean;\n}\n\nconst replaceRootScreenHeightToken = (className: string) =>\n className\n .split(/\\s+/)\n .filter(Boolean)\n .map((token) => {\n const segments = token.split(\":\");\n if (\n segments[segments.length - 1] !== \"h-screen\" &&\n segments[segments.length - 1] !== \"min-h-screen\"\n ) {\n return token;\n }\n segments[segments.length - 1] = \"h-full\";\n return segments.join(\":\");\n })\n .join(\" \");\n\nconst replaceRootScreenHeightWithFullClass = (\n html: string,\n enabled: boolean\n) => {\n if (!enabled || !html.trim()) {\n return html;\n }\n\n return html.replace(\n /^(\\s*<[a-zA-Z][\\w:-]*)(\\s[^>]*?)?>/,\n (match, tagStart: string, attrs = \"\") => {\n const classMatch = attrs.match(/\\bclass\\s*=\\s*([\"'])([^\"']*)\\1/i);\n\n if (!classMatch) {\n return match;\n }\n\n const nextClassName = replaceRootScreenHeightToken(classMatch[2]);\n\n if (nextClassName === classMatch[2]) {\n return match;\n }\n\n return `${tagStart}${attrs.replace(\n classMatch[0],\n `class=${classMatch[1]}${nextClassName}${classMatch[1]}`\n )}>`;\n }\n );\n};\n\nconst IframeSandbox: React.FC<IframeSandboxProps> = ({\n content,\n type,\n className,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n replaceRootScreenHeightWithFull = false,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const rootRef = useRef<Root | null>(null);\n const updateHeightRef = useRef<() => void>(() => {});\n const [height, setHeight] = useState(480);\n const [contentHeight, setContentHeight] = useState(0);\n const [containerWidth, setContainerWidth] = useState(0);\n const lastSandboxInteractionTimeRef = useRef(0);\n const [resetToken, setResetToken] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const shouldInjectSandboxVendor = type === \"sandbox\";\n\n const isBlackboardMode = mode === \"blackboard\";\n const shouldMeasureDynamicHeight = isBlackboardMode && type === \"sandbox\";\n const shouldProcessRootScreenHeight =\n shouldMeasureDynamicHeight && replaceRootScreenHeightWithFull;\n const prevHtmlRef = useRef<string>(\"\");\n const htmlContent = React.useMemo(\n () => (type === \"sandbox\" ? content : \"\"),\n [content, type]\n );\n const normalizedHtmlContent = React.useMemo(\n () =>\n replaceRootScreenHeightWithFullClass(\n htmlContent,\n shouldProcessRootScreenHeight\n ),\n [htmlContent, shouldProcessRootScreenHeight]\n );\n const originalRootHeightMeta = React.useMemo(\n () =>\n shouldProcessRootScreenHeight\n ? inspectViewportHeightFromHtmlRootString(htmlContent)\n : EMPTY_ROOT_HEIGHT_META,\n [htmlContent, shouldProcessRootScreenHeight]\n );\n const shouldStretchRootHeight = React.useMemo(\n () =>\n shouldProcessRootScreenHeight &&\n originalRootHeightMeta.hasFullViewportHeight,\n [\n originalRootHeightMeta.hasFullViewportHeight,\n shouldProcessRootScreenHeight,\n ]\n );\n const [renderHtmlContent, setRenderHtmlContent] = useState(\n normalizedHtmlContent\n );\n const prevIncomingHtmlRef = useRef(normalizedHtmlContent);\n const pendingHtmlRef = useRef(normalizedHtmlContent);\n const deferRenderTimerRef = useRef<number | null>(null);\n const initialPaintFrameRef = useRef<number | null>(null);\n const renderViewportHeightCssRef = useRef<string | null>(null);\n\n const emitSandboxInteraction = useCallback((eventType: string) => {\n if (typeof window === \"undefined\") {\n return;\n }\n const now = Date.now();\n if (\n now - lastSandboxInteractionTimeRef.current <\n SANDBOX_INTERACTION_THROTTLE_MS\n ) {\n return;\n }\n lastSandboxInteractionTimeRef.current = now;\n window.postMessage(\n {\n source: SANDBOX_INTERACTION_MESSAGE_SOURCE,\n type: SANDBOX_INTERACTION_MESSAGE_TYPE,\n eventType,\n },\n window.location.origin\n );\n }, []);\n\n const clearDeferredRenderTimer = () => {\n if (deferRenderTimerRef.current === null) return;\n window.clearTimeout(deferRenderTimerRef.current);\n deferRenderTimerRef.current = null;\n };\n\n const clearInitialPaintFrames = () => {\n if (initialPaintFrameRef.current !== null) {\n window.cancelAnimationFrame(initialPaintFrameRef.current);\n initialPaintFrameRef.current = null;\n }\n };\n\n useEffect(\n () => () => {\n clearDeferredRenderTimer();\n clearInitialPaintFrames();\n },\n []\n );\n\n useEffect(() => {\n const prevIncomingHtml = prevIncomingHtmlRef.current;\n prevIncomingHtmlRef.current = normalizedHtmlContent;\n\n const isAppendOnlyStream =\n !!prevIncomingHtml &&\n normalizedHtmlContent.length > prevIncomingHtml.length &&\n normalizedHtmlContent.startsWith(prevIncomingHtml);\n const containsCompleteImage = COMPLETE_IMAGE_TAG_PATTERN.test(\n normalizedHtmlContent\n );\n const shouldDeferRender = isAppendOnlyStream && containsCompleteImage;\n\n if (!shouldDeferRender) {\n clearDeferredRenderTimer();\n pendingHtmlRef.current = normalizedHtmlContent;\n setRenderHtmlContent(normalizedHtmlContent);\n return;\n }\n\n pendingHtmlRef.current = normalizedHtmlContent;\n clearDeferredRenderTimer();\n deferRenderTimerRef.current = window.setTimeout(() => {\n setRenderHtmlContent(pendingHtmlRef.current);\n deferRenderTimerRef.current = null;\n }, POST_IMAGE_STREAM_DEBOUNCE_MS);\n }, [normalizedHtmlContent]);\n\n const rootViewportHeightCss = React.useMemo(() => {\n if (!shouldMeasureDynamicHeight) {\n return null;\n }\n\n return inspectViewportHeightFromHtmlRootString(renderHtmlContent)\n .viewportHeightCss;\n }, [renderHtmlContent, shouldMeasureDynamicHeight]);\n\n useEffect(() => {\n renderViewportHeightCssRef.current = rootViewportHeightCss;\n }, [rootViewportHeightCss]);\n\n const hasRootVhHeight = Boolean(rootViewportHeightCss);\n const sandboxViewportHeight =\n isBlackboardMode && type === \"sandbox\"\n ? shouldStretchRootHeight\n ? \"100%\"\n : (rootViewportHeightCss ?? `${height}px`)\n : undefined;\n useEffect(() => {\n if (mode !== \"blackboard\") {\n prevHtmlRef.current = normalizedHtmlContent;\n return;\n }\n const prev = prevHtmlRef.current;\n const isContinuation = prev && normalizedHtmlContent.startsWith(prev);\n if (!isContinuation && prev) {\n setResetToken((token) => token + 1);\n }\n prevHtmlRef.current = normalizedHtmlContent;\n }, [mode, normalizedHtmlContent]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return undefined;\n\n const doc = iframe.contentDocument;\n if (!doc) return undefined;\n\n doc.open();\n doc.write(`<!DOCTYPE html>\n<html${mode === \"blackboard\" ? ' style=\"height: 100%;\"' : \"\"}>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <style>\n :root { color-scheme: light; }\n html, body, #root { width: 100%; }\n ${mode === \"blackboard\" ? \"html, body, #root { height: 100%; }\" : \"\"}\n html, body { margin: 0; padding: 0; overflow: auto; }\n *, *::before, *::after { box-sizing: border-box; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n </body>\n</html>`);\n doc.close();\n\n // Force iframe theme to stay in light mode regardless of host OS preference.\n doc.documentElement.setAttribute(\"data-theme\", \"light\");\n doc.documentElement.style.colorScheme = \"light\";\n doc.body?.style.setProperty(\"color-scheme\", \"light\");\n\n const shouldBridgeSandboxInteraction =\n isBlackboardMode && type === \"sandbox\";\n const handleSandboxPointerDown = () =>\n emitSandboxInteraction(\"pointerdown\");\n const handleSandboxMouseDown = () => emitSandboxInteraction(\"mousedown\");\n const handleSandboxTouchStart = () => emitSandboxInteraction(\"touchstart\");\n\n if (shouldBridgeSandboxInteraction) {\n doc.addEventListener(\"pointerdown\", handleSandboxPointerDown, true);\n doc.addEventListener(\"mousedown\", handleSandboxMouseDown, true);\n doc.addEventListener(\"touchstart\", handleSandboxTouchStart, true);\n }\n\n const rootEl = doc.getElementById(\"root\");\n if (!rootEl) return undefined;\n\n const root = createRoot(rootEl);\n rootRef.current = root;\n let isDestroyed = false;\n const getHeightInspectionNode = (node: HTMLElement) => ({\n heightAttrValue: node.getAttribute(\"height\"),\n styleAttrValue: node.getAttribute(\"style\"),\n classAttrValue: node.getAttribute(\"class\"),\n });\n const getSingleChildElement = (node: HTMLElement) => {\n const childElements = Array.from(node.children) as HTMLElement[];\n\n return childElements.length === 1 ? childElements[0] : null;\n };\n\n const resolveExplicitHeight = () => {\n if (!shouldMeasureDynamicHeight) return null;\n if (!iframeRef.current || !doc.body) return null;\n const parentViewportHeight =\n iframeRef.current.ownerDocument?.documentElement?.clientHeight ||\n window.innerHeight;\n // Reuse parsed height metadata from the current html snapshot first to\n // avoid re-inspecting the same DOM chain on every height tick.\n const precomputedViewportHeightCss = renderViewportHeightCssRef.current;\n const parsed = precomputedViewportHeightCss\n ? parseExplicitHeight(\n precomputedViewportHeightCss,\n parentViewportHeight\n )\n : null;\n\n if (parsed !== null) {\n return Math.ceil(parsed);\n }\n\n const wrapper = doc.body.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const container = wrapper?.firstElementChild as HTMLElement | null;\n if (!container) return null;\n const containerChildren = Array.from(container.children) as HTMLElement[];\n const rootContentElement =\n containerChildren.length === 1 ? containerChildren[0] : null;\n const runtimeHeightMeta = inspectViewportHeightFromNodeChain(\n rootContentElement,\n {\n getNode: getHeightInspectionNode,\n getSingleChild: getSingleChildElement,\n }\n );\n const runtimeViewportHeightCss = runtimeHeightMeta.viewportHeightCss;\n\n if (runtimeViewportHeightCss) {\n const runtimeViewportHeight = parseExplicitHeight(\n runtimeViewportHeightCss,\n parentViewportHeight\n );\n\n if (runtimeViewportHeight !== null) {\n return Math.ceil(runtimeViewportHeight);\n }\n }\n\n const explicitPixelHeight = resolveExplicitHeightFromNodeChain(\n rootContentElement,\n parentViewportHeight,\n {\n getNode: getHeightInspectionNode,\n getSingleChild: getSingleChildElement,\n }\n );\n\n return explicitPixelHeight !== null\n ? Math.ceil(explicitPixelHeight)\n : null;\n };\n\n const updateHeight = () => {\n if (!iframeRef.current || !doc.body) return;\n\n if (!isBlackboardMode) {\n // Content mode: neutralize percentage/vh heights on the wrapper\n // chain before measuring so that elements with height:100% don't\n // inflate scrollHeight, while preserving vh-based content layout\n // at a stable reference size (the 16:9 minimum).\n const wrapper = doc.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const prevWrapperH = wrapper?.style.height ?? \"\";\n const prevBodyH = doc.body.style.height;\n const prevHtmlH = doc.documentElement.style.height;\n\n if (wrapper) wrapper.style.height = \"auto\";\n doc.body.style.height = \"auto\";\n doc.documentElement.style.height = \"auto\";\n\n const bodyScrollH = doc.body.scrollHeight;\n const htmlScrollH = doc.documentElement?.scrollHeight || 0;\n const rootScrollH = rootEl?.scrollHeight || 0;\n const measuredHeight = Math.max(bodyScrollH, htmlScrollH, rootScrollH);\n\n // Restore immediately (synchronous, no paint in between)\n if (wrapper) wrapper.style.height = prevWrapperH;\n doc.body.style.height = prevBodyH;\n doc.documentElement.style.height = prevHtmlH;\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredHeight));\n return prev === next ? prev : next;\n });\n return;\n }\n\n // Blackboard mode: use existing explicit height resolution logic\n const bodyScrollH = doc.body.scrollHeight;\n const htmlScrollH = doc.documentElement?.scrollHeight || 0;\n const rootScrollH = rootEl?.scrollHeight || 0;\n const measuredHeight = Math.max(bodyScrollH, htmlScrollH, rootScrollH);\n\n if (shouldMeasureDynamicHeight) {\n const explicitHeight = resolveExplicitHeight();\n const nextHeight = Math.max(\n 200,\n explicitHeight ?? Math.ceil(measuredHeight)\n );\n setHeight((prevHeight) =>\n prevHeight === nextHeight ? prevHeight : nextHeight\n );\n }\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredHeight));\n return prev === next ? prev : next;\n });\n };\n const scheduleHeightUpdate = () => {\n requestAnimationFrame(() => {\n if (isDestroyed) return;\n updateHeight();\n });\n };\n updateHeightRef.current = scheduleHeightUpdate;\n\n updateHeight();\n scheduleHeightUpdate();\n\n if (shouldInjectSandboxVendor) {\n // Inject Tailwind/DaisyUI/GSAP before rendering sandbox content to avoid FOUC.\n loadBlackboardVendor()\n .then((inject) => {\n if (isDestroyed) return;\n inject(doc);\n requestAnimationFrame(() => {\n if (isDestroyed) return;\n scheduleHeightUpdate();\n });\n })\n .catch(() => {\n if (isDestroyed) return;\n scheduleHeightUpdate();\n });\n }\n\n const resizeObserver = new ResizeObserver(() => updateHeight());\n resizeObserver.observe(doc.body);\n if (rootEl) {\n resizeObserver.observe(rootEl);\n }\n\n // MutationObserver: detect DOM changes that ResizeObserver might miss\n // (e.g. content injected by scripts, images loading, dynamic rendering)\n const mutationObserver = new MutationObserver(() => {\n scheduleHeightUpdate();\n });\n mutationObserver.observe(doc.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"style\", \"class\"],\n });\n\n return () => {\n isDestroyed = true;\n resizeObserver.disconnect();\n mutationObserver.disconnect();\n if (shouldBridgeSandboxInteraction) {\n doc.removeEventListener(\"pointerdown\", handleSandboxPointerDown, true);\n doc.removeEventListener(\"mousedown\", handleSandboxMouseDown, true);\n doc.removeEventListener(\"touchstart\", handleSandboxTouchStart, true);\n }\n // Defer unmount to avoid React warning when parent is mid-render\n setTimeout(() => {\n root.unmount();\n rootRef.current = null;\n updateHeightRef.current = () => {};\n }, 0);\n };\n }, []);\n\n useEffect(() => {\n const onFullscreenChange = () => {\n setIsFullscreen(Boolean(document.fullscreenElement));\n };\n document.addEventListener(\"fullscreenchange\", onFullscreenChange);\n return () =>\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange);\n }, []);\n\n // Track container width for computing min-height in content mode\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const ro = new ResizeObserver((entries) => {\n setContainerWidth(entries[0]?.contentRect.width ?? el.clientWidth);\n });\n ro.observe(el);\n setContainerWidth(el.clientWidth);\n return () => ro.disconnect();\n }, []);\n\n // Content mode: min 16:9 aspect ratio, grow to fit content (no scrollbar)\n const contentModeStyle = useMemo<React.CSSProperties | undefined>(() => {\n if (isBlackboardMode || containerWidth === 0 || isFullscreen)\n return undefined;\n const minH = Math.round((containerWidth * 9) / 16);\n const h = Math.max(minH, contentHeight);\n return { height: h };\n }, [isBlackboardMode, containerWidth, contentHeight, isFullscreen]);\n\n const toggleFullscreen = () => {\n const target = containerRef.current || iframeRef.current;\n if (!target) return;\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n return;\n }\n if (target.requestFullscreen) {\n target.requestFullscreen().catch(() => {});\n }\n };\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n root.render(\n <SandboxApp\n html={renderHtmlContent}\n styleLoadingText={styleLoadingText}\n scriptLoadingText={scriptLoadingText}\n resetToken={resetToken}\n hasRootVhHeight={hasRootVhHeight}\n mode={mode}\n stretchRootHeight={shouldStretchRootHeight}\n />\n );\n\n // Schedule multiple measurements to catch async content (scripts, images, styles).\n initialPaintFrameRef.current = window.requestAnimationFrame(() => {\n updateHeightRef.current?.();\n initialPaintFrameRef.current = null;\n });\n const t1 = setTimeout(() => updateHeightRef.current?.(), 100);\n const t2 = setTimeout(() => updateHeightRef.current?.(), 500);\n return () => {\n clearTimeout(t1);\n clearTimeout(t2);\n };\n }, [\n renderHtmlContent,\n styleLoadingText,\n scriptLoadingText,\n resetToken,\n mode,\n ]);\n const containerClassName = [\n \"w-full relative content-render-iframe-sandbox\",\n isBlackboardMode\n ? \"h-full overflow-auto flex flex-col\"\n : contentModeStyle\n ? \"overflow-hidden flex items-center justify-center\"\n : \"aspect-[16/9] overflow-hidden flex items-center justify-center\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n ref={containerRef}\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className={containerClassName}\n style={\n sandboxViewportHeight\n ? {\n height: sandboxViewportHeight,\n minHeight: sandboxViewportHeight,\n }\n : contentModeStyle\n }\n >\n {!hideFullScreen && (\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className={\n \"absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer\"\n }\n >\n {isFullscreen ? \"退出全屏\" : fullScreenButtonText || \"全屏浏览\"}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <div\n onMouseDown={() => emitSandboxInteraction(\"mousedown\")}\n onPointerDown={() => emitSandboxInteraction(\"pointerdown\")}\n onTouchStart={() => emitSandboxInteraction(\"touchstart\")}\n >\n <ContentRender content={content} />\n </div>\n ) : (\n <iframe\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n allow=\"fullscreen\"\n allowFullScreen\n className={[className, \"w-full h-full mx-auto my-auto block\"]\n .filter(Boolean)\n .join(\" \")}\n style={{\n height: sandboxViewportHeight ?? \"100%\",\n minHeight: sandboxViewportHeight,\n margin: \"auto\",\n }}\n />\n )}\n </div>\n );\n};\n\nexport default IframeSandbox;\n"],"names":["blackboardVendorPromise","loadBlackboardVendor","m","COMPLETE_IMAGE_TAG_PATTERN","POST_IMAGE_STREAM_DEBOUNCE_MS","SANDBOX_INTERACTION_THROTTLE_MS","replaceRootScreenHeightToken","className","token","segments","replaceRootScreenHeightWithFullClass","html","enabled","match","tagStart","attrs","classMatch","nextClassName","IframeSandbox","content","type","styleLoadingText","scriptLoadingText","fullScreenButtonText","hideFullScreen","mode","replaceRootScreenHeightWithFull","containerRef","useRef","iframeRef","rootRef","updateHeightRef","height","setHeight","useState","contentHeight","setContentHeight","containerWidth","setContainerWidth","lastSandboxInteractionTimeRef","resetToken","setResetToken","isFullscreen","setIsFullscreen","shouldInjectSandboxVendor","isBlackboardMode","shouldMeasureDynamicHeight","shouldProcessRootScreenHeight","prevHtmlRef","htmlContent","React","normalizedHtmlContent","originalRootHeightMeta","inspectViewportHeightFromHtmlRootString","EMPTY_ROOT_HEIGHT_META","shouldStretchRootHeight","renderHtmlContent","setRenderHtmlContent","prevIncomingHtmlRef","pendingHtmlRef","deferRenderTimerRef","initialPaintFrameRef","renderViewportHeightCssRef","emitSandboxInteraction","useCallback","eventType","now","SANDBOX_INTERACTION_MESSAGE_SOURCE","SANDBOX_INTERACTION_MESSAGE_TYPE","clearDeferredRenderTimer","clearInitialPaintFrames","useEffect","prevIncomingHtml","isAppendOnlyStream","containsCompleteImage","rootViewportHeightCss","hasRootVhHeight","sandboxViewportHeight","prev","iframe","doc","shouldBridgeSandboxInteraction","handleSandboxPointerDown","handleSandboxMouseDown","handleSandboxTouchStart","rootEl","root","createRoot","isDestroyed","getHeightInspectionNode","node","getSingleChildElement","childElements","resolveExplicitHeight","parentViewportHeight","precomputedViewportHeightCss","parsed","parseExplicitHeight","container","containerChildren","rootContentElement","runtimeViewportHeightCss","inspectViewportHeightFromNodeChain","runtimeViewportHeight","explicitPixelHeight","resolveExplicitHeightFromNodeChain","updateHeight","wrapper","prevWrapperH","prevBodyH","prevHtmlH","bodyScrollH","htmlScrollH","rootScrollH","measuredHeight","next","explicitHeight","nextHeight","prevHeight","scheduleHeightUpdate","inject","resizeObserver","mutationObserver","onFullscreenChange","el","ro","entries","contentModeStyle","useMemo","minH","toggleFullscreen","target","jsx","SandboxApp","t1","t2","containerClassName","jsxs","ContentRender"],"mappings":"+XA0BA,IAAIA,EAAqE,KAEzE,MAAMC,GAAuB,KACtBD,IACHA,EAA0B,QAAA,QAAA,EAAA,KAAA,IAAA,QAAO,4BAAqB,CAAA,EAAE,KACrDE,GAAMA,EAAE,yBAAA,GAINF,GAGHG,GAA6B,gBAC7BC,GAAgC,IAChCC,GAAkC,IAelCC,GAAgCC,GACpCA,EACG,MAAM,KAAK,EACX,OAAO,OAAO,EACd,IAAKC,GAAU,CACd,MAAMC,EAAWD,EAAM,MAAM,GAAG,EAChC,OACEC,EAASA,EAAS,OAAS,CAAC,IAAM,YAClCA,EAASA,EAAS,OAAS,CAAC,IAAM,eAE3BD,GAETC,EAASA,EAAS,OAAS,CAAC,EAAI,SACzBA,EAAS,KAAK,GAAG,EAC1B,CAAC,EACA,KAAK,GAAG,EAEPC,GAAuC,CAC3CC,EACAC,IAEI,CAACA,GAAW,CAACD,EAAK,OACbA,EAGFA,EAAK,QACV,qCACA,CAACE,EAAOC,EAAkBC,EAAQ,KAAO,CACvC,MAAMC,EAAaD,EAAM,MAAM,iCAAiC,EAEhE,GAAI,CAACC,EACH,OAAOH,EAGT,MAAMI,EAAgBX,GAA6BU,EAAW,CAAC,CAAC,EAEhE,OAAIC,IAAkBD,EAAW,CAAC,EACzBH,EAGF,GAAGC,CAAQ,GAAGC,EAAM,QACzBC,EAAW,CAAC,EACZ,SAASA,EAAW,CAAC,CAAC,GAAGC,CAAa,GAAGD,EAAW,CAAC,CAAC,EAAA,CACvD,GACH,CAAA,EAIEE,GAA8C,CAAC,CACnD,QAAAC,EACA,KAAAC,EACA,UAAAb,EACA,iBAAAc,EACA,kBAAAC,EACA,qBAAAC,EACA,eAAAC,EAAiB,GACjB,KAAAC,EAAO,UACP,gCAAAC,GAAkC,EACpC,IAAM,CACJ,MAAMC,EAAeC,EAAAA,OAAuB,IAAI,EAC1CC,EAAYD,EAAAA,OAA0B,IAAI,EAC1CE,EAAUF,EAAAA,OAAoB,IAAI,EAClCG,EAAkBH,EAAAA,OAAmB,IAAM,CAAC,CAAC,EAC7C,CAACI,GAAQC,EAAS,EAAIC,EAAAA,SAAS,GAAG,EAClC,CAACC,EAAeC,CAAgB,EAAIF,EAAAA,SAAS,CAAC,EAC9C,CAACG,EAAgBC,CAAiB,EAAIJ,EAAAA,SAAS,CAAC,EAChDK,GAAgCX,EAAAA,OAAO,CAAC,EACxC,CAACY,GAAYC,EAAa,EAAIP,EAAAA,SAAS,CAAC,EACxC,CAACQ,EAAcC,EAAe,EAAIT,EAAAA,SAAS,EAAK,EAChDU,GAA4BxB,IAAS,UAErCyB,EAAmBpB,IAAS,aAC5BqB,EAA6BD,GAAoBzB,IAAS,UAC1D2B,EACJD,GAA8BpB,GAC1BsB,EAAcpB,EAAAA,OAAe,EAAE,EAC/BqB,EAAcC,EAAM,QACxB,IAAO9B,IAAS,UAAYD,EAAU,GACtC,CAACA,EAASC,CAAI,CAAA,EAEV+B,EAAwBD,EAAM,QAClC,IACExC,GACEuC,EACAF,CAAA,EAEJ,CAACE,EAAaF,CAA6B,CAAA,EAEvCK,GAAyBF,EAAM,QACnC,IACEH,EACIM,EAAAA,wCAAwCJ,CAAW,EACnDK,EAAAA,uBACN,CAACL,EAAaF,CAA6B,CAAA,EAEvCQ,GAA0BL,EAAM,QACpC,IACEH,GACAK,GAAuB,sBACzB,CACEA,GAAuB,sBACvBL,CAAA,CACF,EAEI,CAACS,EAAmBC,EAAoB,EAAIvB,EAAAA,SAChDiB,CAAA,EAEIO,GAAsB9B,EAAAA,OAAOuB,CAAqB,EAClDQ,EAAiB/B,EAAAA,OAAOuB,CAAqB,EAC7CS,EAAsBhC,EAAAA,OAAsB,IAAI,EAChDiC,EAAuBjC,EAAAA,OAAsB,IAAI,EACjDkC,GAA6BlC,EAAAA,OAAsB,IAAI,EAEvDmC,EAAyBC,cAAaC,GAAsB,CAChE,GAAI,OAAO,OAAW,IACpB,OAEF,MAAMC,EAAM,KAAK,IAAA,EAEfA,EAAM3B,GAA8B,QACpClC,KAIFkC,GAA8B,QAAU2B,EACxC,OAAO,YACL,CACE,OAAQC,GAAAA,mCACR,KAAMC,GAAAA,iCACN,UAAAH,CAAA,EAEF,OAAO,SAAS,MAAA,EAEpB,EAAG,CAAA,CAAE,EAECI,EAA2B,IAAM,CACjCT,EAAoB,UAAY,OACpC,OAAO,aAAaA,EAAoB,OAAO,EAC/CA,EAAoB,QAAU,KAChC,EAEMU,GAA0B,IAAM,CAChCT,EAAqB,UAAY,OACnC,OAAO,qBAAqBA,EAAqB,OAAO,EACxDA,EAAqB,QAAU,KAEnC,EAEAU,EAAAA,UACE,IAAM,IAAM,CACVF,EAAA,EACAC,GAAA,CACF,EACA,CAAA,CAAC,EAGHC,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAmBd,GAAoB,QAC7CA,GAAoB,QAAUP,EAE9B,MAAMsB,EACJ,CAAC,CAACD,GACFrB,EAAsB,OAASqB,EAAiB,QAChDrB,EAAsB,WAAWqB,CAAgB,EAC7CE,EAAwBvE,GAA2B,KACvDgD,CAAA,EAIF,GAAI,EAFsBsB,GAAsBC,GAExB,CACtBL,EAAA,EACAV,EAAe,QAAUR,EACzBM,GAAqBN,CAAqB,EAC1C,MACF,CAEAQ,EAAe,QAAUR,EACzBkB,EAAA,EACAT,EAAoB,QAAU,OAAO,WAAW,IAAM,CACpDH,GAAqBE,EAAe,OAAO,EAC3CC,EAAoB,QAAU,IAChC,EAAGxD,EAA6B,CAClC,EAAG,CAAC+C,CAAqB,CAAC,EAE1B,MAAMwB,EAAwBzB,EAAM,QAAQ,IACrCJ,EAIEO,EAAAA,wCAAwCG,CAAiB,EAC7D,kBAJM,KAKR,CAACA,EAAmBV,CAA0B,CAAC,EAElDyB,EAAAA,UAAU,IAAM,CACdT,GAA2B,QAAUa,CACvC,EAAG,CAACA,CAAqB,CAAC,EAE1B,MAAMC,GAAkB,EAAQD,EAC1BE,EACJhC,GAAoBzB,IAAS,UACzBmC,GACE,OACCoB,GAAyB,GAAG3C,EAAM,KACrC,OACNuC,EAAAA,UAAU,IAAM,CACd,GAAI9C,IAAS,aAAc,CACzBuB,EAAY,QAAUG,EACtB,MACF,CACA,MAAM2B,EAAO9B,EAAY,QAErB,EADmB8B,GAAQ3B,EAAsB,WAAW2B,CAAI,IAC7CA,GACrBrC,GAAejC,GAAUA,EAAQ,CAAC,EAEpCwC,EAAY,QAAUG,CACxB,EAAG,CAAC1B,EAAM0B,CAAqB,CAAC,EAEhCoB,EAAAA,UAAU,IAAM,CACd,MAAMQ,EAASlD,EAAU,QACzB,GAAI,CAACkD,EAAQ,OAEb,MAAMC,EAAMD,EAAO,gBACnB,GAAI,CAACC,EAAK,OAEVA,EAAI,KAAA,EACJA,EAAI,MAAM;AAAA,OACPvD,IAAS,aAAe,yBAA2B,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOpDA,IAAS,aAAe,sCAAwC,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQlE,EACJuD,EAAI,MAAA,EAGJA,EAAI,gBAAgB,aAAa,aAAc,OAAO,EACtDA,EAAI,gBAAgB,MAAM,YAAc,QACxCA,EAAI,MAAM,MAAM,YAAY,eAAgB,OAAO,EAEnD,MAAMC,EACJpC,GAAoBzB,IAAS,UACzB8D,EAA2B,IAC/BnB,EAAuB,aAAa,EAChCoB,GAAyB,IAAMpB,EAAuB,WAAW,EACjEqB,GAA0B,IAAMrB,EAAuB,YAAY,EAErEkB,IACFD,EAAI,iBAAiB,cAAeE,EAA0B,EAAI,EAClEF,EAAI,iBAAiB,YAAaG,GAAwB,EAAI,EAC9DH,EAAI,iBAAiB,aAAcI,GAAyB,EAAI,GAGlE,MAAMC,EAASL,EAAI,eAAe,MAAM,EACxC,GAAI,CAACK,EAAQ,OAEb,MAAMC,GAAOC,GAAAA,WAAWF,CAAM,EAC9BvD,EAAQ,QAAUwD,GAClB,IAAIE,EAAc,GAClB,MAAMC,GAA2BC,IAAuB,CACtD,gBAAiBA,EAAK,aAAa,QAAQ,EAC3C,eAAgBA,EAAK,aAAa,OAAO,EACzC,eAAgBA,EAAK,aAAa,OAAO,CAAA,GAErCC,GAAyBD,GAAsB,CACnD,MAAME,EAAgB,MAAM,KAAKF,EAAK,QAAQ,EAE9C,OAAOE,EAAc,SAAW,EAAIA,EAAc,CAAC,EAAI,IACzD,EAEMC,GAAwB,IAAM,CAElC,GADI,CAAC/C,GACD,CAACjB,EAAU,SAAW,CAACmD,EAAI,KAAM,OAAO,KAC5C,MAAMc,EACJjE,EAAU,QAAQ,eAAe,iBAAiB,cAClD,OAAO,YAGHkE,EAA+BjC,GAA2B,QAC1DkC,EAASD,EACXE,EAAAA,oBACEF,EACAD,CAAA,EAEF,KAEJ,GAAIE,IAAW,KACb,OAAO,KAAK,KAAKA,CAAM,EAMzB,MAAME,EAHUlB,EAAI,KAAK,cACvB,kBAAA,GAEyB,kBAC3B,GAAI,CAACkB,EAAW,OAAO,KACvB,MAAMC,EAAoB,MAAM,KAAKD,EAAU,QAAQ,EACjDE,EACJD,EAAkB,SAAW,EAAIA,EAAkB,CAAC,EAAI,KAQpDE,EAPoBC,EAAAA,mCACxBF,EACA,CACE,QAASX,GACT,eAAgBE,EAAA,CAClB,EAEiD,kBAEnD,GAAIU,EAA0B,CAC5B,MAAME,EAAwBN,EAAAA,oBAC5BI,EACAP,CAAA,EAGF,GAAIS,IAA0B,KAC5B,OAAO,KAAK,KAAKA,CAAqB,CAE1C,CAEA,MAAMC,EAAsBC,EAAAA,mCAC1BL,EACAN,EACA,CACE,QAASL,GACT,eAAgBE,EAAA,CAClB,EAGF,OAAOa,IAAwB,KAC3B,KAAK,KAAKA,CAAmB,EAC7B,IACN,EAEME,EAAe,IAAM,CACzB,GAAI,CAAC7E,EAAU,SAAW,CAACmD,EAAI,KAAM,OAErC,GAAI,CAACnC,EAAkB,CAKrB,MAAM8D,EAAU3B,EAAI,cAClB,kBAAA,EAEI4B,EAAeD,GAAS,MAAM,QAAU,GACxCE,EAAY7B,EAAI,KAAK,MAAM,OAC3B8B,GAAY9B,EAAI,gBAAgB,MAAM,OAExC2B,IAASA,EAAQ,MAAM,OAAS,QACpC3B,EAAI,KAAK,MAAM,OAAS,OACxBA,EAAI,gBAAgB,MAAM,OAAS,OAEnC,MAAM+B,EAAc/B,EAAI,KAAK,aACvBgC,EAAchC,EAAI,iBAAiB,cAAgB,EACnDiC,EAAc5B,GAAQ,cAAgB,EACtC6B,GAAiB,KAAK,IAAIH,EAAaC,EAAaC,CAAW,EAGjEN,IAASA,EAAQ,MAAM,OAASC,GACpC5B,EAAI,KAAK,MAAM,OAAS6B,EACxB7B,EAAI,gBAAgB,MAAM,OAAS8B,GAEnC1E,EAAkB0C,IAAS,CACzB,MAAMqC,GAAO,KAAK,IAAI,IAAK,KAAK,KAAKD,EAAc,CAAC,EACpD,OAAOpC,KAASqC,GAAOrC,GAAOqC,EAChC,CAAC,EACD,MACF,CAGA,MAAMJ,EAAc/B,EAAI,KAAK,aACvBgC,EAAchC,EAAI,iBAAiB,cAAgB,EACnDiC,EAAc5B,GAAQ,cAAgB,EACtC6B,EAAiB,KAAK,IAAIH,EAAaC,EAAaC,CAAW,EAErE,GAAInE,EAA4B,CAC9B,MAAMsE,EAAiBvB,GAAA,EACjBwB,EAAa,KAAK,IACtB,IACAD,GAAkB,KAAK,KAAKF,CAAc,CAAA,EAE5CjF,GAAWqF,GACTA,IAAeD,EAAaC,EAAaD,CAAA,CAE7C,CAEAjF,EAAkB0C,GAAS,CACzB,MAAMqC,EAAO,KAAK,IAAI,IAAK,KAAK,KAAKD,CAAc,CAAC,EACpD,OAAOpC,IAASqC,EAAOrC,EAAOqC,CAChC,CAAC,CACH,EACMI,EAAuB,IAAM,CACjC,sBAAsB,IAAM,CACtB/B,GACJkB,EAAA,CACF,CAAC,CACH,EACA3E,EAAgB,QAAUwF,EAE1Bb,EAAA,EACAa,EAAA,EAEI3E,IAEF3C,GAAA,EACG,KAAMuH,GAAW,CACZhC,IACJgC,EAAOxC,CAAG,EACV,sBAAsB,IAAM,CACtBQ,GACJ+B,EAAA,CACF,CAAC,EACH,CAAC,EACA,MAAM,IAAM,CACP/B,GACJ+B,EAAA,CACF,CAAC,EAGL,MAAME,EAAiB,IAAI,eAAe,IAAMf,GAAc,EAC9De,EAAe,QAAQzC,EAAI,IAAI,EAC3BK,GACFoC,EAAe,QAAQpC,CAAM,EAK/B,MAAMqC,GAAmB,IAAI,iBAAiB,IAAM,CAClDH,EAAA,CACF,CAAC,EACD,OAAAG,GAAiB,QAAQ1C,EAAI,KAAM,CACjC,UAAW,GACX,QAAS,GACT,WAAY,GACZ,gBAAiB,CAAC,QAAS,OAAO,CAAA,CACnC,EAEM,IAAM,CACXQ,EAAc,GACdiC,EAAe,WAAA,EACfC,GAAiB,WAAA,EACbzC,IACFD,EAAI,oBAAoB,cAAeE,EAA0B,EAAI,EACrEF,EAAI,oBAAoB,YAAaG,GAAwB,EAAI,EACjEH,EAAI,oBAAoB,aAAcI,GAAyB,EAAI,GAGrE,WAAW,IAAM,CACfE,GAAK,QAAA,EACLxD,EAAQ,QAAU,KAClBC,EAAgB,QAAU,IAAM,CAAC,CACnC,EAAG,CAAC,CACN,CACF,EAAG,CAAA,CAAE,EAELwC,EAAAA,UAAU,IAAM,CACd,MAAMoD,EAAqB,IAAM,CAC/BhF,GAAgB,EAAQ,SAAS,iBAAkB,CACrD,EACA,gBAAS,iBAAiB,mBAAoBgF,CAAkB,EACzD,IACL,SAAS,oBAAoB,mBAAoBA,CAAkB,CACvE,EAAG,CAAA,CAAE,EAGLpD,EAAAA,UAAU,IAAM,CACd,MAAMqD,EAAKjG,EAAa,QACxB,GAAI,CAACiG,EAAI,OACT,MAAMC,EAAK,IAAI,eAAgBC,GAAY,CACzCxF,EAAkBwF,EAAQ,CAAC,GAAG,YAAY,OAASF,EAAG,WAAW,CACnE,CAAC,EACD,OAAAC,EAAG,QAAQD,CAAE,EACbtF,EAAkBsF,EAAG,WAAW,EACzB,IAAMC,EAAG,WAAA,CAClB,EAAG,CAAA,CAAE,EAGL,MAAME,GAAmBC,EAAAA,QAAyC,IAAM,CACtE,GAAInF,GAAoBR,IAAmB,GAAKK,EAC9C,OACF,MAAMuF,EAAO,KAAK,MAAO5F,EAAiB,EAAK,EAAE,EAEjD,MAAO,CAAE,OADC,KAAK,IAAI4F,EAAM9F,CAAa,CACrB,CACnB,EAAG,CAACU,EAAkBR,EAAgBF,EAAeO,CAAY,CAAC,EAE5DwF,GAAmB,IAAM,CAC7B,MAAMC,EAASxG,EAAa,SAAWE,EAAU,QACjD,GAAKsG,EACL,IAAI,SAAS,kBAAmB,CAC9B,SAAS,iBAAiB,MAAM,IAAM,CAAC,CAAC,EACxC,MACF,CACIA,EAAO,mBACTA,EAAO,oBAAoB,MAAM,IAAM,CAAC,CAAC,EAE7C,EAEA5D,EAAAA,UAAU,IAAM,CACd,MAAMe,EAAOxD,EAAQ,QACrB,GAAI,CAACwD,EAAM,OAEXA,EAAK,OACH8C,EAAAA,kBAAAA,IAACC,GAAAA,QAAA,CACC,KAAM7E,EACN,iBAAAnC,EACA,kBAAAC,EACA,WAAAkB,GACA,gBAAAoC,GACA,KAAAnD,EACA,kBAAmB8B,EAAA,CAAA,CACrB,EAIFM,EAAqB,QAAU,OAAO,sBAAsB,IAAM,CAChE9B,EAAgB,UAAA,EAChB8B,EAAqB,QAAU,IACjC,CAAC,EACD,MAAMyE,EAAK,WAAW,IAAMvG,EAAgB,UAAA,EAAa,GAAG,EACtDwG,EAAK,WAAW,IAAMxG,EAAgB,UAAA,EAAa,GAAG,EAC5D,MAAO,IAAM,CACX,aAAauG,CAAE,EACf,aAAaC,CAAE,CACjB,CACF,EAAG,CACD/E,EACAnC,EACAC,EACAkB,GACAf,CAAA,CACD,EACD,MAAM+G,GAAqB,CACzB,gDACA3F,EACI,qCACAkF,GACE,mDACA,gEAAA,EAEL,OAAO,OAAO,EACd,KAAK,GAAG,EAEX,OACEU,EAAAA,kBAAAA,KAAC,MAAA,CACC,IAAK9G,EACL,eAAciD,GAAkB,OAAS,QACzC,UAAW4D,GACX,MACE3D,EACI,CACE,OAAQA,EACR,UAAWA,CAAA,EAEbkD,GAGL,SAAA,CAAA,CAACvG,GACA4G,EAAAA,kBAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASF,GACT,UACE,qFAGD,SAAAxF,EAAe,OAASnB,GAAwB,MAAA,CAAA,EAGpDE,IAAS,cAAgBL,IAAS,WACjCgH,EAAAA,kBAAAA,IAAC,MAAA,CACC,YAAa,IAAMrE,EAAuB,WAAW,EACrD,cAAe,IAAMA,EAAuB,aAAa,EACzD,aAAc,IAAMA,EAAuB,YAAY,EAEvD,SAAAqE,EAAAA,kBAAAA,IAACM,YAAc,QAAAvH,CAAA,CAAkB,CAAA,CAAA,EAGnCiH,EAAAA,kBAAAA,IAAC,SAAA,CACC,IAAKvG,EACL,QAAQ,8EACR,MAAM,aACN,gBAAe,GACf,UAAW,CAACtB,EAAW,qCAAqC,EACzD,OAAO,OAAO,EACd,KAAK,GAAG,EACX,MAAO,CACL,OAAQsE,GAAyB,OACjC,UAAWA,EACX,OAAQ,MAAA,CACV,CAAA,CACF,CAAA,CAAA,CAIR"}
|
|
1
|
+
{"version":3,"file":"IframeSandbox.cjs.js","sources":["../../../src/components/ContentRender/IframeSandbox.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport SandboxApp from \"./SandboxApp\";\nimport ContentRender from \"./ContentRender\";\nimport {\n EMPTY_ROOT_HEIGHT_META,\n inspectViewportHeightFromHtmlRootString,\n inspectViewportHeightFromNodeChain,\n parseExplicitHeight,\n resolveExplicitHeightFromNodeChain,\n} from \"./utils/iframe-viewport-height\";\nimport {\n SANDBOX_INTERACTION_MESSAGE_SOURCE,\n SANDBOX_INTERACTION_MESSAGE_TYPE,\n} from \"../../lib/sandboxInteraction\";\n\ntype InjectBlackboardLibraries =\n typeof import(\"./blackboard-vendor\").injectBlackboardLibraries;\n\n// Cache the sandbox vendor loader so every iframe reuses the same preload request.\nlet blackboardVendorPromise: Promise<InjectBlackboardLibraries> | null = null;\n\nconst loadBlackboardVendor = () => {\n if (!blackboardVendorPromise) {\n blackboardVendorPromise = import(\"./blackboard-vendor\").then(\n (m) => m.injectBlackboardLibraries\n );\n }\n\n return blackboardVendorPromise;\n};\n\nconst COMPLETE_IMAGE_TAG_PATTERN = /<img\\b[^>]*>/i;\nconst POST_IMAGE_STREAM_DEBOUNCE_MS = 180;\nconst SANDBOX_INTERACTION_THROTTLE_MS = 240;\n\nexport interface IframeSandboxProps {\n content: string;\n className?: string;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n hideFullScreen?: boolean;\n mode?: \"content\" | \"blackboard\";\n type: \"sandbox\" | \"markdown\";\n replaceRootScreenHeightWithFull?: boolean;\n}\n\nconst replaceRootScreenHeightToken = (className: string) =>\n className\n .split(/\\s+/)\n .filter(Boolean)\n .map((token) => {\n const segments = token.split(\":\");\n if (\n segments[segments.length - 1] !== \"h-screen\" &&\n segments[segments.length - 1] !== \"min-h-screen\"\n ) {\n return token;\n }\n segments[segments.length - 1] = \"h-full\";\n return segments.join(\":\");\n })\n .join(\" \");\n\nconst replaceRootScreenHeightWithFullClass = (\n html: string,\n enabled: boolean\n) => {\n if (!enabled || !html.trim()) {\n return html;\n }\n\n return html.replace(\n /^(\\s*<[a-zA-Z][\\w:-]*)(\\s[^>]*?)?>/,\n (match, tagStart: string, attrs = \"\") => {\n const classMatch = attrs.match(/\\bclass\\s*=\\s*([\"'])([^\"']*)\\1/i);\n\n if (!classMatch) {\n return match;\n }\n\n const nextClassName = replaceRootScreenHeightToken(classMatch[2]);\n\n if (nextClassName === classMatch[2]) {\n return match;\n }\n\n return `${tagStart}${attrs.replace(\n classMatch[0],\n `class=${classMatch[1]}${nextClassName}${classMatch[1]}`\n )}>`;\n }\n );\n};\n\nconst IframeSandbox: React.FC<IframeSandboxProps> = ({\n content,\n type,\n className,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n replaceRootScreenHeightWithFull = false,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const rootRef = useRef<Root | null>(null);\n const updateHeightRef = useRef<() => void>(() => {});\n const [height, setHeight] = useState(480);\n const [contentHeight, setContentHeight] = useState(0);\n const [containerWidth, setContainerWidth] = useState(0);\n const lastSandboxInteractionTimeRef = useRef(0);\n const [resetToken, setResetToken] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const shouldInjectSandboxVendor = type === \"sandbox\";\n\n const isBlackboardMode = mode === \"blackboard\";\n const shouldMeasureDynamicHeight = isBlackboardMode && type === \"sandbox\";\n const shouldProcessRootScreenHeight =\n shouldMeasureDynamicHeight && replaceRootScreenHeightWithFull;\n const prevHtmlRef = useRef<string>(\"\");\n const htmlContent = React.useMemo(\n () => (type === \"sandbox\" ? content : \"\"),\n [content, type]\n );\n const normalizedHtmlContent = React.useMemo(\n () =>\n replaceRootScreenHeightWithFullClass(\n htmlContent,\n shouldProcessRootScreenHeight\n ),\n [htmlContent, shouldProcessRootScreenHeight]\n );\n const originalRootHeightMeta = React.useMemo(\n () =>\n shouldProcessRootScreenHeight\n ? inspectViewportHeightFromHtmlRootString(htmlContent)\n : EMPTY_ROOT_HEIGHT_META,\n [htmlContent, shouldProcessRootScreenHeight]\n );\n const shouldStretchRootHeight = React.useMemo(\n () =>\n shouldProcessRootScreenHeight &&\n originalRootHeightMeta.hasFullViewportHeight,\n [\n originalRootHeightMeta.hasFullViewportHeight,\n shouldProcessRootScreenHeight,\n ]\n );\n const [renderHtmlContent, setRenderHtmlContent] = useState(\n normalizedHtmlContent\n );\n const prevIncomingHtmlRef = useRef(normalizedHtmlContent);\n const pendingHtmlRef = useRef(normalizedHtmlContent);\n const deferRenderTimerRef = useRef<number | null>(null);\n const initialPaintFrameRef = useRef<number | null>(null);\n const renderViewportHeightCssRef = useRef<string | null>(null);\n\n const emitSandboxInteraction = useCallback((eventType: string) => {\n if (typeof window === \"undefined\") {\n return;\n }\n const now = Date.now();\n if (\n now - lastSandboxInteractionTimeRef.current <\n SANDBOX_INTERACTION_THROTTLE_MS\n ) {\n return;\n }\n lastSandboxInteractionTimeRef.current = now;\n window.postMessage(\n {\n source: SANDBOX_INTERACTION_MESSAGE_SOURCE,\n type: SANDBOX_INTERACTION_MESSAGE_TYPE,\n eventType,\n },\n window.location.origin\n );\n }, []);\n\n const clearDeferredRenderTimer = () => {\n if (deferRenderTimerRef.current === null) return;\n window.clearTimeout(deferRenderTimerRef.current);\n deferRenderTimerRef.current = null;\n };\n\n const clearInitialPaintFrames = () => {\n if (initialPaintFrameRef.current !== null) {\n window.cancelAnimationFrame(initialPaintFrameRef.current);\n initialPaintFrameRef.current = null;\n }\n };\n\n useEffect(\n () => () => {\n clearDeferredRenderTimer();\n clearInitialPaintFrames();\n },\n []\n );\n\n useEffect(() => {\n const prevIncomingHtml = prevIncomingHtmlRef.current;\n prevIncomingHtmlRef.current = normalizedHtmlContent;\n\n const isAppendOnlyStream =\n !!prevIncomingHtml &&\n normalizedHtmlContent.length > prevIncomingHtml.length &&\n normalizedHtmlContent.startsWith(prevIncomingHtml);\n const containsCompleteImage = COMPLETE_IMAGE_TAG_PATTERN.test(\n normalizedHtmlContent\n );\n const shouldDeferRender = isAppendOnlyStream && containsCompleteImage;\n\n if (!shouldDeferRender) {\n clearDeferredRenderTimer();\n pendingHtmlRef.current = normalizedHtmlContent;\n setRenderHtmlContent(normalizedHtmlContent);\n return;\n }\n\n pendingHtmlRef.current = normalizedHtmlContent;\n clearDeferredRenderTimer();\n deferRenderTimerRef.current = window.setTimeout(() => {\n setRenderHtmlContent(pendingHtmlRef.current);\n deferRenderTimerRef.current = null;\n }, POST_IMAGE_STREAM_DEBOUNCE_MS);\n }, [normalizedHtmlContent]);\n\n const rootViewportHeightCss = React.useMemo(() => {\n if (!shouldMeasureDynamicHeight) {\n return null;\n }\n\n return inspectViewportHeightFromHtmlRootString(renderHtmlContent)\n .viewportHeightCss;\n }, [renderHtmlContent, shouldMeasureDynamicHeight]);\n\n useEffect(() => {\n renderViewportHeightCssRef.current = rootViewportHeightCss;\n }, [rootViewportHeightCss]);\n\n const hasRootVhHeight = Boolean(rootViewportHeightCss);\n const sandboxViewportHeight =\n isBlackboardMode && type === \"sandbox\"\n ? shouldStretchRootHeight\n ? \"100%\"\n : (rootViewportHeightCss ?? `${height}px`)\n : undefined;\n useEffect(() => {\n if (mode !== \"blackboard\") {\n prevHtmlRef.current = normalizedHtmlContent;\n return;\n }\n const prev = prevHtmlRef.current;\n const isContinuation = prev && normalizedHtmlContent.startsWith(prev);\n if (!isContinuation && prev) {\n setResetToken((token) => token + 1);\n }\n prevHtmlRef.current = normalizedHtmlContent;\n }, [mode, normalizedHtmlContent]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return undefined;\n\n const doc = iframe.contentDocument;\n if (!doc) return undefined;\n\n doc.open();\n doc.write(`<!DOCTYPE html>\n<html${mode === \"blackboard\" ? ' style=\"height: 100%;\"' : \"\"}>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <style>\n :root { color-scheme: light; }\n html, body, #root { width: 100%; }\n ${mode === \"blackboard\" ? \"html, body, #root { height: 100%; }\" : \"\"}\n html, body { margin: 0; padding: 0; overflow: auto; }\n *, *::before, *::after { box-sizing: border-box; }\n html.measuring-height, html.measuring-height body,\n html.measuring-height #root, html.measuring-height .sandbox-wrapper {\n height: auto !important; min-height: 0 !important;\n }\n html.measuring-height * {\n min-height: 0 !important;\n }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n </body>\n</html>`);\n doc.close();\n\n // Force iframe theme to stay in light mode regardless of host OS preference.\n doc.documentElement.setAttribute(\"data-theme\", \"light\");\n doc.documentElement.style.colorScheme = \"light\";\n doc.body?.style.setProperty(\"color-scheme\", \"light\");\n\n const shouldBridgeSandboxInteraction =\n isBlackboardMode && type === \"sandbox\";\n const handleSandboxPointerDown = () =>\n emitSandboxInteraction(\"pointerdown\");\n const handleSandboxMouseDown = () => emitSandboxInteraction(\"mousedown\");\n const handleSandboxTouchStart = () => emitSandboxInteraction(\"touchstart\");\n\n if (shouldBridgeSandboxInteraction) {\n doc.addEventListener(\"pointerdown\", handleSandboxPointerDown, true);\n doc.addEventListener(\"mousedown\", handleSandboxMouseDown, true);\n doc.addEventListener(\"touchstart\", handleSandboxTouchStart, true);\n }\n\n const rootEl = doc.getElementById(\"root\");\n if (!rootEl) return undefined;\n\n const root = createRoot(rootEl);\n rootRef.current = root;\n let isDestroyed = false;\n const getHeightInspectionNode = (node: HTMLElement) => ({\n heightAttrValue: node.getAttribute(\"height\"),\n styleAttrValue: node.getAttribute(\"style\"),\n classAttrValue: node.getAttribute(\"class\"),\n });\n const getSingleChildElement = (node: HTMLElement) => {\n const childElements = Array.from(node.children) as HTMLElement[];\n\n return childElements.length === 1 ? childElements[0] : null;\n };\n\n const resolveExplicitHeight = () => {\n if (!shouldMeasureDynamicHeight) return null;\n if (!iframeRef.current || !doc.body) return null;\n const parentViewportHeight =\n iframeRef.current.ownerDocument?.documentElement?.clientHeight ||\n window.innerHeight;\n // Reuse parsed height metadata from the current html snapshot first to\n // avoid re-inspecting the same DOM chain on every height tick.\n const precomputedViewportHeightCss = renderViewportHeightCssRef.current;\n const parsed = precomputedViewportHeightCss\n ? parseExplicitHeight(\n precomputedViewportHeightCss,\n parentViewportHeight\n )\n : null;\n\n if (parsed !== null) {\n return Math.ceil(parsed);\n }\n\n const wrapper = doc.body.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const container = wrapper?.firstElementChild as HTMLElement | null;\n if (!container) return null;\n const containerChildren = Array.from(container.children) as HTMLElement[];\n const rootContentElement =\n containerChildren.length === 1 ? containerChildren[0] : null;\n const runtimeHeightMeta = inspectViewportHeightFromNodeChain(\n rootContentElement,\n {\n getNode: getHeightInspectionNode,\n getSingleChild: getSingleChildElement,\n }\n );\n const runtimeViewportHeightCss = runtimeHeightMeta.viewportHeightCss;\n\n if (runtimeViewportHeightCss) {\n const runtimeViewportHeight = parseExplicitHeight(\n runtimeViewportHeightCss,\n parentViewportHeight\n );\n\n if (runtimeViewportHeight !== null) {\n return Math.ceil(runtimeViewportHeight);\n }\n }\n\n const explicitPixelHeight = resolveExplicitHeightFromNodeChain(\n rootContentElement,\n parentViewportHeight,\n {\n getNode: getHeightInspectionNode,\n getSingleChild: getSingleChildElement,\n }\n );\n\n return explicitPixelHeight !== null\n ? Math.ceil(explicitPixelHeight)\n : null;\n };\n\n const updateHeight = () => {\n if (!iframeRef.current || !doc.body) return;\n\n if (!isBlackboardMode) {\n // Content mode: toggle a CSS class on <html> to neutralize\n // height:100% / min-h-screen on wrapper chain during measurement.\n // Using <html> class avoids triggering MutationObserver (which\n // only observes doc.body and its descendants).\n doc.documentElement.classList.add(\"measuring-height\");\n\n const bodyScrollH = doc.body.scrollHeight;\n const htmlScrollH = doc.documentElement?.scrollHeight || 0;\n const rootScrollH = rootEl?.scrollHeight || 0;\n const measuredHeight = Math.max(bodyScrollH, htmlScrollH, rootScrollH);\n\n doc.documentElement.classList.remove(\"measuring-height\");\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredHeight));\n return prev === next ? prev : next;\n });\n return;\n }\n\n // Blackboard mode: use existing explicit height resolution logic\n const bodyScrollH = doc.body.scrollHeight;\n const htmlScrollH = doc.documentElement?.scrollHeight || 0;\n const rootScrollH = rootEl?.scrollHeight || 0;\n const measuredHeight = Math.max(bodyScrollH, htmlScrollH, rootScrollH);\n\n if (shouldMeasureDynamicHeight) {\n const explicitHeight = resolveExplicitHeight();\n const nextHeight = Math.max(\n 200,\n explicitHeight ?? Math.ceil(measuredHeight)\n );\n setHeight((prevHeight) =>\n prevHeight === nextHeight ? prevHeight : nextHeight\n );\n }\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredHeight));\n return prev === next ? prev : next;\n });\n };\n const scheduleHeightUpdate = () => {\n requestAnimationFrame(() => {\n if (isDestroyed) return;\n updateHeight();\n });\n };\n updateHeightRef.current = scheduleHeightUpdate;\n\n updateHeight();\n scheduleHeightUpdate();\n\n if (shouldInjectSandboxVendor) {\n // Inject Tailwind/DaisyUI/GSAP before rendering sandbox content to avoid FOUC.\n loadBlackboardVendor()\n .then((inject) => {\n if (isDestroyed) return;\n inject(doc);\n requestAnimationFrame(() => {\n if (isDestroyed) return;\n scheduleHeightUpdate();\n });\n })\n .catch(() => {\n if (isDestroyed) return;\n scheduleHeightUpdate();\n });\n }\n\n const resizeObserver = new ResizeObserver(() => updateHeight());\n resizeObserver.observe(doc.body);\n if (rootEl) {\n resizeObserver.observe(rootEl);\n }\n\n // MutationObserver: detect DOM changes that ResizeObserver might miss\n // (e.g. content injected by scripts, images loading, dynamic rendering)\n const mutationObserver = new MutationObserver(() => {\n scheduleHeightUpdate();\n });\n mutationObserver.observe(doc.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"style\", \"class\"],\n });\n\n return () => {\n isDestroyed = true;\n resizeObserver.disconnect();\n mutationObserver.disconnect();\n if (shouldBridgeSandboxInteraction) {\n doc.removeEventListener(\"pointerdown\", handleSandboxPointerDown, true);\n doc.removeEventListener(\"mousedown\", handleSandboxMouseDown, true);\n doc.removeEventListener(\"touchstart\", handleSandboxTouchStart, true);\n }\n // Defer unmount to avoid React warning when parent is mid-render\n setTimeout(() => {\n root.unmount();\n rootRef.current = null;\n updateHeightRef.current = () => {};\n }, 0);\n };\n }, []);\n\n useEffect(() => {\n const onFullscreenChange = () => {\n setIsFullscreen(Boolean(document.fullscreenElement));\n };\n document.addEventListener(\"fullscreenchange\", onFullscreenChange);\n return () =>\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange);\n }, []);\n\n // Track container width for computing min-height in content mode\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const ro = new ResizeObserver((entries) => {\n setContainerWidth(entries[0]?.contentRect.width ?? el.clientWidth);\n });\n ro.observe(el);\n setContainerWidth(el.clientWidth);\n return () => ro.disconnect();\n }, []);\n\n // Content mode: min 16:9 aspect ratio, grow to fit content (no scrollbar)\n const contentModeStyle = useMemo<React.CSSProperties | undefined>(() => {\n if (isBlackboardMode || containerWidth === 0 || isFullscreen)\n return undefined;\n const minH = Math.round((containerWidth * 9) / 16);\n const h = Math.max(minH, contentHeight);\n return { height: h };\n }, [isBlackboardMode, containerWidth, contentHeight, isFullscreen]);\n\n const toggleFullscreen = () => {\n const target = containerRef.current || iframeRef.current;\n if (!target) return;\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n return;\n }\n if (target.requestFullscreen) {\n target.requestFullscreen().catch(() => {});\n }\n };\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n root.render(\n <SandboxApp\n html={renderHtmlContent}\n styleLoadingText={styleLoadingText}\n scriptLoadingText={scriptLoadingText}\n resetToken={resetToken}\n hasRootVhHeight={hasRootVhHeight}\n mode={mode}\n stretchRootHeight={shouldStretchRootHeight}\n />\n );\n\n // Schedule multiple measurements to catch async content (scripts, images, styles).\n initialPaintFrameRef.current = window.requestAnimationFrame(() => {\n updateHeightRef.current?.();\n initialPaintFrameRef.current = null;\n });\n const t1 = setTimeout(() => updateHeightRef.current?.(), 100);\n const t2 = setTimeout(() => updateHeightRef.current?.(), 500);\n return () => {\n clearTimeout(t1);\n clearTimeout(t2);\n };\n }, [\n renderHtmlContent,\n styleLoadingText,\n scriptLoadingText,\n resetToken,\n mode,\n ]);\n const containerClassName = [\n \"w-full relative content-render-iframe-sandbox\",\n isBlackboardMode\n ? \"h-full overflow-auto flex flex-col\"\n : contentModeStyle\n ? \"overflow-hidden flex items-center justify-center\"\n : \"aspect-[16/9] overflow-hidden flex items-center justify-center\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n ref={containerRef}\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className={containerClassName}\n style={\n sandboxViewportHeight\n ? {\n height: sandboxViewportHeight,\n minHeight: sandboxViewportHeight,\n }\n : contentModeStyle\n }\n >\n {!hideFullScreen && (\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className={\n \"absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer\"\n }\n >\n {isFullscreen ? \"退出全屏\" : fullScreenButtonText || \"全屏浏览\"}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <div\n onMouseDown={() => emitSandboxInteraction(\"mousedown\")}\n onPointerDown={() => emitSandboxInteraction(\"pointerdown\")}\n onTouchStart={() => emitSandboxInteraction(\"touchstart\")}\n >\n <ContentRender content={content} />\n </div>\n ) : (\n <iframe\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n allow=\"fullscreen\"\n allowFullScreen\n className={[className, \"w-full h-full mx-auto my-auto block\"]\n .filter(Boolean)\n .join(\" \")}\n style={{\n height: sandboxViewportHeight ?? \"100%\",\n minHeight: sandboxViewportHeight,\n margin: \"auto\",\n }}\n />\n )}\n </div>\n );\n};\n\nexport default IframeSandbox;\n"],"names":["blackboardVendorPromise","loadBlackboardVendor","m","COMPLETE_IMAGE_TAG_PATTERN","POST_IMAGE_STREAM_DEBOUNCE_MS","SANDBOX_INTERACTION_THROTTLE_MS","replaceRootScreenHeightToken","className","token","segments","replaceRootScreenHeightWithFullClass","html","enabled","match","tagStart","attrs","classMatch","nextClassName","IframeSandbox","content","type","styleLoadingText","scriptLoadingText","fullScreenButtonText","hideFullScreen","mode","replaceRootScreenHeightWithFull","containerRef","useRef","iframeRef","rootRef","updateHeightRef","height","setHeight","useState","contentHeight","setContentHeight","containerWidth","setContainerWidth","lastSandboxInteractionTimeRef","resetToken","setResetToken","isFullscreen","setIsFullscreen","shouldInjectSandboxVendor","isBlackboardMode","shouldMeasureDynamicHeight","shouldProcessRootScreenHeight","prevHtmlRef","htmlContent","React","normalizedHtmlContent","originalRootHeightMeta","inspectViewportHeightFromHtmlRootString","EMPTY_ROOT_HEIGHT_META","shouldStretchRootHeight","renderHtmlContent","setRenderHtmlContent","prevIncomingHtmlRef","pendingHtmlRef","deferRenderTimerRef","initialPaintFrameRef","renderViewportHeightCssRef","emitSandboxInteraction","useCallback","eventType","now","SANDBOX_INTERACTION_MESSAGE_SOURCE","SANDBOX_INTERACTION_MESSAGE_TYPE","clearDeferredRenderTimer","clearInitialPaintFrames","useEffect","prevIncomingHtml","isAppendOnlyStream","containsCompleteImage","rootViewportHeightCss","hasRootVhHeight","sandboxViewportHeight","prev","iframe","doc","shouldBridgeSandboxInteraction","handleSandboxPointerDown","handleSandboxMouseDown","handleSandboxTouchStart","rootEl","root","createRoot","isDestroyed","getHeightInspectionNode","node","getSingleChildElement","childElements","resolveExplicitHeight","parentViewportHeight","precomputedViewportHeightCss","parsed","parseExplicitHeight","container","containerChildren","rootContentElement","runtimeViewportHeightCss","inspectViewportHeightFromNodeChain","runtimeViewportHeight","explicitPixelHeight","resolveExplicitHeightFromNodeChain","updateHeight","bodyScrollH","htmlScrollH","rootScrollH","measuredHeight","next","explicitHeight","nextHeight","prevHeight","scheduleHeightUpdate","inject","resizeObserver","mutationObserver","onFullscreenChange","el","ro","entries","contentModeStyle","useMemo","minH","toggleFullscreen","target","jsx","SandboxApp","t1","t2","containerClassName","jsxs","ContentRender"],"mappings":"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"}
|
|
@@ -1,108 +1,108 @@
|
|
|
1
1
|
import { j as E } from "../../_virtual/jsx-runtime.es.js";
|
|
2
|
-
import
|
|
3
|
-
import { createRoot as
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { inspectViewportHeightFromHtmlRootString as
|
|
7
|
-
import { SANDBOX_INTERACTION_MESSAGE_TYPE as
|
|
8
|
-
let
|
|
9
|
-
const
|
|
10
|
-
(
|
|
11
|
-
)),
|
|
12
|
-
const
|
|
13
|
-
return
|
|
14
|
-
}).join(" "),
|
|
2
|
+
import _, { useRef as l, useState as v, useCallback as Fe, useEffect as m, useMemo as Ie } from "react";
|
|
3
|
+
import { createRoot as Ne } from "react-dom/client";
|
|
4
|
+
import _e from "./SandboxApp.es.js";
|
|
5
|
+
import Oe from "./ContentRender.es.js";
|
|
6
|
+
import { inspectViewportHeightFromHtmlRootString as we, EMPTY_ROOT_HEIGHT_META as Ve, parseExplicitHeight as He, inspectViewportHeightFromNodeChain as De, resolveExplicitHeightFromNodeChain as je } from "./utils/iframe-viewport-height.es.js";
|
|
7
|
+
import { SANDBOX_INTERACTION_MESSAGE_TYPE as ke, SANDBOX_INTERACTION_MESSAGE_SOURCE as Be } from "../../lib/sandboxInteraction.es.js";
|
|
8
|
+
let J = null;
|
|
9
|
+
const Pe = () => (J || (J = import("./blackboard-vendor.es.js").then(
|
|
10
|
+
(s) => s.injectBlackboardLibraries
|
|
11
|
+
)), J), Le = /<img\b[^>]*>/i, $e = 180, ze = 240, We = (s) => s.split(/\s+/).filter(Boolean).map((o) => {
|
|
12
|
+
const i = o.split(":");
|
|
13
|
+
return i[i.length - 1] !== "h-screen" && i[i.length - 1] !== "min-h-screen" ? o : (i[i.length - 1] = "h-full", i.join(":"));
|
|
14
|
+
}).join(" "), qe = (s, o) => !o || !s.trim() ? s : s.replace(
|
|
15
15
|
/^(\s*<[a-zA-Z][\w:-]*)(\s[^>]*?)?>/,
|
|
16
|
-
(
|
|
17
|
-
const h =
|
|
16
|
+
(i, O, S = "") => {
|
|
17
|
+
const h = S.match(/\bclass\s*=\s*(["'])([^"']*)\1/i);
|
|
18
18
|
if (!h)
|
|
19
|
-
return
|
|
20
|
-
const
|
|
21
|
-
return
|
|
19
|
+
return i;
|
|
20
|
+
const V = We(h[2]);
|
|
21
|
+
return V === h[2] ? i : `${O}${S.replace(
|
|
22
22
|
h[0],
|
|
23
|
-
`class=${h[1]}${
|
|
23
|
+
`class=${h[1]}${V}${h[1]}`
|
|
24
24
|
)}>`;
|
|
25
25
|
}
|
|
26
|
-
),
|
|
27
|
-
content:
|
|
28
|
-
type:
|
|
29
|
-
className:
|
|
30
|
-
styleLoadingText:
|
|
31
|
-
scriptLoadingText:
|
|
26
|
+
), Qe = ({
|
|
27
|
+
content: s,
|
|
28
|
+
type: o,
|
|
29
|
+
className: i,
|
|
30
|
+
styleLoadingText: O,
|
|
31
|
+
scriptLoadingText: S,
|
|
32
32
|
fullScreenButtonText: h,
|
|
33
|
-
hideFullScreen:
|
|
33
|
+
hideFullScreen: V = !1,
|
|
34
34
|
mode: d = "content",
|
|
35
|
-
replaceRootScreenHeightWithFull:
|
|
35
|
+
replaceRootScreenHeightWithFull: xe = !1
|
|
36
36
|
}) => {
|
|
37
|
-
const
|
|
38
|
-
}), [
|
|
39
|
-
() =>
|
|
40
|
-
[
|
|
41
|
-
), n =
|
|
42
|
-
() =>
|
|
43
|
-
|
|
37
|
+
const P = l(null), b = l(null), L = l(null), R = l(() => {
|
|
38
|
+
}), [Ee, ve] = v(480), [K, Q] = v(0), [$, ee] = v(0), te = l(0), [ne, Se] = v(0), [z, Re] = v(!1), Me = o === "sandbox", g = d === "blackboard", M = g && o === "sandbox", w = M && xe, W = l(""), D = _.useMemo(
|
|
39
|
+
() => o === "sandbox" ? s : "",
|
|
40
|
+
[s, o]
|
|
41
|
+
), n = _.useMemo(
|
|
42
|
+
() => qe(
|
|
43
|
+
D,
|
|
44
44
|
w
|
|
45
45
|
),
|
|
46
|
-
[
|
|
47
|
-
),
|
|
48
|
-
() => w ?
|
|
49
|
-
[
|
|
50
|
-
),
|
|
51
|
-
() => w &&
|
|
46
|
+
[D, w]
|
|
47
|
+
), re = _.useMemo(
|
|
48
|
+
() => w ? we(D) : Ve,
|
|
49
|
+
[D, w]
|
|
50
|
+
), oe = _.useMemo(
|
|
51
|
+
() => w && re.hasFullViewportHeight,
|
|
52
52
|
[
|
|
53
|
-
|
|
53
|
+
re.hasFullViewportHeight,
|
|
54
54
|
w
|
|
55
55
|
]
|
|
56
|
-
), [
|
|
56
|
+
), [j, ie] = v(
|
|
57
57
|
n
|
|
58
|
-
),
|
|
58
|
+
), se = l(n), q = l(n), C = l(null), y = l(null), le = l(null), H = Fe((t) => {
|
|
59
59
|
if (typeof window > "u")
|
|
60
60
|
return;
|
|
61
61
|
const e = Date.now();
|
|
62
|
-
e -
|
|
62
|
+
e - te.current < ze || (te.current = e, window.postMessage(
|
|
63
63
|
{
|
|
64
|
-
source:
|
|
65
|
-
type:
|
|
64
|
+
source: Be,
|
|
65
|
+
type: ke,
|
|
66
66
|
eventType: t
|
|
67
67
|
},
|
|
68
68
|
window.location.origin
|
|
69
69
|
));
|
|
70
|
-
}, []),
|
|
71
|
-
|
|
72
|
-
},
|
|
73
|
-
|
|
70
|
+
}, []), G = () => {
|
|
71
|
+
C.current !== null && (window.clearTimeout(C.current), C.current = null);
|
|
72
|
+
}, Ce = () => {
|
|
73
|
+
y.current !== null && (window.cancelAnimationFrame(y.current), y.current = null);
|
|
74
74
|
};
|
|
75
75
|
m(
|
|
76
76
|
() => () => {
|
|
77
|
-
|
|
77
|
+
G(), Ce();
|
|
78
78
|
},
|
|
79
79
|
[]
|
|
80
80
|
), m(() => {
|
|
81
|
-
const t =
|
|
82
|
-
|
|
83
|
-
const e = !!t && n.length > t.length && n.startsWith(t),
|
|
81
|
+
const t = se.current;
|
|
82
|
+
se.current = n;
|
|
83
|
+
const e = !!t && n.length > t.length && n.startsWith(t), c = Le.test(
|
|
84
84
|
n
|
|
85
85
|
);
|
|
86
|
-
if (!(e &&
|
|
87
|
-
|
|
86
|
+
if (!(e && c)) {
|
|
87
|
+
G(), q.current = n, ie(n);
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
},
|
|
90
|
+
q.current = n, G(), C.current = window.setTimeout(() => {
|
|
91
|
+
ie(q.current), C.current = null;
|
|
92
|
+
}, $e);
|
|
93
93
|
}, [n]);
|
|
94
|
-
const
|
|
94
|
+
const k = _.useMemo(() => M ? we(j).viewportHeightCss : null, [j, M]);
|
|
95
95
|
m(() => {
|
|
96
|
-
|
|
97
|
-
}, [
|
|
98
|
-
const
|
|
96
|
+
le.current = k;
|
|
97
|
+
}, [k]);
|
|
98
|
+
const ce = !!k, T = g && o === "sandbox" ? oe ? "100%" : k ?? `${Ee}px` : void 0;
|
|
99
99
|
m(() => {
|
|
100
100
|
if (d !== "blackboard") {
|
|
101
|
-
|
|
101
|
+
W.current = n;
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
|
-
const t =
|
|
105
|
-
!(t && n.startsWith(t)) && t &&
|
|
104
|
+
const t = W.current;
|
|
105
|
+
!(t && n.startsWith(t)) && t && Se((c) => c + 1), W.current = n;
|
|
106
106
|
}, [d, n]), m(() => {
|
|
107
107
|
const t = b.current;
|
|
108
108
|
if (!t) return;
|
|
@@ -119,138 +119,142 @@ const $e = () => (K || (K = import("./blackboard-vendor.es.js").then(
|
|
|
119
119
|
${d === "blackboard" ? "html, body, #root { height: 100%; }" : ""}
|
|
120
120
|
html, body { margin: 0; padding: 0; overflow: auto; }
|
|
121
121
|
*, *::before, *::after { box-sizing: border-box; }
|
|
122
|
+
html.measuring-height, html.measuring-height body,
|
|
123
|
+
html.measuring-height #root, html.measuring-height .sandbox-wrapper {
|
|
124
|
+
height: auto !important; min-height: 0 !important;
|
|
125
|
+
}
|
|
126
|
+
html.measuring-height * {
|
|
127
|
+
min-height: 0 !important;
|
|
128
|
+
}
|
|
122
129
|
</style>
|
|
123
130
|
</head>
|
|
124
131
|
<body>
|
|
125
132
|
<div id="root"></div>
|
|
126
133
|
</body>
|
|
127
134
|
</html>`), e.close(), e.documentElement.setAttribute("data-theme", "light"), e.documentElement.style.colorScheme = "light", e.body?.style.setProperty("color-scheme", "light");
|
|
128
|
-
const
|
|
129
|
-
|
|
135
|
+
const c = g && o === "sandbox", U = () => H("pointerdown"), ae = () => H("mousedown"), he = () => H("touchstart");
|
|
136
|
+
c && (e.addEventListener("pointerdown", U, !0), e.addEventListener("mousedown", ae, !0), e.addEventListener("touchstart", he, !0));
|
|
130
137
|
const x = e.getElementById("root");
|
|
131
138
|
if (!x) return;
|
|
132
|
-
const
|
|
133
|
-
|
|
139
|
+
const de = Ne(x);
|
|
140
|
+
L.current = de;
|
|
134
141
|
let A = !1;
|
|
135
|
-
const
|
|
142
|
+
const me = (r) => ({
|
|
136
143
|
heightAttrValue: r.getAttribute("height"),
|
|
137
144
|
styleAttrValue: r.getAttribute("style"),
|
|
138
145
|
classAttrValue: r.getAttribute("class")
|
|
139
146
|
}), ge = (r) => {
|
|
140
|
-
const
|
|
141
|
-
return
|
|
142
|
-
},
|
|
143
|
-
if (!
|
|
144
|
-
const r = b.current.ownerDocument?.documentElement?.clientHeight || window.innerHeight,
|
|
145
|
-
|
|
147
|
+
const f = Array.from(r.children);
|
|
148
|
+
return f.length === 1 ? f[0] : null;
|
|
149
|
+
}, Ae = () => {
|
|
150
|
+
if (!M || !b.current || !e.body) return null;
|
|
151
|
+
const r = b.current.ownerDocument?.documentElement?.clientHeight || window.innerHeight, f = le.current, B = f ? He(
|
|
152
|
+
f,
|
|
146
153
|
r
|
|
147
154
|
) : null;
|
|
148
|
-
if (
|
|
149
|
-
return Math.ceil(
|
|
150
|
-
const
|
|
155
|
+
if (B !== null)
|
|
156
|
+
return Math.ceil(B);
|
|
157
|
+
const a = e.body.querySelector(
|
|
151
158
|
".sandbox-wrapper"
|
|
152
159
|
)?.firstElementChild;
|
|
153
|
-
if (!
|
|
154
|
-
const
|
|
160
|
+
if (!a) return null;
|
|
161
|
+
const u = Array.from(a.children), p = u.length === 1 ? u[0] : null, I = De(
|
|
155
162
|
p,
|
|
156
163
|
{
|
|
157
|
-
getNode:
|
|
164
|
+
getNode: me,
|
|
158
165
|
getSingleChild: ge
|
|
159
166
|
}
|
|
160
167
|
).viewportHeightCss;
|
|
161
|
-
if (
|
|
162
|
-
const
|
|
163
|
-
|
|
168
|
+
if (I) {
|
|
169
|
+
const be = He(
|
|
170
|
+
I,
|
|
164
171
|
r
|
|
165
172
|
);
|
|
166
|
-
if (
|
|
167
|
-
return Math.ceil(
|
|
173
|
+
if (be !== null)
|
|
174
|
+
return Math.ceil(be);
|
|
168
175
|
}
|
|
169
|
-
const
|
|
176
|
+
const N = je(
|
|
170
177
|
p,
|
|
171
178
|
r,
|
|
172
179
|
{
|
|
173
|
-
getNode:
|
|
180
|
+
getNode: me,
|
|
174
181
|
getSingleChild: ge
|
|
175
182
|
}
|
|
176
183
|
);
|
|
177
|
-
return
|
|
178
|
-
},
|
|
184
|
+
return N !== null ? Math.ceil(N) : null;
|
|
185
|
+
}, X = () => {
|
|
179
186
|
if (!b.current || !e.body) return;
|
|
180
|
-
if (!
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
o && (o.style.height = a), e.body.style.height = p, e.documentElement.style.height = be, ee((we) => {
|
|
187
|
-
const He = Math.max(200, Math.ceil(Ne));
|
|
188
|
-
return we === He ? we : He;
|
|
187
|
+
if (!g) {
|
|
188
|
+
e.documentElement.classList.add("measuring-height");
|
|
189
|
+
const a = e.body.scrollHeight, u = e.documentElement?.scrollHeight || 0, p = x?.scrollHeight || 0, pe = Math.max(a, u, p);
|
|
190
|
+
e.documentElement.classList.remove("measuring-height"), Q((I) => {
|
|
191
|
+
const N = Math.max(200, Math.ceil(pe));
|
|
192
|
+
return I === N ? I : N;
|
|
189
193
|
});
|
|
190
194
|
return;
|
|
191
195
|
}
|
|
192
|
-
const r = e.body.scrollHeight,
|
|
193
|
-
if (
|
|
194
|
-
const
|
|
196
|
+
const r = e.body.scrollHeight, f = e.documentElement?.scrollHeight || 0, B = x?.scrollHeight || 0, Z = Math.max(r, f, B);
|
|
197
|
+
if (M) {
|
|
198
|
+
const a = Ae(), u = Math.max(
|
|
195
199
|
200,
|
|
196
|
-
|
|
200
|
+
a ?? Math.ceil(Z)
|
|
197
201
|
);
|
|
198
|
-
|
|
199
|
-
(p) => p ===
|
|
202
|
+
ve(
|
|
203
|
+
(p) => p === u ? p : u
|
|
200
204
|
);
|
|
201
205
|
}
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
return
|
|
206
|
+
Q((a) => {
|
|
207
|
+
const u = Math.max(200, Math.ceil(Z));
|
|
208
|
+
return a === u ? a : u;
|
|
205
209
|
});
|
|
206
210
|
}, F = () => {
|
|
207
211
|
requestAnimationFrame(() => {
|
|
208
|
-
A ||
|
|
212
|
+
A || X();
|
|
209
213
|
});
|
|
210
214
|
};
|
|
211
|
-
|
|
215
|
+
R.current = F, X(), F(), Me && Pe().then((r) => {
|
|
212
216
|
A || (r(e), requestAnimationFrame(() => {
|
|
213
217
|
A || F();
|
|
214
218
|
}));
|
|
215
219
|
}).catch(() => {
|
|
216
220
|
A || F();
|
|
217
221
|
});
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
const
|
|
222
|
+
const Y = new ResizeObserver(() => X());
|
|
223
|
+
Y.observe(e.body), x && Y.observe(x);
|
|
224
|
+
const fe = new MutationObserver(() => {
|
|
221
225
|
F();
|
|
222
226
|
});
|
|
223
|
-
return
|
|
227
|
+
return fe.observe(e.body, {
|
|
224
228
|
childList: !0,
|
|
225
229
|
subtree: !0,
|
|
226
230
|
attributes: !0,
|
|
227
231
|
attributeFilter: ["style", "class"]
|
|
228
232
|
}), () => {
|
|
229
|
-
A = !0,
|
|
230
|
-
|
|
233
|
+
A = !0, Y.disconnect(), fe.disconnect(), c && (e.removeEventListener("pointerdown", U, !0), e.removeEventListener("mousedown", ae, !0), e.removeEventListener("touchstart", he, !0)), setTimeout(() => {
|
|
234
|
+
de.unmount(), L.current = null, R.current = () => {
|
|
231
235
|
};
|
|
232
236
|
}, 0);
|
|
233
237
|
};
|
|
234
238
|
}, []), m(() => {
|
|
235
239
|
const t = () => {
|
|
236
|
-
|
|
240
|
+
Re(!!document.fullscreenElement);
|
|
237
241
|
};
|
|
238
242
|
return document.addEventListener("fullscreenchange", t), () => document.removeEventListener("fullscreenchange", t);
|
|
239
243
|
}, []), m(() => {
|
|
240
|
-
const t =
|
|
244
|
+
const t = P.current;
|
|
241
245
|
if (!t) return;
|
|
242
|
-
const e = new ResizeObserver((
|
|
243
|
-
|
|
246
|
+
const e = new ResizeObserver((c) => {
|
|
247
|
+
ee(c[0]?.contentRect.width ?? t.clientWidth);
|
|
244
248
|
});
|
|
245
|
-
return e.observe(t),
|
|
249
|
+
return e.observe(t), ee(t.clientWidth), () => e.disconnect();
|
|
246
250
|
}, []);
|
|
247
|
-
const
|
|
248
|
-
if (
|
|
251
|
+
const ue = Ie(() => {
|
|
252
|
+
if (g || $ === 0 || z)
|
|
249
253
|
return;
|
|
250
254
|
const t = Math.round($ * 9 / 16);
|
|
251
|
-
return { height: Math.max(t,
|
|
252
|
-
}, [
|
|
253
|
-
const t =
|
|
255
|
+
return { height: Math.max(t, K) };
|
|
256
|
+
}, [g, $, K, z]), ye = () => {
|
|
257
|
+
const t = P.current || b.current;
|
|
254
258
|
if (t) {
|
|
255
259
|
if (document.fullscreenElement) {
|
|
256
260
|
document.exitFullscreen().catch(() => {
|
|
@@ -262,66 +266,66 @@ const $e = () => (K || (K = import("./blackboard-vendor.es.js").then(
|
|
|
262
266
|
}
|
|
263
267
|
};
|
|
264
268
|
m(() => {
|
|
265
|
-
const t =
|
|
269
|
+
const t = L.current;
|
|
266
270
|
if (!t) return;
|
|
267
271
|
t.render(
|
|
268
272
|
/* @__PURE__ */ E.jsx(
|
|
269
|
-
|
|
273
|
+
_e,
|
|
270
274
|
{
|
|
271
|
-
html:
|
|
272
|
-
styleLoadingText:
|
|
273
|
-
scriptLoadingText:
|
|
274
|
-
resetToken:
|
|
275
|
-
hasRootVhHeight:
|
|
275
|
+
html: j,
|
|
276
|
+
styleLoadingText: O,
|
|
277
|
+
scriptLoadingText: S,
|
|
278
|
+
resetToken: ne,
|
|
279
|
+
hasRootVhHeight: ce,
|
|
276
280
|
mode: d,
|
|
277
|
-
stretchRootHeight:
|
|
281
|
+
stretchRootHeight: oe
|
|
278
282
|
}
|
|
279
283
|
)
|
|
280
|
-
),
|
|
281
|
-
|
|
284
|
+
), y.current = window.requestAnimationFrame(() => {
|
|
285
|
+
R.current?.(), y.current = null;
|
|
282
286
|
});
|
|
283
|
-
const e = setTimeout(() =>
|
|
287
|
+
const e = setTimeout(() => R.current?.(), 100), c = setTimeout(() => R.current?.(), 500);
|
|
284
288
|
return () => {
|
|
285
|
-
clearTimeout(e), clearTimeout(
|
|
289
|
+
clearTimeout(e), clearTimeout(c);
|
|
286
290
|
};
|
|
287
291
|
}, [
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
+
j,
|
|
293
|
+
O,
|
|
294
|
+
S,
|
|
295
|
+
ne,
|
|
292
296
|
d
|
|
293
297
|
]);
|
|
294
|
-
const
|
|
298
|
+
const Te = [
|
|
295
299
|
"w-full relative content-render-iframe-sandbox",
|
|
296
|
-
|
|
300
|
+
g ? "h-full overflow-auto flex flex-col" : ue ? "overflow-hidden flex items-center justify-center" : "aspect-[16/9] overflow-hidden flex items-center justify-center"
|
|
297
301
|
].filter(Boolean).join(" ");
|
|
298
302
|
return /* @__PURE__ */ E.jsxs(
|
|
299
303
|
"div",
|
|
300
304
|
{
|
|
301
|
-
ref:
|
|
302
|
-
"data-root-vh":
|
|
303
|
-
className:
|
|
305
|
+
ref: P,
|
|
306
|
+
"data-root-vh": ce ? "true" : "false",
|
|
307
|
+
className: Te,
|
|
304
308
|
style: T ? {
|
|
305
309
|
height: T,
|
|
306
310
|
minHeight: T
|
|
307
|
-
} :
|
|
311
|
+
} : ue,
|
|
308
312
|
children: [
|
|
309
|
-
!
|
|
313
|
+
!V && /* @__PURE__ */ E.jsx(
|
|
310
314
|
"button",
|
|
311
315
|
{
|
|
312
316
|
type: "button",
|
|
313
|
-
onClick:
|
|
317
|
+
onClick: ye,
|
|
314
318
|
className: "absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer",
|
|
315
|
-
children:
|
|
319
|
+
children: z ? "退出全屏" : h || "全屏浏览"
|
|
316
320
|
}
|
|
317
321
|
),
|
|
318
|
-
d === "blackboard" &&
|
|
322
|
+
d === "blackboard" && o === "markdown" ? /* @__PURE__ */ E.jsx(
|
|
319
323
|
"div",
|
|
320
324
|
{
|
|
321
325
|
onMouseDown: () => H("mousedown"),
|
|
322
326
|
onPointerDown: () => H("pointerdown"),
|
|
323
327
|
onTouchStart: () => H("touchstart"),
|
|
324
|
-
children: /* @__PURE__ */ E.jsx(
|
|
328
|
+
children: /* @__PURE__ */ E.jsx(Oe, { content: s })
|
|
325
329
|
}
|
|
326
330
|
) : /* @__PURE__ */ E.jsx(
|
|
327
331
|
"iframe",
|
|
@@ -330,7 +334,7 @@ const $e = () => (K || (K = import("./blackboard-vendor.es.js").then(
|
|
|
330
334
|
sandbox: "allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox",
|
|
331
335
|
allow: "fullscreen",
|
|
332
336
|
allowFullScreen: !0,
|
|
333
|
-
className: [
|
|
337
|
+
className: [i, "w-full h-full mx-auto my-auto block"].filter(Boolean).join(" "),
|
|
334
338
|
style: {
|
|
335
339
|
height: T ?? "100%",
|
|
336
340
|
minHeight: T,
|
|
@@ -343,6 +347,6 @@ const $e = () => (K || (K = import("./blackboard-vendor.es.js").then(
|
|
|
343
347
|
);
|
|
344
348
|
};
|
|
345
349
|
export {
|
|
346
|
-
|
|
350
|
+
Qe as default
|
|
347
351
|
};
|
|
348
352
|
//# sourceMappingURL=IframeSandbox.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeSandbox.es.js","sources":["../../../src/components/ContentRender/IframeSandbox.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport SandboxApp from \"./SandboxApp\";\nimport ContentRender from \"./ContentRender\";\nimport {\n EMPTY_ROOT_HEIGHT_META,\n inspectViewportHeightFromHtmlRootString,\n inspectViewportHeightFromNodeChain,\n parseExplicitHeight,\n resolveExplicitHeightFromNodeChain,\n} from \"./utils/iframe-viewport-height\";\nimport {\n SANDBOX_INTERACTION_MESSAGE_SOURCE,\n SANDBOX_INTERACTION_MESSAGE_TYPE,\n} from \"../../lib/sandboxInteraction\";\n\ntype InjectBlackboardLibraries =\n typeof import(\"./blackboard-vendor\").injectBlackboardLibraries;\n\n// Cache the sandbox vendor loader so every iframe reuses the same preload request.\nlet blackboardVendorPromise: Promise<InjectBlackboardLibraries> | null = null;\n\nconst loadBlackboardVendor = () => {\n if (!blackboardVendorPromise) {\n blackboardVendorPromise = import(\"./blackboard-vendor\").then(\n (m) => m.injectBlackboardLibraries\n );\n }\n\n return blackboardVendorPromise;\n};\n\nconst COMPLETE_IMAGE_TAG_PATTERN = /<img\\b[^>]*>/i;\nconst POST_IMAGE_STREAM_DEBOUNCE_MS = 180;\nconst SANDBOX_INTERACTION_THROTTLE_MS = 240;\n\nexport interface IframeSandboxProps {\n content: string;\n className?: string;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n hideFullScreen?: boolean;\n mode?: \"content\" | \"blackboard\";\n type: \"sandbox\" | \"markdown\";\n replaceRootScreenHeightWithFull?: boolean;\n}\n\nconst replaceRootScreenHeightToken = (className: string) =>\n className\n .split(/\\s+/)\n .filter(Boolean)\n .map((token) => {\n const segments = token.split(\":\");\n if (\n segments[segments.length - 1] !== \"h-screen\" &&\n segments[segments.length - 1] !== \"min-h-screen\"\n ) {\n return token;\n }\n segments[segments.length - 1] = \"h-full\";\n return segments.join(\":\");\n })\n .join(\" \");\n\nconst replaceRootScreenHeightWithFullClass = (\n html: string,\n enabled: boolean\n) => {\n if (!enabled || !html.trim()) {\n return html;\n }\n\n return html.replace(\n /^(\\s*<[a-zA-Z][\\w:-]*)(\\s[^>]*?)?>/,\n (match, tagStart: string, attrs = \"\") => {\n const classMatch = attrs.match(/\\bclass\\s*=\\s*([\"'])([^\"']*)\\1/i);\n\n if (!classMatch) {\n return match;\n }\n\n const nextClassName = replaceRootScreenHeightToken(classMatch[2]);\n\n if (nextClassName === classMatch[2]) {\n return match;\n }\n\n return `${tagStart}${attrs.replace(\n classMatch[0],\n `class=${classMatch[1]}${nextClassName}${classMatch[1]}`\n )}>`;\n }\n );\n};\n\nconst IframeSandbox: React.FC<IframeSandboxProps> = ({\n content,\n type,\n className,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n replaceRootScreenHeightWithFull = false,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const rootRef = useRef<Root | null>(null);\n const updateHeightRef = useRef<() => void>(() => {});\n const [height, setHeight] = useState(480);\n const [contentHeight, setContentHeight] = useState(0);\n const [containerWidth, setContainerWidth] = useState(0);\n const lastSandboxInteractionTimeRef = useRef(0);\n const [resetToken, setResetToken] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const shouldInjectSandboxVendor = type === \"sandbox\";\n\n const isBlackboardMode = mode === \"blackboard\";\n const shouldMeasureDynamicHeight = isBlackboardMode && type === \"sandbox\";\n const shouldProcessRootScreenHeight =\n shouldMeasureDynamicHeight && replaceRootScreenHeightWithFull;\n const prevHtmlRef = useRef<string>(\"\");\n const htmlContent = React.useMemo(\n () => (type === \"sandbox\" ? content : \"\"),\n [content, type]\n );\n const normalizedHtmlContent = React.useMemo(\n () =>\n replaceRootScreenHeightWithFullClass(\n htmlContent,\n shouldProcessRootScreenHeight\n ),\n [htmlContent, shouldProcessRootScreenHeight]\n );\n const originalRootHeightMeta = React.useMemo(\n () =>\n shouldProcessRootScreenHeight\n ? inspectViewportHeightFromHtmlRootString(htmlContent)\n : EMPTY_ROOT_HEIGHT_META,\n [htmlContent, shouldProcessRootScreenHeight]\n );\n const shouldStretchRootHeight = React.useMemo(\n () =>\n shouldProcessRootScreenHeight &&\n originalRootHeightMeta.hasFullViewportHeight,\n [\n originalRootHeightMeta.hasFullViewportHeight,\n shouldProcessRootScreenHeight,\n ]\n );\n const [renderHtmlContent, setRenderHtmlContent] = useState(\n normalizedHtmlContent\n );\n const prevIncomingHtmlRef = useRef(normalizedHtmlContent);\n const pendingHtmlRef = useRef(normalizedHtmlContent);\n const deferRenderTimerRef = useRef<number | null>(null);\n const initialPaintFrameRef = useRef<number | null>(null);\n const renderViewportHeightCssRef = useRef<string | null>(null);\n\n const emitSandboxInteraction = useCallback((eventType: string) => {\n if (typeof window === \"undefined\") {\n return;\n }\n const now = Date.now();\n if (\n now - lastSandboxInteractionTimeRef.current <\n SANDBOX_INTERACTION_THROTTLE_MS\n ) {\n return;\n }\n lastSandboxInteractionTimeRef.current = now;\n window.postMessage(\n {\n source: SANDBOX_INTERACTION_MESSAGE_SOURCE,\n type: SANDBOX_INTERACTION_MESSAGE_TYPE,\n eventType,\n },\n window.location.origin\n );\n }, []);\n\n const clearDeferredRenderTimer = () => {\n if (deferRenderTimerRef.current === null) return;\n window.clearTimeout(deferRenderTimerRef.current);\n deferRenderTimerRef.current = null;\n };\n\n const clearInitialPaintFrames = () => {\n if (initialPaintFrameRef.current !== null) {\n window.cancelAnimationFrame(initialPaintFrameRef.current);\n initialPaintFrameRef.current = null;\n }\n };\n\n useEffect(\n () => () => {\n clearDeferredRenderTimer();\n clearInitialPaintFrames();\n },\n []\n );\n\n useEffect(() => {\n const prevIncomingHtml = prevIncomingHtmlRef.current;\n prevIncomingHtmlRef.current = normalizedHtmlContent;\n\n const isAppendOnlyStream =\n !!prevIncomingHtml &&\n normalizedHtmlContent.length > prevIncomingHtml.length &&\n normalizedHtmlContent.startsWith(prevIncomingHtml);\n const containsCompleteImage = COMPLETE_IMAGE_TAG_PATTERN.test(\n normalizedHtmlContent\n );\n const shouldDeferRender = isAppendOnlyStream && containsCompleteImage;\n\n if (!shouldDeferRender) {\n clearDeferredRenderTimer();\n pendingHtmlRef.current = normalizedHtmlContent;\n setRenderHtmlContent(normalizedHtmlContent);\n return;\n }\n\n pendingHtmlRef.current = normalizedHtmlContent;\n clearDeferredRenderTimer();\n deferRenderTimerRef.current = window.setTimeout(() => {\n setRenderHtmlContent(pendingHtmlRef.current);\n deferRenderTimerRef.current = null;\n }, POST_IMAGE_STREAM_DEBOUNCE_MS);\n }, [normalizedHtmlContent]);\n\n const rootViewportHeightCss = React.useMemo(() => {\n if (!shouldMeasureDynamicHeight) {\n return null;\n }\n\n return inspectViewportHeightFromHtmlRootString(renderHtmlContent)\n .viewportHeightCss;\n }, [renderHtmlContent, shouldMeasureDynamicHeight]);\n\n useEffect(() => {\n renderViewportHeightCssRef.current = rootViewportHeightCss;\n }, [rootViewportHeightCss]);\n\n const hasRootVhHeight = Boolean(rootViewportHeightCss);\n const sandboxViewportHeight =\n isBlackboardMode && type === \"sandbox\"\n ? shouldStretchRootHeight\n ? \"100%\"\n : (rootViewportHeightCss ?? `${height}px`)\n : undefined;\n useEffect(() => {\n if (mode !== \"blackboard\") {\n prevHtmlRef.current = normalizedHtmlContent;\n return;\n }\n const prev = prevHtmlRef.current;\n const isContinuation = prev && normalizedHtmlContent.startsWith(prev);\n if (!isContinuation && prev) {\n setResetToken((token) => token + 1);\n }\n prevHtmlRef.current = normalizedHtmlContent;\n }, [mode, normalizedHtmlContent]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return undefined;\n\n const doc = iframe.contentDocument;\n if (!doc) return undefined;\n\n doc.open();\n doc.write(`<!DOCTYPE html>\n<html${mode === \"blackboard\" ? ' style=\"height: 100%;\"' : \"\"}>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <style>\n :root { color-scheme: light; }\n html, body, #root { width: 100%; }\n ${mode === \"blackboard\" ? \"html, body, #root { height: 100%; }\" : \"\"}\n html, body { margin: 0; padding: 0; overflow: auto; }\n *, *::before, *::after { box-sizing: border-box; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n </body>\n</html>`);\n doc.close();\n\n // Force iframe theme to stay in light mode regardless of host OS preference.\n doc.documentElement.setAttribute(\"data-theme\", \"light\");\n doc.documentElement.style.colorScheme = \"light\";\n doc.body?.style.setProperty(\"color-scheme\", \"light\");\n\n const shouldBridgeSandboxInteraction =\n isBlackboardMode && type === \"sandbox\";\n const handleSandboxPointerDown = () =>\n emitSandboxInteraction(\"pointerdown\");\n const handleSandboxMouseDown = () => emitSandboxInteraction(\"mousedown\");\n const handleSandboxTouchStart = () => emitSandboxInteraction(\"touchstart\");\n\n if (shouldBridgeSandboxInteraction) {\n doc.addEventListener(\"pointerdown\", handleSandboxPointerDown, true);\n doc.addEventListener(\"mousedown\", handleSandboxMouseDown, true);\n doc.addEventListener(\"touchstart\", handleSandboxTouchStart, true);\n }\n\n const rootEl = doc.getElementById(\"root\");\n if (!rootEl) return undefined;\n\n const root = createRoot(rootEl);\n rootRef.current = root;\n let isDestroyed = false;\n const getHeightInspectionNode = (node: HTMLElement) => ({\n heightAttrValue: node.getAttribute(\"height\"),\n styleAttrValue: node.getAttribute(\"style\"),\n classAttrValue: node.getAttribute(\"class\"),\n });\n const getSingleChildElement = (node: HTMLElement) => {\n const childElements = Array.from(node.children) as HTMLElement[];\n\n return childElements.length === 1 ? childElements[0] : null;\n };\n\n const resolveExplicitHeight = () => {\n if (!shouldMeasureDynamicHeight) return null;\n if (!iframeRef.current || !doc.body) return null;\n const parentViewportHeight =\n iframeRef.current.ownerDocument?.documentElement?.clientHeight ||\n window.innerHeight;\n // Reuse parsed height metadata from the current html snapshot first to\n // avoid re-inspecting the same DOM chain on every height tick.\n const precomputedViewportHeightCss = renderViewportHeightCssRef.current;\n const parsed = precomputedViewportHeightCss\n ? parseExplicitHeight(\n precomputedViewportHeightCss,\n parentViewportHeight\n )\n : null;\n\n if (parsed !== null) {\n return Math.ceil(parsed);\n }\n\n const wrapper = doc.body.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const container = wrapper?.firstElementChild as HTMLElement | null;\n if (!container) return null;\n const containerChildren = Array.from(container.children) as HTMLElement[];\n const rootContentElement =\n containerChildren.length === 1 ? containerChildren[0] : null;\n const runtimeHeightMeta = inspectViewportHeightFromNodeChain(\n rootContentElement,\n {\n getNode: getHeightInspectionNode,\n getSingleChild: getSingleChildElement,\n }\n );\n const runtimeViewportHeightCss = runtimeHeightMeta.viewportHeightCss;\n\n if (runtimeViewportHeightCss) {\n const runtimeViewportHeight = parseExplicitHeight(\n runtimeViewportHeightCss,\n parentViewportHeight\n );\n\n if (runtimeViewportHeight !== null) {\n return Math.ceil(runtimeViewportHeight);\n }\n }\n\n const explicitPixelHeight = resolveExplicitHeightFromNodeChain(\n rootContentElement,\n parentViewportHeight,\n {\n getNode: getHeightInspectionNode,\n getSingleChild: getSingleChildElement,\n }\n );\n\n return explicitPixelHeight !== null\n ? Math.ceil(explicitPixelHeight)\n : null;\n };\n\n const updateHeight = () => {\n if (!iframeRef.current || !doc.body) return;\n\n if (!isBlackboardMode) {\n // Content mode: neutralize percentage/vh heights on the wrapper\n // chain before measuring so that elements with height:100% don't\n // inflate scrollHeight, while preserving vh-based content layout\n // at a stable reference size (the 16:9 minimum).\n const wrapper = doc.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const prevWrapperH = wrapper?.style.height ?? \"\";\n const prevBodyH = doc.body.style.height;\n const prevHtmlH = doc.documentElement.style.height;\n\n if (wrapper) wrapper.style.height = \"auto\";\n doc.body.style.height = \"auto\";\n doc.documentElement.style.height = \"auto\";\n\n const bodyScrollH = doc.body.scrollHeight;\n const htmlScrollH = doc.documentElement?.scrollHeight || 0;\n const rootScrollH = rootEl?.scrollHeight || 0;\n const measuredHeight = Math.max(bodyScrollH, htmlScrollH, rootScrollH);\n\n // Restore immediately (synchronous, no paint in between)\n if (wrapper) wrapper.style.height = prevWrapperH;\n doc.body.style.height = prevBodyH;\n doc.documentElement.style.height = prevHtmlH;\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredHeight));\n return prev === next ? prev : next;\n });\n return;\n }\n\n // Blackboard mode: use existing explicit height resolution logic\n const bodyScrollH = doc.body.scrollHeight;\n const htmlScrollH = doc.documentElement?.scrollHeight || 0;\n const rootScrollH = rootEl?.scrollHeight || 0;\n const measuredHeight = Math.max(bodyScrollH, htmlScrollH, rootScrollH);\n\n if (shouldMeasureDynamicHeight) {\n const explicitHeight = resolveExplicitHeight();\n const nextHeight = Math.max(\n 200,\n explicitHeight ?? Math.ceil(measuredHeight)\n );\n setHeight((prevHeight) =>\n prevHeight === nextHeight ? prevHeight : nextHeight\n );\n }\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredHeight));\n return prev === next ? prev : next;\n });\n };\n const scheduleHeightUpdate = () => {\n requestAnimationFrame(() => {\n if (isDestroyed) return;\n updateHeight();\n });\n };\n updateHeightRef.current = scheduleHeightUpdate;\n\n updateHeight();\n scheduleHeightUpdate();\n\n if (shouldInjectSandboxVendor) {\n // Inject Tailwind/DaisyUI/GSAP before rendering sandbox content to avoid FOUC.\n loadBlackboardVendor()\n .then((inject) => {\n if (isDestroyed) return;\n inject(doc);\n requestAnimationFrame(() => {\n if (isDestroyed) return;\n scheduleHeightUpdate();\n });\n })\n .catch(() => {\n if (isDestroyed) return;\n scheduleHeightUpdate();\n });\n }\n\n const resizeObserver = new ResizeObserver(() => updateHeight());\n resizeObserver.observe(doc.body);\n if (rootEl) {\n resizeObserver.observe(rootEl);\n }\n\n // MutationObserver: detect DOM changes that ResizeObserver might miss\n // (e.g. content injected by scripts, images loading, dynamic rendering)\n const mutationObserver = new MutationObserver(() => {\n scheduleHeightUpdate();\n });\n mutationObserver.observe(doc.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"style\", \"class\"],\n });\n\n return () => {\n isDestroyed = true;\n resizeObserver.disconnect();\n mutationObserver.disconnect();\n if (shouldBridgeSandboxInteraction) {\n doc.removeEventListener(\"pointerdown\", handleSandboxPointerDown, true);\n doc.removeEventListener(\"mousedown\", handleSandboxMouseDown, true);\n doc.removeEventListener(\"touchstart\", handleSandboxTouchStart, true);\n }\n // Defer unmount to avoid React warning when parent is mid-render\n setTimeout(() => {\n root.unmount();\n rootRef.current = null;\n updateHeightRef.current = () => {};\n }, 0);\n };\n }, []);\n\n useEffect(() => {\n const onFullscreenChange = () => {\n setIsFullscreen(Boolean(document.fullscreenElement));\n };\n document.addEventListener(\"fullscreenchange\", onFullscreenChange);\n return () =>\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange);\n }, []);\n\n // Track container width for computing min-height in content mode\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const ro = new ResizeObserver((entries) => {\n setContainerWidth(entries[0]?.contentRect.width ?? el.clientWidth);\n });\n ro.observe(el);\n setContainerWidth(el.clientWidth);\n return () => ro.disconnect();\n }, []);\n\n // Content mode: min 16:9 aspect ratio, grow to fit content (no scrollbar)\n const contentModeStyle = useMemo<React.CSSProperties | undefined>(() => {\n if (isBlackboardMode || containerWidth === 0 || isFullscreen)\n return undefined;\n const minH = Math.round((containerWidth * 9) / 16);\n const h = Math.max(minH, contentHeight);\n return { height: h };\n }, [isBlackboardMode, containerWidth, contentHeight, isFullscreen]);\n\n const toggleFullscreen = () => {\n const target = containerRef.current || iframeRef.current;\n if (!target) return;\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n return;\n }\n if (target.requestFullscreen) {\n target.requestFullscreen().catch(() => {});\n }\n };\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n root.render(\n <SandboxApp\n html={renderHtmlContent}\n styleLoadingText={styleLoadingText}\n scriptLoadingText={scriptLoadingText}\n resetToken={resetToken}\n hasRootVhHeight={hasRootVhHeight}\n mode={mode}\n stretchRootHeight={shouldStretchRootHeight}\n />\n );\n\n // Schedule multiple measurements to catch async content (scripts, images, styles).\n initialPaintFrameRef.current = window.requestAnimationFrame(() => {\n updateHeightRef.current?.();\n initialPaintFrameRef.current = null;\n });\n const t1 = setTimeout(() => updateHeightRef.current?.(), 100);\n const t2 = setTimeout(() => updateHeightRef.current?.(), 500);\n return () => {\n clearTimeout(t1);\n clearTimeout(t2);\n };\n }, [\n renderHtmlContent,\n styleLoadingText,\n scriptLoadingText,\n resetToken,\n mode,\n ]);\n const containerClassName = [\n \"w-full relative content-render-iframe-sandbox\",\n isBlackboardMode\n ? \"h-full overflow-auto flex flex-col\"\n : contentModeStyle\n ? \"overflow-hidden flex items-center justify-center\"\n : \"aspect-[16/9] overflow-hidden flex items-center justify-center\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n ref={containerRef}\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className={containerClassName}\n style={\n sandboxViewportHeight\n ? {\n height: sandboxViewportHeight,\n minHeight: sandboxViewportHeight,\n }\n : contentModeStyle\n }\n >\n {!hideFullScreen && (\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className={\n \"absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer\"\n }\n >\n {isFullscreen ? \"退出全屏\" : fullScreenButtonText || \"全屏浏览\"}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <div\n onMouseDown={() => emitSandboxInteraction(\"mousedown\")}\n onPointerDown={() => emitSandboxInteraction(\"pointerdown\")}\n onTouchStart={() => emitSandboxInteraction(\"touchstart\")}\n >\n <ContentRender content={content} />\n </div>\n ) : (\n <iframe\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n allow=\"fullscreen\"\n allowFullScreen\n className={[className, \"w-full h-full mx-auto my-auto block\"]\n .filter(Boolean)\n .join(\" \")}\n style={{\n height: sandboxViewportHeight ?? \"100%\",\n minHeight: sandboxViewportHeight,\n margin: \"auto\",\n }}\n />\n )}\n </div>\n );\n};\n\nexport default IframeSandbox;\n"],"names":["blackboardVendorPromise","loadBlackboardVendor","m","COMPLETE_IMAGE_TAG_PATTERN","POST_IMAGE_STREAM_DEBOUNCE_MS","SANDBOX_INTERACTION_THROTTLE_MS","replaceRootScreenHeightToken","className","token","segments","replaceRootScreenHeightWithFullClass","html","enabled","match","tagStart","attrs","classMatch","nextClassName","IframeSandbox","content","type","styleLoadingText","scriptLoadingText","fullScreenButtonText","hideFullScreen","mode","replaceRootScreenHeightWithFull","containerRef","useRef","iframeRef","rootRef","updateHeightRef","height","setHeight","useState","contentHeight","setContentHeight","containerWidth","setContainerWidth","lastSandboxInteractionTimeRef","resetToken","setResetToken","isFullscreen","setIsFullscreen","shouldInjectSandboxVendor","isBlackboardMode","shouldMeasureDynamicHeight","shouldProcessRootScreenHeight","prevHtmlRef","htmlContent","React","normalizedHtmlContent","originalRootHeightMeta","inspectViewportHeightFromHtmlRootString","EMPTY_ROOT_HEIGHT_META","shouldStretchRootHeight","renderHtmlContent","setRenderHtmlContent","prevIncomingHtmlRef","pendingHtmlRef","deferRenderTimerRef","initialPaintFrameRef","renderViewportHeightCssRef","emitSandboxInteraction","useCallback","eventType","now","SANDBOX_INTERACTION_MESSAGE_SOURCE","SANDBOX_INTERACTION_MESSAGE_TYPE","clearDeferredRenderTimer","clearInitialPaintFrames","useEffect","prevIncomingHtml","isAppendOnlyStream","containsCompleteImage","rootViewportHeightCss","hasRootVhHeight","sandboxViewportHeight","prev","iframe","doc","shouldBridgeSandboxInteraction","handleSandboxPointerDown","handleSandboxMouseDown","handleSandboxTouchStart","rootEl","root","createRoot","isDestroyed","getHeightInspectionNode","node","getSingleChildElement","childElements","resolveExplicitHeight","parentViewportHeight","precomputedViewportHeightCss","parsed","parseExplicitHeight","container","containerChildren","rootContentElement","runtimeViewportHeightCss","inspectViewportHeightFromNodeChain","runtimeViewportHeight","explicitPixelHeight","resolveExplicitHeightFromNodeChain","updateHeight","wrapper","prevWrapperH","prevBodyH","prevHtmlH","bodyScrollH","htmlScrollH","rootScrollH","measuredHeight","next","explicitHeight","nextHeight","prevHeight","scheduleHeightUpdate","inject","resizeObserver","mutationObserver","onFullscreenChange","el","ro","entries","contentModeStyle","useMemo","minH","toggleFullscreen","target","jsx","SandboxApp","t1","t2","containerClassName","jsxs","ContentRender"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"IframeSandbox.es.js","sources":["../../../src/components/ContentRender/IframeSandbox.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport SandboxApp from \"./SandboxApp\";\nimport ContentRender from \"./ContentRender\";\nimport {\n EMPTY_ROOT_HEIGHT_META,\n inspectViewportHeightFromHtmlRootString,\n inspectViewportHeightFromNodeChain,\n parseExplicitHeight,\n resolveExplicitHeightFromNodeChain,\n} from \"./utils/iframe-viewport-height\";\nimport {\n SANDBOX_INTERACTION_MESSAGE_SOURCE,\n SANDBOX_INTERACTION_MESSAGE_TYPE,\n} from \"../../lib/sandboxInteraction\";\n\ntype InjectBlackboardLibraries =\n typeof import(\"./blackboard-vendor\").injectBlackboardLibraries;\n\n// Cache the sandbox vendor loader so every iframe reuses the same preload request.\nlet blackboardVendorPromise: Promise<InjectBlackboardLibraries> | null = null;\n\nconst loadBlackboardVendor = () => {\n if (!blackboardVendorPromise) {\n blackboardVendorPromise = import(\"./blackboard-vendor\").then(\n (m) => m.injectBlackboardLibraries\n );\n }\n\n return blackboardVendorPromise;\n};\n\nconst COMPLETE_IMAGE_TAG_PATTERN = /<img\\b[^>]*>/i;\nconst POST_IMAGE_STREAM_DEBOUNCE_MS = 180;\nconst SANDBOX_INTERACTION_THROTTLE_MS = 240;\n\nexport interface IframeSandboxProps {\n content: string;\n className?: string;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n hideFullScreen?: boolean;\n mode?: \"content\" | \"blackboard\";\n type: \"sandbox\" | \"markdown\";\n replaceRootScreenHeightWithFull?: boolean;\n}\n\nconst replaceRootScreenHeightToken = (className: string) =>\n className\n .split(/\\s+/)\n .filter(Boolean)\n .map((token) => {\n const segments = token.split(\":\");\n if (\n segments[segments.length - 1] !== \"h-screen\" &&\n segments[segments.length - 1] !== \"min-h-screen\"\n ) {\n return token;\n }\n segments[segments.length - 1] = \"h-full\";\n return segments.join(\":\");\n })\n .join(\" \");\n\nconst replaceRootScreenHeightWithFullClass = (\n html: string,\n enabled: boolean\n) => {\n if (!enabled || !html.trim()) {\n return html;\n }\n\n return html.replace(\n /^(\\s*<[a-zA-Z][\\w:-]*)(\\s[^>]*?)?>/,\n (match, tagStart: string, attrs = \"\") => {\n const classMatch = attrs.match(/\\bclass\\s*=\\s*([\"'])([^\"']*)\\1/i);\n\n if (!classMatch) {\n return match;\n }\n\n const nextClassName = replaceRootScreenHeightToken(classMatch[2]);\n\n if (nextClassName === classMatch[2]) {\n return match;\n }\n\n return `${tagStart}${attrs.replace(\n classMatch[0],\n `class=${classMatch[1]}${nextClassName}${classMatch[1]}`\n )}>`;\n }\n );\n};\n\nconst IframeSandbox: React.FC<IframeSandboxProps> = ({\n content,\n type,\n className,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n replaceRootScreenHeightWithFull = false,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const rootRef = useRef<Root | null>(null);\n const updateHeightRef = useRef<() => void>(() => {});\n const [height, setHeight] = useState(480);\n const [contentHeight, setContentHeight] = useState(0);\n const [containerWidth, setContainerWidth] = useState(0);\n const lastSandboxInteractionTimeRef = useRef(0);\n const [resetToken, setResetToken] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const shouldInjectSandboxVendor = type === \"sandbox\";\n\n const isBlackboardMode = mode === \"blackboard\";\n const shouldMeasureDynamicHeight = isBlackboardMode && type === \"sandbox\";\n const shouldProcessRootScreenHeight =\n shouldMeasureDynamicHeight && replaceRootScreenHeightWithFull;\n const prevHtmlRef = useRef<string>(\"\");\n const htmlContent = React.useMemo(\n () => (type === \"sandbox\" ? content : \"\"),\n [content, type]\n );\n const normalizedHtmlContent = React.useMemo(\n () =>\n replaceRootScreenHeightWithFullClass(\n htmlContent,\n shouldProcessRootScreenHeight\n ),\n [htmlContent, shouldProcessRootScreenHeight]\n );\n const originalRootHeightMeta = React.useMemo(\n () =>\n shouldProcessRootScreenHeight\n ? inspectViewportHeightFromHtmlRootString(htmlContent)\n : EMPTY_ROOT_HEIGHT_META,\n [htmlContent, shouldProcessRootScreenHeight]\n );\n const shouldStretchRootHeight = React.useMemo(\n () =>\n shouldProcessRootScreenHeight &&\n originalRootHeightMeta.hasFullViewportHeight,\n [\n originalRootHeightMeta.hasFullViewportHeight,\n shouldProcessRootScreenHeight,\n ]\n );\n const [renderHtmlContent, setRenderHtmlContent] = useState(\n normalizedHtmlContent\n );\n const prevIncomingHtmlRef = useRef(normalizedHtmlContent);\n const pendingHtmlRef = useRef(normalizedHtmlContent);\n const deferRenderTimerRef = useRef<number | null>(null);\n const initialPaintFrameRef = useRef<number | null>(null);\n const renderViewportHeightCssRef = useRef<string | null>(null);\n\n const emitSandboxInteraction = useCallback((eventType: string) => {\n if (typeof window === \"undefined\") {\n return;\n }\n const now = Date.now();\n if (\n now - lastSandboxInteractionTimeRef.current <\n SANDBOX_INTERACTION_THROTTLE_MS\n ) {\n return;\n }\n lastSandboxInteractionTimeRef.current = now;\n window.postMessage(\n {\n source: SANDBOX_INTERACTION_MESSAGE_SOURCE,\n type: SANDBOX_INTERACTION_MESSAGE_TYPE,\n eventType,\n },\n window.location.origin\n );\n }, []);\n\n const clearDeferredRenderTimer = () => {\n if (deferRenderTimerRef.current === null) return;\n window.clearTimeout(deferRenderTimerRef.current);\n deferRenderTimerRef.current = null;\n };\n\n const clearInitialPaintFrames = () => {\n if (initialPaintFrameRef.current !== null) {\n window.cancelAnimationFrame(initialPaintFrameRef.current);\n initialPaintFrameRef.current = null;\n }\n };\n\n useEffect(\n () => () => {\n clearDeferredRenderTimer();\n clearInitialPaintFrames();\n },\n []\n );\n\n useEffect(() => {\n const prevIncomingHtml = prevIncomingHtmlRef.current;\n prevIncomingHtmlRef.current = normalizedHtmlContent;\n\n const isAppendOnlyStream =\n !!prevIncomingHtml &&\n normalizedHtmlContent.length > prevIncomingHtml.length &&\n normalizedHtmlContent.startsWith(prevIncomingHtml);\n const containsCompleteImage = COMPLETE_IMAGE_TAG_PATTERN.test(\n normalizedHtmlContent\n );\n const shouldDeferRender = isAppendOnlyStream && containsCompleteImage;\n\n if (!shouldDeferRender) {\n clearDeferredRenderTimer();\n pendingHtmlRef.current = normalizedHtmlContent;\n setRenderHtmlContent(normalizedHtmlContent);\n return;\n }\n\n pendingHtmlRef.current = normalizedHtmlContent;\n clearDeferredRenderTimer();\n deferRenderTimerRef.current = window.setTimeout(() => {\n setRenderHtmlContent(pendingHtmlRef.current);\n deferRenderTimerRef.current = null;\n }, POST_IMAGE_STREAM_DEBOUNCE_MS);\n }, [normalizedHtmlContent]);\n\n const rootViewportHeightCss = React.useMemo(() => {\n if (!shouldMeasureDynamicHeight) {\n return null;\n }\n\n return inspectViewportHeightFromHtmlRootString(renderHtmlContent)\n .viewportHeightCss;\n }, [renderHtmlContent, shouldMeasureDynamicHeight]);\n\n useEffect(() => {\n renderViewportHeightCssRef.current = rootViewportHeightCss;\n }, [rootViewportHeightCss]);\n\n const hasRootVhHeight = Boolean(rootViewportHeightCss);\n const sandboxViewportHeight =\n isBlackboardMode && type === \"sandbox\"\n ? shouldStretchRootHeight\n ? \"100%\"\n : (rootViewportHeightCss ?? `${height}px`)\n : undefined;\n useEffect(() => {\n if (mode !== \"blackboard\") {\n prevHtmlRef.current = normalizedHtmlContent;\n return;\n }\n const prev = prevHtmlRef.current;\n const isContinuation = prev && normalizedHtmlContent.startsWith(prev);\n if (!isContinuation && prev) {\n setResetToken((token) => token + 1);\n }\n prevHtmlRef.current = normalizedHtmlContent;\n }, [mode, normalizedHtmlContent]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return undefined;\n\n const doc = iframe.contentDocument;\n if (!doc) return undefined;\n\n doc.open();\n doc.write(`<!DOCTYPE html>\n<html${mode === \"blackboard\" ? ' style=\"height: 100%;\"' : \"\"}>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <style>\n :root { color-scheme: light; }\n html, body, #root { width: 100%; }\n ${mode === \"blackboard\" ? \"html, body, #root { height: 100%; }\" : \"\"}\n html, body { margin: 0; padding: 0; overflow: auto; }\n *, *::before, *::after { box-sizing: border-box; }\n html.measuring-height, html.measuring-height body,\n html.measuring-height #root, html.measuring-height .sandbox-wrapper {\n height: auto !important; min-height: 0 !important;\n }\n html.measuring-height * {\n min-height: 0 !important;\n }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n </body>\n</html>`);\n doc.close();\n\n // Force iframe theme to stay in light mode regardless of host OS preference.\n doc.documentElement.setAttribute(\"data-theme\", \"light\");\n doc.documentElement.style.colorScheme = \"light\";\n doc.body?.style.setProperty(\"color-scheme\", \"light\");\n\n const shouldBridgeSandboxInteraction =\n isBlackboardMode && type === \"sandbox\";\n const handleSandboxPointerDown = () =>\n emitSandboxInteraction(\"pointerdown\");\n const handleSandboxMouseDown = () => emitSandboxInteraction(\"mousedown\");\n const handleSandboxTouchStart = () => emitSandboxInteraction(\"touchstart\");\n\n if (shouldBridgeSandboxInteraction) {\n doc.addEventListener(\"pointerdown\", handleSandboxPointerDown, true);\n doc.addEventListener(\"mousedown\", handleSandboxMouseDown, true);\n doc.addEventListener(\"touchstart\", handleSandboxTouchStart, true);\n }\n\n const rootEl = doc.getElementById(\"root\");\n if (!rootEl) return undefined;\n\n const root = createRoot(rootEl);\n rootRef.current = root;\n let isDestroyed = false;\n const getHeightInspectionNode = (node: HTMLElement) => ({\n heightAttrValue: node.getAttribute(\"height\"),\n styleAttrValue: node.getAttribute(\"style\"),\n classAttrValue: node.getAttribute(\"class\"),\n });\n const getSingleChildElement = (node: HTMLElement) => {\n const childElements = Array.from(node.children) as HTMLElement[];\n\n return childElements.length === 1 ? childElements[0] : null;\n };\n\n const resolveExplicitHeight = () => {\n if (!shouldMeasureDynamicHeight) return null;\n if (!iframeRef.current || !doc.body) return null;\n const parentViewportHeight =\n iframeRef.current.ownerDocument?.documentElement?.clientHeight ||\n window.innerHeight;\n // Reuse parsed height metadata from the current html snapshot first to\n // avoid re-inspecting the same DOM chain on every height tick.\n const precomputedViewportHeightCss = renderViewportHeightCssRef.current;\n const parsed = precomputedViewportHeightCss\n ? parseExplicitHeight(\n precomputedViewportHeightCss,\n parentViewportHeight\n )\n : null;\n\n if (parsed !== null) {\n return Math.ceil(parsed);\n }\n\n const wrapper = doc.body.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const container = wrapper?.firstElementChild as HTMLElement | null;\n if (!container) return null;\n const containerChildren = Array.from(container.children) as HTMLElement[];\n const rootContentElement =\n containerChildren.length === 1 ? containerChildren[0] : null;\n const runtimeHeightMeta = inspectViewportHeightFromNodeChain(\n rootContentElement,\n {\n getNode: getHeightInspectionNode,\n getSingleChild: getSingleChildElement,\n }\n );\n const runtimeViewportHeightCss = runtimeHeightMeta.viewportHeightCss;\n\n if (runtimeViewportHeightCss) {\n const runtimeViewportHeight = parseExplicitHeight(\n runtimeViewportHeightCss,\n parentViewportHeight\n );\n\n if (runtimeViewportHeight !== null) {\n return Math.ceil(runtimeViewportHeight);\n }\n }\n\n const explicitPixelHeight = resolveExplicitHeightFromNodeChain(\n rootContentElement,\n parentViewportHeight,\n {\n getNode: getHeightInspectionNode,\n getSingleChild: getSingleChildElement,\n }\n );\n\n return explicitPixelHeight !== null\n ? Math.ceil(explicitPixelHeight)\n : null;\n };\n\n const updateHeight = () => {\n if (!iframeRef.current || !doc.body) return;\n\n if (!isBlackboardMode) {\n // Content mode: toggle a CSS class on <html> to neutralize\n // height:100% / min-h-screen on wrapper chain during measurement.\n // Using <html> class avoids triggering MutationObserver (which\n // only observes doc.body and its descendants).\n doc.documentElement.classList.add(\"measuring-height\");\n\n const bodyScrollH = doc.body.scrollHeight;\n const htmlScrollH = doc.documentElement?.scrollHeight || 0;\n const rootScrollH = rootEl?.scrollHeight || 0;\n const measuredHeight = Math.max(bodyScrollH, htmlScrollH, rootScrollH);\n\n doc.documentElement.classList.remove(\"measuring-height\");\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredHeight));\n return prev === next ? prev : next;\n });\n return;\n }\n\n // Blackboard mode: use existing explicit height resolution logic\n const bodyScrollH = doc.body.scrollHeight;\n const htmlScrollH = doc.documentElement?.scrollHeight || 0;\n const rootScrollH = rootEl?.scrollHeight || 0;\n const measuredHeight = Math.max(bodyScrollH, htmlScrollH, rootScrollH);\n\n if (shouldMeasureDynamicHeight) {\n const explicitHeight = resolveExplicitHeight();\n const nextHeight = Math.max(\n 200,\n explicitHeight ?? Math.ceil(measuredHeight)\n );\n setHeight((prevHeight) =>\n prevHeight === nextHeight ? prevHeight : nextHeight\n );\n }\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredHeight));\n return prev === next ? prev : next;\n });\n };\n const scheduleHeightUpdate = () => {\n requestAnimationFrame(() => {\n if (isDestroyed) return;\n updateHeight();\n });\n };\n updateHeightRef.current = scheduleHeightUpdate;\n\n updateHeight();\n scheduleHeightUpdate();\n\n if (shouldInjectSandboxVendor) {\n // Inject Tailwind/DaisyUI/GSAP before rendering sandbox content to avoid FOUC.\n loadBlackboardVendor()\n .then((inject) => {\n if (isDestroyed) return;\n inject(doc);\n requestAnimationFrame(() => {\n if (isDestroyed) return;\n scheduleHeightUpdate();\n });\n })\n .catch(() => {\n if (isDestroyed) return;\n scheduleHeightUpdate();\n });\n }\n\n const resizeObserver = new ResizeObserver(() => updateHeight());\n resizeObserver.observe(doc.body);\n if (rootEl) {\n resizeObserver.observe(rootEl);\n }\n\n // MutationObserver: detect DOM changes that ResizeObserver might miss\n // (e.g. content injected by scripts, images loading, dynamic rendering)\n const mutationObserver = new MutationObserver(() => {\n scheduleHeightUpdate();\n });\n mutationObserver.observe(doc.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"style\", \"class\"],\n });\n\n return () => {\n isDestroyed = true;\n resizeObserver.disconnect();\n mutationObserver.disconnect();\n if (shouldBridgeSandboxInteraction) {\n doc.removeEventListener(\"pointerdown\", handleSandboxPointerDown, true);\n doc.removeEventListener(\"mousedown\", handleSandboxMouseDown, true);\n doc.removeEventListener(\"touchstart\", handleSandboxTouchStart, true);\n }\n // Defer unmount to avoid React warning when parent is mid-render\n setTimeout(() => {\n root.unmount();\n rootRef.current = null;\n updateHeightRef.current = () => {};\n }, 0);\n };\n }, []);\n\n useEffect(() => {\n const onFullscreenChange = () => {\n setIsFullscreen(Boolean(document.fullscreenElement));\n };\n document.addEventListener(\"fullscreenchange\", onFullscreenChange);\n return () =>\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange);\n }, []);\n\n // Track container width for computing min-height in content mode\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const ro = new ResizeObserver((entries) => {\n setContainerWidth(entries[0]?.contentRect.width ?? el.clientWidth);\n });\n ro.observe(el);\n setContainerWidth(el.clientWidth);\n return () => ro.disconnect();\n }, []);\n\n // Content mode: min 16:9 aspect ratio, grow to fit content (no scrollbar)\n const contentModeStyle = useMemo<React.CSSProperties | undefined>(() => {\n if (isBlackboardMode || containerWidth === 0 || isFullscreen)\n return undefined;\n const minH = Math.round((containerWidth * 9) / 16);\n const h = Math.max(minH, contentHeight);\n return { height: h };\n }, [isBlackboardMode, containerWidth, contentHeight, isFullscreen]);\n\n const toggleFullscreen = () => {\n const target = containerRef.current || iframeRef.current;\n if (!target) return;\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n return;\n }\n if (target.requestFullscreen) {\n target.requestFullscreen().catch(() => {});\n }\n };\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n root.render(\n <SandboxApp\n html={renderHtmlContent}\n styleLoadingText={styleLoadingText}\n scriptLoadingText={scriptLoadingText}\n resetToken={resetToken}\n hasRootVhHeight={hasRootVhHeight}\n mode={mode}\n stretchRootHeight={shouldStretchRootHeight}\n />\n );\n\n // Schedule multiple measurements to catch async content (scripts, images, styles).\n initialPaintFrameRef.current = window.requestAnimationFrame(() => {\n updateHeightRef.current?.();\n initialPaintFrameRef.current = null;\n });\n const t1 = setTimeout(() => updateHeightRef.current?.(), 100);\n const t2 = setTimeout(() => updateHeightRef.current?.(), 500);\n return () => {\n clearTimeout(t1);\n clearTimeout(t2);\n };\n }, [\n renderHtmlContent,\n styleLoadingText,\n scriptLoadingText,\n resetToken,\n mode,\n ]);\n const containerClassName = [\n \"w-full relative content-render-iframe-sandbox\",\n isBlackboardMode\n ? \"h-full overflow-auto flex flex-col\"\n : contentModeStyle\n ? \"overflow-hidden flex items-center justify-center\"\n : \"aspect-[16/9] overflow-hidden flex items-center justify-center\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n ref={containerRef}\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className={containerClassName}\n style={\n sandboxViewportHeight\n ? {\n height: sandboxViewportHeight,\n minHeight: sandboxViewportHeight,\n }\n : contentModeStyle\n }\n >\n {!hideFullScreen && (\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className={\n \"absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer\"\n }\n >\n {isFullscreen ? \"退出全屏\" : fullScreenButtonText || \"全屏浏览\"}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <div\n onMouseDown={() => emitSandboxInteraction(\"mousedown\")}\n onPointerDown={() => emitSandboxInteraction(\"pointerdown\")}\n onTouchStart={() => emitSandboxInteraction(\"touchstart\")}\n >\n <ContentRender content={content} />\n </div>\n ) : (\n <iframe\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n allow=\"fullscreen\"\n allowFullScreen\n className={[className, \"w-full h-full mx-auto my-auto block\"]\n .filter(Boolean)\n .join(\" \")}\n style={{\n height: sandboxViewportHeight ?? \"100%\",\n minHeight: sandboxViewportHeight,\n margin: \"auto\",\n }}\n />\n )}\n </div>\n );\n};\n\nexport default IframeSandbox;\n"],"names":["blackboardVendorPromise","loadBlackboardVendor","m","COMPLETE_IMAGE_TAG_PATTERN","POST_IMAGE_STREAM_DEBOUNCE_MS","SANDBOX_INTERACTION_THROTTLE_MS","replaceRootScreenHeightToken","className","token","segments","replaceRootScreenHeightWithFullClass","html","enabled","match","tagStart","attrs","classMatch","nextClassName","IframeSandbox","content","type","styleLoadingText","scriptLoadingText","fullScreenButtonText","hideFullScreen","mode","replaceRootScreenHeightWithFull","containerRef","useRef","iframeRef","rootRef","updateHeightRef","height","setHeight","useState","contentHeight","setContentHeight","containerWidth","setContainerWidth","lastSandboxInteractionTimeRef","resetToken","setResetToken","isFullscreen","setIsFullscreen","shouldInjectSandboxVendor","isBlackboardMode","shouldMeasureDynamicHeight","shouldProcessRootScreenHeight","prevHtmlRef","htmlContent","React","normalizedHtmlContent","originalRootHeightMeta","inspectViewportHeightFromHtmlRootString","EMPTY_ROOT_HEIGHT_META","shouldStretchRootHeight","renderHtmlContent","setRenderHtmlContent","prevIncomingHtmlRef","pendingHtmlRef","deferRenderTimerRef","initialPaintFrameRef","renderViewportHeightCssRef","emitSandboxInteraction","useCallback","eventType","now","SANDBOX_INTERACTION_MESSAGE_SOURCE","SANDBOX_INTERACTION_MESSAGE_TYPE","clearDeferredRenderTimer","clearInitialPaintFrames","useEffect","prevIncomingHtml","isAppendOnlyStream","containsCompleteImage","rootViewportHeightCss","hasRootVhHeight","sandboxViewportHeight","prev","iframe","doc","shouldBridgeSandboxInteraction","handleSandboxPointerDown","handleSandboxMouseDown","handleSandboxTouchStart","rootEl","root","createRoot","isDestroyed","getHeightInspectionNode","node","getSingleChildElement","childElements","resolveExplicitHeight","parentViewportHeight","precomputedViewportHeightCss","parsed","parseExplicitHeight","container","containerChildren","rootContentElement","runtimeViewportHeightCss","inspectViewportHeightFromNodeChain","runtimeViewportHeight","explicitPixelHeight","resolveExplicitHeightFromNodeChain","updateHeight","bodyScrollH","htmlScrollH","rootScrollH","measuredHeight","next","explicitHeight","nextHeight","prevHeight","scheduleHeightUpdate","inject","resizeObserver","mutationObserver","onFullscreenChange","el","ro","entries","contentModeStyle","useMemo","minH","toggleFullscreen","target","jsx","SandboxApp","t1","t2","containerClassName","jsxs","ContentRender"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const w=require("../../comma-separated-tokens/index.cjs.js"),u=require("../../devlop/lib/default.cjs.js"),f=require("../../property-information/index.cjs.js"),C=require("../../space-separated-tokens/index.cjs.js"),S=require("../../../_virtual/index.
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const w=require("../../comma-separated-tokens/index.cjs.js"),u=require("../../devlop/lib/default.cjs.js"),f=require("../../property-information/index.cjs.js"),C=require("../../space-separated-tokens/index.cjs.js"),S=require("../../../_virtual/index.cjs6.js"),N=require("../../hast-util-whitespace/lib/index.cjs.js"),x=require("../../estree-util-is-identifier-name/lib/index.cjs.js"),h=require("../../vfile-message/lib/index.cjs.js"),j=require("../../property-information/lib/find.cjs.js"),A=require("../../property-information/lib/hast-to-react.cjs.js"),T=require("../../unist-util-position/lib/index.cjs.js"),m={}.hasOwnProperty,F=new Map,P=/[A-Z]/g,q=new Set(["table","tbody","thead","tfoot","tr"]),J=new Set(["td","th"]),g="https://github.com/syntax-tree/hast-util-to-jsx-runtime";function M(t,e){if(!e||e.Fragment===void 0)throw new TypeError("Expected `Fragment` in options");const r=e.filePath||void 0;let n;if(e.development){if(typeof e.jsxDEV!="function")throw new TypeError("Expected `jsxDEV` in options when `development: true`");n=K(r,e.jsxDEV)}else{if(typeof e.jsx!="function")throw new TypeError("Expected `jsx` in production options");if(typeof e.jsxs!="function")throw new TypeError("Expected `jsxs` in production options");n=k(r,e.jsx,e.jsxs)}const s={Fragment:e.Fragment,ancestors:[],components:e.components||{},create:n,elementAttributeNameCase:e.elementAttributeNameCase||"react",evaluater:e.createEvaluater?e.createEvaluater():void 0,filePath:r,ignoreInvalidStyle:e.ignoreInvalidStyle||!1,passKeys:e.passKeys!==!1,passNode:e.passNode||!1,schema:e.space==="svg"?f.svg:f.html,stylePropertyNameCase:e.stylePropertyNameCase||"dom",tableCellAlignToStyle:e.tableCellAlignToStyle!==!1},i=E(s,t,void 0);return i&&typeof i!="string"?i:s.create(t,s.Fragment,{children:i||void 0},void 0)}function E(t,e,r){if(e.type==="element")return I(t,e,r);if(e.type==="mdxFlowExpression"||e.type==="mdxTextExpression")return L(t,e);if(e.type==="mdxJsxFlowElement"||e.type==="mdxJsxTextElement")return V(t,e,r);if(e.type==="mdxjsEsm")return $(t,e);if(e.type==="root")return D(t,e,r);if(e.type==="text")return O(t,e)}function I(t,e,r){const n=t.schema;let s=n;e.tagName.toLowerCase()==="svg"&&n.space==="html"&&(s=f.svg,t.schema=s),t.ancestors.push(e);const i=b(t,e.tagName,!1),a=R(t,e);let o=d(t,e);return q.has(e.tagName)&&(o=o.filter(function(l){return typeof l=="string"?!N.whitespace(l):!0})),v(t,a,i,e),y(a,o),t.ancestors.pop(),t.schema=n,t.create(e,i,a,r)}function L(t,e){if(e.data&&e.data.estree&&t.evaluater){const n=e.data.estree.body[0];return u.ok(n.type==="ExpressionStatement"),t.evaluater.evaluateExpression(n.expression)}p(t,e.position)}function $(t,e){if(e.data&&e.data.estree&&t.evaluater)return t.evaluater.evaluateProgram(e.data.estree);p(t,e.position)}function V(t,e,r){const n=t.schema;let s=n;e.name==="svg"&&n.space==="html"&&(s=f.svg,t.schema=s),t.ancestors.push(e);const i=e.name===null?t.Fragment:b(t,e.name,!0),a=_(t,e),o=d(t,e);return v(t,a,i,e),y(a,o),t.ancestors.pop(),t.schema=n,t.create(e,i,a,r)}function D(t,e,r){const n={};return y(n,d(t,e)),t.create(e,t.Fragment,n,r)}function O(t,e){return e.value}function v(t,e,r,n){typeof r!="string"&&r!==t.Fragment&&t.passNode&&(e.node=n)}function y(t,e){if(e.length>0){const r=e.length>1?e:e[0];r&&(t.children=r)}}function k(t,e,r){return n;function n(s,i,a,o){const c=Array.isArray(a.children)?r:e;return o?c(i,a,o):c(i,a)}}function K(t,e){return r;function r(n,s,i,a){const o=Array.isArray(i.children),l=T.pointStart(n);return e(s,i,a,o,{columnNumber:l?l.column-1:void 0,fileName:t,lineNumber:l?l.line:void 0},void 0)}}function R(t,e){const r={};let n,s;for(s in e.properties)if(s!=="children"&&m.call(e.properties,s)){const i=B(t,s,e.properties[s]);if(i){const[a,o]=i;t.tableCellAlignToStyle&&a==="align"&&typeof o=="string"&&J.has(e.tagName)?n=o:r[a]=o}}if(n){const i=r.style||(r.style={});i[t.stylePropertyNameCase==="css"?"text-align":"textAlign"]=n}return r}function _(t,e){const r={};for(const n of e.attributes)if(n.type==="mdxJsxExpressionAttribute")if(n.data&&n.data.estree&&t.evaluater){const i=n.data.estree.body[0];u.ok(i.type==="ExpressionStatement");const a=i.expression;u.ok(a.type==="ObjectExpression");const o=a.properties[0];u.ok(o.type==="SpreadElement"),Object.assign(r,t.evaluater.evaluateExpression(o.argument))}else p(t,e.position);else{const s=n.name;let i;if(n.value&&typeof n.value=="object")if(n.value.data&&n.value.data.estree&&t.evaluater){const o=n.value.data.estree.body[0];u.ok(o.type==="ExpressionStatement"),i=t.evaluater.evaluateExpression(o.expression)}else p(t,e.position);else i=n.value===null?!0:n.value;r[s]=i}return r}function d(t,e){const r=[];let n=-1;const s=t.passKeys?new Map:F;for(;++n<e.children.length;){const i=e.children[n];let a;if(t.passKeys){const l=i.type==="element"?i.tagName:i.type==="mdxJsxFlowElement"||i.type==="mdxJsxTextElement"?i.name:void 0;if(l){const c=s.get(l)||0;a=l+"-"+c,s.set(l,c+1)}}const o=E(t,i,a);o!==void 0&&r.push(o)}return r}function B(t,e,r){const n=j.find(t.schema,e);if(!(r==null||typeof r=="number"&&Number.isNaN(r))){if(Array.isArray(r)&&(r=n.commaSeparated?w.stringify(r):C.stringify(r)),n.property==="style"){let s=typeof r=="object"?r:z(t,String(r));return t.stylePropertyNameCase==="css"&&(s=X(s)),["style",s]}return[t.elementAttributeNameCase==="react"&&n.space?A.hastToReact[n.property]||n.property:n.attribute,r]}}function z(t,e){try{return S.default(e,{reactCompat:!0})}catch(r){if(t.ignoreInvalidStyle)return{};const n=r,s=new h.VFileMessage("Cannot parse `style` attribute",{ancestors:t.ancestors,cause:n,ruleId:"style",source:"hast-util-to-jsx-runtime"});throw s.file=t.filePath||void 0,s.url=g+"#cannot-parse-style-attribute",s}}function b(t,e,r){let n;if(!r)n={type:"Literal",value:e};else if(e.includes(".")){const s=e.split(".");let i=-1,a;for(;++i<s.length;){const o=x.name(s[i])?{type:"Identifier",name:s[i]}:{type:"Literal",value:s[i]};a=a?{type:"MemberExpression",object:a,property:o,computed:!!(i&&o.type==="Literal"),optional:!1}:o}n=a}else n=x.name(e)&&!/^[a-z]/.test(e)?{type:"Identifier",name:e}:{type:"Literal",value:e};if(n.type==="Literal"){const s=n.value;return m.call(t.components,s)?t.components[s]:s}if(t.evaluater)return t.evaluater.evaluateExpression(n);p(t)}function p(t,e){const r=new h.VFileMessage("Cannot handle MDX estrees without `createEvaluater`",{ancestors:t.ancestors,place:e,ruleId:"mdx-estree",source:"hast-util-to-jsx-runtime"});throw r.file=t.filePath||void 0,r.url=g+"#cannot-handle-mdx-estrees-without-createevaluater",r}function X(t){const e={};let r;for(r in t)m.call(t,r)&&(e[Z(r)]=t[r]);return e}function Z(t){let e=t.replace(P,G);return e.slice(0,3)==="ms-"&&(e="-"+e),e}function G(t){return"-"+t.toLowerCase()}exports.toJsxRuntime=M;
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -2,7 +2,7 @@ import { stringify as w } from "../../comma-separated-tokens/index.es.js";
|
|
|
2
2
|
import { ok as u } from "../../devlop/lib/default.es.js";
|
|
3
3
|
import { svg as m, html as C } from "../../property-information/index.es.js";
|
|
4
4
|
import { stringify as N } from "../../space-separated-tokens/index.es.js";
|
|
5
|
-
import S from "../../../_virtual/index.
|
|
5
|
+
import S from "../../../_virtual/index.es6.js";
|
|
6
6
|
import { whitespace as j } from "../../hast-util-whitespace/lib/index.es.js";
|
|
7
7
|
import { name as x } from "../../estree-util-is-identifier-name/lib/index.es.js";
|
|
8
8
|
import { VFileMessage as h } from "../../vfile-message/lib/index.es.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const P=require("../../bail/index.cjs.js"),w=require("../../../_virtual/index.
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const P=require("../../bail/index.cjs.js"),w=require("../../../_virtual/index.cjs5.js"),z=require("../../is-plain-obj/index.cjs.js"),C=require("./callable-instance.cjs.js"),S=require("../../trough/lib/index.cjs.js"),A=require("../../vfile/lib/index.cjs.js"),F={}.hasOwnProperty;class m extends C.CallableInstance{constructor(){super("copy"),this.Compiler=void 0,this.Parser=void 0,this.attachers=[],this.compiler=void 0,this.freezeIndex=-1,this.frozen=void 0,this.namespace={},this.parser=void 0,this.transformers=S.trough()}copy(){const e=new m;let n=-1;for(;++n<this.attachers.length;){const t=this.attachers[n];e.use(...t)}return e.data(w.default(!0,{},this.namespace)),e}data(e,n){return typeof e=="string"?arguments.length===2?(x("data",this.frozen),this.namespace[e]=n,this):F.call(this.namespace,e)&&this.namespace[e]||void 0:e?(x("data",this.frozen),this.namespace=e,this):this.namespace}freeze(){if(this.frozen)return this;const e=this;for(;++this.freezeIndex<this.attachers.length;){const[n,...t]=this.attachers[this.freezeIndex];if(t[0]===!1)continue;t[0]===!0&&(t[0]=void 0);const i=n.call(e,...t);typeof i=="function"&&this.transformers.use(i)}return this.frozen=!0,this.freezeIndex=Number.POSITIVE_INFINITY,this}parse(e){this.freeze();const n=y(e),t=this.parser||this.Parser;return g("parse",t),t(String(n),n)}process(e,n){const t=this;return this.freeze(),g("process",this.parser||this.Parser),b("process",this.compiler||this.Compiler),n?i(void 0,n):new Promise(i);function i(a,h){const u=y(e),l=t.parse(u);t.run(l,u,function(o,c,f){if(o||!c||!f)return s(o);const p=c,d=t.stringify(p,f);D(d)?f.value=d:f.result=d,s(o,f)});function s(o,c){o||!c?h(o):a?a(c):n(void 0,c)}}}processSync(e){let n=!1,t;return this.freeze(),g("processSync",this.parser||this.Parser),b("processSync",this.compiler||this.Compiler),this.process(e,i),T("processSync","process",n),t;function i(a,h){n=!0,P.bail(a),t=h}}run(e,n,t){I(e),this.freeze();const i=this.transformers;return!t&&typeof n=="function"&&(t=n,n=void 0),t?a(void 0,t):new Promise(a);function a(h,u){const l=y(n);i.run(e,l,s);function s(o,c,f){const p=c||e;o?u(o):h?h(p):t(void 0,p,f)}}}runSync(e,n){let t=!1,i;return this.run(e,n,a),T("runSync","run",t),i;function a(h,u){P.bail(h),i=u,t=!0}}stringify(e,n){this.freeze();const t=y(n),i=this.compiler||this.Compiler;return b("stringify",i),I(e),i(e,t)}use(e,...n){const t=this.attachers,i=this.namespace;if(x("use",this.frozen),e!=null)if(typeof e=="function")l(e,n);else if(typeof e=="object")Array.isArray(e)?u(e):h(e);else throw new TypeError("Expected usable value, not `"+e+"`");return this;function a(s){if(typeof s=="function")l(s,[]);else if(typeof s=="object")if(Array.isArray(s)){const[o,...c]=s;l(o,c)}else h(s);else throw new TypeError("Expected usable value, not `"+s+"`")}function h(s){if(!("plugins"in s)&&!("settings"in s))throw new Error("Expected usable value but received an empty preset, which is probably a mistake: presets typically come with `plugins` and sometimes with `settings`, but this has neither");u(s.plugins),s.settings&&(i.settings=w.default(!0,i.settings,s.settings))}function u(s){let o=-1;if(s!=null)if(Array.isArray(s))for(;++o<s.length;){const c=s[o];a(c)}else throw new TypeError("Expected a list of plugins, not `"+s+"`")}function l(s,o){let c=-1,f=-1;for(;++c<t.length;)if(t[c][0]===s){f=c;break}if(f===-1)t.push([s,...o]);else if(o.length>0){let[p,...d]=o;const E=t[f][1];z.default(E)&&z.default(p)&&(p=w.default(!0,E,p)),t[f]=[s,p,...d]}}}}const q=new m().freeze();function g(r,e){if(typeof e!="function")throw new TypeError("Cannot `"+r+"` without `parser`")}function b(r,e){if(typeof e!="function")throw new TypeError("Cannot `"+r+"` without `compiler`")}function x(r,e){if(e)throw new Error("Cannot call `"+r+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function I(r){if(!z.default(r)||typeof r.type!="string")throw new TypeError("Expected node, got `"+r+"`")}function T(r,e,n){if(!n)throw new Error("`"+r+"` finished async. Use `"+e+"` instead")}function y(r){return j(r)?r:new A.VFile(r)}function j(r){return!!(r&&typeof r=="object"&&"message"in r&&"messages"in r)}function D(r){return typeof r=="string"||L(r)}function L(r){return!!(r&&typeof r=="object"&&"byteLength"in r&&"byteOffset"in r)}exports.Processor=m;exports.unified=q;
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { bail as P } from "../../bail/index.es.js";
|
|
2
|
-
import y from "../../../_virtual/index.
|
|
2
|
+
import y from "../../../_virtual/index.es5.js";
|
|
3
3
|
import z from "../../is-plain-obj/index.es.js";
|
|
4
4
|
import { CallableInstance as C } from "./callable-instance.es.js";
|
|
5
5
|
import { trough as A } from "../../trough/lib/index.es.js";
|