@acronis-platform/ui-react 4.1.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/components/ui/area-chart/area-chart.js +191 -85
  2. package/dist/components/ui/area-chart/area-chart.js.map +1 -1
  3. package/dist/components/ui/bar-chart/bar-chart.js +288 -225
  4. package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
  5. package/dist/components/ui/card-widget-carousel/card-widget-carousel.js +85 -0
  6. package/dist/components/ui/card-widget-carousel/card-widget-carousel.js.map +1 -0
  7. package/dist/components/ui/card-widget-carousel/card-widget.js +82 -0
  8. package/dist/components/ui/card-widget-carousel/card-widget.js.map +1 -0
  9. package/dist/components/ui/category-bar/category-bar.js.map +1 -1
  10. package/dist/components/ui/chart/chart-format.js +25 -22
  11. package/dist/components/ui/chart/chart-format.js.map +1 -1
  12. package/dist/components/ui/chart/chart-palette.js +9 -8
  13. package/dist/components/ui/chart/chart-palette.js.map +1 -1
  14. package/dist/components/ui/chart/chart.js +127 -89
  15. package/dist/components/ui/chart/chart.js.map +1 -1
  16. package/dist/components/ui/funnel-chart/funnel-chart.js +189 -113
  17. package/dist/components/ui/funnel-chart/funnel-chart.js.map +1 -1
  18. package/dist/components/ui/input-select/input-select.js +18 -9
  19. package/dist/components/ui/input-select/input-select.js.map +1 -1
  20. package/dist/components/ui/line-chart/line-chart.js +194 -86
  21. package/dist/components/ui/line-chart/line-chart.js.map +1 -1
  22. package/dist/components/ui/radar-chart/radar-chart.js +76 -66
  23. package/dist/components/ui/radar-chart/radar-chart.js.map +1 -1
  24. package/dist/components/ui/scatter-chart/scatter-chart.js +5 -2
  25. package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
  26. package/dist/components/ui/separator/separator.js +52 -10
  27. package/dist/components/ui/separator/separator.js.map +1 -1
  28. package/dist/components/ui/sidebar-secondary/sidebar-secondary.js +144 -121
  29. package/dist/components/ui/sidebar-secondary/sidebar-secondary.js.map +1 -1
  30. package/dist/components/ui/tree-item/tree-item.js +67 -0
  31. package/dist/components/ui/tree-item/tree-item.js.map +1 -0
  32. package/dist/components/ui/treemap/treemap.js +73 -66
  33. package/dist/components/ui/treemap/treemap.js.map +1 -1
  34. package/dist/index.js +109 -107
  35. package/dist/llms/area-chart.md +2 -1
  36. package/dist/llms/bar-chart.md +132 -33
  37. package/dist/llms/card-widget-carousel.md +252 -0
  38. package/dist/llms/category-bar.md +2 -2
  39. package/dist/llms/funnel-chart.md +269 -101
  40. package/dist/llms/input-select.md +175 -1
  41. package/dist/llms/line-chart.md +2 -1
  42. package/dist/llms/metric.md +10 -5
  43. package/dist/llms/radar-chart.md +15 -5
  44. package/dist/llms/scatter-chart.md +2 -1
  45. package/dist/llms/separator.md +27 -8
  46. package/dist/llms/sidebar-secondary.md +235 -4
  47. package/dist/llms/tree-item.md +359 -0
  48. package/dist/llms/treemap.md +47 -36
  49. package/dist/llms.txt +5 -4
  50. package/dist/react.js +109 -107
  51. package/dist/src/components/ui/area-chart/area-chart.d.ts +10 -0
  52. package/dist/src/components/ui/bar-chart/bar-chart.d.ts +75 -10
  53. package/dist/src/components/ui/bar-chart/bar-chart.docs.d.ts +146 -0
  54. package/dist/src/components/ui/bar-chart/index.d.ts +1 -1
  55. package/dist/src/components/ui/card-widget-carousel/card-widget-carousel.d.ts +9 -0
  56. package/dist/src/components/ui/card-widget-carousel/card-widget.d.ts +43 -0
  57. package/dist/src/components/ui/card-widget-carousel/index.d.ts +2 -0
  58. package/dist/src/components/ui/chart/chart-format.d.ts +9 -1
  59. package/dist/src/components/ui/chart/chart-palette.d.ts +38 -10
  60. package/dist/src/components/ui/chart/chart.d.ts +8 -1
  61. package/dist/src/components/ui/chart/index.d.ts +2 -2
  62. package/dist/src/components/ui/funnel-chart/funnel-chart.d.ts +92 -26
  63. package/dist/src/components/ui/funnel-chart/index.d.ts +1 -1
  64. package/dist/src/components/ui/input-select/input-select.d.ts +34 -2
  65. package/dist/src/components/ui/line-chart/line-chart.d.ts +11 -1
  66. package/dist/src/components/ui/radar-chart/radar-chart.d.ts +42 -9
  67. package/dist/src/components/ui/separator/separator.d.ts +9 -1
  68. package/dist/src/components/ui/sidebar-secondary/sidebar-secondary.d.ts +23 -3
  69. package/dist/src/components/ui/tree-item/index.d.ts +1 -0
  70. package/dist/src/components/ui/tree-item/tree-item.d.ts +64 -0
  71. package/dist/src/components/ui/treemap/treemap.d.ts +16 -5
  72. package/dist/src/index.d.ts +2 -1
  73. package/dist/ui-react.css +1 -1
  74. package/package.json +1 -1
  75. package/dist/components/ui/meter/meter.js +0 -79
  76. package/dist/components/ui/meter/meter.js.map +0 -1
  77. package/dist/llms/meter.md +0 -177
  78. package/dist/src/components/ui/meter/index.d.ts +0 -1
  79. package/dist/src/components/ui/meter/meter.d.ts +0 -25
