@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
@@ -2,7 +2,9 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const web = require("solid-js/web");
4
4
  const solidJs = require("solid-js");
5
- var _tmpl$ = /* @__PURE__ */ web.template(`<div class="verified-text text-sm leading-relaxed"><!$><!/><!$><!/>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span>`), _tmpl$3 = /* @__PURE__ */ web.template(`<span 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"title="Verified against source data"><!$><!/><span class="text-xs opacity-70"aria-label=verified>&#x2705;`), _tmpl$4 = /* @__PURE__ */ web.template(`<span 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">[non v&eacute;rifi&eacute;]`), _tmpl$5 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help"><!$><!/><span class=text-xs aria-label=unverified>&#x26A0;&#xFE0F;`), _tmpl$6 = /* @__PURE__ */ web.template(`<div class="mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><div class="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden"><div class="h-full rounded-full transition-all"></div></div><span><!$><!/>% verified (<!$><!/> unverified)`);
5
+ const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
6
+ const formatString = require("../utils/format-string.cjs");
7
+ var _tmpl$ = /* @__PURE__ */ web.template(`<div class="verified-text text-sm leading-relaxed"><!$><!/><!$><!/>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span>`), _tmpl$3 = /* @__PURE__ */ web.template(`<span 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"><!$><!/><span class="text-xs opacity-70">&#x2705;`), _tmpl$4 = /* @__PURE__ */ web.template(`<span 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">`), _tmpl$5 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help"><!$><!/><span class=text-xs>&#x26A0;&#xFE0F;`), _tmpl$6 = /* @__PURE__ */ web.template(`<div class="mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><div class="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden"><div class="h-full rounded-full transition-all"></div></div><span><!$><!/> <!$><!/>`);
6
8
  function buildAnnotatedSegments(text, validation) {
7
9
  const hallucinatedPositions = /* @__PURE__ */ new Map();
8
10
  for (const h of validation.hallucinated) {
@@ -63,6 +65,7 @@ function buildAnnotatedSegments(text, validation) {
63
65
  return segments;
64
66
  }
65
67
  function VerifiedText(props) {
68
+ const strings = MCPUIStringsContext.useMCPUIStrings();
66
69
  const mode = () => props.mode || "highlight";
67
70
  const segments = solidJs.createMemo(() => {
68
71
  if (!props.validation || props.validation.valid) {
@@ -89,42 +92,55 @@ function VerifiedText(props) {
89
92
  }
90
93
  if (seg.type === "verified") {
91
94
  return (() => {
92
- var _el$7 = web.getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = web.getNextMarker(_el$9.nextSibling);
93
- _el$0.nextSibling;
95
+ var _el$7 = web.getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = web.getNextMarker(_el$9.nextSibling), _el$8 = _el$0.nextSibling;
94
96
  web.insert(_el$7, () => seg.content, _el$0, _co$3);
97
+ web.effect((_p$) => {
98
+ var _v$ = strings.verifiedTitle, _v$2 = strings.verifiedAria;
99
+ _v$ !== _p$.e && web.setAttribute(_el$7, "title", _p$.e = _v$);
100
+ _v$2 !== _p$.t && web.setAttribute(_el$8, "aria-label", _p$.t = _v$2);
101
+ return _p$;
102
+ }, {
103
+ e: void 0,
104
+ t: void 0
105
+ });
95
106
  return _el$7;
96
107
  })();
97
108
  }
98
109
  const h = seg.item;
99
110
  const tooltipText = () => {
100
111
  if (h.closest != null && h.distance != null) {
101
- return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`;
112
+ return formatString.formatMCPUIString(strings.verifiedNotFoundClosest, {
113
+ closest: h.closest,
114
+ pct: Math.round(h.distance * 100)
115
+ });
102
116
  }
103
- return "Not found in source data";
117
+ return strings.verifiedNotFound;
104
118
  };
105
119
  if (mode() === "strip") {
106
120
  return (() => {
107
121
  var _el$1 = web.getNextElement(_tmpl$4);
122
+ web.insert(_el$1, () => strings.verifiedStripLabel);
108
123
  web.effect(() => web.setAttribute(_el$1, "title", tooltipText()));
109
124
  return _el$1;
110
125
  })();
111
126
  }
112
127
  return (() => {
113
- var _el$10 = web.getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = web.getNextMarker(_el$12.nextSibling);
114
- _el$13.nextSibling;
128
+ var _el$10 = web.getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = web.getNextMarker(_el$12.nextSibling), _el$11 = _el$13.nextSibling;
115
129
  _el$10.$$click = () => {
116
130
  var _a;
117
131
  return (_a = props.onHallucinationClick) == null ? void 0 : _a.call(props, h);
118
132
  };
119
133
  web.insert(_el$10, () => seg.content, _el$13, _co$4);
120
134
  web.effect((_p$) => {
121
- var _v$ = tooltipText(), _v$2 = props.onHallucinationClick ? "button" : void 0;
122
- _v$ !== _p$.e && web.setAttribute(_el$10, "title", _p$.e = _v$);
123
- _v$2 !== _p$.t && web.setAttribute(_el$10, "role", _p$.t = _v$2);
135
+ var _v$3 = tooltipText(), _v$4 = props.onHallucinationClick ? "button" : void 0, _v$5 = strings.unverifiedAria;
136
+ _v$3 !== _p$.e && web.setAttribute(_el$10, "title", _p$.e = _v$3);
137
+ _v$4 !== _p$.t && web.setAttribute(_el$10, "role", _p$.t = _v$4);
138
+ _v$5 !== _p$.a && web.setAttribute(_el$11, "aria-label", _p$.a = _v$5);
124
139
  return _p$;
125
140
  }, {
126
141
  e: void 0,
127
- t: void 0
142
+ t: void 0,
143
+ a: void 0
128
144
  });
129
145
  web.runHydrationEvents();
130
146
  return _el$10;
@@ -134,16 +150,19 @@ function VerifiedText(props) {
134
150
  web.insert(_el$, (() => {
135
151
  var _c$ = web.memo(() => !!(props.validation && !props.validation.valid));
136
152
  return () => _c$() && (() => {
137
- var _el$14 = web.getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$20 = _el$17.firstChild, [_el$21, _co$5] = web.getNextMarker(_el$20.nextSibling), _el$18 = _el$21.nextSibling, _el$22 = _el$18.nextSibling, [_el$23, _co$6] = web.getNextMarker(_el$22.nextSibling);
138
- _el$23.nextSibling;
139
- web.insert(_el$17, () => Math.round(props.validation.confidence * 100), _el$21, _co$5);
140
- web.insert(_el$17, () => props.validation.hallucinated.length, _el$23, _co$6);
153
+ var _el$14 = web.getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$19 = _el$17.firstChild, [_el$20, _co$5] = web.getNextMarker(_el$19.nextSibling), _el$18 = _el$20.nextSibling, _el$21 = _el$18.nextSibling, [_el$22, _co$6] = web.getNextMarker(_el$21.nextSibling);
154
+ web.insert(_el$17, () => formatString.formatMCPUIString(strings.verifiedConfidence, {
155
+ pct: Math.round(props.validation.confidence * 100)
156
+ }), _el$20, _co$5);
157
+ web.insert(_el$17, () => formatString.formatMCPUIString(strings.verifiedUnverifiedCount, {
158
+ count: props.validation.hallucinated.length
159
+ }), _el$22, _co$6);
141
160
  web.effect((_p$) => {
142
- var _v$3 = !!(props.validation.confidence >= 0.8), _v$4 = !!(props.validation.confidence >= 0.5 && props.validation.confidence < 0.8), _v$5 = !!(props.validation.confidence < 0.5), _v$6 = `${Math.round(props.validation.confidence * 100)}%`;
143
- _v$3 !== _p$.e && _el$16.classList.toggle("bg-green-500", _p$.e = _v$3);
144
- _v$4 !== _p$.t && _el$16.classList.toggle("bg-amber-500", _p$.t = _v$4);
145
- _v$5 !== _p$.a && _el$16.classList.toggle("bg-red-500", _p$.a = _v$5);
146
- _v$6 !== _p$.o && web.setStyleProperty(_el$16, "width", _p$.o = _v$6);
161
+ var _v$6 = !!(props.validation.confidence >= 0.8), _v$7 = !!(props.validation.confidence >= 0.5 && props.validation.confidence < 0.8), _v$8 = !!(props.validation.confidence < 0.5), _v$9 = `${Math.round(props.validation.confidence * 100)}%`;
162
+ _v$6 !== _p$.e && _el$16.classList.toggle("bg-green-500", _p$.e = _v$6);
163
+ _v$7 !== _p$.t && _el$16.classList.toggle("bg-amber-500", _p$.t = _v$7);
164
+ _v$8 !== _p$.a && _el$16.classList.toggle("bg-red-500", _p$.a = _v$8);
165
+ _v$9 !== _p$.o && web.setStyleProperty(_el$16, "width", _p$.o = _v$9);
147
166
  return _p$;
148
167
  }, {
149
168
  e: void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"VerifiedText.cjs","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with [non vérifié]\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n 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\"\n title=\"Verified against source data\"\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label=\"verified\">&#x2705;</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`\n }\n return 'Not found in source data'\n }\n\n if (mode() === 'strip') {\n return (\n <span\n 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\"\n title={tooltipText()}\n >\n [non v&eacute;rifi&eacute;]\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label=\"unverified\">&#x26A0;&#xFE0F;</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {Math.round(props.validation.confidence * 100)}% verified\n ({props.validation.hallucinated.length} unverified)\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","numberRegex","matches","m","exec","push","start","index","end","length","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","tooltipText","closest","distance","Math","round","_el$1","_tmpl$4","_$effect","_$setAttribute","_el$10","_tmpl$5","_el$12","_el$13","_co$4","$$click","onHallucinationClick","_p$","_v$","_v$2","undefined","e","t","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$20","_el$21","_co$5","_el$18","_el$22","_el$23","_co$6","confidence","_v$3","_v$4","_v$5","_v$6","classList","toggle","a","o","_$setStyleProperty","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"VerifiedText.cjs","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with the `verifiedStripLabel`\n * chrome string ('[unverified]' by default)\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const strings = useMCPUIStrings()\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n 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\"\n title={strings.verifiedTitle}\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label={strings.verifiedAria}>&#x2705;</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return formatMCPUIString(strings.verifiedNotFoundClosest, {\n closest: h.closest,\n pct: Math.round(h.distance * 100),\n })\n }\n return strings.verifiedNotFound\n }\n\n if (mode() === 'strip') {\n return (\n <span\n 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\"\n title={tooltipText()}\n >\n {strings.verifiedStripLabel}\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label={strings.unverifiedAria}>&#x26A0;&#xFE0F;</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {formatMCPUIString(strings.verifiedConfidence, {\n pct: Math.round(props.validation.confidence * 100),\n })}{' '}\n {formatMCPUIString(strings.verifiedUnverifiedCount, {\n count: props.validation.hallucinated.length,\n })}\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","numberRegex","matches","m","exec","push","start","index","end","length","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","strings","useMCPUIStrings","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","_el$8","_$effect","_p$","_v$","verifiedTitle","_v$2","verifiedAria","e","_$setAttribute","t","undefined","tooltipText","closest","distance","formatMCPUIString","verifiedNotFoundClosest","pct","Math","round","verifiedNotFound","_el$1","_tmpl$4","verifiedStripLabel","_el$10","_tmpl$5","_el$12","_el$13","_co$4","_el$11","$$click","onHallucinationClick","_v$3","_v$4","_v$5","unverifiedAria","a","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$19","_el$20","_co$5","_el$18","_el$21","_el$22","_co$6","verifiedConfidence","confidence","verifiedUnverifiedCount","count","_v$6","_v$7","_v$8","_v$9","classList","toggle","o","_$setStyleProperty","_$delegateEvents"],"mappings":"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"}
@@ -6,7 +6,8 @@
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
  import type { DataValidation, HallucinatedNumber } from '../types/chat-bus';
@@ -1 +1 @@
1
- {"version":3,"file":"VerifiedText.d.ts","sourceRoot":"","sources":["../../src/components/VerifiedText.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAE3E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,cAAc,CAAA;IAC1B,0CAA0C;IAC1C,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,CAAA;IACzC,qDAAqD;IACrD,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;CAC1D;AAyED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,kCAsFpD"}
1
+ {"version":3,"file":"VerifiedText.d.ts","sourceRoot":"","sources":["../../src/components/VerifiedText.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAG3E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,cAAc,CAAA;IAC1B,0CAA0C;IAC1C,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,CAAA;IACzC,qDAAqD;IACrD,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;CAC1D;AAyED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,kCA8FpD"}
@@ -1,6 +1,8 @@
1
1
  import { getNextElement, getNextMarker, insert, createComponent, effect, setAttribute, runHydrationEvents, memo, setStyleProperty, template, delegateEvents } from "solid-js/web";
2
2
  import { createMemo, For } from "solid-js";
3
- var _tmpl$ = /* @__PURE__ */ template(`<div class="verified-text text-sm leading-relaxed"><!$><!/><!$><!/>`), _tmpl$2 = /* @__PURE__ */ template(`<span>`), _tmpl$3 = /* @__PURE__ */ template(`<span 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"title="Verified against source data"><!$><!/><span class="text-xs opacity-70"aria-label=verified>&#x2705;`), _tmpl$4 = /* @__PURE__ */ template(`<span 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">[non v&eacute;rifi&eacute;]`), _tmpl$5 = /* @__PURE__ */ template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help"><!$><!/><span class=text-xs aria-label=unverified>&#x26A0;&#xFE0F;`), _tmpl$6 = /* @__PURE__ */ template(`<div class="mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><div class="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden"><div class="h-full rounded-full transition-all"></div></div><span><!$><!/>% verified (<!$><!/> unverified)`);
3
+ import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
4
+ import { formatMCPUIString } from "../utils/format-string.js";
5
+ var _tmpl$ = /* @__PURE__ */ template(`<div class="verified-text text-sm leading-relaxed"><!$><!/><!$><!/>`), _tmpl$2 = /* @__PURE__ */ template(`<span>`), _tmpl$3 = /* @__PURE__ */ template(`<span 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"><!$><!/><span class="text-xs opacity-70">&#x2705;`), _tmpl$4 = /* @__PURE__ */ template(`<span 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">`), _tmpl$5 = /* @__PURE__ */ template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help"><!$><!/><span class=text-xs>&#x26A0;&#xFE0F;`), _tmpl$6 = /* @__PURE__ */ template(`<div class="mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><div class="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden"><div class="h-full rounded-full transition-all"></div></div><span><!$><!/> <!$><!/>`);
4
6
  function buildAnnotatedSegments(text, validation) {
5
7
  const hallucinatedPositions = /* @__PURE__ */ new Map();
6
8
  for (const h of validation.hallucinated) {
@@ -61,6 +63,7 @@ function buildAnnotatedSegments(text, validation) {
61
63
  return segments;
62
64
  }
63
65
  function VerifiedText(props) {
66
+ const strings = useMCPUIStrings();
64
67
  const mode = () => props.mode || "highlight";
65
68
  const segments = createMemo(() => {
66
69
  if (!props.validation || props.validation.valid) {
@@ -87,42 +90,55 @@ function VerifiedText(props) {
87
90
  }
88
91
  if (seg.type === "verified") {
89
92
  return (() => {
90
- var _el$7 = getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = getNextMarker(_el$9.nextSibling);
91
- _el$0.nextSibling;
93
+ var _el$7 = getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = getNextMarker(_el$9.nextSibling), _el$8 = _el$0.nextSibling;
92
94
  insert(_el$7, () => seg.content, _el$0, _co$3);
95
+ effect((_p$) => {
96
+ var _v$ = strings.verifiedTitle, _v$2 = strings.verifiedAria;
97
+ _v$ !== _p$.e && setAttribute(_el$7, "title", _p$.e = _v$);
98
+ _v$2 !== _p$.t && setAttribute(_el$8, "aria-label", _p$.t = _v$2);
99
+ return _p$;
100
+ }, {
101
+ e: void 0,
102
+ t: void 0
103
+ });
93
104
  return _el$7;
94
105
  })();
95
106
  }
96
107
  const h = seg.item;
97
108
  const tooltipText = () => {
98
109
  if (h.closest != null && h.distance != null) {
99
- return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`;
110
+ return formatMCPUIString(strings.verifiedNotFoundClosest, {
111
+ closest: h.closest,
112
+ pct: Math.round(h.distance * 100)
113
+ });
100
114
  }
101
- return "Not found in source data";
115
+ return strings.verifiedNotFound;
102
116
  };
103
117
  if (mode() === "strip") {
104
118
  return (() => {
105
119
  var _el$1 = getNextElement(_tmpl$4);
120
+ insert(_el$1, () => strings.verifiedStripLabel);
106
121
  effect(() => setAttribute(_el$1, "title", tooltipText()));
107
122
  return _el$1;
108
123
  })();
109
124
  }
110
125
  return (() => {
111
- var _el$10 = getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = getNextMarker(_el$12.nextSibling);
112
- _el$13.nextSibling;
126
+ var _el$10 = getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = getNextMarker(_el$12.nextSibling), _el$11 = _el$13.nextSibling;
113
127
  _el$10.$$click = () => {
114
128
  var _a;
115
129
  return (_a = props.onHallucinationClick) == null ? void 0 : _a.call(props, h);
116
130
  };
117
131
  insert(_el$10, () => seg.content, _el$13, _co$4);
118
132
  effect((_p$) => {
119
- var _v$ = tooltipText(), _v$2 = props.onHallucinationClick ? "button" : void 0;
120
- _v$ !== _p$.e && setAttribute(_el$10, "title", _p$.e = _v$);
121
- _v$2 !== _p$.t && setAttribute(_el$10, "role", _p$.t = _v$2);
133
+ var _v$3 = tooltipText(), _v$4 = props.onHallucinationClick ? "button" : void 0, _v$5 = strings.unverifiedAria;
134
+ _v$3 !== _p$.e && setAttribute(_el$10, "title", _p$.e = _v$3);
135
+ _v$4 !== _p$.t && setAttribute(_el$10, "role", _p$.t = _v$4);
136
+ _v$5 !== _p$.a && setAttribute(_el$11, "aria-label", _p$.a = _v$5);
122
137
  return _p$;
123
138
  }, {
124
139
  e: void 0,
125
- t: void 0
140
+ t: void 0,
141
+ a: void 0
126
142
  });
127
143
  runHydrationEvents();
128
144
  return _el$10;
@@ -132,16 +148,19 @@ function VerifiedText(props) {
132
148
  insert(_el$, (() => {
133
149
  var _c$ = memo(() => !!(props.validation && !props.validation.valid));
134
150
  return () => _c$() && (() => {
135
- var _el$14 = getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$20 = _el$17.firstChild, [_el$21, _co$5] = getNextMarker(_el$20.nextSibling), _el$18 = _el$21.nextSibling, _el$22 = _el$18.nextSibling, [_el$23, _co$6] = getNextMarker(_el$22.nextSibling);
136
- _el$23.nextSibling;
137
- insert(_el$17, () => Math.round(props.validation.confidence * 100), _el$21, _co$5);
138
- insert(_el$17, () => props.validation.hallucinated.length, _el$23, _co$6);
151
+ var _el$14 = getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$19 = _el$17.firstChild, [_el$20, _co$5] = getNextMarker(_el$19.nextSibling), _el$18 = _el$20.nextSibling, _el$21 = _el$18.nextSibling, [_el$22, _co$6] = getNextMarker(_el$21.nextSibling);
152
+ insert(_el$17, () => formatMCPUIString(strings.verifiedConfidence, {
153
+ pct: Math.round(props.validation.confidence * 100)
154
+ }), _el$20, _co$5);
155
+ insert(_el$17, () => formatMCPUIString(strings.verifiedUnverifiedCount, {
156
+ count: props.validation.hallucinated.length
157
+ }), _el$22, _co$6);
139
158
  effect((_p$) => {
140
- var _v$3 = !!(props.validation.confidence >= 0.8), _v$4 = !!(props.validation.confidence >= 0.5 && props.validation.confidence < 0.8), _v$5 = !!(props.validation.confidence < 0.5), _v$6 = `${Math.round(props.validation.confidence * 100)}%`;
141
- _v$3 !== _p$.e && _el$16.classList.toggle("bg-green-500", _p$.e = _v$3);
142
- _v$4 !== _p$.t && _el$16.classList.toggle("bg-amber-500", _p$.t = _v$4);
143
- _v$5 !== _p$.a && _el$16.classList.toggle("bg-red-500", _p$.a = _v$5);
144
- _v$6 !== _p$.o && setStyleProperty(_el$16, "width", _p$.o = _v$6);
159
+ var _v$6 = !!(props.validation.confidence >= 0.8), _v$7 = !!(props.validation.confidence >= 0.5 && props.validation.confidence < 0.8), _v$8 = !!(props.validation.confidence < 0.5), _v$9 = `${Math.round(props.validation.confidence * 100)}%`;
160
+ _v$6 !== _p$.e && _el$16.classList.toggle("bg-green-500", _p$.e = _v$6);
161
+ _v$7 !== _p$.t && _el$16.classList.toggle("bg-amber-500", _p$.t = _v$7);
162
+ _v$8 !== _p$.a && _el$16.classList.toggle("bg-red-500", _p$.a = _v$8);
163
+ _v$9 !== _p$.o && setStyleProperty(_el$16, "width", _p$.o = _v$9);
145
164
  return _p$;
146
165
  }, {
147
166
  e: void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"VerifiedText.js","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with [non vérifié]\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n 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\"\n title=\"Verified against source data\"\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label=\"verified\">&#x2705;</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`\n }\n return 'Not found in source data'\n }\n\n if (mode() === 'strip') {\n return (\n <span\n 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\"\n title={tooltipText()}\n >\n [non v&eacute;rifi&eacute;]\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label=\"unverified\">&#x26A0;&#xFE0F;</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {Math.round(props.validation.confidence * 100)}% verified\n ({props.validation.hallucinated.length} unverified)\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","numberRegex","matches","m","exec","push","start","index","end","length","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","tooltipText","closest","distance","Math","round","_el$1","_tmpl$4","_$effect","_$setAttribute","_el$10","_tmpl$5","_el$12","_el$13","_co$4","$$click","onHallucinationClick","_p$","_v$","_v$2","undefined","e","t","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$20","_el$21","_co$5","_el$18","_el$22","_el$23","_co$6","confidence","_v$3","_v$4","_v$5","_v$6","classList","toggle","a","o","_$setStyleProperty","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"VerifiedText.js","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with the `verifiedStripLabel`\n * chrome string ('[unverified]' by default)\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const strings = useMCPUIStrings()\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n 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\"\n title={strings.verifiedTitle}\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label={strings.verifiedAria}>&#x2705;</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return formatMCPUIString(strings.verifiedNotFoundClosest, {\n closest: h.closest,\n pct: Math.round(h.distance * 100),\n })\n }\n return strings.verifiedNotFound\n }\n\n if (mode() === 'strip') {\n return (\n <span\n 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\"\n title={tooltipText()}\n >\n {strings.verifiedStripLabel}\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label={strings.unverifiedAria}>&#x26A0;&#xFE0F;</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {formatMCPUIString(strings.verifiedConfidence, {\n pct: Math.round(props.validation.confidence * 100),\n })}{' '}\n {formatMCPUIString(strings.verifiedUnverifiedCount, {\n count: props.validation.hallucinated.length,\n })}\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","numberRegex","matches","m","exec","push","start","index","end","length","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","strings","useMCPUIStrings","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","_el$8","_$effect","_p$","_v$","verifiedTitle","_v$2","verifiedAria","e","_$setAttribute","t","undefined","tooltipText","closest","distance","formatMCPUIString","verifiedNotFoundClosest","pct","Math","round","verifiedNotFound","_el$1","_tmpl$4","verifiedStripLabel","_el$10","_tmpl$5","_el$12","_el$13","_co$4","_el$11","$$click","onHallucinationClick","_v$3","_v$4","_v$5","unverifiedAria","a","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$19","_el$20","_co$5","_el$18","_el$21","_el$22","_co$6","verifiedConfidence","confidence","verifiedUnverifiedCount","count","_v$6","_v$7","_v$8","_v$9","classList","toggle","o","_$setStyleProperty","_$delegateEvents"],"mappings":"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"}
@@ -3,7 +3,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const web = require("solid-js/web");
4
4
  const solidJs = require("solid-js");
5
5
  const ExpandableWrapper = require("./ExpandableWrapper.cjs");
6
- 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>Your browser does not support the video tag.`);
6
+ const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
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><!$><!/>`);
7
11
  function parseVideoUrl(url) {
8
12
  const youtubeMatch = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|v\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
9
13
  if (youtubeMatch) {
@@ -24,6 +28,8 @@ function parseVideoUrl(url) {
24
28
  };
25
29
  }
26
30
  const VideoRenderer = (props) => {
31
+ const strings = MCPUIStringsContext.useMCPUIStrings();
32
+ const config = MCPUIConfigContext.useMCPUIConfig();
27
33
  const params = () => {
28
34
  var _a;
29
35
  return props.params || ((_a = props.component) == null ? void 0 : _a.params);
@@ -84,18 +90,20 @@ const VideoRenderer = (props) => {
84
90
  return web.createComponent(ExpandableWrapper.ExpandableWrapper, {
85
91
  get title() {
86
92
  var _a;
87
- return ((_a = params()) == null ? void 0 : _a.title) || "Video";
93
+ return ((_a = params()) == null ? void 0 : _a.title) || strings.videoTitle;
88
94
  },
89
95
  get copyData() {
90
96
  var _a;
91
97
  return ((_a = params()) == null ? void 0 : _a.url) || "";
92
98
  },
93
- copyLabel: "Copy video URL",
99
+ get copyLabel() {
100
+ return strings.videoCopy;
101
+ },
94
102
  get toolbarVariant() {
95
103
  return props.toolbarVariant;
96
104
  },
97
105
  get children() {
98
- 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);
99
107
  web.insert(_el$, web.createComponent(solidJs.Show, {
100
108
  get when() {
101
109
  var _a;
@@ -115,17 +123,18 @@ const VideoRenderer = (props) => {
115
123
  return (
116
124
  // Direct video file
117
125
  (() => {
118
- var _el$10 = web.getNextElement(_tmpl$5);
119
- _el$10.addEventListener("error", handleVideoError);
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);
120
129
  web.effect((_p$) => {
121
130
  var _a, _b, _c, _d, _e, _f;
122
- 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;
123
- _v$5 !== _p$.e && web.setAttribute(_el$10, "src", _p$.e = _v$5);
124
- _v$6 !== _p$.t && web.setAttribute(_el$10, "poster", _p$.t = _v$6);
125
- _v$7 !== _p$.a && web.setProperty(_el$10, "autoplay", _p$.a = _v$7);
126
- _v$8 !== _p$.o && web.setProperty(_el$10, "controls", _p$.o = _v$8);
127
- _v$9 !== _p$.i && web.setProperty(_el$10, "loop", _p$.i = _v$9);
128
- _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);
129
138
  return _p$;
130
139
  }, {
131
140
  e: void 0,
@@ -135,7 +144,7 @@ const VideoRenderer = (props) => {
135
144
  i: void 0,
136
145
  n: void 0
137
146
  });
138
- return _el$10;
147
+ return _el$12;
139
148
  })()
140
149
  );
141
150
  },
@@ -143,17 +152,39 @@ const VideoRenderer = (props) => {
143
152
  var _el$5 = web.getNextElement(_tmpl$2);
144
153
  web.effect((_p$) => {
145
154
  var _a;
146
- var _v$ = embedUrl(), _v$2 = ((_a = params()) == null ? void 0 : _a.title) || "Video";
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
+ );
147
163
  _v$ !== _p$.e && web.setAttribute(_el$5, "src", _p$.e = _v$);
148
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);
149
166
  return _p$;
150
167
  }, {
151
168
  e: void 0,
152
- t: void 0
169
+ t: void 0,
170
+ a: void 0
153
171
  });
154
172
  return _el$5;
155
173
  }
156
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);
157
188
  web.insert(_el$, web.createComponent(solidJs.Show, {
158
189
  get when() {
159
190
  var _a;
@@ -164,11 +195,11 @@ const VideoRenderer = (props) => {
164
195
  web.insert(_el$7, () => params().caption);
165
196
  return _el$6;
166
197
  }
167
- }), _el$1, _co$2);
198
+ }), _el$11, _co$3);
168
199
  web.effect((_p$) => {
169
- 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()}`;
170
- _v$3 !== _p$.e && web.className(_el$, _p$.e = _v$3);
171
- _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);
172
203
  return _p$;
173
204
  }, {
174
205
  e: void 0,