@x-plat/design-system 0.5.8 → 0.5.10

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.
@@ -17,24 +17,45 @@ var __copyProps = (to, from, except, desc) => {
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
- // src/components/Card/index.ts
21
- var Card_exports = {};
22
- __export(Card_exports, {
23
- Card: () => Card_default
20
+ // src/components/Box/index.ts
21
+ var Box_exports = {};
22
+ __export(Box_exports, {
23
+ Box: () => Box_default
24
24
  });
25
- module.exports = __toCommonJS(Card_exports);
25
+ module.exports = __toCommonJS(Box_exports);
26
26
 
27
- // src/components/Card/Card.tsx
27
+ // ../../node_modules/clsx/dist/clsx.mjs
28
+ function r(e) {
29
+ var t, f, n = "";
30
+ if ("string" == typeof e || "number" == typeof e) n += e;
31
+ else if ("object" == typeof e) if (Array.isArray(e)) {
32
+ var o = e.length;
33
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
34
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
35
+ return n;
36
+ }
37
+ function clsx() {
38
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
39
+ return n;
40
+ }
41
+ var clsx_default = clsx;
42
+
43
+ // src/components/Box/Box.tsx
28
44
  var import_jsx_runtime = require("react/jsx-runtime");
29
- var Card = ({ children, title }) => {
30
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-card", children: [
31
- title && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "title", children: title }),
32
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "content", children })
45
+ var Box = ({
46
+ children,
47
+ title,
48
+ variant = "outlined",
49
+ padding = "md"
50
+ }) => {
51
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: clsx_default("lib-xplat-box", variant, `pad-${padding}`), children: [
52
+ title && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "box-title", children: title }),
53
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "box-content", children })
33
54
  ] });
34
55
  };
35
- Card.displayName = "Card";
36
- var Card_default = Card;
56
+ Box.displayName = "Box";
57
+ var Box_default = Box;
37
58
  // Annotate the CommonJS export names for ESM import in node:
38
59
  0 && (module.exports = {
39
- Card
60
+ Box
40
61
  });
