{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pricing-select-cards",
  "type": "registry:component",
  "title": "Pricing select cards",
  "description": "Selectable pricing cards with localized prices from Paddle, available in stacked and grid layouts. Uses RadioGroup for single-plan selection — designed for express checkout flows.",
  "dependencies": ["lucide-react"],
  "registryDependencies": [
    "@paddle/paddle-helpers",
    "card",
    "badge",
    "skeleton",
    "radio-group"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/pricing-select-cards/components/pricing-select-card.tsx",
      "content": "export {\n  PricingSelectCardStacked,\n  type PricingSelectCardStackedProps,\n} from \"./pricing-select-card-stacked\"\nexport { PricingSelectCardGrid, type PricingSelectCardGridProps } from \"./pricing-select-card-grid\"\nexport {\n  PricingSelectCardGroup,\n  type PricingSelectCardGroupProps,\n} from \"./pricing-select-card-group\"\n\n/**\n * Plan configuration for use with PricingSelectCardGroup and ExpressCheckout.\n * Maps to a single Paddle price ID — pass an array of these to describe\n * the selectable plans in a checkout or pricing selector.\n */\nexport type PricingSelectPlan = {\n  priceId: string\n  name: string\n  description?: string\n  badge?: string\n  icon?: React.ReactNode\n}\n",
      "type": "registry:component"
    },
    {
      "path": "registry/new-york/blocks/pricing-select-cards/components/pricing-select-card-stacked.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\"\nimport { Card, CardHeader, CardTitle } from \"@/registry/new-york/ui/card\"\nimport { Badge } from \"@/registry/new-york/ui/badge\"\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\nexport type PricingSelectCardStackedProps = {\n  priceId: string\n  name: string\n  priceData?: PriceData\n  description?: string\n  badge?: string\n  badgePosition?: \"left\" | \"center\" | \"right\"\n  icon?: React.ReactNode\n  isCurrent?: boolean\n  currentPlanLabel?: string\n  showInterval?: boolean\n  loading?: boolean\n  className?: string\n}\n\nexport function PricingSelectCardStacked({\n  priceId,\n  name,\n  priceData,\n  description,\n  badge,\n  badgePosition = \"center\",\n  icon,\n  isCurrent = false,\n  currentPlanLabel = \"Current plan\",\n  showInterval = true,\n  loading = false,\n  className,\n}: PricingSelectCardStackedProps) {\n  const { total, originalTotal, interval, trialPeriod } = priceData ?? {}\n\n  const showBadges = badge || isCurrent\n\n  if (loading) {\n    return (\n      <Card className={cn(\"relative p-6\", className)}>\n        <Skeleton className=\"mb-2 h-4 w-24\" />\n        <Skeleton className=\"mb-1 h-8 w-32\" />\n        <Skeleton className=\"h-3 w-16\" />\n        {icon && <Skeleton className=\"absolute top-6 right-6 h-12 w-12 rounded-lg\" />}\n      </Card>\n    )\n  }\n\n  return (\n    <RadioGroupPrimitive.Item value={priceId} disabled={isCurrent} asChild>\n      <Card\n        className={cn(\n          \"relative flex cursor-pointer flex-col overflow-visible rounded-lg border p-6 shadow-sm transition-all hover:shadow-md\",\n          \"data-[state=checked]:border-2 data-[state=checked]:border-primary data-[state=checked]:bg-primary/5\",\n          isCurrent && \"cursor-default border-muted bg-muted/30 hover:shadow-sm\",\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        <div className=\"flex items-start justify-between\">\n          <CardHeader className=\"p-0\">\n            <div className=\"text-muted-foreground mb-1 text-sm\">{description || name}</div>\n            {originalTotal && (\n              <div className=\"text-muted-foreground text-sm line-through\">{originalTotal}</div>\n            )}\n            <CardTitle className=\"text-3xl font-bold\">{total}</CardTitle>\n            {showInterval && interval && (\n              <div className=\"text-muted-foreground text-sm\">per {interval}</div>\n            )}\n            {trialPeriod && (\n              <div className=\"text-muted-foreground text-xs mt-1\">{trialPeriod} free trial</div>\n            )}\n          </CardHeader>\n\n          {icon && <div className=\"h-12 w-12 shrink-0 rounded-lg\">{icon}</div>}\n        </div>\n      </Card>\n    </RadioGroupPrimitive.Item>\n  )\n}\n",
      "type": "registry:component"
    },
    {
      "path": "registry/new-york/blocks/pricing-select-cards/components/pricing-select-card-grid.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\"\nimport { Card, CardContent, CardHeader, CardTitle } from \"@/registry/new-york/ui/card\"\nimport { Badge } from \"@/registry/new-york/ui/badge\"\nimport { Skeleton } from \"@/registry/new-york/ui/skeleton\"\nimport { cn } from \"@/lib/utils\"\nimport { CheckIcon } from \"lucide-react\"\nimport type { PriceData } from \"@/registry/new-york/blocks/paddle-helpers/lib/paddle-types\"\n\nexport type PricingSelectCardGridProps = {\n  priceId: string\n  name: string\n  priceData?: PriceData\n  description?: string\n  badge?: string\n  badgePosition?: \"left\" | \"center\" | \"right\"\n  isCurrent?: boolean\n  currentPlanLabel?: string\n  showInterval?: boolean\n  loading?: boolean\n  className?: string\n}\n\nexport function PricingSelectCardGrid({\n  priceId,\n  name,\n  priceData,\n  description,\n  badge,\n  badgePosition = \"center\",\n  isCurrent = false,\n  currentPlanLabel = \"Current plan\",\n  showInterval = true,\n  loading = false,\n  className,\n}: PricingSelectCardGridProps) {\n  const { total, originalTotal, interval, trialPeriod } = priceData ?? {}\n\n  const showBadges = badge || isCurrent\n\n  if (loading) {\n    return (\n      <Card className={cn(\"relative p-5 text-center\", className)}>\n        <Skeleton className=\"mx-auto mb-2 h-5 w-20\" />\n        <Skeleton className=\"mx-auto mb-6 h-8 w-24\" />\n        <Skeleton className=\"mx-auto h-5 w-5 rounded-full\" />\n      </Card>\n    )\n  }\n\n  return (\n    <RadioGroupPrimitive.Item value={priceId} disabled={isCurrent} asChild>\n      <Card\n        className={cn(\n          \"relative flex cursor-pointer flex-col items-center justify-center overflow-visible rounded-lg border p-5 shadow-none transition-all hover:shadow-md\",\n          \"data-[state=checked]:border-2 data-[state=checked]:border-primary data-[state=checked]:bg-primary/5\",\n          isCurrent && \"cursor-default border-muted bg-muted/30 hover:shadow-none\",\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=\"flex-1 p-0 flex flex-col items-center justify-center text-center\">\n          <CardTitle className=\"text-base font-medium\">{name}</CardTitle>\n          {description && <div className=\"text-muted-foreground text-xs mt-0.5\">{description}</div>}\n          {originalTotal && (\n            <div className=\"text-muted-foreground text-sm line-through mt-2\">{originalTotal}</div>\n          )}\n          <div className=\"text-2xl font-bold mt-2\">{total}</div>\n          {showInterval && interval && (\n            <div className=\"text-muted-foreground text-xs\">per {interval}</div>\n          )}\n          {trialPeriod && (\n            <div className=\"text-muted-foreground text-xs mt-1\">{trialPeriod} free trial</div>\n          )}\n        </CardHeader>\n\n        <CardContent className=\"mt-6 flex items-center justify-center p-0\">\n          <RadioGroupPrimitive.Indicator asChild forceMount>\n            <div\n              className={cn(\n                \"group flex aspect-square size-5 shrink-0 items-center justify-center rounded-full border transition-colors\",\n                \"border-input data-[state=checked]:border-primary data-[state=checked]:bg-primary\"\n              )}\n            >\n              <CheckIcon className=\"size-4 text-primary-foreground opacity-0 group-data-[state=checked]:opacity-100 transition-opacity\" />\n            </div>\n          </RadioGroupPrimitive.Indicator>\n        </CardContent>\n      </Card>\n    </RadioGroupPrimitive.Item>\n  )\n}\n",
      "type": "registry:component"
    },
    {
      "path": "registry/new-york/blocks/pricing-select-cards/components/pricing-select-card-group.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { RadioGroup } from \"@/registry/new-york/ui/radio-group\"\nimport { cn } from \"@/lib/utils\"\n\nexport type PricingSelectCardGroupProps = {\n  children: React.ReactNode\n  value: string\n  onValueChange: (value: string) => void\n  layout?: \"stacked\" | \"grid\"\n  className?: string\n}\n\nexport function PricingSelectCardGroup({\n  children,\n  value,\n  onValueChange,\n  layout = \"stacked\",\n  className,\n}: PricingSelectCardGroupProps) {\n  const layoutClasses = {\n    stacked: \"flex flex-col gap-3\",\n    grid: \"grid grid-cols-2 gap-4\",\n  }\n\n  return (\n    <RadioGroup\n      value={value}\n      onValueChange={onValueChange}\n      className={cn(layoutClasses[layout], className)}\n    >\n      {children}\n    </RadioGroup>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": ["pricing"]
}
