@x-plat/design-system 0.5.34 → 0.5.36

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.
@@ -2357,8 +2357,8 @@ var TOOLTIP_OFFSET = 12;
2357
2357
  var useChartTooltip = (enabled) => {
2358
2358
  const [tooltip, setTooltip] = import_react6.default.useState({
2359
2359
  visible: false,
2360
- clientX: 0,
2361
- clientY: 0,
2360
+ x: 0,
2361
+ y: 0,
2362
2362
  content: ""
2363
2363
  });
2364
2364
  const containerRef = import_react6.default.useRef(null);
@@ -2369,18 +2369,26 @@ var useChartTooltip = (enabled) => {
2369
2369
  const cy = e.clientY;
2370
2370
  cancelAnimationFrame(rafRef.current);
2371
2371
  rafRef.current = requestAnimationFrame(() => {
2372
- setTooltip((prev) => ({ ...prev, clientX: cx, clientY: cy }));
2372
+ const rect = containerRef.current?.getBoundingClientRect();
2373
+ if (!rect) return;
2374
+ setTooltip((prev) => ({ ...prev, x: cx - rect.left, y: cy - rect.top }));
2373
2375
  });
2374
2376
  }, [enabled]);
2375
2377
  const show = import_react6.default.useCallback((e, content) => {
2376
2378
  if (!enabled) return;
2377
- setTooltip({ visible: true, clientX: e.clientX, clientY: e.clientY, content });
2379
+ const rect = containerRef.current?.getBoundingClientRect();
2380
+ if (!rect) return;
2381
+ setTooltip({ visible: true, x: e.clientX - rect.left, y: e.clientY - rect.top, content });
2382
+ }, [enabled]);
2383
+ const showAt = import_react6.default.useCallback((x, y, content) => {
2384
+ if (!enabled) return;
2385
+ setTooltip({ visible: true, x, y, content });
2378
2386
  }, [enabled]);
2379
2387
  const hide = import_react6.default.useCallback(() => {
2380
2388
  cancelAnimationFrame(rafRef.current);
2381
2389
  setTooltip((prev) => ({ ...prev, visible: false }));
2382
2390
  }, []);
2383
- return { tooltip, show, hide, move, containerRef };
2391
+ return { tooltip, show, showAt, hide, move, containerRef };
2384
2392
  };
2385
2393
  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) => {
2386
2394
  const y = PADDING.top + (1 - ratio) * chartH;
@@ -2445,7 +2453,7 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
2445
2453
  }, [entries, seriesPoints]);
2446
2454
  return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
2447
2455
  };
2448
- var LineChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
2456
+ var LineChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
2449
2457
  const entries = import_react6.default.useMemo(() => Object.entries(data), [data]);
