@agent-native/toolkit 0.213.1 → 0.214.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 (198) hide show
  1. package/agent-native.eject.json +9 -0
  2. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  3. package/dist/app/agentkit/react/components.js +10 -4
  4. package/dist/app/agentkit/react/components.js.map +1 -1
  5. package/dist/app/agentkit/react/context.d.ts +13 -1
  6. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  7. package/dist/app/agentkit/react/context.js +3 -1
  8. package/dist/app/agentkit/react/context.js.map +1 -1
  9. package/dist/app/agentkit/react/index.d.ts +1 -0
  10. package/dist/app/agentkit/react/index.d.ts.map +1 -1
  11. package/dist/app/agentkit/react/index.js +1 -0
  12. package/dist/app/agentkit/react/index.js.map +1 -1
  13. package/dist/app/agentkit/react/message-content-order.d.ts +21 -0
  14. package/dist/app/agentkit/react/message-content-order.d.ts.map +1 -0
  15. package/dist/app/agentkit/react/message-content-order.js +173 -0
  16. package/dist/app/agentkit/react/message-content-order.js.map +1 -0
  17. package/dist/app/agentkit/react/root.d.ts +3 -1
  18. package/dist/app/agentkit/react/root.d.ts.map +1 -1
  19. package/dist/app/agentkit/react/root.js +2 -2
  20. package/dist/app/agentkit/react/root.js.map +1 -1
  21. package/dist/app/agentkit/react/styles.css +2 -2
  22. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  23. package/dist/app/chat/AgentKitAssistantChat.js +7 -2
  24. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  25. package/dist/app/chat/AgentPanel.d.ts +14 -2
  26. package/dist/app/chat/AgentPanel.d.ts.map +1 -1
  27. package/dist/app/chat/AgentPanel.js +22 -5
  28. package/dist/app/chat/AgentPanel.js.map +1 -1
  29. package/dist/app/chat/chat/surface-types.d.ts +8 -0
  30. package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
  31. package/dist/app/chat/chat/surface-types.js.map +1 -1
  32. package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts.map +1 -1
  33. package/dist/app/chat/chat/widgets/DataChartRenderer.js +127 -30
  34. package/dist/app/chat/chat/widgets/DataChartRenderer.js.map +1 -1
  35. package/dist/app/chat/chat/widgets/DataChartWidget.d.ts +3 -2
  36. package/dist/app/chat/chat/widgets/DataChartWidget.d.ts.map +1 -1
  37. package/dist/app/chat/chat/widgets/DataChartWidget.js +14 -9
  38. package/dist/app/chat/chat/widgets/DataChartWidget.js.map +1 -1
  39. package/dist/app/chat/chat/widgets/DataInsightsWidget.js +1 -1
  40. package/dist/app/chat/chat/widgets/DataInsightsWidget.js.map +1 -1
  41. package/dist/app/chat/chat/widgets/DataTableWidget.d.ts +3 -2
  42. package/dist/app/chat/chat/widgets/DataTableWidget.d.ts.map +1 -1
  43. package/dist/app/chat/chat/widgets/DataTableWidget.js +10 -66
  44. package/dist/app/chat/chat/widgets/DataTableWidget.js.map +1 -1
  45. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts +11 -0
  46. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts.map +1 -0
  47. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js +131 -0
  48. package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js.map +1 -0
  49. package/dist/app/chat/chat/widgets/builtin-tool-renderers.js +2 -2
  50. package/dist/app/chat/chat/widgets/builtin-tool-renderers.js.map +1 -1
  51. package/dist/app/chat/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  52. package/dist/app/chat/mcp-apps/McpAppRenderer.js +6 -5
  53. package/dist/app/chat/mcp-apps/McpAppRenderer.js.map +1 -1
  54. package/dist/app/chat/mcp-apps/mcp-app-theme.d.ts +2 -0
  55. package/dist/app/chat/mcp-apps/mcp-app-theme.d.ts.map +1 -0
  56. package/dist/app/chat/mcp-apps/mcp-app-theme.js +11 -0
  57. package/dist/app/chat/mcp-apps/mcp-app-theme.js.map +1 -0
  58. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  59. package/dist/app/i18n/catalogs/ar-SA.js +8 -0
  60. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  61. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  62. package/dist/app/i18n/catalogs/de-DE.js +8 -0
  63. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  64. package/dist/app/i18n/catalogs/en-US.d.ts +8 -0
  65. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  66. package/dist/app/i18n/catalogs/en-US.js +8 -0
  67. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  68. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  69. package/dist/app/i18n/catalogs/es-ES.js +8 -0
  70. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  71. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  72. package/dist/app/i18n/catalogs/fr-FR.js +8 -0
  73. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  74. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  75. package/dist/app/i18n/catalogs/hi-IN.js +8 -0
  76. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  77. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  78. package/dist/app/i18n/catalogs/ja-JP.js +8 -0
  79. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  80. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  81. package/dist/app/i18n/catalogs/ko-KR.js +8 -0
  82. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  83. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  84. package/dist/app/i18n/catalogs/pt-BR.js +8 -0
  85. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  86. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  87. package/dist/app/i18n/catalogs/zh-CN.js +8 -0
  88. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  89. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  90. package/dist/app/i18n/catalogs/zh-TW.js +8 -0
  91. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  92. package/dist/app/providers/AppProviders.d.ts +2 -1
  93. package/dist/app/providers/AppProviders.d.ts.map +1 -1
  94. package/dist/app/providers/AppProviders.js +4 -3
  95. package/dist/app/providers/AppProviders.js.map +1 -1
  96. package/dist/app/providers/ThemeFamilySync.d.ts +2 -0
  97. package/dist/app/providers/ThemeFamilySync.d.ts.map +1 -0
  98. package/dist/app/providers/ThemeFamilySync.js +6 -0
  99. package/dist/app/providers/ThemeFamilySync.js.map +1 -0
  100. package/dist/app/settings/account/PreferencesSettings.d.ts.map +1 -1
  101. package/dist/app/settings/account/PreferencesSettings.js +2 -1
  102. package/dist/app/settings/account/PreferencesSettings.js.map +1 -1
  103. package/dist/app/settings/account/ThemeFamilySettings.d.ts +2 -0
  104. package/dist/app/settings/account/ThemeFamilySettings.d.ts.map +1 -0
  105. package/dist/app/settings/account/ThemeFamilySettings.js +31 -0
  106. package/dist/app/settings/account/ThemeFamilySettings.js.map +1 -0
  107. package/dist/app/settings/account/search-entries.d.ts.map +1 -1
  108. package/dist/app/settings/account/search-entries.js +6 -0
  109. package/dist/app/settings/account/search-entries.js.map +1 -1
  110. package/dist/app/shared/DefaultSpinner.d.ts.map +1 -1
  111. package/dist/app/shared/DefaultSpinner.js +4 -5
  112. package/dist/app/shared/DefaultSpinner.js.map +1 -1
  113. package/dist/app/shared/ErrorBoundary.d.ts +1 -0
  114. package/dist/app/shared/ErrorBoundary.d.ts.map +1 -1
  115. package/dist/app/shared/ErrorBoundary.js +27 -12
  116. package/dist/app/shared/ErrorBoundary.js.map +1 -1
  117. package/dist/app/shared/PoweredByBadge.d.ts.map +1 -1
  118. package/dist/app/shared/PoweredByBadge.js +8 -49
  119. package/dist/app/shared/PoweredByBadge.js.map +1 -1
  120. package/dist/app/styles/agent-conversation.css +0 -23
  121. package/dist/app/styles/agent-native.css +1 -1
  122. package/dist/app/styles/theme-families.css +66 -0
  123. package/dist/composer/ComposerContextBanner.d.ts +22 -0
  124. package/dist/composer/ComposerContextBanner.d.ts.map +1 -0
  125. package/dist/composer/ComposerContextBanner.js +9 -0
  126. package/dist/composer/ComposerContextBanner.js.map +1 -0
  127. package/dist/composer/ComposerModePicker.d.ts +26 -0
  128. package/dist/composer/ComposerModePicker.d.ts.map +1 -0
  129. package/dist/composer/ComposerModePicker.js +14 -0
  130. package/dist/composer/ComposerModePicker.js.map +1 -0
  131. package/dist/composer/index.d.ts +2 -0
  132. package/dist/composer/index.d.ts.map +1 -1
  133. package/dist/composer/index.js +2 -0
  134. package/dist/composer/index.js.map +1 -1
  135. package/dist/styles.css +1 -0
  136. package/package.json +3 -3
  137. package/src/app/agentkit/react/components.spec.tsx +12 -0
  138. package/src/app/agentkit/react/components.tsx +41 -22
  139. package/src/app/agentkit/react/context.tsx +17 -0
  140. package/src/app/agentkit/react/index.ts +1 -0
  141. package/src/app/agentkit/react/lifecycle.spec.tsx +116 -1
  142. package/src/app/agentkit/react/message-content-order.spec.ts +190 -0
  143. package/src/app/agentkit/react/message-content-order.ts +246 -0
  144. package/src/app/agentkit/react/root.tsx +4 -0
  145. package/src/app/agentkit/react/styles.css +2 -2
  146. package/src/app/chat/AgentKitAssistantChat.spec.tsx +19 -0
  147. package/src/app/chat/AgentKitAssistantChat.tsx +10 -1
  148. package/src/app/chat/AgentPanel.header.spec.ts +72 -14
  149. package/src/app/chat/AgentPanel.tsx +97 -53
  150. package/src/app/chat/chat/surface-types.ts +8 -0
  151. package/src/app/chat/chat/widgets/DataChartRenderer.spec.tsx +217 -0
  152. package/src/app/chat/chat/widgets/DataChartRenderer.tsx +306 -68
  153. package/src/app/chat/chat/widgets/DataChartWidget.spec.tsx +329 -0
  154. package/src/app/chat/chat/widgets/DataChartWidget.ssr.spec.tsx +25 -0
  155. package/src/app/chat/chat/widgets/DataChartWidget.tsx +48 -33
  156. package/src/app/chat/chat/widgets/DataInsightsWidget.tsx +2 -2
  157. package/src/app/chat/chat/widgets/DataTableWidget.spec.tsx +37 -3
  158. package/src/app/chat/chat/widgets/DataTableWidget.tsx +22 -86
  159. package/src/app/chat/chat/widgets/DataWidgetDisplayControls.tsx +301 -0
  160. package/src/app/chat/chat/widgets/builtin-tool-renderers.tsx +5 -5
  161. package/src/app/chat/mcp-apps/McpAppRenderer.tsx +10 -5
  162. package/src/app/chat/mcp-apps/mcp-app-theme.spec.ts +30 -0
  163. package/src/app/chat/mcp-apps/mcp-app-theme.ts +11 -0
  164. package/src/app/i18n/catalogs/ar-SA.ts +9 -0
  165. package/src/app/i18n/catalogs/de-DE.ts +9 -0
  166. package/src/app/i18n/catalogs/en-US.ts +9 -0
  167. package/src/app/i18n/catalogs/es-ES.ts +10 -0
  168. package/src/app/i18n/catalogs/fr-FR.ts +10 -0
  169. package/src/app/i18n/catalogs/hi-IN.ts +9 -0
  170. package/src/app/i18n/catalogs/ja-JP.ts +9 -0
  171. package/src/app/i18n/catalogs/ko-KR.ts +9 -0
  172. package/src/app/i18n/catalogs/pt-BR.ts +9 -0
  173. package/src/app/i18n/catalogs/zh-CN.ts +8 -0
  174. package/src/app/i18n/catalogs/zh-TW.ts +9 -0
  175. package/src/app/providers/AppProviders.spec.tsx +71 -0
  176. package/src/app/providers/AppProviders.tsx +10 -0
  177. package/src/app/providers/ThemeFamilySync.tsx +6 -0
  178. package/src/app/settings/account/PreferencesSettings.spec.tsx +13 -2
  179. package/src/app/settings/account/PreferencesSettings.tsx +8 -0
  180. package/src/app/settings/account/ThemeFamilySettings.tsx +61 -0
  181. package/src/app/settings/account/search-entries.ts +6 -0
  182. package/src/app/shared/DefaultSpinner.spec.tsx +14 -0
  183. package/src/app/shared/DefaultSpinner.tsx +4 -5
  184. package/src/app/shared/ErrorBoundary.spec.tsx +45 -2
  185. package/src/app/shared/ErrorBoundary.tsx +37 -12
  186. package/src/app/shared/PoweredByBadge.spec.tsx +16 -0
  187. package/src/app/shared/PoweredByBadge.tsx +8 -50
  188. package/src/app/styles/agent-conversation.css +0 -23
  189. package/src/app/styles/agent-native.css +1 -1
  190. package/src/app/styles/agent-native.spec.ts +18 -0
  191. package/src/app/styles/theme-families.css +66 -0
  192. package/src/app/styles/theme-families.spec.ts +29 -0
  193. package/src/composer/ComposerContextBanner.spec.tsx +74 -0
  194. package/src/composer/ComposerContextBanner.tsx +72 -0
  195. package/src/composer/ComposerModePicker.spec.tsx +101 -0
  196. package/src/composer/ComposerModePicker.tsx +98 -0
  197. package/src/composer/index.ts +9 -0
  198. package/src/styles.css +1 -0
