@acronis-platform/ui-react 5.2.0 → 5.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ui/area-chart/area-chart.js +107 -107
- package/dist/components/ui/area-chart/area-chart.js.map +1 -1
- package/dist/components/ui/bar-chart/bar-chart.js +162 -162
- package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
- package/dist/components/ui/category-bar/category-bar.js +50 -50
- package/dist/components/ui/category-bar/category-bar.js.map +1 -1
- package/dist/components/ui/chart/chart.js +53 -40
- package/dist/components/ui/chart/chart.js.map +1 -1
- package/dist/components/ui/composed-chart/composed-chart.js +146 -146
- package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
- package/dist/components/ui/confidence-cone/confidence-cone.js +97 -97
- package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
- package/dist/components/ui/data-table/data-table-bulk-actions-bar.js +1 -1
- package/dist/components/ui/data-table/data-table-bulk-actions-bar.js.map +1 -1
- package/dist/components/ui/data-table/data-table-view-options.js +3 -2
- package/dist/components/ui/data-table/data-table-view-options.js.map +1 -1
- package/dist/components/ui/data-table/data-table.js +136 -132
- package/dist/components/ui/data-table/data-table.js.map +1 -1
- package/dist/components/ui/funnel-chart/funnel-chart.js +120 -120
- package/dist/components/ui/funnel-chart/funnel-chart.js.map +1 -1
- package/dist/components/ui/histogram/histogram.js +58 -58
- package/dist/components/ui/histogram/histogram.js.map +1 -1
- package/dist/components/ui/line-chart/line-chart.js +91 -91
- package/dist/components/ui/line-chart/line-chart.js.map +1 -1
- package/dist/components/ui/pie-chart/pie-chart.js +92 -92
- package/dist/components/ui/pie-chart/pie-chart.js.map +1 -1
- package/dist/components/ui/radar-chart/radar-chart.js +37 -37
- package/dist/components/ui/radar-chart/radar-chart.js.map +1 -1
- package/dist/components/ui/radial-bar-chart/radial-bar-chart.js +112 -112
- package/dist/components/ui/radial-bar-chart/radial-bar-chart.js.map +1 -1
- package/dist/components/ui/sankey-chart/sankey-chart.js +78 -78
- package/dist/components/ui/sankey-chart/sankey-chart.js.map +1 -1
- package/dist/components/ui/scatter-chart/scatter-chart.js +57 -57
- package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
- package/dist/components/ui/table/table-view-options.js +88 -33
- package/dist/components/ui/table/table-view-options.js.map +1 -1
- package/dist/components/ui/table/table.js.map +1 -1
- package/dist/components/ui/treemap/treemap.js +87 -87
- package/dist/components/ui/treemap/treemap.js.map +1 -1
- package/dist/index.js +111 -111
- package/dist/llms/data-table.md +33 -7
- package/dist/llms/table.md +56 -23
- package/dist/llms.txt +1 -1
- package/dist/react.js +111 -111
- package/dist/src/components/ui/chart/chart.d.ts +1 -0
- package/dist/src/components/ui/chart/index.d.ts +1 -1
- package/dist/src/components/ui/data-table/data-table-view-options.d.ts +1 -1
- package/dist/src/components/ui/data-table/data-table.d.ts +11 -1
- package/dist/src/components/ui/data-table/data-table.docs.d.ts +6 -0
- package/dist/src/components/ui/radial-bar-chart/radial-bar-chart.d.ts +3 -2
- package/dist/src/components/ui/sankey-chart/sankey-chart.d.ts +1 -1
- package/dist/src/components/ui/table/table-view-options.d.ts +9 -1
- package/dist/src/components/ui/treemap/treemap.d.ts +3 -2
- package/dist/ui-react.css +1 -1
- package/package.json +3 -3
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../../../lib/utils.js";
|
|
3
3
|
import { CHART_DEFAULT_PALETTE as t } from "../chart/chart-palette.js";
|
|
4
|
-
import { ChartContainer as n, ChartLegendContent as r, ChartTooltip as i, ChartTooltipContent as a, resolveChartColors as o } from "../chart/chart.js";
|
|
5
|
-
import { resolveAnimation as
|
|
6
|
-
import * as
|
|
7
|
-
import { Fragment as
|
|
8
|
-
import { Cell as
|
|
4
|
+
import { ChartContainer as n, ChartLegendContent as r, ChartTooltip as i, ChartTooltipContent as a, resolveChartColors as o, toCssKey as s } from "../chart/chart.js";
|
|
5
|
+
import { resolveAnimation as c, resolveLabelFillClass as l } from "../chart/chart-format.js";
|
|
6
|
+
import * as u from "react";
|
|
7
|
+
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
8
|
+
import { Cell as m, Label as h, LabelList as g, PolarAngleAxis as _, PolarGrid as v, RadialBar as y, RadialBarChart as b } from "recharts";
|
|
9
9
|
//#region src/components/ui/radial-bar-chart/radial-bar-chart.tsx
|
|
10
|
-
function
|
|
11
|
-
return /* @__PURE__ */
|
|
10
|
+
function x({ centerLabel: e }) {
|
|
11
|
+
return /* @__PURE__ */ f(h, { content: ({ viewBox: t }) => {
|
|
12
12
|
if (!t || !("cx" in t)) return null;
|
|
13
13
|
let { cx: n = 0, cy: r = 0 } = t, i = e.value != null, a = e.label != null, o = i && a;
|
|
14
|
-
return /* @__PURE__ */
|
|
14
|
+
return /* @__PURE__ */ p("g", { children: [i && /* @__PURE__ */ f("text", {
|
|
15
15
|
x: n,
|
|
16
16
|
y: o ? r - 10 : r,
|
|
17
17
|
textAnchor: "middle",
|
|
18
18
|
dominantBaseline: "central",
|
|
19
19
|
className: "fill-foreground text-2xl font-semibold",
|
|
20
20
|
children: e.value
|
|
21
|
-
}), a && /* @__PURE__ */
|
|
21
|
+
}), a && /* @__PURE__ */ f("text", {
|
|
22
22
|
x: n,
|
|
23
23
|
y: o ? r + 13 : r,
|
|
24
24
|
textAnchor: "middle",
|
|
@@ -28,14 +28,14 @@ function b({ centerLabel: e }) {
|
|
|
28
28
|
})] });
|
|
29
29
|
} });
|
|
30
30
|
}
|
|
31
|
-
function
|
|
31
|
+
function S(e) {
|
|
32
32
|
let { format: t, name: n, value: r, formatter: i } = e;
|
|
33
33
|
if (r == null) return "";
|
|
34
34
|
let a = i ? i(r) : String(r);
|
|
35
35
|
return t === "name-value" && n != null ? `${n}: ${a}` : a;
|
|
36
36
|
}
|
|
37
|
-
var
|
|
38
|
-
function
|
|
37
|
+
var C = 3;
|
|
38
|
+
function w(e) {
|
|
39
39
|
let { value: t, domain: n, segments: r, sweep: i, closed: a } = e, o = a ? r : r - 1, s = o > 0 ? Math.min(Math.max(e.gap, 0), i / (2 * o)) : 0, c = (i - s * o) / r, [l, u] = n, d = u - l, f = (d > 0 ? Math.min(Math.max((t - l) / d, 0), 1) : 0) * c * r, p = [];
|
|
40
40
|
for (let e = 0; e < r; e++) {
|
|
41
41
|
let t = Math.min(Math.max(f, 0), c);
|
|
@@ -55,10 +55,10 @@ function C(e) {
|
|
|
55
55
|
}
|
|
56
56
|
return p;
|
|
57
57
|
}
|
|
58
|
-
function
|
|
59
|
-
return e === "gap" ? "transparent" : e === "track" ? "var(--ui-border-on-status-neutral)" : `var(--color-${t})`;
|
|
58
|
+
function T(e, t) {
|
|
59
|
+
return e === "gap" ? "transparent" : e === "track" ? "var(--ui-border-on-status-neutral)" : `var(--color-${s(String(t))})`;
|
|
60
60
|
}
|
|
61
|
-
function
|
|
61
|
+
function E(e) {
|
|
62
62
|
let { config: t, row: n, nameKey: r, dataKey: i, domainMax: a } = e, o = String(n[r]), s = n[i], c = typeof s == "number" ? s.toLocaleString() : String(s ?? "");
|
|
63
63
|
return {
|
|
64
64
|
colorName: o,
|
|
@@ -66,52 +66,52 @@ function T(e) {
|
|
|
66
66
|
valueText: a == null ? c : `${c} / ${a.toLocaleString()}`
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
-
function
|
|
70
|
-
let { colorName: r, label: i, valueText: o } =
|
|
71
|
-
return /* @__PURE__ */
|
|
69
|
+
function D({ active: e, payload: t, ...n }) {
|
|
70
|
+
let { colorName: r, label: i, valueText: o } = E(n);
|
|
71
|
+
return /* @__PURE__ */ f(a, {
|
|
72
72
|
active: e,
|
|
73
73
|
payload: t?.slice(0, 1),
|
|
74
74
|
hideLabel: !0,
|
|
75
|
-
formatter: () => /* @__PURE__ */
|
|
75
|
+
formatter: () => /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("div", {
|
|
76
76
|
className: "h-2.5 w-2.5 shrink-0 rounded-full",
|
|
77
|
-
style: { backgroundColor: `var(--color-${r})` }
|
|
78
|
-
}), /* @__PURE__ */
|
|
77
|
+
style: { backgroundColor: `var(--color-${s(r)})` }
|
|
78
|
+
}), /* @__PURE__ */ p("div", {
|
|
79
79
|
className: "flex flex-1 items-center justify-between gap-2 leading-none",
|
|
80
|
-
children: [/* @__PURE__ */
|
|
80
|
+
children: [/* @__PURE__ */ f("span", {
|
|
81
81
|
className: "text-muted-foreground",
|
|
82
82
|
children: i
|
|
83
|
-
}), /* @__PURE__ */
|
|
83
|
+
}), /* @__PURE__ */ f("span", {
|
|
84
84
|
className: "font-medium tabular-nums text-foreground",
|
|
85
85
|
children: o
|
|
86
86
|
})]
|
|
87
87
|
})] })
|
|
88
88
|
});
|
|
89
89
|
}
|
|
90
|
-
function
|
|
90
|
+
function O(e, t) {
|
|
91
91
|
let n = e?.[t];
|
|
92
92
|
return n == null ? "" : String(n);
|
|
93
93
|
}
|
|
94
|
-
function
|
|
94
|
+
function k(e) {
|
|
95
95
|
let { key: t, row: n, isMultiMetric: r, nameKey: i, config: a } = e;
|
|
96
96
|
if (!r) return n?.[i];
|
|
97
97
|
let o = a[t]?.label;
|
|
98
98
|
return typeof o == "string" || typeof o == "number" ? o : t;
|
|
99
99
|
}
|
|
100
|
-
function ee({ seriesKeys: e, seriesData: t, isMultiMetric: n, config: r, nameKey: i, showBackground: a, cornerRadius: o, minPointSize:
|
|
101
|
-
return e.map((e,
|
|
100
|
+
function ee({ seriesKeys: e, seriesData: t, isMultiMetric: n, config: r, nameKey: i, showBackground: a, cornerRadius: o, minPointSize: c, animation: u, centerLabel: d, showLabels: h, labelPosition: _, labelFormat: v, labelFormatter: b }) {
|
|
101
|
+
return e.map((e, C) => /* @__PURE__ */ p(y, {
|
|
102
102
|
dataKey: e,
|
|
103
|
-
fill: n ? `var(--color-${e})` : void 0,
|
|
103
|
+
fill: n ? `var(--color-${s(e)})` : void 0,
|
|
104
104
|
background: a ? { fill: "var(--ui-border-on-status-neutral)" } : !1,
|
|
105
105
|
cornerRadius: o,
|
|
106
|
-
minPointSize:
|
|
107
|
-
...
|
|
106
|
+
minPointSize: c,
|
|
107
|
+
...u,
|
|
108
108
|
children: [
|
|
109
|
-
!n && t.map((e, t) => /* @__PURE__ */
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
valueAccessor: (t) =>
|
|
113
|
-
format:
|
|
114
|
-
name:
|
|
109
|
+
!n && t.map((e, t) => /* @__PURE__ */ f(m, { fill: `var(--color-${s(String(e[i]))})` }, t)),
|
|
110
|
+
C === 0 && d && /* @__PURE__ */ f(x, { centerLabel: d }),
|
|
111
|
+
h && /* @__PURE__ */ f(g, {
|
|
112
|
+
valueAccessor: (t) => S({
|
|
113
|
+
format: v,
|
|
114
|
+
name: k({
|
|
115
115
|
key: e,
|
|
116
116
|
row: t.payload,
|
|
117
117
|
isMultiMetric: n,
|
|
@@ -119,159 +119,159 @@ function ee({ seriesKeys: e, seriesData: t, isMultiMetric: n, config: r, nameKey
|
|
|
119
119
|
config: r
|
|
120
120
|
}),
|
|
121
121
|
value: t.value,
|
|
122
|
-
formatter:
|
|
122
|
+
formatter: b
|
|
123
123
|
}),
|
|
124
|
-
position:
|
|
125
|
-
className:
|
|
124
|
+
position: _,
|
|
125
|
+
className: l(_),
|
|
126
126
|
fontSize: 12
|
|
127
127
|
})
|
|
128
128
|
]
|
|
129
129
|
}, e));
|
|
130
130
|
}
|
|
131
131
|
function te({ ringSegments: e, row: t, nameKey: n, cornerRadius: r, animation: i, centerLabel: a }) {
|
|
132
|
-
return e.map((e, o) => /* @__PURE__ */
|
|
132
|
+
return e.map((e, o) => /* @__PURE__ */ f(y, {
|
|
133
133
|
dataKey: e.key,
|
|
134
134
|
stackId: "segments",
|
|
135
135
|
name: String(t[n]),
|
|
136
|
-
fill:
|
|
136
|
+
fill: T(e.kind, t[n]),
|
|
137
137
|
cornerRadius: r,
|
|
138
138
|
...i,
|
|
139
|
-
children: o === 0 && a && /* @__PURE__ */
|
|
139
|
+
children: o === 0 && a && /* @__PURE__ */ f(x, { centerLabel: a })
|
|
140
140
|
}, e.key));
|
|
141
141
|
}
|
|
142
|
-
var
|
|
143
|
-
let W =
|
|
142
|
+
var A = u.forwardRef(({ className: l, config: d, palette: m, data: h, dataKey: g, dataKeys: y, nameKey: x, innerRadius: S = 20, outerRadius: T = 60, startAngle: E = 90, endAngle: k = -270, valueDomain: A, cornerRadius: j = 4, cx: ne, cy: M, barSize: re, barGap: ie, barCategoryGap: ae, minAngle: N, margin: oe, segments: P, segmentGap: se = C, showBackground: ce = !0, showPolarGrid: le = !1, centerLabel: F, showTooltip: ue = !0, showLegend: I = !0, legendValueFormatter: L, tooltipContent: R, animate: z, animationDuration: B, animationBegin: V, animationEasing: H, showLabels: U = !1, labelPosition: de, labelFormat: fe = "value", labelFormatter: pe, ...me }, he) => {
|
|
143
|
+
let W = c({
|
|
144
144
|
animate: z,
|
|
145
145
|
animationDuration: B,
|
|
146
146
|
animationBegin: V,
|
|
147
147
|
animationEasing: H
|
|
148
|
-
}), G =
|
|
149
|
-
value:
|
|
150
|
-
domain:
|
|
148
|
+
}), G = de ?? "insideStart", K = !!y?.length, q = P != null && P > 1 && !K && h.length === 1 && typeof h[0][g] == "number", ge = K ? y : [g], J = u.useMemo(() => y?.length ? y : [g], [y, g]), Y = Math.abs(k - E), X = q ? w({
|
|
149
|
+
value: h[0][g],
|
|
150
|
+
domain: A ?? [0, h[0][g]],
|
|
151
151
|
segments: P,
|
|
152
|
-
gap:
|
|
152
|
+
gap: se,
|
|
153
153
|
sweep: Y,
|
|
154
154
|
closed: Y >= 360
|
|
155
|
-
}) : [], Z = K ?
|
|
155
|
+
}) : [], Z = K ? h : h.map((e) => ({
|
|
156
156
|
...e,
|
|
157
|
-
fill: `var(--color-${e[
|
|
157
|
+
fill: `var(--color-${s(String(e[x]))})`
|
|
158
158
|
})), Q = q ? [{
|
|
159
|
-
...
|
|
159
|
+
...h[0],
|
|
160
160
|
...Object.fromEntries(X.map((e) => [e.key, e.degrees]))
|
|
161
|
-
}] : Z,
|
|
161
|
+
}] : Z, _e = N === void 0 ? void 0 : k < E ? -N : N, $ = u.useMemo(() => I ? o(d, m ?? t) : null, [
|
|
162
162
|
I,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
]),
|
|
163
|
+
d,
|
|
164
|
+
m
|
|
165
|
+
]), ve = u.useMemo(() => $ ? K ? J.map((e) => ({
|
|
166
166
|
value: e,
|
|
167
167
|
dataKey: e,
|
|
168
|
-
color: $[e]?.color ?? `var(--color-${e})`,
|
|
168
|
+
color: $[e]?.color ?? `var(--color-${s(e)})`,
|
|
169
169
|
type: "rect",
|
|
170
170
|
payload: {}
|
|
171
|
-
})) :
|
|
172
|
-
value: String(e[
|
|
173
|
-
dataKey:
|
|
174
|
-
color: $[String(e[
|
|
171
|
+
})) : h.map((e) => ({
|
|
172
|
+
value: String(e[x]),
|
|
173
|
+
dataKey: x,
|
|
174
|
+
color: $[String(e[x])]?.color ?? `var(--color-${s(String(e[x]))})`,
|
|
175
175
|
type: "rect",
|
|
176
176
|
payload: e
|
|
177
177
|
})) : [], [
|
|
178
178
|
$,
|
|
179
179
|
K,
|
|
180
180
|
J,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
]),
|
|
181
|
+
h,
|
|
182
|
+
x
|
|
183
|
+
]), ye = I && !q && !!$, be = /* @__PURE__ */ p(b, {
|
|
184
184
|
data: Q,
|
|
185
|
-
dataKey: K || q ? void 0 :
|
|
185
|
+
dataKey: K || q ? void 0 : g,
|
|
186
186
|
cx: ne,
|
|
187
|
-
cy:
|
|
188
|
-
innerRadius:
|
|
189
|
-
outerRadius:
|
|
190
|
-
startAngle:
|
|
191
|
-
endAngle:
|
|
187
|
+
cy: M,
|
|
188
|
+
innerRadius: S,
|
|
189
|
+
outerRadius: T,
|
|
190
|
+
startAngle: E,
|
|
191
|
+
endAngle: k,
|
|
192
192
|
barSize: re,
|
|
193
193
|
barGap: ie,
|
|
194
194
|
barCategoryGap: ae,
|
|
195
|
-
margin:
|
|
195
|
+
margin: oe ?? {
|
|
196
196
|
top: 0,
|
|
197
197
|
right: 0,
|
|
198
198
|
bottom: 0,
|
|
199
199
|
left: 0
|
|
200
200
|
},
|
|
201
201
|
children: [
|
|
202
|
-
|
|
202
|
+
le && /* @__PURE__ */ f(v, {
|
|
203
203
|
gridType: "circle",
|
|
204
204
|
radialLines: !1
|
|
205
205
|
}),
|
|
206
|
-
(
|
|
206
|
+
(A || q) && /* @__PURE__ */ f(_, {
|
|
207
207
|
type: "number",
|
|
208
|
-
domain: q ? [0, Y] :
|
|
208
|
+
domain: q ? [0, Y] : A,
|
|
209
209
|
tick: !1,
|
|
210
210
|
axisLine: !1
|
|
211
211
|
}),
|
|
212
|
-
|
|
212
|
+
ue && /* @__PURE__ */ f(i, {
|
|
213
213
|
cursor: !q && void 0,
|
|
214
|
-
content: R ?? (q ? /* @__PURE__ */
|
|
215
|
-
config:
|
|
216
|
-
row:
|
|
217
|
-
nameKey:
|
|
218
|
-
dataKey:
|
|
219
|
-
domainMax:
|
|
220
|
-
}) : K ? /* @__PURE__ */
|
|
221
|
-
nameKey:
|
|
214
|
+
content: R ?? (q ? /* @__PURE__ */ f(D, {
|
|
215
|
+
config: d,
|
|
216
|
+
row: h[0],
|
|
217
|
+
nameKey: x,
|
|
218
|
+
dataKey: g,
|
|
219
|
+
domainMax: A?.[1]
|
|
220
|
+
}) : K ? /* @__PURE__ */ f(a, { labelFormatter: (e, t) => O(t?.[0]?.payload, x) }) : /* @__PURE__ */ f(a, {
|
|
221
|
+
nameKey: x,
|
|
222
222
|
hideLabel: !0
|
|
223
223
|
}))
|
|
224
224
|
}),
|
|
225
|
-
q ? /* @__PURE__ */
|
|
225
|
+
q ? /* @__PURE__ */ f(te, {
|
|
226
226
|
ringSegments: X,
|
|
227
|
-
row:
|
|
228
|
-
nameKey:
|
|
229
|
-
cornerRadius:
|
|
227
|
+
row: h[0],
|
|
228
|
+
nameKey: x,
|
|
229
|
+
cornerRadius: j,
|
|
230
230
|
animation: W,
|
|
231
231
|
centerLabel: F
|
|
232
|
-
}) : /* @__PURE__ */
|
|
233
|
-
seriesKeys:
|
|
232
|
+
}) : /* @__PURE__ */ f(ee, {
|
|
233
|
+
seriesKeys: ge,
|
|
234
234
|
seriesData: Z,
|
|
235
235
|
isMultiMetric: K,
|
|
236
|
-
config:
|
|
237
|
-
nameKey:
|
|
238
|
-
showBackground:
|
|
239
|
-
cornerRadius:
|
|
240
|
-
minPointSize:
|
|
236
|
+
config: d,
|
|
237
|
+
nameKey: x,
|
|
238
|
+
showBackground: ce,
|
|
239
|
+
cornerRadius: j,
|
|
240
|
+
minPointSize: _e,
|
|
241
241
|
animation: W,
|
|
242
242
|
centerLabel: F,
|
|
243
243
|
showLabels: U,
|
|
244
244
|
labelPosition: G,
|
|
245
|
-
labelFormat:
|
|
246
|
-
labelFormatter:
|
|
245
|
+
labelFormat: fe,
|
|
246
|
+
labelFormatter: pe
|
|
247
247
|
})
|
|
248
248
|
]
|
|
249
|
-
}),
|
|
250
|
-
return /* @__PURE__ */
|
|
251
|
-
ref:
|
|
252
|
-
className: e("flex flex-row items-center gap-4", !
|
|
253
|
-
...
|
|
254
|
-
children: [/* @__PURE__ */
|
|
255
|
-
className: e(
|
|
256
|
-
children: /* @__PURE__ */
|
|
257
|
-
config:
|
|
258
|
-
palette:
|
|
249
|
+
}), xe = U && (G === "outside" || G === "end") ? "size-[200px]" : "size-[120px]";
|
|
250
|
+
return /* @__PURE__ */ p("div", {
|
|
251
|
+
ref: he,
|
|
252
|
+
className: e("flex flex-row items-center gap-4", !ye && "justify-center", l),
|
|
253
|
+
...me,
|
|
254
|
+
children: [/* @__PURE__ */ f("div", {
|
|
255
|
+
className: e(xe, "shrink-0"),
|
|
256
|
+
children: /* @__PURE__ */ f(n, {
|
|
257
|
+
config: d,
|
|
258
|
+
palette: m,
|
|
259
259
|
className: "size-full",
|
|
260
|
-
children:
|
|
260
|
+
children: be
|
|
261
261
|
})
|
|
262
|
-
}), I && !q && $ && /* @__PURE__ */
|
|
262
|
+
}), I && !q && $ && /* @__PURE__ */ f(r, {
|
|
263
263
|
variant: "list",
|
|
264
|
-
payload:
|
|
264
|
+
payload: ve,
|
|
265
265
|
config: $,
|
|
266
|
-
nameKey: K ? void 0 :
|
|
267
|
-
valueKey: K ? void 0 :
|
|
266
|
+
nameKey: K ? void 0 : x,
|
|
267
|
+
valueKey: K ? void 0 : g,
|
|
268
268
|
valueFormatter: K ? void 0 : L,
|
|
269
269
|
className: "min-w-0 flex-1"
|
|
270
270
|
})]
|
|
271
271
|
});
|
|
272
272
|
});
|
|
273
|
-
|
|
273
|
+
A.displayName = "RadialBarChart";
|
|
274
274
|
//#endregion
|
|
275
|
-
export {
|
|
275
|
+
export { A as RadialBarChart, D as RadialBarChartSegmentedTooltipContent, O as radialBarChartBandName, S as radialBarChartLabelText, T as radialBarChartSegmentFill, E as radialBarChartSegmentedReading, w as radialBarChartSegments };
|
|
276
276
|
|
|
277
277
|
//# sourceMappingURL=radial-bar-chart.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radial-bar-chart.js","names":[],"sources":["../../../../src/components/ui/radial-bar-chart/radial-bar-chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n Cell,\n Label,\n LabelList,\n PolarAngleAxis,\n PolarGrid,\n RadialBar,\n RadialBarChart as RechartsRadialBarChart,\n} from 'recharts';\n\nimport type { LegendPayload } from 'recharts/types/component/DefaultLegendContent';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n resolveChartColors,\n resolveLabelFillClass,\n CHART_DEFAULT_PALETTE,\n CHART_LABEL_FONT_SIZE,\n type ChartConfig,\n type ChartPalette,\n type ChartAnimationProps,\n type ChartDataLabelProps,\n type ChartTooltipContentProps,\n type PolarLabelPosition,\n type ResolvedAnimation,\n type TickFormatter,\n} from '../chart';\n\n// A typed recharts composition over the shared `Chart` primitives (a polar/radial\n// type). Rows become concentric arcs sized by `dataKey`, each colored from its\n// `--color-<name>` var; `dataKeys` switches to one arc per metric instead. Like\n// ScatterChart/ComposedChart there's no CVA variant: a radial bar's\n// expressiveness is geometry (angles/radii, plain props) and the data mapping,\n// not a visual \"mode\". The angular sweep is exposed as startAngle/endAngle props\n// so a caller can build a gauge or a full ring.\n\n/** Row-per-arc datum: the `nameKey` label plus each metric's numeric value. */\ntype RadialBarChartDatum = Record<string, string | number>;\n\n/** What an arc's data label reads. */\nexport type RadialBarChartLabelFormat = 'value' | 'name-value';\n\nexport interface RadialBarChartCenterLabel {\n // Rendered as SVG <text>, which only lays out text — hence string | number,\n // not ReactNode.\n /** Headline metric rendered large in the hole (e.g. the gauge's value). */\n value?: string | number;\n /** Caption rendered under the value. */\n label?: string | number;\n}\n\n/**\n * The readout in the hole at the centre of the arcs — a headline value over a\n * caption. Rendered as a recharts `<Label>`, which is what supplies the polar\n * viewBox the text centres itself on.\n *\n * There is one readout for the whole chart, so it hangs off the first series\n * drawn — every series shares the same viewBox.\n */\nfunction RadialBarChartCenterLabelContent({\n centerLabel,\n}: {\n centerLabel: RadialBarChartCenterLabel;\n}) {\n return (\n <Label\n content={({ viewBox }) => {\n if (!viewBox || !('cx' in viewBox)) return null;\n const { cx: centerX = 0, cy: centerY = 0 } = viewBox as {\n cx?: number;\n cy?: number;\n };\n const hasValue = centerLabel.value != null;\n const hasLabel = centerLabel.label != null;\n // Straddle the centre when both lines show, so the value + label block\n // is centered as a whole (not just the value).\n const both = hasValue && hasLabel;\n return (\n <g>\n {hasValue && (\n <text\n x={centerX}\n y={both ? centerY - 10 : centerY}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"fill-foreground text-2xl font-semibold\"\n >\n {centerLabel.value}\n </text>\n )}\n {hasLabel && (\n <text\n x={centerX}\n y={both ? centerY + 13 : centerY}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"fill-muted-foreground text-sm\"\n >\n {centerLabel.label}\n </text>\n )}\n </g>\n );\n }}\n />\n );\n}\n\n/**\n * Compose one arc's data-label text. Exported for unit tests; not part of the\n * package's public API.\n *\n * `labelFormatter` only ever formats the numeric part, so a chart's labels and\n * its tooltip stay in the same units under either format. A nullish value yields\n * an empty label, which recharts renders as no `<text>` at all.\n */\nexport function radialBarChartLabelText(options: {\n format: RadialBarChartLabelFormat;\n name: string | number | undefined;\n value: string | number | undefined;\n formatter?: TickFormatter;\n}): string {\n const { format, name, value, formatter } = options;\n if (value == null) return '';\n const valueText = formatter ? formatter(value) : String(value);\n return format === 'name-value' && name != null\n ? `${name}: ${valueText}`\n : valueText;\n}\n\n/** One piece of a segmented gauge's ring: a length in degrees and what it is. */\nexport interface RadialBarChartSegment {\n /** Synthetic series key — stable for a given (index, kind). */\n key: string;\n /** Angular length of the piece, in degrees. */\n degrees: number;\n /** `value` is the metric, `track` the unreached remainder, `gap` the notch. */\n kind: 'value' | 'track' | 'gap';\n}\n\n/** Fallback gap between a segmented gauge's segments, in degrees. */\nconst SEGMENT_GAP = 3;\n\n/**\n * Cut a gauge's sweep into equal segments separated by gaps, and split the\n * segment the value ends inside into its reached and unreached parts. Exported\n * for unit tests; not part of the package's public API.\n *\n * Lengths come back in **degrees**, which is what lets the ring be built as one\n * stack of synthetic series over a `[0, sweep]` angular scale: recharts lays\n * stacked radial bars out sequentially along the angle, so a transparent series\n * between two colored ones reads as a real notch in the ring. A `gap` that\n * would leave no room for the segments themselves is clamped.\n */\nexport function radialBarChartSegments(options: {\n value: number;\n domain: [number, number];\n segments: number;\n gap: number;\n /** Absolute sweep of the chart, in degrees. */\n sweep: number;\n /** A full-circle sweep also needs a gap between the last segment and the first. */\n closed: boolean;\n}): RadialBarChartSegment[] {\n const { value, domain, segments, sweep, closed } = options;\n const gapCount = closed ? segments : segments - 1;\n // Leave at least half the sweep for the segments, however wide a gap is asked\n // for — an all-gap ring would render as nothing at all. A negative gap would\n // stretch the pieces past the sweep and overlap them, so it floors at zero.\n const gap =\n gapCount > 0\n ? Math.min(Math.max(options.gap, 0), sweep / (2 * gapCount))\n : 0;\n const segmentDegrees = (sweep - gap * gapCount) / segments;\n const [min, max] = domain;\n const span = max - min;\n // A domain with no span (`[n, n]`) or an inverted one (`[max, min]`) cannot\n // place a value on the ring at all, so there is no fraction to draw and the\n // ring stays empty. It deliberately does not fall back to comparing the value\n // against zero: that reported a *full* ring for `{ value: 5, domain: [100,\n // 100] }`, i.e. claimed completion the data never supported. For a gauge,\n // under-reading a domain that says nothing is the safe direction.\n const fraction =\n span > 0 ? Math.min(Math.max((value - min) / span, 0), 1) : 0;\n // The value maps onto the *drawn* ring, so the gaps never eat into it.\n let remainingValue = fraction * segmentDegrees * segments;\n\n const pieces: RadialBarChartSegment[] = [];\n for (let index = 0; index < segments; index++) {\n const reached = Math.min(Math.max(remainingValue, 0), segmentDegrees);\n remainingValue -= reached;\n // Both halves are always emitted, including at zero length: a stable key set\n // keeps recharts' series identities steady as the value changes.\n pieces.push({ key: `seg-${index}-value`, degrees: reached, kind: 'value' });\n pieces.push({\n key: `seg-${index}-track`,\n degrees: segmentDegrees - reached,\n kind: 'track',\n });\n if (gap > 0 && (closed || index < segments - 1)) {\n pieces.push({ key: `seg-${index}-gap`, degrees: gap, kind: 'gap' });\n }\n }\n return pieces;\n}\n\n/**\n * Fill for one piece of a segmented gauge's ring. Exported for unit tests and so\n * the forced-open tooltip story can build a ring from the real implementation\n * rather than a copy of it; not part of the package's public API.\n */\nexport function radialBarChartSegmentFill(\n kind: RadialBarChartSegment['kind'],\n colorName: string | number\n): string {\n if (kind === 'gap') return 'transparent';\n // The unreached remainder plays the part `showBackground`'s track plays on a\n // continuous arc, so it takes the same muted surface.\n return kind === 'track'\n ? 'var(--ui-border-on-status-neutral)'\n : `var(--color-${colorName})`;\n}\n\n/**\n * What a segmented gauge's tooltip reads. Exported for unit tests; not part of\n * the package's public API.\n *\n * A segmented ring's series are pieces of geometry, so recharts would offer the\n * hovered piece's own name and length (\"seg-3-value\", 41.2°). Hovering anywhere\n * on the ring should read the metric instead, so the reading is rebuilt from the\n * data row.\n */\nexport function radialBarChartSegmentedReading(options: {\n config: ChartConfig;\n row: RadialBarChartDatum;\n nameKey: string;\n dataKey: string;\n /** The `valueDomain` maximum, when the gauge has one. */\n domainMax?: number;\n}): { colorName: string; label: React.ReactNode; valueText: string } {\n const { config, row, nameKey, dataKey, domainMax } = options;\n const colorName = String(row[nameKey]);\n const value = row[dataKey];\n const valueText =\n typeof value === 'number' ? value.toLocaleString() : String(value ?? '');\n return {\n colorName,\n label: config[colorName]?.label ?? colorName,\n // The gauge's scale is the other half of the reading, so a known maximum\n // comes along: \"29 / 38\", not a bare \"29\".\n valueText:\n domainMax == null\n ? valueText\n : `${valueText} / ${domainMax.toLocaleString()}`,\n };\n}\n\n/**\n * The tooltip a segmented gauge shows — the same swatch/name/value layout the\n * default `ChartTooltipContent` row uses, dot included, over the reading from\n * `radialBarChartSegmentedReading`. Exported for the forced-open\n * visual-regression story; not part of the package's public API.\n *\n * `payload` is trimmed to one row: a radial tooltip is axis-shared and collects a\n * row from every series — two dozen identical rows for one metric.\n * (`tooltipType=\"none\"` only tags them, and scoping the tooltip to the hovered\n * item instead would drop it in the corner — unlike Pie/Bar sectors, a RadialBar\n * sector carries no tooltip coordinate.)\n *\n * A real component rather than a closure so it can be handed to `ChartTooltip`\n * as an *element*: recharts `cloneElement`s an element but `createElement`s a\n * function, and a closure rebuilt each render is a new element *type* — which\n * remounts the tooltip on every parent render instead of updating it.\n */\nexport function RadialBarChartSegmentedTooltipContent({\n active,\n payload,\n ...reading\n}: {\n active?: boolean;\n // Loosely typed on purpose: recharts' own payload generics are wider than the\n // shared `ChartTooltipContentProps` accepts, and only the row count matters.\n payload?: readonly unknown[];\n config: ChartConfig;\n row: RadialBarChartDatum;\n nameKey: string;\n dataKey: string;\n domainMax?: number;\n}) {\n const { colorName, label, valueText } =\n radialBarChartSegmentedReading(reading);\n\n return (\n <ChartTooltipContent\n active={active}\n payload={payload?.slice(0, 1) as ChartTooltipContentProps['payload']}\n hideLabel\n formatter={() => (\n <>\n <div\n className=\"h-2.5 w-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: `var(--color-${colorName})` }}\n />\n <div className=\"flex flex-1 items-center justify-between gap-2 leading-none\">\n <span className=\"text-muted-foreground\">{label}</span>\n <span className=\"font-medium tabular-nums text-foreground\">\n {valueText}\n </span>\n </div>\n </>\n )}\n />\n );\n}\n\n/**\n * The band a multi-metric tooltip's header names. Exported for unit tests; not\n * part of the package's public API.\n *\n * Each tooltip row is one metric, so the header names the band the hovered arc\n * belongs to. recharts' own label is the radius-axis index, which reads as a\n * bare number.\n */\nexport function radialBarChartBandName(\n row: RadialBarChartDatum | undefined,\n nameKey: string\n): string {\n const name = row?.[nameKey];\n return name == null ? '' : String(name);\n}\n\n/**\n * What an arc's data label calls the arc: the row's own `nameKey` value, or — in\n * multi-metric mode, where one arc *is* one metric — that metric's `config` label.\n */\nfunction radialBarChartArcName(options: {\n key: string;\n row: RadialBarChartDatum | undefined;\n isMultiMetric: boolean;\n nameKey: string;\n config: ChartConfig;\n}): string | number | undefined {\n const { key, row, isMultiMetric, nameKey, config } = options;\n if (!isMultiMetric) return row?.[nameKey];\n // ChartConfig labels are ReactNode; only a plain string/number can go into an\n // SVG <text>.\n const label = config[key]?.label;\n return typeof label === 'string' || typeof label === 'number' ? label : key;\n}\n\n/**\n * The default mapping's arcs: one `RadialBar` per series — one for the single\n * `dataKey`, or one per `dataKeys` entry in multi-metric mode — drawn\n * concentrically.\n *\n * recharts collects its graphical items from the store (each `RadialBar`\n * registers itself on render) rather than by scanning the chart's children for\n * their types, so grouping them inside a component of our own is invisible to it.\n * The `Cell`s stay direct children of their `RadialBar`, which *does* read its own\n * children by type.\n */\nfunction RadialBarChartSeries({\n seriesKeys,\n seriesData,\n isMultiMetric,\n config,\n nameKey,\n showBackground,\n cornerRadius,\n minPointSize,\n animation,\n centerLabel,\n showLabels,\n labelPosition,\n labelFormat,\n labelFormatter,\n}: {\n seriesKeys: string[];\n seriesData: RadialBarChartDatum[];\n isMultiMetric: boolean;\n config: ChartConfig;\n nameKey: string;\n showBackground: boolean;\n cornerRadius: number;\n minPointSize: number | undefined;\n animation: ResolvedAnimation;\n centerLabel: RadialBarChartCenterLabel | undefined;\n showLabels: boolean;\n labelPosition: PolarLabelPosition;\n labelFormat: RadialBarChartLabelFormat;\n labelFormatter?: TickFormatter;\n}) {\n return seriesKeys.map((key, seriesIndex) => (\n <RadialBar\n key={key}\n dataKey={key}\n fill={isMultiMetric ? `var(--color-${key})` : undefined}\n background={showBackground ? { fill: 'var(--ui-border-on-status-neutral)' } : false}\n cornerRadius={cornerRadius}\n minPointSize={minPointSize}\n {...animation}\n >\n {!isMultiMetric &&\n seriesData.map((entry, index) => (\n // Keyed by index, not the name: two arcs could share a nameKey\n // value, which would collide as a React key. Same-named arcs\n // intentionally share a color/config entry via `--color-<name>`.\n <Cell key={index} fill={`var(--color-${entry[nameKey]})`} />\n ))}\n {seriesIndex === 0 && centerLabel && (\n <RadialBarChartCenterLabelContent centerLabel={centerLabel} />\n )}\n {showLabels && (\n <LabelList\n // `valueAccessor` rather than `dataKey`: the label text can\n // carry the arc's name, which only the whole row (single\n // metric) or the metric's config entry can supply. recharts\n // ignores the accessor when a dataKey is set, so the two\n // can't be combined.\n valueAccessor={(entry) =>\n radialBarChartLabelText({\n format: labelFormat,\n name: radialBarChartArcName({\n key,\n row: entry.payload as RadialBarChartDatum | undefined,\n isMultiMetric,\n nameKey,\n config,\n }),\n value: entry.value as string | number | undefined,\n formatter: labelFormatter,\n })\n }\n position={labelPosition}\n className={resolveLabelFillClass(labelPosition)}\n fontSize={CHART_LABEL_FONT_SIZE}\n />\n )}\n </RadialBar>\n ));\n}\n\n/**\n * A segmented gauge's ring: the pieces from `radialBarChartSegments` as one stack\n * of synthetic series, so they lay out sequentially around the ring instead of\n * concentrically and the `gap` pieces read as notches.\n */\nfunction RadialBarChartSegmentedSeries({\n ringSegments,\n row,\n nameKey,\n cornerRadius,\n animation,\n centerLabel,\n}: {\n ringSegments: RadialBarChartSegment[];\n row: RadialBarChartDatum;\n nameKey: string;\n cornerRadius: number;\n animation: ResolvedAnimation;\n centerLabel: RadialBarChartCenterLabel | undefined;\n}) {\n return ringSegments.map((segment, index) => (\n <RadialBar\n key={segment.key}\n dataKey={segment.key}\n stackId=\"segments\"\n // The metric's name, so the hover has a row to key off at all\n // (`ChartTooltipContent` keys its row off `name`).\n name={String(row[nameKey])}\n fill={radialBarChartSegmentFill(segment.kind, row[nameKey])}\n cornerRadius={cornerRadius}\n {...animation}\n >\n {index === 0 && centerLabel && (\n <RadialBarChartCenterLabelContent centerLabel={centerLabel} />\n )}\n </RadialBar>\n ));\n}\n\nexport interface RadialBarChartProps\n extends\n Omit<React.ComponentProps<'div'>, 'children'>,\n ChartAnimationProps,\n ChartDataLabelProps {\n /**\n * The dataviz palette this chart's series are painted from. Series that\n * state no `color` of their own take a stop of it. See `ChartPalette`.\n */\n palette?: ChartPalette;\n /** Row-per-arc data. Each object holds the arc's `nameKey` label + its `dataKey` numeric value. */\n data: ReadonlyArray<RadialBarChartDatum>;\n /**\n * Per-arc map of `label` / `icon` / `tone`, keyed by the arc's `nameKey` value\n * — or, in multi-metric mode, by each `dataKeys` entry (imported from the\n * shared `Chart` primitives). Turned into `--color-<name>` custom properties.\n * Series take their colour from the container's `palette`; each entry maps a\n * key to a `label` and an optional `tone`.\n */\n config: ChartConfig;\n /** Numeric field that sizes each arc. Ignored when `dataKeys` is set. */\n dataKey: string;\n /**\n * Plot several metrics instead of one arc per row: one arc per key, colored and\n * named from `config` keyed by the **key** (not by `nameKey`) — the same\n * convention as the cartesian charts. Every metric shares one angular scale, so\n * pair it with `valueDomain` when the metrics are measured against a known\n * maximum. `nameKey` still names the band each metric's arc sits in.\n */\n dataKeys?: string[];\n /**\n * Label field that names each arc (drives the legend, tooltip, and\n * `--color-<name>` lookup). Values should be unique per chart (arcs sharing a\n * name share one `config`/color entry) and CSS-safe — they become part of a\n * custom-property name. In multi-metric mode it names the band rather than the\n * arc, so the legend and colors come from `dataKeys` instead.\n */\n nameKey: string;\n /** Inner radius of the innermost arc. */\n innerRadius?: number;\n /** Outer radius of the outermost arc. */\n outerRadius?: number;\n /** Angle (degrees) the arcs sweep from. */\n startAngle?: number;\n /** Angle (degrees) the arcs sweep to (default is a full clockwise circle). */\n endAngle?: number;\n /**\n * The value range the sweep represents, as `[min, max]`. Without it every arc\n * is drawn relative to the largest value in the data — so a **single** value\n * always fills the whole sweep, which is never what a gauge means. Set it to\n * the metric's own scale (e.g. `[0, 100]` for a percentage) and each arc\n * becomes that fraction of the sweep, over the `showBackground` track.\n */\n valueDomain?: [number, number];\n /** Corner radius on each arc's ends. */\n cornerRadius?: number;\n /**\n * Horizontal center of the arcs, in px or a percentage of the width.\n * Defaults to the middle (`50%`).\n */\n cx?: number | string;\n /**\n * Vertical center of the arcs, in px or a percentage of the height. Defaults to\n * the middle (`50%`) — worth moving for a half-circle gauge, whose drawn half\n * otherwise sits in the upper half of the surface.\n */\n cy?: number | string;\n /** Thickness of each arc, in px. Omit to let the radii and the gaps size it. */\n barSize?: number;\n /** Gap between the arcs of different metrics in one band, in px. */\n barGap?: number | string;\n /** Gap between bands, in px or a percentage string. */\n barCategoryGap?: number | string;\n /**\n * Smallest angle a non-zero arc may occupy, in degrees, so a tiny value stays\n * visible (and hoverable). recharts applies the floor to a `0` as well, which\n * reads as a small positive value — leave this unset when a metric can\n * legitimately be zero.\n */\n minAngle?: number;\n /** Plot-area margin, in px. Omit to use recharts' default (5 on every side). */\n margin?: { top?: number; right?: number; bottom?: number; left?: number };\n /**\n * Draw the gauge's ring as this many equal segments, notched apart — the\n * segmented-gauge look. Applies to a **single-value gauge** only and needs\n * `valueDomain` to know what a full ring means. Anything that isn't one — more\n * than one row, `dataKeys` set, fewer than two segments, or a `dataKey` value\n * that isn't a number (a stringified `\"29\"` off an API) — falls back to the\n * normal concentric arcs, legend included, rather than erroring.\n *\n * The ring is then synthetic geometry rather than data rows, so the arc labels\n * and the legend are suppressed: put the readout in `centerLabel`. The tooltip\n * stays, and reads the metric (with the `valueDomain` maximum when there is\n * one) wherever on the ring it is hovered. `showBackground` is redundant too —\n * the unreached segments *are* the track.\n */\n segments?: number;\n /** Gap between a segmented gauge's segments, in degrees. Defaults to `3`. */\n segmentGap?: number;\n /** Render a muted background track behind each arc. */\n showBackground?: boolean;\n /** Draw the concentric polar grid behind the arcs. */\n showPolarGrid?: boolean;\n /**\n * Custom content for the hole at the center — a headline `value` and/or a\n * `label` caption, stacked and centered. Needs an `innerRadius` big enough to\n * hold the text; it is not clipped to the hole.\n */\n centerLabel?: RadialBarChartCenterLabel;\n showTooltip?: boolean;\n showLegend?: boolean;\n /**\n * Format each arc's value in the list legend. In single-metric mode each arc\n * row gets its formatted value next to its label; in multi-metric mode values\n * are per-row (not per-series) so this is ignored.\n */\n legendValueFormatter?: (value: string | number) => string;\n /**\n * Replace the default tooltip. Pass a configured `ChartTooltipContent`\n * (imported from this library) — e.g. with a `formatter` / `labelFormatter` —\n * to customize formatting, per-arc rows, or extra fields without composing\n * recharts yourself. Ignored when `showTooltip` is false.\n *\n * On a segmented gauge it takes over from the built-in reading, and the payload\n * it receives is the ring's synthetic pieces (`seg-2-track`, a length in\n * degrees) rather than data rows — read the metric off `payload[0].payload`.\n */\n tooltipContent?: React.ComponentProps<typeof ChartTooltip>['content'];\n /**\n * Position of the value labels when `showLabels` is on. Defaults to\n * `insideStart` — the labels sit inside each arc, and therefore render in the\n * on-fill label token so they stay legible over the arc colour.\n */\n labelPosition?: PolarLabelPosition;\n /**\n * What each data label reads when `showLabels` is on — the value alone (the\n * default), or the arc's name and its value. The name is the row's `nameKey`\n * value, or the metric's `config` label in multi-metric mode.\n */\n labelFormat?: RadialBarChartLabelFormat;\n}\n\nconst RadialBarChart = React.forwardRef<HTMLDivElement, RadialBarChartProps>(\n (\n {\n className,\n config,\n palette,\n data,\n dataKey,\n dataKeys,\n nameKey,\n innerRadius = 20,\n outerRadius = 60,\n startAngle = 90,\n endAngle = -270,\n valueDomain,\n cornerRadius = 4,\n cx,\n cy,\n barSize,\n barGap,\n barCategoryGap,\n minAngle,\n margin,\n segments,\n segmentGap = SEGMENT_GAP,\n showBackground = true,\n showPolarGrid = false,\n centerLabel,\n showTooltip = true,\n showLegend = true,\n legendValueFormatter,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n showLabels = false,\n labelPosition,\n labelFormat = 'value',\n labelFormatter,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n const arcLabelPosition = labelPosition ?? 'insideStart';\n const isMultiMetric = !!dataKeys?.length;\n // A segmented ring is one metric cut into pieces, so it only means anything\n // for a single-row, single-metric chart.\n const isSegmented =\n segments != null &&\n segments > 1 &&\n !isMultiMetric &&\n data.length === 1 &&\n typeof data[0][dataKey] === 'number';\n const seriesKeys = isMultiMetric ? dataKeys! : [dataKey];\n // Stable across renders so the memoized legend content below keeps its\n // identity; `seriesKeys` itself is a fresh array every render.\n const legendKeys = React.useMemo(\n () => (dataKeys?.length ? dataKeys : [dataKey]),\n [dataKeys, dataKey]\n );\n const sweep = Math.abs(endAngle - startAngle);\n const ringSegments = isSegmented\n ? radialBarChartSegments({\n value: data[0][dataKey] as number,\n // Without a domain a lone value is its own maximum, so the ring fills.\n domain: valueDomain ?? [0, data[0][dataKey] as number],\n segments: segments!,\n gap: segmentGap,\n sweep,\n closed: sweep >= 360,\n })\n : [];\n\n // Stamp each row with its `fill` (the shadcn data-driven pattern) so a real\n // hover resolves the arc color in the tooltip — recharts' RadialBar, like\n // Funnel, carries no per-arc color on the tooltip payload item. Only in\n // single-metric mode: with one color per *metric*, a row-level fill would\n // paint every tooltip swatch the same.\n const seriesData: RadialBarChartDatum[] = isMultiMetric\n ? (data as RadialBarChartDatum[])\n : data.map((row) => ({\n ...row,\n fill: `var(--color-${row[nameKey]})`,\n }));\n\n // Each piece of the ring becomes a synthetic series on the one row, measured\n // in degrees — see `radialBarChartSegments`. Built from the raw row, *not*\n // from `seriesData`: a row-level `fill` wins over a series' own `fill` in\n // recharts, which would paint the track and the notches the arc's color.\n const plotData: RadialBarChartDatum[] = isSegmented\n ? [\n {\n ...data[0],\n ...Object.fromEntries(ringSegments.map((s) => [s.key, s.degrees])),\n },\n ]\n : seriesData;\n\n // recharts measures the radial floor in degrees, then extends the arc by\n // `mathSign(deltaAngle || minPointSize)`, where `deltaAngle` is the *arc's*\n // own angular length (RadialBar.js). So for a non-zero arc the floor already\n // grows along the arc's direction whatever sign it carries; the sign only\n // decides which way an arc of exactly zero degrees grows. Carry the sweep's\n // sign so that one grows forwards on a counter-clockwise chart too.\n const minPointSize =\n minAngle === undefined\n ? undefined\n : endAngle < startAngle\n ? -minAngle\n : minAngle;\n\n // Resolve colors so the external list legend has the same values as the chart\n // plot without needing to be inside ChartContainer's context.\n const resolvedConfigForLegend = React.useMemo(\n () => (showLegend ? resolveChartColors(config, palette ?? CHART_DEFAULT_PALETTE) : null),\n [showLegend, config, palette]\n );\n const rightLegendPayload: LegendPayload[] = React.useMemo(() => {\n if (!resolvedConfigForLegend) return [];\n if (isMultiMetric) {\n // Multi-metric: one entry per dataKey. No per-series row value is\n // meaningful (each metric spans multiple rows), so values are omitted.\n return legendKeys.map((key) => ({\n value: key,\n dataKey: key,\n color: resolvedConfigForLegend[key]?.color ?? `var(--color-${key})`,\n type: 'rect' as const,\n payload: {} as Record<string, unknown>,\n }));\n }\n // Single-metric: one entry per data row.\n return data.map((row) => ({\n value: String(row[nameKey]),\n dataKey: nameKey,\n color:\n resolvedConfigForLegend[String(row[nameKey])]?.color ??\n `var(--color-${String(row[nameKey])})`,\n type: 'rect' as const,\n payload: row as Record<string, unknown>,\n }));\n }, [resolvedConfigForLegend, isMultiMetric, legendKeys, data, nameKey]);\n\n const hasLegend = showLegend && !isSegmented && !!resolvedConfigForLegend;\n\n // The built-in tooltip reading, which each mapping composes differently: a\n // segmented ring rebuilds it from the data row, multi-metric renames the\n // header after the band, and the default mapping reads the hovered arc.\n const getDefaultTooltipContent = () => {\n if (isSegmented) {\n return (\n <RadialBarChartSegmentedTooltipContent\n config={config}\n row={data[0]}\n nameKey={nameKey}\n dataKey={dataKey}\n domainMax={valueDomain?.[1]}\n />\n );\n }\n\n if (isMultiMetric) {\n return (\n <ChartTooltipContent\n labelFormatter={(_, payload) =>\n radialBarChartBandName(\n payload?.[0]?.payload as RadialBarChartDatum | undefined,\n nameKey\n )\n }\n />\n );\n }\n\n return <ChartTooltipContent nameKey={nameKey} hideLabel />;\n };\n\n // Shared recharts chart composition (used in both layout modes).\n const radialChartContent = (\n <RechartsRadialBarChart\n data={plotData}\n // Only meaningful for the single-metric mapping; in multi-metric and\n // segmented mode each <RadialBar> carries its own key and the scale\n // spans them all.\n dataKey={isMultiMetric || isSegmented ? undefined : dataKey}\n cx={cx}\n cy={cy}\n innerRadius={innerRadius}\n outerRadius={outerRadius}\n startAngle={startAngle}\n endAngle={endAngle}\n barSize={barSize}\n barGap={barGap}\n barCategoryGap={barCategoryGap}\n margin={margin ?? { top: 0, right: 0, bottom: 0, left: 0 }}\n >\n {showPolarGrid && (\n <PolarGrid gridType=\"circle\" radialLines={false} />\n )}\n {(valueDomain || isSegmented) && (\n // The angular scale itself, not chrome: it maps a value onto a\n // fraction of the sweep. Ticks/axis line stay off — the arcs and\n // the optional center readout are the readout. A segmented ring is\n // already measured in degrees, so its scale *is* the sweep.\n <PolarAngleAxis\n type=\"number\"\n domain={isSegmented ? [0, sweep] : valueDomain}\n tick={false}\n axisLine={false}\n />\n )}\n {showTooltip && (\n <ChartTooltip\n // The hover cursor marks which band of the angular axis is\n // active, which on a segmented ring is one metric either way —\n // it just draws a hairline across the gauge.\n cursor={isSegmented ? false : undefined}\n content={tooltipContent ?? getDefaultTooltipContent()}\n />\n )}\n {isSegmented ? (\n <RadialBarChartSegmentedSeries\n ringSegments={ringSegments}\n row={data[0]}\n nameKey={nameKey}\n cornerRadius={cornerRadius}\n animation={animation}\n centerLabel={centerLabel}\n />\n ) : (\n <RadialBarChartSeries\n seriesKeys={seriesKeys}\n seriesData={seriesData}\n isMultiMetric={isMultiMetric}\n config={config}\n nameKey={nameKey}\n showBackground={showBackground}\n cornerRadius={cornerRadius}\n minPointSize={minPointSize}\n animation={animation}\n centerLabel={centerLabel}\n showLabels={showLabels}\n labelPosition={arcLabelPosition}\n labelFormat={labelFormat}\n labelFormatter={labelFormatter}\n />\n )}\n </RechartsRadialBarChart>\n );\n\n const chartDivSize =\n showLabels && (arcLabelPosition === 'outside' || arcLabelPosition === 'end')\n ? 'size-[200px]'\n : 'size-[120px]';\n\n return (\n <div\n ref={ref}\n className={cn('flex flex-row items-center gap-4', !hasLegend && 'justify-center', className)}\n {...props}\n >\n <div className={cn(chartDivSize, 'shrink-0')}>\n <ChartContainer config={config} palette={palette} className=\"size-full\">\n {radialChartContent}\n </ChartContainer>\n </div>\n {showLegend && !isSegmented && resolvedConfigForLegend && (\n <ChartLegendContent\n variant=\"list\"\n payload={rightLegendPayload}\n config={resolvedConfigForLegend}\n nameKey={isMultiMetric ? undefined : nameKey}\n valueKey={isMultiMetric ? undefined : dataKey}\n valueFormatter={isMultiMetric ? undefined : legendValueFormatter}\n className=\"min-w-0 flex-1\"\n />\n )}\n </div>\n );\n }\n);\nRadialBarChart.displayName = 'RadialBarChart';\n\nexport { RadialBarChart };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"radial-bar-chart.js","names":[],"sources":["../../../../src/components/ui/radial-bar-chart/radial-bar-chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n Cell,\n Label,\n LabelList,\n PolarAngleAxis,\n PolarGrid,\n RadialBar,\n RadialBarChart as RechartsRadialBarChart,\n} from 'recharts';\n\nimport type { LegendPayload } from 'recharts/types/component/DefaultLegendContent';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n resolveChartColors,\n resolveLabelFillClass,\n CHART_DEFAULT_PALETTE,\n CHART_LABEL_FONT_SIZE,\n type ChartConfig,\n type ChartPalette,\n type ChartAnimationProps,\n type ChartDataLabelProps,\n type ChartTooltipContentProps,\n type PolarLabelPosition,\n toCssKey,\n type ResolvedAnimation,\n type TickFormatter,\n} from '../chart';\n\n// A typed recharts composition over the shared `Chart` primitives (a polar/radial\n// type). Rows become concentric arcs sized by `dataKey`, each colored from its\n// `--color-<name>` var; `dataKeys` switches to one arc per metric instead. Like\n// ScatterChart/ComposedChart there's no CVA variant: a radial bar's\n// expressiveness is geometry (angles/radii, plain props) and the data mapping,\n// not a visual \"mode\". The angular sweep is exposed as startAngle/endAngle props\n// so a caller can build a gauge or a full ring.\n\n/** Row-per-arc datum: the `nameKey` label plus each metric's numeric value. */\ntype RadialBarChartDatum = Record<string, string | number>;\n\n/** What an arc's data label reads. */\nexport type RadialBarChartLabelFormat = 'value' | 'name-value';\n\nexport interface RadialBarChartCenterLabel {\n // Rendered as SVG <text>, which only lays out text — hence string | number,\n // not ReactNode.\n /** Headline metric rendered large in the hole (e.g. the gauge's value). */\n value?: string | number;\n /** Caption rendered under the value. */\n label?: string | number;\n}\n\n/**\n * The readout in the hole at the centre of the arcs — a headline value over a\n * caption. Rendered as a recharts `<Label>`, which is what supplies the polar\n * viewBox the text centres itself on.\n *\n * There is one readout for the whole chart, so it hangs off the first series\n * drawn — every series shares the same viewBox.\n */\nfunction RadialBarChartCenterLabelContent({\n centerLabel,\n}: {\n centerLabel: RadialBarChartCenterLabel;\n}) {\n return (\n <Label\n content={({ viewBox }) => {\n if (!viewBox || !('cx' in viewBox)) return null;\n const { cx: centerX = 0, cy: centerY = 0 } = viewBox as {\n cx?: number;\n cy?: number;\n };\n const hasValue = centerLabel.value != null;\n const hasLabel = centerLabel.label != null;\n // Straddle the centre when both lines show, so the value + label block\n // is centered as a whole (not just the value).\n const both = hasValue && hasLabel;\n return (\n <g>\n {hasValue && (\n <text\n x={centerX}\n y={both ? centerY - 10 : centerY}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"fill-foreground text-2xl font-semibold\"\n >\n {centerLabel.value}\n </text>\n )}\n {hasLabel && (\n <text\n x={centerX}\n y={both ? centerY + 13 : centerY}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className=\"fill-muted-foreground text-sm\"\n >\n {centerLabel.label}\n </text>\n )}\n </g>\n );\n }}\n />\n );\n}\n\n/**\n * Compose one arc's data-label text. Exported for unit tests; not part of the\n * package's public API.\n *\n * `labelFormatter` only ever formats the numeric part, so a chart's labels and\n * its tooltip stay in the same units under either format. A nullish value yields\n * an empty label, which recharts renders as no `<text>` at all.\n */\nexport function radialBarChartLabelText(options: {\n format: RadialBarChartLabelFormat;\n name: string | number | undefined;\n value: string | number | undefined;\n formatter?: TickFormatter;\n}): string {\n const { format, name, value, formatter } = options;\n if (value == null) return '';\n const valueText = formatter ? formatter(value) : String(value);\n return format === 'name-value' && name != null\n ? `${name}: ${valueText}`\n : valueText;\n}\n\n/** One piece of a segmented gauge's ring: a length in degrees and what it is. */\nexport interface RadialBarChartSegment {\n /** Synthetic series key — stable for a given (index, kind). */\n key: string;\n /** Angular length of the piece, in degrees. */\n degrees: number;\n /** `value` is the metric, `track` the unreached remainder, `gap` the notch. */\n kind: 'value' | 'track' | 'gap';\n}\n\n/** Fallback gap between a segmented gauge's segments, in degrees. */\nconst SEGMENT_GAP = 3;\n\n/**\n * Cut a gauge's sweep into equal segments separated by gaps, and split the\n * segment the value ends inside into its reached and unreached parts. Exported\n * for unit tests; not part of the package's public API.\n *\n * Lengths come back in **degrees**, which is what lets the ring be built as one\n * stack of synthetic series over a `[0, sweep]` angular scale: recharts lays\n * stacked radial bars out sequentially along the angle, so a transparent series\n * between two colored ones reads as a real notch in the ring. A `gap` that\n * would leave no room for the segments themselves is clamped.\n */\nexport function radialBarChartSegments(options: {\n value: number;\n domain: [number, number];\n segments: number;\n gap: number;\n /** Absolute sweep of the chart, in degrees. */\n sweep: number;\n /** A full-circle sweep also needs a gap between the last segment and the first. */\n closed: boolean;\n}): RadialBarChartSegment[] {\n const { value, domain, segments, sweep, closed } = options;\n const gapCount = closed ? segments : segments - 1;\n // Leave at least half the sweep for the segments, however wide a gap is asked\n // for — an all-gap ring would render as nothing at all. A negative gap would\n // stretch the pieces past the sweep and overlap them, so it floors at zero.\n const gap =\n gapCount > 0\n ? Math.min(Math.max(options.gap, 0), sweep / (2 * gapCount))\n : 0;\n const segmentDegrees = (sweep - gap * gapCount) / segments;\n const [min, max] = domain;\n const span = max - min;\n // A domain with no span (`[n, n]`) or an inverted one (`[max, min]`) cannot\n // place a value on the ring at all, so there is no fraction to draw and the\n // ring stays empty. It deliberately does not fall back to comparing the value\n // against zero: that reported a *full* ring for `{ value: 5, domain: [100,\n // 100] }`, i.e. claimed completion the data never supported. For a gauge,\n // under-reading a domain that says nothing is the safe direction.\n const fraction =\n span > 0 ? Math.min(Math.max((value - min) / span, 0), 1) : 0;\n // The value maps onto the *drawn* ring, so the gaps never eat into it.\n let remainingValue = fraction * segmentDegrees * segments;\n\n const pieces: RadialBarChartSegment[] = [];\n for (let index = 0; index < segments; index++) {\n const reached = Math.min(Math.max(remainingValue, 0), segmentDegrees);\n remainingValue -= reached;\n // Both halves are always emitted, including at zero length: a stable key set\n // keeps recharts' series identities steady as the value changes.\n pieces.push({ key: `seg-${index}-value`, degrees: reached, kind: 'value' });\n pieces.push({\n key: `seg-${index}-track`,\n degrees: segmentDegrees - reached,\n kind: 'track',\n });\n if (gap > 0 && (closed || index < segments - 1)) {\n pieces.push({ key: `seg-${index}-gap`, degrees: gap, kind: 'gap' });\n }\n }\n return pieces;\n}\n\n/**\n * Fill for one piece of a segmented gauge's ring. Exported for unit tests and so\n * the forced-open tooltip story can build a ring from the real implementation\n * rather than a copy of it; not part of the package's public API.\n */\nexport function radialBarChartSegmentFill(\n kind: RadialBarChartSegment['kind'],\n colorName: string | number\n): string {\n if (kind === 'gap') return 'transparent';\n // The unreached remainder plays the part `showBackground`'s track plays on a\n // continuous arc, so it takes the same muted surface.\n return kind === 'track'\n ? 'var(--ui-border-on-status-neutral)'\n : `var(--color-${toCssKey(String(colorName))})`;\n}\n\n/**\n * What a segmented gauge's tooltip reads. Exported for unit tests; not part of\n * the package's public API.\n *\n * A segmented ring's series are pieces of geometry, so recharts would offer the\n * hovered piece's own name and length (\"seg-3-value\", 41.2°). Hovering anywhere\n * on the ring should read the metric instead, so the reading is rebuilt from the\n * data row.\n */\nexport function radialBarChartSegmentedReading(options: {\n config: ChartConfig;\n row: RadialBarChartDatum;\n nameKey: string;\n dataKey: string;\n /** The `valueDomain` maximum, when the gauge has one. */\n domainMax?: number;\n}): { colorName: string; label: React.ReactNode; valueText: string } {\n const { config, row, nameKey, dataKey, domainMax } = options;\n const colorName = String(row[nameKey]);\n const value = row[dataKey];\n const valueText =\n typeof value === 'number' ? value.toLocaleString() : String(value ?? '');\n return {\n colorName,\n label: config[colorName]?.label ?? colorName,\n // The gauge's scale is the other half of the reading, so a known maximum\n // comes along: \"29 / 38\", not a bare \"29\".\n valueText:\n domainMax == null\n ? valueText\n : `${valueText} / ${domainMax.toLocaleString()}`,\n };\n}\n\n/**\n * The tooltip a segmented gauge shows — the same swatch/name/value layout the\n * default `ChartTooltipContent` row uses, dot included, over the reading from\n * `radialBarChartSegmentedReading`. Exported for the forced-open\n * visual-regression story; not part of the package's public API.\n *\n * `payload` is trimmed to one row: a radial tooltip is axis-shared and collects a\n * row from every series — two dozen identical rows for one metric.\n * (`tooltipType=\"none\"` only tags them, and scoping the tooltip to the hovered\n * item instead would drop it in the corner — unlike Pie/Bar sectors, a RadialBar\n * sector carries no tooltip coordinate.)\n *\n * A real component rather than a closure so it can be handed to `ChartTooltip`\n * as an *element*: recharts `cloneElement`s an element but `createElement`s a\n * function, and a closure rebuilt each render is a new element *type* — which\n * remounts the tooltip on every parent render instead of updating it.\n */\nexport function RadialBarChartSegmentedTooltipContent({\n active,\n payload,\n ...reading\n}: {\n active?: boolean;\n // Loosely typed on purpose: recharts' own payload generics are wider than the\n // shared `ChartTooltipContentProps` accepts, and only the row count matters.\n payload?: readonly unknown[];\n config: ChartConfig;\n row: RadialBarChartDatum;\n nameKey: string;\n dataKey: string;\n domainMax?: number;\n}) {\n const { colorName, label, valueText } =\n radialBarChartSegmentedReading(reading);\n\n return (\n <ChartTooltipContent\n active={active}\n payload={payload?.slice(0, 1) as ChartTooltipContentProps['payload']}\n hideLabel\n formatter={() => (\n <>\n <div\n className=\"h-2.5 w-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: `var(--color-${toCssKey(colorName)})` }}\n />\n <div className=\"flex flex-1 items-center justify-between gap-2 leading-none\">\n <span className=\"text-muted-foreground\">{label}</span>\n <span className=\"font-medium tabular-nums text-foreground\">\n {valueText}\n </span>\n </div>\n </>\n )}\n />\n );\n}\n\n/**\n * The band a multi-metric tooltip's header names. Exported for unit tests; not\n * part of the package's public API.\n *\n * Each tooltip row is one metric, so the header names the band the hovered arc\n * belongs to. recharts' own label is the radius-axis index, which reads as a\n * bare number.\n */\nexport function radialBarChartBandName(\n row: RadialBarChartDatum | undefined,\n nameKey: string\n): string {\n const name = row?.[nameKey];\n return name == null ? '' : String(name);\n}\n\n/**\n * What an arc's data label calls the arc: the row's own `nameKey` value, or — in\n * multi-metric mode, where one arc *is* one metric — that metric's `config` label.\n */\nfunction radialBarChartArcName(options: {\n key: string;\n row: RadialBarChartDatum | undefined;\n isMultiMetric: boolean;\n nameKey: string;\n config: ChartConfig;\n}): string | number | undefined {\n const { key, row, isMultiMetric, nameKey, config } = options;\n if (!isMultiMetric) return row?.[nameKey];\n // ChartConfig labels are ReactNode; only a plain string/number can go into an\n // SVG <text>.\n const label = config[key]?.label;\n return typeof label === 'string' || typeof label === 'number' ? label : key;\n}\n\n/**\n * The default mapping's arcs: one `RadialBar` per series — one for the single\n * `dataKey`, or one per `dataKeys` entry in multi-metric mode — drawn\n * concentrically.\n *\n * recharts collects its graphical items from the store (each `RadialBar`\n * registers itself on render) rather than by scanning the chart's children for\n * their types, so grouping them inside a component of our own is invisible to it.\n * The `Cell`s stay direct children of their `RadialBar`, which *does* read its own\n * children by type.\n */\nfunction RadialBarChartSeries({\n seriesKeys,\n seriesData,\n isMultiMetric,\n config,\n nameKey,\n showBackground,\n cornerRadius,\n minPointSize,\n animation,\n centerLabel,\n showLabels,\n labelPosition,\n labelFormat,\n labelFormatter,\n}: {\n seriesKeys: string[];\n seriesData: RadialBarChartDatum[];\n isMultiMetric: boolean;\n config: ChartConfig;\n nameKey: string;\n showBackground: boolean;\n cornerRadius: number;\n minPointSize: number | undefined;\n animation: ResolvedAnimation;\n centerLabel: RadialBarChartCenterLabel | undefined;\n showLabels: boolean;\n labelPosition: PolarLabelPosition;\n labelFormat: RadialBarChartLabelFormat;\n labelFormatter?: TickFormatter;\n}) {\n return seriesKeys.map((key, seriesIndex) => (\n <RadialBar\n key={key}\n dataKey={key}\n fill={isMultiMetric ? `var(--color-${toCssKey(key)})` : undefined}\n background={showBackground ? { fill: 'var(--ui-border-on-status-neutral)' } : false}\n cornerRadius={cornerRadius}\n minPointSize={minPointSize}\n {...animation}\n >\n {!isMultiMetric &&\n seriesData.map((entry, index) => (\n // Keyed by index, not the name: two arcs could share a nameKey\n // value, which would collide as a React key. Same-named arcs\n // intentionally share a color/config entry via `--color-<name>`.\n <Cell key={index} fill={`var(--color-${toCssKey(String(entry[nameKey]))})`} />\n ))}\n {seriesIndex === 0 && centerLabel && (\n <RadialBarChartCenterLabelContent centerLabel={centerLabel} />\n )}\n {showLabels && (\n <LabelList\n // `valueAccessor` rather than `dataKey`: the label text can\n // carry the arc's name, which only the whole row (single\n // metric) or the metric's config entry can supply. recharts\n // ignores the accessor when a dataKey is set, so the two\n // can't be combined.\n valueAccessor={(entry) =>\n radialBarChartLabelText({\n format: labelFormat,\n name: radialBarChartArcName({\n key,\n row: entry.payload as RadialBarChartDatum | undefined,\n isMultiMetric,\n nameKey,\n config,\n }),\n value: entry.value as string | number | undefined,\n formatter: labelFormatter,\n })\n }\n position={labelPosition}\n className={resolveLabelFillClass(labelPosition)}\n fontSize={CHART_LABEL_FONT_SIZE}\n />\n )}\n </RadialBar>\n ));\n}\n\n/**\n * A segmented gauge's ring: the pieces from `radialBarChartSegments` as one stack\n * of synthetic series, so they lay out sequentially around the ring instead of\n * concentrically and the `gap` pieces read as notches.\n */\nfunction RadialBarChartSegmentedSeries({\n ringSegments,\n row,\n nameKey,\n cornerRadius,\n animation,\n centerLabel,\n}: {\n ringSegments: RadialBarChartSegment[];\n row: RadialBarChartDatum;\n nameKey: string;\n cornerRadius: number;\n animation: ResolvedAnimation;\n centerLabel: RadialBarChartCenterLabel | undefined;\n}) {\n return ringSegments.map((segment, index) => (\n <RadialBar\n key={segment.key}\n dataKey={segment.key}\n stackId=\"segments\"\n // The metric's name, so the hover has a row to key off at all\n // (`ChartTooltipContent` keys its row off `name`).\n name={String(row[nameKey])}\n fill={radialBarChartSegmentFill(segment.kind, row[nameKey])}\n cornerRadius={cornerRadius}\n {...animation}\n >\n {index === 0 && centerLabel && (\n <RadialBarChartCenterLabelContent centerLabel={centerLabel} />\n )}\n </RadialBar>\n ));\n}\n\nexport interface RadialBarChartProps\n extends\n Omit<React.ComponentProps<'div'>, 'children'>,\n ChartAnimationProps,\n ChartDataLabelProps {\n /**\n * The dataviz palette this chart's series are painted from. Series that\n * state no `color` of their own take a stop of it. See `ChartPalette`.\n */\n palette?: ChartPalette;\n /** Row-per-arc data. Each object holds the arc's `nameKey` label + its `dataKey` numeric value. */\n data: ReadonlyArray<RadialBarChartDatum>;\n /**\n * Per-arc map of `label` / `icon` / `tone`, keyed by the arc's `nameKey` value\n * — or, in multi-metric mode, by each `dataKeys` entry (imported from the\n * shared `Chart` primitives). Turned into `--color-<name>` custom properties.\n * Series take their colour from the container's `palette`; each entry maps a\n * key to a `label` and an optional `tone`.\n */\n config: ChartConfig;\n /** Numeric field that sizes each arc. Ignored when `dataKeys` is set. */\n dataKey: string;\n /**\n * Plot several metrics instead of one arc per row: one arc per key, colored and\n * named from `config` keyed by the **key** (not by `nameKey`) — the same\n * convention as the cartesian charts. Every metric shares one angular scale, so\n * pair it with `valueDomain` when the metrics are measured against a known\n * maximum. `nameKey` still names the band each metric's arc sits in.\n */\n dataKeys?: string[];\n /**\n * Label field that names each arc (drives the legend, tooltip, and\n * `--color-<name>` lookup). Values should be unique per chart (arcs sharing a\n * name share one `config`/color entry); they are sanitized automatically to a\n * valid CSS custom-property fragment (CSS-safe values are preferred to avoid\n * dev-mode warnings). In multi-metric mode it names the band rather than the\n * arc, so the legend and colors come from `dataKeys` instead.\n */\n nameKey: string;\n /** Inner radius of the innermost arc. */\n innerRadius?: number;\n /** Outer radius of the outermost arc. */\n outerRadius?: number;\n /** Angle (degrees) the arcs sweep from. */\n startAngle?: number;\n /** Angle (degrees) the arcs sweep to (default is a full clockwise circle). */\n endAngle?: number;\n /**\n * The value range the sweep represents, as `[min, max]`. Without it every arc\n * is drawn relative to the largest value in the data — so a **single** value\n * always fills the whole sweep, which is never what a gauge means. Set it to\n * the metric's own scale (e.g. `[0, 100]` for a percentage) and each arc\n * becomes that fraction of the sweep, over the `showBackground` track.\n */\n valueDomain?: [number, number];\n /** Corner radius on each arc's ends. */\n cornerRadius?: number;\n /**\n * Horizontal center of the arcs, in px or a percentage of the width.\n * Defaults to the middle (`50%`).\n */\n cx?: number | string;\n /**\n * Vertical center of the arcs, in px or a percentage of the height. Defaults to\n * the middle (`50%`) — worth moving for a half-circle gauge, whose drawn half\n * otherwise sits in the upper half of the surface.\n */\n cy?: number | string;\n /** Thickness of each arc, in px. Omit to let the radii and the gaps size it. */\n barSize?: number;\n /** Gap between the arcs of different metrics in one band, in px. */\n barGap?: number | string;\n /** Gap between bands, in px or a percentage string. */\n barCategoryGap?: number | string;\n /**\n * Smallest angle a non-zero arc may occupy, in degrees, so a tiny value stays\n * visible (and hoverable). recharts applies the floor to a `0` as well, which\n * reads as a small positive value — leave this unset when a metric can\n * legitimately be zero.\n */\n minAngle?: number;\n /** Plot-area margin, in px. Omit to use recharts' default (5 on every side). */\n margin?: { top?: number; right?: number; bottom?: number; left?: number };\n /**\n * Draw the gauge's ring as this many equal segments, notched apart — the\n * segmented-gauge look. Applies to a **single-value gauge** only and needs\n * `valueDomain` to know what a full ring means. Anything that isn't one — more\n * than one row, `dataKeys` set, fewer than two segments, or a `dataKey` value\n * that isn't a number (a stringified `\"29\"` off an API) — falls back to the\n * normal concentric arcs, legend included, rather than erroring.\n *\n * The ring is then synthetic geometry rather than data rows, so the arc labels\n * and the legend are suppressed: put the readout in `centerLabel`. The tooltip\n * stays, and reads the metric (with the `valueDomain` maximum when there is\n * one) wherever on the ring it is hovered. `showBackground` is redundant too —\n * the unreached segments *are* the track.\n */\n segments?: number;\n /** Gap between a segmented gauge's segments, in degrees. Defaults to `3`. */\n segmentGap?: number;\n /** Render a muted background track behind each arc. */\n showBackground?: boolean;\n /** Draw the concentric polar grid behind the arcs. */\n showPolarGrid?: boolean;\n /**\n * Custom content for the hole at the center — a headline `value` and/or a\n * `label` caption, stacked and centered. Needs an `innerRadius` big enough to\n * hold the text; it is not clipped to the hole.\n */\n centerLabel?: RadialBarChartCenterLabel;\n showTooltip?: boolean;\n showLegend?: boolean;\n /**\n * Format each arc's value in the list legend. In single-metric mode each arc\n * row gets its formatted value next to its label; in multi-metric mode values\n * are per-row (not per-series) so this is ignored.\n */\n legendValueFormatter?: (value: string | number) => string;\n /**\n * Replace the default tooltip. Pass a configured `ChartTooltipContent`\n * (imported from this library) — e.g. with a `formatter` / `labelFormatter` —\n * to customize formatting, per-arc rows, or extra fields without composing\n * recharts yourself. Ignored when `showTooltip` is false.\n *\n * On a segmented gauge it takes over from the built-in reading, and the payload\n * it receives is the ring's synthetic pieces (`seg-2-track`, a length in\n * degrees) rather than data rows — read the metric off `payload[0].payload`.\n */\n tooltipContent?: React.ComponentProps<typeof ChartTooltip>['content'];\n /**\n * Position of the value labels when `showLabels` is on. Defaults to\n * `insideStart` — the labels sit inside each arc, and therefore render in the\n * on-fill label token so they stay legible over the arc colour.\n */\n labelPosition?: PolarLabelPosition;\n /**\n * What each data label reads when `showLabels` is on — the value alone (the\n * default), or the arc's name and its value. The name is the row's `nameKey`\n * value, or the metric's `config` label in multi-metric mode.\n */\n labelFormat?: RadialBarChartLabelFormat;\n}\n\nconst RadialBarChart = React.forwardRef<HTMLDivElement, RadialBarChartProps>(\n (\n {\n className,\n config,\n palette,\n data,\n dataKey,\n dataKeys,\n nameKey,\n innerRadius = 20,\n outerRadius = 60,\n startAngle = 90,\n endAngle = -270,\n valueDomain,\n cornerRadius = 4,\n cx,\n cy,\n barSize,\n barGap,\n barCategoryGap,\n minAngle,\n margin,\n segments,\n segmentGap = SEGMENT_GAP,\n showBackground = true,\n showPolarGrid = false,\n centerLabel,\n showTooltip = true,\n showLegend = true,\n legendValueFormatter,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n showLabels = false,\n labelPosition,\n labelFormat = 'value',\n labelFormatter,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n const arcLabelPosition = labelPosition ?? 'insideStart';\n const isMultiMetric = !!dataKeys?.length;\n // A segmented ring is one metric cut into pieces, so it only means anything\n // for a single-row, single-metric chart.\n const isSegmented =\n segments != null &&\n segments > 1 &&\n !isMultiMetric &&\n data.length === 1 &&\n typeof data[0][dataKey] === 'number';\n const seriesKeys = isMultiMetric ? dataKeys! : [dataKey];\n // Stable across renders so the memoized legend content below keeps its\n // identity; `seriesKeys` itself is a fresh array every render.\n const legendKeys = React.useMemo(\n () => (dataKeys?.length ? dataKeys : [dataKey]),\n [dataKeys, dataKey]\n );\n const sweep = Math.abs(endAngle - startAngle);\n const ringSegments = isSegmented\n ? radialBarChartSegments({\n value: data[0][dataKey] as number,\n // Without a domain a lone value is its own maximum, so the ring fills.\n domain: valueDomain ?? [0, data[0][dataKey] as number],\n segments: segments!,\n gap: segmentGap,\n sweep,\n closed: sweep >= 360,\n })\n : [];\n\n // Stamp each row with its `fill` (the shadcn data-driven pattern) so a real\n // hover resolves the arc color in the tooltip — recharts' RadialBar, like\n // Funnel, carries no per-arc color on the tooltip payload item. Only in\n // single-metric mode: with one color per *metric*, a row-level fill would\n // paint every tooltip swatch the same.\n const seriesData: RadialBarChartDatum[] = isMultiMetric\n ? (data as RadialBarChartDatum[])\n : data.map((row) => ({\n ...row,\n fill: `var(--color-${toCssKey(String(row[nameKey]))})`,\n }));\n\n // Each piece of the ring becomes a synthetic series on the one row, measured\n // in degrees — see `radialBarChartSegments`. Built from the raw row, *not*\n // from `seriesData`: a row-level `fill` wins over a series' own `fill` in\n // recharts, which would paint the track and the notches the arc's color.\n const plotData: RadialBarChartDatum[] = isSegmented\n ? [\n {\n ...data[0],\n ...Object.fromEntries(ringSegments.map((s) => [s.key, s.degrees])),\n },\n ]\n : seriesData;\n\n // recharts measures the radial floor in degrees, then extends the arc by\n // `mathSign(deltaAngle || minPointSize)`, where `deltaAngle` is the *arc's*\n // own angular length (RadialBar.js). So for a non-zero arc the floor already\n // grows along the arc's direction whatever sign it carries; the sign only\n // decides which way an arc of exactly zero degrees grows. Carry the sweep's\n // sign so that one grows forwards on a counter-clockwise chart too.\n const minPointSize =\n minAngle === undefined\n ? undefined\n : endAngle < startAngle\n ? -minAngle\n : minAngle;\n\n // Resolve colors so the external list legend has the same values as the chart\n // plot without needing to be inside ChartContainer's context.\n const resolvedConfigForLegend = React.useMemo(\n () => (showLegend ? resolveChartColors(config, palette ?? CHART_DEFAULT_PALETTE) : null),\n [showLegend, config, palette]\n );\n const rightLegendPayload: LegendPayload[] = React.useMemo(() => {\n if (!resolvedConfigForLegend) return [];\n if (isMultiMetric) {\n // Multi-metric: one entry per dataKey. No per-series row value is\n // meaningful (each metric spans multiple rows), so values are omitted.\n return legendKeys.map((key) => ({\n value: key,\n dataKey: key,\n color: resolvedConfigForLegend[key]?.color ?? `var(--color-${toCssKey(key)})`,\n type: 'rect' as const,\n payload: {} as Record<string, unknown>,\n }));\n }\n // Single-metric: one entry per data row.\n return data.map((row) => ({\n value: String(row[nameKey]),\n dataKey: nameKey,\n color:\n resolvedConfigForLegend[String(row[nameKey])]?.color ??\n `var(--color-${toCssKey(String(row[nameKey]))})`,\n type: 'rect' as const,\n payload: row as Record<string, unknown>,\n }));\n }, [resolvedConfigForLegend, isMultiMetric, legendKeys, data, nameKey]);\n\n const hasLegend = showLegend && !isSegmented && !!resolvedConfigForLegend;\n\n // The built-in tooltip reading, which each mapping composes differently: a\n // segmented ring rebuilds it from the data row, multi-metric renames the\n // header after the band, and the default mapping reads the hovered arc.\n const getDefaultTooltipContent = () => {\n if (isSegmented) {\n return (\n <RadialBarChartSegmentedTooltipContent\n config={config}\n row={data[0]}\n nameKey={nameKey}\n dataKey={dataKey}\n domainMax={valueDomain?.[1]}\n />\n );\n }\n\n if (isMultiMetric) {\n return (\n <ChartTooltipContent\n labelFormatter={(_, payload) =>\n radialBarChartBandName(\n payload?.[0]?.payload as RadialBarChartDatum | undefined,\n nameKey\n )\n }\n />\n );\n }\n\n return <ChartTooltipContent nameKey={nameKey} hideLabel />;\n };\n\n // Shared recharts chart composition (used in both layout modes).\n const radialChartContent = (\n <RechartsRadialBarChart\n data={plotData}\n // Only meaningful for the single-metric mapping; in multi-metric and\n // segmented mode each <RadialBar> carries its own key and the scale\n // spans them all.\n dataKey={isMultiMetric || isSegmented ? undefined : dataKey}\n cx={cx}\n cy={cy}\n innerRadius={innerRadius}\n outerRadius={outerRadius}\n startAngle={startAngle}\n endAngle={endAngle}\n barSize={barSize}\n barGap={barGap}\n barCategoryGap={barCategoryGap}\n margin={margin ?? { top: 0, right: 0, bottom: 0, left: 0 }}\n >\n {showPolarGrid && (\n <PolarGrid gridType=\"circle\" radialLines={false} />\n )}\n {(valueDomain || isSegmented) && (\n // The angular scale itself, not chrome: it maps a value onto a\n // fraction of the sweep. Ticks/axis line stay off — the arcs and\n // the optional center readout are the readout. A segmented ring is\n // already measured in degrees, so its scale *is* the sweep.\n <PolarAngleAxis\n type=\"number\"\n domain={isSegmented ? [0, sweep] : valueDomain}\n tick={false}\n axisLine={false}\n />\n )}\n {showTooltip && (\n <ChartTooltip\n // The hover cursor marks which band of the angular axis is\n // active, which on a segmented ring is one metric either way —\n // it just draws a hairline across the gauge.\n cursor={isSegmented ? false : undefined}\n content={tooltipContent ?? getDefaultTooltipContent()}\n />\n )}\n {isSegmented ? (\n <RadialBarChartSegmentedSeries\n ringSegments={ringSegments}\n row={data[0]}\n nameKey={nameKey}\n cornerRadius={cornerRadius}\n animation={animation}\n centerLabel={centerLabel}\n />\n ) : (\n <RadialBarChartSeries\n seriesKeys={seriesKeys}\n seriesData={seriesData}\n isMultiMetric={isMultiMetric}\n config={config}\n nameKey={nameKey}\n showBackground={showBackground}\n cornerRadius={cornerRadius}\n minPointSize={minPointSize}\n animation={animation}\n centerLabel={centerLabel}\n showLabels={showLabels}\n labelPosition={arcLabelPosition}\n labelFormat={labelFormat}\n labelFormatter={labelFormatter}\n />\n )}\n </RechartsRadialBarChart>\n );\n\n const chartDivSize =\n showLabels && (arcLabelPosition === 'outside' || arcLabelPosition === 'end')\n ? 'size-[200px]'\n : 'size-[120px]';\n\n return (\n <div\n ref={ref}\n className={cn('flex flex-row items-center gap-4', !hasLegend && 'justify-center', className)}\n {...props}\n >\n <div className={cn(chartDivSize, 'shrink-0')}>\n <ChartContainer config={config} palette={palette} className=\"size-full\">\n {radialChartContent}\n </ChartContainer>\n </div>\n {showLegend && !isSegmented && resolvedConfigForLegend && (\n <ChartLegendContent\n variant=\"list\"\n payload={rightLegendPayload}\n config={resolvedConfigForLegend}\n nameKey={isMultiMetric ? undefined : nameKey}\n valueKey={isMultiMetric ? undefined : dataKey}\n valueFormatter={isMultiMetric ? undefined : legendValueFormatter}\n className=\"min-w-0 flex-1\"\n />\n )}\n </div>\n );\n }\n);\nRadialBarChart.displayName = 'RadialBarChart';\n\nexport { RadialBarChart };\n"],"mappings":"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"}
|