@x-plat/design-system 0.5.8 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/{Card → Box}/index.cjs +34 -13
- package/dist/components/Box/index.css +55 -0
- package/dist/components/Box/index.d.cts +13 -0
- package/dist/components/Box/index.d.ts +13 -0
- package/dist/components/Box/index.js +34 -0
- package/dist/components/Button/index.css +5 -0
- package/dist/components/Chart/index.cjs +152 -32
- package/dist/components/Chart/index.css +25 -9
- package/dist/components/Chart/index.d.cts +1 -1
- package/dist/components/Chart/index.d.ts +1 -1
- package/dist/components/Chart/index.js +152 -32
- package/dist/components/DatePicker/index.cjs +667 -682
- package/dist/components/DatePicker/index.css +211 -128
- package/dist/components/DatePicker/index.d.cts +2 -0
- package/dist/components/DatePicker/index.d.ts +2 -0
- package/dist/components/DatePicker/index.js +656 -671
- package/dist/components/index.cjs +687 -619
- package/dist/components/index.css +197 -156
- package/dist/components/index.d.cts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +681 -613
- package/dist/index.cjs +687 -619
- package/dist/index.css +197 -156
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +681 -613
- package/package.json +1 -1
- package/dist/components/Card/index.css +0 -28
- package/dist/components/Card/index.d.cts +0 -9
- package/dist/components/Card/index.d.ts +0 -9
- package/dist/components/Card/index.js +0 -13
|
@@ -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/
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
23
|
-
|
|
20
|
+
// src/components/Box/index.ts
|
|
21
|
+
var Box_exports = {};
|
|
22
|
+
__export(Box_exports, {
|
|
23
|
+
Box: () => Box_default
|
|
24
24
|
});
|
|
25
|
-
module.exports = __toCommonJS(
|
|
25
|
+
module.exports = __toCommonJS(Box_exports);
|
|
26
26
|
|
|
27
|
-
//
|
|
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
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
36
|
-
var
|
|
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
|
-
|
|
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 =
|
|
108
|
-
const chartH =
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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 =
|
|
174
|
-
const chartH =
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
227
|
-
const
|
|
228
|
-
const
|
|
229
|
-
const
|
|
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:
|
|
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 === "
|
|
284
|
-
type === "
|
|
285
|
-
type === "
|
|
286
|
-
|
|
287
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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.
|
|
50
|
+
opacity: 0.85;
|
|
51
|
+
filter: brightness(1.08);
|
|
43
52
|
}
|
|
44
53
|
.lib-xplat-chart .chart-slice {
|
|
45
54
|
cursor: pointer;
|
|
46
|
-
|
|
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.
|
|
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-
|
|
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;
|