{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "radar-chart-card",
  "title": "Radar Chart",
  "description": "Polar comparison with filled, dotted, outline, or score treatments.",
  "dependencies": [
    "recharts@^3.10.1"
  ],
  "registryDependencies": [
    "https://components.exe.xyz/r/chart-card.json"
  ],
  "files": [
    {
      "path": "src/components/charts/radar-chart-card.tsx",
      "content": "import { useState } from \"react\"\nimport {\n  PolarAngleAxis,\n  PolarGrid,\n  PolarRadiusAxis,\n  Radar,\n  RadarChart,\n  ResponsiveContainer,\n  Tooltip,\n} from \"recharts\"\nimport type { BaseTickContentProps } from \"recharts\"\n\nimport {\n  ChartCard,\n  ChartPlot,\n  ChartTiles,\n  PlotTooltip,\n  chartColor,\n  formatNumber,\n  useActiveRange,\n  usePrefersReducedMotion,\n} from \"@/components/charts/chart-card\"\n\nexport type RadarRow = Record<string, string | number>\nexport type RadarSeries = { key: string; label: string; color?: string }\n\nconst DEFAULT_DATA: RadarRow[] = [\n  { label: \"Jan\", desktop: 186, mobile: 80 },\n  { label: \"Feb\", desktop: 305, mobile: 200 },\n  { label: \"Mar\", desktop: 237, mobile: 120 },\n  { label: \"Apr\", desktop: 273, mobile: 190 },\n  { label: \"May\", desktop: 209, mobile: 130 },\n  { label: \"Jun\", desktop: 214, mobile: 140 },\n]\n\nconst DEFAULT_SERIES: RadarSeries[] = [\n  { key: \"desktop\", label: \"Desktop\" },\n  { key: \"mobile\", label: \"Mobile\" },\n]\n\nfunction scoreBand(score: number) {\n  if (score >= 75) return \"Strong\"\n  if (score >= 50) return \"Fair\"\n  return \"Low\"\n}\n\nexport function RadarChartCard({\n  title = \"Visitors\",\n  variant = \"filled\",\n  tiles = false,\n  data,\n  series = DEFAULT_SERIES,\n  max,\n  alertBelow,\n  headline,\n  delta = 5.2,\n  range,\n  ranges,\n  defaultRange,\n  onRangeChange,\n}: {\n  title?: string\n  variant?: \"filled\" | \"dots\" | \"lines\" | \"score\"\n  tiles?: boolean\n  data?: RadarRow[]\n  series?: RadarSeries[]\n  max?: number\n  alertBelow?: number\n  headline?: number\n  delta?: number\n  range?: string\n  ranges?: {\n    id: string\n    label: string\n    data: RadarRow[]\n    delta?: number\n    headline?: number\n  }[]\n  defaultRange?: string\n  onRangeChange?: (id: string) => void\n}) {\n  const reduced = usePrefersReducedMotion()\n  const { id, setId, active } = useActiveRange(\n    ranges,\n    range,\n    defaultRange,\n    onRangeChange\n  )\n  const plotData =\n    active?.data ?? (data && data.length > 0 ? data : DEFAULT_DATA)\n  const plotDelta = active?.delta ?? delta\n  const plotSeries = series.length > 0 ? series : DEFAULT_SERIES\n  const primary = plotSeries[0]\n  const values = plotData.map((row) => {\n    const raw = row[primary.key]\n    return typeof raw === \"number\" ? raw : 0\n  })\n  const ceiling =\n    max ??\n    Math.max(\n      1,\n      ...plotData.flatMap((row) =>\n        plotSeries.map((item) => {\n          const raw = row[item.key]\n          return typeof raw === \"number\" ? raw : 0\n        })\n      )\n    )\n  const avg =\n    values.length === 0\n      ? 0\n      : values.reduce((sum, n) => sum + n, 0) / values.length\n  const score = Math.round((avg / ceiling) * 100)\n  const plotHeadline = active?.headline ?? headline ?? Math.round(avg)\n  const [activeAxis, setActiveAxis] = useState<string | null>(null)\n  const band = scoreBand(score)\n  const summary =\n    variant === \"score\"\n      ? `Weekly score ${score}, ${band}`\n      : `${title} ${formatNumber(plotHeadline)}`\n\n  return (\n    <ChartCard\n      title={variant === \"score\" ? \"Weekly score\" : title}\n      headline={variant === \"score\" ? score : plotHeadline}\n      delta={variant === \"score\" ? undefined : plotDelta}\n      period={ranges ? undefined : \"H1 2024\"}\n      ranges={ranges}\n      range={id}\n      onRangeChange={setId}\n      summary={summary}\n      tiles={\n        tiles ? (\n          <ChartTiles\n            activeId={activeAxis}\n            onActiveChange={setActiveAxis}\n            items={plotData.map((row) => {\n              const raw = row[primary.key]\n              const value = typeof raw === \"number\" ? raw : 0\n              return {\n                id: String(row.label),\n                label: String(row.label),\n                value: formatNumber(value),\n                color:\n                  alertBelow != null && value < alertBelow\n                    ? \"var(--destructive)\"\n                    : chartColor(0, primary.color),\n              }\n            })}\n          />\n        ) : undefined\n      }\n    >\n      <div className=\"relative\">\n        <ChartPlot height={240} summary={summary}>\n          <ResponsiveContainer width=\"100%\" height=\"100%\">\n            <RadarChart data={plotData} cx=\"50%\" cy=\"50%\" outerRadius=\"68%\">\n              <PolarGrid stroke=\"var(--border)\" />\n              <PolarAngleAxis\n                dataKey=\"label\"\n                tick={(props: BaseTickContentProps) => {\n                  const index = props.index\n                  const row = plotData[index]\n                  const raw = row[primary.key]\n                  const value = typeof raw === \"number\" ? raw : 0\n                  const alert = alertBelow != null && value < alertBelow\n                  const dimmed =\n                    activeAxis != null && activeAxis !== String(row.label)\n                  const tickValue = props.payload.value\n                  const label =\n                    typeof tickValue === \"string\" ||\n                    typeof tickValue === \"number\"\n                      ? String(tickValue)\n                      : \"\"\n                  return (\n                    <text\n                      x={props.x}\n                      y={props.y}\n                      textAnchor={props.textAnchor}\n                      fill={\n                        alert ? \"var(--destructive)\" : \"var(--muted-foreground)\"\n                      }\n                      fontSize={10}\n                      fontFamily=\"var(--font-mono)\"\n                      opacity={dimmed ? 0.35 : 1}\n                    >\n                      {label}\n                      {variant === \"score\" ? ` ${value}` : \"\"}\n                    </text>\n                  )\n                }}\n              />\n              <PolarRadiusAxis\n                tick={false}\n                axisLine={false}\n                domain={[0, ceiling]}\n              />\n              <Tooltip content={<PlotTooltip />} />\n              {plotSeries.map((item, index) => {\n                const color = chartColor(index, item.color)\n                const filled = variant === \"filled\" || variant === \"score\"\n                const showDots = variant === \"dots\" || filled\n                return (\n                  <Radar\n                    key={item.key}\n                    name={item.label}\n                    dataKey={item.key}\n                    stroke={variant === \"dots\" ? \"none\" : color}\n                    fill={color}\n                    fillOpacity={filled ? 0.22 : 0}\n                    strokeWidth={1.5}\n                    dot={\n                      showDots\n                        ? {\n                            r: variant === \"dots\" ? 3.5 : 2.5,\n                            fill: color,\n                            stroke: \"var(--card)\",\n                            strokeWidth: 1,\n                          }\n                        : false\n                    }\n                    isAnimationActive={!reduced}\n                  />\n                )\n              })}\n            </RadarChart>\n          </ResponsiveContainer>\n        </ChartPlot>\n        {variant === \"score\" ? (\n          <div\n            className=\"pointer-events-none absolute inset-0 flex items-center justify-center\"\n            aria-label={`Weekly score ${score}, ${band}`}\n          >\n            <div className=\"flex size-16 flex-col items-center justify-center rounded-full bg-card ring-1 ring-border\">\n              <span className=\"font-heading text-xl font-semibold tabular-nums\">\n                {score}\n              </span>\n              <span className=\"font-mono text-[9px] tracking-wide text-muted-foreground uppercase\">\n                {band}\n              </span>\n            </div>\n          </div>\n        ) : null}\n      </div>\n    </ChartCard>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}