2450
2458
  const maxVal = import_react6.default.useMemo(() => {
2451
2459
  const allValues = entries.flatMap(([, v]) => v);
@@ -2485,23 +2493,9 @@ var LineChart = import_react6.default.memo(({ data, labels, width, height, anima
2485
2493
  className: "chart-svg",
2486
2494
  onMouseMove: (e) => {
2487
2495
  handleMouseMove(e);
2488
- const svg = e.currentTarget;
2489
- const rect = svg.getBoundingClientRect();
2490
- const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
2491
- const points = seriesPoints[0];
2492
- if (!points || points.length === 0) return;
2493
- const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
2494
- let closest = 0;
2495
- let minDist = Math.abs(points[0].x - mx);
2496
- for (let i = 1; i < points.length; i++) {
2497
- const dist = Math.abs(points[i].x - mx);
2498
- if (dist < minDist) {
2499
- minDist = dist;
2500
- closest = i;
2501
- }
2502
- }
2503
- if (minDist <= step / 2) {
2504
- onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
2496
+ if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
2497
+ const p = seriesPoints[0][activeIndex];
2498
+ onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
2505
2499
  } else {
2506
2500
  onLeave();
2507
2501
  }
@@ -2569,7 +2563,7 @@ var LineChart = import_react6.default.memo(({ data, labels, width, height, anima
2569
2563
  );
2570
2564
  });
2571
2565
  LineChart.displayName = "LineChart";
2572
- var CurveChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
2566
+ var CurveChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
2573
2567
  const entries = import_react6.default.useMemo(() => Object.entries(data), [data]);
2574
2568
  const maxVal = import_react6.default.useMemo(() => {
2575
2569
  const allValues = entries.flatMap(([, v]) => v);
@@ -2609,23 +2603,9 @@ var CurveChart = import_react6.default.memo(({ data, labels, width, height, anim
2609
2603
  className: "chart-svg",
2610
2604
  onMouseMove: (e) => {
2611
2605
  handleMouseMove(e);
2612
- const svg = e.currentTarget;
2613
- const rect = svg.getBoundingClientRect();
2614
- const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
2615
- const points = seriesPoints[0];
2616
- if (!points || points.length === 0) return;
2617
- const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
2618
- let closest = 0;
2619
- let minDist = Math.abs(points[0].x - mx);
2620
- for (let i = 1; i < points.length; i++) {
2621
- const dist = Math.abs(points[i].x - mx);
2622
- if (dist < minDist) {
2623
- minDist = dist;
2624
- closest = i;
2625
- }
2626
- }
2627
- if (minDist <= step / 2) {
2628
- onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
2606
+ if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
2607
+ const p = seriesPoints[0][activeIndex];
2608
+ onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
2629
2609
  } else {
2630
2610
  onLeave();
2631
2611
  }
@@ -2693,7 +2673,7 @@ var CurveChart = import_react6.default.memo(({ data, labels, width, height, anim
2693
2673
  );
2694
2674
  });
2695
2675
  CurveChart.displayName = "CurveChart";
2696
- var BarChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
2676
+ var BarChart = import_react6.default.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
2697
2677
  const entries = import_react6.default.useMemo(() => Object.entries(data), [data]);
2698
2678
  const maxVal = import_react6.default.useMemo(() => {
2699
2679
  const allValues = entries.flatMap(([, v]) => v);
@@ -2743,8 +2723,7 @@ var BarChart = import_react6.default.memo(({ data, labels, width, height, animat
2743
2723
  transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
2744
2724
  animationDelay: `${delay}ms`
2745
2725
  } : void 0,
2746
- onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
2747
- onMouseMove: onMove,
2726
+ onMouseEnter: () => onShowAt(b.x + b.w / 2, b.y, `${key}: ${labels[i]} \u2014 ${b.v}`),
2748
2727
  onMouseLeave: onLeave
2749
2728
  },
2750
2729
  `${di}-${i}`
@@ -2832,30 +2811,14 @@ var PieDonutChart = import_react6.default.memo(
2832
2811
  {
2833
2812
  d: s.d,
2834
2813
  fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
2835
- className: "chart-slice",
2836
- onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
2837
- onMouseMove: onMove,
2838
- onMouseLeave: onLeave
2814
+ className: "chart-slice"
2839
2815
  }
2840
- ) }, i)) }),
2841
- sliceData.map((s, i) => s.angle > 0.2 && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
2842
- "text",
2843
- {
2844
- x: s.lx,
2845
- y: s.ly,
2846
- className: `chart-pie-label ${animate ? "chart-pie-label-animate" : ""}`,
2847
- style: animate ? { animationDelay: `${s.labelDelay}ms` } : void 0,
2848
- textAnchor: "middle",
2849
- dominantBaseline: "central",
2850
- children: s.v
2851
- },
2852
- `label-${i}`
2853
- ))
2816
+ ) }, i)) })
2854
2817
  ] });
2855
2818
  }
2856
2819
  );
2857
2820
  PieDonutChart.displayName = "PieDonutChart";
2858
- var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
2821
+ var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
2859
2822
  const ref = import_react6.default.useRef(null);
2860
2823
  const [pos, setPos] = import_react6.default.useState({ left: 0, top: 0 });
