@seed-ship/mcp-ui-solid 6.22.0 → 6.24.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.
Files changed (120) hide show
  1. package/CHANGELOG.md +219 -0
  2. package/README.md +209 -2
  3. package/dist/components/ChartJSRenderer.cjs +192 -66
  4. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  5. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  6. package/dist/components/ChartJSRenderer.js +192 -66
  7. package/dist/components/ChartJSRenderer.js.map +1 -1
  8. package/dist/components/DegradedFallback.cjs +34 -2
  9. package/dist/components/DegradedFallback.cjs.map +1 -1
  10. package/dist/components/DegradedFallback.d.ts +7 -0
  11. package/dist/components/DegradedFallback.d.ts.map +1 -1
  12. package/dist/components/DegradedFallback.js +34 -2
  13. package/dist/components/DegradedFallback.js.map +1 -1
  14. package/dist/components/MissingValue.cjs +43 -0
  15. package/dist/components/MissingValue.cjs.map +1 -0
  16. package/dist/components/MissingValue.d.ts +27 -0
  17. package/dist/components/MissingValue.d.ts.map +1 -0
  18. package/dist/components/MissingValue.js +43 -0
  19. package/dist/components/MissingValue.js.map +1 -0
  20. package/dist/components/UIResourceRenderer.cjs +250 -202
  21. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  22. package/dist/components/UIResourceRenderer.d.ts +2 -1
  23. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  24. package/dist/components/UIResourceRenderer.js +250 -202
  25. package/dist/components/UIResourceRenderer.js.map +1 -1
  26. package/dist/components/chart-data-table.cjs +30 -5
  27. package/dist/components/chart-data-table.cjs.map +1 -1
  28. package/dist/components/chart-data-table.d.ts +18 -1
  29. package/dist/components/chart-data-table.d.ts.map +1 -1
  30. package/dist/components/chart-data-table.js +30 -5
  31. package/dist/components/chart-data-table.js.map +1 -1
  32. package/dist/components/chart-missing-plugin.cjs +194 -0
  33. package/dist/components/chart-missing-plugin.cjs.map +1 -0
  34. package/dist/components/chart-missing-plugin.d.ts +127 -0
  35. package/dist/components/chart-missing-plugin.d.ts.map +1 -0
  36. package/dist/components/chart-missing-plugin.js +194 -0
  37. package/dist/components/chart-missing-plugin.js.map +1 -0
  38. package/dist/context/MCPUIConfigContext.cjs.map +1 -1
  39. package/dist/context/MCPUIConfigContext.d.ts +57 -28
  40. package/dist/context/MCPUIConfigContext.d.ts.map +1 -1
  41. package/dist/context/MCPUIConfigContext.js.map +1 -1
  42. package/dist/context/MCPUIMathContext.cjs +19 -0
  43. package/dist/context/MCPUIMathContext.cjs.map +1 -0
  44. package/dist/context/MCPUIMathContext.d.ts +18 -0
  45. package/dist/context/MCPUIMathContext.d.ts.map +1 -0
  46. package/dist/context/MCPUIMathContext.js +19 -0
  47. package/dist/context/MCPUIMathContext.js.map +1 -0
  48. package/dist/context/MCPUIStringsContext.cjs +12 -1
  49. package/dist/context/MCPUIStringsContext.cjs.map +1 -1
  50. package/dist/context/MCPUIStringsContext.d.ts +62 -0
  51. package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
  52. package/dist/context/MCPUIStringsContext.js +12 -1
  53. package/dist/context/MCPUIStringsContext.js.map +1 -1
  54. package/dist/index.cjs +2 -0
  55. package/dist/index.cjs.map +1 -1
  56. package/dist/index.d.cts +3 -1
  57. package/dist/index.d.ts +3 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +2 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/plugins/katex.cjs +23 -0
  62. package/dist/plugins/katex.cjs.map +1 -0
  63. package/dist/plugins/katex.d.cts +7 -0
  64. package/dist/plugins/katex.d.ts +7 -0
  65. package/dist/plugins/katex.d.ts.map +1 -0
  66. package/dist/plugins/katex.js +23 -0
  67. package/dist/plugins/katex.js.map +1 -0
  68. package/dist/services/component-registry.cjs +9 -2
  69. package/dist/services/component-registry.cjs.map +1 -1
  70. package/dist/services/component-registry.d.ts.map +1 -1
  71. package/dist/services/component-registry.js +9 -2
  72. package/dist/services/component-registry.js.map +1 -1
  73. package/dist/services/validation.cjs +31 -8
  74. package/dist/services/validation.cjs.map +1 -1
  75. package/dist/services/validation.d.ts.map +1 -1
  76. package/dist/services/validation.js +31 -8
  77. package/dist/services/validation.js.map +1 -1
  78. package/dist/types/index.d.ts +14 -2
  79. package/dist/types/index.d.ts.map +1 -1
  80. package/dist/utils/degraded-projections.cjs +19 -3
  81. package/dist/utils/degraded-projections.cjs.map +1 -1
  82. package/dist/utils/degraded-projections.d.ts +22 -2
  83. package/dist/utils/degraded-projections.d.ts.map +1 -1
  84. package/dist/utils/degraded-projections.js +19 -3
  85. package/dist/utils/degraded-projections.js.map +1 -1
  86. package/dist/utils/iframe-coep.cjs.map +1 -1
  87. package/dist/utils/iframe-coep.d.ts +7 -6
  88. package/dist/utils/iframe-coep.d.ts.map +1 -1
  89. package/dist/utils/iframe-coep.js.map +1 -1
  90. package/dist/utils/math-markdown.cjs +240 -0
  91. package/dist/utils/math-markdown.cjs.map +1 -0
  92. package/dist/utils/math-markdown.d.ts +16 -0
  93. package/dist/utils/math-markdown.d.ts.map +1 -0
  94. package/dist/utils/math-markdown.js +240 -0
  95. package/dist/utils/math-markdown.js.map +1 -0
  96. package/dist/utils/missing-value.cjs +60 -0
  97. package/dist/utils/missing-value.cjs.map +1 -0
  98. package/dist/utils/missing-value.d.ts +79 -0
  99. package/dist/utils/missing-value.d.ts.map +1 -0
  100. package/dist/utils/missing-value.js +60 -0
  101. package/dist/utils/missing-value.js.map +1 -0
  102. package/package.json +23 -4
  103. package/src/components/ChartJSRenderer.tsx +159 -6
  104. package/src/components/DegradedFallback.tsx +24 -2
  105. package/src/components/MissingValue.tsx +61 -0
  106. package/src/components/UIResourceRenderer.tsx +64 -10
  107. package/src/components/chart-data-table.ts +50 -6
  108. package/src/components/chart-missing-plugin.ts +334 -0
  109. package/src/context/MCPUIConfigContext.tsx +57 -28
  110. package/src/context/MCPUIMathContext.tsx +32 -0
  111. package/src/context/MCPUIStringsContext.tsx +76 -0
  112. package/src/index.ts +4 -0
  113. package/src/plugins/katex.ts +25 -0
  114. package/src/services/component-registry.ts +10 -2
  115. package/src/services/validation.ts +44 -9
  116. package/src/types/index.ts +13 -1
  117. package/src/utils/degraded-projections.ts +44 -4
  118. package/src/utils/iframe-coep.ts +7 -6
  119. package/src/utils/math-markdown.ts +222 -0
  120. package/src/utils/missing-value.ts +127 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ChartJSRenderer.js","sources":["../../src/components/ChartJSRenderer.tsx"],"sourcesContent":["/**\n * ChartJSRenderer - Native Chart.js rendering\n * Sprint 4: State & Charts\n *\n * Requires chart.js peer dependency:\n * ```\n * pnpm add chart.js\n * ```\n *\n * Wheel-zoom / drag-pan / pinch (v6.22.0) need a SECOND optional peer, since a\n * canvas cannot be zoomed with a CSS transform without blurring:\n * ```\n * pnpm add chartjs-plugin-zoom\n * ```\n * Without it the chart renders exactly as it did before 6.22.0. Where zoom is\n * offered is the host's call — see `MCPUIConfig.chartZoom`, default\n * `'expanded'` (fullscreen modal only).\n */\n\nimport {\n Component,\n For,\n createEffect,\n createMemo,\n createUniqueId,\n onCleanup,\n createSignal,\n untrack,\n Show,\n} from 'solid-js';\nimport type { Accessor, JSX } from 'solid-js';\nimport type { UIComponent, ChartComponentParams } from '../types';\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper';\nimport { DegradedFallback } from './DegradedFallback';\nimport { chartToDataTable } from './chart-data-table';\nimport { useTelemetry } from '../context/MCPUITelemetryContext';\nimport { useMCPUIConfig } from '../context/MCPUIConfigContext';\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';\n\n// Lazy load Chart.js to avoid bundling if not used\nlet ChartJS: any = null;\nlet chartJSLoadPromise: Promise<any> | null = null;\n\nconst loadChartJS = async () => {\n if (ChartJS) return ChartJS;\n\n if (!chartJSLoadPromise) {\n chartJSLoadPromise = import('chart.js/auto')\n .then((module) => {\n ChartJS = module.default || module.Chart;\n return ChartJS;\n })\n .catch((err) => {\n chartJSLoadPromise = null;\n throw err;\n });\n }\n\n return chartJSLoadPromise;\n};\n\n/**\n * Check if Chart.js is available\n */\nexport async function isChartJSAvailable(): Promise<boolean> {\n try {\n await loadChartJS();\n return true;\n } catch {\n return false;\n }\n}\n\n// ─── Optional zoom peer (v6.22.0) ─────────────────────────────────────────\n//\n// A chart is a CANVAS, so the CSS-transform approach used by `createPanZoom`\n// for DOM surfaces would just magnify a bitmap into a blurry one. Real chart\n// zoom means re-projecting the scales, which only Chart.js itself can do —\n// hence `chartjs-plugin-zoom`, wired here as an OPTIONAL peer dependency\n// alongside `chart.js`, `leaflet` and `@antv/g6`. A host that does not install\n// it gets exactly the chart this renderer built before 6.22.0.\n\nlet zoomPluginPromise: Promise<unknown | null> | null = null;\nlet zoomPluginRegistered = false;\n\n/**\n * Import `chartjs-plugin-zoom` once, lazily.\n *\n * Resolves to `null` instead of rejecting when the peer is absent: an optional\n * dependency that is simply not installed is not an error condition, and the\n * caller must be able to fall through to the unzoomable chart without an error\n * state or console noise. The `null` is cached with the promise — a peer that\n * is missing now is still missing on the next chart, and retrying the import\n * per render would re-log the module-resolution failure every time.\n *\n * Only ever called from an effect, never at module scope or during render, so\n * SSR never reaches `hammerjs` (a plugin dependency that reads `document` as\n * it loads).\n *\n * `@vite-ignore` for the same reason `duckdb.ts` and `MapRenderer.tsx` carry\n * it on THEIR optional peers: this library is built with the peer externalised,\n * so the bare specifier survives into the published bundle and a consumer's\n * bundler resolves it statically — an app that never installed the plugin then\n * fails its own dependency scan at build time, long before the `.catch()`\n * below could turn the absence into the supported `null`. The four peers that\n * anyone using the feature at all has installed (`chart.js`, `leaflet`,\n * `@antv/g6`, `highlight.js`) stay bare on purpose: they benefit from the\n * pre-bundling this comment opts out of.\n */\nconst loadZoomPlugin = (): Promise<unknown | null> => {\n if (!zoomPluginPromise) {\n zoomPluginPromise = import(/* @vite-ignore */ 'chartjs-plugin-zoom')\n .then((module: any) => module.default ?? module)\n .catch(() => null);\n }\n\n return zoomPluginPromise;\n};\n\n/**\n * Load the plugin and register it on the Chart.js singleton, once per process.\n *\n * Registration is global and not undoable, which is precisely why it is\n * deferred to the first surface that actually asks for zoom\n * (`MCPUIConfig.chartZoom`): with the default `'expanded'`, a chart sitting\n * inline in a chat feed never even downloads the plugin.\n *\n * Chart.js only gives the plugin's hooks to charts constructed AFTER the\n * `register()` call, so the caller rebuilds its chart once this resolves.\n *\n * Resolves to `null` on EVERY failure and never rejects. Its one call site is\n * a fire-and-forget `.then()` inside an effect, with nowhere to put a rejection\n * handler that would mean anything to the host: `loadZoomPlugin()` already\n * swallows the missing optional peer, but `loadChartJS()` below rejects on a\n * host that installed neither, and that rejection would surface as an\n * unhandled one. The chart's own render effect reports the missing `chart.js`\n * through `onError` and the degraded table; zoom just quietly is not offered.\n */\nconst ensureZoomPlugin = async (): Promise<unknown | null> => {\n try {\n const plugin = await loadZoomPlugin();\n if (!plugin) return null;\n\n if (!zoomPluginRegistered) {\n const Chart: any = await loadChartJS();\n // A stubbed or partial Chart build may not expose `register`; treat that\n // like an absent peer. Returning the plugin here would be worse than\n // returning nothing: the renderer would hang zoom options off a chart\n // that has no zoom hooks, and paint a toolbar whose buttons do nothing.\n if (typeof Chart?.register !== 'function') return null;\n\n Chart.register(plugin);\n // Set only now that a registration has actually happened, so a later\n // call still gets its chance on a Chart build that does expose it.\n zoomPluginRegistered = true;\n }\n\n return plugin;\n } catch {\n return null;\n }\n};\n\n/**\n * Chart types whose axes zoom meaningfully.\n *\n * `pie`, `doughnut`, `polarArea` and `radar` carry no cartesian scales, so the\n * plugin would capture the wheel and move nothing — strictly worse than not\n * offering zoom at all.\n */\nconst ZOOMABLE_CHART_TYPES = new Set(['bar', 'line', 'scatter', 'bubble']);\n\n/**\n * Ratio one press of the chart's zoom buttons applies.\n *\n * The same 1.5 the lightbox uses for `+` / `-`: coarse enough that a couple of\n * presses get somewhere, fine enough to stop on a region of interest.\n */\nconst CHART_ZOOM_BUTTON_FACTOR = 1.5;\n\n/**\n * Whether a chart instance currently sits off its initial viewport.\n *\n * `isZoomedOrPanned()` is the plugin's own API (2.x). The `getZoomLevel()`\n * branch covers an older plugin build that only exposes the zoom factor, and\n * the `false` covers a chart created before the plugin was registered.\n */\nconst isChartZoomed = (chart: any): boolean => {\n if (typeof chart?.isZoomedOrPanned === 'function') return Boolean(chart.isZoomedOrPanned());\n const level = chart?.getZoomLevel?.();\n return typeof level === 'number' ? level !== 1 : false;\n};\n\n/** A JSON-ish object — the only shape a zoom option tree is ever built from. */\nconst isPlainZoomObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * Deep-merge this renderer's zoom block with the consumer's own.\n *\n * `ChartComponentParams.options` is the public Chart.js escape hatch, and\n * `plugins.zoom` is where a host tunes what this renderer cannot guess:\n * `limits`, wheel `speed`, a pan `modifierKey`, its own callbacks. Spreading\n * the renderer's block over it would silently drop the lot, so the two trees\n * are merged branch by branch (`zoom.wheel`, `zoom.pinch`, `zoom.drag`, `pan`,\n * `limits`, …).\n *\n * Two rules, both deliberate:\n * - on a plain value the CALLER wins — an explicit `mode: 'x'` is a more\n * specific instruction than this renderer's default `'xy'`;\n * - on a function both run, renderer first. The only functions the renderer\n * puts in that tree are `onZoom` / `onPan`, and they are what keeps the\n * reset control in sync with the viewport — letting a caller's callback\n * REPLACE them would leave the toolbar lying about the chart, so they are\n * composed instead.\n */\nconst mergeZoomOptions = (\n base: Record<string, unknown>,\n override: unknown\n): Record<string, unknown> => {\n if (!isPlainZoomObject(override)) return base;\n\n const merged: Record<string, unknown> = { ...base };\n\n for (const [key, value] of Object.entries(override)) {\n // An explicitly-undefined key is an OMISSION, not an instruction to erase.\n // A host forwarding an optional prop — `zoom: { onZoom: props.onZoom }`\n // with nothing passed — would otherwise delete the renderer's own hook,\n // which is exactly what keeps the reset control honest. This is also the\n // semantics `mergeProps` gives every other merge in this package.\n if (value === undefined) continue;\n\n const ours = merged[key];\n\n if (isPlainZoomObject(ours) && isPlainZoomObject(value)) {\n merged[key] = mergeZoomOptions(ours, value);\n } else if (typeof ours === 'function' && typeof value === 'function') {\n const rendererHook = ours as (...args: unknown[]) => unknown;\n const callerHook = value as (...args: unknown[]) => unknown;\n merged[key] = (...args: unknown[]) => {\n rendererHook(...args);\n return callerHook(...args);\n };\n } else {\n merged[key] = value;\n }\n }\n\n return merged;\n};\n\nexport interface ChartJSRendererProps {\n /**\n * UIComponent with chart params\n */\n component: UIComponent;\n\n /**\n * Error callback\n */\n onError?: (error: Error) => void;\n\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible';\n}\n\nconst ContextAwareChartLayout: Component<{\n render: (isExpanded: Accessor<boolean>) => JSX.Element;\n}> = (props) => props.render(useExpanded());\n\n/**\n * Native Chart.js renderer component\n *\n * @example\n * ```tsx\n * const chartComponent: UIComponent = {\n * id: 'revenue-chart',\n * type: 'chart',\n * position: { colStart: 1, colSpan: 6 },\n * params: {\n * type: 'bar',\n * title: 'Monthly Revenue',\n * data: {\n * labels: ['Jan', 'Feb', 'Mar'],\n * datasets: [{ label: 'Revenue', data: [100, 200, 150] }]\n * },\n * renderer: 'native',\n * },\n * }\n * <ChartJSRenderer component={chartComponent} />\n * ```\n */\nexport const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {\n const [isLoading, setIsLoading] = createSignal(true);\n const [error, setError] = createSignal<string>();\n const [activeView, setActiveView] = createSignal<'chart' | 'data'>('chart');\n // Reported by `<ExpandableWrapper onExpandedChange>` rather than read from\n // `useExpanded()`: this component IS the wrapper's owner, so its own\n // `useExpanded()` call sits above the wrapper's provider and would only ever\n // see an outer wrapper (see ExpandableWrapperProps.onExpandedChange).\n const [isExpanded, setIsExpanded] = createSignal(false);\n const [zoomPlugin, setZoomPlugin] = createSignal<unknown | null>(null);\n const [isZoomed, setIsZoomed] = createSignal(false);\n let canvasRef: HTMLCanvasElement | undefined;\n let chartInstance: any;\n let renderVersion = 0;\n\n const params = () => props.component.params as ChartComponentParams;\n const telemetry = useTelemetry();\n const config = useMCPUIConfig();\n const strings = useMCPUIStrings();\n // The accessible data table is a pure projection: its column headers come\n // from the chrome strings, injected rather than hardcoded in the helper.\n const tableData = createMemo(() =>\n chartToDataTable(params(), {\n series: strings.chartTableSeries,\n point: strings.chartTablePoint,\n label: strings.degradedColLabel,\n seriesName: strings.degradedSeries,\n })\n );\n const descriptionId = createUniqueId();\n const title = () => params().title || strings.chartView;\n\n // v6.1.0 — export visibility :\n // - undefined / true → button shown (new default, was opt-in)\n // - false → button hidden (explicit opt-out, unchanged)\n const exportEnabled = () => params().exportable !== false;\n\n // v6.1.0 — copy data for the ExpandableWrapper modal-header copy button.\n // Lazy-stringified each time the button is clicked.\n const copyDataJSON = () => JSON.stringify({ type: params().type, data: params().data }, null, 2);\n\n // ── Zoom / pan (v6.22.0) ───────────────────────────────────────────────\n\n /**\n * Whether this chart should be capturing the wheel right now: the host\n * policy (`MCPUIConfig.chartZoom`) crossed with the surface the chart\n * currently lives on, and with the chart type.\n *\n * `'expanded'` (the default) only says yes inside `ExpandableWrapper`'s\n * fullscreen modal — the one surface that owns its viewport. Inline, the\n * wheel belongs to the page the chart is scrolling in.\n */\n const zoomWanted = createMemo(() => {\n if (!ZOOMABLE_CHART_TYPES.has(params().type)) return false;\n // `false` (or `null`) on the host's own `plugins.zoom` is Chart.js's\n // documented per-chart plugin opt-out. It speaks about THIS chart, so it\n // beats the host-wide `chartZoom` policy — and gating here rather than at\n // the options merge keeps one source of truth, so the plugin is never even\n // downloaded and the toolbar never offers controls that would do nothing.\n const hostZoom = params().options?.plugins?.zoom;\n if (hostZoom === false || hostZoom === null) return false;\n const mode = config.chartZoom;\n if (mode === 'never') return false;\n if (mode === 'always') return true;\n return isExpanded();\n });\n\n // Download + register the plugin the first time a surface asks for zoom.\n // `zoomPlugin` is read untracked: setting it must not re-run this effect.\n createEffect(() => {\n if (!zoomWanted() || untrack(zoomPlugin)) return;\n void ensureZoomPlugin().then((plugin) => {\n if (plugin) setZoomPlugin(() => plugin);\n });\n });\n\n /**\n * The plugin's Chart.js options. Built once per renderer instance so that\n * `zoomOptions()` keeps a STABLE identity: a fresh object each read would\n * look like a config change and rebuild the chart on every update.\n */\n const zoomPluginOptions = {\n zoom: {\n wheel: { enabled: true },\n pinch: { enabled: true },\n // Drag is reserved for panning below; a drag-to-select zoom would make\n // the two gestures fight over the same mouse button.\n drag: { enabled: false },\n mode: 'xy',\n onZoom: ({ chart }: { chart: unknown }) => setIsZoomed(isChartZoomed(chart)),\n },\n pan: {\n enabled: true,\n mode: 'xy',\n onPan: ({ chart }: { chart: unknown }) => setIsZoomed(isChartZoomed(chart)),\n },\n };\n\n /**\n * The `plugins.zoom` block to merge into the chart config, or `null`.\n *\n * `null` while the peer is absent, which keeps the built config byte-for-byte\n * what it was before 6.22.0 — and, because the memo then never changes value,\n * also keeps expanding the modal from rebuilding the chart at all on a host\n * that did not install the plugin.\n */\n const zoomOptions = createMemo(() => (zoomWanted() && zoomPlugin() ? zoomPluginOptions : null));\n\n /**\n * Whether the zoom toolbar belongs on screen at all: the chart is zoomable\n * here (host policy × surface × chart type, and the peer actually loaded),\n * and the chart is what is currently being shown.\n */\n const zoomControlsShown = () =>\n Boolean(zoomOptions()) && activeView() === 'chart' && !error();\n\n /**\n * Zoom the chart by a fixed ratio, about its centre.\n *\n * Every gesture the plugin offers — wheel, drag-pan, pinch — is a POINTER\n * gesture, and the canvas is not focusable, so without these buttons the\n * whole feature is unreachable by keyboard, switch or voice (WCAG 2.1.1) —\n * including the reset control, which only exists once a gesture has already\n * moved the chart. The lightbox settled the same question the same way, with\n * persistent `+` / `-` controls next to its pointer gestures.\n *\n * `chart.zoom()` is `chartjs-plugin-zoom`'s own imperative API; the `?.`\n * covers a chart built before the plugin was registered. The plugin calls\n * `onZoom` itself, but the state is written here too so the reset control\n * appears even on a build whose hook does not fire for a programmatic zoom.\n */\n const handleZoomBy = (factor: number) => {\n chartInstance?.zoom?.(factor);\n setIsZoomed(isChartZoomed(chartInstance));\n };\n\n /** Back to the chart's initial viewport. */\n const handleResetZoom = () => {\n chartInstance?.resetZoom?.();\n setIsZoomed(false);\n };\n\n // Chart PNG export\n const handleExportPNG = () => {\n if (!canvasRef) return;\n const url = canvasRef.toDataURL('image/png');\n const a = document.createElement('a');\n a.href = url;\n a.download = `${(params().title || 'chart').replace(/\\s+/g, '-').toLowerCase()}.png`;\n a.click();\n };\n\n // Create/update chart when params change\n createEffect(async () => {\n if (!canvasRef) return;\n\n // Access params to track dependencies. `zoomOptions()` is read here, before\n // the first `await`, for the same reason: an async effect only tracks what\n // it reads synchronously, and toggling the expanded state has to rebuild\n // the chart rather than leave it on a stale config (Chart.js reads the\n // plugin options at construction and the plugin only hooks charts created\n // after it was registered).\n const chartParams = params();\n const zoom = zoomOptions();\n const version = ++renderVersion;\n\n setIsLoading(true);\n setError(undefined);\n\n try {\n const Chart = await loadChartJS();\n\n // A newer prop update or an unmount superseded this async render.\n if (version !== renderVersion || !canvasRef) return;\n\n // Destroy previous instance\n if (chartInstance) {\n chartInstance.destroy();\n chartInstance = null;\n }\n\n // Build options, merging time-axis config if present (v3.1.0)\n const hostZoomOptions = chartParams.options?.plugins?.zoom;\n const baseOptions: any = {\n responsive: true,\n maintainAspectRatio: false,\n ...chartParams.options,\n plugins: {\n ...chartParams.options?.plugins,\n legend: {\n display: true,\n position: 'bottom',\n ...chartParams.options?.plugins?.legend,\n },\n // Present only once the optional peer has loaded AND the current\n // surface wants zoom. Merged rather than assigned, so a consumer's\n // own `plugins.zoom` survives; when zoom is off, the spread above\n // has already left their block exactly as they wrote it.\n // An explicit `plugins.zoom: false` never reaches here: `zoomWanted`\n // already returned false for it, so `zoom` is null and the spread\n // above carries the host's own value through untouched.\n ...(zoom ? { zoom: mergeZoomOptions(zoom, hostZoomOptions) } : {}),\n },\n };\n\n // Time-series axis (v3.1.0)\n if (chartParams.timeAxis) {\n const ta = chartParams.timeAxis;\n baseOptions.scales = {\n ...baseOptions.scales,\n x: {\n ...baseOptions.scales?.x,\n type: 'time',\n time: {\n parser: ta.parser,\n unit: ta.unit,\n tooltipFormat: ta.tooltipFormat,\n },\n ...(ta.min ? { min: ta.min } : {}),\n ...(ta.max ? { max: ta.max } : {}),\n },\n };\n }\n\n // Create new chart\n chartInstance = new Chart(canvasRef, {\n type: chartParams.type,\n data: chartParams.data,\n options: baseOptions,\n });\n\n // A freshly built chart always sits on its initial viewport, so the\n // reset control goes away until the user zooms again.\n setIsZoomed(false);\n setIsLoading(false);\n } catch (err) {\n if (version !== renderVersion) return;\n const error = err instanceof Error ? err : new Error(strings.chartRenderError);\n setError(error.message);\n setIsLoading(false);\n // Fallback ladder (P2.5): record the failure so it's observable, then\n // degrade to the series table below instead of a blank canvas.\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: error.message,\n id: props.component?.id ?? '',\n componentType: 'chart',\n ts: Date.now(),\n });\n props.onError?.(error);\n }\n });\n\n // Chart.js may measure a zero-sized canvas while the data view is visible.\n // Resize once Solid has revealed it again.\n createEffect(() => {\n if (activeView() !== 'chart' || !chartInstance) return;\n queueMicrotask(() => chartInstance?.resize?.());\n });\n\n // Cleanup on unmount\n onCleanup(() => {\n renderVersion += 1;\n if (chartInstance) {\n chartInstance.destroy();\n chartInstance = null;\n }\n });\n\n return (\n <ExpandableWrapper\n title={title()}\n copyData={copyDataJSON()}\n copyLabel={strings.chartCopy}\n toolbarVariant={props.toolbarVariant}\n onExpandedChange={setIsExpanded}\n >\n <ContextAwareChartLayout\n render={(isExpanded) => (\n <div\n class={`relative w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden p-4 group ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n } ${params().className || ''}`}\n >\n <div class=\"flex items-center justify-between gap-3 mb-3 flex-shrink-0\">\n <div class=\"min-w-0\">\n <Show when={params().title}>\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params().title}</h3>\n </Show>\n </div>\n <div class=\"flex items-center gap-2\">\n <div\n class=\"inline-flex rounded-md border border-gray-200 p-0.5 dark:border-gray-600\"\n role=\"group\"\n aria-label={strings.chartViewSelector}\n >\n <button\n type=\"button\"\n aria-pressed={activeView() === 'chart'}\n class={`rounded px-2 py-1 text-xs font-medium transition-colors ${\n activeView() === 'chart'\n ? 'bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900'\n : 'text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'\n }`}\n onClick={() => setActiveView('chart')}\n >\n {strings.chartView}\n </button>\n <button\n type=\"button\"\n aria-pressed={activeView() === 'data'}\n class={`rounded px-2 py-1 text-xs font-medium transition-colors ${\n activeView() === 'data'\n ? 'bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900'\n : 'text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'\n }`}\n onClick={() => setActiveView('data')}\n >\n {strings.chartDataView}\n </button>\n </div>\n {/* Zoom controls — permanently visible (not hover-revealed like\n the export button) for as long as this chart is zoomable at\n all. Zoom in/out come FIRST and unconditionally: they are the\n only keyboard route into a feature whose gestures are all\n pointer gestures, on a canvas that takes no focus. Reset joins\n them only once the chart is actually off its initial viewport,\n so the toolbar stays quiet on a chart nobody moved. */}\n <Show when={zoomControlsShown()}>\n <div class=\"inline-flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleZoomBy(1 / CHART_ZOOM_BUTTON_FACTOR)}\n class=\"opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm\"\n title={strings.zoomOut}\n aria-label={strings.zoomOut}\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM13.5 10.5h-6\"\n />\n </svg>\n </button>\n\n <button\n type=\"button\"\n onClick={() => handleZoomBy(CHART_ZOOM_BUTTON_FACTOR)}\n class=\"opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm\"\n title={strings.zoomIn}\n aria-label={strings.zoomIn}\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM10.5 7.5v6m3-3h-6\"\n />\n </svg>\n </button>\n\n <Show when={isZoomed()}>\n <button\n type=\"button\"\n onClick={handleResetZoom}\n class=\"opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm\"\n title={strings.zoomReset}\n aria-label={strings.zoomReset}\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\"\n />\n </svg>\n </button>\n </Show>\n </div>\n </Show>\n <Show when={exportEnabled()}>\n <button\n type=\"button\"\n onClick={handleExportPNG}\n disabled={activeView() !== 'chart' || isLoading() || Boolean(error())}\n class=\"opacity-0 group-hover:opacity-60 hover:!opacity-100 disabled:!opacity-30 disabled:cursor-not-allowed px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm\"\n title={strings.chartDownloadPng}\n aria-label={strings.chartDownloadPngAria}\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n 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 />\n </svg>\n </button>\n </Show>\n </div>\n </div>\n\n <p id={descriptionId} class=\"sr-only\">\n {title()}. {strings.chartDataSummary}\n </p>\n\n {/* Fallback ladder (P2.5): degrade to a series table on render error\n instead of a bare \"Chart Error\" message. */}\n <Show when={error() && activeView() === 'chart'}>\n <DegradedFallback\n message={formatMCPUIString(strings.chartRenderFailed, { error: String(error()) })}\n caption={strings.chartDegradedCaption}\n {...tableData()}\n />\n </Show>\n\n <Show when={activeView() === 'data'}>\n <div\n class={`w-full overflow-auto rounded border border-gray-200 dark:border-gray-700 ${\n isExpanded() ? 'flex-1 min-h-0' : ''\n }`}\n style={\n isExpanded()\n ? undefined\n : { height: params().height || '250px', 'max-height': '70vh' }\n }\n >\n <table class=\"w-full border-collapse text-left text-sm\">\n <caption class=\"sr-only\">\n {title()} — {strings.chartDataTable}\n </caption>\n <thead class=\"bg-gray-50 dark:bg-gray-900/40\">\n <tr>\n <For each={tableData().columns}>\n {(column) => (\n <th scope=\"col\" class=\"px-3 py-2 font-medium text-gray-900 dark:text-gray-100\">\n {column}\n </th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={tableData().rows}>\n {(row) => (\n <tr class=\"border-t border-gray-100 dark:border-gray-700\">\n <For each={tableData().columns}>\n {(_column, index) => (\n <td class=\"px-3 py-2 text-gray-700 dark:text-gray-300\">\n {String(row[index()] ?? '')}\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n <Show when={tableData().rows.length === 0}>\n <tr>\n <td\n colSpan={Math.max(1, tableData().columns.length)}\n class=\"px-3 py-6 text-center text-gray-500 dark:text-gray-400\"\n >\n {strings.chartNoData}\n </td>\n </tr>\n </Show>\n </tbody>\n </table>\n </div>\n </Show>\n\n <div\n class={`relative w-full ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n style={\n error() || activeView() === 'data'\n ? { display: 'none' }\n : isExpanded()\n ? { height: '100%', display: 'block' }\n : { height: params().height || '250px', display: 'block' }\n }\n >\n <canvas\n ref={canvasRef}\n role=\"img\"\n aria-label={title()}\n aria-describedby={descriptionId}\n aria-hidden={activeView() !== 'chart' || Boolean(error())}\n />\n <Show when={isLoading() && activeView() === 'chart'}>\n <div class=\"absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80\">\n <div class=\"flex flex-col items-center gap-2\">\n <div class=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600\" />\n <span class=\"text-sm text-gray-500 dark:text-gray-400\">{strings.chartLoading}</span>\n </div>\n </div>\n </Show>\n </div>\n </div>\n )}\n />\n </ExpandableWrapper>\n );\n};\n"],"names":["ChartJS","chartJSLoadPromise","loadChartJS","then","module","default","Chart","catch","err","isChartJSAvailable","zoomPluginPromise","zoomPluginRegistered","loadZoomPlugin","ensureZoomPlugin","plugin","register","ZOOMABLE_CHART_TYPES","Set","CHART_ZOOM_BUTTON_FACTOR","isChartZoomed","chart","isZoomedOrPanned","Boolean","level","getZoomLevel","isPlainZoomObject","value","Array","isArray","mergeZoomOptions","base","override","merged","key","Object","entries","undefined","ours","rendererHook","callerHook","args","ContextAwareChartLayout","props","render","useExpanded","ChartJSRenderer","isLoading","setIsLoading","createSignal","error","setError","activeView","setActiveView","isExpanded","setIsExpanded","zoomPlugin","setZoomPlugin","isZoomed","setIsZoomed","canvasRef","chartInstance","renderVersion","params","component","telemetry","useTelemetry","config","useMCPUIConfig","strings","useMCPUIStrings","tableData","createMemo","chartToDataTable","series","chartTableSeries","point","chartTablePoint","label","degradedColLabel","seriesName","degradedSeries","descriptionId","createUniqueId","title","chartView","exportEnabled","exportable","copyDataJSON","JSON","stringify","type","data","zoomWanted","has","hostZoom","options","plugins","zoom","mode","chartZoom","createEffect","untrack","zoomPluginOptions","wheel","enabled","pinch","drag","onZoom","pan","onPan","zoomOptions","zoomControlsShown","handleZoomBy","factor","handleResetZoom","resetZoom","handleExportPNG","url","toDataURL","a","document","createElement","href","download","replace","toLowerCase","click","chartParams","version","destroy","hostZoomOptions","baseOptions","responsive","maintainAspectRatio","legend","display","position","timeAxis","ta","scales","x","time","parser","unit","tooltipFormat","min","max","Error","chartRenderError","message","dispatch","errorMessage","id","componentType","ts","Date","now","onError","queueMicrotask","resize","onCleanup","_$createComponent","ExpandableWrapper","copyData","copyLabel","chartCopy","toolbarVariant","onExpandedChange","children","_el$","_$getNextElement","_tmpl$8","_el$2","firstChild","_el$3","_el$5","nextSibling","_el$6","_el$7","_el$8","_el$14","_el$15","_co$2","_$getNextMarker","_el$16","_el$17","_co$3","_el$18","_el$20","_el$21","_co$4","_el$19","_el$22","_el$23","_co$5","_el$49","_el$50","_co$1","_el$51","_el$52","_co$10","_el$41","_el$42","_el$47","_el$48","_co$0","_$insert","Show","when","_el$4","_tmpl$","$$click","chartDataView","_el$9","_tmpl$3","_el$0","_el$1","_el$11","_el$12","_co$","_el$10","_tmpl$2","_$effect","_p$","_v$","zoomReset","_v$2","e","_$setAttribute","t","_$runHydrationEvents","_v$3","zoomOut","_v$4","_v$5","zoomIn","_v$6","o","_el$13","_tmpl$4","_v$7","_v$8","chartDownloadPng","_v$9","chartDownloadPngAria","_$setProperty","chartDataSummary","_$memo","DegradedFallback","_$mergeProps","formatMCPUIString","chartRenderFailed","String","caption","chartDegradedCaption","_el$24","_tmpl$6","_el$25","_el$26","_el$28","_el$29","_co$6","_el$27","_el$30","_el$31","_co$7","_el$32","_el$33","_el$34","_el$37","_el$38","_co$8","_el$39","_el$40","_co$9","chartDataTable","For","each","columns","column","_el$53","_tmpl$9","rows","row","_el$54","_tmpl$0","_column","index","_el$55","_tmpl$1","length","_el$35","_tmpl$5","_el$36","chartNoData","Math","_v$0","_v$1","height","_$className","_$style","_ref$","_$use","_el$43","_tmpl$7","_el$44","_el$45","_el$46","chartLoading","_v$10","className","_v$11","chartViewSelector","_v$12","_v$13","_v$14","_v$15","_v$16","_v$17","_v$18","_v$19","i","n","s","h","r","d","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"ChartJSRenderer.js","sources":["../../src/components/ChartJSRenderer.tsx"],"sourcesContent":["/**\n * ChartJSRenderer - Native Chart.js rendering\n * Sprint 4: State & Charts\n *\n * Requires chart.js peer dependency:\n * ```\n * pnpm add chart.js\n * ```\n *\n * Wheel-zoom / drag-pan / pinch (v6.22.0) need a SECOND optional peer, since a\n * canvas cannot be zoomed with a CSS transform without blurring:\n * ```\n * pnpm add chartjs-plugin-zoom\n * ```\n * Without it the chart renders exactly as it did before 6.22.0. Where zoom is\n * offered is the host's call — see `MCPUIConfig.chartZoom`, default\n * `'expanded'` (fullscreen modal only).\n */\n\nimport {\n Component,\n For,\n createEffect,\n createMemo,\n createUniqueId,\n onCleanup,\n createSignal,\n untrack,\n Show,\n} from 'solid-js';\nimport type { Accessor, JSX } from 'solid-js';\nimport type { UIComponent, ChartComponentParams } from '../types';\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper';\nimport { DegradedFallback } from './DegradedFallback';\nimport { MissingValueLegend, MissingValueMark } from './MissingValue';\nimport { chartToDataTable } from './chart-data-table';\nimport {\n applyUnitAxisTitle,\n createMissingLegendGenerator,\n createMissingValuesPlugin,\n createTooltipLabel,\n missingNoteKind,\n withDatasetsNoGapSpan,\n} from './chart-missing-plugin';\nimport { PART_TO_WHOLE_CHART_TYPES, summarizeChartMissing } from '../utils/missing-value';\nimport { useTelemetry } from '../context/MCPUITelemetryContext';\nimport { useMCPUIConfig } from '../context/MCPUIConfigContext';\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';\n\n// Lazy load Chart.js to avoid bundling if not used\nlet ChartJS: any = null;\nlet chartJSLoadPromise: Promise<any> | null = null;\n\nconst loadChartJS = async () => {\n if (ChartJS) return ChartJS;\n\n if (!chartJSLoadPromise) {\n chartJSLoadPromise = import('chart.js/auto')\n .then((module) => {\n ChartJS = module.default || module.Chart;\n return ChartJS;\n })\n .catch((err) => {\n chartJSLoadPromise = null;\n throw err;\n });\n }\n\n return chartJSLoadPromise;\n};\n\n/**\n * Check if Chart.js is available\n */\nexport async function isChartJSAvailable(): Promise<boolean> {\n try {\n await loadChartJS();\n return true;\n } catch {\n return false;\n }\n}\n\n// ─── Optional zoom peer (v6.22.0) ─────────────────────────────────────────\n//\n// A chart is a CANVAS, so the CSS-transform approach used by `createPanZoom`\n// for DOM surfaces would just magnify a bitmap into a blurry one. Real chart\n// zoom means re-projecting the scales, which only Chart.js itself can do —\n// hence `chartjs-plugin-zoom`, wired here as an OPTIONAL peer dependency\n// alongside `chart.js`, `leaflet` and `@antv/g6`. A host that does not install\n// it gets exactly the chart this renderer built before 6.22.0.\n\nlet zoomPluginPromise: Promise<unknown | null> | null = null;\nlet zoomPluginRegistered = false;\n\n/**\n * Import `chartjs-plugin-zoom` once, lazily.\n *\n * Resolves to `null` instead of rejecting when the peer is absent: an optional\n * dependency that is simply not installed is not an error condition, and the\n * caller must be able to fall through to the unzoomable chart without an error\n * state or console noise. The `null` is cached with the promise — a peer that\n * is missing now is still missing on the next chart, and retrying the import\n * per render would re-log the module-resolution failure every time.\n *\n * Only ever called from an effect, never at module scope or during render, so\n * SSR never reaches `hammerjs` (a plugin dependency that reads `document` as\n * it loads).\n *\n * `@vite-ignore` for the same reason `duckdb.ts` and `MapRenderer.tsx` carry\n * it on THEIR optional peers: this library is built with the peer externalised,\n * so the bare specifier survives into the published bundle and a consumer's\n * bundler resolves it statically — an app that never installed the plugin then\n * fails its own dependency scan at build time, long before the `.catch()`\n * below could turn the absence into the supported `null`. The four peers that\n * anyone using the feature at all has installed (`chart.js`, `leaflet`,\n * `@antv/g6`, `highlight.js`) stay bare on purpose: they benefit from the\n * pre-bundling this comment opts out of.\n */\nconst loadZoomPlugin = (): Promise<unknown | null> => {\n if (!zoomPluginPromise) {\n zoomPluginPromise = import(/* @vite-ignore */ 'chartjs-plugin-zoom')\n .then((module: any) => module.default ?? module)\n .catch(() => null);\n }\n\n return zoomPluginPromise;\n};\n\n/**\n * Load the plugin and register it on the Chart.js singleton, once per process.\n *\n * Registration is global and not undoable, which is precisely why it is\n * deferred to the first surface that actually asks for zoom\n * (`MCPUIConfig.chartZoom`): with the default `'expanded'`, a chart sitting\n * inline in a chat feed never even downloads the plugin.\n *\n * Chart.js only gives the plugin's hooks to charts constructed AFTER the\n * `register()` call, so the caller rebuilds its chart once this resolves.\n *\n * Resolves to `null` on EVERY failure and never rejects. Its one call site is\n * a fire-and-forget `.then()` inside an effect, with nowhere to put a rejection\n * handler that would mean anything to the host: `loadZoomPlugin()` already\n * swallows the missing optional peer, but `loadChartJS()` below rejects on a\n * host that installed neither, and that rejection would surface as an\n * unhandled one. The chart's own render effect reports the missing `chart.js`\n * through `onError` and the degraded table; zoom just quietly is not offered.\n */\nconst ensureZoomPlugin = async (): Promise<unknown | null> => {\n try {\n const plugin = await loadZoomPlugin();\n if (!plugin) return null;\n\n if (!zoomPluginRegistered) {\n const Chart: any = await loadChartJS();\n // A stubbed or partial Chart build may not expose `register`; treat that\n // like an absent peer. Returning the plugin here would be worse than\n // returning nothing: the renderer would hang zoom options off a chart\n // that has no zoom hooks, and paint a toolbar whose buttons do nothing.\n if (typeof Chart?.register !== 'function') return null;\n\n Chart.register(plugin);\n // Set only now that a registration has actually happened, so a later\n // call still gets its chance on a Chart build that does expose it.\n zoomPluginRegistered = true;\n }\n\n return plugin;\n } catch {\n return null;\n }\n};\n\n/**\n * Chart types whose axes zoom meaningfully.\n *\n * `pie`, `doughnut`, `polarArea` and `radar` carry no cartesian scales, so the\n * plugin would capture the wheel and move nothing — strictly worse than not\n * offering zoom at all.\n */\nconst ZOOMABLE_CHART_TYPES = new Set(['bar', 'line', 'scatter', 'bubble']);\n\n/**\n * Ratio one press of the chart's zoom buttons applies.\n *\n * The same 1.5 the lightbox uses for `+` / `-`: coarse enough that a couple of\n * presses get somewhere, fine enough to stop on a region of interest.\n */\nconst CHART_ZOOM_BUTTON_FACTOR = 1.5;\n\n/**\n * Whether a chart instance currently sits off its initial viewport.\n *\n * `isZoomedOrPanned()` is the plugin's own API (2.x). The `getZoomLevel()`\n * branch covers an older plugin build that only exposes the zoom factor, and\n * the `false` covers a chart created before the plugin was registered.\n */\nconst isChartZoomed = (chart: any): boolean => {\n if (typeof chart?.isZoomedOrPanned === 'function') return Boolean(chart.isZoomedOrPanned());\n const level = chart?.getZoomLevel?.();\n return typeof level === 'number' ? level !== 1 : false;\n};\n\n/** A JSON-ish object — the only shape a zoom option tree is ever built from. */\nconst isPlainZoomObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * Deep-merge this renderer's zoom block with the consumer's own.\n *\n * `ChartComponentParams.options` is the public Chart.js escape hatch, and\n * `plugins.zoom` is where a host tunes what this renderer cannot guess:\n * `limits`, wheel `speed`, a pan `modifierKey`, its own callbacks. Spreading\n * the renderer's block over it would silently drop the lot, so the two trees\n * are merged branch by branch (`zoom.wheel`, `zoom.pinch`, `zoom.drag`, `pan`,\n * `limits`, …).\n *\n * Two rules, both deliberate:\n * - on a plain value the CALLER wins — an explicit `mode: 'x'` is a more\n * specific instruction than this renderer's default `'xy'`;\n * - on a function both run, renderer first. The only functions the renderer\n * puts in that tree are `onZoom` / `onPan`, and they are what keeps the\n * reset control in sync with the viewport — letting a caller's callback\n * REPLACE them would leave the toolbar lying about the chart, so they are\n * composed instead.\n */\nconst mergeZoomOptions = (\n base: Record<string, unknown>,\n override: unknown\n): Record<string, unknown> => {\n if (!isPlainZoomObject(override)) return base;\n\n const merged: Record<string, unknown> = { ...base };\n\n for (const [key, value] of Object.entries(override)) {\n // An explicitly-undefined key is an OMISSION, not an instruction to erase.\n // A host forwarding an optional prop — `zoom: { onZoom: props.onZoom }`\n // with nothing passed — would otherwise delete the renderer's own hook,\n // which is exactly what keeps the reset control honest. This is also the\n // semantics `mergeProps` gives every other merge in this package.\n if (value === undefined) continue;\n\n const ours = merged[key];\n\n if (isPlainZoomObject(ours) && isPlainZoomObject(value)) {\n merged[key] = mergeZoomOptions(ours, value);\n } else if (typeof ours === 'function' && typeof value === 'function') {\n const rendererHook = ours as (...args: unknown[]) => unknown;\n const callerHook = value as (...args: unknown[]) => unknown;\n merged[key] = (...args: unknown[]) => {\n rendererHook(...args);\n return callerHook(...args);\n };\n } else {\n merged[key] = value;\n }\n }\n\n return merged;\n};\n\nexport interface ChartJSRendererProps {\n /**\n * UIComponent with chart params\n */\n component: UIComponent;\n\n /**\n * Error callback\n */\n onError?: (error: Error) => void;\n\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible';\n}\n\nconst ContextAwareChartLayout: Component<{\n render: (isExpanded: Accessor<boolean>) => JSX.Element;\n}> = (props) => props.render(useExpanded());\n\n/**\n * Native Chart.js renderer component\n *\n * @example\n * ```tsx\n * const chartComponent: UIComponent = {\n * id: 'revenue-chart',\n * type: 'chart',\n * position: { colStart: 1, colSpan: 6 },\n * params: {\n * type: 'bar',\n * title: 'Monthly Revenue',\n * data: {\n * labels: ['Jan', 'Feb', 'Mar'],\n * datasets: [{ label: 'Revenue', data: [100, 200, 150] }]\n * },\n * renderer: 'native',\n * },\n * }\n * <ChartJSRenderer component={chartComponent} />\n * ```\n */\nexport const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {\n const [isLoading, setIsLoading] = createSignal(true);\n const [error, setError] = createSignal<string>();\n const [activeView, setActiveView] = createSignal<'chart' | 'data'>('chart');\n // Reported by `<ExpandableWrapper onExpandedChange>` rather than read from\n // `useExpanded()`: this component IS the wrapper's owner, so its own\n // `useExpanded()` call sits above the wrapper's provider and would only ever\n // see an outer wrapper (see ExpandableWrapperProps.onExpandedChange).\n const [isExpanded, setIsExpanded] = createSignal(false);\n const [zoomPlugin, setZoomPlugin] = createSignal<unknown | null>(null);\n const [isZoomed, setIsZoomed] = createSignal(false);\n let canvasRef: HTMLCanvasElement | undefined;\n let chartInstance: any;\n let renderVersion = 0;\n\n const params = () => props.component.params as ChartComponentParams;\n const telemetry = useTelemetry();\n const config = useMCPUIConfig();\n const strings = useMCPUIStrings();\n // The accessible data table is a pure projection: its column headers come\n // from the chrome strings, injected rather than hardcoded in the helper.\n const tableData = createMemo(() =>\n chartToDataTable(params(), {\n series: strings.chartTableSeries,\n point: strings.chartTablePoint,\n label: strings.degradedColLabel,\n seriesName: strings.degradedSeries,\n withUnit: strings.chartLabelWithUnit,\n })\n );\n // Absence is never zero: which entries are missing, and which series have\n // nothing at all. Drives the notes, the plugin, the legend and the guard.\n const missingSummary = createMemo(() => summarizeChartMissing(params()));\n const unit = () => {\n const value = params().unit;\n return typeof value === 'string' && value !== '' ? value : undefined;\n };\n const anyMissingCell = () => tableData().missing.some((row) => row.some(Boolean));\n // Never for a part-to-whole chart: it refuses missing values outright (the\n // render effect turns it into the data table), so no convention applies —\n // and the async guard must not leave a wrong note in the SSR markup.\n const notesShown = () =>\n missingSummary().hasMissing &&\n !PART_TO_WHOLE_CHART_TYPES.has(params().type) &&\n activeView() === 'chart' &&\n !error();\n const noteKind = () => missingNoteKind(params().type, params().options);\n // The convention line explains a mark the reader can SEE: every missing bar\n // gets a dashed stub, but a line or a scatter only shows an absence inside a\n // series that still has values — a series with no value at all draws\n // nothing, and the \"no data\" line alone covers it.\n const conventionNoteShown = () =>\n noteKind() === 'bars'\n ? missingSummary().hasMissing\n : missingSummary().partiallyMissing.some(Boolean);\n // The series the chart has no data for, as a locale-aware list.\n const noDataSeries = () => {\n const names = (params().data?.datasets ?? [])\n .map((dataset, index) =>\n missingSummary().fullyMissing[index]\n ? dataset?.label || formatMCPUIString(strings.degradedSeries, { n: index + 1 })\n : null\n )\n .filter((name): name is string => name !== null);\n try {\n return new Intl.ListFormat(strings.locale, { type: 'conjunction' }).format(names);\n } catch {\n return names.join(', ');\n }\n };\n const descriptionId = createUniqueId();\n const notesId = createUniqueId();\n const title = () => params().title || strings.chartView;\n\n // v6.1.0 — export visibility :\n // - undefined / true → button shown (new default, was opt-in)\n // - false → button hidden (explicit opt-out, unchanged)\n const exportEnabled = () => params().exportable !== false;\n\n // v6.1.0 — copy data for the ExpandableWrapper modal-header copy button.\n // Lazy-stringified each time the button is clicked.\n const copyDataJSON = () => JSON.stringify({ type: params().type, data: params().data }, null, 2);\n\n // ── Zoom / pan (v6.22.0) ───────────────────────────────────────────────\n\n /**\n * Whether this chart should be capturing the wheel right now: the host\n * policy (`MCPUIConfig.chartZoom`) crossed with the surface the chart\n * currently lives on, and with the chart type.\n *\n * `'expanded'` (the default) only says yes inside `ExpandableWrapper`'s\n * fullscreen modal — the one surface that owns its viewport. Inline, the\n * wheel belongs to the page the chart is scrolling in.\n */\n const zoomWanted = createMemo(() => {\n if (!ZOOMABLE_CHART_TYPES.has(params().type)) return false;\n // `false` (or `null`) on the host's own `plugins.zoom` is Chart.js's\n // documented per-chart plugin opt-out. It speaks about THIS chart, so it\n // beats the host-wide `chartZoom` policy — and gating here rather than at\n // the options merge keeps one source of truth, so the plugin is never even\n // downloaded and the toolbar never offers controls that would do nothing.\n const hostZoom = params().options?.plugins?.zoom;\n if (hostZoom === false || hostZoom === null) return false;\n const mode = config.chartZoom;\n if (mode === 'never') return false;\n if (mode === 'always') return true;\n return isExpanded();\n });\n\n // Download + register the plugin the first time a surface asks for zoom.\n // `zoomPlugin` is read untracked: setting it must not re-run this effect.\n createEffect(() => {\n if (!zoomWanted() || untrack(zoomPlugin)) return;\n void ensureZoomPlugin().then((plugin) => {\n if (plugin) setZoomPlugin(() => plugin);\n });\n });\n\n /**\n * The plugin's Chart.js options. Built once per renderer instance so that\n * `zoomOptions()` keeps a STABLE identity: a fresh object each read would\n * look like a config change and rebuild the chart on every update.\n */\n const zoomPluginOptions = {\n zoom: {\n wheel: { enabled: true },\n pinch: { enabled: true },\n // Drag is reserved for panning below; a drag-to-select zoom would make\n // the two gestures fight over the same mouse button.\n drag: { enabled: false },\n mode: 'xy',\n onZoom: ({ chart }: { chart: unknown }) => setIsZoomed(isChartZoomed(chart)),\n },\n pan: {\n enabled: true,\n mode: 'xy',\n onPan: ({ chart }: { chart: unknown }) => setIsZoomed(isChartZoomed(chart)),\n },\n };\n\n /**\n * The `plugins.zoom` block to merge into the chart config, or `null`.\n *\n * `null` while the peer is absent, which keeps the built config byte-for-byte\n * what it was before 6.22.0 — and, because the memo then never changes value,\n * also keeps expanding the modal from rebuilding the chart at all on a host\n * that did not install the plugin.\n */\n const zoomOptions = createMemo(() => (zoomWanted() && zoomPlugin() ? zoomPluginOptions : null));\n\n /**\n * Whether the zoom toolbar belongs on screen at all: the chart is zoomable\n * here (host policy × surface × chart type, and the peer actually loaded),\n * and the chart is what is currently being shown.\n */\n const zoomControlsShown = () =>\n Boolean(zoomOptions()) && activeView() === 'chart' && !error();\n\n /**\n * Zoom the chart by a fixed ratio, about its centre.\n *\n * Every gesture the plugin offers — wheel, drag-pan, pinch — is a POINTER\n * gesture, and the canvas is not focusable, so without these buttons the\n * whole feature is unreachable by keyboard, switch or voice (WCAG 2.1.1) —\n * including the reset control, which only exists once a gesture has already\n * moved the chart. The lightbox settled the same question the same way, with\n * persistent `+` / `-` controls next to its pointer gestures.\n *\n * `chart.zoom()` is `chartjs-plugin-zoom`'s own imperative API; the `?.`\n * covers a chart built before the plugin was registered. The plugin calls\n * `onZoom` itself, but the state is written here too so the reset control\n * appears even on a build whose hook does not fire for a programmatic zoom.\n */\n const handleZoomBy = (factor: number) => {\n chartInstance?.zoom?.(factor);\n setIsZoomed(isChartZoomed(chartInstance));\n };\n\n /** Back to the chart's initial viewport. */\n const handleResetZoom = () => {\n chartInstance?.resetZoom?.();\n setIsZoomed(false);\n };\n\n // Chart PNG export\n const handleExportPNG = () => {\n if (!canvasRef) return;\n const url = canvasRef.toDataURL('image/png');\n const a = document.createElement('a');\n a.href = url;\n a.download = `${(params().title || 'chart').replace(/\\s+/g, '-').toLowerCase()}.png`;\n a.click();\n };\n\n // Create/update chart when params change\n createEffect(async () => {\n if (!canvasRef) return;\n\n // Access params to track dependencies. `zoomOptions()` is read here, before\n // the first `await`, for the same reason: an async effect only tracks what\n // it reads synchronously, and toggling the expanded state has to rebuild\n // the chart rather than leave it on a stale config (Chart.js reads the\n // plugin options at construction and the plugin only hooks charts created\n // after it was registered).\n const chartParams = params();\n const chartMissing = missingSummary();\n const chartUnit = unit();\n const zoom = zoomOptions();\n const version = ++renderVersion;\n\n setIsLoading(true);\n setError(undefined);\n\n try {\n const Chart = await loadChartJS();\n\n // A newer prop update or an unmount superseded this async render.\n if (version !== renderVersion || !canvasRef) return;\n\n // Destroy previous instance\n if (chartInstance) {\n chartInstance.destroy();\n chartInstance = null;\n }\n\n // A share of a whole cannot be missing: Chart.js parses `null` as 0 and\n // would draw it as a zero slice. Validation rejects this earlier; this\n // is the guard for a host that bypassed it. Thrown here so the catch\n // below shows the data table (with the missing cells marked).\n if (chartMissing.hasMissing && PART_TO_WHOLE_CHART_TYPES.has(chartParams.type)) {\n throw new Error(strings.chartMissingUnsupported);\n }\n\n // Build options, merging time-axis config if present (v3.1.0)\n const hostZoomOptions = chartParams.options?.plugins?.zoom;\n const baseOptions: any = {\n responsive: true,\n maintainAspectRatio: false,\n ...chartParams.options,\n plugins: {\n ...chartParams.options?.plugins,\n legend: {\n display: true,\n position: 'bottom',\n ...chartParams.options?.plugins?.legend,\n },\n // Present only once the optional peer has loaded AND the current\n // surface wants zoom. Merged rather than assigned, so a consumer's\n // own `plugins.zoom` survives; when zoom is off, the spread above\n // has already left their block exactly as they wrote it.\n // An explicit `plugins.zoom: false` never reaches here: `zoomWanted`\n // already returned false for it, so `zoom` is null and the spread\n // above carries the host's own value through untouched.\n ...(zoom ? { zoom: mergeZoomOptions(zoom, hostZoomOptions) } : {}),\n },\n };\n\n // Time-series axis (v3.1.0)\n if (chartParams.timeAxis) {\n const ta = chartParams.timeAxis;\n baseOptions.scales = {\n ...baseOptions.scales,\n x: {\n ...baseOptions.scales?.x,\n type: 'time',\n time: {\n parser: ta.parser,\n unit: ta.unit,\n tooltipFormat: ta.tooltipFormat,\n },\n ...(ta.min ? { min: ta.min } : {}),\n ...(ta.max ? { max: ta.max } : {}),\n },\n };\n }\n\n // Unit (v6.24.0): value-axis title and tooltip suffix. Both are no-ops\n // on a payload without a unit.\n applyUnitAxisTitle(baseOptions, chartParams.type, chartUnit);\n\n const chartConfig: any = {\n type: chartParams.type,\n data: chartParams.data,\n options: baseOptions,\n };\n\n if (chartUnit !== undefined || chartMissing.hasMissing) {\n const tooltip = baseOptions.plugins.tooltip;\n // `tooltip: false` (or `null`) is Chart.js's per-chart plugin opt-out:\n // the payload turned tooltips off, and adding a callback object here\n // would turn them back on. A host-supplied label callback is the\n // host's word too. Both are left exactly as written.\n if (tooltip !== false && tooltip !== null && !tooltip?.callbacks?.label) {\n baseOptions.plugins.tooltip = {\n ...tooltip,\n callbacks: {\n ...tooltip?.callbacks,\n label: createTooltipLabel(() => strings, chartUnit, chartParams.type),\n },\n };\n }\n }\n\n if (chartMissing.hasMissing) {\n // A line must break at a missing value, not join its neighbours.\n chartConfig.data = withDatasetsNoGapSpan(chartParams.data);\n\n // Legend of a fully-missing series: \"{series} (no data)\". Dataset\n // legends only — pie-like legends list categories, not series.\n const defaultGenerate =\n baseOptions.plugins.legend?.labels?.generateLabels ??\n Chart?.defaults?.plugins?.legend?.labels?.generateLabels;\n if (typeof defaultGenerate === 'function') {\n baseOptions.plugins.legend = {\n ...baseOptions.plugins.legend,\n labels: {\n ...baseOptions.plugins.legend?.labels,\n generateLabels: createMissingLegendGenerator(\n defaultGenerate,\n chartMissing.fullyMissing,\n () => strings\n ),\n },\n };\n }\n\n // Per-chart plugin (never `Chart.register`): the dashed stub of a\n // missing bar, and \"no data\" on a chart with nothing to plot.\n chartConfig.plugins = [\n createMissingValuesPlugin({\n allMissing: chartMissing.allMissing,\n getNoDataText: () => strings.chartNoData,\n getFontFamily: () => Chart?.defaults?.font?.family,\n }),\n ];\n }\n\n // Create new chart\n chartInstance = new Chart(canvasRef, chartConfig);\n\n // A freshly built chart always sits on its initial viewport, so the\n // reset control goes away until the user zooms again.\n setIsZoomed(false);\n setIsLoading(false);\n } catch (err) {\n if (version !== renderVersion) return;\n const error = err instanceof Error ? err : new Error(strings.chartRenderError);\n setError(error.message);\n setIsLoading(false);\n // Fallback ladder (P2.5): record the failure so it's observable, then\n // degrade to the series table below instead of a blank canvas.\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: error.message,\n id: props.component?.id ?? '',\n componentType: 'chart',\n ts: Date.now(),\n });\n props.onError?.(error);\n }\n });\n\n // Chart.js may measure a zero-sized canvas while the data view is visible.\n // Resize once Solid has revealed it again.\n createEffect(() => {\n if (activeView() !== 'chart' || !chartInstance) return;\n queueMicrotask(() => chartInstance?.resize?.());\n });\n\n // Cleanup on unmount\n onCleanup(() => {\n renderVersion += 1;\n if (chartInstance) {\n chartInstance.destroy();\n chartInstance = null;\n }\n });\n\n return (\n <ExpandableWrapper\n title={title()}\n copyData={copyDataJSON()}\n copyLabel={strings.chartCopy}\n toolbarVariant={props.toolbarVariant}\n onExpandedChange={setIsExpanded}\n >\n <ContextAwareChartLayout\n render={(isExpanded) => (\n <div\n class={`relative w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden p-4 group ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n } ${params().className || ''}`}\n >\n <div class=\"flex items-center justify-between gap-3 mb-3 flex-shrink-0\">\n <div class=\"min-w-0\">\n <Show when={params().title}>\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params().title}</h3>\n </Show>\n </div>\n <div class=\"flex items-center gap-2\">\n <div\n class=\"inline-flex rounded-md border border-gray-200 p-0.5 dark:border-gray-600\"\n role=\"group\"\n aria-label={strings.chartViewSelector}\n >\n <button\n type=\"button\"\n aria-pressed={activeView() === 'chart'}\n class={`rounded px-2 py-1 text-xs font-medium transition-colors ${\n activeView() === 'chart'\n ? 'bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900'\n : 'text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'\n }`}\n onClick={() => setActiveView('chart')}\n >\n {strings.chartView}\n </button>\n <button\n type=\"button\"\n aria-pressed={activeView() === 'data'}\n class={`rounded px-2 py-1 text-xs font-medium transition-colors ${\n activeView() === 'data'\n ? 'bg-gray-900 text-white dark:bg-gray-100 dark:text-gray-900'\n : 'text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'\n }`}\n onClick={() => setActiveView('data')}\n >\n {strings.chartDataView}\n </button>\n </div>\n {/* Zoom controls — permanently visible (not hover-revealed like\n the export button) for as long as this chart is zoomable at\n all. Zoom in/out come FIRST and unconditionally: they are the\n only keyboard route into a feature whose gestures are all\n pointer gestures, on a canvas that takes no focus. Reset joins\n them only once the chart is actually off its initial viewport,\n so the toolbar stays quiet on a chart nobody moved. */}\n <Show when={zoomControlsShown()}>\n <div class=\"inline-flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleZoomBy(1 / CHART_ZOOM_BUTTON_FACTOR)}\n class=\"opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm\"\n title={strings.zoomOut}\n aria-label={strings.zoomOut}\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM13.5 10.5h-6\"\n />\n </svg>\n </button>\n\n <button\n type=\"button\"\n onClick={() => handleZoomBy(CHART_ZOOM_BUTTON_FACTOR)}\n class=\"opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm\"\n title={strings.zoomIn}\n aria-label={strings.zoomIn}\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM10.5 7.5v6m3-3h-6\"\n />\n </svg>\n </button>\n\n <Show when={isZoomed()}>\n <button\n type=\"button\"\n onClick={handleResetZoom}\n class=\"opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm\"\n title={strings.zoomReset}\n aria-label={strings.zoomReset}\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\"\n />\n </svg>\n </button>\n </Show>\n </div>\n </Show>\n <Show when={exportEnabled()}>\n <button\n type=\"button\"\n onClick={handleExportPNG}\n disabled={activeView() !== 'chart' || isLoading() || Boolean(error())}\n class=\"opacity-0 group-hover:opacity-60 hover:!opacity-100 disabled:!opacity-30 disabled:cursor-not-allowed px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm\"\n title={strings.chartDownloadPng}\n aria-label={strings.chartDownloadPngAria}\n >\n <svg\n class=\"w-3 h-3 text-gray-500 dark:text-gray-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n 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 />\n </svg>\n </button>\n </Show>\n </div>\n </div>\n\n <p id={descriptionId} class=\"sr-only\">\n {title()}. {strings.chartDataSummary}\n </p>\n\n {/* Fallback ladder (P2.5): degrade to a series table on render error\n instead of a bare \"Chart Error\" message. */}\n <Show when={error() && activeView() === 'chart'}>\n <DegradedFallback\n message={formatMCPUIString(strings.chartRenderFailed, { error: String(error()) })}\n caption={strings.chartDegradedCaption}\n {...tableData()}\n />\n </Show>\n\n <Show when={activeView() === 'data'}>\n <div\n class={`w-full overflow-auto rounded border border-gray-200 dark:border-gray-700 ${\n isExpanded() ? 'flex-1 min-h-0' : ''\n }`}\n style={\n isExpanded()\n ? undefined\n : { height: params().height || '250px', 'max-height': '70vh' }\n }\n >\n <table class=\"w-full border-collapse text-left text-sm\">\n <caption class=\"sr-only\">\n {title()} — {strings.chartDataTable}\n </caption>\n <thead class=\"bg-gray-50 dark:bg-gray-900/40\">\n <tr>\n <For each={tableData().columns}>\n {(column) => (\n <th scope=\"col\" class=\"px-3 py-2 font-medium text-gray-900 dark:text-gray-100\">\n {column}\n </th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={tableData().rows}>\n {(row, rowIndex) => (\n <tr class=\"border-t border-gray-100 dark:border-gray-700\">\n <For each={tableData().columns}>\n {(_column, index) => (\n <td class=\"px-3 py-2 text-gray-700 dark:text-gray-300\">\n <Show\n when={tableData().missing[rowIndex()]?.[index()]}\n fallback={String(row[index()] ?? '')}\n >\n <MissingValueMark />\n </Show>\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n <Show when={tableData().rows.length === 0}>\n <tr>\n <td\n colSpan={Math.max(1, tableData().columns.length)}\n class=\"px-3 py-6 text-center text-gray-500 dark:text-gray-400\"\n >\n {strings.chartNoData}\n </td>\n </tr>\n </Show>\n </tbody>\n </table>\n </div>\n <Show when={anyMissingCell()}>\n <MissingValueLegend class=\"mt-2\" />\n </Show>\n </Show>\n\n <div\n class={`relative w-full ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n style={\n error() || activeView() === 'data'\n ? { display: 'none' }\n : isExpanded()\n ? { height: '100%', display: 'block' }\n : { height: params().height || '250px', display: 'block' }\n }\n >\n <canvas\n ref={canvasRef}\n role=\"img\"\n aria-label={title()}\n aria-describedby={notesShown() ? `${descriptionId} ${notesId}` : descriptionId}\n aria-hidden={activeView() !== 'chart' || Boolean(error())}\n />\n <Show when={isLoading() && activeView() === 'chart'}>\n <div class=\"absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80\">\n <div class=\"flex flex-col items-center gap-2\">\n <div class=\"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600\" />\n <span class=\"text-sm text-gray-500 dark:text-gray-400\">{strings.chartLoading}</span>\n </div>\n </div>\n </Show>\n </div>\n\n {/* Missing values (v6.24.0): how THIS chart type shows them, and which\n series have no data at all. Linked from the canvas, so a screen\n reader hears the convention with the chart. */}\n <Show when={notesShown()}>\n <div\n data-mcp-chart-notes=\"\"\n id={notesId}\n class=\"mt-2 space-y-0.5 text-xs text-gray-600 dark:text-gray-400\"\n >\n <Show when={conventionNoteShown()}>\n <p data-mcp-chart-note={noteKind()}>\n {noteKind() === 'bars'\n ? strings.chartMissingBars\n : noteKind() === 'omitted'\n ? strings.chartMissingPoints\n : strings.chartMissingGaps}\n </p>\n </Show>\n <Show when={missingSummary().fullyMissing.some(Boolean)}>\n <p data-mcp-chart-note=\"no-data\">\n {formatMCPUIString(strings.chartSeriesNoData, { series: noDataSeries() })}\n </p>\n </Show>\n </div>\n </Show>\n </div>\n )}\n />\n </ExpandableWrapper>\n );\n};\n"],"names":["ChartJS","chartJSLoadPromise","loadChartJS","then","module","default","Chart","catch","err","isChartJSAvailable","zoomPluginPromise","zoomPluginRegistered","loadZoomPlugin","ensureZoomPlugin","plugin","register","ZOOMABLE_CHART_TYPES","Set","CHART_ZOOM_BUTTON_FACTOR","isChartZoomed","chart","isZoomedOrPanned","Boolean","level","getZoomLevel","isPlainZoomObject","value","Array","isArray","mergeZoomOptions","base","override","merged","key","Object","entries","undefined","ours","rendererHook","callerHook","args","ContextAwareChartLayout","props","render","useExpanded","ChartJSRenderer","isLoading","setIsLoading","createSignal","error","setError","activeView","setActiveView","isExpanded","setIsExpanded","zoomPlugin","setZoomPlugin","isZoomed","setIsZoomed","canvasRef","chartInstance","renderVersion","params","component","telemetry","useTelemetry","config","useMCPUIConfig","strings","useMCPUIStrings","tableData","createMemo","chartToDataTable","series","chartTableSeries","point","chartTablePoint","label","degradedColLabel","seriesName","degradedSeries","withUnit","chartLabelWithUnit","missingSummary","summarizeChartMissing","unit","anyMissingCell","missing","some","row","notesShown","hasMissing","PART_TO_WHOLE_CHART_TYPES","has","type","noteKind","missingNoteKind","options","conventionNoteShown","partiallyMissing","noDataSeries","names","data","datasets","map","dataset","index","fullyMissing","formatMCPUIString","n","filter","name","Intl","ListFormat","locale","format","join","descriptionId","createUniqueId","notesId","title","chartView","exportEnabled","exportable","copyDataJSON","JSON","stringify","zoomWanted","hostZoom","plugins","zoom","mode","chartZoom","createEffect","untrack","zoomPluginOptions","wheel","enabled","pinch","drag","onZoom","pan","onPan","zoomOptions","zoomControlsShown","handleZoomBy","factor","handleResetZoom","resetZoom","handleExportPNG","url","toDataURL","a","document","createElement","href","download","replace","toLowerCase","click","chartParams","chartMissing","chartUnit","version","destroy","Error","chartMissingUnsupported","hostZoomOptions","baseOptions","responsive","maintainAspectRatio","legend","display","position","timeAxis","ta","scales","x","time","parser","tooltipFormat","min","max","applyUnitAxisTitle","chartConfig","tooltip","callbacks","createTooltipLabel","withDatasetsNoGapSpan","defaultGenerate","labels","generateLabels","defaults","createMissingLegendGenerator","createMissingValuesPlugin","allMissing","getNoDataText","chartNoData","getFontFamily","font","family","chartRenderError","message","dispatch","errorMessage","id","componentType","ts","Date","now","onError","queueMicrotask","resize","onCleanup","_$createComponent","ExpandableWrapper","copyData","copyLabel","chartCopy","toolbarVariant","onExpandedChange","children","_el$","_$getNextElement","_tmpl$1","_el$2","firstChild","_el$3","_el$5","nextSibling","_el$6","_el$7","_el$8","_el$14","_el$15","_co$2","_$getNextMarker","_el$16","_el$17","_co$3","_el$18","_el$20","_el$21","_co$4","_el$19","_el$22","_el$23","_co$5","_el$56","_el$57","_co$11","_el$58","_el$59","_co$12","_el$41","_el$42","_el$47","_el$48","_co$0","_el$60","_el$61","_co$13","_$insert","Show","when","_el$4","_tmpl$","$$click","chartDataView","_el$9","_tmpl$3","_el$0","_el$1","_el$11","_el$12","_co$","_el$10","_tmpl$2","_$effect","_p$","_v$","zoomReset","_v$2","e","_$setAttribute","t","_$runHydrationEvents","_v$3","zoomOut","_v$4","_v$5","zoomIn","_v$6","o","_el$13","_tmpl$4","_v$7","_v$8","chartDownloadPng","_v$9","chartDownloadPngAria","_$setProperty","chartDataSummary","_$memo","DegradedFallback","_$mergeProps","chartRenderFailed","String","caption","chartDegradedCaption","_el$24","_tmpl$6","_el$25","_el$26","_el$28","_el$29","_co$6","_el$27","_el$30","_el$31","_co$7","_el$32","_el$33","_el$34","_el$37","_el$38","_co$8","_el$39","_el$40","_co$9","chartDataTable","For","each","columns","column","_el$62","_tmpl$10","rows","rowIndex","_el$63","_tmpl$11","_column","_el$64","_tmpl$12","fallback","MissingValueMark","length","_el$35","_tmpl$5","_el$36","Math","_v$0","_v$1","height","_$className","_$style","MissingValueLegend","_ref$","_$use","_el$43","_tmpl$7","_el$44","_el$45","_el$46","chartLoading","_el$49","_tmpl$0","_el$52","_el$53","_co$1","_el$54","_el$55","_co$10","_el$50","_tmpl$8","_c$","chartMissingBars","chartMissingPoints","chartMissingGaps","_el$51","_tmpl$9","chartSeriesNoData","_v$10","className","_v$11","chartViewSelector","_v$12","_v$13","_v$14","_v$15","_v$16","_v$17","_v$18","_v$19","_v$20","i","s","h","r","d","l","_$delegateEvents"],"mappings":"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"}
