@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.
@@ -163,8 +163,8 @@ var TOOLTIP_OFFSET = 12;
163
163
  var useChartTooltip = (enabled) => {
164
164
  const [tooltip, setTooltip] = import_react.default.useState({
165
165
  visible: false,
166
- clientX: 0,
167
- clientY: 0,
166
+ x: 0,
167
+ y: 0,
168
168
  content: ""
169
169
  });
170
170
  const containerRef = import_react.default.useRef(null);
@@ -175,18 +175,26 @@ var useChartTooltip = (enabled) => {
175
175
  const cy = e.clientY;
176
176
  cancelAnimationFrame(rafRef.current);
177
177
  rafRef.current = requestAnimationFrame(() => {
178
- setTooltip((prev) => ({ ...prev, clientX: cx, clientY: cy }));
178
+ const rect = containerRef.current?.getBoundingClientRect();
179
+ if (!rect) return;
180
+ setTooltip((prev) => ({ ...prev, x: cx - rect.left, y: cy - rect.top }));
179
181
  });
180
182
  }, [enabled]);
181
183
  const show = import_react.default.useCallback((e, content) => {
182
184
  if (!enabled) return;
183
- setTooltip({ visible: true, clientX: e.clientX, clientY: e.clientY, content });
185
+ const rect = containerRef.current?.getBoundingClientRect();
186
+ if (!rect) return;
187
+ setTooltip({ visible: true, x: e.clientX - rect.left, y: e.clientY - rect.top, content });
188
+ }, [enabled]);
189
+ const showAt = import_react.default.useCallback((x, y, content) => {
190
+ if (!enabled) return;
191
+ setTooltip({ visible: true, x, y, content });
184
192
  }, [enabled]);
185
193
  const hide = import_react.default.useCallback(() => {
186
194
  cancelAnimationFrame(rafRef.current);
187
195
  setTooltip((prev) => ({ ...prev, visible: false }));
188
196
  }, []);
189
- return { tooltip, show, hide, move, containerRef };
197
+ return { tooltip, show, showAt, hide, move, containerRef };
190
198
  };
191
199
  var GridLines = import_react.default.memo(({ width, height, chartH, maxVal }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
192
200
  const y = PADDING.top + (1 - ratio) * chartH;
@@ -251,7 +259,7 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
251
259
  }, [entries, seriesPoints]);
252
260
  return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
253
261
  };
254
- var LineChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
262
+ var LineChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
255
263
  const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
256
264
  const maxVal = import_react.default.useMemo(() => {
257
265
  const allValues = entries.flatMap(([, v]) => v);
@@ -291,23 +299,9 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
291
299
  className: "chart-svg",
292
300
  onMouseMove: (e) => {
293
301
  handleMouseMove(e);
294
- const svg = e.currentTarget;
295
- const rect = svg.getBoundingClientRect();
296
- const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
297
- const points = seriesPoints[0];
298
- if (!points || points.length === 0) return;
299
- const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
300
- let closest = 0;
301
- let minDist = Math.abs(points[0].x - mx);
302
- for (let i = 1; i < points.length; i++) {
303
- const dist = Math.abs(points[i].x - mx);
304
- if (dist < minDist) {
305
- minDist = dist;
306
- closest = i;
307
- }
308
- }
309
- if (minDist <= step / 2) {
310
- onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
302
+ if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
303
+ const p = seriesPoints[0][activeIndex];
304
+ onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
311
305
  } else {
312
306
  onLeave();
313
307
  }
@@ -375,7 +369,7 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
375
369
  );
376
370
  });
377
371
  LineChart.displayName = "LineChart";
378
- var CurveChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
372
+ var CurveChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
379
373
  const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
