{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "product-gallery",
  "type": "registry:block",
  "title": "Product image gallery",
  "description": "A large product view with thumbnails that choose it, built as tabs so the arrow keys move between pictures.",
  "author": "Box Kite <https://www.box-kite.dev>",
  "categories": [
    "ecommerce",
    "product"
  ],
  "dependencies": [
    "@box-kite/react"
  ],
  "registryDependencies": [
    "https://www.box-kite.dev/r/store-design.json"
  ],
  "files": [
    {
      "path": "registry/designs/store/product-gallery.tsx",
      "content": "'use client';\nimport Tabs from '@box-kite/react/components/tabs';\nimport VisuallyHidden from '@box-kite/react/components/visuallyHidden';\nimport ProductArt, { type ArtView } from './product-art';\nimport { finishes, type Product, productBySlug } from './store-data';\n\nconst views: { value: ArtView; label: string }[] = [\n  { value: 'front', label: 'Front' },\n  { value: 'set', label: 'All finishes' },\n];\n\nconst list = new Intl.ListFormat('en');\n\nexport interface ProductGalleryProps {\n  product?: Product;\n  /** The finish on show — the variant picker beside the gallery owns it. */\n  finish?: string;\n}\n\n/**\n * A product's pictures: one large view and a row of thumbnails that choose it. The thumbnails are tabs\n * (APG's tabbed carousel), so the arrow keys move between them and each picture is named by its tab.\n */\nexport default function ProductGallery({ product = productBySlug('table-lamp'), finish = product.finishes[0] }: ProductGalleryProps) {\n  const also = product.finishes.filter((id) => id !== finish);\n  const labels: Record<ArtView, string> = {\n    front: `${product.name} in ${finishes[finish].name}`,\n    set: `${product.name} in ${list.format([finish, ...also].map((id) => finishes[id].name))}`,\n  };\n\n  return (\n    <Tabs defaultValue=\"front\" gap={3}>\n      <Tabs.List label={`${product.name} pictures`} order={1} bb={0} gap={3}>\n        {views.map((view) => (\n          <Tabs.Tab\n            key={view.value}\n            value={view.value}\n            px={1}\n            py={1}\n            bgColor=\"transparent\"\n            mb={0}\n            width={20}\n            height={20}\n            borderRadius={3}\n            b={1}\n            borderColor=\"transparent\"\n            hover={{ borderColor: 'stone-300' }}\n            ariaAttr={{ selected: { borderColor: 'stone-900' } }}\n            focusVisible={{ outlineOffset: 2 }}\n            theme={{\n              dark: { bgColor: 'transparent', hover: { borderColor: 'stone-600' }, ariaAttr: { selected: { borderColor: 'stone-100' } } },\n            }}\n          >\n            <ProductArt shape={product.shape} finish={finish} also={also} view={view.value} stroke={1.5} radius={2} />\n            <VisuallyHidden>{view.label}</VisuallyHidden>\n          </Tabs.Tab>\n        ))}\n      </Tabs.List>\n      {views.map((view) => (\n        <Tabs.Panel key={view.value} value={view.value} aspectRatio=\"square\" borderRadius={6} startingStyle={{ opacity: 0 }}>\n          <ProductArt\n            shape={product.shape}\n            finish={finish}\n            also={also}\n            view={view.value}\n            label={labels[view.value]}\n            stroke={0.5}\n            radius={6}\n          />\n        </Tabs.Panel>\n      ))}\n    </Tabs>\n  );\n}\n",
      "type": "registry:block",
      "target": "@components/box-kite/store/product-gallery.tsx"
    }
  ],
  "docs": "Render <ProductGallery product={…} finish={…} />. Wrap it in <StoreSurface> from store-design.tsx, or render it inside one of the store pages."
}
