@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 6.08 kB
Source Map (JSON)
{"version":3,"file":"useMermaidCdn.mjs","names":[],"sources":["../../src/hooks/useMermaidCdn.ts"],"sourcesContent":["'use client';\n\ninterface CdnMermaidConfig {\n fontFamily?: string;\n gantt?: { useWidth?: number };\n securityLevel?: string;\n startOnLoad?: boolean;\n theme?: string;\n themeVariables?: Record<string, string | undefined>;\n}\n\ninterface CdnMermaidApi {\n initialize: (config: CdnMermaidConfig) => void;\n render: (id: string, content: string) => Promise<{ svg: string }>;\n}\n\nconst DEFAULT_MERMAID_CDN_URL = 'https://esm.sh/mermaid@11';\n\nlet mermaidCdnUrl = DEFAULT_MERMAID_CDN_URL;\nlet mermaidPromise: Promise<CdnMermaidApi | null> | null = null;\n\n/**\n * Point the fallback loader at a mirror, or at a self-hosted copy for offline\n * and strict-CSP deployments. Resets any in-flight load.\n */\nexport const setMermaidCdnUrl = (url: string) => {\n if (url === mermaidCdnUrl) return;\n mermaidCdnUrl = url;\n mermaidPromise = null;\n};\n\nexport const getMermaidCdnUrl = () => mermaidCdnUrl;\n\nexport const loadCdnMermaid = (): Promise<CdnMermaidApi | null> => {\n if (typeof window === 'undefined') return Promise.resolve(null);\n\n mermaidPromise ??= import(/* @vite-ignore */ mermaidCdnUrl)\n .then((mod) => (mod.default ?? mod) as CdnMermaidApi)\n .catch(() => null);\n\n return mermaidPromise;\n};\n\n/**\n * Upstream mermaid runs colour maths over themeVariables, so it needs literal\n * values rather than var() references. Reading antd's CSS variables here keeps\n * the cost off the render path — no theme context subscription, and it only\n * runs for the diagram types that actually fall back to the CDN.\n */\nconst readCssVars = <T extends string>(names: Record<T, string>): Record<T, string | undefined> => {\n const result = {} as Record<T, string | undefined>;\n if (typeof document === 'undefined') return result;\n\n const computed = globalThis.getComputedStyle(document.documentElement);\n for (const [key, variable] of Object.entries(names) as [T, string][]) {\n result[key] = computed.getPropertyValue(variable).trim() || undefined;\n }\n return result;\n};\n\nexport const createCdnMermaidConfig = (\n isDarkMode: boolean,\n customTheme?: string,\n): CdnMermaidConfig => {\n const token = readCssVars({\n border: '--ant-color-border',\n error: '--ant-color-error',\n fontFamily: '--ant-font-family',\n fontFamilyCode: '--ant-font-family-code',\n infoBg: '--ant-color-info-bg',\n infoBorder: '--ant-color-info-border',\n infoText: '--ant-color-info-text',\n primary: '--ant-color-primary',\n success: '--ant-color-success',\n successBg: '--ant-color-success-bg',\n successBorder: '--ant-color-success-border',\n successText: '--ant-color-success-text',\n text: '--ant-color-text',\n textDescription: '--ant-color-text-description',\n textSecondary: '--ant-color-text-secondary',\n bgContainer: '--ant-color-bg-container',\n warning: '--ant-color-warning',\n });\n\n return {\n fontFamily: token.fontFamilyCode,\n gantt: { useWidth: 1920 },\n // SECURITY: 'strict' keeps Mermaid from rendering node labels via innerHTML,\n // which would be an XSS vector for model-generated diagram content.\n securityLevel: 'strict',\n startOnLoad: false,\n theme: customTheme || (isDarkMode ? 'dark' : 'neutral'),\n themeVariables: customTheme\n ? undefined\n : {\n errorBkgColor: token.textDescription,\n errorTextColor: token.textDescription,\n fontFamily: token.fontFamily,\n lineColor: token.textSecondary,\n mainBkg: token.bgContainer,\n noteBkgColor: token.infoBg,\n noteTextColor: token.infoText,\n pie1: token.primary,\n pie2: token.warning,\n pie3: token.success,\n pie4: token.error,\n primaryBorderColor: token.border,\n primaryColor: token.bgContainer,\n primaryTextColor: token.text,\n secondaryBorderColor: token.infoBorder,\n secondaryColor: token.infoBg,\n secondaryTextColor: token.infoText,\n tertiaryBorderColor: token.successBorder,\n tertiaryColor: token.successBg,\n tertiaryTextColor: token.successText,\n textColor: token.text,\n },\n };\n};\n\nexport const renderWithCdnMermaid = async (\n content: string,\n id: string,\n config: CdnMermaidConfig,\n): Promise<string> => {\n const mermaid = await loadCdnMermaid();\n if (!mermaid) return '';\n\n mermaid.initialize(config);\n const { svg } = await mermaid.render(id, content);\n return svg;\n};\n"],"mappings":";;AAkBA,IAAI,gBAAgB;AACpB,IAAI,iBAAuD;;;;;AAM3D,MAAa,oBAAoB,QAAgB;CAC/C,IAAI,QAAQ,eAAe;CAC3B,gBAAgB;CAChB,iBAAiB;AACnB;AAEA,MAAa,yBAAyB;AAEtC,MAAa,uBAAsD;CACjE,IAAI,OAAO,WAAW,aAAa,OAAO,QAAQ,QAAQ,IAAI;CAE9D,mBAAmB;;EAA0B;CAAc,CACxD,MAAM,QAAS,IAAI,WAAW,GAAqB,CAAC,CACpD,YAAY,IAAI;CAEnB,OAAO;AACT;;;;;;;AAQA,MAAM,eAAiC,UAA4D;CACjG,MAAM,SAAS,CAAC;CAChB,IAAI,OAAO,aAAa,aAAa,OAAO;CAE5C,MAAM,WAAW,WAAW,iBAAiB,SAAS,eAAe;CACrE,KAAK,MAAM,CAAC,KAAK,aAAa,OAAO,QAAQ,KAAK,GAChD,OAAO,OAAO,SAAS,iBAAiB,QAAQ,CAAC,CAAC,KAAK,KAAK,KAAA;CAE9D,OAAO;AACT;AAEA,MAAa,0BACX,YACA,gBACqB;CACrB,MAAM,QAAQ,YAAY;EACxB,QAAQ;EACR,OAAO;EACP,YAAY;EACZ,gBAAgB;EAChB,QAAQ;EACR,YAAY;EACZ,UAAU;EACV,SAAS;EACT,SAAS;EACT,WAAW;EACX,eAAe;EACf,aAAa;EACb,MAAM;EACN,iBAAiB;EACjB,eAAe;EACf,aAAa;EACb,SAAS;CACX,CAAC;CAED,OAAO;EACL,YAAY,MAAM;EAClB,OAAO,EAAE,UAAU,KAAK;EAGxB,eAAe;EACf,aAAa;EACb,OAAO,gBAAgB,aAAa,SAAS;EAC7C,gBAAgB,cACZ,KAAA,IACA;GACE,eAAe,MAAM;GACrB,gBAAgB,MAAM;GACtB,YAAY,MAAM;GAClB,WAAW,MAAM;GACjB,SAAS,MAAM;GACf,cAAc,MAAM;GACpB,eAAe,MAAM;GACrB,MAAM,MAAM;GACZ,MAAM,MAAM;GACZ,MAAM,MAAM;GACZ,MAAM,MAAM;GACZ,oBAAoB,MAAM;GAC1B,cAAc,MAAM;GACpB,kBAAkB,MAAM;GACxB,sBAAsB,MAAM;GAC5B,gBAAgB,MAAM;GACtB,oBAAoB,MAAM;GAC1B,qBAAqB,MAAM;GAC3B,eAAe,MAAM;GACrB,mBAAmB,MAAM;GACzB,WAAW,MAAM;EACnB;CACN;AACF;AAEA,MAAa,uBAAuB,OAClC,SACA,IACA,WACoB;CACpB,MAAM,UAAU,MAAM,eAAe;CACrC,IAAI,CAAC,SAAS,OAAO;CAErB,QAAQ,WAAW,MAAM;CACzB,MAAM,EAAE,QAAQ,MAAM,QAAQ,OAAO,IAAI,OAAO;CAChD,OAAO;AACT"}