Discussion
Loading...
Files
components/demo.tsx
'use client';
import * as React from 'react';
import { Plate, usePlateEditor } from 'platejs/react';
import { EditorKit } from '@/components/editor/editor-kit';
import { Editor, EditorContainer } from '@/components/ui/editor';
import { DEMO_VALUES } from './values/demo-values';
export default function Demo({ id }: { id: string }) {
const editor = usePlateEditor({
plugins: EditorKit,
value: DEMO_VALUES[id],
});
return (
<Plate editor={editor}>
<EditorContainer variant="demo">
<Editor />
</EditorContainer>
</Plate>
);
}
Features
- User Management: Store and manage user data with avatars and names
- Discussion Threads: Manage discussion data structures with comments
- Current User Tracking: Track the current active user for collaboration
- Data Storage: Pure UI plugin for storing collaboration state
- Selector API: Easy access to user data through plugin selectors
Kit Usage
Installation
The fastest way to add discussion functionality is with the DiscussionKit
, which includes the pre-configured discussionPlugin
along with its Plate UI components.
'use client';
import type { TComment } from '@/components/ui/comment';
import { createPlatePlugin } from 'platejs/react';
import { BlockDiscussion } from '@/components/ui/block-discussion';
export interface TDiscussion {
id: string;
comments: TComment[];
createdAt: Date;
isResolved: boolean;
userId: string;
documentContent?: string;
}
const discussionsData: TDiscussion[] = [
{
id: 'discussion1',
comments: [
{
id: 'comment1',
contentRich: [
{
children: [
{
text: 'Comments are a great way to provide feedback and discuss changes.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 600_000),
discussionId: 'discussion1',
isEdited: false,
userId: 'charlie',
},
{
id: 'comment2',
contentRich: [
{
children: [
{
text: 'Agreed! The link to the docs makes it easy to learn more.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 500_000),
discussionId: 'discussion1',
isEdited: false,
userId: 'bob',
},
],
createdAt: new Date(),
documentContent: 'comments',
isResolved: false,
userId: 'charlie',
},
{
id: 'discussion2',
comments: [
{
id: 'comment1',
contentRich: [
{
children: [
{
text: 'Nice demonstration of overlapping annotations with both comments and suggestions!',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 300_000),
discussionId: 'discussion2',
isEdited: false,
userId: 'bob',
},
{
id: 'comment2',
contentRich: [
{
children: [
{
text: 'This helps users understand how powerful the editor can be.',
},
],
type: 'p',
},
],
createdAt: new Date(Date.now() - 200_000),
discussionId: 'discussion2',
isEdited: false,
userId: 'charlie',
},
],
createdAt: new Date(),
documentContent: 'overlapping',
isResolved: false,
userId: 'bob',
},
];
const avatarUrl = (seed: string) =>
`https://api.dicebear.com/9.x/glass/svg?seed=${seed}`;
const usersData: Record<
string,
{ id: string; avatarUrl: string; name: string; hue?: number }
> = {
alice: {
id: 'alice',
avatarUrl: avatarUrl('alice6'),
name: 'Alice',
},
bob: {
id: 'bob',
avatarUrl: avatarUrl('bob4'),
name: 'Bob',
},
charlie: {
id: 'charlie',
avatarUrl: avatarUrl('charlie2'),
name: 'Charlie',
},
};
// This plugin is purely UI. It's only used to store the discussions and users data
export const discussionPlugin = createPlatePlugin({
key: 'discussion',
options: {
currentUserId: 'alice',
discussions: discussionsData,
users: usersData,
},
})
.configure({
render: { aboveNodes: BlockDiscussion },
})
.extendSelectors(({ getOption }) => ({
currentUser: () => getOption('users')[getOption('currentUserId')],
user: (id: string) => getOption('users')[id],
}));
export const DiscussionKit = [discussionPlugin];
BlockDiscussion
: Renders discussion UI above nodes
Add Kit
import { createPlateEditor } from 'platejs/react';
import { DiscussionKit } from '@/components/editor/plugins/discussion-kit';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
...DiscussionKit,
],
});
Manual Usage
Installation
pnpm add @platejs/comment @platejs/suggestion
Create Plugin
import { createPlatePlugin } from 'platejs/react';
import { BlockDiscussion } from '@/components/ui/block-discussion';
export interface TDiscussion {
id: string;
comments: TComment[];
createdAt: Date;
isResolved: boolean;
userId: string;
documentContent?: string;
}
const usersData = {
alice: {
id: 'alice',
avatarUrl: 'https://api.dicebear.com/9.x/glass/svg?seed=alice6',
name: 'Alice',
},
bob: {
id: 'bob',
avatarUrl: 'https://api.dicebear.com/9.x/glass/svg?seed=bob4',
name: 'Bob',
},
};
export const discussionPlugin = createPlatePlugin({
key: 'discussion',
options: {
currentUserId: 'alice',
discussions: [],
users: usersData,
},
})
.configure({
render: { aboveNodes: BlockDiscussion },
})
.extendSelectors(({ getOption }) => ({
currentUser: () => getOption('users')[getOption('currentUserId')],
user: (id: string) => getOption('users')[id],
}));
options.currentUserId
: ID of the current active useroptions.discussions
: Array of discussion data structuresoptions.users
: Object mapping user IDs to user datarender.aboveNodes
: RendersBlockDiscussion
above nodes for discussion UIselectors.currentUser
: Gets the current user dataselectors.user
: Gets user data by ID
Add Plugin
import { createPlateEditor } from 'platejs/react';
const editor = createPlateEditor({
plugins: [
// ...otherPlugins,
discussionPlugin,
],
});
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
Plugins
discussionPlugin
Pure UI plugin for managing collaboration state including users and discussion data.
Selectors
currentUser
Gets the current user data.
user
Gets user data by ID.
Types
TDiscussion
Discussion data structure containing comments and metadata.
UserData
User information structure for collaboration.