{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "badge",
  "type": "registry:ui",
  "title": "Badge",
  "description": "Fluent 2-styled badge with shadcn APIs. Six variants (default, secondary, destructive, outline, success, warning) as a compact pill, with icon support and asChild support.",
  "author": "graundtech <https://github.com/graundtech/fluent2-react-kit>",
  "dependencies": [
    "class-variance-authority",
    "@radix-ui/react-slot"
  ],
  "registryDependencies": [
    "https://fluent2-react-kit.graund.io/r/utils.json"
  ],
  "files": [
    {
      "path": "components/ui/badge.tsx",
      "type": "registry:ui",
      "target": "components/ui/badge.tsx",
      "content": "import { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Badge — Fluent 2-styled, shadcn-API badge.\n *\n * Aesthetics follow Fluent 2 (a 4px-radius chip — Fluent's fixed `medium`\n * corner token, non-scaling, NOT a full pill — compact 20px height, 10px/600\n * caption-2 label with 4px horizontal padding, flat filled surfaces, brand/\n * status color tokens); the prop surface (`variant`, `asChild`,\n * `badgeVariants`) follows shadcn/ui.\n *\n * Geometry is spec-exact: `rounded-md` (`--radius-md` = 4px, the Fluent badge\n * corner token used at every badge size), `px-1` (4px = `spacingHorizontalXS`),\n * `text-[10px]/[14px]` (Fluent \"Caption 2 Strong\", == the `--text-caption2`\n * token value — see the layout comment for why the arbitrary length is used\n * over the `text-caption2` utility) + `font-semibold` (600), fixed `h-5`\n * (20px Medium).\n *\n * Server-safe: no `\"use client\"`, no hooks/handlers — the React import is\n * type-only, so the file can be dropped straight into an RSC tree.\n *\n * Hover/active state steps only engage when the badge is rendered as an\n * interactive element via `asChild` (`[a&]:` targets the case where the\n * rendered tag is an `<a>`); a plain status label stays static.\n */\nconst badgeVariants = cva(\n  [\n    // layout — Fluent 4px chip, compact 20px height, centered caption-2 label\n    \"inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 whitespace-nowrap\",\n    // Fluent \"Caption 2 Strong\" = 10px/14px, weight 600. Expressed as the\n    // arbitrary `text-[10px]/[14px]` rather than the `text-caption2` token\n    // utility on purpose: every variant also sets a `text-*` color, and\n    // tailwind-merge (unaware of the custom `caption2` font-size) treats\n    // `text-caption2` as a text-color and drops it behind the variant color;\n    // the `--text-caption2` var also lives in `@theme inline`, which isn't\n    // emitted to :root, so a `text-(length:--text-caption2)` reference would be\n    // undefined at runtime. The arbitrary length is twMerge-safe and resolves\n    // with no runtime var. Values equal the `--text-caption2` token exactly.\n    \"rounded-md border px-1 text-[10px]/[14px] font-semibold select-none\",\n    // motion — token duration + Fluent easyEase curve; honors prefers-reduced-motion\n    // automatically (the duration tokens collapse to 0.01ms in tokens.css).\n    \"outline-none transition-colors duration-fast ease-ease\",\n    // focus — Fluent double-stroke approximation: 2px brand ring + 2px surface-colored gap.\n    // Only reachable when the badge is an interactive `asChild` element.\n    \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n    // invalid — shadcn aria-invalid treatment\n    \"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40\",\n    // icon defaults\n    \"[&>svg]:pointer-events-none [&>svg]:size-3\",\n  ],\n  {\n    variants: {\n      variant: {\n        // Fluent brand filled — flat, full brand state ramp on `asChild` links\n        // (spec §2.5): rest brand-80 → hover brand-70 → pressed brand-60 (light);\n        // rest brand-70 → hover brand-80 → pressed brand-60 (dark).\n        default:\n          \"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-brand-70 [a&]:active:bg-brand-60 dark:[a&]:hover:bg-brand-80\",\n        // Fluent standard/neutral — filled neutral surface + subtle border.\n        secondary:\n          \"border-border bg-secondary text-secondary-foreground [a&]:hover:bg-accent [a&]:active:bg-input dark:[a&]:hover:bg-input\",\n        // Fluent danger — red fill. No red ramp is exposed, so hover/pressed\n        // step via opacity; the focus ring switches to destructive.\n        destructive:\n          \"border-transparent bg-destructive text-destructive-foreground [a&]:hover:bg-destructive/90 [a&]:active:bg-destructive/80 focus-visible:ring-destructive\",\n        // Fluent outline — transparent + border, neutral hover.\n        outline:\n          \"border-border bg-transparent text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground [a&]:active:bg-accent/80 dark:[a&]:hover:bg-input/50\",\n        // Fluent success — green fill, AA-safe foreground from the status token pair.\n        success:\n          \"border-transparent bg-success text-success-foreground [a&]:hover:bg-success/90 [a&]:active:bg-success/80\",\n        // Fluent warning badge — bright orange chip (`#f7630c`) with DARK\n        // static text (`#242424`), the opposite foreground polarity from\n        // --warning's white text. Uses the dedicated `--warning-badge` pair\n        // (~4.98:1 AA), matching Figma's WarningBackground3 + NeutralForeground1\n        // Static, so Alert's darkOrange --warning stays put (single-source\n        // decoupling; see tokens.css + tokens-research.md §12.9).\n        warning:\n          \"border-transparent bg-warning-badge text-warning-badge-foreground [a&]:hover:bg-warning-badge/90 [a&]:active:bg-warning-badge/80\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n);\n\nfunction Badge({\n  className,\n  variant = \"default\",\n  asChild = false,\n  ...props\n}: ComponentProps<\"span\"> &\n  VariantProps<typeof badgeVariants> & {\n    asChild?: boolean;\n  }) {\n  const Comp = asChild ? Slot : \"span\";\n\n  return (\n    <Comp\n      data-slot=\"badge\"\n      data-variant={variant}\n      className={cn(badgeVariants({ variant, className }))}\n      {...props}\n    />\n  );\n}\n\nexport { Badge, badgeVariants };\n"
    }
  ]
}
