{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bar-list",
  "type": "registry:ui",
  "title": "Bar List",
  "description": "Horizontal 'top N' ranking list with proportional bar fills. Dashboard staple.",
  "dependencies": [
    "@saasflare/ui",
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/bar-list.tsx",
      "type": "registry:ui",
      "content": "// @draft\n\"use client\"\n\n/**\n * @fileoverview Saasflare BarList — horizontal \"top N\" rankings.\n * @author Saasflare™\n *\n * Each row renders a horizontal bar whose fill width is proportional to the\n * largest value in the list. Useful for \"top countries\", \"top pages\",\n * \"top errors\" style dashboard widgets — a pattern shadcn doesn't ship but\n * Tremor popularized.\n *\n * @module packages/ui/components/ui/bar-list\n * @package ui\n * @layer core\n *\n * @example\n * <BarList\n *   data={[\n *     { name: \"Germany\", value: 4321 },\n *     { name: \"United States\", value: 3210 },\n *     { name: \"Brazil\", value: 2987 },\n *   ]}\n *   valueFormatter={(n) => n.toLocaleString()}\n * />\n */\n\nimport { type ReactNode } from \"react\"\nimport { m } from \"motion/react\"\nimport { cn } from \"@saasflare/ui\"\nimport { useSaasflareProps, type SaasflareComponentProps } from \"@saasflare/ui\"\nimport { useSaasflareMotion, springGentle } from \"@saasflare/ui\"\n\n/** A single row in the list. */\nexport interface BarListItem {\n    /** Row label. */\n    name: string\n    /** Numeric value driving the bar width. */\n    value: number\n    /** Optional icon shown left of the label. */\n    icon?: ReactNode\n    /** Optional click target for the row label (wraps in `<a>`). */\n    href?: string\n    /** Optional per-row color override (any CSS color). */\n    color?: string\n}\n\n/** Props for the BarList component. */\nexport interface BarListProps extends SaasflareComponentProps {\n    /** Rows to render. */\n    data: BarListItem[]\n    /** Formats the numeric value on the right edge. Default: `(n) => n.toLocaleString()`. */\n    valueFormatter?: (value: number) => string\n    /** Sort rows by value descending. Default: `true`. */\n    sortDescending?: boolean\n    /** Maximum rows rendered (truncates after sort). */\n    limit?: number\n    /** Additional class names. */\n    className?: string\n}\n\n/**\n * Horizontal bar list — common dashboard \"top N\" rankings pattern.\n *\n * @component\n * @layer core\n */\nexport function BarList({\n    data,\n    valueFormatter = (n) => n.toLocaleString(),\n    sortDescending = true,\n    limit,\n    className,\n    surface,\n    radius,\n    animated,\n    iconWeight,\n}: BarListProps) {\n    const sf = useSaasflareProps({ surface, radius, animated, iconWeight })\n    const motion = useSaasflareMotion(sf.animated, springGentle)\n\n    const sorted = sortDescending ? [...data].sort((a, b) => b.value - a.value) : data\n    const visible = typeof limit === \"number\" ? sorted.slice(0, limit) : sorted\n    const peak = visible.reduce((max, row) => Math.max(max, row.value), 0) || 1\n\n    return (\n        <div\n            data-slot=\"bar-list\"\n            data-surface={sf.surface}\n            data-radius={sf.radius}\n            data-animated={String(sf.animated)}\n            className={cn(\"flex flex-col gap-1.5\", className)}\n        >\n            {visible.map((row, i) => {\n                const pct = (row.value / peak) * 100\n                const labelClasses = cn(\n                    \"relative z-10 flex flex-1 items-center gap-2 truncate px-2 text-sm\",\n                    row.href && \"hover:underline\",\n                )\n                const labelInner = (\n                    <>\n                        {row.icon !== undefined && (\n                            <span className=\"flex shrink-0 items-center [&_svg]:size-4\">\n                                {row.icon}\n                            </span>\n                        )}\n                        <span className=\"truncate\">{row.name}</span>\n                    </>\n                )\n                return (\n                    <div\n                        key={`${row.name}-${i}`}\n                        data-slot=\"bar-list-item\"\n                        className=\"relative flex h-8 items-center\"\n                    >\n                        <m.div\n                            data-slot=\"bar-list-bar\"\n                            className=\"absolute inset-y-0 left-0 rounded-md bg-primary/15\"\n                            style={\n                                row.color\n                                    ? { backgroundColor: row.color, opacity: 0.18 }\n                                    : undefined\n                            }\n                            initial={motion.disabled ? false : { width: 0 }}\n                            animate={{ width: `${pct}%` }}\n                            transition={motion.transition}\n                        />\n                        {row.href ? (\n                            <a\n                                href={row.href}\n                                data-slot=\"bar-list-label\"\n                                className={labelClasses}\n                            >\n                                {labelInner}\n                            </a>\n                        ) : (\n                            <span data-slot=\"bar-list-label\" className={labelClasses}>\n                                {labelInner}\n                            </span>\n                        )}\n                        <span\n                            data-slot=\"bar-list-value\"\n                            className=\"relative z-10 shrink-0 px-2 text-sm font-medium tabular-nums\"\n                        >\n                            {valueFormatter(row.value)}\n                        </span>\n                    </div>\n                )\n            })}\n        </div>\n    )\n}\n",
      "target": "components/ui/bar-list.tsx"
    }
  ],
  "$meta": {
    "source": "https://ui.saasflare.io/r/bar-list.json"
  }
}
