{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bar-list-card",
  "title": "Bar List",
  "description": "Ranked breakdown rows with share or raw bars, optional tabs and icons.",
  "registryDependencies": [
    "https://components.exe.xyz/r/tabs.json",
    "https://components.exe.xyz/r/utils.json"
  ],
  "files": [
    {
      "path": "src/components/charts/bar-list-card.tsx",
      "content": "import { useState } from \"react\"\nimport type { ReactNode } from \"react\"\n\nimport { Tabs, TabsList, TabsTrigger } from \"@/components/ui/tabs\"\nimport { cn } from \"@/lib/utils\"\n\nexport type BarListItem = {\n  label: string\n  value: number\n  icon?: ReactNode\n}\n\nexport type BarListTab = {\n  id: string\n  label: string\n  items: BarListItem[]\n}\n\nconst DEFAULT_TABS: BarListTab[] = [\n  {\n    id: \"devices\",\n    label: \"Devices\",\n    items: [\n      { label: \"Desktop\", value: 61 },\n      { label: \"Mobile\", value: 31 },\n      { label: \"Tablet\", value: 8 },\n    ],\n  },\n  {\n    id: \"browsers\",\n    label: \"Browsers\",\n    items: [\n      { label: \"Chrome\", value: 53 },\n      { label: \"Safari\", value: 27 },\n      { label: \"Firefox\", value: 9 },\n      { label: \"Edge\", value: 6 },\n      { label: \"Samsung Internet\", value: 2 },\n    ],\n  },\n  {\n    id: \"os\",\n    label: \"OS\",\n    items: [\n      { label: \"macOS\", value: 38 },\n      { label: \"Windows\", value: 34 },\n      { label: \"iOS\", value: 16 },\n      { label: \"Android\", value: 10 },\n      { label: \"Linux\", value: 2 },\n    ],\n  },\n  {\n    id: \"screens\",\n    label: \"Screen sizes\",\n    items: [\n      { label: \"1920×1080\", value: 28 },\n      { label: \"1512×982\", value: 22 },\n      { label: \"390×844\", value: 18 },\n      { label: \"1440×900\", value: 17 },\n      { label: \"2560×1440\", value: 15 },\n    ],\n  },\n]\n\nfunction formatMetric(value: number, total: number, metric: \"share\" | \"value\") {\n  if (metric === \"value\") return value.toLocaleString(\"en-US\")\n  if (total === 0) return \"0%\"\n  return `${Math.round((value / total) * 100)}%`\n}\n\nexport function BarListCard({\n  metricLabel,\n  metric = \"share\",\n  mono = false,\n  limit,\n  title,\n  items,\n  tabs,\n  defaultTab,\n  onTabChange,\n}: {\n  metricLabel?: string\n  metric?: \"share\" | \"value\"\n  mono?: boolean\n  limit?: number\n  title?: string\n  items?: BarListItem[]\n  tabs?: BarListTab[]\n  defaultTab?: string\n  onTabChange?: (id: string) => void\n}) {\n  const groups =\n    tabs && tabs.length > 0\n      ? tabs\n      : items\n        ? [{ id: \"all\", label: title ?? \"All\", items }]\n        : DEFAULT_TABS\n  const firstGroup = groups[0]\n  const [tab, setTab] = useState(defaultTab ?? firstGroup.id)\n  const active = groups.find((group) => group.id === tab) ?? firstGroup\n  const rows = active.items.slice(0, limit)\n  const total = active.items.reduce((sum, row) => sum + row.value, 0)\n  const max = Math.max(1, ...rows.map((row) => row.value))\n  const heading = title ?? active.label\n\n  return (\n    <article\n      className=\"flex w-full flex-col overflow-hidden rounded-[2px] border border-border bg-card\"\n      aria-label={heading}\n    >\n      <header className=\"flex items-center justify-between gap-3 px-4 pt-4\">\n        <div className=\"min-w-0\">\n          <p className=\"text-sm text-muted-foreground\">{heading}</p>\n          {metricLabel ? (\n            <p className=\"font-mono text-[11px] text-muted-foreground\">\n              {metricLabel}\n            </p>\n          ) : null}\n        </div>\n        {groups.length > 1 ? (\n          <Tabs\n            value={tab}\n            onValueChange={(next) => {\n              setTab(next)\n              onTabChange?.(next)\n            }}\n          >\n            <TabsList variant=\"line\" className=\"h-7\">\n              {groups.map((group) => (\n                <TabsTrigger\n                  key={group.id}\n                  value={group.id}\n                  className=\"px-2 font-mono text-[11px]\"\n                >\n                  {group.label}\n                </TabsTrigger>\n              ))}\n            </TabsList>\n          </Tabs>\n        ) : null}\n      </header>\n      <ul className=\"flex flex-col gap-3 px-4 py-4\">\n        {rows.map((row) => (\n          <li key={row.label}>\n            <div className=\"mb-1 flex items-baseline justify-between gap-3 text-sm\">\n              <span className=\"flex min-w-0 items-center gap-2\">\n                {row.icon ? (\n                  <span className=\"size-4 shrink-0 [&_svg]:size-4\">\n                    {row.icon}\n                  </span>\n                ) : null}\n                <span className=\"truncate\">{row.label}</span>\n              </span>\n              <span className=\"font-mono text-[11px] text-muted-foreground tabular-nums\">\n                {formatMetric(row.value, total, metric)}\n              </span>\n            </div>\n            <div className=\"h-2 rounded-[2px] bg-muted\" aria-hidden>\n              <div\n                className={cn(\"h-full rounded-[2px]\")}\n                style={{\n                  width: `${(row.value / max) * 100}%`,\n                  background: mono ? \"var(--chart-5)\" : \"var(--chart-1)\",\n                }}\n              />\n            </div>\n          </li>\n        ))}\n      </ul>\n    </article>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}