{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pricing-table-one",
  "title": "Pricing Table One",
  "description": "A pricing table component",
  "dependencies": ["lucide-react", "class-variance-authority", "motion"],
  "registryDependencies": [
    "button",
    "card",
    "badge",
    "switch",
    "radio-group",
    "label",
    "separator",
    "utils"
  ],
  "files": [
    {
      "path": "src/registry/billingsdk/pricing-table-one.tsx",
      "content": "\"use client\";\n\nimport { Check, Zap } from \"lucide-react\";\nimport { useState, useId } from \"react\";\nimport { motion, AnimatePresence } from \"motion/react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Label } from \"@/components/ui/label\";\nimport { RadioGroup, RadioGroupItem } from \"@/components/ui/radio-group\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { type Plan } from \"@/lib/billingsdk-config\";\nimport { cn } from \"@/lib/utils\";\n\nconst sectionVariants = cva(\"py-32\", {\n  variants: {\n    size: {\n      small: \"py-6 md:py-12\",\n      medium: \"py-10 md:py-20\",\n      large: \"py-16 md:py-32\",\n    },\n    theme: {\n      minimal: \"\",\n      classic:\n        \"bg-gradient-to-b from-background to-muted/20 relative overflow-hidden\",\n    },\n  },\n  defaultVariants: {\n    size: \"medium\",\n    theme: \"minimal\",\n  },\n});\n\nconst titleVariants = cva(\"text-pretty text-left font-bold\", {\n  variants: {\n    size: {\n      small: \"text-3xl lg:text-4xl\",\n      medium: \"text-4xl lg:text-5xl\",\n      large: \"text-4xl lg:text-6xl\",\n    },\n    theme: {\n      minimal: \"\",\n      classic:\n        \"text-center bg-gradient-to-r from-foreground to-muted-foreground bg-clip-text text-transparent p-1\",\n    },\n  },\n  defaultVariants: {\n    size: \"large\",\n    theme: \"minimal\",\n  },\n});\n\nconst descriptionVariants = cva(\"text-muted-foreground max-w-3xl\", {\n  variants: {\n    size: {\n      small: \"text-base lg:text-lg\",\n      medium: \"text-lg lg:text-xl\",\n      large: \"lg:text-xl\",\n    },\n    theme: {\n      minimal: \"text-left\",\n      classic: \"text-center mx-auto\",\n    },\n  },\n  defaultVariants: {\n    size: \"large\",\n    theme: \"minimal\",\n  },\n});\n\nconst cardVariants = cva(\n  \"flex w-full flex-col rounded-lg border text-left h-full transition-all duration-300\",\n  {\n    variants: {\n      size: {\n        small: \"p-4\",\n        medium: \"p-5\",\n        large: \"p-6\",\n      },\n      theme: {\n        minimal: \"\",\n        classic: \"hover:shadow-xl backdrop-blur-sm bg-card/50 border-border/50\",\n      },\n      highlight: {\n        true: \"\",\n        false: \"\",\n      },\n    },\n    compoundVariants: [\n      {\n        theme: \"classic\",\n        highlight: true,\n        className:\n          \"ring-2 ring-primary/20 border-primary/30 bg-gradient-to-b from-primary/5 to-transparent relative overflow-hidden\",\n      },\n      {\n        theme: \"minimal\",\n        highlight: true,\n        className: \"bg-muted\",\n      },\n    ],\n    defaultVariants: {\n      size: \"large\",\n      theme: \"minimal\",\n      highlight: false,\n    },\n  },\n);\n\nconst priceTextVariants = cva(\"font-medium\", {\n  variants: {\n    size: {\n      small: \"text-3xl\",\n      medium: \"text-4xl\",\n      large: \"text-4xl\",\n    },\n    theme: {\n      minimal: \"\",\n      classic:\n        \"text-5xl font-extrabold bg-gradient-to-r from-foreground to-muted-foreground bg-clip-text text-transparent\",\n    },\n  },\n  defaultVariants: {\n    size: \"large\",\n    theme: \"minimal\",\n  },\n});\n\nconst featureIconVariants = cva(\"flex-none h-[1lh]\", {\n  variants: {\n    size: {\n      small: \"size-3\",\n      medium: \"size-4\",\n      large: \"size-4\",\n    },\n    theme: {\n      minimal: \"text-primary\",\n      classic: \"text-emerald-500\",\n    },\n  },\n  defaultVariants: {\n    size: \"large\",\n    theme: \"minimal\",\n  },\n});\n\nconst highlightBadgeVariants = cva(\"mb-8 block w-fit\", {\n  variants: {\n    theme: {\n      minimal: \"\",\n      classic:\n        \"bg-gradient-to-r from-primary to-primary/80 text-primary-foreground border-primary/20 shadow-lg\",\n    },\n  },\n  defaultVariants: {\n    theme: \"minimal\",\n  },\n});\n\nconst toggleVariants = cva(\n  \"flex h-11 w-fit shrink-0 items-center rounded-md p-1 text-lg\",\n  {\n    variants: {\n      theme: {\n        minimal: \"bg-muted\",\n        classic:\n          \"bg-muted/50 backdrop-blur-sm border border-border/50 shadow-lg\",\n      },\n    },\n    defaultVariants: {\n      theme: \"minimal\",\n    },\n  },\n);\n\nconst buttonVariants = cva(\n  \"gap-2 whitespace-nowrap focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 transition-all duration-300\",\n  {\n    variants: {\n      theme: {\n        minimal:\n          \"shadow hover:bg-primary/90 h-9 py-2 group bg-primary text-primary-foreground ring-primary before:from-primary-foreground/20 after:from-primary-foreground/10 relative isolate inline-flex w-full items-center justify-center overflow-hidden rounded-md px-3 text-left text-sm font-medium ring-1 before:pointer-events-none before:absolute before:inset-0 before:-z-10 before:rounded-md before:bg-gradient-to-b before:opacity-80 before:transition-opacity before:duration-300 before:ease-[cubic-bezier(0.4,0.36,0,1)] after:pointer-events-none after:absolute after:inset-0 after:-z-10 after:rounded-md after:bg-gradient-to-b after:to-transparent after:mix-blend-overlay hover:cursor-pointer\",\n        classic:\n          \"relative overflow-hidden bg-gradient-to-r from-primary to-primary/80 text-primary-foreground font-semibold py-3 px-6 rounded-lg hover:shadow-xl active:scale-95 border border-primary/20\",\n      },\n    },\n    defaultVariants: {\n      theme: \"minimal\",\n    },\n  },\n);\n\nexport interface PricingTableOneProps extends VariantProps<\n  typeof sectionVariants\n> {\n  className?: string;\n  plans: Plan[];\n  title?: string;\n  description?: string;\n  onPlanSelect?: (planId: string) => void;\n}\n\nexport function PricingTableOne({\n  className,\n  plans,\n  title,\n  description,\n  onPlanSelect,\n  size,\n  theme = \"minimal\",\n}: PricingTableOneProps) {\n  const [isAnnually, setIsAnnually] = useState(false);\n  const uniqueId = useId(); // Generate unique ID automatically\n\n  function calculateDiscount(\n    monthlyPrice: string,\n    yearlyPrice: string,\n  ): number {\n    const monthly = parseFloat(monthlyPrice);\n    const yearly = parseFloat(yearlyPrice);\n\n    if (\n      monthlyPrice.toLowerCase() === \"custom\" ||\n      yearlyPrice.toLowerCase() === \"custom\" ||\n      isNaN(monthly) ||\n      isNaN(yearly) ||\n      monthly === 0\n    ) {\n      return 0;\n    }\n\n    const discount = ((monthly * 12 - yearly) / (monthly * 12)) * 100;\n    return Math.round(discount);\n  }\n\n  const yearlyPriceDiscount = plans.length\n    ? Math.max(\n        ...plans.map((plan) =>\n          calculateDiscount(plan.monthlyPrice, plan.yearlyPrice),\n        ),\n      )\n    : 0;\n\n  return (\n    <section className={cn(sectionVariants({ size, theme }), className)}>\n      {/* Classic theme background elements */}\n      {theme === \"classic\" && (\n        <>\n          <div className=\"bg-grid-pattern absolute inset-0 opacity-5\" />\n          <div className=\"bg-primary/5 absolute top-1/2 left-1/2 h-96 w-96 -translate-x-1/2 -translate-y-1/2 rounded-full blur-3xl\" />\n          <div className=\"bg-secondary/5 absolute top-1/4 right-1/4 h-64 w-64 rounded-full blur-2xl\" />\n        </>\n      )}\n\n      <div className={cn(\"relative container\", \"p-0 md:p-[1rem]\")}>\n        <div className=\"mx-auto flex max-w-7xl flex-col gap-6\">\n          <div\n            className={cn(\n              \"flex flex-col gap-4\",\n              theme === \"classic\" && \"text-center\",\n            )}\n          >\n            <h2 className={cn(titleVariants({ size, theme }))}>\n              {title || \"Pricing\"}\n            </h2>\n          </div>\n\n          <div\n            className={cn(\n              \"flex flex-col justify-between gap-5 md:gap-10\",\n              theme === \"classic\"\n                ? \"md:flex-col md:items-center\"\n                : \"md:flex-row\",\n            )}\n          >\n            <p className={cn(descriptionVariants({ size, theme }))}>\n              {description ||\n                \"Transparent pricing with no hidden fees. Upgrade or downgrade anytime.\"}\n            </p>\n            <div\n              className={cn(\n                toggleVariants({ theme }),\n                theme === \"classic\" && \"mx-auto\",\n              )}\n            >\n              <RadioGroup\n                defaultValue=\"monthly\"\n                className=\"h-full grid-cols-2\"\n                onValueChange={(value) => {\n                  setIsAnnually(value === \"annually\");\n                }}\n              >\n                <div className='has-[button[data-state=\"checked\"]]:bg-background h-full rounded-md transition-all'>\n                  <RadioGroupItem\n                    value=\"monthly\"\n                    id={`${uniqueId}-monthly`}\n                    className=\"peer sr-only\"\n                  />\n                  <Label\n                    htmlFor={`${uniqueId}-monthly`}\n                    className=\"text-muted-foreground peer-data-[state=checked]:text-primary hover:text-foreground flex h-full cursor-pointer items-center justify-center px-2 font-semibold transition-all md:px-7\"\n                  >\n                    Monthly\n                  </Label>\n                </div>\n                <div className='has-[button[data-state=\"checked\"]]:bg-background h-full rounded-md transition-all'>\n                  <RadioGroupItem\n                    value=\"annually\"\n                    id={`${uniqueId}-annually`}\n                    className=\"peer sr-only\"\n                  />\n                  <Label\n                    htmlFor={`${uniqueId}-annually`}\n                    className=\"text-muted-foreground peer-data-[state=checked]:text-primary hover:text-foreground flex h-full cursor-pointer items-center justify-center gap-1 px-2 font-semibold transition-all md:px-7\"\n                  >\n                    Yearly\n                    {yearlyPriceDiscount > 0 && (\n                      <span className=\"bg-primary/10 text-primary border-primary/20 ml-1 rounded border px-2 py-0.5 text-xs font-medium\">\n                        Save {yearlyPriceDiscount}%\n                      </span>\n                    )}\n                  </Label>\n                </div>\n              </RadioGroup>\n            </div>\n          </div>\n\n          <div className=\"flex w-full flex-col items-stretch gap-6 md:flex-row md:items-stretch\">\n            {plans.map((plan, index) => (\n              <motion.div\n                key={plan.id}\n                layout\n                initial={{ opacity: 0 }}\n                animate={{ opacity: 1 }}\n                transition={{ duration: 0.3, delay: index * 0.1 }}\n                className={cn(\n                  cardVariants({\n                    size,\n                    theme,\n                    highlight: plan.highlight,\n                  }),\n                )}\n              >\n                {/* Classic theme highlight effect */}\n                {theme === \"classic\" && plan.highlight && (\n                  <>\n                    <div className=\"via-primary absolute -top-px left-1/2 h-px w-32 -translate-x-1/2 bg-gradient-to-r from-transparent to-transparent\" />\n                    <div className=\"absolute top-4 right-4\">\n                      <Badge className={highlightBadgeVariants({ theme })}>\n                        Most Popular\n                      </Badge>\n                    </div>\n                  </>\n                )}\n\n                <Badge\n                  className={cn(\n                    theme === \"classic\" && !plan.highlight\n                      ? \"bg-muted text-muted-foreground border-border/50 mb-8\"\n                      : highlightBadgeVariants({ theme }),\n                  )}\n                >\n                  {plan.title}\n                </Badge>\n\n                <AnimatePresence mode=\"wait\">\n                  <motion.div\n                    key={isAnnually ? \"year\" : \"month\"}\n                    initial={{ opacity: 0, y: 10 }}\n                    animate={{ opacity: 1, y: 0 }}\n                    exit={{ opacity: 0, y: -10 }}\n                    transition={{ duration: 0.2 }}\n                  >\n                    {isAnnually ? (\n                      <>\n                        <span\n                          className={cn(\n                            \"my-auto\",\n                            priceTextVariants({ size, theme }),\n                          )}\n                        >\n                          {parseFloat(plan.yearlyPrice) >= 0 && (\n                            <>{plan.currency}</>\n                          )}\n                          {plan.yearlyPrice}\n                          {calculateDiscount(\n                            plan.monthlyPrice,\n                            plan.yearlyPrice,\n                          ) > 0 && (\n                            <span\n                              className={cn(\n                                \"ml-2 text-xs\",\n                                theme === \"classic\"\n                                  ? \"font-semibold text-emerald-500\"\n                                  : \"underline\",\n                              )}\n                            >\n                              {calculateDiscount(\n                                plan.monthlyPrice,\n                                plan.yearlyPrice,\n                              )}\n                              % off\n                            </span>\n                          )}\n                        </span>\n                        <p className=\"text-muted-foreground\">per year</p>\n                      </>\n                    ) : (\n                      <>\n                        <span\n                          className={cn(priceTextVariants({ size, theme }))}\n                        >\n                          {parseFloat(plan.monthlyPrice) >= 0 && (\n                            <>{plan.currency}</>\n                          )}\n                          {plan.monthlyPrice}\n                        </span>\n                        <p className=\"text-muted-foreground\">per month</p>\n                      </>\n                    )}\n                  </motion.div>\n                </AnimatePresence>\n\n                <Separator\n                  className={cn(\n                    \"my-6\",\n                    theme === \"classic\" &&\n                      \"via-border bg-gradient-to-r from-transparent to-transparent\",\n                  )}\n                />\n\n                <div className=\"flex h-full flex-col justify-between gap-10\">\n                  <ul className=\"text-muted-foreground space-y-4\">\n                    {plan.features.map((feature, featureIndex) => (\n                      <motion.li\n                        key={featureIndex}\n                        className=\"flex gap-3\"\n                        initial={{ opacity: 0, x: -10 }}\n                        animate={{ opacity: 1, x: 0 }}\n                        transition={{\n                          duration: 0.3,\n                          delay: featureIndex * 0.05,\n                        }}\n                      >\n                        <Check\n                          className={cn(featureIconVariants({ size, theme }))}\n                        />\n                        <span\n                          className={cn(\n                            theme === \"classic\" && \"text-foreground/90\",\n                          )}\n                        >\n                          {feature.name}\n                        </span>\n                      </motion.li>\n                    ))}\n                  </ul>\n\n                  <Button\n                    className={buttonVariants({ theme })}\n                    onClick={() => onPlanSelect?.(plan.id)}\n                    aria-label={`Select ${plan.title} plan`}\n                  >\n                    {theme === \"classic\" && plan.highlight && (\n                      <Zap className=\"mr-1 h-4 w-4\" />\n                    )}\n                    {plan.buttonText}\n                    {theme === \"classic\" && (\n                      <div className=\"absolute inset-0 translate-x-[-100%] bg-gradient-to-r from-white/0 via-white/10 to-white/0 transition-transform duration-700 hover:translate-x-[100%]\" />\n                    )}\n                  </Button>\n                </div>\n              </motion.div>\n            ))}\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/billingsdk/pricing-table-one.tsx"
    },
    {
      "path": "src/registry/billingsdk/demo/pricing-table-one-demo.tsx",
      "content": "\"use client\";\n\nimport { PricingTableOne } from \"@/components/billingsdk/pricing-table-one\";\nimport { plans } from \"@/lib/billingsdk-config\";\n\nexport function PricingTableOneDemo() {\n  return (\n    <PricingTableOne\n      plans={plans}\n      title=\"Pricing\"\n      description=\"Choose the plan that's right for you\"\n      onPlanSelect={(planId) => console.log(\"Selected plan:\", planId)}\n      size=\"medium\" // small, medium, large\n      theme=\"classic\" // minimal or classic\n      className=\"w-full\"\n    />\n  );\n}\n",
      "type": "registry:component",
      "target": "components/pricing-table-one-demo.tsx"
    },
    {
      "path": "src/registry/lib/billingsdk-config.ts",
      "content": "export interface Plan {\n  id: string;\n  title: string;\n  description: string;\n  highlight?: boolean;\n  type?: \"monthly\" | \"yearly\";\n  currency?: string;\n  monthlyPrice: string;\n  yearlyPrice: string;\n  buttonText: string;\n  badge?: string;\n  features: {\n    name: string;\n    icon: string;\n    iconColor?: string;\n  }[];\n}\n\nexport interface CurrentPlan {\n  plan: Plan;\n  type: \"monthly\" | \"yearly\" | \"custom\";\n  price?: string;\n  nextBillingDate: string;\n  paymentMethod: string;\n  status: \"active\" | \"inactive\" | \"past_due\" | \"cancelled\";\n}\n\nexport const plans: Plan[] = [\n  {\n    id: \"starter\",\n    title: \"Starter\",\n    description: \"For developers testing out Liveblocks locally.\",\n    currency: \"$\",\n    monthlyPrice: \"0\",\n    yearlyPrice: \"0\",\n    buttonText: \"Start today for free\",\n    features: [\n      {\n        name: \"Presence\",\n        icon: \"check\",\n        iconColor: \"text-green-500\",\n      },\n      {\n        name: \"Comments\",\n        icon: \"check\",\n        iconColor: \"text-orange-500\",\n      },\n      {\n        name: \"Notifications\",\n        icon: \"check\",\n        iconColor: \"text-teal-500\",\n      },\n      {\n        name: \"Text Editor\",\n        icon: \"check\",\n        iconColor: \"text-blue-500\",\n      },\n      {\n        name: \"Sync Datastore\",\n        icon: \"check\",\n        iconColor: \"text-zinc-500\",\n      },\n    ],\n  },\n  {\n    id: \"pro\",\n    title: \"Pro\",\n    description: \"For companies adding collaboration in production.\",\n    currency: \"$\",\n    monthlyPrice: \"20\",\n    yearlyPrice: \"199\",\n    buttonText: \"Sign up\",\n    badge: \"Most popular\",\n    highlight: true,\n    features: [\n      {\n        name: \"Presence\",\n        icon: \"check\",\n        iconColor: \"text-green-500\",\n      },\n      {\n        name: \"Comments\",\n        icon: \"check\",\n        iconColor: \"text-orange-500\",\n      },\n      {\n        name: \"Notifications\",\n        icon: \"check\",\n        iconColor: \"text-teal-500\",\n      },\n      {\n        name: \"Text Editor\",\n        icon: \"check\",\n        iconColor: \"text-blue-500\",\n      },\n      {\n        name: \"Sync Datastore\",\n        icon: \"check\",\n        iconColor: \"text-zinc-500\",\n      },\n    ],\n  },\n  {\n    id: \"enterprise\",\n    title: \"Enterprise\",\n    description:\n      \"For organizations that need more support and compliance features.\",\n    currency: \"$\",\n    monthlyPrice: \"Custom\",\n    yearlyPrice: \"Custom\",\n    buttonText: \"Contact sales\",\n    features: [\n      {\n        name: \"Presence\",\n        icon: \"check\",\n        iconColor: \"text-green-500\",\n      },\n      {\n        name: \"Comments\",\n        icon: \"check\",\n        iconColor: \"text-orange-500\",\n      },\n      {\n        name: \"Notifications\",\n        icon: \"check\",\n        iconColor: \"text-teal-500\",\n      },\n      {\n        name: \"Text Editor\",\n        icon: \"check\",\n        iconColor: \"text-blue-500\",\n      },\n      {\n        name: \"Sync Datastore\",\n        icon: \"check\",\n        iconColor: \"text-zinc-500\",\n      },\n    ],\n  },\n];\n",
      "type": "registry:lib",
      "target": "lib/billingsdk-config.ts"
    }
  ],
  "type": "registry:block"
}
