{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pricing-cards",
  "type": "registry:component",
  "title": "Pricing cards",
  "description": "Responsive pricing tier cards with plan name, localized price, feature list, and per-card CTA. Supports current-plan highlighting and selection state for pricing pages and plan change flows.",
  "dependencies": ["lucide-react"],
  "registryDependencies": [
    "@paddle/paddle-helpers",
    "card",
    "badge",
    "button",
    "skeleton"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/pricing-cards/components/pricing-tier-card.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { CheckIcon } from \"lucide-react\"\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from \"@/registry/new-york/ui/card\"\nimport { Badge } from \"@/registry/new-york/ui/badge\"\nimport { Button } from \"@/registry/new-york/ui/button\"\nimport { Skeleton } from \"@/registry/new-york/ui/skeleton\"\nimport { cn } from \"@/lib/utils\"\nimport type { PriceData } from \"@/registry/new-york/blocks/paddle-helpers/lib/paddle-types\"\n\n/** Props for the `PricingTierCard` component. */\nexport type PricingTierCardProps = {\n  name: string\n  priceData?: PriceData\n  description?: string\n  features?: string[]\n  badge?: string\n  icon?: React.ReactNode\n  onSelect?: () => void\n  ctaLabel?: string\n  isSelected?: boolean\n  isCurrent?: boolean\n  currentPlanLabel?: string\n  badgePosition?: \"left\" | \"center\" | \"right\"\n  loading?: boolean\n  className?: string\n}\n\nexport function PricingTierCard({\n  name,\n  priceData,\n  description,\n  features,\n  badge,\n  icon,\n  onSelect,\n  ctaLabel,\n  isSelected,\n  isCurrent = false,\n  currentPlanLabel = \"Current plan\",\n  badgePosition = \"center\",\n  loading = false,\n  className,\n}: PricingTierCardProps) {\n  const { total, originalTotal, interval, trialPeriod } = priceData ?? {}\n\n  // undefined = checkout mode; defined (true/false) = selection mode\n  const isSelectionVariant = isSelected !== undefined\n  const resolvedCtaLabel =\n    ctaLabel ??\n    (isCurrent\n      ? currentPlanLabel\n      : isSelected\n        ? \"Selected\"\n        : isSelectionVariant\n          ? \"Select plan\"\n          : \"Subscribe\")\n\n  const showBadges = badge || isCurrent\n\n  // Custom onSelect (e.g. \"Contact Sales\") stays active on current plan\n  const isDisabled = isCurrent && !onSelect\n\n  const ctaVariant = isCurrent ? \"secondary\" : isSelected ? \"default\" : \"outline\"\n\n  if (loading) {\n    return (\n      <Card className={cn(\"relative flex flex-col\", className)}>\n        <CardHeader className=\"pb-2\">\n          <div className=\"flex items-start gap-3\">\n            {icon && <Skeleton className=\"size-10 rounded-md shrink-0\" />}\n            <div className=\"flex-1 space-y-2\">\n              <Skeleton className=\"h-5 w-24\" />\n              <Skeleton className=\"h-4 w-full\" />\n            </div>\n          </div>\n        </CardHeader>\n        <CardContent className=\"flex-1 space-y-3 pb-3\">\n          <div className=\"flex items-baseline gap-1\">\n            <Skeleton className=\"h-8 w-20\" />\n            <Skeleton className=\"h-4 w-8\" />\n          </div>\n          <div className=\"space-y-1.5\">\n            {[1, 2, 3].map((i) => (\n              <div key={i} className=\"flex items-start gap-2\">\n                <Skeleton className=\"size-4 shrink-0 mt-0.5\" />\n                <Skeleton className=\"h-4 w-full\" />\n              </div>\n            ))}\n          </div>\n        </CardContent>\n        <CardFooter className=\"pt-0 mt-auto\">\n          <Skeleton className=\"h-9 w-full\" />\n        </CardFooter>\n      </Card>\n    )\n  }\n\n  return (\n    <Card\n      data-selected={isSelected || undefined}\n      data-current={isCurrent || undefined}\n      className={cn(\n        \"relative flex flex-col h-full overflow-visible transition-all\",\n        isSelected && \"border-primary ring-1 ring-primary\",\n        isCurrent && \"border-muted bg-muted/30\",\n        className\n      )}\n    >\n      {showBadges && (\n        <div\n          className={cn(\n            \"absolute -top-3 z-10 flex gap-1.5\",\n            badgePosition === \"left\" && \"left-4\",\n            badgePosition === \"center\" && \"left-1/2 -translate-x-1/2\",\n            badgePosition === \"right\" && \"right-4\"\n          )}\n        >\n          {badge && <Badge className=\"bg-primary text-primary-foreground\">{badge}</Badge>}\n          {isCurrent && <Badge variant=\"secondary\">{currentPlanLabel}</Badge>}\n        </div>\n      )}\n\n      <CardHeader className=\"pb-2\">\n        <div className=\"flex items-start gap-3\">\n          {icon && <div className=\"size-10 rounded-md shrink-0 overflow-hidden\">{icon}</div>}\n          <div className=\"flex-1 min-w-0\">\n            <CardTitle className=\"truncate\">{name}</CardTitle>\n            {description && (\n              <CardDescription className=\"line-clamp-2\">{description}</CardDescription>\n            )}\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent className=\"flex-1 space-y-3 pb-3\">\n        {priceData && (\n          <div>\n            {originalTotal && (\n              <div className=\"text-muted-foreground text-sm line-through\">{originalTotal}</div>\n            )}\n            <div className=\"flex items-baseline gap-1 flex-wrap\">\n              <span className=\"text-2xl sm:text-3xl font-bold\">{total}</span>\n              {interval && <span className=\"text-muted-foreground text-sm\">/ {interval}</span>}\n            </div>\n            {trialPeriod && (\n              <div className=\"text-muted-foreground text-xs mt-1\">{trialPeriod} free trial</div>\n            )}\n          </div>\n        )}\n\n        {features && features.length > 0 && (\n          <ul className=\"space-y-1.5\">\n            {features.map((feature, index) => (\n              <li key={index} className=\"flex items-start gap-2 text-sm\">\n                <CheckIcon className=\"size-4 shrink-0 mt-0.5 text-primary\" />\n                <span className=\"text-muted-foreground\">{feature}</span>\n              </li>\n            ))}\n          </ul>\n        )}\n      </CardContent>\n\n      <CardFooter className=\"pt-0 mt-auto\">\n        <Button className=\"w-full\" variant={ctaVariant} disabled={isDisabled} onClick={onSelect}>\n          {resolvedCtaLabel}\n        </Button>\n      </CardFooter>\n    </Card>\n  )\n}\n",
      "type": "registry:component"
    },
    {
      "path": "registry/new-york/blocks/pricing-cards/components/pricing-tier-card-group.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\n\nexport type PricingTierCardGroupProps = {\n  children: React.ReactNode\n  columns?: number\n  className?: string\n}\n\nexport function PricingTierCardGroup({ children, columns, className }: PricingTierCardGroupProps) {\n  const count = columns ?? React.Children.count(children)\n\n  const gridClass =\n    count === 1\n      ? \"max-w-sm mx-auto\"\n      : count === 2\n        ? \"grid grid-cols-1 @md:grid-cols-2 max-w-2xl mx-auto gap-4\"\n        : count === 3\n          ? \"grid grid-cols-1 @md:grid-cols-2 @3xl:grid-cols-3 gap-4\"\n          : \"grid grid-cols-1 @md:grid-cols-2 @3xl:grid-cols-3 @5xl:grid-cols-4 gap-4\"\n\n  return (\n    <div className={cn(\"@container\", className)}>\n      <div className={cn(gridClass)}>{children}</div>\n    </div>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": ["pricing"]
}
