{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "count",
  "title": "Count",
  "author": "Tori Bryan",
  "description": "A number at a glance: capped at 99+, shortened to 1.2K or signed as +4, read out in full.",
  "dependencies": [],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/count.tsx",
      "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport {\n  formatCount,\n  type FormatCountOptions,\n} from \"@/lib/format-count\"\n\ntype CountProps = Omit<React.ComponentProps<\"span\">, \"children\"> &\n  FormatCountOptions & {\n    /** The number. */\n    value: number\n    /** What screen readers hear, such as `(n) => \\`${n} unread\\``. Defaults to the exact number when the shown one is capped or shortened. `null` hides the count when its neighbor already says it. */\n    label?: string | ((value: number) => string) | null\n  }\n\n/**\n * A number as people take it in at a glance: capped at 99+, shortened to\n * 1.2K, or signed as +4, in figures that don't shift as they change. It says\n * the exact number, or your label, to screen readers.\n */\nfunction Count({\n  value,\n  max,\n  notation,\n  plus,\n  locale,\n  label,\n  className,\n  ...props\n}: CountProps) {\n  const { shown, exact } = formatCount(value, { max, notation, plus, locale })\n  const spoken =\n    label === null\n      ? null\n      : typeof label === \"function\"\n        ? label(value)\n        : (label ?? (shown === exact ? null : exact))\n\n  return (\n    <span\n      data-slot=\"count\"\n      aria-hidden={label === null || undefined}\n      className={cn(\"tabular-nums\", className)}\n      {...props}\n    >\n      {spoken ? (\n        <>\n          <span aria-hidden=\"true\">{shown}</span>\n          <span className=\"sr-only\">{spoken}</span>\n        </>\n      ) : (\n        shown\n      )}\n    </span>\n  )\n}\n\nexport { Count, formatCount, type CountProps }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/lib/format-count.ts",
      "content": "export type FormatCountOptions = {\n  /** Above this the count shows as `max+`, such as 99+. */\n  max?: number\n  /** `compact` shortens counts from 1,000 up, such as 1.2K. */\n  notation?: \"standard\" | \"compact\"\n  /** Puts a plus before the count, for things not shown, such as +4. */\n  plus?: boolean\n  /** BCP 47 locale for the digits and separators. */\n  locale?: string\n}\n\n/**\n * A count as it should be shown: capped, shortened or signed. The exact\n * number is for speech, so a capped or shortened count says it in full.\n */\nexport function formatCount(\n  value: number,\n  { max, notation = \"standard\", plus = false, locale }: FormatCountOptions = {}\n) {\n  const standard = new Intl.NumberFormat(locale)\n  const exact = standard.format(value)\n  let shown: string\n  if (max !== undefined && value > max) {\n    shown = `${standard.format(max)}+`\n  } else if (notation === \"compact\" && Math.abs(value) >= 1000) {\n    shown = new Intl.NumberFormat(locale, {\n      notation: \"compact\",\n      maximumFractionDigits: 1,\n    }).format(value)\n  } else {\n    shown = exact\n  }\n  return { shown: plus ? `+${shown}` : shown, exact }\n}\n",
      "type": "registry:lib"
    }
  ],
  "meta": {
    "tier": "base-components",
    "group": "Display",
    "docs": "https://fibo.toribryan.com/?path=/docs/base-components-display-count--docs"
  },
  "docs": "Docs and live examples: https://fibo.toribryan.com/?path=/docs/base-components-display-count--docs",
  "categories": [
    "base-components",
    "display"
  ],
  "type": "registry:ui"
}