{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "media-toolbar-button",
  "title": "Media Toolbar Button",
  "description": "Toolbar button for inserting and managing media.",
  "dependencies": [
    "@platejs/media",
    "use-file-picker@2.1.2",
    "sonner"
  ],
  "registryDependencies": [
    "https://platejs.org/r/toolbar.json",
    "input",
    "dropdown-menu",
    "alert-dialog"
  ],
  "files": [
    {
      "path": "src/registry/ui/media-toolbar-button.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nimport type { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';\n\nimport { PlaceholderPlugin } from '@platejs/media/react';\nimport {\n  AudioLinesIcon,\n  FileUpIcon,\n  FilmIcon,\n  ImageIcon,\n  LinkIcon,\n} from 'lucide-react';\nimport { isUrl, KEYS } from 'platejs';\nimport { useEditorRef } from 'platejs/react';\nimport { toast } from 'sonner';\nimport { useFilePicker } from 'use-file-picker';\n\nimport {\n  AlertDialog,\n  AlertDialogAction,\n  AlertDialogCancel,\n  AlertDialogContent,\n  AlertDialogDescription,\n  AlertDialogFooter,\n  AlertDialogHeader,\n  AlertDialogTitle,\n} from '@/components/ui/alert-dialog';\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\nimport { Input } from '@/components/ui/input';\n\nimport {\n  ToolbarSplitButton,\n  ToolbarSplitButtonPrimary,\n  ToolbarSplitButtonSecondary,\n} from './toolbar';\n\nconst MEDIA_CONFIG: Record<\n  string,\n  {\n    accept: string[];\n    icon: React.ReactNode;\n    title: string;\n    tooltip: string;\n  }\n> = {\n  [KEYS.audio]: {\n    accept: ['audio/*'],\n    icon: <AudioLinesIcon className=\"size-4\" />,\n    title: 'Insert Audio',\n    tooltip: 'Audio',\n  },\n  [KEYS.file]: {\n    accept: ['*'],\n    icon: <FileUpIcon className=\"size-4\" />,\n    title: 'Insert File',\n    tooltip: 'File',\n  },\n  [KEYS.img]: {\n    accept: ['image/*'],\n    icon: <ImageIcon className=\"size-4\" />,\n    title: 'Insert Image',\n    tooltip: 'Image',\n  },\n  [KEYS.video]: {\n    accept: ['video/*'],\n    icon: <FilmIcon className=\"size-4\" />,\n    title: 'Insert Video',\n    tooltip: 'Video',\n  },\n};\n\nexport function MediaToolbarButton({\n  nodeType,\n  ...props\n}: DropdownMenuProps & { nodeType: string }) {\n  const currentConfig = MEDIA_CONFIG[nodeType];\n\n  const editor = useEditorRef();\n  const [open, setOpen] = React.useState(false);\n  const [dialogOpen, setDialogOpen] = React.useState(false);\n\n  const { openFilePicker } = useFilePicker({\n    accept: currentConfig.accept,\n    multiple: true,\n    onFilesSelected: ({ plainFiles: updatedFiles }) => {\n      editor.getTransforms(PlaceholderPlugin).insert.media(updatedFiles);\n    },\n  });\n\n  return (\n    <>\n      <ToolbarSplitButton\n        onClick={() => {\n          openFilePicker();\n        }}\n        onKeyDown={(e) => {\n          if (e.key === 'ArrowDown') {\n            e.preventDefault();\n            setOpen(true);\n          }\n        }}\n        pressed={open}\n      >\n        <ToolbarSplitButtonPrimary>\n          {currentConfig.icon}\n        </ToolbarSplitButtonPrimary>\n\n        <DropdownMenu\n          open={open}\n          onOpenChange={setOpen}\n          modal={false}\n          {...props}\n        >\n          <DropdownMenuTrigger asChild>\n            <ToolbarSplitButtonSecondary />\n          </DropdownMenuTrigger>\n\n          <DropdownMenuContent\n            onClick={(e) => e.stopPropagation()}\n            align=\"start\"\n            alignOffset={-32}\n          >\n            <DropdownMenuGroup>\n              <DropdownMenuItem onSelect={() => openFilePicker()}>\n                {currentConfig.icon}\n                Upload from computer\n              </DropdownMenuItem>\n              <DropdownMenuItem onSelect={() => setDialogOpen(true)}>\n                <LinkIcon />\n                Insert via URL\n              </DropdownMenuItem>\n            </DropdownMenuGroup>\n          </DropdownMenuContent>\n        </DropdownMenu>\n      </ToolbarSplitButton>\n\n      <AlertDialog\n        open={dialogOpen}\n        onOpenChange={(value) => {\n          setDialogOpen(value);\n        }}\n      >\n        <AlertDialogContent className=\"gap-6\">\n          <MediaUrlDialogContent\n            currentConfig={currentConfig}\n            nodeType={nodeType}\n            setOpen={setDialogOpen}\n          />\n        </AlertDialogContent>\n      </AlertDialog>\n    </>\n  );\n}\n\nfunction MediaUrlDialogContent({\n  currentConfig,\n  nodeType,\n  setOpen,\n}: {\n  currentConfig: (typeof MEDIA_CONFIG)[string];\n  nodeType: string;\n  setOpen: (value: boolean) => void;\n}) {\n  const editor = useEditorRef();\n  const [url, setUrl] = React.useState('');\n\n  const embedMedia = React.useCallback(() => {\n    if (!isUrl(url)) return toast.error('Invalid URL');\n\n    setOpen(false);\n    editor.tf.insertNodes({\n      children: [{ text: '' }],\n      name: nodeType === KEYS.file ? url.split('/').pop() : undefined,\n      type: nodeType,\n      url,\n    });\n  }, [url, editor, nodeType, setOpen]);\n\n  return (\n    <>\n      <AlertDialogHeader>\n        <AlertDialogTitle>{currentConfig.title}</AlertDialogTitle>\n      </AlertDialogHeader>\n\n      <AlertDialogDescription className=\"group relative w-full\">\n        <label\n          className=\"-translate-y-1/2 absolute top-1/2 block cursor-text px-1 text-muted-foreground/70 text-sm transition-all group-focus-within:pointer-events-none group-focus-within:top-0 group-focus-within:cursor-default group-focus-within:font-medium group-focus-within:text-foreground group-focus-within:text-xs has-[+input:not(:placeholder-shown)]:pointer-events-none has-[+input:not(:placeholder-shown)]:top-0 has-[+input:not(:placeholder-shown)]:cursor-default has-[+input:not(:placeholder-shown)]:font-medium has-[+input:not(:placeholder-shown)]:text-foreground has-[+input:not(:placeholder-shown)]:text-xs\"\n          htmlFor=\"url\"\n        >\n          <span className=\"inline-flex bg-background px-2\">URL</span>\n        </label>\n        <Input\n          id=\"url\"\n          className=\"w-full\"\n          value={url}\n          onChange={(e) => setUrl(e.target.value)}\n          onKeyDown={(e) => {\n            if (e.key === 'Enter') embedMedia();\n          }}\n          placeholder=\"\"\n          type=\"url\"\n          autoFocus\n        />\n      </AlertDialogDescription>\n\n      <AlertDialogFooter>\n        <AlertDialogCancel>Cancel</AlertDialogCancel>\n        <AlertDialogAction\n          onClick={(e) => {\n            e.preventDefault();\n            embedMedia();\n          }}\n        >\n          Accept\n        </AlertDialogAction>\n      </AlertDialogFooter>\n    </>\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "meta": {
    "docs": [
      {
        "route": "/docs/media"
      }
    ],
    "examples": [
      "media-demo",
      "media-pro"
    ]
  },
  "type": "registry:ui"
}