@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 3.54 kB
Source Map (JSON)
{"version":3,"file":"buildStaticSrcDoc.mjs","names":[],"sources":["../../src/HtmlPreview/buildStaticSrcDoc.ts"],"sourcesContent":["import { buildAutoHeightScript } from './injectAutoHeightScript';\nimport { STORAGE_SHIM_SCRIPT } from './injectStorageShim';\n\ninterface BuildStaticSrcDocOptions {\n background?: string;\n content: string;\n frameId: string;\n}\n\nconst shimsBlock = (frameId: string) =>\n `<script>${STORAGE_SHIM_SCRIPT}</script><script>${buildAutoHeightScript(frameId)}</script>`;\n\nconst baseStyle = (background?: string) =>\n `<style>html,body{margin:0;padding:0;${background ? `background:${background};` : ''}color-scheme:light dark;}</style>`;\n\n/**\n * Wrap a user's HTML document with our shims so the iframe can load it as\n * a single self-contained srcDoc. This path is used when the content is\n * *static* (not streaming) — the browser parses it via the normal HTML\n * pipeline, so external `<script src=…>` tags load and execute exactly\n * like they would on a regular page. Tailwind CDN, Chart.js, p5.js — all\n * the things a Play CDN expects to see at parse time — work naturally.\n *\n * For *streaming* content we instead use `buildShellSrcDoc` + postMessage\n * morph, which trades reliable script execution for the ability to fade\n * in new nodes without reloading the iframe.\n *\n * Strategy: inject our shims (storage shim, auto-height) as early in the\n * resulting `<head>` as possible so they run before any user script. If\n * the user supplied a `<head>` open tag we slot the shims in right after\n * it; otherwise we wrap a minimal document around fragments.\n */\nexport const buildStaticSrcDoc = ({\n background,\n content,\n frameId,\n}: BuildStaticSrcDocOptions): string => {\n const head = `${baseStyle(background)}${shimsBlock(frameId)}`;\n const lower = content.toLowerCase();\n const hasHtmlTag = lower.includes('<html');\n\n if (!hasHtmlTag) {\n return `<!DOCTYPE html><html><head><meta charset=\"utf-8\">${head}</head><body>${content}</body></html>`;\n }\n\n const headOpenMatch = content.match(/<head\\b[^>]*>/i);\n if (headOpenMatch) {\n const idx = headOpenMatch.index! + headOpenMatch[0].length;\n return content.slice(0, idx) + head + content.slice(idx);\n }\n\n const headCloseIdx = lower.indexOf('</head>');\n if (headCloseIdx !== -1) {\n return content.slice(0, headCloseIdx) + head + content.slice(headCloseIdx);\n }\n\n const htmlOpenMatch = content.match(/<html\\b[^>]*>/i);\n if (htmlOpenMatch) {\n const idx = htmlOpenMatch.index! + htmlOpenMatch[0].length;\n return content.slice(0, idx) + `<head>${head}</head>` + content.slice(idx);\n }\n\n return `<!DOCTYPE html><html><head>${head}</head><body>${content}</body></html>`;\n};\n"],"mappings":";;;AASA,MAAM,cAAc,YAClB,WAAW,oBAAoB,oBAAmB,sBAAsB,OAAO,EAAE;AAEnF,MAAM,aAAa,eACjB,uCAAuC,aAAa,cAAc,WAAW,KAAK,GAAG;;;;;;;;;;;;;;;;;;AAmBvF,MAAa,qBAAqB,EAChC,YACA,SACA,cACsC;CACtC,MAAM,OAAO,GAAG,UAAU,UAAU,IAAI,WAAW,OAAO;CAC1D,MAAM,QAAQ,QAAQ,YAAY;CAGlC,IAAI,CAFe,MAAM,SAAS,OAEpB,GACZ,OAAO,oDAAoD,KAAK,eAAe,QAAQ;CAGzF,MAAM,gBAAgB,QAAQ,MAAM,gBAAgB;CACpD,IAAI,eAAe;EACjB,MAAM,MAAM,cAAc,QAAS,cAAc,EAAE,CAAC;EACpD,OAAO,QAAQ,MAAM,GAAG,GAAG,IAAI,OAAO,QAAQ,MAAM,GAAG;CACzD;CAEA,MAAM,eAAe,MAAM,QAAQ,SAAS;CAC5C,IAAI,iBAAiB,IACnB,OAAO,QAAQ,MAAM,GAAG,YAAY,IAAI,OAAO,QAAQ,MAAM,YAAY;CAG3E,MAAM,gBAAgB,QAAQ,MAAM,gBAAgB;CACpD,IAAI,eAAe;EACjB,MAAM,MAAM,cAAc,QAAS,cAAc,EAAE,CAAC;EACpD,OAAO,QAAQ,MAAM,GAAG,GAAG,IAAI,SAAS,KAAK,WAAW,QAAQ,MAAM,GAAG;CAC3E;CAEA,OAAO,8BAA8B,KAAK,eAAe,QAAQ;AACnE"}