{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "link-toolbar",
  "title": "Link Floating Toolbar",
  "description": "A floating interface for link editing.",
  "dependencies": [
    "@platejs/link",
    "@platejs/floating"
  ],
  "registryDependencies": [
    "button",
    "input",
    "popover",
    "separator"
  ],
  "files": [
    {
      "path": "src/registry/ui/link-toolbar.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\n\nimport type { TLinkElement } from 'platejs';\n\nimport {\n  type UseVirtualFloatingOptions,\n  flip,\n  offset,\n} from '@platejs/floating';\nimport { getLinkAttributes } from '@platejs/link';\nimport {\n  type LinkFloatingToolbarState,\n  FloatingLinkUrlInput,\n  useFloatingLinkEdit,\n  useFloatingLinkEditState,\n  useFloatingLinkInsert,\n  useFloatingLinkInsertState,\n} from '@platejs/link/react';\nimport { cva } from 'class-variance-authority';\nimport { ExternalLink, Link, Text, Unlink } from 'lucide-react';\nimport { KEYS } from 'platejs';\nimport {\n  useEditorRef,\n  useEditorSelection,\n  useFormInputProps,\n  usePluginOption,\n} from 'platejs/react';\n\nimport { buttonVariants } from '@/components/ui/button';\nimport { Separator } from '@/components/ui/separator';\n\nconst popoverVariants = cva(\n  'z-50 w-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md outline-hidden'\n);\n\nconst inputVariants = cva(\n  'flex h-[28px] w-full rounded-md border-none bg-transparent px-1.5 py-1 text-base placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-transparent md:text-sm'\n);\n\nexport function LinkFloatingToolbar({\n  state,\n}: {\n  state?: LinkFloatingToolbarState;\n}) {\n  const activeCommentId = usePluginOption({ key: KEYS.comment }, 'activeId');\n  const activeSuggestionId = usePluginOption(\n    { key: KEYS.suggestion },\n    'activeId'\n  );\n\n  const floatingOptions: UseVirtualFloatingOptions = React.useMemo(\n    () => ({\n      middleware: [\n        offset(8),\n        flip({\n          fallbackPlacements: ['bottom-end', 'top-start', 'top-end'],\n          padding: 12,\n        }),\n      ],\n      placement:\n        activeSuggestionId || activeCommentId ? 'top-start' : 'bottom-start',\n    }),\n    [activeCommentId, activeSuggestionId]\n  );\n\n  const insertState = useFloatingLinkInsertState({\n    ...state,\n    floatingOptions: {\n      ...floatingOptions,\n      ...state?.floatingOptions,\n    },\n  });\n  const {\n    hidden,\n    props: insertProps,\n    ref: insertRef,\n    textInputProps,\n  } = useFloatingLinkInsert(insertState);\n\n  const editState = useFloatingLinkEditState({\n    ...state,\n    floatingOptions: {\n      ...floatingOptions,\n      ...state?.floatingOptions,\n    },\n  });\n  const {\n    editButtonProps,\n    props: editProps,\n    ref: editRef,\n    unlinkButtonProps,\n  } = useFloatingLinkEdit(editState);\n  const inputProps = useFormInputProps({\n    preventDefaultOnEnterKeydown: true,\n  });\n\n  if (hidden) return null;\n\n  const input = (\n    <div className=\"flex w-[330px] flex-col\" {...inputProps}>\n      <div className=\"flex items-center\">\n        <div className=\"flex items-center pr-1 pl-2 text-muted-foreground\">\n          <Link className=\"size-4\" />\n        </div>\n\n        <FloatingLinkUrlInput\n          className={inputVariants()}\n          placeholder=\"Paste link\"\n          data-plate-focus\n        />\n      </div>\n      <Separator className=\"my-1\" />\n      <div className=\"flex items-center\">\n        <div className=\"flex items-center pr-1 pl-2 text-muted-foreground\">\n          <Text className=\"size-4\" />\n        </div>\n        <input\n          className={inputVariants()}\n          placeholder=\"Text to display\"\n          data-plate-focus\n          {...textInputProps}\n        />\n      </div>\n    </div>\n  );\n\n  const editContent = editState.isEditing ? (\n    input\n  ) : (\n    <div className=\"box-content flex items-center\">\n      <button\n        className={buttonVariants({ size: 'sm', variant: 'ghost' })}\n        type=\"button\"\n        {...editButtonProps}\n      >\n        Edit link\n      </button>\n\n      <Separator orientation=\"vertical\" />\n\n      <LinkOpenButton />\n\n      <Separator orientation=\"vertical\" />\n\n      <button\n        className={buttonVariants({\n          size: 'sm',\n          variant: 'ghost',\n        })}\n        type=\"button\"\n        {...unlinkButtonProps}\n      >\n        <Unlink width={18} />\n      </button>\n    </div>\n  );\n\n  return (\n    <>\n      <div ref={insertRef} className={popoverVariants()} {...insertProps}>\n        {input}\n      </div>\n\n      <div ref={editRef} className={popoverVariants()} {...editProps}>\n        {editContent}\n      </div>\n    </>\n  );\n}\n\nfunction LinkOpenButton() {\n  const editor = useEditorRef();\n  const selection = useEditorSelection();\n\n  const attributes = React.useMemo(\n    () => {\n      const entry = editor.api.node<TLinkElement>({\n        match: { type: editor.getType(KEYS.link) },\n      });\n      if (!entry) {\n        return {};\n      }\n      const [element] = entry;\n      return getLinkAttributes(editor, element);\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [editor, selection]\n  );\n\n  return (\n    <a\n      {...attributes}\n      className={buttonVariants({\n        size: 'sm',\n        variant: 'ghost',\n      })}\n      onMouseOver={(e) => {\n        e.stopPropagation();\n      }}\n      aria-label=\"Open link in a new tab\"\n      target=\"_blank\"\n    >\n      <ExternalLink width={18} />\n    </a>\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "meta": {
    "docs": [
      {
        "route": "/docs/link"
      },
      {
        "route": "/docs/api/floating"
      },
      {
        "route": "https://pro.platejs.org/docs/components/link-toolbar"
      }
    ],
    "examples": [
      "link-demo",
      "link-pro"
    ]
  },
  "type": "registry:ui"
}