@seed-ship/mcp-ui-solid 6.20.0 → 6.22.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 (103) hide show
  1. package/CHANGELOG.md +223 -0
  2. package/README.md +120 -3
  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/IframeFallbackLink.cjs +37 -0
  15. package/dist/components/IframeFallbackLink.cjs.map +1 -0
  16. package/dist/components/IframeFallbackLink.d.ts +23 -0
  17. package/dist/components/IframeFallbackLink.d.ts.map +1 -0
  18. package/dist/components/IframeFallbackLink.js +37 -0
  19. package/dist/components/IframeFallbackLink.js.map +1 -0
  20. package/dist/components/LightboxOverlay.cjs +139 -16
  21. package/dist/components/LightboxOverlay.cjs.map +1 -1
  22. package/dist/components/LightboxOverlay.d.ts +6 -0
  23. package/dist/components/LightboxOverlay.d.ts.map +1 -1
  24. package/dist/components/LightboxOverlay.js +141 -18
  25. package/dist/components/LightboxOverlay.js.map +1 -1
  26. package/dist/components/UIResourceRenderer.cjs +150 -127
  27. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  28. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  29. package/dist/components/UIResourceRenderer.js +151 -128
  30. package/dist/components/UIResourceRenderer.js.map +1 -1
  31. package/dist/components/VideoRenderer.cjs +45 -19
  32. package/dist/components/VideoRenderer.cjs.map +1 -1
  33. package/dist/components/VideoRenderer.d.ts.map +1 -1
  34. package/dist/components/VideoRenderer.js +45 -19
  35. package/dist/components/VideoRenderer.js.map +1 -1
  36. package/dist/context/MCPUIConfigContext.cjs +30 -0
  37. package/dist/context/MCPUIConfigContext.cjs.map +1 -0
  38. package/dist/context/MCPUIConfigContext.d.ts +173 -0
  39. package/dist/context/MCPUIConfigContext.d.ts.map +1 -0
  40. package/dist/context/MCPUIConfigContext.js +30 -0
  41. package/dist/context/MCPUIConfigContext.js.map +1 -0
  42. package/dist/context/MCPUIStringsContext.cjs +8 -1
  43. package/dist/context/MCPUIStringsContext.cjs.map +1 -1
  44. package/dist/context/MCPUIStringsContext.d.ts +29 -0
  45. package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
  46. package/dist/context/MCPUIStringsContext.js +8 -1
  47. package/dist/context/MCPUIStringsContext.js.map +1 -1
  48. package/dist/hooks/index.d.ts +2 -0
  49. package/dist/hooks/index.d.ts.map +1 -1
  50. package/dist/hooks.cjs +2 -0
  51. package/dist/hooks.cjs.map +1 -1
  52. package/dist/hooks.js +2 -0
  53. package/dist/hooks.js.map +1 -1
  54. package/dist/index.cjs +12 -0
  55. package/dist/index.cjs.map +1 -1
  56. package/dist/index.d.cts +5 -1
  57. package/dist/index.d.ts +5 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +14 -2
  60. package/dist/index.js.map +1 -1
  61. package/dist/services/index.d.ts +1 -1
  62. package/dist/services/index.d.ts.map +1 -1
  63. package/dist/services/validation.cjs +11 -10
  64. package/dist/services/validation.cjs.map +1 -1
  65. package/dist/services/validation.d.ts +20 -0
  66. package/dist/services/validation.d.ts.map +1 -1
  67. package/dist/services/validation.js +11 -10
  68. package/dist/services/validation.js.map +1 -1
  69. package/dist/utils/iframe-coep.cjs +30 -0
  70. package/dist/utils/iframe-coep.cjs.map +1 -0
  71. package/dist/utils/iframe-coep.d.ts +53 -0
  72. package/dist/utils/iframe-coep.d.ts.map +1 -0
  73. package/dist/utils/iframe-coep.js +30 -0
  74. package/dist/utils/iframe-coep.js.map +1 -0
  75. package/dist/utils/pan-zoom.cjs +312 -0
  76. package/dist/utils/pan-zoom.cjs.map +1 -0
  77. package/dist/utils/pan-zoom.d.ts +235 -0
  78. package/dist/utils/pan-zoom.d.ts.map +1 -0
  79. package/dist/utils/pan-zoom.js +312 -0
  80. package/dist/utils/pan-zoom.js.map +1 -0
  81. package/dist/validation.cjs +2 -0
  82. package/dist/validation.cjs.map +1 -1
  83. package/dist/validation.d.cts +1 -1
  84. package/dist/validation.d.ts +1 -1
  85. package/dist/validation.d.ts.map +1 -1
  86. package/dist/validation.js +3 -1
  87. package/package.json +5 -1
  88. package/src/components/ChartJSRenderer.tsx +396 -1
  89. package/src/components/ExpandableWrapper.tsx +26 -0
  90. package/src/components/IframeFallbackLink.tsx +57 -0
  91. package/src/components/LightboxOverlay.tsx +280 -4
  92. package/src/components/UIResourceRenderer.tsx +31 -4
  93. package/src/components/VideoRenderer.tsx +20 -0
  94. package/src/context/MCPUIConfigContext.tsx +202 -0
  95. package/src/context/MCPUIStringsContext.tsx +40 -0
  96. package/src/hooks/index.ts +13 -0
  97. package/src/index.ts +31 -0
  98. package/src/services/index.ts +1 -0
  99. package/src/services/validation.ts +38 -16
  100. package/src/solid-jsx-attrs.d.ts +24 -0
  101. package/src/utils/iframe-coep.ts +81 -0
  102. package/src/utils/pan-zoom.ts +779 -0
  103. package/src/validation.ts +4 -0
@@ -4,7 +4,10 @@ const web = require("solid-js/web");
4
4
  const solidJs = require("solid-js");
5
5
  const ExpandableWrapper = require("./ExpandableWrapper.cjs");
6
6
  const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
