@seed-ship/mcp-ui-solid 6.17.0 → 6.18.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 (156) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +50 -3
  3. package/dist/adapters/index.d.ts +2 -0
  4. package/dist/adapters/index.d.ts.map +1 -1
  5. package/dist/adapters/presentation.cjs +141 -0
  6. package/dist/adapters/presentation.cjs.map +1 -0
  7. package/dist/adapters/presentation.d.ts +68 -0
  8. package/dist/adapters/presentation.d.ts.map +1 -0
  9. package/dist/adapters/presentation.js +141 -0
  10. package/dist/adapters/presentation.js.map +1 -0
  11. package/dist/adapters.cjs +4 -0
  12. package/dist/adapters.cjs.map +1 -1
  13. package/dist/adapters.d.cts +2 -0
  14. package/dist/adapters.d.ts +2 -0
  15. package/dist/adapters.js +4 -0
  16. package/dist/adapters.js.map +1 -1
  17. package/dist/components/ChartJSRenderer.cjs +165 -65
  18. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  19. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  20. package/dist/components/ChartJSRenderer.js +168 -68
  21. package/dist/components/ChartJSRenderer.js.map +1 -1
  22. package/dist/components/ComponentToolbar.cjs.map +1 -1
  23. package/dist/components/ComponentToolbar.d.ts.map +1 -1
  24. package/dist/components/ComponentToolbar.js.map +1 -1
  25. package/dist/components/EditableLayoutContext.cjs +17 -0
  26. package/dist/components/EditableLayoutContext.cjs.map +1 -0
  27. package/dist/components/EditableLayoutContext.d.ts +5 -0
  28. package/dist/components/EditableLayoutContext.d.ts.map +1 -0
  29. package/dist/components/EditableLayoutContext.js +17 -0
  30. package/dist/components/EditableLayoutContext.js.map +1 -0
  31. package/dist/components/EditableUIResourceRenderer.cjs +87 -84
  32. package/dist/components/EditableUIResourceRenderer.cjs.map +1 -1
  33. package/dist/components/EditableUIResourceRenderer.d.ts.map +1 -1
  34. package/dist/components/EditableUIResourceRenderer.js +87 -84
  35. package/dist/components/EditableUIResourceRenderer.js.map +1 -1
  36. package/dist/components/ElicitationForm.cjs.map +1 -1
  37. package/dist/components/ElicitationForm.js.map +1 -1
  38. package/dist/components/FeedbackInline.cjs +0 -1
  39. package/dist/components/FeedbackInline.cjs.map +1 -1
  40. package/dist/components/FeedbackInline.js +0 -1
  41. package/dist/components/FeedbackInline.js.map +1 -1
  42. package/dist/components/GraphRenderer.cjs.map +1 -1
  43. package/dist/components/GraphRenderer.d.ts.map +1 -1
  44. package/dist/components/GraphRenderer.js.map +1 -1
  45. package/dist/components/GridRenderer.cjs +12 -6
  46. package/dist/components/GridRenderer.cjs.map +1 -1
  47. package/dist/components/GridRenderer.d.ts.map +1 -1
  48. package/dist/components/GridRenderer.js +13 -7
  49. package/dist/components/GridRenderer.js.map +1 -1
  50. package/dist/components/MapRenderer.cjs.map +1 -1
  51. package/dist/components/MapRenderer.d.ts.map +1 -1
  52. package/dist/components/MapRenderer.js.map +1 -1
  53. package/dist/components/PresentationFeedback.cjs +0 -1
  54. package/dist/components/PresentationFeedback.cjs.map +1 -1
  55. package/dist/components/PresentationFeedback.js +0 -1
  56. package/dist/components/PresentationFeedback.js.map +1 -1
  57. package/dist/components/UIResourceRenderer.cjs +37 -22
  58. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  59. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  60. package/dist/components/UIResourceRenderer.js +38 -23
  61. package/dist/components/UIResourceRenderer.js.map +1 -1
  62. package/dist/components/VerifiedText.cjs +0 -4
  63. package/dist/components/VerifiedText.cjs.map +1 -1
  64. package/dist/components/VerifiedText.d.ts.map +1 -1
  65. package/dist/components/VerifiedText.js +0 -4
  66. package/dist/components/VerifiedText.js.map +1 -1
  67. package/dist/components/chart-data-table.cjs +73 -0
  68. package/dist/components/chart-data-table.cjs.map +1 -0
  69. package/dist/components/chart-data-table.d.ts +23 -0
  70. package/dist/components/chart-data-table.d.ts.map +1 -0
  71. package/dist/components/chart-data-table.js +73 -0
  72. package/dist/components/chart-data-table.js.map +1 -0
  73. package/dist/context/MCPUIStringsContext.cjs +10 -9
  74. package/dist/context/MCPUIStringsContext.cjs.map +1 -1
  75. package/dist/context/MCPUIStringsContext.d.ts +17 -5
  76. package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
  77. package/dist/context/MCPUIStringsContext.js +11 -10
  78. package/dist/context/MCPUIStringsContext.js.map +1 -1
  79. package/dist/hooks/createResponsiveGrid.cjs +37 -0
  80. package/dist/hooks/createResponsiveGrid.cjs.map +1 -0
  81. package/dist/hooks/createResponsiveGrid.d.ts +6 -0
  82. package/dist/hooks/createResponsiveGrid.d.ts.map +1 -0
  83. package/dist/hooks/createResponsiveGrid.js +37 -0
  84. package/dist/hooks/createResponsiveGrid.js.map +1 -0
  85. package/dist/index.cjs +1 -0
  86. package/dist/index.cjs.map +1 -1
  87. package/dist/index.js +1 -0
  88. package/dist/index.js.map +1 -1
  89. package/dist/mcp-ui-spec/dist/schemas.cjs +13 -1
  90. package/dist/mcp-ui-spec/dist/schemas.cjs.map +1 -1
  91. package/dist/mcp-ui-spec/dist/schemas.js +13 -1
  92. package/dist/mcp-ui-spec/dist/schemas.js.map +1 -1
  93. package/dist/services/chat-bus.cjs.map +1 -1
  94. package/dist/services/chat-bus.d.ts.map +1 -1
  95. package/dist/services/chat-bus.js.map +1 -1
  96. package/dist/services/chat-prompt-controller.cjs.map +1 -1
  97. package/dist/services/chat-prompt-controller.d.ts.map +1 -1
  98. package/dist/services/chat-prompt-controller.js.map +1 -1
  99. package/dist/services/component-registry.cjs +162 -22
  100. package/dist/services/component-registry.cjs.map +1 -1
  101. package/dist/services/component-registry.d.ts +6 -3
  102. package/dist/services/component-registry.d.ts.map +1 -1
  103. package/dist/services/component-registry.js +162 -22
  104. package/dist/services/component-registry.js.map +1 -1
  105. package/dist/services/telemetry.cjs +0 -1
  106. package/dist/services/telemetry.cjs.map +1 -1
  107. package/dist/services/telemetry.js +0 -1
  108. package/dist/services/telemetry.js.map +1 -1
  109. package/dist/services/validation.cjs +21 -7
  110. package/dist/services/validation.cjs.map +1 -1
  111. package/dist/services/validation.d.ts.map +1 -1
  112. package/dist/services/validation.js +21 -7
  113. package/dist/services/validation.js.map +1 -1
  114. package/dist/types/index.d.ts +43 -8
  115. package/dist/types/index.d.ts.map +1 -1
  116. package/dist/types.d.cts +43 -8
  117. package/dist/types.d.ts +43 -8
  118. package/docs/briefs/VISUALIZATION-FOUNDATION-2026-09-14.md +105 -0
  119. package/package.json +4 -4
  120. package/src/adapters/index.ts +18 -0
  121. package/src/adapters/presentation.test.ts +114 -0
  122. package/src/adapters/presentation.ts +229 -0
  123. package/src/components/ChartJSRenderer.test.tsx +325 -0
  124. package/src/components/ChartJSRenderer.tsx +162 -27
  125. package/src/components/ChatPrompt.test.tsx +1 -1
  126. package/src/components/ComponentToolbar.tsx +1 -1
  127. package/src/components/EditableLayoutContext.tsx +12 -0
  128. package/src/components/EditableUIResourceRenderer.tsx +11 -8
  129. package/src/components/ElicitationForm.tsx +1 -1
  130. package/src/components/FeedbackInline.tsx +1 -1
  131. package/src/components/GraphRenderer.test.tsx +1 -2
  132. package/src/components/GraphRenderer.tsx +0 -2
  133. package/src/components/GridRenderer.tsx +6 -4
  134. package/src/components/MapRenderer.tsx +0 -3
  135. package/src/components/PresentationFeedback.tsx +1 -1
  136. package/src/components/ResponsiveGrid.test.tsx +166 -0
  137. package/src/components/TableRenderer.pagination.test.tsx +31 -0
  138. package/src/components/UIResourceRenderer.tsx +14 -9
  139. package/src/components/VerifiedText.tsx +0 -5
  140. package/src/components/chart-data-table.ts +97 -0
  141. package/src/context/MCPUIStringsContext.test.tsx +60 -0
  142. package/src/context/MCPUIStringsContext.tsx +31 -12
  143. package/src/hooks/createResponsiveGrid.ts +41 -0
  144. package/src/services/chat-bus.test.ts +1 -1
  145. package/src/services/chat-bus.ts +0 -2
  146. package/src/services/chat-prompt-controller.ts +0 -8
  147. package/src/services/component-registry.test.ts +81 -2
  148. package/src/services/component-registry.ts +167 -23
  149. package/src/services/telemetry.ts +1 -1
  150. package/src/services/validation.test.ts +1 -14
  151. package/src/services/validation.ts +23 -6
  152. package/src/services/visualization-validation.test.ts +42 -0
  153. package/src/types/index.ts +50 -9
  154. package/src/types/visualization-contracts.test.ts +66 -0
  155. package/src/utils/perf.test.ts +3 -3
  156. package/tsconfig.tsbuildinfo +1 -1
