@seed-ship/mcp-ui-solid 6.21.0 → 6.23.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 (93) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/README.md +102 -0
  3. package/dist/components/ChartJSRenderer.cjs +244 -68
  4. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  5. package/dist/components/ChartJSRenderer.d.ts +9 -0
  6. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  7. package/dist/components/ChartJSRenderer.js +246 -70
  8. package/dist/components/ChartJSRenderer.js.map +1 -1
  9. package/dist/components/ExpandableWrapper.cjs +9 -1
  10. package/dist/components/ExpandableWrapper.cjs.map +1 -1
  11. package/dist/components/ExpandableWrapper.d.ts.map +1 -1
  12. package/dist/components/ExpandableWrapper.js +9 -1
  13. package/dist/components/ExpandableWrapper.js.map +1 -1
  14. package/dist/components/LightboxOverlay.cjs +139 -16
  15. package/dist/components/LightboxOverlay.cjs.map +1 -1
  16. package/dist/components/LightboxOverlay.d.ts +6 -0
  17. package/dist/components/LightboxOverlay.d.ts.map +1 -1
  18. package/dist/components/LightboxOverlay.js +141 -18
  19. package/dist/components/LightboxOverlay.js.map +1 -1
  20. package/dist/components/UIResourceRenderer.cjs +15 -5
  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 +15 -5
  25. package/dist/components/UIResourceRenderer.js.map +1 -1
  26. package/dist/context/MCPUIConfigContext.cjs +2 -1
  27. package/dist/context/MCPUIConfigContext.cjs.map +1 -1
  28. package/dist/context/MCPUIConfigContext.d.ts +90 -12
  29. package/dist/context/MCPUIConfigContext.d.ts.map +1 -1
  30. package/dist/context/MCPUIConfigContext.js +2 -1
  31. package/dist/context/MCPUIConfigContext.js.map +1 -1
  32. package/dist/context/MCPUIMathContext.cjs +19 -0
  33. package/dist/context/MCPUIMathContext.cjs.map +1 -0
  34. package/dist/context/MCPUIMathContext.d.ts +18 -0
  35. package/dist/context/MCPUIMathContext.d.ts.map +1 -0
  36. package/dist/context/MCPUIMathContext.js +19 -0
  37. package/dist/context/MCPUIMathContext.js.map +1 -0
  38. package/dist/context/MCPUIStringsContext.cjs +6 -1
  39. package/dist/context/MCPUIStringsContext.cjs.map +1 -1
  40. package/dist/context/MCPUIStringsContext.d.ts +22 -0
  41. package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
  42. package/dist/context/MCPUIStringsContext.js +6 -1
  43. package/dist/context/MCPUIStringsContext.js.map +1 -1
  44. package/dist/hooks/index.d.ts +2 -0
  45. package/dist/hooks/index.d.ts.map +1 -1
  46. package/dist/hooks.cjs +2 -0
  47. package/dist/hooks.cjs.map +1 -1
  48. package/dist/hooks.js +2 -0
  49. package/dist/hooks.js.map +1 -1
  50. package/dist/index.cjs +8 -0
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +5 -1
  53. package/dist/index.d.ts +5 -1
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +9 -1
  56. package/dist/index.js.map +1 -1
  57. package/dist/plugins/katex.cjs +23 -0
  58. package/dist/plugins/katex.cjs.map +1 -0
  59. package/dist/plugins/katex.d.cts +7 -0
  60. package/dist/plugins/katex.d.ts +7 -0
  61. package/dist/plugins/katex.d.ts.map +1 -0
  62. package/dist/plugins/katex.js +23 -0
  63. package/dist/plugins/katex.js.map +1 -0
  64. package/dist/utils/iframe-coep.cjs.map +1 -1
  65. package/dist/utils/iframe-coep.d.ts +8 -0
  66. package/dist/utils/iframe-coep.d.ts.map +1 -1
  67. package/dist/utils/iframe-coep.js.map +1 -1
  68. package/dist/utils/math-markdown.cjs +240 -0
  69. package/dist/utils/math-markdown.cjs.map +1 -0
  70. package/dist/utils/math-markdown.d.ts +16 -0
  71. package/dist/utils/math-markdown.d.ts.map +1 -0
  72. package/dist/utils/math-markdown.js +240 -0
  73. package/dist/utils/math-markdown.js.map +1 -0
  74. package/dist/utils/pan-zoom.cjs +312 -0
  75. package/dist/utils/pan-zoom.cjs.map +1 -0
  76. package/dist/utils/pan-zoom.d.ts +235 -0
  77. package/dist/utils/pan-zoom.d.ts.map +1 -0
  78. package/dist/utils/pan-zoom.js +312 -0
  79. package/dist/utils/pan-zoom.js.map +1 -0
  80. package/package.json +26 -3
  81. package/src/components/ChartJSRenderer.tsx +396 -1
  82. package/src/components/ExpandableWrapper.tsx +26 -0
  83. package/src/components/LightboxOverlay.tsx +280 -4
  84. package/src/components/UIResourceRenderer.tsx +24 -3
  85. package/src/context/MCPUIConfigContext.tsx +92 -12
  86. package/src/context/MCPUIMathContext.tsx +32 -0
  87. package/src/context/MCPUIStringsContext.tsx +30 -0
  88. package/src/hooks/index.ts +13 -0
  89. package/src/index.ts +20 -0
  90. package/src/plugins/katex.ts +25 -0
  91. package/src/utils/iframe-coep.ts +8 -0
  92. package/src/utils/math-markdown.ts +222 -0
  93. package/src/utils/pan-zoom.ts +779 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,179 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [6.23.0] - 2026-09-18
