{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "combo-chart-card",
  "title": "Combo Chart",
  "description": "Bars and a line on independent axes with optional stat tiles.",
  "dependencies": [
    "recharts@^3.10.1"
  ],
  "registryDependencies": [
    "https://components.exe.xyz/r/chart-card.json"
  ],
  "files": [
    {
      "path": "src/components/charts/combo-chart-card.tsx",
      "content": "import { useState } from \"react\"\nimport {\n  Bar,\n  CartesianGrid,\n  ComposedChart,\n  Line,\n  ResponsiveContainer,\n  Tooltip,\n  XAxis,\n  YAxis,\n} from \"recharts\"\n\nimport {\n  ChartCard,\n  ChartPlot,\n  ChartTiles,\n  PlotTooltip,\n  axisTick,\n  chartColor,\n  formatNumber,\n  useActiveRange,\n  usePrefersReducedMotion,\n} from \"@/components/charts/chart-card\"\n\nexport type ComboChartRow = Record<string, string | number>\nexport type ComboSeries = {\n  key: string\n  label: string\n  color?: string\n  format?: (n: number) => string\n}\n\nconst DEFAULT_DATA: ComboChartRow[] = [\n  { label: \"Jan\", sessions: 6200, conversion: 3.2 },\n  { label: \"Feb\", sessions: 6400, conversion: 3.4 },\n  { label: \"Mar\", sessions: 7100, conversion: 3.8 },\n  { label: \"Apr\", sessions: 6800, conversion: 3.6 },\n  { label: \"May\", sessions: 7200, conversion: 3.9 },\n  { label: \"Jun\", sessions: 6900, conversion: 3.7 },\n  { label: \"Jul\", sessions: 7400, conversion: 4.1 },\n  { label: \"Aug\", sessions: 7100, conversion: 3.8 },\n  { label: \"Sep\", sessions: 6800, conversion: 3.5 },\n  { label: \"Oct\", sessions: 7600, conversion: 4.0 },\n  { label: \"Nov\", sessions: 7200, conversion: 3.7 },\n  { label: \"Dec\", sessions: 6500, conversion: 3.7 },\n]\n\nconst DEFAULT_BAR: ComboSeries = {\n  key: \"sessions\",\n  label: \"Sessions\",\n  format: (n) => formatNumber(Math.round(n)),\n}\n\nconst DEFAULT_LINE: ComboSeries = {\n  key: \"conversion\",\n  label: \"Conversion\",\n  format: (n) => `${n.toFixed(1)}%`,\n}\n\nfunction num(row: ComboChartRow, key: string) {\n  const value = row[key]\n  return typeof value === \"number\" ? value : 0\n}\n\nexport function ComboChartCard({\n  title = \"Sessions\",\n  data,\n  bar = DEFAULT_BAR,\n  line = DEFAULT_LINE,\n  delta = 9.4,\n  ranges,\n  tiles = true,\n}: {\n  title?: string\n  data?: ComboChartRow[]\n  bar?: ComboSeries\n  line?: ComboSeries\n  delta?: number\n  ranges?: {\n    id: string\n    label: string\n    data: ComboChartRow[]\n    delta?: number\n  }[]\n  tiles?: boolean\n}) {\n  const reduced = usePrefersReducedMotion()\n  const { id, setId, active } = useActiveRange(ranges)\n  const plotData = active?.data ?? data ?? DEFAULT_DATA\n  const plotDelta = active?.delta ?? delta\n  const [activeKey, setActiveKey] = useState<string | null>(null)\n  const barColor = chartColor(0, bar.color)\n  const lineColor = chartColor(1, line.color)\n  const barFormat = bar.format ?? ((n) => formatNumber(Math.round(n)))\n  const lineFormat = line.format ?? ((n) => n.toFixed(1))\n  const barTotal = plotData.reduce((sum, row) => sum + num(row, bar.key), 0)\n  const lineAvg =\n    plotData.length === 0\n      ? 0\n      : plotData.reduce((sum, row) => sum + num(row, line.key), 0) /\n        plotData.length\n  const summary = `${title} ${barFormat(barTotal)}. ${line.label} average ${lineFormat(lineAvg)}`\n\n  return (\n    <ChartCard\n      title={title}\n      headline={barTotal}\n      headlineFormat={barFormat}\n      delta={plotDelta}\n      period={ranges ? undefined : \"This year\"}\n      ranges={ranges}\n      range={id}\n      onRangeChange={setId}\n      summary={summary}\n      tiles={\n        tiles ? (\n          <ChartTiles\n            activeId={activeKey}\n            onActiveChange={setActiveKey}\n            items={[\n              {\n                id: bar.key,\n                label: bar.label,\n                value: barFormat(barTotal),\n                color: barColor,\n              },\n              {\n                id: line.key,\n                label: `${line.label} avg`,\n                value: lineFormat(lineAvg),\n                color: lineColor,\n              },\n            ]}\n          />\n        ) : undefined\n      }\n    >\n      <ChartPlot height={220} summary={summary}>\n        <ResponsiveContainer width=\"100%\" height=\"100%\">\n          <ComposedChart\n            data={plotData}\n            margin={{ top: 8, right: 8, left: 0, bottom: 0 }}\n            barCategoryGap=\"28%\"\n          >\n            <CartesianGrid\n              vertical={false}\n              stroke=\"var(--border)\"\n              strokeDasharray=\"1 4\"\n            />\n            <XAxis\n              dataKey=\"label\"\n              tick={axisTick}\n              tickLine={false}\n              axisLine={{ stroke: \"var(--border)\" }}\n            />\n            <YAxis\n              yAxisId=\"bar\"\n              tick={axisTick}\n              tickLine={false}\n              axisLine={false}\n              width={40}\n              tickFormatter={(value: number) =>\n                value >= 1000\n                  ? `${Math.round(value / 100) / 10}k`\n                  : String(value)\n              }\n            />\n            <YAxis\n              yAxisId=\"line\"\n              orientation=\"right\"\n              tick={axisTick}\n              tickLine={false}\n              axisLine={false}\n              width={36}\n              tickFormatter={(value: number) => `${value}%`}\n            />\n            <Tooltip\n              cursor={false}\n              content={\n                <PlotTooltip\n                  formatter={(value, name) =>\n                    name === line.label ? lineFormat(value) : barFormat(value)\n                  }\n                />\n              }\n            />\n            <Bar\n              yAxisId=\"bar\"\n              dataKey={bar.key}\n              name={bar.label}\n              fill={barColor}\n              fillOpacity={\n                activeKey != null && activeKey !== bar.key ? 0.28 : 1\n              }\n              radius={2}\n              maxBarSize={36}\n              isAnimationActive={!reduced}\n              activeBar={{\n                fill: barColor,\n                stroke: \"var(--ring)\",\n                strokeWidth: 2,\n                radius: 2,\n              }}\n            />\n            <Line\n              yAxisId=\"line\"\n              type=\"monotone\"\n              dataKey={line.key}\n              name={line.label}\n              stroke={lineColor}\n              strokeWidth={2}\n              strokeOpacity={\n                activeKey != null && activeKey !== line.key ? 0.25 : 1\n              }\n              dot={false}\n              activeDot={{\n                r: 4,\n                fill: lineColor,\n                stroke: \"var(--ring)\",\n                strokeWidth: 2,\n              }}\n              isAnimationActive={!reduced}\n            />\n          </ComposedChart>\n        </ResponsiveContainer>\n      </ChartPlot>\n    </ChartCard>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}