{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "media-preview-dialog",
  "title": "Media Preview Dialog",
  "description": "A modal component for previewing and manipulating images.",
  "dependencies": [
    "@platejs/media"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "src/registry/ui/media-preview-dialog.tsx",
      "content": "'use client';\n\nimport {\n  PreviewImage,\n  useImagePreview,\n  useImagePreviewValue,\n  useScaleInput,\n} from '@platejs/media/react';\nimport { cva } from 'class-variance-authority';\nimport { ArrowLeft, ArrowRight, Download, Minus, Plus, X } from 'lucide-react';\nimport { useEditorRef } from 'platejs/react';\n\nimport { cn } from '@/lib/utils';\n\nconst buttonVariants = cva('rounded bg-[rgba(0,0,0,0.5)] px-1', {\n  defaultVariants: {\n    variant: 'default',\n  },\n  variants: {\n    variant: {\n      default: 'text-white',\n      disabled: 'cursor-not-allowed text-gray-400',\n    },\n  },\n});\n\nconst SCROLL_SPEED = 4;\nconst DEFAULT_DOWNLOAD_FILENAME = 'image';\n\nexport function MediaPreviewDialog() {\n  const editor = useEditorRef();\n  const isOpen = useImagePreviewValue('isOpen', editor.id);\n  const scale = useImagePreviewValue('scale');\n  const isEditingScale = useImagePreviewValue('isEditingScale');\n  const currentPreview = useImagePreviewValue('currentPreview');\n  const {\n    closeProps,\n    currentUrlIndex,\n    maskLayerProps,\n    nextDisabled,\n    nextProps,\n    prevDisabled,\n    prevProps,\n    scaleTextProps,\n    zommOutProps,\n    zoomInDisabled,\n    zoomInProps,\n    zoomOutDisabled,\n  } = useImagePreview({ scrollSpeed: SCROLL_SPEED });\n  const downloadDisabled = !currentPreview?.url;\n  const handleDownload = () => {\n    if (!currentPreview?.url) return;\n\n    const link = document.createElement('a');\n    link.download = getImageDownloadFilename(currentPreview.url);\n    link.href = currentPreview.url;\n    link.rel = 'noopener noreferrer';\n    document.body.append(link);\n    link.click();\n    link.remove();\n  };\n\n  return (\n    <div\n      className={cn(\n        'fixed top-0 left-0 z-50 h-screen w-screen select-none',\n        !isOpen && 'hidden'\n      )}\n      onContextMenu={(e) => e.stopPropagation()}\n      {...maskLayerProps}\n    >\n      <div className=\"absolute inset-0 size-full bg-black opacity-30\" />\n      <div className=\"absolute inset-0 size-full bg-black opacity-30\" />\n      <div className=\"absolute inset-0 flex items-center justify-center\">\n        <div className=\"relative flex max-h-screen w-full items-center\">\n          <PreviewImage\n            className={cn(\n              'mx-auto block max-h-[calc(100vh-4rem)] w-auto object-contain transition-transform'\n            )}\n          />\n          <div\n            className=\"-translate-x-1/2 absolute bottom-0 left-1/2 z-40 flex w-fit justify-center gap-4 p-2 text-center text-white\"\n            onClick={(e) => e.stopPropagation()}\n          >\n            <div className=\"flex gap-1\">\n              <button\n                {...prevProps}\n                className={cn(\n                  buttonVariants({\n                    variant: prevDisabled ? 'disabled' : 'default',\n                  })\n                )}\n                type=\"button\"\n              >\n                <ArrowLeft />\n              </button>\n              {(currentUrlIndex ?? 0) + 1}\n              <button\n                {...nextProps}\n                className={cn(\n                  buttonVariants({\n                    variant: nextDisabled ? 'disabled' : 'default',\n                  })\n                )}\n                type=\"button\"\n              >\n                <ArrowRight />\n              </button>\n            </div>\n            <div className=\"flex\">\n              <button\n                className={cn(\n                  buttonVariants({\n                    variant: zoomOutDisabled ? 'disabled' : 'default',\n                  })\n                )}\n                {...zommOutProps}\n                type=\"button\"\n              >\n                <Minus className=\"size-4\" />\n              </button>\n              <div className=\"mx-px\">\n                {isEditingScale ? (\n                  <>\n                    <ScaleInput className=\"w-10 rounded px-1 text-slate-500 outline\" />{' '}\n                    <span>%</span>\n                  </>\n                ) : (\n                  <span {...scaleTextProps}>{`${scale * 100}%`}</span>\n                )}\n              </div>\n              <button\n                className={cn(\n                  buttonVariants({\n                    variant: zoomInDisabled ? 'disabled' : 'default',\n                  })\n                )}\n                {...zoomInProps}\n                type=\"button\"\n              >\n                <Plus className=\"size-4\" />\n              </button>\n            </div>\n            <button\n              className={cn(\n                buttonVariants({\n                  variant: downloadDisabled ? 'disabled' : 'default',\n                })\n              )}\n              disabled={downloadDisabled}\n              onClick={handleDownload}\n              type=\"button\"\n            >\n              <Download className=\"size-4\" />\n            </button>\n            <button\n              {...closeProps}\n              className={cn(buttonVariants())}\n              type=\"button\"\n            >\n              <X className=\"size-4\" />\n            </button>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nfunction ScaleInput(props: React.ComponentProps<'input'>) {\n  const { props: scaleInputProps, ref } = useScaleInput();\n\n  return <input {...scaleInputProps} {...props} ref={ref} />;\n}\n\nfunction getImageDownloadFilename(url: string) {\n  try {\n    const pathname = new URL(url, window.location.href).pathname;\n    const filename = pathname.split('/').filter(Boolean).pop();\n\n    return filename || DEFAULT_DOWNLOAD_FILENAME;\n  } catch {\n    return DEFAULT_DOWNLOAD_FILENAME;\n  }\n}\n",
      "type": "registry:ui"
    }
  ],
  "meta": {
    "docs": [
      {
        "route": "/docs/media"
      },
      {
        "route": "https://pro.platejs.org/docs/components/image-preview"
      }
    ],
    "examples": [
      "media-demo",
      "media-pro"
    ]
  },
  "type": "registry:ui"
}