@@ -0,0 +1,55 @@
1
+ /* src/components/Box/box.scss */
2
+ .lib-xplat-box {
3
+ contain: layout style;
4
+ width: 100%;
5
+ height: 100%;
6
+ display: flex;
7
+ flex-direction: column;
8
+ flex: 1;
9
+ min-width: 0;
10
+ border-radius: var(--spacing-radius-xl);
11
+ background-color: var(--semantic-surface-neutral-default);
12
+ overflow: hidden;
13
+ }
14
+ .lib-xplat-box.outlined {
15
+ border: 1px solid var(--semantic-border-default);
16
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
17
+ }
18
+ .lib-xplat-box.elevated {
19
+ border: none;
20
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06), 0 8px 24px rgba(0, 0, 0, 0.08);
21
+ }
22
+ .lib-xplat-box.flat {
23
+ border: none;
24
+ background-color: var(--semantic-surface-neutral-subtle);
25
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
26
+ }
27
+ .lib-xplat-box > .box-title {
28
+ font-weight: 600;
29
+ font-size: 14px;
30
+ color: var(--semantic-text-strong);
31
+ padding: var(--spacing-space-3) var(--spacing-space-4);
32
+ border-bottom: 1px solid var(--semantic-border-subtle);
33
+ min-width: 0;
34
+ overflow: hidden;
35
+ text-overflow: ellipsis;
36
+ white-space: nowrap;
37
+ }
38
+ .lib-xplat-box > .box-content {
39
+ display: flex;
40
+ flex-direction: column;
41
+ flex: 1;
42
+ min-height: 0;
43
+ }
44
+ .lib-xplat-box.pad-none > .box-content {
45
+ padding: 0;
46
+ }
47
+ .lib-xplat-box.pad-sm > .box-content {
48
+ padding: var(--spacing-space-2) var(--spacing-space-3);
49
+ }
50
+ .lib-xplat-box.pad-md > .box-content {
51
+ padding: var(--spacing-space-4);
52
+ }
53
+ .lib-xplat-box.pad-lg > .box-content {
54
+ padding: var(--spacing-space-6);
55
+ }
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+
3
+ type BoxVariant = "outlined" | "elevated" | "flat";
4
+ type BoxPadding = "none" | "sm" | "md" | "lg";
5
+ interface BoxProps {
6
+ children: React.ReactNode;
7
+ title?: React.ReactNode;
8
+ variant?: BoxVariant;
9
+ padding?: BoxPadding;
10
+ }
11
+ declare const Box: React.FC<BoxProps>;
12
+
13
+ export { Box };
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+
3
+ type BoxVariant = "outlined" | "elevated" | "flat";
4
+ type BoxPadding = "none" | "sm" | "md" | "lg";
5
+ interface BoxProps {
6
+ children: React.ReactNode;
7
+ title?: React.ReactNode;
8
+ variant?: BoxVariant;
9
+ padding?: BoxPadding;
10
+ }
11
+ declare const Box: React.FC<BoxProps>;
12
+
13
+ export { Box };
@@ -0,0 +1,34 @@
1
+ // ../../node_modules/clsx/dist/clsx.mjs
2
+ function r(e) {
3
+ var t, f, n = "";
4
+ if ("string" == typeof e || "number" == typeof e) n += e;
5
+ else if ("object" == typeof e) if (Array.isArray(e)) {
6
+ var o = e.length;
7
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
8
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
9
+ return n;
10
+ }
11
+ function clsx() {
12
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
13
+ return n;
14
+ }
15
+ var clsx_default = clsx;
16
+
17
+ // src/components/Box/Box.tsx
18
+ import { jsx, jsxs } from "react/jsx-runtime";
19
+ var Box = ({
20
+ children,
21
+ title,
22
+ variant = "outlined",
23
+ padding = "md"
24
+ }) => {
25
+ return /* @__PURE__ */ jsxs("div", { className: clsx_default("lib-xplat-box", variant, `pad-${padding}`), children: [
26
+ title && /* @__PURE__ */ jsx("div", { className: "box-title", children: title }),
27
+ /* @__PURE__ */ jsx("div", { className: "box-content", children })
28
+ ] });
29
+ };
30
+ Box.displayName = "Box";
31
+ var Box_default = Box;
32
+ export {
33
+ Box_default as Box
34
+ };
@@ -1,6 +1,11 @@
1
1
  /* src/components/Button/button.scss */
2
2
  .lib-xplat-button {
3
3
  width: 100%;
4
+ display: inline-flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ gap: var(--spacing-space-2);
8
+ white-space: nowrap;
4
9
  border-radius: var(--spacing-radius-md);
5
10
  font-weight: 500;
6
11
  cursor: pointer;
@@ -63,6 +63,39 @@ var getPalette = (palettes, index, key) => {
63
63
  return palettes[(index + offset) % palettes.length];
64
64
  };
65
65
  var PADDING = { top: 20, right: 20, bottom: 30, left: 40 };
66
+ var toSmoothPath = (points) => {
67
+ if (points.length < 2) return "";
68
+ const p = points;
69
+ let d = `M ${p[0].x} ${p[0].y}`;
70
+ for (let i = 0; i < p.length - 1; i++) {
71
+ const p0 = p[Math.max(0, i - 1)];
72
+ const p1 = p[i];
73
+ const p2 = p[i + 1];
74
+ const p3 = p[Math.min(p.length - 1, i + 2)];
75
+ const cp1x = p1.x + (p2.x - p0.x) / 6;
76
+ const cp1y = p1.y + (p2.y - p0.y) / 6;
77
+ const cp2x = p2.x - (p3.x - p1.x) / 6;
78
+ const cp2y = p2.y - (p3.y - p1.y) / 6;
79
+ d += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;
80
+ }
81
+ return d;
82
+ };
83
+ var useChartSize = (ref) => {
84
+ const [size, setSize] = import_react.default.useState({ width: 0, height: 0 });
85
+ import_react.default.useEffect(() => {
86
+ const el = ref.current;
87
+ if (!el) return;
88
+ const observer = new ResizeObserver((entries) => {
89
+ const entry = entries[0];
90
+ if (!entry) return;
91
+ const { width, height } = entry.contentRect;
92
+ setSize({ width: Math.floor(width), height: Math.floor(height) });
93
+ });
94
+ observer.observe(el);
95
+ return () => observer.disconnect();
96
+ }, [ref]);
97
+ return size;
98
+ };
66
99
  var useChartTooltip = (enabled) => {
67
100
  const [tooltip, setTooltip] = import_react.default.useState({
68
101
  visible: false,
@@ -97,15 +130,15 @@ var useChartTooltip = (enabled) => {
97
130
  }, []);
98
131
  return { tooltip, show, hide, move, containerRef };
99
132
  };
100
- var LineChart = import_react.default.memo(({ data, labels, onHover, onMove, onLeave }) => {
133
+ var LineChart = import_react.default.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
101
134
  const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
102
135
  const maxVal = import_react.default.useMemo(() => {
103
136
  const allValues = entries.flatMap(([, v]) => v);
104
137
  return Math.max(...allValues) * 1.2 || 1;
105
138
  }, [entries]);
106
139
  const count = labels.length;
107
- const chartW = 600 - PADDING.left - PADDING.right;
108
- const chartH = 300 - PADDING.top - PADDING.bottom;
140
+ const chartW = width - PADDING.left - PADDING.right;
141
+ const chartH = height - PADDING.top - PADDING.bottom;
109
142
  const seriesPoints = import_react.default.useMemo(
110
143
  () => entries.map(
111
144
  ([, values]) => values.map((v, i) => ({
@@ -116,18 +149,18 @@ var LineChart = import_react.default.memo(({ data, labels, onHover, onMove, onLe
116
149
  ),
117
150
  [entries, count, chartW, chartH, maxVal]
118
151
  );
119
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: "0 0 600 300", className: "chart-svg", children: [
152
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
120
153
  [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
121
154
  const y = PADDING.top + (1 - ratio) * chartH;
122
155
  const val = Math.round(maxVal * ratio);
123
156
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
124
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: PADDING.left, y1: y, x2: 600 - PADDING.right, y2: y, className: "chart-grid" }),
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: PADDING.left, y1: y, x2: width - PADDING.right, y2: y, className: "chart-grid" }),
125
158
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x: PADDING.left - 8, y: y + 4, className: "chart-axis-label", textAnchor: "end", children: val })
126
159
  ] }, ratio);
127
160
  }),
128
161
  labels.map((label, i) => {
129
162
  const x = PADDING.left + i / (count - 1 || 1) * chartW;
130
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x, y: 300 - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i);
163
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x, y: height - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i);
131
164
  }),
