AI 光标

AiCaret 扩展会在 AI 当前插入内容的位置显示一个光标装饰。在流式操作期间,它提供实时的视觉反馈,类似于 协作光标扩展

用法

@tiptap-pro/ai-toolkit 导入 AiCaret 扩展并添加到你的编辑器扩展中。

import { AiCaret, AiToolkit } from '@tiptap-pro/ai-toolkit'

const editor = useEditor({
  extensions: [StarterKit, AiToolkit, AiCaret],
})

光标会在流式操作(如 streamHtmlstreamTooltiptapEditWorkflow)期间自动显示,流处理完成后光标消失。

配置

你可以配置光标的超时时间、用户标签和渲染方式。

AiCaret.configure({
  // 在最后一次更新后,光标保持可见的时间(毫秒)
  timeout: 2000,
  // 光标标签的用户信息
  user: {
    name: 'AI',
    color: '#a5b4fc',
  },
})

选项

选项类型默认值描述
timeoutnumber2000在最后一次更新后光标保持可见的时间(毫秒)。
user{ name: string, color: string }{ name: 'AI', color: '#a5b4fc' }光标标签中显示的名称和颜色。
render(user: AiCaretUser) => HTMLElement内置渲染函数用于自定义渲染光标 DOM 元素的函数。

CSS 样式

默认的渲染函数会创建一个带有类名 tiptap-ai-caret 的 DOM 元素和一个带有类名 tiptap-ai-caret__label 的标签。添加以下 CSS 以美化光标:

.tiptap .tiptap-ai-caret {
  border-left: 1px solid #0d0d0d;
  border-right: 1px solid #0d0d0d;
  margin-left: -1px;
  margin-right: -1px;
  pointer-events: none;
  position: relative;
  word-break: normal;
}

.tiptap .tiptap-ai-caret__label {
  border-radius: 3px 3px 3px 0;
  color: #0d0d0d;
  font-size: 12px;
  font-style: normal;
  font-weight: 600;
  left: -1px;
  line-height: normal;
  padding: 0.1rem 0.3rem;
  position: absolute;
  top: -1.4em;
  user-select: none;
  white-space: nowrap;
}

光标和标签的 border-colorbackground-color 会根据 user.color 选项内联设置。

自定义渲染

你可以提供一个自定义的 render 函数,完全控制光标的 DOM 元素。

AiCaret.configure({
  render: (user) => {
    const el = document.createElement('span')
    el.className = 'my-custom-ai-caret'
    el.style.borderColor = user.color
    el.textContent = user.name
    return el
  },
})

事件

AiCaret 扩展会通过 Tiptap 的事件 API 触发事件。你可以订阅这些事件,以响应光标的移动——例如,用自定义 UI 行为跟随 AI 的写作位置。

可用事件

事件描述载荷
aiCaret:positionChanged在流式传输或编辑操作期间,每当 AI 光标位置更新时触发。{ position: number }

position 值是一个 ProseMirror 文档位置,指向 AI 光标当前所在的位置。

订阅事件

使用 editor.on 监听事件,并在不再需要时使用 editor.off 取消订阅。

editor.on('aiCaret:positionChanged', ({ position }) => {
  console.log('AI 光标移动到了位置', position)
})

aiCaret:positionChanged 事件在流式传输期间可能会频繁触发——每个流式块都会触发一次。如果你的处理函数会执行开销较大的工作,建议使用 requestAnimationFrame 或像 lodash.throttle 这样的工具进行节流。