inconvo 1.4.0 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inconvo",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "CLI for installing Inconvo assistant-ui tool components into any project.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,188 +1,75 @@
1
1
  "use client";
2
2
 
3
- import { useMemo, type ReactNode } from "react";
4
- import {
5
- ResponsiveContainer,
6
- LineChart as RechartsLineChart,
7
- Line,
8
- BarChart as RechartsBarChart,
9
- Bar,
10
- CartesianGrid,
11
- Tooltip,
12
- XAxis,
13
- YAxis,
14
- Label,
15
- Legend,
16
- } from "recharts";
3
+ import { useEffect, useMemo, useState } from "react";
4
+ import { VegaEmbed } from "react-vega";
5
+ import type { VisualizationSpec } from "vega-embed";
17
6
 
18
- import type { InconvoChartData, InconvoChartType } from "~/lib/inconvo/types";
19
- import { buildChartPalette } from "~/components/assistant-ui/tools/inconvo-chart-colors";
7
+ import type {
8
+ InconvoChartData,
9
+ InconvoChartType,
10
+ InconvoChartSpec,
11
+ } from "~/lib/inconvo/types";
20
12
 
21
13
  interface InconvoChartProps {
22
- data: InconvoChartData;
23
- variant: InconvoChartType;
14
+ data?: InconvoChartData;
15
+ spec?: InconvoChartSpec;
16
+ variant?: InconvoChartType;
24
17
  xLabel?: string;
25
18
  yLabel?: string;
26
19
  title?: string;
27
20
  }
28
21
 
