{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "credit-card-shadcnui",
  "type": "registry:component",
  "title": "Credit Card",
  "description": "3D animated credit card with flip animation to show CVV",
  "dependencies": [
    "framer-motion",
    "react"
  ],
  "files": [
    {
      "path": "@uitripled/react-shadcn/src/components/components/cards/shadcnui/credit-card.tsx",
      "content": "\"use client\";\n\nimport {\n  motion,\n  useMotionValue,\n  useReducedMotion,\n  useSpring,\n  useTransform,\n} from \"framer-motion\";\nimport { CreditCard as CreditCardIcon } from \"lucide-react\";\nimport { useMemo, useState } from \"react\";\ninterface CreditCardProps {\n  cardNumber?: string;\n  cardholderName?: string;\n  expiryDate?: string;\n  cvv?: string;\n}\n\nconst gradients = {\n  front:\n    \"linear-gradient(145deg, hsl(var(--primary) / 0.45), hsl(var(--primary) / 0.18))\",\n  back: \"linear-gradient(145deg, hsl(var(--primary) / 0.45), hsl(var(--primary) / 0.18))\",\n};\n\nconst overlayLights = [\n  \"radial-gradient(circle at 20% 30%, hsl(var(--foreground) / 0.12), transparent 55%)\",\n  \"radial-gradient(circle at 80% 20%, hsl(var(--primary) / 0.22), transparent 60%)\",\n  \"radial-gradient(circle at 50% 80%, hsl(var(--accent) / 0.28), transparent 65%)\",\n];\n\nexport function CreditCard({\n  cardNumber = \"4532 1234 5678 9010\",\n  cardholderName = \"JORDAN PARK\",\n  expiryDate = \"09/27\",\n  cvv = \"123\",\n}: CreditCardProps) {\n  const [isFlipped, setIsFlipped] = useState(false);\n\n  const x = useMotionValue(0);\n  const y = useMotionValue(0);\n\n  const rotateX = useSpring(useTransform(y, [-0.5, 0.5], [6, -6]), {\n    stiffness: 280,\n    damping: 28,\n  });\n  const rotateY = useSpring(useTransform(x, [-0.5, 0.5], [-6, 6]), {\n    stiffness: 280,\n    damping: 28,\n  });\n\n  const shouldReduceMotion = useReducedMotion();\n\n  const overlayGradient = useMemo(() => overlayLights.join(\",\"), []);\n\n  const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n    if (shouldReduceMotion) return;\n    const rect = event.currentTarget.getBoundingClientRect();\n    const width = rect.width;\n    const height = rect.height;\n    const mouseX = event.clientX - rect.left;\n    const mouseY = event.clientY - rect.top;\n    const xPct = mouseX / width - 0.5;\n    const yPct = mouseY / height - 0.5;\n    x.set(xPct);\n    y.set(yPct);\n  };\n\n  const handleMouseLeave = () => {\n    x.set(0);\n    y.set(0);\n  };\n\n  const formatCardNumber = (number: string) => {\n    return number.replace(/(.{4})/g, \"$1 \").trim();\n  };\n\n  return (\n    <div className=\"flex items-center justify-center p-8 perspective-1000\">\n      <motion.div\n        onMouseMove={handleMouseMove}\n        onMouseLeave={handleMouseLeave}\n        onClick={() => setIsFlipped(!isFlipped)}\n        className=\"relative h-[240px] w-[380px] cursor-pointer\"\n        style={{\n          rotateX,\n          rotateY,\n          transformStyle: \"preserve-3d\",\n        }}\n        whileHover={shouldReduceMotion ? undefined : { scale: 1.015 }}\n        transition={{ type: \"spring\", stiffness: 260, damping: 26 }}\n      >\n        <div className=\"absolute inset-0 rounded-[1.5rem] bg-foreground/10 blur-2xl\" />\n        {/* Front */}\n        <motion.div\n          className=\"absolute inset-0 flex flex-col justify-between rounded-[1.5rem] p-6 shadow-[0_22px_55px_-30px_rgba(15,23,42,0.75)]\"\n          style={{\n            background: gradients.front,\n            backfaceVisibility: \"hidden\",\n            WebkitBackfaceVisibility: \"hidden\",\n          }}\n          animate={{ rotateY: isFlipped ? 180 : 0 }}\n          transition={{ duration: 0.55, ease: \"easeInOut\" }}\n        >\n          <div\n            aria-hidden\n            className=\"pointer-events-none absolute inset-0 rounded-[1.5rem]\"\n            style={{\n              background: overlayGradient,\n              opacity: shouldReduceMotion ? 0.5 : 1,\n            }}\n          />\n          <div className=\"relative flex items-start justify-between\">\n            <div className=\"relative\">\n              <div className=\"flex h-12 w-14 items-center justify-center rounded-lg border border-border/60 bg-foreground/15 backdrop-blur\">\n                <div className=\"h-8 w-10 rounded-md border border-border/40 bg-background/60\" />\n              </div>\n              <div className=\"absolute -bottom-1 left-0 right-0 h-1 rounded-full bg-foreground/10\" />\n            </div>\n          </div>\n\n          <div className=\"relative space-y-2\">\n            <span className=\"text-[10px] uppercase tracking-[0.42em] text-muted-foreground/70\">\n              Card Number\n            </span>\n            <p className=\"font-mono text-2xl tracking-[0.4em] text-foreground/90\">\n              {formatCardNumber(cardNumber)}\n            </p>\n          </div>\n\n          <div className=\"relative flex items-end justify-between\">\n            <div className=\"space-y-1\">\n              <span className=\"text-[10px] uppercase tracking-[0.36em] text-muted-foreground/70\">\n                Cardholder\n              </span>\n              <p className=\"text-sm font-semibold uppercase tracking-[0.32em] text-foreground/85\">\n                {cardholderName}\n              </p>\n            </div>\n            <div className=\"space-y-1 text-right\">\n              <span className=\"text-[10px] uppercase tracking-[0.36em] text-muted-foreground/70\">\n                Expires\n              </span>\n              <p className=\"text-sm font-semibold text-foreground/85\">\n                {expiryDate}\n              </p>\n            </div>\n          </div>\n        </motion.div>\n\n        {/* Back */}\n        <motion.div\n          className=\"absolute inset-0 flex flex-col justify-between rounded-[1.5rem] p-6 shadow-[0_22px_55px_-30px_rgba(15,23,42,0.75)]\"\n          style={{\n            background: gradients.back,\n            backfaceVisibility: \"hidden\",\n            WebkitBackfaceVisibility: \"hidden\",\n            rotateY: 180,\n          }}\n          animate={{ rotateY: isFlipped ? 0 : 180 }}\n          transition={{ duration: 0.55, ease: \"easeInOut\" }}\n        >\n          <div\n            aria-hidden\n            className=\"pointer-events-none absolute inset-0 rounded-[1.5rem]\"\n            style={{\n              background: overlayGradient,\n              opacity: shouldReduceMotion ? 0.5 : 0.9,\n            }}\n          />\n          <div\n            className=\"absolute left-0 right-0 top-8 h-12 rounded-sm bg-foreground/10\"\n            aria-hidden\n          />\n\n          <div className=\"relative mt-16 space-y-3\">\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-[10px] uppercase tracking-[0.32em] text-muted-foreground/70\">\n                CVV\n              </span>\n              <span className=\"flex min-w-[80px] items-center justify-center rounded-md border border-border/50 bg-muted px-3 py-1 font-mono text-lg font-semibold text-foreground shadow-[0_6px_18px_-12px_rgba(15,23,42,0.6)]\">\n                {cvv}\n              </span>\n            </div>\n            <p className=\"text-[10px] uppercase tracking-[0.32em] text-muted-foreground/60\">\n              Contact support if you notice unauthorized activity.\n            </p>\n          </div>\n\n          <div className=\"relative flex items-center justify-end\">\n            <CreditCardIcon\n              className=\"h-6 w-6 text-muted-foreground/70\"\n              aria-hidden\n            />\n          </div>\n        </motion.div>\n      </motion.div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/uitripled/credit-card-shadcnui.tsx"
    }
  ]
}