{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chart",
  "title": "Chart",
  "description": "shadcn's Chart over Recharts, restyled to the brand. Recharts is a charting library rather than a headless primitive library, so nothing here swaps out of Radix; what the port changes is the palette. ChartContainer takes a ChartConfig keyed by series and ChartStyle writes it out as --color-<series> custom properties scoped to that one chart's data-chart attribute, so a series colour is passed in by the caller from the brand tokens and never restated here. Recharts paints its own defaults as literal hex, so the container overrides them by attribute selector: grid, polar-grid and reference lines take --border, the tooltip cursor takes --border or --muted, and the white dot and sector strokes go transparent. Axis ticks and legend labels are --text-subtle. The tooltip surface is the raised popover at the kit radius with the overlay shadow and a themed hairline, matching Popover and DropdownMenu. ChartContainer is a plain div that forwards its props, so the caller owns the accessible name: give the chart role=\"img\" with an aria-label, or a figure with a caption.",
  "dependencies": [
    "recharts@3.8.0"
  ],
  "registryDependencies": [
    "@waimakers/utils",
    "@waimakers/theme"
  ],
  "files": [
    {
      "path": "src/components/ui/chart.tsx",
      "content": "import * as React from \"react\";\nimport * as RechartsPrimitive from \"recharts\";\nimport type { TooltipValueType } from \"recharts\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst THEMES = {\n  light: { media: null },\n  dark: { media: \"(prefers-color-scheme: dark)\" },\n} as const satisfies Record<string, { media: string | null }>;\n\nconst INITIAL_DIMENSION = { width: 320, height: 200 } as const;\ntype TooltipNameType = number | string;\n\nexport type ChartConfig = Record<\n  string,\n  {\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\nfunction ChartContainer({\n  id,\n  className,\n  children,\n  config,\n  initialDimension = INITIAL_DIMENSION,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  config: ChartConfig;\n  children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>[\"children\"];\n  initialDimension?: {\n    width: number;\n    height: number;\n  };\n}) {\n  const uniqueId = React.useId();\n  const chartId = `chart-${id ?? uniqueId.replace(/:/g, \"\")}`;\n  const context = React.useMemo(() => ({ config }), [config]);\n\n  return (\n    <ChartContext.Provider value={context}>\n      <div\n        data-slot=\"chart\"\n        data-chart={chartId}\n        className={cn(\n          \"flex aspect-video justify-center text-xs [&_.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-dot[stroke='#fff']]:stroke-transparent [&_.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-sector[stroke='#fff']]:stroke-transparent\",\n          className,\n        )}\n        {...props}\n      >\n        <ChartStyle id={chartId} config={config} />\n        <RechartsPrimitive.ResponsiveContainer initialDimension={initialDimension}>\n          {children}\n        </RechartsPrimitive.ResponsiveContainer>\n      </div>\n    </ChartContext.Provider>\n  );\n}\n\nconst CSS_IDENTIFIER = /^[a-zA-Z0-9_-]+$/u;\nconst CSS_PUNCTUATION = /[;{}<]/u;\n\nfunction colorDeclaration(key: string, color: string | undefined): string | null {\n  if (color === undefined || !CSS_IDENTIFIER.test(key) || CSS_PUNCTUATION.test(color)) {\n    return null;\n  }\n\n  return `  --color-${key}: ${color};`;\n}\n\nfunction chartStylesheet(id: string, config: ChartConfig): string | null {\n  if (!CSS_IDENTIFIER.test(id)) {\n    return null;\n  }\n\n  const blocks = Object.entries(THEMES).flatMap(([theme, { media }]) => {\n    const declarations = Object.entries(config)\n      .map(([key, itemConfig]) =>\n        colorDeclaration(\n          key,\n          itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ?? itemConfig.color,\n        ),\n      )\n      .filter((declaration) => declaration !== null);\n\n    if (declarations.length === 0) {\n      return [];\n    }\n\n    const rule = `[data-chart=${id}] {\\n${declarations.join(\"\\n\")}\\n}`;\n    return [media === null ? rule : `@media ${media} {\\n${rule}\\n}`];\n  });\n\n  return blocks.length === 0 ? null : blocks.join(\"\\n\");\n}\n\nconst ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {\n  const stylesheet = chartStylesheet(id, config);\n\n  if (stylesheet === null) {\n    return null;\n  }\n\n  return <style>{stylesheet}</style>;\n};\n\nfunction configKey(...candidates: readonly unknown[]): string {\n  for (const candidate of candidates) {\n    if (typeof candidate === \"string\") {\n      return candidate;\n    }\n    if (typeof candidate === \"number\") {\n      return String(candidate);\n    }\n  }\n\n  return \"value\";\n}\n\nconst ChartTooltip = RechartsPrimitive.Tooltip;\n\nfunction ChartTooltipContent({\n  active,\n  payload,\n  className,\n  indicator = \"dot\",\n  hideLabel = false,\n  hideIndicator = false,\n  label,\n  labelFormatter,\n  labelClassName,\n  formatter,\n  color,\n  nameKey,\n  labelKey,\n}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &\n  React.ComponentProps<\"div\"> & {\n    hideLabel?: boolean;\n    hideIndicator?: boolean;\n    indicator?: \"line\" | \"dot\" | \"dashed\";\n    nameKey?: string;\n    labelKey?: string;\n  } & Omit<\n    RechartsPrimitive.DefaultTooltipContentProps<TooltipValueType, TooltipNameType>,\n    \"accessibilityLayer\"\n  >) {\n  const { config } = useChart();\n\n  const tooltipLabel = React.useMemo(() => {\n    if (hideLabel || !payload?.length) {\n      return null;\n    }\n\n    const [item] = payload;\n    const key = configKey(labelKey, item?.dataKey, item?.name);\n    const itemConfig = getPayloadConfigFromPayload(config, item, key);\n    const value =\n      !labelKey && typeof label === \"string\" ? (config[label]?.label ?? label) : itemConfig?.label;\n\n    if (labelFormatter) {\n      return (\n        <div className={cn(\"font-medium\", labelClassName)}>{labelFormatter(value, payload)}</div>\n      );\n    }\n\n    if (!value) {\n      return null;\n    }\n\n    return <div className={cn(\"font-medium\", labelClassName)}>{value}</div>;\n  }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey]);\n\n  if (!active || !payload?.length) {\n    return null;\n  }\n\n  const nestLabel = payload.length === 1 && indicator !== \"dot\";\n\n  return (\n    <div\n      className={cn(\n        \"grid min-w-[8rem] items-start gap-1.5 rounded-md border border-border bg-popover px-2.5 py-1.5 text-popover-foreground text-xs shadow-brand-overlay\",\n        className,\n      )}\n    >\n      {!nestLabel ? tooltipLabel : null}\n      <div className=\"grid gap-1.5\">\n        {payload\n          .filter((item) => item.type !== \"none\")\n          .map((item, index) => {\n            const key = configKey(nameKey, item.name, item.dataKey);\n            const itemConfig = getPayloadConfigFromPayload(config, item, key);\n            const indicatorColor = color ?? item.payload?.fill ?? item.color;\n\n            return (\n              <div\n                key={index}\n                className={cn(\n                  \"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground\",\n                  indicator === \"dot\" && \"items-center\",\n                )}\n              >\n                {formatter && item?.value !== undefined && item.name ? (\n                  formatter(item.value, item.name, item, index, item.payload)\n                ) : (\n                  <>\n                    {itemConfig?.icon ? (\n                      <itemConfig.icon />\n                    ) : (\n                      !hideIndicator && (\n                        <div\n                          className={cn(\n                            \"shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)\",\n                            {\n                              \"h-2.5 w-2.5\": indicator === \"dot\",\n                              \"w-1\": indicator === \"line\",\n                              \"w-0 border-[1.5px] border-dashed bg-transparent\":\n                                indicator === \"dashed\",\n                              \"my-0.5\": nestLabel && indicator === \"dashed\",\n                            },\n                          )}\n                          style={\n                            {\n                              \"--color-bg\": indicatorColor,\n                              \"--color-border\": indicatorColor,\n                            } as React.CSSProperties\n                          }\n                        />\n                      )\n                    )}\n                    <div\n                      className={cn(\n                        \"flex flex-1 justify-between 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 != null && (\n                        <span className=\"font-mono font-medium text-foreground tabular-nums\">\n                          {typeof item.value === \"number\"\n                            ? item.value.toLocaleString()\n                            : String(item.value)}\n                        </span>\n                      )}\n                    </div>\n                  </>\n                )}\n              </div>\n            );\n          })}\n      </div>\n    </div>\n  );\n}\n\nconst ChartLegend = RechartsPrimitive.Legend;\n\nfunction ChartLegendContent({\n  className,\n  hideIcon = false,\n  payload,\n  verticalAlign = \"bottom\",\n  nameKey,\n}: React.ComponentProps<\"div\"> & {\n  hideIcon?: boolean;\n  nameKey?: string;\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 justify-center gap-4\",\n        verticalAlign === \"top\" ? \"pb-3\" : \"pt-3\",\n        className,\n      )}\n    >\n      {payload\n        .filter((item) => item.type !== \"none\")\n        .map((item, index) => {\n          const key = configKey(nameKey, item.dataKey);\n          const itemConfig = getPayloadConfigFromPayload(config, item, key);\n\n          return (\n            <div\n              key={index}\n              className={cn(\n                \"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground\",\n              )}\n            >\n              {itemConfig?.icon && !hideIcon ? (\n                <itemConfig.icon />\n              ) : (\n                <div\n                  className=\"h-2 w-2 shrink-0 rounded-[2px]\"\n                  style={{\n                    backgroundColor: item.color,\n                  }}\n                />\n              )}\n              {itemConfig?.label}\n            </div>\n          );\n        })}\n    </div>\n  );\n}\n\nfunction getPayloadConfigFromPayload(config: ChartConfig, payload: unknown, key: string) {\n  if (typeof payload !== \"object\" || payload === null) {\n    return undefined;\n  }\n\n  const payloadPayload =\n    \"payload\" in payload && typeof payload.payload === \"object\" && payload.payload !== null\n      ? payload.payload\n      : undefined;\n\n  let configLabelKey: string = key;\n\n  if (key in payload && typeof payload[key as keyof typeof payload] === \"string\") {\n    configLabelKey = payload[key as keyof typeof payload] as string;\n  } else if (\n    payloadPayload &&\n    key in payloadPayload &&\n    typeof payloadPayload[key as keyof typeof payloadPayload] === \"string\"\n  ) {\n    configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string;\n  }\n\n  return configLabelKey in config ? config[configLabelKey] : config[key];\n}\n\nexport {\n  ChartContainer,\n  ChartTooltip,\n  ChartTooltipContent,\n  ChartLegend,\n  ChartLegendContent,\n  ChartStyle,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/chart.tsx"
    }
  ],
  "type": "registry:ui"
}