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

View File

@@ -80,6 +80,8 @@ const usePatchSpecs = (mode: DocMode) => {
featureFlagService.flags.enable_pdf_embed_preview.$
);
const enableComment = useLiveData(featureFlagService.flags.enable_comment.$);
const patchedSpecs = useMemo(() => {
const manager = getViewManager()
.config.init()
@@ -106,7 +108,8 @@ const usePatchSpecs = (mode: DocMode) => {
.mobile(framework)
.electron(framework)
.linkPreview(framework)
.codeBlockHtmlPreview(framework).value;
.codeBlockHtmlPreview(framework)
.comment(enableComment).value;
if (BUILD_CONFIG.isMobileEdition) {
if (mode === 'page') {
@@ -122,6 +125,7 @@ const usePatchSpecs = (mode: DocMode) => {
enableAI,
enablePDFEmbedPreview,
enableTurboRenderer,
enableComment,
framework,
isInPeekView,
isCloud,

View File

@@ -2,6 +2,7 @@ import type { ReactToLit } from '@affine/component';
import { AIViewExtension } from '@affine/core/blocksuite/view-extensions/ai';
import { CloudViewExtension } from '@affine/core/blocksuite/view-extensions/cloud';
import { CodeBlockPreviewViewExtension } from '@affine/core/blocksuite/view-extensions/code-block-preview';
import { CommentViewExtension } from '@affine/core/blocksuite/view-extensions/comment';
import { AffineDatabaseViewExtension } from '@affine/core/blocksuite/view-extensions/database';
import {
EdgelessBlockHeaderConfigViewExtension,
@@ -56,6 +57,7 @@ type Configure = {
electron: (framework?: FrameworkProvider) => Configure;
linkPreview: (framework?: FrameworkProvider) => Configure;
codeBlockHtmlPreview: (framework?: FrameworkProvider) => Configure;
comment: (enableComment?: boolean) => Configure;
value: ViewExtensionManager;
};
@@ -116,6 +118,7 @@ class ViewProvider {
electron: this._configureElectron,
linkPreview: this._configureLinkPreview,
codeBlockHtmlPreview: this._configureCodeBlockHtmlPreview,
comment: this._configureComment,
value: this._manager,
};
}
@@ -137,7 +140,8 @@ class ViewProvider {
.ai()
.electron()
.linkPreview()
.codeBlockHtmlPreview();
.codeBlockHtmlPreview()
.comment();
return this.config;
};
@@ -323,6 +327,11 @@ class ViewProvider {
this._manager.configure(CodeBlockPreviewViewExtension, { framework });
return this.config;
};
private readonly _configureComment = (enableComment?: boolean) => {
this._manager.configure(CommentViewExtension, { enableComment });
return this.config;
};
}
export function getViewManager() {

View File

@@ -0,0 +1,14 @@
import { noop } from '@blocksuite/affine/global/utils';
import { CommentProviderExtension } from '@blocksuite/affine/shared/services';
export const AffineCommentProvider = CommentProviderExtension({
addComment: noop,
resolveComment: noop,
highlightComment: noop,
getComments: () => [],
onCommentAdded: () => noop,
onCommentResolved: () => noop,
onCommentDeleted: () => noop,
onCommentHighlighted: () => noop,
});

View File

@@ -0,0 +1,27 @@
import {
type ViewExtensionContext,
ViewExtensionProvider,
} from '@blocksuite/affine/ext-loader';
import z from 'zod';
import { AffineCommentProvider } from './comment-provider';
const optionsSchema = z.object({
enableComment: z.boolean().optional(),
});
export class CommentViewExtension extends ViewExtensionProvider {
override name = 'comment';
override schema = optionsSchema;
override setup(
context: ViewExtensionContext,
options?: z.infer<typeof optionsSchema>
) {
super.setup(context, options);
if (!options?.enableComment) return;
context.register([AffineCommentProvider]);
}
}