380
374
  const maxVal = import_react.default.useMemo(() => {
381
375
  const allValues = entries.flatMap(([, v]) => v);
@@ -415,23 +409,9 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
415
409
  className: "chart-svg",
416
410
  onMouseMove: (e) => {
417
411
  handleMouseMove(e);
418
- const svg = e.currentTarget;
419
- const rect = svg.getBoundingClientRect();
420
- const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
421
- const points = seriesPoints[0];
422
- if (!points || points.length === 0) return;
423
- const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
424
- let closest = 0;
425
- let minDist = Math.abs(points[0].x - mx);
426
- for (let i = 1; i < points.length; i++) {
427
- const dist = Math.abs(points[i].x - mx);
428
- if (dist < minDist) {
429
- minDist = dist;
430
- closest = i;
431
- }
432
- }
433
- if (minDist <= step / 2) {
434
- onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
412
+ if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
413
+ const p = seriesPoints[0][activeIndex];
414
+ onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
435
415
  } else {
436
416
  onLeave();
437
417
  }
@@ -499,7 +479,7 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
499
479
  );
500
480
  });
501
481
  CurveChart.displayName = "CurveChart";
502
- var BarChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
482
+ var BarChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
503
483
  const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
504
484
  const maxVal = import_react.default.useMemo(() => {
505
485
  const allValues = entries.flatMap(([, v]) => v);
@@ -549,8 +529,7 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, animate
549
529
  transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
550
530
  animationDelay: `${delay}ms`
551
531
  } : void 0,
552
- onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
553
- onMouseMove: onMove,
532
+ onMouseEnter: () => onShowAt(b.x + b.w / 2, b.y, `${key}: ${labels[i]} \u2014 ${b.v}`),
554
533
  onMouseLeave: onLeave
555
534
  },
556
535
  `${di}-${i}`
@@ -638,30 +617,14 @@ var PieDonutChart = import_react.default.memo(
638
617
  {
639
618
  d: s.d,
640
619
  fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
641
- className: "chart-slice",
642
- onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
643
- onMouseMove: onMove,
644
- onMouseLeave: onLeave
620
+ className: "chart-slice"
645
621
  }
646
- ) }, i)) }),
647
- sliceData.map((s, i) => s.angle > 0.2 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
648
- "text",
649
- {
650
- x: s.lx,
651
- y: s.ly,
652
- className: `chart-pie-label ${animate ? "chart-pie-label-animate" : ""}`,
653
- style: animate ? { animationDelay: `${s.labelDelay}ms` } : void 0,
654
- textAnchor: "middle",
655
- dominantBaseline: "central",
656
- children: s.v
657
- },
658
- `label-${i}`
659
- ))
622
+ ) }, i)) })
660
623
  ] });
661
624
  }
662
625
  );
663
626
  PieDonutChart.displayName = "PieDonutChart";
664
- var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
627
+ var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
665
628
  const ref = import_react.default.useRef(null);
666
629
  const [pos, setPos] = import_react.default.useState({ left: 0, top: 0 });
667
630
  import_react.default.useLayoutEffect(() => {
@@ -669,20 +632,19 @@ var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
669
632
  if (!el) return;
670
633
  const w = el.offsetWidth;
671
634
  const h = el.offsetHeight;
672
- const vw = window.innerWidth;
673
- let left = clientX + TOOLTIP_OFFSET;
674
- let top = clientY - h - TOOLTIP_OFFSET;
675
- if (left + w > vw - 8) left = clientX - w - TOOLTIP_OFFSET;
676
- if (top < 8) top = clientY + TOOLTIP_OFFSET;
677
- if (left < 8) left = 8;
635
+ let left = x + TOOLTIP_OFFSET;
636
+ let top = y - h - TOOLTIP_OFFSET;
637
+ if (left + w > containerWidth) left = x - w - TOOLTIP_OFFSET;
638
+ if (top < 0) top = y + TOOLTIP_OFFSET;
639
+ if (left < 0) left = 0;
678
640
  setPos({ left, top });
679
- }, [clientX, clientY]);
641
+ }, [x, y, containerWidth, containerHeight]);
680
642
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
681
643
  "div",
