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,188 +1,75 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useMemo,
|
|
4
|
-
import {
|
|
5
|
-
|
|
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 {
|
|
19
|
-
|
|
7
|
+
import type {
|
|
8
|
+
InconvoChartData,
|
|
9
|
+
InconvoChartType,
|
|
10
|
+
InconvoChartSpec,
|
|
11
|
+
} from "~/lib/inconvo/types";
|
|
20
12
|
|
|
21
13
|
interface InconvoChartProps {
|
|
22
|
-
data
|
|
23
|
-
|
|
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
|
|
30
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
[data.datasets.length],
|
|
124
|
-
);
|
|
36
|
+
return null;
|
|
37
|
+
}, [providedSpec]);
|
|
125
38
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
setError(null);
|
|
41
|
+
}, [resolvedSpec]);
|
|
129
42
|
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
<
|
|
160
|
-
{
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
};
|