markdown-flow-ui 0.2.3-dev.1 → 0.2.3-dev.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 (41) hide show
  1. package/dist/components/ContentRender/SandboxApp.cjs.js +2 -2
  2. package/dist/components/ContentRender/SandboxApp.cjs.js.map +1 -1
  3. package/dist/components/ContentRender/SandboxApp.es.js +95 -106
  4. package/dist/components/ContentRender/SandboxApp.es.js.map +1 -1
  5. package/dist/components/Slide/Slide.cjs.js +1 -1
  6. package/dist/components/Slide/Slide.cjs.js.map +1 -1
  7. package/dist/components/Slide/Slide.es.js +732 -776
  8. package/dist/components/Slide/Slide.es.js.map +1 -1
  9. package/dist/components/Slide/Slide.stories.d.ts +4 -4
  10. package/dist/components/Slide/constants.d.ts +0 -1
  11. package/dist/components/Slide/utils/interactionPlayback.cjs.js +1 -1
  12. package/dist/components/Slide/utils/interactionPlayback.cjs.js.map +1 -1
  13. package/dist/components/Slide/utils/interactionPlayback.d.ts +2 -1
  14. package/dist/components/Slide/utils/interactionPlayback.es.js +3 -2
  15. package/dist/components/Slide/utils/interactionPlayback.es.js.map +1 -1
  16. package/dist/components/Slide/utils/streamingNavigation.cjs.js +1 -1
  17. package/dist/components/Slide/utils/streamingNavigation.cjs.js.map +1 -1
  18. package/dist/components/Slide/utils/streamingNavigation.es.js +15 -9
  19. package/dist/components/Slide/utils/streamingNavigation.es.js.map +1 -1
  20. package/package.json +1 -1
  21. package/dist/components/ContentRender/utils/link-targets.cjs.js +0 -2
  22. package/dist/components/ContentRender/utils/link-targets.cjs.js.map +0 -1
  23. package/dist/components/ContentRender/utils/link-targets.d.ts +0 -6
  24. package/dist/components/ContentRender/utils/link-targets.es.js +0 -26
  25. package/dist/components/ContentRender/utils/link-targets.es.js.map +0 -1
  26. package/dist/components/ContentRender/utils/link-targets.test.d.ts +0 -1
  27. package/dist/components/Slide/constants.cjs.js +0 -2
  28. package/dist/components/Slide/constants.cjs.js.map +0 -1
  29. package/dist/components/Slide/constants.es.js +0 -5
  30. package/dist/components/Slide/constants.es.js.map +0 -1
  31. package/dist/components/Slide/utils/imageOnlyStepVisualReady.cjs.js +0 -2
  32. package/dist/components/Slide/utils/imageOnlyStepVisualReady.cjs.js.map +0 -1
  33. package/dist/components/Slide/utils/imageOnlyStepVisualReady.d.ts +0 -13
  34. package/dist/components/Slide/utils/imageOnlyStepVisualReady.es.js +0 -12
  35. package/dist/components/Slide/utils/imageOnlyStepVisualReady.es.js.map +0 -1
  36. package/dist/components/Slide/utils/silentStepAutoAdvance.cjs.js +0 -2
  37. package/dist/components/Slide/utils/silentStepAutoAdvance.cjs.js.map +0 -1
  38. package/dist/components/Slide/utils/silentStepAutoAdvance.d.ts +0 -14
  39. package/dist/components/Slide/utils/silentStepAutoAdvance.es.js +0 -37
  40. package/dist/components/Slide/utils/silentStepAutoAdvance.es.js.map +0 -1
  41. package/dist/components/Slide/utils/silentStepAutoAdvance.test.d.ts +0 -1
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const T=require("../../_virtual/jsx-runtime.cjs.js"),n=require("react"),oe=require("../ui/loading-overlay-card.cjs.js"),ce=require("./contentRenderI18n.cjs.js"),p=require("./utils/link-targets.cjs.js"),ae=["src","srcset","sizes","alt","class","width","height","style","loading","decoding","crossorigin","referrerpolicy","fetchpriority"],Q=c=>ae.map(s=>`${s}:${c.getAttribute(s)||""}`).join("|"),ie=c=>{const s=new Map;return c.querySelectorAll("img").forEach(l=>{const u=l,o=Q(u),i=s.get(o)||[];i.push(u),s.set(o,i)}),s},le=(c,s)=>{const l=Array.from(c.attributes),u=new Set(l.map(o=>o.name));Array.from(s.attributes).forEach(o=>{u.has(o.name)||s.removeAttribute(o.name)}),l.forEach(o=>{s.setAttribute(o.name,o.value)})},ue=(c,s)=>{s.size&&c.querySelectorAll("img").forEach(l=>{const u=l,o=Q(u),i=s.get(o),y=i?.shift();y&&(le(u,y),u.replaceWith(y),i&&i.length===0&&s.delete(o))})},fe=({html:c,locale:s,loadingText:l,styleLoadingText:u,scriptLoadingText:o,resetToken:i=0,mode:y="content",hasRootVhHeight:J=!1,stretchRootHeight:X=!1,enableScaling:F=!1,disableLoadingOverlay:j=!1})=>{const N=ce.getContentRenderLocaleTexts(s),k=n.useRef(null),[Y,R]=n.useState(!1),[Z,S]=n.useState(!1),[ee,L]=n.useState(!1),_=n.useRef([]),q=n.useRef([]),G=n.useRef(0),V=n.useRef(0),g=n.useRef(null),b=n.useRef(null),x=n.useRef(!1),v=n.useRef(!1),z=n.useRef(i),te=200,d=t=>{t.current&&(clearTimeout(t.current),t.current=null)},U=(t,a,f,H)=>{const h=performance.now()-f.current,I=Math.max(0,te-h);d(a),a.current=window.setTimeout(()=>{t(!1),H?.(),a.current=null},I)};n.useEffect(()=>{const t=k.current?.ownerDocument;if(!t)return;const a="sandbox-spinner-style";let f=t.getElementById(a);f||(f=t.createElement("style"),f.id=a,t.head?.appendChild(f)),f.textContent=`
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const I=require("../../_virtual/jsx-runtime.cjs.js"),n=require("react"),re=require("../ui/loading-overlay-card.cjs.js"),se=require("./contentRenderI18n.cjs.js"),oe=["src","srcset","sizes","alt","class","width","height","style","loading","decoding","crossorigin","referrerpolicy","fetchpriority"],K=c=>oe.map(r=>`${r}:${c.getAttribute(r)||""}`).join("|"),ce=c=>{const r=new Map;return c.querySelectorAll("img").forEach(l=>{const u=l,s=K(u),i=r.get(s)||[];i.push(u),r.set(s,i)}),r},ae=(c,r)=>{const l=Array.from(c.attributes),u=new Set(l.map(s=>s.name));Array.from(r.attributes).forEach(s=>{u.has(s.name)||r.removeAttribute(s.name)}),l.forEach(s=>{r.setAttribute(s.name,s.value)})},ie=(c,r)=>{r.size&&c.querySelectorAll("img").forEach(l=>{const u=l,s=K(u),i=r.get(s),p=i?.shift();p&&(ae(u,p),u.replaceWith(p),i&&i.length===0&&r.delete(s))})},le=({html:c,locale:r,loadingText:l,styleLoadingText:u,scriptLoadingText:s,resetToken:i=0,mode:p="content",hasRootVhHeight:P=!1,stretchRootHeight:Q=!1,enableScaling:D=!1,disableLoadingOverlay:j=!1})=>{const N=se.getContentRenderLocaleTexts(r),T=n.useRef(null),[J,S]=n.useState(!1),[X,R]=n.useState(!1),[Y,M]=n.useState(!1),_=n.useRef([]),L=n.useRef([]),G=n.useRef(0),z=n.useRef(0),y=n.useRef(null),g=n.useRef(null),b=n.useRef(!1),x=n.useRef(!1),F=n.useRef(i),Z=200,d=t=>{t.current&&(clearTimeout(t.current),t.current=null)},U=(t,a,f,k)=>{const m=performance.now()-f.current,A=Math.max(0,Z-m);d(a),a.current=window.setTimeout(()=>{t(!1),k?.(),a.current=null},A)};n.useEffect(()=>{const t=T.current?.ownerDocument;if(!t)return;const a="sandbox-spinner-style";let f=t.getElementById(a);f||(f=t.createElement("style"),f.id=a,t.head?.appendChild(f)),f.textContent=`
2
2
  .sandbox-wrapper { align-items: center; }
3
3
  .sandbox-container { position: relative; width: 100%; }
4
4
  .sandbox-container svg,
@@ -17,5 +17,5 @@
17
17
  justify-content: safe center;
18
18
  }
19
19
  .overflow-y-auto { overflow-y: visible !important; }
20
- `},[]),n.useEffect(()=>{i!==z.current&&(L(!1),z.current=i),d(g),d(b),x.current=!1,v.current=!1;const t=k.current;if(!t)return;const a=t.ownerDocument,f=a?.body;if(!f)return;const H=ie(t);_.current.forEach(e=>e.remove()),_.current=[],q.current.forEach(e=>e.remove()),q.current=[],R(!1),S(!1);const h=a.createElement("div");h.innerHTML=c,h.querySelectorAll("a[href]").forEach(e=>{p.isAnchorElement(e)&&p.shouldForceAnchorHrefToNewTab(e.getAttribute("href"))&&(e.setAttribute("target","_blank"),e.setAttribute("rel",p.mergeAnchorRelValue(e.getAttribute("rel"))))});const I=(c.match(/<script[\s>]/gi)||[]).length,se=(c.match(/<\/script>/gi)||[]).length,W=I>0&&I===se,w=[];Array.from(h.querySelectorAll("style, script")).forEach(e=>{if(e.tagName.toLowerCase()==="style"){const r=a.createElement("style");r.textContent=e.textContent||"",Array.from(e.attributes).forEach(m=>{r.setAttribute(m.name,m.value)}),w.push(r)}else{const r=a.createElement("script");Array.from(e.attributes).forEach(m=>{r.setAttribute(m.name,m.value)}),r.textContent=e.textContent||"",w.push(r)}e.remove()}),ue(h,H);const B=w.some(e=>e.tagName.toLowerCase()==="style"),D=w.some(e=>e.tagName.toLowerCase()==="script");B&&(x.current=!0,G.current=performance.now(),d(g),R(!0)),D&&(v.current=!0,V.current=performance.now(),d(b),S(!0));const O=Array.from(h.childNodes),$=O.length>0;L($),t.replaceChildren(...O);const K=e=>{const r=p.resolveClosestAnchor(e.target);r&&p.shouldForceAnchorHrefToNewTab(r.getAttribute("href"))&&(r.setAttribute("target","_blank"),r.setAttribute("rel",p.mergeAnchorRelValue(r.getAttribute("rel"))))};t.addEventListener("click",K,!0);let A=null;const P=()=>t.childNodes.length===0?!1:(L(!0),A?.disconnect(),A=null,!0);return!$&&D&&W&&(A=new MutationObserver(()=>{P()}),A.observe(t,{childList:!0,subtree:!0})),w.forEach(e=>{if(e.tagName.toLowerCase()==="style"){a.head?.appendChild(e),_.current.push(e);return}if(W){const r=e,m=r.textContent||"";if(!r.src)try{new Function(m)}catch{r.remove();return}try{f.appendChild(r),q.current.push(r)}catch{r.remove()}}else e.remove()}),P(),F&&t.ownerDocument?.defaultView?.__mdf_triggerFitContent?.(),requestAnimationFrame(()=>{B&&U(R,g,G,()=>{x.current=!1}),D&&U(S,b,V,()=>{v.current=!1})}),()=>{A?.disconnect(),t.removeEventListener("click",K,!0)}},[c,i,F]),n.useEffect(()=>()=>{d(g),d(b)},[]),n.useEffect(()=>{j&&(d(g),d(b),x.current=!1,v.current=!1,R(!1),S(!1))},[j]);const E=j?null:Z||v.current?o||l||N.sandboxScriptLoadingText:Y||x.current?u||l||N.sandboxStyleLoadingText:ee?null:l||N.sandboxLoadingText,M=y==="blackboard",C=M&&X,re={position:"relative",width:"100%",height:"100%",display:"flex",flexDirection:"column",justifyContent:C?"flex-start":M?"space-around":"flex-start"},ne={pointerEvents:E?"none":void 0,margin:M?void 0:"auto 0",width:"100%",height:C?"100%":void 0,minHeight:C?0:void 0,flex:C?"1 1 auto":void 0};return T.jsxRuntimeExports.jsxs("div",{"data-root-vh":J?"true":"false",className:"sandbox-wrapper",style:re,"aria-busy":!!E,children:[T.jsxRuntimeExports.jsx("div",{ref:k,className:"sandbox-container",style:ne}),E&&T.jsxRuntimeExports.jsx("div",{style:{position:"absolute",inset:0,zIndex:20,display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:T.jsxRuntimeExports.jsx(oe.default,{message:E})})]})};exports.default=fe;
20
+ `},[]),n.useEffect(()=>{i!==F.current&&(M(!1),F.current=i),d(y),d(g),b.current=!1,x.current=!1;const t=T.current;if(!t)return;const a=t.ownerDocument,f=a?.body;if(!f)return;const k=ce(t);_.current.forEach(e=>e.remove()),_.current=[],L.current.forEach(e=>e.remove()),L.current=[],S(!1),R(!1);const m=a.createElement("div");m.innerHTML=c;const A=(c.match(/<script[\s>]/gi)||[]).length,ne=(c.match(/<\/script>/gi)||[]).length,W=A>0&&A===ne,v=[];Array.from(m.querySelectorAll("style, script")).forEach(e=>{if(e.tagName.toLowerCase()==="style"){const o=a.createElement("style");o.textContent=e.textContent||"",Array.from(e.attributes).forEach(h=>{o.setAttribute(h.name,h.value)}),v.push(o)}else{const o=a.createElement("script");Array.from(e.attributes).forEach(h=>{o.setAttribute(h.name,h.value)}),o.textContent=e.textContent||"",v.push(o)}e.remove()}),ie(m,k);const B=v.some(e=>e.tagName.toLowerCase()==="style"),H=v.some(e=>e.tagName.toLowerCase()==="script");B&&(b.current=!0,G.current=performance.now(),d(y),S(!0)),H&&(x.current=!0,z.current=performance.now(),d(g),R(!0));const O=Array.from(m.childNodes),V=O.length>0;M(V),t.replaceChildren(...O);let w=null;const $=()=>t.childNodes.length===0?!1:(M(!0),w?.disconnect(),w=null,!0);return!V&&H&&W&&(w=new MutationObserver(()=>{$()}),w.observe(t,{childList:!0,subtree:!0})),v.forEach(e=>{if(e.tagName.toLowerCase()==="style"){a.head?.appendChild(e),_.current.push(e);return}if(W){const o=e,h=o.textContent||"";if(!o.src)try{new Function(h)}catch{o.remove();return}try{f.appendChild(o),L.current.push(o)}catch{o.remove()}}else e.remove()}),$(),D&&t.ownerDocument?.defaultView?.__mdf_triggerFitContent?.(),requestAnimationFrame(()=>{B&&U(S,y,G,()=>{b.current=!1}),H&&U(R,g,z,()=>{x.current=!1})}),()=>{w?.disconnect()}},[c,i,D]),n.useEffect(()=>()=>{d(y),d(g)},[]),n.useEffect(()=>{j&&(d(y),d(g),b.current=!1,x.current=!1,S(!1),R(!1))},[j]);const E=j?null:X||x.current?s||l||N.sandboxScriptLoadingText:J||b.current?u||l||N.sandboxStyleLoadingText:Y?null:l||N.sandboxLoadingText,q=p==="blackboard",C=q&&Q,ee={position:"relative",width:"100%",height:"100%",display:"flex",flexDirection:"column",justifyContent:C?"flex-start":q?"space-around":"flex-start"},te={pointerEvents:E?"none":void 0,margin:q?void 0:"auto 0",width:"100%",height:C?"100%":void 0,minHeight:C?0:void 0,flex:C?"1 1 auto":void 0};return I.jsxRuntimeExports.jsxs("div",{"data-root-vh":P?"true":"false",className:"sandbox-wrapper",style:ee,"aria-busy":!!E,children:[I.jsxRuntimeExports.jsx("div",{ref:T,className:"sandbox-container",style:te}),E&&I.jsxRuntimeExports.jsx("div",{style:{position:"absolute",inset:0,zIndex:20,display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:I.jsxRuntimeExports.jsx(re.default,{message:E})})]})};exports.default=le;
21
21
  //# sourceMappingURL=SandboxApp.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SandboxApp.cjs.js","sources":["../../../src/components/ContentRender/SandboxApp.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport LoadingOverlayCard from \"../ui/loading-overlay-card\";\nimport type { MarkdownFlowLocale } from \"../../lib/locale\";\nimport { getContentRenderLocaleTexts } from \"./contentRenderI18n\";\nimport type { ScalingWindow } from \"./utils/iframe-scaling\";\nimport {\n isAnchorElement,\n mergeAnchorRelValue,\n resolveClosestAnchor,\n shouldForceAnchorHrefToNewTab,\n} from \"./utils/link-targets\";\n\nexport interface SandboxAppProps {\n html: string;\n locale?: MarkdownFlowLocale;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n resetToken?: number;\n mode?: \"content\" | \"blackboard\";\n hasRootVhHeight?: boolean;\n stretchRootHeight?: boolean;\n enableScaling?: boolean;\n disableLoadingOverlay?: boolean;\n}\n\nconst IMAGE_REUSE_ATTRIBUTES = [\n \"src\",\n \"srcset\",\n \"sizes\",\n \"alt\",\n \"class\",\n \"width\",\n \"height\",\n \"style\",\n \"loading\",\n \"decoding\",\n \"crossorigin\",\n \"referrerpolicy\",\n \"fetchpriority\",\n];\n\nconst getImageReuseKey = (image: HTMLImageElement) =>\n IMAGE_REUSE_ATTRIBUTES.map(\n (attribute) => `${attribute}:${image.getAttribute(attribute) || \"\"}`\n ).join(\"|\");\n\nconst collectReusableImages = (root: ParentNode) => {\n const imageMap = new Map<string, HTMLImageElement[]>();\n root.querySelectorAll(\"img\").forEach((node) => {\n const image = node as HTMLImageElement;\n const key = getImageReuseKey(image);\n const bucket = imageMap.get(key) || [];\n bucket.push(image);\n imageMap.set(key, bucket);\n });\n return imageMap;\n};\n\nconst syncImageAttributes = (\n sourceImage: HTMLImageElement,\n targetImage: HTMLImageElement\n) => {\n const sourceAttributes = Array.from(sourceImage.attributes);\n const sourceAttributeNames = new Set(\n sourceAttributes.map((attribute) => attribute.name)\n );\n\n Array.from(targetImage.attributes).forEach((attribute) => {\n if (!sourceAttributeNames.has(attribute.name)) {\n targetImage.removeAttribute(attribute.name);\n }\n });\n\n sourceAttributes.forEach((attribute) => {\n targetImage.setAttribute(attribute.name, attribute.value);\n });\n};\n\nconst reuseRenderedImages = (\n root: ParentNode,\n imageMap: Map<string, HTMLImageElement[]>\n) => {\n if (!imageMap.size) return;\n\n root.querySelectorAll(\"img\").forEach((node) => {\n const nextImage = node as HTMLImageElement;\n const key = getImageReuseKey(nextImage);\n const bucket = imageMap.get(key);\n const preservedImage = bucket?.shift();\n if (!preservedImage) return;\n\n syncImageAttributes(nextImage, preservedImage);\n nextImage.replaceWith(preservedImage);\n\n if (bucket && bucket.length === 0) {\n imageMap.delete(key);\n }\n });\n};\n\nconst SandboxApp: React.FC<SandboxAppProps> = ({\n html,\n locale,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n resetToken = 0,\n mode = \"content\",\n hasRootVhHeight = false,\n stretchRootHeight = false,\n enableScaling = false,\n disableLoadingOverlay = false,\n}) => {\n const localeTexts = getContentRenderLocaleTexts(locale);\n const containerRef = useRef<HTMLDivElement>(null);\n const [isGeneratingStyles, setIsGeneratingStyles] = useState(false);\n const [isGeneratingScripts, setIsGeneratingScripts] = useState(false);\n const [hasRenderedContent, setHasRenderedContent] = useState(false);\n const appendedStylesRef = useRef<HTMLStyleElement[]>([]);\n const appendedScriptsRef = useRef<HTMLScriptElement[]>([]);\n const styleStartRef = useRef(0);\n const scriptStartRef = useRef(0);\n const styleTimerRef = useRef<number | null>(null);\n const scriptTimerRef = useRef<number | null>(null);\n const hasStylesRef = useRef(false);\n const hasScriptsRef = useRef(false);\n const prevResetTokenRef = useRef(resetToken);\n const MIN_LOADING_MS = 200;\n\n const clearTimer = (timerRef: React.MutableRefObject<number | null>) => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const settleStateWithMinimumDelay = (\n setter: React.Dispatch<React.SetStateAction<boolean>>,\n timerRef: React.MutableRefObject<number | null>,\n startRef: React.MutableRefObject<number>,\n onDone?: () => void\n ) => {\n const elapsed = performance.now() - startRef.current;\n const delay = Math.max(0, MIN_LOADING_MS - elapsed);\n clearTimer(timerRef);\n timerRef.current = window.setTimeout(() => {\n setter(false);\n onDone?.();\n timerRef.current = null;\n }, delay);\n };\n\n useEffect(() => {\n const doc = containerRef.current?.ownerDocument;\n if (!doc) return;\n const styleId = \"sandbox-spinner-style\";\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = doc.createElement(\"style\");\n styleEl.id = styleId;\n doc.head?.appendChild(styleEl);\n }\n styleEl.textContent = `\n .sandbox-wrapper { align-items: center; }\n .sandbox-container { position: relative; width: 100%; }\n .sandbox-container svg,\n .sandbox-container img { display: block; margin-left: auto; margin-right: auto; }\n /* Hide scroll UI without removing scroll semantics. Content roots with\n inline style=\"height:100vh; overflow-y:auto\" are the signal that\n IframeSandbox.getInnerScrollableHeight relies on to grow the iframe\n when content exceeds the viewport. We must not change overflow-y,\n but sub-pixel rounding (1px below the +1 detection threshold) can\n still surface a phantom scrollbar on content that visually fits.\n Hide the scrollbar UI globally; when content truly overflows the\n iframe is resized and no scrollbar would render anyway. */\n .sandbox-container *::-webkit-scrollbar { display: none; }\n .sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }\n .justify-\\\\[safe_center\\\\]{\n justify-content: safe center;\n }\n .overflow-y-auto { overflow-y: visible !important; }\n `;\n }, []);\n\n useEffect(() => {\n if (resetToken !== prevResetTokenRef.current) {\n setHasRenderedContent(false);\n prevResetTokenRef.current = resetToken;\n }\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n\n const container = containerRef.current;\n if (!container) return;\n const doc = container.ownerDocument;\n const body = doc?.body;\n if (!body) return;\n const reusableImages = collectReusableImages(container);\n\n appendedStylesRef.current.forEach((node) => node.remove());\n appendedStylesRef.current = [];\n appendedScriptsRef.current.forEach((node) => node.remove());\n appendedScriptsRef.current = [];\n\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n const wrapper = doc.createElement(\"div\");\n wrapper.innerHTML = html;\n wrapper.querySelectorAll(\"a[href]\").forEach((node) => {\n if (!isAnchorElement(node)) {\n return;\n }\n\n if (!shouldForceAnchorHrefToNewTab(node.getAttribute(\"href\"))) {\n return;\n }\n\n node.setAttribute(\"target\", \"_blank\");\n node.setAttribute(\"rel\", mergeAnchorRelValue(node.getAttribute(\"rel\")));\n });\n\n const openScriptCount = (html.match(/<script[\\s>]/gi) || []).length;\n const closeScriptCount = (html.match(/<\\/script>/gi) || []).length;\n const shouldExecuteScripts =\n openScriptCount > 0 && openScriptCount === closeScriptCount;\n\n const resourceQueue: HTMLElement[] = [];\n\n Array.from(wrapper.querySelectorAll(\"style, script\")).forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n const cloned = doc.createElement(\"style\");\n cloned.textContent = node.textContent || \"\";\n Array.from(node.attributes).forEach((attr) => {\n cloned.setAttribute(attr.name, attr.value);\n });\n resourceQueue.push(cloned);\n } else {\n const replacement = doc.createElement(\"script\");\n Array.from(node.attributes).forEach((attr) => {\n replacement.setAttribute(attr.name, attr.value);\n });\n replacement.textContent = node.textContent || \"\";\n resourceQueue.push(replacement);\n }\n node.remove();\n });\n reuseRenderedImages(wrapper, reusableImages);\n\n const hasStyles = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"style\"\n );\n const hasScripts = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"script\"\n );\n if (hasStyles) {\n hasStylesRef.current = true;\n styleStartRef.current = performance.now();\n clearTimer(styleTimerRef);\n setIsGeneratingStyles(true);\n }\n if (hasScripts) {\n hasScriptsRef.current = true;\n scriptStartRef.current = performance.now();\n clearTimer(scriptTimerRef);\n setIsGeneratingScripts(true);\n }\n\n const contentNodes = Array.from(wrapper.childNodes);\n const hasInitialContent = contentNodes.length > 0;\n setHasRenderedContent(hasInitialContent);\n container.replaceChildren(...contentNodes);\n\n const handleLinkClick = (event: MouseEvent) => {\n const anchor = resolveClosestAnchor(event.target);\n if (!anchor) {\n return;\n }\n\n if (!shouldForceAnchorHrefToNewTab(anchor.getAttribute(\"href\"))) {\n return;\n }\n\n anchor.setAttribute(\"target\", \"_blank\");\n anchor.setAttribute(\n \"rel\",\n mergeAnchorRelValue(anchor.getAttribute(\"rel\"))\n );\n };\n container.addEventListener(\"click\", handleLinkClick, true);\n\n let scriptContentObserver: MutationObserver | null = null;\n const markRenderedContentFromContainer = () => {\n if (container.childNodes.length === 0) {\n return false;\n }\n\n setHasRenderedContent(true);\n scriptContentObserver?.disconnect();\n scriptContentObserver = null;\n return true;\n };\n if (!hasInitialContent && hasScripts && shouldExecuteScripts) {\n scriptContentObserver = new MutationObserver(() => {\n markRenderedContentFromContainer();\n });\n scriptContentObserver.observe(container, {\n childList: true,\n subtree: true,\n });\n }\n\n resourceQueue.forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n doc.head?.appendChild(node);\n appendedStylesRef.current.push(node as HTMLStyleElement);\n return;\n }\n\n if (shouldExecuteScripts) {\n const scriptNode = node as HTMLScriptElement;\n const scriptText = scriptNode.textContent || \"\";\n const shouldValidate = !scriptNode.src;\n\n if (shouldValidate) {\n try {\n // Validate script is syntactically complete before executing\n\n new Function(scriptText);\n } catch {\n scriptNode.remove();\n return;\n }\n }\n\n try {\n body.appendChild(scriptNode);\n appendedScriptsRef.current.push(scriptNode);\n } catch {\n scriptNode.remove();\n }\n } else {\n // Defer execution until all script tags are fully received\n node.remove();\n }\n });\n markRenderedContentFromContainer();\n if (enableScaling) {\n const win = container.ownerDocument?.defaultView as ScalingWindow | null;\n win?.__mdf_triggerFitContent?.();\n }\n\n requestAnimationFrame(() => {\n if (hasStyles) {\n settleStateWithMinimumDelay(\n setIsGeneratingStyles,\n styleTimerRef,\n styleStartRef,\n () => {\n hasStylesRef.current = false;\n }\n );\n }\n if (hasScripts) {\n settleStateWithMinimumDelay(\n setIsGeneratingScripts,\n scriptTimerRef,\n scriptStartRef,\n () => {\n hasScriptsRef.current = false;\n }\n );\n }\n });\n\n return () => {\n scriptContentObserver?.disconnect();\n container.removeEventListener(\"click\", handleLinkClick, true);\n };\n }, [html, resetToken, enableScaling]);\n\n useEffect(\n () => () => {\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n },\n []\n );\n\n useEffect(() => {\n if (!disableLoadingOverlay) {\n return;\n }\n\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n }, [disableLoadingOverlay]);\n\n const overlayMessage = (() => {\n if (disableLoadingOverlay) {\n return null;\n }\n\n if (isGeneratingScripts || hasScriptsRef.current)\n return (\n scriptLoadingText || loadingText || localeTexts.sandboxScriptLoadingText\n );\n if (isGeneratingStyles || hasStylesRef.current)\n return (\n styleLoadingText || loadingText || localeTexts.sandboxStyleLoadingText\n );\n if (!hasRenderedContent)\n return loadingText || localeTexts.sandboxLoadingText;\n return null;\n })();\n\n const isBlackboard = mode === \"blackboard\";\n const shouldStretchRootHeight = isBlackboard && stretchRootHeight;\n const sandboxWrapperStyle: React.CSSProperties = {\n position: \"relative\",\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n // Keep blackboard scroll behavior while centering content in non-blackboard mode\n justifyContent: shouldStretchRootHeight\n ? \"flex-start\"\n : isBlackboard\n ? \"space-around\"\n : \"flex-start\",\n };\n const sandboxContainerStyle: React.CSSProperties = {\n pointerEvents: overlayMessage ? \"none\" : undefined,\n margin: isBlackboard ? undefined : \"auto 0\",\n width: \"100%\",\n height: shouldStretchRootHeight ? \"100%\" : undefined,\n minHeight: shouldStretchRootHeight ? 0 : undefined,\n flex: shouldStretchRootHeight ? \"1 1 auto\" : undefined,\n };\n\n return (\n <div\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className=\"sandbox-wrapper\"\n style={sandboxWrapperStyle}\n aria-busy={!!overlayMessage}\n >\n <div\n ref={containerRef}\n className=\"sandbox-container\"\n style={sandboxContainerStyle}\n />\n {overlayMessage && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 20,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"none\",\n }}\n >\n <LoadingOverlayCard message={overlayMessage} />\n </div>\n )}\n </div>\n );\n};\n\nexport default SandboxApp;\n"],"names":["IMAGE_REUSE_ATTRIBUTES","getImageReuseKey","image","attribute","collectReusableImages","root","imageMap","node","key","bucket","syncImageAttributes","sourceImage","targetImage","sourceAttributes","sourceAttributeNames","reuseRenderedImages","nextImage","preservedImage","SandboxApp","html","locale","loadingText","styleLoadingText","scriptLoadingText","resetToken","mode","hasRootVhHeight","stretchRootHeight","enableScaling","disableLoadingOverlay","localeTexts","getContentRenderLocaleTexts","containerRef","useRef","isGeneratingStyles","setIsGeneratingStyles","useState","isGeneratingScripts","setIsGeneratingScripts","hasRenderedContent","setHasRenderedContent","appendedStylesRef","appendedScriptsRef","styleStartRef","scriptStartRef","styleTimerRef","scriptTimerRef","hasStylesRef","hasScriptsRef","prevResetTokenRef","MIN_LOADING_MS","clearTimer","timerRef","settleStateWithMinimumDelay","setter","startRef","onDone","elapsed","delay","useEffect","doc","styleId","styleEl","container","body","reusableImages","wrapper","isAnchorElement","shouldForceAnchorHrefToNewTab","mergeAnchorRelValue","openScriptCount","closeScriptCount","shouldExecuteScripts","resourceQueue","cloned","attr","replacement","hasStyles","hasScripts","contentNodes","hasInitialContent","handleLinkClick","event","anchor","resolveClosestAnchor","scriptContentObserver","markRenderedContentFromContainer","scriptNode","scriptText","overlayMessage","isBlackboard","shouldStretchRootHeight","sandboxWrapperStyle","sandboxContainerStyle","jsxs","jsx","LoadingOverlayCard"],"mappings":"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"}
