{
  "name": "store-video",
  "title": "StoreVideo",
  "description": "Autoplay-muted-loop video for storefront heroes / product demos. Lazy-loaded, mobile-safe (playsInline), poster fallback for browsers without video.",
  "type": "component",
  "registryDependencies": [],
  "files": [
    {
      "path": "store-video.tsx",
      "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\n\nexport interface StoreVideoProps {\n  src: string;\n  /** Poster shown before play + as the fallback if `<video>` isn't supported. */\n  poster?: string;\n  /** Accessible label; also the alt of the fallback `<img>`. */\n  alt?: string;\n  aspectRatio?: \"square\" | \"4/3\" | \"16/9\" | \"16/10\" | \"3/4\";\n  /** Show native browser controls. Default off for autoplay-friendly hero clips. */\n  controls?: boolean;\n  /** Default `true` — muted is the only way mobile browsers allow autoplay. */\n  autoplay?: boolean;\n  loop?: boolean;\n  muted?: boolean;\n  /** Lazy-load: defer the src until the player scrolls into view. Default `true`. */\n  lazy?: boolean;\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/9\": { aspectRatio: \"16/9\" },\n  \"16/10\": { aspectRatio: \"16/10\" },\n  \"3/4\": { aspectRatio: \"3/4\" },\n};\n\n/**\n * StoreVideo — `<video>` with mobile-safe defaults (muted + playsInline + loop),\n * IntersectionObserver-driven lazy load, and a poster `<img>` fallback for\n * browsers without video support. Drop-in replacement for a static hero image.\n */\nexport function StoreVideo({\n  src,\n  poster,\n  alt,\n  aspectRatio = \"16/9\",\n  controls = false,\n  autoplay = true,\n  loop = true,\n  muted = true,\n  lazy = true,\n  className,\n}: StoreVideoProps): React.ReactElement {\n  const ref = useRef<HTMLVideoElement>(null);\n  const [inView, setInView] = useState(!lazy);\n\n  useEffect(() => {\n    if (!lazy || inView) return;\n    const node = ref.current;\n    if (!node || typeof IntersectionObserver === \"undefined\") {\n      setInView(true);\n      return;\n    }\n    const observer = new IntersectionObserver(\n      (entries) => {\n        if (entries.some((e) => e.isIntersecting)) {\n          setInView(true);\n          observer.disconnect();\n        }\n      },\n      { rootMargin: \"200px\" },\n    );\n    observer.observe(node);\n    return () => observer.disconnect();\n  }, [lazy, inView]);\n\n  return (\n    <div\n      data-cimplify-store-video\n      className={className}\n      style={{ position: \"relative\", overflow: \"hidden\", ...ASPECT_STYLES[aspectRatio] }}\n    >\n      <video\n        ref={ref}\n        src={inView ? src : undefined}\n        poster={poster}\n        autoPlay={autoplay}\n        loop={loop}\n        muted={muted}\n        playsInline\n        controls={controls}\n        preload={lazy ? \"metadata\" : \"auto\"}\n        aria-label={alt}\n        style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\", display: \"block\" }}\n      >\n        {poster ? (\n          <img\n            src={poster}\n            alt={alt ?? \"\"}\n            style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\" }}\n          />\n        ) : null}\n      </video>\n    </div>\n  );\n}\n"
    }
  ]
}
