@x-plat/design-system 0.5.30 → 0.5.32

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/index.js CHANGED
@@ -6416,6 +6416,40 @@ var AxisLabels = React6.memo(({ labels, count, chartW, height }) => {
6416
6416
  }) });
6417
6417
  });
6418
6418
  AxisLabels.displayName = "AxisLabels";
6419
+ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
6420
+ const [activeIndex, setActiveIndex] = React6.useState(null);
6421
+ const [mouseX, setMouseX] = React6.useState(null);
6422
+ const handleMouseMove = React6.useCallback((e) => {
6423
+ const svg = e.currentTarget;
6424
+ const rect = svg.getBoundingClientRect();
6425
+ const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
6426
+ setMouseX(mx);
6427
+ if (seriesPoints.length === 0 || seriesPoints[0].length === 0) return;
6428
+ const points = seriesPoints[0];
6429
+ let closest = 0;
6430
+ let minDist = Math.abs(points[0].x - mx);
6431
+ for (let i = 1; i < points.length; i++) {
6432
+ const dist = Math.abs(points[i].x - mx);
6433
+ if (dist < minDist) {
6434
+ minDist = dist;
6435
+ closest = i;
6436
+ }
6437
+ }
6438
+ setActiveIndex(closest);
6439
+ }, [seriesPoints]);
6440
+ const handleMouseLeave = React6.useCallback(() => {
6441
+ setActiveIndex(null);
6442
+ setMouseX(null);
6443
+ }, []);
6444
+ const tooltipContent = React6.useMemo(() => {
6445
+ if (activeIndex === null) return "";
6446
+ return entries.map(([key], di) => {
6447
+ const p = seriesPoints[di]?.[activeIndex];
6448
+ return p ? `${key}: ${p.v}` : "";
6449
+ }).filter(Boolean).join(" / ");
6450
+ }, [activeIndex, entries, seriesPoints]);
6451
+ return { activeIndex, mouseX, handleMouseMove, handleMouseLeave, tooltipContent };
6452
+ };
6419
6453
  var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
6420
6454
  const entries = React6.useMemo(() => Object.entries(data), [data]);
6421
6455
  const maxVal = React6.useMemo(() => {
@@ -6435,8 +6469,9 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
6435
6469
  ),
6436
6470
  [entries, count, chartW, chartH, maxVal]
6437
6471
  );
6438
- const showPoints = count <= 100;
6439
6472
  const lineRefs = React6.useRef([]);
6473
+ const clipRef = React6.useRef(null);
6474
+ const { activeIndex, mouseX, handleMouseMove, handleMouseLeave, tooltipContent } = useCrosshair(seriesPoints, entries, labels, chartH);
6440
6475
  React6.useEffect(() => {
6441
6476
  if (!animate) return;
6442
6477
  lineRefs.current.forEach((el) => {
@@ -6449,61 +6484,110 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
6449
6484
  el.style.strokeDashoffset = "0";
6450
6485
  });
6451
6486
  });