@@ -3,17 +3,21 @@ import { useT } from "@agent-native/core/client/i18n";
3
3
  import type { DataChartWidget as DataChartWidgetData } from "./data-widget-types.js";
4
4
 
5
5
  const DEFAULT_COLORS = [
6
- "hsl(var(--primary))",
7
- "hsl(199 89% 48%)",
8
- "hsl(151 55% 42%)",
9
- "hsl(35 92% 50%)",
6
+ "hsl(var(--chart-1, var(--primary)))",
7
+ "hsl(var(--chart-2, 199 89% 48%))",
8
+ "hsl(var(--chart-3, 151 55% 42%))",
9
+ "hsl(var(--chart-4, 35 92% 50%))",
10
10
  ];
11
11
 
12
12
  const WIDTH = 640;
13
- const HEIGHT = 240;
13
+ const HEIGHT = 360;
14
14
  const MARGIN = { top: 14, right: 18, bottom: 34, left: 46 };
15
- const PLOT_WIDTH = WIDTH - MARGIN.left - MARGIN.right;
16
- const PLOT_HEIGHT = HEIGHT - MARGIN.top - MARGIN.bottom;
15
+ const MAX_LABEL_LENGTH = 16;
16
+ const LABEL_FONT_FAMILIES = {
17
+ sans: "var(--font-sans, ui-sans-serif, system-ui, sans-serif)",
18
+ serif: "ui-serif, Georgia, Cambria, serif",
19
+ mono: "ui-monospace, SFMono-Regular, Menlo, monospace",
20
+ } as const;
17
21
 
