{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chart-kit",
  "title": "Chart Kit",
  "description": "Shared chart parts: colors, fills, legend, tooltip, loading and reveal used by ikas charts.",
  "dependencies": [
    "motion",
    "recharts"
  ],
  "registryDependencies": [
    "@ikas/motion",
    "@ikas/skeleton",
    "@ikas/theme",
    "@ikas/utils"
  ],
  "files": [
    {
      "path": "registry/ikas/chart-kit.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\nimport { usePlotArea } from \"recharts\"\n\nimport { useSkeletonVariant } from \"@/components/ui/skeleton\"\nimport { EASE_OUT } from \"@/lib/motion\"\nimport { cn } from \"@/lib/utils\"\n\n/**\n * Shared building blocks for the ikas charts (AreaChart, BarChart, DonutChart…).\n * Charts compose these instead of re-implementing fills, reveals and legends,\n * so every chart moves and reads the same way.\n */\n\n/** Categorical slots in fixed order. Never cycle: a 7th series folds into \"Diğer\". */\nconst CHART_COLORS = [\"var(--chart-1)\", \"var(--chart-2)\", \"var(--chart-3)\", \"var(--chart-4)\", \"var(--chart-5)\", \"var(--chart-6)\"] as const\n\ntype ChartSeries = {\n  /** Data key in each row. */\n  key: string\n  /** Legend and tooltip label. */\n  label: string\n  /** Override the slot color. Single-series charts default to --chart-ink. */\n  color?: string\n  /** Opt-in. dashed for targets, animated-dashed for live or estimated values. */\n  strokeStyle?: ChartStrokeStyle\n}\n\ntype ChartStrokeStyle = \"solid\" | \"dashed\" | \"animated-dashed\"\n\n/** strokeDasharray for a stroke style. */\nfunction strokeDash(style: ChartStrokeStyle | undefined) {\n  return style === \"dashed\" || style === \"animated-dashed\" ? \"5 4\" : undefined\n}\n\n/**\n * Keyframes for animated-dashed strokes, scoped to the chart. Rendered once per\n * chart that needs it; reduced motion keeps the dashes still.\n */\nfunction ChartMotionStyles() {\n  return (\n    <style>{`\n@keyframes ikas-chart-dash-flow { to { stroke-dashoffset: -18; } }\n.ikas-chart-dash-flow .recharts-area-curve, .ikas-chart-dash-flow.recharts-curve, path.ikas-chart-dash-flow { animation: ikas-chart-dash-flow 0.9s linear infinite; }\n@media (prefers-reduced-motion: reduce) { .ikas-chart-dash-flow .recharts-area-curve, .ikas-chart-dash-flow.recharts-curve, path.ikas-chart-dash-flow { animation: none; } }\n`}</style>\n  )\n}\n\n/**\n * Soft outer glow in the element's own color: a blurred copy at half strength\n * merged under the original. Opt-in only; one glowing element per screen.\n */\nfunction GlowFilter({ id, blur = 4, strength = 0.5 }: { id: string; blur?: number; strength?: number }) {\n  return (\n    <filter id={id} x=\"-20%\" y=\"-50%\" width=\"140%\" height=\"200%\">\n      <feGaussianBlur in=\"SourceGraphic\" stdDeviation={blur} result=\"blur\" />\n      <feComponentTransfer in=\"blur\" result=\"soft\">\n        <feFuncA type=\"linear\" slope={strength} />\n      </feComponentTransfer>\n      <feMerge>\n        <feMergeNode in=\"soft\" />\n        <feMergeNode in=\"SourceGraphic\" />\n      </feMerge>\n    </filter>\n  )\n}\n\ntype ChartBackgroundVariant = \"none\" | \"dots\" | \"grid\" | \"diagonal\"\n\n/** Subtle plot-area texture in the border color. Pair with <ChartBackground>. */\nfunction ChartBackgroundDefs({ id, variant }: { id: string; variant: ChartBackgroundVariant }) {\n  if (variant === \"dots\")\n    return (\n      <pattern id={id} width=\"10\" height=\"10\" patternUnits=\"userSpaceOnUse\">\n        <circle cx=\"1\" cy=\"1\" r=\"1\" fill=\"var(--border-strong)\" />\n      </pattern>\n    )\n  if (variant === \"grid\")\n    return (\n      <pattern id={id} width=\"16\" height=\"16\" patternUnits=\"userSpaceOnUse\">\n        <path d=\"M16 0H0V16\" fill=\"none\" stroke=\"var(--border)\" strokeWidth=\"1\" />\n      </pattern>\n    )\n  if (variant === \"diagonal\")\n    return (\n      <pattern id={id} width=\"8\" height=\"8\" patternUnits=\"userSpaceOnUse\" patternTransform=\"rotate(45)\">\n        <line x1=\"0\" y1=\"0\" x2=\"0\" y2=\"8\" stroke=\"var(--border)\" strokeWidth=\"1\" />\n      </pattern>\n    )\n  return null\n}\n\n/** Fills the plot area with a background pattern. Render it inside a recharts chart. */\nfunction ChartBackground({ id, variant }: { id: string; variant: ChartBackgroundVariant }) {\n  const plot = usePlotArea()\n  if (variant === \"none\" || !plot) return null\n  return <rect x={plot.x} y={plot.y} width={plot.width} height={plot.height} fill={`url(#${id})`} opacity={0.7} pointerEvents=\"none\" />\n}\n\n/** Resolves each series to a color: explicit, ink for a lone series, else its slot. */\nfunction resolveSeries<T extends ChartSeries>(series: T[]): (T & { color: string })[] {\n  return series.map((s, i) => ({ ...s, color: s.color ?? (series.length === 1 ? \"var(--chart-ink)\" : CHART_COLORS[i % CHART_COLORS.length]) }))\n}\n\ntype ChartFillVariant = \"gradient\" | \"solid\" | \"hatched\" | \"dotted\" | \"none\"\n\n/**\n * SVG <defs> for one series' fill. Reference it with `fill={chartFill(id, color, variant)}`.\n * Washes stay light (≈10–25%) so the data line, not the fill, carries the value.\n */\nfunction ChartFillDefs({ id, color, variant }: { id: string; color: string; variant: ChartFillVariant }) {\n  if (variant === \"gradient\")\n    return (\n      <linearGradient id={id} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n        <stop offset=\"0%\" stopColor={color} stopOpacity={0.28} />\n        <stop offset=\"95%\" stopColor={color} stopOpacity={0} />\n      </linearGradient>\n    )\n  if (variant === \"hatched\")\n    return (\n      <pattern id={id} width=\"6\" height=\"6\" patternUnits=\"userSpaceOnUse\" patternTransform=\"rotate(45)\">\n        <rect width=\"6\" height=\"6\" fill={color} fillOpacity={0.06} />\n        <line x1=\"0\" y1=\"0\" x2=\"0\" y2=\"6\" stroke={color} strokeOpacity={0.35} strokeWidth=\"1.5\" />\n      </pattern>\n    )\n  if (variant === \"dotted\")\n    return (\n      <pattern id={id} width=\"6\" height=\"6\" patternUnits=\"userSpaceOnUse\">\n        <circle cx=\"3\" cy=\"3\" r=\"1\" fill={color} fillOpacity={0.45} />\n      </pattern>\n    )\n  return null\n}\n\nfunction chartFill(id: string, color: string, variant: ChartFillVariant) {\n  if (variant === \"none\") return \"transparent\"\n  if (variant === \"solid\") return color\n  return `url(#${id})`\n}\n\ntype RevealDirection = \"left-to-right\" | \"right-to-left\" | \"center-out\"\n\n/**\n * A mask that wipes a series in once, on mount. Apply it with\n * `style={{ mask: `url(#${id})` }}` on the line, fill and dots together so they\n * reveal in lockstep. Reduced motion shows everything immediately.\n */\nfunction RevealMask({ id, direction = \"left-to-right\", duration = 0.9 }: { id: string; direction?: RevealDirection; duration?: number }) {\n  const reduce = useReducedMotion()\n  const originX = direction === \"left-to-right\" ? 0 : direction === \"right-to-left\" ? 1 : 0.5\n\n  return (\n    <mask id={id} maskUnits=\"userSpaceOnUse\" maskContentUnits=\"userSpaceOnUse\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\">\n      <motion.rect\n        x=\"0\"\n        y=\"0\"\n        width=\"100%\"\n        height=\"100%\"\n        fill=\"white\"\n        initial={reduce ? false : { scaleX: 0 }}\n        animate={{ scaleX: 1 }}\n        transition={{ duration, ease: EASE_OUT }}\n        style={{ originX }}\n      />\n    </mask>\n  )\n}\n\n/**\n * Holds a chart's placeholder while it loads. Pulses or shimmers like Skeleton,\n * following the nearest SkeletonProvider, so charts match the tables beside them.\n * Draw the placeholder in `bg-skeleton` / `var(--skeleton)`.\n */\nfunction ChartLoading({ className, children }: { className?: string; children?: React.ReactNode }) {\n  const variant = useSkeletonVariant()\n  return (\n    <div\n      role=\"status\"\n      aria-label=\"Grafik yükleniyor\"\n      data-slot=\"chart-loading\"\n      data-variant={variant}\n      className={cn(\n        \"relative overflow-hidden\",\n        variant === \"shimmer\" ? \"animate-skeleton-shimmer\" : \"animate-pulse motion-reduce:animate-none\",\n        className\n      )}\n    >\n      {children}\n    </div>\n  )\n}\n\n/**\n * Legend with selectable entries. Clicking an entry focuses that series (others\n * dim); clicking it again clears the focus. Text uses text tokens, the swatch\n * carries the color.\n */\nfunction ChartLegend({\n  series,\n  active,\n  onActiveChange,\n  className,\n}: {\n  series: { key: string; label: string; color: string }[]\n  /** Key of the focused series. Others dim. */\n  active?: string | null\n  onActiveChange?: (key: string | null) => void\n  className?: string\n}) {\n  const interactive = Boolean(onActiveChange)\n\n  return (\n    <div role={interactive ? \"group\" : \"list\"} aria-label=\"Seriler\" className={cn(\"flex flex-wrap items-center gap-x-4 gap-y-1.5\", className)}>\n      {series.map((s) => {\n        const dimmed = active != null && active !== s.key\n        const content = (\n          <>\n            <span aria-hidden className=\"size-2 rounded-[3px] transition-opacity duration-150\" style={{ background: s.color, opacity: dimmed ? 0.35 : 1 }} />\n            <span className={cn(\"transition-colors duration-150\", dimmed ? \"text-muted-foreground\" : \"text-foreground\")}>{s.label}</span>\n          </>\n        )\n        return interactive ? (\n          <button\n            key={s.key}\n            type=\"button\"\n            aria-pressed={active === s.key}\n            onClick={() => onActiveChange?.(active === s.key ? null : s.key)}\n            className=\"flex items-center gap-1.5 rounded-md text-[13px] outline-none focus-visible:ring-3 focus-visible:ring-ring/30\"\n          >\n            {content}\n          </button>\n        ) : (\n          <span key={s.key} role=\"listitem\" className=\"flex items-center gap-1.5 text-[13px]\">\n            {content}\n          </span>\n        )\n      })}\n    </div>\n  )\n}\n\ntype TooltipRow = { key: string; label: string; color: string; value: number | null | undefined }\n\n/** Tooltip surface shared by all charts. Values are right-aligned and tabular. */\nfunction ChartTooltipCard({\n  title,\n  rows,\n  format,\n  note,\n}: {\n  title?: React.ReactNode\n  rows: TooltipRow[]\n  /** Formats each row's value. */\n  format: (value: number) => string\n  /** Short qualifier next to the title, e.g. \"Tahmini\" or \"Devam ediyor\". */\n  note?: React.ReactNode\n}) {\n  return (\n    <div className=\"flex min-w-40 flex-col gap-1.5 rounded-lg bg-popover px-3 py-2 text-xs shadow-overlay\">\n      {(title != null || note != null) && (\n        <span className=\"flex items-center justify-between gap-3\">\n          {title != null && <span className=\"font-medium text-foreground\">{title}</span>}\n          {note != null && <span className=\"rounded-[4px] bg-muted px-1.5 py-px text-[11px] font-medium text-muted-foreground\">{note}</span>}\n        </span>\n      )}\n      {rows.map((row) => (\n        <div key={row.key} className=\"flex items-center gap-2\">\n          <span aria-hidden className=\"size-2 shrink-0 rounded-[3px]\" style={{ background: row.color }} />\n          <span className=\"flex-1 text-muted-foreground\">{row.label}</span>\n          <span className=\"font-medium text-foreground tabular-nums\">{row.value == null ? \"—\" : format(row.value)}</span>\n        </div>\n      ))}\n    </div>\n  )\n}\n\nconst defaultNumberFormat = (value: number) => new Intl.NumberFormat(\"tr-TR\").format(value)\nconst compactNumberFormat = (value: number) => new Intl.NumberFormat(\"tr-TR\", { notation: \"compact\", maximumFractionDigits: 1 }).format(value)\n\nexport {\n  CHART_COLORS,\n  ChartBackground,\n  ChartBackgroundDefs,\n  ChartMotionStyles,\n  GlowFilter,\n  strokeDash,\n  type ChartBackgroundVariant,\n  type ChartStrokeStyle,\n  ChartFillDefs,\n  ChartLegend,\n  ChartLoading,\n  ChartTooltipCard,\n  RevealMask,\n  chartFill,\n  compactNumberFormat,\n  defaultNumberFormat,\n  resolveSeries,\n  type ChartFillVariant,\n  type ChartSeries,\n  type RevealDirection,\n  type TooltipRow,\n}\n",
      "type": "registry:component",
      "target": "@components/ikas/chart-kit.tsx"
    }
  ],
  "docs": "https://builders.ikas.com/tr/docs/app-development/ui-kit/components/chart-kit",
  "categories": [
    "charts",
    "utilities"
  ],
  "type": "registry:component"
}