{
  "name": "media-gallery",
  "title": "MediaGallery",
  "description": "Like ProductImageGallery but accepts mixed image/video/3D items in one carousel. Thumbnails show a poster + small overlay icon for video/3D.",
  "type": "component",
  "registryDependencies": [
    "store-video",
    "product-model-3d"
  ],
  "files": [
    {
      "path": "media-gallery.tsx",
      "content": "\"use client\";\n\nimport React, { useEffect, useMemo, useState } from \"react\";\nimport { RadioGroup } from \"@base-ui/react/radio-group\";\nimport { Radio } from \"@base-ui/react/radio\";\nimport { StoreVideo } from \"@cimplify/sdk/react\";\nimport { ProductModel3D } from \"@cimplify/sdk/react\";\n\nexport type MediaItem =\n  | { type: \"image\"; src: string; alt?: string }\n  | { type: \"video\"; src: string; poster?: string; alt?: string }\n  | { type: \"model\"; src: string; iosSrc?: string; poster?: string; alt?: string };\n\nexport interface MediaGalleryProps {\n  items: MediaItem[];\n  productName: string;\n  aspectRatio?: \"square\" | \"4/3\" | \"16/10\" | \"3/4\";\n  className?: string;\n}\n\nconst ASPECT_STYLES: Record<string, React.CSSProperties> = {\n  square: { aspectRatio: \"1/1\" },\n  \"4/3\": { aspectRatio: \"4/3\" },\n  \"16/10\": { aspectRatio: \"16/10\" },\n  \"3/4\": { aspectRatio: \"3/4\" },\n};\n\nfunction thumbnailFor(item: MediaItem): string | null {\n  if (item.type === \"image\") return item.src;\n  return item.poster ?? null;\n}\n\nfunction thumbIcon(item: MediaItem): string | null {\n  if (item.type === \"video\") return \"▶\";\n  if (item.type === \"model\") return \"◆\";\n  return null;\n}\n\n/**\n * MediaGallery — like ProductImageGallery, but accepts mixed image/video/3D\n * items in one carousel. The active item renders via the matching SDK\n * component (img / StoreVideo / ProductModel3D); thumbnails show a poster\n * (or the image itself) with a small overlay icon for video/3D.\n */\nexport function MediaGallery({\n  items,\n  productName,\n  aspectRatio = \"4/3\",\n  className,\n}: MediaGalleryProps): React.ReactElement | null {\n  const validItems = useMemo(\n    () => items.filter((i) => typeof i.src === \"string\" && i.src.trim().length > 0),\n    [items],\n  );\n\n  const [selected, setSelected] = useState(0);\n\n  useEffect(() => {\n    setSelected(0);\n  }, [validItems.length, productName]);\n\n  if (validItems.length === 0) return null;\n\n  const active = validItems[selected] ?? validItems[0];\n\n  return (\n    <div data-cimplify-media-gallery className={className}>\n      <div\n        data-cimplify-media-gallery-main\n        style={{ position: \"relative\", overflow: \"hidden\", ...ASPECT_STYLES[aspectRatio] }}\n      >\n        {active.type === \"image\" ? (\n          <img\n            src={active.src}\n            alt={active.alt ?? productName}\n            style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\" }}\n            data-cimplify-media-gallery-active\n          />\n        ) : active.type === \"video\" ? (\n          <StoreVideo\n            src={active.src}\n            poster={active.poster}\n            alt={active.alt ?? productName}\n            aspectRatio=\"square\"\n            lazy={false}\n          />\n        ) : (\n          <ProductModel3D\n            src={active.src}\n            iosSrc={active.iosSrc}\n            poster={active.poster}\n            alt={active.alt ?? productName}\n            aspectRatio=\"square\"\n          />\n        )}\n      </div>\n\n      {validItems.length > 1 && (\n        <RadioGroup\n          aria-label={`${productName} media thumbnails`}\n          value={String(selected)}\n          onValueChange={(v) => setSelected(Number(v))}\n          data-cimplify-media-gallery-thumbnails\n          style={{ display: \"flex\", gap: \"0.5rem\", marginTop: \"0.75rem\" }}\n        >\n          {validItems.map((item, index) => {\n            const thumb = thumbnailFor(item);\n            const icon = thumbIcon(item);\n            const isSelected = selected === index;\n            return (\n              <Radio.Root\n                key={`${item.src}-${index}`}\n                value={String(index)}\n                data-cimplify-media-gallery-thumb\n                data-selected={isSelected || undefined}\n                data-type={item.type}\n                style={{\n                  position: \"relative\",\n                  width: \"4rem\",\n                  height: \"4rem\",\n                  overflow: \"hidden\",\n                  padding: 0,\n                  border: \"none\",\n                  cursor: \"pointer\",\n                  backgroundColor: \"var(--muted, #f3f4f6)\",\n                }}\n              >\n                {thumb ? (\n                  <img\n                    src={thumb}\n                    alt=\"\"\n                    style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\" }}\n                  />\n                ) : null}\n                {icon ? (\n                  <span\n                    aria-hidden\n                    style={{\n                      position: \"absolute\",\n                      inset: 0,\n                      display: \"flex\",\n                      alignItems: \"center\",\n                      justifyContent: \"center\",\n                      color: \"white\",\n                      fontSize: \"0.875rem\",\n                      textShadow: \"0 1px 2px rgba(0,0,0,0.6)\",\n                      pointerEvents: \"none\",\n                    }}\n                  >\n                    {icon}\n                  </span>\n                ) : null}\n              </Radio.Root>\n            );\n          })}\n        </RadioGroup>\n      )}\n    </div>\n  );\n}\n"
    }
  ]
}
