@seed-ship/mcp-ui-solid 6.3.0 → 6.4.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 +87 -0
- package/dist/components/CarouselRenderer.cjs +3 -0
- package/dist/components/CarouselRenderer.cjs.map +1 -1
- package/dist/components/CarouselRenderer.d.ts +5 -0
- package/dist/components/CarouselRenderer.d.ts.map +1 -1
- package/dist/components/CarouselRenderer.js +3 -0
- package/dist/components/CarouselRenderer.js.map +1 -1
- package/dist/components/ChartJSRenderer.cjs +3 -0
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts +5 -0
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +3 -0
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/CodeBlockRenderer.cjs +3 -0
- package/dist/components/CodeBlockRenderer.cjs.map +1 -1
- package/dist/components/CodeBlockRenderer.d.ts +5 -0
- package/dist/components/CodeBlockRenderer.d.ts.map +1 -1
- package/dist/components/CodeBlockRenderer.js +3 -0
- package/dist/components/CodeBlockRenderer.js.map +1 -1
- package/dist/components/GraphRenderer.cjs +33 -24
- package/dist/components/GraphRenderer.cjs.map +1 -1
- package/dist/components/GraphRenderer.d.ts +8 -2
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +33 -24
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/ImageGalleryRenderer.cjs +3 -0
- package/dist/components/ImageGalleryRenderer.cjs.map +1 -1
- package/dist/components/ImageGalleryRenderer.d.ts +5 -0
- package/dist/components/ImageGalleryRenderer.d.ts.map +1 -1
- package/dist/components/ImageGalleryRenderer.js +3 -0
- package/dist/components/ImageGalleryRenderer.js.map +1 -1
- package/dist/components/MapRenderer.cjs +3 -0
- package/dist/components/MapRenderer.cjs.map +1 -1
- package/dist/components/MapRenderer.d.ts +5 -0
- package/dist/components/MapRenderer.d.ts.map +1 -1
- package/dist/components/MapRenderer.js +3 -0
- package/dist/components/MapRenderer.js.map +1 -1
- package/dist/components/PortalDropdownMenu.cjs +82 -0
- package/dist/components/PortalDropdownMenu.cjs.map +1 -0
- package/dist/components/PortalDropdownMenu.d.ts +56 -0
- package/dist/components/PortalDropdownMenu.d.ts.map +1 -0
- package/dist/components/PortalDropdownMenu.js +82 -0
- package/dist/components/PortalDropdownMenu.js.map +1 -0
- package/dist/components/UIResourceRenderer.cjs +296 -256
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts +12 -0
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +296 -256
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/components/VideoRenderer.cjs +3 -0
- package/dist/components/VideoRenderer.cjs.map +1 -1
- package/dist/components/VideoRenderer.d.ts +5 -0
- package/dist/components/VideoRenderer.d.ts.map +1 -1
- package/dist/components/VideoRenderer.js +3 -0
- package/dist/components/VideoRenderer.js.map +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components.cjs +2 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +2 -0
- package/dist/components.d.ts +2 -0
- package/dist/components.js +2 -0
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/CarouselRenderer.tsx +6 -0
- package/src/components/ChartJSRenderer.tsx +7 -0
- package/src/components/CodeBlockRenderer.tsx +7 -1
- package/src/components/GraphRenderer.tsx +40 -21
- package/src/components/ImageGalleryRenderer.tsx +7 -0
- package/src/components/MapRenderer.tsx +7 -0
- package/src/components/PortalDropdownMenu.test.tsx +113 -0
- package/src/components/PortalDropdownMenu.tsx +130 -0
- package/src/components/UIResourceRenderer.fluidity.test.tsx +51 -0
- package/src/components/UIResourceRenderer.tsx +50 -24
- package/src/components/VideoRenderer.tsx +7 -0
- package/src/components/index.ts +4 -0
- package/src/index.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBlockRenderer.js","sources":["../../src/components/CodeBlockRenderer.tsx"],"sourcesContent":["/**\n * CodeBlockRenderer - Syntax highlighted code block\n * Sprint 6: Code & Maps\n * Sprint Ultimate: Theme Synchronization (U.1)\n */\n\nimport { Component, createEffect, onCleanup, createSignal, Show, For } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport type { UIComponent, CodeComponentParams } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\nimport { highlightQuery } from './UIResourceRenderer'\n\n/** Map of `params.language` → file extension for the v6.2.0 download button. */\nconst LANGUAGE_EXTENSIONS: Record<string, string> = {\n typescript: 'ts', tsx: 'tsx', javascript: 'js', jsx: 'jsx',\n python: 'py', ruby: 'rb', go: 'go', rust: 'rs', java: 'java',\n kotlin: 'kt', swift: 'swift', php: 'php', csharp: 'cs', cpp: 'cpp',\n c: 'c', sql: 'sql', json: 'json', yaml: 'yml', toml: 'toml',\n bash: 'sh', shell: 'sh', html: 'html', css: 'css', scss: 'scss',\n markdown: 'md', xml: 'xml', graphql: 'graphql',\n}\n\n// Lazy load highlight.js\nlet hljs: any = null\n// Track if styles have been loaded globally\nlet stylesLoaded = false\n\nexport interface CodeBlockRendererProps {\n /**\n * UIComponent containing code params\n */\n component?: UIComponent\n\n /**\n * Direct code params\n */\n params?: CodeComponentParams\n}\n\nexport const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {\n const [highlightedCode, setHighlightedCode] = createSignal<string>('')\n const [isCopied, setIsCopied] = createSignal(false)\n const [isHljsLoaded, setIsHljsLoaded] = createSignal(false)\n const [activeTheme, setActiveTheme] = createSignal<'light' | 'dark'>('dark')\n const [wordWrap, setWordWrap] = createSignal(false)\n\n const params = () => props.params || (props.component?.params as CodeComponentParams)\n const isExpanded = useExpanded()\n const [searchQuery, setSearchQuery] = createSignal('')\n\n // v6.2.0 — search highlight: re-wraps `<mark>` around matches in the\n // already-highlighted (hljs) HTML output. `highlightQuery` is the same\n // helper TableRenderer uses (only wraps text outside of HTML tags so\n // syntax span colors stay intact).\n const displayedHTML = () => {\n const q = searchQuery().trim()\n return q ? highlightQuery(highlightedCode(), q) : highlightedCode()\n }\n\n const handleDownload = () => {\n const code = params()?.code\n if (!code) return\n const lang = (params()?.language || '').toLowerCase()\n const ext = LANGUAGE_EXTENSIONS[lang] || 'txt'\n const stem = (params()?.filename || `code-${Date.now()}`).replace(/\\.[^.]+$/, '')\n const filename = stem.endsWith(`.${ext}`) ? stem : `${stem}.${ext}`\n const blob = new Blob([code], { type: 'text/plain' })\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\n // Load highlight.js on mount\n createEffect(async () => {\n if (!hljs) {\n try {\n // Use the full highlight.js bundle with all languages for simplicity\n const module = await import('highlight.js')\n const resolved = module.default || module\n // Guard: verify the resolved module has the expected API\n if (typeof resolved?.highlight === 'function') {\n hljs = resolved\n } else {\n console.warn('highlight.js loaded but missing highlight() method')\n }\n setIsHljsLoaded(true)\n } catch (e) {\n console.warn('Failed to load highlight.js', e)\n // Continue without highlighting - fallback to plain text\n setIsHljsLoaded(true)\n }\n } else {\n setIsHljsLoaded(true)\n }\n })\n\n // Theme management - Sprint Ultimate U.1: Reactive theme synchronization\n // Load both theme stylesheets once, then toggle via data-attribute\n createEffect(async () => {\n if (isServer || stylesLoaded) return\n\n // Load both themes upfront for instant switching\n try {\n await Promise.all([\n import('highlight.js/styles/github.css'),\n import('highlight.js/styles/github-dark.css')\n ])\n stylesLoaded = true\n } catch (e) {\n console.warn('Failed to load highlight.js themes', e)\n }\n })\n\n // Reactive theme detection - listens to system preference changes\n createEffect(() => {\n if (isServer) return\n\n // Priority 1: Explicit theme from params\n const paramTheme = params()?.theme\n if (paramTheme) {\n setActiveTheme(paramTheme)\n return\n }\n\n // Priority 2: System preference with live updates\n // Check if matchMedia is available (not in all test environments)\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n setActiveTheme(mediaQuery.matches ? 'dark' : 'light')\n\n const handleChange = (e: MediaQueryListEvent) => {\n // Only update if no explicit theme in params\n if (!params()?.theme) {\n setActiveTheme(e.matches ? 'dark' : 'light')\n }\n }\n\n mediaQuery.addEventListener('change', handleChange)\n onCleanup(() => mediaQuery.removeEventListener('change', handleChange))\n }\n })\n\n // Apply highlighting\n createEffect(() => {\n const code = params()?.code || ''\n const language = params()?.language || ''\n\n if (hljs && isHljsLoaded()) {\n try {\n let result\n if (language && hljs.getLanguage(language)) {\n result = hljs.highlight(code, { language }).value\n } else {\n result = hljs.highlightAuto(code).value\n }\n setHighlightedCode(result)\n } catch (e) {\n setHighlightedCode(code.replace(/</g, '<').replace(/>/g, '>'))\n }\n } else {\n // Fallback: simple escaping\n setHighlightedCode(code.replace(/</g, '<').replace(/>/g, '>'))\n }\n })\n\n // Line numbers generation\n const lineNumbers = () => {\n if (params()?.showLineNumbers === false) return []\n const code = params()?.code || ''\n const lines = code.split('\\n')\n const start = params()?.startLine || 1\n return lines.map((_, i) => start + i)\n }\n\n const handleCopy = async () => {\n const code = params()?.code\n if (code) {\n try {\n await navigator.clipboard.writeText(code)\n setIsCopied(true)\n setTimeout(() => setIsCopied(false), 2000)\n } catch (e) {\n console.error('Failed to copy code', e)\n }\n }\n }\n\n return (\n <ExpandableWrapper title={params()?.filename || params()?.language || 'Code'} copyData={params()?.code} copyLabel=\"Copy code\">\n <div class={`w-full bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden text-sm flex flex-col ${isExpanded() ? 'flex-1 min-h-0' : ''}`}>\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0\">\n <div class=\"font-mono text-xs text-gray-600 dark:text-gray-400\">\n {params()?.filename || params()?.language || 'Code'}\n </div>\n <div class=\"flex items-center gap-2\">\n {/* Search input (v6.2.0) */}\n <input\n type=\"text\"\n value={searchQuery()}\n onInput={(e) => setSearchQuery(e.currentTarget.value)}\n placeholder=\"Search…\"\n class=\"px-2 py-0.5 text-xs border border-gray-200 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none w-32\"\n aria-label=\"Search in code\"\n />\n {/* Download button (v6.2.0) */}\n <button\n onClick={handleDownload}\n class=\"text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors\"\n aria-label=\"Download code as file\"\n title=\"Download code\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n </button>\n {/* Word wrap toggle */}\n <button\n onClick={() => setWordWrap(!wordWrap())}\n class={`focus:outline-none transition-colors ${wordWrap() ? 'text-blue-500 dark:text-blue-400' : 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}`}\n aria-label=\"Toggle word wrap\"\n title={wordWrap() ? 'Disable word wrap' : 'Enable word wrap'}\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4\" />\n </svg>\n </button>\n {/* Copy button */}\n <button\n onClick={handleCopy}\n class=\"text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors\"\n aria-label=\"Copy code\"\n title=\"Copy code\"\n >\n <Show when={isCopied()} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n }>\n <svg class=\"w-4 h-4 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </Show>\n </button>\n </div>\n </div>\n\n {/* Code Area */}\n <div\n class={`relative overflow-auto flex ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n style={!isExpanded() && params()?.maxHeight ? { 'max-height': params()?.maxHeight } : {}}\n >\n {/* Line Numbers */}\n <Show when={params()?.showLineNumbers !== false}>\n <div class=\"flex-none text-right select-none bg-gray-100 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 py-4 px-2 text-gray-400 font-mono text-xs leading-5\">\n <For each={lineNumbers()}>\n {(num) => <div class=\"px-2\">{num}</div>}\n </For>\n </div>\n </Show>\n\n {/* Code Content - Sprint Ultimate U.1: data-theme for reactive theming */}\n <pre\n class=\"flex-1 m-0 p-4 font-mono text-gray-800 dark:text-gray-100 bg-transparent leading-5\"\n style={wordWrap() ? { 'white-space': 'pre-wrap', 'word-break': 'break-all' } : {}}\n data-theme={activeTheme()}\n >\n <code\n class={`hljs ${params()?.language ? `language-${params()?.language}` : ''}`}\n innerHTML={displayedHTML()}\n />\n </pre>\n </div>\n </div>\n </ExpandableWrapper>\n )\n}\n"],"names":["LANGUAGE_EXTENSIONS","typescript","tsx","javascript","jsx","python","ruby","go","rust","java","kotlin","swift","php","csharp","cpp","c","sql","json","yaml","toml","bash","shell","html","css","scss","markdown","xml","graphql","hljs","stylesLoaded","CodeBlockRenderer","props","highlightedCode","setHighlightedCode","createSignal","isCopied","setIsCopied","isHljsLoaded","setIsHljsLoaded","activeTheme","setActiveTheme","wordWrap","setWordWrap","params","component","isExpanded","useExpanded","searchQuery","setSearchQuery","displayedHTML","q","trim","highlightQuery","handleDownload","code","lang","language","toLowerCase","ext","stem","filename","Date","now","replace","endsWith","blob","Blob","type","url","URL","createObjectURL","a","document","createElement","href","download","body","appendChild","click","removeChild","revokeObjectURL","createEffect","module","resolved","default","highlight","console","warn","e","isServer","Promise","all","paramTheme","theme","window","matchMedia","mediaQuery","matches","handleChange","addEventListener","onCleanup","removeEventListener","result","getLanguage","value","highlightAuto","lineNumbers","showLineNumbers","lines","split","start","startLine","map","_","i","handleCopy","navigator","clipboard","writeText","setTimeout","error","_$createComponent","ExpandableWrapper","title","copyData","copyLabel","children","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$7","_el$8","_el$0","_el$12","_el$13","_co$","_$getNextMarker","_el$10","_el$11","_$insert","$$input","currentTarget","$$click","Show","when","fallback","_tmpl$4","_tmpl$","_el$1","_tmpl$2","For","each","num","_el$15","_tmpl$5","_$effect","_p$","_v$","_v$2","_v$3","_v$4","_v$5","maxHeight","_v$6","_v$7","_v$8","_v$9","_$className","t","_$setAttribute","o","_$style","n","s","h","r","_$setProperty","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CodeBlockRenderer.js","sources":["../../src/components/CodeBlockRenderer.tsx"],"sourcesContent":["/**\n * CodeBlockRenderer - Syntax highlighted code block\n * Sprint 6: Code & Maps\n * Sprint Ultimate: Theme Synchronization (U.1)\n */\n\nimport { Component, createEffect, onCleanup, createSignal, Show, For } from 'solid-js'\nimport { isServer } from 'solid-js/web'\nimport type { UIComponent, CodeComponentParams } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\nimport { highlightQuery } from './UIResourceRenderer'\n\n/** Map of `params.language` → file extension for the v6.2.0 download button. */\nconst LANGUAGE_EXTENSIONS: Record<string, string> = {\n typescript: 'ts', tsx: 'tsx', javascript: 'js', jsx: 'jsx',\n python: 'py', ruby: 'rb', go: 'go', rust: 'rs', java: 'java',\n kotlin: 'kt', swift: 'swift', php: 'php', csharp: 'cs', cpp: 'cpp',\n c: 'c', sql: 'sql', json: 'json', yaml: 'yml', toml: 'toml',\n bash: 'sh', shell: 'sh', html: 'html', css: 'css', scss: 'scss',\n markdown: 'md', xml: 'xml', graphql: 'graphql',\n}\n\n// Lazy load highlight.js\nlet hljs: any = null\n// Track if styles have been loaded globally\nlet stylesLoaded = false\n\nexport interface CodeBlockRendererProps {\n /**\n * UIComponent containing code params\n */\n component?: UIComponent\n\n /**\n * Direct code params\n */\n params?: CodeComponentParams\n\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible'\n}\n\nexport const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {\n const [highlightedCode, setHighlightedCode] = createSignal<string>('')\n const [isCopied, setIsCopied] = createSignal(false)\n const [isHljsLoaded, setIsHljsLoaded] = createSignal(false)\n const [activeTheme, setActiveTheme] = createSignal<'light' | 'dark'>('dark')\n const [wordWrap, setWordWrap] = createSignal(false)\n\n const params = () => props.params || (props.component?.params as CodeComponentParams)\n const isExpanded = useExpanded()\n const [searchQuery, setSearchQuery] = createSignal('')\n\n // v6.2.0 — search highlight: re-wraps `<mark>` around matches in the\n // already-highlighted (hljs) HTML output. `highlightQuery` is the same\n // helper TableRenderer uses (only wraps text outside of HTML tags so\n // syntax span colors stay intact).\n const displayedHTML = () => {\n const q = searchQuery().trim()\n return q ? highlightQuery(highlightedCode(), q) : highlightedCode()\n }\n\n const handleDownload = () => {\n const code = params()?.code\n if (!code) return\n const lang = (params()?.language || '').toLowerCase()\n const ext = LANGUAGE_EXTENSIONS[lang] || 'txt'\n const stem = (params()?.filename || `code-${Date.now()}`).replace(/\\.[^.]+$/, '')\n const filename = stem.endsWith(`.${ext}`) ? stem : `${stem}.${ext}`\n const blob = new Blob([code], { type: 'text/plain' })\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\n // Load highlight.js on mount\n createEffect(async () => {\n if (!hljs) {\n try {\n // Use the full highlight.js bundle with all languages for simplicity\n const module = await import('highlight.js')\n const resolved = module.default || module\n // Guard: verify the resolved module has the expected API\n if (typeof resolved?.highlight === 'function') {\n hljs = resolved\n } else {\n console.warn('highlight.js loaded but missing highlight() method')\n }\n setIsHljsLoaded(true)\n } catch (e) {\n console.warn('Failed to load highlight.js', e)\n // Continue without highlighting - fallback to plain text\n setIsHljsLoaded(true)\n }\n } else {\n setIsHljsLoaded(true)\n }\n })\n\n // Theme management - Sprint Ultimate U.1: Reactive theme synchronization\n // Load both theme stylesheets once, then toggle via data-attribute\n createEffect(async () => {\n if (isServer || stylesLoaded) return\n\n // Load both themes upfront for instant switching\n try {\n await Promise.all([\n import('highlight.js/styles/github.css'),\n import('highlight.js/styles/github-dark.css')\n ])\n stylesLoaded = true\n } catch (e) {\n console.warn('Failed to load highlight.js themes', e)\n }\n })\n\n // Reactive theme detection - listens to system preference changes\n createEffect(() => {\n if (isServer) return\n\n // Priority 1: Explicit theme from params\n const paramTheme = params()?.theme\n if (paramTheme) {\n setActiveTheme(paramTheme)\n return\n }\n\n // Priority 2: System preference with live updates\n // Check if matchMedia is available (not in all test environments)\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n setActiveTheme(mediaQuery.matches ? 'dark' : 'light')\n\n const handleChange = (e: MediaQueryListEvent) => {\n // Only update if no explicit theme in params\n if (!params()?.theme) {\n setActiveTheme(e.matches ? 'dark' : 'light')\n }\n }\n\n mediaQuery.addEventListener('change', handleChange)\n onCleanup(() => mediaQuery.removeEventListener('change', handleChange))\n }\n })\n\n // Apply highlighting\n createEffect(() => {\n const code = params()?.code || ''\n const language = params()?.language || ''\n\n if (hljs && isHljsLoaded()) {\n try {\n let result\n if (language && hljs.getLanguage(language)) {\n result = hljs.highlight(code, { language }).value\n } else {\n result = hljs.highlightAuto(code).value\n }\n setHighlightedCode(result)\n } catch (e) {\n setHighlightedCode(code.replace(/</g, '<').replace(/>/g, '>'))\n }\n } else {\n // Fallback: simple escaping\n setHighlightedCode(code.replace(/</g, '<').replace(/>/g, '>'))\n }\n })\n\n // Line numbers generation\n const lineNumbers = () => {\n if (params()?.showLineNumbers === false) return []\n const code = params()?.code || ''\n const lines = code.split('\\n')\n const start = params()?.startLine || 1\n return lines.map((_, i) => start + i)\n }\n\n const handleCopy = async () => {\n const code = params()?.code\n if (code) {\n try {\n await navigator.clipboard.writeText(code)\n setIsCopied(true)\n setTimeout(() => setIsCopied(false), 2000)\n } catch (e) {\n console.error('Failed to copy code', e)\n }\n }\n }\n\n return (\n <ExpandableWrapper title={params()?.filename || params()?.language || 'Code'} copyData={params()?.code} copyLabel=\"Copy code\" toolbarVariant={props.toolbarVariant}>\n <div class={`w-full bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden text-sm flex flex-col ${isExpanded() ? 'flex-1 min-h-0' : ''}`}>\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0\">\n <div class=\"font-mono text-xs text-gray-600 dark:text-gray-400\">\n {params()?.filename || params()?.language || 'Code'}\n </div>\n <div class=\"flex items-center gap-2\">\n {/* Search input (v6.2.0) */}\n <input\n type=\"text\"\n value={searchQuery()}\n onInput={(e) => setSearchQuery(e.currentTarget.value)}\n placeholder=\"Search…\"\n class=\"px-2 py-0.5 text-xs border border-gray-200 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none w-32\"\n aria-label=\"Search in code\"\n />\n {/* Download button (v6.2.0) */}\n <button\n onClick={handleDownload}\n class=\"text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors\"\n aria-label=\"Download code as file\"\n title=\"Download code\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n </button>\n {/* Word wrap toggle */}\n <button\n onClick={() => setWordWrap(!wordWrap())}\n class={`focus:outline-none transition-colors ${wordWrap() ? 'text-blue-500 dark:text-blue-400' : 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}`}\n aria-label=\"Toggle word wrap\"\n title={wordWrap() ? 'Disable word wrap' : 'Enable word wrap'}\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4\" />\n </svg>\n </button>\n {/* Copy button */}\n <button\n onClick={handleCopy}\n class=\"text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors\"\n aria-label=\"Copy code\"\n title=\"Copy code\"\n >\n <Show when={isCopied()} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n }>\n <svg class=\"w-4 h-4 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </Show>\n </button>\n </div>\n </div>\n\n {/* Code Area */}\n <div\n class={`relative overflow-auto flex ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n style={!isExpanded() && params()?.maxHeight ? { 'max-height': params()?.maxHeight } : {}}\n >\n {/* Line Numbers */}\n <Show when={params()?.showLineNumbers !== false}>\n <div class=\"flex-none text-right select-none bg-gray-100 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 py-4 px-2 text-gray-400 font-mono text-xs leading-5\">\n <For each={lineNumbers()}>\n {(num) => <div class=\"px-2\">{num}</div>}\n </For>\n </div>\n </Show>\n\n {/* Code Content - Sprint Ultimate U.1: data-theme for reactive theming */}\n <pre\n class=\"flex-1 m-0 p-4 font-mono text-gray-800 dark:text-gray-100 bg-transparent leading-5\"\n style={wordWrap() ? { 'white-space': 'pre-wrap', 'word-break': 'break-all' } : {}}\n data-theme={activeTheme()}\n >\n <code\n class={`hljs ${params()?.language ? `language-${params()?.language}` : ''}`}\n innerHTML={displayedHTML()}\n />\n </pre>\n </div>\n </div>\n </ExpandableWrapper>\n )\n}\n"],"names":["LANGUAGE_EXTENSIONS","typescript","tsx","javascript","jsx","python","ruby","go","rust","java","kotlin","swift","php","csharp","cpp","c","sql","json","yaml","toml","bash","shell","html","css","scss","markdown","xml","graphql","hljs","stylesLoaded","CodeBlockRenderer","props","highlightedCode","setHighlightedCode","createSignal","isCopied","setIsCopied","isHljsLoaded","setIsHljsLoaded","activeTheme","setActiveTheme","wordWrap","setWordWrap","params","component","isExpanded","useExpanded","searchQuery","setSearchQuery","displayedHTML","q","trim","highlightQuery","handleDownload","code","lang","language","toLowerCase","ext","stem","filename","Date","now","replace","endsWith","blob","Blob","type","url","URL","createObjectURL","a","document","createElement","href","download","body","appendChild","click","removeChild","revokeObjectURL","createEffect","module","resolved","default","highlight","console","warn","e","isServer","Promise","all","paramTheme","theme","window","matchMedia","mediaQuery","matches","handleChange","addEventListener","onCleanup","removeEventListener","result","getLanguage","value","highlightAuto","lineNumbers","showLineNumbers","lines","split","start","startLine","map","_","i","handleCopy","navigator","clipboard","writeText","setTimeout","error","_$createComponent","ExpandableWrapper","title","copyData","copyLabel","toolbarVariant","children","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_el$6","_el$7","_el$8","_el$0","_el$12","_el$13","_co$","_$getNextMarker","_el$10","_el$11","_$insert","$$input","currentTarget","$$click","Show","when","fallback","_tmpl$4","_tmpl$","_el$1","_tmpl$2","For","each","num","_el$15","_tmpl$5","_$effect","_p$","_v$","_v$2","_v$3","_v$4","_v$5","maxHeight","_v$6","_v$7","_v$8","_v$9","_$className","t","_$setAttribute","o","_$style","n","s","h","r","_$setProperty","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":"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"}
|
|
@@ -3,7 +3,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const web = require("solid-js/web");
|
|
4
4
|
const solidJs = require("solid-js");
|
|
5
5
|
const ExpandableWrapper = require("./ExpandableWrapper.cjs");
|
|
6
|
-
|
|
6
|
+
const PortalDropdownMenu = require("./PortalDropdownMenu.cjs");
|
|
7
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<p class="text-xs text-red-600 dark:text-red-400 mt-1">Render error: <!$><!/>`), _tmpl$2 = /* @__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"title="Export graph"aria-label="Export graph"aria-haspopup=menu>Export ▾</button><!$><!/></div><div></div><!$><!/>`), _tmpl$3 = /* @__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">Graph rendering unavailable</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$4 = /* @__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$5 = /* @__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">`);
|
|
7
8
|
let g6ModulePromise;
|
|
8
9
|
async function isG6Available() {
|
|
9
10
|
try {
|
|
@@ -97,6 +98,7 @@ const GraphRenderer = (props) => {
|
|
|
97
98
|
const [error, setError] = solidJs.createSignal();
|
|
98
99
|
const [exportMenuOpen, setExportMenuOpen] = solidJs.createSignal(false);
|
|
99
100
|
let containerRef;
|
|
101
|
+
let exportTriggerRef;
|
|
100
102
|
let graphInstance;
|
|
101
103
|
solidJs.onMount(async () => {
|
|
102
104
|
const g6Available = await isG6Available();
|
|
@@ -186,11 +188,11 @@ const GraphRenderer = (props) => {
|
|
|
186
188
|
get fallback() {
|
|
187
189
|
return (
|
|
188
190
|
// Loading skeleton while we determine peer availability
|
|
189
|
-
web.getNextElement(_tmpl$
|
|
191
|
+
web.getNextElement(_tmpl$4)
|
|
190
192
|
);
|
|
191
193
|
},
|
|
192
194
|
get children() {
|
|
193
|
-
return web.getNextElement(_tmpl$
|
|
195
|
+
return web.getNextElement(_tmpl$3);
|
|
194
196
|
}
|
|
195
197
|
});
|
|
196
198
|
},
|
|
@@ -203,16 +205,24 @@ const GraphRenderer = (props) => {
|
|
|
203
205
|
return toJSON(params());
|
|
204
206
|
},
|
|
205
207
|
copyLabel: "Copy graph (JSON)",
|
|
208
|
+
get toolbarVariant() {
|
|
209
|
+
return props.toolbarVariant;
|
|
210
|
+
},
|
|
206
211
|
get children() {
|
|
207
|
-
var _el$ = web.getNextElement(_tmpl$
|
|
212
|
+
var _el$ = web.getNextElement(_tmpl$2), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, [_el$5, _co$] = web.getNextMarker(_el$4.nextSibling), _el$6 = _el$2.nextSibling, _el$1 = _el$6.nextSibling, [_el$10, _co$3] = web.getNextMarker(_el$1.nextSibling);
|
|
208
213
|
_el$3.$$click = () => setExportMenuOpen((v) => !v);
|
|
209
|
-
|
|
210
|
-
|
|
214
|
+
var _ref$ = exportTriggerRef;
|
|
215
|
+
typeof _ref$ === "function" ? web.use(_ref$, _el$3) : exportTriggerRef = _el$3;
|
|
216
|
+
web.insert(_el$2, web.createComponent(PortalDropdownMenu.PortalDropdownMenu, {
|
|
217
|
+
get open() {
|
|
211
218
|
return exportMenuOpen();
|
|
212
219
|
},
|
|
220
|
+
onClose: () => setExportMenuOpen(false),
|
|
221
|
+
trigger: exportTriggerRef,
|
|
222
|
+
width: 176,
|
|
223
|
+
"class": "text-xs",
|
|
213
224
|
get children() {
|
|
214
|
-
|
|
215
|
-
web.insert(_el$4, web.createComponent(solidJs.For, {
|
|
225
|
+
return web.createComponent(solidJs.For, {
|
|
216
226
|
each: [{
|
|
217
227
|
label: "Download PNG",
|
|
218
228
|
onClick: handleExportPNG,
|
|
@@ -227,35 +237,34 @@ const GraphRenderer = (props) => {
|
|
|
227
237
|
hint: "raw data"
|
|
228
238
|
}],
|
|
229
239
|
children: (item) => (() => {
|
|
230
|
-
var _el$
|
|
231
|
-
web.addEventListener(_el$
|
|
232
|
-
web.insert(_el$
|
|
233
|
-
web.insert(_el$
|
|
240
|
+
var _el$13 = web.getNextElement(_tmpl$5), _el$14 = _el$13.firstChild, _el$15 = _el$14.nextSibling;
|
|
241
|
+
web.addEventListener(_el$13, "click", item.onClick, true);
|
|
242
|
+
web.insert(_el$14, () => item.label);
|
|
243
|
+
web.insert(_el$15, () => item.hint);
|
|
234
244
|
web.runHydrationEvents();
|
|
235
|
-
return _el$
|
|
245
|
+
return _el$13;
|
|
236
246
|
})()
|
|
237
|
-
})
|
|
238
|
-
return _el$4;
|
|
247
|
+
});
|
|
239
248
|
}
|
|
240
|
-
}), _el$
|
|
241
|
-
var _ref$ = containerRef;
|
|
242
|
-
typeof _ref$ === "function" ? web.use(_ref
|
|
249
|
+
}), _el$5, _co$);
|
|
250
|
+
var _ref$2 = containerRef;
|
|
251
|
+
typeof _ref$2 === "function" ? web.use(_ref$2, _el$6) : containerRef = _el$6;
|
|
243
252
|
web.insert(_el$, web.createComponent(solidJs.Show, {
|
|
244
253
|
get when() {
|
|
245
254
|
return error();
|
|
246
255
|
},
|
|
247
256
|
get children() {
|
|
248
|
-
var _el$
|
|
249
|
-
web.insert(_el$
|
|
250
|
-
return _el$
|
|
257
|
+
var _el$7 = web.getNextElement(_tmpl$), _el$8 = _el$7.firstChild, _el$9 = _el$8.nextSibling, [_el$0, _co$2] = web.getNextMarker(_el$9.nextSibling);
|
|
258
|
+
web.insert(_el$7, error, _el$0, _co$2);
|
|
259
|
+
return _el$7;
|
|
251
260
|
}
|
|
252
|
-
}), _el$
|
|
261
|
+
}), _el$10, _co$3);
|
|
253
262
|
web.effect((_p$) => {
|
|
254
263
|
var _v$ = `relative w-full ${params().className ?? ""} ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$2 = exportMenuOpen(), _v$3 = `bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$4 = isExpanded() ? `height: 100%; width: ${params().width ?? "100%"};` : `height: ${params().height ?? "400px"}; width: ${params().width ?? "100%"};`;
|
|
255
264
|
_v$ !== _p$.e && web.className(_el$, _p$.e = _v$);
|
|
256
265
|
_v$2 !== _p$.t && web.setAttribute(_el$3, "aria-expanded", _p$.t = _v$2);
|
|
257
|
-
_v$3 !== _p$.a && web.className(_el$
|
|
258
|
-
_p$.o = web.style(_el$
|
|
266
|
+
_v$3 !== _p$.a && web.className(_el$6, _p$.a = _v$3);
|
|
267
|
+
_p$.o = web.style(_el$6, _v$4, _p$.o);
|
|
259
268
|
return _p$;
|
|
260
269
|
}, {
|
|
261
270
|
e: void 0,
|
|
@@ -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 { GraphComponentParams, GraphLayout, GraphNode, GraphEdge } from '@seed-ship/mcp-ui-spec'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\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 `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.replace(/[\"[\\]|]/g, '').replace(/\\s+/g, ' ').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 = 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 const GraphRenderer: Component<{ component: UIComponent }> = (props) => {\n const params = () => props.component.params as GraphComponentParams\n const isExpanded = useExpanded()\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 // 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 renderer: p.rendererPref === 'svg' ? 'svg' : 'canvas',\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 ? `<br><span style=\"font-size:11px;opacity:0.7\">${escapeHtml(data)}</span>` : ''\n }</div>`\n },\n },\n ]\n }\n graphInstance = new (Graph as any)(config)\n await graphInstance.render()\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to render graph')\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> 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 >\n <div class={`relative w-full ${params().className ?? ''} ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}>\n {/* Export menu — top-right, mirrors TableRenderer's pattern */}\n <div class=\"absolute right-2 top-2 z-10\">\n <button\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-expanded={exportMenuOpen()}\n >\n Export ▾\n </button>\n <Show when={exportMenuOpen()}>\n <div class=\"absolute right-0 mt-1 w-44 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded shadow-lg text-xs\">\n <For each={[\n { label: 'Download PNG', onClick: handleExportPNG, hint: 'visual snapshot' },\n { label: 'Download Mermaid', onClick: handleExportMermaid, hint: 'markdown / GitHub' },\n { label: 'Download JSON', onClick: handleExportJSON, hint: 'raw data' },\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 </div>\n </Show>\n </div>\n\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 isExpanded() ? 'flex-1 min-h-0' : ''\n }`}\n style={\n isExpanded()\n ? `height: 100%; width: ${params().width ?? '100%'};`\n : `height: ${params().height ?? '400px'}; width: ${params().width ?? '100%'};`\n }\n />\n <Show when={error()}>\n <p class=\"text-xs text-red-600 dark:text-red-400 mt-1\">Render error: {error()}</p>\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\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => {\n switch (c) {\n case '&': return '&'\n case '<': return '<'\n case '>': return '>'\n case '\"': return '"'\n case \"'\": return '''\n default: return c\n }\n })\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","available","setAvailable","createSignal","error","setError","exportMenuOpen","setExportMenuOpen","containerRef","graphInstance","onMount","g6Available","Graph","p","config","container","data","renderer","rendererPref","fitView","autoFit","tooltip","plugins","getContent","_evt","items","item","escapeHtml","render","err","Error","message","onCleanup","destroy","handleExportJSON","graphFilenameStem","handleExportMermaid","handleExportPNG","dataUrl","toDataURL","canvas","querySelector","downloadDataUrl","_$createComponent","Show","when","fallback","_$getNextElement","_tmpl$5","children","_tmpl$4","ExpandableWrapper","title","copyData","copyLabel","_el$","_tmpl$3","_el$2","firstChild","_el$3","_el$5","nextSibling","_el$6","_co$","_$getNextMarker","_el$7","_el$10","_el$11","_co$3","$$click","v","_$insert","_el$4","_tmpl$","For","each","onClick","hint","_el$14","_tmpl$6","_el$15","_el$16","_$addEventListener","_$runHydrationEvents","_ref$","_$use","_el$8","_tmpl$2","_el$9","_el$0","_el$1","_co$2","_$effect","_p$","_v$","className","_v$2","_v$3","_v$4","width","height","_$className","t","_$setAttribute","o","_$style","base","res","fetch","c","_$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 { GraphComponentParams, GraphLayout, GraphNode, GraphEdge } from '@seed-ship/mcp-ui-spec'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\nimport { PortalDropdownMenu } from './PortalDropdownMenu'\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 `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.replace(/[\"[\\]|]/g, '').replace(/\\s+/g, ' ').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 = 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 [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 renderer: p.rendererPref === 'svg' ? 'svg' : 'canvas',\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 ? `<br><span style=\"font-size:11px;opacity:0.7\">${escapeHtml(data)}</span>` : ''\n }</div>`\n },\n },\n ]\n }\n graphInstance = new (Graph as any)(config)\n await graphInstance.render()\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to render graph')\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> 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 class={`relative w-full ${params().className ?? ''} ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\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 each={[\n { label: 'Download PNG', onClick: handleExportPNG, hint: 'visual snapshot' },\n { label: 'Download Mermaid', onClick: handleExportMermaid, hint: 'markdown / GitHub' },\n { label: 'Download JSON', onClick: handleExportJSON, hint: 'raw data' },\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 <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 isExpanded() ? 'flex-1 min-h-0' : ''\n }`}\n style={\n isExpanded()\n ? `height: 100%; width: ${params().width ?? '100%'};`\n : `height: ${params().height ?? '400px'}; width: ${params().width ?? '100%'};`\n }\n />\n <Show when={error()}>\n <p class=\"text-xs text-red-600 dark:text-red-400 mt-1\">Render error: {error()}</p>\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\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => {\n switch (c) {\n case '&': return '&'\n case '<': return '<'\n case '>': return '>'\n case '\"': return '"'\n case \"'\": return '''\n default: return c\n }\n })\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","available","setAvailable","createSignal","error","setError","exportMenuOpen","setExportMenuOpen","containerRef","exportTriggerRef","graphInstance","onMount","g6Available","Graph","p","config","container","data","renderer","rendererPref","fitView","autoFit","tooltip","plugins","getContent","_evt","items","item","escapeHtml","render","err","Error","message","onCleanup","destroy","handleExportJSON","graphFilenameStem","handleExportMermaid","handleExportPNG","dataUrl","toDataURL","canvas","querySelector","downloadDataUrl","_$createComponent","Show","when","fallback","_$getNextElement","_tmpl$4","children","_tmpl$3","ExpandableWrapper","title","copyData","copyLabel","toolbarVariant","_el$","_tmpl$2","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_co$","_$getNextMarker","_el$6","_el$1","_el$10","_co$3","$$click","v","_ref$","_$use","_$insert","PortalDropdownMenu","open","onClose","trigger","width","For","each","onClick","hint","_el$13","_tmpl$5","_el$14","_el$15","_$addEventListener","_$runHydrationEvents","_ref$2","_el$7","_tmpl$","_el$8","_el$9","_el$0","_co$2","_$effect","_p$","_v$","className","_v$2","_v$3","_v$4","height","_$className","t","_$setAttribute","o","_$style","base","res","fetch","c","_$delegateEvents"],"mappings":"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"}
|
|
@@ -33,8 +33,14 @@ export declare function isG6Available(): Promise<boolean>;
|
|
|
33
33
|
*/
|
|
34
34
|
declare function toMermaid(params: GraphComponentParams): string;
|
|
35
35
|
declare function toJSON(params: GraphComponentParams): string;
|
|
36
|
-
export
|
|
36
|
+
export interface GraphRendererProps {
|
|
37
37
|
component: UIComponent;
|
|
38
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).
|
|
40
|
+
* @see ExpandableWrapperProps.toolbarVariant
|
|
41
|
+
*/
|
|
42
|
+
toolbarVariant?: 'hover' | 'always-visible';
|
|
43
|
+
}
|
|
44
|
+
export declare const GraphRenderer: Component<GraphRendererProps>;
|
|
39
45
|
export { toMermaid as graphToMermaid, toJSON as graphToJSON };
|
|
40
46
|
//# sourceMappingURL=GraphRenderer.d.ts.map
|
|
@@ -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,CAAA;AACjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,KAAK,EAAE,oBAAoB,EAAqC,MAAM,wBAAwB,CAAA;
|
|
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,CAAA;AACjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,KAAK,EAAE,oBAAoB,EAAqC,MAAM,wBAAwB,CAAA;AAQrG;;;;;GAKG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAUtD;AAoDD;;;GAGG;AACH,iBAAS,SAAS,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAoBvD;AAED,iBAAS,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAEpD;AAcD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,WAAW,CAAA;IACtB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAA;CAC5C;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,kBAAkB,CAgMvD,CAAA;AA6BD,OAAO,EAAE,SAAS,IAAI,cAAc,EAAE,MAAM,IAAI,WAAW,EAAE,CAAA"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { delegateEvents, createComponent, getNextElement, template, getNextMarker, insert, addEventListener, runHydrationEvents, effect, className, setAttribute, style, use } from "solid-js/web";
|
|
2
2
|
import { createSignal, onMount, onCleanup, Show, For } from "solid-js";
|
|
3
3
|
import { useExpanded, ExpandableWrapper } from "./ExpandableWrapper.js";
|
|
4
|
-
|
|
4
|
+
import { PortalDropdownMenu } from "./PortalDropdownMenu.js";
|
|
5
|
+
var _tmpl$ = /* @__PURE__ */ template(`<p class="text-xs text-red-600 dark:text-red-400 mt-1">Render error: <!$><!/>`), _tmpl$2 = /* @__PURE__ */ 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"title="Export graph"aria-label="Export graph"aria-haspopup=menu>Export ▾</button><!$><!/></div><div></div><!$><!/>`), _tmpl$3 = /* @__PURE__ */ 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">Graph rendering unavailable</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$4 = /* @__PURE__ */ 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$5 = /* @__PURE__ */ 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">`);
|
|
5
6
|
let g6ModulePromise;
|
|
6
7
|
async function isG6Available() {
|
|
7
8
|
try {
|
|
@@ -95,6 +96,7 @@ const GraphRenderer = (props) => {
|
|
|
95
96
|
const [error, setError] = createSignal();
|
|
96
97
|
const [exportMenuOpen, setExportMenuOpen] = createSignal(false);
|
|
97
98
|
let containerRef;
|
|
99
|
+
let exportTriggerRef;
|
|
98
100
|
let graphInstance;
|
|
99
101
|
onMount(async () => {
|
|
100
102
|
const g6Available = await isG6Available();
|
|
@@ -184,11 +186,11 @@ const GraphRenderer = (props) => {
|
|
|
184
186
|
get fallback() {
|
|
185
187
|
return (
|
|
186
188
|
// Loading skeleton while we determine peer availability
|
|
187
|
-
getNextElement(_tmpl$
|
|
189
|
+
getNextElement(_tmpl$4)
|
|
188
190
|
);
|
|
189
191
|
},
|
|
190
192
|
get children() {
|
|
191
|
-
return getNextElement(_tmpl$
|
|
193
|
+
return getNextElement(_tmpl$3);
|
|
192
194
|
}
|
|
193
195
|
});
|
|
194
196
|
},
|
|
@@ -201,16 +203,24 @@ const GraphRenderer = (props) => {
|
|
|
201
203
|
return toJSON(params());
|
|
202
204
|
},
|
|
203
205
|
copyLabel: "Copy graph (JSON)",
|
|
206
|
+
get toolbarVariant() {
|
|
207
|
+
return props.toolbarVariant;
|
|
208
|
+
},
|
|
204
209
|
get children() {
|
|
205
|
-
var _el$ = getNextElement(_tmpl$
|
|
210
|
+
var _el$ = getNextElement(_tmpl$2), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, [_el$5, _co$] = getNextMarker(_el$4.nextSibling), _el$6 = _el$2.nextSibling, _el$1 = _el$6.nextSibling, [_el$10, _co$3] = getNextMarker(_el$1.nextSibling);
|
|
206
211
|
_el$3.$$click = () => setExportMenuOpen((v) => !v);
|
|
207
|
-
|
|
208
|
-
|
|
212
|
+
var _ref$ = exportTriggerRef;
|
|
213
|
+
typeof _ref$ === "function" ? use(_ref$, _el$3) : exportTriggerRef = _el$3;
|
|
214
|
+
insert(_el$2, createComponent(PortalDropdownMenu, {
|
|
215
|
+
get open() {
|
|
209
216
|
return exportMenuOpen();
|
|
210
217
|
},
|
|
218
|
+
onClose: () => setExportMenuOpen(false),
|
|
219
|
+
trigger: exportTriggerRef,
|
|
220
|
+
width: 176,
|
|
221
|
+
"class": "text-xs",
|
|
211
222
|
get children() {
|
|
212
|
-
|
|
213
|
-
insert(_el$4, createComponent(For, {
|
|
223
|
+
return createComponent(For, {
|
|
214
224
|
each: [{
|
|
215
225
|
label: "Download PNG",
|
|
216
226
|
onClick: handleExportPNG,
|
|
@@ -225,35 +235,34 @@ const GraphRenderer = (props) => {
|
|
|
225
235
|
hint: "raw data"
|
|
226
236
|
}],
|
|
227
237
|
children: (item) => (() => {
|
|
228
|
-
var _el$
|
|
229
|
-
addEventListener(_el$
|
|
230
|
-
insert(_el$
|
|
231
|
-
insert(_el$
|
|
238
|
+
var _el$13 = getNextElement(_tmpl$5), _el$14 = _el$13.firstChild, _el$15 = _el$14.nextSibling;
|
|
239
|
+
addEventListener(_el$13, "click", item.onClick, true);
|
|
240
|
+
insert(_el$14, () => item.label);
|
|
241
|
+
insert(_el$15, () => item.hint);
|
|
232
242
|
runHydrationEvents();
|
|
233
|
-
return _el$
|
|
243
|
+
return _el$13;
|
|
234
244
|
})()
|
|
235
|
-
})
|
|
236
|
-
return _el$4;
|
|
245
|
+
});
|
|
237
246
|
}
|
|
238
|
-
}), _el$
|
|
239
|
-
var _ref$ = containerRef;
|
|
240
|
-
typeof _ref$ === "function" ? use(_ref
|
|
247
|
+
}), _el$5, _co$);
|
|
248
|
+
var _ref$2 = containerRef;
|
|
249
|
+
typeof _ref$2 === "function" ? use(_ref$2, _el$6) : containerRef = _el$6;
|
|
241
250
|
insert(_el$, createComponent(Show, {
|
|
242
251
|
get when() {
|
|
243
252
|
return error();
|
|
244
253
|
},
|
|
245
254
|
get children() {
|
|
246
|
-
var _el$
|
|
247
|
-
insert(_el$
|
|
248
|
-
return _el$
|
|
255
|
+
var _el$7 = getNextElement(_tmpl$), _el$8 = _el$7.firstChild, _el$9 = _el$8.nextSibling, [_el$0, _co$2] = getNextMarker(_el$9.nextSibling);
|
|
256
|
+
insert(_el$7, error, _el$0, _co$2);
|
|
257
|
+
return _el$7;
|
|
249
258
|
}
|
|
250
|
-
}), _el$
|
|
259
|
+
}), _el$10, _co$3);
|
|
251
260
|
effect((_p$) => {
|
|
252
261
|
var _v$ = `relative w-full ${params().className ?? ""} ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$2 = exportMenuOpen(), _v$3 = `bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${isExpanded() ? "flex-1 min-h-0" : ""}`, _v$4 = isExpanded() ? `height: 100%; width: ${params().width ?? "100%"};` : `height: ${params().height ?? "400px"}; width: ${params().width ?? "100%"};`;
|
|
253
262
|
_v$ !== _p$.e && className(_el$, _p$.e = _v$);
|
|
254
263
|
_v$2 !== _p$.t && setAttribute(_el$3, "aria-expanded", _p$.t = _v$2);
|
|
255
|
-
_v$3 !== _p$.a && className(_el$
|
|
256
|
-
_p$.o = style(_el$
|
|
264
|
+
_v$3 !== _p$.a && className(_el$6, _p$.a = _v$3);
|
|
265
|
+
_p$.o = style(_el$6, _v$4, _p$.o);
|
|
257
266
|
return _p$;
|
|
258
267
|
}, {
|
|
259
268
|
e: void 0,
|