{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "qr-code",
  "title": "Qr Code",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-svelte/components/qr-code/QRCode.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export type QRCodeType = 'canvas' | 'svg'\n  export type QRCodeStatus = 'active' | 'expired' | 'loading' | 'scanned'\n  export type QRCodeErrorLevel = 'L' | 'M' | 'Q' | 'H'\n\n  export interface QRCodeProps extends HTMLAttributes<HTMLDivElement> {\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    /** Replaces the default download button (parity with the Vue `extra` slot). */\n    extra?: Snippet\n    /** Fired when the expired overlay's Refresh button is clicked. */\n    onrefresh?: () => void\n    ref?: HTMLDivElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { toDataURL, toString as qrToString } from 'qrcode'\n  import { Check, Loader2, RotateCcw, ScanLine } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n\n  let {\n    class: className,\n    value,\n    type = 'canvas',\n    size = 160,\n    // qrcode requires resolvable hex/rgb — CSS vars like var(--foreground) throw.\n    color = '#000000',\n    bgColor = '#ffffff',\n    icon,\n    iconSize,\n    errorLevel = 'M',\n    bordered = true,\n    status = 'active',\n    marginSize = 0,\n    extra,\n    onrefresh,\n    ref = $bindable(null),\n    ...restProps\n  }: QRCodeProps = $props()\n\n  let qrDataUrl = $state('')\n  let qrSvg = $state('')\n\n  const iconDimensions = $derived(\n    typeof iconSize === 'number'\n      ? { width: iconSize, height: iconSize }\n      : (iconSize ?? { width: 40, height: 40 }),\n  )\n\n  async function generateQR() {\n    if (!value || status === 'loading') return\n\n    try {\n      const options = {\n        width: size,\n        margin: marginSize,\n        color: {\n          dark: color,\n          light: bgColor,\n        },\n        errorCorrectionLevel: errorLevel,\n      }\n\n      if (type === 'svg') {\n        qrSvg = await qrToString(value, {\n          type: 'svg',\n          ...options,\n        })\n      } else {\n        qrDataUrl = await toDataURL(value, options)\n      }\n    } catch (e) {\n      console.error('QR Code generation failed:', e)\n    }\n  }\n\n  // Regenerate whenever any input changes (parity with Vue's immediate watcher).\n  $effect(() => {\n    void generateQR()\n  })\n\n  function downloadQR() {\n    const link = document.createElement('a')\n    link.download = `qrcode-${value.slice(0, 20)}.png`\n    link.href = qrDataUrl\n    link.click()\n  }\n\n  const statusOverlay = $derived(\n    status === 'expired'\n      ? { Icon: RotateCcw, text: 'Expired', action: true }\n      : status === 'scanned'\n        ? { Icon: Check, text: 'Scanned', action: false }\n        : status === 'loading'\n          ? { Icon: Loader2, text: 'Loading...', action: false }\n          : null,\n  )\n</script>\n\n<div\n  {...restProps}\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"qr-code\"\n  aria-busy={status === 'loading' || undefined}\n  class={cn('inline-flex flex-col items-center gap-2', bordered && 'bg-background rounded-lg border p-4', className)}\n>\n  <div class=\"relative inline-flex items-center justify-center overflow-hidden\" style:width={`${size}px`} style:height={`${size}px`}>\n    <!-- QR Code -->\n    {#if type === 'svg' && qrSvg}\n      <div class=\"size-full\">{@html qrSvg}</div>\n    {:else if qrDataUrl}\n      <img src={qrDataUrl} alt={`QR Code for ${value}`} class=\"size-full\" />\n    {/if}\n\n    <!-- Icon overlay -->\n    {#if icon && status === 'active'}\n      <div class=\"absolute inset-0 flex items-center justify-center\">\n        <div\n          class=\"bg-background overflow-hidden rounded-md shadow-sm\"\n          style:width={`${iconDimensions.width}px`}\n          style:height={`${iconDimensions.height}px`}\n        >\n          <img src={icon} alt=\"\" class=\"size-full object-cover\" />\n        </div>\n      </div>\n    {/if}\n\n    <!-- Status overlay -->\n    {#if statusOverlay}\n      {@const StatusIcon = statusOverlay.Icon}\n      <div class=\"bg-background/90 absolute inset-0 flex flex-col items-center justify-center gap-2 backdrop-blur-sm\">\n        <StatusIcon class={cn('size-8', status === 'loading' && 'animate-spin')} />\n        <span class=\"text-foreground text-sm font-medium\">{statusOverlay.text}</span>\n        {#if statusOverlay.action}\n          <button\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            onclick={() => onrefresh?.()}\n          >\n            <ScanLine class=\"size-3\" />\n            Refresh\n          </button>\n        {/if}\n      </div>\n    {/if}\n  </div>\n\n  <!-- Download button -->\n  {#if extra}\n    {@render extra()}\n  {:else if type === 'canvas' && status === 'active' && qrDataUrl}\n    <button\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      onclick={downloadQR}\n    >\n      Download\n    </button>\n  {/if}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/qr-code/QRCode.svelte"
    },
    {
      "path": "packages/registry-svelte/components/qr-code/index.ts",
      "content": "export {\n  default as QrCode,\n  default as QRCode,\n  type QRCodeProps as QrCodeProps,\n  type QRCodeProps,\n} from './QRCode.svelte'\nexport type { QRCodeType, QRCodeStatus, QRCodeErrorLevel } from './QRCode.svelte'\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/qr-code/index.ts"
    }
  ],
  "dependencies": [
    "qrcode",
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "QR code renderer — pass `value` and a size, get a canvas PNG or SVG. Useful for sign-in links, share URLs, and Wi-Fi credentials. Depends on the `qrcode` package.",
  "categories": [
    "data-display"
  ]
}