{"_id":"@alphinex/printing","_rev":"3-81f754222678ac607e2512cb03331dec","name":"@alphinex/printing","dist-tags":{"latest":"1.1.1"},"versions":{"1.0.0":{"name":"@alphinex/printing","version":"1.0.0","license":"UNLICENSED","_id":"@alphinex/printing@1.0.0","maintainers":[{"name":"anasaliqureshi","email":"anas@alphinex.com"}],"dist":{"shasum":"d04ede37cf6d841da738ea892e41a5270e1f0ffe","tarball":"https://registry.npmjs.org/@alphinex/printing/-/printing-1.0.0.tgz","fileCount":5,"integrity":"sha512-wXRxQnGqCn13/uWQHGGWQc37D2xzDXmAzQIvj/Rm7FK5N5Dhmid2pswygD0PACiA3U5EKXB1h8Gti5YP8bxvtQ==","signatures":[{"sig":"MEQCIAbtXERiAN6IdycBfX7cekRlieg7WH4N3/z7Vf5WM6CPAiBKDCQnsx0sSY6sezuN9wDEVhh5+MQf/bmAA7dE9l4WCA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":16697},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"private":false,"scripts":{"dev":"vite build --watch","lint":"eslint .","test":"vitest run","build":"vite build","clean":"rimraf dist .turbo","typecheck":"tsc --noEmit"},"_npmUser":{"name":"anasaliqureshi","email":"anas@alphinex.com"},"description":"Thermal (58mm/80mm) and A4 print rendering, barcode/QR generation, and the usePrint() hook. See ADR-0008.","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","dependencies":{"jsbarcode":"^3.12.3","@alphinex/core":"1.0.0","@alphinex/theme":"1.1.0","@alphinex/utils":"1.0.0","qrcode-generator":"^2.0.4"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.5","jsdom":"^25.0.1","react":"^19.0.0","eslint":"^9.17.0","vitest":"^2.1.8","react-dom":"^19.0.0","typescript":"^5.7.2","@types/react":"^19.0.2","@types/jsbarcode":"^3.11.4","@types/react-dom":"^19.0.2","@vitejs/plugin-react":"^4.3.4","@alphinex/build-config":"0.0.0","@testing-library/react":"^16.1.0","@alphinex/eslint-config":"0.0.0","@testing-library/jest-dom":"^6.6.3","@alphinex/typescript-config":"0.0.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"peerDependenciesMeta":{"react":{"optional":false},"react-dom":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/printing_1.0.0_1785893598306_0.3436385666738637","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@alphinex/printing","version":"1.1.0","license":"UNLICENSED","_id":"@alphinex/printing@1.1.0","maintainers":[{"name":"anasaliqureshi","email":"anas@alphinex.com"}],"dist":{"shasum":"32bde25954169ce50ef8d2c03c5cbe8de186ea42","tarball":"https://registry.npmjs.org/@alphinex/printing/-/printing-1.1.0.tgz","fileCount":5,"integrity":"sha512-XIOJ+ElETitCVoHUnjeC6R37EGamr2Y+M1g+h32FeWfTCkiwE9vl+Zm2PwzXrp5AKfcpP85OVe25BtysGBHNZw==","signatures":[{"sig":"MEUCIQDcgWVKLwJxozwQqd7+qJjCRH9k7Im+76YK9GGZe7bt8wIgagPyxvaSHD9KnvYx+Ogx5PhOygT/Ykr5EYq4MznnSRc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":44502},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"private":false,"scripts":{"dev":"vite build --watch","lint":"eslint .","test":"vitest run","build":"vite build","clean":"rimraf dist .turbo","typecheck":"tsc --noEmit"},"_npmUser":{"name":"anasaliqureshi","email":"anas@alphinex.com"},"description":"Thermal (58mm/80mm) and A4 print rendering, barcode/QR generation, and the usePrint() hook. See ADR-0008.","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","dependencies":{"jsbarcode":"^3.12.3","@alphinex/core":"1.0.0","@alphinex/theme":"1.1.0","@alphinex/utils":"1.0.0","qrcode-generator":"^2.0.4"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.5","jsdom":"^25.0.1","react":"^19.0.0","eslint":"^9.17.0","vitest":"^2.1.8","react-dom":"^19.0.0","typescript":"^5.7.2","@types/react":"^19.0.2","@types/jsbarcode":"^3.11.4","@types/react-dom":"^19.0.2","@types/w3c-web-usb":"^1.0.14","@vitejs/plugin-react":"^4.3.4","@types/w3c-web-serial":"^1.0.8","@alphinex/build-config":"0.0.0","@testing-library/react":"^16.1.0","@alphinex/eslint-config":"0.0.0","@testing-library/jest-dom":"^6.6.3","@alphinex/typescript-config":"0.0.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"peerDependenciesMeta":{"react":{"optional":false},"react-dom":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/printing_1.1.0_1785944578780_0.776664277944692","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@alphinex/printing","version":"1.1.1","private":false,"description":"Thermal (58mm/80mm) and A4 print rendering, barcode/QR generation, and the usePrint() hook. See ADR-0008.","license":"UNLICENSED","type":"module","sideEffects":false,"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"dependencies":{"jsbarcode":"^3.12.3","qrcode-generator":"^2.0.4","@alphinex/core":"1.0.0","@alphinex/utils":"1.1.0","@alphinex/theme":"1.1.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"peerDependenciesMeta":{"react":{"optional":false},"react-dom":{"optional":false}},"devDependencies":{"typescript":"^5.7.2","vite":"^6.0.5","vitest":"^2.1.8","react":"^19.0.0","react-dom":"^19.0.0","@types/react":"^19.0.2","@types/react-dom":"^19.0.2","@testing-library/react":"^16.1.0","@testing-library/jest-dom":"^6.6.3","@vitejs/plugin-react":"^4.3.4","jsdom":"^25.0.1","eslint":"^9.17.0","@types/jsbarcode":"^3.11.4","@types/w3c-web-usb":"^1.0.14","@types/w3c-web-serial":"^1.0.8","@alphinex/build-config":"0.0.0","@alphinex/eslint-config":"0.0.0","@alphinex/typescript-config":"0.0.0"},"scripts":{"build":"vite build","dev":"vite build --watch","lint":"eslint .","typecheck":"tsc --noEmit","test":"vitest run","clean":"rimraf dist .turbo"},"_nodeVersion":"22.14.0","_id":"@alphinex/printing@1.1.1","dist":{"integrity":"sha512-NW4XkaNhqJvtUe/g2icoLNR7+TcmRDTuDb5cI+g3Oyv+tqCxzmzOtjLYausWDbeVwCzcxMD5A1QUc2doqab7Tw==","shasum":"ee6461412795219cadb4757766f48680268e0e62","tarball":"https://registry.npmjs.org/@alphinex/printing/-/printing-1.1.1.tgz","fileCount":5,"unpackedSize":44502,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGAvZCucZtztx7JSECxy9M+GruMo87rcQNUXeIRdS8kSAiEA4z9aW4SRjbZCcYWonk9qoarQJJbw5NWFAHiU+DpdaI4="}]},"_npmUser":{"name":"anasaliqureshi","email":"anas@alphinex.com"},"directories":{},"maintainers":[{"name":"anasaliqureshi","email":"anas@alphinex.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/printing_1.1.1_1786525496912_0.9758875372806752"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-05T01:33:18.118Z","modified":"2026-08-12T09:04:57.234Z","1.0.0":"2026-08-05T01:33:18.447Z","1.1.0":"2026-08-05T15:42:58.917Z","1.1.1":"2026-08-12T09:04:57.057Z"},"license":"UNLICENSED","description":"Thermal (58mm/80mm) and A4 print rendering, barcode/QR generation, and the usePrint() hook. See ADR-0008.","maintainers":[{"name":"anasaliqureshi","email":"anas@alphinex.com"}],"readme":"# @alphinex/printing\n\nThermal (58mm/80mm) and A4 print rendering, barcode/QR generation, the `usePrint()` hook, and\ndirect ESC/POS hardware printing over WebUSB/Web Serial.\n\n## `<PrintFrame>` + `usePrint()`\n\n```tsx\nimport { PrintFrame, usePrint } from \"@alphinex/printing\";\n\nfunction InvoicePrintButton({\n  invoiceNumber,\n  children,\n}: {\n  invoiceNumber: string;\n  children: React.ReactNode;\n}) {\n  const { print } = usePrint({ documentTitle: `Invoice-${invoiceNumber}` });\n  return (\n    <>\n      <button onClick={print}>Print</button>\n      <PrintFrame paperSize=\"a4\">{children}</PrintFrame>\n    </>\n  );\n}\n```\n\n`<PrintFrame>` hides everything else on the page under `@media print` and sizes the `@page` box\nto `paperSize` (`\"a4\"` | `\"80mm\"` | `\"58mm\"`). `usePrint()` just triggers `window.print()` and\noptionally swaps `document.title` for the print job's default filename.\n\n**Known constraint:** the visibility rule is class-based (`.aui-print-frame`), not scoped per\ninstance. If more than one `<PrintFrame>`/`<PrintLayout>` is mounted at the same time, printing\nwill make _all_ of them visible at once, overlapping. Only mount one active print frame at a\ntime (e.g. behind a tab/toggle for \"which document is currently the print target\").\n\n## `<Barcode>` / `<QRCode>`\n\n```tsx\nimport { Barcode, QRCode } from \"@alphinex/printing\";\n\n<Barcode value=\"4006381333931\" format=\"EAN13\" />;\n<QRCode value=\"https://alphinex.example/invoice/1042\" size={96} />;\n```\n\nBoth render pure SVG (no canvas/raster assets) via `jsbarcode`/`qrcode-generator` — see\n[ADR-0008](../../documentation/adr/0008-adopt-jsbarcode-qrcode-generator.md) for why those two\nlibraries were chosen.\n\n## Direct hardware printing: `EscPosBuilder` + `useThermalPrinter`\n\nA second, independent printing path from `<PrintFrame>`/`usePrint()` — direct byte-level ESC/POS\noutput to real thermal-printer hardware, for receipts needing a cut command, cash-drawer kick, or\nnarrower control than a full-page browser print gives you.\n\n```tsx\nimport {\n  EscPosBuilder,\n  MockTransport,\n  useThermalPrinter,\n  WebUSBTransport,\n} from \"@alphinex/printing\";\nimport { useMemo } from \"react\";\n\nfunction ReceiptPrintButton() {\n  // Swap MockTransport for WebUSBTransport/WebSerialTransport against real hardware.\n  const transport = useMemo(() => new WebUSBTransport({ vendorId: 0x04b8 }), []);\n  const printer = useThermalPrinter({ transport });\n\n  const printReceipt = async () => {\n    if (printer.status !== \"connected\") {\n      await printer.connect();\n    }\n    const bytes = new EscPosBuilder()\n      .initialize()\n      .align(\"center\")\n      .bold(true)\n      .line(\"RECEIPT\")\n      .bold(false)\n      .align(\"left\")\n      .line(\"1x Widget — $9.99\")\n      .feed(2)\n      .cut()\n      .build();\n    await printer.print(bytes);\n  };\n\n  return <button onClick={printReceipt}>Print receipt</button>;\n}\n```\n\n`WebUSBTransport`/`WebSerialTransport`/`MockTransport` all implement the same\n`ThermalPrinterTransport` interface (`connect`/`write`/`disconnect`), so `useThermalPrinter`\nnever branches on which one is in use — use `MockTransport` in your own tests and demos.\n\n**Important — hardware verification gap:** `WebUSBTransport` and `WebSerialTransport` are\nimplemented against the published WebUSB/Web Serial specs and unit-tested for the exact API call\nsequence and bytes written, but **have not been verified against real thermal-printer hardware**\nin this environment (no physical device available). Test against your actual printer before\nshipping — see [ADR-0014](../../documentation/adr/0014-hand-roll-escpos-webusb-webserial.md) for\nthe full rationale and the trigger for closing this gap. WebUSB/Web Serial themselves are\nChromium-only browser APIs (not Firefox/Safari as of this writing).\n\n`EscPosBuilder`'s `text()` encodes via `TextEncoder` (UTF-8) — it does not select or convert to a\nprinter-specific codepage. ASCII text prints correctly on any codepage; non-ASCII characters may\nnot render as expected depending on the printer's default codepage.\n\nSee [documentation/PRODUCT-RESEARCH-MASTER-PLAN.md](../../documentation/PRODUCT-RESEARCH-MASTER-PLAN.md)\n§8.3 for the full package contract.\n","readmeFilename":""}