{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "order-tracker",
  "type": "registry:component",
  "title": "Order Tracker",
  "description": "A shipment card with a live ETA, a step rail whose current stop gently pulses, carrier scans that slide in as they arrive, and a small spray of confetti when it lands.",
  "categories": [
    "component",
    "Commerce"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/devl/order-tracker.tsx",
      "type": "registry:component",
      "content": "\"use client\";\n\nimport { CheckIcon, ChevronDownIcon, CopyIcon, MapPinIcon, PackageCheckIcon, TruckIcon } from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface TrackerStep {\n  label: string;\n  date?: string;\n}\n\nexport interface CarrierEvent {\n  id: string;\n  time: string;\n  day?: string;\n  title: string;\n  location?: string;\n}\n\nexport interface OrderTrackerProps {\n  orderId: string;\n  carrier: string;\n  trackingNumber?: string;\n  steps: TrackerStep[];\n  current: number;\n  eta: { title: string; detail?: string };\n  delivered?: { title: string; detail?: string };\n  events: CarrierEvent[];\n  visibleEvents?: number;\n  className?: string;\n}\n\nexport function OrderTracker({\n  orderId,\n  carrier,\n  trackingNumber,\n  steps,\n  current,\n  eta,\n  delivered,\n  events,\n  visibleEvents = 3,\n  className,\n}: OrderTrackerProps) {\n  const reduce = useReducedMotion();\n  const [expanded, setExpanded] = useState(false);\n  const [copied, setCopied] = useState(false);\n  const [celebrate, setCelebrate] = useState(0);\n  const last = steps.length - 1;\n  const isDelivered = current >= last;\n  const prev = useRef(current);\n  const copyTimer = useRef<number>(undefined);\n\n  useEffect(() => {\n    if (current >= last && prev.current < last) setCelebrate((n) => n + 1);\n    prev.current = current;\n  }, [current, last]);\n  useEffect(() => () => clearTimeout(copyTimer.current), []);\n\n  const copy = async () => {\n    if (!trackingNumber) return;\n    try {\n      await navigator.clipboard.writeText(trackingNumber);\n    } catch {}\n    setCopied(true);\n    clearTimeout(copyTimer.current);\n    copyTimer.current = window.setTimeout(() => setCopied(false), 1400);\n  };\n\n  const ease = [0.23, 1, 0.32, 1] as const;\n  const head = isDelivered && delivered ? delivered : eta;\n  const shown = expanded ? events : events.slice(0, visibleEvents);\n  const progress = Math.min(1, current / Math.max(1, last));\n\n  return (\n    <div className={cn(\"w-full max-w-[400px] rounded-2xl border bg-card text-card-foreground shadow-xs/5\", className)}>\n      <div className=\"flex items-center justify-between gap-3 border-b px-4 py-3\">\n        <div className=\"min-w-0\">\n          <p className=\"font-medium text-sm\">Order {orderId}</p>\n          <p className=\"truncate text-muted-foreground text-xs\">\n            {carrier}\n            {trackingNumber && (\n              <>\n                {\" · \"}\n                <span className=\"font-mono\">{trackingNumber}</span>\n              </>\n            )}\n          </p>\n        </div>\n        {trackingNumber && (\n          <button\n            aria-label={copied ? \"Tracking number copied\" : \"Copy tracking number\"}\n            className=\"flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-lg text-muted-foreground outline-none transition-[background-color,color,scale] hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring active:scale-[0.97]\"\n            onClick={copy}\n            type=\"button\"\n          >\n            <AnimatePresence initial={false} mode=\"popLayout\">\n              <motion.span\n                animate={{ opacity: 1, scale: 1 }}\n                exit={{ opacity: 0, scale: 0.6 }}\n                initial={{ opacity: 0, scale: 0.6 }}\n                key={copied ? \"y\" : \"n\"}\n                transition={{ duration: 0.15 }}\n              >\n                {copied ? <CheckIcon className=\"size-4 text-success\" /> : <CopyIcon className=\"size-3.5\" />}\n              </motion.span>\n            </AnimatePresence>\n          </button>\n        )}\n      </div>\n\n      <div className=\"px-4 pt-4\">\n        <div className=\"flex items-start gap-3\">\n          <span\n            className={cn(\n              \"flex size-10 shrink-0 items-center justify-center rounded-xl transition-colors duration-300\",\n              isDelivered ? \"bg-success/12 text-success-foreground\" : \"bg-info/10 text-info-foreground\",\n            )}\n          >\n            <AnimatePresence initial={false} mode=\"popLayout\">\n              <motion.span\n                animate={{ opacity: 1, scale: 1, rotate: 0 }}\n                exit={{ opacity: 0, scale: 0.7 }}\n                initial={reduce ? { opacity: 0 } : { opacity: 0, scale: 0.7, rotate: -8 }}\n                key={isDelivered ? \"done\" : \"truck\"}\n                transition={{ duration: 0.24, ease }}\n              >\n                {isDelivered ? <PackageCheckIcon className=\"size-5\" /> : <TruckIcon className=\"size-5\" />}\n              </motion.span>\n            </AnimatePresence>\n          </span>\n          <div className=\"relative min-w-0 flex-1\">\n            <AnimatePresence initial={false} mode=\"popLayout\">\n              <motion.div\n                animate={{ opacity: 1, y: 0, filter: \"blur(0px)\" }}\n                exit={reduce ? { opacity: 0 } : { opacity: 0, y: -6, filter: \"blur(2px)\" }}\n                initial={reduce ? { opacity: 0 } : { opacity: 0, y: 6, filter: \"blur(2px)\" }}\n                key={head.title}\n                transition={{ duration: 0.24, ease }}\n              >\n                <p aria-live=\"polite\" className=\"text-balance font-semibold text-lg leading-tight\">\n                  {head.title}\n                </p>\n                {head.detail && <p className=\"mt-0.5 text-muted-foreground text-sm tabular-nums\">{head.detail}</p>}\n              </motion.div>\n            </AnimatePresence>\n          </div>\n        </div>\n\n        <ol aria-label=\"Shipment progress\" className=\"relative mt-5 grid\" style={{ gridTemplateColumns: `repeat(${steps.length}, minmax(0, 1fr))` }}>\n          <div aria-hidden className=\"absolute top-[9px] h-0.5 rounded-full bg-border\" style={{ left: `${50 / steps.length}%`, right: `${50 / steps.length}%` }}>\n            <motion.div\n              animate={{ scaleX: progress }}\n              className={cn(\"h-full origin-left rounded-full transition-colors duration-300\", isDelivered ? \"bg-success\" : \"bg-primary\")}\n              initial={false}\n              transition={reduce ? { duration: 0 } : { type: \"spring\", stiffness: 140, damping: 24 }}\n            />\n          </div>\n          {steps.map((s, i) => {\n            const done = i < current || isDelivered;\n            const active = i === current && !isDelivered;\n            return (\n              <li aria-current={active ? \"step\" : undefined} className=\"relative flex flex-col items-center text-center\" key={s.label}>\n                <span className=\"relative flex size-5 items-center justify-center\">\n                  {active && (\n                    <motion.span\n                      animate={reduce ? { opacity: 0 } : { scale: [1, 2.1], opacity: [0.35, 0] }}\n                      className=\"absolute inset-0 rounded-full bg-info opacity-0\"\n                      transition={reduce ? { duration: 0 } : { duration: 1.8, repeat: Number.POSITIVE_INFINITY, ease: \"easeOut\" }}\n                    />\n                  )}\n                  <motion.span\n                    animate={{ scale: 1 }}\n                    className={cn(\n                      \"relative flex size-5 items-center justify-center rounded-full border-2 transition-colors duration-300\",\n                      done && (isDelivered ? \"border-success bg-success text-white\" : \"border-primary bg-primary text-primary-foreground\"),\n                      active && \"border-info bg-card\",\n                      !done && !active && \"border-border bg-card\",\n                    )}\n                    initial={false}\n                  >\n                    {done ? (\n                      <svg aria-hidden className=\"size-3\" fill=\"none\" viewBox=\"0 0 12 12\">\n                        <motion.path\n                          animate={{ pathLength: 1 }}\n                          d=\"M2.5 6.2 5 8.5l4.5-5\"\n                          initial={{ pathLength: 0 }}\n                          stroke=\"currentColor\"\n                          strokeLinecap=\"round\"\n                          strokeLinejoin=\"round\"\n                          strokeWidth={1.8}\n                          transition={reduce ? { duration: 0 } : { duration: 0.3, ease: \"easeOut\", delay: 0.1 }}\n                        />\n                      </svg>\n                    ) : active ? (\n                      <span className=\"size-2 rounded-full bg-info\" />\n                    ) : null}\n                  </motion.span>\n                  {i === last && <Burst key={celebrate} run={celebrate > 0 && !reduce} />}\n                </span>\n                <span className={cn(\"mt-2 text-pretty font-medium text-xs leading-tight\", done || active ? \"text-foreground\" : \"text-muted-foreground\")}>{s.label}</span>\n                {s.date && <span className=\"mt-0.5 text-[11px] text-muted-foreground tabular-nums\">{s.date}</span>}\n              </li>\n            );\n          })}\n        </ol>\n      </div>\n\n      <div className=\"mt-4 border-t px-4 pt-3 pb-2\">\n        <p className=\"mb-1 font-medium text-muted-foreground text-xs\">Updates from {carrier}</p>\n        <ol className=\"relative -mx-1 px-1\">\n          <AnimatePresence initial={false}>\n            {shown.map((e, i) => (\n              <motion.li\n                animate={{ opacity: 1, height: \"auto\" }}\n                className=\"overflow-hidden\"\n                exit={{ opacity: 0, height: 0 }}\n                initial={reduce ? { opacity: 0, height: \"auto\" } : { opacity: 0, height: 0 }}\n                key={e.id}\n                layout={reduce ? false : \"position\"}\n                transition={{ duration: 0.28, ease }}\n              >\n                <div className=\"relative flex gap-3 py-2\">\n                  <span className=\"relative flex w-3 shrink-0 justify-center pt-1.5\">\n                    <span className={cn(\"relative z-10 size-2 rounded-full ring-4 ring-card\", i === 0 ? (isDelivered ? \"bg-success\" : \"bg-info\") : \"bg-muted-foreground/40\")} />\n                    {i < shown.length - 1 && <span className=\"absolute top-3.5 -bottom-3.5 w-px bg-border\" />}\n                  </span>\n                  <div className=\"min-w-0 flex-1\">\n                    <p className={cn(\"text-sm leading-snug\", i === 0 ? \"font-medium text-foreground\" : \"text-muted-foreground\")}>{e.title}</p>\n                    {e.location && (\n                      <p className=\"mt-0.5 flex items-center gap-1 text-muted-foreground text-xs\">\n                        <MapPinIcon className=\"size-3\" />\n                        {e.location}\n                      </p>\n                    )}\n                  </div>\n                  <span className=\"shrink-0 text-end text-muted-foreground text-xs tabular-nums\">\n                    {e.day && <span className=\"block\">{e.day}</span>}\n                    {e.time}\n                  </span>\n                </div>\n              </motion.li>\n            ))}\n          </AnimatePresence>\n        </ol>\n        {events.length > visibleEvents && (\n          <button\n            aria-expanded={expanded}\n            className=\"-mx-1.5 mt-0.5 flex h-8 cursor-pointer items-center gap-1 rounded-md px-1.5 font-medium text-muted-foreground text-xs outline-none transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring\"\n            onClick={() => setExpanded((v) => !v)}\n            type=\"button\"\n          >\n            {expanded ? \"Show fewer\" : `Show all ${events.length} updates`}\n            <ChevronDownIcon className={cn(\"size-3.5 transition-transform duration-200\", expanded && \"rotate-180\")} />\n          </button>\n        )}\n      </div>\n    </div>\n  );\n}\n\nfunction Burst({ run }: { run: boolean }) {\n  if (!run) return null;\n  const dots = Array.from({ length: 10 }, (_, i) => {\n    const angle = (i / 10) * Math.PI * 2 + 0.3;\n    const dist = 16 + (i % 3) * 5;\n    return { x: Math.cos(angle) * dist, y: Math.sin(angle) * dist, tone: [\"bg-success\", \"bg-amber-400\", \"bg-info\", \"bg-rose-400\"][i % 4] };\n  });\n  return (\n    <span aria-hidden className=\"pointer-events-none absolute inset-0\">\n      {dots.map((d, i) => (\n        <motion.span\n          animate={{ x: d.x, y: d.y, opacity: [0, 1, 0], scale: [0.6, 1, 0.4] }}\n          className={cn(\"absolute top-1/2 left-1/2 -mt-[2px] -ml-[2px] size-1 rounded-full\", d.tone)}\n          initial={{ x: 0, y: 0, opacity: 0 }}\n          key={i}\n          transition={{ duration: 0.6, ease: [0.23, 1, 0.32, 1], delay: 0.15 }}\n        />\n      ))}\n    </span>\n  );\n}\n"
    }
  ]
}