UNPKG

@lobehub/ui

Version:

Lobe UI is an open-source UI component library for building AIGC web apps

1 lines 3.52 kB
{"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,QAAQ,CAAC;AAEnF,MAAM,aAAa,eACjB,uCAAuC,aAAa,cAAc,WAAW,KAAK,GAAG;;;;;;;;;;;;;;;;;;AAmBvF,MAAa,qBAAqB,EAChC,YACA,SACA,cACsC;CACtC,MAAM,OAAO,GAAG,UAAU,WAAW,GAAG,WAAW,QAAQ;CAC3D,MAAM,QAAQ,QAAQ,aAAa;AAGnC,KAAI,CAFe,MAAM,SAAS,QAEnB,CACb,QAAO,oDAAoD,KAAK,eAAe,QAAQ;CAGzF,MAAM,gBAAgB,QAAQ,MAAM,iBAAiB;AACrD,KAAI,eAAe;EACjB,MAAM,MAAM,cAAc,QAAS,cAAc,GAAG;AACpD,SAAO,QAAQ,MAAM,GAAG,IAAI,GAAG,OAAO,QAAQ,MAAM,IAAI;;CAG1D,MAAM,eAAe,MAAM,QAAQ,UAAU;AAC7C,KAAI,iBAAiB,GACnB,QAAO,QAAQ,MAAM,GAAG,aAAa,GAAG,OAAO,QAAQ,MAAM,aAAa;CAG5E,MAAM,gBAAgB,QAAQ,MAAM,iBAAiB;AACrD,KAAI,eAAe;EACjB,MAAM,MAAM,cAAc,QAAS,cAAc,GAAG;AACpD,SAAO,QAAQ,MAAM,GAAG,IAAI,GAAG,SAAS,KAAK,WAAW,QAAQ,MAAM,IAAI;;AAG5E,QAAO,8BAA8B,KAAK,eAAe,QAAQ"}