{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "stat-card",
  "title": "Stat Card",
  "description": "A key figure with a label, a trend and a comparison, for dashboards and overviews.",
  "dependencies": [
    "@base-ui/react@^1.8.0",
    "lucide-react@^1.48.0"
  ],
  "files": [
    {
      "path": "registry/rapid/ui/stat-card/stat-card.tsx",
      "content": "import { mergeProps } from '@base-ui/react/merge-props'\nimport { useRender } from '@base-ui/react/use-render'\nimport { MinusIcon, TrendingDownIcon, TrendingUpIcon } from 'lucide-react'\nimport type * as React from 'react'\nimport { cn } from '@/lib/utils'\n\nfunction StatCardGroup({ className, ...props }: React.ComponentProps<'div'>) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"stat-card-group\"\n\t\t\tclassName={cn('grid grid-cols-[repeat(auto-fit,minmax(min(100%,13rem),1fr))] gap-4', className)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\n\nfunction StatCard({ className, render, ...props }: useRender.ComponentProps<'div'>) {\n\treturn useRender({\n\t\tdefaultTagName: 'div',\n\t\tprops: mergeProps<'div'>(\n\t\t\t{\n\t\t\t\tclassName: cn(\n\t\t\t\t\t'group/stat-card relative flex min-w-0 flex-col gap-1 rounded-xl bg-card p-4 text-sm text-card-foreground ring-1 ring-border outline-none transition-colors has-data-[slot=stat-card-icon]:pr-12 focus-visible:ring-3 focus-visible:ring-ring [a]:hover:bg-muted/50',\n\t\t\t\t\tclassName,\n\t\t\t\t),\n\t\t\t},\n\t\t\tprops,\n\t\t),\n\t\trender,\n\t\tstate: {\n\t\t\tslot: 'stat-card',\n\t\t},\n\t})\n}\n\nfunction StatCardLabel({ className, ...props }: React.ComponentProps<'p'>) {\n\treturn (\n\t\t<p\n\t\t\tdata-slot=\"stat-card-label\"\n\t\t\tclassName={cn('text-sm leading-snug font-medium text-muted-foreground', className)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\n\nfunction StatCardIcon({ className, ...props }: React.ComponentProps<'div'>) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"stat-card-icon\"\n\t\t\taria-hidden=\"true\"\n\t\t\tclassName={cn(\n\t\t\t\t\"absolute top-3 right-3 flex size-8 items-center justify-center rounded-lg bg-muted text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\n\nfunction StatCardValue({ className, ...props }: React.ComponentProps<'div'>) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"stat-card-value\"\n\t\t\tclassName={cn('font-heading text-2xl leading-tight font-semibold tabular-nums', className)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\n\nfunction StatCardUnit({ className, ...props }: React.ComponentProps<'span'>) {\n\treturn (\n\t\t<span\n\t\t\tdata-slot=\"stat-card-unit\"\n\t\t\tclassName={cn('ml-1 text-sm font-normal text-muted-foreground', className)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\n\ntype StatCardTrendDirection = 'up' | 'down' | 'flat'\ntype StatCardTrendTone = 'good' | 'bad' | 'neutral'\n\nconst defaultTrendLabels = {\n\tup: 'Increase',\n\tdown: 'Decrease',\n\tflat: 'No change',\n\tgood: 'good',\n\tbad: 'bad',\n}\n\ntype StatCardTrendLabels = typeof defaultTrendLabels\n\nconst trendIcons = {\n\tup: TrendingUpIcon,\n\tdown: TrendingDownIcon,\n\tflat: MinusIcon,\n} satisfies Record<StatCardTrendDirection, React.ComponentType<React.SVGProps<SVGSVGElement>>>\n\nfunction getTrendTone(direction: StatCardTrendDirection, goodDirection: 'up' | 'down' | 'none'): StatCardTrendTone {\n\tif (direction === 'flat' || goodDirection === 'none') return 'neutral'\n\treturn direction === goodDirection ? 'good' : 'bad'\n}\n\nfunction StatCardTrend({\n\tclassName,\n\tdirection,\n\tgoodDirection = 'up',\n\tlabels,\n\tchildren,\n\t...props\n}: React.ComponentProps<'p'> & {\n\t/** Which way the figure moved */\n\tdirection: StatCardTrendDirection\n\t/**\n\t * Which direction is an improvement. `up` for e.g. decided cases, `down` for e.g. overdue cases or handling time,\n\t * `none` when the change is neither good nor bad. The colour follows from this.\n\t */\n\tgoodDirection?: 'up' | 'down' | 'none'\n\t/** Screen-reader text for the direction and its meaning; English defaults, override to translate */\n\tlabels?: Partial<StatCardTrendLabels>\n}) {\n\tconst tone = getTrendTone(direction, goodDirection)\n\tconst text = { ...defaultTrendLabels, ...labels }\n\tconst Icon = trendIcons[direction]\n\tconst srText = tone === 'neutral' ? text[direction] : `${text[direction]}, ${text[tone]}`\n\n\treturn (\n\t\t<p\n\t\t\tdata-slot=\"stat-card-trend\"\n\t\t\tdata-direction={direction}\n\t\t\tdata-tone={tone}\n\t\t\tclassName={cn(\n\t\t\t\t'inline-flex w-fit items-center gap-1 text-sm font-medium tabular-nums data-[tone=bad]:text-destructive-subtle-foreground data-[tone=good]:text-success-subtle-foreground data-[tone=neutral]:text-muted-foreground [&>svg]:pointer-events-none [&>svg]:size-4 [&>svg]:shrink-0',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Icon aria-hidden=\"true\" />\n\t\t\t<span className=\"sr-only\">{srText}: </span>\n\t\t\t{children}\n\t\t</p>\n\t)\n}\n\nfunction StatCardDescription({ className, ...props }: React.ComponentProps<'p'>) {\n\treturn <p data-slot=\"stat-card-description\" className={cn('text-sm text-muted-foreground', className)} {...props} />\n}\n\nfunction StatCardFooter({ className, ...props }: React.ComponentProps<'div'>) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"stat-card-footer\"\n\t\t\tclassName={cn('mt-1 flex flex-wrap items-center gap-x-1.5 gap-y-0.5', className)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\n\nexport {\n\tStatCard,\n\tStatCardGroup,\n\tStatCardLabel,\n\tStatCardIcon,\n\tStatCardValue,\n\tStatCardUnit,\n\tStatCardTrend,\n\tStatCardDescription,\n\tStatCardFooter,\n\tgetTrendTone,\n\ttype StatCardTrendDirection,\n\ttype StatCardTrendLabels,\n\ttype StatCardTrendTone,\n}\n",
      "type": "registry:ui",
      "target": "components/ui/stat-card.tsx"
    }
  ],
  "meta": {
    "new": true
  },
  "type": "registry:ui"
}