@seed-ship/mcp-ui-solid 6.19.0 → 6.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +532 -0
- package/README.md +798 -1
- package/dist/adapters/connector.cjs +15 -4
- package/dist/adapters/connector.cjs.map +1 -1
- package/dist/adapters/connector.d.ts +38 -0
- package/dist/adapters/connector.d.ts.map +1 -1
- package/dist/adapters/connector.js +15 -4
- package/dist/adapters/connector.js.map +1 -1
- package/dist/adapters/index.d.ts +4 -3
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/macro-run.cjs +25 -13
- package/dist/adapters/macro-run.cjs.map +1 -1
- package/dist/adapters/macro-run.d.ts +37 -2
- package/dist/adapters/macro-run.d.ts.map +1 -1
- package/dist/adapters/macro-run.js +25 -13
- package/dist/adapters/macro-run.js.map +1 -1
- package/dist/adapters.cjs +2 -0
- package/dist/adapters.cjs.map +1 -1
- package/dist/adapters.js +4 -2
- package/dist/components/ActionGroupRenderer.cjs +3 -1
- package/dist/components/ActionGroupRenderer.cjs.map +1 -1
- package/dist/components/ActionGroupRenderer.d.ts.map +1 -1
- package/dist/components/ActionGroupRenderer.js +3 -1
- package/dist/components/ActionGroupRenderer.js.map +1 -1
- package/dist/components/AgentCard.cjs +11 -8
- package/dist/components/AgentCard.cjs.map +1 -1
- package/dist/components/AgentCard.d.ts.map +1 -1
- package/dist/components/AgentCard.js +11 -8
- package/dist/components/AgentCard.js.map +1 -1
- package/dist/components/AgentHandoff.cjs +6 -1
- package/dist/components/AgentHandoff.cjs.map +1 -1
- package/dist/components/AgentHandoff.d.ts.map +1 -1
- package/dist/components/AgentHandoff.js +6 -1
- package/dist/components/AgentHandoff.js.map +1 -1
- package/dist/components/ArtifactRenderer.cjs +25 -6
- package/dist/components/ArtifactRenderer.cjs.map +1 -1
- package/dist/components/ArtifactRenderer.d.ts.map +1 -1
- package/dist/components/ArtifactRenderer.js +25 -6
- package/dist/components/ArtifactRenderer.js.map +1 -1
- package/dist/components/AutocompleteDropdown.cjs +30 -24
- package/dist/components/AutocompleteDropdown.cjs.map +1 -1
- package/dist/components/AutocompleteDropdown.d.ts.map +1 -1
- package/dist/components/AutocompleteDropdown.js +30 -24
- package/dist/components/AutocompleteDropdown.js.map +1 -1
- package/dist/components/AutocompleteFormField.cjs +3 -1
- package/dist/components/AutocompleteFormField.cjs.map +1 -1
- package/dist/components/AutocompleteFormField.d.ts.map +1 -1
- package/dist/components/AutocompleteFormField.js +4 -2
- package/dist/components/AutocompleteFormField.js.map +1 -1
- package/dist/components/BriefingDiff.cjs +45 -39
- package/dist/components/BriefingDiff.cjs.map +1 -1
- package/dist/components/BriefingDiff.d.ts.map +1 -1
- package/dist/components/BriefingDiff.js +45 -39
- package/dist/components/BriefingDiff.js.map +1 -1
- package/dist/components/CarouselRenderer.cjs +8 -2
- package/dist/components/CarouselRenderer.cjs.map +1 -1
- package/dist/components/CarouselRenderer.d.ts.map +1 -1
- package/dist/components/CarouselRenderer.js +8 -2
- package/dist/components/CarouselRenderer.js.map +1 -1
- package/dist/components/ChartJSRenderer.cjs +60 -36
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +61 -37
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/ChatPrompt.cjs +15 -9
- package/dist/components/ChatPrompt.cjs.map +1 -1
- package/dist/components/ChatPrompt.d.ts.map +1 -1
- package/dist/components/ChatPrompt.js +15 -9
- package/dist/components/ChatPrompt.js.map +1 -1
- package/dist/components/CodeBlockRenderer.cjs +34 -16
- package/dist/components/CodeBlockRenderer.cjs.map +1 -1
- package/dist/components/CodeBlockRenderer.d.ts.map +1 -1
- package/dist/components/CodeBlockRenderer.js +34 -16
- package/dist/components/CodeBlockRenderer.js.map +1 -1
- package/dist/components/DataPreviewSection.cjs +91 -44
- package/dist/components/DataPreviewSection.cjs.map +1 -1
- package/dist/components/DataPreviewSection.d.ts.map +1 -1
- package/dist/components/DataPreviewSection.js +92 -45
- package/dist/components/DataPreviewSection.js.map +1 -1
- package/dist/components/DegradedFallback.cjs +20 -16
- package/dist/components/DegradedFallback.cjs.map +1 -1
- package/dist/components/DegradedFallback.d.ts.map +1 -1
- package/dist/components/DegradedFallback.js +20 -16
- package/dist/components/DegradedFallback.js.map +1 -1
- package/dist/components/FeedbackInline.cjs +19 -3
- package/dist/components/FeedbackInline.cjs.map +1 -1
- package/dist/components/FeedbackInline.js +19 -3
- package/dist/components/FeedbackInline.js.map +1 -1
- package/dist/components/FooterRenderer.cjs +21 -17
- package/dist/components/FooterRenderer.cjs.map +1 -1
- package/dist/components/FooterRenderer.d.ts.map +1 -1
- package/dist/components/FooterRenderer.js +21 -17
- package/dist/components/FooterRenderer.js.map +1 -1
- package/dist/components/FormFieldRenderer.cjs +116 -93
- package/dist/components/FormFieldRenderer.cjs.map +1 -1
- package/dist/components/FormFieldRenderer.d.ts.map +1 -1
- package/dist/components/FormFieldRenderer.js +116 -93
- package/dist/components/FormFieldRenderer.js.map +1 -1
- package/dist/components/FormRenderer.cjs +55 -31
- package/dist/components/FormRenderer.cjs.map +1 -1
- package/dist/components/FormRenderer.d.ts.map +1 -1
- package/dist/components/FormRenderer.js +55 -31
- package/dist/components/FormRenderer.js.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.cjs +20 -15
- package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.d.ts.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.js +20 -15
- package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
- package/dist/components/GraphRenderer.cjs +56 -33
- package/dist/components/GraphRenderer.cjs.map +1 -1
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +56 -33
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/ImageGalleryRenderer.cjs +13 -4
- package/dist/components/ImageGalleryRenderer.cjs.map +1 -1
- package/dist/components/ImageGalleryRenderer.d.ts.map +1 -1
- package/dist/components/ImageGalleryRenderer.js +13 -4
- package/dist/components/ImageGalleryRenderer.js.map +1 -1
- package/dist/components/LightboxOverlay.cjs +16 -8
- package/dist/components/LightboxOverlay.cjs.map +1 -1
- package/dist/components/LightboxOverlay.d.ts.map +1 -1
- package/dist/components/LightboxOverlay.js +17 -9
- package/dist/components/LightboxOverlay.js.map +1 -1
- package/dist/components/MapRenderer.cjs +59 -29
- package/dist/components/MapRenderer.cjs.map +1 -1
- package/dist/components/MapRenderer.d.ts +10 -2
- package/dist/components/MapRenderer.d.ts.map +1 -1
- package/dist/components/MapRenderer.js +60 -30
- package/dist/components/MapRenderer.js.map +1 -1
- package/dist/components/ModalRenderer.cjs +4 -1
- package/dist/components/ModalRenderer.cjs.map +1 -1
- package/dist/components/ModalRenderer.d.ts.map +1 -1
- package/dist/components/ModalRenderer.js +5 -2
- package/dist/components/ModalRenderer.js.map +1 -1
- package/dist/components/ScratchpadPanel.cjs +578 -535
- package/dist/components/ScratchpadPanel.cjs.map +1 -1
- package/dist/components/ScratchpadPanel.d.ts.map +1 -1
- package/dist/components/ScratchpadPanel.js +578 -535
- package/dist/components/ScratchpadPanel.js.map +1 -1
- package/dist/components/StreamingUIRenderer.cjs +92 -28
- package/dist/components/StreamingUIRenderer.cjs.map +1 -1
- package/dist/components/StreamingUIRenderer.d.ts.map +1 -1
- package/dist/components/StreamingUIRenderer.js +92 -28
- package/dist/components/StreamingUIRenderer.js.map +1 -1
- package/dist/components/UIResourceRenderer.cjs +456 -363
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts +21 -0
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +458 -365
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/components/VerifiedText.cjs +39 -20
- package/dist/components/VerifiedText.cjs.map +1 -1
- package/dist/components/VerifiedText.d.ts +2 -1
- package/dist/components/VerifiedText.d.ts.map +1 -1
- package/dist/components/VerifiedText.js +39 -20
- package/dist/components/VerifiedText.js.map +1 -1
- package/dist/components/VideoRenderer.cjs +10 -5
- package/dist/components/VideoRenderer.cjs.map +1 -1
- package/dist/components/VideoRenderer.d.ts.map +1 -1
- package/dist/components/VideoRenderer.js +10 -5
- package/dist/components/VideoRenderer.js.map +1 -1
- package/dist/components/chart-data-table.cjs +38 -17
- package/dist/components/chart-data-table.cjs.map +1 -1
- package/dist/components/chart-data-table.d.ts +30 -1
- package/dist/components/chart-data-table.d.ts.map +1 -1
- package/dist/components/chart-data-table.js +38 -17
- package/dist/components/chart-data-table.js.map +1 -1
- package/dist/context/MCPActionContext.cjs +3 -1
- package/dist/context/MCPActionContext.cjs.map +1 -1
- package/dist/context/MCPActionContext.d.ts.map +1 -1
- package/dist/context/MCPActionContext.js +3 -1
- package/dist/context/MCPActionContext.js.map +1 -1
- package/dist/context/MCPUIStringsContext.cjs +285 -2
- package/dist/context/MCPUIStringsContext.cjs.map +1 -1
- package/dist/context/MCPUIStringsContext.d.ts +600 -3
- package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
- package/dist/context/MCPUIStringsContext.js +285 -2
- package/dist/context/MCPUIStringsContext.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useStreamingUI.cjs +28 -10
- package/dist/hooks/useStreamingUI.cjs.map +1 -1
- package/dist/hooks/useStreamingUI.d.ts +37 -0
- package/dist/hooks/useStreamingUI.d.ts.map +1 -1
- package/dist/hooks/useStreamingUI.js +28 -10
- package/dist/hooks/useStreamingUI.js.map +1 -1
- package/dist/hooks.cjs +1 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.js +2 -1
- package/dist/index.cjs +23 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/dist/services/validation.cjs +41 -16
- package/dist/services/validation.cjs.map +1 -1
- package/dist/services/validation.d.ts +47 -2
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/services/validation.js +41 -16
- package/dist/services/validation.js.map +1 -1
- package/dist/utils/degraded-projections.cjs +37 -12
- package/dist/utils/degraded-projections.cjs.map +1 -1
- package/dist/utils/degraded-projections.d.ts +39 -3
- package/dist/utils/degraded-projections.d.ts.map +1 -1
- package/dist/utils/degraded-projections.js +37 -12
- package/dist/utils/degraded-projections.js.map +1 -1
- package/dist/utils/format-string.cjs +10 -0
- package/dist/utils/format-string.cjs.map +1 -0
- package/dist/utils/format-string.d.ts +26 -0
- package/dist/utils/format-string.d.ts.map +1 -0
- package/dist/utils/format-string.js +10 -0
- package/dist/utils/format-string.js.map +1 -0
- package/dist/validation.cjs +3 -0
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.cts +2 -1
- package/dist/validation.d.ts +2 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +4 -1
- package/package.json +1 -1
- package/src/adapters/connector.ts +58 -4
- package/src/adapters/index.ts +12 -2
- package/src/adapters/macro-run.ts +71 -11
- package/src/components/ActionGroupRenderer.tsx +3 -1
- package/src/components/AgentCard.tsx +27 -9
- package/src/components/AgentHandoff.tsx +4 -1
- package/src/components/ArtifactRenderer.tsx +17 -5
- package/src/components/AutocompleteDropdown.tsx +8 -6
- package/src/components/AutocompleteFormField.tsx +5 -1
- package/src/components/BriefingDiff.tsx +11 -3
- package/src/components/CarouselRenderer.tsx +4 -2
- package/src/components/ChartJSRenderer.tsx +18 -9
- package/src/components/ChatPrompt.tsx +13 -8
- package/src/components/CodeBlockRenderer.tsx +12 -10
- package/src/components/DataPreviewSection.tsx +92 -26
- package/src/components/DegradedFallback.tsx +4 -2
- package/src/components/FeedbackInline.tsx +2 -2
- package/src/components/FooterRenderer.tsx +3 -1
- package/src/components/FormFieldRenderer.tsx +34 -19
- package/src/components/FormRenderer.tsx +38 -10
- package/src/components/GenerativeUIErrorBoundary.tsx +8 -3
- package/src/components/GraphRenderer.tsx +31 -16
- package/src/components/ImageGalleryRenderer.tsx +8 -4
- package/src/components/LightboxOverlay.tsx +6 -4
- package/src/components/MapRenderer.tsx +57 -20
- package/src/components/ModalRenderer.tsx +3 -1
- package/src/components/ScratchpadPanel.tsx +95 -44
- package/src/components/StreamingUIRenderer.tsx +41 -11
- package/src/components/UIResourceRenderer.tsx +145 -63
- package/src/components/VerifiedText.tsx +19 -9
- package/src/components/VideoRenderer.tsx +6 -4
- package/src/components/chart-data-table.ts +68 -14
- package/src/context/MCPActionContext.tsx +4 -1
- package/src/context/MCPUIStringsContext.tsx +1004 -1
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useStreamingUI.ts +64 -10
- package/src/index.ts +23 -0
- package/src/services/validation.ts +93 -16
- package/src/utils/degraded-projections.ts +75 -12
- package/src/utils/format-string.ts +33 -0
- package/src/validation.ts +5 -0
|
@@ -2,39 +2,44 @@ import { createComponent, memo, isServer, getNextElement, getNextMarker, insert,
|
|
|
2
2
|
import { createSignal, onMount, ErrorBoundary, Show } from "solid-js";
|
|
3
3
|
import { createLogger } from "../utils/logger.js";
|
|
4
4
|
import { useTelemetry } from "../context/MCPUITelemetryContext.js";
|
|
5
|
-
|
|
5
|
+
import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
|
|
6
|
+
import { formatMCPUIString } from "../utils/format-string.js";
|
|
7
|
+
var _tmpl$ = /* @__PURE__ */ template(`<p class="text-xs text-yellow-600 dark:text-yellow-400 mt-2 font-mono">`), _tmpl$2 = /* @__PURE__ */ template(`<button class="mt-3 text-xs font-medium text-yellow-800 dark:text-yellow-200 hover:text-yellow-900 dark:hover:text-yellow-100 underline">`), _tmpl$3 = /* @__PURE__ */ template(`<div class="w-full h-full bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4"><div class="flex items-start gap-3"><div class=flex-shrink-0><svg class="w-5 h-5 text-yellow-600 dark:text-yellow-400"fill=none stroke=currentColor viewBox="0 0 24 24"><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg></div><div class="flex-1 min-w-0"><p class="text-sm font-medium text-yellow-900 dark:text-yellow-100"></p><p class="text-xs text-yellow-700 dark:text-yellow-300 mt-1"></p><!$><!/><!$><!/>`);
|
|
6
8
|
const logger = createLogger("generative-ui");
|
|
7
9
|
function DefaultErrorFallback(props) {
|
|
10
|
+
const strings = useMCPUIStrings();
|
|
8
11
|
return (() => {
|
|
9
|
-
var _el$ = getNextElement(_tmpl$3), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$
|
|
10
|
-
_el$
|
|
11
|
-
var _el$14 = _el$6.nextSibling, [_el$15, _co$3] = getNextMarker(_el$14.nextSibling), _el$16 = _el$15.nextSibling, [_el$17, _co$4] = getNextMarker(_el$16.nextSibling);
|
|
12
|
-
insert(_el$6, () => props.componentType || "unknown", _el$1, _co$);
|
|
12
|
+
var _el$ = getNextElement(_tmpl$3), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$9 = _el$6.nextSibling, [_el$0, _co$] = getNextMarker(_el$9.nextSibling), _el$1 = _el$0.nextSibling, [_el$10, _co$2] = getNextMarker(_el$1.nextSibling);
|
|
13
|
+
insert(_el$5, () => strings.errorBoundaryTitle);
|
|
13
14
|
insert(_el$6, () => {
|
|
14
15
|
var _a;
|
|
15
|
-
return (
|
|
16
|
-
|
|
16
|
+
return formatMCPUIString(strings.errorBoundaryMeta, {
|
|
17
|
+
type: props.componentType || strings.unknown,
|
|
18
|
+
id: ((_a = props.componentId) == null ? void 0 : _a.slice(0, 8)) || strings.unknown
|
|
19
|
+
});
|
|
20
|
+
});
|
|
17
21
|
insert(_el$4, createComponent(Show, {
|
|
18
22
|
get when() {
|
|
19
23
|
return false;
|
|
20
24
|
},
|
|
21
25
|
get children() {
|
|
22
|
-
var _el$
|
|
23
|
-
insert(_el$
|
|
24
|
-
return _el$
|
|
26
|
+
var _el$7 = getNextElement(_tmpl$);
|
|
27
|
+
insert(_el$7, () => props.error.message);
|
|
28
|
+
return _el$7;
|
|
25
29
|
}
|
|
26
|
-
}), _el$
|
|
30
|
+
}), _el$0, _co$);
|
|
27
31
|
insert(_el$4, createComponent(Show, {
|
|
28
32
|
get when() {
|
|
29
33
|
return props.allowRetry;
|
|
30
34
|
},
|
|
31
35
|
get children() {
|
|
32
|
-
var _el$
|
|
33
|
-
addEventListener(_el$
|
|
36
|
+
var _el$8 = getNextElement(_tmpl$2);
|
|
37
|
+
addEventListener(_el$8, "click", props.onRetry, true);
|
|
38
|
+
insert(_el$8, () => strings.errorBoundaryRetry);
|
|
34
39
|
runHydrationEvents();
|
|
35
|
-
return _el$
|
|
40
|
+
return _el$8;
|
|
36
41
|
}
|
|
37
|
-
}), _el$
|
|
42
|
+
}), _el$10, _co$2);
|
|
38
43
|
return _el$;
|
|
39
44
|
})();
|
|
40
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenerativeUIErrorBoundary.js","sources":["../../src/components/GenerativeUIErrorBoundary.tsx"],"sourcesContent":["/**\n * Generative UI Error Boundary with Telemetry\n * Phase 0: Error isolation + structured logging\n *\n * Features:\n * - Component-level error isolation\n * - Structured logging with context\n * - Performance timing\n * - Retry mechanism\n * - User-friendly fallback UI\n */\n\nimport { Component, ErrorBoundary, createSignal, Show, onMount } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport { createLogger } from '../utils/logger'\nimport type { RendererError, ComponentType } from '../types'\nimport { useTelemetry } from '../context/MCPUITelemetryContext'\n\nconst logger = createLogger('generative-ui')\n\n/**\n * Props for GenerativeUIErrorBoundary\n */\nexport interface GenerativeUIErrorBoundaryProps {\n /**\n * Component identifier for telemetry\n */\n componentId: string\n\n /**\n * Component type for context\n */\n componentType: string\n\n /**\n * Error callback\n */\n onError?: (error: RendererError) => void\n\n /**\n * Allow retry on error\n */\n allowRetry?: boolean\n\n /**\n * Child components to wrap\n */\n children: any\n\n /**\n * Custom fallback UI (optional)\n */\n fallback?: (error: Error, retry?: () => void) => any\n}\n\n/**\n * Default fallback UI for errors\n */\nfunction DefaultErrorFallback(props: {\n error: Error\n componentId: string\n componentType: string\n allowRetry?: boolean\n onRetry?: () => void\n}) {\n return (\n <div class=\"w-full h-full bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4\">\n <div class=\"flex items-start gap-3\">\n <div class=\"flex-shrink-0\">\n <svg\n class=\"w-5 h-5 text-yellow-600 dark:text-yellow-400\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"text-sm font-medium text-yellow-900 dark:text-yellow-100\">\n Component Failed to Render\n </p>\n <p class=\"text-xs text-yellow-700 dark:text-yellow-300 mt-1\">\n Type: {props.componentType || 'unknown'} | ID: {props.componentId?.slice(0, 8) || 'unknown'}...\n </p>\n <Show when={import.meta.env.DEV}>\n <p class=\"text-xs text-yellow-600 dark:text-yellow-400 mt-2 font-mono\">\n {props.error.message}\n </p>\n </Show>\n <Show when={props.allowRetry}>\n <button\n onClick={props.onRetry}\n class=\"mt-3 text-xs font-medium text-yellow-800 dark:text-yellow-200 hover:text-yellow-900 dark:hover:text-yellow-100 underline\"\n >\n Retry Rendering\n </button>\n </Show>\n </div>\n </div>\n </div>\n )\n}\n\n/**\n * Generative UI Error Boundary Component\n */\nexport const GenerativeUIErrorBoundary: Component<GenerativeUIErrorBoundaryProps> = (props) => {\n const [retryKey, setRetryKey] = createSignal(0)\n const [renderStartTime, setRenderStartTime] = createSignal(0)\n // Telemetry sink (B.5 — v5.6.0). Null when no Provider is mounted.\n const telemetry = useTelemetry()\n\n // SSR-safe: Initialize performance timing on client only\n onMount(() => {\n if (typeof performance !== 'undefined') {\n setRenderStartTime(performance.now())\n }\n })\n\n // Handle error with telemetry\n const handleError = (error: Error) => {\n // SSR-safe: Calculate render duration\n const renderDuration = !isServer && typeof performance !== 'undefined'\n ? performance.now() - renderStartTime()\n : 0\n\n // SSR-safe: Get client-only context\n const userAgent = !isServer && typeof navigator !== 'undefined'\n ? navigator.userAgent\n : 'server'\n const viewport = !isServer && typeof window !== 'undefined'\n ? { width: window.innerWidth, height: window.innerHeight }\n : { width: 0, height: 0 }\n\n // Structure error context\n const errorContext = {\n componentId: props.componentId,\n componentType: props.componentType,\n errorMessage: error.message,\n errorStack: error.stack,\n renderDuration,\n retryCount: retryKey(),\n timestamp: new Date().toISOString(),\n userAgent,\n viewport,\n }\n\n // Log to structured logger\n logger.error(`Component render failed: ${props.componentType}`, errorContext)\n\n // Call error callback\n props.onError?.({\n type: 'render',\n message: error.message,\n componentId: props.componentId,\n details: errorContext,\n })\n\n // Dispatch render:error to telemetry sink (B.5 — v5.6.0). Only the\n // message (capped semantically by the consumer if desired) — NO stack\n // trace, NO component payload, per privacy hard rule (§M.6.2).\n if (telemetry) {\n telemetry.dispatch({\n type: 'render:error',\n id: props.componentId,\n componentType: props.componentType as ComponentType,\n errorMessage: error.message,\n ts: Date.now(),\n })\n }\n\n // In production, send to monitoring service\n if (import.meta.env.PROD) {\n // Future: Send to Sentry or other APM\n // Sentry.captureException(error, { contexts: { component: errorContext } })\n }\n }\n\n // Retry mechanism\n const handleRetry = () => {\n const newRetryCount = retryKey() + 1\n logger.info(`Retrying component render: ${props.componentType}`, {\n componentId: props.componentId,\n retryCount: newRetryCount,\n })\n setRetryKey(newRetryCount)\n }\n\n return (\n <ErrorBoundary\n fallback={(error) => {\n handleError(error)\n\n // Use custom fallback if provided\n if (props.fallback) {\n return props.fallback(error, props.allowRetry ? handleRetry : undefined)\n }\n\n // Default fallback\n return (\n <DefaultErrorFallback\n error={error}\n componentId={props.componentId}\n componentType={props.componentType}\n allowRetry={props.allowRetry}\n onRetry={handleRetry}\n />\n )\n }}\n >\n {/* Key prop for forcing remount on retry */}\n {(() => {\n void retryKey() // Access signal to track changes\n return <>{props.children}</>\n })()}\n </ErrorBoundary>\n )\n}\n\n/**\n * Performance monitoring wrapper\n * Logs render times for performance analysis\n */\nexport function withPerformanceMonitoring<P extends { componentId: string; componentType: string }>(\n WrappedComponent: Component<P>\n) {\n return (props: P) => {\n const [renderStart, setRenderStart] = createSignal(0)\n\n // Log render start\n logger.debug(`Component render start: ${props.componentType}`, {\n componentId: props.componentId,\n timestamp: new Date().toISOString(),\n })\n\n // SSR-safe: Measure on mount completion (client-side only)\n onMount(() => {\n if (typeof performance !== 'undefined') {\n setRenderStart(performance.now())\n\n requestAnimationFrame(() => {\n const renderEnd = performance.now()\n const duration = renderEnd - renderStart()\n\n logger.info(`Component rendered: ${props.componentType}`, {\n componentId: props.componentId,\n renderDuration: duration,\n timestamp: new Date().toISOString(),\n })\n\n // Warn if render is slow (>50ms target)\n if (duration > 50) {\n logger.warn(`Slow component render: ${props.componentType}`, {\n componentId: props.componentId,\n renderDuration: duration,\n threshold: 50,\n })\n }\n })\n }\n })\n\n return <WrappedComponent {...props} />\n }\n}\n\n/**\n * Hook to track component lifecycle events\n */\nexport function useComponentTelemetry(componentId: string, componentType: string) {\n const [mountTime, setMountTime] = createSignal(0)\n\n // SSR-safe: Initialize mount time on client only\n onMount(() => {\n if (typeof performance !== 'undefined') {\n setMountTime(performance.now())\n }\n\n // Log mount\n logger.debug(`Component mounted: ${componentType}`, {\n componentId,\n timestamp: new Date().toISOString(),\n })\n })\n\n // Return cleanup function for unmount\n return () => {\n const lifetime = !isServer && typeof performance !== 'undefined'\n ? performance.now() - mountTime()\n : 0\n logger.debug(`Component unmounted: ${componentType}`, {\n componentId,\n lifetime,\n timestamp: new Date().toISOString(),\n })\n }\n}\n"],"names":["logger","createLogger","DefaultErrorFallback","props","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$7","_el$0","_el$1","_co$","_$getNextMarker","_el$8","_el$10","_el$11","_co$2","_el$14","_el$15","_co$3","_el$16","_el$17","_co$4","_$insert","componentType","componentId","slice","_$createComponent","Show","when","import","children","_el$12","_tmpl$","error","message","allowRetry","_el$13","_tmpl$2","_$addEventListener","onRetry","_$runHydrationEvents","GenerativeUIErrorBoundary","retryKey","setRetryKey","createSignal","renderStartTime","setRenderStartTime","telemetry","useTelemetry","onMount","performance","now","handleError","renderDuration","isServer","userAgent","navigator","viewport","window","width","innerWidth","height","innerHeight","errorContext","errorMessage","errorStack","stack","retryCount","timestamp","Date","toISOString","onError","type","details","dispatch","id","ts","handleRetry","newRetryCount","info","ErrorBoundary","fallback","undefined","_$memo","_$delegateEvents"],"mappings":";;;;;AAkBA,MAAMA,SAASC,aAAa,eAAe;AAwC3C,SAASC,qBAAqBC,OAM3B;AACD,UAAA,MAAA;AAAA,QAAAC,OAAAC,eAAAC,OAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAD,MAAAE,aAAAC,QAAAF,MAAAF,YAAAK,QAAAD,MAAAD,aAAAG,QAAAD,MAAAL,YAAAO,QAAAD,MAAAH,aAAA,CAAAK,OAAAC,IAAA,IAAAC,cAAAH,MAAAJ,WAAA,GAAAQ,QAAAH,MAAAL,aAAAS,SAAAD,MAAAR,aAAA,CAAAU,QAAAC,KAAA,IAAAJ,cAAAE,OAAAT,WAAA;AAAAU,WAAAV;AAAAA,QAAAY,SAAAV,MAAAF,aAAA,CAAAa,QAAAC,KAAA,IAAAP,cAAAK,OAAAZ,WAAA,GAAAe,SAAAF,OAAAb,aAAA,CAAAgB,QAAAC,KAAA,IAAAV,cAAAQ,OAAAf,WAAA;AAAAkB,WAAAhB,OAAA,MAuBiBV,MAAM2B,iBAAiB,WAASd,OAAAC,IAAA;AAAAY,WAAAhB,OAAA;;AAASV,0BAAM4B,gBAAN5B,mBAAmB6B,MAAM,GAAG,OAAM;AAAA,OAASX,QAAAC,KAAA;AAAAO,WAAAnB,OAAAuB,gBAE5FC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEC;AAAAA,MAAmB;AAAA,MAAA,IAAAC,WAAA;AAAA,YAAAC,SAAAjC,eAAAkC,MAAA;AAAAV,eAAAS,QAAA,MAE1BnC,MAAMqC,MAAMC,OAAO;AAAA,eAAAH;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAAd,QAAAC,KAAA;AAAAI,WAAAnB,OAAAuB,gBAGvBC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEhC,MAAMuC;AAAAA,MAAU;AAAA,MAAA,IAAAL,WAAA;AAAA,YAAAM,SAAAtC,eAAAuC,OAAA;AAAAC,yBAAAF,QAAA,SAEfxC,MAAM2C,SAAO,IAAA;AAAAC,2BAAAA;AAAA,eAAAJ;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAAhB,QAAAC,KAAA;AAAA,WAAAxB;AAAAA,EAAA,GAAA;AAUpC;AAKO,MAAM4C,4BAAwE7C,CAAAA,UAAU;AAC7F,QAAM,CAAC8C,UAAUC,WAAW,IAAIC,aAAa,CAAC;AAC9C,QAAM,CAACC,iBAAiBC,kBAAkB,IAAIF,aAAa,CAAC;AAE5D,QAAMG,YAAYC,aAAAA;AAGlBC,UAAQ,MAAM;AACZ,QAAI,OAAOC,gBAAgB,aAAa;AACtCJ,yBAAmBI,YAAYC,KAAK;AAAA,IACtC;AAAA,EACF,CAAC;AAGD,QAAMC,cAAcA,CAACnB,UAAiB;;AAEpC,UAAMoB,iBAAiB,CAACC,YAAY,OAAOJ,gBAAgB,cACvDA,YAAYC,IAAAA,IAAQN,gBAAAA,IACpB;AAGJ,UAAMU,YAAY,CAACD,YAAY,OAAOE,cAAc,cAChDA,UAAUD,YACV;AACJ,UAAME,WAAW,CAACH,YAAY,OAAOI,WAAW,cAC5C;AAAA,MAAEC,OAAOD,OAAOE;AAAAA,MAAYC,QAAQH,OAAOI;AAAAA,IAAAA,IAC3C;AAAA,MAAEH,OAAO;AAAA,MAAGE,QAAQ;AAAA,IAAA;AAGxB,UAAME,eAAe;AAAA,MACnBvC,aAAa5B,MAAM4B;AAAAA,MACnBD,eAAe3B,MAAM2B;AAAAA,MACrByC,cAAc/B,MAAMC;AAAAA,MACpB+B,YAAYhC,MAAMiC;AAAAA,MAClBb;AAAAA,MACAc,YAAYzB,SAAAA;AAAAA,MACZ0B,YAAW,oBAAIC,KAAAA,GAAOC,YAAAA;AAAAA,MACtBf;AAAAA,MACAE;AAAAA,IAAAA;AAIFhE,WAAOwC,MAAM,4BAA4BrC,MAAM2B,aAAa,IAAIwC,YAAY;AAG5EnE,gBAAM2E,YAAN3E,+BAAgB;AAAA,MACd4E,MAAM;AAAA,MACNtC,SAASD,MAAMC;AAAAA,MACfV,aAAa5B,MAAM4B;AAAAA,MACnBiD,SAASV;AAAAA,IAAAA;AAMX,QAAIhB,WAAW;AACbA,gBAAU2B,SAAS;AAAA,QACjBF,MAAM;AAAA,QACNG,IAAI/E,MAAM4B;AAAAA,QACVD,eAAe3B,MAAM2B;AAAAA,QACrByC,cAAc/B,MAAMC;AAAAA,QACpB0C,IAAIP,KAAKlB,IAAAA;AAAAA,MAAI,CACd;AAAA,IACH;AAAA,EAOF;AAGA,QAAM0B,cAAcA,MAAM;AACxB,UAAMC,gBAAgBpC,aAAa;AACnCjD,WAAOsF,KAAK,8BAA8BnF,MAAM2B,aAAa,IAAI;AAAA,MAC/DC,aAAa5B,MAAM4B;AAAAA,MACnB2C,YAAYW;AAAAA,IAAAA,CACb;AACDnC,gBAAYmC,aAAa;AAAA,EAC3B;AAEA,SAAApD,gBACGsD,eAAa;AAAA,IACZC,UAAWhD,CAAAA,UAAU;AACnBmB,kBAAYnB,KAAK;AAGjB,UAAIrC,MAAMqF,UAAU;AAClB,eAAOrF,MAAMqF,SAAShD,OAAOrC,MAAMuC,aAAa0C,cAAcK,MAAS;AAAA,MACzE;AAGA,aAAAxD,gBACG/B,sBAAoB;AAAA,QACnBsC;AAAAA,QAAY,IACZT,cAAW;AAAA,iBAAE5B,MAAM4B;AAAAA,QAAW;AAAA,QAAA,IAC9BD,gBAAa;AAAA,iBAAE3B,MAAM2B;AAAAA,QAAa;AAAA,QAAA,IAClCY,aAAU;AAAA,iBAAEvC,MAAMuC;AAAAA,QAAU;AAAA,QAC5BI,SAASsC;AAAAA,MAAAA,CAAW;AAAA,IAG1B;AAAA,IAAC,IAAA/C,WAAA;AAAA,cAGC,MAAM;AACN,aAAKY,SAAAA;AACL,eAAAyC,KAAA,MAAUvF,MAAMkC,QAAQ;AAAA,MAC1B,GAAA;AAAA,IAAI;AAAA,EAAA,CAAA;AAGV;AA+ECsD,eAAA,CAAA,OAAA,CAAA;"}
|
|
1
|
+
{"version":3,"file":"GenerativeUIErrorBoundary.js","sources":["../../src/components/GenerativeUIErrorBoundary.tsx"],"sourcesContent":["/**\n * Generative UI Error Boundary with Telemetry\n * Phase 0: Error isolation + structured logging\n *\n * Features:\n * - Component-level error isolation\n * - Structured logging with context\n * - Performance timing\n * - Retry mechanism\n * - User-friendly fallback UI\n */\n\nimport { Component, ErrorBoundary, createSignal, Show, onMount } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport { createLogger } from '../utils/logger'\nimport type { RendererError, ComponentType } from '../types'\nimport { useTelemetry } from '../context/MCPUITelemetryContext'\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nconst logger = createLogger('generative-ui')\n\n/**\n * Props for GenerativeUIErrorBoundary\n */\nexport interface GenerativeUIErrorBoundaryProps {\n /**\n * Component identifier for telemetry\n */\n componentId: string\n\n /**\n * Component type for context\n */\n componentType: string\n\n /**\n * Error callback\n */\n onError?: (error: RendererError) => void\n\n /**\n * Allow retry on error\n */\n allowRetry?: boolean\n\n /**\n * Child components to wrap\n */\n children: any\n\n /**\n * Custom fallback UI (optional)\n */\n fallback?: (error: Error, retry?: () => void) => any\n}\n\n/**\n * Default fallback UI for errors\n */\nfunction DefaultErrorFallback(props: {\n error: Error\n componentId: string\n componentType: string\n allowRetry?: boolean\n onRetry?: () => void\n}) {\n const strings = useMCPUIStrings()\n return (\n <div class=\"w-full h-full bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4\">\n <div class=\"flex items-start gap-3\">\n <div class=\"flex-shrink-0\">\n <svg\n class=\"w-5 h-5 text-yellow-600 dark:text-yellow-400\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"text-sm font-medium text-yellow-900 dark:text-yellow-100\">\n {strings.errorBoundaryTitle}\n </p>\n <p class=\"text-xs text-yellow-700 dark:text-yellow-300 mt-1\">\n {formatMCPUIString(strings.errorBoundaryMeta, {\n type: props.componentType || strings.unknown,\n id: props.componentId?.slice(0, 8) || strings.unknown,\n })}\n </p>\n <Show when={import.meta.env.DEV}>\n <p class=\"text-xs text-yellow-600 dark:text-yellow-400 mt-2 font-mono\">\n {props.error.message}\n </p>\n </Show>\n <Show when={props.allowRetry}>\n <button\n onClick={props.onRetry}\n class=\"mt-3 text-xs font-medium text-yellow-800 dark:text-yellow-200 hover:text-yellow-900 dark:hover:text-yellow-100 underline\"\n >\n {strings.errorBoundaryRetry}\n </button>\n </Show>\n </div>\n </div>\n </div>\n )\n}\n\n/**\n * Generative UI Error Boundary Component\n */\nexport const GenerativeUIErrorBoundary: Component<GenerativeUIErrorBoundaryProps> = (props) => {\n const [retryKey, setRetryKey] = createSignal(0)\n const [renderStartTime, setRenderStartTime] = createSignal(0)\n // Telemetry sink (B.5 — v5.6.0). Null when no Provider is mounted.\n const telemetry = useTelemetry()\n\n // SSR-safe: Initialize performance timing on client only\n onMount(() => {\n if (typeof performance !== 'undefined') {\n setRenderStartTime(performance.now())\n }\n })\n\n // Handle error with telemetry\n const handleError = (error: Error) => {\n // SSR-safe: Calculate render duration\n const renderDuration = !isServer && typeof performance !== 'undefined'\n ? performance.now() - renderStartTime()\n : 0\n\n // SSR-safe: Get client-only context\n const userAgent = !isServer && typeof navigator !== 'undefined'\n ? navigator.userAgent\n : 'server'\n const viewport = !isServer && typeof window !== 'undefined'\n ? { width: window.innerWidth, height: window.innerHeight }\n : { width: 0, height: 0 }\n\n // Structure error context\n const errorContext = {\n componentId: props.componentId,\n componentType: props.componentType,\n errorMessage: error.message,\n errorStack: error.stack,\n renderDuration,\n retryCount: retryKey(),\n timestamp: new Date().toISOString(),\n userAgent,\n viewport,\n }\n\n // Log to structured logger\n logger.error(`Component render failed: ${props.componentType}`, errorContext)\n\n // Call error callback\n props.onError?.({\n type: 'render',\n message: error.message,\n componentId: props.componentId,\n details: errorContext,\n })\n\n // Dispatch render:error to telemetry sink (B.5 — v5.6.0). Only the\n // message (capped semantically by the consumer if desired) — NO stack\n // trace, NO component payload, per privacy hard rule (§M.6.2).\n if (telemetry) {\n telemetry.dispatch({\n type: 'render:error',\n id: props.componentId,\n componentType: props.componentType as ComponentType,\n errorMessage: error.message,\n ts: Date.now(),\n })\n }\n\n // In production, send to monitoring service\n if (import.meta.env.PROD) {\n // Future: Send to Sentry or other APM\n // Sentry.captureException(error, { contexts: { component: errorContext } })\n }\n }\n\n // Retry mechanism\n const handleRetry = () => {\n const newRetryCount = retryKey() + 1\n logger.info(`Retrying component render: ${props.componentType}`, {\n componentId: props.componentId,\n retryCount: newRetryCount,\n })\n setRetryKey(newRetryCount)\n }\n\n return (\n <ErrorBoundary\n fallback={(error) => {\n handleError(error)\n\n // Use custom fallback if provided\n if (props.fallback) {\n return props.fallback(error, props.allowRetry ? handleRetry : undefined)\n }\n\n // Default fallback\n return (\n <DefaultErrorFallback\n error={error}\n componentId={props.componentId}\n componentType={props.componentType}\n allowRetry={props.allowRetry}\n onRetry={handleRetry}\n />\n )\n }}\n >\n {/* Key prop for forcing remount on retry */}\n {(() => {\n void retryKey() // Access signal to track changes\n return <>{props.children}</>\n })()}\n </ErrorBoundary>\n )\n}\n\n/**\n * Performance monitoring wrapper\n * Logs render times for performance analysis\n */\nexport function withPerformanceMonitoring<P extends { componentId: string; componentType: string }>(\n WrappedComponent: Component<P>\n) {\n return (props: P) => {\n const [renderStart, setRenderStart] = createSignal(0)\n\n // Log render start\n logger.debug(`Component render start: ${props.componentType}`, {\n componentId: props.componentId,\n timestamp: new Date().toISOString(),\n })\n\n // SSR-safe: Measure on mount completion (client-side only)\n onMount(() => {\n if (typeof performance !== 'undefined') {\n setRenderStart(performance.now())\n\n requestAnimationFrame(() => {\n const renderEnd = performance.now()\n const duration = renderEnd - renderStart()\n\n logger.info(`Component rendered: ${props.componentType}`, {\n componentId: props.componentId,\n renderDuration: duration,\n timestamp: new Date().toISOString(),\n })\n\n // Warn if render is slow (>50ms target)\n if (duration > 50) {\n logger.warn(`Slow component render: ${props.componentType}`, {\n componentId: props.componentId,\n renderDuration: duration,\n threshold: 50,\n })\n }\n })\n }\n })\n\n return <WrappedComponent {...props} />\n }\n}\n\n/**\n * Hook to track component lifecycle events\n */\nexport function useComponentTelemetry(componentId: string, componentType: string) {\n const [mountTime, setMountTime] = createSignal(0)\n\n // SSR-safe: Initialize mount time on client only\n onMount(() => {\n if (typeof performance !== 'undefined') {\n setMountTime(performance.now())\n }\n\n // Log mount\n logger.debug(`Component mounted: ${componentType}`, {\n componentId,\n timestamp: new Date().toISOString(),\n })\n })\n\n // Return cleanup function for unmount\n return () => {\n const lifetime = !isServer && typeof performance !== 'undefined'\n ? performance.now() - mountTime()\n : 0\n logger.debug(`Component unmounted: ${componentType}`, {\n componentId,\n lifetime,\n timestamp: new Date().toISOString(),\n })\n }\n}\n"],"names":["logger","createLogger","DefaultErrorFallback","props","strings","useMCPUIStrings","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$9","_el$0","_co$","_$getNextMarker","_el$1","_el$10","_co$2","_$insert","errorBoundaryTitle","formatMCPUIString","errorBoundaryMeta","type","componentType","unknown","id","componentId","slice","_$createComponent","Show","when","import","children","_el$7","_tmpl$","error","message","allowRetry","_el$8","_tmpl$2","_$addEventListener","onRetry","errorBoundaryRetry","_$runHydrationEvents","GenerativeUIErrorBoundary","retryKey","setRetryKey","createSignal","renderStartTime","setRenderStartTime","telemetry","useTelemetry","onMount","performance","now","handleError","renderDuration","isServer","userAgent","navigator","viewport","window","width","innerWidth","height","innerHeight","errorContext","errorMessage","errorStack","stack","retryCount","timestamp","Date","toISOString","onError","details","dispatch","ts","handleRetry","newRetryCount","info","ErrorBoundary","fallback","undefined","_$memo","_$delegateEvents"],"mappings":"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"}
|
|
@@ -30,7 +30,9 @@ const DegradedFallback = require("./DegradedFallback.cjs");
|
|
|
30
30
|
const degradedProjections = require("../utils/degraded-projections.cjs");
|
|
31
31
|
const escapeHtml = require("../utils/escape-html.cjs");
|
|
32
32
|
const MCPUITelemetryContext = require("../context/MCPUITelemetryContext.cjs");
|
|
33
|
-
|
|
33
|
+
const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
|
|
34
|
+
const formatString = require("../utils/format-string.cjs");
|
|
35
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<div><div class="absolute right-2 top-2 z-10"><button type=button class="px-2 py-1 text-xs bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300"aria-haspopup=menu></button><!$><!/></div><div></div><!$><!/>`), _tmpl$2 = /* @__PURE__ */ web.template(`<div class="w-full p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg"><p class="text-sm font-medium text-yellow-900 dark:text-yellow-100"></p><p class="text-xs text-yellow-700 dark:text-yellow-300 mt-1">Install <code>@antv/g6</code> peer dependency to render <code>type: "graph"</code> components.`), _tmpl$3 = /* @__PURE__ */ web.template(`<div class="w-full p-4 bg-gray-50 dark:bg-gray-800/40 border border-gray-200 dark:border-gray-700 rounded-lg animate-pulse"><div class="h-4 w-32 bg-gray-200 dark:bg-gray-700 rounded mb-2"></div><div class="h-3 w-48 bg-gray-200 dark:bg-gray-700 rounded">`), _tmpl$4 = /* @__PURE__ */ web.template(`<button type=button class="w-full text-left px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-gray-700 last:border-b-0"><div class=font-medium></div><div class="text-[10px] text-gray-500 dark:text-gray-400">`);
|
|
34
36
|
let g6ModulePromise;
|
|
35
37
|
async function isG6Available() {
|
|
36
38
|
try {
|
|
@@ -118,6 +120,7 @@ function downloadBlob(content, filename, mimeType) {
|
|
|
118
120
|
URL.revokeObjectURL(url);
|
|
119
121
|
}
|
|
120
122
|
const GraphRenderer = (props) => {
|
|
123
|
+
const strings = MCPUIStringsContext.useMCPUIStrings();
|
|
121
124
|
const params = () => props.component.params;
|
|
122
125
|
const isExpanded = ExpandableWrapper.useExpanded();
|
|
123
126
|
const telemetry = MCPUITelemetryContext.useTelemetry();
|
|
@@ -166,7 +169,7 @@ const GraphRenderer = (props) => {
|
|
|
166
169
|
graphInstance = new Graph(config);
|
|
167
170
|
await graphInstance.render();
|
|
168
171
|
} catch (err) {
|
|
169
|
-
const message = err instanceof Error ? err.message :
|
|
172
|
+
const message = err instanceof Error ? err.message : strings.graphRenderError;
|
|
170
173
|
setError(message);
|
|
171
174
|
telemetry == null ? void 0 : telemetry.dispatch({
|
|
172
175
|
type: "render:error",
|
|
@@ -203,13 +206,13 @@ const GraphRenderer = (props) => {
|
|
|
203
206
|
const url = canvas.toDataURL("image/png");
|
|
204
207
|
await downloadDataUrl(url, `${graphFilenameStem(params())}.png`);
|
|
205
208
|
} else {
|
|
206
|
-
setError(
|
|
209
|
+
setError(strings.graphPngUnsupported);
|
|
207
210
|
}
|
|
208
211
|
} else {
|
|
209
212
|
await downloadDataUrl(dataUrl, `${graphFilenameStem(params())}.png`);
|
|
210
213
|
}
|
|
211
214
|
} catch (err) {
|
|
212
|
-
setError(err instanceof Error ? err.message :
|
|
215
|
+
setError(err instanceof Error ? err.message : strings.graphPngExportFailed);
|
|
213
216
|
}
|
|
214
217
|
setExportMenuOpen(false);
|
|
215
218
|
};
|
|
@@ -229,19 +232,23 @@ const GraphRenderer = (props) => {
|
|
|
229
232
|
);
|
|
230
233
|
},
|
|
231
234
|
get children() {
|
|
232
|
-
|
|
235
|
+
var _el$9 = web.getNextElement(_tmpl$2), _el$0 = _el$9.firstChild;
|
|
236
|
+
web.insert(_el$0, () => strings.graphUnavailable);
|
|
237
|
+
return _el$9;
|
|
233
238
|
}
|
|
234
239
|
});
|
|
235
240
|
},
|
|
236
241
|
get children() {
|
|
237
242
|
return web.createComponent(ExpandableWrapper.ExpandableWrapper, {
|
|
238
243
|
get title() {
|
|
239
|
-
return params().title ??
|
|
244
|
+
return params().title ?? strings.graphTitle;
|
|
240
245
|
},
|
|
241
246
|
get copyData() {
|
|
242
247
|
return toJSON(params());
|
|
243
248
|
},
|
|
244
|
-
copyLabel
|
|
249
|
+
get copyLabel() {
|
|
250
|
+
return strings.graphCopy;
|
|
251
|
+
},
|
|
245
252
|
get toolbarVariant() {
|
|
246
253
|
return props.toolbarVariant;
|
|
247
254
|
},
|
|
@@ -250,6 +257,7 @@ const GraphRenderer = (props) => {
|
|
|
250
257
|
_el$3.$$click = () => setExportMenuOpen((v) => !v);
|
|
251
258
|
var _ref$ = exportTriggerRef;
|
|
252
259
|
typeof _ref$ === "function" ? web.use(_ref$, _el$3) : exportTriggerRef = _el$3;
|
|
260
|
+
web.insert(_el$3, () => strings.graphExportMenu);
|
|
253
261
|
web.insert(_el$2, web.createComponent(PortalDropdownMenu.PortalDropdownMenu, {
|
|
254
262
|
get open() {
|
|
255
263
|
return exportMenuOpen();
|
|
@@ -260,26 +268,28 @@ const GraphRenderer = (props) => {
|
|
|
260
268
|
"class": "text-xs",
|
|
261
269
|
get children() {
|
|
262
270
|
return web.createComponent(solidJs.For, {
|
|
263
|
-
each
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
271
|
+
get each() {
|
|
272
|
+
return [{
|
|
273
|
+
label: strings.graphDownloadPng,
|
|
274
|
+
onClick: handleExportPNG,
|
|
275
|
+
hint: strings.graphDownloadPngHint
|
|
276
|
+
}, {
|
|
277
|
+
label: strings.graphDownloadMermaid,
|
|
278
|
+
onClick: handleExportMermaid,
|
|
279
|
+
hint: strings.graphDownloadMermaidHint
|
|
280
|
+
}, {
|
|
281
|
+
label: strings.graphDownloadJson,
|
|
282
|
+
onClick: handleExportJSON,
|
|
283
|
+
hint: strings.graphDownloadJsonHint
|
|
284
|
+
}];
|
|
285
|
+
},
|
|
276
286
|
children: (item) => (() => {
|
|
277
|
-
var _el$
|
|
278
|
-
web.addEventListener(_el$
|
|
279
|
-
web.insert(_el$
|
|
280
|
-
web.insert(_el$
|
|
287
|
+
var _el$10 = web.getNextElement(_tmpl$4), _el$11 = _el$10.firstChild, _el$12 = _el$11.nextSibling;
|
|
288
|
+
web.addEventListener(_el$10, "click", item.onClick, true);
|
|
289
|
+
web.insert(_el$11, () => item.label);
|
|
290
|
+
web.insert(_el$12, () => item.hint);
|
|
281
291
|
web.runHydrationEvents();
|
|
282
|
-
return _el$
|
|
292
|
+
return _el$10;
|
|
283
293
|
})()
|
|
284
294
|
});
|
|
285
295
|
}
|
|
@@ -293,24 +303,37 @@ const GraphRenderer = (props) => {
|
|
|
293
303
|
get children() {
|
|
294
304
|
return web.createComponent(DegradedFallback.DegradedFallback, web.mergeProps({
|
|
295
305
|
get message() {
|
|
296
|
-
return
|
|
306
|
+
return formatString.formatMCPUIString(strings.graphRenderFailed, {
|
|
307
|
+
error: String(error())
|
|
308
|
+
});
|
|
297
309
|
},
|
|
298
|
-
caption
|
|
299
|
-
|
|
310
|
+
get caption() {
|
|
311
|
+
return strings.graphDegradedCaption;
|
|
312
|
+
}
|
|
313
|
+
}, () => degradedProjections.graphToDegradedTable(params(), {
|
|
314
|
+
source: strings.degradedColSource,
|
|
315
|
+
target: strings.degradedColTarget,
|
|
316
|
+
label: strings.degradedColLabel,
|
|
317
|
+
node: strings.degradedColNode
|
|
318
|
+
})));
|
|
300
319
|
}
|
|
301
320
|
}), _el$8, _co$2);
|
|
302
321
|
web.effect((_p$) => {
|
|
303
|
-
var _v$ = `relative w-full ${params().className ?? ""} ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$2 = exportMenuOpen(), _v$
|
|
322
|
+
var _v$ = `relative w-full ${params().className ?? ""} ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$2 = strings.graphExport, _v$3 = strings.graphExport, _v$4 = exportMenuOpen(), _v$5 = `bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${error() ? "hidden" : ""} ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$6 = isExpanded() ? `height: 100%; width: ${params().width ?? "100%"};` : `height: ${params().height ?? "400px"}; width: ${params().width ?? "100%"};`;
|
|
304
323
|
_v$ !== _p$.e && web.className(_el$, _p$.e = _v$);
|
|
305
|
-
_v$2 !== _p$.t && web.setAttribute(_el$3, "
|
|
306
|
-
_v$3 !== _p$.a && web.
|
|
307
|
-
_p$.o
|
|
324
|
+
_v$2 !== _p$.t && web.setAttribute(_el$3, "title", _p$.t = _v$2);
|
|
325
|
+
_v$3 !== _p$.a && web.setAttribute(_el$3, "aria-label", _p$.a = _v$3);
|
|
326
|
+
_v$4 !== _p$.o && web.setAttribute(_el$3, "aria-expanded", _p$.o = _v$4);
|
|
327
|
+
_v$5 !== _p$.i && web.className(_el$6, _p$.i = _v$5);
|
|
328
|
+
_p$.n = web.style(_el$6, _v$6, _p$.n);
|
|
308
329
|
return _p$;
|
|
309
330
|
}, {
|
|
310
331
|
e: void 0,
|
|
311
332
|
t: void 0,
|
|
312
333
|
a: void 0,
|
|
313
|
-
o: void 0
|
|
334
|
+
o: void 0,
|
|
335
|
+
i: void 0,
|
|
336
|
+
n: void 0
|
|
314
337
|
});
|
|
315
338
|
web.runHydrationEvents();
|
|
316
339
|
return _el$;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GraphRenderer.cjs","sources":["../../src/components/GraphRenderer.tsx"],"sourcesContent":["/**\n * GraphRenderer (v6.0.0) — generic node-link visualization powered by\n * `@antv/g6 ^5` (peer-optional). Same lazy-load pattern as\n * `ChartJSRenderer` and `MapRenderer` : the heavy lib is dynamically\n * imported only on first mount, and apps that don't install the peer\n * see an informative fallback instead of a crash.\n *\n * Spec : `@seed-ship/mcp-ui-spec@5.0.4` exports `GraphComponentParamsSchema`,\n * `GraphNode`, `GraphEdge`, `GraphLayoutName`, `GraphLayout`,\n * `GraphComponentParams` — the shape consumed here. Domain semantics\n * (`weight` etc.) are opaque to this renderer ; consumers decide what\n * the values mean.\n *\n * Copy + export : the renderer ships with `<ExpandableWrapper>` (default\n * copy = JSON of `{nodes, edges}`) plus a 3-format export menu — **PNG**\n * (visual snapshot via the underlying canvas/SVG), **Mermaid** (markdown\n * / GitHub-renderable `flowchart` syntax), **JSON** (raw reimportable\n * data). All three are computed lazily on click.\n */\n\nimport { Component, createSignal, onCleanup, onMount, Show, For } from 'solid-js';\nimport type { UIComponent } from '../types';\nimport type {\n GraphComponentParams,\n GraphLayout,\n} from '@seed-ship/mcp-ui-spec';\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper';\nimport { PortalDropdownMenu } from './PortalDropdownMenu';\nimport { DegradedFallback } from './DegradedFallback';\nimport { graphToDegradedTable } from '../utils/degraded-projections';\nimport { escapeHtml } from '../utils/escape-html';\nimport { useTelemetry } from '../context/MCPUITelemetryContext';\n\n// Module-scoped lazy import promise — first call triggers the dynamic\n// import, subsequent calls reuse the resolved module.\nlet g6ModulePromise: Promise<typeof import('@antv/g6')> | undefined;\n\n/**\n * Whether the `@antv/g6` peer dependency is installed and importable.\n * Resolves to `true` when the lib is available, `false` otherwise.\n *\n * Mirrors `isChartJSAvailable()` from `ChartJSRenderer`.\n */\nexport async function isG6Available(): Promise<boolean> {\n try {\n if (!g6ModulePromise) {\n g6ModulePromise = import('@antv/g6');\n }\n await g6ModulePromise;\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve the spec layout shorthand or object form into the config object\n * G6 v5 expects. When `layout` is omitted, picks `'force'` if edges are\n * present (universal default) or `'circular'` otherwise.\n */\nfunction resolveLayout(params: GraphComponentParams): { type: string; [key: string]: unknown } {\n const layout: GraphLayout | undefined = params.layout;\n if (layout === undefined) {\n const hasEdges = (params.edges?.length ?? 0) > 0;\n return { type: hasEdges ? 'force' : 'circular' };\n }\n if (typeof layout === 'string') {\n return { type: layout };\n }\n // Object form: spread the passthrough options alongside `type`.\n return { type: layout.type, ...(layout.options ?? {}) };\n}\n\n/**\n * Build the G6 v5 `Graph` constructor config from the component params.\n *\n * Pure (no DOM/lib side effects beyond reading `container`), so it can be\n * unit-tested directly without a jsdom render — this is the contract the\n * 2026-05-30 audit (P0.2) wants locked.\n *\n * ⚠️ G6 v5's `renderer` is a factory `(layer) => IRenderer`, NOT a string\n * (that was the v4 contract). Passing the string `'canvas'` / `'svg'` makes\n * G6 throw `renderer is not a function` — and because the default path used\n * to pass the string `'canvas'`, EVERY graph crashed, not just svg. So we\n * **omit `renderer` entirely**: G6 then uses its built-in canvas renderer\n * (documented default `() => new CanvasRenderer()`).\n *\n * `rendererPref: 'svg'` is reserved but NOT wired yet — a real G6 v5 SVG\n * renderer needs the `@antv/g-svg` factory (a transitive dep of `@antv/g6`,\n * not statically resolvable at build time). Until that's wired behind proper\n * optional-peer resolution, svg degrades to the canvas default with a\n * one-time warning. It must NEVER inject a string `renderer`.\n */\nexport function buildGraphConfig(\n p: GraphComponentParams,\n container?: HTMLElement\n): Record<string, unknown> {\n const config: Record<string, unknown> = {\n container,\n data: { nodes: p.nodes, edges: p.edges ?? [] },\n layout: resolveLayout(p),\n behaviors: resolveBehaviors(p),\n };\n\n if (p.rendererPref === 'svg') {\n console.warn(\n '[MCP-UI] GraphRenderer: rendererPref \"svg\" is not yet supported; using the default canvas renderer.'\n );\n }\n\n if (p.fitView !== false) {\n config.autoFit = 'view';\n }\n\n if (p.tooltip !== false) {\n config.plugins = [\n {\n type: 'tooltip',\n getContent: (_evt: unknown, items: any[]) => {\n const item = items?.[0];\n if (!item) return '';\n const label = item.label ?? item.id ?? '';\n const data = item.data ? JSON.stringify(item.data) : '';\n return `<div style=\"padding:4px 8px\"><strong>${escapeHtml(String(label))}</strong>${\n data ? `<br><span style=\"font-size:11px;opacity:0.7\">${escapeHtml(data)}</span>` : ''\n }</div>`;\n },\n },\n ];\n }\n\n return config;\n}\n\n/**\n * Build the G6 v5 `behaviors` array from the params interactivity flags.\n * Defaults : drag-canvas + zoom-canvas + drag-element + click-select.\n * Any flag set to `false` opts out.\n */\nfunction resolveBehaviors(params: GraphComponentParams): string[] {\n const behaviors: string[] = [];\n if (params.enableDrag !== false) behaviors.push('drag-element');\n if (params.enableZoom !== false) {\n behaviors.push('zoom-canvas', 'drag-canvas');\n }\n if (params.enableSelect !== false) behaviors.push('click-select');\n return behaviors;\n}\n\n/**\n * Pick a sensible Mermaid `flowchart` direction from the resolved layout.\n * `dagre` / `tree` / `mindmap` are top-down hierarchies → TD ; everything\n * else (force, concentric, circular, grid) → LR (default mermaid).\n */\nfunction mermaidDirection(layoutType: string): 'TD' | 'LR' {\n return layoutType === 'dagre' || layoutType === 'tree' || layoutType === 'mindmap' ? 'TD' : 'LR';\n}\n\n/**\n * Sanitize a string for use inside a Mermaid node label. Mermaid breaks\n * on raw quotes / brackets / pipes ; we strip the worst offenders.\n */\nfunction mermaidLabel(s: string): string {\n return s\n .replace(/[\"[\\]|]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/**\n * Convert the graph data to Mermaid `flowchart` syntax. The edge label\n * carries the optional `weight` prefix when present (e.g. `|3| label`).\n */\nfunction toMermaid(params: GraphComponentParams): string {\n const layoutType = resolveLayout(params).type;\n const dir = mermaidDirection(layoutType);\n const lines: string[] = [`flowchart ${dir}`];\n for (const n of params.nodes) {\n const label = mermaidLabel(n.label ?? n.id);\n lines.push(` ${n.id}[\"${label}\"]`);\n }\n for (const e of params.edges ?? []) {\n const labelParts: string[] = [];\n if (e.weight !== undefined) labelParts.push(String(e.weight));\n if (e.label) labelParts.push(mermaidLabel(e.label));\n const labelText = labelParts.join(' · ');\n if (labelText) {\n lines.push(` ${e.source} -->|${labelText}| ${e.target}`);\n } else {\n lines.push(` ${e.source} --> ${e.target}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction toJSON(params: GraphComponentParams): string {\n return JSON.stringify({ nodes: params.nodes, edges: params.edges ?? [] }, null, 2);\n}\n\nfunction downloadBlob(content: string | Blob, filename: string, mimeType?: string): void {\n const blob =\n typeof content === 'string' ? new Blob([content], { type: mimeType ?? 'text/plain' }) : content;\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n}\n\nexport interface GraphRendererProps {\n component: UIComponent;\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible';\n}\n\nexport const GraphRenderer: Component<GraphRendererProps> = (props) => {\n const params = () => props.component.params as GraphComponentParams;\n const isExpanded = useExpanded();\n const telemetry = useTelemetry();\n const [available, setAvailable] = createSignal<boolean | null>(null);\n const [error, setError] = createSignal<string | undefined>();\n const [exportMenuOpen, setExportMenuOpen] = createSignal(false);\n let containerRef: HTMLDivElement | undefined;\n // v6.4.0 — trigger ref consumed by <PortalDropdownMenu> for positioning\n let exportTriggerRef: HTMLButtonElement | undefined;\n // Loosely typed because G6 is a peer-optional — we don't pull its\n // types into the bundle just to type a transient local handle.\n let graphInstance: any | undefined;\n\n onMount(async () => {\n const g6Available = await isG6Available();\n setAvailable(g6Available);\n if (!g6Available || !containerRef) return;\n\n try {\n const { Graph } = await g6ModulePromise!;\n const p = params();\n const config: Record<string, unknown> = {\n container: containerRef,\n data: { nodes: p.nodes, edges: p.edges ?? [] },\n layout: resolveLayout(p),\n behaviors: resolveBehaviors(p),\n };\n\n // G6 v5's `renderer` is a factory `(layer) => IRenderer`, NOT a string\n // (that was the v4 contract). Passing the string `'canvas'` / `'svg'`\n // makes G6 throw `renderer is not a function` — and because the default\n // path also passed the string `'canvas'`, EVERY graph crashed, not just\n // the svg one.\n //\n // Fix: omit `renderer` entirely. G6 then uses its built-in canvas\n // renderer (documented default `() => new CanvasRenderer()`), which is\n // what we want for every graph.\n //\n // `rendererPref: 'svg'` is NOT wired yet: a real G6 v5 SVG renderer\n // needs the `@antv/g-svg` factory, which is a *transitive* dep of\n // `@antv/g6` (not a declared peer) and isn't statically resolvable at\n // build time. Rather than ship a fragile/unresolvable import, we treat\n // svg as \"not yet supported\" and fall back to the canvas default with a\n // one-time warning. Tracked for a follow-up that wires the factory\n // behind a proper optional-peer resolution. (Never pass a string here.)\n if (p.rendererPref === 'svg') {\n console.warn(\n '[MCP-UI] GraphRenderer: rendererPref \"svg\" is not yet supported; using the default canvas renderer.'\n );\n }\n if (p.fitView !== false) {\n config.autoFit = 'view';\n }\n if (p.tooltip !== false) {\n // Built-in tooltip plugin — shows label + a compact dump of\n // node.data on hover. Consumers can opt out with `tooltip: false`.\n config.plugins = [\n {\n type: 'tooltip',\n getContent: (_evt: unknown, items: any[]) => {\n const item = items?.[0];\n if (!item) return '';\n const label = item.label ?? item.id ?? '';\n const data = item.data ? JSON.stringify(item.data) : '';\n return `<div style=\"padding:4px 8px\"><strong>${escapeHtml(String(label))}</strong>${\n data\n ? `<br><span style=\"font-size:11px;opacity:0.7\">${escapeHtml(data)}</span>`\n : ''\n }</div>`;\n },\n },\n ];\n }\n graphInstance = new (Graph as any)(config);\n await graphInstance.render();\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to render graph';\n setError(message);\n // Fallback ladder (P2.5): the native G6 render threw — emit telemetry\n // so the failure is observable, then degrade to the edge/node table\n // below instead of leaving a blank canvas.\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: message,\n id: props.component.id ?? '',\n componentType: 'graph',\n ts: Date.now(),\n });\n }\n });\n\n onCleanup(() => {\n try {\n graphInstance?.destroy();\n } catch {\n // G6 destroy can throw on already-destroyed instances or partial\n // init failures — silent because the component is unmounting anyway.\n }\n graphInstance = undefined;\n });\n\n // ─── Export handlers ────────────────────────────────────────────────\n const handleExportJSON = () => {\n downloadBlob(toJSON(params()), `${graphFilenameStem(params())}.json`, 'application/json');\n setExportMenuOpen(false);\n };\n\n const handleExportMermaid = () => {\n downloadBlob(toMermaid(params()), `${graphFilenameStem(params())}.mmd`, 'text/plain');\n setExportMenuOpen(false);\n };\n\n const handleExportPNG = async () => {\n if (!graphInstance) return;\n try {\n // G6 v5 exposes `toDataURL()` on the graph instance.\n const dataUrl: string = await graphInstance.toDataURL?.('image/png');\n if (!dataUrl) {\n // Fallback: try to grab the underlying canvas directly.\n const canvas = containerRef?.querySelector('canvas');\n if (canvas) {\n const url = (canvas as HTMLCanvasElement).toDataURL('image/png');\n await downloadDataUrl(url, `${graphFilenameStem(params())}.png`);\n } else {\n setError('PNG export not supported in current renderer mode');\n }\n } else {\n await downloadDataUrl(dataUrl, `${graphFilenameStem(params())}.png`);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'PNG export failed');\n }\n setExportMenuOpen(false);\n };\n\n return (\n <Show\n when={available() === true}\n fallback={\n <Show\n when={available() === false}\n fallback={\n // Loading skeleton while we determine peer availability\n <div class=\"w-full p-4 bg-gray-50 dark:bg-gray-800/40 border border-gray-200 dark:border-gray-700 rounded-lg animate-pulse\">\n <div class=\"h-4 w-32 bg-gray-200 dark:bg-gray-700 rounded mb-2\" />\n <div class=\"h-3 w-48 bg-gray-200 dark:bg-gray-700 rounded\" />\n </div>\n }\n >\n <div class=\"w-full p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg\">\n <p class=\"text-sm font-medium text-yellow-900 dark:text-yellow-100\">\n Graph rendering unavailable\n </p>\n <p class=\"text-xs text-yellow-700 dark:text-yellow-300 mt-1\">\n Install <code>@antv/g6</code> peer dependency to render <code>type: \"graph\"</code>{' '}\n components.\n </p>\n </div>\n </Show>\n }\n >\n <ExpandableWrapper\n title={params().title ?? 'Graph'}\n copyData={toJSON(params())}\n copyLabel=\"Copy graph (JSON)\"\n toolbarVariant={props.toolbarVariant}\n >\n <div\n class={`relative w-full ${params().className ?? ''} ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}\n >\n {/* Export menu — top-right, mirrors TableRenderer's pattern */}\n <div class=\"absolute right-2 top-2 z-10\">\n <button\n ref={exportTriggerRef}\n type=\"button\"\n onClick={() => setExportMenuOpen((v) => !v)}\n class=\"px-2 py-1 text-xs bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300\"\n title=\"Export graph\"\n aria-label=\"Export graph\"\n aria-haspopup=\"menu\"\n aria-expanded={exportMenuOpen()}\n >\n Export ▾\n </button>\n <PortalDropdownMenu\n open={exportMenuOpen()}\n onClose={() => setExportMenuOpen(false)}\n trigger={exportTriggerRef}\n width={176}\n class=\"text-xs\"\n >\n <For\n each={[\n { label: 'Download PNG', onClick: handleExportPNG, hint: 'visual snapshot' },\n {\n label: 'Download Mermaid',\n onClick: handleExportMermaid,\n hint: 'markdown / GitHub',\n },\n { label: 'Download JSON', onClick: handleExportJSON, hint: 'raw data' },\n ]}\n >\n {(item) => (\n <button\n type=\"button\"\n onClick={item.onClick}\n class=\"w-full text-left px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-gray-700 last:border-b-0\"\n >\n <div class=\"font-medium\">{item.label}</div>\n <div class=\"text-[10px] text-gray-500 dark:text-gray-400\">{item.hint}</div>\n </button>\n )}\n </For>\n </PortalDropdownMenu>\n </div>\n\n {/* Native G6 canvas — hidden once a render error degrades us. */}\n <div\n ref={containerRef}\n class={`bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${\n error() ? 'hidden' : ''\n } ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n style={\n isExpanded()\n ? `height: 100%; width: ${params().width ?? '100%'};`\n : `height: ${params().height ?? '400px'}; width: ${params().width ?? '100%'};`\n }\n />\n {/* Fallback ladder (P2.5): degrade to an edge/node table on error\n rather than showing a bare message. Export menu stays usable. */}\n <Show when={error()}>\n <DegradedFallback\n message={`Graph rendering failed: ${error()}`}\n caption=\"Showing the graph data as a table — the interactive view is unavailable.\"\n {...graphToDegradedTable(params())}\n />\n </Show>\n </div>\n </ExpandableWrapper>\n </Show>\n );\n};\n\n// ─── Helpers ──────────────────────────────────────────────────────────\n\nfunction graphFilenameStem(params: GraphComponentParams): string {\n const base = (params.title ?? 'graph').replace(/[^a-z0-9-_]+/gi, '-').replace(/^-+|-+$/g, '');\n return base || 'graph';\n}\n\nasync function downloadDataUrl(dataUrl: string, filename: string): Promise<void> {\n const res = await fetch(dataUrl);\n const blob = await res.blob();\n downloadBlob(blob, filename);\n}\n\n// Re-export for tests + consumers that want to compose their own export menu\nexport { toMermaid as graphToMermaid, toJSON as graphToJSON };\n"],"names":["g6ModulePromise","isG6Available","resolveLayout","params","layout","undefined","hasEdges","edges","length","type","options","resolveBehaviors","behaviors","enableDrag","push","enableZoom","enableSelect","mermaidDirection","layoutType","mermaidLabel","s","replace","trim","toMermaid","dir","lines","n","nodes","label","id","e","labelParts","weight","String","labelText","join","source","target","toJSON","JSON","stringify","downloadBlob","content","filename","mimeType","blob","Blob","url","URL","createObjectURL","a","document","createElement","href","download","body","appendChild","click","removeChild","revokeObjectURL","GraphRenderer","props","component","isExpanded","useExpanded","telemetry","useTelemetry","available","setAvailable","createSignal","error","setError","exportMenuOpen","setExportMenuOpen","containerRef","exportTriggerRef","graphInstance","onMount","g6Available","Graph","p","config","container","data","rendererPref","console","warn","fitView","autoFit","tooltip","plugins","getContent","_evt","items","item","escapeHtml","render","err","message","Error","dispatch","errorMessage","componentType","ts","Date","now","onCleanup","destroy","handleExportJSON","graphFilenameStem","handleExportMermaid","handleExportPNG","dataUrl","toDataURL","canvas","querySelector","downloadDataUrl","_$createComponent","Show","when","fallback","_$getNextElement","_tmpl$3","children","_tmpl$2","ExpandableWrapper","title","copyData","copyLabel","toolbarVariant","_el$","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_co$","_$getNextMarker","_el$6","_el$7","_el$8","_co$2","$$click","v","_ref$","_$use","_$insert","PortalDropdownMenu","open","onClose","trigger","width","For","each","onClick","hint","_el$1","_tmpl$4","_el$10","_el$11","_$addEventListener","_$runHydrationEvents","_ref$2","DegradedFallback","_$mergeProps","caption","graphToDegradedTable","_$effect","_p$","_v$","className","_v$2","_v$3","_v$4","height","_$className","t","_$setAttribute","o","_$style","base","res","fetch","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GraphRenderer.cjs","sources":["../../src/components/GraphRenderer.tsx"],"sourcesContent":["/**\n * GraphRenderer (v6.0.0) — generic node-link visualization powered by\n * `@antv/g6 ^5` (peer-optional). Same lazy-load pattern as\n * `ChartJSRenderer` and `MapRenderer` : the heavy lib is dynamically\n * imported only on first mount, and apps that don't install the peer\n * see an informative fallback instead of a crash.\n *\n * Spec : `@seed-ship/mcp-ui-spec@5.0.4` exports `GraphComponentParamsSchema`,\n * `GraphNode`, `GraphEdge`, `GraphLayoutName`, `GraphLayout`,\n * `GraphComponentParams` — the shape consumed here. Domain semantics\n * (`weight` etc.) are opaque to this renderer ; consumers decide what\n * the values mean.\n *\n * Copy + export : the renderer ships with `<ExpandableWrapper>` (default\n * copy = JSON of `{nodes, edges}`) plus a 3-format export menu — **PNG**\n * (visual snapshot via the underlying canvas/SVG), **Mermaid** (markdown\n * / GitHub-renderable `flowchart` syntax), **JSON** (raw reimportable\n * data). All three are computed lazily on click.\n */\n\nimport { Component, createSignal, onCleanup, onMount, Show, For } from 'solid-js';\nimport type { UIComponent } from '../types';\nimport type {\n GraphComponentParams,\n GraphLayout,\n} from '@seed-ship/mcp-ui-spec';\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper';\nimport { PortalDropdownMenu } from './PortalDropdownMenu';\nimport { DegradedFallback } from './DegradedFallback';\nimport { graphToDegradedTable } from '../utils/degraded-projections';\nimport { escapeHtml } from '../utils/escape-html';\nimport { useTelemetry } from '../context/MCPUITelemetryContext';\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';\n\n// Module-scoped lazy import promise — first call triggers the dynamic\n// import, subsequent calls reuse the resolved module.\nlet g6ModulePromise: Promise<typeof import('@antv/g6')> | undefined;\n\n/**\n * Whether the `@antv/g6` peer dependency is installed and importable.\n * Resolves to `true` when the lib is available, `false` otherwise.\n *\n * Mirrors `isChartJSAvailable()` from `ChartJSRenderer`.\n */\nexport async function isG6Available(): Promise<boolean> {\n try {\n if (!g6ModulePromise) {\n g6ModulePromise = import('@antv/g6');\n }\n await g6ModulePromise;\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve the spec layout shorthand or object form into the config object\n * G6 v5 expects. When `layout` is omitted, picks `'force'` if edges are\n * present (universal default) or `'circular'` otherwise.\n */\nfunction resolveLayout(params: GraphComponentParams): { type: string; [key: string]: unknown } {\n const layout: GraphLayout | undefined = params.layout;\n if (layout === undefined) {\n const hasEdges = (params.edges?.length ?? 0) > 0;\n return { type: hasEdges ? 'force' : 'circular' };\n }\n if (typeof layout === 'string') {\n return { type: layout };\n }\n // Object form: spread the passthrough options alongside `type`.\n return { type: layout.type, ...(layout.options ?? {}) };\n}\n\n/**\n * Build the G6 v5 `Graph` constructor config from the component params.\n *\n * Pure (no DOM/lib side effects beyond reading `container`), so it can be\n * unit-tested directly without a jsdom render — this is the contract the\n * 2026-05-30 audit (P0.2) wants locked.\n *\n * ⚠️ G6 v5's `renderer` is a factory `(layer) => IRenderer`, NOT a string\n * (that was the v4 contract). Passing the string `'canvas'` / `'svg'` makes\n * G6 throw `renderer is not a function` — and because the default path used\n * to pass the string `'canvas'`, EVERY graph crashed, not just svg. So we\n * **omit `renderer` entirely**: G6 then uses its built-in canvas renderer\n * (documented default `() => new CanvasRenderer()`).\n *\n * `rendererPref: 'svg'` is reserved but NOT wired yet — a real G6 v5 SVG\n * renderer needs the `@antv/g-svg` factory (a transitive dep of `@antv/g6`,\n * not statically resolvable at build time). Until that's wired behind proper\n * optional-peer resolution, svg degrades to the canvas default with a\n * one-time warning. It must NEVER inject a string `renderer`.\n */\nexport function buildGraphConfig(\n p: GraphComponentParams,\n container?: HTMLElement\n): Record<string, unknown> {\n const config: Record<string, unknown> = {\n container,\n data: { nodes: p.nodes, edges: p.edges ?? [] },\n layout: resolveLayout(p),\n behaviors: resolveBehaviors(p),\n };\n\n if (p.rendererPref === 'svg') {\n console.warn(\n '[MCP-UI] GraphRenderer: rendererPref \"svg\" is not yet supported; using the default canvas renderer.'\n );\n }\n\n if (p.fitView !== false) {\n config.autoFit = 'view';\n }\n\n if (p.tooltip !== false) {\n config.plugins = [\n {\n type: 'tooltip',\n getContent: (_evt: unknown, items: any[]) => {\n const item = items?.[0];\n if (!item) return '';\n const label = item.label ?? item.id ?? '';\n const data = item.data ? JSON.stringify(item.data) : '';\n return `<div style=\"padding:4px 8px\"><strong>${escapeHtml(String(label))}</strong>${\n data ? `<br><span style=\"font-size:11px;opacity:0.7\">${escapeHtml(data)}</span>` : ''\n }</div>`;\n },\n },\n ];\n }\n\n return config;\n}\n\n/**\n * Build the G6 v5 `behaviors` array from the params interactivity flags.\n * Defaults : drag-canvas + zoom-canvas + drag-element + click-select.\n * Any flag set to `false` opts out.\n */\nfunction resolveBehaviors(params: GraphComponentParams): string[] {\n const behaviors: string[] = [];\n if (params.enableDrag !== false) behaviors.push('drag-element');\n if (params.enableZoom !== false) {\n behaviors.push('zoom-canvas', 'drag-canvas');\n }\n if (params.enableSelect !== false) behaviors.push('click-select');\n return behaviors;\n}\n\n/**\n * Pick a sensible Mermaid `flowchart` direction from the resolved layout.\n * `dagre` / `tree` / `mindmap` are top-down hierarchies → TD ; everything\n * else (force, concentric, circular, grid) → LR (default mermaid).\n */\nfunction mermaidDirection(layoutType: string): 'TD' | 'LR' {\n return layoutType === 'dagre' || layoutType === 'tree' || layoutType === 'mindmap' ? 'TD' : 'LR';\n}\n\n/**\n * Sanitize a string for use inside a Mermaid node label. Mermaid breaks\n * on raw quotes / brackets / pipes ; we strip the worst offenders.\n */\nfunction mermaidLabel(s: string): string {\n return s\n .replace(/[\"[\\]|]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n/**\n * Convert the graph data to Mermaid `flowchart` syntax. The edge label\n * carries the optional `weight` prefix when present (e.g. `|3| label`).\n */\nfunction toMermaid(params: GraphComponentParams): string {\n const layoutType = resolveLayout(params).type;\n const dir = mermaidDirection(layoutType);\n const lines: string[] = [`flowchart ${dir}`];\n for (const n of params.nodes) {\n const label = mermaidLabel(n.label ?? n.id);\n lines.push(` ${n.id}[\"${label}\"]`);\n }\n for (const e of params.edges ?? []) {\n const labelParts: string[] = [];\n if (e.weight !== undefined) labelParts.push(String(e.weight));\n if (e.label) labelParts.push(mermaidLabel(e.label));\n const labelText = labelParts.join(' · ');\n if (labelText) {\n lines.push(` ${e.source} -->|${labelText}| ${e.target}`);\n } else {\n lines.push(` ${e.source} --> ${e.target}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction toJSON(params: GraphComponentParams): string {\n return JSON.stringify({ nodes: params.nodes, edges: params.edges ?? [] }, null, 2);\n}\n\nfunction downloadBlob(content: string | Blob, filename: string, mimeType?: string): void {\n const blob =\n typeof content === 'string' ? new Blob([content], { type: mimeType ?? 'text/plain' }) : content;\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n}\n\nexport interface GraphRendererProps {\n component: UIComponent;\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible';\n}\n\nexport const GraphRenderer: Component<GraphRendererProps> = (props) => {\n const strings = useMCPUIStrings();\n const params = () => props.component.params as GraphComponentParams;\n const isExpanded = useExpanded();\n const telemetry = useTelemetry();\n const [available, setAvailable] = createSignal<boolean | null>(null);\n const [error, setError] = createSignal<string | undefined>();\n const [exportMenuOpen, setExportMenuOpen] = createSignal(false);\n let containerRef: HTMLDivElement | undefined;\n // v6.4.0 — trigger ref consumed by <PortalDropdownMenu> for positioning\n let exportTriggerRef: HTMLButtonElement | undefined;\n // Loosely typed because G6 is a peer-optional — we don't pull its\n // types into the bundle just to type a transient local handle.\n let graphInstance: any | undefined;\n\n onMount(async () => {\n const g6Available = await isG6Available();\n setAvailable(g6Available);\n if (!g6Available || !containerRef) return;\n\n try {\n const { Graph } = await g6ModulePromise!;\n const p = params();\n const config: Record<string, unknown> = {\n container: containerRef,\n data: { nodes: p.nodes, edges: p.edges ?? [] },\n layout: resolveLayout(p),\n behaviors: resolveBehaviors(p),\n };\n\n // G6 v5's `renderer` is a factory `(layer) => IRenderer`, NOT a string\n // (that was the v4 contract). Passing the string `'canvas'` / `'svg'`\n // makes G6 throw `renderer is not a function` — and because the default\n // path also passed the string `'canvas'`, EVERY graph crashed, not just\n // the svg one.\n //\n // Fix: omit `renderer` entirely. G6 then uses its built-in canvas\n // renderer (documented default `() => new CanvasRenderer()`), which is\n // what we want for every graph.\n //\n // `rendererPref: 'svg'` is NOT wired yet: a real G6 v5 SVG renderer\n // needs the `@antv/g-svg` factory, which is a *transitive* dep of\n // `@antv/g6` (not a declared peer) and isn't statically resolvable at\n // build time. Rather than ship a fragile/unresolvable import, we treat\n // svg as \"not yet supported\" and fall back to the canvas default with a\n // one-time warning. Tracked for a follow-up that wires the factory\n // behind a proper optional-peer resolution. (Never pass a string here.)\n if (p.rendererPref === 'svg') {\n console.warn(\n '[MCP-UI] GraphRenderer: rendererPref \"svg\" is not yet supported; using the default canvas renderer.'\n );\n }\n if (p.fitView !== false) {\n config.autoFit = 'view';\n }\n if (p.tooltip !== false) {\n // Built-in tooltip plugin — shows label + a compact dump of\n // node.data on hover. Consumers can opt out with `tooltip: false`.\n config.plugins = [\n {\n type: 'tooltip',\n getContent: (_evt: unknown, items: any[]) => {\n const item = items?.[0];\n if (!item) return '';\n const label = item.label ?? item.id ?? '';\n const data = item.data ? JSON.stringify(item.data) : '';\n return `<div style=\"padding:4px 8px\"><strong>${escapeHtml(String(label))}</strong>${\n data\n ? `<br><span style=\"font-size:11px;opacity:0.7\">${escapeHtml(data)}</span>`\n : ''\n }</div>`;\n },\n },\n ];\n }\n graphInstance = new (Graph as any)(config);\n await graphInstance.render();\n } catch (err) {\n const message = err instanceof Error ? err.message : strings.graphRenderError;\n setError(message);\n // Fallback ladder (P2.5): the native G6 render threw — emit telemetry\n // so the failure is observable, then degrade to the edge/node table\n // below instead of leaving a blank canvas.\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: message,\n id: props.component.id ?? '',\n componentType: 'graph',\n ts: Date.now(),\n });\n }\n });\n\n onCleanup(() => {\n try {\n graphInstance?.destroy();\n } catch {\n // G6 destroy can throw on already-destroyed instances or partial\n // init failures — silent because the component is unmounting anyway.\n }\n graphInstance = undefined;\n });\n\n // ─── Export handlers ────────────────────────────────────────────────\n const handleExportJSON = () => {\n downloadBlob(toJSON(params()), `${graphFilenameStem(params())}.json`, 'application/json');\n setExportMenuOpen(false);\n };\n\n const handleExportMermaid = () => {\n downloadBlob(toMermaid(params()), `${graphFilenameStem(params())}.mmd`, 'text/plain');\n setExportMenuOpen(false);\n };\n\n const handleExportPNG = async () => {\n if (!graphInstance) return;\n try {\n // G6 v5 exposes `toDataURL()` on the graph instance.\n const dataUrl: string = await graphInstance.toDataURL?.('image/png');\n if (!dataUrl) {\n // Fallback: try to grab the underlying canvas directly.\n const canvas = containerRef?.querySelector('canvas');\n if (canvas) {\n const url = (canvas as HTMLCanvasElement).toDataURL('image/png');\n await downloadDataUrl(url, `${graphFilenameStem(params())}.png`);\n } else {\n setError(strings.graphPngUnsupported);\n }\n } else {\n await downloadDataUrl(dataUrl, `${graphFilenameStem(params())}.png`);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : strings.graphPngExportFailed);\n }\n setExportMenuOpen(false);\n };\n\n return (\n <Show\n when={available() === true}\n fallback={\n <Show\n when={available() === false}\n fallback={\n // Loading skeleton while we determine peer availability\n <div class=\"w-full p-4 bg-gray-50 dark:bg-gray-800/40 border border-gray-200 dark:border-gray-700 rounded-lg animate-pulse\">\n <div class=\"h-4 w-32 bg-gray-200 dark:bg-gray-700 rounded mb-2\" />\n <div class=\"h-3 w-48 bg-gray-200 dark:bg-gray-700 rounded\" />\n </div>\n }\n >\n <div class=\"w-full p-4 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg\">\n <p class=\"text-sm font-medium text-yellow-900 dark:text-yellow-100\">\n {strings.graphUnavailable}\n </p>\n <p class=\"text-xs text-yellow-700 dark:text-yellow-300 mt-1\">\n Install <code>@antv/g6</code> peer dependency to render <code>type: \"graph\"</code>{' '}\n components.\n </p>\n </div>\n </Show>\n }\n >\n <ExpandableWrapper\n title={params().title ?? strings.graphTitle}\n copyData={toJSON(params())}\n copyLabel={strings.graphCopy}\n toolbarVariant={props.toolbarVariant}\n >\n <div\n class={`relative w-full ${params().className ?? ''} ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}\n >\n {/* Export menu — top-right, mirrors TableRenderer's pattern */}\n <div class=\"absolute right-2 top-2 z-10\">\n <button\n ref={exportTriggerRef}\n type=\"button\"\n onClick={() => setExportMenuOpen((v) => !v)}\n class=\"px-2 py-1 text-xs bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300\"\n title={strings.graphExport}\n aria-label={strings.graphExport}\n aria-haspopup=\"menu\"\n aria-expanded={exportMenuOpen()}\n >\n {strings.graphExportMenu}\n </button>\n <PortalDropdownMenu\n open={exportMenuOpen()}\n onClose={() => setExportMenuOpen(false)}\n trigger={exportTriggerRef}\n width={176}\n class=\"text-xs\"\n >\n <For\n each={[\n {\n label: strings.graphDownloadPng,\n onClick: handleExportPNG,\n hint: strings.graphDownloadPngHint,\n },\n {\n label: strings.graphDownloadMermaid,\n onClick: handleExportMermaid,\n hint: strings.graphDownloadMermaidHint,\n },\n {\n label: strings.graphDownloadJson,\n onClick: handleExportJSON,\n hint: strings.graphDownloadJsonHint,\n },\n ]}\n >\n {(item) => (\n <button\n type=\"button\"\n onClick={item.onClick}\n class=\"w-full text-left px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-gray-700 last:border-b-0\"\n >\n <div class=\"font-medium\">{item.label}</div>\n <div class=\"text-[10px] text-gray-500 dark:text-gray-400\">{item.hint}</div>\n </button>\n )}\n </For>\n </PortalDropdownMenu>\n </div>\n\n {/* Native G6 canvas — hidden once a render error degrades us. */}\n <div\n ref={containerRef}\n class={`bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${\n error() ? 'hidden' : ''\n } ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n style={\n isExpanded()\n ? `height: 100%; width: ${params().width ?? '100%'};`\n : `height: ${params().height ?? '400px'}; width: ${params().width ?? '100%'};`\n }\n />\n {/* Fallback ladder (P2.5): degrade to an edge/node table on error\n rather than showing a bare message. Export menu stays usable. */}\n <Show when={error()}>\n <DegradedFallback\n message={formatMCPUIString(strings.graphRenderFailed, { error: String(error()) })}\n caption={strings.graphDegradedCaption}\n {...graphToDegradedTable(params(), {\n source: strings.degradedColSource,\n target: strings.degradedColTarget,\n label: strings.degradedColLabel,\n node: strings.degradedColNode,\n })}\n />\n </Show>\n </div>\n </ExpandableWrapper>\n </Show>\n );\n};\n\n// ─── Helpers ──────────────────────────────────────────────────────────\n\nfunction graphFilenameStem(params: GraphComponentParams): string {\n const base = (params.title ?? 'graph').replace(/[^a-z0-9-_]+/gi, '-').replace(/^-+|-+$/g, '');\n return base || 'graph';\n}\n\nasync function downloadDataUrl(dataUrl: string, filename: string): Promise<void> {\n const res = await fetch(dataUrl);\n const blob = await res.blob();\n downloadBlob(blob, filename);\n}\n\n// Re-export for tests + consumers that want to compose their own export menu\nexport { toMermaid as graphToMermaid, toJSON as graphToJSON };\n"],"names":["g6ModulePromise","isG6Available","resolveLayout","params","layout","undefined","hasEdges","edges","length","type","options","resolveBehaviors","behaviors","enableDrag","push","enableZoom","enableSelect","mermaidDirection","layoutType","mermaidLabel","s","replace","trim","toMermaid","dir","lines","n","nodes","label","id","e","labelParts","weight","String","labelText","join","source","target","toJSON","JSON","stringify","downloadBlob","content","filename","mimeType","blob","Blob","url","URL","createObjectURL","a","document","createElement","href","download","body","appendChild","click","removeChild","revokeObjectURL","GraphRenderer","props","strings","useMCPUIStrings","component","isExpanded","useExpanded","telemetry","useTelemetry","available","setAvailable","createSignal","error","setError","exportMenuOpen","setExportMenuOpen","containerRef","exportTriggerRef","graphInstance","onMount","g6Available","Graph","p","config","container","data","rendererPref","console","warn","fitView","autoFit","tooltip","plugins","getContent","_evt","items","item","escapeHtml","render","err","message","Error","graphRenderError","dispatch","errorMessage","componentType","ts","Date","now","onCleanup","destroy","handleExportJSON","graphFilenameStem","handleExportMermaid","handleExportPNG","dataUrl","toDataURL","canvas","querySelector","downloadDataUrl","graphPngUnsupported","graphPngExportFailed","_$createComponent","Show","when","fallback","_$getNextElement","_tmpl$3","children","_el$9","_tmpl$2","_el$0","firstChild","_$insert","graphUnavailable","ExpandableWrapper","title","graphTitle","copyData","copyLabel","graphCopy","toolbarVariant","_el$","_tmpl$","_el$2","_el$3","_el$4","nextSibling","_el$5","_co$","_$getNextMarker","_el$6","_el$7","_el$8","_co$2","$$click","v","_ref$","_$use","graphExportMenu","PortalDropdownMenu","open","onClose","trigger","width","For","each","graphDownloadPng","onClick","hint","graphDownloadPngHint","graphDownloadMermaid","graphDownloadMermaidHint","graphDownloadJson","graphDownloadJsonHint","_el$10","_tmpl$4","_el$11","_el$12","_$addEventListener","_$runHydrationEvents","_ref$2","DegradedFallback","_$mergeProps","formatMCPUIString","graphRenderFailed","caption","graphDegradedCaption","graphToDegradedTable","degradedColSource","degradedColTarget","degradedColLabel","node","degradedColNode","_$effect","_p$","_v$","className","_v$2","graphExport","_v$3","_v$4","_v$5","_v$6","height","_$className","t","_$setAttribute","o","i","_$style","base","res","fetch","_$delegateEvents"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GraphRenderer.d.ts","sourceRoot":"","sources":["../../src/components/GraphRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,SAAS,EAA+C,MAAM,UAAU,CAAC;AAClF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"GraphRenderer.d.ts","sourceRoot":"","sources":["../../src/components/GraphRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,SAAS,EAA+C,MAAM,UAAU,CAAC;AAClF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,wBAAwB,CAAC;AAahC;;;;;GAKG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAUtD;AAoBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,EAAE,oBAAoB,EACvB,SAAS,CAAC,EAAE,WAAW,GACtB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoCzB;AAqCD;;;GAGG;AACH,iBAAS,SAAS,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAoBvD;AAED,iBAAS,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAEpD;AAeD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,WAAW,CAAC;IACvB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;CAC7C;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,kBAAkB,CAkQvD,CAAC;AAgBF,OAAO,EAAE,SAAS,IAAI,cAAc,EAAE,MAAM,IAAI,WAAW,EAAE,CAAC"}
|