orbitchat 2.14.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/dist/assets/ChartRenderer-B1mYF_kk.js +80 -0
  2. package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  3. package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  4. package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  5. package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  6. package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  7. package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  8. package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  9. package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  10. package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  11. package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  12. package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  13. package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  14. package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  15. package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  16. package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  17. package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  18. package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  19. package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  20. package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  21. package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  22. package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  23. package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  24. package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  25. package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  26. package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  27. package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  28. package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  29. package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  30. package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  31. package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  32. package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  33. package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  34. package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  35. package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  36. package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  37. package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  38. package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  39. package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  40. package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  41. package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  42. package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  43. package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  44. package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  45. package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  46. package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  47. package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  48. package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  49. package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  50. package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  51. package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  52. package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  53. package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  54. package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  55. package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  56. package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  57. package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  58. package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  59. package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  60. package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  61. package/dist/assets/MermaidRenderer-Dhffx5mc.js +260 -0
  62. package/dist/assets/MusicRenderer-DbXJ8e4-.js +18 -0
  63. package/dist/assets/SVGRenderer-EhamRX_K.js +6 -0
  64. package/dist/assets/_basePickBy-C2AibBqo.js +1 -0
  65. package/dist/assets/_baseUniq-D52pUSvn.js +1 -0
  66. package/dist/assets/arc-BSnyvXPh.js +1 -0
  67. package/dist/assets/architectureDiagram-VXUJARFQ-BLMvVsZu.js +36 -0
  68. package/dist/assets/band-CquvqAHh.js +1 -0
  69. package/dist/assets/blockDiagram-VD42YOAC-CTz0dv5u.js +122 -0
  70. package/dist/assets/c4Diagram-YG6GDRKO-BjbN-GGh.js +10 -0
  71. package/dist/assets/channel-ryTtfXZE.js +1 -0
  72. package/dist/assets/chunk-4BX2VUAB-DEMWGIsU.js +1 -0
  73. package/dist/assets/chunk-55IACEB6-BYaauHLT.js +1 -0
  74. package/dist/assets/chunk-B4BG7PRW-D3_GFcfd.js +165 -0
  75. package/dist/assets/chunk-DI55MBZ5-Dy2EuzfA.js +220 -0
  76. package/dist/assets/{chunk-FMBD7UC4-dPK7Boav-Cz7OoDLR.js → chunk-FMBD7UC4-C9XHmwza.js} +2 -2
  77. package/dist/assets/chunk-QN33PNHL-BOCltIi9.js +1 -0
  78. package/dist/assets/chunk-QZHKN3VN-CvA964eQ.js +1 -0
  79. package/dist/assets/chunk-TZMSLE5B-B-3rZz90.js +1 -0
  80. package/dist/assets/classDiagram-2ON5EDUG-VbShFIzz.js +1 -0
  81. package/dist/assets/classDiagram-v2-WZHVMYZB-VbShFIzz.js +1 -0
  82. package/dist/assets/clone-BlhdKVDQ.js +1 -0
  83. package/dist/assets/cose-bilkent-S5V4N54A-CzPip3he.js +1 -0
  84. package/dist/assets/cytoscape.esm-CyJtwmzi.js +331 -0
  85. package/dist/assets/dagre-6UL2VRFP-CfCXYus3.js +4 -0
  86. package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  87. package/dist/assets/diagram-PSM6KHXK-DyI2eDqp.js +24 -0
  88. package/dist/assets/diagram-QEK2KX5R-DuakIh40.js +43 -0
  89. package/dist/assets/diagram-S2PKOQOG-C3-4IORM.js +24 -0
  90. package/dist/assets/erDiagram-Q2GNP2WA-Dt-nZEaD.js +60 -0
  91. package/dist/assets/flowDiagram-NV44I4VS-B-2wjyTQ.js +162 -0
  92. package/dist/assets/ganttDiagram-JELNMOA3-CHTvjPq0.js +267 -0
  93. package/dist/assets/gitGraphDiagram-V2S2FVAM-d5GWmgY4.js +65 -0
  94. package/dist/assets/graph-COgkbiU8.js +1 -0
  95. package/dist/assets/index-DN2bBcCs.js +134 -0
  96. package/dist/assets/index-DtztdW2a.js +643 -0
  97. package/dist/assets/index-lGqyWNWb.css +1 -0
  98. package/dist/assets/infoDiagram-HS3SLOUP-30Hn0iLj.js +2 -0
  99. package/dist/assets/init-Dmth1JHB.js +1 -0
  100. package/dist/assets/journeyDiagram-XKPGCS4Q-CMOYXQ79.js +139 -0
  101. package/dist/assets/kanban-definition-3W4ZIXB7-dt3376cq.js +89 -0
  102. package/dist/assets/layout-DH97sy5g.js +1 -0
  103. package/dist/assets/linear-CKzVTQ0r.js +1 -0
  104. package/dist/assets/mindmap-definition-VGOIOE7T-BcZHPAlA.js +68 -0
  105. package/dist/assets/ordinal-DILIJJjt.js +1 -0
  106. package/dist/assets/pieDiagram-ADFJNKIX-DXjvgcgl.js +30 -0
  107. package/dist/assets/purify.es-A66Cw1IH.js +2 -0
  108. package/dist/assets/quadrantDiagram-AYHSOK5B-CICk2FdS.js +7 -0
  109. package/dist/assets/requirementDiagram-UZGBJVZJ-BdtxpQRA.js +64 -0
  110. package/dist/assets/sankeyDiagram-TZEHDZUN-BVNS9BQJ.js +10 -0
  111. package/dist/assets/sequenceDiagram-WL72ISMW-DF4fJTM7.js +145 -0
  112. package/dist/assets/stateDiagram-FKZM4ZOC-C8H8HujX.js +1 -0
  113. package/dist/assets/stateDiagram-v2-4FDKWEC3-DwtU033b.js +1 -0
  114. package/dist/assets/step-EjIQ8UIn.js +1 -0
  115. package/dist/assets/time-h5EapSZu.js +1 -0
  116. package/dist/assets/timeline-definition-IT6M3QCI-DUSG5Vfy.js +61 -0
  117. package/dist/assets/treemap-GDKQZRPO-1PI2PY4S.js +160 -0
  118. package/dist/assets/xychartDiagram-PRI3JC2R-CFPJj8WK.js +7 -0
  119. package/dist/favicon.svg +3 -1
  120. package/dist/index.html +2 -2
  121. package/markdown-renderer/LICENSE +201 -0
  122. package/markdown-renderer/src/CodeBlock.tsx +332 -0
  123. package/markdown-renderer/src/MarkdownComponents.tsx +233 -0
  124. package/markdown-renderer/src/MarkdownStyles.css +668 -0
  125. package/markdown-renderer/src/css.d.ts +4 -0
  126. package/markdown-renderer/src/index.ts +32 -0
  127. package/markdown-renderer/src/preprocessing.ts +519 -0
  128. package/markdown-renderer/src/renderers/ChartRenderer.tsx +1434 -0
  129. package/markdown-renderer/src/renderers/MermaidRenderer.tsx +474 -0
  130. package/markdown-renderer/src/renderers/MusicRenderer.tsx +394 -0
  131. package/markdown-renderer/src/renderers/SVGRenderer.tsx +307 -0
  132. package/markdown-renderer/src/types.ts +174 -0
  133. package/package.json +25 -3
  134. package/dist/assets/_baseUniq-BRKsqoH--68FUaYxk.js +0 -1
  135. package/dist/assets/arc-pab_su9s-BuY-VRZt.js +0 -1
  136. package/dist/assets/architectureDiagram-VXUJARFQ-DqQ8r_6g-C5b5VsO8.js +0 -36
  137. package/dist/assets/blockDiagram-VD42YOAC-B-dKfcH3-DVjqMJ-3.js +0 -122
  138. package/dist/assets/c4Diagram-YG6GDRKO-DMUPaBEl-o6ghjFV9.js +0 -10
  139. package/dist/assets/channel-HKsfPa5q-rOME8XF8.js +0 -1
  140. package/dist/assets/chunk-4BX2VUAB-CX67kh_B-Dl0Loq_e.js +0 -1
  141. package/dist/assets/chunk-55IACEB6-BocSyyvr-DYW83vZR.js +0 -1
  142. package/dist/assets/chunk-B4BG7PRW-CO8QAyfE-CsF1OX4R.js +0 -165
  143. package/dist/assets/chunk-DI55MBZ5-Dw1L6Eos-Dl1shJzL.js +0 -220
  144. package/dist/assets/chunk-QN33PNHL-vP2PqfVG-BuQNN8G2.js +0 -1
  145. package/dist/assets/chunk-QZHKN3VN-Bcidzu63-Bud1NKOb.js +0 -1
  146. package/dist/assets/chunk-TZMSLE5B-BtljMjlg-BKLxPJ-x.js +0 -1
  147. package/dist/assets/classDiagram-2ON5EDUG-C7cYN9hv-BHg-LSxQ.js +0 -1
  148. package/dist/assets/classDiagram-v2-WZHVMYZB-C7cYN9hv-BHg-LSxQ.js +0 -1
  149. package/dist/assets/clone-DoPb9X13-DejjKfXe.js +0 -1
  150. package/dist/assets/cose-bilkent-S5V4N54A-BGzO4EsH-rofdToAx.js +0 -1
  151. package/dist/assets/cytoscape.esm-CjI2IsL8-Da6dFVsf.js +0 -331
  152. package/dist/assets/dagre-6UL2VRFP-TzNvXCds-Ls1mVyc7.js +0 -4
  153. package/dist/assets/diagram-PSM6KHXK-BqY4RpUg-BJmYXUei.js +0 -24
  154. package/dist/assets/diagram-QEK2KX5R-CTjgBsne-dz-VLadE.js +0 -43
  155. package/dist/assets/diagram-S2PKOQOG-BqrhTIpA-ikxUE9Dj.js +0 -24
  156. package/dist/assets/erDiagram-Q2GNP2WA-B2hsi_Tl-B5gu6Jrx.js +0 -60
  157. package/dist/assets/flowDiagram-NV44I4VS-C03vtt_F-C9LVdVvn.js +0 -162
  158. package/dist/assets/ganttDiagram-JELNMOA3-B3hAg964-CYO6ZcQ8.js +0 -267
  159. package/dist/assets/gitGraphDiagram-NY62KEGX-ByhMH0yZ-BvO0WGzP.js +0 -65
  160. package/dist/assets/graph-BmNkcFEM-Bl2fiTgr.js +0 -1
  161. package/dist/assets/index-BXexqYFc-CFPIFV8r.js +0 -134
  162. package/dist/assets/index-KsGsuMGp.css +0 -1
  163. package/dist/assets/index-nqhgVFEP.js +0 -1010
  164. package/dist/assets/infoDiagram-WHAUD3N6-is6Ho4-T-D6tHdi3J.js +0 -2
  165. package/dist/assets/journeyDiagram-XKPGCS4Q-CRTOL26C-CL4DFaQP.js +0 -139
  166. package/dist/assets/kanban-definition-3W4ZIXB7-CNnO_t6O-DZBlsSao.js +0 -89
  167. package/dist/assets/layout-C0kZPebx-DiUdszUx.js +0 -1
  168. package/dist/assets/min-7Gb0pNxh-DsojA8pm.js +0 -1
  169. package/dist/assets/mindmap-definition-VGOIOE7T-CJZ2wTTa-Cd46k2jT.js +0 -68
  170. package/dist/assets/pieDiagram-ADFJNKIX-C9OSknjr-BGVcHmss.js +0 -30
  171. package/dist/assets/quadrantDiagram-AYHSOK5B-CW8yuAqv-CrCYjmJT.js +0 -7
  172. package/dist/assets/requirementDiagram-UZGBJVZJ-nGPhruO1-BzOGHXGi.js +0 -64
  173. package/dist/assets/sankeyDiagram-TZEHDZUN-CmL90u-m-BWp9STLO.js +0 -10
  174. package/dist/assets/sequenceDiagram-WL72ISMW-B02VRcnM-DB4Adljk.js +0 -145
  175. package/dist/assets/stateDiagram-FKZM4ZOC-DjoyLUdz-pDyQ50aU.js +0 -1
  176. package/dist/assets/stateDiagram-v2-4FDKWEC3-Bq76BTB7-C3j4gDpN.js +0 -1
  177. package/dist/assets/timeline-definition-IT6M3QCI-CTn0Gm3T-O1FhSixZ.js +0 -61
  178. package/dist/assets/treemap-KMMF4GRG-BjgLKKyi-DG8IQefJ.js +0 -128
  179. package/dist/assets/xychartDiagram-PRI3JC2R-Cgg6Uija-CPVch5-l.js +0 -7
