@wallarm-org/design-system 4.0.0 → 4.1.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/SimpleCharts/Metric/MetricSparkline.d.ts +30 -0
- package/dist/components/SimpleCharts/Metric/MetricSparkline.js +365 -0
- package/dist/components/SimpleCharts/Metric/classes.d.ts +4 -0
- package/dist/components/SimpleCharts/Metric/classes.js +5 -1
- package/dist/components/SimpleCharts/Metric/index.d.ts +1 -0
- package/dist/components/SimpleCharts/Metric/index.js +1 -0
- package/dist/components/SimpleCharts/index.d.ts +1 -1
- package/dist/components/SimpleCharts/index.js +1 -1
- package/dist/components/SimpleCharts/lib/timeFormatters.d.ts +5 -1
- package/dist/components/SimpleCharts/lib/timeFormatters.js +4 -3
- package/dist/metadata/components.json +5011 -4705
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type FC, type HTMLAttributes, type ReactNode, type Ref } from 'react';
|
|
2
|
+
import { type TestableProps } from '../../../utils/testId.js';
|
|
3
|
+
export type MetricSparklineColor = 'brand' | 'positive' | 'negative' | 'neutral';
|
|
4
|
+
export interface MetricSparklinePoint {
|
|
5
|
+
/** The point's position on the period — a date (`Date`, timestamp, ISO string) or any label. */
|
|
6
|
+
x: Date | number | string;
|
|
7
|
+
value: number;
|
|
8
|
+
}
|
|
9
|
+
export interface MetricSparklineProps extends Omit<HTMLAttributes<HTMLDivElement>, 'color'>, TestableProps {
|
|
10
|
+
ref?: Ref<HTMLDivElement>;
|
|
11
|
+
/** The trend over the period, oldest first. */
|
|
12
|
+
data: MetricSparklinePoint[];
|
|
13
|
+
/**
|
|
14
|
+
* Line colour. Independent of the `MetricDelta` sentiment — set both. `brand` (default) ·
|
|
15
|
+
* `positive` (success) · `negative` (danger) · `neutral` (slate).
|
|
16
|
+
*/
|
|
17
|
+
color?: MetricSparklineColor;
|
|
18
|
+
/** Series name on the hover popover row (Figma "Attribute"). */
|
|
19
|
+
label?: ReactNode;
|
|
20
|
+
/** Formats the hovered point's `x` for the popover. Defaults to `1 Jan, 2026` for dates. */
|
|
21
|
+
formatX?: (x: MetricSparklinePoint['x']) => ReactNode;
|
|
22
|
+
/** Formats the hovered value. Defaults to `toLocaleString('en-US')`. */
|
|
23
|
+
formatValue?: (value: number) => ReactNode;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The trend under a `Metric`: a 48px line + area spanning the card width, with a ruler and a
|
|
27
|
+
* date/value popover on hover. Compose it inside `Chart`, after `Metric` — the metric's bottom
|
|
28
|
+
* padding is the 8px gap, and the sparkline sits flush with the card's bottom edge.
|
|
29
|
+
*/
|
|
30
|
+
export declare const MetricSparkline: FC<MetricSparklineProps>;
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { c } from "react/compiler-runtime";
|
|
3
|
+
import { useEffect, useId, useState } from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
import { cn } from "../../../utils/cn.js";
|
|
6
|
+
import { useTestId } from "../../../utils/testId.js";
|
|
7
|
+
import { useDateFormat } from "../../DateFormatProvider/useDateFormat.js";
|
|
8
|
+
import { ChartHoverCardRow } from "../internal/ChartHoverCard.js";
|
|
9
|
+
import { LineChartHoverPopover, LineChartHoverPopoverTimestamp } from "../LineChart/index.js";
|
|
10
|
+
import { LINE_CURSOR_DASHARRAY } from "../LineChart/constants.js";
|
|
11
|
+
import { formatChartDate } from "../lib/timeFormatters.js";
|
|
12
|
+
import { metricSparklineClasses, metricSparklinePlotClasses, metricSparklinePopoverClasses, metricSparklineRulerClasses } from "./classes.js";
|
|
13
|
+
const SPARKLINE_COLORS = {
|
|
14
|
+
brand: {
|
|
15
|
+
line: "var(--color-bg-fill-brand)",
|
|
16
|
+
area: "var(--color-bg-fill-brand)"
|
|
17
|
+
},
|
|
18
|
+
positive: {
|
|
19
|
+
line: "var(--color-bg-fill-success)",
|
|
20
|
+
area: "var(--color-bg-fill-success)"
|
|
21
|
+
},
|
|
22
|
+
negative: {
|
|
23
|
+
line: "var(--color-bg-fill-danger)",
|
|
24
|
+
area: "var(--color-bg-fill-danger)"
|
|
25
|
+
},
|
|
26
|
+
neutral: {
|
|
27
|
+
line: "var(--color-border-strong-primary)",
|
|
28
|
+
area: "var(--color-bg-strong-primary)"
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const HEIGHT = 48;
|
|
32
|
+
const PAD_TOP = 4;
|
|
33
|
+
const PAD_BOTTOM = 8;
|
|
34
|
+
const STROKE_WIDTH = 1.5;
|
|
35
|
+
const POPOVER_OFFSET_X = 8;
|
|
36
|
+
const POPOVER_OFFSET_Y = 14;
|
|
37
|
+
const buildPaths = (values)=>{
|
|
38
|
+
const ys = 1 === values.length ? values.concat(values) : values;
|
|
39
|
+
const finite = ys.filter(Number.isFinite);
|
|
40
|
+
const min = Math.min(...finite);
|
|
41
|
+
const span = Math.max(...finite) - min;
|
|
42
|
+
const inner = HEIGHT - PAD_TOP - PAD_BOTTOM;
|
|
43
|
+
const toY = (v)=>0 === span ? PAD_TOP + inner / 2 : PAD_TOP + (1 - (v - min) / span) * inner;
|
|
44
|
+
const line = [];
|
|
45
|
+
const area = [];
|
|
46
|
+
let runEnd = -1;
|
|
47
|
+
ys.forEach((v, i)=>{
|
|
48
|
+
if (!Number.isFinite(v)) {
|
|
49
|
+
if (runEnd >= 0) area.push(`L${runEnd},${HEIGHT} Z`);
|
|
50
|
+
runEnd = -1;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const y = toY(v);
|
|
54
|
+
line.push(`${runEnd < 0 ? "M" : "L"}${i},${y}`);
|
|
55
|
+
area.push(runEnd < 0 ? `M${i},${HEIGHT} L${i},${y}` : `L${i},${y}`);
|
|
56
|
+
runEnd = i;
|
|
57
|
+
});
|
|
58
|
+
if (runEnd >= 0) area.push(`L${runEnd},${HEIGHT} Z`);
|
|
59
|
+
return {
|
|
60
|
+
width: ys.length - 1,
|
|
61
|
+
line: line.join(" "),
|
|
62
|
+
area: area.join(" ")
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
const ISO_DATE = /^\d{4}-\d{2}-\d{2}/;
|
|
66
|
+
const MetricSparkline = (t0)=>{
|
|
67
|
+
const $ = c(61);
|
|
68
|
+
let className;
|
|
69
|
+
let data;
|
|
70
|
+
let formatValue;
|
|
71
|
+
let formatX;
|
|
72
|
+
let label;
|
|
73
|
+
let props;
|
|
74
|
+
let ref;
|
|
75
|
+
let t1;
|
|
76
|
+
let testIdProp;
|
|
77
|
+
if ($[0] !== t0) {
|
|
78
|
+
({ data, color: t1, label, formatX, formatValue, className, ref, "data-testid": testIdProp, ...props } = t0);
|
|
79
|
+
$[0] = t0;
|
|
80
|
+
$[1] = className;
|
|
81
|
+
$[2] = data;
|
|
82
|
+
$[3] = formatValue;
|
|
83
|
+
$[4] = formatX;
|
|
84
|
+
$[5] = label;
|
|
85
|
+
$[6] = props;
|
|
86
|
+
$[7] = ref;
|
|
87
|
+
$[8] = t1;
|
|
88
|
+
$[9] = testIdProp;
|
|
89
|
+
} else {
|
|
90
|
+
className = $[1];
|
|
91
|
+
data = $[2];
|
|
92
|
+
formatValue = $[3];
|
|
93
|
+
formatX = $[4];
|
|
94
|
+
label = $[5];
|
|
95
|
+
props = $[6];
|
|
96
|
+
ref = $[7];
|
|
97
|
+
t1 = $[8];
|
|
98
|
+
testIdProp = $[9];
|
|
99
|
+
}
|
|
100
|
+
const color = void 0 === t1 ? "brand" : t1;
|
|
101
|
+
const testId = useTestId("sparkline", testIdProp);
|
|
102
|
+
const popoverTestId = testId ? `${testId}--popover` : void 0;
|
|
103
|
+
const { order } = useDateFormat();
|
|
104
|
+
const t2 = useId();
|
|
105
|
+
let t3;
|
|
106
|
+
if ($[10] !== t2) {
|
|
107
|
+
let t4;
|
|
108
|
+
if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
|
|
109
|
+
t4 = /[^\w-]/g;
|
|
110
|
+
$[12] = t4;
|
|
111
|
+
} else t4 = $[12];
|
|
112
|
+
t3 = t2.replace(t4, "");
|
|
113
|
+
$[10] = t2;
|
|
114
|
+
$[11] = t3;
|
|
115
|
+
} else t3 = $[11];
|
|
116
|
+
const gradientId = `metric-sparkline-${t3}`;
|
|
117
|
+
const [hover, setHover] = useState(null);
|
|
118
|
+
const { line, area } = SPARKLINE_COLORS[color];
|
|
119
|
+
let t4;
|
|
120
|
+
if ($[13] !== data) {
|
|
121
|
+
t4 = data.length > 0 ? buildPaths(data.map(_temp)) : null;
|
|
122
|
+
$[13] = data;
|
|
123
|
+
$[14] = t4;
|
|
124
|
+
} else t4 = $[14];
|
|
125
|
+
const paths = t4;
|
|
126
|
+
const last = data.length - 1;
|
|
127
|
+
let t5;
|
|
128
|
+
if ($[15] !== last) {
|
|
129
|
+
t5 = (index)=>0 === last ? 0.5 : index / last;
|
|
130
|
+
$[15] = last;
|
|
131
|
+
$[16] = t5;
|
|
132
|
+
} else t5 = $[16];
|
|
133
|
+
const fractionOf = t5;
|
|
134
|
+
let t6;
|
|
135
|
+
if ($[17] !== last) {
|
|
136
|
+
t6 = (event)=>{
|
|
137
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
138
|
+
if (last < 0 || 0 === rect.width) return;
|
|
139
|
+
const ratio = Math.min(Math.max((event.clientX - rect.left) / rect.width, 0), 1);
|
|
140
|
+
setHover({
|
|
141
|
+
index: Math.round(ratio * last),
|
|
142
|
+
left: rect.left,
|
|
143
|
+
top: rect.top,
|
|
144
|
+
width: rect.width
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
$[17] = last;
|
|
148
|
+
$[18] = t6;
|
|
149
|
+
} else t6 = $[18];
|
|
150
|
+
const handlePointerMove = t6;
|
|
151
|
+
let t7;
|
|
152
|
+
if ($[19] === Symbol.for("react.memo_cache_sentinel")) {
|
|
153
|
+
t7 = ()=>setHover(null);
|
|
154
|
+
$[19] = t7;
|
|
155
|
+
} else t7 = $[19];
|
|
156
|
+
const handlePointerLeave = t7;
|
|
157
|
+
const isHovering = null !== hover;
|
|
158
|
+
let t8;
|
|
159
|
+
let t9;
|
|
160
|
+
if ($[20] !== isHovering) {
|
|
161
|
+
t8 = ()=>{
|
|
162
|
+
if (!isHovering) return;
|
|
163
|
+
const clear = ()=>setHover(null);
|
|
164
|
+
window.addEventListener("scroll", clear, {
|
|
165
|
+
capture: true,
|
|
166
|
+
passive: true
|
|
167
|
+
});
|
|
168
|
+
window.addEventListener("resize", clear);
|
|
169
|
+
return ()=>{
|
|
170
|
+
window.removeEventListener("scroll", clear, {
|
|
171
|
+
capture: true
|
|
172
|
+
});
|
|
173
|
+
window.removeEventListener("resize", clear);
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
t9 = [
|
|
177
|
+
isHovering
|
|
178
|
+
];
|
|
179
|
+
$[20] = isHovering;
|
|
180
|
+
$[21] = t8;
|
|
181
|
+
$[22] = t9;
|
|
182
|
+
} else {
|
|
183
|
+
t8 = $[21];
|
|
184
|
+
t9 = $[22];
|
|
185
|
+
}
|
|
186
|
+
useEffect(t8, t9);
|
|
187
|
+
const index_0 = hover && hover.index <= last ? hover.index : null;
|
|
188
|
+
const point = null === index_0 ? void 0 : data[index_0];
|
|
189
|
+
const fraction = null === index_0 ? 0 : fractionOf(index_0);
|
|
190
|
+
const flip = fraction > 0.5;
|
|
191
|
+
let t10;
|
|
192
|
+
if ($[23] !== formatX || $[24] !== order || $[25] !== point) {
|
|
193
|
+
t10 = point ? formatX ? formatX(point.x) : "string" != typeof point.x || ISO_DATE.test(point.x) ? formatChartDate(point.x, {
|
|
194
|
+
order,
|
|
195
|
+
withYear: true
|
|
196
|
+
}) || String(point.x) : point.x : null;
|
|
197
|
+
$[23] = formatX;
|
|
198
|
+
$[24] = order;
|
|
199
|
+
$[25] = point;
|
|
200
|
+
$[26] = t10;
|
|
201
|
+
} else t10 = $[26];
|
|
202
|
+
const formattedX = t10;
|
|
203
|
+
let t11;
|
|
204
|
+
if ($[27] !== className) {
|
|
205
|
+
t11 = cn(metricSparklineClasses, className);
|
|
206
|
+
$[27] = className;
|
|
207
|
+
$[28] = t11;
|
|
208
|
+
} else t11 = $[28];
|
|
209
|
+
const t12 = testId && `${testId}--plot`;
|
|
210
|
+
let t13;
|
|
211
|
+
if ($[29] !== area || $[30] !== gradientId || $[31] !== line || $[32] !== paths) {
|
|
212
|
+
t13 = paths && /*#__PURE__*/ jsxs("svg", {
|
|
213
|
+
className: "block size-full",
|
|
214
|
+
viewBox: `0 0 ${paths.width} ${HEIGHT}`,
|
|
215
|
+
preserveAspectRatio: "none",
|
|
216
|
+
children: [
|
|
217
|
+
/*#__PURE__*/ jsx("defs", {
|
|
218
|
+
children: /*#__PURE__*/ jsxs("linearGradient", {
|
|
219
|
+
id: gradientId,
|
|
220
|
+
x1: "0",
|
|
221
|
+
y1: "0",
|
|
222
|
+
x2: "0",
|
|
223
|
+
y2: "1",
|
|
224
|
+
children: [
|
|
225
|
+
/*#__PURE__*/ jsx("stop", {
|
|
226
|
+
offset: "0",
|
|
227
|
+
stopColor: area,
|
|
228
|
+
stopOpacity: 0.2
|
|
229
|
+
}),
|
|
230
|
+
/*#__PURE__*/ jsx("stop", {
|
|
231
|
+
offset: "1",
|
|
232
|
+
stopColor: area,
|
|
233
|
+
stopOpacity: 0
|
|
234
|
+
})
|
|
235
|
+
]
|
|
236
|
+
})
|
|
237
|
+
}),
|
|
238
|
+
/*#__PURE__*/ jsx("path", {
|
|
239
|
+
d: paths.area,
|
|
240
|
+
fill: `url(#${gradientId})`
|
|
241
|
+
}),
|
|
242
|
+
/*#__PURE__*/ jsx("path", {
|
|
243
|
+
d: paths.line,
|
|
244
|
+
fill: "none",
|
|
245
|
+
stroke: line,
|
|
246
|
+
strokeWidth: STROKE_WIDTH,
|
|
247
|
+
strokeLinejoin: "round",
|
|
248
|
+
strokeLinecap: "round",
|
|
249
|
+
vectorEffect: "non-scaling-stroke"
|
|
250
|
+
})
|
|
251
|
+
]
|
|
252
|
+
});
|
|
253
|
+
$[29] = area;
|
|
254
|
+
$[30] = gradientId;
|
|
255
|
+
$[31] = line;
|
|
256
|
+
$[32] = paths;
|
|
257
|
+
$[33] = t13;
|
|
258
|
+
} else t13 = $[33];
|
|
259
|
+
let t14;
|
|
260
|
+
if ($[34] !== fraction || $[35] !== point || $[36] !== testId) {
|
|
261
|
+
t14 = point && /*#__PURE__*/ jsx("svg", {
|
|
262
|
+
"data-slot": "metric-sparkline-ruler",
|
|
263
|
+
"data-testid": testId && `${testId}--ruler`,
|
|
264
|
+
className: metricSparklineRulerClasses,
|
|
265
|
+
style: {
|
|
266
|
+
left: `${100 * fraction}%`
|
|
267
|
+
},
|
|
268
|
+
children: /*#__PURE__*/ jsx("line", {
|
|
269
|
+
x1: "0.5",
|
|
270
|
+
x2: "0.5",
|
|
271
|
+
y1: "0",
|
|
272
|
+
y2: "100%",
|
|
273
|
+
stroke: "var(--color-border-strong-primary)",
|
|
274
|
+
strokeDasharray: LINE_CURSOR_DASHARRAY
|
|
275
|
+
})
|
|
276
|
+
});
|
|
277
|
+
$[34] = fraction;
|
|
278
|
+
$[35] = point;
|
|
279
|
+
$[36] = testId;
|
|
280
|
+
$[37] = t14;
|
|
281
|
+
} else t14 = $[37];
|
|
282
|
+
let t15;
|
|
283
|
+
if ($[38] !== handlePointerMove || $[39] !== t12 || $[40] !== t13 || $[41] !== t14) {
|
|
284
|
+
t15 = /*#__PURE__*/ jsxs("div", {
|
|
285
|
+
"data-slot": "metric-sparkline-plot",
|
|
286
|
+
"data-testid": t12,
|
|
287
|
+
"aria-hidden": "true",
|
|
288
|
+
className: metricSparklinePlotClasses,
|
|
289
|
+
onPointerMove: handlePointerMove,
|
|
290
|
+
onPointerLeave: handlePointerLeave,
|
|
291
|
+
children: [
|
|
292
|
+
t13,
|
|
293
|
+
t14
|
|
294
|
+
]
|
|
295
|
+
});
|
|
296
|
+
$[38] = handlePointerMove;
|
|
297
|
+
$[39] = t12;
|
|
298
|
+
$[40] = t13;
|
|
299
|
+
$[41] = t14;
|
|
300
|
+
$[42] = t15;
|
|
301
|
+
} else t15 = $[42];
|
|
302
|
+
let t16;
|
|
303
|
+
if ($[43] !== flip || $[44] !== formatValue || $[45] !== formattedX || $[46] !== fraction || $[47] !== hover || $[48] !== label || $[49] !== line || $[50] !== point || $[51] !== popoverTestId) {
|
|
304
|
+
t16 = hover && point && /*#__PURE__*/ createPortal(/*#__PURE__*/ jsx("div", {
|
|
305
|
+
className: cn(metricSparklinePopoverClasses, flip && "-translate-x-full"),
|
|
306
|
+
style: {
|
|
307
|
+
left: hover.left + fraction * hover.width + (flip ? -POPOVER_OFFSET_X : POPOVER_OFFSET_X),
|
|
308
|
+
top: hover.top + POPOVER_OFFSET_Y
|
|
309
|
+
},
|
|
310
|
+
children: /*#__PURE__*/ jsxs(LineChartHoverPopover, {
|
|
311
|
+
"data-testid": popoverTestId,
|
|
312
|
+
children: [
|
|
313
|
+
/*#__PURE__*/ jsx(LineChartHoverPopoverTimestamp, {
|
|
314
|
+
children: formattedX
|
|
315
|
+
}),
|
|
316
|
+
/*#__PURE__*/ jsx(ChartHoverCardRow, {
|
|
317
|
+
color: line,
|
|
318
|
+
label: label,
|
|
319
|
+
value: Number.isFinite(point.value) ? point.value : null,
|
|
320
|
+
formatValue: formatValue && ((v)=>"number" == typeof v ? formatValue(v) : "—")
|
|
321
|
+
})
|
|
322
|
+
]
|
|
323
|
+
})
|
|
324
|
+
}), document.body);
|
|
325
|
+
$[43] = flip;
|
|
326
|
+
$[44] = formatValue;
|
|
327
|
+
$[45] = formattedX;
|
|
328
|
+
$[46] = fraction;
|
|
329
|
+
$[47] = hover;
|
|
330
|
+
$[48] = label;
|
|
331
|
+
$[49] = line;
|
|
332
|
+
$[50] = point;
|
|
333
|
+
$[51] = popoverTestId;
|
|
334
|
+
$[52] = t16;
|
|
335
|
+
} else t16 = $[52];
|
|
336
|
+
let t17;
|
|
337
|
+
if ($[53] !== color || $[54] !== props || $[55] !== ref || $[56] !== t11 || $[57] !== t15 || $[58] !== t16 || $[59] !== testId) {
|
|
338
|
+
t17 = /*#__PURE__*/ jsxs("div", {
|
|
339
|
+
...props,
|
|
340
|
+
ref: ref,
|
|
341
|
+
"data-slot": "metric-sparkline",
|
|
342
|
+
"data-testid": testId,
|
|
343
|
+
"data-color": color,
|
|
344
|
+
className: t11,
|
|
345
|
+
children: [
|
|
346
|
+
t15,
|
|
347
|
+
t16
|
|
348
|
+
]
|
|
349
|
+
});
|
|
350
|
+
$[53] = color;
|
|
351
|
+
$[54] = props;
|
|
352
|
+
$[55] = ref;
|
|
353
|
+
$[56] = t11;
|
|
354
|
+
$[57] = t15;
|
|
355
|
+
$[58] = t16;
|
|
356
|
+
$[59] = testId;
|
|
357
|
+
$[60] = t17;
|
|
358
|
+
} else t17 = $[60];
|
|
359
|
+
return t17;
|
|
360
|
+
};
|
|
361
|
+
MetricSparkline.displayName = "MetricSparkline";
|
|
362
|
+
function _temp(d) {
|
|
363
|
+
return d.value;
|
|
364
|
+
}
|
|
365
|
+
export { MetricSparkline };
|
|
@@ -6,3 +6,7 @@ export declare const metricTotalValueClasses = "font-sans-display text-lg font-m
|
|
|
6
6
|
export declare const metricTotalWordClasses = "text-xs font-normal text-text-secondary";
|
|
7
7
|
export declare const metricCaptionClasses = "text-xs text-text-secondary";
|
|
8
8
|
export declare const metricSkeletonLineClasses = "w-full py-4";
|
|
9
|
+
export declare const metricSparklineClasses = "mt-auto w-full px-px";
|
|
10
|
+
export declare const metricSparklinePlotClasses = "relative h-48";
|
|
11
|
+
export declare const metricSparklineRulerClasses = "pointer-events-none absolute top-0 h-full w-px -translate-x-1/2 overflow-visible";
|
|
12
|
+
export declare const metricSparklinePopoverClasses = "pointer-events-none fixed z-(--tooltip-z-index)";
|
|
@@ -6,4 +6,8 @@ const metricTotalValueClasses = 'font-sans-display text-lg font-medium text-text
|
|
|
6
6
|
const metricTotalWordClasses = 'text-xs font-normal text-text-secondary';
|
|
7
7
|
const metricCaptionClasses = 'text-xs text-text-secondary';
|
|
8
8
|
const metricSkeletonLineClasses = 'w-full py-4';
|
|
9
|
-
|
|
9
|
+
const metricSparklineClasses = 'mt-auto w-full px-px';
|
|
10
|
+
const metricSparklinePlotClasses = 'relative h-48';
|
|
11
|
+
const metricSparklineRulerClasses = 'pointer-events-none absolute top-0 h-full w-px -translate-x-1/2 overflow-visible';
|
|
12
|
+
const metricSparklinePopoverClasses = 'pointer-events-none fixed z-(--tooltip-z-index)';
|
|
13
|
+
export { metricCaptionClasses, metricHeaderClasses, metricRootClasses, metricSkeletonLineClasses, metricSparklineClasses, metricSparklinePlotClasses, metricSparklinePopoverClasses, metricSparklineRulerClasses, metricTotalClasses, metricTotalValueClasses, metricTotalWordClasses, metricValueClasses };
|
|
@@ -3,5 +3,6 @@ export { MetricCaption, type MetricCaptionProps } from './MetricCaption.js';
|
|
|
3
3
|
export { MetricDelta, type MetricDeltaProps } from './MetricDelta.js';
|
|
4
4
|
export { MetricHeader, type MetricHeaderProps } from './MetricHeader.js';
|
|
5
5
|
export { MetricSkeleton, type MetricSkeletonProps } from './MetricSkeleton.js';
|
|
6
|
+
export { MetricSparkline, type MetricSparklineColor, type MetricSparklinePoint, type MetricSparklineProps, } from './MetricSparkline.js';
|
|
6
7
|
export { MetricTotal, type MetricTotalConnector, type MetricTotalProps } from './MetricTotal.js';
|
|
7
8
|
export { MetricValue, type MetricValueProps } from './MetricValue.js';
|
|
@@ -3,5 +3,6 @@ export { MetricCaption } from "./MetricCaption.js";
|
|
|
3
3
|
export { MetricDelta } from "./MetricDelta.js";
|
|
4
4
|
export { MetricHeader } from "./MetricHeader.js";
|
|
5
5
|
export { MetricSkeleton } from "./MetricSkeleton.js";
|
|
6
|
+
export { MetricSparkline } from "./MetricSparkline.js";
|
|
6
7
|
export { MetricTotal } from "./MetricTotal.js";
|
|
7
8
|
export { MetricValue } from "./MetricValue.js";
|
|
@@ -5,6 +5,6 @@ export { HorizontalBarStack, type HorizontalBarStackDatum, type HorizontalBarSta
|
|
|
5
5
|
export { type ChartTimeFormatters, useChartTimeFormatters } from './hooks/index.js';
|
|
6
6
|
export { LineChart, LineChartBody, type LineChartBodyProps, type LineChartDatum, LineChartEmpty, type LineChartEmptyProps, LineChartGrid, type LineChartGridProps, LineChartHoverPopover, LineChartHoverPopoverDot, type LineChartHoverPopoverDotProps, type LineChartHoverPopoverProps, LineChartHoverPopoverRow, type LineChartHoverPopoverRowProps, LineChartHoverPopoverTimestamp, type LineChartHoverPopoverTimestampProps, LineChartLegend, LineChartLegendItem, type LineChartLegendItemProps, type LineChartLegendOrientation, type LineChartLegendProps, LineChartLine, type LineChartLineProps, type LineChartProps, type LineChartSeries, LineChartTooltip, type LineChartTooltipProps, type LineChartTooltipRenderArgs, LineChartXAxis, type LineChartXAxisProps, LineChartYAxis, type LineChartYAxisProps, LineChartZoomBrush, type LineChartZoomBrushProps, LineChartZoomPopover, LineChartZoomPopoverConfirm, type LineChartZoomPopoverConfirmProps, type LineChartZoomPopoverProps, LineChartZoomPopoverRange, type LineChartZoomPopoverRangeProps, type LineChartZoomRange, } from './LineChart/index.js';
|
|
7
7
|
export { type ChartHourCycle, type ChartTimeFormatterOptions, type ChartTimeOrder, formatChartDate, formatChartDateTime, formatChartHour, formatChartTimezone, withTimezoneChip, } from './lib/index.js';
|
|
8
|
-
export { Metric, MetricCaption, type MetricCaptionProps, MetricDelta, type MetricDeltaProps, MetricHeader, type MetricHeaderProps, type MetricProps, MetricSkeleton, type MetricSkeletonProps, MetricTotal, type MetricTotalConnector, type MetricTotalProps, MetricValue, type MetricValueProps, } from './Metric/index.js';
|
|
8
|
+
export { Metric, MetricCaption, type MetricCaptionProps, MetricDelta, type MetricDeltaProps, MetricHeader, type MetricHeaderProps, type MetricProps, MetricSkeleton, type MetricSkeletonProps, MetricSparkline, type MetricSparklineColor, type MetricSparklinePoint, type MetricSparklineProps, MetricTotal, type MetricTotalConnector, type MetricTotalProps, MetricValue, type MetricValueProps, } from './Metric/index.js';
|
|
9
9
|
export { LegendDot, type LegendDotProps, PieChart, PieChartCenter, PieChartCenterLabel, type PieChartCenterLabelPluralRules, type PieChartCenterLabelProps, type PieChartCenterProps, PieChartCenterValue, type PieChartCenterValueProps, type PieChartDatum, PieChartDonut, type PieChartDonutProps, PieChartLegend, PieChartLegendItem, type PieChartLegendItemProps, PieChartLegendPercent, type PieChartLegendPercentProps, type PieChartLegendPercentVariant, type PieChartLegendProps, PieChartLegendValue, type PieChartLegendValueProps, type PieChartProps, PieChartSkeleton, type PieChartSkeletonProps, } from './PieChart/index.js';
|
|
10
10
|
export type { ChartColor } from './types.js';
|
|
@@ -5,5 +5,5 @@ export { HorizontalBarStack, HorizontalBarStackSkeleton } from "./HorizontalBarS
|
|
|
5
5
|
export { useChartTimeFormatters } from "./hooks/index.js";
|
|
6
6
|
export { LineChart, LineChartBody, LineChartEmpty, LineChartGrid, LineChartHoverPopover, LineChartHoverPopoverDot, LineChartHoverPopoverRow, LineChartHoverPopoverTimestamp, LineChartLegend, LineChartLegendItem, LineChartLine, LineChartTooltip, LineChartXAxis, LineChartYAxis, LineChartZoomBrush, LineChartZoomPopover, LineChartZoomPopoverConfirm, LineChartZoomPopoverRange } from "./LineChart/index.js";
|
|
7
7
|
export { formatChartDate, formatChartDateTime, formatChartHour, formatChartTimezone, withTimezoneChip } from "./lib/index.js";
|
|
8
|
-
export { Metric, MetricCaption, MetricDelta, MetricHeader, MetricSkeleton, MetricTotal, MetricValue } from "./Metric/index.js";
|
|
8
|
+
export { Metric, MetricCaption, MetricDelta, MetricHeader, MetricSkeleton, MetricSparkline, MetricTotal, MetricValue } from "./Metric/index.js";
|
|
9
9
|
export { LegendDot, PieChart, PieChartCenter, PieChartCenterLabel, PieChartCenterValue, PieChartDonut, PieChartLegend, PieChartLegendItem, PieChartLegendPercent, PieChartLegendValue, PieChartSkeleton } from "./PieChart/index.js";
|
|
@@ -10,9 +10,13 @@ export interface ChartTimeFormatterOptions {
|
|
|
10
10
|
export declare const formatChartHour: (value: unknown, options?: {
|
|
11
11
|
hourCycle?: ChartHourCycle;
|
|
12
12
|
}) => string;
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* `24 Jan` (day-first) / `Jan 24` (month-first). Year is omitted by default — axis space is
|
|
15
|
+
* precious; `withYear` gives `24 Jan, 2026` / `Jan 24, 2026` for popovers.
|
|
16
|
+
*/
|
|
14
17
|
export declare const formatChartDate: (value: unknown, options?: {
|
|
15
18
|
order?: ChartTimeOrder;
|
|
19
|
+
withYear?: boolean;
|
|
16
20
|
}) => string;
|
|
17
21
|
/** Combined `24 Jan 14:32`. Respects both `order` and `hourCycle`. */
|
|
18
22
|
export declare const formatChartDateTime: (value: unknown, options?: ChartTimeFormatterOptions) => string;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { format, isValid } from "date-fns";
|
|
2
|
+
import { format, isValid, parseISO } from "date-fns";
|
|
3
3
|
import { formatTimezone } from "../../../utils/formatDateTime.js";
|
|
4
|
+
const DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
|
|
4
5
|
const toDate = (value)=>{
|
|
5
6
|
if (value instanceof Date) return isValid(value) ? value : null;
|
|
6
7
|
if ('number' == typeof value || 'string' == typeof value) {
|
|
7
|
-
const d = new Date(value);
|
|
8
|
+
const d = 'string' == typeof value && DATE_ONLY.test(value) ? parseISO(value) : new Date(value);
|
|
8
9
|
return isValid(d) ? d : null;
|
|
9
10
|
}
|
|
10
11
|
return null;
|
|
@@ -25,7 +26,7 @@ const formatChartHour = (value, options = {})=>{
|
|
|
25
26
|
const formatChartDate = (value, options = {})=>{
|
|
26
27
|
const date = toDate(value);
|
|
27
28
|
if (!date) return '';
|
|
28
|
-
return format(date, datePattern(options.order ?? 'day-first', false));
|
|
29
|
+
return format(date, datePattern(options.order ?? 'day-first', options.withYear ?? false));
|
|
29
30
|
};
|
|
30
31
|
const formatChartDateTime = (value, options = {})=>{
|
|
31
32
|
const date = toDate(value);
|