@acronis-platform/ui-react 5.5.1 → 5.5.2
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 +117 -113
- package/dist/components/ui/area-chart/area-chart.js.map +1 -1
- package/dist/components/ui/bar-chart/bar-chart.js +133 -131
- package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
- package/dist/components/ui/chart/chart.js +91 -48
- package/dist/components/ui/chart/chart.js.map +1 -1
- package/dist/components/ui/composed-chart/composed-chart.js +138 -136
- package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
- package/dist/components/ui/confidence-cone/confidence-cone.js +55 -54
- package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
- package/dist/components/ui/funnel-chart/funnel-chart.js +24 -23
- package/dist/components/ui/funnel-chart/funnel-chart.js.map +1 -1
- package/dist/components/ui/line-chart/line-chart.js +57 -53
- package/dist/components/ui/line-chart/line-chart.js.map +1 -1
- package/dist/components/ui/pie-chart/pie-chart.js +29 -28
- package/dist/components/ui/pie-chart/pie-chart.js.map +1 -1
- package/dist/components/ui/radar-chart/radar-chart.js +74 -73
- package/dist/components/ui/radar-chart/radar-chart.js.map +1 -1
- package/dist/components/ui/radial-bar-chart/radial-bar-chart.js +46 -45
- package/dist/components/ui/radial-bar-chart/radial-bar-chart.js.map +1 -1
- package/dist/components/ui/scatter-chart/scatter-chart.js +29 -26
- package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
- package/dist/components/ui/treemap/treemap.js +22 -21
- package/dist/components/ui/treemap/treemap.js.map +1 -1
- package/dist/llms/area-chart.md +1 -0
- package/dist/llms/bar-chart.md +1 -0
- package/dist/llms/chart.md +21 -0
- package/dist/llms/composed-chart.md +1 -0
- package/dist/llms/confidence-cone.md +1 -0
- package/dist/llms/funnel-chart.md +1 -0
- package/dist/llms/line-chart.md +1 -0
- package/dist/llms/pie-chart.md +1 -0
- package/dist/llms/radar-chart.md +1 -0
- package/dist/llms/radial-bar-chart.md +1 -0
- package/dist/llms/scatter-chart.md +1 -0
- package/dist/llms/treemap.md +1 -0
- package/dist/llms.txt +1 -1
- package/dist/src/components/ui/area-chart/area-chart.d.ts +2 -2
- package/dist/src/components/ui/bar-chart/bar-chart.d.ts +4 -3
- package/dist/src/components/ui/chart/chart.d.ts +15 -5
- package/dist/src/components/ui/chart/index.d.ts +1 -1
- package/dist/src/components/ui/composed-chart/composed-chart.d.ts +2 -2
- package/dist/src/components/ui/confidence-cone/confidence-cone.d.ts +2 -2
- package/dist/src/components/ui/funnel-chart/funnel-chart.d.ts +2 -2
- package/dist/src/components/ui/line-chart/line-chart.d.ts +2 -2
- package/dist/src/components/ui/pie-chart/pie-chart.d.ts +2 -2
- package/dist/src/components/ui/radar-chart/radar-chart.d.ts +2 -2
- package/dist/src/components/ui/radial-bar-chart/radial-bar-chart.d.ts +2 -2
- package/dist/src/components/ui/scatter-chart/scatter-chart.d.ts +2 -2
- package/dist/src/components/ui/treemap/treemap.d.ts +2 -2
- package/dist/ui-react.css +1 -1
- package/package.json +3 -3
|
@@ -128,7 +128,7 @@ function ee({ seriesKeys: e, seriesData: t, isMultiMetric: n, config: r, nameKey
|
|
|
128
128
|
]
|
|
129
129
|
}, e));
|
|
130
130
|
}
|
|
131
|
-
function
|
|
131
|
+
function te({ ringSegments: e, row: t, nameKey: n, cornerRadius: r, animation: i, centerLabel: a }) {
|
|
132
132
|
return e.map((e, o) => /* @__PURE__ */ f(y, {
|
|
133
133
|
dataKey: e.key,
|
|
134
134
|
stackId: "segments",
|
|
@@ -139,30 +139,30 @@ function A({ ringSegments: e, row: t, nameKey: n, cornerRadius: r, animation: i,
|
|
|
139
139
|
children: o === 0 && a && /* @__PURE__ */ f(x, { centerLabel: a })
|
|
140
140
|
}, e.key));
|
|
141
141
|
}
|
|
142
|
-
var
|
|
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, legendFontSize: L, legendAriaLabel: R, legendValueFormatter: z, tooltipContent: B, animate: V, animationDuration: H, animationBegin: U, animationEasing: de, showLabels: W = !1, labelPosition: fe, labelFormat: pe = "value", labelFormatter: me, ...he }, ge) => {
|
|
143
143
|
let G = c({
|
|
144
144
|
animate: V,
|
|
145
145
|
animationDuration: H,
|
|
146
146
|
animationBegin: U,
|
|
147
|
-
animationEasing:
|
|
148
|
-
}), K =
|
|
147
|
+
animationEasing: de
|
|
148
|
+
}), K = fe ?? "insideStart", q = !!y?.length, J = P != null && P > 1 && !q && h.length === 1 && typeof h[0][g] == "number", _e = q ? y : [g], Y = u.useMemo(() => y?.length ? y : [g], [y, g]), X = Math.abs(k - E), Z = J ? w({
|
|
149
149
|
value: h[0][g],
|
|
150
|
-
domain:
|
|
151
|
-
segments:
|
|
152
|
-
gap:
|
|
150
|
+
domain: A ?? [0, h[0][g]],
|
|
151
|
+
segments: P,
|
|
152
|
+
gap: se,
|
|
153
153
|
sweep: X,
|
|
154
154
|
closed: X >= 360
|
|
155
155
|
}) : [], Q = q ? h : h.map((e) => ({
|
|
156
156
|
...e,
|
|
157
157
|
fill: `var(--color-${s(String(e[x]))})`
|
|
158
|
-
})),
|
|
158
|
+
})), ve = J ? [{
|
|
159
159
|
...h[0],
|
|
160
160
|
...Object.fromEntries(Z.map((e) => [e.key, e.degrees]))
|
|
161
|
-
}] : Q,
|
|
162
|
-
|
|
161
|
+
}] : Q, ye = N === void 0 ? void 0 : k < E ? -N : N, $ = u.useMemo(() => I ? o(d, m ?? t) : null, [
|
|
162
|
+
I,
|
|
163
163
|
d,
|
|
164
164
|
m
|
|
165
|
-
]),
|
|
165
|
+
]), be = u.useMemo(() => $ ? q ? Y.map((e) => ({
|
|
166
166
|
value: e,
|
|
167
167
|
dataKey: e,
|
|
168
168
|
color: $[e]?.color ?? `var(--color-${s(e)})`,
|
|
@@ -180,99 +180,100 @@ var j = u.forwardRef(({ className: l, config: d, palette: m, data: h, dataKey: g
|
|
|
180
180
|
Y,
|
|
181
181
|
h,
|
|
182
182
|
x
|
|
183
|
-
]),
|
|
184
|
-
data:
|
|
183
|
+
]), xe = I && !J && !!$, Se = /* @__PURE__ */ p(b, {
|
|
184
|
+
data: ve,
|
|
185
185
|
dataKey: q || J ? void 0 : g,
|
|
186
|
-
cx:
|
|
187
|
-
cy:
|
|
186
|
+
cx: ne,
|
|
187
|
+
cy: M,
|
|
188
188
|
innerRadius: S,
|
|
189
189
|
outerRadius: T,
|
|
190
190
|
startAngle: E,
|
|
191
191
|
endAngle: k,
|
|
192
|
-
barSize:
|
|
193
|
-
barGap:
|
|
194
|
-
barCategoryGap:
|
|
195
|
-
margin:
|
|
192
|
+
barSize: re,
|
|
193
|
+
barGap: ie,
|
|
194
|
+
barCategoryGap: ae,
|
|
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 || J) && /* @__PURE__ */ f(_, {
|
|
207
207
|
type: "number",
|
|
208
|
-
domain: J ? [0, X] :
|
|
208
|
+
domain: J ? [0, X] : A,
|
|
209
209
|
tick: !1,
|
|
210
210
|
axisLine: !1
|
|
211
211
|
}),
|
|
212
|
-
|
|
212
|
+
ue && /* @__PURE__ */ f(i, {
|
|
213
213
|
cursor: !J && void 0,
|
|
214
214
|
content: B ?? (J ? /* @__PURE__ */ f(D, {
|
|
215
215
|
config: d,
|
|
216
216
|
row: h[0],
|
|
217
217
|
nameKey: x,
|
|
218
218
|
dataKey: g,
|
|
219
|
-
domainMax:
|
|
219
|
+
domainMax: A?.[1]
|
|
220
220
|
}) : q ? /* @__PURE__ */ f(a, { labelFormatter: (e, t) => O(t?.[0]?.payload, x) }) : /* @__PURE__ */ f(a, {
|
|
221
221
|
nameKey: x,
|
|
222
222
|
hideLabel: !0
|
|
223
223
|
}))
|
|
224
224
|
}),
|
|
225
|
-
J ? /* @__PURE__ */ f(
|
|
225
|
+
J ? /* @__PURE__ */ f(te, {
|
|
226
226
|
ringSegments: Z,
|
|
227
227
|
row: h[0],
|
|
228
228
|
nameKey: x,
|
|
229
|
-
cornerRadius:
|
|
229
|
+
cornerRadius: j,
|
|
230
230
|
animation: G,
|
|
231
|
-
centerLabel:
|
|
231
|
+
centerLabel: F
|
|
232
232
|
}) : /* @__PURE__ */ f(ee, {
|
|
233
|
-
seriesKeys:
|
|
233
|
+
seriesKeys: _e,
|
|
234
234
|
seriesData: Q,
|
|
235
235
|
isMultiMetric: q,
|
|
236
236
|
config: d,
|
|
237
237
|
nameKey: x,
|
|
238
|
-
showBackground:
|
|
239
|
-
cornerRadius:
|
|
240
|
-
minPointSize:
|
|
238
|
+
showBackground: ce,
|
|
239
|
+
cornerRadius: j,
|
|
240
|
+
minPointSize: ye,
|
|
241
241
|
animation: G,
|
|
242
|
-
centerLabel:
|
|
242
|
+
centerLabel: F,
|
|
243
243
|
showLabels: W,
|
|
244
244
|
labelPosition: K,
|
|
245
|
-
labelFormat:
|
|
246
|
-
labelFormatter:
|
|
245
|
+
labelFormat: pe,
|
|
246
|
+
labelFormatter: me
|
|
247
247
|
})
|
|
248
248
|
]
|
|
249
|
-
}),
|
|
249
|
+
}), Ce = W && (K === "outside" || K === "end") ? "size-[200px]" : "size-[120px]";
|
|
250
250
|
return /* @__PURE__ */ p("div", {
|
|
251
|
-
ref:
|
|
252
|
-
className: e("flex flex-row items-center gap-4", !
|
|
253
|
-
...
|
|
251
|
+
ref: ge,
|
|
252
|
+
className: e("flex flex-row items-center gap-4", !xe && "justify-center", l),
|
|
253
|
+
...he,
|
|
254
254
|
children: [/* @__PURE__ */ f("div", {
|
|
255
|
-
className: e(
|
|
255
|
+
className: e(Ce, "shrink-0"),
|
|
256
256
|
children: /* @__PURE__ */ f(n, {
|
|
257
257
|
config: d,
|
|
258
258
|
palette: m,
|
|
259
259
|
className: "size-full",
|
|
260
|
-
children:
|
|
260
|
+
children: Se
|
|
261
261
|
})
|
|
262
|
-
}),
|
|
262
|
+
}), I && !J && $ && /* @__PURE__ */ f(r, {
|
|
263
263
|
variant: "list",
|
|
264
|
-
payload:
|
|
264
|
+
payload: be,
|
|
265
265
|
config: $,
|
|
266
266
|
nameKey: q ? void 0 : x,
|
|
267
|
-
fontSize:
|
|
267
|
+
fontSize: L,
|
|
268
|
+
ariaLabel: R,
|
|
268
269
|
valueKey: q ? void 0 : g,
|
|
269
270
|
valueFormatter: q ? void 0 : z,
|
|
270
271
|
className: "min-w-0 flex-1"
|
|
271
272
|
})]
|
|
272
273
|
});
|
|
273
274
|
});
|
|
274
|
-
|
|
275
|
+
A.displayName = "RadialBarChart";
|
|
275
276
|
//#endregion
|
|
276
|
-
export {
|
|
277
|
+
export { A as RadialBarChart, D as RadialBarChartSegmentedTooltipContent, O as radialBarChartBandName, S as radialBarChartLabelText, T as radialBarChartSegmentFill, E as radialBarChartSegmentedReading, w as radialBarChartSegments };
|
|
277
278
|
|
|
278
279
|
//# 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 ChartLegendFontSize,\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 * Font size of the legend text (labels and values). Defaults to `'xs'` —\n * the size the legend has always rendered at. See `ChartLegendFontSize`.\n */\n legendFontSize?: ChartLegendFontSize;\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 legendFontSize,\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 fontSize={legendFontSize}\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 ChartLegendFontSize,\n type ChartLegendAriaLabelProps,\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 ChartLegendAriaLabelProps {\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 * Font size of the legend text (labels and values). Defaults to `'xs'` —\n * the size the legend has always rendered at. See `ChartLegendFontSize`.\n */\n legendFontSize?: ChartLegendFontSize;\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 legendFontSize,\n legendAriaLabel,\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 fontSize={legendFontSize}\n ariaLabel={legendAriaLabel}\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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"}
|
|
@@ -10,17 +10,17 @@ import { CartesianGrid as g, Scatter as _, ScatterChart as v, XAxis as y, YAxis
|
|
|
10
10
|
var S = p.forwardRef(({ className: S, config: C, palette: w = {
|
|
11
11
|
type: "diverging",
|
|
12
12
|
pair: "teal-violet"
|
|
13
|
-
}, series: T, xKey: E, yKey: D, zKey: O, zRange: k = [60, 400], shape: A = "circle", xAxisLabel: j, yAxisLabel: M, xUnit: N, yUnit: P, showGrid: F = !0, showTooltip: I = !0, showLegend: ne = !0, legendFontSize: L,
|
|
14
|
-
let
|
|
15
|
-
animate:
|
|
16
|
-
animationDuration:
|
|
17
|
-
animationBegin:
|
|
18
|
-
animationEasing:
|
|
19
|
-
}),
|
|
13
|
+
}, series: T, xKey: E, yKey: D, zKey: O, zRange: k = [60, 400], shape: A = "circle", xAxisLabel: j, yAxisLabel: M, xUnit: N, yUnit: P, showGrid: F = !0, showTooltip: I = !0, showLegend: ne = !0, legendFontSize: L, legendAriaLabel: R, showXAxis: z = !0, showYAxis: B = !0, xTickFormatter: V, yTickFormatter: H, xAxisAngle: U, xAxisInterval: W, yAxisTickCount: G, yAxisDomain: K, gridDashed: q = !0, gridHorizontal: J, gridVertical: Y, tooltipContent: X, animate: Z, animationDuration: re, animationBegin: ie, animationEasing: ae, ...oe }, se) => {
|
|
14
|
+
let ce = o({
|
|
15
|
+
animate: Z,
|
|
16
|
+
animationDuration: re,
|
|
17
|
+
animationBegin: ie,
|
|
18
|
+
animationEasing: ae
|
|
19
|
+
}), le = u(j, "insideBottom", -8), ue = d(M), de = s(K), fe = l(T.flatMap(({ data: e }) => e.map((e) => e[E])), V), Q = p.useRef(null), $ = te(Q, U, j, fe.join("\0"));
|
|
20
20
|
return /* @__PURE__ */ m("div", {
|
|
21
|
-
ref:
|
|
21
|
+
ref: se,
|
|
22
22
|
className: e(S),
|
|
23
|
-
...
|
|
23
|
+
...oe,
|
|
24
24
|
children: /* @__PURE__ */ m(t, {
|
|
25
25
|
ref: Q,
|
|
26
26
|
config: C,
|
|
@@ -35,40 +35,40 @@ var S = p.forwardRef(({ className: S, config: C, palette: w = {
|
|
|
35
35
|
}, $.margin),
|
|
36
36
|
children: [
|
|
37
37
|
F && /* @__PURE__ */ m(g, {
|
|
38
|
-
horizontal:
|
|
39
|
-
vertical:
|
|
40
|
-
strokeDasharray:
|
|
38
|
+
horizontal: J ?? !0,
|
|
39
|
+
vertical: Y ?? !1,
|
|
40
|
+
strokeDasharray: q ? "3 3" : void 0
|
|
41
41
|
}),
|
|
42
42
|
/* @__PURE__ */ m(y, {
|
|
43
43
|
type: "number",
|
|
44
44
|
dataKey: E,
|
|
45
45
|
name: E,
|
|
46
46
|
unit: N,
|
|
47
|
-
hide: !
|
|
47
|
+
hide: !z,
|
|
48
48
|
tickLine: !1,
|
|
49
49
|
axisLine: !1,
|
|
50
50
|
tickMargin: 8,
|
|
51
|
-
tickFormatter:
|
|
52
|
-
angle:
|
|
53
|
-
interval:
|
|
54
|
-
textAnchor: c(
|
|
51
|
+
tickFormatter: V,
|
|
52
|
+
angle: U,
|
|
53
|
+
interval: W,
|
|
54
|
+
textAnchor: c(U),
|
|
55
55
|
height: $.height,
|
|
56
|
-
label:
|
|
56
|
+
label: le
|
|
57
57
|
}),
|
|
58
58
|
/* @__PURE__ */ m(b, {
|
|
59
59
|
type: "number",
|
|
60
60
|
dataKey: D,
|
|
61
61
|
name: D,
|
|
62
62
|
unit: P,
|
|
63
|
-
hide: !
|
|
63
|
+
hide: !B,
|
|
64
64
|
tickLine: !1,
|
|
65
65
|
axisLine: !1,
|
|
66
66
|
tickMargin: 8,
|
|
67
|
-
tickFormatter:
|
|
68
|
-
tickCount:
|
|
69
|
-
domain:
|
|
67
|
+
tickFormatter: H,
|
|
68
|
+
tickCount: G,
|
|
69
|
+
domain: de,
|
|
70
70
|
width: M ? 72 : void 0,
|
|
71
|
-
label:
|
|
71
|
+
label: ue
|
|
72
72
|
}),
|
|
73
73
|
O && /* @__PURE__ */ m(x, {
|
|
74
74
|
type: "number",
|
|
@@ -78,15 +78,18 @@ var S = p.forwardRef(({ className: S, config: C, palette: w = {
|
|
|
78
78
|
}),
|
|
79
79
|
I && /* @__PURE__ */ m(r, {
|
|
80
80
|
cursor: { strokeDasharray: "3 3" },
|
|
81
|
-
content:
|
|
81
|
+
content: X ?? /* @__PURE__ */ m(i, {})
|
|
82
82
|
}),
|
|
83
|
-
ne && /* @__PURE__ */ m(ee, { content: /* @__PURE__ */ m(n, {
|
|
83
|
+
ne && /* @__PURE__ */ m(ee, { content: /* @__PURE__ */ m(n, {
|
|
84
|
+
fontSize: L,
|
|
85
|
+
ariaLabel: R
|
|
86
|
+
}) }),
|
|
84
87
|
T.map((e) => /* @__PURE__ */ m(_, {
|
|
85
88
|
name: e.key,
|
|
86
89
|
data: e.data,
|
|
87
90
|
fill: `var(--color-${a(e.key)})`,
|
|
88
91
|
shape: A,
|
|
89
|
-
...
|
|
92
|
+
...ce
|
|
90
93
|
}, e.key))
|
|
91
94
|
]
|
|
92
95
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scatter-chart.js","names":[],"sources":["../../../../src/components/ui/scatter-chart/scatter-chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n CartesianGrid,\n Scatter,\n ScatterChart as RechartsScatterChart,\n XAxis,\n YAxis,\n ZAxis,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartLegend,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n resolveAxisDomain,\n resolveRotatedTickAnchor,\n resolveXAxisTitle,\n resolveYAxisTitle,\n type ChartConfig,\n type ChartLegendFontSize,\n type ChartPalette,\n toCssKey,\n type CartesianChartProps,\n type ChartAnimationProps,\n} from '../chart';\nimport {\n mergeXAxisLayoutMargin,\n useXAxisLayout,\n} from '../chart/use-x-axis-layout';\nimport { resolveXAxisTickLabels } from '../chart/chart-format';\n\n// A typed recharts composition over the shared `Chart` primitives. Unlike the\n// other chart types, a scatter has no visual \"mode\" to model as a CVA variant —\n// its shape is fixed (x/y points, optionally sized by z) and its expressiveness\n// comes from the data mapping. So there is no `cva` axis here (matches the\n// skill's \"usually none\"); marker `shape` and bubble sizing are plain props.\n// Each series carries its own point array (points aren't columns of a shared\n// row the way bar/line/area series are), so the API takes a `series` list rather\n// than `dataKeys` over one `data` array.\nexport type ScatterMarkerShape =\n | 'circle'\n | 'cross'\n | 'diamond'\n | 'square'\n | 'star'\n | 'triangle'\n | 'wye';\n\nexport interface ScatterSeries {\n /** Series key — must match a `config` entry; drives its `--color-<key>` fill and legend label. */\n key: string;\n /** This series' points — each row holds at least `xKey` and `yKey` (and `zKey` when used). */\n data: ReadonlyArray<Record<string, number>>;\n}\n\nexport interface ScatterChartProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n CartesianChartProps,\n ChartAnimationProps {\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 /** One `<Scatter>` per entry — each with its own point array. Use a single entry for an ungrouped scatter. */\n series: ScatterSeries[];\n /**\n * Per-series map of `label` / `icon` / `tone`, keyed by `series[].key`\n * (imported from the shared `Chart` primitives). Turned into `--color-<key>`\n * custom properties. Series take their colour from the container's `palette`;\n * each entry maps a key to a `label` and an optional `tone`.\n */\n config: ChartConfig;\n /** Numeric field for the horizontal axis. */\n xKey: string;\n /** Numeric field for the vertical axis. */\n yKey: string;\n /** Unit suffix appended to X-axis tick values (recharts `unit`). */\n xUnit?: string;\n /** Optional numeric field mapped to point size (a bubble chart), via recharts `ZAxis`. */\n zKey?: string;\n /** Point-size range `[min, max]` the `zKey` maps into. Ignored when `zKey` is unset (points use recharts' default size). */\n zRange?: [number, number];\n /** Marker shape for every point. */\n shape?: ScatterMarkerShape;\n showLegend?: boolean;\n /**\n * Font size of the legend text. Defaults to `'xs'` — the size the legend has\n * always rendered at. See `ChartLegendFontSize`.\n */\n legendFontSize?: ChartLegendFontSize;\n}\n\nconst ScatterChart = React.forwardRef<HTMLDivElement, ScatterChartProps>(\n (\n {\n className,\n config,\n palette = { type: 'diverging', pair: 'teal-violet' },\n series,\n xKey,\n yKey,\n zKey,\n zRange = [60, 400],\n shape = 'circle',\n xAxisLabel,\n yAxisLabel,\n xUnit,\n yUnit,\n showGrid = true,\n showTooltip = true,\n showLegend = true,\n legendFontSize,\n showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed = true,\n gridHorizontal,\n gridVertical,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n // Axis titles: the X title sits below the ticks; the Y title is rotated in\n // the left gutter. Passed to recharts' native `label` (themed via the\n // `.recharts-label` fill selector on the container).\n const xAxisTitle = resolveXAxisTitle(\n xAxisLabel,\n 'insideBottom',\n -8\n );\n const yAxisTitle = resolveYAxisTitle(yAxisLabel);\n\n const yDomain = resolveAxisDomain(yAxisDomain);\n\n const xAxisTickLabels = resolveXAxisTickLabels(\n series.flatMap(({ data }) => data.map((row) => row[xKey])),\n xTickFormatter\n );\n const chartContainerRef = React.useRef<HTMLDivElement>(null);\n const xAxisLayout = useXAxisLayout(\n chartContainerRef,\n xAxisAngle,\n xAxisLabel,\n xAxisTickLabels.join('\\u0000')\n );\n\n return (\n <div ref={ref} className={cn(className)} {...props}>\n <ChartContainer\n ref={chartContainerRef}\n config={config}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RechartsScatterChart\n margin={mergeXAxisLayoutMargin(\n { top: 16, right: 16, bottom: 16, left: 16 },\n xAxisLayout.margin\n )}\n >\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? false}\n strokeDasharray={gridDashed ? '3 3' : undefined}\n />\n )}\n <XAxis\n type=\"number\"\n dataKey={xKey}\n name={xKey}\n unit={xUnit}\n hide={!showXAxis}\n tickLine={false}\n axisLine={false}\n tickMargin={8}\n tickFormatter={xTickFormatter}\n angle={xAxisAngle}\n interval={xAxisInterval}\n textAnchor={resolveRotatedTickAnchor(xAxisAngle)}\n height={xAxisLayout.height}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n dataKey={yKey}\n name={yKey}\n unit={yUnit}\n hide={!showYAxis}\n tickLine={false}\n axisLine={false}\n tickMargin={8}\n tickFormatter={yTickFormatter}\n tickCount={yAxisTickCount}\n domain={yDomain}\n width={yAxisLabel ? 72 : undefined}\n label={yAxisTitle}\n />\n {zKey && (\n <ZAxis type=\"number\" dataKey={zKey} range={zRange} name={zKey} />\n )}\n {showTooltip && (\n <ChartTooltip\n cursor={{ strokeDasharray: '3 3' }}\n content={tooltipContent ?? <ChartTooltipContent />}\n />\n )}\n {showLegend && (\n <ChartLegend\n content={<ChartLegendContent fontSize={legendFontSize} />}\n />\n )}\n {series.map((s) => (\n <Scatter\n key={s.key}\n name={s.key}\n data={s.data as Record<string, number>[]}\n fill={`var(--color-${toCssKey(s.key)})`}\n shape={shape}\n {...animation}\n />\n ))}\n </RechartsScatterChart>\n </ChartContainer>\n </div>\n );\n }\n);\nScatterChart.displayName = 'ScatterChart';\n\nexport { ScatterChart };\n"],"mappings":";;;;;;;;;AAmGA,IAAM,IAAe,EAAM,YAEvB,EACE,cACA,WACA,aAAU;CAAE,MAAM;CAAa,MAAM;AAAc,GACnD,WACA,SACA,SACA,SACA,YAAS,CAAC,IAAI,GAAG,GACjB,WAAQ,UACR,eACA,eACA,UACA,UACA,cAAW,IACX,iBAAc,IACd,iBAAa,IACb,mBACA,eAAY,IACZ,eAAY,IACZ,mBACA,mBACA,eACA,kBACA,mBACA,gBACA,gBAAa,IACb,mBACA,iBACA,mBACA,YACA,sBACA,oBACA,qBACA,GAAG,MAEL,OACG;CACH,IAAM,KAAY,EAAiB;EACjC;EACA;EACA;EACA;CACF,CAAC,GAIK,KAAa,EACjB,GACA,gBACA,EACF,GACM,KAAa,EAAkB,CAAU,GAEzC,KAAU,EAAkB,CAAW,GAEvC,KAAkB,EACtB,EAAO,SAAS,EAAE,cAAW,EAAK,KAAK,MAAQ,EAAI,EAAK,CAAC,GACzD,CACF,GACM,IAAoB,EAAM,OAAuB,IAAI,GACrD,IAAc,GAClB,GACA,GACA,GACA,GAAgB,KAAK,IAAQ,CAC/B;CAEA,OACE,kBAAC,OAAD;EAAU;EAAK,WAAW,EAAG,CAAS;EAAG,GAAI;EAC3C,UAAA,kBAAC,GAAD;GACE,KAAK;GACG;GACC;GACT,WAAU;GAEV,UAAA,kBAAC,GAAD;IACE,QAAQ,EACN;KAAE,KAAK;KAAI,OAAO;KAAI,QAAQ;KAAI,MAAM;IAAG,GAC3C,EAAY,MACd;IAJF,UAAA;KAMG,KACC,kBAAC,GAAD;MACE,YAAY,KAAkB;MAC9B,UAAU,KAAgB;MAC1B,iBAAiB,IAAa,QAAQ,KAAA;KACvC,CAAA;KAEH,kBAAC,GAAD;MACE,MAAK;MACL,SAAS;MACT,MAAM;MACN,MAAM;MACN,MAAM,CAAC;MACP,UAAU;MACV,UAAU;MACV,YAAY;MACZ,eAAe;MACf,OAAO;MACP,UAAU;MACV,YAAY,EAAyB,CAAU;MAC/C,QAAQ,EAAY;MACpB,OAAO;KACR,CAAA;KACD,kBAAC,GAAD;MACE,MAAK;MACL,SAAS;MACT,MAAM;MACN,MAAM;MACN,MAAM,CAAC;MACP,UAAU;MACV,UAAU;MACV,YAAY;MACZ,eAAe;MACf,WAAW;MACX,QAAQ;MACR,OAAO,IAAa,KAAK,KAAA;MACzB,OAAO;KACR,CAAA;KACA,KACC,kBAAC,GAAD;MAAO,MAAK;MAAS,SAAS;MAAM,OAAO;MAAQ,MAAM;KAAO,CAAA;KAEjE,KACC,kBAAC,GAAD;MACE,QAAQ,EAAE,iBAAiB,MAAM;MACjC,SAAS,KAAkB,kBAAC,GAAD,CAAsB,CAAA;KAClD,CAAA;KAEF,MACC,kBAAC,IAAD,EACE,SAAS,kBAAC,GAAD,EAAoB,UAAU,EAAiB,CAAA,EACzD,CAAA;KAEF,EAAO,KAAK,MACX,kBAAC,GAAD;MAEE,MAAM,EAAE;MACR,MAAM,EAAE;MACR,MAAM,eAAe,EAAS,EAAE,GAAG,EAAE;MAC9B;MACP,GAAI;KACL,GANM,EAAE,GAMR,CACF;IACmB;;EACR,CAAA;CACb,CAAA;AAET,CACF;AACA,EAAa,cAAc"}
|
|
1
|
+
{"version":3,"file":"scatter-chart.js","names":[],"sources":["../../../../src/components/ui/scatter-chart/scatter-chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n CartesianGrid,\n Scatter,\n ScatterChart as RechartsScatterChart,\n XAxis,\n YAxis,\n ZAxis,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartLegend,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n resolveAxisDomain,\n resolveRotatedTickAnchor,\n resolveXAxisTitle,\n resolveYAxisTitle,\n type ChartConfig,\n type ChartLegendFontSize,\n type ChartLegendAriaLabelProps,\n type ChartPalette,\n toCssKey,\n type CartesianChartProps,\n type ChartAnimationProps,\n} from '../chart';\nimport {\n mergeXAxisLayoutMargin,\n useXAxisLayout,\n} from '../chart/use-x-axis-layout';\nimport { resolveXAxisTickLabels } from '../chart/chart-format';\n\n// A typed recharts composition over the shared `Chart` primitives. Unlike the\n// other chart types, a scatter has no visual \"mode\" to model as a CVA variant —\n// its shape is fixed (x/y points, optionally sized by z) and its expressiveness\n// comes from the data mapping. So there is no `cva` axis here (matches the\n// skill's \"usually none\"); marker `shape` and bubble sizing are plain props.\n// Each series carries its own point array (points aren't columns of a shared\n// row the way bar/line/area series are), so the API takes a `series` list rather\n// than `dataKeys` over one `data` array.\nexport type ScatterMarkerShape =\n | 'circle'\n | 'cross'\n | 'diamond'\n | 'square'\n | 'star'\n | 'triangle'\n | 'wye';\n\nexport interface ScatterSeries {\n /** Series key — must match a `config` entry; drives its `--color-<key>` fill and legend label. */\n key: string;\n /** This series' points — each row holds at least `xKey` and `yKey` (and `zKey` when used). */\n data: ReadonlyArray<Record<string, number>>;\n}\n\nexport interface ScatterChartProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n CartesianChartProps,\n ChartAnimationProps,\n ChartLegendAriaLabelProps {\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 /** One `<Scatter>` per entry — each with its own point array. Use a single entry for an ungrouped scatter. */\n series: ScatterSeries[];\n /**\n * Per-series map of `label` / `icon` / `tone`, keyed by `series[].key`\n * (imported from the shared `Chart` primitives). Turned into `--color-<key>`\n * custom properties. Series take their colour from the container's `palette`;\n * each entry maps a key to a `label` and an optional `tone`.\n */\n config: ChartConfig;\n /** Numeric field for the horizontal axis. */\n xKey: string;\n /** Numeric field for the vertical axis. */\n yKey: string;\n /** Unit suffix appended to X-axis tick values (recharts `unit`). */\n xUnit?: string;\n /** Optional numeric field mapped to point size (a bubble chart), via recharts `ZAxis`. */\n zKey?: string;\n /** Point-size range `[min, max]` the `zKey` maps into. Ignored when `zKey` is unset (points use recharts' default size). */\n zRange?: [number, number];\n /** Marker shape for every point. */\n shape?: ScatterMarkerShape;\n showLegend?: boolean;\n /**\n * Font size of the legend text. Defaults to `'xs'` — the size the legend has\n * always rendered at. See `ChartLegendFontSize`.\n */\n legendFontSize?: ChartLegendFontSize;\n}\n\nconst ScatterChart = React.forwardRef<HTMLDivElement, ScatterChartProps>(\n (\n {\n className,\n config,\n palette = { type: 'diverging', pair: 'teal-violet' },\n series,\n xKey,\n yKey,\n zKey,\n zRange = [60, 400],\n shape = 'circle',\n xAxisLabel,\n yAxisLabel,\n xUnit,\n yUnit,\n showGrid = true,\n showTooltip = true,\n showLegend = true,\n legendFontSize,\n legendAriaLabel,\n showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed = true,\n gridHorizontal,\n gridVertical,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n // Axis titles: the X title sits below the ticks; the Y title is rotated in\n // the left gutter. Passed to recharts' native `label` (themed via the\n // `.recharts-label` fill selector on the container).\n const xAxisTitle = resolveXAxisTitle(\n xAxisLabel,\n 'insideBottom',\n -8\n );\n const yAxisTitle = resolveYAxisTitle(yAxisLabel);\n\n const yDomain = resolveAxisDomain(yAxisDomain);\n\n const xAxisTickLabels = resolveXAxisTickLabels(\n series.flatMap(({ data }) => data.map((row) => row[xKey])),\n xTickFormatter\n );\n const chartContainerRef = React.useRef<HTMLDivElement>(null);\n const xAxisLayout = useXAxisLayout(\n chartContainerRef,\n xAxisAngle,\n xAxisLabel,\n xAxisTickLabels.join('\\u0000')\n );\n\n return (\n <div ref={ref} className={cn(className)} {...props}>\n <ChartContainer\n ref={chartContainerRef}\n config={config}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RechartsScatterChart\n margin={mergeXAxisLayoutMargin(\n { top: 16, right: 16, bottom: 16, left: 16 },\n xAxisLayout.margin\n )}\n >\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? false}\n strokeDasharray={gridDashed ? '3 3' : undefined}\n />\n )}\n <XAxis\n type=\"number\"\n dataKey={xKey}\n name={xKey}\n unit={xUnit}\n hide={!showXAxis}\n tickLine={false}\n axisLine={false}\n tickMargin={8}\n tickFormatter={xTickFormatter}\n angle={xAxisAngle}\n interval={xAxisInterval}\n textAnchor={resolveRotatedTickAnchor(xAxisAngle)}\n height={xAxisLayout.height}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n dataKey={yKey}\n name={yKey}\n unit={yUnit}\n hide={!showYAxis}\n tickLine={false}\n axisLine={false}\n tickMargin={8}\n tickFormatter={yTickFormatter}\n tickCount={yAxisTickCount}\n domain={yDomain}\n width={yAxisLabel ? 72 : undefined}\n label={yAxisTitle}\n />\n {zKey && (\n <ZAxis type=\"number\" dataKey={zKey} range={zRange} name={zKey} />\n )}\n {showTooltip && (\n <ChartTooltip\n cursor={{ strokeDasharray: '3 3' }}\n content={tooltipContent ?? <ChartTooltipContent />}\n />\n )}\n {showLegend && (\n <ChartLegend\n content={\n <ChartLegendContent\n fontSize={legendFontSize}\n ariaLabel={legendAriaLabel}\n />\n }\n />\n )}\n {series.map((s) => (\n <Scatter\n key={s.key}\n name={s.key}\n data={s.data as Record<string, number>[]}\n fill={`var(--color-${toCssKey(s.key)})`}\n shape={shape}\n {...animation}\n />\n ))}\n </RechartsScatterChart>\n </ChartContainer>\n </div>\n );\n }\n);\nScatterChart.displayName = 'ScatterChart';\n\nexport { ScatterChart };\n"],"mappings":";;;;;;;;;AAqGA,IAAM,IAAe,EAAM,YAEvB,EACE,cACA,WACA,aAAU;CAAE,MAAM;CAAa,MAAM;AAAc,GACnD,WACA,SACA,SACA,SACA,YAAS,CAAC,IAAI,GAAG,GACjB,WAAQ,UACR,eACA,eACA,UACA,UACA,cAAW,IACX,iBAAc,IACd,iBAAa,IACb,mBACA,oBACA,eAAY,IACZ,eAAY,IACZ,mBACA,mBACA,eACA,kBACA,mBACA,gBACA,gBAAa,IACb,mBACA,iBACA,mBACA,YACA,uBACA,oBACA,qBACA,GAAG,MAEL,OACG;CACH,IAAM,KAAY,EAAiB;EACjC;EACA;EACA;EACA;CACF,CAAC,GAIK,KAAa,EACjB,GACA,gBACA,EACF,GACM,KAAa,EAAkB,CAAU,GAEzC,KAAU,EAAkB,CAAW,GAEvC,KAAkB,EACtB,EAAO,SAAS,EAAE,cAAW,EAAK,KAAK,MAAQ,EAAI,EAAK,CAAC,GACzD,CACF,GACM,IAAoB,EAAM,OAAuB,IAAI,GACrD,IAAc,GAClB,GACA,GACA,GACA,GAAgB,KAAK,IAAQ,CAC/B;CAEA,OACE,kBAAC,OAAD;EAAU;EAAK,WAAW,EAAG,CAAS;EAAG,GAAI;EAC3C,UAAA,kBAAC,GAAD;GACE,KAAK;GACG;GACC;GACT,WAAU;GAEV,UAAA,kBAAC,GAAD;IACE,QAAQ,EACN;KAAE,KAAK;KAAI,OAAO;KAAI,QAAQ;KAAI,MAAM;IAAG,GAC3C,EAAY,MACd;IAJF,UAAA;KAMG,KACC,kBAAC,GAAD;MACE,YAAY,KAAkB;MAC9B,UAAU,KAAgB;MAC1B,iBAAiB,IAAa,QAAQ,KAAA;KACvC,CAAA;KAEH,kBAAC,GAAD;MACE,MAAK;MACL,SAAS;MACT,MAAM;MACN,MAAM;MACN,MAAM,CAAC;MACP,UAAU;MACV,UAAU;MACV,YAAY;MACZ,eAAe;MACf,OAAO;MACP,UAAU;MACV,YAAY,EAAyB,CAAU;MAC/C,QAAQ,EAAY;MACpB,OAAO;KACR,CAAA;KACD,kBAAC,GAAD;MACE,MAAK;MACL,SAAS;MACT,MAAM;MACN,MAAM;MACN,MAAM,CAAC;MACP,UAAU;MACV,UAAU;MACV,YAAY;MACZ,eAAe;MACf,WAAW;MACX,QAAQ;MACR,OAAO,IAAa,KAAK,KAAA;MACzB,OAAO;KACR,CAAA;KACA,KACC,kBAAC,GAAD;MAAO,MAAK;MAAS,SAAS;MAAM,OAAO;MAAQ,MAAM;KAAO,CAAA;KAEjE,KACC,kBAAC,GAAD;MACE,QAAQ,EAAE,iBAAiB,MAAM;MACjC,SAAS,KAAkB,kBAAC,GAAD,CAAsB,CAAA;KAClD,CAAA;KAEF,MACC,kBAAC,IAAD,EACE,SACE,kBAAC,GAAD;MACE,UAAU;MACV,WAAW;KACZ,CAAA,EAEJ,CAAA;KAEF,EAAO,KAAK,MACX,kBAAC,GAAD;MAEE,MAAM,EAAE;MACR,MAAM,EAAE;MACR,MAAM,eAAe,EAAS,EAAE,GAAG,EAAE;MAC9B;MACP,GAAI;KACL,GANM,EAAE,GAMR,CACF;IACmB;;EACR,CAAA;CACb,CAAA;AAET,CACF;AACA,EAAa,cAAc"}
|