@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.
@@ -186,28 +186,11 @@ var useChartTooltip = (enabled) => {
186
186
  if (!rect) return;
187
187
  setTooltip({ visible: true, x: e.clientX - rect.left, y: e.clientY - rect.top, content });
188
188
  }, [enabled]);
189
- const showAt = import_react.default.useCallback((svgX, svgY, content, svgEl) => {
190
- if (!enabled) return;
191
- const container = containerRef.current;
192
- if (!container) return;
193
- let x = svgX;
194
- let y = svgY;
195
- if (svgEl) {
196
- const svgRect = svgEl.getBoundingClientRect();
197
- const containerRect = container.getBoundingClientRect();
198
- const vb = svgEl.viewBox.baseVal;
199
- const scaleX = svgRect.width / (vb.width || 1);
200
- const scaleY = svgRect.height / (vb.height || 1);
201
- x = svgX * scaleX + (svgRect.left - containerRect.left);
202
- y = svgY * scaleY + (svgRect.top - containerRect.top);
203
- }
204
- setTooltip({ visible: true, x, y, content });
205
- }, [enabled]);
206
189
  const hide = import_react.default.useCallback(() => {
207
190
  cancelAnimationFrame(rafRef.current);
208
191
  setTooltip((prev) => ({ ...prev, visible: false }));
209
192
  }, []);
210
- return { tooltip, show, showAt, hide, move, containerRef };
193
+ return { tooltip, show, hide, move, containerRef };
211
194
  };
212
195
  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) => {
213
196
  const y = PADDING.top + (1 - ratio) * chartH;
@@ -272,7 +255,7 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
272
255
  }, [entries, seriesPoints]);
273
256
  return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
274
257
  };
275
- var LineChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
258
+ var LineChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
276
259
  const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
277
260
  const maxVal = import_react.default.useMemo(() => {
278
261
  const allValues = entries.flatMap(([, v]) => v);
@@ -292,7 +275,6 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
292
275
  [entries, count, chartW, chartH, maxVal]
293
276
  );
294
277
  const clipRef = import_react.default.useRef(null);
295
- const svgRef = import_react.default.useRef(null);
296
278
  const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
297
279
  import_react.default.useEffect(() => {
298
280
  if (!animate || !clipRef.current) return;
@@ -309,14 +291,12 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
309
291
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
310
292
  "svg",
311
293
  {
312
- ref: svgRef,
313
294
  viewBox: `0 0 ${width} ${height}`,
314
295
  className: "chart-svg",
315
296
  onMouseMove: (e) => {
316
297
  handleMouseMove(e);
317
- if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
318
- const p = seriesPoints[0][activeIndex];
319
- onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`, svgRef.current);
298
+ if (activeIndex !== null) {
299
+ onHover(e, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
320
300
  } else {
321
301
  onLeave();
322
302
  }
@@ -384,7 +364,7 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
384
364
  );
385
365
  });
386
366
  LineChart.displayName = "LineChart";
387
- var CurveChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
367
+ var CurveChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
388
368
  const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
389
369
  const maxVal = import_react.default.useMemo(() => {
390
370
  const allValues = entries.flatMap(([, v]) => v);
@@ -404,7 +384,6 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
404
384
  [entries, count, chartW, chartH, maxVal]
405
385
  );
406
386
  const curveClipRef = import_react.default.useRef(null);
407
- const curveSvgRef = import_react.default.useRef(null);
408
387
  const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
409
388
  import_react.default.useEffect(() => {
410
389
  if (!animate || !curveClipRef.current) return;
@@ -421,14 +400,13 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
421
400
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
422
401
  "svg",
423
402
  {
424
- ref: curveSvgRef,
425
403
  viewBox: `0 0 ${width} ${height}`,
426
404
  className: "chart-svg",
427
405
  onMouseMove: (e) => {
428
406
  handleMouseMove(e);
429
407
  if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
430
408
  const p = seriesPoints[0][activeIndex];
431
- onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`, curveSvgRef.current);
409
+ onHover(e, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
432
410
  } else {
433
411
  onLeave();
434
412
  }
@@ -496,8 +474,7 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
496
474
  );
497
475
  });
498
476
  CurveChart.displayName = "CurveChart";
499
- var BarChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
500
- const barSvgRef = import_react.default.useRef(null);
477
+ var BarChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
501
478
  const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
502
479
  const maxVal = import_react.default.useMemo(() => {
503
480
  const allValues = entries.flatMap(([, v]) => v);
@@ -524,7 +501,7 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, animate
524
501
  [entries, maxVal, chartH, groupW, barW, barGap, groupCount]
525
502
  );
526
503
  const barLabelStep = getLabelStep(count, chartW);
527
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ref: barSvgRef, viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
504
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
528
505
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GridLines, { width, height, chartH, maxVal }),
529
506
  labels.map((label, i) => {
530
507
  if (i % barLabelStep !== 0) return null;
@@ -547,7 +524,8 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, animate
547
524
  transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
548
525
  animationDelay: `${delay}ms`
549
526
  } : void 0,
550
- onMouseEnter: () => onShowAt(b.x + b.w / 2, b.y, `${key}: ${labels[i]} \u2014 ${b.v}`, barSvgRef.current),
527
+ onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
528
+ onMouseMove: onMove,
551
529
  onMouseLeave: onLeave
552
530
  },
553
531
  `${di}-${i}`
@@ -635,14 +613,17 @@ var PieDonutChart = import_react.default.memo(
635
613
  {
636
614
  d: s.d,
637
615
  fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
638
- className: "chart-slice"
616
+ className: "chart-slice",
617
+ onMouseEnter: (e) => onHover(e, `${s.label} \u2014 ${s.v.toLocaleString()} (${s.pct}%)`),
618
+ onMouseMove: onMove,
619
+ onMouseLeave: onLeave
639
620
  }
640
621
  ) }, i)) })
