{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chart-2",
  "dependencies": [
    "recharts",
    "zod"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/components/watermelon-ui/chart-2.tsx",
      "content": "\"use client\";\n\nimport { useMemo, useCallback, memo } from \"react\";\nimport {\n  BarChart,\n  LineChart,\n  Bar,\n  Line,\n  XAxis,\n  YAxis,\n  CartesianGrid,\n} from \"recharts\";\n\nconst DEFAULT_COLORS = [\n  \"var(--chart-1)\",\n  \"var(--chart-2)\",\n  \"var(--chart-3)\",\n  \"var(--chart-4)\",\n  \"var(--chart-5)\",\n];\n\nexport const Chart = memo(function Chart({\n  id,\n  type,\n  title,\n  description,\n  data,\n  xKey,\n  series,\n  colors,\n  showLegend = false,\n  showGrid = true,\n  className,\n  onDataPointClick,\n}: ChartProps) {\n  const palette = colors?.length ? colors : DEFAULT_COLORS;\n\n  const seriesColors = useMemo(\n    () =>\n      series.map(\n        (seriesItem, index) =>\n          seriesItem.color ?? palette[index % palette.length]\n      ),\n    [series, palette]\n  );\n\n  const chartConfig: ChartConfig = useMemo(\n    () =>\n      Object.fromEntries(\n        series.map((seriesItem, index) => [\n          seriesItem.key,\n          {\n            label: seriesItem.label,\n            color: seriesColors[index],\n          },\n        ])\n      ),\n    [series, seriesColors]\n  );\n\n  const handleDataPointClick = useCallback(\n    (\n      seriesKey: string,\n      seriesLabel: string,\n      payload: Record<string, unknown>,\n      index: number\n    ) => {\n      onDataPointClick?.({\n        seriesKey,\n        seriesLabel,\n        xValue: payload[xKey],\n        yValue: payload[seriesKey],\n        index,\n        payload,\n      });\n    },\n    [onDataPointClick, xKey]\n  );\n\n  const ChartComponent = type === \"bar\" ? BarChart : LineChart;\n\n  const chartContent = (\n    <ChartContainer\n      config={chartConfig}\n      className=\"min-h-[200px] w-full\"\n      data-tool-ui-id={id}\n    >\n      <ChartComponent data={data} accessibilityLayer>\n        {showGrid && <CartesianGrid vertical={false} />}\n        <XAxis\n          dataKey={xKey}\n          tickLine={false}\n          tickMargin={10}\n          axisLine={false}\n        />\n        <YAxis tickLine={false} axisLine={false} tickMargin={10} />\n        <ChartTooltip content={<ChartTooltipContent />} />\n        {showLegend && <ChartLegend content={<ChartLegendContent />} />}\n\n        {type === \"bar\" &&\n          series.map((s, i) => (\n            <Bar\n              key={s.key}\n              dataKey={s.key}\n              fill={seriesColors[i]}\n              radius={4}\n              onClick={(data, index) =>\n                handleDataPointClick(s.key, s.label, data.payload, index)\n              }\n              cursor={onDataPointClick ? \"pointer\" : undefined}\n            />\n          ))}\n\n        {type === \"line\" &&\n          series.map((s, i) => (\n            <Line\n              key={s.key}\n              dataKey={s.key}\n              type=\"monotone\"\n              stroke={seriesColors[i]}\n              strokeWidth={2}\n              dot={{ r: 4, cursor: onDataPointClick ? \"pointer\" : undefined }}\n              activeDot={{\n                r: 6,\n                cursor: onDataPointClick ? \"pointer\" : undefined,\n                // Recharts 3 passes the active dot's props (payload, index) first.\n                onClick: (dotProps) => {\n                  const dot = dotProps as unknown as {\n                    payload: Record<string, unknown>;\n                    index: number;\n                  };\n                  handleDataPointClick(s.key, s.label, dot.payload, dot.index);\n                },\n              }}\n            />\n          ))}\n      </ChartComponent>\n    </ChartContainer>\n  );\n\n  return (\n    <Card\n      className={cn(\"w-full min-w-80\", className)}\n      data-tool-ui-id={id}\n      data-slot=\"chart\"\n    >\n      {(title || description) && (\n        <CardHeader>\n          {title && <CardTitle className=\"text-pretty\">{title}</CardTitle>}\n          {description && (\n            <CardDescription className=\"text-pretty\">\n              {description}\n            </CardDescription>\n          )}\n        </CardHeader>\n      )}\n      <CardContent>{chartContent}</CardContent>\n    </Card>\n  );\n});\n\n\n\nimport * as React from \"react\";\nimport * as RechartsPrimitive from \"recharts\";\n\n\n// Format: { THEME_NAME: CSS_SELECTOR }\nconst THEMES = { light: \"\", dark: \".dark\" } 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\nfunction ChartContainer({\n  id,\n  className,\n  children,\n  config,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  config: ChartConfig;\n  children: React.ComponentProps<\n    typeof RechartsPrimitive.ResponsiveContainer\n  >[\"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        data-slot=\"chart\"\n        data-chart={chartId}\n        className={cn(\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 flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden\",\n          className,\n        )}\n        {...props}\n      >\n        <ChartStyle id={chartId} config={config} />\n        <RechartsPrimitive.ResponsiveContainer>\n          {children}\n        </RechartsPrimitive.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 = 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<\"div\"> &\n  Partial<RechartsPrimitive.TooltipContentProps> & {\n    hideLabel?: boolean;\n    hideIndicator?: boolean;\n    indicator?: \"line\" | \"dot\" | \"dashed\";\n    nameKey?: string;\n    labelKey?: string;\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 as keyof typeof config]?.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    <div\n      className={cn(\n        \"border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl\",\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 = `${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                key={String(item.dataKey)}\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              >\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 && (\n                        <span className=\"text-foreground font-mono 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 = RechartsPrimitive.Legend;\n\nfunction ChartLegendContent({\n  className,\n  hideIcon = false,\n  payload,\n  verticalAlign = \"bottom\",\n  nameKey,\n}: React.ComponentProps<\"div\"> &\n  Pick<RechartsPrimitive.LegendProps, \"verticalAlign\"> & {\n    payload?: ReadonlyArray<RechartsPrimitive.LegendPayload>\n    hideIcon?: boolean;\n    nameKey?: string;\n  }) {\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) => {\n          const key = `${nameKey || item.dataKey || \"value\"}`;\n          const itemConfig = getPayloadConfigFromPayload(config, item, key);\n\n          return (\n            <div\n              key={item.value}\n              className={cn(\n                \"[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3\",\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(\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\n    ? config[configLabelKey]\n    : config[key as keyof typeof config];\n}\n\nexport {\n  ChartContainer,\n  ChartTooltip,\n  ChartTooltipContent,\n  ChartLegend,\n  ChartLegendContent,\n  ChartStyle,\n};\n\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card\"\n      className={cn(\n        \"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-header\"\n      className={cn(\n        \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-title\"\n      className={cn(\"leading-none font-semibold\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-description\"\n      className={cn(\"text-muted-foreground text-sm\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-action\"\n      className={cn(\n        \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-content\"\n      className={cn(\"px-6\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-footer\"\n      className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n      {...props}\n    />\n  );\n}\n\nexport {\n  Card,\n  CardHeader,\n  CardFooter,\n  CardTitle,\n  CardAction,\n  CardDescription,\n  CardContent,\n};\n\nexport const ChartSeriesSchema = z.object({\n  key: z.string().min(1),\n  label: z.string().min(1),\n  color: z.string().optional(),\n});\n\nexport type ChartSeries = z.infer<typeof ChartSeriesSchema>;\n\nimport type { ReactNode } from \"react\";\n\n/**\n * Tool UI conventions:\n * - Serializable schemas are JSON-safe (no callbacks/ReactNode/`className`).\n * - Schema: `SerializableXSchema`\n * - Parser: `parseSerializableX(input: unknown)`\n * - Actions: `responseActions`, `onResponseAction`, `onBeforeResponseAction`\n * - Root attrs: `data-tool-ui-id` + `data-slot`\n */\n\n/**\n * Schema for tool UI identity.\n *\n * Every tool UI should have a unique identifier that:\n * - Is stable across re-renders\n * - Is meaningful (not auto-generated)\n * - Is unique within the conversation\n *\n * Format recommendation: `{component-type}-{semantic-identifier}`\n * Examples: \"data-table-expenses-q3\", \"option-list-deploy-target\"\n */\nexport const ToolUIIdSchema = z.string().min(1);\n\nexport type ToolUIId = z.infer<typeof ToolUIIdSchema>;\n\n/**\n * Primary role of a Tool UI surface in a chat context.\n */\nexport const ToolUIRoleSchema = z.enum([\n  \"information\",\n  \"decision\",\n  \"control\",\n  \"state\",\n  \"composite\",\n]);\n\nexport type ToolUIRole = z.infer<typeof ToolUIRoleSchema>;\n\nexport const ToolUIReceiptOutcomeSchema = z.enum([\n  \"success\",\n  \"partial\",\n  \"failed\",\n  \"cancelled\",\n]);\n\nexport type ToolUIReceiptOutcome = z.infer<typeof ToolUIReceiptOutcomeSchema>;\n\n/**\n * Optional receipt metadata: a durable summary of an outcome.\n */\nexport const ToolUIReceiptSchema = z.object({\n  outcome: ToolUIReceiptOutcomeSchema,\n  summary: z.string().min(1),\n  identifiers: z.record(z.string(), z.string()).optional(),\n  at: z.string().datetime(),\n});\n\nexport type ToolUIReceipt = z.infer<typeof ToolUIReceiptSchema>;\n\n/**\n * Base schema for Tool UI payloads (id + optional role/receipt).\n */\nexport const ToolUISurfaceSchema = z.object({\n  id: ToolUIIdSchema,\n  role: ToolUIRoleSchema.optional(),\n  receipt: ToolUIReceiptSchema.optional(),\n});\n\nexport type ToolUISurface = z.infer<typeof ToolUISurfaceSchema>;\n\nexport const ActionSchema = z.object({\n  id: z.string().min(1),\n  label: z.string().min(1),\n  /**\n   * Canonical narration the assistant can use after this action is taken.\n   *\n   * Example: \"I exported the table as CSV.\" / \"I opened the link in a new tab.\"\n   */\n  sentence: z.string().optional(),\n  confirmLabel: z.string().optional(),\n  variant: z\n    .enum([\"default\", \"destructive\", \"secondary\", \"ghost\", \"outline\"])\n    .optional(),\n  icon: z.custom<ReactNode>().optional(),\n  loading: z.boolean().optional(),\n  disabled: z.boolean().optional(),\n  shortcut: z.string().optional(),\n});\n\nexport type Action = z.infer<typeof ActionSchema>;\n\nexport const ActionButtonsPropsSchema = z.object({\n  actions: z.array(ActionSchema).min(1),\n  align: z.enum([\"left\", \"center\", \"right\"]).optional(),\n  confirmTimeout: z.number().positive().optional(),\n  className: z.string().optional(),\n});\n\nexport const SerializableActionSchema = ActionSchema.omit({ icon: true });\nexport const SerializableActionsSchema = ActionButtonsPropsSchema.extend({\n  actions: z.array(SerializableActionSchema),\n}).omit({ className: true });\n\nexport interface ActionsConfig {\n  items: Action[];\n  align?: \"left\" | \"center\" | \"right\";\n  confirmTimeout?: number;\n}\n\nexport const SerializableActionsConfigSchema = z.object({\n  items: z.array(SerializableActionSchema).min(1),\n  align: z.enum([\"left\", \"center\", \"right\"]).optional(),\n  confirmTimeout: z.number().positive().optional(),\n});\n\nexport type SerializableActionsConfig = z.infer<\n  typeof SerializableActionsConfigSchema\n>;\n\nexport type SerializableAction = z.infer<typeof SerializableActionSchema>;\n\n\nimport { z } from \"zod\";\nimport { cn } from \"@/lib/utils\";\n\nfunction formatZodPath(path: Array<string | number | symbol>): string {\n  if (path.length === 0) return \"root\";\n  return path\n    .map((segment) =>\n      typeof segment === \"number\" ? `[${segment}]` : String(segment),\n    )\n    .join(\".\");\n}\n\n/**\n * Format Zod errors into a compact `path: message` string.\n */\nexport function formatZodError(error: z.ZodError): string {\n  const parts = error.issues.map((issue) => {\n    const path = formatZodPath(issue.path);\n    return `${path}: ${issue.message}`;\n  });\n\n  return Array.from(new Set(parts)).join(\"; \");\n}\n\n/**\n * Parse unknown input and throw a readable error.\n */\nexport function parseWithSchema<T>(\n  schema: z.ZodType<T>,\n  input: unknown,\n  name: string,\n): T {\n  const res = schema.safeParse(input);\n  if (!res.success) {\n    throw new Error(`Invalid ${name} payload: ${formatZodError(res.error)}`);\n  }\n  return res.data;\n}\n\n\nexport const ChartPropsSchema = z\n  .object({\n    id: ToolUIIdSchema,\n    role: ToolUIRoleSchema.optional(),\n    receipt: ToolUIReceiptSchema.optional(),\n    type: z.enum([\"bar\", \"line\"]),\n    title: z.string().optional(),\n    description: z.string().optional(),\n    data: z.array(z.record(z.string(), z.unknown())).min(1),\n    xKey: z.string().min(1),\n    series: z.array(ChartSeriesSchema).min(1),\n    /** Color palette applied to series in order. Individual series.color takes precedence. */\n    colors: z.array(z.string().min(1)).min(1).optional(),\n    showLegend: z.boolean().optional(),\n    showGrid: z.boolean().optional(),\n  })\n  .superRefine((value, ctx) => {\n    const seenSeriesKeys = new Set<string>();\n    value.series.forEach((series, index) => {\n      if (seenSeriesKeys.has(series.key)) {\n        ctx.addIssue({\n          code: \"custom\",\n          path: [\"series\", index, \"key\"],\n          message: `Duplicate series key \"${series.key}\".`,\n        });\n        return;\n      }\n      seenSeriesKeys.add(series.key);\n    });\n\n    value.data.forEach((row, rowIndex) => {\n      if (!(value.xKey in row)) {\n        ctx.addIssue({\n          code: \"custom\",\n          path: [\"data\", rowIndex, value.xKey],\n          message: `Missing xKey \"${value.xKey}\" in data row.`,\n        });\n      } else {\n        const xVal = row[value.xKey];\n        const isValidX = typeof xVal === \"string\" || typeof xVal === \"number\";\n        if (!isValidX) {\n          ctx.addIssue({\n            code: \"custom\",\n            path: [\"data\", rowIndex, value.xKey],\n            message: `Expected \"${value.xKey}\" to be a string or number.`,\n          });\n        }\n      }\n\n      value.series.forEach((series) => {\n        if (!(series.key in row)) {\n          ctx.addIssue({\n            code: \"custom\",\n            path: [\"data\", rowIndex, series.key],\n            message: `Missing series key \"${series.key}\" in data row.`,\n          });\n          return;\n        }\n\n        const yVal = row[series.key];\n        if (yVal === null) {\n          return;\n        }\n        if (typeof yVal !== \"number\" || !Number.isFinite(yVal)) {\n          ctx.addIssue({\n            code: \"custom\",\n            path: [\"data\", rowIndex, series.key],\n            message: `Expected \"${series.key}\" to be a finite number (or null).`,\n          });\n        }\n      });\n    });\n  });\n\nexport type ChartDataPoint = {\n  seriesKey: string;\n  seriesLabel: string;\n  xValue: unknown;\n  yValue: unknown;\n  index: number;\n  payload: Record<string, unknown>;\n};\n\nexport type ChartClientProps = {\n  className?: string;\n  onDataPointClick?: (point: ChartDataPoint) => void;\n};\n\nexport type ChartProps = z.infer<typeof ChartPropsSchema> & ChartClientProps;\n\nexport const SerializableChartSchema = ChartPropsSchema;\n\nexport type SerializableChart = z.infer<typeof SerializableChartSchema>;\n\nexport function parseSerializableChart(input: unknown): SerializableChart {\n  return parseWithSchema(SerializableChartSchema, input, \"Chart\");\n}\n\n",
      "type": "registry:ui",
      "target": "components/ui/chart-2.tsx"
    }
  ],
  "type": "registry:ui"
}
