markdown-flow-ui 0.1.112 → 0.1.113

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.
Files changed (41) hide show
  1. package/dist/_virtual/index.cjs8.js +1 -1
  2. package/dist/_virtual/index.cjs9.js +1 -1
  3. package/dist/_virtual/index.es8.js +2 -3
  4. package/dist/_virtual/index.es8.js.map +1 -1
  5. package/dist/_virtual/index.es9.js +3 -2
  6. package/dist/_virtual/index.es9.js.map +1 -1
  7. package/dist/components/ContentRender/ContentRender.cjs.js +2 -2
  8. package/dist/components/ContentRender/ContentRender.cjs.js.map +1 -1
  9. package/dist/components/ContentRender/ContentRender.d.ts +1 -0
  10. package/dist/components/ContentRender/ContentRender.es.js +118 -116
  11. package/dist/components/ContentRender/ContentRender.es.js.map +1 -1
  12. package/dist/components/ContentRender/IframeSandbox.cjs.js +2 -2
  13. package/dist/components/ContentRender/IframeSandbox.cjs.js.map +1 -1
  14. package/dist/components/ContentRender/IframeSandbox.d.ts +1 -0
  15. package/dist/components/ContentRender/IframeSandbox.es.js +108 -100
  16. package/dist/components/ContentRender/IframeSandbox.es.js.map +1 -1
  17. package/dist/components/ContentRender/SandboxApp.cjs.js +2 -2
  18. package/dist/components/ContentRender/SandboxApp.cjs.js.map +1 -1
  19. package/dist/components/ContentRender/SandboxApp.d.ts +1 -0
  20. package/dist/components/ContentRender/SandboxApp.es.js +90 -87
  21. package/dist/components/ContentRender/SandboxApp.es.js.map +1 -1
  22. package/dist/components/Slide/Slide.cjs.js +1 -1
  23. package/dist/components/Slide/Slide.cjs.js.map +1 -1
  24. package/dist/components/Slide/Slide.d.ts +1 -0
  25. package/dist/components/Slide/Slide.es.js +524 -503
  26. package/dist/components/Slide/Slide.es.js.map +1 -1
  27. package/dist/components/Slide/Slide.stories.d.ts +1 -0
  28. package/dist/markdown-flow-ui/node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.cjs.js +1 -1
  29. package/dist/markdown-flow-ui/node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.es.js +1 -1
  30. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/c4Diagram-YG6GDRKO.cjs.js +1 -1
  31. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/c4Diagram-YG6GDRKO.es.js +1 -1
  32. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/chunk-S3R3BYOJ.cjs.js +1 -1
  33. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/chunk-S3R3BYOJ.es.js +1 -1
  34. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/chunk-TZMSLE5B.cjs.js +1 -1
  35. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/chunk-TZMSLE5B.es.js +1 -1
  36. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/ganttDiagram-LVOFAZNH.cjs.js +1 -1
  37. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/ganttDiagram-LVOFAZNH.es.js +1 -1
  38. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/sequenceDiagram-WL72ISMW.cjs.js +1 -1
  39. package/dist/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/sequenceDiagram-WL72ISMW.es.js +1 -1
  40. package/dist/markdown-flow-ui-lib.css +1 -1
  41. package/package.json +1 -1
