markdown-flow-ui 0.2.1 → 0.2.2

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 (57) hide show
  1. package/dist/assets/markdown-flow-ui.css +1 -1
  2. package/dist/components/ContentRender/IframeSandbox.cjs.js +7 -7
  3. package/dist/components/ContentRender/IframeSandbox.cjs.js.map +1 -1
  4. package/dist/components/ContentRender/IframeSandbox.es.js +283 -252
  5. package/dist/components/ContentRender/IframeSandbox.es.js.map +1 -1
  6. package/dist/components/ContentRender/blackboard-vendor.cjs.js +1 -1
  7. package/dist/components/ContentRender/blackboard-vendor.cjs.js.map +1 -1
  8. package/dist/components/ContentRender/blackboard-vendor.d.ts +2 -0
  9. package/dist/components/ContentRender/blackboard-vendor.es.js +9 -12
  10. package/dist/components/ContentRender/blackboard-vendor.es.js.map +1 -1
  11. package/dist/components/ContentRender/utils/iframe-scaling.cjs.js +12 -9
  12. package/dist/components/ContentRender/utils/iframe-scaling.cjs.js.map +1 -1
  13. package/dist/components/ContentRender/utils/iframe-scaling.es.js +16 -12
  14. package/dist/components/ContentRender/utils/iframe-scaling.es.js.map +1 -1
  15. package/dist/components/ContentRender/utils/presentation-scaling.cjs.js +2 -0
  16. package/dist/components/ContentRender/utils/presentation-scaling.cjs.js.map +1 -0
  17. package/dist/components/ContentRender/utils/presentation-scaling.d.ts +34 -0
  18. package/dist/components/ContentRender/utils/presentation-scaling.es.js +67 -0
  19. package/dist/components/ContentRender/utils/presentation-scaling.es.js.map +1 -0
  20. package/dist/components/ContentRender/utils/presentation-scaling.test.d.ts +1 -0
  21. package/dist/components/ContentRender/utils/tailwind-runtime.cjs.js +2 -0
  22. package/dist/components/ContentRender/utils/tailwind-runtime.cjs.js.map +1 -0
  23. package/dist/components/ContentRender/utils/tailwind-runtime.d.ts +5 -0
  24. package/dist/components/ContentRender/utils/tailwind-runtime.es.js +11 -0
  25. package/dist/components/ContentRender/utils/tailwind-runtime.es.js.map +1 -0
  26. package/dist/components/ContentRender/utils/tailwind-runtime.test.d.ts +1 -0
  27. package/dist/components/Slide/MarkdownSlideScaling.cjs.js +2 -0
  28. package/dist/components/Slide/MarkdownSlideScaling.cjs.js.map +1 -0
  29. package/dist/components/Slide/MarkdownSlideScaling.d.ts +13 -0
  30. package/dist/components/Slide/MarkdownSlideScaling.es.js +109 -0
  31. package/dist/components/Slide/MarkdownSlideScaling.es.js.map +1 -0
  32. package/dist/components/Slide/Slide.cjs.js +1 -1
  33. package/dist/components/Slide/Slide.cjs.js.map +1 -1
  34. package/dist/components/Slide/Slide.d.ts +7 -0
  35. package/dist/components/Slide/Slide.es.js +448 -438
  36. package/dist/components/Slide/Slide.es.js.map +1 -1
  37. package/dist/components/Slide/Slide.stories.d.ts +2473 -0
  38. package/dist/components/Slide/utils/markdownScaling.cjs.js +2 -0
  39. package/dist/components/Slide/utils/markdownScaling.cjs.js.map +1 -0
  40. package/dist/components/Slide/utils/markdownScaling.d.ts +7 -0
  41. package/dist/components/Slide/utils/markdownScaling.es.js +12 -0
  42. package/dist/components/Slide/utils/markdownScaling.es.js.map +1 -0
  43. package/dist/components/Slide/utils/markdownScaling.test.d.ts +1 -0
  44. package/dist/markdown-flow-ui-lib.css +1 -1
  45. package/dist/node_modules/cose-base/cose-base.cjs.js +1 -1
  46. package/dist/node_modules/cose-base/cose-base.cjs.js.map +1 -1
  47. package/dist/node_modules/cose-base/cose-base.es.js +1 -1
  48. package/dist/node_modules/cytoscape-fcose/node_modules/cose-base/cose-base.cjs.js +1 -1
  49. package/dist/node_modules/cytoscape-fcose/node_modules/cose-base/cose-base.cjs.js.map +1 -1
  50. package/dist/node_modules/cytoscape-fcose/node_modules/cose-base/cose-base.es.js +1 -1
  51. package/dist/node_modules/cytoscape-fcose/node_modules/layout-base/layout-base.cjs.js +1 -1
  52. package/dist/node_modules/cytoscape-fcose/node_modules/layout-base/layout-base.cjs.js.map +1 -1
  53. package/dist/node_modules/cytoscape-fcose/node_modules/layout-base/layout-base.es.js +1 -1
  54. package/dist/node_modules/layout-base/layout-base.cjs.js +1 -1
  55. package/dist/node_modules/layout-base/layout-base.cjs.js.map +1 -1
  56. package/dist/node_modules/layout-base/layout-base.es.js +1 -1
  57. 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\";\nimport type { MarkdownFlowLocale } from \"../../lib/locale\";\nimport { getContentRenderLocaleTexts } from \"./contentRenderI18n\";\nimport { CJK_SAFE_SANS_FONT_FAMILY } from \"./cjkFontFamily\";\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 locale?: MarkdownFlowLocale;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n exitFullScreenButtonText?: 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 locale,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n exitFullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n replaceRootScreenHeightWithFull = false,\n enableScaling = false,\n disableLoadingOverlay = false,\n}) => {\n const localeTexts = getContentRenderLocaleTexts(locale);\n const resolvedFullScreenButtonText =\n fullScreenButtonText || localeTexts.sandboxFullscreenButtonText;\n const resolvedExitFullScreenButtonText =\n exitFullScreenButtonText || localeTexts.sandboxExitFullscreenButtonText;\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%; font-family: ${CJK_SAFE_SANS_FONT_FAMILY}; }\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 // Absolute height cap. Diverging vh-feedback (multiple `height:100vh`\n // siblings, or compound vh-relative children whose sum exceeds the\n // viewport) can otherwise grow the iframe geometrically across\n // repeated ResizeObserver/MutationObserver passes. 1:20 aspect is\n // a generous upper bound for any single sandbox slide.\n const maxH = Math.max(8192, cw * 20);\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 // Geometric vh-feedback detection: vh-relative children scale\n // with the iframe viewport, so growing the iframe makes them\n // larger which grows scrollHeight — runaway divergence. Two\n // `height:100vh` siblings produce a 2× per-iteration multiplier.\n // Stop iterating; keep the prior (stable) measuredH.\n if (nextH >= measuredH * 1.5) break;\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.min(maxH, 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 locale={locale}\n loadingText={loadingText}\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 locale,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n resetToken,\n disableLoadingOverlay,\n hasRootVhHeight,\n mode,\n shouldStretchRootHeight,\n shouldEnableScaling,\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\n ? resolvedExitFullScreenButtonText\n : resolvedFullScreenButtonText}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <div onClick={() => emitSandboxInteraction(\"click\")}>\n <ContentRender\n content={content}\n locale={locale}\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","locale","loadingText","styleLoadingText","scriptLoadingText","fullScreenButtonText","exitFullScreenButtonText","hideFullScreen","mode","replaceRootScreenHeightWithFull","enableScaling","disableLoadingOverlay","localeTexts","getContentRenderLocaleTexts","resolvedFullScreenButtonText","resolvedExitFullScreenButtonText","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","CJK_SAFE_SANS_FONT_FAMILY","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","maxH","measuredH","iframeWin","getInnerScrollableHeight","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\";\nimport type { MarkdownFlowLocale } from \"../../lib/locale\";\nimport { getContentRenderLocaleTexts } from \"./contentRenderI18n\";\nimport { CJK_SAFE_SANS_FONT_FAMILY } from \"./cjkFontFamily\";\n\ntype BlackboardVendorModule = typeof import(\"./blackboard-vendor\");\n\n// Cache the sandbox vendor loader so every iframe reuses the same preload request.\nlet blackboardVendorPromise: Promise<BlackboardVendorModule> | null = null;\n\nconst loadBlackboardVendor = () => {\n if (!blackboardVendorPromise) {\n blackboardVendorPromise = import(\"./blackboard-vendor\");\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 locale?: MarkdownFlowLocale;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n exitFullScreenButtonText?: 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 IframeSandboxInstance: React.FC<IframeSandboxProps> = ({\n content,\n type,\n className,\n locale,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n exitFullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n replaceRootScreenHeightWithFull = false,\n enableScaling = false,\n disableLoadingOverlay = false,\n}) => {\n const localeTexts = getContentRenderLocaleTexts(locale);\n const resolvedFullScreenButtonText =\n fullScreenButtonText || localeTexts.sandboxFullscreenButtonText;\n const resolvedExitFullScreenButtonText =\n exitFullScreenButtonText || localeTexts.sandboxExitFullscreenButtonText;\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%; font-family: ${CJK_SAFE_SANS_FONT_FAMILY}; }\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 // Absolute height cap. Diverging vh-feedback (multiple `height:100vh`\n // siblings, or compound vh-relative children whose sum exceeds the\n // viewport) can otherwise grow the iframe geometrically across\n // repeated ResizeObserver/MutationObserver passes. 1:20 aspect is\n // a generous upper bound for any single sandbox slide.\n const maxH = Math.max(8192, cw * 20);\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 // Geometric vh-feedback detection: vh-relative children scale\n // with the iframe viewport, so growing the iframe makes them\n // larger which grows scrollHeight — runaway divergence. Two\n // `height:100vh` siblings produce a 2× per-iteration multiplier.\n // Stop iterating; keep the prior (stable) measuredH.\n if (nextH >= measuredH * 1.5) break;\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.min(maxH, 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(({ injectBlackboardLibraries }) => {\n if (isDestroyed) return;\n injectBlackboardLibraries(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 hostElement = containerRef.current;\n let needsTailwindRefreshAfterHidden = Boolean(\n hostElement &&\n (hostElement.clientWidth <= 0 || hostElement.clientHeight <= 0)\n );\n let isTailwindRefreshQueued = false;\n let tailwindRefreshFrame: number | null = null;\n let tailwindRefreshTimer: number | null = null;\n const runPostTailwindRefreshLayout = () => {\n if (isDestroyed) return;\n scheduleHeightUpdate();\n const iframeWin = iframe.contentWindow as ScalingWindow | null;\n iframeWin?.__mdf_triggerFitContent?.();\n };\n const isHostVisible = () =>\n Boolean(\n hostElement &&\n hostElement.clientWidth > 0 &&\n hostElement.clientHeight > 0\n );\n const queueTailwindRefreshAfterHidden = () => {\n if (\n !shouldInjectSandboxVendor ||\n !hostElement ||\n !needsTailwindRefreshAfterHidden ||\n isTailwindRefreshQueued ||\n !isHostVisible()\n ) {\n return;\n }\n\n isTailwindRefreshQueued = true;\n loadBlackboardVendor()\n .then(({ refreshTailwindRuntime }) => {\n if (isDestroyed) return;\n\n tailwindRefreshFrame = window.requestAnimationFrame(() => {\n tailwindRefreshFrame = null;\n isTailwindRefreshQueued = false;\n\n const sandboxContainer = doc.querySelector(\".sandbox-container\");\n if (\n isDestroyed ||\n !isHostVisible() ||\n !sandboxContainer?.childNodes.length ||\n !refreshTailwindRuntime(doc)\n ) {\n return;\n }\n\n needsTailwindRefreshAfterHidden = false;\n runPostTailwindRefreshLayout();\n tailwindRefreshTimer = window.setTimeout(() => {\n tailwindRefreshTimer = null;\n runPostTailwindRefreshLayout();\n }, 100);\n });\n })\n .catch(() => {\n isTailwindRefreshQueued = false;\n });\n };\n const canObserveResize = typeof ResizeObserver !== \"undefined\";\n const hostResizeObserver =\n shouldInjectSandboxVendor && hostElement && canObserveResize\n ? new ResizeObserver((entries) => {\n const contentRect = entries[0]?.contentRect;\n const hostWidth = contentRect?.width ?? hostElement.clientWidth;\n const hostHeight = contentRect?.height ?? hostElement.clientHeight;\n const isHostSizeVisible = hostWidth > 0 && hostHeight > 0;\n\n if (!isHostSizeVisible) {\n return;\n }\n\n queueTailwindRefreshAfterHidden();\n })\n : null;\n if (hostResizeObserver && hostElement) {\n hostResizeObserver.observe(hostElement);\n }\n\n const resizeObserver = canObserveResize\n ? new ResizeObserver(() => updateHeight())\n : null;\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 if (!isHostVisible()) {\n needsTailwindRefreshAfterHidden = true;\n return;\n }\n queueTailwindRefreshAfterHidden();\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 hostResizeObserver?.disconnect();\n resizeObserver?.disconnect();\n mutationObserver.disconnect();\n if (tailwindRefreshFrame !== null) {\n window.cancelAnimationFrame(tailwindRefreshFrame);\n }\n if (tailwindRefreshTimer !== null) {\n window.clearTimeout(tailwindRefreshTimer);\n }\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 if (rootRef.current === root) {\n rootRef.current = null;\n updateHeightRef.current = () => {};\n }\n // Defer unmount to avoid React warning when parent is mid-render\n setTimeout(() => {\n root.unmount();\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 if (typeof ResizeObserver === \"undefined\") {\n setContainerWidth(el.clientWidth);\n return;\n }\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 locale={locale}\n loadingText={loadingText}\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 if (initialPaintFrameRef.current !== null) {\n window.cancelAnimationFrame(initialPaintFrameRef.current);\n initialPaintFrameRef.current = null;\n }\n clearTimeout(t1);\n clearTimeout(t2);\n };\n }, [\n renderHtmlContent,\n locale,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n resetToken,\n disableLoadingOverlay,\n hasRootVhHeight,\n mode,\n shouldStretchRootHeight,\n shouldEnableScaling,\n ]);\n const containerClassName = [\n `w-full relative content-render-iframe-sandbox content-render-iframe-sandbox--${type}`,\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\n ? resolvedExitFullScreenButtonText\n : resolvedFullScreenButtonText}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <div onClick={() => emitSandboxInteraction(\"click\")}>\n <ContentRender\n content={content}\n locale={locale}\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\nconst IframeSandbox: React.FC<IframeSandboxProps> = (props) => {\n const mode = props.mode ?? \"content\";\n const shouldEnableScaling = Boolean(\n props.enableScaling && mode === \"blackboard\" && props.type === \"sandbox\"\n );\n // The iframe shell captures these initialization-only values. Remounting the\n // inner instance keeps old and new React roots from sharing cleanup refs.\n const lifecycleKey = `${props.type}:${mode}:${shouldEnableScaling ? \"scaled\" : \"unscaled\"}`;\n\n return <IframeSandboxInstance key={lifecycleKey} {...props} />;\n};\n\nexport default IframeSandbox;\n"],"names":["blackboardVendorPromise","loadBlackboardVendor","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","IframeSandboxInstance","content","type","locale","loadingText","styleLoadingText","scriptLoadingText","fullScreenButtonText","exitFullScreenButtonText","hideFullScreen","mode","replaceRootScreenHeightWithFull","enableScaling","disableLoadingOverlay","localeTexts","getContentRenderLocaleTexts","resolvedFullScreenButtonText","resolvedExitFullScreenButtonText","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","CJK_SAFE_SANS_FONT_FAMILY","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","maxH","measuredH","iframeWin","getInnerScrollableHeight","walk","el","oy","rect","child","i","nextH","next","scheduleHeightUpdate","bodyScrollH","htmlScrollH","rootScrollH","measuredHeight","explicitHeight","nextHeight","prevHeight","injectBlackboardLibraries","injectScalingSystem","hostElement","needsTailwindRefreshAfterHidden","isTailwindRefreshQueued","tailwindRefreshFrame","tailwindRefreshTimer","runPostTailwindRefreshLayout","isHostVisible","queueTailwindRefreshAfterHidden","refreshTailwindRuntime","sandboxContainer","canObserveResize","hostResizeObserver","entries","contentRect","hostWidth","hostHeight","resizeObserver","mutationObserver","onFullscreenChange","ro","contentModeStyle","useMemo","toggleFullscreen","target","jsx","SandboxApp","t1","t2","containerClassName","jsxs","ContentRender","IframeSandbox","props","lifecycleKey"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("./vendor/tailwindcss-v3.min.cjs.js"),r=require("./vendor/daisyui-v4.min.css.cjs.js"),s=require("./vendor/gsap-v3.min.cjs.js"),d=require("./cjkFontFamily.cjs.js");function c(e){const i=e.createElement("script");i.textContent=l.default,e.head.appendChild(i);const t=e.defaultView?.tailwind;t&&(t.config=d.addCjkSafeSansToTailwindConfig(t.config));const n=e.createElement("style");n.textContent=r.default,e.head.appendChild(n);const a=e.createElement("script");a.textContent=s.default,e.head.appendChild(a)}exports.injectBlackboardLibraries=c;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./vendor/tailwindcss-v3.min.cjs.js"),l=require("./vendor/daisyui-v4.min.css.cjs.js"),s=require("./vendor/gsap-v3.min.cjs.js"),a=require("./utils/tailwind-runtime.cjs.js");function d(e){const t=e.createElement("script");t.textContent=r.default,e.head.appendChild(t),a.refreshTailwindRuntime(e);const i=e.createElement("style");i.textContent=l.default,e.head.appendChild(i);const n=e.createElement("script");n.textContent=s.default,e.head.appendChild(n)}exports.refreshTailwindRuntime=a.refreshTailwindRuntime;exports.injectBlackboardLibraries=d;
2
2
  //# sourceMappingURL=blackboard-vendor.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"blackboard-vendor.cjs.js","sources":["../../../src/components/ContentRender/blackboard-vendor.ts"],"sourcesContent":["import tailwindScript from \"./vendor/tailwindcss-v3.min.js?raw\";\nimport daisyuiCss from \"./vendor/daisyui-v4.min.css?raw\";\nimport gsapScript from \"./vendor/gsap-v3.min.js?raw\";\nimport { addCjkSafeSansToTailwindConfig } from \"./cjkFontFamily\";\n\ninterface TailwindRuntimeWindow extends Window {\n tailwind?: {\n config?: unknown;\n };\n}\n\n/**\n * Inject blackboard-mode libraries (Tailwind CSS, DaisyUI, GSAP)\n * into an iframe document using DOM API to avoid template-string escaping issues.\n */\nexport function injectBlackboardLibraries(doc: Document): void {\n // 1. Tailwind CSS v3 (JIT compiler, must load first)\n const tailwindEl = doc.createElement(\"script\");\n tailwindEl.textContent = tailwindScript;\n // The Play CDN script replaces window.tailwind with its Proxy during execution,\n // so configure that runtime only after the synchronous append completes.\n doc.head.appendChild(tailwindEl);\n const tailwindRuntime = (doc.defaultView as TailwindRuntimeWindow | null)\n ?.tailwind;\n if (tailwindRuntime) {\n tailwindRuntime.config = addCjkSafeSansToTailwindConfig(\n tailwindRuntime.config\n );\n }\n\n // 2. DaisyUI v4 CSS\n const daisyuiEl = doc.createElement(\"style\");\n daisyuiEl.textContent = daisyuiCss;\n doc.head.appendChild(daisyuiEl);\n\n // 3. GSAP v3\n const gsapEl = doc.createElement(\"script\");\n gsapEl.textContent = gsapScript;\n doc.head.appendChild(gsapEl);\n}\n"],"names":["injectBlackboardLibraries","doc","tailwindEl","tailwindScript","tailwindRuntime","addCjkSafeSansToTailwindConfig","daisyuiEl","daisyuiCss","gsapEl","gsapScript"],"mappings":"mQAeO,SAASA,EAA0BC,EAAqB,CAE7D,MAAMC,EAAaD,EAAI,cAAc,QAAQ,EAC7CC,EAAW,YAAcC,EAAAA,QAGzBF,EAAI,KAAK,YAAYC,CAAU,EAC/B,MAAME,EAAmBH,EAAI,aACzB,SACAG,IACFA,EAAgB,OAASC,EAAAA,+BACvBD,EAAgB,MAAA,GAKpB,MAAME,EAAYL,EAAI,cAAc,OAAO,EAC3CK,EAAU,YAAcC,EAAAA,QACxBN,EAAI,KAAK,YAAYK,CAAS,EAG9B,MAAME,EAASP,EAAI,cAAc,QAAQ,EACzCO,EAAO,YAAcC,EAAAA,QACrBR,EAAI,KAAK,YAAYO,CAAM,CAC7B"}
1
+ {"version":3,"file":"blackboard-vendor.cjs.js","sources":["../../../src/components/ContentRender/blackboard-vendor.ts"],"sourcesContent":["import tailwindScript from \"./vendor/tailwindcss-v3.min.js?raw\";\nimport daisyuiCss from \"./vendor/daisyui-v4.min.css?raw\";\nimport gsapScript from \"./vendor/gsap-v3.min.js?raw\";\nimport { refreshTailwindRuntime } from \"./utils/tailwind-runtime\";\n\nexport { refreshTailwindRuntime };\n\n/**\n * Inject blackboard-mode libraries (Tailwind CSS, DaisyUI, GSAP)\n * into an iframe document using DOM API to avoid template-string escaping issues.\n */\nexport function injectBlackboardLibraries(doc: Document): void {\n // 1. Tailwind CSS v3 (JIT compiler, must load first)\n const tailwindEl = doc.createElement(\"script\");\n tailwindEl.textContent = tailwindScript;\n // The Play CDN script replaces window.tailwind with its Proxy during execution,\n // so configure that runtime only after the synchronous append completes.\n doc.head.appendChild(tailwindEl);\n refreshTailwindRuntime(doc);\n\n // 2. DaisyUI v4 CSS\n const daisyuiEl = doc.createElement(\"style\");\n daisyuiEl.textContent = daisyuiCss;\n doc.head.appendChild(daisyuiEl);\n\n // 3. GSAP v3\n const gsapEl = doc.createElement(\"script\");\n gsapEl.textContent = gsapScript;\n doc.head.appendChild(gsapEl);\n}\n"],"names":["injectBlackboardLibraries","doc","tailwindEl","tailwindScript","refreshTailwindRuntime","daisyuiEl","daisyuiCss","gsapEl","gsapScript"],"mappings":"4QAWO,SAASA,EAA0BC,EAAqB,CAE7D,MAAMC,EAAaD,EAAI,cAAc,QAAQ,EAC7CC,EAAW,YAAcC,EAAAA,QAGzBF,EAAI,KAAK,YAAYC,CAAU,EAC/BE,EAAAA,uBAAuBH,CAAG,EAG1B,MAAMI,EAAYJ,EAAI,cAAc,OAAO,EAC3CI,EAAU,YAAcC,EAAAA,QACxBL,EAAI,KAAK,YAAYI,CAAS,EAG9B,MAAME,EAASN,EAAI,cAAc,QAAQ,EACzCM,EAAO,YAAcC,EAAAA,QACrBP,EAAI,KAAK,YAAYM,CAAM,CAC7B"}
@@ -1,3 +1,5 @@
1
+ import { refreshTailwindRuntime } from './utils/tailwind-runtime';
2
+ export { refreshTailwindRuntime };
1
3
  /**
2
4
  * Inject blackboard-mode libraries (Tailwind CSS, DaisyUI, GSAP)
3
5
  * into an iframe document using DOM API to avoid template-string escaping issues.
@@ -1,20 +1,17 @@
1
1
  import r from "./vendor/tailwindcss-v3.min.es.js";
2
- import l from "./vendor/daisyui-v4.min.css.es.js";
2
+ import a from "./vendor/daisyui-v4.min.css.es.js";
3
3
  import p from "./vendor/gsap-v3.min.es.js";
4
- import { addCjkSafeSansToTailwindConfig as o } from "./cjkFontFamily.es.js";
4
+ import { refreshTailwindRuntime as l } from "./utils/tailwind-runtime.es.js";
5
5
  function c(t) {
6
6
  const e = t.createElement("script");
7
- e.textContent = r, t.head.appendChild(e);
8
- const i = t.defaultView?.tailwind;
9
- i && (i.config = o(
10
- i.config
11
- ));
12
- const n = t.createElement("style");
13
- n.textContent = l, t.head.appendChild(n);
14
- const a = t.createElement("script");
15
- a.textContent = p, t.head.appendChild(a);
7
+ e.textContent = r, t.head.appendChild(e), l(t);
8
+ const i = t.createElement("style");
9
+ i.textContent = a, t.head.appendChild(i);
10
+ const n = t.createElement("script");
11
+ n.textContent = p, t.head.appendChild(n);
16
12
  }
17
13
  export {
18
- c as injectBlackboardLibraries
14
+ c as injectBlackboardLibraries,
15
+ l as refreshTailwindRuntime
19
16
  };
20
17
  //# sourceMappingURL=blackboard-vendor.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"blackboard-vendor.es.js","sources":["../../../src/components/ContentRender/blackboard-vendor.ts"],"sourcesContent":["import tailwindScript from \"./vendor/tailwindcss-v3.min.js?raw\";\nimport daisyuiCss from \"./vendor/daisyui-v4.min.css?raw\";\nimport gsapScript from \"./vendor/gsap-v3.min.js?raw\";\nimport { addCjkSafeSansToTailwindConfig } from \"./cjkFontFamily\";\n\ninterface TailwindRuntimeWindow extends Window {\n tailwind?: {\n config?: unknown;\n };\n}\n\n/**\n * Inject blackboard-mode libraries (Tailwind CSS, DaisyUI, GSAP)\n * into an iframe document using DOM API to avoid template-string escaping issues.\n */\nexport function injectBlackboardLibraries(doc: Document): void {\n // 1. Tailwind CSS v3 (JIT compiler, must load first)\n const tailwindEl = doc.createElement(\"script\");\n tailwindEl.textContent = tailwindScript;\n // The Play CDN script replaces window.tailwind with its Proxy during execution,\n // so configure that runtime only after the synchronous append completes.\n doc.head.appendChild(tailwindEl);\n const tailwindRuntime = (doc.defaultView as TailwindRuntimeWindow | null)\n ?.tailwind;\n if (tailwindRuntime) {\n tailwindRuntime.config = addCjkSafeSansToTailwindConfig(\n tailwindRuntime.config\n );\n }\n\n // 2. DaisyUI v4 CSS\n const daisyuiEl = doc.createElement(\"style\");\n daisyuiEl.textContent = daisyuiCss;\n doc.head.appendChild(daisyuiEl);\n\n // 3. GSAP v3\n const gsapEl = doc.createElement(\"script\");\n gsapEl.textContent = gsapScript;\n doc.head.appendChild(gsapEl);\n}\n"],"names":["injectBlackboardLibraries","doc","tailwindEl","tailwindScript","tailwindRuntime","addCjkSafeSansToTailwindConfig","daisyuiEl","daisyuiCss","gsapEl","gsapScript"],"mappings":";;;;AAeO,SAASA,EAA0BC,GAAqB;AAE7D,QAAMC,IAAaD,EAAI,cAAc,QAAQ;AAC7C,EAAAC,EAAW,cAAcC,GAGzBF,EAAI,KAAK,YAAYC,CAAU;AAC/B,QAAME,IAAmBH,EAAI,aACzB;AACJ,EAAIG,MACFA,EAAgB,SAASC;AAAA,IACvBD,EAAgB;AAAA,EAAA;AAKpB,QAAME,IAAYL,EAAI,cAAc,OAAO;AAC3C,EAAAK,EAAU,cAAcC,GACxBN,EAAI,KAAK,YAAYK,CAAS;AAG9B,QAAME,IAASP,EAAI,cAAc,QAAQ;AACzC,EAAAO,EAAO,cAAcC,GACrBR,EAAI,KAAK,YAAYO,CAAM;AAC7B;"}
1
+ {"version":3,"file":"blackboard-vendor.es.js","sources":["../../../src/components/ContentRender/blackboard-vendor.ts"],"sourcesContent":["import tailwindScript from \"./vendor/tailwindcss-v3.min.js?raw\";\nimport daisyuiCss from \"./vendor/daisyui-v4.min.css?raw\";\nimport gsapScript from \"./vendor/gsap-v3.min.js?raw\";\nimport { refreshTailwindRuntime } from \"./utils/tailwind-runtime\";\n\nexport { refreshTailwindRuntime };\n\n/**\n * Inject blackboard-mode libraries (Tailwind CSS, DaisyUI, GSAP)\n * into an iframe document using DOM API to avoid template-string escaping issues.\n */\nexport function injectBlackboardLibraries(doc: Document): void {\n // 1. Tailwind CSS v3 (JIT compiler, must load first)\n const tailwindEl = doc.createElement(\"script\");\n tailwindEl.textContent = tailwindScript;\n // The Play CDN script replaces window.tailwind with its Proxy during execution,\n // so configure that runtime only after the synchronous append completes.\n doc.head.appendChild(tailwindEl);\n refreshTailwindRuntime(doc);\n\n // 2. DaisyUI v4 CSS\n const daisyuiEl = doc.createElement(\"style\");\n daisyuiEl.textContent = daisyuiCss;\n doc.head.appendChild(daisyuiEl);\n\n // 3. GSAP v3\n const gsapEl = doc.createElement(\"script\");\n gsapEl.textContent = gsapScript;\n doc.head.appendChild(gsapEl);\n}\n"],"names":["injectBlackboardLibraries","doc","tailwindEl","tailwindScript","refreshTailwindRuntime","daisyuiEl","daisyuiCss","gsapEl","gsapScript"],"mappings":";;;;AAWO,SAASA,EAA0BC,GAAqB;AAE7D,QAAMC,IAAaD,EAAI,cAAc,QAAQ;AAC7C,EAAAC,EAAW,cAAcC,GAGzBF,EAAI,KAAK,YAAYC,CAAU,GAC/BE,EAAuBH,CAAG;AAG1B,QAAMI,IAAYJ,EAAI,cAAc,OAAO;AAC3C,EAAAI,EAAU,cAAcC,GACxBL,EAAI,KAAK,YAAYI,CAAS;AAG9B,QAAME,IAASN,EAAI,cAAc,QAAQ;AACzC,EAAAM,EAAO,cAAcC,GACrBP,EAAI,KAAK,YAAYM,CAAM;AAC7B;"}
@@ -1,6 +1,6 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./presentation-scaling.cjs.js"),n=`
2
2
  /* Gamma-style scaling base */
3
- :root { --mdf-fs: 16px; }
3
+ :root { --mdf-fs: ${e.PRESENTATION_DEFAULT_FONT_SIZE_PX}px; }
4
4
 
5
5
  *, *::before, *::after {
6
6
  box-sizing: border-box;
@@ -25,13 +25,13 @@ html, body {
25
25
  /* Hide scrollbars inside scaled content — overflow handled by compression */
26
26
  .sandbox-container *::-webkit-scrollbar { display: none; }
27
27
  .sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }
28
- `,n=`
28
+ `,s=`
29
29
  !function() {
30
30
  var fitTimer = null;
31
- var baseFontSize = 16;
31
+ var baseFontSize = ${e.PRESENTATION_DEFAULT_FONT_SIZE_PX};
32
32
  var compressionRatio = 1;
33
33
  var lastCompressTime = 0;
34
- var MIN_FONT_PX = 8;
34
+ var MIN_FONT_PX = ${e.PRESENTATION_MIN_FONT_SIZE_PX};
35
35
 
36
36
  function applyFs(fs) {
37
37
  document.documentElement.style.setProperty('--mdf-fs', fs + 'px');
@@ -48,8 +48,8 @@ html, body {
48
48
  var naturalH = slide.offsetHeight;
49
49
  var naturalW = slide.scrollWidth;
50
50
 
51
- var overflowH = naturalH > viewH + 4;
52
- var overflowW = naturalW > viewW + 4;
51
+ var overflowH = naturalH > viewH + ${e.PRESENTATION_OVERFLOW_TOLERANCE_PX};
52
+ var overflowW = naturalW > viewW + ${e.PRESENTATION_OVERFLOW_TOLERANCE_PX};
53
53
 
54
54
  if (overflowH || overflowW) {
55
55
  var now = Date.now();
@@ -84,7 +84,10 @@ html, body {
84
84
  function syncFs() {
85
85
  var w = document.documentElement.clientWidth;
86
86
  var h = document.documentElement.clientHeight;
87
- baseFontSize = Math.min(Math.max(12, w / 48), h * 0.03);
87
+ baseFontSize = Math.min(
88
+ Math.max(${e.PRESENTATION_MIN_BASE_FONT_SIZE_PX}, w / ${e.PRESENTATION_WIDTH_FONT_DIVISOR}),
89
+ h * ${e.PRESENTATION_HEIGHT_FONT_RATIO}
90
+ );
88
91
  applyFs(Math.max(baseFontSize * compressionRatio, MIN_FONT_PX));
89
92
  clearTimeout(fitTimer);
90
93
  fitTimer = setTimeout(fitContent, 60);
@@ -157,5 +160,5 @@ html, body {
157
160
  delete window.__mdf_cleanupScaling;
158
161
  };
159
162
  }();
160
- `;function s(e){const t=e.createElement("style");t.id="mdf-scaling-style",t.textContent=i,e.head.appendChild(t);const o=e.createElement("script");o.id="mdf-scaling-script",o.textContent=n,e.head.appendChild(o)}exports.injectScalingSystem=s;
163
+ `;function r(t){const o=t.createElement("style");o.id="mdf-scaling-style",o.textContent=n,t.head.appendChild(o);const i=t.createElement("script");i.id="mdf-scaling-script",i.textContent=s,t.head.appendChild(i)}exports.injectScalingSystem=r;
161
164
  //# sourceMappingURL=iframe-scaling.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"iframe-scaling.cjs.js","sources":["../../../../src/components/ContentRender/utils/iframe-scaling.ts"],"sourcesContent":["/**\n * Gamma-style font-size scaling system for iframe sandbox.\n *\n * Injects CSS + JS into an iframe document so that:\n * 1. A base font-size is computed from the viewport: clamp(12px, width/48, height*3%)\n * 2. The CSS variable --mdf-fs drives html/body font-size; all em children follow.\n * 3. When content overflows the viewport, a compression ratio shrinks font-size.\n * 4. ResizeObserver / MutationObserver keep everything in sync.\n */\n\n/** Window extension for the scaling system injected into the iframe. */\nexport interface ScalingWindow extends Window {\n __mdf_triggerFitContent?: () => void;\n __mdf_cleanupScaling?: () => void;\n}\n\nconst SCALING_CSS = `\n/* Gamma-style scaling base */\n:root { --mdf-fs: 16px; }\n\n*, *::before, *::after {\n box-sizing: border-box;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\nhtml, body {\n font-size: var(--mdf-fs);\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n/* Force sandbox content children into the em scaling chain */\n.sandbox-container > * {\n height: auto !important;\n min-height: 100vh !important;\n overflow: hidden !important;\n font-size: var(--mdf-fs) !important;\n}\n\n/* Hide scrollbars inside scaled content — overflow handled by compression */\n.sandbox-container *::-webkit-scrollbar { display: none; }\n.sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }\n`;\n\nconst SCALING_JS = `\n!function() {\n var fitTimer = null;\n var baseFontSize = 16;\n var compressionRatio = 1;\n var lastCompressTime = 0;\n var MIN_FONT_PX = 8;\n\n function applyFs(fs) {\n document.documentElement.style.setProperty('--mdf-fs', fs + 'px');\n if (document.body) document.body.style.fontSize = fs + 'px';\n }\n\n function fitContent() {\n var container = document.querySelector('.sandbox-container');\n if (!container || !container.firstElementChild) return;\n\n var slide = container.firstElementChild;\n var viewH = document.documentElement.clientHeight;\n var viewW = document.documentElement.clientWidth;\n var naturalH = slide.offsetHeight;\n var naturalW = slide.scrollWidth;\n\n var overflowH = naturalH > viewH + 4;\n var overflowW = naturalW > viewW + 4;\n\n if (overflowH || overflowW) {\n var now = Date.now();\n if (now - lastCompressTime < 300) return;\n lastCompressTime = now;\n\n var ratioH = overflowH ? (viewH / naturalH) : 1;\n var ratioW = overflowW ? (viewW / naturalW) : 1;\n compressionRatio = compressionRatio * Math.min(ratioH, ratioW);\n compressionRatio = Math.max(compressionRatio, MIN_FONT_PX / baseFontSize);\n applyFs(baseFontSize * compressionRatio);\n\n if (baseFontSize * compressionRatio <= MIN_FONT_PX * 1.1 && viewH < 400) {\n document.documentElement.style.overflowY = 'hidden';\n if (document.body) document.body.style.overflowY = 'hidden';\n }\n } else {\n if (compressionRatio < 1 && naturalH > 0) {\n var maxRatio = viewH * compressionRatio / naturalH;\n if (maxRatio >= 1) {\n compressionRatio = 1;\n } else if (maxRatio > compressionRatio) {\n compressionRatio = maxRatio;\n }\n applyFs(baseFontSize * compressionRatio);\n }\n document.documentElement.style.overflowY = '';\n if (document.body) document.body.style.overflowY = '';\n }\n }\n\n function syncFs() {\n var w = document.documentElement.clientWidth;\n var h = document.documentElement.clientHeight;\n baseFontSize = Math.min(Math.max(12, w / 48), h * 0.03);\n applyFs(Math.max(baseFontSize * compressionRatio, MIN_FONT_PX));\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 60);\n }\n\n var rootResizeObs = null;\n if (window.ResizeObserver) {\n rootResizeObs = new ResizeObserver(syncFs);\n rootResizeObs.observe(document.documentElement);\n } else {\n window.addEventListener('resize', syncFs);\n }\n syncFs();\n\n var slideResizeObs = null;\n function observeSlide(slide) {\n if (!window.ResizeObserver) return;\n if (slideResizeObs) slideResizeObs.disconnect();\n slideResizeObs = new ResizeObserver(function() {\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 50);\n });\n slideResizeObs.observe(slide);\n }\n\n var mutationObs = null;\n function startFitObserver() {\n var c = document.querySelector('.sandbox-container');\n if (!c) return;\n mutationObs = new MutationObserver(function(mutations) {\n var hasNewContent = false;\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 &&\n node.tagName !== 'STYLE' && node.tagName !== 'SCRIPT') {\n hasNewContent = true;\n observeSlide(node);\n }\n });\n });\n if (hasNewContent) {\n compressionRatio = 1;\n lastCompressTime = 0;\n applyFs(baseFontSize);\n }\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 80);\n });\n mutationObs.observe(c, { childList: true });\n }\n\n if (document.readyState !== 'loading') {\n startFitObserver();\n } else {\n document.addEventListener('DOMContentLoaded', startFitObserver);\n }\n\n window.__mdf_triggerFitContent = function() {\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 100);\n };\n\n window.__mdf_cleanupScaling = function() {\n clearTimeout(fitTimer);\n if (rootResizeObs) rootResizeObs.disconnect();\n if (slideResizeObs) slideResizeObs.disconnect();\n if (mutationObs) mutationObs.disconnect();\n window.removeEventListener('resize', syncFs);\n delete window.__mdf_triggerFitContent;\n delete window.__mdf_cleanupScaling;\n };\n}();\n`;\n\n/**\n * Inject the Gamma-style font-size scaling system into an iframe document.\n * Must be called AFTER blackboard vendor libraries (Tailwind/DaisyUI/GSAP)\n * so that the scaling CSS rules take precedence.\n */\nexport function injectScalingSystem(doc: Document): void {\n const styleEl = doc.createElement(\"style\");\n styleEl.id = \"mdf-scaling-style\";\n styleEl.textContent = SCALING_CSS;\n doc.head.appendChild(styleEl);\n\n const scriptEl = doc.createElement(\"script\");\n scriptEl.id = \"mdf-scaling-script\";\n scriptEl.textContent = SCALING_JS;\n doc.head.appendChild(scriptEl);\n}\n"],"names":["SCALING_CSS","SCALING_JS","injectScalingSystem","doc","styleEl","scriptEl"],"mappings":"gFAgBA,MAAMA,EAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BdC,EAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2IZ,SAASC,EAAoBC,EAAqB,CACvD,MAAMC,EAAUD,EAAI,cAAc,OAAO,EACzCC,EAAQ,GAAK,oBACbA,EAAQ,YAAcJ,EACtBG,EAAI,KAAK,YAAYC,CAAO,EAE5B,MAAMC,EAAWF,EAAI,cAAc,QAAQ,EAC3CE,EAAS,GAAK,qBACdA,EAAS,YAAcJ,EACvBE,EAAI,KAAK,YAAYE,CAAQ,CAC/B"}
1
+ {"version":3,"file":"iframe-scaling.cjs.js","sources":["../../../../src/components/ContentRender/utils/iframe-scaling.ts"],"sourcesContent":["/**\n * Gamma-style font-size scaling system for iframe sandbox.\n *\n * Injects CSS + JS into an iframe document so that:\n * 1. A base font-size is computed from the viewport: clamp(12px, width/48, height*3%)\n * 2. The CSS variable --mdf-fs drives html/body font-size; all em children follow.\n * 3. When content overflows the viewport, a compression ratio shrinks font-size.\n * 4. ResizeObserver / MutationObserver keep everything in sync.\n */\n\nimport {\n PRESENTATION_DEFAULT_FONT_SIZE_PX,\n PRESENTATION_HEIGHT_FONT_RATIO,\n PRESENTATION_MIN_BASE_FONT_SIZE_PX,\n PRESENTATION_MIN_FONT_SIZE_PX,\n PRESENTATION_OVERFLOW_TOLERANCE_PX,\n PRESENTATION_WIDTH_FONT_DIVISOR,\n} from \"./presentation-scaling\";\n\n/** Window extension for the scaling system injected into the iframe. */\nexport interface ScalingWindow extends Window {\n __mdf_triggerFitContent?: () => void;\n __mdf_cleanupScaling?: () => void;\n}\n\nconst SCALING_CSS = `\n/* Gamma-style scaling base */\n:root { --mdf-fs: ${PRESENTATION_DEFAULT_FONT_SIZE_PX}px; }\n\n*, *::before, *::after {\n box-sizing: border-box;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\nhtml, body {\n font-size: var(--mdf-fs);\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n/* Force sandbox content children into the em scaling chain */\n.sandbox-container > * {\n height: auto !important;\n min-height: 100vh !important;\n overflow: hidden !important;\n font-size: var(--mdf-fs) !important;\n}\n\n/* Hide scrollbars inside scaled content — overflow handled by compression */\n.sandbox-container *::-webkit-scrollbar { display: none; }\n.sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }\n`;\n\nconst SCALING_JS = `\n!function() {\n var fitTimer = null;\n var baseFontSize = ${PRESENTATION_DEFAULT_FONT_SIZE_PX};\n var compressionRatio = 1;\n var lastCompressTime = 0;\n var MIN_FONT_PX = ${PRESENTATION_MIN_FONT_SIZE_PX};\n\n function applyFs(fs) {\n document.documentElement.style.setProperty('--mdf-fs', fs + 'px');\n if (document.body) document.body.style.fontSize = fs + 'px';\n }\n\n function fitContent() {\n var container = document.querySelector('.sandbox-container');\n if (!container || !container.firstElementChild) return;\n\n var slide = container.firstElementChild;\n var viewH = document.documentElement.clientHeight;\n var viewW = document.documentElement.clientWidth;\n var naturalH = slide.offsetHeight;\n var naturalW = slide.scrollWidth;\n\n var overflowH = naturalH > viewH + ${PRESENTATION_OVERFLOW_TOLERANCE_PX};\n var overflowW = naturalW > viewW + ${PRESENTATION_OVERFLOW_TOLERANCE_PX};\n\n if (overflowH || overflowW) {\n var now = Date.now();\n if (now - lastCompressTime < 300) return;\n lastCompressTime = now;\n\n var ratioH = overflowH ? (viewH / naturalH) : 1;\n var ratioW = overflowW ? (viewW / naturalW) : 1;\n compressionRatio = compressionRatio * Math.min(ratioH, ratioW);\n compressionRatio = Math.max(compressionRatio, MIN_FONT_PX / baseFontSize);\n applyFs(baseFontSize * compressionRatio);\n\n if (baseFontSize * compressionRatio <= MIN_FONT_PX * 1.1 && viewH < 400) {\n document.documentElement.style.overflowY = 'hidden';\n if (document.body) document.body.style.overflowY = 'hidden';\n }\n } else {\n if (compressionRatio < 1 && naturalH > 0) {\n var maxRatio = viewH * compressionRatio / naturalH;\n if (maxRatio >= 1) {\n compressionRatio = 1;\n } else if (maxRatio > compressionRatio) {\n compressionRatio = maxRatio;\n }\n applyFs(baseFontSize * compressionRatio);\n }\n document.documentElement.style.overflowY = '';\n if (document.body) document.body.style.overflowY = '';\n }\n }\n\n function syncFs() {\n var w = document.documentElement.clientWidth;\n var h = document.documentElement.clientHeight;\n baseFontSize = Math.min(\n Math.max(${PRESENTATION_MIN_BASE_FONT_SIZE_PX}, w / ${PRESENTATION_WIDTH_FONT_DIVISOR}),\n h * ${PRESENTATION_HEIGHT_FONT_RATIO}\n );\n applyFs(Math.max(baseFontSize * compressionRatio, MIN_FONT_PX));\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 60);\n }\n\n var rootResizeObs = null;\n if (window.ResizeObserver) {\n rootResizeObs = new ResizeObserver(syncFs);\n rootResizeObs.observe(document.documentElement);\n } else {\n window.addEventListener('resize', syncFs);\n }\n syncFs();\n\n var slideResizeObs = null;\n function observeSlide(slide) {\n if (!window.ResizeObserver) return;\n if (slideResizeObs) slideResizeObs.disconnect();\n slideResizeObs = new ResizeObserver(function() {\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 50);\n });\n slideResizeObs.observe(slide);\n }\n\n var mutationObs = null;\n function startFitObserver() {\n var c = document.querySelector('.sandbox-container');\n if (!c) return;\n mutationObs = new MutationObserver(function(mutations) {\n var hasNewContent = false;\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 &&\n node.tagName !== 'STYLE' && node.tagName !== 'SCRIPT') {\n hasNewContent = true;\n observeSlide(node);\n }\n });\n });\n if (hasNewContent) {\n compressionRatio = 1;\n lastCompressTime = 0;\n applyFs(baseFontSize);\n }\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 80);\n });\n mutationObs.observe(c, { childList: true });\n }\n\n if (document.readyState !== 'loading') {\n startFitObserver();\n } else {\n document.addEventListener('DOMContentLoaded', startFitObserver);\n }\n\n window.__mdf_triggerFitContent = function() {\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 100);\n };\n\n window.__mdf_cleanupScaling = function() {\n clearTimeout(fitTimer);\n if (rootResizeObs) rootResizeObs.disconnect();\n if (slideResizeObs) slideResizeObs.disconnect();\n if (mutationObs) mutationObs.disconnect();\n window.removeEventListener('resize', syncFs);\n delete window.__mdf_triggerFitContent;\n delete window.__mdf_cleanupScaling;\n };\n}();\n`;\n\n/**\n * Inject the Gamma-style font-size scaling system into an iframe document.\n * Must be called AFTER blackboard vendor libraries (Tailwind/DaisyUI/GSAP)\n * so that the scaling CSS rules take precedence.\n */\nexport function injectScalingSystem(doc: Document): void {\n const styleEl = doc.createElement(\"style\");\n styleEl.id = \"mdf-scaling-style\";\n styleEl.textContent = SCALING_CSS;\n doc.head.appendChild(styleEl);\n\n const scriptEl = doc.createElement(\"script\");\n scriptEl.id = \"mdf-scaling-script\";\n scriptEl.textContent = SCALING_JS;\n doc.head.appendChild(scriptEl);\n}\n"],"names":["SCALING_CSS","PRESENTATION_DEFAULT_FONT_SIZE_PX","SCALING_JS","PRESENTATION_MIN_FONT_SIZE_PX","PRESENTATION_OVERFLOW_TOLERANCE_PX","PRESENTATION_MIN_BASE_FONT_SIZE_PX","PRESENTATION_WIDTH_FONT_DIVISOR","PRESENTATION_HEIGHT_FONT_RATIO","injectScalingSystem","doc","styleEl","scriptEl"],"mappings":"iIAyBMA,EAAc;AAAA;AAAA,oBAEAC,mCAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2B/CC,EAAa;AAAA;AAAA;AAAA,uBAGID,mCAAiC;AAAA;AAAA;AAAA,sBAGlCE,+BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yCAiBVC,oCAAkC;AAAA,yCAClCA,oCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAoC1DC,EAAAA,kCAAkC,SAASC,iCAA+B;AAAA,YAC/EC,EAAAA,8BAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiFnC,SAASC,EAAoBC,EAAqB,CACvD,MAAMC,EAAUD,EAAI,cAAc,OAAO,EACzCC,EAAQ,GAAK,oBACbA,EAAQ,YAAcV,EACtBS,EAAI,KAAK,YAAYC,CAAO,EAE5B,MAAMC,EAAWF,EAAI,cAAc,QAAQ,EAC3CE,EAAS,GAAK,qBACdA,EAAS,YAAcT,EACvBO,EAAI,KAAK,YAAYE,CAAQ,CAC/B"}
@@ -1,6 +1,7 @@
1
- const i = `
1
+ import { PRESENTATION_DEFAULT_FONT_SIZE_PX as n, PRESENTATION_MIN_FONT_SIZE_PX as s, PRESENTATION_OVERFLOW_TOLERANCE_PX as i, PRESENTATION_MIN_BASE_FONT_SIZE_PX as r, PRESENTATION_WIDTH_FONT_DIVISOR as a, PRESENTATION_HEIGHT_FONT_RATIO as d } from "./presentation-scaling.es.js";
2
+ const l = `
2
3
  /* Gamma-style scaling base */
3
- :root { --mdf-fs: 16px; }
4
+ :root { --mdf-fs: ${n}px; }
4
5
 
5
6
  *, *::before, *::after {
6
7
  box-sizing: border-box;
@@ -25,13 +26,13 @@ html, body {
25
26
  /* Hide scrollbars inside scaled content — overflow handled by compression */
26
27
  .sandbox-container *::-webkit-scrollbar { display: none; }
27
28
  .sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }
28
- `, n = `
29
+ `, m = `
29
30
  !function() {
30
31
  var fitTimer = null;
31
- var baseFontSize = 16;
32
+ var baseFontSize = ${n};
32
33
  var compressionRatio = 1;
33
34
  var lastCompressTime = 0;
34
- var MIN_FONT_PX = 8;
35
+ var MIN_FONT_PX = ${s};
35
36
 
36
37
  function applyFs(fs) {
37
38
  document.documentElement.style.setProperty('--mdf-fs', fs + 'px');
@@ -48,8 +49,8 @@ html, body {
48
49
  var naturalH = slide.offsetHeight;
49
50
  var naturalW = slide.scrollWidth;
50
51
 
51
- var overflowH = naturalH > viewH + 4;
52
- var overflowW = naturalW > viewW + 4;
52
+ var overflowH = naturalH > viewH + ${i};
53
+ var overflowW = naturalW > viewW + ${i};
53
54
 
54
55
  if (overflowH || overflowW) {
55
56
  var now = Date.now();
@@ -84,7 +85,10 @@ html, body {
84
85
  function syncFs() {
85
86
  var w = document.documentElement.clientWidth;
86
87
  var h = document.documentElement.clientHeight;
87
- baseFontSize = Math.min(Math.max(12, w / 48), h * 0.03);
88
+ baseFontSize = Math.min(
89
+ Math.max(${r}, w / ${a}),
90
+ h * ${d}
91
+ );
88
92
  applyFs(Math.max(baseFontSize * compressionRatio, MIN_FONT_PX));
89
93
  clearTimeout(fitTimer);
90
94
  fitTimer = setTimeout(fitContent, 60);
@@ -158,13 +162,13 @@ html, body {
158
162
  };
159
163
  }();
160
164
  `;
161
- function s(e) {
165
+ function f(e) {
162
166
  const t = e.createElement("style");
163
- t.id = "mdf-scaling-style", t.textContent = i, e.head.appendChild(t);
167
+ t.id = "mdf-scaling-style", t.textContent = l, e.head.appendChild(t);
164
168
  const o = e.createElement("script");
165
- o.id = "mdf-scaling-script", o.textContent = n, e.head.appendChild(o);
169
+ o.id = "mdf-scaling-script", o.textContent = m, e.head.appendChild(o);
166
170
  }
167
171
  export {
168
- s as injectScalingSystem
172
+ f as injectScalingSystem
169
173
  };
170
174
  //# sourceMappingURL=iframe-scaling.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"iframe-scaling.es.js","sources":["../../../../src/components/ContentRender/utils/iframe-scaling.ts"],"sourcesContent":["/**\n * Gamma-style font-size scaling system for iframe sandbox.\n *\n * Injects CSS + JS into an iframe document so that:\n * 1. A base font-size is computed from the viewport: clamp(12px, width/48, height*3%)\n * 2. The CSS variable --mdf-fs drives html/body font-size; all em children follow.\n * 3. When content overflows the viewport, a compression ratio shrinks font-size.\n * 4. ResizeObserver / MutationObserver keep everything in sync.\n */\n\n/** Window extension for the scaling system injected into the iframe. */\nexport interface ScalingWindow extends Window {\n __mdf_triggerFitContent?: () => void;\n __mdf_cleanupScaling?: () => void;\n}\n\nconst SCALING_CSS = `\n/* Gamma-style scaling base */\n:root { --mdf-fs: 16px; }\n\n*, *::before, *::after {\n box-sizing: border-box;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\nhtml, body {\n font-size: var(--mdf-fs);\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n/* Force sandbox content children into the em scaling chain */\n.sandbox-container > * {\n height: auto !important;\n min-height: 100vh !important;\n overflow: hidden !important;\n font-size: var(--mdf-fs) !important;\n}\n\n/* Hide scrollbars inside scaled content — overflow handled by compression */\n.sandbox-container *::-webkit-scrollbar { display: none; }\n.sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }\n`;\n\nconst SCALING_JS = `\n!function() {\n var fitTimer = null;\n var baseFontSize = 16;\n var compressionRatio = 1;\n var lastCompressTime = 0;\n var MIN_FONT_PX = 8;\n\n function applyFs(fs) {\n document.documentElement.style.setProperty('--mdf-fs', fs + 'px');\n if (document.body) document.body.style.fontSize = fs + 'px';\n }\n\n function fitContent() {\n var container = document.querySelector('.sandbox-container');\n if (!container || !container.firstElementChild) return;\n\n var slide = container.firstElementChild;\n var viewH = document.documentElement.clientHeight;\n var viewW = document.documentElement.clientWidth;\n var naturalH = slide.offsetHeight;\n var naturalW = slide.scrollWidth;\n\n var overflowH = naturalH > viewH + 4;\n var overflowW = naturalW > viewW + 4;\n\n if (overflowH || overflowW) {\n var now = Date.now();\n if (now - lastCompressTime < 300) return;\n lastCompressTime = now;\n\n var ratioH = overflowH ? (viewH / naturalH) : 1;\n var ratioW = overflowW ? (viewW / naturalW) : 1;\n compressionRatio = compressionRatio * Math.min(ratioH, ratioW);\n compressionRatio = Math.max(compressionRatio, MIN_FONT_PX / baseFontSize);\n applyFs(baseFontSize * compressionRatio);\n\n if (baseFontSize * compressionRatio <= MIN_FONT_PX * 1.1 && viewH < 400) {\n document.documentElement.style.overflowY = 'hidden';\n if (document.body) document.body.style.overflowY = 'hidden';\n }\n } else {\n if (compressionRatio < 1 && naturalH > 0) {\n var maxRatio = viewH * compressionRatio / naturalH;\n if (maxRatio >= 1) {\n compressionRatio = 1;\n } else if (maxRatio > compressionRatio) {\n compressionRatio = maxRatio;\n }\n applyFs(baseFontSize * compressionRatio);\n }\n document.documentElement.style.overflowY = '';\n if (document.body) document.body.style.overflowY = '';\n }\n }\n\n function syncFs() {\n var w = document.documentElement.clientWidth;\n var h = document.documentElement.clientHeight;\n baseFontSize = Math.min(Math.max(12, w / 48), h * 0.03);\n applyFs(Math.max(baseFontSize * compressionRatio, MIN_FONT_PX));\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 60);\n }\n\n var rootResizeObs = null;\n if (window.ResizeObserver) {\n rootResizeObs = new ResizeObserver(syncFs);\n rootResizeObs.observe(document.documentElement);\n } else {\n window.addEventListener('resize', syncFs);\n }\n syncFs();\n\n var slideResizeObs = null;\n function observeSlide(slide) {\n if (!window.ResizeObserver) return;\n if (slideResizeObs) slideResizeObs.disconnect();\n slideResizeObs = new ResizeObserver(function() {\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 50);\n });\n slideResizeObs.observe(slide);\n }\n\n var mutationObs = null;\n function startFitObserver() {\n var c = document.querySelector('.sandbox-container');\n if (!c) return;\n mutationObs = new MutationObserver(function(mutations) {\n var hasNewContent = false;\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 &&\n node.tagName !== 'STYLE' && node.tagName !== 'SCRIPT') {\n hasNewContent = true;\n observeSlide(node);\n }\n });\n });\n if (hasNewContent) {\n compressionRatio = 1;\n lastCompressTime = 0;\n applyFs(baseFontSize);\n }\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 80);\n });\n mutationObs.observe(c, { childList: true });\n }\n\n if (document.readyState !== 'loading') {\n startFitObserver();\n } else {\n document.addEventListener('DOMContentLoaded', startFitObserver);\n }\n\n window.__mdf_triggerFitContent = function() {\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 100);\n };\n\n window.__mdf_cleanupScaling = function() {\n clearTimeout(fitTimer);\n if (rootResizeObs) rootResizeObs.disconnect();\n if (slideResizeObs) slideResizeObs.disconnect();\n if (mutationObs) mutationObs.disconnect();\n window.removeEventListener('resize', syncFs);\n delete window.__mdf_triggerFitContent;\n delete window.__mdf_cleanupScaling;\n };\n}();\n`;\n\n/**\n * Inject the Gamma-style font-size scaling system into an iframe document.\n * Must be called AFTER blackboard vendor libraries (Tailwind/DaisyUI/GSAP)\n * so that the scaling CSS rules take precedence.\n */\nexport function injectScalingSystem(doc: Document): void {\n const styleEl = doc.createElement(\"style\");\n styleEl.id = \"mdf-scaling-style\";\n styleEl.textContent = SCALING_CSS;\n doc.head.appendChild(styleEl);\n\n const scriptEl = doc.createElement(\"script\");\n scriptEl.id = \"mdf-scaling-script\";\n scriptEl.textContent = SCALING_JS;\n doc.head.appendChild(scriptEl);\n}\n"],"names":["SCALING_CSS","SCALING_JS","injectScalingSystem","doc","styleEl","scriptEl"],"mappings":"AAgBA,MAAMA,IAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GA6BdC,IAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2IZ,SAASC,EAAoBC,GAAqB;AACvD,QAAMC,IAAUD,EAAI,cAAc,OAAO;AACzC,EAAAC,EAAQ,KAAK,qBACbA,EAAQ,cAAcJ,GACtBG,EAAI,KAAK,YAAYC,CAAO;AAE5B,QAAMC,IAAWF,EAAI,cAAc,QAAQ;AAC3C,EAAAE,EAAS,KAAK,sBACdA,EAAS,cAAcJ,GACvBE,EAAI,KAAK,YAAYE,CAAQ;AAC/B;"}
1
+ {"version":3,"file":"iframe-scaling.es.js","sources":["../../../../src/components/ContentRender/utils/iframe-scaling.ts"],"sourcesContent":["/**\n * Gamma-style font-size scaling system for iframe sandbox.\n *\n * Injects CSS + JS into an iframe document so that:\n * 1. A base font-size is computed from the viewport: clamp(12px, width/48, height*3%)\n * 2. The CSS variable --mdf-fs drives html/body font-size; all em children follow.\n * 3. When content overflows the viewport, a compression ratio shrinks font-size.\n * 4. ResizeObserver / MutationObserver keep everything in sync.\n */\n\nimport {\n PRESENTATION_DEFAULT_FONT_SIZE_PX,\n PRESENTATION_HEIGHT_FONT_RATIO,\n PRESENTATION_MIN_BASE_FONT_SIZE_PX,\n PRESENTATION_MIN_FONT_SIZE_PX,\n PRESENTATION_OVERFLOW_TOLERANCE_PX,\n PRESENTATION_WIDTH_FONT_DIVISOR,\n} from \"./presentation-scaling\";\n\n/** Window extension for the scaling system injected into the iframe. */\nexport interface ScalingWindow extends Window {\n __mdf_triggerFitContent?: () => void;\n __mdf_cleanupScaling?: () => void;\n}\n\nconst SCALING_CSS = `\n/* Gamma-style scaling base */\n:root { --mdf-fs: ${PRESENTATION_DEFAULT_FONT_SIZE_PX}px; }\n\n*, *::before, *::after {\n box-sizing: border-box;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\nhtml, body {\n font-size: var(--mdf-fs);\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n/* Force sandbox content children into the em scaling chain */\n.sandbox-container > * {\n height: auto !important;\n min-height: 100vh !important;\n overflow: hidden !important;\n font-size: var(--mdf-fs) !important;\n}\n\n/* Hide scrollbars inside scaled content — overflow handled by compression */\n.sandbox-container *::-webkit-scrollbar { display: none; }\n.sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }\n`;\n\nconst SCALING_JS = `\n!function() {\n var fitTimer = null;\n var baseFontSize = ${PRESENTATION_DEFAULT_FONT_SIZE_PX};\n var compressionRatio = 1;\n var lastCompressTime = 0;\n var MIN_FONT_PX = ${PRESENTATION_MIN_FONT_SIZE_PX};\n\n function applyFs(fs) {\n document.documentElement.style.setProperty('--mdf-fs', fs + 'px');\n if (document.body) document.body.style.fontSize = fs + 'px';\n }\n\n function fitContent() {\n var container = document.querySelector('.sandbox-container');\n if (!container || !container.firstElementChild) return;\n\n var slide = container.firstElementChild;\n var viewH = document.documentElement.clientHeight;\n var viewW = document.documentElement.clientWidth;\n var naturalH = slide.offsetHeight;\n var naturalW = slide.scrollWidth;\n\n var overflowH = naturalH > viewH + ${PRESENTATION_OVERFLOW_TOLERANCE_PX};\n var overflowW = naturalW > viewW + ${PRESENTATION_OVERFLOW_TOLERANCE_PX};\n\n if (overflowH || overflowW) {\n var now = Date.now();\n if (now - lastCompressTime < 300) return;\n lastCompressTime = now;\n\n var ratioH = overflowH ? (viewH / naturalH) : 1;\n var ratioW = overflowW ? (viewW / naturalW) : 1;\n compressionRatio = compressionRatio * Math.min(ratioH, ratioW);\n compressionRatio = Math.max(compressionRatio, MIN_FONT_PX / baseFontSize);\n applyFs(baseFontSize * compressionRatio);\n\n if (baseFontSize * compressionRatio <= MIN_FONT_PX * 1.1 && viewH < 400) {\n document.documentElement.style.overflowY = 'hidden';\n if (document.body) document.body.style.overflowY = 'hidden';\n }\n } else {\n if (compressionRatio < 1 && naturalH > 0) {\n var maxRatio = viewH * compressionRatio / naturalH;\n if (maxRatio >= 1) {\n compressionRatio = 1;\n } else if (maxRatio > compressionRatio) {\n compressionRatio = maxRatio;\n }\n applyFs(baseFontSize * compressionRatio);\n }\n document.documentElement.style.overflowY = '';\n if (document.body) document.body.style.overflowY = '';\n }\n }\n\n function syncFs() {\n var w = document.documentElement.clientWidth;\n var h = document.documentElement.clientHeight;\n baseFontSize = Math.min(\n Math.max(${PRESENTATION_MIN_BASE_FONT_SIZE_PX}, w / ${PRESENTATION_WIDTH_FONT_DIVISOR}),\n h * ${PRESENTATION_HEIGHT_FONT_RATIO}\n );\n applyFs(Math.max(baseFontSize * compressionRatio, MIN_FONT_PX));\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 60);\n }\n\n var rootResizeObs = null;\n if (window.ResizeObserver) {\n rootResizeObs = new ResizeObserver(syncFs);\n rootResizeObs.observe(document.documentElement);\n } else {\n window.addEventListener('resize', syncFs);\n }\n syncFs();\n\n var slideResizeObs = null;\n function observeSlide(slide) {\n if (!window.ResizeObserver) return;\n if (slideResizeObs) slideResizeObs.disconnect();\n slideResizeObs = new ResizeObserver(function() {\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 50);\n });\n slideResizeObs.observe(slide);\n }\n\n var mutationObs = null;\n function startFitObserver() {\n var c = document.querySelector('.sandbox-container');\n if (!c) return;\n mutationObs = new MutationObserver(function(mutations) {\n var hasNewContent = false;\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 &&\n node.tagName !== 'STYLE' && node.tagName !== 'SCRIPT') {\n hasNewContent = true;\n observeSlide(node);\n }\n });\n });\n if (hasNewContent) {\n compressionRatio = 1;\n lastCompressTime = 0;\n applyFs(baseFontSize);\n }\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 80);\n });\n mutationObs.observe(c, { childList: true });\n }\n\n if (document.readyState !== 'loading') {\n startFitObserver();\n } else {\n document.addEventListener('DOMContentLoaded', startFitObserver);\n }\n\n window.__mdf_triggerFitContent = function() {\n clearTimeout(fitTimer);\n fitTimer = setTimeout(fitContent, 100);\n };\n\n window.__mdf_cleanupScaling = function() {\n clearTimeout(fitTimer);\n if (rootResizeObs) rootResizeObs.disconnect();\n if (slideResizeObs) slideResizeObs.disconnect();\n if (mutationObs) mutationObs.disconnect();\n window.removeEventListener('resize', syncFs);\n delete window.__mdf_triggerFitContent;\n delete window.__mdf_cleanupScaling;\n };\n}();\n`;\n\n/**\n * Inject the Gamma-style font-size scaling system into an iframe document.\n * Must be called AFTER blackboard vendor libraries (Tailwind/DaisyUI/GSAP)\n * so that the scaling CSS rules take precedence.\n */\nexport function injectScalingSystem(doc: Document): void {\n const styleEl = doc.createElement(\"style\");\n styleEl.id = \"mdf-scaling-style\";\n styleEl.textContent = SCALING_CSS;\n doc.head.appendChild(styleEl);\n\n const scriptEl = doc.createElement(\"script\");\n scriptEl.id = \"mdf-scaling-script\";\n scriptEl.textContent = SCALING_JS;\n doc.head.appendChild(scriptEl);\n}\n"],"names":["SCALING_CSS","PRESENTATION_DEFAULT_FONT_SIZE_PX","SCALING_JS","PRESENTATION_MIN_FONT_SIZE_PX","PRESENTATION_OVERFLOW_TOLERANCE_PX","PRESENTATION_MIN_BASE_FONT_SIZE_PX","PRESENTATION_WIDTH_FONT_DIVISOR","PRESENTATION_HEIGHT_FONT_RATIO","injectScalingSystem","doc","styleEl","scriptEl"],"mappings":";AAyBA,MAAMA,IAAc;AAAA;AAAA,oBAEAC,CAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GA2B/CC,IAAa;AAAA;AAAA;AAAA,uBAGID,CAAiC;AAAA;AAAA;AAAA,sBAGlCE,CAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yCAiBVC,CAAkC;AAAA,yCAClCA,CAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAoC1DC,CAAkC,SAASC,CAA+B;AAAA,YAC/EC,CAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiFnC,SAASC,EAAoBC,GAAqB;AACvD,QAAMC,IAAUD,EAAI,cAAc,OAAO;AACzC,EAAAC,EAAQ,KAAK,qBACbA,EAAQ,cAAcV,GACtBS,EAAI,KAAK,YAAYC,CAAO;AAE5B,QAAMC,IAAWF,EAAI,cAAc,QAAQ;AAC3C,EAAAE,EAAS,KAAK,sBACdA,EAAS,cAAcT,GACvBO,EAAI,KAAK,YAAYE,CAAQ;AAC/B;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=16,h=12,N=8,S=48,r=.03,T=4,A=8,c=.05,o=i=>Number.isFinite(i)&&i>0,P=({height:i,width:t})=>!o(t)||!o(i)?a:Math.max(N,Math.min(Math.max(h,t/S),i*r)),R=(i,t)=>t.height<=i.height+T&&t.width<=i.width+T,F=({baseFontSize:i,content:t,currentRatio:s=1,viewport:n})=>{if(!o(i)||!o(n.width)||!o(n.height)||!o(t.width)||!o(t.height))return 1;const e=t.height>n.height+T?n.height/t.height:1,_=t.width>n.width+T?n.width/t.width:1,E=Math.min(1,N/i);return Math.max(E,Math.min(1,s*Math.min(e,_)))},m=({measure:i,viewport:t})=>{const s=P(t);let n=1,e=s;for(let _=0;_<A;_+=1){const E=i(e);if(R(t,E))return e;const O=F({baseFontSize:s,content:E,currentRatio:n,viewport:t}),I=Math.max(N,s*O);if(Math.abs(I-e)<c)return I;n=O,e=I}return e};exports.PRESENTATION_DEFAULT_FONT_SIZE_PX=a;exports.PRESENTATION_HEIGHT_FONT_RATIO=r;exports.PRESENTATION_MIN_BASE_FONT_SIZE_PX=h;exports.PRESENTATION_MIN_FONT_SIZE_PX=N;exports.PRESENTATION_OVERFLOW_TOLERANCE_PX=T;exports.PRESENTATION_WIDTH_FONT_DIVISOR=S;exports.fitPresentationFontSize=m;exports.presentationContentFits=R;exports.resolvePresentationBaseFontSize=P;exports.resolvePresentationCompressionRatio=F;
2
+ //# sourceMappingURL=presentation-scaling.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation-scaling.cjs.js","sources":["../../../../src/components/ContentRender/utils/presentation-scaling.ts"],"sourcesContent":["export const PRESENTATION_DEFAULT_FONT_SIZE_PX = 16;\nexport const PRESENTATION_MIN_BASE_FONT_SIZE_PX = 12;\nexport const PRESENTATION_MIN_FONT_SIZE_PX = 8;\nexport const PRESENTATION_WIDTH_FONT_DIVISOR = 48;\nexport const PRESENTATION_HEIGHT_FONT_RATIO = 0.03;\nexport const PRESENTATION_OVERFLOW_TOLERANCE_PX = 4;\n\nconst MAX_FIT_ITERATIONS = 8;\nconst MIN_FONT_SIZE_DELTA_PX = 0.05;\n\nexport interface PresentationSize {\n height: number;\n width: number;\n}\n\nexport interface FitPresentationFontSizeOptions {\n measure: (fontSize: number) => PresentationSize;\n viewport: PresentationSize;\n}\n\nconst isPositiveFinite = (value: number) => Number.isFinite(value) && value > 0;\n\n/**\n * Matches the viewport-driven base font-size used by HTML presentation slides.\n */\nexport const resolvePresentationBaseFontSize = ({\n height,\n width,\n}: PresentationSize) => {\n if (!isPositiveFinite(width) || !isPositiveFinite(height)) {\n return PRESENTATION_DEFAULT_FONT_SIZE_PX;\n }\n\n return Math.max(\n PRESENTATION_MIN_FONT_SIZE_PX,\n Math.min(\n Math.max(\n PRESENTATION_MIN_BASE_FONT_SIZE_PX,\n width / PRESENTATION_WIDTH_FONT_DIVISOR\n ),\n height * PRESENTATION_HEIGHT_FONT_RATIO\n )\n );\n};\n\nexport const presentationContentFits = (\n viewport: PresentationSize,\n content: PresentationSize\n) =>\n content.height <= viewport.height + PRESENTATION_OVERFLOW_TOLERANCE_PX &&\n content.width <= viewport.width + PRESENTATION_OVERFLOW_TOLERANCE_PX;\n\nexport interface ResolvePresentationCompressionRatioOptions {\n baseFontSize: number;\n content: PresentationSize;\n currentRatio?: number;\n viewport: PresentationSize;\n}\n\n/**\n * Returns the next cumulative compression ratio for content that overflows.\n */\nexport const resolvePresentationCompressionRatio = ({\n baseFontSize,\n content,\n currentRatio = 1,\n viewport,\n}: ResolvePresentationCompressionRatioOptions) => {\n if (\n !isPositiveFinite(baseFontSize) ||\n !isPositiveFinite(viewport.width) ||\n !isPositiveFinite(viewport.height) ||\n !isPositiveFinite(content.width) ||\n !isPositiveFinite(content.height)\n ) {\n return 1;\n }\n\n const heightRatio =\n content.height > viewport.height + PRESENTATION_OVERFLOW_TOLERANCE_PX\n ? viewport.height / content.height\n : 1;\n const widthRatio =\n content.width > viewport.width + PRESENTATION_OVERFLOW_TOLERANCE_PX\n ? viewport.width / content.width\n : 1;\n const minimumRatio = Math.min(\n 1,\n PRESENTATION_MIN_FONT_SIZE_PX / baseFontSize\n );\n\n return Math.max(\n minimumRatio,\n Math.min(1, currentRatio * Math.min(heightRatio, widthRatio))\n );\n};\n\n/**\n * Applies the presentation font-size through `measure` and iteratively shrinks\n * it until the content fits or reaches the shared 8px lower bound.\n */\nexport const fitPresentationFontSize = ({\n measure,\n viewport,\n}: FitPresentationFontSizeOptions) => {\n const baseFontSize = resolvePresentationBaseFontSize(viewport);\n let compressionRatio = 1;\n let fontSize = baseFontSize;\n\n for (let iteration = 0; iteration < MAX_FIT_ITERATIONS; iteration += 1) {\n const content = measure(fontSize);\n\n if (presentationContentFits(viewport, content)) {\n return fontSize;\n }\n\n const nextCompressionRatio = resolvePresentationCompressionRatio({\n baseFontSize,\n content,\n currentRatio: compressionRatio,\n viewport,\n });\n const nextFontSize = Math.max(\n PRESENTATION_MIN_FONT_SIZE_PX,\n baseFontSize * nextCompressionRatio\n );\n\n if (Math.abs(nextFontSize - fontSize) < MIN_FONT_SIZE_DELTA_PX) {\n return nextFontSize;\n }\n\n compressionRatio = nextCompressionRatio;\n fontSize = nextFontSize;\n }\n\n return fontSize;\n};\n"],"names":["PRESENTATION_DEFAULT_FONT_SIZE_PX","PRESENTATION_MIN_BASE_FONT_SIZE_PX","PRESENTATION_MIN_FONT_SIZE_PX","PRESENTATION_WIDTH_FONT_DIVISOR","PRESENTATION_HEIGHT_FONT_RATIO","PRESENTATION_OVERFLOW_TOLERANCE_PX","MAX_FIT_ITERATIONS","MIN_FONT_SIZE_DELTA_PX","isPositiveFinite","value","resolvePresentationBaseFontSize","height","width","presentationContentFits","viewport","content","resolvePresentationCompressionRatio","baseFontSize","currentRatio","heightRatio","widthRatio","minimumRatio","fitPresentationFontSize","measure","compressionRatio","fontSize","iteration","nextCompressionRatio","nextFontSize"],"mappings":"gFAAO,MAAMA,EAAoC,GACpCC,EAAqC,GACrCC,EAAgC,EAChCC,EAAkC,GAClCC,EAAiC,IACjCC,EAAqC,EAE5CC,EAAqB,EACrBC,EAAyB,IAYzBC,EAAoBC,GAAkB,OAAO,SAASA,CAAK,GAAKA,EAAQ,EAKjEC,EAAkC,CAAC,CAC9C,OAAAC,EACA,MAAAC,CACF,IACM,CAACJ,EAAiBI,CAAK,GAAK,CAACJ,EAAiBG,CAAM,EAC/CX,EAGF,KAAK,IACVE,EACA,KAAK,IACH,KAAK,IACHD,EACAW,EAAQT,CAAA,EAEVQ,EAASP,CAAA,CACX,EAISS,EAA0B,CACrCC,EACAC,IAEAA,EAAQ,QAAUD,EAAS,OAAST,GACpCU,EAAQ,OAASD,EAAS,MAAQT,EAYvBW,EAAsC,CAAC,CAClD,aAAAC,EACA,QAAAF,EACA,aAAAG,EAAe,EACf,SAAAJ,CACF,IAAkD,CAChD,GACE,CAACN,EAAiBS,CAAY,GAC9B,CAACT,EAAiBM,EAAS,KAAK,GAChC,CAACN,EAAiBM,EAAS,MAAM,GACjC,CAACN,EAAiBO,EAAQ,KAAK,GAC/B,CAACP,EAAiBO,EAAQ,MAAM,EAEhC,MAAO,GAGT,MAAMI,EACJJ,EAAQ,OAASD,EAAS,OAAST,EAC/BS,EAAS,OAASC,EAAQ,OAC1B,EACAK,EACJL,EAAQ,MAAQD,EAAS,MAAQT,EAC7BS,EAAS,MAAQC,EAAQ,MACzB,EACAM,EAAe,KAAK,IACxB,EACAnB,EAAgCe,CAAA,EAGlC,OAAO,KAAK,IACVI,EACA,KAAK,IAAI,EAAGH,EAAe,KAAK,IAAIC,EAAaC,CAAU,CAAC,CAAA,CAEhE,EAMaE,EAA0B,CAAC,CACtC,QAAAC,EACA,SAAAT,CACF,IAAsC,CACpC,MAAMG,EAAeP,EAAgCI,CAAQ,EAC7D,IAAIU,EAAmB,EACnBC,EAAWR,EAEf,QAASS,EAAY,EAAGA,EAAYpB,EAAoBoB,GAAa,EAAG,CACtE,MAAMX,EAAUQ,EAAQE,CAAQ,EAEhC,GAAIZ,EAAwBC,EAAUC,CAAO,EAC3C,OAAOU,EAGT,MAAME,EAAuBX,EAAoC,CAC/D,aAAAC,EACA,QAAAF,EACA,aAAcS,EACd,SAAAV,CAAA,CACD,EACKc,EAAe,KAAK,IACxB1B,EACAe,EAAeU,CAAA,EAGjB,GAAI,KAAK,IAAIC,EAAeH,CAAQ,EAAIlB,EACtC,OAAOqB,EAGTJ,EAAmBG,EACnBF,EAAWG,CACb,CAEA,OAAOH,CACT"}
@@ -0,0 +1,34 @@
1
+ export declare const PRESENTATION_DEFAULT_FONT_SIZE_PX = 16;
2
+ export declare const PRESENTATION_MIN_BASE_FONT_SIZE_PX = 12;
3
+ export declare const PRESENTATION_MIN_FONT_SIZE_PX = 8;
4
+ export declare const PRESENTATION_WIDTH_FONT_DIVISOR = 48;
5
+ export declare const PRESENTATION_HEIGHT_FONT_RATIO = 0.03;
6
+ export declare const PRESENTATION_OVERFLOW_TOLERANCE_PX = 4;
7
+ export interface PresentationSize {
8
+ height: number;
9
+ width: number;
10
+ }
11
+ export interface FitPresentationFontSizeOptions {
12
+ measure: (fontSize: number) => PresentationSize;
13
+ viewport: PresentationSize;
14
+ }
15
+ /**
16
+ * Matches the viewport-driven base font-size used by HTML presentation slides.
17
+ */
18
+ export declare const resolvePresentationBaseFontSize: ({ height, width, }: PresentationSize) => number;
19
+ export declare const presentationContentFits: (viewport: PresentationSize, content: PresentationSize) => boolean;
20
+ export interface ResolvePresentationCompressionRatioOptions {
21
+ baseFontSize: number;
22
+ content: PresentationSize;
23
+ currentRatio?: number;
24
+ viewport: PresentationSize;
25
+ }
26
+ /**
27
+ * Returns the next cumulative compression ratio for content that overflows.
28
+ */
29
+ export declare const resolvePresentationCompressionRatio: ({ baseFontSize, content, currentRatio, viewport, }: ResolvePresentationCompressionRatioOptions) => number;
30
+ /**
31
+ * Applies the presentation font-size through `measure` and iteratively shrinks
32
+ * it until the content fits or reaches the shared 8px lower bound.
33
+ */
34
+ export declare const fitPresentationFontSize: ({ measure, viewport, }: FitPresentationFontSizeOptions) => number;