@@ -14,10 +14,6 @@ function buildAnnotatedSegments(text, validation) {
14
14
  verifiedPositions.add(n.position);
15
15
  }
16
16
  }
17
- validation.llmNumbers.map((n) => ({
18
- position: n.position,
19
- length: n.context.length - 20
20
- })).sort((a, b) => a.position - b.position);
21
17
  const numberRegex = /\d[\d\s,.]*\d|\d+/g;
22
18
  const matches = [];
23
19
  let m;
@@ -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 // Build all number positions sorted\n const allPositions = validation.llmNumbers\n .map(n => ({ position: n.position, length: n.context.length - 20 })) // approximate original match length\n .sort((a, b) => a.position - b.position)\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","map","length","context","sort","a","b","numberRegex","matches","m","exec","push","start","index","end","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","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 [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 +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;AA8ED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,kCAsFpD"}
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"}
@@ -12,10 +12,6 @@ function buildAnnotatedSegments(text, validation) {
12
12
  verifiedPositions.add(n.position);
13
13
  }
14
14
  }
15
- validation.llmNumbers.map((n) => ({
16
- position: n.position,
17
- length: n.context.length - 20
18
- })).sort((a, b) => a.position - b.position);
19
15
  const numberRegex = /\d[\d\s,.]*\d|\d+/g;
20
16
  const matches = [];
21
17
  let m;
