添加链接弹出框 UI 组件

Available for free

用于创建和编辑链接的弹出框。

安装

您可以通过 Tiptap CLI(适用于 Vite 或 Next.js)添加组件:

npx @tiptap/cli@latest add link-popover

手动集成

对于 Vite 或 Next.js 以外的框架,请从 开源仓库 手动添加组件。

导入样式

此组件需要您导入我们的样式,这些样式已添加到 styles/keyframe-animation.scssstyles/_variables.scss 中。

使用

<LinkPopover />

一个为 Tiptap 编辑器提供完整链接编辑界面的预制 React 组件,带有弹出框。用户友好的弹出界面支持键盘快捷键和灵活的自定义选项,可轻松添加、编辑和删除链接。

使用范例

import { EditorContent, EditorContext, useEditor } from '@tiptap/react'
import { StarterKit } from '@tiptap/starter-kit'
import { Link } from '@/components/tiptap-extension/link-extension'
import { LinkPopover } from '@/components/tiptap-ui/link-popover'

import '@/components/tiptap-node/paragraph-node/paragraph-node.scss'

export default function MyEditor() {
  const editor = useEditor({
    immediatelyRender: false,
    extensions: [StarterKit, Link.configure({ openOnClick: false })],
    content: `
        <p>点击按钮打开链接弹出框。</p>
        <p><a href="https://www.tiptap.dev">Tiptap</a></p>
        `,
  })

  return (
    <EditorContext.Provider value={{ editor }}>
      <LinkPopover
        editor={editor}
        hideWhenUnavailable={true}
        autoOpenOnLinkActive={true}
        onSetLink={() => console.log('Link set!')}
        onOpenChange={(isOpen) => console.log('Popover opened:', isOpen)}
      />

      <EditorContent editor={editor} role="presentation" />
    </EditorContext.Provider>
  )
}

参数说明

名称类型默认值描述
editorEditor | nullnullTiptap 编辑器实例
hideWhenUnavailablebooleanfalse链接功能不可用时是否隐藏按钮
onSetLink() => void-成功设置链接后的回调
onOpenChange(isOpen: boolean) => void-弹出框打开状态改变时的回调
autoOpenOnLinkActivebooleantrue链接激活时是否自动打开弹出框

<LinkButton />

一个独立的链接按钮组件,用以触发链接相关功能。

使用范例

<LinkButton onClick={handleClick} aria-label="添加链接">
  自定义链接内容
</LinkButton>

<LinkContent />

一个独立组件,渲染链接编辑界面,但不包含弹出框包装。

使用范例

<LinkContent editor={editor} />

Hooks

useLinkPopover()

自定义钩子,可构建自定义链接界面,全面控制渲染及行为。

使用范例

function MyLinkButton() {
  const { isVisible, canSet, isActive, url, setUrl, setLink, removeLink, label, Icon } =
    useLinkPopover({
      editor: myEditor,
      hideWhenUnavailable: true,
      onSetLink: () => console.log('Link set!'),
    })

  if (!isVisible) return null

  return (
    <div>
      <button onClick={setLink} disabled={!canSet} aria-label={label} aria-pressed={isActive}>
        <Icon />
        {label}
      </button>
      <input
        type="url"
        value={url}
        onChange={(e) => setUrl(e.target.value)}
        placeholder="请输入 URL..."
      />
      <button onClick={removeLink}>移除</button>
    </div>
  )
}

参数说明

名称类型默认值描述
editorEditor | null-Tiptap 编辑器实例
hideWhenUnavailablebooleanfalse链接不能应用时是否隐藏功能
onSetLink() => void-设置链接后的回调

返回值说明

NameTypeDescription
isVisiblebooleanWhether the link functionality should be rendered
canSetbooleanIf a link can be set in the current context
isActivebooleanIf a link is currently active/selected
urlstringCurrent URL value for the link
setUrlReact.Dispatch<React.SetStateAction<string | null>>Function to update the URL state
setLink() => voidFunction to apply the link in the editor
removeLink() => voidFunction to remove the link from the editor
labelstringAccessible label text for the button
IconReact.FCIcon component for the link button

useLinkHandler()

专注于处理链接操作的钩子,不包含 UI 状态管理。

使用范例

function MyCustomLinkInterface() {
  const { url, setUrl, setLink, removeLink } = useLinkHandler({
    editor: myEditor,
    onSetLink: () => console.log('链接已应用!'),
  })

  return (
    <div>
      <input
        value={url}
        onChange={(e) => setUrl(e.target.value)}
        onKeyDown={(e) => e.key === 'Enter' && setLink()}
      />
      <button onClick={setLink}>应用</button>
      <button onClick={removeLink}>移除</button>
    </div>
  )
}

参数说明

NameTypeDefaultDescription
editorEditor | nullundefinedThe Tiptap editor instance
onSetLink() => voidundefinedCallback fired after setting a link

返回值说明

NameTypeDescription
urlstringCurrent URL value for the link
setUrlReact.Dispatch<React.SetStateAction<string | null>>Function to update the URL state
setLink() => voidFunction to apply the link in the editor
removeLink() => voidFunction to remove the link from the editor

工具函数

canSetLink(editor)

判断当前编辑器状态是否允许设置链接。

import { canSetLink } from '@/components/tiptap-ui/link-popover'

const canSet = canSetLink(editor)
if (canSet) {
  console.log('当前选区可应用链接')
}

isLinkActive(editor)

判断编辑器中是否当前处于链接激活状态。

import { isLinkActive } from '@/components/tiptap-ui/link-popover'

const isActive = isLinkActive(editor)
if (isActive) {
  console.log('当前已选中链接')
}

键盘快捷键

链接弹出框支持以下键盘操作:

  • Enter:应用当前输入框中 URL 作为链接(当焦点在 URL 输入框时)
  • Escape:关闭弹出框(标准弹出框行为)

需求

依赖

  • @tiptap/react - Tiptap React 核心集成
  • @tiptap/extension-link - 链接功能扩展

使用到的参考组件

  • use-tiptap-editor(钩子)
  • use-mobile(钩子)
  • use-link-popover(钩子)
  • button(原语)
  • popover(原语)
  • card(原语)
  • input(原语)
  • separator(原语)
  • tiptap-utils(库)
  • corner-down-left-icon(图标)
  • external-link-icon(图标)
  • link-icon(图标)
  • trash-icon(图标)