@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
@@ -14,13 +14,23 @@
14
14
  * ```
15
15
  */
16
16
 
17
- export { connectorResultToUILayout, connectorActionsToActionGroup } from './connector';
17
+ export {
18
+ connectorResultToUILayout,
19
+ connectorActionsToActionGroup,
20
+ DEFAULT_CONNECTOR_MESSAGES,
21
+ } from './connector';
18
22
  export type {
19
23
  ConnectorResultToUILayoutOptions,
20
24
  ConnectorActionsToActionGroupOptions,
25
+ ConnectorAdapterMessages,
21
26
  } from './connector';
22
27
 
23
- export { macroRunToScratchpadState, macroInterrogationToChatPromptConfig } from './macro-run';
28
+ export {
29
+ macroRunToScratchpadState,
30
+ macroInterrogationToChatPromptConfig,
31
+ DEFAULT_MACRO_RUN_MESSAGES,
32
+ } from './macro-run';
33
+ export type { MacroRunAdapterMessages, MacroRunAdapterOptions } from './macro-run';
24
34
 
25
35
  export {
26
36
  createComparisonLayout,
@@ -174,7 +174,59 @@ function resultSectionType(componentType: unknown): ScratchpadSection['type'] {
174
174
  }
175
175
  }
176
176
 
177
- function buildError(run: MacroRunV1): ScratchpadState['error'] | undefined {
177
+ /**
178
+ * The English wording this adapter produces on its own — section titles and
179
+ * the fallbacks used when the run (or the interrogation) carries none.
180
+ *
181
+ * The adapter is runtime-free by contract: no `solid-js`, no
182
+ * `MCPUIStringsContext`. Hosts that render in another language pass a
183
+ * partial override through `MacroRunAdapterOptions.messages`, exactly like
184
+ * `ConnectorResultToUILayoutOptions.messages`.
185
+ *
186
+ * @since v6.20.0
187
+ */
188
+ export interface MacroRunAdapterMessages {
189
+ /** Title of the always-present `agent_card` section. */
190
+ agentSectionTitle: string;
191
+ /** Title of the `stepper` / `split_stepper` section. */
192
+ progressSectionTitle: string;
193
+ /** Title of each result section. */
194
+ resultSectionTitle: string;
195
+ /** Error message of an aborted run that carries no `error`. */
196
+ runAborted: string;
197
+ /** Error message of a failed run that carries no `error`. */
198
+ runFailed: string;
199
+ /** Prompt body of an elicitation with no usable schema and no message. */
200
+ confirmDefault: string;
201
+ }
202
+
203
+ /** English defaults for {@link MacroRunAdapterMessages}. */
204
+ export const DEFAULT_MACRO_RUN_MESSAGES: MacroRunAdapterMessages = {
205
+ agentSectionTitle: 'Agent',
206
+ progressSectionTitle: 'Progress',
207
+ resultSectionTitle: 'Result',
208
+ runAborted: 'Macro run aborted.',
209
+ runFailed: 'Macro run failed.',
210
+ confirmDefault: 'Please confirm to continue.',
211
+ };
212
+
213
+ /** Options shared by the MacroRun adapters. @since v6.20.0 */
214
+ export interface MacroRunAdapterOptions {
215
+ /**
216
+ * Partial override of the adapter's own wording, merged over
217
+ * {@link DEFAULT_MACRO_RUN_MESSAGES}.
218
+ */
219
+ messages?: Partial<MacroRunAdapterMessages>;
220
+ }
221
+
222
+ const withMessages = (
223
+ options: MacroRunAdapterOptions = {}
224
+ ): MacroRunAdapterMessages => ({ ...DEFAULT_MACRO_RUN_MESSAGES, ...options.messages });
225
+
226
+ function buildError(
227
+ run: MacroRunV1,
228
+ messages: MacroRunAdapterMessages
229
+ ): ScratchpadState['error'] | undefined {
178
230
  if (run.status !== 'failed' && run.status !== 'aborted') return undefined;
179
231
  const aborted = run.status === 'aborted';
180
232
  if (run.error) {
@@ -187,7 +239,7 @@ function buildError(run: MacroRunV1): ScratchpadState['error'] | undefined {
187
239
  return err;
188
240
  }
189
241
  return {
190
- message: aborted ? 'Macro run aborted.' : 'Macro run failed.',
242
+ message: aborted ? messages.runAborted : messages.runFailed,
191
243
  retryable: false,
192
244
  };
193
245
  }
@@ -209,13 +261,17 @@ function buildError(run: MacroRunV1): ScratchpadState['error'] | undefined {
209
261
  *
210
262
  * Pure: no fetch, no SSE, no persistence. The host owns all wiring.
211
263
  */
212
- export function macroRunToScratchpadState(run: MacroRunV1): ScratchpadState {
264
+ export function macroRunToScratchpadState(
265
+ run: MacroRunV1,
266
+ options: MacroRunAdapterOptions = {}
267
+ ): ScratchpadState {
268
+ const messages = withMessages(options);
213
269
  const sections: ScratchpadSection[] = [];
214
270
 
215
271
  // 1. Agent card — always present.
216
272
  sections.push({
217
273
  id: 'macro-agent',
218
- title: 'Agent',
274
+ title: messages.agentSectionTitle,
219
275
  type: 'agent_card',
220
276
  content: buildAgentCard(run),
221
277
  editable: false,
@@ -229,7 +285,7 @@ export function macroRunToScratchpadState(run: MacroRunV1): ScratchpadState {
229
285
  hasParallel
230
286
  ? {
231
287
  id: 'macro-split-stepper',
232
- title: 'Progress',
288
+ title: messages.progressSectionTitle,
233
289
  type: 'split_stepper',
234
290
  content: buildSplitStepperContent(run.steps),
235
291
  editable: false,
@@ -237,7 +293,7 @@ export function macroRunToScratchpadState(run: MacroRunV1): ScratchpadState {
237
293
  }
238
294
  : {
239
295
  id: 'macro-stepper',
240
- title: 'Progress',
296
+ title: messages.progressSectionTitle,
241
297
  type: 'stepper',
242
298
  content: buildStepperContent(run.steps),
243
299
  editable: false,
@@ -252,7 +308,7 @@ export function macroRunToScratchpadState(run: MacroRunV1): ScratchpadState {
252
308
  id: 'macro-prompt',
253
309
  title: run.pendingInterrogation.title,
254
310
  type: 'prompt',
255
- content: macroInterrogationToChatPromptConfig(run.pendingInterrogation),
311
+ content: macroInterrogationToChatPromptConfig(run.pendingInterrogation, options),
256
312
  editable: false,
257
313
  source: 'agent',
258
314
  });
@@ -265,7 +321,7 @@ export function macroRunToScratchpadState(run: MacroRunV1): ScratchpadState {
265
321
  results.forEach((component, index) => {
266
322
  sections.push({
267
323
  id: `macro-result-${String(component?.id ?? index)}`,
268
- title: 'Result',
324
+ title: messages.resultSectionTitle,
269
325
  type: resultSectionType(component?.type),
270
326
  content: component,
271
327
  editable: false,
@@ -282,7 +338,7 @@ export function macroRunToScratchpadState(run: MacroRunV1): ScratchpadState {
282
338
  status: RUN_STATUS_TO_SCRATCHPAD[run.status],
283
339
  };
284
340
 
285
- const error = buildError(run);
341
+ const error = buildError(run, messages);
286
342
  if (error) state.error = error;
287
343
 
288
344
  return state;
@@ -311,7 +367,11 @@ function isElicitationSchema(value: unknown): value is ElicitationRequestedSchem
311
367
  * {@link macroRunToScratchpadState} (which calls it for an embedded
312
368
  * `pendingInterrogation`).
313
369
  */
314
- export function macroInterrogationToChatPromptConfig(q: MacroInterrogationV1): ChatPromptConfig {
370
+ export function macroInterrogationToChatPromptConfig(
371
+ q: MacroInterrogationV1,
372
+ options: MacroRunAdapterOptions = {}
373
+ ): ChatPromptConfig {
374
+ const messages = withMessages(options);
315
375
  switch (q.kind) {
316
376
  case 'choice': {
317
377
  const options: ChoiceOption[] = (q.options ?? []).map((o) => {
@@ -355,7 +415,7 @@ export function macroInterrogationToChatPromptConfig(q: MacroInterrogationV1): C
355
415
  return {
356
416
  type: 'confirm',
357
417
  title: q.title,
358
- config: { message: q.message ?? 'Please confirm to continue.' },
418
+ config: { message: q.message ?? messages.confirmDefault },
359
419
  };
360
420
  }
361
421
  }
@@ -7,6 +7,7 @@ import { Component, For, Show } from 'solid-js'
7
7
  import type { UIComponent, ActionGroupParams, ActionComponentParams } from '../types'
8
8
  import { useAction } from '../hooks/useAction'
9
9
  import { safeUrl } from '../utils/safe-url'
10
+ import { useMCPUIStrings } from '../context/MCPUIStringsContext'
10
11
 
11
12
  export interface ActionGroupRendererProps {
12
13
  /**
@@ -147,6 +148,7 @@ const ActionButton: Component<{
147
148
  * ```
