@x-plat/design-system 0.5.12 → 0.5.14

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
@@ -6165,29 +6165,50 @@ var toSmoothPath = (points) => {
6165
6165
  }
6166
6166
  return d;
6167
6167
  };
6168
+ var RESIZE_SETTLE_MS = 150;
6168
6169
  var useChartSize = (ref) => {
6169
6170
  const [size, setSize] = React5.useState({ width: 0, height: 0 });
6171
+ const isResizing = React5.useRef(false);
6172
+ const settleTimer = React5.useRef(0);
6173
+ const lastSize = React5.useRef({ width: 0, height: 0 });
6174
+ const initialRef = React5.useRef(true);
6170
6175
  React5.useEffect(() => {
6171
6176
  const el = ref.current;
6172
6177
  if (!el) return;
6173
- let rafId = 0;
6174
6178
  const observer = new ResizeObserver((entries) => {
6175
- cancelAnimationFrame(rafId);
6176
- rafId = requestAnimationFrame(() => {
6177
- const entry = entries[0];
6178
- if (!entry) return;
6179
- const { width, height } = entry.contentRect;
6180
- const w = Math.floor(width);
6181
- const h = Math.floor(height);
6182
- setSize((prev) => prev.width === w && prev.height === h ? prev : { width: w, height: h });
6183
- });
6179
+ const entry = entries[0];
6180
+ if (!entry) return;
6181
+ const { width, height } = entry.contentRect;
6182
+ const w = Math.floor(width);
6183
+ const h = Math.floor(height);
6184
+ if (w === lastSize.current.width && h === lastSize.current.height) return;
6185
+ lastSize.current = { width: w, height: h };
6186
+ if (initialRef.current) {
6187
+ initialRef.current = false;
6188
+ setSize({ width: w, height: h });
6189
+ return;
6190
+ }
6191
+ isResizing.current = true;
6192
+ if (el.firstElementChild) {
6193
+ const svg = el.firstElementChild;
6194
+ svg.style.transformOrigin = "0 0";
6195
+ svg.style.transform = `scale(${w / (size.width || w)}, ${h / (size.height || h)})`;
6196
+ }
6197
+ window.clearTimeout(settleTimer.current);
6198
+ settleTimer.current = window.setTimeout(() => {
6199
+ isResizing.current = false;
6200
+ if (el.firstElementChild) {
6201
+ el.firstElementChild.style.transform = "";
6202
+ }
6203
+ setSize({ width: w, height: h });
6204
+ }, RESIZE_SETTLE_MS);
6184
6205
  });
6185
6206
  observer.observe(el);
6186
6207
  return () => {
6187
- cancelAnimationFrame(rafId);
6208
+ window.clearTimeout(settleTimer.current);
6188
6209
  observer.disconnect();
6189
6210
  };
6190
- }, [ref]);
6211
+ }, [ref, size.width, size.height]);
6191
6212
  return size;
6192
6213
  };
