@vertesia/ui 0.80.0-dev.20251121 → 0.80.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 (277) hide show
  1. package/README.md +105 -0
  2. package/lib/esm/core/components/MenuList.js +2 -5
  3. package/lib/esm/core/components/MenuList.js.map +1 -1
  4. package/lib/esm/core/components/MessageBox.js +1 -1
  5. package/lib/esm/core/components/MessageBox.js.map +1 -1
  6. package/lib/esm/core/components/shadcn/dialog.js +16 -2
  7. package/lib/esm/core/components/shadcn/dialog.js.map +1 -1
  8. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js +6 -9
  9. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js.map +1 -1
  10. package/lib/esm/core/components/shadcn/filters/filterBar.js +1 -1
  11. package/lib/esm/core/components/shadcn/filters/filterBar.js.map +1 -1
  12. package/lib/esm/core/components/shadcn/selectBox.js +23 -5
  13. package/lib/esm/core/components/shadcn/selectBox.js.map +1 -1
  14. package/lib/esm/core/components/shadcn/tabs.js +3 -3
  15. package/lib/esm/core/components/shadcn/tabs.js.map +1 -1
  16. package/lib/esm/env/index.js +3 -0
  17. package/lib/esm/env/index.js.map +1 -1
  18. package/lib/esm/features/agent/chat/AgentChart.js +184 -0
  19. package/lib/esm/features/agent/chat/AgentChart.js.map +1 -0
  20. package/lib/esm/features/agent/chat/ModernAgentConversation.js +87 -10
  21. package/lib/esm/features/agent/chat/ModernAgentConversation.js.map +1 -1
  22. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +6 -2
  23. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  24. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js +4 -4
  25. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  26. package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js +4 -1
  27. package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js.map +1 -1
  28. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageInput.js +12 -4
  29. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  30. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js +60 -56
  31. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  32. package/lib/esm/features/agent/chat/index.js +1 -0
  33. package/lib/esm/features/agent/chat/index.js.map +1 -1
  34. package/lib/esm/features/agent/createChartTool.js +354 -0
  35. package/lib/esm/features/agent/createChartTool.js.map +1 -0
  36. package/lib/esm/features/agent/examples.js +295 -0
  37. package/lib/esm/features/agent/examples.js.map +1 -0
  38. package/lib/esm/features/agent/index.js +2 -0
  39. package/lib/esm/features/agent/index.js.map +1 -1
  40. package/lib/esm/features/agent/visualization.js +165 -0
  41. package/lib/esm/features/agent/visualization.js.map +1 -0
  42. package/lib/esm/features/facets/CollectionsFacetsNav.js +5 -1
  43. package/lib/esm/features/facets/CollectionsFacetsNav.js.map +1 -1
  44. package/lib/esm/features/index.js +1 -0
  45. package/lib/esm/features/index.js.map +1 -1
  46. package/lib/esm/features/layout/GenericPageNavHeader.js +14 -4
  47. package/lib/esm/features/layout/GenericPageNavHeader.js.map +1 -1
  48. package/lib/esm/features/magic-pdf/AnnotatedImageSlider.js +268 -0
  49. package/lib/esm/features/magic-pdf/AnnotatedImageSlider.js.map +1 -0
  50. package/lib/esm/features/magic-pdf/DownloadPopover.js +11 -11
  51. package/lib/esm/features/magic-pdf/DownloadPopover.js.map +1 -1
  52. package/lib/esm/features/magic-pdf/ExtractedContentView.js +77 -0
  53. package/lib/esm/features/magic-pdf/ExtractedContentView.js.map +1 -0
  54. package/lib/esm/features/magic-pdf/MagicPdfProvider.js +242 -0
  55. package/lib/esm/features/magic-pdf/MagicPdfProvider.js.map +1 -0
  56. package/lib/esm/features/magic-pdf/MagicPdfView.js +41 -47
  57. package/lib/esm/features/magic-pdf/MagicPdfView.js.map +1 -1
  58. package/lib/esm/features/pdf-viewer/PdfPageRenderer.js +261 -0
  59. package/lib/esm/features/pdf-viewer/PdfPageRenderer.js.map +1 -0
  60. package/lib/esm/features/pdf-viewer/PdfPageSlider.js +276 -0
  61. package/lib/esm/features/pdf-viewer/PdfPageSlider.js.map +1 -0
  62. package/lib/esm/features/pdf-viewer/SimplePdfViewer.js +71 -0
  63. package/lib/esm/features/pdf-viewer/SimplePdfViewer.js.map +1 -0
  64. package/lib/esm/features/pdf-viewer/index.js +4 -0
  65. package/lib/esm/features/pdf-viewer/index.js.map +1 -0
  66. package/lib/esm/features/store/collections/EditCollectionView.js +3 -5
  67. package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
  68. package/lib/esm/features/store/collections/SharedPropsEditor.js +1 -2
  69. package/lib/esm/features/store/collections/SharedPropsEditor.js.map +1 -1
  70. package/lib/esm/features/store/objects/DocumentSearchResults.js +0 -7
  71. package/lib/esm/features/store/objects/DocumentSearchResults.js.map +1 -1
  72. package/lib/esm/features/store/objects/components/ContentOverview.js +273 -83
  73. package/lib/esm/features/store/objects/components/ContentOverview.js.map +1 -1
  74. package/lib/esm/features/store/objects/components/useContentPanelHooks.js +153 -0
  75. package/lib/esm/features/store/objects/components/useContentPanelHooks.js.map +1 -0
  76. package/lib/esm/features/store/objects/layout/DocumentTableColumn.js +3 -3
  77. package/lib/esm/features/store/objects/layout/DocumentTableColumn.js.map +1 -1
  78. package/lib/esm/features/store/objects/layout/renderers.js +13 -0
  79. package/lib/esm/features/store/objects/layout/renderers.js.map +1 -1
  80. package/lib/esm/features/utils/index.js +2 -0
  81. package/lib/esm/features/utils/index.js.map +1 -1
  82. package/lib/esm/features/utils/mimeType.js +8 -0
  83. package/lib/esm/features/utils/mimeType.js.map +1 -1
  84. package/lib/esm/features/utils/print.js +181 -0
  85. package/lib/esm/features/utils/print.js.map +1 -0
  86. package/lib/esm/features/utils/workflowStatus.js +43 -0
  87. package/lib/esm/features/utils/workflowStatus.js.map +1 -0
  88. package/lib/esm/router/HistoryNavigator.js +22 -2
  89. package/lib/esm/router/HistoryNavigator.js.map +1 -1
  90. package/lib/esm/shell/login/UserInfo.js +2 -1
  91. package/lib/esm/shell/login/UserInfo.js.map +1 -1
  92. package/lib/esm/shell/login/UserSessionMenu.js +7 -1
  93. package/lib/esm/shell/login/UserSessionMenu.js.map +1 -1
  94. package/lib/esm/widgets/form/Form.js +6 -2
  95. package/lib/esm/widgets/form/Form.js.map +1 -1
  96. package/lib/esm/widgets/markdown/MarkdownRenderer.js +226 -4
  97. package/lib/esm/widgets/markdown/MarkdownRenderer.js.map +1 -1
  98. package/lib/esm/widgets/schema-editor/ManagedSchema.js +0 -3
  99. package/lib/esm/widgets/schema-editor/ManagedSchema.js.map +1 -1
  100. package/lib/esm/widgets/schema-editor/json-schema4-utils.js +1 -1
  101. package/lib/esm/widgets/schema-editor/json-schema4-utils.js.map +1 -1
  102. package/lib/esm/widgets/xml-viewer/components/XMLViewer.js +18 -9
  103. package/lib/esm/widgets/xml-viewer/components/XMLViewer.js.map +1 -1
  104. package/lib/esm/widgets/xml-viewer/constants/index.js +10 -0
  105. package/lib/esm/widgets/xml-viewer/constants/index.js.map +1 -1
  106. package/lib/tsconfig.tsbuildinfo +1 -1
  107. package/lib/types/core/components/MessageBox.d.ts.map +1 -1
  108. package/lib/types/core/components/shadcn/dialog.d.ts +2 -1
  109. package/lib/types/core/components/shadcn/dialog.d.ts.map +1 -1
  110. package/lib/types/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
  111. package/lib/types/core/components/shadcn/selectBox.d.ts +5 -1
  112. package/lib/types/core/components/shadcn/selectBox.d.ts.map +1 -1
  113. package/lib/types/core/components/shadcn/tabs.d.ts +3 -1
  114. package/lib/types/core/components/shadcn/tabs.d.ts.map +1 -1
  115. package/lib/types/env/index.d.ts +2 -0
  116. package/lib/types/env/index.d.ts.map +1 -1
  117. package/lib/types/features/agent/chat/AgentChart.d.ts +48 -0
  118. package/lib/types/features/agent/chat/AgentChart.d.ts.map +1 -0
  119. package/lib/types/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  120. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -2
  121. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  122. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts +2 -1
  123. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  124. package/lib/types/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.d.ts +4 -2
  125. package/lib/types/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.d.ts.map +1 -1
  126. package/lib/types/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +2 -4
  127. package/lib/types/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  128. package/lib/types/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  129. package/lib/types/features/agent/chat/index.d.ts +1 -0
  130. package/lib/types/features/agent/chat/index.d.ts.map +1 -1
  131. package/lib/types/features/agent/createChartTool.d.ts +178 -0
  132. package/lib/types/features/agent/createChartTool.d.ts.map +1 -0
  133. package/lib/types/features/agent/examples.d.ts +59 -0
  134. package/lib/types/features/agent/examples.d.ts.map +1 -0
  135. package/lib/types/features/agent/index.d.ts +2 -0
  136. package/lib/types/features/agent/index.d.ts.map +1 -1
  137. package/lib/types/features/agent/visualization.d.ts +95 -0
  138. package/lib/types/features/agent/visualization.d.ts.map +1 -0
  139. package/lib/types/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
  140. package/lib/types/features/index.d.ts +1 -0
  141. package/lib/types/features/index.d.ts.map +1 -1
  142. package/lib/types/features/layout/GenericPageNavHeader.d.ts.map +1 -1
  143. package/lib/types/features/magic-pdf/AnnotatedImageSlider.d.ts +13 -0
  144. package/lib/types/features/magic-pdf/AnnotatedImageSlider.d.ts.map +1 -0
  145. package/lib/types/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
  146. package/lib/types/features/magic-pdf/ExtractedContentView.d.ts +8 -0
  147. package/lib/types/features/magic-pdf/ExtractedContentView.d.ts.map +1 -0
  148. package/lib/types/features/magic-pdf/MagicPdfProvider.d.ts +58 -0
  149. package/lib/types/features/magic-pdf/MagicPdfProvider.d.ts.map +1 -0
  150. package/lib/types/features/magic-pdf/MagicPdfView.d.ts +1 -1
  151. package/lib/types/features/magic-pdf/MagicPdfView.d.ts.map +1 -1
  152. package/lib/types/features/pdf-viewer/PdfPageRenderer.d.ts +83 -0
  153. package/lib/types/features/pdf-viewer/PdfPageRenderer.d.ts.map +1 -0
  154. package/lib/types/features/pdf-viewer/PdfPageSlider.d.ts +29 -0
  155. package/lib/types/features/pdf-viewer/PdfPageSlider.d.ts.map +1 -0
  156. package/lib/types/features/pdf-viewer/SimplePdfViewer.d.ts +19 -0
  157. package/lib/types/features/pdf-viewer/SimplePdfViewer.d.ts.map +1 -0
  158. package/lib/types/features/pdf-viewer/index.d.ts +4 -0
  159. package/lib/types/features/pdf-viewer/index.d.ts.map +1 -0
  160. package/lib/types/features/store/collections/EditCollectionView.d.ts.map +1 -1
  161. package/lib/types/features/store/collections/SharedPropsEditor.d.ts.map +1 -1
  162. package/lib/types/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
  163. package/lib/types/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  164. package/lib/types/features/store/objects/components/useContentPanelHooks.d.ts +30 -0
  165. package/lib/types/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -0
  166. package/lib/types/features/store/objects/layout/renderers.d.ts.map +1 -1
  167. package/lib/types/features/utils/index.d.ts +2 -0
  168. package/lib/types/features/utils/index.d.ts.map +1 -1
  169. package/lib/types/features/utils/mimeType.d.ts +1 -0
  170. package/lib/types/features/utils/mimeType.d.ts.map +1 -1
  171. package/lib/types/features/utils/print.d.ts +10 -0
  172. package/lib/types/features/utils/print.d.ts.map +1 -0
  173. package/lib/types/features/utils/workflowStatus.d.ts +10 -0
  174. package/lib/types/features/utils/workflowStatus.d.ts.map +1 -0
  175. package/lib/types/router/HistoryNavigator.d.ts +3 -0
  176. package/lib/types/router/HistoryNavigator.d.ts.map +1 -1
  177. package/lib/types/shell/login/UserInfo.d.ts.map +1 -1
  178. package/lib/types/shell/login/UserSessionMenu.d.ts.map +1 -1
  179. package/lib/types/widgets/form/Form.d.ts.map +1 -1
  180. package/lib/types/widgets/markdown/MarkdownRenderer.d.ts +5 -1
  181. package/lib/types/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
  182. package/lib/types/widgets/schema-editor/ManagedSchema.d.ts.map +1 -1
  183. package/lib/types/widgets/xml-viewer/components/XMLViewer.d.ts.map +1 -1
  184. package/lib/types/widgets/xml-viewer/constants/index.d.ts +10 -0
  185. package/lib/types/widgets/xml-viewer/constants/index.d.ts.map +1 -1
  186. package/lib/vertesia-ui-core.js +1 -1
  187. package/lib/vertesia-ui-core.js.map +1 -1
  188. package/lib/vertesia-ui-env.js +1 -1
  189. package/lib/vertesia-ui-env.js.map +1 -1
  190. package/lib/vertesia-ui-features.js +1 -1
  191. package/lib/vertesia-ui-features.js.map +1 -1
  192. package/lib/vertesia-ui-layout.js +1 -1
  193. package/lib/vertesia-ui-layout.js.map +1 -1
  194. package/lib/vertesia-ui-router.js +1 -1
  195. package/lib/vertesia-ui-router.js.map +1 -1
  196. package/lib/vertesia-ui-session.js +1 -1
  197. package/lib/vertesia-ui-session.js.map +1 -1
  198. package/lib/vertesia-ui-shell.js +1 -1
  199. package/lib/vertesia-ui-shell.js.map +1 -1
  200. package/lib/vertesia-ui-widgets.js +1 -1
  201. package/lib/vertesia-ui-widgets.js.map +1 -1
  202. package/package.json +11 -8
  203. package/src/core/components/MenuList.tsx +3 -6
  204. package/src/core/components/MessageBox.tsx +7 -2
  205. package/src/core/components/SelectBox.tsx +1 -1
  206. package/src/core/components/shadcn/dialog.tsx +19 -1
  207. package/src/core/components/shadcn/filters/filter/SelectFilter.tsx +31 -31
  208. package/src/core/components/shadcn/filters/filterBar.tsx +1 -0
  209. package/src/core/components/shadcn/selectBox.tsx +32 -6
  210. package/src/core/components/shadcn/tabs.tsx +3 -2
  211. package/src/env/index.ts +5 -0
  212. package/src/features/agent/CHART_INSTRUCTIONS.md +228 -0
  213. package/src/features/agent/chat/AgentChart.tsx +601 -0
  214. package/src/features/agent/chat/ModernAgentConversation.tsx +123 -11
  215. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +8 -2
  216. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +12 -2
  217. package/src/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.tsx +6 -1
  218. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +15 -10
  219. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +122 -87
  220. package/src/features/agent/chat/index.ts +1 -0
  221. package/src/features/agent/createChartTool.ts +364 -0
  222. package/src/features/agent/examples.ts +321 -0
  223. package/src/features/agent/index.ts +2 -0
  224. package/src/features/agent/visualization.ts +227 -0
  225. package/src/features/facets/CollectionsFacetsNav.tsx +5 -1
  226. package/src/features/index.ts +1 -0
  227. package/src/features/layout/GenericPageNavHeader.tsx +15 -4
  228. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +482 -0
  229. package/src/features/magic-pdf/DownloadPopover.tsx +45 -40
  230. package/src/features/magic-pdf/ExtractedContentView.tsx +132 -0
  231. package/src/features/magic-pdf/MagicPdfProvider.tsx +297 -0
  232. package/src/features/magic-pdf/MagicPdfView.tsx +184 -91
  233. package/src/features/pdf-viewer/PdfPageRenderer.tsx +612 -0
  234. package/src/features/pdf-viewer/PdfPageSlider.tsx +473 -0
  235. package/src/features/pdf-viewer/SimplePdfViewer.tsx +142 -0
  236. package/src/features/pdf-viewer/index.ts +3 -0
  237. package/src/features/store/collections/EditCollectionView.tsx +3 -5
  238. package/src/features/store/collections/SharedPropsEditor.tsx +1 -2
  239. package/src/features/store/objects/DocumentSearchResults.tsx +0 -7
  240. package/src/features/store/objects/components/ContentOverview.tsx +677 -210
  241. package/src/features/store/objects/components/useContentPanelHooks.ts +169 -0
  242. package/src/features/store/objects/layout/DocumentTableColumn.tsx +3 -3
  243. package/src/features/store/objects/layout/knowledge.md +1 -0
  244. package/src/features/store/objects/layout/renderers.tsx +25 -0
  245. package/src/features/utils/index.ts +3 -1
  246. package/src/features/utils/mimeType.ts +10 -1
  247. package/src/features/utils/print.ts +189 -0
  248. package/src/features/utils/workflowStatus.ts +44 -0
  249. package/src/router/HistoryNavigator.ts +30 -2
  250. package/src/shell/login/UserInfo.tsx +2 -0
  251. package/src/shell/login/UserSessionMenu.tsx +12 -1
  252. package/src/widgets/form/Form.tsx +8 -3
  253. package/src/widgets/markdown/MarkdownRenderer.tsx +350 -6
  254. package/src/widgets/schema-editor/ManagedSchema.ts +0 -3
  255. package/src/widgets/schema-editor/json-schema4-utils.ts +1 -1
  256. package/src/widgets/xml-viewer/components/XMLViewer.tsx +22 -10
  257. package/src/widgets/xml-viewer/constants/index.ts +11 -0
  258. package/lib/esm/features/magic-pdf/PageSlider.js +0 -70
  259. package/lib/esm/features/magic-pdf/PageSlider.js.map +0 -1
  260. package/lib/esm/features/magic-pdf/PdfPageProvider.js +0 -188
  261. package/lib/esm/features/magic-pdf/PdfPageProvider.js.map +0 -1
  262. package/lib/esm/features/magic-pdf/TextPageView.js +0 -62
  263. package/lib/esm/features/magic-pdf/TextPageView.js.map +0 -1
  264. package/lib/esm/features/magic-pdf/useResizeOnDrag.js +0 -34
  265. package/lib/esm/features/magic-pdf/useResizeOnDrag.js.map +0 -1
  266. package/lib/types/features/magic-pdf/PageSlider.d.ts +0 -9
  267. package/lib/types/features/magic-pdf/PageSlider.d.ts.map +0 -1
  268. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts +0 -39
  269. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts.map +0 -1
  270. package/lib/types/features/magic-pdf/TextPageView.d.ts +0 -8
  271. package/lib/types/features/magic-pdf/TextPageView.d.ts.map +0 -1
  272. package/lib/types/features/magic-pdf/useResizeOnDrag.d.ts +0 -9
  273. package/lib/types/features/magic-pdf/useResizeOnDrag.d.ts.map +0 -1
  274. package/src/features/magic-pdf/PageSlider.tsx +0 -142
  275. package/src/features/magic-pdf/PdfPageProvider.tsx +0 -310
  276. package/src/features/magic-pdf/TextPageView.tsx +0 -91
  277. package/src/features/magic-pdf/useResizeOnDrag.ts +0 -42