1
+ {"version":3,"file":"SandboxApp.cjs.js","sources":["../../../src/components/ContentRender/SandboxApp.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport LoadingOverlayCard from \"../ui/loading-overlay-card\";\nimport type { MarkdownFlowLocale } from \"../../lib/locale\";\nimport { getContentRenderLocaleTexts } from \"./contentRenderI18n\";\nimport type { ScalingWindow } from \"./utils/iframe-scaling\";\n\nexport interface SandboxAppProps {\n html: string;\n locale?: MarkdownFlowLocale;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n resetToken?: number;\n mode?: \"content\" | \"blackboard\";\n hasRootVhHeight?: boolean;\n stretchRootHeight?: boolean;\n enableScaling?: boolean;\n disableLoadingOverlay?: boolean;\n}\n\nconst IMAGE_REUSE_ATTRIBUTES = [\n \"src\",\n \"srcset\",\n \"sizes\",\n \"alt\",\n \"class\",\n \"width\",\n \"height\",\n \"style\",\n \"loading\",\n \"decoding\",\n \"crossorigin\",\n \"referrerpolicy\",\n \"fetchpriority\",\n];\n\nconst getImageReuseKey = (image: HTMLImageElement) =>\n IMAGE_REUSE_ATTRIBUTES.map(\n (attribute) => `${attribute}:${image.getAttribute(attribute) || \"\"}`\n ).join(\"|\");\n\nconst collectReusableImages = (root: ParentNode) => {\n const imageMap = new Map<string, HTMLImageElement[]>();\n root.querySelectorAll(\"img\").forEach((node) => {\n const image = node as HTMLImageElement;\n const key = getImageReuseKey(image);\n const bucket = imageMap.get(key) || [];\n bucket.push(image);\n imageMap.set(key, bucket);\n });\n return imageMap;\n};\n\nconst syncImageAttributes = (\n sourceImage: HTMLImageElement,\n targetImage: HTMLImageElement\n) => {\n const sourceAttributes = Array.from(sourceImage.attributes);\n const sourceAttributeNames = new Set(\n sourceAttributes.map((attribute) => attribute.name)\n );\n\n Array.from(targetImage.attributes).forEach((attribute) => {\n if (!sourceAttributeNames.has(attribute.name)) {\n targetImage.removeAttribute(attribute.name);\n }\n });\n\n sourceAttributes.forEach((attribute) => {\n targetImage.setAttribute(attribute.name, attribute.value);\n });\n};\n\nconst reuseRenderedImages = (\n root: ParentNode,\n imageMap: Map<string, HTMLImageElement[]>\n) => {\n if (!imageMap.size) return;\n\n root.querySelectorAll(\"img\").forEach((node) => {\n const nextImage = node as HTMLImageElement;\n const key = getImageReuseKey(nextImage);\n const bucket = imageMap.get(key);\n const preservedImage = bucket?.shift();\n if (!preservedImage) return;\n\n syncImageAttributes(nextImage, preservedImage);\n nextImage.replaceWith(preservedImage);\n\n if (bucket && bucket.length === 0) {\n imageMap.delete(key);\n }\n });\n};\n\nconst SandboxApp: React.FC<SandboxAppProps> = ({\n html,\n locale,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n resetToken = 0,\n mode = \"content\",\n hasRootVhHeight = false,\n stretchRootHeight = false,\n enableScaling = false,\n disableLoadingOverlay = false,\n}) => {\n const localeTexts = getContentRenderLocaleTexts(locale);\n const containerRef = useRef<HTMLDivElement>(null);\n const [isGeneratingStyles, setIsGeneratingStyles] = useState(false);\n const [isGeneratingScripts, setIsGeneratingScripts] = useState(false);\n const [hasRenderedContent, setHasRenderedContent] = useState(false);\n const appendedStylesRef = useRef<HTMLStyleElement[]>([]);\n const appendedScriptsRef = useRef<HTMLScriptElement[]>([]);\n const styleStartRef = useRef(0);\n const scriptStartRef = useRef(0);\n const styleTimerRef = useRef<number | null>(null);\n const scriptTimerRef = useRef<number | null>(null);\n const hasStylesRef = useRef(false);\n const hasScriptsRef = useRef(false);\n const prevResetTokenRef = useRef(resetToken);\n const MIN_LOADING_MS = 200;\n\n const clearTimer = (timerRef: React.MutableRefObject<number | null>) => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const settleStateWithMinimumDelay = (\n setter: React.Dispatch<React.SetStateAction<boolean>>,\n timerRef: React.MutableRefObject<number | null>,\n startRef: React.MutableRefObject<number>,\n onDone?: () => void\n ) => {\n const elapsed = performance.now() - startRef.current;\n const delay = Math.max(0, MIN_LOADING_MS - elapsed);\n clearTimer(timerRef);\n timerRef.current = window.setTimeout(() => {\n setter(false);\n onDone?.();\n timerRef.current = null;\n }, delay);\n };\n\n useEffect(() => {\n const doc = containerRef.current?.ownerDocument;\n if (!doc) return;\n const styleId = \"sandbox-spinner-style\";\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = doc.createElement(\"style\");\n styleEl.id = styleId;\n doc.head?.appendChild(styleEl);\n }\n styleEl.textContent = `\n .sandbox-wrapper { align-items: center; }\n .sandbox-container { position: relative; width: 100%; }\n .sandbox-container svg,\n .sandbox-container img { display: block; margin-left: auto; margin-right: auto; }\n /* Hide scroll UI without removing scroll semantics. Content roots with\n inline style=\"height:100vh; overflow-y:auto\" are the signal that\n IframeSandbox.getInnerScrollableHeight relies on to grow the iframe\n when content exceeds the viewport. We must not change overflow-y,\n but sub-pixel rounding (1px below the +1 detection threshold) can\n still surface a phantom scrollbar on content that visually fits.\n Hide the scrollbar UI globally; when content truly overflows the\n iframe is resized and no scrollbar would render anyway. */\n .sandbox-container *::-webkit-scrollbar { display: none; }\n .sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }\n .justify-\\\\[safe_center\\\\]{\n justify-content: safe center;\n }\n .overflow-y-auto { overflow-y: visible !important; }\n `;\n }, []);\n\n useEffect(() => {\n if (resetToken !== prevResetTokenRef.current) {\n setHasRenderedContent(false);\n prevResetTokenRef.current = resetToken;\n }\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n\n const container = containerRef.current;\n if (!container) return;\n const doc = container.ownerDocument;\n const body = doc?.body;\n if (!body) return;\n const reusableImages = collectReusableImages(container);\n\n appendedStylesRef.current.forEach((node) => node.remove());\n appendedStylesRef.current = [];\n appendedScriptsRef.current.forEach((node) => node.remove());\n appendedScriptsRef.current = [];\n\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n const wrapper = doc.createElement(\"div\");\n wrapper.innerHTML = html;\n\n const openScriptCount = (html.match(/<script[\\s>]/gi) || []).length;\n const closeScriptCount = (html.match(/<\\/script>/gi) || []).length;\n const shouldExecuteScripts =\n openScriptCount > 0 && openScriptCount === closeScriptCount;\n\n const resourceQueue: HTMLElement[] = [];\n\n Array.from(wrapper.querySelectorAll(\"style, script\")).forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n const cloned = doc.createElement(\"style\");\n cloned.textContent = node.textContent || \"\";\n Array.from(node.attributes).forEach((attr) => {\n cloned.setAttribute(attr.name, attr.value);\n });\n resourceQueue.push(cloned);\n } else {\n const replacement = doc.createElement(\"script\");\n Array.from(node.attributes).forEach((attr) => {\n replacement.setAttribute(attr.name, attr.value);\n });\n replacement.textContent = node.textContent || \"\";\n resourceQueue.push(replacement);\n }\n node.remove();\n });\n reuseRenderedImages(wrapper, reusableImages);\n\n const hasStyles = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"style\"\n );\n const hasScripts = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"script\"\n );\n if (hasStyles) {\n hasStylesRef.current = true;\n styleStartRef.current = performance.now();\n clearTimer(styleTimerRef);\n setIsGeneratingStyles(true);\n }\n if (hasScripts) {\n hasScriptsRef.current = true;\n scriptStartRef.current = performance.now();\n clearTimer(scriptTimerRef);\n setIsGeneratingScripts(true);\n }\n\n const contentNodes = Array.from(wrapper.childNodes);\n const hasInitialContent = contentNodes.length > 0;\n setHasRenderedContent(hasInitialContent);\n container.replaceChildren(...contentNodes);\n\n let scriptContentObserver: MutationObserver | null = null;\n const markRenderedContentFromContainer = () => {\n if (container.childNodes.length === 0) {\n return false;\n }\n\n setHasRenderedContent(true);\n scriptContentObserver?.disconnect();\n scriptContentObserver = null;\n return true;\n };\n if (!hasInitialContent && hasScripts && shouldExecuteScripts) {\n scriptContentObserver = new MutationObserver(() => {\n markRenderedContentFromContainer();\n });\n scriptContentObserver.observe(container, {\n childList: true,\n subtree: true,\n });\n }\n\n resourceQueue.forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n doc.head?.appendChild(node);\n appendedStylesRef.current.push(node as HTMLStyleElement);\n return;\n }\n\n if (shouldExecuteScripts) {\n const scriptNode = node as HTMLScriptElement;\n const scriptText = scriptNode.textContent || \"\";\n const shouldValidate = !scriptNode.src;\n\n if (shouldValidate) {\n try {\n // Validate script is syntactically complete before executing\n\n new Function(scriptText);\n } catch {\n scriptNode.remove();\n return;\n }\n }\n\n try {\n body.appendChild(scriptNode);\n appendedScriptsRef.current.push(scriptNode);\n } catch {\n scriptNode.remove();\n }\n } else {\n // Defer execution until all script tags are fully received\n node.remove();\n }\n });\n markRenderedContentFromContainer();\n if (enableScaling) {\n const win = container.ownerDocument?.defaultView as ScalingWindow | null;\n win?.__mdf_triggerFitContent?.();\n }\n\n requestAnimationFrame(() => {\n if (hasStyles) {\n settleStateWithMinimumDelay(\n setIsGeneratingStyles,\n styleTimerRef,\n styleStartRef,\n () => {\n hasStylesRef.current = false;\n }\n );\n }\n if (hasScripts) {\n settleStateWithMinimumDelay(\n setIsGeneratingScripts,\n scriptTimerRef,\n scriptStartRef,\n () => {\n hasScriptsRef.current = false;\n }\n );\n }\n });\n\n return () => {\n scriptContentObserver?.disconnect();\n };\n }, [html, resetToken, enableScaling]);\n\n useEffect(\n () => () => {\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n },\n []\n );\n\n useEffect(() => {\n if (!disableLoadingOverlay) {\n return;\n }\n\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n }, [disableLoadingOverlay]);\n\n const overlayMessage = (() => {\n if (disableLoadingOverlay) {\n return null;\n }\n\n if (isGeneratingScripts || hasScriptsRef.current)\n return (\n scriptLoadingText || loadingText || localeTexts.sandboxScriptLoadingText\n );\n if (isGeneratingStyles || hasStylesRef.current)\n return (\n styleLoadingText || loadingText || localeTexts.sandboxStyleLoadingText\n );\n if (!hasRenderedContent)\n return loadingText || localeTexts.sandboxLoadingText;\n return null;\n })();\n\n const isBlackboard = mode === \"blackboard\";\n const shouldStretchRootHeight = isBlackboard && stretchRootHeight;\n const sandboxWrapperStyle: React.CSSProperties = {\n position: \"relative\",\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n // Keep blackboard scroll behavior while centering content in non-blackboard mode\n justifyContent: shouldStretchRootHeight\n ? \"flex-start\"\n : isBlackboard\n ? \"space-around\"\n : \"flex-start\",\n };\n const sandboxContainerStyle: React.CSSProperties = {\n pointerEvents: overlayMessage ? \"none\" : undefined,\n margin: isBlackboard ? undefined : \"auto 0\",\n width: \"100%\",\n height: shouldStretchRootHeight ? \"100%\" : undefined,\n minHeight: shouldStretchRootHeight ? 0 : undefined,\n flex: shouldStretchRootHeight ? \"1 1 auto\" : undefined,\n };\n\n return (\n <div\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className=\"sandbox-wrapper\"\n style={sandboxWrapperStyle}\n aria-busy={!!overlayMessage}\n >\n <div\n ref={containerRef}\n className=\"sandbox-container\"\n style={sandboxContainerStyle}\n />\n {overlayMessage && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 20,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"none\",\n }}\n >\n <LoadingOverlayCard message={overlayMessage} />\n </div>\n )}\n </div>\n );\n};\n\nexport default SandboxApp;\n"],"names":["IMAGE_REUSE_ATTRIBUTES","getImageReuseKey","image","attribute","collectReusableImages","root","imageMap","node","key","bucket","syncImageAttributes","sourceImage","targetImage","sourceAttributes","sourceAttributeNames","reuseRenderedImages","nextImage","preservedImage","SandboxApp","html","locale","loadingText","styleLoadingText","scriptLoadingText","resetToken","mode","hasRootVhHeight","stretchRootHeight","enableScaling","disableLoadingOverlay","localeTexts","getContentRenderLocaleTexts","containerRef","useRef","isGeneratingStyles","setIsGeneratingStyles","useState","isGeneratingScripts","setIsGeneratingScripts","hasRenderedContent","setHasRenderedContent","appendedStylesRef","appendedScriptsRef","styleStartRef","scriptStartRef","styleTimerRef","scriptTimerRef","hasStylesRef","hasScriptsRef","prevResetTokenRef","MIN_LOADING_MS","clearTimer","timerRef","settleStateWithMinimumDelay","setter","startRef","onDone","elapsed","delay","useEffect","doc","styleId","styleEl","container","body","reusableImages","wrapper","openScriptCount","closeScriptCount","shouldExecuteScripts","resourceQueue","cloned","attr","replacement","hasStyles","hasScripts","contentNodes","hasInitialContent","scriptContentObserver","markRenderedContentFromContainer","scriptNode","scriptText","overlayMessage","isBlackboard","shouldStretchRootHeight","sandboxWrapperStyle","sandboxContainerStyle","jsxs","jsx","LoadingOverlayCard"],"mappings":"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"}
@@ -1,9 +1,8 @@
1
1
  import { j as R } from "../../_virtual/jsx-runtime.es.js";
