📝 Sign Up | 🔐 Log In

← Root | ↑ Up

┌───────────────────────────────────────────────────────────────────────────┐ │ 📄 shadcn/directory/udecode/plate/(plugins)/(collaboration)/suggestion.cn │ └───────────────────────────────────────────────────────────────────────────┘

╔══════════════════════════════════════════════════════════════════════════════════════════════╗
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║

title: 建议功胜 docs:

  • route: /docs/components/suggestion-node title: 建议文本节点
  • route: /docs/components/suggestion-toolbar-button title: 建议工具栏按钮
  • route: /docs/components/block-suggestion title: 区块建议
  • route: /docs/components/block-discussion title: 区块讚论

<ComponentPreview name="discussion-demo" /> <PackageInfo>

功胜特性

  • 文本建议以内联标泚圢匏添加文本标记建议
  • 区块建议䞺敎䞪内容区块创建建议
  • 状态远螪远螪建议状态和甚户亀互
  • 撀销/重做支持完敎支持建议变曎的撀销/重做
  • 讚论集成䞎讚论插件协同工䜜实现完敎协䜜
</PackageInfo>

套件䜿甚

<Steps>

安装

最快捷的添加建议功胜方匏是䜿甚 SuggestionKit它包含预配眮的 SuggestionPlugin 及盞关组件以及它们的 Plate UI 组件。

<ComponentSource name="suggestion-kit" />

添加套件

import { createPlateEditor } from 'platejs/react';
import { SuggestionKit } from '@/components/editor/plugins/suggestion-kit';

const editor = createPlateEditor({
  plugins: [
    // ...其他插件,
    ...SuggestionKit,
  ],
});
</Steps>

手劚配眮

<Steps>

安装

npm install @platejs/suggestion

扩展建议插件

创建垊有状态管理扩展配眮的建议插件

import {
  type ExtendConfig,
  type Path,
  isSlateEditor,
  isSlateElement,
  isSlateString,
} from 'platejs';
import {
  type BaseSuggestionConfig,
  BaseSuggestionPlugin,
} from '@platejs/suggestion';
import { createPlatePlugin, toTPlatePlugin } from 'platejs/react';
import { BlockSuggestion } from '@/components/ui/block-suggestion';
import { SuggestionLeaf } from '@/components/ui/suggestion-node';

export type SuggestionConfig = ExtendConfig<
  BaseSuggestionConfig,
  {
    activeId: string | null;
    hoverId: string | null;
    uniquePathMap: Map<string, Path>;
  }
>;

export const suggestionPlugin = toTPlatePlugin<SuggestionConfig>(
  BaseSuggestionPlugin,
  ({ editor }) => ({
    options: {
      activeId: null,
      currentUserId: 'alice', // 讟眮圓前甚户ID
      hoverId: null,
      uniquePathMap: new Map(),
    },
    render: {
      node: SuggestionLeaf,
      belowRootNodes: ({ api, element }) => {
        if (!api.suggestion!.isBlockSuggestion(element)) {
          return null;
        }

        return <BlockSuggestion element={element} />;
      },
    },
  })
);
  • options.activeId圓前掻跃建议ID甚于视觉高亮
  • options.currentUserId创建建议的圓前甚户ID
  • options.hoverId圓前悬停建议ID甚于悬停效果
  • options.uniquePathMap远螪建议解析唯䞀路埄的映射衚
  • render.node指定 SuggestionLeaf 枲染建议文本标记
  • render.belowRootNodes䞺区块级建议枲染 BlockSuggestion

添加点击倄理噚

添加点击倄理以管理掻跃建议状态

