@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
@@ -1 +1 @@
1
- {"version":3,"file":"MapRenderer.cjs","sources":["../../src/components/MapRenderer.tsx"],"sourcesContent":["/**\n * MapRenderer - Interactive map Component\n * Sprint 6: Markers + clustering\n * v3.1.0: GeoJSON, choropleth, popups, multi-layer, PMTiles\n */\n\nimport { Component, createEffect, onCleanup, createSignal, Show } from 'solid-js';\nimport { isServer } from 'solid-js/web';\nimport type {\n UIComponent,\n MapComponentParams,\n MapClusterOptions,\n MapGeoJSONStyle,\n MapPopupConfig,\n} from '../types';\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper';\nimport { DegradedFallback } from './DegradedFallback';\nimport { mapToDegradedTable } from '../utils/degraded-projections';\nimport { escapeHtml } from '../utils/escape-html';\nimport { useTelemetry } from '../context/MCPUITelemetryContext';\n\n// Lazy load leaflet (it doesn't support SSR well)\nlet L: any = null;\n// Track if marker cluster CSS has been loaded\nlet clusterCssLoaded = false;\n\nexport interface MapRendererProps {\n /**\n * UIComponent containing map params\n */\n component?: UIComponent;\n\n /**\n * Direct map params\n */\n params?: MapComponentParams;\n\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible';\n\n /**\n * Trust marker / popup content as raw HTML (v6.10.0, audit P1.2).\n *\n * Leaflet renders bound tooltip/popup strings as HTML, so `marker.tooltip`,\n * `marker.popup` and a GeoJSON `popup.template` are XSS vectors when the\n * payload is untrusted (the default for an LLM/connector-driven public\n * package). **Default `false`** → those are escaped as plain text, and\n * `popup.template` is ignored in favour of the safe auto-generated popup.\n *\n * This is a **host-level** trust decision, deliberately NOT a payload field\n * (a malicious payload could just set its own flag). The\n * `<UIResourceRenderer>` path never sets it, so payload-driven maps are\n * always text-safe. A host rendering `<MapRenderer>` directly with trusted\n * data may set `allowHtmlPopups` to restore rich HTML popups. The\n * auto-generated popup (`titleField` / `fields`) is safe-by-construction\n * and unaffected either way.\n */\n allowHtmlPopups?: boolean;\n}\n\n// ─── Helpers ────────────────────────────────────────────────\n\n/**\n * Resolve choropleth color for a feature based on property value and scale stops.\n */\nfunction getChoroplethColor(\n value: unknown,\n scale: Array<[number, string]>,\n fallback: string\n): string {\n if (value == null || typeof value !== 'number' || !isFinite(value)) return fallback;\n\n // Scale is sorted ascending: [[0, '#eff3ff'], [100, '#084594']]\n if (scale.length === 0) return fallback;\n if (value <= scale[0][0]) return scale[0][1];\n if (value >= scale[scale.length - 1][0]) return scale[scale.length - 1][1];\n\n // Find surrounding stops and interpolate (use upper bracket color)\n for (let i = 1; i < scale.length; i++) {\n if (value <= scale[i][0]) return scale[i][1];\n }\n return scale[scale.length - 1][1];\n}\n\n/**\n * Build a Leaflet style function from MapGeoJSONStyle config.\n */\nfunction buildStyleFn(\n style: MapGeoJSONStyle | undefined\n): (feature: any) => Record<string, unknown> {\n if (!style) {\n return () => ({\n fillColor: '#3388ff',\n fillOpacity: 0.6,\n color: '#333',\n weight: 1,\n opacity: 1,\n });\n }\n\n return (feature: any) => {\n let fillColor = style.fillColor || '#3388ff';\n\n // Choropleth: override fillColor based on feature property\n if (style.choroplethField && style.choroplethScale && feature?.properties) {\n const val = feature.properties[style.choroplethField];\n fillColor = getChoroplethColor(\n val,\n style.choroplethScale,\n style.choroplethFallback || '#ccc'\n );\n }\n\n return {\n fillColor,\n fillOpacity: style.fillOpacity ?? 0.6,\n color: style.strokeColor || '#333',\n weight: style.strokeWeight ?? 1,\n opacity: style.strokeOpacity ?? 1,\n };\n };\n}\n\n/**\n * Build popup HTML from a feature's properties using popup config.\n *\n * `allowHtml` (audit P1.2) gates the raw-HTML `popup.template`: it is honored\n * only when the host trusts the payload. On the default (untrusted) path the\n * template is ignored and we fall through to the auto-generated popup, whose\n * structure is renderer-authored and whose values are always escaped — safe\n * by construction. Even in the trusted path, substituted `{{prop}}` values\n * are escaped (they are data, not markup).\n */\nexport function buildPopupContent(\n feature: any,\n popup: MapPopupConfig | undefined,\n allowHtml = false\n): string | null {\n if (!popup || !feature?.properties) return null;\n const props = feature.properties;\n\n // Custom template — raw HTML, so trusted-host only.\n if (allowHtml && popup.template) {\n return popup.template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key) => {\n const val = props[key];\n return val != null ? escapeHtml(String(val)) : '';\n });\n }\n\n // Auto-generated popup\n const parts: string[] = [];\n\n if (popup.titleField && props[popup.titleField] != null) {\n parts.push(`<strong>${escapeHtml(String(props[popup.titleField]))}</strong>`);\n }\n\n const fields = popup.fields || Object.keys(props).slice(0, 8);\n for (const key of fields) {\n if (key === popup.titleField) continue;\n const val = props[key];\n if (val == null) continue;\n const formatted = typeof val === 'number' ? val.toLocaleString('fr-FR') : String(val);\n parts.push(\n `<span style=\"color:#666;font-size:11px\">${escapeHtml(key)}</span>: ${escapeHtml(formatted)}`\n );\n }\n\n return parts.join('<br/>');\n}\n\n/**\n * Resolve a marker's tooltip/popup string for binding (audit P1.2). Leaflet\n * renders bound strings as HTML; `marker.tooltip` / `marker.popup` come from\n * the (untrusted) payload, so they are escaped to plain text unless the host\n * has opted into raw HTML via `allowHtmlPopups`. Pure + exported for tests.\n */\nexport function popupSafeText(value: string | undefined, allowHtml = false): string | undefined {\n if (value == null) return undefined;\n return allowHtml ? value : escapeHtml(value);\n}\n\n/** Bind a marker's tooltip + popup, escaping by default (see popupSafeText). */\nexport function bindMarkerContent(\n m: any,\n marker: { tooltip?: string; popup?: string },\n allowHtml: boolean\n): void {\n const tooltip = popupSafeText(marker.tooltip, allowHtml);\n if (tooltip) m.bindTooltip(tooltip);\n const popup = popupSafeText(marker.popup, allowHtml);\n if (popup) m.bindPopup(popup);\n}\n\n/**\n * Add a GeoJSON layer to the map with style and popup support.\n * Returns the layer for bounds calculation.\n */\nexport function addGeoJSONLayer(\n mapInst: any,\n leaflet: any,\n geojson: unknown,\n style?: MapGeoJSONStyle,\n popup?: MapPopupConfig,\n allowHtml = false\n): any {\n const styleFn = buildStyleFn(style);\n\n const layer = leaflet.geoJSON(geojson, {\n style: styleFn,\n pointToLayer: (feature: any, latlng: any) => {\n // Render points as circle markers for consistency\n const s = styleFn(feature);\n return leaflet.circleMarker(latlng, {\n radius: 6,\n fillColor: s.fillColor,\n fillOpacity: s.fillOpacity,\n color: s.color,\n weight: s.weight,\n opacity: s.opacity,\n });\n },\n onEachFeature: (feature: any, featureLayer: any) => {\n const html = buildPopupContent(feature, popup, allowHtml);\n if (html) {\n featureLayer.bindPopup(html, { maxWidth: 300 });\n }\n },\n });\n\n layer.addTo(mapInst);\n return layer;\n}\n\n// ─── Component ──────────────────────────────────────────────\n\n/**\n * Build a GeoJSON FeatureCollection from the map's `markers` (and any\n * inlined GeoJSON layers, when present). Used by the \"Copy data\" button\n * shipped via `<ExpandableWrapper>` (v6.2.0). Best-effort — clusters,\n * tile layers, and choropleth-only data don't get round-tripped.\n */\nfunction mapToGeoJSON(p: MapComponentParams | undefined): string {\n if (!p) return '{\"type\":\"FeatureCollection\",\"features\":[]}';\n const features: any[] = [];\n for (const marker of p.markers ?? []) {\n const pos: any = marker.position as any;\n // Accept both [lat, lng] tuple and {lat, lng} object shapes (v5.0.2 spec)\n const lat = Array.isArray(pos) ? pos[0] : pos?.lat;\n const lng = Array.isArray(pos) ? pos[1] : pos?.lng;\n if (typeof lat !== 'number' || typeof lng !== 'number') continue;\n features.push({\n type: 'Feature',\n geometry: { type: 'Point', coordinates: [lng, lat] },\n properties: {\n ...(marker.tooltip ? { tooltip: marker.tooltip } : {}),\n ...(marker.popup ? { popup: marker.popup } : {}),\n },\n });\n }\n return JSON.stringify({ type: 'FeatureCollection', features }, null, 2);\n}\n\nexport const MapRenderer: Component<MapRendererProps> = (props) => {\n let mapContainer: HTMLDivElement | undefined;\n let mapInstance: any = null;\n const [isLeafletLoaded, setIsLeafletLoaded] = createSignal(false);\n const [error, setError] = createSignal<string | null>(null);\n // PMTiles is an optional overlay on top of the base map. When it fails we\n // keep the base map but surface a visible notice (audit P1.3) instead of a\n // silent console.warn that leaves the user with an unexplained empty layer.\n const [pmtilesError, setPmtilesError] = createSignal<string | null>(null);\n const isExpanded = useExpanded();\n const telemetry = useTelemetry();\n // Host-level trust for raw HTML in marker/popup content (audit P1.2).\n // Default false → tooltip/popup escaped, GeoJSON `popup.template` ignored.\n const allowHtml = () => props.allowHtmlPopups === true;\n\n const params = () => props.params || (props.component?.params as MapComponentParams);\n\n // v6.2.0 — Leaflet has to be told to re-measure when its container\n // resizes (e.g. transitioning to fullscreen via ExpandableWrapper).\n // We give the DOM a tick to settle the new dimensions, then ask\n // Leaflet to reflow tiles.\n createEffect(() => {\n const expanded = isExpanded();\n if (!mapInstance) return;\n // Read the signal so the effect re-runs on toggle ; the value is\n // observed for its side effects on layout.\n void expanded;\n setTimeout(() => mapInstance?.invalidateSize?.(), 100);\n });\n\n // Initialize Map\n createEffect(async () => {\n if (isServer) return; // Don't run on server\n\n if (!L) {\n try {\n const module = await import('leaflet');\n L = module.default || module;\n await import('leaflet/dist/leaflet.css'); // Import CSS\n setIsLeafletLoaded(true);\n } catch (e) {\n console.warn('Failed to load leaflet', e);\n setError('Map library could not be loaded.');\n return;\n }\n } else {\n setIsLeafletLoaded(true);\n }\n\n if (isLeafletLoaded() && mapContainer && !mapInstance) {\n const p = params();\n const center = p?.center || [51.505, -0.09]; // Default to London\n const zoom = p?.zoom || 13;\n\n mapInstance = L.map(mapContainer, {\n zoomControl: p?.zoomControl !== false,\n scrollWheelZoom: p?.scrollWheelZoom !== false,\n attributionControl: false,\n }).setView(center, zoom);\n\n // Add OpenStreetMap tile layer\n const tileLayerUrl = p?.tileLayer || 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';\n L.tileLayer(tileLayerUrl, {\n attribution:\n p?.attribution ||\n '&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors',\n }).addTo(mapInstance);\n\n if (p?.attribution !== '') {\n L.control.attribution({ prefix: false }).addTo(mapInstance);\n }\n\n // Fix marker icons (Leaflet issue with bundlers)\n delete (L.Icon.Default.prototype as any)._getIconUrl;\n L.Icon.Default.mergeOptions({\n iconRetinaUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png',\n iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png',\n shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',\n });\n }\n\n // Update markers and view\n if (mapInstance && L) {\n try {\n const p = params();\n const allBoundsLayers: any[] = [];\n\n // Clear existing layers (markers, cluster groups, GeoJSON)\n mapInstance.eachLayer((layer: any) => {\n if (\n layer instanceof L.Marker ||\n layer instanceof L.GeoJSON ||\n layer instanceof L.CircleMarker ||\n layer._group ||\n layer._featureGroup\n ) {\n mapInstance.removeLayer(layer);\n }\n });\n\n // ─── Markers (legacy) ────────────────────────\n const markers: any[] = [];\n const shouldCluster = p?.clustering && p?.markers && p.markers.length > 0;\n\n if (shouldCluster) {\n try {\n await import('leaflet.markercluster');\n if (!clusterCssLoaded) {\n await import('leaflet.markercluster/dist/MarkerCluster.css');\n await import('leaflet.markercluster/dist/MarkerCluster.Default.css');\n clusterCssLoaded = true;\n }\n const clusterOpts: MapClusterOptions =\n typeof p.clustering === 'object' ? p.clustering : {};\n const clusterGroup = (L as any).markerClusterGroup({\n maxClusterRadius: clusterOpts.maxClusterRadius ?? 80,\n spiderfyOnMaxZoom: clusterOpts.spiderfyOnMaxZoom ?? true,\n showCoverageOnHover: clusterOpts.showCoverageOnHover ?? true,\n disableClusteringAtZoom: clusterOpts.disableClusteringAtZoom,\n animate: clusterOpts.animateAddingMarkers ?? true,\n });\n p?.markers?.forEach((marker) => {\n const m = L.marker(marker.position);\n bindMarkerContent(m, marker, allowHtml());\n clusterGroup.addLayer(m);\n markers.push(m);\n });\n mapInstance.addLayer(clusterGroup);\n } catch {\n p?.markers?.forEach((marker) => {\n const m = L.marker(marker.position).addTo(mapInstance);\n bindMarkerContent(m, marker, allowHtml());\n markers.push(m);\n });\n }\n } else {\n p?.markers?.forEach((marker) => {\n const m = L.marker(marker.position).addTo(mapInstance);\n bindMarkerContent(m, marker, allowHtml());\n markers.push(m);\n });\n }\n\n if (markers.length > 0) {\n allBoundsLayers.push(...markers);\n }\n\n // ─── GeoJSON (v3.1.0) ───────────────────────\n if (p?.geojson) {\n const geoLayer = addGeoJSONLayer(\n mapInstance,\n L,\n p.geojson,\n p.geojsonStyle,\n p.popup,\n allowHtml()\n );\n allBoundsLayers.push(geoLayer);\n }\n\n // ─── Named layers (v3.1.0) ──────────────────\n if (p?.layers && p.layers.length > 0) {\n const overlays: Record<string, any> = {};\n\n for (const layerDef of p.layers) {\n const geoLayer = addGeoJSONLayer(\n mapInstance,\n L,\n layerDef.geojson,\n layerDef.style || p?.geojsonStyle,\n layerDef.popup || p?.popup,\n allowHtml()\n );\n\n overlays[layerDef.name] = geoLayer;\n allBoundsLayers.push(geoLayer);\n\n // Respect initial visibility\n if (layerDef.visible === false) {\n mapInstance.removeLayer(geoLayer);\n }\n }\n\n // Add layer control if multiple layers\n if (Object.keys(overlays).length > 1) {\n L.control.layers(null, overlays, { collapsed: true }).addTo(mapInstance);\n }\n }\n\n // ─── PMTiles (v3.1.0) ────────────────────────\n setPmtilesError(null);\n if (p?.pmtiles) {\n try {\n const protomaps = await import(/* @vite-ignore */ 'protomaps-leaflet');\n const pmConfig = p.pmtiles;\n\n const paintRules =\n pmConfig.paintRules?.map((rule) => ({\n dataLayer: rule.dataLayer,\n symbolizer: new (protomaps as any)[\n rule.symbolizer === 'polygon'\n ? 'PolygonSymbolizer'\n : rule.symbolizer === 'line'\n ? 'LineSymbolizer'\n : 'CircleSymbolizer'\n ]({\n fill: rule.color || '#3388ff',\n stroke: rule.color || '#333',\n width: rule.width ?? 1,\n opacity: rule.opacity ?? 0.6,\n }),\n })) || [];\n\n const labelRules =\n pmConfig.labelRules?.map((rule) => ({\n dataLayer: rule.dataLayer,\n symbolizer: new (protomaps as any).TextSymbolizer({\n label_props: [rule.textField],\n fontSize: rule.fontSize ?? 12,\n }),\n })) || [];\n\n const pmLayer = (protomaps as any).leafletLayer({\n url: pmConfig.url,\n attribution: pmConfig.attribution,\n paintRules,\n labelRules,\n maxZoom: pmConfig.maxZoom,\n minZoom: pmConfig.minZoom,\n });\n\n pmLayer.addTo(mapInstance);\n } catch (e) {\n // P1.3 — do NOT fail silently. Keep the base map, but surface a\n // visible notice and report a renderer error via telemetry. The\n // most common cause is the optional `protomaps-leaflet` peer not\n // being installed.\n const detail = e instanceof Error ? e.message : String(e);\n const message =\n 'PMTiles layer unavailable — the optional \"protomaps-leaflet\" ' +\n 'peer dependency failed to load or render.';\n console.warn('[MCP-UI] ' + message, e);\n setPmtilesError(message);\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: `${message} (${detail})`,\n id: props.component?.id ?? '',\n componentType: 'map',\n ts: Date.now(),\n });\n }\n }\n\n // ─── Fit bounds ─────────────────────────────\n if (p?.fitBounds && allBoundsLayers.length > 0) {\n const group = L.featureGroup(allBoundsLayers);\n const bounds = group.getBounds();\n if (bounds.isValid()) {\n mapInstance.fitBounds(bounds.pad(0.1));\n }\n } else if (p?.center) {\n mapInstance.setView(p.center, p.zoom || mapInstance.getZoom());\n }\n } catch (err) {\n // Fallback ladder (P2.5): a Leaflet drawing failure degrades to\n // the coordinate table below instead of a blank/partial map.\n const message = err instanceof Error ? err.message : 'Failed to render map';\n setError(message);\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: message,\n id: props.component?.id ?? '',\n componentType: 'map',\n ts: Date.now(),\n });\n }\n }\n });\n\n // Cleanup\n onCleanup(() => {\n if (mapInstance) {\n mapInstance.remove();\n mapInstance = null;\n }\n });\n\n return (\n <ExpandableWrapper\n title={'Map'}\n copyData={mapToGeoJSON(params())}\n copyLabel=\"Copy markers as GeoJSON\"\n toolbarVariant={props.toolbarVariant}\n >\n <div\n class={`w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${params()?.className || ''} ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}\n >\n <Show when={error()}>\n {/* Fallback ladder (P2.5): degrade to a coordinate table\n rather than a bare error string. */}\n <div class=\"p-3\">\n <DegradedFallback\n message={`Map rendering failed: ${error()}`}\n caption=\"Showing the map data as a coordinate table — the interactive map is unavailable.\"\n {...mapToDegradedTable(params() ?? {})}\n />\n </div>\n </Show>\n <Show when={!error()}>\n {/* P1.3 — visible notice when the PMTiles overlay fails but the\n base map is still usable. */}\n <Show when={pmtilesError()}>\n <div\n role=\"alert\"\n class=\"m-2 rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-800 dark:border-amber-700/50 dark:bg-amber-900/20 dark:text-amber-200\"\n >\n {pmtilesError()} The base map is still shown.\n </div>\n </Show>\n <div\n ref={mapContainer}\n style={\n isExpanded()\n ? { height: '100%', width: '100%', 'z-index': 0 }\n : { height: params()?.height || '400px', width: '100%', 'z-index': 0 }\n }\n class={`relative z-0 ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n />\n </Show>\n </div>\n </ExpandableWrapper>\n );\n};\n"],"names":["L","clusterCssLoaded","getChoroplethColor","value","scale","fallback","isFinite","length","i","buildStyleFn","style","fillColor","fillOpacity","color","weight","opacity","feature","choroplethField","choroplethScale","properties","val","choroplethFallback","strokeColor","strokeWeight","strokeOpacity","buildPopupContent","popup","allowHtml","props","template","replace","_","key","escapeHtml","String","parts","titleField","push","fields","Object","keys","slice","formatted","toLocaleString","join","popupSafeText","undefined","bindMarkerContent","m","marker","tooltip","bindTooltip","bindPopup","addGeoJSONLayer","mapInst","leaflet","geojson","styleFn","layer","geoJSON","pointToLayer","latlng","s","circleMarker","radius","onEachFeature","featureLayer","html","maxWidth","addTo","mapToGeoJSON","p","features","markers","pos","position","lat","Array","isArray","lng","type","geometry","coordinates","JSON","stringify","MapRenderer","mapContainer","mapInstance","isLeafletLoaded","setIsLeafletLoaded","createSignal","error","setError","pmtilesError","setPmtilesError","isExpanded","useExpanded","telemetry","useTelemetry","allowHtmlPopups","params","component","createEffect","setTimeout","invalidateSize","isServer","module","default","e","console","warn","center","zoom","map","zoomControl","scrollWheelZoom","attributionControl","setView","tileLayerUrl","tileLayer","attribution","control","prefix","Icon","Default","prototype","_getIconUrl","mergeOptions","iconRetinaUrl","iconUrl","shadowUrl","allBoundsLayers","eachLayer","Marker","GeoJSON","CircleMarker","_group","_featureGroup","removeLayer","shouldCluster","clustering","clusterOpts","clusterGroup","markerClusterGroup","maxClusterRadius","spiderfyOnMaxZoom","showCoverageOnHover","disableClusteringAtZoom","animate","animateAddingMarkers","forEach","addLayer","geoLayer","geojsonStyle","layers","overlays","layerDef","name","visible","collapsed","pmtiles","protomaps","pmConfig","paintRules","rule","dataLayer","symbolizer","fill","stroke","width","labelRules","TextSymbolizer","label_props","textField","fontSize","pmLayer","leafletLayer","url","maxZoom","minZoom","detail","Error","message","dispatch","errorMessage","id","componentType","ts","Date","now","fitBounds","group","featureGroup","bounds","getBounds","isValid","pad","getZoom","err","onCleanup","remove","_$createComponent","ExpandableWrapper","title","copyData","copyLabel","toolbarVariant","children","_el$","_$getNextElement","_tmpl$4","_el$8","firstChild","_el$9","_co$2","_$getNextMarker","nextSibling","_el$0","_el$1","_co$3","_$insert","Show","when","_el$2","_tmpl$","DegradedFallback","_$mergeProps","caption","mapToDegradedTable","_el$3","_tmpl$2","_el$5","_el$6","_co$","_el$7","_tmpl$3","_ref$","_$use","_$effect","_p$","_v$","height","_v$2","_$style","t","_$className","className"],"mappings":"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"}
1
+ {"version":3,"file":"MapRenderer.cjs","sources":["../../src/components/MapRenderer.tsx"],"sourcesContent":["/**\n * MapRenderer - Interactive map Component\n * Sprint 6: Markers + clustering\n * v3.1.0: GeoJSON, choropleth, popups, multi-layer, PMTiles\n */\n\nimport { Component, createEffect, onCleanup, createSignal, Show, untrack } from 'solid-js';\nimport { isServer } from 'solid-js/web';\nimport type {\n UIComponent,\n MapComponentParams,\n MapClusterOptions,\n MapGeoJSONStyle,\n MapPopupConfig,\n} from '../types';\nimport { ExpandableWrapper, useExpanded } from './ExpandableWrapper';\nimport { DegradedFallback } from './DegradedFallback';\nimport { mapToDegradedTable } from '../utils/degraded-projections';\nimport { escapeHtml } from '../utils/escape-html';\nimport { useTelemetry } from '../context/MCPUITelemetryContext';\nimport {\n DEFAULT_MCPUI_STRINGS,\n formatMCPUIString,\n useMCPUIStrings,\n} from '../context/MCPUIStringsContext';\n\n// Lazy load leaflet (it doesn't support SSR well)\nlet L: any = null;\n// Track if marker cluster CSS has been loaded\nlet clusterCssLoaded = false;\n\nexport interface MapRendererProps {\n /**\n * UIComponent containing map params\n */\n component?: UIComponent;\n\n /**\n * Direct map params\n */\n params?: MapComponentParams;\n\n /**\n * Forwarded to the underlying `<ExpandableWrapper>` (v6.3.1).\n * @see ExpandableWrapperProps.toolbarVariant\n */\n toolbarVariant?: 'hover' | 'always-visible';\n\n /**\n * Trust marker / popup content as raw HTML (v6.10.0, audit P1.2).\n *\n * Leaflet renders bound tooltip/popup strings as HTML, so `marker.tooltip`,\n * `marker.popup` and a GeoJSON `popup.template` are XSS vectors when the\n * payload is untrusted (the default for an LLM/connector-driven public\n * package). **Default `false`** → those are escaped as plain text, and\n * `popup.template` is ignored in favour of the safe auto-generated popup.\n *\n * This is a **host-level** trust decision, deliberately NOT a payload field\n * (a malicious payload could just set its own flag). The\n * `<UIResourceRenderer>` path never sets it, so payload-driven maps are\n * always text-safe. A host rendering `<MapRenderer>` directly with trusted\n * data may set `allowHtmlPopups` to restore rich HTML popups. The\n * auto-generated popup (`titleField` / `fields`) is safe-by-construction\n * and unaffected either way.\n */\n allowHtmlPopups?: boolean;\n}\n\n// ─── Helpers ────────────────────────────────────────────────\n\n/**\n * Resolve choropleth color for a feature based on property value and scale stops.\n */\nfunction getChoroplethColor(\n value: unknown,\n scale: Array<[number, string]>,\n fallback: string\n): string {\n if (value == null || typeof value !== 'number' || !isFinite(value)) return fallback;\n\n // Scale is sorted ascending: [[0, '#eff3ff'], [100, '#084594']]\n if (scale.length === 0) return fallback;\n if (value <= scale[0][0]) return scale[0][1];\n if (value >= scale[scale.length - 1][0]) return scale[scale.length - 1][1];\n\n // Find surrounding stops and interpolate (use upper bracket color)\n for (let i = 1; i < scale.length; i++) {\n if (value <= scale[i][0]) return scale[i][1];\n }\n return scale[scale.length - 1][1];\n}\n\n/**\n * Build a Leaflet style function from MapGeoJSONStyle config.\n */\nfunction buildStyleFn(\n style: MapGeoJSONStyle | undefined\n): (feature: any) => Record<string, unknown> {\n if (!style) {\n return () => ({\n fillColor: '#3388ff',\n fillOpacity: 0.6,\n color: '#333',\n weight: 1,\n opacity: 1,\n });\n }\n\n return (feature: any) => {\n let fillColor = style.fillColor || '#3388ff';\n\n // Choropleth: override fillColor based on feature property\n if (style.choroplethField && style.choroplethScale && feature?.properties) {\n const val = feature.properties[style.choroplethField];\n fillColor = getChoroplethColor(\n val,\n style.choroplethScale,\n style.choroplethFallback || '#ccc'\n );\n }\n\n return {\n fillColor,\n fillOpacity: style.fillOpacity ?? 0.6,\n color: style.strokeColor || '#333',\n weight: style.strokeWeight ?? 1,\n opacity: style.strokeOpacity ?? 1,\n };\n };\n}\n\n/**\n * Build popup HTML from a feature's properties using popup config.\n *\n * `allowHtml` (audit P1.2) gates the raw-HTML `popup.template`: it is honored\n * only when the host trusts the payload. On the default (untrusted) path the\n * template is ignored and we fall through to the auto-generated popup, whose\n * structure is renderer-authored and whose values are always escaped — safe\n * by construction. Even in the trusted path, substituted `{{prop}}` values\n * are escaped (they are data, not markup).\n */\nexport function buildPopupContent(\n feature: any,\n popup: MapPopupConfig | undefined,\n allowHtml = false,\n /** BCP-47 tag for numeric values (`MCPUIStrings.locale`). Was `'fr-FR'` before 6.20.0. */\n locale: string = DEFAULT_MCPUI_STRINGS.locale\n): string | null {\n if (!popup || !feature?.properties) return null;\n const props = feature.properties;\n\n // Custom template — raw HTML, so trusted-host only.\n if (allowHtml && popup.template) {\n return popup.template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key) => {\n const val = props[key];\n return val != null ? escapeHtml(String(val)) : '';\n });\n }\n\n // Auto-generated popup\n const parts: string[] = [];\n\n if (popup.titleField && props[popup.titleField] != null) {\n parts.push(`<strong>${escapeHtml(String(props[popup.titleField]))}</strong>`);\n }\n\n const fields = popup.fields || Object.keys(props).slice(0, 8);\n for (const key of fields) {\n if (key === popup.titleField) continue;\n const val = props[key];\n if (val == null) continue;\n const formatted = typeof val === 'number' ? val.toLocaleString(locale) : String(val);\n parts.push(\n `<span style=\"color:#666;font-size:11px\">${escapeHtml(key)}</span>: ${escapeHtml(formatted)}`\n );\n }\n\n return parts.join('<br/>');\n}\n\n/**\n * Resolve a marker's tooltip/popup string for binding (audit P1.2). Leaflet\n * renders bound strings as HTML; `marker.tooltip` / `marker.popup` come from\n * the (untrusted) payload, so they are escaped to plain text unless the host\n * has opted into raw HTML via `allowHtmlPopups`. Pure + exported for tests.\n */\nexport function popupSafeText(value: string | undefined, allowHtml = false): string | undefined {\n if (value == null) return undefined;\n return allowHtml ? value : escapeHtml(value);\n}\n\n/** Bind a marker's tooltip + popup, escaping by default (see popupSafeText). */\nexport function bindMarkerContent(\n m: any,\n marker: { tooltip?: string; popup?: string },\n allowHtml: boolean\n): void {\n const tooltip = popupSafeText(marker.tooltip, allowHtml);\n if (tooltip) m.bindTooltip(tooltip);\n const popup = popupSafeText(marker.popup, allowHtml);\n if (popup) m.bindPopup(popup);\n}\n\n/**\n * Add a GeoJSON layer to the map with style and popup support.\n * Returns the layer for bounds calculation.\n */\nexport function addGeoJSONLayer(\n mapInst: any,\n leaflet: any,\n geojson: unknown,\n style?: MapGeoJSONStyle,\n popup?: MapPopupConfig,\n allowHtml = false,\n /**\n * BCP-47 tag forwarded to {@link buildPopupContent}, or a getter. With a\n * getter, each popup is bound to a function Leaflet evaluates when the popup\n * opens, so it follows locale changes without rebuilding the layer.\n */\n locale: string | (() => string) = DEFAULT_MCPUI_STRINGS.locale\n): any {\n const styleFn = buildStyleFn(style);\n\n const layer = leaflet.geoJSON(geojson, {\n style: styleFn,\n pointToLayer: (feature: any, latlng: any) => {\n // Render points as circle markers for consistency\n const s = styleFn(feature);\n return leaflet.circleMarker(latlng, {\n radius: 6,\n fillColor: s.fillColor,\n fillOpacity: s.fillOpacity,\n color: s.color,\n weight: s.weight,\n opacity: s.opacity,\n });\n },\n onEachFeature: (feature: any, featureLayer: any) => {\n // `untrack`: onEachFeature runs synchronously inside the map setup effect\n // when Leaflet is already loaded. A tracked read there would subscribe\n // that non-idempotent effect to the locale.\n const currentLocale = () => (typeof locale === 'function' ? untrack(locale) : locale);\n const html = buildPopupContent(feature, popup, allowHtml, currentLocale());\n if (html) {\n featureLayer.bindPopup(\n typeof locale === 'function'\n ? () => buildPopupContent(feature, popup, allowHtml, currentLocale()) ?? ''\n : html,\n { maxWidth: 300 }\n );\n }\n },\n });\n\n layer.addTo(mapInst);\n return layer;\n}\n\n// ─── Component ──────────────────────────────────────────────\n\n/**\n * Build a GeoJSON FeatureCollection from the map's `markers` (and any\n * inlined GeoJSON layers, when present). Used by the \"Copy data\" button\n * shipped via `<ExpandableWrapper>` (v6.2.0). Best-effort — clusters,\n * tile layers, and choropleth-only data don't get round-tripped.\n */\nfunction mapToGeoJSON(p: MapComponentParams | undefined): string {\n if (!p) return '{\"type\":\"FeatureCollection\",\"features\":[]}';\n const features: any[] = [];\n for (const marker of p.markers ?? []) {\n const pos: any = marker.position as any;\n // Accept both [lat, lng] tuple and {lat, lng} object shapes (v5.0.2 spec)\n const lat = Array.isArray(pos) ? pos[0] : pos?.lat;\n const lng = Array.isArray(pos) ? pos[1] : pos?.lng;\n if (typeof lat !== 'number' || typeof lng !== 'number') continue;\n features.push({\n type: 'Feature',\n geometry: { type: 'Point', coordinates: [lng, lat] },\n properties: {\n ...(marker.tooltip ? { tooltip: marker.tooltip } : {}),\n ...(marker.popup ? { popup: marker.popup } : {}),\n },\n });\n }\n return JSON.stringify({ type: 'FeatureCollection', features }, null, 2);\n}\n\nexport const MapRenderer: Component<MapRendererProps> = (props) => {\n const strings = useMCPUIStrings();\n let mapContainer: HTMLDivElement | undefined;\n let mapInstance: any = null;\n const [isLeafletLoaded, setIsLeafletLoaded] = createSignal(false);\n const [error, setError] = createSignal<string | null>(null);\n // PMTiles is an optional overlay on top of the base map. When it fails we\n // keep the base map but surface a visible notice (audit P1.3) instead of a\n // silent console.warn that leaves the user with an unexplained empty layer.\n const [pmtilesError, setPmtilesError] = createSignal<string | null>(null);\n const isExpanded = useExpanded();\n const telemetry = useTelemetry();\n // Host-level trust for raw HTML in marker/popup content (audit P1.2).\n // Default false → tooltip/popup escaped, GeoJSON `popup.template` ignored.\n const allowHtml = () => props.allowHtmlPopups === true;\n\n const params = () => props.params || (props.component?.params as MapComponentParams);\n\n // v6.2.0 — Leaflet has to be told to re-measure when its container\n // resizes (e.g. transitioning to fullscreen via ExpandableWrapper).\n // We give the DOM a tick to settle the new dimensions, then ask\n // Leaflet to reflow tiles.\n createEffect(() => {\n const expanded = isExpanded();\n if (!mapInstance) return;\n // Read the signal so the effect re-runs on toggle ; the value is\n // observed for its side effects on layout.\n void expanded;\n setTimeout(() => mapInstance?.invalidateSize?.(), 100);\n });\n\n // Initialize Map\n createEffect(async () => {\n if (isServer) return; // Don't run on server\n\n if (!L) {\n try {\n const module = await import('leaflet');\n L = module.default || module;\n await import('leaflet/dist/leaflet.css'); // Import CSS\n setIsLeafletLoaded(true);\n } catch (e) {\n console.warn('Failed to load leaflet', e);\n setError(strings.mapLibraryUnavailable);\n return;\n }\n } else {\n setIsLeafletLoaded(true);\n }\n\n if (isLeafletLoaded() && mapContainer && !mapInstance) {\n const p = params();\n const center = p?.center || [51.505, -0.09]; // Default to London\n const zoom = p?.zoom || 13;\n\n mapInstance = L.map(mapContainer, {\n zoomControl: p?.zoomControl !== false,\n scrollWheelZoom: p?.scrollWheelZoom !== false,\n attributionControl: false,\n }).setView(center, zoom);\n\n // Add OpenStreetMap tile layer\n const tileLayerUrl = p?.tileLayer || 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';\n L.tileLayer(tileLayerUrl, {\n attribution:\n p?.attribution ||\n '&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors',\n }).addTo(mapInstance);\n\n if (p?.attribution !== '') {\n L.control.attribution({ prefix: false }).addTo(mapInstance);\n }\n\n // Fix marker icons (Leaflet issue with bundlers)\n delete (L.Icon.Default.prototype as any)._getIconUrl;\n L.Icon.Default.mergeOptions({\n iconRetinaUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png',\n iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png',\n shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',\n });\n }\n\n // Update markers and view\n if (mapInstance && L) {\n try {\n const p = params();\n const allBoundsLayers: any[] = [];\n\n // Clear existing layers (markers, cluster groups, GeoJSON)\n mapInstance.eachLayer((layer: any) => {\n if (\n layer instanceof L.Marker ||\n layer instanceof L.GeoJSON ||\n layer instanceof L.CircleMarker ||\n layer._group ||\n layer._featureGroup\n ) {\n mapInstance.removeLayer(layer);\n }\n });\n\n // ─── Markers (legacy) ────────────────────────\n const markers: any[] = [];\n const shouldCluster = p?.clustering && p?.markers && p.markers.length > 0;\n\n if (shouldCluster) {\n try {\n await import('leaflet.markercluster');\n if (!clusterCssLoaded) {\n await import('leaflet.markercluster/dist/MarkerCluster.css');\n await import('leaflet.markercluster/dist/MarkerCluster.Default.css');\n clusterCssLoaded = true;\n }\n const clusterOpts: MapClusterOptions =\n typeof p.clustering === 'object' ? p.clustering : {};\n const clusterGroup = (L as any).markerClusterGroup({\n maxClusterRadius: clusterOpts.maxClusterRadius ?? 80,\n spiderfyOnMaxZoom: clusterOpts.spiderfyOnMaxZoom ?? true,\n showCoverageOnHover: clusterOpts.showCoverageOnHover ?? true,\n disableClusteringAtZoom: clusterOpts.disableClusteringAtZoom,\n animate: clusterOpts.animateAddingMarkers ?? true,\n });\n p?.markers?.forEach((marker) => {\n const m = L.marker(marker.position);\n bindMarkerContent(m, marker, allowHtml());\n clusterGroup.addLayer(m);\n markers.push(m);\n });\n mapInstance.addLayer(clusterGroup);\n } catch {\n p?.markers?.forEach((marker) => {\n const m = L.marker(marker.position).addTo(mapInstance);\n bindMarkerContent(m, marker, allowHtml());\n markers.push(m);\n });\n }\n } else {\n p?.markers?.forEach((marker) => {\n const m = L.marker(marker.position).addTo(mapInstance);\n bindMarkerContent(m, marker, allowHtml());\n markers.push(m);\n });\n }\n\n if (markers.length > 0) {\n allBoundsLayers.push(...markers);\n }\n\n // ─── GeoJSON (v3.1.0) ───────────────────────\n if (p?.geojson) {\n const geoLayer = addGeoJSONLayer(\n mapInstance,\n L,\n p.geojson,\n p.geojsonStyle,\n p.popup,\n allowHtml(),\n // A getter, not a value: popups read the current locale when they\n // open. Tracking the locale here would re-run this effect, which is\n // not idempotent (layer control, PMTiles layer, view reset).\n () => strings.locale\n );\n allBoundsLayers.push(geoLayer);\n }\n\n // ─── Named layers (v3.1.0) ──────────────────\n if (p?.layers && p.layers.length > 0) {\n const overlays: Record<string, any> = {};\n\n for (const layerDef of p.layers) {\n const geoLayer = addGeoJSONLayer(\n mapInstance,\n L,\n layerDef.geojson,\n layerDef.style || p?.geojsonStyle,\n layerDef.popup || p?.popup,\n allowHtml(),\n () => strings.locale\n );\n\n overlays[layerDef.name] = geoLayer;\n allBoundsLayers.push(geoLayer);\n\n // Respect initial visibility\n if (layerDef.visible === false) {\n mapInstance.removeLayer(geoLayer);\n }\n }\n\n // Add layer control if multiple layers\n if (Object.keys(overlays).length > 1) {\n L.control.layers(null, overlays, { collapsed: true }).addTo(mapInstance);\n }\n }\n\n // ─── PMTiles (v3.1.0) ────────────────────────\n setPmtilesError(null);\n if (p?.pmtiles) {\n try {\n const protomaps = await import(/* @vite-ignore */ 'protomaps-leaflet');\n const pmConfig = p.pmtiles;\n\n const paintRules =\n pmConfig.paintRules?.map((rule) => ({\n dataLayer: rule.dataLayer,\n symbolizer: new (protomaps as any)[\n rule.symbolizer === 'polygon'\n ? 'PolygonSymbolizer'\n : rule.symbolizer === 'line'\n ? 'LineSymbolizer'\n : 'CircleSymbolizer'\n ]({\n fill: rule.color || '#3388ff',\n stroke: rule.color || '#333',\n width: rule.width ?? 1,\n opacity: rule.opacity ?? 0.6,\n }),\n })) || [];\n\n const labelRules =\n pmConfig.labelRules?.map((rule) => ({\n dataLayer: rule.dataLayer,\n symbolizer: new (protomaps as any).TextSymbolizer({\n label_props: [rule.textField],\n fontSize: rule.fontSize ?? 12,\n }),\n })) || [];\n\n const pmLayer = (protomaps as any).leafletLayer({\n url: pmConfig.url,\n attribution: pmConfig.attribution,\n paintRules,\n labelRules,\n maxZoom: pmConfig.maxZoom,\n minZoom: pmConfig.minZoom,\n });\n\n pmLayer.addTo(mapInstance);\n } catch (e) {\n // P1.3 — do NOT fail silently. Keep the base map, but surface a\n // visible notice and report a renderer error via telemetry. The\n // most common cause is the optional `protomaps-leaflet` peer not\n // being installed.\n const detail = e instanceof Error ? e.message : String(e);\n // English diagnostic for logs and telemetry (P7); the visible\n // banner reads the localized `mapPmtilesUnavailable` key.\n const diagnostic =\n 'PMTiles layer unavailable — the optional \"protomaps-leaflet\" ' +\n 'peer dependency failed to load or render.';\n console.warn('[MCP-UI] ' + diagnostic, e);\n setPmtilesError(strings.mapPmtilesUnavailable);\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: `${diagnostic} (${detail})`,\n id: props.component?.id ?? '',\n componentType: 'map',\n ts: Date.now(),\n });\n }\n }\n\n // ─── Fit bounds ─────────────────────────────\n if (p?.fitBounds && allBoundsLayers.length > 0) {\n const group = L.featureGroup(allBoundsLayers);\n const bounds = group.getBounds();\n if (bounds.isValid()) {\n mapInstance.fitBounds(bounds.pad(0.1));\n }\n } else if (p?.center) {\n mapInstance.setView(p.center, p.zoom || mapInstance.getZoom());\n }\n } catch (err) {\n // Fallback ladder (P2.5): a Leaflet drawing failure degrades to\n // the coordinate table below instead of a blank/partial map.\n const message = err instanceof Error ? err.message : strings.mapRenderError;\n setError(message);\n telemetry?.dispatch({\n type: 'render:error',\n errorMessage: message,\n id: props.component?.id ?? '',\n componentType: 'map',\n ts: Date.now(),\n });\n }\n }\n });\n\n // Cleanup\n onCleanup(() => {\n if (mapInstance) {\n mapInstance.remove();\n mapInstance = null;\n }\n });\n\n return (\n <ExpandableWrapper\n title={strings.mapTitle}\n copyData={mapToGeoJSON(params())}\n copyLabel={strings.mapCopy}\n toolbarVariant={props.toolbarVariant}\n >\n <div\n class={`w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${params()?.className || ''} ${\n isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''\n }`}\n >\n <Show when={error()}>\n {/* Fallback ladder (P2.5): degrade to a coordinate table\n rather than a bare error string. */}\n <div class=\"p-3\">\n <DegradedFallback\n message={formatMCPUIString(strings.mapRenderFailed, { error: String(error()) })}\n caption={strings.mapDegradedCaption}\n {...mapToDegradedTable(params() ?? {}, {\n type: strings.degradedColType,\n lat: strings.degradedColLat,\n lng: strings.degradedColLng,\n info: strings.degradedColInfo,\n marker: strings.degradedMarker,\n feature: strings.degradedFeature,\n })}\n />\n </div>\n </Show>\n <Show when={!error()}>\n {/* P1.3 — visible notice when the PMTiles overlay fails but the\n base map is still usable. */}\n <Show when={pmtilesError()}>\n <div\n role=\"alert\"\n class=\"m-2 rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-800 dark:border-amber-700/50 dark:bg-amber-900/20 dark:text-amber-200\"\n >\n {pmtilesError()} {strings.mapBaseMapStillShown}\n </div>\n </Show>\n <div\n ref={mapContainer}\n style={\n isExpanded()\n ? { height: '100%', width: '100%', 'z-index': 0 }\n : { height: params()?.height || '400px', width: '100%', 'z-index': 0 }\n }\n class={`relative z-0 ${isExpanded() ? 'flex-1 min-h-0' : ''}`}\n />\n </Show>\n </div>\n </ExpandableWrapper>\n );\n};\n"],"names":["L","clusterCssLoaded","getChoroplethColor","value","scale","fallback","isFinite","length","i","buildStyleFn","style","fillColor","fillOpacity","color","weight","opacity","feature","choroplethField","choroplethScale","properties","val","choroplethFallback","strokeColor","strokeWeight","strokeOpacity","buildPopupContent","popup","allowHtml","locale","DEFAULT_MCPUI_STRINGS","props","template","replace","_","key","escapeHtml","String","parts","titleField","push","fields","Object","keys","slice","formatted","toLocaleString","join","popupSafeText","undefined","bindMarkerContent","m","marker","tooltip","bindTooltip","bindPopup","addGeoJSONLayer","mapInst","leaflet","geojson","styleFn","layer","geoJSON","pointToLayer","latlng","s","circleMarker","radius","onEachFeature","featureLayer","currentLocale","untrack","html","maxWidth","addTo","mapToGeoJSON","p","features","markers","pos","position","lat","Array","isArray","lng","type","geometry","coordinates","JSON","stringify","MapRenderer","strings","useMCPUIStrings","mapContainer","mapInstance","isLeafletLoaded","setIsLeafletLoaded","createSignal","error","setError","pmtilesError","setPmtilesError","isExpanded","useExpanded","telemetry","useTelemetry","allowHtmlPopups","params","component","createEffect","setTimeout","invalidateSize","isServer","module","default","e","console","warn","mapLibraryUnavailable","center","zoom","map","zoomControl","scrollWheelZoom","attributionControl","setView","tileLayerUrl","tileLayer","attribution","control","prefix","Icon","Default","prototype","_getIconUrl","mergeOptions","iconRetinaUrl","iconUrl","shadowUrl","allBoundsLayers","eachLayer","Marker","GeoJSON","CircleMarker","_group","_featureGroup","removeLayer","shouldCluster","clustering","clusterOpts","clusterGroup","markerClusterGroup","maxClusterRadius","spiderfyOnMaxZoom","showCoverageOnHover","disableClusteringAtZoom","animate","animateAddingMarkers","forEach","addLayer","geoLayer","geojsonStyle","layers","overlays","layerDef","name","visible","collapsed","pmtiles","protomaps","pmConfig","paintRules","rule","dataLayer","symbolizer","fill","stroke","width","labelRules","TextSymbolizer","label_props","textField","fontSize","pmLayer","leafletLayer","url","maxZoom","minZoom","detail","Error","message","diagnostic","mapPmtilesUnavailable","dispatch","errorMessage","id","componentType","ts","Date","now","fitBounds","group","featureGroup","bounds","getBounds","isValid","pad","getZoom","err","mapRenderError","onCleanup","remove","_$createComponent","ExpandableWrapper","title","mapTitle","copyData","copyLabel","mapCopy","toolbarVariant","children","_el$","_$getNextElement","_tmpl$4","_el$0","firstChild","_el$1","_co$3","_$getNextMarker","nextSibling","_el$10","_el$11","_co$4","_$insert","Show","when","_el$2","_tmpl$","DegradedFallback","_$mergeProps","formatMCPUIString","mapRenderFailed","caption","mapDegradedCaption","mapToDegradedTable","degradedColType","degradedColLat","degradedColLng","info","degradedColInfo","degradedMarker","degradedFeature","_el$3","_tmpl$2","_el$5","_el$6","_co$","_el$4","_el$7","_el$8","_co$2","mapBaseMapStillShown","_el$9","_tmpl$3","_ref$","_$use","_$effect","_p$","_v$","height","_v$2","_$style","t","_$className","className"],"mappings":"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"}
@@ -48,7 +48,9 @@ export interface MapRendererProps {
48
48
  * by construction. Even in the trusted path, substituted `{{prop}}` values
49
49
  * are escaped (they are data, not markup).
50
50
  */
51
- export declare function buildPopupContent(feature: any, popup: MapPopupConfig | undefined, allowHtml?: boolean): string | null;
51
+ export declare function buildPopupContent(feature: any, popup: MapPopupConfig | undefined, allowHtml?: boolean,
52
+ /** BCP-47 tag for numeric values (`MCPUIStrings.locale`). Was `'fr-FR'` before 6.20.0. */
53
+ locale?: string): string | null;
52
54
  /**
53
55
  * Resolve a marker's tooltip/popup string for binding (audit P1.2). Leaflet
54
56
  * renders bound strings as HTML; `marker.tooltip` / `marker.popup` come from
@@ -65,6 +67,12 @@ export declare function bindMarkerContent(m: any, marker: {
65
67
  * Add a GeoJSON layer to the map with style and popup support.
66
68
  * Returns the layer for bounds calculation.
67
69
  */
68
- export declare function addGeoJSONLayer(mapInst: any, leaflet: any, geojson: unknown, style?: MapGeoJSONStyle, popup?: MapPopupConfig, allowHtml?: boolean): any;
70
+ export declare function addGeoJSONLayer(mapInst: any, leaflet: any, geojson: unknown, style?: MapGeoJSONStyle, popup?: MapPopupConfig, allowHtml?: boolean,
71
+ /**
72
+ * BCP-47 tag forwarded to {@link buildPopupContent}, or a getter. With a
73
+ * getter, each popup is bound to a function Leaflet evaluates when the popup
74
+ * opens, so it follows locale changes without rebuilding the layer.
75
+ */
76
+ locale?: string | (() => string)): any;
69
77
  export declare const MapRenderer: Component<MapRendererProps>;
70
78
  //# sourceMappingURL=MapRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MapRenderer.d.ts","sourceRoot":"","sources":["../../src/components/MapRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAA+C,MAAM,UAAU,CAAC;AAElF,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAElB,eAAe,EACf,cAAc,EACf,MAAM,UAAU,CAAC;AAYlB,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAC;IAExB;;OAEG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAE5B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IAE5C;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAiED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,GAAG,EACZ,KAAK,EAAE,cAAc,GAAG,SAAS,EACjC,SAAS,UAAQ,GAChB,MAAM,GAAG,IAAI,CA+Bf;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,UAAQ,GAAG,MAAM,GAAG,SAAS,CAG9F;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,GAAG,EACN,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5C,SAAS,EAAE,OAAO,GACjB,IAAI,CAKN;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,OAAO,EAChB,KAAK,CAAC,EAAE,eAAe,EACvB,KAAK,CAAC,EAAE,cAAc,EACtB,SAAS,UAAQ,GAChB,GAAG,CA2BL;AA+BD,eAAO,MAAM,WAAW,EAAE,SAAS,CAAC,gBAAgB,CA8UnD,CAAC"}
1
+ {"version":3,"file":"MapRenderer.d.ts","sourceRoot":"","sources":["../../src/components/MapRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAwD,MAAM,UAAU,CAAC;AAE3F,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAElB,eAAe,EACf,cAAc,EACf,MAAM,UAAU,CAAC;AAiBlB,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,SAAS,CAAC,EAAE,WAAW,CAAC;IAExB;;OAEG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAE5B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IAE5C;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAiED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,GAAG,EACZ,KAAK,EAAE,cAAc,GAAG,SAAS,EACjC,SAAS,UAAQ;AACjB,0FAA0F;AAC1F,MAAM,GAAE,MAAqC,GAC5C,MAAM,GAAG,IAAI,CA+Bf;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,UAAQ,GAAG,MAAM,GAAG,SAAS,CAG9F;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,GAAG,EACN,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5C,SAAS,EAAE,OAAO,GACjB,IAAI,CAKN;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,OAAO,EAChB,KAAK,CAAC,EAAE,eAAe,EACvB,KAAK,CAAC,EAAE,cAAc,EACtB,SAAS,UAAQ;AACjB;;;;GAIG;AACH,MAAM,GAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAgC,GAC7D,GAAG,CAoCL;AA+BD,eAAO,MAAM,WAAW,EAAE,SAAS,CAAC,gBAAgB,CA6VnD,CAAC"}
@@ -1,11 +1,13 @@
1
1
  import { isServer, createComponent, getNextElement, getNextMarker, insert, mergeProps, use, effect, style, className, template } from "solid-js/web";
2
- import { createSignal, createEffect, onCleanup, Show } from "solid-js";
2
+ import { createSignal, createEffect, onCleanup, Show, untrack } from "solid-js";
3
3
  import { useExpanded, ExpandableWrapper } from "./ExpandableWrapper.js";
4
4
  import { DegradedFallback } from "./DegradedFallback.js";
5
5
  import { mapToDegradedTable } from "../utils/degraded-projections.js";
6
6
  import { escapeHtml } from "../utils/escape-html.js";
7
7
  import { useTelemetry } from "../context/MCPUITelemetryContext.js";
8
- var _tmpl$ = /* @__PURE__ */ template(`<div class=p-3>`), _tmpl$2 = /* @__PURE__ */ template(`<div role=alert class="m-2 rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-800 dark:border-amber-700/50 dark:bg-amber-900/20 dark:text-amber-200"><!$><!/> The base map is still shown.`), _tmpl$3 = /* @__PURE__ */ template(`<div>`), _tmpl$4 = /* @__PURE__ */ template(`<div><!$><!/><!$><!/>`);
8
+ import { useMCPUIStrings, DEFAULT_MCPUI_STRINGS } from "../context/MCPUIStringsContext.js";
9
+ import { formatMCPUIString } from "../utils/format-string.js";
10
+ var _tmpl$ = /* @__PURE__ */ template(`<div class=p-3>`), _tmpl$2 = /* @__PURE__ */ template(`<div role=alert class="m-2 rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-800 dark:border-amber-700/50 dark:bg-amber-900/20 dark:text-amber-200"><!$><!/> <!$><!/>`), _tmpl$3 = /* @__PURE__ */ template(`<div>`), _tmpl$4 = /* @__PURE__ */ template(`<div><!$><!/><!$><!/>`);
9
11
  let L = null;
10
12
  let clusterCssLoaded = false;
11
13
  function getChoroplethColor(value, scale, fallback) {
@@ -43,7 +45,7 @@ function buildStyleFn(style2) {
43
45
  };
44
46
  };
45
47
  }
46
- function buildPopupContent(feature, popup, allowHtml = false) {
48
+ function buildPopupContent(feature, popup, allowHtml = false, locale = DEFAULT_MCPUI_STRINGS.locale) {
47
49
  if (!popup || !(feature == null ? void 0 : feature.properties)) return null;
48
50
  const props = feature.properties;
49
51
  if (allowHtml && popup.template) {
@@ -61,7 +63,7 @@ function buildPopupContent(feature, popup, allowHtml = false) {
61
63
  if (key === popup.titleField) continue;
62
64
  const val = props[key];
63
65
  if (val == null) continue;
64
- const formatted = typeof val === "number" ? val.toLocaleString("fr-FR") : String(val);
66
+ const formatted = typeof val === "number" ? val.toLocaleString(locale) : String(val);
65
67
  parts.push(`<span style="color:#666;font-size:11px">${escapeHtml(key)}</span>: ${escapeHtml(formatted)}`);
66
68
  }
67
69
  return parts.join("<br/>");
@@ -76,7 +78,7 @@ function bindMarkerContent(m, marker, allowHtml) {
76
78
  const popup = popupSafeText(marker.popup, allowHtml);
77
79
  if (popup) m.bindPopup(popup);
78
80
  }
79
- function addGeoJSONLayer(mapInst, leaflet, geojson, style2, popup, allowHtml = false) {
81
+ function addGeoJSONLayer(mapInst, leaflet, geojson, style2, popup, allowHtml = false, locale = DEFAULT_MCPUI_STRINGS.locale) {
80
82
  const styleFn = buildStyleFn(style2);
81
83
  const layer = leaflet.geoJSON(geojson, {
82
84
  style: styleFn,
@@ -92,9 +94,10 @@ function addGeoJSONLayer(mapInst, leaflet, geojson, style2, popup, allowHtml = f
92
94
  });
93
95
  },
94
96
  onEachFeature: (feature, featureLayer) => {
95
- const html = buildPopupContent(feature, popup, allowHtml);
97
+ const currentLocale = () => typeof locale === "function" ? untrack(locale) : locale;
98
+ const html = buildPopupContent(feature, popup, allowHtml, currentLocale());
96
99
  if (html) {
97
- featureLayer.bindPopup(html, {
100
+ featureLayer.bindPopup(typeof locale === "function" ? () => buildPopupContent(feature, popup, allowHtml, currentLocale()) ?? "" : html, {
98
101
  maxWidth: 300
99
102
  });
100
103
  }
@@ -133,6 +136,7 @@ function mapToGeoJSON(p) {
133
136
  }, null, 2);
134
137
  }
135
138
  const MapRenderer = (props) => {
139
+ const strings = useMCPUIStrings();
136
140
  let mapContainer;
137
141
  let mapInstance = null;
138
142
  const [isLeafletLoaded, setIsLeafletLoaded] = createSignal(false);
@@ -164,7 +168,7 @@ const MapRenderer = (props) => {
164
168
  setIsLeafletLoaded(true);
165
169
  } catch (e) {
166
170
  console.warn("Failed to load leaflet", e);
167
- setError("Map library could not be loaded.");
171
+ setError(strings.mapLibraryUnavailable);
168
172
  return;
169
173
  }
170
174
  } else {
@@ -247,13 +251,24 @@ const MapRenderer = (props) => {
247
251
  allBoundsLayers.push(...markers);
248
252
  }
249
253
  if (p == null ? void 0 : p.geojson) {
250
- const geoLayer = addGeoJSONLayer(mapInstance, L, p.geojson, p.geojsonStyle, p.popup, allowHtml());
254
+ const geoLayer = addGeoJSONLayer(
255
+ mapInstance,
256
+ L,
257
+ p.geojson,
258
+ p.geojsonStyle,
259
+ p.popup,
260
+ allowHtml(),
261
+ // A getter, not a value: popups read the current locale when they
262
+ // open. Tracking the locale here would re-run this effect, which is
263
+ // not idempotent (layer control, PMTiles layer, view reset).
264
+ () => strings.locale
265
+ );
251
266
  allBoundsLayers.push(geoLayer);
252
267
  }
253
268
  if ((p == null ? void 0 : p.layers) && p.layers.length > 0) {
254
269
  const overlays = {};
255
270
  for (const layerDef of p.layers) {
256
- const geoLayer = addGeoJSONLayer(mapInstance, L, layerDef.geojson, layerDef.style || (p == null ? void 0 : p.geojsonStyle), layerDef.popup || (p == null ? void 0 : p.popup), allowHtml());
271
+ const geoLayer = addGeoJSONLayer(mapInstance, L, layerDef.geojson, layerDef.style || (p == null ? void 0 : p.geojsonStyle), layerDef.popup || (p == null ? void 0 : p.popup), allowHtml(), () => strings.locale);
257
272
  overlays[layerDef.name] = geoLayer;
258
273
  allBoundsLayers.push(geoLayer);
259
274
  if (layerDef.visible === false) {
@@ -301,12 +316,12 @@ const MapRenderer = (props) => {
301
316
  pmLayer.addTo(mapInstance);
302
317
  } catch (e) {
303
318
  const detail = e instanceof Error ? e.message : String(e);
304
- const message = 'PMTiles layer unavailable — the optional "protomaps-leaflet" peer dependency failed to load or render.';
305
- console.warn("[MCP-UI] " + message, e);
306
- setPmtilesError(message);
319
+ const diagnostic = 'PMTiles layer unavailable — the optional "protomaps-leaflet" peer dependency failed to load or render.';
320
+ console.warn("[MCP-UI] " + diagnostic, e);
321
+ setPmtilesError(strings.mapPmtilesUnavailable);
307
322
  telemetry == null ? void 0 : telemetry.dispatch({
308
323
  type: "render:error",
309
- errorMessage: `${message} (${detail})`,
324
+ errorMessage: `${diagnostic} (${detail})`,
310
325
  id: ((_f = props.component) == null ? void 0 : _f.id) ?? "",
311
326
  componentType: "map",
312
327
  ts: Date.now()
@@ -323,7 +338,7 @@ const MapRenderer = (props) => {
323
338
  mapInstance.setView(p.center, p.zoom || mapInstance.getZoom());
324
339
  }
325
340
  } catch (err) {
326
- const message = err instanceof Error ? err.message : "Failed to render map";
341
+ const message = err instanceof Error ? err.message : strings.mapRenderError;
327
342
  setError(message);
328
343
  telemetry == null ? void 0 : telemetry.dispatch({
329
344
  type: "render:error",
@@ -342,16 +357,20 @@ const MapRenderer = (props) => {
342
357
  }
343
358
  });
344
359
  return createComponent(ExpandableWrapper, {
345
- title: "Map",
360
+ get title() {
361
+ return strings.mapTitle;
362
+ },
346
363
  get copyData() {
347
364
  return mapToGeoJSON(params());
348
365
  },
349
- copyLabel: "Copy markers as GeoJSON",
366
+ get copyLabel() {
367
+ return strings.mapCopy;
368
+ },
350
369
  get toolbarVariant() {
351
370
  return props.toolbarVariant;
352
371
  },
353
372
  get children() {
354
- var _el$ = getNextElement(_tmpl$4), _el$8 = _el$.firstChild, [_el$9, _co$2] = getNextMarker(_el$8.nextSibling), _el$0 = _el$9.nextSibling, [_el$1, _co$3] = getNextMarker(_el$0.nextSibling);
373
+ var _el$ = getNextElement(_tmpl$4), _el$0 = _el$.firstChild, [_el$1, _co$3] = getNextMarker(_el$0.nextSibling), _el$10 = _el$1.nextSibling, [_el$11, _co$4] = getNextMarker(_el$10.nextSibling);
355
374
  insert(_el$, createComponent(Show, {
356
375
  get when() {
357
376
  return error();
@@ -360,13 +379,24 @@ const MapRenderer = (props) => {
360
379
  var _el$2 = getNextElement(_tmpl$);
361
380
  insert(_el$2, createComponent(DegradedFallback, mergeProps({
362
381
  get message() {
363
- return `Map rendering failed: ${error()}`;
382
+ return formatMCPUIString(strings.mapRenderFailed, {
383
+ error: String(error())
384
+ });
364
385
  },
365
- caption: "Showing the map data as a coordinate table — the interactive map is unavailable."
366
- }, () => mapToDegradedTable(params() ?? {}))));
386
+ get caption() {
387
+ return strings.mapDegradedCaption;
388
+ }
389
+ }, () => mapToDegradedTable(params() ?? {}, {
390
+ type: strings.degradedColType,
391
+ lat: strings.degradedColLat,
392
+ lng: strings.degradedColLng,
393
+ info: strings.degradedColInfo,
394
+ marker: strings.degradedMarker,
395
+ feature: strings.degradedFeature
396
+ }))));
367
397
  return _el$2;
368
398
  }
369
- }), _el$9, _co$2);
399
+ }), _el$1, _co$3);
370
400
  insert(_el$, createComponent(Show, {
371
401
  get when() {
372
402
  return !error();
@@ -377,15 +407,15 @@ const MapRenderer = (props) => {
377
407
  return pmtilesError();
378
408
  },
379
409
  get children() {
380
- var _el$3 = getNextElement(_tmpl$2), _el$5 = _el$3.firstChild, [_el$6, _co$] = getNextMarker(_el$5.nextSibling);
381
- _el$6.nextSibling;
410
+ var _el$3 = getNextElement(_tmpl$2), _el$5 = _el$3.firstChild, [_el$6, _co$] = getNextMarker(_el$5.nextSibling), _el$4 = _el$6.nextSibling, _el$7 = _el$4.nextSibling, [_el$8, _co$2] = getNextMarker(_el$7.nextSibling);
382
411
  insert(_el$3, pmtilesError, _el$6, _co$);
412
+ insert(_el$3, () => strings.mapBaseMapStillShown, _el$8, _co$2);
383
413
  return _el$3;
384
414
  }
385
415
  }), (() => {
386
- var _el$7 = getNextElement(_tmpl$3);
416
+ var _el$9 = getNextElement(_tmpl$3);
387
417
  var _ref$ = mapContainer;
388
- typeof _ref$ === "function" ? use(_ref$, _el$7) : mapContainer = _el$7;
418
+ typeof _ref$ === "function" ? use(_ref$, _el$9) : mapContainer = _el$9;
389
419
  effect((_p$) => {
390
420
  var _a;
391
421
  var _v$ = isExpanded() ? {
@@ -397,17 +427,17 @@ const MapRenderer = (props) => {
397
427
  width: "100%",
398
428
  "z-index": 0
399
429
  }, _v$2 = `relative z-0 ${isExpanded() ? "flex-1 min-h-0" : ""}`;
400
- _p$.e = style(_el$7, _v$, _p$.e);
401
- _v$2 !== _p$.t && className(_el$7, _p$.t = _v$2);
430
+ _p$.e = style(_el$9, _v$, _p$.e);
431
+ _v$2 !== _p$.t && className(_el$9, _p$.t = _v$2);
402
432
  return _p$;
403
433
  }, {
404
434
  e: void 0,
405
435
  t: void 0
406
436
  });
407
- return _el$7;
437
+ return _el$9;
408
438
  })()];
409
439
  }
410
- }), _el$1, _co$3);
440
+ }), _el$11, _co$4);
411
441
  effect(() => {
412
442
  var _a;
413
443
  return className(_el$, `w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden ${((_a = params()) == null ? void 0 : _a.className) || ""} ${isExpanded() ? "flex-1 min-h-0 flex flex-col" : ""}`);