@seed-ship/mcp-ui-solid 6.19.1 → 6.21.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 (282) hide show
  1. package/CHANGELOG.md +663 -0
  2. package/README.md +911 -4
  3. package/dist/adapters/connector.cjs +15 -4
  4. package/dist/adapters/connector.cjs.map +1 -1
  5. package/dist/adapters/connector.d.ts +38 -0
  6. package/dist/adapters/connector.d.ts.map +1 -1
  7. package/dist/adapters/connector.js +15 -4
  8. package/dist/adapters/connector.js.map +1 -1
  9. package/dist/adapters/index.d.ts +4 -3
  10. package/dist/adapters/index.d.ts.map +1 -1
  11. package/dist/adapters/macro-run.cjs +25 -13
  12. package/dist/adapters/macro-run.cjs.map +1 -1
  13. package/dist/adapters/macro-run.d.ts +37 -2
  14. package/dist/adapters/macro-run.d.ts.map +1 -1
  15. package/dist/adapters/macro-run.js +25 -13
  16. package/dist/adapters/macro-run.js.map +1 -1
  17. package/dist/adapters.cjs +2 -0
  18. package/dist/adapters.cjs.map +1 -1
  19. package/dist/adapters.js +4 -2
  20. package/dist/components/ActionGroupRenderer.cjs +3 -1
  21. package/dist/components/ActionGroupRenderer.cjs.map +1 -1
  22. package/dist/components/ActionGroupRenderer.d.ts.map +1 -1
  23. package/dist/components/ActionGroupRenderer.js +3 -1
  24. package/dist/components/ActionGroupRenderer.js.map +1 -1
  25. package/dist/components/AgentCard.cjs +11 -8
  26. package/dist/components/AgentCard.cjs.map +1 -1
  27. package/dist/components/AgentCard.d.ts.map +1 -1
  28. package/dist/components/AgentCard.js +11 -8
  29. package/dist/components/AgentCard.js.map +1 -1
  30. package/dist/components/AgentHandoff.cjs +6 -1
  31. package/dist/components/AgentHandoff.cjs.map +1 -1
  32. package/dist/components/AgentHandoff.d.ts.map +1 -1
  33. package/dist/components/AgentHandoff.js +6 -1
  34. package/dist/components/AgentHandoff.js.map +1 -1
  35. package/dist/components/ArtifactRenderer.cjs +25 -6
  36. package/dist/components/ArtifactRenderer.cjs.map +1 -1
  37. package/dist/components/ArtifactRenderer.d.ts.map +1 -1
  38. package/dist/components/ArtifactRenderer.js +25 -6
  39. package/dist/components/ArtifactRenderer.js.map +1 -1
  40. package/dist/components/AutocompleteDropdown.cjs +30 -24
  41. package/dist/components/AutocompleteDropdown.cjs.map +1 -1
  42. package/dist/components/AutocompleteDropdown.d.ts.map +1 -1
  43. package/dist/components/AutocompleteDropdown.js +30 -24
  44. package/dist/components/AutocompleteDropdown.js.map +1 -1
  45. package/dist/components/AutocompleteFormField.cjs +3 -1
  46. package/dist/components/AutocompleteFormField.cjs.map +1 -1
  47. package/dist/components/AutocompleteFormField.d.ts.map +1 -1
  48. package/dist/components/AutocompleteFormField.js +4 -2
  49. package/dist/components/AutocompleteFormField.js.map +1 -1
  50. package/dist/components/BriefingDiff.cjs +45 -39
  51. package/dist/components/BriefingDiff.cjs.map +1 -1
  52. package/dist/components/BriefingDiff.d.ts.map +1 -1
  53. package/dist/components/BriefingDiff.js +45 -39
  54. package/dist/components/BriefingDiff.js.map +1 -1
  55. package/dist/components/CarouselRenderer.cjs +8 -2
  56. package/dist/components/CarouselRenderer.cjs.map +1 -1
  57. package/dist/components/CarouselRenderer.d.ts.map +1 -1
  58. package/dist/components/CarouselRenderer.js +8 -2
  59. package/dist/components/CarouselRenderer.js.map +1 -1
  60. package/dist/components/ChartJSRenderer.cjs +60 -36
  61. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  62. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  63. package/dist/components/ChartJSRenderer.js +61 -37
  64. package/dist/components/ChartJSRenderer.js.map +1 -1
  65. package/dist/components/ChatPrompt.cjs +15 -9
  66. package/dist/components/ChatPrompt.cjs.map +1 -1
  67. package/dist/components/ChatPrompt.d.ts.map +1 -1
  68. package/dist/components/ChatPrompt.js +15 -9
  69. package/dist/components/ChatPrompt.js.map +1 -1
  70. package/dist/components/CodeBlockRenderer.cjs +34 -16
  71. package/dist/components/CodeBlockRenderer.cjs.map +1 -1
  72. package/dist/components/CodeBlockRenderer.d.ts.map +1 -1
  73. package/dist/components/CodeBlockRenderer.js +34 -16
  74. package/dist/components/CodeBlockRenderer.js.map +1 -1
  75. package/dist/components/DataPreviewSection.cjs +91 -44
  76. package/dist/components/DataPreviewSection.cjs.map +1 -1
  77. package/dist/components/DataPreviewSection.d.ts.map +1 -1
  78. package/dist/components/DataPreviewSection.js +92 -45
  79. package/dist/components/DataPreviewSection.js.map +1 -1
  80. package/dist/components/DegradedFallback.cjs +20 -16
  81. package/dist/components/DegradedFallback.cjs.map +1 -1
  82. package/dist/components/DegradedFallback.d.ts.map +1 -1
  83. package/dist/components/DegradedFallback.js +20 -16
  84. package/dist/components/DegradedFallback.js.map +1 -1
  85. package/dist/components/FooterRenderer.cjs +21 -17
  86. package/dist/components/FooterRenderer.cjs.map +1 -1
  87. package/dist/components/FooterRenderer.d.ts.map +1 -1
  88. package/dist/components/FooterRenderer.js +21 -17
  89. package/dist/components/FooterRenderer.js.map +1 -1
  90. package/dist/components/FormFieldRenderer.cjs +116 -93
  91. package/dist/components/FormFieldRenderer.cjs.map +1 -1
  92. package/dist/components/FormFieldRenderer.d.ts.map +1 -1
  93. package/dist/components/FormFieldRenderer.js +116 -93
  94. package/dist/components/FormFieldRenderer.js.map +1 -1
  95. package/dist/components/FormRenderer.cjs +55 -31
  96. package/dist/components/FormRenderer.cjs.map +1 -1
  97. package/dist/components/FormRenderer.d.ts.map +1 -1
  98. package/dist/components/FormRenderer.js +55 -31
  99. package/dist/components/FormRenderer.js.map +1 -1
  100. package/dist/components/GenerativeUIErrorBoundary.cjs +20 -15
  101. package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
  102. package/dist/components/GenerativeUIErrorBoundary.d.ts.map +1 -1
  103. package/dist/components/GenerativeUIErrorBoundary.js +20 -15
  104. package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
  105. package/dist/components/GraphRenderer.cjs +56 -33
  106. package/dist/components/GraphRenderer.cjs.map +1 -1
  107. package/dist/components/GraphRenderer.d.ts.map +1 -1
  108. package/dist/components/GraphRenderer.js +56 -33
  109. package/dist/components/GraphRenderer.js.map +1 -1
  110. package/dist/components/IframeFallbackLink.cjs +37 -0
  111. package/dist/components/IframeFallbackLink.cjs.map +1 -0
  112. package/dist/components/IframeFallbackLink.d.ts +23 -0
  113. package/dist/components/IframeFallbackLink.d.ts.map +1 -0
  114. package/dist/components/IframeFallbackLink.js +37 -0
  115. package/dist/components/IframeFallbackLink.js.map +1 -0
  116. package/dist/components/ImageGalleryRenderer.cjs +13 -4
  117. package/dist/components/ImageGalleryRenderer.cjs.map +1 -1
  118. package/dist/components/ImageGalleryRenderer.d.ts.map +1 -1
  119. package/dist/components/ImageGalleryRenderer.js +13 -4
  120. package/dist/components/ImageGalleryRenderer.js.map +1 -1
  121. package/dist/components/LightboxOverlay.cjs +16 -8
  122. package/dist/components/LightboxOverlay.cjs.map +1 -1
  123. package/dist/components/LightboxOverlay.d.ts.map +1 -1
  124. package/dist/components/LightboxOverlay.js +17 -9
  125. package/dist/components/LightboxOverlay.js.map +1 -1
  126. package/dist/components/MapRenderer.cjs +59 -29
  127. package/dist/components/MapRenderer.cjs.map +1 -1
  128. package/dist/components/MapRenderer.d.ts +10 -2
  129. package/dist/components/MapRenderer.d.ts.map +1 -1
  130. package/dist/components/MapRenderer.js +60 -30
  131. package/dist/components/MapRenderer.js.map +1 -1
  132. package/dist/components/ModalRenderer.cjs +4 -1
  133. package/dist/components/ModalRenderer.cjs.map +1 -1
  134. package/dist/components/ModalRenderer.d.ts.map +1 -1
  135. package/dist/components/ModalRenderer.js +5 -2
  136. package/dist/components/ModalRenderer.js.map +1 -1
  137. package/dist/components/ScratchpadPanel.cjs +578 -535
  138. package/dist/components/ScratchpadPanel.cjs.map +1 -1
  139. package/dist/components/ScratchpadPanel.d.ts.map +1 -1
  140. package/dist/components/ScratchpadPanel.js +578 -535
  141. package/dist/components/ScratchpadPanel.js.map +1 -1
  142. package/dist/components/StreamingUIRenderer.cjs +92 -28
  143. package/dist/components/StreamingUIRenderer.cjs.map +1 -1
  144. package/dist/components/StreamingUIRenderer.d.ts.map +1 -1
  145. package/dist/components/StreamingUIRenderer.js +92 -28
  146. package/dist/components/StreamingUIRenderer.js.map +1 -1
  147. package/dist/components/UIResourceRenderer.cjs +481 -365
  148. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  149. package/dist/components/UIResourceRenderer.d.ts +21 -0
  150. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  151. package/dist/components/UIResourceRenderer.js +484 -368
  152. package/dist/components/UIResourceRenderer.js.map +1 -1
  153. package/dist/components/VerifiedText.cjs +39 -20
  154. package/dist/components/VerifiedText.cjs.map +1 -1
  155. package/dist/components/VerifiedText.d.ts +2 -1
  156. package/dist/components/VerifiedText.d.ts.map +1 -1
  157. package/dist/components/VerifiedText.js +39 -20
  158. package/dist/components/VerifiedText.js.map +1 -1
  159. package/dist/components/VideoRenderer.cjs +51 -20
  160. package/dist/components/VideoRenderer.cjs.map +1 -1
  161. package/dist/components/VideoRenderer.d.ts.map +1 -1
  162. package/dist/components/VideoRenderer.js +51 -20
  163. package/dist/components/VideoRenderer.js.map +1 -1
  164. package/dist/components/chart-data-table.cjs +38 -17
  165. package/dist/components/chart-data-table.cjs.map +1 -1
  166. package/dist/components/chart-data-table.d.ts +30 -1
  167. package/dist/components/chart-data-table.d.ts.map +1 -1
  168. package/dist/components/chart-data-table.js +38 -17
  169. package/dist/components/chart-data-table.js.map +1 -1
  170. package/dist/context/MCPActionContext.cjs +3 -1
  171. package/dist/context/MCPActionContext.cjs.map +1 -1
  172. package/dist/context/MCPActionContext.d.ts.map +1 -1
  173. package/dist/context/MCPActionContext.js +3 -1
  174. package/dist/context/MCPActionContext.js.map +1 -1
  175. package/dist/context/MCPUIConfigContext.cjs +29 -0
  176. package/dist/context/MCPUIConfigContext.cjs.map +1 -0
  177. package/dist/context/MCPUIConfigContext.d.ts +124 -0
  178. package/dist/context/MCPUIConfigContext.d.ts.map +1 -0
  179. package/dist/context/MCPUIConfigContext.js +29 -0
  180. package/dist/context/MCPUIConfigContext.js.map +1 -0
  181. package/dist/context/MCPUIStringsContext.cjs +287 -2
  182. package/dist/context/MCPUIStringsContext.cjs.map +1 -1
  183. package/dist/context/MCPUIStringsContext.d.ts +607 -3
  184. package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
  185. package/dist/context/MCPUIStringsContext.js +287 -2
  186. package/dist/context/MCPUIStringsContext.js.map +1 -1
  187. package/dist/hooks/index.d.ts +2 -2
  188. package/dist/hooks/index.d.ts.map +1 -1
  189. package/dist/hooks/useStreamingUI.cjs +28 -10
  190. package/dist/hooks/useStreamingUI.cjs.map +1 -1
  191. package/dist/hooks/useStreamingUI.d.ts +37 -0
  192. package/dist/hooks/useStreamingUI.d.ts.map +1 -1
  193. package/dist/hooks/useStreamingUI.js +28 -10
  194. package/dist/hooks/useStreamingUI.js.map +1 -1
  195. package/dist/hooks.cjs +1 -0
  196. package/dist/hooks.cjs.map +1 -1
  197. package/dist/hooks.js +2 -1
  198. package/dist/index.cjs +29 -8
  199. package/dist/index.cjs.map +1 -1
  200. package/dist/index.d.cts +12 -4
  201. package/dist/index.d.ts +12 -4
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +24 -3
  204. package/dist/index.js.map +1 -1
  205. package/dist/services/index.d.ts +1 -1
  206. package/dist/services/index.d.ts.map +1 -1
  207. package/dist/services/validation.cjs +52 -26
  208. package/dist/services/validation.cjs.map +1 -1
  209. package/dist/services/validation.d.ts +67 -2
  210. package/dist/services/validation.d.ts.map +1 -1
  211. package/dist/services/validation.js +52 -26
  212. package/dist/services/validation.js.map +1 -1
  213. package/dist/utils/degraded-projections.cjs +37 -12
  214. package/dist/utils/degraded-projections.cjs.map +1 -1
  215. package/dist/utils/degraded-projections.d.ts +39 -3
  216. package/dist/utils/degraded-projections.d.ts.map +1 -1
  217. package/dist/utils/degraded-projections.js +37 -12
  218. package/dist/utils/degraded-projections.js.map +1 -1
  219. package/dist/utils/format-string.cjs +10 -0
  220. package/dist/utils/format-string.cjs.map +1 -0
  221. package/dist/utils/format-string.d.ts +26 -0
  222. package/dist/utils/format-string.d.ts.map +1 -0
  223. package/dist/utils/format-string.js +10 -0
  224. package/dist/utils/format-string.js.map +1 -0
  225. package/dist/utils/iframe-coep.cjs +30 -0
  226. package/dist/utils/iframe-coep.cjs.map +1 -0
  227. package/dist/utils/iframe-coep.d.ts +46 -0
  228. package/dist/utils/iframe-coep.d.ts.map +1 -0
  229. package/dist/utils/iframe-coep.js +30 -0
  230. package/dist/utils/iframe-coep.js.map +1 -0
  231. package/dist/validation.cjs +5 -0
  232. package/dist/validation.cjs.map +1 -1
  233. package/dist/validation.d.cts +2 -1
  234. package/dist/validation.d.ts +2 -1
  235. package/dist/validation.d.ts.map +1 -1
  236. package/dist/validation.js +6 -1
  237. package/package.json +1 -1
  238. package/src/adapters/connector.ts +58 -4
  239. package/src/adapters/index.ts +12 -2
  240. package/src/adapters/macro-run.ts +71 -11
  241. package/src/components/ActionGroupRenderer.tsx +3 -1
  242. package/src/components/AgentCard.tsx +27 -9
  243. package/src/components/AgentHandoff.tsx +4 -1
  244. package/src/components/ArtifactRenderer.tsx +17 -5
  245. package/src/components/AutocompleteDropdown.tsx +8 -6
  246. package/src/components/AutocompleteFormField.tsx +5 -1
  247. package/src/components/BriefingDiff.tsx +11 -3
  248. package/src/components/CarouselRenderer.tsx +4 -2
  249. package/src/components/ChartJSRenderer.tsx +18 -9
  250. package/src/components/ChatPrompt.tsx +13 -8
  251. package/src/components/CodeBlockRenderer.tsx +12 -10
  252. package/src/components/DataPreviewSection.tsx +92 -26
  253. package/src/components/DegradedFallback.tsx +4 -2
  254. package/src/components/FooterRenderer.tsx +3 -1
  255. package/src/components/FormFieldRenderer.tsx +34 -19
  256. package/src/components/FormRenderer.tsx +38 -10
  257. package/src/components/GenerativeUIErrorBoundary.tsx +8 -3
  258. package/src/components/GraphRenderer.tsx +31 -16
  259. package/src/components/IframeFallbackLink.tsx +57 -0
  260. package/src/components/ImageGalleryRenderer.tsx +8 -4
  261. package/src/components/LightboxOverlay.tsx +6 -4
  262. package/src/components/MapRenderer.tsx +57 -20
  263. package/src/components/ModalRenderer.tsx +3 -1
  264. package/src/components/ScratchpadPanel.tsx +95 -44
  265. package/src/components/StreamingUIRenderer.tsx +41 -11
  266. package/src/components/UIResourceRenderer.tsx +176 -67
  267. package/src/components/VerifiedText.tsx +19 -9
  268. package/src/components/VideoRenderer.tsx +26 -4
  269. package/src/components/chart-data-table.ts +68 -14
  270. package/src/context/MCPActionContext.tsx +4 -1
  271. package/src/context/MCPUIConfigContext.tsx +151 -0
  272. package/src/context/MCPUIStringsContext.tsx +1014 -1
  273. package/src/hooks/index.ts +2 -1
  274. package/src/hooks/useStreamingUI.ts +64 -10
  275. package/src/index.ts +38 -0
  276. package/src/services/index.ts +1 -0
  277. package/src/services/validation.ts +131 -32
  278. package/src/solid-jsx-attrs.d.ts +24 -0
  279. package/src/utils/degraded-projections.ts +75 -12
  280. package/src/utils/format-string.ts +33 -0
  281. package/src/utils/iframe-coep.ts +74 -0
  282. package/src/validation.ts +9 -0
