Loading…
Kit 用法
安装
添加评论功能最快的方式是使用 CommentKit,它包含预配置的 commentPlugin 和相关组件,以及对应的 Plate UI 组件。
'use client';
import type { ExtendConfig, Path } from 'platejs';
import {
type BaseCommentConfig,
BaseCommentPlugin,
getDraftCommentKey,
} from '@platejs/comment';
import { toTPlatePlugin } from 'platejs/react';
import { CommentLeaf } from '@/components/ui/comment-node';
import { getDiscussionClickTarget } from './discussion-kit';
type CommentConfig = ExtendConfig<
BaseCommentConfig,
{
activeId: string | null;
commentingBlock: Path | null;
hoverId: string | null;
}
>;
export const commentPlugin = toTPlatePlugin<CommentConfig>(BaseCommentPlugin, {
handlers: {
onClick: ({ api, event, setOption, type }) => {
const activeTarget = getDiscussionClickTarget({
selector: `.slate-${type}`,
target: event.target,
});
if (!activeTarget) {
setOption('activeId', null);
return;
}
const commentEntry = api.comment?.node();
setOption(
'activeId',
commentEntry ? (api.comment?.nodeId(commentEntry[0]) ?? null) : null
);
},
},
options: {
activeId: null,
commentingBlock: null,
hoverId: null,
},
})
.extendTransforms(
({
editor,
setOption,
tf: {
comment: { setDraft },
},
}) => ({
setDraft: () => {
if (editor.api.isCollapsed()) {
editor.tf.select(editor.api.block()![1]);
}
setDraft();
editor.tf.collapse();
setOption('activeId', getDraftCommentKey());
setOption('commentingBlock', editor.selection!.focus.path.slice(0, 1));
},
})
)
.configure({
node: { component: CommentLeaf },
shortcuts: {
setDraft: { keys: 'mod+shift+m' },
},
});
export const CommentKit = [commentPlugin];'use client';
import type { ExtendConfig, Path } from 'platejs';
import {
type BaseCommentConfig,
BaseCommentPlugin,
getDraftCommentKey,
} from '@platejs/comment';
import { toTPlatePlugin } from 'platejs/react';
import { CommentLeaf } from '@/components/ui/comment-node';
import { getDiscussionClickTarget } from './discussion-kit';
type CommentConfig = ExtendConfig<
BaseCommentConfig,
{
activeId: string | null;
commentingBlock: Path | null;
hoverId: string | null;
}
>;
export const commentPlugin = toTPlatePlugin<CommentConfig>(BaseCommentPlugin, {
handlers: {
onClick: ({ api, event, setOption, type }) => {
const activeTarget = getDiscussionClickTarget({
selector: `.slate-${type}`,
target: event.target,
});
if (!activeTarget) {
setOption('activeId', null);
return;
}
const commentEntry = api.comment?.node();
setOption(
'activeId',
commentEntry ? (api.comment?.nodeId(commentEntry[0]) ?? null) : null
);
},
},
options: {
activeId: null,
commentingBlock: null,
hoverId: null,
},
})
.extendTransforms(
({
editor,
setOption,
tf: {
comment: { setDraft },
},
}) => ({
setDraft: () => {
if (editor.api.isCollapsed()) {
editor.tf.select(editor.api.block()![1]);
}
setDraft();
editor.tf.collapse();
setOption('activeId', getDraftCommentKey());
setOption('commentingBlock', editor.selection!.focus.path.slice(0, 1));
},
})
)
.configure({
node: { component: CommentLeaf },
shortcuts: {
setDraft: { keys: 'mod+shift+m' },
},
});
export const CommentKit = [commentPlugin];CommentLeaf: 渲染评论文本标记BlockDiscussion: 渲染带有评论集成的讨论 UI
添加 Kit
import { createPlateEditor } from 'platejs/react';
import { CommentKit } from '@/components/editor/plugins/comment-kit';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
...CommentKit,
],
});import { createPlateEditor } from 'platejs/react';
import { CommentKit } from '@/components/editor/plugins/comment-kit';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
...CommentKit,
],
});手动用法
安装
pnpm add @platejs/commentpnpm add @platejs/comment扩展评论插件
创建带有扩展配置的评论插件以进行状态管理:
import { type ExtendConfig, type Path, isSlateString } from 'platejs';
import {
type BaseCommentConfig,
BaseCommentPlugin,
getDraftCommentKey,
} from '@platejs/comment';
import { toTPlatePlugin } from 'platejs/react';
import { CommentLeaf } from '@/components/ui/comment-node';
type CommentConfig = ExtendConfig<
BaseCommentConfig,
{
activeId: string | null;
commentingBlock: Path | null;
hoverId: string | null;
}
>;
export const commentPlugin = toTPlatePlugin<CommentConfig>(
BaseCommentPlugin,
({ editor }) => ({
options: {
activeId: null,
commentingBlock: null,
hoverId: null,
},
render: {
node: CommentLeaf,
},
})
);import { type ExtendConfig, type Path, isSlateString } from 'platejs';
import {
type BaseCommentConfig,
BaseCommentPlugin,
getDraftCommentKey,
} from '@platejs/comment';
import { toTPlatePlugin } from 'platejs/react';
import { CommentLeaf } from '@/components/ui/comment-node';
type CommentConfig = ExtendConfig<
BaseCommentConfig,
{
activeId: string | null;
commentingBlock: Path | null;
hoverId: string | null;
}
>;
export const commentPlugin = toTPlatePlugin<CommentConfig>(
BaseCommentPlugin,
({ editor }) => ({
options: {
activeId: null,
commentingBlock: null,
hoverId: null,
},
render: {
node: CommentLeaf,
},
})
);options.activeId: 当前激活的评论 ID,用于视觉高亮options.commentingBlock: 当前正在评论的块的路径options.hoverId: 当前悬停的评论 ID,用于悬停效果render.node: 指定CommentLeaf来渲染评论文本标记
添加点击处理器
添加点击处理来管理激活评论状态:
export const commentPlugin = toTPlatePlugin<CommentConfig>(
BaseCommentPlugin,
({ editor }) => ({
handlers: {
// Set active comment when clicking on comment marks
onClick: ({ api, event, setOption, type }) => {
let leaf = event.target as HTMLElement;
let isSet = false;
const unsetActiveComment = () => {
setOption('activeId', null);
isSet = true;
};
if (!isSlateString(leaf)) unsetActiveComment();
while (leaf.parentElement) {
if (leaf.classList.contains(`slate-${type}`)) {
const commentsEntry = api.comment.node();
if (!commentsEntry) {
unsetActiveComment();
break;
}
const id = api.comment.nodeId(commentsEntry[0]);
setOption('activeId', id ?? null);
isSet = true;
break;
}
leaf = leaf.parentElement;
}
if (!isSet) unsetActiveComment();
},
},
// ... previous options and render
})
);export const commentPlugin = toTPlatePlugin<CommentConfig>(
BaseCommentPlugin,
({ editor }) => ({
handlers: {
// Set active comment when clicking on comment marks
onClick: ({ api, event, setOption, type }) => {
let leaf = event.target as HTMLElement;
let isSet = false;
const unsetActiveComment = () => {
setOption('activeId', null);
isSet = true;
};
if (!isSlateString(leaf)) unsetActiveComment();
while (leaf.parentElement) {
if (leaf.classList.contains(`slate-${type}`)) {
const commentsEntry = api.comment.node();
if (!commentsEntry) {
unsetActiveComment();
break;
}
const id = api.comment.nodeId(commentsEntry[0]);
setOption('activeId', id ?? null);
isSet = true;
break;
}
leaf = leaf.parentElement;
}
if (!isSet) unsetActiveComment();
},
},
// ... previous options and render
})
);点击处理器追踪当前激活的评论:
- 检测评论点击: 遍历 DOM 以找到评论元素
- 设置激活状态: 点击评论时更新
activeId - 清除状态: 点击评论外部时取消
activeId - 视觉反馈: 在评论组件中启用悬停/激活样式
扩展 Transforms
扩展 setDraft transform 以增强功能:
export const commentPlugin = toTPlatePlugin<CommentConfig>(
BaseCommentPlugin,
({ editor }) => ({
// ... previous configuration
})
)
.extendTransforms(
({
editor,
setOption,
tf: {
comment: { setDraft },
},
}) => ({
setDraft: () => {
if (editor.api.isCollapsed()) {
editor.tf.select(editor.api.block()![1]);
}
setDraft();
editor.tf.collapse();
setOption('activeId', getDraftCommentKey());
setOption('commentingBlock', editor.selection!.focus.path.slice(0, 1));
},
})
)
.configure({
node: { component: CommentLeaf },
shortcuts: {
setDraft: { keys: 'mod+shift+m' },
},
});export const commentPlugin = toTPlatePlugin<CommentConfig>(
BaseCommentPlugin,
({ editor }) => ({
// ... previous configuration
})
)
.extendTransforms(
({
editor,
setOption,
tf: {
comment: { setDraft },
},
}) => ({
setDraft: () => {
if (editor.api.isCollapsed()) {
editor.tf.select(editor.api.block()![1]);
}
setDraft();
editor.tf.collapse();
setOption('activeId', getDraftCommentKey());
setOption('commentingBlock', editor.selection!.focus.path.slice(0, 1));
},
})
)
.configure({
node: { component: CommentLeaf },
shortcuts: {
setDraft: { keys: 'mod+shift+m' },
},
});添加工具栏按钮
你可以将 CommentToolbarButton 添加到你的工具栏中,以便在选中文本上添加评论。
添加插件
import { createPlateEditor } from 'platejs/react';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
commentPlugin,
],
});import { createPlateEditor } from 'platejs/react';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
commentPlugin,
],
});讨论集成
评论插件与讨论插件配合使用,实现完整的协作功能:
import { discussionPlugin } from '@/components/editor/plugins/discussion-kit';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
discussionPlugin,
commentPlugin,
],
});import { discussionPlugin } from '@/components/editor/plugins/discussion-kit';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
discussionPlugin,
commentPlugin,
],
});键盘快捷键
| Key | Description |
|---|---|
| Cmd + Shift + M | 在选中文本上添加评论。 |
Plate Plus
- Full stack example for Suggestion and Comment
- Floating comments & suggestions UI with better user experience
- Comment rendered with Plate editor
- Discussion list in the sidebar
插件
CommentPlugin
用于创建和管理文本评论的插件,支持状态追踪和讨论集成。
API
api.comment.has
检查编辑器中是否存在指定 ID 的评论。
api.comment.node
获取评论节点条目。
api.comment.nodeId
从叶子节点获取评论的 ID。
api.comment.nodes
获取匹配选项的所有评论节点条目。
Transforms
tf.comment.removeMark
从当前选区或指定位置移除评论标记。
tf.comment.setDraft
在当前选区设置草稿评论标记。
tf.comment.unsetMark
从编辑器中取消指定 ID 的评论节点。
工具函数
getCommentCount
获取评论节点中非草稿评论的数量。
getCommentKey
根据提供的 ID 生成评论键。
getCommentKeyId
从评论键中提取评论 ID。
getCommentKeys
返回给定节点中存在的评论键数组。
getDraftCommentKey
获取用于草稿评论的键。
isCommentKey
检查给定的键是否是评论键。
isCommentNodeById
检查给定节点是否是具有指定 ID 的评论。
类型
TCommentText
可以包含评论的文本节点。
On This Page
功能特性Kit 用法安装添加 Kit手动用法安装扩展评论插件添加点击处理器扩展 Transforms添加工具栏按钮添加插件讨论集成键盘快捷键Plate Plus插件CommentPluginAPIapi.comment.hasapi.comment.nodeapi.comment.nodeIdapi.comment.nodesTransformstf.comment.removeMarktf.comment.setDrafttf.comment.unsetMark工具函数getCommentCountgetCommentKeygetCommentKeyIdgetCommentKeysgetDraftCommentKeyisCommentKeyisCommentNodeById类型TCommentText