641
622
  ] });
642
623
  }
643
624
  );
644
625
  PieDonutChart.displayName = "PieDonutChart";
645
- var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
626
+ var ChartTooltip = ({ x, y, containerWidth, containerHeight, tooltipType, children }) => {
646
627
  const ref = import_react.default.useRef(null);
647
628
  const [pos, setPos] = import_react.default.useState({ left: 0, top: 0 });
648
629
  import_react.default.useLayoutEffect(() => {
@@ -653,17 +634,25 @@ var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
653
634
  let left = x + TOOLTIP_OFFSET;
654
635
  let top = y - h - TOOLTIP_OFFSET;
655
636
  if (left + w > containerWidth) left = x - w - TOOLTIP_OFFSET;
656
- if (top < 0) top = y + TOOLTIP_OFFSET;
657
637
  if (left < 0) left = 0;
638
+ if (top < 0) top = y + TOOLTIP_OFFSET;
639
+ if (top + h > containerHeight) top = containerHeight - h;
658
640
  setPos({ left, top });
659
641
  }, [x, y, containerWidth, containerHeight]);
660
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
642
+ const content = typeof children === "string" ? children : "";
643
+ const sepIdx = content.indexOf(" \u2014 ");
644
+ const title = sepIdx >= 0 ? content.slice(0, sepIdx) : content;
645
+ const desc = sepIdx >= 0 ? content.slice(sepIdx + 3) : "";
646
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
661
647
  "div",
662
648
  {
663
649
  ref,
664
- className: "chart-tooltip chart-tooltip-show",
650
+ className: `chart-tooltip chart-tooltip-show chart-tooltip-${tooltipType}`,
665
651
  style: { left: pos.left, top: pos.top },
666
- children
652
+ children: [
653
+ title && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "chart-tooltip-title", children: title }),
654
+ desc && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "chart-tooltip-desc", children: desc })
655
+ ]
667
656
  }
668
657
  );
669
658
  };
@@ -706,8 +695,8 @@ var ChartLegend = ({ data, labels, type }) => {
706
695
  }) });
707
696
  };
