{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "area-chart",
  "title": "Area Chart",
  "description": "Area or line chart over time, with stacking, legend, tooltip and estimated points.",
  "dependencies": [
    "motion",
    "recharts"
  ],
  "registryDependencies": [
    "@ikas/chart",
    "@ikas/chart-kit",
    "@ikas/theme",
    "@ikas/utils"
  ],
  "files": [
    {
      "path": "registry/ikas/area-chart.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { useReducedMotion } from \"motion/react\"\nimport { Area, AreaChart as RechartsAreaChart, CartesianGrid, Tooltip, XAxis, YAxis } from \"recharts\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ChartContainer, type ChartConfig } from \"@/components/ui/chart\"\nimport {\n  ChartBackground,\n  ChartBackgroundDefs,\n  ChartFillDefs,\n  ChartMotionStyles,\n  GlowFilter,\n  strokeDash,\n  type ChartBackgroundVariant,\n  ChartLegend,\n  ChartLoading,\n  ChartTooltipCard,\n  RevealMask,\n  chartFill,\n  compactNumberFormat,\n  defaultNumberFormat,\n  resolveSeries,\n  type ChartSeries,\n  type RevealDirection,\n} from \"@/components/ikas/chart-kit\"\n\ntype AreaChartVariant = \"gradient\" | \"solid\" | \"hatched\" | \"dotted\" | \"line\"\n\ntype AreaChartProps<T extends Record<string, unknown>> = {\n  /** Rows, in x order. */\n  data: T[]\n  /** Key of the x value in each row (date, month…). */\n  index: keyof T & string\n  /** One entry per area. Colors follow the categorical order; a lone series is ink. */\n  series: ChartSeries[]\n  /** Fill style. `line` draws the stroke only. */\n  variant?: AreaChartVariant\n  /** Line interpolation between points. */\n  curve?: \"monotone\" | \"linear\" | \"step\" | \"bump\"\n  /** Stack series on top of each other (parts of a whole over time). */\n  stacked?: boolean\n  /** Intro wipe. Plays once on mount; skipped with reduced motion. */\n  reveal?: RevealDirection | \"none\"\n  /** Shows a placeholder instead of the data. It pulses or shimmers like Skeleton (see SkeletonProvider). */\n  loading?: boolean\n  /** Formats values in the tooltip. Defaults to tr-TR numbers. */\n  valueFormat?: (value: number) => string\n  /** Formats y-axis ticks. Defaults to compact tr-TR (12,4 B). */\n  yFormat?: (value: number) => string\n  /** Formats x-axis ticks and the tooltip title. */\n  xFormat?: (value: string) => string\n  /** Plot height in px. */\n  height?: number\n  /** Legend is shown automatically for 2+ series. */\n  showLegend?: boolean\n  /** Accessible summary of what the chart shows. */\n  \"aria-label\"?: string\n  className?: string\n  /** Expressive, opt-in: soft glow under the lines. */\n  glow?: boolean\n  /** Expressive, opt-in: subtle texture behind the plot. */\n  background?: ChartBackgroundVariant\n  /** Draw the last N points as an estimate: dashed line, lighter wash, \"Tahmini\" in the tooltip. */\n  projectedLast?: number\n  /** Animate data changes (live data). Off by default; the reveal handles the first paint. */\n  animateUpdates?: boolean\n}\n\nconst PROJECTED = \"__projected\"\n\n/** Active point: filled dot with a surface ring, plus a soft pulse around it. */\nfunction ActiveDot({ cx, cy, color }: { cx?: number; cy?: number; color: string }) {\n  if (cx == null || cy == null) return null\n  return (\n    <g>\n      <circle\n        cx={cx}\n        cy={cy}\n        r={5}\n        fill={color}\n        fillOpacity={0.3}\n        className=\"origin-center animate-ping [animation-duration:1.6s] [transform-box:fill-box] motion-reduce:animate-none\"\n      />\n      <circle cx={cx} cy={cy} r={4.5} fill={color} stroke=\"var(--card)\" strokeWidth={2} />\n    </g>\n  )\n}\n\n/** Muted wave drawn while loading. Static shape; ChartLoading does the moving. */\nfunction LoadingWave({ height }: { height: number }) {\n  const points = Array.from({ length: 25 }, (_, i) => {\n    const x = (i / 24) * 400\n    const y = 58 - Math.sin(i / 3.2) * 16 - Math.sin(i / 1.7) * 6 - i * 0.9\n    return `${x.toFixed(1)},${y.toFixed(1)}`\n  })\n  const line = `M${points.join(\" L\")}`\n\n  return (\n    <svg viewBox=\"0 0 400 100\" preserveAspectRatio=\"none\" className=\"w-full\" style={{ height }} aria-hidden>\n      {[20, 45, 70, 95].map((y) => (\n        <line key={y} x1=\"0\" x2=\"400\" y1={y} y2={y} stroke=\"var(--border)\" strokeWidth=\"1\" vectorEffect=\"non-scaling-stroke\" />\n      ))}\n      <path d={`${line} L400,100 L0,100 Z`} fill=\"var(--skeleton)\" />\n      <path d={line} fill=\"none\" stroke=\"var(--border-strong)\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" vectorEffect=\"non-scaling-stroke\" />\n    </svg>\n  )\n}\n\n/**\n * Change over time for one to six series. Thin 2px lines over a light wash,\n * horizontal hairline grid, one y-axis, crosshair tooltip. Series reveal from\n * left to right on mount and can be focused from the legend.\n */\nfunction AreaChart<T extends Record<string, unknown>>({\n  data,\n  index,\n  series,\n  variant = \"gradient\",\n  curve = \"monotone\",\n  stacked = false,\n  reveal = \"left-to-right\",\n  loading = false,\n  valueFormat = defaultNumberFormat,\n  yFormat = compactNumberFormat,\n  xFormat,\n  height = 240,\n  showLegend,\n  \"aria-label\": ariaLabel,\n  className,\n  glow = false,\n  background = \"none\",\n  projectedLast = 0,\n  animateUpdates = false,\n}: AreaChartProps<T>) {\n  const id = React.useId().replace(/:/g, \"\")\n  const reduceMotion = useReducedMotion()\n  const resolved = resolveSeries(series)\n  const [active, setActive] = React.useState<string | null>(null)\n  const legend = showLegend ?? resolved.length > 1\n  const maskId = reveal === \"none\" || reduceMotion ? undefined : `${id}-reveal`\n  const config = Object.fromEntries(resolved.map((s) => [s.key, { label: s.label, color: s.color }])) satisfies ChartConfig\n  const animate = animateUpdates && !reduceMotion\n  const flows = resolved.some((s) => s.strokeStyle === \"animated-dashed\")\n\n  // Projection: the split point belongs to both halves so the dashed tail joins the solid line.\n  const split = projectedLast > 0 ? Math.max(0, data.length - 1 - projectedLast) : -1\n  const rows: Record<string, unknown>[] =\n    split < 0\n      ? data\n      : data.map((row, i) => {\n          const next: Record<string, unknown> = { ...row }\n          for (const s of resolved) {\n            next[`${s.key}${PROJECTED}`] = i >= split ? row[s.key] : null\n            if (i > split) next[s.key] = null\n          }\n          return next\n        })\n\n  return (\n    <div data-slot=\"area-chart\" className={cn(\"flex w-full flex-col gap-3\", className)}>\n      {flows && <ChartMotionStyles />}\n      {legend && <ChartLegend series={resolved} active={active} onActiveChange={setActive} />}\n      {loading ? (\n        <ChartLoading className=\"rounded-md\">\n          <LoadingWave height={height} />\n        </ChartLoading>\n      ) : (\n        <ChartContainer config={config} className=\"aspect-auto w-full\" style={{ height }} role=\"img\" aria-label={ariaLabel}>\n          <RechartsAreaChart data={rows} margin={{ top: 8, right: 8, bottom: 0, left: 0 }}>\n            <defs>\n              {glow && <GlowFilter id={`${id}-glow`} />}\n              {background !== \"none\" && <ChartBackgroundDefs id={`${id}-bg`} variant={background} />}\n              {maskId && <RevealMask id={maskId} direction={reveal === \"none\" ? undefined : reveal} />}\n              {resolved.map((s) => (\n                <ChartFillDefs key={s.key} id={`${id}-fill-${s.key}`} color={s.color} variant={variant === \"line\" ? \"none\" : variant} />\n              ))}\n            </defs>\n            {background !== \"none\" && <ChartBackground id={`${id}-bg`} variant={background} />}\n            <CartesianGrid vertical={false} stroke=\"var(--border)\" strokeDasharray=\"0\" />\n            <XAxis\n              dataKey={index as string}\n              tickLine={false}\n              axisLine={false}\n              tickMargin={10}\n              minTickGap={24}\n              tick={{ fontSize: 12 }}\n              tickFormatter={xFormat ? (value) => xFormat(String(value)) : undefined}\n            />\n            <YAxis\n              width={56}\n              tickLine={false}\n              axisLine={false}\n              tickMargin={6}\n              tickCount={4}\n              tick={{ fontSize: 12 }}\n              tickFormatter={(value) => yFormat(Number(value))}\n            />\n            <Tooltip\n              cursor={{ stroke: \"var(--border-strong)\", strokeWidth: 1 }}\n              isAnimationActive={false}\n              content={({ active: open, payload, label }) => {\n                if (!open || !payload?.length) return null\n                const row = payload[0]?.payload as Record<string, unknown> | undefined\n                const at = rows.indexOf(row as Record<string, unknown>)\n                const estimated = split >= 0 && at > split\n                return (\n                  <ChartTooltipCard\n                    title={xFormat ? xFormat(String(label)) : String(label)}\n                    note={estimated ? \"Tahmini\" : undefined}\n                    format={valueFormat}\n                    rows={resolved.map((s) => ({\n                      key: s.key,\n                      label: s.label,\n                      color: s.color,\n                      value: (row?.[s.key] ?? row?.[`${s.key}${PROJECTED}`]) as number | null | undefined,\n                    }))}\n                  />\n                )\n              }}\n            />\n            {resolved.map((s) => {\n              const dimmed = active != null && active !== s.key\n              const fillVariant = variant === \"line\" ? \"none\" : variant === \"solid\" ? \"solid\" : variant\n              const fillOpacity = variant === \"solid\" ? (dimmed ? 0.04 : 0.14) : variant === \"gradient\" ? (dimmed ? 0.15 : 0.65) : dimmed ? 0.25 : 1\n              const masked = maskId ? { mask: `url(#${maskId})` } : {}\n              const transition = { transition: \"stroke-opacity 150ms var(--ease-out), fill-opacity 150ms var(--ease-out)\" }\n              return (\n                <React.Fragment key={s.key}>\n                  {glow && !dimmed && (\n                    <Area\n                      type={curve}\n                      dataKey={s.key}\n                      stackId={stacked ? \"glow\" : undefined}\n                      stroke={s.color}\n                      strokeWidth={2}\n                      fill=\"none\"\n                      dot={false}\n                      activeDot={false}\n                      tooltipType=\"none\"\n                      legendType=\"none\"\n                      isAnimationActive={false}\n                      filter={`url(#${id}-glow)`}\n                      style={{ ...masked, pointerEvents: \"none\" }}\n                    />\n                  )}\n                  <Area\n                    type={curve}\n                    dataKey={s.key}\n                    name={s.label}\n                    stackId={stacked ? \"stack\" : undefined}\n                    stroke={s.color}\n                    strokeWidth={2}\n                    strokeLinecap=\"round\"\n                    strokeLinejoin=\"round\"\n                    strokeDasharray={strokeDash(s.strokeStyle)}\n                    className={s.strokeStyle === \"animated-dashed\" ? \"ikas-chart-dash-flow\" : undefined}\n                    strokeOpacity={dimmed ? 0.25 : 1}\n                    fill={chartFill(`${id}-fill-${s.key}`, s.color, fillVariant)}\n                    fillOpacity={fillOpacity}\n                    dot={false}\n                    activeDot={dimmed ? false : (props: { cx?: number; cy?: number }) => <ActiveDot cx={props.cx} cy={props.cy} color={s.color} />}\n                    isAnimationActive={animate}\n                    animationDuration={600}\n                    animationEasing=\"ease-out\"\n                    style={{ ...transition, ...masked }}\n                  />\n                  {split >= 0 && (\n                    <Area\n                      type={curve}\n                      dataKey={`${s.key}${PROJECTED}`}\n                      name={`${s.label} (tahmini)`}\n                      stackId={stacked ? \"projected\" : undefined}\n                      stroke={s.color}\n                      strokeWidth={2}\n                      strokeLinecap=\"round\"\n                      strokeDasharray=\"4 4\"\n                      strokeOpacity={dimmed ? 0.2 : 0.75}\n                      fill={chartFill(`${id}-fill-${s.key}`, s.color, fillVariant)}\n                      fillOpacity={fillOpacity * 0.45}\n                      dot={false}\n                      activeDot={dimmed ? false : (props: { cx?: number; cy?: number }) => <ActiveDot cx={props.cx} cy={props.cy} color={s.color} />}\n                      tooltipType=\"none\"\n                      legendType=\"none\"\n                      isAnimationActive={false}\n                      style={{ ...transition, ...masked }}\n                    />\n                  )}\n                </React.Fragment>\n              )\n            })}\n          </RechartsAreaChart>\n        </ChartContainer>\n      )}\n    </div>\n  )\n}\n\nexport { AreaChart, type AreaChartProps, type AreaChartVariant }\n",
      "type": "registry:component",
      "target": "@components/ikas/area-chart.tsx"
    }
  ],
  "docs": "https://builders.ikas.com/tr/docs/app-development/ui-kit/components/area-chart",
  "categories": [
    "charts"
  ],
  "type": "registry:component"
}