@@ -1 +1 @@
1
- {"version":3,"file":"line-chart.js","names":[],"sources":["../../../../src/components/ui/line-chart/line-chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n Area,\n Brush,\n CartesianGrid,\n ComposedChart,\n LabelList,\n Line,\n LineChart as RechartsLineChart,\n ReferenceLine,\n XAxis,\n YAxis,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n CHART_LABEL_FONT_SIZE,\n CHART_LABEL_MARGIN,\n ChartContainer,\n ChartLegend,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n resolveAxisDomain,\n resolveBrushProps,\n resolveChartReferenceValue,\n resolveLabelFillClass,\n resolveReferenceLineProps,\n resolveRotatedTickAnchor,\n resolveXAxisHeight,\n resolveXAxisTitle,\n resolveYAxisTitle,\n toLabelFormatter,\n toReferenceLineList,\n type ChartConfig,\n type ChartPalette,\n type ChartLegendContentProps,\n type ChartTooltipContentProps,\n type CartesianChartProps,\n type ChartAnimationProps,\n type ChartBrushProps,\n type ChartCurveType,\n type ChartDataLabelProps,\n type ChartReferenceLine,\n type CartesianLabelPosition,\n} from '../chart';\n\n// A typed recharts composition over the shared `Chart` primitives. The two CVA\n// axes are the design's Line-chart variant set: `curve` (how the segments\n// interpolate between points — straight, smoothed, or stepped; the seven values\n// are documented on the shared `ChartCurveType`) and `lineStyle` (a solid or\n// dashed stroke). \"single\" vs \"multi\" line is not a variant — it\n// falls out of how many `dataKeys` the caller plots. The classes stay empty\n// because recharts' SVG — not CSS — draws the lines: `curve` drives each\n// `<Line type>` and `lineStyle` drives its `strokeDasharray`. CVA is kept so the\n// variant set is a first-class, spec-conformant part of the API (matched against\n// ui-spec's api.yaml enums) and exposed via `VariantProps`; the resolved values\n// are also mirrored onto `data-curve` / `data-line-style` for styling hooks and\n// tests.\nconst lineChartVariants = cva('', {\n variants: {\n curve: {\n linear: '',\n monotone: '',\n natural: '',\n basis: '',\n step: '',\n stepBefore: '',\n stepAfter: '',\n },\n lineStyle: {\n solid: '',\n dashed: '',\n },\n },\n defaultVariants: {\n curve: 'monotone',\n lineStyle: 'solid',\n },\n});\n\n// Reserved field prefix for the synthetic delta-band range series. Each band\n// mints one `__band_<n>` field that feeds an <Area>; it must never surface in\n// the tooltip or legend (those describe only real, caller-supplied series).\nconst BAND_FIELD_PREFIX = '__band_';\n\n/**\n * Drop the synthetic delta-band range series from a recharts tooltip/legend\n * payload, keeping the real series (and their order). recharts already excludes\n * the band via `legendType`/`tooltipType=\"none\"`, so this is a second, explicit\n * guard — hence it's unit-tested rather than relying on that behavior.\n */\nexport function dropBandSeries<T extends { dataKey?: unknown }>(\n payload: readonly T[] | undefined\n): T[] | undefined {\n return payload?.filter(\n (item) => !String(item.dataKey).startsWith(BAND_FIELD_PREFIX)\n );\n}\n\ntype TooltipContentType = NonNullable<\n React.ComponentProps<typeof ChartTooltip>['content']\n>;\ntype TooltipContentFn = Extract<TooltipContentType, (...args: never[]) => unknown>;\ntype LegendContentFn = Extract<\n React.ComponentProps<typeof ChartLegend>['content'],\n (...args: never[]) => unknown\n>;\ntype LegendContentProps = Parameters<LegendContentFn>[0];\ntype TooltipRenderProps = Parameters<TooltipContentFn>[0];\n\n/**\n * Wrap a caller-supplied `tooltipContent` so the synthetic delta bands are\n * stripped from the payload before it renders, while preserving recharts' own\n * mount semantics — a function is mounted via `createElement` (its own component\n * identity + hook state), an element via `cloneElement`. This mirrors what the\n * pass-through charts get by handing `content` straight to recharts, so a\n * function-form tooltip keeps its state across re-renders here too. The returned\n * component is a stable content type (memoize it on `tooltipContent`).\n */\nexport function createBandStrippedTooltip(tooltipContent: TooltipContentType) {\n return function BandStrippedTooltip(props: TooltipRenderProps) {\n const merged = {\n ...props,\n payload: dropBandSeries(props.payload),\n } as TooltipRenderProps;\n return typeof tooltipContent === 'function'\n ? React.createElement(\n tooltipContent as React.FunctionComponent<TooltipRenderProps>,\n merged\n )\n : React.cloneElement(tooltipContent, merged);\n };\n}\n\n/**\n * Style override for one series, keyed by its `dataKeys` entry. Anything left\n * unset falls back to the chart-wide prop, so an entry only states what differs\n * — e.g. one thicker, dashed \"target\" line among otherwise identical series.\n *\n * A series listed in `comparisonKeys` keeps its dashed, dimmed, dot-less\n * treatment: `color`, `strokeWidth` and `curveType` still apply to it, but\n * `showDots` / `dotSize` do not (the overlay is defined by having no dots).\n */\nexport interface LineChartLineSettings {\n /** Stroke color. Defaults to the series' `config` color. */\n color?: string;\n /** Stroke width. Defaults to the chart's `strokeWidth`. */\n strokeWidth?: number;\n /** Dash this series' stroke, whatever the chart-wide `lineStyle` is. */\n dashed?: boolean;\n /** Interpolation for this series only. Defaults to the chart's `curve`. */\n curveType?: ChartCurveType;\n /** Render this series' per-point dots. Defaults to the chart's `showDots`. */\n showDots?: boolean;\n /** Dot radius for this series, in px. Defaults to the chart's `dotSize`. */\n dotSize?: number;\n /** Show/hide this series' value labels, overriding the chart's `showLabels`. */\n showLabel?: boolean;\n /** Position of this series' value labels. Defaults to the chart's `labelPosition`. */\n labelPosition?: CartesianLabelPosition;\n}\n\nexport interface LineChartProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n VariantProps<typeof lineChartVariants>,\n CartesianChartProps,\n ChartAnimationProps,\n ChartBrushProps,\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-point data. Each object holds the category key + one numeric field per series (`null` breaks the line unless `connectNulls`). */\n data: ReadonlyArray<Record<string, string | number | null>>;\n /**\n * Per-series map of `label` / `icon` / `tone` (from the shared `Chart`\n * primitives). Series take their colour from the container's `palette`; each\n * entry maps a key to a `label` and an optional `tone`.\n */\n config: ChartConfig;\n /** Series to plot — one `<Line>` per key. Each must exist in `config` and in every data row. */\n dataKeys: string[];\n /**\n * Subset of `dataKeys` to render as comparison/trend overlays (e.g. a\n * previous quarter or year) — dashed, dimmed, and dot-less, so they read as\n * secondary to the current-period lines. Keeps each series' own `config` color.\n */\n comparisonKeys?: string[];\n /**\n * Pairs of `[currentKey, comparisonKey]` to shade a delta band between — a\n * dimmed area filling the gap between the two series at each point,\n * visualizing the QoQ/YoY difference. Tinted with the first key's `config`\n * color. Rows where either value isn't numeric are left un-banded.\n *\n * Each pair mints an internal `__band_<n>` field (kept out of the tooltip and\n * legend), so avoid data/`config` keys with that reserved prefix.\n */\n deltaBands?: Array<[string, string]>;\n /** Category axis key (the shared dimension across rows, e.g. `\"month\"`). */\n xKey: string;\n /** Stroke width of each line. */\n strokeWidth?: number;\n /** Render a dot at each data point. */\n showDots?: boolean;\n /** Radius of each point's dot, in px. Its hover dot is 2px larger. */\n dotSize?: number;\n /**\n * Enlarge the hovered point's dot. Defaults to following `showDots`, so pass\n * it explicitly to get hover dots on a dot-less line (`showDots={false}`\n * with `showActiveDot`) or a static-only line (dots without the hover one).\n */\n showActiveDot?: boolean;\n /** Bridge `null` gaps in the data instead of breaking the line. */\n connectNulls?: boolean;\n /**\n * Per-series style overrides, keyed by `dataKeys` entry. Series with no entry\n * render from the chart-wide props.\n */\n lineSettings?: Record<string, LineChartLineSettings>;\n /**\n * One or more dashed reference/average lines on the value axis — a target, a\n * threshold, or a series mean. Pass a single object or an array to draw\n * several at once.\n */\n referenceLine?: ChartReferenceLine | ChartReferenceLine[];\n showLegend?: boolean;\n /** Position of the value labels when `showLabels` is on. Defaults to `top`. */\n labelPosition?: CartesianLabelPosition;\n}\n\nconst LineChart = React.forwardRef<HTMLDivElement, LineChartProps>(\n (\n {\n className,\n config,\n palette,\n data,\n dataKeys,\n comparisonKeys,\n deltaBands,\n xKey,\n xAxisLabel,\n yAxisLabel,\n yUnit,\n curve = 'monotone',\n lineStyle = 'solid',\n strokeWidth = 2,\n showDots = true,\n dotSize = 3,\n showActiveDot,\n connectNulls = false,\n lineSettings,\n referenceLine,\n showGrid = true,\n showTooltip = true,\n showLegend = true,\n showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed,\n gridHorizontal,\n gridVertical,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n showLabels = false,\n labelPosition,\n labelFormatter,\n showBrush = false,\n brushHeight,\n brushAriaLabel,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n const lineLabelPosition = labelPosition ?? 'top';\n const yDomain = resolveAxisDomain(yAxisDomain);\n const referenceLines = toReferenceLineList(referenceLine);\n\n // A series' own `color` and `curveType` overrides also drive its delta band,\n // so the band keeps following the line it belongs to instead of the\n // chart-wide defaults.\n const colorFor = (key: string) =>\n lineSettings?.[key]?.color ?? `var(--color-${key})`;\n const curveFor = (key: string) =>\n lineSettings?.[key]?.curveType ?? curve ?? 'monotone';\n\n // The plot inset is needed as soon as *any* series carries outside labels —\n // a per-series `showLabel` counts, not only the chart-wide `showLabels`.\n const hasLabels =\n showLabels ||\n Object.values(lineSettings ?? {}).some((settings) => settings.showLabel);\n\n const xAxisHeight = resolveXAxisHeight(xAxisLabel, xAxisAngle);\n\n // Memoized so recharts sees a stable content type across renders — a fresh\n // wrapper each render would remount the caller's tooltip and reset its state.\n const customTooltip = React.useMemo(\n () =>\n tooltipContent ? createBandStrippedTooltip(tooltipContent) : undefined,\n [tooltipContent]\n );\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(xAxisLabel);\n const yAxisTitle = resolveYAxisTitle(yAxisLabel);\n\n // Each delta band becomes a synthetic `[min, max]` range field per row that\n // a recharts <Area> shades. Rows where either series isn't numeric are left\n // un-banded (the area breaks there).\n const bands = (deltaBands ?? []).map(([current, comparison], index) => ({\n field: `${BAND_FIELD_PREFIX}${index}`,\n current,\n comparison,\n }));\n\n // A delta band is a synthetic `__band_*` series feeding an <Area>, not a\n // trend of its own — so it has to be stripped from the tooltip rows and the\n // legend entries before either is rendered. A caller's own tooltip is\n // already wrapped for that above; these cover the two default contents.\n const hasBands = bands.length > 0;\n const tooltipNode =\n customTooltip ??\n (hasBands ? (\n (props: TooltipRenderProps) => (\n <ChartTooltipContent\n active={props.active}\n label={props.label}\n payload={\n dropBandSeries(\n props.payload\n ) as ChartTooltipContentProps['payload']\n }\n />\n )\n ) : (\n <ChartTooltipContent />\n ));\n const legendNode = hasBands ? (\n (props: LegendContentProps) => (\n <ChartLegendContent\n verticalAlign={props.verticalAlign}\n payload={\n dropBandSeries(props.payload) as ChartLegendContentProps['payload']\n }\n />\n )\n ) : (\n <ChartLegendContent />\n );\n const chartData = bands.length\n ? data.map((row) => {\n const augmented: Record<string, unknown> = { ...row };\n for (const { field, current, comparison } of bands) {\n const a = row[current];\n const b = row[comparison];\n augmented[field] =\n typeof a === 'number' && typeof b === 'number'\n ? [Math.min(a, b), Math.max(a, b)]\n : undefined;\n }\n return augmented;\n })\n : data;\n\n // Only a delta band needs an <Area>, which recharts renders under\n // ComposedChart, not LineChart. Escalate to ComposedChart only then, so\n // plain line charts keep the LineChart base (and their baselines) untouched.\n const RootChart = bands.length > 0 ? ComposedChart : RechartsLineChart;\n\n return (\n <div\n ref={ref}\n data-curve={curve}\n data-line-style={lineStyle}\n className={cn(lineChartVariants({ curve, lineStyle }), className)}\n {...props}\n >\n <ChartContainer\n config={config}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RootChart\n data={chartData as readonly unknown[]}\n margin={hasLabels ? CHART_LABEL_MARGIN : undefined}\n >\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? false}\n strokeDasharray={gridDashed ? '3 3' : undefined}\n />\n )}\n <XAxis\n dataKey={xKey}\n type=\"category\"\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={xAxisHeight}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n hide={!showYAxis}\n tickLine={false}\n axisLine={false}\n unit={yUnit}\n tickFormatter={yTickFormatter}\n tickCount={yAxisTickCount}\n domain={yDomain}\n width={yAxisLabel ? 72 : undefined}\n label={yAxisTitle}\n />\n {showTooltip && <ChartTooltip content={tooltipNode} />}\n {showLegend && <ChartLegend content={legendNode} />}\n {/* Delta bands render before the lines so the lines draw on top. */}\n {bands.map(({ field, current }) => (\n <Area\n key={field}\n dataKey={field}\n // An <Area> takes one interpolation, so a pair whose two series\n // set different `curveType`s can only follow the current one.\n type={curveFor(current)}\n stroke=\"none\"\n fill={colorFor(current)}\n fillOpacity={0.12}\n connectNulls={connectNulls}\n dot={false}\n activeDot={false}\n {...animation}\n legendType=\"none\"\n tooltipType=\"none\"\n />\n ))}\n {dataKeys.map((key) => {\n // Comparison series read as secondary: always dashed, dimmed, and\n // dot-less, regardless of the global lineStyle / showDots.\n const isComparison = comparisonKeys?.includes(key);\n const settings = lineSettings?.[key];\n const seriesDots =\n !isComparison && (settings?.showDots ?? showDots);\n const dotRadius = settings?.dotSize ?? dotSize;\n // The hover dot follows the static dots unless asked otherwise, so\n // a chart that sets neither renders exactly as before.\n const activeDot = !isComparison && (showActiveDot ?? seriesDots);\n const seriesDashed = settings?.dashed ?? lineStyle === 'dashed';\n const seriesLabel = settings?.showLabel ?? showLabels;\n const seriesLabelPosition =\n settings?.labelPosition ?? lineLabelPosition;\n return (\n <Line\n key={key}\n type={curveFor(key)}\n dataKey={key}\n stroke={colorFor(key)}\n strokeWidth={settings?.strokeWidth ?? strokeWidth}\n strokeDasharray={isComparison || seriesDashed ? '5 5' : undefined}\n strokeOpacity={isComparison ? 0.5 : undefined}\n dot={seriesDots ? { r: dotRadius } : false}\n activeDot={activeDot ? { r: dotRadius + 2 } : false}\n connectNulls={connectNulls}\n {...animation}\n >\n {seriesLabel && (\n <LabelList\n dataKey={key}\n position={seriesLabelPosition}\n formatter={toLabelFormatter(labelFormatter)}\n className={resolveLabelFillClass(seriesLabelPosition)}\n fontSize={CHART_LABEL_FONT_SIZE}\n />\n )}\n </Line>\n );\n })}\n {/* Annotations draw over the series they describe. */}\n {referenceLines.map((ref, index) => {\n const value = resolveChartReferenceValue(ref, data, dataKeys);\n if (value === undefined) return null;\n return (\n <ReferenceLine\n key={`${ref.label ?? 'ref'}-${index}`}\n y={value}\n {...resolveReferenceLineProps(ref.label, ref.labelPosition)}\n />\n );\n })}\n {showBrush && (\n <Brush\n dataKey={xKey}\n tickFormatter={xTickFormatter}\n {...resolveBrushProps({ brushHeight, brushAriaLabel })}\n />\n )}\n </RootChart>\n </ChartContainer>\n </div>\n );\n }\n);\nLineChart.displayName = 'LineChart';\n\nexport { LineChart, lineChartVariants };\n"],"mappings":";;;;;;;;;AA+DA,IAAM,IAAoB,EAAI,IAAI;CAChC,UAAU;EACR,OAAO;GACL,QAAQ;GACR,UAAU;GACV,SAAS;GACT,OAAO;GACP,MAAM;GACN,YAAY;GACZ,WAAW;EACb;EACA,WAAW;GACT,OAAO;GACP,QAAQ;EACV;CACF;CACA,iBAAiB;EACf,OAAO;EACP,WAAW;CACb;AACF,CAAC,GAKK,IAAoB;AAQ1B,SAAgB,EACd,GACiB;CACjB,OAAO,GAAS,QACb,MAAS,CAAC,OAAO,EAAK,OAAO,CAAC,CAAC,WAAW,CAAiB,CAC9D;AACF;AAsBA,SAAgB,EAA0B,GAAoC;CAC5E,OAAO,SAA6B,GAA2B;EAC7D,IAAM,IAAS;GACb,GAAG;GACH,SAAS,EAAe,EAAM,OAAO;EACvC;EACA,OAAO,OAAO,KAAmB,aAC7B,EAAM,cACJ,GACA,CACF,IACA,EAAM,aAAa,GAAgB,CAAM;CAC/C;AACF;AAoGA,IAAM,IAAY,EAAM,YAEpB,EACE,cACA,WACA,YACA,SACA,aACA,mBACA,eACA,SACA,eACA,eACA,UACA,WAAQ,YACR,eAAY,SACZ,iBAAc,GACd,cAAW,IACX,aAAU,GACV,kBACA,kBAAe,IACf,iBACA,mBACA,eAAW,IACX,kBAAc,IACd,iBAAa,IACb,gBAAY,IACZ,gBAAY,IACZ,mBACA,oBACA,eACA,mBACA,oBACA,iBACA,gBACA,oBACA,kBACA,mBACA,aACA,uBACA,oBACA,qBACA,gBAAa,IACb,mBACA,oBACA,gBAAY,IACZ,iBACA,oBACA,GAAG,MAEL,OACG;CACH,IAAM,IAAY,EAAiB;EACjC;EACA;EACA;EACA;CACF,CAAC,GACK,KAAoB,MAAiB,OACrC,KAAU,EAAkB,EAAW,GACvC,KAAiB,EAAoB,EAAa,GAKlD,KAAY,MAChB,IAAe,EAAI,EAAE,SAAS,eAAe,EAAI,IAC7C,KAAY,MAChB,IAAe,EAAI,EAAE,aAAa,KAAS,YAIvC,KACJ,KACA,OAAO,OAAO,KAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,MAAa,EAAS,SAAS,GAEnE,KAAc,EAAmB,GAAY,CAAU,GAIvD,IAAgB,EAAM,cAExB,IAAiB,EAA0B,CAAc,IAAI,KAAA,GAC/D,CAAC,CAAc,CACjB,GAKM,KAAa,EAAkB,CAAU,GACzC,KAAa,EAAkB,CAAU,GAKzC,KAAS,KAAc,CAAC,EAAA,CAAG,KAAK,CAAC,GAAS,IAAa,OAAW;EACtE,OAAO,GAAG,IAAoB;EAC9B;EACA;CACF,EAAE,GAMI,IAAW,EAAM,SAAS,GAC1B,KACJ,MACC,MACE,MACC,kBAAC,GAAD;EACE,QAAQ,EAAM;EACd,OAAO,EAAM;EACb,SACE,EACE,EAAM,OACR;CAEH,CAAA,KAGH,kBAAC,GAAD,CAAsB,CAAA,IAEpB,KAAa,MAChB,MACC,kBAAC,GAAD;EACE,eAAe,EAAM;EACrB,SACE,EAAe,EAAM,OAAO;CAE/B,CAAA,KAGH,kBAAC,GAAD,CAAqB,CAAA,GAEjB,KAAY,EAAM,SACpB,EAAK,KAAK,MAAQ;EAChB,IAAM,IAAqC,EAAE,GAAG,EAAI;EACpD,KAAK,IAAM,EAAE,UAAO,YAAS,mBAAgB,GAAO;GAClD,IAAM,IAAI,EAAI,IACR,IAAI,EAAI;GACd,EAAU,KACR,OAAO,KAAM,YAAY,OAAO,KAAM,WAClC,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,IAC/B,KAAA;EACR;EACA,OAAO;CACT,CAAC,IACD,GAKE,KAAY,EAAM,SAAS,IAAI,KAAgB;CAErD,OACE,kBAAC,OAAD;EACO;EACL,cAAY;EACZ,mBAAiB;EACjB,WAAW,EAAG,EAAkB;GAAE;GAAO;EAAU,CAAC,GAAG,CAAS;EAChE,GAAI;EAEJ,UAAA,kBAAC,GAAD;GACU;GACC;GACT,WAAU;GAEV,UAAA,kBAAC,IAAD;IACE,MAAM;IACN,QAAQ,KAAY,IAAqB,KAAA;IAF3C,UAAA;KAIG,MACC,kBAAC,IAAD;MACE,YAAY,MAAkB;MAC9B,UAAU,MAAgB;MAC1B,iBAAiB,KAAa,QAAQ,KAAA;KACvC,CAAA;KAEH,kBAAC,IAAD;MACE,SAAS;MACT,MAAK;MACL,MAAM,CAAC;MACP,UAAU;MACV,UAAU;MACV,YAAY;MACZ,eAAe;MACf,OAAO;MACP,UAAU;MACV,YAAY,EAAyB,CAAU;MAC/C,QAAQ;MACR,OAAO;KACR,CAAA;KACD,kBAAC,IAAD;MACE,MAAK;MACL,MAAM,CAAC;MACP,UAAU;MACV,UAAU;MACV,MAAM;MACN,eAAe;MACf,WAAW;MACX,QAAQ;MACR,OAAO,IAAa,KAAK,KAAA;MACzB,OAAO;KACR,CAAA;KACA,MAAe,kBAAC,GAAD,EAAc,SAAS,GAAc,CAAA;KACpD,MAAc,kBAAC,GAAD,EAAa,SAAS,GAAa,CAAA;KAEjD,EAAM,KAAK,EAAE,UAAO,iBACnB,kBAAC,GAAD;MAEE,SAAS;MAGT,MAAM,EAAS,CAAO;MACtB,QAAO;MACP,MAAM,EAAS,CAAO;MACtB,aAAa;MACC;MACd,KAAK;MACL,WAAW;MACX,GAAI;MACJ,YAAW;MACX,aAAY;KACb,GAdM,CAcN,CACF;KACA,EAAS,KAAK,MAAQ;MAGrB,IAAM,IAAe,GAAgB,SAAS,CAAG,GAC3C,IAAW,IAAe,IAC1B,IACJ,CAAC,MAAiB,GAAU,YAAY,IACpC,IAAY,GAAU,WAAW,GAGjC,IAAY,CAAC,MAAiB,KAAiB,IAC/C,IAAe,GAAU,UAAU,MAAc,UACjD,IAAc,GAAU,aAAa,GACrC,IACJ,GAAU,iBAAiB;MAC7B,OACE,kBAAC,IAAD;OAEE,MAAM,EAAS,CAAG;OAClB,SAAS;OACT,QAAQ,EAAS,CAAG;OACpB,aAAa,GAAU,eAAe;OACtC,iBAAiB,KAAgB,IAAe,QAAQ,KAAA;OACxD,eAAe,IAAe,KAAM,KAAA;OACpC,KAAK,IAAa,EAAE,GAAG,EAAU,IAAI;OACrC,WAAW,IAAY,EAAE,GAAG,IAAY,EAAE,IAAI;OAChC;OACd,GAAI;OAEH,UAAA,KACC,kBAAC,IAAD;QACE,SAAS;QACT,UAAU;QACV,WAAW,EAAiB,EAAc;QAC1C,WAAW,GAAsB,CAAmB;QACpD,UAAA;OACD,CAAA;MAEC,GArBC,CAqBD;KAEV,CAAC;KAEA,GAAe,KAAK,GAAK,MAAU;MAClC,IAAM,IAAQ,GAA2B,GAAK,GAAM,CAAQ;MAE5D,OADI,MAAU,KAAA,IAAkB,OAE9B,kBAAC,IAAD;OAEE,GAAG;OACH,GAAI,GAA0B,EAAI,OAAO,EAAI,aAAa;MAC3D,GAHM,GAAG,EAAI,SAAS,MAAM,GAAG,GAG/B;KAEL,CAAC;KACA,MACC,kBAAC,GAAD;MACE,SAAS;MACT,eAAe;MACf,GAAI,EAAkB;OAAE;OAAa;MAAe,CAAC;KACtD,CAAA;IAEM;;EACG,CAAA;CACb,CAAA;AAET,CACF;AACA,EAAU,cAAc"}
1
+ {"version":3,"file":"line-chart.js","names":[],"sources":["../../../../src/components/ui/line-chart/line-chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n Area,\n Brush,\n CartesianGrid,\n ComposedChart,\n LabelList,\n Line,\n LineChart as RechartsLineChart,\n ReferenceLine,\n Text,\n XAxis,\n YAxis,\n useXAxisScale,\n usePlotArea,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n CHART_LABEL_FONT_SIZE,\n CHART_LABEL_MARGIN,\n ChartContainer,\n ChartLegend,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n resolveAxisDomain,\n resolveBrushProps,\n dropProjectionPayload,\n resolveChartReferenceValue,\n resolveLabelFillClass,\n resolveReferenceLineProps,\n resolveRotatedTickAnchor,\n resolveXAxisHeight,\n resolveXAxisTitle,\n resolveYAxisTitle,\n toLabelFormatter,\n toReferenceLineList,\n type ChartConfig,\n type ChartPalette,\n type ChartLegendContentProps,\n type ChartTooltipContentProps,\n type CartesianChartProps,\n type ChartAnimationProps,\n type ChartBrushProps,\n type ChartCurveType,\n type ChartDataLabelProps,\n type ChartReferenceLine,\n type CartesianLabelPosition,\n} from '../chart';\n\n// A typed recharts composition over the shared `Chart` primitives. The two CVA\n// axes are the design's Line-chart variant set: `curve` (how the segments\n// interpolate between points — straight, smoothed, or stepped; the seven values\n// are documented on the shared `ChartCurveType`) and `lineStyle` (a solid or\n// dashed stroke). \"single\" vs \"multi\" line is not a variant — it\n// falls out of how many `dataKeys` the caller plots. The classes stay empty\n// because recharts' SVG — not CSS — draws the lines: `curve` drives each\n// `<Line type>` and `lineStyle` drives its `strokeDasharray`. CVA is kept so the\n// variant set is a first-class, spec-conformant part of the API (matched against\n// ui-spec's api.yaml enums) and exposed via `VariantProps`; the resolved values\n// are also mirrored onto `data-curve` / `data-line-style` for styling hooks and\n// tests.\nconst lineChartVariants = cva('', {\n variants: {\n curve: {\n linear: '',\n monotone: '',\n natural: '',\n basis: '',\n step: '',\n stepBefore: '',\n stepAfter: '',\n },\n lineStyle: {\n solid: '',\n dashed: '',\n },\n },\n defaultVariants: {\n curve: 'monotone',\n lineStyle: 'solid',\n },\n});\n\n// Renders two <clipPath> defs (actual / projection), a CSS <style> that clips\n// each recharts Line layer to its half, and a dashed separator line at the\n// visual midpoint between the last actual tick and the first projection tick.\n//\n// recharts' StaticCurve explicitly overwrites any clipPath prop passed to\n// <Line> with its own plot-area URL, so the prop-based approach used by\n// <Area> cannot be used here. Instead we apply CSS clip-path to the outer <g>\n// that recharts wraps each Line series in (targeted via a unique className we\n// set on the <Line> component). CSS clip-path on a class selector (specificity\n// 0,1,0) beats the SVG presentation attribute recharts sets on the inner\n// <path> (specificity 0), so the two clips compose: outer = our half, inner =\n// recharts' plot-area — net effect is the correct half within the plot area.\nfunction ProjectionClip({\n projectionStart,\n prevTick,\n clipId,\n dataKeys,\n}: {\n projectionStart: string | number;\n prevTick: string | number;\n clipId: string;\n dataKeys: string[];\n}) {\n const xScale = useXAxisScale();\n const plotArea = usePlotArea();\n if (!xScale || !plotArea) return null;\n const prevX = xScale(prevTick as string);\n const currX = xScale(projectionStart as string);\n if (prevX == null || currX == null) return null;\n const midX = (prevX + currX) / 2;\n const { x, y, width, height } = plotArea;\n const css = dataKeys\n .map(\n (_, i) =>\n `.actual-${clipId}-${i}{clip-path:url(#${clipId}-actual)}` +\n `.proj-${clipId}-${i}{clip-path:url(#${clipId}-projection)}`\n )\n .join('');\n return (\n <>\n <defs>\n <clipPath id={`${clipId}-actual`}>\n <rect x={x} y={y} width={midX - x} height={height} />\n </clipPath>\n <clipPath id={`${clipId}-projection`}>\n <rect x={midX} y={y} width={x + width - midX} height={height} />\n </clipPath>\n </defs>\n <style>{css}</style>\n <line\n x1={midX}\n y1={y}\n x2={midX}\n y2={y + height}\n stroke=\"var(--ui-border-on-surface-border)\"\n strokeDasharray=\"4 4\"\n />\n </>\n );\n}\n\n// Reserved field prefix for the synthetic delta-band range series. Each band\n// mints one `__band_<n>` field that feeds an <Area>; it must never surface in\n// the tooltip or legend (those describe only real, caller-supplied series).\nconst BAND_FIELD_PREFIX = '__band_';\n\n/**\n * Drop the synthetic delta-band range series from a recharts tooltip/legend\n * payload, keeping the real series (and their order). recharts already excludes\n * the band via `legendType`/`tooltipType=\"none\"`, so this is a second, explicit\n * guard — hence it's unit-tested rather than relying on that behavior.\n */\nexport function dropBandSeries<T extends { dataKey?: unknown }>(\n payload: readonly T[] | undefined\n): T[] | undefined {\n return payload?.filter(\n (item) => !String(item.dataKey).startsWith(BAND_FIELD_PREFIX)\n );\n}\n\ntype TooltipContentType = NonNullable<\n React.ComponentProps<typeof ChartTooltip>['content']\n>;\ntype TooltipContentFn = Extract<TooltipContentType, (...args: never[]) => unknown>;\ntype LegendContentFn = Extract<\n React.ComponentProps<typeof ChartLegend>['content'],\n (...args: never[]) => unknown\n>;\ntype LegendContentProps = Parameters<LegendContentFn>[0];\ntype TooltipRenderProps = Parameters<TooltipContentFn>[0];\n\n/**\n * Wrap a caller-supplied `tooltipContent` so the synthetic delta bands are\n * stripped from the payload before it renders, while preserving recharts' own\n * mount semantics — a function is mounted via `createElement` (its own component\n * identity + hook state), an element via `cloneElement`. This mirrors what the\n * pass-through charts get by handing `content` straight to recharts, so a\n * function-form tooltip keeps its state across re-renders here too. The returned\n * component is a stable content type (memoize it on `tooltipContent`).\n */\nexport function createBandStrippedTooltip(tooltipContent: TooltipContentType) {\n return function BandStrippedTooltip(props: TooltipRenderProps) {\n const merged = {\n ...props,\n payload: dropBandSeries(props.payload),\n } as TooltipRenderProps;\n if (typeof tooltipContent === 'function') {\n const Comp = tooltipContent as React.FunctionComponent<TooltipRenderProps>;\n return <Comp {...merged} />;\n }\n // Element-form tooltip: cloneElement is the React-idiomatic way to\n // re-render an existing element with new props (preserves refs & keys).\n return React.cloneElement(tooltipContent, merged);\n };\n}\n\nfunction createProjectionTooltip(tooltipContent: TooltipContentType) {\n return function ProjectionTooltip(props: TooltipRenderProps) {\n const merged = {\n ...props,\n payload: dropProjectionPayload(props.payload),\n } as TooltipRenderProps;\n if (typeof tooltipContent === 'function') {\n const Comp = tooltipContent as React.FunctionComponent<TooltipRenderProps>;\n return <Comp {...merged} />;\n }\n // Element-form tooltip: cloneElement is the React-idiomatic way to\n // re-render an existing element with new props (preserves refs & keys).\n return React.cloneElement(tooltipContent, merged);\n };\n}\n\n/**\n * Style override for one series, keyed by its `dataKeys` entry. Anything left\n * unset falls back to the chart-wide prop, so an entry only states what differs\n * — e.g. one thicker, dashed \"target\" line among otherwise identical series.\n *\n * A series listed in `comparisonKeys` keeps its dashed, dimmed, dot-less\n * treatment: `color`, `strokeWidth` and `curveType` still apply to it, but\n * `showDots` / `dotSize` do not (the overlay is defined by having no dots).\n */\nexport interface LineChartLineSettings {\n /** Stroke color. Defaults to the series' `config` color. */\n color?: string;\n /** Stroke width. Defaults to the chart's `strokeWidth`. */\n strokeWidth?: number;\n /** Dash this series' stroke, whatever the chart-wide `lineStyle` is. */\n dashed?: boolean;\n /** Interpolation for this series only. Defaults to the chart's `curve`. */\n curveType?: ChartCurveType;\n /** Render this series' per-point dots. Defaults to the chart's `showDots`. */\n showDots?: boolean;\n /** Dot radius for this series, in px. Defaults to the chart's `dotSize`. */\n dotSize?: number;\n /** Show/hide this series' value labels, overriding the chart's `showLabels`. */\n showLabel?: boolean;\n /** Position of this series' value labels. Defaults to the chart's `labelPosition`. */\n labelPosition?: CartesianLabelPosition;\n}\n\nexport interface LineChartProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n VariantProps<typeof lineChartVariants>,\n CartesianChartProps,\n ChartAnimationProps,\n ChartBrushProps,\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-point data. Each object holds the category key + one numeric field per series (`null` breaks the line unless `connectNulls`). */\n data: ReadonlyArray<Record<string, string | number | null>>;\n /**\n * Per-series map of `label` / `icon` / `tone` (from the shared `Chart`\n * primitives). Series take their colour from the container's `palette`; each\n * entry maps a key to a `label` and an optional `tone`.\n */\n config: ChartConfig;\n /** Series to plot — one `<Line>` per key. Each must exist in `config` and in every data row. */\n dataKeys: string[];\n /**\n * Subset of `dataKeys` to render as comparison/trend overlays (e.g. a\n * previous quarter or year) — dashed, dimmed, and dot-less, so they read as\n * secondary to the current-period lines. Keeps each series' own `config` color.\n */\n comparisonKeys?: string[];\n /**\n * Pairs of `[currentKey, comparisonKey]` to shade a delta band between — a\n * dimmed area filling the gap between the two series at each point,\n * visualizing the QoQ/YoY difference. Tinted with the first key's `config`\n * color. Rows where either value isn't numeric are left un-banded.\n *\n * Each pair mints an internal `__band_<n>` field (kept out of the tooltip and\n * legend), so avoid data/`config` keys with that reserved prefix.\n */\n deltaBands?: Array<[string, string]>;\n /** Category axis key (the shared dimension across rows, e.g. `\"month\"`). */\n xKey: string;\n /** Stroke width of each line. */\n strokeWidth?: number;\n /** Render a dot at each data point. */\n showDots?: boolean;\n /** Radius of each point's dot, in px. Its hover dot is 2px larger. */\n dotSize?: number;\n /**\n * Enlarge the hovered point's dot. Defaults to following `showDots`, so pass\n * it explicitly to get hover dots on a dot-less line (`showDots={false}`\n * with `showActiveDot`) or a static-only line (dots without the hover one).\n */\n showActiveDot?: boolean;\n /** Bridge `null` gaps in the data instead of breaking the line. */\n connectNulls?: boolean;\n /**\n * Per-series style overrides, keyed by `dataKeys` entry. Series with no entry\n * render from the chart-wide props.\n */\n lineSettings?: Record<string, LineChartLineSettings>;\n /**\n * One or more dashed reference/average lines on the value axis — a target, a\n * threshold, or a series mean. Pass a single object or an array to draw\n * several at once.\n */\n referenceLine?: ChartReferenceLine | ChartReferenceLine[];\n /**\n * The category value (matching an `xKey` entry) at which the projection\n * zone starts. Ticks from this point onward render in the disabled text\n * color (`--ui-text-on-surface-disabled`). The chart data and series\n * themselves are not affected — only the X-axis tick appearance changes.\n *\n * Use this when displaying a forecast/projection range where future\n * data points should be visually de-emphasized on the axis.\n */\n projectionStart?: string | number;\n showLegend?: boolean;\n /** Position of the value labels when `showLabels` is on. Defaults to `top`. */\n labelPosition?: CartesianLabelPosition;\n}\n\nconst LineChart = React.forwardRef<HTMLDivElement, LineChartProps>(\n (\n {\n className,\n config,\n palette,\n data,\n dataKeys,\n comparisonKeys,\n deltaBands,\n xKey,\n xAxisLabel,\n yAxisLabel,\n yUnit,\n curve = 'monotone',\n lineStyle = 'solid',\n strokeWidth = 2,\n showDots = false,\n dotSize = 3,\n showActiveDot,\n connectNulls = false,\n lineSettings,\n referenceLine,\n projectionStart,\n showGrid = true,\n showTooltip = true,\n showLegend = true,\n showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed,\n gridHorizontal,\n gridVertical,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n showLabels = false,\n labelPosition,\n labelFormatter,\n showBrush = false,\n brushHeight,\n brushAriaLabel,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n const lineLabelPosition = labelPosition ?? 'top';\n const yDomain = resolveAxisDomain(yAxisDomain);\n const referenceLines = toReferenceLineList(referenceLine);\n\n // A series' own `color` and `curveType` overrides also drive its delta band,\n // so the band keeps following the line it belongs to instead of the\n // chart-wide defaults.\n const colorFor = (key: string) =>\n lineSettings?.[key]?.color ?? `var(--color-${key})`;\n const curveFor = (key: string) =>\n lineSettings?.[key]?.curveType ?? curve ?? 'monotone';\n\n // The plot inset is needed as soon as *any* series carries outside labels —\n // a per-series `showLabel` counts, not only the chart-wide `showLabels`.\n const hasLabels =\n showLabels ||\n Object.values(lineSettings ?? {}).some((settings) => settings.showLabel);\n\n const xAxisHeight = resolveXAxisHeight(xAxisLabel, xAxisAngle);\n\n const projStartIndex = React.useMemo(() => {\n if (projectionStart === undefined) return -1;\n return data.findIndex((row) => row[xKey] === projectionStart);\n }, [projectionStart, data, xKey]);\n // projStartIndex === 0 (boundary at the first tick) is excluded: there is no\n // \"previous tick\" to define the clip midpoint, so clipPath defs can't be\n // emitted, which would make all series invisible. Treat it as no-projection.\n const hasProjection = projStartIndex > 0;\n\n // Build the projection tick renderer when projectionStart is set. Each tick\n // past (and including) the start value renders in the disabled text color;\n // ticks before it stay in the muted-foreground color. Returns undefined when\n // projectionStart is absent or not found so recharts uses its own renderer.\n const projectionTick = React.useMemo(() => {\n if (!hasProjection) return undefined;\n const projectedValues = new Set(\n data.slice(projStartIndex).map((row) => row[xKey])\n );\n const ProjectionTick = ({\n payload,\n index,\n ...tickProps\n }: {\n payload: { value: string | number };\n index?: number;\n [key: string]: unknown;\n }) => (\n <Text\n {...(tickProps as React.ComponentProps<typeof Text>)}\n fontSize={12}\n className={\n projectedValues.has(payload.value)\n ? 'fill-[var(--ui-text-on-surface-disabled)]'\n : 'fill-muted-foreground'\n }\n >\n {xTickFormatter\n ? xTickFormatter(payload.value as never, index)\n : payload.value}\n </Text>\n );\n return ProjectionTick;\n }, [hasProjection, projStartIndex, data, xKey, xTickFormatter]);\n\n // When projection is active, copy each series value to `_proj_${key}` — same\n // data, no nulls. Both the actual and projection <Line> see the identical curve;\n // the clipPath (computed in ProjectionClip) restricts which half each paints.\n const projectionData = React.useMemo(() => {\n if (!hasProjection) return data;\n return data.map((row) => ({\n ...row,\n ...Object.fromEntries(\n dataKeys.map((k) => [`_proj_${k}`, row[k]])\n ),\n }));\n }, [hasProjection, data, dataKeys]);\n\n // The tick immediately before the projection boundary — needed to compute the\n // visual midpoint where the clip edge and separator line are placed.\n const prevTickValue = React.useMemo(() => {\n if (projStartIndex <= 0) return undefined;\n return data[projStartIndex - 1]?.[xKey];\n }, [projStartIndex, data, xKey]);\n\n const clipId = `line-proj-${React.useId().replace(/:/g, '')}`;\n\n // Memoized so recharts sees a stable content type across renders — a fresh\n // wrapper each render would remount the caller's tooltip and reset its state.\n const customTooltip = React.useMemo(() => {\n if (!tooltipContent) return undefined;\n const bandStripped = createBandStrippedTooltip(tooltipContent);\n return hasProjection ? createProjectionTooltip(bandStripped) : bandStripped;\n }, [tooltipContent, hasProjection]);\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(xAxisLabel);\n const yAxisTitle = resolveYAxisTitle(yAxisLabel);\n\n // Each delta band becomes a synthetic `[min, max]` range field per row that\n // a recharts <Area> shades. Rows where either series isn't numeric are left\n // un-banded (the area breaks there).\n const bands = (deltaBands ?? []).map(([current, comparison], index) => ({\n field: `${BAND_FIELD_PREFIX}${index}`,\n current,\n comparison,\n }));\n\n // A delta band is a synthetic `__band_*` series feeding an <Area>, not a\n // trend of its own — so it has to be stripped from the tooltip rows and the\n // legend entries before either is rendered. A caller's own tooltip is\n // already wrapped for that above; these cover the two default contents.\n const hasBands = bands.length > 0;\n const tooltipNode =\n customTooltip ??\n (hasBands || hasProjection ? (\n (props: TooltipRenderProps) => (\n <ChartTooltipContent\n active={props.active}\n label={props.label}\n payload={\n dropProjectionPayload(\n dropBandSeries(props.payload)\n ) as ChartTooltipContentProps['payload']\n }\n />\n )\n ) : (\n <ChartTooltipContent />\n ));\n const legendNode = hasBands || hasProjection ? (\n (props: LegendContentProps) => (\n <ChartLegendContent\n verticalAlign={props.verticalAlign}\n payload={\n dropProjectionPayload(\n dropBandSeries(props.payload)\n ) as ChartLegendContentProps['payload']\n }\n />\n )\n ) : (\n <ChartLegendContent />\n );\n // Bands are computed over the full (projection-augmented) rows; when\n // projection is active the band <Area> is clipped to the actual zone.\n const chartData = bands.length\n ? projectionData.map((row) => {\n const augmented: Record<string, unknown> = { ...row };\n for (const { field, current, comparison } of bands) {\n const a = row[current];\n const b = row[comparison];\n augmented[field] =\n typeof a === 'number' && typeof b === 'number'\n ? [Math.min(a, b), Math.max(a, b)]\n : undefined;\n }\n return augmented;\n })\n : projectionData;\n\n // Only a delta band needs an <Area>, which recharts renders under\n // ComposedChart, not LineChart. Escalate to ComposedChart only then, so\n // plain line charts keep the LineChart base (and their baselines) untouched.\n const RootChart = bands.length > 0 ? ComposedChart : RechartsLineChart;\n\n return (\n <div\n ref={ref}\n data-curve={curve}\n data-line-style={lineStyle}\n className={cn(lineChartVariants({ curve, lineStyle }), className)}\n {...props}\n >\n <ChartContainer\n config={config}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RootChart\n data={chartData as readonly unknown[]}\n margin={hasLabels ? CHART_LABEL_MARGIN : undefined}\n >\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? false}\n strokeDasharray={gridDashed ? '3 3' : undefined}\n />\n )}\n <XAxis\n dataKey={xKey}\n type=\"category\"\n hide={!showXAxis}\n tickLine={false}\n axisLine={false}\n tickMargin={8}\n tickFormatter={projectionTick ? undefined : xTickFormatter}\n tick={projectionTick}\n angle={xAxisAngle}\n interval={xAxisInterval}\n textAnchor={resolveRotatedTickAnchor(xAxisAngle)}\n height={xAxisHeight}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n hide={!showYAxis}\n tickLine={false}\n axisLine={false}\n unit={yUnit}\n tickFormatter={yTickFormatter}\n tickCount={yAxisTickCount}\n domain={yDomain}\n width={yAxisLabel ? 72 : undefined}\n label={yAxisTitle}\n />\n {showTooltip && <ChartTooltip content={tooltipNode} />}\n {showLegend && <ChartLegend content={legendNode} />}\n {hasProjection && prevTickValue != null && (\n <ProjectionClip\n projectionStart={projectionStart!}\n prevTick={prevTickValue}\n clipId={clipId}\n dataKeys={dataKeys}\n />\n )}\n {/* Delta bands render before the lines so the lines draw on top.\n When projection is active, clip bands to the actual zone — the\n comparison series they measure against is absent past the\n boundary, so an unclipped band would shade a region with no\n visible far edge. */}\n {bands.map(({ field, current }) => (\n <Area\n key={field}\n dataKey={field}\n // An <Area> takes one interpolation, so a pair whose two series\n // set different `curveType`s can only follow the current one.\n type={curveFor(current)}\n stroke=\"none\"\n fill={colorFor(current)}\n fillOpacity={0.12}\n connectNulls={connectNulls}\n dot={false}\n activeDot={false}\n clipPath={hasProjection ? `url(#${clipId}-actual)` : undefined}\n {...animation}\n legendType=\"none\"\n tooltipType=\"none\"\n />\n ))}\n {dataKeys.map((key, index) => {\n // Comparison series read as secondary: always dashed, dimmed, and\n // dot-less, regardless of the global lineStyle / showDots.\n const isComparison = comparisonKeys?.includes(key);\n const settings = lineSettings?.[key];\n const seriesDots =\n !isComparison && (settings?.showDots ?? showDots);\n const dotRadius = settings?.dotSize ?? dotSize;\n // The hover dot follows the static dots unless asked otherwise, so\n // a chart that sets neither renders exactly as before.\n const activeDot = !isComparison && (showActiveDot ?? seriesDots);\n const seriesDashed = settings?.dashed ?? lineStyle === 'dashed';\n const seriesLabel = settings?.showLabel ?? showLabels;\n const seriesLabelPosition =\n settings?.labelPosition ?? lineLabelPosition;\n // Comparison series have no projection counterpart — they render\n // unclipped across the full width so they don't vanish at the\n // projection boundary.\n return (\n <Line\n key={key}\n className={hasProjection && !isComparison ? `actual-${clipId}-${index}` : undefined}\n type={curveFor(key)}\n dataKey={key}\n stroke={colorFor(key)}\n strokeWidth={settings?.strokeWidth ?? strokeWidth}\n strokeDasharray={isComparison || seriesDashed ? '5 5' : undefined}\n strokeOpacity={isComparison ? 0.5 : undefined}\n dot={seriesDots ? { r: dotRadius } : false}\n activeDot={activeDot ? { r: dotRadius + 2 } : false}\n connectNulls={connectNulls}\n {...animation}\n >\n {seriesLabel && (\n <LabelList\n dataKey={key}\n position={seriesLabelPosition}\n formatter={toLabelFormatter(labelFormatter)}\n className={resolveLabelFillClass(seriesLabelPosition)}\n fontSize={CHART_LABEL_FONT_SIZE}\n />\n )}\n </Line>\n );\n })}\n {hasProjection &&\n dataKeys.map((key, index) => {\n const isComparison = comparisonKeys?.includes(key);\n if (isComparison) return null;\n const settings = lineSettings?.[key];\n return (\n <Line\n key={`_proj_${key}`}\n className={`proj-${clipId}-${index}`}\n type={curveFor(key)}\n dataKey={`_proj_${key}`}\n name={key}\n stroke={colorFor(key)}\n strokeWidth={settings?.strokeWidth ?? strokeWidth}\n strokeDasharray=\"5 5\"\n dot={false}\n activeDot={false}\n legendType=\"none\"\n tooltipType=\"none\"\n {...animation}\n />\n );\n })}\n {/* Annotations draw over the series they describe. */}\n {referenceLines.map((ref, index) => {\n const value = resolveChartReferenceValue(ref, data, dataKeys);\n if (value === undefined) return null;\n return (\n <ReferenceLine\n key={`${ref.label ?? 'ref'}-${index}`}\n y={value}\n {...resolveReferenceLineProps(ref.label, ref.labelPosition)}\n />\n );\n })}\n {showBrush && (\n <Brush\n dataKey={xKey}\n tickFormatter={xTickFormatter}\n {...resolveBrushProps({ brushHeight, brushAriaLabel })}\n />\n )}\n </RootChart>\n </ChartContainer>\n </div>\n );\n }\n);\nLineChart.displayName = 'LineChart';\n\nexport { LineChart, lineChartVariants };\n"],"mappings":"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"}
@@ -1,27 +1,27 @@
1
1
  "use client";
