{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sparkline",
  "title": "Sparkline",
  "description": "Tiny inline trend charts for tables and stat cards - line, area, and bar variants",
  "dependencies": [
    "recharts"
  ],
  "registryDependencies": [
    "@boldkit/utils"
  ],
  "files": [
    {
      "path": "registry/default/ui/sparkline.tsx",
      "content": "import * as React from 'react'\nimport { cn } from '@/lib/utils'\nimport {\n  Area,\n  AreaChart,\n  Bar,\n  BarChart,\n  Line,\n  LineChart,\n  ResponsiveContainer,\n} from 'recharts'\n\nexport interface SparklineProps extends React.HTMLAttributes<HTMLDivElement> {\n  data: number[]\n  type?: 'line' | 'area' | 'bar'\n  color?: string\n  height?: number\n  width?: number | string\n  showEndDot?: boolean\n  strokeWidth?: number\n  trend?: 'up' | 'down' | 'neutral'\n  animated?: boolean\n  /** Accessible name. A sparkline conveys a trend, which is invisible to AT\n   *  without one; defaults to a summary of the series. */\n  ariaLabel?: string\n}\n\nconst Sparkline = React.forwardRef<HTMLDivElement, SparklineProps>(\n  (\n    {\n      data,\n      type = 'line',\n      color,\n      height = 32,\n      width = '100%',\n      showEndDot = false,\n      strokeWidth = 2,\n      trend,\n      animated = true,\n      ariaLabel,\n      className,\n      ...props\n    },\n    ref\n  ) => {\n    // `aria-label` on a plain <div> is ignored by most AT — it needs a role.\n    // Default the name to something useful rather than leaving the trend\n    // entirely invisible.\n    const accessibleLabel =\n      ariaLabel ??\n      (data && data.length\n        ? `Sparkline, ${data.length} points, from ${data[0]} to ${data[data.length - 1]}`\n        : 'Sparkline, no data')\n    // Unique ID per instance prevents gradient collision when multiple sparklines render on the same page\n    const uid = React.useId().replace(/:/g, '')\n\n    // Determine color based on trend or explicit color.\n    // Must run before the empty-data early return — hooks cannot be called\n    // conditionally, otherwise an empty→populated data transition crashes with\n    // \"Rendered more hooks than during the previous render\".\n    const resolvedColor = React.useMemo(() => {\n      if (color) return color\n      if (trend === 'up') return 'hsl(var(--success))'\n      if (trend === 'down') return 'hsl(var(--destructive))'\n      return 'hsl(var(--primary))'\n    }, [color, trend])\n\n    if (!data || data.length === 0) {\n      return (\n        <div\n          ref={ref}\n          role=\"img\"\n          aria-label={ariaLabel ?? 'Sparkline, no data'}\n          className={cn('inline-block border-b-2 border-dashed border-foreground/30', className)}\n          style={{ width, height }}\n          {...props}\n        />\n      )\n    }\n\n    // Convert data array to format recharts expects\n    const chartData = data.map((value, index) => ({ value, index }))\n\n    const strokeColor = 'hsl(var(--foreground))'\n    const lastIndex = data.length - 1\n\n    /**\n     * Custom dot renderer that only draws a circle on the final data point.\n     * Used directly on the primary series — no duplicate series needed.\n     */\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const endDotRenderer = (dotProps: any) => {\n      const { cx, cy, index } = dotProps\n      if (!showEndDot || index !== lastIndex) return null\n      return (\n        <circle\n          key=\"end-dot\"\n          cx={cx}\n          cy={cy}\n          r={4}\n          fill={resolvedColor}\n          stroke={strokeColor}\n          strokeWidth={2}\n        />\n      )\n    }\n\n    if (type === 'bar') {\n      return (\n        <div\n          ref={ref}\n          role=\"img\"\n          aria-label={accessibleLabel}\n          className={cn('inline-block', className)}\n          style={{ width, height }}\n          {...props}\n        >\n          <ResponsiveContainer width=\"100%\" height=\"100%\">\n            <BarChart data={chartData} margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>\n              <Bar\n                dataKey=\"value\"\n                fill={resolvedColor}\n                stroke={strokeColor}\n                strokeWidth={1}\n                isAnimationActive={animated}\n                animationDuration={300}\n              />\n            </BarChart>\n          </ResponsiveContainer>\n        </div>\n      )\n    }\n\n    if (type === 'area') {\n      return (\n        <div\n          ref={ref}\n          role=\"img\"\n          aria-label={accessibleLabel}\n          className={cn('inline-block', className)}\n          style={{ width, height }}\n          {...props}\n        >\n          <ResponsiveContainer width=\"100%\" height=\"100%\">\n            <AreaChart data={chartData} margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>\n              <defs>\n                <linearGradient id={`sparkline-gradient-${uid}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n                  <stop offset=\"0%\" stopColor={resolvedColor} stopOpacity={0.6} />\n                  <stop offset=\"100%\" stopColor={resolvedColor} stopOpacity={0.1} />\n                </linearGradient>\n              </defs>\n              <Area\n                type=\"monotone\"\n                dataKey=\"value\"\n                stroke={resolvedColor}\n                strokeWidth={strokeWidth}\n                fill={`url(#sparkline-gradient-${uid})`}\n                isAnimationActive={animated}\n                animationDuration={300}\n                dot={endDotRenderer}\n                activeDot={false}\n              />\n            </AreaChart>\n          </ResponsiveContainer>\n        </div>\n      )\n    }\n\n    // Default: line\n    return (\n      <div\n        ref={ref}\n        role=\"img\"\n        aria-label={accessibleLabel}\n        className={cn('inline-block', className)}\n        style={{ width, height }}\n        {...props}\n      >\n        <ResponsiveContainer width=\"100%\" height=\"100%\">\n          <LineChart data={chartData} margin={{ top: 2, right: 2, bottom: 2, left: 2 }}>\n            <Line\n              type=\"monotone\"\n              dataKey=\"value\"\n              stroke={resolvedColor}\n              strokeWidth={strokeWidth}\n              dot={endDotRenderer}\n              activeDot={false}\n              isAnimationActive={animated}\n              animationDuration={300}\n            />\n          </LineChart>\n        </ResponsiveContainer>\n      </div>\n    )\n  }\n)\nSparkline.displayName = 'Sparkline'\n\nexport { Sparkline }\n",
      "type": "registry:ui",
      "target": "components/ui/sparkline.tsx"
    }
  ],
  "type": "registry:ui"
}