{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "frequently-bought-together",
  "title": "Frequently Bought Together",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-svelte/blocks/frequently-bought-together/FrequentlyBoughtTogether.svelte",
      "content": "<script lang=\"ts\" module>\n  export interface BundleItem {\n    id: string\n    name: string\n    subtitle: string\n    price: number\n    image: string\n    isMain?: boolean\n  }\n\n  export interface FrequentlyBoughtTogetherProps {\n    className?: string\n  }\n</script>\n\n<script lang=\"ts\">\n  import { Plus, ShoppingBag, Truck } from '@lucide/svelte'\n  import { Badge } from '$lib/components/ui/badge'\n  import { Button } from '$lib/components/ui/button'\n  import { Card } from '$lib/components/ui/card'\n  import { Checkbox } from '$lib/components/ui/checkbox'\n  import { cn } from '$lib/utils'\n\n  let { className }: FrequentlyBoughtTogetherProps = $props()\n\n  const items: BundleItem[] = [\n    {\n      id: 'headphones',\n      name: 'Pro Studio Headphones',\n      subtitle: 'Space Black · Over-Ear Wireless ANC',\n      price: 299.0,\n      image: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=500&auto=format&fit=crop&q=80',\n      isMain: true,\n    },\n    {\n      id: 'case',\n      name: 'Premium Hard Shell Case',\n      subtitle: 'Weather-resistant EVA shell with plush velvet lining',\n      price: 45.0,\n      image: 'https://images.unsplash.com/photo-1583394838336-acd977736f90?w=500&auto=format&fit=crop&q=80',\n    },\n    {\n      id: 'cable',\n      name: 'Braided 3.5mm Audiophile Cable',\n      subtitle: '1.5m Silver-plated OFC copper with gold-plated jacks',\n      price: 25.0,\n      image: 'https://images.unsplash.com/photo-1546435770-a3e426bf472b?w=500&auto=format&fit=crop&q=80',\n    },\n  ]\n\n  let selectedIds = $state<string[]>(['headphones', 'case', 'cable'])\n\n  function toggleItem(id: string) {\n    if (selectedIds.includes(id)) {\n      selectedIds = selectedIds.filter((itemId) => itemId !== id)\n    } else {\n      selectedIds = [...selectedIds, id]\n    }\n  }\n\n  const selectedItems = $derived(items.filter((item) => selectedIds.includes(item.id)))\n  const selectedCount = $derived(selectedItems.length)\n\n  const originalTotal = $derived(selectedItems.reduce((sum, item) => sum + item.price, 0))\n\n  const discountRate = $derived(selectedCount >= 2 ? 0.15 : 0)\n  const discountAmount = $derived(originalTotal * discountRate)\n  const finalPrice = $derived(originalTotal - discountAmount)\n  const hasDiscount = $derived(discountRate > 0)\n\n  const buttonText = $derived.by(() => {\n    if (selectedCount === items.length) return `Add all ${items.length} to Cart`\n    if (selectedCount > 1) return `Add ${selectedCount} selected to Cart`\n    if (selectedCount === 1) return 'Add 1 selected to Cart'\n    return 'Select items to add'\n  })\n\n  const deliveryNote = $derived.by(() => {\n    if (selectedCount >= 2) return 'Free express delivery included with this bundle'\n    if (selectedCount === 1) return 'Standard delivery included'\n    return 'Select items to view delivery options'\n  })\n\n  function formatCurrency(val: number) {\n    return '$' + val.toFixed(2)\n  }\n</script>\n\n<Card data-slot=\"frequently-bought-together\" class={cn('mx-auto w-full max-w-4xl space-y-6 p-6 shadow-xs', className)}>\n  <!-- Header -->\n  <div class=\"space-y-1.5\">\n    <h2 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">Frequently Bought Together</h2>\n    <p class=\"text-muted-foreground text-sm\">\n      Pair with these recommended essentials for maximum performance and save 15% on the bundle\n    </p>\n  </div>\n\n  <!-- Product Visual Row -->\n  <div class=\"grid grid-cols-1 items-center gap-3 sm:grid-cols-[1fr_auto_1fr_auto_1fr] sm:gap-4\">\n    {#each items as item, index (item.id)}\n      <div\n        class={cn(\n          'border-border bg-muted/20 relative flex flex-col rounded-xl border p-3 text-left transition-colors duration-200 sm:p-4',\n          selectedIds.includes(item.id) ? 'opacity-100' : 'opacity-40 grayscale',\n        )}\n      >\n        <div class=\"border-border bg-background relative mb-3 aspect-square w-full overflow-hidden rounded-lg border\">\n          <img src={item.image} alt={item.name} class=\"size-full object-cover\" />\n          {#if item.isMain}\n            <Badge\n              variant=\"secondary\"\n              class=\"bg-background/90 text-foreground absolute top-2 left-2 text-xs font-medium backdrop-blur-xs\"\n            >\n              This item\n            </Badge>\n          {/if}\n        </div>\n        <span class=\"text-foreground line-clamp-1 text-xs leading-tight font-semibold sm:text-sm\">\n          {item.name}\n        </span>\n        <span class=\"text-foreground mt-1 text-xs font-semibold tabular-nums sm:text-sm\">\n          {formatCurrency(item.price)}\n        </span>\n      </div>\n\n      {#if index < items.length - 1}\n        <div\n          class=\"border-border/50 text-muted-foreground bg-muted mx-auto flex size-8 shrink-0 items-center justify-center rounded-full border\"\n          aria-hidden=\"true\"\n        >\n          <Plus class=\"size-4\" />\n        </div>\n      {/if}\n    {/each}\n  </div>\n\n  <!-- Item Selection Checkbox List -->\n  <div class=\"space-y-2.5\">\n    {#each items as item (item.id)}\n      <div\n        role=\"button\"\n        tabindex={0}\n        class={cn(\n          'border-border focus-visible:ring-ring flex cursor-pointer items-start justify-between gap-3 rounded-lg border p-3.5 transition-colors select-none focus-visible:ring-2 focus-visible:outline-none sm:items-center',\n          selectedIds.includes(item.id)\n            ? 'bg-card hover:border-primary/40'\n            : 'border-border/60 bg-muted/10 opacity-60 hover:opacity-80',\n        )}\n        onclick={() => toggleItem(item.id)}\n        onkeydown={(e) => {\n          if (e.key === ' ' || e.key === 'Enter') {\n            e.preventDefault()\n            toggleItem(item.id)\n          }\n        }}\n      >\n        <div class=\"flex items-start gap-3 sm:items-center\">\n          <Checkbox\n            id={item.id}\n            checked={selectedIds.includes(item.id)}\n            class=\"pointer-events-none mt-0.5 sm:mt-0\"\n            tabindex={-1}\n          />\n          <div class=\"space-y-0.5\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <span class=\"text-foreground text-sm font-medium\">\n                {#if item.isMain}<span class=\"font-semibold\">This item: </span>{/if}\n                {item.name}\n              </span>\n              {#if item.isMain}<Badge variant=\"secondary\" class=\"text-xs\"> Main Item </Badge>{/if}\n            </div>\n            <p class=\"text-muted-foreground text-xs\">{item.subtitle}</p>\n          </div>\n        </div>\n        <span class=\"text-foreground shrink-0 text-sm font-semibold tabular-nums\">\n          {formatCurrency(item.price)}\n        </span>\n      </div>\n    {/each}\n  </div>\n\n  <!-- Price & Bundle Checkout Summary Box -->\n  <div\n    class=\"border-border bg-muted/30 flex flex-col gap-4 rounded-xl border p-4 sm:p-5 md:flex-row md:items-center md:justify-between\"\n  >\n    <div class=\"space-y-1.5\">\n      <div class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">\n        {selectedCount >= 2 ? 'Bundle Price' : 'Total Price'}\n      </div>\n      <div class=\"flex flex-wrap items-baseline gap-2.5\">\n        <span class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums sm:text-3xl\">\n          {formatCurrency(finalPrice)}\n        </span>\n        {#if hasDiscount}\n          <span class=\"text-muted-foreground text-sm font-medium tabular-nums line-through sm:text-base\">\n            {formatCurrency(originalTotal)}\n          </span>\n          <Badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success text-xs font-medium\">\n            Save {formatCurrency(discountAmount)} (15% Bundle Discount)\n          </Badge>\n        {/if}\n      </div>\n      <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">\n        <Truck class=\"text-success size-3.5 shrink-0\" />\n        <span>{deliveryNote}</span>\n      </div>\n    </div>\n\n    <Button size=\"lg\" disabled={selectedCount === 0} class=\"w-full gap-2 font-semibold shadow-xs md:w-auto\">\n      <ShoppingBag class=\"size-4\" />\n      <span>{buttonText}</span>\n    </Button>\n  </div>\n</Card>\n",
      "type": "registry:block",
      "target": "~/src/lib/components/blocks/frequently-bought-together/FrequentlyBoughtTogether.svelte"
    }
  ],
  "dependencies": [
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/svelte/badge.json",
    "https://uipkge.dev/r/svelte/button.json",
    "https://uipkge.dev/r/svelte/card.json",
    "https://uipkge.dev/r/svelte/checkbox.json"
  ],
  "description": "E-commerce frequently bought together bundle builder with interactive product preview cards, checkbox selection, dynamic bundle discount calculation, and one-click cart checkout.",
  "categories": [
    "commerce",
    "ecommerce"
  ]
}