@x-plat/design-system 0.5.37 → 0.5.39
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 +35 -46
- package/dist/components/Chart/index.css +26 -6
- package/dist/components/Chart/index.d.cts +1 -0
- package/dist/components/Chart/index.d.ts +1 -0
- package/dist/components/Chart/index.js +35 -46
- package/dist/components/Tooltip/index.cjs +98 -8
- package/dist/components/Tooltip/index.css +38 -38
- package/dist/components/Tooltip/index.d.cts +6 -8
- package/dist/components/Tooltip/index.d.ts +6 -8
- package/dist/components/Tooltip/index.js +98 -8
- package/dist/components/index.cjs +118 -53
- package/dist/components/index.css +61 -41
- package/dist/components/index.js +119 -54
- package/dist/index.cjs +118 -53
- package/dist/index.css +61 -41
- package/dist/index.js +121 -56
- package/package.json +1 -1
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
/* src/components/Tooltip/tooltip.scss */
|
|
2
|
+
.lib-xplat-tooltip-trigger {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
}
|
|
2
5
|
.lib-xplat-tooltip {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
width: fit-content;
|
|
8
|
-
height: fit-content;
|
|
9
|
-
}
|
|
10
|
-
.lib-xplat-tooltip > .tooltip-wrapper {
|
|
11
|
-
position: absolute;
|
|
12
|
-
transform: translateX(-50%) scale(0.5);
|
|
13
|
-
left: 50%;
|
|
14
|
-
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
|
15
|
-
white-space: nowrap;
|
|
16
|
-
border-radius: var(--spacing-radius-sm);
|
|
17
|
-
padding: var(--spacing-space-2) var(--spacing-space-2);
|
|
18
|
-
opacity: 0;
|
|
6
|
+
z-index: 1100;
|
|
7
|
+
padding: var(--spacing-space-3);
|
|
8
|
+
border-radius: var(--spacing-radius-md);
|
|
9
|
+
max-width: 240px;
|
|
19
10
|
pointer-events: none;
|
|
20
|
-
|
|
21
|
-
transition: opacity 0.12s ease, transform 0.15s cubic-bezier(0.16, 1, 0.3, 1);
|
|
11
|
+
animation: tooltip-show 120ms ease-out;
|
|
22
12
|
}
|
|
23
|
-
.lib-xplat-tooltip
|
|
24
|
-
|
|
13
|
+
.lib-xplat-tooltip .tooltip-title {
|
|
14
|
+
font-size: 13px;
|
|
15
|
+
line-height: 18px;
|
|
16
|
+
font-weight: 400;
|
|
17
|
+
}
|
|
18
|
+
.lib-xplat-tooltip .tooltip-desc {
|
|
19
|
+
font-size: 12px;
|
|
20
|
+
line-height: 18px;
|
|
21
|
+
font-weight: 400;
|
|
22
|
+
}
|
|
23
|
+
.lib-xplat-tooltip.dark {
|
|
25
24
|
background-color: var(--semantic-surface-neutral-strong);
|
|
25
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
26
|
+
}
|
|
27
|
+
.lib-xplat-tooltip.dark .tooltip-title,
|
|
28
|
+
.lib-xplat-tooltip.dark .tooltip-desc {
|
|
29
|
+
color: var(--semantic-text-inverse);
|
|
26
30
|
}
|
|
27
|
-
.lib-xplat-tooltip
|
|
31
|
+
.lib-xplat-tooltip.light {
|
|
28
32
|
background-color: var(--semantic-surface-neutral-default);
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
.lib-xplat-tooltip.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
.lib-xplat-tooltip > .tooltip-content:hover + .tooltip-wrapper {
|
|
43
|
-
opacity: 1;
|
|
44
|
-
pointer-events: auto;
|
|
45
|
-
transform: translateX(-50%) scale(1);
|
|
33
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
34
|
+
}
|
|
35
|
+
.lib-xplat-tooltip.light .tooltip-title,
|
|
36
|
+
.lib-xplat-tooltip.light .tooltip-desc {
|
|
37
|
+
color: var(--semantic-text-subtle);
|
|
38
|
+
}
|
|
39
|
+
@keyframes tooltip-show {
|
|
40
|
+
from {
|
|
41
|
+
opacity: 0;
|
|
42
|
+
}
|
|
43
|
+
to {
|
|
44
|
+
opacity: 1;
|
|
45
|
+
}
|
|
46
46
|
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
1
|
import React from 'react';
|
|
3
2
|
|
|
4
3
|
interface TooltipProps {
|
|
5
|
-
type?: "
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
type?: "dark" | "light";
|
|
5
|
+
title?: React.ReactNode;
|
|
6
|
+
description?: React.ReactNode;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
8
9
|
}
|
|
9
|
-
declare const Tooltip:
|
|
10
|
-
(props: TooltipProps): react_jsx_runtime.JSX.Element;
|
|
11
|
-
displayName: string;
|
|
12
|
-
};
|
|
10
|
+
declare const Tooltip: React.FC<TooltipProps>;
|
|
13
11
|
|
|
14
12
|
export { Tooltip };
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
1
|
import React from 'react';
|
|
3
2
|
|
|
4
3
|
interface TooltipProps {
|
|
5
|
-
type?: "
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
type?: "dark" | "light";
|
|
5
|
+
title?: React.ReactNode;
|
|
6
|
+
description?: React.ReactNode;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
8
9
|
}
|
|
9
|
-
declare const Tooltip:
|
|
10
|
-
(props: TooltipProps): react_jsx_runtime.JSX.Element;
|
|
11
|
-
displayName: string;
|
|
12
|
-
};
|
|
10
|
+
declare const Tooltip: React.FC<TooltipProps>;
|
|
13
11
|
|
|
14
12
|
export { Tooltip };
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
// src/components/Tooltip/Tooltip.tsx
|
|
2
|
+
import React2 from "react";
|
|
3
|
+
|
|
4
|
+
// src/tokens/hooks/Portal.tsx
|
|
2
5
|
import React from "react";
|
|
6
|
+
import ReactDOM from "react-dom";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
var PortalContainerContext = React.createContext(null);
|
|
9
|
+
var Portal = ({ children }) => {
|
|
10
|
+
const contextContainer = React.useContext(PortalContainerContext);
|
|
11
|
+
if (typeof document === "undefined") return null;
|
|
12
|
+
const container = contextContainer ?? document.body;
|
|
13
|
+
return ReactDOM.createPortal(children, container);
|
|
14
|
+
};
|
|
15
|
+
Portal.displayName = "Portal";
|
|
16
|
+
var Portal_default = Portal;
|
|
3
17
|
|
|
4
18
|
// ../../node_modules/clsx/dist/clsx.mjs
|
|
5
19
|
function r(e) {
|
|
@@ -18,18 +32,94 @@ function clsx() {
|
|
|
18
32
|
var clsx_default = clsx;
|
|
19
33
|
|
|
20
34
|
// src/components/Tooltip/Tooltip.tsx
|
|
21
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
35
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
36
|
+
var OFFSET = 12;
|
|
37
|
+
var SHOW_DELAY = 300;
|
|
22
38
|
var Tooltip = (props) => {
|
|
23
39
|
const {
|
|
24
|
-
type = "
|
|
40
|
+
type = "dark",
|
|
41
|
+
title,
|
|
25
42
|
description,
|
|
26
|
-
children
|
|
43
|
+
children,
|
|
44
|
+
disabled = false
|
|
27
45
|
} = props;
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
const triggerRef = React2.useRef(null);
|
|
47
|
+
const tooltipRef = React2.useRef(null);
|
|
48
|
+
const [visible, setVisible] = React2.useState(false);
|
|
49
|
+
const [pos, setPos] = React2.useState({ left: 0, top: 0 });
|
|
50
|
+
const delayTimer = React2.useRef(0);
|
|
51
|
+
const calculatePos = React2.useCallback((clientX, clientY) => {
|
|
52
|
+
const el = tooltipRef.current;
|
|
53
|
+
if (!el) return;
|
|
54
|
+
const w = el.offsetWidth;
|
|
55
|
+
const h = el.offsetHeight;
|
|
56
|
+
const vw = window.innerWidth;
|
|
57
|
+
let left = clientX + OFFSET;
|
|
58
|
+
let top = clientY - h - OFFSET;
|
|
59
|
+
if (left + w > vw - 8) left = clientX - w - OFFSET;
|
|
60
|
+
if (top < 8) top = clientY + OFFSET;
|
|
61
|
+
if (left < 8) left = 8;
|
|
62
|
+
setPos({ left, top });
|
|
63
|
+
}, []);
|
|
64
|
+
const handleMouseEnter = React2.useCallback(() => {
|
|
65
|
+
if (disabled) return;
|
|
66
|
+
delayTimer.current = window.setTimeout(() => {
|
|
67
|
+
setVisible(true);
|
|
68
|
+
}, SHOW_DELAY);
|
|
69
|
+
}, [disabled]);
|
|
70
|
+
const handleMouseMove = React2.useCallback((e) => {
|
|
71
|
+
if (!visible) return;
|
|
72
|
+
calculatePos(e.clientX, e.clientY);
|
|
73
|
+
}, [visible, calculatePos]);
|
|
74
|
+
const handleMouseLeave = React2.useCallback(() => {
|
|
75
|
+
window.clearTimeout(delayTimer.current);
|
|
76
|
+
setVisible(false);
|
|
77
|
+
}, []);
|
|
78
|
+
const handleClick = React2.useCallback(() => {
|
|
79
|
+
window.clearTimeout(delayTimer.current);
|
|
80
|
+
setVisible(false);
|
|
81
|
+
}, []);
|
|
82
|
+
const handleFocus = React2.useCallback(() => {
|
|
83
|
+
if (disabled) return;
|
|
84
|
+
setVisible(true);
|
|
85
|
+
}, [disabled]);
|
|
86
|
+
const handleBlur = React2.useCallback(() => {
|
|
87
|
+
setVisible(false);
|
|
88
|
+
}, []);
|
|
89
|
+
React2.useLayoutEffect(() => {
|
|
90
|
+
if (!visible || !triggerRef.current) return;
|
|
91
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
92
|
+
calculatePos(rect.right, rect.top);
|
|
93
|
+
}, [visible, calculatePos]);
|
|
94
|
+
if (!title && !description) return /* @__PURE__ */ jsx2(Fragment, { children });
|
|
95
|
+
return /* @__PURE__ */ jsxs(
|
|
96
|
+
"div",
|
|
97
|
+
{
|
|
98
|
+
ref: triggerRef,
|
|
99
|
+
className: "lib-xplat-tooltip-trigger",
|
|
100
|
+
onMouseEnter: handleMouseEnter,
|
|
101
|
+
onMouseMove: handleMouseMove,
|
|
102
|
+
onMouseLeave: handleMouseLeave,
|
|
103
|
+
onClick: handleClick,
|
|
104
|
+
onFocus: handleFocus,
|
|
105
|
+
onBlur: handleBlur,
|
|
106
|
+
children: [
|
|
107
|
+
children,
|
|
108
|
+
visible && /* @__PURE__ */ jsx2(Portal_default, { children: /* @__PURE__ */ jsxs(
|
|
109
|
+
"div",
|
|
110
|
+
{
|
|
111
|
+
ref: tooltipRef,
|
|
112
|
+
className: clsx_default("lib-xplat-tooltip", type),
|
|
113
|
+
style: { position: "fixed", left: pos.left, top: pos.top },
|
|
114
|
+
children: [
|
|
115
|
+
title && /* @__PURE__ */ jsx2("div", { className: "tooltip-title", children: title }),
|
|
116
|
+
description && /* @__PURE__ */ jsx2("div", { className: "tooltip-desc", children: description })
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
) })
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
);
|
|
33
123
|
};
|
|
34
124
|
Tooltip.displayName = "Tooltip";
|
|
35
125
|
var Tooltip_default = Tooltip;
|
|
@@ -2380,28 +2380,11 @@ var useChartTooltip = (enabled) => {
|
|
|
2380
2380
|
if (!rect) return;
|
|
2381
2381
|
setTooltip({ visible: true, x: e.clientX - rect.left, y: e.clientY - rect.top, content });
|
|
2382
2382
|
}, [enabled]);
|
|
2383
|
-
const showAt = import_react6.default.useCallback((svgX, svgY, content, svgEl) => {
|
|
2384
|
-
if (!enabled) return;
|
|
2385
|
-
const container = containerRef.current;
|
|
2386
|
-
if (!container) return;
|
|
2387
|
-
let x = svgX;
|
|
2388
|
-
let y = svgY;
|
|
2389
|
-
if (svgEl) {
|
|
2390
|
-
const svgRect = svgEl.getBoundingClientRect();
|
|
2391
|
-
const containerRect = container.getBoundingClientRect();
|
|
2392
|
-
const vb = svgEl.viewBox.baseVal;
|
|
2393
|
-
const scaleX = svgRect.width / (vb.width || 1);
|
|
2394
|
-
const scaleY = svgRect.height / (vb.height || 1);
|
|
2395
|
-
x = svgX * scaleX + (svgRect.left - containerRect.left);
|
|
2396
|
-
y = svgY * scaleY + (svgRect.top - containerRect.top);
|
|
2397
|
-
}
|
|
2398
|
-
setTooltip({ visible: true, x, y, content });
|
|
2399
|
-
}, [enabled]);
|
|
2400
2383
|
const hide = import_react6.default.useCallback(() => {
|
|
2401
2384
|
cancelAnimationFrame(rafRef.current);
|
|
2402
2385
|
setTooltip((prev) => ({ ...prev, visible: false }));
|
|
2403
2386
|
}, []);
|
|
2404
|
-
return { tooltip, show,
|
|
2387
|
+
return { tooltip, show, hide, move, containerRef };
|
|
2405
2388
|
};
|
|
2406
2389
|
var GridLines = import_react6.default.memo(({ width, height, chartH, maxVal }) => /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(import_jsx_runtime307.Fragment, { children: [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
|
|
2407
2390
|
const y = PADDING.top + (1 - ratio) * chartH;
|
|
@@ -2466,7 +2449,7 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
|
|
|
2466
2449
|
}, [entries, seriesPoints]);
|
|
2467
2450
|
return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
|
|
2468
2451
|
};
|
|
2469
|
-
var LineChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover,
|
|
2452
|
+
var LineChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
2470
2453
|
const entries = import_react6.default.useMemo(() => Object.entries(data), [data]);
|
|
2471
2454
|
const maxVal = import_react6.default.useMemo(() => {
|
|
2472
2455
|
const allValues = entries.flatMap(([, v]) => v);
|
|
@@ -2486,7 +2469,6 @@ var LineChart = import_react6.default.memo(({ data, labels, width, height, anima
|
|
|
2486
2469
|
[entries, count, chartW, chartH, maxVal]
|
|
2487
2470
|
);
|
|
2488
2471
|
const clipRef = import_react6.default.useRef(null);
|
|
2489
|
-
const svgRef = import_react6.default.useRef(null);
|
|
2490
2472
|
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
2491
2473
|
import_react6.default.useEffect(() => {
|
|
2492
2474
|
if (!animate || !clipRef.current) return;
|
|
@@ -2503,14 +2485,12 @@ var LineChart = import_react6.default.memo(({ data, labels, width, height, anima
|
|
|
2503
2485
|
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)(
|
|
2504
2486
|
"svg",
|
|
2505
2487
|
{
|
|
2506
|
-
ref: svgRef,
|
|
2507
2488
|
viewBox: `0 0 ${width} ${height}`,
|
|
2508
2489
|
className: "chart-svg",
|
|
2509
2490
|
onMouseMove: (e) => {
|
|
2510
2491
|
handleMouseMove(e);
|
|
2511
|
-
if (activeIndex !== null
|
|
2512
|
-
|
|
2513
|
-
onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`, svgRef.current);
|
|
2492
|
+
if (activeIndex !== null) {
|
|
2493
|
+
onHover(e, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
|
|
2514
2494
|
} else {
|
|
2515
2495
|
onLeave();
|
|
2516
2496
|
}
|
|
@@ -2578,7 +2558,7 @@ var LineChart = import_react6.default.memo(({ data, labels, width, height, anima
|
|
|
2578
2558
|
);
|
|
2579
2559
|
});
|
|
2580
2560
|
LineChart.displayName = "LineChart";
|
|
2581
|
-
var CurveChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover,
|
|
2561
|
+
var CurveChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
2582
2562
|
const entries = import_react6.default.useMemo(() => Object.entries(data), [data]);
|
|
2583
2563
|
const maxVal = import_react6.default.useMemo(() => {
|
|
2584
2564
|
const allValues = entries.flatMap(([, v]) => v);
|
|
@@ -2598,7 +2578,6 @@ var CurveChart = import_react6.default.memo(({ data, labels, width, height, anim
|
|
|
2598
2578
|
[entries, count, chartW, chartH, maxVal]
|
|
2599
2579
|
);
|
|
2600
2580
|
const curveClipRef = import_react6.default.useRef(null);
|
|
2601
|
-
const curveSvgRef = import_react6.default.useRef(null);
|
|
2602
2581
|
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
2603
2582
|
import_react6.default.useEffect(() => {
|
|
2604
2583
|
if (!animate || !curveClipRef.current) return;
|
|
@@ -2615,14 +2594,13 @@ var CurveChart = import_react6.default.memo(({ data, labels, width, height, anim
|
|
|
2615
2594
|
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)(
|
|
2616
2595
|
"svg",
|
|
2617
2596
|
{
|
|
2618
|
-
ref: curveSvgRef,
|
|
2619
2597
|
viewBox: `0 0 ${width} ${height}`,
|
|
2620
2598
|
className: "chart-svg",
|
|
2621
2599
|
onMouseMove: (e) => {
|
|
2622
2600
|
handleMouseMove(e);
|
|
2623
2601
|
if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
|
|
2624
2602
|
const p = seriesPoints[0][activeIndex];
|
|
2625
|
-
|
|
2603
|
+
onHover(e, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
|
|
2626
2604
|
} else {
|
|
2627
2605
|
onLeave();
|
|
2628
2606
|
}
|
|
@@ -2690,8 +2668,7 @@ var CurveChart = import_react6.default.memo(({ data, labels, width, height, anim
|
|
|
2690
2668
|
);
|
|
2691
2669
|
});
|
|
2692
2670
|
CurveChart.displayName = "CurveChart";
|
|
2693
|
-
var BarChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover,
|
|
2694
|
-
const barSvgRef = import_react6.default.useRef(null);
|
|
2671
|
+
var BarChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
2695
2672
|
const entries = import_react6.default.useMemo(() => Object.entries(data), [data]);
|
|
2696
2673
|
const maxVal = import_react6.default.useMemo(() => {
|
|
2697
2674
|
const allValues = entries.flatMap(([, v]) => v);
|
|
@@ -2718,7 +2695,7 @@ var BarChart = import_react6.default.memo(({ data, labels, width, height, animat
|
|
|
2718
2695
|
[entries, maxVal, chartH, groupW, barW, barGap, groupCount]
|
|
2719
2696
|
);
|
|
2720
2697
|
const barLabelStep = getLabelStep(count, chartW);
|
|
2721
|
-
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("svg", {
|
|
2698
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
2722
2699
|
/* @__PURE__ */ (0, import_jsx_runtime307.jsx)(GridLines, { width, height, chartH, maxVal }),
|
|
2723
2700
|
labels.map((label, i) => {
|
|
2724
2701
|
if (i % barLabelStep !== 0) return null;
|
|
@@ -2741,7 +2718,8 @@ var BarChart = import_react6.default.memo(({ data, labels, width, height, animat
|
|
|
2741
2718
|
transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
|
|
2742
2719
|
animationDelay: `${delay}ms`
|
|
2743
2720
|
} : void 0,
|
|
2744
|
-
onMouseEnter: () =>
|
|
2721
|
+
onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
|
|
2722
|
+
onMouseMove: onMove,
|
|
2745
2723
|
onMouseLeave: onLeave
|
|
2746
2724
|
},
|
|
2747
2725
|
`${di}-${i}`
|
|
@@ -2829,14 +2807,17 @@ var PieDonutChart = import_react6.default.memo(
|
|
|
2829
2807
|
{
|
|
2830
2808
|
d: s.d,
|
|
2831
2809
|
fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
|
|
2832
|
-
className: "chart-slice"
|
|
2810
|
+
className: "chart-slice",
|
|
2811
|
+
onMouseEnter: (e) => onHover(e, `${s.label} \u2014 ${s.v.toLocaleString()} (${s.pct}%)`),
|
|
2812
|
+
onMouseMove: onMove,
|
|
2813
|
+
onMouseLeave: onLeave
|
|
2833
2814
|
}
|
|
2834
2815
|
) }, i)) })
|
|
2835
2816
|
] });
|
|
2836
2817
|
}
|
|
2837
2818
|
);
|
|
2838
2819
|
PieDonutChart.displayName = "PieDonutChart";
|
|
2839
|
-
var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
|
|
2820
|
+
var ChartTooltip = ({ x, y, containerWidth, containerHeight, tooltipType, children }) => {
|
|
2840
2821
|
const ref = import_react6.default.useRef(null);
|
|
2841
2822
|
const [pos, setPos] = import_react6.default.useState({ left: 0, top: 0 });
|
|
2842
2823
|
import_react6.default.useLayoutEffect(() => {
|
|
@@ -2847,17 +2828,25 @@ var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
|
|
|
2847
2828
|
let left = x + TOOLTIP_OFFSET;
|
|
2848
2829
|
let top = y - h - TOOLTIP_OFFSET;
|
|
2849
2830
|
if (left + w > containerWidth) left = x - w - TOOLTIP_OFFSET;
|
|
2850
|
-
if (top < 0) top = y + TOOLTIP_OFFSET;
|
|
2851
2831
|
if (left < 0) left = 0;
|
|
2832
|
+
if (top < 0) top = y + TOOLTIP_OFFSET;
|
|
2833
|
+
if (top + h > containerHeight) top = containerHeight - h;
|
|
2852
2834
|
setPos({ left, top });
|
|
2853
2835
|
}, [x, y, containerWidth, containerHeight]);
|
|
2854
|
-
|
|
2836
|
+
const content = typeof children === "string" ? children : "";
|
|
2837
|
+
const sepIdx = content.indexOf(" \u2014 ");
|
|
2838
|
+
const title = sepIdx >= 0 ? content.slice(0, sepIdx) : content;
|
|
2839
|
+
const desc = sepIdx >= 0 ? content.slice(sepIdx + 3) : "";
|
|
2840
|
+
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)(
|
|
2855
2841
|
"div",
|
|
2856
2842
|
{
|
|
2857
2843
|
ref,
|
|
2858
|
-
className:
|
|
2844
|
+
className: `chart-tooltip chart-tooltip-show chart-tooltip-${tooltipType}`,
|
|
2859
2845
|
style: { left: pos.left, top: pos.top },
|
|
2860
|
-
children
|
|
2846
|
+
children: [
|
|
2847
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("div", { className: "chart-tooltip-title", children: title }),
|
|
2848
|
+
desc && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)("div", { className: "chart-tooltip-desc", children: desc })
|
|
2849
|
+
]
|
|
2861
2850
|
}
|
|
2862
2851
|
);
|
|
2863
2852
|
};
|
|
@@ -2900,8 +2889,8 @@ var ChartLegend = ({ data, labels, type }) => {
|
|
|
2900
2889
|
}) });
|
|
2901
2890
|
};
|
|
2902
2891
|
var Chart = import_react6.default.memo((props) => {
|
|
2903
|
-
const { type, data, labels, tooltip: showTooltip = true } = props;
|
|
2904
|
-
const { tooltip, show,
|
|
2892
|
+
const { type, data, labels, tooltip: showTooltip = true, tooltipType = "dark" } = props;
|
|
2893
|
+
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
2905
2894
|
const { width, height } = useChartSize(containerRef);
|
|
2906
2895
|
const stableData = import_react6.default.useMemo(() => data, [JSON.stringify(data)]);
|
|
2907
2896
|
const stableLabels = import_react6.default.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
@@ -2909,13 +2898,13 @@ var Chart = import_react6.default.memo((props) => {
|
|
|
2909
2898
|
const animate = useChartAnimation(containerRef, dataKey);
|
|
2910
2899
|
const ready = width > 0 && height > 0;
|
|
2911
2900
|
return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
2912
|
-
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show,
|
|
2913
|
-
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show,
|
|
2914
|
-
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show,
|
|
2915
|
-
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show,
|
|
2916
|
-
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show,
|
|
2901
|
+
ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2902
|
+
ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2903
|
+
ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2904
|
+
ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2905
|
+
ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
2917
2906
|
ready && (type === "pie" || type === "doughnut") && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(ChartLegend, { data: stableData, labels: stableLabels, type }),
|
|
2918
|
-
tooltip.visible && tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, children: tooltip.content })
|
|
2907
|
+
tooltip.visible && tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, tooltipType, children: tooltip.content })
|
|
2919
2908
|
] });
|
|
2920
2909
|
});
|
|
2921
2910
|
Chart.displayName = "Chart";
|
|
@@ -5423,17 +5412,93 @@ ToastProvider.displayName = "ToastProvider";
|
|
|
5423
5412
|
// src/components/Tooltip/Tooltip.tsx
|
|
5424
5413
|
var import_react40 = __toESM(require("react"), 1);
|
|
5425
5414
|
var import_jsx_runtime348 = require("react/jsx-runtime");
|
|
5415
|
+
var OFFSET = 12;
|
|
5416
|
+
var SHOW_DELAY = 300;
|
|
5426
5417
|
var Tooltip = (props) => {
|
|
5427
5418
|
const {
|
|
5428
|
-
type = "
|
|
5419
|
+
type = "dark",
|
|
5420
|
+
title,
|
|
5429
5421
|
description,
|
|
5430
|
-
children
|
|
5422
|
+
children,
|
|
5423
|
+
disabled = false
|
|
5431
5424
|
} = props;
|
|
5432
|
-
const
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5425
|
+
const triggerRef = import_react40.default.useRef(null);
|
|
5426
|
+
const tooltipRef = import_react40.default.useRef(null);
|
|
5427
|
+
const [visible, setVisible] = import_react40.default.useState(false);
|
|
5428
|
+
const [pos, setPos] = import_react40.default.useState({ left: 0, top: 0 });
|
|
5429
|
+
const delayTimer = import_react40.default.useRef(0);
|
|
5430
|
+
const calculatePos = import_react40.default.useCallback((clientX, clientY) => {
|
|
5431
|
+
const el = tooltipRef.current;
|
|
5432
|
+
if (!el) return;
|
|
5433
|
+
const w = el.offsetWidth;
|
|
5434
|
+
const h = el.offsetHeight;
|
|
5435
|
+
const vw = window.innerWidth;
|
|
5436
|
+
let left = clientX + OFFSET;
|
|
5437
|
+
let top = clientY - h - OFFSET;
|
|
5438
|
+
if (left + w > vw - 8) left = clientX - w - OFFSET;
|
|
5439
|
+
if (top < 8) top = clientY + OFFSET;
|
|
5440
|
+
if (left < 8) left = 8;
|
|
5441
|
+
setPos({ left, top });
|
|
5442
|
+
}, []);
|
|
5443
|
+
const handleMouseEnter = import_react40.default.useCallback(() => {
|
|
5444
|
+
if (disabled) return;
|
|
5445
|
+
delayTimer.current = window.setTimeout(() => {
|
|
5446
|
+
setVisible(true);
|
|
5447
|
+
}, SHOW_DELAY);
|
|
5448
|
+
}, [disabled]);
|
|
5449
|
+
const handleMouseMove = import_react40.default.useCallback((e) => {
|
|
5450
|
+
if (!visible) return;
|
|
5451
|
+
calculatePos(e.clientX, e.clientY);
|
|
5452
|
+
}, [visible, calculatePos]);
|
|
5453
|
+
const handleMouseLeave = import_react40.default.useCallback(() => {
|
|
5454
|
+
window.clearTimeout(delayTimer.current);
|
|
5455
|
+
setVisible(false);
|
|
5456
|
+
}, []);
|
|
5457
|
+
const handleClick = import_react40.default.useCallback(() => {
|
|
5458
|
+
window.clearTimeout(delayTimer.current);
|
|
5459
|
+
setVisible(false);
|
|
5460
|
+
}, []);
|
|
5461
|
+
const handleFocus = import_react40.default.useCallback(() => {
|
|
5462
|
+
if (disabled) return;
|
|
5463
|
+
setVisible(true);
|
|
5464
|
+
}, [disabled]);
|
|
5465
|
+
const handleBlur = import_react40.default.useCallback(() => {
|
|
5466
|
+
setVisible(false);
|
|
5467
|
+
}, []);
|
|
5468
|
+
import_react40.default.useLayoutEffect(() => {
|
|
5469
|
+
if (!visible || !triggerRef.current) return;
|
|
5470
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
5471
|
+
calculatePos(rect.right, rect.top);
|
|
5472
|
+
}, [visible, calculatePos]);
|
|
5473
|
+
if (!title && !description) return /* @__PURE__ */ (0, import_jsx_runtime348.jsx)(import_jsx_runtime348.Fragment, { children });
|
|
5474
|
+
return /* @__PURE__ */ (0, import_jsx_runtime348.jsxs)(
|
|
5475
|
+
"div",
|
|
5476
|
+
{
|
|
5477
|
+
ref: triggerRef,
|
|
5478
|
+
className: "lib-xplat-tooltip-trigger",
|
|
5479
|
+
onMouseEnter: handleMouseEnter,
|
|
5480
|
+
onMouseMove: handleMouseMove,
|
|
5481
|
+
onMouseLeave: handleMouseLeave,
|
|
5482
|
+
onClick: handleClick,
|
|
5483
|
+
onFocus: handleFocus,
|
|
5484
|
+
onBlur: handleBlur,
|
|
5485
|
+
children: [
|
|
5486
|
+
children,
|
|
5487
|
+
visible && /* @__PURE__ */ (0, import_jsx_runtime348.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime348.jsxs)(
|
|
5488
|
+
"div",
|
|
5489
|
+
{
|
|
5490
|
+
ref: tooltipRef,
|
|
5491
|
+
className: clsx_default("lib-xplat-tooltip", type),
|
|
5492
|
+
style: { position: "fixed", left: pos.left, top: pos.top },
|
|
5493
|
+
children: [
|
|
5494
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime348.jsx)("div", { className: "tooltip-title", children: title }),
|
|
5495
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime348.jsx)("div", { className: "tooltip-desc", children: description })
|
|
5496
|
+
]
|
|
5497
|
+
}
|
|
5498
|
+
) })
|
|
5499
|
+
]
|
|
5500
|
+
}
|
|
5501
|
+
);
|
|
5437
5502
|
};
|
|
5438
5503
|
Tooltip.displayName = "Tooltip";
|
|
5439
5504
|
var Tooltip_default = Tooltip;
|