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.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\";\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.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\";\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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"}
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const w=require("../../_virtual/jsx-runtime.cjs.js"),r=require("react"),Q=require("../ui/loading-overlay-card.cjs.js"),J=["src","srcset","sizes","alt","class","width","height","style","loading","decoding","crossorigin","referrerpolicy","fetchpriority"],z=a=>J.map(t=>`${t}:${a.getAttribute(t)||""}`).join("|"),X=a=>{const t=new Map;return a.querySelectorAll("img").forEach(l=>{const c=l,n=z(c),f=t.get(n)||[];f.push(c),t.set(n,f)}),t},Y=(a,t)=>{const l=Array.from(a.attributes),c=new Set(l.map(n=>n.name));Array.from(t.attributes).forEach(n=>{c.has(n.name)||t.removeAttribute(n.name)}),l.forEach(n=>{t.setAttribute(n.name,n.value)})},Z=(a,t)=>{t.size&&a.querySelectorAll("img").forEach(l=>{const c=l,n=z(c),f=t.get(n),h=f?.shift();h&&(Y(c,h),c.replaceWith(h),f&&f.length===0&&t.delete(n))})},ee=({html:a,styleLoadingText:t,scriptLoadingText:l,resetToken:c=0,mode:n="content",hasRootVhHeight:f=!1,stretchRootHeight:h=!1,enableScaling:T=!1})=>{const C=r.useRef(null),[H,A]=r.useState(!1),[O,j]=r.useState(!1),I=r.useRef([]),N=r.useRef([]),q=r.useRef(0),D=r.useRef(0),g=r.useRef(null),x=r.useRef(null),v=r.useRef(!1),b=r.useRef(!1),G=r.useRef(!1),L=r.useRef(c),V=200,d=s=>{s.current&&(clearTimeout(s.current),s.current=null)},k=(s,i,u,M)=>{const m=performance.now()-u.current,S=Math.max(0,V-m);d(i),i.current=window.setTimeout(()=>{s(!1),M?.(),i.current=null},S)};r.useEffect(()=>{const s=C.current?.ownerDocument;if(!s)return;const i="sandbox-spinner-style";let u=s.getElementById(i);u||(u=s.createElement("style"),u.id=i,s.head?.appendChild(u)),u.textContent=`
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const A=require("../../_virtual/jsx-runtime.cjs.js"),t=require("react"),J=require("../ui/loading-overlay-card.cjs.js"),X=["src","srcset","sizes","alt","class","width","height","style","loading","decoding","crossorigin","referrerpolicy","fetchpriority"],H=a=>X.map(r=>`${r}:${a.getAttribute(r)||""}`).join("|"),Y=a=>{const r=new Map;return a.querySelectorAll("img").forEach(f=>{const c=f,n=H(c),d=r.get(n)||[];d.push(c),r.set(n,d)}),r},Z=(a,r)=>{const f=Array.from(a.attributes),c=new Set(f.map(n=>n.name));Array.from(r.attributes).forEach(n=>{c.has(n.name)||r.removeAttribute(n.name)}),f.forEach(n=>{r.setAttribute(n.name,n.value)})},ee=(a,r)=>{r.size&&a.querySelectorAll("img").forEach(f=>{const c=f,n=H(c),d=r.get(n),h=d?.shift();h&&(Z(c,h),c.replaceWith(h),d&&d.length===0&&r.delete(n))})},te=({html:a,styleLoadingText:r,scriptLoadingText:f,resetToken:c=0,mode:n="content",hasRootVhHeight:d=!1,stretchRootHeight:h=!1,enableScaling:q=!1,disableLoadingOverlay:j=!1})=>{const I=t.useRef(null),[V,R]=t.useState(!1),[W,b]=t.useState(!1),N=t.useRef([]),_=t.useRef([]),D=t.useRef(0),G=t.useRef(0),y=t.useRef(null),g=t.useRef(null),x=t.useRef(!1),E=t.useRef(!1),k=t.useRef(!1),B=t.useRef(c),U=200,l=s=>{s.current&&(clearTimeout(s.current),s.current=null)},F=(s,i,u,T)=>{const m=performance.now()-u.current,C=Math.max(0,U-m);l(i),i.current=window.setTimeout(()=>{s(!1),T?.(),i.current=null},C)};t.useEffect(()=>{const s=I.current?.ownerDocument;if(!s)return;const i="sandbox-spinner-style";let u=s.getElementById(i);u||(u=s.createElement("style"),u.id=i,s.head?.appendChild(u)),u.textContent=`
2
2
  .sandbox-wrapper { align-items: center; }
3
3
  .sandbox-container { position: relative; width: 100%; }
4
4
  .sandbox-container svg,
@@ -7,5 +7,5 @@
7
7
  justify-content: safe center;
8
8
  }
9
9
  .overflow-y-auto { overflow-y: visible !important; }
10
- `},[]),r.useEffect(()=>{c!==L.current&&(G.current=!1,L.current=c),d(g),d(x),v.current=!1,b.current=!1;const s=C.current;if(!s)return;const i=s.ownerDocument,u=i?.body;if(!u)return;const M=X(s);I.current.forEach(e=>e.remove()),I.current=[],N.current.forEach(e=>e.remove()),N.current=[],A(!1),j(!1);const m=i.createElement("div");m.innerHTML=a;const S=(a.match(/<script[\s>]/gi)||[]).length,$=(a.match(/<\/script>/gi)||[]).length,K=S>0&&S===$,y=[];Array.from(m.querySelectorAll("style, script")).forEach(e=>{if(e.tagName.toLowerCase()==="style"){const o=i.createElement("style");o.textContent=e.textContent||"",Array.from(e.attributes).forEach(p=>{o.setAttribute(p.name,p.value)}),y.push(o)}else{const o=i.createElement("script");Array.from(e.attributes).forEach(p=>{o.setAttribute(p.name,p.value)}),o.textContent=e.textContent||"",y.push(o)}e.remove()}),Z(m,M);const B=y.some(e=>e.tagName.toLowerCase()==="style"),F=y.some(e=>e.tagName.toLowerCase()==="script");B&&(v.current=!0,q.current=performance.now(),d(g),A(!0)),F&&(b.current=!0,D.current=performance.now(),d(x),j(!0)),!!m.firstElementChild&&(G.current=!0);const P=Array.from(m.childNodes);s.replaceChildren(...P),y.forEach(e=>{if(e.tagName.toLowerCase()==="style"){i.head?.appendChild(e),I.current.push(e);return}if(K){const o=e,p=o.textContent||"";if(!o.src)try{new Function(p)}catch{o.remove();return}try{u.appendChild(o),N.current.push(o)}catch{o.remove()}}else e.remove()}),T&&s.ownerDocument?.defaultView?.__mdf_triggerFitContent?.(),requestAnimationFrame(()=>{B&&k(A,g,q,()=>{v.current=!1}),F&&k(j,x,D,()=>{b.current=!1})})},[a,c,T]),r.useEffect(()=>()=>{d(g),d(x)},[]);const E=O||b.current?l||"Building scripts cache...":H||v.current?t||"Building styles...":null,_=n==="blackboard",R=_&&h,W={position:"relative",width:"100%",height:"100%",display:"flex",flexDirection:"column",justifyContent:R?"flex-start":_?"space-around":"flex-start"},U={pointerEvents:E?"none":void 0,margin:_?void 0:"auto 0",width:"100%",height:R?"100%":void 0,minHeight:R?0:void 0,flex:R?"1 1 auto":void 0};return w.jsxRuntimeExports.jsxs("div",{"data-root-vh":f?"true":"false",className:"sandbox-wrapper",style:W,"aria-busy":!!E,children:[w.jsxRuntimeExports.jsx("div",{ref:C,className:"sandbox-container",style:U}),E&&w.jsxRuntimeExports.jsx("div",{style:{position:"absolute",inset:0,zIndex:20,display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:w.jsxRuntimeExports.jsx(Q.default,{message:E})})]})};exports.default=ee;
10
+ `},[]),t.useEffect(()=>{c!==B.current&&(k.current=!1,B.current=c),l(y),l(g),x.current=!1,E.current=!1;const s=I.current;if(!s)return;const i=s.ownerDocument,u=i?.body;if(!u)return;const T=Y(s);N.current.forEach(e=>e.remove()),N.current=[],_.current.forEach(e=>e.remove()),_.current=[],R(!1),b(!1);const m=i.createElement("div");m.innerHTML=a;const C=(a.match(/<script[\s>]/gi)||[]).length,O=(a.match(/<\/script>/gi)||[]).length,P=C>0&&C===O,v=[];Array.from(m.querySelectorAll("style, script")).forEach(e=>{if(e.tagName.toLowerCase()==="style"){const o=i.createElement("style");o.textContent=e.textContent||"",Array.from(e.attributes).forEach(p=>{o.setAttribute(p.name,p.value)}),v.push(o)}else{const o=i.createElement("script");Array.from(e.attributes).forEach(p=>{o.setAttribute(p.name,p.value)}),o.textContent=e.textContent||"",v.push(o)}e.remove()}),ee(m,T);const L=v.some(e=>e.tagName.toLowerCase()==="style"),z=v.some(e=>e.tagName.toLowerCase()==="script");L&&(x.current=!0,D.current=performance.now(),l(y),R(!0)),z&&(E.current=!0,G.current=performance.now(),l(g),b(!0)),!!m.firstElementChild&&(k.current=!0);const Q=Array.from(m.childNodes);s.replaceChildren(...Q),v.forEach(e=>{if(e.tagName.toLowerCase()==="style"){i.head?.appendChild(e),N.current.push(e);return}if(P){const o=e,p=o.textContent||"";if(!o.src)try{new Function(p)}catch{o.remove();return}try{u.appendChild(o),_.current.push(o)}catch{o.remove()}}else e.remove()}),q&&s.ownerDocument?.defaultView?.__mdf_triggerFitContent?.(),requestAnimationFrame(()=>{L&&F(R,y,D,()=>{x.current=!1}),z&&F(b,g,G,()=>{E.current=!1})})},[a,c,q]),t.useEffect(()=>()=>{l(y),l(g)},[]),t.useEffect(()=>{j&&(l(y),l(g),x.current=!1,E.current=!1,R(!1),b(!1))},[j]);const S=j?null:W||E.current?f||"Building scripts cache...":V||x.current?r||"Building styles...":null,M=n==="blackboard",w=M&&h,$={position:"relative",width:"100%",height:"100%",display:"flex",flexDirection:"column",justifyContent:w?"flex-start":M?"space-around":"flex-start"},K={pointerEvents:S?"none":void 0,margin:M?void 0:"auto 0",width:"100%",height:w?"100%":void 0,minHeight:w?0:void 0,flex:w?"1 1 auto":void 0};return A.jsxRuntimeExports.jsxs("div",{"data-root-vh":d?"true":"false",className:"sandbox-wrapper",style:$,"aria-busy":!!S,children:[A.jsxRuntimeExports.jsx("div",{ref:I,className:"sandbox-container",style:K}),S&&A.jsxRuntimeExports.jsx("div",{style:{position:"absolute",inset:0,zIndex:20,display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:A.jsxRuntimeExports.jsx(J.default,{message:S})})]})};exports.default=te;
11
11
  //# sourceMappingURL=SandboxApp.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SandboxApp.cjs.js","sources":["../../../src/components/ContentRender/SandboxApp.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport LoadingOverlayCard from \"../ui/loading-overlay-card\";\nimport type { ScalingWindow } from \"./utils/iframe-scaling\";\n\nexport interface SandboxAppProps {\n html: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n resetToken?: number;\n mode?: \"content\" | \"blackboard\";\n hasRootVhHeight?: boolean;\n stretchRootHeight?: boolean;\n enableScaling?: boolean;\n}\n\nconst IMAGE_REUSE_ATTRIBUTES = [\n \"src\",\n \"srcset\",\n \"sizes\",\n \"alt\",\n \"class\",\n \"width\",\n \"height\",\n \"style\",\n \"loading\",\n \"decoding\",\n \"crossorigin\",\n \"referrerpolicy\",\n \"fetchpriority\",\n];\n\nconst getImageReuseKey = (image: HTMLImageElement) =>\n IMAGE_REUSE_ATTRIBUTES.map(\n (attribute) => `${attribute}:${image.getAttribute(attribute) || \"\"}`\n ).join(\"|\");\n\nconst collectReusableImages = (root: ParentNode) => {\n const imageMap = new Map<string, HTMLImageElement[]>();\n root.querySelectorAll(\"img\").forEach((node) => {\n const image = node as HTMLImageElement;\n const key = getImageReuseKey(image);\n const bucket = imageMap.get(key) || [];\n bucket.push(image);\n imageMap.set(key, bucket);\n });\n return imageMap;\n};\n\nconst syncImageAttributes = (\n sourceImage: HTMLImageElement,\n targetImage: HTMLImageElement\n) => {\n const sourceAttributes = Array.from(sourceImage.attributes);\n const sourceAttributeNames = new Set(\n sourceAttributes.map((attribute) => attribute.name)\n );\n\n Array.from(targetImage.attributes).forEach((attribute) => {\n if (!sourceAttributeNames.has(attribute.name)) {\n targetImage.removeAttribute(attribute.name);\n }\n });\n\n sourceAttributes.forEach((attribute) => {\n targetImage.setAttribute(attribute.name, attribute.value);\n });\n};\n\nconst reuseRenderedImages = (\n root: ParentNode,\n imageMap: Map<string, HTMLImageElement[]>\n) => {\n if (!imageMap.size) return;\n\n root.querySelectorAll(\"img\").forEach((node) => {\n const nextImage = node as HTMLImageElement;\n const key = getImageReuseKey(nextImage);\n const bucket = imageMap.get(key);\n const preservedImage = bucket?.shift();\n if (!preservedImage) return;\n\n syncImageAttributes(nextImage, preservedImage);\n nextImage.replaceWith(preservedImage);\n\n if (bucket && bucket.length === 0) {\n imageMap.delete(key);\n }\n });\n};\n\nconst SandboxApp: React.FC<SandboxAppProps> = ({\n html,\n styleLoadingText,\n scriptLoadingText,\n resetToken = 0,\n mode = \"content\",\n hasRootVhHeight = false,\n stretchRootHeight = false,\n enableScaling = false,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [isGeneratingStyles, setIsGeneratingStyles] = useState(false);\n const [isGeneratingScripts, setIsGeneratingScripts] = useState(false);\n const appendedStylesRef = useRef<HTMLStyleElement[]>([]);\n const appendedScriptsRef = useRef<HTMLScriptElement[]>([]);\n const styleStartRef = useRef(0);\n const scriptStartRef = useRef(0);\n const styleTimerRef = useRef<number | null>(null);\n const scriptTimerRef = useRef<number | null>(null);\n const hasStylesRef = useRef(false);\n const hasScriptsRef = useRef(false);\n const hasRenderedContentRef = useRef(false);\n const prevResetTokenRef = useRef(resetToken);\n const MIN_LOADING_MS = 200;\n\n const clearTimer = (timerRef: React.MutableRefObject<number | null>) => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const settleStateWithMinimumDelay = (\n setter: React.Dispatch<React.SetStateAction<boolean>>,\n timerRef: React.MutableRefObject<number | null>,\n startRef: React.MutableRefObject<number>,\n onDone?: () => void\n ) => {\n const elapsed = performance.now() - startRef.current;\n const delay = Math.max(0, MIN_LOADING_MS - elapsed);\n clearTimer(timerRef);\n timerRef.current = window.setTimeout(() => {\n setter(false);\n onDone?.();\n timerRef.current = null;\n }, delay);\n };\n\n useEffect(() => {\n const doc = containerRef.current?.ownerDocument;\n if (!doc) return;\n const styleId = \"sandbox-spinner-style\";\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = doc.createElement(\"style\");\n styleEl.id = styleId;\n doc.head?.appendChild(styleEl);\n }\n styleEl.textContent = `\n .sandbox-wrapper { align-items: center; }\n .sandbox-container { position: relative; width: 100%; }\n .sandbox-container svg,\n .sandbox-container img { display: block; margin-left: auto; margin-right: auto; }\n .justify-\\\\[safe_center\\\\]{\n justify-content: safe center;\n }\n .overflow-y-auto { overflow-y: visible !important; }\n `;\n }, []);\n\n useEffect(() => {\n if (resetToken !== prevResetTokenRef.current) {\n hasRenderedContentRef.current = false;\n prevResetTokenRef.current = resetToken;\n }\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n\n const container = containerRef.current;\n if (!container) return;\n const doc = container.ownerDocument;\n const body = doc?.body;\n if (!body) return;\n const reusableImages = collectReusableImages(container);\n\n appendedStylesRef.current.forEach((node) => node.remove());\n appendedStylesRef.current = [];\n appendedScriptsRef.current.forEach((node) => node.remove());\n appendedScriptsRef.current = [];\n\n // const hasRenderedBefore = hasRenderedContentRef.current;\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n const wrapper = doc.createElement(\"div\");\n wrapper.innerHTML = html;\n\n const openScriptCount = (html.match(/<script[\\s>]/gi) || []).length;\n const closeScriptCount = (html.match(/<\\/script>/gi) || []).length;\n const shouldExecuteScripts =\n openScriptCount > 0 && openScriptCount === closeScriptCount;\n\n const resourceQueue: HTMLElement[] = [];\n\n Array.from(wrapper.querySelectorAll(\"style, script\")).forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n const cloned = doc.createElement(\"style\");\n cloned.textContent = node.textContent || \"\";\n Array.from(node.attributes).forEach((attr) => {\n cloned.setAttribute(attr.name, attr.value);\n });\n resourceQueue.push(cloned);\n } else {\n const replacement = doc.createElement(\"script\");\n Array.from(node.attributes).forEach((attr) => {\n replacement.setAttribute(attr.name, attr.value);\n });\n replacement.textContent = node.textContent || \"\";\n resourceQueue.push(replacement);\n }\n node.remove();\n });\n reuseRenderedImages(wrapper, reusableImages);\n\n const hasStyles = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"style\"\n );\n const hasScripts = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"script\"\n );\n if (hasStyles) {\n hasStylesRef.current = true;\n styleStartRef.current = performance.now();\n clearTimer(styleTimerRef);\n setIsGeneratingStyles(true);\n }\n if (hasScripts) {\n hasScriptsRef.current = true;\n scriptStartRef.current = performance.now();\n clearTimer(scriptTimerRef);\n setIsGeneratingScripts(true);\n }\n\n const hasFirstElement = !!wrapper.firstElementChild;\n if (hasFirstElement) {\n hasRenderedContentRef.current = true;\n }\n\n const contentNodes = Array.from(wrapper.childNodes);\n container.replaceChildren(...contentNodes);\n\n resourceQueue.forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n doc.head?.appendChild(node);\n appendedStylesRef.current.push(node as HTMLStyleElement);\n return;\n }\n\n if (shouldExecuteScripts) {\n const scriptNode = node as HTMLScriptElement;\n const scriptText = scriptNode.textContent || \"\";\n const shouldValidate = !scriptNode.src;\n\n if (shouldValidate) {\n try {\n // Validate script is syntactically complete before executing\n\n new Function(scriptText);\n } catch {\n scriptNode.remove();\n return;\n }\n }\n\n try {\n body.appendChild(scriptNode);\n appendedScriptsRef.current.push(scriptNode);\n } catch {\n scriptNode.remove();\n }\n } else {\n // Defer execution until all script tags are fully received\n node.remove();\n }\n });\n if (enableScaling) {\n const win = container.ownerDocument?.defaultView as ScalingWindow | null;\n win?.__mdf_triggerFitContent?.();\n }\n\n requestAnimationFrame(() => {\n if (hasStyles) {\n settleStateWithMinimumDelay(\n setIsGeneratingStyles,\n styleTimerRef,\n styleStartRef,\n () => {\n hasStylesRef.current = false;\n }\n );\n }\n if (hasScripts) {\n settleStateWithMinimumDelay(\n setIsGeneratingScripts,\n scriptTimerRef,\n scriptStartRef,\n () => {\n hasScriptsRef.current = false;\n }\n );\n }\n });\n }, [html, resetToken, enableScaling]);\n\n useEffect(\n () => () => {\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n },\n []\n );\n\n const overlayMessage = (() => {\n if (isGeneratingScripts || hasScriptsRef.current)\n return scriptLoadingText || \"Building scripts cache...\";\n if (isGeneratingStyles || hasStylesRef.current)\n return styleLoadingText || \"Building styles...\";\n return null;\n })();\n\n const isBlackboard = mode === \"blackboard\";\n const shouldStretchRootHeight = isBlackboard && stretchRootHeight;\n const sandboxWrapperStyle: React.CSSProperties = {\n position: \"relative\",\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n // Keep blackboard scroll behavior while centering content in non-blackboard mode\n justifyContent: shouldStretchRootHeight\n ? \"flex-start\"\n : isBlackboard\n ? \"space-around\"\n : \"flex-start\",\n };\n const sandboxContainerStyle: React.CSSProperties = {\n pointerEvents: overlayMessage ? \"none\" : undefined,\n margin: isBlackboard ? undefined : \"auto 0\",\n width: \"100%\",\n height: shouldStretchRootHeight ? \"100%\" : undefined,\n minHeight: shouldStretchRootHeight ? 0 : undefined,\n flex: shouldStretchRootHeight ? \"1 1 auto\" : undefined,\n };\n\n return (\n <div\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className=\"sandbox-wrapper\"\n style={sandboxWrapperStyle}\n aria-busy={!!overlayMessage}\n >\n <div\n ref={containerRef}\n className=\"sandbox-container\"\n style={sandboxContainerStyle}\n />\n {overlayMessage && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 20,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"none\",\n }}\n >\n <LoadingOverlayCard message={overlayMessage} />\n </div>\n )}\n </div>\n );\n};\n\nexport default SandboxApp;\n"],"names":["IMAGE_REUSE_ATTRIBUTES","getImageReuseKey","image","attribute","collectReusableImages","root","imageMap","node","key","bucket","syncImageAttributes","sourceImage","targetImage","sourceAttributes","sourceAttributeNames","reuseRenderedImages","nextImage","preservedImage","SandboxApp","html","styleLoadingText","scriptLoadingText","resetToken","mode","hasRootVhHeight","stretchRootHeight","enableScaling","containerRef","useRef","isGeneratingStyles","setIsGeneratingStyles","useState","isGeneratingScripts","setIsGeneratingScripts","appendedStylesRef","appendedScriptsRef","styleStartRef","scriptStartRef","styleTimerRef","scriptTimerRef","hasStylesRef","hasScriptsRef","hasRenderedContentRef","prevResetTokenRef","MIN_LOADING_MS","clearTimer","timerRef","settleStateWithMinimumDelay","setter","startRef","onDone","elapsed","delay","useEffect","doc","styleId","styleEl","container","body","reusableImages","wrapper","openScriptCount","closeScriptCount","shouldExecuteScripts","resourceQueue","cloned","attr","replacement","hasStyles","hasScripts","contentNodes","scriptNode","scriptText","overlayMessage","isBlackboard","shouldStretchRootHeight","sandboxWrapperStyle","sandboxContainerStyle","jsxs","jsx","LoadingOverlayCard"],"mappings":"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"}
