{ "$schema": "https://blode.co/ui/schema/registry-item.json", "name": "bar-list", "title": "Bar List", "author": "Matthew Blode", "description": "A compact comparison list that visualises values as horizontal bars.", "files": [ { "path": "ui/bar-list.tsx", "content": "import type * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface BarListItemBase {\n color?: string;\n href?: string;\n icon?: React.ComponentType<{ className?: string }>;\n key?: string;\n name: string;\n target?: React.HTMLAttributeAnchorTarget;\n value: number;\n}\n\ninterface BarListProps<\n T extends object = Record,\n> extends React.ComponentProps<\"div\"> {\n color?: string;\n data?: (T & BarListItemBase)[];\n labelFormatter?: (label: string) => React.ReactNode;\n showAnimation?: boolean;\n sortOrder?: \"ascending\" | \"descending\";\n valueFormatter?: (value: number) => React.ReactNode;\n}\n\nconst EMPTY_BAR_LIST_DATA: never[] = [];\n\nconst defaultValueFormatter = (value: number): string => value.toLocaleString();\n\nconst defaultLabelFormatter = (label: string): string => label;\n\nconst BarList = >({\n className,\n color = \"hsl(var(--chart-1))\",\n data = EMPTY_BAR_LIST_DATA,\n labelFormatter = defaultLabelFormatter,\n showAnimation = false,\n sortOrder = \"descending\",\n valueFormatter = defaultValueFormatter,\n ...props\n}: BarListProps) => {\n const sortedData = [...data].toSorted((a, b) =>\n sortOrder === \"ascending\" ? a.value - b.value : b.value - a.value,\n );\n\n const maxValue = Math.max(0, ...sortedData.map((item) => item.value));\n\n const widths = sortedData.map((item) => {\n if (item.value === 0 || maxValue === 0) {\n return 0;\n }\n\n return Math.max((item.value / maxValue) * 100, 2);\n });\n\n const rowHeight = \"h-8\";\n\n return (\n \n
\n {sortedData.map((item, index) => {\n const Icon = item.icon;\n\n return (\n \n \n \n
\n\n
\n {Icon ? : null}\n\n {item.href ? (\n event.stopPropagation()}\n rel=\"noreferrer\"\n target={item.target ?? \"_blank\"}\n >\n {labelFormatter(item.name)}\n \n ) : (\n

\n {labelFormatter(item.name)}\n

\n )}\n
\n \n );\n })}\n \n\n
\n {sortedData.map((item, index) => (\n \n

\n {valueFormatter(item.value)}\n

\n
\n ))}\n \n \n );\n};\n\nexport { BarList };\nexport type { BarListProps };\n", "type": "registry:ui", "target": "" } ], "type": "registry:ui" }