@@ -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\";\nimport {\n injectScalingSystem,\n type ScalingWindow,\n} from \"./utils/iframe-scaling\";\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 enableScaling?: 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 enableScaling = 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 isMeasuringContentRef = useRef(false);\n const pendingHeightUpdateRef = useRef(false);\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 shouldEnableScaling =\n enableScaling && isBlackboardMode && type === \"sandbox\";\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 ? shouldEnableScaling\n ? \"100%\"\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: ${shouldEnableScaling ? \"hidden auto\" : mode === \"blackboard\" ? \"auto\" : \"hidden\"}; }\n *, *::before, *::after { box-sizing: border-box; }\n ${\n mode !== \"blackboard\"\n ? `\n .h-screen { height: auto !important; }\n .min-h-screen { min-height: auto !important; }\n .h-dvh, .h-svh, .h-lvh { height: auto !important; }\n .min-h-dvh, .min-h-svh, .min-h-lvh { min-height: auto !important; }\n `\n : \"\"\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 handleSandboxClick = () => emitSandboxInteraction(\"click\");\n\n if (shouldBridgeSandboxInteraction) {\n doc.addEventListener(\"click\", handleSandboxClick, 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 // Guard: prevent re-entrant measurement from ResizeObserver /\n // MutationObserver callbacks triggered by our own height changes.\n if (isMeasuringContentRef.current) {\n // Mark that an update was requested while the guard was active.\n // We will retry once the guard releases (see setTimeout below).\n pendingHeightUpdateRef.current = true;\n return;\n }\n isMeasuringContentRef.current = true;\n\n // Content mode height measurement strategy:\n // Temporarily set iframe height to the 16:9 minimum so that:\n // 1. vmin units are stable: vmin = min(cw, minH)/100 = minH/100,\n // consistent with the final rendered 16:9 iframe.\n // 2. Viewport-filling content (e.g. inline style=\"height:100vh\")\n // fills the 16:9 space → scrollHeight = minH, which is then\n // correctly bounded by the 16:9 minimum in contentModeStyle.\n // (Previously using cw caused such content to report 1:1 height,\n // overriding the 16:9 minimum.)\n const iframe = iframeRef.current;\n const cw = containerRef.current?.clientWidth || 0;\n const prevH = iframe.style.height;\n\n if (cw > 0) {\n const minH = Math.round((cw * 9) / 16);\n iframe.style.height = minH + \"px\";\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n doc.body.offsetHeight; // force layout\n\n let measuredH = doc.body.scrollHeight;\n\n // Detect inner elements that clip overflowing content behind a\n // scrollbar (e.g. <div style=\"height:100vh; overflow-y:auto\"> whose\n // content is taller than the iframe). body.scrollHeight won't see\n // that overflow, so we walk the tree and factor in each scrollable\n // element's full scroll height based on its position in the iframe.\n const iframeWin = doc.defaultView;\n if (iframeWin) {\n // Returns the max natural bottom of inner elements that clip\n // content via overflow:auto/scroll (i.e. internal scrollbars).\n const getInnerScrollableHeight = (root: Element): number => {\n let maxH = 0;\n const walk = (el: Element) => {\n if (el !== root && el.scrollHeight > el.clientHeight + 1) {\n const oy = iframeWin.getComputedStyle(el).overflowY;\n if (oy === \"auto\" || oy === \"scroll\") {\n const rect = el.getBoundingClientRect();\n if (rect.top >= 0) {\n maxH = Math.max(\n maxH,\n Math.ceil(rect.top + el.scrollHeight)\n );\n }\n }\n }\n for (const child of el.children) walk(child);\n };\n walk(root);\n return maxH;\n };\n\n measuredH = Math.max(measuredH, getInnerScrollableHeight(doc.body));\n\n // Content that uses vh-relative sizing grows as the viewport\n // expands. Measure up to 8 more times at the expanded height so\n // we capture the full content height in a single updateHeight()\n // call rather than waiting for external re-triggers.\n for (let i = 0; i < 8 && measuredH > minH; i++) {\n iframe.style.height = measuredH + \"px\";\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n doc.body.offsetHeight; // force layout at expanded size\n const nextH = Math.max(\n doc.body.scrollHeight,\n getInnerScrollableHeight(doc.body)\n );\n if (nextH <= measuredH + 1) break; // stable — stop iterating\n measuredH = nextH;\n }\n }\n\n // Restore iframe to let React control it via contentModeStyle\n iframe.style.height = prevH;\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredH));\n return prev === next ? prev : next;\n });\n }\n\n setTimeout(() => {\n isMeasuringContentRef.current = false;\n // Retry any update that was blocked while the guard was active\n // (e.g. dynamic content injected by scripts or images loading).\n if (pendingHeightUpdateRef.current) {\n pendingHeightUpdateRef.current = false;\n scheduleHeightUpdate();\n }\n }, 50);\n return;\n }\n\n // Scaling mode: viewport is fixed, content scales via font-size.\n if (shouldEnableScaling) return;\n\n // Blackboard mode: use existing measurement 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 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 if (shouldEnableScaling) {\n injectScalingSystem(doc);\n }\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 (shouldEnableScaling) {\n const iframeWin = iframe.contentWindow as ScalingWindow | null;\n iframeWin?.__mdf_cleanupScaling?.();\n }\n if (shouldBridgeSandboxInteraction) {\n doc.removeEventListener(\"click\", handleSandboxClick, 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 enableScaling={shouldEnableScaling}\n />\n );\n\n // Schedule multiple measurements to catch async content (scripts, images, styles).\n initialPaintFrameRef.current = window.requestAnimationFrame(() => {\n updateHeightRef.current?.();\n if (shouldEnableScaling) {\n const iframeWin = iframeRef.current\n ?.contentWindow as ScalingWindow | null;\n iframeWin?.__mdf_triggerFitContent?.();\n }\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 onClick={() => emitSandboxInteraction(\"click\")}>\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","enableScaling","containerRef","useRef","iframeRef","rootRef","updateHeightRef","height","setHeight","useState","contentHeight","setContentHeight","containerWidth","setContainerWidth","isMeasuringContentRef","pendingHeightUpdateRef","lastSandboxInteractionTimeRef","resetToken","setResetToken","isFullscreen","setIsFullscreen","shouldInjectSandboxVendor","isBlackboardMode","shouldEnableScaling","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","handleSandboxClick","rootEl","root","createRoot","isDestroyed","getHeightInspectionNode","node","getSingleChildElement","childElements","resolveExplicitHeight","parentViewportHeight","precomputedViewportHeightCss","parsed","parseExplicitHeight","container","containerChildren","rootContentElement","runtimeViewportHeightCss","inspectViewportHeightFromNodeChain","runtimeViewportHeight","explicitPixelHeight","resolveExplicitHeightFromNodeChain","updateHeight","cw","prevH","minH","measuredH","iframeWin","getInnerScrollableHeight","maxH","walk","el","oy","rect","child","i","nextH","next","scheduleHeightUpdate","bodyScrollH","htmlScrollH","rootScrollH","measuredHeight","explicitHeight","nextHeight","prevHeight","inject","injectScalingSystem","resizeObserver","mutationObserver","onFullscreenChange","ro","entries","contentModeStyle","useMemo","toggleFullscreen","target","jsx","SandboxApp","t1","t2","containerClassName","jsxs","ContentRender"],"mappings":"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"}
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\";\nimport {\n injectScalingSystem,\n type ScalingWindow,\n} from \"./utils/iframe-scaling\";\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 enableScaling?: boolean;\n disableLoadingOverlay?: 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 enableScaling = false,\n disableLoadingOverlay = 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 isMeasuringContentRef = useRef(false);\n const pendingHeightUpdateRef = useRef(false);\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 shouldEnableScaling =\n enableScaling && isBlackboardMode && type === \"sandbox\";\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 ? shouldEnableScaling\n ? \"100%\"\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: ${shouldEnableScaling ? \"hidden auto\" : mode === \"blackboard\" ? \"auto\" : \"hidden\"}; }\n *, *::before, *::after { box-sizing: border-box; }\n ${\n mode !== \"blackboard\"\n ? `\n .h-screen { height: auto !important; }\n .min-h-screen { min-height: auto !important; }\n .h-dvh, .h-svh, .h-lvh { height: auto !important; }\n .min-h-dvh, .min-h-svh, .min-h-lvh { min-height: auto !important; }\n `\n : \"\"\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 handleSandboxClick = () => emitSandboxInteraction(\"click\");\n\n if (shouldBridgeSandboxInteraction) {\n doc.addEventListener(\"click\", handleSandboxClick, 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 // Guard: prevent re-entrant measurement from ResizeObserver /\n // MutationObserver callbacks triggered by our own height changes.\n if (isMeasuringContentRef.current) {\n // Mark that an update was requested while the guard was active.\n // We will retry once the guard releases (see setTimeout below).\n pendingHeightUpdateRef.current = true;\n return;\n }\n isMeasuringContentRef.current = true;\n\n // Content mode height measurement strategy:\n // Temporarily set iframe height to the 16:9 minimum so that:\n // 1. vmin units are stable: vmin = min(cw, minH)/100 = minH/100,\n // consistent with the final rendered 16:9 iframe.\n // 2. Viewport-filling content (e.g. inline style=\"height:100vh\")\n // fills the 16:9 space → scrollHeight = minH, which is then\n // correctly bounded by the 16:9 minimum in contentModeStyle.\n // (Previously using cw caused such content to report 1:1 height,\n // overriding the 16:9 minimum.)\n const iframe = iframeRef.current;\n const cw = containerRef.current?.clientWidth || 0;\n const prevH = iframe.style.height;\n\n if (cw > 0) {\n const minH = Math.round((cw * 9) / 16);\n iframe.style.height = minH + \"px\";\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n doc.body.offsetHeight; // force layout\n\n let measuredH = doc.body.scrollHeight;\n\n // Detect inner elements that clip overflowing content behind a\n // scrollbar (e.g. <div style=\"height:100vh; overflow-y:auto\"> whose\n // content is taller than the iframe). body.scrollHeight won't see\n // that overflow, so we walk the tree and factor in each scrollable\n // element's full scroll height based on its position in the iframe.\n const iframeWin = doc.defaultView;\n if (iframeWin) {\n // Returns the max natural bottom of inner elements that clip\n // content via overflow:auto/scroll (i.e. internal scrollbars).\n const getInnerScrollableHeight = (root: Element): number => {\n let maxH = 0;\n const walk = (el: Element) => {\n if (el !== root && el.scrollHeight > el.clientHeight + 1) {\n const oy = iframeWin.getComputedStyle(el).overflowY;\n if (oy === \"auto\" || oy === \"scroll\") {\n const rect = el.getBoundingClientRect();\n if (rect.top >= 0) {\n maxH = Math.max(\n maxH,\n Math.ceil(rect.top + el.scrollHeight)\n );\n }\n }\n }\n for (const child of el.children) walk(child);\n };\n walk(root);\n return maxH;\n };\n\n measuredH = Math.max(measuredH, getInnerScrollableHeight(doc.body));\n\n // Content that uses vh-relative sizing grows as the viewport\n // expands. Measure up to 8 more times at the expanded height so\n // we capture the full content height in a single updateHeight()\n // call rather than waiting for external re-triggers.\n for (let i = 0; i < 8 && measuredH > minH; i++) {\n iframe.style.height = measuredH + \"px\";\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n doc.body.offsetHeight; // force layout at expanded size\n const nextH = Math.max(\n doc.body.scrollHeight,\n getInnerScrollableHeight(doc.body)\n );\n if (nextH <= measuredH + 1) break; // stable — stop iterating\n measuredH = nextH;\n }\n }\n\n // Restore iframe to let React control it via contentModeStyle\n iframe.style.height = prevH;\n\n setContentHeight((prev) => {\n const next = Math.max(200, Math.ceil(measuredH));\n return prev === next ? prev : next;\n });\n }\n\n setTimeout(() => {\n isMeasuringContentRef.current = false;\n // Retry any update that was blocked while the guard was active\n // (e.g. dynamic content injected by scripts or images loading).\n if (pendingHeightUpdateRef.current) {\n pendingHeightUpdateRef.current = false;\n scheduleHeightUpdate();\n }\n }, 50);\n return;\n }\n\n // Scaling mode: viewport is fixed, content scales via font-size.\n if (shouldEnableScaling) return;\n\n // Blackboard mode: use existing measurement 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 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 if (shouldEnableScaling) {\n injectScalingSystem(doc);\n }\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 (shouldEnableScaling) {\n const iframeWin = iframe.contentWindow as ScalingWindow | null;\n iframeWin?.__mdf_cleanupScaling?.();\n }\n if (shouldBridgeSandboxInteraction) {\n doc.removeEventListener(\"click\", handleSandboxClick, 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 disableLoadingOverlay={disableLoadingOverlay}\n resetToken={resetToken}\n hasRootVhHeight={hasRootVhHeight}\n mode={mode}\n stretchRootHeight={shouldStretchRootHeight}\n enableScaling={shouldEnableScaling}\n />\n );\n\n // Schedule multiple measurements to catch async content (scripts, images, styles).\n initialPaintFrameRef.current = window.requestAnimationFrame(() => {\n updateHeightRef.current?.();\n if (shouldEnableScaling) {\n const iframeWin = iframeRef.current\n ?.contentWindow as ScalingWindow | null;\n iframeWin?.__mdf_triggerFitContent?.();\n }\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 onClick={() => emitSandboxInteraction(\"click\")}>\n <ContentRender\n content={content}\n disableSandboxLoadingOverlay={disableLoadingOverlay}\n />\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","enableScaling","disableLoadingOverlay","containerRef","useRef","iframeRef","rootRef","updateHeightRef","height","setHeight","useState","contentHeight","setContentHeight","containerWidth","setContainerWidth","isMeasuringContentRef","pendingHeightUpdateRef","lastSandboxInteractionTimeRef","resetToken","setResetToken","isFullscreen","setIsFullscreen","shouldInjectSandboxVendor","isBlackboardMode","shouldEnableScaling","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","handleSandboxClick","rootEl","root","createRoot","isDestroyed","getHeightInspectionNode","node","getSingleChildElement","childElements","resolveExplicitHeight","parentViewportHeight","precomputedViewportHeightCss","parsed","parseExplicitHeight","container","containerChildren","rootContentElement","runtimeViewportHeightCss","inspectViewportHeightFromNodeChain","runtimeViewportHeight","explicitPixelHeight","resolveExplicitHeightFromNodeChain","updateHeight","cw","prevH","minH","measuredH","iframeWin","getInnerScrollableHeight","maxH","walk","el","oy","rect","child","i","nextH","next","scheduleHeightUpdate","bodyScrollH","htmlScrollH","rootScrollH","measuredHeight","explicitHeight","nextHeight","prevHeight","inject","injectScalingSystem","resizeObserver","mutationObserver","onFullscreenChange","ro","entries","contentModeStyle","useMemo","toggleFullscreen","target","jsx","SandboxApp","t1","t2","containerClassName","jsxs","ContentRender"],"mappings":"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"}
@@ -11,6 +11,7 @@ export interface IframeSandboxProps {
11
11
  type: "sandbox" | "markdown";
12
12
  replaceRootScreenHeightWithFull?: boolean;
13
13
  enableScaling?: boolean;
14
+ disableLoadingOverlay?: boolean;
14
15
  }
