@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
@@ -7,7 +7,8 @@ const DEFAULT_MCPUI_CONFIG = {
7
7
  customTrustedIframeDomains: [],
8
8
  iframePolicy: "strict",
9
9
  customIframeDomains: [],
10
- iframeFallbackLink: "auto"
10
+ iframeFallbackLink: "auto",
11
+ chartZoom: "expanded"
11
12
  };
12
13
  const MCPUIConfigContext = solidJs.createContext(DEFAULT_MCPUI_CONFIG);
13
14
  function useMCPUIConfig() {
@@ -1 +1 @@
1
- {"version":3,"file":"MCPUIConfigContext.cjs","sources":["../../src/context/MCPUIConfigContext.tsx"],"sourcesContent":["/**\n * MCPUIConfigContext — host-level rendering policy for the library's iframes.\n *\n * @since v6.21.0\n *\n * ## Why\n *\n * A host that serves `Cross-Origin-Embedder-Policy: credentialless` makes the\n * browser refuse every cross-origin iframe whose own document does not send a\n * COEP header — which is YouTube, Vimeo, Google Docs, Notion and nearly all of\n * `DEFAULT_IFRAME_DOMAINS`. The escape hatch is the boolean HTML attribute\n * `credentialless` on the `<iframe>` itself: the document then loads, but\n * without access to the cookies and storage of its own origin.\n *\n * That trade-off is free for a public video or chart and fatal for an\n * authenticated embed, so the library keys it on the distinction it already\n * makes: `TRUSTED_IFRAME_DOMAINS` (the hosts that receive `allow-same-origin`\n * because they need their own cookies) do NOT get the attribute; everything\n * else does. This context lets a host override that, add its own trusted\n * hosts, and control the \"open in a new tab\" fallback link.\n *\n * ## Scope — policy only, NOT strings\n *\n * Text lives in `MCPUIStrings` (`MCPUIStringsContext`). This context carries\n * only behavioural switches, and like the strings context every renderer works\n * standalone: with no provider mounted, `DEFAULT_MCPUI_CONFIG` applies.\n *\n * @example\n * ```tsx\n * import { MCPUIConfigProvider } from '@seed-ship/mcp-ui-solid'\n *\n * <MCPUIConfigProvider config={{ customTrustedIframeDomains: ['embed.acme.com'] }}>\n * <App />\n * </MCPUIConfigProvider>\n * ```\n */\n\nimport { createContext, mergeProps, useContext, type JSX } from 'solid-js'\nimport type { IframePolicy } from '../types'\n\n/**\n * Host-level rendering policy. Every field has a default — a provider passes\n * a partial override.\n */\nexport interface MCPUIConfig {\n /**\n * When the library puts the boolean `credentialless` attribute on an\n * `<iframe>` it renders.\n *\n * - `'auto'` (default) — on every iframe whose host is NOT in\n * `TRUSTED_IFRAME_DOMAINS` (plus `customTrustedIframeDomains`). Those\n * hosts already ran without cookies, since their sandbox has no\n * `allow-same-origin`; the attribute is what unblocks them under COEP.\n * - `'always'` — on every iframe, trusted hosts included. An authenticated\n * embed will then render its login screen.\n * - `'never'` — never. The right value for a host that sends no COEP header\n * and does not want its embeds to lose their cookies.\n *\n * Chrome/Edge 110+ honour the attribute; Firefox ignores it (iframes stay\n * blocked while the host sends COEP); Safari ignores the COEP value itself,\n * so nothing is blocked there in the first place.\n */\n iframeCredentialless: 'auto' | 'always' | 'never'\n\n /**\n * Extra hosts treated as trusted, on top of `TRUSTED_IFRAME_DOMAINS`:\n * no `credentialless` attribute, and `allow-same-origin` in the sandbox.\n * A subdomain of a listed host matches too.\n *\n * This only RECLASSIFIES a host the allow-list already accepts. To render an\n * iframe whose host is outside `DEFAULT_IFRAME_DOMAINS`, add it to\n * {@link MCPUIConfig.customIframeDomains} with `iframePolicy: 'extend'`.\n */\n customTrustedIframeDomains: string[]\n\n /**\n * How `UIResourceRenderer` validates an `iframe` component's host:\n * `'strict'` (default) accepts `DEFAULT_IFRAME_DOMAINS` only, `'extend'`\n * also accepts {@link MCPUIConfig.customIframeDomains}.\n */\n iframePolicy: IframePolicy\n\n /**\n * Extra hosts the allow-list accepts when `iframePolicy` is `'extend'`.\n * Without this, a component pointing at an unlisted host is replaced by the\n * validation card before any renderer runs.\n */\n customIframeDomains: string[]\n\n /**\n * When the library renders an \"open in a new tab\" link under an embed\n * (`strings.iframeOpenInNewTab`).\n *\n * A COEP-blocked iframe fires no event the parent page can observe, so\n * without this the user sees an unexplained blank frame.\n *\n * - `'auto'` (default) — only when the page is cross-origin isolated\n * (`window.crossOriginIsolated`). That flag needs COOP `same-origin` AND\n * COEP, so a host that sends COEP alone still blocks embeds while the\n * flag is false: set `'always'` there. Read after mount, never during\n * render, so SSR markup and hydration agree.\n * - `'always'` / `'never'` — unconditional.\n */\n iframeFallbackLink: 'auto' | 'always' | 'never'\n}\n\n/**\n * Defaults. Chosen so a host that sends no COEP header sees no change from\n * 6.20.0 apart from the fallback link, which `'auto'` keeps hidden there.\n */\nexport const DEFAULT_MCPUI_CONFIG: MCPUIConfig = {\n iframeCredentialless: 'auto',\n customTrustedIframeDomains: [],\n iframePolicy: 'strict',\n customIframeDomains: [],\n iframeFallbackLink: 'auto',\n}\n\nexport const MCPUIConfigContext = createContext<MCPUIConfig>(DEFAULT_MCPUI_CONFIG)\n\n/**\n * Reads the active host config. Returns `DEFAULT_MCPUI_CONFIG` when no\n * `<MCPUIConfigProvider>` is mounted above.\n */\nexport function useMCPUIConfig(): MCPUIConfig {\n return mergeProps(DEFAULT_MCPUI_CONFIG, useContext(MCPUIConfigContext))\n}\n\nexport interface MCPUIConfigProviderProps {\n /**\n * Partial override of the host config. Any key left unset falls back to\n * `DEFAULT_MCPUI_CONFIG`.\n */\n config?: Partial<MCPUIConfig>\n children: JSX.Element\n}\n\n/**\n * Provides the host config to every MCP-UI renderer below it.\n * Merges the partial `config` override over the defaults.\n */\nexport function MCPUIConfigProvider(props: MCPUIConfigProviderProps): JSX.Element {\n // The function source keeps replacement `config` objects reactive while\n // mergeProps fills any omitted key without taking a one-time snapshot.\n const value = mergeProps(DEFAULT_MCPUI_CONFIG, () => props.config)\n return (\n <MCPUIConfigContext.Provider value={value}>\n {props.children}\n </MCPUIConfigContext.Provider>\n )\n}\n"],"names":["DEFAULT_MCPUI_CONFIG","iframeCredentialless","customTrustedIframeDomains","iframePolicy","customIframeDomains","iframeFallbackLink","MCPUIConfigContext","createContext","useMCPUIConfig","mergeProps","useContext","MCPUIConfigProvider","props","value","config","_$createComponent","Provider","children"],"mappings":";;;;AA8GO,MAAMA,uBAAoC;AAAA,EAC/CC,sBAAsB;AAAA,EACtBC,4BAA4B,CAAA;AAAA,EAC5BC,cAAc;AAAA,EACdC,qBAAqB,CAAA;AAAA,EACrBC,oBAAoB;AACtB;AAEO,MAAMC,qBAAqBC,QAAAA,cAA2BP,oBAAoB;AAM1E,SAASQ,iBAA8B;AAC5C,SAAOC,mBAAWT,sBAAsBU,QAAAA,WAAWJ,kBAAkB,CAAC;AACxE;AAeO,SAASK,oBAAoBC,OAA8C;AAGhF,QAAMC,QAAQJ,QAAAA,WAAWT,sBAAsB,MAAMY,MAAME,MAAM;AACjE,SAAAC,IAAAA,gBACGT,mBAAmBU,UAAQ;AAAA,IAACH;AAAAA,IAAY,IAAAI,WAAA;AAAA,aACtCL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;;;;;"}
1
+ {"version":3,"file":"MCPUIConfigContext.cjs","sources":["../../src/context/MCPUIConfigContext.tsx"],"sourcesContent":["/**\n * MCPUIConfigContext — host-level rendering policy: the library's iframes\n * (v6.21.0) and, since v6.22.0, where a chart may capture the wheel.\n *\n * @since v6.21.0\n *\n * ## Why\n *\n * A host that serves `Cross-Origin-Embedder-Policy: credentialless` makes the\n * browser refuse every cross-origin iframe whose own document does not send a\n * COEP header — which is YouTube, Vimeo, Google Docs, Notion and nearly all of\n * `DEFAULT_IFRAME_DOMAINS`. The escape hatch is the boolean HTML attribute\n * `credentialless` on the `<iframe>` itself: the document then loads, but\n * without access to the cookies and storage of its own origin.\n *\n * That trade-off is free for a public video or chart and fatal for an\n * authenticated embed, so the library keys it on the distinction it already\n * makes: `TRUSTED_IFRAME_DOMAINS` (the hosts that receive `allow-same-origin`\n * because they need their own cookies) do NOT get the attribute; everything\n * else does. This context lets a host override that, add its own trusted\n * hosts, and control the \"open in a new tab\" fallback link.\n *\n * ## Scope — policy only, NOT strings\n *\n * Text lives in `MCPUIStrings` (`MCPUIStringsContext`). This context carries\n * only behavioural switches, and like the strings context every renderer works\n * standalone: with no provider mounted, `DEFAULT_MCPUI_CONFIG` applies.\n *\n * @example\n * ```tsx\n * import { MCPUIConfigProvider } from '@seed-ship/mcp-ui-solid'\n *\n * <MCPUIConfigProvider config={{ customTrustedIframeDomains: ['embed.acme.com'] }}>\n * <App />\n * </MCPUIConfigProvider>\n * ```\n */\n\nimport { createContext, mergeProps, useContext, type JSX } from 'solid-js'\nimport type { IframePolicy } from '../types'\n\n/**\n * Host-level rendering policy. Every field has a default — a provider passes\n * a partial override.\n *\n * ## Two names, because there are two jobs\n *\n * This type grows a key every time the library gains a policy switch, and\n * those releases are MINOR — so neither AUTHORING a config nor READING one\n * may break when a key appears. Those two demands pull in opposite\n * directions, and one name cannot serve both:\n *\n * - an author must be allowed to omit the new key, so the fields they write\n * have to be OPTIONAL;\n * - a reader assigning `const p: IframePolicy = config.iframePolicy` must not\n * suddenly face `undefined`, so the fields they read have to be REQUIRED.\n *\n * Hence {@link MCPUIConfigInput} (what a host writes — every field optional)\n * and {@link MCPUIConfig} (what the library hands back — every field\n * resolved). `MCPUIConfig` is derived from the input type, so the two can\n * never drift and a key is declared exactly once.\n *\n * Which one you name depends on the surface:\n *\n * - `<MCPUIConfigProvider config={…}>` takes `MCPUIConfigInput` — name that\n * type for a partial you build, and it merges the rest;\n * - `<MCPUIConfigContext.Provider value={…}>` takes the RESOLVED\n * `MCPUIConfig`, because that context is read as well as written, so a\n * direct provider hands over `{ ...DEFAULT_MCPUI_CONFIG, ...mine }`;\n * - anything you RECEIVE is `MCPUIConfig`, which is what\n * {@link useMCPUIConfig} returns.\n */\nexport interface MCPUIConfigInput {\n /**\n * When the library puts the boolean `credentialless` attribute on an\n * `<iframe>` it renders.\n *\n * - `'auto'` (default) — on every iframe whose host is NOT in\n * `TRUSTED_IFRAME_DOMAINS` (plus `customTrustedIframeDomains`). Those\n * hosts already ran without cookies, since their sandbox has no\n * `allow-same-origin`; the attribute is what unblocks them under COEP.\n * - `'always'` — on every iframe, trusted hosts included. An authenticated\n * embed will then render its login screen.\n * - `'never'` — never. The right value for a host that sends no COEP header\n * and does not want its embeds to lose their cookies.\n *\n * Chrome/Edge 110+ honour the attribute; Firefox ignores it (iframes stay\n * blocked while the host sends COEP); Safari ignores the COEP value itself,\n * so nothing is blocked there in the first place.\n */\n iframeCredentialless?: 'auto' | 'always' | 'never'\n\n /**\n * Extra hosts treated as trusted, on top of `TRUSTED_IFRAME_DOMAINS`:\n * no `credentialless` attribute, and `allow-same-origin` in the sandbox.\n * A subdomain of a listed host matches too.\n *\n * This only RECLASSIFIES a host the allow-list already accepts. To render an\n * iframe whose host is outside `DEFAULT_IFRAME_DOMAINS`, add it to\n * {@link MCPUIConfigInput.customIframeDomains} with `iframePolicy: 'extend'`.\n */\n customTrustedIframeDomains?: string[]\n\n /**\n * How `UIResourceRenderer` validates an `iframe` component's host:\n * `'strict'` (default) accepts `DEFAULT_IFRAME_DOMAINS` only, `'extend'`\n * also accepts {@link MCPUIConfigInput.customIframeDomains}.\n */\n iframePolicy?: IframePolicy\n\n /**\n * Extra hosts the allow-list accepts when `iframePolicy` is `'extend'`.\n * Without this, a component pointing at an unlisted host is replaced by the\n * validation card before any renderer runs.\n */\n customIframeDomains?: string[]\n\n /**\n * When the library renders an \"open in a new tab\" link under an embed\n * (`strings.iframeOpenInNewTab`).\n *\n * A COEP-blocked iframe fires no event the parent page can observe, so\n * without this the user sees an unexplained blank frame.\n *\n * - `'auto'` (default) — only when the page is cross-origin isolated\n * (`window.crossOriginIsolated`). That flag needs COOP `same-origin` AND\n * COEP, so a host that sends COEP alone still blocks embeds while the\n * flag is false: set `'always'` there. Read after mount, never during\n * render, so SSR markup and hydration agree.\n * - `'always'` / `'never'` — unconditional.\n */\n iframeFallbackLink?: 'auto' | 'always' | 'never'\n\n /**\n * Where `ChartJSRenderer` enables wheel-zoom / drag-pan / pinch on a chart\n * (through the optional `chartjs-plugin-zoom` peer dependency — absent, the\n * chart renders exactly as it does without this setting).\n *\n * Hijacking the mouse wheel on a component sitting inline in a scrolling\n * chat feed is hostile: the user scrolls the conversation and the chart eats\n * the gesture. So zoom belongs to a surface that OWNS its viewport, which\n * here is `ExpandableWrapper`'s fullscreen modal.\n *\n * - `'expanded'` (default) — only inside the fullscreen modal.\n * - `'always'` — inline as well. For a host that lays charts out in a\n * dashboard rather than in a feed, where the wheel has nothing to steal.\n * - `'never'` — off everywhere; the plugin is never registered.\n *\n * @since 6.22.0\n */\n chartZoom?: 'expanded' | 'always' | 'never'\n}\n\n/**\n * The resolved host policy: every key present. This is what the library hands\n * back, so a reader never null-checks a policy.\n *\n * Extends `Required<`{@link MCPUIConfigInput}`>` rather than declaring the\n * fields again, so a key exists in exactly one place and the two views cannot\n * drift. It remains an interface so existing consumers can extend or augment\n * the public contract as they could before 6.22.0.\n */\nexport interface MCPUIConfig extends Required<MCPUIConfigInput> {}\n\n/**\n * Defaults. Chosen so a host that sends no COEP header sees no change from\n * 6.20.0 apart from the fallback link, which `'auto'` keeps hidden there —\n * and, since 6.22.0, so no inline component ever captures the wheel\n * (`chartZoom: 'expanded'`).\n *\n * Typed `MCPUIConfig` (i.e. resolved): that annotation is what stops a new\n * key from shipping without a default.\n */\nexport const DEFAULT_MCPUI_CONFIG: MCPUIConfig = {\n iframeCredentialless: 'auto',\n customTrustedIframeDomains: [],\n iframePolicy: 'strict',\n customIframeDomains: [],\n iframeFallbackLink: 'auto',\n chartZoom: 'expanded',\n}\n\n/**\n * Typed with the RESOLVED view, because this context is read as well as\n * written: it is exported, so a consumer may call\n * `useContext(MCPUIConfigContext)` directly, and typing it as the input view\n * would hand them `IframePolicy | undefined` — exactly the regression this\n * whole split exists to undo.\n *\n * The cost lands on the rarer side: a host feeding this context directly\n * passes a COMPLETE value, `{ ...DEFAULT_MCPUI_CONFIG, ...mine }`. Anyone who\n * wants to pass only the keys they care about uses `MCPUIConfigProvider`,\n * whose `config` prop takes `Partial<`{@link MCPUIConfig}`>` and does that\n * merge. That preserves optional properties added through declaration\n * merging; {@link MCPUIConfigInput} remains the unaugmented built-in input\n * shape a host can name for ordinary authored configs.\n */\nexport const MCPUIConfigContext = createContext<MCPUIConfig>(DEFAULT_MCPUI_CONFIG)\n\n/**\n * Reads the active host config, resolved: every key is present, whether it\n * came from the provider or from `DEFAULT_MCPUI_CONFIG`. Returns the defaults\n * outright when no `<MCPUIConfigProvider>` is mounted above.\n */\nexport function useMCPUIConfig(): MCPUIConfig {\n return mergeProps(DEFAULT_MCPUI_CONFIG, useContext(MCPUIConfigContext))\n}\n\nexport interface MCPUIConfigProviderProps {\n /**\n * Partial override of the host config. Any key left unset falls back to\n * `DEFAULT_MCPUI_CONFIG`.\n */\n config?: Partial<MCPUIConfig>\n children: JSX.Element\n}\n\n/**\n * Provides the host config to every MCP-UI renderer below it.\n * Merges the partial `config` override over the defaults.\n */\nexport function MCPUIConfigProvider(props: MCPUIConfigProviderProps): JSX.Element {\n // The function source keeps replacement `config` objects reactive while\n // mergeProps fills any omitted key without taking a one-time snapshot.\n const value = mergeProps(DEFAULT_MCPUI_CONFIG, () => props.config)\n return (\n <MCPUIConfigContext.Provider value={value}>\n {props.children}\n </MCPUIConfigContext.Provider>\n )\n}\n"],"names":["DEFAULT_MCPUI_CONFIG","iframeCredentialless","customTrustedIframeDomains","iframePolicy","customIframeDomains","iframeFallbackLink","chartZoom","MCPUIConfigContext","createContext","useMCPUIConfig","mergeProps","useContext","MCPUIConfigProvider","props","value","config","_$createComponent","Provider","children"],"mappings":";;;;AA6KO,MAAMA,uBAAoC;AAAA,EAC/CC,sBAAsB;AAAA,EACtBC,4BAA4B,CAAA;AAAA,EAC5BC,cAAc;AAAA,EACdC,qBAAqB,CAAA;AAAA,EACrBC,oBAAoB;AAAA,EACpBC,WAAW;AACb;AAiBO,MAAMC,qBAAqBC,QAAAA,cAA2BR,oBAAoB;AAO1E,SAASS,iBAA8B;AAC5C,SAAOC,mBAAWV,sBAAsBW,QAAAA,WAAWJ,kBAAkB,CAAC;AACxE;AAeO,SAASK,oBAAoBC,OAA8C;AAGhF,QAAMC,QAAQJ,QAAAA,WAAWV,sBAAsB,MAAMa,MAAME,MAAM;AACjE,SAAAC,IAAAA,gBACGT,mBAAmBU,UAAQ;AAAA,IAACH;AAAAA,IAAY,IAAAI,WAAA;AAAA,aACtCL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;;;;;"}
@@ -1,5 +1,6 @@
1
1
  /**
2
- * MCPUIConfigContext — host-level rendering policy for the library's iframes.
2
+ * MCPUIConfigContext — host-level rendering policy: the library's iframes
3
+ * (v6.21.0) and, since v6.22.0, where a chart may capture the wheel.
3
4
  *
4
5
  * @since v6.21.0
5
6
  *
@@ -39,8 +40,35 @@ import type { IframePolicy } from '../types';
39
40
  /**
40
41
  * Host-level rendering policy. Every field has a default — a provider passes
41
42
  * a partial override.
43
+ *
44
+ * ## Two names, because there are two jobs
45
+ *
46
+ * This type grows a key every time the library gains a policy switch, and
47
+ * those releases are MINOR — so neither AUTHORING a config nor READING one
48
+ * may break when a key appears. Those two demands pull in opposite
49
+ * directions, and one name cannot serve both:
50
+ *
51
+ * - an author must be allowed to omit the new key, so the fields they write
52
+ * have to be OPTIONAL;
53
+ * - a reader assigning `const p: IframePolicy = config.iframePolicy` must not
54
+ * suddenly face `undefined`, so the fields they read have to be REQUIRED.
55
+ *
56
+ * Hence {@link MCPUIConfigInput} (what a host writes — every field optional)
57
+ * and {@link MCPUIConfig} (what the library hands back — every field
58
+ * resolved). `MCPUIConfig` is derived from the input type, so the two can
59
+ * never drift and a key is declared exactly once.
60
+ *
61
+ * Which one you name depends on the surface:
62
+ *
63
+ * - `<MCPUIConfigProvider config={…}>` takes `MCPUIConfigInput` — name that
64
+ * type for a partial you build, and it merges the rest;
65
+ * - `<MCPUIConfigContext.Provider value={…}>` takes the RESOLVED
66
+ * `MCPUIConfig`, because that context is read as well as written, so a
67
+ * direct provider hands over `{ ...DEFAULT_MCPUI_CONFIG, ...mine }`;
68
+ * - anything you RECEIVE is `MCPUIConfig`, which is what
69
+ * {@link useMCPUIConfig} returns.
42
70
  */
43
- export interface MCPUIConfig {
71
+ export interface MCPUIConfigInput {
44
72
  /**
45
73
  * When the library puts the boolean `credentialless` attribute on an
46
74
  * `<iframe>` it renders.
@@ -58,7 +86,7 @@ export interface MCPUIConfig {
58
86
  * blocked while the host sends COEP); Safari ignores the COEP value itself,
59
87
  * so nothing is blocked there in the first place.
60
88
  */
61
- iframeCredentialless: 'auto' | 'always' | 'never';
89
+ iframeCredentialless?: 'auto' | 'always' | 'never';
62
90
  /**
63
91
  * Extra hosts treated as trusted, on top of `TRUSTED_IFRAME_DOMAINS`:
64
92
  * no `credentialless` attribute, and `allow-same-origin` in the sandbox.
@@ -66,21 +94,21 @@ export interface MCPUIConfig {
66
94
  *
67
95
  * This only RECLASSIFIES a host the allow-list already accepts. To render an
68
96
  * iframe whose host is outside `DEFAULT_IFRAME_DOMAINS`, add it to
69
- * {@link MCPUIConfig.customIframeDomains} with `iframePolicy: 'extend'`.
97
+ * {@link MCPUIConfigInput.customIframeDomains} with `iframePolicy: 'extend'`.
70
98
  */
71
- customTrustedIframeDomains: string[];
99
+ customTrustedIframeDomains?: string[];
72
100
  /**
73
101
  * How `UIResourceRenderer` validates an `iframe` component's host:
74
102
  * `'strict'` (default) accepts `DEFAULT_IFRAME_DOMAINS` only, `'extend'`
75
- * also accepts {@link MCPUIConfig.customIframeDomains}.
103
+ * also accepts {@link MCPUIConfigInput.customIframeDomains}.
76
104
  */
77
- iframePolicy: IframePolicy;
105
+ iframePolicy?: IframePolicy;
78
106
  /**
79
107
  * Extra hosts the allow-list accepts when `iframePolicy` is `'extend'`.
80
108
  * Without this, a component pointing at an unlisted host is replaced by the
81
109
  * validation card before any renderer runs.
82
110
  */
83
- customIframeDomains: string[];
111
+ customIframeDomains?: string[];
84
112
  /**
85
113
  * When the library renders an "open in a new tab" link under an embed
86
114
  * (`strings.iframeOpenInNewTab`).
@@ -95,17 +123,67 @@ export interface MCPUIConfig {
95
123
  * render, so SSR markup and hydration agree.
96
124
  * - `'always'` / `'never'` — unconditional.
97
125
  */
98
- iframeFallbackLink: 'auto' | 'always' | 'never';
126
+ iframeFallbackLink?: 'auto' | 'always' | 'never';
127
+ /**
128
+ * Where `ChartJSRenderer` enables wheel-zoom / drag-pan / pinch on a chart
129
+ * (through the optional `chartjs-plugin-zoom` peer dependency — absent, the
130
+ * chart renders exactly as it does without this setting).
131
+ *
132
+ * Hijacking the mouse wheel on a component sitting inline in a scrolling
133
+ * chat feed is hostile: the user scrolls the conversation and the chart eats
134
+ * the gesture. So zoom belongs to a surface that OWNS its viewport, which
135
+ * here is `ExpandableWrapper`'s fullscreen modal.
136
+ *
137
+ * - `'expanded'` (default) — only inside the fullscreen modal.
138
+ * - `'always'` — inline as well. For a host that lays charts out in a
139
+ * dashboard rather than in a feed, where the wheel has nothing to steal.
140
+ * - `'never'` — off everywhere; the plugin is never registered.
141
+ *
142
+ * @since 6.22.0
143
+ */
144
+ chartZoom?: 'expanded' | 'always' | 'never';
145
+ }
146
+ /**
147
+ * The resolved host policy: every key present. This is what the library hands
148
+ * back, so a reader never null-checks a policy.
149
+ *
150
+ * Extends `Required<`{@link MCPUIConfigInput}`>` rather than declaring the
151
+ * fields again, so a key exists in exactly one place and the two views cannot
152
+ * drift. It remains an interface so existing consumers can extend or augment
153
+ * the public contract as they could before 6.22.0.
154
+ */
155
+ export interface MCPUIConfig extends Required<MCPUIConfigInput> {
99
156
  }
100
157
  /**
101
158
  * Defaults. Chosen so a host that sends no COEP header sees no change from
102
- * 6.20.0 apart from the fallback link, which `'auto'` keeps hidden there.
159
+ * 6.20.0 apart from the fallback link, which `'auto'` keeps hidden there —
160
+ * and, since 6.22.0, so no inline component ever captures the wheel
161
+ * (`chartZoom: 'expanded'`).
162
+ *
163
+ * Typed `MCPUIConfig` (i.e. resolved): that annotation is what stops a new
164
+ * key from shipping without a default.
103
165
  */
104
166
  export declare const DEFAULT_MCPUI_CONFIG: MCPUIConfig;
167
+ /**
168
+ * Typed with the RESOLVED view, because this context is read as well as
169
+ * written: it is exported, so a consumer may call
170
+ * `useContext(MCPUIConfigContext)` directly, and typing it as the input view
171
+ * would hand them `IframePolicy | undefined` — exactly the regression this
172
+ * whole split exists to undo.
173
+ *
174
+ * The cost lands on the rarer side: a host feeding this context directly
175
+ * passes a COMPLETE value, `{ ...DEFAULT_MCPUI_CONFIG, ...mine }`. Anyone who
176
+ * wants to pass only the keys they care about uses `MCPUIConfigProvider`,
177
+ * whose `config` prop takes `Partial<`{@link MCPUIConfig}`>` and does that
178
+ * merge. That preserves optional properties added through declaration
179
+ * merging; {@link MCPUIConfigInput} remains the unaugmented built-in input
180
+ * shape a host can name for ordinary authored configs.
181
+ */
105
182
  export declare const MCPUIConfigContext: import("solid-js").Context<MCPUIConfig>;
106
183
  /**
107
- * Reads the active host config. Returns `DEFAULT_MCPUI_CONFIG` when no
108
- * `<MCPUIConfigProvider>` is mounted above.
184
+ * Reads the active host config, resolved: every key is present, whether it
185
+ * came from the provider or from `DEFAULT_MCPUI_CONFIG`. Returns the defaults
186
+ * outright when no `<MCPUIConfigProvider>` is mounted above.
109
187
  */
110
188
  export declare function useMCPUIConfig(): MCPUIConfig;
111
189
  export interface MCPUIConfigProviderProps {
@@ -1 +1 @@
1
- {"version":3,"file":"MCPUIConfigContext.d.ts","sourceRoot":"","sources":["../../src/context/MCPUIConfigContext.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAyC,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;;;;;;;;OAgBG;IACH,oBAAoB,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;IAEjD;;;;;;;;OAQG;IACH,0BAA0B,EAAE,MAAM,EAAE,CAAA;IAEpC;;;;OAIG;IACH,YAAY,EAAE,YAAY,CAAA;IAE1B;;;;OAIG;IACH,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAE7B;;;;;;;;;;;;;OAaG;IACH,kBAAkB,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;CAChD;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAMlC,CAAA;AAED,eAAO,MAAM,kBAAkB,yCAAmD,CAAA;AAElF;;;GAGG;AACH,wBAAgB,cAAc,IAAI,WAAW,CAE5C;AAED,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,CAShF"}
1
+ {"version":3,"file":"MCPUIConfigContext.d.ts","sourceRoot":"","sources":["../../src/context/MCPUIConfigContext.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAyC,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;;;;;;;OAgBG;IACH,oBAAoB,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;IAElD;;;;;;;;OAQG;IACH,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAA;IAErC;;;;OAIG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;IAE3B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;IAE9B;;;;;;;;;;;;;OAaG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;IAEhD;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;CAC5C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAY,SAAQ,QAAQ,CAAC,gBAAgB,CAAC;CAAG;AAElE;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAOlC,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,yCAAmD,CAAA;AAElF;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,WAAW,CAE5C;AAED,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC7B,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,CAShF"}
@@ -5,7 +5,8 @@ const DEFAULT_MCPUI_CONFIG = {
5
5
  customTrustedIframeDomains: [],
6
6
  iframePolicy: "strict",
7
7
  customIframeDomains: [],
8
- iframeFallbackLink: "auto"
8
+ iframeFallbackLink: "auto",
9
+ chartZoom: "expanded"
9
10
  };
10
11
  const MCPUIConfigContext = createContext(DEFAULT_MCPUI_CONFIG);
11
12
  function useMCPUIConfig() {
@@ -1 +1 @@
1
- {"version":3,"file":"MCPUIConfigContext.js","sources":["../../src/context/MCPUIConfigContext.tsx"],"sourcesContent":["/**\n * MCPUIConfigContext — host-level rendering policy for the library's iframes.\n *\n * @since v6.21.0\n *\n * ## Why\n *\n * A host that serves `Cross-Origin-Embedder-Policy: credentialless` makes the\n * browser refuse every cross-origin iframe whose own document does not send a\n * COEP header — which is YouTube, Vimeo, Google Docs, Notion and nearly all of\n * `DEFAULT_IFRAME_DOMAINS`. The escape hatch is the boolean HTML attribute\n * `credentialless` on the `<iframe>` itself: the document then loads, but\n * without access to the cookies and storage of its own origin.\n *\n * That trade-off is free for a public video or chart and fatal for an\n * authenticated embed, so the library keys it on the distinction it already\n * makes: `TRUSTED_IFRAME_DOMAINS` (the hosts that receive `allow-same-origin`\n * because they need their own cookies) do NOT get the attribute; everything\n * else does. This context lets a host override that, add its own trusted\n * hosts, and control the \"open in a new tab\" fallback link.\n *\n * ## Scope — policy only, NOT strings\n *\n * Text lives in `MCPUIStrings` (`MCPUIStringsContext`). This context carries\n * only behavioural switches, and like the strings context every renderer works\n * standalone: with no provider mounted, `DEFAULT_MCPUI_CONFIG` applies.\n *\n * @example\n * ```tsx\n * import { MCPUIConfigProvider } from '@seed-ship/mcp-ui-solid'\n *\n * <MCPUIConfigProvider config={{ customTrustedIframeDomains: ['embed.acme.com'] }}>\n * <App />\n * </MCPUIConfigProvider>\n * ```\n */\n\nimport { createContext, mergeProps, useContext, type JSX } from 'solid-js'\nimport type { IframePolicy } from '../types'\n\n/**\n * Host-level rendering policy. Every field has a default — a provider passes\n * a partial override.\n */\nexport interface MCPUIConfig {\n /**\n * When the library puts the boolean `credentialless` attribute on an\n * `<iframe>` it renders.\n *\n * - `'auto'` (default) — on every iframe whose host is NOT in\n * `TRUSTED_IFRAME_DOMAINS` (plus `customTrustedIframeDomains`). Those\n * hosts already ran without cookies, since their sandbox has no\n * `allow-same-origin`; the attribute is what unblocks them under COEP.\n * - `'always'` — on every iframe, trusted hosts included. An authenticated\n * embed will then render its login screen.\n * - `'never'` — never. The right value for a host that sends no COEP header\n * and does not want its embeds to lose their cookies.\n *\n * Chrome/Edge 110+ honour the attribute; Firefox ignores it (iframes stay\n * blocked while the host sends COEP); Safari ignores the COEP value itself,\n * so nothing is blocked there in the first place.\n */\n iframeCredentialless: 'auto' | 'always' | 'never'\n\n /**\n * Extra hosts treated as trusted, on top of `TRUSTED_IFRAME_DOMAINS`:\n * no `credentialless` attribute, and `allow-same-origin` in the sandbox.\n * A subdomain of a listed host matches too.\n *\n * This only RECLASSIFIES a host the allow-list already accepts. To render an\n * iframe whose host is outside `DEFAULT_IFRAME_DOMAINS`, add it to\n * {@link MCPUIConfig.customIframeDomains} with `iframePolicy: 'extend'`.\n */\n customTrustedIframeDomains: string[]\n\n /**\n * How `UIResourceRenderer` validates an `iframe` component's host:\n * `'strict'` (default) accepts `DEFAULT_IFRAME_DOMAINS` only, `'extend'`\n * also accepts {@link MCPUIConfig.customIframeDomains}.\n */\n iframePolicy: IframePolicy\n\n /**\n * Extra hosts the allow-list accepts when `iframePolicy` is `'extend'`.\n * Without this, a component pointing at an unlisted host is replaced by the\n * validation card before any renderer runs.\n */\n customIframeDomains: string[]\n\n /**\n * When the library renders an \"open in a new tab\" link under an embed\n * (`strings.iframeOpenInNewTab`).\n *\n * A COEP-blocked iframe fires no event the parent page can observe, so\n * without this the user sees an unexplained blank frame.\n *\n * - `'auto'` (default) — only when the page is cross-origin isolated\n * (`window.crossOriginIsolated`). That flag needs COOP `same-origin` AND\n * COEP, so a host that sends COEP alone still blocks embeds while the\n * flag is false: set `'always'` there. Read after mount, never during\n * render, so SSR markup and hydration agree.\n * - `'always'` / `'never'` — unconditional.\n */\n iframeFallbackLink: 'auto' | 'always' | 'never'\n}\n\n/**\n * Defaults. Chosen so a host that sends no COEP header sees no change from\n * 6.20.0 apart from the fallback link, which `'auto'` keeps hidden there.\n */\nexport const DEFAULT_MCPUI_CONFIG: MCPUIConfig = {\n iframeCredentialless: 'auto',\n customTrustedIframeDomains: [],\n iframePolicy: 'strict',\n customIframeDomains: [],\n iframeFallbackLink: 'auto',\n}\n\nexport const MCPUIConfigContext = createContext<MCPUIConfig>(DEFAULT_MCPUI_CONFIG)\n\n/**\n * Reads the active host config. Returns `DEFAULT_MCPUI_CONFIG` when no\n * `<MCPUIConfigProvider>` is mounted above.\n */\nexport function useMCPUIConfig(): MCPUIConfig {\n return mergeProps(DEFAULT_MCPUI_CONFIG, useContext(MCPUIConfigContext))\n}\n\nexport interface MCPUIConfigProviderProps {\n /**\n * Partial override of the host config. Any key left unset falls back to\n * `DEFAULT_MCPUI_CONFIG`.\n */\n config?: Partial<MCPUIConfig>\n children: JSX.Element\n}\n\n/**\n * Provides the host config to every MCP-UI renderer below it.\n * Merges the partial `config` override over the defaults.\n */\nexport function MCPUIConfigProvider(props: MCPUIConfigProviderProps): JSX.Element {\n // The function source keeps replacement `config` objects reactive while\n // mergeProps fills any omitted key without taking a one-time snapshot.\n const value = mergeProps(DEFAULT_MCPUI_CONFIG, () => props.config)\n return (\n <MCPUIConfigContext.Provider value={value}>\n {props.children}\n </MCPUIConfigContext.Provider>\n )\n}\n"],"names":["DEFAULT_MCPUI_CONFIG","iframeCredentialless","customTrustedIframeDomains","iframePolicy","customIframeDomains","iframeFallbackLink","MCPUIConfigContext","createContext","useMCPUIConfig","mergeProps","useContext","MCPUIConfigProvider","props","value","config","_$createComponent","Provider","children"],"mappings":";;AA8GO,MAAMA,uBAAoC;AAAA,EAC/CC,sBAAsB;AAAA,EACtBC,4BAA4B,CAAA;AAAA,EAC5BC,cAAc;AAAA,EACdC,qBAAqB,CAAA;AAAA,EACrBC,oBAAoB;AACtB;AAEO,MAAMC,qBAAqBC,cAA2BP,oBAAoB;AAM1E,SAASQ,iBAA8B;AAC5C,SAAOC,WAAWT,sBAAsBU,WAAWJ,kBAAkB,CAAC;AACxE;AAeO,SAASK,oBAAoBC,OAA8C;AAGhF,QAAMC,QAAQJ,WAAWT,sBAAsB,MAAMY,MAAME,MAAM;AACjE,SAAAC,gBACGT,mBAAmBU,UAAQ;AAAA,IAACH;AAAAA,IAAY,IAAAI,WAAA;AAAA,aACtCL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;"}
1
+ {"version":3,"file":"MCPUIConfigContext.js","sources":["../../src/context/MCPUIConfigContext.tsx"],"sourcesContent":["/**\n * MCPUIConfigContext — host-level rendering policy: the library's iframes\n * (v6.21.0) and, since v6.22.0, where a chart may capture the wheel.\n *\n * @since v6.21.0\n *\n * ## Why\n *\n * A host that serves `Cross-Origin-Embedder-Policy: credentialless` makes the\n * browser refuse every cross-origin iframe whose own document does not send a\n * COEP header — which is YouTube, Vimeo, Google Docs, Notion and nearly all of\n * `DEFAULT_IFRAME_DOMAINS`. The escape hatch is the boolean HTML attribute\n * `credentialless` on the `<iframe>` itself: the document then loads, but\n * without access to the cookies and storage of its own origin.\n *\n * That trade-off is free for a public video or chart and fatal for an\n * authenticated embed, so the library keys it on the distinction it already\n * makes: `TRUSTED_IFRAME_DOMAINS` (the hosts that receive `allow-same-origin`\n * because they need their own cookies) do NOT get the attribute; everything\n * else does. This context lets a host override that, add its own trusted\n * hosts, and control the \"open in a new tab\" fallback link.\n *\n * ## Scope — policy only, NOT strings\n *\n * Text lives in `MCPUIStrings` (`MCPUIStringsContext`). This context carries\n * only behavioural switches, and like the strings context every renderer works\n * standalone: with no provider mounted, `DEFAULT_MCPUI_CONFIG` applies.\n *\n * @example\n * ```tsx\n * import { MCPUIConfigProvider } from '@seed-ship/mcp-ui-solid'\n *\n * <MCPUIConfigProvider config={{ customTrustedIframeDomains: ['embed.acme.com'] }}>\n * <App />\n * </MCPUIConfigProvider>\n * ```\n */\n\nimport { createContext, mergeProps, useContext, type JSX } from 'solid-js'\nimport type { IframePolicy } from '../types'\n\n/**\n * Host-level rendering policy. Every field has a default — a provider passes\n * a partial override.\n *\n * ## Two names, because there are two jobs\n *\n * This type grows a key every time the library gains a policy switch, and\n * those releases are MINOR — so neither AUTHORING a config nor READING one\n * may break when a key appears. Those two demands pull in opposite\n * directions, and one name cannot serve both:\n *\n * - an author must be allowed to omit the new key, so the fields they write\n * have to be OPTIONAL;\n * - a reader assigning `const p: IframePolicy = config.iframePolicy` must not\n * suddenly face `undefined`, so the fields they read have to be REQUIRED.\n *\n * Hence {@link MCPUIConfigInput} (what a host writes — every field optional)\n * and {@link MCPUIConfig} (what the library hands back — every field\n * resolved). `MCPUIConfig` is derived from the input type, so the two can\n * never drift and a key is declared exactly once.\n *\n * Which one you name depends on the surface:\n *\n * - `<MCPUIConfigProvider config={…}>` takes `MCPUIConfigInput` — name that\n * type for a partial you build, and it merges the rest;\n * - `<MCPUIConfigContext.Provider value={…}>` takes the RESOLVED\n * `MCPUIConfig`, because that context is read as well as written, so a\n * direct provider hands over `{ ...DEFAULT_MCPUI_CONFIG, ...mine }`;\n * - anything you RECEIVE is `MCPUIConfig`, which is what\n * {@link useMCPUIConfig} returns.\n */\nexport interface MCPUIConfigInput {\n /**\n * When the library puts the boolean `credentialless` attribute on an\n * `<iframe>` it renders.\n *\n * - `'auto'` (default) — on every iframe whose host is NOT in\n * `TRUSTED_IFRAME_DOMAINS` (plus `customTrustedIframeDomains`). Those\n * hosts already ran without cookies, since their sandbox has no\n * `allow-same-origin`; the attribute is what unblocks them under COEP.\n * - `'always'` — on every iframe, trusted hosts included. An authenticated\n * embed will then render its login screen.\n * - `'never'` — never. The right value for a host that sends no COEP header\n * and does not want its embeds to lose their cookies.\n *\n * Chrome/Edge 110+ honour the attribute; Firefox ignores it (iframes stay\n * blocked while the host sends COEP); Safari ignores the COEP value itself,\n * so nothing is blocked there in the first place.\n */\n iframeCredentialless?: 'auto' | 'always' | 'never'\n\n /**\n * Extra hosts treated as trusted, on top of `TRUSTED_IFRAME_DOMAINS`:\n * no `credentialless` attribute, and `allow-same-origin` in the sandbox.\n * A subdomain of a listed host matches too.\n *\n * This only RECLASSIFIES a host the allow-list already accepts. To render an\n * iframe whose host is outside `DEFAULT_IFRAME_DOMAINS`, add it to\n * {@link MCPUIConfigInput.customIframeDomains} with `iframePolicy: 'extend'`.\n */\n customTrustedIframeDomains?: string[]\n\n /**\n * How `UIResourceRenderer` validates an `iframe` component's host:\n * `'strict'` (default) accepts `DEFAULT_IFRAME_DOMAINS` only, `'extend'`\n * also accepts {@link MCPUIConfigInput.customIframeDomains}.\n */\n iframePolicy?: IframePolicy\n\n /**\n * Extra hosts the allow-list accepts when `iframePolicy` is `'extend'`.\n * Without this, a component pointing at an unlisted host is replaced by the\n * validation card before any renderer runs.\n */\n customIframeDomains?: string[]\n\n /**\n * When the library renders an \"open in a new tab\" link under an embed\n * (`strings.iframeOpenInNewTab`).\n *\n * A COEP-blocked iframe fires no event the parent page can observe, so\n * without this the user sees an unexplained blank frame.\n *\n * - `'auto'` (default) — only when the page is cross-origin isolated\n * (`window.crossOriginIsolated`). That flag needs COOP `same-origin` AND\n * COEP, so a host that sends COEP alone still blocks embeds while the\n * flag is false: set `'always'` there. Read after mount, never during\n * render, so SSR markup and hydration agree.\n * - `'always'` / `'never'` — unconditional.\n */\n iframeFallbackLink?: 'auto' | 'always' | 'never'\n\n /**\n * Where `ChartJSRenderer` enables wheel-zoom / drag-pan / pinch on a chart\n * (through the optional `chartjs-plugin-zoom` peer dependency — absent, the\n * chart renders exactly as it does without this setting).\n *\n * Hijacking the mouse wheel on a component sitting inline in a scrolling\n * chat feed is hostile: the user scrolls the conversation and the chart eats\n * the gesture. So zoom belongs to a surface that OWNS its viewport, which\n * here is `ExpandableWrapper`'s fullscreen modal.\n *\n * - `'expanded'` (default) — only inside the fullscreen modal.\n * - `'always'` — inline as well. For a host that lays charts out in a\n * dashboard rather than in a feed, where the wheel has nothing to steal.\n * - `'never'` — off everywhere; the plugin is never registered.\n *\n * @since 6.22.0\n */\n chartZoom?: 'expanded' | 'always' | 'never'\n}\n\n/**\n * The resolved host policy: every key present. This is what the library hands\n * back, so a reader never null-checks a policy.\n *\n * Extends `Required<`{@link MCPUIConfigInput}`>` rather than declaring the\n * fields again, so a key exists in exactly one place and the two views cannot\n * drift. It remains an interface so existing consumers can extend or augment\n * the public contract as they could before 6.22.0.\n */\nexport interface MCPUIConfig extends Required<MCPUIConfigInput> {}\n\n/**\n * Defaults. Chosen so a host that sends no COEP header sees no change from\n * 6.20.0 apart from the fallback link, which `'auto'` keeps hidden there —\n * and, since 6.22.0, so no inline component ever captures the wheel\n * (`chartZoom: 'expanded'`).\n *\n * Typed `MCPUIConfig` (i.e. resolved): that annotation is what stops a new\n * key from shipping without a default.\n */\nexport const DEFAULT_MCPUI_CONFIG: MCPUIConfig = {\n iframeCredentialless: 'auto',\n customTrustedIframeDomains: [],\n iframePolicy: 'strict',\n customIframeDomains: [],\n iframeFallbackLink: 'auto',\n chartZoom: 'expanded',\n}\n\n/**\n * Typed with the RESOLVED view, because this context is read as well as\n * written: it is exported, so a consumer may call\n * `useContext(MCPUIConfigContext)` directly, and typing it as the input view\n * would hand them `IframePolicy | undefined` — exactly the regression this\n * whole split exists to undo.\n *\n * The cost lands on the rarer side: a host feeding this context directly\n * passes a COMPLETE value, `{ ...DEFAULT_MCPUI_CONFIG, ...mine }`. Anyone who\n * wants to pass only the keys they care about uses `MCPUIConfigProvider`,\n * whose `config` prop takes `Partial<`{@link MCPUIConfig}`>` and does that\n * merge. That preserves optional properties added through declaration\n * merging; {@link MCPUIConfigInput} remains the unaugmented built-in input\n * shape a host can name for ordinary authored configs.\n */\nexport const MCPUIConfigContext = createContext<MCPUIConfig>(DEFAULT_MCPUI_CONFIG)\n\n/**\n * Reads the active host config, resolved: every key is present, whether it\n * came from the provider or from `DEFAULT_MCPUI_CONFIG`. Returns the defaults\n * outright when no `<MCPUIConfigProvider>` is mounted above.\n */\nexport function useMCPUIConfig(): MCPUIConfig {\n return mergeProps(DEFAULT_MCPUI_CONFIG, useContext(MCPUIConfigContext))\n}\n\nexport interface MCPUIConfigProviderProps {\n /**\n * Partial override of the host config. Any key left unset falls back to\n * `DEFAULT_MCPUI_CONFIG`.\n */\n config?: Partial<MCPUIConfig>\n children: JSX.Element\n}\n\n/**\n * Provides the host config to every MCP-UI renderer below it.\n * Merges the partial `config` override over the defaults.\n */\nexport function MCPUIConfigProvider(props: MCPUIConfigProviderProps): JSX.Element {\n // The function source keeps replacement `config` objects reactive while\n // mergeProps fills any omitted key without taking a one-time snapshot.\n const value = mergeProps(DEFAULT_MCPUI_CONFIG, () => props.config)\n return (\n <MCPUIConfigContext.Provider value={value}>\n {props.children}\n </MCPUIConfigContext.Provider>\n )\n}\n"],"names":["DEFAULT_MCPUI_CONFIG","iframeCredentialless","customTrustedIframeDomains","iframePolicy","customIframeDomains","iframeFallbackLink","chartZoom","MCPUIConfigContext","createContext","useMCPUIConfig","mergeProps","useContext","MCPUIConfigProvider","props","value","config","_$createComponent","Provider","children"],"mappings":";;AA6KO,MAAMA,uBAAoC;AAAA,EAC/CC,sBAAsB;AAAA,EACtBC,4BAA4B,CAAA;AAAA,EAC5BC,cAAc;AAAA,EACdC,qBAAqB,CAAA;AAAA,EACrBC,oBAAoB;AAAA,EACpBC,WAAW;AACb;AAiBO,MAAMC,qBAAqBC,cAA2BR,oBAAoB;AAO1E,SAASS,iBAA8B;AAC5C,SAAOC,WAAWV,sBAAsBW,WAAWJ,kBAAkB,CAAC;AACxE;AAeO,SAASK,oBAAoBC,OAA8C;AAGhF,QAAMC,QAAQJ,WAAWV,sBAAsB,MAAMa,MAAME,MAAM;AACjE,SAAAC,gBACGT,mBAAmBU,UAAQ;AAAA,IAACH;AAAAA,IAAY,IAAAI,WAAA;AAAA,aACtCL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const web = require("solid-js/web");
4
+ const solidJs = require("solid-js");
5
+ const MCPUIMathContext = solidJs.createContext(() => void 0);
6
+ function MCPUIMathProvider(props) {
7
+ return web.createComponent(MCPUIMathContext.Provider, {
8
+ value: () => props.renderMath ?? void 0,
9
+ get children() {
10
+ return props.children;
11
+ }
12
+ });
13
+ }
14
+ function useMCPUIMath() {
15
+ return solidJs.useContext(MCPUIMathContext);
16
+ }
17
+ exports.MCPUIMathProvider = MCPUIMathProvider;
18
+ exports.useMCPUIMath = useMCPUIMath;
19
+ //# sourceMappingURL=MCPUIMathContext.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MCPUIMathContext.cjs","sources":["../../src/context/MCPUIMathContext.tsx"],"sourcesContent":["import { createContext, useContext, type Accessor, type JSX } from 'solid-js'\n\nexport interface MathRenderOptions {\n displayMode: boolean\n}\n\n/** A synchronous, host-supplied renderer. Returned markup is always sanitized by MCP-UI. */\nexport type MathRenderer = (tex: string, options: MathRenderOptions) => string | null\n\nconst MCPUIMathContext = createContext<Accessor<MathRenderer | undefined>>(() => undefined)\n\nexport interface MCPUIMathProviderProps {\n /** Omit or pass null to explicitly disable an inherited renderer. */\n renderMath?: MathRenderer | null\n children: JSX.Element\n}\n\nexport function MCPUIMathProvider(props: MCPUIMathProviderProps): JSX.Element {\n return (\n <MCPUIMathContext.Provider value={() => props.renderMath ?? undefined}>\n {props.children}\n </MCPUIMathContext.Provider>\n )\n}\n\n/**\n * Returns a reactive accessor for the nearest math renderer. Call the accessor\n * at use time; its value changes when a provider swaps or disables its renderer.\n */\nexport function useMCPUIMath(): Accessor<MathRenderer | undefined> {\n return useContext(MCPUIMathContext)\n}\n"],"names":["MCPUIMathContext","createContext","undefined","MCPUIMathProvider","props","_$createComponent","Provider","value","renderMath","children","useMCPUIMath","useContext"],"mappings":";;;;AASA,MAAMA,mBAAmBC,QAAAA,cAAkD,MAAMC,MAAS;AAQnF,SAASC,kBAAkBC,OAA4C;AAC5E,SAAAC,IAAAA,gBACGL,iBAAiBM,UAAQ;AAAA,IAACC,OAAOA,MAAMH,MAAMI,cAAcN;AAAAA,IAAS,IAAAO,WAAA;AAAA,aAClEL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;AAMO,SAASC,eAAmD;AACjE,SAAOC,QAAAA,WAAWX,gBAAgB;AACpC;;;"}
@@ -0,0 +1,18 @@
1
+ import { type Accessor, type JSX } from 'solid-js';
2
+ export interface MathRenderOptions {
3
+ displayMode: boolean;
4
+ }
5
+ /** A synchronous, host-supplied renderer. Returned markup is always sanitized by MCP-UI. */
6
+ export type MathRenderer = (tex: string, options: MathRenderOptions) => string | null;
7
+ export interface MCPUIMathProviderProps {
8
+ /** Omit or pass null to explicitly disable an inherited renderer. */
9
+ renderMath?: MathRenderer | null;
10
+ children: JSX.Element;
11
+ }
12
+ export declare function MCPUIMathProvider(props: MCPUIMathProviderProps): JSX.Element;
13
+ /**
14
+ * Returns a reactive accessor for the nearest math renderer. Call the accessor
15
+ * at use time; its value changes when a provider swaps or disables its renderer.
16
+ */
17
+ export declare function useMCPUIMath(): Accessor<MathRenderer | undefined>;
18
+ //# sourceMappingURL=MCPUIMathContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MCPUIMathContext.d.ts","sourceRoot":"","sources":["../../src/context/MCPUIMathContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,QAAQ,EAAE,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAE7E,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,4FAA4F;AAC5F,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,KAAK,MAAM,GAAG,IAAI,CAAA;AAIrF,MAAM,WAAW,sBAAsB;IACrC,qEAAqE;IACrE,UAAU,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAChC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,GAAG,CAAC,OAAO,CAM5E;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,QAAQ,CAAC,YAAY,GAAG,SAAS,CAAC,CAEjE"}
@@ -0,0 +1,19 @@
1
+ import { createComponent } from "solid-js/web";
2
+ import { createContext, useContext } from "solid-js";
3
+ const MCPUIMathContext = createContext(() => void 0);
4
+ function MCPUIMathProvider(props) {
5
+ return createComponent(MCPUIMathContext.Provider, {
6
+ value: () => props.renderMath ?? void 0,
7
+ get children() {
8
+ return props.children;
9
+ }
10
+ });
11
+ }
12
+ function useMCPUIMath() {
13
+ return useContext(MCPUIMathContext);
14
+ }
15
+ export {
16
+ MCPUIMathProvider,
17
+ useMCPUIMath
18
+ };
19
+ //# sourceMappingURL=MCPUIMathContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MCPUIMathContext.js","sources":["../../src/context/MCPUIMathContext.tsx"],"sourcesContent":["import { createContext, useContext, type Accessor, type JSX } from 'solid-js'\n\nexport interface MathRenderOptions {\n displayMode: boolean\n}\n\n/** A synchronous, host-supplied renderer. Returned markup is always sanitized by MCP-UI. */\nexport type MathRenderer = (tex: string, options: MathRenderOptions) => string | null\n\nconst MCPUIMathContext = createContext<Accessor<MathRenderer | undefined>>(() => undefined)\n\nexport interface MCPUIMathProviderProps {\n /** Omit or pass null to explicitly disable an inherited renderer. */\n renderMath?: MathRenderer | null\n children: JSX.Element\n}\n\nexport function MCPUIMathProvider(props: MCPUIMathProviderProps): JSX.Element {\n return (\n <MCPUIMathContext.Provider value={() => props.renderMath ?? undefined}>\n {props.children}\n </MCPUIMathContext.Provider>\n )\n}\n\n/**\n * Returns a reactive accessor for the nearest math renderer. Call the accessor\n * at use time; its value changes when a provider swaps or disables its renderer.\n */\nexport function useMCPUIMath(): Accessor<MathRenderer | undefined> {\n return useContext(MCPUIMathContext)\n}\n"],"names":["MCPUIMathContext","createContext","undefined","MCPUIMathProvider","props","_$createComponent","Provider","value","renderMath","children","useMCPUIMath","useContext"],"mappings":";;AASA,MAAMA,mBAAmBC,cAAkD,MAAMC,MAAS;AAQnF,SAASC,kBAAkBC,OAA4C;AAC5E,SAAAC,gBACGL,iBAAiBM,UAAQ;AAAA,IAACC,OAAOA,MAAMH,MAAMI,cAAcN;AAAAA,IAAS,IAAAO,WAAA;AAAA,aAClEL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;AAMO,SAASC,eAAmD;AACjE,SAAOC,WAAWX,gBAAgB;AACpC;"}
@@ -284,7 +284,12 @@ const DEFAULT_MCPUI_STRINGS = {
284
284
  sizeKilobytes: "{size} KB",
285
285
  sizeMegabytes: "{size} MB",
286
286
  // ── 6.21.0 — iframe COEP fallback ──────────────────────────
287
- iframeOpenInNewTab: "Open in a new tab"
287
+ iframeOpenInNewTab: "Open in a new tab",
288
+ // ── 6.22.0 — zoom / pan controls ───────────────────────────
289
+ zoomIn: "Zoom in",
290
+ zoomOut: "Zoom out",
291
+ zoomReset: "Reset zoom",
292
+ zoomLevel: "Zoom {percent}%"
288
293
  };
289
294
  const MCPUIStringsContext = solidJs.createContext(DEFAULT_MCPUI_STRINGS);
290
295
  const resolvedLocales = /* @__PURE__ */ new Map();