148
149
  */
149
150
  export const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props) => {
151
+ const strings = useMCPUIStrings()
150
152
  const params = () => props.params || (props.component?.params as ActionGroupParams) || { actions: [] }
151
153
 
152
154
  const layoutClass = () => {
@@ -181,7 +183,7 @@ export const ActionGroupRenderer: Component<ActionGroupRendererProps> = (props)
181
183
  <div
182
184
  class={`${layoutClass()} ${gapClass()} ${params()?.fullWidth ? 'w-full' : ''}`}
183
185
  role="group"
184
- aria-label={params()?.label || 'Action group'}
186
+ aria-label={params()?.label || strings.actionGroupLabel}
185
187
  >
186
188
  <For each={params()?.actions || []}>
187
189
  {(action, index) => <ActionButton action={action} index={index()} />}
@@ -7,6 +7,7 @@
7
7
 
8
8
  import { Show, For } from 'solid-js'
9
9
  import type { AgentCardContent } from '../types/chat-bus'
10
+ import { useMCPUIStrings } from '../context/MCPUIStringsContext'
10
11
 
11
12
  export interface AgentCardProps {
12
13
  content: AgentCardContent
@@ -23,15 +24,31 @@ const AVATAR_MAP: Record<string, string> = {
23
24
  robot: '\uD83E\uDD16',
24
25
  }
25
26
 
26
- const STATUS_CONFIG: Record<string, { label: string; color: string; pulse: boolean }> = {
27
- idle: { label: 'Idle', color: 'bg-gray-400', pulse: false },
28
- running: { label: 'Running', color: 'bg-blue-500', pulse: true },
29
- waiting: { label: 'Waiting', color: 'bg-amber-500', pulse: true },
30
- done: { label: 'Done', color: 'bg-green-500', pulse: false },
31
- error: { label: 'Error', color: 'bg-red-500', pulse: false },
27
+ /**
28
+ * Status styling. The record stays module-level, but it carries a
29
+ * `labelKey` rather than English: the label is resolved from
30
+ * `useMCPUIStrings()` at render time so a host provider can localize it.
31
+ */
32
+ type AgentStatusLabelKey =
33
+ | 'agentStatusIdle'
34
+ | 'agentStatusRunning'
35
+ | 'agentStatusWaiting'
36
+ | 'agentStatusDone'
37
+ | 'agentStatusError'
38
+
39
+ const STATUS_CONFIG: Record<
40
+ string,
41
+ { labelKey: AgentStatusLabelKey; color: string; pulse: boolean }
42
+ > = {
43
+ idle: { labelKey: 'agentStatusIdle', color: 'bg-gray-400', pulse: false },
44
+ running: { labelKey: 'agentStatusRunning', color: 'bg-blue-500', pulse: true },
45
+ waiting: { labelKey: 'agentStatusWaiting', color: 'bg-amber-500', pulse: true },
46
+ done: { labelKey: 'agentStatusDone', color: 'bg-green-500', pulse: false },
47
+ error: { labelKey: 'agentStatusError', color: 'bg-red-500', pulse: false },
32
48
  }
33
49
 
34
50
  export function AgentCard(props: AgentCardProps) {
51
+ const strings = useMCPUIStrings()
35
52
  const c = () => props.content
36
53
  const status = () => STATUS_CONFIG[c().status] || STATUS_CONFIG.idle
37
54
  const avatar = () => AVATAR_MAP[c().avatar || ''] || c().avatar || '\uD83E\uDD16'
@@ -54,8 +71,8 @@ export function AgentCard(props: AgentCardProps) {
54
71
  <div class="flex items-center gap-2">
55
72
  <span class="font-medium text-sm text-gray-900 dark:text-white truncate">{c().name}</span>
56
73
  {/* Status dot */}
57
- <span class={`inline-block w-2 h-2 rounded-full ${status().color} ${status().pulse ? 'animate-pulse' : ''}`} title={status().label} />
58
- <span class="text-xs text-gray-500 dark:text-gray-400">{status().label}</span>
74
+ <span class={`inline-block w-2 h-2 rounded-full ${status().color} ${status().pulse ? 'animate-pulse' : ''}`} title={strings[status().labelKey]} />
75
+ <span class="text-xs text-gray-500 dark:text-gray-400">{strings[status().labelKey]}</span>
59
76
  </div>
60
77
 
61
78
  {/* Model */}
@@ -97,13 +114,14 @@ export interface AgentStatusBadgeProps {
97
114
  }
98
115
 
99
116
  export function AgentStatusBadge(props: AgentStatusBadgeProps) {
117
+ const strings = useMCPUIStrings()
100
118
  const status = () => STATUS_CONFIG[props.status] || STATUS_CONFIG.idle
101
119
 
102
120
  return (
103
121
  <span class="inline-flex items-center gap-1.5 text-xs">
104
122
  <span class={`w-2 h-2 rounded-full ${status().color} ${status().pulse ? 'animate-pulse' : ''}`} />
105
123
  <span class="text-gray-600 dark:text-gray-300">{props.agentName}</span>
106
- <span class="text-gray-400 dark:text-gray-500">{status().label}</span>
124
+ <span class="text-gray-400 dark:text-gray-500">{strings[status().labelKey]}</span>
107
125
  </span>
108
126
  )
109
127
  }
@@ -7,6 +7,7 @@
7
7
 
8
8
  import { Show } from 'solid-js'
9
9
  import type { AgentHandoffContent } from '../types/chat-bus'
10
+ import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'
10
11
 
11
12
  export interface AgentHandoffProps {
12
13
  content: AgentHandoffContent
@@ -24,6 +25,7 @@ function getAvatar(key?: string): string {
24
25
  }
25
26
 
26
27
  export function AgentHandoff(props: AgentHandoffProps) {
28
+ const strings = useMCPUIStrings()
27
29
  const c = () => props.content
28
30
 
29
31
  if (typeof console !== 'undefined') {
@@ -49,7 +51,8 @@ export function AgentHandoff(props: AgentHandoffProps) {
49
51
  </div>
50
52
  <Show when={c().summary || c().itemCount}>
51
53
  <span class="text-[10px] text-gray-500 dark:text-gray-400 text-center">
52
- {c().summary || `${c().itemCount} items`}
54
+ {c().summary ||
55
+ formatMCPUIString(strings.handoffItems, { count: c().itemCount ?? 0 })}
53
56
  </span>
54
57
  </Show>
55
58
  </div>
@@ -1,5 +1,6 @@
1
1
  import { Component } from 'solid-js'
2
2
  import { safeUrl } from '../utils/safe-url'
3
+ import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'
3
4
 
4
5
  export interface ArtifactComponentParams {
5
6
  url: string
@@ -10,6 +11,7 @@ export interface ArtifactComponentParams {
10
11
  }
11
12
 
12
13
  export const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> = (props) => {
14
+ const strings = useMCPUIStrings()
13
15
  const getIcon = () => {
14
16
  if (props.params.mimeType?.includes('csv')) return '📊'
15
17
  if (props.params.mimeType?.includes('json')) return '{}'
@@ -19,9 +21,19 @@ export const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> =
19
21
 
20
22
  const formatSize = (bytes?: number) => {
21
23
  if (!bytes) return ''
22
- if (bytes < 1024) return `${bytes} B`
23
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
24
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
24
+ const oneDecimal = (n: number) =>
25
+ new Intl.NumberFormat(strings.locale, {
26
+ minimumFractionDigits: 1,
27
+ maximumFractionDigits: 1,
28
+ useGrouping: false,
29
+ }).format(n)
30
+ if (bytes < 1024) {
31
+ return formatMCPUIString(strings.sizeBytes, {
32
+ size: new Intl.NumberFormat(strings.locale, { maximumFractionDigits: 0 }).format(bytes),
33
+ })
34
+ }
35
+ if (bytes < 1024 * 1024) return formatMCPUIString(strings.sizeKilobytes, { size: oneDecimal(bytes / 1024) })
36
+ return formatMCPUIString(strings.sizeMegabytes, { size: oneDecimal(bytes / (1024 * 1024)) })
25
37
  }
26
38
 
27
39
  return (
@@ -35,7 +47,7 @@ export const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> =
35
47
  {props.params.filename}
36
48
  </h4>
37
49
  <p class="text-xs text-gray-500 dark:text-gray-400">
38
- {formatSize(props.params.size)} • {props.params.description || 'Generated artifact'}
50
+ {formatSize(props.params.size)} • {props.params.description || strings.artifactDescription}
39
51
  </p>
40
52
  </div>
41
53
  </div>
@@ -48,7 +60,7 @@ export const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> =
48
60
  <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
49
61
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
50
62
  </svg>
51
- Download
63
+ {strings.download}
52
64
  </a>
53
65
  </div>
54
66
  )
@@ -7,6 +7,7 @@
7
7
 
8
8
  import { Component, For, Show, createMemo, JSX } from 'solid-js'
9
9
  import type { AutocompleteOption } from '../types'
10
+ import { useMCPUIStrings } from '../context/MCPUIStringsContext'
10
11
 
11
12
  /**
12
13
  * Props for AutocompleteDropdown
@@ -142,6 +143,7 @@ const DefaultOptionRenderer: Component<{
142
143
  * AutocompleteDropdown Component
143
144
  */
144
145
  export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props) => {
146
+ const strings = useMCPUIStrings()
145
147
  const positionStyles = createMemo((): JSX.CSSProperties => {
146
148
  if (props.position === 'top') {
147
149
  return {
@@ -175,7 +177,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
175
177
  class={`mcp-autocomplete-dropdown ${props.class || ''}`}
176
178
  style={containerStyles()}
177
179
  role="listbox"
178
- aria-label="Suggestions"
180
+ aria-label={strings.autocompleteSuggestions}
179
181
  >
180
182
  {/* Loading state */}
181
183
  <Show when={props.isLoading}>
@@ -201,7 +203,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
201
203
  animation: 'mcp-spin 0.6s linear infinite'
202
204
  }}
203
205
  />
204
- {props.loadingMessage || 'Loading...'}
206
+ {props.loadingMessage || strings.autocompleteLoading}
205
207
  </div>
206
208
  </Show>
207
209
 
@@ -216,7 +218,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
216
218
  'text-align': 'center'
217
219
  }}
218
220
  >
219
- {props.emptyMessage || 'No suggestions found'}
221
+ {props.emptyMessage || strings.autocompleteEmpty}
220
222
  </div>
221
223
  </Show>
222
224
 
@@ -302,7 +304,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
302
304
  'font-family': 'inherit',
303
305
  'font-size': '0.7rem'
304
306
  }}>↓</kbd>
305
- {' to navigate, '}
307
+ {strings.autocompleteHintNavigate}
306
308
  <kbd style={{
307
309
  'background-color': '#e5e7eb',
308
310
  padding: '1px 4px',
@@ -310,7 +312,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
310
312
  'font-family': 'inherit',
311
313
  'font-size': '0.7rem'
312
314
  }}>Enter</kbd>
313
- {' to select, '}
315
+ {strings.autocompleteHintSelect}
314
316
  <kbd style={{
315
317
  'background-color': '#e5e7eb',
316
318
  padding: '1px 4px',
@@ -318,7 +320,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
318
320
  'font-family': 'inherit',
319
321
  'font-size': '0.7rem'
320
322
  }}>Esc</kbd>
321
- {' to dismiss'}
323
+ {strings.autocompleteHintDismiss}
322
324
  </div>
323
325
  </Show>
324
326
  </div>
@@ -10,6 +10,7 @@ import type { FormFieldParams, FieldAutocompleteConfig, AutocompleteContext } fr
10
10
  import { useConditionalField } from '../hooks/useConditionalField'
11
11
  import { useAutocomplete } from '../hooks/useAutocomplete'
12
12
  import { useAutocompleteContextSafe } from '../context/AutocompleteContext'
13
+ import { useMCPUIStrings } from '../context/MCPUIStringsContext'
13
14
  import { GhostText } from './GhostText'
14
15
  import { AutocompleteDropdown } from './AutocompleteDropdown'
15
16
 
@@ -62,6 +63,7 @@ export interface AutocompleteFormFieldProps {
62
63
  * AutocompleteFormField Component
63
64
  */
64
65
  export const AutocompleteFormField: Component<AutocompleteFormFieldProps> = (props) => {
66
+ const strings = useMCPUIStrings()
65
67
  // Check if autocomplete context is available
66
68
  const autocompleteCtx = useAutocompleteContextSafe()
67
69
 
@@ -205,7 +207,9 @@ export const AutocompleteFormField: Component<AutocompleteFormFieldProps> = (pro
205
207
  inputValue={localValue()}
206
208
  ghostText={autocomplete.ghostText()}
207
209
  visible={autocomplete.isOpen()}
208
- hintText={autocomplete.ghostText() ? 'Tab to accept' : undefined}
210
+ hintText={
211
+ autocomplete.ghostText() ? strings.autocompleteTabToAccept : undefined
212
+ }
209
213
  isLoading={autocomplete.isLoading()}
210
214
  />
211
215
  </Show>
@@ -7,6 +7,7 @@
7
7
 
8
8
  import { For, Show } from 'solid-js'
9
9
  import type { BriefingDiffContent } from '../types/chat-bus'
10
+ import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'
10
11
 
11
12
  export interface BriefingDiffProps {
12
13
  content: BriefingDiffContent
@@ -19,6 +20,7 @@ const CHANGE_CONFIG: Record<string, { icon: string; color: string; bg: string }>
19
20
  }
20
21
 
21
22
  export function BriefingDiff(props: BriefingDiffProps) {
23
+ const strings = useMCPUIStrings()
22
24
  const c = () => props.content
23
25
 
24
26
  if (typeof console !== 'undefined') {
@@ -45,13 +47,19 @@ export function BriefingDiff(props: BriefingDiffProps) {
45
47
  {(stats) => (
46
48
  <div class="flex items-center gap-3 text-xs">
47
49
  <Show when={stats().added > 0}>
48
- <span class="text-green-600 dark:text-green-400">+{stats().added} added</span>
50
+ <span class="text-green-600 dark:text-green-400">
51
+ {formatMCPUIString(strings.briefingAdded, { count: stats().added })}
52
+ </span>
49
53
  </Show>
50
54
  <Show when={stats().removed > 0}>
51
- <span class="text-red-600 dark:text-red-400">{stats().removed} removed</span>
55
+ <span class="text-red-600 dark:text-red-400">
56
+ {formatMCPUIString(strings.briefingRemoved, { count: stats().removed })}
57
+ </span>
52
58
  </Show>
53
59
  <Show when={stats().changed > 0}>
54
- <span class="text-amber-600 dark:text-amber-400">{stats().changed} changed</span>
60
+ <span class="text-amber-600 dark:text-amber-400">
61
+ {formatMCPUIString(strings.briefingChanged, { count: stats().changed })}
62
+ </span>
55
63
  </Show>
56
64
  </div>
57
65
  )}
@@ -3,6 +3,7 @@ import { isServer } from 'solid-js/web'
3
3
  import { useRenderContext } from './RenderContext'
4
4
  import type { UIComponent } from '../types'
5
5
  import { ExpandableWrapper, useExpanded } from './ExpandableWrapper'
6
+ import { useMCPUIStrings } from '../context/MCPUIStringsContext'
6
7
 
7
8
  export interface CarouselRendererProps {
8
9
  items: UIComponent[]
@@ -15,6 +16,7 @@ export interface CarouselRendererProps {
15
16
  }
16
17
 
17
18
  export const CarouselRenderer: Component<CarouselRendererProps> = (props) => {
19
+ const strings = useMCPUIStrings()
18
20
  let scrollContainer: HTMLDivElement | undefined
19
21
  const [canScrollLeft, setCanScrollLeft] = createSignal(false)
20
22
  const [canScrollRight, setCanScrollRight] = createSignal(true)
@@ -42,9 +44,9 @@ export const CarouselRenderer: Component<CarouselRendererProps> = (props) => {
42
44
 
43
45
  return (
44
46
  <ExpandableWrapper
45
- title={'Carousel'}
47
+ title={strings.carouselTitle}
46
48
  copyData={JSON.stringify(props.items, null, 2)}
47
- copyLabel="Copy items (JSON)"
49
+ copyLabel={strings.carouselCopy}
48
50
  toolbarVariant={props.toolbarVariant}
49
51
  >
50
52
  <div class={`relative group ${isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''}`}>
@@ -24,7 +24,7 @@ import { ExpandableWrapper, useExpanded } from './ExpandableWrapper';
24
24
  import { DegradedFallback } from './DegradedFallback';
25
25
  import { chartToDataTable } from './chart-data-table';
26
26
  import { useTelemetry } from '../context/MCPUITelemetryContext';
27
- import { useMCPUIStrings } from '../context/MCPUIStringsContext';
27
+ import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';
28
28
 
29
29
  // Lazy load Chart.js to avoid bundling if not used
30
30
  let ChartJS: any = null;
@@ -113,9 +113,18 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
113
113
  let renderVersion = 0;
114
114
 
115
115
  const params = () => props.component.params as ChartComponentParams;
116
- const tableData = createMemo(() => chartToDataTable(params()));
117
116
  const telemetry = useTelemetry();
118
117
  const strings = useMCPUIStrings();
118
+ // The accessible data table is a pure projection: its column headers come
119
+ // from the chrome strings, injected rather than hardcoded in the helper.
120
+ const tableData = createMemo(() =>
121
+ chartToDataTable(params(), {
122
+ series: strings.chartTableSeries,
123
+ point: strings.chartTablePoint,
124
+ label: strings.degradedColLabel,
125
+ seriesName: strings.degradedSeries,
126
+ })
127
+ );
119
128
  const descriptionId = createUniqueId();
120
129
  const title = () => params().title || strings.chartView;
121
130
 
@@ -205,7 +214,7 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
205
214
  setIsLoading(false);
206
215
  } catch (err) {
207
216
  if (version !== renderVersion) return;
208
- const error = err instanceof Error ? err : new Error('Chart rendering failed');
217
+ const error = err instanceof Error ? err : new Error(strings.chartRenderError);
209
218
  setError(error.message);
210
219
  setIsLoading(false);
211
220
  // Fallback ladder (P2.5): record the failure so it's observable, then
@@ -241,7 +250,7 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
241
250
  <ExpandableWrapper
242
251
  title={title()}
243
252
  copyData={copyDataJSON()}
244
- copyLabel="Copy chart data (JSON)"
253
+ copyLabel={strings.chartCopy}
245
254
  toolbarVariant={props.toolbarVariant}
246
255
  >
247
256
  <ContextAwareChartLayout
@@ -294,8 +303,8 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
294
303
  onClick={handleExportPNG}
295
304
  disabled={activeView() !== 'chart' || isLoading() || Boolean(error())}
296
305
  class="opacity-0 group-hover:opacity-60 hover:!opacity-100 disabled:!opacity-30 disabled:cursor-not-allowed px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"
297
- title="Download PNG"
298
- aria-label="Download chart as PNG"
306
+ title={strings.chartDownloadPng}
307
+ aria-label={strings.chartDownloadPngAria}
299
308
  >
300
309
  <svg
301
310
  class="w-3 h-3 text-gray-500 dark:text-gray-400"
@@ -323,8 +332,8 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
323
332
  instead of a bare "Chart Error" message. */}
324
333
  <Show when={error() && activeView() === 'chart'}>
325
334
  <DegradedFallback
326
- message={`Chart rendering failed: ${error()}`}
327
- caption="Showing the chart data as a table — the interactive chart is unavailable."
335
+ message={formatMCPUIString(strings.chartRenderFailed, { error: String(error()) })}
336
+ caption={strings.chartDegradedCaption}
328
337
  {...tableData()}
329
338
  />
330
339
  </Show>
@@ -405,7 +414,7 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
405
414
  <div class="absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80">
406
415
  <div class="flex flex-col items-center gap-2">
407
416
  <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" />
408
- <span class="text-sm text-gray-500 dark:text-gray-400">Loading chart...</span>
417
+ <span class="text-sm text-gray-500 dark:text-gray-400">{strings.chartLoading}</span>
409
418
  </div>
410
419
  </div>
411
420
  </Show>