15
16
  declare const IframeSandbox: React.FC<IframeSandboxProps>;
16
17
  export default IframeSandbox;
@@ -1,30 +1,30 @@
1
- import { j as S } from "../../_virtual/jsx-runtime.es.js";
2
- import j, { useRef as i, useState as M, useCallback as Be, useEffect as H, useMemo as We } from "react";
3
- import { createRoot as De } from "react-dom/client";
4
- import Pe from "./SandboxApp.es.js";
5
- import $e from "./ContentRender.es.js";
6
- import { inspectViewportHeightFromHtmlRootString as ye, EMPTY_ROOT_HEIGHT_META as ze, parseExplicitHeight as Ce, inspectViewportHeightFromNodeChain as qe, resolveExplicitHeightFromNodeChain as Ge } from "./utils/iframe-viewport-height.es.js";
7
- import { SANDBOX_INTERACTION_MESSAGE_TYPE as Le, SANDBOX_INTERACTION_MESSAGE_SOURCE as Ue } from "../../lib/sandboxInteraction.es.js";
8
- import { injectScalingSystem as Ye } from "./utils/iframe-scaling.es.js";
1
+ import { j as C } from "../../_virtual/jsx-runtime.es.js";
2
+ import j, { useRef as i, useState as M, useCallback as We, useEffect as H, useMemo as De } from "react";
3
+ import { createRoot as Pe } from "react-dom/client";
4
+ import $e from "./SandboxApp.es.js";
5
+ import ze from "./ContentRender.es.js";
6
+ import { inspectViewportHeightFromHtmlRootString as ye, EMPTY_ROOT_HEIGHT_META as qe, parseExplicitHeight as Ce, inspectViewportHeightFromNodeChain as Ge, resolveExplicitHeightFromNodeChain as Le } from "./utils/iframe-viewport-height.es.js";
7
+ import { SANDBOX_INTERACTION_MESSAGE_TYPE as Ue, SANDBOX_INTERACTION_MESSAGE_SOURCE as Ye } from "../../lib/sandboxInteraction.es.js";
8
+ import { injectScalingSystem as Xe } from "./utils/iframe-scaling.es.js";
9
9
  let oe = null;