708
697
  var Chart = import_react.default.memo((props) => {
709
- const { type, data, labels, tooltip: showTooltip = true } = props;
710
- const { tooltip, show, showAt, hide, move, containerRef } = useChartTooltip(showTooltip);
698
+ const { type, data, labels, tooltip: showTooltip = true, tooltipType = "dark" } = props;
699
+ const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
711
700
  const { width, height } = useChartSize(containerRef);
712
701
  const stableData = import_react.default.useMemo(() => data, [JSON.stringify(data)]);
713
702
  const stableLabels = import_react.default.useMemo(() => labels, [JSON.stringify(labels)]);
@@ -715,13 +704,13 @@ var Chart = import_react.default.memo((props) => {
715
704
  const animate = useChartAnimation(containerRef, dataKey);
716
705
  const ready = width > 0 && height > 0;
717
706
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
718
- 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 }),
719
- 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 }),
720
- 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 }),
721
- 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 }),
722
- 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 }),
707
+ ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
708
+ ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
709
+ ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
710
+ ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
711
+ 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 }),
723
712
  ready && (type === "pie" || type === "doughnut") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartLegend, { data: stableData, labels: stableLabels, type }),
724
- tooltip.visible && tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, children: tooltip.content })
713
+ tooltip.visible && tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, tooltipType, children: tooltip.content })
725
714
  ] });
726
715
  });
727
716
  Chart.displayName = "Chart";
@@ -109,17 +109,37 @@
109
109
  position: absolute;
110
110
  z-index: 10;
111
111
  padding: var(--spacing-space-3);
112
- background-color: var(--semantic-surface-neutral-strong);
113
- color: var(--semantic-text-inverse);
114
- font-size: 12px;
115
- line-height: 18px;
116
- font-weight: 500;
117
112
  border-radius: var(--spacing-radius-md);
118
113
  max-width: 240px;
119
114
  pointer-events: none;
120
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
121
115
  animation: chart-tooltip-in 120ms ease-out;
122
116
  }
117
+ .lib-xplat-chart .chart-tooltip .chart-tooltip-title {
118
+ font-size: 13px;
119
+ line-height: 18px;
120
+ font-weight: 400;
121
+ }
122
+ .lib-xplat-chart .chart-tooltip .chart-tooltip-desc {
123
+ font-size: 12px;
124
+ line-height: 18px;
125
+ font-weight: 400;
126
+ }
127
+ .lib-xplat-chart .chart-tooltip.chart-tooltip-dark {
128
+ background-color: var(--semantic-surface-neutral-strong);
129
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
130
+ }
131
+ .lib-xplat-chart .chart-tooltip.chart-tooltip-dark .chart-tooltip-title,
132
+ .lib-xplat-chart .chart-tooltip.chart-tooltip-dark .chart-tooltip-desc {
133
+ color: var(--semantic-text-inverse);
134
+ }
135
+ .lib-xplat-chart .chart-tooltip.chart-tooltip-light {
136
+ background-color: var(--semantic-surface-neutral-default);
137
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
138
+ }
139
+ .lib-xplat-chart .chart-tooltip.chart-tooltip-light .chart-tooltip-title,
140
+ .lib-xplat-chart .chart-tooltip.chart-tooltip-light .chart-tooltip-desc {
141
+ color: var(--semantic-text-subtle);
142
+ }
123
143
  .lib-xplat-chart .chart-legend {
124
144
  display: flex;
125
145
  flex-wrap: wrap;
@@ -5,6 +5,7 @@ interface ChartProps {
5
5
  data: Record<string, number[]>;
6
6
  labels: string[];
7
7
  tooltip?: boolean;
8
+ tooltipType?: "dark" | "light";
8
9
  }
9
10
  declare const Chart: React.NamedExoticComponent<ChartProps>;
10
11
 
@@ -5,6 +5,7 @@ interface ChartProps {
5
5
  data: Record<string, number[]>;
6
6
  labels: string[];
7
7
  tooltip?: boolean;
8
+ tooltipType?: "dark" | "light";
8
9
  }
9
10
  declare const Chart: React.NamedExoticComponent<ChartProps>;
10
11
 
@@ -150,28 +150,11 @@ var useChartTooltip = (enabled) => {
150
150
  if (!rect) return;
151
151
  setTooltip({ visible: true, x: e.clientX - rect.left, y: e.clientY - rect.top, content });
152
152
  }, [enabled]);