2861
2824
  import_react6.default.useLayoutEffect(() => {
@@ -2863,20 +2826,19 @@ var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
2863
2826
  if (!el) return;
2864
2827
  const w = el.offsetWidth;
2865
2828
  const h = el.offsetHeight;
2866
- const vw = window.innerWidth;
2867
- let left = clientX + TOOLTIP_OFFSET;
2868
- let top = clientY - h - TOOLTIP_OFFSET;
2869
- if (left + w > vw - 8) left = clientX - w - TOOLTIP_OFFSET;
2870
- if (top < 8) top = clientY + TOOLTIP_OFFSET;
2871
- if (left < 8) left = 8;
2829
+ let left = x + TOOLTIP_OFFSET;
2830
+ let top = y - h - TOOLTIP_OFFSET;
2831
+ if (left + w > containerWidth) left = x - w - TOOLTIP_OFFSET;
2832
+ if (top < 0) top = y + TOOLTIP_OFFSET;
2833
+ if (left < 0) left = 0;
2872
2834
  setPos({ left, top });
2873
- }, [clientX, clientY]);
2835
+ }, [x, y, containerWidth, containerHeight]);
2874
2836
  return /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(
2875
2837
  "div",
2876
2838
  {
2877
2839
  ref,
2878
- className: `chart-tooltip ${visible ? "chart-tooltip-show" : "chart-tooltip-hide"}`,
2879
- style: { position: "fixed", left: pos.left, top: pos.top, zIndex: 1100 },
2840
+ className: "chart-tooltip chart-tooltip-show",
2841
+ style: { left: pos.left, top: pos.top },
2880
2842
  children
2881
2843
  }
2882
2844
  );
@@ -2921,7 +2883,7 @@ var ChartLegend = ({ data, labels, type }) => {
2921
2883
  };
2922
2884
  var Chart = import_react6.default.memo((props) => {
2923
2885
  const { type, data, labels, tooltip: showTooltip = true } = props;
2924
- const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
2886
+ const { tooltip, show, showAt, hide, move, containerRef } = useChartTooltip(showTooltip);
2925
2887
  const { width, height } = useChartSize(containerRef);
2926
2888
  const stableData = import_react6.default.useMemo(() => data, [JSON.stringify(data)]);
2927
2889
  const stableLabels = import_react6.default.useMemo(() => labels, [JSON.stringify(labels)]);
@@ -2929,13 +2891,13 @@ var Chart = import_react6.default.memo((props) => {
2929
2891
  const animate = useChartAnimation(containerRef, dataKey);
2930
2892
  const ready = width > 0 && height > 0;
2931
2893
  return /* @__PURE__ */ (0, import_jsx_runtime307.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
2932
- ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2933
- ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2934
- ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2935
- ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2936
- 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 }),
2894
+ ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2895
+ ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2896
+ ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2897
+ ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2898
+ ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2937
2899
  ready && (type === "bar" || type === "pie" || type === "doughnut") && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(ChartLegend, { data: stableData, labels: stableLabels, type }),
2938
- tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(ChartTooltipPortal, { clientX: tooltip.clientX, clientY: tooltip.clientY, visible: tooltip.visible, children: tooltip.content })
2900
+ tooltip.visible && tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime307.jsx)(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, children: tooltip.content })
2939
2901
  ] });
2940
2902
  });
2941
2903
  Chart.displayName = "Chart";
@@ -1929,11 +1929,14 @@
1929
1929
  width: 100%;
1930
1930
  height: 100%;
1931
1931
  position: relative;
1932
+ display: flex;
1933
+ flex-direction: column;
1932
1934
  }
1933
1935
  .lib-xplat-chart .chart-svg {
1934
1936
  display: block;
1935
1937
  width: 100%;
1936
- height: 100%;
1938
+ flex: 1;
1939
+ min-height: 0;
1937
1940
  will-change: transform;
1938
1941
  contain: layout style paint;
1939
1942
  }
@@ -2017,7 +2020,19 @@
2017
2020
  white-space: nowrap;
2018
2021
  overflow: visible;
2019
2022
  }
2023
+ .lib-xplat-chart .chart-bar-animate {
2024
+ animation: chart-bar-grow 800ms ease-out both;
2025
+ }
2026
+ .lib-xplat-chart .chart-pie-label-animate {
2027
+ opacity: 0;
2028
+ animation: chart-fade-in 150ms ease-out both;
2029
+ }
2030
+ .lib-xplat-chart .chart-area[style*=animationDelay] {
2031
+ animation: chart-fade-in 800ms ease-out both;
2032
+ }
2020
2033
  .lib-xplat-chart .chart-tooltip {
2034
+ position: absolute;
2035
+ z-index: 10;
2021
2036
  padding: var(--spacing-space-3);
2022
2037
  background-color: var(--semantic-surface-neutral-strong);
2023
2038
  color: var(--semantic-text-inverse);
@@ -2028,25 +2043,8 @@
2028
2043
  max-width: 240px;
2029
2044
  pointer-events: none;
2030
2045
  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
2046
  animation: chart-tooltip-in 120ms ease-out;
2035
2047
  }
