@x-plat/design-system 0.5.31 → 0.5.33
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/Chart/index.cjs +326 -132
- package/dist/components/Chart/index.css +70 -8
- package/dist/components/Chart/index.js +326 -132
- package/dist/components/Table/index.css +4 -0
- package/dist/components/index.cjs +326 -132
- package/dist/components/index.css +74 -8
- package/dist/components/index.js +326 -132
- package/dist/index.cjs +326 -132
- package/dist/index.css +74 -8
- package/dist/index.js +326 -132
- package/package.json +1 -1
package/dist/index.css
CHANGED
|
@@ -1999,19 +1999,43 @@
|
|
|
1999
1999
|
.lib-xplat-chart .chart-area {
|
|
2000
2000
|
opacity: 1;
|
|
2001
2001
|
}
|
|
2002
|
+
.lib-xplat-chart .chart-crosshair {
|
|
2003
|
+
stroke: var(--semantic-border-strong);
|
|
2004
|
+
stroke-width: 1;
|
|
2005
|
+
stroke-dasharray: 4 3;
|
|
2006
|
+
pointer-events: none;
|
|
2007
|
+
}
|
|
2008
|
+
.lib-xplat-chart .chart-point-active {
|
|
2009
|
+
pointer-events: none;
|
|
2010
|
+
transition: cx 0.05s, cy 0.05s;
|
|
2011
|
+
}
|
|
2012
|
+
.lib-xplat-chart .chart-crosshair-label {
|
|
2013
|
+
font-size: 11px;
|
|
2014
|
+
font-weight: 500;
|
|
2015
|
+
color: var(--semantic-text-strong);
|
|
2016
|
+
text-align: center;
|
|
2017
|
+
white-space: nowrap;
|
|
2018
|
+
overflow: visible;
|
|
2019
|
+
}
|
|
2002
2020
|
.lib-xplat-chart .chart-tooltip {
|
|
2003
|
-
|
|
2004
|
-
transform: translate(-50%, -100%);
|
|
2005
|
-
padding: var(--spacing-space-2) var(--spacing-space-3);
|
|
2021
|
+
padding: var(--spacing-space-3);
|
|
2006
2022
|
background-color: var(--semantic-surface-neutral-strong);
|
|
2007
2023
|
color: var(--semantic-text-inverse);
|
|
2008
2024
|
font-size: 12px;
|
|
2025
|
+
line-height: 18px;
|
|
2009
2026
|
font-weight: 500;
|
|
2010
2027
|
border-radius: var(--spacing-radius-md);
|
|
2011
|
-
|
|
2028
|
+
max-width: 240px;
|
|
2012
2029
|
pointer-events: none;
|
|
2013
|
-
|
|
2014
|
-
|
|
2030
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
2031
|
+
}
|
|
2032
|
+
.lib-xplat-chart .chart-tooltip.chart-tooltip-show {
|
|
2033
|
+
opacity: 1;
|
|
2034
|
+
animation: chart-tooltip-in 120ms ease-out;
|
|
2035
|
+
}
|
|
2036
|
+
.lib-xplat-chart .chart-tooltip.chart-tooltip-hide {
|
|
2037
|
+
opacity: 0;
|
|
2038
|
+
animation: chart-tooltip-out 80ms ease-in;
|
|
2015
2039
|
}
|
|
2016
2040
|
.lib-xplat-chart .chart-bar-animate {
|
|
2017
2041
|
animation: chart-bar-grow 800ms ease-out both;
|
|
@@ -2023,6 +2047,38 @@
|
|
|
2023
2047
|
.lib-xplat-chart .chart-area[style*=animationDelay] {
|
|
2024
2048
|
animation: chart-fade-in 800ms ease-out both;
|
|
2025
2049
|
}
|
|
2050
|
+
.lib-xplat-chart .chart-legend {
|
|
2051
|
+
display: flex;
|
|
2052
|
+
flex-wrap: wrap;
|
|
2053
|
+
justify-content: center;
|
|
2054
|
+
gap: var(--spacing-space-4);
|
|
2055
|
+
padding: var(--spacing-space-3) 0;
|
|
2056
|
+
}
|
|
2057
|
+
.lib-xplat-chart .chart-legend-item {
|
|
2058
|
+
display: flex;
|
|
2059
|
+
align-items: flex-start;
|
|
2060
|
+
gap: var(--spacing-space-2);
|
|
2061
|
+
}
|
|
2062
|
+
.lib-xplat-chart .chart-legend-dot {
|
|
2063
|
+
flex-shrink: 0;
|
|
2064
|
+
width: 10px;
|
|
2065
|
+
height: 10px;
|
|
2066
|
+
border-radius: 50%;
|
|
2067
|
+
margin-top: 3px;
|
|
2068
|
+
}
|
|
2069
|
+
.lib-xplat-chart .chart-legend-text {
|
|
2070
|
+
display: flex;
|
|
2071
|
+
flex-direction: column;
|
|
2072
|
+
}
|
|
2073
|
+
.lib-xplat-chart .chart-legend-label {
|
|
2074
|
+
font-size: 12px;
|
|
2075
|
+
color: var(--semantic-text-muted);
|
|
2076
|
+
}
|
|
2077
|
+
.lib-xplat-chart .chart-legend-value {
|
|
2078
|
+
font-size: 14px;
|
|
2079
|
+
font-weight: 600;
|
|
2080
|
+
color: var(--semantic-text-strong);
|
|
2081
|
+
}
|
|
2026
2082
|
@keyframes chart-bar-grow {
|
|
2027
2083
|
from {
|
|
2028
2084
|
transform: scaleY(0);
|
|
@@ -2042,11 +2098,17 @@
|
|
|
2042
2098
|
@keyframes chart-tooltip-in {
|
|
2043
2099
|
from {
|
|
2044
2100
|
opacity: 0;
|
|
2045
|
-
transform: translate(-50%, -90%);
|
|
2046
2101
|
}
|
|
2047
2102
|
to {
|
|
2048
2103
|
opacity: 1;
|
|
2049
|
-
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
@keyframes chart-tooltip-out {
|
|
2107
|
+
from {
|
|
2108
|
+
opacity: 1;
|
|
2109
|
+
}
|
|
2110
|
+
to {
|
|
2111
|
+
opacity: 0;
|
|
2050
2112
|
}
|
|
2051
2113
|
}
|
|
2052
2114
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -3844,6 +3906,10 @@
|
|
|
3844
3906
|
height: 100%;
|
|
3845
3907
|
position: relative;
|
|
3846
3908
|
overflow: auto;
|
|
3909
|
+
scrollbar-width: none;
|
|
3910
|
+
}
|
|
3911
|
+
.lib-xplat-table-wrapper::-webkit-scrollbar {
|
|
3912
|
+
display: none;
|
|
3847
3913
|
}
|
|
3848
3914
|
.lib-xplat-table-wrapper.sm > .lib-xplat-table > thead > tr > th,
|
|
3849
3915
|
.lib-xplat-table-wrapper.sm > .lib-xplat-table > thead > tr > td,
|
package/dist/index.js
CHANGED
|
@@ -6351,40 +6351,28 @@ var useChartAnimation = (containerRef, dataKey) => {
|
|
|
6351
6351
|
}, [dataKey]);
|
|
6352
6352
|
return animate || prefersReducedMotion();
|
|
6353
6353
|
};
|
|
6354
|
+
var TOOLTIP_OFFSET = 12;
|
|
6354
6355
|
var useChartTooltip = (enabled) => {
|
|
6355
6356
|
const [tooltip, setTooltip] = React6.useState({
|
|
6356
6357
|
visible: false,
|
|
6357
|
-
|
|
6358
|
-
|
|
6358
|
+
clientX: 0,
|
|
6359
|
+
clientY: 0,
|
|
6359
6360
|
content: ""
|
|
6360
6361
|
});
|
|
6361
6362
|
const containerRef = React6.useRef(null);
|
|
6362
6363
|
const rafRef = React6.useRef(0);
|
|
6363
6364
|
const move = React6.useCallback((e) => {
|
|
6364
6365
|
if (!enabled) return;
|
|
6365
|
-
const
|
|
6366
|
-
const
|
|
6366
|
+
const cx = e.clientX;
|
|
6367
|
+
const cy = e.clientY;
|
|
6367
6368
|
cancelAnimationFrame(rafRef.current);
|
|
6368
6369
|
rafRef.current = requestAnimationFrame(() => {
|
|
6369
|
-
|
|
6370
|
-
if (!rect) return;
|
|
6371
|
-
setTooltip((prev) => ({
|
|
6372
|
-
...prev,
|
|
6373
|
-
x: clientX - rect.left,
|
|
6374
|
-
y: clientY - rect.top - 12
|
|
6375
|
-
}));
|
|
6370
|
+
setTooltip((prev) => ({ ...prev, clientX: cx, clientY: cy }));
|
|
6376
6371
|
});
|
|
6377
6372
|
}, [enabled]);
|
|
6378
6373
|
const show = React6.useCallback((e, content) => {
|
|
6379
6374
|
if (!enabled) return;
|
|
6380
|
-
|
|
6381
|
-
if (!rect) return;
|
|
6382
|
-
setTooltip({
|
|
6383
|
-
visible: true,
|
|
6384
|
-
x: e.clientX - rect.left,
|
|
6385
|
-
y: e.clientY - rect.top - 12,
|
|
6386
|
-
content
|
|
6387
|
-
});
|
|
6375
|
+
setTooltip({ visible: true, clientX: e.clientX, clientY: e.clientY, content });
|
|
6388
6376
|
}, [enabled]);
|
|
6389
6377
|
const hide = React6.useCallback(() => {
|
|
6390
6378
|
cancelAnimationFrame(rafRef.current);
|
|
@@ -6416,6 +6404,45 @@ var AxisLabels = React6.memo(({ labels, count, chartW, height }) => {
|
|
|
6416
6404
|
}) });
|
|
6417
6405
|
});
|
|
6418
6406
|
AxisLabels.displayName = "AxisLabels";
|
|
6407
|
+
var useCrosshair = (seriesPoints, entries, labels, chartH) => {
|
|
6408
|
+
const [activeIndex, setActiveIndex] = React6.useState(null);
|
|
6409
|
+
const handleMouseMove = React6.useCallback((e) => {
|
|
6410
|
+
const svg = e.currentTarget;
|
|
6411
|
+
const rect = svg.getBoundingClientRect();
|
|
6412
|
+
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
6413
|
+
if (seriesPoints.length === 0 || seriesPoints[0].length === 0) return;
|
|
6414
|
+
const points = seriesPoints[0];
|
|
6415
|
+
const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
|
|
6416
|
+
const threshold = step / 2;
|
|
6417
|
+
let closest = 0;
|
|
6418
|
+
let minDist = Math.abs(points[0].x - mx);
|
|
6419
|
+
for (let i = 1; i < points.length; i++) {
|
|
6420
|
+
const dist = Math.abs(points[i].x - mx);
|
|
6421
|
+
if (dist < minDist) {
|
|
6422
|
+
minDist = dist;
|
|
6423
|
+
closest = i;
|
|
6424
|
+
}
|
|
6425
|
+
}
|
|
6426
|
+
setActiveIndex(minDist <= threshold ? closest : null);
|
|
6427
|
+
}, [seriesPoints]);
|
|
6428
|
+
const handleMouseLeave = React6.useCallback(() => {
|
|
6429
|
+
setActiveIndex(null);
|
|
6430
|
+
}, []);
|
|
6431
|
+
const tooltipContent = React6.useMemo(() => {
|
|
6432
|
+
if (activeIndex === null) return "";
|
|
6433
|
+
return entries.map(([key], di) => {
|
|
6434
|
+
const p = seriesPoints[di]?.[activeIndex];
|
|
6435
|
+
return p ? `${key}: ${p.v}` : "";
|
|
6436
|
+
}).filter(Boolean).join(" / ");
|
|
6437
|
+
}, [activeIndex, entries, seriesPoints]);
|
|
6438
|
+
const getTooltipAt = React6.useCallback((idx) => {
|
|
6439
|
+
return entries.map(([key], di) => {
|
|
6440
|
+
const p = seriesPoints[di]?.[idx];
|
|
6441
|
+
return p ? `${key}: ${p.v}` : "";
|
|
6442
|
+
}).filter(Boolean).join(" / ");
|
|
6443
|
+
}, [entries, seriesPoints]);
|
|
6444
|
+
return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
|
|
6445
|
+
};
|
|
6419
6446
|
var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
6420
6447
|
const entries = React6.useMemo(() => Object.entries(data), [data]);
|
|
6421
6448
|
const maxVal = React6.useMemo(() => {
|
|
@@ -6435,8 +6462,9 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
|
|
|
6435
6462
|
),
|
|
6436
6463
|
[entries, count, chartW, chartH, maxVal]
|
|
6437
6464
|
);
|
|
6438
|
-
const showPoints = count <= 100;
|
|
6439
6465
|
const lineRefs = React6.useRef([]);
|
|
6466
|
+
const clipRef = React6.useRef(null);
|
|
6467
|
+
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
6440
6468
|
React6.useEffect(() => {
|
|
6441
6469
|
if (!animate) return;
|
|
6442
6470
|
lineRefs.current.forEach((el) => {
|
|
@@ -6449,61 +6477,123 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
|
|
|
6449
6477
|
el.style.strokeDashoffset = "0";
|
|
6450
6478
|
});
|
|
6451
6479
|
});
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6480
|
+
if (clipRef.current) {
|
|
6481
|
+
clipRef.current.setAttribute("width", "0");
|
|
6482
|
+
requestAnimationFrame(() => {
|
|
6483
|
+
if (clipRef.current) {
|
|
6484
|
+
clipRef.current.style.transition = "width 1200ms ease-out 200ms";
|
|
6485
|
+
clipRef.current.setAttribute("width", `${width}`);
|
|
6486
|
+
}
|
|
6487
|
+
});
|
|
6488
|
+
}
|
|
6489
|
+
}, [animate, seriesPoints, width]);
|
|
6490
|
+
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
|
|
6491
|
+
const lineClipId = "line-area-clip";
|
|
6492
|
+
return /* @__PURE__ */ jsxs197(
|
|
6493
|
+
"svg",
|
|
6494
|
+
{
|
|
6495
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
6496
|
+
className: "chart-svg",
|
|
6497
|
+
onMouseMove: (e) => {
|
|
6498
|
+
handleMouseMove(e);
|
|
6499
|
+
const svg = e.currentTarget;
|
|
6500
|
+
const rect = svg.getBoundingClientRect();
|
|
6501
|
+
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
6502
|
+
const points = seriesPoints[0];
|
|
6503
|
+
if (!points || points.length === 0) return;
|
|
6504
|
+
const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
|
|
6505
|
+
let closest = 0;
|
|
6506
|
+
let minDist = Math.abs(points[0].x - mx);
|
|
6507
|
+
for (let i = 1; i < points.length; i++) {
|
|
6508
|
+
const dist = Math.abs(points[i].x - mx);
|
|
6509
|
+
if (dist < minDist) {
|
|
6510
|
+
minDist = dist;
|
|
6511
|
+
closest = i;
|
|
6512
|
+
}
|
|
6513
|
+
}
|
|
6514
|
+
if (minDist <= step / 2) {
|
|
6515
|
+
onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
|
|
6516
|
+
} else {
|
|
6517
|
+
onLeave();
|
|
6518
|
+
}
|
|
6519
|
+
},
|
|
6520
|
+
onMouseLeave: () => {
|
|
6521
|
+
handleMouseLeave();
|
|
6522
|
+
onLeave();
|
|
6523
|
+
},
|
|
6524
|
+
children: [
|
|
6525
|
+
animate && /* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsx307("clipPath", { id: lineClipId, children: /* @__PURE__ */ jsx307("rect", { ref: clipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
|
|
6526
|
+
/* @__PURE__ */ jsx307(GridLines, { width, height, chartH, maxVal }),
|
|
6527
|
+
/* @__PURE__ */ jsx307(AxisLabels, { labels, count, chartW, height }),
|
|
6528
|
+
entries.map(([key], di) => {
|
|
6529
|
+
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
6530
|
+
const color = palette[2];
|
|
6531
|
+
const areaColor = palette[0];
|
|
6532
|
+
const points = seriesPoints[di];
|
|
6533
|
+
const gradientId = `line-gradient-${di}`;
|
|
6534
|
+
const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
|
|
6535
|
+
const areaD = `M ${points[0].x},${points[0].y} ${points.map((p) => `L ${p.x},${p.y}`).join(" ")} L ${points[points.length - 1].x},${PADDING.top + chartH} L ${points[0].x},${PADDING.top + chartH} Z`;
|
|
6536
|
+
return /* @__PURE__ */ jsxs197("g", { children: [
|
|
6537
|
+
/* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsxs197("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
6538
|
+
/* @__PURE__ */ jsx307("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
|
|
6539
|
+
/* @__PURE__ */ jsx307("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
|
|
6540
|
+
] }) }),
|
|
6541
|
+
/* @__PURE__ */ jsx307(
|
|
6542
|
+
"path",
|
|
6543
|
+
{
|
|
6544
|
+
d: areaD,
|
|
6545
|
+
fill: `url(#${gradientId})`,
|
|
6546
|
+
clipPath: animate ? `url(#${lineClipId})` : void 0
|
|
6547
|
+
}
|
|
6548
|
+
),
|
|
6549
|
+
/* @__PURE__ */ jsx307(
|
|
6550
|
+
"polyline",
|
|
6551
|
+
{
|
|
6552
|
+
ref: (el) => {
|
|
6553
|
+
lineRefs.current[di] = el;
|
|
6554
|
+
},
|
|
6555
|
+
points: polyPoints,
|
|
6556
|
+
fill: "none",
|
|
6557
|
+
stroke: color,
|
|
6558
|
+
strokeWidth: "2"
|
|
6559
|
+
}
|
|
6560
|
+
),
|
|
6561
|
+
activeIndex !== null && points[activeIndex] && /* @__PURE__ */ jsx307(
|
|
6562
|
+
"circle",
|
|
6563
|
+
{
|
|
6564
|
+
cx: points[activeIndex].x,
|
|
6565
|
+
cy: points[activeIndex].y,
|
|
6566
|
+
r: "5",
|
|
6567
|
+
fill: color,
|
|
6568
|
+
className: "chart-point-active"
|
|
6569
|
+
}
|
|
6570
|
+
)
|
|
6571
|
+
] }, di);
|
|
6572
|
+
}),
|
|
6573
|
+
activeX !== null && /* @__PURE__ */ jsx307(
|
|
6574
|
+
"line",
|
|
6471
6575
|
{
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6576
|
+
x1: activeX,
|
|
6577
|
+
y1: PADDING.top,
|
|
6578
|
+
x2: activeX,
|
|
6579
|
+
y2: PADDING.top + chartH,
|
|
6580
|
+
className: "chart-crosshair"
|
|
6476
6581
|
}
|
|
6477
6582
|
),
|
|
6478
6583
|
/* @__PURE__ */ jsx307(
|
|
6479
|
-
"
|
|
6584
|
+
"rect",
|
|
6480
6585
|
{
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
fill: "
|
|
6486
|
-
|
|
6487
|
-
strokeWidth: "2"
|
|
6586
|
+
x: PADDING.left,
|
|
6587
|
+
y: PADDING.top,
|
|
6588
|
+
width: chartW,
|
|
6589
|
+
height: chartH,
|
|
6590
|
+
fill: "transparent",
|
|
6591
|
+
style: { cursor: "crosshair" }
|
|
6488
6592
|
}
|
|
6489
|
-
)
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
cx: p.x,
|
|
6494
|
-
cy: p.y,
|
|
6495
|
-
r: "4",
|
|
6496
|
-
fill: color,
|
|
6497
|
-
className: "chart-point",
|
|
6498
|
-
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${p.v}`),
|
|
6499
|
-
onMouseMove: onMove,
|
|
6500
|
-
onMouseLeave: onLeave
|
|
6501
|
-
},
|
|
6502
|
-
i
|
|
6503
|
-
))
|
|
6504
|
-
] }, di);
|
|
6505
|
-
})
|
|
6506
|
-
] });
|
|
6593
|
+
)
|
|
6594
|
+
]
|
|
6595
|
+
}
|
|
6596
|
+
);
|
|
6507
6597
|
});
|
|
6508
6598
|
LineChart.displayName = "LineChart";
|
|
6509
6599
|
var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
@@ -6525,8 +6615,9 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
|
|
|
6525
6615
|
),
|
|
6526
6616
|
[entries, count, chartW, chartH, maxVal]
|
|
6527
6617
|
);
|
|
6528
|
-
const showPoints = count <= 100;
|
|
6529
6618
|
const lineRefs = React6.useRef([]);
|
|
6619
|
+
const curveClipRef = React6.useRef(null);
|
|
6620
|
+
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
6530
6621
|
React6.useEffect(() => {
|
|
6531
6622
|
if (!animate) return;
|
|
6532
6623
|
lineRefs.current.forEach((el) => {
|
|
@@ -6539,61 +6630,123 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
|
|
|
6539
6630
|
el.style.strokeDashoffset = "0";
|
|
6540
6631
|
});
|
|
6541
6632
|
});
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6633
|
+
if (curveClipRef.current) {
|
|
6634
|
+
curveClipRef.current.setAttribute("width", "0");
|
|
6635
|
+
requestAnimationFrame(() => {
|
|
6636
|
+
if (curveClipRef.current) {
|
|
6637
|
+
curveClipRef.current.style.transition = "width 1200ms ease-out 200ms";
|
|
6638
|
+
curveClipRef.current.setAttribute("width", `${width}`);
|
|
6639
|
+
}
|
|
6640
|
+
});
|
|
6641
|
+
}
|
|
6642
|
+
}, [animate, seriesPoints, width]);
|
|
6643
|
+
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
|
|
6644
|
+
const curveClipId = "curve-area-clip";
|
|
6645
|
+
return /* @__PURE__ */ jsxs197(
|
|
6646
|
+
"svg",
|
|
6647
|
+
{
|
|
6648
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
6649
|
+
className: "chart-svg",
|
|
6650
|
+
onMouseMove: (e) => {
|
|
6651
|
+
handleMouseMove(e);
|
|
6652
|
+
const svg = e.currentTarget;
|
|
6653
|
+
const rect = svg.getBoundingClientRect();
|
|
6654
|
+
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
6655
|
+
const points = seriesPoints[0];
|
|
6656
|
+
if (!points || points.length === 0) return;
|
|
6657
|
+
const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
|
|
6658
|
+
let closest = 0;
|
|
6659
|
+
let minDist = Math.abs(points[0].x - mx);
|
|
6660
|
+
for (let i = 1; i < points.length; i++) {
|
|
6661
|
+
const dist = Math.abs(points[i].x - mx);
|
|
6662
|
+
if (dist < minDist) {
|
|
6663
|
+
minDist = dist;
|
|
6664
|
+
closest = i;
|
|
6665
|
+
}
|
|
6666
|
+
}
|
|
6667
|
+
if (minDist <= step / 2) {
|
|
6668
|
+
onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
|
|
6669
|
+
} else {
|
|
6670
|
+
onLeave();
|
|
6671
|
+
}
|
|
6672
|
+
},
|
|
6673
|
+
onMouseLeave: () => {
|
|
6674
|
+
handleMouseLeave();
|
|
6675
|
+
onLeave();
|
|
6676
|
+
},
|
|
6677
|
+
children: [
|
|
6678
|
+
animate && /* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsx307("clipPath", { id: curveClipId, children: /* @__PURE__ */ jsx307("rect", { ref: curveClipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
|
|
6679
|
+
/* @__PURE__ */ jsx307(GridLines, { width, height, chartH, maxVal }),
|
|
6680
|
+
/* @__PURE__ */ jsx307(AxisLabels, { labels, count, chartW, height }),
|
|
6681
|
+
entries.map(([key], di) => {
|
|
6682
|
+
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
6683
|
+
const color = palette[2];
|
|
6684
|
+
const areaColor = palette[0];
|
|
6685
|
+
const points = seriesPoints[di];
|
|
6686
|
+
const gradientId = `curve-gradient-${di}`;
|
|
6687
|
+
const linePath = toSmoothPath(points);
|
|
6688
|
+
const areaPath = linePath + ` L ${points[points.length - 1].x} ${PADDING.top + chartH} L ${points[0].x} ${PADDING.top + chartH} Z`;
|
|
6689
|
+
return /* @__PURE__ */ jsxs197("g", { children: [
|
|
6690
|
+
/* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsxs197("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
6691
|
+
/* @__PURE__ */ jsx307("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
|
|
6692
|
+
/* @__PURE__ */ jsx307("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
|
|
6693
|
+
] }) }),
|
|
6694
|
+
/* @__PURE__ */ jsx307(
|
|
6695
|
+
"path",
|
|
6696
|
+
{
|
|
6697
|
+
d: areaPath,
|
|
6698
|
+
fill: `url(#${gradientId})`,
|
|
6699
|
+
clipPath: animate ? `url(#${curveClipId})` : void 0
|
|
6700
|
+
}
|
|
6701
|
+
),
|
|
6702
|
+
/* @__PURE__ */ jsx307(
|
|
6703
|
+
"path",
|
|
6704
|
+
{
|
|
6705
|
+
ref: (el) => {
|
|
6706
|
+
lineRefs.current[di] = el;
|
|
6707
|
+
},
|
|
6708
|
+
d: linePath,
|
|
6709
|
+
fill: "none",
|
|
6710
|
+
stroke: color,
|
|
6711
|
+
strokeWidth: "2"
|
|
6712
|
+
}
|
|
6713
|
+
),
|
|
6714
|
+
activeIndex !== null && points[activeIndex] && /* @__PURE__ */ jsx307(
|
|
6715
|
+
"circle",
|
|
6716
|
+
{
|
|
6717
|
+
cx: points[activeIndex].x,
|
|
6718
|
+
cy: points[activeIndex].y,
|
|
6719
|
+
r: "5",
|
|
6720
|
+
fill: color,
|
|
6721
|
+
className: "chart-point-active"
|
|
6722
|
+
}
|
|
6723
|
+
)
|
|
6724
|
+
] }, di);
|
|
6725
|
+
}),
|
|
6726
|
+
activeX !== null && /* @__PURE__ */ jsx307(
|
|
6727
|
+
"line",
|
|
6561
6728
|
{
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6729
|
+
x1: activeX,
|
|
6730
|
+
y1: PADDING.top,
|
|
6731
|
+
x2: activeX,
|
|
6732
|
+
y2: PADDING.top + chartH,
|
|
6733
|
+
className: "chart-crosshair"
|
|
6566
6734
|
}
|
|
6567
6735
|
),
|
|
6568
6736
|
/* @__PURE__ */ jsx307(
|
|
6569
|
-
"
|
|
6737
|
+
"rect",
|
|
6570
6738
|
{
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
fill: "
|
|
6576
|
-
|
|
6577
|
-
strokeWidth: "2"
|
|
6739
|
+
x: PADDING.left,
|
|
6740
|
+
y: PADDING.top,
|
|
6741
|
+
width: chartW,
|
|
6742
|
+
height: chartH,
|
|
6743
|
+
fill: "transparent",
|
|
6744
|
+
style: { cursor: "crosshair" }
|
|
6578
6745
|
}
|
|
6579
|
-
)
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
cx: p.x,
|
|
6584
|
-
cy: p.y,
|
|
6585
|
-
r: "4",
|
|
6586
|
-
fill: color,
|
|
6587
|
-
className: "chart-point",
|
|
6588
|
-
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${p.v}`),
|
|
6589
|
-
onMouseMove: onMove,
|
|
6590
|
-
onMouseLeave: onLeave
|
|
6591
|
-
},
|
|
6592
|
-
i
|
|
6593
|
-
))
|
|
6594
|
-
] }, di);
|
|
6595
|
-
})
|
|
6596
|
-
] });
|
|
6746
|
+
)
|
|
6747
|
+
]
|
|
6748
|
+
}
|
|
6749
|
+
);
|
|
6597
6750
|
});
|
|
6598
6751
|
CurveChart.displayName = "CurveChart";
|
|
6599
6752
|
var BarChart = React6.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
@@ -6758,30 +6911,70 @@ var PieDonutChart = React6.memo(
|
|
|
6758
6911
|
}
|
|
6759
6912
|
);
|
|
6760
6913
|
PieDonutChart.displayName = "PieDonutChart";
|
|
6761
|
-
var
|
|
6914
|
+
var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
|
|
6762
6915
|
const ref = React6.useRef(null);
|
|
6763
|
-
const [
|
|
6764
|
-
React6.
|
|
6916
|
+
const [pos, setPos] = React6.useState({ left: 0, top: 0 });
|
|
6917
|
+
React6.useLayoutEffect(() => {
|
|
6765
6918
|
const el = ref.current;
|
|
6766
6919
|
if (!el) return;
|
|
6767
6920
|
const w = el.offsetWidth;
|
|
6768
|
-
const
|
|
6769
|
-
const
|
|
6770
|
-
let
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6921
|
+
const h = el.offsetHeight;
|
|
6922
|
+
const vw = window.innerWidth;
|
|
6923
|
+
let left = clientX + TOOLTIP_OFFSET;
|
|
6924
|
+
let top = clientY - h - TOOLTIP_OFFSET;
|
|
6925
|
+
if (left + w > vw - 8) left = clientX - w - TOOLTIP_OFFSET;
|
|
6926
|
+
if (top < 8) top = clientY + TOOLTIP_OFFSET;
|
|
6927
|
+
if (left < 8) left = 8;
|
|
6928
|
+
setPos({ left, top });
|
|
6929
|
+
}, [clientX, clientY]);
|
|
6775
6930
|
return /* @__PURE__ */ jsx307(
|
|
6776
6931
|
"div",
|
|
6777
6932
|
{
|
|
6778
6933
|
ref,
|
|
6779
|
-
className: "chart-tooltip"
|
|
6780
|
-
style: { left:
|
|
6934
|
+
className: `chart-tooltip ${visible ? "chart-tooltip-show" : "chart-tooltip-hide"}`,
|
|
6935
|
+
style: { position: "fixed", left: pos.left, top: pos.top, zIndex: 1100 },
|
|
6781
6936
|
children
|
|
6782
6937
|
}
|
|
6783
6938
|
);
|
|
6784
6939
|
};
|
|
6940
|
+
var ChartLegend = ({ data, labels, type }) => {
|
|
6941
|
+
const entries = Object.entries(data);
|
|
6942
|
+
if (type === "pie" || type === "doughnut") {
|
|
6943
|
+
const values = entries.flatMap(([, v]) => v);
|
|
6944
|
+
const total = values.reduce((a, b) => a + b, 0) || 1;
|
|
6945
|
+
const firstKey = entries[0]?.[0] ?? "";
|
|
6946
|
+
const colorOffset = hashString(firstKey);
|
|
6947
|
+
return /* @__PURE__ */ jsx307("div", { className: "chart-legend", children: values.map((v, i) => {
|
|
6948
|
+
const pct = Math.round(v / total * 100);
|
|
6949
|
+
const color = PIE_COLORS[(i + colorOffset) % PIE_COLORS.length];
|
|
6950
|
+
return /* @__PURE__ */ jsxs197("div", { className: "chart-legend-item", children: [
|
|
6951
|
+
/* @__PURE__ */ jsx307("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
|
|
6952
|
+
/* @__PURE__ */ jsxs197("div", { className: "chart-legend-text", children: [
|
|
6953
|
+
/* @__PURE__ */ jsx307("span", { className: "chart-legend-label", children: labels[i] || `${i + 1}` }),
|
|
6954
|
+
/* @__PURE__ */ jsxs197("span", { className: "chart-legend-value", children: [
|
|
6955
|
+
v.toLocaleString(),
|
|
6956
|
+
"(",
|
|
6957
|
+
pct,
|
|
6958
|
+
"%)"
|
|
6959
|
+
] })
|
|
6960
|
+
] })
|
|
6961
|
+
] }, i);
|
|
6962
|
+
}) });
|
|
6963
|
+
}
|
|
6964
|
+
return /* @__PURE__ */ jsx307("div", { className: "chart-legend", children: entries.map(([key], di) => {
|
|
6965
|
+
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
6966
|
+
const color = palette[2];
|
|
6967
|
+
const values = entries[di][1];
|
|
6968
|
+
const sum = values.reduce((a, b) => a + b, 0);
|
|
6969
|
+
return /* @__PURE__ */ jsxs197("div", { className: "chart-legend-item", children: [
|
|
6970
|
+
/* @__PURE__ */ jsx307("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
|
|
6971
|
+
/* @__PURE__ */ jsxs197("div", { className: "chart-legend-text", children: [
|
|
6972
|
+
/* @__PURE__ */ jsx307("span", { className: "chart-legend-label", children: key }),
|
|
6973
|
+
/* @__PURE__ */ jsx307("span", { className: "chart-legend-value", children: sum.toLocaleString() })
|
|
6974
|
+
] })
|
|
6975
|
+
] }, di);
|
|
6976
|
+
}) });
|
|
6977
|
+
};
|
|
6785
6978
|
var Chart = React6.memo((props) => {
|
|
6786
6979
|
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
6787
6980
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
@@ -6797,7 +6990,8 @@ var Chart = React6.memo((props) => {
|
|
|
6797
6990
|
ready && type === "bar" && /* @__PURE__ */ jsx307(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
6798
6991
|
ready && type === "pie" && /* @__PURE__ */ jsx307(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
6799
6992
|
ready && type === "doughnut" && /* @__PURE__ */ jsx307(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
6800
|
-
|
|
6993
|
+
ready && (type === "bar" || type === "pie" || type === "doughnut") && /* @__PURE__ */ jsx307(ChartLegend, { data: stableData, labels: stableLabels, type }),
|
|
6994
|
+
tooltip.content && /* @__PURE__ */ jsx307(ChartTooltipPortal, { clientX: tooltip.clientX, clientY: tooltip.clientY, visible: tooltip.visible, children: tooltip.content })
|
|
6801
6995
|
] });
|
|
6802
6996
|
});
|
|
6803
6997
|
Chart.displayName = "Chart";
|