@x-plat/design-system 0.5.33 → 0.5.35

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.
@@ -35,8 +35,24 @@ __export(Chart_exports, {
35
35
  module.exports = __toCommonJS(Chart_exports);
36
36
 
37
37
  // src/components/Chart/Chart.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);
39
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;
53
+
54
+ // src/components/Chart/Chart.tsx
55
+ var import_jsx_runtime2 = require("react/jsx-runtime");
40
56
  var CATEGORICAL_COUNT = 8;
41
57
  var LINE_BAR_PALETTES = Array.from({ length: CATEGORICAL_COUNT }, (_, i) => {
42
58
  const n = i + 1;
@@ -82,11 +98,11 @@ var toSmoothPath = (points) => {
82
98
  };
83
99
  var RESIZE_SETTLE_MS = 150;
84
100
  var useChartSize = (ref) => {
85
- const [size, setSize] = import_react.default.useState({ width: 0, height: 0 });
86
- const settleTimer = import_react.default.useRef(0);
87
- const committedSize = import_react.default.useRef({ width: 0, height: 0 });
88
- const initialRef = import_react.default.useRef(true);
89
- import_react.default.useEffect(() => {
101
+ const [size, setSize] = import_react2.default.useState({ width: 0, height: 0 });
102
+ const settleTimer = import_react2.default.useRef(0);
103
+ const committedSize = import_react2.default.useRef({ width: 0, height: 0 });
104
+ const initialRef = import_react2.default.useRef(true);
105
+ import_react2.default.useEffect(() => {
90
106
  const el = ref.current;
91
107
  if (!el) return;
92
108
  const observer = new ResizeObserver((entries) => {
@@ -128,10 +144,10 @@ var useChartSize = (ref) => {
128
144
  };
129
145
  var prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
130
146
  var useChartAnimation = (containerRef, dataKey) => {
131
- const [animate, setAnimate] = import_react.default.useState(false);
132
- const prevDataKey = import_react.default.useRef(dataKey);
133
- const hasAnimated = import_react.default.useRef(false);
134
- import_react.default.useEffect(() => {
147
+ const [animate, setAnimate] = import_react2.default.useState(false);
148
+ const prevDataKey = import_react2.default.useRef(dataKey);
149
+ const hasAnimated = import_react2.default.useRef(false);
150
+ import_react2.default.useEffect(() => {
135
151
  if (prefersReducedMotion()) return;
136
152
  const el = containerRef.current;
137
153
  if (!el) return;
@@ -147,27 +163,29 @@ var useChartAnimation = (containerRef, dataKey) => {
147
163
  observer.observe(el);
148
164
  return () => observer.disconnect();
149
165
  }, [containerRef]);
150
- import_react.default.useEffect(() => {
166
+ import_react2.default.useEffect(() => {
151
167
  if (dataKey !== prevDataKey.current) {
152
168
  prevDataKey.current = dataKey;
153
169
  if (prefersReducedMotion()) return;
154
170
  setAnimate(false);
155
- requestAnimationFrame(() => setAnimate(true));
171
+ requestAnimationFrame(() => {
172
+ requestAnimationFrame(() => setAnimate(true));
173
+ });
156
174
  }
157
175
  }, [dataKey]);
158
176
  return animate || prefersReducedMotion();
159
177
  };
160
178
  var TOOLTIP_OFFSET = 12;
161
179
  var useChartTooltip = (enabled) => {
162
- const [tooltip, setTooltip] = import_react.default.useState({
180
+ const [tooltip, setTooltip] = import_react2.default.useState({
163
181
  visible: false,
164
182
  clientX: 0,
165
183
  clientY: 0,
166
184
  content: ""
167
185
  });
168
- const containerRef = import_react.default.useRef(null);
169
- const rafRef = import_react.default.useRef(0);
170
- const move = import_react.default.useCallback((e) => {
186
+ const containerRef = import_react2.default.useRef(null);
187
+ const rafRef = import_react2.default.useRef(0);
188
+ const move = import_react2.default.useCallback((e) => {
171
189
  if (!enabled) return;
172
190
  const cx = e.clientX;
173
191
  const cy = e.clientY;
@@ -176,22 +194,22 @@ var useChartTooltip = (enabled) => {
176
194
  setTooltip((prev) => ({ ...prev, clientX: cx, clientY: cy }));
177
195
  });
178
196
  }, [enabled]);
179
- const show = import_react.default.useCallback((e, content) => {
197
+ const show = import_react2.default.useCallback((e, content) => {
180
198
  if (!enabled) return;
181
199
  setTooltip({ visible: true, clientX: e.clientX, clientY: e.clientY, content });
182
200
  }, [enabled]);
183
- const hide = import_react.default.useCallback(() => {
201
+ const hide = import_react2.default.useCallback(() => {
184
202
  cancelAnimationFrame(rafRef.current);
185
203
  setTooltip((prev) => ({ ...prev, visible: false }));
186
204
  }, []);
187
205
  return { tooltip, show, hide, move, containerRef };
188
206
  };
189
- 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) => {
207
+ var GridLines = import_react2.default.memo(({ width, height, chartH, maxVal }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
190
208
  const y = PADDING.top + (1 - ratio) * chartH;
191
209
  const val = Math.round(maxVal * ratio);
192
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
193
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: PADDING.left, y1: y, x2: width - PADDING.right, y2: y, className: "chart-grid" }),
194
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x: PADDING.left - 8, y: y + 4, className: "chart-axis-label", textAnchor: "end", children: val })
210
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { children: [
211
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: PADDING.left, y1: y, x2: width - PADDING.right, y2: y, className: "chart-grid" }),
212
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("text", { x: PADDING.left - 8, y: y + 4, className: "chart-axis-label", textAnchor: "end", children: val })
195
213
  ] }, ratio);
196
214
  }) }));
197
215
  GridLines.displayName = "GridLines";
@@ -201,18 +219,18 @@ var getLabelStep = (count, chartW) => {
201
219
  if (count <= maxLabels) return 1;
202
220
  return Math.ceil(count / maxLabels);
203
221
  };
204
- var AxisLabels = import_react.default.memo(({ labels, count, chartW, height }) => {
222
+ var AxisLabels = import_react2.default.memo(({ labels, count, chartW, height }) => {
205
223
  const step = getLabelStep(count, chartW);
206
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: labels.map((label, i) => {
224
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: labels.map((label, i) => {
207
225
  if (i % step !== 0) return null;
208
226
  const x = PADDING.left + i / (count - 1 || 1) * chartW;
209
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x, y: height - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i);
227
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("text", { x, y: height - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i);
210
228
  }) });
211
229
  });
212
230
  AxisLabels.displayName = "AxisLabels";
213
231
  var useCrosshair = (seriesPoints, entries, labels, chartH) => {
214
- const [activeIndex, setActiveIndex] = import_react.default.useState(null);
215
- const handleMouseMove = import_react.default.useCallback((e) => {
232
+ const [activeIndex, setActiveIndex] = import_react2.default.useState(null);
233
+ const handleMouseMove = import_react2.default.useCallback((e) => {
216
234
  const svg = e.currentTarget;
217
235
  const rect = svg.getBoundingClientRect();
218
236
  const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
@@ -231,17 +249,17 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
231
249
  }
232
250
  setActiveIndex(minDist <= threshold ? closest : null);
233
251
  }, [seriesPoints]);
234
- const handleMouseLeave = import_react.default.useCallback(() => {
252
+ const handleMouseLeave = import_react2.default.useCallback(() => {
235
253
  setActiveIndex(null);
236
254
  }, []);
237
- const tooltipContent = import_react.default.useMemo(() => {
255
+ const tooltipContent = import_react2.default.useMemo(() => {
238
256
  if (activeIndex === null) return "";
239
257
  return entries.map(([key], di) => {
240
258
  const p = seriesPoints[di]?.[activeIndex];
241
259
  return p ? `${key}: ${p.v}` : "";
242
260
  }).filter(Boolean).join(" / ");
243
261
  }, [activeIndex, entries, seriesPoints]);
244
- const getTooltipAt = import_react.default.useCallback((idx) => {
262
+ const getTooltipAt = import_react2.default.useCallback((idx) => {
245
263
  return entries.map(([key], di) => {
246
264
  const p = seriesPoints[di]?.[idx];
247
265
  return p ? `${key}: ${p.v}` : "";
@@ -249,16 +267,16 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
249
267
  }, [entries, seriesPoints]);
250
268
  return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
251
269
  };
252
- var LineChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
253
- const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
254
- const maxVal = import_react.default.useMemo(() => {
270
+ var LineChart = import_react2.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
271
+ const entries = import_react2.default.useMemo(() => Object.entries(data), [data]);
272
+ const maxVal = import_react2.default.useMemo(() => {
255
273
  const allValues = entries.flatMap(([, v]) => v);
256
274
  return Math.max(...allValues) * 1.2 || 1;
257
275
  }, [entries]);
258
276
  const count = labels.length;
259
277
  const chartW = width - PADDING.left - PADDING.right;
260
278
  const chartH = height - PADDING.top - PADDING.bottom;
261
- const seriesPoints = import_react.default.useMemo(
279
+ const seriesPoints = import_react2.default.useMemo(
262
280
  () => entries.map(
263
281
  ([, values]) => values.map((v, i) => ({
264
282
  x: PADDING.left + i / (count - 1 || 1) * chartW,
@@ -268,34 +286,21 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
268
286
  ),
269
287
  [entries, count, chartW, chartH, maxVal]
270
288
  );
271
- const lineRefs = import_react.default.useRef([]);
272
- const clipRef = import_react.default.useRef(null);
289
+ const clipRef = import_react2.default.useRef(null);
273
290
  const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
274
- import_react.default.useEffect(() => {
275
- if (!animate) return;
276
- lineRefs.current.forEach((el) => {
277
- if (!el) return;
278
- const len = el.getTotalLength();
279
- el.style.strokeDasharray = `${len}`;
280
- el.style.strokeDashoffset = `${len}`;
281
- requestAnimationFrame(() => {
282
- el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
283
- el.style.strokeDashoffset = "0";
284
- });
291
+ import_react2.default.useEffect(() => {
292
+ if (!animate || !clipRef.current) return;
293
+ clipRef.current.setAttribute("width", "0");
294
+ requestAnimationFrame(() => {
295
+ if (clipRef.current) {
296
+ clipRef.current.style.transition = "width 1200ms ease-out 200ms";
297
+ clipRef.current.setAttribute("width", `${width}`);
298
+ }
285
299
  });
286
- if (clipRef.current) {
287
- clipRef.current.setAttribute("width", "0");
288
- requestAnimationFrame(() => {
289
- if (clipRef.current) {
290
- clipRef.current.style.transition = "width 1200ms ease-out 200ms";
291
- clipRef.current.setAttribute("width", `${width}`);
292
- }
293
- });
294
- }
295
- }, [animate, seriesPoints, width]);
300
+ }, [animate, width]);
296
301
  const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
297
302
  const lineClipId = "line-area-clip";
298
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
303
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
299
304
  "svg",
300
305
  {
301
306
  viewBox: `0 0 ${width} ${height}`,
@@ -328,9 +333,9 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
328
333
  onLeave();
329
334
  },
330
335
  children: [
331
- animate && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("clipPath", { id: lineClipId, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { ref: clipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
332
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GridLines, { width, height, chartH, maxVal }),
333
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AxisLabels, { labels, count, chartW, height }),
336
+ animate && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("clipPath", { id: lineClipId, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { ref: clipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
337
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GridLines, { width, height, chartH, maxVal }),
338
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AxisLabels, { labels, count, chartW, height }),
334
339
  entries.map(([key], di) => {
335
340
  const palette = getPalette(LINE_BAR_PALETTES, di, key);
336
341
  const color = palette[2];
@@ -339,32 +344,16 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
339
344
  const gradientId = `line-gradient-${di}`;
340
345
  const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
341
346
  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`;
342
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
343
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
344
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
345
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
347
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { children: [
348
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
349
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
350
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
346
351
  ] }) }),
347
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
348
- "path",
349
- {
350
- d: areaD,
351
- fill: `url(#${gradientId})`,
352
- clipPath: animate ? `url(#${lineClipId})` : void 0
353
- }
354
- ),
355
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
356
- "polyline",
357
- {
358
- ref: (el) => {
359
- lineRefs.current[di] = el;
360
- },
361
- points: polyPoints,
362
- fill: "none",
363
- stroke: color,
364
- strokeWidth: "2"
365
- }
366
- ),
367
- activeIndex !== null && points[activeIndex] && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
352
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { clipPath: animate ? `url(#${lineClipId})` : void 0, children: [
353
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: areaD, fill: `url(#${gradientId})` }),
354
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: polyPoints, fill: "none", stroke: color, strokeWidth: "2" })
355
+ ] }),
356
+ activeIndex !== null && points[activeIndex] && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
368
357
  "circle",
369
358
  {
370
359
  cx: points[activeIndex].x,
@@ -376,7 +365,7 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
376
365
  )
377
366
  ] }, di);
378
367
  }),
379
- activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
368
+ activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
380
369
  "line",
381
370
  {
382
371
  x1: activeX,
@@ -386,7 +375,7 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
386
375
  className: "chart-crosshair"
387
376
  }
388
377
  ),
389
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
378
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
390
379
  "rect",
391
380
  {
392
381
  x: PADDING.left,
@@ -402,16 +391,16 @@ var LineChart = import_react.default.memo(({ data, labels, width, height, animat
402
391
  );
403
392
  });
404
393
  LineChart.displayName = "LineChart";
405
- var CurveChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
406
- const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
407
- const maxVal = import_react.default.useMemo(() => {
394
+ var CurveChart = import_react2.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
395
+ const entries = import_react2.default.useMemo(() => Object.entries(data), [data]);
396
+ const maxVal = import_react2.default.useMemo(() => {
408
397
  const allValues = entries.flatMap(([, v]) => v);
409
398
  return Math.max(...allValues) * 1.2 || 1;
410
399
  }, [entries]);
411
400
  const count = labels.length;
412
401
  const chartW = width - PADDING.left - PADDING.right;
413
402
  const chartH = height - PADDING.top - PADDING.bottom;
414
- const seriesPoints = import_react.default.useMemo(
403
+ const seriesPoints = import_react2.default.useMemo(
415
404
  () => entries.map(
416
405
  ([, values]) => values.map((v, i) => ({
417
406
  x: PADDING.left + i / (count - 1 || 1) * chartW,
@@ -421,34 +410,21 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
421
410
  ),
422
411
  [entries, count, chartW, chartH, maxVal]
423
412
  );
424
- const lineRefs = import_react.default.useRef([]);
425
- const curveClipRef = import_react.default.useRef(null);
413
+ const curveClipRef = import_react2.default.useRef(null);
426
414
  const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
427
- import_react.default.useEffect(() => {
428
- if (!animate) return;
429
- lineRefs.current.forEach((el) => {
430
- if (!el) return;
431
- const len = el.getTotalLength();
432
- el.style.strokeDasharray = `${len}`;
433
- el.style.strokeDashoffset = `${len}`;
434
- requestAnimationFrame(() => {
435
- el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
436
- el.style.strokeDashoffset = "0";
437
- });
415
+ import_react2.default.useEffect(() => {
416
+ if (!animate || !curveClipRef.current) return;
417
+ curveClipRef.current.setAttribute("width", "0");
418
+ requestAnimationFrame(() => {
419
+ if (curveClipRef.current) {
420
+ curveClipRef.current.style.transition = "width 1200ms ease-out 200ms";
421
+ curveClipRef.current.setAttribute("width", `${width}`);
422
+ }
438
423
  });
439
- if (curveClipRef.current) {
440
- curveClipRef.current.setAttribute("width", "0");
441
- requestAnimationFrame(() => {
442
- if (curveClipRef.current) {
443
- curveClipRef.current.style.transition = "width 1200ms ease-out 200ms";
444
- curveClipRef.current.setAttribute("width", `${width}`);
445
- }
446
- });
447
- }
448
- }, [animate, seriesPoints, width]);
424
+ }, [animate, width]);
449
425
  const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
450
426
  const curveClipId = "curve-area-clip";
451
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
427
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
452
428
  "svg",
453
429
  {
454
430
  viewBox: `0 0 ${width} ${height}`,
@@ -481,9 +457,9 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
481
457
  onLeave();
482
458
  },
483
459
  children: [
484
- animate && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("clipPath", { id: curveClipId, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { ref: curveClipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
485
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GridLines, { width, height, chartH, maxVal }),
486
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AxisLabels, { labels, count, chartW, height }),
460
+ animate && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("clipPath", { id: curveClipId, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { ref: curveClipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
461
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GridLines, { width, height, chartH, maxVal }),
462
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AxisLabels, { labels, count, chartW, height }),
487
463
  entries.map(([key], di) => {
488
464
  const palette = getPalette(LINE_BAR_PALETTES, di, key);
489
465
  const color = palette[2];
@@ -492,32 +468,16 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
492
468
  const gradientId = `curve-gradient-${di}`;
493
469
  const linePath = toSmoothPath(points);
494
470
  const areaPath = linePath + ` L ${points[points.length - 1].x} ${PADDING.top + chartH} L ${points[0].x} ${PADDING.top + chartH} Z`;
495
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
496
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
497
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
498
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
471
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { children: [
472
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
473
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
474
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
499
475
  ] }) }),
500
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
501
- "path",
502
- {
503
- d: areaPath,
504
- fill: `url(#${gradientId})`,
505
- clipPath: animate ? `url(#${curveClipId})` : void 0
506
- }
507
- ),
508
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
509
- "path",
510
- {
511
- ref: (el) => {
512
- lineRefs.current[di] = el;
513
- },
514
- d: linePath,
515
- fill: "none",
516
- stroke: color,
517
- strokeWidth: "2"
518
- }
519
- ),
520
- activeIndex !== null && points[activeIndex] && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
476
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { clipPath: animate ? `url(#${curveClipId})` : void 0, children: [
477
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: areaPath, fill: `url(#${gradientId})` }),
478
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: linePath, fill: "none", stroke: color, strokeWidth: "2" })
479
+ ] }),
480
+ activeIndex !== null && points[activeIndex] && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
521
481
  "circle",
522
482
  {
523
483
  cx: points[activeIndex].x,
@@ -529,7 +489,7 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
529
489
  )
530
490
  ] }, di);
531
491
  }),
532
- activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
492
+ activeX !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
533
493
  "line",
534
494
  {
535
495
  x1: activeX,
@@ -539,7 +499,7 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
539
499
  className: "chart-crosshair"
540
500
  }
541
501
  ),
542
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
502
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
543
503
  "rect",
544
504
  {
545
505
  x: PADDING.left,
@@ -555,9 +515,9 @@ var CurveChart = import_react.default.memo(({ data, labels, width, height, anima
555
515
  );
556
516
  });
557
517
  CurveChart.displayName = "CurveChart";
558
- var BarChart = import_react.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
559
- const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
560
- const maxVal = import_react.default.useMemo(() => {
518
+ var BarChart = import_react2.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
519
+ const entries = import_react2.default.useMemo(() => Object.entries(data), [data]);
520
+ const maxVal = import_react2.default.useMemo(() => {
561
521
  const allValues = entries.flatMap(([, v]) => v);
562
522
  return Math.max(...allValues) * 1.2 || 1;
563
523
  }, [entries]);
@@ -569,7 +529,7 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, animate
569
529
  const barGap = groupCount > 1 ? 2 : 0;
570
530
  const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
571
531
  const baseline = PADDING.top + chartH;
572
- const bars = import_react.default.useMemo(
532
+ const bars = import_react2.default.useMemo(
573
533
  () => entries.map(
574
534
  ([, values], di) => values.map((v, i) => {
575
535
  const totalBarsW = barW * groupCount + barGap * (groupCount - 1);
@@ -582,11 +542,11 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, animate
582
542
  [entries, maxVal, chartH, groupW, barW, barGap, groupCount]
583
543
  );
584
544
  const barLabelStep = getLabelStep(count, chartW);
585
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
586
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GridLines, { width, height, chartH, maxVal }),
545
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
546
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GridLines, { width, height, chartH, maxVal }),
587
547
  labels.map((label, i) => {
588
548
  if (i % barLabelStep !== 0) return null;
589
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x: PADDING.left + groupW * i + groupW / 2, y: height - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i);
549
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("text", { x: PADDING.left + groupW * i + groupW / 2, y: height - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i);
590
550
  }),
591
551
  entries.map(([key], di) => {
592
552
  const palette = getPalette(LINE_BAR_PALETTES, di, key);
@@ -595,7 +555,7 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, animate
595
555
  const r = Math.min(4, b.w / 2);
596
556
  const d = b.h <= r ? `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 + r} Q ${b.x} ${b.y} ${b.x + r} ${b.y} H ${b.x + b.w - r} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r} V ${b.y + b.h} Z`;
597
557
  const delay = 100 + i * 80;
598
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
558
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
599
559
  "path",
600
560
  {
601
561
  d,
@@ -616,11 +576,11 @@ var BarChart = import_react.default.memo(({ data, labels, width, height, animate
616
576
  ] });
617
577
  });
618
578
  BarChart.displayName = "BarChart";
619
- var PieDonutChart = import_react.default.memo(
579
+ var PieDonutChart = import_react2.default.memo(
620
580
  ({ data, labels, width, height, animate, isDoughnut, onHover, onMove, onLeave }) => {
621
- const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
622
- const values = import_react.default.useMemo(() => entries.flatMap(([, v]) => v), [entries]);
623
- const total = import_react.default.useMemo(() => values.reduce((a, b) => a + b, 0) || 1, [values]);
581
+ const entries = import_react2.default.useMemo(() => Object.entries(data), [data]);
582
+ const values = import_react2.default.useMemo(() => entries.flatMap(([, v]) => v), [entries]);
583
+ const total = import_react2.default.useMemo(() => values.reduce((a, b) => a + b, 0) || 1, [values]);
624
584
  const size = Math.min(width, height);
625
585
  const cx = size / 2;
626
586
  const cy = size / 2;
@@ -628,10 +588,10 @@ var PieDonutChart = import_react.default.memo(
628
588
  const innerR = isDoughnut ? r * 0.5 : 0;
629
589
  const firstKey = entries[0]?.[0] ?? "";
630
590
  const colorOffset = hashString(firstKey);
631
- const maskRef = import_react.default.useRef(null);
591
+ const maskRef = import_react2.default.useRef(null);
632
592
  const maskR = r + 10;
633
593
  const maskCircumference = 2 * Math.PI * maskR;
634
- import_react.default.useEffect(() => {
594
+ import_react2.default.useEffect(() => {
635
595
  if (!animate || !maskRef.current) return;
636
596
  const el = maskRef.current;
637
597
  el.style.strokeDasharray = `${maskCircumference}`;
@@ -641,7 +601,7 @@ var PieDonutChart = import_react.default.memo(
641
601
  el.style.strokeDashoffset = "0";
642
602
  });
643
603
  }, [animate, maskCircumference]);
644
- const sliceData = import_react.default.useMemo(() => {
604
+ const sliceData = import_react2.default.useMemo(() => {
645
605
  let angle0 = -Math.PI / 2;
646
606
  let cumulativeAngle = 0;
647
607
  return values.map((v, i) => {
@@ -675,8 +635,8 @@ var PieDonutChart = import_react.default.memo(
675
635
  });
676
636
  }, [values, total, cx, cy, r, innerR, labels]);
677
637
  const maskId = `pie-mask-${isDoughnut ? "d" : "p"}`;
678
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: [
679
- animate && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("mask", { id: maskId, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
638
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: [
639
+ animate && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("mask", { id: maskId, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
680
640
  "circle",
681
641
  {
682
642
  ref: maskRef,
@@ -689,7 +649,7 @@ var PieDonutChart = import_react.default.memo(
689
649
  transform: `rotate(-90 ${cx} ${cy})`
690
650
  }
691
651
  ) }) }),
692
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("g", { mask: animate ? `url(#${maskId})` : void 0, children: sliceData.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("g", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
652
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { mask: animate ? `url(#${maskId})` : void 0, children: sliceData.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("g", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
693
653
  "path",
694
654
  {
695
655
  d: s.d,
@@ -700,7 +660,7 @@ var PieDonutChart = import_react.default.memo(
700
660
  onMouseLeave: onLeave
701
661
  }
702
662
  ) }, i)) }),
703
- sliceData.map((s, i) => s.angle > 0.2 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
663
+ sliceData.map((s, i) => s.angle > 0.2 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
704
664
  "text",
705
665
  {
706
666
  x: s.lx,
@@ -718,9 +678,9 @@ var PieDonutChart = import_react.default.memo(
718
678
  );
719
679
  PieDonutChart.displayName = "PieDonutChart";
720
680
  var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
721
- const ref = import_react.default.useRef(null);
722
- const [pos, setPos] = import_react.default.useState({ left: 0, top: 0 });
723
- import_react.default.useLayoutEffect(() => {
681
+ const ref = import_react2.default.useRef(null);
682
+ const [pos, setPos] = import_react2.default.useState({ left: 0, top: 0 });
683
+ import_react2.default.useLayoutEffect(() => {
724
684
  const el = ref.current;
725
685
  if (!el) return;
726
686
  const w = el.offsetWidth;
@@ -733,7 +693,7 @@ var ChartTooltipPortal = ({ clientX, clientY, visible, children }) => {
733
693
  if (left < 8) left = 8;
734
694
  setPos({ left, top });
735
695
  }, [clientX, clientY]);
736
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
696
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
737
697
  "div",
738
698
  {
739
699
  ref,
@@ -750,14 +710,14 @@ var ChartLegend = ({ data, labels, type }) => {
750
710
  const total = values.reduce((a, b) => a + b, 0) || 1;
751
711
  const firstKey = entries[0]?.[0] ?? "";
752
712
  const colorOffset = hashString(firstKey);
753
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "chart-legend", children: values.map((v, i) => {
713
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "chart-legend", children: values.map((v, i) => {
754
714
  const pct = Math.round(v / total * 100);
755
715
  const color = PIE_COLORS[(i + colorOffset) % PIE_COLORS.length];
756
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-legend-item", children: [
757
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
758
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-legend-text", children: [
759
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-label", children: labels[i] || `${i + 1}` }),
760
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "chart-legend-value", children: [
716
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "chart-legend-item", children: [
717
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
718
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "chart-legend-text", children: [
719
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "chart-legend-label", children: labels[i] || `${i + 1}` }),
720
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "chart-legend-value", children: [
761
721
  v.toLocaleString(),
762
722
  "(",
763
723
  pct,
@@ -767,37 +727,37 @@ var ChartLegend = ({ data, labels, type }) => {
767
727
  ] }, i);
768
728
  }) });
769
729
  }
770
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "chart-legend", children: entries.map(([key], di) => {
730
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "chart-legend", children: entries.map(([key], di) => {
771
731
  const palette = getPalette(LINE_BAR_PALETTES, di, key);
772
732
  const color = palette[2];
773
733
  const values = entries[di][1];
774
734
  const sum = values.reduce((a, b) => a + b, 0);
775
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-legend-item", children: [
776
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
777
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "chart-legend-text", children: [
778
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-label", children: key }),
779
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "chart-legend-value", children: sum.toLocaleString() })
735
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "chart-legend-item", children: [
736
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
737
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "chart-legend-text", children: [
738
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "chart-legend-label", children: key }),
739
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "chart-legend-value", children: sum.toLocaleString() })
780
740
  ] })
781
741
  ] }, di);
782
742
  }) });
783
743
  };
784
- var Chart = import_react.default.memo((props) => {
744
+ var Chart = import_react2.default.memo((props) => {
785
745
  const { type, data, labels, tooltip: showTooltip = true } = props;
786
746
  const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
787
747
  const { width, height } = useChartSize(containerRef);
788
- const stableData = import_react.default.useMemo(() => data, [JSON.stringify(data)]);
789
- const stableLabels = import_react.default.useMemo(() => labels, [JSON.stringify(labels)]);
790
- const dataKey = import_react.default.useMemo(() => JSON.stringify(labels), [labels]);
748
+ const stableData = import_react2.default.useMemo(() => data, [JSON.stringify(data)]);
749
+ const stableLabels = import_react2.default.useMemo(() => labels, [JSON.stringify(labels)]);
750
+ const dataKey = import_react2.default.useMemo(() => JSON.stringify(labels), [labels]);
791
751
  const animate = useChartAnimation(containerRef, dataKey);
792
752
  const ready = width > 0 && height > 0;
793
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
794
- ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
795
- ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
796
- ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
797
- ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
798
- 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 }),
799
- ready && (type === "bar" || type === "pie" || type === "doughnut") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartLegend, { data: stableData, labels: stableLabels, type }),
800
- tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChartTooltipPortal, { clientX: tooltip.clientX, clientY: tooltip.clientY, visible: tooltip.visible, children: tooltip.content })
753
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
754
+ ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
755
+ ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
756
+ ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
757
+ ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
758
+ ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
759
+ ready && (type === "bar" || type === "pie" || type === "doughnut") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChartLegend, { data: stableData, labels: stableLabels, type }),
760
+ tooltip.content && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChartTooltipPortal, { clientX: tooltip.clientX, clientY: tooltip.clientY, visible: tooltip.visible, children: tooltip.content }) })
801
761
  ] });
802
762
  });
803
763
  Chart.displayName = "Chart";