@x-plat/design-system 0.5.32 → 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 +121 -61
- package/dist/components/Chart/index.css +54 -10
- package/dist/components/Chart/index.js +121 -61
- package/dist/components/index.cjs +121 -61
- package/dist/components/index.css +54 -10
- package/dist/components/index.js +121 -61
- package/dist/index.cjs +121 -61
- package/dist/index.css +54 -10
- package/dist/index.js +121 -61
- package/package.json +1 -1
|
@@ -157,40 +157,28 @@ var useChartAnimation = (containerRef, dataKey) => {
|
|
|
157
157
|
}, [dataKey]);
|
|
158
158
|
return animate || prefersReducedMotion();
|
|
159
159
|
};
|
|
160
|
+
var TOOLTIP_OFFSET = 12;
|
|
160
161
|
var useChartTooltip = (enabled) => {
|
|
161
162
|
const [tooltip, setTooltip] = import_react.default.useState({
|
|
162
163
|
visible: false,
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
clientX: 0,
|
|
165
|
+
clientY: 0,
|
|
165
166
|
content: ""
|
|
166
167
|
});
|
|
167
168
|
const containerRef = import_react.default.useRef(null);
|
|
168
169
|
const rafRef = import_react.default.useRef(0);
|
|
169
170
|
const move = import_react.default.useCallback((e) => {
|
|
170
171
|
if (!enabled) return;
|
|
171
|
-
const
|
|
172
|
-
const
|
|
172
|
+
const cx = e.clientX;
|
|
173
|
+
const cy = e.clientY;
|
|
173
174
|
cancelAnimationFrame(rafRef.current);
|
|
174
175
|
rafRef.current = requestAnimationFrame(() => {
|
|
175
|
-
|
|
176
|
-
if (!rect) return;
|
|
177
|
-
setTooltip((prev) => ({
|
|
178
|
-
...prev,
|
|
179
|
-
x: clientX - rect.left,
|
|
180
|
-
y: clientY - rect.top - 12
|
|
181
|
-
}));
|
|
176
|
+
setTooltip((prev) => ({ ...prev, clientX: cx, clientY: cy }));
|
|
182
177
|
});
|
|
183
178
|
}, [enabled]);
|
|
184
179
|
const show = import_react.default.useCallback((e, content) => {
|
|
185
180
|
if (!enabled) return;
|
|
186
|
-
|
|
187
|
-
if (!rect) return;
|
|
188
|
-
setTooltip({
|
|
189
|
-
visible: true,
|
|
190
|
-
x: e.clientX - rect.left,
|
|
191
|
-
y: e.clientY - rect.top - 12,
|
|
192
|
-
content
|
|
193
|
-
});
|
|
181
|
+
setTooltip({ visible: true, clientX: e.clientX, clientY: e.clientY, content });
|
|
194
182
|
}, [enabled]);
|
|
195
183
|
const hide = import_react.default.useCallback(() => {
|
|
196
184
|
cancelAnimationFrame(rafRef.current);
|
|
@@ -224,14 +212,14 @@ var AxisLabels = import_react.default.memo(({ labels, count, chartW, height }) =
|
|
|
224
212
|
AxisLabels.displayName = "AxisLabels";
|
|
225
213
|
var useCrosshair = (seriesPoints, entries, labels, chartH) => {
|
|
226
214
|
const [activeIndex, setActiveIndex] = import_react.default.useState(null);
|
|
227
|
-
const [mouseX, setMouseX] = import_react.default.useState(null);
|
|
228
215
|
const handleMouseMove = import_react.default.useCallback((e) => {
|
|
229
216
|
const svg = e.currentTarget;
|
|
230
217
|
const rect = svg.getBoundingClientRect();
|
|
231
218
|
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
232
|
-
setMouseX(mx);
|
|
233
219
|
if (seriesPoints.length === 0 || seriesPoints[0].length === 0) return;
|
|
234
220
|
const points = seriesPoints[0];
|
|
221
|
+
const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
|
|
222
|
+
const threshold = step / 2;
|
|
235
223
|
let closest = 0;
|
|
236
224
|
let minDist = Math.abs(points[0].x - mx);
|
|
237
225
|
for (let i = 1; i < points.length; i++) {
|
|
@@ -241,11 +229,10 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
|
|
|
241
229
|
closest = i;
|
|
242
230
|
}
|
|
243
231
|
}
|
|
244
|
-
setActiveIndex(closest);
|
|
232
|
+
setActiveIndex(minDist <= threshold ? closest : null);
|
|
245
233
|
}, [seriesPoints]);
|
|
246
234
|
const handleMouseLeave = import_react.default.useCallback(() => {
|
|
247
235
|
setActiveIndex(null);
|
|
248
|
-
setMouseX(null);
|
|
249
236
|
}, []);
|
|
250
237
|
const tooltipContent = import_react.default.useMemo(() => {
|
|
251
238
|
if (activeIndex === null) return "";
|
|
@@ -254,7 +241,13 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
|
|
|
254
241
|
return p ? `${key}: ${p.v}` : "";
|
|
255
242
|
}).filter(Boolean).join(" / ");
|
|
256
243
|
}, [activeIndex, entries, seriesPoints]);
|
|
257
|
-
|
|
244
|
+
const getTooltipAt = import_react.default.useCallback((idx) => {
|
|
245
|
+
return entries.map(([key], di) => {
|
|
246
|
+
const p = seriesPoints[di]?.[idx];
|
|
247
|
+
return p ? `${key}: ${p.v}` : "";
|
|
248
|
+
}).filter(Boolean).join(" / ");
|
|
249
|
+
}, [entries, seriesPoints]);
|
|
250
|
+
return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
|
|
258
251
|
};
|
|
259
252
|
var LineChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
260
253
|
const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
|
|
@@ -277,7 +270,7 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
|
|
|
277
270
|
);
|
|
278
271
|
const lineRefs = import_react.default.useRef([]);
|
|
279
272
|
const clipRef = import_react.default.useRef(null);
|
|
280
|
-
const { activeIndex,
|
|
273
|
+
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
281
274
|
import_react.default.useEffect(() => {
|
|
282
275
|
if (!animate) return;
|
|
283
276
|
lineRefs.current.forEach((el) => {
|
|
@@ -300,8 +293,7 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
|
|
|
300
293
|
});
|
|
301
294
|
}
|
|
302
295
|
}, [animate, seriesPoints, width]);
|
|
303
|
-
const
|
|
304
|
-
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x : null;
|
|
296
|
+
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
|
|
305
297
|
const lineClipId = "line-area-clip";
|
|
306
298
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
307
299
|
"svg",
|
|
@@ -310,7 +302,26 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
|
|
|
310
302
|
className: "chart-svg",
|
|
311
303
|
onMouseMove: (e) => {
|
|
312
304
|
handleMouseMove(e);
|
|
313
|
-
|
|
305
|
+
const svg = e.currentTarget;
|
|
306
|
+
const rect = svg.getBoundingClientRect();
|
|
307
|
+
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
308
|
+
const points = seriesPoints[0];
|
|
309
|
+
if (!points || points.length === 0) return;
|
|
310
|
+
const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
|
|
311
|
+
let closest = 0;
|
|
312
|
+
let minDist = Math.abs(points[0].x - mx);
|
|
313
|
+
for (let i = 1; i < points.length; i++) {
|
|
314
|
+
const dist = Math.abs(points[i].x - mx);
|
|
315
|
+
if (dist < minDist) {
|
|
316
|
+
minDist = dist;
|
|
317
|
+
closest = i;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (minDist <= step / 2) {
|
|
321
|
+
onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
|
|
322
|
+
} else {
|
|
323
|
+
onLeave();
|
|
324
|
+
}
|
|
314
325
|
},
|
|
315
326
|
onMouseLeave: () => {
|
|
316
327
|
handleMouseLeave();
|
|
@@ -365,21 +376,16 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
|
|
|
365
376
|
)
|
|
366
377
|
] }, di);
|
|
367
378
|
}),
|
|
368
|
-
|
|
379
|
+
activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
369
380
|
"line",
|
|
370
381
|
{
|
|
371
|
-
x1:
|
|
382
|
+
x1: activeX,
|
|
372
383
|
y1: PADDING.top,
|
|
373
|
-
x2:
|
|
384
|
+
x2: activeX,
|
|
374
385
|
y2: PADDING.top + chartH,
|
|
375
386
|
className: "chart-crosshair"
|
|
376
387
|
}
|
|
377
388
|
),
|
|
378
|
-
activeIndex !== null && activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("foreignObject", { x: activeX - 100, y: 0, width: "200", height: PADDING.top, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-crosshair-label", children: [
|
|
379
|
-
labels[activeIndex],
|
|
380
|
-
" \u2014 ",
|
|
381
|
-
tooltipContent
|
|
382
|
-
] }) }),
|
|
383
389
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
384
390
|
"rect",
|
|
385
391
|
{
|
|
@@ -417,7 +423,7 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
|
|
|
417
423
|
);
|
|
418
424
|
const lineRefs = import_react.default.useRef([]);
|
|
419
425
|
const curveClipRef = import_react.default.useRef(null);
|
|
420
|
-
const { activeIndex,
|
|
426
|
+
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
421
427
|
import_react.default.useEffect(() => {
|
|
422
428
|
if (!animate) return;
|
|
423
429
|
lineRefs.current.forEach((el) => {
|
|
@@ -440,8 +446,7 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
|
|
|
440
446
|
});
|
|
441
447
|
}
|
|
442
448
|
}, [animate, seriesPoints, width]);
|
|
443
|
-
const
|
|
444
|
-
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x : null;
|
|
449
|
+
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
|
|
445
450
|
const curveClipId = "curve-area-clip";
|
|
446
451
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
447
452
|
"svg",
|
|
@@ -450,7 +455,26 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
|
|
|
450
455
|
className: "chart-svg",
|
|
451
456
|
onMouseMove: (e) => {
|
|
452
457
|
handleMouseMove(e);
|
|
453
|
-
|
|
458
|
+
const svg = e.currentTarget;
|
|
459
|
+
const rect = svg.getBoundingClientRect();
|
|
460
|
+
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
461
|
+
const points = seriesPoints[0];
|
|
462
|
+
if (!points || points.length === 0) return;
|
|
463
|
+
const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
|
|
464
|
+
let closest = 0;
|
|
465
|
+
let minDist = Math.abs(points[0].x - mx);
|
|
466
|
+
for (let i = 1; i < points.length; i++) {
|
|
467
|
+
const dist = Math.abs(points[i].x - mx);
|
|
468
|
+
if (dist < minDist) {
|
|
469
|
+
minDist = dist;
|
|
470
|
+
closest = i;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (minDist <= step / 2) {
|
|
474
|
+
onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
|
|
475
|
+
} else {
|
|
476
|
+
onLeave();
|
|
477
|
+
}
|
|
454
478
|
},
|
|
455
479
|
onMouseLeave: () => {
|
|
456
480
|
handleMouseLeave();
|
|
@@ -505,21 +529,16 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
|
|
|
505
529
|
)
|
|
506
530
|
] }, di);
|
|
507
531
|
}),
|
|
508
|
-
|
|
532
|
+
activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
509
533
|
"line",
|
|
510
534
|
{
|
|
511
|
-
x1:
|
|
535
|
+
x1: activeX,
|
|
512
536
|
y1: PADDING.top,
|
|
513
|
-
x2:
|
|
537
|
+
x2: activeX,
|
|
514
538
|
y2: PADDING.top + chartH,
|
|
515
539
|
className: "chart-crosshair"
|
|
516
540
|
}
|
|
517
541
|
),
|
|
518
|
-
activeIndex !== null && activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("foreignObject", { x: activeX - 100, y: 0, width: "200", height: PADDING.top, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-crosshair-label", children: [
|
|
519
|
-
labels[activeIndex],
|
|
520
|
-
" \u2014 ",
|
|
521
|
-
tooltipContent
|
|
522
|
-
] }) }),
|
|
523
542
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
524
543
|
"rect",
|
|
525
544
|
{
|
|
@@ -698,30 +717,70 @@ var PieDonutChart = import_react.default.memo(
|
|
|
698
717
|
}
|
|
699
718
|
);
|
|
700
719
|
PieDonutChart.displayName = "PieDonutChart";
|
|
701
|
-
var
|
|
720
|
+
var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
|
|
702
721
|
const ref = import_react.default.useRef(null);
|
|
703
|
-
const [
|
|
704
|
-
import_react.default.
|
|
722
|
+
const [pos, setPos] = import_react.default.useState({ left: 0, top: 0 });
|
|
723
|
+
import_react.default.useLayoutEffect(() => {
|
|
705
724
|
const el = ref.current;
|
|
706
725
|
if (!el) return;
|
|
707
726
|
const w = el.offsetWidth;
|
|
708
|
-
const
|
|
709
|
-
const
|
|
710
|
-
let
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
727
|
+
const h = el.offsetHeight;
|
|
728
|
+
const vw = window.innerWidth;
|
|
729
|
+
let left = clientX + TOOLTIP_OFFSET;
|
|
730
|
+
let top = clientY - h - TOOLTIP_OFFSET;
|
|
731
|
+
if (left + w > vw - 8) left = clientX - w - TOOLTIP_OFFSET;
|
|
732
|
+
if (top < 8) top = clientY + TOOLTIP_OFFSET;
|
|
733
|
+
if (left < 8) left = 8;
|
|
734
|
+
setPos({ left, top });
|
|
735
|
+
}, [clientX, clientY]);
|
|
715
736
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
716
737
|
"div",
|
|
717
738
|
{
|
|
718
739
|
ref,
|
|
719
|
-
className: "chart-tooltip"
|
|
720
|
-
style: { left:
|
|
740
|
+
className: `chart-tooltip ${visible ? "chart-tooltip-show" : "chart-tooltip-hide"}`,
|
|
741
|
+
style: { position: "fixed", left: pos.left, top: pos.top, zIndex: 1100 },
|
|
721
742
|
children
|
|
722
743
|
}
|
|
723
744
|
);
|
|
724
745
|
};
|
|
746
|
+
var ChartLegend = ({ data, labels, type }) => {
|
|
747
|
+
const entries = Object.entries(data);
|
|
748
|
+
if (type === "pie" || type === "doughnut") {
|
|
749
|
+
const values = entries.flatMap(([, v]) => v);
|
|
750
|
+
const total = values.reduce((a, b) => a + b, 0) || 1;
|
|
751
|
+
const firstKey = entries[0]?.[0] ?? "";
|
|
752
|
+
const colorOffset = hashString(firstKey);
|
|
753
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "chart-legend", children: values.map((v, i) => {
|
|
754
|
+
const pct = Math.round(v / total * 100);
|
|
755
|
+
const color = PIE_COLORS[(i + colorOffset) % PIE_COLORS.length];
|
|
756
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-legend-item", children: [
|
|
757
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
|
|
758
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-legend-text", children: [
|
|
759
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-label", children: labels[i] || `${i + 1}` }),
|
|
760
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "chart-legend-value", children: [
|
|
761
|
+
v.toLocaleString(),
|
|
762
|
+
"(",
|
|
763
|
+
pct,
|
|
764
|
+
"%)"
|
|
765
|
+
] })
|
|
766
|
+
] })
|
|
767
|
+
] }, i);
|
|
768
|
+
}) });
|
|
769
|
+
}
|
|
770
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "chart-legend", children: entries.map(([key], di) => {
|
|
771
|
+
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
772
|
+
const color = palette[2];
|
|
773
|
+
const values = entries[di][1];
|
|
774
|
+
const sum = values.reduce((a, b) => a + b, 0);
|
|
775
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-legend-item", children: [
|
|
776
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
|
|
777
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-legend-text", children: [
|
|
778
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-label", children: key }),
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-value", children: sum.toLocaleString() })
|
|
780
|
+
] })
|
|
781
|
+
] }, di);
|
|
782
|
+
}) });
|
|
783
|
+
};
|
|
725
784
|
var Chart = import_react.default.memo((props) => {
|
|
726
785
|
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
727
786
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
@@ -737,7 +796,8 @@ var Chart = import_react.default.memo((props) => {
|
|
|
737
796
|
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
738
797
|
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
739
798
|
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 }),
|
|
740
|
-
|
|
799
|
+
ready && (type === "bar" || type === "pie" || type === "doughnut") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartLegend, { data: stableData, labels: stableLabels, type }),
|
|
800
|
+
tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartTooltipPortal, { clientX: tooltip.clientX, clientY: tooltip.clientY, visible: tooltip.visible, children: tooltip.content })
|
|
741
801
|
] });
|
|
742
802
|
});
|
|
743
803
|
Chart.displayName = "Chart";
|
|
@@ -75,9 +75,9 @@
|
|
|
75
75
|
opacity: 1;
|
|
76
76
|
}
|
|
77
77
|
.lib-xplat-chart .chart-crosshair {
|
|
78
|
-
stroke: var(--semantic-border-
|
|
78
|
+
stroke: var(--semantic-border-strong);
|
|
79
79
|
stroke-width: 1;
|
|
80
|
-
stroke-dasharray: 4
|
|
80
|
+
stroke-dasharray: 4 3;
|
|
81
81
|
pointer-events: none;
|
|
82
82
|
}
|
|
83
83
|
.lib-xplat-chart .chart-point-active {
|
|
@@ -93,18 +93,24 @@
|
|
|
93
93
|
overflow: visible;
|
|
94
94
|
}
|
|
95
95
|
.lib-xplat-chart .chart-tooltip {
|
|
96
|
-
|
|
97
|
-
transform: translate(-50%, -100%);
|
|
98
|
-
padding: var(--spacing-space-2) var(--spacing-space-3);
|
|
96
|
+
padding: var(--spacing-space-3);
|
|
99
97
|
background-color: var(--semantic-surface-neutral-strong);
|
|
100
98
|
color: var(--semantic-text-inverse);
|
|
101
99
|
font-size: 12px;
|
|
100
|
+
line-height: 18px;
|
|
102
101
|
font-weight: 500;
|
|
103
102
|
border-radius: var(--spacing-radius-md);
|
|
104
|
-
|
|
103
|
+
max-width: 240px;
|
|
105
104
|
pointer-events: none;
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
106
|
+
}
|
|
107
|
+
.lib-xplat-chart .chart-tooltip.chart-tooltip-show {
|
|
108
|
+
opacity: 1;
|
|
109
|
+
animation: chart-tooltip-in 120ms ease-out;
|
|
110
|
+
}
|
|
111
|
+
.lib-xplat-chart .chart-tooltip.chart-tooltip-hide {
|
|
112
|
+
opacity: 0;
|
|
113
|
+
animation: chart-tooltip-out 80ms ease-in;
|
|
108
114
|
}
|
|
109
115
|
.lib-xplat-chart .chart-bar-animate {
|
|
110
116
|
animation: chart-bar-grow 800ms ease-out both;
|
|
@@ -116,6 +122,38 @@
|
|
|
116
122
|
.lib-xplat-chart .chart-area[style*=animationDelay] {
|
|
117
123
|
animation: chart-fade-in 800ms ease-out both;
|
|
118
124
|
}
|
|
125
|
+
.lib-xplat-chart .chart-legend {
|
|
126
|
+
display: flex;
|
|
127
|
+
flex-wrap: wrap;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
gap: var(--spacing-space-4);
|
|
130
|
+
padding: var(--spacing-space-3) 0;
|
|
131
|
+
}
|
|
132
|
+
.lib-xplat-chart .chart-legend-item {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: flex-start;
|
|
135
|
+
gap: var(--spacing-space-2);
|
|
136
|
+
}
|
|
137
|
+
.lib-xplat-chart .chart-legend-dot {
|
|
138
|
+
flex-shrink: 0;
|
|
139
|
+
width: 10px;
|
|
140
|
+
height: 10px;
|
|
141
|
+
border-radius: 50%;
|
|
142
|
+
margin-top: 3px;
|
|
143
|
+
}
|
|
144
|
+
.lib-xplat-chart .chart-legend-text {
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
}
|
|
148
|
+
.lib-xplat-chart .chart-legend-label {
|
|
149
|
+
font-size: 12px;
|
|
150
|
+
color: var(--semantic-text-muted);
|
|
151
|
+
}
|
|
152
|
+
.lib-xplat-chart .chart-legend-value {
|
|
153
|
+
font-size: 14px;
|
|
154
|
+
font-weight: 600;
|
|
155
|
+
color: var(--semantic-text-strong);
|
|
156
|
+
}
|
|
119
157
|
@keyframes chart-bar-grow {
|
|
120
158
|
from {
|
|
121
159
|
transform: scaleY(0);
|
|
@@ -135,11 +173,17 @@
|
|
|
135
173
|
@keyframes chart-tooltip-in {
|
|
136
174
|
from {
|
|
137
175
|
opacity: 0;
|
|
138
|
-
transform: translate(-50%, -90%);
|
|
139
176
|
}
|
|
140
177
|
to {
|
|
141
178
|
opacity: 1;
|
|
142
|
-
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
@keyframes chart-tooltip-out {
|
|
182
|
+
from {
|
|
183
|
+
opacity: 1;
|
|
184
|
+
}
|
|
185
|
+
to {
|
|
186
|
+
opacity: 0;
|
|
143
187
|
}
|
|
144
188
|
}
|
|
145
189
|
@media (prefers-reduced-motion: reduce) {
|