@@ -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 // Build all number positions sorted\n const allPositions = validation.llmNumbers\n .map(n => ({ position: n.position, length: n.context.length - 20 })) // approximate original match length\n .sort((a, b) => a.position - b.position)\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","map","length","context","sort","a","b","numberRegex","matches","m","exec","push","start","index","end","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","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 [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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"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ function tableCell(value) {
4
+ if (value == null) return "";
5
+ if (typeof value === "string" || typeof value === "number") return value;
6
+ if (typeof value === "boolean") return String(value);
7
+ try {
8
+ return JSON.stringify(value);
9
+ } catch {
10
+ return String(value);
11
+ }
12
+ }
13
+ function isPoint(value) {
14
+ return value !== null && typeof value === "object" && !Array.isArray(value) && ("x" in value || "y" in value || "r" in value);
15
+ }
16
+ function chartToDataTable(params) {
17
+ var _a, _b;
18
+ const datasets = ((_a = params.data) == null ? void 0 : _a.datasets) ?? [];
19
+ const labels = ((_b = params.data) == null ? void 0 : _b.labels) ?? [];
20
+ const pointData = params.type === "scatter" || params.type === "bubble" || datasets.some((dataset) => {
21
+ var _a2;
22
+ return (_a2 = dataset.data) == null ? void 0 : _a2.some(isPoint);
23
+ });
24
+ if (pointData) {
25
+ const hasLabels = labels.length > 0;
26
+ const hasRadius = params.type === "bubble" || datasets.some((dataset) => {
27
+ var _a2;
28
+ return (_a2 = dataset.data) == null ? void 0 : _a2.some((value) => isPoint(value) && "r" in value);
29
+ });
30
+ const columns2 = [
31
+ "Series",
32
+ "Point",
33
+ ...hasLabels ? ["Label"] : [],
34
+ "x",
35
+ "y",
36
+ ...hasRadius ? ["r"] : []
37
+ ];
38
+ const rows2 = [];
39
+ datasets.forEach((dataset, datasetIndex) => {
40
+ const series = dataset.label || `Series ${datasetIndex + 1}`;
41
+ (dataset.data ?? []).forEach((value, pointIndex) => {
42
+ const point = isPoint(value) ? value : { y: value };
43
+ rows2.push([
44
+ series,
45
+ pointIndex + 1,
46
+ ...hasLabels ? [tableCell(labels[pointIndex])] : [],
47
+ tableCell(point.x),
48
+ tableCell(point.y),
49
+ ...hasRadius ? [tableCell(point.r)] : []
50
+ ]);
51
+ });
52
+ });
53
+ return { columns: columns2, rows: rows2 };
54
+ }
55
+ const rowCount = Math.max(labels.length, ...datasets.map((dataset) => {
56
+ var _a2;
57
+ return ((_a2 = dataset.data) == null ? void 0 : _a2.length) ?? 0;
58
+ }), 0);
59
+ const columns = ["Label", ...datasets.map((dataset, index) => dataset.label || `Series ${index + 1}`)];
60
+ const rows = [];
61
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
62
+ rows.push([
63
+ tableCell(labels[rowIndex] ?? rowIndex + 1),
64
+ ...datasets.map((dataset) => {
65
+ var _a2;
66
+ return tableCell((_a2 = dataset.data) == null ? void 0 : _a2[rowIndex]);
67
+ })
68
+ ]);
69
+ }
70
+ return { columns, rows };
71
+ }
72
+ exports.chartToDataTable = chartToDataTable;
73
+ //# sourceMappingURL=chart-data-table.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-data-table.cjs","sources":["../../src/components/chart-data-table.ts"],"sourcesContent":["export interface ChartDataTable {\n columns: string[];\n rows: Array<Array<string | number>>;\n}\n\ninterface ChartDatasetLike {\n label?: string;\n data?: unknown[];\n}\n\nexport interface ChartDataLike {\n type?: string;\n data?: {\n labels?: Array<string | number>;\n datasets?: ChartDatasetLike[];\n };\n}\n\nfunction tableCell(value: unknown): string | number {\n if (value == null) return '';\n if (typeof value === 'string' || typeof value === 'number') return value;\n if (typeof value === 'boolean') return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction isPoint(value: unknown): value is Record<string, unknown> {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n ('x' in value || 'y' in value || 'r' in value)\n );\n}\n\n/**\n * Project Chart.js data into an accessible table without flattening point\n * coordinates. Categorical charts use a compact wide table; scatter, bubble,\n * and object-valued line charts use one row per point so x/y/r remain distinct.\n */\nexport function chartToDataTable(params: ChartDataLike): ChartDataTable {\n const datasets = params.data?.datasets ?? [];\n const labels = params.data?.labels ?? [];\n const pointData =\n params.type === 'scatter' ||\n params.type === 'bubble' ||\n datasets.some((dataset) => dataset.data?.some(isPoint));\n\n if (pointData) {\n const hasLabels = labels.length > 0;\n const hasRadius =\n params.type === 'bubble' ||\n datasets.some((dataset) => dataset.data?.some((value) => isPoint(value) && 'r' in value));\n const columns = [\n 'Series',\n 'Point',\n ...(hasLabels ? ['Label'] : []),\n 'x',\n 'y',\n ...(hasRadius ? ['r'] : []),\n ];\n const rows: Array<Array<string | number>> = [];\n\n datasets.forEach((dataset, datasetIndex) => {\n const series = dataset.label || `Series ${datasetIndex + 1}`;\n (dataset.data ?? []).forEach((value, pointIndex) => {\n const point = isPoint(value) ? value : { y: value };\n rows.push([\n series,\n pointIndex + 1,\n ...(hasLabels ? [tableCell(labels[pointIndex])] : []),\n tableCell(point.x),\n tableCell(point.y),\n ...(hasRadius ? [tableCell(point.r)] : []),\n ]);\n });\n });\n\n return { columns, rows };\n }\n\n const rowCount = Math.max(labels.length, ...datasets.map((dataset) => dataset.data?.length ?? 0), 0);\n const columns = ['Label', ...datasets.map((dataset, index) => dataset.label || `Series ${index + 1}`)];\n const rows: Array<Array<string | number>> = [];\n\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {\n rows.push([\n tableCell(labels[rowIndex] ?? rowIndex + 1),\n ...datasets.map((dataset) => tableCell(dataset.data?.[rowIndex])),\n ]);\n }\n\n return { columns, rows };\n}\n"],"names":["_a","columns","rows"],"mappings":";;AAkBA,SAAS,UAAU,OAAiC;AAClD,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,SAAU,QAAO;AACnE,MAAI,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AACnD,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAEA,SAAS,QAAQ,OAAkD;AACjE,SACE,UAAU,QACV,OAAO,UAAU,YACjB,CAAC,MAAM,QAAQ,KAAK,MACnB,OAAO,SAAS,OAAO,SAAS,OAAO;AAE5C;AAOO,SAAS,iBAAiB,QAAuC;;AACtE,QAAM,aAAW,YAAO,SAAP,mBAAa,aAAY,CAAA;AAC1C,QAAM,WAAS,YAAO,SAAP,mBAAa,WAAU,CAAA;AACtC,QAAM,YACJ,OAAO,SAAS,aAChB,OAAO,SAAS,YAChB,SAAS,KAAK,CAAC,YAAA;;AAAY,YAAAA,MAAA,QAAQ,SAAR,gBAAAA,IAAc,KAAK;AAAA,GAAQ;AAExD,MAAI,WAAW;AACb,UAAM,YAAY,OAAO,SAAS;AAClC,UAAM,YACJ,OAAO,SAAS,YAChB,SAAS,KAAK,CAAC,YAAA;;AAAY,cAAAA,MAAA,QAAQ,SAAR,gBAAAA,IAAc,KAAK,CAAC,UAAU,QAAQ,KAAK,KAAK,OAAO;AAAA,KAAM;AAC1F,UAAMC,WAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA,GAAI,YAAY,CAAC,OAAO,IAAI,CAAA;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,GAAI,YAAY,CAAC,GAAG,IAAI,CAAA;AAAA,IAAC;AAE3B,UAAMC,QAAsC,CAAA;AAE5C,aAAS,QAAQ,CAAC,SAAS,iBAAiB;AAC1C,YAAM,SAAS,QAAQ,SAAS,UAAU,eAAe,CAAC;AAC1D,OAAC,QAAQ,QAAQ,CAAA,GAAI,QAAQ,CAAC,OAAO,eAAe;AAClD,cAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,EAAE,GAAG,MAAA;AAC5CA,cAAK,KAAK;AAAA,UACR;AAAA,UACA,aAAa;AAAA,UACb,GAAI,YAAY,CAAC,UAAU,OAAO,UAAU,CAAC,CAAC,IAAI,CAAA;AAAA,UAClD,UAAU,MAAM,CAAC;AAAA,UACjB,UAAU,MAAM,CAAC;AAAA,UACjB,GAAI,YAAY,CAAC,UAAU,MAAM,CAAC,CAAC,IAAI,CAAA;AAAA,QAAC,CACzC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAED,WAAO,EAAE,SAAAD,UAAS,MAAAC,MAAAA;AAAAA,EACpB;AAEA,QAAM,WAAW,KAAK,IAAI,OAAO,QAAQ,GAAG,SAAS,IAAI,CAAC;;AAAY,aAAAF,MAAA,QAAQ,SAAR,gBAAAA,IAAc,WAAU;AAAA,GAAC,GAAG,CAAC;AACnG,QAAM,UAAU,CAAC,SAAS,GAAG,SAAS,IAAI,CAAC,SAAS,UAAU,QAAQ,SAAS,UAAU,QAAQ,CAAC,EAAE,CAAC;AACrG,QAAM,OAAsC,CAAA;AAE5C,WAAS,WAAW,GAAG,WAAW,UAAU,YAAY,GAAG;AACzD,SAAK,KAAK;AAAA,MACR,UAAU,OAAO,QAAQ,KAAK,WAAW,CAAC;AAAA,MAC1C,GAAG,SAAS,IAAI,CAAC,YAAA;;AAAY,0BAAUA,MAAA,QAAQ,SAAR,gBAAAA,IAAe,SAAS;AAAA,OAAC;AAAA,IAAA,CACjE;AAAA,EACH;AAEA,SAAO,EAAE,SAAS,KAAA;AACpB;;"}
@@ -0,0 +1,23 @@
1
+ export interface ChartDataTable {
2
+ columns: string[];
3
+ rows: Array<Array<string | number>>;
4
+ }
5
+ interface ChartDatasetLike {
6
+ label?: string;
7
+ data?: unknown[];
8
+ }
9
+ export interface ChartDataLike {
10
+ type?: string;
11
+ data?: {
12
+ labels?: Array<string | number>;
13
+ datasets?: ChartDatasetLike[];
14
+ };
15
+ }
16
+ /**
17
+ * Project Chart.js data into an accessible table without flattening point
18
+ * coordinates. Categorical charts use a compact wide table; scatter, bubble,
19
+ * and object-valued line charts use one row per point so x/y/r remain distinct.
20
+ */
21
+ export declare function chartToDataTable(params: ChartDataLike): ChartDataTable;
22
+ export {};
23
+ //# sourceMappingURL=chart-data-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-data-table.d.ts","sourceRoot":"","sources":["../../src/components/chart-data-table.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;CACrC;AAED,UAAU,gBAAgB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;KAC/B,CAAC;CACH;AAsBD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,CAqDtE"}
@@ -0,0 +1,73 @@
1
+ function tableCell(value) {
2
+ if (value == null) return "";
3
+ if (typeof value === "string" || typeof value === "number") return value;
4
+ if (typeof value === "boolean") return String(value);
5
+ try {
6
+ return JSON.stringify(value);
7
+ } catch {
8
+ return String(value);
9
+ }
10
+ }
11
+ function isPoint(value) {
12
+ return value !== null && typeof value === "object" && !Array.isArray(value) && ("x" in value || "y" in value || "r" in value);
13
+ }
14
+ function chartToDataTable(params) {
15
+ var _a, _b;
16
+ const datasets = ((_a = params.data) == null ? void 0 : _a.datasets) ?? [];
17
+ const labels = ((_b = params.data) == null ? void 0 : _b.labels) ?? [];
18
+ const pointData = params.type === "scatter" || params.type === "bubble" || datasets.some((dataset) => {
19
+ var _a2;
20
+ return (_a2 = dataset.data) == null ? void 0 : _a2.some(isPoint);
21
+ });
22
+ if (pointData) {
23
+ const hasLabels = labels.length > 0;
24
+ const hasRadius = params.type === "bubble" || datasets.some((dataset) => {
25
+ var _a2;
26
+ return (_a2 = dataset.data) == null ? void 0 : _a2.some((value) => isPoint(value) && "r" in value);
27
+ });
28
+ const columns2 = [
29
+ "Series",
30
+ "Point",
31
+ ...hasLabels ? ["Label"] : [],
32
+ "x",
33
+ "y",
34
+ ...hasRadius ? ["r"] : []
35
+ ];
36
+ const rows2 = [];
37
+ datasets.forEach((dataset, datasetIndex) => {
38
+ const series = dataset.label || `Series ${datasetIndex + 1}`;
39
+ (dataset.data ?? []).forEach((value, pointIndex) => {
40
+ const point = isPoint(value) ? value : { y: value };
41
+ rows2.push([
42
+ series,
43
+ pointIndex + 1,
44
+ ...hasLabels ? [tableCell(labels[pointIndex])] : [],
45
+ tableCell(point.x),
46
+ tableCell(point.y),
47
+ ...hasRadius ? [tableCell(point.r)] : []
48
+ ]);
49
+ });
50
+ });
51
+ return { columns: columns2, rows: rows2 };
52
+ }
53
+ const rowCount = Math.max(labels.length, ...datasets.map((dataset) => {
54
+ var _a2;
55
+ return ((_a2 = dataset.data) == null ? void 0 : _a2.length) ?? 0;
56
+ }), 0);
57
+ const columns = ["Label", ...datasets.map((dataset, index) => dataset.label || `Series ${index + 1}`)];
58
+ const rows = [];
59
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
60
+ rows.push([
61
+ tableCell(labels[rowIndex] ?? rowIndex + 1),
62
+ ...datasets.map((dataset) => {
63
+ var _a2;
64
+ return tableCell((_a2 = dataset.data) == null ? void 0 : _a2[rowIndex]);
65
+ })
66
+ ]);
67
+ }
68
+ return { columns, rows };
69
+ }
70
+ export {
71
+ chartToDataTable
72
+ };
73
+ //# sourceMappingURL=chart-data-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-data-table.js","sources":["../../src/components/chart-data-table.ts"],"sourcesContent":["export interface ChartDataTable {\n columns: string[];\n rows: Array<Array<string | number>>;\n}\n\ninterface ChartDatasetLike {\n label?: string;\n data?: unknown[];\n}\n\nexport interface ChartDataLike {\n type?: string;\n data?: {\n labels?: Array<string | number>;\n datasets?: ChartDatasetLike[];\n };\n}\n\nfunction tableCell(value: unknown): string | number {\n if (value == null) return '';\n if (typeof value === 'string' || typeof value === 'number') return value;\n if (typeof value === 'boolean') return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction isPoint(value: unknown): value is Record<string, unknown> {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n ('x' in value || 'y' in value || 'r' in value)\n );\n}\n\n/**\n * Project Chart.js data into an accessible table without flattening point\n * coordinates. Categorical charts use a compact wide table; scatter, bubble,\n * and object-valued line charts use one row per point so x/y/r remain distinct.\n */\nexport function chartToDataTable(params: ChartDataLike): ChartDataTable {\n const datasets = params.data?.datasets ?? [];\n const labels = params.data?.labels ?? [];\n const pointData =\n params.type === 'scatter' ||\n params.type === 'bubble' ||\n datasets.some((dataset) => dataset.data?.some(isPoint));\n\n if (pointData) {\n const hasLabels = labels.length > 0;\n const hasRadius =\n params.type === 'bubble' ||\n datasets.some((dataset) => dataset.data?.some((value) => isPoint(value) && 'r' in value));\n const columns = [\n 'Series',\n 'Point',\n ...(hasLabels ? ['Label'] : []),\n 'x',\n 'y',\n ...(hasRadius ? ['r'] : []),\n ];\n const rows: Array<Array<string | number>> = [];\n\n datasets.forEach((dataset, datasetIndex) => {\n const series = dataset.label || `Series ${datasetIndex + 1}`;\n (dataset.data ?? []).forEach((value, pointIndex) => {\n const point = isPoint(value) ? value : { y: value };\n rows.push([\n series,\n pointIndex + 1,\n ...(hasLabels ? [tableCell(labels[pointIndex])] : []),\n tableCell(point.x),\n tableCell(point.y),\n ...(hasRadius ? [tableCell(point.r)] : []),\n ]);\n });\n });\n\n return { columns, rows };\n }\n\n const rowCount = Math.max(labels.length, ...datasets.map((dataset) => dataset.data?.length ?? 0), 0);\n const columns = ['Label', ...datasets.map((dataset, index) => dataset.label || `Series ${index + 1}`)];\n const rows: Array<Array<string | number>> = [];\n\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {\n rows.push([\n tableCell(labels[rowIndex] ?? rowIndex + 1),\n ...datasets.map((dataset) => tableCell(dataset.data?.[rowIndex])),\n ]);\n }\n\n return { columns, rows };\n}\n"],"names":["_a","columns","rows"],"mappings":"AAkBA,SAAS,UAAU,OAAiC;AAClD,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,SAAU,QAAO;AACnE,MAAI,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AACnD,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAEA,SAAS,QAAQ,OAAkD;AACjE,SACE,UAAU,QACV,OAAO,UAAU,YACjB,CAAC,MAAM,QAAQ,KAAK,MACnB,OAAO,SAAS,OAAO,SAAS,OAAO;AAE5C;AAOO,SAAS,iBAAiB,QAAuC;AAzBxE;AA0BE,QAAM,aAAW,YAAO,SAAP,mBAAa,aAAY,CAAA;AAC1C,QAAM,WAAS,YAAO,SAAP,mBAAa,WAAU,CAAA;AACtC,QAAM,YACJ,OAAO,SAAS,aAChB,OAAO,SAAS,YAChB,SAAS,KAAK,CAAC,YAAA;AA/BnB,QAAAA;AA+B+B,YAAAA,MAAA,QAAQ,SAAR,gBAAAA,IAAc,KAAK;AAAA,GAAQ;AAExD,MAAI,WAAW;AACb,UAAM,YAAY,OAAO,SAAS;AAClC,UAAM,YACJ,OAAO,SAAS,YAChB,SAAS,KAAK,CAAC,YAAA;AArCrB,UAAAA;AAqCiC,cAAAA,MAAA,QAAQ,SAAR,gBAAAA,IAAc,KAAK,CAAC,UAAU,QAAQ,KAAK,KAAK,OAAO;AAAA,KAAM;AAC1F,UAAMC,WAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA,GAAI,YAAY,CAAC,OAAO,IAAI,CAAA;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,GAAI,YAAY,CAAC,GAAG,IAAI,CAAA;AAAA,IAAC;AAE3B,UAAMC,QAAsC,CAAA;AAE5C,aAAS,QAAQ,CAAC,SAAS,iBAAiB;AAC1C,YAAM,SAAS,QAAQ,SAAS,UAAU,eAAe,CAAC;AAC1D,OAAC,QAAQ,QAAQ,CAAA,GAAI,QAAQ,CAAC,OAAO,eAAe;AAClD,cAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,EAAE,GAAG,MAAA;AAC5CA,cAAK,KAAK;AAAA,UACR;AAAA,UACA,aAAa;AAAA,UACb,GAAI,YAAY,CAAC,UAAU,OAAO,UAAU,CAAC,CAAC,IAAI,CAAA;AAAA,UAClD,UAAU,MAAM,CAAC;AAAA,UACjB,UAAU,MAAM,CAAC;AAAA,UACjB,GAAI,YAAY,CAAC,UAAU,MAAM,CAAC,CAAC,IAAI,CAAA;AAAA,QAAC,CACzC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAED,WAAO,EAAE,SAAAD,UAAS,MAAAC,MAAAA;AAAAA,EACpB;AAEA,QAAM,WAAW,KAAK,IAAI,OAAO,QAAQ,GAAG,SAAS,IAAI,CAAC;AAlE5D,QAAAF;AAkEwE,aAAAA,MAAA,QAAQ,SAAR,gBAAAA,IAAc,WAAU;AAAA,GAAC,GAAG,CAAC;AACnG,QAAM,UAAU,CAAC,SAAS,GAAG,SAAS,IAAI,CAAC,SAAS,UAAU,QAAQ,SAAS,UAAU,QAAQ,CAAC,EAAE,CAAC;AACrG,QAAM,OAAsC,CAAA;AAE5C,WAAS,WAAW,GAAG,WAAW,UAAU,YAAY,GAAG;AACzD,SAAK,KAAK;AAAA,MACR,UAAU,OAAO,QAAQ,KAAK,WAAW,CAAC;AAAA,MAC1C,GAAG,SAAS,IAAI,CAAC,YAAA;AAzEvB,YAAAA;AAyEmC,0BAAUA,MAAA,QAAQ,SAAR,gBAAAA,IAAe,SAAS;AAAA,OAAC;AAAA,IAAA,CACjE;AAAA,EACH;AAEA,SAAO,EAAE,SAAS,KAAA;AACpB;"}
@@ -11,21 +11,22 @@ const DEFAULT_MCPUI_STRINGS = {
11
11
  feedbackNotUseful: "Not useful",
12
12
  feedbackPositiveAck: "Thanks!",
13
13
  feedbackNegativeAck: "Noted — we'll improve",
14
- retry: "Retry"
14
+ retry: "Retry",
15
+ chartView: "Chart",
16
+ chartDataView: "Data",
17
+ chartViewSelector: "Chart or data view",
18
+ chartDataTable: "Chart data",
19
+ chartDataSummary: "Exact values are available in the data view.",
20
+ chartNoData: "No chart data"
15
21
  };
