@frontmcp/ui 0.12.2 → 1.0.0-beta.1

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 (310) hide show
  1. package/README.md +279 -72
  2. package/bridge/adapters/claude.adapter.d.ts.map +1 -1
  3. package/bridge/adapters/gemini.adapter.d.ts.map +1 -1
  4. package/bridge/index.js +2 -36
  5. package/components/Alert/Alert.d.ts +11 -0
  6. package/components/Alert/Alert.d.ts.map +1 -0
  7. package/components/Alert/index.d.ts +4 -0
  8. package/components/Alert/index.d.ts.map +1 -0
  9. package/components/Alert/index.js +61 -0
  10. package/components/Avatar/Avatar.d.ts +10 -0
  11. package/components/Avatar/Avatar.d.ts.map +1 -0
  12. package/components/Avatar/index.d.ts +4 -0
  13. package/components/Avatar/index.d.ts.map +1 -0
  14. package/components/Avatar/index.js +43 -0
  15. package/components/Badge/Badge.d.ts +13 -0
  16. package/components/Badge/Badge.d.ts.map +1 -0
  17. package/components/Badge/index.d.ts +4 -0
  18. package/components/Badge/index.d.ts.map +1 -0
  19. package/{render → components/Badge}/index.js +54 -42
  20. package/components/Button/Button.d.ts +16 -0
  21. package/components/Button/Button.d.ts.map +1 -0
  22. package/components/Button/index.d.ts +4 -0
  23. package/components/Button/index.d.ts.map +1 -0
  24. package/components/Button/index.js +91 -0
  25. package/components/Card/Card.d.ts +25 -0
  26. package/components/Card/Card.d.ts.map +1 -0
  27. package/components/Card/index.d.ts +4 -0
  28. package/components/Card/index.d.ts.map +1 -0
  29. package/components/Card/index.js +110 -0
  30. package/components/List/List.d.ts +15 -0
  31. package/components/List/List.d.ts.map +1 -0
  32. package/components/List/index.d.ts +4 -0
  33. package/components/List/index.d.ts.map +1 -0
  34. package/components/List/index.js +58 -0
  35. package/components/Loader/Loader.d.ts +28 -0
  36. package/components/Loader/Loader.d.ts.map +1 -0
  37. package/components/Loader/LoaderContext.d.ts +20 -0
  38. package/components/Loader/LoaderContext.d.ts.map +1 -0
  39. package/components/Loader/index.d.ts +6 -0
  40. package/components/Loader/index.d.ts.map +1 -0
  41. package/components/Loader/index.js +174 -0
  42. package/components/Modal/Modal.d.ts +22 -0
  43. package/components/Modal/Modal.d.ts.map +1 -0
  44. package/components/Modal/index.d.ts +4 -0
  45. package/components/Modal/index.d.ts.map +1 -0
  46. package/components/Modal/index.js +80 -0
  47. package/components/Select/Select.d.ts +21 -0
  48. package/components/Select/Select.d.ts.map +1 -0
  49. package/components/Select/index.d.ts +4 -0
  50. package/components/Select/index.d.ts.map +1 -0
  51. package/components/Select/index.js +78 -0
  52. package/components/Table/Table.d.ts +15 -0
  53. package/components/Table/Table.d.ts.map +1 -0
  54. package/components/Table/index.d.ts +4 -0
  55. package/components/Table/index.d.ts.map +1 -0
  56. package/components/Table/index.js +70 -0
  57. package/components/TextField/TextField.d.ts +19 -0
  58. package/components/TextField/TextField.d.ts.map +1 -0
  59. package/components/TextField/index.d.ts +4 -0
  60. package/components/TextField/index.d.ts.map +1 -0
  61. package/components/TextField/index.js +77 -0
  62. package/components/index.d.ts +22 -28
  63. package/components/index.d.ts.map +1 -1
  64. package/components/index.js +523 -2521
  65. package/esm/bridge/index.mjs +2 -6
  66. package/esm/components/Alert/index.mjs +28 -0
  67. package/esm/components/Avatar/index.mjs +10 -0
  68. package/esm/components/Badge/index.mjs +56 -0
  69. package/esm/components/Button/index.mjs +58 -0
  70. package/esm/components/Card/index.mjs +77 -0
  71. package/esm/components/List/index.mjs +25 -0
  72. package/esm/components/Loader/index.mjs +141 -0
  73. package/esm/components/Modal/index.mjs +47 -0
  74. package/esm/components/Select/index.mjs +45 -0
  75. package/esm/components/Table/index.mjs +37 -0
  76. package/esm/components/TextField/index.mjs +44 -0
  77. package/esm/components/index.mjs +513 -2415
  78. package/esm/index.mjs +62 -4652
  79. package/esm/package.json +372 -16
  80. package/esm/react/index.mjs +2 -285
  81. package/esm/renderer/charts/index.mjs +336 -0
  82. package/esm/renderer/common/index.mjs +135 -0
  83. package/esm/renderer/csv/index.mjs +193 -0
  84. package/esm/renderer/flow/index.mjs +259 -0
  85. package/esm/renderer/html/index.mjs +99 -0
  86. package/esm/renderer/image/index.mjs +125 -0
  87. package/esm/renderer/index.mjs +2173 -0
  88. package/esm/renderer/maps/index.mjs +217 -0
  89. package/esm/renderer/math/index.mjs +229 -0
  90. package/esm/renderer/mdx/index.mjs +261 -0
  91. package/esm/renderer/media/index.mjs +235 -0
  92. package/esm/renderer/mermaid/index.mjs +220 -0
  93. package/esm/renderer/pdf/index.mjs +229 -0
  94. package/esm/renderer/react/index.mjs +230 -0
  95. package/esm/runtime/index.mjs +194 -0
  96. package/esm/theme/index.mjs +93 -0
  97. package/index.d.ts +10 -18
  98. package/index.d.ts.map +1 -1
  99. package/index.js +63 -4806
  100. package/package.json +372 -16
  101. package/react/index.d.ts +8 -54
  102. package/react/index.d.ts.map +1 -1
  103. package/react/index.js +2 -295
  104. package/renderer/auto-detect.d.ts +39 -0
  105. package/renderer/auto-detect.d.ts.map +1 -0
  106. package/renderer/charts/index.d.ts +22 -0
  107. package/renderer/charts/index.d.ts.map +1 -0
  108. package/renderer/charts/index.js +367 -0
  109. package/renderer/common/index.d.ts +5 -0
  110. package/renderer/common/index.d.ts.map +1 -0
  111. package/renderer/common/index.js +158 -0
  112. package/renderer/common/inject-stylesheet.d.ts +9 -0
  113. package/renderer/common/inject-stylesheet.d.ts.map +1 -0
  114. package/renderer/common/lazy-import.d.ts +85 -0
  115. package/renderer/common/lazy-import.d.ts.map +1 -0
  116. package/renderer/common/use-lazy-module.d.ts +13 -0
  117. package/renderer/common/use-lazy-module.d.ts.map +1 -0
  118. package/renderer/common/use-renderer-theme.d.ts +35 -0
  119. package/renderer/common/use-renderer-theme.d.ts.map +1 -0
  120. package/renderer/csv/index.d.ts +12 -0
  121. package/renderer/csv/index.d.ts.map +1 -0
  122. package/renderer/csv/index.js +224 -0
  123. package/renderer/flow/index.d.ts +40 -0
  124. package/renderer/flow/index.d.ts.map +1 -0
  125. package/renderer/flow/index.js +290 -0
  126. package/renderer/html/index.d.ts +12 -0
  127. package/renderer/html/index.d.ts.map +1 -0
  128. package/renderer/html/index.js +130 -0
  129. package/renderer/image/index.d.ts +11 -0
  130. package/renderer/image/index.d.ts.map +1 -0
  131. package/renderer/image/index.js +156 -0
  132. package/renderer/index.d.ts +32 -0
  133. package/renderer/index.d.ts.map +1 -0
  134. package/renderer/index.js +2206 -0
  135. package/renderer/maps/index.d.ts +27 -0
  136. package/renderer/maps/index.d.ts.map +1 -0
  137. package/renderer/maps/index.js +248 -0
  138. package/renderer/math/index.d.ts +11 -0
  139. package/renderer/math/index.d.ts.map +1 -0
  140. package/renderer/math/index.js +260 -0
  141. package/renderer/mdx/index.d.ts +10 -0
  142. package/renderer/mdx/index.d.ts.map +1 -0
  143. package/renderer/mdx/index.js +292 -0
  144. package/renderer/media/index.d.ts +20 -0
  145. package/renderer/media/index.d.ts.map +1 -0
  146. package/renderer/media/index.js +266 -0
  147. package/renderer/mermaid/index.d.ts +11 -0
  148. package/renderer/mermaid/index.d.ts.map +1 -0
  149. package/renderer/mermaid/index.js +251 -0
  150. package/renderer/pdf/index.d.ts +10 -0
  151. package/renderer/pdf/index.d.ts.map +1 -0
  152. package/renderer/pdf/index.js +260 -0
  153. package/renderer/react/index.d.ts +45 -0
  154. package/renderer/react/index.d.ts.map +1 -0
  155. package/renderer/react/index.js +261 -0
  156. package/renderer/types.d.ts +24 -0
  157. package/renderer/types.d.ts.map +1 -0
  158. package/runtime/babel-runtime.d.ts +70 -0
  159. package/runtime/babel-runtime.d.ts.map +1 -0
  160. package/runtime/content-detector.d.ts +43 -0
  161. package/runtime/content-detector.d.ts.map +1 -0
  162. package/runtime/index.d.ts +10 -0
  163. package/runtime/index.d.ts.map +1 -0
  164. package/runtime/index.js +217 -0
  165. package/theme/FrontMcpThemeProvider.d.ts +4 -0
  166. package/theme/FrontMcpThemeProvider.d.ts.map +1 -0
  167. package/theme/create-theme.d.ts +9 -0
  168. package/theme/create-theme.d.ts.map +1 -0
  169. package/theme/index.d.ts +5 -0
  170. package/theme/index.d.ts.map +1 -0
  171. package/theme/index.js +126 -0
  172. package/theme/types.d.ts +28 -0
  173. package/theme/types.d.ts.map +1 -0
  174. package/theme/use-theme.d.ts +3 -0
  175. package/theme/use-theme.d.ts.map +1 -0
  176. package/bundler/browser-components.d.ts +0 -42
  177. package/bundler/browser-components.d.ts.map +0 -1
  178. package/bundler/bundler.d.ts +0 -282
  179. package/bundler/bundler.d.ts.map +0 -1
  180. package/bundler/index.d.ts +0 -43
  181. package/bundler/index.d.ts.map +0 -1
  182. package/bundler/index.js +0 -3168
  183. package/bundler/types.d.ts +0 -883
  184. package/bundler/types.d.ts.map +0 -1
  185. package/components/alert.d.ts +0 -83
  186. package/components/alert.d.ts.map +0 -1
  187. package/components/alert.schema.d.ts +0 -98
  188. package/components/alert.schema.d.ts.map +0 -1
  189. package/components/avatar.d.ts +0 -77
  190. package/components/avatar.d.ts.map +0 -1
  191. package/components/avatar.schema.d.ts +0 -170
  192. package/components/avatar.schema.d.ts.map +0 -1
  193. package/components/badge.d.ts +0 -78
  194. package/components/badge.d.ts.map +0 -1
  195. package/components/badge.schema.d.ts +0 -91
  196. package/components/badge.schema.d.ts.map +0 -1
  197. package/components/button.d.ts +0 -100
  198. package/components/button.d.ts.map +0 -1
  199. package/components/button.schema.d.ts +0 -120
  200. package/components/button.schema.d.ts.map +0 -1
  201. package/components/card.d.ts +0 -76
  202. package/components/card.d.ts.map +0 -1
  203. package/components/card.schema.d.ts +0 -93
  204. package/components/card.schema.d.ts.map +0 -1
  205. package/components/form.d.ts +0 -227
  206. package/components/form.d.ts.map +0 -1
  207. package/components/form.schema.d.ts +0 -365
  208. package/components/form.schema.d.ts.map +0 -1
  209. package/components/list.d.ts +0 -121
  210. package/components/list.d.ts.map +0 -1
  211. package/components/list.schema.d.ts +0 -129
  212. package/components/list.schema.d.ts.map +0 -1
  213. package/components/modal.d.ts +0 -100
  214. package/components/modal.d.ts.map +0 -1
  215. package/components/modal.schema.d.ts +0 -151
  216. package/components/modal.schema.d.ts.map +0 -1
  217. package/components/table.d.ts +0 -91
  218. package/components/table.d.ts.map +0 -1
  219. package/components/table.schema.d.ts +0 -123
  220. package/components/table.schema.d.ts.map +0 -1
  221. package/esm/bundler/index.mjs +0 -3136
  222. package/esm/layouts/index.mjs +0 -409
  223. package/esm/render/index.mjs +0 -45
  224. package/esm/renderers/index.mjs +0 -621
  225. package/esm/universal/index.mjs +0 -1946
  226. package/esm/web-components/index.mjs +0 -2023
  227. package/layouts/base.d.ts +0 -86
  228. package/layouts/base.d.ts.map +0 -1
  229. package/layouts/index.d.ts +0 -8
  230. package/layouts/index.d.ts.map +0 -1
  231. package/layouts/index.js +0 -437
  232. package/layouts/presets.d.ts +0 -134
  233. package/layouts/presets.d.ts.map +0 -1
  234. package/react/Alert.d.ts +0 -101
  235. package/react/Alert.d.ts.map +0 -1
  236. package/react/Badge.d.ts +0 -100
  237. package/react/Badge.d.ts.map +0 -1
  238. package/react/Button.d.ts +0 -108
  239. package/react/Button.d.ts.map +0 -1
  240. package/react/Card.d.ts +0 -103
  241. package/react/Card.d.ts.map +0 -1
  242. package/react/types.d.ts +0 -105
  243. package/react/types.d.ts.map +0 -1
  244. package/render/index.d.ts +0 -8
  245. package/render/index.d.ts.map +0 -1
  246. package/render/prerender.d.ts +0 -57
  247. package/render/prerender.d.ts.map +0 -1
  248. package/renderers/index.d.ts +0 -26
  249. package/renderers/index.d.ts.map +0 -1
  250. package/renderers/index.js +0 -666
  251. package/renderers/mdx.renderer.d.ts +0 -99
  252. package/renderers/mdx.renderer.d.ts.map +0 -1
  253. package/renderers/react.adapter.d.ts +0 -70
  254. package/renderers/react.adapter.d.ts.map +0 -1
  255. package/renderers/react.renderer.d.ts +0 -105
  256. package/renderers/react.renderer.d.ts.map +0 -1
  257. package/renderers/transpiler.d.ts +0 -49
  258. package/renderers/transpiler.d.ts.map +0 -1
  259. package/universal/UniversalApp.d.ts +0 -108
  260. package/universal/UniversalApp.d.ts.map +0 -1
  261. package/universal/cached-runtime.d.ts +0 -139
  262. package/universal/cached-runtime.d.ts.map +0 -1
  263. package/universal/context.d.ts +0 -122
  264. package/universal/context.d.ts.map +0 -1
  265. package/universal/index.d.ts +0 -57
  266. package/universal/index.d.ts.map +0 -1
  267. package/universal/index.js +0 -2032
  268. package/universal/renderers/html.renderer.d.ts +0 -36
  269. package/universal/renderers/html.renderer.d.ts.map +0 -1
  270. package/universal/renderers/index.d.ts +0 -112
  271. package/universal/renderers/index.d.ts.map +0 -1
  272. package/universal/renderers/markdown.renderer.d.ts +0 -33
  273. package/universal/renderers/markdown.renderer.d.ts.map +0 -1
  274. package/universal/renderers/mdx.renderer.d.ts +0 -38
  275. package/universal/renderers/mdx.renderer.d.ts.map +0 -1
  276. package/universal/renderers/react.renderer.d.ts +0 -46
  277. package/universal/renderers/react.renderer.d.ts.map +0 -1
  278. package/universal/runtime-builder.d.ts +0 -33
  279. package/universal/runtime-builder.d.ts.map +0 -1
  280. package/universal/store.d.ts +0 -135
  281. package/universal/store.d.ts.map +0 -1
  282. package/universal/types.d.ts +0 -199
  283. package/universal/types.d.ts.map +0 -1
  284. package/web-components/core/attribute-parser.d.ts +0 -82
  285. package/web-components/core/attribute-parser.d.ts.map +0 -1
  286. package/web-components/core/base-element.d.ts +0 -197
  287. package/web-components/core/base-element.d.ts.map +0 -1
  288. package/web-components/core/index.d.ts +0 -9
  289. package/web-components/core/index.d.ts.map +0 -1
  290. package/web-components/elements/fmcp-alert.d.ts +0 -46
  291. package/web-components/elements/fmcp-alert.d.ts.map +0 -1
  292. package/web-components/elements/fmcp-badge.d.ts +0 -47
  293. package/web-components/elements/fmcp-badge.d.ts.map +0 -1
  294. package/web-components/elements/fmcp-button.d.ts +0 -117
  295. package/web-components/elements/fmcp-button.d.ts.map +0 -1
  296. package/web-components/elements/fmcp-card.d.ts +0 -53
  297. package/web-components/elements/fmcp-card.d.ts.map +0 -1
  298. package/web-components/elements/fmcp-input.d.ts +0 -96
  299. package/web-components/elements/fmcp-input.d.ts.map +0 -1
  300. package/web-components/elements/fmcp-select.d.ts +0 -100
  301. package/web-components/elements/fmcp-select.d.ts.map +0 -1
  302. package/web-components/elements/index.d.ts +0 -13
  303. package/web-components/elements/index.d.ts.map +0 -1
  304. package/web-components/index.d.ts +0 -49
  305. package/web-components/index.d.ts.map +0 -1
  306. package/web-components/index.js +0 -2058
  307. package/web-components/register.d.ts +0 -57
  308. package/web-components/register.d.ts.map +0 -1
  309. package/web-components/types.d.ts +0 -122
  310. package/web-components/types.d.ts.map +0 -1