18
22
  function numericValue(
19
23
  row: Record<string, unknown>,
@@ -35,8 +39,17 @@ function formatTick(value: number): string {
35
39
  }
36
40
 
37
41
  function labelFor(value: unknown): string {
38
- const label = value == null ? "" : String(value);
39
- return label.length > 16 ? `${label.slice(0, 15)}...` : label;
42
+ const characters = Array.from(value == null ? "" : String(value));
43
+ return characters.length > MAX_LABEL_LENGTH
44
+ ? `${characters.slice(0, MAX_LABEL_LENGTH - 3).join("")}...`
45
+ : characters.join("");
46
+ }
47
+
48
+ function estimateTextWidth(text: string, fontSize: number): number {
49
+ return Array.from(text).reduce((width, character) => {
50
+ const codePoint = character.codePointAt(0) ?? 0;
51
+ return width + (codePoint >= 0x2e80 ? fontSize : fontSize * 0.65);
52
+ }, 0);
40
53
  }
41
54
 
42
55
  function rangeFor(chart: DataChartWidgetData) {
@@ -61,76 +74,215 @@ function rangeFor(chart: DataChartWidgetData) {
61
74
  return { min, max };
62
75
  }
63
76
 
64
- function ChartBody({ chart }: { chart: DataChartWidgetData }) {
77
+ function ChartBody({
78
+ chart,
79
+ labelFontSize,
80
+ }: {
81
+ chart: DataChartWidgetData;
82
+ labelFontSize: number;
83
+ }) {
65
84
  const { min, max } = rangeFor(chart);
66
- const yFor = (value: number) =>
67
- MARGIN.top + ((max - value) / (max - min)) * PLOT_HEIGHT;
85
+ const isHorizontalBar = chart.type === "bar" && chart.layout === "horizontal";
86
+ const horizontalCategoryWidth = isHorizontalBar
87
+ ? Math.max(
88
+ 0,
89
+ ...chart.data.map((row) =>
90
+ estimateTextWidth(labelFor(row[chart.xKey]), labelFontSize),
91
+ ),
92
+ )
93
+ : 0;
94
+ const horizontalPositiveValueWidth =
95
+ isHorizontalBar && chart.showValueLabels
96
+ ? Math.max(
97
+ 0,
98
+ ...chart.data.flatMap((row) =>
99
+ chart.series
100
+ .map((series) => numericValue(row, series.key))
101
+ .filter((value): value is number => value !== null && value >= 0)
102
+ .map((value) =>
103
+ estimateTextWidth(
104
+ formatTick(value),
105
+ chart.valueLabelFontSize ?? 11,
106
+ ),
107
+ ),
108
+ ),
109
+ )
110
+ : 0;
111
+ const horizontalNegativeValueWidth =
112
+ isHorizontalBar && chart.showValueLabels
113
+ ? Math.max(
114
+ 0,
115
+ ...chart.data.flatMap((row) =>
116
+ chart.series
117
+ .map((series) => numericValue(row, series.key))
118
+ .filter((value): value is number => value !== null && value < 0)
119
+ .map((value) =>
120
+ estimateTextWidth(
121
+ formatTick(value),
122
+ chart.valueLabelFontSize ?? 11,
123
+ ),
124
+ ),
125
+ ),
126
+ )
127
+ : 0;
128
+ const categoryMargin =
129
+ Math.max(MARGIN.left, horizontalCategoryWidth + 14) +
130
+ (chart.yAxisTitle ? 20 : 0);
131
+ const categoryLabelX = categoryMargin - 8;
132
+ const margin = {
133
+ ...MARGIN,
134
+ left:
135
+ categoryMargin +
136
+ (horizontalNegativeValueWidth > 0
137
+ ? horizontalNegativeValueWidth + 13
138
+ : 0),
139
+ right: Math.max(MARGIN.right, horizontalPositiveValueWidth + 13),
140
+ bottom: MARGIN.bottom + (chart.xAxisTitle ? 16 : 0),
141
+ };
142
+ const plotWidth = WIDTH - margin.left - margin.right;
143
+ const plotHeight = HEIGHT - margin.top - margin.bottom;
144
+ const xForValue = (value: number) =>
145
+ margin.left + ((value - min) / (max - min)) * plotWidth;
146
+ const yForValue = (value: number) =>
147
+ margin.top + ((max - value) / (max - min)) * plotHeight;
68
148
  const xForPoint = (index: number) =>
69
149
  chart.data.length <= 1
70
- ? MARGIN.left + PLOT_WIDTH / 2
71
- : MARGIN.left + (index / (chart.data.length - 1)) * PLOT_WIDTH;
150
+ ? margin.left + plotWidth / 2
151
+ : margin.left + (index / (chart.data.length - 1)) * plotWidth;
152
+ const yForRow = (index: number) =>
153
+ margin.top + ((index + 0.5) * plotHeight) / Math.max(1, chart.data.length);
72
154
  const gridTicks = Array.from({ length: 4 }, (_, index) => {
73
155
  const value = min + ((max - min) * index) / 3;
74
- return { value, y: yFor(value) };
156
+ return {
157
+ value,
158
+ x: xForValue(value),
159
+ y: yForValue(value),
160
+ };
75
161
  });
76
162
  const xTickEvery = Math.max(1, Math.ceil(chart.data.length / 6));
77
- const zeroY = yFor(Math.max(min, Math.min(max, 0)));
163
+ const zero = Math.max(min, Math.min(max, 0));
164
+ const zeroX = xForValue(zero);
165
+ const zeroY = yForValue(zero);
166
+ const axisTitleFontSize = chart.axisTitleFontSize ?? 11;
167
+ const axisTitleFontWeight = chart.axisTitleFontWeight ?? 500;
168
+ const valueLabelFontSize = chart.valueLabelFontSize ?? 11;
169
+ const valueLabelFontWeight = chart.valueLabelFontWeight ?? 400;
78
170
 
79
171
  const axes = (
80
172
  <g aria-hidden="true">
81
- {gridTicks.map((tick) => (
82
- <g key={tick.y}>
83
- <line
84
- x1={MARGIN.left}
85
- x2={WIDTH - MARGIN.right}
86
- y1={tick.y}
87
- y2={tick.y}
88
- stroke="hsl(var(--border))"
89
- strokeDasharray="3 3"
90
- />
173
+ {gridTicks.map((tick) =>
174
+ isHorizontalBar ? (
175
+ <g key={tick.x}>
176
+ <line
177
+ x1={tick.x}
178
+ x2={tick.x}
179
+ y1={margin.top}
180
+ y2={HEIGHT - margin.bottom}
181
+ stroke="hsl(var(--border))"
182
+ strokeDasharray="3 3"
183
+ />
184
+ <text
185
+ x={tick.x}
186
+ y={HEIGHT - margin.bottom + 14}
187
+ fill="hsl(var(--muted-foreground))"
188
+ fontSize={labelFontSize}
189
+ textAnchor="middle"
190
+ >
191
+ {formatTick(tick.value)}
192
+ </text>
193
+ </g>
194
+ ) : (
195
+ <g key={tick.y}>
196
+ <line
197
+ x1={margin.left}
198
+ x2={WIDTH - margin.right}
199
+ y1={tick.y}
200
+ y2={tick.y}
201
+ stroke="hsl(var(--border))"
202
+ strokeDasharray="3 3"
203
+ />
204
+ <text
205
+ x={margin.left - 8}
206
+ y={tick.y + 4}
207
+ fill="hsl(var(--muted-foreground))"
208
+ fontSize={labelFontSize}
209
+ textAnchor="end"
210
+ >
211
+ {formatTick(tick.value)}
212
+ </text>
213
+ </g>
214
+ ),
215
+ )}
216
+ <line
217
+ x1={isHorizontalBar ? zeroX : margin.left}
218
+ x2={isHorizontalBar ? zeroX : WIDTH - margin.right}
219
+ y1={isHorizontalBar ? margin.top : zeroY}
220
+ y2={isHorizontalBar ? HEIGHT - margin.bottom : zeroY}
221
+ stroke="hsl(var(--border))"
222
+ />
223
+ {chart.data.map((row, index) =>
224
+ isHorizontalBar ? (
91
225
  <text
92
- x={MARGIN.left - 8}
93
- y={tick.y + 4}
226
+ key={`${index}-${String(row[chart.xKey] ?? "")}`}
227
+ x={categoryLabelX}
228
+ y={yForRow(index) + labelFontSize * 0.35}
94
229
  fill="hsl(var(--muted-foreground))"
95
- fontSize="11"
230
+ fontSize={labelFontSize}
96
231
  textAnchor="end"
97
232
  >
98
- {formatTick(tick.value)}
233
+ {labelFor(row[chart.xKey])}
99
234
  </text>
100
- </g>
101
- ))}
102
- <line
103
- x1={MARGIN.left}
104
- x2={WIDTH - MARGIN.right}
105
- y1={zeroY}
106
- y2={zeroY}
107
- stroke="hsl(var(--border))"
108
- />
109
- {chart.data.map((row, index) =>
110
- index % xTickEvery === 0 || index === chart.data.length - 1 ? (
235
+ ) : index % xTickEvery === 0 || index === chart.data.length - 1 ? (
111
236
  <text
112
237
  key={`${index}-${String(row[chart.xKey] ?? "")}`}
113
238
  x={
114
239
  chart.type === "bar"
115
- ? MARGIN.left + (index + 0.5) * (PLOT_WIDTH / chart.data.length)
240
+ ? margin.left + (index + 0.5) * (plotWidth / chart.data.length)
116
241
  : xForPoint(index)
117
242
  }
118
243
  y={HEIGHT - 12}
119
244
  fill="hsl(var(--muted-foreground))"
120
- fontSize="11"
245
+ fontSize={labelFontSize}
121
246
  textAnchor="middle"
122
247
  >
123
248
  {labelFor(row[chart.xKey])}
124
249
  </text>
125
250
  ) : null,
126
251
  )}
252
+ {chart.xAxisTitle ? (
253
+ <text
254
+ x={margin.left + plotWidth / 2}
255
+ y={HEIGHT - 4}
256
+ fill="hsl(var(--foreground))"
257
+ fontSize={axisTitleFontSize}
258
+ fontWeight={axisTitleFontWeight}
259
+ textAnchor="middle"
260
+ >
261
+ {chart.xAxisTitle}
262
+ </text>
263
+ ) : null}
264
+ {chart.yAxisTitle ? (
265
+ <text
266
+ x={14}
267
+ y={margin.top + plotHeight / 2}
268
+ transform={`rotate(-90 14 ${margin.top + plotHeight / 2})`}
269
+ fill="hsl(var(--foreground))"
270
+ fontSize={axisTitleFontSize}
271
+ fontWeight={axisTitleFontWeight}
272
+ textAnchor="middle"
273
+ >
274
+ {chart.yAxisTitle}
275
+ </text>
276
+ ) : null}
127
277
  </g>
128
278
  );
129
279
 
130
280
  if (chart.type === "bar") {
131
- const slotWidth = PLOT_WIDTH / Math.max(1, chart.data.length);
132
- const groupWidth = slotWidth * 0.72;
133
- const barWidth = groupWidth / Math.max(1, chart.series.length);
281
+ const slotSize =
282
+ (isHorizontalBar ? plotHeight : plotWidth) /
283
+ Math.max(1, chart.data.length);
284
+ const groupSize = slotSize * 0.72;
285
+ const barSize = groupSize / Math.max(1, chart.series.length);
134
286
  return (
135
287
  <>
136
288
  {axes}
@@ -141,23 +293,59 @@ function ChartBody({ chart }: { chart: DataChartWidgetData }) {
141
293
  const color =
142
294
  series.color ??
143
295
  DEFAULT_COLORS[seriesIndex % DEFAULT_COLORS.length];
144
- const y = yFor(Math.max(value, 0));
145
- const height = Math.max(1, Math.abs(zeroY - yFor(value)));
296
+ const valueX = xForValue(value);
297
+ const valueY = yForValue(value);
298
+ const x = isHorizontalBar
299
+ ? Math.min(zeroX, valueX)
300
+ : margin.left +
301
+ rowIndex * slotSize +
302
+ (slotSize - groupSize) / 2 +
303
+ seriesIndex * barSize;
304
+ const y = isHorizontalBar
305
+ ? margin.top +
306
+ rowIndex * slotSize +
307
+ (slotSize - groupSize) / 2 +
308
+ seriesIndex * barSize
309
+ : yForValue(Math.max(value, 0));
310
+ const width = isHorizontalBar
311
+ ? Math.max(2, Math.abs(valueX - zeroX))
312
+ : Math.max(2, barSize - 2);
313
+ const height = isHorizontalBar
314
+ ? Math.max(2, barSize - 2)
315
+ : Math.max(1, Math.abs(zeroY - valueY));
146
316
  return (
147
- <rect
148
- key={`${rowIndex}-${series.key}`}
149
- x={
150
- MARGIN.left +
151
- rowIndex * slotWidth +
152
- (slotWidth - groupWidth) / 2 +
153
- seriesIndex * barWidth
154
- }
155
- y={y}
156
- width={Math.max(2, barWidth - 2)}
157
- height={height}
158
- rx="3"
159
- fill={color}
160
- />
317
+ <g key={`${rowIndex}-${series.key}`}>
318
+ <rect
319
+ x={x}
320
+ y={y}
321
+ width={width}
322
+ height={height}
323
+ rx="3"
324
+ fill={color}
325
+ />
326
+ {chart.showValueLabels ? (
327
+ <text
328
+ x={
329
+ isHorizontalBar
330
+ ? valueX + (value < 0 ? -5 : 5)
331
+ : x + width / 2
332
+ }
333
+ y={
334
+ isHorizontalBar
335
+ ? y + height / 2 + valueLabelFontSize * 0.35
336
+ : y - 5
337
+ }
338
+ fill="hsl(var(--muted-foreground))"
339
+ fontSize={valueLabelFontSize}
340
+ fontWeight={valueLabelFontWeight}
341
+ textAnchor={
342
+ isHorizontalBar ? (value < 0 ? "end" : "start") : "middle"
343
+ }
344
+ >
345
+ {formatTick(value)}
346
+ </text>
347
+ ) : null}
348
+ </g>
161
349
  );
162
350
  }),
163
351
  )}
@@ -171,9 +359,12 @@ function ChartBody({ chart }: { chart: DataChartWidgetData }) {
171
359
  const value = numericValue(row, series.key);
172
360
  return value === null
173
361
  ? null
174
- : { x: xForPoint(rowIndex), y: yFor(value) };
362
+ : { x: xForPoint(rowIndex), y: yForValue(value), value };
175
363
  })
176
- .filter((point): point is { x: number; y: number } => point !== null);
364
+ .filter(
365
+ (point): point is { x: number; y: number; value: number } =>
366
+ point !== null,
367
+ );
177
368
  const color =
178
369
  series.color ?? DEFAULT_COLORS[seriesIndex % DEFAULT_COLORS.length];
179
370
  const linePath = points
@@ -221,6 +412,35 @@ function ChartBody({ chart }: { chart: DataChartWidgetData }) {
221
412
  strokeWidth="2"
222
413
  />
223
414
  ))}
415
+ {chart.showValueLabels
416
+ ? points.map((point, index) => {
417
+ const abovePoint =
418
+ point.y - valueLabelFontSize - 5 >= margin.top;
419
+ return (
420
+ <text
421
+ key={`value-${index}`}
422
+ x={point.x}
423
+ y={
424
+ abovePoint
425
+ ? point.y - 5
426
+ : point.y + valueLabelFontSize + 5
427
+ }
428
+ fill="hsl(var(--muted-foreground))"
429
+ fontSize={valueLabelFontSize}
430
+ fontWeight={valueLabelFontWeight}
431
+ textAnchor={
432
+ point.x <= margin.left
433
+ ? "start"
434
+ : point.x >= WIDTH - margin.right
435
+ ? "end"
436
+ : "middle"
437
+ }
438
+ >
439
+ {formatTick(point.value)}
440
+ </text>
441
+ );
442
+ })
443
+ : null}
224
444
  </g>
225
445
  ))}
