{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "recharts-legend",
  "dependencies": [
    "recharts"
  ],
  "files": [
    {
      "path": "src/registry/ui/recharts-legend.tsx",
      "content": "import { getPayloadConfigFromPayload, getColorsCount, useChart } from \"@/registry/ui/recharts-chart\";\nimport * as RechartsPrimitive from \"recharts\";\nimport { cn } from \"@/lib/utils\";\nimport * as React from \"react\";\n\ntype ChartLegendVariant =\n  | \"square\"\n  | \"circle\"\n  | \"circle-outline\"\n  | \"rounded-square\"\n  | \"rounded-square-outline\"\n  | \"vertical-bar\"\n  | \"horizontal-bar\";\n\nfunction ChartLegendContent({\n  className,\n  hideIcon = false,\n  nameKey,\n  payload,\n  verticalAlign,\n  align = \"right\",\n  selected,\n  onSelectChange,\n  isClickable,\n  variant = \"rounded-square\",\n}: React.ComponentProps<\"div\"> & {\n  hideIcon?: boolean;\n  nameKey?: string;\n  selected?: string | null;\n  isClickable?: boolean;\n  onSelectChange?: (selected: string | null) => void;\n  variant?: ChartLegendVariant;\n} & RechartsPrimitive.DefaultLegendContentProps) {\n  const { config } = useChart();\n\n  if (!payload?.length) {\n    return null;\n  }\n\n  return (\n    <div\n      className={cn(\n        \"flex items-center gap-4 select-none\",\n        align === \"left\" && \"justify-start\",\n        align === \"center\" && \"justify-center\",\n        align === \"right\" && \"justify-end\",\n        verticalAlign === \"top\" ? \"pb-4\" : \"pt-4\",\n        className,\n      )}\n    >\n      {payload\n        .filter((item) => item.type !== \"none\")\n        .map((item) => {\n          // For pie charts, item.value contains the sector name (e.g., \"chrome\")\n          // For radial charts, the name is in item.payload[nameKey]\n          // For other charts, item.dataKey contains the series name (e.g., \"desktop\")\n          const payloadName =\n            nameKey && item.payload\n              ? (item.payload as Record<string, unknown>)[nameKey]\n              : undefined;\n          const key = `${payloadName ?? item.value ?? item.dataKey ?? \"value\"}`;\n          const itemConfig = getPayloadConfigFromPayload(config, item, key);\n          const isSelected = selected === null || selected === key;\n\n          // Get colors count for this item to determine gradient vs solid\n          const colorsCount = itemConfig ? getColorsCount(itemConfig) : 1;\n\n          return (\n            <div\n              key={key}\n              className={cn(\n                \"[&>svg]:text-muted-foreground flex items-center gap-1.5 transition-opacity [&>svg]:h-3 [&>svg]:w-3\",\n                !isSelected && \"opacity-30\",\n                isClickable && \"cursor-pointer\",\n              )}\n              onClick={() => {\n                if (!isClickable) return;\n\n                onSelectChange?.(selected === key ? null : key);\n              }}\n            >\n              {itemConfig?.icon && !hideIcon ? (\n                <itemConfig.icon />\n              ) : (\n                <LegendIndicator\n                  variant={variant}\n                  dataKey={key}\n                  colorsCount={colorsCount}\n                />\n              )}\n              {itemConfig?.label}\n            </div>\n          );\n        })}\n    </div>\n  );\n}\n\n// ---------------------------------------------------------------------------\n// Legend indicator — each variant gets its own branch so future variants\n// can diverge freely in markup & style.\n// ---------------------------------------------------------------------------\n\nfunction LegendIndicator({\n  variant,\n  dataKey,\n  colorsCount,\n}: {\n  variant: ChartLegendVariant;\n  dataKey: string;\n  colorsCount: number;\n}) {\n  const fillStyle = getLegendFillStyle(dataKey, colorsCount);\n  const outlineStyle = getLegendOutlineStyle(dataKey, colorsCount);\n\n  switch (variant) {\n    case \"square\":\n      return <div className=\"h-2 w-2 shrink-0\" style={fillStyle} />;\n\n    case \"circle\":\n      return <div className=\"h-2 w-2 shrink-0 rounded-full\" style={fillStyle} />;\n\n    case \"circle-outline\":\n      return (\n        <div\n          className=\"h-2.5 w-2.5 shrink-0 rounded-full p-[1.5px]\"\n          style={outlineStyle}\n        />\n      );\n\n    case \"vertical-bar\":\n      return <div className=\"h-3 w-1 shrink-0 rounded-[2px]\" style={fillStyle} />;\n\n    case \"horizontal-bar\":\n      return <div className=\"h-1 w-3 shrink-0 rounded-[2px]\" style={fillStyle} />;\n\n    case \"rounded-square-outline\":\n      return (\n        <div\n          className=\"h-2.5 w-2.5 shrink-0 rounded-[3px] p-[1.5px]\"\n          style={outlineStyle}\n        />\n      );\n\n    case \"rounded-square\":\n    default:\n      return <div className=\"h-2 w-2 shrink-0 rounded-[2px]\" style={fillStyle} />;\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Style helpers\n// ---------------------------------------------------------------------------\n\n/** Solid fill / gradient background for filled variants. */\nfunction getLegendFillStyle(dataKey: string, colorsCount: number): React.CSSProperties {\n  if (colorsCount <= 1) {\n    return { backgroundColor: `var(--color-${dataKey}-0)` };\n  }\n\n  const stops = Array.from({ length: colorsCount }, (_, i) => {\n    const offset = (i / (colorsCount - 1)) * 100;\n    return `var(--color-${dataKey}-${i}) ${offset}%`;\n  }).join(\", \");\n\n  return { background: `linear-gradient(to right, ${stops})` };\n}\n\n/**\n * Outline style for stroke variants.\n * Uses background + mask-composite to punch out the center, leaving only the\n * \"border\" visible. Works with both solid colors and gradients, and respects\n * border-radius — unlike plain `border-color`.\n */\nfunction getLegendOutlineStyle(dataKey: string, colorsCount: number): React.CSSProperties {\n  const maskStyle: React.CSSProperties = {\n    WebkitMask:\n      \"linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)\",\n    WebkitMaskComposite: \"xor\",\n    mask: \"linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)\",\n    maskComposite: \"exclude\",\n  };\n\n  if (colorsCount <= 1) {\n    return {\n      backgroundColor: `var(--color-${dataKey}-0)`,\n      ...maskStyle,\n    };\n  }\n\n  const stops = Array.from({ length: colorsCount }, (_, i) => {\n    const offset = (i / (colorsCount - 1)) * 100;\n    return `var(--color-${dataKey}-${i}) ${offset}%`;\n  }).join(\", \");\n\n  return {\n    background: `linear-gradient(to right, ${stops})`,\n    ...maskStyle,\n  };\n}\n\nconst ChartLegend = RechartsPrimitive.Legend;\n\nexport { ChartLegend, ChartLegendContent, type ChartLegendVariant };\n",
      "type": "registry:component",
      "target": "components/evilcharts/ui/recharts-legend.tsx"
    }
  ],
  "type": "registry:component"
}