@x-plat/design-system 0.5.18 → 0.5.20
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 +147 -27
- package/dist/components/Chart/index.css +74 -7
- package/dist/components/Chart/index.js +147 -27
- package/dist/components/Dropdown/index.cjs +2 -0
- package/dist/components/Dropdown/index.js +2 -0
- package/dist/components/PopOver/index.cjs +2 -0
- package/dist/components/PopOver/index.css +2 -0
- package/dist/components/PopOver/index.js +2 -0
- package/dist/components/Select/index.cjs +2 -0
- package/dist/components/Select/index.js +2 -0
- package/dist/components/Skeleton/index.cjs +11 -3
- package/dist/components/Skeleton/index.d.cts +1 -1
- package/dist/components/Skeleton/index.d.ts +1 -1
- package/dist/components/Skeleton/index.js +11 -3
- package/dist/components/index.cjs +160 -30
- package/dist/components/index.css +76 -7
- package/dist/components/index.js +160 -30
- package/dist/index.cjs +180 -32
- package/dist/index.css +76 -7
- package/dist/index.js +180 -32
- package/dist/layout/Grid/FullGrid/index.cjs +10 -1
- package/dist/layout/Grid/FullGrid/index.d.cts +2 -2
- package/dist/layout/Grid/FullGrid/index.d.ts +2 -2
- package/dist/layout/Grid/FullGrid/index.js +10 -1
- package/dist/layout/Grid/FullScreen/index.cjs +10 -1
- package/dist/layout/Grid/FullScreen/index.d.cts +2 -2
- package/dist/layout/Grid/FullScreen/index.d.ts +2 -2
- package/dist/layout/Grid/FullScreen/index.js +10 -1
- package/dist/layout/Grid/index.cjs +20 -2
- package/dist/layout/Grid/index.js +20 -2
- package/dist/layout/index.cjs +20 -2
- package/dist/layout/index.js +20 -2
- package/package.json +1 -1
|
@@ -126,6 +126,37 @@ var useChartSize = (ref) => {
|
|
|
126
126
|
}, [ref]);
|
|
127
127
|
return size;
|
|
128
128
|
};
|
|
129
|
+
var prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
130
|
+
var useChartAnimation = (containerRef, dataKey) => {
|
|
131
|
+
const [animate, setAnimate] = import_react.default.useState(false);
|
|
132
|
+
const prevDataKey = import_react.default.useRef(dataKey);
|
|
133
|
+
const hasAnimated = import_react.default.useRef(false);
|
|
134
|
+
import_react.default.useEffect(() => {
|
|
135
|
+
if (prefersReducedMotion()) return;
|
|
136
|
+
const el = containerRef.current;
|
|
137
|
+
if (!el) return;
|
|
138
|
+
const observer = new IntersectionObserver(
|
|
139
|
+
([entry]) => {
|
|
140
|
+
if (entry.isIntersecting && !hasAnimated.current) {
|
|
141
|
+
hasAnimated.current = true;
|
|
142
|
+
setAnimate(true);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{ threshold: 0.1 }
|
|
146
|
+
);
|
|
147
|
+
observer.observe(el);
|
|
148
|
+
return () => observer.disconnect();
|
|
149
|
+
}, [containerRef]);
|
|
150
|
+
import_react.default.useEffect(() => {
|
|
151
|
+
if (dataKey !== prevDataKey.current) {
|
|
152
|
+
prevDataKey.current = dataKey;
|
|
153
|
+
if (prefersReducedMotion()) return;
|
|
154
|
+
setAnimate(false);
|
|
155
|
+
requestAnimationFrame(() => setAnimate(true));
|
|
156
|
+
}
|
|
157
|
+
}, [dataKey]);
|
|
158
|
+
return animate || prefersReducedMotion();
|
|
159
|
+
};
|
|
129
160
|
var useChartTooltip = (enabled) => {
|
|
130
161
|
const [tooltip, setTooltip] = import_react.default.useState({
|
|
131
162
|
visible: false,
|
|
@@ -191,7 +222,7 @@ var AxisLabels = import_react.default.memo(({ labels, count, chartW, height }) =
|
|
|
191
222
|
}) });
|
|
192
223
|
});
|
|
193
224
|
AxisLabels.displayName = "AxisLabels";
|
|
194
|
-
var LineChart = import_react.default.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
|
|
225
|
+
var LineChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
195
226
|
const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
|
|
196
227
|
const maxVal = import_react.default.useMemo(() => {
|
|
197
228
|
const allValues = entries.flatMap(([, v]) => v);
|
|
@@ -211,18 +242,52 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, onHove
|
|
|
211
242
|
[entries, count, chartW, chartH, maxVal]
|
|
212
243
|
);
|
|
213
244
|
const showPoints = count <= 100;
|
|
245
|
+
const lineRefs = import_react.default.useRef([]);
|
|
246
|
+
import_react.default.useEffect(() => {
|
|
247
|
+
if (!animate) return;
|
|
248
|
+
lineRefs.current.forEach((el) => {
|
|
249
|
+
if (!el) return;
|
|
250
|
+
const len = el.getTotalLength();
|
|
251
|
+
el.style.strokeDasharray = `${len}`;
|
|
252
|
+
el.style.strokeDashoffset = `${len}`;
|
|
253
|
+
requestAnimationFrame(() => {
|
|
254
|
+
el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
|
|
255
|
+
el.style.strokeDashoffset = "0";
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
}, [animate, seriesPoints]);
|
|
214
259
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
215
260
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GridLines, { width, height, chartH, maxVal }),
|
|
216
261
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AxisLabels, { labels, count, chartW, height }),
|
|
217
262
|
entries.map(([key], di) => {
|
|
218
263
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
219
264
|
const color = palette[2];
|
|
265
|
+
const areaColor = palette[0];
|
|
220
266
|
const points = seriesPoints[di];
|
|
267
|
+
const gradientId = `line-gradient-${di}`;
|
|
268
|
+
const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
|
|
269
|
+
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`;
|
|
221
270
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
|
|
271
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
272
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
|
|
273
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
|
|
274
|
+
] }) }),
|
|
275
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
276
|
+
"path",
|
|
277
|
+
{
|
|
278
|
+
d: areaD,
|
|
279
|
+
fill: `url(#${gradientId})`,
|
|
280
|
+
className: "chart-area",
|
|
281
|
+
style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
|
|
282
|
+
}
|
|
283
|
+
),
|
|
222
284
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
223
285
|
"polyline",
|
|
224
286
|
{
|
|
225
|
-
|
|
287
|
+
ref: (el) => {
|
|
288
|
+
lineRefs.current[di] = el;
|
|
289
|
+
},
|
|
290
|
+
points: polyPoints,
|
|
226
291
|
fill: "none",
|
|
227
292
|
stroke: color,
|
|
228
293
|
strokeWidth: "2"
|
|
@@ -247,7 +312,7 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, onHove
|
|
|
247
312
|
] });
|
|
248
313
|
});
|
|
249
314
|
LineChart.displayName = "LineChart";
|
|
250
|
-
var CurveChart = import_react.default.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
|
|
315
|
+
var CurveChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
251
316
|
const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
|
|
252
317
|
const maxVal = import_react.default.useMemo(() => {
|
|
253
318
|
const allValues = entries.flatMap(([, v]) => v);
|
|
@@ -267,6 +332,20 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, onHov
|
|
|
267
332
|
[entries, count, chartW, chartH, maxVal]
|
|
268
333
|
);
|
|
269
334
|
const showPoints = count <= 100;
|
|
335
|
+
const lineRefs = import_react.default.useRef([]);
|
|
336
|
+
import_react.default.useEffect(() => {
|
|
337
|
+
if (!animate) return;
|
|
338
|
+
lineRefs.current.forEach((el) => {
|
|
339
|
+
if (!el) return;
|
|
340
|
+
const len = el.getTotalLength();
|
|
341
|
+
el.style.strokeDasharray = `${len}`;
|
|
342
|
+
el.style.strokeDashoffset = `${len}`;
|
|
343
|
+
requestAnimationFrame(() => {
|
|
344
|
+
el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
|
|
345
|
+
el.style.strokeDashoffset = "0";
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
}, [animate, seriesPoints]);
|
|
270
349
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
271
350
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GridLines, { width, height, chartH, maxVal }),
|
|
272
351
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AxisLabels, { labels, count, chartW, height }),
|
|
@@ -283,8 +362,27 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, onHov
|
|
|
283
362
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
|
|
284
363
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
|
|
285
364
|
] }) }),
|
|
286
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
287
|
-
|
|
365
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
366
|
+
"path",
|
|
367
|
+
{
|
|
368
|
+
d: areaPath,
|
|
369
|
+
fill: `url(#${gradientId})`,
|
|
370
|
+
className: "chart-area",
|
|
371
|
+
style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
|
|
372
|
+
}
|
|
373
|
+
),
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
375
|
+
"path",
|
|
376
|
+
{
|
|
377
|
+
ref: (el) => {
|
|
378
|
+
lineRefs.current[di] = el;
|
|
379
|
+
},
|
|
380
|
+
d: linePath,
|
|
381
|
+
fill: "none",
|
|
382
|
+
stroke: color,
|
|
383
|
+
strokeWidth: "2"
|
|
384
|
+
}
|
|
385
|
+
),
|
|
288
386
|
showPoints && points.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
289
387
|
"circle",
|
|
290
388
|
{
|
|
@@ -304,7 +402,7 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, onHov
|
|
|
304
402
|
] });
|
|
305
403
|
});
|
|
306
404
|
CurveChart.displayName = "CurveChart";
|
|
307
|
-
var BarChart = import_react.default.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
|
|
405
|
+
var BarChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
308
406
|
const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
|
|
309
407
|
const maxVal = import_react.default.useMemo(() => {
|
|
310
408
|
const allValues = entries.flatMap(([, v]) => v);
|
|
@@ -317,6 +415,7 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, onHover
|
|
|
317
415
|
const groupW = chartW / count;
|
|
318
416
|
const barGap = groupCount > 1 ? 2 : 0;
|
|
319
417
|
const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
|
|
418
|
+
const baseline = PADDING.top + chartH;
|
|
320
419
|
const bars = import_react.default.useMemo(
|
|
321
420
|
() => entries.map(
|
|
322
421
|
([, values], di) => values.map((v, i) => {
|
|
@@ -342,12 +441,17 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, onHover
|
|
|
342
441
|
return bars[di].map((b, i) => {
|
|
343
442
|
const r = Math.min(4, b.w / 2);
|
|
344
443
|
const d = b.h <= r ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r} Q ${b.x} ${b.y} ${b.x + r} ${b.y} H ${b.x + b.w - r} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r} V ${b.y + b.h} Z`;
|
|
444
|
+
const delay = 100 + i * 80;
|
|
345
445
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
346
446
|
"path",
|
|
347
447
|
{
|
|
348
448
|
d,
|
|
349
449
|
fill: color,
|
|
350
|
-
className: "chart-bar"
|
|
450
|
+
className: `chart-bar ${animate ? "chart-bar-animate" : ""}`,
|
|
451
|
+
style: animate ? {
|
|
452
|
+
transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
|
|
453
|
+
animationDelay: `${delay}ms`
|
|
454
|
+
} : void 0,
|
|
351
455
|
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
|
|
352
456
|
onMouseMove: onMove,
|
|
353
457
|
onMouseLeave: onLeave
|
|
@@ -360,7 +464,7 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, onHover
|
|
|
360
464
|
});
|
|
361
465
|
BarChart.displayName = "BarChart";
|
|
362
466
|
var PieDonutChart = import_react.default.memo(
|
|
363
|
-
({ data, labels, width, height, isDoughnut, onHover, onMove, onLeave }) => {
|
|
467
|
+
({ data, labels, width, height, animate, isDoughnut, onHover, onMove, onLeave }) => {
|
|
364
468
|
const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
|
|
365
469
|
const values = import_react.default.useMemo(() => entries.flatMap(([, v]) => v), [entries]);
|
|
366
470
|
const total = import_react.default.useMemo(() => values.reduce((a, b) => a + b, 0) || 1, [values]);
|
|
@@ -400,20 +504,34 @@ var PieDonutChart = import_react.default.memo(
|
|
|
400
504
|
return { d, lx, ly, v, pct, angle, label: labels[i] || `${i + 1}` };
|
|
401
505
|
});
|
|
402
506
|
}, [values, total, cx, cy, r, innerR, labels]);
|
|
403
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: sliceData.map((s, i) =>
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
507
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: sliceData.map((s, i) => {
|
|
508
|
+
const delay = i * 100;
|
|
509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { className: animate ? "chart-slice-group-animate" : "", style: animate ? { animationDelay: `${delay}ms` } : void 0, children: [
|
|
510
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
511
|
+
"path",
|
|
512
|
+
{
|
|
513
|
+
d: s.d,
|
|
514
|
+
fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
|
|
515
|
+
className: "chart-slice",
|
|
516
|
+
onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
|
|
517
|
+
onMouseMove: onMove,
|
|
518
|
+
onMouseLeave: onLeave
|
|
519
|
+
}
|
|
520
|
+
),
|
|
521
|
+
s.angle > 0.2 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
522
|
+
"text",
|
|
523
|
+
{
|
|
524
|
+
x: s.lx,
|
|
525
|
+
y: s.ly,
|
|
526
|
+
className: `chart-pie-label ${animate ? "chart-pie-label-animate" : ""}`,
|
|
527
|
+
style: animate ? { animationDelay: `${delay + 150}ms` } : void 0,
|
|
528
|
+
textAnchor: "middle",
|
|
529
|
+
dominantBaseline: "central",
|
|
530
|
+
children: s.v
|
|
531
|
+
}
|
|
532
|
+
)
|
|
533
|
+
] }, i);
|
|
534
|
+
}) });
|
|
417
535
|
}
|
|
418
536
|
);
|
|
419
537
|
PieDonutChart.displayName = "PieDonutChart";
|
|
@@ -447,13 +565,15 @@ var Chart = import_react.default.memo((props) => {
|
|
|
447
565
|
const { width, height } = useChartSize(containerRef);
|
|
448
566
|
const stableData = import_react.default.useMemo(() => data, [JSON.stringify(data)]);
|
|
449
567
|
const stableLabels = import_react.default.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
568
|
+
const dataKey = import_react.default.useMemo(() => JSON.stringify(labels), [labels]);
|
|
569
|
+
const animate = useChartAnimation(containerRef, dataKey);
|
|
450
570
|
const ready = width > 0 && height > 0;
|
|
451
571
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
452
|
-
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
453
|
-
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
454
|
-
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
455
|
-
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
456
|
-
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
572
|
+
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
573
|
+
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
574
|
+
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
575
|
+
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
576
|
+
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
457
577
|
tooltip.visible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
|
|
458
578
|
] });
|
|
459
579
|
});
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
font-weight: 600;
|
|
26
26
|
fill: var(--semantic-text-inverse);
|
|
27
27
|
pointer-events: none;
|
|
28
|
+
opacity: 1;
|
|
28
29
|
}
|
|
29
30
|
.lib-xplat-chart .chart-pie {
|
|
30
31
|
max-width: 300px;
|
|
@@ -34,10 +35,10 @@
|
|
|
34
35
|
cursor: pointer;
|
|
35
36
|
r: 0;
|
|
36
37
|
opacity: 0;
|
|
37
|
-
transition: r 0.15s, opacity 0.15s;
|
|
38
|
+
transition: r 0.15s ease-out, opacity 0.15s ease-out;
|
|
38
39
|
}
|
|
39
40
|
.lib-xplat-chart .chart-point:hover {
|
|
40
|
-
r:
|
|
41
|
+
r: 6;
|
|
41
42
|
opacity: 1;
|
|
42
43
|
}
|
|
43
44
|
.lib-xplat-chart .chart-svg:hover .chart-point {
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
}
|
|
47
48
|
.lib-xplat-chart .chart-bar {
|
|
48
49
|
cursor: pointer;
|
|
49
|
-
transition: opacity 0.15s, filter 0.15s;
|
|
50
|
+
transition: opacity 0.15s ease-out, filter 0.15s ease-out;
|
|
50
51
|
}
|
|
51
52
|
.lib-xplat-chart .chart-bar:hover {
|
|
52
53
|
opacity: 0.85;
|
|
@@ -57,15 +58,22 @@
|
|
|
57
58
|
stroke: var(--semantic-surface-neutral-default);
|
|
58
59
|
stroke-width: 2;
|
|
59
60
|
transition:
|
|
60
|
-
opacity 0.15s,
|
|
61
|
-
filter 0.15s,
|
|
62
|
-
transform 0.15s;
|
|
61
|
+
opacity 0.15s ease-out,
|
|
62
|
+
filter 0.15s ease-out,
|
|
63
|
+
transform 0.15s ease-out;
|
|
63
64
|
transform-origin: center;
|
|
64
65
|
}
|
|
66
|
+
.lib-xplat-chart .chart-svg:hover .chart-slice {
|
|
67
|
+
opacity: 0.5;
|
|
68
|
+
}
|
|
65
69
|
.lib-xplat-chart .chart-slice:hover {
|
|
66
|
-
opacity:
|
|
70
|
+
opacity: 1 !important;
|
|
71
|
+
transform: scale(1.03);
|
|
67
72
|
filter: brightness(1.05) drop-shadow(0 2px 6px rgba(0, 0, 0, 0.2));
|
|
68
73
|
}
|
|
74
|
+
.lib-xplat-chart .chart-area {
|
|
75
|
+
opacity: 1;
|
|
76
|
+
}
|
|
69
77
|
.lib-xplat-chart .chart-tooltip {
|
|
70
78
|
position: absolute;
|
|
71
79
|
transform: translate(-50%, -100%);
|
|
@@ -78,4 +86,63 @@
|
|
|
78
86
|
white-space: nowrap;
|
|
79
87
|
pointer-events: none;
|
|
80
88
|
z-index: 10;
|
|
89
|
+
animation: chart-tooltip-in 150ms ease-out;
|
|
90
|
+
}
|
|
91
|
+
.lib-xplat-chart .chart-bar-animate {
|
|
92
|
+
animation: chart-bar-grow 800ms ease-out both;
|
|
93
|
+
}
|
|
94
|
+
.lib-xplat-chart .chart-slice-group-animate {
|
|
95
|
+
animation: chart-slice-in 1000ms ease-out both;
|
|
96
|
+
}
|
|
97
|
+
.lib-xplat-chart .chart-pie-label-animate {
|
|
98
|
+
animation: chart-fade-in 150ms ease-out both;
|
|
99
|
+
}
|
|
100
|
+
.lib-xplat-chart .chart-area[style*=animationDelay] {
|
|
101
|
+
animation: chart-fade-in 800ms ease-out both;
|
|
102
|
+
}
|
|
103
|
+
@keyframes chart-bar-grow {
|
|
104
|
+
from {
|
|
105
|
+
transform: scaleY(0);
|
|
106
|
+
}
|
|
107
|
+
to {
|
|
108
|
+
transform: scaleY(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
@keyframes chart-slice-in {
|
|
112
|
+
from {
|
|
113
|
+
opacity: 0;
|
|
114
|
+
transform: scale(0.8);
|
|
115
|
+
}
|
|
116
|
+
to {
|
|
117
|
+
opacity: 1;
|
|
118
|
+
transform: scale(1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
@keyframes chart-fade-in {
|
|
122
|
+
from {
|
|
123
|
+
opacity: 0;
|
|
124
|
+
}
|
|
125
|
+
to {
|
|
126
|
+
opacity: 1;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
@keyframes chart-tooltip-in {
|
|
130
|
+
from {
|
|
131
|
+
opacity: 0;
|
|
132
|
+
transform: translate(-50%, -90%);
|
|
133
|
+
}
|
|
134
|
+
to {
|
|
135
|
+
opacity: 1;
|
|
136
|
+
transform: translate(-50%, -100%);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
@media (prefers-reduced-motion: reduce) {
|
|
140
|
+
.lib-xplat-chart .chart-bar-animate,
|
|
141
|
+
.lib-xplat-chart .chart-slice-group-animate,
|
|
142
|
+
.lib-xplat-chart .chart-pie-label-animate,
|
|
143
|
+
.lib-xplat-chart .chart-area {
|
|
144
|
+
animation: none !important;
|
|
145
|
+
opacity: 1 !important;
|
|
146
|
+
transform: none !important;
|
|
147
|
+
}
|
|
81
148
|
}
|
|
@@ -90,6 +90,37 @@ var useChartSize = (ref) => {
|
|
|
90
90
|
}, [ref]);
|
|
91
91
|
return size;
|
|
92
92
|
};
|
|
93
|
+
var prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
94
|
+
var useChartAnimation = (containerRef, dataKey) => {
|
|
95
|
+
const [animate, setAnimate] = React.useState(false);
|
|
96
|
+
const prevDataKey = React.useRef(dataKey);
|
|
97
|
+
const hasAnimated = React.useRef(false);
|
|
98
|
+
React.useEffect(() => {
|
|
99
|
+
if (prefersReducedMotion()) return;
|
|
100
|
+
const el = containerRef.current;
|
|
101
|
+
if (!el) return;
|
|
102
|
+
const observer = new IntersectionObserver(
|
|
103
|
+
([entry]) => {
|
|
104
|
+
if (entry.isIntersecting && !hasAnimated.current) {
|
|
105
|
+
hasAnimated.current = true;
|
|
106
|
+
setAnimate(true);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{ threshold: 0.1 }
|
|
110
|
+
);
|
|
111
|
+
observer.observe(el);
|
|
112
|
+
return () => observer.disconnect();
|
|
113
|
+
}, [containerRef]);
|
|
114
|
+
React.useEffect(() => {
|
|
115
|
+
if (dataKey !== prevDataKey.current) {
|
|
116
|
+
prevDataKey.current = dataKey;
|
|
117
|
+
if (prefersReducedMotion()) return;
|
|
118
|
+
setAnimate(false);
|
|
119
|
+
requestAnimationFrame(() => setAnimate(true));
|
|
120
|
+
}
|
|
121
|
+
}, [dataKey]);
|
|
122
|
+
return animate || prefersReducedMotion();
|
|
123
|
+
};
|
|
93
124
|
var useChartTooltip = (enabled) => {
|
|
94
125
|
const [tooltip, setTooltip] = React.useState({
|
|
95
126
|
visible: false,
|
|
@@ -155,7 +186,7 @@ var AxisLabels = React.memo(({ labels, count, chartW, height }) => {
|
|
|
155
186
|
}) });
|
|
156
187
|
});
|
|
157
188
|
AxisLabels.displayName = "AxisLabels";
|
|
158
|
-
var LineChart = React.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
|
|
189
|
+
var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
159
190
|
const entries = React.useMemo(() => Object.entries(data), [data]);
|
|
160
191
|
const maxVal = React.useMemo(() => {
|
|
161
192
|
const allValues = entries.flatMap(([, v]) => v);
|
|
@@ -175,18 +206,52 @@ var LineChart = React.memo(({ data, labels, width, height, onHover, onMove, onLe
|
|
|
175
206
|
[entries, count, chartW, chartH, maxVal]
|
|
176
207
|
);
|
|
177
208
|
const showPoints = count <= 100;
|
|
209
|
+
const lineRefs = React.useRef([]);
|
|
210
|
+
React.useEffect(() => {
|
|
211
|
+
if (!animate) return;
|
|
212
|
+
lineRefs.current.forEach((el) => {
|
|
213
|
+
if (!el) return;
|
|
214
|
+
const len = el.getTotalLength();
|
|
215
|
+
el.style.strokeDasharray = `${len}`;
|
|
216
|
+
el.style.strokeDashoffset = `${len}`;
|
|
217
|
+
requestAnimationFrame(() => {
|
|
218
|
+
el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
|
|
219
|
+
el.style.strokeDashoffset = "0";
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
}, [animate, seriesPoints]);
|
|
178
223
|
return /* @__PURE__ */ jsxs("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
179
224
|
/* @__PURE__ */ jsx(GridLines, { width, height, chartH, maxVal }),
|
|
180
225
|
/* @__PURE__ */ jsx(AxisLabels, { labels, count, chartW, height }),
|
|
181
226
|
entries.map(([key], di) => {
|
|
182
227
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
183
228
|
const color = palette[2];
|
|
229
|
+
const areaColor = palette[0];
|
|
184
230
|
const points = seriesPoints[di];
|
|
231
|
+
const gradientId = `line-gradient-${di}`;
|
|
232
|
+
const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
|
|
233
|
+
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`;
|
|
185
234
|
return /* @__PURE__ */ jsxs("g", { children: [
|
|
235
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
236
|
+
/* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
|
|
237
|
+
/* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
|
|
238
|
+
] }) }),
|
|
239
|
+
/* @__PURE__ */ jsx(
|
|
240
|
+
"path",
|
|
241
|
+
{
|
|
242
|
+
d: areaD,
|
|
243
|
+
fill: `url(#${gradientId})`,
|
|
244
|
+
className: "chart-area",
|
|
245
|
+
style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
|
|
246
|
+
}
|
|
247
|
+
),
|
|
186
248
|
/* @__PURE__ */ jsx(
|
|
187
249
|
"polyline",
|
|
188
250
|
{
|
|
189
|
-
|
|
251
|
+
ref: (el) => {
|
|
252
|
+
lineRefs.current[di] = el;
|
|
253
|
+
},
|
|
254
|
+
points: polyPoints,
|
|
190
255
|
fill: "none",
|
|
191
256
|
stroke: color,
|
|
192
257
|
strokeWidth: "2"
|
|
@@ -211,7 +276,7 @@ var LineChart = React.memo(({ data, labels, width, height, onHover, onMove, onLe
|
|
|
211
276
|
] });
|
|
212
277
|
});
|
|
213
278
|
LineChart.displayName = "LineChart";
|
|
214
|
-
var CurveChart = React.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
|
|
279
|
+
var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
215
280
|
const entries = React.useMemo(() => Object.entries(data), [data]);
|
|
216
281
|
const maxVal = React.useMemo(() => {
|
|
217
282
|
const allValues = entries.flatMap(([, v]) => v);
|
|
@@ -231,6 +296,20 @@ var CurveChart = React.memo(({ data, labels, width, height, onHover, onMove, onL
|
|
|
231
296
|
[entries, count, chartW, chartH, maxVal]
|
|
232
297
|
);
|
|
233
298
|
const showPoints = count <= 100;
|
|
299
|
+
const lineRefs = React.useRef([]);
|
|
300
|
+
React.useEffect(() => {
|
|
301
|
+
if (!animate) return;
|
|
302
|
+
lineRefs.current.forEach((el) => {
|
|
303
|
+
if (!el) return;
|
|
304
|
+
const len = el.getTotalLength();
|
|
305
|
+
el.style.strokeDasharray = `${len}`;
|
|
306
|
+
el.style.strokeDashoffset = `${len}`;
|
|
307
|
+
requestAnimationFrame(() => {
|
|
308
|
+
el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
|
|
309
|
+
el.style.strokeDashoffset = "0";
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
}, [animate, seriesPoints]);
|
|
234
313
|
return /* @__PURE__ */ jsxs("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
235
314
|
/* @__PURE__ */ jsx(GridLines, { width, height, chartH, maxVal }),
|
|
236
315
|
/* @__PURE__ */ jsx(AxisLabels, { labels, count, chartW, height }),
|
|
@@ -247,8 +326,27 @@ var CurveChart = React.memo(({ data, labels, width, height, onHover, onMove, onL
|
|
|
247
326
|
/* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
|
|
248
327
|
/* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
|
|
249
328
|
] }) }),
|
|
250
|
-
/* @__PURE__ */ jsx(
|
|
251
|
-
|
|
329
|
+
/* @__PURE__ */ jsx(
|
|
330
|
+
"path",
|
|
331
|
+
{
|
|
332
|
+
d: areaPath,
|
|
333
|
+
fill: `url(#${gradientId})`,
|
|
334
|
+
className: "chart-area",
|
|
335
|
+
style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
|
|
336
|
+
}
|
|
337
|
+
),
|
|
338
|
+
/* @__PURE__ */ jsx(
|
|
339
|
+
"path",
|
|
340
|
+
{
|
|
341
|
+
ref: (el) => {
|
|
342
|
+
lineRefs.current[di] = el;
|
|
343
|
+
},
|
|
344
|
+
d: linePath,
|
|
345
|
+
fill: "none",
|
|
346
|
+
stroke: color,
|
|
347
|
+
strokeWidth: "2"
|
|
348
|
+
}
|
|
349
|
+
),
|
|
252
350
|
showPoints && points.map((p, i) => /* @__PURE__ */ jsx(
|
|
253
351
|
"circle",
|
|
254
352
|
{
|
|
@@ -268,7 +366,7 @@ var CurveChart = React.memo(({ data, labels, width, height, onHover, onMove, onL
|
|
|
268
366
|
] });
|
|
269
367
|
});
|
|
270
368
|
CurveChart.displayName = "CurveChart";
|
|
271
|
-
var BarChart = React.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
|
|
369
|
+
var BarChart = React.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
272
370
|
const entries = React.useMemo(() => Object.entries(data), [data]);
|
|
273
371
|
const maxVal = React.useMemo(() => {
|
|
274
372
|
const allValues = entries.flatMap(([, v]) => v);
|
|
@@ -281,6 +379,7 @@ var BarChart = React.memo(({ data, labels, width, height, onHover, onMove, onLea
|
|
|
281
379
|
const groupW = chartW / count;
|
|
282
380
|
const barGap = groupCount > 1 ? 2 : 0;
|
|
283
381
|
const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
|
|
382
|
+
const baseline = PADDING.top + chartH;
|
|
284
383
|
const bars = React.useMemo(
|
|
285
384
|
() => entries.map(
|
|
286
385
|
([, values], di) => values.map((v, i) => {
|
|
@@ -306,12 +405,17 @@ var BarChart = React.memo(({ data, labels, width, height, onHover, onMove, onLea
|
|
|
306
405
|
return bars[di].map((b, i) => {
|
|
307
406
|
const r = Math.min(4, b.w / 2);
|
|
308
407
|
const d = b.h <= r ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r} Q ${b.x} ${b.y} ${b.x + r} ${b.y} H ${b.x + b.w - r} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r} V ${b.y + b.h} Z`;
|
|
408
|
+
const delay = 100 + i * 80;
|
|
309
409
|
return /* @__PURE__ */ jsx(
|
|
310
410
|
"path",
|
|
311
411
|
{
|
|
312
412
|
d,
|
|
313
413
|
fill: color,
|
|
314
|
-
className: "chart-bar"
|
|
414
|
+
className: `chart-bar ${animate ? "chart-bar-animate" : ""}`,
|
|
415
|
+
style: animate ? {
|
|
416
|
+
transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
|
|
417
|
+
animationDelay: `${delay}ms`
|
|
418
|
+
} : void 0,
|
|
315
419
|
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
|
|
316
420
|
onMouseMove: onMove,
|
|
317
421
|
onMouseLeave: onLeave
|
|
@@ -324,7 +428,7 @@ var BarChart = React.memo(({ data, labels, width, height, onHover, onMove, onLea
|
|
|
324
428
|
});
|
|
325
429
|
BarChart.displayName = "BarChart";
|
|
326
430
|
var PieDonutChart = React.memo(
|
|
327
|
-
({ data, labels, width, height, isDoughnut, onHover, onMove, onLeave }) => {
|
|
431
|
+
({ data, labels, width, height, animate, isDoughnut, onHover, onMove, onLeave }) => {
|
|
328
432
|
const entries = React.useMemo(() => Object.entries(data), [data]);
|
|
329
433
|
const values = React.useMemo(() => entries.flatMap(([, v]) => v), [entries]);
|
|
330
434
|
const total = React.useMemo(() => values.reduce((a, b) => a + b, 0) || 1, [values]);
|
|
@@ -364,20 +468,34 @@ var PieDonutChart = React.memo(
|
|
|
364
468
|
return { d, lx, ly, v, pct, angle, label: labels[i] || `${i + 1}` };
|
|
365
469
|
});
|
|
366
470
|
}, [values, total, cx, cy, r, innerR, labels]);
|
|
367
|
-
return /* @__PURE__ */ jsx("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: sliceData.map((s, i) =>
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
471
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: sliceData.map((s, i) => {
|
|
472
|
+
const delay = i * 100;
|
|
473
|
+
return /* @__PURE__ */ jsxs("g", { className: animate ? "chart-slice-group-animate" : "", style: animate ? { animationDelay: `${delay}ms` } : void 0, children: [
|
|
474
|
+
/* @__PURE__ */ jsx(
|
|
475
|
+
"path",
|
|
476
|
+
{
|
|
477
|
+
d: s.d,
|
|
478
|
+
fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
|
|
479
|
+
className: "chart-slice",
|
|
480
|
+
onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
|
|
481
|
+
onMouseMove: onMove,
|
|
482
|
+
onMouseLeave: onLeave
|
|
483
|
+
}
|
|
484
|
+
),
|
|
485
|
+
s.angle > 0.2 && /* @__PURE__ */ jsx(
|
|
486
|
+
"text",
|
|
487
|
+
{
|
|
488
|
+
x: s.lx,
|
|
489
|
+
y: s.ly,
|
|
490
|
+
className: `chart-pie-label ${animate ? "chart-pie-label-animate" : ""}`,
|
|
491
|
+
style: animate ? { animationDelay: `${delay + 150}ms` } : void 0,
|
|
492
|
+
textAnchor: "middle",
|
|
493
|
+
dominantBaseline: "central",
|
|
494
|
+
children: s.v
|
|
495
|
+
}
|
|
496
|
+
)
|
|
497
|
+
] }, i);
|
|
498
|
+
}) });
|
|
381
499
|
}
|
|
382
500
|
);
|
|
383
501
|
PieDonutChart.displayName = "PieDonutChart";
|
|
@@ -411,13 +529,15 @@ var Chart = React.memo((props) => {
|
|
|
411
529
|
const { width, height } = useChartSize(containerRef);
|
|
412
530
|
const stableData = React.useMemo(() => data, [JSON.stringify(data)]);
|
|
413
531
|
const stableLabels = React.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
532
|
+
const dataKey = React.useMemo(() => JSON.stringify(labels), [labels]);
|
|
533
|
+
const animate = useChartAnimation(containerRef, dataKey);
|
|
414
534
|
const ready = width > 0 && height > 0;
|
|
415
535
|
return /* @__PURE__ */ jsxs("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
416
|
-
ready && type === "line" && /* @__PURE__ */ jsx(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
417
|
-
ready && type === "curve" && /* @__PURE__ */ jsx(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
418
|
-
ready && type === "bar" && /* @__PURE__ */ jsx(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
419
|
-
ready && type === "pie" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
|
|
420
|
-
ready && type === "doughnut" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
536
|
+
ready && type === "line" && /* @__PURE__ */ jsx(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
537
|
+
ready && type === "curve" && /* @__PURE__ */ jsx(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
538
|
+
ready && type === "bar" && /* @__PURE__ */ jsx(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
539
|
+
ready && type === "pie" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
540
|
+
ready && type === "doughnut" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
421
541
|
tooltip.visible && /* @__PURE__ */ jsx(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
|
|
422
542
|
] });
|
|
423
543
|
});
|