{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "vcard-qr-code",
  "type": "registry:component",
  "title": "vCard QR Code",
  "description": "A QR code that saves a contact card when scanned, with a typed vCard 3.0 builder.",
  "author": "bucharitesh <https://qrdx.dev>",
  "dependencies": ["qrdx"],
  "files": [
    {
      "path": "registry/qrdx/vcard-qr-code.tsx",
      "type": "registry:component",
      "content": "\"use client\";\n\nimport { QRCode } from \"qrdx\";\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\n/** qrdx style options: colors, gradients, patterns, logo, template. */\nexport type QrCodeStyle = Omit<ComponentProps<typeof QRCode>, \"value\" | \"size\">;\n\nexport interface VCardAddress {\n  street?: string;\n  city?: string;\n  region?: string;\n  postalCode?: string;\n  country?: string;\n}\n\nexport interface VCardContact {\n  firstName: string;\n  lastName?: string;\n  organization?: string;\n  /** Job title. */\n  title?: string;\n  /** Work phone, ideally in international format (+1 555 0100). */\n  phone?: string;\n  mobile?: string;\n  email?: string;\n  /** Website, including https://. */\n  url?: string;\n  address?: VCardAddress;\n  note?: string;\n}\n\n/** Escapes text for a vCard 3.0 value. */\nfunction escapeVCard(value: string) {\n  return value\n    .replace(/\\\\/g, \"\\\\\\\\\")\n    .replace(/\\r?\\n/g, \"\\\\n\")\n    .replace(/([,;])/g, \"\\\\$1\");\n}\n\n/**\n * Builds a vCard 3.0 that phone cameras offer to save as a contact.\n * Empty fields are left out to keep the code small.\n */\nexport function buildVCard(contact: VCardContact): string {\n  const {\n    firstName,\n    lastName = \"\",\n    organization,\n    title,\n    phone,\n    mobile,\n    email,\n    url,\n    address,\n    note,\n  } = contact;\n  const fullName = [firstName, lastName].filter(Boolean).join(\" \");\n  const lines = [\n    \"BEGIN:VCARD\",\n    \"VERSION:3.0\",\n    `N:${escapeVCard(lastName)};${escapeVCard(firstName)};;;`,\n    `FN:${escapeVCard(fullName)}`,\n  ];\n  if (organization) lines.push(`ORG:${escapeVCard(organization)}`);\n  if (title) lines.push(`TITLE:${escapeVCard(title)}`);\n  if (phone) lines.push(`TEL;TYPE=WORK,VOICE:${escapeVCard(phone)}`);\n  if (mobile) lines.push(`TEL;TYPE=CELL:${escapeVCard(mobile)}`);\n  if (email) lines.push(`EMAIL;TYPE=INTERNET:${escapeVCard(email)}`);\n  if (url) lines.push(`URL:${escapeVCard(url)}`);\n  if (address && Object.values(address).some(Boolean)) {\n    const { street, city, region, postalCode, country } = address;\n    const parts = [street, city, region, postalCode, country].map((part) =>\n      escapeVCard(part ?? \"\"),\n    );\n    lines.push(`ADR;TYPE=WORK:;;${parts.join(\";\")}`);\n  }\n  if (note) lines.push(`NOTE:${escapeVCard(note)}`);\n  lines.push(\"END:VCARD\");\n  return lines.join(\"\\r\\n\");\n}\n\nexport interface VCardQrCodeProps\n  extends Omit<ComponentProps<\"figure\">, \"children\"> {\n  /** The contact to encode. */\n  contact: VCardContact;\n  /**\n   * Width and height of the code in pixels.\n   * @default 200\n   */\n  size?: number;\n  /** qrdx style options for the code. */\n  qr?: QrCodeStyle;\n  /**\n   * Show the name and organization under the code.\n   * @default true\n   */\n  showDetails?: boolean;\n}\n\nexport function VCardQrCode({\n  contact,\n  size = 200,\n  qr,\n  showDetails = true,\n  className,\n  ...props\n}: VCardQrCodeProps) {\n  const name = [contact.firstName, contact.lastName].filter(Boolean).join(\" \");\n  const role = [contact.title, contact.organization].filter(Boolean).join(\", \");\n\n  return (\n    <figure\n      className={cn(\"inline-flex flex-col items-center gap-3\", className)}\n      data-slot=\"vcard-qr-code\"\n      {...props}\n    >\n      <div\n        aria-label={`QR code with the contact card for ${name}`}\n        className=\"overflow-hidden rounded-[10px] border\"\n        role=\"img\"\n        style={{ width: size, height: size }}\n      >\n        {/* vCards are long: level \"M\" keeps the modules large enough to scan. */}\n        <QRCode\n          level=\"M\"\n          margin={2}\n          {...qr}\n          size={size}\n          value={buildVCard(contact)}\n        />\n      </div>\n      {showDetails ? (\n        <figcaption className=\"flex flex-col items-center gap-0.5 text-center text-sm\">\n          <span className=\"font-medium\">{name}</span>\n          {role ? <span className=\"text-muted-foreground\">{role}</span> : null}\n        </figcaption>\n      ) : null}\n    </figure>\n  );\n}\n"
    }
  ],
  "docs": "Import it with `import { VCardQrCode } from \"@/components/vcard-qr-code\"`. Props and examples: https://qrdx.dev/docs/components/vcard-qr-code",
  "categories": ["qr-code"]
}