1
+ {"version":3,"file":"SandboxApp.cjs.js","sources":["../../../src/components/ContentRender/SandboxApp.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport LoadingOverlayCard from \"../ui/loading-overlay-card\";\nimport type { ScalingWindow } from \"./utils/iframe-scaling\";\n\nexport interface SandboxAppProps {\n html: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n resetToken?: number;\n mode?: \"content\" | \"blackboard\";\n hasRootVhHeight?: boolean;\n stretchRootHeight?: boolean;\n enableScaling?: boolean;\n disableLoadingOverlay?: boolean;\n}\n\nconst IMAGE_REUSE_ATTRIBUTES = [\n \"src\",\n \"srcset\",\n \"sizes\",\n \"alt\",\n \"class\",\n \"width\",\n \"height\",\n \"style\",\n \"loading\",\n \"decoding\",\n \"crossorigin\",\n \"referrerpolicy\",\n \"fetchpriority\",\n];\n\nconst getImageReuseKey = (image: HTMLImageElement) =>\n IMAGE_REUSE_ATTRIBUTES.map(\n (attribute) => `${attribute}:${image.getAttribute(attribute) || \"\"}`\n ).join(\"|\");\n\nconst collectReusableImages = (root: ParentNode) => {\n const imageMap = new Map<string, HTMLImageElement[]>();\n root.querySelectorAll(\"img\").forEach((node) => {\n const image = node as HTMLImageElement;\n const key = getImageReuseKey(image);\n const bucket = imageMap.get(key) || [];\n bucket.push(image);\n imageMap.set(key, bucket);\n });\n return imageMap;\n};\n\nconst syncImageAttributes = (\n sourceImage: HTMLImageElement,\n targetImage: HTMLImageElement\n) => {\n const sourceAttributes = Array.from(sourceImage.attributes);\n const sourceAttributeNames = new Set(\n sourceAttributes.map((attribute) => attribute.name)\n );\n\n Array.from(targetImage.attributes).forEach((attribute) => {\n if (!sourceAttributeNames.has(attribute.name)) {\n targetImage.removeAttribute(attribute.name);\n }\n });\n\n sourceAttributes.forEach((attribute) => {\n targetImage.setAttribute(attribute.name, attribute.value);\n });\n};\n\nconst reuseRenderedImages = (\n root: ParentNode,\n imageMap: Map<string, HTMLImageElement[]>\n) => {\n if (!imageMap.size) return;\n\n root.querySelectorAll(\"img\").forEach((node) => {\n const nextImage = node as HTMLImageElement;\n const key = getImageReuseKey(nextImage);\n const bucket = imageMap.get(key);\n const preservedImage = bucket?.shift();\n if (!preservedImage) return;\n\n syncImageAttributes(nextImage, preservedImage);\n nextImage.replaceWith(preservedImage);\n\n if (bucket && bucket.length === 0) {\n imageMap.delete(key);\n }\n });\n};\n\nconst SandboxApp: React.FC<SandboxAppProps> = ({\n html,\n styleLoadingText,\n scriptLoadingText,\n resetToken = 0,\n mode = \"content\",\n hasRootVhHeight = false,\n stretchRootHeight = false,\n enableScaling = false,\n disableLoadingOverlay = false,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const [isGeneratingStyles, setIsGeneratingStyles] = useState(false);\n const [isGeneratingScripts, setIsGeneratingScripts] = useState(false);\n const appendedStylesRef = useRef<HTMLStyleElement[]>([]);\n const appendedScriptsRef = useRef<HTMLScriptElement[]>([]);\n const styleStartRef = useRef(0);\n const scriptStartRef = useRef(0);\n const styleTimerRef = useRef<number | null>(null);\n const scriptTimerRef = useRef<number | null>(null);\n const hasStylesRef = useRef(false);\n const hasScriptsRef = useRef(false);\n const hasRenderedContentRef = useRef(false);\n const prevResetTokenRef = useRef(resetToken);\n const MIN_LOADING_MS = 200;\n\n const clearTimer = (timerRef: React.MutableRefObject<number | null>) => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const settleStateWithMinimumDelay = (\n setter: React.Dispatch<React.SetStateAction<boolean>>,\n timerRef: React.MutableRefObject<number | null>,\n startRef: React.MutableRefObject<number>,\n onDone?: () => void\n ) => {\n const elapsed = performance.now() - startRef.current;\n const delay = Math.max(0, MIN_LOADING_MS - elapsed);\n clearTimer(timerRef);\n timerRef.current = window.setTimeout(() => {\n setter(false);\n onDone?.();\n timerRef.current = null;\n }, delay);\n };\n\n useEffect(() => {\n const doc = containerRef.current?.ownerDocument;\n if (!doc) return;\n const styleId = \"sandbox-spinner-style\";\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = doc.createElement(\"style\");\n styleEl.id = styleId;\n doc.head?.appendChild(styleEl);\n }\n styleEl.textContent = `\n .sandbox-wrapper { align-items: center; }\n .sandbox-container { position: relative; width: 100%; }\n .sandbox-container svg,\n .sandbox-container img { display: block; margin-left: auto; margin-right: auto; }\n .justify-\\\\[safe_center\\\\]{\n justify-content: safe center;\n }\n .overflow-y-auto { overflow-y: visible !important; }\n `;\n }, []);\n\n useEffect(() => {\n if (resetToken !== prevResetTokenRef.current) {\n hasRenderedContentRef.current = false;\n prevResetTokenRef.current = resetToken;\n }\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n\n const container = containerRef.current;\n if (!container) return;\n const doc = container.ownerDocument;\n const body = doc?.body;\n if (!body) return;\n const reusableImages = collectReusableImages(container);\n\n appendedStylesRef.current.forEach((node) => node.remove());\n appendedStylesRef.current = [];\n appendedScriptsRef.current.forEach((node) => node.remove());\n appendedScriptsRef.current = [];\n\n // const hasRenderedBefore = hasRenderedContentRef.current;\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n const wrapper = doc.createElement(\"div\");\n wrapper.innerHTML = html;\n\n const openScriptCount = (html.match(/<script[\\s>]/gi) || []).length;\n const closeScriptCount = (html.match(/<\\/script>/gi) || []).length;\n const shouldExecuteScripts =\n openScriptCount > 0 && openScriptCount === closeScriptCount;\n\n const resourceQueue: HTMLElement[] = [];\n\n Array.from(wrapper.querySelectorAll(\"style, script\")).forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n const cloned = doc.createElement(\"style\");\n cloned.textContent = node.textContent || \"\";\n Array.from(node.attributes).forEach((attr) => {\n cloned.setAttribute(attr.name, attr.value);\n });\n resourceQueue.push(cloned);\n } else {\n const replacement = doc.createElement(\"script\");\n Array.from(node.attributes).forEach((attr) => {\n replacement.setAttribute(attr.name, attr.value);\n });\n replacement.textContent = node.textContent || \"\";\n resourceQueue.push(replacement);\n }\n node.remove();\n });\n reuseRenderedImages(wrapper, reusableImages);\n\n const hasStyles = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"style\"\n );\n const hasScripts = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"script\"\n );\n if (hasStyles) {\n hasStylesRef.current = true;\n styleStartRef.current = performance.now();\n clearTimer(styleTimerRef);\n setIsGeneratingStyles(true);\n }\n if (hasScripts) {\n hasScriptsRef.current = true;\n scriptStartRef.current = performance.now();\n clearTimer(scriptTimerRef);\n setIsGeneratingScripts(true);\n }\n\n const hasFirstElement = !!wrapper.firstElementChild;\n if (hasFirstElement) {\n hasRenderedContentRef.current = true;\n }\n\n const contentNodes = Array.from(wrapper.childNodes);\n container.replaceChildren(...contentNodes);\n\n resourceQueue.forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n doc.head?.appendChild(node);\n appendedStylesRef.current.push(node as HTMLStyleElement);\n return;\n }\n\n if (shouldExecuteScripts) {\n const scriptNode = node as HTMLScriptElement;\n const scriptText = scriptNode.textContent || \"\";\n const shouldValidate = !scriptNode.src;\n\n if (shouldValidate) {\n try {\n // Validate script is syntactically complete before executing\n\n new Function(scriptText);\n } catch {\n scriptNode.remove();\n return;\n }\n }\n\n try {\n body.appendChild(scriptNode);\n appendedScriptsRef.current.push(scriptNode);\n } catch {\n scriptNode.remove();\n }\n } else {\n // Defer execution until all script tags are fully received\n node.remove();\n }\n });\n if (enableScaling) {\n const win = container.ownerDocument?.defaultView as ScalingWindow | null;\n win?.__mdf_triggerFitContent?.();\n }\n\n requestAnimationFrame(() => {\n if (hasStyles) {\n settleStateWithMinimumDelay(\n setIsGeneratingStyles,\n styleTimerRef,\n styleStartRef,\n () => {\n hasStylesRef.current = false;\n }\n );\n }\n if (hasScripts) {\n settleStateWithMinimumDelay(\n setIsGeneratingScripts,\n scriptTimerRef,\n scriptStartRef,\n () => {\n hasScriptsRef.current = false;\n }\n );\n }\n });\n }, [html, resetToken, enableScaling]);\n\n useEffect(\n () => () => {\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n },\n []\n );\n\n useEffect(() => {\n if (!disableLoadingOverlay) {\n return;\n }\n\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n }, [disableLoadingOverlay]);\n\n const overlayMessage = (() => {\n if (disableLoadingOverlay) {\n return null;\n }\n\n if (isGeneratingScripts || hasScriptsRef.current)\n return scriptLoadingText || \"Building scripts cache...\";\n if (isGeneratingStyles || hasStylesRef.current)\n return styleLoadingText || \"Building styles...\";\n return null;\n })();\n\n const isBlackboard = mode === \"blackboard\";\n const shouldStretchRootHeight = isBlackboard && stretchRootHeight;\n const sandboxWrapperStyle: React.CSSProperties = {\n position: \"relative\",\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n // Keep blackboard scroll behavior while centering content in non-blackboard mode\n justifyContent: shouldStretchRootHeight\n ? \"flex-start\"\n : isBlackboard\n ? \"space-around\"\n : \"flex-start\",\n };\n const sandboxContainerStyle: React.CSSProperties = {\n pointerEvents: overlayMessage ? \"none\" : undefined,\n margin: isBlackboard ? undefined : \"auto 0\",\n width: \"100%\",\n height: shouldStretchRootHeight ? \"100%\" : undefined,\n minHeight: shouldStretchRootHeight ? 0 : undefined,\n flex: shouldStretchRootHeight ? \"1 1 auto\" : undefined,\n };\n\n return (\n <div\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className=\"sandbox-wrapper\"\n style={sandboxWrapperStyle}\n aria-busy={!!overlayMessage}\n >\n <div\n ref={containerRef}\n className=\"sandbox-container\"\n style={sandboxContainerStyle}\n />\n {overlayMessage && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 20,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"none\",\n }}\n >\n <LoadingOverlayCard message={overlayMessage} />\n </div>\n )}\n </div>\n );\n};\n\nexport default SandboxApp;\n"],"names":["IMAGE_REUSE_ATTRIBUTES","getImageReuseKey","image","attribute","collectReusableImages","root","imageMap","node","key","bucket","syncImageAttributes","sourceImage","targetImage","sourceAttributes","sourceAttributeNames","reuseRenderedImages","nextImage","preservedImage","SandboxApp","html","styleLoadingText","scriptLoadingText","resetToken","mode","hasRootVhHeight","stretchRootHeight","enableScaling","disableLoadingOverlay","containerRef","useRef","isGeneratingStyles","setIsGeneratingStyles","useState","isGeneratingScripts","setIsGeneratingScripts","appendedStylesRef","appendedScriptsRef","styleStartRef","scriptStartRef","styleTimerRef","scriptTimerRef","hasStylesRef","hasScriptsRef","hasRenderedContentRef","prevResetTokenRef","MIN_LOADING_MS","clearTimer","timerRef","settleStateWithMinimumDelay","setter","startRef","onDone","elapsed","delay","useEffect","doc","styleId","styleEl","container","body","reusableImages","wrapper","openScriptCount","closeScriptCount","shouldExecuteScripts","resourceQueue","cloned","attr","replacement","hasStyles","hasScripts","contentNodes","scriptNode","scriptText","overlayMessage","isBlackboard","shouldStretchRootHeight","sandboxWrapperStyle","sandboxContainerStyle","jsxs","jsx","LoadingOverlayCard"],"mappings":"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"}
@@ -8,6 +8,7 @@ export interface SandboxAppProps {
8
8
  hasRootVhHeight?: boolean;
9
9
  stretchRootHeight?: boolean;
10
10
  enableScaling?: boolean;
11
+ disableLoadingOverlay?: boolean;
11
12
  }
12
13
  declare const SandboxApp: React.FC<SandboxAppProps>;
13
14
  export default SandboxApp;