10
- const Xe = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
10
+ const Ze = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
11
11
  (c) => c.injectBlackboardLibraries
12
- )), oe), Ze = /<img\b[^>]*>/i, Je = 180, Ke = 240, Qe = (c) => c.split(/\s+/).filter(Boolean).map((o) => {
12
+ )), oe), Je = /<img\b[^>]*>/i, Ke = 180, Qe = 240, et = (c) => c.split(/\s+/).filter(Boolean).map((o) => {
13
13
  const s = o.split(":");
14
14
  return s[s.length - 1] !== "h-screen" && s[s.length - 1] !== "min-h-screen" ? o : (s[s.length - 1] = "h-full", s.join(":"));
15
- }).join(" "), et = (c, o) => !o || !c.trim() ? c : c.replace(
15
+ }).join(" "), tt = (c, o) => !o || !c.trim() ? c : c.replace(
16
16
  /^(\s*<[a-zA-Z][\w:-]*)(\s[^>]*?)?>/,
17
17
  (s, B, T = "") => {
18
18
  const d = T.match(/\bclass\s*=\s*(["'])([^"']*)\1/i);
19
19
  if (!d)
20
20
  return s;
21
- const W = Qe(d[2]);
21
+ const W = et(d[2]);
22
22
  return W === d[2] ? s : `${B}${T.replace(
23
23
  d[0],
24
24
  `class=${d[1]}${W}${d[1]}`
25
25
  )}>`;
26
26
  }
27
- ), at = ({
27
+ ), ut = ({
28
28
  content: c,
29
29
  type: o,
30
30
  className: s,
@@ -33,78 +33,79 @@ const Xe = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
33
33
  fullScreenButtonText: d,
34
34
  hideFullScreen: W = !1,
35
35
  mode: l = "content",
36
- replaceRootScreenHeightWithFull: Se = !1,
37
- enableScaling: Me = !1
36
+ replaceRootScreenHeightWithFull: Me = !1,
37
+ enableScaling: Te = !1,
38
+ disableLoadingOverlay: ie = !1
38
39
  }) => {
39
40
  const D = i(null), m = i(null), U = i(null), A = i(() => {
40
- }), [Te, Ae] = M(480), [ie, _e] = M(0), [Y, se] = M(0), X = i(!1), Z = i(!1), ce = i(0), [le, ke] = M(0), [J, Fe] = M(!1), Ie = o === "sandbox", f = l === "blackboard", w = Me && f && o === "sandbox", _ = f && o === "sandbox", R = _ && Se, K = i(""), P = j.useMemo(
41
+ }), [Ae, _e] = M(480), [se, ke] = M(0), [Y, ce] = M(0), X = i(!1), Z = i(!1), le = i(0), [ae, Fe] = M(0), [J, Ie] = M(!1), Ne = o === "sandbox", f = l === "blackboard", w = Te && f && o === "sandbox", _ = f && o === "sandbox", R = _ && Me, K = i(""), P = j.useMemo(
41
42
  () => o === "sandbox" ? c : "",
42
43
  [c, o]
43
44
  ), n = j.useMemo(
44
- () => et(
45
+ () => tt(
45
46
  P,
46
47
  R
47
48
  ),
48
49
  [P, R]
49
- ), ae = j.useMemo(
50
- () => R ? ye(P) : ze,
51
- [P, R]
52
50
  ), ue = j.useMemo(
53
- () => R && ae.hasFullViewportHeight,
51
+ () => R ? ye(P) : qe,
52
+ [P, R]
53
+ ), he = j.useMemo(
54
+ () => R && ue.hasFullViewportHeight,
54
55
  [
55
- ae.hasFullViewportHeight,
56
+ ue.hasFullViewportHeight,
56
57
  R
57
58
  ]
58
- ), [$, he] = M(
59
+ ), [$, de] = M(
59
60
  n
60
- ), de = i(n), Q = i(n), k = i(null), F = i(null), me = i(null), fe = Be((t) => {
61
+ ), me = i(n), Q = i(n), k = i(null), F = i(null), fe = i(null), ge = We((t) => {
61
62
  if (typeof window > "u")
62
63
  return;
63
64
  const e = Date.now();
64
- e - ce.current < Ke || (ce.current = e, window.postMessage(
65
+ e - le.current < Qe || (le.current = e, window.postMessage(
65
66
  {
66
- source: Ue,
67
- type: Le,
67
+ source: Ye,
68
+ type: Ue,
68
69
  eventType: t
69
70
  },
70
71
  window.location.origin
71
72
  ));
72
73
  }, []), ee = () => {
73
74
  k.current !== null && (window.clearTimeout(k.current), k.current = null);
74
- }, Ne = () => {
75
+ }, Oe = () => {
75
76
  F.current !== null && (window.cancelAnimationFrame(F.current), F.current = null);
76
77
  };
77
78
  H(
78
79
  () => () => {
79
- ee(), Ne();
80
+ ee(), Oe();
80
81
  },
81
82
  []
82
83
  ), H(() => {
83
- const t = de.current;
84
- de.current = n;
85
- const e = !!t && n.length > t.length && n.startsWith(t), a = Ze.test(
84
+ const t = me.current;
85
+ me.current = n;
86
+ const e = !!t && n.length > t.length && n.startsWith(t), a = Je.test(
86
87
  n
87
88
  );
88
89
  if (!(e && a)) {
89
- ee(), Q.current = n, he(n);
90
+ ee(), Q.current = n, de(n);
90
91
  return;
91
92
  }
92
93
  Q.current = n, ee(), k.current = window.setTimeout(() => {
93
- he(Q.current), k.current = null;
94
- }, Je);
94
+ de(Q.current), k.current = null;
95
+ }, Ke);
95
96
  }, [n]);
96
97
  const z = j.useMemo(() => _ ? ye($).viewportHeightCss : null, [$, _]);
97
98
  H(() => {
98
- me.current = z;
99
+ fe.current = z;
99
100
  }, [z]);
100
- const ge = !!z, I = f && o === "sandbox" ? w || ue ? "100%" : z ?? `${Te}px` : void 0;
101
+ const be = !!z, I = f && o === "sandbox" ? w || he ? "100%" : z ?? `${Ae}px` : void 0;
101
102
  H(() => {
102
103
  if (l !== "blackboard") {
103
104
  K.current = n;
104
105
  return;
105
106
  }
106
107
  const t = K.current;
107
- !(t && n.startsWith(t)) && t && ke((a) => a + 1), K.current = n;
108
+ !(t && n.startsWith(t)) && t && Fe((a) => a + 1), K.current = n;
108
109
  }, [l, n]), H(() => {
109
110
  const t = m.current;
110
111
  if (!t) return;
@@ -133,23 +134,23 @@ const Xe = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
133
134
  <div id="root"></div>
134
135
  </body>
135
136
  </html>`), e.close(), e.documentElement.setAttribute("data-theme", "light"), e.documentElement.style.colorScheme = "light", e.body?.style.setProperty("color-scheme", "light");
136
- const a = f && o === "sandbox", q = () => fe("click");
137
+ const a = f && o === "sandbox", q = () => ge("click");
137
138
  a && e.addEventListener("click", q, !0);
138
139
  const N = e.getElementById("root");
139
140
  if (!N) return;
140
- const pe = De(N);
141
- U.current = pe;
141
+ const He = Pe(N);
142
+ U.current = He;
142
143
  let O = !1;
143
- const He = (r) => ({
144
+ const we = (r) => ({
144
145
  heightAttrValue: r.getAttribute("height"),
145
146
  styleAttrValue: r.getAttribute("style"),
146
147
  classAttrValue: r.getAttribute("class")
147
- }), we = (r) => {
148
+ }), xe = (r) => {
148
149
  const x = Array.from(r.children);
149
150
  return x.length === 1 ? x[0] : null;
150
- }, je = () => {
151
+ }, Be = () => {
151
152
  if (!_ || !m.current || !e.body) return null;
152
- const r = m.current.ownerDocument?.documentElement?.clientHeight || window.innerHeight, x = me.current, G = x ? Ce(
153
+ const r = m.current.ownerDocument?.documentElement?.clientHeight || window.innerHeight, x = fe.current, G = x ? Ce(
153
154
  x,
154
155
  r
155
156
  ) : null;
@@ -159,11 +160,11 @@ const Xe = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
159
160
  ".sandbox-wrapper"
160
161
  )?.firstElementChild;
161
162
  if (!h) return null;
162
- const g = Array.from(h.children), v = g.length === 1 ? g[0] : null, u = qe(
163
+ const g = Array.from(h.children), v = g.length === 1 ? g[0] : null, u = Ge(
163
164
  v,
164
165
  {
165
- getNode: He,
166
- getSingleChild: we
166
+ getNode: we,
167
+ getSingleChild: xe
167
168
  }
168
169
  ).viewportHeightCss;
169
170
  if (u) {
@@ -174,12 +175,12 @@ const Xe = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
174
175
  if (b !== null)
175
176
  return Math.ceil(b);
176
177
  }
177
- const V = Ge(
178
+ const V = Le(
178
179
  v,
179
180
  r,
180
181
  {
181
- getNode: He,
182
- getSingleChild: we
182
+ getNode: we,
183
+ getSingleChild: xe
183
184
  }
184
185
  );
185
186
  return V !== null ? Math.ceil(V) : null;
@@ -199,101 +200,101 @@ const Xe = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
199
200
  const V = e.defaultView;
200
201
  if (V) {
201
202
  const b = (p) => {
202
- let C = 0;
203
- const Ee = (E) => {
203
+ let y = 0;
204
+ const Re = (E) => {
204
205
  if (E !== p && E.scrollHeight > E.clientHeight + 1) {
205
206
  const L = V.getComputedStyle(E).overflowY;
206
207
  if (L === "auto" || L === "scroll") {
207
- const Re = E.getBoundingClientRect();
208
- Re.top >= 0 && (C = Math.max(
209
- C,
210
- Math.ceil(Re.top + E.scrollHeight)
208
+ const Se = E.getBoundingClientRect();
209
+ Se.top >= 0 && (y = Math.max(
210
+ y,
211
+ Math.ceil(Se.top + E.scrollHeight)
211
212
  ));
212
213
  }
213
214
  }
214
- for (const L of E.children) Ee(L);
215
+ for (const L of E.children) Re(L);
215
216
  };
216
- return Ee(p), C;
217
+ return Re(p), y;
217
218
  };
218
219
  u = Math.max(u, b(e.body));
219
220
  for (let p = 0; p < 8 && u > re; p++) {
220
221
  h.style.height = u + "px", e.body.offsetHeight;
221
- const C = Math.max(
222
+ const y = Math.max(
222
223
  e.body.scrollHeight,
223
224
  b(e.body)
224
225
  );
225
- if (C <= u + 1) break;
226
- u = C;
226
+ if (y <= u + 1) break;
227
+ u = y;
227
228
  }
228
229
  }
229
- h.style.height = v, _e((b) => {
230
+ h.style.height = v, ke((b) => {
230
231
  const p = Math.max(200, Math.ceil(u));
231
232
  return b === p ? b : p;
232
233
  });
233
234
  }
234
235
  setTimeout(() => {
235
- X.current = !1, Z.current && (Z.current = !1, y());
236
+ X.current = !1, Z.current && (Z.current = !1, S());
236
237
  }, 50);
237
238
  return;
238
239
  }
239
240
  if (w) return;
240
- const r = e.body.scrollHeight, x = e.documentElement?.scrollHeight || 0, G = N?.scrollHeight || 0, ve = Math.max(r, x, G);
241
+ const r = e.body.scrollHeight, x = e.documentElement?.scrollHeight || 0, G = N?.scrollHeight || 0, Ee = Math.max(r, x, G);
241
242
  if (_) {
242
- const h = je(), g = Math.max(
243
+ const h = Be(), g = Math.max(
243
244
  200,
244
- h ?? Math.ceil(ve)
245
+ h ?? Math.ceil(Ee)
245
246
  );
246
- Ae(
247
+ _e(
247
248
  (v) => v === g ? v : g
248
249
  );
249
250
  }
250
- }, y = () => {
251
+ }, S = () => {
251
252
  requestAnimationFrame(() => {
252
253
  O || te();
253
254
  });
254
255
  };
255
- A.current = y, te(), y(), Ie && Xe().then((r) => {
256
- O || (r(e), w && Ye(e), requestAnimationFrame(() => {
257
- O || y();
256
+ A.current = S, te(), S(), Ne && Ze().then((r) => {
257
+ O || (r(e), w && Xe(e), requestAnimationFrame(() => {
258
+ O || S();
258
259
  }));
259
260
  }).catch(() => {
260
- O || y();
261
+ O || S();
261
262
  });
262
263
  const ne = new ResizeObserver(() => te());
263
264
  ne.observe(e.body), N && ne.observe(N);
264
- const xe = new MutationObserver(() => {
265
- y();
265
+ const ve = new MutationObserver(() => {
266
+ S();
266
267
  });
267
- return xe.observe(e.body, {
268
+ return ve.observe(e.body, {
268
269
  childList: !0,
269
270
  subtree: !0,
270
271
  attributes: !0,
271
272
  attributeFilter: ["style", "class"]
272
273
  }), () => {
273
- O = !0, ne.disconnect(), xe.disconnect(), w && t.contentWindow?.__mdf_cleanupScaling?.(), a && e.removeEventListener("click", q, !0), setTimeout(() => {
274
- pe.unmount(), U.current = null, A.current = () => {
274
+ O = !0, ne.disconnect(), ve.disconnect(), w && t.contentWindow?.__mdf_cleanupScaling?.(), a && e.removeEventListener("click", q, !0), setTimeout(() => {
275
+ He.unmount(), U.current = null, A.current = () => {
275
276
  };
276
277
  }, 0);
277
278
  };
278
279
  }, []), H(() => {
279
280
  const t = () => {
280
- Fe(!!document.fullscreenElement);
281
+ Ie(!!document.fullscreenElement);
281
282
  };
282
283
  return document.addEventListener("fullscreenchange", t), () => document.removeEventListener("fullscreenchange", t);
283
284
  }, []), H(() => {
284
285
  const t = D.current;
285
286
  if (!t) return;
286
287
  const e = new ResizeObserver((a) => {
287
- se(a[0]?.contentRect.width ?? t.clientWidth);
288
+ ce(a[0]?.contentRect.width ?? t.clientWidth);
288
289
  });
289
- return e.observe(t), se(t.clientWidth), () => e.disconnect();
290
+ return e.observe(t), ce(t.clientWidth), () => e.disconnect();
290
291
  }, []);
291
- const be = We(() => {
292
+ const pe = De(() => {
292
293
  if (f || Y === 0 || J)
293
294
  return;
294
295
  const t = Math.round(Y * 9 / 16);
295
- return { height: Math.max(t, ie) };
296
- }, [f, Y, ie, J]), Oe = () => {
296
+ return { height: Math.max(t, se) };
297
+ }, [f, Y, se, J]), Ve = () => {
297
298
  const t = D.current || m.current;
298
299
  if (t) {
299
300
  if (document.fullscreenElement) {
@@ -309,16 +310,17 @@ const Xe = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
309
310
  const t = U.current;
310
311
  if (!t) return;
311
312
  t.render(
312
- /* @__PURE__ */ S.jsx(
313
- Pe,
313
+ /* @__PURE__ */ C.jsx(
314
+ $e,
314
315
  {
315
316
  html: $,
316
317
  styleLoadingText: B,
317
318
  scriptLoadingText: T,
318
- resetToken: le,
319
- hasRootVhHeight: ge,
319
+ disableLoadingOverlay: ie,
320
+ resetToken: ae,
321
+ hasRootVhHeight: be,
320
322
  mode: l,
321
- stretchRootHeight: ue,
323
+ stretchRootHeight: he,
322
324
  enableScaling: w
323
325
  }
324
326
  )
@@ -333,34 +335,40 @@ const Xe = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
333
335
  $,
334
336
  B,
335
337
  T,
336
- le,
338
+ ae,
337
339
  l
338
340
  ]);
339
- const Ve = [
341
+ const je = [
340
342
  "w-full relative content-render-iframe-sandbox",
341
- f ? "h-full overflow-auto flex flex-col" : be ? "overflow-hidden flex items-center justify-center" : "aspect-[16/9] overflow-hidden flex items-center justify-center"
343
+ f ? "h-full overflow-auto flex flex-col" : pe ? "overflow-hidden flex items-center justify-center" : "aspect-[16/9] overflow-hidden flex items-center justify-center"
342
344
  ].filter(Boolean).join(" ");
343
- return /* @__PURE__ */ S.jsxs(
345
+ return /* @__PURE__ */ C.jsxs(
344
346
  "div",
345
347
  {
346
348
  ref: D,
347
- "data-root-vh": ge ? "true" : "false",
348
- className: Ve,
349
+ "data-root-vh": be ? "true" : "false",
350
+ className: je,
349
351
  style: I ? {
350
352
  height: I,
351
353
  minHeight: I
352
- } : be,
354
+ } : pe,
353
355
  children: [
354
- !W && /* @__PURE__ */ S.jsx(
356
+ !W && /* @__PURE__ */ C.jsx(
355
357
  "button",
356
358
  {
357
359
  type: "button",
358
- onClick: Oe,
360
+ onClick: Ve,
359
361
  className: "absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer",
360
362
  children: J ? "退出全屏" : d || "全屏浏览"
361
363
  }
362
364
  ),
363
- l === "blackboard" && o === "markdown" ? /* @__PURE__ */ S.jsx("div", { onClick: () => fe("click"), children: /* @__PURE__ */ S.jsx($e, { content: c }) }) : /* @__PURE__ */ S.jsx(
365
+ l === "blackboard" && o === "markdown" ? /* @__PURE__ */ C.jsx("div", { onClick: () => ge("click"), children: /* @__PURE__ */ C.jsx(
366
+ ze,
367
+ {
368
+ content: c,
369
+ disableSandboxLoadingOverlay: ie
370
+ }
371
+ ) }) : /* @__PURE__ */ C.jsx(
364
372
  "iframe",
365
373
  {
366
374
  ref: m,
@@ -380,6 +388,6 @@ const Xe = () => (oe || (oe = import("./blackboard-vendor.es.js").then(
380
388
  );
381
389
  };
382
390
  export {
383
- at as default
391
+ ut as default
384
392
  };
385
393
  //# sourceMappingURL=IframeSandbox.es.js.map