9
+
10
+ ### Added
11
+
12
+ - Opt-in `MCPUIMathProvider` and `MathRenderer` for markdown text and table
13
+ cells, including virtualized tables; separate optional `/plugins/katex`
14
+ adapter. No new required config fields and no KaTeX import from the root.
15
+ - Bounded dollar-delimited math parsing, currency guards, isolated Marked
16
+ instances, sanitized MathML-only rendering and literal fallback. Styles,
17
+ annotation subtrees, executable markup and trusted TeX commands stay blocked.
18
+ - SSR keeps escaped source until the existing client hydration upgrade;
19
+ original text/data is retained for copy and export. No CSS or font install.
20
+ - Optional KaTeX peer pinned to 0.18.4 to preserve Node 20 installation
21
+ compatibility; later 0.18.x releases currently require Node >=22.12 via
22
+ Commander. Cell links retain the existing new-tab, rel and styling policy.
23
+
24
+ ## [6.22.1] - 2026-09-18
25
+
26
+ Fixes a typing regression 6.22.0 introduced. Runtime behaviour is identical.
27
+
28
+ ### The mistake
29
+
30
+ 6.22.0 made every `MCPUIConfig` field optional so that adding a policy key
31
+ would stop breaking consumers who *author* a complete config. That fixed one
32
+ direction and broke the other: `MCPUIConfig` is a published type, so anyone who
33
+ *reads* one — `const policy: IframePolicy = config.iframePolicy` — suddenly
34
+ faced `… | undefined` and stopped compiling under `strictNullChecks`. Trading
35
+ one compile break for the opposite one is not a fix.
36
+
37
+ The two demands genuinely conflict, and one name cannot serve both: an author
38
+ must be allowed to omit a key, a reader must never meet `undefined`.
39
+
40
+ ### The fix — two names
41
+
42
+ - **`MCPUIConfigInput`** (new, exported): what a host writes. Every field
43
+ optional, so a new policy key is always additive. This is what
44
+ `MCPUIConfigProvider`'s `config` prop takes. Note it is NOT what
45
+ `MCPUIConfigContext.Provider` takes — see below.
46
+ - **`MCPUIConfig`**: what the library hands back — an interface extending
47
+ `Required<MCPUIConfigInput>`, every key present, which is the 6.21.0 meaning
48
+ restored. Keeping it an interface also preserves consumer extension and
49
+ declaration merging. `useMCPUIConfig()`, `DEFAULT_MCPUI_CONFIG` and
50
+ `MCPUIConfigContext` carry it.
51
+
52
+ `MCPUIConfigContext` keeps the resolved type on purpose: it is exported, so
53
+ `useContext(MCPUIConfigContext)` is a public read surface and typing it with the
54
+ input view would leave a direct reader on `IframePolicy | undefined` — the very
55
+ regression being undone. A host that bypasses `MCPUIConfigProvider` therefore
56
+ passes a complete value, `{ ...DEFAULT_MCPUI_CONFIG, ...mine }`; passing only
57
+ some keys is what the provider's `config` prop is for. `useMCPUIConfig()` still
58
+ merges at runtime, so an untyped host cannot break a renderer.
59
+
60
+ Derived rather than declared twice, so a key is written once and the two views
61
+ cannot drift. The guard test now pins **both** halves: every `MCPUIConfigInput`
62
+ field stays optional, and `MCPUIConfig` stays an interface extending
63
+ `Required<…>`. The contract typecheck also pins interface extension and
64
+ declaration merging. Both sides were verified to fail when their corresponding
65
+ regression is reintroduced.
66
+
67
+ ### How this got through
68
+
69
+ Through 6.22.0, `pnpm typecheck` ran the main `tsconfig.json` alone, and that
70
+ config excludes `**/*.test.ts(x)`: a type-level claim written in a test file
71
+ failed nothing. 6.22.0 shipped both a broken `MCPUIConfig` and a fixture
72
+ annotated with the wrong type, and neither `typecheck` nor `test` said a word.
73
+ `typecheck` now runs a second pass, `tsconfig.contracts.json`, which
74
+ type-checks the handful of test files whose `satisfies` and annotations *are*
75
+ the test. Including every test file instead would surface 53 unrelated errors,
76
+ so that stays a separate piece of work.
77
+
78
+ ### Upgrading
79
+
80
+ Reading is exactly as it was in 6.21.0, whether through `useMCPUIConfig()`,
81
+ `useContext(MCPUIConfigContext)` or a value typed `MCPUIConfig`.
82
+ `MCPUIConfigProvider`'s `config` prop still accepts everything it accepted
83
+ before, `Partial<MCPUIConfig>` included.
84
+
85
+ Two authoring patterns stop compiling, coming from 6.21.0 or from 6.22.0:
86
+
87
+ - **A config annotated `MCPUIConfig`.** From 6.22.0 a partial one fails; from
88
+ 6.21.0 a complete one fails too, since it lacks `chartZoom`. Annotate it
89
+ `MCPUIConfigInput` instead.
90
+ - **A value handed straight to `<MCPUIConfigContext.Provider>`**, annotated or
91
+ not: an inline literal fails the same way. Spread the defaults,
92
+ `{ ...DEFAULT_MCPUI_CONFIG, ...mine }`, or pass the keys to
93
+ `<MCPUIConfigProvider config={…}>`, which does that merge for you.
94
+
95
+ Both replacements keep compiling when the library adds its next policy key.
96
+
97
+ ## [6.22.0] - 2026-09-18
98
+
99
+ Wheel zoom and drag pan on the surfaces that could not be read when the content
100
+ was dense: the image lightbox, and Chart.js charts in their expanded view.
101
+
102
+ ### The rule this follows
103
+
104
+ **Wheel zoom is only ever enabled on a surface that owns its viewport** — a
105
+ fullscreen overlay or the expanded modal. A component sitting inline in a
106
+ scrolling page must not swallow the wheel, or a user scrolling the page finds
107
+ themselves zooming a chart instead. That is why chart zoom defaults to the
108
+ expanded view only, and why inline zoom is opt-in.
109
+
110
+ ### Added
111
+
112
+ - **`createPanZoom(options)`** (`src/utils/pan-zoom.ts`, exported from the root
113
+ and from the `./hooks` subpath) — a dependency-free cursor-anchored zoom and
114
+ drag-pan primitive: the point under the pointer stays under the pointer.
115
+ Handles two-finger pinch, clamps to `min`/`max`, and exposes
116
+ `cancelGesture()` for the case where the surface carrying the handlers is
117
+ torn down while a pointer is still down. The pure helpers behind it
118
+ (`clampScale`, `contentPointAt`, `viewportPointOf`, `zoomAtAnchor`) are
119
+ exported too.
120
+ - **`LightboxOverlay` zooms.** Wheel, drag to pan, double-click to toggle,
121
+ pinch on touch, and the keyboard shortcuts `+` / `-` / `0` alongside the
122
+ existing Escape and arrows. Zoom controls carry a level readout, and the zoom
123
+ resets when the displayed image changes.
124
+ - **Chart.js zoom and pan**, through `chartjs-plugin-zoom` as a new **optional**
125
+ peer dependency. Absent, charts render exactly as before — no warning, no
126
+ broken UI. A reset button appears in the toolbar only while the chart is
127
+ actually zoomed. A chart's own `options.plugins.zoom` is preserved: the
128
+ renderer's block is deep-merged into it, the caller's explicit values win
129
+ (`limits`, wheel `speed`, a pan `modifierKey`, `mode`), and a caller's
130
+ `onZoom` / `onPan` is *composed* with the renderer's rather than replacing
131
+ it, so the reset control stays in sync with the viewport either way. A key
132
+ the caller left `undefined` is read as an omission, not as an erasure. And
133
+ `options.plugins.zoom: false` — Chart.js's documented per-chart plugin
134
+ opt-out — beats `chartZoom`: the plugin is never downloaded and the toolbar
135
+ offers no controls.
136
+ - **`MCPUIConfig.chartZoom`**: `'expanded'` (default), `'always'` or `'never'`.
137
+ - Four string keys: `zoomIn`, `zoomOut`, `zoomReset`, `zoomLevel`
138
+ (`'Zoom {percent}%'`). Chrome key count 271 → 275.
139
+
140
+ ### Changed
141
+
142
+ > **Superseded by 6.22.1.** Making the fields of the published `MCPUIConfig`
143
+ > optional broke every consumer that *reads* one. 6.22.1 moves the optional
144
+ > fields to a new `MCPUIConfigInput` and restores `MCPUIConfig` as the
145
+ > resolved type. The entry below describes 6.22.0 as published.
146
+
147
+ - **Every `MCPUIConfig` field is now optional**, as `MCPUIStrings` has always
148
+ been. `MCPUIConfig` grows a key in a minor release each time the library
149
+ gains a policy switch — `iframeFallbackLink` in 6.21.0, `chartZoom` here —
150
+ and while the fields were required, each addition broke the build of anyone
151
+ holding a *complete* config: a typed constant, a helper returning one, or a
152
+ direct `<MCPUIConfigContext.Provider value={…}>`. Nothing about their
153
+ behaviour had changed; only `tsc` failed. Adding a key is additive now.
154
+
155
+ The completeness guarantee moved onto the values: `DEFAULT_MCPUI_CONFIG` is
156
+ typed `Required<MCPUIConfig>` (a new key without a default is a compile error
157
+ in the library), and `useMCPUIConfig()` returns `Required<MCPUIConfig>`, so
158
+ every renderer still reads a fully resolved policy and never null-checks one.
159
+ `MCPUIConfigContext` itself stays typed `MCPUIConfig`, which makes providing
160
+ it directly *more* permissive than before. Backward compatible in both
161
+ directions: a consumer already passing a field still type-checks.
162
+
163
+ ### Fixed
164
+
165
+ - **`ExpandableWrapper` no longer closes on a drag released over its backdrop.**
166
+ When a press and its release have different targets the browser dispatches
167
+ `click` on their nearest common ancestor — the backdrop — so panning a zoomed
168
+ chart, or selecting text in an expanded table, and releasing over the 16px
169
+ margin around the panel tore the modal down mid-gesture. The close now
170
+ requires the gesture to have *begun* on the backdrop. This was reachable
171
+ before this release for any drag inside an expanded view; chart panning just
172
+ made it easy to hit.
173
+
174
+ ### Not affected
175
+
176
+ Maps and graphs already zoomed: `MapRenderer` enables Leaflet's
177
+ `scrollWheelZoom` and `GraphRenderer` registers G6's `zoom-canvas` /
178
+ `drag-canvas`. Iframes (including a diagram served from `mermaid.ink`) are
179
+ cross-origin documents and cannot be transformed by the host at all.
180
+
8
181
  ## [6.21.0] - 2026-09-17
