{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "announcement-pill",
  "type": "registry:ui",
  "title": "Announcement Pill",
  "description": "Link above a hero where a sheen crosses once and the chevron becomes an arrow.",
  "categories": [
    "marketing"
  ],
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "https://www.stealth.pm/r/tokens.json",
    "https://www.stealth.pm/r/cn.json"
  ],
  "files": [
    {
      "path": "components/ui/announcement-pill.tsx",
      "content": "\"use client\";\nimport { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { cn } from \"@/lib/cn\";\n\ntype Size = \"sm\" | \"md\";\ntype BadgeVariant = \"solid\" | \"soft\";\n\nconst isExternalHref = (href?: string) => !!href && /^(https?:)?\\/\\//.test(href);\n\nexport type AnnouncementPillProps = useRender.ComponentProps<\"a\"> & {\n  /** The short label in the leading chip: \"New\", \"Beta\", \"v2.4\". Leave it out for a plain pill. */\n  badge?: React.ReactNode;\n  /** A filled chip that catches the eye, or a quiet outlined one. */\n  badgeVariant?: BadgeVariant;\n  size?: Size;\n  /** Opens in a new tab with an up-right arrow. Defaults to true for absolute URLs. */\n  external?: boolean;\n};\n\n/**\n * The link above a hero that says what's new. On hover a band of light crosses\n * it once, left to right, and the chevron pulls a stem out behind it to become\n * an arrow. Renders an anchor; pass `render={<Link href=\"…\" />}` for a router link.\n */\nexport function AnnouncementPill({\n  badge,\n  badgeVariant = \"solid\",\n  size = \"md\",\n  external: externalProp,\n  render,\n  className,\n  children,\n  ...rest\n}: AnnouncementPillProps) {\n  const external = externalProp ?? isExternalHref(rest.href);\n  const sm = size === \"sm\";\n\n  const own: useRender.ElementProps<\"a\"> & Record<`data-${string}`, string | undefined> = {\n    \"data-slot\": \"announcement-pill\",\n    \"data-size\": size,\n    \"data-badge\": badge ? badgeVariant : undefined,\n    target: external ? \"_blank\" : undefined,\n    rel: external ? \"noopener noreferrer\" : undefined,\n    className: cn(\n      \"group/pill relative isolate inline-flex max-w-full min-w-0 cursor-pointer select-none items-center rounded-full\",\n      \"border border-line-2 bg-raised text-fg-2 shadow-[var(--shadow)]\",\n      \"touch-manipulation [-webkit-tap-highlight-color:transparent]\",\n      \"outline-none focus-visible:outline-solid focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-fg-3\",\n      // One-step hover: the surface and the text each brighten a step. Press sinks it a touch.\n      \"transition-[background-color,border-color,color,scale] duration-150 ease-out-quart\",\n      \"hover:border-fg-4/70 hover:bg-hover hover:text-fg focus-visible:text-fg active:scale-[0.98] active:duration-75\",\n      sm ? \"h-7 gap-1.5 text-[12px]\" : \"h-8 gap-2 text-[12.5px]\",\n      badge ? (sm ? \"pl-[3px] pr-2\" : \"pl-1 pr-2.5\") : sm ? \"pl-2.5 pr-2\" : \"pl-3 pr-2.5\",\n      // 28–32px tall to the eye, 44px to a thumb.\n      \"pointer-coarse:after:absolute pointer-coarse:after:inset-x-0 pointer-coarse:after:-inset-y-2 pointer-coarse:after:content-['']\",\n      className,\n    ),\n    children: (\n      <>\n        {/* The sheen lives in its own clipped layer so the pill's touch area can reach past its edge. */}\n        <span aria-hidden className=\"pointer-events-none absolute inset-0 -z-10 overflow-hidden rounded-[inherit] motion-reduce:hidden\">\n          <span\n            className={cn(\n              \"absolute inset-y-0 left-0 w-1/2 -skew-x-[20deg]\",\n              \"bg-linear-to-r from-transparent via-raised to-transparent dark:via-fg/[0.09]\",\n              // Crosses once on the way in (850ms), snaps home unseen on the way out (0ms),\n              // so leaving never plays it backwards.\n              \"-translate-x-[120%] transition-[translate] duration-0 ease-in-out-quart\",\n              \"group-hover/pill:translate-x-[240%] group-hover/pill:duration-[850ms]\",\n              \"group-focus-visible/pill:translate-x-[240%] group-focus-visible/pill:duration-[850ms]\",\n            )}\n          />\n        </span>\n\n        {badge != null && badge !== false && (\n          <span\n            data-slot=\"announcement-pill-badge\"\n            className={cn(\n              \"inline-flex shrink-0 items-center rounded-full font-medium tracking-[-0.005em] transition-colors duration-150\",\n              sm ? \"h-5 px-1.5 text-[11px]\" : \"h-6 px-2 text-[11.5px]\",\n              badgeVariant === \"solid\" ? \"bg-fg text-frame\" : \"border border-line-2 bg-frame text-fg group-hover/pill:border-fg-4/70\",\n            )}\n          >\n            {badge}\n            {/* Read as \"New: Agent mode is here\", not \"New Agent mode is here\". */}\n            <span className=\"sr-only\">: </span>\n          </span>\n        )}\n\n        <span className=\"min-w-0 truncate font-[450] tracking-[-0.005em]\">{children}</span>\n\n        <Arrow external={external} />\n        {external && <span className=\"sr-only\"> (opens in a new tab)</span>}\n      </>\n    ),\n  };\n\n  return useRender({ defaultTagName: \"a\", render, props: mergeProps<\"a\">(own, rest) });\n}\n\n/**\n * At rest a chevron. On hover it steps 1.5px forward and a stem draws in behind\n * it, so the mark turns into an arrow pointing where the link goes.\n */\nfunction Arrow({ external }: { external: boolean }) {\n  const common = {\n    width: 14,\n    height: 14,\n    viewBox: \"0 0 16 16\",\n    fill: \"none\",\n    stroke: \"currentColor\",\n    strokeWidth: 1.5,\n    strokeLinecap: \"round\" as const,\n    strokeLinejoin: \"round\" as const,\n    \"aria-hidden\": true,\n    focusable: false,\n    className: \"-mr-0.5 shrink-0 text-fg-3 transition-colors duration-150 group-hover/pill:text-fg group-focus-visible/pill:text-fg\",\n  };\n  const move = \"transition-transform duration-200 ease-out-quart\";\n  if (external)\n    return (\n      <svg {...common}>\n        <g className={cn(move, \"group-hover/pill:translate-x-px group-hover/pill:-translate-y-px group-focus-visible/pill:translate-x-px group-focus-visible/pill:-translate-y-px\")}>\n          <path d=\"M5 11 11 5M6 5h5v5\" />\n        </g>\n      </svg>\n    );\n  return (\n    <svg {...common}>\n      <path\n        d=\"M3.75 8h6.5\"\n        className={cn(\n          \"origin-right [transform-box:fill-box] scale-x-0 opacity-0\",\n          \"transition-[scale,opacity,translate] duration-200 ease-out-quart\",\n          \"group-hover/pill:translate-x-[1.5px] group-hover/pill:scale-x-100 group-hover/pill:opacity-100\",\n          \"group-focus-visible/pill:translate-x-[1.5px] group-focus-visible/pill:scale-x-100 group-focus-visible/pill:opacity-100\",\n        )}\n      />\n      <path d=\"m7.25 4.5 3.5 3.5-3.5 3.5\" className={cn(move, \"group-hover/pill:translate-x-[1.5px] group-focus-visible/pill:translate-x-[1.5px]\")} />\n    </svg>\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "docs": "https://www.stealth.pm/ui/announcement-pill"
}