2
2
  import { cn as e } from "../../../lib/utils.js";
3
3
  import { cva as t } from "../../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.js";
4
- import { ChartContainer as n, ChartLegend as r, ChartLegendContent as i, ChartTooltip as a, ChartTooltipContent as ee } from "../chart/chart.js";
5
- import { resolveAnimation as o, resolveLabelFillClass as s, toLabelFormatter as c } from "../chart/chart-format.js";
4
+ import { ChartContainer as n, ChartLegend as r, ChartLegendContent as i, ChartTooltip as a, ChartTooltipContent as o } from "../chart/chart.js";
5
+ import { resolveAnimation as ee, resolveLabelFillClass as s, toLabelFormatter as c } from "../chart/chart-format.js";
6
6
  import * as l from "react";
7
- import { jsx as u, jsxs as d } from "react/jsx-runtime";
8
- import { LabelList as f, PolarAngleAxis as te, PolarGrid as p, PolarRadiusAxis as m, Radar as h, RadarChart as g } from "recharts";
7
+ import { jsx as u, jsxs as te } from "react/jsx-runtime";
8
+ import { LabelList as d, PolarAngleAxis as f, PolarGrid as ne, PolarRadiusAxis as re, Radar as p, RadarChart as ie } from "recharts";
9
9
  //#region src/components/ui/radar-chart/radar-chart.tsx