@@ -0,0 +1,474 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import mermaid from 'mermaid';
3
+ import type { MermaidRendererProps } from '../types';
4
+
5
+ type MermaidTheme = 'light' | 'dark';
6
+
7
+ const DEFAULT_THEME_VARIABLES: Record<MermaidTheme, Record<string, string>> = {
8
+ light: {
9
+ background: '#ffffff',
10
+ primaryColor: '#e0e7ff',
11
+ secondaryColor: '#ddd6fe',
12
+ tertiaryColor: '#fce7f3',
13
+ primaryTextColor: '#111827',
14
+ secondaryTextColor: '#4b5563',
15
+ primaryBorderColor: '#6366f1',
16
+ lineColor: '#111827',
17
+ // Pie chart specific
18
+ pie1: '#3b82f6',
19
+ pie2: '#8b5cf6',
20
+ pie3: '#ec4899',
21
+ pie4: '#f59e0b',
22
+ pie5: '#10b981',
23
+ pie6: '#06b6d4',
24
+ pie7: '#6366f1',
25
+ pie8: '#ef4444',
26
+ pieStrokeColor: '#ffffff',
27
+ pieStrokeWidth: '2px',
28
+ pieTitleTextColor: '#111827',
29
+ pieLegendTextColor: '#374151',
30
+ },
31
+ dark: {
32
+ background: '#1e293b',
33
+ primaryColor: '#3b82f6',
34
+ secondaryColor: '#8b5cf6',
35
+ tertiaryColor: '#6366f1',
36
+ primaryTextColor: '#f1f5f9',
37
+ secondaryTextColor: '#cbd5e1',
38
+ primaryBorderColor: '#60a5fa',
39
+ lineColor: '#f1f5f9',
40
+ // Pie chart specific - brighter colors for dark mode
41
+ pie1: '#60a5fa',
42
+ pie2: '#a78bfa',
43
+ pie3: '#f472b6',
44
+ pie4: '#fbbf24',
45
+ pie5: '#34d399',
46
+ pie6: '#22d3ee',
47
+ pie7: '#818cf8',
48
+ pie8: '#f87171',
49
+ pieStrokeColor: '#1e293b',
50
+ pieStrokeWidth: '2px',
51
+ pieTitleTextColor: '#f1f5f9',
52
+ pieLegendTextColor: '#e2e8f0',
53
+ },
54
+ };
55
+
56
+ // Initialize mermaid once
57
+ let mermaidInitialized = false;
58
+ const initializeMermaid = () => {
59
+ if (typeof window === 'undefined' || mermaidInitialized) return;
60
+
61
+ try {
62
+ mermaid.initialize({
63
+ startOnLoad: false,
64
+ theme: 'default',
65
+ securityLevel: 'loose',
66
+ themeVariables: DEFAULT_THEME_VARIABLES.light,
67
+ });
68
+ mermaidInitialized = true;
69
+ } catch (err) {
70
+ console.warn('Failed to initialize Mermaid:', err);
71
+ }
72
+ };
73
+
74
+ const formatMermaidError = (err: unknown): string => {
75
+ let errorMessage = 'Failed to render Mermaid diagram';
76
+
77
+ if (err instanceof Error) {
78
+ const message = err.message || '';
79
+
80
+ if (message.includes('Syntax error')) {
81
+ const lineMatch = message.match(/line\s+(\d+)/i);
82
+ const tokenMatch = message.match(/token\s+['"]([^'"]+)['"]/i);
83
+ const details = [];
84
+
85
+ if (lineMatch) details.push(`Line ${lineMatch[1]}`);
86
+ if (tokenMatch) details.push(`Unexpected token: ${tokenMatch[1]}`);
87
+
88
+ errorMessage = `Syntax error${details.length ? ` (${details.join(', ')})` : ''}`;
89
+ } else if (message) {
90
+ errorMessage = message.length > 160 ? `${message.substring(0, 157)}...` : message;
91
+ }
92
+ } else if (typeof err === 'string') {
93
+ errorMessage = err;
94
+ }
95
+
96
+ return errorMessage;
97
+ };
98
+
99
+ const readCSSVariable = (element: Element | null, name: string): string | undefined => {
100
+ if (typeof window === 'undefined' || !element) return undefined;
101
+ const value = window.getComputedStyle(element).getPropertyValue(name);
102
+ if (!value) return undefined;
103
+ const trimmed = value.trim();
104
+ return trimmed.length ? trimmed : undefined;
105
+ };
106
+
107
+ const resolveThemeVariables = (theme: MermaidTheme, element: Element | null) => {
108
+ const fallback = DEFAULT_THEME_VARIABLES[theme];
109
+ if (typeof window === 'undefined' || !element) {
110
+ return fallback;
111
+ }
112
+
113
+ const overrides: Record<string, string | undefined> = {
114
+ background: readCSSVariable(element, '--md-bg-primary'),
115
+ primaryColor: readCSSVariable(element, '--md-bg-secondary'),
116
+ secondaryColor: readCSSVariable(element, '--md-bg-tertiary'),
117
+ tertiaryColor: readCSSVariable(element, '--md-bg-primary'),
118
+ primaryTextColor: readCSSVariable(element, '--md-text-primary'),
119
+ secondaryTextColor: readCSSVariable(element, '--md-text-secondary'),
120
+ primaryBorderColor: readCSSVariable(element, '--md-border-color'),
121
+ lineColor: readCSSVariable(element, '--md-text-primary'),
122
+ };
123
+
124
+ const filteredEntries = Object.entries(overrides).filter(
125
+ ([, value]) => typeof value === 'string' && value.length
126
+ ) as Array<[string, string]>;
127
+
128
+ return filteredEntries.length ? { ...fallback, ...Object.fromEntries(filteredEntries) } : fallback;
129
+ };
130
+
131
+ const detectThemeFromElement = (element: Element | null): MermaidTheme | null => {
132
+ if (!element) return null;
133
+
134
+ const attr = element.getAttribute('data-theme');
135
+ if (attr === 'dark') return 'dark';
136
+ if (attr === 'light') return 'light';
137
+
138
+ if (element.classList.contains('dark')) return 'dark';
139
+ if (element.classList.contains('light')) return 'light';
140
+
141
+ return null;
142
+ };
143
+
144
+ export const MermaidRenderer: React.FC<MermaidRendererProps> = ({ code }) => {
145
+ const hostRef = useRef<HTMLDivElement>(null);
146
+ const containerRef = useRef<HTMLDivElement>(null);
147
+ const renderIdRef = useRef(0);
148
+
149
+ const [error, setError] = useState<string | null>(null);
150
+ const [svg, setSvg] = useState<string | null>(null);
151
+ const [bindFunctions, setBindFunctions] = useState<((element: Element) => void) | null>(null);
152
+ const [showErrorDetails, setShowErrorDetails] = useState(false);
153
+ const [theme, setTheme] = useState<MermaidTheme>('light');
154
+ const lastThemeRef = useRef<MermaidTheme>('light');
155
+
156
+ useEffect(() => {
157
+ if (typeof window === 'undefined') return;
158
+ const host = hostRef.current;
159
+ if (!host) return;
160
+
161
+ const markdownRoot = host.closest('.markdown-content') ?? host;
162
+ const prefersDarkQuery = window.matchMedia?.('(prefers-color-scheme: dark)');
163
+
164
+ const readTheme = (): MermaidTheme => {
165
+ const prefersDark = Boolean(prefersDarkQuery?.matches);
166
+ return (
167
+ detectThemeFromElement(markdownRoot) ??
168
+ detectThemeFromElement(document.documentElement) ??
169
+ (prefersDark ? 'dark' : 'light')
170
+ );
171
+ };
172
+
173
+ const updateTheme = () => {
174
+ const next = readTheme();
175
+ // Only update if theme actually changed to prevent re-render loops
176
+ if (next !== lastThemeRef.current) {
177
+ lastThemeRef.current = next;
178
+ setTheme(next);
179
+ }
180
+ };
181
+
182
+ updateTheme();
183
+
184
+ const observer = new MutationObserver(updateTheme);
185
+ observer.observe(markdownRoot, { attributes: true, attributeFilter: ['class', 'data-theme'] });
186
+
187
+ let docObserver: MutationObserver | null = null;
188
+ if (markdownRoot !== document.documentElement) {
189
+ docObserver = new MutationObserver(updateTheme);
190
+ docObserver.observe(document.documentElement, {
191
+ attributes: true,
192
+ attributeFilter: ['class', 'data-theme'],
193
+ });
194
+ }
195
+
196
+ const handleMediaChange = () => updateTheme();
197
+ prefersDarkQuery?.addEventListener('change', handleMediaChange);
198
+
199
+ return () => {
200
+ observer.disconnect();
201
+ docObserver?.disconnect();
202
+ prefersDarkQuery?.removeEventListener('change', handleMediaChange);
203
+ };
204
+ }, []);
205
+
206
+ useEffect(() => {
207
+ if (!code.trim()) {
208
+ setSvg(null);
209
+ setError(null);
210
+ setBindFunctions(null);
211
+ return;
212
+ }
213
+
214
+ const renderDiagram = async () => {
215
+ const currentRenderId = ++renderIdRef.current;
216
+ try {
217
+ initializeMermaid();
218
+
219
+ const diagramId = `mermaid-${Math.random().toString(36).substring(2, 11)}`;
220
+
221
+ // Parse early to provide clearer syntax errors and avoid throwing during render
222
+ await mermaid.parse(code);
223
+
224
+ const themeTarget = hostRef.current?.closest('.markdown-content') ?? hostRef.current;
225
+ const themeVariables = resolveThemeVariables(theme, themeTarget);
226
+
227
+ // Re-initialize mermaid with current theme before rendering
228
+ mermaid.initialize({
229
+ startOnLoad: false,
230
+ theme: theme === 'dark' ? 'dark' : 'default',
231
+ securityLevel: 'loose',
232
+ themeVariables,
233
+ // Optimized diagram settings for readability and compact display
234
+ flowchart: {
235
+ useMaxWidth: true,
236
+ htmlLabels: true,
237
+ curve: 'basis',
238
+ padding: 15,
239
+ nodeSpacing: 50,
240
+ rankSpacing: 50,
241
+ },
242
+ sequence: {
243
+ useMaxWidth: true,
244
+ diagramMarginX: 30,
245
+ diagramMarginY: 15,
246
+ actorMargin: 50,
247
+ width: 120,
248
+ height: 40,
249
+ boxMargin: 8,
250
+ boxTextMargin: 4,
251
+ noteMargin: 10,
252
+ messageMargin: 35,
253
+ mirrorActors: true,
254
+ actorFontSize: 13,
255
+ messageFontSize: 12,
256
+ noteFontSize: 12,
257
+ wrap: true,
258
+ wrapPadding: 10,
259
+ },
260
+ gantt: {
261
+ useMaxWidth: true,
262
+ barHeight: 24,
263
+ barGap: 4,
264
+ topPadding: 40,
265
+ leftPadding: 80,
266
+ gridLineStartPadding: 40,
267
+ fontSize: 12,
268
+ sectionFontSize: 13,
269
+ numberSectionStyles: 4,
270
+ },
271
+ er: {
272
+ useMaxWidth: true,
273
+ fontSize: 12,
274
+ entityPadding: 15,
275
+ },
276
+ pie: {
277
+ useMaxWidth: true,
278
+ textPosition: 0.75,
279
+ },
280
+ journey: {
281
+ useMaxWidth: true,
282
+ diagramMarginX: 30,
283
+ diagramMarginY: 20,
284
+ leftMargin: 100,
285
+ width: 120,
286
+ height: 50,
287
+ boxMargin: 8,
288
+ boxTextMargin: 4,
289
+ noteMargin: 10,
290
+ messageMargin: 30,
291
+ },
292
+ gitGraph: {
293
+ useMaxWidth: true,
294
+ diagramPadding: 8,
295
+ nodeLabel: {
296
+ width: 75,
297
+ height: 100,
298
+ x: -25,
299
+ y: 0,
300
+ },
301
+ },
302
+ class: {
303
+ useMaxWidth: true,
304
+ padding: 10,
305
+ },
306
+ state: {
307
+ useMaxWidth: true,
308
+ padding: 8,
309
+ dividerMargin: 10,
310
+ },
311
+ mindmap: {
312
+ useMaxWidth: true,
313
+ padding: 10,
314
+ },
315
+ timeline: {
316
+ useMaxWidth: true,
317
+ padding: 10,
318
+ },
319
+ quadrantChart: {
320
+ useMaxWidth: true,
321
+ },
322
+ sankey: {
323
+ useMaxWidth: true,
324
+ },
325
+ });
326
+
327
+ const result = await mermaid.render(diagramId, code);
328
+
329
+ if (renderIdRef.current !== currentRenderId) {
330
+ return;
331
+ }
332
+
333
+ setSvg(result.svg);
334
+ setBindFunctions(() => (result.bindFunctions ? result.bindFunctions : null));
335
+ setError(null);
336
+ } catch (err) {
337
+ if (renderIdRef.current !== currentRenderId) {
338
+ return;
339
+ }
340
+
341
+ setError(formatMermaidError(err));
342
+ setSvg(null);
343
+ setBindFunctions(null);
344
+ setShowErrorDetails(false); // Reset details visibility on new error
345
+ }
346
+ };
347
+
348
+ renderDiagram();
349
+
350
+ return () => {
351
+ renderIdRef.current += 1;
352
+ };
353
+ }, [code, theme]);
354
+
355
+ useEffect(() => {
356
+ if (!svg || !bindFunctions || !containerRef.current) return;
357
+
358
+ try {
359
+ bindFunctions(containerRef.current);
360
+ } catch (err) {
361
+ console.warn('Failed to bind Mermaid interactions:', err);
362
+ }
363
+ }, [svg, bindFunctions]);
364
+
365
+ const renderError = () => (
366
+ <div className="graph-error">
367
+ <div className="graph-error-header">
368
+ <div className="graph-error-icon">⚠️</div>
369
+ <div className="graph-error-content">
370
+ <div className="graph-error-title">Mermaid Diagram Error</div>
371
+ <div className="graph-error-message">{error}</div>
372
+ </div>
373
+ </div>
374
+ <button
375
+ className="graph-error-toggle"
376
+ onClick={() => setShowErrorDetails(!showErrorDetails)}
377
+ type="button"
378
+ >
379
+ {showErrorDetails ? 'Hide' : 'Show'} Details
380
+ </button>
381
+ {showErrorDetails && (
382
+ <details className="graph-error-details" open>
383
+ <summary style={{ cursor: 'pointer', marginBottom: '8px', fontWeight: 500 }}>
384
+ Mermaid Code
385
+ </summary>
386
+ <pre
387
+ style={{
388
+ marginTop: '8px',
389
+ fontSize: '0.8em',
390
+ opacity: 0.8,
391
+ padding: '8px',
392
+ background: 'rgba(0, 0, 0, 0.05)',
393
+ borderRadius: '4px',
394
+ overflow: 'auto',
395
+ maxHeight: '200px',
396
+ }}
397
+ >
398
+ <code>{code}</code>
399
+ </pre>
400
+ </details>
401
+ )}
402
+ </div>
403
+ );
404
+
405
+ const renderContent = () => {
406
+ if (error) {
407
+ return renderError();
408
+ }
409
+
410
+ if (!svg) {
411
+ return (
412
+ <div style={{
413
+ display: 'flex',
414
+ flexDirection: 'column',
415
+ alignItems: 'center',
416
+ justifyContent: 'center',
417
+ padding: '30px 20px',
418
+ color: 'var(--md-text-secondary, #6b7280)',
419
+ minHeight: '120px',
420
+ }}>
421
+ <svg
422
+ style={{
423
+ animation: 'spin 1s linear infinite',
424
+ marginBottom: '10px',
425
+ width: '28px',
426
+ height: '28px',
427
+ }}
428
+ viewBox="0 0 24 24"
429
+ fill="none"
430
+ >
431
+ <circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="2" strokeDasharray="32" strokeLinecap="round" />
432
+ </svg>
433
+ <span style={{ fontWeight: 500, fontSize: '14px' }}>
434
+ Rendering diagram...
435
+ </span>
436
+ <style>{`
437
+ @keyframes spin {
438
+ from { transform: rotate(0deg); }
439
+ to { transform: rotate(360deg); }
440
+ }
441
+ `}</style>
442
+ </div>
443
+ );
444
+ }
445
+
446
+ return (
447
+ <div
448
+ ref={containerRef}
449
+ className="mermaid-svg-container"
450
+ style={{
451
+ display: 'flex',
452
+ justifyContent: 'center',
453
+ alignItems: 'center',
454
+ width: '100%',
455
+ overflow: 'auto',
456
+ }}
457
+ dangerouslySetInnerHTML={{ __html: svg }}
458
+ />
459
+ );
460
+ };
461
+
462
+ return (
463
+ <div
464
+ className="graph-container mermaid-container"
465
+ ref={hostRef}
466
+ style={{
467
+ padding: '16px',
468
+ minHeight: '100px',
469
+ }}
470
+ >
471
+ {renderContent()}
472
+ </div>
473
+ );
474
+ };