{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"video-viewer","type":"registry:ui","title":"VideoViewer","description":"Native video controls with poster and fit.","package":"react-fancy","dependencies":[],"registryDependencies":[],"files":[{"path":"components\/fancy\/video-viewer\/VideoViewer.tsx","content":"import { forwardRef, useState } from \"react\";\nimport { cn } from \"..\/..\/utils\/cn\";\nimport type { VideoViewerProps } from \".\/VideoViewer.types\";\n\n\/**\n * A standalone video viewer \u2014 native controls, optional poster, fit-to-box, and\n * dark-aware framing. Renders for video sources inside `<MediaViewer>`.\n *\n * ```tsx\n * <VideoViewer src=\"\/clip.mp4\" poster=\"\/clip.jpg\" style={{ height: 360 }} \/>\n * ```\n *\/\nexport const VideoViewer = forwardRef<HTMLDivElement, VideoViewerProps>(\n  (\n    {\n      src,\n      poster,\n      controls = true,\n      autoPlay = false,\n      loop = false,\n      muted = false,\n      fit = \"contain\",\n      onError,\n      className,\n      style,\n    },\n    ref,\n  ) => {\n    const [errored, setErrored] = useState(false);\n\n    return (\n      <div\n        ref={ref}\n        data-react-fancy-video-viewer=\"\"\n        className={cn(\n          \"relative flex items-center justify-center overflow-hidden rounded-md bg-black\",\n          className,\n        )}\n        style={style}\n      >\n        {errored ? (\n          <div className=\"flex flex-col items-center justify-center gap-1 p-4 text-center text-sm text-zinc-400\">\n            <span className=\"font-medium\">Couldn&apos;t load video<\/span>\n            <span className=\"max-w-full truncate text-xs opacity-70\">{src}<\/span>\n          <\/div>\n        ) : (\n          <video\n            src={src}\n            poster={poster}\n            controls={controls}\n            autoPlay={autoPlay}\n            loop={loop}\n            muted={muted}\n            playsInline\n            onError={() => {\n              setErrored(true);\n              onError?.();\n            }}\n            className={cn(\n              \"max-h-full max-w-full\",\n              fit === \"cover\" ? \"h-full w-full object-cover\" : \"object-contain\",\n            )}\n          \/>\n        )}\n      <\/div>\n    );\n  },\n);\n\nVideoViewer.displayName = \"VideoViewer\";\n","type":"registry:ui","target":"components\/fancy\/video-viewer\/VideoViewer.tsx"},{"path":"components\/fancy\/video-viewer\/VideoViewer.types.ts","content":"import type { CSSProperties } from \"react\";\n\nexport interface VideoViewerProps {\n  \/** Video source \u2014 an `http(s):`, `data:`, or `blob:` URL. *\/\n  src: string;\n  \/** Poster image shown before playback. *\/\n  poster?: string;\n  \/** Show native playback controls (default `true`). *\/\n  controls?: boolean;\n  \/** Autoplay on mount (most browsers require `muted` too). *\/\n  autoPlay?: boolean;\n  \/** Loop playback (default `false`). *\/\n  loop?: boolean;\n  \/** Start muted (default `false`). *\/\n  muted?: boolean;\n  \/** How the video fits its box: `\"contain\"` (default) or `\"cover\"`. *\/\n  fit?: \"contain\" | \"cover\";\n  \/** Fired when the video fails to load. *\/\n  onError?: () => void;\n  \/** Additional CSS classes for the container. *\/\n  className?: string;\n  \/** Inline styles for the container (e.g. a fixed height). *\/\n  style?: CSSProperties;\n}\n","type":"registry:ui","target":"components\/fancy\/video-viewer\/VideoViewer.types.ts"},{"path":"components\/fancy\/video-viewer\/index.ts","content":"export { VideoViewer } from \".\/VideoViewer\";\nexport type { VideoViewerProps } from \".\/VideoViewer.types\";\n","type":"registry:ui","target":"components\/fancy\/video-viewer\/index.ts"}]}