@@ -3,6 +3,7 @@ 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 MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
6
+ const MissingValue = require("./MissingValue.cjs");
6
7
  const formatString = require("../utils/format-string.cjs");
7
8
  var _tmpl$ = /* @__PURE__ */ web.template(`<div class="mt-2 max-h-64 overflow-auto rounded border border-amber-200 dark:border-amber-800"><table class="w-full border-collapse text-left text-xs"><thead class="sticky top-0 bg-amber-100 dark:bg-amber-900/40"><tr></tr></thead><tbody>`), _tmpl$2 = /* @__PURE__ */ web.template(`<p class="mt-1 text-[10px] text-amber-600 dark:text-amber-400">`), _tmpl$3 = /* @__PURE__ */ web.template(`<div class="w-full rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-800 dark:bg-amber-900/20"role=alert><p class="text-sm font-medium text-amber-900 dark:text-amber-100"></p><p class="mt-0.5 text-xs text-amber-700 dark:text-amber-300"></p><!$><!/>`), _tmpl$4 = /* @__PURE__ */ web.template(`<th class="px-2 py-1 font-medium text-amber-900 dark:text-amber-100">`), _tmpl$5 = /* @__PURE__ */ web.template(`<tr class="border-t border-amber-100 dark:border-amber-800/60">`), _tmpl$6 = /* @__PURE__ */ web.template(`<td class="px-2 py-1 text-amber-800 dark:text-amber-200">`);
