---
title: "使用 AI 工具包的样式建议"
description: "使用 AI 工具包为建议应用样式。"
canonical_url: "https://tiptap.zhcndoc.com/content-ai/capabilities/ai-toolkit/agents/review-changes/style-suggestions"
---

# 使用 AI 工具包的样式建议

使用 AI 工具包为建议应用样式。

当 AI 对文档进行更改时，您可以在编辑器中将这些更改显示为[建议](https://tiptap.zhcndoc.com/content-ai/capabilities/ai-toolkit/api-reference/suggestions.md)。在本指南中，您将学习如何通过修改样式来自定义建议的外观，并在其中显示自定义元素（例如菜单）。

## 为建议添加 CSS 样式

当使用默认的 `renderDecorations` 函数时，会应用以下类名：

- `.tiptap-ai-suggestion`：应用于被建议范围覆盖的内容。
- `.tiptap-ai-suggestion--selected`：当光标位于建议范围内时应用。
- `.tiptap-ai-suggestion--change-group`：当建议是多个更改组成的组而非单个更改时应用。
- `.tiptap-ai-suggestion-sub-change`：应用于更改组中的单个子更改。
- `.tiptap-ai-suggestion-diff`：应用于显示在建议范围旁边的差异部件。
- `.tiptap-ai-suggestion-diff--selected`：当光标位于建议范围内时，应用于差异部件。
- `.tiptap-ai-suggestion-diff--change-group`：当差异部件是多个更改组成的组而非单个更改时应用。
- `.tiptap-ai-suggestion-diff-sub-change`：应用于差异更改组中的单个子更改。

您可以使用上述类来样式化建议，或提供自定义的 `renderDecorations` 函数以完全控制 UI。

### CSS 样式示例

我们提供示例 CSS 样式供您快速上手。

#### 预览模式

在[预览模式](https://tiptap.zhcndoc.com/content-ai/capabilities/ai-toolkit/agents/review-changes.md#two-types-of-suggestions)中使用这些样式，以便在更改插入文档之前预览它们。

```css
/* 将删除文字高亮为红色 */
.tiptap-ai-suggestion,
.tiptap-ai-suggestion > * {
  background-color: oklch(80.8% 0.114 19.571);
  color: oklch(0.396 0.141 25.723);
}

/* 更改组的背景色较浅（子更改变为较强高亮） */
.tiptap-ai-suggestion.tiptap-ai-suggestion--change-group,
.tiptap-ai-suggestion.tiptap-ai-suggestion--change-group > *:not(.tiptap-ai-suggestion-sub-change) {
  background-color: oklch(0.936 0.032 17.717);
}

/* 行内更改组内的子更改高亮 */
.tiptap-ai-suggestion-sub-change {
  background-color: oklch(80.8% 0.114 19.571);
}

/* 将插入文字高亮为绿色 */
.tiptap-ai-suggestion-diff,
.tiptap-ai-suggestion-diff > * {
  background-color: oklch(87.1% 0.15 154.449);
}

/* 差异更改组的背景色较浅（子更改变为较强高亮） */
.tiptap-ai-suggestion-diff.tiptap-ai-suggestion-diff--change-group,
.tiptap-ai-suggestion-diff.tiptap-ai-suggestion-diff--change-group
  > *:not(.tiptap-ai-suggestion-diff-sub-change) {
  background-color: oklch(0.962 0.044 156.743);
}

/* 替换差异部件内的子更改高亮 */
.tiptap-ai-suggestion-diff-sub-change {
  background-color: oklch(87.1% 0.15 154.449);
}

/* 正确渲染表格行插入 */
.tiptap-ai-suggestion-diff:has(tr) {
  display: contents;
}

.tiptap-ai-suggestion-diff:has(tr) td,
.tiptap-ai-suggestion-diff:has(tr) th {
  background-color: oklch(87.1% 0.15 154.449);
}
```

#### 审阅模式 / 文档比较

在[审阅模式](https://tiptap.zhcndoc.com/content-ai/capabilities/ai-toolkit/agents/review-changes.md#two-types-of-suggestions)中使用这些样式，用于在文档中插入后审阅更改。

显示由[文档比较](https://tiptap.zhcndoc.com/content-ai/capabilities/ai-toolkit/advanced-guides/compare-documents.md)功能生成的建议时也使用这些样式。

```css
/* 将插入文字高亮为绿色 */
.tiptap-ai-suggestion,
.tiptap-ai-suggestion > * {
  background-color: oklch(87.1% 0.15 154.449);
}

/* 更改组的背景色较浅（子更改变为较强高亮） */
.tiptap-ai-suggestion.tiptap-ai-suggestion--change-group,
.tiptap-ai-suggestion.tiptap-ai-suggestion--change-group > *:not(.tiptap-ai-suggestion-sub-change) {
  background-color: oklch(0.962 0.044 156.743);
}

/* 行内更改组内的子更改高亮 */
.tiptap-ai-suggestion-sub-change {
  background-color: oklch(87.1% 0.15 154.449);
}

/* 将删除文字高亮为红色 */
.tiptap-ai-suggestion-diff,
.tiptap-ai-suggestion-diff > * {
  background-color: oklch(80.8% 0.114 19.571);
  color: oklch(0.396 0.141 25.723);
}

/* 差异更改组的背景色较浅（子更改变为较强高亮） */
.tiptap-ai-suggestion-diff.tiptap-ai-suggestion-diff--change-group,
.tiptap-ai-suggestion-diff.tiptap-ai-suggestion-diff--change-group
  > *:not(.tiptap-ai-suggestion-diff-sub-change) {
  background-color: oklch(0.936 0.032 17.717);
}

/* 替换差异部件内的子更改高亮 */
.tiptap-ai-suggestion-diff-sub-change {
  background-color: oklch(80.8% 0.114 19.571);
}

/* 正确渲染表格行删除 */
.tiptap-ai-suggestion-diff:has(tr) {
  display: contents;
}

.tiptap-ai-suggestion-diff:has(tr) td,
.tiptap-ai-suggestion-diff:has(tr) th {
  background-color: oklch(80.8% 0.114 19.571);
}
```

## 在建议预览中将自定义节点视图设为只读

当建议预览渲染自定义节点视图时，这些节点视图会接收到标记它们属于 AI 工具包建议的装饰。使用 `isAiToolkitSuggestionNodeView` 来检测该状态，并禁用节点视图中的编辑控件。

```tsx
import { NodeViewWrapper } from '@tiptap/react'
import { isAiToolkitSuggestionNodeView } from '@tiptap-pro/ai-toolkit'

function MathBlockNodeView({ decorations }) {
  const isAiToolkitSuggestion = isAiToolkitSuggestionNodeView(decorations)

  return (
    <NodeViewWrapper contentEditable={!isAiToolkitSuggestion}>
      {!isAiToolkitSuggestion ? <button>Edit equation</button> : null}
      {/* 在此处渲染节点视图内容。 */}
    </NodeViewWrapper>
  )
}
```

## 在建议中渲染 React 组件

您可以使用 `renderDecorations` 选项，结合[React 门户](https://react.dev/reference/react-dom/createPortal)，在建议内显示 React 组件。

首先，定义一个 React 组件并用 hook 存储 React 门户的挂载 HTML 元素。

```tsx
import { useState } from 'react'

function MyComponent() {
  const [portalElement, setPortalElement] = useState<HTMLElement | null>(null)

  return null
}
```

然后，在 `displayOptions.renderDecorations` 选项里，创建一个带有 HTML 元素的小部件装饰，用作 React 门户的入口点。

```tsx
const aiToolkit = getAiToolkit(editor)
// AI 工具包中生成建议的示例方法
aiToolkit.executeTool({
  reviewOptions: {
    mode: 'preview',
    displayOptions: {
      renderDecorations({ suggestion, defaultRenderDecorations }) {
        const decorations = defaultRenderDecorations()
        decorations.push(
          Decoration.widget(suggestion.range.to, () => {
            const element = document.createElement('span')
            setPortalElement(element)
            return element
          }),
        )
        return decorations
      },
    },
  },
})
```

最后，在 React 组件内，将任意 React 元素渲染到该门户内。

```tsx
import { useState } from 'react'
import { createPortal } from 'react-dom'

function MyComponent() {
  const [portalElement, setPortalElement] = useState<HTMLElement | null>(null)

  if (portalElement) {
    return <>{createPortal(<div>Hello, world!</div>, portalElement)}</>
  }
  return null
}
```

## 选中建议时显示弹出框或提示框

您可以使用上述技术，在选中建议时显示提示框。

若要在选中建议时显示弹出框，需要使用 `getCustomSuggestionDecoration` 选项。此函数允许您向建议中添加自定义元素，包括弹出框。

下面是使用 React UI 库实现的简化示例。

```tsx
import { useState } from 'react'
import { createPortal } from 'react-dom'

// 在 React 组件内部
function MyComponent() {
  const toolkit = getAiToolkit(editor)

  // 首先，定义 hook 存储弹出框挂载的 HTML 元素
  const [popoverElement, setPopoverElement] = useState<HTMLElement | null>(null)

  // 工具执行时，配置装饰的渲染方式
  aiToolkit.executeTool({
    reviewOptions: {
      mode: 'preview',
      displayOptions: {
        renderDecorations({ suggestion, defaultRenderDecorations }) {
          const decorations = defaultRenderDecorations()

          // 创建包含 HTML 元素的 Prosemirror 装饰
          decorations.push(
            Decoration.widget(suggestion.range.to, () => {
              const element = document.createElement('span')

              setPopoverElement(element)
              return element
            }),
          )

          return decorations
        },
      },
    },
  })

  const selectedSuggestion = toolkit.getSelectedSuggestion()

  if (popoverElement && selectedSuggestion) {
    // 将内容添加到自定义元素中。本例使用 React 门户渲染弹出框。
    return <>{createPortal(<Popover suggestion={selectedSuggestion} />, popoverElement)}</>
  }

  return null
}
```

我们推荐使用 [Floating UI](https://floating-ui.com/) 库来显示弹出框。

在弹出框中渲染建议时，可以使用 `getNextWord` 和 `getPreviousWord` 工具函数，显示建议所在句子的前后单词。

```ts
import { getNextWord, getPreviousWord } from '@tiptap-pro/ai-toolkit'

// 获取句子中的前一个单词。
const { previousWord } = getPreviousWord(editor, suggestion.range.from)
// 获取句子中的后一个单词及其后面的标点符号（如果为句尾）。
const { nextWord, punctuationMark } = getNextWord(editor, suggestion.range.to)
```

## 在编辑器外的侧边栏中显示建议

您可以通过 AI 工具包的 `getSuggestions` 方法获取当前建议。

```ts
const toolkit = getAiToolkit(editor)
const suggestions = toolkit.getSuggestions()
```

然后，您可以使用这些数据在 UI 中（编辑器外）渲染建议。以下是使用 React UI 库实现的示例：

```tsx
// 从 AI 工具包获取建议
const toolkit = getAiToolkit(editor)
const suggestions = toolkit.getSuggestions()

// 在 UI 中渲染建议
return (
  <div>
    {suggestions.map((suggestion) => (
      <div key={suggestion.id}>
        <p>删除内容: {toolkit.getTextRange(suggestion.range)}</p>
        <p>添加内容: {suggestion.replacementOptions[0].content.toString()}</p>
      </div>
    ))}
  </div>
)
```

## 后续步骤

- 在[API 参考](https://tiptap.zhcndoc.com/content-ai/capabilities/ai-toolkit/api-reference/suggestions.md)中了解更多有关建议的信息。请查看 `displayOptions` 参数以了解所有自定义选项。