@@ -6,12 +6,14 @@
6
6
  *
7
7
  * Modes:
8
8
  * - highlight: ✅/⚠️ badges next to numbers (default)
9
- * - strip: replaces hallucinated numbers with [non vérifié]
9
+ * - strip: replaces hallucinated numbers with the `verifiedStripLabel`
10
+ * chrome string ('[unverified]' by default)
10
11
  * - annotate: tooltip on hover with closest source number
11
12
  */
12
13
 
13
14
  import { createMemo, For } from 'solid-js'
14
15
  import type { DataValidation, HallucinatedNumber } from '../types/chat-bus'
16
+ import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'
15
17
 
16
18
  export interface VerifiedTextProps {
17
19
  text: string
@@ -94,6 +96,7 @@ function buildAnnotatedSegments(text: string, validation: DataValidation): TextS
94
96
  }
95
97
 
96
98
  export function VerifiedText(props: VerifiedTextProps) {
99
+ const strings = useMCPUIStrings()
97
100
  const mode = () => props.mode || 'highlight'
98
101
 
99
102
  const segments = createMemo<TextSegment[]>(() => {
@@ -115,10 +118,10 @@ export function VerifiedText(props: VerifiedTextProps) {
115
118
  return (
116
119
  <span
117
120
  class="inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300"
118
- title="Verified against source data"
121
+ title={strings.verifiedTitle}
119
122
  >
120
123
  {seg.content}
121
- <span class="text-xs opacity-70" aria-label="verified">&#x2705;</span>
124
+ <span class="text-xs opacity-70" aria-label={strings.verifiedAria}>&#x2705;</span>
122
125
  </span>
123
126
  )
124
127
  }
@@ -127,9 +130,12 @@ export function VerifiedText(props: VerifiedTextProps) {
127
130
  const h = seg.item!
128
131
  const tooltipText = () => {
129
132
  if (h.closest != null && h.distance != null) {
130
- return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`
133
+ return formatMCPUIString(strings.verifiedNotFoundClosest, {
134
+ closest: h.closest,
135
+ pct: Math.round(h.distance * 100),
136
+ })
131
137
  }
132
- return 'Not found in source data'
138
+ return strings.verifiedNotFound
133
139
  }
134
140
 
135
141
  if (mode() === 'strip') {
@@ -138,7 +144,7 @@ export function VerifiedText(props: VerifiedTextProps) {
138
144
  class="inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs"
139
145
  title={tooltipText()}
140
146
  >
141
- [non v&eacute;rifi&eacute;]
147
+ {strings.verifiedStripLabel}
142
148
  </span>
143
149
  )
144
150
  }
@@ -151,7 +157,7 @@ export function VerifiedText(props: VerifiedTextProps) {
151
157
  role={props.onHallucinationClick ? 'button' : undefined}
152
158
  >
153
159
  {seg.content}
154
- <span class="text-xs" aria-label="unverified">&#x26A0;&#xFE0F;</span>
160
+ <span class="text-xs" aria-label={strings.unverifiedAria}>&#x26A0;&#xFE0F;</span>
155
161
  </span>
156
162
  )
157
163
  }}
@@ -172,8 +178,12 @@ export function VerifiedText(props: VerifiedTextProps) {
172
178
  />
173
179
  </div>
174
180
  <span>
175
- {Math.round(props.validation.confidence * 100)}% verified
176
- ({props.validation.hallucinated.length} unverified)
181
+ {formatMCPUIString(strings.verifiedConfidence, {
182
+ pct: Math.round(props.validation.confidence * 100),
183
+ })}{' '}
184
+ {formatMCPUIString(strings.verifiedUnverifiedCount, {
185
+ count: props.validation.hallucinated.length,
186
+ })}
177
187
  </span>
178
188
  </div>
179
189
  )}
@@ -8,6 +8,10 @@
8
8
  import { Component, createMemo, Show } from 'solid-js'
9
9
  import type { UIComponent, VideoComponentParams } from '../types'
10
10
  import { ExpandableWrapper, useExpanded } from './ExpandableWrapper'
11
+ import { useMCPUIStrings } from '../context/MCPUIStringsContext'
12
+ import { useMCPUIConfig } from '../context/MCPUIConfigContext'
13
+ import { shouldSetCredentialless } from '../utils/iframe-coep'
14
+ import { IframeFallbackLink } from './IframeFallbackLink'
11
15
 
12
16
  export interface VideoRendererProps {
13
17
  /**
@@ -74,6 +78,8 @@ function parseVideoUrl(url: string): VideoInfo {
74
78
  }
75
79
 
76
80
  export const VideoRenderer: Component<VideoRendererProps> = (props) => {
81
+ const strings = useMCPUIStrings()
82
+ const config = useMCPUIConfig()
77
83
  const params = () => props.params || (props.component?.params as VideoComponentParams)
78
84
  const isExpanded = useExpanded()
79
85
 
@@ -135,9 +141,9 @@ export const VideoRenderer: Component<VideoRendererProps> = (props) => {
135
141
 
136
142
  return (
137
143
  <ExpandableWrapper
138
- title={params()?.title || 'Video'}
144
+ title={params()?.title || strings.videoTitle}
139
145
  copyData={params()?.url || ''}
140
- copyLabel="Copy video URL"
146
+ copyLabel={strings.videoCopy}
141
147
  toolbarVariant={props.toolbarVariant}
142
148
  >
143
149
  <div class={`w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${
@@ -168,22 +174,38 @@ export const VideoRenderer: Component<VideoRendererProps> = (props) => {
168
174
  onError={handleVideoError}
169
175
  >
170
176
  <track kind="captions" />
171
- Your browser does not support the video tag.
177
+ {strings.videoUnsupported}
172
178
  </video>
173
179
  }
174
180
  >
175
181
  {/* YouTube/Vimeo embed */}
176
182
  <iframe
177
183
  src={embedUrl()!}
178
- title={params()?.title || 'Video'}
184
+ title={params()?.title || strings.videoTitle}
179
185
  class="absolute inset-0 w-full h-full"
180
186
  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
181
187
  allowfullscreen
188
+ // v6.21.0 — youtube-nocookie / player.vimeo are not trusted hosts,
189
+ // so under COEP `credentialless` is what lets them load at all.
190
+ // `attr:` + `true | undefined` — see the note in `IframeRenderer`.
191
+ attr:credentialless={
192
+ // No sandbox here: a YouTube/Vimeo embed keeps its provider
193
+ // cookies, so `'auto'` leaves it alone and a COEP host opts in
194
+ // with `iframeCredentialless: 'always'`.
195
+ shouldSetCredentialless(embedUrl()!, config, {
196
+ sandboxedWithoutSameOrigin: false,
197
+ }) || undefined
198
+ }
182
199
  loading="lazy"
183
200
  />
184
201
  </Show>
185
202
  </div>
186
203
 
204
+ {/* v6.21.0 — a COEP-blocked embed is silent; this link is the way out. */}
205
+ <Show when={embedUrl()}>
206
+ <IframeFallbackLink url={params()?.url || ''} />
207
+ </Show>
208
+
187
209
  {/* Caption */}
188
210
  <Show when={params()?.caption}>
189
211
  <div class="px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex-shrink-0">
@@ -1,3 +1,44 @@
1
+ import { formatMCPUIString } from '../utils/format-string';
2
+
3
+ /**
4
+ * Column headers and series names of the accessible chart data table.
5
+ *
6
+ * `chartToDataTable` is a pure helper with no access to `MCPUIStrings`, so
7
+ * the wording is injected: it takes an optional trailing `labels` partial,
8
+ * which `ChartJSRenderer` feeds from `useMCPUIStrings()`. Left out, the
9
+ * English defaults below apply — the pre-v6.20.0 behaviour.
10
+ *
11
+ * `x` / `y` / `r` stay untranslated on purpose: they are the Chart.js point
12
+ * property NAMES the cells mirror, not prose.
13
+ *
14
+ * @since v6.20.0
15
+ */
16
+ export interface ChartDataTableLabels {
17
+ /** Series column of the per-point table. */
18
+ series: string;
19
+ /** Point-index column of the per-point table. */
20
+ point: string;
21
+ /** Label column (categorical table, and per-point table when labelled). */
22
+ label: string;
23
+ /** Fallback dataset name. Template — `{n}`. */
24
+ seriesName: string;
25
+ /** Chart.js point property names — machine tokens, rarely overridden. */
26
+ x: string;
27
+ y: string;
28
+ r: string;
29
+ }
30
+
31
+ /** English defaults for {@link ChartDataTableLabels}. */
32
+ export const CHART_DATA_TABLE_LABELS: ChartDataTableLabels = {
33
+ series: 'Series',
34
+ point: 'Point',
35
+ label: 'Label',
36
+ seriesName: 'Series {n}',
37
+ x: 'x',
38
+ y: 'y',
39
+ r: 'r',
40
+ };
41
+
1
42
  export interface ChartDataTable {
2
43
  columns: string[];
3
44
  rows: Array<Array<string | number>>;
@@ -41,37 +82,41 @@ function isPoint(value: unknown): value is Record<string, unknown> {
41
82
  * coordinates. Categorical charts use a compact wide table; scatter, bubble,
42
83
  * and object-valued line charts use one row per point so x/y/r remain distinct.
43
84
  */
44
- export function chartToDataTable(params: ChartDataLike): ChartDataTable {
85
+ export function chartToDataTable(
86
+ params: ChartDataLike,
87
+ labels?: Partial<ChartDataTableLabels>
88
+ ): ChartDataTable {
89
+ const l: ChartDataTableLabels = { ...CHART_DATA_TABLE_LABELS, ...labels };
45
90
  const datasets = params.data?.datasets ?? [];
46
- const labels = params.data?.labels ?? [];
91
+ const dataLabels = params.data?.labels ?? [];
47
92
  const pointData =
48
93
  params.type === 'scatter' ||
49
94
  params.type === 'bubble' ||
50
95
  datasets.some((dataset) => dataset.data?.some(isPoint));
51
96
 
52
97
  if (pointData) {
53
- const hasLabels = labels.length > 0;
98
+ const hasLabels = dataLabels.length > 0;
54
99
  const hasRadius =
55
100
  params.type === 'bubble' ||
56
101
  datasets.some((dataset) => dataset.data?.some((value) => isPoint(value) && 'r' in value));
57
102
  const columns = [
58
- 'Series',
59
- 'Point',
60
- ...(hasLabels ? ['Label'] : []),
61
- 'x',
62
- 'y',
63
- ...(hasRadius ? ['r'] : []),
103
+ l.series,
104
+ l.point,
105
+ ...(hasLabels ? [l.label] : []),
106
+ l.x,
107
+ l.y,
108
+ ...(hasRadius ? [l.r] : []),
64
109
  ];
65
110
  const rows: Array<Array<string | number>> = [];
66
111
 
67
112
  datasets.forEach((dataset, datasetIndex) => {
68
- const series = dataset.label || `Series ${datasetIndex + 1}`;
113
+ const series = dataset.label || formatMCPUIString(l.seriesName, { n: datasetIndex + 1 });
69
114
  (dataset.data ?? []).forEach((value, pointIndex) => {
70
115
  const point = isPoint(value) ? value : { y: value };
71
116
  rows.push([
72
117
  series,
73
118
  pointIndex + 1,
74
- ...(hasLabels ? [tableCell(labels[pointIndex])] : []),
119
+ ...(hasLabels ? [tableCell(dataLabels[pointIndex])] : []),
75
120
  tableCell(point.x),
76
121
  tableCell(point.y),
77
122
  ...(hasRadius ? [tableCell(point.r)] : []),
@@ -82,13 +127,22 @@ export function chartToDataTable(params: ChartDataLike): ChartDataTable {
82
127
  return { columns, rows };
83
128
  }
84
129
 
85
- const rowCount = Math.max(labels.length, ...datasets.map((dataset) => dataset.data?.length ?? 0), 0);
86
- const columns = ['Label', ...datasets.map((dataset, index) => dataset.label || `Series ${index + 1}`)];
130
+ const rowCount = Math.max(
131
+ dataLabels.length,
132
+ ...datasets.map((dataset) => dataset.data?.length ?? 0),
133
+ 0
134
+ );
135
+ const columns = [
136
+ l.label,
137
+ ...datasets.map(
138
+ (dataset, index) => dataset.label || formatMCPUIString(l.seriesName, { n: index + 1 })
139
+ ),
140
+ ];
87
141
  const rows: Array<Array<string | number>> = [];
88
142
 
89
143
  for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
90
144
  rows.push([
91
- tableCell(labels[rowIndex] ?? rowIndex + 1),
145
+ tableCell(dataLabels[rowIndex] ?? rowIndex + 1),
92
146
  ...datasets.map((dataset) => tableCell(dataset.data?.[rowIndex])),
93
147
  ]);
94
148
  }
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { createContext, createSignal, useContext, ParentComponent, Accessor } from 'solid-js'
7
+ import { useMCPUIStrings } from './MCPUIStringsContext'
7
8
 
8
9
  /**
9
10
  * Action request payload
@@ -223,6 +224,8 @@ const defaultExecutor = async (request: ActionRequest): Promise<ActionResult> =>
223
224
  * ```
224
225
  */
225
226
  export const MCPActionProvider: ParentComponent<MCPActionProviderProps> = (props) => {
227
+ // The error of a failed action can be rendered by FormRenderer.
228
+ const strings = useMCPUIStrings()
226
229
  const [isExecuting, setIsExecuting] = createSignal(false)
227
230
  const [lastResult, setLastResult] = createSignal<ActionResult>()
228
231
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -270,7 +273,7 @@ export const MCPActionProvider: ParentComponent<MCPActionProviderProps> = (props
270
273
  } catch (error) {
271
274
  const errorResult: ActionResult = {
272
275
  success: false,
273
- error: error instanceof Error ? error.message : 'Unknown error',
276
+ error: error instanceof Error ? error.message : strings.errorUnknown,
274
277
  timestamp: new Date().toISOString(),
275
278
  toolName: request.toolName,
276
279
  }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * MCPUIConfigContext — host-level rendering policy for the library's iframes.
3
+ *
4
+ * @since v6.21.0
5
+ *
6
+ * ## Why
7
+ *
8
+ * A host that serves `Cross-Origin-Embedder-Policy: credentialless` makes the
9
+ * browser refuse every cross-origin iframe whose own document does not send a
10
+ * COEP header — which is YouTube, Vimeo, Google Docs, Notion and nearly all of
11
+ * `DEFAULT_IFRAME_DOMAINS`. The escape hatch is the boolean HTML attribute
12
+ * `credentialless` on the `<iframe>` itself: the document then loads, but
13
+ * without access to the cookies and storage of its own origin.
14
+ *
15
+ * That trade-off is free for a public video or chart and fatal for an
16
+ * authenticated embed, so the library keys it on the distinction it already
17
+ * makes: `TRUSTED_IFRAME_DOMAINS` (the hosts that receive `allow-same-origin`
18
+ * because they need their own cookies) do NOT get the attribute; everything
19
+ * else does. This context lets a host override that, add its own trusted
20
+ * hosts, and control the "open in a new tab" fallback link.
21
+ *
22
+ * ## Scope — policy only, NOT strings
23
+ *
24
+ * Text lives in `MCPUIStrings` (`MCPUIStringsContext`). This context carries
25
+ * only behavioural switches, and like the strings context every renderer works
26
+ * standalone: with no provider mounted, `DEFAULT_MCPUI_CONFIG` applies.
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * import { MCPUIConfigProvider } from '@seed-ship/mcp-ui-solid'
31
+ *
32
+ * <MCPUIConfigProvider config={{ customTrustedIframeDomains: ['embed.acme.com'] }}>
33
+ * <App />
34
+ * </MCPUIConfigProvider>
35
+ * ```
36
+ */
37
+
38
+ import { createContext, mergeProps, useContext, type JSX } from 'solid-js'
39
+ import type { IframePolicy } from '../types'
40
+
41
+ /**
42
+ * Host-level rendering policy. Every field has a default — a provider passes
43
+ * a partial override.
44
+ */
45
+ export interface MCPUIConfig {
46
+ /**
47
+ * When the library puts the boolean `credentialless` attribute on an
48
+ * `<iframe>` it renders.
49
+ *
50
+ * - `'auto'` (default) — on every iframe whose host is NOT in
51
+ * `TRUSTED_IFRAME_DOMAINS` (plus `customTrustedIframeDomains`). Those
52
+ * hosts already ran without cookies, since their sandbox has no
53
+ * `allow-same-origin`; the attribute is what unblocks them under COEP.
54
+ * - `'always'` — on every iframe, trusted hosts included. An authenticated
55
+ * embed will then render its login screen.
56
+ * - `'never'` — never. The right value for a host that sends no COEP header
57
+ * and does not want its embeds to lose their cookies.
58
+ *
59
+ * Chrome/Edge 110+ honour the attribute; Firefox ignores it (iframes stay
60
+ * blocked while the host sends COEP); Safari ignores the COEP value itself,
61
+ * so nothing is blocked there in the first place.
62
+ */
63
+ iframeCredentialless: 'auto' | 'always' | 'never'
64
+
65
+ /**
66
+ * Extra hosts treated as trusted, on top of `TRUSTED_IFRAME_DOMAINS`:
67
+ * no `credentialless` attribute, and `allow-same-origin` in the sandbox.
68
+ * A subdomain of a listed host matches too.
69
+ *
70
+ * This only RECLASSIFIES a host the allow-list already accepts. To render an
71
+ * iframe whose host is outside `DEFAULT_IFRAME_DOMAINS`, add it to
72
+ * {@link MCPUIConfig.customIframeDomains} with `iframePolicy: 'extend'`.
73
+ */
74
+ customTrustedIframeDomains: string[]
75
+
76
+ /**
77
+ * How `UIResourceRenderer` validates an `iframe` component's host:
78
+ * `'strict'` (default) accepts `DEFAULT_IFRAME_DOMAINS` only, `'extend'`
79
+ * also accepts {@link MCPUIConfig.customIframeDomains}.
80
+ */
81
+ iframePolicy: IframePolicy
82
+
83
+ /**
84
+ * Extra hosts the allow-list accepts when `iframePolicy` is `'extend'`.
85
+ * Without this, a component pointing at an unlisted host is replaced by the
86
+ * validation card before any renderer runs.
87
+ */
88
+ customIframeDomains: string[]
89
+
90
+ /**
91
+ * When the library renders an "open in a new tab" link under an embed
92
+ * (`strings.iframeOpenInNewTab`).
93
+ *
94
+ * A COEP-blocked iframe fires no event the parent page can observe, so
95
+ * without this the user sees an unexplained blank frame.
96
+ *
97
+ * - `'auto'` (default) — only when the page is cross-origin isolated
98
+ * (`window.crossOriginIsolated`). That flag needs COOP `same-origin` AND
99
+ * COEP, so a host that sends COEP alone still blocks embeds while the
100
+ * flag is false: set `'always'` there. Read after mount, never during
101
+ * render, so SSR markup and hydration agree.
102
+ * - `'always'` / `'never'` — unconditional.
103
+ */
104
+ iframeFallbackLink: 'auto' | 'always' | 'never'
105
+ }
106
+
107
+ /**
108
+ * Defaults. Chosen so a host that sends no COEP header sees no change from
109
+ * 6.20.0 apart from the fallback link, which `'auto'` keeps hidden there.
110
+ */
111
+ export const DEFAULT_MCPUI_CONFIG: MCPUIConfig = {
112
+ iframeCredentialless: 'auto',
113
+ customTrustedIframeDomains: [],
114
+ iframePolicy: 'strict',
115
+ customIframeDomains: [],
116
+ iframeFallbackLink: 'auto',
117
+ }
118
+
119
+ export const MCPUIConfigContext = createContext<MCPUIConfig>(DEFAULT_MCPUI_CONFIG)
120
+
121
+ /**
122
+ * Reads the active host config. Returns `DEFAULT_MCPUI_CONFIG` when no
123
+ * `<MCPUIConfigProvider>` is mounted above.
124
+ */
125
+ export function useMCPUIConfig(): MCPUIConfig {
126
+ return mergeProps(DEFAULT_MCPUI_CONFIG, useContext(MCPUIConfigContext))
127
+ }
128
+
129
+ export interface MCPUIConfigProviderProps {
130
+ /**
131
+ * Partial override of the host config. Any key left unset falls back to
132
+ * `DEFAULT_MCPUI_CONFIG`.
133
+ */
134
+ config?: Partial<MCPUIConfig>
135
+ children: JSX.Element
136
+ }
137
+
138
+ /**
139
+ * Provides the host config to every MCP-UI renderer below it.
140
+ * Merges the partial `config` override over the defaults.
141
+ */
142
+ export function MCPUIConfigProvider(props: MCPUIConfigProviderProps): JSX.Element {
143
+ // The function source keeps replacement `config` objects reactive while
144
+ // mergeProps fills any omitted key without taking a one-time snapshot.
145
+ const value = mergeProps(DEFAULT_MCPUI_CONFIG, () => props.config)
146
+ return (
147
+ <MCPUIConfigContext.Provider value={value}>
148
+ {props.children}
149
+ </MCPUIConfigContext.Provider>
150
+ )
151
+ }