682
644
  {
683
645
  ref,
684
- className: `chart-tooltip ${visible ? "chart-tooltip-show" : "chart-tooltip-hide"}`,
685
- style: { position: "fixed", left: pos.left, top: pos.top, zIndex: 1100 },
646
+ className: "chart-tooltip chart-tooltip-show",
647
+ style: { left: pos.left, top: pos.top },
686
648
  children
687
649
  }
688
650
  );
@@ -727,7 +689,7 @@ var ChartLegend = ({ data, labels, type }) => {
727
689
  };
728
690
  var Chart = import_react.default.memo((props) => {
729
691
  const { type, data, labels, tooltip: showTooltip = true } = props;
730
- const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
692
+ const { tooltip, show, showAt, hide, move, containerRef } = useChartTooltip(showTooltip);
731
693
  const { width, height } = useChartSize(containerRef);
732
694
  const stableData = import_react.default.useMemo(() => data, [JSON.stringify(data)]);
733
695
  const stableLabels = import_react.default.useMemo(() => labels, [JSON.stringify(labels)]);
@@ -735,13 +697,13 @@ var Chart = import_react.default.memo((props) => {
735
697
  const animate = useChartAnimation(containerRef, dataKey);
736
698
  const ready = width > 0 && height > 0;
737
699
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
738
- ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
739
- ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
740
- ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
741
- ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
742
- 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 }),
700
+ ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
701
+ ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
702
+ ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
703
+ ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
704
+ ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
743
705
  ready && (type === "bar" || type === "pie" || type === "doughnut") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartLegend, { data: stableData, labels: stableLabels, type }),
744
- tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartTooltipPortal, { clientX: tooltip.clientX, clientY: tooltip.clientY, visible: tooltip.visible, children: tooltip.content })
706
+ tooltip.visible && tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, children: tooltip.content })
745
707
  ] });
746
708
  });
747
709
  Chart.displayName = "Chart";
@@ -4,11 +4,14 @@
4
4
  width: 100%;
5
5
  height: 100%;
6
6
  position: relative;
7
+ display: flex;
8
+ flex-direction: column;
7
9
  }
8
10
  .lib-xplat-chart .chart-svg {
9
11
  display: block;
10
12
  width: 100%;
11
- height: 100%;
13
+ flex: 1;
14
+ min-height: 0;
12
15
  will-change: transform;
13
16
  contain: layout style paint;
14
17
  }
@@ -92,7 +95,19 @@
92
95
  white-space: nowrap;
93
96
  overflow: visible;
94
97
  }
98
+ .lib-xplat-chart .chart-bar-animate {
99
+ animation: chart-bar-grow 800ms ease-out both;
100
+ }
101
+ .lib-xplat-chart .chart-pie-label-animate {
102
+ opacity: 0;
103
+ animation: chart-fade-in 150ms ease-out both;
104
+ }
105
+ .lib-xplat-chart .chart-area[style*=animationDelay] {
106
+ animation: chart-fade-in 800ms ease-out both;
107
+ }
95
108
  .lib-xplat-chart .chart-tooltip {
109
+ position: absolute;
110
+ z-index: 10;
96
111
  padding: var(--spacing-space-3);
97
112
  background-color: var(--semantic-surface-neutral-strong);
98
113
  color: var(--semantic-text-inverse);
@@ -103,25 +118,8 @@
103
118
  max-width: 240px;
104
119
  pointer-events: none;
105
120
  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
121
  animation: chart-tooltip-in 120ms ease-out;
110
122
  }