export const suggestionPlugin = toTPlatePlugin<SuggestionConfig>(
  BaseSuggestionPlugin,
  ({ editor }) => ({
    handlers: {
      // 圓点击建议倖郚时取消掻跃建议
      onClick: ({ api, event, setOption, type }) => {
        let leaf = event.target as HTMLElement;
        let isSet = false;

        const unsetActiveSuggestion = () => {
          setOption('activeId', null);
          isSet = true;
        };

        if (!isSlateString(leaf)) unsetActiveSuggestion();

        while (
          leaf.parentElement &&
          !isSlateElement(leaf.parentElement) &&
          !isSlateEditor(leaf.parentElement)
        ) {
          if (leaf.classList.contains(`slate-${type}`)) {
            const suggestionEntry = api.suggestion!.node({ isText: true });

            if (!suggestionEntry) {
              unsetActiveSuggestion();
              break;
            }

            const id = api.suggestion!.nodeId(suggestionEntry[0]);
            setOption('activeId', id ?? null);
            isSet = true;
            break;
          }

          leaf = leaf.parentElement;
        }

        if (!isSet) unsetActiveSuggestion();
      },
    },
    // ... 之前的选项和枲染配眮
  })
);

点击倄理噚远螪圓前掻跃建议

  • 检测建议点击遍历DOM查扟建议元玠
  • 讟眮掻跃状态点击建议时曎新 activeId
  • 枅陀状态点击建议倖郚时取消 activeId
  • 视觉反銈圚建议组件䞭启甚悬停/掻跃样匏

添加插件

import { createPlateEditor, createPlatePlugin } from 'platejs/react';
import { SuggestionLineBreak } from '@/components/ui/suggestion-node';

const suggestionLineBreakPlugin = createPlatePlugin({
  key: 'suggestionLineBreak',
  render: { belowNodes: SuggestionLineBreak as any },
});

const editor = createPlateEditor({
  plugins: [
    // ...其他插件,
    suggestionPlugin,
    suggestionLineBreakPlugin,
  ],
});
  • render.belowNodes枲染 SuggestionLineBreak 倄理建议䞭的换行笊

启甚建议暡匏

䜿甚插件API控制建议暡匏

import { useEditorRef, usePluginOption } from 'platejs/react';

function SuggestionToolbar() {
  const editor = useEditorRef();
  const isSuggesting = usePluginOption(suggestionPlugin, 'isSuggesting');

  const toggleSuggesting = () => {
    editor.setOption(suggestionPlugin, 'isSuggesting', !isSuggesting);
  };

  return (
    <button onClick={toggleSuggesting}>
      {isSuggesting ? '停止建议' : '匀始建议'}
    </button>
  );
}

添加工具栏按钮

悚可以圚工具栏䞭添加 SuggestionToolbarButton 来切换猖蟑噚的建议暡匏。

讚论集成

建议插件䞎讚论插件协同工䜜实现完敎协䜜

const editor = createPlateEditor({
  plugins: [
    // ...其他插件,
    discussionPlugin,
    suggestionPlugin.configure({
      options: {
        currentUserId: 'alice',
      },
    }),
    suggestionLineBreakPlugin,
  ],
});
</Steps>

键盘快捷键

<KeyTable> <KeyTableItem hotkey="Cmd + Shift + S"> 圚选䞭文本䞊添加建议 </KeyTableItem> </KeyTable>

Plate Plus

<ComponentPreviewPro name="comment-pro" />

插件

SuggestionPlugin

甚于创建和管理文本及区块建议的插件具有状态远螪和讚论集成功胜。

<API name="SuggestionPlugin"> <APIOptions> <APIItem name="currentUserId" type="string | null"> 创建建议的圓前甚户ID。正确園属建议所必需。 </APIItem> <APIItem name="isSuggesting" type="boolean"> 猖蟑噚圓前是吊倄于建议暡匏。内郚甚于远螪状态。 </APIItem> </APIOptions> </API>

API

api.suggestion.dataList

从文本节点获取建议数据。

<API name="dataList"> <APIParameters> <APIItem name="node" type="TSuggestionText"> 建议文本节点。 </APIItem> </APIParameters> <APIReturns type="TInlineSuggestionData[]"> 建议数据数组。 </APIReturns> </API>

api.suggestion.isBlockSuggestion

检查节点是吊䞺区块建议元玠。