16
22
  const MCPUIStringsContext = solidJs.createContext(DEFAULT_MCPUI_STRINGS);
17
23
  function useMCPUIStrings() {
18
- return solidJs.useContext(MCPUIStringsContext);
24
+ return solidJs.mergeProps(DEFAULT_MCPUI_STRINGS, solidJs.useContext(MCPUIStringsContext));
19
25
  }
20
26
  function MCPUIStringsProvider(props) {
21
- const value = () => ({
22
- ...DEFAULT_MCPUI_STRINGS,
23
- ...props.strings
24
- });
27
+ const value = solidJs.mergeProps(DEFAULT_MCPUI_STRINGS, () => props.strings);
25
28
  return web.createComponent(MCPUIStringsContext.Provider, {
26
- get value() {
27
- return value();
28
- },
29
+ value,
29
30
  get children() {
30
31
  return props.children;
31
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MCPUIStringsContext.cjs","sources":["../../src/context/MCPUIStringsContext.tsx"],"sourcesContent":["/**\n * MCPUIStringsContext — i18n for the library's own \"chrome\" strings.\n *\n * @since v6.6.0 (D2 / R4 of ROADMAP-opendata-macro-mcpui)\n *\n * ## Scope — chrome only, NOT content\n *\n * MCP-UI renders two kinds of text :\n *\n * - **Content** — table headers, chart titles, action labels, prompt\n * questions. These come from the payload and are ALREADY localized by\n * whoever produced the payload (the connector / MCP server). MCP-UI\n * renders them verbatim and this context never touches them.\n * - **Chrome** — the handful of strings the library itself hardcodes :\n * the expand-button tooltip, the feedback acknowledgements, etc. THIS\n * is what `MCPUIStrings` covers.\n *\n * There is deliberately no full i18n framework here : no per-renderer\n * `locale` prop, no message catalogue, no ICU. A flat string map behind a\n * context is enough — the chrome surface is small and static.\n *\n * ## Defaults are English\n *\n * `DEFAULT_MCPUI_STRINGS` is English. A published library should not ship\n * hardcoded French. Consumers that want another language wrap their tree\n * in `<MCPUIStringsProvider strings={...}>` with a partial override.\n *\n * Component props that already carry a label (e.g. `FeedbackInline`'s\n * `positiveAck`, `ExpandableWrapper`'s `copyLabel`) keep priority over the\n * provider — the provider only fills the gap when no explicit prop is set.\n *\n * @example\n * ```tsx\n * import { MCPUIStringsProvider } from '@seed-ship/mcp-ui-solid'\n *\n * <MCPUIStringsProvider strings={{ expand: 'Agrandir', feedbackUseful: 'Utile' }}>\n * <App />\n * </MCPUIStringsProvider>\n * ```\n */\n\nimport { createContext, useContext, type JSX } from 'solid-js'\n\n/**\n * The library's own chrome strings. Flat map, no interpolation.\n *\n * Marked exhaustive as of v6.6.0 ; new chrome strings added by later\n * renderers extend this interface (the `MCPUIStringsProvider` merge keeps\n * older consumers working — any unset key falls back to the EN default).\n */\nexport interface MCPUIStrings {\n // ── ExpandableWrapper toolbar ──────────────────────────────\n /** `title` of the expand-to-fullscreen button. */\n expand: string\n /** Heading + `aria-label` of the fullscreen modal when no title is given. */\n expandedView: string\n /** Default tooltip of the copy button (overridden by `copyLabel` prop). */\n copyToClipboard: string\n /** `aria-label` of the close button in the fullscreen modal. */\n closeExpandedView: string\n\n // ── FeedbackInline (response-quality feedback) ─────────────\n /** `title` of the thumb-up button. */\n feedbackUseful: string\n /** `title` of the thumb-down button. */\n feedbackNotUseful: string\n /** Acknowledgement shown after a positive rating (overridden by `positiveAck`). */\n feedbackPositiveAck: string\n /** Acknowledgement shown after a negative rating (overridden by `negativeAck`). */\n feedbackNegativeAck: string\n\n // ── Generic chrome ────────────────────────────────────────\n /** Label of the streaming retry button. */\n retry: string\n}\n\n/**\n * English defaults. A published library ships no hardcoded non-English\n * chrome — consumers localize via `<MCPUIStringsProvider>`.\n */\nexport const DEFAULT_MCPUI_STRINGS: MCPUIStrings = {\n expand: 'Expand',\n expandedView: 'Expanded view',\n copyToClipboard: 'Copy to clipboard',\n closeExpandedView: 'Close expanded view',\n feedbackUseful: 'Useful',\n feedbackNotUseful: 'Not useful',\n feedbackPositiveAck: 'Thanks!',\n feedbackNegativeAck: \"Noted — we'll improve\",\n retry: 'Retry',\n}\n\nexport const MCPUIStringsContext = createContext<MCPUIStrings>(DEFAULT_MCPUI_STRINGS)\n\n/**\n * Reads the active chrome strings. Returns `DEFAULT_MCPUI_STRINGS` when no\n * `<MCPUIStringsProvider>` is mounted above — every renderer works\n * standalone with English chrome.\n */\nexport function useMCPUIStrings(): MCPUIStrings {\n return useContext(MCPUIStringsContext)\n}\n\nexport interface MCPUIStringsProviderProps {\n /**\n * Partial override of the chrome strings. Any key left unset falls back\n * to the English `DEFAULT_MCPUI_STRINGS` — so a consumer can localize\n * just the strings they care about.\n */\n strings?: Partial<MCPUIStrings>\n children: JSX.Element\n}\n\n/**\n * Provides localized chrome strings to every MCP-UI renderer below it.\n * Merges the partial `strings` override over the English defaults.\n */\nexport function MCPUIStringsProvider(props: MCPUIStringsProviderProps): JSX.Element {\n // `props.strings` is read inside the getter so a reactive override\n // (signal-backed) re-propagates ; for the common static case it is read\n // once at mount.\n const value = (): MCPUIStrings => ({ ...DEFAULT_MCPUI_STRINGS, ...props.strings })\n return (\n <MCPUIStringsContext.Provider value={value()}>\n {props.children}\n </MCPUIStringsContext.Provider>\n )\n}\n"],"names":["DEFAULT_MCPUI_STRINGS","expand","expandedView","copyToClipboard","closeExpandedView","feedbackUseful","feedbackNotUseful","feedbackPositiveAck","feedbackNegativeAck","retry","MCPUIStringsContext","createContext","useMCPUIStrings","useContext","MCPUIStringsProvider","props","value","strings","_$createComponent","Provider","children"],"mappings":";;;;AAgFO,MAAMA,wBAAsC;AAAA,EACjDC,QAAQ;AAAA,EACRC,cAAc;AAAA,EACdC,iBAAiB;AAAA,EACjBC,mBAAmB;AAAA,EACnBC,gBAAgB;AAAA,EAChBC,mBAAmB;AAAA,EACnBC,qBAAqB;AAAA,EACrBC,qBAAqB;AAAA,EACrBC,OAAO;AACT;AAEO,MAAMC,sBAAsBC,QAAAA,cAA4BX,qBAAqB;AAO7E,SAASY,kBAAgC;AAC9C,SAAOC,QAAAA,WAAWH,mBAAmB;AACvC;AAgBO,SAASI,qBAAqBC,OAA+C;AAIlF,QAAMC,QAAQA,OAAqB;AAAA,IAAE,GAAGhB;AAAAA,IAAuB,GAAGe,MAAME;AAAAA,EAAAA;AACxE,SAAAC,IAAAA,gBACGR,oBAAoBS,UAAQ;AAAA,IAAA,IAACH,QAAK;AAAA,aAAEA,MAAAA;AAAAA,IAAO;AAAA,IAAA,IAAAI,WAAA;AAAA,aACzCL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;;;;;"}
1
+ {"version":3,"file":"MCPUIStringsContext.cjs","sources":["../../src/context/MCPUIStringsContext.tsx"],"sourcesContent":["/**\n * MCPUIStringsContext — i18n for the library's own \"chrome\" strings.\n *\n * @since v6.6.0 (D2 / R4 of ROADMAP-opendata-macro-mcpui)\n *\n * ## Scope — chrome only, NOT content\n *\n * MCP-UI renders two kinds of text :\n *\n * - **Content** — table headers, chart titles, action labels, prompt\n * questions. These come from the payload and are ALREADY localized by\n * whoever produced the payload (the connector / MCP server). MCP-UI\n * renders them verbatim and this context never touches them.\n * - **Chrome** — the handful of strings the library itself hardcodes :\n * the expand-button tooltip, the feedback acknowledgements, etc. THIS\n * is what `MCPUIStrings` covers.\n *\n * There is deliberately no full i18n framework here : no per-renderer\n * `locale` prop, no message catalogue, no ICU. A flat string map behind a\n * context is enough — the chrome surface is small and static.\n *\n * ## Defaults are English\n *\n * `DEFAULT_MCPUI_STRINGS` is English. A published library should not ship\n * hardcoded French. Consumers that want another language wrap their tree\n * in `<MCPUIStringsProvider strings={...}>` with a partial override.\n *\n * Component props that already carry a label (e.g. `FeedbackInline`'s\n * `positiveAck`, `ExpandableWrapper`'s `copyLabel`) keep priority over the\n * provider — the provider only fills the gap when no explicit prop is set.\n *\n * @example\n * ```tsx\n * import { MCPUIStringsProvider } from '@seed-ship/mcp-ui-solid'\n *\n * <MCPUIStringsProvider strings={{ expand: 'Agrandir', feedbackUseful: 'Utile' }}>\n * <App />\n * </MCPUIStringsProvider>\n * ```\n */\n\nimport { createContext, mergeProps, useContext, type JSX } from 'solid-js'\n\n/**\n * The library's own chrome strings. Flat map, no interpolation.\n *\n * The original chrome keys remain required. Later additions are optional\n * so existing typed dictionaries remain valid across minor releases.\n * `useMCPUIStrings` resolves omitted keys to their English defaults.\n */\nexport interface MCPUIStrings {\n // ── ExpandableWrapper toolbar ──────────────────────────────\n /** `title` of the expand-to-fullscreen button. */\n expand: string\n /** Heading + `aria-label` of the fullscreen modal when no title is given. */\n expandedView: string\n /** Default tooltip of the copy button (overridden by `copyLabel` prop). */\n copyToClipboard: string\n /** `aria-label` of the close button in the fullscreen modal. */\n closeExpandedView: string\n\n // ── FeedbackInline (response-quality feedback) ─────────────\n /** `title` of the thumb-up button. */\n feedbackUseful: string\n /** `title` of the thumb-down button. */\n feedbackNotUseful: string\n /** Acknowledgement shown after a positive rating (overridden by `positiveAck`). */\n feedbackPositiveAck: string\n /** Acknowledgement shown after a negative rating (overridden by `negativeAck`). */\n feedbackNegativeAck: string\n\n // ── Generic chrome ────────────────────────────────────────\n /** Label of the streaming retry button. */\n retry: string\n\n // ── Chart data access ─────────────────────────────────────\n /** Label of the native chart view button. */\n chartView?: string\n /** Label of the exact-data table view button. */\n chartDataView?: string\n /** Accessible name of the chart/data view selector. */\n chartViewSelector?: string\n /** Caption and accessible name for the chart's data table. */\n chartDataTable?: string\n /** Screen-reader description associated with the chart canvas. */\n chartDataSummary?: string\n /** Empty state shown when a chart has no data points. */\n chartNoData?: string\n}\n\n/**\n * English defaults. A published library ships no hardcoded non-English\n * chrome — consumers localize via `<MCPUIStringsProvider>`.\n */\nexport const DEFAULT_MCPUI_STRINGS: Required<MCPUIStrings> = {\n expand: 'Expand',\n expandedView: 'Expanded view',\n copyToClipboard: 'Copy to clipboard',\n closeExpandedView: 'Close expanded view',\n feedbackUseful: 'Useful',\n feedbackNotUseful: 'Not useful',\n feedbackPositiveAck: 'Thanks!',\n feedbackNegativeAck: \"Noted — we'll improve\",\n retry: 'Retry',\n chartView: 'Chart',\n chartDataView: 'Data',\n chartViewSelector: 'Chart or data view',\n chartDataTable: 'Chart data',\n chartDataSummary: 'Exact values are available in the data view.',\n chartNoData: 'No chart data',\n}\n\nexport const MCPUIStringsContext = createContext<MCPUIStrings>(DEFAULT_MCPUI_STRINGS)\n\n/**\n * Reads the active chrome strings. Returns `DEFAULT_MCPUI_STRINGS` when no\n * `<MCPUIStringsProvider>` is mounted above — every renderer works\n * standalone with English chrome.\n */\nexport function useMCPUIStrings(): Required<MCPUIStrings> {\n return mergeProps(DEFAULT_MCPUI_STRINGS, useContext(MCPUIStringsContext))\n}\n\nexport interface MCPUIStringsProviderProps {\n /**\n * Partial override of the chrome strings. Any key left unset falls back\n * to the English `DEFAULT_MCPUI_STRINGS` — so a consumer can localize\n * just the strings they care about.\n */\n strings?: Partial<MCPUIStrings>\n children: JSX.Element\n}\n\n/**\n * Provides localized chrome strings to every MCP-UI renderer below it.\n * Merges the partial `strings` override over the English defaults.\n */\nexport function MCPUIStringsProvider(props: MCPUIStringsProviderProps): JSX.Element {\n // The function source keeps replacement `strings` objects reactive while\n // mergeProps fills any omitted key without taking a one-time snapshot.\n const value = mergeProps(DEFAULT_MCPUI_STRINGS, () => props.strings)\n return (\n <MCPUIStringsContext.Provider value={value}>\n {props.children}\n </MCPUIStringsContext.Provider>\n )\n}\n"],"names":["DEFAULT_MCPUI_STRINGS","expand","expandedView","copyToClipboard","closeExpandedView","feedbackUseful","feedbackNotUseful","feedbackPositiveAck","feedbackNegativeAck","retry","chartView","chartDataView","chartViewSelector","chartDataTable","chartDataSummary","chartNoData","MCPUIStringsContext","createContext","useMCPUIStrings","mergeProps","useContext","MCPUIStringsProvider","props","value","strings","_$createComponent","Provider","children"],"mappings":";;;;AA8FO,MAAMA,wBAAgD;AAAA,EAC3DC,QAAQ;AAAA,EACRC,cAAc;AAAA,EACdC,iBAAiB;AAAA,EACjBC,mBAAmB;AAAA,EACnBC,gBAAgB;AAAA,EAChBC,mBAAmB;AAAA,EACnBC,qBAAqB;AAAA,EACrBC,qBAAqB;AAAA,EACrBC,OAAO;AAAA,EACPC,WAAW;AAAA,EACXC,eAAe;AAAA,EACfC,mBAAmB;AAAA,EACnBC,gBAAgB;AAAA,EAChBC,kBAAkB;AAAA,EAClBC,aAAa;AACf;AAEO,MAAMC,sBAAsBC,QAAAA,cAA4BjB,qBAAqB;AAO7E,SAASkB,kBAA0C;AACxD,SAAOC,mBAAWnB,uBAAuBoB,QAAAA,WAAWJ,mBAAmB,CAAC;AAC1E;AAgBO,SAASK,qBAAqBC,OAA+C;AAGlF,QAAMC,QAAQJ,QAAAA,WAAWnB,uBAAuB,MAAMsB,MAAME,OAAO;AACnE,SAAAC,IAAAA,gBACGT,oBAAoBU,UAAQ;AAAA,IAACH;AAAAA,IAAY,IAAAI,WAAA;AAAA,aACvCL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;;;;;"}
@@ -42,9 +42,9 @@ import { type JSX } from 'solid-js';
42
42
  /**
43
43
  * The library's own chrome strings. Flat map, no interpolation.
44
44
  *
45
- * Marked exhaustive as of v6.6.0 ; new chrome strings added by later
46
- * renderers extend this interface (the `MCPUIStringsProvider` merge keeps
47
- * older consumers working — any unset key falls back to the EN default).
45
+ * The original chrome keys remain required. Later additions are optional
46
+ * so existing typed dictionaries remain valid across minor releases.
47
+ * `useMCPUIStrings` resolves omitted keys to their English defaults.
48
48
  */
49
49
  export interface MCPUIStrings {
50
50
  /** `title` of the expand-to-fullscreen button. */
@@ -65,19 +65,31 @@ export interface MCPUIStrings {
65
65
  feedbackNegativeAck: string;
66
66
  /** Label of the streaming retry button. */
67
67
  retry: string;
68
+ /** Label of the native chart view button. */
69
+ chartView?: string;
70
+ /** Label of the exact-data table view button. */
71
+ chartDataView?: string;
72
+ /** Accessible name of the chart/data view selector. */
73
+ chartViewSelector?: string;
74
+ /** Caption and accessible name for the chart's data table. */
75
+ chartDataTable?: string;
76
+ /** Screen-reader description associated with the chart canvas. */
77
+ chartDataSummary?: string;
78
+ /** Empty state shown when a chart has no data points. */
79
+ chartNoData?: string;
68
80
  }
69
81
  /**
70
82
  * English defaults. A published library ships no hardcoded non-English
71
83
  * chrome — consumers localize via `<MCPUIStringsProvider>`.
72
84
  */
73
- export declare const DEFAULT_MCPUI_STRINGS: MCPUIStrings;
85
+ export declare const DEFAULT_MCPUI_STRINGS: Required<MCPUIStrings>;
74
86
  export declare const MCPUIStringsContext: import("solid-js").Context<MCPUIStrings>;
75
87
  /**
76
88
  * Reads the active chrome strings. Returns `DEFAULT_MCPUI_STRINGS` when no
77
89
  * `<MCPUIStringsProvider>` is mounted above — every renderer works
78
90
  * standalone with English chrome.
79
91
  */
80
- export declare function useMCPUIStrings(): MCPUIStrings;
92
+ export declare function useMCPUIStrings(): Required<MCPUIStrings>;
81
93
  export interface MCPUIStringsProviderProps {
82
94
  /**
83
95
  * Partial override of the chrome strings. Any key left unset falls back
@@ -1 +1 @@
1
- {"version":3,"file":"MCPUIStringsContext.d.ts","sourceRoot":"","sources":["../../src/context/MCPUIStringsContext.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAA6B,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAE9D;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAE3B,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAA;IACpB,2EAA2E;IAC3E,eAAe,EAAE,MAAM,CAAA;IACvB,gEAAgE;IAChE,iBAAiB,EAAE,MAAM,CAAA;IAGzB,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAA;IACtB,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,mBAAmB,EAAE,MAAM,CAAA;IAC3B,mFAAmF;IACnF,mBAAmB,EAAE,MAAM,CAAA;IAG3B,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,YAUnC,CAAA;AAED,eAAO,MAAM,mBAAmB,0CAAqD,CAAA;AAErF;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;IAC/B,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,GAAG,CAAC,OAAO,CAUlF"}
1
+ {"version":3,"file":"MCPUIStringsContext.d.ts","sourceRoot":"","sources":["../../src/context/MCPUIStringsContext.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAyC,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAE1E;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAE3B,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAA;IACpB,2EAA2E;IAC3E,eAAe,EAAE,MAAM,CAAA;IACvB,gEAAgE;IAChE,iBAAiB,EAAE,MAAM,CAAA;IAGzB,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAA;IACtB,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,mBAAmB,EAAE,MAAM,CAAA;IAC3B,mFAAmF;IACnF,mBAAmB,EAAE,MAAM,CAAA;IAG3B,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAA;IAGb,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,8DAA8D;IAC9D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,YAAY,CAgBxD,CAAA;AAED,eAAO,MAAM,mBAAmB,0CAAqD,CAAA;AAErF;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,QAAQ,CAAC,YAAY,CAAC,CAExD;AAED,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;IAC/B,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,GAAG,CAAC,OAAO,CASlF"}
@@ -1,5 +1,5 @@
1
1
  import { createComponent } from "solid-js/web";
2
- import { createContext, useContext } from "solid-js";
2
+ import { createContext, mergeProps, useContext } from "solid-js";
3
3
  const DEFAULT_MCPUI_STRINGS = {
4
4
  expand: "Expand",
5
5
  expandedView: "Expanded view",
@@ -9,21 +9,22 @@ const DEFAULT_MCPUI_STRINGS = {
9
9
  feedbackNotUseful: "Not useful",
10
10
  feedbackPositiveAck: "Thanks!",
11
11
  feedbackNegativeAck: "Noted — we'll improve",
12
- retry: "Retry"
12
+ retry: "Retry",
13
+ chartView: "Chart",
14
+ chartDataView: "Data",
15
+ chartViewSelector: "Chart or data view",
16
+ chartDataTable: "Chart data",
17
+ chartDataSummary: "Exact values are available in the data view.",
18
+ chartNoData: "No chart data"
13
19
  };
14
20
  const MCPUIStringsContext = createContext(DEFAULT_MCPUI_STRINGS);
15
21
  function useMCPUIStrings() {
16
- return useContext(MCPUIStringsContext);
22
+ return mergeProps(DEFAULT_MCPUI_STRINGS, useContext(MCPUIStringsContext));
17
23
  }
18
24
  function MCPUIStringsProvider(props) {
19
- const value = () => ({
20
- ...DEFAULT_MCPUI_STRINGS,
21
- ...props.strings
22
- });
25
+ const value = mergeProps(DEFAULT_MCPUI_STRINGS, () => props.strings);
23
26
  return createComponent(MCPUIStringsContext.Provider, {
24
- get value() {
25
- return value();
26
- },
27
+ value,
27
28
  get children() {
28
29
  return props.children;
29
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MCPUIStringsContext.js","sources":["../../src/context/MCPUIStringsContext.tsx"],"sourcesContent":["/**\n * MCPUIStringsContext — i18n for the library's own \"chrome\" strings.\n *\n * @since v6.6.0 (D2 / R4 of ROADMAP-opendata-macro-mcpui)\n *\n * ## Scope — chrome only, NOT content\n *\n * MCP-UI renders two kinds of text :\n *\n * - **Content** — table headers, chart titles, action labels, prompt\n * questions. These come from the payload and are ALREADY localized by\n * whoever produced the payload (the connector / MCP server). MCP-UI\n * renders them verbatim and this context never touches them.\n * - **Chrome** — the handful of strings the library itself hardcodes :\n * the expand-button tooltip, the feedback acknowledgements, etc. THIS\n * is what `MCPUIStrings` covers.\n *\n * There is deliberately no full i18n framework here : no per-renderer\n * `locale` prop, no message catalogue, no ICU. A flat string map behind a\n * context is enough — the chrome surface is small and static.\n *\n * ## Defaults are English\n *\n * `DEFAULT_MCPUI_STRINGS` is English. A published library should not ship\n * hardcoded French. Consumers that want another language wrap their tree\n * in `<MCPUIStringsProvider strings={...}>` with a partial override.\n *\n * Component props that already carry a label (e.g. `FeedbackInline`'s\n * `positiveAck`, `ExpandableWrapper`'s `copyLabel`) keep priority over the\n * provider — the provider only fills the gap when no explicit prop is set.\n *\n * @example\n * ```tsx\n * import { MCPUIStringsProvider } from '@seed-ship/mcp-ui-solid'\n *\n * <MCPUIStringsProvider strings={{ expand: 'Agrandir', feedbackUseful: 'Utile' }}>\n * <App />\n * </MCPUIStringsProvider>\n * ```\n */\n\nimport { createContext, useContext, type JSX } from 'solid-js'\n\n/**\n * The library's own chrome strings. Flat map, no interpolation.\n *\n * Marked exhaustive as of v6.6.0 ; new chrome strings added by later\n * renderers extend this interface (the `MCPUIStringsProvider` merge keeps\n * older consumers working — any unset key falls back to the EN default).\n */\nexport interface MCPUIStrings {\n // ── ExpandableWrapper toolbar ──────────────────────────────\n /** `title` of the expand-to-fullscreen button. */\n expand: string\n /** Heading + `aria-label` of the fullscreen modal when no title is given. */\n expandedView: string\n /** Default tooltip of the copy button (overridden by `copyLabel` prop). */\n copyToClipboard: string\n /** `aria-label` of the close button in the fullscreen modal. */\n closeExpandedView: string\n\n // ── FeedbackInline (response-quality feedback) ─────────────\n /** `title` of the thumb-up button. */\n feedbackUseful: string\n /** `title` of the thumb-down button. */\n feedbackNotUseful: string\n /** Acknowledgement shown after a positive rating (overridden by `positiveAck`). */\n feedbackPositiveAck: string\n /** Acknowledgement shown after a negative rating (overridden by `negativeAck`). */\n feedbackNegativeAck: string\n\n // ── Generic chrome ────────────────────────────────────────\n /** Label of the streaming retry button. */\n retry: string\n}\n\n/**\n * English defaults. A published library ships no hardcoded non-English\n * chrome — consumers localize via `<MCPUIStringsProvider>`.\n */\nexport const DEFAULT_MCPUI_STRINGS: MCPUIStrings = {\n expand: 'Expand',\n expandedView: 'Expanded view',\n copyToClipboard: 'Copy to clipboard',\n closeExpandedView: 'Close expanded view',\n feedbackUseful: 'Useful',\n feedbackNotUseful: 'Not useful',\n feedbackPositiveAck: 'Thanks!',\n feedbackNegativeAck: \"Noted — we'll improve\",\n retry: 'Retry',\n}\n\nexport const MCPUIStringsContext = createContext<MCPUIStrings>(DEFAULT_MCPUI_STRINGS)\n\n/**\n * Reads the active chrome strings. Returns `DEFAULT_MCPUI_STRINGS` when no\n * `<MCPUIStringsProvider>` is mounted above — every renderer works\n * standalone with English chrome.\n */\nexport function useMCPUIStrings(): MCPUIStrings {\n return useContext(MCPUIStringsContext)\n}\n\nexport interface MCPUIStringsProviderProps {\n /**\n * Partial override of the chrome strings. Any key left unset falls back\n * to the English `DEFAULT_MCPUI_STRINGS` — so a consumer can localize\n * just the strings they care about.\n */\n strings?: Partial<MCPUIStrings>\n children: JSX.Element\n}\n\n/**\n * Provides localized chrome strings to every MCP-UI renderer below it.\n * Merges the partial `strings` override over the English defaults.\n */\nexport function MCPUIStringsProvider(props: MCPUIStringsProviderProps): JSX.Element {\n // `props.strings` is read inside the getter so a reactive override\n // (signal-backed) re-propagates ; for the common static case it is read\n // once at mount.\n const value = (): MCPUIStrings => ({ ...DEFAULT_MCPUI_STRINGS, ...props.strings })\n return (\n <MCPUIStringsContext.Provider value={value()}>\n {props.children}\n </MCPUIStringsContext.Provider>\n )\n}\n"],"names":["DEFAULT_MCPUI_STRINGS","expand","expandedView","copyToClipboard","closeExpandedView","feedbackUseful","feedbackNotUseful","feedbackPositiveAck","feedbackNegativeAck","retry","MCPUIStringsContext","createContext","useMCPUIStrings","useContext","MCPUIStringsProvider","props","value","strings","_$createComponent","Provider","children"],"mappings":";;AAgFO,MAAMA,wBAAsC;AAAA,EACjDC,QAAQ;AAAA,EACRC,cAAc;AAAA,EACdC,iBAAiB;AAAA,EACjBC,mBAAmB;AAAA,EACnBC,gBAAgB;AAAA,EAChBC,mBAAmB;AAAA,EACnBC,qBAAqB;AAAA,EACrBC,qBAAqB;AAAA,EACrBC,OAAO;AACT;AAEO,MAAMC,sBAAsBC,cAA4BX,qBAAqB;AAO7E,SAASY,kBAAgC;AAC9C,SAAOC,WAAWH,mBAAmB;AACvC;AAgBO,SAASI,qBAAqBC,OAA+C;AAIlF,QAAMC,QAAQA,OAAqB;AAAA,IAAE,GAAGhB;AAAAA,IAAuB,GAAGe,MAAME;AAAAA,EAAAA;AACxE,SAAAC,gBACGR,oBAAoBS,UAAQ;AAAA,IAAA,IAACH,QAAK;AAAA,aAAEA,MAAAA;AAAAA,IAAO;AAAA,IAAA,IAAAI,WAAA;AAAA,aACzCL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;"}
1
+ {"version":3,"file":"MCPUIStringsContext.js","sources":["../../src/context/MCPUIStringsContext.tsx"],"sourcesContent":["/**\n * MCPUIStringsContext — i18n for the library's own \"chrome\" strings.\n *\n * @since v6.6.0 (D2 / R4 of ROADMAP-opendata-macro-mcpui)\n *\n * ## Scope — chrome only, NOT content\n *\n * MCP-UI renders two kinds of text :\n *\n * - **Content** — table headers, chart titles, action labels, prompt\n * questions. These come from the payload and are ALREADY localized by\n * whoever produced the payload (the connector / MCP server). MCP-UI\n * renders them verbatim and this context never touches them.\n * - **Chrome** — the handful of strings the library itself hardcodes :\n * the expand-button tooltip, the feedback acknowledgements, etc. THIS\n * is what `MCPUIStrings` covers.\n *\n * There is deliberately no full i18n framework here : no per-renderer\n * `locale` prop, no message catalogue, no ICU. A flat string map behind a\n * context is enough — the chrome surface is small and static.\n *\n * ## Defaults are English\n *\n * `DEFAULT_MCPUI_STRINGS` is English. A published library should not ship\n * hardcoded French. Consumers that want another language wrap their tree\n * in `<MCPUIStringsProvider strings={...}>` with a partial override.\n *\n * Component props that already carry a label (e.g. `FeedbackInline`'s\n * `positiveAck`, `ExpandableWrapper`'s `copyLabel`) keep priority over the\n * provider — the provider only fills the gap when no explicit prop is set.\n *\n * @example\n * ```tsx\n * import { MCPUIStringsProvider } from '@seed-ship/mcp-ui-solid'\n *\n * <MCPUIStringsProvider strings={{ expand: 'Agrandir', feedbackUseful: 'Utile' }}>\n * <App />\n * </MCPUIStringsProvider>\n * ```\n */\n\nimport { createContext, mergeProps, useContext, type JSX } from 'solid-js'\n\n/**\n * The library's own chrome strings. Flat map, no interpolation.\n *\n * The original chrome keys remain required. Later additions are optional\n * so existing typed dictionaries remain valid across minor releases.\n * `useMCPUIStrings` resolves omitted keys to their English defaults.\n */\nexport interface MCPUIStrings {\n // ── ExpandableWrapper toolbar ──────────────────────────────\n /** `title` of the expand-to-fullscreen button. */\n expand: string\n /** Heading + `aria-label` of the fullscreen modal when no title is given. */\n expandedView: string\n /** Default tooltip of the copy button (overridden by `copyLabel` prop). */\n copyToClipboard: string\n /** `aria-label` of the close button in the fullscreen modal. */\n closeExpandedView: string\n\n // ── FeedbackInline (response-quality feedback) ─────────────\n /** `title` of the thumb-up button. */\n feedbackUseful: string\n /** `title` of the thumb-down button. */\n feedbackNotUseful: string\n /** Acknowledgement shown after a positive rating (overridden by `positiveAck`). */\n feedbackPositiveAck: string\n /** Acknowledgement shown after a negative rating (overridden by `negativeAck`). */\n feedbackNegativeAck: string\n\n // ── Generic chrome ────────────────────────────────────────\n /** Label of the streaming retry button. */\n retry: string\n\n // ── Chart data access ─────────────────────────────────────\n /** Label of the native chart view button. */\n chartView?: string\n /** Label of the exact-data table view button. */\n chartDataView?: string\n /** Accessible name of the chart/data view selector. */\n chartViewSelector?: string\n /** Caption and accessible name for the chart's data table. */\n chartDataTable?: string\n /** Screen-reader description associated with the chart canvas. */\n chartDataSummary?: string\n /** Empty state shown when a chart has no data points. */\n chartNoData?: string\n}\n\n/**\n * English defaults. A published library ships no hardcoded non-English\n * chrome — consumers localize via `<MCPUIStringsProvider>`.\n */\nexport const DEFAULT_MCPUI_STRINGS: Required<MCPUIStrings> = {\n expand: 'Expand',\n expandedView: 'Expanded view',\n copyToClipboard: 'Copy to clipboard',\n closeExpandedView: 'Close expanded view',\n feedbackUseful: 'Useful',\n feedbackNotUseful: 'Not useful',\n feedbackPositiveAck: 'Thanks!',\n feedbackNegativeAck: \"Noted — we'll improve\",\n retry: 'Retry',\n chartView: 'Chart',\n chartDataView: 'Data',\n chartViewSelector: 'Chart or data view',\n chartDataTable: 'Chart data',\n chartDataSummary: 'Exact values are available in the data view.',\n chartNoData: 'No chart data',\n}\n\nexport const MCPUIStringsContext = createContext<MCPUIStrings>(DEFAULT_MCPUI_STRINGS)\n\n/**\n * Reads the active chrome strings. Returns `DEFAULT_MCPUI_STRINGS` when no\n * `<MCPUIStringsProvider>` is mounted above — every renderer works\n * standalone with English chrome.\n */\nexport function useMCPUIStrings(): Required<MCPUIStrings> {\n return mergeProps(DEFAULT_MCPUI_STRINGS, useContext(MCPUIStringsContext))\n}\n\nexport interface MCPUIStringsProviderProps {\n /**\n * Partial override of the chrome strings. Any key left unset falls back\n * to the English `DEFAULT_MCPUI_STRINGS` — so a consumer can localize\n * just the strings they care about.\n */\n strings?: Partial<MCPUIStrings>\n children: JSX.Element\n}\n\n/**\n * Provides localized chrome strings to every MCP-UI renderer below it.\n * Merges the partial `strings` override over the English defaults.\n */\nexport function MCPUIStringsProvider(props: MCPUIStringsProviderProps): JSX.Element {\n // The function source keeps replacement `strings` objects reactive while\n // mergeProps fills any omitted key without taking a one-time snapshot.\n const value = mergeProps(DEFAULT_MCPUI_STRINGS, () => props.strings)\n return (\n <MCPUIStringsContext.Provider value={value}>\n {props.children}\n </MCPUIStringsContext.Provider>\n )\n}\n"],"names":["DEFAULT_MCPUI_STRINGS","expand","expandedView","copyToClipboard","closeExpandedView","feedbackUseful","feedbackNotUseful","feedbackPositiveAck","feedbackNegativeAck","retry","chartView","chartDataView","chartViewSelector","chartDataTable","chartDataSummary","chartNoData","MCPUIStringsContext","createContext","useMCPUIStrings","mergeProps","useContext","MCPUIStringsProvider","props","value","strings","_$createComponent","Provider","children"],"mappings":";;AA8FO,MAAMA,wBAAgD;AAAA,EAC3DC,QAAQ;AAAA,EACRC,cAAc;AAAA,EACdC,iBAAiB;AAAA,EACjBC,mBAAmB;AAAA,EACnBC,gBAAgB;AAAA,EAChBC,mBAAmB;AAAA,EACnBC,qBAAqB;AAAA,EACrBC,qBAAqB;AAAA,EACrBC,OAAO;AAAA,EACPC,WAAW;AAAA,EACXC,eAAe;AAAA,EACfC,mBAAmB;AAAA,EACnBC,gBAAgB;AAAA,EAChBC,kBAAkB;AAAA,EAClBC,aAAa;AACf;AAEO,MAAMC,sBAAsBC,cAA4BjB,qBAAqB;AAO7E,SAASkB,kBAA0C;AACxD,SAAOC,WAAWnB,uBAAuBoB,WAAWJ,mBAAmB,CAAC;AAC1E;AAgBO,SAASK,qBAAqBC,OAA+C;AAGlF,QAAMC,QAAQJ,WAAWnB,uBAAuB,MAAMsB,MAAME,OAAO;AACnE,SAAAC,gBACGT,oBAAoBU,UAAQ;AAAA,IAACH;AAAAA,IAAY,IAAAI,WAAA;AAAA,aACvCL,MAAMK;AAAAA,IAAQ;AAAA,EAAA,CAAA;AAGrB;"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const solidJs = require("solid-js");
4
+ const EditableLayoutContext = require("../components/EditableLayoutContext.cjs");
5
+ function createResponsiveGrid(breakpoint = 640) {
6
+ const [stacked, setStacked] = solidJs.createSignal(false);
7
+ const preserveEditablePositions = EditableLayoutContext.useEditableLayoutPositions();
8
+ let container;
9
+ const ref = (element) => {
10
+ container = element;
11
+ };
12
+ if (preserveEditablePositions) return { stacked: () => false, ref };
13
+ solidJs.onMount(() => {
14
+ if (!container) return;
15
+ const element = container;
16
+ const updateWidth = (width) => {
17
+ if (Number.isFinite(width) && width > 0) setStacked(width < breakpoint);
18
+ };
19
+ const measure = () => updateWidth(element.getBoundingClientRect().width);
20
+ measure();
21
+ if (typeof ResizeObserver !== "undefined") {
22
+ const observer = new ResizeObserver((entries) => {
23
+ for (const entry of entries) {
24
+ if (entry.target === element) updateWidth(entry.contentRect.width);
25
+ }
26
+ });
27
+ observer.observe(element);
28
+ solidJs.onCleanup(() => observer.disconnect());
29
+ } else if (typeof window !== "undefined") {
30
+ window.addEventListener("resize", measure);
31
+ solidJs.onCleanup(() => window.removeEventListener("resize", measure));
32
+ }
33
+ });
34
+ return { stacked, ref };
35
+ }
36
+ exports.createResponsiveGrid = createResponsiveGrid;
37
+ //# sourceMappingURL=createResponsiveGrid.cjs.map