@@ -0,0 +1,601 @@
1
+ import { Component, memo, useState, useRef, useCallback, type ReactNode, type ErrorInfo } from 'react';
2
+ import { toPng } from 'html-to-image';
3
+ import { Download, Copy, Check } from 'lucide-react';
4
+ import {
5
+ ResponsiveContainer,
6
+ BarChart,
7
+ LineChart,
8
+ ComposedChart,
9
+ AreaChart,
10
+ PieChart,
11
+ ScatterChart,
12
+ RadarChart,
13
+ RadialBarChart,
14
+ FunnelChart,
15
+ Treemap,
16
+ Bar,
17
+ Line,
18
+ Area,
19
+ Pie,
20
+ Cell,
21
+ Scatter,
22
+ Radar,
23
+ RadialBar,
24
+ Funnel,
25
+ LabelList,
26
+ PolarGrid,
27
+ PolarAngleAxis,
28
+ PolarRadiusAxis,
29
+ XAxis,
30
+ YAxis,
31
+ CartesianGrid,
32
+ Tooltip,
33
+ Legend,
34
+ ReferenceLine,
35
+ } from 'recharts';
36
+
37
+ // Default color palette for charts
38
+ const COLORS = ['#4f46e5', '#06b6d4', '#22c55e', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899', '#14b8a6'];
39
+
40
+ // Error boundary for chart rendering
41
+ type ChartErrorBoundaryProps = {
42
+ chartType: string;
43
+ children: ReactNode;
44
+ };
45
+
46
+ type ChartErrorBoundaryState = {
47
+ hasError: boolean;
48
+ error: Error | null;
49
+ };
50
+
51
+ class ChartErrorBoundary extends Component<ChartErrorBoundaryProps, ChartErrorBoundaryState> {
52
+ constructor(props: ChartErrorBoundaryProps) {
53
+ super(props);
54
+ this.state = { hasError: false, error: null };
55
+ }
56
+
57
+ static getDerivedStateFromError(error: Error): ChartErrorBoundaryState {
58
+ return { hasError: true, error };
59
+ }
60
+
61
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
62
+ console.error(`Chart rendering error (${this.props.chartType}):`, error, errorInfo);
63
+ }
64
+
65
+ render() {
66
+ if (this.state.hasError) {
67
+ return (
68
+ <div className="flex items-center justify-center h-full bg-red-50 dark:bg-red-950 rounded-md p-4">
69
+ <div className="text-center">
70
+ <p className="text-sm font-medium text-red-600 dark:text-red-400">
71
+ Cannot render {this.props.chartType} chart
72
+ </p>
73
+ <p className="text-xs text-red-500 dark:text-red-500 mt-1 max-w-xs truncate">
74
+ {this.state.error?.message || 'Unknown error'}
75
+ </p>
76
+ </div>
77
+ </div>
78
+ );
79
+ }
80
+
81
+ return this.props.children;
82
+ }
83
+ }
84
+
85
+ export type AgentChartSpec = {
86
+ version?: '1.0';
87
+ library?: 'recharts';
88
+ chart: 'bar' | 'line' | 'composed' | 'area' | 'pie' | 'scatter' | 'radar' | 'radialBar' | 'funnel' | 'treemap';
89
+ title?: string;
90
+ description?: string;
91
+ data: Record<string, any>[];
92
+ xKey: string;
93
+ series: Array<{
94
+ key: string;
95
+ label?: string;
96
+ type?: 'bar' | 'line' | 'area';
97
+ color?: string;
98
+ yAxisId?: 'left' | 'right';
99
+ stackId?: string;
100
+ dot?: boolean;
101
+ }>;
102
+ // For pie/radialBar charts
103
+ nameKey?: string;
104
+ valueKey?: string;
105
+ // For scatter charts
106
+ yKey?: string;
107
+ zKey?: string; // optional size dimension
108
+ // For radar charts
109
+ axisKey?: string;
110
+ // For treemap
111
+ dataKey?: string;
112
+ yAxis?: {
113
+ left?: { label?: string };
114
+ right?: { label?: string };
115
+ };
116
+ options?: {
117
+ stacked?: boolean;
118
+ referenceZero?: boolean;
119
+ collapsible?: boolean;
120
+ collapseInitially?: boolean;
121
+ innerRadius?: number; // for pie/radialBar (donut style)
122
+ showLabels?: boolean; // for pie/funnel
123
+ startAngle?: number; // for radialBar
124
+ endAngle?: number; // for radialBar
125
+ };
126
+ };
127
+
128
+ type AgentChartProps = {
129
+ spec: AgentChartSpec;
130
+ };
131
+
132
+ function formatNumber(n: number): string {
133
+ if (!isFinite(n)) return String(n);
134
+ const abs = Math.abs(n);
135
+ if (abs >= 1_000_000_000) return (n / 1_000_000_000).toFixed(1) + 'B';
136
+ if (abs >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M';
137
+ if (abs >= 1_000) return (n / 1_000).toFixed(1) + 'K';
138
+ return n.toLocaleString();
139
+ }
140
+
141
+ // Memoized chart component to prevent unnecessary re-renders
142
+ export const AgentChart = memo(function AgentChart({ spec }: AgentChartProps) {
143
+ const {
144
+ chart,
145
+ title,
146
+ description,
147
+ data,
148
+ xKey,
149
+ series,
150
+ yAxis,
151
+ options,
152
+ nameKey,
153
+ valueKey,
154
+ yKey,
155
+ zKey: _zKey,
156
+ axisKey,
157
+ dataKey,
158
+ } = spec;
159
+ const [isExporting, setIsExporting] = useState(false);
160
+ const [isCopied, setIsCopied] = useState(false);
161
+ const chartRef = useRef<HTMLDivElement>(null);
162
+
163
+ const handleCopy = useCallback(async () => {
164
+ if (!chartRef.current || isCopied) return;
165
+
166
+ try {
167
+ const dataUrl = await toPng(chartRef.current, {
168
+ backgroundColor: '#ffffff',
169
+ pixelRatio: 2,
170
+ });
171
+ const response = await fetch(dataUrl);
172
+ const blob = await response.blob();
173
+ await navigator.clipboard.write([
174
+ new ClipboardItem({ 'image/png': blob })
175
+ ]);
176
+ setIsCopied(true);
177
+ setTimeout(() => setIsCopied(false), 2000);
178
+ } catch (err) {
179
+ console.error('Failed to copy chart:', err);
180
+ }
181
+ }, [isCopied]);
182
+
183
+ const handleExport = useCallback(async () => {
184
+ if (!chartRef.current || isExporting) return;
185
+
186
+ setIsExporting(true);
187
+ try {
188
+ const dataUrl = await toPng(chartRef.current, {
189
+ backgroundColor: '#ffffff',
190
+ pixelRatio: 2,
191
+ });
192
+ const link = document.createElement('a');
193
+ link.download = `${title || 'chart'}.png`;
194
+ link.href = dataUrl;
195
+ link.click();
196
+ } catch (err) {
197
+ console.error('Failed to export chart:', err);
198
+ } finally {
199
+ setIsExporting(false);
200
+ }
201
+ }, [title, isExporting]);
202
+
203
+ // Safe arrays - default to empty array if undefined
204
+ const safeSeries = series || [];
205
+ const safeData = data || [];
206
+
207
+ const commonAxes = (
208
+ <>
209
+ <XAxis dataKey={xKey} tick={{ fontSize: 12 }} />
210
+ <YAxis
211
+ yAxisId="left"
212
+ tickFormatter={formatNumber}
213
+ label={yAxis?.left?.label ? { value: yAxis.left.label, angle: -90, position: 'insideLeft' } : undefined}
214
+ />
215
+ {safeSeries.some((s) => s.yAxisId === 'right') && (
216
+ <YAxis
217
+ yAxisId="right"
218
+ orientation="right"
219
+ tickFormatter={formatNumber}
220
+ label={yAxis?.right?.label ? { value: yAxis.right.label, angle: -90, position: 'insideRight' } : undefined}
221
+ />
222
+ )}
223
+ </>
224
+ );
225
+
226
+ const commonOverlays = (
227
+ <>
228
+ <CartesianGrid strokeDasharray="3 3" />
229
+ <Tooltip formatter={(value) => (typeof value === 'number' ? formatNumber(value) : String(value))} />
230
+ <Legend />
231
+ {options?.referenceZero && <ReferenceLine y={0} stroke="#999" strokeDasharray="3 3" />}
232
+ </>
233
+ );
234
+
235
+ const renderSeries = () =>
236
+ safeSeries.map((s, idx) => {
237
+ const color = s.color || COLORS[idx % COLORS.length];
238
+ const yAxisId = s.yAxisId || 'left';
239
+ if (chart === 'line') {
240
+ return (
241
+ <Line
242
+ key={s.key}
243
+ type="monotone"
244
+ dataKey={s.key}
245
+ name={s.label || s.key}
246
+ stroke={color}
247
+ dot={s.dot ?? false}
248
+ yAxisId={yAxisId}
249
+ />
250
+ );
251
+ }
252
+ if (chart === 'area') {
253
+ return (
254
+ <Area
255
+ key={s.key}
256
+ type="monotone"
257
+ dataKey={s.key}
258
+ name={s.label || s.key}
259
+ stroke={color}
260
+ fill={color}
261
+ fillOpacity={0.3}
262
+ stackId={options?.stacked ? (s.stackId || 'stack') : undefined}
263
+ yAxisId={yAxisId}
264
+ />
265
+ );
266
+ }
267
+ if (chart === 'bar' || s.type === 'bar') {
268
+ return (
269
+ <Bar
270
+ key={s.key}
271
+ dataKey={s.key}
272
+ name={s.label || s.key}
273
+ fill={color}
274
+ stackId={options?.stacked ? (s.stackId || 'stack') : undefined}
275
+ yAxisId={yAxisId}
276
+ />
277
+ );
278
+ }
279
+ if (s.type === 'area') {
280
+ return (
281
+ <Area
282
+ key={s.key}
283
+ type="monotone"
284
+ dataKey={s.key}
285
+ name={s.label || s.key}
286
+ stroke={color}
287
+ fill={color}
288
+ fillOpacity={0.3}
289
+ stackId={options?.stacked ? (s.stackId || 'stack') : undefined}
290
+ yAxisId={yAxisId}
291
+ />
292
+ );
293
+ }
294
+ // default to line in composed
295
+ return (
296
+ <Line
297
+ key={s.key}
298
+ type="monotone"
299
+ dataKey={s.key}
300
+ name={s.label || s.key}
301
+ stroke={color}
302
+ dot={s.dot ?? false}
303
+ yAxisId={yAxisId}
304
+ />
305
+ );
306
+ });
307
+
308
+ // Render Pie Chart
309
+ const renderPieChart = () => {
310
+ const nKey = nameKey || 'name';
311
+ const vKey = valueKey || 'value';
312
+ const innerRadius = options?.innerRadius || 0;
313
+ return (
314
+ <PieChart>
315
+ <Pie
316
+ data={safeData}
317
+ dataKey={vKey}
318
+ nameKey={nKey}
319
+ cx="50%"
320
+ cy="50%"
321
+ innerRadius={innerRadius}
322
+ outerRadius={100}
323
+ label={options?.showLabels !== false}
324
+ >
325
+ {safeData.map((_, index) => (
326
+ <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
327
+ ))}
328
+ </Pie>
329
+ <Tooltip formatter={(value) => (typeof value === 'number' ? formatNumber(value) : String(value))} />
330
+ <Legend />
331
+ </PieChart>
332
+ );
333
+ };
334
+
335
+ // Render Scatter Chart
336
+ const renderScatterChart = () => {
337
+ const xDataKey = xKey;
338
+ const yDataKey = yKey || 'y';
339
+ return (
340
+ <ScatterChart>
341
+ <CartesianGrid strokeDasharray="3 3" />
342
+ <XAxis dataKey={xDataKey} name={xDataKey} tick={{ fontSize: 12 }} />
343
+ <YAxis dataKey={yDataKey} name={yDataKey} tickFormatter={formatNumber} />
344
+ <Tooltip formatter={(value) => (typeof value === 'number' ? formatNumber(value) : String(value))} />
345
+ <Legend />
346
+ {safeSeries.length > 0 ? (
347
+ safeSeries.map((s, idx) => (
348
+ <Scatter
349
+ key={s.key}
350
+ name={s.label || s.key}
351
+ data={safeData}
352
+ fill={s.color || COLORS[idx % COLORS.length]}
353
+ />
354
+ ))
355
+ ) : (
356
+ <Scatter name="Data" data={safeData} fill={COLORS[0]} />
357
+ )}
358
+ </ScatterChart>
359
+ );
360
+ };
361
+
362
+ // Render Radar Chart
363
+ const renderRadarChart = () => {
364
+ const aKey = axisKey || xKey || 'axis';
365
+ return (
366
+ <RadarChart cx="50%" cy="50%" outerRadius={100} data={safeData}>
367
+ <PolarGrid />
368
+ <PolarAngleAxis dataKey={aKey} tick={{ fontSize: 11 }} />
369
+ <PolarRadiusAxis tickFormatter={formatNumber} />
370
+ {safeSeries.map((s, idx) => (
371
+ <Radar
372
+ key={s.key}
373
+ name={s.label || s.key}
374
+ dataKey={s.key}
375
+ stroke={s.color || COLORS[idx % COLORS.length]}
376
+ fill={s.color || COLORS[idx % COLORS.length]}
377
+ fillOpacity={0.3}
378
+ />
379
+ ))}
380
+ <Tooltip formatter={(value) => (typeof value === 'number' ? formatNumber(value) : String(value))} />
381
+ <Legend />
382
+ </RadarChart>
383
+ );
384
+ };
385
+
386
+ // Render RadialBar Chart
387
+ const renderRadialBarChart = () => {
388
+ const nKey = nameKey || 'name';
389
+ const vKey = valueKey || 'value';
390
+ const startAngle = options?.startAngle ?? 180;
391
+ const endAngle = options?.endAngle ?? 0;
392
+ const innerRadius = options?.innerRadius ?? 30;
393
+ return (
394
+ <RadialBarChart
395
+ cx="50%"
396
+ cy="50%"
397
+ innerRadius={innerRadius}
398
+ outerRadius={100}
399
+ barSize={15}
400
+ data={safeData}
401
+ startAngle={startAngle}
402
+ endAngle={endAngle}
403
+ >
404
+ <RadialBar
405
+ label={{ position: 'insideStart', fill: '#fff', fontSize: 11 }}
406
+ background
407
+ dataKey={vKey}
408
+ >
409
+ {safeData.map((_, index) => (
410
+ <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
411
+ ))}
412
+ </RadialBar>
413
+ <Tooltip formatter={(value) => (typeof value === 'number' ? formatNumber(value) : String(value))} />
414
+ <Legend
415
+ iconSize={10}
416
+ layout="vertical"
417
+ verticalAlign="middle"
418
+ align="right"
419
+ formatter={(value, entry) => {
420
+ const item = safeData.find((d) => d[nKey] === value || d[vKey] === entry.payload?.value);
421
+ return item ? item[nKey] : value;
422
+ }}
423
+ />
424
+ </RadialBarChart>
425
+ );
426
+ };
427
+
428
+ // Render Funnel Chart
429
+ const renderFunnelChart = () => {
430
+ const nKey = nameKey || 'name';
431
+ const vKey = valueKey || 'value';
432
+ return (
433
+ <FunnelChart>
434
+ <Tooltip formatter={(value) => (typeof value === 'number' ? formatNumber(value) : String(value))} />
435
+ <Funnel dataKey={vKey} data={safeData} isAnimationActive>
436
+ {safeData.map((_, index) => (
437
+ <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
438
+ ))}
439
+ {options?.showLabels !== false && (
440
+ <LabelList position="center" fill="#fff" stroke="none" dataKey={nKey} />
441
+ )}
442
+ </Funnel>
443
+ </FunnelChart>
444
+ );
445
+ };
446
+
447
+ // Render Treemap
448
+ const renderTreemap = () => {
449
+ const dKey = dataKey || valueKey || 'value';
450
+ return (
451
+ <Treemap
452
+ data={safeData}
453
+ dataKey={dKey}
454
+ aspectRatio={4 / 3}
455
+ stroke="#fff"
456
+ fill="#4f46e5"
457
+ content={({ x, y, width, height, name, value, index }) => {
458
+ const fill = COLORS[(index as number) % COLORS.length];
459
+ return (
460
+ <g>
461
+ <rect
462
+ x={x}
463
+ y={y}
464
+ width={width}
465
+ height={height}
466
+ style={{ fill, stroke: '#fff', strokeWidth: 2 }}
467
+ />
468
+ {(width as number) > 50 && (height as number) > 30 && (
469
+ <>
470
+ <text
471
+ x={(x as number) + (width as number) / 2}
472
+ y={(y as number) + (height as number) / 2 - 7}
473
+ textAnchor="middle"
474
+ fill="#fff"
475
+ fontSize={12}
476
+ >
477
+ {name}
478
+ </text>
479
+ <text
480
+ x={(x as number) + (width as number) / 2}
481
+ y={(y as number) + (height as number) / 2 + 10}
482
+ textAnchor="middle"
483
+ fill="#fff"
484
+ fontSize={11}
485
+ >
486
+ {formatNumber(value as number)}
487
+ </text>
488
+ </>
489
+ )}
490
+ </g>
491
+ );
492
+ }}
493
+ />
494
+ );
495
+ };
496
+
497
+ // Render chart based on type
498
+ const renderChart = () => {
499
+ switch (chart) {
500
+ case 'bar':
501
+ return (
502
+ <BarChart data={safeData}>
503
+ {commonAxes}
504
+ {commonOverlays}
505
+ {renderSeries()}
506
+ </BarChart>
507
+ );
508
+ case 'line':
509
+ return (
510
+ <LineChart data={safeData}>
511
+ {commonAxes}
512
+ {commonOverlays}
513
+ {renderSeries()}
514
+ </LineChart>
515
+ );
516
+ case 'area':
517
+ return (
518
+ <AreaChart data={safeData}>
519
+ {commonAxes}
520
+ {commonOverlays}
521
+ {renderSeries()}
522
+ </AreaChart>
523
+ );
524
+ case 'composed':
525
+ return (
526
+ <ComposedChart data={safeData}>
527
+ {commonAxes}
528
+ {commonOverlays}
529
+ {renderSeries()}
530
+ </ComposedChart>
531
+ );
532
+ case 'pie':
533
+ return renderPieChart();
534
+ case 'scatter':
535
+ return renderScatterChart();
536
+ case 'radar':
537
+ return renderRadarChart();
538
+ case 'radialBar':
539
+ return renderRadialBarChart();
540
+ case 'funnel':
541
+ return renderFunnelChart();
542
+ case 'treemap':
543
+ return renderTreemap();
544
+ default:
545
+ return (
546
+ <ComposedChart data={safeData}>
547
+ {commonAxes}
548
+ {commonOverlays}
549
+ {renderSeries()}
550
+ </ComposedChart>
551
+ );
552
+ }
553
+ };
554
+
555
+ return (
556
+ <div className="bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-800 shadow-sm">
557
+ <div className="flex flex-col gap-2 p-3">
558
+ <div className="flex items-center justify-between">
559
+ <span className="font-medium text-sm text-gray-900 dark:text-gray-100">
560
+ {title || 'Chart'}
561
+ </span>
562
+ <div className="flex items-center gap-2 print:hidden chart-actions">
563
+ <button
564
+ onClick={handleCopy}
565
+ disabled={isCopied}
566
+ className="text-xs px-2 py-1 rounded border border-gray-300 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer transition-colors disabled:opacity-50 flex items-center gap-1"
567
+ title="Copy to clipboard"
568
+ >
569
+ {isCopied ? <Check className="w-3 h-3" /> : <Copy className="w-3 h-3" />}
570
+ {isCopied ? 'Copied' : 'Copy'}
571
+ </button>
572
+ <button
573
+ onClick={handleExport}
574
+ disabled={isExporting}
575
+ className="text-xs px-2 py-1 rounded border border-gray-300 dark:border-gray-700 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-1"
576
+ title="Export as PNG"
577
+ >
578
+ <Download className="w-3 h-3" />
579
+ {isExporting ? 'Exporting...' : 'Export'}
580
+ </button>
581
+ </div>
582
+ </div>
583
+ {description && (
584
+ <span className="text-xs text-gray-500 dark:text-gray-400">
585
+ {description}
586
+ </span>
587
+ )}
588
+ <div ref={chartRef} className="bg-white dark:bg-gray-900 rounded" style={{ width: '100%', height: 280, minWidth: 0 }}>
589
+ <ChartErrorBoundary chartType={chart}>
590
+ <ResponsiveContainer width="100%" height="100%">
591
+ {renderChart()}
592
+ </ResponsiveContainer>
593
+ </ChartErrorBoundary>
594
+ </div>
595
+ </div>
596
+ </div>
597
+ );
598
+ }, (prevProps, nextProps) => {
599
+ // Deep compare the spec to prevent re-renders when data hasn't changed
600
+ return JSON.stringify(prevProps.spec) === JSON.stringify(nextProps.spec);
601
+ });