111
- .lib-xplat-chart .chart-tooltip.chart-tooltip-hide {
112
- opacity: 0;
113
- animation: chart-tooltip-out 80ms ease-in;
114
- }
115
- .lib-xplat-chart .chart-bar-animate {
116
- animation: chart-bar-grow 800ms ease-out both;
117
- }
118
- .lib-xplat-chart .chart-pie-label-animate {
119
- opacity: 0;
120
- animation: chart-fade-in 150ms ease-out both;
121
- }
122
- .lib-xplat-chart .chart-area[style*=animationDelay] {
123
- animation: chart-fade-in 800ms ease-out both;
124
- }
125
123
  .lib-xplat-chart .chart-legend {
126
124
  display: flex;
127
125
  flex-wrap: wrap;
@@ -178,14 +176,6 @@
178
176
  opacity: 1;
179
177
  }
180
178
  }
181
- @keyframes chart-tooltip-out {
182
- from {
183
- opacity: 1;
184
- }
185
- to {
186
- opacity: 0;
187
- }
188
- }
189
179
  @media (prefers-reduced-motion: reduce) {
190
180
  .lib-xplat-chart .chart-bar-animate,
191
181
  .lib-xplat-chart .chart-pie-label-animate,
@@ -127,8 +127,8 @@ var TOOLTIP_OFFSET = 12;
127
127
  var useChartTooltip = (enabled) => {
128
128
  const [tooltip, setTooltip] = React.useState({
129
129
  visible: false,
130
- clientX: 0,
131
- clientY: 0,
130
+ x: 0,
131
+ y: 0,
132
132
  content: ""
133
133
  });
134
134
  const containerRef = React.useRef(null);
@@ -139,18 +139,26 @@ var useChartTooltip = (enabled) => {
139
139
  const cy = e.clientY;
140
140
  cancelAnimationFrame(rafRef.current);
141
141
  rafRef.current = requestAnimationFrame(() => {
142
- setTooltip((prev) => ({ ...prev, clientX: cx, clientY: cy }));
142
+ const rect = containerRef.current?.getBoundingClientRect();
143
+ if (!rect) return;
144
+ setTooltip((prev) => ({ ...prev, x: cx - rect.left, y: cy - rect.top }));
143
145
  });
144
146
  }, [enabled]);
145
147
  const show = React.useCallback((e, content) => {
146
148
  if (!enabled) return;
147
- setTooltip({ visible: true, clientX: e.clientX, clientY: e.clientY, content });
149
+ const rect = containerRef.current?.getBoundingClientRect();
150
+ if (!rect) return;
151
+ setTooltip({ visible: true, x: e.clientX - rect.left, y: e.clientY - rect.top, content });
152
+ }, [enabled]);
153
+ const showAt = React.useCallback((x, y, content) => {
154
+ if (!enabled) return;
155
+ setTooltip({ visible: true, x, y, content });
148
156
  }, [enabled]);
149
157
  const hide = React.useCallback(() => {
150
158
  cancelAnimationFrame(rafRef.current);
151
159
  setTooltip((prev) => ({ ...prev, visible: false }));
152
160
  }, []);
153
- return { tooltip, show, hide, move, containerRef };
161
+ return { tooltip, show, showAt, hide, move, containerRef };
154
162
  };
