{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"sparkline","type":"registry:ui","title":"Sparkline","description":"A tiny trend line with no axes, for use inside text and tables.","dependencies":["clsx","tailwind-merge"],"registryDependencies":["https://caliperui.site/r/styles.json"],"files":[{"path":"ui/lib/cn.ts","type":"registry:ui","target":"components/ui/lib/cn.ts","content":"import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({\n  extend: { theme: { radius: [\"control\", \"surface\", \"overlay\"], shadow: [\"overlay\"] } },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n"},{"path":"ui/sparkline.tsx","type":"registry:ui","target":"components/ui/sparkline.tsx","content":"import type { ComponentProps } from \"react\";\nimport { cn } from \"./lib/cn\";\nimport \"./sparkline.css\";\n\nexport type SparklineProps = Omit<ComponentProps<\"svg\">, \"values\"> & {\n  values: readonly number[];\n  label: string;\n};\n\nexport function Sparkline({\n  values,\n  label,\n  className,\n  ...props\n}: SparklineProps) {\n  const width = 100;\n  const height = 36;\n  const min = Math.min(...values);\n  const max = Math.max(...values);\n  const span = max - min || 1;\n  const points = values.map((value, index) => {\n    const x =\n      values.length === 1 ? width / 2 : (index / (values.length - 1)) * width;\n    const y = height - ((value - min) / span) * (height - 4) - 2;\n    return [x, y] as const;\n  });\n  const line = points\n    .map(([x, y], index) => `${index === 0 ? \"M\" : \"L\"}${x},${y}`)\n    .join(\" \");\n  const fill = `${line} L${width},${height} L0,${height} Z`;\n\n  return (\n    <svg\n      data-slot=\"sparkline\"\n      viewBox={`0 0 ${width} ${height}`}\n      preserveAspectRatio=\"none\"\n      role=\"img\"\n      aria-label={label}\n      className={cn(\"h-9 w-full text-foreground\", className)}\n      {...props}\n    >\n      <path d={fill} fill=\"currentColor\" opacity=\"0.08\" />\n      <path\n        key={values.join(\",\")}\n        data-slot=\"sparkline-line\"\n        d={line}\n        fill=\"none\"\n        stroke=\"currentColor\"\n        strokeWidth=\"1.5\"\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n        vectorEffect=\"non-scaling-stroke\"\n        pathLength={100}\n      />\n    </svg>\n  );\n}\n"},{"path":"ui/sparkline.css","type":"registry:file","target":"components/ui/sparkline.css","content":"/* sparkline.tsx's styles; it imports this file. Edit freely. */\n@layer theme, base, components, utilities;\n\n@layer components {\n  /* Drawn left to right by a clip, not a dash: with a non-scaling stroke Chrome ignores pathLength, so a dash pattern\n     would leave a wide sparkline broken into segments. */\n  [data-slot=\"sparkline-line\"] {\n    animation: caliper-sparkline var(--duration-deliberate) var(--ease-out) both;\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    [data-slot=\"sparkline-line\"] {\n      animation: none;\n      stroke-dashoffset: 0;\n    }\n  }\n}\n\n@keyframes caliper-sparkline {\n  from {\n    clip-path: inset(-10% 100% -10% 0);\n  }\n  to {\n    clip-path: inset(-10% 0 -10% 0);\n  }\n}\n"}],"categories":["data"],"meta":{"tier":"free","license":"MIT","family":"blocks","docs":"/docs/components/sparkline"}}