@alpic-ai/ui 0.0.0-staging.gdee4b0b → 0.0.0-staging.gdfe3a14
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 +14 -12
- package/dist/components/bar-chart.d.mts +2 -0
- package/dist/components/bar-chart.mjs +15 -17
- 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 +54 -27
- package/dist/components/donut-chart.mjs +5 -3
- package/dist/components/form.mjs +3 -1
- package/dist/components/heatmap-chart.d.mts +14 -0
- package/dist/components/heatmap-chart.mjs +158 -97
- package/dist/components/line-chart.d.mts +2 -0
- package/dist/components/line-chart.mjs +15 -12
- package/dist/components/sidebar.mjs +1 -1
- package/dist/components/skeleton.mjs +1 -1
- package/dist/components/stat.d.mts +3 -1
- package/dist/components/stat.mjs +18 -8
- package/dist/components/textarea.mjs +1 -1
- package/dist/lib/chart-palette.mjs +20 -17
- package/dist/lib/chart.mjs +16 -1
- package/package.json +2 -2
- package/src/components/area-chart.tsx +23 -13
- package/src/components/bar-chart.tsx +24 -14
- 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 +22 -6
- package/src/components/donut-chart.tsx +2 -5
- package/src/components/form.tsx +4 -2
- package/src/components/heatmap-chart.tsx +109 -21
- package/src/components/line-chart.tsx +29 -14
- package/src/components/skeleton.tsx +1 -1
- package/src/components/stat.tsx +14 -10
- package/src/components/textarea.tsx +1 -1
- package/src/lib/chart-palette.ts +20 -17
- package/src/lib/chart.ts +34 -0
- package/src/stories/textarea.stories.tsx +7 -0
- package/src/stories/wizard.stories.tsx +1 -1
- 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,10 +1,10 @@
|
|
|
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";
|
|
7
|
+
import { Skeleton } from "./skeleton.mjs";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import * as React$1 from "react";
|
|
10
10
|
import { Area, AreaChart as AreaChart$1, CartesianGrid, LabelList, ReferenceArea, ReferenceDot, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
|
|
@@ -14,10 +14,9 @@ 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
|
-
const animated = !useReducedMotion();
|
|
21
20
|
const resolved = resolveSeries(series, paletteColors, theme);
|
|
22
21
|
const stacked = variant === "stacked" || variant === "expand";
|
|
23
22
|
const rendered = stacked ? orderByLuminance(resolved) : resolved;
|
|
@@ -115,19 +114,20 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
115
114
|
const isEmpty = data.length === 0 || rendered.length === 0;
|
|
116
115
|
return /* @__PURE__ */ jsxs("div", {
|
|
117
116
|
"data-slot": "area-chart",
|
|
118
|
-
className: cn("flex w-full flex-col gap-3", className),
|
|
117
|
+
className: cn("flex w-full flex-col gap-3", "[&_.recharts-surface]:outline-none [&_.recharts-wrapper]:outline-none", className),
|
|
119
118
|
children: [/* @__PURE__ */ jsx("div", {
|
|
120
119
|
className: "w-full",
|
|
121
120
|
style: { height },
|
|
122
|
-
children: loading ? /* @__PURE__ */
|
|
123
|
-
className: "flex h-full items-center justify-center gap-2.5 font-mono text-quaternary-foreground text-text-xs",
|
|
124
|
-
children: [/* @__PURE__ */ jsx("span", { className: "size-4 animate-spin rounded-full border-2 border-border border-t-foreground" }), "loading…"]
|
|
125
|
-
}) : isEmpty ? /* @__PURE__ */ jsx("div", {
|
|
121
|
+
children: loading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-full w-full rounded-lg" }) : isEmpty ? /* @__PURE__ */ jsx("div", {
|
|
126
122
|
className: "flex h-full items-center justify-center rounded-lg border border-border border-dashed font-mono text-quaternary-foreground text-text-xs",
|
|
127
123
|
children: "no data in range"
|
|
128
124
|
}) : /* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
129
125
|
width: "100%",
|
|
130
126
|
height: "100%",
|
|
127
|
+
initialDimension: {
|
|
128
|
+
width: 0,
|
|
129
|
+
height
|
|
130
|
+
},
|
|
131
131
|
children: /* @__PURE__ */ jsxs(AreaChart$1, {
|
|
132
132
|
data,
|
|
133
133
|
stackOffset: variant === "expand" ? "expand" : "none",
|
|
@@ -177,8 +177,9 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
177
177
|
/* @__PURE__ */ jsx(XAxis, {
|
|
178
178
|
dataKey: index,
|
|
179
179
|
...axis,
|
|
180
|
+
tick: makeXAxisTick(theme),
|
|
180
181
|
interval: "preserveStartEnd",
|
|
181
|
-
minTickGap:
|
|
182
|
+
minTickGap: 56
|
|
182
183
|
}),
|
|
183
184
|
/* @__PURE__ */ jsx(YAxis, {
|
|
184
185
|
...axis,
|
|
@@ -233,7 +234,7 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
233
234
|
fill: fillFor(entry, slot),
|
|
234
235
|
dot: false,
|
|
235
236
|
activeDot: activeDotFor(entry),
|
|
236
|
-
isAnimationActive:
|
|
237
|
+
isAnimationActive: false,
|
|
237
238
|
animationDuration: 650,
|
|
238
239
|
animationEasing: "ease-out",
|
|
239
240
|
children: lastValueLabel && /* @__PURE__ */ jsx(LabelList, {
|
|
@@ -261,7 +262,8 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
261
262
|
})
|
|
262
263
|
}), legend && !isEmpty && /* @__PURE__ */ jsx(ChartLegend, {
|
|
263
264
|
items: legendItems,
|
|
264
|
-
|
|
265
|
+
align: legendAlign,
|
|
266
|
+
insetLeft: yAxisWidth
|
|
265
267
|
})]
|
|
266
268
|
});
|
|
267
269
|
}
|
|
@@ -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,20 +1,19 @@
|
|
|
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";
|
|
7
|
+
import { Skeleton } from "./skeleton.mjs";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import * as React$1 from "react";
|
|
10
10
|
import { Bar, BarChart as BarChart$1, CartesianGrid, LabelList, ReferenceArea, ReferenceDot, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
|
|
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
|
-
const animated = !useReducedMotion();
|
|
18
17
|
const resolved = resolveSeries(series, paletteColors, theme);
|
|
19
18
|
const stacked = variant === "stacked" || variant === "expand";
|
|
20
19
|
const rendered = stacked ? orderByLuminance(resolved) : resolved;
|
|
@@ -98,19 +97,20 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
98
97
|
const isEmpty = data.length === 0 || rendered.length === 0;
|
|
99
98
|
return /* @__PURE__ */ jsxs("div", {
|
|
100
99
|
"data-slot": "bar-chart",
|
|
101
|
-
className: cn("flex w-full flex-col gap-3", className),
|
|
100
|
+
className: cn("flex w-full flex-col gap-3", "[&_.recharts-surface]:outline-none [&_.recharts-wrapper]:outline-none", className),
|
|
102
101
|
children: [/* @__PURE__ */ jsx("div", {
|
|
103
102
|
className: "w-full",
|
|
104
103
|
style: { height },
|
|
105
|
-
children: loading ? /* @__PURE__ */
|
|
106
|
-
className: "flex h-full items-center justify-center gap-2.5 font-mono text-quaternary-foreground text-text-xs",
|
|
107
|
-
children: [/* @__PURE__ */ jsx("span", { className: "size-4 animate-spin rounded-full border-2 border-border border-t-foreground" }), "loading…"]
|
|
108
|
-
}) : isEmpty ? /* @__PURE__ */ jsx("div", {
|
|
104
|
+
children: loading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-full w-full rounded-lg" }) : isEmpty ? /* @__PURE__ */ jsx("div", {
|
|
109
105
|
className: "flex h-full items-center justify-center rounded-lg border border-border border-dashed font-mono text-quaternary-foreground text-text-xs",
|
|
110
106
|
children: "no data in range"
|
|
111
107
|
}) : /* @__PURE__ */ jsx(ResponsiveContainer, {
|
|
112
108
|
width: "100%",
|
|
113
109
|
height: "100%",
|
|
110
|
+
initialDimension: {
|
|
111
|
+
width: 0,
|
|
112
|
+
height
|
|
113
|
+
},
|
|
114
114
|
children: /* @__PURE__ */ jsxs(BarChart$1, {
|
|
115
115
|
data,
|
|
116
116
|
stackOffset: variant === "expand" ? "expand" : "none",
|
|
@@ -161,8 +161,9 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
161
161
|
/* @__PURE__ */ jsx(XAxis, {
|
|
162
162
|
dataKey: index,
|
|
163
163
|
...axis,
|
|
164
|
+
tick: makeXAxisTick(theme),
|
|
164
165
|
interval: "preserveStartEnd",
|
|
165
|
-
minTickGap:
|
|
166
|
+
minTickGap: 56
|
|
166
167
|
}),
|
|
167
168
|
/* @__PURE__ */ jsx(YAxis, {
|
|
168
169
|
...axis,
|
|
@@ -215,12 +216,8 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
215
216
|
strokeWidth: 0,
|
|
216
217
|
radius: radiusFor(slot),
|
|
217
218
|
maxBarSize: MAX_BAR_SIZE,
|
|
218
|
-
activeBar:
|
|
219
|
-
|
|
220
|
-
stroke: theme.card,
|
|
221
|
-
strokeWidth: 1
|
|
222
|
-
},
|
|
223
|
-
isAnimationActive: animated,
|
|
219
|
+
activeBar: false,
|
|
220
|
+
isAnimationActive: false,
|
|
224
221
|
animationDuration: 650,
|
|
225
222
|
animationEasing: "ease-out",
|
|
226
223
|
children: valueLabels && (!stacked || rendered.length === 1) && /* @__PURE__ */ jsx(LabelList, {
|
|
@@ -248,7 +245,8 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, va
|
|
|
248
245
|
})
|
|
249
246
|
}), legend && !isEmpty && /* @__PURE__ */ jsx(ChartLegend, {
|
|
250
247
|
items: legendItems,
|
|
251
|
-
|
|
248
|
+
align: legendAlign,
|
|
249
|
+
insetLeft: yAxisWidth
|
|
252
250
|
})]
|
|
253
251
|
});
|
|
254
252
|
}
|
|
@@ -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]",
|
|
@@ -3,10 +3,16 @@ import { cn } from "../lib/cn.mjs";
|
|
|
3
3
|
import { useChartContext } from "./chart-container.mjs";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/chart-tooltip.tsx
|
|
6
|
+
const MAX_TOOLTIP_ROWS = 8;
|
|
6
7
|
function ChartTooltipContent({ active, payload, label, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, hideLabel, showTotal, totalLabel = "Total", className }) {
|
|
7
8
|
const { theme } = useChartContext();
|
|
8
9
|
if (!active || !payload?.length) return null;
|
|
9
|
-
const
|
|
10
|
+
const toNumber = (value) => typeof value === "number" ? value : Number(value ?? 0);
|
|
11
|
+
const total = payload.reduce((sum, item) => sum + toNumber(item.value), 0);
|
|
12
|
+
const sorted = [...payload].sort((lower, upper) => toNumber(upper.value) - toNumber(lower.value));
|
|
13
|
+
const rows = sorted.slice(0, MAX_TOOLTIP_ROWS);
|
|
14
|
+
const overflow = sorted.slice(MAX_TOOLTIP_ROWS);
|
|
15
|
+
const overflowTotal = overflow.reduce((sum, item) => sum + toNumber(item.value), 0);
|
|
10
16
|
return /* @__PURE__ */ jsxs("div", {
|
|
11
17
|
className: cn("min-w-[130px] rounded-lg border px-3 py-2.5 shadow-lg", "border-border bg-popover text-popover-foreground", className),
|
|
12
18
|
children: [!hideLabel && label !== void 0 && /* @__PURE__ */ jsx("p", {
|
|
@@ -14,37 +20,58 @@ function ChartTooltipContent({ active, payload, label, valueFormatter = (value)
|
|
|
14
20
|
children: labelFormatter ? labelFormatter(label) : label
|
|
15
21
|
}), /* @__PURE__ */ jsxs("div", {
|
|
16
22
|
className: "flex flex-col gap-1",
|
|
17
|
-
children: [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
children: [
|
|
24
|
+
rows.map((item, index) => {
|
|
25
|
+
const swatch = [
|
|
26
|
+
item.color,
|
|
27
|
+
item.stroke,
|
|
28
|
+
item.fill
|
|
29
|
+
].find((candidate) => typeof candidate === "string" && candidate.length > 0 && !candidate.startsWith("url(")) ?? theme.mutedForeground;
|
|
30
|
+
const numeric = toNumber(item.value);
|
|
31
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
32
|
+
className: "flex items-center justify-between gap-4 text-text-xs",
|
|
33
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
34
|
+
className: "inline-flex items-center gap-2 text-muted-foreground",
|
|
35
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
36
|
+
"aria-hidden": true,
|
|
37
|
+
className: "size-2 shrink-0 rounded-[2px]",
|
|
38
|
+
style: { background: swatch }
|
|
39
|
+
}), item.name]
|
|
40
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
41
|
+
className: "font-mono font-semibold tabular-nums text-foreground",
|
|
42
|
+
children: valueFormatter(numeric)
|
|
43
|
+
})]
|
|
44
|
+
}, `${item.dataKey ?? index}`);
|
|
45
|
+
}),
|
|
46
|
+
overflow.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
25
47
|
className: "flex items-center justify-between gap-4 text-text-xs",
|
|
26
48
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
27
|
-
className: "inline-flex items-center gap-2 text-
|
|
28
|
-
children: [
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
49
|
+
className: "inline-flex items-center gap-2 text-quaternary-foreground",
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ jsx("span", {
|
|
52
|
+
"aria-hidden": true,
|
|
53
|
+
className: "size-2 shrink-0"
|
|
54
|
+
}),
|
|
55
|
+
"+",
|
|
56
|
+
overflow.length,
|
|
57
|
+
" more"
|
|
58
|
+
]
|
|
59
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
60
|
+
className: "font-mono font-semibold tabular-nums text-quaternary-foreground",
|
|
61
|
+
children: valueFormatter(overflowTotal)
|
|
62
|
+
})]
|
|
63
|
+
}),
|
|
64
|
+
showTotal && /* @__PURE__ */ jsxs("div", {
|
|
65
|
+
className: "mt-1 flex items-center justify-between gap-4 border-border border-t pt-1.5 text-text-xs",
|
|
66
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
67
|
+
className: "font-mono text-quaternary-foreground uppercase tracking-wider text-[10px]",
|
|
68
|
+
children: totalLabel
|
|
33
69
|
}), /* @__PURE__ */ jsx("span", {
|
|
34
70
|
className: "font-mono font-semibold tabular-nums text-foreground",
|
|
35
|
-
children: valueFormatter(
|
|
71
|
+
children: valueFormatter(total)
|
|
36
72
|
})]
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
className: "mt-1 flex items-center justify-between gap-4 border-border border-t pt-1.5 text-text-xs",
|
|
40
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
41
|
-
className: "font-mono text-quaternary-foreground uppercase tracking-wider text-[10px]",
|
|
42
|
-
children: totalLabel
|
|
43
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
44
|
-
className: "font-mono font-semibold tabular-nums text-foreground",
|
|
45
|
-
children: valueFormatter(total)
|
|
46
|
-
})]
|
|
47
|
-
})]
|
|
73
|
+
})
|
|
74
|
+
]
|
|
48
75
|
})]
|
|
49
76
|
});
|
|
50
77
|
}
|
|
@@ -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,20 @@ 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
|
+
}>;
|
|
25
|
+
tooltipTitleKey?: string;
|
|
26
|
+
colorScale?: "linear" | "rank";
|
|
27
|
+
showLegend?: boolean;
|
|
19
28
|
ariaLabel?: string;
|
|
20
29
|
className?: string;
|
|
21
30
|
}
|
|
@@ -28,11 +37,16 @@ declare function HeatmapChart({
|
|
|
28
37
|
palette,
|
|
29
38
|
xLabels,
|
|
30
39
|
yLabels,
|
|
40
|
+
showAllXLabels,
|
|
31
41
|
highlightPeak,
|
|
32
42
|
loading,
|
|
33
43
|
valueFormatter,
|
|
34
44
|
xTickFormatter,
|
|
35
45
|
yTickFormatter,
|
|
46
|
+
tooltipMetrics,
|
|
47
|
+
tooltipTitleKey,
|
|
48
|
+
colorScale,
|
|
49
|
+
showLegend,
|
|
36
50
|
ariaLabel,
|
|
37
51
|
className
|
|
38
52
|
}: HeatmapChartProps): React$1.JSX.Element;
|