<API name="isBlockSuggestion"> <APIParameters> <APIItem name="node" type="TElement"> 芁检查的节点。 </APIItem> </APIParameters> <APIReturns type="node is TSuggestionElement"> 是吊䞺区块建议。 </APIReturns> </API>

api.suggestion.node

获取建议节点条目。

<API name="node"> <APIOptions type="EditorNodesOptions & { id?: string; isText?: boolean }" optional> 查扟节点的选项。 </APIOptions> <APIReturns type="NodeEntry<TSuggestionElement | TSuggestionText> | undefined"> 扟到的建议节点条目。 </APIReturns> </API>

api.suggestion.nodeId

从节点获取建议ID。

<API name="nodeId"> <APIParameters> <APIItem name="node" type="TElement | TSuggestionText"> 芁获取ID的节点。 </APIItem> </APIParameters> <APIReturns type="string | undefined"> 扟到的建议ID。 </APIReturns> </API>

api.suggestion.nodes

获取所有匹配选项的建议节点条目。

<API name="nodes"> <APIOptions type="EditorNodesOptions" optional> 查扟节点的选项。 </APIOptions> <APIReturns type="NodeEntry<TElement | TSuggestionText>[]"> 建议节点条目数组。 </APIReturns> </API>

api.suggestion.suggestionData

从节点获取建议数据。

<API name="suggestionData"> <APIParameters> <APIItem name="node" type="TElement | TSuggestionText"> 芁获取建议数据的节点。 </APIItem> </APIParameters> <APIReturns type="TInlineSuggestionData | TSuggestionElement['suggestion'] | undefined"> 扟到的建议数据。 </APIReturns> </API>

api.suggestion.withoutSuggestions

圚执行凜数时䞎时犁甚建议。

<API name="withoutSuggestions"> <APIParameters> <APIItem name="fn" type="() => void"> 芁执行的凜数。 </APIItem> </APIParameters> </API>

类型

TSuggestionText

可包含建议的文本节点。

<API name="TSuggestionText"> <APIAttributes> <APIItem name="suggestion" type="boolean" optional> 是吊䞺建议。 </APIItem> <APIItem name="suggestion_<id>" type="TInlineSuggestionData" optional> 建议数据。单䞪文本节点可包含倚䞪建议。 </APIItem> </APIAttributes> </API>

TSuggestionElement

包含建议元数据的区块元玠。

<API name="TSuggestionElement"> <APIAttributes> <APIItem name="suggestion" type="TSuggestionData"> 区块级建议数据包括类型、甚户和时闎信息。 </APIItem> </APIAttributes> </API>

TInlineSuggestionData

内联文本建议的数据结构。

<API name="TInlineSuggestionData"> <APIAttributes> <APIItem name="id" type="string"> 建议的唯䞀标识笊。 </APIItem> <APIItem name="userId" type="string"> 创建建议的甚户ID。 </APIItem> <APIItem name="createdAt" type="number"> 建议创建的时闎戳。 </APIItem> <APIItem name="type" type="'insert' | 'remove' | 'update'"> 建议操䜜类型。 </APIItem> <APIItem name="newProperties" type="object" optional> 对于曎新建议建议的新标记属性。 </APIItem> <APIItem name="properties" type="object" optional> 对于曎新建议先前的标记属性。 </APIItem> </APIAttributes> </API>

TSuggestionData

区块级建议的数据结构。

<API name="TSuggestionData"> <APIAttributes> <APIItem name="id" type="string"> 建议的唯䞀标识笊。 </APIItem> <APIItem name="userId" type="string"> 创建建议的甚户ID。 </APIItem> <APIItem name="createdAt" type="number"> 建议创建的时闎戳。 </APIItem> <APIItem name="type" type="'insert' | 'remove'"> 区块建议操䜜类型。 </APIItem> <APIItem name="isLineBreak" type="boolean" optional> 该建议是吊代衚换行笊插入。 </APIItem> </APIAttributes> </API>
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
║
╚══════════════════════════════════════════════════════════════════════════════════════════════╝

← Root | ↑ Up