@agent-native/toolkit 0.217.0 → 0.219.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.
- package/agent-native.eject.json +21 -0
- package/dist/app/agent-page/AgentContextTab.d.ts.map +1 -1
- package/dist/app/agent-page/AgentContextTab.js +1 -0
- package/dist/app/agent-page/AgentContextTab.js.map +1 -1
- package/dist/app/agentkit/react/components.d.ts.map +1 -1
- package/dist/app/agentkit/react/components.js +1 -1
- package/dist/app/agentkit/react/components.js.map +1 -1
- package/dist/app/agentkit/react/context.d.ts +4 -1
- package/dist/app/agentkit/react/context.d.ts.map +1 -1
- package/dist/app/agentkit/react/context.js +3 -1
- package/dist/app/agentkit/react/context.js.map +1 -1
- package/dist/app/agentkit/react/data-chart-layout.d.ts +30 -0
- package/dist/app/agentkit/react/data-chart-layout.d.ts.map +1 -0
- package/dist/app/agentkit/react/data-chart-layout.js +2 -0
- package/dist/app/agentkit/react/data-chart-layout.js.map +1 -0
- package/dist/app/agentkit/react/index.d.ts +1 -0
- package/dist/app/agentkit/react/index.d.ts.map +1 -1
- package/dist/app/agentkit/react/index.js +1 -0
- package/dist/app/agentkit/react/index.js.map +1 -1
- package/dist/app/agentkit/react/root.d.ts +3 -1
- package/dist/app/agentkit/react/root.d.ts.map +1 -1
- package/dist/app/agentkit/react/root.js +2 -2
- package/dist/app/agentkit/react/root.js.map +1 -1
- package/dist/app/agentkit/react/styles.css +31 -6
- package/dist/app/agentkit/react/transcript-layout.d.ts +2 -0
- package/dist/app/agentkit/react/transcript-layout.d.ts.map +1 -1
- package/dist/app/agentkit/react/transcript-layout.js.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js +2 -2
- package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
- package/dist/app/chat/AgentPanel.js +6 -6
- package/dist/app/chat/AgentPanel.js.map +1 -1
- package/dist/app/chat/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/MultiTabAssistantChat.js +53 -95
- package/dist/app/chat/MultiTabAssistantChat.js.map +1 -1
- package/dist/app/chat/agentkit-chat/action-widget.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/action-widget.js +4 -1
- package/dist/app/chat/agentkit-chat/action-widget.js.map +1 -1
- package/dist/app/chat/agentkit-chat/rail.d.ts +1 -1
- package/dist/app/chat/agentkit-chat/rail.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/rail.js +1 -1
- package/dist/app/chat/agentkit-chat/rail.js.map +1 -1
- package/dist/app/chat/chat/index.d.ts +2 -1
- package/dist/app/chat/chat/index.d.ts.map +1 -1
- package/dist/app/chat/chat/index.js +1 -1
- package/dist/app/chat/chat/index.js.map +1 -1
- package/dist/app/chat/chat/surface-types.d.ts +3 -0
- package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
- package/dist/app/chat/chat/surface-types.js.map +1 -1
- package/dist/app/chat/chat/tool-call-display.d.ts +5 -1
- package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
- package/dist/app/chat/chat/tool-call-display.js +6 -4
- package/dist/app/chat/chat/tool-call-display.js.map +1 -1
- package/dist/app/chat/chat/tool-render-registry.d.ts +4 -0
- package/dist/app/chat/chat/tool-render-registry.d.ts.map +1 -1
- package/dist/app/chat/chat/tool-render-registry.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts +3 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.js +116 -26
- package/dist/app/chat/chat/widgets/DataChartRenderer.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.d.ts +3 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.js +21 -2
- package/dist/app/chat/chat/widgets/DataChartWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.d.ts +3 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.js +2 -2
- package/dist/app/chat/chat/widgets/DataInsightsWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts +1 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js +3 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js.map +1 -1
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.js +2 -2
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.js.map +1 -1
- package/dist/app/chat/chat-first/chat-history.d.ts +13 -2
- package/dist/app/chat/chat-first/chat-history.d.ts.map +1 -1
- package/dist/app/chat/chat-first/chat-history.js +24 -3
- package/dist/app/chat/chat-first/chat-history.js.map +1 -1
- package/dist/app/chat/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/app/chat/conversation/AgentConversation.js +6 -1
- package/dist/app/chat/conversation/AgentConversation.js.map +1 -1
- package/dist/app/chat/ownership-history/ChatOwnerAvatar.d.ts +6 -0
- package/dist/app/chat/ownership-history/ChatOwnerAvatar.d.ts.map +1 -0
- package/dist/app/chat/ownership-history/ChatOwnerAvatar.js +9 -0
- package/dist/app/chat/ownership-history/ChatOwnerAvatar.js.map +1 -0
- package/dist/app/chat/ownership-history/index.d.ts +11 -0
- package/dist/app/chat/ownership-history/index.d.ts.map +1 -0
- package/dist/app/chat/ownership-history/index.js +22 -0
- package/dist/app/chat/ownership-history/index.js.map +1 -0
- package/dist/app/chat/ownership-history/rows.d.ts +27 -0
- package/dist/app/chat/ownership-history/rows.d.ts.map +1 -0
- package/dist/app/chat/ownership-history/rows.js +101 -0
- package/dist/app/chat/ownership-history/rows.js.map +1 -0
- package/dist/app/chat/ownership-history/useOwnershipChatHistory.d.ts +52 -0
- package/dist/app/chat/ownership-history/useOwnershipChatHistory.d.ts.map +1 -0
- package/dist/app/chat/ownership-history/useOwnershipChatHistory.js +497 -0
- package/dist/app/chat/ownership-history/useOwnershipChatHistory.js.map +1 -0
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +3 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +3 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +3 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +3 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +3 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +3 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +3 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +3 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +3 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +3 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +3 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +3 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/shared/CommandMenu.d.ts +2 -0
- package/dist/app/shared/CommandMenu.d.ts.map +1 -1
- package/dist/app/shared/CommandMenu.js +11 -6
- package/dist/app/shared/CommandMenu.js.map +1 -1
- package/dist/app/sharing/ShareButton.d.ts.map +1 -1
- package/dist/app/sharing/ShareButton.js +9 -8
- package/dist/app/sharing/ShareButton.js.map +1 -1
- package/dist/chat-history/ChatHistoryList.d.ts +16 -3
- package/dist/chat-history/ChatHistoryList.d.ts.map +1 -1
- package/dist/chat-history/ChatHistoryList.js +25 -15
- package/dist/chat-history/ChatHistoryList.js.map +1 -1
- package/dist/chat-history.css +109 -9
- package/dist/composer/TiptapComposer.js +1 -1
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/package.json +10 -3
- package/src/app/agent-page/AgentContextTab.spec.ts +50 -2
- package/src/app/agent-page/AgentContextTab.tsx +1 -0
- package/src/app/agentkit/react/components.interaction.spec.tsx +2 -0
- package/src/app/agentkit/react/components.spec.tsx +11 -6
- package/src/app/agentkit/react/components.tsx +3 -0
- package/src/app/agentkit/react/context.tsx +6 -0
- package/src/app/agentkit/react/data-chart-layout.ts +25 -0
- package/src/app/agentkit/react/index.ts +1 -0
- package/src/app/agentkit/react/root.tsx +4 -0
- package/src/app/agentkit/react/styles.css +31 -6
- package/src/app/agentkit/react/transcript-layout.ts +2 -0
- package/src/app/chat/AgentKitAssistantChat.spec.tsx +201 -27
- package/src/app/chat/AgentKitAssistantChat.tsx +3 -0
- package/src/app/chat/AgentPanel.tsx +8 -8
- package/src/app/chat/MultiTabAssistantChat.spec.tsx +270 -3
- package/src/app/chat/MultiTabAssistantChat.tsx +81 -158
- package/src/app/chat/agentkit-chat/action-widget.spec.tsx +62 -0
- package/src/app/chat/agentkit-chat/action-widget.tsx +4 -0
- package/src/app/chat/agentkit-chat/rail.ts +11 -0
- package/src/app/chat/chat/index.ts +10 -0
- package/src/app/chat/chat/surface-types.ts +3 -0
- package/src/app/chat/chat/tool-call-display.spec.tsx +29 -0
- package/src/app/chat/chat/tool-call-display.tsx +17 -1
- package/src/app/chat/chat/tool-render-registry.tsx +5 -0
- package/src/app/chat/chat/widgets/DataChartRenderer.spec.tsx +377 -17
- package/src/app/chat/chat/widgets/DataChartRenderer.tsx +232 -63
- package/src/app/chat/chat/widgets/DataChartWidget.spec.tsx +67 -0
- package/src/app/chat/chat/widgets/DataChartWidget.tsx +39 -5
- package/src/app/chat/chat/widgets/DataInsightsWidget.tsx +13 -2
- package/src/app/chat/chat/widgets/DataWidgetDisplayControls.tsx +6 -4
- package/src/app/chat/chat/widgets/builtin-tool-renderers.tsx +5 -1
- package/src/app/chat/chat-first/chat-history.spec.tsx +79 -0
- package/src/app/chat/chat-first/chat-history.tsx +75 -22
- package/src/app/chat/conversation/AgentConversation.spec.tsx +51 -1
- package/src/app/chat/conversation/AgentConversation.tsx +11 -2
- package/src/app/chat/ownership-history/ChatOwnerAvatar.tsx +27 -0
- package/src/app/chat/ownership-history/index.tsx +67 -0
- package/src/app/chat/ownership-history/ownership-history.spec.tsx +3146 -0
- package/src/app/chat/ownership-history/rows.ts +156 -0
- package/src/app/chat/ownership-history/useOwnershipChatHistory.ts +709 -0
- package/src/app/i18n/catalogs/ar-SA.ts +3 -0
- package/src/app/i18n/catalogs/de-DE.ts +3 -0
- package/src/app/i18n/catalogs/en-US.ts +3 -0
- package/src/app/i18n/catalogs/es-ES.ts +3 -0
- package/src/app/i18n/catalogs/fr-FR.ts +3 -0
- package/src/app/i18n/catalogs/hi-IN.ts +3 -0
- package/src/app/i18n/catalogs/ja-JP.ts +3 -0
- package/src/app/i18n/catalogs/ko-KR.ts +3 -0
- package/src/app/i18n/catalogs/pt-BR.ts +3 -0
- package/src/app/i18n/catalogs/zh-CN.ts +3 -0
- package/src/app/i18n/catalogs/zh-TW.ts +3 -0
- package/src/app/shared/CommandMenu.spec.tsx +175 -6
- package/src/app/shared/CommandMenu.tsx +24 -7
- package/src/app/sharing/ShareButton.tsx +12 -10
- package/src/chat-history/ChatHistoryList.spec.tsx +51 -0
- package/src/chat-history/ChatHistoryList.tsx +87 -26
- package/src/chat-history/ChatHistoryRailSections.spec.tsx +12 -4
- package/src/chat-history.css +109 -9
- package/src/composer/TiptapComposer.tsx +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
2
|
import { DATA_WIDGET_MAX_CHART_POINTS } from "@agent-native/core/data-widgets";
|
|
3
3
|
|
|
4
|
+
import type { AgentChatDataChartLayout } from "../../../agentkit/react/data-chart-layout.js";
|
|
4
5
|
import type { DataChartWidget as DataChartWidgetData } from "./data-widget-types.js";
|
|
5
6
|
|
|
6
7
|
const DEFAULT_COLORS = [
|
|
@@ -38,12 +39,25 @@ function numericValue(
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
function formatTick(value: number): string {
|
|
42
|
+
if (Number.isInteger(value)) {
|
|
43
|
+
return Math.abs(value) >= 1000 ? value.toLocaleString() : String(value);
|
|
44
|
+
}
|
|
41
45
|
if (Math.abs(value) >= 1000) return value.toLocaleString();
|
|
42
|
-
if (Number.isInteger(value)) return String(value);
|
|
43
46
|
return value.toFixed(1);
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
function
|
|
49
|
+
function formatValueLabel(value: number): string {
|
|
50
|
+
if (Number.isInteger(value)) {
|
|
51
|
+
return Math.abs(value) >= 1000 ? value.toLocaleString() : String(value);
|
|
52
|
+
}
|
|
53
|
+
return formatTick(value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function formatAxisTick(
|
|
57
|
+
value: number,
|
|
58
|
+
interval: number,
|
|
59
|
+
compactInteger: boolean,
|
|
60
|
+
): string {
|
|
47
61
|
const [mantissa, exponent = "0"] = interval
|
|
48
62
|
.toString()
|
|
49
63
|
.toLowerCase()
|
|
@@ -52,6 +66,9 @@ function formatAxisTick(value: number, interval: number): string {
|
|
|
52
66
|
0,
|
|
53
67
|
(mantissa.split(".")[1]?.length ?? 0) - Number(exponent),
|
|
54
68
|
);
|
|
69
|
+
if (compactInteger && decimalPlaces === 1 && Number.isInteger(value)) {
|
|
70
|
+
return Math.abs(value) >= 1000 ? value.toLocaleString() : String(value);
|
|
71
|
+
}
|
|
55
72
|
if (Math.abs(value) >= 1000) {
|
|
56
73
|
return value.toLocaleString(undefined, {
|
|
57
74
|
minimumFractionDigits: decimalPlaces,
|
|
@@ -61,6 +78,41 @@ function formatAxisTick(value: number, interval: number): string {
|
|
|
61
78
|
return value.toFixed(decimalPlaces);
|
|
62
79
|
}
|
|
63
80
|
|
|
81
|
+
function lineValueLabelY(
|
|
82
|
+
pointY: number,
|
|
83
|
+
valueLabelFontSize: number,
|
|
84
|
+
plotTop: number,
|
|
85
|
+
): number {
|
|
86
|
+
const minimumY = valueLabelFontSize;
|
|
87
|
+
const maximumY = HEIGHT - valueLabelFontSize * 0.25;
|
|
88
|
+
const fitsAbove = pointY - valueLabelFontSize - 5 >= plotTop;
|
|
89
|
+
const fitsBelow = pointY + valueLabelFontSize + 5 <= maximumY;
|
|
90
|
+
const labelY =
|
|
91
|
+
fitsAbove || !fitsBelow ? pointY - 5 : pointY + valueLabelFontSize + 5;
|
|
92
|
+
|
|
93
|
+
return Math.min(Math.max(labelY, minimumY), maximumY);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function inset(value: number | undefined, name: string, fallback: number) {
|
|
97
|
+
if (value === undefined) return fallback;
|
|
98
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
99
|
+
throw new RangeError(
|
|
100
|
+
`dataChartLayout.plotInsets.${name} must be a non-negative CSS length`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function fontSize(value: number | undefined, name: string, fallback: number) {
|
|
107
|
+
if (value === undefined) return fallback;
|
|
108
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
109
|
+
throw new RangeError(
|
|
110
|
+
`dataChartLayout.${name} must be a positive CSS length`,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
|
|
64
116
|
function labelFor(value: unknown): string {
|
|
65
117
|
const characters = Array.from(value == null ? "" : String(value));
|
|
66
118
|
return characters.length > MAX_LABEL_LENGTH
|
|
@@ -116,7 +168,7 @@ function formatHorizontalValueLabel(
|
|
|
116
168
|
fontSize: number,
|
|
117
169
|
maxWidth: number,
|
|
118
170
|
): string {
|
|
119
|
-
const label =
|
|
171
|
+
const label = formatValueLabel(value);
|
|
120
172
|
return estimateTextWidth(label, fontSize) > maxWidth
|
|
121
173
|
? formatCompactTick(value, fontSize, maxWidth)
|
|
122
174
|
: label;
|
|
@@ -146,9 +198,11 @@ function rangeFor(chart: DataChartWidgetData) {
|
|
|
146
198
|
|
|
147
199
|
function ChartBody({
|
|
148
200
|
chart,
|
|
201
|
+
layout,
|
|
149
202
|
labelFontSize,
|
|
150
203
|
}: {
|
|
151
204
|
chart: DataChartWidgetData;
|
|
205
|
+
layout?: AgentChatDataChartLayout;
|
|
152
206
|
labelFontSize: number;
|
|
153
207
|
}) {
|
|
154
208
|
const categoryGapRatio = chart.horizontalCategoryGapRatio;
|
|
@@ -163,6 +217,7 @@ function ChartBody({
|
|
|
163
217
|
const { min, max } = rangeFor(chart);
|
|
164
218
|
const isHorizontalBar = chart.type === "bar" && chart.layout === "horizontal";
|
|
165
219
|
const tickInterval = chart.valueAxisTickInterval;
|
|
220
|
+
const valueLabelFontSize = chart.valueLabelFontSize ?? 11;
|
|
166
221
|
const gridTickValues =
|
|
167
222
|
tickInterval === undefined
|
|
168
223
|
? Array.from({ length: 4 }, (_, index) => min + ((max - min) * index) / 3)
|
|
@@ -223,7 +278,7 @@ function ChartBody({
|
|
|
223
278
|
const label =
|
|
224
279
|
tickInterval === undefined
|
|
225
280
|
? formatTick(value)
|
|
226
|
-
: formatAxisTick(value, tickInterval);
|
|
281
|
+
: formatAxisTick(value, tickInterval, layout !== undefined);
|
|
227
282
|
const maximumWidth = isHorizontalBar
|
|
228
283
|
? horizontalTextWidthLimit
|
|
229
284
|
: WIDTH - MARGIN.right - MIN_PLOT_WIDTH - verticalValueTickMargin;
|
|
@@ -239,6 +294,27 @@ function ChartBody({
|
|
|
239
294
|
const horizontalValueTickLabelInset = isHorizontalBar
|
|
240
295
|
? Math.ceil(valueTickLabelWidth / 2) + 2
|
|
241
296
|
: 0;
|
|
297
|
+
const minimumHorizontalTickBottom = isHorizontalBar
|
|
298
|
+
? 14 +
|
|
299
|
+
labelFontSize * 0.25 +
|
|
300
|
+
4 +
|
|
301
|
+
(chart.xAxisTitle ? axisTitleFontSize * 0.8 + 6 : 0)
|
|
302
|
+
: 0;
|
|
303
|
+
const axisTitleBottomInset = chart.xAxisTitle ? 16 : 0;
|
|
304
|
+
const minimumVerticalCategoryBottom =
|
|
305
|
+
isHorizontalBar || layout?.plotInsets?.bottom === undefined
|
|
306
|
+
? 0
|
|
307
|
+
: labelFontSize + 12 + (chart.xAxisTitle ? axisTitleFontSize + 2 : 0);
|
|
308
|
+
const configuredTopInset = inset(layout?.plotInsets?.top, "top", MARGIN.top);
|
|
309
|
+
const minimumVerticalValueLabelTop =
|
|
310
|
+
chart.type === "bar" && !isHorizontalBar && chart.showValueLabels
|
|
311
|
+
? valueLabelFontSize + 5
|
|
312
|
+
: 0;
|
|
313
|
+
const configuredBottomInset = inset(
|
|
314
|
+
layout?.plotInsets?.bottom,
|
|
315
|
+
"bottom",
|
|
316
|
+
MARGIN.bottom,
|
|
317
|
+
);
|
|
242
318
|
const customValueTickWidth = isHorizontalBar ? 0 : customValueTickLabelWidth;
|
|
243
319
|
const horizontalPositiveValueWidth =
|
|
244
320
|
isHorizontalBar && chart.showValueLabels
|
|
@@ -282,8 +358,28 @@ function ChartBody({
|
|
|
282
358
|
),
|
|
283
359
|
)
|
|
284
360
|
: 0;
|
|
361
|
+
const verticalBarValueLabelInset =
|
|
362
|
+
chart.type === "bar" && !isHorizontalBar && chart.showValueLabels
|
|
363
|
+
? Math.ceil(
|
|
364
|
+
Math.max(
|
|
365
|
+
0,
|
|
366
|
+
...chart.data.flatMap((row) =>
|
|
367
|
+
chart.series
|
|
368
|
+
.map((series) => numericValue(row, series.key))
|
|
369
|
+
.filter((value): value is number => value !== null)
|
|
370
|
+
.map((value) =>
|
|
371
|
+
estimateTextWidth(
|
|
372
|
+
formatValueLabel(value),
|
|
373
|
+
valueLabelFontSize,
|
|
374
|
+
),
|
|
375
|
+
),
|
|
376
|
+
),
|
|
377
|
+
) / 2,
|
|
378
|
+
) + 4
|
|
379
|
+
: 0;
|
|
285
380
|
const margin = {
|
|
286
381
|
...MARGIN,
|
|
382
|
+
top: Math.max(configuredTopInset, minimumVerticalValueLabelTop),
|
|
287
383
|
left:
|
|
288
384
|
Math.max(
|
|
289
385
|
categoryMargin,
|
|
@@ -293,15 +389,40 @@ function ChartBody({
|
|
|
293
389
|
(horizontalNegativeValueWidth > 0
|
|
294
390
|
? horizontalNegativeValueWidth + 13
|
|
295
391
|
: 0),
|
|
296
|
-
right:
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
392
|
+
right:
|
|
393
|
+
layout?.plotInsets?.right === undefined
|
|
394
|
+
? Math.max(
|
|
395
|
+
MARGIN.right,
|
|
396
|
+
horizontalPositiveValueWidth + 13,
|
|
397
|
+
horizontalValueTickLabelInset,
|
|
398
|
+
verticalBarValueLabelInset,
|
|
399
|
+
)
|
|
400
|
+
: Math.max(
|
|
401
|
+
inset(layout.plotInsets.right, "right", MARGIN.right),
|
|
402
|
+
horizontalPositiveValueWidth > 0
|
|
403
|
+
? horizontalPositiveValueWidth + 13
|
|
404
|
+
: 0,
|
|
405
|
+
horizontalValueTickLabelInset,
|
|
406
|
+
verticalBarValueLabelInset,
|
|
407
|
+
),
|
|
408
|
+
bottom:
|
|
409
|
+
Math.max(
|
|
410
|
+
configuredBottomInset,
|
|
411
|
+
minimumHorizontalTickBottom - axisTitleBottomInset,
|
|
412
|
+
minimumVerticalCategoryBottom - axisTitleBottomInset,
|
|
413
|
+
) + axisTitleBottomInset,
|
|
302
414
|
};
|
|
303
415
|
const plotWidth = WIDTH - margin.left - margin.right;
|
|
304
416
|
const plotHeight = HEIGHT - margin.top - margin.bottom;
|
|
417
|
+
if (plotWidth <= 0 || plotHeight <= 0) {
|
|
418
|
+
throw new RangeError(
|
|
419
|
+
"dataChartLayout.plotInsets must leave a positive chart plot area",
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
const labelColor =
|
|
423
|
+
layout?.labelTone === "foreground"
|
|
424
|
+
? "hsl(var(--foreground))"
|
|
425
|
+
: "hsl(var(--muted-foreground))";
|
|
305
426
|
const xForValue = (value: number) =>
|
|
306
427
|
margin.left + ((value - min) / (max - min)) * plotWidth;
|
|
307
428
|
const yForValue = (value: number) =>
|
|
@@ -400,7 +521,6 @@ function ChartBody({
|
|
|
400
521
|
const zeroX = xForValue(zero);
|
|
401
522
|
const zeroY = yForValue(zero);
|
|
402
523
|
const axisTitleFontWeight = chart.axisTitleFontWeight ?? 500;
|
|
403
|
-
const valueLabelFontSize = chart.valueLabelFontSize ?? 11;
|
|
404
524
|
const valueLabelFontWeight = chart.valueLabelFontWeight ?? 400;
|
|
405
525
|
|
|
406
526
|
const axes = (
|
|
@@ -420,7 +540,7 @@ function ChartBody({
|
|
|
420
540
|
<text
|
|
421
541
|
x={tick.x}
|
|
422
542
|
y={HEIGHT - margin.bottom + 14}
|
|
423
|
-
fill=
|
|
543
|
+
fill={labelColor}
|
|
424
544
|
fontSize={labelFontSize}
|
|
425
545
|
textAnchor="middle"
|
|
426
546
|
>
|
|
@@ -440,9 +560,13 @@ function ChartBody({
|
|
|
440
560
|
/>
|
|
441
561
|
{axisLabelIndexes.has(tick.index) ? (
|
|
442
562
|
<text
|
|
563
|
+
data-value-axis-tick="true"
|
|
443
564
|
x={margin.left - VALUE_AXIS_TICK_LABEL_INSET}
|
|
444
|
-
y={
|
|
445
|
-
|
|
565
|
+
y={Math.min(
|
|
566
|
+
Math.max(tick.y + 4, labelFontSize),
|
|
567
|
+
HEIGHT - labelFontSize * 0.25,
|
|
568
|
+
)}
|
|
569
|
+
fill={labelColor}
|
|
446
570
|
fontSize={labelFontSize}
|
|
447
571
|
textAnchor="end"
|
|
448
572
|
>
|
|
@@ -459,35 +583,64 @@ function ChartBody({
|
|
|
459
583
|
y2={isHorizontalBar ? HEIGHT - margin.bottom : zeroY}
|
|
460
584
|
stroke="hsl(var(--chart-grid, var(--border)))"
|
|
461
585
|
/>
|
|
462
|
-
{chart.data.map((row, index) =>
|
|
463
|
-
isHorizontalBar
|
|
586
|
+
{chart.data.map((row, index) => {
|
|
587
|
+
if (isHorizontalBar) {
|
|
588
|
+
const label = labelFor(row[chart.xKey]);
|
|
589
|
+
return (
|
|
590
|
+
<text
|
|
591
|
+
key={`${index}-${String(row[chart.xKey] ?? "")}`}
|
|
592
|
+
x={categoryLabelX}
|
|
593
|
+
y={yForRow(index) + labelFontSize * 0.35}
|
|
594
|
+
fill={labelColor}
|
|
595
|
+
fontSize={labelFontSize}
|
|
596
|
+
textAnchor="end"
|
|
597
|
+
>
|
|
598
|
+
{label}
|
|
599
|
+
</text>
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
if (index % xTickEvery !== 0 && index !== chart.data.length - 1) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const label = labelFor(row[chart.xKey]);
|
|
607
|
+
const categoryLabelY =
|
|
608
|
+
layout?.plotInsets?.bottom === undefined
|
|
609
|
+
? HEIGHT - 12
|
|
610
|
+
: chart.xAxisTitle
|
|
611
|
+
? HEIGHT - axisTitleFontSize - 12
|
|
612
|
+
: Math.max(
|
|
613
|
+
HEIGHT - 12,
|
|
614
|
+
HEIGHT - margin.bottom + labelFontSize + 1,
|
|
615
|
+
);
|
|
616
|
+
const x =
|
|
617
|
+
chart.type === "bar"
|
|
618
|
+
? margin.left + (index + 0.5) * (plotWidth / chart.data.length)
|
|
619
|
+
: xForPoint(index);
|
|
620
|
+
const labelHalfWidth = estimateTextWidth(label, labelFontSize) / 2;
|
|
621
|
+
const leftEndpointOverflows = index === 0 && x - labelHalfWidth < 0;
|
|
622
|
+
const rightEndpointOverflows =
|
|
623
|
+
index === chart.data.length - 1 && x + labelHalfWidth > WIDTH;
|
|
624
|
+
|
|
625
|
+
return (
|
|
464
626
|
<text
|
|
465
627
|
key={`${index}-${String(row[chart.xKey] ?? "")}`}
|
|
466
|
-
x={
|
|
467
|
-
y={
|
|
468
|
-
fill=
|
|
628
|
+
x={x}
|
|
629
|
+
y={categoryLabelY}
|
|
630
|
+
fill={labelColor}
|
|
469
631
|
fontSize={labelFontSize}
|
|
470
|
-
textAnchor=
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
key={`${index}-${String(row[chart.xKey] ?? "")}`}
|
|
477
|
-
x={
|
|
478
|
-
chart.type === "bar"
|
|
479
|
-
? margin.left + (index + 0.5) * (plotWidth / chart.data.length)
|
|
480
|
-
: xForPoint(index)
|
|
632
|
+
textAnchor={
|
|
633
|
+
leftEndpointOverflows
|
|
634
|
+
? "start"
|
|
635
|
+
: rightEndpointOverflows
|
|
636
|
+
? "end"
|
|
637
|
+
: "middle"
|
|
481
638
|
}
|
|
482
|
-
y={HEIGHT - 12}
|
|
483
|
-
fill="hsl(var(--muted-foreground))"
|
|
484
|
-
fontSize={labelFontSize}
|
|
485
|
-
textAnchor="middle"
|
|
486
639
|
>
|
|
487
|
-
{
|
|
640
|
+
{label}
|
|
488
641
|
</text>
|
|
489
|
-
)
|
|
490
|
-
)}
|
|
642
|
+
);
|
|
643
|
+
})}
|
|
491
644
|
{chart.xAxisTitle ? (
|
|
492
645
|
<text
|
|
493
646
|
x={margin.left + plotWidth / 2}
|
|
@@ -556,6 +709,21 @@ function ChartBody({
|
|
|
556
709
|
const height = isHorizontalBar
|
|
557
710
|
? Math.max(0, barSize - Math.min(2, barSize * 0.1))
|
|
558
711
|
: Math.max(1, Math.abs(zeroY - valueY));
|
|
712
|
+
const valueLabel = isHorizontalBar
|
|
713
|
+
? formatHorizontalValueLabel(
|
|
714
|
+
value,
|
|
715
|
+
valueLabelFontSize,
|
|
716
|
+
horizontalTextWidthLimit,
|
|
717
|
+
)
|
|
718
|
+
: formatValueLabel(value);
|
|
719
|
+
const valueLabelWidth = estimateTextWidth(
|
|
720
|
+
valueLabel,
|
|
721
|
+
valueLabelFontSize,
|
|
722
|
+
);
|
|
723
|
+
const valueLabelX =
|
|
724
|
+
isHorizontalBar && value >= 0
|
|
725
|
+
? Math.min(valueX + 5, WIDTH - valueLabelWidth - 4)
|
|
726
|
+
: valueX + (value < 0 ? -5 : 5);
|
|
559
727
|
return (
|
|
560
728
|
<g key={`${rowIndex}-${series.key}`}>
|
|
561
729
|
<rect
|
|
@@ -568,30 +736,21 @@ function ChartBody({
|
|
|
568
736
|
/>
|
|
569
737
|
{chart.showValueLabels ? (
|
|
570
738
|
<text
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
? valueX + (value < 0 ? -5 : 5)
|
|
574
|
-
: x + width / 2
|
|
575
|
-
}
|
|
739
|
+
data-value-label="true"
|
|
740
|
+
x={isHorizontalBar ? valueLabelX : x + width / 2}
|
|
576
741
|
y={
|
|
577
742
|
isHorizontalBar
|
|
578
743
|
? y + height / 2 + valueLabelFontSize * 0.35
|
|
579
|
-
: y - 5
|
|
744
|
+
: Math.max(valueLabelFontSize, y - 5)
|
|
580
745
|
}
|
|
581
|
-
fill=
|
|
746
|
+
fill={labelColor}
|
|
582
747
|
fontSize={valueLabelFontSize}
|
|
583
748
|
fontWeight={valueLabelFontWeight}
|
|
584
749
|
textAnchor={
|
|
585
750
|
isHorizontalBar ? (value < 0 ? "end" : "start") : "middle"
|
|
586
751
|
}
|
|
587
752
|
>
|
|
588
|
-
{
|
|
589
|
-
? formatHorizontalValueLabel(
|
|
590
|
-
value,
|
|
591
|
-
valueLabelFontSize,
|
|
592
|
-
horizontalTextWidthLimit,
|
|
593
|
-
)
|
|
594
|
-
: formatTick(value)}
|
|
753
|
+
{valueLabel}
|
|
595
754
|
</text>
|
|
596
755
|
) : null}
|
|
597
756
|
</g>
|
|
@@ -663,18 +822,13 @@ function ChartBody({
|
|
|
663
822
|
))}
|
|
664
823
|
{chart.showValueLabels
|
|
665
824
|
? points.map((point, index) => {
|
|
666
|
-
const abovePoint =
|
|
667
|
-
point.y - valueLabelFontSize - 5 >= margin.top;
|
|
668
825
|
return (
|
|
669
826
|
<text
|
|
670
827
|
key={`value-${index}`}
|
|
828
|
+
data-value-label="true"
|
|
671
829
|
x={point.x}
|
|
672
|
-
y={
|
|
673
|
-
|
|
674
|
-
? point.y - 5
|
|
675
|
-
: point.y + valueLabelFontSize + 5
|
|
676
|
-
}
|
|
677
|
-
fill="hsl(var(--muted-foreground))"
|
|
830
|
+
y={lineValueLabelY(point.y, valueLabelFontSize, margin.top)}
|
|
831
|
+
fill={labelColor}
|
|
678
832
|
fontSize={valueLabelFontSize}
|
|
679
833
|
fontWeight={valueLabelFontWeight}
|
|
680
834
|
textAnchor={
|
|
@@ -685,7 +839,7 @@ function ChartBody({
|
|
|
685
839
|
: "middle"
|
|
686
840
|
}
|
|
687
841
|
>
|
|
688
|
-
{
|
|
842
|
+
{formatValueLabel(point.value)}
|
|
689
843
|
</text>
|
|
690
844
|
);
|
|
691
845
|
})
|
|
@@ -696,7 +850,13 @@ function ChartBody({
|
|
|
696
850
|
);
|
|
697
851
|
}
|
|
698
852
|
|
|
699
|
-
export function DataChartRenderer({
|
|
853
|
+
export function DataChartRenderer({
|
|
854
|
+
chart,
|
|
855
|
+
layout,
|
|
856
|
+
}: {
|
|
857
|
+
chart: DataChartWidgetData;
|
|
858
|
+
layout?: AgentChatDataChartLayout;
|
|
859
|
+
}) {
|
|
700
860
|
const t = useT();
|
|
701
861
|
const renderedChart =
|
|
702
862
|
chart.data.length > DATA_WIDGET_MAX_CHART_POINTS
|
|
@@ -709,8 +869,13 @@ export function DataChartRenderer({ chart }: { chart: DataChartWidgetData }) {
|
|
|
709
869
|
const contentPadding = renderedChart.contentPadding ?? 0;
|
|
710
870
|
const hasContentBox = contentHeight !== undefined || contentPadding > 0;
|
|
711
871
|
const labelFontFamily =
|
|
872
|
+
layout?.labelFontFamily ??
|
|
712
873
|
LABEL_FONT_FAMILIES[renderedChart.labelFontFamily ?? "sans"];
|
|
713
|
-
const labelFontSize =
|
|
874
|
+
const labelFontSize = fontSize(
|
|
875
|
+
layout?.labelFontSize,
|
|
876
|
+
"labelFontSize",
|
|
877
|
+
renderedChart.labelFontSize ?? 11,
|
|
878
|
+
);
|
|
714
879
|
return (
|
|
715
880
|
<div
|
|
716
881
|
className="box-border w-full min-w-0 overflow-hidden"
|
|
@@ -733,7 +898,11 @@ export function DataChartRenderer({ chart }: { chart: DataChartWidgetData }) {
|
|
|
733
898
|
role="img"
|
|
734
899
|
aria-label={renderedChart.title ?? t("agentChat.widget.dataChart")}
|
|
735
900
|
>
|
|
736
|
-
<ChartBody
|
|
901
|
+
<ChartBody
|
|
902
|
+
chart={renderedChart}
|
|
903
|
+
layout={layout}
|
|
904
|
+
labelFontSize={labelFontSize}
|
|
905
|
+
/>
|
|
737
906
|
</svg>
|
|
738
907
|
</div>
|
|
739
908
|
);
|
|
@@ -5,6 +5,7 @@ import React, { act } from "react";
|
|
|
5
5
|
import { createRoot, type Root } from "react-dom/client";
|
|
6
6
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
7
|
|
|
8
|
+
import type { AgentChatDataChartLayout } from "../../../agentkit/react/data-chart-layout.js";
|
|
8
9
|
import { createToolkitI18nCatalog } from "../../../i18n.js";
|
|
9
10
|
import type {
|
|
10
11
|
DataWidgetAction,
|
|
@@ -27,6 +28,7 @@ vi.mock("../../../../hooks/use-toast.js", () => ({ toast: mocks.toast }));
|
|
|
27
28
|
vi.mock("./DataChartRenderer.js", () => ({
|
|
28
29
|
DataChartRenderer: ({
|
|
29
30
|
chart,
|
|
31
|
+
layout,
|
|
30
32
|
}: {
|
|
31
33
|
chart: {
|
|
32
34
|
contentHeight?: number;
|
|
@@ -34,6 +36,7 @@ vi.mock("./DataChartRenderer.js", () => ({
|
|
|
34
36
|
labelFontFamily?: string;
|
|
35
37
|
labelFontSize?: number;
|
|
36
38
|
};
|
|
39
|
+
layout?: AgentChatDataChartLayout;
|
|
37
40
|
}) => (
|
|
38
41
|
<div
|
|
39
42
|
data-testid="chart-surface"
|
|
@@ -41,6 +44,8 @@ vi.mock("./DataChartRenderer.js", () => ({
|
|
|
41
44
|
data-content-padding={chart.contentPadding}
|
|
42
45
|
data-label-font-family={chart.labelFontFamily}
|
|
43
46
|
data-label-font-size={chart.labelFontSize}
|
|
47
|
+
data-layout-label-font-family={layout?.labelFontFamily}
|
|
48
|
+
data-layout-label-font-size={layout?.labelFontSize}
|
|
44
49
|
/>
|
|
45
50
|
),
|
|
46
51
|
}));
|
|
@@ -74,6 +79,7 @@ async function renderWidget(
|
|
|
74
79
|
sampled = false,
|
|
75
80
|
chartDataCount = 1,
|
|
76
81
|
truncated = false,
|
|
82
|
+
layout?: AgentChatDataChartLayout,
|
|
77
83
|
) {
|
|
78
84
|
const container = document.createElement("div");
|
|
79
85
|
document.body.appendChild(container);
|
|
@@ -115,6 +121,7 @@ async function renderWidget(
|
|
|
115
121
|
],
|
|
116
122
|
actions: displayActions,
|
|
117
123
|
}}
|
|
124
|
+
layout={layout}
|
|
118
125
|
/>
|
|
119
126
|
</AgentNativeI18nProvider>,
|
|
120
127
|
);
|
|
@@ -186,6 +193,66 @@ describe("DataChartWidget display contract", () => {
|
|
|
186
193
|
expect(window.location.search).toBe("?tab=chart");
|
|
187
194
|
});
|
|
188
195
|
|
|
196
|
+
it("opts into responsive chart sizing and quiet controls", async () => {
|
|
197
|
+
const container = await renderWidget(
|
|
198
|
+
[
|
|
199
|
+
{
|
|
200
|
+
id: "explore",
|
|
201
|
+
label: "Explore",
|
|
202
|
+
href: "/explore",
|
|
203
|
+
icon: "explore",
|
|
204
|
+
presentation: "icon",
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
undefined,
|
|
208
|
+
false,
|
|
209
|
+
1,
|
|
210
|
+
false,
|
|
211
|
+
{
|
|
212
|
+
maxWidth: 720,
|
|
213
|
+
labelFontFamily: "IBM Plex Sans",
|
|
214
|
+
labelFontSize: 14,
|
|
215
|
+
titleFontFamily: "IBM Plex Sans",
|
|
216
|
+
titleFontSize: 14,
|
|
217
|
+
titleFontWeight: 400,
|
|
218
|
+
titleLineHeight: 20,
|
|
219
|
+
titleTone: "muted",
|
|
220
|
+
actionsVariant: "quiet",
|
|
221
|
+
},
|
|
222
|
+
);
|
|
223
|
+
const card = container.querySelector<HTMLElement>(".my-4");
|
|
224
|
+
const title = card?.querySelector<HTMLElement>(".border-b .min-w-0");
|
|
225
|
+
const chart = container.querySelector<HTMLElement>(
|
|
226
|
+
'[data-testid="chart-surface"]',
|
|
227
|
+
);
|
|
228
|
+
const primary = Array.from(container.querySelectorAll("a")).find((link) =>
|
|
229
|
+
link.textContent?.includes("Open report"),
|
|
230
|
+
);
|
|
231
|
+
const explore = container.querySelector<HTMLAnchorElement>(
|
|
232
|
+
'a[aria-label="Explore"]',
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
expect(card?.style.width).toBe("100%");
|
|
236
|
+
expect(card?.style.maxWidth).toBe("720px");
|
|
237
|
+
expect(card?.style.marginInline).toBe("auto");
|
|
238
|
+
expect(title?.style.fontFamily).toContain("IBM Plex Sans");
|
|
239
|
+
expect(title?.style.fontSize).toBe("14px");
|
|
240
|
+
expect(title?.style.fontWeight).toBe("400");
|
|
241
|
+
expect(title?.style.lineHeight).toBe("20px");
|
|
242
|
+
expect(title?.classList.contains("text-muted-foreground")).toBe(true);
|
|
243
|
+
expect(chart?.dataset.layoutLabelFontFamily).toBe("IBM Plex Sans");
|
|
244
|
+
expect(chart?.dataset.layoutLabelFontSize).toBe("14");
|
|
245
|
+
expect(primary?.classList.contains("border")).toBe(false);
|
|
246
|
+
expect(explore?.classList.contains("border")).toBe(false);
|
|
247
|
+
expect(explore?.classList.contains("size-7")).toBe(true);
|
|
248
|
+
const chartActions = container.querySelector<HTMLButtonElement>(
|
|
249
|
+
'[aria-label="Chart actions"]',
|
|
250
|
+
);
|
|
251
|
+
expect(chartActions).not.toBeNull();
|
|
252
|
+
expect(chartActions?.classList.contains("size-7")).toBe(true);
|
|
253
|
+
expect(chartActions?.classList.contains("border")).toBe(false);
|
|
254
|
+
});
|
|
255
|
+
|
|
189
256
|
it("announces incomplete chart data and stays quiet for complete data", async () => {
|
|
190
257
|
const cappedContainer = await renderWidget(
|
|
191
258
|
undefined,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
2
|
import { DATA_WIDGET_MAX_CHART_POINTS } from "@agent-native/core/data-widgets";
|
|
3
|
-
import { lazy, Suspense, useEffect, useState } from "react";
|
|
3
|
+
import { lazy, Suspense, useEffect, useState, type CSSProperties } from "react";
|
|
4
4
|
|
|
5
|
+
import type { AgentChatDataChartLayout } from "../../../agentkit/react/data-chart-layout.js";
|
|
5
6
|
import type {
|
|
6
7
|
DataChartWidget as DataChartWidgetData,
|
|
7
8
|
DataWidgetDisplay,
|
|
@@ -20,9 +21,11 @@ const LazyDataChartRenderer = lazy(() =>
|
|
|
20
21
|
export function DataChartWidget({
|
|
21
22
|
chart,
|
|
22
23
|
display,
|
|
24
|
+
layout,
|
|
23
25
|
}: {
|
|
24
26
|
chart: DataChartWidgetData;
|
|
25
27
|
display?: DataWidgetDisplay;
|
|
28
|
+
layout?: AgentChatDataChartLayout;
|
|
26
29
|
}) {
|
|
27
30
|
const t = useT();
|
|
28
31
|
const [mounted, setMounted] = useState(false);
|
|
@@ -32,6 +35,16 @@ export function DataChartWidget({
|
|
|
32
35
|
chart.sampled === true ||
|
|
33
36
|
chart.truncated === true ||
|
|
34
37
|
chart.data.length > DATA_WIDGET_MAX_CHART_POINTS;
|
|
38
|
+
const maxWidth = layout?.maxWidth;
|
|
39
|
+
if (maxWidth !== undefined && (!Number.isFinite(maxWidth) || maxWidth <= 0)) {
|
|
40
|
+
throw new RangeError(
|
|
41
|
+
"dataChartLayout.maxWidth must be a positive CSS length",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
const cardStyle: CSSProperties | undefined =
|
|
45
|
+
maxWidth === undefined
|
|
46
|
+
? undefined
|
|
47
|
+
: { width: "100%", maxWidth: `${maxWidth}px`, marginInline: "auto" };
|
|
35
48
|
|
|
36
49
|
useEffect(() => {
|
|
37
50
|
setMounted(true);
|
|
@@ -56,22 +69,43 @@ export function DataChartWidget({
|
|
|
56
69
|
);
|
|
57
70
|
|
|
58
71
|
return (
|
|
59
|
-
<div
|
|
72
|
+
<div
|
|
73
|
+
className="my-4 overflow-hidden rounded-[3px] border border-border bg-background text-foreground shadow-sm"
|
|
74
|
+
style={cardStyle}
|
|
75
|
+
>
|
|
60
76
|
<div className="flex h-12 items-center gap-2 border-b border-border px-3">
|
|
61
|
-
<div
|
|
77
|
+
<div
|
|
78
|
+
className={`min-w-0 flex-1 truncate text-sm font-medium ${layout?.titleTone === "muted" ? "text-muted-foreground" : ""}`}
|
|
79
|
+
style={{
|
|
80
|
+
fontFamily: layout?.titleFontFamily,
|
|
81
|
+
fontSize:
|
|
82
|
+
layout?.titleFontSize === undefined
|
|
83
|
+
? undefined
|
|
84
|
+
: `${layout.titleFontSize}px`,
|
|
85
|
+
fontWeight: layout?.titleFontWeight,
|
|
86
|
+
lineHeight:
|
|
87
|
+
layout?.titleLineHeight === undefined
|
|
88
|
+
? undefined
|
|
89
|
+
: `${layout.titleLineHeight}px`,
|
|
90
|
+
color:
|
|
91
|
+
layout?.titleTone === "muted"
|
|
92
|
+
? "hsl(var(--muted-foreground))"
|
|
93
|
+
: undefined,
|
|
94
|
+
}}
|
|
95
|
+
>
|
|
62
96
|
{chart.title ?? t("agentChat.widget.dataChart")}
|
|
63
97
|
</div>
|
|
64
98
|
<DataWidgetDisplayControls
|
|
65
99
|
display={display}
|
|
66
100
|
chartActions={chart.actions}
|
|
67
|
-
variant="secondary"
|
|
101
|
+
variant={layout?.actionsVariant ?? "secondary"}
|
|
68
102
|
/>
|
|
69
103
|
</div>
|
|
70
104
|
{!mounted ? (
|
|
71
105
|
fallback
|
|
72
106
|
) : (
|
|
73
107
|
<Suspense fallback={fallback}>
|
|
74
|
-
<LazyDataChartRenderer chart={chart} />
|
|
108
|
+
<LazyDataChartRenderer chart={chart} layout={layout} />
|
|
75
109
|
</Suspense>
|
|
76
110
|
)}
|
|
77
111
|
{hasOmittedRows ? (
|