8
9
  const DegradedFallback = (props) => {
@@ -11,6 +12,18 @@ const DegradedFallback = (props) => {
11
12
  const allRows = () => props.rows ?? [];
12
13
  const shownRows = () => allRows().slice(0, maxRows());
13
14
  const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);
15
+ const isMissing = (rowIndex, colIndex) => {
16
+ var _a, _b;
17
+ return ((_b = (_a = props.missing) == null ? void 0 : _a[rowIndex]) == null ? void 0 : _b[colIndex]) === true;
18
+ };
19
+ const anyShownMissing = () => {
20
+ var _a;
21
+ const columnCount = ((_a = props.columns) == null ? void 0 : _a.length) ?? 0;
22
+ return shownRows().some((_row, r) => {
23
+ for (let c = 0; c < columnCount; c += 1) if (isMissing(r, c)) return true;
24
+ return false;
25
+ });
26
+ };
14
27
  const hasTable = () => {
15
28
  var _a;
16
29
  return (((_a = props.columns) == null ? void 0 : _a.length) ?? 0) > 0 && allRows().length > 0;
@@ -40,7 +53,7 @@ const DegradedFallback = (props) => {
40
53
  get each() {
41
54
  return shownRows();
42
55
  },
43
- children: (row) => (() => {
56
+ children: (row, rowIndex) => (() => {
44
57
  var _el$11 = web.getNextElement(_tmpl$5);
45
58
  web.insert(_el$11, web.createComponent(solidJs.For, {
46
59
  get each() {
@@ -48,7 +61,17 @@ const DegradedFallback = (props) => {
48
61
  },
49
62
  children: (_col, i) => (() => {
50
63
  var _el$12 = web.getNextElement(_tmpl$6);
51
- web.insert(_el$12, () => String(row[i()] ?? ""));
64
+ web.insert(_el$12, web.createComponent(solidJs.Show, {
65
+ get when() {
66
+ return isMissing(rowIndex(), i());
67
+ },
68
+ get fallback() {
69
+ return String(row[i()] ?? "");
70
+ },
71
+ get children() {
72
+ return web.createComponent(MissingValue.MissingValueMark, {});
73
+ }
74
+ }));
52
75
  return _el$12;
53
76
  })()
54
77
  }));
@@ -57,6 +80,15 @@ const DegradedFallback = (props) => {
57
80
  }));
58
81
  return _el$4;
59
82
  })(), web.createComponent(solidJs.Show, {
83
+ get when() {
84
+ return anyShownMissing();
85
+ },
86
+ get children() {
87
+ return web.createComponent(MissingValue.MissingValueLegend, {
88
+ "class": "mt-2"
89
+ });
90
+ }
91
+ }), web.createComponent(solidJs.Show, {
60
92
  get when() {
61
93
  return hiddenCount() > 0;
62
94
  },
@@ -1 +1 @@
1
- {"version":3,"file":"DegradedFallback.cjs","sources":["../../src/components/DegradedFallback.tsx"],"sourcesContent":["/**\n * DegradedFallback — the middle rung of the renderer fallback ladder\n * (audit 2026-05-30, P2.5).\n *\n * Each heavy renderer (graph / map / chart) follows the same contract:\n * 1. native render when its peer lib is available and succeeds;\n * 2. **degraded but useful** view when the native render throws — this\n * component: a visible notice + a plain data table so the user still\n * sees the underlying data instead of a blank space;\n * 3. (the caller also emits a `render:error` telemetry event).\n *\n * Pure / presentational — no peer deps, no side effects — so a render-path\n * failure in a heavy lib can never cascade into the fallback itself, and it\n * is trivially unit-testable. Rows/cells are rendered as text; callers are\n * responsible for stringifying complex cell values.\n */\n\nimport { Component, For, Show } from 'solid-js';\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';\n\nexport interface DegradedFallbackProps {\n /** Short, human-readable reason the native render was skipped/failed. */\n message: string;\n /**\n * Column headers for the degraded data table. When omitted (or empty),\n * only the notice banner is shown.\n */\n columns?: string[];\n /** Row data — each row is an array of cells aligned to `columns`. */\n rows?: Array<Array<string | number>>;\n /**\n * Caption under the table. Defaults to a generic\n * \"interactive view unavailable\" line.\n */\n caption?: string;\n /** Max rows to render before truncating (default 50). */\n maxRows?: number;\n}\n\nexport const DegradedFallback: Component<DegradedFallbackProps> = (props) => {\n const strings = useMCPUIStrings();\n const maxRows = () => props.maxRows ?? 50;\n const allRows = () => props.rows ?? [];\n const shownRows = () => allRows().slice(0, maxRows());\n const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);\n const hasTable = () => (props.columns?.length ?? 0) > 0 && allRows().length > 0;\n\n return (\n <div\n class=\"w-full rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-800 dark:bg-amber-900/20\"\n role=\"alert\"\n >\n <p class=\"text-sm font-medium text-amber-900 dark:text-amber-100\">{props.message}</p>\n <p class=\"mt-0.5 text-xs text-amber-700 dark:text-amber-300\">\n {props.caption ?? strings.degradedCaption}\n </p>\n\n <Show when={hasTable()}>\n <div class=\"mt-2 max-h-64 overflow-auto rounded border border-amber-200 dark:border-amber-800\">\n <table class=\"w-full border-collapse text-left text-xs\">\n <thead class=\"sticky top-0 bg-amber-100 dark:bg-amber-900/40\">\n <tr>\n <For each={props.columns}>\n {(col) => (\n <th class=\"px-2 py-1 font-medium text-amber-900 dark:text-amber-100\">{col}</th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={shownRows()}>\n {(row) => (\n <tr class=\"border-t border-amber-100 dark:border-amber-800/60\">\n <For each={props.columns}>\n {(_col, i) => (\n <td class=\"px-2 py-1 text-amber-800 dark:text-amber-200\">\n {String(row[i()] ?? '')}\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n </div>\n <Show when={hiddenCount() > 0}>\n <p class=\"mt-1 text-[10px] text-amber-600 dark:text-amber-400\">\n {formatMCPUIString(strings.degradedMoreRows, { count: hiddenCount() })}\n </p>\n </Show>\n </Show>\n </div>\n );\n};\n"],"names":["DegradedFallback","props","strings","useMCPUIStrings","maxRows","allRows","rows","shownRows","slice","hiddenCount","Math","max","length","hasTable","columns","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","nextSibling","_el$0","_el$1","_co$","_$getNextMarker","_$insert","message","caption","degradedCaption","_$createComponent","Show","when","children","_el$4","_tmpl$","_el$5","_el$6","_el$7","_el$8","For","each","col","_el$10","_tmpl$4","row","_el$11","_tmpl$5","_col","i","_el$12","_tmpl$6","String","_el$9","_tmpl$2","formatMCPUIString","degradedMoreRows","count"],"mappings":";;;;;;;AAuCO,MAAMA,mBAAsDC,CAAAA,UAAU;AAC3E,QAAMC,UAAUC,oBAAAA,gBAAAA;AAChB,QAAMC,UAAUA,MAAMH,MAAMG,WAAW;AACvC,QAAMC,UAAUA,MAAMJ,MAAMK,QAAQ,CAAA;AACpC,QAAMC,YAAYA,MAAMF,QAAAA,EAAUG,MAAM,GAAGJ,SAAS;AACpD,QAAMK,cAAcA,MAAMC,KAAKC,IAAI,GAAGN,UAAUO,SAASL,UAAAA,EAAYK,MAAM;AAC3E,QAAMC,WAAWA,MAAAA;;AAAOZ,yBAAMa,YAANb,mBAAeW,WAAU,KAAK,KAAKP,UAAUO,SAAS;AAAA;AAE9E,UAAA,MAAA;AAAA,QAAAG,OAAAC,IAAAA,eAAAC,OAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAG,aAAAC,QAAAF,MAAAC,aAAA,CAAAE,OAAAC,IAAA,IAAAC,IAAAA,cAAAH,MAAAD,WAAA;AAAAK,QAAAA,OAAAR,OAAA,MAKuEjB,MAAM0B,OAAO;AAAAD,QAAAA,OAAAN,OAAA,MAE7EnB,MAAM2B,WAAW1B,QAAQ2B,eAAe;AAAAH,eAAAX,MAAAe,IAAAA,gBAG1CC,cAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEnB,SAAAA;AAAAA,MAAU;AAAA,MAAA,IAAAoB,WAAA;AAAA,eAAA,EAAA,MAAA;AAAA,cAAAC,QAAAlB,IAAAA,eAAAmB,MAAA,GAAAC,QAAAF,MAAAf,YAAAkB,QAAAD,MAAAjB,YAAAmB,QAAAD,MAAAlB,YAAAoB,QAAAF,MAAAhB;AAAAK,qBAAAY,OAAAR,IAAAA,gBAKXU,aAAG;AAAA,YAAA,IAACC,OAAI;AAAA,qBAAExC,MAAMa;AAAAA,YAAO;AAAA,YAAAmB,UACpBS,UAAG,MAAA;AAAA,kBAAAC,SAAA3B,IAAAA,eAAA4B,OAAA;AAAAlB,kBAAAA,OAAAiB,QACmED,GAAG;AAAA,qBAAAC;AAAAA,YAAA,GAAA;AAAA,UAAA,CAC1E,CAAA;AAAAjB,qBAAAa,OAAAT,IAAAA,gBAKJU,aAAG;AAAA,YAAA,IAACC,OAAI;AAAA,qBAAElC,UAAAA;AAAAA,YAAW;AAAA,YAAA0B,UAClBY,UAAG,MAAA;AAAA,kBAAAC,SAAA9B,IAAAA,eAAA+B,OAAA;AAAArB,yBAAAoB,QAAAhB,IAAAA,gBAEAU,aAAG;AAAA,gBAAA,IAACC,OAAI;AAAA,yBAAExC,MAAMa;AAAAA,gBAAO;AAAA,gBAAAmB,UACrBA,CAACe,MAAMC,OAAC,MAAA;AAAA,sBAAAC,SAAAlC,IAAAA,eAAAmC,OAAA;AAAAzB,sBAAAA,OAAAwB,QAAA,MAEJE,OAAOP,IAAII,GAAG,KAAK,EAAE,CAAC;AAAA,yBAAAC;AAAAA,gBAAA,GAAA;AAAA,cAAA,CAE1B,CAAA;AAAA,qBAAAJ;AAAAA,YAAA,GAAA;AAAA,UAAA,CAGN,CAAA;AAAA,iBAAAZ;AAAAA,QAAA,GAAA,GAAAJ,IAAAA,gBAKRC,cAAI;AAAA,UAAA,IAACC,OAAI;AAAA,mBAAEvB,gBAAgB;AAAA,UAAC;AAAA,UAAA,IAAAwB,WAAA;AAAA,gBAAAoB,QAAArC,IAAAA,eAAAsC,OAAA;AAAA5B,gBAAAA,OAAA2B,OAAA,MAExBE,+BAAkBrD,QAAQsD,kBAAkB;AAAA,cAAEC,OAAOhD,YAAAA;AAAAA,YAAY,CAAG,CAAC;AAAA,mBAAA4C;AAAAA,UAAA;AAAA,QAAA,CAAA,CAAA;AAAA,MAAA;AAAA,IAAA,CAAA,GAAA9B,OAAAC,IAAA;AAAA,WAAAT;AAAAA,EAAA,GAAA;AAMlF;;"}
1
+ {"version":3,"file":"DegradedFallback.cjs","sources":["../../src/components/DegradedFallback.tsx"],"sourcesContent":["/**\n * DegradedFallback — the middle rung of the renderer fallback ladder\n * (audit 2026-05-30, P2.5).\n *\n * Each heavy renderer (graph / map / chart) follows the same contract:\n * 1. native render when its peer lib is available and succeeds;\n * 2. **degraded but useful** view when the native render throws — this\n * component: a visible notice + a plain data table so the user still\n * sees the underlying data instead of a blank space;\n * 3. (the caller also emits a `render:error` telemetry event).\n *\n * Pure / presentational — no peer deps, no side effects — so a render-path\n * failure in a heavy lib can never cascade into the fallback itself, and it\n * is trivially unit-testable. Rows/cells are rendered as text; callers are\n * responsible for stringifying complex cell values.\n */\n\nimport { Component, For, Show } from 'solid-js';\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';\nimport { MissingValueLegend, MissingValueMark } from './MissingValue';\n\nexport interface DegradedFallbackProps {\n /** Short, human-readable reason the native render was skipped/failed. */\n message: string;\n /**\n * Column headers for the degraded data table. When omitted (or empty),\n * only the notice banner is shown.\n */\n columns?: string[];\n /** Row data — each row is an array of cells aligned to `columns`. */\n rows?: Array<Array<string | number>>;\n /**\n * Caption under the table. Defaults to a generic\n * \"interactive view unavailable\" line.\n */\n caption?: string;\n /** Max rows to render before truncating (default 50). */\n maxRows?: number;\n /**\n * Same shape as `rows`: `true` marks a cell whose value is missing, which\n * renders as `<MissingValueMark/>` instead of its text. A\n * `<MissingValueLegend/>` follows the table when a SHOWN cell is missing.\n * Omitted, the output is unchanged. @since v6.24.0\n */\n missing?: boolean[][];\n}\n\nexport const DegradedFallback: Component<DegradedFallbackProps> = (props) => {\n const strings = useMCPUIStrings();\n const maxRows = () => props.maxRows ?? 50;\n const allRows = () => props.rows ?? [];\n const shownRows = () => allRows().slice(0, maxRows());\n const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);\n const isMissing = (rowIndex: number, colIndex: number) =>\n props.missing?.[rowIndex]?.[colIndex] === true;\n const anyShownMissing = () => {\n const columnCount = props.columns?.length ?? 0;\n return shownRows().some((_row, r) => {\n for (let c = 0; c < columnCount; c += 1) if (isMissing(r, c)) return true;\n return false;\n });\n };\n const hasTable = () => (props.columns?.length ?? 0) > 0 && allRows().length > 0;\n\n return (\n <div\n class=\"w-full rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-800 dark:bg-amber-900/20\"\n role=\"alert\"\n >\n <p class=\"text-sm font-medium text-amber-900 dark:text-amber-100\">{props.message}</p>\n <p class=\"mt-0.5 text-xs text-amber-700 dark:text-amber-300\">\n {props.caption ?? strings.degradedCaption}\n </p>\n\n <Show when={hasTable()}>\n <div class=\"mt-2 max-h-64 overflow-auto rounded border border-amber-200 dark:border-amber-800\">\n <table class=\"w-full border-collapse text-left text-xs\">\n <thead class=\"sticky top-0 bg-amber-100 dark:bg-amber-900/40\">\n <tr>\n <For each={props.columns}>\n {(col) => (\n <th class=\"px-2 py-1 font-medium text-amber-900 dark:text-amber-100\">{col}</th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={shownRows()}>\n {(row, rowIndex) => (\n <tr class=\"border-t border-amber-100 dark:border-amber-800/60\">\n <For each={props.columns}>\n {(_col, i) => (\n <td class=\"px-2 py-1 text-amber-800 dark:text-amber-200\">\n <Show when={isMissing(rowIndex(), i())} fallback={String(row[i()] ?? '')}>\n <MissingValueMark />\n </Show>\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n </div>\n <Show when={anyShownMissing()}>\n <MissingValueLegend class=\"mt-2\" />\n </Show>\n <Show when={hiddenCount() > 0}>\n <p class=\"mt-1 text-[10px] text-amber-600 dark:text-amber-400\">\n {formatMCPUIString(strings.degradedMoreRows, { count: hiddenCount() })}\n </p>\n </Show>\n </Show>\n </div>\n );\n};\n"],"names":["DegradedFallback","props","strings","useMCPUIStrings","maxRows","allRows","rows","shownRows","slice","hiddenCount","Math","max","length","isMissing","rowIndex","colIndex","missing","anyShownMissing","columnCount","columns","some","_row","r","c","hasTable","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","nextSibling","_el$0","_el$1","_co$","_$getNextMarker","_$insert","message","caption","degradedCaption","_$createComponent","Show","when","children","_el$4","_tmpl$","_el$5","_el$6","_el$7","_el$8","For","each","col","_el$10","_tmpl$4","row","_el$11","_tmpl$5","_col","i","_el$12","_tmpl$6","fallback","String","MissingValueMark","MissingValueLegend","_el$9","_tmpl$2","formatMCPUIString","degradedMoreRows","count"],"mappings":";;;;;;;;AA+CO,MAAMA,mBAAsDC,CAAAA,UAAU;AAC3E,QAAMC,UAAUC,oBAAAA,gBAAAA;AAChB,QAAMC,UAAUA,MAAMH,MAAMG,WAAW;AACvC,QAAMC,UAAUA,MAAMJ,MAAMK,QAAQ,CAAA;AACpC,QAAMC,YAAYA,MAAMF,QAAAA,EAAUG,MAAM,GAAGJ,SAAS;AACpD,QAAMK,cAAcA,MAAMC,KAAKC,IAAI,GAAGN,UAAUO,SAASL,UAAAA,EAAYK,MAAM;AAC3E,QAAMC,YAAYA,CAACC,UAAkBC,aAAAA;;AACnCd,8BAAMe,YAANf,mBAAgBa,cAAhBb,mBAA4Bc,eAAc;AAAA;AAC5C,QAAME,kBAAkBA,MAAM;;AAC5B,UAAMC,gBAAcjB,WAAMkB,YAANlB,mBAAeW,WAAU;AAC7C,WAAOL,UAAAA,EAAYa,KAAK,CAACC,MAAMC,MAAM;AACnC,eAASC,IAAI,GAAGA,IAAIL,aAAaK,KAAK,EAAG,KAAIV,UAAUS,GAAGC,CAAC,EAAG,QAAO;AACrE,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,QAAMC,WAAWA,MAAAA;;AAAOvB,yBAAMkB,YAANlB,mBAAeW,WAAU,KAAK,KAAKP,UAAUO,SAAS;AAAA;AAE9E,UAAA,MAAA;AAAA,QAAAa,OAAAC,IAAAA,eAAAC,OAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAG,aAAAC,QAAAF,MAAAC,aAAA,CAAAE,OAAAC,IAAA,IAAAC,IAAAA,cAAAH,MAAAD,WAAA;AAAAK,QAAAA,OAAAR,OAAA,MAKuE3B,MAAMoC,OAAO;AAAAD,QAAAA,OAAAN,OAAA,MAE7E7B,MAAMqC,WAAWpC,QAAQqC,eAAe;AAAAH,eAAAX,MAAAe,IAAAA,gBAG1CC,cAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAElB,SAAAA;AAAAA,MAAU;AAAA,MAAA,IAAAmB,WAAA;AAAA,eAAA,EAAA,MAAA;AAAA,cAAAC,QAAAlB,IAAAA,eAAAmB,MAAA,GAAAC,QAAAF,MAAAf,YAAAkB,QAAAD,MAAAjB,YAAAmB,QAAAD,MAAAlB,YAAAoB,QAAAF,MAAAhB;AAAAK,qBAAAY,OAAAR,IAAAA,gBAKXU,aAAG;AAAA,YAAA,IAACC,OAAI;AAAA,qBAAElD,MAAMkB;AAAAA,YAAO;AAAA,YAAAwB,UACpBS,UAAG,MAAA;AAAA,kBAAAC,SAAA3B,IAAAA,eAAA4B,OAAA;AAAAlB,kBAAAA,OAAAiB,QACmED,GAAG;AAAA,qBAAAC;AAAAA,YAAA,GAAA;AAAA,UAAA,CAC1E,CAAA;AAAAjB,qBAAAa,OAAAT,IAAAA,gBAKJU,aAAG;AAAA,YAAA,IAACC,OAAI;AAAA,qBAAE5C,UAAAA;AAAAA,YAAW;AAAA,YAAAoC,UACnBA,CAACY,KAAKzC,cAAQ,MAAA;AAAA,kBAAA0C,SAAA9B,IAAAA,eAAA+B,OAAA;AAAArB,yBAAAoB,QAAAhB,IAAAA,gBAEVU,aAAG;AAAA,gBAAA,IAACC,OAAI;AAAA,yBAAElD,MAAMkB;AAAAA,gBAAO;AAAA,gBAAAwB,UACrBA,CAACe,MAAMC,OAAC,MAAA;AAAA,sBAAAC,SAAAlC,IAAAA,eAAAmC,OAAA;AAAAzB,6BAAAwB,QAAApB,IAAAA,gBAEJC,cAAI;AAAA,oBAAA,IAACC,OAAI;AAAA,6BAAE7B,UAAUC,YAAY6C,GAAG;AAAA,oBAAC;AAAA,oBAAA,IAAEG,WAAQ;AAAA,6BAAEC,OAAOR,IAAII,EAAAA,CAAG,KAAK,EAAE;AAAA,oBAAC;AAAA,oBAAA,IAAAhB,WAAA;AAAA,6BAAAH,IAAAA,gBACrEwB,aAAAA,kBAAgB,EAAA;AAAA,oBAAA;AAAA,kBAAA,CAAA,CAAA;AAAA,yBAAAJ;AAAAA,gBAAA,GAAA;AAAA,cAAA,CAGtB,CAAA;AAAA,qBAAAJ;AAAAA,YAAA,GAAA;AAAA,UAAA,CAGN,CAAA;AAAA,iBAAAZ;AAAAA,QAAA,GAAA,GAAAJ,IAAAA,gBAKRC,cAAI;AAAA,UAAA,IAACC,OAAI;AAAA,mBAAEzB,gBAAAA;AAAAA,UAAiB;AAAA,UAAA,IAAA0B,WAAA;AAAA,mBAAAH,IAAAA,gBAC1ByB,aAAAA,oBAAkB;AAAA,cAAA,SAAA;AAAA,YAAA,CAAA;AAAA,UAAA;AAAA,QAAA,CAAA,GAAAzB,IAAAA,gBAEpBC,cAAI;AAAA,UAAA,IAACC,OAAI;AAAA,mBAAEjC,gBAAgB;AAAA,UAAC;AAAA,UAAA,IAAAkC,WAAA;AAAA,gBAAAuB,QAAAxC,IAAAA,eAAAyC,OAAA;AAAA/B,gBAAAA,OAAA8B,OAAA,MAExBE,+BAAkBlE,QAAQmE,kBAAkB;AAAA,cAAEC,OAAO7D,YAAAA;AAAAA,YAAY,CAAG,CAAC;AAAA,mBAAAyD;AAAAA,UAAA;AAAA,QAAA,CAAA,CAAA;AAAA,MAAA;AAAA,IAAA,CAAA,GAAAjC,OAAAC,IAAA;AAAA,WAAAT;AAAAA,EAAA,GAAA;AAMlF;;"}
@@ -32,6 +32,13 @@ export interface DegradedFallbackProps {
32
32
  caption?: string;
33
33
  /** Max rows to render before truncating (default 50). */
34
34
  maxRows?: number;
35
+ /**
36
+ * Same shape as `rows`: `true` marks a cell whose value is missing, which
37
+ * renders as `<MissingValueMark/>` instead of its text. A
38
+ * `<MissingValueLegend/>` follows the table when a SHOWN cell is missing.
39
+ * Omitted, the output is unchanged. @since v6.24.0
40
+ */
41
+ missing?: boolean[][];
35
42
  }
36
43
  export declare const DegradedFallback: Component<DegradedFallbackProps>;
37
44
  //# sourceMappingURL=DegradedFallback.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DegradedFallback.d.ts","sourceRoot":"","sources":["../../src/components/DegradedFallback.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,SAAS,EAAa,MAAM,UAAU,CAAC;AAGhD,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,qEAAqE;IACrE,IAAI,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,gBAAgB,EAAE,SAAS,CAAC,qBAAqB,CAuD7D,CAAC"}
1
+ {"version":3,"file":"DegradedFallback.d.ts","sourceRoot":"","sources":["../../src/components/DegradedFallback.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,SAAS,EAAa,MAAM,UAAU,CAAC;AAIhD,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,qEAAqE;IACrE,IAAI,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;CACvB;AAED,eAAO,MAAM,gBAAgB,EAAE,SAAS,CAAC,qBAAqB,CAqE7D,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { getNextElement, getNextMarker, insert, createComponent, template } from "solid-js/web";
2
2
  import { Show, For } from "solid-js";
3
3
  import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
4
+ import { MissingValueMark, MissingValueLegend } from "./MissingValue.js";
4
5
  import { formatMCPUIString } from "../utils/format-string.js";
5
6
  var _tmpl$ = /* @__PURE__ */ template(`<div class="mt-2 max-h-64 overflow-auto rounded border border-amber-200 dark:border-amber-800"><table class="w-full border-collapse text-left text-xs"><thead class="sticky top-0 bg-amber-100 dark:bg-amber-900/40"><tr></tr></thead><tbody>`), _tmpl$2 = /* @__PURE__ */ template(`<p class="mt-1 text-[10px] text-amber-600 dark:text-amber-400">`), _tmpl$3 = /* @__PURE__ */ template(`<div class="w-full rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-800 dark:bg-amber-900/20"role=alert><p class="text-sm font-medium text-amber-900 dark:text-amber-100"></p><p class="mt-0.5 text-xs text-amber-700 dark:text-amber-300"></p><!$><!/>`), _tmpl$4 = /* @__PURE__ */ template(`<th class="px-2 py-1 font-medium text-amber-900 dark:text-amber-100">`), _tmpl$5 = /* @__PURE__ */ template(`<tr class="border-t border-amber-100 dark:border-amber-800/60">`), _tmpl$6 = /* @__PURE__ */ template(`<td class="px-2 py-1 text-amber-800 dark:text-amber-200">`);
6
7
  const DegradedFallback = (props) => {
@@ -9,6 +10,18 @@ const DegradedFallback = (props) => {
9
10
  const allRows = () => props.rows ?? [];
10
11
  const shownRows = () => allRows().slice(0, maxRows());
11
12
  const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);
13
+ const isMissing = (rowIndex, colIndex) => {
14
+ var _a, _b;
15
+ return ((_b = (_a = props.missing) == null ? void 0 : _a[rowIndex]) == null ? void 0 : _b[colIndex]) === true;
16
+ };
17
+ const anyShownMissing = () => {
18
+ var _a;
19
+ const columnCount = ((_a = props.columns) == null ? void 0 : _a.length) ?? 0;
20
+ return shownRows().some((_row, r) => {
21
+ for (let c = 0; c < columnCount; c += 1) if (isMissing(r, c)) return true;
22
+ return false;
23
+ });
24
+ };
12
25
  const hasTable = () => {
13
26
  var _a;
14
27
  return (((_a = props.columns) == null ? void 0 : _a.length) ?? 0) > 0 && allRows().length > 0;
@@ -38,7 +51,7 @@ const DegradedFallback = (props) => {
38
51
  get each() {
39
52
  return shownRows();
40
53
  },
41
- children: (row) => (() => {
54
+ children: (row, rowIndex) => (() => {
42
55
  var _el$11 = getNextElement(_tmpl$5);
43
56
  insert(_el$11, createComponent(For, {
44
57
  get each() {
@@ -46,7 +59,17 @@ const DegradedFallback = (props) => {
46
59
  },
47
60
  children: (_col, i) => (() => {
48
61
  var _el$12 = getNextElement(_tmpl$6);
49
- insert(_el$12, () => String(row[i()] ?? ""));
62
+ insert(_el$12, createComponent(Show, {
63
+ get when() {
64
+ return isMissing(rowIndex(), i());
65
+ },
66
+ get fallback() {
67
+ return String(row[i()] ?? "");
68
+ },
69
+ get children() {
70
+ return createComponent(MissingValueMark, {});
71
+ }
72
+ }));
50
73
  return _el$12;
51
74
  })()
52
75
  }));
@@ -55,6 +78,15 @@ const DegradedFallback = (props) => {
55
78
  }));
56
79
  return _el$4;
57
80
  })(), createComponent(Show, {
81
+ get when() {
82
+ return anyShownMissing();
83
+ },
84
+ get children() {
85
+ return createComponent(MissingValueLegend, {
86
+ "class": "mt-2"
87
+ });
88
+ }
89
+ }), createComponent(Show, {
58
90
  get when() {
59
91
  return hiddenCount() > 0;
60
92
  },
@@ -1 +1 @@
1
- {"version":3,"file":"DegradedFallback.js","sources":["../../src/components/DegradedFallback.tsx"],"sourcesContent":["/**\n * DegradedFallback — the middle rung of the renderer fallback ladder\n * (audit 2026-05-30, P2.5).\n *\n * Each heavy renderer (graph / map / chart) follows the same contract:\n * 1. native render when its peer lib is available and succeeds;\n * 2. **degraded but useful** view when the native render throws — this\n * component: a visible notice + a plain data table so the user still\n * sees the underlying data instead of a blank space;\n * 3. (the caller also emits a `render:error` telemetry event).\n *\n * Pure / presentational — no peer deps, no side effects — so a render-path\n * failure in a heavy lib can never cascade into the fallback itself, and it\n * is trivially unit-testable. Rows/cells are rendered as text; callers are\n * responsible for stringifying complex cell values.\n */\n\nimport { Component, For, Show } from 'solid-js';\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';\n\nexport interface DegradedFallbackProps {\n /** Short, human-readable reason the native render was skipped/failed. */\n message: string;\n /**\n * Column headers for the degraded data table. When omitted (or empty),\n * only the notice banner is shown.\n */\n columns?: string[];\n /** Row data — each row is an array of cells aligned to `columns`. */\n rows?: Array<Array<string | number>>;\n /**\n * Caption under the table. Defaults to a generic\n * \"interactive view unavailable\" line.\n */\n caption?: string;\n /** Max rows to render before truncating (default 50). */\n maxRows?: number;\n}\n\nexport const DegradedFallback: Component<DegradedFallbackProps> = (props) => {\n const strings = useMCPUIStrings();\n const maxRows = () => props.maxRows ?? 50;\n const allRows = () => props.rows ?? [];\n const shownRows = () => allRows().slice(0, maxRows());\n const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);\n const hasTable = () => (props.columns?.length ?? 0) > 0 && allRows().length > 0;\n\n return (\n <div\n class=\"w-full rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-800 dark:bg-amber-900/20\"\n role=\"alert\"\n >\n <p class=\"text-sm font-medium text-amber-900 dark:text-amber-100\">{props.message}</p>\n <p class=\"mt-0.5 text-xs text-amber-700 dark:text-amber-300\">\n {props.caption ?? strings.degradedCaption}\n </p>\n\n <Show when={hasTable()}>\n <div class=\"mt-2 max-h-64 overflow-auto rounded border border-amber-200 dark:border-amber-800\">\n <table class=\"w-full border-collapse text-left text-xs\">\n <thead class=\"sticky top-0 bg-amber-100 dark:bg-amber-900/40\">\n <tr>\n <For each={props.columns}>\n {(col) => (\n <th class=\"px-2 py-1 font-medium text-amber-900 dark:text-amber-100\">{col}</th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={shownRows()}>\n {(row) => (\n <tr class=\"border-t border-amber-100 dark:border-amber-800/60\">\n <For each={props.columns}>\n {(_col, i) => (\n <td class=\"px-2 py-1 text-amber-800 dark:text-amber-200\">\n {String(row[i()] ?? '')}\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n </div>\n <Show when={hiddenCount() > 0}>\n <p class=\"mt-1 text-[10px] text-amber-600 dark:text-amber-400\">\n {formatMCPUIString(strings.degradedMoreRows, { count: hiddenCount() })}\n </p>\n </Show>\n </Show>\n </div>\n );\n};\n"],"names":["DegradedFallback","props","strings","useMCPUIStrings","maxRows","allRows","rows","shownRows","slice","hiddenCount","Math","max","length","hasTable","columns","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","nextSibling","_el$0","_el$1","_co$","_$getNextMarker","_$insert","message","caption","degradedCaption","_$createComponent","Show","when","children","_el$4","_tmpl$","_el$5","_el$6","_el$7","_el$8","For","each","col","_el$10","_tmpl$4","row","_el$11","_tmpl$5","_col","i","_el$12","_tmpl$6","String","_el$9","_tmpl$2","formatMCPUIString","degradedMoreRows","count"],"mappings":";;;;;AAuCO,MAAMA,mBAAsDC,CAAAA,UAAU;AAC3E,QAAMC,UAAUC,gBAAAA;AAChB,QAAMC,UAAUA,MAAMH,MAAMG,WAAW;AACvC,QAAMC,UAAUA,MAAMJ,MAAMK,QAAQ,CAAA;AACpC,QAAMC,YAAYA,MAAMF,QAAAA,EAAUG,MAAM,GAAGJ,SAAS;AACpD,QAAMK,cAAcA,MAAMC,KAAKC,IAAI,GAAGN,UAAUO,SAASL,UAAAA,EAAYK,MAAM;AAC3E,QAAMC,WAAWA,MAAAA;;AAAOZ,yBAAMa,YAANb,mBAAeW,WAAU,KAAK,KAAKP,UAAUO,SAAS;AAAA;AAE9E,UAAA,MAAA;AAAA,QAAAG,OAAAC,eAAAC,OAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAG,aAAAC,QAAAF,MAAAC,aAAA,CAAAE,OAAAC,IAAA,IAAAC,cAAAH,MAAAD,WAAA;AAAAK,WAAAR,OAAA,MAKuEjB,MAAM0B,OAAO;AAAAD,WAAAN,OAAA,MAE7EnB,MAAM2B,WAAW1B,QAAQ2B,eAAe;AAAAH,WAAAX,MAAAe,gBAG1CC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEnB,SAAAA;AAAAA,MAAU;AAAA,MAAA,IAAAoB,WAAA;AAAA,eAAA,EAAA,MAAA;AAAA,cAAAC,QAAAlB,eAAAmB,MAAA,GAAAC,QAAAF,MAAAf,YAAAkB,QAAAD,MAAAjB,YAAAmB,QAAAD,MAAAlB,YAAAoB,QAAAF,MAAAhB;AAAAK,iBAAAY,OAAAR,gBAKXU,KAAG;AAAA,YAAA,IAACC,OAAI;AAAA,qBAAExC,MAAMa;AAAAA,YAAO;AAAA,YAAAmB,UACpBS,UAAG,MAAA;AAAA,kBAAAC,SAAA3B,eAAA4B,OAAA;AAAAlB,qBAAAiB,QACmED,GAAG;AAAA,qBAAAC;AAAAA,YAAA,GAAA;AAAA,UAAA,CAC1E,CAAA;AAAAjB,iBAAAa,OAAAT,gBAKJU,KAAG;AAAA,YAAA,IAACC,OAAI;AAAA,qBAAElC,UAAAA;AAAAA,YAAW;AAAA,YAAA0B,UAClBY,UAAG,MAAA;AAAA,kBAAAC,SAAA9B,eAAA+B,OAAA;AAAArB,qBAAAoB,QAAAhB,gBAEAU,KAAG;AAAA,gBAAA,IAACC,OAAI;AAAA,yBAAExC,MAAMa;AAAAA,gBAAO;AAAA,gBAAAmB,UACrBA,CAACe,MAAMC,OAAC,MAAA;AAAA,sBAAAC,SAAAlC,eAAAmC,OAAA;AAAAzB,yBAAAwB,QAAA,MAEJE,OAAOP,IAAII,GAAG,KAAK,EAAE,CAAC;AAAA,yBAAAC;AAAAA,gBAAA,GAAA;AAAA,cAAA,CAE1B,CAAA;AAAA,qBAAAJ;AAAAA,YAAA,GAAA;AAAA,UAAA,CAGN,CAAA;AAAA,iBAAAZ;AAAAA,QAAA,GAAA,GAAAJ,gBAKRC,MAAI;AAAA,UAAA,IAACC,OAAI;AAAA,mBAAEvB,gBAAgB;AAAA,UAAC;AAAA,UAAA,IAAAwB,WAAA;AAAA,gBAAAoB,QAAArC,eAAAsC,OAAA;AAAA5B,mBAAA2B,OAAA,MAExBE,kBAAkBrD,QAAQsD,kBAAkB;AAAA,cAAEC,OAAOhD,YAAAA;AAAAA,YAAY,CAAG,CAAC;AAAA,mBAAA4C;AAAAA,UAAA;AAAA,QAAA,CAAA,CAAA;AAAA,MAAA;AAAA,IAAA,CAAA,GAAA9B,OAAAC,IAAA;AAAA,WAAAT;AAAAA,EAAA,GAAA;AAMlF;"}
1
+ {"version":3,"file":"DegradedFallback.js","sources":["../../src/components/DegradedFallback.tsx"],"sourcesContent":["/**\n * DegradedFallback — the middle rung of the renderer fallback ladder\n * (audit 2026-05-30, P2.5).\n *\n * Each heavy renderer (graph / map / chart) follows the same contract:\n * 1. native render when its peer lib is available and succeeds;\n * 2. **degraded but useful** view when the native render throws — this\n * component: a visible notice + a plain data table so the user still\n * sees the underlying data instead of a blank space;\n * 3. (the caller also emits a `render:error` telemetry event).\n *\n * Pure / presentational — no peer deps, no side effects — so a render-path\n * failure in a heavy lib can never cascade into the fallback itself, and it\n * is trivially unit-testable. Rows/cells are rendered as text; callers are\n * responsible for stringifying complex cell values.\n */\n\nimport { Component, For, Show } from 'solid-js';\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';\nimport { MissingValueLegend, MissingValueMark } from './MissingValue';\n\nexport interface DegradedFallbackProps {\n /** Short, human-readable reason the native render was skipped/failed. */\n message: string;\n /**\n * Column headers for the degraded data table. When omitted (or empty),\n * only the notice banner is shown.\n */\n columns?: string[];\n /** Row data — each row is an array of cells aligned to `columns`. */\n rows?: Array<Array<string | number>>;\n /**\n * Caption under the table. Defaults to a generic\n * \"interactive view unavailable\" line.\n */\n caption?: string;\n /** Max rows to render before truncating (default 50). */\n maxRows?: number;\n /**\n * Same shape as `rows`: `true` marks a cell whose value is missing, which\n * renders as `<MissingValueMark/>` instead of its text. A\n * `<MissingValueLegend/>` follows the table when a SHOWN cell is missing.\n * Omitted, the output is unchanged. @since v6.24.0\n */\n missing?: boolean[][];\n}\n\nexport const DegradedFallback: Component<DegradedFallbackProps> = (props) => {\n const strings = useMCPUIStrings();\n const maxRows = () => props.maxRows ?? 50;\n const allRows = () => props.rows ?? [];\n const shownRows = () => allRows().slice(0, maxRows());\n const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);\n const isMissing = (rowIndex: number, colIndex: number) =>\n props.missing?.[rowIndex]?.[colIndex] === true;\n const anyShownMissing = () => {\n const columnCount = props.columns?.length ?? 0;\n return shownRows().some((_row, r) => {\n for (let c = 0; c < columnCount; c += 1) if (isMissing(r, c)) return true;\n return false;\n });\n };\n const hasTable = () => (props.columns?.length ?? 0) > 0 && allRows().length > 0;\n\n return (\n <div\n class=\"w-full rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-800 dark:bg-amber-900/20\"\n role=\"alert\"\n >\n <p class=\"text-sm font-medium text-amber-900 dark:text-amber-100\">{props.message}</p>\n <p class=\"mt-0.5 text-xs text-amber-700 dark:text-amber-300\">\n {props.caption ?? strings.degradedCaption}\n </p>\n\n <Show when={hasTable()}>\n <div class=\"mt-2 max-h-64 overflow-auto rounded border border-amber-200 dark:border-amber-800\">\n <table class=\"w-full border-collapse text-left text-xs\">\n <thead class=\"sticky top-0 bg-amber-100 dark:bg-amber-900/40\">\n <tr>\n <For each={props.columns}>\n {(col) => (\n <th class=\"px-2 py-1 font-medium text-amber-900 dark:text-amber-100\">{col}</th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={shownRows()}>\n {(row, rowIndex) => (\n <tr class=\"border-t border-amber-100 dark:border-amber-800/60\">\n <For each={props.columns}>\n {(_col, i) => (\n <td class=\"px-2 py-1 text-amber-800 dark:text-amber-200\">\n <Show when={isMissing(rowIndex(), i())} fallback={String(row[i()] ?? '')}>\n <MissingValueMark />\n </Show>\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n </div>\n <Show when={anyShownMissing()}>\n <MissingValueLegend class=\"mt-2\" />\n </Show>\n <Show when={hiddenCount() > 0}>\n <p class=\"mt-1 text-[10px] text-amber-600 dark:text-amber-400\">\n {formatMCPUIString(strings.degradedMoreRows, { count: hiddenCount() })}\n </p>\n </Show>\n </Show>\n </div>\n );\n};\n"],"names":["DegradedFallback","props","strings","useMCPUIStrings","maxRows","allRows","rows","shownRows","slice","hiddenCount","Math","max","length","isMissing","rowIndex","colIndex","missing","anyShownMissing","columnCount","columns","some","_row","r","c","hasTable","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","nextSibling","_el$0","_el$1","_co$","_$getNextMarker","_$insert","message","caption","degradedCaption","_$createComponent","Show","when","children","_el$4","_tmpl$","_el$5","_el$6","_el$7","_el$8","For","each","col","_el$10","_tmpl$4","row","_el$11","_tmpl$5","_col","i","_el$12","_tmpl$6","fallback","String","MissingValueMark","MissingValueLegend","_el$9","_tmpl$2","formatMCPUIString","degradedMoreRows","count"],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const web = require("solid-js/web");
4
+ const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
5
+ const missingValue = require("../utils/missing-value.cjs");
6
+ const formatString = require("../utils/format-string.cjs");
7
+ var _tmpl$ = /* @__PURE__ */ web.template(`<span data-mcp-missing-value><span aria-hidden=true class="text-gray-400 dark:text-gray-500"></span><span>`), _tmpl$2 = /* @__PURE__ */ web.template(`<p data-mcp-missing-legend role=note>`);
8
+ const VISUALLY_HIDDEN_STYLE = {
9
+ position: "absolute",
10
+ width: "1px",
11
+ height: "1px",
12
+ padding: "0",
13
+ margin: "-1px",
14
+ overflow: "hidden",
15
+ clip: "rect(0, 0, 0, 0)",
16
+ "white-space": "nowrap",
17
+ border: "0"
18
+ };
19
+ const MissingValueMark = () => {
20
+ const strings = MCPUIStringsContext.useMCPUIStrings();
21
+ return (() => {
22
+ var _el$ = web.getNextElement(_tmpl$), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
23
+ web.insert(_el$2, missingValue.MISSING_VALUE_MARKER);
24
+ web.insert(_el$3, () => strings.missingValue);
25
+ web.effect((_$p) => web.style(_el$3, VISUALLY_HIDDEN_STYLE, _$p));
26
+ return _el$;
27
+ })();
28
+ };
29
+ const MissingValueLegend = (props) => {
30
+ const strings = MCPUIStringsContext.useMCPUIStrings();
31
+ return (() => {
32
+ var _el$4 = web.getNextElement(_tmpl$2);
33
+ web.insert(_el$4, () => formatString.formatMCPUIString(strings.missingValueLegend, {
34
+ marker: missingValue.MISSING_VALUE_MARKER
35
+ }));
36
+ web.effect(() => web.className(_el$4, `text-xs text-gray-500 dark:text-gray-400 ${props.class ?? ""}`));
37
+ return _el$4;
38
+ })();
39
+ };
40
+ exports.MissingValueLegend = MissingValueLegend;
41
+ exports.MissingValueMark = MissingValueMark;
42
+ exports.VISUALLY_HIDDEN_STYLE = VISUALLY_HIDDEN_STYLE;
43
+ //# sourceMappingURL=MissingValue.cjs.map