2036
- .lib-xplat-chart .chart-tooltip.chart-tooltip-hide {
2037
- opacity: 0;
2038
- animation: chart-tooltip-out 80ms ease-in;
2039
- }
2040
- .lib-xplat-chart .chart-bar-animate {
2041
- animation: chart-bar-grow 800ms ease-out both;
2042
- }
2043
- .lib-xplat-chart .chart-pie-label-animate {
2044
- opacity: 0;
2045
- animation: chart-fade-in 150ms ease-out both;
2046
- }
2047
- .lib-xplat-chart .chart-area[style*=animationDelay] {
2048
- animation: chart-fade-in 800ms ease-out both;
2049
- }
2050
2048
  .lib-xplat-chart .chart-legend {
2051
2049
  display: flex;
2052
2050
  flex-wrap: wrap;
@@ -2103,14 +2101,6 @@
2103
2101
  opacity: 1;
2104
2102
  }
2105
2103
  }
2106
- @keyframes chart-tooltip-out {
2107
- from {
2108
- opacity: 1;
2109
- }
2110
- to {
2111
- opacity: 0;
2112
- }
2113
- }
2114
2104
  @media (prefers-reduced-motion: reduce) {
2115
2105
  .lib-xplat-chart .chart-bar-animate,
2116
2106
  .lib-xplat-chart .chart-pie-label-animate,
@@ -2267,8 +2267,8 @@ var TOOLTIP_OFFSET = 12;
2267
2267
  var useChartTooltip = (enabled) => {
2268
2268
  const [tooltip, setTooltip] = React6.useState({
2269
2269
  visible: false,
2270
- clientX: 0,
2271
- clientY: 0,
2270
+ x: 0,
2271
+ y: 0,
2272
2272
  content: ""
2273
2273
  });
2274
2274
  const containerRef = React6.useRef(null);
@@ -2279,18 +2279,26 @@ var useChartTooltip = (enabled) => {
2279
2279
  const cy = e.clientY;
2280
2280
  cancelAnimationFrame(rafRef.current);
2281
2281
  rafRef.current = requestAnimationFrame(() => {
2282
- setTooltip((prev) => ({ ...prev, clientX: cx, clientY: cy }));
2282
+ const rect = containerRef.current?.getBoundingClientRect();
2283
+ if (!rect) return;
2284
+ setTooltip((prev) => ({ ...prev, x: cx - rect.left, y: cy - rect.top }));
2283
2285
  });
2284
2286
  }, [enabled]);
2285
2287
  const show = React6.useCallback((e, content) => {
2286
2288
  if (!enabled) return;
2287
- setTooltip({ visible: true, clientX: e.clientX, clientY: e.clientY, content });
2289
+ const rect = containerRef.current?.getBoundingClientRect();
2290
+ if (!rect) return;
2291
+ setTooltip({ visible: true, x: e.clientX - rect.left, y: e.clientY - rect.top, content });
2292
+ }, [enabled]);
2293
+ const showAt = React6.useCallback((x, y, content) => {
2294
+ if (!enabled) return;
2295
+ setTooltip({ visible: true, x, y, content });
2288
2296
  }, [enabled]);
2289
2297
  const hide = React6.useCallback(() => {
2290
2298
  cancelAnimationFrame(rafRef.current);
2291
2299
  setTooltip((prev) => ({ ...prev, visible: false }));
2292
2300
  }, []);
2293
- return { tooltip, show, hide, move, containerRef };
2301
+ return { tooltip, show, showAt, hide, move, containerRef };
2294
2302
  };
