{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sparkline-grid",
  "type": "registry:component",
  "title": "Sparkline Grid",
  "description": "KPI grid of labeled value tiles each paired with a compact sparkline trend.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/sparkline-grid/sparkline-grid.tsx",
      "content": "import * as React from \"react\";\n\nimport { ArrowDownRight, ArrowUpRight } from \"lucide-react\";\n\nimport { cn } from \"@vllnt/ui\";\n\nexport type SparklineGridItem = {\n  change: number;\n  data: number[];\n  label: string;\n  value: string;\n};\n\nexport type SparklineGridProps = {\n  columns?: 2 | 3 | 4;\n  items: SparklineGridItem[];\n} & React.HTMLAttributes<HTMLDivElement>;\n\nfunction buildSparklinePath(data: number[], width: number, height: number) {\n  const min = Math.min(...data);\n  const max = Math.max(...data);\n  const range = max - min || 1;\n\n  return data\n    .map((value, index) => {\n      const x =\n        data.length === 1 ? width / 2 : (index / (data.length - 1)) * width;\n      const y = height - ((value - min) / range) * height;\n      return `${index === 0 ? \"M\" : \"L\"}${x},${y}`;\n    })\n    .join(\" \");\n}\n\nconst gridColumns = {\n  2: \"md:grid-cols-2\",\n  3: \"md:grid-cols-2 xl:grid-cols-3\",\n  4: \"md:grid-cols-2 xl:grid-cols-4\",\n};\n\nexport const SparklineGrid = React.forwardRef<\n  HTMLDivElement,\n  SparklineGridProps\n>(({ className, columns = 2, items, ...props }, reference) => {\n  if (items.length === 0) {\n    return null;\n  }\n\n  return (\n    <div\n      className={cn(\"grid grid-cols-1 gap-4\", gridColumns[columns], className)}\n      ref={reference}\n      {...props}\n    >\n      {items.map((item) => {\n        const isPositive = item.change >= 0;\n        const TrendIcon = isPositive ? ArrowUpRight : ArrowDownRight;\n        const stroke = isPositive ? \"hsl(142 71% 45%)\" : \"hsl(348 83% 47%)\";\n\n        return (\n          <section\n            className=\"rounded-2xl border border-border bg-card/80 p-4 shadow-sm\"\n            key={item.label}\n          >\n            <div className=\"mb-4 flex items-start justify-between gap-3\">\n              <div>\n                <p className=\"text-sm font-medium text-muted-foreground\">\n                  {item.label}\n                </p>\n                <p className=\"mt-1 text-2xl font-semibold tracking-tight text-foreground\">\n                  {item.value}\n                </p>\n              </div>\n              <div\n                className={cn(\n                  \"inline-flex items-center gap-1 rounded-full border px-2.5 py-1 text-xs font-medium tabular-nums\",\n                  isPositive\n                    ? \"border-emerald-500/30 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400\"\n                    : \"border-rose-500/30 bg-rose-500/10 text-rose-600 dark:text-rose-400\",\n                )}\n              >\n                <TrendIcon className=\"size-3.5\" />\n                {item.change > 0 ? \"+\" : \"\"}\n                {item.change.toFixed(2)}%\n              </div>\n            </div>\n            <div className=\"rounded-xl border border-border/60 bg-muted/20 p-3\">\n              <svg\n                aria-label={`${item.label} sparkline`}\n                className=\"h-16 w-full\"\n                role=\"img\"\n                viewBox=\"0 0 120 48\"\n              >\n                <path\n                  d={buildSparklinePath(item.data, 120, 48)}\n                  fill=\"none\"\n                  stroke={stroke}\n                  strokeLinecap=\"round\"\n                  strokeLinejoin=\"round\"\n                  strokeWidth=\"2.5\"\n                  vectorEffect=\"non-scaling-stroke\"\n                />\n              </svg>\n            </div>\n          </section>\n        );\n      })}\n    </div>\n  );\n});\n\nSparklineGrid.displayName = \"SparklineGrid\";\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
