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.
- package/dist/components/ContentRender/SandboxApp.cjs.js +2 -2
- package/dist/components/ContentRender/SandboxApp.cjs.js.map +1 -1
- package/dist/components/ContentRender/SandboxApp.es.js +95 -106
- package/dist/components/ContentRender/SandboxApp.es.js.map +1 -1
- package/dist/components/Slide/Slide.cjs.js +1 -1
- package/dist/components/Slide/Slide.cjs.js.map +1 -1
- package/dist/components/Slide/Slide.es.js +732 -776
- package/dist/components/Slide/Slide.es.js.map +1 -1
- package/dist/components/Slide/Slide.stories.d.ts +4 -4
- package/dist/components/Slide/constants.d.ts +0 -1
- package/dist/components/Slide/utils/interactionPlayback.cjs.js +1 -1
- package/dist/components/Slide/utils/interactionPlayback.cjs.js.map +1 -1
- package/dist/components/Slide/utils/interactionPlayback.d.ts +2 -1
- package/dist/components/Slide/utils/interactionPlayback.es.js +3 -2
- package/dist/components/Slide/utils/interactionPlayback.es.js.map +1 -1
- package/dist/components/Slide/utils/streamingNavigation.cjs.js +1 -1
- package/dist/components/Slide/utils/streamingNavigation.cjs.js.map +1 -1
- package/dist/components/Slide/utils/streamingNavigation.es.js +15 -9
- package/dist/components/Slide/utils/streamingNavigation.es.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/ContentRender/utils/link-targets.cjs.js +0 -2
- package/dist/components/ContentRender/utils/link-targets.cjs.js.map +0 -1
- package/dist/components/ContentRender/utils/link-targets.d.ts +0 -6
- package/dist/components/ContentRender/utils/link-targets.es.js +0 -26
- package/dist/components/ContentRender/utils/link-targets.es.js.map +0 -1
- package/dist/components/ContentRender/utils/link-targets.test.d.ts +0 -1
- package/dist/components/Slide/constants.cjs.js +0 -2
- package/dist/components/Slide/constants.cjs.js.map +0 -1
- package/dist/components/Slide/constants.es.js +0 -5
- package/dist/components/Slide/constants.es.js.map +0 -1
- package/dist/components/Slide/utils/imageOnlyStepVisualReady.cjs.js +0 -2
- package/dist/components/Slide/utils/imageOnlyStepVisualReady.cjs.js.map +0 -1
- package/dist/components/Slide/utils/imageOnlyStepVisualReady.d.ts +0 -13
- package/dist/components/Slide/utils/imageOnlyStepVisualReady.es.js +0 -12
- package/dist/components/Slide/utils/imageOnlyStepVisualReady.es.js.map +0 -1
- package/dist/components/Slide/utils/silentStepAutoAdvance.cjs.js +0 -2
- package/dist/components/Slide/utils/silentStepAutoAdvance.cjs.js.map +0 -1
- package/dist/components/Slide/utils/silentStepAutoAdvance.d.ts +0 -14
- package/dist/components/Slide/utils/silentStepAutoAdvance.es.js +0 -37
- package/dist/components/Slide/utils/silentStepAutoAdvance.es.js.map +0 -1
- 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
|
|
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!==
|
|
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
|
|
4
|
-
import { getContentRenderLocaleTexts as
|
|
5
|
-
|
|
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
|
-
],
|
|
19
|
+
], J = (o) => ce.map(
|
|
21
20
|
(n) => `${n}:${o.getAttribute(n) || ""}`
|
|
22
|
-
).join("|"),
|
|
21
|
+
).join("|"), ie = (o) => {
|
|
23
22
|
const n = /* @__PURE__ */ new Map();
|
|
24
23
|
return o.querySelectorAll("img").forEach((i) => {
|
|
25
|
-
const l = i,
|
|
26
|
-
|
|
24
|
+
const l = i, r = J(l), c = n.get(r) || [];
|
|
25
|
+
c.push(l), n.set(r, c);
|
|
27
26
|
}), n;
|
|
28
|
-
},
|
|
27
|
+
}, le = (o, n) => {
|
|
29
28
|
const i = Array.from(o.attributes), l = new Set(
|
|
30
|
-
i.map((
|
|
29
|
+
i.map((r) => r.name)
|
|
31
30
|
);
|
|
32
|
-
Array.from(n.attributes).forEach((
|
|
33
|
-
l.has(
|
|
34
|
-
}), i.forEach((
|
|
35
|
-
n.setAttribute(
|
|
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
|
-
},
|
|
36
|
+
}, ue = (o, n) => {
|
|
38
37
|
n.size && o.querySelectorAll("img").forEach((i) => {
|
|
39
|
-
const l = i,
|
|
40
|
-
p && (
|
|
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
|
-
},
|
|
41
|
+
}, ye = ({
|
|
43
42
|
html: o,
|
|
44
43
|
locale: n,
|
|
45
44
|
loadingText: i,
|
|
46
45
|
styleLoadingText: l,
|
|
47
|
-
scriptLoadingText:
|
|
48
|
-
resetToken:
|
|
46
|
+
scriptLoadingText: r,
|
|
47
|
+
resetToken: c = 0,
|
|
49
48
|
mode: p = "content",
|
|
50
|
-
hasRootVhHeight:
|
|
51
|
-
stretchRootHeight:
|
|
52
|
-
enableScaling:
|
|
53
|
-
disableLoadingOverlay:
|
|
49
|
+
hasRootVhHeight: P = !1,
|
|
50
|
+
stretchRootHeight: X = !1,
|
|
51
|
+
enableScaling: z = !1,
|
|
52
|
+
disableLoadingOverlay: j = !1
|
|
54
53
|
}) => {
|
|
55
|
-
const
|
|
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
|
-
},
|
|
58
|
-
const
|
|
59
|
-
d(
|
|
60
|
-
t(!1), D?.(),
|
|
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 =
|
|
63
|
+
const t = L.current?.ownerDocument;
|
|
65
64
|
if (!t) return;
|
|
66
|
-
const
|
|
67
|
-
let u = t.getElementById(
|
|
68
|
-
u || (u = t.createElement("style"), u.id =
|
|
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
|
-
|
|
90
|
-
const t =
|
|
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
|
|
91
|
+
const a = t.ownerDocument, u = a?.body;
|
|
93
92
|
if (!u) return;
|
|
94
|
-
const D =
|
|
95
|
-
_.current.forEach((e) => e.remove()), _.current = [],
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
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
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}),
|
|
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
|
|
109
|
-
Array.from(e.attributes).forEach((
|
|
110
|
-
|
|
111
|
-
}),
|
|
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
|
-
}),
|
|
115
|
-
const O =
|
|
111
|
+
}), ue(m, D);
|
|
112
|
+
const O = w.some(
|
|
116
113
|
(e) => e.tagName.toLowerCase() === "style"
|
|
117
|
-
), G =
|
|
114
|
+
), G = w.some(
|
|
118
115
|
(e) => e.tagName.toLowerCase() === "script"
|
|
119
116
|
);
|
|
120
|
-
O && (b.current = !0,
|
|
121
|
-
const $ = Array.from(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
})),
|
|
127
|
+
})), w.forEach((e) => {
|
|
139
128
|
if (e.tagName.toLowerCase() === "style") {
|
|
140
|
-
|
|
129
|
+
a.head?.appendChild(e), _.current.push(e);
|
|
141
130
|
return;
|
|
142
131
|
}
|
|
143
|
-
if (
|
|
144
|
-
const
|
|
145
|
-
if (!
|
|
132
|
+
if (V) {
|
|
133
|
+
const s = e, h = s.textContent || "";
|
|
134
|
+
if (!s.src)
|
|
146
135
|
try {
|
|
147
|
-
new Function(
|
|
136
|
+
new Function(h);
|
|
148
137
|
} catch {
|
|
149
|
-
|
|
138
|
+
s.remove();
|
|
150
139
|
return;
|
|
151
140
|
}
|
|
152
141
|
try {
|
|
153
|
-
u.appendChild(
|
|
142
|
+
u.appendChild(s), k.current.push(s);
|
|
154
143
|
} catch {
|
|
155
|
-
|
|
144
|
+
s.remove();
|
|
156
145
|
}
|
|
157
146
|
} else
|
|
158
147
|
e.remove();
|
|
159
|
-
}),
|
|
160
|
-
O &&
|
|
161
|
-
|
|
148
|
+
}), Q(), z && t.ownerDocument?.defaultView?.__mdf_triggerFitContent?.(), requestAnimationFrame(() => {
|
|
149
|
+
O && B(
|
|
150
|
+
S,
|
|
162
151
|
y,
|
|
163
|
-
|
|
152
|
+
F,
|
|
164
153
|
() => {
|
|
165
154
|
b.current = !1;
|
|
166
155
|
}
|
|
167
|
-
), G &&
|
|
168
|
-
|
|
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
|
-
|
|
165
|
+
v?.disconnect();
|
|
177
166
|
};
|
|
178
|
-
}, [o,
|
|
167
|
+
}, [o, c, z]), N(
|
|
179
168
|
() => () => {
|
|
180
169
|
d(y), d(g);
|
|
181
170
|
},
|
|
182
171
|
[]
|
|
183
172
|
), N(() => {
|
|
184
|
-
|
|
185
|
-
}, [
|
|
186
|
-
const
|
|
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:
|
|
194
|
-
},
|
|
195
|
-
pointerEvents:
|
|
196
|
-
margin:
|
|
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:
|
|
199
|
-
minHeight:
|
|
200
|
-
flex:
|
|
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":
|
|
194
|
+
"data-root-vh": P ? "true" : "false",
|
|
206
195
|
className: "sandbox-wrapper",
|
|
207
|
-
style:
|
|
208
|
-
"aria-busy": !!
|
|
196
|
+
style: ne,
|
|
197
|
+
"aria-busy": !!E,
|
|
209
198
|
children: [
|
|
210
199
|
/* @__PURE__ */ R.jsx(
|
|
211
200
|
"div",
|
|
212
201
|
{
|
|
213
|
-
ref:
|
|
202
|
+
ref: L,
|
|
214
203
|
className: "sandbox-container",
|
|
215
|
-
style:
|
|
204
|
+
style: re
|
|
216
205
|
}
|
|
217
206
|
),
|
|
218
|
-
|
|
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(
|
|
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
|
-
|
|
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":";;;;AAoBA,MAAMA,KAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAEMC,IAAmB,CAACC,MACxBF,GAAuB;AAAA,EACrB,CAACG,MAAc,GAAGA,CAAS,IAAID,EAAM,aAAaC,CAAS,KAAK,EAAE;AACpE,EAAE,KAAK,GAAG,GAENC,KAAwB,CAACC,MAAqB;AAClD,QAAMC,wBAAe,IAAA;AACrB,SAAAD,EAAK,iBAAiB,KAAK,EAAE,QAAQ,CAACE,MAAS;AAC7C,UAAML,IAAQK,GACRC,IAAMP,EAAiBC,CAAK,GAC5BO,IAASH,EAAS,IAAIE,CAAG,KAAK,CAAA;AACpC,IAAAC,EAAO,KAAKP,CAAK,GACjBI,EAAS,IAAIE,GAAKC,CAAM;AAAA,EAC1B,CAAC,GACMH;AACT,GAEMI,KAAsB,CAC1BC,GACAC,MACG;AACH,QAAMC,IAAmB,MAAM,KAAKF,EAAY,UAAU,GACpDG,IAAuB,IAAI;AAAA,IAC/BD,EAAiB,IAAI,CAACV,MAAcA,EAAU,IAAI;AAAA,EAAA;AAGpD,QAAM,KAAKS,EAAY,UAAU,EAAE,QAAQ,CAACT,MAAc;AACxD,IAAKW,EAAqB,IAAIX,EAAU,IAAI,KAC1CS,EAAY,gBAAgBT,EAAU,IAAI;AAAA,EAE9C,CAAC,GAEDU,EAAiB,QAAQ,CAACV,MAAc;AACtC,IAAAS,EAAY,aAAaT,EAAU,MAAMA,EAAU,KAAK;AAAA,EAC1D,CAAC;AACH,GAEMY,KAAsB,CAC1BV,GACAC,MACG;AACH,EAAKA,EAAS,QAEdD,EAAK,iBAAiB,KAAK,EAAE,QAAQ,CAACE,MAAS;AAC7C,UAAMS,IAAYT,GACZC,IAAMP,EAAiBe,CAAS,GAChCP,IAASH,EAAS,IAAIE,CAAG,GACzBS,IAAiBR,GAAQ,MAAA;AAC/B,IAAKQ,MAELP,GAAoBM,GAAWC,CAAc,GAC7CD,EAAU,YAAYC,CAAc,GAEhCR,KAAUA,EAAO,WAAW,KAC9BH,EAAS,OAAOE,CAAG;AAAA,EAEvB,CAAC;AACH,GAEMU,KAAwC,CAAC;AAAA,EAC7C,MAAAC;AAAA,EACA,QAAAC;AAAA,EACA,aAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,YAAAC,IAAa;AAAA,EACb,MAAAC,IAAO;AAAA,EACP,iBAAAC,IAAkB;AAAA,EAClB,mBAAAC,IAAoB;AAAA,EACpB,eAAAC,IAAgB;AAAA,EAChB,uBAAAC,IAAwB;AAC1B,MAAM;AACJ,QAAMC,IAAcC,GAA4BX,CAAM,GAChDY,IAAeC,EAAuB,IAAI,GAC1C,CAACC,GAAoBC,CAAqB,IAAIC,EAAS,EAAK,GAC5D,CAACC,GAAqBC,CAAsB,IAAIF,EAAS,EAAK,GAC9D,CAACG,IAAoBC,CAAqB,IAAIJ,EAAS,EAAK,GAC5DK,IAAoBR,EAA2B,EAAE,GACjDS,IAAqBT,EAA4B,EAAE,GACnDU,IAAgBV,EAAO,CAAC,GACxBW,IAAiBX,EAAO,CAAC,GACzBY,IAAgBZ,EAAsB,IAAI,GAC1Ca,IAAiBb,EAAsB,IAAI,GAC3Cc,IAAed,EAAO,EAAK,GAC3Be,IAAgBf,EAAO,EAAK,GAC5BgB,IAAoBhB,EAAOT,CAAU,GACrC0B,KAAiB,KAEjBC,IAAa,CAACC,MAAoD;AACtE,IAAIA,EAAS,YACX,aAAaA,EAAS,OAAO,GAC7BA,EAAS,UAAU;AAAA,EAEvB,GAEMC,IAA8B,CAClCC,GACAF,GACAG,GACAC,MACG;AACH,UAAMC,IAAU,YAAY,IAAA,IAAQF,EAAS,SACvCG,IAAQ,KAAK,IAAI,GAAGR,KAAiBO,CAAO;AAClD,IAAAN,EAAWC,CAAQ,GACnBA,EAAS,UAAU,OAAO,WAAW,MAAM;AACzC,MAAAE,EAAO,EAAK,GACZE,IAAA,GACAJ,EAAS,UAAU;AAAA,IACrB,GAAGM,CAAK;AAAA,EACV;AAEA,EAAAC,EAAU,MAAM;AACd,UAAMC,IAAM5B,EAAa,SAAS;AAClC,QAAI,CAAC4B,EAAK;AACV,UAAMC,IAAU;AAChB,QAAIC,IAAUF,EAAI,eAAeC,CAAO;AACxC,IAAKC,MACHA,IAAUF,EAAI,cAAc,OAAO,GACnCE,EAAQ,KAAKD,GACbD,EAAI,MAAM,YAAYE,CAAO,IAE/BA,EAAQ,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBxB,GAAG,CAAA,CAAE,GAELH,EAAU,MAAM;AACd,IAAInC,MAAeyB,EAAkB,YACnCT,EAAsB,EAAK,GAC3BS,EAAkB,UAAUzB,IAE9B2B,EAAWN,CAAa,GACxBM,EAAWL,CAAc,GACzBC,EAAa,UAAU,IACvBC,EAAc,UAAU;AAExB,UAAMe,IAAY/B,EAAa;AAC/B,QAAI,CAAC+B,EAAW;AAChB,UAAMH,IAAMG,EAAU,eAChBC,IAAOJ,GAAK;AAClB,QAAI,CAACI,EAAM;AACX,UAAMC,IAAiB7D,GAAsB2D,CAAS;AAEtD,IAAAtB,EAAkB,QAAQ,QAAQ,CAAClC,MAASA,EAAK,QAAQ,GACzDkC,EAAkB,UAAU,CAAA,GAC5BC,EAAmB,QAAQ,QAAQ,CAACnC,MAASA,EAAK,QAAQ,GAC1DmC,EAAmB,UAAU,CAAA,GAE7BP,EAAsB,EAAK,GAC3BG,EAAuB,EAAK;AAC5B,UAAM4B,IAAUN,EAAI,cAAc,KAAK;AACvC,IAAAM,EAAQ,YAAY/C;AAEpB,UAAMgD,KAAmBhD,EAAK,MAAM,gBAAgB,KAAK,CAAA,GAAI,QACvDiD,MAAoBjD,EAAK,MAAM,cAAc,KAAK,CAAA,GAAI,QACtDkD,IACJF,IAAkB,KAAKA,MAAoBC,IAEvCE,IAA+B,CAAA;AAErC,UAAM,KAAKJ,EAAQ,iBAAiB,eAAe,CAAC,EAAE,QAAQ,CAAC3D,MAAS;AACtE,UAAIA,EAAK,QAAQ,YAAA,MAAkB,SAAS;AAC1C,cAAMgE,IAASX,EAAI,cAAc,OAAO;AACxC,QAAAW,EAAO,cAAchE,EAAK,eAAe,IACzC,MAAM,KAAKA,EAAK,UAAU,EAAE,QAAQ,CAACiE,MAAS;AAC5C,UAAAD,EAAO,aAAaC,EAAK,MAAMA,EAAK,KAAK;AAAA,QAC3C,CAAC,GACDF,EAAc,KAAKC,CAAM;AAAA,MAC3B,OAAO;AACL,cAAME,IAAcb,EAAI,cAAc,QAAQ;AAC9C,cAAM,KAAKrD,EAAK,UAAU,EAAE,QAAQ,CAACiE,MAAS;AAC5C,UAAAC,EAAY,aAAaD,EAAK,MAAMA,EAAK,KAAK;AAAA,QAChD,CAAC,GACDC,EAAY,cAAclE,EAAK,eAAe,IAC9C+D,EAAc,KAAKG,CAAW;AAAA,MAChC;AACA,MAAAlE,EAAK,OAAA;AAAA,IACP,CAAC,GACDQ,GAAoBmD,GAASD,CAAc;AAE3C,UAAMS,IAAYJ,EAAc;AAAA,MAC9B,CAAC/D,MAASA,EAAK,QAAQ,kBAAkB;AAAA,IAAA,GAErCoE,IAAaL,EAAc;AAAA,MAC/B,CAAC/D,MAASA,EAAK,QAAQ,kBAAkB;AAAA,IAAA;AAE3C,IAAImE,MACF3B,EAAa,UAAU,IACvBJ,EAAc,UAAU,YAAY,IAAA,GACpCQ,EAAWN,CAAa,GACxBV,EAAsB,EAAI,IAExBwC,MACF3B,EAAc,UAAU,IACxBJ,EAAe,UAAU,YAAY,IAAA,GACrCO,EAAWL,CAAc,GACzBR,EAAuB,EAAI;AAG7B,UAAMsC,IAAe,MAAM,KAAKV,EAAQ,UAAU,GAC5CW,IAAoBD,EAAa,SAAS;AAChD,IAAApC,EAAsBqC,CAAiB,GACvCd,EAAU,gBAAgB,GAAGa,CAAY;AAEzC,QAAIE,IAAiD;AACrD,UAAMC,IAAmC,MACnChB,EAAU,WAAW,WAAW,IAC3B,MAGTvB,EAAsB,EAAI,GAC1BsC,GAAuB,WAAA,GACvBA,IAAwB,MACjB;AAET,WAAI,CAACD,KAAqBF,KAAcN,MACtCS,IAAwB,IAAI,iBAAiB,MAAM;AACjD,MAAAC,EAAA;AAAA,IACF,CAAC,GACDD,EAAsB,QAAQf,GAAW;AAAA,MACvC,WAAW;AAAA,MACX,SAAS;AAAA,IAAA,CACV,IAGHO,EAAc,QAAQ,CAAC/D,MAAS;AAC9B,UAAIA,EAAK,QAAQ,YAAA,MAAkB,SAAS;AAC1C,QAAAqD,EAAI,MAAM,YAAYrD,CAAI,GAC1BkC,EAAkB,QAAQ,KAAKlC,CAAwB;AACvD;AAAA,MACF;AAEA,UAAI8D,GAAsB;AACxB,cAAMW,IAAazE,GACb0E,IAAaD,EAAW,eAAe;AAG7C,YAFuB,CAACA,EAAW;AAGjC,cAAI;AAGF,gBAAI,SAASC,CAAU;AAAA,UACzB,QAAQ;AACN,YAAAD,EAAW,OAAA;AACX;AAAA,UACF;AAGF,YAAI;AACF,UAAAhB,EAAK,YAAYgB,CAAU,GAC3BtC,EAAmB,QAAQ,KAAKsC,CAAU;AAAA,QAC5C,QAAQ;AACN,UAAAA,EAAW,OAAA;AAAA,QACb;AAAA,MACF;AAEE,QAAAzE,EAAK,OAAA;AAAA,IAET,CAAC,GACDwE,EAAA,GACInD,KACUmC,EAAU,eAAe,aAChC,0BAAA,GAGP,sBAAsB,MAAM;AAC1B,MAAIW,KACFrB;AAAA,QACElB;AAAA,QACAU;AAAA,QACAF;AAAA,QACA,MAAM;AACJ,UAAAI,EAAa,UAAU;AAAA,QACzB;AAAA,MAAA,GAGA4B,KACFtB;AAAA,QACEf;AAAA,QACAQ;AAAA,QACAF;AAAA,QACA,MAAM;AACJ,UAAAI,EAAc,UAAU;AAAA,QAC1B;AAAA,MAAA;AAAA,IAGN,CAAC,GAEM,MAAM;AACX,MAAA8B,GAAuB,WAAA;AAAA,IACzB;AAAA,EACF,GAAG,CAAC3D,GAAMK,GAAYI,CAAa,CAAC,GAEpC+B;AAAA,IACE,MAAM,MAAM;AACV,MAAAR,EAAWN,CAAa,GACxBM,EAAWL,CAAc;AAAA,IAC3B;AAAA,IACA,CAAA;AAAA,EAAC,GAGHa,EAAU,MAAM;AACd,IAAK9B,MAILsB,EAAWN,CAAa,GACxBM,EAAWL,CAAc,GACzBC,EAAa,UAAU,IACvBC,EAAc,UAAU,IACxBb,EAAsB,EAAK,GAC3BG,EAAuB,EAAK;AAAA,EAC9B,GAAG,CAACT,CAAqB,CAAC;AAE1B,QAAMqD,IACArD,IACK,OAGLQ,KAAuBW,EAAc,UAErCzB,KAAqBF,KAAeS,EAAY,2BAEhDI,KAAsBa,EAAa,UAEnCzB,KAAoBD,KAAeS,EAAY,0BAE9CS,KAEE,OADElB,KAAeS,EAAY,oBAIhCqD,IAAe1D,MAAS,cACxB2D,IAA0BD,KAAgBxD,GAC1C0D,KAA2C;AAAA,IAC/C,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,eAAe;AAAA;AAAA,IAEf,gBAAgBD,IACZ,eACAD,IACE,iBACA;AAAA,EAAA,GAEFG,KAA6C;AAAA,IACjD,eAAeJ,IAAiB,SAAS;AAAA,IACzC,QAAQC,IAAe,SAAY;AAAA,IACnC,OAAO;AAAA,IACP,QAAQC,IAA0B,SAAS;AAAA,IAC3C,WAAWA,IAA0B,IAAI;AAAA,IACzC,MAAMA,IAA0B,aAAa;AAAA,EAAA;AAG/C,SACEG,gBAAAA,EAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,gBAAc7D,IAAkB,SAAS;AAAA,MACzC,WAAU;AAAA,MACV,OAAO2D;AAAA,MACP,aAAW,CAAC,CAACH;AAAA,MAEb,UAAA;AAAA,QAAAM,gBAAAA,EAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAKxD;AAAA,YACL,WAAU;AAAA,YACV,OAAOsD;AAAA,UAAA;AAAA,QAAA;AAAA,QAERJ,KACCM,gBAAAA,EAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,cACL,UAAU;AAAA,cACV,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,gBAAgB;AAAA,cAChB,eAAe;AAAA,YAAA;AAAA,YAGjB,UAAAA,gBAAAA,EAAAA,IAACC,IAAA,EAAmB,SAASP,EAAA,CAAgB;AAAA,UAAA;AAAA,QAAA;AAAA,MAC/C;AAAA,IAAA;AAAA,EAAA;AAIR;"}
|