153
- const showAt = React.useCallback((svgX, svgY, content, svgEl) => {
154
- if (!enabled) return;
155
- const container = containerRef.current;
156
- if (!container) return;
157
- let x = svgX;
158
- let y = svgY;
159
- if (svgEl) {
160
- const svgRect = svgEl.getBoundingClientRect();
161
- const containerRect = container.getBoundingClientRect();
162
- const vb = svgEl.viewBox.baseVal;
163
- const scaleX = svgRect.width / (vb.width || 1);
164
- const scaleY = svgRect.height / (vb.height || 1);
165
- x = svgX * scaleX + (svgRect.left - containerRect.left);
166
- y = svgY * scaleY + (svgRect.top - containerRect.top);
167
- }
168
- setTooltip({ visible: true, x, y, content });
169
- }, [enabled]);
170
153
  const hide = React.useCallback(() => {
171
154
  cancelAnimationFrame(rafRef.current);
172
155
  setTooltip((prev) => ({ ...prev, visible: false }));
173
156
  }, []);
174
- return { tooltip, show, showAt, hide, move, containerRef };
157
+ return { tooltip, show, hide, move, containerRef };
175
158
  };
176
159
  var GridLines = React.memo(({ width, height, chartH, maxVal }) => /* @__PURE__ */ jsx(Fragment, { children: [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
177
160
  const y = PADDING.top + (1 - ratio) * chartH;
@@ -236,7 +219,7 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
236
219
  }, [entries, seriesPoints]);
237
220
  return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
238
221
  };
239
- var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
222
+ var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
240
223
  const entries = React.useMemo(() => Object.entries(data), [data]);
241
224
  const maxVal = React.useMemo(() => {
242
225
  const allValues = entries.flatMap(([, v]) => v);
@@ -256,7 +239,6 @@ var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onS
256
239
  [entries, count, chartW, chartH, maxVal]
257
240
  );
258
241
  const clipRef = React.useRef(null);
259
- const svgRef = React.useRef(null);
260
242
  const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
261
243
  React.useEffect(() => {
262
244
  if (!animate || !clipRef.current) return;
@@ -273,14 +255,12 @@ var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onS
273
255
  return /* @__PURE__ */ jsxs(
274
256
  "svg",
275
257
  {
276
- ref: svgRef,
277
258
  viewBox: `0 0 ${width} ${height}`,
278
259
  className: "chart-svg",
279
260
  onMouseMove: (e) => {
280
261
  handleMouseMove(e);
281
- if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
282
- const p = seriesPoints[0][activeIndex];
283
- onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`, svgRef.current);
262
+ if (activeIndex !== null) {
263
+ onHover(e, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
284
264
  } else {
285
265
  onLeave();
286
266
  }
@@ -348,7 +328,7 @@ var LineChart = React.memo(({ data, labels, width, height, animate, onHover, onS
348
328
  );
349
329
  });
350
330
  LineChart.displayName = "LineChart";
351
- var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
331
+ var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
352
332
  const entries = React.useMemo(() => Object.entries(data), [data]);
353
333
  const maxVal = React.useMemo(() => {
354
334
  const allValues = entries.flatMap(([, v]) => v);
@@ -368,7 +348,6 @@ var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, on
368
348
  [entries, count, chartW, chartH, maxVal]
369
349
  );
370
350
  const curveClipRef = React.useRef(null);
371
- const curveSvgRef = React.useRef(null);
372
351
  const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
373
352
  React.useEffect(() => {
374
353
  if (!animate || !curveClipRef.current) return;
@@ -385,14 +364,13 @@ var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, on
385
364
  return /* @__PURE__ */ jsxs(
386
365
  "svg",
387
366
  {
388
- ref: curveSvgRef,
389
367
  viewBox: `0 0 ${width} ${height}`,
390
368
  className: "chart-svg",
391
369
  onMouseMove: (e) => {
392
370
  handleMouseMove(e);
393
371
  if (activeIndex !== null && seriesPoints[0]?.[activeIndex]) {
394
372
  const p = seriesPoints[0][activeIndex];
395
- onShowAt(p.x, p.y, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`, curveSvgRef.current);
373
+ onHover(e, `${labels[activeIndex]} \u2014 ${getTooltipAt(activeIndex)}`);
396
374
  } else {
397
375
  onLeave();
398
376
  }
@@ -460,8 +438,7 @@ var CurveChart = React.memo(({ data, labels, width, height, animate, onHover, on
460
438
  );
461
439
  });
462
440
  CurveChart.displayName = "CurveChart";
463
- var BarChart = React.memo(({ data, labels, width, height, animate, onHover, onShowAt, onMove, onLeave }) => {
464
- const barSvgRef = React.useRef(null);
441
+ var BarChart = React.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
465
442
  const entries = React.useMemo(() => Object.entries(data), [data]);
466
443
  const maxVal = React.useMemo(() => {
467
444
  const allValues = entries.flatMap(([, v]) => v);
@@ -488,7 +465,7 @@ var BarChart = React.memo(({ data, labels, width, height, animate, onHover, onSh
488
465
  [entries, maxVal, chartH, groupW, barW, barGap, groupCount]
489
466
  );
490
467
  const barLabelStep = getLabelStep(count, chartW);
491
- return /* @__PURE__ */ jsxs("svg", { ref: barSvgRef, viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
468
+ return /* @__PURE__ */ jsxs("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
492
469
  /* @__PURE__ */ jsx(GridLines, { width, height, chartH, maxVal }),
493
470
  labels.map((label, i) => {
494
471
  if (i % barLabelStep !== 0) return null;
@@ -511,7 +488,8 @@ var BarChart = React.memo(({ data, labels, width, height, animate, onHover, onSh
511
488
  transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
512
489
  animationDelay: `${delay}ms`
513
490
  } : void 0,
514
- onMouseEnter: () => onShowAt(b.x + b.w / 2, b.y, `${key}: ${labels[i]} \u2014 ${b.v}`, barSvgRef.current),
491
+ onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
492
+ onMouseMove: onMove,
515
493
  onMouseLeave: onLeave
516
494
  },
517
495
  `${di}-${i}`
@@ -599,14 +577,17 @@ var PieDonutChart = React.memo(
599
577
  {
600
578
  d: s.d,
601
579
  fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
602
- className: "chart-slice"
580
+ className: "chart-slice",
581
+ onMouseEnter: (e) => onHover(e, `${s.label} \u2014 ${s.v.toLocaleString()} (${s.pct}%)`),
582
+ onMouseMove: onMove,
583
+ onMouseLeave: onLeave
603
584
  }
604
585
  ) }, i)) })
605
586
  ] });
606
587
  }
607
588
  );
608
589
  PieDonutChart.displayName = "PieDonutChart";
609
- var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
590
+ var ChartTooltip = ({ x, y, containerWidth, containerHeight, tooltipType, children }) => {
610
591
  const ref = React.useRef(null);
611
592
  const [pos, setPos] = React.useState({ left: 0, top: 0 });
612
593
  React.useLayoutEffect(() => {
@@ -617,17 +598,25 @@ var ChartTooltip = ({ x, y, containerWidth, containerHeight, children }) => {
617
598
  let left = x + TOOLTIP_OFFSET;
618
599
  let top = y - h - TOOLTIP_OFFSET;
619
600
  if (left + w > containerWidth) left = x - w - TOOLTIP_OFFSET;
620
- if (top < 0) top = y + TOOLTIP_OFFSET;
621
601
  if (left < 0) left = 0;
602
+ if (top < 0) top = y + TOOLTIP_OFFSET;
603
+ if (top + h > containerHeight) top = containerHeight - h;
622
604
  setPos({ left, top });
623
605
  }, [x, y, containerWidth, containerHeight]);
624
- return /* @__PURE__ */ jsx(
606
+ const content = typeof children === "string" ? children : "";
607
+ const sepIdx = content.indexOf(" \u2014 ");
608
+ const title = sepIdx >= 0 ? content.slice(0, sepIdx) : content;
609
+ const desc = sepIdx >= 0 ? content.slice(sepIdx + 3) : "";
610
+ return /* @__PURE__ */ jsxs(
625
611
  "div",
626
612
  {
627
613
  ref,
628
- className: "chart-tooltip chart-tooltip-show",
614
+ className: `chart-tooltip chart-tooltip-show chart-tooltip-${tooltipType}`,
629
615
  style: { left: pos.left, top: pos.top },
630
- children
616
+ children: [
617
+ title && /* @__PURE__ */ jsx("div", { className: "chart-tooltip-title", children: title }),
618
+ desc && /* @__PURE__ */ jsx("div", { className: "chart-tooltip-desc", children: desc })
619
+ ]
631
620
  }
632
621
  );
633
622
  };
@@ -670,8 +659,8 @@ var ChartLegend = ({ data, labels, type }) => {
670
659
  }) });
671
660
  };
672
661
  var Chart = React.memo((props) => {
673
- const { type, data, labels, tooltip: showTooltip = true } = props;
674
- const { tooltip, show, showAt, hide, move, containerRef } = useChartTooltip(showTooltip);
662
+ const { type, data, labels, tooltip: showTooltip = true, tooltipType = "dark" } = props;
663
+ const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
675
664
  const { width, height } = useChartSize(containerRef);
676
665
  const stableData = React.useMemo(() => data, [JSON.stringify(data)]);
677
666
  const stableLabels = React.useMemo(() => labels, [JSON.stringify(labels)]);
@@ -679,13 +668,13 @@ var Chart = React.memo((props) => {
679
668
  const animate = useChartAnimation(containerRef, dataKey);
680
669
  const ready = width > 0 && height > 0;
681
670
  return /* @__PURE__ */ jsxs("div", { className: "lib-xplat-chart", ref: containerRef, children: [
682
- ready && type === "line" && /* @__PURE__ */ jsx(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
683
- ready && type === "curve" && /* @__PURE__ */ jsx(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
684
- ready && type === "bar" && /* @__PURE__ */ jsx(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
685
- ready && type === "pie" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
686
- ready && type === "doughnut" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onShowAt: showAt, onMove: move, onLeave: hide }),
671
+ ready && type === "line" && /* @__PURE__ */ jsx(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
672
+ ready && type === "curve" && /* @__PURE__ */ jsx(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
673
+ ready && type === "bar" && /* @__PURE__ */ jsx(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
674
+ ready && type === "pie" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
675
+ ready && type === "doughnut" && /* @__PURE__ */ jsx(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
687
676
  ready && (type === "pie" || type === "doughnut") && /* @__PURE__ */ jsx(ChartLegend, { data: stableData, labels: stableLabels, type }),
688
- tooltip.visible && tooltip.content && /* @__PURE__ */ jsx(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, children: tooltip.content })
677
+ tooltip.visible && tooltip.content && /* @__PURE__ */ jsx(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, tooltipType, children: tooltip.content })
689
678
  ] });
690
679
  });
691
680
  Chart.displayName = "Chart";
@@ -35,7 +35,21 @@ __export(Tooltip_exports, {
35
35
  module.exports = __toCommonJS(Tooltip_exports);
36
36
 
37
37
  // src/components/Tooltip/Tooltip.tsx
38
+ var import_react2 = __toESM(require("react"), 1);
39
+
40
+ // src/tokens/hooks/Portal.tsx
38
41
  var import_react = __toESM(require("react"), 1);
42
+ var import_react_dom = __toESM(require("react-dom"), 1);
43
+ var import_jsx_runtime = require("react/jsx-runtime");
44
+ var PortalContainerContext = import_react.default.createContext(null);
45
+ var Portal = ({ children }) => {
46
+ const contextContainer = import_react.default.useContext(PortalContainerContext);
47
+ if (typeof document === "undefined") return null;
48
+ const container = contextContainer ?? document.body;
49
+ return import_react_dom.default.createPortal(children, container);
50
+ };
51
+ Portal.displayName = "Portal";
52
+ var Portal_default = Portal;
39
53
 
40
54
  // ../../node_modules/clsx/dist/clsx.mjs
41
55
  function r(e) {
@@ -54,18 +68,94 @@ function clsx() {
54
68
  var clsx_default = clsx;
55
69
 
56
70
  // src/components/Tooltip/Tooltip.tsx
57
- var import_jsx_runtime = require("react/jsx-runtime");
71
+ var import_jsx_runtime2 = require("react/jsx-runtime");
72
+ var OFFSET = 12;
73
+ var SHOW_DELAY = 300;
58
74
  var Tooltip = (props) => {
59
75
  const {
60
- type = "primary",
76
+ type = "dark",
77
+ title,
61
78
  description,
62
- children
79
+ children,
80
+ disabled = false
63
81
  } = props;
64
- const iconRef = import_react.default.useRef(null);
65
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-tooltip", children: [
66
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tooltip-content", ref: iconRef, children: children || "Tooltip" }),
67
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: clsx_default("tooltip-wrapper", type), children: description })
68
- ] });
82
+ const triggerRef = import_react2.default.useRef(null);
83
+ const tooltipRef = import_react2.default.useRef(null);
84
+ const [visible, setVisible] = import_react2.default.useState(false);
85
+ const [pos, setPos] = import_react2.default.useState({ left: 0, top: 0 });
86
+ const delayTimer = import_react2.default.useRef(0);
87
+ const calculatePos = import_react2.default.useCallback((clientX, clientY) => {
88
+ const el = tooltipRef.current;
89
+ if (!el) return;
90
+ const w = el.offsetWidth;
91
+ const h = el.offsetHeight;
92
+ const vw = window.innerWidth;
93
+ let left = clientX + OFFSET;
94
+ let top = clientY - h - OFFSET;
95
+ if (left + w > vw - 8) left = clientX - w - OFFSET;
96
+ if (top < 8) top = clientY + OFFSET;
97
+ if (left < 8) left = 8;
98
+ setPos({ left, top });
99
+ }, []);
100
+ const handleMouseEnter = import_react2.default.useCallback(() => {
101
+ if (disabled) return;
102
+ delayTimer.current = window.setTimeout(() => {
103
+ setVisible(true);
104
+ }, SHOW_DELAY);
105
+ }, [disabled]);
106
+ const handleMouseMove = import_react2.default.useCallback((e) => {
107
+ if (!visible) return;
108
+ calculatePos(e.clientX, e.clientY);
109
+ }, [visible, calculatePos]);
110
+ const handleMouseLeave = import_react2.default.useCallback(() => {
111
+ window.clearTimeout(delayTimer.current);
112
+ setVisible(false);
113
+ }, []);
114
+ const handleClick = import_react2.default.useCallback(() => {
115
+ window.clearTimeout(delayTimer.current);
116
+ setVisible(false);
117
+ }, []);
118
+ const handleFocus = import_react2.default.useCallback(() => {
119
+ if (disabled) return;
120
+ setVisible(true);
121
+ }, [disabled]);
122
+ const handleBlur = import_react2.default.useCallback(() => {
123
+ setVisible(false);
124
+ }, []);
125
+ import_react2.default.useLayoutEffect(() => {
126
+ if (!visible || !triggerRef.current) return;
127
+ const rect = triggerRef.current.getBoundingClientRect();
128
+ calculatePos(rect.right, rect.top);
129
+ }, [visible, calculatePos]);
130
+ if (!title && !description) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
131
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
132
+ "div",
133
+ {
134
+ ref: triggerRef,
135
+ className: "lib-xplat-tooltip-trigger",
136
+ onMouseEnter: handleMouseEnter,
137
+ onMouseMove: handleMouseMove,
138
+ onMouseLeave: handleMouseLeave,
139
+ onClick: handleClick,
140
+ onFocus: handleFocus,
141
+ onBlur: handleBlur,
142
+ children: [
143
+ children,
144
+ visible && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
145
+ "div",
146
+ {
147
+ ref: tooltipRef,
148
+ className: clsx_default("lib-xplat-tooltip", type),
149
+ style: { position: "fixed", left: pos.left, top: pos.top },
150
+ children: [
151
+ title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "tooltip-title", children: title }),
152
+ description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "tooltip-desc", children: description })
153
+ ]
154
+ }
155
+ ) })
156
+ ]
157
+ }
158
+ );
69
159
  };
70
160
  Tooltip.displayName = "Tooltip";
71
161
  var Tooltip_default = Tooltip;