{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chart",
  "title": "Chart",
  "description": "Beautiful charts. Built using Recharts.",
  "dependencies": [
    "recharts"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/chart.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n  Legend as RechartsLegend,\n  Tooltip as RechartsTooltip,\n  ResponsiveContainer,\n} from \"recharts\";\nimport type { LegendPayload } from \"recharts/types/component/DefaultLegendContent\";\nimport type {\n  NameType,\n  Payload,\n  ValueType,\n} from \"recharts/types/component/DefaultTooltipContent\";\nimport type { Props as LegendProps } from \"recharts/types/component/Legend\";\nimport type { TooltipContentProps } from \"recharts/types/component/Tooltip\";\nimport { cn } from \"@/registry/lib/utils\";\n\ndeclare module \"react\" {\n  interface CSSProperties {\n    [key: `--${string}`]: string | number | undefined;\n  }\n}\n\nconst THEMES = { dark: \".dark\", light: \"\" } as const;\n\nexport type ChartConfig = {\n  [k in string]: {\n    label?: React.ReactNode;\n    icon?: React.ComponentType;\n  } & (\n    | { color?: string; theme?: never }\n    | { color?: never; theme: Record<keyof typeof THEMES, string> }\n  );\n};\n\ntype ChartContextProps = {\n  config: ChartConfig;\n};\n\nconst ChartContext = React.createContext<ChartContextProps | null>(null);\n\nfunction useChart() {\n  const context = React.useContext(ChartContext);\n\n  if (!context) {\n    throw new Error(\"useChart must be used within a <ChartContainer />\");\n  }\n\n  return context;\n}\n\ninterface ChartItem {\n  dataKey?: string | number;\n  payload?: Record<string, unknown> | undefined;\n  name?: string | number;\n  value?: ValueType | string | undefined;\n  color?: string;\n  fill?: string;\n}\n\nfunction ChartContainer({\n  id,\n  className,\n  children,\n  config,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  config: ChartConfig;\n  children: React.ComponentProps<typeof ResponsiveContainer>[\"children\"];\n}) {\n  const uniqueId = React.useId();\n  const chartId = `chart-${id || uniqueId.replace(/:/g, \"\")}`;\n\n  return (\n    <ChartContext.Provider value={{ config }}>\n      <div\n        className={cn(\n          \"min-w-0 min-h-0 aspect-auto w-full h-full text-xs\",\n          \"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-sector[stroke='#fff']]:stroke-transparent\",\n          \"[&_.recharts-wrapper]:outline-hidden [&_.recharts-surface]:outline-hidden [&_g]:outline-hidden\",\n          className,\n        )}\n        data-chart={chartId}\n        data-slot=\"chart\"\n        {...props}\n      >\n        <ChartStyle config={config} id={chartId} />\n        <ResponsiveContainer\n          initialDimension={{ height: 100, width: 100 }}\n          minHeight={100}\n          minWidth={100}\n        >\n          {children}\n        </ResponsiveContainer>\n      </div>\n    </ChartContext.Provider>\n  );\n}\n\nconst ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {\n  const colorConfig = Object.entries(config).filter(\n    ([, config]) => config.theme || config.color,\n  );\n\n  if (!colorConfig.length) {\n    return null;\n  }\n\n  return (\n    <style\n      dangerouslySetInnerHTML={{\n        __html: Object.entries(THEMES)\n          .map(\n            ([theme, prefix]) => `\n            ${prefix} [data-chart=${id}] {\n            ${colorConfig\n              .map(([key, itemConfig]) => {\n                const color =\n                  itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||\n                  itemConfig.color;\n                return color ? `  --color-${key}: ${color};` : null;\n              })\n              .join(\"\\n\")}\n            }\n            `,\n          )\n          .join(\"\\n\"),\n      }}\n    />\n  );\n};\n\nconst ChartTooltip = RechartsTooltip;\n\ntype CustomTooltipProps<\n  TValue extends ValueType = ValueType,\n  TName extends NameType = NameType,\n> = Partial<Omit<TooltipContentProps<TValue, TName>, \"payload\">> & {\n  payload?: ReadonlyArray<Payload<TValue, TName>>;\n  className?: string;\n  hideLabel?: boolean;\n  hideIndicator?: boolean;\n  indicator?: \"line\" | \"dot\" | \"dashed\";\n  nameKey?: string;\n  labelKey?: string;\n  labelFormatter?: (\n    label: TooltipContentProps<TValue, TName>[\"label\"],\n    payload: ReadonlyArray<Payload<TValue, TName>>,\n  ) => React.ReactNode;\n  formatter?: (\n    value: TValue | undefined,\n    name: TName | undefined,\n    item: Payload<TValue, TName>,\n    index: number,\n    payload: ReadonlyArray<Payload<TValue, TName>>,\n  ) => React.ReactNode;\n  labelClassName?: string;\n  color?: string;\n};\n\nfunction ChartTooltipContent<TValue extends ValueType, TName extends NameType>({\n  active,\n  payload,\n  label,\n  className,\n  indicator = \"dot\",\n  hideLabel = false,\n  hideIndicator = false,\n  labelFormatter,\n  formatter,\n  labelClassName,\n  color,\n  nameKey,\n  labelKey,\n}: CustomTooltipProps<TValue, TName>) {\n  const { config } = useChart();\n  const payloadItems = payload ?? [];\n  const isVisible = Boolean(active && payloadItems.length);\n\n  const tooltipLabel = React.useMemo(() => {\n    if (hideLabel || !payload?.length) {\n      return null;\n    }\n\n    const [item] = payload;\n    const key = `${labelKey || item.dataKey || item.name || \"value\"}`;\n    const itemConfig = getPayloadConfigFromPayload(config, item, key);\n    const value = (() => {\n      const v =\n        !labelKey && typeof label === \"string\"\n          ? config[label as keyof typeof config]?.label || label\n          : itemConfig?.label;\n\n      return typeof v === \"string\" || typeof v === \"number\" ? v : undefined;\n    })();\n\n    if (labelFormatter) {\n      return (\n        <div className={cn(\"font-medium\", labelClassName)}>\n          {labelFormatter(value, payload)}\n        </div>\n      );\n    }\n\n    if (!value) {\n      return null;\n    }\n\n    return <div className={cn(\"font-medium\", labelClassName)}>{value}</div>;\n  }, [\n    label,\n    labelFormatter,\n    payload,\n    hideLabel,\n    labelClassName,\n    config,\n    labelKey,\n  ]);\n\n  const nestLabel = payloadItems.length === 1 && indicator !== \"dot\";\n\n  return (\n    <div\n      className={cn(\n        \"border-border/50 bg-accent text-accent-foreground overlay-outline grid min-w-16 items-start gap-1.5 rounded-sm px-2.5 py-1.5 text-xs shadow-xl\",\n        className,\n      )}\n      // Workaround for Recharts tooltip reset to top-left with custom content:\n      // https://github.com/recharts/recharts/issues/5986\n      style={{ visibility: isVisible ? \"visible\" : \"hidden\" }}\n    >\n      {!nestLabel ? tooltipLabel : null}\n      <div className=\"grid gap-1.5\">\n        {payloadItems.map((item, index) => {\n          const key = `${nameKey || item.name || item.dataKey || \"value\"}`;\n          const itemConfig = getPayloadConfigFromPayload(config, item, key);\n          const indicatorColor = color || item.payload?.fill || item.color;\n\n          return (\n            <div\n              className={cn(\n                \"[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5\",\n                indicator === \"dot\" && \"items-center\",\n              )}\n              key={`${item.dataKey}-${index}`}\n            >\n              {formatter && item?.value !== undefined && item.name ? (\n                formatter(item.value, item.name, item, index, payloadItems)\n              ) : (\n                <>\n                  {itemConfig?.icon ? (\n                    <itemConfig.icon />\n                  ) : (\n                    !hideIndicator && (\n                      <div\n                        className={cn(\n                          \"shrink-0 rounded-xs border-(--color-border) bg-(--color-bg)\",\n                          {\n                            \"h-2.5 w-2.5\": indicator === \"dot\",\n                            \"my-0.5\": nestLabel && indicator === \"dashed\",\n                            \"w-0 border border-dashed bg-transparent\":\n                              indicator === \"dashed\",\n                            \"w-1\": indicator === \"line\",\n                          },\n                        )}\n                        style={{\n                          \"--color-bg\": indicatorColor,\n                          \"--color-border\": indicatorColor,\n                        }}\n                      />\n                    )\n                  )}\n                  <div\n                    className={cn(\n                      \"flex flex-1 gap-2 leading-none\",\n                      nestLabel ? \"items-end\" : \"items-center\",\n                    )}\n                  >\n                    <div className=\"grid gap-1.5\">\n                      {nestLabel ? tooltipLabel : null}\n                      <span className=\"text-muted-foreground\">\n                        {itemConfig?.label || item.name}\n                      </span>\n                    </div>\n                    {item.value && (\n                      <span className=\"font-medium tabular-nums\">\n                        {item.value.toLocaleString()}\n                      </span>\n                    )}\n                  </div>\n                </>\n              )}\n            </div>\n          );\n        })}\n      </div>\n    </div>\n  );\n}\n\nconst ChartLegend = RechartsLegend;\n\ntype ChartLegendContentProps = {\n  className?: string;\n  hideIcon?: boolean;\n  verticalAlign?: LegendProps[\"verticalAlign\"];\n  payload?: LegendPayload[];\n  nameKey?: string;\n};\n\nfunction ChartLegendContent({\n  className,\n  hideIcon = false,\n  payload,\n  verticalAlign = \"bottom\",\n  nameKey,\n}: ChartLegendContentProps) {\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 justify-center gap-4\",\n        verticalAlign === \"top\" ? \"pb-3\" : \"pt-3\",\n        className,\n      )}\n    >\n      {payload.map((item) => {\n        const key = `${nameKey || item.dataKey || \"value\"}`;\n        const itemConfig = getPayloadConfigFromPayload(config, item, key);\n\n        return (\n          <div\n            className={cn(\n              \"[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3\",\n            )}\n            key={item.value}\n          >\n            {itemConfig?.icon && !hideIcon ? (\n              <itemConfig.icon />\n            ) : (\n              <div\n                className=\"h-2 w-2 shrink-0 rounded-xs\"\n                style={{\n                  backgroundColor: item.color,\n                }}\n              />\n            )}\n            {itemConfig?.label}\n          </div>\n        );\n      })}\n    </div>\n  );\n}\n\nfunction getPayloadConfigFromPayload(\n  config: ChartConfig,\n  payload: unknown,\n  key: string,\n) {\n  if (typeof payload !== \"object\" || payload === null) {\n    return undefined;\n  }\n\n  const payloadItem = payload as ChartItem;\n\n  let configLabelKey: string = key;\n\n  if (\n    key in payloadItem &&\n    typeof payloadItem[key as keyof ChartItem] === \"string\"\n  ) {\n    configLabelKey = payloadItem[key as keyof ChartItem] as string;\n  } else if (\n    payloadItem.payload &&\n    key in payloadItem.payload &&\n    typeof payloadItem.payload[key] === \"string\"\n  ) {\n    configLabelKey = payloadItem.payload[key] as string;\n  }\n\n  return configLabelKey in config\n    ? config[configLabelKey]\n    : config[key as keyof typeof config];\n}\n\nexport {\n  ChartContainer,\n  ChartLegend,\n  ChartLegendContent,\n  ChartStyle,\n  ChartTooltip,\n  ChartTooltipContent,\n};\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}