2
2
  import { useRef as f, useState as q, useEffect as N } from "react";
3
- import ie from "../ui/loading-overlay-card.es.js";
4
- import { getContentRenderLocaleTexts as le } from "./contentRenderI18n.es.js";
5
- import { isAnchorElement as ue, shouldForceAnchorHrefToNewTab as P, mergeAnchorRelValue as X, resolveClosestAnchor as fe } from "./utils/link-targets.es.js";
6
- const de = [
3
+ import oe from "../ui/loading-overlay-card.es.js";
4
+ import { getContentRenderLocaleTexts as ae } from "./contentRenderI18n.es.js";
5
+ const ce = [
7
6
  "src",
8
7
  "srcset",
9
8
  "sizes",
@@ -17,55 +16,55 @@ const de = [
17
16
  "crossorigin",
18
17
  "referrerpolicy",
19
18
  "fetchpriority"
20
- ], Y = (o) => de.map(
19
+ ], J = (o) => ce.map(
21
20
  (n) => `${n}:${o.getAttribute(n) || ""}`
22
- ).join("|"), he = (o) => {
21
+ ).join("|"), ie = (o) => {
23
22
  const n = /* @__PURE__ */ new Map();
24
23
  return o.querySelectorAll("img").forEach((i) => {
25
- const l = i, s = Y(l), a = n.get(s) || [];
26
- a.push(l), n.set(s, a);
24
+ const l = i, r = J(l), c = n.get(r) || [];
25
+ c.push(l), n.set(r, c);
27
26
  }), n;
28
- }, me = (o, n) => {
27
+ }, le = (o, n) => {
29
28
  const i = Array.from(o.attributes), l = new Set(
30
- i.map((s) => s.name)
29
+ i.map((r) => r.name)
31
30
  );
32
- Array.from(n.attributes).forEach((s) => {
33
- l.has(s.name) || n.removeAttribute(s.name);
34
- }), i.forEach((s) => {
35
- n.setAttribute(s.name, s.value);
31
+ Array.from(n.attributes).forEach((r) => {
32
+ l.has(r.name) || n.removeAttribute(r.name);
33
+ }), i.forEach((r) => {
34
+ n.setAttribute(r.name, r.value);
36
35
  });
37
- }, pe = (o, n) => {
36
+ }, ue = (o, n) => {
38
37
  n.size && o.querySelectorAll("img").forEach((i) => {
39
- const l = i, s = Y(l), a = n.get(s), p = a?.shift();
40
- p && (me(l, p), l.replaceWith(p), a && a.length === 0 && n.delete(s));
38
+ const l = i, r = J(l), c = n.get(r), p = c?.shift();
39
+ p && (le(l, p), l.replaceWith(p), c && c.length === 0 && n.delete(r));
41
40
  });
42
- }, Ae = ({
41
+ }, ye = ({
43
42
  html: o,
44
43
  locale: n,
45
44
  loadingText: i,
46
45
  styleLoadingText: l,
47
- scriptLoadingText: s,
48
- resetToken: a = 0,
46
+ scriptLoadingText: r,
47
+ resetToken: c = 0,
49
48
  mode: p = "content",
50
- hasRootVhHeight: Z = !1,
51
- stretchRootHeight: ee = !1,
52
- enableScaling: F = !1,
53
- disableLoadingOverlay: k = !1
49
+ hasRootVhHeight: P = !1,
50
+ stretchRootHeight: X = !1,
51
+ enableScaling: z = !1,
52
+ disableLoadingOverlay: j = !1
54
53
  }) => {
55
- const L = le(n), T = f(null), [te, A] = q(!1), [re, S] = q(!1), [ne, j] = q(!1), _ = f([]), H = f([]), z = f(0), U = f(0), y = f(null), g = f(null), b = f(!1), x = f(!1), V = f(a), se = 200, d = (t) => {
54
+ const T = ae(n), L = f(null), [Y, S] = q(!1), [Z, C] = q(!1), [ee, M] = q(!1), _ = f([]), k = f([]), F = f(0), U = f(0), y = f(null), g = f(null), b = f(!1), x = f(!1), W = f(c), te = 200, d = (t) => {
56
55
  t.current && (clearTimeout(t.current), t.current = null);
57
- }, W = (t, c, u, D) => {
58
- const h = performance.now() - u.current, I = Math.max(0, se - h);
59
- d(c), c.current = window.setTimeout(() => {
60
- t(!1), D?.(), c.current = null;
56
+ }, B = (t, a, u, D) => {
57
+ const m = performance.now() - u.current, I = Math.max(0, te - m);
58
+ d(a), a.current = window.setTimeout(() => {
59
+ t(!1), D?.(), a.current = null;
61
60
  }, I);
62
61
  };
63
62
  N(() => {
64
- const t = T.current?.ownerDocument;
63
+ const t = L.current?.ownerDocument;
65
64
  if (!t) return;
66
- const c = "sandbox-spinner-style";
67
- let u = t.getElementById(c);
68
- u || (u = t.createElement("style"), u.id = c, t.head?.appendChild(u)), u.textContent = `
65
+ const a = "sandbox-spinner-style";
66
+ let u = t.getElementById(a);
67
+ u || (u = t.createElement("style"), u.id = a, t.head?.appendChild(u)), u.textContent = `
69
68
  .sandbox-wrapper { align-items: center; }
70
69
  .sandbox-container { position: relative; width: 100%; }
71
70
  .sandbox-container svg,
@@ -86,86 +85,76 @@ const de = [
86
85
  .overflow-y-auto { overflow-y: visible !important; }
87
86
  `;
88
87
  }, []), N(() => {
89
- a !== V.current && (j(!1), V.current = a), d(y), d(g), b.current = !1, x.current = !1;
90
- const t = T.current;
88
+ c !== W.current && (M(!1), W.current = c), d(y), d(g), b.current = !1, x.current = !1;
89
+ const t = L.current;
91
90
  if (!t) return;
92
- const c = t.ownerDocument, u = c?.body;
91
+ const a = t.ownerDocument, u = a?.body;
93
92
  if (!u) return;
94
- const D = he(t);
95
- _.current.forEach((e) => e.remove()), _.current = [], H.current.forEach((e) => e.remove()), H.current = [], A(!1), S(!1);
96
- const h = c.createElement("div");
97
- h.innerHTML = o, h.querySelectorAll("a[href]").forEach((e) => {
98
- ue(e) && P(e.getAttribute("href")) && (e.setAttribute("target", "_blank"), e.setAttribute("rel", X(e.getAttribute("rel"))));
99
- });
100
- const I = (o.match(/<script[\s>]/gi) || []).length, ae = (o.match(/<\/script>/gi) || []).length, B = I > 0 && I === ae, v = [];
101
- Array.from(h.querySelectorAll("style, script")).forEach((e) => {
93
+ const D = ie(t);
94
+ _.current.forEach((e) => e.remove()), _.current = [], k.current.forEach((e) => e.remove()), k.current = [], S(!1), C(!1);
95
+ const m = a.createElement("div");
96
+ m.innerHTML = o;
97
+ const I = (o.match(/<script[\s>]/gi) || []).length, se = (o.match(/<\/script>/gi) || []).length, V = I > 0 && I === se, w = [];
98
+ Array.from(m.querySelectorAll("style, script")).forEach((e) => {
102
99
  if (e.tagName.toLowerCase() === "style") {
103
- const r = c.createElement("style");
104
- r.textContent = e.textContent || "", Array.from(e.attributes).forEach((m) => {
105
- r.setAttribute(m.name, m.value);
106
- }), v.push(r);
100
+ const s = a.createElement("style");
101
+ s.textContent = e.textContent || "", Array.from(e.attributes).forEach((h) => {
102
+ s.setAttribute(h.name, h.value);
103
+ }), w.push(s);
107
104
  } else {
108
- const r = c.createElement("script");
109
- Array.from(e.attributes).forEach((m) => {
110
- r.setAttribute(m.name, m.value);
111
- }), r.textContent = e.textContent || "", v.push(r);
105
+ const s = a.createElement("script");
106
+ Array.from(e.attributes).forEach((h) => {
107
+ s.setAttribute(h.name, h.value);
108
+ }), s.textContent = e.textContent || "", w.push(s);
112
109
  }
113
110
  e.remove();
114
- }), pe(h, D);
115
- const O = v.some(
111
+ }), ue(m, D);
112
+ const O = w.some(
116
113
  (e) => e.tagName.toLowerCase() === "style"
117
- ), G = v.some(
114
+ ), G = w.some(
118
115
  (e) => e.tagName.toLowerCase() === "script"
119
116
  );
120
- O && (b.current = !0, z.current = performance.now(), d(y), A(!0)), G && (x.current = !0, U.current = performance.now(), d(g), S(!0));
121
- const $ = Array.from(h.childNodes), K = $.length > 0;
122
- j(K), t.replaceChildren(...$);
123
- const Q = (e) => {
124
- const r = fe(e.target);
125
- r && P(r.getAttribute("href")) && (r.setAttribute("target", "_blank"), r.setAttribute(
126
- "rel",
127
- X(r.getAttribute("rel"))
128
- ));
129
- };
130
- t.addEventListener("click", Q, !0);
131
- let w = null;
132
- const J = () => t.childNodes.length === 0 ? !1 : (j(!0), w?.disconnect(), w = null, !0);
133
- return !K && G && B && (w = new MutationObserver(() => {
134
- J();
135
- }), w.observe(t, {
117
+ O && (b.current = !0, F.current = performance.now(), d(y), S(!0)), G && (x.current = !0, U.current = performance.now(), d(g), C(!0));
118
+ const $ = Array.from(m.childNodes), K = $.length > 0;
119
+ M(K), t.replaceChildren(...$);
120
+ let v = null;
121
+ const Q = () => t.childNodes.length === 0 ? !1 : (M(!0), v?.disconnect(), v = null, !0);
122
+ return !K && G && V && (v = new MutationObserver(() => {
123
+ Q();
124
+ }), v.observe(t, {
136
125
  childList: !0,
137
126
  subtree: !0
138
- })), v.forEach((e) => {
127
+ })), w.forEach((e) => {
139
128
  if (e.tagName.toLowerCase() === "style") {
140
- c.head?.appendChild(e), _.current.push(e);
129
+ a.head?.appendChild(e), _.current.push(e);
141
130
  return;
142
131
  }
143
- if (B) {
144
- const r = e, m = r.textContent || "";
145
- if (!r.src)
132
+ if (V) {
133
+ const s = e, h = s.textContent || "";
134
+ if (!s.src)
146
135
  try {
147
- new Function(m);
136
+ new Function(h);
148
137
  } catch {
149
- r.remove();
138
+ s.remove();
150
139
  return;
151
140
  }
152
141
  try {
153
- u.appendChild(r), H.current.push(r);
142
+ u.appendChild(s), k.current.push(s);
154
143
  } catch {
155
- r.remove();
144
+ s.remove();
156
145
  }
157
146
  } else
158
147
  e.remove();
159
- }), J(), F && t.ownerDocument?.defaultView?.__mdf_triggerFitContent?.(), requestAnimationFrame(() => {
160
- O && W(
161
- A,
148
+ }), Q(), z && t.ownerDocument?.defaultView?.__mdf_triggerFitContent?.(), requestAnimationFrame(() => {
149
+ O && B(
150
+ S,
162
151
  y,
163
- z,
152
+ F,
164
153
  () => {
165
154
  b.current = !1;
166
155
  }
167
- ), G && W(
168
- S,
156
+ ), G && B(
157
+ C,
169
158
  g,
170
159
  U,
171
160
  () => {
@@ -173,49 +162,49 @@ const de = [
173
162
  }
174
163
  );
175
164
  }), () => {
176
- w?.disconnect(), t.removeEventListener("click", Q, !0);
165
+ v?.disconnect();
177
166
  };
178
- }, [o, a, F]), N(
167
+ }, [o, c, z]), N(
179
168
  () => () => {
180
169
  d(y), d(g);
181
170
  },
182
171
  []
183
172
  ), N(() => {
184
- k && (d(y), d(g), b.current = !1, x.current = !1, A(!1), S(!1));
185
- }, [k]);
186
- const C = k ? null : re || x.current ? s || i || L.sandboxScriptLoadingText : te || b.current ? l || i || L.sandboxStyleLoadingText : ne ? null : i || L.sandboxLoadingText, M = p === "blackboard", E = M && ee, oe = {
173
+ j && (d(y), d(g), b.current = !1, x.current = !1, S(!1), C(!1));
174
+ }, [j]);
175
+ const E = j ? null : Z || x.current ? r || i || T.sandboxScriptLoadingText : Y || b.current ? l || i || T.sandboxStyleLoadingText : ee ? null : i || T.sandboxLoadingText, H = p === "blackboard", A = H && X, ne = {
187
176
  position: "relative",
188
177
  width: "100%",
189
178
  height: "100%",
190
179
  display: "flex",
191
180
  flexDirection: "column",
192
181
  // Keep blackboard scroll behavior while centering content in non-blackboard mode
193
- justifyContent: E ? "flex-start" : M ? "space-around" : "flex-start"
194
- }, ce = {
195
- pointerEvents: C ? "none" : void 0,
196
- margin: M ? void 0 : "auto 0",
182
+ justifyContent: A ? "flex-start" : H ? "space-around" : "flex-start"
183
+ }, re = {
184
+ pointerEvents: E ? "none" : void 0,
185
+ margin: H ? void 0 : "auto 0",
197
186
  width: "100%",
198
- height: E ? "100%" : void 0,
199
- minHeight: E ? 0 : void 0,
200
- flex: E ? "1 1 auto" : void 0
187
+ height: A ? "100%" : void 0,
188
+ minHeight: A ? 0 : void 0,
189
+ flex: A ? "1 1 auto" : void 0
201
190
  };
202
191
  return /* @__PURE__ */ R.jsxs(
203
192
  "div",
204
193
  {
205
- "data-root-vh": Z ? "true" : "false",
194
+ "data-root-vh": P ? "true" : "false",
206
195
  className: "sandbox-wrapper",
207
- style: oe,
208
- "aria-busy": !!C,
196
+ style: ne,
197
+ "aria-busy": !!E,
209
198
  children: [
210
199
  /* @__PURE__ */ R.jsx(
211
200
  "div",
212
201
  {
213
- ref: T,
202
+ ref: L,
214
203
  className: "sandbox-container",
215
- style: ce
204
+ style: re
216
205
  }
217
206
  ),
218
- C && /* @__PURE__ */ R.jsx(
207
+ E && /* @__PURE__ */ R.jsx(
219
208
  "div",
220
209
  {
221
210
  style: {
@@ -227,7 +216,7 @@ const de = [
227
216
  justifyContent: "center",
228
217
  pointerEvents: "none"
229
218
  },
230
- children: /* @__PURE__ */ R.jsx(ie, { message: C })
219
+ children: /* @__PURE__ */ R.jsx(oe, { message: E })
231
220
  }
232
221
  )
233
222
  ]
@@ -235,6 +224,6 @@ const de = [
235
224
  );
236
225
  };
237
226
  export {
238
- Ae as default
227
+ ye as default
239
228
  };
240
229
  //# sourceMappingURL=SandboxApp.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SandboxApp.es.js","sources":["../../../src/components/ContentRender/SandboxApp.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport LoadingOverlayCard from \"../ui/loading-overlay-card\";\nimport type { MarkdownFlowLocale } from \"../../lib/locale\";\nimport { getContentRenderLocaleTexts } from \"./contentRenderI18n\";\nimport type { ScalingWindow } from \"./utils/iframe-scaling\";\nimport {\n isAnchorElement,\n mergeAnchorRelValue,\n resolveClosestAnchor,\n shouldForceAnchorHrefToNewTab,\n} from \"./utils/link-targets\";\n\nexport interface SandboxAppProps {\n html: string;\n locale?: MarkdownFlowLocale;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n resetToken?: number;\n mode?: \"content\" | \"blackboard\";\n hasRootVhHeight?: boolean;\n stretchRootHeight?: boolean;\n enableScaling?: boolean;\n disableLoadingOverlay?: boolean;\n}\n\nconst IMAGE_REUSE_ATTRIBUTES = [\n \"src\",\n \"srcset\",\n \"sizes\",\n \"alt\",\n \"class\",\n \"width\",\n \"height\",\n \"style\",\n \"loading\",\n \"decoding\",\n \"crossorigin\",\n \"referrerpolicy\",\n \"fetchpriority\",\n];\n\nconst getImageReuseKey = (image: HTMLImageElement) =>\n IMAGE_REUSE_ATTRIBUTES.map(\n (attribute) => `${attribute}:${image.getAttribute(attribute) || \"\"}`\n ).join(\"|\");\n\nconst collectReusableImages = (root: ParentNode) => {\n const imageMap = new Map<string, HTMLImageElement[]>();\n root.querySelectorAll(\"img\").forEach((node) => {\n const image = node as HTMLImageElement;\n const key = getImageReuseKey(image);\n const bucket = imageMap.get(key) || [];\n bucket.push(image);\n imageMap.set(key, bucket);\n });\n return imageMap;\n};\n\nconst syncImageAttributes = (\n sourceImage: HTMLImageElement,\n targetImage: HTMLImageElement\n) => {\n const sourceAttributes = Array.from(sourceImage.attributes);\n const sourceAttributeNames = new Set(\n sourceAttributes.map((attribute) => attribute.name)\n );\n\n Array.from(targetImage.attributes).forEach((attribute) => {\n if (!sourceAttributeNames.has(attribute.name)) {\n targetImage.removeAttribute(attribute.name);\n }\n });\n\n sourceAttributes.forEach((attribute) => {\n targetImage.setAttribute(attribute.name, attribute.value);\n });\n};\n\nconst reuseRenderedImages = (\n root: ParentNode,\n imageMap: Map<string, HTMLImageElement[]>\n) => {\n if (!imageMap.size) return;\n\n root.querySelectorAll(\"img\").forEach((node) => {\n const nextImage = node as HTMLImageElement;\n const key = getImageReuseKey(nextImage);\n const bucket = imageMap.get(key);\n const preservedImage = bucket?.shift();\n if (!preservedImage) return;\n\n syncImageAttributes(nextImage, preservedImage);\n nextImage.replaceWith(preservedImage);\n\n if (bucket && bucket.length === 0) {\n imageMap.delete(key);\n }\n });\n};\n\nconst SandboxApp: React.FC<SandboxAppProps> = ({\n html,\n locale,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n resetToken = 0,\n mode = \"content\",\n hasRootVhHeight = false,\n stretchRootHeight = false,\n enableScaling = false,\n disableLoadingOverlay = false,\n}) => {\n const localeTexts = getContentRenderLocaleTexts(locale);\n const containerRef = useRef<HTMLDivElement>(null);\n const [isGeneratingStyles, setIsGeneratingStyles] = useState(false);\n const [isGeneratingScripts, setIsGeneratingScripts] = useState(false);\n const [hasRenderedContent, setHasRenderedContent] = useState(false);\n const appendedStylesRef = useRef<HTMLStyleElement[]>([]);\n const appendedScriptsRef = useRef<HTMLScriptElement[]>([]);\n const styleStartRef = useRef(0);\n const scriptStartRef = useRef(0);\n const styleTimerRef = useRef<number | null>(null);\n const scriptTimerRef = useRef<number | null>(null);\n const hasStylesRef = useRef(false);\n const hasScriptsRef = useRef(false);\n const prevResetTokenRef = useRef(resetToken);\n const MIN_LOADING_MS = 200;\n\n const clearTimer = (timerRef: React.MutableRefObject<number | null>) => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const settleStateWithMinimumDelay = (\n setter: React.Dispatch<React.SetStateAction<boolean>>,\n timerRef: React.MutableRefObject<number | null>,\n startRef: React.MutableRefObject<number>,\n onDone?: () => void\n ) => {\n const elapsed = performance.now() - startRef.current;\n const delay = Math.max(0, MIN_LOADING_MS - elapsed);\n clearTimer(timerRef);\n timerRef.current = window.setTimeout(() => {\n setter(false);\n onDone?.();\n timerRef.current = null;\n }, delay);\n };\n\n useEffect(() => {\n const doc = containerRef.current?.ownerDocument;\n if (!doc) return;\n const styleId = \"sandbox-spinner-style\";\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = doc.createElement(\"style\");\n styleEl.id = styleId;\n doc.head?.appendChild(styleEl);\n }\n styleEl.textContent = `\n .sandbox-wrapper { align-items: center; }\n .sandbox-container { position: relative; width: 100%; }\n .sandbox-container svg,\n .sandbox-container img { display: block; margin-left: auto; margin-right: auto; }\n /* Hide scroll UI without removing scroll semantics. Content roots with\n inline style=\"height:100vh; overflow-y:auto\" are the signal that\n IframeSandbox.getInnerScrollableHeight relies on to grow the iframe\n when content exceeds the viewport. We must not change overflow-y,\n but sub-pixel rounding (1px below the +1 detection threshold) can\n still surface a phantom scrollbar on content that visually fits.\n Hide the scrollbar UI globally; when content truly overflows the\n iframe is resized and no scrollbar would render anyway. */\n .sandbox-container *::-webkit-scrollbar { display: none; }\n .sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }\n .justify-\\\\[safe_center\\\\]{\n justify-content: safe center;\n }\n .overflow-y-auto { overflow-y: visible !important; }\n `;\n }, []);\n\n useEffect(() => {\n if (resetToken !== prevResetTokenRef.current) {\n setHasRenderedContent(false);\n prevResetTokenRef.current = resetToken;\n }\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n\n const container = containerRef.current;\n if (!container) return;\n const doc = container.ownerDocument;\n const body = doc?.body;\n if (!body) return;\n const reusableImages = collectReusableImages(container);\n\n appendedStylesRef.current.forEach((node) => node.remove());\n appendedStylesRef.current = [];\n appendedScriptsRef.current.forEach((node) => node.remove());\n appendedScriptsRef.current = [];\n\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n const wrapper = doc.createElement(\"div\");\n wrapper.innerHTML = html;\n wrapper.querySelectorAll(\"a[href]\").forEach((node) => {\n if (!isAnchorElement(node)) {\n return;\n }\n\n if (!shouldForceAnchorHrefToNewTab(node.getAttribute(\"href\"))) {\n return;\n }\n\n node.setAttribute(\"target\", \"_blank\");\n node.setAttribute(\"rel\", mergeAnchorRelValue(node.getAttribute(\"rel\")));\n });\n\n const openScriptCount = (html.match(/<script[\\s>]/gi) || []).length;\n const closeScriptCount = (html.match(/<\\/script>/gi) || []).length;\n const shouldExecuteScripts =\n openScriptCount > 0 && openScriptCount === closeScriptCount;\n\n const resourceQueue: HTMLElement[] = [];\n\n Array.from(wrapper.querySelectorAll(\"style, script\")).forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n const cloned = doc.createElement(\"style\");\n cloned.textContent = node.textContent || \"\";\n Array.from(node.attributes).forEach((attr) => {\n cloned.setAttribute(attr.name, attr.value);\n });\n resourceQueue.push(cloned);\n } else {\n const replacement = doc.createElement(\"script\");\n Array.from(node.attributes).forEach((attr) => {\n replacement.setAttribute(attr.name, attr.value);\n });\n replacement.textContent = node.textContent || \"\";\n resourceQueue.push(replacement);\n }\n node.remove();\n });\n reuseRenderedImages(wrapper, reusableImages);\n\n const hasStyles = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"style\"\n );\n const hasScripts = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"script\"\n );\n if (hasStyles) {\n hasStylesRef.current = true;\n styleStartRef.current = performance.now();\n clearTimer(styleTimerRef);\n setIsGeneratingStyles(true);\n }\n if (hasScripts) {\n hasScriptsRef.current = true;\n scriptStartRef.current = performance.now();\n clearTimer(scriptTimerRef);\n setIsGeneratingScripts(true);\n }\n\n const contentNodes = Array.from(wrapper.childNodes);\n const hasInitialContent = contentNodes.length > 0;\n setHasRenderedContent(hasInitialContent);\n container.replaceChildren(...contentNodes);\n\n const handleLinkClick = (event: MouseEvent) => {\n const anchor = resolveClosestAnchor(event.target);\n if (!anchor) {\n return;\n }\n\n if (!shouldForceAnchorHrefToNewTab(anchor.getAttribute(\"href\"))) {\n return;\n }\n\n anchor.setAttribute(\"target\", \"_blank\");\n anchor.setAttribute(\n \"rel\",\n mergeAnchorRelValue(anchor.getAttribute(\"rel\"))\n );\n };\n container.addEventListener(\"click\", handleLinkClick, true);\n\n let scriptContentObserver: MutationObserver | null = null;\n const markRenderedContentFromContainer = () => {\n if (container.childNodes.length === 0) {\n return false;\n }\n\n setHasRenderedContent(true);\n scriptContentObserver?.disconnect();\n scriptContentObserver = null;\n return true;\n };\n if (!hasInitialContent && hasScripts && shouldExecuteScripts) {\n scriptContentObserver = new MutationObserver(() => {\n markRenderedContentFromContainer();\n });\n scriptContentObserver.observe(container, {\n childList: true,\n subtree: true,\n });\n }\n\n resourceQueue.forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n doc.head?.appendChild(node);\n appendedStylesRef.current.push(node as HTMLStyleElement);\n return;\n }\n\n if (shouldExecuteScripts) {\n const scriptNode = node as HTMLScriptElement;\n const scriptText = scriptNode.textContent || \"\";\n const shouldValidate = !scriptNode.src;\n\n if (shouldValidate) {\n try {\n // Validate script is syntactically complete before executing\n\n new Function(scriptText);\n } catch {\n scriptNode.remove();\n return;\n }\n }\n\n try {\n body.appendChild(scriptNode);\n appendedScriptsRef.current.push(scriptNode);\n } catch {\n scriptNode.remove();\n }\n } else {\n // Defer execution until all script tags are fully received\n node.remove();\n }\n });\n markRenderedContentFromContainer();\n if (enableScaling) {\n const win = container.ownerDocument?.defaultView as ScalingWindow | null;\n win?.__mdf_triggerFitContent?.();\n }\n\n requestAnimationFrame(() => {\n if (hasStyles) {\n settleStateWithMinimumDelay(\n setIsGeneratingStyles,\n styleTimerRef,\n styleStartRef,\n () => {\n hasStylesRef.current = false;\n }\n );\n }\n if (hasScripts) {\n settleStateWithMinimumDelay(\n setIsGeneratingScripts,\n scriptTimerRef,\n scriptStartRef,\n () => {\n hasScriptsRef.current = false;\n }\n );\n }\n });\n\n return () => {\n scriptContentObserver?.disconnect();\n container.removeEventListener(\"click\", handleLinkClick, true);\n };\n }, [html, resetToken, enableScaling]);\n\n useEffect(\n () => () => {\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n },\n []\n );\n\n useEffect(() => {\n if (!disableLoadingOverlay) {\n return;\n }\n\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n }, [disableLoadingOverlay]);\n\n const overlayMessage = (() => {\n if (disableLoadingOverlay) {\n return null;\n }\n\n if (isGeneratingScripts || hasScriptsRef.current)\n return (\n scriptLoadingText || loadingText || localeTexts.sandboxScriptLoadingText\n );\n if (isGeneratingStyles || hasStylesRef.current)\n return (\n styleLoadingText || loadingText || localeTexts.sandboxStyleLoadingText\n );\n if (!hasRenderedContent)\n return loadingText || localeTexts.sandboxLoadingText;\n return null;\n })();\n\n const isBlackboard = mode === \"blackboard\";\n const shouldStretchRootHeight = isBlackboard && stretchRootHeight;\n const sandboxWrapperStyle: React.CSSProperties = {\n position: \"relative\",\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n // Keep blackboard scroll behavior while centering content in non-blackboard mode\n justifyContent: shouldStretchRootHeight\n ? \"flex-start\"\n : isBlackboard\n ? \"space-around\"\n : \"flex-start\",\n };\n const sandboxContainerStyle: React.CSSProperties = {\n pointerEvents: overlayMessage ? \"none\" : undefined,\n margin: isBlackboard ? undefined : \"auto 0\",\n width: \"100%\",\n height: shouldStretchRootHeight ? \"100%\" : undefined,\n minHeight: shouldStretchRootHeight ? 0 : undefined,\n flex: shouldStretchRootHeight ? \"1 1 auto\" : undefined,\n };\n\n return (\n <div\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className=\"sandbox-wrapper\"\n style={sandboxWrapperStyle}\n aria-busy={!!overlayMessage}\n >\n <div\n ref={containerRef}\n className=\"sandbox-container\"\n style={sandboxContainerStyle}\n />\n {overlayMessage && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 20,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"none\",\n }}\n >\n <LoadingOverlayCard message={overlayMessage} />\n </div>\n )}\n </div>\n );\n};\n\nexport default SandboxApp;\n"],"names":["IMAGE_REUSE_ATTRIBUTES","getImageReuseKey","image","attribute","collectReusableImages","root","imageMap","node","key","bucket","syncImageAttributes","sourceImage","targetImage","sourceAttributes","sourceAttributeNames","reuseRenderedImages","nextImage","preservedImage","SandboxApp","html","locale","loadingText","styleLoadingText","scriptLoadingText","resetToken","mode","hasRootVhHeight","stretchRootHeight","enableScaling","disableLoadingOverlay","localeTexts","getContentRenderLocaleTexts","containerRef","useRef","isGeneratingStyles","setIsGeneratingStyles","useState","isGeneratingScripts","setIsGeneratingScripts","hasRenderedContent","setHasRenderedContent","appendedStylesRef","appendedScriptsRef","styleStartRef","scriptStartRef","styleTimerRef","scriptTimerRef","hasStylesRef","hasScriptsRef","prevResetTokenRef","MIN_LOADING_MS","clearTimer","timerRef","settleStateWithMinimumDelay","setter","startRef","onDone","elapsed","delay","useEffect","doc","styleId","styleEl","container","body","reusableImages","wrapper","isAnchorElement","shouldForceAnchorHrefToNewTab","mergeAnchorRelValue","openScriptCount","closeScriptCount","shouldExecuteScripts","resourceQueue","cloned","attr","replacement","hasStyles","hasScripts","contentNodes","hasInitialContent","handleLinkClick","event","anchor","resolveClosestAnchor","scriptContentObserver","markRenderedContentFromContainer","scriptNode","scriptText","overlayMessage","isBlackboard","shouldStretchRootHeight","sandboxWrapperStyle","sandboxContainerStyle","jsxs","jsx","LoadingOverlayCard"],"mappings":"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"}
1
+ {"version":3,"file":"SandboxApp.es.js","sources":["../../../src/components/ContentRender/SandboxApp.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport LoadingOverlayCard from \"../ui/loading-overlay-card\";\nimport type { MarkdownFlowLocale } from \"../../lib/locale\";\nimport { getContentRenderLocaleTexts } from \"./contentRenderI18n\";\nimport type { ScalingWindow } from \"./utils/iframe-scaling\";\n\nexport interface SandboxAppProps {\n html: string;\n locale?: MarkdownFlowLocale;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n resetToken?: number;\n mode?: \"content\" | \"blackboard\";\n hasRootVhHeight?: boolean;\n stretchRootHeight?: boolean;\n enableScaling?: boolean;\n disableLoadingOverlay?: boolean;\n}\n\nconst IMAGE_REUSE_ATTRIBUTES = [\n \"src\",\n \"srcset\",\n \"sizes\",\n \"alt\",\n \"class\",\n \"width\",\n \"height\",\n \"style\",\n \"loading\",\n \"decoding\",\n \"crossorigin\",\n \"referrerpolicy\",\n \"fetchpriority\",\n];\n\nconst getImageReuseKey = (image: HTMLImageElement) =>\n IMAGE_REUSE_ATTRIBUTES.map(\n (attribute) => `${attribute}:${image.getAttribute(attribute) || \"\"}`\n ).join(\"|\");\n\nconst collectReusableImages = (root: ParentNode) => {\n const imageMap = new Map<string, HTMLImageElement[]>();\n root.querySelectorAll(\"img\").forEach((node) => {\n const image = node as HTMLImageElement;\n const key = getImageReuseKey(image);\n const bucket = imageMap.get(key) || [];\n bucket.push(image);\n imageMap.set(key, bucket);\n });\n return imageMap;\n};\n\nconst syncImageAttributes = (\n sourceImage: HTMLImageElement,\n targetImage: HTMLImageElement\n) => {\n const sourceAttributes = Array.from(sourceImage.attributes);\n const sourceAttributeNames = new Set(\n sourceAttributes.map((attribute) => attribute.name)\n );\n\n Array.from(targetImage.attributes).forEach((attribute) => {\n if (!sourceAttributeNames.has(attribute.name)) {\n targetImage.removeAttribute(attribute.name);\n }\n });\n\n sourceAttributes.forEach((attribute) => {\n targetImage.setAttribute(attribute.name, attribute.value);\n });\n};\n\nconst reuseRenderedImages = (\n root: ParentNode,\n imageMap: Map<string, HTMLImageElement[]>\n) => {\n if (!imageMap.size) return;\n\n root.querySelectorAll(\"img\").forEach((node) => {\n const nextImage = node as HTMLImageElement;\n const key = getImageReuseKey(nextImage);\n const bucket = imageMap.get(key);\n const preservedImage = bucket?.shift();\n if (!preservedImage) return;\n\n syncImageAttributes(nextImage, preservedImage);\n nextImage.replaceWith(preservedImage);\n\n if (bucket && bucket.length === 0) {\n imageMap.delete(key);\n }\n });\n};\n\nconst SandboxApp: React.FC<SandboxAppProps> = ({\n html,\n locale,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n resetToken = 0,\n mode = \"content\",\n hasRootVhHeight = false,\n stretchRootHeight = false,\n enableScaling = false,\n disableLoadingOverlay = false,\n}) => {\n const localeTexts = getContentRenderLocaleTexts(locale);\n const containerRef = useRef<HTMLDivElement>(null);\n const [isGeneratingStyles, setIsGeneratingStyles] = useState(false);\n const [isGeneratingScripts, setIsGeneratingScripts] = useState(false);\n const [hasRenderedContent, setHasRenderedContent] = useState(false);\n const appendedStylesRef = useRef<HTMLStyleElement[]>([]);\n const appendedScriptsRef = useRef<HTMLScriptElement[]>([]);\n const styleStartRef = useRef(0);\n const scriptStartRef = useRef(0);\n const styleTimerRef = useRef<number | null>(null);\n const scriptTimerRef = useRef<number | null>(null);\n const hasStylesRef = useRef(false);\n const hasScriptsRef = useRef(false);\n const prevResetTokenRef = useRef(resetToken);\n const MIN_LOADING_MS = 200;\n\n const clearTimer = (timerRef: React.MutableRefObject<number | null>) => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n };\n\n const settleStateWithMinimumDelay = (\n setter: React.Dispatch<React.SetStateAction<boolean>>,\n timerRef: React.MutableRefObject<number | null>,\n startRef: React.MutableRefObject<number>,\n onDone?: () => void\n ) => {\n const elapsed = performance.now() - startRef.current;\n const delay = Math.max(0, MIN_LOADING_MS - elapsed);\n clearTimer(timerRef);\n timerRef.current = window.setTimeout(() => {\n setter(false);\n onDone?.();\n timerRef.current = null;\n }, delay);\n };\n\n useEffect(() => {\n const doc = containerRef.current?.ownerDocument;\n if (!doc) return;\n const styleId = \"sandbox-spinner-style\";\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n if (!styleEl) {\n styleEl = doc.createElement(\"style\");\n styleEl.id = styleId;\n doc.head?.appendChild(styleEl);\n }\n styleEl.textContent = `\n .sandbox-wrapper { align-items: center; }\n .sandbox-container { position: relative; width: 100%; }\n .sandbox-container svg,\n .sandbox-container img { display: block; margin-left: auto; margin-right: auto; }\n /* Hide scroll UI without removing scroll semantics. Content roots with\n inline style=\"height:100vh; overflow-y:auto\" are the signal that\n IframeSandbox.getInnerScrollableHeight relies on to grow the iframe\n when content exceeds the viewport. We must not change overflow-y,\n but sub-pixel rounding (1px below the +1 detection threshold) can\n still surface a phantom scrollbar on content that visually fits.\n Hide the scrollbar UI globally; when content truly overflows the\n iframe is resized and no scrollbar would render anyway. */\n .sandbox-container *::-webkit-scrollbar { display: none; }\n .sandbox-container * { scrollbar-width: none; -ms-overflow-style: none; }\n .justify-\\\\[safe_center\\\\]{\n justify-content: safe center;\n }\n .overflow-y-auto { overflow-y: visible !important; }\n `;\n }, []);\n\n useEffect(() => {\n if (resetToken !== prevResetTokenRef.current) {\n setHasRenderedContent(false);\n prevResetTokenRef.current = resetToken;\n }\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n\n const container = containerRef.current;\n if (!container) return;\n const doc = container.ownerDocument;\n const body = doc?.body;\n if (!body) return;\n const reusableImages = collectReusableImages(container);\n\n appendedStylesRef.current.forEach((node) => node.remove());\n appendedStylesRef.current = [];\n appendedScriptsRef.current.forEach((node) => node.remove());\n appendedScriptsRef.current = [];\n\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n const wrapper = doc.createElement(\"div\");\n wrapper.innerHTML = html;\n\n const openScriptCount = (html.match(/<script[\\s>]/gi) || []).length;\n const closeScriptCount = (html.match(/<\\/script>/gi) || []).length;\n const shouldExecuteScripts =\n openScriptCount > 0 && openScriptCount === closeScriptCount;\n\n const resourceQueue: HTMLElement[] = [];\n\n Array.from(wrapper.querySelectorAll(\"style, script\")).forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n const cloned = doc.createElement(\"style\");\n cloned.textContent = node.textContent || \"\";\n Array.from(node.attributes).forEach((attr) => {\n cloned.setAttribute(attr.name, attr.value);\n });\n resourceQueue.push(cloned);\n } else {\n const replacement = doc.createElement(\"script\");\n Array.from(node.attributes).forEach((attr) => {\n replacement.setAttribute(attr.name, attr.value);\n });\n replacement.textContent = node.textContent || \"\";\n resourceQueue.push(replacement);\n }\n node.remove();\n });\n reuseRenderedImages(wrapper, reusableImages);\n\n const hasStyles = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"style\"\n );\n const hasScripts = resourceQueue.some(\n (node) => node.tagName.toLowerCase() === \"script\"\n );\n if (hasStyles) {\n hasStylesRef.current = true;\n styleStartRef.current = performance.now();\n clearTimer(styleTimerRef);\n setIsGeneratingStyles(true);\n }\n if (hasScripts) {\n hasScriptsRef.current = true;\n scriptStartRef.current = performance.now();\n clearTimer(scriptTimerRef);\n setIsGeneratingScripts(true);\n }\n\n const contentNodes = Array.from(wrapper.childNodes);\n const hasInitialContent = contentNodes.length > 0;\n setHasRenderedContent(hasInitialContent);\n container.replaceChildren(...contentNodes);\n\n let scriptContentObserver: MutationObserver | null = null;\n const markRenderedContentFromContainer = () => {\n if (container.childNodes.length === 0) {\n return false;\n }\n\n setHasRenderedContent(true);\n scriptContentObserver?.disconnect();\n scriptContentObserver = null;\n return true;\n };\n if (!hasInitialContent && hasScripts && shouldExecuteScripts) {\n scriptContentObserver = new MutationObserver(() => {\n markRenderedContentFromContainer();\n });\n scriptContentObserver.observe(container, {\n childList: true,\n subtree: true,\n });\n }\n\n resourceQueue.forEach((node) => {\n if (node.tagName.toLowerCase() === \"style\") {\n doc.head?.appendChild(node);\n appendedStylesRef.current.push(node as HTMLStyleElement);\n return;\n }\n\n if (shouldExecuteScripts) {\n const scriptNode = node as HTMLScriptElement;\n const scriptText = scriptNode.textContent || \"\";\n const shouldValidate = !scriptNode.src;\n\n if (shouldValidate) {\n try {\n // Validate script is syntactically complete before executing\n\n new Function(scriptText);\n } catch {\n scriptNode.remove();\n return;\n }\n }\n\n try {\n body.appendChild(scriptNode);\n appendedScriptsRef.current.push(scriptNode);\n } catch {\n scriptNode.remove();\n }\n } else {\n // Defer execution until all script tags are fully received\n node.remove();\n }\n });\n markRenderedContentFromContainer();\n if (enableScaling) {\n const win = container.ownerDocument?.defaultView as ScalingWindow | null;\n win?.__mdf_triggerFitContent?.();\n }\n\n requestAnimationFrame(() => {\n if (hasStyles) {\n settleStateWithMinimumDelay(\n setIsGeneratingStyles,\n styleTimerRef,\n styleStartRef,\n () => {\n hasStylesRef.current = false;\n }\n );\n }\n if (hasScripts) {\n settleStateWithMinimumDelay(\n setIsGeneratingScripts,\n scriptTimerRef,\n scriptStartRef,\n () => {\n hasScriptsRef.current = false;\n }\n );\n }\n });\n\n return () => {\n scriptContentObserver?.disconnect();\n };\n }, [html, resetToken, enableScaling]);\n\n useEffect(\n () => () => {\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n },\n []\n );\n\n useEffect(() => {\n if (!disableLoadingOverlay) {\n return;\n }\n\n clearTimer(styleTimerRef);\n clearTimer(scriptTimerRef);\n hasStylesRef.current = false;\n hasScriptsRef.current = false;\n setIsGeneratingStyles(false);\n setIsGeneratingScripts(false);\n }, [disableLoadingOverlay]);\n\n const overlayMessage = (() => {\n if (disableLoadingOverlay) {\n return null;\n }\n\n if (isGeneratingScripts || hasScriptsRef.current)\n return (\n scriptLoadingText || loadingText || localeTexts.sandboxScriptLoadingText\n );\n if (isGeneratingStyles || hasStylesRef.current)\n return (\n styleLoadingText || loadingText || localeTexts.sandboxStyleLoadingText\n );\n if (!hasRenderedContent)\n return loadingText || localeTexts.sandboxLoadingText;\n return null;\n })();\n\n const isBlackboard = mode === \"blackboard\";\n const shouldStretchRootHeight = isBlackboard && stretchRootHeight;\n const sandboxWrapperStyle: React.CSSProperties = {\n position: \"relative\",\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n // Keep blackboard scroll behavior while centering content in non-blackboard mode\n justifyContent: shouldStretchRootHeight\n ? \"flex-start\"\n : isBlackboard\n ? \"space-around\"\n : \"flex-start\",\n };\n const sandboxContainerStyle: React.CSSProperties = {\n pointerEvents: overlayMessage ? \"none\" : undefined,\n margin: isBlackboard ? undefined : \"auto 0\",\n width: \"100%\",\n height: shouldStretchRootHeight ? \"100%\" : undefined,\n minHeight: shouldStretchRootHeight ? 0 : undefined,\n flex: shouldStretchRootHeight ? \"1 1 auto\" : undefined,\n };\n\n return (\n <div\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className=\"sandbox-wrapper\"\n style={sandboxWrapperStyle}\n aria-busy={!!overlayMessage}\n >\n <div\n ref={containerRef}\n className=\"sandbox-container\"\n style={sandboxContainerStyle}\n />\n {overlayMessage && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 20,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n pointerEvents: \"none\",\n }}\n >\n <LoadingOverlayCard message={overlayMessage} />\n </div>\n )}\n </div>\n );\n};\n\nexport default SandboxApp;\n"],"names":["IMAGE_REUSE_ATTRIBUTES","getImageReuseKey","image","attribute","collectReusableImages","root","imageMap","node","key","bucket","syncImageAttributes","sourceImage","targetImage","sourceAttributes","sourceAttributeNames","reuseRenderedImages","nextImage","preservedImage","SandboxApp","html","locale","loadingText","styleLoadingText","scriptLoadingText","resetToken","mode","hasRootVhHeight","stretchRootHeight","enableScaling","disableLoadingOverlay","localeTexts","getContentRenderLocaleTexts","containerRef","useRef","isGeneratingStyles","setIsGeneratingStyles","useState","isGeneratingScripts","setIsGeneratingScripts","hasRenderedContent","setHasRenderedContent","appendedStylesRef","appendedScriptsRef","styleStartRef","scriptStartRef","styleTimerRef","scriptTimerRef","hasStylesRef","hasScriptsRef","prevResetTokenRef","MIN_LOADING_MS","clearTimer","timerRef","settleStateWithMinimumDelay","setter","startRef","onDone","elapsed","delay","useEffect","doc","styleId","styleEl","container","body","reusableImages","wrapper","openScriptCount","closeScriptCount","shouldExecuteScripts","resourceQueue","cloned","attr","replacement","hasStyles","hasScripts","contentNodes","hasInitialContent","scriptContentObserver","markRenderedContentFromContainer","scriptNode","scriptText","overlayMessage","isBlackboard","shouldStretchRootHeight","sandboxWrapperStyle","sandboxContainerStyle","jsxs","jsx","LoadingOverlayCard"],"mappings":"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"}