2295
2303
  var GridLines = React6.memo(({ width, height, chartH, maxVal }) => /* @__PURE__ */ jsx307(Fragment2, { children: [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
2296
2304
  const y = PADDING.top + (1 - ratio) * chartH;
@@ -2355,7 +2363,7 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
2355
2363
  }, [entries, seriesPoints]);
2356
2364
  return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
2357
2365
  };
2358
- var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
2366
+ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
2359
2367
  const entries = React6.useMemo(() => Object.entries(data), [data]);
2360
2368
  const maxVal = React6.useMemo(() => {
2361
2369
  const allValues = entries.flatMap(([, v]) => v);
@@ -2395,23 +2403,9 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
2395
2403
  className: "chart-svg",
2396
2404
  onMouseMove: (e) => {
2397
2405
  handleMouseMove(e);
2398
- const svg = e.currentTarget;
2399
- const rect = svg.getBoundingClientRect();
2400
- const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
2401
- const points = seriesPoints[0];
2402
- if (!points || points.length === 0) return;
2403
- const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
2404
- let closest = 0;
2405
- let minDist = Math.abs(points[0].x - mx);
2406
- for (let i = 1; i < points.length; i++) {
2407
- const dist = Math.abs(points[i].x - mx);
2408
- if (dist < minDist) {
2409
- minDist = dist;
2410
- closest = i;
2411
- }
2412
- }
2413
- if (minDist <= step / 2) {
2414
- onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
2406
+ if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
2407
+ const p = seriesPoints[0][activeIndex];
2408
+ onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
2415
2409
  } else {
2416
2410
  onLeave();
2417
2411
  }
@@ -2479,7 +2473,7 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
2479
2473
  );
2480
2474
  });
2481
2475
  LineChart.displayName = "LineChart";
2482
- var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
2476
+ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
2483
2477
  const entries = React6.useMemo(() => Object.entries(data), [data]);
2484
2478
  const maxVal = React6.useMemo(() => {
2485
2479
  const allValues = entries.flatMap(([, v]) => v);
@@ -2519,23 +2513,9 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
2519
2513
  className: "chart-svg",
2520
2514
  onMouseMove: (e) => {
2521
2515
  handleMouseMove(e);
2522
- const svg = e.currentTarget;
2523
- const rect = svg.getBoundingClientRect();
2524
- const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
2525
- const points = seriesPoints[0];
2526
- if (!points || points.length === 0) return;
2527
- const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
2528
- let closest = 0;
2529
- let minDist = Math.abs(points[0].x - mx);
2530
- for (let i = 1; i < points.length; i++) {
2531
- const dist = Math.abs(points[i].x - mx);
2532
- if (dist < minDist) {
2533
- minDist = dist;
2534
- closest = i;
2535
- }
2536
- }
2537
- if (minDist <= step / 2) {
2538
- onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
2516
+ if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
2517
+ const p = seriesPoints[0][activeIndex];
2518
+ onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
2539
2519
  } else {
2540
2520
  onLeave();
2541
2521
  }
@@ -2603,7 +2583,7 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
2603
2583
  );
2604
2584
  });
2605
2585
  CurveChart.displayName = "CurveChart";
2606
- var BarChart = React6.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
2586
+ var BarChart = React6.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
2607
2587
  const entries = React6.useMemo(() => Object.entries(data), [data]);
2608
2588
  const maxVal = React6.useMemo(() => {
2609
2589
  const allValues = entries.flatMap(([, v]) => v);
@@ -2653,8 +2633,7 @@ var BarChart = React6.memo(({ data, labels, width, height, animate, onHover, onM
2653
2633
  transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
2654
2634
  animationDelay: `${delay}ms`
2655
2635
  } : void 0,
2656
- onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
2657
- onMouseMove: onMove,
2636
+ onMouseEnter: () => onShowAt(b.x + b.w / 2, b.y, `${key}: ${labels[i]} \u2014 ${b.v}`),
2658
2637
  onMouseLeave: onLeave
2659
2638
  },
2660
2639
  `${di}-${i}`
@@ -2742,30 +2721,14 @@ var PieDonutChart = React6.memo(
2742
2721
  {
2743
2722
  d: s.d,
2744
2723
  fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
2745
- className: "chart-slice",
2746
- onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
2747
- onMouseMove: onMove,
2748
- onMouseLeave: onLeave
2724
+ className: "chart-slice"
2749
2725
  }
2750
- ) }, i)) }),
2751
- sliceData.map((s, i) => s.angle > 0.2 && /* @__PURE__ */ jsx307(
2752
- "text",
2753
- {
2754
- x: s.lx,
2755
- y: s.ly,
2756
- className: `chart-pie-label ${animate ? "chart-pie-label-animate" : ""}`,
2757
- style: animate ? { animationDelay: `${s.labelDelay}ms` } : void 0,
2758
- textAnchor: "middle",
2759
- dominantBaseline: "central",
2760
- children: s.v
2761
- },
2762
- `label-${i}`
2763
- ))
2726
+ ) }, i)) })
2764
2727
  ] });
2765
2728
  }
2766
2729
  );
2767
2730
  PieDonutChart.displayName = "PieDonutChart";
