{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "charts",
  "type": "registry:ui",
  "registryDependencies": [],
  "dependencies": ["recharts", "motion"],
  "devDependencies": [],
  "files": [
    {
      "path": "charts.tsx",
      "content": "\"use client\";\n\nimport { motion } from \"motion/react\";\nimport * as React from \"react\";\nimport type { TooltipValueType } from \"recharts\";\nimport * as RechartsPrimitive from \"recharts\";\n\nimport { cn } from \"@/lib/utils\";\n\n// Format: { THEME_NAME: CSS_SELECTOR }\nconst THEMES = { light: \"\", dark: \".dark\" } as const;\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\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 payloadPayload =\n    \"payload\" in payload &&\n    typeof payload.payload === \"object\" &&\n    payload.payload !== null\n      ? payload.payload\n      : undefined;\n\n  let configLabelKey: string = key;\n\n  if (\n    key in payload &&\n    typeof payload[key as keyof typeof payload] === \"string\"\n  ) {\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[\n      key as keyof typeof payloadPayload\n    ] as string;\n  }\n\n  return configLabelKey in config ? config[configLabelKey] : config[key];\n}\n\nfunction getChartConfigKey(config: ChartConfig, payload: unknown, key: string) {\n  if (typeof payload !== \"object\" || payload === null) {\n    return key;\n  }\n\n  const payloadPayload =\n    \"payload\" in payload &&\n    typeof payload.payload === \"object\" &&\n    payload.payload !== null\n      ? payload.payload\n      : undefined;\n\n  let configLabelKey: string = key;\n\n  if (\n    key in payload &&\n    typeof payload[key as keyof typeof payload] === \"string\"\n  ) {\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[\n      key as keyof typeof payloadPayload\n    ] as string;\n  }\n\n  if (configLabelKey in config) {\n    return configLabelKey;\n  }\n\n  return key in config ? key : key;\n}\n\nfunction normalizeChartField(\n  value: string | number | ((obj: unknown) => unknown) | undefined\n) {\n  return typeof value === \"function\" ? undefined : value;\n}\n\nfunction getChartSeriesKey(item: unknown, nameKey?: string) {\n  if (typeof item !== \"object\" || item === null) {\n    return nameKey ?? \"value\";\n  }\n\n  const record = item as {\n    dataKey?: string | number | ((obj: unknown) => unknown);\n    name?: string | number;\n    value?: unknown;\n    payload?: object;\n  };\n\n  if (nameKey) {\n    const payloadRecord =\n      record.payload && typeof record.payload === \"object\"\n        ? (record.payload as Record<string, unknown>)\n        : (record as Record<string, unknown>);\n\n    if (\n      nameKey in payloadRecord &&\n      payloadRecord[nameKey] != null &&\n      payloadRecord[nameKey] !== \"\"\n    ) {\n      return String(payloadRecord[nameKey]);\n    }\n  }\n\n  const dataKey = normalizeChartField(record.dataKey);\n  const value =\n    typeof record.value === \"string\" || typeof record.value === \"number\"\n      ? record.value\n      : undefined;\n\n  return String(dataKey ?? record.name ?? value ?? \"value\");\n}\n\nfunction getChartLegendLabel(\n  item: unknown,\n  itemConfig: ChartConfig[string] | undefined\n) {\n  if (typeof item !== \"object\" || item === null) {\n    return null;\n  }\n\n  const record = item as {\n    dataKey?: string | number | ((obj: unknown) => unknown);\n    name?: string | number;\n    value?: unknown;\n  };\n  if (itemConfig?.label != null) {\n    return itemConfig.label;\n  }\n\n  if (record.name != null) {\n    return String(record.name);\n  }\n\n  if (typeof record.value === \"string\") {\n    return record.value;\n  }\n\n  if (record.dataKey != null && typeof record.dataKey !== \"function\") {\n    return String(record.dataKey);\n  }\n\n  return null;\n}\n\nfunction getChartLegendSwatchColor(\n  configKey: string,\n  itemConfig: ChartConfig[string] | undefined,\n  fallbackColor?: string\n) {\n  if (itemConfig) {\n    return `var(--color-${configKey})`;\n  }\n\n  return fallbackColor;\n}\n\nconst componentThemeClassName =\n  \"[--ic-background:#ffffff] [--ic-foreground:#111111] [--ic-primary:#111111] [--ic-secondary:#646b75] [--ic-surface-border:#e9edf2] [--ic-border:#e3e7ec] [--ic-card:#ffffff] [--ic-card-foreground:#111111] [--ic-muted:#f5f7fa] [--ic-muted-foreground:#6d7480] [--ic-accent:#f3f5f8] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] [--ic-accent-foreground:#111111] [--ic-input:#e3e7ec] [--ic-ring:rgba(17,17,17,0.16)] [--ic-destructive:#dc2626] [--ic-paper:#fcfcfd] [--ic-popover-foreground:#111111] [--ic-brand:#0ea5e9] [--ic-brand-soft:#bae6fd] [--ic-shadow-soft:0_18px_38px_-24px_rgba(15,23,42,0.35)] [--ic-chart-1:#1d4ed8] [--ic-chart-2:#7dd3fc] [--ic-chart-3:oklch(0.42_0.16_262)] [--ic-chart-4:oklch(0.84_0.07_228)] [--ic-chart-5:oklch(0.62_0.14_240)] [--color-background:var(--ic-background)] [--color-foreground:var(--ic-foreground)] [--color-primary:var(--ic-primary)] [--color-secondary:var(--ic-secondary)] [--color-border:var(--ic-border)] [--color-card:var(--ic-card)] [--color-card-foreground:var(--ic-card-foreground)] [--color-muted:var(--ic-muted)] [--color-muted-foreground:var(--ic-muted-foreground)] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] [--color-input:var(--ic-input)] [--color-ring:var(--ic-ring)] [--color-destructive:var(--ic-destructive)] [--color-paper:var(--ic-paper)] [--color-popover-foreground:var(--ic-popover-foreground)] [--color-brand:var(--ic-brand)] [--color-brand-soft:var(--ic-brand-soft)] [--color-chart-1:var(--ic-chart-1)] [--color-chart-2:var(--ic-chart-2)] [--color-chart-3:var(--ic-chart-3)] [--color-chart-4:var(--ic-chart-4)] [--color-chart-5:var(--ic-chart-5)] [--chart-1:var(--ic-chart-1)] [--chart-2:var(--ic-chart-2)] [--chart-3:var(--ic-chart-3)] [--chart-4:var(--ic-chart-4)] [--chart-5:var(--ic-chart-5)] dark:[--ic-background:#111111] dark:[--ic-foreground:#f6f3ec] dark:[--ic-primary:#f6f3ec] dark:[--ic-secondary:#cbc6bb] dark:[--ic-surface-border:#2a2a25] dark:[--ic-border:#2b2a25] dark:[--ic-card:#111111] dark:[--ic-card-foreground:#f6f3ec] dark:[--ic-muted:#171716] dark:[--ic-muted-foreground:#9a958a] dark:[--ic-accent:#1a1a18] [--color-accent:var(--ic-accent)] [--color-accent-foreground:var(--ic-accent-foreground)] dark:[--ic-accent-foreground:#f6f3ec] dark:[--ic-input:#2b2a25] dark:[--ic-ring:rgba(246,243,236,0.18)] dark:[--ic-destructive:#f87171] dark:[--ic-paper:#171716] dark:[--ic-popover-foreground:#f6f3ec] dark:[--ic-brand:#38bdf8] dark:[--ic-brand-soft:#0c4a6e] dark:[--ic-shadow-soft:0_20px_44px_-28px_rgba(0,0,0,0.6)] dark:[--ic-chart-1:#60a5fa] dark:[--ic-chart-2:#bfdbfe] dark:[--ic-chart-3:oklch(0.58_0.15_260)] dark:[--ic-chart-4:oklch(0.75_0.12_235)] dark:[--ic-chart-5:oklch(0.88_0.06_220)]\";\n\n/** Calm easing — no spring overshoot on data surfaces. */\nconst chartEase = [0.22, 1, 0.36, 1] as const;\n\nconst chartSurfaceFade = {\n  duration: 0.22,\n  ease: chartEase,\n};\n\nconst chartTooltipFade = {\n  duration: 0.14,\n  ease: chartEase,\n};\n\nconst CHART_SERIES_ANIMATION_DURATION = 480;\nconst CHART_SERIES_ANIMATION_EASING = \"ease-out\" as const;\nconst CHART_SERIES_STAGGER_MS = 32;\n\nfunction getChartAnimationTimeoutMs(seriesCount: number) {\n  const safeSeriesCount = Math.max(1, seriesCount);\n\n  return (\n    CHART_SERIES_ANIMATION_DURATION +\n    CHART_SERIES_STAGGER_MS * Math.max(0, safeSeriesCount - 1)\n  );\n}\n\nconst MotionDiv = motion.div;\n\ntype MotionSafeDivProps = Omit<\n  React.HTMLAttributes<HTMLDivElement>,\n  | \"onAnimationEnd\"\n  | \"onAnimationIteration\"\n  | \"onAnimationStart\"\n  | \"onDrag\"\n  | \"onDragEnd\"\n  | \"onDragEnter\"\n  | \"onDragExit\"\n  | \"onDragLeave\"\n  | \"onDragOver\"\n  | \"onDragStart\"\n  | \"onDrop\"\n>;\n\ntype TooltipNameType = number | string;\n\nconst CHART_RESIZE_DEBOUNCE_MS = 150;\n\ntype ChartContextProps = {\n  config: ChartConfig;\n  chartAnimationActive: boolean;\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 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      // biome-ignore lint/security/noDangerouslySetInnerHtml: scoped chart color variables from trusted ChartConfig\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\nfunction ChartContainer({\n  id,\n  className,\n  children,\n  config,\n  initialDimension,\n  seriesCount,\n  ...props\n}: MotionSafeDivProps & {\n  config: ChartConfig;\n  children: React.ComponentProps<\n    typeof RechartsPrimitive.ResponsiveContainer\n  >[\"children\"];\n  initialDimension?: {\n    width: number;\n    height: number;\n  };\n  /** Overrides inferred series count for animation timing when config keys do not match plotted series. */\n  seriesCount?: number;\n}) {\n  const uniqueId = React.useId();\n  const chartId = `chart-${id ?? uniqueId.replace(/:/g, \"\")}`;\n  const initialChartAnimationDoneRef = React.useRef(false);\n  const resizeMeasureCountRef = React.useRef(0);\n  const [chartAnimationActive, setChartAnimationActive] = React.useState(true);\n  const resolvedSeriesCount = seriesCount ?? Object.keys(config).length;\n\n  React.useEffect(() => {\n    const timeoutId = window.setTimeout(() => {\n      initialChartAnimationDoneRef.current = true;\n      setChartAnimationActive(false);\n    }, getChartAnimationTimeoutMs(resolvedSeriesCount));\n\n    return () => {\n      window.clearTimeout(timeoutId);\n    };\n  }, [resolvedSeriesCount]);\n\n  const handleResize = React.useCallback(() => {\n    resizeMeasureCountRef.current += 1;\n\n    if (resizeMeasureCountRef.current <= 1) {\n      return;\n    }\n\n    if (initialChartAnimationDoneRef.current) {\n      setChartAnimationActive(false);\n    }\n  }, []);\n\n  return (\n    <ChartContext.Provider\n      value={{\n        config,\n        chartAnimationActive,\n      }}\n    >\n      <MotionDiv\n        animate={{ opacity: 1 }}\n        className={cn(\n          componentThemeClassName,\n          \"flex aspect-video min-h-[12rem] w-full 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[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-hidden [&_.recharts-surface]:outline-hidden\",\n          className\n        )}\n        data-chart={chartId}\n        data-slot=\"chart\"\n        initial={{ opacity: 0 }}\n        transition={chartSurfaceFade}\n        {...props}\n      >\n        <ChartStyle config={config} id={chartId} />\n        <RechartsPrimitive.ResponsiveContainer\n          debounce={CHART_RESIZE_DEBOUNCE_MS}\n          height=\"100%\"\n          onResize={handleResize}\n          width=\"100%\"\n          {...(initialDimension ? { initialDimension } : {})}\n        >\n          {children}\n        </RechartsPrimitive.ResponsiveContainer>\n      </MotionDiv>\n    </ChartContext.Provider>\n  );\n}\n\nfunction useChartSeriesAnimation(seriesIndex = 0) {\n  const { chartAnimationActive } = useChart();\n\n  return {\n    animationBegin: seriesIndex * CHART_SERIES_STAGGER_MS,\n    animationDuration: chartAnimationActive\n      ? CHART_SERIES_ANIMATION_DURATION\n      : 0,\n    animationEasing: CHART_SERIES_ANIMATION_EASING,\n    isAnimationActive: chartAnimationActive,\n  };\n}\n\nfunction ChartBar({\n  animationBegin,\n  animationDuration,\n  animationEasing,\n  isAnimationActive,\n  seriesIndex = 0,\n  ...props\n}: React.ComponentProps<typeof RechartsPrimitive.Bar> & {\n  /** Staggers bar growth when plotting multiple series (0, 1, 2, …). */\n  seriesIndex?: number;\n}) {\n  const defaults = useChartSeriesAnimation(seriesIndex);\n  const shouldAnimate = isAnimationActive ?? defaults.isAnimationActive;\n\n  return (\n    <RechartsPrimitive.Bar\n      {...props}\n      animationBegin={animationBegin ?? defaults.animationBegin}\n      animationDuration={\n        shouldAnimate ? (animationDuration ?? defaults.animationDuration) : 0\n      }\n      animationEasing={animationEasing ?? defaults.animationEasing}\n      isAnimationActive={shouldAnimate}\n    />\n  );\n}\n\nfunction ChartLine({\n  animationBegin,\n  animationDuration,\n  animationEasing,\n  isAnimationActive,\n  seriesIndex = 0,\n  ...props\n}: React.ComponentProps<typeof RechartsPrimitive.Line> & {\n  seriesIndex?: number;\n}) {\n  const defaults = useChartSeriesAnimation(seriesIndex);\n  const shouldAnimate = isAnimationActive ?? defaults.isAnimationActive;\n\n  return (\n    <RechartsPrimitive.Line\n      {...props}\n      animationBegin={animationBegin ?? defaults.animationBegin}\n      animationDuration={\n        shouldAnimate ? (animationDuration ?? defaults.animationDuration) : 0\n      }\n      animationEasing={animationEasing ?? defaults.animationEasing}\n      isAnimationActive={shouldAnimate}\n    />\n  );\n}\n\nfunction ChartArea({\n  animationBegin,\n  animationDuration,\n  animationEasing,\n  isAnimationActive,\n  seriesIndex = 0,\n  ...props\n}: React.ComponentProps<typeof RechartsPrimitive.Area> & {\n  seriesIndex?: number;\n}) {\n  const defaults = useChartSeriesAnimation(seriesIndex);\n  const shouldAnimate = isAnimationActive ?? defaults.isAnimationActive;\n\n  return (\n    <RechartsPrimitive.Area\n      {...props}\n      animationBegin={animationBegin ?? defaults.animationBegin}\n      animationDuration={\n        shouldAnimate ? (animationDuration ?? defaults.animationDuration) : 0\n      }\n      animationEasing={animationEasing ?? defaults.animationEasing}\n      isAnimationActive={shouldAnimate}\n    />\n  );\n}\n\nfunction ChartTooltipRow({\n  color,\n  formatter,\n  hideIndicator,\n  index,\n  indicator,\n  item,\n  itemConfig,\n  nestLabel,\n  tooltipLabel,\n}: {\n  color?: string;\n  formatter: React.ComponentProps<typeof ChartTooltipContent>[\"formatter\"];\n  hideIndicator: boolean;\n  index: number;\n  indicator: \"line\" | \"dot\" | \"dashed\";\n  item: NonNullable<\n    React.ComponentProps<typeof ChartTooltipContent>[\"payload\"]\n  >[number];\n  itemConfig: ChartConfig[string] | undefined;\n  nestLabel: boolean;\n  tooltipLabel: React.ReactNode;\n}) {\n  const indicatorColor = color ?? item.payload?.fill ?? item.color;\n\n  return (\n    <div\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 ? (\n        formatter(\n          item.value,\n          item.name ?? String(item.dataKey ?? index),\n          item,\n          index,\n          item.payload\n        )\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-medium font-mono 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\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<\n      TooltipValueType,\n      TooltipNameType\n    >,\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 = `${labelKey ?? item?.dataKey ?? item?.name ?? \"value\"}`;\n    const itemConfig = getPayloadConfigFromPayload(config, item, key);\n    const value =\n      !labelKey && typeof label === \"string\"\n        ? (config[label]?.label ?? label)\n        : itemConfig?.label;\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  if (!(active && payload?.length)) {\n    return null;\n  }\n\n  const nestLabel = payload.length === 1 && indicator !== \"dot\";\n\n  return (\n    <MotionDiv\n      animate={{ opacity: 1 }}\n      className={cn(\n        \"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        className\n      )}\n      initial={{ opacity: 0 }}\n      role=\"tooltip\"\n      transition={chartTooltipFade}\n    >\n      {nestLabel ? null : tooltipLabel}\n      <div className=\"grid gap-1.5\">\n        {payload\n          .filter((item) => item.type !== \"none\")\n          .map((item, index) => {\n            const key = getChartSeriesKey(item, nameKey);\n            const itemConfig = getPayloadConfigFromPayload(config, item, key);\n\n            return (\n              <ChartTooltipRow\n                color={color}\n                formatter={formatter}\n                hideIndicator={hideIndicator}\n                index={index}\n                indicator={indicator}\n                item={item}\n                itemConfig={itemConfig}\n                key={`${key}-${index}`}\n                nestLabel={nestLabel}\n                tooltipLabel={tooltipLabel}\n              />\n            );\n          })}\n      </div>\n    </MotionDiv>\n  );\n}\n\nfunction ChartTooltip({\n  content,\n  ...props\n}: React.ComponentProps<typeof RechartsPrimitive.Tooltip>) {\n  return (\n    <RechartsPrimitive.Tooltip\n      content={\n        (content ?? ChartTooltipContentRenderer) as React.ComponentProps<\n          typeof RechartsPrimitive.Tooltip\n        >[\"content\"]\n      }\n      {...props}\n    />\n  );\n}\n\nfunction ChartTooltipContentRenderer(\n  props: RechartsPrimitive.TooltipContentProps<\n    TooltipValueType,\n    TooltipNameType\n  >\n) {\n  return (\n    <ChartTooltipContent\n      {...(props as React.ComponentProps<typeof ChartTooltipContent>)}\n    />\n  );\n}\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    <MotionDiv\n      animate={{ opacity: 1, y: 0 }}\n      className={cn(\n        \"flex items-center justify-center gap-4\",\n        verticalAlign === \"top\" ? \"pb-3\" : \"pt-3\",\n        className\n      )}\n      initial={{ opacity: 0, y: 4 }}\n      transition={chartTooltipFade}\n    >\n      {payload\n        .filter((item) => item.type !== \"none\")\n        .map((item) => {\n          const seriesKey = getChartSeriesKey(item, nameKey);\n          const configKey = getChartConfigKey(config, item, seriesKey);\n          const itemConfig = getPayloadConfigFromPayload(\n            config,\n            item,\n            seriesKey\n          );\n          const label = getChartLegendLabel(item, itemConfig);\n          const swatchColor = getChartLegendSwatchColor(\n            configKey,\n            itemConfig,\n            item.color\n          );\n\n          return (\n            <div\n              className=\"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground\"\n              key={seriesKey}\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: swatchColor,\n                  }}\n                />\n              )}\n              {label}\n            </div>\n          );\n        })}\n    </MotionDiv>\n  );\n}\n\nfunction ChartLegend({\n  className,\n  content,\n  hideIcon,\n  nameKey,\n  ...props\n}: React.ComponentProps<typeof RechartsPrimitive.Legend> & {\n  className?: string;\n  hideIcon?: boolean;\n  nameKey?: string;\n}) {\n  const legendContent =\n    content ??\n    ((legendProps: RechartsPrimitive.DefaultLegendContentProps) => (\n      <ChartLegendContent\n        {...(legendProps as React.ComponentProps<typeof ChartLegendContent>)}\n        className={className}\n        hideIcon={hideIcon}\n        nameKey={nameKey}\n      />\n    ));\n\n  return (\n    <RechartsPrimitive.Legend\n      content={\n        legendContent as React.ComponentProps<\n          typeof RechartsPrimitive.Legend\n        >[\"content\"]\n      }\n      {...props}\n    />\n  );\n}\n\nfunction ChartEmptyState({\n  className,\n  description = \"Try adjusting filters or adding data to render this chart.\",\n  label = \"No data available\",\n}: {\n  className?: string;\n  description?: React.ReactNode;\n  label?: React.ReactNode;\n}) {\n  return (\n    <div\n      className={cn(\n        \"flex h-full min-h-[12rem] flex-col items-center justify-center gap-1 rounded-lg border border-border/70 border-dashed bg-muted/20 px-6 text-center\",\n        className\n      )}\n    >\n      <p className=\"font-medium text-foreground text-sm\">{label}</p>\n      {description ? (\n        <p className=\"max-w-xs text-muted-foreground text-xs\">{description}</p>\n      ) : null}\n    </div>\n  );\n}\n\nexport {\n  ChartArea,\n  ChartBar,\n  ChartContainer,\n  ChartEmptyState,\n  ChartLegend,\n  ChartLegendContent,\n  ChartLine,\n  ChartTooltip,\n  ChartTooltipContent,\n  useChart,\n};\n\nexport {\n  getChartAnimationTimeoutMs,\n  getChartLegendLabel,\n  getChartLegendSwatchColor,\n  getChartSeriesKey,\n  getPayloadConfigFromPayload,\n};\n",
      "type": "registry:ui"
    }
  ],
  "title": "Charts",
  "description": "Recharts shell with registry chart tokens, ease-out series growth, and calm tooltip and legend transitions."
}