10
- var _ = t("", {
10
+ var m = t("", {
11
11
  variants: { gridType: {
12
12
  polygon: "",
13
13
  circle: ""
14
14
  } },
15
15
  defaultVariants: { gridType: "polygon" }
16
16
  });
17
- function v(e, t) {
17
+ function h(e, t) {
18
18
  switch (e) {
19
19
  case "auto": return ["auto", "auto"];
20
20
  case "fixed": return [0, t !== void 0 && Number.isFinite(t) && t > 0 ? t : "auto"];
21
21
  default: return;
22
22
  }
23
23
  }
24
- function y(e, t, n) {
24
+ function g(e, t, n) {
25
25
  let r = t?.color ?? `var(--color-${e})`, i = t?.dot ?? n.showDots;
26
26
  return {
27
27
  fill: r,
@@ -32,9 +32,19 @@ function y(e, t, n) {
32
32
  activeDot: t?.activeDot ?? n.activeDot
33
33
  };
34
34
  }
35
- var ne = 30;
36
- function re({ seriesKey: e, style: t, animation: n, showLabels: r, labelPosition: i, labelFormatter: a }) {
37
- return /* @__PURE__ */ u(h, {
35
+ var _ = 30, ae = 8, v = 187, y = 240, b = 32;
36
+ function x(e, t) {
37
+ let n = e !== void 0 && e > v / 2, r = n ? y : v;
38
+ return t ? {
39
+ heightClass: n ? "h-[272px]" : "h-[219px]",
40
+ cy: `${Math.floor(r / 2 / (r + b) * 1e5) / 1e3}%`
41
+ } : {
42
+ heightClass: n ? "h-[240px]" : "h-[187px]",
43
+ cy: void 0
44
+ };
45
+ }
46
+ function oe({ seriesKey: e, style: t, animation: n, showLabels: r, labelPosition: i, labelFormatter: a }) {
47
+ return /* @__PURE__ */ u(p, {
38
48
  dataKey: e,
39
49
  stroke: t.stroke,
40
50
  fill: t.fill,
@@ -43,7 +53,7 @@ function re({ seriesKey: e, style: t, animation: n, showLabels: r, labelPosition
43
53
  dot: t.dot,
44
54
  activeDot: t.activeDot,
45
55
  ...n,
46
- children: r && /* @__PURE__ */ u(f, {
56
+ children: r && /* @__PURE__ */ u(d, {
47
57
  dataKey: e,
48
58
  position: i,
49
59
  formatter: c(a),
@@ -52,80 +62,80 @@ function re({ seriesKey: e, style: t, animation: n, showLabels: r, labelPosition
52
62
  })
53
63
  }, e);
54
64
  }
55
- var b = l.forwardRef(({ className: t, config: s, palette: c, data: l, dataKeys: f, angleKey: h, seriesSettings: b, gridType: x = "polygon", fillOpacity: S = .3, strokeWidth: C = 2, showDots: w = !1, dotRadius: T = 3, activeDot: E, showGrid: D = !0, radialLines: O = !0, showAngleAxis: k = !0, angleAxisOrientation: A, angleAxisLine: j = !0, angleAxisLineType: M, angleTickLine: N = !0, angleTickSize: P, showRadiusAxis: F = !1, radiusAxisAngle: I, radiusAxisOrientation: L, radiusAxisDomain: R, radiusAxisDomainMax: z, radiusAxisTickCount: ie, radiusAxisReversed: B = !1, cx: V, cy: H, startAngle: U, endAngle: W, innerRadius: G, outerRadius: K, margin: q, showTooltip: J = !0, showLegend: Y = !0, legendPosition: X = "bottom", tooltipContent: ae, animate: oe, animationDuration: se, animationBegin: ce, animationEasing: Z, showLabels: Q = !1, labelPosition: le, labelFormatter: ue, ...de }, fe) => {
56
- let pe = o({
57
- animate: oe,
58
- animationDuration: se,
59
- animationBegin: ce,
60
- animationEasing: Z
61
- }), me = le ?? "top", $ = v(R, z), he = F || $ !== void 0 || B, ge = {
62
- fillOpacity: S,
63
- strokeWidth: C,
64
- showDots: w,
65
- dotRadius: T,
66
- activeDot: E
67
- };
65
+ var S = l.forwardRef(({ className: t, config: s, palette: c, data: l, dataKeys: d, angleKey: p, seriesSettings: v, gridType: y = "polygon", fillOpacity: b = .3, strokeWidth: S = 2, showDots: C = !0, dotRadius: w = 2, activeDot: T, showGrid: E = !0, radialLines: D = !0, showAngleAxis: O = !0, angleAxisOrientation: k, angleAxisLine: A = !0, angleAxisLineType: j, angleTickLine: M = !0, angleTickSize: N, showRadiusAxis: P = !1, radiusAxisAngle: F, radiusAxisOrientation: I, radiusAxisDomain: L, radiusAxisDomainMax: R, radiusAxisTickCount: z, radiusAxisReversed: B = !1, cx: V, cy: H, startAngle: se, endAngle: U, innerRadius: W, outerRadius: G, margin: K, showTooltip: ce = !0, showLegend: q = !0, tooltipContent: le, animate: ue, animationDuration: de, animationBegin: fe, animationEasing: pe, showLabels: J = !1, labelPosition: me, labelFormatter: he, ...ge }, _e) => {
66
+ let Y = ee({
67
+ animate: ue,
68
+ animationDuration: de,
69
+ animationBegin: fe,
70
+ animationEasing: pe
71
+ }), ve = me ?? "top", X = h(L, R), ye = P || X !== void 0 || B, be = {
72
+ fillOpacity: b,
73
+ strokeWidth: S,
74
+ showDots: C,
75
+ dotRadius: w,
76
+ activeDot: T
77
+ }, Z = G ?? 78, Q = N ?? (J ? _ : 4), $ = x(typeof Z == "number" ? Z + Q + ae : void 0, q), xe = /(?:^|\s)(?:h-|size-|min-h-|max-h-)/.test(t ?? "");
68
78
  return /* @__PURE__ */ u("div", {
69
- ref: fe,
70
- "data-grid-type": x,
71
- className: e(_({ gridType: x }), t),
72
- ...de,
79
+ ref: _e,
80
+ "data-grid-type": y,
81
+ className: e(m({ gridType: y }), $.heightClass, t),
82
+ ...ge,
73
83
  children: /* @__PURE__ */ u(n, {
74
84
  config: s,
75
85
  palette: c,
76
- className: "size-full [&_.recharts-polar-angle-axis-tick_text]:fill-muted-foreground [&_.recharts-polar-radius-axis-line]:stroke-border [&_.recharts-polar-radius-axis-tick_text]:fill-muted-foreground",
77
- children: /* @__PURE__ */ d(g, {
86
+ className: e("size-full", "[&_.recharts-polar-angle-axis-tick_text]:fill-[var(--ui-text-on-surface-secondary)]! [&_.recharts-polar-angle-axis-tick_text]:text-xs [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-[var(--ui-border-on-surface-divider)]! [&_.recharts-polar-radius-axis-line]:stroke-[var(--ui-border-on-surface-divider)]! [&_.recharts-polar-radius-axis-tick_text]:fill-[var(--ui-text-on-surface-secondary)]! [&_.recharts-polar-radius-axis-tick_text]:text-xs"),
87
+ children: /* @__PURE__ */ te(ie, {
78
88
  data: l,
79
89
  cx: V,
80
- cy: H,
81
- startAngle: U,
82
- endAngle: W,
83
- innerRadius: G,
84
- outerRadius: K,
85
- margin: q,
90
+ cy: H ?? (xe ? void 0 : $.cy),
91
+ startAngle: se,
92
+ endAngle: U,
93
+ innerRadius: W,
94
+ outerRadius: Z,
95
+ margin: K,
86
96
  children: [
87
- J && /* @__PURE__ */ u(a, { content: ae ?? /* @__PURE__ */ u(ee, {}) }),
88
- D && /* @__PURE__ */ u(p, {
89
- gridType: x ?? "polygon",
90
- radialLines: O
97
+ ce && /* @__PURE__ */ u(a, { content: le ?? /* @__PURE__ */ u(o, {}) }),
98
+ E && /* @__PURE__ */ u(ne, {
99
+ gridType: y ?? "polygon",
100
+ radialLines: D
91
101
  }),
92
- /* @__PURE__ */ u(te, {
93
- dataKey: h,
94
- orientation: A,
95
- axisLineType: M,
96
- tick: k,
97
- axisLine: k && j,
98
- tickLine: k && N,
99
- tickSize: P ?? (Q ? ne : void 0)
102
+ /* @__PURE__ */ u(f, {
103
+ dataKey: p,
104
+ orientation: k,
105
+ axisLineType: j,
106
+ tick: O,
107
+ axisLine: O && A,
108
+ tickLine: O && M,
109
+ tickSize: Q
100
110
  }),
101
- he && /* @__PURE__ */ u(m, {
102
- angle: I,
103
- orientation: L,
104
- domain: $,
105
- tickCount: ie,
111
+ ye && /* @__PURE__ */ u(re, {
112
+ angle: F,
113
+ orientation: I,
114
+ domain: X,
115
+ tickCount: z,
106
116
  reversed: B,
107
- tick: F,
108
- axisLine: F
117
+ tick: P,
118
+ axisLine: P
109
119
  }),
110
- Y && /* @__PURE__ */ u(r, {
111
- verticalAlign: X,
112
- content: /* @__PURE__ */ u(i, { verticalAlign: X })
120
+ q && /* @__PURE__ */ u(r, {
121
+ verticalAlign: "bottom",
122
+ content: /* @__PURE__ */ u(i, { verticalAlign: "bottom" })
113
123
  }),
114
- f.map((e) => re({
124
+ d.map((e) => oe({
115
125
  seriesKey: e,
116
- style: y(e, b?.[e], ge),
117
- animation: pe,
118
- showLabels: Q,
119
- labelPosition: me,
120
- labelFormatter: ue
126
+ style: g(e, v?.[e], be),
127
+ animation: Y,
128
+ showLabels: J,
129
+ labelPosition: ve,
130
+ labelFormatter: he
121
131
  }))
122
132
  ]
123
133
  })
124
134
  })
125
135
  });
126
136
  });
127
- b.displayName = "RadarChart";
137
+ S.displayName = "RadarChart";
128
138
  //#endregion
129
- export { b as RadarChart, _ as radarChartVariants, v as radarRadiusAxisDomain, y as radarSeriesStyle };
139
+ export { S as RadarChart, m as radarChartVariants, x as radarPlotBox, h as radarRadiusAxisDomain, g as radarSeriesStyle };
130
140
 
131
141
  //# sourceMappingURL=radar-chart.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"radar-chart.js","names":[],"sources":["../../../../src/components/ui/radar-chart/radar-chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n LabelList,\n PolarAngleAxis,\n PolarGrid,\n PolarRadiusAxis,\n Radar,\n RadarChart as RechartsRadarChart,\n type AxisDomainItem,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartLegend,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n toLabelFormatter,\n resolveLabelFillClass,\n CHART_LABEL_FONT_SIZE,\n type ChartConfig,\n type ChartPalette,\n type ChartAnimationProps,\n type ChartDataLabelProps,\n type CartesianLabelPosition,\n type ResolvedAnimation,\n} from '../chart';\n\n// A typed recharts composition over the shared `Chart` primitives — the first\n// polar chart type. The single CVA axis is the design's Radar-chart variant set:\n// `gridType` (the polar web is drawn as straight-edged `polygon` rings or smooth\n// `circle` rings). The class stays empty because recharts' SVG — not CSS — draws\n// the web: `gridType` drives `<PolarGrid gridType>`. CVA is kept so the variant\n// set is a first-class, spec-conformant part of the API (matched against\n// ui-spec's api.yaml enums) and exposed via `VariantProps`; the resolved value is\n// also mirrored onto `data-grid-type`.\nconst radarChartVariants = cva('', {\n variants: {\n gridType: {\n polygon: '',\n circle: '',\n },\n },\n defaultVariants: {\n gridType: 'polygon',\n },\n});\n\n/** Per-series overrides, keyed by the series' `dataKeys` entry. */\nexport interface RadarChartSeriesSettings {\n /**\n * Fill for this series' area, overriding its `config` color. Reference an\n * existing semantic `--ui-*` token, same as `config`.\n */\n color?: string;\n /**\n * Outline color, when it should read differently from the fill (e.g. a solid\n * outline over a barely-tinted area). Defaults to the fill.\n *\n * recharts derives a Radar's legend/tooltip color from its stroke first, so\n * setting this alone also recolors that series' legend swatch and tooltip dot\n * — set `color` too if the marker should keep following the fill.\n */\n stroke?: string;\n /** Fill opacity for this series, overriding the chart-level `fillOpacity`. */\n fillOpacity?: number;\n /** Outline width for this series, overriding the chart-level `strokeWidth`. */\n strokeWidth?: number;\n /** Per-point dots for this series, overriding the chart-level `showDots`. */\n dot?: boolean;\n /** Dot radius for this series, overriding the chart-level `dotRadius`. */\n dotRadius?: number;\n /**\n * Highlight this series' hovered point, overriding the chart-level\n * `activeDot`.\n */\n activeDot?: boolean;\n}\n\n/**\n * Map the `radiusAxisDomain` preset to a recharts radius-axis `domain`. Exported\n * for unit tests; not part of the package's public API.\n *\n * The radius axis is what scales the web, so this is the difference between \"the\n * largest value in the data reaches the outer ring\" (recharts' own behavior, and\n * what an unset preset keeps) and \"the outer ring is a known maximum\" (`fixed`\n * plus `radiusAxisDomainMax`). The two only mean something together: a `fixed`\n * preset with no maximum falls back to the data's own top, i.e. that same\n * default.\n */\nexport function radarRadiusAxisDomain(\n preset: 'auto' | 'fixed' | undefined,\n max: number | undefined\n): Readonly<[AxisDomainItem, AxisDomainItem]> | undefined {\n switch (preset) {\n case 'auto':\n return ['auto', 'auto'];\n case 'fixed':\n // A maximum that isn't a positive, finite number can't bound a scale that\n // grows outward from 0: `[0, 0]` collapses the web onto its centre and a\n // negative inverts it. A computed max (`Math.max` over an empty or all-zero\n // series) reaches this, so fall back to the data's own top — the same\n // behavior as `fixed` with no maximum at all.\n return [0, max !== undefined && Number.isFinite(max) && max > 0 ? max : 'auto'];\n default:\n return undefined;\n }\n}\n\n/** The chart-level styling a `seriesSettings` entry overrides. */\nexport interface RadarSeriesDefaults {\n fillOpacity: number;\n strokeWidth: number;\n showDots: boolean;\n dotRadius: number;\n activeDot: boolean | undefined;\n}\n\n/** Resolved recharts `<Radar>` styling for one series. */\nexport interface RadarSeriesStyle {\n fill: string;\n stroke: string;\n fillOpacity: number;\n strokeWidth: number;\n dot: { r: number } | false;\n activeDot: boolean | undefined;\n}\n\n/**\n * Fold a series' `seriesSettings` entry over the chart-level styling. Exported\n * for unit tests; not part of the package's public API.\n *\n * Every fallback is `??`, not `||`, so a deliberate falsy override survives —\n * `fillOpacity: 0` (outline only), `strokeWidth: 0` (fill only), `dot: false`\n * and `activeDot: false` all have to beat a truthy chart-level value. An\n * un-overridden fill stays the `--color-<key>` custom property the shared\n * `ChartContainer` injects from `config`, so the series a caller doesn't name\n * keeps reading its config color.\n */\nexport function radarSeriesStyle(\n key: string,\n settings: RadarChartSeriesSettings | undefined,\n defaults: RadarSeriesDefaults\n): RadarSeriesStyle {\n const fill = settings?.color ?? `var(--color-${key})`;\n const dot = settings?.dot ?? defaults.showDots;\n return {\n fill,\n stroke: settings?.stroke ?? fill,\n fillOpacity: settings?.fillOpacity ?? defaults.fillOpacity,\n strokeWidth: settings?.strokeWidth ?? defaults.strokeWidth,\n dot: dot ? { r: settings?.dotRadius ?? defaults.dotRadius } : false,\n activeDot: settings?.activeDot ?? defaults.activeDot,\n };\n}\n\nexport interface RadarChartProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n VariantProps<typeof radarChartVariants>,\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 /**\n * Row-per-axis data. Each object holds the `angleKey` label + one numeric field\n * per series. Every plotted series needs a value in every row: recharts places a\n * missing one at the centre, which reads as a zero rather than as a gap.\n */\n data: ReadonlyArray<Record<string, string | number>>;\n /**\n * Per-series map of `label` / `icon` / `tone` (imported from the shared\n * `Chart` primitives). Turned into `--color-<key>` custom properties. Series\n * take their colour from the container's `palette`; each entry maps a key to a\n * `label` and an optional `tone`.\n */\n config: ChartConfig;\n /** Series to plot — one `<Radar>` per key. Each must exist in `config` and in every data row. */\n dataKeys: string[];\n /** The categorical axis key placed around the web (e.g. `\"subject\"`). */\n angleKey: string;\n /**\n * Per-series style overrides, keyed by a `dataKeys` entry — color, outline, and\n * dots for one series while the rest keep the chart-level values. Keys that\n * aren't plotted are ignored. An overridden `color` — or `stroke`, which\n * recharts reads first — follows through to that series' legend swatch and\n * tooltip dot.\n */\n seriesSettings?: Record<string, RadarChartSeriesSettings>;\n /** Fill opacity of each radar area. */\n fillOpacity?: number;\n /** Stroke width of each radar outline. */\n strokeWidth?: number;\n /** Render a dot at each axis point. */\n showDots?: boolean;\n /** Radius of the per-point dots when `showDots` is on. */\n dotRadius?: number;\n /**\n * Enlarge the hovered point's dot. On by default (recharts' behavior) — pass\n * `false` for a chart that shouldn't react to the pointer at all.\n */\n activeDot?: boolean;\n /** Render the polar grid (the web). */\n showGrid?: boolean;\n /**\n * Draw the grid's spokes — the radial lines from the centre out to each\n * category. Defaults to `true`; off leaves only the concentric rings.\n */\n radialLines?: boolean;\n /**\n * Render the categorical axis around the web (its spoke labels, tick lines,\n * and outer line). Defaults to `true`. Turning it off keeps the axis itself —\n * so the tooltip still names each category — and only hides its chrome.\n */\n showAngleAxis?: boolean;\n /** Place the spoke labels outside the web (default) or inside it. */\n angleAxisOrientation?: 'inner' | 'outer';\n /** Draw the line around the web that the spoke labels sit against. Defaults to `true`. */\n angleAxisLine?: boolean;\n /**\n * Shape of that line: straight-edged `polygon` (recharts' default) or a smooth\n * `circle`. Independent of `gridType`, so pair them to keep a circular web's\n * outline circular too.\n */\n angleAxisLineType?: 'polygon' | 'circle';\n /** Draw a tick line from the axis line to each spoke label. Defaults to `true`. */\n angleTickLine?: boolean;\n /**\n * Distance from the web to the spoke labels, in px (recharts' default is 8).\n * Left alone, `showLabels` widens it so a vertex's value can't land on its own\n * category label.\n */\n angleTickSize?: number;\n /**\n * Render the value scale — a radial axis of ticks from the centre outward, so\n * an area can be read as a number and not only compared to its neighbours.\n * Defaults to `false` (recharts draws no radius axis unless asked).\n *\n * `radiusAxisAngle` and `radiusAxisOrientation` only describe the drawn scale,\n * so they need it shown. `radiusAxisDomain`, `radiusAxisReversed` and\n * `radiusAxisTickCount` apply while it's hidden too — the first two scale the\n * web, and the third sets how many rings the grid draws (recharts takes the\n * grid's concentric radii from the radius axis' ticks).\n */\n showRadiusAxis?: boolean;\n /**\n * Angle the value scale is drawn at, in degrees counter-clockwise from 3\n * o'clock (recharts' default is `0`). Point it *between* two spokes: on a\n * spoke, the outermost tick collides with that category's own label.\n *\n * The ticks sit over the areas at any angle — a radar's plot area is its\n * areas — so this trades one overlap for none of the other.\n */\n radiusAxisAngle?: number;\n /** Which side of the scale its tick labels sit on. Defaults to `right`. */\n radiusAxisOrientation?: 'left' | 'right' | 'middle';\n /**\n * How the value scale is bounded — and with it the web, since the radius axis\n * is what maps a value to a radius:\n *\n * - unset — recharts' own scaling: the data's largest value reaches the outer\n * ring, so two charts of the same metric aren't comparable.\n * - `fixed` — pin the outer ring to `radiusAxisDomainMax` (the metric's own\n * maximum, e.g. a score out of 150), which is what makes a radar readable as\n * an absolute profile rather than a relative one.\n * - `auto` — fit the data at both ends; the scale need not start at 0.\n *\n * Takes effect whether or not the scale is shown, so a chart can be scaled to a\n * known maximum without displaying the ticks.\n */\n radiusAxisDomain?: 'auto' | 'fixed';\n /**\n * The value at the outer ring when `radiusAxisDomain` is `fixed`. Must be\n * positive — a `0` or negative maximum can't bound an outward-growing scale, so\n * it falls back to the data's own top.\n */\n radiusAxisDomainMax?: number;\n /**\n * Desired number of ticks on the value scale (a hint, not exact). Defaults to\n * recharts' `5`. Also sets how many rings the grid draws, whether or not the\n * scale itself is shown.\n */\n radiusAxisTickCount?: number;\n /**\n * Invert the value scale — the maximum at the centre and 0 at the outer ring —\n * for a metric where less is better (latency, error rate), so a good profile\n * still reads as a large area.\n */\n radiusAxisReversed?: boolean;\n /** Horizontal centre of the web, in px or a percentage of the width. Defaults to `50%`. */\n cx?: number | string;\n /** Vertical centre of the web, in px or a percentage of the height. Defaults to `50%`. */\n cy?: number | string;\n /** Angle the first category sits at, in degrees. Defaults to `90` (12 o'clock). */\n startAngle?: number;\n /**\n * Angle the sweep ends at, in degrees. Defaults to `-270` — a full turn\n * clockwise from `startAngle`. Together the two rotate the web (or wrap the\n * categories into a partial sweep).\n */\n endAngle?: number;\n /**\n * Radius of the hole at the centre, in px or a percentage of the available\n * radius. Defaults to `0`. Also lifts the grid and the areas off the centre,\n * which separates the series where they all bottom out.\n */\n innerRadius?: number | string;\n /** Outer radius of the web, in px or a percentage of the available radius. Defaults to `80%`. */\n outerRadius?: number | string;\n /**\n * Plot-area margin, in px. Omit it entirely to use recharts' default (5 on\n * every side) — passing the object replaces all four, and recharts fills the\n * sides you leave out with `0`, not with `5`. Name every side you want.\n */\n margin?: { top?: number; right?: number; bottom?: number; left?: number };\n showTooltip?: boolean;\n showLegend?: boolean;\n /** Which side of the chart the legend sits on. Defaults to `bottom`. */\n legendPosition?: 'top' | 'bottom';\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-series rows, or extra fields without composing\n * recharts yourself. Ignored when `showTooltip` is false.\n */\n tooltipContent?: React.ComponentProps<typeof ChartTooltip>['content'];\n /** Position of the value labels when `showLabels` is on. Defaults to `top`. */\n labelPosition?: CartesianLabelPosition;\n}\n\n// Distance from the polygon to the category tick text when value labels are on\n// (recharts' default is 8). Has to clear a CHART_LABEL_FONT_SIZE line plus the\n// LabelList's own 5px offset, or the topmost vertex's value overlaps its tick.\nconst RADAR_LABEL_TICK_SIZE = 30;\n\n/**\n * One series' `<Radar>` (and its value labels).\n *\n * Called as a plain function rather than mounted as `<RadarSeries />`, purely\n * to keep the chart's children readable as a flat list — recharts imposes no\n * constraint here. `RadarChart` picks up the series from the store `<Radar>`\n * registers itself in, and `Radar` passes its children straight through to a\n * label-list context instead of scanning them by type. `<Cell>` is the only\n * child recharts still looks up by element type, and a radar series has none.\n */\nfunction radarSeries({\n seriesKey,\n style,\n animation,\n showLabels,\n labelPosition,\n labelFormatter,\n}: {\n seriesKey: string;\n style: RadarSeriesStyle;\n animation: ResolvedAnimation;\n showLabels: boolean;\n labelPosition: CartesianLabelPosition;\n labelFormatter: ChartDataLabelProps['labelFormatter'];\n}) {\n return (\n <Radar\n key={seriesKey}\n dataKey={seriesKey}\n stroke={style.stroke}\n fill={style.fill}\n fillOpacity={style.fillOpacity}\n strokeWidth={style.strokeWidth}\n dot={style.dot}\n activeDot={style.activeDot}\n {...animation}\n >\n {showLabels && (\n <LabelList\n dataKey={seriesKey}\n position={labelPosition}\n formatter={toLabelFormatter(labelFormatter)}\n // A radar area is a flat `fillOpacity`, so an `inside*` label sits on\n // the *surface tinted by* the series color, not on the color itself —\n // the white on-fill token disappears into it in light mode. Same call\n // as the other translucent families (Area, the composed chart's areas).\n className={resolveLabelFillClass(labelPosition, {\n translucentSeries: true,\n })}\n fontSize={CHART_LABEL_FONT_SIZE}\n />\n )}\n </Radar>\n );\n}\n\nconst RadarChart = React.forwardRef<HTMLDivElement, RadarChartProps>(\n (\n {\n className,\n config,\n palette,\n data,\n dataKeys,\n angleKey,\n seriesSettings,\n gridType = 'polygon',\n fillOpacity = 0.3,\n strokeWidth = 2,\n showDots = false,\n dotRadius = 3,\n activeDot,\n showGrid = true,\n radialLines = true,\n showAngleAxis = true,\n angleAxisOrientation,\n angleAxisLine = true,\n angleAxisLineType,\n angleTickLine = true,\n angleTickSize,\n showRadiusAxis = false,\n radiusAxisAngle,\n radiusAxisOrientation,\n radiusAxisDomain,\n radiusAxisDomainMax,\n radiusAxisTickCount,\n radiusAxisReversed = false,\n cx,\n cy,\n startAngle,\n endAngle,\n innerRadius,\n outerRadius,\n margin,\n showTooltip = true,\n showLegend = true,\n legendPosition = 'bottom',\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n showLabels = false,\n labelPosition,\n labelFormatter,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n const radarLabelPosition = labelPosition ?? 'top';\n const radiusDomain = radarRadiusAxisDomain(\n radiusAxisDomain,\n radiusAxisDomainMax\n );\n // The radius axis is only mounted when it has something to do: it either\n // paints the scale, or it carries a domain/reversal that rescales the web\n // (recharts registers those from the element even when nothing is drawn).\n // Without one of the three, leaving the element out keeps recharts' own\n // implicit axis — and every existing chart's geometry.\n const hasRadiusAxis =\n showRadiusAxis || radiusDomain !== undefined || radiusAxisReversed;\n const seriesDefaults: RadarSeriesDefaults = {\n fillOpacity,\n strokeWidth,\n showDots,\n dotRadius,\n activeDot,\n };\n\n return (\n <div\n ref={ref}\n data-grid-type={gridType}\n className={cn(radarChartVariants({ gridType }), className)}\n {...props}\n >\n <ChartContainer\n config={config}\n palette={palette}\n // The shared container themes cartesian axis ticks but not polar ones,\n // so scope the angle-axis (spoke) labels and the radius-axis scale to\n // the muted-foreground / border tokens here — otherwise they render\n // near-black (or recharts' raw `#ccc`) and vanish in dark mode. This\n // is a shared-primitives gap (a Chart task); worked around locally, not\n // by editing chart.tsx.\n className=\"size-full [&_.recharts-polar-angle-axis-tick_text]:fill-muted-foreground [&_.recharts-polar-radius-axis-line]:stroke-border [&_.recharts-polar-radius-axis-tick_text]:fill-muted-foreground\"\n >\n <RechartsRadarChart\n data={data as readonly unknown[]}\n cx={cx}\n cy={cy}\n startAngle={startAngle}\n endAngle={endAngle}\n innerRadius={innerRadius}\n outerRadius={outerRadius}\n margin={margin}\n >\n {showTooltip && (\n <ChartTooltip content={tooltipContent ?? <ChartTooltipContent />} />\n )}\n {showGrid && (\n <PolarGrid gridType={gridType ?? 'polygon'} radialLines={radialLines} />\n )}\n <PolarAngleAxis\n dataKey={angleKey}\n orientation={angleAxisOrientation}\n axisLineType={angleAxisLineType}\n // `showAngleAxis` hides the chrome rather than dropping the axis:\n // the angle axis is also what maps a row to its category name, so\n // removing it would leave the tooltip labelling rows by index.\n tick={showAngleAxis}\n axisLine={showAngleAxis && angleAxisLine}\n tickLine={showAngleAxis && angleTickLine}\n // Push the category ticks out when value labels are on. recharts\n // gives a Radar's label list a *cartesian* viewBox (width/height 0\n // at the vertex), so `top` offsets straight up in screen space —\n // at the topmost vertex the value lands on its own category tick.\n // The tick text is drawn at `outerRadius + tickSize`, so this is\n // the only lever that adds *absolute* clearance: shrinking\n // outerRadius scales the tick ring down with the polygon and keeps\n // the overlap.\n tickSize={\n angleTickSize ?? (showLabels ? RADAR_LABEL_TICK_SIZE : undefined)\n }\n />\n {hasRadiusAxis && (\n <PolarRadiusAxis\n angle={radiusAxisAngle}\n orientation={radiusAxisOrientation}\n domain={radiusDomain}\n tickCount={radiusAxisTickCount}\n reversed={radiusAxisReversed}\n tick={showRadiusAxis}\n axisLine={showRadiusAxis}\n />\n )}\n {showLegend && (\n <ChartLegend\n verticalAlign={legendPosition}\n content={<ChartLegendContent verticalAlign={legendPosition} />}\n />\n )}\n {dataKeys.map((key) =>\n radarSeries({\n seriesKey: key,\n style: radarSeriesStyle(\n key,\n seriesSettings?.[key],\n seriesDefaults\n ),\n animation,\n showLabels,\n labelPosition: radarLabelPosition,\n labelFormatter,\n })\n )}\n </RechartsRadarChart>\n </ChartContainer>\n </div>\n );\n }\n);\nRadarChart.displayName = 'RadarChart';\n\nexport { RadarChart, radarChartVariants };\n"],"mappings":"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"}
1
+ {"version":3,"file":"radar-chart.js","names":[],"sources":["../../../../src/components/ui/radar-chart/radar-chart.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n LabelList,\n PolarAngleAxis,\n PolarGrid,\n PolarRadiusAxis,\n Radar,\n RadarChart as RechartsRadarChart,\n type AxisDomainItem,\n} from 'recharts';\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartLegend,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n toLabelFormatter,\n resolveLabelFillClass,\n CHART_LABEL_FONT_SIZE,\n type ChartConfig,\n type ChartPalette,\n type ChartAnimationProps,\n type ChartDataLabelProps,\n type CartesianLabelPosition,\n type ResolvedAnimation,\n} from '../chart';\n\n// A typed recharts composition over the shared `Chart` primitives — the first\n// polar chart type. The single CVA axis is the design's Radar-chart variant set:\n// `gridType` (the polar web is drawn as straight-edged `polygon` rings or smooth\n// `circle` rings). The class stays empty because recharts' SVG — not CSS — draws\n// the web: `gridType` drives `<PolarGrid gridType>`. CVA is kept so the variant\n// set is a first-class, spec-conformant part of the API (matched against\n// ui-spec's api.yaml enums) and exposed via `VariantProps`; the resolved value is\n// also mirrored onto `data-grid-type`.\nconst radarChartVariants = cva('', {\n variants: {\n gridType: {\n polygon: '',\n circle: '',\n },\n },\n defaultVariants: {\n gridType: 'polygon',\n },\n});\n\n/** Per-series overrides, keyed by the series' `dataKeys` entry. */\nexport interface RadarChartSeriesSettings {\n /**\n * Fill for this series' area, overriding its `config` color. Reference an\n * existing semantic `--ui-*` token, same as `config`.\n */\n color?: string;\n /**\n * Outline color, when it should read differently from the fill (e.g. a solid\n * outline over a barely-tinted area). Defaults to the fill.\n *\n * recharts derives a Radar's legend/tooltip color from its stroke first, so\n * setting this alone also recolors that series' legend swatch and tooltip dot\n * — set `color` too if the marker should keep following the fill.\n */\n stroke?: string;\n /** Fill opacity for this series, overriding the chart-level `fillOpacity`. */\n fillOpacity?: number;\n /** Outline width for this series, overriding the chart-level `strokeWidth`. */\n strokeWidth?: number;\n /** Per-point dots for this series, overriding the chart-level `showDots`. */\n dot?: boolean;\n /** Dot radius for this series, overriding the chart-level `dotRadius`. */\n dotRadius?: number;\n /**\n * Highlight this series' hovered point, overriding the chart-level\n * `activeDot`.\n */\n activeDot?: boolean;\n}\n\n/**\n * Map the `radiusAxisDomain` preset to a recharts radius-axis `domain`. Exported\n * for unit tests; not part of the package's public API.\n *\n * The radius axis is what scales the web, so this is the difference between \"the\n * largest value in the data reaches the outer ring\" (recharts' own behavior, and\n * what an unset preset keeps) and \"the outer ring is a known maximum\" (`fixed`\n * plus `radiusAxisDomainMax`). The two only mean something together: a `fixed`\n * preset with no maximum falls back to the data's own top, i.e. that same\n * default.\n */\nexport function radarRadiusAxisDomain(\n preset: 'auto' | 'fixed' | undefined,\n max: number | undefined\n): Readonly<[AxisDomainItem, AxisDomainItem]> | undefined {\n switch (preset) {\n case 'auto':\n return ['auto', 'auto'];\n case 'fixed':\n // A maximum that isn't a positive, finite number can't bound a scale that\n // grows outward from 0: `[0, 0]` collapses the web onto its centre and a\n // negative inverts it. A computed max (`Math.max` over an empty or all-zero\n // series) reaches this, so fall back to the data's own top — the same\n // behavior as `fixed` with no maximum at all.\n return [0, max !== undefined && Number.isFinite(max) && max > 0 ? max : 'auto'];\n default:\n return undefined;\n }\n}\n\n/** The chart-level styling a `seriesSettings` entry overrides. */\nexport interface RadarSeriesDefaults {\n fillOpacity: number;\n strokeWidth: number;\n showDots: boolean;\n dotRadius: number;\n activeDot: boolean | undefined;\n}\n\n/** Resolved recharts `<Radar>` styling for one series. */\nexport interface RadarSeriesStyle {\n fill: string;\n stroke: string;\n fillOpacity: number;\n strokeWidth: number;\n dot: { r: number } | false;\n activeDot: boolean | undefined;\n}\n\n/**\n * Fold a series' `seriesSettings` entry over the chart-level styling. Exported\n * for unit tests; not part of the package's public API.\n *\n * Every fallback is `??`, not `||`, so a deliberate falsy override survives —\n * `fillOpacity: 0` (outline only), `strokeWidth: 0` (fill only), `dot: false`\n * and `activeDot: false` all have to beat a truthy chart-level value. An\n * un-overridden fill stays the `--color-<key>` custom property the shared\n * `ChartContainer` injects from `config`, so the series a caller doesn't name\n * keeps reading its config color.\n */\nexport function radarSeriesStyle(\n key: string,\n settings: RadarChartSeriesSettings | undefined,\n defaults: RadarSeriesDefaults\n): RadarSeriesStyle {\n const fill = settings?.color ?? `var(--color-${key})`;\n const dot = settings?.dot ?? defaults.showDots;\n return {\n fill,\n stroke: settings?.stroke ?? fill,\n fillOpacity: settings?.fillOpacity ?? defaults.fillOpacity,\n strokeWidth: settings?.strokeWidth ?? defaults.strokeWidth,\n dot: dot ? { r: settings?.dotRadius ?? defaults.dotRadius } : false,\n activeDot: settings?.activeDot ?? defaults.activeDot,\n };\n}\n\nexport interface RadarChartProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n VariantProps<typeof radarChartVariants>,\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 /**\n * Row-per-axis data. Each object holds the `angleKey` label + one numeric field\n * per series. Every plotted series needs a value in every row: recharts places a\n * missing one at the centre, which reads as a zero rather than as a gap.\n */\n data: ReadonlyArray<Record<string, string | number>>;\n /**\n * Per-series map of `label` / `icon` / `tone` (imported from the shared\n * `Chart` primitives). Turned into `--color-<key>` custom properties. Series\n * take their colour from the container's `palette`; each entry maps a key to a\n * `label` and an optional `tone`.\n */\n config: ChartConfig;\n /** Series to plot — one `<Radar>` per key. Each must exist in `config` and in every data row. */\n dataKeys: string[];\n /** The categorical axis key placed around the web (e.g. `\"subject\"`). */\n angleKey: string;\n /**\n * Per-series style overrides, keyed by a `dataKeys` entry — color, outline, and\n * dots for one series while the rest keep the chart-level values. Keys that\n * aren't plotted are ignored. An overridden `color` — or `stroke`, which\n * recharts reads first — follows through to that series' legend swatch and\n * tooltip dot.\n */\n seriesSettings?: Record<string, RadarChartSeriesSettings>;\n /** Fill opacity of each radar area. */\n fillOpacity?: number;\n /** Stroke width of each radar outline. */\n strokeWidth?: number;\n /** Render a dot at each axis point. Defaults to `true`. */\n showDots?: boolean;\n /** Radius of the per-point dots when `showDots` is on. Defaults to `2`. */\n dotRadius?: number;\n /**\n * Enlarge the hovered point's dot. On by default (recharts' behavior) — pass\n * `false` for a chart that shouldn't react to the pointer at all.\n */\n activeDot?: boolean;\n /** Render the polar grid (the web). */\n showGrid?: boolean;\n /**\n * Draw the grid's spokes — the radial lines from the centre out to each\n * category. Defaults to `true`; off leaves only the concentric rings.\n */\n radialLines?: boolean;\n /**\n * Render the categorical axis around the web (its spoke labels, tick lines,\n * and outer line). Defaults to `true`. Turning it off keeps the axis itself —\n * so the tooltip still names each category — and only hides its chrome.\n */\n showAngleAxis?: boolean;\n /** Place the spoke labels outside the web (default) or inside it. */\n angleAxisOrientation?: 'inner' | 'outer';\n /** Draw the line around the web that the spoke labels sit against. Defaults to `true`. */\n angleAxisLine?: boolean;\n /**\n * Shape of that line: straight-edged `polygon` (recharts' default) or a smooth\n * `circle`. Independent of `gridType`, so pair them to keep a circular web's\n * outline circular too.\n */\n angleAxisLineType?: 'polygon' | 'circle';\n /** Draw a tick line from the axis line to each spoke label. Defaults to `true`. */\n angleTickLine?: boolean;\n /**\n * Distance from each polygon vertex to its outer category label, in px.\n * Defaults to `4` (Figma geometry). When `showLabels` is on and no explicit\n * value is given, widens automatically to clear the value labels.\n */\n angleTickSize?: number;\n /**\n * Render the value scale — a radial axis of ticks from the centre outward, so\n * an area can be read as a number and not only compared to its neighbours.\n * Defaults to `false` (recharts draws no radius axis unless asked).\n *\n * `radiusAxisAngle` and `radiusAxisOrientation` only describe the drawn scale,\n * so they need it shown. `radiusAxisDomain`, `radiusAxisReversed` and\n * `radiusAxisTickCount` apply while it's hidden too — the first two scale the\n * web, and the third sets how many rings the grid draws (recharts takes the\n * grid's concentric radii from the radius axis' ticks).\n */\n showRadiusAxis?: boolean;\n /**\n * Angle the value scale is drawn at, in degrees counter-clockwise from 3\n * o'clock (recharts' default is `0`). Point it *between* two spokes: on a\n * spoke, the outermost tick collides with that category's own label.\n *\n * The ticks sit over the areas at any angle — a radar's plot area is its\n * areas — so this trades one overlap for none of the other.\n */\n radiusAxisAngle?: number;\n /** Which side of the scale its tick labels sit on. Defaults to `right`. */\n radiusAxisOrientation?: 'left' | 'right' | 'middle';\n /**\n * How the value scale is bounded — and with it the web, since the radius axis\n * is what maps a value to a radius:\n *\n * - unset — recharts' own scaling: the data's largest value reaches the outer\n * ring, so two charts of the same metric aren't comparable.\n * - `fixed` — pin the outer ring to `radiusAxisDomainMax` (the metric's own\n * maximum, e.g. a score out of 150), which is what makes a radar readable as\n * an absolute profile rather than a relative one.\n * - `auto` — fit the data at both ends; the scale need not start at 0.\n *\n * Takes effect whether or not the scale is shown, so a chart can be scaled to a\n * known maximum without displaying the ticks.\n */\n radiusAxisDomain?: 'auto' | 'fixed';\n /**\n * The value at the outer ring when `radiusAxisDomain` is `fixed`. Must be\n * positive — a `0` or negative maximum can't bound an outward-growing scale, so\n * it falls back to the data's own top.\n */\n radiusAxisDomainMax?: number;\n /**\n * Desired number of ticks on the value scale (a hint, not exact). Defaults to\n * recharts' `5`. Also sets how many rings the grid draws, whether or not the\n * scale itself is shown.\n */\n radiusAxisTickCount?: number;\n /**\n * Invert the value scale — the maximum at the centre and 0 at the outer ring —\n * for a metric where less is better (latency, error rate), so a good profile\n * still reads as a large area.\n */\n radiusAxisReversed?: boolean;\n /** Horizontal centre of the web, in px or a percentage of the width. Defaults to `50%`. */\n cx?: number | string;\n /**\n * Vertical centre of the web, in px or a percentage of the height. Defaults to\n * the middle of the plot band — i.e. `50%` of what the legend leaves, not of\n * the whole box (see `radarPlotBox`).\n */\n cy?: number | string;\n /** Angle the first category sits at, in degrees. Defaults to `90` (12 o'clock). */\n startAngle?: number;\n /**\n * Angle the sweep ends at, in degrees. Defaults to `-270` — a full turn\n * clockwise from `startAngle`. Together the two rotate the web (or wrap the\n * categories into a partial sweep).\n */\n endAngle?: number;\n /**\n * Radius of the hole at the centre, in px or a percentage of the available\n * radius. Defaults to `0`. Also lifts the grid and the areas off the centre,\n * which separates the series where they all bottom out.\n */\n innerRadius?: number | string;\n /**\n * Outer radius of the web, in px or a percentage of the available radius.\n * Defaults to `78px`, matching the Figma radar geometry. The legend and labels\n * do not change the radius — they change the box it is drawn in (see\n * `radarPlotBox`).\n */\n outerRadius?: number | string;\n /**\n * Plot-area margin, in px. Omit it entirely to use recharts' default (5 on\n * every side) — passing the object replaces all four, and recharts fills the\n * sides you leave out with `0`, not with `5`. Name every side you want.\n */\n margin?: { top?: number; right?: number; bottom?: number; left?: number };\n showTooltip?: boolean;\n showLegend?: boolean;\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-series rows, or extra fields without composing\n * recharts yourself. Ignored when `showTooltip` is false.\n */\n tooltipContent?: React.ComponentProps<typeof ChartTooltip>['content'];\n /** Position of the value labels when `showLabels` is on. Defaults to `top`. */\n labelPosition?: CartesianLabelPosition;\n}\n\n// Distance from the polygon to the category tick text when value labels are on\n// (recharts' default is 8). Has to clear a CHART_LABEL_FONT_SIZE line plus the\n// LabelList's own 5px offset, or the topmost vertex's value overlaps its tick.\nconst RADAR_LABEL_TICK_SIZE = 30;\n\n// Vertical geometry of the chart's own box, in px.\n//\n// recharts centres a polar chart on the *whole* SVG: `cy` falls back to\n// `height / 2` and — unlike a percentage `outerRadius`, which it does fit to the\n// plot area — takes no account of the legend band it reserves at the bottom.\n// With the fixed-px `outerRadius` the Figma geometry asks for, that leaves the\n// ring the category labels are drawn on centred over rows the legend has\n// already claimed: the bottom label lands behind the legend and the top one runs\n// off the edge. `radarPlotBox` derives the box height and `cy` together so the\n// ring always has somewhere to go.\n\n// Half a `text-xs` line (16px). recharts anchors the top and bottom category\n// ticks' text *on* their point (`verticalAnchor: 'middle'`), so this much of the\n// text falls beyond the ring on each side.\nconst RADAR_TICK_TEXT_HALF_LINE = 8;\n// Figma's plot band. Holds the 78px web plus its 4px tick ring and that half\n// line (90px each side of the centre) with a little to spare.\nconst RADAR_PLOT_BAND = 187;\n// What a chart whose category ring outgrows RADAR_PLOT_BAND gets instead:\n// 2 × (78 + RADAR_LABEL_TICK_SIZE + RADAR_TICK_TEXT_HALF_LINE) — the cost of\n// `showLabels` at the Figma radius — rounded up to keep the same few px of slack\n// Figma's 187 leaves around the 4px ring.\nconst RADAR_LABELLED_PLOT_BAND = 240;\n// Figma's legend row, and what recharts' wrapper occupies too: it parks the\n// wrapper at `margin.bottom` (5) and `ChartLegendContent` is a `pt-3` above a\n// 16px line.\nconst RADAR_LEGEND_BAND = 32;\n\n/** The chart's own box: the height it reserves, and the polar centre inside it. */\nexport interface RadarPlotBox {\n /**\n * Tailwind height for the outer element. Merged *before* the consumer's\n * `className`, so a caller-supplied height still wins.\n */\n heightClass: string;\n /** `cy` for recharts, or `undefined` to keep its own `height / 2` default. */\n cy: string | undefined;\n}\n\n/**\n * Size the chart's box around its category ring, and centre the web in the part\n * of that box the legend does not take. Exported for unit tests; not part of the\n * package's public API.\n *\n * `ringRadius` is how far the category labels reach from the centre —\n * `outerRadius + angleTickSize + RADAR_TICK_TEXT_HALF_LINE` — or `undefined`\n * when `outerRadius` is a percentage, which recharts already fits to the plot\n * area (legend included) on its own.\n *\n * `cy` comes back as a percentage rather than the px it resolves to at the\n * default height, so a caller-supplied height keeps the proportion instead of\n * pinning the web to an absolute offset. On a taller box that lifts the web a\n * little further than the legend alone needs — towards the side with the slack.\n */\nexport function radarPlotBox(\n ringRadius: number | undefined,\n showLegend: boolean\n): RadarPlotBox {\n const tall = ringRadius !== undefined && ringRadius > RADAR_PLOT_BAND / 2;\n const plotBand = tall ? RADAR_LABELLED_PLOT_BAND : RADAR_PLOT_BAND;\n if (!showLegend) {\n // 240 / 187 — the plot band on its own.\n return { heightClass: tall ? 'h-[240px]' : 'h-[187px]', cy: undefined };\n }\n return {\n // 240 + 32 / 187 + 32 — the plot band above the legend band. Tailwind only\n // sees classes it can read in the source, so these stay literal.\n heightClass: tall ? 'h-[272px]' : 'h-[219px]',\n // Truncated rather than rounded: the leftover fraction has to come off the\n // top, the side with the slack, and never off the legend's.\n cy: `${Math.floor((plotBand / 2 / (plotBand + RADAR_LEGEND_BAND)) * 1e5) / 1e3}%`,\n };\n}\n\n/**\n * One series' `<Radar>` (and its value labels).\n *\n * Called as a plain function rather than mounted as `<RadarSeries />`, purely\n * to keep the chart's children readable as a flat list — recharts imposes no\n * constraint here. `RadarChart` picks up the series from the store `<Radar>`\n * registers itself in, and `Radar` passes its children straight through to a\n * label-list context instead of scanning them by type. `<Cell>` is the only\n * child recharts still looks up by element type, and a radar series has none.\n */\nfunction radarSeries({\n seriesKey,\n style,\n animation,\n showLabels,\n labelPosition,\n labelFormatter,\n}: {\n seriesKey: string;\n style: RadarSeriesStyle;\n animation: ResolvedAnimation;\n showLabels: boolean;\n labelPosition: CartesianLabelPosition;\n labelFormatter: ChartDataLabelProps['labelFormatter'];\n}) {\n return (\n <Radar\n key={seriesKey}\n dataKey={seriesKey}\n stroke={style.stroke}\n fill={style.fill}\n fillOpacity={style.fillOpacity}\n strokeWidth={style.strokeWidth}\n dot={style.dot}\n activeDot={style.activeDot}\n {...animation}\n >\n {showLabels && (\n <LabelList\n dataKey={seriesKey}\n position={labelPosition}\n formatter={toLabelFormatter(labelFormatter)}\n // A radar area is a flat `fillOpacity`, so an `inside*` label sits on\n // the *surface tinted by* the series color, not on the color itself —\n // the white on-fill token disappears into it in light mode. Same call\n // as the other translucent families (Area, the composed chart's areas).\n className={resolveLabelFillClass(labelPosition, {\n translucentSeries: true,\n })}\n fontSize={CHART_LABEL_FONT_SIZE}\n />\n )}\n </Radar>\n );\n}\n\nconst RadarChart = React.forwardRef<HTMLDivElement, RadarChartProps>(\n (\n {\n className,\n config,\n palette,\n data,\n dataKeys,\n angleKey,\n seriesSettings,\n gridType = 'polygon',\n fillOpacity = 0.3,\n strokeWidth = 2,\n showDots = true,\n dotRadius = 2,\n activeDot,\n showGrid = true,\n radialLines = true,\n showAngleAxis = true,\n angleAxisOrientation,\n angleAxisLine = true,\n angleAxisLineType,\n angleTickLine = true,\n angleTickSize,\n showRadiusAxis = false,\n radiusAxisAngle,\n radiusAxisOrientation,\n radiusAxisDomain,\n radiusAxisDomainMax,\n radiusAxisTickCount,\n radiusAxisReversed = false,\n cx,\n cy,\n startAngle,\n endAngle,\n innerRadius,\n outerRadius: outerRadiusProp,\n margin,\n showTooltip = true,\n showLegend = true,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n showLabels = false,\n labelPosition,\n labelFormatter,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n const radarLabelPosition = labelPosition ?? 'top';\n const radiusDomain = radarRadiusAxisDomain(\n radiusAxisDomain,\n radiusAxisDomainMax\n );\n // The radius axis is only mounted when it has something to do: it either\n // paints the scale, or it carries a domain/reversal that rescales the web\n // (recharts registers those from the element even when nothing is drawn).\n // Without one of the three, leaving the element out keeps recharts' own\n // implicit axis — and every existing chart's geometry.\n const hasRadiusAxis =\n showRadiusAxis || radiusDomain !== undefined || radiusAxisReversed;\n const seriesDefaults: RadarSeriesDefaults = {\n fillOpacity,\n strokeWidth,\n showDots,\n dotRadius,\n activeDot,\n };\n const outerRadius = outerRadiusProp ?? 78;\n const resolvedTickSize =\n angleTickSize ?? (showLabels ? RADAR_LABEL_TICK_SIZE : 4);\n // A percentage `outerRadius` is already fitted to the plot area by recharts,\n // so only a fixed radius has a ring whose reach the box has to be sized to.\n const plotBox = radarPlotBox(\n typeof outerRadius === 'number'\n ? outerRadius + resolvedTickSize + RADAR_TICK_TEXT_HALF_LINE\n : undefined,\n showLegend\n );\n // When the consumer supplies their own height (size-*, h-*, min-h-*, max-h-*)\n // the plotBox.cy percentage — calibrated for the compact default heights — would\n // shift the web too far up in a taller box. Fall back to recharts' default\n // cy = height/2 in that case; a large container has room for ring + legend\n // without the legend-band compensation radarPlotBox does.\n const consumerOwnsHeight = /(?:^|\\s)(?:h-|size-|min-h-|max-h-)/.test(\n className ?? ''\n );\n return (\n <div\n ref={ref}\n data-grid-type={gridType}\n // Default height matches the Figma geometry (187px plot + 32px legend),\n // widening only when the category ring outgrows it (see `radarPlotBox`).\n // The consumer's `className` is merged after the default, so a\n // caller-supplied height (e.g. `h-[380px]`) wins via Tailwind's\n // last-class-wins rule.\n className={cn(\n radarChartVariants({ gridType }),\n plotBox.heightClass,\n className\n )}\n {...props}\n >\n <ChartContainer\n config={config}\n palette={palette}\n // The shared container themes cartesian axis ticks but not polar ones,\n // so scope the angle-axis (spoke) labels and the radius-axis scale to\n // the muted-foreground / border tokens here — otherwise they render\n // near-black (or recharts' raw `#ccc`) and vanish in dark mode. This\n // is a shared-primitives gap (a Chart task); worked around locally, not\n // by editing chart.tsx.\n className={cn(\n 'size-full',\n \"[&_.recharts-polar-angle-axis-tick_text]:fill-[var(--ui-text-on-surface-secondary)]! [&_.recharts-polar-angle-axis-tick_text]:text-xs [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-[var(--ui-border-on-surface-divider)]! [&_.recharts-polar-radius-axis-line]:stroke-[var(--ui-border-on-surface-divider)]! [&_.recharts-polar-radius-axis-tick_text]:fill-[var(--ui-text-on-surface-secondary)]! [&_.recharts-polar-radius-axis-tick_text]:text-xs\"\n )}\n >\n <RechartsRadarChart\n data={data as readonly unknown[]}\n cx={cx}\n cy={cy ?? (consumerOwnsHeight ? undefined : plotBox.cy)}\n startAngle={startAngle}\n endAngle={endAngle}\n innerRadius={innerRadius}\n outerRadius={outerRadius}\n margin={margin}\n >\n {showTooltip && (\n <ChartTooltip content={tooltipContent ?? <ChartTooltipContent />} />\n )}\n {showGrid && (\n <PolarGrid gridType={gridType ?? 'polygon'} radialLines={radialLines} />\n )}\n <PolarAngleAxis\n dataKey={angleKey}\n orientation={angleAxisOrientation}\n axisLineType={angleAxisLineType}\n // `showAngleAxis` hides the chrome rather than dropping the axis:\n // the angle axis is also what maps a row to its category name, so\n // removing it would leave the tooltip labelling rows by index.\n tick={showAngleAxis}\n axisLine={showAngleAxis && angleAxisLine}\n tickLine={showAngleAxis && angleTickLine}\n // Push the category ticks out when value labels are on. recharts\n // gives a Radar's label list a *cartesian* viewBox (width/height 0\n // at the vertex), so `top` offsets straight up in screen space —\n // at the topmost vertex the value lands on its own category tick.\n // The tick text is drawn at `outerRadius + tickSize`, so this is\n // the only lever that adds *absolute* clearance: shrinking\n // outerRadius scales the tick ring down with the polygon and keeps\n // the overlap. Default 4px matches the Figma geometry when labels\n // are off. The box grows to fit whatever this resolves to — see\n // `radarPlotBox`.\n tickSize={resolvedTickSize}\n />\n {hasRadiusAxis && (\n <PolarRadiusAxis\n angle={radiusAxisAngle}\n orientation={radiusAxisOrientation}\n domain={radiusDomain}\n tickCount={radiusAxisTickCount}\n reversed={radiusAxisReversed}\n tick={showRadiusAxis}\n axisLine={showRadiusAxis}\n />\n )}\n {showLegend && (\n <ChartLegend\n verticalAlign=\"bottom\"\n content={<ChartLegendContent verticalAlign=\"bottom\" />}\n />\n )}\n {dataKeys.map((key) =>\n radarSeries({\n seriesKey: key,\n style: radarSeriesStyle(\n key,\n seriesSettings?.[key],\n seriesDefaults\n ),\n animation,\n showLabels,\n labelPosition: radarLabelPosition,\n labelFormatter,\n })\n )}\n </RechartsRadarChart>\n </ChartContainer>\n </div>\n );\n }\n);\nRadarChart.displayName = 'RadarChart';\n\nexport { RadarChart, radarChartVariants };\n"],"mappings":"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"}
@@ -6,7 +6,10 @@ import * as f from "react";
6
6
  import { jsx as p, jsxs as m } from "react/jsx-runtime";
7
7
  import { CartesianGrid as h, Scatter as g, ScatterChart as _, XAxis as v, YAxis as y, ZAxis as b } from "recharts";
8
8
  //#region src/components/ui/scatter-chart/scatter-chart.tsx
9
- var x = f.forwardRef(({ className: f, config: x, palette: S, series: C, xKey: w, yKey: T, zKey: E, zRange: D = [60, 400], shape: O = "circle", xAxisLabel: k, yAxisLabel: A, xUnit: j, yUnit: M, showGrid: N = !0, showTooltip: P = !0, showLegend: ee = !0, showXAxis: F = !0, showYAxis: I = !0, xTickFormatter: L, yTickFormatter: R, xAxisAngle: z, xAxisInterval: B, yAxisTickCount: V, yAxisDomain: H, gridDashed: U, gridHorizontal: W, gridVertical: G, tooltipContent: K, animate: q, animationDuration: J, animationBegin: Y, animationEasing: X, ...Z }, Q) => {
9
+ var x = f.forwardRef(({ className: f, config: x, palette: S = {
10
+ type: "diverging",
11
+ pair: "teal-violet"
12
+ }, series: C, xKey: w, yKey: T, zKey: E, zRange: D = [60, 400], shape: O = "circle", xAxisLabel: k, yAxisLabel: A, xUnit: j, yUnit: M, showGrid: N = !0, showTooltip: P = !0, showLegend: ee = !0, showXAxis: F = !0, showYAxis: I = !0, xTickFormatter: L, yTickFormatter: R, xAxisAngle: z, xAxisInterval: B, yAxisTickCount: V, yAxisDomain: H, gridDashed: U = !0, gridHorizontal: W, gridVertical: G, tooltipContent: K, animate: q, animationDuration: J, animationBegin: Y, animationEasing: X, ...Z }, Q) => {
10
13
  let $ = o({
11
14
  animate: q,
12
15
  animationDuration: J,
@@ -31,7 +34,7 @@ var x = f.forwardRef(({ className: f, config: x, palette: S, series: C, xKey: w,
31
34
  children: [
32
35
  N && /* @__PURE__ */ p(h, {
33
36
  horizontal: W ?? !0,
34
- vertical: G ?? !0,
37
+ vertical: G ?? !1,
35
38
  strokeDasharray: U ? "3 3" : void 0
36
39
  }),
37
40
  /* @__PURE__ */ p(v, {
@@ -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 resolveXAxisHeight,\n resolveXAxisTitle,\n resolveYAxisTitle,\n type ChartConfig,\n type ChartPalette,\n type CartesianChartProps,\n type ChartAnimationProps,\n} from '../chart';\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\nconst ScatterChart = React.forwardRef<HTMLDivElement, ScatterChartProps>(\n (\n {\n className,\n config,\n palette,\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 showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed,\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 xAxisHeight = resolveXAxisHeight(xAxisLabel, xAxisAngle);\n\n return (\n <div ref={ref} className={cn(className)} {...props}>\n <ChartContainer\n config={config}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RechartsScatterChart\n margin={{ top: 16, right: 16, bottom: 16, left: 16 }}\n >\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? true}\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={xAxisHeight}\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 && <ChartLegend content={<ChartLegendContent />} />}\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-${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":";;;;;;;;AAwFA,IAAM,IAAe,EAAM,YAEvB,EACE,cACA,WACA,YACA,WACA,SACA,SACA,SACA,YAAS,CAAC,IAAI,GAAG,GACjB,WAAQ,UACR,eACA,eACA,UACA,UACA,cAAW,IACX,iBAAc,IACd,iBAAa,IACb,eAAY,IACZ,eAAY,IACZ,mBACA,mBACA,eACA,kBACA,mBACA,gBACA,eACA,mBACA,iBACA,mBACA,YACA,sBACA,mBACA,oBACA,GAAG,KAEL,MACG;CACH,IAAM,IAAY,EAAiB;EACjC;EACA;EACA;EACA;CACF,CAAC,GAIK,KAAa,EACjB,GACA,gBACA,EACF,GACM,KAAa,EAAkB,CAAU,GAEzC,KAAU,EAAkB,CAAW,GAEvC,KAAc,EAAmB,GAAY,CAAU;CAE7D,OACE,kBAAC,OAAD;EAAU;EAAK,WAAW,EAAG,CAAS;EAAG,GAAI;EAC3C,UAAA,kBAAC,GAAD;GACU;GACC;GACT,WAAU;GAEV,UAAA,kBAAC,GAAD;IACE,QAAQ;KAAE,KAAK;KAAI,OAAO;KAAI,QAAQ;KAAI,MAAM;IAAG;IADrD,UAAA;KAGG,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;MACR,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,MAAc,kBAAC,GAAD,EAAa,SAAS,kBAAC,GAAD,CAAqB,CAAA,EAAI,CAAA;KAC7D,EAAO,KAAK,MACX,kBAAC,GAAD;MAEE,MAAM,EAAE;MACR,MAAM,EAAE;MACR,MAAM,eAAe,EAAE,IAAI;MACpB;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 resolveXAxisHeight,\n resolveXAxisTitle,\n resolveYAxisTitle,\n type ChartConfig,\n type ChartPalette,\n type CartesianChartProps,\n type ChartAnimationProps,\n} from '../chart';\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\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 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 xAxisHeight = resolveXAxisHeight(xAxisLabel, xAxisAngle);\n\n return (\n <div ref={ref} className={cn(className)} {...props}>\n <ChartContainer\n config={config}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RechartsScatterChart\n margin={{ top: 16, right: 16, bottom: 16, left: 16 }}\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={xAxisHeight}\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 && <ChartLegend content={<ChartLegendContent />} />}\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-${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":";;;;;;;;AAwFA,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,eAAY,IACZ,eAAY,IACZ,mBACA,mBACA,eACA,kBACA,mBACA,gBACA,gBAAa,IACb,mBACA,iBACA,mBACA,YACA,sBACA,mBACA,oBACA,GAAG,KAEL,MACG;CACH,IAAM,IAAY,EAAiB;EACjC;EACA;EACA;EACA;CACF,CAAC,GAIK,KAAa,EACjB,GACA,gBACA,EACF,GACM,KAAa,EAAkB,CAAU,GAEzC,KAAU,EAAkB,CAAW,GAEvC,KAAc,EAAmB,GAAY,CAAU;CAE7D,OACE,kBAAC,OAAD;EAAU;EAAK,WAAW,EAAG,CAAS;EAAG,GAAI;EAC3C,UAAA,kBAAC,GAAD;GACU;GACC;GACT,WAAU;GAEV,UAAA,kBAAC,GAAD;IACE,QAAQ;KAAE,KAAK;KAAI,OAAO;KAAI,QAAQ;KAAI,MAAM;IAAG;IADrD,UAAA;KAGG,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;MACR,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,MAAc,kBAAC,GAAD,EAAa,SAAS,kBAAC,GAAD,CAAqB,CAAA,EAAI,CAAA;KAC7D,EAAO,KAAK,MACX,kBAAC,GAAD;MAEE,MAAM,EAAE;MACR,MAAM,EAAE;MACR,MAAM,eAAe,EAAE,IAAI;MACpB;MACP,GAAI;KACL,GANM,EAAE,GAMR,CACF;IACmB;;EACR,CAAA;CACb,CAAA;AAET,CACF;AACA,EAAa,cAAc"}