@alpic-ai/ui 1.154.0 → 1.155.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/area-chart.mjs +20 -109
- package/dist/components/bar-chart.mjs +10 -68
- package/dist/components/chart-primitives.d.mts +69 -0
- package/dist/components/chart-primitives.mjs +134 -0
- package/dist/components/field.d.mts +14 -0
- package/dist/components/field.mjs +41 -0
- package/dist/components/input.mjs +25 -49
- package/dist/components/line-chart.mjs +20 -102
- package/dist/components/textarea.mjs +17 -41
- package/dist/lib/chart.d.mts +5 -1
- package/package.json +1 -1
- package/src/components/area-chart.tsx +21 -142
- package/src/components/bar-chart.tsx +12 -81
- package/src/components/chart-primitives.tsx +188 -0
- package/src/components/field.tsx +57 -0
- package/src/components/input.tsx +3 -33
- package/src/components/line-chart.tsx +21 -133
- package/src/components/textarea.tsx +3 -33
- package/src/stories/area-chart.stories.tsx +8 -6
- package/src/stories/bar-chart.stories.tsx +8 -6
- package/src/stories/donut-chart.stories.tsx +8 -6
- package/src/stories/line-chart.stories.tsx +8 -6
- package/src/stories/stat.stories.tsx +8 -6
|
@@ -3,11 +3,12 @@ import { cn } from "../lib/cn.mjs";
|
|
|
3
3
|
import { makeXAxisTick, orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
4
4
|
import { useChartContext } from "./chart-container.mjs";
|
|
5
5
|
import { ChartLegend } from "./chart-legend.mjs";
|
|
6
|
+
import { computeNumericMax, makeActiveDot, makeChartAxis, makeLastValueLabel, makeLegendItems, renderMarkers, renderReferenceLine } from "./chart-primitives.mjs";
|
|
6
7
|
import { ChartTooltipContent } from "./chart-tooltip.mjs";
|
|
7
8
|
import { Skeleton } from "./skeleton.mjs";
|
|
8
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
10
|
import * as React$1 from "react";
|
|
10
|
-
import { Area, AreaChart as AreaChart$1, CartesianGrid, LabelList,
|
|
11
|
+
import { Area, AreaChart as AreaChart$1, CartesianGrid, LabelList, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
|
|
11
12
|
//#region src/components/area-chart.tsx
|
|
12
13
|
const CURVE_TYPE = {
|
|
13
14
|
monotone: "monotone",
|
|
@@ -23,21 +24,7 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
23
24
|
const filled = !(variant === "grouped" && rendered.length > 1);
|
|
24
25
|
const lead = resolved[0];
|
|
25
26
|
const withTotal = stacked && rendered.length > 1;
|
|
26
|
-
const numericMax = React$1.useMemo(() =>
|
|
27
|
-
let max = 0;
|
|
28
|
-
for (const row of data) {
|
|
29
|
-
let rowTotal = 0;
|
|
30
|
-
for (const entry of series) {
|
|
31
|
-
const value = Number(row[entry.key]);
|
|
32
|
-
if (Number.isFinite(value)) {
|
|
33
|
-
rowTotal += value;
|
|
34
|
-
if (!stacked && value > max) max = value;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (stacked && rowTotal > max) max = rowTotal;
|
|
38
|
-
}
|
|
39
|
-
return max;
|
|
40
|
-
}, [
|
|
27
|
+
const numericMax = React$1.useMemo(() => computeNumericMax(data, series, stacked), [
|
|
41
28
|
data,
|
|
42
29
|
series,
|
|
43
30
|
stacked
|
|
@@ -49,68 +36,13 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
49
36
|
bottom: 2,
|
|
50
37
|
left: 0
|
|
51
38
|
};
|
|
52
|
-
const axis =
|
|
53
|
-
|
|
54
|
-
tick: {
|
|
55
|
-
fill: theme.axisForeground,
|
|
56
|
-
fontSize: 10,
|
|
57
|
-
fontFamily: theme.fontMono
|
|
58
|
-
},
|
|
59
|
-
tickLine: false,
|
|
60
|
-
axisLine: {
|
|
61
|
-
stroke: theme.border,
|
|
62
|
-
strokeOpacity: .6
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
const legendItems = resolved.map((entry) => ({
|
|
66
|
-
name: entry.name,
|
|
67
|
-
color: entry.color,
|
|
68
|
-
dashed: entry.dashed
|
|
69
|
-
}));
|
|
70
|
-
const activeDotFor = (entry) => valueFlags ? (dotProps) => {
|
|
71
|
-
if (dotProps.cx == null || dotProps.cy == null) return /* @__PURE__ */ jsx("g", {});
|
|
72
|
-
return /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("circle", {
|
|
73
|
-
cx: dotProps.cx,
|
|
74
|
-
cy: dotProps.cy,
|
|
75
|
-
r: 3.5,
|
|
76
|
-
fill: entry.color,
|
|
77
|
-
stroke: theme.card,
|
|
78
|
-
strokeWidth: 2
|
|
79
|
-
}), /* @__PURE__ */ jsx("text", {
|
|
80
|
-
x: dotProps.cx,
|
|
81
|
-
y: dotProps.cy - 8,
|
|
82
|
-
textAnchor: "middle",
|
|
83
|
-
fill: entry.color,
|
|
84
|
-
fontFamily: theme.fontMono,
|
|
85
|
-
fontSize: 10,
|
|
86
|
-
style: { fontVariantNumeric: "tabular-nums" },
|
|
87
|
-
children: valueFormatter(Number(dotProps.value ?? 0))
|
|
88
|
-
})] });
|
|
89
|
-
} : {
|
|
90
|
-
r: 3.5,
|
|
91
|
-
fill: entry.color,
|
|
92
|
-
stroke: theme.card,
|
|
93
|
-
strokeWidth: 2
|
|
94
|
-
};
|
|
39
|
+
const axis = makeChartAxis(theme);
|
|
40
|
+
const legendItems = makeLegendItems(resolved);
|
|
95
41
|
const fillFor = (entry, slot) => {
|
|
96
42
|
if (!filled) return "none";
|
|
97
43
|
if (texture && lead && entry.key === lead.key) return `url(#hatch-${reactId})`;
|
|
98
44
|
return `url(#area-${reactId}-${slot})`;
|
|
99
45
|
};
|
|
100
|
-
const renderLastLabel = (color) => (props) => {
|
|
101
|
-
if (props.index !== data.length - 1 || props.x == null || props.y == null) return null;
|
|
102
|
-
return /* @__PURE__ */ jsx("text", {
|
|
103
|
-
x: Number(props.x) + 6,
|
|
104
|
-
y: Number(props.y),
|
|
105
|
-
dy: 3,
|
|
106
|
-
fill: color,
|
|
107
|
-
fontFamily: theme.fontMono,
|
|
108
|
-
fontSize: 10,
|
|
109
|
-
textAnchor: "start",
|
|
110
|
-
style: { fontVariantNumeric: "tabular-nums" },
|
|
111
|
-
children: valueFormatter(Number(props.value ?? 0))
|
|
112
|
-
});
|
|
113
|
-
};
|
|
114
46
|
const isEmpty = data.length === 0 || rendered.length === 0;
|
|
115
47
|
return /* @__PURE__ */ jsxs("div", {
|
|
116
48
|
"data-slot": "area-chart",
|
|
@@ -203,25 +135,10 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
203
135
|
showTotal: withTotal
|
|
204
136
|
})
|
|
205
137
|
}),
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
fillOpacity: .06,
|
|
211
|
-
ifOverflow: "extendDomain"
|
|
212
|
-
}),
|
|
213
|
-
referenceLine && /* @__PURE__ */ jsx(ReferenceLine, {
|
|
214
|
-
y: referenceLine.y,
|
|
215
|
-
stroke: theme.warning,
|
|
216
|
-
strokeDasharray: "4 4",
|
|
217
|
-
strokeOpacity: .6,
|
|
218
|
-
label: referenceLine.label ? {
|
|
219
|
-
value: referenceLine.label,
|
|
220
|
-
fill: theme.warning,
|
|
221
|
-
fontSize: 9,
|
|
222
|
-
fontFamily: theme.fontMono,
|
|
223
|
-
position: "insideBottomRight"
|
|
224
|
-
} : void 0
|
|
138
|
+
renderReferenceLine({
|
|
139
|
+
referenceLine,
|
|
140
|
+
numericMax,
|
|
141
|
+
theme
|
|
225
142
|
}),
|
|
226
143
|
rendered.map((entry, slot) => /* @__PURE__ */ jsx(Area, {
|
|
227
144
|
type: curveType,
|
|
@@ -233,30 +150,24 @@ function AreaChart({ data, index, series, variant = "stacked", curve = "monotone
|
|
|
233
150
|
strokeDasharray: entry.dashed ? "5 3" : void 0,
|
|
234
151
|
fill: fillFor(entry, slot),
|
|
235
152
|
dot: false,
|
|
236
|
-
activeDot:
|
|
153
|
+
activeDot: makeActiveDot(entry, {
|
|
154
|
+
valueFlags,
|
|
155
|
+
theme,
|
|
156
|
+
valueFormatter
|
|
157
|
+
}),
|
|
237
158
|
isAnimationActive: false,
|
|
238
159
|
animationDuration: 650,
|
|
239
160
|
animationEasing: "ease-out",
|
|
240
161
|
children: lastValueLabel && /* @__PURE__ */ jsx(LabelList, {
|
|
241
162
|
dataKey: entry.key,
|
|
242
|
-
content:
|
|
163
|
+
content: makeLastValueLabel(entry.color, {
|
|
164
|
+
dataLength: data.length,
|
|
165
|
+
theme,
|
|
166
|
+
valueFormatter
|
|
167
|
+
})
|
|
243
168
|
})
|
|
244
169
|
}, entry.key)),
|
|
245
|
-
markers
|
|
246
|
-
x: marker.x,
|
|
247
|
-
y: marker.y,
|
|
248
|
-
r: 3.5,
|
|
249
|
-
fill: marker.color ?? theme.foreground,
|
|
250
|
-
stroke: theme.card,
|
|
251
|
-
strokeWidth: 2,
|
|
252
|
-
label: marker.label ? {
|
|
253
|
-
value: marker.label,
|
|
254
|
-
fill: marker.color ?? theme.foreground,
|
|
255
|
-
fontSize: 9,
|
|
256
|
-
fontFamily: theme.fontMono,
|
|
257
|
-
position: "top"
|
|
258
|
-
} : void 0
|
|
259
|
-
}, `${marker.x}-${marker.y}`))
|
|
170
|
+
renderMarkers(markers, theme)
|
|
260
171
|
]
|
|
261
172
|
})
|
|
262
173
|
})
|
|
@@ -3,11 +3,12 @@ import { cn } from "../lib/cn.mjs";
|
|
|
3
3
|
import { makeXAxisTick, orderByLuminance, resolveSeries } from "../lib/chart.mjs";
|
|
4
4
|
import { useChartContext } from "./chart-container.mjs";
|
|
5
5
|
import { ChartLegend } from "./chart-legend.mjs";
|
|
6
|
+
import { computeNumericMax, makeChartAxis, makeLegendItems, renderMarkers, renderReferenceLine } from "./chart-primitives.mjs";
|
|
6
7
|
import { ChartTooltipContent } from "./chart-tooltip.mjs";
|
|
7
8
|
import { Skeleton } from "./skeleton.mjs";
|
|
8
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
10
|
import * as React$1 from "react";
|
|
10
|
-
import { Bar, BarChart as BarChart$1, CartesianGrid, Cell, LabelList,
|
|
11
|
+
import { Bar, BarChart as BarChart$1, CartesianGrid, Cell, LabelList, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
|
|
11
12
|
//#region src/components/bar-chart.tsx
|
|
12
13
|
const BAR_RADIUS = 4;
|
|
13
14
|
const MAX_BAR_SIZE = 48;
|
|
@@ -19,21 +20,7 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, le
|
|
|
19
20
|
const rendered = stacked ? orderByLuminance(resolved) : resolved;
|
|
20
21
|
const lead = resolved[0];
|
|
21
22
|
const withTotal = stacked && rendered.length > 1;
|
|
22
|
-
const numericMax = React$1.useMemo(() =>
|
|
23
|
-
let max = 0;
|
|
24
|
-
for (const row of data) {
|
|
25
|
-
let rowTotal = 0;
|
|
26
|
-
for (const entry of series) {
|
|
27
|
-
const value = Number(row[entry.key]);
|
|
28
|
-
if (Number.isFinite(value)) {
|
|
29
|
-
rowTotal += value;
|
|
30
|
-
if (!stacked && value > max) max = value;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
if (stacked && rowTotal > max) max = rowTotal;
|
|
34
|
-
}
|
|
35
|
-
return max;
|
|
36
|
-
}, [
|
|
23
|
+
const numericMax = React$1.useMemo(() => computeNumericMax(data, series, stacked), [
|
|
37
24
|
data,
|
|
38
25
|
series,
|
|
39
26
|
stacked
|
|
@@ -58,24 +45,8 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, le
|
|
|
58
45
|
bottom: 2,
|
|
59
46
|
left: 0
|
|
60
47
|
};
|
|
61
|
-
const axis =
|
|
62
|
-
|
|
63
|
-
tick: {
|
|
64
|
-
fill: theme.axisForeground,
|
|
65
|
-
fontSize: 10,
|
|
66
|
-
fontFamily: theme.fontMono
|
|
67
|
-
},
|
|
68
|
-
tickLine: false,
|
|
69
|
-
axisLine: {
|
|
70
|
-
stroke: theme.border,
|
|
71
|
-
strokeOpacity: .6
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
const legendItems = resolved.map((entry) => ({
|
|
75
|
-
name: entry.name,
|
|
76
|
-
color: entry.color,
|
|
77
|
-
dashed: entry.dashed
|
|
78
|
-
}));
|
|
48
|
+
const axis = makeChartAxis(theme);
|
|
49
|
+
const legendItems = makeLegendItems(resolved);
|
|
79
50
|
const radiusFor = (slot) => {
|
|
80
51
|
if (!stacked || slot === rendered.length - 1) return [
|
|
81
52
|
BAR_RADIUS,
|
|
@@ -201,25 +172,10 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, le
|
|
|
201
172
|
showTotal: withTotal
|
|
202
173
|
})
|
|
203
174
|
}),
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
fillOpacity: .06,
|
|
209
|
-
ifOverflow: "extendDomain"
|
|
210
|
-
}),
|
|
211
|
-
referenceLine && /* @__PURE__ */ jsx(ReferenceLine, {
|
|
212
|
-
y: referenceLine.y,
|
|
213
|
-
stroke: theme.warning,
|
|
214
|
-
strokeDasharray: "4 4",
|
|
215
|
-
strokeOpacity: .6,
|
|
216
|
-
label: referenceLine.label ? {
|
|
217
|
-
value: referenceLine.label,
|
|
218
|
-
fill: theme.warning,
|
|
219
|
-
fontSize: 9,
|
|
220
|
-
fontFamily: theme.fontMono,
|
|
221
|
-
position: "insideBottomRight"
|
|
222
|
-
} : void 0
|
|
175
|
+
renderReferenceLine({
|
|
176
|
+
referenceLine,
|
|
177
|
+
numericMax,
|
|
178
|
+
theme
|
|
223
179
|
}),
|
|
224
180
|
rendered.map((entry, slot) => /* @__PURE__ */ jsxs(Bar, {
|
|
225
181
|
dataKey: entry.key,
|
|
@@ -259,21 +215,7 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, le
|
|
|
259
215
|
content: renderValueLabel(entry.color)
|
|
260
216
|
})]
|
|
261
217
|
}, entry.key)),
|
|
262
|
-
markers
|
|
263
|
-
x: marker.x,
|
|
264
|
-
y: marker.y,
|
|
265
|
-
r: 3.5,
|
|
266
|
-
fill: marker.color ?? theme.foreground,
|
|
267
|
-
stroke: theme.card,
|
|
268
|
-
strokeWidth: 2,
|
|
269
|
-
label: marker.label ? {
|
|
270
|
-
value: marker.label,
|
|
271
|
-
fill: marker.color ?? theme.foreground,
|
|
272
|
-
fontSize: 9,
|
|
273
|
-
fontFamily: theme.fontMono,
|
|
274
|
-
position: "top"
|
|
275
|
-
} : void 0
|
|
276
|
-
}, `${marker.x}-${marker.y}`))
|
|
218
|
+
renderMarkers(markers, theme)
|
|
277
219
|
]
|
|
278
220
|
})
|
|
279
221
|
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ChartTheme } from "../hooks/use-chart-theme.mjs";
|
|
2
|
+
import { ChartSeries, ResolvedSeries } from "../lib/chart.mjs";
|
|
3
|
+
import { ChartMarker } from "./area-chart.mjs";
|
|
4
|
+
//#region src/components/chart-primitives.d.ts
|
|
5
|
+
type ReferenceLineConfig = {
|
|
6
|
+
y: number;
|
|
7
|
+
label?: string;
|
|
8
|
+
band?: boolean;
|
|
9
|
+
};
|
|
10
|
+
type ChartData = ReadonlyArray<Record<string, string | number | null | undefined>>;
|
|
11
|
+
declare function makeChartAxis(theme: ChartTheme): {
|
|
12
|
+
stroke: string;
|
|
13
|
+
tick: {
|
|
14
|
+
fill: string;
|
|
15
|
+
fontSize: number;
|
|
16
|
+
fontFamily: string;
|
|
17
|
+
};
|
|
18
|
+
tickLine: false;
|
|
19
|
+
axisLine: {
|
|
20
|
+
stroke: string;
|
|
21
|
+
strokeOpacity: number;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
declare function makeLegendItems(resolved: ResolvedSeries[]): {
|
|
25
|
+
name: string;
|
|
26
|
+
color: string;
|
|
27
|
+
dashed: boolean | undefined;
|
|
28
|
+
}[];
|
|
29
|
+
/**
|
|
30
|
+
* Stacked series must reach the stack height (sum per x-point), not the tallest
|
|
31
|
+
* single series, or reference bands and explicit Y domains clip a tall stack short.
|
|
32
|
+
*/
|
|
33
|
+
declare function computeNumericMax(data: ChartData, series: ChartSeries[], stacked: boolean): number;
|
|
34
|
+
declare function makeActiveDot(entry: ResolvedSeries, { valueFlags, theme, valueFormatter }: {
|
|
35
|
+
valueFlags: boolean;
|
|
36
|
+
theme: ChartTheme;
|
|
37
|
+
valueFormatter: (value: number) => string;
|
|
38
|
+
}): ((dotProps: {
|
|
39
|
+
cx?: number;
|
|
40
|
+
cy?: number;
|
|
41
|
+
value?: number | string;
|
|
42
|
+
}) => import("react").JSX.Element) | {
|
|
43
|
+
r: number;
|
|
44
|
+
fill: string;
|
|
45
|
+
stroke: string;
|
|
46
|
+
strokeWidth: number;
|
|
47
|
+
};
|
|
48
|
+
declare function makeLastValueLabel(color: string, { dataLength, theme, valueFormatter }: {
|
|
49
|
+
dataLength: number;
|
|
50
|
+
theme: ChartTheme;
|
|
51
|
+
valueFormatter: (value: number) => string;
|
|
52
|
+
}): (props: {
|
|
53
|
+
x?: string | number;
|
|
54
|
+
y?: string | number;
|
|
55
|
+
value?: string | number | boolean | Array<string | number | boolean> | null;
|
|
56
|
+
index?: number;
|
|
57
|
+
}) => import("react").JSX.Element | null;
|
|
58
|
+
/**
|
|
59
|
+
* Returns recharts elements (not a wrapper component) so recharts still detects
|
|
60
|
+
* them as direct children when spread into a chart via `{renderReferenceLine(...)}`.
|
|
61
|
+
*/
|
|
62
|
+
declare function renderReferenceLine({ referenceLine, numericMax, theme }: {
|
|
63
|
+
referenceLine: ReferenceLineConfig | undefined;
|
|
64
|
+
numericMax: number;
|
|
65
|
+
theme: ChartTheme;
|
|
66
|
+
}): (import("react").JSX.Element | null)[] | null;
|
|
67
|
+
declare function renderMarkers(markers: ChartMarker[] | undefined, theme: ChartTheme): import("react").JSX.Element[] | undefined;
|
|
68
|
+
//#endregion
|
|
69
|
+
export { ReferenceLineConfig, computeNumericMax, makeActiveDot, makeChartAxis, makeLastValueLabel, makeLegendItems, renderMarkers, renderReferenceLine };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ReferenceArea, ReferenceDot, ReferenceLine } from "recharts";
|
|
4
|
+
//#region src/components/chart-primitives.tsx
|
|
5
|
+
function makeChartAxis(theme) {
|
|
6
|
+
return {
|
|
7
|
+
stroke: theme.border,
|
|
8
|
+
tick: {
|
|
9
|
+
fill: theme.axisForeground,
|
|
10
|
+
fontSize: 10,
|
|
11
|
+
fontFamily: theme.fontMono
|
|
12
|
+
},
|
|
13
|
+
tickLine: false,
|
|
14
|
+
axisLine: {
|
|
15
|
+
stroke: theme.border,
|
|
16
|
+
strokeOpacity: .6
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function makeLegendItems(resolved) {
|
|
21
|
+
return resolved.map((entry) => ({
|
|
22
|
+
name: entry.name,
|
|
23
|
+
color: entry.color,
|
|
24
|
+
dashed: entry.dashed
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Stacked series must reach the stack height (sum per x-point), not the tallest
|
|
29
|
+
* single series, or reference bands and explicit Y domains clip a tall stack short.
|
|
30
|
+
*/
|
|
31
|
+
function computeNumericMax(data, series, stacked) {
|
|
32
|
+
let max = 0;
|
|
33
|
+
for (const row of data) {
|
|
34
|
+
let rowTotal = 0;
|
|
35
|
+
for (const entry of series) {
|
|
36
|
+
const value = Number(row[entry.key]);
|
|
37
|
+
if (Number.isFinite(value)) {
|
|
38
|
+
rowTotal += value;
|
|
39
|
+
if (!stacked && value > max) max = value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (stacked && rowTotal > max) max = rowTotal;
|
|
43
|
+
}
|
|
44
|
+
return max;
|
|
45
|
+
}
|
|
46
|
+
function makeActiveDot(entry, { valueFlags, theme, valueFormatter }) {
|
|
47
|
+
if (!valueFlags) return {
|
|
48
|
+
r: 3.5,
|
|
49
|
+
fill: entry.color,
|
|
50
|
+
stroke: theme.card,
|
|
51
|
+
strokeWidth: 2
|
|
52
|
+
};
|
|
53
|
+
return (dotProps) => {
|
|
54
|
+
if (dotProps.cx == null || dotProps.cy == null) return /* @__PURE__ */ jsx("g", {});
|
|
55
|
+
return /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("circle", {
|
|
56
|
+
cx: dotProps.cx,
|
|
57
|
+
cy: dotProps.cy,
|
|
58
|
+
r: 3.5,
|
|
59
|
+
fill: entry.color,
|
|
60
|
+
stroke: theme.card,
|
|
61
|
+
strokeWidth: 2
|
|
62
|
+
}), /* @__PURE__ */ jsx("text", {
|
|
63
|
+
x: dotProps.cx,
|
|
64
|
+
y: dotProps.cy - 8,
|
|
65
|
+
textAnchor: "middle",
|
|
66
|
+
fill: entry.color,
|
|
67
|
+
fontFamily: theme.fontMono,
|
|
68
|
+
fontSize: 10,
|
|
69
|
+
style: { fontVariantNumeric: "tabular-nums" },
|
|
70
|
+
children: valueFormatter(Number(dotProps.value ?? 0))
|
|
71
|
+
})] });
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function makeLastValueLabel(color, { dataLength, theme, valueFormatter }) {
|
|
75
|
+
return (props) => {
|
|
76
|
+
if (props.index !== dataLength - 1 || props.x == null || props.y == null) return null;
|
|
77
|
+
return /* @__PURE__ */ jsx("text", {
|
|
78
|
+
x: Number(props.x) + 6,
|
|
79
|
+
y: Number(props.y),
|
|
80
|
+
dy: 3,
|
|
81
|
+
fill: color,
|
|
82
|
+
fontFamily: theme.fontMono,
|
|
83
|
+
fontSize: 10,
|
|
84
|
+
textAnchor: "start",
|
|
85
|
+
style: { fontVariantNumeric: "tabular-nums" },
|
|
86
|
+
children: valueFormatter(Number(props.value ?? 0))
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Returns recharts elements (not a wrapper component) so recharts still detects
|
|
92
|
+
* them as direct children when spread into a chart via `{renderReferenceLine(...)}`.
|
|
93
|
+
*/
|
|
94
|
+
function renderReferenceLine({ referenceLine, numericMax, theme }) {
|
|
95
|
+
if (!referenceLine) return null;
|
|
96
|
+
return [referenceLine.band ? /* @__PURE__ */ jsx(ReferenceArea, {
|
|
97
|
+
y1: referenceLine.y,
|
|
98
|
+
y2: numericMax,
|
|
99
|
+
fill: theme.warning,
|
|
100
|
+
fillOpacity: .06,
|
|
101
|
+
ifOverflow: "extendDomain"
|
|
102
|
+
}, "reference-band") : null, /* @__PURE__ */ jsx(ReferenceLine, {
|
|
103
|
+
y: referenceLine.y,
|
|
104
|
+
stroke: theme.warning,
|
|
105
|
+
strokeDasharray: "4 4",
|
|
106
|
+
strokeOpacity: .6,
|
|
107
|
+
label: referenceLine.label ? {
|
|
108
|
+
value: referenceLine.label,
|
|
109
|
+
fill: theme.warning,
|
|
110
|
+
fontSize: 9,
|
|
111
|
+
fontFamily: theme.fontMono,
|
|
112
|
+
position: "insideBottomRight"
|
|
113
|
+
} : void 0
|
|
114
|
+
}, "reference-line")];
|
|
115
|
+
}
|
|
116
|
+
function renderMarkers(markers, theme) {
|
|
117
|
+
return markers?.map((marker) => /* @__PURE__ */ jsx(ReferenceDot, {
|
|
118
|
+
x: marker.x,
|
|
119
|
+
y: marker.y,
|
|
120
|
+
r: 3.5,
|
|
121
|
+
fill: marker.color ?? theme.foreground,
|
|
122
|
+
stroke: theme.card,
|
|
123
|
+
strokeWidth: 2,
|
|
124
|
+
label: marker.label ? {
|
|
125
|
+
value: marker.label,
|
|
126
|
+
fill: marker.color ?? theme.foreground,
|
|
127
|
+
fontSize: 9,
|
|
128
|
+
fontFamily: theme.fontMono,
|
|
129
|
+
position: "top"
|
|
130
|
+
} : void 0
|
|
131
|
+
}, `${marker.x}-${marker.y}`));
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
export { computeNumericMax, makeActiveDot, makeChartAxis, makeLastValueLabel, makeLegendItems, renderMarkers, renderReferenceLine };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
//#region src/components/field.d.ts
|
|
3
|
+
interface FieldProps {
|
|
4
|
+
fieldId: string;
|
|
5
|
+
label?: string;
|
|
6
|
+
required?: boolean;
|
|
7
|
+
hint?: string;
|
|
8
|
+
error?: string;
|
|
9
|
+
tooltip?: string;
|
|
10
|
+
children: React$1.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
declare function Field({ fieldId, label, required, hint, error, tooltip, children }: FieldProps): React$1.JSX.Element;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { Field, type FieldProps };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.mjs";
|
|
3
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.mjs";
|
|
4
|
+
import { Label } from "./label.mjs";
|
|
5
|
+
import { Info } from "lucide-react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
//#region src/components/field.tsx
|
|
8
|
+
function Field({ fieldId, label, required, hint, error, tooltip, children }) {
|
|
9
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
10
|
+
className: "flex flex-col gap-1.5",
|
|
11
|
+
children: [
|
|
12
|
+
label && /* @__PURE__ */ jsxs("div", {
|
|
13
|
+
className: "flex items-center gap-0.5",
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ jsx(Label, {
|
|
16
|
+
htmlFor: fieldId,
|
|
17
|
+
className: "type-text-sm font-medium text-muted-foreground",
|
|
18
|
+
children: label
|
|
19
|
+
}),
|
|
20
|
+
required && /* @__PURE__ */ jsx("span", {
|
|
21
|
+
"aria-hidden": true,
|
|
22
|
+
className: "type-text-sm font-medium text-required",
|
|
23
|
+
children: "*"
|
|
24
|
+
}),
|
|
25
|
+
tooltip && /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
26
|
+
asChild: true,
|
|
27
|
+
children: /* @__PURE__ */ jsx(Info, { className: "size-4 text-muted-foreground" })
|
|
28
|
+
}), /* @__PURE__ */ jsx(TooltipContent, { children: tooltip })] })
|
|
29
|
+
]
|
|
30
|
+
}),
|
|
31
|
+
children,
|
|
32
|
+
(hint || error) && /* @__PURE__ */ jsx("p", {
|
|
33
|
+
id: fieldId ? `${fieldId}-description` : void 0,
|
|
34
|
+
className: cn("type-text-sm", error ? "text-destructive" : "text-subtle-foreground"),
|
|
35
|
+
children: error ?? hint
|
|
36
|
+
})
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { Field };
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { Label } from "./label.mjs";
|
|
5
|
-
import { Info } from "lucide-react";
|
|
3
|
+
import { Field } from "./field.mjs";
|
|
6
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
5
|
import * as React$1 from "react";
|
|
8
6
|
//#region src/components/input.tsx
|
|
@@ -47,52 +45,30 @@ function Input({ className, id, label, required, hint, error, tooltip, leadingTe
|
|
|
47
45
|
"aria-describedby": fieldId && (hint || error) ? `${fieldId}-description` : void 0,
|
|
48
46
|
...props
|
|
49
47
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
htmlFor: fieldId,
|
|
75
|
-
className: "type-text-sm font-medium text-muted-foreground",
|
|
76
|
-
children: label
|
|
77
|
-
}),
|
|
78
|
-
required && /* @__PURE__ */ jsx("span", {
|
|
79
|
-
"aria-hidden": true,
|
|
80
|
-
className: "type-text-sm font-medium text-required",
|
|
81
|
-
children: "*"
|
|
82
|
-
}),
|
|
83
|
-
tooltip && /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
84
|
-
asChild: true,
|
|
85
|
-
children: /* @__PURE__ */ jsx(Info, { className: "size-4 text-muted-foreground" })
|
|
86
|
-
}), /* @__PURE__ */ jsx(TooltipContent, { children: tooltip })] })
|
|
87
|
-
]
|
|
88
|
-
}),
|
|
89
|
-
wrappedInput,
|
|
90
|
-
(hint || error) && /* @__PURE__ */ jsx("p", {
|
|
91
|
-
id: fieldId ? `${fieldId}-description` : void 0,
|
|
92
|
-
className: cn("type-text-sm", error ? "text-destructive" : "text-subtle-foreground"),
|
|
93
|
-
children: error ?? hint
|
|
94
|
-
})
|
|
95
|
-
]
|
|
48
|
+
return /* @__PURE__ */ jsx(Field, {
|
|
49
|
+
fieldId,
|
|
50
|
+
label,
|
|
51
|
+
required,
|
|
52
|
+
hint,
|
|
53
|
+
error,
|
|
54
|
+
tooltip,
|
|
55
|
+
children: hasAddons ? /* @__PURE__ */ jsxs("div", {
|
|
56
|
+
className: cn("flex items-center w-full overflow-hidden", sizes.wrapper, "bg-background border border-border rounded-md", "transition-colors", "has-[input:focus-visible]:border-ring has-[input:focus-visible]:border-2", "has-[input:disabled]:bg-disabled has-[input:disabled]:text-disabled-foreground has-[input:disabled]:cursor-not-allowed", error && "border-border-error"),
|
|
57
|
+
children: [
|
|
58
|
+
leadingIcon && /* @__PURE__ */ jsx("span", {
|
|
59
|
+
className: cn("flex items-center text-subtle-foreground [&_svg]:shrink-0", sizes.leadingIcon),
|
|
60
|
+
children: leadingIcon
|
|
61
|
+
}),
|
|
62
|
+
leadingText && /* @__PURE__ */ jsx("span", {
|
|
63
|
+
className: cn("flex items-center text-subtle-foreground whitespace-nowrap border-r border-border self-stretch", sizes.leadingText),
|
|
64
|
+
children: leadingText
|
|
65
|
+
}),
|
|
66
|
+
/* @__PURE__ */ jsx("div", {
|
|
67
|
+
className: cn("flex flex-1 items-center min-w-0", sizes.inner),
|
|
68
|
+
children: inputElement
|
|
69
|
+
})
|
|
70
|
+
]
|
|
71
|
+
}) : inputElement
|
|
96
72
|
});
|
|
97
73
|
}
|
|
98
74
|
//#endregion
|