@x-plat/design-system 0.5.18 → 0.5.20

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.
Files changed (33) hide show
  1. package/dist/components/Chart/index.cjs +147 -27
  2. package/dist/components/Chart/index.css +74 -7
  3. package/dist/components/Chart/index.js +147 -27
  4. package/dist/components/Dropdown/index.cjs +2 -0
  5. package/dist/components/Dropdown/index.js +2 -0
  6. package/dist/components/PopOver/index.cjs +2 -0
  7. package/dist/components/PopOver/index.css +2 -0
  8. package/dist/components/PopOver/index.js +2 -0
  9. package/dist/components/Select/index.cjs +2 -0
  10. package/dist/components/Select/index.js +2 -0
  11. package/dist/components/Skeleton/index.cjs +11 -3
  12. package/dist/components/Skeleton/index.d.cts +1 -1
  13. package/dist/components/Skeleton/index.d.ts +1 -1
  14. package/dist/components/Skeleton/index.js +11 -3
  15. package/dist/components/index.cjs +160 -30
  16. package/dist/components/index.css +76 -7
  17. package/dist/components/index.js +160 -30
  18. package/dist/index.cjs +180 -32
  19. package/dist/index.css +76 -7
  20. package/dist/index.js +180 -32
  21. package/dist/layout/Grid/FullGrid/index.cjs +10 -1
  22. package/dist/layout/Grid/FullGrid/index.d.cts +2 -2
  23. package/dist/layout/Grid/FullGrid/index.d.ts +2 -2
  24. package/dist/layout/Grid/FullGrid/index.js +10 -1
  25. package/dist/layout/Grid/FullScreen/index.cjs +10 -1
  26. package/dist/layout/Grid/FullScreen/index.d.cts +2 -2
  27. package/dist/layout/Grid/FullScreen/index.d.ts +2 -2
  28. package/dist/layout/Grid/FullScreen/index.js +10 -1
  29. package/dist/layout/Grid/index.cjs +20 -2
  30. package/dist/layout/Grid/index.js +20 -2
  31. package/dist/layout/index.cjs +20 -2
  32. package/dist/layout/index.js +20 -2
  33. package/package.json +1 -1
@@ -2109,6 +2109,37 @@ var useChartSize = (ref) => {
2109
2109
  }, [ref]);
2110
2110
  return size;
2111
2111
  };
2112
+ var prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2113
+ var useChartAnimation = (containerRef, dataKey) => {
2114
+ const [animate, setAnimate] = React5.useState(false);
2115
+ const prevDataKey = React5.useRef(dataKey);
2116
+ const hasAnimated = React5.useRef(false);
2117
+ React5.useEffect(() => {
2118
+ if (prefersReducedMotion()) return;
2119
+ const el = containerRef.current;
2120
+ if (!el) return;
2121
+ const observer = new IntersectionObserver(
2122
+ ([entry]) => {
2123
+ if (entry.isIntersecting && !hasAnimated.current) {
2124
+ hasAnimated.current = true;
2125
+ setAnimate(true);
2126
+ }
2127
+ },
2128
+ { threshold: 0.1 }
2129
+ );
2130
+ observer.observe(el);
2131
+ return () => observer.disconnect();
2132
+ }, [containerRef]);
2133
+ React5.useEffect(() => {
2134
+ if (dataKey !== prevDataKey.current) {
2135
+ prevDataKey.current = dataKey;
2136
+ if (prefersReducedMotion()) return;
2137
+ setAnimate(false);
2138
+ requestAnimationFrame(() => setAnimate(true));
2139
+ }
2140
+ }, [dataKey]);
2141
+ return animate || prefersReducedMotion();
2142
+ };
2112
2143
  var useChartTooltip = (enabled) => {
2113
2144
  const [tooltip, setTooltip] = React5.useState({
2114
2145
  visible: false,
@@ -2174,7 +2205,7 @@ var AxisLabels = React5.memo(({ labels, count, chartW, height }) => {
2174
2205
  }) });
2175
2206
  });
2176
2207
  AxisLabels.displayName = "AxisLabels";
2177
- var LineChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
2208
+ var LineChart = React5.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
2178
2209
  const entries = React5.useMemo(() => Object.entries(data), [data]);
