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