226
446
  </>
@@ -229,16 +449,34 @@ function ChartBody({ chart }: { chart: DataChartWidgetData }) {
229
449
 
230
450
  export function DataChartRenderer({ chart }: { chart: DataChartWidgetData }) {
231
451
  const t = useT();
452
+ const contentHeight = chart.contentHeight;
453
+ const contentPadding = chart.contentPadding ?? 0;
454
+ const hasContentBox = contentHeight !== undefined || contentPadding > 0;
455
+ const labelFontFamily = LABEL_FONT_FAMILIES[chart.labelFontFamily ?? "sans"];
456
+ const labelFontSize = chart.labelFontSize ?? 11;
232
457
  return (
233
- <div className="h-60 w-full min-w-0 overflow-hidden">
458
+ <div
459
+ className="box-border w-full min-w-0 overflow-hidden"
460
+ style={
461
+ hasContentBox
462
+ ? {
463
+ ...(contentHeight !== undefined
464
+ ? { height: `${contentHeight}px` }
465
+ : {}),
466
+ padding: `${contentPadding}px`,
467
+ }
468
+ : undefined
469
+ }
470
+ >
234
471
  <svg
235
- className="agent-data-chart-renderer h-full w-full"
472
+ className={`agent-data-chart-renderer block w-full ${contentHeight !== undefined ? "h-full" : "h-auto"}`}
236
473
  viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
474
+ preserveAspectRatio={contentHeight !== undefined ? "none" : undefined}
475
+ fontFamily={labelFontFamily}
237
476
  role="img"
238
477
  aria-label={chart.title ?? t("agentChat.widget.dataChart")}
239
- preserveAspectRatio="none"
240
478
  >
241
- <ChartBody chart={chart} />
479
+ <ChartBody chart={chart} labelFontSize={labelFontSize} />
242
480
  </svg>
243
481
  </div>
244
482
  );