2768
- var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
2731
+ var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
2769
2732
  const ref = React6.useRef(null);
2770
2733
  const [pos, setPos] = React6.useState({ left: 0, top: 0 });
2771
2734
  React6.useLayoutEffect(() => {
@@ -2773,20 +2736,19 @@ var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
2773
2736
  if (!el) return;
2774
2737
  const w = el.offsetWidth;
2775
2738
  const h = el.offsetHeight;
2776
- const vw = window.innerWidth;
2777
- let left = clientX + TOOLTIP_OFFSET;
2778
- let top = clientY - h - TOOLTIP_OFFSET;
2779
- if (left + w > vw - 8) left = clientX - w - TOOLTIP_OFFSET;
2780
- if (top < 8) top = clientY + TOOLTIP_OFFSET;
2781
- if (left < 8) left = 8;
2739
+ let left = x + TOOLTIP_OFFSET;
2740
+ let top = y - h - TOOLTIP_OFFSET;
2741
+ if (left + w > containerWidth) left = x - w - TOOLTIP_OFFSET;
2742
+ if (top < 0) top = y + TOOLTIP_OFFSET;
2743
+ if (left < 0) left = 0;
2782
2744
  setPos({ left, top });
2783
- }, [clientX, clientY]);
2745
+ }, [x, y, containerWidth, containerHeight]);
2784
2746
  return /* @__PURE__ */ jsx307(
2785
2747
  "div",
2786
2748
  {
2787
2749
  ref,
2788
- className: `chart-tooltip ${visible ? "chart-tooltip-show" : "chart-tooltip-hide"}`,
2789
- style: { position: "fixed", left: pos.left, top: pos.top, zIndex: 1100 },
2750
+ className: "chart-tooltip chart-tooltip-show",
2751
+ style: { left: pos.left, top: pos.top },
2790
2752
  children
2791
2753
  }
2792
2754
  );
@@ -2831,7 +2793,7 @@ var ChartLegend = ({ data, labels, type }) => {
2831
2793
  };
2832
2794
  var Chart = React6.memo((props) => {
2833
2795
  const { type, data, labels, tooltip: showTooltip = true } = props;
2834
- const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
2796
+ const { tooltip, show, showAt, hide, move, containerRef } = useChartTooltip(showTooltip);
2835
2797
  const { width, height } = useChartSize(containerRef);
2836
2798
  const stableData = React6.useMemo(() => data, [JSON.stringify(data)]);
2837
2799
  const stableLabels = React6.useMemo(() => labels, [JSON.stringify(labels)]);
@@ -2839,13 +2801,13 @@ var Chart = React6.memo((props) => {
2839
2801
  const animate = useChartAnimation(containerRef, dataKey);
2840
2802
  const ready = width > 0 && height > 0;
2841
2803
  return /* @__PURE__ */ jsxs197("div", { className: "lib-xplat-chart", ref: containerRef, children: [
2842
- ready && type === "line" && /* @__PURE__ */ jsx307(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2843
- ready && type === "curve" && /* @__PURE__ */ jsx307(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2844
- ready && type === "bar" && /* @__PURE__ */ jsx307(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2845
- ready && type === "pie" && /* @__PURE__ */ jsx307(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2846
- ready && type === "doughnut" && /* @__PURE__ */ jsx307(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
2804
+ ready && type === "line" && /* @__PURE__ */ jsx307(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2805
+ ready && type === "curve" && /* @__PURE__ */ jsx307(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2806
+ ready && type === "bar" && /* @__PURE__ */ jsx307(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2807
+ ready && type === "pie" && /* @__PURE__ */ jsx307(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2808
+ ready && type === "doughnut" && /* @__PURE__ */ jsx307(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
2847
2809
  ready && (type === "bar" || type === "pie" || type === "doughnut") && /* @__PURE__ */ jsx307(ChartLegend, { data: stableData, labels: stableLabels, type }),
2848
- tooltip.content && /* @__PURE__ */ jsx307(ChartTooltipPortal, { clientX: tooltip.clientX, clientY: tooltip.clientY, visible: tooltip.visible, children: tooltip.content })
2810
+ tooltip.visible && tooltip.content && /* @__PURE__ */ jsx307(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, children: tooltip.content })
2849
2811
  ] });
2850
2812
  });
2851
2813
  Chart.displayName = "Chart";