@hejiayue/x-markdown-test 0.0.1-beta.130 → 0.0.1-beta.131

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.
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue");let t=null,l=null,n=!1;function a(e){return new Function('return import("'+e+'")')()}const o=e=>{if(!e.length)return[[]];const t=[[]];let l=t[0];const n=()=>{l=[],t.push(l)};return e.forEach(e=>{const t=e.content??"";if("\n"===t)return void n();if(!t.includes("\n"))return void l.push(e);const a=t.split("\n");a.forEach((t,o)=>{t&&l.push({...e,content:t}),o<a.length-1&&n()})}),0===t.length?[[]]:t};exports.useHighlight=function(r,c){const i=e.ref(),s=e.ref(!1),u=e.ref(null);let p=null,h="",g=null,v="",m="";const d=e.computed(()=>(e.isRef(c.theme)?c.theme.value:c.theme)||"slack-dark"),y=e.computed(()=>e.toValue(c.language)||"text"),f=e.computed(()=>i.value?.lines||[[]]),w=e.computed(()=>i.value?.preStyle),S=async(e,t=!1)=>{if(!p)return;t&&(p.clear(),h="");const l=!t&&e.startsWith(h);let n=e;if(l?n=e.slice(h.length):t||p.clear(),h=e,!n){const e=[...p.tokensStable,...p.tokensUnstable];return void(i.value={colorReplacements:c.colorReplacements,lines:e.length?o(e):[[]],preStyle:i.value?.preStyle})}try{await p.enqueue(n);const e=[...p.tokensStable,...p.tokensUnstable];i.value={colorReplacements:c.colorReplacements,lines:o(e),preStyle:i.value?.preStyle}}catch(a){console.error("[x-markdown] Streaming highlighting failed:",a),u.value=a}},k=async()=>{s.value=!0,u.value=null;let e=y.value;const o=d.value;try{const s=await(async()=>(t||(t=(async()=>{try{return await a("shiki")}catch{return null}})()),t))();if(!s)return i.value={colorReplacements:c.colorReplacements,lines:[[{content:r.value}]],preStyle:void 0},void(n||(n=!0,console.log("%c[x-markdown]%c 代码高亮功能已降级为纯文本模式","font-weight: bold; color: #0066cc;","color: #666;"),console.log("%c如需语法高亮功能,请安装以下依赖:","color: #666; font-weight: bold;"),console.log("%c pnpm add shiki shiki-stream","color: #00aa00; font-family: monospace;"),console.log("%c安装后请重启开发服务器","color: #999; font-size: 12px;")));g=await s.createHighlighter({themes:[o],langs:[]}),m=e;try{await g.loadLanguage(e),v=e}catch{e="plaintext",v="plaintext"}const u=await(async()=>(l||(l=(async()=>{try{return await a("shiki-stream")}catch{return null}})()),l))();u&&(p=new u.ShikiStreamTokenizer({highlighter:g,lang:e,theme:o})),h="";const d=g.getTheme(o),y=((e,t)=>{if(e||t)return{backgroundColor:e,color:t}})(d?.bg,d?.fg);r.value?(await S(r.value,!0),i.value&&(i.value.preStyle=y)):i.value={colorReplacements:c.colorReplacements,lines:[[]],preStyle:y}}catch(f){i.value={colorReplacements:c.colorReplacements,lines:[[{content:r.value}]],preStyle:void 0}}finally{s.value=!1}};return e.watch(()=>[y.value,d.value],async([e])=>{const t=e;if(g&&"plaintext"===v&&t!==m&&"plaintext"!==t)try{return await g.loadLanguage(t),void k()}catch{return void(m=t)}k()},{immediate:!0}),e.watch(r,async e=>{const t=y.value;if(g&&"plaintext"===v&&t!==m&&"plaintext"!==t)try{return await g.loadLanguage(t),void(await k())}catch{m=t}p?S(e):g||(i.value={colorReplacements:c.colorReplacements,lines:[[{content:e}]],preStyle:i.value?.preStyle})}),e.onUnmounted(()=>{p?.clear(),p=null,h=""}),{streaming:i,lines:f,preStyle:w,isLoading:s,error:u}};
1
+ "use strict";Object.create,Object.defineProperty,Object.getOwnPropertyDescriptor,Object.getOwnPropertyNames,Object.getPrototypeOf,Object.prototype.hasOwnProperty,Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue");let t=null,l=null,n=!1;const a=e=>{if(!e.length)return[[]];const t=[[]];let l=t[0];const n=()=>{l=[],t.push(l)};return e.forEach(e=>{const t=e.content??"";if("\n"===t)return void n();if(!t.includes("\n"))return void l.push(e);const a=t.split("\n");a.forEach((t,o)=>{t&&l.push({...e,content:t}),o<a.length-1&&n()})}),0===t.length?[[]]:t};exports.useHighlight=function(o,r){const c=e.ref(),i=e.ref(!1),s=e.ref(null);let u=null,p="",h=null,g="",m="";const v=e.computed(()=>(e.isRef(r.theme)?r.theme.value:r.theme)||"slack-dark"),y=e.computed(()=>e.toValue(r.language)||"text"),d=e.computed(()=>c.value?.lines||[[]]),f=e.computed(()=>c.value?.preStyle),w=async(e,t=!1)=>{if(!u)return;t&&(u.clear(),p="");const l=!t&&e.startsWith(p);let n=e;if(l?n=e.slice(p.length):t||u.clear(),p=e,!n){const e=[...u.tokensStable,...u.tokensUnstable];return void(c.value={colorReplacements:r.colorReplacements,lines:e.length?a(e):[[]],preStyle:c.value?.preStyle})}try{await u.enqueue(n);const e=[...u.tokensStable,...u.tokensUnstable];c.value={colorReplacements:r.colorReplacements,lines:a(e),preStyle:c.value?.preStyle}}catch(o){console.error("[x-markdown] Streaming highlighting failed:",o),s.value=o}},S=async()=>{i.value=!0,s.value=null;let e=y.value;const a=v.value;try{const i=await(async()=>(t||(t=(async()=>{try{return await import("shiki")}catch{return null}})()),t))();if(!i)return c.value={colorReplacements:r.colorReplacements,lines:[[{content:o.value}]],preStyle:void 0},void(n||(n=!0,console.log("%c[x-markdown]%c 代码高亮功能已降级为纯文本模式","font-weight: bold; color: #0066cc;","color: #666;"),console.log("%c如需语法高亮功能,请安装以下依赖:","color: #666; font-weight: bold;"),console.log("%c pnpm add shiki shiki-stream","color: #00aa00; font-family: monospace;"),console.log("%c安装后请重启开发服务器","color: #999; font-size: 12px;")));h=await i.createHighlighter({themes:[a],langs:[]}),m=e;try{await h.loadLanguage(e),g=e}catch{e="plaintext",g="plaintext"}const s=await(async()=>(l||(l=(async()=>{try{return await import("shiki-stream")}catch{return null}})()),l))();s&&(u=new s.ShikiStreamTokenizer({highlighter:h,lang:e,theme:a})),p="";const v=h.getTheme(a),y=((e,t)=>{if(e||t)return{backgroundColor:e,color:t}})(v?.bg,v?.fg);o.value?(await w(o.value,!0),c.value&&(c.value.preStyle=y)):c.value={colorReplacements:r.colorReplacements,lines:[[]],preStyle:y}}catch(d){c.value={colorReplacements:r.colorReplacements,lines:[[{content:o.value}]],preStyle:void 0}}finally{i.value=!1}};return e.watch(()=>[y.value,v.value],async([e])=>{const t=e;if(h&&"plaintext"===g&&t!==m&&"plaintext"!==t)try{return await h.loadLanguage(t),void S()}catch{return void(m=t)}S()},{immediate:!0}),e.watch(o,async e=>{const t=y.value;if(h&&"plaintext"===g&&t!==m&&"plaintext"!==t)try{return await h.loadLanguage(t),void(await S())}catch{m=t}u?w(e):h||(c.value={colorReplacements:r.colorReplacements,lines:[[{content:e}]],preStyle:c.value?.preStyle})}),e.onUnmounted(()=>{u?.clear(),u=null,p=""}),{streaming:c,lines:d,preStyle:f,isLoading:i,error:s}};
2
2
  //# sourceMappingURL=x-markdown.cjs7.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"x-markdown.cjs7.js","sources":["../src/hooks/useHighlight.ts"],"sourcesContent":["import { ref, watch, onUnmounted, computed, isRef, toValue, type Ref, type MaybeRef, type CSSProperties } from 'vue'\r\n\r\ninterface HighlightToken {\r\n content?: string\r\n color?: string\r\n fontStyle?: 'italic' | null\r\n fontWeight?: 'normal' | 'bold' | null\r\n htmlStyle?: Record<string, string>\r\n}\r\n\r\ninterface StreamingHighlightResult {\r\n colorReplacements?: Record<string, string>\r\n lines: HighlightToken[][]\r\n preStyle?: CSSProperties\r\n}\r\n\r\ninterface UseHighlightOptions {\r\n language: MaybeRef<string>\r\n theme?: string | Ref<string>\r\n colorReplacements?: Record<string, string>\r\n}\r\n\r\nlet shikiModulePromise: Promise<any | null> | null = null\r\nlet shikiStreamModulePromise: Promise<any | null> | null = null\r\nlet hasShownDependencyHint = false\r\n\r\n/**\r\n * 真正的动态导入,使用 Function 构造器绕过 Vite 的 import-analysis\r\n */\r\nfunction dynamicImport(moduleName: string): Promise<any> {\r\n // 使用 Function 构造器来创建一个真正动态的 import\r\n // 这样 Vite 在 import-analysis 阶段不会尝试解析这个模块路径\r\n return new Function('return import(\"' + moduleName + '\")')()\r\n}\r\n\r\nconst showDependencyHint = () => {\r\n if (hasShownDependencyHint) return\r\n hasShownDependencyHint = true\r\n\r\n console.log(\r\n '%c[x-markdown]%c 代码高亮功能已降级为纯文本模式',\r\n 'font-weight: bold; color: #0066cc;',\r\n 'color: #666;'\r\n )\r\n console.log(\r\n '%c如需语法高亮功能,请安装以下依赖:',\r\n 'color: #666; font-weight: bold;'\r\n )\r\n console.log(\r\n '%c pnpm add shiki shiki-stream',\r\n 'color: #00aa00; font-family: monospace;'\r\n )\r\n console.log(\r\n '%c安装后请重启开发服务器',\r\n 'color: #999; font-size: 12px;'\r\n )\r\n}\r\n\r\nconst loadShiki = async () => {\r\n if (!shikiModulePromise) {\r\n shikiModulePromise = (async () => {\r\n try {\r\n const mod = await dynamicImport('shiki')\r\n return mod\r\n } catch {\r\n // 静默失败,返回 null\r\n return null\r\n }\r\n })()\r\n }\r\n return shikiModulePromise\r\n}\r\n\r\nconst loadShikiStream = async () => {\r\n if (!shikiStreamModulePromise) {\r\n shikiStreamModulePromise = (async () => {\r\n try {\r\n const mod = await dynamicImport('shiki-stream')\r\n return mod\r\n } catch {\r\n // 静默失败,返回 null\r\n return null\r\n }\r\n })()\r\n }\r\n return shikiStreamModulePromise\r\n}\r\n\r\nconst tokensToLineTokens = (tokens: HighlightToken[]): HighlightToken[][] => {\r\n if (!tokens.length) return [[]]\r\n\r\n const lines: HighlightToken[][] = [[]]\r\n let currentLine = lines[0]\r\n\r\n const startNewLine = () => {\r\n currentLine = []\r\n lines.push(currentLine)\r\n }\r\n\r\n tokens.forEach((token) => {\r\n const content = token.content ?? ''\r\n\r\n if (content === '\\n') {\r\n startNewLine()\r\n return\r\n }\r\n\r\n if (!content.includes('\\n')) {\r\n currentLine.push(token)\r\n return\r\n }\r\n\r\n const segments = content.split('\\n')\r\n segments.forEach((segment, index) => {\r\n if (segment) {\r\n currentLine.push({\r\n ...token,\r\n content: segment,\r\n })\r\n }\r\n\r\n if (index < segments.length - 1) {\r\n startNewLine()\r\n }\r\n })\r\n })\r\n\r\n return lines.length === 0 ? [[]] : lines\r\n}\r\n\r\nconst createPreStyle = (bg?: string, fg?: string): CSSProperties | undefined => {\r\n if (!bg && !fg) return undefined\r\n return {\r\n backgroundColor: bg,\r\n color: fg,\r\n }\r\n}\r\n\r\nexport function useHighlight(text: Ref<string>, options: UseHighlightOptions) {\r\n const streaming = ref<StreamingHighlightResult>()\r\n const isLoading = ref(false)\r\n const error = ref<Error | null>(null)\r\n\r\n let tokenizer: any | null = null\r\n let previousText = ''\r\n let highlighter: any | null = null\r\n let currentUsedLang = ''\r\n let lastRequestedLang = ''\r\n\r\n const effectiveTheme = computed(() => {\r\n const theme = isRef(options.theme) ? options.theme.value : options.theme\r\n return theme || 'slack-dark'\r\n })\r\n\r\n const effectiveLanguage = computed(() => {\r\n return toValue(options.language) || 'text'\r\n })\r\n\r\n const lines = computed(() => streaming.value?.lines || [[]])\r\n const preStyle = computed(() => streaming.value?.preStyle)\r\n\r\n const updateTokens = async (nextText: string, forceReset = false) => {\r\n if (!tokenizer) return\r\n\r\n if (forceReset) {\r\n tokenizer.clear()\r\n previousText = ''\r\n }\r\n\r\n const canAppend = !forceReset && nextText.startsWith(previousText)\r\n let chunk = nextText\r\n\r\n if (canAppend) {\r\n chunk = nextText.slice(previousText.length)\r\n } else if (!forceReset) {\r\n tokenizer.clear()\r\n }\r\n\r\n previousText = nextText\r\n\r\n if (!chunk) {\r\n const mergedTokens = [...tokenizer.tokensStable, ...tokenizer.tokensUnstable]\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: mergedTokens.length ? tokensToLineTokens(mergedTokens) : [[]],\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n return\r\n }\r\n\r\n try {\r\n await tokenizer.enqueue(chunk)\r\n\r\n const mergedTokens = [...tokenizer.tokensStable, ...tokenizer.tokensUnstable]\r\n\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: tokensToLineTokens(mergedTokens),\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n } catch (err) {\r\n console.error('[x-markdown] Streaming highlighting failed:', err)\r\n error.value = err as Error\r\n }\r\n }\r\n\r\n const initHighlighter = async () => {\r\n isLoading.value = true\r\n error.value = null\r\n\r\n let currentLang = effectiveLanguage.value\r\n const currentTheme = effectiveTheme.value\r\n\r\n try {\r\n const mod = await loadShiki()\r\n if (!mod) {\r\n // 静默降级为纯文本\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: text.value }]],\r\n preStyle: undefined,\r\n }\r\n showDependencyHint()\r\n return\r\n }\r\n\r\n // shiki 3.x API\r\n highlighter = await mod.createHighlighter({\r\n themes: [currentTheme],\r\n langs: [], // 将动态加载语言\r\n })\r\n\r\n lastRequestedLang = currentLang\r\n\r\n try {\r\n await highlighter.loadLanguage(currentLang as any)\r\n currentUsedLang = currentLang\r\n } catch {\r\n currentLang = 'plaintext'\r\n currentUsedLang = 'plaintext'\r\n }\r\n\r\n // 动态加载 shiki-stream\r\n const shikiStreamMod = await loadShikiStream()\r\n if (shikiStreamMod) {\r\n tokenizer = new shikiStreamMod.ShikiStreamTokenizer({\r\n highlighter: highlighter,\r\n lang: currentLang,\r\n theme: currentTheme,\r\n })\r\n }\r\n\r\n previousText = ''\r\n\r\n const themeInfo = highlighter.getTheme(currentTheme)\r\n const preStyleValue = createPreStyle(themeInfo?.bg, themeInfo?.fg)\r\n\r\n if (text.value) {\r\n await updateTokens(text.value, true)\r\n if (streaming.value) {\r\n streaming.value.preStyle = preStyleValue\r\n }\r\n } else {\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[]],\r\n preStyle: preStyleValue,\r\n }\r\n }\r\n } catch (err) {\r\n // 静默降级\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: text.value }]],\r\n preStyle: undefined,\r\n }\r\n } finally {\r\n isLoading.value = false\r\n }\r\n }\r\n\r\n watch(\r\n () => [effectiveLanguage.value, effectiveTheme.value],\r\n async ([newLang]) => {\r\n const requestedLang = newLang as string\r\n\r\n if (\r\n highlighter &&\r\n currentUsedLang === 'plaintext' &&\r\n requestedLang !== lastRequestedLang &&\r\n requestedLang !== 'plaintext'\r\n ) {\r\n try {\r\n await highlighter.loadLanguage(requestedLang as any)\r\n initHighlighter()\r\n return\r\n } catch {\r\n lastRequestedLang = requestedLang\r\n return\r\n }\r\n }\r\n\r\n initHighlighter()\r\n },\r\n { immediate: true },\r\n )\r\n\r\n watch(text, async (newText) => {\r\n const requestedLang = effectiveLanguage.value\r\n if (\r\n highlighter &&\r\n currentUsedLang === 'plaintext' &&\r\n requestedLang !== lastRequestedLang &&\r\n requestedLang !== 'plaintext'\r\n ) {\r\n try {\r\n await highlighter.loadLanguage(requestedLang as any)\r\n await initHighlighter()\r\n return\r\n } catch {\r\n lastRequestedLang = requestedLang\r\n }\r\n }\r\n\r\n if (tokenizer) {\r\n updateTokens(newText)\r\n } else if (!highlighter) {\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: newText }]],\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n }\r\n })\r\n\r\n onUnmounted(() => {\r\n tokenizer?.clear()\r\n tokenizer = null\r\n previousText = ''\r\n })\r\n\r\n return {\r\n streaming,\r\n lines,\r\n preStyle,\r\n isLoading,\r\n error,\r\n }\r\n}\r\n"],"names":["shikiModulePromise","shikiStreamModulePromise","hasShownDependencyHint","dynamicImport","moduleName","Function","tokensToLineTokens","tokens","length","lines","currentLine","startNewLine","push","forEach","token","content","includes","segments","split","segment","index","text","options","streaming","ref","isLoading","error","tokenizer","previousText","highlighter","currentUsedLang","lastRequestedLang","effectiveTheme","computed","isRef","theme","value","effectiveLanguage","toValue","language","preStyle","updateTokens","async","nextText","forceReset","clear","canAppend","startsWith","chunk","slice","mergedTokens","tokensStable","tokensUnstable","colorReplacements","enqueue","err","console","initHighlighter","currentLang","currentTheme","mod","loadShiki","log","createHighlighter","themes","langs","loadLanguage","shikiStreamMod","loadShikiStream","ShikiStreamTokenizer","lang","themeInfo","getTheme","preStyleValue","bg","fg","backgroundColor","color","createPreStyle","watch","newLang","requestedLang","immediate","newText","onUnmounted"],"mappings":"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"}
