{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "receipt-printer",
  "title": "Receipt Printer",
  "description": "A tactile checkout printer with processing stages and a composable thermal-paper receipt.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/base/ui/receipt-printer.tsx",
      "content": "\"use client\"\n\nimport { CheckIcon, LoaderCircleIcon } from \"lucide-react\"\nimport { motion, useReducedMotion } from \"motion/react\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport type ReceiptPrinterStage = \"processing\" | \"printing\" | \"complete\"\n\nconst ReceiptPrinterContext =\n  React.createContext<ReceiptPrinterStage>(\"complete\")\n\ntype RootProps = React.ComponentProps<\"section\"> & {\n  stage?: ReceiptPrinterStage\n}\n\nconst receiptToothDepth = 5\nconst receiptTeeth = Array.from({ length: 80 }, (_, index) => {\n  const x = 100 - ((index + 1) * 100) / 80\n  const y = index % 2 === 0 ? \"100%\" : `calc(100% - ${receiptToothDepth}px)`\n  return `${x}% ${y}`\n}).join(\", \")\nconst receiptEdge = `polygon(0 0, 100% 0, 100% calc(100% - ${receiptToothDepth}px), ${receiptTeeth})`\n\nfunction ReceiptPrinterRoot({\n  className,\n  stage = \"complete\",\n  ...props\n}: RootProps) {\n  return (\n    <ReceiptPrinterContext.Provider value={stage}>\n      <section\n        data-slot=\"receipt-printer\"\n        data-stage={stage}\n        className={cn(\n          \"group/receipt-printer flex w-full max-w-sm flex-col items-center\",\n          className\n        )}\n        {...props}\n      />\n    </ReceiptPrinterContext.Provider>\n  )\n}\n\nfunction ReceiptPrinterMachine({\n  children,\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"receipt-printer-machine\"\n      className={cn(\n        \"relative z-10 w-full overflow-visible rounded-[1.6rem] border border-white/15 bg-[#292825] p-3 pb-8 shadow-[0_22px_38px_-24px_rgba(0,0,0,.8),inset_0_1px_0_rgba(255,255,255,.14),inset_0_-3px_0_rgba(0,0,0,.3)] before:absolute before:inset-0 before:z-0 before:rounded-[inherit] before:bg-[radial-gradient(rgba(255,255,255,.09)_1px,transparent_1px)] before:bg-[size:4px_4px] before:opacity-35 before:content-['']\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute inset-x-6 bottom-3 z-30 h-2 rounded-[0.25rem] border border-black/80 bg-[#11110f] shadow-[inset_0_1px_2px_rgba(0,0,0,.95),0_1px_0_rgba(255,255,255,.12)]\"\n      >\n        <div className=\"mx-1 h-px bg-white/10\" />\n      </div>\n    </div>\n  )\n}\n\nfunction ReceiptPrinterHeader({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"receipt-printer-header\"\n      className={cn(\n        \"relative z-10 flex h-10 items-start justify-between px-1\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ReceiptPrinterStatus({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"receipt-printer-status\"\n      className={cn(\n        \"flex items-center gap-2 text-[11px] font-medium text-stone-300\",\n        className\n      )}\n      {...props}\n    >\n      <span className=\"grid size-4 place-items-center rounded-full bg-emerald-400 text-emerald-950 group-data-[stage=printing]/receipt-printer:bg-sky-300 group-data-[stage=processing]/receipt-printer:bg-amber-300\">\n        <CheckIcon\n          className=\"size-3 group-data-[stage=printing]/receipt-printer:hidden group-data-[stage=processing]/receipt-printer:hidden\"\n          strokeWidth={3}\n        />\n        <LoaderCircleIcon\n          className=\"hidden size-3 animate-spin group-data-[stage=printing]/receipt-printer:block group-data-[stage=processing]/receipt-printer:block motion-reduce:animate-none\"\n          strokeWidth={3}\n        />\n      </span>\n      <span>{children ?? \"Payment approved\"}</span>\n    </div>\n  )\n}\n\nfunction ReceiptPrinterScreen({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"receipt-printer-screen\"\n      className={cn(\n        \"relative z-10 rounded-xl border border-black/60 bg-[#151514] px-4 py-3 font-mono text-[10px] tracking-[.12em] text-[#c7e6ad] shadow-inner\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ReceiptPrinterOutput({\n  children,\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  const stage = React.useContext(ReceiptPrinterContext)\n  const shouldReduceMotion = useReducedMotion()\n  const isPrinting = stage === \"printing\" && !shouldReduceMotion\n\n  return (\n    <div\n      data-slot=\"receipt-printer-output\"\n      className={cn(\n        \"relative z-20 -mt-4 w-[84%] overflow-hidden px-2 pt-0\",\n        className\n      )}\n      {...props}\n    >\n      <motion.div\n        animate={{\n          y: isPrinting\n            ? [\n                \"-96%\",\n                \"-82%\",\n                \"-82%\",\n                \"-67%\",\n                \"-67%\",\n                \"-49%\",\n                \"-49%\",\n                \"-29%\",\n                \"-29%\",\n                \"-12%\",\n                \"0%\",\n              ]\n            : stage === \"processing\"\n              ? \"-96%\"\n              : \"0%\",\n        }}\n        initial={{\n          y: stage === \"printing\" ? \"-96%\" : \"0%\",\n        }}\n        transition={{\n          duration: isPrinting ? 2.4 : 0,\n          ease: isPrinting ? \"linear\" : \"easeOut\",\n          times: isPrinting\n            ? [0, 0.11, 0.16, 0.27, 0.32, 0.45, 0.5, 0.64, 0.69, 0.84, 1]\n            : undefined,\n        }}\n      >\n        {children}\n      </motion.div>\n    </div>\n  )\n}\n\nfunction ReceiptPrinterPaper({\n  className,\n  style,\n  ...props\n}: React.ComponentProps<\"article\">) {\n  return (\n    <article\n      data-slot=\"receipt-printer-paper\"\n      className={cn(\n        \"relative bg-[#fffdf7] px-5 pt-6 pb-10 font-mono text-[#282722] shadow-[0_14px_20px_-12px_rgba(0,0,0,.5)] before:pointer-events-none before:absolute before:inset-x-0 before:top-0 before:z-10 before:h-8 before:bg-gradient-to-b before:from-black/20 before:to-transparent before:content-[''] dark:bg-[#f4f0e7]\",\n        className\n      )}\n      style={{ clipPath: receiptEdge, ...style }}\n      {...props}\n    />\n  )\n}\n\nexport {\n  ReceiptPrinterHeader,\n  ReceiptPrinterMachine,\n  ReceiptPrinterOutput,\n  ReceiptPrinterPaper,\n  ReceiptPrinterRoot,\n  ReceiptPrinterScreen,\n  ReceiptPrinterStatus,\n}\n\nexport const ReceiptPrinter = {\n  Root: ReceiptPrinterRoot,\n  Machine: ReceiptPrinterMachine,\n  Header: ReceiptPrinterHeader,\n  Screen: ReceiptPrinterScreen,\n  Status: ReceiptPrinterStatus,\n  Output: ReceiptPrinterOutput,\n  Paper: ReceiptPrinterPaper,\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}