@alpic-ai/ui 0.0.0-dev.g05467b7 → 0.0.0-dev.g05c89ce
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 +9 -3
- package/dist/components/bar-chart.d.mts +2 -0
- package/dist/components/bar-chart.mjs +9 -3
- package/dist/components/bar-list.d.mts +3 -0
- package/dist/components/bar-list.mjs +25 -12
- 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/donut-chart.mjs +9 -5
- package/dist/components/form.mjs +1 -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 +10 -3
- package/dist/components/stat.d.mts +3 -1
- package/dist/components/stat.mjs +14 -4
- package/dist/components/wizard.d.mts +1 -19
- package/dist/components/wizard.mjs +1 -19
- package/dist/lib/chart.mjs +16 -1
- package/package.json +23 -23
- package/src/components/area-chart.tsx +12 -4
- package/src/components/bar-chart.tsx +12 -4
- package/src/components/bar-list.tsx +26 -10
- 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/donut-chart.tsx +6 -6
- package/src/components/form.tsx +1 -1
- package/src/components/heatmap-chart.tsx +62 -18
- package/src/components/line-chart.tsx +18 -5
- package/src/components/stat.tsx +10 -6
- package/src/components/wizard.tsx +1 -35
- package/src/lib/chart.ts +34 -0
- package/src/stories/area-chart.stories.tsx +1 -3
- package/src/stories/bar-chart.stories.tsx +1 -3
- package/src/stories/bar-list.stories.tsx +1 -3
- package/src/stories/donut-chart.stories.tsx +1 -3
- package/src/stories/heatmap-chart.stories.tsx +1 -3
- package/src/stories/line-chart.stories.tsx +1 -3
- package/src/stories/wizard.stories.tsx +23 -5
- package/src/styles/tokens.css +0 -45
- package/dist/components/grid-fx.d.mts +0 -13
- package/dist/components/grid-fx.mjs +0 -188
- package/src/components/grid-fx.tsx +0 -238
|
@@ -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,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
3
|
import { useReducedMotion } from "../hooks/use-reduced-motion.mjs";
|
|
4
|
-
import { orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
4
|
+
import { makeXAxisTick, orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
5
5
|
import { useChartContext } from "./chart-container.mjs";
|
|
6
6
|
import { ChartLegend } from "./chart-legend.mjs";
|
|
7
7
|
import { ChartTooltipContent } from "./chart-tooltip.mjs";
|
|
@@ -14,7 +14,7 @@ const CURVE_TYPE = {
|
|
|
14
14
|
linear: "linear",
|
|
15
15
|
step: "stepAfter"
|
|
16
16
|
};
|
|
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 }) {
|
|
17
|
+
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
18
|
const { palette: paletteColors, theme } = useChartContext(palette);
|
|
19
19
|
const reactId = React$1.useId().replace(/:/g, "");
|
|
20
20
|
const animated = !useReducedMotion();
|
|
@@ -128,6 +128,10 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
128
128
|
}) : /* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
129
129
|
width: "100%",
|
|
130
130
|
height: "100%",
|
|
131
|
+
initialDimension: {
|
|
132
|
+
width: 0,
|
|
133
|
+
height
|
|
134
|
+
},
|
|
131
135
|
children: /* @__PURE__ */ jsxs(AreaChart$1, {
|
|
132
136
|
data,
|
|
133
137
|
stackOffset: variant === "expand" ? "expand" : "none",
|
|
@@ -177,6 +181,7 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
177
181
|
/* @__PURE__ */ jsx(XAxis, {
|
|
178
182
|
dataKey: index,
|
|
179
183
|
...axis,
|
|
184
|
+
tick: makeXAxisTick(theme),
|
|
180
185
|
interval: "preserveStartEnd",
|
|
181
186
|
minTickGap: 44
|
|
182
187
|
}),
|
|
@@ -261,7 +266,8 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
261
266
|
})
|
|
262
267
|
}), legend && !isEmpty && /* @__PURE__ */ jsx(ChartLegend, {
|
|
263
268
|
items: legendItems,
|
|
264
|
-
|
|
269
|
+
align: legendAlign,
|
|
270
|
+
insetLeft: yAxisWidth
|
|
265
271
|
})]
|
|
266
272
|
});
|
|
267
273
|
}
|
|
@@ -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,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
3
|
import { useReducedMotion } from "../hooks/use-reduced-motion.mjs";
|
|
4
|
-
import { orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
4
|
+
import { makeXAxisTick, orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
5
5
|
import { useChartContext } from "./chart-container.mjs";
|
|
6
6
|
import { ChartLegend } from "./chart-legend.mjs";
|
|
7
7
|
import { ChartTooltipContent } from "./chart-tooltip.mjs";
|
|
@@ -11,7 +11,7 @@ import { Bar, BarChart as BarChart$1, CartesianGrid, LabelList, ReferenceArea, R
|
|
|
11
11
|
//#region src/components/bar-chart.tsx
|
|
12
12
|
const BAR_RADIUS = 4;
|
|
13
13
|
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 }) {
|
|
14
|
+
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
15
|
const { palette: paletteColors, theme } = useChartContext(palette);
|
|
16
16
|
const reactId = React$1.useId().replace(/:/g, "");
|
|
17
17
|
const animated = !useReducedMotion();
|
|
@@ -111,6 +111,10 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
111
111
|
}) : /* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
112
112
|
width: "100%",
|
|
113
113
|
height: "100%",
|
|
114
|
+
initialDimension: {
|
|
115
|
+
width: 0,
|
|
116
|
+
height
|
|
117
|
+
},
|
|
114
118
|
children: /* @__PURE__ */ jsxs(BarChart$1, {
|
|
115
119
|
data,
|
|
116
120
|
stackOffset: variant === "expand" ? "expand" : "none",
|
|
@@ -161,6 +165,7 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
161
165
|
/* @__PURE__ */ jsx(XAxis, {
|
|
162
166
|
dataKey: index,
|
|
163
167
|
...axis,
|
|
168
|
+
tick: makeXAxisTick(theme),
|
|
164
169
|
interval: "preserveStartEnd",
|
|
165
170
|
minTickGap: 44
|
|
166
171
|
}),
|
|
@@ -248,7 +253,8 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
248
253
|
})
|
|
249
254
|
}), legend && !isEmpty && /* @__PURE__ */ jsx(ChartLegend, {
|
|
250
255
|
items: legendItems,
|
|
251
|
-
|
|
256
|
+
align: legendAlign,
|
|
257
|
+
insetLeft: yAxisWidth
|
|
252
258
|
})]
|
|
253
259
|
});
|
|
254
260
|
}
|
|
@@ -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,
|
|
@@ -7,11 +7,18 @@ import { useChartContext } from "./chart-container.mjs";
|
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import * as React$1 from "react";
|
|
9
9
|
//#region src/components/bar-list.tsx
|
|
10
|
+
const SEMANTIC_KEY = {
|
|
11
|
+
error: "destructive",
|
|
12
|
+
warning: "warning",
|
|
13
|
+
success: "success"
|
|
14
|
+
};
|
|
10
15
|
const PLACEHOLDER_HEIGHT = 168;
|
|
11
16
|
const RAMP_CEILING = .8;
|
|
17
|
+
const SEMANTIC_FLOOR = .62;
|
|
12
18
|
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);
|
|
19
|
+
function BarList({ data, index, dataKey = "value", maxItems, palette, semantic, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
|
|
20
|
+
const { paletteName, theme } = useChartContext(palette);
|
|
21
|
+
const accent = semantic ? theme[SEMANTIC_KEY[semantic]] : null;
|
|
15
22
|
const reducedMotion = useReducedMotion();
|
|
16
23
|
const [mounted, setMounted] = React$1.useState(false);
|
|
17
24
|
const [active, setActive] = React$1.useState(null);
|
|
@@ -26,16 +33,21 @@ function BarList({ data, index, dataKey = "value", maxItems, palette, loading =
|
|
|
26
33
|
}));
|
|
27
34
|
mapped.sort((lower, upper) => upper.value - lower.value);
|
|
28
35
|
const capped = maxItems ? mapped.slice(0, maxItems) : mapped;
|
|
29
|
-
return capped.map((row, rank) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
return capped.map((row, rank) => {
|
|
37
|
+
const rankFraction = capped.length > 1 ? rank / (capped.length - 1) : 0;
|
|
38
|
+
const accentWeight = Math.round((1 - rankFraction * (1 - SEMANTIC_FLOOR)) * 100);
|
|
39
|
+
return {
|
|
40
|
+
...row,
|
|
41
|
+
color: accent ? `color-mix(in oklab, ${accent} ${accentWeight}%, white)` : rampColor(paletteName, rankFraction * RAMP_CEILING)
|
|
42
|
+
};
|
|
43
|
+
});
|
|
33
44
|
}, [
|
|
34
45
|
data,
|
|
35
46
|
index,
|
|
36
47
|
dataKey,
|
|
37
48
|
maxItems,
|
|
38
|
-
paletteName
|
|
49
|
+
paletteName,
|
|
50
|
+
accent
|
|
39
51
|
]);
|
|
40
52
|
const maxValue = rows.reduce((max, row) => row.value > max ? row.value : max, 0);
|
|
41
53
|
const isEmpty = rows.length === 0;
|
|
@@ -52,7 +64,7 @@ function BarList({ data, index, dataKey = "value", maxItems, palette, loading =
|
|
|
52
64
|
});
|
|
53
65
|
return /* @__PURE__ */ jsx("div", {
|
|
54
66
|
"data-slot": "bar-list",
|
|
55
|
-
className: cn("flex w-full flex-col
|
|
67
|
+
className: cn("flex w-full flex-col", className),
|
|
56
68
|
children: rows.map((row, slot) => {
|
|
57
69
|
const fraction = maxValue > 0 ? row.value / maxValue : 0;
|
|
58
70
|
const fillWidth = !reducedMotion && !mounted ? "0%" : `${fraction * 100}%`;
|
|
@@ -61,19 +73,20 @@ function BarList({ data, index, dataKey = "value", maxItems, palette, loading =
|
|
|
61
73
|
return /* @__PURE__ */ jsxs("div", {
|
|
62
74
|
onMouseEnter: () => setActive(slot),
|
|
63
75
|
onMouseLeave: () => setActive(null),
|
|
64
|
-
className: "flex items-center gap-3",
|
|
76
|
+
className: "flex items-center gap-3 py-1",
|
|
65
77
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
66
78
|
className: "relative h-[30px] flex-1 overflow-hidden rounded-md bg-muted",
|
|
67
79
|
children: [/* @__PURE__ */ jsx("span", {
|
|
68
80
|
className: "pointer-events-none absolute inset-x-3 top-1/2 z-0 -translate-y-1/2 truncate type-text-xs font-medium text-foreground",
|
|
69
81
|
children: formatName(row.name)
|
|
70
82
|
}), /* @__PURE__ */ jsx("div", {
|
|
71
|
-
className: "absolute inset-y-0 left-0 z-10 overflow-hidden rounded-md
|
|
83
|
+
className: "absolute inset-y-0 left-0 z-10 overflow-hidden rounded-md",
|
|
72
84
|
style: {
|
|
73
85
|
width: fillWidth,
|
|
74
86
|
background: `linear-gradient(90deg, ${row.color}, color-mix(in oklab, ${row.color} 82%, transparent))`,
|
|
75
87
|
boxShadow: `inset 0 0 0 1px ${row.color}`,
|
|
76
|
-
opacity: dimmed ? .45 : 1
|
|
88
|
+
opacity: dimmed ? .45 : 1,
|
|
89
|
+
transition: reducedMotion ? void 0 : "width 700ms ease-out"
|
|
77
90
|
},
|
|
78
91
|
children: /* @__PURE__ */ jsx("span", {
|
|
79
92
|
className: "pointer-events-none absolute top-1/2 -translate-y-1/2 truncate type-text-xs font-medium text-white",
|
|
@@ -86,7 +99,7 @@ function BarList({ data, index, dataKey = "value", maxItems, palette, loading =
|
|
|
86
99
|
})
|
|
87
100
|
})]
|
|
88
101
|
}), /* @__PURE__ */ jsx("span", {
|
|
89
|
-
className: "w-
|
|
102
|
+
className: "min-w-[4rem] shrink-0 whitespace-nowrap text-right font-mono text-text-xs tabular-nums motion-safe:transition-colors",
|
|
90
103
|
style: { color: isActive ? row.color : void 0 },
|
|
91
104
|
children: isActive ? formatShare(total > 0 ? row.value / total : 0) : valueFormatter(row.value)
|
|
92
105
|
})]
|
|
@@ -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]",
|
|
@@ -73,6 +73,10 @@ function DonutChart({ data, index, dataKey = "value", variant = "donut", legend
|
|
|
73
73
|
children: [/* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
74
74
|
width: "100%",
|
|
75
75
|
height: "100%",
|
|
76
|
+
initialDimension: {
|
|
77
|
+
width: 0,
|
|
78
|
+
height
|
|
79
|
+
},
|
|
76
80
|
children: /* @__PURE__ */ jsxs(PieChart, { children: [/* @__PURE__ */ jsx("defs", { children: slices.map((slice, slot) => /* @__PURE__ */ jsxs("linearGradient", {
|
|
77
81
|
id: `donut-${reactId}-${slot}`,
|
|
78
82
|
x1: "0",
|
|
@@ -117,7 +121,7 @@ function DonutChart({ data, index, dataKey = "value", variant = "donut", legend
|
|
|
117
121
|
className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-1 text-center",
|
|
118
122
|
children: [
|
|
119
123
|
/* @__PURE__ */ jsx("span", {
|
|
120
|
-
className: "max-w-[
|
|
124
|
+
className: "max-w-[52%] truncate font-mono text-[10px] text-quaternary-foreground uppercase tracking-[0.18em]",
|
|
121
125
|
children: centerTitle
|
|
122
126
|
}),
|
|
123
127
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -143,7 +147,7 @@ function DonutChart({ data, index, dataKey = "value", variant = "donut", legend
|
|
|
143
147
|
onMouseLeave: () => setActive(null),
|
|
144
148
|
className: cn("flex flex-col gap-1.5 border-border/40 border-b px-2 py-2 text-text-xs last:border-b-0 motion-safe:transition-colors", active === slot ? "bg-muted/50" : "bg-transparent"),
|
|
145
149
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
146
|
-
className: "flex items-center justify-between gap-
|
|
150
|
+
className: "flex items-center justify-between gap-2",
|
|
147
151
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
148
152
|
className: "inline-flex min-w-0 items-center gap-2 text-muted-foreground",
|
|
149
153
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -155,12 +159,12 @@ function DonutChart({ data, index, dataKey = "value", variant = "donut", legend
|
|
|
155
159
|
children: formatName(slice.name)
|
|
156
160
|
})]
|
|
157
161
|
}), /* @__PURE__ */ jsxs("span", {
|
|
158
|
-
className: "flex shrink-0 items-center gap-
|
|
162
|
+
className: "flex shrink-0 items-center gap-2 font-mono tabular-nums",
|
|
159
163
|
children: [/* @__PURE__ */ jsx("span", {
|
|
160
|
-
className: "min-w-[
|
|
164
|
+
className: "min-w-[2.25rem] text-right font-semibold text-foreground",
|
|
161
165
|
children: valueFormatter(slice.value)
|
|
162
166
|
}), /* @__PURE__ */ jsx("span", {
|
|
163
|
-
className: "w-
|
|
167
|
+
className: "w-9 text-right text-quaternary-foreground",
|
|
164
168
|
children: formatShare(slice.value / total)
|
|
165
169
|
})]
|
|
166
170
|
})]
|
package/dist/components/form.mjs
CHANGED
|
@@ -65,7 +65,7 @@ function FormLabel({ className, required, tooltip, children, ...props }) {
|
|
|
65
65
|
}),
|
|
66
66
|
required && /* @__PURE__ */ jsx("span", {
|
|
67
67
|
"aria-hidden": true,
|
|
68
|
-
className: "type-text-sm font-medium text-required",
|
|
68
|
+
className: "type-text-sm font-medium text-required leading-none",
|
|
69
69
|
children: "*"
|
|
70
70
|
}),
|
|
71
71
|
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,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
3
|
import { useReducedMotion } from "../hooks/use-reduced-motion.mjs";
|
|
4
|
-
import { resolveSeries } from "../lib/chart.mjs";
|
|
4
|
+
import { makeXAxisTick, resolveSeries } from "../lib/chart.mjs";
|
|
5
5
|
import { useChartContext } from "./chart-container.mjs";
|
|
6
6
|
import { ChartLegend } from "./chart-legend.mjs";
|
|
7
7
|
import { ChartTooltipContent } from "./chart-tooltip.mjs";
|
|
@@ -14,7 +14,7 @@ const CURVE_TYPE = {
|
|
|
14
14
|
linear: "linear",
|
|
15
15
|
step: "stepAfter"
|
|
16
16
|
};
|
|
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 }) {
|
|
17
|
+
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
18
|
const { palette: paletteColors, theme } = useChartContext(palette);
|
|
19
19
|
const animated = !useReducedMotion();
|
|
20
20
|
const resolved = resolveSeries(series, paletteColors, theme);
|
|
@@ -106,6 +106,10 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, va
|
|
|
106
106
|
}) : /* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
107
107
|
width: "100%",
|
|
108
108
|
height: "100%",
|
|
109
|
+
initialDimension: {
|
|
110
|
+
width: 0,
|
|
111
|
+
height
|
|
112
|
+
},
|
|
109
113
|
children: /* @__PURE__ */ jsxs(LineChart$1, {
|
|
110
114
|
data,
|
|
111
115
|
margin,
|
|
@@ -118,12 +122,14 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, va
|
|
|
118
122
|
/* @__PURE__ */ jsx(XAxis, {
|
|
119
123
|
dataKey: index,
|
|
120
124
|
...axis,
|
|
125
|
+
tick: makeXAxisTick(theme),
|
|
121
126
|
interval: "preserveStartEnd",
|
|
122
127
|
minTickGap: 44
|
|
123
128
|
}),
|
|
124
129
|
/* @__PURE__ */ jsx(YAxis, {
|
|
125
130
|
...axis,
|
|
126
131
|
width: yAxisWidth,
|
|
132
|
+
domain: ["auto", "auto"],
|
|
127
133
|
tickFormatter: (value) => valueFormatter(value)
|
|
128
134
|
}),
|
|
129
135
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
@@ -203,7 +209,8 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, va
|
|
|
203
209
|
})
|
|
204
210
|
}), legend && !isEmpty && /* @__PURE__ */ jsx(ChartLegend, {
|
|
205
211
|
items: legendItems,
|
|
206
|
-
|
|
212
|
+
align: legendAlign,
|
|
213
|
+
insetLeft: yAxisWidth
|
|
207
214
|
})]
|
|
208
215
|
});
|
|
209
216
|
}
|
|
@@ -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;
|
package/dist/components/stat.mjs
CHANGED
|
@@ -21,11 +21,17 @@ const toSparkData = (sparkline) => (sparkline ?? []).map((point, index) => typeo
|
|
|
21
21
|
index,
|
|
22
22
|
value: point.value
|
|
23
23
|
});
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const SEMANTIC_KEY = {
|
|
25
|
+
error: "destructive",
|
|
26
|
+
warning: "warning",
|
|
27
|
+
success: "success"
|
|
28
|
+
};
|
|
29
|
+
function Stat({ value, unit, delta, sparkline, semantic, className, ...props }) {
|
|
30
|
+
const { palette, theme } = useChartContext();
|
|
26
31
|
const gradientId = React$1.useId().replace(/:/g, "");
|
|
27
32
|
const sparkData = React$1.useMemo(() => toSparkData(sparkline), [sparkline]);
|
|
28
|
-
const
|
|
33
|
+
const hasSpark = sparkData.some((point) => point.value > 0);
|
|
34
|
+
const sparkColor = semantic ? theme[SEMANTIC_KEY[semantic]] : palette[0];
|
|
29
35
|
const sentiment = delta && (delta.invert ? delta.direction === "down" : delta.direction === "up") ? "positive" : "negative";
|
|
30
36
|
return /* @__PURE__ */ jsxs("div", {
|
|
31
37
|
"data-slot": "stat",
|
|
@@ -48,11 +54,15 @@ function Stat({ value, unit, delta, sparkline, className, ...props }) {
|
|
|
48
54
|
children: [delta.direction === "up" ? /* @__PURE__ */ jsx(ArrowUp, { className: "size-3" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "size-3" }), delta.label ?? `${delta.value}%`]
|
|
49
55
|
})
|
|
50
56
|
]
|
|
51
|
-
}),
|
|
57
|
+
}), hasSpark && /* @__PURE__ */ jsx("div", {
|
|
52
58
|
className: "h-9 w-full",
|
|
53
59
|
children: /* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
54
60
|
width: "100%",
|
|
55
61
|
height: "100%",
|
|
62
|
+
initialDimension: {
|
|
63
|
+
width: 0,
|
|
64
|
+
height: 36
|
|
65
|
+
},
|
|
56
66
|
children: /* @__PURE__ */ jsxs(AreaChart, {
|
|
57
67
|
data: sparkData,
|
|
58
68
|
margin: {
|
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
import * as React$1 from "react";
|
|
2
2
|
|
|
3
3
|
//#region src/components/wizard.d.ts
|
|
4
|
-
interface WizardStep {
|
|
5
|
-
id: string;
|
|
6
|
-
label: string;
|
|
7
|
-
}
|
|
8
|
-
interface WizardStepsProps {
|
|
9
|
-
steps: readonly WizardStep[];
|
|
10
|
-
activeIdx: number;
|
|
11
|
-
onSelect: (idx: number) => void;
|
|
12
|
-
ariaLabel?: string;
|
|
13
|
-
className?: string;
|
|
14
|
-
}
|
|
15
|
-
declare function WizardSteps({
|
|
16
|
-
steps,
|
|
17
|
-
activeIdx,
|
|
18
|
-
onSelect,
|
|
19
|
-
ariaLabel,
|
|
20
|
-
className
|
|
21
|
-
}: WizardStepsProps): React$1.JSX.Element;
|
|
22
4
|
interface WizardProgressProps extends React$1.ComponentProps<"div"> {
|
|
23
5
|
current: number;
|
|
24
6
|
total: number;
|
|
@@ -30,4 +12,4 @@ declare function WizardProgress({
|
|
|
30
12
|
...props
|
|
31
13
|
}: WizardProgressProps): React$1.JSX.Element;
|
|
32
14
|
//#endregion
|
|
33
|
-
export { WizardProgress
|
|
15
|
+
export { WizardProgress };
|