{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "qr-code", "title": "QR Code", "description": "A beautiful QR code component with dot styling, gradient support, and extensive color customization.", "dependencies": [ "qrcode" ], "registryDependencies": [], "files": [ { "path": "registry/spark-ui/qr-code.tsx", "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport QRCodeLib from \"qrcode\";\nimport * as React from \"react\";\n\ntype GradientPreset =\n | \"default\"\n | \"ocean\"\n | \"sunset\"\n | \"forest\"\n | \"berry\"\n | \"twilight\"\n | \"aurora\"\n | \"fire\"\n | \"neon\"\n | \"rose\"\n | \"mint\";\n\nexport type { GradientPreset };\n\ninterface QRCodeProps extends React.SVGProps {\n /** The URL or data to encode in the QR code */\n value: string;\n /** Overall size of the QR code */\n size?: number;\n /** Foreground color (ignored if gradient is set) */\n fgColor?: string;\n /** Background color */\n bgColor?: string;\n /** Error correction level */\n errorCorrectionLevel?: \"L\" | \"M\" | \"Q\" | \"H\";\n /** Gradient preset to apply */\n gradient?: GradientPreset;\n /** Custom className for the SVG */\n className?: string;\n}\n\nconst gradients: Record = {\n default: [\"var(--foreground)\", \"var(--foreground)\"],\n ocean: [\"#06b6d4\", \"#3b82f6\"],\n sunset: [\"#f97316\", \"#ec4899\"],\n forest: [\"#22c55e\", \"#06b6d4\"],\n berry: [\"#8b5cf6\", \"#ec4899\"],\n twilight: [\"#6366f1\", \"#06b6d4\"],\n aurora: [\"#10b981\", \"#8b5cf6\"],\n fire: [\"#ef4444\", \"#f59e0b\"],\n neon: [\"#06b6d4\", \"#8b5cf6\"],\n rose: [\"#f43f5e\", \"#ec4899\"],\n mint: [\"#10b981\", \"#06b6d4\"],\n};\n\nfunction isInFinderPattern(row: number, col: number, size: number): boolean {\n return (\n (row < 7 && col < 7) ||\n (row < 7 && col >= size - 7) ||\n (row >= size - 7 && col < 7)\n );\n}\n\nexport function QRCode({\n value,\n size = 160,\n fgColor = \"var(--foreground)\",\n bgColor = \"var(--background)\",\n errorCorrectionLevel = \"M\",\n gradient = \"default\",\n className,\n ...props\n}: QRCodeProps) {\n const qrData = React.useMemo(() => {\n try {\n return QRCodeLib.create(value, { errorCorrectionLevel });\n } catch {\n return null;\n }\n }, [value, errorCorrectionLevel]);\n\n if (!qrData) {\n return null;\n }\n\n const moduleCount = qrData.modules.size;\n const moduleSize = size / moduleCount;\n const radius = moduleSize * 0.45;\n const gradientId = `qr-grad-${gradient}-${size}`;\n const [gradStart, gradEnd] = gradients[gradient];\n const useGradient = gradient !== \"default\";\n const effectiveColor = useGradient ? `url(#${gradientId})` : (gradient === \"default\" ? fgColor : gradStart);\n\n const finderPositions: [number, number][] = [\n [0, 0],\n [0, moduleCount - 7],\n [moduleCount - 7, 0],\n ];\n\n const finderOuterSize = 7 * moduleSize;\n const finderMiddleSize = 3 * moduleSize;\n\n const dots: { cx: number; cy: number }[] = [];\n\n for (let row = 0; row < moduleCount; row++) {\n for (let col = 0; col < moduleCount; col++) {\n if (\n qrData.modules.get(row, col) &&\n !isInFinderPattern(row, col, moduleCount)\n ) {\n dots.push({\n cx: (col + 0.5) * moduleSize,\n cy: (row + 0.5) * moduleSize,\n });\n }\n }\n }\n\n return (\n \n \n {useGradient && (\n \n \n \n \n )}\n \n\n \n\n {finderPositions.map(([r, c], idx) => {\n const cx = c * moduleSize + finderOuterSize / 2;\n const cy = r * moduleSize + finderOuterSize / 2;\n const outerSize = finderOuterSize;\n const whiteSize = finderOuterSize - moduleSize * 1.5;\n const innerSize = finderMiddleSize;\n\n return (\n \n \n \n \n \n );\n })}\n\n {dots.map(({ cx, cy }, i) => (\n \n ))}\n \n );\n}\n\n", "type": "registry:component" } ], "type": "registry:component" }