29
- const ChartScaffold = ({
30
- children,
31
- axisColor,
32
- textColor,
33
- xLabel,
34
- yLabel,
35
- labelCount,
36
- }: {
37
- children: ReactNode;
38
- axisColor: string;
39
- textColor: string;
40
- xLabel?: string;
41
- yLabel?: string;
42
- labelCount: number;
43
- }) => (
44
- <>
45
- <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
46
- <XAxis
47
- dataKey="name"
48
- stroke={axisColor}
49
- tick={{ fill: axisColor, fontSize: 12 }}
50
- angle={-30}
51
- textAnchor="end"
52
- interval={labelCount > 12 ? "preserveStartEnd" : 0}
53
- >
54
- {xLabel ? (
55
- <Label
56
- position="bottom"
57
- offset={24}
58
- style={{
59
- fill: axisColor,
60
- textAnchor: "middle",
61
- }}
62
- value={xLabel}
63
- />
64
- ) : null}
65
- </XAxis>
66
- <YAxis width={80} stroke={axisColor} tick={{ fill: axisColor, fontSize: 12 }}>
67
- {yLabel ? (
68
- <Label
69
- angle={-90}
70
- position="insideLeft"
71
- style={{
72
- fill: axisColor,
73
- textAnchor: "middle",
74
- }}
75
- value={yLabel}
76
- />
77
- ) : null}
78
- </YAxis>
79
- <Tooltip
80
- contentStyle={{
81
- backgroundColor: "var(--card)",
82
- border: "1px solid var(--border)",
83
- borderRadius: 8,
84
- color: textColor,
85
- }}
86
- labelStyle={{
87
- color: textColor,
88
- fontWeight: 600,
89
- }}
90
- />
91
- <Legend
92
- verticalAlign="top"
93
- align="right"
94
- wrapperStyle={{
95
- color: axisColor,
96
- paddingBottom: "4px",
97
- }}
98
- />
99
- {children}
100
- </>
101
- );
22
+ export const InconvoChart = ({ spec: providedSpec }: InconvoChartProps) => {
23
+ const [error, setError] = useState<string | null>(null);
102
24
 
103
- export const InconvoChart = ({
104
- data,
105
- variant,
106
- xLabel,
107
- yLabel,
108
- }: InconvoChartProps) => {
109
- const chartData = useMemo(() => {
110
- return data.labels.map((label, index) => {
111
- const row: { name: string; [key: string]: string | number } = {
112
- name: label,
113
- };
114
- data.datasets.forEach((dataset) => {
115
- row[dataset.name] = dataset.values[index] ?? 0;
116
- });
117
- return row;
118
- });
119
- }, [data]);
25
+ const resolvedSpec = useMemo<VisualizationSpec | null>(() => {
26
+ if (providedSpec) {
27
+ return {
28
+ $schema: "https://vega.github.io/schema/vega-lite/v5.json",
29
+ background: "transparent",
30
+ autosize: { type: "fit", contains: "padding" },
31
+ width: "container",
32
+ ...providedSpec,
33
+ } as VisualizationSpec;
34
+ }
120
35
 
121
- const palette = useMemo(
122
- () => buildChartPalette(data.datasets.length),
123
- [data.datasets.length],
124
- );
36
+ return null;
37
+ }, [providedSpec]);
125
38
 
126
- const axisColor = "var(--muted-foreground)";
127
- const textColor = "var(--foreground)";
128
- const margins = { top: 20, right: 30, bottom: xLabel ? 80 : 40, left: 20 };
39
+ useEffect(() => {
40
+ setError(null);
41
+ }, [resolvedSpec]);
129
42
 
130
- const renderLines = () =>
131
- data.datasets.map((dataset, index) => {
132
- const stroke = palette[index] ?? "var(--chart-series-primary)";
133
- return (
134
- <Line
135
- key={dataset.name}
136
- type="monotone"
137
- dataKey={dataset.name}
138
- stroke={stroke}
139
- strokeWidth={2}
140
- dot={{ r: 3, strokeWidth: 2, stroke, fill: "var(--card)" }}
141
- activeDot={{ r: 5, strokeWidth: 2, stroke, fill: stroke }}
142
- />
143
- );
144
- });
43
+ const handleError = (err: unknown) => {
44
+ const message = err instanceof Error ? err.message : String(err);
45
+ console.error("Vega-Lite render error:", err);
46
+ setError(message);
47
+ };
145
48
 
146
- const renderBars = () =>
147
- data.datasets.map((dataset, index) => (
148
- <Bar
149
- key={dataset.name}
150
- dataKey={dataset.name}
151
- fill={palette[index] ?? "var(--chart-series-primary)"}
152
- radius={[4, 4, 0, 0]}
153
- maxBarSize={48}
154
- />
155
- ));
49
+ if (!resolvedSpec) {
50
+ return (
51
+ <div className="text-sm text-muted-foreground">
52
+ No chart data provided.
53
+ </div>
54
+ );
55
+ }
56
+
57
+ if (error) {
58
+ return (
59
+ <div className="text-sm text-red-500">
60
+ Failed to render chart: {error}
61
+ </div>
62
+ );
63
+ }
156
64
 
157
65
  return (
158
66
  <div className="flex w-full flex-col gap-4 text-foreground">
159
- <ResponsiveContainer width="100%" height={400}>
160
- {variant === "line" ? (
161
- <RechartsLineChart data={chartData} margin={margins}>
162
- <ChartScaffold
163
- axisColor={axisColor}
164
- textColor={textColor}
165
- xLabel={xLabel}
166
- yLabel={yLabel}
167
- labelCount={data.labels.length}
168
- >
169
- {renderLines()}
170
- </ChartScaffold>
171
- </RechartsLineChart>
172
- ) : (
173
- <RechartsBarChart data={chartData} margin={margins}>
174
- <ChartScaffold
175
- axisColor={axisColor}
176
- textColor={textColor}
177
- xLabel={xLabel}
178
- yLabel={yLabel}
179
- labelCount={data.labels.length}
180
- >
181
- {renderBars()}
182
- </ChartScaffold>
183
- </RechartsBarChart>
184
- )}
185
- </ResponsiveContainer>
67
+ <VegaEmbed
68
+ spec={resolvedSpec}
69
+ options={{ actions: false }}
70
+ onError={handleError}
71
+ style={{ width: "100%" }}
72
+ />
186
73
  </div>
187
74
  );
188
75
  };
@@ -1,15 +0,0 @@
1
- const chartColorVars = [
2
- "var(--chart-1)",
3
- "var(--chart-2)",
4
- "var(--chart-3)",
5
- "var(--chart-4)",
6
- "var(--chart-5)",
7
- ];
8
-
9
- export const buildChartPalette = (seriesCount: number) => {
10
- if (seriesCount <= 0) return [];
11
- return Array.from({ length: seriesCount }, (_, index) => {
12
- const colorIndex = index % chartColorVars.length;
13
- return chartColorVars[colorIndex] ?? "var(--chart-series-primary)";
14
- });
15
- };