6452
- }, [animate, seriesPoints]);
6453
- return /* @__PURE__ */ jsxs197("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
6454
- /* @__PURE__ */ jsx307(GridLines, { width, height, chartH, maxVal }),
6455
- /* @__PURE__ */ jsx307(AxisLabels, { labels, count, chartW, height }),
6456
- entries.map(([key], di) => {
6457
- const palette = getPalette(LINE_BAR_PALETTES, di, key);
6458
- const color = palette[2];
6459
- const areaColor = palette[0];
6460
- const points = seriesPoints[di];
6461
- const gradientId = `line-gradient-${di}`;
6462
- const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
6463
- const areaD = `M ${points[0].x},${points[0].y} ${points.map((p) => `L ${p.x},${p.y}`).join(" ")} L ${points[points.length - 1].x},${PADDING.top + chartH} L ${points[0].x},${PADDING.top + chartH} Z`;
6464
- return /* @__PURE__ */ jsxs197("g", { children: [
6465
- /* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsxs197("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
6466
- /* @__PURE__ */ jsx307("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
6467
- /* @__PURE__ */ jsx307("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
6468
- ] }) }),
6469
- /* @__PURE__ */ jsx307(
6470
- "path",
6487
+ if (clipRef.current) {
6488
+ clipRef.current.setAttribute("width", "0");
6489
+ requestAnimationFrame(() => {
6490
+ if (clipRef.current) {
6491
+ clipRef.current.style.transition = "width 1200ms ease-out 200ms";
6492
+ clipRef.current.setAttribute("width", `${width}`);
6493
+ }
6494
+ });
6495
+ }
6496
+ }, [animate, seriesPoints, width]);
6497
+ const guideX = mouseX != null && mouseX >= PADDING.left && mouseX <= width - PADDING.right ? mouseX : null;
6498
+ const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x : null;
6499
+ const lineClipId = "line-area-clip";
6500
+ return /* @__PURE__ */ jsxs197(
6501
+ "svg",
6502
+ {
6503
+ viewBox: `0 0 ${width} ${height}`,
6504
+ className: "chart-svg",
6505
+ onMouseMove: (e) => {
6506
+ handleMouseMove(e);
6507
+ onMove(e);
6508
+ },
6509
+ onMouseLeave: () => {
6510
+ handleMouseLeave();
6511
+ onLeave();
6512
+ },
6513
+ children: [
6514
+ animate && /* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsx307("clipPath", { id: lineClipId, children: /* @__PURE__ */ jsx307("rect", { ref: clipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
6515
+ /* @__PURE__ */ jsx307(GridLines, { width, height, chartH, maxVal }),
6516
+ /* @__PURE__ */ jsx307(AxisLabels, { labels, count, chartW, height }),
6517
+ entries.map(([key], di) => {
6518
+ const palette = getPalette(LINE_BAR_PALETTES, di, key);
6519
+ const color = palette[2];
6520
+ const areaColor = palette[0];
6521
+ const points = seriesPoints[di];
6522
+ const gradientId = `line-gradient-${di}`;
6523
+ const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
6524
+ const areaD = `M ${points[0].x},${points[0].y} ${points.map((p) => `L ${p.x},${p.y}`).join(" ")} L ${points[points.length - 1].x},${PADDING.top + chartH} L ${points[0].x},${PADDING.top + chartH} Z`;
6525
+ return /* @__PURE__ */ jsxs197("g", { children: [
6526
+ /* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsxs197("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
6527
+ /* @__PURE__ */ jsx307("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
6528
+ /* @__PURE__ */ jsx307("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
6529
+ ] }) }),
6530
+ /* @__PURE__ */ jsx307(
6531
+ "path",
6532
+ {
6533
+ d: areaD,
6534
+ fill: `url(#${gradientId})`,
6535
+ clipPath: animate ? `url(#${lineClipId})` : void 0
6536
+ }
6537
+ ),
6538
+ /* @__PURE__ */ jsx307(
6539
+ "polyline",
6540
+ {
6541
+ ref: (el) => {
6542
+ lineRefs.current[di] = el;
6543
+ },
6544
+ points: polyPoints,
6545
+ fill: "none",
6546
+ stroke: color,
6547
+ strokeWidth: "2"
6548
+ }
6549
+ ),
6550
+ activeIndex !== null && points[activeIndex] && /* @__PURE__ */ jsx307(
6551
+ "circle",
6552
+ {
6553
+ cx: points[activeIndex].x,
6554
+ cy: points[activeIndex].y,
6555
+ r: "5",
6556
+ fill: color,
6557
+ className: "chart-point-active"
6558
+ }
6559
+ )
6560
+ ] }, di);
6561
+ }),
6562
+ guideX !== null && /* @__PURE__ */ jsx307(
6563
+ "line",
6471
6564
  {
6472
- d: areaD,
6473
- fill: `url(#${gradientId})`,
6474
- className: "chart-area",
6475
- style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
6565
+ x1: guideX,
6566
+ y1: PADDING.top,
6567
+ x2: guideX,
6568
+ y2: PADDING.top + chartH,
6569
+ className: "chart-crosshair"
6476
6570
  }
6477
6571
  ),
6572
+ activeIndex !== null && activeX !== null && /* @__PURE__ */ jsx307("foreignObject", { x: activeX - 100, y: 0, width: "200", height: PADDING.top, children: /* @__PURE__ */ jsxs197("div", { className: "chart-crosshair-label", children: [
6573
+ labels[activeIndex],
6574
+ " \u2014 ",
6575
+ tooltipContent
6576
+ ] }) }),
6478
6577
  /* @__PURE__ */ jsx307(
6479
- "polyline",
6578
+ "rect",
6480
6579
  {
6481
- ref: (el) => {
6482
- lineRefs.current[di] = el;
6483
- },
6484
- points: polyPoints,
6485
- fill: "none",
6486
- stroke: color,
6487
- strokeWidth: "2"
6580
+ x: PADDING.left,
6581
+ y: PADDING.top,
6582
+ width: chartW,
6583
+ height: chartH,
6584
+ fill: "transparent",
6585
+ style: { cursor: "crosshair" }
6488
6586
  }
6489
- ),
6490
- showPoints && points.map((p, i) => /* @__PURE__ */ jsx307(
6491
- "circle",
6492
- {
6493
- cx: p.x,
6494
- cy: p.y,
6495
- r: "4",
6496
- fill: color,
6497
- className: "chart-point",
6498
- onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${p.v}`),
6499
- onMouseMove: onMove,
6500
- onMouseLeave: onLeave
6501
- },
6502
- i
6503
- ))
6504
- ] }, di);
6505
- })
6506
- ] });
6587
+ )
6588
+ ]
6589
+ }
6590
+ );
6507
6591
  });
6508
6592
  LineChart.displayName = "LineChart";
6509
6593
  var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
@@ -6525,8 +6609,9 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
6525
6609
  ),
6526
6610
  [entries, count, chartW, chartH, maxVal]
6527
6611
  );
6528
- const showPoints = count <= 100;
6529
6612
  const lineRefs = React6.useRef([]);
6613
+ const curveClipRef = React6.useRef(null);
6614
+ const { activeIndex, mouseX, handleMouseMove, handleMouseLeave, tooltipContent } = useCrosshair(seriesPoints, entries, labels, chartH);
6530
6615
  React6.useEffect(() => {
6531
6616
  if (!animate) return;
6532
6617
  lineRefs.current.forEach((el) => {
@@ -6539,61 +6624,110 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
6539
6624
  el.style.strokeDashoffset = "0";
6540
6625
  });
6541
6626
  });
6542
- }, [animate, seriesPoints]);
6543
- return /* @__PURE__ */ jsxs197("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
6544
- /* @__PURE__ */ jsx307(GridLines, { width, height, chartH, maxVal }),
6545
- /* @__PURE__ */ jsx307(AxisLabels, { labels, count, chartW, height }),
6546
- entries.map(([key], di) => {
6547
- const palette = getPalette(LINE_BAR_PALETTES, di, key);
6548
- const color = palette[2];
6549
- const areaColor = palette[0];
6550
- const points = seriesPoints[di];
6551
- const gradientId = `curve-gradient-${di}`;
6552
- const linePath = toSmoothPath(points);
6553
- const areaPath = linePath + ` L ${points[points.length - 1].x} ${PADDING.top + chartH} L ${points[0].x} ${PADDING.top + chartH} Z`;
6554
- return /* @__PURE__ */ jsxs197("g", { children: [
6555
- /* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsxs197("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
6556
- /* @__PURE__ */ jsx307("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
6557
- /* @__PURE__ */ jsx307("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
6558
- ] }) }),
6559
- /* @__PURE__ */ jsx307(
6560
- "path",
6627
+ if (curveClipRef.current) {
6628
+ curveClipRef.current.setAttribute("width", "0");
6629
+ requestAnimationFrame(() => {
6630
+ if (curveClipRef.current) {
6631
+ curveClipRef.current.style.transition = "width 1200ms ease-out 200ms";
6632
+ curveClipRef.current.setAttribute("width", `${width}`);
6633
+ }
6634
+ });
6635
+ }
6636
+ }, [animate, seriesPoints, width]);
6637
+ const guideX = mouseX != null && mouseX >= PADDING.left && mouseX <= width - PADDING.right ? mouseX : null;
6638
+ const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x : null;
6639
+ const curveClipId = "curve-area-clip";
6640
+ return /* @__PURE__ */ jsxs197(
6641
+ "svg",
6642
+ {
6643
+ viewBox: `0 0 ${width} ${height}`,
6644
+ className: "chart-svg",
6645
+ onMouseMove: (e) => {
6646
+ handleMouseMove(e);
6647
+ onMove(e);
6648
+ },
6649
+ onMouseLeave: () => {
6650
+ handleMouseLeave();
6651
+ onLeave();
6652
+ },
6653
+ children: [
6654
+ animate && /* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsx307("clipPath", { id: curveClipId, children: /* @__PURE__ */ jsx307("rect", { ref: curveClipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
6655
+ /* @__PURE__ */ jsx307(GridLines, { width, height, chartH, maxVal }),
6656
+ /* @__PURE__ */ jsx307(AxisLabels, { labels, count, chartW, height }),
6657
+ entries.map(([key], di) => {
6658
+ const palette = getPalette(LINE_BAR_PALETTES, di, key);
6659
+ const color = palette[2];
6660
+ const areaColor = palette[0];
6661
+ const points = seriesPoints[di];
6662
+ const gradientId = `curve-gradient-${di}`;
6663
+ const linePath = toSmoothPath(points);
6664
+ const areaPath = linePath + ` L ${points[points.length - 1].x} ${PADDING.top + chartH} L ${points[0].x} ${PADDING.top + chartH} Z`;
6665
+ return /* @__PURE__ */ jsxs197("g", { children: [
6666
+ /* @__PURE__ */ jsx307("defs", { children: /* @__PURE__ */ jsxs197("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
6667
+ /* @__PURE__ */ jsx307("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
6668
+ /* @__PURE__ */ jsx307("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
6669
+ ] }) }),
6670
+ /* @__PURE__ */ jsx307(
6671
+ "path",
6672
+ {
6673
+ d: areaPath,
6674
+ fill: `url(#${gradientId})`,
6675
+ clipPath: animate ? `url(#${curveClipId})` : void 0
6676
+ }
6677
+ ),
6678
+ /* @__PURE__ */ jsx307(
6679
+ "path",
6680
+ {
6681
+ ref: (el) => {
6682
+ lineRefs.current[di] = el;
6683
+ },
6684
+ d: linePath,
6685
+ fill: "none",
6686
+ stroke: color,
6687
+ strokeWidth: "2"
6688
+ }
6689
+ ),
6690
+ activeIndex !== null && points[activeIndex] && /* @__PURE__ */ jsx307(
6691
+ "circle",
6692
+ {
6693
+ cx: points[activeIndex].x,
6694
+ cy: points[activeIndex].y,
6695
+ r: "5",
6696
+ fill: color,
6697
+ className: "chart-point-active"
6698
+ }
6699
+ )
6700
+ ] }, di);
6701
+ }),
6702
+ guideX !== null && /* @__PURE__ */ jsx307(
6703
+ "line",
6561
6704
  {
6562
- d: areaPath,
6563
- fill: `url(#${gradientId})`,
6564
- className: "chart-area",
6565
- style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
6705
+ x1: guideX,
6706
+ y1: PADDING.top,
6707
+ x2: guideX,
6708
+ y2: PADDING.top + chartH,
6709
+ className: "chart-crosshair"
6566
6710
  }
6567
6711
  ),
6712
+ activeIndex !== null && activeX !== null && /* @__PURE__ */ jsx307("foreignObject", { x: activeX - 100, y: 0, width: "200", height: PADDING.top, children: /* @__PURE__ */ jsxs197("div", { className: "chart-crosshair-label", children: [
6713
+ labels[activeIndex],
6714
+ " \u2014 ",
6715
+ tooltipContent
6716
+ ] }) }),
6568
6717
  /* @__PURE__ */ jsx307(
6569
- "path",
6718
+ "rect",
6570
6719
  {
6571
- ref: (el) => {
6572
- lineRefs.current[di] = el;
6573
- },
6574
- d: linePath,
6575
- fill: "none",
6576
- stroke: color,
6577
- strokeWidth: "2"
6720
+ x: PADDING.left,
6721
+ y: PADDING.top,
6722
+ width: chartW,
6723
+ height: chartH,
6724
+ fill: "transparent",
6725
+ style: { cursor: "crosshair" }
6578
6726
  }
6579
- ),
6580
- showPoints && points.map((p, i) => /* @__PURE__ */ jsx307(
6581
- "circle",
6582
- {
6583
- cx: p.x,
6584
- cy: p.y,
6585
- r: "4",
6586
- fill: color,
6587
- className: "chart-point",
6588
- onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${p.v}`),
6589
- onMouseMove: onMove,
6590
- onMouseLeave: onLeave
6591
- },
6592
- i
6593
- ))
6594
- ] }, di);
6595
- })
6596
- ] });
6727
+ )
6728
+ ]
6729
+ }
6730
+ );
6597
6731
  });
6598
6732
  CurveChart.displayName = "CurveChart";
6599
6733
  var BarChart = React6.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
@@ -9101,6 +9235,7 @@ var TableRow = React36.memo((props) => {
9101
9235
  const {
9102
9236
  children,
9103
9237
  type = "secondary",
9238
+ color,
9104
9239
  isHover,
9105
9240
  onClick
9106
9241
  } = props;
@@ -9117,11 +9252,17 @@ var TableRow = React36.memo((props) => {
9117
9252
  {
9118
9253
  className: clsx_default(
9119
9254
  rowBorderUse ? "table-bottom-border" : null,
9120
- type,
9255
+ color != null ? "categorical" : type,
9256
+ color === "neutral" && "cat-neutral",
9121
9257
  isHover && "hover",
9122
9258
  onClick && "clickable"
9123
9259
  ),
9124
9260
  onClick,
9261
+ style: color != null && color !== "neutral" ? {
9262
+ "--cat-fill": `var(--semantic-categorical-${color}-fill)`,
9263
+ "--cat-text": `var(--semantic-categorical-${color}-text)`,
9264
+ "--cat-bg": `var(--semantic-categorical-${color}-bg)`
9265
+ } : void 0,
9125
9266
  children
9126
9267
  }
9127
9268
  ) });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-plat/design-system",
3
- "version": "0.5.30",
3
+ "version": "0.5.32",
4
4
  "description": "XPLAT UI Design System",
5
5
  "author": "XPLAT WOONG",
6
6
  "main": "dist/index.cjs",