markdown-flow-ui 0.1.89 → 0.1.90-beta.0
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/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/c4Diagram-YG6GDRKO.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/c4Diagram-YG6GDRKO.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/chunk-S3R3BYOJ.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/chunk-S3R3BYOJ.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/chunk-TZMSLE5B.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/chunk-TZMSLE5B.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/ganttDiagram-LVOFAZNH.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/ganttDiagram-LVOFAZNH.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/sequenceDiagram-WL72ISMW.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/mermaid@11.12.1/node_modules/mermaid/dist/chunks/mermaid.core/sequenceDiagram-WL72ISMW.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/rc-input@1.8.0_react-dom@19.0.1_react@19.0.1__react@19.0.1/node_modules/rc-input/es/BaseInput.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/rc-input@1.8.0_react-dom@19.0.1_react@19.0.1__react@19.0.1/node_modules/rc-input/es/BaseInput.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/rc-textarea@1.10.2_react-dom@19.0.1_react@19.0.1__react@19.0.1/node_modules/rc-textarea/es/ResizableTextArea.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/rc-textarea@1.10.2_react-dom@19.0.1_react@19.0.1__react@19.0.1/node_modules/rc-textarea/es/ResizableTextArea.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/rc-textarea@1.10.2_react-dom@19.0.1_react@19.0.1__react@19.0.1/node_modules/rc-textarea/es/TextArea.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/rc-textarea@1.10.2_react-dom@19.0.1_react@19.0.1__react@19.0.1/node_modules/rc-textarea/es/TextArea.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/rc-textarea@1.10.2_react-dom@19.0.1_react@19.0.1__react@19.0.1/node_modules/rc-textarea/es/index.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/rc-textarea@1.10.2_react-dom@19.0.1_react@19.0.1__react@19.0.1/node_modules/rc-textarea/es/index.es.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/remark-flow@0.1.6/node_modules/remark-flow/dist/index.cjs.js +1 -1
- package/dist/Documents/ai-shifu/markdown-flow-ui/node_modules/.pnpm/remark-flow@0.1.6/node_modules/remark-flow/dist/index.es.js +1 -1
- package/dist/_virtual/index.cjs2.js +1 -1
- package/dist/_virtual/index.cjs3.js +1 -1
- package/dist/_virtual/index.cjs7.js +1 -1
- package/dist/_virtual/index.cjs8.js +1 -1
- package/dist/_virtual/index.es2.js +5 -2
- package/dist/_virtual/index.es2.js.map +1 -1
- package/dist/_virtual/index.es3.js +2 -5
- package/dist/_virtual/index.es3.js.map +1 -1
- package/dist/_virtual/index.es7.js +2 -3
- package/dist/_virtual/index.es7.js.map +1 -1
- package/dist/_virtual/index.es8.js +3 -2
- package/dist/_virtual/index.es8.js.map +1 -1
- package/dist/components/ContentRender/ContentRender.cjs.js +2 -2
- package/dist/components/ContentRender/ContentRender.cjs.js.map +1 -1
- package/dist/components/ContentRender/ContentRender.es.js +149 -140
- package/dist/components/ContentRender/ContentRender.es.js.map +1 -1
- package/dist/components/ContentRender/IframeSandbox.cjs.js +1 -1
- package/dist/components/ContentRender/IframeSandbox.cjs.js.map +1 -1
- package/dist/components/ContentRender/IframeSandbox.es.js +1 -1
- package/dist/components/ContentRender/IframeSandbox.es.js.map +1 -1
- package/dist/components/ContentRender/SplitContent.stories.d.ts +16 -0
- package/dist/components/ContentRender/utils/split-content.cjs.js +5 -3
- package/dist/components/ContentRender/utils/split-content.cjs.js.map +1 -1
- package/dist/components/ContentRender/utils/split-content.es.js +93 -62
- package/dist/components/ContentRender/utils/split-content.es.js.map +1 -1
- package/dist/components/ContentRender/utils/strip-svg-text-line-breaks.cjs.js +2 -0
- package/dist/components/ContentRender/utils/strip-svg-text-line-breaks.cjs.js.map +1 -0
- package/dist/components/ContentRender/utils/strip-svg-text-line-breaks.d.ts +1 -0
- package/dist/components/ContentRender/utils/strip-svg-text-line-breaks.es.js +10 -0
- package/dist/components/ContentRender/utils/strip-svg-text-line-breaks.es.js.map +1 -0
- package/dist/components/ui/inputGroup/textarea.cjs.js +1 -1
- package/dist/components/ui/inputGroup/textarea.es.js +1 -1
- package/dist/markdown-flow-ui-lib.css +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeSandbox.cjs.js","sources":["../../../src/components/ContentRender/IframeSandbox.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport SandboxApp from \"./SandboxApp\";\nimport { splitContentSegments } from \"./utils/split-content\";\nimport ContentRender from \"./ContentRender\";\nexport interface IframeSandboxProps {\n content: string;\n className?: string;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n hideFullScreen?: boolean;\n mode?: \"content\" | \"blackboard\";\n type: \"sandbox\" | \"markdown\";\n}\n\nconst IframeSandbox: React.FC<IframeSandboxProps> = ({\n content,\n type,\n className,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const rootRef = useRef<Root | null>(null);\n const docRef = useRef<Document | null>(null);\n const updateHeightRef = useRef<() => void>(() => {});\n const [height, setHeight] = useState(480);\n const [resetToken, setResetToken] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const prevHtmlRef = useRef<string>(\"\");\n const htmlContent = React.useMemo(() => {\n const segments = splitContentSegments(content);\n // console.log('segments=====', segments);\n const sandboxSegments = segments.filter((seg) => seg.type === \"sandbox\");\n const sandboxContent =\n mode === \"blackboard\"\n ? sandboxSegments[sandboxSegments.length - 1]?.value || \"\"\n : sandboxSegments.map((seg) => seg.value).join(\"\\n\");\n return sandboxContent || \"\";\n }, [content, mode]);\n const hasRootVhHeight = React.useMemo(() => {\n const normalized = htmlContent.trim();\n if (!normalized) return false;\n const rootMatch = normalized.match(/^<([a-zA-Z][\\w:-]*)(\\s[^>]*?)?>/);\n if (!rootMatch) return false;\n const attrs = rootMatch[2] || \"\";\n const heightAttrMatch = attrs.match(/\\bheight\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (heightAttrMatch && /vh$/i.test(heightAttrMatch[1].trim())) {\n return true;\n }\n const styleAttrMatch = attrs.match(/\\bstyle\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (!styleAttrMatch) return false;\n return /height\\s*:\\s*[^;]*vh\\b/i.test(styleAttrMatch[1]);\n }, [htmlContent]);\n useEffect(() => {\n if (mode !== \"blackboard\") {\n prevHtmlRef.current = htmlContent;\n return;\n }\n const prev = prevHtmlRef.current;\n const isContinuation = prev && htmlContent.startsWith(prev);\n if (!isContinuation && prev) {\n setResetToken((token) => token + 1);\n }\n prevHtmlRef.current = htmlContent;\n }, [htmlContent, mode]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return undefined;\n\n const doc = iframe.contentDocument;\n if (!doc) return undefined;\n\n doc.open();\n doc.write(`<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <style>\n html, body { margin: 0; padding: 0; }\n *, *::before, *::after { box-sizing: border-box; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n </body>\n</html>`);\n doc.close();\n docRef.current = doc;\n\n const rootEl = doc.getElementById(\"root\");\n if (!rootEl) return undefined;\n\n const root = createRoot(rootEl);\n rootRef.current = root;\n\n const parseExplicitHeight = (\n value: string,\n parentViewportHeight: number\n ) => {\n const normalized = value.trim().toLowerCase();\n if (!normalized) return null;\n const numeric = Number.parseFloat(normalized);\n if (Number.isNaN(numeric)) return null;\n if (normalized.endsWith(\"vh\")) {\n return (numeric / 100) * parentViewportHeight;\n }\n if (normalized.endsWith(\"px\") || /^[0-9.]+$/.test(normalized)) {\n return numeric;\n }\n return null;\n };\n\n const resolveExplicitHeight = () => {\n if (!iframeRef.current || !doc.body) return null;\n const wrapper = doc.body.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const container = wrapper?.firstElementChild as HTMLElement | null;\n if (!container) return null;\n const elements = Array.from(container.children) as HTMLElement[];\n if (elements.length !== 1) return null;\n const target = elements[0];\n const heightValue = target.style.height || target.getAttribute(\"height\");\n if (!heightValue) return null;\n const parentViewportHeight =\n iframeRef.current.ownerDocument?.documentElement?.clientHeight ||\n window.innerHeight;\n const parsed = parseExplicitHeight(heightValue, parentViewportHeight);\n return parsed ? Math.ceil(parsed) : null;\n };\n\n const updateHeight = () => {\n if (!iframeRef.current || !doc.body) return;\n const bodyRect = doc.body.getBoundingClientRect();\n const htmlRect = doc.documentElement?.getBoundingClientRect();\n const bodyHeight = bodyRect.height;\n const htmlHeight = htmlRect?.height || 0;\n const contentHeight = Math.max(bodyHeight, htmlHeight);\n const explicitHeight = resolveExplicitHeight();\n const nextHeight = Math.max(\n 200,\n explicitHeight ?? Math.ceil(contentHeight)\n );\n setHeight(nextHeight);\n };\n updateHeightRef.current = updateHeight;\n\n updateHeight();\n\n const resizeObserver = new ResizeObserver(() => updateHeight());\n resizeObserver.observe(doc.body);\n if (rootEl) {\n resizeObserver.observe(rootEl);\n }\n\n return () => {\n resizeObserver.disconnect();\n // Defer unmount to avoid React warning when parent is mid-render\n setTimeout(() => {\n root.unmount();\n rootRef.current = null;\n docRef.current = null;\n updateHeightRef.current = () => {};\n }, 0);\n };\n }, []);\n\n useEffect(() => {\n const onFullscreenChange = () => {\n setIsFullscreen(Boolean(document.fullscreenElement));\n };\n document.addEventListener(\"fullscreenchange\", onFullscreenChange);\n return () =>\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange);\n }, []);\n\n const toggleFullscreen = () => {\n const target = containerRef.current || iframeRef.current;\n if (!target) return;\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n return;\n }\n if (target.requestFullscreen) {\n target.requestFullscreen().catch(() => {});\n }\n };\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n root.render(\n <SandboxApp\n html={htmlContent}\n loadingText={loadingText}\n styleLoadingText={styleLoadingText}\n scriptLoadingText={scriptLoadingText}\n fullScreenButtonText={fullScreenButtonText}\n hideFullScreen={hideFullScreen}\n resetToken={resetToken}\n hasRootVhHeight={hasRootVhHeight}\n mode={mode}\n />\n );\n requestAnimationFrame(() => updateHeightRef.current?.());\n }, [\n content,\n htmlContent,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n resetToken,\n mode,\n ]);\n\n return (\n <div\n ref={containerRef}\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className={\n \"w-full h-full overflow-auto relative flex flex-col justify-center content-render-iframe-sandbox\"\n }\n >\n {!hideFullScreen && (\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className={\n \"absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer\"\n }\n >\n {isFullscreen ? \"退出全屏\" : fullScreenButtonText || \"全屏浏览\"}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <ContentRender content={content} />\n ) : (\n <iframe\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin\"\n allow=\"fullscreen\"\n allowFullScreen\n className={(className, \"w-full\")}\n style={{\n height: mode === \"blackboard\" ? \"100%\" : `${height}px`,\n // height: `${height}px`,\n // margin: \"16px 0\",\n }}\n />\n )}\n </div>\n );\n};\n\nexport default IframeSandbox;\n"],"names":["IframeSandbox","content","type","className","loadingText","styleLoadingText","scriptLoadingText","fullScreenButtonText","hideFullScreen","mode","containerRef","useRef","iframeRef","rootRef","docRef","updateHeightRef","height","setHeight","useState","resetToken","setResetToken","isFullscreen","setIsFullscreen","prevHtmlRef","htmlContent","React","sandboxSegments","splitContentSegments","seg","hasRootVhHeight","normalized","rootMatch","attrs","heightAttrMatch","styleAttrMatch","useEffect","prev","token","iframe","doc","rootEl","root","createRoot","parseExplicitHeight","value","parentViewportHeight","numeric","resolveExplicitHeight","container","elements","target","heightValue","parsed","updateHeight","bodyRect","htmlRect","bodyHeight","htmlHeight","contentHeight","explicitHeight","nextHeight","resizeObserver","onFullscreenChange","toggleFullscreen","jsx","SandboxApp","jsxs","ContentRender"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"IframeSandbox.cjs.js","sources":["../../../src/components/ContentRender/IframeSandbox.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport SandboxApp from \"./SandboxApp\";\nimport { splitContentSegments } from \"./utils/split-content\";\nimport ContentRender from \"./ContentRender\";\nexport interface IframeSandboxProps {\n content: string;\n className?: string;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n hideFullScreen?: boolean;\n mode?: \"content\" | \"blackboard\";\n type: \"sandbox\" | \"markdown\";\n}\n\nconst IframeSandbox: React.FC<IframeSandboxProps> = ({\n content,\n type,\n className,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const rootRef = useRef<Root | null>(null);\n const docRef = useRef<Document | null>(null);\n const updateHeightRef = useRef<() => void>(() => {});\n const [height, setHeight] = useState(480);\n const [resetToken, setResetToken] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const prevHtmlRef = useRef<string>(\"\");\n const htmlContent = React.useMemo(() => {\n const segments = splitContentSegments(content, true);\n // console.log('segments=====', segments);\n const sandboxSegments = segments.filter((seg) => seg.type === \"sandbox\");\n const sandboxContent =\n mode === \"blackboard\"\n ? sandboxSegments[sandboxSegments.length - 1]?.value || \"\"\n : sandboxSegments.map((seg) => seg.value).join(\"\\n\");\n return sandboxContent || \"\";\n }, [content, mode]);\n const hasRootVhHeight = React.useMemo(() => {\n const normalized = htmlContent.trim();\n if (!normalized) return false;\n const rootMatch = normalized.match(/^<([a-zA-Z][\\w:-]*)(\\s[^>]*?)?>/);\n if (!rootMatch) return false;\n const attrs = rootMatch[2] || \"\";\n const heightAttrMatch = attrs.match(/\\bheight\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (heightAttrMatch && /vh$/i.test(heightAttrMatch[1].trim())) {\n return true;\n }\n const styleAttrMatch = attrs.match(/\\bstyle\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (!styleAttrMatch) return false;\n return /height\\s*:\\s*[^;]*vh\\b/i.test(styleAttrMatch[1]);\n }, [htmlContent]);\n useEffect(() => {\n if (mode !== \"blackboard\") {\n prevHtmlRef.current = htmlContent;\n return;\n }\n const prev = prevHtmlRef.current;\n const isContinuation = prev && htmlContent.startsWith(prev);\n if (!isContinuation && prev) {\n setResetToken((token) => token + 1);\n }\n prevHtmlRef.current = htmlContent;\n }, [htmlContent, mode]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return undefined;\n\n const doc = iframe.contentDocument;\n if (!doc) return undefined;\n\n doc.open();\n doc.write(`<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <style>\n html, body { margin: 0; padding: 0; }\n *, *::before, *::after { box-sizing: border-box; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n </body>\n</html>`);\n doc.close();\n docRef.current = doc;\n\n const rootEl = doc.getElementById(\"root\");\n if (!rootEl) return undefined;\n\n const root = createRoot(rootEl);\n rootRef.current = root;\n\n const parseExplicitHeight = (\n value: string,\n parentViewportHeight: number\n ) => {\n const normalized = value.trim().toLowerCase();\n if (!normalized) return null;\n const numeric = Number.parseFloat(normalized);\n if (Number.isNaN(numeric)) return null;\n if (normalized.endsWith(\"vh\")) {\n return (numeric / 100) * parentViewportHeight;\n }\n if (normalized.endsWith(\"px\") || /^[0-9.]+$/.test(normalized)) {\n return numeric;\n }\n return null;\n };\n\n const resolveExplicitHeight = () => {\n if (!iframeRef.current || !doc.body) return null;\n const wrapper = doc.body.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const container = wrapper?.firstElementChild as HTMLElement | null;\n if (!container) return null;\n const elements = Array.from(container.children) as HTMLElement[];\n if (elements.length !== 1) return null;\n const target = elements[0];\n const heightValue = target.style.height || target.getAttribute(\"height\");\n if (!heightValue) return null;\n const parentViewportHeight =\n iframeRef.current.ownerDocument?.documentElement?.clientHeight ||\n window.innerHeight;\n const parsed = parseExplicitHeight(heightValue, parentViewportHeight);\n return parsed ? Math.ceil(parsed) : null;\n };\n\n const updateHeight = () => {\n if (!iframeRef.current || !doc.body) return;\n const bodyRect = doc.body.getBoundingClientRect();\n const htmlRect = doc.documentElement?.getBoundingClientRect();\n const bodyHeight = bodyRect.height;\n const htmlHeight = htmlRect?.height || 0;\n const contentHeight = Math.max(bodyHeight, htmlHeight);\n const explicitHeight = resolveExplicitHeight();\n const nextHeight = Math.max(\n 200,\n explicitHeight ?? Math.ceil(contentHeight)\n );\n setHeight(nextHeight);\n };\n updateHeightRef.current = updateHeight;\n\n updateHeight();\n\n const resizeObserver = new ResizeObserver(() => updateHeight());\n resizeObserver.observe(doc.body);\n if (rootEl) {\n resizeObserver.observe(rootEl);\n }\n\n return () => {\n resizeObserver.disconnect();\n // Defer unmount to avoid React warning when parent is mid-render\n setTimeout(() => {\n root.unmount();\n rootRef.current = null;\n docRef.current = null;\n updateHeightRef.current = () => {};\n }, 0);\n };\n }, []);\n\n useEffect(() => {\n const onFullscreenChange = () => {\n setIsFullscreen(Boolean(document.fullscreenElement));\n };\n document.addEventListener(\"fullscreenchange\", onFullscreenChange);\n return () =>\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange);\n }, []);\n\n const toggleFullscreen = () => {\n const target = containerRef.current || iframeRef.current;\n if (!target) return;\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n return;\n }\n if (target.requestFullscreen) {\n target.requestFullscreen().catch(() => {});\n }\n };\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n root.render(\n <SandboxApp\n html={htmlContent}\n loadingText={loadingText}\n styleLoadingText={styleLoadingText}\n scriptLoadingText={scriptLoadingText}\n fullScreenButtonText={fullScreenButtonText}\n hideFullScreen={hideFullScreen}\n resetToken={resetToken}\n hasRootVhHeight={hasRootVhHeight}\n mode={mode}\n />\n );\n requestAnimationFrame(() => updateHeightRef.current?.());\n }, [\n content,\n htmlContent,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n resetToken,\n mode,\n ]);\n\n return (\n <div\n ref={containerRef}\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className={\n \"w-full h-full overflow-auto relative flex flex-col justify-center content-render-iframe-sandbox\"\n }\n >\n {!hideFullScreen && (\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className={\n \"absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer\"\n }\n >\n {isFullscreen ? \"退出全屏\" : fullScreenButtonText || \"全屏浏览\"}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <ContentRender content={content} />\n ) : (\n <iframe\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin\"\n allow=\"fullscreen\"\n allowFullScreen\n className={(className, \"w-full\")}\n style={{\n height: mode === \"blackboard\" ? \"100%\" : `${height}px`,\n // height: `${height}px`,\n // margin: \"16px 0\",\n }}\n />\n )}\n </div>\n );\n};\n\nexport default IframeSandbox;\n"],"names":["IframeSandbox","content","type","className","loadingText","styleLoadingText","scriptLoadingText","fullScreenButtonText","hideFullScreen","mode","containerRef","useRef","iframeRef","rootRef","docRef","updateHeightRef","height","setHeight","useState","resetToken","setResetToken","isFullscreen","setIsFullscreen","prevHtmlRef","htmlContent","React","sandboxSegments","splitContentSegments","seg","hasRootVhHeight","normalized","rootMatch","attrs","heightAttrMatch","styleAttrMatch","useEffect","prev","token","iframe","doc","rootEl","root","createRoot","parseExplicitHeight","value","parentViewportHeight","numeric","resolveExplicitHeight","container","elements","target","heightValue","parsed","updateHeight","bodyRect","htmlRect","bodyHeight","htmlHeight","contentHeight","explicitHeight","nextHeight","resizeObserver","onFullscreenChange","toggleFullscreen","jsx","SandboxApp","jsxs","ContentRender"],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ const ee = ({
|
|
|
17
17
|
}) => {
|
|
18
18
|
const N = a(null), i = a(null), v = a(null), z = a(null), y = a(() => {
|
|
19
19
|
}), [I, O] = E(480), [A, V] = E(0), [W, $] = E(!1), w = a(""), c = S.useMemo(() => {
|
|
20
|
-
const t = Y(m).filter((o) => o.type === "sandbox");
|
|
20
|
+
const t = Y(m, !0).filter((o) => o.type === "sandbox");
|
|
21
21
|
return (s === "blackboard" ? t[t.length - 1]?.value || "" : t.map((o) => o.value).join(`
|
|
22
22
|
`)) || "";
|
|
23
23
|
}, [m, s]), q = S.useMemo(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeSandbox.es.js","sources":["../../../src/components/ContentRender/IframeSandbox.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport SandboxApp from \"./SandboxApp\";\nimport { splitContentSegments } from \"./utils/split-content\";\nimport ContentRender from \"./ContentRender\";\nexport interface IframeSandboxProps {\n content: string;\n className?: string;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n hideFullScreen?: boolean;\n mode?: \"content\" | \"blackboard\";\n type: \"sandbox\" | \"markdown\";\n}\n\nconst IframeSandbox: React.FC<IframeSandboxProps> = ({\n content,\n type,\n className,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const rootRef = useRef<Root | null>(null);\n const docRef = useRef<Document | null>(null);\n const updateHeightRef = useRef<() => void>(() => {});\n const [height, setHeight] = useState(480);\n const [resetToken, setResetToken] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const prevHtmlRef = useRef<string>(\"\");\n const htmlContent = React.useMemo(() => {\n const segments = splitContentSegments(content);\n // console.log('segments=====', segments);\n const sandboxSegments = segments.filter((seg) => seg.type === \"sandbox\");\n const sandboxContent =\n mode === \"blackboard\"\n ? sandboxSegments[sandboxSegments.length - 1]?.value || \"\"\n : sandboxSegments.map((seg) => seg.value).join(\"\\n\");\n return sandboxContent || \"\";\n }, [content, mode]);\n const hasRootVhHeight = React.useMemo(() => {\n const normalized = htmlContent.trim();\n if (!normalized) return false;\n const rootMatch = normalized.match(/^<([a-zA-Z][\\w:-]*)(\\s[^>]*?)?>/);\n if (!rootMatch) return false;\n const attrs = rootMatch[2] || \"\";\n const heightAttrMatch = attrs.match(/\\bheight\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (heightAttrMatch && /vh$/i.test(heightAttrMatch[1].trim())) {\n return true;\n }\n const styleAttrMatch = attrs.match(/\\bstyle\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (!styleAttrMatch) return false;\n return /height\\s*:\\s*[^;]*vh\\b/i.test(styleAttrMatch[1]);\n }, [htmlContent]);\n useEffect(() => {\n if (mode !== \"blackboard\") {\n prevHtmlRef.current = htmlContent;\n return;\n }\n const prev = prevHtmlRef.current;\n const isContinuation = prev && htmlContent.startsWith(prev);\n if (!isContinuation && prev) {\n setResetToken((token) => token + 1);\n }\n prevHtmlRef.current = htmlContent;\n }, [htmlContent, mode]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return undefined;\n\n const doc = iframe.contentDocument;\n if (!doc) return undefined;\n\n doc.open();\n doc.write(`<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <style>\n html, body { margin: 0; padding: 0; }\n *, *::before, *::after { box-sizing: border-box; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n </body>\n</html>`);\n doc.close();\n docRef.current = doc;\n\n const rootEl = doc.getElementById(\"root\");\n if (!rootEl) return undefined;\n\n const root = createRoot(rootEl);\n rootRef.current = root;\n\n const parseExplicitHeight = (\n value: string,\n parentViewportHeight: number\n ) => {\n const normalized = value.trim().toLowerCase();\n if (!normalized) return null;\n const numeric = Number.parseFloat(normalized);\n if (Number.isNaN(numeric)) return null;\n if (normalized.endsWith(\"vh\")) {\n return (numeric / 100) * parentViewportHeight;\n }\n if (normalized.endsWith(\"px\") || /^[0-9.]+$/.test(normalized)) {\n return numeric;\n }\n return null;\n };\n\n const resolveExplicitHeight = () => {\n if (!iframeRef.current || !doc.body) return null;\n const wrapper = doc.body.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const container = wrapper?.firstElementChild as HTMLElement | null;\n if (!container) return null;\n const elements = Array.from(container.children) as HTMLElement[];\n if (elements.length !== 1) return null;\n const target = elements[0];\n const heightValue = target.style.height || target.getAttribute(\"height\");\n if (!heightValue) return null;\n const parentViewportHeight =\n iframeRef.current.ownerDocument?.documentElement?.clientHeight ||\n window.innerHeight;\n const parsed = parseExplicitHeight(heightValue, parentViewportHeight);\n return parsed ? Math.ceil(parsed) : null;\n };\n\n const updateHeight = () => {\n if (!iframeRef.current || !doc.body) return;\n const bodyRect = doc.body.getBoundingClientRect();\n const htmlRect = doc.documentElement?.getBoundingClientRect();\n const bodyHeight = bodyRect.height;\n const htmlHeight = htmlRect?.height || 0;\n const contentHeight = Math.max(bodyHeight, htmlHeight);\n const explicitHeight = resolveExplicitHeight();\n const nextHeight = Math.max(\n 200,\n explicitHeight ?? Math.ceil(contentHeight)\n );\n setHeight(nextHeight);\n };\n updateHeightRef.current = updateHeight;\n\n updateHeight();\n\n const resizeObserver = new ResizeObserver(() => updateHeight());\n resizeObserver.observe(doc.body);\n if (rootEl) {\n resizeObserver.observe(rootEl);\n }\n\n return () => {\n resizeObserver.disconnect();\n // Defer unmount to avoid React warning when parent is mid-render\n setTimeout(() => {\n root.unmount();\n rootRef.current = null;\n docRef.current = null;\n updateHeightRef.current = () => {};\n }, 0);\n };\n }, []);\n\n useEffect(() => {\n const onFullscreenChange = () => {\n setIsFullscreen(Boolean(document.fullscreenElement));\n };\n document.addEventListener(\"fullscreenchange\", onFullscreenChange);\n return () =>\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange);\n }, []);\n\n const toggleFullscreen = () => {\n const target = containerRef.current || iframeRef.current;\n if (!target) return;\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n return;\n }\n if (target.requestFullscreen) {\n target.requestFullscreen().catch(() => {});\n }\n };\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n root.render(\n <SandboxApp\n html={htmlContent}\n loadingText={loadingText}\n styleLoadingText={styleLoadingText}\n scriptLoadingText={scriptLoadingText}\n fullScreenButtonText={fullScreenButtonText}\n hideFullScreen={hideFullScreen}\n resetToken={resetToken}\n hasRootVhHeight={hasRootVhHeight}\n mode={mode}\n />\n );\n requestAnimationFrame(() => updateHeightRef.current?.());\n }, [\n content,\n htmlContent,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n resetToken,\n mode,\n ]);\n\n return (\n <div\n ref={containerRef}\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className={\n \"w-full h-full overflow-auto relative flex flex-col justify-center content-render-iframe-sandbox\"\n }\n >\n {!hideFullScreen && (\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className={\n \"absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer\"\n }\n >\n {isFullscreen ? \"退出全屏\" : fullScreenButtonText || \"全屏浏览\"}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <ContentRender content={content} />\n ) : (\n <iframe\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin\"\n allow=\"fullscreen\"\n allowFullScreen\n className={(className, \"w-full\")}\n style={{\n height: mode === \"blackboard\" ? \"100%\" : `${height}px`,\n // height: `${height}px`,\n // margin: \"16px 0\",\n }}\n />\n )}\n </div>\n );\n};\n\nexport default IframeSandbox;\n"],"names":["IframeSandbox","content","type","className","loadingText","styleLoadingText","scriptLoadingText","fullScreenButtonText","hideFullScreen","mode","containerRef","useRef","iframeRef","rootRef","docRef","updateHeightRef","height","setHeight","useState","resetToken","setResetToken","isFullscreen","setIsFullscreen","prevHtmlRef","htmlContent","React","sandboxSegments","splitContentSegments","seg","hasRootVhHeight","normalized","rootMatch","attrs","heightAttrMatch","styleAttrMatch","useEffect","prev","token","iframe","doc","rootEl","root","createRoot","parseExplicitHeight","value","parentViewportHeight","numeric","resolveExplicitHeight","container","elements","target","heightValue","parsed","updateHeight","bodyRect","htmlRect","bodyHeight","htmlHeight","contentHeight","explicitHeight","nextHeight","resizeObserver","onFullscreenChange","toggleFullscreen","jsx","SandboxApp","jsxs","ContentRender"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"IframeSandbox.es.js","sources":["../../../src/components/ContentRender/IframeSandbox.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from \"react\";\nimport { createRoot, Root } from \"react-dom/client\";\nimport SandboxApp from \"./SandboxApp\";\nimport { splitContentSegments } from \"./utils/split-content\";\nimport ContentRender from \"./ContentRender\";\nexport interface IframeSandboxProps {\n content: string;\n className?: string;\n loadingText?: string;\n styleLoadingText?: string;\n scriptLoadingText?: string;\n fullScreenButtonText?: string;\n hideFullScreen?: boolean;\n mode?: \"content\" | \"blackboard\";\n type: \"sandbox\" | \"markdown\";\n}\n\nconst IframeSandbox: React.FC<IframeSandboxProps> = ({\n content,\n type,\n className,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n hideFullScreen = false,\n mode = \"content\",\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const rootRef = useRef<Root | null>(null);\n const docRef = useRef<Document | null>(null);\n const updateHeightRef = useRef<() => void>(() => {});\n const [height, setHeight] = useState(480);\n const [resetToken, setResetToken] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const prevHtmlRef = useRef<string>(\"\");\n const htmlContent = React.useMemo(() => {\n const segments = splitContentSegments(content, true);\n // console.log('segments=====', segments);\n const sandboxSegments = segments.filter((seg) => seg.type === \"sandbox\");\n const sandboxContent =\n mode === \"blackboard\"\n ? sandboxSegments[sandboxSegments.length - 1]?.value || \"\"\n : sandboxSegments.map((seg) => seg.value).join(\"\\n\");\n return sandboxContent || \"\";\n }, [content, mode]);\n const hasRootVhHeight = React.useMemo(() => {\n const normalized = htmlContent.trim();\n if (!normalized) return false;\n const rootMatch = normalized.match(/^<([a-zA-Z][\\w:-]*)(\\s[^>]*?)?>/);\n if (!rootMatch) return false;\n const attrs = rootMatch[2] || \"\";\n const heightAttrMatch = attrs.match(/\\bheight\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (heightAttrMatch && /vh$/i.test(heightAttrMatch[1].trim())) {\n return true;\n }\n const styleAttrMatch = attrs.match(/\\bstyle\\s*=\\s*[\"']([^\"']+)[\"']/i);\n if (!styleAttrMatch) return false;\n return /height\\s*:\\s*[^;]*vh\\b/i.test(styleAttrMatch[1]);\n }, [htmlContent]);\n useEffect(() => {\n if (mode !== \"blackboard\") {\n prevHtmlRef.current = htmlContent;\n return;\n }\n const prev = prevHtmlRef.current;\n const isContinuation = prev && htmlContent.startsWith(prev);\n if (!isContinuation && prev) {\n setResetToken((token) => token + 1);\n }\n prevHtmlRef.current = htmlContent;\n }, [htmlContent, mode]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe) return undefined;\n\n const doc = iframe.contentDocument;\n if (!doc) return undefined;\n\n doc.open();\n doc.write(`<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <style>\n html, body { margin: 0; padding: 0; }\n *, *::before, *::after { box-sizing: border-box; }\n </style>\n </head>\n <body>\n <div id=\"root\"></div>\n </body>\n</html>`);\n doc.close();\n docRef.current = doc;\n\n const rootEl = doc.getElementById(\"root\");\n if (!rootEl) return undefined;\n\n const root = createRoot(rootEl);\n rootRef.current = root;\n\n const parseExplicitHeight = (\n value: string,\n parentViewportHeight: number\n ) => {\n const normalized = value.trim().toLowerCase();\n if (!normalized) return null;\n const numeric = Number.parseFloat(normalized);\n if (Number.isNaN(numeric)) return null;\n if (normalized.endsWith(\"vh\")) {\n return (numeric / 100) * parentViewportHeight;\n }\n if (normalized.endsWith(\"px\") || /^[0-9.]+$/.test(normalized)) {\n return numeric;\n }\n return null;\n };\n\n const resolveExplicitHeight = () => {\n if (!iframeRef.current || !doc.body) return null;\n const wrapper = doc.body.querySelector(\n \".sandbox-wrapper\"\n ) as HTMLElement | null;\n const container = wrapper?.firstElementChild as HTMLElement | null;\n if (!container) return null;\n const elements = Array.from(container.children) as HTMLElement[];\n if (elements.length !== 1) return null;\n const target = elements[0];\n const heightValue = target.style.height || target.getAttribute(\"height\");\n if (!heightValue) return null;\n const parentViewportHeight =\n iframeRef.current.ownerDocument?.documentElement?.clientHeight ||\n window.innerHeight;\n const parsed = parseExplicitHeight(heightValue, parentViewportHeight);\n return parsed ? Math.ceil(parsed) : null;\n };\n\n const updateHeight = () => {\n if (!iframeRef.current || !doc.body) return;\n const bodyRect = doc.body.getBoundingClientRect();\n const htmlRect = doc.documentElement?.getBoundingClientRect();\n const bodyHeight = bodyRect.height;\n const htmlHeight = htmlRect?.height || 0;\n const contentHeight = Math.max(bodyHeight, htmlHeight);\n const explicitHeight = resolveExplicitHeight();\n const nextHeight = Math.max(\n 200,\n explicitHeight ?? Math.ceil(contentHeight)\n );\n setHeight(nextHeight);\n };\n updateHeightRef.current = updateHeight;\n\n updateHeight();\n\n const resizeObserver = new ResizeObserver(() => updateHeight());\n resizeObserver.observe(doc.body);\n if (rootEl) {\n resizeObserver.observe(rootEl);\n }\n\n return () => {\n resizeObserver.disconnect();\n // Defer unmount to avoid React warning when parent is mid-render\n setTimeout(() => {\n root.unmount();\n rootRef.current = null;\n docRef.current = null;\n updateHeightRef.current = () => {};\n }, 0);\n };\n }, []);\n\n useEffect(() => {\n const onFullscreenChange = () => {\n setIsFullscreen(Boolean(document.fullscreenElement));\n };\n document.addEventListener(\"fullscreenchange\", onFullscreenChange);\n return () =>\n document.removeEventListener(\"fullscreenchange\", onFullscreenChange);\n }, []);\n\n const toggleFullscreen = () => {\n const target = containerRef.current || iframeRef.current;\n if (!target) return;\n if (document.fullscreenElement) {\n document.exitFullscreen().catch(() => {});\n return;\n }\n if (target.requestFullscreen) {\n target.requestFullscreen().catch(() => {});\n }\n };\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n\n root.render(\n <SandboxApp\n html={htmlContent}\n loadingText={loadingText}\n styleLoadingText={styleLoadingText}\n scriptLoadingText={scriptLoadingText}\n fullScreenButtonText={fullScreenButtonText}\n hideFullScreen={hideFullScreen}\n resetToken={resetToken}\n hasRootVhHeight={hasRootVhHeight}\n mode={mode}\n />\n );\n requestAnimationFrame(() => updateHeightRef.current?.());\n }, [\n content,\n htmlContent,\n loadingText,\n styleLoadingText,\n scriptLoadingText,\n fullScreenButtonText,\n resetToken,\n mode,\n ]);\n\n return (\n <div\n ref={containerRef}\n data-root-vh={hasRootVhHeight ? \"true\" : \"false\"}\n className={\n \"w-full h-full overflow-auto relative flex flex-col justify-center content-render-iframe-sandbox\"\n }\n >\n {!hideFullScreen && (\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className={\n \"absolute top-2 right-2 z-50 p-1.5 bg-black/75 text-white rounded-md cursor-pointer\"\n }\n >\n {isFullscreen ? \"退出全屏\" : fullScreenButtonText || \"全屏浏览\"}\n </button>\n )}\n {mode === \"blackboard\" && type === \"markdown\" ? (\n <ContentRender content={content} />\n ) : (\n <iframe\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin\"\n allow=\"fullscreen\"\n allowFullScreen\n className={(className, \"w-full\")}\n style={{\n height: mode === \"blackboard\" ? \"100%\" : `${height}px`,\n // height: `${height}px`,\n // margin: \"16px 0\",\n }}\n />\n )}\n </div>\n );\n};\n\nexport default IframeSandbox;\n"],"names":["IframeSandbox","content","type","className","loadingText","styleLoadingText","scriptLoadingText","fullScreenButtonText","hideFullScreen","mode","containerRef","useRef","iframeRef","rootRef","docRef","updateHeightRef","height","setHeight","useState","resetToken","setResetToken","isFullscreen","setIsFullscreen","prevHtmlRef","htmlContent","React","sandboxSegments","splitContentSegments","seg","hasRootVhHeight","normalized","rootMatch","attrs","heightAttrMatch","styleAttrMatch","useEffect","prev","token","iframe","doc","rootEl","root","createRoot","parseExplicitHeight","value","parentViewportHeight","numeric","resolveExplicitHeight","container","elements","target","heightValue","parsed","updateHeight","bodyRect","htmlRect","bodyHeight","htmlHeight","contentHeight","explicitHeight","nextHeight","resizeObserver","onFullscreenChange","toggleFullscreen","jsx","SandboxApp","jsxs","ContentRender"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { StoryObj } from '@storybook/nextjs-vite';
|
|
2
|
+
declare const meta: {
|
|
3
|
+
title: string;
|
|
4
|
+
component: import('react').FC<import('./ContentRender').ContentRenderProps>;
|
|
5
|
+
parameters: {
|
|
6
|
+
layout: string;
|
|
7
|
+
};
|
|
8
|
+
tags: string[];
|
|
9
|
+
args: {
|
|
10
|
+
content: string;
|
|
11
|
+
enableTypewriter: false;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof meta>;
|
|
16
|
+
export declare const SplitContentValidation: Story;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const F=/<(script|style|link|iframe|html|head|body|meta|title|base|template|div|section|article|main)[\s>]/i,C=[/<svg[\s\S]*?<\/svg>/i,/<img\b[^>]*?>/i,/```mermaid[\s\S]*?```/i,/```[a-zA-Z0-9]+[\s\S]*?```/i],E=/!\[[^\]]*]\([^\s)\n]+(?:\s+"[^"]*")?\)/i,A=/^(?: {0,3})#{1,6}[ \t]+[^\n]+$/m,O=/<iframe\b[^>]*\bdata-tag\s*=\s*(["'])video\1[^>]*>[\s\S]*?<\/iframe>/i,T=/<\/[a-z][^>]*>\s*\n(?=[^\s<])/gi,N=/<custom-button-after-content\b[\s\S]*?<\/custom-button-after-content>/gi,W=t=>{const n=[],e=/```/g;let s;for(;(s=e.exec(t))!==null;){const c=s.index,o=e.exec(t);if(!o){n.push({start:c,end:t.length});break}n.push({start:c,end:o.index+3})}return n},H=(t,n)=>n.some(({start:e,end:s})=>t>=e&&t<s),h=(t,n,e)=>{const s=n.flags.includes("g")?n.flags:`${n.flags}g`,c=new RegExp(n.source,s);let o;for(;(o=c.exec(t))!==null;)if(!H(o.index,e))return o.index;return-1},L=(t,n)=>{let e=t.length,s;for(T.lastIndex=0;s=T.exec(t);)if(!(s.index<=n)){e=s.index+s[0].length;break}return e},$=t=>{if(!t.length)return t;const n=[];return t.forEach(e=>{if(e.type!=="sandbox"){n.push(e);return}N.lastIndex=0;let s=0,c;for(;(c=N.exec(e.value))!==null;){const i=e.value.slice(s,c.index);i.trim()&&n.push({type:"sandbox",value:i}),n.push({type:"markdown",value:c[0]}),s=c.index+c[0].length}const o=e.value.slice(s);o.trim()&&n.push({type:"sandbox",value:o})}),n},z=t=>{let n=null;return C.forEach(e=>{const s=e.exec(t);if(!s||typeof s.index!="number")return;const c=s.index,o=s.index+s[0].length;(!n||c<n.start)&&(n={start:c,end:o})}),n},K=(...t)=>t.reduce((n,e)=>e&&(!n||e.start<n.start)?e:n,null),U=(t,n)=>{const e=h(t,E,n);if(e===-1)return null;const s=t.slice(e).match(E);return s?{start:e,end:e+s[0].length}:null},V=(t,n)=>{const e=h(t,A,n);if(e===-1)return null;const s=t.slice(e).match(A);return s?{start:e,end:e+s[0].length}:null},j=(t,n)=>{const e=h(t,O,n);if(e===-1)return null;const s=t.slice(e).match(O);return s?{start:e,end:e+s[0].length}:null},G=(t,n)=>{const e=t.lastIndexOf(`
|
|
2
|
+
`,n-1)+1,s=t.indexOf(`
|
|
3
|
+
`,n),c=s===-1?t.length:s;return t.slice(e,c).trimStart().startsWith("|")},X=t=>{const n=t.match(/^\s*\|.+\|\s*$/m);if(!n||typeof n.index!="number")return null;const e=n[0].match(/^\s*/)?.[0].length??0,s=n.index+e,c=t.slice(s).split(`
|
|
4
|
+
`),o=[];for(const m of c){if(!m.trim().startsWith("|"))break;o.push(m)}const i=o.join(`
|
|
5
|
+
`);return{start:s,block:i,end:s+i.length}},d=(t,n=!0)=>{const e=l=>$(l),s=t.indexOf("```");if(n&&s!==-1&&t.indexOf("```",s+3)===-1)return e([{type:"markdown",value:t}]);const c=W(t),o=h(t,F,c),i=h(t,/<svg\b/i,c),m=i!==-1&&G(t,i),S=o!==-1&&i!==-1&&o<i;if(i!==-1&&!S&&!m){const l=t.slice(0,i),r=t.indexOf("</svg>",i),a=r===-1?`${t.slice(i)}</svg>`:t.slice(i,r+6),b=r===-1?"":t.slice(r+6);if(n){const x=[];return l.trim()&&x.push(...d(l,!0)),x.push({type:"markdown",value:a}),b.trim()&&x.push(...d(b,!0)),e(x)}if(r===-1)return e([{type:"markdown",value:a}])}const u=X(t),p=V(t,c),R=!!u&&(!p||u.start<p.start);if(u&&R){const l=[],r=t.slice(0,u.start);n&&r.trim()&&l.push({type:"text",value:r}),l.push({type:"markdown",value:u.block});const a=t.slice(u.end),b=a.length<t.length;return a.trim()&&b&&l.push(...n?d(a,!0):d(a)),e(l)}const _=z(t),B=U(t,c),P=j(t,c),f=K(_,B,p,P);if(o===-1&&!f)return n&&t.trim()?e([{type:"text",value:t}]):[];const v=!!f&&(o===-1||f.start<=o),I=v?f.start:o,M=v?f.end:L(t,I),g=[],k=t.slice(0,I),D=t.slice(I,M),y=t.slice(M);return n&&k.trim()&&g.push({type:"text",value:k}),g.push({type:v?"markdown":"sandbox",value:D}),y.trim()&&g.push(...d(y,n)),e(g)};exports.splitContentSegments=d;
|
|
4
6
|
//# sourceMappingURL=split-content.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split-content.cjs.js","sources":["../../../../src/components/ContentRender/utils/split-content.ts"],"sourcesContent":["export type RenderSegment =\n | { type: \"markdown\"; value: string }\n | { type: \"sandbox\"; value: string }\n | { type: \"text\"; value: string };\n\nconst SANDBOX_START_PATTERN =\n /<(script|style|link|iframe|html|head|body|meta|title|base|template|div|section|article|main)[\\s>]/i;\n\nconst INLINE_SANDBOX_PATTERNS: RegExp[] = [\n /<svg[\\s\\S]*?<\\/svg>/i,\n /<img\\b[^>]*?>/i,\n /```mermaid[\\s\\S]*?```/i,\n /```[a-zA-Z0-9]+[\\s\\S]*?```/i,\n];\nconst MARKDOWN_IMAGE_PATTERN = /!\\[[^\\]]*]\\([^\\s)\\n]+(?:\\s+\"[^\"]*\")?\\)/i;\n\nconst closingBoundary = /<\\/[a-z][^>]*>\\s*\\n(?=[^\\s<])/gi;\nconst CUSTOM_BUTTON_PATTERN =\n /<custom-button-after-content\\b[\\s\\S]*?<\\/custom-button-after-content>/gi;\n\ntype MatchResult = { start: number; end: number };\ntype FenceRange = { start: number; end: number };\n\nconst getFenceRanges = (raw: string): FenceRange[] => {\n const ranges: FenceRange[] = [];\n const fencePattern = /```/g;\n let match: RegExpExecArray | null;\n\n while ((match = fencePattern.exec(raw)) !== null) {\n const start = match.index;\n const closeMatch = fencePattern.exec(raw);\n if (!closeMatch) {\n ranges.push({ start, end: raw.length });\n break;\n }\n ranges.push({ start, end: closeMatch.index + 3 });\n }\n\n return ranges;\n};\n\nconst isIndexInRanges = (index: number, ranges: FenceRange[]) =>\n ranges.some(({ start, end }) => index >= start && index < end);\n\nconst findFirstMatchOutsideFence = (\n raw: string,\n pattern: RegExp,\n fenceRanges: FenceRange[]\n) => {\n const flags = pattern.flags.includes(\"g\")\n ? pattern.flags\n : `${pattern.flags}g`;\n const matcher = new RegExp(pattern.source, flags);\n let match: RegExpExecArray | null;\n\n while ((match = matcher.exec(raw)) !== null) {\n if (!isIndexInRanges(match.index, fenceRanges)) {\n return match.index;\n }\n }\n\n return -1;\n};\n\nconst findHtmlBlockEnd = (raw: string, startIndex: number) => {\n let blockEnd = raw.length;\n let match: RegExpExecArray | null;\n closingBoundary.lastIndex = 0;\n\n while ((match = closingBoundary.exec(raw))) {\n if (match.index <= startIndex) continue;\n blockEnd = match.index + match[0].length;\n break;\n }\n\n return blockEnd;\n};\n\nconst splitCustomButtonsFromSandbox = (segments: RenderSegment[]) => {\n if (!segments.length) return segments;\n const output: RenderSegment[] = [];\n\n segments.forEach((segment) => {\n if (segment.type !== \"sandbox\") {\n output.push(segment);\n return;\n }\n\n CUSTOM_BUTTON_PATTERN.lastIndex = 0;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = CUSTOM_BUTTON_PATTERN.exec(segment.value)) !== null) {\n const before = segment.value.slice(lastIndex, match.index);\n if (before.trim()) {\n output.push({ type: \"sandbox\", value: before });\n }\n output.push({ type: \"markdown\", value: match[0] });\n lastIndex = match.index + match[0].length;\n }\n\n const rest = segment.value.slice(lastIndex);\n if (rest.trim()) {\n output.push({ type: \"sandbox\", value: rest });\n }\n });\n\n return output;\n};\n\nconst findInlineSandboxMatch = (raw: string): MatchResult | null => {\n let earliest: MatchResult | null = null;\n\n INLINE_SANDBOX_PATTERNS.forEach((pattern) => {\n const match = pattern.exec(raw);\n if (!match || typeof match.index !== \"number\") return;\n const start = match.index;\n const end = match.index + match[0].length;\n\n if (!earliest || start < earliest.start) {\n earliest = { start, end };\n }\n });\n\n return earliest;\n};\n\nconst findMarkdownImageMatch = (\n raw: string,\n fenceRanges: FenceRange[]\n): MatchResult | null => {\n const start = findFirstMatchOutsideFence(\n raw,\n MARKDOWN_IMAGE_PATTERN,\n fenceRanges\n );\n\n if (start === -1) return null;\n const match = raw.slice(start).match(MARKDOWN_IMAGE_PATTERN);\n if (!match) return null;\n\n return { start, end: start + match[0].length };\n};\n\nconst extractTableBlock = (\n raw: string\n): { start: number; block: string; end: number } | null => {\n const tableMatch = raw.match(/^\\s*\\|.+\\|\\s*$/m);\n if (!tableMatch || typeof tableMatch.index !== \"number\") return null;\n\n const leadingSpaces = tableMatch[0].match(/^\\s*/)?.[0].length ?? 0;\n const tableStart = tableMatch.index + leadingSpaces;\n\n const lines = raw.slice(tableStart).split(\"\\n\");\n const tableLines: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"|\")) break;\n tableLines.push(line);\n }\n\n const block = tableLines.join(\"\\n\");\n return { start: tableStart, block, end: tableStart + block.length };\n};\n\n// Split incoming markdown content into markdown and sandbox HTML segments\nexport const splitContentSegments = (\n raw: string,\n keepText = false\n): RenderSegment[] => {\n const finalizeSegments = (segments: RenderSegment[]) =>\n splitCustomButtonsFromSandbox(segments);\n\n const fenceStart = raw.indexOf(\"```\");\n if (keepText && fenceStart !== -1) {\n const closingFence = raw.indexOf(\"```\", fenceStart + 3);\n if (closingFence === -1) {\n return finalizeSegments([{ type: \"markdown\", value: raw }]);\n }\n }\n\n const fenceRanges = getFenceRanges(raw);\n // Avoid treating fenced code blocks as sandbox content.\n const sandboxStartIndex = findFirstMatchOutsideFence(\n raw,\n SANDBOX_START_PATTERN,\n fenceRanges\n );\n const svgOpenIndex = findFirstMatchOutsideFence(raw, /<svg\\b/i, fenceRanges);\n const hasSandboxBeforeSvg =\n sandboxStartIndex !== -1 &&\n svgOpenIndex !== -1 &&\n sandboxStartIndex < svgOpenIndex;\n if (svgOpenIndex !== -1 && !hasSandboxBeforeSvg) {\n const before = raw.slice(0, svgOpenIndex);\n const closeIdx = raw.indexOf(\"</svg>\", svgOpenIndex);\n const svgBlock =\n closeIdx === -1\n ? `${raw.slice(svgOpenIndex)}</svg>`\n : raw.slice(svgOpenIndex, closeIdx + \"</svg>\".length);\n const after = closeIdx === -1 ? \"\" : raw.slice(closeIdx + \"</svg>\".length);\n\n if (keepText) {\n const segments: RenderSegment[] = [];\n if (before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n segments.push({ type: \"markdown\", value: svgBlock });\n if (after.trim()) {\n segments.push(...splitContentSegments(after, true));\n }\n return finalizeSegments(segments);\n }\n\n if (closeIdx === -1) {\n return finalizeSegments([{ type: \"markdown\", value: svgBlock }]);\n }\n }\n\n const tableBlock = extractTableBlock(raw);\n if (tableBlock) {\n const segments: RenderSegment[] = [];\n const before = raw.slice(0, tableBlock.start);\n if (keepText && before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n segments.push({ type: \"markdown\", value: tableBlock.block });\n const after = raw.slice(tableBlock.end);\n const hasProgress = after.length < raw.length;\n if (after.trim() && hasProgress) {\n segments.push(\n ...(keepText\n ? splitContentSegments(after, true)\n : splitContentSegments(after))\n );\n }\n return finalizeSegments(segments);\n }\n\n const inlineMatch = findInlineSandboxMatch(raw);\n const markdownImageMatch = findMarkdownImageMatch(raw, fenceRanges);\n const inlineCandidate =\n inlineMatch && markdownImageMatch\n ? inlineMatch.start <= markdownImageMatch.start\n ? inlineMatch\n : markdownImageMatch\n : (inlineMatch ?? markdownImageMatch);\n\n if (sandboxStartIndex === -1 && !inlineCandidate) {\n if (keepText && raw.trim()) {\n return finalizeSegments([{ type: \"text\", value: raw }]);\n }\n return [];\n }\n\n const shouldUseInline =\n !!inlineCandidate &&\n (sandboxStartIndex === -1 || inlineCandidate.start < sandboxStartIndex);\n\n const startIndex = shouldUseInline\n ? inlineCandidate!.start\n : sandboxStartIndex;\n const blockEnd = shouldUseInline\n ? inlineCandidate!.end\n : findHtmlBlockEnd(raw, startIndex);\n\n const segments: RenderSegment[] = [];\n const before = raw.slice(0, startIndex);\n const matchedBlock = raw.slice(startIndex, blockEnd);\n const after = raw.slice(blockEnd);\n\n if (keepText && before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n\n segments.push({\n type: shouldUseInline ? \"markdown\" : \"sandbox\",\n value: matchedBlock,\n });\n\n if (after.trim()) {\n segments.push(...splitContentSegments(after, keepText));\n }\n\n return finalizeSegments(segments);\n};\n"],"names":["SANDBOX_START_PATTERN","INLINE_SANDBOX_PATTERNS","MARKDOWN_IMAGE_PATTERN","closingBoundary","CUSTOM_BUTTON_PATTERN","getFenceRanges","raw","ranges","fencePattern","match","start","closeMatch","isIndexInRanges","index","end","findFirstMatchOutsideFence","pattern","fenceRanges","flags","matcher","findHtmlBlockEnd","startIndex","blockEnd","splitCustomButtonsFromSandbox","segments","output","segment","lastIndex","before","rest","findInlineSandboxMatch","earliest","findMarkdownImageMatch","extractTableBlock","tableMatch","leadingSpaces","tableStart","lines","tableLines","line","block","splitContentSegments","keepText","finalizeSegments","fenceStart","sandboxStartIndex","svgOpenIndex","hasSandboxBeforeSvg","closeIdx","svgBlock","after","tableBlock","hasProgress","inlineMatch","markdownImageMatch","inlineCandidate","shouldUseInline","matchedBlock"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"split-content.cjs.js","sources":["../../../../src/components/ContentRender/utils/split-content.ts"],"sourcesContent":["export type RenderSegment =\n | { type: \"markdown\"; value: string }\n | { type: \"sandbox\"; value: string }\n | { type: \"text\"; value: string };\n\nconst SANDBOX_START_PATTERN =\n /<(script|style|link|iframe|html|head|body|meta|title|base|template|div|section|article|main)[\\s>]/i;\n\nconst INLINE_SANDBOX_PATTERNS: RegExp[] = [\n /<svg[\\s\\S]*?<\\/svg>/i,\n /<img\\b[^>]*?>/i,\n /```mermaid[\\s\\S]*?```/i,\n /```[a-zA-Z0-9]+[\\s\\S]*?```/i,\n];\nconst MARKDOWN_IMAGE_PATTERN = /!\\[[^\\]]*]\\([^\\s)\\n]+(?:\\s+\"[^\"]*\")?\\)/i;\nconst MARKDOWN_HEADING_PATTERN = /^(?: {0,3})#{1,6}[ \\t]+[^\\n]+$/m;\nconst MARKDOWN_VIDEO_IFRAME_PATTERN =\n /<iframe\\b[^>]*\\bdata-tag\\s*=\\s*([\"'])video\\1[^>]*>[\\s\\S]*?<\\/iframe>/i;\n\nconst closingBoundary = /<\\/[a-z][^>]*>\\s*\\n(?=[^\\s<])/gi;\nconst CUSTOM_BUTTON_PATTERN =\n /<custom-button-after-content\\b[\\s\\S]*?<\\/custom-button-after-content>/gi;\n\ntype MatchResult = { start: number; end: number };\ntype FenceRange = { start: number; end: number };\n\nconst getFenceRanges = (raw: string): FenceRange[] => {\n const ranges: FenceRange[] = [];\n const fencePattern = /```/g;\n let match: RegExpExecArray | null;\n\n while ((match = fencePattern.exec(raw)) !== null) {\n const start = match.index;\n const closeMatch = fencePattern.exec(raw);\n if (!closeMatch) {\n ranges.push({ start, end: raw.length });\n break;\n }\n ranges.push({ start, end: closeMatch.index + 3 });\n }\n\n return ranges;\n};\n\nconst isIndexInRanges = (index: number, ranges: FenceRange[]) =>\n ranges.some(({ start, end }) => index >= start && index < end);\n\nconst findFirstMatchOutsideFence = (\n raw: string,\n pattern: RegExp,\n fenceRanges: FenceRange[]\n) => {\n const flags = pattern.flags.includes(\"g\")\n ? pattern.flags\n : `${pattern.flags}g`;\n const matcher = new RegExp(pattern.source, flags);\n let match: RegExpExecArray | null;\n\n while ((match = matcher.exec(raw)) !== null) {\n if (!isIndexInRanges(match.index, fenceRanges)) {\n return match.index;\n }\n }\n\n return -1;\n};\n\nconst findHtmlBlockEnd = (raw: string, startIndex: number) => {\n let blockEnd = raw.length;\n let match: RegExpExecArray | null;\n closingBoundary.lastIndex = 0;\n\n while ((match = closingBoundary.exec(raw))) {\n if (match.index <= startIndex) continue;\n blockEnd = match.index + match[0].length;\n break;\n }\n\n return blockEnd;\n};\n\nconst splitCustomButtonsFromSandbox = (segments: RenderSegment[]) => {\n if (!segments.length) return segments;\n const output: RenderSegment[] = [];\n\n segments.forEach((segment) => {\n if (segment.type !== \"sandbox\") {\n output.push(segment);\n return;\n }\n\n CUSTOM_BUTTON_PATTERN.lastIndex = 0;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = CUSTOM_BUTTON_PATTERN.exec(segment.value)) !== null) {\n const before = segment.value.slice(lastIndex, match.index);\n if (before.trim()) {\n output.push({ type: \"sandbox\", value: before });\n }\n output.push({ type: \"markdown\", value: match[0] });\n lastIndex = match.index + match[0].length;\n }\n\n const rest = segment.value.slice(lastIndex);\n if (rest.trim()) {\n output.push({ type: \"sandbox\", value: rest });\n }\n });\n\n return output;\n};\n\nconst findInlineSandboxMatch = (raw: string): MatchResult | null => {\n let earliest: MatchResult | null = null;\n\n INLINE_SANDBOX_PATTERNS.forEach((pattern) => {\n const match = pattern.exec(raw);\n if (!match || typeof match.index !== \"number\") return;\n const start = match.index;\n const end = match.index + match[0].length;\n\n if (!earliest || start < earliest.start) {\n earliest = { start, end };\n }\n });\n\n return earliest;\n};\n\nconst pickEarliestMatch = (...matches: Array<MatchResult | null>) =>\n matches.reduce<MatchResult | null>((earliest, match) => {\n if (!match) return earliest;\n if (!earliest || match.start < earliest.start) return match;\n return earliest;\n }, null);\n\nconst findMarkdownImageMatch = (\n raw: string,\n fenceRanges: FenceRange[]\n): MatchResult | null => {\n const start = findFirstMatchOutsideFence(\n raw,\n MARKDOWN_IMAGE_PATTERN,\n fenceRanges\n );\n\n if (start === -1) return null;\n const match = raw.slice(start).match(MARKDOWN_IMAGE_PATTERN);\n if (!match) return null;\n\n return { start, end: start + match[0].length };\n};\n\nconst findMarkdownHeadingMatch = (\n raw: string,\n fenceRanges: FenceRange[]\n): MatchResult | null => {\n const start = findFirstMatchOutsideFence(\n raw,\n MARKDOWN_HEADING_PATTERN,\n fenceRanges\n );\n\n if (start === -1) return null;\n const match = raw.slice(start).match(MARKDOWN_HEADING_PATTERN);\n if (!match) return null;\n\n return { start, end: start + match[0].length };\n};\n\nconst findMarkdownVideoIframeMatch = (\n raw: string,\n fenceRanges: FenceRange[]\n): MatchResult | null => {\n const start = findFirstMatchOutsideFence(\n raw,\n MARKDOWN_VIDEO_IFRAME_PATTERN,\n fenceRanges\n );\n\n if (start === -1) return null;\n const match = raw.slice(start).match(MARKDOWN_VIDEO_IFRAME_PATTERN);\n if (!match) return null;\n\n return { start, end: start + match[0].length };\n};\n\nconst isIndexInsideMarkdownTableLine = (raw: string, index: number) => {\n const lineStart = raw.lastIndexOf(\"\\n\", index - 1) + 1;\n const lineEnd = raw.indexOf(\"\\n\", index);\n const end = lineEnd === -1 ? raw.length : lineEnd;\n const line = raw.slice(lineStart, end).trimStart();\n return line.startsWith(\"|\");\n};\n\nconst extractTableBlock = (\n raw: string\n): { start: number; block: string; end: number } | null => {\n const tableMatch = raw.match(/^\\s*\\|.+\\|\\s*$/m);\n if (!tableMatch || typeof tableMatch.index !== \"number\") return null;\n\n const leadingSpaces = tableMatch[0].match(/^\\s*/)?.[0].length ?? 0;\n const tableStart = tableMatch.index + leadingSpaces;\n\n const lines = raw.slice(tableStart).split(\"\\n\");\n const tableLines: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"|\")) break;\n tableLines.push(line);\n }\n\n const block = tableLines.join(\"\\n\");\n return { start: tableStart, block, end: tableStart + block.length };\n};\n\n// Split incoming markdown content into markdown and sandbox HTML segments\nexport const splitContentSegments = (\n raw: string,\n keepText = true\n): RenderSegment[] => {\n const finalizeSegments = (segments: RenderSegment[]) =>\n splitCustomButtonsFromSandbox(segments);\n\n const fenceStart = raw.indexOf(\"```\");\n if (keepText && fenceStart !== -1) {\n const closingFence = raw.indexOf(\"```\", fenceStart + 3);\n if (closingFence === -1) {\n return finalizeSegments([{ type: \"markdown\", value: raw }]);\n }\n }\n\n const fenceRanges = getFenceRanges(raw);\n // Avoid treating fenced code blocks as sandbox content.\n const sandboxStartIndex = findFirstMatchOutsideFence(\n raw,\n SANDBOX_START_PATTERN,\n fenceRanges\n );\n const svgOpenIndex = findFirstMatchOutsideFence(raw, /<svg\\b/i, fenceRanges);\n const svgInTableLine =\n svgOpenIndex !== -1 && isIndexInsideMarkdownTableLine(raw, svgOpenIndex);\n const hasSandboxBeforeSvg =\n sandboxStartIndex !== -1 &&\n svgOpenIndex !== -1 &&\n sandboxStartIndex < svgOpenIndex;\n if (svgOpenIndex !== -1 && !hasSandboxBeforeSvg && !svgInTableLine) {\n const before = raw.slice(0, svgOpenIndex);\n const closeIdx = raw.indexOf(\"</svg>\", svgOpenIndex);\n const svgBlock =\n closeIdx === -1\n ? `${raw.slice(svgOpenIndex)}</svg>`\n : raw.slice(svgOpenIndex, closeIdx + \"</svg>\".length);\n const after = closeIdx === -1 ? \"\" : raw.slice(closeIdx + \"</svg>\".length);\n\n if (keepText) {\n const segments: RenderSegment[] = [];\n if (before.trim()) {\n // Keep splitting the prefix so headings and other markdown markers\n // become their own segments instead of one large text block.\n segments.push(...splitContentSegments(before, true));\n }\n segments.push({ type: \"markdown\", value: svgBlock });\n if (after.trim()) {\n segments.push(...splitContentSegments(after, true));\n }\n return finalizeSegments(segments);\n }\n\n if (closeIdx === -1) {\n return finalizeSegments([{ type: \"markdown\", value: svgBlock }]);\n }\n }\n\n const tableBlock = extractTableBlock(raw);\n const markdownHeadingMatch = findMarkdownHeadingMatch(raw, fenceRanges);\n const shouldProcessTableBlock =\n !!tableBlock &&\n (!markdownHeadingMatch || tableBlock.start < markdownHeadingMatch.start);\n if (tableBlock && shouldProcessTableBlock) {\n const segments: RenderSegment[] = [];\n const before = raw.slice(0, tableBlock.start);\n if (keepText && before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n segments.push({ type: \"markdown\", value: tableBlock.block });\n const after = raw.slice(tableBlock.end);\n const hasProgress = after.length < raw.length;\n if (after.trim() && hasProgress) {\n segments.push(\n ...(keepText\n ? splitContentSegments(after, true)\n : splitContentSegments(after))\n );\n }\n return finalizeSegments(segments);\n }\n\n const inlineMatch = findInlineSandboxMatch(raw);\n const markdownImageMatch = findMarkdownImageMatch(raw, fenceRanges);\n const markdownVideoIframeMatch = findMarkdownVideoIframeMatch(\n raw,\n fenceRanges\n );\n const inlineCandidate = pickEarliestMatch(\n inlineMatch,\n markdownImageMatch,\n markdownHeadingMatch,\n markdownVideoIframeMatch\n );\n\n if (sandboxStartIndex === -1 && !inlineCandidate) {\n if (keepText && raw.trim()) {\n return finalizeSegments([{ type: \"text\", value: raw }]);\n }\n return [];\n }\n\n const shouldUseInline =\n !!inlineCandidate &&\n (sandboxStartIndex === -1 || inlineCandidate.start <= sandboxStartIndex);\n\n const startIndex = shouldUseInline\n ? inlineCandidate!.start\n : sandboxStartIndex;\n const blockEnd = shouldUseInline\n ? inlineCandidate!.end\n : findHtmlBlockEnd(raw, startIndex);\n\n const segments: RenderSegment[] = [];\n const before = raw.slice(0, startIndex);\n const matchedBlock = raw.slice(startIndex, blockEnd);\n const after = raw.slice(blockEnd);\n\n if (keepText && before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n\n segments.push({\n type: shouldUseInline ? \"markdown\" : \"sandbox\",\n value: matchedBlock,\n });\n\n if (after.trim()) {\n segments.push(...splitContentSegments(after, keepText));\n }\n\n return finalizeSegments(segments);\n};\n"],"names":["SANDBOX_START_PATTERN","INLINE_SANDBOX_PATTERNS","MARKDOWN_IMAGE_PATTERN","MARKDOWN_HEADING_PATTERN","MARKDOWN_VIDEO_IFRAME_PATTERN","closingBoundary","CUSTOM_BUTTON_PATTERN","getFenceRanges","raw","ranges","fencePattern","match","start","closeMatch","isIndexInRanges","index","end","findFirstMatchOutsideFence","pattern","fenceRanges","flags","matcher","findHtmlBlockEnd","startIndex","blockEnd","splitCustomButtonsFromSandbox","segments","output","segment","lastIndex","before","rest","findInlineSandboxMatch","earliest","pickEarliestMatch","matches","findMarkdownImageMatch","findMarkdownHeadingMatch","findMarkdownVideoIframeMatch","isIndexInsideMarkdownTableLine","lineStart","lineEnd","extractTableBlock","tableMatch","leadingSpaces","tableStart","lines","tableLines","line","block","splitContentSegments","keepText","finalizeSegments","fenceStart","sandboxStartIndex","svgOpenIndex","svgInTableLine","hasSandboxBeforeSvg","closeIdx","svgBlock","after","tableBlock","markdownHeadingMatch","shouldProcessTableBlock","hasProgress","inlineMatch","markdownImageMatch","markdownVideoIframeMatch","inlineCandidate","shouldUseInline","matchedBlock"],"mappings":"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"}
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
const
|
|
1
|
+
const F = /<(script|style|link|iframe|html|head|body|meta|title|base|template|div|section|article|main)[\s>]/i, W = [
|
|
2
2
|
/<svg[\s\S]*?<\/svg>/i,
|
|
3
3
|
/<img\b[^>]*?>/i,
|
|
4
4
|
/```mermaid[\s\S]*?```/i,
|
|
5
5
|
/```[a-zA-Z0-9]+[\s\S]*?```/i
|
|
6
|
-
],
|
|
6
|
+
], y = /!\[[^\]]*]\([^\s)\n]+(?:\s+"[^"]*")?\)/i, A = /^(?: {0,3})#{1,6}[ \t]+[^\n]+$/m, N = /<iframe\b[^>]*\bdata-tag\s*=\s*(["'])video\1[^>]*>[\s\S]*?<\/iframe>/i, O = /<\/[a-z][^>]*>\s*\n(?=[^\s<])/gi, R = /<custom-button-after-content\b[\s\S]*?<\/custom-button-after-content>/gi, C = (t) => {
|
|
7
7
|
const n = [], e = /```/g;
|
|
8
8
|
let s;
|
|
9
9
|
for (; (s = e.exec(t)) !== null; ) {
|
|
10
|
-
const
|
|
11
|
-
if (!
|
|
12
|
-
n.push({ start:
|
|
10
|
+
const c = s.index, o = e.exec(t);
|
|
11
|
+
if (!o) {
|
|
12
|
+
n.push({ start: c, end: t.length });
|
|
13
13
|
break;
|
|
14
14
|
}
|
|
15
|
-
n.push({ start:
|
|
15
|
+
n.push({ start: c, end: o.index + 3 });
|
|
16
16
|
}
|
|
17
17
|
return n;
|
|
18
|
-
},
|
|
19
|
-
const s = n.flags.includes("g") ? n.flags : `${n.flags}g`,
|
|
20
|
-
let
|
|
21
|
-
for (; (
|
|
22
|
-
if (!
|
|
23
|
-
return
|
|
18
|
+
}, H = (t, n) => n.some(({ start: e, end: s }) => t >= e && t < s), h = (t, n, e) => {
|
|
19
|
+
const s = n.flags.includes("g") ? n.flags : `${n.flags}g`, c = new RegExp(n.source, s);
|
|
20
|
+
let o;
|
|
21
|
+
for (; (o = c.exec(t)) !== null; )
|
|
22
|
+
if (!H(o.index, e))
|
|
23
|
+
return o.index;
|
|
24
24
|
return -1;
|
|
25
|
-
},
|
|
25
|
+
}, L = (t, n) => {
|
|
26
26
|
let e = t.length, s;
|
|
27
|
-
for (
|
|
27
|
+
for (O.lastIndex = 0; s = O.exec(t); )
|
|
28
28
|
if (!(s.index <= n)) {
|
|
29
29
|
e = s.index + s[0].length;
|
|
30
30
|
break;
|
|
31
31
|
}
|
|
32
32
|
return e;
|
|
33
|
-
},
|
|
33
|
+
}, $ = (t) => {
|
|
34
34
|
if (!t.length) return t;
|
|
35
35
|
const n = [];
|
|
36
36
|
return t.forEach((e) => {
|
|
@@ -38,81 +38,112 @@ const O = /<(script|style|link|iframe|html|head|body|meta|title|base|template|di
|
|
|
38
38
|
n.push(e);
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
let s = 0,
|
|
43
|
-
for (; (
|
|
44
|
-
const i = e.value.slice(s,
|
|
45
|
-
i.trim() && n.push({ type: "sandbox", value: i }), n.push({ type: "markdown", value:
|
|
41
|
+
R.lastIndex = 0;
|
|
42
|
+
let s = 0, c;
|
|
43
|
+
for (; (c = R.exec(e.value)) !== null; ) {
|
|
44
|
+
const i = e.value.slice(s, c.index);
|
|
45
|
+
i.trim() && n.push({ type: "sandbox", value: i }), n.push({ type: "markdown", value: c[0] }), s = c.index + c[0].length;
|
|
46
46
|
}
|
|
47
|
-
const
|
|
48
|
-
|
|
47
|
+
const o = e.value.slice(s);
|
|
48
|
+
o.trim() && n.push({ type: "sandbox", value: o });
|
|
49
49
|
}), n;
|
|
50
|
-
},
|
|
50
|
+
}, z = (t) => {
|
|
51
51
|
let n = null;
|
|
52
|
-
return
|
|
52
|
+
return W.forEach((e) => {
|
|
53
53
|
const s = e.exec(t);
|
|
54
54
|
if (!s || typeof s.index != "number") return;
|
|
55
|
-
const
|
|
56
|
-
(!n ||
|
|
55
|
+
const c = s.index, o = s.index + s[0].length;
|
|
56
|
+
(!n || c < n.start) && (n = { start: c, end: o });
|
|
57
57
|
}), n;
|
|
58
|
-
},
|
|
59
|
-
const e =
|
|
58
|
+
}, K = (...t) => t.reduce((n, e) => e && (!n || e.start < n.start) ? e : n, null), U = (t, n) => {
|
|
59
|
+
const e = h(
|
|
60
60
|
t,
|
|
61
|
-
|
|
61
|
+
y,
|
|
62
|
+
n
|
|
63
|
+
);
|
|
64
|
+
if (e === -1) return null;
|
|
65
|
+
const s = t.slice(e).match(y);
|
|
66
|
+
return s ? { start: e, end: e + s[0].length } : null;
|
|
67
|
+
}, V = (t, n) => {
|
|
68
|
+
const e = h(
|
|
69
|
+
t,
|
|
70
|
+
A,
|
|
71
|
+
n
|
|
72
|
+
);
|
|
73
|
+
if (e === -1) return null;
|
|
74
|
+
const s = t.slice(e).match(A);
|
|
75
|
+
return s ? { start: e, end: e + s[0].length } : null;
|
|
76
|
+
}, G = (t, n) => {
|
|
77
|
+
const e = h(
|
|
78
|
+
t,
|
|
79
|
+
N,
|
|
62
80
|
n
|
|
63
81
|
);
|
|
64
82
|
if (e === -1) return null;
|
|
65
|
-
const s = t.slice(e).match(
|
|
83
|
+
const s = t.slice(e).match(N);
|
|
66
84
|
return s ? { start: e, end: e + s[0].length } : null;
|
|
67
|
-
},
|
|
85
|
+
}, X = (t, n) => {
|
|
86
|
+
const e = t.lastIndexOf(`
|
|
87
|
+
`, n - 1) + 1, s = t.indexOf(`
|
|
88
|
+
`, n), c = s === -1 ? t.length : s;
|
|
89
|
+
return t.slice(e, c).trimStart().startsWith("|");
|
|
90
|
+
}, j = (t) => {
|
|
68
91
|
const n = t.match(/^\s*\|.+\|\s*$/m);
|
|
69
92
|
if (!n || typeof n.index != "number") return null;
|
|
70
|
-
const e = n[0].match(/^\s*/)?.[0].length ?? 0, s = n.index + e,
|
|
71
|
-
`),
|
|
72
|
-
for (const
|
|
73
|
-
if (!
|
|
74
|
-
|
|
93
|
+
const e = n[0].match(/^\s*/)?.[0].length ?? 0, s = n.index + e, c = t.slice(s).split(`
|
|
94
|
+
`), o = [];
|
|
95
|
+
for (const m of c) {
|
|
96
|
+
if (!m.trim().startsWith("|")) break;
|
|
97
|
+
o.push(m);
|
|
75
98
|
}
|
|
76
|
-
const i =
|
|
99
|
+
const i = o.join(`
|
|
77
100
|
`);
|
|
78
101
|
return { start: s, block: i, end: s + i.length };
|
|
79
|
-
},
|
|
80
|
-
const e = (l) =>
|
|
102
|
+
}, f = (t, n = !0) => {
|
|
103
|
+
const e = (l) => $(l), s = t.indexOf("```");
|
|
81
104
|
if (n && s !== -1 && t.indexOf("```", s + 3) === -1)
|
|
82
105
|
return e([{ type: "markdown", value: t }]);
|
|
83
|
-
const
|
|
106
|
+
const c = C(t), o = h(
|
|
84
107
|
t,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
), i =
|
|
88
|
-
if (i !== -1 && !
|
|
89
|
-
const l = t.slice(0, i),
|
|
108
|
+
F,
|
|
109
|
+
c
|
|
110
|
+
), i = h(t, /<svg\b/i, c), m = i !== -1 && X(t, i), k = o !== -1 && i !== -1 && o < i;
|
|
111
|
+
if (i !== -1 && !k && !m) {
|
|
112
|
+
const l = t.slice(0, i), r = t.indexOf("</svg>", i), a = r === -1 ? `${t.slice(i)}</svg>` : t.slice(i, r + 6), x = r === -1 ? "" : t.slice(r + 6);
|
|
90
113
|
if (n) {
|
|
91
114
|
const b = [];
|
|
92
|
-
return l.trim() && b.push(
|
|
115
|
+
return l.trim() && b.push(...f(l, !0)), b.push({ type: "markdown", value: a }), x.trim() && b.push(...f(x, !0)), e(b);
|
|
93
116
|
}
|
|
94
|
-
if (
|
|
95
|
-
return e([{ type: "markdown", value:
|
|
117
|
+
if (r === -1)
|
|
118
|
+
return e([{ type: "markdown", value: a }]);
|
|
96
119
|
}
|
|
97
|
-
const u =
|
|
98
|
-
if (u) {
|
|
99
|
-
const l = [],
|
|
100
|
-
n &&
|
|
101
|
-
const
|
|
102
|
-
return
|
|
103
|
-
...n ?
|
|
120
|
+
const u = j(t), p = V(t, c), T = !!u && (!p || u.start < p.start);
|
|
121
|
+
if (u && T) {
|
|
122
|
+
const l = [], r = t.slice(0, u.start);
|
|
123
|
+
n && r.trim() && l.push({ type: "text", value: r }), l.push({ type: "markdown", value: u.block });
|
|
124
|
+
const a = t.slice(u.end), x = a.length < t.length;
|
|
125
|
+
return a.trim() && x && l.push(
|
|
126
|
+
...n ? f(a, !0) : f(a)
|
|
104
127
|
), e(l);
|
|
105
128
|
}
|
|
106
|
-
const
|
|
107
|
-
|
|
129
|
+
const _ = z(t), B = U(t, c), P = G(
|
|
130
|
+
t,
|
|
131
|
+
c
|
|
132
|
+
), d = K(
|
|
133
|
+
_,
|
|
134
|
+
B,
|
|
135
|
+
p,
|
|
136
|
+
P
|
|
137
|
+
);
|
|
138
|
+
if (o === -1 && !d)
|
|
108
139
|
return n && t.trim() ? e([{ type: "text", value: t }]) : [];
|
|
109
|
-
const v = !!d && (
|
|
110
|
-
return n &&
|
|
140
|
+
const v = !!d && (o === -1 || d.start <= o), I = v ? d.start : o, M = v ? d.end : L(t, I), g = [], S = t.slice(0, I), D = t.slice(I, M), E = t.slice(M);
|
|
141
|
+
return n && S.trim() && g.push({ type: "text", value: S }), g.push({
|
|
111
142
|
type: v ? "markdown" : "sandbox",
|
|
112
|
-
value:
|
|
113
|
-
}), E.trim() && g.push(...
|
|
143
|
+
value: D
|
|
144
|
+
}), E.trim() && g.push(...f(E, n)), e(g);
|
|
114
145
|
};
|
|
115
146
|
export {
|
|
116
|
-
|
|
147
|
+
f as splitContentSegments
|
|
117
148
|
};
|
|
118
149
|
//# sourceMappingURL=split-content.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split-content.es.js","sources":["../../../../src/components/ContentRender/utils/split-content.ts"],"sourcesContent":["export type RenderSegment =\n | { type: \"markdown\"; value: string }\n | { type: \"sandbox\"; value: string }\n | { type: \"text\"; value: string };\n\nconst SANDBOX_START_PATTERN =\n /<(script|style|link|iframe|html|head|body|meta|title|base|template|div|section|article|main)[\\s>]/i;\n\nconst INLINE_SANDBOX_PATTERNS: RegExp[] = [\n /<svg[\\s\\S]*?<\\/svg>/i,\n /<img\\b[^>]*?>/i,\n /```mermaid[\\s\\S]*?```/i,\n /```[a-zA-Z0-9]+[\\s\\S]*?```/i,\n];\nconst MARKDOWN_IMAGE_PATTERN = /!\\[[^\\]]*]\\([^\\s)\\n]+(?:\\s+\"[^\"]*\")?\\)/i;\n\nconst closingBoundary = /<\\/[a-z][^>]*>\\s*\\n(?=[^\\s<])/gi;\nconst CUSTOM_BUTTON_PATTERN =\n /<custom-button-after-content\\b[\\s\\S]*?<\\/custom-button-after-content>/gi;\n\ntype MatchResult = { start: number; end: number };\ntype FenceRange = { start: number; end: number };\n\nconst getFenceRanges = (raw: string): FenceRange[] => {\n const ranges: FenceRange[] = [];\n const fencePattern = /```/g;\n let match: RegExpExecArray | null;\n\n while ((match = fencePattern.exec(raw)) !== null) {\n const start = match.index;\n const closeMatch = fencePattern.exec(raw);\n if (!closeMatch) {\n ranges.push({ start, end: raw.length });\n break;\n }\n ranges.push({ start, end: closeMatch.index + 3 });\n }\n\n return ranges;\n};\n\nconst isIndexInRanges = (index: number, ranges: FenceRange[]) =>\n ranges.some(({ start, end }) => index >= start && index < end);\n\nconst findFirstMatchOutsideFence = (\n raw: string,\n pattern: RegExp,\n fenceRanges: FenceRange[]\n) => {\n const flags = pattern.flags.includes(\"g\")\n ? pattern.flags\n : `${pattern.flags}g`;\n const matcher = new RegExp(pattern.source, flags);\n let match: RegExpExecArray | null;\n\n while ((match = matcher.exec(raw)) !== null) {\n if (!isIndexInRanges(match.index, fenceRanges)) {\n return match.index;\n }\n }\n\n return -1;\n};\n\nconst findHtmlBlockEnd = (raw: string, startIndex: number) => {\n let blockEnd = raw.length;\n let match: RegExpExecArray | null;\n closingBoundary.lastIndex = 0;\n\n while ((match = closingBoundary.exec(raw))) {\n if (match.index <= startIndex) continue;\n blockEnd = match.index + match[0].length;\n break;\n }\n\n return blockEnd;\n};\n\nconst splitCustomButtonsFromSandbox = (segments: RenderSegment[]) => {\n if (!segments.length) return segments;\n const output: RenderSegment[] = [];\n\n segments.forEach((segment) => {\n if (segment.type !== \"sandbox\") {\n output.push(segment);\n return;\n }\n\n CUSTOM_BUTTON_PATTERN.lastIndex = 0;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = CUSTOM_BUTTON_PATTERN.exec(segment.value)) !== null) {\n const before = segment.value.slice(lastIndex, match.index);\n if (before.trim()) {\n output.push({ type: \"sandbox\", value: before });\n }\n output.push({ type: \"markdown\", value: match[0] });\n lastIndex = match.index + match[0].length;\n }\n\n const rest = segment.value.slice(lastIndex);\n if (rest.trim()) {\n output.push({ type: \"sandbox\", value: rest });\n }\n });\n\n return output;\n};\n\nconst findInlineSandboxMatch = (raw: string): MatchResult | null => {\n let earliest: MatchResult | null = null;\n\n INLINE_SANDBOX_PATTERNS.forEach((pattern) => {\n const match = pattern.exec(raw);\n if (!match || typeof match.index !== \"number\") return;\n const start = match.index;\n const end = match.index + match[0].length;\n\n if (!earliest || start < earliest.start) {\n earliest = { start, end };\n }\n });\n\n return earliest;\n};\n\nconst findMarkdownImageMatch = (\n raw: string,\n fenceRanges: FenceRange[]\n): MatchResult | null => {\n const start = findFirstMatchOutsideFence(\n raw,\n MARKDOWN_IMAGE_PATTERN,\n fenceRanges\n );\n\n if (start === -1) return null;\n const match = raw.slice(start).match(MARKDOWN_IMAGE_PATTERN);\n if (!match) return null;\n\n return { start, end: start + match[0].length };\n};\n\nconst extractTableBlock = (\n raw: string\n): { start: number; block: string; end: number } | null => {\n const tableMatch = raw.match(/^\\s*\\|.+\\|\\s*$/m);\n if (!tableMatch || typeof tableMatch.index !== \"number\") return null;\n\n const leadingSpaces = tableMatch[0].match(/^\\s*/)?.[0].length ?? 0;\n const tableStart = tableMatch.index + leadingSpaces;\n\n const lines = raw.slice(tableStart).split(\"\\n\");\n const tableLines: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"|\")) break;\n tableLines.push(line);\n }\n\n const block = tableLines.join(\"\\n\");\n return { start: tableStart, block, end: tableStart + block.length };\n};\n\n// Split incoming markdown content into markdown and sandbox HTML segments\nexport const splitContentSegments = (\n raw: string,\n keepText = false\n): RenderSegment[] => {\n const finalizeSegments = (segments: RenderSegment[]) =>\n splitCustomButtonsFromSandbox(segments);\n\n const fenceStart = raw.indexOf(\"```\");\n if (keepText && fenceStart !== -1) {\n const closingFence = raw.indexOf(\"```\", fenceStart + 3);\n if (closingFence === -1) {\n return finalizeSegments([{ type: \"markdown\", value: raw }]);\n }\n }\n\n const fenceRanges = getFenceRanges(raw);\n // Avoid treating fenced code blocks as sandbox content.\n const sandboxStartIndex = findFirstMatchOutsideFence(\n raw,\n SANDBOX_START_PATTERN,\n fenceRanges\n );\n const svgOpenIndex = findFirstMatchOutsideFence(raw, /<svg\\b/i, fenceRanges);\n const hasSandboxBeforeSvg =\n sandboxStartIndex !== -1 &&\n svgOpenIndex !== -1 &&\n sandboxStartIndex < svgOpenIndex;\n if (svgOpenIndex !== -1 && !hasSandboxBeforeSvg) {\n const before = raw.slice(0, svgOpenIndex);\n const closeIdx = raw.indexOf(\"</svg>\", svgOpenIndex);\n const svgBlock =\n closeIdx === -1\n ? `${raw.slice(svgOpenIndex)}</svg>`\n : raw.slice(svgOpenIndex, closeIdx + \"</svg>\".length);\n const after = closeIdx === -1 ? \"\" : raw.slice(closeIdx + \"</svg>\".length);\n\n if (keepText) {\n const segments: RenderSegment[] = [];\n if (before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n segments.push({ type: \"markdown\", value: svgBlock });\n if (after.trim()) {\n segments.push(...splitContentSegments(after, true));\n }\n return finalizeSegments(segments);\n }\n\n if (closeIdx === -1) {\n return finalizeSegments([{ type: \"markdown\", value: svgBlock }]);\n }\n }\n\n const tableBlock = extractTableBlock(raw);\n if (tableBlock) {\n const segments: RenderSegment[] = [];\n const before = raw.slice(0, tableBlock.start);\n if (keepText && before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n segments.push({ type: \"markdown\", value: tableBlock.block });\n const after = raw.slice(tableBlock.end);\n const hasProgress = after.length < raw.length;\n if (after.trim() && hasProgress) {\n segments.push(\n ...(keepText\n ? splitContentSegments(after, true)\n : splitContentSegments(after))\n );\n }\n return finalizeSegments(segments);\n }\n\n const inlineMatch = findInlineSandboxMatch(raw);\n const markdownImageMatch = findMarkdownImageMatch(raw, fenceRanges);\n const inlineCandidate =\n inlineMatch && markdownImageMatch\n ? inlineMatch.start <= markdownImageMatch.start\n ? inlineMatch\n : markdownImageMatch\n : (inlineMatch ?? markdownImageMatch);\n\n if (sandboxStartIndex === -1 && !inlineCandidate) {\n if (keepText && raw.trim()) {\n return finalizeSegments([{ type: \"text\", value: raw }]);\n }\n return [];\n }\n\n const shouldUseInline =\n !!inlineCandidate &&\n (sandboxStartIndex === -1 || inlineCandidate.start < sandboxStartIndex);\n\n const startIndex = shouldUseInline\n ? inlineCandidate!.start\n : sandboxStartIndex;\n const blockEnd = shouldUseInline\n ? inlineCandidate!.end\n : findHtmlBlockEnd(raw, startIndex);\n\n const segments: RenderSegment[] = [];\n const before = raw.slice(0, startIndex);\n const matchedBlock = raw.slice(startIndex, blockEnd);\n const after = raw.slice(blockEnd);\n\n if (keepText && before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n\n segments.push({\n type: shouldUseInline ? \"markdown\" : \"sandbox\",\n value: matchedBlock,\n });\n\n if (after.trim()) {\n segments.push(...splitContentSegments(after, keepText));\n }\n\n return finalizeSegments(segments);\n};\n"],"names":["SANDBOX_START_PATTERN","INLINE_SANDBOX_PATTERNS","MARKDOWN_IMAGE_PATTERN","closingBoundary","CUSTOM_BUTTON_PATTERN","getFenceRanges","raw","ranges","fencePattern","match","start","closeMatch","isIndexInRanges","index","end","findFirstMatchOutsideFence","pattern","fenceRanges","flags","matcher","findHtmlBlockEnd","startIndex","blockEnd","splitCustomButtonsFromSandbox","segments","output","segment","lastIndex","before","rest","findInlineSandboxMatch","earliest","findMarkdownImageMatch","extractTableBlock","tableMatch","leadingSpaces","tableStart","lines","tableLines","line","block","splitContentSegments","keepText","finalizeSegments","fenceStart","sandboxStartIndex","svgOpenIndex","hasSandboxBeforeSvg","closeIdx","svgBlock","after","tableBlock","hasProgress","inlineMatch","markdownImageMatch","inlineCandidate","shouldUseInline","matchedBlock"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"split-content.es.js","sources":["../../../../src/components/ContentRender/utils/split-content.ts"],"sourcesContent":["export type RenderSegment =\n | { type: \"markdown\"; value: string }\n | { type: \"sandbox\"; value: string }\n | { type: \"text\"; value: string };\n\nconst SANDBOX_START_PATTERN =\n /<(script|style|link|iframe|html|head|body|meta|title|base|template|div|section|article|main)[\\s>]/i;\n\nconst INLINE_SANDBOX_PATTERNS: RegExp[] = [\n /<svg[\\s\\S]*?<\\/svg>/i,\n /<img\\b[^>]*?>/i,\n /```mermaid[\\s\\S]*?```/i,\n /```[a-zA-Z0-9]+[\\s\\S]*?```/i,\n];\nconst MARKDOWN_IMAGE_PATTERN = /!\\[[^\\]]*]\\([^\\s)\\n]+(?:\\s+\"[^\"]*\")?\\)/i;\nconst MARKDOWN_HEADING_PATTERN = /^(?: {0,3})#{1,6}[ \\t]+[^\\n]+$/m;\nconst MARKDOWN_VIDEO_IFRAME_PATTERN =\n /<iframe\\b[^>]*\\bdata-tag\\s*=\\s*([\"'])video\\1[^>]*>[\\s\\S]*?<\\/iframe>/i;\n\nconst closingBoundary = /<\\/[a-z][^>]*>\\s*\\n(?=[^\\s<])/gi;\nconst CUSTOM_BUTTON_PATTERN =\n /<custom-button-after-content\\b[\\s\\S]*?<\\/custom-button-after-content>/gi;\n\ntype MatchResult = { start: number; end: number };\ntype FenceRange = { start: number; end: number };\n\nconst getFenceRanges = (raw: string): FenceRange[] => {\n const ranges: FenceRange[] = [];\n const fencePattern = /```/g;\n let match: RegExpExecArray | null;\n\n while ((match = fencePattern.exec(raw)) !== null) {\n const start = match.index;\n const closeMatch = fencePattern.exec(raw);\n if (!closeMatch) {\n ranges.push({ start, end: raw.length });\n break;\n }\n ranges.push({ start, end: closeMatch.index + 3 });\n }\n\n return ranges;\n};\n\nconst isIndexInRanges = (index: number, ranges: FenceRange[]) =>\n ranges.some(({ start, end }) => index >= start && index < end);\n\nconst findFirstMatchOutsideFence = (\n raw: string,\n pattern: RegExp,\n fenceRanges: FenceRange[]\n) => {\n const flags = pattern.flags.includes(\"g\")\n ? pattern.flags\n : `${pattern.flags}g`;\n const matcher = new RegExp(pattern.source, flags);\n let match: RegExpExecArray | null;\n\n while ((match = matcher.exec(raw)) !== null) {\n if (!isIndexInRanges(match.index, fenceRanges)) {\n return match.index;\n }\n }\n\n return -1;\n};\n\nconst findHtmlBlockEnd = (raw: string, startIndex: number) => {\n let blockEnd = raw.length;\n let match: RegExpExecArray | null;\n closingBoundary.lastIndex = 0;\n\n while ((match = closingBoundary.exec(raw))) {\n if (match.index <= startIndex) continue;\n blockEnd = match.index + match[0].length;\n break;\n }\n\n return blockEnd;\n};\n\nconst splitCustomButtonsFromSandbox = (segments: RenderSegment[]) => {\n if (!segments.length) return segments;\n const output: RenderSegment[] = [];\n\n segments.forEach((segment) => {\n if (segment.type !== \"sandbox\") {\n output.push(segment);\n return;\n }\n\n CUSTOM_BUTTON_PATTERN.lastIndex = 0;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = CUSTOM_BUTTON_PATTERN.exec(segment.value)) !== null) {\n const before = segment.value.slice(lastIndex, match.index);\n if (before.trim()) {\n output.push({ type: \"sandbox\", value: before });\n }\n output.push({ type: \"markdown\", value: match[0] });\n lastIndex = match.index + match[0].length;\n }\n\n const rest = segment.value.slice(lastIndex);\n if (rest.trim()) {\n output.push({ type: \"sandbox\", value: rest });\n }\n });\n\n return output;\n};\n\nconst findInlineSandboxMatch = (raw: string): MatchResult | null => {\n let earliest: MatchResult | null = null;\n\n INLINE_SANDBOX_PATTERNS.forEach((pattern) => {\n const match = pattern.exec(raw);\n if (!match || typeof match.index !== \"number\") return;\n const start = match.index;\n const end = match.index + match[0].length;\n\n if (!earliest || start < earliest.start) {\n earliest = { start, end };\n }\n });\n\n return earliest;\n};\n\nconst pickEarliestMatch = (...matches: Array<MatchResult | null>) =>\n matches.reduce<MatchResult | null>((earliest, match) => {\n if (!match) return earliest;\n if (!earliest || match.start < earliest.start) return match;\n return earliest;\n }, null);\n\nconst findMarkdownImageMatch = (\n raw: string,\n fenceRanges: FenceRange[]\n): MatchResult | null => {\n const start = findFirstMatchOutsideFence(\n raw,\n MARKDOWN_IMAGE_PATTERN,\n fenceRanges\n );\n\n if (start === -1) return null;\n const match = raw.slice(start).match(MARKDOWN_IMAGE_PATTERN);\n if (!match) return null;\n\n return { start, end: start + match[0].length };\n};\n\nconst findMarkdownHeadingMatch = (\n raw: string,\n fenceRanges: FenceRange[]\n): MatchResult | null => {\n const start = findFirstMatchOutsideFence(\n raw,\n MARKDOWN_HEADING_PATTERN,\n fenceRanges\n );\n\n if (start === -1) return null;\n const match = raw.slice(start).match(MARKDOWN_HEADING_PATTERN);\n if (!match) return null;\n\n return { start, end: start + match[0].length };\n};\n\nconst findMarkdownVideoIframeMatch = (\n raw: string,\n fenceRanges: FenceRange[]\n): MatchResult | null => {\n const start = findFirstMatchOutsideFence(\n raw,\n MARKDOWN_VIDEO_IFRAME_PATTERN,\n fenceRanges\n );\n\n if (start === -1) return null;\n const match = raw.slice(start).match(MARKDOWN_VIDEO_IFRAME_PATTERN);\n if (!match) return null;\n\n return { start, end: start + match[0].length };\n};\n\nconst isIndexInsideMarkdownTableLine = (raw: string, index: number) => {\n const lineStart = raw.lastIndexOf(\"\\n\", index - 1) + 1;\n const lineEnd = raw.indexOf(\"\\n\", index);\n const end = lineEnd === -1 ? raw.length : lineEnd;\n const line = raw.slice(lineStart, end).trimStart();\n return line.startsWith(\"|\");\n};\n\nconst extractTableBlock = (\n raw: string\n): { start: number; block: string; end: number } | null => {\n const tableMatch = raw.match(/^\\s*\\|.+\\|\\s*$/m);\n if (!tableMatch || typeof tableMatch.index !== \"number\") return null;\n\n const leadingSpaces = tableMatch[0].match(/^\\s*/)?.[0].length ?? 0;\n const tableStart = tableMatch.index + leadingSpaces;\n\n const lines = raw.slice(tableStart).split(\"\\n\");\n const tableLines: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"|\")) break;\n tableLines.push(line);\n }\n\n const block = tableLines.join(\"\\n\");\n return { start: tableStart, block, end: tableStart + block.length };\n};\n\n// Split incoming markdown content into markdown and sandbox HTML segments\nexport const splitContentSegments = (\n raw: string,\n keepText = true\n): RenderSegment[] => {\n const finalizeSegments = (segments: RenderSegment[]) =>\n splitCustomButtonsFromSandbox(segments);\n\n const fenceStart = raw.indexOf(\"```\");\n if (keepText && fenceStart !== -1) {\n const closingFence = raw.indexOf(\"```\", fenceStart + 3);\n if (closingFence === -1) {\n return finalizeSegments([{ type: \"markdown\", value: raw }]);\n }\n }\n\n const fenceRanges = getFenceRanges(raw);\n // Avoid treating fenced code blocks as sandbox content.\n const sandboxStartIndex = findFirstMatchOutsideFence(\n raw,\n SANDBOX_START_PATTERN,\n fenceRanges\n );\n const svgOpenIndex = findFirstMatchOutsideFence(raw, /<svg\\b/i, fenceRanges);\n const svgInTableLine =\n svgOpenIndex !== -1 && isIndexInsideMarkdownTableLine(raw, svgOpenIndex);\n const hasSandboxBeforeSvg =\n sandboxStartIndex !== -1 &&\n svgOpenIndex !== -1 &&\n sandboxStartIndex < svgOpenIndex;\n if (svgOpenIndex !== -1 && !hasSandboxBeforeSvg && !svgInTableLine) {\n const before = raw.slice(0, svgOpenIndex);\n const closeIdx = raw.indexOf(\"</svg>\", svgOpenIndex);\n const svgBlock =\n closeIdx === -1\n ? `${raw.slice(svgOpenIndex)}</svg>`\n : raw.slice(svgOpenIndex, closeIdx + \"</svg>\".length);\n const after = closeIdx === -1 ? \"\" : raw.slice(closeIdx + \"</svg>\".length);\n\n if (keepText) {\n const segments: RenderSegment[] = [];\n if (before.trim()) {\n // Keep splitting the prefix so headings and other markdown markers\n // become their own segments instead of one large text block.\n segments.push(...splitContentSegments(before, true));\n }\n segments.push({ type: \"markdown\", value: svgBlock });\n if (after.trim()) {\n segments.push(...splitContentSegments(after, true));\n }\n return finalizeSegments(segments);\n }\n\n if (closeIdx === -1) {\n return finalizeSegments([{ type: \"markdown\", value: svgBlock }]);\n }\n }\n\n const tableBlock = extractTableBlock(raw);\n const markdownHeadingMatch = findMarkdownHeadingMatch(raw, fenceRanges);\n const shouldProcessTableBlock =\n !!tableBlock &&\n (!markdownHeadingMatch || tableBlock.start < markdownHeadingMatch.start);\n if (tableBlock && shouldProcessTableBlock) {\n const segments: RenderSegment[] = [];\n const before = raw.slice(0, tableBlock.start);\n if (keepText && before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n segments.push({ type: \"markdown\", value: tableBlock.block });\n const after = raw.slice(tableBlock.end);\n const hasProgress = after.length < raw.length;\n if (after.trim() && hasProgress) {\n segments.push(\n ...(keepText\n ? splitContentSegments(after, true)\n : splitContentSegments(after))\n );\n }\n return finalizeSegments(segments);\n }\n\n const inlineMatch = findInlineSandboxMatch(raw);\n const markdownImageMatch = findMarkdownImageMatch(raw, fenceRanges);\n const markdownVideoIframeMatch = findMarkdownVideoIframeMatch(\n raw,\n fenceRanges\n );\n const inlineCandidate = pickEarliestMatch(\n inlineMatch,\n markdownImageMatch,\n markdownHeadingMatch,\n markdownVideoIframeMatch\n );\n\n if (sandboxStartIndex === -1 && !inlineCandidate) {\n if (keepText && raw.trim()) {\n return finalizeSegments([{ type: \"text\", value: raw }]);\n }\n return [];\n }\n\n const shouldUseInline =\n !!inlineCandidate &&\n (sandboxStartIndex === -1 || inlineCandidate.start <= sandboxStartIndex);\n\n const startIndex = shouldUseInline\n ? inlineCandidate!.start\n : sandboxStartIndex;\n const blockEnd = shouldUseInline\n ? inlineCandidate!.end\n : findHtmlBlockEnd(raw, startIndex);\n\n const segments: RenderSegment[] = [];\n const before = raw.slice(0, startIndex);\n const matchedBlock = raw.slice(startIndex, blockEnd);\n const after = raw.slice(blockEnd);\n\n if (keepText && before.trim()) {\n segments.push({ type: \"text\", value: before });\n }\n\n segments.push({\n type: shouldUseInline ? \"markdown\" : \"sandbox\",\n value: matchedBlock,\n });\n\n if (after.trim()) {\n segments.push(...splitContentSegments(after, keepText));\n }\n\n return finalizeSegments(segments);\n};\n"],"names":["SANDBOX_START_PATTERN","INLINE_SANDBOX_PATTERNS","MARKDOWN_IMAGE_PATTERN","MARKDOWN_HEADING_PATTERN","MARKDOWN_VIDEO_IFRAME_PATTERN","closingBoundary","CUSTOM_BUTTON_PATTERN","getFenceRanges","raw","ranges","fencePattern","match","start","closeMatch","isIndexInRanges","index","end","findFirstMatchOutsideFence","pattern","fenceRanges","flags","matcher","findHtmlBlockEnd","startIndex","blockEnd","splitCustomButtonsFromSandbox","segments","output","segment","lastIndex","before","rest","findInlineSandboxMatch","earliest","pickEarliestMatch","matches","findMarkdownImageMatch","findMarkdownHeadingMatch","findMarkdownVideoIframeMatch","isIndexInsideMarkdownTableLine","lineStart","lineEnd","extractTableBlock","tableMatch","leadingSpaces","tableStart","lines","tableLines","line","block","splitContentSegments","keepText","finalizeSegments","fenceStart","sandboxStartIndex","svgOpenIndex","svgInTableLine","hasSandboxBeforeSvg","closeIdx","svgBlock","after","tableBlock","markdownHeadingMatch","shouldProcessTableBlock","hasProgress","inlineMatch","markdownImageMatch","markdownVideoIframeMatch","inlineCandidate","shouldUseInline","matchedBlock"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=/(<text\b[^>]*>)([\s\S]*?)(<\/text>)/gi,c=/<br\s*\/?>/i,o=/<br\s*\/?>/gi,u=e=>typeof e!="string"?"":!e||e.indexOf("<text")===-1||e.indexOf("<br")===-1?e:e.replace(s,(r,i,t,n)=>{if(!c.test(t))return r;const E=t.replace(o,"");return`${i}${E}${n}`});exports.stripSvgTextLineBreaks=u;
|
|
2
|
+
//# sourceMappingURL=strip-svg-text-line-breaks.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip-svg-text-line-breaks.cjs.js","sources":["../../../../src/components/ContentRender/utils/strip-svg-text-line-breaks.ts"],"sourcesContent":["const TEXT_BLOCK_REGEX = /(<text\\b[^>]*>)([\\s\\S]*?)(<\\/text>)/gi;\nconst LINE_BREAK_TEST_REGEX = /<br\\s*\\/?>/i;\nconst LINE_BREAK_REPLACE_REGEX = /<br\\s*\\/?>/gi;\n\nexport const stripSvgTextLineBreaks = (svg: string) => {\n if (typeof svg !== \"string\") {\n return \"\";\n }\n\n if (!svg || svg.indexOf(\"<text\") === -1 || svg.indexOf(\"<br\") === -1) {\n return svg;\n }\n\n return svg.replace(TEXT_BLOCK_REGEX, (match, openTag, content, closeTag) => {\n if (!LINE_BREAK_TEST_REGEX.test(content)) {\n return match;\n }\n\n const cleaned = content.replace(LINE_BREAK_REPLACE_REGEX, \"\");\n return `${openTag}${cleaned}${closeTag}`;\n });\n};\n"],"names":["TEXT_BLOCK_REGEX","LINE_BREAK_TEST_REGEX","LINE_BREAK_REPLACE_REGEX","stripSvgTextLineBreaks","svg","match","openTag","content","closeTag","cleaned"],"mappings":"gFAAA,MAAMA,EAAmB,wCACnBC,EAAwB,cACxBC,EAA2B,eAEpBC,EAA0BC,GACjC,OAAOA,GAAQ,SACV,GAGL,CAACA,GAAOA,EAAI,QAAQ,OAAO,IAAM,IAAMA,EAAI,QAAQ,KAAK,IAAM,GACzDA,EAGFA,EAAI,QAAQJ,EAAkB,CAACK,EAAOC,EAASC,EAASC,IAAa,CAC1E,GAAI,CAACP,EAAsB,KAAKM,CAAO,EACrC,OAAOF,EAGT,MAAMI,EAAUF,EAAQ,QAAQL,EAA0B,EAAE,EAC5D,MAAO,GAAGI,CAAO,GAAGG,CAAO,GAAGD,CAAQ,EACxC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const stripSvgTextLineBreaks: (svg: string) => string;
|