6193
6214
  var useChartTooltip = (enabled) => {
@@ -6379,17 +6400,19 @@ var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLe
6379
6400
  const chartW = width - PADDING.left - PADDING.right;
6380
6401
  const chartH = height - PADDING.top - PADDING.bottom;
6381
6402
  const groupW = chartW / count;
6382
- const barW = Math.max(1, Math.min(32, groupW * 0.7 / groupCount));
6403
+ const barGap = groupCount > 1 ? 2 : 0;
6404
+ const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
6383
6405
  const bars = React5.useMemo(
6384
6406
  () => entries.map(
6385
6407
  ([, values], di) => values.map((v, i) => {
6408
+ const totalBarsW = barW * groupCount + barGap * (groupCount - 1);
6386
6409
  const h = Math.max(0, v / maxVal * chartH);
6387
- const x = PADDING.left + groupW * i + (groupW - barW * groupCount) / 2 + barW * di;
6410
+ const x = PADDING.left + groupW * i + (groupW - totalBarsW) / 2 + (barW + barGap) * di;
6388
6411
  const y = PADDING.top + chartH - h;
6389
6412
  return { x, y, w: barW, h, v };
6390
6413
  })
6391
6414
  ),
6392
- [entries, maxVal, chartH, groupW, barW, groupCount]
6415
+ [entries, maxVal, chartH, groupW, barW, barGap, groupCount]
6393
6416
  );
6394
6417
  const barLabelStep = getLabelStep(count, chartW);
6395
6418
  return /* @__PURE__ */ jsxs196("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
@@ -6401,22 +6424,22 @@ var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLe
6401
6424
  entries.map(([key], di) => {
6402
6425
  const palette = getPalette(LINE_BAR_PALETTES, di, key);
6403
6426
  const color = palette[2];
6404
- return bars[di].map((b, i) => /* @__PURE__ */ jsx305(
6405
- "rect",
6406
- {
6407
- x: b.x,
6408
- y: b.y,
6409
- width: b.w,
6410
- height: b.h,
6411
- rx: Math.min(4, b.w / 2),
6412
- fill: color,
6413
- className: "chart-bar",
6414
- onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
6415
- onMouseMove: onMove,
6416
- onMouseLeave: onLeave
6417
- },
6418
- `${di}-${i}`
6419
- ));
6427
+ return bars[di].map((b, i) => {
6428
+ const r2 = Math.min(4, b.w / 2);
6429
+ const d = b.h <= r2 ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r2} Q ${b.x} ${b.y} ${b.x + r2} ${b.y} H ${b.x + b.w - r2} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r2} V ${b.y + b.h} Z`;
6430
+ return /* @__PURE__ */ jsx305(
6431
+ "path",
6432
+ {
6433
+ d,
6434
+ fill: color,
6435
+ className: "chart-bar",
6436
+ onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
6437
+ onMouseMove: onMove,
6438
+ onMouseLeave: onLeave
6439
+ },
6440
+ `${di}-${i}`
6441
+ );
6442
+ });
6420
6443
  })
6421
6444
  ] });
6422
6445
  });
@@ -6503,20 +6526,22 @@ var TooltipBubble = ({ x, y, containerWidth, children }) => {
6503
6526
  }
6504
6527
  );
6505
6528
  };
6506
- var Chart = (props) => {
6529
+ var Chart = React5.memo((props) => {
6507
6530
  const { type, data, labels, tooltip: showTooltip = true } = props;
6508
6531
  const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
6509
6532
  const { width, height } = useChartSize(containerRef);
6533
+ const stableData = React5.useMemo(() => data, [JSON.stringify(data)]);
6534
+ const stableLabels = React5.useMemo(() => labels, [JSON.stringify(labels)]);
6510
6535
  const ready = width > 0 && height > 0;
6511
6536
  return /* @__PURE__ */ jsxs196("div", { className: "lib-xplat-chart", ref: containerRef, children: [
6512
- ready && type === "line" && /* @__PURE__ */ jsx305(LineChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
6513
- ready && type === "curve" && /* @__PURE__ */ jsx305(CurveChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
6514
- ready && type === "bar" && /* @__PURE__ */ jsx305(BarChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
6515
- ready && type === "pie" && /* @__PURE__ */ jsx305(PieDonutChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
6516
- ready && type === "doughnut" && /* @__PURE__ */ jsx305(PieDonutChart, { data, labels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
6537
+ ready && type === "line" && /* @__PURE__ */ jsx305(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
6538
+ ready && type === "curve" && /* @__PURE__ */ jsx305(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
6539
+ ready && type === "bar" && /* @__PURE__ */ jsx305(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
6540
+ ready && type === "pie" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
6541
+ ready && type === "doughnut" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
6517
6542
  tooltip.visible && /* @__PURE__ */ jsx305(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
6518
6543
  ] });
6519
- };
6544
+ });
6520
6545
  Chart.displayName = "Chart";
6521
6546
  var Chart_default = Chart;
6522
6547
 
@@ -6791,12 +6816,8 @@ var PortalContainerContext = React8.createContext(null);
6791
6816
  var PortalProvider = ({ container, children }) => /* @__PURE__ */ jsx311(PortalContainerContext.Provider, { value: container, children });
6792
6817
  var Portal = ({ children }) => {
6793
6818
  const contextContainer = React8.useContext(PortalContainerContext);
6794
- const [fallback, setFallback] = React8.useState(null);
6795
- React8.useEffect(() => {
6796
- if (!contextContainer) setFallback(document.body);
6797
- }, [contextContainer]);
6798
- const container = contextContainer ?? fallback;
6799
- if (!container) return null;
6819
+ if (typeof document === "undefined") return null;
6820
+ const container = contextContainer ?? document.body;
6800
6821
  return ReactDOM.createPortal(children, container);
6801
6822
  };
6802
6823
  Portal.displayName = "Portal";
@@ -7424,15 +7445,15 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
7424
7445
  direction
7425
7446
  });
7426
7447
  }, [triggerRef, popRef]);
7448
+ React17.useLayoutEffect(() => {
7449
+ if (!enabled) return;
7450
+ calculatePosition();
7451
+ }, [calculatePosition, enabled]);
7427
7452
  React17.useEffect(() => {
7428
7453
  if (!enabled) return;
7429
- const raf = requestAnimationFrame(() => {
7430
- calculatePosition();
7431
- });
7432
7454
  window.addEventListener("resize", calculatePosition);
7433
7455
  window.addEventListener("scroll", calculatePosition, true);
7434
7456
  return () => {
7435
- cancelAnimationFrame(raf);
7436
7457
  window.removeEventListener("resize", calculatePosition);
7437
7458
  window.removeEventListener("scroll", calculatePosition, true);
7438
7459
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-plat/design-system",
3
- "version": "0.5.12",
3
+ "version": "0.5.14",
4
4
  "description": "XPLAT UI Design System",
5
5
  "author": "XPLAT WOONG",
6
6
  "main": "dist/index.cjs",