155
163
  var GridLines = React.memo(({ width, height, chartH, maxVal }) => /* @__PURE__ */ jsx(Fragment, { children: [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
156
164
  const y = PADDING.top + (1 - ratio) * chartH;
@@ -215,7 +223,7 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
215
223
  }, [entries, seriesPoints]);
216
224
  return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
217
225
  };
218
- var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
226
+ var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
219
227
  const entries = React.useMemo(() => Object.entries(data), [data]);
220
228
  const maxVal = React.useMemo(() => {
221
229
  const allValues = entries.flatMap(([, v]) => v);
@@ -255,23 +263,9 @@ var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onM
255
263
  className: "chart-svg",
256
264
  onMouseMove: (e) => {
257
265
  handleMouseMove(e);
258
- const svg = e.currentTarget;
259
- const rect = svg.getBoundingClientRect();
260
- const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
261
- const points = seriesPoints[0];
262
- if (!points || points.length === 0) return;
263
- const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
264
- let closest = 0;
265
- let minDist = Math.abs(points[0].x - mx);
266
- for (let i = 1; i < points.length; i++) {
267
- const dist = Math.abs(points[i].x - mx);
268
- if (dist < minDist) {
269
- minDist = dist;
270
- closest = i;
271
- }
272
- }
273
- if (minDist <= step / 2) {
274
- onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
266
+ if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
267
+ const p = seriesPoints[0][activeIndex];
268
+ onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
275
269
  } else {
276
270
  onLeave();
277
271
  }
@@ -339,7 +333,7 @@ var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onM
339
333
  );
340
334
  });
341
335
  LineChart.displayName = "LineChart";
342
- var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
336
+ var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
343
337
  const entries = React.useMemo(() => Object.entries(data), [data]);
344
338
  const maxVal = React.useMemo(() => {
345
339
  const allValues = entries.flatMap(([, v]) => v);
@@ -379,23 +373,9 @@ var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, on
379
373
  className: "chart-svg",
380
374
  onMouseMove: (e) => {
381
375
  handleMouseMove(e);
382
- const svg = e.currentTarget;
383
- const rect = svg.getBoundingClientRect();
384
- const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
385
- const points = seriesPoints[0];
386
- if (!points || points.length === 0) return;
387
- const step = points.length > 1 ? Math.abs(points[1].x - points[0].x) : 20;
388
- let closest = 0;
389
- let minDist = Math.abs(points[0].x - mx);
390
- for (let i = 1; i < points.length; i++) {
391
- const dist = Math.abs(points[i].x - mx);
392
- if (dist < minDist) {
393
- minDist = dist;
394
- closest = i;
395
- }
396
- }
397
- if (minDist <= step / 2) {
398
- onHover(e, `${labels[closest]} \u2014 ${getTooltipAt(closest)}`);
376
+ if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
377
+ const p = seriesPoints[0][activeIndex];
378
+ onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
399
379
  } else {
400
380
  onLeave();
401
381
  }
@@ -463,7 +443,7 @@ var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, on
463
443
  );
464
444
  });
465
445
  CurveChart.displayName = "CurveChart";
466
- var BarChart = React.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
446
+ var BarChart = React.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
467
447
  const entries = React.useMemo(() => Object.entries(data), [data]);
468
448
  const maxVal = React.useMemo(() => {
469
449
  const allValues = entries.flatMap(([, v]) => v);
@@ -513,8 +493,7 @@ var BarChart = React.memo(({ data, labels, width, height, animate, onHover, onMo
513
493
  transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
514
494
  animationDelay: `${delay}ms`
515
495
  } : void 0,
516
- onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
517
- onMouseMove: onMove,
496
+ onMouseEnter: () => onShowAt(b.x + b.w / 2, b.y, `${key}: ${labels[i]} \u2014 ${b.v}`),
518
497
  onMouseLeave: onLeave
519
498
  },
520
499
  `${di}-${i}`
@@ -602,30 +581,14 @@ var PieDonutChart = React.memo(
602
581
  {
603
582
  d: s.d,
604
583
  fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
605
- className: "chart-slice",
606
- onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
607
- onMouseMove: onMove,
608
- onMouseLeave: onLeave
584
+ className: "chart-slice"
609
585
  }
610
- ) }, i)) }),
611
- sliceData.map((s, i) => s.angle > 0.2 && /* @__PURE__ */ jsx(
612
- "text",
613
- {
614
- x: s.lx,
615
- y: s.ly,
616
- className: `chart-pie-label ${animate ? "chart-pie-label-animate" : ""}`,
617
- style: animate ? { animationDelay: `${s.labelDelay}ms` } : void 0,
618
- textAnchor: "middle",
619
- dominantBaseline: "central",
620
- children: s.v
621
- },
622
- `label-${i}`
623
- ))
586
+ ) }, i)) })
624
587
  ] });
625
588
  }
626
589
  );
627
590
  PieDonutChart.displayName = "PieDonutChart";
