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