{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "qr-code",
  "title": "Qr Code",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-vue/components/qr-code/QRCode.vue",
      "content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { computed, ref, watch } from 'vue'\n// @ts-expect-error -- qrcode ships no type declarations; consumers may install @types/qrcode optionally\nimport QRCodeLib from 'qrcode'\nimport { Loader2, RotateCcw, Check, ScanLine } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\n\nexport type QRCodeType = 'canvas' | 'svg'\nexport type QRCodeStatus = 'active' | 'expired' | 'loading' | 'scanned'\nexport type QRCodeErrorLevel = 'L' | 'M' | 'Q' | 'H'\n\nconst props = withDefaults(\n  defineProps<{\n    value: string\n    type?: QRCodeType\n    size?: number\n    color?: string\n    bgColor?: string\n    icon?: string\n    iconSize?: number | { width: number; height: number }\n    errorLevel?: QRCodeErrorLevel\n    bordered?: boolean\n    status?: QRCodeStatus\n    marginSize?: number\n    class?: HTMLAttributes['class']\n  }>(),\n  {\n    type: 'canvas',\n    size: 160,\n    color: '#000000',\n    bgColor: '#ffffff',\n    errorLevel: 'M',\n    bordered: true,\n    status: 'active',\n    marginSize: 0,\n  },\n)\n\nconst emit = defineEmits<{\n  refresh: []\n}>()\n\nconst qrDataUrl = ref('')\nconst qrSvg = ref('')\nconst isGenerating = ref(false)\n\nconst iconDimensions = computed(() => {\n  if (typeof props.iconSize === 'number') {\n    return { width: props.iconSize, height: props.iconSize }\n  }\n  return props.iconSize ?? { width: 40, height: 40 }\n})\n\nconst errorCorrectionLevel = computed(() => props.errorLevel)\n\nasync function generateQR() {\n  if (!props.value || props.status === 'loading') return\n\n  isGenerating.value = true\n  try {\n    const options = {\n      width: props.size,\n      margin: props.marginSize,\n      color: {\n        dark: props.color,\n        light: props.bgColor,\n      },\n      errorCorrectionLevel: errorCorrectionLevel.value,\n    }\n\n    if (props.type === 'svg') {\n      qrSvg.value = await QRCodeLib.toString(props.value, {\n        type: 'svg',\n        ...options,\n      })\n    } else {\n      qrDataUrl.value = await QRCodeLib.toDataURL(props.value, options)\n    }\n  } catch (e) {\n    console.error('QR Code generation failed:', e)\n  } finally {\n    isGenerating.value = false\n  }\n}\n\nwatch(\n  () => [\n    props.value,\n    props.type,\n    props.size,\n    props.color,\n    props.bgColor,\n    props.errorLevel,\n    props.marginSize,\n    props.status,\n  ],\n  () => generateQR(),\n  { immediate: true },\n)\n\nfunction downloadQR() {\n  const link = document.createElement('a')\n  link.download = `qrcode-${props.value.slice(0, 20)}.png`\n  link.href = qrDataUrl.value\n  link.click()\n}\n\nfunction handleRefresh() {\n  emit('refresh')\n}\n\nconst statusOverlay = computed(() => {\n  switch (props.status) {\n    case 'expired':\n      return {\n        icon: RotateCcw,\n        text: 'Expired',\n        action: handleRefresh,\n      }\n    case 'scanned':\n      return {\n        icon: Check,\n        text: 'Scanned',\n        action: null,\n      }\n    case 'loading':\n      return {\n        icon: Loader2,\n        text: 'Loading...',\n        action: null,\n      }\n    default:\n      return null\n  }\n})\n</script>\n\n<template>\n  <div\n    data-uipkge\n    data-slot=\"qr-code\"\n    :class=\"\n      cn('inline-flex flex-col items-center gap-2', bordered && 'bg-background rounded-lg border p-4', props.class)\n    \"\n  >\n    <div\n      class=\"relative inline-flex items-center justify-center overflow-hidden\"\n      :style=\"{ width: `${size}px`, height: `${size}px` }\"\n    >\n      <!-- QR Code -->\n      <template v-if=\"type === 'svg' && qrSvg\">\n        <div v-html=\"qrSvg\" class=\"size-full\" />\n      </template>\n      <template v-else-if=\"qrDataUrl\">\n        <img :src=\"qrDataUrl\" :alt=\"`QR Code for ${value}`\" class=\"size-full\" />\n      </template>\n\n      <!-- Icon overlay -->\n      <div v-if=\"icon && status === 'active'\" class=\"absolute inset-0 flex items-center justify-center\">\n        <div\n          class=\"overflow-hidden rounded-md bg-white shadow-sm\"\n          :style=\"{\n            width: `${iconDimensions.width}px`,\n            height: `${iconDimensions.height}px`,\n          }\"\n        >\n          <img :src=\"icon\" alt=\"\" class=\"size-full object-cover\" />\n        </div>\n      </div>\n\n      <!-- Status overlay -->\n      <div\n        v-if=\"statusOverlay\"\n        class=\"absolute inset-0 flex flex-col items-center justify-center gap-2 bg-white/90 backdrop-blur-sm\"\n      >\n        <component :is=\"statusOverlay.icon\" class=\"size-8\" :class=\"status === 'loading' && 'animate-spin'\" />\n        <span class=\"text-foreground text-sm font-medium\">{{ statusOverlay.text }}</span>\n        <button\n          v-if=\"statusOverlay.action\"\n          type=\"button\"\n          class=\"bg-primary text-primary-foreground hover:bg-primary/90 focus-visible:ring-ring inline-flex items-center gap-1 rounded-md px-3 py-1 text-xs font-medium focus-visible:ring-2 focus-visible:outline-none\"\n          @click=\"statusOverlay.action\"\n        >\n          <ScanLine class=\"size-3\" />\n          Refresh\n        </button>\n      </div>\n    </div>\n\n    <!-- Download button -->\n    <slot name=\"extra\">\n      <button\n        v-if=\"type === 'canvas' && status === 'active' && qrDataUrl\"\n        type=\"button\"\n        class=\"text-muted-foreground hover:text-foreground focus-visible:ring-ring text-xs underline-offset-2 hover:underline focus-visible:ring-2 focus-visible:outline-none\"\n        @click=\"downloadQR\"\n      >\n        Download\n      </button>\n    </slot>\n  </div>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/qr-code/QRCode.vue"
    },
    {
      "path": "packages/registry-vue/components/qr-code/index.ts",
      "content": "export { default as QRCode } from './QRCode.vue'\nexport type { QRCodeType, QRCodeStatus, QRCodeErrorLevel } from './QRCode.vue'\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/qr-code/index.ts"
    }
  ],
  "dependencies": [
    "qrcode",
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Static QR code renderer — pass `value` and a size, get an SVG. Useful for sign-in links, share URLs, and Wi-Fi credentials. No dependencies on a heavy QR library.",
  "categories": [
    "data-display"
  ]
}