@frontmcp/ui 0.12.2 → 1.0.0-beta.2
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/README.md +279 -72
- package/bridge/adapters/claude.adapter.d.ts.map +1 -1
- package/bridge/adapters/gemini.adapter.d.ts.map +1 -1
- package/bridge/index.js +2 -36
- package/components/Alert/Alert.d.ts +11 -0
- package/components/Alert/Alert.d.ts.map +1 -0
- package/components/Alert/index.d.ts +4 -0
- package/components/Alert/index.d.ts.map +1 -0
- package/components/Alert/index.js +61 -0
- package/components/Avatar/Avatar.d.ts +10 -0
- package/components/Avatar/Avatar.d.ts.map +1 -0
- package/components/Avatar/index.d.ts +4 -0
- package/components/Avatar/index.d.ts.map +1 -0
- package/components/Avatar/index.js +43 -0
- package/components/Badge/Badge.d.ts +13 -0
- package/components/Badge/Badge.d.ts.map +1 -0
- package/components/Badge/index.d.ts +4 -0
- package/components/Badge/index.d.ts.map +1 -0
- package/{render → components/Badge}/index.js +54 -42
- package/components/Button/Button.d.ts +16 -0
- package/components/Button/Button.d.ts.map +1 -0
- package/components/Button/index.d.ts +4 -0
- package/components/Button/index.d.ts.map +1 -0
- package/components/Button/index.js +91 -0
- package/components/Card/Card.d.ts +25 -0
- package/components/Card/Card.d.ts.map +1 -0
- package/components/Card/index.d.ts +4 -0
- package/components/Card/index.d.ts.map +1 -0
- package/components/Card/index.js +110 -0
- package/components/List/List.d.ts +15 -0
- package/components/List/List.d.ts.map +1 -0
- package/components/List/index.d.ts +4 -0
- package/components/List/index.d.ts.map +1 -0
- package/components/List/index.js +58 -0
- package/components/Loader/Loader.d.ts +28 -0
- package/components/Loader/Loader.d.ts.map +1 -0
- package/components/Loader/LoaderContext.d.ts +20 -0
- package/components/Loader/LoaderContext.d.ts.map +1 -0
- package/components/Loader/index.d.ts +6 -0
- package/components/Loader/index.d.ts.map +1 -0
- package/components/Loader/index.js +174 -0
- package/components/Modal/Modal.d.ts +22 -0
- package/components/Modal/Modal.d.ts.map +1 -0
- package/components/Modal/index.d.ts +4 -0
- package/components/Modal/index.d.ts.map +1 -0
- package/components/Modal/index.js +80 -0
- package/components/Select/Select.d.ts +21 -0
- package/components/Select/Select.d.ts.map +1 -0
- package/components/Select/index.d.ts +4 -0
- package/components/Select/index.d.ts.map +1 -0
- package/components/Select/index.js +78 -0
- package/components/Table/Table.d.ts +15 -0
- package/components/Table/Table.d.ts.map +1 -0
- package/components/Table/index.d.ts +4 -0
- package/components/Table/index.d.ts.map +1 -0
- package/components/Table/index.js +70 -0
- package/components/TextField/TextField.d.ts +19 -0
- package/components/TextField/TextField.d.ts.map +1 -0
- package/components/TextField/index.d.ts +4 -0
- package/components/TextField/index.d.ts.map +1 -0
- package/components/TextField/index.js +77 -0
- package/components/index.d.ts +22 -28
- package/components/index.d.ts.map +1 -1
- package/components/index.js +523 -2521
- package/esm/bridge/index.mjs +2 -6
- package/esm/components/Alert/index.mjs +28 -0
- package/esm/components/Avatar/index.mjs +10 -0
- package/esm/components/Badge/index.mjs +56 -0
- package/esm/components/Button/index.mjs +58 -0
- package/esm/components/Card/index.mjs +77 -0
- package/esm/components/List/index.mjs +25 -0
- package/esm/components/Loader/index.mjs +141 -0
- package/esm/components/Modal/index.mjs +47 -0
- package/esm/components/Select/index.mjs +45 -0
- package/esm/components/Table/index.mjs +37 -0
- package/esm/components/TextField/index.mjs +44 -0
- package/esm/components/index.mjs +513 -2415
- package/esm/index.mjs +62 -4652
- package/esm/package.json +372 -16
- package/esm/react/index.mjs +2 -285
- package/esm/renderer/charts/index.mjs +336 -0
- package/esm/renderer/common/index.mjs +135 -0
- package/esm/renderer/csv/index.mjs +193 -0
- package/esm/renderer/flow/index.mjs +259 -0
- package/esm/renderer/html/index.mjs +99 -0
- package/esm/renderer/image/index.mjs +125 -0
- package/esm/renderer/index.mjs +2173 -0
- package/esm/renderer/maps/index.mjs +217 -0
- package/esm/renderer/math/index.mjs +229 -0
- package/esm/renderer/mdx/index.mjs +261 -0
- package/esm/renderer/media/index.mjs +235 -0
- package/esm/renderer/mermaid/index.mjs +220 -0
- package/esm/renderer/pdf/index.mjs +229 -0
- package/esm/renderer/react/index.mjs +230 -0
- package/esm/runtime/index.mjs +194 -0
- package/esm/theme/index.mjs +93 -0
- package/index.d.ts +10 -18
- package/index.d.ts.map +1 -1
- package/index.js +63 -4806
- package/package.json +372 -16
- package/react/index.d.ts +8 -54
- package/react/index.d.ts.map +1 -1
- package/react/index.js +2 -295
- package/renderer/auto-detect.d.ts +39 -0
- package/renderer/auto-detect.d.ts.map +1 -0
- package/renderer/charts/index.d.ts +22 -0
- package/renderer/charts/index.d.ts.map +1 -0
- package/renderer/charts/index.js +367 -0
- package/renderer/common/index.d.ts +5 -0
- package/renderer/common/index.d.ts.map +1 -0
- package/renderer/common/index.js +158 -0
- package/renderer/common/inject-stylesheet.d.ts +9 -0
- package/renderer/common/inject-stylesheet.d.ts.map +1 -0
- package/renderer/common/lazy-import.d.ts +85 -0
- package/renderer/common/lazy-import.d.ts.map +1 -0
- package/renderer/common/use-lazy-module.d.ts +13 -0
- package/renderer/common/use-lazy-module.d.ts.map +1 -0
- package/renderer/common/use-renderer-theme.d.ts +35 -0
- package/renderer/common/use-renderer-theme.d.ts.map +1 -0
- package/renderer/csv/index.d.ts +12 -0
- package/renderer/csv/index.d.ts.map +1 -0
- package/renderer/csv/index.js +224 -0
- package/renderer/flow/index.d.ts +40 -0
- package/renderer/flow/index.d.ts.map +1 -0
- package/renderer/flow/index.js +290 -0
- package/renderer/html/index.d.ts +12 -0
- package/renderer/html/index.d.ts.map +1 -0
- package/renderer/html/index.js +130 -0
- package/renderer/image/index.d.ts +11 -0
- package/renderer/image/index.d.ts.map +1 -0
- package/renderer/image/index.js +156 -0
- package/renderer/index.d.ts +32 -0
- package/renderer/index.d.ts.map +1 -0
- package/renderer/index.js +2206 -0
- package/renderer/maps/index.d.ts +27 -0
- package/renderer/maps/index.d.ts.map +1 -0
- package/renderer/maps/index.js +248 -0
- package/renderer/math/index.d.ts +11 -0
- package/renderer/math/index.d.ts.map +1 -0
- package/renderer/math/index.js +260 -0
- package/renderer/mdx/index.d.ts +10 -0
- package/renderer/mdx/index.d.ts.map +1 -0
- package/renderer/mdx/index.js +292 -0
- package/renderer/media/index.d.ts +20 -0
- package/renderer/media/index.d.ts.map +1 -0
- package/renderer/media/index.js +266 -0
- package/renderer/mermaid/index.d.ts +11 -0
- package/renderer/mermaid/index.d.ts.map +1 -0
- package/renderer/mermaid/index.js +251 -0
- package/renderer/pdf/index.d.ts +10 -0
- package/renderer/pdf/index.d.ts.map +1 -0
- package/renderer/pdf/index.js +260 -0
- package/renderer/react/index.d.ts +45 -0
- package/renderer/react/index.d.ts.map +1 -0
- package/renderer/react/index.js +261 -0
- package/renderer/types.d.ts +24 -0
- package/renderer/types.d.ts.map +1 -0
- package/runtime/babel-runtime.d.ts +70 -0
- package/runtime/babel-runtime.d.ts.map +1 -0
- package/runtime/content-detector.d.ts +43 -0
- package/runtime/content-detector.d.ts.map +1 -0
- package/runtime/index.d.ts +10 -0
- package/runtime/index.d.ts.map +1 -0
- package/runtime/index.js +217 -0
- package/theme/FrontMcpThemeProvider.d.ts +4 -0
- package/theme/FrontMcpThemeProvider.d.ts.map +1 -0
- package/theme/create-theme.d.ts +9 -0
- package/theme/create-theme.d.ts.map +1 -0
- package/theme/index.d.ts +5 -0
- package/theme/index.d.ts.map +1 -0
- package/theme/index.js +126 -0
- package/theme/types.d.ts +28 -0
- package/theme/types.d.ts.map +1 -0
- package/theme/use-theme.d.ts +3 -0
- package/theme/use-theme.d.ts.map +1 -0
- package/bundler/browser-components.d.ts +0 -42
- package/bundler/browser-components.d.ts.map +0 -1
- package/bundler/bundler.d.ts +0 -282
- package/bundler/bundler.d.ts.map +0 -1
- package/bundler/index.d.ts +0 -43
- package/bundler/index.d.ts.map +0 -1
- package/bundler/index.js +0 -3168
- package/bundler/types.d.ts +0 -883
- package/bundler/types.d.ts.map +0 -1
- package/components/alert.d.ts +0 -83
- package/components/alert.d.ts.map +0 -1
- package/components/alert.schema.d.ts +0 -98
- package/components/alert.schema.d.ts.map +0 -1
- package/components/avatar.d.ts +0 -77
- package/components/avatar.d.ts.map +0 -1
- package/components/avatar.schema.d.ts +0 -170
- package/components/avatar.schema.d.ts.map +0 -1
- package/components/badge.d.ts +0 -78
- package/components/badge.d.ts.map +0 -1
- package/components/badge.schema.d.ts +0 -91
- package/components/badge.schema.d.ts.map +0 -1
- package/components/button.d.ts +0 -100
- package/components/button.d.ts.map +0 -1
- package/components/button.schema.d.ts +0 -120
- package/components/button.schema.d.ts.map +0 -1
- package/components/card.d.ts +0 -76
- package/components/card.d.ts.map +0 -1
- package/components/card.schema.d.ts +0 -93
- package/components/card.schema.d.ts.map +0 -1
- package/components/form.d.ts +0 -227
- package/components/form.d.ts.map +0 -1
- package/components/form.schema.d.ts +0 -365
- package/components/form.schema.d.ts.map +0 -1
- package/components/list.d.ts +0 -121
- package/components/list.d.ts.map +0 -1
- package/components/list.schema.d.ts +0 -129
- package/components/list.schema.d.ts.map +0 -1
- package/components/modal.d.ts +0 -100
- package/components/modal.d.ts.map +0 -1
- package/components/modal.schema.d.ts +0 -151
- package/components/modal.schema.d.ts.map +0 -1
- package/components/table.d.ts +0 -91
- package/components/table.d.ts.map +0 -1
- package/components/table.schema.d.ts +0 -123
- package/components/table.schema.d.ts.map +0 -1
- package/esm/bundler/index.mjs +0 -3136
- package/esm/layouts/index.mjs +0 -409
- package/esm/render/index.mjs +0 -45
- package/esm/renderers/index.mjs +0 -621
- package/esm/universal/index.mjs +0 -1946
- package/esm/web-components/index.mjs +0 -2023
- package/layouts/base.d.ts +0 -86
- package/layouts/base.d.ts.map +0 -1
- package/layouts/index.d.ts +0 -8
- package/layouts/index.d.ts.map +0 -1
- package/layouts/index.js +0 -437
- package/layouts/presets.d.ts +0 -134
- package/layouts/presets.d.ts.map +0 -1
- package/react/Alert.d.ts +0 -101
- package/react/Alert.d.ts.map +0 -1
- package/react/Badge.d.ts +0 -100
- package/react/Badge.d.ts.map +0 -1
- package/react/Button.d.ts +0 -108
- package/react/Button.d.ts.map +0 -1
- package/react/Card.d.ts +0 -103
- package/react/Card.d.ts.map +0 -1
- package/react/types.d.ts +0 -105
- package/react/types.d.ts.map +0 -1
- package/render/index.d.ts +0 -8
- package/render/index.d.ts.map +0 -1
- package/render/prerender.d.ts +0 -57
- package/render/prerender.d.ts.map +0 -1
- package/renderers/index.d.ts +0 -26
- package/renderers/index.d.ts.map +0 -1
- package/renderers/index.js +0 -666
- package/renderers/mdx.renderer.d.ts +0 -99
- package/renderers/mdx.renderer.d.ts.map +0 -1
- package/renderers/react.adapter.d.ts +0 -70
- package/renderers/react.adapter.d.ts.map +0 -1
- package/renderers/react.renderer.d.ts +0 -105
- package/renderers/react.renderer.d.ts.map +0 -1
- package/renderers/transpiler.d.ts +0 -49
- package/renderers/transpiler.d.ts.map +0 -1
- package/universal/UniversalApp.d.ts +0 -108
- package/universal/UniversalApp.d.ts.map +0 -1
- package/universal/cached-runtime.d.ts +0 -139
- package/universal/cached-runtime.d.ts.map +0 -1
- package/universal/context.d.ts +0 -122
- package/universal/context.d.ts.map +0 -1
- package/universal/index.d.ts +0 -57
- package/universal/index.d.ts.map +0 -1
- package/universal/index.js +0 -2032
- package/universal/renderers/html.renderer.d.ts +0 -36
- package/universal/renderers/html.renderer.d.ts.map +0 -1
- package/universal/renderers/index.d.ts +0 -112
- package/universal/renderers/index.d.ts.map +0 -1
- package/universal/renderers/markdown.renderer.d.ts +0 -33
- package/universal/renderers/markdown.renderer.d.ts.map +0 -1
- package/universal/renderers/mdx.renderer.d.ts +0 -38
- package/universal/renderers/mdx.renderer.d.ts.map +0 -1
- package/universal/renderers/react.renderer.d.ts +0 -46
- package/universal/renderers/react.renderer.d.ts.map +0 -1
- package/universal/runtime-builder.d.ts +0 -33
- package/universal/runtime-builder.d.ts.map +0 -1
- package/universal/store.d.ts +0 -135
- package/universal/store.d.ts.map +0 -1
- package/universal/types.d.ts +0 -199
- package/universal/types.d.ts.map +0 -1
- package/web-components/core/attribute-parser.d.ts +0 -82
- package/web-components/core/attribute-parser.d.ts.map +0 -1
- package/web-components/core/base-element.d.ts +0 -197
- package/web-components/core/base-element.d.ts.map +0 -1
- package/web-components/core/index.d.ts +0 -9
- package/web-components/core/index.d.ts.map +0 -1
- package/web-components/elements/fmcp-alert.d.ts +0 -46
- package/web-components/elements/fmcp-alert.d.ts.map +0 -1
- package/web-components/elements/fmcp-badge.d.ts +0 -47
- package/web-components/elements/fmcp-badge.d.ts.map +0 -1
- package/web-components/elements/fmcp-button.d.ts +0 -117
- package/web-components/elements/fmcp-button.d.ts.map +0 -1
- package/web-components/elements/fmcp-card.d.ts +0 -53
- package/web-components/elements/fmcp-card.d.ts.map +0 -1
- package/web-components/elements/fmcp-input.d.ts +0 -96
- package/web-components/elements/fmcp-input.d.ts.map +0 -1
- package/web-components/elements/fmcp-select.d.ts +0 -100
- package/web-components/elements/fmcp-select.d.ts.map +0 -1
- package/web-components/elements/index.d.ts +0 -13
- package/web-components/elements/index.d.ts.map +0 -1
- package/web-components/index.d.ts +0 -49
- package/web-components/index.d.ts.map +0 -1
- package/web-components/index.js +0 -2058
- package/web-components/register.d.ts +0 -57
- package/web-components/register.d.ts.map +0 -1
- package/web-components/types.d.ts +0 -122
- package/web-components/types.d.ts.map +0 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// libs/ui/src/renderer/common/use-renderer-theme.ts
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { useTheme } from "@mui/material/styles";
|
|
4
|
+
function extractThemeValues(theme) {
|
|
5
|
+
const palette = theme.palette;
|
|
6
|
+
return {
|
|
7
|
+
mode: palette.mode,
|
|
8
|
+
primary: palette.primary.main,
|
|
9
|
+
secondary: palette.secondary.main,
|
|
10
|
+
error: palette.error.main,
|
|
11
|
+
warning: palette.warning.main,
|
|
12
|
+
success: palette.success.main,
|
|
13
|
+
info: palette.info.main,
|
|
14
|
+
background: palette.background.default,
|
|
15
|
+
paper: palette.background.paper,
|
|
16
|
+
textPrimary: palette.text.primary,
|
|
17
|
+
textSecondary: palette.text.secondary,
|
|
18
|
+
divider: palette.divider,
|
|
19
|
+
fontFamily: theme.typography.fontFamily ?? "sans-serif",
|
|
20
|
+
monoFontFamily: theme.typography["monoFontFamily"] ?? '"SF Mono", "Fira Code", "Fira Mono", "Roboto Mono", monospace',
|
|
21
|
+
fontSize: theme.typography.fontSize ?? 14,
|
|
22
|
+
borderRadius: typeof theme.shape.borderRadius === "number" ? theme.shape.borderRadius : 4,
|
|
23
|
+
seriesColors: [
|
|
24
|
+
palette.primary.main,
|
|
25
|
+
palette.secondary.main,
|
|
26
|
+
palette.error.main,
|
|
27
|
+
palette.warning.main,
|
|
28
|
+
palette.success.main,
|
|
29
|
+
palette.info.main
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function useRendererTheme() {
|
|
34
|
+
const theme = useTheme();
|
|
35
|
+
return useMemo(() => extractThemeValues(theme), [theme]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// libs/ui/src/renderer/common/inject-stylesheet.ts
|
|
39
|
+
function injectStylesheet(href, id) {
|
|
40
|
+
if (typeof document === "undefined") return;
|
|
41
|
+
if (document.getElementById(id)) return;
|
|
42
|
+
const link = document.createElement("link");
|
|
43
|
+
link.id = id;
|
|
44
|
+
link.rel = "stylesheet";
|
|
45
|
+
link.href = href;
|
|
46
|
+
link.crossOrigin = "anonymous";
|
|
47
|
+
document.head.appendChild(link);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// libs/ui/src/renderer/common/lazy-import.ts
|
|
51
|
+
var ESM_SH_BASE = "https://esm.sh/";
|
|
52
|
+
function esmShUrl(pkg, options) {
|
|
53
|
+
let url = `${ESM_SH_BASE}${pkg}`;
|
|
54
|
+
if (options?.external?.length) {
|
|
55
|
+
url += `?external=${options.external.join(",")}`;
|
|
56
|
+
}
|
|
57
|
+
return url;
|
|
58
|
+
}
|
|
59
|
+
function runtimeImport(specifier) {
|
|
60
|
+
const dynamicImport = new Function("s", "return import(s)");
|
|
61
|
+
return dynamicImport(specifier);
|
|
62
|
+
}
|
|
63
|
+
async function runtimeImportWithFallback(bareSpecifier, fallbackUrl) {
|
|
64
|
+
try {
|
|
65
|
+
return await runtimeImport(bareSpecifier);
|
|
66
|
+
} catch {
|
|
67
|
+
return runtimeImport(fallbackUrl);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function createLazyImport(moduleId, importer) {
|
|
71
|
+
let state = { status: "idle" };
|
|
72
|
+
const doImport = importer ?? (async () => {
|
|
73
|
+
const mod = await runtimeImport(moduleId);
|
|
74
|
+
return mod["default"] ?? mod;
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
load() {
|
|
78
|
+
if (state.status === "loaded") return Promise.resolve(state.module);
|
|
79
|
+
if (state.status === "loading") return state.promise;
|
|
80
|
+
if (state.status === "error") {
|
|
81
|
+
state = { status: "idle" };
|
|
82
|
+
}
|
|
83
|
+
const promise = doImport().then(
|
|
84
|
+
(mod) => {
|
|
85
|
+
state = { status: "loaded", module: mod };
|
|
86
|
+
return mod;
|
|
87
|
+
},
|
|
88
|
+
(err) => {
|
|
89
|
+
const error = err instanceof Error ? err : new Error(`Failed to load module "${moduleId}": ${String(err)}`);
|
|
90
|
+
state = { status: "error", error };
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
state = { status: "loading", promise };
|
|
95
|
+
return promise;
|
|
96
|
+
},
|
|
97
|
+
get() {
|
|
98
|
+
return state.status === "loaded" ? state.module : void 0;
|
|
99
|
+
},
|
|
100
|
+
getState() {
|
|
101
|
+
return state;
|
|
102
|
+
},
|
|
103
|
+
reset() {
|
|
104
|
+
state = { status: "idle" };
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// libs/ui/src/renderer/common/use-lazy-module.ts
|
|
110
|
+
import { useState, useEffect } from "react";
|
|
111
|
+
function useLazyModule(lazy) {
|
|
112
|
+
const [, forceUpdate] = useState(0);
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (lazy.getState().status === "loaded") {
|
|
115
|
+
forceUpdate((n) => n + 1);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
lazy.load().then(
|
|
119
|
+
() => forceUpdate((n) => n + 1),
|
|
120
|
+
() => forceUpdate((n) => n + 1)
|
|
121
|
+
);
|
|
122
|
+
}, [lazy]);
|
|
123
|
+
return lazy.get();
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
ESM_SH_BASE,
|
|
127
|
+
createLazyImport,
|
|
128
|
+
esmShUrl,
|
|
129
|
+
extractThemeValues,
|
|
130
|
+
injectStylesheet,
|
|
131
|
+
runtimeImport,
|
|
132
|
+
runtimeImportWithFallback,
|
|
133
|
+
useLazyModule,
|
|
134
|
+
useRendererTheme
|
|
135
|
+
};
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// libs/ui/src/renderer/csv/index.ts
|
|
2
|
+
import React, { useState, useMemo, useCallback } from "react";
|
|
3
|
+
import Box from "@mui/material/Box";
|
|
4
|
+
import MuiTable from "@mui/material/Table";
|
|
5
|
+
import TableBody from "@mui/material/TableBody";
|
|
6
|
+
import TableCell from "@mui/material/TableCell";
|
|
7
|
+
import TableContainer from "@mui/material/TableContainer";
|
|
8
|
+
import TableHead from "@mui/material/TableHead";
|
|
9
|
+
import TableRow from "@mui/material/TableRow";
|
|
10
|
+
import TablePagination from "@mui/material/TablePagination";
|
|
11
|
+
import TableSortLabel from "@mui/material/TableSortLabel";
|
|
12
|
+
import TextField from "@mui/material/TextField";
|
|
13
|
+
import { styled } from "@mui/material/styles";
|
|
14
|
+
function detectDelimiter(content) {
|
|
15
|
+
const firstLine = content.split("\n")[0];
|
|
16
|
+
const commas = (firstLine.match(/,/g) ?? []).length;
|
|
17
|
+
const tabs = (firstLine.match(/\t/g) ?? []).length;
|
|
18
|
+
const semicolons = (firstLine.match(/;/g) ?? []).length;
|
|
19
|
+
if (tabs > commas && tabs > semicolons) return " ";
|
|
20
|
+
if (semicolons > commas) return ";";
|
|
21
|
+
return ",";
|
|
22
|
+
}
|
|
23
|
+
function parseCsv(content, delimiter) {
|
|
24
|
+
return content.trim().split("\n").map((line) => line.split(delimiter).map((cell) => cell.trim()));
|
|
25
|
+
}
|
|
26
|
+
var CsvRoot = styled(Box, {
|
|
27
|
+
name: "FrontMcpCsvTable",
|
|
28
|
+
slot: "Root"
|
|
29
|
+
})({
|
|
30
|
+
width: "100%"
|
|
31
|
+
});
|
|
32
|
+
var StyledHeaderCell = styled(TableCell, {
|
|
33
|
+
name: "FrontMcpCsvTable",
|
|
34
|
+
slot: "Header"
|
|
35
|
+
})(({ theme }) => ({
|
|
36
|
+
fontWeight: 600,
|
|
37
|
+
backgroundColor: theme.palette.mode === "dark" ? theme.palette.grey[900] : theme.palette.grey[50],
|
|
38
|
+
whiteSpace: "nowrap"
|
|
39
|
+
}));
|
|
40
|
+
var FilterToolbar = styled(Box, {
|
|
41
|
+
name: "FrontMcpCsvTable",
|
|
42
|
+
slot: "Toolbar"
|
|
43
|
+
})(({ theme }) => ({
|
|
44
|
+
padding: theme.spacing(1, 2),
|
|
45
|
+
display: "flex",
|
|
46
|
+
gap: theme.spacing(1)
|
|
47
|
+
}));
|
|
48
|
+
function CsvTableView({ content, className, pageSize = 25 }) {
|
|
49
|
+
const delimiter = useMemo(() => detectDelimiter(content), [content]);
|
|
50
|
+
const allRows = useMemo(() => parseCsv(content, delimiter), [content, delimiter]);
|
|
51
|
+
const headers = allRows[0] ?? [];
|
|
52
|
+
const dataRows = useMemo(() => allRows.slice(1), [allRows]);
|
|
53
|
+
const [page, setPage] = useState(0);
|
|
54
|
+
const [rowsPerPage, setRowsPerPage] = useState(pageSize);
|
|
55
|
+
const [sortCol, setSortCol] = useState(null);
|
|
56
|
+
const [sortDir, setSortDir] = useState("asc");
|
|
57
|
+
const [filter, setFilter] = useState("");
|
|
58
|
+
const filteredRows = useMemo(() => {
|
|
59
|
+
if (!filter) return dataRows;
|
|
60
|
+
const lower = filter.toLowerCase();
|
|
61
|
+
return dataRows.filter((row) => row.some((cell) => cell.toLowerCase().includes(lower)));
|
|
62
|
+
}, [dataRows, filter]);
|
|
63
|
+
const sortedRows = useMemo(() => {
|
|
64
|
+
if (sortCol === null) return filteredRows;
|
|
65
|
+
const sorted = [...filteredRows];
|
|
66
|
+
sorted.sort((a, b) => {
|
|
67
|
+
const va = a[sortCol] ?? "";
|
|
68
|
+
const vb = b[sortCol] ?? "";
|
|
69
|
+
const numA = Number(va);
|
|
70
|
+
const numB = Number(vb);
|
|
71
|
+
if (!isNaN(numA) && !isNaN(numB)) {
|
|
72
|
+
return sortDir === "asc" ? numA - numB : numB - numA;
|
|
73
|
+
}
|
|
74
|
+
return sortDir === "asc" ? va.localeCompare(vb) : vb.localeCompare(va);
|
|
75
|
+
});
|
|
76
|
+
return sorted;
|
|
77
|
+
}, [filteredRows, sortCol, sortDir]);
|
|
78
|
+
const pageRows = useMemo(
|
|
79
|
+
() => sortedRows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage),
|
|
80
|
+
[sortedRows, page, rowsPerPage]
|
|
81
|
+
);
|
|
82
|
+
const handleSort = useCallback((colIndex) => {
|
|
83
|
+
setSortCol((prev) => {
|
|
84
|
+
if (prev === colIndex) {
|
|
85
|
+
setSortDir((d) => d === "asc" ? "desc" : "asc");
|
|
86
|
+
return colIndex;
|
|
87
|
+
}
|
|
88
|
+
setSortDir("asc");
|
|
89
|
+
return colIndex;
|
|
90
|
+
});
|
|
91
|
+
}, []);
|
|
92
|
+
const handleChangePage = useCallback((_, newPage) => setPage(newPage), []);
|
|
93
|
+
const handleChangeRowsPerPage = useCallback((e) => {
|
|
94
|
+
setRowsPerPage(parseInt(e.target.value, 10));
|
|
95
|
+
setPage(0);
|
|
96
|
+
}, []);
|
|
97
|
+
return React.createElement(
|
|
98
|
+
CsvRoot,
|
|
99
|
+
{ className },
|
|
100
|
+
React.createElement(
|
|
101
|
+
FilterToolbar,
|
|
102
|
+
null,
|
|
103
|
+
React.createElement(TextField, {
|
|
104
|
+
size: "small",
|
|
105
|
+
placeholder: "Filter rows...",
|
|
106
|
+
value: filter,
|
|
107
|
+
onChange: (e) => {
|
|
108
|
+
setFilter(e.target.value);
|
|
109
|
+
setPage(0);
|
|
110
|
+
},
|
|
111
|
+
sx: { minWidth: 200 }
|
|
112
|
+
})
|
|
113
|
+
),
|
|
114
|
+
React.createElement(
|
|
115
|
+
TableContainer,
|
|
116
|
+
{ sx: { border: 1, borderColor: "divider", borderRadius: 1 } },
|
|
117
|
+
React.createElement(
|
|
118
|
+
MuiTable,
|
|
119
|
+
{ size: "small", stickyHeader: true },
|
|
120
|
+
React.createElement(
|
|
121
|
+
TableHead,
|
|
122
|
+
null,
|
|
123
|
+
React.createElement(
|
|
124
|
+
TableRow,
|
|
125
|
+
null,
|
|
126
|
+
headers.map(
|
|
127
|
+
(header, i) => React.createElement(
|
|
128
|
+
StyledHeaderCell,
|
|
129
|
+
{ key: i },
|
|
130
|
+
React.createElement(
|
|
131
|
+
TableSortLabel,
|
|
132
|
+
{
|
|
133
|
+
active: sortCol === i,
|
|
134
|
+
direction: sortCol === i ? sortDir : "asc",
|
|
135
|
+
onClick: () => handleSort(i)
|
|
136
|
+
},
|
|
137
|
+
header
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
),
|
|
143
|
+
React.createElement(
|
|
144
|
+
TableBody,
|
|
145
|
+
null,
|
|
146
|
+
pageRows.map(
|
|
147
|
+
(row, ri) => React.createElement(
|
|
148
|
+
TableRow,
|
|
149
|
+
{ key: ri, hover: true },
|
|
150
|
+
row.map((cell, ci) => React.createElement(TableCell, { key: ci }, cell))
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
),
|
|
156
|
+
sortedRows.length > rowsPerPage && React.createElement(TablePagination, {
|
|
157
|
+
count: sortedRows.length,
|
|
158
|
+
page,
|
|
159
|
+
rowsPerPage,
|
|
160
|
+
onPageChange: handleChangePage,
|
|
161
|
+
onRowsPerPageChange: handleChangeRowsPerPage,
|
|
162
|
+
rowsPerPageOptions: [10, 25, 50, 100]
|
|
163
|
+
})
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
var CsvRenderer = class {
|
|
167
|
+
type = "csv";
|
|
168
|
+
priority = 10;
|
|
169
|
+
canHandle(content) {
|
|
170
|
+
const lines = content.trim().split("\n").slice(0, 5);
|
|
171
|
+
if (lines.length < 2) return false;
|
|
172
|
+
for (const delim of [",", " ", ";"]) {
|
|
173
|
+
const counts = lines.map((line) => line.split(delim).length);
|
|
174
|
+
if (counts[0] > 1 && counts.every((c) => c === counts[0])) return true;
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
render(content, options) {
|
|
179
|
+
const pageSize = options?.rendererOptions?.["pageSize"];
|
|
180
|
+
return React.createElement(CsvTableView, {
|
|
181
|
+
content,
|
|
182
|
+
className: options?.className ?? "fmcp-csv-table",
|
|
183
|
+
pageSize
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
var csvRenderer = new CsvRenderer();
|
|
188
|
+
export {
|
|
189
|
+
CsvRenderer,
|
|
190
|
+
csvRenderer,
|
|
191
|
+
detectDelimiter,
|
|
192
|
+
parseCsv
|
|
193
|
+
};
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// libs/ui/src/renderer/flow/index.ts
|
|
2
|
+
import React, { useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
3
|
+
import Box from "@mui/material/Box";
|
|
4
|
+
import Alert from "@mui/material/Alert";
|
|
5
|
+
import Typography from "@mui/material/Typography";
|
|
6
|
+
import { styled } from "@mui/material/styles";
|
|
7
|
+
|
|
8
|
+
// libs/ui/src/renderer/common/lazy-import.ts
|
|
9
|
+
var ESM_SH_BASE = "https://esm.sh/";
|
|
10
|
+
function esmShUrl(pkg, options) {
|
|
11
|
+
let url = `${ESM_SH_BASE}${pkg}`;
|
|
12
|
+
if (options?.external?.length) {
|
|
13
|
+
url += `?external=${options.external.join(",")}`;
|
|
14
|
+
}
|
|
15
|
+
return url;
|
|
16
|
+
}
|
|
17
|
+
function runtimeImport(specifier) {
|
|
18
|
+
const dynamicImport = new Function("s", "return import(s)");
|
|
19
|
+
return dynamicImport(specifier);
|
|
20
|
+
}
|
|
21
|
+
async function runtimeImportWithFallback(bareSpecifier, fallbackUrl) {
|
|
22
|
+
try {
|
|
23
|
+
return await runtimeImport(bareSpecifier);
|
|
24
|
+
} catch {
|
|
25
|
+
return runtimeImport(fallbackUrl);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function createLazyImport(moduleId, importer) {
|
|
29
|
+
let state = { status: "idle" };
|
|
30
|
+
const doImport = importer ?? (async () => {
|
|
31
|
+
const mod = await runtimeImport(moduleId);
|
|
32
|
+
return mod["default"] ?? mod;
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
load() {
|
|
36
|
+
if (state.status === "loaded") return Promise.resolve(state.module);
|
|
37
|
+
if (state.status === "loading") return state.promise;
|
|
38
|
+
if (state.status === "error") {
|
|
39
|
+
state = { status: "idle" };
|
|
40
|
+
}
|
|
41
|
+
const promise = doImport().then(
|
|
42
|
+
(mod) => {
|
|
43
|
+
state = { status: "loaded", module: mod };
|
|
44
|
+
return mod;
|
|
45
|
+
},
|
|
46
|
+
(err) => {
|
|
47
|
+
const error = err instanceof Error ? err : new Error(`Failed to load module "${moduleId}": ${String(err)}`);
|
|
48
|
+
state = { status: "error", error };
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
state = { status: "loading", promise };
|
|
53
|
+
return promise;
|
|
54
|
+
},
|
|
55
|
+
get() {
|
|
56
|
+
return state.status === "loaded" ? state.module : void 0;
|
|
57
|
+
},
|
|
58
|
+
getState() {
|
|
59
|
+
return state;
|
|
60
|
+
},
|
|
61
|
+
reset() {
|
|
62
|
+
state = { status: "idle" };
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// libs/ui/src/renderer/common/inject-stylesheet.ts
|
|
68
|
+
function injectStylesheet(href, id) {
|
|
69
|
+
if (typeof document === "undefined") return;
|
|
70
|
+
if (document.getElementById(id)) return;
|
|
71
|
+
const link = document.createElement("link");
|
|
72
|
+
link.id = id;
|
|
73
|
+
link.rel = "stylesheet";
|
|
74
|
+
link.href = href;
|
|
75
|
+
link.crossOrigin = "anonymous";
|
|
76
|
+
document.head.appendChild(link);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// libs/ui/src/renderer/common/use-renderer-theme.ts
|
|
80
|
+
import { useMemo } from "react";
|
|
81
|
+
import { useTheme } from "@mui/material/styles";
|
|
82
|
+
function extractThemeValues(theme) {
|
|
83
|
+
const palette = theme.palette;
|
|
84
|
+
return {
|
|
85
|
+
mode: palette.mode,
|
|
86
|
+
primary: palette.primary.main,
|
|
87
|
+
secondary: palette.secondary.main,
|
|
88
|
+
error: palette.error.main,
|
|
89
|
+
warning: palette.warning.main,
|
|
90
|
+
success: palette.success.main,
|
|
91
|
+
info: palette.info.main,
|
|
92
|
+
background: palette.background.default,
|
|
93
|
+
paper: palette.background.paper,
|
|
94
|
+
textPrimary: palette.text.primary,
|
|
95
|
+
textSecondary: palette.text.secondary,
|
|
96
|
+
divider: palette.divider,
|
|
97
|
+
fontFamily: theme.typography.fontFamily ?? "sans-serif",
|
|
98
|
+
monoFontFamily: theme.typography["monoFontFamily"] ?? '"SF Mono", "Fira Code", "Fira Mono", "Roboto Mono", monospace',
|
|
99
|
+
fontSize: theme.typography.fontSize ?? 14,
|
|
100
|
+
borderRadius: typeof theme.shape.borderRadius === "number" ? theme.shape.borderRadius : 4,
|
|
101
|
+
seriesColors: [
|
|
102
|
+
palette.primary.main,
|
|
103
|
+
palette.secondary.main,
|
|
104
|
+
palette.error.main,
|
|
105
|
+
palette.warning.main,
|
|
106
|
+
palette.success.main,
|
|
107
|
+
palette.info.main
|
|
108
|
+
]
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function useRendererTheme() {
|
|
112
|
+
const theme = useTheme();
|
|
113
|
+
return useMemo(() => extractThemeValues(theme), [theme]);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// libs/ui/src/renderer/common/use-lazy-module.ts
|
|
117
|
+
import { useState, useEffect } from "react";
|
|
118
|
+
function useLazyModule(lazy) {
|
|
119
|
+
const [, forceUpdate] = useState(0);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (lazy.getState().status === "loaded") {
|
|
122
|
+
forceUpdate((n) => n + 1);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
lazy.load().then(
|
|
126
|
+
() => forceUpdate((n) => n + 1),
|
|
127
|
+
() => forceUpdate((n) => n + 1)
|
|
128
|
+
);
|
|
129
|
+
}, [lazy]);
|
|
130
|
+
return lazy.get();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// libs/ui/src/renderer/flow/index.ts
|
|
134
|
+
var XYFLOW_CSS_URL = "https://esm.sh/@xyflow/react@12/dist/style.css";
|
|
135
|
+
var XYFLOW_CSS_ID = "fmcp-xyflow-css";
|
|
136
|
+
function isFlow(content) {
|
|
137
|
+
const trimmed = content.trim();
|
|
138
|
+
if (trimmed.charCodeAt(0) !== 123) return false;
|
|
139
|
+
return trimmed.includes('"nodes"') && trimmed.includes('"edges"');
|
|
140
|
+
}
|
|
141
|
+
var lazyXYFlow = createLazyImport("@xyflow/react", async () => {
|
|
142
|
+
const mod = await runtimeImportWithFallback(
|
|
143
|
+
"@xyflow/react",
|
|
144
|
+
esmShUrl("@xyflow/react@12", { external: ["react", "react-dom"] })
|
|
145
|
+
);
|
|
146
|
+
return mod;
|
|
147
|
+
});
|
|
148
|
+
var FlowRoot = styled(Box, {
|
|
149
|
+
name: "FrontMcpFlow",
|
|
150
|
+
slot: "Root"
|
|
151
|
+
})(({ theme }) => ({
|
|
152
|
+
width: "100%",
|
|
153
|
+
borderRadius: theme.shape.borderRadius,
|
|
154
|
+
overflow: "hidden",
|
|
155
|
+
border: `1px solid ${theme.palette.divider}`
|
|
156
|
+
}));
|
|
157
|
+
function FlowView({ config, className }) {
|
|
158
|
+
useEffect2(() => {
|
|
159
|
+
injectStylesheet(XYFLOW_CSS_URL, XYFLOW_CSS_ID);
|
|
160
|
+
}, []);
|
|
161
|
+
const themeValues = useRendererTheme();
|
|
162
|
+
const xyflow = useLazyModule(lazyXYFlow);
|
|
163
|
+
const height = config.height ?? 500;
|
|
164
|
+
const styledNodes = useMemo2(() => {
|
|
165
|
+
return config.nodes.map((node) => ({
|
|
166
|
+
...node,
|
|
167
|
+
style: {
|
|
168
|
+
background: themeValues.paper,
|
|
169
|
+
color: themeValues.textPrimary,
|
|
170
|
+
border: `1px solid ${themeValues.divider}`,
|
|
171
|
+
borderRadius: themeValues.borderRadius,
|
|
172
|
+
padding: 8,
|
|
173
|
+
fontSize: themeValues.fontSize,
|
|
174
|
+
fontFamily: themeValues.fontFamily,
|
|
175
|
+
...node.style
|
|
176
|
+
}
|
|
177
|
+
}));
|
|
178
|
+
}, [config.nodes, themeValues]);
|
|
179
|
+
const styledEdges = useMemo2(() => {
|
|
180
|
+
return config.edges.map((edge, i) => ({
|
|
181
|
+
...edge,
|
|
182
|
+
style: {
|
|
183
|
+
stroke: themeValues.seriesColors[i % themeValues.seriesColors.length],
|
|
184
|
+
strokeWidth: 2,
|
|
185
|
+
...edge.style
|
|
186
|
+
}
|
|
187
|
+
}));
|
|
188
|
+
}, [config.edges, themeValues]);
|
|
189
|
+
if (!xyflow) {
|
|
190
|
+
return React.createElement(Alert, { severity: "info" }, "Loading flow diagram library...");
|
|
191
|
+
}
|
|
192
|
+
const { ReactFlow, Controls, MiniMap, Background } = xyflow;
|
|
193
|
+
return React.createElement(
|
|
194
|
+
FlowRoot,
|
|
195
|
+
{ className },
|
|
196
|
+
config.title && React.createElement(
|
|
197
|
+
Typography,
|
|
198
|
+
{ variant: "subtitle1", fontWeight: 600, sx: { p: 1.5, borderBottom: 1, borderColor: "divider" } },
|
|
199
|
+
config.title
|
|
200
|
+
),
|
|
201
|
+
React.createElement(
|
|
202
|
+
Box,
|
|
203
|
+
{ sx: { height } },
|
|
204
|
+
React.createElement(
|
|
205
|
+
ReactFlow,
|
|
206
|
+
{
|
|
207
|
+
nodes: styledNodes,
|
|
208
|
+
edges: styledEdges,
|
|
209
|
+
fitView: config.fitView !== false,
|
|
210
|
+
proOptions: { hideAttribution: true }
|
|
211
|
+
},
|
|
212
|
+
React.createElement(Controls, {
|
|
213
|
+
style: {
|
|
214
|
+
backgroundColor: themeValues.paper,
|
|
215
|
+
borderRadius: themeValues.borderRadius,
|
|
216
|
+
border: `1px solid ${themeValues.divider}`
|
|
217
|
+
}
|
|
218
|
+
}),
|
|
219
|
+
React.createElement(MiniMap, {
|
|
220
|
+
style: {
|
|
221
|
+
backgroundColor: themeValues.background,
|
|
222
|
+
borderRadius: themeValues.borderRadius
|
|
223
|
+
},
|
|
224
|
+
nodeColor: themeValues.primary
|
|
225
|
+
}),
|
|
226
|
+
Background && React.createElement(Background, {
|
|
227
|
+
color: themeValues.divider,
|
|
228
|
+
gap: 16
|
|
229
|
+
})
|
|
230
|
+
)
|
|
231
|
+
)
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
lazyXYFlow.load().catch(() => {
|
|
235
|
+
});
|
|
236
|
+
var FlowRenderer = class {
|
|
237
|
+
type = "flow";
|
|
238
|
+
priority = 70;
|
|
239
|
+
canHandle(content) {
|
|
240
|
+
return isFlow(content);
|
|
241
|
+
}
|
|
242
|
+
render(content, options) {
|
|
243
|
+
try {
|
|
244
|
+
const config = JSON.parse(content);
|
|
245
|
+
return React.createElement(FlowView, {
|
|
246
|
+
config,
|
|
247
|
+
className: options?.className ?? "fmcp-flow-content"
|
|
248
|
+
});
|
|
249
|
+
} catch {
|
|
250
|
+
return React.createElement(Alert, { severity: "error" }, "Invalid flow JSON");
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
var flowRenderer = new FlowRenderer();
|
|
255
|
+
export {
|
|
256
|
+
FlowRenderer,
|
|
257
|
+
flowRenderer,
|
|
258
|
+
isFlow
|
|
259
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// libs/ui/src/renderer/html/index.ts
|
|
2
|
+
import React, { useMemo, useState, useEffect } from "react";
|
|
3
|
+
import Box from "@mui/material/Box";
|
|
4
|
+
import { styled } from "@mui/material/styles";
|
|
5
|
+
|
|
6
|
+
// libs/ui/src/renderer/common/lazy-import.ts
|
|
7
|
+
var ESM_SH_BASE = "https://esm.sh/";
|
|
8
|
+
function esmShUrl(pkg, options) {
|
|
9
|
+
let url = `${ESM_SH_BASE}${pkg}`;
|
|
10
|
+
if (options?.external?.length) {
|
|
11
|
+
url += `?external=${options.external.join(",")}`;
|
|
12
|
+
}
|
|
13
|
+
return url;
|
|
14
|
+
}
|
|
15
|
+
function runtimeImport(specifier) {
|
|
16
|
+
const dynamicImport = new Function("s", "return import(s)");
|
|
17
|
+
return dynamicImport(specifier);
|
|
18
|
+
}
|
|
19
|
+
async function runtimeImportWithFallback(bareSpecifier, fallbackUrl) {
|
|
20
|
+
try {
|
|
21
|
+
return await runtimeImport(bareSpecifier);
|
|
22
|
+
} catch {
|
|
23
|
+
return runtimeImport(fallbackUrl);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// libs/ui/src/renderer/html/index.ts
|
|
28
|
+
var HtmlRoot = styled(Box, {
|
|
29
|
+
name: "FrontMcpHtml",
|
|
30
|
+
slot: "Root"
|
|
31
|
+
})(({ theme }) => ({
|
|
32
|
+
"& a": { color: theme.palette.primary.main },
|
|
33
|
+
"& table": { borderCollapse: "collapse", width: "100%" },
|
|
34
|
+
"& th, & td": { border: `1px solid ${theme.palette.divider}`, padding: theme.spacing(1) },
|
|
35
|
+
"& pre": {
|
|
36
|
+
backgroundColor: theme.palette.mode === "dark" ? theme.palette.grey[900] : theme.palette.grey[100],
|
|
37
|
+
padding: theme.spacing(1.5),
|
|
38
|
+
borderRadius: theme.shape.borderRadius,
|
|
39
|
+
overflow: "auto"
|
|
40
|
+
}
|
|
41
|
+
}));
|
|
42
|
+
var purifyModule = null;
|
|
43
|
+
var purifyPromise = null;
|
|
44
|
+
function loadDOMPurify() {
|
|
45
|
+
if (purifyModule) return Promise.resolve(purifyModule);
|
|
46
|
+
if (purifyPromise) return purifyPromise;
|
|
47
|
+
purifyPromise = runtimeImportWithFallback("dompurify", esmShUrl("dompurify@3")).then((mod) => {
|
|
48
|
+
purifyModule = mod;
|
|
49
|
+
return purifyModule;
|
|
50
|
+
}).catch(() => {
|
|
51
|
+
purifyModule = null;
|
|
52
|
+
purifyPromise = null;
|
|
53
|
+
return null;
|
|
54
|
+
});
|
|
55
|
+
return purifyPromise;
|
|
56
|
+
}
|
|
57
|
+
function escapeHtml(html) {
|
|
58
|
+
return html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
59
|
+
}
|
|
60
|
+
function sanitizeSync(html) {
|
|
61
|
+
if (!purifyModule) return escapeHtml(html);
|
|
62
|
+
const sanitize = purifyModule.default?.sanitize ?? purifyModule.sanitize;
|
|
63
|
+
return sanitize ? sanitize(html) : escapeHtml(html);
|
|
64
|
+
}
|
|
65
|
+
loadDOMPurify();
|
|
66
|
+
function HtmlView({ html, className }) {
|
|
67
|
+
const [purifyReady, setPurifyReady] = useState(!!purifyModule);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (!purifyModule) {
|
|
70
|
+
loadDOMPurify().then((mod) => {
|
|
71
|
+
if (mod) setPurifyReady(true);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}, []);
|
|
75
|
+
const sanitized = useMemo(() => sanitizeSync(html), [html, purifyReady]);
|
|
76
|
+
return React.createElement(HtmlRoot, {
|
|
77
|
+
className,
|
|
78
|
+
dangerouslySetInnerHTML: { __html: sanitized }
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
var HtmlRenderer = class {
|
|
82
|
+
type = "html";
|
|
83
|
+
priority = 0;
|
|
84
|
+
canHandle(content) {
|
|
85
|
+
return /^\s*</.test(content) && /<\/\w+>/.test(content);
|
|
86
|
+
}
|
|
87
|
+
render(content, options) {
|
|
88
|
+
return React.createElement(HtmlView, {
|
|
89
|
+
html: content,
|
|
90
|
+
className: options?.className ?? "fmcp-html-content"
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var htmlRenderer = new HtmlRenderer();
|
|
95
|
+
export {
|
|
96
|
+
HtmlRenderer,
|
|
97
|
+
escapeHtml,
|
|
98
|
+
htmlRenderer
|
|
99
|
+
};
|