9
182
 
10
183
  The library's iframes now work on a host that serves
package/README.md CHANGED
@@ -5,6 +5,65 @@ SolidJS components + chat toolkit for MCP-generated UI. Part of the [MCP UI ecos
5
5
  [![npm version](https://img.shields.io/npm/v/@seed-ship/mcp-ui-solid.svg)](https://www.npmjs.com/package/@seed-ship/mcp-ui-solid)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
+ ## What's New in v6.23.0
9
+
10
+ Opt-in LaTeX in markdown text components and table cells, with the same
11
+ currency guards and sanitized MathML output. No change without a provider;
12
+ `MCPUIConfig` is unchanged. See [Math rendering](#math-rendering).
13
+
14
+ ## Math rendering
15
+
16
+ Install the optional peer only if the host wants the supplied KaTeX adapter:
17
+
18
+ ```bash
19
+ pnpm add --save-exact katex@0.18.4
20
+ ```
21
+
22
+ ```tsx
23
+ import { MCPUIMathProvider, UIResourceRenderer } from '@seed-ship/mcp-ui-solid'
24
+ import { renderKatexMath } from '@seed-ship/mcp-ui-solid/plugins/katex'
25
+
26
+ <MCPUIMathProvider renderMath={renderKatexMath}>
27
+ <UIResourceRenderer content={resource} />
28
+ </MCPUIMathProvider>
29
+ ```
30
+
31
+ The adapter's optional peer is pinned to 0.18.4 to retain Node 20 installation
32
+ compatibility. KaTeX 0.18.5–0.18.7 pull in Commander 15 (Node >=22.12);
33
+ do not replace the pin with a caret range on Node 20.
34
+
35
+ The provider applies to `text` with `markdown: true` and string-valued table
36
+ cells, including virtualized rows. It recognizes `$...$` inline and `$$...$$`
37
+ display formulas in their own paragraph (not embedded mid-sentence).
38
+ Code spans/fences and link destinations are not formulas;
39
+ currency such as `$5` and `$5-$10` remains text. Malformed/incomplete formulas
40
+ degrade to their source. Copy/export continues to use the original data.
41
+ Dollar syntax can be ambiguous: `$5$` is a formula. Escape a literal dollar
42
+ as `\$` when composing currency and formulas; numeric math such as `$2 + 3$`
43
+ remains supported. Math-enabled cell links keep their existing new-tab behavior.
44
+
45
+ The adapter emits **MathML only**: no KaTeX stylesheet, fonts, CDN requests,
46
+ HTML layout or inline styles. Native MathML rendering varies by browser and
47
+ may differ from the chat's HTML+MathML layout. There is no automatic loading:
48
+ the explicit plugin import is the opt-in dependency boundary; hosts can load
49
+ that module before mounting the provider if they want a separate chunk.
50
+
51
+ Alternatively pass a synchronous `MathRenderer` function returning MathML
52
+ (`(tex, { displayMode }) => string | null`). The library still sanitizes it;
53
+ return `null` or throw to retain literal source. Passing `null` (or omitting
54
+ `renderMath`) on a nested provider disables inherited math. Arbitrary Marked
55
+ extensions and sanitizer overrides are deliberately not public API.
56
+
57
+ On the server, escaped source is emitted without calling the renderer. The
58
+ existing `SafeHtml` client upgrade renders sanitized formulas after hydration.
59
+ Processing is bounded to 100,000 source characters, 4,096 per expression and
60
+ 128 expressions per parse; oversized input stays escaped text. The adapter
61
+ also limits macro expansion and dimensions, disables trusted commands, and
62
+ does not share macro definitions across formulas. TeX annotation subtrees are
63
+ removed rather than exposing duplicate source after sanitization.
64
+
65
+ See the [design and integration handoff](./docs/briefs/LATEX-MATHML-2026-09-18.md).
66
+
8
67
  ## What's New in v6.21.0
9
68
 
10
69
  - **Iframes work under `Cross-Origin-Embedder-Policy: credentialless`.** Both
@@ -1029,6 +1088,48 @@ import { MCPUIConfigProvider } from '@seed-ship/mcp-ui-solid'
1029
1088
  </MCPUIConfigProvider>
1030
1089
  ```
1031
1090
 
1091
+ When you keep a partial configuration in a variable, name the authored,
1092
+ all-optional view explicitly:
1093
+
1094
+ ```tsx
1095
+ import {
1096
+ MCPUIConfigProvider,
1097
+ type MCPUIConfigInput,
1098
+ } from '@seed-ship/mcp-ui-solid'
1099
+
1100
+ const config: MCPUIConfigInput = {
1101
+ iframeCredentialless: 'always',
1102
+ chartZoom: 'never',
1103
+ }
1104
+
1105
+ <MCPUIConfigProvider config={config}>
1106
+ <App />
1107
+ </MCPUIConfigProvider>
1108
+ ```
1109
+
1110
+ Prefer `MCPUIConfigProvider` for partial overrides. The exported raw context is
1111
+ also a public read surface, so its `Provider` requires the complete, resolved
1112
+ `MCPUIConfig` value. If an integration must provide that context directly,
1113
+ spread the defaults first:
1114
+
1115
+ ```tsx
1116
+ import {
1117
+ DEFAULT_MCPUI_CONFIG,
1118
+ MCPUIConfigContext,
1119
+ } from '@seed-ship/mcp-ui-solid'
1120
+
1121
+ <MCPUIConfigContext.Provider
1122
+ value={{ ...DEFAULT_MCPUI_CONFIG, iframeCredentialless: 'always' }}
1123
+ >
1124
+ <App />
1125
+ </MCPUIConfigContext.Provider>
1126
+ ```
1127
+
1128
+ `MCPUIConfigInput` contains the library's built-in authoring fields.
1129
+ `MCPUIConfig` remains an interface for consumers that extend or augment the
1130
+ resolved contract; `MCPUIConfigProvider` also accepts those augmented fields
1131
+ as partial inline overrides.
1132
+
1032
1133
  | Option | Values | Default | What it does |
1033
1134
  |--------|--------|---------|--------------|
1034
1135
  | `iframeCredentialless` | `'auto'` \| `'always'` \| `'never'` | `'auto'` | `'auto'`: the attribute on the `iframe` component when its host is **not** in `TRUSTED_IFRAME_DOMAINS` (+ `customTrustedIframeDomains`) — those frames already run without cookies. The video embed is excluded, since it has none of that sandboxing. `'always'`: every iframe, video and trusted hosts included — what a COEP host wants. `'never'`: none. |
@@ -1966,6 +2067,7 @@ import type {
1966
2067
  IframePolicy, ValidationOptions,
1967
2068
  CitationCtx, CitationEntry, DuplicateMountInfo, DuplicateMountReporter,
1968
2069
  MCPUIStrings, MCPUIConfig, // v6.21.0
2070
+ MCPUIConfigInput, // v6.22.1 — the authored, all-optional view
1969
2071
  TelemetryEvent, TelemetrySink, TelemetryOptions, TelemetryDispatcher,
1970
2072
  DataValidation, HallucinatedNumber, DataValidationOptions,
1971
2073
  VerifiedTextContent, DataPreviewContent, MapSectionContent,