@@ -0,0 +1,2173 @@
1
+ // libs/ui/src/renderer/auto-detect.ts
2
+ import React, { Suspense } from "react";
3
+
4
+ // libs/ui/src/runtime/content-detector.ts
5
+ var JSX_PATTERNS = [
6
+ // JSX-specific syntax: self-closing tags with capitalized names
7
+ /<[A-Z][a-zA-Z0-9]*[\s/>]/,
8
+ // JSX expressions: {someVar} or {() => ...}
9
+ /\{[a-zA-Z_$][\w$.]*\}/,
10
+ // React hooks: useState, useEffect, etc.
11
+ /\buse[A-Z]\w+\s*\(/,
12
+ // Arrow function components or function declarations: const Foo = / function Foo(
13
+ /(?:const|let|var|function)\s+[A-Z]\w*\s*[=(]/,
14
+ // Import from react
15
+ /import\s[^\n]{1,200}from\s+['"]react['"]/,
16
+ // JSX pragma or import
17
+ /\/\*\*?\s*@jsx\b/,
18
+ // export default function/const (component pattern)
19
+ /export\s+default\s+function\s+[A-Z]/
20
+ ];
21
+ var MDX_PATTERNS = [
22
+ // MDX frontmatter
23
+ /^---\s*\n/,
24
+ // Markdown headings
25
+ /^#{1,6}\s+\S/m,
26
+ // MDX import statements followed by markdown
27
+ /^import\s[^\n]*\n+#/m,
28
+ // MDX export default (layout pattern)
29
+ /^export\s+default\s+/m,
30
+ // Markdown bullet lists
31
+ /^\s*[-*+]\s+\S/m,
32
+ // Markdown links
33
+ /\[[^\]]+\]\([^)]+\)/,
34
+ // Markdown code blocks
35
+ /^```\w*/m,
36
+ // Markdown emphasis
37
+ /(?:\*\*|__)(?:(?!\*\*|__).)+(?:\*\*|__)/
38
+ ];
39
+ var CHART_TYPE_RE = /"type"\s*:\s*"(?:bar|line|area|pie|scatter|radar|composed)"/;
40
+ var MERMAID_PATTERN = /^\s*(?:graph|sequenceDiagram|classDiagram|stateDiagram|flowchart|erDiagram|gantt|pie|journey|gitGraph)\b/;
41
+ function looksLikeChart(s) {
42
+ return s.charCodeAt(0) === 123 && CHART_TYPE_RE.test(s) && s.includes('"data"');
43
+ }
44
+ function looksLikeFlow(s) {
45
+ return s.charCodeAt(0) === 123 && s.includes('"nodes"') && s.includes('"edges"');
46
+ }
47
+ var MATH_PATTERNS = [
48
+ /\$\$(?:[^$]|\$(?!\$))+\$\$/s,
49
+ /\$[^$\n]+?\$/,
50
+ /\\\[(?:[^\\]|\\.)*\\\]/s,
51
+ /\\\((?:[^\\]|\\.)*\\\)/s,
52
+ /\\begin\{(?:equation|align|gather|matrix|pmatrix|bmatrix|cases)\}/
53
+ ];
54
+ var GEOJSON_TYPE_RE = /"type"\s*:\s*"(?:FeatureCollection|Feature|Point|LineString|Polygon|MultiPoint|MultiLineString|MultiPolygon|GeometryCollection)"/;
55
+ function looksLikeMap(s) {
56
+ return s.charCodeAt(0) === 123 && GEOJSON_TYPE_RE.test(s);
57
+ }
58
+ var IMAGE_PATTERNS = [
59
+ /^data:image\/(?:png|jpeg|jpg|gif|webp|svg\+xml)[;,]/,
60
+ /^https?:\/\/[^?#\s]+\.(?:png|jpe?g|gif|webp|svg|avif|ico)(?:\?[^#\s]*)?$/i
61
+ ];
62
+ var VIDEO_PATTERNS = [
63
+ /^https?:\/\/[^?#\s]+\.(?:mp4|webm|ogg|mov)(?:\?[^#\s]*)?$/i,
64
+ /^https?:\/\/(?:www\.)?(?:youtube\.com|youtu\.be|vimeo\.com)\//i,
65
+ /^data:video\//
66
+ ];
67
+ var AUDIO_PATTERNS = [
68
+ /^https?:\/\/[^?#\s]+\.(?:mp3|wav|ogg|aac|flac|m4a)(?:\?[^#\s]*)?$/i,
69
+ /^https?:\/\/(?:www\.)?soundcloud\.com\//i,
70
+ /^data:audio\//
71
+ ];
72
+ function detectContentType(content) {
73
+ if (!content || typeof content !== "string") {
74
+ return "html";
75
+ }
76
+ const trimmed = content.trim();
77
+ if (looksLikeChart(trimmed)) return "chart";
78
+ if (looksLikeFlow(trimmed)) return "flow";
79
+ if (looksLikeMap(trimmed)) return "map";
80
+ if (MERMAID_PATTERN.test(trimmed)) return "mermaid";
81
+ if (MATH_PATTERNS.some((p) => p.test(trimmed))) return "math";
82
+ if (IMAGE_PATTERNS.some((p) => p.test(trimmed))) return "image";
83
+ if (VIDEO_PATTERNS.some((p) => p.test(trimmed))) return "video";
84
+ if (AUDIO_PATTERNS.some((p) => p.test(trimmed))) return "audio";
85
+ const jsxScore = countMatches(trimmed, JSX_PATTERNS);
86
+ const mdxScore = countMatches(trimmed, MDX_PATTERNS);
87
+ if (jsxScore > 0 && jsxScore >= mdxScore) {
88
+ return "jsx";
89
+ }
90
+ if (mdxScore >= 2) {
91
+ return "mdx";
92
+ }
93
+ if (mdxScore === 1 && /^import\s+/m.test(trimmed)) {
94
+ return "mdx";
95
+ }
96
+ return "html";
97
+ }
98
+ function countMatches(content, patterns) {
99
+ let count = 0;
100
+ for (const pattern of patterns) {
101
+ if (pattern.test(content)) {
102
+ count++;
103
+ }
104
+ }
105
+ return count;
106
+ }
107
+
108
+ // libs/ui/src/renderer/auto-detect.ts
109
+ var PDF_HEADER = "%PDF-";
110
+ var BASE64_PDF_PREFIX = "JVBER";
111
+ function isPdf(content) {
112
+ if (content.startsWith(PDF_HEADER)) return true;
113
+ const trimmed = content.trim();
114
+ return trimmed.startsWith(BASE64_PDF_PREFIX) || /^data:application\/pdf[;,]/.test(trimmed);
115
+ }
116
+ function isCsv(content) {
117
+ const lines = content.trim().split("\n").slice(0, 5);
118
+ if (lines.length < 2) return false;
119
+ for (const delim of [",", " ", ";"]) {
120
+ const counts = lines.map((line) => line.split(delim).length);
121
+ if (counts[0] > 1 && counts.every((c) => c === counts[0])) return true;
122
+ }
123
+ return false;
124
+ }
125
+ function detectContentType2(content) {
126
+ if (isPdf(content)) return "pdf";
127
+ if (isCsv(content)) return "csv";
128
+ return detectContentType(content);
129
+ }
130
+ var rendererRegistry = [];
131
+ var rendererByType = /* @__PURE__ */ new Map();
132
+ function sortRegistry() {
133
+ rendererRegistry.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
134
+ }
135
+ function registerRenderer(renderer) {
136
+ if (rendererByType.has(renderer.type)) {
137
+ const idx = rendererRegistry.findIndex((r) => r.type === renderer.type);
138
+ if (idx !== -1) rendererRegistry.splice(idx, 1);
139
+ }
140
+ rendererRegistry.push(renderer);
141
+ rendererByType.set(renderer.type, renderer);
142
+ sortRegistry();
143
+ }
144
+ function clearRegistry() {
145
+ rendererRegistry.length = 0;
146
+ rendererByType.clear();
147
+ }
148
+ function getRenderer(type) {
149
+ return rendererByType.get(type);
150
+ }
151
+ function getRegisteredRenderers() {
152
+ return rendererRegistry;
153
+ }
154
+ function renderContent(content, options) {
155
+ const type = detectContentType2(content);
156
+ for (const renderer of rendererRegistry) {
157
+ if (renderer.canHandle(content)) {
158
+ return renderer.render(content, options);
159
+ }
160
+ }
161
+ const exact = rendererByType.get(type);
162
+ if (exact) {
163
+ return exact.render(content, options);
164
+ }
165
+ throw new Error(`No renderer found for content type: ${type}`);
166
+ }
167
+ function ContentView({ content, options, fallback }) {
168
+ return React.createElement(
169
+ Suspense,
170
+ { fallback: fallback ?? React.createElement("div", { className: "fmcp-content-loading" }, "Loading...") },
171
+ React.createElement(ContentViewInner, { content, options })
172
+ );
173
+ }
174
+ function ContentViewInner({ content, options }) {
175
+ return renderContent(content, options);
176
+ }
177
+
178
+ // libs/ui/src/renderer/common/use-renderer-theme.ts
179
+ import { useMemo } from "react";
180
+ import { useTheme } from "@mui/material/styles";
181
+ function extractThemeValues(theme) {
182
+ const palette = theme.palette;
183
+ return {
184
+ mode: palette.mode,
185
+ primary: palette.primary.main,
186
+ secondary: palette.secondary.main,
187
+ error: palette.error.main,
188
+ warning: palette.warning.main,
189
+ success: palette.success.main,
190
+ info: palette.info.main,
191
+ background: palette.background.default,
192
+ paper: palette.background.paper,
193
+ textPrimary: palette.text.primary,
194
+ textSecondary: palette.text.secondary,
195
+ divider: palette.divider,
196
+ fontFamily: theme.typography.fontFamily ?? "sans-serif",
197
+ monoFontFamily: theme.typography["monoFontFamily"] ?? '"SF Mono", "Fira Code", "Fira Mono", "Roboto Mono", monospace',
198
+ fontSize: theme.typography.fontSize ?? 14,
199
+ borderRadius: typeof theme.shape.borderRadius === "number" ? theme.shape.borderRadius : 4,
200
+ seriesColors: [
201
+ palette.primary.main,
202
+ palette.secondary.main,
203
+ palette.error.main,
204
+ palette.warning.main,
205
+ palette.success.main,
206
+ palette.info.main
207
+ ]
208
+ };
209
+ }
210
+ function useRendererTheme() {
211
+ const theme = useTheme();
212
+ return useMemo(() => extractThemeValues(theme), [theme]);
213
+ }
214
+
215
+ // libs/ui/src/renderer/common/inject-stylesheet.ts
216
+ function injectStylesheet(href, id) {
217
+ if (typeof document === "undefined") return;
218
+ if (document.getElementById(id)) return;
219
+ const link = document.createElement("link");
220
+ link.id = id;
221
+ link.rel = "stylesheet";
222
+ link.href = href;
223
+ link.crossOrigin = "anonymous";
224
+ document.head.appendChild(link);
225
+ }
226
+
227
+ // libs/ui/src/renderer/common/lazy-import.ts
228
+ var ESM_SH_BASE = "https://esm.sh/";
229
+ function esmShUrl(pkg, options) {
230
+ let url = `${ESM_SH_BASE}${pkg}`;
231
+ if (options?.external?.length) {
232
+ url += `?external=${options.external.join(",")}`;
233
+ }
234
+ return url;
235
+ }
236
+ function runtimeImport(specifier) {
237
+ const dynamicImport = new Function("s", "return import(s)");
238
+ return dynamicImport(specifier);
239
+ }
240
+ async function runtimeImportWithFallback(bareSpecifier, fallbackUrl) {
241
+ try {
242
+ return await runtimeImport(bareSpecifier);
243
+ } catch {
244
+ return runtimeImport(fallbackUrl);
245
+ }
246
+ }
247
+ function createLazyImport(moduleId, importer) {
248
+ let state = { status: "idle" };
249
+ const doImport = importer ?? (async () => {
250
+ const mod = await runtimeImport(moduleId);
251
+ return mod["default"] ?? mod;
252
+ });
253
+ return {
254
+ load() {
255
+ if (state.status === "loaded") return Promise.resolve(state.module);
256
+ if (state.status === "loading") return state.promise;
257
+ if (state.status === "error") {
258
+ state = { status: "idle" };
259
+ }
260
+ const promise = doImport().then(
261
+ (mod) => {
262
+ state = { status: "loaded", module: mod };
263
+ return mod;
264
+ },
265
+ (err) => {
266
+ const error = err instanceof Error ? err : new Error(`Failed to load module "${moduleId}": ${String(err)}`);
267
+ state = { status: "error", error };
268
+ throw error;
269
+ }
270
+ );
271
+ state = { status: "loading", promise };
272
+ return promise;
273
+ },
274
+ get() {
275
+ return state.status === "loaded" ? state.module : void 0;
276
+ },
277
+ getState() {
278
+ return state;
279
+ },
280
+ reset() {
281
+ state = { status: "idle" };
282
+ }
283
+ };
284
+ }
285
+
286
+ // libs/ui/src/renderer/common/use-lazy-module.ts
287
+ import { useState, useEffect } from "react";
288
+ function useLazyModule(lazy) {
289
+ const [, forceUpdate] = useState(0);
290
+ useEffect(() => {
291
+ if (lazy.getState().status === "loaded") {
292
+ forceUpdate((n) => n + 1);
293
+ return;
294
+ }
295
+ lazy.load().then(
296
+ () => forceUpdate((n) => n + 1),
297
+ () => forceUpdate((n) => n + 1)
298
+ );
299
+ }, [lazy]);
300
+ return lazy.get();
301
+ }
302
+
303
+ // libs/ui/src/renderer/mdx/index.ts
304
+ import React2, { useMemo as useMemo2 } from "react";
305
+ import Box from "@mui/material/Box";
306
+ import Typography from "@mui/material/Typography";
307
+ import Link from "@mui/material/Link";
308
+ import MuiTable from "@mui/material/Table";
309
+ import TableBody from "@mui/material/TableBody";
310
+ import TableCell from "@mui/material/TableCell";
311
+ import TableHead from "@mui/material/TableHead";
312
+ import TableRow from "@mui/material/TableRow";
313
+ import { styled } from "@mui/material/styles";
314
+ var lazyReactMarkdown = createLazyImport(
315
+ "react-markdown",
316
+ async () => {
317
+ const mod = await runtimeImportWithFallback(
318
+ "react-markdown",
319
+ esmShUrl("react-markdown@9", { external: ["react", "react-dom"] })
320
+ );
321
+ return mod;
322
+ }
323
+ );
324
+ var lazyRemarkGfm = createLazyImport("remark-gfm", async () => {
325
+ const mod = await runtimeImportWithFallback("remark-gfm", esmShUrl("remark-gfm@4"));
326
+ return mod;
327
+ });
328
+ var lazyRehypeHighlight = createLazyImport("rehype-highlight", async () => {
329
+ const mod = await runtimeImportWithFallback("rehype-highlight", esmShUrl("rehype-highlight@7"));
330
+ return mod;
331
+ });
332
+ var lazyRehypeRaw = createLazyImport("rehype-raw", async () => {
333
+ const mod = await runtimeImportWithFallback("rehype-raw", esmShUrl("rehype-raw@7"));
334
+ return mod;
335
+ });
336
+ var MarkdownRoot = styled(Box, {
337
+ name: "FrontMcpMarkdown",
338
+ slot: "Root"
339
+ })(() => ({
340
+ lineHeight: 1.7,
341
+ "& > *:first-of-type": { marginTop: 0 },
342
+ "& > *:last-child": { marginBottom: 0 },
343
+ "& img": { maxWidth: "100%", height: "auto" }
344
+ }));
345
+ var CodeBlock = styled("pre", {
346
+ name: "FrontMcpMarkdown",
347
+ slot: "Code"
348
+ })(({ theme }) => {
349
+ const monoFont = String(
350
+ theme.typography["monoFontFamily"] ?? '"SF Mono", "Fira Code", "Roboto Mono", monospace'
351
+ );
352
+ return {
353
+ backgroundColor: theme.palette.mode === "dark" ? theme.palette.grey[900] : theme.palette.grey[100],
354
+ padding: theme.spacing(2),
355
+ borderRadius: Number(theme.shape.borderRadius),
356
+ overflow: "auto",
357
+ fontFamily: monoFont,
358
+ fontSize: "0.875rem",
359
+ "& code": {
360
+ backgroundColor: "transparent",
361
+ padding: 0,
362
+ fontSize: "inherit",
363
+ fontFamily: "inherit"
364
+ }
365
+ };
366
+ });
367
+ var InlineCode = styled("code")(({ theme }) => {
368
+ const monoFont = String(
369
+ theme.typography["monoFontFamily"] ?? '"SF Mono", "Fira Code", "Roboto Mono", monospace'
370
+ );
371
+ return {
372
+ backgroundColor: theme.palette.mode === "dark" ? theme.palette.grey[800] : theme.palette.grey[200],
373
+ padding: "2px 6px",
374
+ borderRadius: Number(theme.shape.borderRadius) / 2,
375
+ fontFamily: monoFont,
376
+ fontSize: "0.85em"
377
+ };
378
+ });
379
+ var Blockquote = styled("blockquote", {
380
+ name: "FrontMcpMarkdown",
381
+ slot: "Blockquote"
382
+ })(({ theme }) => ({
383
+ borderLeft: `4px solid ${theme.palette.primary.main}`,
384
+ margin: theme.spacing(2, 0),
385
+ padding: theme.spacing(1, 2),
386
+ color: theme.palette.text.secondary,
387
+ "& > p": { margin: 0 }
388
+ }));
389
+ function createMuiComponents() {
390
+ return {
391
+ h1: (props) => React2.createElement(Typography, { ...props, variant: "h4", gutterBottom: true }),
392
+ h2: (props) => React2.createElement(Typography, { ...props, variant: "h5", gutterBottom: true }),
393
+ h3: (props) => React2.createElement(Typography, { ...props, variant: "h6", gutterBottom: true }),
394
+ h4: (props) => React2.createElement(Typography, { ...props, variant: "subtitle1", gutterBottom: true, fontWeight: 600 }),
395
+ h5: (props) => React2.createElement(Typography, { ...props, variant: "subtitle2", gutterBottom: true }),
396
+ h6: (props) => React2.createElement(Typography, { ...props, variant: "subtitle2", gutterBottom: true }),
397
+ p: (props) => React2.createElement(Typography, { ...props, variant: "body1", paragraph: true }),
398
+ a: (props) => React2.createElement(Link, { ...props, target: "_blank", rel: "noopener noreferrer" }),
399
+ blockquote: (props) => React2.createElement(Blockquote, props),
400
+ pre: (props) => React2.createElement(CodeBlock, props),
401
+ code: ({ inline, className, children, ...rest }) => {
402
+ if (inline) return React2.createElement(InlineCode, rest, children);
403
+ return React2.createElement("code", { className, ...rest }, children);
404
+ },
405
+ table: (props) => React2.createElement(MuiTable, { ...props, size: "small" }),
406
+ thead: (props) => React2.createElement(TableHead, props),
407
+ tbody: (props) => React2.createElement(TableBody, props),
408
+ tr: (props) => React2.createElement(TableRow, { ...props, hover: true }),
409
+ th: (props) => React2.createElement(TableCell, { ...props, sx: { fontWeight: 600 } }),
410
+ td: (props) => React2.createElement(TableCell, props)
411
+ };
412
+ }
413
+ function MarkdownView({ content, className }) {
414
+ const components = useMemo2(() => createMuiComponents(), []);
415
+ const ReactMarkdownMod = useLazyModule(lazyReactMarkdown);
416
+ const remarkGfmMod = lazyRemarkGfm.get();
417
+ const rehypeHighlightMod = lazyRehypeHighlight.get();
418
+ const rehypeRawMod = lazyRehypeRaw.get();
419
+ if (ReactMarkdownMod) {
420
+ const ReactMarkdown = ReactMarkdownMod.default;
421
+ const remarkPlugins = [];
422
+ const rehypePlugins = [];
423
+ if (remarkGfmMod) remarkPlugins.push(remarkGfmMod.default);
424
+ if (rehypeHighlightMod) rehypePlugins.push(rehypeHighlightMod.default);
425
+ if (rehypeRawMod) rehypePlugins.push(rehypeRawMod.default);
426
+ return React2.createElement(
427
+ MarkdownRoot,
428
+ { className },
429
+ React2.createElement(ReactMarkdown, {
430
+ children: content,
431
+ remarkPlugins,
432
+ rehypePlugins,
433
+ components
434
+ })
435
+ );
436
+ }
437
+ return React2.createElement(MarkdownRoot, { className }, ...renderFallback(content));
438
+ }
439
+ function renderFallback(content) {
440
+ const lines = content.split("\n");
441
+ const elements = [];
442
+ for (let i = 0; i < lines.length; i++) {
443
+ const line = lines[i];
444
+ if (line.startsWith("# ")) {
445
+ elements.push(React2.createElement(Typography, { key: i, variant: "h4", gutterBottom: true }, line.slice(2)));
446
+ } else if (line.startsWith("## ")) {
447
+ elements.push(React2.createElement(Typography, { key: i, variant: "h5", gutterBottom: true }, line.slice(3)));
448
+ } else if (line.startsWith("### ")) {
449
+ elements.push(React2.createElement(Typography, { key: i, variant: "h6", gutterBottom: true }, line.slice(4)));
450
+ } else if (line.startsWith("- ") || line.startsWith("* ")) {
451
+ elements.push(React2.createElement("li", { key: i }, line.slice(2)));
452
+ } else if (line.startsWith("**") && line.endsWith("**")) {
453
+ elements.push(React2.createElement(Typography, { key: i, variant: "body1", fontWeight: 700 }, line.slice(2, -2)));
454
+ } else if (line.trim()) {
455
+ elements.push(React2.createElement(Typography, { key: i, variant: "body1", paragraph: true }, line));
456
+ }
457
+ }
458
+ return elements;
459
+ }
460
+ lazyReactMarkdown.load().catch(() => {
461
+ });
462
+ lazyRemarkGfm.load().catch(() => {
463
+ });
464
+ lazyRehypeHighlight.load().catch(() => {
465
+ });
466
+ lazyRehypeRaw.load().catch(() => {
467
+ });
468
+ var MdxRenderer = class {
469
+ type = "mdx";
470
+ priority = 5;
471
+ canHandle(content) {
472
+ return /^---\s*\n/.test(content) || /import\s+/.test(content) || /<[A-Z]/.test(content) || /^#{1,6}\s+\S/m.test(content) || /^\s*[-*+]\s+\S/m.test(content);
473
+ }
474
+ render(content, options) {
475
+ return React2.createElement(MarkdownView, {
476
+ content,
477
+ className: options?.className ?? "fmcp-mdx-content"
478
+ });
479
+ }
480
+ };
481
+ var mdxRenderer = new MdxRenderer();
482
+
483
+ // libs/ui/src/renderer/html/index.ts
484
+ import React3, { useMemo as useMemo3, useState as useState2, useEffect as useEffect2 } from "react";
485
+ import Box2 from "@mui/material/Box";
486
+ import { styled as styled2 } from "@mui/material/styles";
487
+ var HtmlRoot = styled2(Box2, {
488
+ name: "FrontMcpHtml",
489
+ slot: "Root"
490
+ })(({ theme }) => ({
491
+ "& a": { color: theme.palette.primary.main },
492
+ "& table": { borderCollapse: "collapse", width: "100%" },
493
+ "& th, & td": { border: `1px solid ${theme.palette.divider}`, padding: theme.spacing(1) },
494
+ "& pre": {
495
+ backgroundColor: theme.palette.mode === "dark" ? theme.palette.grey[900] : theme.palette.grey[100],
496
+ padding: theme.spacing(1.5),
497
+ borderRadius: theme.shape.borderRadius,
498
+ overflow: "auto"
499
+ }
500
+ }));
501
+ var purifyModule = null;
502
+ var purifyPromise = null;
503
+ function loadDOMPurify() {
504
+ if (purifyModule) return Promise.resolve(purifyModule);
505
+ if (purifyPromise) return purifyPromise;
506
+ purifyPromise = runtimeImportWithFallback("dompurify", esmShUrl("dompurify@3")).then((mod) => {
507
+ purifyModule = mod;
508
+ return purifyModule;
509
+ }).catch(() => {
510
+ purifyModule = null;
511
+ purifyPromise = null;
512
+ return null;
513
+ });
514
+ return purifyPromise;
515
+ }
516
+ function escapeHtml(html) {
517
+ return html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
518
+ }
519
+ function sanitizeSync(html) {
520
+ if (!purifyModule) return escapeHtml(html);
521
+ const sanitize = purifyModule.default?.sanitize ?? purifyModule.sanitize;
522
+ return sanitize ? sanitize(html) : escapeHtml(html);
523
+ }
524
+ loadDOMPurify();
525
+ function HtmlView({ html, className }) {
526
+ const [purifyReady, setPurifyReady] = useState2(!!purifyModule);
527
+ useEffect2(() => {
528
+ if (!purifyModule) {
529
+ loadDOMPurify().then((mod) => {
530
+ if (mod) setPurifyReady(true);
531
+ });
532
+ }
533
+ }, []);
534
+ const sanitized = useMemo3(() => sanitizeSync(html), [html, purifyReady]);
535
+ return React3.createElement(HtmlRoot, {
536
+ className,
537
+ dangerouslySetInnerHTML: { __html: sanitized }
538
+ });
539
+ }
540
+ var HtmlRenderer = class {
541
+ type = "html";
542
+ priority = 0;
543
+ canHandle(content) {
544
+ return /^\s*</.test(content) && /<\/\w+>/.test(content);
545
+ }
546
+ render(content, options) {
547
+ return React3.createElement(HtmlView, {
548
+ html: content,
549
+ className: options?.className ?? "fmcp-html-content"
550
+ });
551
+ }
552
+ };
553
+ var htmlRenderer = new HtmlRenderer();
554
+
555
+ // libs/ui/src/renderer/react/index.ts
556
+ import React4, { useState as useState3, useEffect as useEffect3 } from "react";
557
+ import Box3 from "@mui/material/Box";
558
+ import Alert from "@mui/material/Alert";
559
+
560
+ // libs/ui/src/runtime/babel-runtime.ts
561
+ var BABEL_STANDALONE_CDN = "https://esm.sh/@babel/standalone@7";
562
+ var BABEL_STANDALONE_FALLBACK_CDN = "https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.10/babel.min.js";
563
+ var babelState = { status: "idle" };
564
+ async function loadBabel() {
565
+ if (babelState.status === "loaded") {
566
+ return babelState.babel;
567
+ }
568
+ if (babelState.status === "loading") {
569
+ return babelState.promise;
570
+ }
571
+ if (babelState.status === "error") {
572
+ throw babelState.error;
573
+ }
574
+ const promise = doLoadBabel();
575
+ babelState = { status: "loading", promise };
576
+ try {
577
+ const babel = await promise;
578
+ babelState = { status: "loaded", babel };
579
+ return babel;
580
+ } catch (error) {
581
+ const err = error instanceof Error ? error : new Error(String(error));
582
+ babelState = { status: "error", error: err };
583
+ throw err;
584
+ }
585
+ }
586
+ async function doLoadBabel() {
587
+ const globalBabel = globalThis["Babel"];
588
+ if (globalBabel && typeof globalBabel.transform === "function") {
589
+ return globalBabel;
590
+ }
591
+ try {
592
+ const module = await import(
593
+ /* @vite-ignore */
594
+ /* webpackIgnore: true */
595
+ BABEL_STANDALONE_CDN
596
+ );
597
+ if (module && typeof module.transform === "function") {
598
+ return module;
599
+ }
600
+ if (module.default && typeof module.default.transform === "function") {
601
+ return module.default;
602
+ }
603
+ } catch {
604
+ }
605
+ return new Promise((resolve, reject) => {
606
+ if (typeof document === "undefined") {
607
+ reject(new Error("Babel Standalone requires a browser environment"));
608
+ return;
609
+ }
610
+ const script = document.createElement("script");
611
+ script.src = BABEL_STANDALONE_FALLBACK_CDN;
612
+ script.crossOrigin = "anonymous";
613
+ script.onload = () => {
614
+ const babel = globalThis["Babel"];
615
+ if (babel && typeof babel.transform === "function") {
616
+ resolve(babel);
617
+ } else {
618
+ reject(new Error("Babel Standalone loaded but transform function not found"));
619
+ }
620
+ };
621
+ script.onerror = () => {
622
+ reject(new Error(`Failed to load Babel Standalone from ${BABEL_STANDALONE_FALLBACK_CDN}`));
623
+ };
624
+ document.head.appendChild(script);
625
+ });
626
+ }
627
+ async function transpileJsx(source, filename = "component.jsx") {
628
+ const babel = await loadBabel();
629
+ const result = babel.transform(source, {
630
+ presets: ["react"],
631
+ filename
632
+ });
633
+ return result.code;
634
+ }
635
+
636
+ // libs/ui/src/renderer/react/index.ts
637
+ function isReactJsx(content) {
638
+ if (/^#{1,6}\s+\S/m.test(content)) return false;
639
+ return /(?:function|const|class)\s+\w+/.test(content) && /(?:return|=>)[\s(]*</.test(content);
640
+ }
641
+ function parseImports(source) {
642
+ const results = [];
643
+ const defaultRe = /^import\s+(\w+)\s+from\s+['"]([^'"]+)['"][\s;]*$/gm;
644
+ let m;
645
+ while ((m = defaultRe.exec(source)) !== null) {
646
+ results.push({ line: m[0], localName: m[1], specifier: m[2], named: false });
647
+ }
648
+ const namedRe = /^import\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"][\s;]*$/gm;
649
+ while ((m = namedRe.exec(source)) !== null) {
650
+ const names = m[1].split(",").map((n) => n.trim()).filter(Boolean);
651
+ for (const name of names) {
652
+ results.push({ line: m[0], localName: name, specifier: m[2], named: true });
653
+ }
654
+ }
655
+ return results;
656
+ }
657
+ function stripImports(source) {
658
+ return source.replace(/^import\s+\w+\s+from\s+['"][^'"]+['"][\s;]*$/gm, "").replace(/^import\s+\{[^}]+\}\s+from\s+['"][^'"]+['"][\s;]*$/gm, "");
659
+ }
660
+ function rewriteExportDefault(source) {
661
+ let result = source.replace(/^export\s+default\s+(function|class)\b/gm, "var __default__ = $1");
662
+ result = result.replace(/^export\s+default\s+(\([^)]*\)\s*=>)/gm, "var __default__ = $1");
663
+ result = result.replace(/^export\s+default\s+(\w+)\s*;?\s*$/gm, "var __default__ = $1;");
664
+ return result;
665
+ }
666
+ function isReactSpecifier(specifier) {
667
+ return specifier === "react" || /^https?:\/\/esm\.sh\/react(?:@[\d.]+)?$/.test(specifier);
668
+ }
669
+ async function resolveModules(imports) {
670
+ const modules = {};
671
+ const specifierMap = /* @__PURE__ */ new Map();
672
+ for (const imp of imports) {
673
+ const existing = specifierMap.get(imp.specifier) ?? [];
674
+ existing.push(imp);
675
+ specifierMap.set(imp.specifier, existing);
676
+ }
677
+ for (const [specifier, specImports] of specifierMap) {
678
+ let mod;
679
+ if (isReactSpecifier(specifier)) {
680
+ mod = React4;
681
+ } else {
682
+ mod = await runtimeImport(specifier);
683
+ }
684
+ for (const imp of specImports) {
685
+ if (imp.named) {
686
+ modules[imp.localName] = mod[imp.localName] ?? mod["default"]?.[imp.localName];
687
+ } else {
688
+ modules[imp.localName] = mod["default"] ?? mod;
689
+ }
690
+ }
691
+ }
692
+ return modules;
693
+ }
694
+ function ReactJsxView({ source, className }) {
695
+ const [Component, setComponent] = useState3(null);
696
+ const [error, setError] = useState3(null);
697
+ const [loading, setLoading] = useState3(true);
698
+ useEffect3(() => {
699
+ let cancelled = false;
700
+ async function transpileAndRender() {
701
+ try {
702
+ const imports = parseImports(source);
703
+ const modules = await resolveModules(imports);
704
+ let code = stripImports(source);
705
+ code = rewriteExportDefault(code);
706
+ code = await transpileJsx(code, "component.jsx");
707
+ code += "\nreturn __default__;";
708
+ const argNames = Object.keys(modules);
709
+ const argValues = argNames.map((n) => modules[n]);
710
+ const factory = new Function(...argNames, code);
711
+ const Comp = factory(...argValues);
712
+ if (!cancelled) {
713
+ setComponent(() => Comp);
714
+ setError(null);
715
+ setLoading(false);
716
+ }
717
+ } catch (err) {
718
+ if (!cancelled) {
719
+ setError(err instanceof Error ? err.message : String(err));
720
+ setComponent(null);
721
+ setLoading(false);
722
+ }
723
+ }
724
+ }
725
+ setLoading(true);
726
+ setError(null);
727
+ setComponent(null);
728
+ transpileAndRender();
729
+ return () => {
730
+ cancelled = true;
731
+ };
732
+ }, [source]);
733
+ if (loading) {
734
+ return React4.createElement(Box3, { className, sx: { p: 2, color: "text.secondary" } }, "Transpiling JSX...");
735
+ }
736
+ if (error) {
737
+ return React4.createElement(
738
+ Box3,
739
+ { className },
740
+ React4.createElement(Alert, { severity: "error", sx: { mb: 1 } }, `JSX render error: ${error}`),
741
+ React4.createElement(
742
+ "pre",
743
+ { style: { fontFamily: "monospace", whiteSpace: "pre-wrap", fontSize: "0.85em" } },
744
+ source
745
+ )
746
+ );
747
+ }
748
+ if (!Component) {
749
+ return React4.createElement(
750
+ Box3,
751
+ { className },
752
+ React4.createElement(Alert, { severity: "warning" }, "No component exported. Use `export default MyComponent`.")
753
+ );
754
+ }
755
+ return React4.createElement(Box3, { className }, React4.createElement(Component, {}));
756
+ }
757
+ var ReactJsxRenderer = class {
758
+ type = "jsx";
759
+ priority = 10;
760
+ canHandle(content) {
761
+ return isReactJsx(content);
762
+ }
763
+ render(content, options) {
764
+ return React4.createElement(ReactJsxView, {
765
+ source: content,
766
+ className: options?.className ?? "fmcp-jsx-content"
767
+ });
768
+ }
769
+ };
770
+ var reactJsxRenderer = new ReactJsxRenderer();
771
+
772
+ // libs/ui/src/renderer/pdf/index.ts
773
+ import React5, { useState as useState4, useCallback, useMemo as useMemo4 } from "react";
774
+ import Box4 from "@mui/material/Box";
775
+ import IconButton from "@mui/material/IconButton";
776
+ import Typography2 from "@mui/material/Typography";
777
+ import TextField from "@mui/material/TextField";
778
+ import { styled as styled3 } from "@mui/material/styles";
779
+ var lazyReactPdf = createLazyImport("react-pdf", async () => {
780
+ const mod = await runtimeImportWithFallback(
781
+ "react-pdf",
782
+ esmShUrl("react-pdf@9", { external: ["react", "react-dom"] })
783
+ );
784
+ const pdfjs = mod["pdfjs"];
785
+ if (pdfjs?.GlobalWorkerOptions) {
786
+ pdfjs.GlobalWorkerOptions.workerSrc = `${ESM_SH_BASE}pdfjs-dist@${pdfjs.version ?? "4"}/build/pdf.worker.min.mjs?raw`;
787
+ }
788
+ return mod;
789
+ });
790
+ function toDataUri(content) {
791
+ if (content.startsWith("data:")) return content;
792
+ if (content.startsWith("%PDF-")) {
793
+ const base64 = typeof btoa === "function" ? btoa(content) : Buffer.from(content).toString("base64");
794
+ return `data:application/pdf;base64,${base64}`;
795
+ }
796
+ return `data:application/pdf;base64,${content}`;
797
+ }
798
+ var PdfRoot = styled3(Box4, {
799
+ name: "FrontMcpPdf",
800
+ slot: "Root"
801
+ })(({ theme }) => ({
802
+ width: "100%",
803
+ borderRadius: theme.shape.borderRadius,
804
+ overflow: "hidden",
805
+ border: `1px solid ${theme.palette.divider}`
806
+ }));
807
+ var Toolbar = styled3(Box4, {
808
+ name: "FrontMcpPdf",
809
+ slot: "Toolbar"
810
+ })(({ theme }) => ({
811
+ display: "flex",
812
+ alignItems: "center",
813
+ gap: theme.spacing(1),
814
+ padding: theme.spacing(1, 2),
815
+ borderBottom: `1px solid ${theme.palette.divider}`,
816
+ backgroundColor: theme.palette.mode === "dark" ? theme.palette.grey[900] : theme.palette.grey[50]
817
+ }));
818
+ var PageContainer = styled3(Box4, {
819
+ name: "FrontMcpPdf",
820
+ slot: "PageContainer"
821
+ })({
822
+ display: "flex",
823
+ justifyContent: "center",
824
+ overflow: "auto",
825
+ maxHeight: 700
826
+ });
827
+ function PdfView({ content, className, title }) {
828
+ const [numPages, setNumPages] = useState4(0);
829
+ const [pageNumber, setPageNumber] = useState4(1);
830
+ const [scale, setScale] = useState4(1);
831
+ const reactPdf = useLazyModule(lazyReactPdf);
832
+ const dataUri = useMemo4(() => toDataUri(content), [content]);
833
+ const onDocumentLoadSuccess = useCallback(({ numPages: n }) => {
834
+ setNumPages(n);
835
+ }, []);
836
+ const goToPrev = useCallback(() => setPageNumber((p) => Math.max(1, p - 1)), []);
837
+ const goToNext = useCallback(() => setPageNumber((p) => Math.min(numPages, p + 1)), []);
838
+ const zoomIn = useCallback(() => setScale((s) => Math.min(3, s + 0.25)), []);
839
+ const zoomOut = useCallback(() => setScale((s) => Math.max(0.25, s - 0.25)), []);
840
+ if (!reactPdf) {
841
+ return React5.createElement("iframe", {
842
+ className: className ?? "fmcp-pdf-content",
843
+ src: dataUri,
844
+ style: { width: "100%", height: "600px", border: "none" },
845
+ title: title ?? "PDF Document"
846
+ });
847
+ }
848
+ const { Document, Page } = reactPdf;
849
+ return React5.createElement(
850
+ PdfRoot,
851
+ { className },
852
+ React5.createElement(
853
+ Toolbar,
854
+ null,
855
+ React5.createElement(
856
+ IconButton,
857
+ { size: "small", onClick: goToPrev, disabled: pageNumber <= 1, "aria-label": "Previous page" },
858
+ "\u25C0"
859
+ ),
860
+ React5.createElement(
861
+ Typography2,
862
+ { variant: "body2", sx: { minWidth: 80, textAlign: "center" } },
863
+ `${pageNumber} / ${numPages || "..."}`
864
+ ),
865
+ React5.createElement(
866
+ IconButton,
867
+ { size: "small", onClick: goToNext, disabled: pageNumber >= numPages, "aria-label": "Next page" },
868
+ "\u25B6"
869
+ ),
870
+ React5.createElement(Box4, { sx: { flex: 1 } }),
871
+ React5.createElement(IconButton, { size: "small", onClick: zoomOut, "aria-label": "Zoom out" }, "\u2212"),
872
+ React5.createElement(
873
+ Typography2,
874
+ { variant: "body2", sx: { minWidth: 50, textAlign: "center" } },
875
+ `${Math.round(scale * 100)}%`
876
+ ),
877
+ React5.createElement(IconButton, { size: "small", onClick: zoomIn, "aria-label": "Zoom in" }, "+"),
878
+ React5.createElement(Box4, { sx: { flex: 1 } }),
879
+ React5.createElement(TextField, {
880
+ size: "small",
881
+ type: "number",
882
+ value: pageNumber,
883
+ onChange: (e) => {
884
+ const n = parseInt(e.target.value, 10);
885
+ if (n >= 1 && n <= numPages) setPageNumber(n);
886
+ },
887
+ sx: { width: 70 },
888
+ slotProps: { htmlInput: { min: 1, max: numPages, "aria-label": "Go to page" } }
889
+ })
890
+ ),
891
+ React5.createElement(
892
+ PageContainer,
893
+ null,
894
+ React5.createElement(
895
+ Document,
896
+ { file: dataUri, onLoadSuccess: onDocumentLoadSuccess },
897
+ React5.createElement(Page, { pageNumber, scale, renderTextLayer: false, renderAnnotationLayer: false })
898
+ )
899
+ )
900
+ );
901
+ }
902
+ lazyReactPdf.load().catch(() => {
903
+ });
904
+ var PdfRenderer = class {
905
+ type = "pdf";
906
+ priority = 90;
907
+ canHandle(content) {
908
+ return content.startsWith("%PDF-") || content.trim().startsWith("JVBER") || /^data:application\/pdf[;,]/.test(content.trim());
909
+ }
910
+ render(content, options) {
911
+ return React5.createElement(PdfView, {
912
+ content,
913
+ className: options?.className ?? "fmcp-pdf-content",
914
+ title: options?.toolName ?? "PDF Document"
915
+ });
916
+ }
917
+ };
918
+ var pdfRenderer = new PdfRenderer();
919
+
920
+ // libs/ui/src/renderer/csv/index.ts
921
+ import React6, { useState as useState5, useMemo as useMemo5, useCallback as useCallback2 } from "react";
922
+ import Box5 from "@mui/material/Box";
923
+ import MuiTable2 from "@mui/material/Table";
924
+ import TableBody2 from "@mui/material/TableBody";
925
+ import TableCell2 from "@mui/material/TableCell";
926
+ import TableContainer from "@mui/material/TableContainer";
927
+ import TableHead2 from "@mui/material/TableHead";
928
+ import TableRow2 from "@mui/material/TableRow";
929
+ import TablePagination from "@mui/material/TablePagination";
930
+ import TableSortLabel from "@mui/material/TableSortLabel";
931
+ import TextField2 from "@mui/material/TextField";
932
+ import { styled as styled4 } from "@mui/material/styles";
933
+ function detectDelimiter(content) {
934
+ const firstLine = content.split("\n")[0];
935
+ const commas = (firstLine.match(/,/g) ?? []).length;
936
+ const tabs = (firstLine.match(/\t/g) ?? []).length;
937
+ const semicolons = (firstLine.match(/;/g) ?? []).length;
938
+ if (tabs > commas && tabs > semicolons) return " ";
939
+ if (semicolons > commas) return ";";
940
+ return ",";
941
+ }
942
+ function parseCsv(content, delimiter) {
943
+ return content.trim().split("\n").map((line) => line.split(delimiter).map((cell) => cell.trim()));
944
+ }
945
+ var CsvRoot = styled4(Box5, {
946
+ name: "FrontMcpCsvTable",
947
+ slot: "Root"
948
+ })({
949
+ width: "100%"
950
+ });
951
+ var StyledHeaderCell = styled4(TableCell2, {
952
+ name: "FrontMcpCsvTable",
953
+ slot: "Header"
954
+ })(({ theme }) => ({
955
+ fontWeight: 600,
956
+ backgroundColor: theme.palette.mode === "dark" ? theme.palette.grey[900] : theme.palette.grey[50],
957
+ whiteSpace: "nowrap"
958
+ }));
959
+ var FilterToolbar = styled4(Box5, {
960
+ name: "FrontMcpCsvTable",
961
+ slot: "Toolbar"
962
+ })(({ theme }) => ({
963
+ padding: theme.spacing(1, 2),
964
+ display: "flex",
965
+ gap: theme.spacing(1)
966
+ }));
967
+ function CsvTableView({ content, className, pageSize = 25 }) {
968
+ const delimiter = useMemo5(() => detectDelimiter(content), [content]);
969
+ const allRows = useMemo5(() => parseCsv(content, delimiter), [content, delimiter]);
970
+ const headers = allRows[0] ?? [];
971
+ const dataRows = useMemo5(() => allRows.slice(1), [allRows]);
972
+ const [page, setPage] = useState5(0);
973
+ const [rowsPerPage, setRowsPerPage] = useState5(pageSize);
974
+ const [sortCol, setSortCol] = useState5(null);
975
+ const [sortDir, setSortDir] = useState5("asc");
976
+ const [filter, setFilter] = useState5("");
977
+ const filteredRows = useMemo5(() => {
978
+ if (!filter) return dataRows;
979
+ const lower = filter.toLowerCase();
980
+ return dataRows.filter((row) => row.some((cell) => cell.toLowerCase().includes(lower)));
981
+ }, [dataRows, filter]);
982
+ const sortedRows = useMemo5(() => {
983
+ if (sortCol === null) return filteredRows;
984
+ const sorted = [...filteredRows];
985
+ sorted.sort((a, b) => {
986
+ const va = a[sortCol] ?? "";
987
+ const vb = b[sortCol] ?? "";
988
+ const numA = Number(va);
989
+ const numB = Number(vb);
990
+ if (!isNaN(numA) && !isNaN(numB)) {
991
+ return sortDir === "asc" ? numA - numB : numB - numA;
992
+ }
993
+ return sortDir === "asc" ? va.localeCompare(vb) : vb.localeCompare(va);
994
+ });
995
+ return sorted;
996
+ }, [filteredRows, sortCol, sortDir]);
997
+ const pageRows = useMemo5(
998
+ () => sortedRows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage),
999
+ [sortedRows, page, rowsPerPage]
1000
+ );
1001
+ const handleSort = useCallback2((colIndex) => {
1002
+ setSortCol((prev) => {
1003
+ if (prev === colIndex) {
1004
+ setSortDir((d) => d === "asc" ? "desc" : "asc");
1005
+ return colIndex;
1006
+ }
1007
+ setSortDir("asc");
1008
+ return colIndex;
1009
+ });
1010
+ }, []);
1011
+ const handleChangePage = useCallback2((_, newPage) => setPage(newPage), []);
1012
+ const handleChangeRowsPerPage = useCallback2((e) => {
1013
+ setRowsPerPage(parseInt(e.target.value, 10));
1014
+ setPage(0);
1015
+ }, []);
1016
+ return React6.createElement(
1017
+ CsvRoot,
1018
+ { className },
1019
+ React6.createElement(
1020
+ FilterToolbar,
1021
+ null,
1022
+ React6.createElement(TextField2, {
1023
+ size: "small",
1024
+ placeholder: "Filter rows...",
1025
+ value: filter,
1026
+ onChange: (e) => {
1027
+ setFilter(e.target.value);
1028
+ setPage(0);
1029
+ },
1030
+ sx: { minWidth: 200 }
1031
+ })
1032
+ ),
1033
+ React6.createElement(
1034
+ TableContainer,
1035
+ { sx: { border: 1, borderColor: "divider", borderRadius: 1 } },
1036
+ React6.createElement(
1037
+ MuiTable2,
1038
+ { size: "small", stickyHeader: true },
1039
+ React6.createElement(
1040
+ TableHead2,
1041
+ null,
1042
+ React6.createElement(
1043
+ TableRow2,
1044
+ null,
1045
+ headers.map(
1046
+ (header, i) => React6.createElement(
1047
+ StyledHeaderCell,
1048
+ { key: i },
1049
+ React6.createElement(
1050
+ TableSortLabel,
1051
+ {
1052
+ active: sortCol === i,
1053
+ direction: sortCol === i ? sortDir : "asc",
1054
+ onClick: () => handleSort(i)
1055
+ },
1056
+ header
1057
+ )
1058
+ )
1059
+ )
1060
+ )
1061
+ ),
1062
+ React6.createElement(
1063
+ TableBody2,
1064
+ null,
1065
+ pageRows.map(
1066
+ (row, ri) => React6.createElement(
1067
+ TableRow2,
1068
+ { key: ri, hover: true },
1069
+ row.map((cell, ci) => React6.createElement(TableCell2, { key: ci }, cell))
1070
+ )
1071
+ )
1072
+ )
1073
+ )
1074
+ ),
1075
+ sortedRows.length > rowsPerPage && React6.createElement(TablePagination, {
1076
+ count: sortedRows.length,
1077
+ page,
1078
+ rowsPerPage,
1079
+ onPageChange: handleChangePage,
1080
+ onRowsPerPageChange: handleChangeRowsPerPage,
1081
+ rowsPerPageOptions: [10, 25, 50, 100]
1082
+ })
1083
+ );
1084
+ }
1085
+ var CsvRenderer = class {
1086
+ type = "csv";
1087
+ priority = 10;
1088
+ canHandle(content) {
1089
+ const lines = content.trim().split("\n").slice(0, 5);
1090
+ if (lines.length < 2) return false;
1091
+ for (const delim of [",", " ", ";"]) {
1092
+ const counts = lines.map((line) => line.split(delim).length);
1093
+ if (counts[0] > 1 && counts.every((c) => c === counts[0])) return true;
1094
+ }
1095
+ return false;
1096
+ }
1097
+ render(content, options) {
1098
+ const pageSize = options?.rendererOptions?.["pageSize"];
1099
+ return React6.createElement(CsvTableView, {
1100
+ content,
1101
+ className: options?.className ?? "fmcp-csv-table",
1102
+ pageSize
1103
+ });
1104
+ }
1105
+ };
1106
+ var csvRenderer = new CsvRenderer();
1107
+
1108
+ // libs/ui/src/renderer/image/index.ts
1109
+ import React7, { useState as useState6, useCallback as useCallback3, useEffect as useEffect4 } from "react";
1110
+ import Box6 from "@mui/material/Box";
1111
+ import Skeleton from "@mui/material/Skeleton";
1112
+ import Alert2 from "@mui/material/Alert";
1113
+ import Typography3 from "@mui/material/Typography";
1114
+ import { styled as styled5 } from "@mui/material/styles";
1115
+ var IMAGE_DATA_URI = /^data:image\/(?:png|jpeg|jpg|gif|webp|svg\+xml|avif)[;,]/;
1116
+ var IMAGE_URL = /^https?:\/\/[^?#\s]+\.(?:png|jpe?g|gif|webp|svg|avif|ico)(?:\?[^#\s]*)?$/i;
1117
+ var IMAGE_SERVICE_URL = /^https?:\/\/(?:picsum\.photos|images\.unsplash\.com|i\.imgur\.com|placekitten\.com|via\.placeholder\.com)\//i;
1118
+ function isImage(content) {
1119
+ const trimmed = content.trim();
1120
+ return IMAGE_DATA_URI.test(trimmed) || IMAGE_URL.test(trimmed) || IMAGE_SERVICE_URL.test(trimmed);
1121
+ }
1122
+ var ImageRoot = styled5(Box6, {
1123
+ name: "FrontMcpImage",
1124
+ slot: "Root"
1125
+ })({
1126
+ display: "inline-block",
1127
+ position: "relative",
1128
+ maxWidth: "100%"
1129
+ });
1130
+ var StyledImage = styled5("img", {
1131
+ name: "FrontMcpImage",
1132
+ slot: "Image"
1133
+ })({
1134
+ maxWidth: "100%",
1135
+ height: "auto",
1136
+ display: "block",
1137
+ cursor: "pointer",
1138
+ borderRadius: "inherit"
1139
+ });
1140
+ var LightboxBackdrop = styled5(Box6, {
1141
+ name: "FrontMcpImage",
1142
+ slot: "Lightbox"
1143
+ })({
1144
+ display: "flex",
1145
+ alignItems: "center",
1146
+ justifyContent: "center",
1147
+ padding: 16
1148
+ });
1149
+ var LightboxImage = styled5("img")({
1150
+ maxWidth: "90vw",
1151
+ maxHeight: "90vh",
1152
+ objectFit: "contain",
1153
+ borderRadius: 8
1154
+ });
1155
+ function LightboxOverlay({ src, alt, onClose }) {
1156
+ return React7.createElement(
1157
+ LightboxBackdrop,
1158
+ {
1159
+ onClick: onClose,
1160
+ sx: {
1161
+ position: "fixed",
1162
+ inset: 0,
1163
+ zIndex: 1300,
1164
+ bgcolor: "rgba(0,0,0,0.8)"
1165
+ }
1166
+ },
1167
+ React7.createElement(LightboxImage, { src, alt })
1168
+ );
1169
+ }
1170
+ function ImageView({ src, alt, caption, className }) {
1171
+ const [loaded, setLoaded] = useState6(false);
1172
+ const [error, setError] = useState6(false);
1173
+ const [lightboxOpen, setLightboxOpen] = useState6(false);
1174
+ useEffect4(() => {
1175
+ setLoaded(false);
1176
+ setError(false);
1177
+ setLightboxOpen(false);
1178
+ }, [src]);
1179
+ const handleLoad = useCallback3(() => setLoaded(true), []);
1180
+ const handleError = useCallback3(() => {
1181
+ setLoaded(true);
1182
+ setError(true);
1183
+ }, []);
1184
+ if (error) {
1185
+ return React7.createElement(Alert2, { severity: "error" }, `Failed to load image: ${src}`);
1186
+ }
1187
+ return React7.createElement(
1188
+ ImageRoot,
1189
+ { className },
1190
+ !loaded && React7.createElement(Skeleton, { variant: "rectangular", width: 400, height: 300 }),
1191
+ React7.createElement(StyledImage, {
1192
+ src,
1193
+ alt: alt ?? "Image",
1194
+ onLoad: handleLoad,
1195
+ onError: handleError,
1196
+ onClick: () => setLightboxOpen(true),
1197
+ style: loaded ? void 0 : { display: "none" }
1198
+ }),
1199
+ caption && React7.createElement(
1200
+ Typography3,
1201
+ { variant: "caption", color: "text.secondary", sx: { mt: 0.5, display: "block", textAlign: "center" } },
1202
+ caption
1203
+ ),
1204
+ lightboxOpen && React7.createElement(LightboxOverlay, {
1205
+ src,
1206
+ alt: alt ?? "Image",
1207
+ onClose: () => setLightboxOpen(false)
1208
+ })
1209
+ );
1210
+ }
1211
+ var ImageRenderer = class {
1212
+ type = "image";
1213
+ priority = 30;
1214
+ canHandle(content) {
1215
+ return isImage(content);
1216
+ }
1217
+ render(content, options) {
1218
+ const caption = options?.rendererOptions?.["caption"];
1219
+ return React7.createElement(ImageView, {
1220
+ src: content.trim(),
1221
+ alt: options?.toolName ?? "Image",
1222
+ caption,
1223
+ className: options?.className ?? "fmcp-image-content"
1224
+ });
1225
+ }
1226
+ };
1227
+ var imageRenderer = new ImageRenderer();
1228
+
1229
+ // libs/ui/src/renderer/charts/index.ts
1230
+ import React8, { useMemo as useMemo6 } from "react";
1231
+ import Box7 from "@mui/material/Box";
1232
+ import Alert3 from "@mui/material/Alert";
1233
+ import Typography4 from "@mui/material/Typography";
1234
+ import { styled as styled6 } from "@mui/material/styles";
1235
+ var CHART_TYPE_RE2 = /"type"\s*:\s*"(?:bar|line|area|pie|scatter|radar|composed)"/;
1236
+ function isChart(content) {
1237
+ const trimmed = content.trim();
1238
+ if (trimmed.charCodeAt(0) !== 123) return false;
1239
+ return CHART_TYPE_RE2.test(trimmed) && trimmed.includes('"data"');
1240
+ }
1241
+ var lazyRecharts = createLazyImport("recharts", async () => {
1242
+ const mod = await runtimeImportWithFallback("recharts", esmShUrl("recharts@2", { external: ["react", "react-dom"] }));
1243
+ return mod;
1244
+ });
1245
+ var ChartRoot = styled6(Box7, {
1246
+ name: "FrontMcpChart",
1247
+ slot: "Root"
1248
+ })(({ theme }) => ({
1249
+ width: "100%",
1250
+ padding: theme.spacing(2)
1251
+ }));
1252
+ function ChartView({ config, className }) {
1253
+ const themeValues = useRendererTheme();
1254
+ const recharts = useLazyModule(lazyRecharts);
1255
+ const colors = useMemo6(() => config.colors ?? themeValues.seriesColors, [config.colors, themeValues.seriesColors]);
1256
+ if (!recharts) {
1257
+ return React8.createElement(Alert3, { severity: "info" }, "Loading chart library...");
1258
+ }
1259
+ const { ResponsiveContainer, Tooltip, Legend, CartesianGrid, XAxis, YAxis } = recharts;
1260
+ const height = config.height ?? 400;
1261
+ const xKey = config.xKey ?? "name";
1262
+ const yKeys = config.yKeys ?? Object.keys(config.data?.[0] ?? {}).filter((k) => k !== xKey);
1263
+ const chartContent = renderChartType(
1264
+ recharts,
1265
+ config.type,
1266
+ config.data,
1267
+ xKey,
1268
+ yKeys,
1269
+ colors,
1270
+ themeValues.borderRadius
1271
+ );
1272
+ return React8.createElement(
1273
+ ChartRoot,
1274
+ { className },
1275
+ config.title && React8.createElement(
1276
+ Typography4,
1277
+ { variant: "subtitle1", gutterBottom: true, fontWeight: 600, textAlign: "center" },
1278
+ config.title
1279
+ ),
1280
+ React8.createElement(ResponsiveContainer, { width: "100%", height }, chartContent)
1281
+ );
1282
+ }
1283
+ function renderChartType(rc, type, data, xKey, yKeys, colors, borderRadius) {
1284
+ const commonProps = { data };
1285
+ const grid = React8.createElement(rc.CartesianGrid, { strokeDasharray: "3 3", opacity: 0.3 });
1286
+ const xAxis = React8.createElement(rc.XAxis, { dataKey: xKey });
1287
+ const yAxis = React8.createElement(rc.YAxis);
1288
+ const tooltip = React8.createElement(rc.Tooltip, { contentStyle: { borderRadius } });
1289
+ const legend = React8.createElement(rc.Legend);
1290
+ switch (type) {
1291
+ case "bar":
1292
+ return React8.createElement(
1293
+ rc.BarChart,
1294
+ commonProps,
1295
+ grid,
1296
+ xAxis,
1297
+ yAxis,
1298
+ tooltip,
1299
+ legend,
1300
+ ...yKeys.map(
1301
+ (key, i) => React8.createElement(rc.Bar, {
1302
+ key,
1303
+ dataKey: key,
1304
+ fill: colors[i % colors.length],
1305
+ radius: [borderRadius, borderRadius, 0, 0]
1306
+ })
1307
+ )
1308
+ );
1309
+ case "line":
1310
+ return React8.createElement(
1311
+ rc.LineChart,
1312
+ commonProps,
1313
+ grid,
1314
+ xAxis,
1315
+ yAxis,
1316
+ tooltip,
1317
+ legend,
1318
+ ...yKeys.map(
1319
+ (key, i) => React8.createElement(rc.Line, {
1320
+ key,
1321
+ type: "monotone",
1322
+ dataKey: key,
1323
+ stroke: colors[i % colors.length],
1324
+ strokeWidth: 2
1325
+ })
1326
+ )
1327
+ );
1328
+ case "area":
1329
+ return React8.createElement(
1330
+ rc.AreaChart,
1331
+ commonProps,
1332
+ grid,
1333
+ xAxis,
1334
+ yAxis,
1335
+ tooltip,
1336
+ legend,
1337
+ ...yKeys.map(
1338
+ (key, i) => React8.createElement(rc.Area, {
1339
+ key,
1340
+ type: "monotone",
1341
+ dataKey: key,
1342
+ stroke: colors[i % colors.length],
1343
+ fill: colors[i % colors.length],
1344
+ fillOpacity: 0.3
1345
+ })
1346
+ )
1347
+ );
1348
+ case "pie":
1349
+ return React8.createElement(
1350
+ rc.PieChart,
1351
+ {},
1352
+ tooltip,
1353
+ legend,
1354
+ React8.createElement(
1355
+ rc.Pie,
1356
+ { data, dataKey: yKeys[0] ?? "value", nameKey: xKey, cx: "50%", cy: "50%", outerRadius: "80%", label: true },
1357
+ ...data.map((_, i) => React8.createElement(rc.Cell, { key: i, fill: colors[i % colors.length] }))
1358
+ )
1359
+ );
1360
+ case "scatter":
1361
+ return React8.createElement(
1362
+ rc.ScatterChart,
1363
+ {},
1364
+ grid,
1365
+ xAxis,
1366
+ yAxis,
1367
+ tooltip,
1368
+ legend,
1369
+ ...yKeys.map(
1370
+ (key, i) => React8.createElement(rc.Scatter, { key, name: key, dataKey: key, data, fill: colors[i % colors.length] })
1371
+ )
1372
+ );
1373
+ case "radar":
1374
+ return React8.createElement(
1375
+ rc.RadarChart,
1376
+ { cx: "50%", cy: "50%", outerRadius: "80%", data },
1377
+ React8.createElement(rc.PolarGrid),
1378
+ React8.createElement(rc.PolarAngleAxis, { dataKey: xKey }),
1379
+ React8.createElement(rc.PolarRadiusAxis),
1380
+ tooltip,
1381
+ legend,
1382
+ ...yKeys.map(
1383
+ (key, i) => React8.createElement(rc.Radar, {
1384
+ key,
1385
+ name: key,
1386
+ dataKey: key,
1387
+ stroke: colors[i % colors.length],
1388
+ fill: colors[i % colors.length],
1389
+ fillOpacity: 0.3
1390
+ })
1391
+ )
1392
+ );
1393
+ case "composed":
1394
+ return React8.createElement(
1395
+ rc.ComposedChart,
1396
+ commonProps,
1397
+ grid,
1398
+ xAxis,
1399
+ yAxis,
1400
+ tooltip,
1401
+ legend,
1402
+ ...yKeys.map((key, i) => {
1403
+ if (i % 2 === 0) {
1404
+ return React8.createElement(rc.Bar, {
1405
+ key,
1406
+ dataKey: key,
1407
+ fill: colors[i % colors.length],
1408
+ radius: [borderRadius, borderRadius, 0, 0]
1409
+ });
1410
+ }
1411
+ return React8.createElement(rc.Line, {
1412
+ key,
1413
+ type: "monotone",
1414
+ dataKey: key,
1415
+ stroke: colors[i % colors.length],
1416
+ strokeWidth: 2
1417
+ });
1418
+ })
1419
+ );
1420
+ default:
1421
+ return React8.createElement(rc.BarChart, commonProps, grid, xAxis, yAxis, tooltip, legend);
1422
+ }
1423
+ }
1424
+ lazyRecharts.load().catch(() => {
1425
+ });
1426
+ var ChartsRenderer = class {
1427
+ type = "chart";
1428
+ priority = 80;
1429
+ canHandle(content) {
1430
+ return isChart(content);
1431
+ }
1432
+ render(content, options) {
1433
+ try {
1434
+ const config = JSON.parse(content);
1435
+ return React8.createElement(ChartView, {
1436
+ config,
1437
+ className: options?.className ?? "fmcp-chart-content"
1438
+ });
1439
+ } catch {
1440
+ return React8.createElement(Alert3, { severity: "error" }, "Invalid chart JSON");
1441
+ }
1442
+ }
1443
+ };
1444
+ var chartsRenderer = new ChartsRenderer();
1445
+
1446
+ // libs/ui/src/renderer/mermaid/index.ts
1447
+ import React9, { useEffect as useEffect5, useRef, useState as useState7, useId } from "react";
1448
+ import Box8 from "@mui/material/Box";
1449
+ import Alert4 from "@mui/material/Alert";
1450
+ import { styled as styled7 } from "@mui/material/styles";
1451
+ var MERMAID_PATTERN2 = /^\s*(?:graph|sequenceDiagram|classDiagram|stateDiagram|flowchart|erDiagram|gantt|pie|journey|gitGraph)\b/;
1452
+ function isMermaid(content) {
1453
+ return MERMAID_PATTERN2.test(content.trim());
1454
+ }
1455
+ var lazyMermaid = createLazyImport("mermaid", async () => {
1456
+ const mod = await runtimeImportWithFallback("mermaid", esmShUrl("mermaid@11"));
1457
+ const mermaid = mod["default"] ?? mod;
1458
+ return mermaid;
1459
+ });
1460
+ var MermaidRoot = styled7(Box8, {
1461
+ name: "FrontMcpMermaid",
1462
+ slot: "Root"
1463
+ })(({ theme }) => ({
1464
+ width: "100%",
1465
+ display: "flex",
1466
+ justifyContent: "center",
1467
+ padding: theme.spacing(2),
1468
+ "& svg": {
1469
+ maxWidth: "100%",
1470
+ height: "auto"
1471
+ }
1472
+ }));
1473
+ function getMermaidTheme(tv) {
1474
+ return tv.mode === "dark" ? "dark" : "default";
1475
+ }
1476
+ function getMermaidThemeVariables(tv) {
1477
+ return {
1478
+ primaryColor: tv.primary,
1479
+ secondaryColor: tv.secondary,
1480
+ tertiaryColor: tv.info,
1481
+ primaryTextColor: tv.textPrimary,
1482
+ secondaryTextColor: tv.textSecondary,
1483
+ lineColor: tv.divider,
1484
+ fontFamily: tv.fontFamily,
1485
+ fontSize: `${tv.fontSize}px`
1486
+ };
1487
+ }
1488
+ function MermaidView({ definition, className }) {
1489
+ const containerRef = useRef(null);
1490
+ const [svg, setSvg] = useState7(null);
1491
+ const [error, setError] = useState7(null);
1492
+ const themeValues = useRendererTheme();
1493
+ const uniqueId = useId().replace(/:/g, "-");
1494
+ useEffect5(() => {
1495
+ let cancelled = false;
1496
+ async function renderDiagram() {
1497
+ try {
1498
+ const mermaid = lazyMermaid.get() ?? await lazyMermaid.load();
1499
+ mermaid.initialize({
1500
+ startOnLoad: false,
1501
+ theme: getMermaidTheme(themeValues),
1502
+ themeVariables: getMermaidThemeVariables(themeValues),
1503
+ securityLevel: "strict"
1504
+ });
1505
+ const result = await mermaid.render(`mermaid-${uniqueId}`, definition);
1506
+ if (!cancelled) {
1507
+ setSvg(result.svg);
1508
+ setError(null);
1509
+ }
1510
+ } catch (err) {
1511
+ if (!cancelled) {
1512
+ setError(err instanceof Error ? err.message : String(err));
1513
+ setSvg(null);
1514
+ }
1515
+ }
1516
+ }
1517
+ renderDiagram();
1518
+ return () => {
1519
+ cancelled = true;
1520
+ };
1521
+ }, [definition, themeValues, uniqueId]);
1522
+ if (error) {
1523
+ return React9.createElement(
1524
+ Box8,
1525
+ { className },
1526
+ React9.createElement(Alert4, { severity: "error", sx: { mb: 1 } }, `Mermaid parse error: ${error}`),
1527
+ React9.createElement(
1528
+ "pre",
1529
+ { style: { fontFamily: "monospace", whiteSpace: "pre-wrap", fontSize: "0.85em" } },
1530
+ definition
1531
+ )
1532
+ );
1533
+ }
1534
+ if (!svg) {
1535
+ return React9.createElement(
1536
+ MermaidRoot,
1537
+ { className },
1538
+ React9.createElement(Box8, { sx: { color: "text.secondary" } }, "Rendering diagram...")
1539
+ );
1540
+ }
1541
+ return React9.createElement(MermaidRoot, {
1542
+ ref: containerRef,
1543
+ className,
1544
+ dangerouslySetInnerHTML: { __html: svg }
1545
+ });
1546
+ }
1547
+ lazyMermaid.load().catch(() => {
1548
+ });
1549
+ var MermaidRenderer = class {
1550
+ type = "mermaid";
1551
+ priority = 50;
1552
+ canHandle(content) {
1553
+ return isMermaid(content);
1554
+ }
1555
+ render(content, options) {
1556
+ return React9.createElement(MermaidView, {
1557
+ definition: content.trim(),
1558
+ className: options?.className ?? "fmcp-mermaid-content"
1559
+ });
1560
+ }
1561
+ };
1562
+ var mermaidRenderer = new MermaidRenderer();
1563
+
1564
+ // libs/ui/src/renderer/flow/index.ts
1565
+ import React10, { useEffect as useEffect6, useMemo as useMemo7 } from "react";
1566
+ import Box9 from "@mui/material/Box";
1567
+ import Alert5 from "@mui/material/Alert";
1568
+ import Typography5 from "@mui/material/Typography";
1569
+ import { styled as styled8 } from "@mui/material/styles";
1570
+ var XYFLOW_CSS_URL = "https://esm.sh/@xyflow/react@12/dist/style.css";
1571
+ var XYFLOW_CSS_ID = "fmcp-xyflow-css";
1572
+ function isFlow(content) {
1573
+ const trimmed = content.trim();
1574
+ if (trimmed.charCodeAt(0) !== 123) return false;
1575
+ return trimmed.includes('"nodes"') && trimmed.includes('"edges"');
1576
+ }
1577
+ var lazyXYFlow = createLazyImport("@xyflow/react", async () => {
1578
+ const mod = await runtimeImportWithFallback(
1579
+ "@xyflow/react",
1580
+ esmShUrl("@xyflow/react@12", { external: ["react", "react-dom"] })
1581
+ );
1582
+ return mod;
1583
+ });
1584
+ var FlowRoot = styled8(Box9, {
1585
+ name: "FrontMcpFlow",
1586
+ slot: "Root"
1587
+ })(({ theme }) => ({
1588
+ width: "100%",
1589
+ borderRadius: theme.shape.borderRadius,
1590
+ overflow: "hidden",
1591
+ border: `1px solid ${theme.palette.divider}`
1592
+ }));
1593
+ function FlowView({ config, className }) {
1594
+ useEffect6(() => {
1595
+ injectStylesheet(XYFLOW_CSS_URL, XYFLOW_CSS_ID);
1596
+ }, []);
1597
+ const themeValues = useRendererTheme();
1598
+ const xyflow = useLazyModule(lazyXYFlow);
1599
+ const height = config.height ?? 500;
1600
+ const styledNodes = useMemo7(() => {
1601
+ return config.nodes.map((node) => ({
1602
+ ...node,
1603
+ style: {
1604
+ background: themeValues.paper,
1605
+ color: themeValues.textPrimary,
1606
+ border: `1px solid ${themeValues.divider}`,
1607
+ borderRadius: themeValues.borderRadius,
1608
+ padding: 8,
1609
+ fontSize: themeValues.fontSize,
1610
+ fontFamily: themeValues.fontFamily,
1611
+ ...node.style
1612
+ }
1613
+ }));
1614
+ }, [config.nodes, themeValues]);
1615
+ const styledEdges = useMemo7(() => {
1616
+ return config.edges.map((edge, i) => ({
1617
+ ...edge,
1618
+ style: {
1619
+ stroke: themeValues.seriesColors[i % themeValues.seriesColors.length],
1620
+ strokeWidth: 2,
1621
+ ...edge.style
1622
+ }
1623
+ }));
1624
+ }, [config.edges, themeValues]);
1625
+ if (!xyflow) {
1626
+ return React10.createElement(Alert5, { severity: "info" }, "Loading flow diagram library...");
1627
+ }
1628
+ const { ReactFlow, Controls, MiniMap, Background } = xyflow;
1629
+ return React10.createElement(
1630
+ FlowRoot,
1631
+ { className },
1632
+ config.title && React10.createElement(
1633
+ Typography5,
1634
+ { variant: "subtitle1", fontWeight: 600, sx: { p: 1.5, borderBottom: 1, borderColor: "divider" } },
1635
+ config.title
1636
+ ),
1637
+ React10.createElement(
1638
+ Box9,
1639
+ { sx: { height } },
1640
+ React10.createElement(
1641
+ ReactFlow,
1642
+ {
1643
+ nodes: styledNodes,
1644
+ edges: styledEdges,
1645
+ fitView: config.fitView !== false,
1646
+ proOptions: { hideAttribution: true }
1647
+ },
1648
+ React10.createElement(Controls, {
1649
+ style: {
1650
+ backgroundColor: themeValues.paper,
1651
+ borderRadius: themeValues.borderRadius,
1652
+ border: `1px solid ${themeValues.divider}`
1653
+ }
1654
+ }),
1655
+ React10.createElement(MiniMap, {
1656
+ style: {
1657
+ backgroundColor: themeValues.background,
1658
+ borderRadius: themeValues.borderRadius
1659
+ },
1660
+ nodeColor: themeValues.primary
1661
+ }),
1662
+ Background && React10.createElement(Background, {
1663
+ color: themeValues.divider,
1664
+ gap: 16
1665
+ })
1666
+ )
1667
+ )
1668
+ );
1669
+ }
1670
+ lazyXYFlow.load().catch(() => {
1671
+ });
1672
+ var FlowRenderer = class {
1673
+ type = "flow";
1674
+ priority = 70;
1675
+ canHandle(content) {
1676
+ return isFlow(content);
1677
+ }
1678
+ render(content, options) {
1679
+ try {
1680
+ const config = JSON.parse(content);
1681
+ return React10.createElement(FlowView, {
1682
+ config,
1683
+ className: options?.className ?? "fmcp-flow-content"
1684
+ });
1685
+ } catch {
1686
+ return React10.createElement(Alert5, { severity: "error" }, "Invalid flow JSON");
1687
+ }
1688
+ }
1689
+ };
1690
+ var flowRenderer = new FlowRenderer();
1691
+
1692
+ // libs/ui/src/renderer/math/index.ts
1693
+ import React11, { useEffect as useEffect7, useMemo as useMemo8 } from "react";
1694
+ import Box10 from "@mui/material/Box";
1695
+ import Alert6 from "@mui/material/Alert";
1696
+ import { styled as styled9 } from "@mui/material/styles";
1697
+ var KATEX_CSS_URL = "https://esm.sh/katex@0.16.11/dist/katex.min.css";
1698
+ var KATEX_CSS_ID = "fmcp-katex-css";
1699
+ var MATH_DISPLAY = /\$\$(?:[^$]|\$(?!\$))+\$\$/s;
1700
+ var MATH_INLINE = /\$[^$\n]+?\$/;
1701
+ var MATH_BRACKET_DISPLAY = /\\\[(?:[^\\]|\\.)*\\\]/s;
1702
+ var MATH_PAREN_INLINE = /\\\((?:[^\\]|\\.)*\\\)/s;
1703
+ var MATH_BEGIN = /\\begin\{(?:equation|align|gather|matrix|pmatrix|bmatrix|cases)\}/;
1704
+ function isMath(content) {
1705
+ const trimmed = content.trim();
1706
+ return MATH_DISPLAY.test(trimmed) || MATH_INLINE.test(trimmed) || MATH_BRACKET_DISPLAY.test(trimmed) || MATH_PAREN_INLINE.test(trimmed) || MATH_BEGIN.test(trimmed);
1707
+ }
1708
+ var lazyKatex = createLazyImport("katex", async () => {
1709
+ const mod = await runtimeImportWithFallback("katex", esmShUrl("katex@0.16"));
1710
+ return mod;
1711
+ });
1712
+ var MathRoot = styled9(Box10, {
1713
+ name: "FrontMcpMath",
1714
+ slot: "Root"
1715
+ })(({ theme }) => ({
1716
+ color: theme.palette.text.primary,
1717
+ "& .katex-display": {
1718
+ margin: theme.spacing(2, 0),
1719
+ textAlign: "center"
1720
+ }
1721
+ }));
1722
+ var MathDisplay = styled9(Box10, {
1723
+ name: "FrontMcpMath",
1724
+ slot: "Display"
1725
+ })(({ theme }) => ({
1726
+ display: "block",
1727
+ textAlign: "center",
1728
+ margin: theme.spacing(2, 0),
1729
+ fontSize: "1.2em",
1730
+ overflow: "auto"
1731
+ }));
1732
+ var MathInline = styled9("span", {
1733
+ name: "FrontMcpMath",
1734
+ slot: "Inline"
1735
+ })({
1736
+ display: "inline"
1737
+ });
1738
+ function parseMathContent(source) {
1739
+ const segments = [];
1740
+ const mathRegex = /(\$\$(?:[^$]|\$(?!\$))+\$\$|\$[^$\n]+?\$|\\\[(?:[^\\]|\\.)*\\\]|\\\((?:[^\\]|\\.)*\\\)|\\begin\{(?:[^\\]|\\.)*\\end\{[^}]+\})/gs;
1741
+ let lastIndex = 0;
1742
+ let match;
1743
+ while ((match = mathRegex.exec(source)) !== null) {
1744
+ if (match.index > lastIndex) {
1745
+ segments.push({ type: "text", content: source.slice(lastIndex, match.index) });
1746
+ }
1747
+ const raw = match[0];
1748
+ if (raw.startsWith("$$")) {
1749
+ segments.push({ type: "display", content: raw.slice(2, -2).trim() });
1750
+ } else if (raw.startsWith("\\[")) {
1751
+ segments.push({ type: "display", content: raw.slice(2, -2).trim() });
1752
+ } else if (raw.startsWith("\\begin")) {
1753
+ segments.push({ type: "display", content: raw });
1754
+ } else if (raw.startsWith("\\(")) {
1755
+ segments.push({ type: "inline", content: raw.slice(2, -2).trim() });
1756
+ } else if (raw.startsWith("$")) {
1757
+ segments.push({ type: "inline", content: raw.slice(1, -1).trim() });
1758
+ }
1759
+ lastIndex = match.index + raw.length;
1760
+ }
1761
+ if (lastIndex < source.length) {
1762
+ segments.push({ type: "text", content: source.slice(lastIndex) });
1763
+ }
1764
+ return segments;
1765
+ }
1766
+ function MathView({ content, className }) {
1767
+ useEffect7(() => {
1768
+ injectStylesheet(KATEX_CSS_URL, KATEX_CSS_ID);
1769
+ }, []);
1770
+ const katexMod = useLazyModule(lazyKatex);
1771
+ const segments = useMemo8(() => parseMathContent(content), [content]);
1772
+ const renderToString = katexMod?.default?.renderToString ?? katexMod?.renderToString;
1773
+ if (!renderToString) {
1774
+ return React11.createElement(
1775
+ MathRoot,
1776
+ { className },
1777
+ React11.createElement("pre", { style: { fontFamily: "monospace", whiteSpace: "pre-wrap" } }, content)
1778
+ );
1779
+ }
1780
+ const elements = segments.map((seg, i) => {
1781
+ if (seg.type === "text") {
1782
+ return React11.createElement("span", { key: i }, seg.content);
1783
+ }
1784
+ try {
1785
+ const html = renderToString(seg.content, {
1786
+ displayMode: seg.type === "display",
1787
+ throwOnError: false
1788
+ });
1789
+ if (seg.type === "display") {
1790
+ return React11.createElement(MathDisplay, {
1791
+ key: i,
1792
+ dangerouslySetInnerHTML: { __html: html }
1793
+ });
1794
+ }
1795
+ return React11.createElement(MathInline, {
1796
+ key: i,
1797
+ dangerouslySetInnerHTML: { __html: html }
1798
+ });
1799
+ } catch (err) {
1800
+ return React11.createElement(
1801
+ Alert6,
1802
+ { key: i, severity: "error", sx: { my: 1 } },
1803
+ `LaTeX error: ${err instanceof Error ? err.message : String(err)}
1804
+ Source: ${seg.content}`
1805
+ );
1806
+ }
1807
+ });
1808
+ return React11.createElement(MathRoot, { className }, ...elements);
1809
+ }
1810
+ lazyKatex.load().catch(() => {
1811
+ });
1812
+ var MathRenderer = class {
1813
+ type = "math";
1814
+ priority = 40;
1815
+ canHandle(content) {
1816
+ return isMath(content);
1817
+ }
1818
+ render(content, options) {
1819
+ return React11.createElement(MathView, {
1820
+ content,
1821
+ className: options?.className ?? "fmcp-math-content"
1822
+ });
1823
+ }
1824
+ };
1825
+ var mathRenderer = new MathRenderer();
1826
+
1827
+ // libs/ui/src/renderer/maps/index.ts
1828
+ import React12, { useEffect as useEffect8 } from "react";
1829
+ import Box11 from "@mui/material/Box";
1830
+ import Alert7 from "@mui/material/Alert";
1831
+ import Paper from "@mui/material/Paper";
1832
+ import Typography6 from "@mui/material/Typography";
1833
+ import { styled as styled10 } from "@mui/material/styles";
1834
+ var LEAFLET_CSS_URL = "https://esm.sh/leaflet@1.9.4/dist/leaflet.css";
1835
+ var LEAFLET_CSS_ID = "fmcp-leaflet-css";
1836
+ var DEFAULT_TILE_URL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
1837
+ var DEFAULT_ATTRIBUTION = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
1838
+ var GEOJSON_TYPE_RE2 = /"type"\s*:\s*"(?:FeatureCollection|Feature|Point|LineString|Polygon|MultiPoint|MultiLineString|MultiPolygon|GeometryCollection)"/;
1839
+ function isMap(content) {
1840
+ const trimmed = content.trim();
1841
+ if (trimmed.charCodeAt(0) === 123 && GEOJSON_TYPE_RE2.test(trimmed)) return true;
1842
+ try {
1843
+ const parsed = JSON.parse(trimmed);
1844
+ return !!(parsed.center && Array.isArray(parsed.center) || parsed.markers && Array.isArray(parsed.markers) || parsed.geojson && typeof parsed.geojson === "object");
1845
+ } catch {
1846
+ return false;
1847
+ }
1848
+ }
1849
+ var lazyReactLeaflet = createLazyImport("react-leaflet", async () => {
1850
+ const mod = await runtimeImportWithFallback(
1851
+ "react-leaflet",
1852
+ esmShUrl("react-leaflet@5", { external: ["react", "react-dom"] })
1853
+ );
1854
+ return mod;
1855
+ });
1856
+ var MapRoot = styled10(Box11, {
1857
+ name: "FrontMcpMap",
1858
+ slot: "Root"
1859
+ })(({ theme }) => ({
1860
+ width: "100%",
1861
+ borderRadius: theme.shape.borderRadius,
1862
+ overflow: "hidden",
1863
+ border: `1px solid ${theme.palette.divider}`
1864
+ }));
1865
+ function parseMapConfig(content) {
1866
+ const parsed = JSON.parse(content);
1867
+ if (parsed.type && [
1868
+ "FeatureCollection",
1869
+ "Feature",
1870
+ "Point",
1871
+ "LineString",
1872
+ "Polygon",
1873
+ "MultiPoint",
1874
+ "MultiLineString",
1875
+ "MultiPolygon",
1876
+ "GeometryCollection"
1877
+ ].includes(parsed.type)) {
1878
+ return {
1879
+ center: [0, 0],
1880
+ zoom: 2,
1881
+ geojson: parsed
1882
+ };
1883
+ }
1884
+ return parsed;
1885
+ }
1886
+ function MapView({ config, className }) {
1887
+ useEffect8(() => {
1888
+ injectStylesheet(LEAFLET_CSS_URL, LEAFLET_CSS_ID);
1889
+ }, []);
1890
+ const leaflet = useLazyModule(lazyReactLeaflet);
1891
+ const height = config.height ?? 400;
1892
+ const center = config.center ?? [51.505, -0.09];
1893
+ const zoom = config.zoom ?? 13;
1894
+ if (!leaflet) {
1895
+ return React12.createElement(Alert7, { severity: "info" }, "Loading map library...");
1896
+ }
1897
+ const { MapContainer, TileLayer, Marker, Popup, GeoJSON } = leaflet;
1898
+ const tileUrl = config.tileLayer?.url ?? DEFAULT_TILE_URL;
1899
+ const attribution = config.tileLayer?.attribution ?? DEFAULT_ATTRIBUTION;
1900
+ return React12.createElement(
1901
+ MapRoot,
1902
+ { className },
1903
+ config.title && React12.createElement(
1904
+ Typography6,
1905
+ { variant: "subtitle1", fontWeight: 600, sx: { p: 1.5, borderBottom: 1, borderColor: "divider" } },
1906
+ config.title
1907
+ ),
1908
+ React12.createElement(
1909
+ MapContainer,
1910
+ {
1911
+ center,
1912
+ zoom,
1913
+ style: { height, width: "100%" },
1914
+ scrollWheelZoom: true
1915
+ },
1916
+ React12.createElement(TileLayer, { url: tileUrl, attribution }),
1917
+ config.markers?.map(
1918
+ (marker, i) => React12.createElement(
1919
+ Marker,
1920
+ { key: i, position: marker.position },
1921
+ marker.popup && React12.createElement(Popup, null, React12.createElement(Paper, { elevation: 0, sx: { p: 1 } }, marker.popup))
1922
+ )
1923
+ ),
1924
+ config.geojson && React12.createElement(GeoJSON, { data: config.geojson })
1925
+ )
1926
+ );
1927
+ }
1928
+ lazyReactLeaflet.load().catch(() => {
1929
+ });
1930
+ var MapsRenderer = class {
1931
+ type = "map";
1932
+ priority = 60;
1933
+ canHandle(content) {
1934
+ return isMap(content);
1935
+ }
1936
+ render(content, options) {
1937
+ try {
1938
+ const config = parseMapConfig(content);
1939
+ return React12.createElement(MapView, {
1940
+ config,
1941
+ className: options?.className ?? "fmcp-map-content"
1942
+ });
1943
+ } catch {
1944
+ return React12.createElement(Alert7, { severity: "error" }, "Invalid map/GeoJSON data");
1945
+ }
1946
+ }
1947
+ };
1948
+ var mapsRenderer = new MapsRenderer();
1949
+
1950
+ // libs/ui/src/renderer/media/index.ts
1951
+ import React13 from "react";
1952
+ import Box12 from "@mui/material/Box";
1953
+ import Paper2 from "@mui/material/Paper";
1954
+ import { styled as styled11 } from "@mui/material/styles";
1955
+ var VIDEO_PATTERNS2 = [
1956
+ /^https?:\/\/[^?#\s]+\.(?:mp4|webm|ogg|mov)(?:\?[^#\s]*)?$/i,
1957
+ /^https?:\/\/(?:www\.)?(?:youtube\.com|youtu\.be|vimeo\.com)\//i,
1958
+ /^data:video\//
1959
+ ];
1960
+ var AUDIO_PATTERNS2 = [
1961
+ /^https?:\/\/[^?#\s]+\.(?:mp3|wav|ogg|aac|flac|m4a)(?:\?[^#\s]*)?$/i,
1962
+ /^https?:\/\/(?:www\.)?soundcloud\.com\//i,
1963
+ /^data:audio\//
1964
+ ];
1965
+ function isVideo(content) {
1966
+ const trimmed = content.trim();
1967
+ return VIDEO_PATTERNS2.some((p) => p.test(trimmed));
1968
+ }
1969
+ function isAudio(content) {
1970
+ const trimmed = content.trim();
1971
+ return AUDIO_PATTERNS2.some((p) => p.test(trimmed));
1972
+ }
1973
+ function isMedia(content) {
1974
+ return isVideo(content) || isAudio(content);
1975
+ }
1976
+ var lazyReactPlayer = createLazyImport("react-player", async () => {
1977
+ const mod = await runtimeImportWithFallback(
1978
+ "react-player",
1979
+ esmShUrl("react-player@2", { external: ["react", "react-dom"] })
1980
+ );
1981
+ return mod;
1982
+ });
1983
+ var MediaRoot = styled11(Paper2, {
1984
+ name: "FrontMcpMedia",
1985
+ slot: "Root"
1986
+ })(({ theme }) => ({
1987
+ overflow: "hidden",
1988
+ borderRadius: theme.shape.borderRadius
1989
+ }));
1990
+ var VideoWrapper = styled11(Box12)({
1991
+ position: "relative",
1992
+ paddingTop: "56.25%",
1993
+ // 16:9 aspect ratio
1994
+ "& > *": {
1995
+ position: "absolute",
1996
+ top: 0,
1997
+ left: 0
1998
+ }
1999
+ });
2000
+ var AudioWrapper = styled11(Box12)(({ theme }) => ({
2001
+ padding: theme.spacing(1),
2002
+ "& > *": {
2003
+ width: "100%"
2004
+ }
2005
+ }));
2006
+ function MediaView({ url, isAudioContent, className }) {
2007
+ const reactPlayerMod = useLazyModule(lazyReactPlayer);
2008
+ if (!reactPlayerMod) {
2009
+ if (isAudioContent) {
2010
+ return React13.createElement(
2011
+ MediaRoot,
2012
+ { variant: "outlined", className },
2013
+ React13.createElement(
2014
+ AudioWrapper,
2015
+ null,
2016
+ React13.createElement("audio", { controls: true, src: url, style: { width: "100%" } })
2017
+ )
2018
+ );
2019
+ }
2020
+ return React13.createElement(
2021
+ MediaRoot,
2022
+ { variant: "outlined", className },
2023
+ React13.createElement(
2024
+ VideoWrapper,
2025
+ null,
2026
+ React13.createElement("video", {
2027
+ controls: true,
2028
+ src: url,
2029
+ style: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%" }
2030
+ })
2031
+ )
2032
+ );
2033
+ }
2034
+ const ReactPlayer = reactPlayerMod.default;
2035
+ if (isAudioContent) {
2036
+ return React13.createElement(
2037
+ MediaRoot,
2038
+ { variant: "outlined", className },
2039
+ React13.createElement(
2040
+ AudioWrapper,
2041
+ null,
2042
+ React13.createElement(ReactPlayer, {
2043
+ url,
2044
+ controls: true,
2045
+ width: "100%",
2046
+ height: 50
2047
+ })
2048
+ )
2049
+ );
2050
+ }
2051
+ return React13.createElement(
2052
+ MediaRoot,
2053
+ { variant: "outlined", className },
2054
+ React13.createElement(
2055
+ VideoWrapper,
2056
+ null,
2057
+ React13.createElement(ReactPlayer, {
2058
+ url,
2059
+ controls: true,
2060
+ width: "100%",
2061
+ height: "100%"
2062
+ })
2063
+ )
2064
+ );
2065
+ }
2066
+ lazyReactPlayer.load().catch(() => {
2067
+ });
2068
+ var VideoRenderer = class {
2069
+ type = "video";
2070
+ priority = 20;
2071
+ canHandle(content) {
2072
+ return isVideo(content);
2073
+ }
2074
+ render(content, options) {
2075
+ return React13.createElement(MediaView, {
2076
+ url: content.trim(),
2077
+ isAudioContent: false,
2078
+ className: options?.className ?? "fmcp-media-content"
2079
+ });
2080
+ }
2081
+ };
2082
+ var AudioRenderer = class {
2083
+ type = "audio";
2084
+ priority = 20;
2085
+ canHandle(content) {
2086
+ return isAudio(content);
2087
+ }
2088
+ render(content, options) {
2089
+ return React13.createElement(MediaView, {
2090
+ url: content.trim(),
2091
+ isAudioContent: true,
2092
+ className: options?.className ?? "fmcp-media-content"
2093
+ });
2094
+ }
2095
+ };
2096
+ var videoRenderer = new VideoRenderer();
2097
+ var audioRenderer = new AudioRenderer();
2098
+
2099
+ // libs/ui/src/renderer/index.ts
2100
+ function registerAllRenderers() {
2101
+ const all = [
2102
+ pdfRenderer,
2103
+ chartsRenderer,
2104
+ flowRenderer,
2105
+ mapsRenderer,
2106
+ mermaidRenderer,
2107
+ mathRenderer,
2108
+ imageRenderer,
2109
+ videoRenderer,
2110
+ audioRenderer,
2111
+ csvRenderer,
2112
+ reactJsxRenderer,
2113
+ mdxRenderer,
2114
+ htmlRenderer
2115
+ ];
2116
+ for (const renderer of all) {
2117
+ registerRenderer(renderer);
2118
+ }
2119
+ }
2120
+ export {
2121
+ AudioRenderer,
2122
+ ChartsRenderer,
2123
+ ContentView,
2124
+ CsvRenderer,
2125
+ ESM_SH_BASE,
2126
+ FlowRenderer,
2127
+ HtmlRenderer,
2128
+ ImageRenderer,
2129
+ MapsRenderer,
2130
+ MathRenderer,
2131
+ MdxRenderer,
2132
+ MermaidRenderer,
2133
+ PdfRenderer,
2134
+ ReactJsxRenderer,
2135
+ VideoRenderer,
2136
+ audioRenderer,
2137
+ chartsRenderer,
2138
+ clearRegistry,
2139
+ createLazyImport,
2140
+ csvRenderer,
2141
+ detectContentType2 as detectContentType,
2142
+ esmShUrl,
2143
+ extractThemeValues,
2144
+ flowRenderer,
2145
+ getRegisteredRenderers,
2146
+ getRenderer,
2147
+ htmlRenderer,
2148
+ imageRenderer,
2149
+ injectStylesheet,
2150
+ isAudio,
2151
+ isChart,
2152
+ isFlow,
2153
+ isImage,
2154
+ isMap,
2155
+ isMath,
2156
+ isMedia,
2157
+ isMermaid,
2158
+ isReactJsx,
2159
+ isVideo,
2160
+ mapsRenderer,
2161
+ mathRenderer,
2162
+ mdxRenderer,
2163
+ mermaidRenderer,
2164
+ pdfRenderer,
2165
+ reactJsxRenderer,
2166
+ registerAllRenderers,
2167
+ registerRenderer,
2168
+ renderContent,
2169
+ runtimeImportWithFallback,
2170
+ useLazyModule,
2171
+ useRendererTheme,
2172
+ videoRenderer
2173
+ };