2179
2210
  const maxVal = React5.useMemo(() => {
2180
2211
  const allValues = entries.flatMap(([, v]) => v);
@@ -2194,18 +2225,52 @@ var LineChart = React5.memo(({ data, labels, width, height, onHover, onMove, onL
2194
2225
  [entries, count, chartW, chartH, maxVal]
2195
2226
  );
2196
2227
  const showPoints = count <= 100;
2228
+ const lineRefs = React5.useRef([]);
2229
+ React5.useEffect(() => {
2230
+ if (!animate) return;
2231
+ lineRefs.current.forEach((el) => {
2232
+ if (!el) return;
2233
+ const len = el.getTotalLength();
2234
+ el.style.strokeDasharray = `${len}`;
2235
+ el.style.strokeDashoffset = `${len}`;
2236
+ requestAnimationFrame(() => {
2237
+ el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
2238
+ el.style.strokeDashoffset = "0";
2239
+ });
2240
+ });
2241
+ }, [animate, seriesPoints]);
2197
2242
  return /* @__PURE__ */ jsxs196("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
2198
2243
  /* @__PURE__ */ jsx305(GridLines, { width, height, chartH, maxVal }),
2199
2244
  /* @__PURE__ */ jsx305(AxisLabels, { labels, count, chartW, height }),
2200
2245
  entries.map(([key], di) => {
2201
2246
  const palette = getPalette(LINE_BAR_PALETTES, di, key);
2202
2247
  const color = palette[2];
2248
+ const areaColor = palette[0];
2203
2249
  const points = seriesPoints[di];
2250
+ const gradientId = `line-gradient-${di}`;
2251
+ const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
2252
+ 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`;
2204
2253
  return /* @__PURE__ */ jsxs196("g", { children: [
2254
+ /* @__PURE__ */ jsx305("defs", { children: /* @__PURE__ */ jsxs196("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
2255
+ /* @__PURE__ */ jsx305("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
2256
+ /* @__PURE__ */ jsx305("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
2257
+ ] }) }),
2258
+ /* @__PURE__ */ jsx305(
2259
+ "path",
2260
+ {
2261
+ d: areaD,
2262
+ fill: `url(#${gradientId})`,
2263
+ className: "chart-area",
2264
+ style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
2265
+ }
2266
+ ),
2205
2267
  /* @__PURE__ */ jsx305(
2206
2268
  "polyline",
2207
2269
  {
2208
- points: points.map((p) => `${p.x},${p.y}`).join(" "),
2270
+ ref: (el) => {
2271
+ lineRefs.current[di] = el;
2272
+ },
2273
+ points: polyPoints,
2209
2274
  fill: "none",
2210
2275
  stroke: color,
2211
2276
  strokeWidth: "2"
@@ -2230,7 +2295,7 @@ var LineChart = React5.memo(({ data, labels, width, height, onHover, onMove, onL
2230
2295
  ] });
2231
2296
  });
2232
2297
  LineChart.displayName = "LineChart";
2233
- var CurveChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
2298
+ var CurveChart = React5.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
2234
2299
  const entries = React5.useMemo(() => Object.entries(data), [data]);
2235
2300
  const maxVal = React5.useMemo(() => {
2236
2301
  const allValues = entries.flatMap(([, v]) => v);
@@ -2250,6 +2315,20 @@ var CurveChart = React5.memo(({ data, labels, width, height, onHover, onMove, on
2250
2315
  [entries, count, chartW, chartH, maxVal]
2251
2316
  );
2252
2317
  const showPoints = count <= 100;
2318
+ const lineRefs = React5.useRef([]);
2319
+ React5.useEffect(() => {
2320
+ if (!animate) return;
2321
+ lineRefs.current.forEach((el) => {
2322
+ if (!el) return;
2323
+ const len = el.getTotalLength();
2324
+ el.style.strokeDasharray = `${len}`;
2325
+ el.style.strokeDashoffset = `${len}`;
2326
+ requestAnimationFrame(() => {
2327
+ el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
2328
+ el.style.strokeDashoffset = "0";
2329
+ });
2330
+ });
2331
+ }, [animate, seriesPoints]);
2253
2332
  return /* @__PURE__ */ jsxs196("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
2254
2333
  /* @__PURE__ */ jsx305(GridLines, { width, height, chartH, maxVal }),
2255
2334
  /* @__PURE__ */ jsx305(AxisLabels, { labels, count, chartW, height }),
@@ -2266,8 +2345,27 @@ var CurveChart = React5.memo(({ data, labels, width, height, onHover, onMove, on
2266
2345
  /* @__PURE__ */ jsx305("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
2267
2346
  /* @__PURE__ */ jsx305("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
2268
2347
  ] }) }),
2269
- /* @__PURE__ */ jsx305("path", { d: areaPath, fill: `url(#${gradientId})` }),
2270
- /* @__PURE__ */ jsx305("path", { d: linePath, fill: "none", stroke: color, strokeWidth: "2" }),
2348
+ /* @__PURE__ */ jsx305(
2349
+ "path",
2350
+ {
2351
+ d: areaPath,
2352
+ fill: `url(#${gradientId})`,
2353
+ className: "chart-area",
2354
+ style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
2355
+ }
2356
+ ),
2357
+ /* @__PURE__ */ jsx305(
2358
+ "path",
2359
+ {
2360
+ ref: (el) => {
2361
+ lineRefs.current[di] = el;
2362
+ },
2363
+ d: linePath,
2364
+ fill: "none",
2365
+ stroke: color,
2366
+ strokeWidth: "2"
2367
+ }
2368
+ ),
2271
2369
  showPoints && points.map((p, i) => /* @__PURE__ */ jsx305(
2272
2370
  "circle",
2273
2371
  {
@@ -2287,7 +2385,7 @@ var CurveChart = React5.memo(({ data, labels, width, height, onHover, onMove, on
2287
2385
  ] });
2288
2386
  });
2289
2387
  CurveChart.displayName = "CurveChart";
2290
- var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
2388
+ var BarChart = React5.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
2291
2389
  const entries = React5.useMemo(() => Object.entries(data), [data]);
2292
2390
  const maxVal = React5.useMemo(() => {
2293
2391
  const allValues = entries.flatMap(([, v]) => v);
@@ -2300,6 +2398,7 @@ var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLe
2300
2398
  const groupW = chartW / count;
2301
2399
  const barGap = groupCount > 1 ? 2 : 0;
2302
2400
  const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
2401
+ const baseline = PADDING.top + chartH;
2303
2402
  const bars = React5.useMemo(
2304
2403
  () => entries.map(
2305
2404
  ([, values], di) => values.map((v, i) => {
@@ -2325,12 +2424,17 @@ var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLe
2325
2424
  return bars[di].map((b, i) => {
2326
2425
  const r2 = Math.min(4, b.w / 2);
2327
2426
  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`;
2427
+ const delay = 100 + i * 80;
2328
2428
  return /* @__PURE__ */ jsx305(
2329
2429
  "path",
2330
2430
  {
2331
2431
  d,
2332
2432
  fill: color,
2333
- className: "chart-bar",
2433
+ className: `chart-bar ${animate ? "chart-bar-animate" : ""}`,
2434
+ style: animate ? {
2435
+ transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
2436
+ animationDelay: `${delay}ms`
2437
+ } : void 0,
2334
2438
  onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
2335
2439
  onMouseMove: onMove,
2336
2440
  onMouseLeave: onLeave
@@ -2343,7 +2447,7 @@ var BarChart = React5.memo(({ data, labels, width, height, onHover, onMove, onLe
2343
2447
  });
2344
2448
  BarChart.displayName = "BarChart";
2345
2449
  var PieDonutChart = React5.memo(
2346
- ({ data, labels, width, height, isDoughnut, onHover, onMove, onLeave }) => {
2450
+ ({ data, labels, width, height, animate, isDoughnut, onHover, onMove, onLeave }) => {
2347
2451
  const entries = React5.useMemo(() => Object.entries(data), [data]);
2348
2452
  const values = React5.useMemo(() => entries.flatMap(([, v]) => v), [entries]);
2349
2453
  const total = React5.useMemo(() => values.reduce((a, b) => a + b, 0) || 1, [values]);
@@ -2383,20 +2487,34 @@ var PieDonutChart = React5.memo(
2383
2487
  return { d, lx, ly, v, pct, angle, label: labels[i] || `${i + 1}` };
2384
2488
  });
2385
2489
  }, [values, total, cx, cy, r2, innerR, labels]);
2386
- return /* @__PURE__ */ jsx305("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: sliceData.map((s, i) => /* @__PURE__ */ jsxs196("g", { children: [
2387
- /* @__PURE__ */ jsx305(
2388
- "path",
2389
- {
2390
- d: s.d,
2391
- fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
2392
- className: "chart-slice",
2393
- onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
2394
- onMouseMove: onMove,
2395
- onMouseLeave: onLeave
2396
- }
2397
- ),
2398
- s.angle > 0.2 && /* @__PURE__ */ jsx305("text", { x: s.lx, y: s.ly, className: "chart-pie-label", textAnchor: "middle", dominantBaseline: "central", children: s.v })
2399
- ] }, i)) });
2490
+ return /* @__PURE__ */ jsx305("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: sliceData.map((s, i) => {
2491
+ const delay = i * 100;
2492
+ return /* @__PURE__ */ jsxs196("g", { className: animate ? "chart-slice-group-animate" : "", style: animate ? { animationDelay: `${delay}ms` } : void 0, children: [
2493
+ /* @__PURE__ */ jsx305(
2494
+ "path",
2495
+ {
2496
+ d: s.d,
2497
+ fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
2498
+ className: "chart-slice",
2499
+ onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
2500
+ onMouseMove: onMove,
2501
+ onMouseLeave: onLeave
2502
+ }
2503
+ ),
2504
+ s.angle > 0.2 && /* @__PURE__ */ jsx305(
2505
+ "text",
2506
+ {
2507
+ x: s.lx,
2508
+ y: s.ly,
2509
+ className: `chart-pie-label ${animate ? "chart-pie-label-animate" : ""}`,
2510
+ style: animate ? { animationDelay: `${delay + 150}ms` } : void 0,
2511
+ textAnchor: "middle",
2512
+ dominantBaseline: "central",
2513
+ children: s.v
2514
+ }
2515
+ )
2516
+ ] }, i);
2517
+ }) });
2400
2518
  }
2401
2519
  );
2402
2520
  PieDonutChart.displayName = "PieDonutChart";
@@ -2430,13 +2548,15 @@ var Chart = React5.memo((props) => {
2430
2548
  const { width, height } = useChartSize(containerRef);
2431
2549
  const stableData = React5.useMemo(() => data, [JSON.stringify(data)]);
2432
2550
  const stableLabels = React5.useMemo(() => labels, [JSON.stringify(labels)]);
2551
+ const dataKey = React5.useMemo(() => JSON.stringify(labels), [labels]);
2552
+ const animate = useChartAnimation(containerRef, dataKey);
2433
2553
  const ready = width > 0 && height > 0;
2434
2554
  return /* @__PURE__ */ jsxs196("div", { className: "lib-xplat-chart", ref: containerRef, children: [
2435
- ready && type === "line" && /* @__PURE__ */ jsx305(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
2436
- ready && type === "curve" && /* @__PURE__ */ jsx305(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
2437
- ready && type === "bar" && /* @__PURE__ */ jsx305(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
2438
- ready && type === "pie" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
2439
- ready && type === "doughnut" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
2555
+ ready && type === "line" && /* @__PURE__ */ jsx305(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2556
+ ready && type === "curve" && /* @__PURE__ */ jsx305(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2557
+ ready && type === "bar" && /* @__PURE__ */ jsx305(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2558
+ ready && type === "pie" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
2559
+ ready && type === "doughnut" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
2440
2560
  tooltip.visible && /* @__PURE__ */ jsx305(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
2441
2561
  ] });
2442
2562
  });
@@ -3333,6 +3453,8 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
3333
3453
  React17.useLayoutEffect(() => {
3334
3454
  if (!enabled) return;
3335
3455
  calculatePosition();
3456
+ const raf = requestAnimationFrame(calculatePosition);
3457
+ return () => cancelAnimationFrame(raf);
3336
3458
  }, [calculatePosition, enabled]);
3337
3459
  React17.useEffect(() => {
3338
3460
  if (!enabled) return;
@@ -4149,12 +4271,20 @@ var Select_default = Select;
4149
4271
 
4150
4272
  // src/components/Skeleton/Skeleton.tsx
4151
4273
  import { jsx as jsx333 } from "react/jsx-runtime";
4152
- var toSizeVar = (token) => token === "full" ? "100%" : `var(--spacing-size-${token})`;
4274
+ var SIZE_MAP = {
4275
+ xs: "var(--spacing-size-1)",
4276
+ sm: "var(--spacing-size-2)",
4277
+ md: "var(--spacing-size-4)",
4278
+ lg: "var(--spacing-size-8)",
4279
+ xl: "var(--spacing-size-12)",
4280
+ "2xl": "var(--spacing-size-16)",
4281
+ full: "100%"
4282
+ };
4153
4283
  var Skeleton = (props) => {
4154
4284
  const { variant = "text", width, height } = props;
4155
4285
  const style = {
4156
- ...width != null && { width: toSizeVar(width) },
4157
- ...height != null && { height: toSizeVar(height) }
4286
+ ...width != null && { width: SIZE_MAP[width] },
4287
+ ...height != null && { height: SIZE_MAP[height] }
4158
4288
  };
4159
4289
  return /* @__PURE__ */ jsx333(
4160
4290
  "div",
package/dist/index.cjs CHANGED
@@ -6608,6 +6608,37 @@ var useChartSize = (ref) => {
6608
6608
  }, [ref]);
6609
6609
  return size;
6610
6610
  };
6611
+ var prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
6612
+ var useChartAnimation = (containerRef, dataKey) => {
6613
+ const [animate, setAnimate] = import_react5.default.useState(false);
6614
+ const prevDataKey = import_react5.default.useRef(dataKey);
6615
+ const hasAnimated = import_react5.default.useRef(false);
6616
+ import_react5.default.useEffect(() => {
6617
+ if (prefersReducedMotion()) return;
6618
+ const el = containerRef.current;
6619
+ if (!el) return;
6620
+ const observer = new IntersectionObserver(
6621
+ ([entry]) => {
6622
+ if (entry.isIntersecting && !hasAnimated.current) {
6623
+ hasAnimated.current = true;
6624
+ setAnimate(true);
6625
+ }
6626
+ },
6627
+ { threshold: 0.1 }
6628
+ );
6629
+ observer.observe(el);
6630
+ return () => observer.disconnect();
6631
+ }, [containerRef]);
6632
+ import_react5.default.useEffect(() => {
6633
+ if (dataKey !== prevDataKey.current) {
6634
+ prevDataKey.current = dataKey;
6635
+ if (prefersReducedMotion()) return;
6636
+ setAnimate(false);
6637
+ requestAnimationFrame(() => setAnimate(true));
6638
+ }
6639
+ }, [dataKey]);
6640
+ return animate || prefersReducedMotion();
6641
+ };
6611
6642
  var useChartTooltip = (enabled) => {
6612
6643
  const [tooltip, setTooltip] = import_react5.default.useState({
6613
6644
  visible: false,
@@ -6673,7 +6704,7 @@ var AxisLabels = import_react5.default.memo(({ labels, count, chartW, height })
6673
6704
  }) });
6674
6705
  });
6675
6706
  AxisLabels.displayName = "AxisLabels";
6676
- var LineChart = import_react5.default.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
6707
+ var LineChart = import_react5.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
6677
6708
  const entries = import_react5.default.useMemo(() => Object.entries(data), [data]);
6678
6709
  const maxVal = import_react5.default.useMemo(() => {
6679
6710
  const allValues = entries.flatMap(([, v]) => v);
@@ -6693,18 +6724,52 @@ var LineChart = import_react5.default.memo(({ data, labels, width, height, onHov
6693
6724
  [entries, count, chartW, chartH, maxVal]
6694
6725
  );
6695
6726
  const showPoints = count <= 100;
6727
+ const lineRefs = import_react5.default.useRef([]);
6728
+ import_react5.default.useEffect(() => {
6729
+ if (!animate) return;
6730
+ lineRefs.current.forEach((el) => {
6731
+ if (!el) return;
6732
+ const len = el.getTotalLength();
6733
+ el.style.strokeDasharray = `${len}`;
6734
+ el.style.strokeDashoffset = `${len}`;
6735
+ requestAnimationFrame(() => {
6736
+ el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
6737
+ el.style.strokeDashoffset = "0";
6738
+ });
6739
+ });
6740
+ }, [animate, seriesPoints]);
6696
6741
  return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
6697
6742
  /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(GridLines, { width, height, chartH, maxVal }),
6698
6743
  /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(AxisLabels, { labels, count, chartW, height }),
6699
6744
  entries.map(([key], di) => {
6700
6745
  const palette = getPalette(LINE_BAR_PALETTES, di, key);
6701
6746
  const color = palette[2];
6747
+ const areaColor = palette[0];
6702
6748
  const points = seriesPoints[di];
6749
+ const gradientId = `line-gradient-${di}`;
6750
+ const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
6751
+ 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`;
6703
6752
  return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("g", { children: [
6753
+ /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
6754
+ /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
6755
+ /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
6756
+ ] }) }),
6757
+ /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
6758
+ "path",
6759
+ {
6760
+ d: areaD,
6761
+ fill: `url(#${gradientId})`,
6762
+ className: "chart-area",
6763
+ style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
6764
+ }
6765
+ ),
6704
6766
  /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
6705
6767
  "polyline",
6706
6768
  {
6707
- points: points.map((p) => `${p.x},${p.y}`).join(" "),
6769
+ ref: (el) => {
6770
+ lineRefs.current[di] = el;
6771
+ },
6772
+ points: polyPoints,
6708
6773
  fill: "none",
6709
6774
  stroke: color,
6710
6775
  strokeWidth: "2"
@@ -6729,7 +6794,7 @@ var LineChart = import_react5.default.memo(({ data, labels, width, height, onHov
6729
6794
  ] });
6730
6795
  });
6731
6796
  LineChart.displayName = "LineChart";
6732
- var CurveChart = import_react5.default.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
6797
+ var CurveChart = import_react5.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
6733
6798
  const entries = import_react5.default.useMemo(() => Object.entries(data), [data]);
6734
6799
  const maxVal = import_react5.default.useMemo(() => {
6735
6800
  const allValues = entries.flatMap(([, v]) => v);
@@ -6749,6 +6814,20 @@ var CurveChart = import_react5.default.memo(({ data, labels, width, height, onHo
6749
6814
  [entries, count, chartW, chartH, maxVal]
6750
6815
  );
6751
6816
  const showPoints = count <= 100;
6817
+ const lineRefs = import_react5.default.useRef([]);
6818
+ import_react5.default.useEffect(() => {
6819
+ if (!animate) return;
6820
+ lineRefs.current.forEach((el) => {
6821
+ if (!el) return;
6822
+ const len = el.getTotalLength();
6823
+ el.style.strokeDasharray = `${len}`;
6824
+ el.style.strokeDashoffset = `${len}`;
6825
+ requestAnimationFrame(() => {
6826
+ el.style.transition = "stroke-dashoffset 1200ms ease-out 200ms";
6827
+ el.style.strokeDashoffset = "0";
6828
+ });
6829
+ });
6830
+ }, [animate, seriesPoints]);
6752
6831
  return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
6753
6832
  /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(GridLines, { width, height, chartH, maxVal }),
6754
6833
  /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(AxisLabels, { labels, count, chartW, height }),
@@ -6765,8 +6844,27 @@ var CurveChart = import_react5.default.memo(({ data, labels, width, height, onHo
6765
6844
  /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
6766
6845
  /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
6767
6846
  ] }) }),
6768
- /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("path", { d: areaPath, fill: `url(#${gradientId})` }),
6769
- /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("path", { d: linePath, fill: "none", stroke: color, strokeWidth: "2" }),
6847
+ /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
6848
+ "path",
6849
+ {
6850
+ d: areaPath,
6851
+ fill: `url(#${gradientId})`,
6852
+ className: "chart-area",
6853
+ style: animate ? { animationDelay: "600ms" } : { opacity: 1 }
6854
+ }
6855
+ ),
6856
+ /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
6857
+ "path",
6858
+ {
6859
+ ref: (el) => {
6860
+ lineRefs.current[di] = el;
6861
+ },
6862
+ d: linePath,
6863
+ fill: "none",
6864
+ stroke: color,
6865
+ strokeWidth: "2"
6866
+ }
6867
+ ),
6770
6868
  showPoints && points.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
6771
6869
  "circle",
6772
6870
  {
@@ -6786,7 +6884,7 @@ var CurveChart = import_react5.default.memo(({ data, labels, width, height, onHo
6786
6884
  ] });
6787
6885
  });
6788
6886
  CurveChart.displayName = "CurveChart";
6789
- var BarChart = import_react5.default.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
6887
+ var BarChart = import_react5.default.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
6790
6888
  const entries = import_react5.default.useMemo(() => Object.entries(data), [data]);
6791
6889
  const maxVal = import_react5.default.useMemo(() => {
6792
6890
  const allValues = entries.flatMap(([, v]) => v);
@@ -6799,6 +6897,7 @@ var BarChart = import_react5.default.memo(({ data, labels, width, height, onHove
6799
6897
  const groupW = chartW / count;
6800
6898
  const barGap = groupCount > 1 ? 2 : 0;
6801
6899
  const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
6900
+ const baseline = PADDING.top + chartH;
6802
6901
  const bars = import_react5.default.useMemo(
6803
6902
  () => entries.map(
6804
6903
  ([, values], di) => values.map((v, i) => {
@@ -6824,12 +6923,17 @@ var BarChart = import_react5.default.memo(({ data, labels, width, height, onHove
6824
6923
  return bars[di].map((b, i) => {
6825
6924
  const r2 = Math.min(4, b.w / 2);
6826
6925
  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`;
6926
+ const delay = 100 + i * 80;
6827
6927
  return /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
6828
6928
  "path",
6829
6929
  {
6830
6930
  d,
6831
6931
  fill: color,
6832
- className: "chart-bar",
6932
+ className: `chart-bar ${animate ? "chart-bar-animate" : ""}`,
6933
+ style: animate ? {
6934
+ transformOrigin: `${b.x + b.w / 2}px ${baseline}px`,
6935
+ animationDelay: `${delay}ms`
6936
+ } : void 0,
6833
6937
  onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
6834
6938
  onMouseMove: onMove,
6835
6939
  onMouseLeave: onLeave
@@ -6842,7 +6946,7 @@ var BarChart = import_react5.default.memo(({ data, labels, width, height, onHove
6842
6946
  });
6843
6947
  BarChart.displayName = "BarChart";
6844
6948
  var PieDonutChart = import_react5.default.memo(
6845
- ({ data, labels, width, height, isDoughnut, onHover, onMove, onLeave }) => {
6949
+ ({ data, labels, width, height, animate, isDoughnut, onHover, onMove, onLeave }) => {
6846
6950
  const entries = import_react5.default.useMemo(() => Object.entries(data), [data]);
6847
6951
  const values = import_react5.default.useMemo(() => entries.flatMap(([, v]) => v), [entries]);
6848
6952
  const total = import_react5.default.useMemo(() => values.reduce((a, b) => a + b, 0) || 1, [values]);
@@ -6882,20 +6986,34 @@ var PieDonutChart = import_react5.default.memo(
6882
6986
  return { d, lx, ly, v, pct, angle, label: labels[i] || `${i + 1}` };
6883
6987
  });
6884
6988
  }, [values, total, cx, cy, r2, innerR, labels]);
6885
- return /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: sliceData.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("g", { children: [
6886
- /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
6887
- "path",
6888
- {
6889
- d: s.d,
6890
- fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
6891
- className: "chart-slice",
6892
- onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
6893
- onMouseMove: onMove,
6894
- onMouseLeave: onLeave
6895
- }
6896
- ),
6897
- s.angle > 0.2 && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("text", { x: s.lx, y: s.ly, className: "chart-pie-label", textAnchor: "middle", dominantBaseline: "central", children: s.v })
6898
- ] }, i)) });
6989
+ return /* @__PURE__ */ (0, import_jsx_runtime305.jsx)("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: sliceData.map((s, i) => {
6990
+ const delay = i * 100;
6991
+ return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("g", { className: animate ? "chart-slice-group-animate" : "", style: animate ? { animationDelay: `${delay}ms` } : void 0, children: [
6992
+ /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
6993
+ "path",
6994
+ {
6995
+ d: s.d,
6996
+ fill: PIE_COLORS[(i + colorOffset) % PIE_COLORS.length],
6997
+ className: "chart-slice",
6998
+ onMouseEnter: (e) => onHover(e, `${s.label}: ${s.v} (${s.pct}%)`),
6999
+ onMouseMove: onMove,
7000
+ onMouseLeave: onLeave
7001
+ }
7002
+ ),
7003
+ s.angle > 0.2 && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(
7004
+ "text",
7005
+ {
7006
+ x: s.lx,
7007
+ y: s.ly,
7008
+ className: `chart-pie-label ${animate ? "chart-pie-label-animate" : ""}`,
7009
+ style: animate ? { animationDelay: `${delay + 150}ms` } : void 0,
7010
+ textAnchor: "middle",
7011
+ dominantBaseline: "central",
7012
+ children: s.v
7013
+ }
7014
+ )
7015
+ ] }, i);
7016
+ }) });
6899
7017
  }
6900
7018
  );
6901
7019
  PieDonutChart.displayName = "PieDonutChart";
@@ -6929,13 +7047,15 @@ var Chart = import_react5.default.memo((props) => {
6929
7047
  const { width, height } = useChartSize(containerRef);
6930
7048
  const stableData = import_react5.default.useMemo(() => data, [JSON.stringify(data)]);
6931
7049
  const stableLabels = import_react5.default.useMemo(() => labels, [JSON.stringify(labels)]);
7050
+ const dataKey = import_react5.default.useMemo(() => JSON.stringify(labels), [labels]);
7051
+ const animate = useChartAnimation(containerRef, dataKey);
6932
7052
  const ready = width > 0 && height > 0;
6933
7053
  return /* @__PURE__ */ (0, import_jsx_runtime305.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
6934
- ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
6935
- ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
6936
- ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
6937
- ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, onHover: show, onMove: move, onLeave: hide }),
6938
- ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
7054
+ ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
7055
+ ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
7056
+ ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
7057
+ ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
7058
+ ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
6939
7059
  tooltip.visible && /* @__PURE__ */ (0, import_jsx_runtime305.jsx)(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
6940
7060
  ] });
6941
7061
  });
@@ -7845,6 +7965,8 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
7845
7965
  import_react18.default.useLayoutEffect(() => {
7846
7966
  if (!enabled) return;
7847
7967
  calculatePosition();
7968
+ const raf = requestAnimationFrame(calculatePosition);
7969
+ return () => cancelAnimationFrame(raf);
7848
7970
  }, [calculatePosition, enabled]);
7849
7971
  import_react18.default.useEffect(() => {
7850
7972
  if (!enabled) return;
@@ -8661,12 +8783,20 @@ var Select_default = Select;
8661
8783
 
8662
8784
  // src/components/Skeleton/Skeleton.tsx
8663
8785
  var import_jsx_runtime333 = require("react/jsx-runtime");
8664
- var toSizeVar = (token) => token === "full" ? "100%" : `var(--spacing-size-${token})`;
8786
+ var SIZE_MAP = {
8787
+ xs: "var(--spacing-size-1)",
8788
+ sm: "var(--spacing-size-2)",
8789
+ md: "var(--spacing-size-4)",
8790
+ lg: "var(--spacing-size-8)",
8791
+ xl: "var(--spacing-size-12)",
8792
+ "2xl": "var(--spacing-size-16)",
8793
+ full: "100%"
8794
+ };
8665
8795
  var Skeleton = (props) => {
8666
8796
  const { variant = "text", width, height } = props;
8667
8797
  const style = {
8668
- ...width != null && { width: toSizeVar(width) },
8669
- ...height != null && { height: toSizeVar(height) }
8798
+ ...width != null && { width: SIZE_MAP[width] },
8799
+ ...height != null && { height: SIZE_MAP[height] }
8670
8800
  };
8671
8801
  return /* @__PURE__ */ (0, import_jsx_runtime333.jsx)(
8672
8802
  "div",
@@ -9809,9 +9939,18 @@ var Video_default = Video;
9809
9939
 
9810
9940
  // src/layout/Grid/FullGrid/FullGrid.tsx
9811
9941
  var import_jsx_runtime348 = require("react/jsx-runtime");
9942
+ var GAP_MAP = {
9943
+ none: "var(--spacing-space-none)",
9944
+ xs: "var(--spacing-space-1)",
9945
+ sm: "var(--spacing-space-2)",
9946
+ md: "var(--spacing-space-4)",
9947
+ lg: "var(--spacing-space-6)",
9948
+ xl: "var(--spacing-space-8)",
9949
+ "2xl": "var(--spacing-space-12)"
9950
+ };
9812
9951
  var FullGrid = (props) => {
9813
9952
  const { children, gap } = props;
9814
- const style = gap != null ? { gap: `var(--spacing-space-${gap})` } : void 0;
9953
+ const style = gap != null ? { gap: GAP_MAP[gap] } : void 0;
9815
9954
  return /* @__PURE__ */ (0, import_jsx_runtime348.jsx)("div", { className: "lib-xplat-full-grid", style, children });
9816
9955
  };
9817
9956
  FullGrid.displayName = "FullGrid";
@@ -9819,9 +9958,18 @@ var FullGrid_default = FullGrid;
9819
9958
 
9820
9959
  // src/layout/Grid/FullScreen/FullScreen.tsx
9821
9960
  var import_jsx_runtime349 = require("react/jsx-runtime");
9961
+ var GAP_MAP2 = {
9962
+ none: "var(--spacing-space-none)",
9963
+ xs: "var(--spacing-space-1)",
9964
+ sm: "var(--spacing-space-2)",
9965
+ md: "var(--spacing-space-4)",
9966
+ lg: "var(--spacing-space-6)",
9967
+ xl: "var(--spacing-space-8)",
9968
+ "2xl": "var(--spacing-space-12)"
9969
+ };
9822
9970
  var FullScreen = (props) => {
9823
9971
  const { children, gap } = props;
9824
- const style = gap != null ? { gap: `var(--spacing-space-${gap})` } : void 0;
9972
+ const style = gap != null ? { gap: GAP_MAP2[gap] } : void 0;
9825
9973
  return /* @__PURE__ */ (0, import_jsx_runtime349.jsx)("div", { className: "lib-xplat-full-screen", style, children });
9826
9974
  };
9827
9975
  FullScreen.displayName = "FullScreen";