{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chart",
  "title": "Chart",
  "description": "Recharts wrapper with theme-aware colors, tooltips and legends.",
  "dependencies": [
    "recharts@3.8.0"
  ],
  "files": [
    {
      "path": "registry/rapid/ui/chart/chart.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport type { TooltipValueType } from 'recharts'\nimport * as RechartsPrimitive from 'recharts'\nimport { cn } from '@/lib/utils'\n\n// Format: { THEME_NAME: CSS_SELECTOR }\nconst THEMES = { light: '', dark: '.dark' } as const\n\nconst INITIAL_DIMENSION = { width: 320, height: 200 } as const\ntype TooltipNameType = number | string\n\nexport type ChartConfig = Record<\n\tstring,\n\t{\n\t\tlabel?: React.ReactNode\n\t\ticon?: React.ComponentType\n\t} & ({ color?: string; theme?: never } | { color?: never; theme: Record<keyof typeof THEMES, string> })\n>\n\ntype ChartContextProps = {\n\tconfig: ChartConfig\n}\n\nconst ChartContext = React.createContext<ChartContextProps | null>(null)\n\nfunction useChart() {\n\tconst context = React.useContext(ChartContext)\n\n\tif (!context) {\n\t\tthrow new Error('useChart must be used within a <ChartContainer />')\n\t}\n\n\treturn context\n}\n\nfunction ChartContainer({\n\tid,\n\tclassName,\n\tchildren,\n\tconfig,\n\tinitialDimension = INITIAL_DIMENSION,\n\t...props\n}: React.ComponentProps<'div'> & {\n\tconfig: ChartConfig\n\tchildren: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>['children']\n\tinitialDimension?: {\n\t\twidth: number\n\t\theight: number\n\t}\n}) {\n\tconst uniqueId = React.useId()\n\tconst chartId = `chart-${id ?? uniqueId.replaceAll(':', '')}`\n\n\treturn (\n\t\t<ChartContext.Provider value={{ config }}>\n\t\t\t<div\n\t\t\t\tdata-slot=\"chart\"\n\t\t\t\tdata-chart={chartId}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"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-layer]:outline-hidden [&_.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]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t<ChartStyle id={chartId} config={config} />\n\t\t\t\t<RechartsPrimitive.ResponsiveContainer initialDimension={initialDimension}>\n\t\t\t\t\t{children}\n\t\t\t\t</RechartsPrimitive.ResponsiveContainer>\n\t\t\t</div>\n\t\t</ChartContext.Provider>\n\t)\n}\n\nconst ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {\n\tconst colorConfig = Object.entries(config).filter(([, config]) => config.theme ?? config.color)\n\n\tif (!colorConfig.length) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<style\n\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t__html: Object.entries(THEMES)\n\t\t\t\t\t.map(\n\t\t\t\t\t\t([theme, prefix]) => `\n${prefix} [data-chart=${id}] {\n${colorConfig\n\t.map(([key, itemConfig]) => {\n\t\tconst color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ?? itemConfig.color\n\t\treturn color ? `  --color-${key}: ${color};` : null\n\t})\n\t.join('\\n')}\n}\n`,\n\t\t\t\t\t)\n\t\t\t\t\t.join('\\n'),\n\t\t\t}}\n\t\t/>\n\t)\n}\n\nconst ChartTooltip = RechartsPrimitive.Tooltip\n\nfunction ChartTooltipContent({\n\tactive,\n\tpayload,\n\tclassName,\n\tindicator = 'dot',\n\thideLabel = false,\n\thideIndicator = false,\n\tlabel,\n\tlabelFormatter,\n\tlabelClassName,\n\tformatter,\n\tcolor,\n\tnameKey,\n\tlabelKey,\n}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &\n\tReact.ComponentProps<'div'> & {\n\t\thideLabel?: boolean\n\t\thideIndicator?: boolean\n\t\tindicator?: 'line' | 'dot' | 'dashed'\n\t\tnameKey?: string\n\t\tlabelKey?: string\n\t} & Omit<RechartsPrimitive.DefaultTooltipContentProps<TooltipValueType, TooltipNameType>, 'accessibilityLayer'>) {\n\tconst { config } = useChart()\n\n\tconst tooltipLabel = React.useMemo(() => {\n\t\tif (hideLabel || !payload?.length) {\n\t\t\treturn null\n\t\t}\n\n\t\tconst [item] = payload\n\t\tconst key = `${labelKey ?? item?.dataKey ?? item?.name ?? 'value'}`\n\t\tconst itemConfig = getPayloadConfigFromPayload(config, item, key)\n\t\tconst value = !labelKey && typeof label === 'string' ? (config[label]?.label ?? label) : itemConfig?.label\n\n\t\tif (labelFormatter) {\n\t\t\treturn <div className={cn('font-medium', labelClassName)}>{labelFormatter(value, payload)}</div>\n\t\t}\n\n\t\tif (!value) {\n\t\t\treturn null\n\t\t}\n\n\t\treturn <div className={cn('font-medium', labelClassName)}>{value}</div>\n\t}, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey])\n\n\tif (!active || !payload?.length) {\n\t\treturn null\n\t}\n\n\tconst nestLabel = payload.length === 1 && indicator !== 'dot'\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'grid min-w-32 items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{!nestLabel ? tooltipLabel : null}\n\t\t\t<div className=\"grid gap-1.5\">\n\t\t\t\t{payload\n\t\t\t\t\t.filter((item) => item.type !== 'none')\n\t\t\t\t\t.map((item, index) => {\n\t\t\t\t\t\tconst key = `${nameKey ?? item.name ?? item.dataKey ?? 'value'}`\n\t\t\t\t\t\tconst itemConfig = getPayloadConfigFromPayload(config, item, key)\n\t\t\t\t\t\tconst indicatorColor = color ?? item.payload?.fill ?? item.color\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t// One row per series; a series with several values (a scatter point) differs by data key and name\n\t\t\t\t\t\t\t\tkey={`${item.graphicalItemId}:${item.dataKey}:${item.name}`}\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground',\n\t\t\t\t\t\t\t\t\tindicator === 'dot' && 'items-center',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{formatter && item?.value !== undefined && item.name ? (\n\t\t\t\t\t\t\t\t\tformatter(item.value, item.name, item, index, item.payload)\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t{itemConfig?.icon ? (\n\t\t\t\t\t\t\t\t\t\t\t<itemConfig.icon />\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t!hideIndicator && (\n\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn('shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)', {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'h-2.5 w-2.5': indicator === 'dot',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'w-1': indicator === 'line',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'w-0 border-[1.5px] border-dashed bg-transparent': indicator === 'dashed',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'my-0.5': nestLabel && indicator === 'dashed',\n\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'--color-bg': indicatorColor,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'--color-border': indicatorColor,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t} as React.CSSProperties\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t<div className={cn('flex flex-1 justify-between leading-none', nestLabel ? 'items-end' : 'items-center')}>\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"grid gap-1.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t{nestLabel ? tooltipLabel : null}\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">{itemConfig?.label ?? item.name}</span>\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t{item.value != null && (\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono font-medium text-foreground tabular-nums\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{typeof item.value === 'number' ? item.value.toLocaleString() : String(item.value)}\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)\n\t\t\t\t\t})}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nconst ChartLegend = RechartsPrimitive.Legend\n\nfunction ChartLegendContent({\n\tclassName,\n\thideIcon = false,\n\tpayload,\n\tverticalAlign = 'bottom',\n\tnameKey,\n}: React.ComponentProps<'div'> & {\n\thideIcon?: boolean\n\tnameKey?: string\n} & RechartsPrimitive.DefaultLegendContentProps) {\n\tconst { config } = useChart()\n\n\tif (!payload?.length) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<div className={cn('flex items-center justify-center gap-4', verticalAlign === 'top' ? 'pb-3' : 'pt-3', className)}>\n\t\t\t{payload\n\t\t\t\t.filter((item) => item.type !== 'none')\n\t\t\t\t.map((item) => {\n\t\t\t\t\tconst key = `${nameKey ?? item.dataKey ?? 'value'}`\n\t\t\t\t\tconst itemConfig = getPayloadConfigFromPayload(config, item, key)\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t// Series differ by data key; the sectors of one pie share it and differ by name and colour\n\t\t\t\t\t\t\tkey={`${item.dataKey}:${item.value}:${item.color}`}\n\t\t\t\t\t\t\tclassName={cn('flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground')}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{itemConfig?.icon && !hideIcon ? (\n\t\t\t\t\t\t\t\t<itemConfig.icon />\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclassName=\"h-2 w-2 shrink-0 rounded-[2px]\"\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\tbackgroundColor: item.color,\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{itemConfig?.label}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t</div>\n\t)\n}\n\nfunction getPayloadConfigFromPayload(config: ChartConfig, payload: unknown, key: string) {\n\tif (typeof payload !== 'object' || payload === null) {\n\t\treturn undefined\n\t}\n\n\tconst payloadPayload =\n\t\t'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null ? payload.payload : undefined\n\n\tlet configLabelKey: string = key\n\n\tif (key in payload && typeof payload[key as keyof typeof payload] === 'string') {\n\t\tconfigLabelKey = payload[key as keyof typeof payload] as string\n\t} else if (\n\t\tpayloadPayload &&\n\t\tkey in payloadPayload &&\n\t\ttypeof payloadPayload[key as keyof typeof payloadPayload] === 'string'\n\t) {\n\t\tconfigLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string\n\t}\n\n\treturn configLabelKey in config ? config[configLabelKey] : config[key]\n}\n\nexport { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartStyle }\n",
      "type": "registry:ui",
      "target": "components/ui/chart.tsx"
    }
  ],
  "type": "registry:ui"
}