@alpic-ai/ui 0.0.0-staging.g5cfa7c7 → 0.0.0-staging.g5fc2bcf
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/dist/components/area-chart.d.mts +2 -0
- package/dist/components/area-chart.mjs +10 -6
- package/dist/components/bar-chart.d.mts +2 -0
- package/dist/components/bar-chart.mjs +10 -6
- package/dist/components/bar-list.d.mts +3 -0
- package/dist/components/bar-list.mjs +21 -16
- package/dist/components/chart-card.d.mts +1 -1
- package/dist/components/chart-card.mjs +1 -1
- package/dist/components/chart-container.d.mts +1 -1
- package/dist/components/chart-legend.d.mts +5 -0
- package/dist/components/chart-legend.mjs +11 -2
- package/dist/components/chart-tooltip.mjs +5 -3
- package/dist/components/donut-chart.mjs +5 -3
- package/dist/components/form.mjs +3 -1
- package/dist/components/heatmap-chart.d.mts +8 -0
- package/dist/components/heatmap-chart.mjs +39 -8
- package/dist/components/line-chart.d.mts +2 -0
- package/dist/components/line-chart.mjs +11 -6
- package/dist/components/stat.d.mts +3 -1
- package/dist/components/stat.mjs +14 -4
- package/dist/components/textarea.mjs +1 -1
- package/dist/lib/chart-palette.mjs +16 -16
- package/dist/lib/chart.mjs +16 -1
- package/package.json +24 -24
- package/src/components/area-chart.tsx +13 -8
- package/src/components/bar-chart.tsx +13 -8
- package/src/components/bar-list.tsx +22 -15
- package/src/components/chart-card.tsx +8 -6
- package/src/components/chart-container.tsx +2 -0
- package/src/components/chart-legend.tsx +10 -2
- package/src/components/chart-tooltip.tsx +6 -6
- package/src/components/donut-chart.tsx +2 -5
- package/src/components/form.tsx +4 -2
- package/src/components/heatmap-chart.tsx +62 -18
- package/src/components/line-chart.tsx +19 -9
- package/src/components/stat.tsx +10 -6
- package/src/components/textarea.tsx +1 -1
- package/src/lib/chart-palette.ts +16 -16
- package/src/lib/chart.ts +34 -0
- package/src/stories/area-chart.stories.tsx +1 -1
- package/src/stories/bar-chart.stories.tsx +1 -1
- package/src/stories/bar-list.stories.tsx +1 -1
- package/src/stories/donut-chart.stories.tsx +1 -1
- package/src/stories/heatmap-chart.stories.tsx +1 -1
- package/src/stories/line-chart.stories.tsx +1 -1
- package/src/stories/textarea.stories.tsx +7 -0
- package/src/stories/wizard.stories.tsx +1 -1
- package/src/styles/tokens.css +0 -45
- package/dist/hooks/use-reduced-motion.d.mts +0 -4
- package/dist/hooks/use-reduced-motion.mjs +0 -16
- package/src/hooks/use-reduced-motion.ts +0 -17
|
@@ -21,6 +21,7 @@ interface AreaChartProps {
|
|
|
21
21
|
variant?: "stacked" | "grouped" | "expand";
|
|
22
22
|
curve?: keyof typeof CURVE_TYPE;
|
|
23
23
|
legend?: boolean;
|
|
24
|
+
legendAlign?: "left" | "center" | "right";
|
|
24
25
|
valueFlags?: boolean;
|
|
25
26
|
height?: number;
|
|
26
27
|
yAxisWidth?: number;
|
|
@@ -45,6 +46,7 @@ declare function AreaChart({
|
|
|
45
46
|
variant,
|
|
46
47
|
curve,
|
|
47
48
|
legend,
|
|
49
|
+
legendAlign,
|
|
48
50
|
valueFlags,
|
|
49
51
|
height,
|
|
50
52
|
yAxisWidth,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
3
|
+
import { makeXAxisTick, orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
5
4
|
import { useChartContext } from "./chart-container.mjs";
|
|
6
5
|
import { ChartLegend } from "./chart-legend.mjs";
|
|
7
6
|
import { ChartTooltipContent } from "./chart-tooltip.mjs";
|
|
@@ -14,10 +13,9 @@ const CURVE_TYPE = {
|
|
|
14
13
|
linear: "linear",
|
|
15
14
|
step: "stepAfter"
|
|
16
15
|
};
|
|
17
|
-
function AreaChart({ data, index, series, variant = "stacked", curve = "monotone", legend = false, valueFlags = false, height = 200, yAxisWidth = 48, palette, referenceLine, markers, lastValueLabel = false, texture = false, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
16
|
+
function AreaChart({ data, index, series, variant = "stacked", curve = "monotone", legend = false, legendAlign = "left", valueFlags = false, height = 200, yAxisWidth = 48, palette, referenceLine, markers, lastValueLabel = false, texture = false, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
18
17
|
const { palette: paletteColors, theme } = useChartContext(palette);
|
|
19
18
|
const reactId = React$1.useId().replace(/:/g, "");
|
|
20
|
-
const animated = !useReducedMotion();
|
|
21
19
|
const resolved = resolveSeries(series, paletteColors, theme);
|
|
22
20
|
const stacked = variant === "stacked" || variant === "expand";
|
|
23
21
|
const rendered = stacked ? orderByLuminance(resolved) : resolved;
|
|
@@ -128,6 +126,10 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
128
126
|
}) : /* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
129
127
|
width: "100%",
|
|
130
128
|
height: "100%",
|
|
129
|
+
initialDimension: {
|
|
130
|
+
width: 0,
|
|
131
|
+
height
|
|
132
|
+
},
|
|
131
133
|
children: /* @__PURE__ */ jsxs(AreaChart$1, {
|
|
132
134
|
data,
|
|
133
135
|
stackOffset: variant === "expand" ? "expand" : "none",
|
|
@@ -177,6 +179,7 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
177
179
|
/* @__PURE__ */ jsx(XAxis, {
|
|
178
180
|
dataKey: index,
|
|
179
181
|
...axis,
|
|
182
|
+
tick: makeXAxisTick(theme),
|
|
180
183
|
interval: "preserveStartEnd",
|
|
181
184
|
minTickGap: 44
|
|
182
185
|
}),
|
|
@@ -233,7 +236,7 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
233
236
|
fill: fillFor(entry, slot),
|
|
234
237
|
dot: false,
|
|
235
238
|
activeDot: activeDotFor(entry),
|
|
236
|
-
isAnimationActive:
|
|
239
|
+
isAnimationActive: false,
|
|
237
240
|
animationDuration: 650,
|
|
238
241
|
animationEasing: "ease-out",
|
|
239
242
|
children: lastValueLabel && /* @__PURE__ */ jsx(LabelList, {
|
|
@@ -261,7 +264,8 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
261
264
|
})
|
|
262
265
|
}), legend && !isEmpty && /* @__PURE__ */ jsx(ChartLegend, {
|
|
263
266
|
items: legendItems,
|
|
264
|
-
|
|
267
|
+
align: legendAlign,
|
|
268
|
+
insetLeft: yAxisWidth
|
|
265
269
|
})]
|
|
266
270
|
});
|
|
267
271
|
}
|
|
@@ -10,6 +10,7 @@ interface BarChartProps {
|
|
|
10
10
|
series: ChartSeries[];
|
|
11
11
|
variant?: "stacked" | "grouped" | "expand";
|
|
12
12
|
legend?: boolean;
|
|
13
|
+
legendAlign?: "left" | "center" | "right";
|
|
13
14
|
valueLabels?: boolean;
|
|
14
15
|
height?: number;
|
|
15
16
|
yAxisWidth?: number;
|
|
@@ -32,6 +33,7 @@ declare function BarChart({
|
|
|
32
33
|
series,
|
|
33
34
|
variant,
|
|
34
35
|
legend,
|
|
36
|
+
legendAlign,
|
|
35
37
|
valueLabels,
|
|
36
38
|
height,
|
|
37
39
|
yAxisWidth,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
3
|
+
import { makeXAxisTick, orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
5
4
|
import { useChartContext } from "./chart-container.mjs";
|
|
6
5
|
import { ChartLegend } from "./chart-legend.mjs";
|
|
7
6
|
import { ChartTooltipContent } from "./chart-tooltip.mjs";
|
|
@@ -11,10 +10,9 @@ import { Bar, BarChart as BarChart$1, CartesianGrid, LabelList, ReferenceArea, R
|
|
|
11
10
|
//#region src/components/bar-chart.tsx
|
|
12
11
|
const BAR_RADIUS = 4;
|
|
13
12
|
const MAX_BAR_SIZE = 48;
|
|
14
|
-
function BarChart({ data, index, series, variant = "stacked", legend = false, valueLabels = false, height = 200, yAxisWidth = 48, palette, referenceLine, markers, texture = false, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
13
|
+
function BarChart({ data, index, series, variant = "stacked", legend = false, legendAlign = "left", valueLabels = false, height = 200, yAxisWidth = 48, palette, referenceLine, markers, texture = false, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
15
14
|
const { palette: paletteColors, theme } = useChartContext(palette);
|
|
16
15
|
const reactId = React$1.useId().replace(/:/g, "");
|
|
17
|
-
const animated = !useReducedMotion();
|
|
18
16
|
const resolved = resolveSeries(series, paletteColors, theme);
|
|
19
17
|
const stacked = variant === "stacked" || variant === "expand";
|
|
20
18
|
const rendered = stacked ? orderByLuminance(resolved) : resolved;
|
|
@@ -111,6 +109,10 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
111
109
|
}) : /* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
112
110
|
width: "100%",
|
|
113
111
|
height: "100%",
|
|
112
|
+
initialDimension: {
|
|
113
|
+
width: 0,
|
|
114
|
+
height
|
|
115
|
+
},
|
|
114
116
|
children: /* @__PURE__ */ jsxs(BarChart$1, {
|
|
115
117
|
data,
|
|
116
118
|
stackOffset: variant === "expand" ? "expand" : "none",
|
|
@@ -161,6 +163,7 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
161
163
|
/* @__PURE__ */ jsx(XAxis, {
|
|
162
164
|
dataKey: index,
|
|
163
165
|
...axis,
|
|
166
|
+
tick: makeXAxisTick(theme),
|
|
164
167
|
interval: "preserveStartEnd",
|
|
165
168
|
minTickGap: 44
|
|
166
169
|
}),
|
|
@@ -220,7 +223,7 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
220
223
|
stroke: theme.card,
|
|
221
224
|
strokeWidth: 1
|
|
222
225
|
},
|
|
223
|
-
isAnimationActive:
|
|
226
|
+
isAnimationActive: false,
|
|
224
227
|
animationDuration: 650,
|
|
225
228
|
animationEasing: "ease-out",
|
|
226
229
|
children: valueLabels && (!stacked || rendered.length === 1) && /* @__PURE__ */ jsx(LabelList, {
|
|
@@ -248,7 +251,8 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
248
251
|
})
|
|
249
252
|
}), legend && !isEmpty && /* @__PURE__ */ jsx(ChartLegend, {
|
|
250
253
|
items: legendItems,
|
|
251
|
-
|
|
254
|
+
align: legendAlign,
|
|
255
|
+
insetLeft: yAxisWidth
|
|
252
256
|
})]
|
|
253
257
|
});
|
|
254
258
|
}
|
|
@@ -8,6 +8,8 @@ interface BarListProps {
|
|
|
8
8
|
dataKey?: string;
|
|
9
9
|
maxItems?: number;
|
|
10
10
|
palette?: ChartPaletteName;
|
|
11
|
+
/** Renders bars in a single semantic hue (e.g. red for errors) rather than the palette ramp. */
|
|
12
|
+
semantic?: "error" | "warning" | "success";
|
|
11
13
|
loading?: boolean;
|
|
12
14
|
valueFormatter?: (value: number) => string;
|
|
13
15
|
labelFormatter?: (label: string | number) => string;
|
|
@@ -19,6 +21,7 @@ declare function BarList({
|
|
|
19
21
|
dataKey,
|
|
20
22
|
maxItems,
|
|
21
23
|
palette,
|
|
24
|
+
semantic,
|
|
22
25
|
loading,
|
|
23
26
|
valueFormatter,
|
|
24
27
|
labelFormatter,
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
|
-
import { useReducedMotion } from "../hooks/use-reduced-motion.mjs";
|
|
4
3
|
import { rampColor } from "../lib/chart-palette.mjs";
|
|
5
4
|
import { formatShare } from "../lib/chart.mjs";
|
|
6
5
|
import { useChartContext } from "./chart-container.mjs";
|
|
7
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
7
|
import * as React$1 from "react";
|
|
9
8
|
//#region src/components/bar-list.tsx
|
|
9
|
+
const SEMANTIC_KEY = {
|
|
10
|
+
error: "destructive",
|
|
11
|
+
warning: "warning",
|
|
12
|
+
success: "success"
|
|
13
|
+
};
|
|
10
14
|
const PLACEHOLDER_HEIGHT = 168;
|
|
11
15
|
const RAMP_CEILING = .8;
|
|
16
|
+
const SEMANTIC_FLOOR = .62;
|
|
12
17
|
const IN_FILL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.28)";
|
|
13
|
-
function BarList({ data, index, dataKey = "value", maxItems, palette, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
14
|
-
const { paletteName } = useChartContext(palette);
|
|
15
|
-
const
|
|
16
|
-
const [mounted, setMounted] = React$1.useState(false);
|
|
18
|
+
function BarList({ data, index, dataKey = "value", maxItems, palette, semantic, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
19
|
+
const { paletteName, theme } = useChartContext(palette);
|
|
20
|
+
const accent = semantic ? theme[SEMANTIC_KEY[semantic]] : null;
|
|
17
21
|
const [active, setActive] = React$1.useState(null);
|
|
18
|
-
React$1.useEffect(() => {
|
|
19
|
-
setMounted(true);
|
|
20
|
-
}, []);
|
|
21
22
|
const total = React$1.useMemo(() => data.reduce((sum, row) => sum + (Number(row[dataKey]) || 0), 0), [data, dataKey]);
|
|
22
23
|
const rows = React$1.useMemo(() => {
|
|
23
24
|
const mapped = data.map((row) => ({
|
|
@@ -26,16 +27,21 @@ function BarList({ data, index, dataKey = "value", maxItems, palette, loading =
|
|
|
26
27
|
}));
|
|
27
28
|
mapped.sort((lower, upper) => upper.value - lower.value);
|
|
28
29
|
const capped = maxItems ? mapped.slice(0, maxItems) : mapped;
|
|
29
|
-
return capped.map((row, rank) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
return capped.map((row, rank) => {
|
|
31
|
+
const rankFraction = capped.length > 1 ? rank / (capped.length - 1) : 0;
|
|
32
|
+
const accentWeight = Math.round((1 - rankFraction * (1 - SEMANTIC_FLOOR)) * 100);
|
|
33
|
+
return {
|
|
34
|
+
...row,
|
|
35
|
+
color: accent ? `color-mix(in oklab, ${accent} ${accentWeight}%, white)` : rampColor(paletteName, rankFraction * RAMP_CEILING)
|
|
36
|
+
};
|
|
37
|
+
});
|
|
33
38
|
}, [
|
|
34
39
|
data,
|
|
35
40
|
index,
|
|
36
41
|
dataKey,
|
|
37
42
|
maxItems,
|
|
38
|
-
paletteName
|
|
43
|
+
paletteName,
|
|
44
|
+
accent
|
|
39
45
|
]);
|
|
40
46
|
const maxValue = rows.reduce((max, row) => row.value > max ? row.value : max, 0);
|
|
41
47
|
const isEmpty = rows.length === 0;
|
|
@@ -55,7 +61,7 @@ function BarList({ data, index, dataKey = "value", maxItems, palette, loading =
|
|
|
55
61
|
className: cn("flex w-full flex-col", className),
|
|
56
62
|
children: rows.map((row, slot) => {
|
|
57
63
|
const fraction = maxValue > 0 ? row.value / maxValue : 0;
|
|
58
|
-
const fillWidth =
|
|
64
|
+
const fillWidth = `${fraction * 100}%`;
|
|
59
65
|
const dimmed = active !== null && active !== slot;
|
|
60
66
|
const isActive = active === slot;
|
|
61
67
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -73,8 +79,7 @@ function BarList({ data, index, dataKey = "value", maxItems, palette, loading =
|
|
|
73
79
|
width: fillWidth,
|
|
74
80
|
background: `linear-gradient(90deg, ${row.color}, color-mix(in oklab, ${row.color} 82%, transparent))`,
|
|
75
81
|
boxShadow: `inset 0 0 0 1px ${row.color}`,
|
|
76
|
-
opacity: dimmed ? .45 : 1
|
|
77
|
-
transition: reducedMotion ? void 0 : "width 700ms ease-out"
|
|
82
|
+
opacity: dimmed ? .45 : 1
|
|
78
83
|
},
|
|
79
84
|
children: /* @__PURE__ */ jsx("span", {
|
|
80
85
|
className: "pointer-events-none absolute top-1/2 -translate-y-1/2 truncate type-text-xs font-medium text-white",
|
|
@@ -8,7 +8,7 @@ interface ChartCardProps extends Omit<React$1.ComponentProps<"section">, "title"
|
|
|
8
8
|
title?: React$1.ReactNode;
|
|
9
9
|
description?: React$1.ReactNode;
|
|
10
10
|
action?: React$1.ReactNode;
|
|
11
|
-
accent?: "top" | "left";
|
|
11
|
+
accent?: "top" | "left" | "none";
|
|
12
12
|
}
|
|
13
13
|
declare function ChartCard({
|
|
14
14
|
palette,
|
|
@@ -12,7 +12,7 @@ function ChartCard({ palette = "magenta", kicker, title, description, action, ac
|
|
|
12
12
|
className: cn("chart-rise relative overflow-hidden rounded-xl border bg-card p-5 text-card-foreground shadow-shadow", isLeft && "pl-6", className),
|
|
13
13
|
...props,
|
|
14
14
|
children: [
|
|
15
|
-
/* @__PURE__ */ jsx("span", {
|
|
15
|
+
accent !== "none" && /* @__PURE__ */ jsx("span", {
|
|
16
16
|
"aria-hidden": true,
|
|
17
17
|
className: cn("absolute", isLeft ? "inset-y-0 left-0 w-[3px]" : "inset-x-0 top-0 h-[3px]"),
|
|
18
18
|
style: { background: lead }
|
|
@@ -17,4 +17,4 @@ declare function ChartContainer({
|
|
|
17
17
|
}): React$1.JSX.Element;
|
|
18
18
|
declare function useChartContext(paletteOverride?: ChartPaletteName): ChartContextValue;
|
|
19
19
|
//#endregion
|
|
20
|
-
export { ChartContainer, type ChartContextValue, useChartContext };
|
|
20
|
+
export { ChartContainer, type ChartContextValue, type ChartPaletteName, useChartContext };
|
|
@@ -6,10 +6,15 @@ interface ChartLegendItem {
|
|
|
6
6
|
}
|
|
7
7
|
interface ChartLegendProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
8
8
|
items: ChartLegendItem[];
|
|
9
|
+
align?: "left" | "center" | "right";
|
|
10
|
+
insetLeft?: number;
|
|
9
11
|
}
|
|
10
12
|
declare function ChartLegend({
|
|
11
13
|
items,
|
|
14
|
+
align,
|
|
15
|
+
insetLeft,
|
|
12
16
|
className,
|
|
17
|
+
style,
|
|
13
18
|
...props
|
|
14
19
|
}: ChartLegendProps): import("react").JSX.Element;
|
|
15
20
|
//#endregion
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/components/chart-legend.tsx
|
|
5
|
+
const ALIGN_CLASS = {
|
|
6
|
+
left: "justify-start",
|
|
7
|
+
center: "justify-center",
|
|
8
|
+
right: "justify-end"
|
|
9
|
+
};
|
|
5
10
|
function Swatch({ color, dashed }) {
|
|
6
11
|
return /* @__PURE__ */ jsx("span", {
|
|
7
12
|
"aria-hidden": true,
|
|
@@ -9,9 +14,13 @@ function Swatch({ color, dashed }) {
|
|
|
9
14
|
style: dashed ? { border: `1.5px solid ${color}` } : { background: color }
|
|
10
15
|
});
|
|
11
16
|
}
|
|
12
|
-
function ChartLegend({ items, className, ...props }) {
|
|
17
|
+
function ChartLegend({ items, align = "left", insetLeft, className, style, ...props }) {
|
|
13
18
|
return /* @__PURE__ */ jsx("div", {
|
|
14
|
-
className: cn("flex flex-wrap gap-x-4 gap-y-1.5", className),
|
|
19
|
+
className: cn("flex flex-wrap gap-x-4 gap-y-1.5", ALIGN_CLASS[align], className),
|
|
20
|
+
style: {
|
|
21
|
+
paddingLeft: align === "left" ? insetLeft : void 0,
|
|
22
|
+
...style
|
|
23
|
+
},
|
|
15
24
|
...props,
|
|
16
25
|
children: items.map((item) => /* @__PURE__ */ jsxs("span", {
|
|
17
26
|
className: "inline-flex items-center gap-1.5 font-mono text-[10px] text-muted-foreground uppercase tracking-[0.12em]",
|
|
@@ -6,7 +6,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
function ChartTooltipContent({ active, payload, label, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, hideLabel, showTotal, totalLabel = "Total", className }) {
|
|
7
7
|
const { theme } = useChartContext();
|
|
8
8
|
if (!active || !payload?.length) return null;
|
|
9
|
-
const
|
|
9
|
+
const toNumber = (value) => typeof value === "number" ? value : Number(value ?? 0);
|
|
10
|
+
const total = payload.reduce((sum, item) => sum + toNumber(item.value), 0);
|
|
11
|
+
const rows = [...payload].sort((lower, upper) => toNumber(upper.value) - toNumber(lower.value));
|
|
10
12
|
return /* @__PURE__ */ jsxs("div", {
|
|
11
13
|
className: cn("min-w-[130px] rounded-lg border px-3 py-2.5 shadow-lg", "border-border bg-popover text-popover-foreground", className),
|
|
12
14
|
children: [!hideLabel && label !== void 0 && /* @__PURE__ */ jsx("p", {
|
|
@@ -14,13 +16,13 @@ function ChartTooltipContent({ active, payload, label, valueFormatter = (value)
|
|
|
14
16
|
children: labelFormatter ? labelFormatter(label) : label
|
|
15
17
|
}), /* @__PURE__ */ jsxs("div", {
|
|
16
18
|
className: "flex flex-col gap-1",
|
|
17
|
-
children: [
|
|
19
|
+
children: [rows.map((item, index) => {
|
|
18
20
|
const swatch = [
|
|
19
21
|
item.color,
|
|
20
22
|
item.stroke,
|
|
21
23
|
item.fill
|
|
22
24
|
].find((candidate) => typeof candidate === "string" && candidate.length > 0 && !candidate.startsWith("url(")) ?? theme.mutedForeground;
|
|
23
|
-
const numeric =
|
|
25
|
+
const numeric = toNumber(item.value);
|
|
24
26
|
return /* @__PURE__ */ jsxs("div", {
|
|
25
27
|
className: "flex items-center justify-between gap-4 text-text-xs",
|
|
26
28
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
|
-
import { useReducedMotion } from "../hooks/use-reduced-motion.mjs";
|
|
4
3
|
import { paletteColor } from "../lib/chart-palette.mjs";
|
|
5
4
|
import { formatShare } from "../lib/chart.mjs";
|
|
6
5
|
import { useChartContext } from "./chart-container.mjs";
|
|
@@ -21,7 +20,6 @@ const GEOMETRY = {
|
|
|
21
20
|
function DonutChart({ data, index, dataKey = "value", variant = "donut", legend = false, paddingAngle = 1, height = 220, palette, centerLabel = "total", loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
22
21
|
const { palette: paletteColors, theme } = useChartContext(palette);
|
|
23
22
|
const reactId = React$1.useId().replace(/:/g, "");
|
|
24
|
-
const animated = !useReducedMotion();
|
|
25
23
|
const [active, setActive] = React$1.useState(null);
|
|
26
24
|
const rowRefs = React$1.useRef([]);
|
|
27
25
|
const slices = React$1.useMemo(() => {
|
|
@@ -73,6 +71,10 @@ function DonutChart({ data, index, dataKey = "value", variant = "donut", legend
|
|
|
73
71
|
children: [/* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
74
72
|
width: "100%",
|
|
75
73
|
height: "100%",
|
|
74
|
+
initialDimension: {
|
|
75
|
+
width: 0,
|
|
76
|
+
height
|
|
77
|
+
},
|
|
76
78
|
children: /* @__PURE__ */ jsxs(PieChart, { children: [/* @__PURE__ */ jsx("defs", { children: slices.map((slice, slot) => /* @__PURE__ */ jsxs("linearGradient", {
|
|
77
79
|
id: `donut-${reactId}-${slot}`,
|
|
78
80
|
x1: "0",
|
|
@@ -100,7 +102,7 @@ function DonutChart({ data, index, dataKey = "value", variant = "donut", legend
|
|
|
100
102
|
cornerRadius: 2,
|
|
101
103
|
stroke: theme.card,
|
|
102
104
|
strokeWidth: 1.5,
|
|
103
|
-
isAnimationActive:
|
|
105
|
+
isAnimationActive: false,
|
|
104
106
|
animationDuration: 650,
|
|
105
107
|
animationEasing: "ease-out",
|
|
106
108
|
onMouseEnter: (_entry, sliceIndex) => setActive(sliceIndex),
|
package/dist/components/form.mjs
CHANGED
|
@@ -41,10 +41,12 @@ const useFormField = () => {
|
|
|
41
41
|
const FormItemContext = React$1.createContext({});
|
|
42
42
|
function FormItem({ className, ...props }) {
|
|
43
43
|
const id = React$1.useId();
|
|
44
|
+
const { name } = React$1.useContext(FormFieldContext);
|
|
44
45
|
return /* @__PURE__ */ jsx(FormItemContext.Provider, {
|
|
45
46
|
value: { id },
|
|
46
47
|
children: /* @__PURE__ */ jsx("div", {
|
|
47
48
|
"data-slot": "form-item",
|
|
49
|
+
"data-field-name": name,
|
|
48
50
|
className: cn("grid gap-2", className),
|
|
49
51
|
...props
|
|
50
52
|
})
|
|
@@ -65,7 +67,7 @@ function FormLabel({ className, required, tooltip, children, ...props }) {
|
|
|
65
67
|
}),
|
|
66
68
|
required && /* @__PURE__ */ jsx("span", {
|
|
67
69
|
"aria-hidden": true,
|
|
68
|
-
className: "type-text-sm font-medium text-required",
|
|
70
|
+
className: "type-text-sm font-medium text-required leading-none",
|
|
69
71
|
children: "*"
|
|
70
72
|
}),
|
|
71
73
|
tooltip && /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
@@ -11,11 +11,17 @@ interface HeatmapChartProps {
|
|
|
11
11
|
palette?: ChartPaletteName;
|
|
12
12
|
xLabels?: readonly string[];
|
|
13
13
|
yLabels?: readonly string[];
|
|
14
|
+
showAllXLabels?: boolean;
|
|
14
15
|
highlightPeak?: boolean;
|
|
15
16
|
loading?: boolean;
|
|
16
17
|
valueFormatter?: (value: number) => string;
|
|
17
18
|
xTickFormatter?: (label: string) => string;
|
|
18
19
|
yTickFormatter?: (label: string) => string;
|
|
20
|
+
tooltipMetrics?: ReadonlyArray<{
|
|
21
|
+
key: string;
|
|
22
|
+
label: string;
|
|
23
|
+
format?: (value: number) => string;
|
|
24
|
+
}>;
|
|
19
25
|
ariaLabel?: string;
|
|
20
26
|
className?: string;
|
|
21
27
|
}
|
|
@@ -28,11 +34,13 @@ declare function HeatmapChart({
|
|
|
28
34
|
palette,
|
|
29
35
|
xLabels,
|
|
30
36
|
yLabels,
|
|
37
|
+
showAllXLabels,
|
|
31
38
|
highlightPeak,
|
|
32
39
|
loading,
|
|
33
40
|
valueFormatter,
|
|
34
41
|
xTickFormatter,
|
|
35
42
|
yTickFormatter,
|
|
43
|
+
tooltipMetrics,
|
|
36
44
|
ariaLabel,
|
|
37
45
|
className
|
|
38
46
|
}: HeatmapChartProps): React$1.JSX.Element;
|
|
@@ -31,7 +31,7 @@ const uniqueInOrder = (values) => {
|
|
|
31
31
|
}
|
|
32
32
|
return ordered;
|
|
33
33
|
};
|
|
34
|
-
function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square", palette, xLabels, yLabels, highlightPeak = true, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), xTickFormatter, yTickFormatter, ariaLabel = "Activity heatmap", className }) {
|
|
34
|
+
function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square", palette, xLabels, yLabels, showAllXLabels = false, highlightPeak = true, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), xTickFormatter, yTickFormatter, tooltipMetrics, ariaLabel = "Activity heatmap", className }) {
|
|
35
35
|
const { paletteName, theme } = useChartContext(palette);
|
|
36
36
|
const [hovered, setHovered] = React$1.useState(null);
|
|
37
37
|
const [mounted, setMounted] = React$1.useState(false);
|
|
@@ -42,24 +42,31 @@ function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square",
|
|
|
42
42
|
const columns = xLabels ? [...xLabels] : uniqueInOrder(data.map((row) => String(row[xKey] ?? "")));
|
|
43
43
|
const rows = yLabels ? [...yLabels] : uniqueInOrder(data.map((row) => String(row[yKey] ?? "")));
|
|
44
44
|
const valueAt = /* @__PURE__ */ new Map();
|
|
45
|
-
|
|
45
|
+
const recordAt = /* @__PURE__ */ new Map();
|
|
46
|
+
for (const row of data) {
|
|
47
|
+
const key = pairKey(String(row[yKey] ?? ""), String(row[xKey] ?? ""));
|
|
48
|
+
valueAt.set(key, Number(row[dataKey]) || 0);
|
|
49
|
+
recordAt.set(key, row);
|
|
50
|
+
}
|
|
46
51
|
let maxValue = 0;
|
|
47
52
|
let peakKey = "";
|
|
48
53
|
return {
|
|
49
54
|
columns,
|
|
50
55
|
rows,
|
|
51
56
|
cells: rows.flatMap((rowLabel, rowIndex) => columns.map((colLabel, colIndex) => {
|
|
52
|
-
const
|
|
57
|
+
const key = pairKey(rowLabel, colLabel);
|
|
58
|
+
const value = valueAt.get(key) ?? 0;
|
|
53
59
|
if (value > maxValue) {
|
|
54
60
|
maxValue = value;
|
|
55
|
-
peakKey =
|
|
61
|
+
peakKey = key;
|
|
56
62
|
}
|
|
57
63
|
return {
|
|
58
64
|
rowLabel,
|
|
59
65
|
colLabel,
|
|
60
66
|
rowIndex,
|
|
61
67
|
colIndex,
|
|
62
|
-
value
|
|
68
|
+
value,
|
|
69
|
+
record: recordAt.get(key) ?? null
|
|
63
70
|
};
|
|
64
71
|
})),
|
|
65
72
|
maxValue,
|
|
@@ -87,7 +94,7 @@ function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square",
|
|
|
87
94
|
const ramp = heatRamp(paletteName, theme.isDark ? HEAT_EMPTY.dark : HEAT_EMPTY.light);
|
|
88
95
|
const totalWidth = PAD.left + columns.length * CELL + (columns.length - 1) * GAP + PAD.right;
|
|
89
96
|
const totalHeight = PAD.top + rows.length * CELL + (rows.length - 1) * GAP + PAD.bottom;
|
|
90
|
-
const xStride = Math.ceil(columns.length / MAX_X_TICKS);
|
|
97
|
+
const xStride = showAllXLabels ? 1 : Math.ceil(columns.length / MAX_X_TICKS);
|
|
91
98
|
const cellX = (col) => PAD.left + col * 25;
|
|
92
99
|
const cellY = (row) => PAD.top + row * 25;
|
|
93
100
|
const formatX = (label) => xTickFormatter ? xTickFormatter(label) : label;
|
|
@@ -159,7 +166,8 @@ function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square",
|
|
|
159
166
|
y: event.clientY,
|
|
160
167
|
rowLabel: cell.rowLabel,
|
|
161
168
|
colLabel: cell.colLabel,
|
|
162
|
-
value: cell.value
|
|
169
|
+
value: cell.value,
|
|
170
|
+
record: cell.record
|
|
163
171
|
})
|
|
164
172
|
}, `hit-${pairKey(cell.rowLabel, cell.colLabel)}`))
|
|
165
173
|
]
|
|
@@ -177,7 +185,30 @@ function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square",
|
|
|
177
185
|
" · ",
|
|
178
186
|
formatX(hovered.colLabel)
|
|
179
187
|
]
|
|
180
|
-
}), /* @__PURE__ */
|
|
188
|
+
}), tooltipMetrics && tooltipMetrics.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
189
|
+
className: "flex flex-col gap-1",
|
|
190
|
+
children: tooltipMetrics.map((metric) => {
|
|
191
|
+
const raw = hovered.record ? Number(hovered.record[metric.key]) || 0 : 0;
|
|
192
|
+
const isActive = metric.key === dataKey;
|
|
193
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
194
|
+
className: "flex items-center justify-between gap-4 text-text-xs",
|
|
195
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
196
|
+
className: "inline-flex items-center gap-2 text-muted-foreground",
|
|
197
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
198
|
+
"aria-hidden": true,
|
|
199
|
+
className: "size-2 shrink-0 rounded-[2px]",
|
|
200
|
+
style: {
|
|
201
|
+
background: isActive ? heatColor(ramp, hovered.value / maxValue) : theme.mutedForeground,
|
|
202
|
+
opacity: isActive ? 1 : .35
|
|
203
|
+
}
|
|
204
|
+
}), metric.label]
|
|
205
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
206
|
+
className: cn("font-mono tabular-nums", isActive ? "font-semibold text-foreground" : "text-muted-foreground"),
|
|
207
|
+
children: (metric.format ?? valueFormatter)(raw)
|
|
208
|
+
})]
|
|
209
|
+
}, metric.key);
|
|
210
|
+
})
|
|
211
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
181
212
|
className: "flex items-center justify-between gap-4 text-text-xs",
|
|
182
213
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
183
214
|
className: "inline-flex items-center gap-2 text-muted-foreground",
|
|
@@ -15,6 +15,7 @@ interface LineChartProps {
|
|
|
15
15
|
series: ChartSeries[];
|
|
16
16
|
curve?: keyof typeof CURVE_TYPE;
|
|
17
17
|
legend?: boolean;
|
|
18
|
+
legendAlign?: "left" | "center" | "right";
|
|
18
19
|
valueFlags?: boolean;
|
|
19
20
|
dots?: boolean;
|
|
20
21
|
height?: number;
|
|
@@ -38,6 +39,7 @@ declare function LineChart({
|
|
|
38
39
|
series,
|
|
39
40
|
curve,
|
|
40
41
|
legend,
|
|
42
|
+
legendAlign,
|
|
41
43
|
valueFlags,
|
|
42
44
|
dots,
|
|
43
45
|
height,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { resolveSeries } from "../lib/chart.mjs";
|
|
3
|
+
import { makeXAxisTick, resolveSeries } from "../lib/chart.mjs";
|
|
5
4
|
import { useChartContext } from "./chart-container.mjs";
|
|
6
5
|
import { ChartLegend } from "./chart-legend.mjs";
|
|
7
6
|
import { ChartTooltipContent } from "./chart-tooltip.mjs";
|
|
@@ -14,9 +13,8 @@ const CURVE_TYPE = {
|
|
|
14
13
|
linear: "linear",
|
|
15
14
|
step: "stepAfter"
|
|
16
15
|
};
|
|
17
|
-
function LineChart({ data, index, series, curve = "monotone", legend = false, valueFlags = false, dots = false, height = 200, yAxisWidth = 48, palette, referenceLine, markers, lastValueLabel = false, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
16
|
+
function LineChart({ data, index, series, curve = "monotone", legend = false, legendAlign = "left", valueFlags = false, dots = false, height = 200, yAxisWidth = 48, palette, referenceLine, markers, lastValueLabel = false, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
18
17
|
const { palette: paletteColors, theme } = useChartContext(palette);
|
|
19
|
-
const animated = !useReducedMotion();
|
|
20
18
|
const resolved = resolveSeries(series, paletteColors, theme);
|
|
21
19
|
const numericMax = React$1.useMemo(() => {
|
|
22
20
|
let max = 0;
|
|
@@ -106,6 +104,10 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, va
|
|
|
106
104
|
}) : /* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
107
105
|
width: "100%",
|
|
108
106
|
height: "100%",
|
|
107
|
+
initialDimension: {
|
|
108
|
+
width: 0,
|
|
109
|
+
height
|
|
110
|
+
},
|
|
109
111
|
children: /* @__PURE__ */ jsxs(LineChart$1, {
|
|
110
112
|
data,
|
|
111
113
|
margin,
|
|
@@ -118,12 +120,14 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, va
|
|
|
118
120
|
/* @__PURE__ */ jsx(XAxis, {
|
|
119
121
|
dataKey: index,
|
|
120
122
|
...axis,
|
|
123
|
+
tick: makeXAxisTick(theme),
|
|
121
124
|
interval: "preserveStartEnd",
|
|
122
125
|
minTickGap: 44
|
|
123
126
|
}),
|
|
124
127
|
/* @__PURE__ */ jsx(YAxis, {
|
|
125
128
|
...axis,
|
|
126
129
|
width: yAxisWidth,
|
|
130
|
+
domain: ["auto", "auto"],
|
|
127
131
|
tickFormatter: (value) => valueFormatter(value)
|
|
128
132
|
}),
|
|
129
133
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
@@ -175,7 +179,7 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, va
|
|
|
175
179
|
strokeWidth: 0
|
|
176
180
|
} : false,
|
|
177
181
|
activeDot: activeDotFor(entry),
|
|
178
|
-
isAnimationActive:
|
|
182
|
+
isAnimationActive: false,
|
|
179
183
|
animationDuration: 650,
|
|
180
184
|
animationEasing: "ease-out",
|
|
181
185
|
children: lastValueLabel && /* @__PURE__ */ jsx(LabelList, {
|
|
@@ -203,7 +207,8 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, va
|
|
|
203
207
|
})
|
|
204
208
|
}), legend && !isEmpty && /* @__PURE__ */ jsx(ChartLegend, {
|
|
205
209
|
items: legendItems,
|
|
206
|
-
|
|
210
|
+
align: legendAlign,
|
|
211
|
+
insetLeft: yAxisWidth
|
|
207
212
|
})]
|
|
208
213
|
});
|
|
209
214
|
}
|
|
@@ -13,16 +13,18 @@ interface StatDelta {
|
|
|
13
13
|
interface StatProps extends React$1.ComponentProps<"div"> {
|
|
14
14
|
value: React$1.ReactNode;
|
|
15
15
|
unit?: string;
|
|
16
|
-
delta?: StatDelta;
|
|
16
|
+
delta?: StatDelta | null;
|
|
17
17
|
sparkline?: number[] | Array<{
|
|
18
18
|
value: number;
|
|
19
19
|
}>;
|
|
20
|
+
semantic?: "error" | "warning" | "success";
|
|
20
21
|
}
|
|
21
22
|
declare function Stat({
|
|
22
23
|
value,
|
|
23
24
|
unit,
|
|
24
25
|
delta,
|
|
25
26
|
sparkline,
|
|
27
|
+
semantic,
|
|
26
28
|
className,
|
|
27
29
|
...props
|
|
28
30
|
}: StatProps): React$1.JSX.Element;
|