132
165
  entries.map(([key], di) => {
133
166
  const palette = getPalette(LINE_BAR_PALETTES, di, key);
@@ -162,7 +195,73 @@ var LineChart = import_react.default.memo(({ data, labels, onHover, onMove, onLe
162
195
  ] });
163
196
  });
164
197
  LineChart.displayName = "LineChart";
165
- var BarChart = import_react.default.memo(({ data, labels, onHover, onMove, onLeave }) => {
198
+ var CurveChart = import_react.default.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
199
+ const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
200
+ const maxVal = import_react.default.useMemo(() => {
201
+ const allValues = entries.flatMap(([, v]) => v);
202
+ return Math.max(...allValues) * 1.2 || 1;
203
+ }, [entries]);
204
+ const count = labels.length;
205
+ const chartW = width - PADDING.left - PADDING.right;
206
+ const chartH = height - PADDING.top - PADDING.bottom;
207
+ const seriesPoints = import_react.default.useMemo(
208
+ () => entries.map(
209
+ ([, values]) => values.map((v, i) => ({
210
+ x: PADDING.left + i / (count - 1 || 1) * chartW,
211
+ y: PADDING.top + (1 - v / maxVal) * chartH,
212
+ v
213
+ }))
214
+ ),
215
+ [entries, count, chartW, chartH, maxVal]
216
+ );
217
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
218
+ [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
219
+ const y = PADDING.top + (1 - ratio) * chartH;
220
+ const val = Math.round(maxVal * ratio);
221
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
222
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: PADDING.left, y1: y, x2: width - PADDING.right, y2: y, className: "chart-grid" }),
223
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x: PADDING.left - 8, y: y + 4, className: "chart-axis-label", textAnchor: "end", children: val })
224
+ ] }, ratio);
225
+ }),
226
+ labels.map((label, i) => {
227
+ const x = PADDING.left + i / (count - 1 || 1) * chartW;
228
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x, y: height - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i);
229
+ }),
230
+ entries.map(([key], di) => {
231
+ const palette = getPalette(LINE_BAR_PALETTES, di, key);
232
+ const color = palette[2];
233
+ const areaColor = palette[0];
234
+ const points = seriesPoints[di];
235
+ const gradientId = `curve-gradient-${di}`;
236
+ const linePath = toSmoothPath(points);
237
+ const areaPath = linePath + ` L ${points[points.length - 1].x} ${PADDING.top + chartH} L ${points[0].x} ${PADDING.top + chartH} Z`;
238
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
239
+ /* @__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: [
240
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
241
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
242
+ ] }) }),
243
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: areaPath, fill: `url(#${gradientId})` }),
244
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: linePath, fill: "none", stroke: color, strokeWidth: "2" }),
245
+ points.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
246
+ "circle",
247
+ {
248
+ cx: p.x,
249
+ cy: p.y,
250
+ r: "4",
251
+ fill: color,
252
+ className: "chart-point",
253
+ onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${p.v}`),
254
+ onMouseMove: onMove,
255
+ onMouseLeave: onLeave
256
+ },
257
+ i
258
+ ))
259
+ ] }, di);
260
+ })
261
+ ] });
262
+ });
263
+ CurveChart.displayName = "CurveChart";
264
+ var BarChart = import_react.default.memo(({ data, labels, width, height, onHover, onMove, onLeave }) => {
166
265
  const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
167
266
  const maxVal = import_react.default.useMemo(() => {
168
267
  const allValues = entries.flatMap(([, v]) => v);
@@ -170,8 +269,8 @@ var BarChart = import_react.default.memo(({ data, labels, onHover, onMove, onLea
170
269
  }, [entries]);
171
270
  const count = labels.length;
172
271
  const groupCount = entries.length;
173
- const chartW = 600 - PADDING.left - PADDING.right;
174
- const chartH = 300 - PADDING.top - PADDING.bottom;
272
+ const chartW = width - PADDING.left - PADDING.right;
273
+ const chartH = height - PADDING.top - PADDING.bottom;
175
274
  const groupW = chartW / count;
176
275
  const barW = Math.min(32, groupW * 0.7 / groupCount);
177
276
  const bars = import_react.default.useMemo(
@@ -185,16 +284,16 @@ var BarChart = import_react.default.memo(({ data, labels, onHover, onMove, onLea
185
284
  ),
186
285
  [entries, maxVal, chartH, groupW, barW, groupCount]
187
286
  );
188
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: "0 0 600 300", className: "chart-svg", children: [
287
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
189
288
  [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
190
289
  const y = PADDING.top + (1 - ratio) * chartH;
191
290
  const val = Math.round(maxVal * ratio);
192
291
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
193
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: PADDING.left, y1: y, x2: 600 - PADDING.right, y2: y, className: "chart-grid" }),
292
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: PADDING.left, y1: y, x2: width - PADDING.right, y2: y, className: "chart-grid" }),
194
293
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x: PADDING.left - 8, y: y + 4, className: "chart-axis-label", textAnchor: "end", children: val })
195
294
  ] }, ratio);
196
295
  }),
197
- labels.map((label, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x: PADDING.left + groupW * i + groupW / 2, y: 300 - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i)),
296
+ labels.map((label, i) => /* @__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)),
198
297
  entries.map(([key], di) => {
199
298
  const palette = getPalette(LINE_BAR_PALETTES, di, key);
200
299
  const color = palette[2];
@@ -205,7 +304,7 @@ var BarChart = import_react.default.memo(({ data, labels, onHover, onMove, onLea
205
304
  y: b.y,
206
305
  width: b.w,
207
306
  height: b.h,
208
- rx: "2",
307
+ rx: Math.min(4, b.w / 2),
209
308
  fill: color,
210
309
  className: "chart-bar",
211
310
  onMouseEnter: (e) => onHover(e, `${key}: ${labels[i]} \u2014 ${b.v}`),
@@ -219,14 +318,15 @@ var BarChart = import_react.default.memo(({ data, labels, onHover, onMove, onLea
219
318
  });
220
319
  BarChart.displayName = "BarChart";
221
320
  var PieDonutChart = import_react.default.memo(
222
- ({ data, labels, isDoughnut, onHover, onMove, onLeave }) => {
321
+ ({ data, labels, width, height, isDoughnut, onHover, onMove, onLeave }) => {
223
322
  const entries = import_react.default.useMemo(() => Object.entries(data), [data]);
224
323
  const values = import_react.default.useMemo(() => entries.flatMap(([, v]) => v), [entries]);
225
324
  const total = import_react.default.useMemo(() => values.reduce((a, b) => a + b, 0) || 1, [values]);
226
- const cx = 150;
227
- const cy = 150;
228
- const r = 120;
229
- const innerR = isDoughnut ? 60 : 0;
325
+ const size = Math.min(width, height);
326
+ const cx = size / 2;
327
+ const cy = size / 2;
328
+ const r = size * 0.4;
329
+ const innerR = isDoughnut ? r * 0.5 : 0;
230
330
  const firstKey = entries[0]?.[0] ?? "";
231
331
  const colorOffset = hashString(firstKey);
232
332
  const sliceData = import_react.default.useMemo(() => {
@@ -257,8 +357,8 @@ var PieDonutChart = import_react.default.memo(
257
357
  angle0 = endAngle;
258
358
  return { d, lx, ly, v, pct, angle, label: labels[i] || `${i + 1}` };
259
359
  });
260
- }, [values, total, innerR, labels]);
261
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 300 300", className: "chart-svg chart-pie", children: sliceData.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
360
+ }, [values, total, cx, cy, r, innerR, labels]);
361
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: sliceData.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
262
362
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
263
363
  "path",
264
364
  {
@@ -275,22 +375,42 @@ var PieDonutChart = import_react.default.memo(
275
375
  }
276
376
  );
277
377
  PieDonutChart.displayName = "PieDonutChart";
378
+ var TooltipBubble = ({ x, y, containerWidth, children }) => {
379
+ const ref = import_react.default.useRef(null);
380
+ const [adjustedX, setAdjustedX] = import_react.default.useState(x);
381
+ import_react.default.useEffect(() => {
382
+ const el = ref.current;
383
+ if (!el) return;
384
+ const w = el.offsetWidth;
385
+ const half = w / 2;
386
+ const margin = 8;
387
+ let nx = x;
388
+ if (x - half < margin) nx = half + margin;
389
+ else if (x + half > containerWidth - margin) nx = containerWidth - half - margin;
390
+ setAdjustedX(nx);
391
+ }, [x, containerWidth]);
392
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
393
+ "div",
394
+ {
395
+ ref,
396
+ className: "chart-tooltip",
397
+ style: { left: adjustedX, top: y },
398
+ children
399
+ }
400
+ );
401
+ };
278
402
  var Chart = (props) => {
279
403
  const { type, data, labels, tooltip: showTooltip = true } = props;
280
404
  const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
405
+ const { width, height } = useChartSize(containerRef);
406
+ const ready = width > 0 && height > 0;
281
407
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-chart", ref: containerRef, children: [
282
- type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data, labels, onHover: show, onMove: move, onLeave: hide }),
283
- type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data, labels, onHover: show, onMove: move, onLeave: hide }),
284
- type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data, labels, onHover: show, onMove: move, onLeave: hide }),
285
- type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data, labels, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
286
- tooltip.visible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
287
- "div",
288
- {
289
- className: "chart-tooltip",
290
- style: { left: tooltip.x, top: tooltip.y },
291
- children: tooltip.content
292
- }
293
- )
408
+ ready && type === "line" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LineChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
409
+ ready && type === "curve" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CurveChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
410
+ ready && type === "bar" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BarChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
411
+ ready && type === "pie" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data, labels, width, height, onHover: show, onMove: move, onLeave: hide }),
412
+ ready && type === "doughnut" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PieDonutChart, { data, labels, width, height, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
413
+ tooltip.visible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipBubble, { x: tooltip.x, y: tooltip.y, containerWidth: width, children: tooltip.content })
294
414
  ] });
295
415
  };
296
416
  Chart.displayName = "Chart";
@@ -1,13 +1,14 @@
1
1
  /* src/components/Chart/chart.scss */
2
2
  .lib-xplat-chart {
3
- contain: content;
3
+ contain: layout style;
4
4
  width: 100%;
5
5
  height: 100%;
6
6
  position: relative;
7
7
  }
8
8
  .lib-xplat-chart .chart-svg {
9
+ display: block;
9
10
  width: 100%;
10
- height: auto;
11
+ height: 100%;
11
12
  }
12
13
  .lib-xplat-chart .chart-grid {
13
14
  stroke: var(--semantic-border-subtle);
@@ -29,29 +30,44 @@
29
30
  }
30
31
  .lib-xplat-chart .chart-point {
31
32
  cursor: pointer;
32
- transition: r 0.15s;
33
+ r: 0;
34
+ opacity: 0;
35
+ transition: r 0.15s, opacity 0.15s;
33
36
  }
34
37
  .lib-xplat-chart .chart-point:hover {
35
- r: 6;
38
+ r: 5;
39
+ opacity: 1;
40
+ }
41
+ .lib-xplat-chart .chart-svg:hover .chart-point {
42
+ r: 3;
43
+ opacity: 0.6;
36
44
  }
37
45
  .lib-xplat-chart .chart-bar {
38
46
  cursor: pointer;
39
- transition: opacity 0.15s;
47
+ transition: opacity 0.15s, filter 0.15s;
40
48
  }
41
49
  .lib-xplat-chart .chart-bar:hover {
42
- opacity: 0.8;
50
+ opacity: 0.85;
51
+ filter: brightness(1.08);
43
52
  }
44
53
  .lib-xplat-chart .chart-slice {
45
54
  cursor: pointer;
46
- transition: opacity 0.15s;
55
+ stroke: var(--semantic-surface-neutral-default);
56
+ stroke-width: 2;
57
+ transition:
58
+ opacity 0.15s,
59
+ filter 0.15s,
60
+ transform 0.15s;
61
+ transform-origin: center;
47
62
  }
48
63
  .lib-xplat-chart .chart-slice:hover {
49
- opacity: 0.85;
64
+ opacity: 0.9;
65
+ filter: brightness(1.05) drop-shadow(0 2px 6px rgba(0, 0, 0, 0.2));
50
66
  }
51
67
  .lib-xplat-chart .chart-tooltip {
52
68
  position: absolute;
53
69
  transform: translate(-50%, -100%);
54
- padding: var(--spacing-space-2) var(--spacing-space-2);
70
+ padding: var(--spacing-space-2) var(--spacing-space-3);
55
71
  background-color: var(--semantic-surface-neutral-strong);
56
72
  color: var(--semantic-text-inverse);
57
73
  font-size: 12px;
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  interface ChartProps {
4
- type: "line" | "bar" | "pie" | "doughnut";
4
+ type: "line" | "curve" | "bar" | "pie" | "doughnut";
5
5
  data: Record<string, number[]>;
6
6
  labels: string[];
7
7
  tooltip?: boolean;
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  interface ChartProps {
4
- type: "line" | "bar" | "pie" | "doughnut";
4
+ type: "line" | "curve" | "bar" | "pie" | "doughnut";
5
5
  data: Record<string, number[]>;
6
6
  labels: string[];
7
7
  tooltip?: boolean;