@sesionario/blocks 1.26.1 → 1.28.0
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/charts.cjs +1904 -0
- package/dist/charts.cjs.map +1 -0
- package/dist/charts.d.cts +247 -0
- package/dist/charts.d.ts +247 -0
- package/dist/charts.js +1887 -0
- package/dist/charts.js.map +1 -0
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/pdf.cjs +129 -118
- package/dist/pdf.cjs.map +1 -1
- package/dist/pdf.d.cts +7 -1
- package/dist/pdf.d.ts +7 -1
- package/dist/pdf.js +129 -118
- package/dist/pdf.js.map +1 -1
- package/package.json +19 -1
package/dist/charts.cjs
ADDED
|
@@ -0,0 +1,1904 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var responsive = require('@visx/responsive');
|
|
5
|
+
var react$1 = require('motion/react');
|
|
6
|
+
var react = require('react');
|
|
7
|
+
var clsx = require('clsx');
|
|
8
|
+
var tailwindMerge = require('tailwind-merge');
|
|
9
|
+
var NumberFlow = require('@number-flow/react');
|
|
10
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
11
|
+
var d3Shape = require('d3-shape');
|
|
12
|
+
var group = require('@visx/group');
|
|
13
|
+
var shape = require('@visx/shape');
|
|
14
|
+
|
|
15
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
|
+
|
|
17
|
+
var NumberFlow__default = /*#__PURE__*/_interopDefault(NumberFlow);
|
|
18
|
+
|
|
19
|
+
function cn(...inputs) {
|
|
20
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
21
|
+
}
|
|
22
|
+
var defaultChartStatFlowFormat = {
|
|
23
|
+
notation: "standard",
|
|
24
|
+
maximumFractionDigits: 0
|
|
25
|
+
};
|
|
26
|
+
function formatStatValue(value, formatOptions, prefix, suffix) {
|
|
27
|
+
const formatted = new Intl.NumberFormat(void 0, formatOptions).format(
|
|
28
|
+
value
|
|
29
|
+
);
|
|
30
|
+
return `${prefix ?? ""}${formatted}${suffix ?? ""}`;
|
|
31
|
+
}
|
|
32
|
+
function useNumberFlowElementReady() {
|
|
33
|
+
const [ready, setReady] = react.useState(
|
|
34
|
+
() => typeof customElements !== "undefined" && Boolean(customElements.get("number-flow-react"))
|
|
35
|
+
);
|
|
36
|
+
react.useEffect(() => {
|
|
37
|
+
if (ready) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
let cancelled = false;
|
|
41
|
+
customElements.whenDefined("number-flow-react").then(() => {
|
|
42
|
+
if (!cancelled) {
|
|
43
|
+
setReady(true);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return () => {
|
|
47
|
+
cancelled = true;
|
|
48
|
+
};
|
|
49
|
+
}, [ready]);
|
|
50
|
+
return ready;
|
|
51
|
+
}
|
|
52
|
+
function ChartStatFlow({
|
|
53
|
+
value,
|
|
54
|
+
label,
|
|
55
|
+
formatOptions = defaultChartStatFlowFormat,
|
|
56
|
+
prefix,
|
|
57
|
+
suffix,
|
|
58
|
+
valueClassName = "text-2xl font-bold",
|
|
59
|
+
labelClassName = "text-xs",
|
|
60
|
+
icon
|
|
61
|
+
}) {
|
|
62
|
+
const numberFlowReady = useNumberFlowElementReady();
|
|
63
|
+
const staticValue = react.useMemo(
|
|
64
|
+
() => formatStatValue(value, formatOptions, prefix, suffix),
|
|
65
|
+
[value, formatOptions, prefix, suffix]
|
|
66
|
+
);
|
|
67
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
68
|
+
icon ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 flex h-12 w-12 items-center justify-center rounded-full bg-muted/50", children: icon }) : null,
|
|
69
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-foreground tabular-nums", valueClassName), children: numberFlowReady ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
70
|
+
NumberFlow__default.default,
|
|
71
|
+
{
|
|
72
|
+
format: formatOptions,
|
|
73
|
+
isolate: true,
|
|
74
|
+
prefix,
|
|
75
|
+
suffix,
|
|
76
|
+
value,
|
|
77
|
+
willChange: true
|
|
78
|
+
}
|
|
79
|
+
) : staticValue }),
|
|
80
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("mt-0.5 text-chart-label", labelClassName), children: label })
|
|
81
|
+
] });
|
|
82
|
+
}
|
|
83
|
+
ChartStatFlow.displayName = "ChartStatFlow";
|
|
84
|
+
|
|
85
|
+
// src/components/charts/chart-center-typography.ts
|
|
86
|
+
var chartCenterContainerClassName = "@container/chart-center size-full min-w-0";
|
|
87
|
+
var chartCenterValueClassName = "font-bold tabular-nums leading-none text-[clamp(0.75rem,22cqw,1.875rem)]";
|
|
88
|
+
var chartCenterLabelClassName = "max-w-full truncate leading-tight text-[clamp(0.625rem,9cqw,0.75rem)]";
|
|
89
|
+
var labelAlignClass = {
|
|
90
|
+
start: "items-start text-left",
|
|
91
|
+
center: "items-center text-center",
|
|
92
|
+
end: "items-end text-right"
|
|
93
|
+
};
|
|
94
|
+
function GaugeLabelShell({
|
|
95
|
+
centerValue,
|
|
96
|
+
defaultLabel = "Total",
|
|
97
|
+
prefix,
|
|
98
|
+
suffix,
|
|
99
|
+
formatOptions = defaultChartStatFlowFormat,
|
|
100
|
+
align = "center",
|
|
101
|
+
className
|
|
102
|
+
}) {
|
|
103
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
104
|
+
"div",
|
|
105
|
+
{
|
|
106
|
+
className: cn(
|
|
107
|
+
chartCenterContainerClassName,
|
|
108
|
+
"flex min-w-0 flex-col",
|
|
109
|
+
labelAlignClass[align],
|
|
110
|
+
className
|
|
111
|
+
),
|
|
112
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
113
|
+
ChartStatFlow,
|
|
114
|
+
{
|
|
115
|
+
formatOptions,
|
|
116
|
+
label: defaultLabel,
|
|
117
|
+
labelClassName: cn(
|
|
118
|
+
chartCenterLabelClassName,
|
|
119
|
+
"text-[length:var(--chart-foreground-muted)]"
|
|
120
|
+
),
|
|
121
|
+
prefix,
|
|
122
|
+
suffix,
|
|
123
|
+
value: centerValue,
|
|
124
|
+
valueClassName: cn(
|
|
125
|
+
chartCenterValueClassName,
|
|
126
|
+
"text-[length:var(--chart-foreground)]"
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
var crossAxisSelf = {
|
|
134
|
+
start: "self-start",
|
|
135
|
+
center: "self-center",
|
|
136
|
+
end: "self-end"
|
|
137
|
+
};
|
|
138
|
+
var crossAxisAlign = {
|
|
139
|
+
start: "items-start",
|
|
140
|
+
center: "items-center",
|
|
141
|
+
end: "items-end"
|
|
142
|
+
};
|
|
143
|
+
var inlineAxisAlign = {
|
|
144
|
+
start: "justify-start",
|
|
145
|
+
center: "justify-center",
|
|
146
|
+
end: "justify-end"
|
|
147
|
+
};
|
|
148
|
+
function GaugeLabelLayout({
|
|
149
|
+
placement,
|
|
150
|
+
align,
|
|
151
|
+
label,
|
|
152
|
+
children,
|
|
153
|
+
className
|
|
154
|
+
}) {
|
|
155
|
+
if (!label) {
|
|
156
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full min-w-0", className), children });
|
|
157
|
+
}
|
|
158
|
+
if (placement === "top") {
|
|
159
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
160
|
+
"div",
|
|
161
|
+
{
|
|
162
|
+
className: cn(
|
|
163
|
+
"flex w-full min-w-0 flex-col gap-3",
|
|
164
|
+
crossAxisAlign[align],
|
|
165
|
+
className
|
|
166
|
+
),
|
|
167
|
+
children: [
|
|
168
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: crossAxisSelf[align], children: label }),
|
|
169
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full min-w-0", children })
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
if (placement === "bottom") {
|
|
175
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
176
|
+
"div",
|
|
177
|
+
{
|
|
178
|
+
className: cn(
|
|
179
|
+
"flex w-full min-w-0 flex-col gap-3",
|
|
180
|
+
crossAxisAlign[align],
|
|
181
|
+
className
|
|
182
|
+
),
|
|
183
|
+
children: [
|
|
184
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full min-w-0", children }),
|
|
185
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: crossAxisSelf[align], children: label })
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (placement === "left") {
|
|
191
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
192
|
+
"div",
|
|
193
|
+
{
|
|
194
|
+
className: cn(
|
|
195
|
+
"flex w-full min-w-0 items-center gap-4",
|
|
196
|
+
inlineAxisAlign[align],
|
|
197
|
+
className
|
|
198
|
+
),
|
|
199
|
+
children: [
|
|
200
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: label }),
|
|
201
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children })
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
207
|
+
"div",
|
|
208
|
+
{
|
|
209
|
+
className: cn(
|
|
210
|
+
"flex w-full min-w-0 items-center gap-4",
|
|
211
|
+
inlineAxisAlign[align],
|
|
212
|
+
className
|
|
213
|
+
),
|
|
214
|
+
children: [
|
|
215
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children }),
|
|
216
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: label })
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
var DEFAULT_ACTIVE_GRADIENT = [
|
|
222
|
+
"#bef264",
|
|
223
|
+
"#10b981"
|
|
224
|
+
];
|
|
225
|
+
var DEFAULT_ACTIVE_FILL_OPACITY = 1;
|
|
226
|
+
var DEFAULT_INACTIVE_FILL_OPACITY = 0.8;
|
|
227
|
+
var DEFAULT_LINEAR_GAUGE_HEIGHT = 24;
|
|
228
|
+
function isDefsComponent(child) {
|
|
229
|
+
const typeLabel = child.type?.displayName || child.type?.name || "";
|
|
230
|
+
return typeLabel.includes("Gradient") || typeLabel.includes("Pattern") || typeLabel === "LinearGradient" || typeLabel === "RadialGradient" || typeLabel === "Lines" || typeLabel === "PatternLines" || typeLabel === "Circles" || typeLabel === "Hexagons" || typeLabel === "Waves";
|
|
231
|
+
}
|
|
232
|
+
function collectGaugeDefsElements(nodes) {
|
|
233
|
+
const out = [];
|
|
234
|
+
react.Children.forEach(nodes, (child) => {
|
|
235
|
+
if (!react.isValidElement(child)) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (child.type === react.Fragment) {
|
|
239
|
+
out.push(
|
|
240
|
+
...collectGaugeDefsElements(
|
|
241
|
+
child.props.children
|
|
242
|
+
)
|
|
243
|
+
);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (isDefsComponent(child)) {
|
|
247
|
+
out.push(child);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
function interpolateGaugeHex(color1, color2, factor) {
|
|
253
|
+
const hex = (c) => Number.parseInt(c, 16);
|
|
254
|
+
const r1 = hex(color1.slice(1, 3));
|
|
255
|
+
const g1 = hex(color1.slice(3, 5));
|
|
256
|
+
const b1 = hex(color1.slice(5, 7));
|
|
257
|
+
const r2 = hex(color2.slice(1, 3));
|
|
258
|
+
const g2 = hex(color2.slice(3, 5));
|
|
259
|
+
const b2 = hex(color2.slice(5, 7));
|
|
260
|
+
const r = Math.round(r1 + (r2 - r1) * factor);
|
|
261
|
+
const g = Math.round(g1 + (g2 - g1) * factor);
|
|
262
|
+
const b = Math.round(b1 + (b2 - b1) * factor);
|
|
263
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
264
|
+
}
|
|
265
|
+
function createNotchPath(points, cornerRadiusPx, verticalDepth) {
|
|
266
|
+
const { x1, y1, x2, y2, x3, y3, x4, y4 } = points;
|
|
267
|
+
const lerp = (a, b, t) => a + (b - a) * t;
|
|
268
|
+
const dist = (ax, ay, bx, by) => Math.hypot(bx - ax, by - ay);
|
|
269
|
+
const d12 = dist(x1, y1, x2, y2);
|
|
270
|
+
const d23 = dist(x2, y2, x3, y3);
|
|
271
|
+
const d34 = dist(x3, y3, x4, y4);
|
|
272
|
+
const d41 = dist(x4, y4, x1, y1);
|
|
273
|
+
if (cornerRadiusPx <= 0) {
|
|
274
|
+
return `M ${x1} ${y1} L ${x2} ${y2} L ${x3} ${y3} L ${x4} ${y4} Z`;
|
|
275
|
+
}
|
|
276
|
+
const minEdge = Math.min(d12, d23, d34, d41);
|
|
277
|
+
const cr = Math.min(
|
|
278
|
+
cornerRadiusPx,
|
|
279
|
+
verticalDepth * 0.48,
|
|
280
|
+
d12 * 0.49,
|
|
281
|
+
d23 * 0.49,
|
|
282
|
+
d34 * 0.49,
|
|
283
|
+
d41 * 0.49,
|
|
284
|
+
minEdge * 0.49
|
|
285
|
+
);
|
|
286
|
+
const r1 = Math.min(cr / d12, 0.49);
|
|
287
|
+
const r2 = Math.min(cr / d23, 0.49);
|
|
288
|
+
const r3 = Math.min(cr / d34, 0.49);
|
|
289
|
+
const r4 = Math.min(cr / d41, 0.49);
|
|
290
|
+
const p1a = { x: lerp(x1, x4, r4), y: lerp(y1, y4, r4) };
|
|
291
|
+
const p1b = { x: lerp(x1, x2, r1), y: lerp(y1, y2, r1) };
|
|
292
|
+
const p2a = { x: lerp(x2, x1, r1), y: lerp(y2, y1, r1) };
|
|
293
|
+
const p2b = { x: lerp(x2, x3, r2), y: lerp(y2, y3, r2) };
|
|
294
|
+
const p3a = { x: lerp(x3, x2, r2), y: lerp(y3, y2, r2) };
|
|
295
|
+
const p3b = { x: lerp(x3, x4, r3), y: lerp(y3, y4, r3) };
|
|
296
|
+
const p4a = { x: lerp(x4, x3, r3), y: lerp(y4, y3, r3) };
|
|
297
|
+
const p4b = { x: lerp(x4, x1, r4), y: lerp(y4, y1, r4) };
|
|
298
|
+
return `M ${p1a.x} ${p1a.y} Q ${x1} ${y1} ${p1b.x} ${p1b.y} L ${p2a.x} ${p2a.y} Q ${x2} ${y2} ${p2b.x} ${p2b.y} L ${p3a.x} ${p3a.y} Q ${x3} ${y3} ${p3b.x} ${p3b.y} L ${p4a.x} ${p4a.y} Q ${x4} ${y4} ${p4b.x} ${p4b.y} Z`;
|
|
299
|
+
}
|
|
300
|
+
function resolveGaugeBgFill(options) {
|
|
301
|
+
const {
|
|
302
|
+
notchIndex,
|
|
303
|
+
totalNotches,
|
|
304
|
+
hasCustomInactive,
|
|
305
|
+
inactiveFill,
|
|
306
|
+
useThemePaletteGradient,
|
|
307
|
+
useGradient,
|
|
308
|
+
inactiveGrad0,
|
|
309
|
+
inactiveGrad1,
|
|
310
|
+
arcTrackFill,
|
|
311
|
+
linearTrackFill,
|
|
312
|
+
linearMode
|
|
313
|
+
} = options;
|
|
314
|
+
if (hasCustomInactive) {
|
|
315
|
+
return inactiveFill;
|
|
316
|
+
}
|
|
317
|
+
if (useThemePaletteGradient) {
|
|
318
|
+
return linearMode ? "var(--chart-1)" : arcTrackFill;
|
|
319
|
+
}
|
|
320
|
+
if (useGradient) {
|
|
321
|
+
const denom = totalNotches > 1 ? totalNotches - 1 : 1;
|
|
322
|
+
return interpolateGaugeHex(
|
|
323
|
+
inactiveGrad0,
|
|
324
|
+
inactiveGrad1,
|
|
325
|
+
notchIndex / denom
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
return linearMode ? linearTrackFill : arcTrackFill;
|
|
329
|
+
}
|
|
330
|
+
function resolveGaugeActiveFill(options) {
|
|
331
|
+
const {
|
|
332
|
+
notch,
|
|
333
|
+
hasCustomActive,
|
|
334
|
+
activeFill,
|
|
335
|
+
useThemePaletteGradient,
|
|
336
|
+
themeActiveGradientId,
|
|
337
|
+
useGradient,
|
|
338
|
+
activeFillSolid
|
|
339
|
+
} = options;
|
|
340
|
+
if (hasCustomActive) {
|
|
341
|
+
return activeFill;
|
|
342
|
+
}
|
|
343
|
+
if (useThemePaletteGradient) {
|
|
344
|
+
return `url(#${themeActiveGradientId})`;
|
|
345
|
+
}
|
|
346
|
+
if (useGradient) {
|
|
347
|
+
return notch.gradientColor;
|
|
348
|
+
}
|
|
349
|
+
return activeFillSolid;
|
|
350
|
+
}
|
|
351
|
+
var pieCssVars = {
|
|
352
|
+
// Default slice colors from chart palette
|
|
353
|
+
slice1: "var(--chart-1)",
|
|
354
|
+
slice2: "var(--chart-2)",
|
|
355
|
+
slice3: "var(--chart-3)",
|
|
356
|
+
slice4: "var(--chart-4)",
|
|
357
|
+
slice5: "var(--chart-5)"
|
|
358
|
+
};
|
|
359
|
+
var defaultPieColors = [
|
|
360
|
+
pieCssVars.slice1,
|
|
361
|
+
pieCssVars.slice2,
|
|
362
|
+
pieCssVars.slice3,
|
|
363
|
+
pieCssVars.slice4,
|
|
364
|
+
pieCssVars.slice5
|
|
365
|
+
];
|
|
366
|
+
var PieStableContext = react.createContext(null);
|
|
367
|
+
var PieHoverContext = react.createContext(null);
|
|
368
|
+
function PieProvider({
|
|
369
|
+
children,
|
|
370
|
+
value
|
|
371
|
+
}) {
|
|
372
|
+
const stable = react.useMemo(
|
|
373
|
+
() => ({
|
|
374
|
+
data: value.data,
|
|
375
|
+
arcs: value.arcs,
|
|
376
|
+
size: value.size,
|
|
377
|
+
center: value.center,
|
|
378
|
+
outerRadius: value.outerRadius,
|
|
379
|
+
innerRadius: value.innerRadius,
|
|
380
|
+
padAngle: value.padAngle,
|
|
381
|
+
cornerRadius: value.cornerRadius,
|
|
382
|
+
hoverOffset: value.hoverOffset,
|
|
383
|
+
animationKey: value.animationKey,
|
|
384
|
+
isLoaded: value.isLoaded,
|
|
385
|
+
enterTransition: value.enterTransition,
|
|
386
|
+
enterStaggerScale: value.enterStaggerScale,
|
|
387
|
+
containerRef: value.containerRef,
|
|
388
|
+
totalValue: value.totalValue,
|
|
389
|
+
getColor: value.getColor,
|
|
390
|
+
getFill: value.getFill,
|
|
391
|
+
geometryScrubbing: value.geometryScrubbing,
|
|
392
|
+
scrubSlicePaths: value.scrubSlicePaths
|
|
393
|
+
}),
|
|
394
|
+
[
|
|
395
|
+
value.data,
|
|
396
|
+
value.arcs,
|
|
397
|
+
value.size,
|
|
398
|
+
value.center,
|
|
399
|
+
value.outerRadius,
|
|
400
|
+
value.innerRadius,
|
|
401
|
+
value.padAngle,
|
|
402
|
+
value.cornerRadius,
|
|
403
|
+
value.hoverOffset,
|
|
404
|
+
value.animationKey,
|
|
405
|
+
value.isLoaded,
|
|
406
|
+
value.enterTransition,
|
|
407
|
+
value.enterStaggerScale,
|
|
408
|
+
value.containerRef,
|
|
409
|
+
value.totalValue,
|
|
410
|
+
value.getColor,
|
|
411
|
+
value.getFill,
|
|
412
|
+
value.geometryScrubbing,
|
|
413
|
+
value.scrubSlicePaths
|
|
414
|
+
]
|
|
415
|
+
);
|
|
416
|
+
const hover = react.useMemo(
|
|
417
|
+
() => ({
|
|
418
|
+
hoveredIndex: value.hoveredIndex,
|
|
419
|
+
setHoveredIndex: value.setHoveredIndex
|
|
420
|
+
}),
|
|
421
|
+
[value.hoveredIndex, value.setHoveredIndex]
|
|
422
|
+
);
|
|
423
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PieStableContext.Provider, { value: stable, children: /* @__PURE__ */ jsxRuntime.jsx(PieHoverContext.Provider, { value: hover, children }) });
|
|
424
|
+
}
|
|
425
|
+
function usePieStable() {
|
|
426
|
+
const context = react.useContext(PieStableContext);
|
|
427
|
+
if (!context) {
|
|
428
|
+
throw new Error(
|
|
429
|
+
"usePieStable must be used within a PieProvider. Make sure your component is wrapped in <PieChart>."
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
return context;
|
|
433
|
+
}
|
|
434
|
+
function usePieHover() {
|
|
435
|
+
const context = react.useContext(PieHoverContext);
|
|
436
|
+
if (!context) {
|
|
437
|
+
throw new Error(
|
|
438
|
+
"usePieHover must be used within a PieProvider. Make sure your component is wrapped in <PieChart>."
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
return context;
|
|
442
|
+
}
|
|
443
|
+
function PieCenter({
|
|
444
|
+
defaultLabel = "Total",
|
|
445
|
+
formatOptions = defaultChartStatFlowFormat,
|
|
446
|
+
children,
|
|
447
|
+
className = "",
|
|
448
|
+
valueClassName = chartCenterValueClassName,
|
|
449
|
+
labelClassName = chartCenterLabelClassName,
|
|
450
|
+
prefix,
|
|
451
|
+
suffix
|
|
452
|
+
}) {
|
|
453
|
+
const { data, totalValue, innerRadius, geometryScrubbing } = usePieStable();
|
|
454
|
+
const { hoveredIndex } = usePieHover();
|
|
455
|
+
const effectiveHoveredIndex = geometryScrubbing ? null : hoveredIndex;
|
|
456
|
+
const hoveredData = effectiveHoveredIndex === null ? null : data[effectiveHoveredIndex];
|
|
457
|
+
const displayValue = hoveredData ? hoveredData.value : totalValue;
|
|
458
|
+
const displayLabel = hoveredData ? hoveredData.label : defaultLabel;
|
|
459
|
+
const centerSize = innerRadius * 2 - 16;
|
|
460
|
+
if (innerRadius <= 0) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
if (children && hoveredData) {
|
|
464
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
465
|
+
"div",
|
|
466
|
+
{
|
|
467
|
+
className: cn(
|
|
468
|
+
chartCenterContainerClassName,
|
|
469
|
+
"flex items-center justify-center",
|
|
470
|
+
className
|
|
471
|
+
),
|
|
472
|
+
style: { width: centerSize, height: centerSize },
|
|
473
|
+
children: children({
|
|
474
|
+
value: displayValue,
|
|
475
|
+
label: displayLabel,
|
|
476
|
+
isHovered: effectiveHoveredIndex !== null,
|
|
477
|
+
data: hoveredData
|
|
478
|
+
})
|
|
479
|
+
}
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
483
|
+
"div",
|
|
484
|
+
{
|
|
485
|
+
className: cn(
|
|
486
|
+
chartCenterContainerClassName,
|
|
487
|
+
"flex flex-col items-center justify-center text-center",
|
|
488
|
+
className
|
|
489
|
+
),
|
|
490
|
+
style: { width: centerSize, height: centerSize },
|
|
491
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
492
|
+
ChartStatFlow,
|
|
493
|
+
{
|
|
494
|
+
formatOptions,
|
|
495
|
+
label: displayLabel,
|
|
496
|
+
labelClassName,
|
|
497
|
+
prefix,
|
|
498
|
+
suffix,
|
|
499
|
+
value: displayValue,
|
|
500
|
+
valueClassName
|
|
501
|
+
}
|
|
502
|
+
)
|
|
503
|
+
}
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
PieCenter.displayName = "PieCenter";
|
|
507
|
+
var SHELL_HOVER_OFFSET = 10;
|
|
508
|
+
function PieCenterShell({
|
|
509
|
+
centerValue,
|
|
510
|
+
contextSize,
|
|
511
|
+
innerRadiusPx,
|
|
512
|
+
animateEntrance = true,
|
|
513
|
+
...pieCenterProps
|
|
514
|
+
}) {
|
|
515
|
+
const containerRef = react.useRef(null);
|
|
516
|
+
const introStartedRef = react.useRef(false);
|
|
517
|
+
const [flowTotal, setFlowTotal] = react.useState(
|
|
518
|
+
() => animateEntrance ? 0 : centerValue
|
|
519
|
+
);
|
|
520
|
+
react.useEffect(() => {
|
|
521
|
+
if (!animateEntrance) {
|
|
522
|
+
setFlowTotal(centerValue);
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
if (!introStartedRef.current) {
|
|
526
|
+
introStartedRef.current = true;
|
|
527
|
+
setFlowTotal(0);
|
|
528
|
+
let innerRaf = 0;
|
|
529
|
+
const outerRaf = requestAnimationFrame(() => {
|
|
530
|
+
innerRaf = requestAnimationFrame(() => setFlowTotal(centerValue));
|
|
531
|
+
});
|
|
532
|
+
return () => {
|
|
533
|
+
cancelAnimationFrame(outerRaf);
|
|
534
|
+
cancelAnimationFrame(innerRaf);
|
|
535
|
+
introStartedRef.current = false;
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
setFlowTotal(centerValue);
|
|
539
|
+
}, [animateEntrance, centerValue]);
|
|
540
|
+
const data = react.useMemo(
|
|
541
|
+
() => [{ label: "_pieCenterShell", value: Math.max(flowTotal, 0) }],
|
|
542
|
+
[flowTotal]
|
|
543
|
+
);
|
|
544
|
+
const totalValue = flowTotal;
|
|
545
|
+
const arcs = react.useMemo(() => {
|
|
546
|
+
const v = data[0]?.value ?? 0;
|
|
547
|
+
if (v > 0) {
|
|
548
|
+
const pieGenerator = d3Shape.pie().value((d) => d.value).startAngle(-Math.PI / 2).endAngle(3 * Math.PI / 2).padAngle(0).sort(null);
|
|
549
|
+
const computed = pieGenerator(data);
|
|
550
|
+
return computed.map((arc, index) => ({
|
|
551
|
+
data: arc.data,
|
|
552
|
+
index,
|
|
553
|
+
startAngle: arc.startAngle,
|
|
554
|
+
endAngle: arc.endAngle,
|
|
555
|
+
padAngle: arc.padAngle,
|
|
556
|
+
value: arc.value
|
|
557
|
+
}));
|
|
558
|
+
}
|
|
559
|
+
const d0 = data[0];
|
|
560
|
+
if (!d0) {
|
|
561
|
+
return [];
|
|
562
|
+
}
|
|
563
|
+
return [
|
|
564
|
+
{
|
|
565
|
+
data: d0,
|
|
566
|
+
index: 0,
|
|
567
|
+
startAngle: -Math.PI / 2,
|
|
568
|
+
endAngle: 3 * Math.PI / 2,
|
|
569
|
+
padAngle: 0,
|
|
570
|
+
value: 0
|
|
571
|
+
}
|
|
572
|
+
];
|
|
573
|
+
}, [data]);
|
|
574
|
+
const getColor = react.useCallback((index) => {
|
|
575
|
+
return defaultPieColors[index % defaultPieColors.length];
|
|
576
|
+
}, []);
|
|
577
|
+
const getFill = react.useCallback(
|
|
578
|
+
(index) => {
|
|
579
|
+
const item = data[index];
|
|
580
|
+
if (item?.fill) {
|
|
581
|
+
return item.fill;
|
|
582
|
+
}
|
|
583
|
+
return getColor(index);
|
|
584
|
+
},
|
|
585
|
+
[data, getColor]
|
|
586
|
+
);
|
|
587
|
+
const center = contextSize / 2;
|
|
588
|
+
const outerRadius = center - SHELL_HOVER_OFFSET;
|
|
589
|
+
const contextValue = react.useMemo(
|
|
590
|
+
() => ({
|
|
591
|
+
data,
|
|
592
|
+
arcs,
|
|
593
|
+
size: contextSize,
|
|
594
|
+
center,
|
|
595
|
+
outerRadius,
|
|
596
|
+
innerRadius: innerRadiusPx,
|
|
597
|
+
padAngle: 0,
|
|
598
|
+
cornerRadius: 0,
|
|
599
|
+
hoverOffset: SHELL_HOVER_OFFSET,
|
|
600
|
+
hoveredIndex: null,
|
|
601
|
+
setHoveredIndex: () => void 0,
|
|
602
|
+
animationKey: 0,
|
|
603
|
+
isLoaded: true,
|
|
604
|
+
enterStaggerScale: 1,
|
|
605
|
+
containerRef,
|
|
606
|
+
totalValue,
|
|
607
|
+
getColor,
|
|
608
|
+
getFill,
|
|
609
|
+
geometryScrubbing: false,
|
|
610
|
+
scrubSlicePaths: null
|
|
611
|
+
}),
|
|
612
|
+
[
|
|
613
|
+
data,
|
|
614
|
+
arcs,
|
|
615
|
+
contextSize,
|
|
616
|
+
center,
|
|
617
|
+
outerRadius,
|
|
618
|
+
innerRadiusPx,
|
|
619
|
+
totalValue,
|
|
620
|
+
getColor,
|
|
621
|
+
getFill
|
|
622
|
+
]
|
|
623
|
+
);
|
|
624
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PieProvider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(PieCenter, { ...pieCenterProps }) });
|
|
625
|
+
}
|
|
626
|
+
PieCenterShell.displayName = "PieCenterShell";
|
|
627
|
+
var DEFAULT_NOTCH_ENTER_TRANSITION = {
|
|
628
|
+
type: "spring",
|
|
629
|
+
stiffness: 300,
|
|
630
|
+
damping: 20
|
|
631
|
+
};
|
|
632
|
+
function GaugeNotchSvg({
|
|
633
|
+
notches,
|
|
634
|
+
width,
|
|
635
|
+
height,
|
|
636
|
+
notchCornerRadius,
|
|
637
|
+
cornerDepth,
|
|
638
|
+
geometryScrubbing,
|
|
639
|
+
notchTransition,
|
|
640
|
+
stagger,
|
|
641
|
+
defsChildren,
|
|
642
|
+
useThemePaletteGradient,
|
|
643
|
+
themeActiveGradientId,
|
|
644
|
+
resolvedInactiveFillOpacity,
|
|
645
|
+
resolvedActiveFillOpacity,
|
|
646
|
+
resolveBgFill,
|
|
647
|
+
resolveActiveFill
|
|
648
|
+
}) {
|
|
649
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
650
|
+
"svg",
|
|
651
|
+
{
|
|
652
|
+
"aria-hidden": "true",
|
|
653
|
+
className: "block w-full overflow-visible",
|
|
654
|
+
height,
|
|
655
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
656
|
+
width,
|
|
657
|
+
children: [
|
|
658
|
+
defsChildren.length > 0 || useThemePaletteGradient ? /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
|
|
659
|
+
useThemePaletteGradient ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
660
|
+
"linearGradient",
|
|
661
|
+
{
|
|
662
|
+
id: themeActiveGradientId,
|
|
663
|
+
x1: "0%",
|
|
664
|
+
x2: "100%",
|
|
665
|
+
y1: "0%",
|
|
666
|
+
y2: "0%",
|
|
667
|
+
children: [
|
|
668
|
+
/* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: "var(--chart-1)" }),
|
|
669
|
+
/* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: "var(--chart-5)" })
|
|
670
|
+
]
|
|
671
|
+
}
|
|
672
|
+
) : null,
|
|
673
|
+
defsChildren
|
|
674
|
+
] }) : null,
|
|
675
|
+
notches.map((notch) => {
|
|
676
|
+
const pathD = createNotchPath(
|
|
677
|
+
notch.points,
|
|
678
|
+
notchCornerRadius,
|
|
679
|
+
cornerDepth
|
|
680
|
+
);
|
|
681
|
+
if (geometryScrubbing) {
|
|
682
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
683
|
+
"path",
|
|
684
|
+
{
|
|
685
|
+
d: pathD,
|
|
686
|
+
fill: resolveBgFill(notch.index),
|
|
687
|
+
fillOpacity: resolvedInactiveFillOpacity
|
|
688
|
+
},
|
|
689
|
+
`bg-${notch.index}`
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
693
|
+
react$1.motion.path,
|
|
694
|
+
{
|
|
695
|
+
animate: { opacity: 1, scale: 1 },
|
|
696
|
+
d: pathD,
|
|
697
|
+
fill: resolveBgFill(notch.index),
|
|
698
|
+
fillOpacity: resolvedInactiveFillOpacity,
|
|
699
|
+
initial: { opacity: 0, scale: 0 },
|
|
700
|
+
style: {
|
|
701
|
+
transformOrigin: `${notch.xCenter}px ${notch.yCenter}px`
|
|
702
|
+
},
|
|
703
|
+
transition: {
|
|
704
|
+
...notchTransition,
|
|
705
|
+
delay: notch.index * 0.015 * stagger
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
`bg-${notch.index}`
|
|
709
|
+
);
|
|
710
|
+
}),
|
|
711
|
+
notches.filter((n) => n.isActive).map((notch) => {
|
|
712
|
+
const pathD = createNotchPath(
|
|
713
|
+
notch.points,
|
|
714
|
+
notchCornerRadius,
|
|
715
|
+
cornerDepth
|
|
716
|
+
);
|
|
717
|
+
if (geometryScrubbing) {
|
|
718
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
719
|
+
"path",
|
|
720
|
+
{
|
|
721
|
+
d: pathD,
|
|
722
|
+
fill: resolveActiveFill(notch),
|
|
723
|
+
fillOpacity: resolvedActiveFillOpacity
|
|
724
|
+
},
|
|
725
|
+
`active-${notch.index}`
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
729
|
+
react$1.motion.path,
|
|
730
|
+
{
|
|
731
|
+
animate: { opacity: 1, scale: 1 },
|
|
732
|
+
d: pathD,
|
|
733
|
+
fill: resolveActiveFill(notch),
|
|
734
|
+
fillOpacity: resolvedActiveFillOpacity,
|
|
735
|
+
initial: { opacity: 0, scale: 0 },
|
|
736
|
+
style: {
|
|
737
|
+
transformOrigin: `${notch.xCenter}px ${notch.yCenter}px`
|
|
738
|
+
},
|
|
739
|
+
transition: {
|
|
740
|
+
...notchTransition,
|
|
741
|
+
delay: (0.3 + notch.index * 0.02) * stagger
|
|
742
|
+
}
|
|
743
|
+
},
|
|
744
|
+
`active-${notch.index}`
|
|
745
|
+
);
|
|
746
|
+
})
|
|
747
|
+
]
|
|
748
|
+
}
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
function useGaugeFillState(props) {
|
|
752
|
+
const {
|
|
753
|
+
useGradient = false,
|
|
754
|
+
activeGradient,
|
|
755
|
+
inactiveGradient,
|
|
756
|
+
inactiveFill,
|
|
757
|
+
activeFill,
|
|
758
|
+
inactiveFillOpacity,
|
|
759
|
+
activeFillOpacity,
|
|
760
|
+
children,
|
|
761
|
+
totalNotches = 40
|
|
762
|
+
} = props;
|
|
763
|
+
const themeActiveGradientId = `gauge-theme-active-${react.useId().replace(/:/g, "")}`;
|
|
764
|
+
const defsChildren = react.useMemo(
|
|
765
|
+
() => collectGaugeDefsElements(children),
|
|
766
|
+
[children]
|
|
767
|
+
);
|
|
768
|
+
const hasCustomInactive = inactiveFill !== void 0 && inactiveFill.length > 0;
|
|
769
|
+
const hasCustomActive = activeFill !== void 0 && activeFill.length > 0;
|
|
770
|
+
const activeGrad0 = activeGradient?.[0] ?? DEFAULT_ACTIVE_GRADIENT[0];
|
|
771
|
+
const activeGrad1 = activeGradient?.[1] ?? DEFAULT_ACTIVE_GRADIENT[1];
|
|
772
|
+
const inactiveGrad0 = inactiveGradient?.[0] ?? activeGrad0;
|
|
773
|
+
const inactiveGrad1 = inactiveGradient?.[1] ?? activeGrad1;
|
|
774
|
+
const useThemePaletteGradient = useGradient && activeGradient === void 0;
|
|
775
|
+
return {
|
|
776
|
+
themeActiveGradientId,
|
|
777
|
+
defsChildren,
|
|
778
|
+
hasCustomInactive,
|
|
779
|
+
hasCustomActive,
|
|
780
|
+
activeGrad0,
|
|
781
|
+
activeGrad1,
|
|
782
|
+
inactiveGrad0,
|
|
783
|
+
inactiveGrad1,
|
|
784
|
+
useThemePaletteGradient,
|
|
785
|
+
resolvedActiveFillOpacity: activeFillOpacity ?? DEFAULT_ACTIVE_FILL_OPACITY,
|
|
786
|
+
resolvedInactiveFillOpacity: inactiveFillOpacity ?? DEFAULT_INACTIVE_FILL_OPACITY,
|
|
787
|
+
totalNotches
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
function GaugeArcInner(props) {
|
|
791
|
+
const {
|
|
792
|
+
value,
|
|
793
|
+
totalNotches = 40,
|
|
794
|
+
spacing = 25,
|
|
795
|
+
notchCornerRadius = 0,
|
|
796
|
+
uniformWidth = false,
|
|
797
|
+
width,
|
|
798
|
+
height,
|
|
799
|
+
startAngle = 135,
|
|
800
|
+
endAngle = 405,
|
|
801
|
+
useGradient = false,
|
|
802
|
+
centerValue,
|
|
803
|
+
defaultLabel = "Total",
|
|
804
|
+
prefix,
|
|
805
|
+
suffix,
|
|
806
|
+
formatOptions = defaultChartStatFlowFormat,
|
|
807
|
+
inactiveFill,
|
|
808
|
+
activeFill,
|
|
809
|
+
notchLengthPercent = 100,
|
|
810
|
+
enterTransition,
|
|
811
|
+
enterStaggerScale = 1
|
|
812
|
+
} = props;
|
|
813
|
+
const prefersReducedMotion = react$1.useReducedMotion();
|
|
814
|
+
const fillState = useGaugeFillState(props);
|
|
815
|
+
const notchTransition = prefersReducedMotion ? { duration: 0 } : enterTransition ?? DEFAULT_NOTCH_ENTER_TRANSITION;
|
|
816
|
+
const stagger = Math.max(0.25, Math.min(2.5, enterStaggerScale));
|
|
817
|
+
const size = Math.min(width, height);
|
|
818
|
+
const centerX = width / 2;
|
|
819
|
+
const centerY = height / 2;
|
|
820
|
+
const outerRadius = size * 0.42;
|
|
821
|
+
const innerRadiusBase = size * 0.28;
|
|
822
|
+
const defaultRadialDepth = outerRadius - innerRadiusBase;
|
|
823
|
+
const depthFactor = Math.min(100, Math.max(5, notchLengthPercent)) / 100;
|
|
824
|
+
const notchLength = defaultRadialDepth * depthFactor;
|
|
825
|
+
const innerRadius = outerRadius - notchLength;
|
|
826
|
+
const activeNotches = Math.round(value / 100 * totalNotches);
|
|
827
|
+
const totalAngle = endAngle - startAngle;
|
|
828
|
+
const availableAngle = totalAngle * (1 - spacing / 100);
|
|
829
|
+
const notchAngle = totalNotches > 0 ? availableAngle / totalNotches : 0;
|
|
830
|
+
const gapDen = totalNotches - 1 > 0 ? totalNotches - 1 : 1;
|
|
831
|
+
const gapAngle = totalAngle * (spacing / 100) / gapDen;
|
|
832
|
+
const notches = react.useMemo(() => {
|
|
833
|
+
return Array.from({ length: totalNotches }, (_, i) => {
|
|
834
|
+
const angle = startAngle + i * (notchAngle + gapAngle) + notchAngle / 2;
|
|
835
|
+
const radians = angle * Math.PI / 180;
|
|
836
|
+
const arcNotchWidth = notchAngle * 0.8;
|
|
837
|
+
const halfWidth = arcNotchWidth * Math.PI / 180 / 2;
|
|
838
|
+
const x1 = centerX + Math.cos(radians - halfWidth) * outerRadius;
|
|
839
|
+
const y1 = centerY + Math.sin(radians - halfWidth) * outerRadius;
|
|
840
|
+
const x2 = centerX + Math.cos(radians + halfWidth) * outerRadius;
|
|
841
|
+
const y2 = centerY + Math.sin(radians + halfWidth) * outerRadius;
|
|
842
|
+
let x3;
|
|
843
|
+
let y3;
|
|
844
|
+
let x4;
|
|
845
|
+
let y4;
|
|
846
|
+
if (uniformWidth) {
|
|
847
|
+
const perpX = Math.cos(radians);
|
|
848
|
+
const perpY = Math.sin(radians);
|
|
849
|
+
x3 = x2 - perpX * notchLength;
|
|
850
|
+
y3 = y2 - perpY * notchLength;
|
|
851
|
+
x4 = x1 - perpX * notchLength;
|
|
852
|
+
y4 = y1 - perpY * notchLength;
|
|
853
|
+
} else {
|
|
854
|
+
x3 = centerX + Math.cos(radians + halfWidth) * innerRadius;
|
|
855
|
+
y3 = centerY + Math.sin(radians + halfWidth) * innerRadius;
|
|
856
|
+
x4 = centerX + Math.cos(radians - halfWidth) * innerRadius;
|
|
857
|
+
y4 = centerY + Math.sin(radians - halfWidth) * innerRadius;
|
|
858
|
+
}
|
|
859
|
+
const denom = totalNotches > 1 ? totalNotches - 1 : 1;
|
|
860
|
+
const gradientColor = useGradient && !fillState.useThemePaletteGradient ? interpolateGaugeHex(
|
|
861
|
+
fillState.activeGrad0,
|
|
862
|
+
fillState.activeGrad1,
|
|
863
|
+
i / denom
|
|
864
|
+
) : "var(--chart-1)";
|
|
865
|
+
return {
|
|
866
|
+
index: i,
|
|
867
|
+
points: { x1, y1, x2, y2, x3, y3, x4, y4 },
|
|
868
|
+
isActive: i < activeNotches,
|
|
869
|
+
gradientColor,
|
|
870
|
+
xCenter: centerX,
|
|
871
|
+
yCenter: centerY
|
|
872
|
+
};
|
|
873
|
+
});
|
|
874
|
+
}, [
|
|
875
|
+
totalNotches,
|
|
876
|
+
notchAngle,
|
|
877
|
+
gapAngle,
|
|
878
|
+
centerX,
|
|
879
|
+
centerY,
|
|
880
|
+
outerRadius,
|
|
881
|
+
innerRadius,
|
|
882
|
+
activeNotches,
|
|
883
|
+
startAngle,
|
|
884
|
+
uniformWidth,
|
|
885
|
+
notchLength,
|
|
886
|
+
useGradient,
|
|
887
|
+
fillState.useThemePaletteGradient,
|
|
888
|
+
fillState.activeGrad0,
|
|
889
|
+
fillState.activeGrad1
|
|
890
|
+
]);
|
|
891
|
+
const resolveBgFill = (notchIndex) => resolveGaugeBgFill({
|
|
892
|
+
notchIndex,
|
|
893
|
+
totalNotches,
|
|
894
|
+
hasCustomInactive: fillState.hasCustomInactive,
|
|
895
|
+
inactiveFill,
|
|
896
|
+
useThemePaletteGradient: fillState.useThemePaletteGradient,
|
|
897
|
+
useGradient,
|
|
898
|
+
inactiveGrad0: fillState.inactiveGrad0,
|
|
899
|
+
inactiveGrad1: fillState.inactiveGrad1,
|
|
900
|
+
arcTrackFill: "var(--border)",
|
|
901
|
+
linearTrackFill: "var(--chart-background)",
|
|
902
|
+
linearMode: false
|
|
903
|
+
});
|
|
904
|
+
const resolveActiveFill = (notch) => resolveGaugeActiveFill({
|
|
905
|
+
notch,
|
|
906
|
+
hasCustomActive: fillState.hasCustomActive,
|
|
907
|
+
activeFill,
|
|
908
|
+
useThemePaletteGradient: fillState.useThemePaletteGradient,
|
|
909
|
+
themeActiveGradientId: fillState.themeActiveGradientId,
|
|
910
|
+
useGradient,
|
|
911
|
+
activeFillSolid: "var(--chart-1)"
|
|
912
|
+
});
|
|
913
|
+
const showCenter = centerValue != null;
|
|
914
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", style: { height, width }, children: [
|
|
915
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
916
|
+
GaugeNotchSvg,
|
|
917
|
+
{
|
|
918
|
+
cornerDepth: notchLength,
|
|
919
|
+
defsChildren: fillState.defsChildren,
|
|
920
|
+
geometryScrubbing: false,
|
|
921
|
+
height,
|
|
922
|
+
notchCornerRadius,
|
|
923
|
+
notches,
|
|
924
|
+
notchTransition,
|
|
925
|
+
resolveActiveFill,
|
|
926
|
+
resolveBgFill,
|
|
927
|
+
resolvedActiveFillOpacity: fillState.resolvedActiveFillOpacity,
|
|
928
|
+
resolvedInactiveFillOpacity: fillState.resolvedInactiveFillOpacity,
|
|
929
|
+
stagger,
|
|
930
|
+
themeActiveGradientId: fillState.themeActiveGradientId,
|
|
931
|
+
useThemePaletteGradient: fillState.useThemePaletteGradient,
|
|
932
|
+
width
|
|
933
|
+
}
|
|
934
|
+
),
|
|
935
|
+
showCenter ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
936
|
+
"div",
|
|
937
|
+
{
|
|
938
|
+
className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center",
|
|
939
|
+
style: { paddingTop: size * 0.08 },
|
|
940
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
941
|
+
PieCenterShell,
|
|
942
|
+
{
|
|
943
|
+
centerValue,
|
|
944
|
+
contextSize: size,
|
|
945
|
+
defaultLabel,
|
|
946
|
+
formatOptions,
|
|
947
|
+
innerRadiusPx: Math.max(size * 0.2, 52),
|
|
948
|
+
prefix,
|
|
949
|
+
suffix
|
|
950
|
+
}
|
|
951
|
+
)
|
|
952
|
+
}
|
|
953
|
+
) : null
|
|
954
|
+
] });
|
|
955
|
+
}
|
|
956
|
+
function GaugeLinearInner(props) {
|
|
957
|
+
const {
|
|
958
|
+
value,
|
|
959
|
+
totalNotches = 40,
|
|
960
|
+
spacing = 25,
|
|
961
|
+
notchCornerRadius = 0,
|
|
962
|
+
uniformWidth = true,
|
|
963
|
+
width,
|
|
964
|
+
height,
|
|
965
|
+
useGradient = false,
|
|
966
|
+
centerValue,
|
|
967
|
+
defaultLabel = "Total",
|
|
968
|
+
prefix,
|
|
969
|
+
suffix,
|
|
970
|
+
formatOptions = defaultChartStatFlowFormat,
|
|
971
|
+
labelPlacement = "top",
|
|
972
|
+
labelAlign = "start",
|
|
973
|
+
inactiveFill,
|
|
974
|
+
activeFill,
|
|
975
|
+
notchLengthPercent = 100,
|
|
976
|
+
notchWidthPercent = 80,
|
|
977
|
+
enterTransition,
|
|
978
|
+
enterStaggerScale = 1,
|
|
979
|
+
geometryScrubbing = false
|
|
980
|
+
} = props;
|
|
981
|
+
const prefersReducedMotion = react$1.useReducedMotion();
|
|
982
|
+
const fillState = useGaugeFillState(props);
|
|
983
|
+
const notchTransition = prefersReducedMotion ? { duration: 0 } : enterTransition ?? DEFAULT_NOTCH_ENTER_TRANSITION;
|
|
984
|
+
const stagger = Math.max(0.25, Math.min(2.5, enterStaggerScale));
|
|
985
|
+
const centerY = height / 2;
|
|
986
|
+
const depthFactor = Math.min(100, Math.max(5, notchLengthPercent)) / 100;
|
|
987
|
+
const outerOffset = height / 2 * depthFactor;
|
|
988
|
+
const taperRatio = 28 / 42;
|
|
989
|
+
const innerOffset = uniformWidth ? outerOffset : outerOffset * taperRatio;
|
|
990
|
+
const notchDepth = uniformWidth ? outerOffset * 2 : outerOffset - innerOffset;
|
|
991
|
+
const cornerVerticalDepth = uniformWidth ? notchDepth : outerOffset * 2;
|
|
992
|
+
const widthFactor = Math.min(100, Math.max(10, notchWidthPercent)) / 100;
|
|
993
|
+
const activeNotches = Math.round(value / 100 * totalNotches);
|
|
994
|
+
const availableWidth = width * (1 - spacing / 100);
|
|
995
|
+
const slotWidth = totalNotches > 0 ? availableWidth / totalNotches : 0;
|
|
996
|
+
const gapDen = totalNotches - 1 > 0 ? totalNotches - 1 : 1;
|
|
997
|
+
const gapWidth = width * (spacing / 100) / gapDen;
|
|
998
|
+
const notches = react.useMemo(() => {
|
|
999
|
+
return Array.from({ length: totalNotches }, (_, i) => {
|
|
1000
|
+
const xCenter = i * (slotWidth + gapWidth) + slotWidth / 2;
|
|
1001
|
+
const halfWidth = slotWidth * widthFactor / 2;
|
|
1002
|
+
let x1;
|
|
1003
|
+
let y1;
|
|
1004
|
+
let x2;
|
|
1005
|
+
let y2;
|
|
1006
|
+
let x3;
|
|
1007
|
+
let y3;
|
|
1008
|
+
let x4;
|
|
1009
|
+
let y4;
|
|
1010
|
+
if (uniformWidth) {
|
|
1011
|
+
const halfHeight = notchDepth / 2;
|
|
1012
|
+
x1 = xCenter - halfWidth;
|
|
1013
|
+
y1 = centerY - halfHeight;
|
|
1014
|
+
x2 = xCenter + halfWidth;
|
|
1015
|
+
y2 = centerY - halfHeight;
|
|
1016
|
+
x3 = xCenter + halfWidth;
|
|
1017
|
+
y3 = centerY + halfHeight;
|
|
1018
|
+
x4 = xCenter - halfWidth;
|
|
1019
|
+
y4 = centerY + halfHeight;
|
|
1020
|
+
} else {
|
|
1021
|
+
x1 = xCenter - halfWidth;
|
|
1022
|
+
y1 = centerY - outerOffset;
|
|
1023
|
+
x2 = xCenter + halfWidth;
|
|
1024
|
+
y2 = centerY - outerOffset;
|
|
1025
|
+
const innerHalfWidth = halfWidth * (innerOffset / outerOffset);
|
|
1026
|
+
x3 = xCenter + innerHalfWidth;
|
|
1027
|
+
y3 = centerY + outerOffset;
|
|
1028
|
+
x4 = xCenter - innerHalfWidth;
|
|
1029
|
+
y4 = centerY + outerOffset;
|
|
1030
|
+
}
|
|
1031
|
+
const denom = totalNotches > 1 ? totalNotches - 1 : 1;
|
|
1032
|
+
const gradientColor = useGradient && !fillState.useThemePaletteGradient ? interpolateGaugeHex(
|
|
1033
|
+
fillState.activeGrad0,
|
|
1034
|
+
fillState.activeGrad1,
|
|
1035
|
+
i / denom
|
|
1036
|
+
) : "var(--chart-1)";
|
|
1037
|
+
return {
|
|
1038
|
+
index: i,
|
|
1039
|
+
points: { x1, y1, x2, y2, x3, y3, x4, y4 },
|
|
1040
|
+
isActive: i < activeNotches,
|
|
1041
|
+
gradientColor,
|
|
1042
|
+
xCenter,
|
|
1043
|
+
yCenter: centerY
|
|
1044
|
+
};
|
|
1045
|
+
});
|
|
1046
|
+
}, [
|
|
1047
|
+
totalNotches,
|
|
1048
|
+
slotWidth,
|
|
1049
|
+
gapWidth,
|
|
1050
|
+
centerY,
|
|
1051
|
+
outerOffset,
|
|
1052
|
+
innerOffset,
|
|
1053
|
+
activeNotches,
|
|
1054
|
+
uniformWidth,
|
|
1055
|
+
notchDepth,
|
|
1056
|
+
widthFactor,
|
|
1057
|
+
useGradient,
|
|
1058
|
+
fillState.useThemePaletteGradient,
|
|
1059
|
+
fillState.activeGrad0,
|
|
1060
|
+
fillState.activeGrad1
|
|
1061
|
+
]);
|
|
1062
|
+
const resolveBgFill = (notchIndex) => resolveGaugeBgFill({
|
|
1063
|
+
notchIndex,
|
|
1064
|
+
totalNotches,
|
|
1065
|
+
hasCustomInactive: fillState.hasCustomInactive,
|
|
1066
|
+
inactiveFill,
|
|
1067
|
+
useThemePaletteGradient: fillState.useThemePaletteGradient,
|
|
1068
|
+
useGradient,
|
|
1069
|
+
inactiveGrad0: fillState.inactiveGrad0,
|
|
1070
|
+
inactiveGrad1: fillState.inactiveGrad1,
|
|
1071
|
+
arcTrackFill: "var(--border)",
|
|
1072
|
+
linearTrackFill: "var(--chart-background)",
|
|
1073
|
+
linearMode: true
|
|
1074
|
+
});
|
|
1075
|
+
const resolveActiveFill = (notch) => resolveGaugeActiveFill({
|
|
1076
|
+
notch,
|
|
1077
|
+
hasCustomActive: fillState.hasCustomActive,
|
|
1078
|
+
activeFill,
|
|
1079
|
+
useThemePaletteGradient: fillState.useThemePaletteGradient,
|
|
1080
|
+
themeActiveGradientId: fillState.themeActiveGradientId,
|
|
1081
|
+
useGradient,
|
|
1082
|
+
activeFillSolid: "var(--chart-1)"
|
|
1083
|
+
});
|
|
1084
|
+
const label = centerValue == null ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1085
|
+
GaugeLabelShell,
|
|
1086
|
+
{
|
|
1087
|
+
align: labelAlign,
|
|
1088
|
+
centerValue,
|
|
1089
|
+
defaultLabel,
|
|
1090
|
+
formatOptions,
|
|
1091
|
+
prefix,
|
|
1092
|
+
suffix
|
|
1093
|
+
}
|
|
1094
|
+
);
|
|
1095
|
+
const track = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full", style: { height, width }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1096
|
+
GaugeNotchSvg,
|
|
1097
|
+
{
|
|
1098
|
+
cornerDepth: cornerVerticalDepth,
|
|
1099
|
+
defsChildren: fillState.defsChildren,
|
|
1100
|
+
geometryScrubbing,
|
|
1101
|
+
height,
|
|
1102
|
+
notchCornerRadius,
|
|
1103
|
+
notches,
|
|
1104
|
+
notchTransition,
|
|
1105
|
+
resolveActiveFill,
|
|
1106
|
+
resolveBgFill,
|
|
1107
|
+
resolvedActiveFillOpacity: fillState.resolvedActiveFillOpacity,
|
|
1108
|
+
resolvedInactiveFillOpacity: fillState.resolvedInactiveFillOpacity,
|
|
1109
|
+
stagger,
|
|
1110
|
+
themeActiveGradientId: fillState.themeActiveGradientId,
|
|
1111
|
+
useThemePaletteGradient: fillState.useThemePaletteGradient,
|
|
1112
|
+
width
|
|
1113
|
+
}
|
|
1114
|
+
) });
|
|
1115
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1116
|
+
GaugeLabelLayout,
|
|
1117
|
+
{
|
|
1118
|
+
align: labelAlign,
|
|
1119
|
+
label,
|
|
1120
|
+
placement: labelPlacement,
|
|
1121
|
+
children: track
|
|
1122
|
+
}
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
function GaugeInner(props) {
|
|
1126
|
+
if (props.orientation === "linear") {
|
|
1127
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GaugeLinearInner, { ...props });
|
|
1128
|
+
}
|
|
1129
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GaugeArcInner, { ...props });
|
|
1130
|
+
}
|
|
1131
|
+
function Gauge({
|
|
1132
|
+
width: widthProp,
|
|
1133
|
+
height: heightProp,
|
|
1134
|
+
className,
|
|
1135
|
+
minWidth,
|
|
1136
|
+
orientation = "arc",
|
|
1137
|
+
linearHeight,
|
|
1138
|
+
...props
|
|
1139
|
+
}) {
|
|
1140
|
+
const isLinear = orientation === "linear";
|
|
1141
|
+
const resolvedMinWidth = minWidth ?? (isLinear ? 200 : 300);
|
|
1142
|
+
const resolvedLinearHeight = linearHeight ?? DEFAULT_LINEAR_GAUGE_HEIGHT;
|
|
1143
|
+
if (isLinear) {
|
|
1144
|
+
if (widthProp != null) {
|
|
1145
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1146
|
+
"div",
|
|
1147
|
+
{
|
|
1148
|
+
className: cn("relative w-full max-w-full", className),
|
|
1149
|
+
style: { width: widthProp },
|
|
1150
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1151
|
+
GaugeInner,
|
|
1152
|
+
{
|
|
1153
|
+
height: heightProp ?? resolvedLinearHeight,
|
|
1154
|
+
orientation: "linear",
|
|
1155
|
+
width: widthProp,
|
|
1156
|
+
...props
|
|
1157
|
+
}
|
|
1158
|
+
)
|
|
1159
|
+
}
|
|
1160
|
+
);
|
|
1161
|
+
}
|
|
1162
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("relative w-full min-w-0 max-w-full", className), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full min-w-0", style: { minWidth: resolvedMinWidth }, children: /* @__PURE__ */ jsxRuntime.jsx(responsive.ParentSize, { debounceTime: 10, children: ({ width }) => width > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1163
|
+
GaugeInner,
|
|
1164
|
+
{
|
|
1165
|
+
height: resolvedLinearHeight,
|
|
1166
|
+
orientation: "linear",
|
|
1167
|
+
width,
|
|
1168
|
+
...props
|
|
1169
|
+
}
|
|
1170
|
+
) : null }) }) });
|
|
1171
|
+
}
|
|
1172
|
+
if (widthProp != null && heightProp != null) {
|
|
1173
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("relative inline-flex max-w-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1174
|
+
GaugeInner,
|
|
1175
|
+
{
|
|
1176
|
+
height: heightProp,
|
|
1177
|
+
orientation: "arc",
|
|
1178
|
+
width: widthProp,
|
|
1179
|
+
...props
|
|
1180
|
+
}
|
|
1181
|
+
) });
|
|
1182
|
+
}
|
|
1183
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1184
|
+
"div",
|
|
1185
|
+
{
|
|
1186
|
+
className: cn("relative w-full max-w-full", className),
|
|
1187
|
+
style: { minWidth: resolvedMinWidth },
|
|
1188
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto aspect-[21/16] w-full max-w-[560px]", children: /* @__PURE__ */ jsxRuntime.jsx(responsive.ParentSize, { debounceTime: 10, children: ({ width, height }) => width > 0 && height > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1189
|
+
GaugeInner,
|
|
1190
|
+
{
|
|
1191
|
+
height,
|
|
1192
|
+
orientation: "arc",
|
|
1193
|
+
width,
|
|
1194
|
+
...props
|
|
1195
|
+
}
|
|
1196
|
+
) : null }) })
|
|
1197
|
+
}
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
Gauge.displayName = "Gauge";
|
|
1201
|
+
var ringCssVars = {
|
|
1202
|
+
background: "var(--chart-background)",
|
|
1203
|
+
foreground: "var(--chart-foreground)",
|
|
1204
|
+
foregroundMuted: "var(--chart-foreground-muted)",
|
|
1205
|
+
label: "var(--chart-label)",
|
|
1206
|
+
ringBackground: "var(--border)",
|
|
1207
|
+
// Default ring colors from chart palette
|
|
1208
|
+
ring1: "var(--chart-1)",
|
|
1209
|
+
ring2: "var(--chart-2)",
|
|
1210
|
+
ring3: "var(--chart-3)",
|
|
1211
|
+
ring4: "var(--chart-4)",
|
|
1212
|
+
ring5: "var(--chart-5)"
|
|
1213
|
+
};
|
|
1214
|
+
var defaultRingColors = [
|
|
1215
|
+
ringCssVars.ring1,
|
|
1216
|
+
ringCssVars.ring2,
|
|
1217
|
+
ringCssVars.ring3,
|
|
1218
|
+
ringCssVars.ring4,
|
|
1219
|
+
ringCssVars.ring5
|
|
1220
|
+
];
|
|
1221
|
+
var RingStableContext = react.createContext(null);
|
|
1222
|
+
var RingHoverContext = react.createContext(null);
|
|
1223
|
+
function RingProvider({
|
|
1224
|
+
children,
|
|
1225
|
+
value
|
|
1226
|
+
}) {
|
|
1227
|
+
const stable = react.useMemo(
|
|
1228
|
+
() => ({
|
|
1229
|
+
data: value.data,
|
|
1230
|
+
size: value.size,
|
|
1231
|
+
center: value.center,
|
|
1232
|
+
strokeWidth: value.strokeWidth,
|
|
1233
|
+
ringGap: value.ringGap,
|
|
1234
|
+
baseInnerRadius: value.baseInnerRadius,
|
|
1235
|
+
animationKey: value.animationKey,
|
|
1236
|
+
isLoaded: value.isLoaded,
|
|
1237
|
+
enterTransition: value.enterTransition,
|
|
1238
|
+
enterStaggerScale: value.enterStaggerScale,
|
|
1239
|
+
containerRef: value.containerRef,
|
|
1240
|
+
totalValue: value.totalValue,
|
|
1241
|
+
getColor: value.getColor,
|
|
1242
|
+
getRingRadii: value.getRingRadii,
|
|
1243
|
+
startAngle: value.startAngle,
|
|
1244
|
+
endAngle: value.endAngle,
|
|
1245
|
+
geometryScrubbing: value.geometryScrubbing
|
|
1246
|
+
}),
|
|
1247
|
+
[
|
|
1248
|
+
value.data,
|
|
1249
|
+
value.size,
|
|
1250
|
+
value.center,
|
|
1251
|
+
value.strokeWidth,
|
|
1252
|
+
value.ringGap,
|
|
1253
|
+
value.baseInnerRadius,
|
|
1254
|
+
value.animationKey,
|
|
1255
|
+
value.isLoaded,
|
|
1256
|
+
value.enterTransition,
|
|
1257
|
+
value.enterStaggerScale,
|
|
1258
|
+
value.containerRef,
|
|
1259
|
+
value.totalValue,
|
|
1260
|
+
value.getColor,
|
|
1261
|
+
value.getRingRadii,
|
|
1262
|
+
value.startAngle,
|
|
1263
|
+
value.endAngle,
|
|
1264
|
+
value.geometryScrubbing
|
|
1265
|
+
]
|
|
1266
|
+
);
|
|
1267
|
+
const hover = react.useMemo(
|
|
1268
|
+
() => ({
|
|
1269
|
+
hoveredIndex: value.hoveredIndex,
|
|
1270
|
+
setHoveredIndex: value.setHoveredIndex
|
|
1271
|
+
}),
|
|
1272
|
+
[value.hoveredIndex, value.setHoveredIndex]
|
|
1273
|
+
);
|
|
1274
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RingStableContext.Provider, { value: stable, children: /* @__PURE__ */ jsxRuntime.jsx(RingHoverContext.Provider, { value: hover, children }) });
|
|
1275
|
+
}
|
|
1276
|
+
function useRingStable() {
|
|
1277
|
+
const context = react.useContext(RingStableContext);
|
|
1278
|
+
if (!context) {
|
|
1279
|
+
throw new Error(
|
|
1280
|
+
"useRingStable must be used within a RingProvider. Make sure your component is wrapped in <RingChart>."
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
return context;
|
|
1284
|
+
}
|
|
1285
|
+
function useRingHover() {
|
|
1286
|
+
const context = react.useContext(RingHoverContext);
|
|
1287
|
+
if (!context) {
|
|
1288
|
+
throw new Error(
|
|
1289
|
+
"useRingHover must be used within a RingProvider. Make sure your component is wrapped in <RingChart>."
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
return context;
|
|
1293
|
+
}
|
|
1294
|
+
function useRing() {
|
|
1295
|
+
return { ...useRingStable(), ...useRingHover() };
|
|
1296
|
+
}
|
|
1297
|
+
function generateRingArcPath(innerRadius, outerRadius, startAngle, endAngle, cornerRadius) {
|
|
1298
|
+
const generator = shape.arc({
|
|
1299
|
+
innerRadius,
|
|
1300
|
+
outerRadius,
|
|
1301
|
+
cornerRadius
|
|
1302
|
+
});
|
|
1303
|
+
return generator({ startAngle, endAngle }) || "";
|
|
1304
|
+
}
|
|
1305
|
+
function isRing(child) {
|
|
1306
|
+
return react.isValidElement(child) && typeof child.type === "function" && (child.type.displayName === "Ring" || child.type.name === "Ring");
|
|
1307
|
+
}
|
|
1308
|
+
function isRingCenter(child) {
|
|
1309
|
+
return react.isValidElement(child) && typeof child.type === "function" && (child.type.displayName === "RingCenter" || child.type.name === "RingCenter");
|
|
1310
|
+
}
|
|
1311
|
+
function RingChartInner(props) {
|
|
1312
|
+
const size = Math.min(props.width, props.height);
|
|
1313
|
+
if (size < 10) {
|
|
1314
|
+
return null;
|
|
1315
|
+
}
|
|
1316
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RingChartCore, { ...props });
|
|
1317
|
+
}
|
|
1318
|
+
var RingChartCore = react.memo(function RingChartCore2({
|
|
1319
|
+
width,
|
|
1320
|
+
height,
|
|
1321
|
+
data,
|
|
1322
|
+
strokeWidth: strokeWidthProp,
|
|
1323
|
+
ringGap: ringGapProp,
|
|
1324
|
+
baseInnerRadius: baseInnerRadiusProp,
|
|
1325
|
+
children,
|
|
1326
|
+
containerRef,
|
|
1327
|
+
hoveredIndexProp,
|
|
1328
|
+
onHoverChange,
|
|
1329
|
+
startAngle,
|
|
1330
|
+
endAngle,
|
|
1331
|
+
enterTransition,
|
|
1332
|
+
enterStaggerScale,
|
|
1333
|
+
geometryScrubbing
|
|
1334
|
+
}) {
|
|
1335
|
+
const [internalHoveredIndex, setInternalHoveredIndex] = react.useState(null);
|
|
1336
|
+
const [animationKey] = react.useState(0);
|
|
1337
|
+
const [isLoaded, setIsLoaded] = react.useState(false);
|
|
1338
|
+
const isControlled = hoveredIndexProp !== void 0;
|
|
1339
|
+
const hoveredIndex = isControlled ? hoveredIndexProp : internalHoveredIndex;
|
|
1340
|
+
const setHoveredIndex = react.useCallback(
|
|
1341
|
+
(index) => {
|
|
1342
|
+
if (isControlled) {
|
|
1343
|
+
onHoverChange?.(index);
|
|
1344
|
+
} else {
|
|
1345
|
+
setInternalHoveredIndex(index);
|
|
1346
|
+
}
|
|
1347
|
+
},
|
|
1348
|
+
[isControlled, onHoverChange]
|
|
1349
|
+
);
|
|
1350
|
+
const size = Math.min(width, height);
|
|
1351
|
+
const center = size / 2;
|
|
1352
|
+
const ringCount = data.length;
|
|
1353
|
+
const padding = 8;
|
|
1354
|
+
const availableRadius = center - padding;
|
|
1355
|
+
const designOuterRadius = baseInnerRadiusProp + (ringCount - 1) * (strokeWidthProp + ringGapProp) + strokeWidthProp;
|
|
1356
|
+
const scale = Math.min(1, availableRadius / designOuterRadius);
|
|
1357
|
+
const strokeWidth = strokeWidthProp * scale;
|
|
1358
|
+
const ringGap = ringGapProp * scale;
|
|
1359
|
+
const baseInnerRadius = baseInnerRadiusProp * scale;
|
|
1360
|
+
const totalValue = react.useMemo(
|
|
1361
|
+
() => data.reduce((sum, d) => sum + d.value, 0),
|
|
1362
|
+
[data]
|
|
1363
|
+
);
|
|
1364
|
+
const getColor = react.useCallback(
|
|
1365
|
+
(index) => {
|
|
1366
|
+
const item = data[index];
|
|
1367
|
+
if (item?.color) {
|
|
1368
|
+
return item.color;
|
|
1369
|
+
}
|
|
1370
|
+
return defaultRingColors[index % defaultRingColors.length];
|
|
1371
|
+
},
|
|
1372
|
+
[data]
|
|
1373
|
+
);
|
|
1374
|
+
const getRingRadii = react.useCallback(
|
|
1375
|
+
(index) => {
|
|
1376
|
+
const innerRadius = baseInnerRadius + index * (strokeWidth + ringGap);
|
|
1377
|
+
const outerRadius = innerRadius + strokeWidth;
|
|
1378
|
+
return { innerRadius, outerRadius };
|
|
1379
|
+
},
|
|
1380
|
+
[baseInnerRadius, strokeWidth, ringGap]
|
|
1381
|
+
);
|
|
1382
|
+
const arcRange = endAngle - startAngle;
|
|
1383
|
+
const scrubRingLayers = react.useMemo(() => {
|
|
1384
|
+
if (!geometryScrubbing) {
|
|
1385
|
+
return null;
|
|
1386
|
+
}
|
|
1387
|
+
return data.map((ringData, index) => {
|
|
1388
|
+
const { innerRadius, outerRadius } = getRingRadii(index);
|
|
1389
|
+
const cornerRadius = (outerRadius - innerRadius) / 2;
|
|
1390
|
+
const progress = ringData.value / ringData.maxValue;
|
|
1391
|
+
const progressEndAngle = startAngle + arcRange * progress;
|
|
1392
|
+
return {
|
|
1393
|
+
bgPath: generateRingArcPath(
|
|
1394
|
+
innerRadius,
|
|
1395
|
+
outerRadius,
|
|
1396
|
+
startAngle,
|
|
1397
|
+
endAngle,
|
|
1398
|
+
cornerRadius
|
|
1399
|
+
),
|
|
1400
|
+
progressPath: progressEndAngle <= startAngle + 0.01 ? "" : generateRingArcPath(
|
|
1401
|
+
innerRadius,
|
|
1402
|
+
outerRadius,
|
|
1403
|
+
startAngle,
|
|
1404
|
+
progressEndAngle,
|
|
1405
|
+
cornerRadius
|
|
1406
|
+
),
|
|
1407
|
+
color: getColor(index)
|
|
1408
|
+
};
|
|
1409
|
+
});
|
|
1410
|
+
}, [
|
|
1411
|
+
geometryScrubbing,
|
|
1412
|
+
data,
|
|
1413
|
+
getRingRadii,
|
|
1414
|
+
getColor,
|
|
1415
|
+
startAngle,
|
|
1416
|
+
endAngle,
|
|
1417
|
+
arcRange
|
|
1418
|
+
]);
|
|
1419
|
+
const effectiveIsLoaded = geometryScrubbing || isLoaded;
|
|
1420
|
+
react.useEffect(() => {
|
|
1421
|
+
if (geometryScrubbing) {
|
|
1422
|
+
return;
|
|
1423
|
+
}
|
|
1424
|
+
setIsLoaded(false);
|
|
1425
|
+
const timer = setTimeout(() => {
|
|
1426
|
+
setIsLoaded(true);
|
|
1427
|
+
}, 100);
|
|
1428
|
+
return () => clearTimeout(timer);
|
|
1429
|
+
}, [enterTransition, enterStaggerScale, geometryScrubbing]);
|
|
1430
|
+
const { svgChildren, centerChildren } = react.useMemo(() => {
|
|
1431
|
+
const svgNodes = [];
|
|
1432
|
+
const centerNodes = [];
|
|
1433
|
+
react.Children.forEach(children, (child) => {
|
|
1434
|
+
if (isRingCenter(child)) {
|
|
1435
|
+
centerNodes.push(child);
|
|
1436
|
+
} else if (geometryScrubbing && isRing(child)) {
|
|
1437
|
+
return;
|
|
1438
|
+
} else {
|
|
1439
|
+
svgNodes.push(child);
|
|
1440
|
+
}
|
|
1441
|
+
});
|
|
1442
|
+
return { svgChildren: svgNodes, centerChildren: centerNodes };
|
|
1443
|
+
}, [children, geometryScrubbing]);
|
|
1444
|
+
const contextValue = react.useMemo(
|
|
1445
|
+
() => ({
|
|
1446
|
+
data,
|
|
1447
|
+
size,
|
|
1448
|
+
center,
|
|
1449
|
+
strokeWidth,
|
|
1450
|
+
ringGap,
|
|
1451
|
+
baseInnerRadius,
|
|
1452
|
+
hoveredIndex,
|
|
1453
|
+
setHoveredIndex,
|
|
1454
|
+
animationKey,
|
|
1455
|
+
isLoaded: effectiveIsLoaded,
|
|
1456
|
+
enterTransition,
|
|
1457
|
+
enterStaggerScale,
|
|
1458
|
+
containerRef,
|
|
1459
|
+
totalValue,
|
|
1460
|
+
getColor,
|
|
1461
|
+
getRingRadii,
|
|
1462
|
+
startAngle,
|
|
1463
|
+
endAngle,
|
|
1464
|
+
geometryScrubbing
|
|
1465
|
+
}),
|
|
1466
|
+
[
|
|
1467
|
+
data,
|
|
1468
|
+
size,
|
|
1469
|
+
center,
|
|
1470
|
+
strokeWidth,
|
|
1471
|
+
ringGap,
|
|
1472
|
+
baseInnerRadius,
|
|
1473
|
+
hoveredIndex,
|
|
1474
|
+
setHoveredIndex,
|
|
1475
|
+
animationKey,
|
|
1476
|
+
effectiveIsLoaded,
|
|
1477
|
+
enterTransition,
|
|
1478
|
+
enterStaggerScale,
|
|
1479
|
+
containerRef,
|
|
1480
|
+
totalValue,
|
|
1481
|
+
getColor,
|
|
1482
|
+
getRingRadii,
|
|
1483
|
+
startAngle,
|
|
1484
|
+
endAngle,
|
|
1485
|
+
geometryScrubbing
|
|
1486
|
+
]
|
|
1487
|
+
);
|
|
1488
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RingProvider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1489
|
+
"div",
|
|
1490
|
+
{
|
|
1491
|
+
className: "grid",
|
|
1492
|
+
style: {
|
|
1493
|
+
gridTemplateColumns: "1fr",
|
|
1494
|
+
gridTemplateRows: "1fr",
|
|
1495
|
+
width: size,
|
|
1496
|
+
height: size
|
|
1497
|
+
},
|
|
1498
|
+
children: [
|
|
1499
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1500
|
+
"svg",
|
|
1501
|
+
{
|
|
1502
|
+
"aria-hidden": "true",
|
|
1503
|
+
height: size,
|
|
1504
|
+
style: { gridArea: "1 / 1", contain: "layout style paint" },
|
|
1505
|
+
width: size,
|
|
1506
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(group.Group, { left: center, top: center, children: [
|
|
1507
|
+
scrubRingLayers ? scrubRingLayers.map((layer, index) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
1508
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: layer.bgPath, fill: ringCssVars.ringBackground }),
|
|
1509
|
+
layer.progressPath ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: layer.progressPath, fill: layer.color }) : null
|
|
1510
|
+
] }, data[index]?.label ?? index)) : null,
|
|
1511
|
+
svgChildren
|
|
1512
|
+
] })
|
|
1513
|
+
}
|
|
1514
|
+
),
|
|
1515
|
+
centerChildren.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1516
|
+
"div",
|
|
1517
|
+
{
|
|
1518
|
+
className: "pointer-events-none flex items-center justify-center",
|
|
1519
|
+
style: { gridArea: "1 / 1" },
|
|
1520
|
+
children: centerChildren
|
|
1521
|
+
}
|
|
1522
|
+
)
|
|
1523
|
+
]
|
|
1524
|
+
}
|
|
1525
|
+
) });
|
|
1526
|
+
}, ringChartCorePropsEqual);
|
|
1527
|
+
function ringChartCorePropsEqual(prev, next) {
|
|
1528
|
+
return prev.width === next.width && prev.height === next.height && prev.data === next.data && prev.strokeWidth === next.strokeWidth && prev.ringGap === next.ringGap && prev.baseInnerRadius === next.baseInnerRadius && prev.hoveredIndexProp === next.hoveredIndexProp && prev.onHoverChange === next.onHoverChange && prev.startAngle === next.startAngle && prev.endAngle === next.endAngle && prev.enterTransition === next.enterTransition && prev.enterStaggerScale === next.enterStaggerScale && prev.geometryScrubbing === next.geometryScrubbing && prev.children === next.children;
|
|
1529
|
+
}
|
|
1530
|
+
function RingChart({
|
|
1531
|
+
data,
|
|
1532
|
+
size: fixedSize,
|
|
1533
|
+
strokeWidth = 12,
|
|
1534
|
+
ringGap = 6,
|
|
1535
|
+
baseInnerRadius = 60,
|
|
1536
|
+
className = "",
|
|
1537
|
+
hoveredIndex,
|
|
1538
|
+
onHoverChange,
|
|
1539
|
+
startAngle = -Math.PI / 2,
|
|
1540
|
+
endAngle = 3 * Math.PI / 2,
|
|
1541
|
+
enterTransition,
|
|
1542
|
+
enterStaggerScale = 1,
|
|
1543
|
+
geometryScrubbing = false,
|
|
1544
|
+
children
|
|
1545
|
+
}) {
|
|
1546
|
+
const containerRef = react.useRef(null);
|
|
1547
|
+
if (fixedSize) {
|
|
1548
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1549
|
+
"div",
|
|
1550
|
+
{
|
|
1551
|
+
className: cn("relative flex items-center justify-center", className),
|
|
1552
|
+
ref: containerRef,
|
|
1553
|
+
style: { width: fixedSize, height: fixedSize },
|
|
1554
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1555
|
+
RingChartInner,
|
|
1556
|
+
{
|
|
1557
|
+
baseInnerRadius,
|
|
1558
|
+
containerRef,
|
|
1559
|
+
data,
|
|
1560
|
+
endAngle,
|
|
1561
|
+
enterStaggerScale,
|
|
1562
|
+
enterTransition,
|
|
1563
|
+
geometryScrubbing,
|
|
1564
|
+
height: fixedSize,
|
|
1565
|
+
hoveredIndexProp: hoveredIndex,
|
|
1566
|
+
onHoverChange,
|
|
1567
|
+
ringGap,
|
|
1568
|
+
startAngle,
|
|
1569
|
+
strokeWidth,
|
|
1570
|
+
width: fixedSize,
|
|
1571
|
+
children
|
|
1572
|
+
}
|
|
1573
|
+
)
|
|
1574
|
+
}
|
|
1575
|
+
);
|
|
1576
|
+
}
|
|
1577
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1578
|
+
"div",
|
|
1579
|
+
{
|
|
1580
|
+
className: cn("relative aspect-square w-full", className),
|
|
1581
|
+
ref: containerRef,
|
|
1582
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(responsive.ParentSize, { debounceTime: 10, children: ({ width, height }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1583
|
+
RingChartInner,
|
|
1584
|
+
{
|
|
1585
|
+
baseInnerRadius,
|
|
1586
|
+
containerRef,
|
|
1587
|
+
data,
|
|
1588
|
+
endAngle,
|
|
1589
|
+
enterStaggerScale,
|
|
1590
|
+
enterTransition,
|
|
1591
|
+
geometryScrubbing,
|
|
1592
|
+
height,
|
|
1593
|
+
hoveredIndexProp: hoveredIndex,
|
|
1594
|
+
onHoverChange,
|
|
1595
|
+
ringGap,
|
|
1596
|
+
startAngle,
|
|
1597
|
+
strokeWidth,
|
|
1598
|
+
width,
|
|
1599
|
+
children
|
|
1600
|
+
}
|
|
1601
|
+
) })
|
|
1602
|
+
}
|
|
1603
|
+
);
|
|
1604
|
+
}
|
|
1605
|
+
function useEnterComplete(mountProgress) {
|
|
1606
|
+
const [complete, setComplete] = react.useState(() => mountProgress.get() >= 1);
|
|
1607
|
+
react.useEffect(() => {
|
|
1608
|
+
if (mountProgress.get() >= 1) {
|
|
1609
|
+
setComplete(true);
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
return mountProgress.on("change", (value) => {
|
|
1613
|
+
if (value >= 1) {
|
|
1614
|
+
setComplete(true);
|
|
1615
|
+
}
|
|
1616
|
+
});
|
|
1617
|
+
}, [mountProgress]);
|
|
1618
|
+
return complete;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
// src/components/charts/animation.ts
|
|
1622
|
+
var DEFAULT_ANIMATION_DURATION_MS = 1100;
|
|
1623
|
+
var DEFAULT_CHART_ENTER_TRANSITION = {
|
|
1624
|
+
type: "tween",
|
|
1625
|
+
duration: DEFAULT_ANIMATION_DURATION_MS / 1e3,
|
|
1626
|
+
ease: [0.85, 0, 0.15, 1]
|
|
1627
|
+
};
|
|
1628
|
+
|
|
1629
|
+
// src/components/charts/use-mount-progress.ts
|
|
1630
|
+
function useMountProgress(enterTransition, delaySeconds, replayKey) {
|
|
1631
|
+
const progress = react$1.useMotionValue(0);
|
|
1632
|
+
const transitionRef = react.useRef(enterTransition);
|
|
1633
|
+
transitionRef.current = enterTransition;
|
|
1634
|
+
react.useEffect(() => {
|
|
1635
|
+
progress.set(0);
|
|
1636
|
+
const controls = react$1.animate(progress, 1, {
|
|
1637
|
+
...transitionRef.current ?? DEFAULT_CHART_ENTER_TRANSITION,
|
|
1638
|
+
delay: delaySeconds
|
|
1639
|
+
});
|
|
1640
|
+
return () => controls.stop();
|
|
1641
|
+
}, [delaySeconds, replayKey, progress]);
|
|
1642
|
+
return progress;
|
|
1643
|
+
}
|
|
1644
|
+
function generateArcPath(innerRadius, outerRadius, startAngle, endAngle, cornerRadius) {
|
|
1645
|
+
const generator = shape.arc({
|
|
1646
|
+
innerRadius,
|
|
1647
|
+
outerRadius,
|
|
1648
|
+
cornerRadius
|
|
1649
|
+
});
|
|
1650
|
+
return generator({ startAngle, endAngle }) || "";
|
|
1651
|
+
}
|
|
1652
|
+
function ringHoverScale(isHovered, isPushedOut) {
|
|
1653
|
+
if (isHovered) {
|
|
1654
|
+
return 1.03;
|
|
1655
|
+
}
|
|
1656
|
+
if (isPushedOut) {
|
|
1657
|
+
return 1.02;
|
|
1658
|
+
}
|
|
1659
|
+
return 1;
|
|
1660
|
+
}
|
|
1661
|
+
function RingProgressPath({
|
|
1662
|
+
progressComplete,
|
|
1663
|
+
progressPath,
|
|
1664
|
+
animatedProgressPath,
|
|
1665
|
+
color
|
|
1666
|
+
}) {
|
|
1667
|
+
if (progressComplete) {
|
|
1668
|
+
if (!progressPath) {
|
|
1669
|
+
return null;
|
|
1670
|
+
}
|
|
1671
|
+
return /* @__PURE__ */ jsxRuntime.jsx("path", { d: progressPath, fill: color });
|
|
1672
|
+
}
|
|
1673
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react$1.motion.path, { d: animatedProgressPath, fill: color });
|
|
1674
|
+
}
|
|
1675
|
+
var Ring = react.memo(function Ring2({
|
|
1676
|
+
index,
|
|
1677
|
+
color: colorProp,
|
|
1678
|
+
animate: animate2 = true,
|
|
1679
|
+
showGlow = true,
|
|
1680
|
+
lineCap = "round"
|
|
1681
|
+
}) {
|
|
1682
|
+
const {
|
|
1683
|
+
data,
|
|
1684
|
+
getColor,
|
|
1685
|
+
getRingRadii,
|
|
1686
|
+
startAngle,
|
|
1687
|
+
endAngle,
|
|
1688
|
+
enterTransition,
|
|
1689
|
+
enterStaggerScale,
|
|
1690
|
+
animationKey
|
|
1691
|
+
} = useRingStable();
|
|
1692
|
+
const { hoveredIndex, setHoveredIndex } = useRingHover();
|
|
1693
|
+
const expandDelay = index * 0.08 * enterStaggerScale;
|
|
1694
|
+
const expandProgress = useMountProgress(
|
|
1695
|
+
enterTransition,
|
|
1696
|
+
expandDelay,
|
|
1697
|
+
`${animationKey}-expand-${index}`
|
|
1698
|
+
);
|
|
1699
|
+
const expandComplete = useEnterComplete(expandProgress);
|
|
1700
|
+
const progressDelay = (0.6 + index * 0.1) * enterStaggerScale;
|
|
1701
|
+
const progressMount = useMountProgress(
|
|
1702
|
+
enterTransition,
|
|
1703
|
+
progressDelay,
|
|
1704
|
+
`${animationKey}-progress-${index}`
|
|
1705
|
+
);
|
|
1706
|
+
const progressComplete = useEnterComplete(progressMount);
|
|
1707
|
+
const ringData = data[index];
|
|
1708
|
+
const progress = ringData ? ringData.value / ringData.maxValue : 0;
|
|
1709
|
+
const arcRange = endAngle - startAngle;
|
|
1710
|
+
const animatedProgressPath = react$1.useTransform(progressMount, (v) => {
|
|
1711
|
+
if (!ringData) {
|
|
1712
|
+
return "";
|
|
1713
|
+
}
|
|
1714
|
+
const currentEndAngle = startAngle + arcRange * progress * v;
|
|
1715
|
+
if (currentEndAngle <= startAngle + 0.01) {
|
|
1716
|
+
return "";
|
|
1717
|
+
}
|
|
1718
|
+
const radii = getRingRadii(index);
|
|
1719
|
+
const corner = lineCap === "round" ? (radii.outerRadius - radii.innerRadius) / 2 : 0;
|
|
1720
|
+
return generateArcPath(
|
|
1721
|
+
radii.innerRadius,
|
|
1722
|
+
radii.outerRadius,
|
|
1723
|
+
startAngle,
|
|
1724
|
+
currentEndAngle,
|
|
1725
|
+
corner
|
|
1726
|
+
);
|
|
1727
|
+
});
|
|
1728
|
+
const enterScale = react$1.useTransform(expandProgress, [0, 1], [0, 1]);
|
|
1729
|
+
const handleMouseEnter = react.useCallback(
|
|
1730
|
+
() => setHoveredIndex(index),
|
|
1731
|
+
[index, setHoveredIndex]
|
|
1732
|
+
);
|
|
1733
|
+
const handleMouseLeave = react.useCallback(
|
|
1734
|
+
() => setHoveredIndex(null),
|
|
1735
|
+
[setHoveredIndex]
|
|
1736
|
+
);
|
|
1737
|
+
if (!ringData) {
|
|
1738
|
+
return null;
|
|
1739
|
+
}
|
|
1740
|
+
const { innerRadius, outerRadius } = getRingRadii(index);
|
|
1741
|
+
const color = colorProp || getColor(index);
|
|
1742
|
+
const isHovered = hoveredIndex === index;
|
|
1743
|
+
const isFaded = hoveredIndex !== null && hoveredIndex !== index;
|
|
1744
|
+
const isPushedOut = hoveredIndex !== null && hoveredIndex < index;
|
|
1745
|
+
const cornerRadius = lineCap === "round" ? (outerRadius - innerRadius) / 2 : 0;
|
|
1746
|
+
const bgPath = generateArcPath(
|
|
1747
|
+
innerRadius,
|
|
1748
|
+
outerRadius,
|
|
1749
|
+
startAngle,
|
|
1750
|
+
endAngle,
|
|
1751
|
+
cornerRadius
|
|
1752
|
+
);
|
|
1753
|
+
const progressEndAngle = startAngle + arcRange * progress;
|
|
1754
|
+
const progressPath = progressEndAngle <= startAngle + 0.01 ? "" : generateArcPath(
|
|
1755
|
+
innerRadius,
|
|
1756
|
+
outerRadius,
|
|
1757
|
+
startAngle,
|
|
1758
|
+
progressEndAngle,
|
|
1759
|
+
cornerRadius
|
|
1760
|
+
);
|
|
1761
|
+
const hoverScale = ringHoverScale(isHovered, isPushedOut);
|
|
1762
|
+
const layerOpacity = isFaded ? 0.35 : 1;
|
|
1763
|
+
const enterDone = !animate2 || expandComplete && progressComplete;
|
|
1764
|
+
const groupStyle = {
|
|
1765
|
+
cursor: "pointer",
|
|
1766
|
+
transformOrigin: "0px 0px",
|
|
1767
|
+
filter: showGlow && isHovered ? `drop-shadow(0 0 12px ${color})` : "none"
|
|
1768
|
+
};
|
|
1769
|
+
if (enterDone) {
|
|
1770
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1771
|
+
react$1.motion.g,
|
|
1772
|
+
{
|
|
1773
|
+
animate: { scale: hoverScale, opacity: layerOpacity },
|
|
1774
|
+
onMouseEnter: handleMouseEnter,
|
|
1775
|
+
onMouseLeave: handleMouseLeave,
|
|
1776
|
+
style: groupStyle,
|
|
1777
|
+
transition: {
|
|
1778
|
+
scale: { type: "spring", stiffness: 400, damping: 25 },
|
|
1779
|
+
opacity: { duration: 0.15 }
|
|
1780
|
+
},
|
|
1781
|
+
children: [
|
|
1782
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: bgPath, fill: ringCssVars.ringBackground }),
|
|
1783
|
+
progressPath ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: progressPath, fill: color }) : null
|
|
1784
|
+
]
|
|
1785
|
+
}
|
|
1786
|
+
);
|
|
1787
|
+
}
|
|
1788
|
+
if (!expandComplete) {
|
|
1789
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1790
|
+
react$1.motion.g,
|
|
1791
|
+
{
|
|
1792
|
+
onMouseEnter: handleMouseEnter,
|
|
1793
|
+
onMouseLeave: handleMouseLeave,
|
|
1794
|
+
style: {
|
|
1795
|
+
...groupStyle,
|
|
1796
|
+
scale: enterScale,
|
|
1797
|
+
opacity: layerOpacity
|
|
1798
|
+
},
|
|
1799
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: bgPath, fill: ringCssVars.ringBackground })
|
|
1800
|
+
}
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1804
|
+
react$1.motion.g,
|
|
1805
|
+
{
|
|
1806
|
+
animate: { scale: hoverScale, opacity: layerOpacity },
|
|
1807
|
+
onMouseEnter: handleMouseEnter,
|
|
1808
|
+
onMouseLeave: handleMouseLeave,
|
|
1809
|
+
style: groupStyle,
|
|
1810
|
+
transition: {
|
|
1811
|
+
scale: { type: "spring", stiffness: 400, damping: 25 },
|
|
1812
|
+
opacity: { duration: 0.15 }
|
|
1813
|
+
},
|
|
1814
|
+
children: [
|
|
1815
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: bgPath, fill: ringCssVars.ringBackground }),
|
|
1816
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1817
|
+
RingProgressPath,
|
|
1818
|
+
{
|
|
1819
|
+
animatedProgressPath,
|
|
1820
|
+
color,
|
|
1821
|
+
progressComplete,
|
|
1822
|
+
progressPath
|
|
1823
|
+
}
|
|
1824
|
+
)
|
|
1825
|
+
]
|
|
1826
|
+
}
|
|
1827
|
+
);
|
|
1828
|
+
});
|
|
1829
|
+
Ring.displayName = "Ring";
|
|
1830
|
+
function RingCenter({
|
|
1831
|
+
defaultLabel = "Total",
|
|
1832
|
+
formatOptions = defaultChartStatFlowFormat,
|
|
1833
|
+
children,
|
|
1834
|
+
className = "",
|
|
1835
|
+
valueClassName = chartCenterValueClassName,
|
|
1836
|
+
labelClassName = chartCenterLabelClassName,
|
|
1837
|
+
prefix,
|
|
1838
|
+
suffix
|
|
1839
|
+
}) {
|
|
1840
|
+
const { data, totalValue, baseInnerRadius } = useRingStable();
|
|
1841
|
+
const { hoveredIndex } = useRingHover();
|
|
1842
|
+
const hoveredData = hoveredIndex === null ? null : data[hoveredIndex];
|
|
1843
|
+
const displayValue = hoveredData ? hoveredData.value : totalValue;
|
|
1844
|
+
const displayLabel = hoveredData ? hoveredData.label : defaultLabel;
|
|
1845
|
+
const centerSize = baseInnerRadius * 2 - 16;
|
|
1846
|
+
if (children && hoveredData) {
|
|
1847
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1848
|
+
"div",
|
|
1849
|
+
{
|
|
1850
|
+
className: cn(
|
|
1851
|
+
chartCenterContainerClassName,
|
|
1852
|
+
"flex items-center justify-center",
|
|
1853
|
+
className
|
|
1854
|
+
),
|
|
1855
|
+
style: { width: centerSize, height: centerSize },
|
|
1856
|
+
children: children({
|
|
1857
|
+
value: displayValue,
|
|
1858
|
+
label: displayLabel,
|
|
1859
|
+
isHovered: hoveredIndex !== null,
|
|
1860
|
+
data: hoveredData
|
|
1861
|
+
})
|
|
1862
|
+
}
|
|
1863
|
+
);
|
|
1864
|
+
}
|
|
1865
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1866
|
+
"div",
|
|
1867
|
+
{
|
|
1868
|
+
className: cn(
|
|
1869
|
+
chartCenterContainerClassName,
|
|
1870
|
+
"flex flex-col items-center justify-center text-center",
|
|
1871
|
+
className
|
|
1872
|
+
),
|
|
1873
|
+
style: { width: centerSize, height: centerSize },
|
|
1874
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1875
|
+
ChartStatFlow,
|
|
1876
|
+
{
|
|
1877
|
+
formatOptions,
|
|
1878
|
+
label: displayLabel,
|
|
1879
|
+
labelClassName,
|
|
1880
|
+
prefix,
|
|
1881
|
+
suffix,
|
|
1882
|
+
value: displayValue,
|
|
1883
|
+
valueClassName
|
|
1884
|
+
}
|
|
1885
|
+
)
|
|
1886
|
+
}
|
|
1887
|
+
);
|
|
1888
|
+
}
|
|
1889
|
+
RingCenter.displayName = "RingCenter";
|
|
1890
|
+
|
|
1891
|
+
exports.ChartStatFlow = ChartStatFlow;
|
|
1892
|
+
exports.Gauge = Gauge;
|
|
1893
|
+
exports.Ring = Ring;
|
|
1894
|
+
exports.RingCenter = RingCenter;
|
|
1895
|
+
exports.RingChart = RingChart;
|
|
1896
|
+
exports.RingProvider = RingProvider;
|
|
1897
|
+
exports.defaultChartStatFlowFormat = defaultChartStatFlowFormat;
|
|
1898
|
+
exports.defaultRingColors = defaultRingColors;
|
|
1899
|
+
exports.ringCssVars = ringCssVars;
|
|
1900
|
+
exports.useRing = useRing;
|
|
1901
|
+
exports.useRingHover = useRingHover;
|
|
1902
|
+
exports.useRingStable = useRingStable;
|
|
1903
|
+
//# sourceMappingURL=charts.cjs.map
|
|
1904
|
+
//# sourceMappingURL=charts.cjs.map
|