1
+ {"version":3,"file":"x-markdown.cjs7.js","sources":["../src/hooks/useHighlight.ts"],"sourcesContent":["import { ref, watch, onUnmounted, computed, isRef, toValue, type Ref, type MaybeRef, type CSSProperties } from 'vue'\r\n\r\ninterface HighlightToken {\r\n content?: string\r\n color?: string\r\n fontStyle?: 'italic' | null\r\n fontWeight?: 'normal' | 'bold' | null\r\n htmlStyle?: Record<string, string>\r\n}\r\n\r\ninterface StreamingHighlightResult {\r\n colorReplacements?: Record<string, string>\r\n lines: HighlightToken[][]\r\n preStyle?: CSSProperties\r\n}\r\n\r\ninterface UseHighlightOptions {\r\n language: MaybeRef<string>\r\n theme?: string | Ref<string>\r\n colorReplacements?: Record<string, string>\r\n}\r\n\r\nlet shikiModulePromise: Promise<any | null> | null = null\r\nlet shikiStreamModulePromise: Promise<any | null> | null = null\r\nlet hasShownDependencyHint = false\r\n\r\n\r\nconst showDependencyHint = () => {\r\n if (hasShownDependencyHint) return\r\n hasShownDependencyHint = true\r\n\r\n console.log(\r\n '%c[x-markdown]%c 代码高亮功能已降级为纯文本模式',\r\n 'font-weight: bold; color: #0066cc;',\r\n 'color: #666;'\r\n )\r\n console.log(\r\n '%c如需语法高亮功能,请安装以下依赖:',\r\n 'color: #666; font-weight: bold;'\r\n )\r\n console.log(\r\n '%c pnpm add shiki shiki-stream',\r\n 'color: #00aa00; font-family: monospace;'\r\n )\r\n console.log(\r\n '%c安装后请重启开发服务器',\r\n 'color: #999; font-size: 12px;'\r\n )\r\n}\r\n\r\nconst loadShiki = async () => {\r\n if (!shikiModulePromise) {\r\n shikiModulePromise = (async () => {\r\n try {\r\n const mod = await import('shiki')\r\n return mod\r\n } catch {\r\n // 静默失败,返回 null\r\n return null\r\n }\r\n })()\r\n }\r\n return shikiModulePromise\r\n}\r\n\r\nconst loadShikiStream = async () => {\r\n if (!shikiStreamModulePromise) {\r\n shikiStreamModulePromise = (async () => {\r\n try {\r\n const mod = await import('shiki-stream')\r\n return mod\r\n } catch {\r\n // 静默失败,返回 null\r\n return null\r\n }\r\n })()\r\n }\r\n return shikiStreamModulePromise\r\n}\r\n\r\nconst tokensToLineTokens = (tokens: HighlightToken[]): HighlightToken[][] => {\r\n if (!tokens.length) return [[]]\r\n\r\n const lines: HighlightToken[][] = [[]]\r\n let currentLine = lines[0]\r\n\r\n const startNewLine = () => {\r\n currentLine = []\r\n lines.push(currentLine)\r\n }\r\n\r\n tokens.forEach((token) => {\r\n const content = token.content ?? ''\r\n\r\n if (content === '\\n') {\r\n startNewLine()\r\n return\r\n }\r\n\r\n if (!content.includes('\\n')) {\r\n currentLine.push(token)\r\n return\r\n }\r\n\r\n const segments = content.split('\\n')\r\n segments.forEach((segment, index) => {\r\n if (segment) {\r\n currentLine.push({\r\n ...token,\r\n content: segment,\r\n })\r\n }\r\n\r\n if (index < segments.length - 1) {\r\n startNewLine()\r\n }\r\n })\r\n })\r\n\r\n return lines.length === 0 ? [[]] : lines\r\n}\r\n\r\nconst createPreStyle = (bg?: string, fg?: string): CSSProperties | undefined => {\r\n if (!bg && !fg) return undefined\r\n return {\r\n backgroundColor: bg,\r\n color: fg,\r\n }\r\n}\r\n\r\nexport function useHighlight(text: Ref<string>, options: UseHighlightOptions) {\r\n const streaming = ref<StreamingHighlightResult>()\r\n const isLoading = ref(false)\r\n const error = ref<Error | null>(null)\r\n\r\n let tokenizer: any | null = null\r\n let previousText = ''\r\n let highlighter: any | null = null\r\n let currentUsedLang = ''\r\n let lastRequestedLang = ''\r\n\r\n const effectiveTheme = computed(() => {\r\n const theme = isRef(options.theme) ? options.theme.value : options.theme\r\n return theme || 'slack-dark'\r\n })\r\n\r\n const effectiveLanguage = computed(() => {\r\n return toValue(options.language) || 'text'\r\n })\r\n\r\n const lines = computed(() => streaming.value?.lines || [[]])\r\n const preStyle = computed(() => streaming.value?.preStyle)\r\n\r\n const updateTokens = async (nextText: string, forceReset = false) => {\r\n if (!tokenizer) return\r\n\r\n if (forceReset) {\r\n tokenizer.clear()\r\n previousText = ''\r\n }\r\n\r\n const canAppend = !forceReset && nextText.startsWith(previousText)\r\n let chunk = nextText\r\n\r\n if (canAppend) {\r\n chunk = nextText.slice(previousText.length)\r\n } else if (!forceReset) {\r\n tokenizer.clear()\r\n }\r\n\r\n previousText = nextText\r\n\r\n if (!chunk) {\r\n const mergedTokens = [...tokenizer.tokensStable, ...tokenizer.tokensUnstable]\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: mergedTokens.length ? tokensToLineTokens(mergedTokens) : [[]],\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n return\r\n }\r\n\r\n try {\r\n await tokenizer.enqueue(chunk)\r\n\r\n const mergedTokens = [...tokenizer.tokensStable, ...tokenizer.tokensUnstable]\r\n\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: tokensToLineTokens(mergedTokens),\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n } catch (err) {\r\n console.error('[x-markdown] Streaming highlighting failed:', err)\r\n error.value = err as Error\r\n }\r\n }\r\n\r\n const initHighlighter = async () => {\r\n isLoading.value = true\r\n error.value = null\r\n\r\n let currentLang = effectiveLanguage.value\r\n const currentTheme = effectiveTheme.value\r\n\r\n try {\r\n const mod = await loadShiki()\r\n if (!mod) {\r\n // 静默降级为纯文本\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: text.value }]],\r\n preStyle: undefined,\r\n }\r\n showDependencyHint()\r\n return\r\n }\r\n\r\n // shiki 3.x API\r\n highlighter = await mod.createHighlighter({\r\n themes: [currentTheme],\r\n langs: [], // 将动态加载语言\r\n })\r\n\r\n lastRequestedLang = currentLang\r\n\r\n try {\r\n await highlighter.loadLanguage(currentLang as any)\r\n currentUsedLang = currentLang\r\n } catch {\r\n currentLang = 'plaintext'\r\n currentUsedLang = 'plaintext'\r\n }\r\n\r\n // 动态加载 shiki-stream\r\n const shikiStreamMod = await loadShikiStream()\r\n if (shikiStreamMod) {\r\n tokenizer = new shikiStreamMod.ShikiStreamTokenizer({\r\n highlighter: highlighter,\r\n lang: currentLang,\r\n theme: currentTheme,\r\n })\r\n }\r\n\r\n previousText = ''\r\n\r\n const themeInfo = highlighter.getTheme(currentTheme)\r\n const preStyleValue = createPreStyle(themeInfo?.bg, themeInfo?.fg)\r\n\r\n if (text.value) {\r\n await updateTokens(text.value, true)\r\n if (streaming.value) {\r\n streaming.value.preStyle = preStyleValue\r\n }\r\n } else {\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[]],\r\n preStyle: preStyleValue,\r\n }\r\n }\r\n } catch (err) {\r\n // 静默降级\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: text.value }]],\r\n preStyle: undefined,\r\n }\r\n } finally {\r\n isLoading.value = false\r\n }\r\n }\r\n\r\n watch(\r\n () => [effectiveLanguage.value, effectiveTheme.value],\r\n async ([newLang]) => {\r\n const requestedLang = newLang as string\r\n\r\n if (\r\n highlighter &&\r\n currentUsedLang === 'plaintext' &&\r\n requestedLang !== lastRequestedLang &&\r\n requestedLang !== 'plaintext'\r\n ) {\r\n try {\r\n await highlighter.loadLanguage(requestedLang as any)\r\n initHighlighter()\r\n return\r\n } catch {\r\n lastRequestedLang = requestedLang\r\n return\r\n }\r\n }\r\n\r\n initHighlighter()\r\n },\r\n { immediate: true },\r\n )\r\n\r\n watch(text, async (newText) => {\r\n const requestedLang = effectiveLanguage.value\r\n if (\r\n highlighter &&\r\n currentUsedLang === 'plaintext' &&\r\n requestedLang !== lastRequestedLang &&\r\n requestedLang !== 'plaintext'\r\n ) {\r\n try {\r\n await highlighter.loadLanguage(requestedLang as any)\r\n await initHighlighter()\r\n return\r\n } catch {\r\n lastRequestedLang = requestedLang\r\n }\r\n }\r\n\r\n if (tokenizer) {\r\n updateTokens(newText)\r\n } else if (!highlighter) {\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: newText }]],\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n }\r\n })\r\n\r\n onUnmounted(() => {\r\n tokenizer?.clear()\r\n tokenizer = null\r\n previousText = ''\r\n })\r\n\r\n return {\r\n streaming,\r\n lines,\r\n preStyle,\r\n isLoading,\r\n error,\r\n }\r\n}\r\n"],"names":["shikiModulePromise","shikiStreamModulePromise","hasShownDependencyHint","tokensToLineTokens","tokens","length","lines","currentLine","startNewLine","push","forEach","token","content","includes","segments","split","segment","index","text","options","streaming","ref","isLoading","error","tokenizer","previousText","highlighter","currentUsedLang","lastRequestedLang","effectiveTheme","computed","isRef","theme","value","effectiveLanguage","toValue","language","preStyle","updateTokens","async","nextText","forceReset","clear","canAppend","startsWith","chunk","slice","mergedTokens","tokensStable","tokensUnstable","colorReplacements","enqueue","err","console","initHighlighter","currentLang","currentTheme","mod","import","loadShiki","log","createHighlighter","themes","langs","loadLanguage","shikiStreamMod","loadShikiStream","ShikiStreamTokenizer","lang","themeInfo","getTheme","preStyleValue","bg","fg","backgroundColor","color","createPreStyle","watch","newLang","requestedLang","immediate","newText","onUnmounted"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("lodash-es"),t=require("vue");let n=null,o=!1,a=null,r=null;function l(e){return new Function('return import("'+e+'")')()}const u=[];let i=!1;exports.checkMermaidAvailable=async function(){return null!==a?a:r||(r=(async()=>{try{const e=await l("mermaid");return a=!!e,a}catch(e){return console.error("[x-markdown] Failed to load mermaid:",e),a=!1,!1}})(),r)},exports.downloadSvgAsPng=function(e){if(e)try{const t=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(e)}`,n=new Image;n.onload=()=>{try{const o=document.createElement("canvas"),a=o.getContext("2d",{willReadFrequently:!1});if(!a)return;const r=2;o.width=n.width*r,o.height=n.height*r,a.imageSmoothingEnabled=!0,a.imageSmoothingQuality="high",a.fillStyle="#ffffff",a.fillRect(0,0,o.width,o.height),a.drawImage(n,0,0,o.width,o.height);const l=(new Date).toISOString().slice(0,19).replace(/:/g,"-");try{o.toBlob(e=>{if(!e)return;const t=URL.createObjectURL(e),n=document.createElement("a");n.href=t,n.download=`mermaid-diagram-${l}.png`,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(t)},"image/png",.95)}catch(e){console.error("Failed to convert canvas to blob:",e);try{const e=o.toDataURL("image/png",.95),t=document.createElement("a");t.href=e,t.download=`mermaid-diagram-${l}.png`,document.body.appendChild(t),t.click(),document.body.removeChild(t)}catch(t){console.error("Failed to convert canvas to data URL:",t)}}}catch(o){console.error("Canvas operation failed:",o)}},n.onerror=e=>{console.error("Failed to load image:",e)},n.src=t}catch(t){console.error("Failed to download SVG:",t)}},exports.useMermaid=function(a,r={}){const c=t.computed(()=>"object"==typeof r&&"value"in r?r.value:r),s=t.computed(()=>({suppressErrorRendering:!0,startOnLoad:!1,securityLevel:"loose",theme:c.value.theme||"default",...c.value.config||{}})),d=t.ref(""),v=t.ref(null),m=t.ref(!1);let f=!1;const h=e.throttle(()=>{const e="string"==typeof a?a:a.value;if(!e?.trim())return d.value="",v.value=null,void(m.value=!1);var t;m.value=!0,t=async()=>{if(!f)try{const t=await async function(){return"undefined"==typeof window?null:(n||(n=(async()=>{try{const e=await l("mermaid");return e?.default}catch(v){return console.error("[x-markdown] Failed to load mermaid:",v),o||(o=!0,console.log("%c[x-markdown]%c Mermaid 图表功能已降级为代码块显示","font-weight: bold; color: #9333ea;","color: #666;"),console.log("%c如需 Mermaid 图表渲染功能,请安装:","color: #666; font-weight: bold;"),console.log("%c pnpm add mermaid","color: #9333ea; font-family: monospace;"),console.log("%c安装后请重启开发服务器","color: #999; font-size: 12px;")),null}})()),n)}();if(!t)return d.value=e,v.value=null,void(m.value=!1);if(t.initialize(s.value),!(await t.parse(e.trim())))return d.value="",v.value=new Error("Mermaid parse error: Invalid syntax"),void(m.value=!1);const a=`${c.value.id||"mermaid"}-${Math.random().toString(36).substring(2,11)}`,r=(()=>{const e=c.value.container;return e?"object"==typeof e&&"value"in e?e.value:e:null})();if(!r)return void(m.value=!1);const{svg:u}=await t.render(a,e,r);d.value=u,v.value=null,m.value=!1}catch(t){d.value="",v.value=t,m.value=!1}},u.push(t),async function(){if(!i){for(i=!0;u.length>0;){const t=u.shift();if(t)try{await t()}catch(e){console.error("Mermaid render queue error:",e)}}i=!1}}()},100,{leading:!1,trailing:!0});return t.watch([()=>"string"==typeof a?a:a.value,()=>s.value],()=>{h()},{immediate:!0}),t.onUnmounted(()=>{f=!0}),{data:d,error:v,isLoading:m}},exports.useMermaidZoom=function(n){const{container:o}=n,a=t.ref(1),r=t.ref(0),l=t.ref(0),u=t.ref(!1);let i=null;const c=()=>o.value?.querySelector(".syntax-mermaid__content svg"),s=e=>{e.style.transformOrigin="center center",e.style.transform=`translate(${r.value}px, ${l.value}px) scale(${a.value})`},d=()=>{a.value=1,r.value=0,l.value=0,u.value=!1},v=()=>{i?.(),i=null,d()};return t.watch(()=>o.value,()=>{v(),d()}),t.onUnmounted(v),{zoomIn:()=>{const e=c();e&&(a.value=Math.min(a.value+.2,10),s(e))},zoomOut:()=>{const e=c();e&&(a.value=Math.max(a.value-.2,.1),s(e))},reset:()=>{const e=c();e&&(d(),s(e))},fullscreen:()=>{o.value&&(document.fullscreenElement?document.exitFullscreen():o.value.requestFullscreen?.())},destroy:v,initialize:()=>{if(!o.value)return;d(),i=(t=>{let n=0,o=0,i=!1;const d=(e,t)=>{u.value=!0,n=e-r.value,o=t-l.value,document.body.style.userSelect="none"},v=(e,t)=>{if(u.value&&i){r.value=e-n,l.value=t-o;const a=c();a&&s(a)}},m=()=>{u.value=!1,i=!1,document.body.style.userSelect=""},f=e=>{0===e.button&&(e.target===t||t.contains(e.target))&&(e.preventDefault(),i=!0,d(e.clientX,e.clientY))},h=e=>{i&&v(e.clientX,e.clientY)},g=e.throttle(e=>{const n=c();if(!n)return;const o=t.getBoundingClientRect(),u=n.getBoundingClientRect(),i=e.clientX-o.left,d=e.clientY-o.top,v=u.left-o.left+u.width/2,m=u.top-o.top+u.height/2,f=(i-v-r.value)/a.value,h=(d-m-l.value)/a.value,g=e.deltaY>0?-.05:.05,p=Math.min(Math.max(a.value+g,.1),10);p!==a.value&&(a.value=p,r.value=i-v-f*a.value,l.value=d-m-h*a.value,s(n))},20,{leading:!0,trailing:!0}),p=e=>{(e.target===t||t.contains(e.target))&&(e.preventDefault(),g(e))},y=e=>{(e.target===t||t.contains(e.target))&&1===e.touches.length&&(e.preventDefault(),i=!0,d(e.touches[0].clientX,e.touches[0].clientY))},w=e=>{i&&(e.preventDefault(),v(e.touches[0].clientX,e.touches[0].clientY))};return t.addEventListener("mousedown",f),document.addEventListener("mousemove",h),document.addEventListener("mouseup",m),t.addEventListener("wheel",p,{passive:!1}),t.addEventListener("touchstart",y,{passive:!1}),t.addEventListener("touchmove",w,{passive:!1}),document.addEventListener("touchend",m),()=>{t.removeEventListener("mousedown",f),document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",m),t.removeEventListener("wheel",p),t.removeEventListener("touchstart",y),t.removeEventListener("touchmove",w),document.removeEventListener("touchend",m),document.body.style.userSelect=""}})(o.value);const t=c();t&&s(t)}}};
1
+ "use strict";Object.create,Object.defineProperty,Object.getOwnPropertyDescriptor,Object.getOwnPropertyNames,Object.getPrototypeOf,Object.prototype.hasOwnProperty,Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("lodash-es"),t=require("vue");let n=null,o=!1,r=null,a=null;const l=[];let u=!1;exports.checkMermaidAvailable=async function(){return null!==r?r:a||(a=(async()=>{try{const e=await import("mermaid");return r=!!e,r}catch(e){return console.error("[x-markdown] Failed to load mermaid:",e),r=!1,!1}})(),a)},exports.downloadSvgAsPng=function(e){if(e)try{const t=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(e)}`,n=new Image;n.onload=()=>{try{const o=document.createElement("canvas"),r=o.getContext("2d",{willReadFrequently:!1});if(!r)return;const a=2;o.width=n.width*a,o.height=n.height*a,r.imageSmoothingEnabled=!0,r.imageSmoothingQuality="high",r.fillStyle="#ffffff",r.fillRect(0,0,o.width,o.height),r.drawImage(n,0,0,o.width,o.height);const l=(new Date).toISOString().slice(0,19).replace(/:/g,"-");try{o.toBlob(e=>{if(!e)return;const t=URL.createObjectURL(e),n=document.createElement("a");n.href=t,n.download=`mermaid-diagram-${l}.png`,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(t)},"image/png",.95)}catch(e){console.error("Failed to convert canvas to blob:",e);try{const e=o.toDataURL("image/png",.95),t=document.createElement("a");t.href=e,t.download=`mermaid-diagram-${l}.png`,document.body.appendChild(t),t.click(),document.body.removeChild(t)}catch(t){console.error("Failed to convert canvas to data URL:",t)}}}catch(o){console.error("Canvas operation failed:",o)}},n.onerror=e=>{console.error("Failed to load image:",e)},n.src=t}catch(t){console.error("Failed to download SVG:",t)}},exports.useMermaid=function(r,a={}){const c=t.computed(()=>"object"==typeof a&&"value"in a?a.value:a),i=t.computed(()=>({suppressErrorRendering:!0,startOnLoad:!1,securityLevel:"loose",theme:c.value.theme||"default",...c.value.config||{}})),s=t.ref(""),d=t.ref(null),v=t.ref(!1);let m=!1;const f=e.throttle(()=>{const e="string"==typeof r?r:r.value;if(!e?.trim())return s.value="",d.value=null,void(v.value=!1);var t;v.value=!0,t=async()=>{if(!m)try{const t=await async function(){return"undefined"==typeof window?null:(n||(n=(async()=>{try{const e=await import("mermaid");return e?.default}catch(d){return console.error("[x-markdown] Failed to load mermaid:",d),o||(o=!0,console.log("%c[x-markdown]%c Mermaid 图表功能已降级为代码块显示","font-weight: bold; color: #9333ea;","color: #666;"),console.log("%c如需 Mermaid 图表渲染功能,请安装:","color: #666; font-weight: bold;"),console.log("%c pnpm add mermaid","color: #9333ea; font-family: monospace;"),console.log("%c安装后请重启开发服务器","color: #999; font-size: 12px;")),null}})()),n)}();if(!t)return s.value=e,d.value=null,void(v.value=!1);if(t.initialize(i.value),!(await t.parse(e.trim())))return s.value="",d.value=new Error("Mermaid parse error: Invalid syntax"),void(v.value=!1);const r=`${c.value.id||"mermaid"}-${Math.random().toString(36).substring(2,11)}`,a=(()=>{const e=c.value.container;return e?"object"==typeof e&&"value"in e?e.value:e:null})();if(!a)return void(v.value=!1);const{svg:l}=await t.render(r,e,a);s.value=l,d.value=null,v.value=!1}catch(t){s.value="",d.value=t,v.value=!1}},l.push(t),async function(){if(!u){for(u=!0;l.length>0;){const t=l.shift();if(t)try{await t()}catch(e){console.error("Mermaid render queue error:",e)}}u=!1}}()},100,{leading:!1,trailing:!0});return t.watch([()=>"string"==typeof r?r:r.value,()=>i.value],()=>{f()},{immediate:!0}),t.onUnmounted(()=>{m=!0}),{data:s,error:d,isLoading:v}},exports.useMermaidZoom=function(n){const{container:o}=n,r=t.ref(1),a=t.ref(0),l=t.ref(0),u=t.ref(!1);let c=null;const i=()=>o.value?.querySelector(".syntax-mermaid__content svg"),s=e=>{e.style.transformOrigin="center center",e.style.transform=`translate(${a.value}px, ${l.value}px) scale(${r.value})`},d=()=>{r.value=1,a.value=0,l.value=0,u.value=!1},v=()=>{c?.(),c=null,d()};return t.watch(()=>o.value,()=>{v(),d()}),t.onUnmounted(v),{zoomIn:()=>{const e=i();e&&(r.value=Math.min(r.value+.2,10),s(e))},zoomOut:()=>{const e=i();e&&(r.value=Math.max(r.value-.2,.1),s(e))},reset:()=>{const e=i();e&&(d(),s(e))},fullscreen:()=>{o.value&&(document.fullscreenElement?document.exitFullscreen():o.value.requestFullscreen?.())},destroy:v,initialize:()=>{if(!o.value)return;d(),c=(t=>{let n=0,o=0,c=!1;const d=(e,t)=>{u.value=!0,n=e-a.value,o=t-l.value,document.body.style.userSelect="none"},v=(e,t)=>{if(u.value&&c){a.value=e-n,l.value=t-o;const r=i();r&&s(r)}},m=()=>{u.value=!1,c=!1,document.body.style.userSelect=""},f=e=>{0===e.button&&(e.target===t||t.contains(e.target))&&(e.preventDefault(),c=!0,d(e.clientX,e.clientY))},h=e=>{c&&v(e.clientX,e.clientY)},g=e.throttle(e=>{const n=i();if(!n)return;const o=t.getBoundingClientRect(),u=n.getBoundingClientRect(),c=e.clientX-o.left,d=e.clientY-o.top,v=u.left-o.left+u.width/2,m=u.top-o.top+u.height/2,f=(c-v-a.value)/r.value,h=(d-m-l.value)/r.value,g=e.deltaY>0?-.05:.05,p=Math.min(Math.max(r.value+g,.1),10);p!==r.value&&(r.value=p,a.value=c-v-f*r.value,l.value=d-m-h*r.value,s(n))},20,{leading:!0,trailing:!0}),p=e=>{(e.target===t||t.contains(e.target))&&(e.preventDefault(),g(e))},y=e=>{(e.target===t||t.contains(e.target))&&1===e.touches.length&&(e.preventDefault(),c=!0,d(e.touches[0].clientX,e.touches[0].clientY))},w=e=>{c&&(e.preventDefault(),v(e.touches[0].clientX,e.touches[0].clientY))};return t.addEventListener("mousedown",f),document.addEventListener("mousemove",h),document.addEventListener("mouseup",m),t.addEventListener("wheel",p,{passive:!1}),t.addEventListener("touchstart",y,{passive:!1}),t.addEventListener("touchmove",w,{passive:!1}),document.addEventListener("touchend",m),()=>{t.removeEventListener("mousedown",f),document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",m),t.removeEventListener("wheel",p),t.removeEventListener("touchstart",y),t.removeEventListener("touchmove",w),document.removeEventListener("touchend",m),document.body.style.userSelect=""}})(o.value);const t=i();t&&s(t)}}};
2
2
  //# sourceMappingURL=x-markdown.cjs9.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"x-markdown.cjs9.js","sources":["../src/hooks/useMermaid.ts"],"sourcesContent":["import type { Ref } from 'vue'\r\nimport { throttle } from 'lodash-es'\r\nimport { computed, ref, watch, onUnmounted } from 'vue'\r\nimport type { MermaidZoomControls, UseMermaidZoomOptions, UseMermaidResult } from '../components/Mermaid/types'\r\n\r\nexport function downloadSvgAsPng(svg: string): void {\r\n if (!svg) return\r\n\r\n try {\r\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`\r\n const img = new Image()\r\n\r\n img.onload = () => {\r\n try {\r\n const canvas = document.createElement('canvas')\r\n const ctx = canvas.getContext('2d', { willReadFrequently: false })\r\n if (!ctx) return\r\n\r\n const scale = 2\r\n canvas.width = img.width * scale\r\n canvas.height = img.height * scale\r\n ctx.imageSmoothingEnabled = true\r\n ctx.imageSmoothingQuality = 'high'\r\n\r\n ctx.fillStyle = '#ffffff'\r\n ctx.fillRect(0, 0, canvas.width, canvas.height)\r\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\r\n\r\n const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-')\r\n\r\n try {\r\n canvas.toBlob(\r\n (blob) => {\r\n if (!blob) return\r\n const url = URL.createObjectURL(blob)\r\n const link = document.createElement('a')\r\n link.href = url\r\n link.download = `mermaid-diagram-${timestamp}.png`\r\n document.body.appendChild(link)\r\n link.click()\r\n document.body.removeChild(link)\r\n URL.revokeObjectURL(url)\r\n },\r\n 'image/png',\r\n 0.95,\r\n )\r\n } catch (toBlobError) {\r\n console.error('Failed to convert canvas to blob:', toBlobError)\r\n try {\r\n const dataUrl = canvas.toDataURL('image/png', 0.95)\r\n const link = document.createElement('a')\r\n link.href = dataUrl\r\n link.download = `mermaid-diagram-${timestamp}.png`\r\n document.body.appendChild(link)\r\n link.click()\r\n document.body.removeChild(link)\r\n } catch (dataUrlError) {\r\n console.error('Failed to convert canvas to data URL:', dataUrlError)\r\n }\r\n }\r\n } catch (canvasError) {\r\n console.error('Canvas operation failed:', canvasError)\r\n }\r\n }\r\n\r\n img.onerror = (error) => {\r\n console.error('Failed to load image:', error)\r\n }\r\n\r\n img.src = svgDataUrl\r\n } catch (error) {\r\n console.error('Failed to download SVG:', error)\r\n }\r\n}\r\n\r\ninterface UseMermaidOptions {\r\n id?: string\r\n theme?: 'default' | 'dark' | 'forest' | 'neutral' | string\r\n config?: any\r\n container?: HTMLElement | Ref<HTMLElement | null> | null\r\n}\r\n\r\ntype UseMermaidOptionsInput = UseMermaidOptions | Ref<UseMermaidOptions>\r\n\r\nlet mermaidPromise: Promise<any> | null = null\r\nlet hasShownMermaidHint = false\r\nlet mermaidAvailableCache: boolean | null = null\r\nlet mermaidCheckPromise: Promise<boolean> | null = null\r\n\r\n/**\r\n * 真正的动态导入,使用 Function 构造器绕过 Vite 的 import-analysis\r\n */\r\nfunction dynamicImport(moduleName: string): Promise<any> {\r\n // 使用 Function 构造器来创建一个真正动态的 import\r\n // 这样 Vite 在 import-analysis 阶段不会尝试解析这个模块路径\r\n return new Function('return import(\"' + moduleName + '\")')()\r\n}\r\n\r\n/**\r\n * 同步检查缓存状态(不触发检测)\r\n * @returns 缓存状态,null 表示未检测\r\n */\r\nexport function getMermaidAvailableCache(): boolean | null {\r\n return mermaidAvailableCache\r\n}\r\n\r\n/**\r\n * 检测 mermaid 是否可用(全局缓存,只检测一次)\r\n */\r\nexport async function checkMermaidAvailable(): Promise<boolean> {\r\n // 如果已经有缓存结果,直接返回\r\n if (mermaidAvailableCache !== null) {\r\n return mermaidAvailableCache\r\n }\r\n\r\n // 如果正在检测,返回检测 Promise\r\n if (mermaidCheckPromise) {\r\n return mermaidCheckPromise\r\n }\r\n\r\n // 开始检测\r\n mermaidCheckPromise = (async () => {\r\n try {\r\n // 使用 dynamicImport 来绕过 Vite 的 import-analysis\r\n // mermaid 已在 vite.config.ts 中配置为 external,不会被打包进库\r\n const mod = await dynamicImport('mermaid')\r\n mermaidAvailableCache = !!mod\r\n return mermaidAvailableCache\r\n } catch (error) {\r\n console.error('[x-markdown] Failed to load mermaid:', error)\r\n mermaidAvailableCache = false\r\n return false\r\n }\r\n })()\r\n\r\n return mermaidCheckPromise\r\n}\r\n\r\nconst showMermaidHint = () => {\r\n if (hasShownMermaidHint) return\r\n hasShownMermaidHint = true\r\n\r\n console.log(\r\n '%c[x-markdown]%c Mermaid 图表功能已降级为代码块显示',\r\n 'font-weight: bold; color: #9333ea;',\r\n 'color: #666;'\r\n )\r\n console.log(\r\n '%c如需 Mermaid 图表渲染功能,请安装:',\r\n 'color: #666; font-weight: bold;'\r\n )\r\n console.log(\r\n '%c pnpm add mermaid',\r\n 'color: #9333ea; font-family: monospace;'\r\n )\r\n console.log(\r\n '%c安装后请重启开发服务器',\r\n 'color: #999; font-size: 12px;'\r\n )\r\n}\r\n\r\nasync function loadMermaid() {\r\n if (typeof window === 'undefined') return null\r\n if (!mermaidPromise) {\r\n mermaidPromise = (async () => {\r\n try {\r\n // 使用 dynamicImport 来绕过 Vite 的 import-analysis\r\n const mod = await dynamicImport('mermaid')\r\n return (mod as any)?.default\r\n } catch (error) {\r\n console.error('[x-markdown] Failed to load mermaid:', error)\r\n showMermaidHint()\r\n return null\r\n }\r\n })()\r\n }\r\n return mermaidPromise\r\n}\r\n\r\ntype RenderTask = () => Promise<void>\r\nconst renderQueue: RenderTask[] = []\r\nlet isProcessingQueue = false\r\n\r\nasync function processRenderQueue() {\r\n if (isProcessingQueue) return\r\n isProcessingQueue = true\r\n\r\n while (renderQueue.length > 0) {\r\n const task = renderQueue.shift()\r\n if (task) {\r\n try {\r\n await task()\r\n } catch (err) {\r\n console.error('Mermaid render queue error:', err)\r\n }\r\n }\r\n }\r\n\r\n isProcessingQueue = false\r\n}\r\n\r\nfunction addToRenderQueue(task: RenderTask) {\r\n renderQueue.push(task)\r\n processRenderQueue()\r\n}\r\n\r\nexport function useMermaid(content: string | Ref<string>, options: UseMermaidOptionsInput = {}): UseMermaidResult {\r\n const optionsRef = computed(() => (typeof options === 'object' && 'value' in options ? options.value : options))\r\n const mermaidConfig = computed(() => ({\r\n suppressErrorRendering: true,\r\n startOnLoad: false,\r\n securityLevel: 'loose',\r\n theme: optionsRef.value.theme || 'default',\r\n ...(optionsRef.value.config || {}),\r\n }))\r\n const data = ref('')\r\n const error = ref<unknown>(null)\r\n const isLoading = ref(false)\r\n\r\n let isUnmounted = false\r\n\r\n const getRenderContainer = () => {\r\n const containerOption = optionsRef.value.container\r\n if (containerOption) {\r\n return typeof containerOption === 'object' && 'value' in containerOption ? containerOption.value : containerOption\r\n }\r\n return null\r\n }\r\n\r\n const throttledRender = throttle(\r\n () => {\r\n const contentValue = typeof content === 'string' ? content : content.value\r\n if (!contentValue?.trim()) {\r\n data.value = ''\r\n error.value = null\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n isLoading.value = true\r\n\r\n addToRenderQueue(async () => {\r\n if (isUnmounted) return\r\n\r\n try {\r\n const mermaidInstance = await loadMermaid()\r\n if (!mermaidInstance) {\r\n data.value = contentValue\r\n error.value = null\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n mermaidInstance.initialize(mermaidConfig.value)\r\n\r\n const isValid = await mermaidInstance.parse(contentValue.trim())\r\n if (!isValid) {\r\n data.value = ''\r\n error.value = new Error('Mermaid parse error: Invalid syntax')\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n const renderId = `${optionsRef.value.id || 'mermaid'}-${Math.random().toString(36).substring(2, 11)}`\r\n const container = getRenderContainer()\r\n if (!container) {\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n const { svg } = await mermaidInstance.render(renderId, contentValue, container)\r\n data.value = svg\r\n error.value = null\r\n isLoading.value = false\r\n } catch (err) {\r\n // Mermaid render error\r\n data.value = ''\r\n error.value = err\r\n isLoading.value = false\r\n }\r\n })\r\n },\r\n 100,\r\n { leading: false, trailing: true },\r\n )\r\n\r\n watch(\r\n [() => (typeof content === 'string' ? content : content.value), () => mermaidConfig.value],\r\n () => {\r\n throttledRender()\r\n },\r\n { immediate: true },\r\n )\r\n\r\n onUnmounted(() => {\r\n isUnmounted = true\r\n })\r\n\r\n return {\r\n data,\r\n error,\r\n isLoading,\r\n }\r\n}\r\n\r\nexport function useMermaidZoom(options: UseMermaidZoomOptions): MermaidZoomControls {\r\n const { container } = options\r\n\r\n const scale = ref(1)\r\n const posX = ref(0)\r\n const posY = ref(0)\r\n const isDragging = ref(false)\r\n\r\n let removeEvents: (() => void) | null = null\r\n\r\n const getSvg = () => container.value?.querySelector('.syntax-mermaid__content svg') as HTMLElement\r\n\r\n const updateTransform = (svg: HTMLElement) => {\r\n svg.style.transformOrigin = 'center center'\r\n svg.style.transform = `translate(${posX.value}px, ${posY.value}px) scale(${scale.value})`\r\n }\r\n\r\n const resetState = () => {\r\n scale.value = 1\r\n posX.value = 0\r\n posY.value = 0\r\n isDragging.value = false\r\n }\r\n\r\n const addInteractionEvents = (containerEl: HTMLElement) => {\r\n let startX = 0\r\n let startY = 0\r\n let isInteractingWithMermaid = false\r\n\r\n const onStart = (clientX: number, clientY: number) => {\r\n isDragging.value = true\r\n startX = clientX - posX.value\r\n startY = clientY - posY.value\r\n document.body.style.userSelect = 'none'\r\n }\r\n\r\n const onMove = (clientX: number, clientY: number) => {\r\n if (isDragging.value && isInteractingWithMermaid) {\r\n posX.value = clientX - startX\r\n posY.value = clientY - startY\r\n const svg = getSvg()\r\n if (svg) {\r\n updateTransform(svg)\r\n }\r\n }\r\n }\r\n\r\n const onEnd = () => {\r\n isDragging.value = false\r\n isInteractingWithMermaid = false\r\n document.body.style.userSelect = ''\r\n }\r\n\r\n const onMouseDown = (e: MouseEvent) => {\r\n if (e.button !== 0) return\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n e.preventDefault()\r\n isInteractingWithMermaid = true\r\n onStart(e.clientX, e.clientY)\r\n }\r\n }\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n if (isInteractingWithMermaid) {\r\n onMove(e.clientX, e.clientY)\r\n }\r\n }\r\n\r\n const handleWheelZoom = (e: WheelEvent) => {\r\n const svg = getSvg()\r\n if (!svg) return\r\n\r\n const containerRect = containerEl.getBoundingClientRect()\r\n const svgRect = svg.getBoundingClientRect()\r\n\r\n const mouseX = e.clientX - containerRect.left\r\n const mouseY = e.clientY - containerRect.top\r\n\r\n const svgCenterX = svgRect.left - containerRect.left + svgRect.width / 2\r\n const svgCenterY = svgRect.top - containerRect.top + svgRect.height / 2\r\n\r\n const offsetX = (mouseX - svgCenterX - posX.value) / scale.value\r\n const offsetY = (mouseY - svgCenterY - posY.value) / scale.value\r\n\r\n const delta = e.deltaY > 0 ? -0.05 : 0.05\r\n const newScale = Math.min(Math.max(scale.value + delta, 0.1), 10)\r\n\r\n if (newScale === scale.value) return\r\n\r\n scale.value = newScale\r\n\r\n posX.value = mouseX - svgCenterX - offsetX * scale.value\r\n posY.value = mouseY - svgCenterY - offsetY * scale.value\r\n\r\n updateTransform(svg)\r\n }\r\n\r\n const throttledWheelZoom = throttle(handleWheelZoom, 20, { leading: true, trailing: true })\r\n\r\n const onWheel = (e: WheelEvent) => {\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n e.preventDefault()\r\n throttledWheelZoom(e)\r\n }\r\n }\r\n\r\n const onTouchStart = (e: TouchEvent) => {\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n if (e.touches.length === 1) {\r\n e.preventDefault()\r\n isInteractingWithMermaid = true\r\n onStart(e.touches[0].clientX, e.touches[0].clientY)\r\n }\r\n }\r\n }\r\n\r\n const onTouchMove = (e: TouchEvent) => {\r\n if (isInteractingWithMermaid) {\r\n e.preventDefault()\r\n onMove(e.touches[0].clientX, e.touches[0].clientY)\r\n }\r\n }\r\n\r\n containerEl.addEventListener('mousedown', onMouseDown)\r\n document.addEventListener('mousemove', onMouseMove)\r\n document.addEventListener('mouseup', onEnd)\r\n containerEl.addEventListener('wheel', onWheel, { passive: false })\r\n containerEl.addEventListener('touchstart', onTouchStart, { passive: false })\r\n containerEl.addEventListener('touchmove', onTouchMove, { passive: false })\r\n document.addEventListener('touchend', onEnd)\r\n\r\n return () => {\r\n containerEl.removeEventListener('mousedown', onMouseDown)\r\n document.removeEventListener('mousemove', onMouseMove)\r\n document.removeEventListener('mouseup', onEnd)\r\n containerEl.removeEventListener('wheel', onWheel)\r\n containerEl.removeEventListener('touchstart', onTouchStart)\r\n containerEl.removeEventListener('touchmove', onTouchMove)\r\n document.removeEventListener('touchend', onEnd)\r\n document.body.style.userSelect = ''\r\n }\r\n }\r\n\r\n const zoomIn = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n scale.value = Math.min(scale.value + 0.2, 10)\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const zoomOut = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n scale.value = Math.max(scale.value - 0.2, 0.1)\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const reset = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n resetState()\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const fullscreen = () => {\r\n if (!container.value) return\r\n\r\n if (document.fullscreenElement) {\r\n document.exitFullscreen()\r\n } else {\r\n container.value.requestFullscreen?.()\r\n }\r\n }\r\n\r\n const initialize = () => {\r\n if (!container.value) return\r\n\r\n resetState()\r\n\r\n removeEvents = addInteractionEvents(container.value)\r\n\r\n const svg = getSvg()\r\n if (svg) {\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const destroy = () => {\r\n removeEvents?.()\r\n removeEvents = null\r\n resetState()\r\n }\r\n\r\n watch(\r\n () => container.value,\r\n () => {\r\n destroy()\r\n resetState()\r\n },\r\n )\r\n\r\n onUnmounted(destroy)\r\n\r\n return {\r\n zoomIn,\r\n zoomOut,\r\n reset,\r\n fullscreen,\r\n destroy,\r\n initialize,\r\n }\r\n}\r\n"],"names":["mermaidPromise","hasShownMermaidHint","mermaidAvailableCache","mermaidCheckPromise","dynamicImport","moduleName","Function","renderQueue","isProcessingQueue","async","mod","error","console","svg","svgDataUrl","encodeURIComponent","img","Image","onload","canvas","document","createElement","ctx","getContext","willReadFrequently","scale","width","height","imageSmoothingEnabled","imageSmoothingQuality","fillStyle","fillRect","drawImage","timestamp","Date","toISOString","slice","replace","toBlob","blob","url","URL","createObjectURL","link","href","download","body","appendChild","click","removeChild","revokeObjectURL","toBlobError","dataUrl","toDataURL","dataUrlError","canvasError","onerror","src","content","options","optionsRef","computed","value","mermaidConfig","suppressErrorRendering","startOnLoad","securityLevel","theme","config","data","ref","isLoading","isUnmounted","throttledRender","throttle","contentValue","trim","task","mermaidInstance","window","default","log","loadMermaid","initialize","parse","Error","renderId","id","Math","random","toString","substring","container","containerOption","getRenderContainer","render","err","push","length","shift","processRenderQueue","leading","trailing","watch","immediate","onUnmounted","posX","posY","isDragging","removeEvents","getSvg","querySelector","updateTransform","style","transformOrigin","transform","resetState","destroy","zoomIn","min","zoomOut","max","reset","fullscreen","fullscreenElement","exitFullscreen","requestFullscreen","containerEl","startX","startY","isInteractingWithMermaid","onStart","clientX","clientY","userSelect","onMove","onEnd","onMouseDown","e","button","target","contains","preventDefault","onMouseMove","throttledWheelZoom","containerRect","getBoundingClientRect","svgRect","mouseX","left","mouseY","top","svgCenterX","svgCenterY","offsetX","offsetY","delta","deltaY","newScale","onWheel","onTouchStart","touches","onTouchMove","addEventListener","passive","removeEventListener","addInteractionEvents"],"mappings":"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"}
1
+ {"version":3,"file":"x-markdown.cjs9.js","sources":["../src/hooks/useMermaid.ts"],"sourcesContent":["import type { Ref } from 'vue'\r\nimport { throttle } from 'lodash-es'\r\nimport { computed, ref, watch, onUnmounted } from 'vue'\r\nimport type { MermaidZoomControls, UseMermaidZoomOptions, UseMermaidResult } from '../components/Mermaid/types'\r\n\r\nexport function downloadSvgAsPng(svg: string): void {\r\n if (!svg) return\r\n\r\n try {\r\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`\r\n const img = new Image()\r\n\r\n img.onload = () => {\r\n try {\r\n const canvas = document.createElement('canvas')\r\n const ctx = canvas.getContext('2d', { willReadFrequently: false })\r\n if (!ctx) return\r\n\r\n const scale = 2\r\n canvas.width = img.width * scale\r\n canvas.height = img.height * scale\r\n ctx.imageSmoothingEnabled = true\r\n ctx.imageSmoothingQuality = 'high'\r\n\r\n ctx.fillStyle = '#ffffff'\r\n ctx.fillRect(0, 0, canvas.width, canvas.height)\r\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\r\n\r\n const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-')\r\n\r\n try {\r\n canvas.toBlob(\r\n (blob) => {\r\n if (!blob) return\r\n const url = URL.createObjectURL(blob)\r\n const link = document.createElement('a')\r\n link.href = url\r\n link.download = `mermaid-diagram-${timestamp}.png`\r\n document.body.appendChild(link)\r\n link.click()\r\n document.body.removeChild(link)\r\n URL.revokeObjectURL(url)\r\n },\r\n 'image/png',\r\n 0.95,\r\n )\r\n } catch (toBlobError) {\r\n console.error('Failed to convert canvas to blob:', toBlobError)\r\n try {\r\n const dataUrl = canvas.toDataURL('image/png', 0.95)\r\n const link = document.createElement('a')\r\n link.href = dataUrl\r\n link.download = `mermaid-diagram-${timestamp}.png`\r\n document.body.appendChild(link)\r\n link.click()\r\n document.body.removeChild(link)\r\n } catch (dataUrlError) {\r\n console.error('Failed to convert canvas to data URL:', dataUrlError)\r\n }\r\n }\r\n } catch (canvasError) {\r\n console.error('Canvas operation failed:', canvasError)\r\n }\r\n }\r\n\r\n img.onerror = (error) => {\r\n console.error('Failed to load image:', error)\r\n }\r\n\r\n img.src = svgDataUrl\r\n } catch (error) {\r\n console.error('Failed to download SVG:', error)\r\n }\r\n}\r\n\r\ninterface UseMermaidOptions {\r\n id?: string\r\n theme?: 'default' | 'dark' | 'forest' | 'neutral' | string\r\n config?: any\r\n container?: HTMLElement | Ref<HTMLElement | null> | null\r\n}\r\n\r\ntype UseMermaidOptionsInput = UseMermaidOptions | Ref<UseMermaidOptions>\r\n\r\nlet mermaidPromise: Promise<any> | null = null\r\nlet hasShownMermaidHint = false\r\nlet mermaidAvailableCache: boolean | null = null\r\nlet mermaidCheckPromise: Promise<boolean> | null = null\r\n\r\n/**\r\n * 同步检查缓存状态(不触发检测)\r\n * @returns 缓存状态,null 表示未检测\r\n */\r\nexport function getMermaidAvailableCache(): boolean | null {\r\n return mermaidAvailableCache\r\n}\r\n\r\n/**\r\n * 检测 mermaid 是否可用(全局缓存,只检测一次)\r\n */\r\nexport async function checkMermaidAvailable(): Promise<boolean> {\r\n // 如果已经有缓存结果,直接返回\r\n if (mermaidAvailableCache !== null) {\r\n return mermaidAvailableCache\r\n }\r\n\r\n // 如果正在检测,返回检测 Promise\r\n if (mermaidCheckPromise) {\r\n return mermaidCheckPromise\r\n }\r\n\r\n // 开始检测\r\n mermaidCheckPromise = (async () => {\r\n try {\r\n const mod = await import('mermaid')\r\n mermaidAvailableCache = !!mod\r\n return mermaidAvailableCache\r\n } catch (error) {\r\n console.error('[x-markdown] Failed to load mermaid:', error)\r\n mermaidAvailableCache = false\r\n return false\r\n }\r\n })()\r\n\r\n return mermaidCheckPromise\r\n}\r\n\r\nconst showMermaidHint = () => {\r\n if (hasShownMermaidHint) return\r\n hasShownMermaidHint = true\r\n\r\n console.log(\r\n '%c[x-markdown]%c Mermaid 图表功能已降级为代码块显示',\r\n 'font-weight: bold; color: #9333ea;',\r\n 'color: #666;'\r\n )\r\n console.log(\r\n '%c如需 Mermaid 图表渲染功能,请安装:',\r\n 'color: #666; font-weight: bold;'\r\n )\r\n console.log(\r\n '%c pnpm add mermaid',\r\n 'color: #9333ea; font-family: monospace;'\r\n )\r\n console.log(\r\n '%c安装后请重启开发服务器',\r\n 'color: #999; font-size: 12px;'\r\n )\r\n}\r\n\r\nasync function loadMermaid() {\r\n if (typeof window === 'undefined') return null\r\n if (!mermaidPromise) {\r\n mermaidPromise = (async () => {\r\n try {\r\n const mod = await import('mermaid')\r\n return (mod as any)?.default\r\n } catch (error) {\r\n console.error('[x-markdown] Failed to load mermaid:', error)\r\n showMermaidHint()\r\n return null\r\n }\r\n })()\r\n }\r\n return mermaidPromise\r\n}\r\n\r\ntype RenderTask = () => Promise<void>\r\nconst renderQueue: RenderTask[] = []\r\nlet isProcessingQueue = false\r\n\r\nasync function processRenderQueue() {\r\n if (isProcessingQueue) return\r\n isProcessingQueue = true\r\n\r\n while (renderQueue.length > 0) {\r\n const task = renderQueue.shift()\r\n if (task) {\r\n try {\r\n await task()\r\n } catch (err) {\r\n console.error('Mermaid render queue error:', err)\r\n }\r\n }\r\n }\r\n\r\n isProcessingQueue = false\r\n}\r\n\r\nfunction addToRenderQueue(task: RenderTask) {\r\n renderQueue.push(task)\r\n processRenderQueue()\r\n}\r\n\r\nexport function useMermaid(content: string | Ref<string>, options: UseMermaidOptionsInput = {}): UseMermaidResult {\r\n const optionsRef = computed(() => (typeof options === 'object' && 'value' in options ? options.value : options))\r\n const mermaidConfig = computed(() => ({\r\n suppressErrorRendering: true,\r\n startOnLoad: false,\r\n securityLevel: 'loose',\r\n theme: optionsRef.value.theme || 'default',\r\n ...(optionsRef.value.config || {}),\r\n }))\r\n const data = ref('')\r\n const error = ref<unknown>(null)\r\n const isLoading = ref(false)\r\n\r\n let isUnmounted = false\r\n\r\n const getRenderContainer = () => {\r\n const containerOption = optionsRef.value.container\r\n if (containerOption) {\r\n return typeof containerOption === 'object' && 'value' in containerOption ? containerOption.value : containerOption\r\n }\r\n return null\r\n }\r\n\r\n const throttledRender = throttle(\r\n () => {\r\n const contentValue = typeof content === 'string' ? content : content.value\r\n if (!contentValue?.trim()) {\r\n data.value = ''\r\n error.value = null\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n isLoading.value = true\r\n\r\n addToRenderQueue(async () => {\r\n if (isUnmounted) return\r\n\r\n try {\r\n const mermaidInstance = await loadMermaid()\r\n if (!mermaidInstance) {\r\n data.value = contentValue\r\n error.value = null\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n mermaidInstance.initialize(mermaidConfig.value)\r\n\r\n const isValid = await mermaidInstance.parse(contentValue.trim())\r\n if (!isValid) {\r\n data.value = ''\r\n error.value = new Error('Mermaid parse error: Invalid syntax')\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n const renderId = `${optionsRef.value.id || 'mermaid'}-${Math.random().toString(36).substring(2, 11)}`\r\n const container = getRenderContainer()\r\n if (!container) {\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n const { svg } = await mermaidInstance.render(renderId, contentValue, container)\r\n data.value = svg\r\n error.value = null\r\n isLoading.value = false\r\n } catch (err) {\r\n // Mermaid render error\r\n data.value = ''\r\n error.value = err\r\n isLoading.value = false\r\n }\r\n })\r\n },\r\n 100,\r\n { leading: false, trailing: true },\r\n )\r\n\r\n watch(\r\n [() => (typeof content === 'string' ? content : content.value), () => mermaidConfig.value],\r\n () => {\r\n throttledRender()\r\n },\r\n { immediate: true },\r\n )\r\n\r\n onUnmounted(() => {\r\n isUnmounted = true\r\n })\r\n\r\n return {\r\n data,\r\n error,\r\n isLoading,\r\n }\r\n}\r\n\r\nexport function useMermaidZoom(options: UseMermaidZoomOptions): MermaidZoomControls {\r\n const { container } = options\r\n\r\n const scale = ref(1)\r\n const posX = ref(0)\r\n const posY = ref(0)\r\n const isDragging = ref(false)\r\n\r\n let removeEvents: (() => void) | null = null\r\n\r\n const getSvg = () => container.value?.querySelector('.syntax-mermaid__content svg') as HTMLElement\r\n\r\n const updateTransform = (svg: HTMLElement) => {\r\n svg.style.transformOrigin = 'center center'\r\n svg.style.transform = `translate(${posX.value}px, ${posY.value}px) scale(${scale.value})`\r\n }\r\n\r\n const resetState = () => {\r\n scale.value = 1\r\n posX.value = 0\r\n posY.value = 0\r\n isDragging.value = false\r\n }\r\n\r\n const addInteractionEvents = (containerEl: HTMLElement) => {\r\n let startX = 0\r\n let startY = 0\r\n let isInteractingWithMermaid = false\r\n\r\n const onStart = (clientX: number, clientY: number) => {\r\n isDragging.value = true\r\n startX = clientX - posX.value\r\n startY = clientY - posY.value\r\n document.body.style.userSelect = 'none'\r\n }\r\n\r\n const onMove = (clientX: number, clientY: number) => {\r\n if (isDragging.value && isInteractingWithMermaid) {\r\n posX.value = clientX - startX\r\n posY.value = clientY - startY\r\n const svg = getSvg()\r\n if (svg) {\r\n updateTransform(svg)\r\n }\r\n }\r\n }\r\n\r\n const onEnd = () => {\r\n isDragging.value = false\r\n isInteractingWithMermaid = false\r\n document.body.style.userSelect = ''\r\n }\r\n\r\n const onMouseDown = (e: MouseEvent) => {\r\n if (e.button !== 0) return\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n e.preventDefault()\r\n isInteractingWithMermaid = true\r\n onStart(e.clientX, e.clientY)\r\n }\r\n }\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n if (isInteractingWithMermaid) {\r\n onMove(e.clientX, e.clientY)\r\n }\r\n }\r\n\r\n const handleWheelZoom = (e: WheelEvent) => {\r\n const svg = getSvg()\r\n if (!svg) return\r\n\r\n const containerRect = containerEl.getBoundingClientRect()\r\n const svgRect = svg.getBoundingClientRect()\r\n\r\n const mouseX = e.clientX - containerRect.left\r\n const mouseY = e.clientY - containerRect.top\r\n\r\n const svgCenterX = svgRect.left - containerRect.left + svgRect.width / 2\r\n const svgCenterY = svgRect.top - containerRect.top + svgRect.height / 2\r\n\r\n const offsetX = (mouseX - svgCenterX - posX.value) / scale.value\r\n const offsetY = (mouseY - svgCenterY - posY.value) / scale.value\r\n\r\n const delta = e.deltaY > 0 ? -0.05 : 0.05\r\n const newScale = Math.min(Math.max(scale.value + delta, 0.1), 10)\r\n\r\n if (newScale === scale.value) return\r\n\r\n scale.value = newScale\r\n\r\n posX.value = mouseX - svgCenterX - offsetX * scale.value\r\n posY.value = mouseY - svgCenterY - offsetY * scale.value\r\n\r\n updateTransform(svg)\r\n }\r\n\r\n const throttledWheelZoom = throttle(handleWheelZoom, 20, { leading: true, trailing: true })\r\n\r\n const onWheel = (e: WheelEvent) => {\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n e.preventDefault()\r\n throttledWheelZoom(e)\r\n }\r\n }\r\n\r\n const onTouchStart = (e: TouchEvent) => {\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n if (e.touches.length === 1) {\r\n e.preventDefault()\r\n isInteractingWithMermaid = true\r\n onStart(e.touches[0].clientX, e.touches[0].clientY)\r\n }\r\n }\r\n }\r\n\r\n const onTouchMove = (e: TouchEvent) => {\r\n if (isInteractingWithMermaid) {\r\n e.preventDefault()\r\n onMove(e.touches[0].clientX, e.touches[0].clientY)\r\n }\r\n }\r\n\r\n containerEl.addEventListener('mousedown', onMouseDown)\r\n document.addEventListener('mousemove', onMouseMove)\r\n document.addEventListener('mouseup', onEnd)\r\n containerEl.addEventListener('wheel', onWheel, { passive: false })\r\n containerEl.addEventListener('touchstart', onTouchStart, { passive: false })\r\n containerEl.addEventListener('touchmove', onTouchMove, { passive: false })\r\n document.addEventListener('touchend', onEnd)\r\n\r\n return () => {\r\n containerEl.removeEventListener('mousedown', onMouseDown)\r\n document.removeEventListener('mousemove', onMouseMove)\r\n document.removeEventListener('mouseup', onEnd)\r\n containerEl.removeEventListener('wheel', onWheel)\r\n containerEl.removeEventListener('touchstart', onTouchStart)\r\n containerEl.removeEventListener('touchmove', onTouchMove)\r\n document.removeEventListener('touchend', onEnd)\r\n document.body.style.userSelect = ''\r\n }\r\n }\r\n\r\n const zoomIn = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n scale.value = Math.min(scale.value + 0.2, 10)\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const zoomOut = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n scale.value = Math.max(scale.value - 0.2, 0.1)\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const reset = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n resetState()\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const fullscreen = () => {\r\n if (!container.value) return\r\n\r\n if (document.fullscreenElement) {\r\n document.exitFullscreen()\r\n } else {\r\n container.value.requestFullscreen?.()\r\n }\r\n }\r\n\r\n const initialize = () => {\r\n if (!container.value) return\r\n\r\n resetState()\r\n\r\n removeEvents = addInteractionEvents(container.value)\r\n\r\n const svg = getSvg()\r\n if (svg) {\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const destroy = () => {\r\n removeEvents?.()\r\n removeEvents = null\r\n resetState()\r\n }\r\n\r\n watch(\r\n () => container.value,\r\n () => {\r\n destroy()\r\n resetState()\r\n },\r\n )\r\n\r\n onUnmounted(destroy)\r\n\r\n return {\r\n zoomIn,\r\n zoomOut,\r\n reset,\r\n fullscreen,\r\n destroy,\r\n initialize,\r\n }\r\n}\r\n"],"names":["mermaidPromise","hasShownMermaidHint","mermaidAvailableCache","mermaidCheckPromise","renderQueue","isProcessingQueue","async","mod","import","error","console","svg","svgDataUrl","encodeURIComponent","img","Image","onload","canvas","document","createElement","ctx","getContext","willReadFrequently","scale","width","height","imageSmoothingEnabled","imageSmoothingQuality","fillStyle","fillRect","drawImage","timestamp","Date","toISOString","slice","replace","toBlob","blob","url","URL","createObjectURL","link","href","download","body","appendChild","click","removeChild","revokeObjectURL","toBlobError","dataUrl","toDataURL","dataUrlError","canvasError","onerror","src","content","options","optionsRef","computed","value","mermaidConfig","suppressErrorRendering","startOnLoad","securityLevel","theme","config","data","ref","isLoading","isUnmounted","throttledRender","throttle","contentValue","trim","task","mermaidInstance","window","default","log","loadMermaid","initialize","parse","Error","renderId","id","Math","random","toString","substring","container","containerOption","getRenderContainer","render","err","push","length","shift","processRenderQueue","leading","trailing","watch","immediate","onUnmounted","posX","posY","isDragging","removeEvents","getSvg","querySelector","updateTransform","style","transformOrigin","transform","resetState","destroy","zoomIn","min","zoomOut","max","reset","fullscreen","fullscreenElement","exitFullscreen","requestFullscreen","containerEl","startX","startY","isInteractingWithMermaid","onStart","clientX","clientY","userSelect","onMove","onEnd","onMouseDown","e","button","target","contains","preventDefault","onMouseMove","throttledWheelZoom","containerRect","getBoundingClientRect","svgRect","mouseX","left","mouseY","top","svgCenterX","svgCenterY","offsetX","offsetY","delta","deltaY","newScale","onWheel","onTouchStart","touches","onTouchMove","addEventListener","passive","removeEventListener","addInteractionEvents"],"mappings":"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"}
@@ -2,9 +2,6 @@ import { ref, computed, isRef, toValue, watch, onUnmounted } from "vue";
2
2
  let shikiModulePromise = null;
3
3
  let shikiStreamModulePromise = null;
4
4
  let hasShownDependencyHint = false;
5
- function dynamicImport(moduleName) {
6
- return new Function('return import("' + moduleName + '")')();
7
- }
8
5
  const showDependencyHint = () => {
9
6
  if (hasShownDependencyHint) return;
10
7
  hasShownDependencyHint = true;
@@ -30,7 +27,7 @@ const loadShiki = async () => {
30
27
  if (!shikiModulePromise) {
31
28
  shikiModulePromise = (async () => {
32
29
  try {
33
- const mod = await dynamicImport("shiki");
30
+ const mod = await import("shiki");
34
31
  return mod;
35
32
  } catch {
36
33
  return null;
@@ -43,7 +40,7 @@ const loadShikiStream = async () => {
43
40
  if (!shikiStreamModulePromise) {
44
41
  shikiStreamModulePromise = (async () => {
45
42
  try {
46
- const mod = await dynamicImport("shiki-stream");
43
+ const mod = await import("shiki-stream");
47
44
  return mod;
48
45
  } catch {
49
46
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"x-markdown.es7.js","sources":["../src/hooks/useHighlight.ts"],"sourcesContent":["import { ref, watch, onUnmounted, computed, isRef, toValue, type Ref, type MaybeRef, type CSSProperties } from 'vue'\r\n\r\ninterface HighlightToken {\r\n content?: string\r\n color?: string\r\n fontStyle?: 'italic' | null\r\n fontWeight?: 'normal' | 'bold' | null\r\n htmlStyle?: Record<string, string>\r\n}\r\n\r\ninterface StreamingHighlightResult {\r\n colorReplacements?: Record<string, string>\r\n lines: HighlightToken[][]\r\n preStyle?: CSSProperties\r\n}\r\n\r\ninterface UseHighlightOptions {\r\n language: MaybeRef<string>\r\n theme?: string | Ref<string>\r\n colorReplacements?: Record<string, string>\r\n}\r\n\r\nlet shikiModulePromise: Promise<any | null> | null = null\r\nlet shikiStreamModulePromise: Promise<any | null> | null = null\r\nlet hasShownDependencyHint = false\r\n\r\n/**\r\n * 真正的动态导入,使用 Function 构造器绕过 Vite 的 import-analysis\r\n */\r\nfunction dynamicImport(moduleName: string): Promise<any> {\r\n // 使用 Function 构造器来创建一个真正动态的 import\r\n // 这样 Vite 在 import-analysis 阶段不会尝试解析这个模块路径\r\n return new Function('return import(\"' + moduleName + '\")')()\r\n}\r\n\r\nconst showDependencyHint = () => {\r\n if (hasShownDependencyHint) return\r\n hasShownDependencyHint = true\r\n\r\n console.log(\r\n '%c[x-markdown]%c 代码高亮功能已降级为纯文本模式',\r\n 'font-weight: bold; color: #0066cc;',\r\n 'color: #666;'\r\n )\r\n console.log(\r\n '%c如需语法高亮功能,请安装以下依赖:',\r\n 'color: #666; font-weight: bold;'\r\n )\r\n console.log(\r\n '%c pnpm add shiki shiki-stream',\r\n 'color: #00aa00; font-family: monospace;'\r\n )\r\n console.log(\r\n '%c安装后请重启开发服务器',\r\n 'color: #999; font-size: 12px;'\r\n )\r\n}\r\n\r\nconst loadShiki = async () => {\r\n if (!shikiModulePromise) {\r\n shikiModulePromise = (async () => {\r\n try {\r\n const mod = await dynamicImport('shiki')\r\n return mod\r\n } catch {\r\n // 静默失败,返回 null\r\n return null\r\n }\r\n })()\r\n }\r\n return shikiModulePromise\r\n}\r\n\r\nconst loadShikiStream = async () => {\r\n if (!shikiStreamModulePromise) {\r\n shikiStreamModulePromise = (async () => {\r\n try {\r\n const mod = await dynamicImport('shiki-stream')\r\n return mod\r\n } catch {\r\n // 静默失败,返回 null\r\n return null\r\n }\r\n })()\r\n }\r\n return shikiStreamModulePromise\r\n}\r\n\r\nconst tokensToLineTokens = (tokens: HighlightToken[]): HighlightToken[][] => {\r\n if (!tokens.length) return [[]]\r\n\r\n const lines: HighlightToken[][] = [[]]\r\n let currentLine = lines[0]\r\n\r\n const startNewLine = () => {\r\n currentLine = []\r\n lines.push(currentLine)\r\n }\r\n\r\n tokens.forEach((token) => {\r\n const content = token.content ?? ''\r\n\r\n if (content === '\\n') {\r\n startNewLine()\r\n return\r\n }\r\n\r\n if (!content.includes('\\n')) {\r\n currentLine.push(token)\r\n return\r\n }\r\n\r\n const segments = content.split('\\n')\r\n segments.forEach((segment, index) => {\r\n if (segment) {\r\n currentLine.push({\r\n ...token,\r\n content: segment,\r\n })\r\n }\r\n\r\n if (index < segments.length - 1) {\r\n startNewLine()\r\n }\r\n })\r\n })\r\n\r\n return lines.length === 0 ? [[]] : lines\r\n}\r\n\r\nconst createPreStyle = (bg?: string, fg?: string): CSSProperties | undefined => {\r\n if (!bg && !fg) return undefined\r\n return {\r\n backgroundColor: bg,\r\n color: fg,\r\n }\r\n}\r\n\r\nexport function useHighlight(text: Ref<string>, options: UseHighlightOptions) {\r\n const streaming = ref<StreamingHighlightResult>()\r\n const isLoading = ref(false)\r\n const error = ref<Error | null>(null)\r\n\r\n let tokenizer: any | null = null\r\n let previousText = ''\r\n let highlighter: any | null = null\r\n let currentUsedLang = ''\r\n let lastRequestedLang = ''\r\n\r\n const effectiveTheme = computed(() => {\r\n const theme = isRef(options.theme) ? options.theme.value : options.theme\r\n return theme || 'slack-dark'\r\n })\r\n\r\n const effectiveLanguage = computed(() => {\r\n return toValue(options.language) || 'text'\r\n })\r\n\r\n const lines = computed(() => streaming.value?.lines || [[]])\r\n const preStyle = computed(() => streaming.value?.preStyle)\r\n\r\n const updateTokens = async (nextText: string, forceReset = false) => {\r\n if (!tokenizer) return\r\n\r\n if (forceReset) {\r\n tokenizer.clear()\r\n previousText = ''\r\n }\r\n\r\n const canAppend = !forceReset && nextText.startsWith(previousText)\r\n let chunk = nextText\r\n\r\n if (canAppend) {\r\n chunk = nextText.slice(previousText.length)\r\n } else if (!forceReset) {\r\n tokenizer.clear()\r\n }\r\n\r\n previousText = nextText\r\n\r\n if (!chunk) {\r\n const mergedTokens = [...tokenizer.tokensStable, ...tokenizer.tokensUnstable]\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: mergedTokens.length ? tokensToLineTokens(mergedTokens) : [[]],\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n return\r\n }\r\n\r\n try {\r\n await tokenizer.enqueue(chunk)\r\n\r\n const mergedTokens = [...tokenizer.tokensStable, ...tokenizer.tokensUnstable]\r\n\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: tokensToLineTokens(mergedTokens),\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n } catch (err) {\r\n console.error('[x-markdown] Streaming highlighting failed:', err)\r\n error.value = err as Error\r\n }\r\n }\r\n\r\n const initHighlighter = async () => {\r\n isLoading.value = true\r\n error.value = null\r\n\r\n let currentLang = effectiveLanguage.value\r\n const currentTheme = effectiveTheme.value\r\n\r\n try {\r\n const mod = await loadShiki()\r\n if (!mod) {\r\n // 静默降级为纯文本\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: text.value }]],\r\n preStyle: undefined,\r\n }\r\n showDependencyHint()\r\n return\r\n }\r\n\r\n // shiki 3.x API\r\n highlighter = await mod.createHighlighter({\r\n themes: [currentTheme],\r\n langs: [], // 将动态加载语言\r\n })\r\n\r\n lastRequestedLang = currentLang\r\n\r\n try {\r\n await highlighter.loadLanguage(currentLang as any)\r\n currentUsedLang = currentLang\r\n } catch {\r\n currentLang = 'plaintext'\r\n currentUsedLang = 'plaintext'\r\n }\r\n\r\n // 动态加载 shiki-stream\r\n const shikiStreamMod = await loadShikiStream()\r\n if (shikiStreamMod) {\r\n tokenizer = new shikiStreamMod.ShikiStreamTokenizer({\r\n highlighter: highlighter,\r\n lang: currentLang,\r\n theme: currentTheme,\r\n })\r\n }\r\n\r\n previousText = ''\r\n\r\n const themeInfo = highlighter.getTheme(currentTheme)\r\n const preStyleValue = createPreStyle(themeInfo?.bg, themeInfo?.fg)\r\n\r\n if (text.value) {\r\n await updateTokens(text.value, true)\r\n if (streaming.value) {\r\n streaming.value.preStyle = preStyleValue\r\n }\r\n } else {\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[]],\r\n preStyle: preStyleValue,\r\n }\r\n }\r\n } catch (err) {\r\n // 静默降级\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: text.value }]],\r\n preStyle: undefined,\r\n }\r\n } finally {\r\n isLoading.value = false\r\n }\r\n }\r\n\r\n watch(\r\n () => [effectiveLanguage.value, effectiveTheme.value],\r\n async ([newLang]) => {\r\n const requestedLang = newLang as string\r\n\r\n if (\r\n highlighter &&\r\n currentUsedLang === 'plaintext' &&\r\n requestedLang !== lastRequestedLang &&\r\n requestedLang !== 'plaintext'\r\n ) {\r\n try {\r\n await highlighter.loadLanguage(requestedLang as any)\r\n initHighlighter()\r\n return\r\n } catch {\r\n lastRequestedLang = requestedLang\r\n return\r\n }\r\n }\r\n\r\n initHighlighter()\r\n },\r\n { immediate: true },\r\n )\r\n\r\n watch(text, async (newText) => {\r\n const requestedLang = effectiveLanguage.value\r\n if (\r\n highlighter &&\r\n currentUsedLang === 'plaintext' &&\r\n requestedLang !== lastRequestedLang &&\r\n requestedLang !== 'plaintext'\r\n ) {\r\n try {\r\n await highlighter.loadLanguage(requestedLang as any)\r\n await initHighlighter()\r\n return\r\n } catch {\r\n lastRequestedLang = requestedLang\r\n }\r\n }\r\n\r\n if (tokenizer) {\r\n updateTokens(newText)\r\n } else if (!highlighter) {\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: newText }]],\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n }\r\n })\r\n\r\n onUnmounted(() => {\r\n tokenizer?.clear()\r\n tokenizer = null\r\n previousText = ''\r\n })\r\n\r\n return {\r\n streaming,\r\n lines,\r\n preStyle,\r\n isLoading,\r\n error,\r\n }\r\n}\r\n"],"names":[],"mappings":";AAsBA,IAAI,qBAAiD;AACrD,IAAI,2BAAuD;AAC3D,IAAI,yBAAyB;AAK7B,SAAS,cAAc,YAAkC;AAGvD,SAAO,IAAI,SAAS,oBAAoB,aAAa,IAAI,EAAA;AAC3D;AAEA,MAAM,qBAAqB,MAAM;AAC/B,MAAI,uBAAwB;AAC5B,2BAAyB;AAEzB,UAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEF,UAAQ;AAAA,IACN;AAAA,IACA;AAAA,EAAA;AAEF,UAAQ;AAAA,IACN;AAAA,IACA;AAAA,EAAA;AAEF,UAAQ;AAAA,IACN;AAAA,IACA;AAAA,EAAA;AAEJ;AAEA,MAAM,YAAY,YAAY;AAC5B,MAAI,CAAC,oBAAoB;AACvB,0BAAsB,YAAY;AAChC,UAAI;AACF,cAAM,MAAM,MAAM,cAAc,OAAO;AACvC,eAAO;AAAA,MACT,QAAQ;AAEN,eAAO;AAAA,MACT;AAAA,IACF,GAAA;AAAA,EACF;AACA,SAAO;AACT;AAEA,MAAM,kBAAkB,YAAY;AAClC,MAAI,CAAC,0BAA0B;AAC7B,gCAA4B,YAAY;AACtC,UAAI;AACF,cAAM,MAAM,MAAM,cAAc,cAAc;AAC9C,eAAO;AAAA,MACT,QAAQ;AAEN,eAAO;AAAA,MACT;AAAA,IACF,GAAA;AAAA,EACF;AACA,SAAO;AACT;AAEA,MAAM,qBAAqB,CAAC,WAAiD;AAC3E,MAAI,CAAC,OAAO,OAAQ,QAAO,CAAC,CAAA,CAAE;AAE9B,QAAM,QAA4B,CAAC,EAAE;AACrC,MAAI,cAAc,MAAM,CAAC;AAEzB,QAAM,eAAe,MAAM;AACzB,kBAAc,CAAA;AACd,UAAM,KAAK,WAAW;AAAA,EACxB;AAEA,SAAO,QAAQ,CAAC,UAAU;AACxB,UAAM,UAAU,MAAM,WAAW;AAEjC,QAAI,YAAY,MAAM;AACpB,mBAAA;AACA;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ,SAAS,IAAI,GAAG;AAC3B,kBAAY,KAAK,KAAK;AACtB;AAAA,IACF;AAEA,UAAM,WAAW,QAAQ,MAAM,IAAI;AACnC,aAAS,QAAQ,CAAC,SAAS,UAAU;AACnC,UAAI,SAAS;AACX,oBAAY,KAAK;AAAA,UACf,GAAG;AAAA,UACH,SAAS;AAAA,QAAA,CACV;AAAA,MACH;AAEA,UAAI,QAAQ,SAAS,SAAS,GAAG;AAC/B,qBAAA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,SAAO,MAAM,WAAW,IAAI,CAAC,CAAA,CAAE,IAAI;AACrC;AAEA,MAAM,iBAAiB,CAAC,IAAa,OAA2C;AAC9E,MAAI,CAAC,MAAM,CAAC,GAAI,QAAO;AACvB,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,OAAO;AAAA,EAAA;AAEX;AAEO,SAAS,aAAa,MAAmB,SAA8B;AAC5E,QAAM,YAAY,IAAA;AAClB,QAAM,YAAY,IAAI,KAAK;AAC3B,QAAM,QAAQ,IAAkB,IAAI;AAEpC,MAAI,YAAwB;AAC5B,MAAI,eAAe;AACnB,MAAI,cAA0B;AAC9B,MAAI,kBAAkB;AACtB,MAAI,oBAAoB;AAExB,QAAM,iBAAiB,SAAS,MAAM;AACpC,UAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,MAAM,QAAQ,QAAQ;AACnE,WAAO,SAAS;AAAA,EAClB,CAAC;AAED,QAAM,oBAAoB,SAAS,MAAM;AACvC,WAAO,QAAQ,QAAQ,QAAQ,KAAK;AAAA,EACtC,CAAC;AAED,QAAM,QAAQ,SAAS,MAAM,UAAU,OAAO,SAAS,CAAC,CAAA,CAAE,CAAC;AAC3D,QAAM,WAAW,SAAS,MAAM,UAAU,OAAO,QAAQ;AAEzD,QAAM,eAAe,OAAO,UAAkB,aAAa,UAAU;AACnE,QAAI,CAAC,UAAW;AAEhB,QAAI,YAAY;AACd,gBAAU,MAAA;AACV,qBAAe;AAAA,IACjB;AAEA,UAAM,YAAY,CAAC,cAAc,SAAS,WAAW,YAAY;AACjE,QAAI,QAAQ;AAEZ,QAAI,WAAW;AACb,cAAQ,SAAS,MAAM,aAAa,MAAM;AAAA,IAC5C,WAAW,CAAC,YAAY;AACtB,gBAAU,MAAA;AAAA,IACZ;AAEA,mBAAe;AAEf,QAAI,CAAC,OAAO;AACV,YAAM,eAAe,CAAC,GAAG,UAAU,cAAc,GAAG,UAAU,cAAc;AAC5E,gBAAU,QAAQ;AAAA,QAChB,mBAAmB,QAAQ;AAAA,QAC3B,OAAO,aAAa,SAAS,mBAAmB,YAAY,IAAI,CAAC,EAAE;AAAA,QACnE,UAAU,UAAU,OAAO;AAAA,MAAA;AAE7B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,UAAU,QAAQ,KAAK;AAE7B,YAAM,eAAe,CAAC,GAAG,UAAU,cAAc,GAAG,UAAU,cAAc;AAE5E,gBAAU,QAAQ;AAAA,QAChB,mBAAmB,QAAQ;AAAA,QAC3B,OAAO,mBAAmB,YAAY;AAAA,QACtC,UAAU,UAAU,OAAO;AAAA,MAAA;AAAA,IAE/B,SAAS,KAAK;AACZ,cAAQ,MAAM,+CAA+C,GAAG;AAChE,YAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,kBAAkB,YAAY;AAClC,cAAU,QAAQ;AAClB,UAAM,QAAQ;AAEd,QAAI,cAAc,kBAAkB;AACpC,UAAM,eAAe,eAAe;AAEpC,QAAI;AACF,YAAM,MAAM,MAAM,UAAA;AAClB,UAAI,CAAC,KAAK;AAER,kBAAU,QAAQ;AAAA,UAChB,mBAAmB,QAAQ;AAAA,UAC3B,OAAO,CAAC,CAAC,EAAE,SAAS,KAAK,MAAA,CAAO,CAAC;AAAA,UACjC,UAAU;AAAA,QAAA;AAEZ,2BAAA;AACA;AAAA,MACF;AAGA,oBAAc,MAAM,IAAI,kBAAkB;AAAA,QACxC,QAAQ,CAAC,YAAY;AAAA,QACrB,OAAO,CAAA;AAAA;AAAA,MAAC,CACT;AAED,0BAAoB;AAEpB,UAAI;AACF,cAAM,YAAY,aAAa,WAAkB;AACjD,0BAAkB;AAAA,MACpB,QAAQ;AACN,sBAAc;AACd,0BAAkB;AAAA,MACpB;AAGA,YAAM,iBAAiB,MAAM,gBAAA;AAC7B,UAAI,gBAAgB;AAClB,oBAAY,IAAI,eAAe,qBAAqB;AAAA,UAClD;AAAA,UACA,MAAM;AAAA,UACN,OAAO;AAAA,QAAA,CACR;AAAA,MACH;AAEA,qBAAe;AAEf,YAAM,YAAY,YAAY,SAAS,YAAY;AACnD,YAAM,gBAAgB,eAAe,WAAW,IAAI,WAAW,EAAE;AAEjE,UAAI,KAAK,OAAO;AACd,cAAM,aAAa,KAAK,OAAO,IAAI;AACnC,YAAI,UAAU,OAAO;AACnB,oBAAU,MAAM,WAAW;AAAA,QAC7B;AAAA,MACF,OAAO;AACL,kBAAU,QAAQ;AAAA,UAChB,mBAAmB,QAAQ;AAAA,UAC3B,OAAO,CAAC,CAAA,CAAE;AAAA,UACV,UAAU;AAAA,QAAA;AAAA,MAEd;AAAA,IACF,SAAS,KAAK;AAEZ,gBAAU,QAAQ;AAAA,QAChB,mBAAmB,QAAQ;AAAA,QAC3B,OAAO,CAAC,CAAC,EAAE,SAAS,KAAK,MAAA,CAAO,CAAC;AAAA,QACjC,UAAU;AAAA,MAAA;AAAA,IAEd,UAAA;AACE,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF;AAEA;AAAA,IACE,MAAM,CAAC,kBAAkB,OAAO,eAAe,KAAK;AAAA,IACpD,OAAO,CAAC,OAAO,MAAM;AACnB,YAAM,gBAAgB;AAEtB,UACE,eACA,oBAAoB,eACpB,kBAAkB,qBAClB,kBAAkB,aAClB;AACA,YAAI;AACF,gBAAM,YAAY,aAAa,aAAoB;AACnD,0BAAA;AACA;AAAA,QACF,QAAQ;AACN,8BAAoB;AACpB;AAAA,QACF;AAAA,MACF;AAEA,sBAAA;AAAA,IACF;AAAA,IACA,EAAE,WAAW,KAAA;AAAA,EAAK;AAGpB,QAAM,MAAM,OAAO,YAAY;AAC7B,UAAM,gBAAgB,kBAAkB;AACxC,QACE,eACA,oBAAoB,eACpB,kBAAkB,qBAClB,kBAAkB,aAClB;AACA,UAAI;AACF,cAAM,YAAY,aAAa,aAAoB;AACnD,cAAM,gBAAA;AACN;AAAA,MACF,QAAQ;AACN,4BAAoB;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,WAAW;AACb,mBAAa,OAAO;AAAA,IACtB,WAAW,CAAC,aAAa;AACvB,gBAAU,QAAQ;AAAA,QAChB,mBAAmB,QAAQ;AAAA,QAC3B,OAAO,CAAC,CAAC,EAAE,SAAS,QAAA,CAAS,CAAC;AAAA,QAC9B,UAAU,UAAU,OAAO;AAAA,MAAA;AAAA,IAE/B;AAAA,EACF,CAAC;AAED,cAAY,MAAM;AAChB,eAAW,MAAA;AACX,gBAAY;AACZ,mBAAe;AAAA,EACjB,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
1
+ {"version":3,"file":"x-markdown.es7.js","sources":["../src/hooks/useHighlight.ts"],"sourcesContent":["import { ref, watch, onUnmounted, computed, isRef, toValue, type Ref, type MaybeRef, type CSSProperties } from 'vue'\r\n\r\ninterface HighlightToken {\r\n content?: string\r\n color?: string\r\n fontStyle?: 'italic' | null\r\n fontWeight?: 'normal' | 'bold' | null\r\n htmlStyle?: Record<string, string>\r\n}\r\n\r\ninterface StreamingHighlightResult {\r\n colorReplacements?: Record<string, string>\r\n lines: HighlightToken[][]\r\n preStyle?: CSSProperties\r\n}\r\n\r\ninterface UseHighlightOptions {\r\n language: MaybeRef<string>\r\n theme?: string | Ref<string>\r\n colorReplacements?: Record<string, string>\r\n}\r\n\r\nlet shikiModulePromise: Promise<any | null> | null = null\r\nlet shikiStreamModulePromise: Promise<any | null> | null = null\r\nlet hasShownDependencyHint = false\r\n\r\n\r\nconst showDependencyHint = () => {\r\n if (hasShownDependencyHint) return\r\n hasShownDependencyHint = true\r\n\r\n console.log(\r\n '%c[x-markdown]%c 代码高亮功能已降级为纯文本模式',\r\n 'font-weight: bold; color: #0066cc;',\r\n 'color: #666;'\r\n )\r\n console.log(\r\n '%c如需语法高亮功能,请安装以下依赖:',\r\n 'color: #666; font-weight: bold;'\r\n )\r\n console.log(\r\n '%c pnpm add shiki shiki-stream',\r\n 'color: #00aa00; font-family: monospace;'\r\n )\r\n console.log(\r\n '%c安装后请重启开发服务器',\r\n 'color: #999; font-size: 12px;'\r\n )\r\n}\r\n\r\nconst loadShiki = async () => {\r\n if (!shikiModulePromise) {\r\n shikiModulePromise = (async () => {\r\n try {\r\n const mod = await import('shiki')\r\n return mod\r\n } catch {\r\n // 静默失败,返回 null\r\n return null\r\n }\r\n })()\r\n }\r\n return shikiModulePromise\r\n}\r\n\r\nconst loadShikiStream = async () => {\r\n if (!shikiStreamModulePromise) {\r\n shikiStreamModulePromise = (async () => {\r\n try {\r\n const mod = await import('shiki-stream')\r\n return mod\r\n } catch {\r\n // 静默失败,返回 null\r\n return null\r\n }\r\n })()\r\n }\r\n return shikiStreamModulePromise\r\n}\r\n\r\nconst tokensToLineTokens = (tokens: HighlightToken[]): HighlightToken[][] => {\r\n if (!tokens.length) return [[]]\r\n\r\n const lines: HighlightToken[][] = [[]]\r\n let currentLine = lines[0]\r\n\r\n const startNewLine = () => {\r\n currentLine = []\r\n lines.push(currentLine)\r\n }\r\n\r\n tokens.forEach((token) => {\r\n const content = token.content ?? ''\r\n\r\n if (content === '\\n') {\r\n startNewLine()\r\n return\r\n }\r\n\r\n if (!content.includes('\\n')) {\r\n currentLine.push(token)\r\n return\r\n }\r\n\r\n const segments = content.split('\\n')\r\n segments.forEach((segment, index) => {\r\n if (segment) {\r\n currentLine.push({\r\n ...token,\r\n content: segment,\r\n })\r\n }\r\n\r\n if (index < segments.length - 1) {\r\n startNewLine()\r\n }\r\n })\r\n })\r\n\r\n return lines.length === 0 ? [[]] : lines\r\n}\r\n\r\nconst createPreStyle = (bg?: string, fg?: string): CSSProperties | undefined => {\r\n if (!bg && !fg) return undefined\r\n return {\r\n backgroundColor: bg,\r\n color: fg,\r\n }\r\n}\r\n\r\nexport function useHighlight(text: Ref<string>, options: UseHighlightOptions) {\r\n const streaming = ref<StreamingHighlightResult>()\r\n const isLoading = ref(false)\r\n const error = ref<Error | null>(null)\r\n\r\n let tokenizer: any | null = null\r\n let previousText = ''\r\n let highlighter: any | null = null\r\n let currentUsedLang = ''\r\n let lastRequestedLang = ''\r\n\r\n const effectiveTheme = computed(() => {\r\n const theme = isRef(options.theme) ? options.theme.value : options.theme\r\n return theme || 'slack-dark'\r\n })\r\n\r\n const effectiveLanguage = computed(() => {\r\n return toValue(options.language) || 'text'\r\n })\r\n\r\n const lines = computed(() => streaming.value?.lines || [[]])\r\n const preStyle = computed(() => streaming.value?.preStyle)\r\n\r\n const updateTokens = async (nextText: string, forceReset = false) => {\r\n if (!tokenizer) return\r\n\r\n if (forceReset) {\r\n tokenizer.clear()\r\n previousText = ''\r\n }\r\n\r\n const canAppend = !forceReset && nextText.startsWith(previousText)\r\n let chunk = nextText\r\n\r\n if (canAppend) {\r\n chunk = nextText.slice(previousText.length)\r\n } else if (!forceReset) {\r\n tokenizer.clear()\r\n }\r\n\r\n previousText = nextText\r\n\r\n if (!chunk) {\r\n const mergedTokens = [...tokenizer.tokensStable, ...tokenizer.tokensUnstable]\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: mergedTokens.length ? tokensToLineTokens(mergedTokens) : [[]],\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n return\r\n }\r\n\r\n try {\r\n await tokenizer.enqueue(chunk)\r\n\r\n const mergedTokens = [...tokenizer.tokensStable, ...tokenizer.tokensUnstable]\r\n\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: tokensToLineTokens(mergedTokens),\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n } catch (err) {\r\n console.error('[x-markdown] Streaming highlighting failed:', err)\r\n error.value = err as Error\r\n }\r\n }\r\n\r\n const initHighlighter = async () => {\r\n isLoading.value = true\r\n error.value = null\r\n\r\n let currentLang = effectiveLanguage.value\r\n const currentTheme = effectiveTheme.value\r\n\r\n try {\r\n const mod = await loadShiki()\r\n if (!mod) {\r\n // 静默降级为纯文本\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: text.value }]],\r\n preStyle: undefined,\r\n }\r\n showDependencyHint()\r\n return\r\n }\r\n\r\n // shiki 3.x API\r\n highlighter = await mod.createHighlighter({\r\n themes: [currentTheme],\r\n langs: [], // 将动态加载语言\r\n })\r\n\r\n lastRequestedLang = currentLang\r\n\r\n try {\r\n await highlighter.loadLanguage(currentLang as any)\r\n currentUsedLang = currentLang\r\n } catch {\r\n currentLang = 'plaintext'\r\n currentUsedLang = 'plaintext'\r\n }\r\n\r\n // 动态加载 shiki-stream\r\n const shikiStreamMod = await loadShikiStream()\r\n if (shikiStreamMod) {\r\n tokenizer = new shikiStreamMod.ShikiStreamTokenizer({\r\n highlighter: highlighter,\r\n lang: currentLang,\r\n theme: currentTheme,\r\n })\r\n }\r\n\r\n previousText = ''\r\n\r\n const themeInfo = highlighter.getTheme(currentTheme)\r\n const preStyleValue = createPreStyle(themeInfo?.bg, themeInfo?.fg)\r\n\r\n if (text.value) {\r\n await updateTokens(text.value, true)\r\n if (streaming.value) {\r\n streaming.value.preStyle = preStyleValue\r\n }\r\n } else {\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[]],\r\n preStyle: preStyleValue,\r\n }\r\n }\r\n } catch (err) {\r\n // 静默降级\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: text.value }]],\r\n preStyle: undefined,\r\n }\r\n } finally {\r\n isLoading.value = false\r\n }\r\n }\r\n\r\n watch(\r\n () => [effectiveLanguage.value, effectiveTheme.value],\r\n async ([newLang]) => {\r\n const requestedLang = newLang as string\r\n\r\n if (\r\n highlighter &&\r\n currentUsedLang === 'plaintext' &&\r\n requestedLang !== lastRequestedLang &&\r\n requestedLang !== 'plaintext'\r\n ) {\r\n try {\r\n await highlighter.loadLanguage(requestedLang as any)\r\n initHighlighter()\r\n return\r\n } catch {\r\n lastRequestedLang = requestedLang\r\n return\r\n }\r\n }\r\n\r\n initHighlighter()\r\n },\r\n { immediate: true },\r\n )\r\n\r\n watch(text, async (newText) => {\r\n const requestedLang = effectiveLanguage.value\r\n if (\r\n highlighter &&\r\n currentUsedLang === 'plaintext' &&\r\n requestedLang !== lastRequestedLang &&\r\n requestedLang !== 'plaintext'\r\n ) {\r\n try {\r\n await highlighter.loadLanguage(requestedLang as any)\r\n await initHighlighter()\r\n return\r\n } catch {\r\n lastRequestedLang = requestedLang\r\n }\r\n }\r\n\r\n if (tokenizer) {\r\n updateTokens(newText)\r\n } else if (!highlighter) {\r\n streaming.value = {\r\n colorReplacements: options.colorReplacements,\r\n lines: [[{ content: newText }]],\r\n preStyle: streaming.value?.preStyle,\r\n }\r\n }\r\n })\r\n\r\n onUnmounted(() => {\r\n tokenizer?.clear()\r\n tokenizer = null\r\n previousText = ''\r\n })\r\n\r\n return {\r\n streaming,\r\n lines,\r\n preStyle,\r\n isLoading,\r\n error,\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
@@ -65,9 +65,6 @@ let mermaidPromise = null;
65
65
  let hasShownMermaidHint = false;
66
66
  let mermaidAvailableCache = null;
67
67
  let mermaidCheckPromise = null;
68
- function dynamicImport(moduleName) {
69
- return new Function('return import("' + moduleName + '")')();
70
- }
71
68
  async function checkMermaidAvailable() {
72
69
  if (mermaidAvailableCache !== null) {
73
70
  return mermaidAvailableCache;
@@ -77,7 +74,7 @@ async function checkMermaidAvailable() {
77
74
  }
78
75
  mermaidCheckPromise = (async () => {
79
76
  try {
80
- const mod = await dynamicImport("mermaid");
77
+ const mod = await import("mermaid");
81
78
  mermaidAvailableCache = !!mod;
82
79
  return mermaidAvailableCache;
83
80
  } catch (error) {
@@ -114,7 +111,7 @@ async function loadMermaid() {
114
111
  if (!mermaidPromise) {
115
112
  mermaidPromise = (async () => {
116
113
  try {
117
- const mod = await dynamicImport("mermaid");
114
+ const mod = await import("mermaid");
118
115
  return mod?.default;
119
116
  } catch (error) {
120
117
  console.error("[x-markdown] Failed to load mermaid:", error);
@@ -1 +1 @@
1
- {"version":3,"file":"x-markdown.es9.js","sources":["../src/hooks/useMermaid.ts"],"sourcesContent":["import type { Ref } from 'vue'\r\nimport { throttle } from 'lodash-es'\r\nimport { computed, ref, watch, onUnmounted } from 'vue'\r\nimport type { MermaidZoomControls, UseMermaidZoomOptions, UseMermaidResult } from '../components/Mermaid/types'\r\n\r\nexport function downloadSvgAsPng(svg: string): void {\r\n if (!svg) return\r\n\r\n try {\r\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`\r\n const img = new Image()\r\n\r\n img.onload = () => {\r\n try {\r\n const canvas = document.createElement('canvas')\r\n const ctx = canvas.getContext('2d', { willReadFrequently: false })\r\n if (!ctx) return\r\n\r\n const scale = 2\r\n canvas.width = img.width * scale\r\n canvas.height = img.height * scale\r\n ctx.imageSmoothingEnabled = true\r\n ctx.imageSmoothingQuality = 'high'\r\n\r\n ctx.fillStyle = '#ffffff'\r\n ctx.fillRect(0, 0, canvas.width, canvas.height)\r\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\r\n\r\n const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-')\r\n\r\n try {\r\n canvas.toBlob(\r\n (blob) => {\r\n if (!blob) return\r\n const url = URL.createObjectURL(blob)\r\n const link = document.createElement('a')\r\n link.href = url\r\n link.download = `mermaid-diagram-${timestamp}.png`\r\n document.body.appendChild(link)\r\n link.click()\r\n document.body.removeChild(link)\r\n URL.revokeObjectURL(url)\r\n },\r\n 'image/png',\r\n 0.95,\r\n )\r\n } catch (toBlobError) {\r\n console.error('Failed to convert canvas to blob:', toBlobError)\r\n try {\r\n const dataUrl = canvas.toDataURL('image/png', 0.95)\r\n const link = document.createElement('a')\r\n link.href = dataUrl\r\n link.download = `mermaid-diagram-${timestamp}.png`\r\n document.body.appendChild(link)\r\n link.click()\r\n document.body.removeChild(link)\r\n } catch (dataUrlError) {\r\n console.error('Failed to convert canvas to data URL:', dataUrlError)\r\n }\r\n }\r\n } catch (canvasError) {\r\n console.error('Canvas operation failed:', canvasError)\r\n }\r\n }\r\n\r\n img.onerror = (error) => {\r\n console.error('Failed to load image:', error)\r\n }\r\n\r\n img.src = svgDataUrl\r\n } catch (error) {\r\n console.error('Failed to download SVG:', error)\r\n }\r\n}\r\n\r\ninterface UseMermaidOptions {\r\n id?: string\r\n theme?: 'default' | 'dark' | 'forest' | 'neutral' | string\r\n config?: any\r\n container?: HTMLElement | Ref<HTMLElement | null> | null\r\n}\r\n\r\ntype UseMermaidOptionsInput = UseMermaidOptions | Ref<UseMermaidOptions>\r\n\r\nlet mermaidPromise: Promise<any> | null = null\r\nlet hasShownMermaidHint = false\r\nlet mermaidAvailableCache: boolean | null = null\r\nlet mermaidCheckPromise: Promise<boolean> | null = null\r\n\r\n/**\r\n * 真正的动态导入,使用 Function 构造器绕过 Vite 的 import-analysis\r\n */\r\nfunction dynamicImport(moduleName: string): Promise<any> {\r\n // 使用 Function 构造器来创建一个真正动态的 import\r\n // 这样 Vite 在 import-analysis 阶段不会尝试解析这个模块路径\r\n return new Function('return import(\"' + moduleName + '\")')()\r\n}\r\n\r\n/**\r\n * 同步检查缓存状态(不触发检测)\r\n * @returns 缓存状态,null 表示未检测\r\n */\r\nexport function getMermaidAvailableCache(): boolean | null {\r\n return mermaidAvailableCache\r\n}\r\n\r\n/**\r\n * 检测 mermaid 是否可用(全局缓存,只检测一次)\r\n */\r\nexport async function checkMermaidAvailable(): Promise<boolean> {\r\n // 如果已经有缓存结果,直接返回\r\n if (mermaidAvailableCache !== null) {\r\n return mermaidAvailableCache\r\n }\r\n\r\n // 如果正在检测,返回检测 Promise\r\n if (mermaidCheckPromise) {\r\n return mermaidCheckPromise\r\n }\r\n\r\n // 开始检测\r\n mermaidCheckPromise = (async () => {\r\n try {\r\n // 使用 dynamicImport 来绕过 Vite 的 import-analysis\r\n // mermaid 已在 vite.config.ts 中配置为 external,不会被打包进库\r\n const mod = await dynamicImport('mermaid')\r\n mermaidAvailableCache = !!mod\r\n return mermaidAvailableCache\r\n } catch (error) {\r\n console.error('[x-markdown] Failed to load mermaid:', error)\r\n mermaidAvailableCache = false\r\n return false\r\n }\r\n })()\r\n\r\n return mermaidCheckPromise\r\n}\r\n\r\nconst showMermaidHint = () => {\r\n if (hasShownMermaidHint) return\r\n hasShownMermaidHint = true\r\n\r\n console.log(\r\n '%c[x-markdown]%c Mermaid 图表功能已降级为代码块显示',\r\n 'font-weight: bold; color: #9333ea;',\r\n 'color: #666;'\r\n )\r\n console.log(\r\n '%c如需 Mermaid 图表渲染功能,请安装:',\r\n 'color: #666; font-weight: bold;'\r\n )\r\n console.log(\r\n '%c pnpm add mermaid',\r\n 'color: #9333ea; font-family: monospace;'\r\n )\r\n console.log(\r\n '%c安装后请重启开发服务器',\r\n 'color: #999; font-size: 12px;'\r\n )\r\n}\r\n\r\nasync function loadMermaid() {\r\n if (typeof window === 'undefined') return null\r\n if (!mermaidPromise) {\r\n mermaidPromise = (async () => {\r\n try {\r\n // 使用 dynamicImport 来绕过 Vite 的 import-analysis\r\n const mod = await dynamicImport('mermaid')\r\n return (mod as any)?.default\r\n } catch (error) {\r\n console.error('[x-markdown] Failed to load mermaid:', error)\r\n showMermaidHint()\r\n return null\r\n }\r\n })()\r\n }\r\n return mermaidPromise\r\n}\r\n\r\ntype RenderTask = () => Promise<void>\r\nconst renderQueue: RenderTask[] = []\r\nlet isProcessingQueue = false\r\n\r\nasync function processRenderQueue() {\r\n if (isProcessingQueue) return\r\n isProcessingQueue = true\r\n\r\n while (renderQueue.length > 0) {\r\n const task = renderQueue.shift()\r\n if (task) {\r\n try {\r\n await task()\r\n } catch (err) {\r\n console.error('Mermaid render queue error:', err)\r\n }\r\n }\r\n }\r\n\r\n isProcessingQueue = false\r\n}\r\n\r\nfunction addToRenderQueue(task: RenderTask) {\r\n renderQueue.push(task)\r\n processRenderQueue()\r\n}\r\n\r\nexport function useMermaid(content: string | Ref<string>, options: UseMermaidOptionsInput = {}): UseMermaidResult {\r\n const optionsRef = computed(() => (typeof options === 'object' && 'value' in options ? options.value : options))\r\n const mermaidConfig = computed(() => ({\r\n suppressErrorRendering: true,\r\n startOnLoad: false,\r\n securityLevel: 'loose',\r\n theme: optionsRef.value.theme || 'default',\r\n ...(optionsRef.value.config || {}),\r\n }))\r\n const data = ref('')\r\n const error = ref<unknown>(null)\r\n const isLoading = ref(false)\r\n\r\n let isUnmounted = false\r\n\r\n const getRenderContainer = () => {\r\n const containerOption = optionsRef.value.container\r\n if (containerOption) {\r\n return typeof containerOption === 'object' && 'value' in containerOption ? containerOption.value : containerOption\r\n }\r\n return null\r\n }\r\n\r\n const throttledRender = throttle(\r\n () => {\r\n const contentValue = typeof content === 'string' ? content : content.value\r\n if (!contentValue?.trim()) {\r\n data.value = ''\r\n error.value = null\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n isLoading.value = true\r\n\r\n addToRenderQueue(async () => {\r\n if (isUnmounted) return\r\n\r\n try {\r\n const mermaidInstance = await loadMermaid()\r\n if (!mermaidInstance) {\r\n data.value = contentValue\r\n error.value = null\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n mermaidInstance.initialize(mermaidConfig.value)\r\n\r\n const isValid = await mermaidInstance.parse(contentValue.trim())\r\n if (!isValid) {\r\n data.value = ''\r\n error.value = new Error('Mermaid parse error: Invalid syntax')\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n const renderId = `${optionsRef.value.id || 'mermaid'}-${Math.random().toString(36).substring(2, 11)}`\r\n const container = getRenderContainer()\r\n if (!container) {\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n const { svg } = await mermaidInstance.render(renderId, contentValue, container)\r\n data.value = svg\r\n error.value = null\r\n isLoading.value = false\r\n } catch (err) {\r\n // Mermaid render error\r\n data.value = ''\r\n error.value = err\r\n isLoading.value = false\r\n }\r\n })\r\n },\r\n 100,\r\n { leading: false, trailing: true },\r\n )\r\n\r\n watch(\r\n [() => (typeof content === 'string' ? content : content.value), () => mermaidConfig.value],\r\n () => {\r\n throttledRender()\r\n },\r\n { immediate: true },\r\n )\r\n\r\n onUnmounted(() => {\r\n isUnmounted = true\r\n })\r\n\r\n return {\r\n data,\r\n error,\r\n isLoading,\r\n }\r\n}\r\n\r\nexport function useMermaidZoom(options: UseMermaidZoomOptions): MermaidZoomControls {\r\n const { container } = options\r\n\r\n const scale = ref(1)\r\n const posX = ref(0)\r\n const posY = ref(0)\r\n const isDragging = ref(false)\r\n\r\n let removeEvents: (() => void) | null = null\r\n\r\n const getSvg = () => container.value?.querySelector('.syntax-mermaid__content svg') as HTMLElement\r\n\r\n const updateTransform = (svg: HTMLElement) => {\r\n svg.style.transformOrigin = 'center center'\r\n svg.style.transform = `translate(${posX.value}px, ${posY.value}px) scale(${scale.value})`\r\n }\r\n\r\n const resetState = () => {\r\n scale.value = 1\r\n posX.value = 0\r\n posY.value = 0\r\n isDragging.value = false\r\n }\r\n\r\n const addInteractionEvents = (containerEl: HTMLElement) => {\r\n let startX = 0\r\n let startY = 0\r\n let isInteractingWithMermaid = false\r\n\r\n const onStart = (clientX: number, clientY: number) => {\r\n isDragging.value = true\r\n startX = clientX - posX.value\r\n startY = clientY - posY.value\r\n document.body.style.userSelect = 'none'\r\n }\r\n\r\n const onMove = (clientX: number, clientY: number) => {\r\n if (isDragging.value && isInteractingWithMermaid) {\r\n posX.value = clientX - startX\r\n posY.value = clientY - startY\r\n const svg = getSvg()\r\n if (svg) {\r\n updateTransform(svg)\r\n }\r\n }\r\n }\r\n\r\n const onEnd = () => {\r\n isDragging.value = false\r\n isInteractingWithMermaid = false\r\n document.body.style.userSelect = ''\r\n }\r\n\r\n const onMouseDown = (e: MouseEvent) => {\r\n if (e.button !== 0) return\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n e.preventDefault()\r\n isInteractingWithMermaid = true\r\n onStart(e.clientX, e.clientY)\r\n }\r\n }\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n if (isInteractingWithMermaid) {\r\n onMove(e.clientX, e.clientY)\r\n }\r\n }\r\n\r\n const handleWheelZoom = (e: WheelEvent) => {\r\n const svg = getSvg()\r\n if (!svg) return\r\n\r\n const containerRect = containerEl.getBoundingClientRect()\r\n const svgRect = svg.getBoundingClientRect()\r\n\r\n const mouseX = e.clientX - containerRect.left\r\n const mouseY = e.clientY - containerRect.top\r\n\r\n const svgCenterX = svgRect.left - containerRect.left + svgRect.width / 2\r\n const svgCenterY = svgRect.top - containerRect.top + svgRect.height / 2\r\n\r\n const offsetX = (mouseX - svgCenterX - posX.value) / scale.value\r\n const offsetY = (mouseY - svgCenterY - posY.value) / scale.value\r\n\r\n const delta = e.deltaY > 0 ? -0.05 : 0.05\r\n const newScale = Math.min(Math.max(scale.value + delta, 0.1), 10)\r\n\r\n if (newScale === scale.value) return\r\n\r\n scale.value = newScale\r\n\r\n posX.value = mouseX - svgCenterX - offsetX * scale.value\r\n posY.value = mouseY - svgCenterY - offsetY * scale.value\r\n\r\n updateTransform(svg)\r\n }\r\n\r\n const throttledWheelZoom = throttle(handleWheelZoom, 20, { leading: true, trailing: true })\r\n\r\n const onWheel = (e: WheelEvent) => {\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n e.preventDefault()\r\n throttledWheelZoom(e)\r\n }\r\n }\r\n\r\n const onTouchStart = (e: TouchEvent) => {\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n if (e.touches.length === 1) {\r\n e.preventDefault()\r\n isInteractingWithMermaid = true\r\n onStart(e.touches[0].clientX, e.touches[0].clientY)\r\n }\r\n }\r\n }\r\n\r\n const onTouchMove = (e: TouchEvent) => {\r\n if (isInteractingWithMermaid) {\r\n e.preventDefault()\r\n onMove(e.touches[0].clientX, e.touches[0].clientY)\r\n }\r\n }\r\n\r\n containerEl.addEventListener('mousedown', onMouseDown)\r\n document.addEventListener('mousemove', onMouseMove)\r\n document.addEventListener('mouseup', onEnd)\r\n containerEl.addEventListener('wheel', onWheel, { passive: false })\r\n containerEl.addEventListener('touchstart', onTouchStart, { passive: false })\r\n containerEl.addEventListener('touchmove', onTouchMove, { passive: false })\r\n document.addEventListener('touchend', onEnd)\r\n\r\n return () => {\r\n containerEl.removeEventListener('mousedown', onMouseDown)\r\n document.removeEventListener('mousemove', onMouseMove)\r\n document.removeEventListener('mouseup', onEnd)\r\n containerEl.removeEventListener('wheel', onWheel)\r\n containerEl.removeEventListener('touchstart', onTouchStart)\r\n containerEl.removeEventListener('touchmove', onTouchMove)\r\n document.removeEventListener('touchend', onEnd)\r\n document.body.style.userSelect = ''\r\n }\r\n }\r\n\r\n const zoomIn = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n scale.value = Math.min(scale.value + 0.2, 10)\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const zoomOut = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n scale.value = Math.max(scale.value - 0.2, 0.1)\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const reset = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n resetState()\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const fullscreen = () => {\r\n if (!container.value) return\r\n\r\n if (document.fullscreenElement) {\r\n document.exitFullscreen()\r\n } else {\r\n container.value.requestFullscreen?.()\r\n }\r\n }\r\n\r\n const initialize = () => {\r\n if (!container.value) return\r\n\r\n resetState()\r\n\r\n removeEvents = addInteractionEvents(container.value)\r\n\r\n const svg = getSvg()\r\n if (svg) {\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const destroy = () => {\r\n removeEvents?.()\r\n removeEvents = null\r\n resetState()\r\n }\r\n\r\n watch(\r\n () => container.value,\r\n () => {\r\n destroy()\r\n resetState()\r\n },\r\n )\r\n\r\n onUnmounted(destroy)\r\n\r\n return {\r\n zoomIn,\r\n zoomOut,\r\n reset,\r\n fullscreen,\r\n destroy,\r\n initialize,\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"x-markdown.es9.js","sources":["../src/hooks/useMermaid.ts"],"sourcesContent":["import type { Ref } from 'vue'\r\nimport { throttle } from 'lodash-es'\r\nimport { computed, ref, watch, onUnmounted } from 'vue'\r\nimport type { MermaidZoomControls, UseMermaidZoomOptions, UseMermaidResult } from '../components/Mermaid/types'\r\n\r\nexport function downloadSvgAsPng(svg: string): void {\r\n if (!svg) return\r\n\r\n try {\r\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`\r\n const img = new Image()\r\n\r\n img.onload = () => {\r\n try {\r\n const canvas = document.createElement('canvas')\r\n const ctx = canvas.getContext('2d', { willReadFrequently: false })\r\n if (!ctx) return\r\n\r\n const scale = 2\r\n canvas.width = img.width * scale\r\n canvas.height = img.height * scale\r\n ctx.imageSmoothingEnabled = true\r\n ctx.imageSmoothingQuality = 'high'\r\n\r\n ctx.fillStyle = '#ffffff'\r\n ctx.fillRect(0, 0, canvas.width, canvas.height)\r\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\r\n\r\n const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-')\r\n\r\n try {\r\n canvas.toBlob(\r\n (blob) => {\r\n if (!blob) return\r\n const url = URL.createObjectURL(blob)\r\n const link = document.createElement('a')\r\n link.href = url\r\n link.download = `mermaid-diagram-${timestamp}.png`\r\n document.body.appendChild(link)\r\n link.click()\r\n document.body.removeChild(link)\r\n URL.revokeObjectURL(url)\r\n },\r\n 'image/png',\r\n 0.95,\r\n )\r\n } catch (toBlobError) {\r\n console.error('Failed to convert canvas to blob:', toBlobError)\r\n try {\r\n const dataUrl = canvas.toDataURL('image/png', 0.95)\r\n const link = document.createElement('a')\r\n link.href = dataUrl\r\n link.download = `mermaid-diagram-${timestamp}.png`\r\n document.body.appendChild(link)\r\n link.click()\r\n document.body.removeChild(link)\r\n } catch (dataUrlError) {\r\n console.error('Failed to convert canvas to data URL:', dataUrlError)\r\n }\r\n }\r\n } catch (canvasError) {\r\n console.error('Canvas operation failed:', canvasError)\r\n }\r\n }\r\n\r\n img.onerror = (error) => {\r\n console.error('Failed to load image:', error)\r\n }\r\n\r\n img.src = svgDataUrl\r\n } catch (error) {\r\n console.error('Failed to download SVG:', error)\r\n }\r\n}\r\n\r\ninterface UseMermaidOptions {\r\n id?: string\r\n theme?: 'default' | 'dark' | 'forest' | 'neutral' | string\r\n config?: any\r\n container?: HTMLElement | Ref<HTMLElement | null> | null\r\n}\r\n\r\ntype UseMermaidOptionsInput = UseMermaidOptions | Ref<UseMermaidOptions>\r\n\r\nlet mermaidPromise: Promise<any> | null = null\r\nlet hasShownMermaidHint = false\r\nlet mermaidAvailableCache: boolean | null = null\r\nlet mermaidCheckPromise: Promise<boolean> | null = null\r\n\r\n/**\r\n * 同步检查缓存状态(不触发检测)\r\n * @returns 缓存状态,null 表示未检测\r\n */\r\nexport function getMermaidAvailableCache(): boolean | null {\r\n return mermaidAvailableCache\r\n}\r\n\r\n/**\r\n * 检测 mermaid 是否可用(全局缓存,只检测一次)\r\n */\r\nexport async function checkMermaidAvailable(): Promise<boolean> {\r\n // 如果已经有缓存结果,直接返回\r\n if (mermaidAvailableCache !== null) {\r\n return mermaidAvailableCache\r\n }\r\n\r\n // 如果正在检测,返回检测 Promise\r\n if (mermaidCheckPromise) {\r\n return mermaidCheckPromise\r\n }\r\n\r\n // 开始检测\r\n mermaidCheckPromise = (async () => {\r\n try {\r\n const mod = await import('mermaid')\r\n mermaidAvailableCache = !!mod\r\n return mermaidAvailableCache\r\n } catch (error) {\r\n console.error('[x-markdown] Failed to load mermaid:', error)\r\n mermaidAvailableCache = false\r\n return false\r\n }\r\n })()\r\n\r\n return mermaidCheckPromise\r\n}\r\n\r\nconst showMermaidHint = () => {\r\n if (hasShownMermaidHint) return\r\n hasShownMermaidHint = true\r\n\r\n console.log(\r\n '%c[x-markdown]%c Mermaid 图表功能已降级为代码块显示',\r\n 'font-weight: bold; color: #9333ea;',\r\n 'color: #666;'\r\n )\r\n console.log(\r\n '%c如需 Mermaid 图表渲染功能,请安装:',\r\n 'color: #666; font-weight: bold;'\r\n )\r\n console.log(\r\n '%c pnpm add mermaid',\r\n 'color: #9333ea; font-family: monospace;'\r\n )\r\n console.log(\r\n '%c安装后请重启开发服务器',\r\n 'color: #999; font-size: 12px;'\r\n )\r\n}\r\n\r\nasync function loadMermaid() {\r\n if (typeof window === 'undefined') return null\r\n if (!mermaidPromise) {\r\n mermaidPromise = (async () => {\r\n try {\r\n const mod = await import('mermaid')\r\n return (mod as any)?.default\r\n } catch (error) {\r\n console.error('[x-markdown] Failed to load mermaid:', error)\r\n showMermaidHint()\r\n return null\r\n }\r\n })()\r\n }\r\n return mermaidPromise\r\n}\r\n\r\ntype RenderTask = () => Promise<void>\r\nconst renderQueue: RenderTask[] = []\r\nlet isProcessingQueue = false\r\n\r\nasync function processRenderQueue() {\r\n if (isProcessingQueue) return\r\n isProcessingQueue = true\r\n\r\n while (renderQueue.length > 0) {\r\n const task = renderQueue.shift()\r\n if (task) {\r\n try {\r\n await task()\r\n } catch (err) {\r\n console.error('Mermaid render queue error:', err)\r\n }\r\n }\r\n }\r\n\r\n isProcessingQueue = false\r\n}\r\n\r\nfunction addToRenderQueue(task: RenderTask) {\r\n renderQueue.push(task)\r\n processRenderQueue()\r\n}\r\n\r\nexport function useMermaid(content: string | Ref<string>, options: UseMermaidOptionsInput = {}): UseMermaidResult {\r\n const optionsRef = computed(() => (typeof options === 'object' && 'value' in options ? options.value : options))\r\n const mermaidConfig = computed(() => ({\r\n suppressErrorRendering: true,\r\n startOnLoad: false,\r\n securityLevel: 'loose',\r\n theme: optionsRef.value.theme || 'default',\r\n ...(optionsRef.value.config || {}),\r\n }))\r\n const data = ref('')\r\n const error = ref<unknown>(null)\r\n const isLoading = ref(false)\r\n\r\n let isUnmounted = false\r\n\r\n const getRenderContainer = () => {\r\n const containerOption = optionsRef.value.container\r\n if (containerOption) {\r\n return typeof containerOption === 'object' && 'value' in containerOption ? containerOption.value : containerOption\r\n }\r\n return null\r\n }\r\n\r\n const throttledRender = throttle(\r\n () => {\r\n const contentValue = typeof content === 'string' ? content : content.value\r\n if (!contentValue?.trim()) {\r\n data.value = ''\r\n error.value = null\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n isLoading.value = true\r\n\r\n addToRenderQueue(async () => {\r\n if (isUnmounted) return\r\n\r\n try {\r\n const mermaidInstance = await loadMermaid()\r\n if (!mermaidInstance) {\r\n data.value = contentValue\r\n error.value = null\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n mermaidInstance.initialize(mermaidConfig.value)\r\n\r\n const isValid = await mermaidInstance.parse(contentValue.trim())\r\n if (!isValid) {\r\n data.value = ''\r\n error.value = new Error('Mermaid parse error: Invalid syntax')\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n const renderId = `${optionsRef.value.id || 'mermaid'}-${Math.random().toString(36).substring(2, 11)}`\r\n const container = getRenderContainer()\r\n if (!container) {\r\n isLoading.value = false\r\n return\r\n }\r\n\r\n const { svg } = await mermaidInstance.render(renderId, contentValue, container)\r\n data.value = svg\r\n error.value = null\r\n isLoading.value = false\r\n } catch (err) {\r\n // Mermaid render error\r\n data.value = ''\r\n error.value = err\r\n isLoading.value = false\r\n }\r\n })\r\n },\r\n 100,\r\n { leading: false, trailing: true },\r\n )\r\n\r\n watch(\r\n [() => (typeof content === 'string' ? content : content.value), () => mermaidConfig.value],\r\n () => {\r\n throttledRender()\r\n },\r\n { immediate: true },\r\n )\r\n\r\n onUnmounted(() => {\r\n isUnmounted = true\r\n })\r\n\r\n return {\r\n data,\r\n error,\r\n isLoading,\r\n }\r\n}\r\n\r\nexport function useMermaidZoom(options: UseMermaidZoomOptions): MermaidZoomControls {\r\n const { container } = options\r\n\r\n const scale = ref(1)\r\n const posX = ref(0)\r\n const posY = ref(0)\r\n const isDragging = ref(false)\r\n\r\n let removeEvents: (() => void) | null = null\r\n\r\n const getSvg = () => container.value?.querySelector('.syntax-mermaid__content svg') as HTMLElement\r\n\r\n const updateTransform = (svg: HTMLElement) => {\r\n svg.style.transformOrigin = 'center center'\r\n svg.style.transform = `translate(${posX.value}px, ${posY.value}px) scale(${scale.value})`\r\n }\r\n\r\n const resetState = () => {\r\n scale.value = 1\r\n posX.value = 0\r\n posY.value = 0\r\n isDragging.value = false\r\n }\r\n\r\n const addInteractionEvents = (containerEl: HTMLElement) => {\r\n let startX = 0\r\n let startY = 0\r\n let isInteractingWithMermaid = false\r\n\r\n const onStart = (clientX: number, clientY: number) => {\r\n isDragging.value = true\r\n startX = clientX - posX.value\r\n startY = clientY - posY.value\r\n document.body.style.userSelect = 'none'\r\n }\r\n\r\n const onMove = (clientX: number, clientY: number) => {\r\n if (isDragging.value && isInteractingWithMermaid) {\r\n posX.value = clientX - startX\r\n posY.value = clientY - startY\r\n const svg = getSvg()\r\n if (svg) {\r\n updateTransform(svg)\r\n }\r\n }\r\n }\r\n\r\n const onEnd = () => {\r\n isDragging.value = false\r\n isInteractingWithMermaid = false\r\n document.body.style.userSelect = ''\r\n }\r\n\r\n const onMouseDown = (e: MouseEvent) => {\r\n if (e.button !== 0) return\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n e.preventDefault()\r\n isInteractingWithMermaid = true\r\n onStart(e.clientX, e.clientY)\r\n }\r\n }\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n if (isInteractingWithMermaid) {\r\n onMove(e.clientX, e.clientY)\r\n }\r\n }\r\n\r\n const handleWheelZoom = (e: WheelEvent) => {\r\n const svg = getSvg()\r\n if (!svg) return\r\n\r\n const containerRect = containerEl.getBoundingClientRect()\r\n const svgRect = svg.getBoundingClientRect()\r\n\r\n const mouseX = e.clientX - containerRect.left\r\n const mouseY = e.clientY - containerRect.top\r\n\r\n const svgCenterX = svgRect.left - containerRect.left + svgRect.width / 2\r\n const svgCenterY = svgRect.top - containerRect.top + svgRect.height / 2\r\n\r\n const offsetX = (mouseX - svgCenterX - posX.value) / scale.value\r\n const offsetY = (mouseY - svgCenterY - posY.value) / scale.value\r\n\r\n const delta = e.deltaY > 0 ? -0.05 : 0.05\r\n const newScale = Math.min(Math.max(scale.value + delta, 0.1), 10)\r\n\r\n if (newScale === scale.value) return\r\n\r\n scale.value = newScale\r\n\r\n posX.value = mouseX - svgCenterX - offsetX * scale.value\r\n posY.value = mouseY - svgCenterY - offsetY * scale.value\r\n\r\n updateTransform(svg)\r\n }\r\n\r\n const throttledWheelZoom = throttle(handleWheelZoom, 20, { leading: true, trailing: true })\r\n\r\n const onWheel = (e: WheelEvent) => {\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n e.preventDefault()\r\n throttledWheelZoom(e)\r\n }\r\n }\r\n\r\n const onTouchStart = (e: TouchEvent) => {\r\n if (e.target === containerEl || containerEl.contains(e.target as Node)) {\r\n if (e.touches.length === 1) {\r\n e.preventDefault()\r\n isInteractingWithMermaid = true\r\n onStart(e.touches[0].clientX, e.touches[0].clientY)\r\n }\r\n }\r\n }\r\n\r\n const onTouchMove = (e: TouchEvent) => {\r\n if (isInteractingWithMermaid) {\r\n e.preventDefault()\r\n onMove(e.touches[0].clientX, e.touches[0].clientY)\r\n }\r\n }\r\n\r\n containerEl.addEventListener('mousedown', onMouseDown)\r\n document.addEventListener('mousemove', onMouseMove)\r\n document.addEventListener('mouseup', onEnd)\r\n containerEl.addEventListener('wheel', onWheel, { passive: false })\r\n containerEl.addEventListener('touchstart', onTouchStart, { passive: false })\r\n containerEl.addEventListener('touchmove', onTouchMove, { passive: false })\r\n document.addEventListener('touchend', onEnd)\r\n\r\n return () => {\r\n containerEl.removeEventListener('mousedown', onMouseDown)\r\n document.removeEventListener('mousemove', onMouseMove)\r\n document.removeEventListener('mouseup', onEnd)\r\n containerEl.removeEventListener('wheel', onWheel)\r\n containerEl.removeEventListener('touchstart', onTouchStart)\r\n containerEl.removeEventListener('touchmove', onTouchMove)\r\n document.removeEventListener('touchend', onEnd)\r\n document.body.style.userSelect = ''\r\n }\r\n }\r\n\r\n const zoomIn = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n scale.value = Math.min(scale.value + 0.2, 10)\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const zoomOut = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n scale.value = Math.max(scale.value - 0.2, 0.1)\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const reset = () => {\r\n const svg = getSvg()\r\n if (svg) {\r\n resetState()\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const fullscreen = () => {\r\n if (!container.value) return\r\n\r\n if (document.fullscreenElement) {\r\n document.exitFullscreen()\r\n } else {\r\n container.value.requestFullscreen?.()\r\n }\r\n }\r\n\r\n const initialize = () => {\r\n if (!container.value) return\r\n\r\n resetState()\r\n\r\n removeEvents = addInteractionEvents(container.value)\r\n\r\n const svg = getSvg()\r\n if (svg) {\r\n updateTransform(svg)\r\n }\r\n }\r\n\r\n const destroy = () => {\r\n removeEvents?.()\r\n removeEvents = null\r\n resetState()\r\n }\r\n\r\n watch(\r\n () => container.value,\r\n () => {\r\n destroy()\r\n resetState()\r\n },\r\n )\r\n\r\n onUnmounted(destroy)\r\n\r\n return {\r\n zoomIn,\r\n zoomOut,\r\n reset,\r\n fullscreen,\r\n destroy,\r\n initialize,\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hejiayue/x-markdown-test",
3
- "version": "0.0.1-beta.130",
3
+ "version": "0.0.1-beta.131",
4
4
  "description": "A markdown component library for Vue",
5
5
  "type": "module",
6
6
  "main": "./dist/x-markdown.cjs.js",