{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cart-shipping-bar",
  "type": "registry:component",
  "title": "Free shipping bar",
  "description": "Progress toward a free-shipping threshold that computes the remainder and flips to a confirmation.",
  "author": "StoreKit <hello@storekit.dev>",
  "categories": [
    "cart",
    "any"
  ],
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://storekit-eight.vercel.app/r/cn.json"
  ],
  "files": [
    {
      "path": "cart/cart-shipping-bar.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"motion/react\"\nimport { Check, Truck } from \"lucide-react\"\nimport { cn, money } from \"@/components/storekit/lib/cn\"\n\n/* Free-shipping meter. Computes the remainder against a threshold, fills a\n   bar (scaleX, so only transform animates) and flips to the savings color with\n   a confirmation once the threshold is reached. */\n\nexport function CartShippingBar({\n  subtotal = 5200,\n  threshold = 7500,\n  className,\n}: {\n  /** Cart subtotal in cents. */\n  subtotal?: number\n  /** Free-shipping threshold in cents. */\n  threshold?: number\n  className?: string\n}) {\n  const reduce = useReducedMotion()\n  const remaining = Math.max(0, threshold - subtotal)\n  const unlocked = remaining === 0\n  const pct = Math.min(1, subtotal / threshold)\n  return (\n    <div data-sk-section=\"cart\" data-sk-variant=\"cart-shipping-bar\" className={cn(\"w-full\", className)}>\n      <div className=\"flex items-center justify-between gap-3\">\n        <p className=\"flex items-center gap-2 text-sm text-sk-ink\" aria-live=\"polite\">\n          <span\n            className={cn(\n              \"grid h-7 w-7 place-items-center rounded-full transition-colors duration-300\",\n              unlocked ? \"bg-sk-savings/15 text-sk-savings\" : \"bg-sk-ink/[0.06] text-sk-muted\"\n            )}\n          >\n            {unlocked ? <Check size={14} /> : <Truck size={14} />}\n          </span>\n          {unlocked ? (\n            <span className=\"font-medium text-sk-savings\">Free shipping unlocked</span>\n          ) : (\n            <span>\n              You are <span className=\"font-semibold tabular-nums\">{money(remaining)}</span> away from free shipping\n            </span>\n          )}\n        </p>\n        <span className=\"hidden font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted tabular-nums sm:inline\">\n          {money(threshold)}\n        </span>\n      </div>\n      <div\n        className=\"mt-3 h-1.5 overflow-hidden rounded-full bg-sk-ink/[0.08]\"\n        role=\"progressbar\"\n        aria-label=\"Progress to free shipping\"\n        aria-valuemin={0}\n        aria-valuemax={threshold}\n        aria-valuenow={Math.min(subtotal, threshold)}\n      >\n        <motion.div\n          className={cn(\"h-full w-full origin-left rounded-full transition-colors duration-300\", unlocked ? \"bg-sk-savings\" : \"bg-sk-accent\")}\n          initial={false}\n          animate={{ scaleX: pct }}\n          transition={{ duration: reduce ? 0 : 0.5, ease: [0.16, 1, 0.3, 1] }}\n        />\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/storekit/cart/cart-shipping-bar.tsx"
    }
  ],
  "meta": {
    "section": "cart",
    "variant": "meter",
    "niche": [
      "any"
    ],
    "commerce": [
      "shipping-threshold"
    ],
    "previewHeight": 240
  }
}