Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip: feat: comments #1376

Draft
wants to merge 39 commits into
base: main
Choose a base branch
from
Draft

wip: feat: comments #1376

wants to merge 39 commits into from

Conversation

YousefED
Copy link
Collaborator

@YousefED YousefED commented Jan 16, 2025

First POC of native comments in BlockNote.

  • We implement several Comment / Thread related components that can be customized similar to other BlockNote components. Standard implementation will support Mantine / ShadCN / Ariakit variants.
  • The storage interface (ThreadStore) will be pluggable. This means you can "bring your own provider" if you like.

Providers

YjsThreadStore

We store thread / comment information directly in yjs so it can be easily integrate with existing sync / storage mechanisms. The downside of this is that comments require a more advanced permission model than text documents; so we need to provide a workaround for this and clearly explain the pros / cons. Of course, users can always implement their own (e.g.: REST-based) ThreadStore with more advanced permissions built-in.

TODO:

  • ! add unit tests
  • add server side validation (make sure users can't edit other users comments, etc)
  • implement / document how read-only users can add comments

LiveBlocks

The UI Components are roughly based on the LiveBlocks open source components. LiveBlocks users will have two different ways to use LiveBlocks:

  • Use LiveBlocks UI components: this can be done with Feature/liveblocks v2 #1259. This would support all liveblocks functionality (read status, attachments, etc), but the style is a bit different from the other BlockNote components.
  • Use BlockNote UI components (matching your existing mantine / shadcn / ... version of BlockNote). These are "first-class" supported in BlockNote but miss some features compared to liveblocks (i.e.: read status, attachments, etc)

TODO:

  • Implement LiveBlocksThreadStore (and possibly move to separate package)

TipTap

We can probably integrate directly with the TiptapCollabProvider

TODO:

  • Implement TipTapThreadStore

UX TODOs

  • (later) implement stream threads (right sidebar)
  • (later) implement anchored threads
  • ! implement resolve / unresolve
  • ! implement reactions
  • bug: delete thread error
  • clean up mantine design
  • add icons
  • implement shadcn / ariakit
  • comment editor: auto focus
  • comment editor: disable things like text alignment, etc
  • how to show soft-deletes
  • test both dark and light mode
  • emojis: hover effects, nicer icon

Misc

TODO:

  • create a way to test with different user / role
  • ! implement user management
  • ! make sure UX reflects user auth
  • test / decide on copy / paste behaviour
  • test / fix commenting on block nodes (i.e.: images)
  • comments are not part of the blocknote schema. Is this ok? Do we want an API to access comment positions?
  • i18n
  • docs
  • fix or remove the liveblocks integration
  • review new mounting system
  • implement a REST api based version (e.g.: sample nextjs / hono api)

Copy link

vercel bot commented Jan 16, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
blocknote ✅ Ready (Inspect) Visit Preview Feb 11, 2025 1:35pm
blocknote-website ✅ Ready (Inspect) Visit Preview Feb 11, 2025 1:35pm

text={reaction.usersIds.length.toString()}
icon={reaction.emoji}
isSelected={
user && reaction.usersIds.includes(user.id)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: user is the author of the comment, not the logged in user

@@ -157,8 +157,14 @@ function BlockNoteViewComponent<
const mount = useCallback(
(element: HTMLElement | null) => {
editor.mount(element, portalManager);

// Since we mount the editor ourselves, we also have to manually
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this? shouldn't this automatically work if the contenteditable has an autofocus attribute?

@@ -126,6 +128,9 @@ export const getBlockNoteExtensions = <

ret["nodeSelectionKeyboard"] = new NodeSelectionKeyboardPlugin();

// TODO
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo, make optional / external?

@@ -244,6 +251,7 @@ const getTipTapExtensions = <
...(opts.trailingBlock === undefined || opts.trailingBlock
? [TrailingNode]
: []),
CommentMark,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo, only if comments are enabled?

@@ -0,0 +1,278 @@
import { Node } from "prosemirror-model";
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: review + document

@@ -0,0 +1,48 @@
import { EventEmitter } from "../../../util/EventEmitter.js";
import { User } from "../types.js";
export class UserStore<U extends User> extends EventEmitter<any> {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: document and review

import { BlockNoteEditor, ThreadData } from "@blocknote/core";
import { useCallback, useRef, useSyncExternalStore } from "react";

export function useThreadStore(editor: BlockNoteEditor<any, any, any>) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo, discuss with Nick

@@ -0,0 +1,8 @@
import { BlockNoteSchema, defaultBlockSpecs } from "@blocknote/core";

// TODO: disable props on paragraph
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: trim down further and decide if we want multi-line (multi-block) comments

return useUsers(editor, [userId]).get(userId);
}

export function useUsers(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: document and review with Nick

</>
);
};
export function getInstance() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: review new mounting system with nick

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants