{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cart-saved-later",
  "type": "registry:component",
  "title": "Saved for later",
  "description": "Cart with a saved-for-later list below it; lines move between the two and the subtotal only counts the cart.",
  "author": "StoreKit <hello@storekit.dev>",
  "categories": [
    "cart",
    "any"
  ],
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://storekit-eight.vercel.app/r/cn.json",
    "https://storekit-eight.vercel.app/r/product-image.json",
    "https://storekit-eight.vercel.app/r/sk-analytics.json"
  ],
  "files": [
    {
      "path": "cart/cart-saved-later.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\nimport { Bookmark, ShoppingBag, X } from \"lucide-react\"\nimport { cn, money } from \"@/components/storekit/lib/cn\"\nimport { ProductImage } from \"@/components/storekit/ui/product-image\"\nimport { useSkBlock } from \"@/components/storekit/lib/sk-analytics\"\n\n/* Cart with a saved-for-later list underneath. Lines move between the two\n   with a layout animation; the subtotal only counts what is in the cart.\n   Saving is the gentler alternative to removing. */\n\nexport type SavedLine = { id: string; title: string; variant?: string; price: number; image: string; quantity: number }\n\nconst SAMPLE_CART: SavedLine[] = [\n  { id: \"daily-greens\", title: \"Daily Greens\", variant: \"30 servings\", price: 4900, image: \"/brands/morrow/greens.webp\", quantity: 1 },\n  { id: \"electrolytes\", title: \"Electrolytes\", variant: \"30 sticks\", price: 3200, image: \"/brands/morrow/electrolytes.webp\", quantity: 1 },\n]\nconst SAMPLE_SAVED: SavedLine[] = [{ id: \"protein\", title: \"Protein\", variant: \"30 servings\", price: 5400, image: \"/brands/morrow/protein.webp\", quantity: 1 }]\n\nconst LINK = \"inline-flex h-11 items-center gap-1.5 rounded-sk-btn px-2 text-[13px] font-medium text-sk-ink underline-offset-4 transition-colors duration-200 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sk-accent active:scale-[0.97] sm:h-9\"\n\nexport function CartSavedLater({\n  cart: initialCart = SAMPLE_CART,\n  saved: initialSaved = SAMPLE_SAVED,\n  onChange,\n  className,\n}: {\n  cart?: SavedLine[]\n  saved?: SavedLine[]\n  onChange?: (v: { cart: SavedLine[]; saved: SavedLine[] }) => void\n  className?: string\n}) {\n  const reduce = useReducedMotion()\n  const sk = useSkBlock(\"cart\", \"cart-saved-later\")\n  const [cart, setCart] = React.useState(initialCart)\n  const [saved, setSaved] = React.useState(initialSaved)\n  const subtotal = cart.reduce((n, l) => n + l.price * l.quantity, 0)\n  const t = { duration: reduce ? 0 : 0.35, ease: [0.16, 1, 0.3, 1] as const }\n\n  const commit = (c: SavedLine[], s: SavedLine[]) => {\n    setCart(c)\n    setSaved(s)\n    onChange?.({ cart: c, saved: s })\n  }\n  const saveForLater = (l: SavedLine) => {\n    sk.emit(\"interact\", \"save_for_later\", l.price)\n    commit(cart.filter((x) => x.id !== l.id), [l, ...saved])\n  }\n  const moveToCart = (l: SavedLine) => {\n    sk.emit(\"convert\", \"move_to_cart\", l.price * l.quantity)\n    commit([...cart, l], saved.filter((x) => x.id !== l.id))\n  }\n  const removeSaved = (l: SavedLine) => commit(cart, saved.filter((x) => x.id !== l.id))\n\n  const row = (l: SavedLine, kind: \"cart\" | \"saved\") => (\n    <motion.li\n      key={l.id}\n      layout={!reduce}\n      layoutId={reduce ? undefined : `sk-saved-${l.id}`}\n      initial={{ opacity: 0, y: 8 }}\n      animate={{ opacity: 1, y: 0 }}\n      exit={{ opacity: 0 }}\n      transition={t}\n      className=\"flex gap-3 border-b border-sk-line py-4 last:border-b-0\"\n    >\n      <ProductImage src={l.image} alt={l.title} className={cn(\"shrink-0 rounded-sk-card border border-sk-line\", kind === \"cart\" ? \"h-20 w-20\" : \"h-16 w-16\")} fit=\"cover\" zoomOnHover={false} />\n      <div className=\"min-w-0 flex-1\">\n        <div className=\"flex items-start justify-between gap-3\">\n          <div className=\"min-w-0\">\n            <p className=\"truncate text-sm font-medium\">{l.title}</p>\n            {l.variant ? <p className=\"text-[13px] text-sk-muted\">{l.variant}</p> : null}\n          </div>\n          <p className={cn(\"shrink-0 text-sm font-semibold tabular-nums\", kind === \"cart\" ? \"text-sk-price\" : \"text-sk-muted\")}>{money(l.price * l.quantity)}</p>\n        </div>\n        <div className=\"-ml-2 mt-1 flex items-center justify-between gap-1\">\n          {kind === \"cart\" ? (\n            <button type=\"button\" onClick={() => saveForLater(l)} className={LINK}>\n              <Bookmark size={14} />\n              Save for later\n            </button>\n          ) : (\n            <>\n              <button type=\"button\" onClick={() => moveToCart(l)} className={LINK}>\n                <ShoppingBag size={14} />\n                Move to cart\n              </button>\n              <button\n                type=\"button\"\n                aria-label={`Remove ${l.title} from saved`}\n                onClick={() => removeSaved(l)}\n                className=\"grid h-11 w-11 place-items-center rounded-sk-btn text-sk-muted transition-colors duration-200 hover:bg-sk-ink/[0.05] hover:text-sk-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sk-accent active:scale-[0.97] sm:h-9 sm:w-9\"\n              >\n                <X size={15} />\n              </button>\n            </>\n          )}\n        </div>\n      </div>\n    </motion.li>\n  )\n\n  return (\n    <div ref={sk.ref as React.Ref<HTMLDivElement>} {...sk.attrs} className={cn(\"w-full\", className)}>\n      <div className=\"flex items-baseline justify-between border-b border-sk-line pb-3\">\n        <h3 className=\"font-sk-display text-lg font-semibold tracking-[-0.02em]\">\n          Cart <span className=\"tabular-nums text-sk-muted\">({cart.length})</span>\n        </h3>\n        <p className=\"text-sm text-sk-muted\">\n          Subtotal <span className=\"font-semibold tabular-nums text-sk-ink\">{money(subtotal)}</span>\n        </p>\n      </div>\n      {cart.length === 0 ? <p className=\"py-6 text-sm text-sk-muted\">Nothing in your cart. Saved items are below.</p> : null}\n      <ul>\n        <AnimatePresence initial={false} mode=\"popLayout\">\n          {cart.map((l) => row(l, \"cart\"))}\n        </AnimatePresence>\n      </ul>\n\n      <div className=\"mt-6 rounded-sk-card bg-sk-surface px-4 pt-3\">\n        <h4 className=\"font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted\">\n          Saved for later (<span className=\"tabular-nums\">{saved.length}</span>)\n        </h4>\n        {saved.length === 0 ? <p className=\"pb-4 pt-2 text-[13px] text-sk-muted\">Items you save stay here without holding stock.</p> : null}\n        <ul>\n          <AnimatePresence initial={false} mode=\"popLayout\">\n            {saved.map((l) => row(l, \"saved\"))}\n          </AnimatePresence>\n        </ul>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/storekit/cart/cart-saved-later.tsx"
    }
  ],
  "meta": {
    "section": "cart",
    "variant": "list",
    "niche": [
      "any"
    ],
    "commerce": [
      "cart",
      "save-for-later"
    ],
    "previewHeight": 620
  }
}