7
- var _tmpl$ = /* @__PURE__ */ web.template(`<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700"><h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ web.template(`<iframe class="absolute inset-0 w-full h-full"allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"allowfullscreen loading=lazy>`, true, false, false), _tmpl$3 = /* @__PURE__ */ web.template(`<div class="px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0"><p class="text-sm text-gray-600 dark:text-gray-400">`), _tmpl$4 = /* @__PURE__ */ web.template(`<div><!$><!/><div></div><!$><!/>`), _tmpl$5 = /* @__PURE__ */ web.template(`<video playsinline class="absolute inset-0 w-full h-full object-contain"><track kind=captions><!$><!/>`);
7
+ const MCPUIConfigContext = require("../context/MCPUIConfigContext.cjs");
8
+ const iframeCoep = require("../utils/iframe-coep.cjs");
9
+ const IframeFallbackLink = require("./IframeFallbackLink.cjs");
10
+ var _tmpl$ = /* @__PURE__ */ web.template(`<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700"><h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ web.template(`<iframe class="absolute inset-0 w-full h-full"allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"allowfullscreen loading=lazy>`, true, false, false), _tmpl$3 = /* @__PURE__ */ web.template(`<div class="px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0"><p class="text-sm text-gray-600 dark:text-gray-400">`), _tmpl$4 = /* @__PURE__ */ web.template(`<div><!$><!/><div></div><!$><!/><!$><!/>`), _tmpl$5 = /* @__PURE__ */ web.template(`<video playsinline class="absolute inset-0 w-full h-full object-contain"><track kind=captions><!$><!/>`);
8
11
  function parseVideoUrl(url) {
9
12
  const youtubeMatch = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|v\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
10
13
  if (youtubeMatch) {
@@ -26,6 +29,7 @@ function parseVideoUrl(url) {
26
29
  }
27
30
  const VideoRenderer = (props) => {
28
31
  const strings = MCPUIStringsContext.useMCPUIStrings();
32
+ const config = MCPUIConfigContext.useMCPUIConfig();
29
33
  const params = () => {
30
34
  var _a;
31
35
  return props.params || ((_a = props.component) == null ? void 0 : _a.params);
@@ -99,7 +103,7 @@ const VideoRenderer = (props) => {
99
103
  return props.toolbarVariant;
100
104
  },
101
105
  get children() {
102
- var _el$ = web.getNextElement(_tmpl$4), _el$8 = _el$.firstChild, [_el$9, _co$] = web.getNextMarker(_el$8.nextSibling), _el$4 = _el$9.nextSibling, _el$0 = _el$4.nextSibling, [_el$1, _co$2] = web.getNextMarker(_el$0.nextSibling);
106
+ var _el$ = web.getNextElement(_tmpl$4), _el$8 = _el$.firstChild, [_el$9, _co$] = web.getNextMarker(_el$8.nextSibling), _el$4 = _el$9.nextSibling, _el$0 = _el$4.nextSibling, [_el$1, _co$2] = web.getNextMarker(_el$0.nextSibling), _el$10 = _el$1.nextSibling, [_el$11, _co$3] = web.getNextMarker(_el$10.nextSibling);
103
107
  web.insert(_el$, web.createComponent(solidJs.Show, {
104
108
  get when() {
105
109
  var _a;
@@ -119,18 +123,18 @@ const VideoRenderer = (props) => {
119
123
  return (
120
124
  // Direct video file
121
125
  (() => {
122
- var _el$10 = web.getNextElement(_tmpl$5), _el$11 = _el$10.firstChild, _el$12 = _el$11.nextSibling, [_el$13, _co$3] = web.getNextMarker(_el$12.nextSibling);
123
- _el$10.addEventListener("error", handleVideoError);
124
- web.insert(_el$10, () => strings.videoUnsupported, _el$13, _co$3);
126
+ var _el$12 = web.getNextElement(_tmpl$5), _el$13 = _el$12.firstChild, _el$14 = _el$13.nextSibling, [_el$15, _co$4] = web.getNextMarker(_el$14.nextSibling);
127
+ _el$12.addEventListener("error", handleVideoError);
128
+ web.insert(_el$12, () => strings.videoUnsupported, _el$15, _co$4);
125
129
  web.effect((_p$) => {
126
130
  var _a, _b, _c, _d, _e, _f;
127
- var _v$5 = (_a = params()) == null ? void 0 : _a.url, _v$6 = (_b = params()) == null ? void 0 : _b.poster, _v$7 = (_c = params()) == null ? void 0 : _c.autoplay, _v$8 = ((_d = params()) == null ? void 0 : _d.controls) !== false, _v$9 = (_e = params()) == null ? void 0 : _e.loop, _v$0 = (_f = params()) == null ? void 0 : _f.muted;
128
- _v$5 !== _p$.e && web.setAttribute(_el$10, "src", _p$.e = _v$5);
129
- _v$6 !== _p$.t && web.setAttribute(_el$10, "poster", _p$.t = _v$6);
130
- _v$7 !== _p$.a && web.setProperty(_el$10, "autoplay", _p$.a = _v$7);
131
- _v$8 !== _p$.o && web.setProperty(_el$10, "controls", _p$.o = _v$8);
132
- _v$9 !== _p$.i && web.setProperty(_el$10, "loop", _p$.i = _v$9);
133
- _v$0 !== _p$.n && web.setProperty(_el$10, "muted", _p$.n = _v$0);
131
+ var _v$6 = (_a = params()) == null ? void 0 : _a.url, _v$7 = (_b = params()) == null ? void 0 : _b.poster, _v$8 = (_c = params()) == null ? void 0 : _c.autoplay, _v$9 = ((_d = params()) == null ? void 0 : _d.controls) !== false, _v$0 = (_e = params()) == null ? void 0 : _e.loop, _v$1 = (_f = params()) == null ? void 0 : _f.muted;
132
+ _v$6 !== _p$.e && web.setAttribute(_el$12, "src", _p$.e = _v$6);
133
+ _v$7 !== _p$.t && web.setAttribute(_el$12, "poster", _p$.t = _v$7);
134
+ _v$8 !== _p$.a && web.setProperty(_el$12, "autoplay", _p$.a = _v$8);
135
+ _v$9 !== _p$.o && web.setProperty(_el$12, "controls", _p$.o = _v$9);
136
+ _v$0 !== _p$.i && web.setProperty(_el$12, "loop", _p$.i = _v$0);
137
+ _v$1 !== _p$.n && web.setProperty(_el$12, "muted", _p$.n = _v$1);
134
138
  return _p$;
135
139
  }, {
136
140
  e: void 0,
@@ -140,7 +144,7 @@ const VideoRenderer = (props) => {
140
144
  i: void 0,
141
145
  n: void 0
142
146
  });
143
- return _el$10;
147
+ return _el$12;
144
148
  })()
145
149
  );
146
150
  },
@@ -148,17 +152,39 @@ const VideoRenderer = (props) => {
148
152
  var _el$5 = web.getNextElement(_tmpl$2);
149
153
  web.effect((_p$) => {
150
154
  var _a;
151
- var _v$ = embedUrl(), _v$2 = ((_a = params()) == null ? void 0 : _a.title) || strings.videoTitle;
155
+ var _v$ = embedUrl(), _v$2 = ((_a = params()) == null ? void 0 : _a.title) || strings.videoTitle, _v$3 = (
156
+ // No sandbox here: a YouTube/Vimeo embed keeps its provider
157
+ // cookies, so `'auto'` leaves it alone and a COEP host opts in
158
+ // with `iframeCredentialless: 'always'`.
159
+ iframeCoep.shouldSetCredentialless(embedUrl(), config, {
160
+ sandboxedWithoutSameOrigin: false
161
+ }) || void 0
162
+ );
152
163
  _v$ !== _p$.e && web.setAttribute(_el$5, "src", _p$.e = _v$);
153
164
  _v$2 !== _p$.t && web.setAttribute(_el$5, "title", _p$.t = _v$2);
165
+ _v$3 !== _p$.a && web.setAttribute(_el$5, "credentialless", _p$.a = _v$3);
154
166
  return _p$;
155
167
  }, {
156
168
  e: void 0,
157
- t: void 0
169
+ t: void 0,
170
+ a: void 0
158
171
  });
159
172
  return _el$5;
160
173
  }
161
174
  }));
175
+ web.insert(_el$, web.createComponent(solidJs.Show, {
176
+ get when() {
177
+ return embedUrl();
178
+ },
179
+ get children() {
180
+ return web.createComponent(IframeFallbackLink.IframeFallbackLink, {
181
+ get url() {
182
+ var _a;
183
+ return ((_a = params()) == null ? void 0 : _a.url) || "";
184
+ }
185
+ });
186
+ }
187
+ }), _el$1, _co$2);
162
188
  web.insert(_el$, web.createComponent(solidJs.Show, {
163
189
  get when() {
164
190
  var _a;
@@ -169,11 +195,11 @@ const VideoRenderer = (props) => {
169
195
  web.insert(_el$7, () => params().caption);
170
196
  return _el$6;
171
197
  }
172
- }), _el$1, _co$2);
198
+ }), _el$11, _co$3);
173
199
  web.effect((_p$) => {
174
- var _v$3 = `w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$4 = `relative bg-black ${isExpanded() ? "flex-1 min-h-0" : aspectClass()}`;
175
- _v$3 !== _p$.e && web.className(_el$, _p$.e = _v$3);
176
- _v$4 !== _p$.t && web.className(_el$4, _p$.t = _v$4);
200
+ var _v$4 = `w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$5 = `relative bg-black ${isExpanded() ? "flex-1 min-h-0" : aspectClass()}`;
201
+ _v$4 !== _p$.e && web.className(_el$, _p$.e = _v$4);
202
+ _v$5 !== _p$.t && web.className(_el$4, _p$.t = _v$5);
177
203
  return _p$;
178
204
  }, {
179
205
  e: void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"VideoRenderer.cjs","sources":["../../src/components/VideoRenderer.tsx"],"sourcesContent":["/**\n * VideoRenderer - Video embed component\n * Sprint 5: Media Components\n *\n * Supports YouTube, Vimeo, and direct video files\n */\n\nimport { Component, createMemo, Show } from 'solid-js'\nimport type { UIComponent, VideoComponentParams } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface VideoRendererProps {\n /**\n * UIComponent containing video params\n */\n component?: UIComponent\n\n /**\n * Direct video params (alternative to component)\n */\n params?: VideoComponentParams\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\n/**\n * Video provider type\n */\ntype VideoProvider = 'youtube' | 'vimeo' | 'direct'\n\n/**\n * Parsed video info\n */\ninterface VideoInfo {\n provider: VideoProvider\n videoId?: string\n}\n\n/**\n * Extract video ID and provider from URL\n */\nfunction parseVideoUrl(url: string): VideoInfo {\n // YouTube patterns:\n // - youtube.com/watch?v=VIDEO_ID\n // - youtube.com/embed/VIDEO_ID\n // - youtube.com/v/VIDEO_ID\n // - youtu.be/VIDEO_ID\n const youtubeMatch = url.match(\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/|v\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/\n )\n if (youtubeMatch) {\n return { provider: 'youtube', videoId: youtubeMatch[1] }\n }\n\n // Vimeo patterns:\n // - vimeo.com/VIDEO_ID\n // - player.vimeo.com/video/VIDEO_ID\n const vimeoMatch = url.match(/(?:vimeo\\.com\\/|player\\.vimeo\\.com\\/video\\/)(\\d+)/)\n if (vimeoMatch) {\n return { provider: 'vimeo', videoId: vimeoMatch[1] }\n }\n\n // Direct video file\n return { provider: 'direct' }\n}\n\nexport const VideoRenderer: Component<VideoRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const params = () => props.params || (props.component?.params as VideoComponentParams)\n const isExpanded = useExpanded()\n\n const videoInfo = createMemo(() => parseVideoUrl(params()?.url || ''))\n\n const embedUrl = createMemo(() => {\n const info = videoInfo()\n const p = params()\n\n if (!p?.url) return null\n\n switch (info.provider) {\n case 'youtube': {\n const ytParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n controls: p.controls !== false ? '1' : '0',\n loop: p.loop ? '1' : '0',\n mute: p.muted ? '1' : '0',\n })\n if (p.startTime) {\n ytParams.set('start', String(p.startTime))\n }\n // Use youtube-nocookie.com for privacy\n return `https://www.youtube-nocookie.com/embed/${info.videoId}?${ytParams}`\n }\n\n case 'vimeo': {\n const vParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n loop: p.loop ? '1' : '0',\n muted: p.muted ? '1' : '0',\n })\n return `https://player.vimeo.com/video/${info.videoId}?${vParams}`\n }\n\n default:\n return null\n }\n })\n\n const aspectClass = () => {\n switch (params()?.aspectRatio) {\n case '1:1':\n return 'aspect-square'\n case '4:3':\n return 'aspect-[4/3]'\n case '21:9':\n return 'aspect-[21/9]'\n default:\n return 'aspect-video' // 16:9\n }\n }\n\n const handleVideoError = (e: Event) => {\n const error = new Error('Video failed to load')\n console.error('Video error:', e)\n props.onError?.(error)\n }\n\n return (\n <ExpandableWrapper\n title={params()?.title || strings.videoTitle}\n copyData={params()?.url || ''}\n copyLabel={strings.videoCopy}\n toolbarVariant={props.toolbarVariant}\n >\n <div class={`w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}>\n {/* Title */}\n <Show when={params()?.title}>\n <div class=\"px-4 py-3 border-b border-gray-200 dark:border-gray-700\">\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params()!.title}</h3>\n </div>\n </Show>\n\n {/* Video Container — when expanded, fill remaining space (override aspect ratio) */}\n <div class={`relative bg-black ${isExpanded() ? 'flex-1 min-h-0' : aspectClass()}`}>\n <Show\n when={embedUrl()}\n fallback={\n // Direct video file\n <video\n src={params()?.url}\n poster={params()?.poster}\n autoplay={params()?.autoplay}\n controls={params()?.controls !== false}\n loop={params()?.loop}\n muted={params()?.muted}\n playsinline\n class=\"absolute inset-0 w-full h-full object-contain\"\n onError={handleVideoError}\n >\n <track kind=\"captions\" />\n {strings.videoUnsupported}\n </video>\n }\n >\n {/* YouTube/Vimeo embed */}\n <iframe\n src={embedUrl()!}\n title={params()?.title || strings.videoTitle}\n class=\"absolute inset-0 w-full h-full\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowfullscreen\n loading=\"lazy\"\n />\n </Show>\n </div>\n\n {/* Caption */}\n <Show when={params()?.caption}>\n <div class=\"px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <p class=\"text-sm text-gray-600 dark:text-gray-400\">{params()!.caption}</p>\n </div>\n </Show>\n </div>\n </ExpandableWrapper>\n )\n}\n\n/**\n * Check if a URL is from a supported video provider\n */\nexport function isSupportedVideoUrl(url: string): boolean {\n const info = parseVideoUrl(url)\n return info.provider !== 'direct' || url.match(/\\.(mp4|webm|ogg|mov)$/i) !== null\n}\n\n/**\n * Get video provider from URL\n */\nexport function getVideoProvider(url: string): VideoProvider {\n return parseVideoUrl(url).provider\n}\n"],"names":["parseVideoUrl","url","youtubeMatch","match","provider","videoId","vimeoMatch","VideoRenderer","props","strings","useMCPUIStrings","params","component","isExpanded","useExpanded","videoInfo","createMemo","embedUrl","info","p","ytParams","URLSearchParams","autoplay","controls","loop","mute","muted","startTime","set","String","vParams","aspectClass","aspectRatio","handleVideoError","e","error","Error","console","onError","_$createComponent","ExpandableWrapper","title","videoTitle","copyData","copyLabel","videoCopy","toolbarVariant","children","_el$","_$getNextElement","_tmpl$4","_el$8","firstChild","_el$9","_co$","_$getNextMarker","nextSibling","_el$4","_el$0","_el$1","_co$2","_$insert","Show","when","_el$2","_tmpl$","_el$3","fallback","_el$10","_tmpl$5","_el$11","_el$12","_el$13","_co$3","addEventListener","videoUnsupported","_$effect","_p$","_v$5","_v$6","poster","_v$7","_v$8","_v$9","_v$0","_$setAttribute","t","a","_$setProperty","o","i","n","undefined","_el$5","_tmpl$2","_v$","_v$2","caption","_el$6","_tmpl$3","_el$7","_v$3","_v$4","_$className","isSupportedVideoUrl","getVideoProvider"],"mappings":"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"}
1
+ {"version":3,"file":"VideoRenderer.cjs","sources":["../../src/components/VideoRenderer.tsx"],"sourcesContent":["/**\n * VideoRenderer - Video embed component\n * Sprint 5: Media Components\n *\n * Supports YouTube, Vimeo, and direct video files\n */\n\nimport { Component, createMemo, Show } from 'solid-js'\nimport type { UIComponent, VideoComponentParams } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\nimport { useMCPUIConfig } from '../context/MCPUIConfigContext'\nimport { shouldSetCredentialless } from '../utils/iframe-coep'\nimport { IframeFallbackLink } from './IframeFallbackLink'\n\nexport interface VideoRendererProps {\n /**\n * UIComponent containing video params\n */\n component?: UIComponent\n\n /**\n * Direct video params (alternative to component)\n */\n params?: VideoComponentParams\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\n/**\n * Video provider type\n */\ntype VideoProvider = 'youtube' | 'vimeo' | 'direct'\n\n/**\n * Parsed video info\n */\ninterface VideoInfo {\n provider: VideoProvider\n videoId?: string\n}\n\n/**\n * Extract video ID and provider from URL\n */\nfunction parseVideoUrl(url: string): VideoInfo {\n // YouTube patterns:\n // - youtube.com/watch?v=VIDEO_ID\n // - youtube.com/embed/VIDEO_ID\n // - youtube.com/v/VIDEO_ID\n // - youtu.be/VIDEO_ID\n const youtubeMatch = url.match(\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/|v\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/\n )\n if (youtubeMatch) {\n return { provider: 'youtube', videoId: youtubeMatch[1] }\n }\n\n // Vimeo patterns:\n // - vimeo.com/VIDEO_ID\n // - player.vimeo.com/video/VIDEO_ID\n const vimeoMatch = url.match(/(?:vimeo\\.com\\/|player\\.vimeo\\.com\\/video\\/)(\\d+)/)\n if (vimeoMatch) {\n return { provider: 'vimeo', videoId: vimeoMatch[1] }\n }\n\n // Direct video file\n return { provider: 'direct' }\n}\n\nexport const VideoRenderer: Component<VideoRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const config = useMCPUIConfig()\n const params = () => props.params || (props.component?.params as VideoComponentParams)\n const isExpanded = useExpanded()\n\n const videoInfo = createMemo(() => parseVideoUrl(params()?.url || ''))\n\n const embedUrl = createMemo(() => {\n const info = videoInfo()\n const p = params()\n\n if (!p?.url) return null\n\n switch (info.provider) {\n case 'youtube': {\n const ytParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n controls: p.controls !== false ? '1' : '0',\n loop: p.loop ? '1' : '0',\n mute: p.muted ? '1' : '0',\n })\n if (p.startTime) {\n ytParams.set('start', String(p.startTime))\n }\n // Use youtube-nocookie.com for privacy\n return `https://www.youtube-nocookie.com/embed/${info.videoId}?${ytParams}`\n }\n\n case 'vimeo': {\n const vParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n loop: p.loop ? '1' : '0',\n muted: p.muted ? '1' : '0',\n })\n return `https://player.vimeo.com/video/${info.videoId}?${vParams}`\n }\n\n default:\n return null\n }\n })\n\n const aspectClass = () => {\n switch (params()?.aspectRatio) {\n case '1:1':\n return 'aspect-square'\n case '4:3':\n return 'aspect-[4/3]'\n case '21:9':\n return 'aspect-[21/9]'\n default:\n return 'aspect-video' // 16:9\n }\n }\n\n const handleVideoError = (e: Event) => {\n const error = new Error('Video failed to load')\n console.error('Video error:', e)\n props.onError?.(error)\n }\n\n return (\n <ExpandableWrapper\n title={params()?.title || strings.videoTitle}\n copyData={params()?.url || ''}\n copyLabel={strings.videoCopy}\n toolbarVariant={props.toolbarVariant}\n >\n <div class={`w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}>\n {/* Title */}\n <Show when={params()?.title}>\n <div class=\"px-4 py-3 border-b border-gray-200 dark:border-gray-700\">\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params()!.title}</h3>\n </div>\n </Show>\n\n {/* Video Container — when expanded, fill remaining space (override aspect ratio) */}\n <div class={`relative bg-black ${isExpanded() ? 'flex-1 min-h-0' : aspectClass()}`}>\n <Show\n when={embedUrl()}\n fallback={\n // Direct video file\n <video\n src={params()?.url}\n poster={params()?.poster}\n autoplay={params()?.autoplay}\n controls={params()?.controls !== false}\n loop={params()?.loop}\n muted={params()?.muted}\n playsinline\n class=\"absolute inset-0 w-full h-full object-contain\"\n onError={handleVideoError}\n >\n <track kind=\"captions\" />\n {strings.videoUnsupported}\n </video>\n }\n >\n {/* YouTube/Vimeo embed */}\n <iframe\n src={embedUrl()!}\n title={params()?.title || strings.videoTitle}\n class=\"absolute inset-0 w-full h-full\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowfullscreen\n // v6.21.0 — youtube-nocookie / player.vimeo are not trusted hosts,\n // so under COEP `credentialless` is what lets them load at all.\n // `attr:` + `true | undefined` — see the note in `IframeRenderer`.\n attr:credentialless={\n // No sandbox here: a YouTube/Vimeo embed keeps its provider\n // cookies, so `'auto'` leaves it alone and a COEP host opts in\n // with `iframeCredentialless: 'always'`.\n shouldSetCredentialless(embedUrl()!, config, {\n sandboxedWithoutSameOrigin: false,\n }) || undefined\n }\n loading=\"lazy\"\n />\n </Show>\n </div>\n\n {/* v6.21.0 — a COEP-blocked embed is silent; this link is the way out. */}\n <Show when={embedUrl()}>\n <IframeFallbackLink url={params()?.url || ''} />\n </Show>\n\n {/* Caption */}\n <Show when={params()?.caption}>\n <div class=\"px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <p class=\"text-sm text-gray-600 dark:text-gray-400\">{params()!.caption}</p>\n </div>\n </Show>\n </div>\n </ExpandableWrapper>\n )\n}\n\n/**\n * Check if a URL is from a supported video provider\n */\nexport function isSupportedVideoUrl(url: string): boolean {\n const info = parseVideoUrl(url)\n return info.provider !== 'direct' || url.match(/\\.(mp4|webm|ogg|mov)$/i) !== null\n}\n\n/**\n * Get video provider from URL\n */\nexport function getVideoProvider(url: string): VideoProvider {\n return parseVideoUrl(url).provider\n}\n"],"names":["parseVideoUrl","url","youtubeMatch","match","provider","videoId","vimeoMatch","VideoRenderer","props","strings","useMCPUIStrings","config","useMCPUIConfig","params","component","isExpanded","useExpanded","videoInfo","createMemo","embedUrl","info","p","ytParams","URLSearchParams","autoplay","controls","loop","mute","muted","startTime","set","String","vParams","aspectClass","aspectRatio","handleVideoError","e","error","Error","console","onError","_$createComponent","ExpandableWrapper","title","videoTitle","copyData","copyLabel","videoCopy","toolbarVariant","children","_el$","_$getNextElement","_tmpl$4","_el$8","firstChild","_el$9","_co$","_$getNextMarker","nextSibling","_el$4","_el$0","_el$1","_co$2","_el$10","_el$11","_co$3","_$insert","Show","when","_el$2","_tmpl$","_el$3","fallback","_el$12","_tmpl$5","_el$13","_el$14","_el$15","_co$4","addEventListener","videoUnsupported","_$effect","_p$","_v$6","_v$7","poster","_v$8","_v$9","_v$0","_v$1","_$setAttribute","t","a","_$setProperty","o","i","n","undefined","_el$5","_tmpl$2","_v$","_v$2","_v$3","shouldSetCredentialless","sandboxedWithoutSameOrigin","IframeFallbackLink","caption","_el$6","_tmpl$3","_el$7","_v$4","_v$5","_$className","isSupportedVideoUrl","getVideoProvider"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"VideoRenderer.d.ts","sourceRoot":"","sources":["../../src/components/VideoRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAoB,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAIjE,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAA;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAA;IAE7B;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAA;CAC5C;AAED;;GAEG;AACH,KAAK,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAA;AAsCnD,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,kBAAkB,CAyHvD,CAAA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAE3D"}
1
+ {"version":3,"file":"VideoRenderer.d.ts","sourceRoot":"","sources":["../../src/components/VideoRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAoB,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAOjE,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAA;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAA;IAE7B;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAA;CAC5C;AAED;;GAEG;AACH,KAAK,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAA;AAsCnD,eAAO,MAAM,aAAa,EAAE,SAAS,CAAC,kBAAkB,CA0IvD,CAAA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGxD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAE3D"}
@@ -2,7 +2,10 @@ import { createComponent, getNextElement, getNextMarker, insert, effect, setAttr
2
2
  import { createMemo, Show } from "solid-js";
3
3
  import { useExpanded, ExpandableWrapper } from "./ExpandableWrapper.js";
4
4
  import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
5
- var _tmpl$ = /* @__PURE__ */ template(`<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700"><h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ template(`<iframe class="absolute inset-0 w-full h-full"allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"allowfullscreen loading=lazy>`, true, false, false), _tmpl$3 = /* @__PURE__ */ template(`<div class="px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0"><p class="text-sm text-gray-600 dark:text-gray-400">`), _tmpl$4 = /* @__PURE__ */ template(`<div><!$><!/><div></div><!$><!/>`), _tmpl$5 = /* @__PURE__ */ template(`<video playsinline class="absolute inset-0 w-full h-full object-contain"><track kind=captions><!$><!/>`);
5
+ import { useMCPUIConfig } from "../context/MCPUIConfigContext.js";
6
+ import { shouldSetCredentialless } from "../utils/iframe-coep.js";
7
+ import { IframeFallbackLink } from "./IframeFallbackLink.js";
8
+ var _tmpl$ = /* @__PURE__ */ template(`<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700"><h3 class="text-sm font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ template(`<iframe class="absolute inset-0 w-full h-full"allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"allowfullscreen loading=lazy>`, true, false, false), _tmpl$3 = /* @__PURE__ */ template(`<div class="px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0"><p class="text-sm text-gray-600 dark:text-gray-400">`), _tmpl$4 = /* @__PURE__ */ template(`<div><!$><!/><div></div><!$><!/><!$><!/>`), _tmpl$5 = /* @__PURE__ */ template(`<video playsinline class="absolute inset-0 w-full h-full object-contain"><track kind=captions><!$><!/>`);
6
9
  function parseVideoUrl(url) {
7
10
  const youtubeMatch = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|v\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
8
11
  if (youtubeMatch) {
@@ -24,6 +27,7 @@ function parseVideoUrl(url) {
24
27
  }
25
28
  const VideoRenderer = (props) => {
26
29
  const strings = useMCPUIStrings();
30
+ const config = useMCPUIConfig();
27
31
  const params = () => {
28
32
  var _a;
29
33
  return props.params || ((_a = props.component) == null ? void 0 : _a.params);
@@ -97,7 +101,7 @@ const VideoRenderer = (props) => {
97
101
  return props.toolbarVariant;
98
102
  },
99
103
  get children() {
100
- var _el$ = getNextElement(_tmpl$4), _el$8 = _el$.firstChild, [_el$9, _co$] = getNextMarker(_el$8.nextSibling), _el$4 = _el$9.nextSibling, _el$0 = _el$4.nextSibling, [_el$1, _co$2] = getNextMarker(_el$0.nextSibling);
104
+ var _el$ = getNextElement(_tmpl$4), _el$8 = _el$.firstChild, [_el$9, _co$] = getNextMarker(_el$8.nextSibling), _el$4 = _el$9.nextSibling, _el$0 = _el$4.nextSibling, [_el$1, _co$2] = getNextMarker(_el$0.nextSibling), _el$10 = _el$1.nextSibling, [_el$11, _co$3] = getNextMarker(_el$10.nextSibling);
101
105
  insert(_el$, createComponent(Show, {
102
106
  get when() {
103
107
  var _a;
@@ -117,18 +121,18 @@ const VideoRenderer = (props) => {
117
121
  return (
118
122
  // Direct video file
119
123
  (() => {
120
- var _el$10 = getNextElement(_tmpl$5), _el$11 = _el$10.firstChild, _el$12 = _el$11.nextSibling, [_el$13, _co$3] = getNextMarker(_el$12.nextSibling);
121
- _el$10.addEventListener("error", handleVideoError);
122
- insert(_el$10, () => strings.videoUnsupported, _el$13, _co$3);
124
+ var _el$12 = getNextElement(_tmpl$5), _el$13 = _el$12.firstChild, _el$14 = _el$13.nextSibling, [_el$15, _co$4] = getNextMarker(_el$14.nextSibling);
125
+ _el$12.addEventListener("error", handleVideoError);
126
+ insert(_el$12, () => strings.videoUnsupported, _el$15, _co$4);
123
127
  effect((_p$) => {
124
128
  var _a, _b, _c, _d, _e, _f;
125
- var _v$5 = (_a = params()) == null ? void 0 : _a.url, _v$6 = (_b = params()) == null ? void 0 : _b.poster, _v$7 = (_c = params()) == null ? void 0 : _c.autoplay, _v$8 = ((_d = params()) == null ? void 0 : _d.controls) !== false, _v$9 = (_e = params()) == null ? void 0 : _e.loop, _v$0 = (_f = params()) == null ? void 0 : _f.muted;
126
- _v$5 !== _p$.e && setAttribute(_el$10, "src", _p$.e = _v$5);
127
- _v$6 !== _p$.t && setAttribute(_el$10, "poster", _p$.t = _v$6);
128
- _v$7 !== _p$.a && setProperty(_el$10, "autoplay", _p$.a = _v$7);
129
- _v$8 !== _p$.o && setProperty(_el$10, "controls", _p$.o = _v$8);
130
- _v$9 !== _p$.i && setProperty(_el$10, "loop", _p$.i = _v$9);
131
- _v$0 !== _p$.n && setProperty(_el$10, "muted", _p$.n = _v$0);
129
+ var _v$6 = (_a = params()) == null ? void 0 : _a.url, _v$7 = (_b = params()) == null ? void 0 : _b.poster, _v$8 = (_c = params()) == null ? void 0 : _c.autoplay, _v$9 = ((_d = params()) == null ? void 0 : _d.controls) !== false, _v$0 = (_e = params()) == null ? void 0 : _e.loop, _v$1 = (_f = params()) == null ? void 0 : _f.muted;
130
+ _v$6 !== _p$.e && setAttribute(_el$12, "src", _p$.e = _v$6);
131
+ _v$7 !== _p$.t && setAttribute(_el$12, "poster", _p$.t = _v$7);
132
+ _v$8 !== _p$.a && setProperty(_el$12, "autoplay", _p$.a = _v$8);
133
+ _v$9 !== _p$.o && setProperty(_el$12, "controls", _p$.o = _v$9);
134
+ _v$0 !== _p$.i && setProperty(_el$12, "loop", _p$.i = _v$0);
135
+ _v$1 !== _p$.n && setProperty(_el$12, "muted", _p$.n = _v$1);
132
136
  return _p$;
133
137
  }, {
134
138
  e: void 0,
@@ -138,7 +142,7 @@ const VideoRenderer = (props) => {
138
142
  i: void 0,
139
143
  n: void 0
140
144
  });
141
- return _el$10;
145
+ return _el$12;
142
146
  })()
143
147
  );
144
148
  },
@@ -146,17 +150,39 @@ const VideoRenderer = (props) => {
146
150
  var _el$5 = getNextElement(_tmpl$2);
147
151
  effect((_p$) => {
148
152
  var _a;
149
- var _v$ = embedUrl(), _v$2 = ((_a = params()) == null ? void 0 : _a.title) || strings.videoTitle;
153
+ var _v$ = embedUrl(), _v$2 = ((_a = params()) == null ? void 0 : _a.title) || strings.videoTitle, _v$3 = (
154
+ // No sandbox here: a YouTube/Vimeo embed keeps its provider
155
+ // cookies, so `'auto'` leaves it alone and a COEP host opts in
156
+ // with `iframeCredentialless: 'always'`.
157
+ shouldSetCredentialless(embedUrl(), config, {
158
+ sandboxedWithoutSameOrigin: false
159
+ }) || void 0
160
+ );
150
161
  _v$ !== _p$.e && setAttribute(_el$5, "src", _p$.e = _v$);
151
162
  _v$2 !== _p$.t && setAttribute(_el$5, "title", _p$.t = _v$2);
163
+ _v$3 !== _p$.a && setAttribute(_el$5, "credentialless", _p$.a = _v$3);
152
164
  return _p$;
153
165
  }, {
154
166
  e: void 0,
155
- t: void 0
167
+ t: void 0,
168
+ a: void 0
156
169
  });
157
170
  return _el$5;
158
171
  }
159
172
  }));
173
+ insert(_el$, createComponent(Show, {
174
+ get when() {
175
+ return embedUrl();
176
+ },
177
+ get children() {
178
+ return createComponent(IframeFallbackLink, {
179
+ get url() {
180
+ var _a;
181
+ return ((_a = params()) == null ? void 0 : _a.url) || "";
182
+ }
183
+ });
184
+ }
185
+ }), _el$1, _co$2);
160
186
  insert(_el$, createComponent(Show, {
161
187
  get when() {
162
188
  var _a;
@@ -167,11 +193,11 @@ const VideoRenderer = (props) => {
167
193
  insert(_el$7, () => params().caption);
168
194
  return _el$6;
169
195
  }
170
- }), _el$1, _co$2);
196
+ }), _el$11, _co$3);
171
197
  effect((_p$) => {
172
- var _v$3 = `w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$4 = `relative bg-black ${isExpanded() ? "flex-1 min-h-0" : aspectClass()}`;
173
- _v$3 !== _p$.e && className(_el$, _p$.e = _v$3);
174
- _v$4 !== _p$.t && className(_el$4, _p$.t = _v$4);
198
+ var _v$4 = `w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`, _v$5 = `relative bg-black ${isExpanded() ? "flex-1 min-h-0" : aspectClass()}`;
199
+ _v$4 !== _p$.e && className(_el$, _p$.e = _v$4);
200
+ _v$5 !== _p$.t && className(_el$4, _p$.t = _v$5);
175
201
  return _p$;
176
202
  }, {
177
203
  e: void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"VideoRenderer.js","sources":["../../src/components/VideoRenderer.tsx"],"sourcesContent":["/**\n * VideoRenderer - Video embed component\n * Sprint 5: Media Components\n *\n * Supports YouTube, Vimeo, and direct video files\n */\n\nimport { Component, createMemo, Show } from 'solid-js'\nimport type { UIComponent, VideoComponentParams } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface VideoRendererProps {\n /**\n * UIComponent containing video params\n */\n component?: UIComponent\n\n /**\n * Direct video params (alternative to component)\n */\n params?: VideoComponentParams\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\n/**\n * Video provider type\n */\ntype VideoProvider = 'youtube' | 'vimeo' | 'direct'\n\n/**\n * Parsed video info\n */\ninterface VideoInfo {\n provider: VideoProvider\n videoId?: string\n}\n\n/**\n * Extract video ID and provider from URL\n */\nfunction parseVideoUrl(url: string): VideoInfo {\n // YouTube patterns:\n // - youtube.com/watch?v=VIDEO_ID\n // - youtube.com/embed/VIDEO_ID\n // - youtube.com/v/VIDEO_ID\n // - youtu.be/VIDEO_ID\n const youtubeMatch = url.match(\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/|v\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/\n )\n if (youtubeMatch) {\n return { provider: 'youtube', videoId: youtubeMatch[1] }\n }\n\n // Vimeo patterns:\n // - vimeo.com/VIDEO_ID\n // - player.vimeo.com/video/VIDEO_ID\n const vimeoMatch = url.match(/(?:vimeo\\.com\\/|player\\.vimeo\\.com\\/video\\/)(\\d+)/)\n if (vimeoMatch) {\n return { provider: 'vimeo', videoId: vimeoMatch[1] }\n }\n\n // Direct video file\n return { provider: 'direct' }\n}\n\nexport const VideoRenderer: Component<VideoRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const params = () => props.params || (props.component?.params as VideoComponentParams)\n const isExpanded = useExpanded()\n\n const videoInfo = createMemo(() => parseVideoUrl(params()?.url || ''))\n\n const embedUrl = createMemo(() => {\n const info = videoInfo()\n const p = params()\n\n if (!p?.url) return null\n\n switch (info.provider) {\n case 'youtube': {\n const ytParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n controls: p.controls !== false ? '1' : '0',\n loop: p.loop ? '1' : '0',\n mute: p.muted ? '1' : '0',\n })\n if (p.startTime) {\n ytParams.set('start', String(p.startTime))\n }\n // Use youtube-nocookie.com for privacy\n return `https://www.youtube-nocookie.com/embed/${info.videoId}?${ytParams}`\n }\n\n case 'vimeo': {\n const vParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n loop: p.loop ? '1' : '0',\n muted: p.muted ? '1' : '0',\n })\n return `https://player.vimeo.com/video/${info.videoId}?${vParams}`\n }\n\n default:\n return null\n }\n })\n\n const aspectClass = () => {\n switch (params()?.aspectRatio) {\n case '1:1':\n return 'aspect-square'\n case '4:3':\n return 'aspect-[4/3]'\n case '21:9':\n return 'aspect-[21/9]'\n default:\n return 'aspect-video' // 16:9\n }\n }\n\n const handleVideoError = (e: Event) => {\n const error = new Error('Video failed to load')\n console.error('Video error:', e)\n props.onError?.(error)\n }\n\n return (\n <ExpandableWrapper\n title={params()?.title || strings.videoTitle}\n copyData={params()?.url || ''}\n copyLabel={strings.videoCopy}\n toolbarVariant={props.toolbarVariant}\n >\n <div class={`w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}>\n {/* Title */}\n <Show when={params()?.title}>\n <div class=\"px-4 py-3 border-b border-gray-200 dark:border-gray-700\">\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params()!.title}</h3>\n </div>\n </Show>\n\n {/* Video Container — when expanded, fill remaining space (override aspect ratio) */}\n <div class={`relative bg-black ${isExpanded() ? 'flex-1 min-h-0' : aspectClass()}`}>\n <Show\n when={embedUrl()}\n fallback={\n // Direct video file\n <video\n src={params()?.url}\n poster={params()?.poster}\n autoplay={params()?.autoplay}\n controls={params()?.controls !== false}\n loop={params()?.loop}\n muted={params()?.muted}\n playsinline\n class=\"absolute inset-0 w-full h-full object-contain\"\n onError={handleVideoError}\n >\n <track kind=\"captions\" />\n {strings.videoUnsupported}\n </video>\n }\n >\n {/* YouTube/Vimeo embed */}\n <iframe\n src={embedUrl()!}\n title={params()?.title || strings.videoTitle}\n class=\"absolute inset-0 w-full h-full\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowfullscreen\n loading=\"lazy\"\n />\n </Show>\n </div>\n\n {/* Caption */}\n <Show when={params()?.caption}>\n <div class=\"px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <p class=\"text-sm text-gray-600 dark:text-gray-400\">{params()!.caption}</p>\n </div>\n </Show>\n </div>\n </ExpandableWrapper>\n )\n}\n\n/**\n * Check if a URL is from a supported video provider\n */\nexport function isSupportedVideoUrl(url: string): boolean {\n const info = parseVideoUrl(url)\n return info.provider !== 'direct' || url.match(/\\.(mp4|webm|ogg|mov)$/i) !== null\n}\n\n/**\n * Get video provider from URL\n */\nexport function getVideoProvider(url: string): VideoProvider {\n return parseVideoUrl(url).provider\n}\n"],"names":["parseVideoUrl","url","youtubeMatch","match","provider","videoId","vimeoMatch","VideoRenderer","props","strings","useMCPUIStrings","params","component","isExpanded","useExpanded","videoInfo","createMemo","embedUrl","info","p","ytParams","URLSearchParams","autoplay","controls","loop","mute","muted","startTime","set","String","vParams","aspectClass","aspectRatio","handleVideoError","e","error","Error","console","onError","_$createComponent","ExpandableWrapper","title","videoTitle","copyData","copyLabel","videoCopy","toolbarVariant","children","_el$","_$getNextElement","_tmpl$4","_el$8","firstChild","_el$9","_co$","_$getNextMarker","nextSibling","_el$4","_el$0","_el$1","_co$2","_$insert","Show","when","_el$2","_tmpl$","_el$3","fallback","_el$10","_tmpl$5","_el$11","_el$12","_el$13","_co$3","addEventListener","videoUnsupported","_$effect","_p$","_v$5","_v$6","poster","_v$7","_v$8","_v$9","_v$0","_$setAttribute","t","a","_$setProperty","o","i","n","undefined","_el$5","_tmpl$2","_v$","_v$2","caption","_el$6","_tmpl$3","_el$7","_v$3","_v$4","_$className","isSupportedVideoUrl","getVideoProvider"],"mappings":"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"}
1
+ {"version":3,"file":"VideoRenderer.js","sources":["../../src/components/VideoRenderer.tsx"],"sourcesContent":["/**\n * VideoRenderer - Video embed component\n * Sprint 5: Media Components\n *\n * Supports YouTube, Vimeo, and direct video files\n */\n\nimport { Component, createMemo, Show } from 'solid-js'\nimport type { UIComponent, VideoComponentParams } from '../types'\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\nimport { useMCPUIConfig } from '../context/MCPUIConfigContext'\nimport { shouldSetCredentialless } from '../utils/iframe-coep'\nimport { IframeFallbackLink } from './IframeFallbackLink'\n\nexport interface VideoRendererProps {\n /**\n * UIComponent containing video params\n */\n component?: UIComponent\n\n /**\n * Direct video params (alternative to component)\n */\n params?: VideoComponentParams\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\n/**\n * Video provider type\n */\ntype VideoProvider = 'youtube' | 'vimeo' | 'direct'\n\n/**\n * Parsed video info\n */\ninterface VideoInfo {\n provider: VideoProvider\n videoId?: string\n}\n\n/**\n * Extract video ID and provider from URL\n */\nfunction parseVideoUrl(url: string): VideoInfo {\n // YouTube patterns:\n // - youtube.com/watch?v=VIDEO_ID\n // - youtube.com/embed/VIDEO_ID\n // - youtube.com/v/VIDEO_ID\n // - youtu.be/VIDEO_ID\n const youtubeMatch = url.match(\n /(?:youtube\\.com\\/(?:watch\\?v=|embed\\/|v\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/\n )\n if (youtubeMatch) {\n return { provider: 'youtube', videoId: youtubeMatch[1] }\n }\n\n // Vimeo patterns:\n // - vimeo.com/VIDEO_ID\n // - player.vimeo.com/video/VIDEO_ID\n const vimeoMatch = url.match(/(?:vimeo\\.com\\/|player\\.vimeo\\.com\\/video\\/)(\\d+)/)\n if (vimeoMatch) {\n return { provider: 'vimeo', videoId: vimeoMatch[1] }\n }\n\n // Direct video file\n return { provider: 'direct' }\n}\n\nexport const VideoRenderer: Component<VideoRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const config = useMCPUIConfig()\n const params = () => props.params || (props.component?.params as VideoComponentParams)\n const isExpanded = useExpanded()\n\n const videoInfo = createMemo(() => parseVideoUrl(params()?.url || ''))\n\n const embedUrl = createMemo(() => {\n const info = videoInfo()\n const p = params()\n\n if (!p?.url) return null\n\n switch (info.provider) {\n case 'youtube': {\n const ytParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n controls: p.controls !== false ? '1' : '0',\n loop: p.loop ? '1' : '0',\n mute: p.muted ? '1' : '0',\n })\n if (p.startTime) {\n ytParams.set('start', String(p.startTime))\n }\n // Use youtube-nocookie.com for privacy\n return `https://www.youtube-nocookie.com/embed/${info.videoId}?${ytParams}`\n }\n\n case 'vimeo': {\n const vParams = new URLSearchParams({\n autoplay: p.autoplay ? '1' : '0',\n loop: p.loop ? '1' : '0',\n muted: p.muted ? '1' : '0',\n })\n return `https://player.vimeo.com/video/${info.videoId}?${vParams}`\n }\n\n default:\n return null\n }\n })\n\n const aspectClass = () => {\n switch (params()?.aspectRatio) {\n case '1:1':\n return 'aspect-square'\n case '4:3':\n return 'aspect-[4/3]'\n case '21:9':\n return 'aspect-[21/9]'\n default:\n return 'aspect-video' // 16:9\n }\n }\n\n const handleVideoError = (e: Event) => {\n const error = new Error('Video failed to load')\n console.error('Video error:', e)\n props.onError?.(error)\n }\n\n return (\n <ExpandableWrapper\n title={params()?.title || strings.videoTitle}\n copyData={params()?.url || ''}\n copyLabel={strings.videoCopy}\n toolbarVariant={props.toolbarVariant}\n >\n <div class={`w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}>\n {/* Title */}\n <Show when={params()?.title}>\n <div class=\"px-4 py-3 border-b border-gray-200 dark:border-gray-700\">\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{params()!.title}</h3>\n </div>\n </Show>\n\n {/* Video Container — when expanded, fill remaining space (override aspect ratio) */}\n <div class={`relative bg-black ${isExpanded() ? 'flex-1 min-h-0' : aspectClass()}`}>\n <Show\n when={embedUrl()}\n fallback={\n // Direct video file\n <video\n src={params()?.url}\n poster={params()?.poster}\n autoplay={params()?.autoplay}\n controls={params()?.controls !== false}\n loop={params()?.loop}\n muted={params()?.muted}\n playsinline\n class=\"absolute inset-0 w-full h-full object-contain\"\n onError={handleVideoError}\n >\n <track kind=\"captions\" />\n {strings.videoUnsupported}\n </video>\n }\n >\n {/* YouTube/Vimeo embed */}\n <iframe\n src={embedUrl()!}\n title={params()?.title || strings.videoTitle}\n class=\"absolute inset-0 w-full h-full\"\n allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\"\n allowfullscreen\n // v6.21.0 — youtube-nocookie / player.vimeo are not trusted hosts,\n // so under COEP `credentialless` is what lets them load at all.\n // `attr:` + `true | undefined` — see the note in `IframeRenderer`.\n attr:credentialless={\n // No sandbox here: a YouTube/Vimeo embed keeps its provider\n // cookies, so `'auto'` leaves it alone and a COEP host opts in\n // with `iframeCredentialless: 'always'`.\n shouldSetCredentialless(embedUrl()!, config, {\n sandboxedWithoutSameOrigin: false,\n }) || undefined\n }\n loading=\"lazy\"\n />\n </Show>\n </div>\n\n {/* v6.21.0 — a COEP-blocked embed is silent; this link is the way out. */}\n <Show when={embedUrl()}>\n <IframeFallbackLink url={params()?.url || ''} />\n </Show>\n\n {/* Caption */}\n <Show when={params()?.caption}>\n <div class=\"px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0\">\n <p class=\"text-sm text-gray-600 dark:text-gray-400\">{params()!.caption}</p>\n </div>\n </Show>\n </div>\n </ExpandableWrapper>\n )\n}\n\n/**\n * Check if a URL is from a supported video provider\n */\nexport function isSupportedVideoUrl(url: string): boolean {\n const info = parseVideoUrl(url)\n return info.provider !== 'direct' || url.match(/\\.(mp4|webm|ogg|mov)$/i) !== null\n}\n\n/**\n * Get video provider from URL\n */\nexport function getVideoProvider(url: string): VideoProvider {\n return parseVideoUrl(url).provider\n}\n"],"names":["parseVideoUrl","url","youtubeMatch","match","provider","videoId","vimeoMatch","VideoRenderer","props","strings","useMCPUIStrings","config","useMCPUIConfig","params","component","isExpanded","useExpanded","videoInfo","createMemo","embedUrl","info","p","ytParams","URLSearchParams","autoplay","controls","loop","mute","muted","startTime","set","String","vParams","aspectClass","aspectRatio","handleVideoError","e","error","Error","console","onError","_$createComponent","ExpandableWrapper","title","videoTitle","copyData","copyLabel","videoCopy","toolbarVariant","children","_el$","_$getNextElement","_tmpl$4","_el$8","firstChild","_el$9","_co$","_$getNextMarker","nextSibling","_el$4","_el$0","_el$1","_co$2","_el$10","_el$11","_co$3","_$insert","Show","when","_el$2","_tmpl$","_el$3","fallback","_el$12","_tmpl$5","_el$13","_el$14","_el$15","_co$4","addEventListener","videoUnsupported","_$effect","_p$","_v$6","_v$7","poster","_v$8","_v$9","_v$0","_v$1","_$setAttribute","t","a","_$setProperty","o","i","n","undefined","_el$5","_tmpl$2","_v$","_v$2","_v$3","shouldSetCredentialless","sandboxedWithoutSameOrigin","IframeFallbackLink","caption","_el$6","_tmpl$3","_el$7","_v$4","_v$5","_$className","isSupportedVideoUrl","getVideoProvider"],"mappings":"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"}
@@ -0,0 +1,30 @@
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 DEFAULT_MCPUI_CONFIG = {
6
+ iframeCredentialless: "auto",
7
+ customTrustedIframeDomains: [],
8
+ iframePolicy: "strict",
9
+ customIframeDomains: [],
10
+ iframeFallbackLink: "auto",
11
+ chartZoom: "expanded"
12
+ };
13
+ const MCPUIConfigContext = solidJs.createContext(DEFAULT_MCPUI_CONFIG);
14
+ function useMCPUIConfig() {
15
+ return solidJs.mergeProps(DEFAULT_MCPUI_CONFIG, solidJs.useContext(MCPUIConfigContext));
16
+ }
17
+ function MCPUIConfigProvider(props) {
18
+ const value = solidJs.mergeProps(DEFAULT_MCPUI_CONFIG, () => props.config);
19
+ return web.createComponent(MCPUIConfigContext.Provider, {
20
+ value,
21
+ get children() {
22
+ return props.children;
23
+ }
24
+ });
25
+ }
26
+ exports.DEFAULT_MCPUI_CONFIG = DEFAULT_MCPUI_CONFIG;
27
+ exports.MCPUIConfigContext = MCPUIConfigContext;
28
+ exports.MCPUIConfigProvider = MCPUIConfigProvider;
29
+ exports.useMCPUIConfig = useMCPUIConfig;
30
+ //# sourceMappingURL=MCPUIConfigContext.cjs.map
@@ -0,0 +1 @@
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 * ## Why every field is optional\n *\n * This interface grows a key every time the library gains a policy switch,\n * and those releases are MINOR. Were the fields required, adding one would\n * break the build of any consumer holding a COMPLETE `MCPUIConfig` value —\n * a typed constant, a helper that returns one, or a direct\n * `<MCPUIConfigContext.Provider value={…}>` — because their object would\n * suddenly miss a key. Nothing about their behaviour changed; only `tsc`\n * would fail. Optional fields make each new key additive.\n *\n * The completeness guarantee moves from the type to the two values that\n * actually need it, exactly as `MCPUIStrings` does it:\n * `DEFAULT_MCPUI_CONFIG` is `Required<MCPUIConfig>`, so forgetting a default\n * is a compile error HERE, and {@link useMCPUIConfig} returns\n * `Required<MCPUIConfig>`, so every renderer still reads a fully resolved\n * value and never has to null-check a policy.\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 * 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 * 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 `Required<MCPUIConfig>`: the interface's fields are optional so that\n * adding one stays backward compatible, and this annotation is what keeps a\n * new key from shipping without a default.\n */\nexport const DEFAULT_MCPUI_CONFIG: Required<MCPUIConfig> = {\n iframeCredentialless: 'auto',\n customTrustedIframeDomains: [],\n iframePolicy: 'strict',\n customIframeDomains: [],\n iframeFallbackLink: 'auto',\n chartZoom: 'expanded',\n}\n\n/**\n * Deliberately typed with the PARTIAL `MCPUIConfig`, not `Required<…>`: a\n * host that bypasses `MCPUIConfigProvider` and feeds this provider directly\n * may pass whichever keys it cares about, and `useMCPUIConfig` fills the\n * rest. Widening it this way only ever accepts more than before.\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(): Required<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":";;;;AAyJO,MAAMA,uBAA8C;AAAA,EACzDC,sBAAsB;AAAA,EACtBC,4BAA4B,CAAA;AAAA,EAC5BC,cAAc;AAAA,EACdC,qBAAqB,CAAA;AAAA,EACrBC,oBAAoB;AAAA,EACpBC,WAAW;AACb;AAQO,MAAMC,qBAAqBC,QAAAA,cAA2BR,oBAAoB;AAO1E,SAASS,iBAAwC;AACtD,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;;;;;"}