feat(editor): comment extension (#12948)

#### PR Dependency Tree


* **PR #12948** 👈
  * **PR #12980**

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Introduced inline comment functionality, allowing users to add,
resolve, and highlight comments directly within text.
  * Added a new toolbar action for inserting comments when supported.
* Inline comments are visually highlighted and can be interacted with in
the editor.

* **Enhancements**
  * Integrated a feature flag to enable or disable the comment feature.
* Improved inline manager rendering to support wrapper specs for
advanced formatting.

* **Developer Tools**
* Added mock comment provider for testing and development environments.

* **Chores**
* Updated dependencies and project references to support the new inline
comment module.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
L-Sun
2025-07-02 17:14:34 +08:00
committed by GitHub
parent a66096cdf9
commit 8ce85f708d
40 changed files with 760 additions and 14 deletions
@@ -0,0 +1,41 @@
import { createIdentifier } from '@blocksuite/global/di';
import type { DisposableMember } from '@blocksuite/global/disposable';
import type { BaseSelection, ExtensionType } from '@blocksuite/store';
export type CommentId = string;
/**
* The `CommentProvider` is an interface used to connect external comment services
* with in-editor comment operations and rendering.
* All comment-related actions within the editor are routed through
* this interface to make external requests, and the editor is notified via callbacks.
* In essence, it follows the flow: BlockSuite -> AFFiNE -> BlockSuite.
*/
export interface CommentProvider {
addComment: (selections: BaseSelection[]) => void;
resolveComment: (id: CommentId) => void;
highlightComment: (id: CommentId | null) => void;
getComments: () => CommentId[];
onCommentAdded: (
callback: (id: CommentId, selections: BaseSelection[]) => void
) => DisposableMember;
onCommentResolved: (callback: (id: CommentId) => void) => DisposableMember;
onCommentDeleted: (callback: (id: CommentId) => void) => DisposableMember;
onCommentHighlighted: (
callback: (id: CommentId | null) => void
) => DisposableMember;
}
export const CommentProviderIdentifier =
createIdentifier<CommentProvider>('comment-provider');
export const CommentProviderExtension = (
provider: CommentProvider
): ExtensionType => {
return {
setup: di => {
di.addImpl(CommentProviderIdentifier, provider);
},
};
};
@@ -0,0 +1 @@
export * from './comment-provider';
@@ -0,0 +1,9 @@
import type { Store } from '@blocksuite/store';
import type { CommentId } from './comment-provider';
export function findCommentedBlocks(store: Store, commentId: CommentId) {
return store.getAllModels().filter(block => {
return 'comment' in block.props && block.props.comment === commentId;
});
}
@@ -1,6 +1,7 @@
export * from './auto-clear-selection-service';
export * from './block-meta-service';
export * from './citation-service';
export * from './comment-service';
export * from './doc-display-meta-service';
export * from './doc-mode-service';
export * from './drag-handle-config';
@@ -58,6 +58,7 @@ export type AffineTextAttributes = AffineTextStyleAttributes & {
member: string;
notification?: string;
} | null;
[key: `comment-${string}`]: boolean | null;
};
export type AffineInlineEditor = InlineEditor<AffineTextAttributes>;