628
- var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
591
+ var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
629
592
  const ref = React.useRef(null);
630
593
  const [pos, setPos] = React.useState({ left: 0, top: 0 });
631
594
  React.useLayoutEffect(() => {
@@ -633,20 +596,19 @@ var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
633
596
  if (!el) return;
634
597
  const w = el.offsetWidth;
635
598
  const h = el.offsetHeight;
636
- const vw = window.innerWidth;
637
- let left = clientX + TOOLTIP_OFFSET;
638
- let top = clientY - h - TOOLTIP_OFFSET;
639
- if (left + w > vw - 8) left = clientX - w - TOOLTIP_OFFSET;
640
- if (top < 8) top = clientY + TOOLTIP_OFFSET;
641
- if (left < 8) left = 8;
599
+ let left = x + TOOLTIP_OFFSET;
600
+ let top = y - h - TOOLTIP_OFFSET;
601
+ if (left + w > containerWidth) left = x - w - TOOLTIP_OFFSET;
602
+ if (top < 0) top = y + TOOLTIP_OFFSET;
603
+ if (left < 0) left = 0;
642
604
  setPos({ left, top });
643
- }, [clientX, clientY]);
605
+ }, [x, y, containerWidth, containerHeight]);
644
606
  return /* @__PURE__ */ jsx(
645
607
  "div",
646
608
  {
647
609
  ref,
648
- className: `chart-tooltip ${visible ? "chart-tooltip-show" : "chart-tooltip-hide"}`,
649
- style: { position: "fixed", left: pos.left, top: pos.top, zIndex: 1100 },
610
+ className: "chart-tooltip chart-tooltip-show",
611
+ style: { left: pos.left, top: pos.top },
650
612
  children
651
613
  }
652
614
  );
@@ -691,7 +653,7 @@ var ChartLegend = ({ data, labels, type }) => {
691
653
  };
692
654
  var Chart = React.memo((props) => {
693
655
  const { type, data, labels, tooltip: showTooltip = true } = props;
694
- const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
656
+ const { tooltip, show, showAt, hide, move, containerRef } = useChartTooltip(showTooltip);
695
657
  const { width, height } = useChartSize(containerRef);
696
658
  const stableData = React.useMemo(() => data, [JSON.stringify(data)]);
697
659
  const stableLabels = React.useMemo(() => labels, [JSON.stringify(labels)]);
@@ -699,13 +661,13 @@ var Chart = React.memo((props) => {
699
661
  const animate = useChartAnimation(containerRef, dataKey);
700
662
  const ready = width > 0 && height > 0;
701
663
  return /* @__PURE__ */ jsxs("div", { className: "lib-xplat-chart", ref: containerRef, children: [
702
- ready && type === "line" && /* @__PURE__ */ jsx(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
703
- ready && type === "curve" && /* @__PURE__ */ jsx(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
704
- ready && type === "bar" && /* @__PURE__ */ jsx(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
705
- ready && type === "pie" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
706
- ready && type === "doughnut" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
664
+ ready && type === "line" && /* @__PURE__ */ jsx(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
665
+ ready && type === "curve" && /* @__PURE__ */ jsx(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
666
+ ready && type === "bar" && /* @__PURE__ */ jsx(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
667
+ ready && type === "pie" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
668
+ ready && type === "doughnut" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
707
669
  ready && (type === "bar" || type === "pie" || type === "doughnut") && /* @__PURE__ */ jsx(ChartLegend, { data: stableData, labels: stableLabels, type }),
708
- tooltip.content && /* @__PURE__ */ jsx(ChartTooltipPortal, { clientX: tooltip.clientX, clientY: tooltip.clientY, visible: tooltip.visible, children: tooltip.content })
670
+ tooltip.visible && tooltip.content && /* @__PURE__ */ jsx(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, children: tooltip.content })
709
671
  ] });
710
672
  });
711
673
  Chart.displayName = "Chart";