mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-06 03:49:56 +08:00
feat(editor): comment for edgeless element (#13098)
#### PR Dependency Tree * **PR #13098** 👈 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** * Added support for comments on graphical elements, allowing users to comment on both blocks and graphical elements within surfaces. * Enhanced comment previews to include graphical elements in selection summaries. * Improved editor navigation to focus on commented graphical elements in addition to blocks and inline texts. * **Bug Fixes** * Updated comment highlighting and management to consistently use the new comment manager across all block and element types. * **Refactor** * Renamed and extended the comment manager to handle both block and element comments. * Streamlined toolbar configurations by removing outdated comment button entries and adding a consolidated comment button in the root toolbar. * **Tests** * Disabled the mock comment provider integration in the test editor environment to refine testing setup. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -17,7 +17,7 @@ import {
|
|||||||
AttachmentBlockStyles,
|
AttachmentBlockStyles,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
CitationProvider,
|
CitationProvider,
|
||||||
DocModeProvider,
|
DocModeProvider,
|
||||||
FileSizeLimitProvider,
|
FileSizeLimitProvider,
|
||||||
@@ -96,7 +96,7 @@ export class AttachmentBlockComponent extends CaptionedBlockComponent<Attachment
|
|||||||
get isCommentHighlighted() {
|
get isCommentHighlighted() {
|
||||||
return (
|
return (
|
||||||
this.std
|
this.std
|
||||||
.getOptional(BlockCommentManager)
|
.getOptional(BlockElementCommentManager)
|
||||||
?.isBlockCommentHighlighted(this.model) ?? false
|
?.isBlockCommentHighlighted(this.model) ?? false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
} from '@blocksuite/affine-shared/consts';
|
} from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
blockCommentToolbarButton,
|
|
||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
type ToolbarActionGroup,
|
type ToolbarActionGroup,
|
||||||
type ToolbarModuleConfig,
|
type ToolbarModuleConfig,
|
||||||
@@ -241,10 +240,6 @@ const builtinToolbarConfig = {
|
|||||||
replaceAction,
|
replaceAction,
|
||||||
downloadAction,
|
downloadAction,
|
||||||
captionAction,
|
captionAction,
|
||||||
{
|
|
||||||
id: 'f.comment',
|
|
||||||
...blockCommentToolbarButton,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
placement: ActionPlacement.More,
|
placement: ActionPlacement.More,
|
||||||
id: 'a.clipboard',
|
id: 'a.clipboard',
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import type {
|
|||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import { ImageProxyService } from '@blocksuite/affine-shared/adapters';
|
import { ImageProxyService } from '@blocksuite/affine-shared/adapters';
|
||||||
import {
|
import {
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
CitationProvider,
|
CitationProvider,
|
||||||
DocModeProvider,
|
DocModeProvider,
|
||||||
LinkPreviewServiceIdentifier,
|
LinkPreviewServiceIdentifier,
|
||||||
@@ -132,7 +132,7 @@ export class BookmarkBlockComponent extends CaptionedBlockComponent<BookmarkBloc
|
|||||||
get isCommentHighlighted() {
|
get isCommentHighlighted() {
|
||||||
return (
|
return (
|
||||||
this.std
|
this.std
|
||||||
.getOptional(BlockCommentManager)
|
.getOptional(BlockElementCommentManager)
|
||||||
?.isBlockCommentHighlighted(this.model) ?? false
|
?.isBlockCommentHighlighted(this.model) ?? false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import {
|
|||||||
} from '@blocksuite/affine-shared/consts';
|
} from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
blockCommentToolbarButton,
|
|
||||||
EmbedIframeService,
|
EmbedIframeService,
|
||||||
EmbedOptionProvider,
|
EmbedOptionProvider,
|
||||||
type LinkEventType,
|
type LinkEventType,
|
||||||
@@ -289,10 +288,6 @@ const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
} satisfies ToolbarActionGroup<ToolbarAction>,
|
} satisfies ToolbarActionGroup<ToolbarAction>,
|
||||||
captionAction,
|
captionAction,
|
||||||
{
|
|
||||||
id: 'e.comment',
|
|
||||||
...blockCommentToolbarButton,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
placement: ActionPlacement.More,
|
placement: ActionPlacement.More,
|
||||||
id: 'a.clipboard',
|
id: 'a.clipboard',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
EDGELESS_TOP_CONTENTEDITABLE_SELECTOR,
|
EDGELESS_TOP_CONTENTEDITABLE_SELECTOR,
|
||||||
} from '@blocksuite/affine-shared/consts';
|
} from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
DocModeProvider,
|
DocModeProvider,
|
||||||
NotificationProvider,
|
NotificationProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
@@ -394,7 +394,7 @@ export class CodeBlockComponent extends CaptionedBlockComponent<CodeBlockModel>
|
|||||||
get isCommentHighlighted() {
|
get isCommentHighlighted() {
|
||||||
return (
|
return (
|
||||||
this.std
|
this.std
|
||||||
.getOptional(BlockCommentManager)
|
.getOptional(BlockElementCommentManager)
|
||||||
?.isBlockCommentHighlighted(this.model) ?? false
|
?.isBlockCommentHighlighted(this.model) ?? false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { toast } from '@blocksuite/affine-components/toast';
|
|||||||
import type { DatabaseBlockModel } from '@blocksuite/affine-model';
|
import type { DatabaseBlockModel } from '@blocksuite/affine-model';
|
||||||
import { EDGELESS_TOP_CONTENTEDITABLE_SELECTOR } from '@blocksuite/affine-shared/consts';
|
import { EDGELESS_TOP_CONTENTEDITABLE_SELECTOR } from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
CommentProviderIdentifier,
|
CommentProviderIdentifier,
|
||||||
DocModeProvider,
|
DocModeProvider,
|
||||||
NotificationProvider,
|
NotificationProvider,
|
||||||
@@ -316,7 +316,7 @@ export class DatabaseBlockComponent extends CaptionedBlockComponent<DatabaseBloc
|
|||||||
get isCommentHighlighted() {
|
get isCommentHighlighted() {
|
||||||
return (
|
return (
|
||||||
this.std
|
this.std
|
||||||
.getOptional(BlockCommentManager)
|
.getOptional(BlockElementCommentManager)
|
||||||
?.isBlockCommentHighlighted(this.model) ?? false
|
?.isBlockCommentHighlighted(this.model) ?? false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from '@blocksuite/affine-shared/consts';
|
} from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
blockCommentToolbarButton,
|
|
||||||
DocDisplayMetaProvider,
|
DocDisplayMetaProvider,
|
||||||
EditorSettingProvider,
|
EditorSettingProvider,
|
||||||
type LinkEventType,
|
type LinkEventType,
|
||||||
@@ -306,10 +305,6 @@ const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
} satisfies ToolbarActionGroup<ToolbarAction>,
|
} satisfies ToolbarActionGroup<ToolbarAction>,
|
||||||
captionAction,
|
captionAction,
|
||||||
{
|
|
||||||
id: 'e.comment',
|
|
||||||
...blockCommentToolbarButton,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
placement: ActionPlacement.More,
|
placement: ActionPlacement.More,
|
||||||
id: 'a.clipboard',
|
id: 'a.clipboard',
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
|
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
blockCommentToolbarButton,
|
|
||||||
EditorSettingProvider,
|
EditorSettingProvider,
|
||||||
type LinkEventType,
|
type LinkEventType,
|
||||||
type OpenDocMode,
|
type OpenDocMode,
|
||||||
@@ -226,10 +225,6 @@ const builtinToolbarConfig = {
|
|||||||
openDocActionGroup,
|
openDocActionGroup,
|
||||||
conversionsActionGroup,
|
conversionsActionGroup,
|
||||||
captionAction,
|
captionAction,
|
||||||
{
|
|
||||||
id: 'e.comment',
|
|
||||||
...blockCommentToolbarButton,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
placement: ActionPlacement.More,
|
placement: ActionPlacement.More,
|
||||||
id: 'a.clipboard',
|
id: 'a.clipboard',
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
EMBED_CARD_WIDTH,
|
EMBED_CARD_WIDTH,
|
||||||
} from '@blocksuite/affine-shared/consts';
|
} from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
DocModeProvider,
|
DocModeProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
|
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
|
||||||
@@ -65,7 +65,7 @@ export class EmbedBlockComponent<
|
|||||||
get isCommentHighlighted() {
|
get isCommentHighlighted() {
|
||||||
return (
|
return (
|
||||||
this.std
|
this.std
|
||||||
.getOptional(BlockCommentManager)
|
.getOptional(BlockElementCommentManager)
|
||||||
?.isBlockCommentHighlighted(this.model) ?? false
|
?.isBlockCommentHighlighted(this.model) ?? false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
} from '@blocksuite/affine-shared/consts';
|
} from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
blockCommentToolbarButton,
|
|
||||||
EmbedOptionProvider,
|
EmbedOptionProvider,
|
||||||
type LinkEventType,
|
type LinkEventType,
|
||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
@@ -349,10 +348,6 @@ function createBuiltinToolbarConfigForExternal(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'e.comment',
|
|
||||||
...blockCommentToolbarButton,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
placement: ActionPlacement.More,
|
placement: ActionPlacement.More,
|
||||||
id: 'a.clipboard',
|
id: 'a.clipboard',
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { ImageBlockModel } from '@blocksuite/affine-model';
|
import { ImageBlockModel } from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
blockCommentToolbarButton,
|
|
||||||
type ToolbarModuleConfig,
|
type ToolbarModuleConfig,
|
||||||
ToolbarModuleExtension,
|
ToolbarModuleExtension,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
@@ -50,10 +49,6 @@ const builtinToolbarConfig = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'c.comment',
|
|
||||||
...blockCommentToolbarButton,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
placement: ActionPlacement.More,
|
placement: ActionPlacement.More,
|
||||||
id: 'a.clipboard',
|
id: 'a.clipboard',
|
||||||
@@ -146,10 +141,6 @@ const builtinSurfaceToolbarConfig = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'c.comment',
|
|
||||||
...blockCommentToolbarButton,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
when: ctx => ctx.getSurfaceModelsByType(ImageBlockModel).length === 1,
|
when: ctx => ctx.getSurfaceModelsByType(ImageBlockModel).length === 1,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { ResourceController } from '@blocksuite/affine-components/resource';
|
|||||||
import type { ImageBlockModel } from '@blocksuite/affine-model';
|
import type { ImageBlockModel } from '@blocksuite/affine-model';
|
||||||
import { ImageSelection } from '@blocksuite/affine-shared/selection';
|
import { ImageSelection } from '@blocksuite/affine-shared/selection';
|
||||||
import {
|
import {
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
ToolbarRegistryIdentifier,
|
ToolbarRegistryIdentifier,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { formatSize } from '@blocksuite/affine-shared/utils';
|
import { formatSize } from '@blocksuite/affine-shared/utils';
|
||||||
@@ -71,7 +71,7 @@ export class ImageBlockComponent extends CaptionedBlockComponent<ImageBlockModel
|
|||||||
get isCommentHighlighted() {
|
get isCommentHighlighted() {
|
||||||
return (
|
return (
|
||||||
this.std
|
this.std
|
||||||
.getOptional(BlockCommentManager)
|
.getOptional(BlockElementCommentManager)
|
||||||
?.isBlockCommentHighlighted(this.model) ?? false
|
?.isBlockCommentHighlighted(this.model) ?? false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
EDGELESS_TOP_CONTENTEDITABLE_SELECTOR,
|
EDGELESS_TOP_CONTENTEDITABLE_SELECTOR,
|
||||||
} from '@blocksuite/affine-shared/consts';
|
} from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
CitationProvider,
|
CitationProvider,
|
||||||
DocModeProvider,
|
DocModeProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
@@ -112,7 +112,7 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<ParagraphBl
|
|||||||
get isCommentHighlighted() {
|
get isCommentHighlighted() {
|
||||||
return (
|
return (
|
||||||
this.std
|
this.std
|
||||||
.getOptional(BlockCommentManager)
|
.getOptional(BlockElementCommentManager)
|
||||||
?.isBlockCommentHighlighted(this.model) ?? false
|
?.isBlockCommentHighlighted(this.model) ?? false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
|
blockCommentToolbarButton,
|
||||||
type ElementLockEvent,
|
type ElementLockEvent,
|
||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
type ToolbarContext,
|
type ToolbarContext,
|
||||||
@@ -305,6 +306,12 @@ export const builtinMiscToolbarConfig = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
placement: ActionPlacement.End,
|
||||||
|
id: 'c.comment',
|
||||||
|
...blockCommentToolbarButton,
|
||||||
|
},
|
||||||
|
|
||||||
// More actions
|
// More actions
|
||||||
...moreActions.map(action => ({
|
...moreActions.map(action => ({
|
||||||
...action,
|
...action,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
} from '@blocksuite/affine-shared/commands';
|
} from '@blocksuite/affine-shared/commands';
|
||||||
import {
|
import {
|
||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
blockCommentToolbarButton,
|
|
||||||
type ToolbarModuleConfig,
|
type ToolbarModuleConfig,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { CaptionIcon, CopyIcon, DeleteIcon } from '@blocksuite/icons/lit';
|
import { CaptionIcon, CopyIcon, DeleteIcon } from '@blocksuite/icons/lit';
|
||||||
@@ -62,10 +61,6 @@ export const surfaceRefToolbarModuleConfig: ToolbarModuleConfig = {
|
|||||||
surfaceRefBlock.captionElement.show();
|
surfaceRefBlock.captionElement.show();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'e.comment',
|
|
||||||
...blockCommentToolbarButton,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'a.clipboard',
|
id: 'a.clipboard',
|
||||||
placement: ActionPlacement.More,
|
placement: ActionPlacement.More,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
type SurfaceRefBlockModel,
|
type SurfaceRefBlockModel,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
DocModeProvider,
|
DocModeProvider,
|
||||||
EditPropsStore,
|
EditPropsStore,
|
||||||
type OpenDocMode,
|
type OpenDocMode,
|
||||||
@@ -145,7 +145,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
|
|||||||
get isCommentHighlighted() {
|
get isCommentHighlighted() {
|
||||||
return (
|
return (
|
||||||
this.std
|
this.std
|
||||||
.getOptional(BlockCommentManager)
|
.getOptional(BlockElementCommentManager)
|
||||||
?.isBlockCommentHighlighted(this.model) ?? false
|
?.isBlockCommentHighlighted(this.model) ?? false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
} from '@blocksuite/affine-ext-loader';
|
} from '@blocksuite/affine-ext-loader';
|
||||||
import {
|
import {
|
||||||
AutoClearSelectionService,
|
AutoClearSelectionService,
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
CitationService,
|
CitationService,
|
||||||
DefaultOpenDocExtension,
|
DefaultOpenDocExtension,
|
||||||
DNDAPIExtension,
|
DNDAPIExtension,
|
||||||
@@ -79,7 +79,7 @@ export class FoundationViewExtension extends ViewExtensionProvider<FoundationVie
|
|||||||
LinkPreviewCache,
|
LinkPreviewCache,
|
||||||
LinkPreviewService,
|
LinkPreviewService,
|
||||||
CitationService,
|
CitationService,
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
]);
|
]);
|
||||||
context.register(clipboardConfigs);
|
context.register(clipboardConfigs);
|
||||||
if (this.isEdgeless(context.scope)) {
|
if (this.isEdgeless(context.scope)) {
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import {
|
|||||||
TextAlign,
|
TextAlign,
|
||||||
type TextStyleProps,
|
type TextStyleProps,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import type {
|
import {
|
||||||
ToolbarActions,
|
type ToolbarActions,
|
||||||
ToolbarContext,
|
type ToolbarContext,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import {
|
import {
|
||||||
getMostCommonResolvedValue,
|
getMostCommonResolvedValue,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { getInlineEditorByModel } from '@blocksuite/affine-rich-text';
|
import { getInlineEditorByModel } from '@blocksuite/affine-rich-text';
|
||||||
import { getSelectedBlocksCommand } from '@blocksuite/affine-shared/commands';
|
import { getSelectedBlocksCommand } from '@blocksuite/affine-shared/commands';
|
||||||
import {
|
import {
|
||||||
BlockCommentManager,
|
BlockElementCommentManager,
|
||||||
type CommentId,
|
type CommentId,
|
||||||
CommentProviderIdentifier,
|
CommentProviderIdentifier,
|
||||||
findAllCommentedBlocks,
|
findAllCommentedBlocks,
|
||||||
@@ -78,7 +78,7 @@ export class InlineCommentManager extends LifeCycleWatcher {
|
|||||||
// which means the comment may be removed or resolved in provider side
|
// which means the comment may be removed or resolved in provider side
|
||||||
difference(commentsInEditor, commentsInProvider).forEach(comment => {
|
difference(commentsInEditor, commentsInProvider).forEach(comment => {
|
||||||
this._handleDeleteAndResolve(comment);
|
this._handleDeleteAndResolve(comment);
|
||||||
this.std.get(BlockCommentManager).handleDeleteAndResolve(comment);
|
this.std.get(BlockElementCommentManager).handleDeleteAndResolve(comment);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
import { DividerBlockModel } from '@blocksuite/affine-model';
|
|
||||||
import { DisposableGroup } from '@blocksuite/global/disposable';
|
|
||||||
import {
|
|
||||||
BlockSelection,
|
|
||||||
LifeCycleWatcher,
|
|
||||||
TextSelection,
|
|
||||||
} from '@blocksuite/std';
|
|
||||||
import type { BaseSelection, BlockModel } from '@blocksuite/store';
|
|
||||||
import { signal } from '@preact/signals-core';
|
|
||||||
|
|
||||||
import { getSelectedBlocksCommand } from '../../commands';
|
|
||||||
import { ImageSelection } from '../../selection';
|
|
||||||
import { matchModels } from '../../utils';
|
|
||||||
import { type CommentId, CommentProviderIdentifier } from './comment-provider';
|
|
||||||
import { findCommentedBlocks } from './utils';
|
|
||||||
|
|
||||||
export class BlockCommentManager extends LifeCycleWatcher {
|
|
||||||
static override key = 'block-comment-manager';
|
|
||||||
|
|
||||||
private readonly _highlightedCommentId$ = signal<CommentId | null>(null);
|
|
||||||
|
|
||||||
private readonly _disposables = new DisposableGroup();
|
|
||||||
|
|
||||||
private get _provider() {
|
|
||||||
return this.std.getOptional(CommentProviderIdentifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
isBlockCommentHighlighted(
|
|
||||||
block: BlockModel<{ comments?: Record<CommentId, boolean> }>
|
|
||||||
) {
|
|
||||||
const comments = block.props.comments;
|
|
||||||
if (!comments) return false;
|
|
||||||
return (
|
|
||||||
this._highlightedCommentId$.value !== null &&
|
|
||||||
Object.keys(comments).includes(this._highlightedCommentId$.value)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
override mounted() {
|
|
||||||
const provider = this._provider;
|
|
||||||
if (!provider) return;
|
|
||||||
|
|
||||||
this._disposables.add(provider.onCommentAdded(this._handleAddComment));
|
|
||||||
this._disposables.add(
|
|
||||||
provider.onCommentDeleted(this.handleDeleteAndResolve)
|
|
||||||
);
|
|
||||||
this._disposables.add(
|
|
||||||
provider.onCommentResolved(this.handleDeleteAndResolve)
|
|
||||||
);
|
|
||||||
this._disposables.add(
|
|
||||||
provider.onCommentHighlighted(this._handleHighlightComment)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
override unmounted() {
|
|
||||||
this._disposables.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly _handleAddComment = (
|
|
||||||
id: CommentId,
|
|
||||||
selections: BaseSelection[]
|
|
||||||
) => {
|
|
||||||
const blocksFromTextRange = selections
|
|
||||||
.filter((s): s is TextSelection => s.is(TextSelection))
|
|
||||||
.map(s => {
|
|
||||||
const [_, { selectedBlocks }] = this.std.command.exec(
|
|
||||||
getSelectedBlocksCommand,
|
|
||||||
{
|
|
||||||
textSelection: s,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (!selectedBlocks) return [];
|
|
||||||
return selectedBlocks.map(b => b.model).filter(m => !m.text);
|
|
||||||
});
|
|
||||||
|
|
||||||
const needCommentBlocks = [
|
|
||||||
...blocksFromTextRange.flat(),
|
|
||||||
...selections
|
|
||||||
.filter(s => s instanceof BlockSelection || s instanceof ImageSelection)
|
|
||||||
.map(({ blockId }) => this.std.store.getModelById(blockId))
|
|
||||||
.filter(
|
|
||||||
(m): m is BlockModel =>
|
|
||||||
m !== null && !matchModels(m, [DividerBlockModel])
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (needCommentBlocks.length === 0) return;
|
|
||||||
|
|
||||||
this.std.store.withoutTransact(() => {
|
|
||||||
needCommentBlocks.forEach(block => {
|
|
||||||
const comments = (
|
|
||||||
'comments' in block.props &&
|
|
||||||
typeof block.props.comments === 'object' &&
|
|
||||||
block.props.comments !== null
|
|
||||||
? block.props.comments
|
|
||||||
: {}
|
|
||||||
) as Record<CommentId, boolean>;
|
|
||||||
|
|
||||||
this.std.store.updateBlock(block, {
|
|
||||||
comments: { [id]: true, ...comments },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
readonly handleDeleteAndResolve = (id: CommentId) => {
|
|
||||||
const commentedBlocks = findCommentedBlocks(this.std.store, id);
|
|
||||||
this.std.store.withoutTransact(() => {
|
|
||||||
commentedBlocks.forEach(block => {
|
|
||||||
delete block.props.comments[id];
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly _handleHighlightComment = (id: CommentId | null) => {
|
|
||||||
this._highlightedCommentId$.value = id;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
+169
@@ -0,0 +1,169 @@
|
|||||||
|
import { DividerBlockModel } from '@blocksuite/affine-model';
|
||||||
|
import { DisposableGroup } from '@blocksuite/global/disposable';
|
||||||
|
import {
|
||||||
|
BlockSelection,
|
||||||
|
LifeCycleWatcher,
|
||||||
|
SurfaceSelection,
|
||||||
|
TextSelection,
|
||||||
|
} from '@blocksuite/std';
|
||||||
|
import {
|
||||||
|
GfxControllerIdentifier,
|
||||||
|
type GfxModel,
|
||||||
|
type GfxPrimitiveElementModel,
|
||||||
|
} from '@blocksuite/std/gfx';
|
||||||
|
import type { BaseSelection, BlockModel } from '@blocksuite/store';
|
||||||
|
import { signal } from '@preact/signals-core';
|
||||||
|
|
||||||
|
import { getSelectedBlocksCommand } from '../../commands';
|
||||||
|
import { ImageSelection } from '../../selection';
|
||||||
|
import { matchModels } from '../../utils';
|
||||||
|
import { type CommentId, CommentProviderIdentifier } from './comment-provider';
|
||||||
|
import { findCommentedBlocks, findCommentedElements } from './utils';
|
||||||
|
|
||||||
|
export class BlockElementCommentManager extends LifeCycleWatcher {
|
||||||
|
static override key = 'block-element-comment-manager';
|
||||||
|
|
||||||
|
private readonly _highlightedCommentId$ = signal<CommentId | null>(null);
|
||||||
|
|
||||||
|
private readonly _disposables = new DisposableGroup();
|
||||||
|
|
||||||
|
private get _provider() {
|
||||||
|
return this.std.getOptional(CommentProviderIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
isBlockCommentHighlighted(
|
||||||
|
block: BlockModel<{ comments?: Record<CommentId, boolean> }>
|
||||||
|
) {
|
||||||
|
const comments = block.props.comments;
|
||||||
|
if (!comments) return false;
|
||||||
|
return (
|
||||||
|
this._highlightedCommentId$.value !== null &&
|
||||||
|
Object.keys(comments).includes(this._highlightedCommentId$.value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isElementCommentHighlighted(element: GfxPrimitiveElementModel) {
|
||||||
|
const comments = element.comments;
|
||||||
|
if (!comments) return false;
|
||||||
|
return (
|
||||||
|
this._highlightedCommentId$.value !== null &&
|
||||||
|
Object.keys(comments).includes(this._highlightedCommentId$.value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
override mounted() {
|
||||||
|
const provider = this._provider;
|
||||||
|
if (!provider) return;
|
||||||
|
|
||||||
|
this._disposables.add(provider.onCommentAdded(this._handleAddComment));
|
||||||
|
this._disposables.add(
|
||||||
|
provider.onCommentDeleted(this.handleDeleteAndResolve)
|
||||||
|
);
|
||||||
|
this._disposables.add(
|
||||||
|
provider.onCommentResolved(this.handleDeleteAndResolve)
|
||||||
|
);
|
||||||
|
this._disposables.add(
|
||||||
|
provider.onCommentHighlighted(this._handleHighlightComment)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
override unmounted() {
|
||||||
|
this._disposables.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly _handleAddComment = (
|
||||||
|
id: CommentId,
|
||||||
|
selections: BaseSelection[]
|
||||||
|
) => {
|
||||||
|
// get blocks from text range that some no-text blocks are selected such as image, bookmark, etc.
|
||||||
|
const noTextBlocksFromTextRange = selections
|
||||||
|
.filter((s): s is TextSelection => s.is(TextSelection))
|
||||||
|
.flatMap(s => {
|
||||||
|
const [_, { selectedBlocks }] = this.std.command.exec(
|
||||||
|
getSelectedBlocksCommand,
|
||||||
|
{
|
||||||
|
textSelection: s,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!selectedBlocks) return [];
|
||||||
|
return selectedBlocks.map(b => b.model).filter(m => !m.text);
|
||||||
|
});
|
||||||
|
|
||||||
|
const blocksFromBlockSelection = selections
|
||||||
|
.filter(s => s instanceof BlockSelection || s instanceof ImageSelection)
|
||||||
|
.map(({ blockId }) => this.std.store.getModelById(blockId))
|
||||||
|
.filter(
|
||||||
|
(m): m is BlockModel =>
|
||||||
|
m !== null && !matchModels(m, [DividerBlockModel])
|
||||||
|
);
|
||||||
|
|
||||||
|
const needCommentBlocks = [
|
||||||
|
...noTextBlocksFromTextRange,
|
||||||
|
...blocksFromBlockSelection,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (needCommentBlocks.length !== 0) {
|
||||||
|
this.std.store.withoutTransact(() => {
|
||||||
|
needCommentBlocks.forEach(block => {
|
||||||
|
const comments = (
|
||||||
|
'comments' in block.props &&
|
||||||
|
typeof block.props.comments === 'object' &&
|
||||||
|
block.props.comments !== null
|
||||||
|
? block.props.comments
|
||||||
|
: {}
|
||||||
|
) as Record<CommentId, boolean>;
|
||||||
|
|
||||||
|
this.std.store.updateBlock(block, {
|
||||||
|
comments: { [id]: true, ...comments },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const gfx = this.std.get(GfxControllerIdentifier);
|
||||||
|
const elementsFromSurfaceSelection = selections
|
||||||
|
.filter(s => s instanceof SurfaceSelection)
|
||||||
|
.flatMap(({ blockId, elements }) => {
|
||||||
|
if (blockId !== gfx.surface?.id) return [];
|
||||||
|
return elements
|
||||||
|
.map(id => gfx.getElementById<GfxModel>(id))
|
||||||
|
.filter(m => m !== null);
|
||||||
|
});
|
||||||
|
if (elementsFromSurfaceSelection.length !== 0) {
|
||||||
|
this.std.store.withoutTransact(() => {
|
||||||
|
elementsFromSurfaceSelection.forEach(element => {
|
||||||
|
const comments =
|
||||||
|
'comments' in element &&
|
||||||
|
typeof element.comments === 'object' &&
|
||||||
|
element.comments !== null
|
||||||
|
? element.comments
|
||||||
|
: {};
|
||||||
|
|
||||||
|
gfx.updateElement(element, {
|
||||||
|
comments: { [id]: true, ...comments },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
readonly handleDeleteAndResolve = (id: CommentId) => {
|
||||||
|
const commentedBlocks = findCommentedBlocks(this.std.store, id);
|
||||||
|
this.std.store.withoutTransact(() => {
|
||||||
|
commentedBlocks.forEach(block => {
|
||||||
|
delete block.props.comments[id];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const commentedElements = findCommentedElements(this.std.store, id);
|
||||||
|
this.std.store.withoutTransact(() => {
|
||||||
|
commentedElements.forEach(element => {
|
||||||
|
delete element.comments[id];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly _handleHighlightComment = (id: CommentId | null) => {
|
||||||
|
this._highlightedCommentId$.value = id;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
export * from './block-comment-manager';
|
export * from './block-element-comment-manager';
|
||||||
export * from './comment-provider';
|
export * from './comment-provider';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { CommentIcon } from '@blocksuite/icons/lit';
|
import { CommentIcon } from '@blocksuite/icons/lit';
|
||||||
import { BlockSelection } from '@blocksuite/std';
|
import { BlockSelection, SurfaceSelection } from '@blocksuite/std';
|
||||||
import type { BlockModel, Store } from '@blocksuite/store';
|
import type {
|
||||||
|
GfxPrimitiveElementModel,
|
||||||
|
SurfaceBlockModel,
|
||||||
|
} from '@blocksuite/std/gfx';
|
||||||
|
import { BlockModel, type Store } from '@blocksuite/store';
|
||||||
|
|
||||||
import type { ToolbarAction } from '../toolbar-service';
|
import type { ToolbarAction } from '../toolbar-service';
|
||||||
import { type CommentId, CommentProviderIdentifier } from './comment-provider';
|
import { type CommentId, CommentProviderIdentifier } from './comment-provider';
|
||||||
@@ -22,6 +26,31 @@ export function findCommentedBlocks(store: Store, commentId: CommentId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function findAllCommentedElements(store: Store) {
|
||||||
|
type CommentedElement = GfxPrimitiveElementModel & {
|
||||||
|
comments: Record<CommentId, boolean>;
|
||||||
|
};
|
||||||
|
const surface = store.getModelsByFlavour('affine:surface')[0] as
|
||||||
|
| SurfaceBlockModel
|
||||||
|
| undefined;
|
||||||
|
if (!surface) return [];
|
||||||
|
|
||||||
|
return surface.elementModels.filter(
|
||||||
|
(element): element is CommentedElement => {
|
||||||
|
return (
|
||||||
|
element.comments !== undefined &&
|
||||||
|
Object.keys(element.comments).length > 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findCommentedElements(store: Store, commentId: CommentId) {
|
||||||
|
return findAllCommentedElements(store).filter(element => {
|
||||||
|
return element.comments[commentId];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const blockCommentToolbarButton: Omit<ToolbarAction, 'id'> = {
|
export const blockCommentToolbarButton: Omit<ToolbarAction, 'id'> = {
|
||||||
tooltip: 'Comment',
|
tooltip: 'Comment',
|
||||||
when: ({ std }) => !!std.getOptional(CommentProviderIdentifier),
|
when: ({ std }) => !!std.getOptional(CommentProviderIdentifier),
|
||||||
@@ -29,22 +58,26 @@ export const blockCommentToolbarButton: Omit<ToolbarAction, 'id'> = {
|
|||||||
run: ctx => {
|
run: ctx => {
|
||||||
const commentProvider = ctx.std.getOptional(CommentProviderIdentifier);
|
const commentProvider = ctx.std.getOptional(CommentProviderIdentifier);
|
||||||
if (!commentProvider) return;
|
if (!commentProvider) return;
|
||||||
const selections = ctx.selection.value;
|
|
||||||
|
|
||||||
|
const selections = ctx.selection.value;
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentModel();
|
||||||
|
|
||||||
if (selections.length > 1) {
|
// may be hover on a block or element, in this case
|
||||||
|
// the selection is empty, so we need to get the current model
|
||||||
|
if (model && selections.length === 0) {
|
||||||
|
if (model instanceof BlockModel) {
|
||||||
|
commentProvider.addComment([
|
||||||
|
new BlockSelection({
|
||||||
|
blockId: model.id,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
} else if (ctx.gfx.surface?.id) {
|
||||||
|
commentProvider.addComment([
|
||||||
|
new SurfaceSelection(ctx.gfx.surface.id, [model.id], false),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else if (selections.length > 0) {
|
||||||
commentProvider.addComment(selections);
|
commentProvider.addComment(selections);
|
||||||
} else if (model) {
|
|
||||||
commentProvider.addComment([
|
|
||||||
new BlockSelection({
|
|
||||||
blockId: model.id,
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
} else if (selections.length === 1) {
|
|
||||||
commentProvider.addComment(selections);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export type BaseElementProps = {
|
|||||||
index: string;
|
index: string;
|
||||||
seed: number;
|
seed: number;
|
||||||
lockedBySelf?: boolean;
|
lockedBySelf?: boolean;
|
||||||
|
comments?: Record<string, boolean>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SerializedElement = Record<string, unknown> & {
|
export type SerializedElement = Record<string, unknown> & {
|
||||||
@@ -60,6 +61,7 @@ export type SerializedElement = Record<string, unknown> & {
|
|||||||
id: string;
|
id: string;
|
||||||
index: string;
|
index: string;
|
||||||
lockedBySelf?: boolean;
|
lockedBySelf?: boolean;
|
||||||
|
comments?: Record<string, boolean>;
|
||||||
props: Record<string, unknown>;
|
props: Record<string, unknown>;
|
||||||
};
|
};
|
||||||
export abstract class GfxPrimitiveElementModel<
|
export abstract class GfxPrimitiveElementModel<
|
||||||
@@ -372,6 +374,9 @@ export abstract class GfxPrimitiveElementModel<
|
|||||||
|
|
||||||
@field()
|
@field()
|
||||||
accessor seed!: number;
|
accessor seed!: number;
|
||||||
|
|
||||||
|
@field()
|
||||||
|
accessor comments: Record<string, boolean> | undefined = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class GfxGroupLikeElementModel<
|
export abstract class GfxGroupLikeElementModel<
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export function getTestCommonExtensions(
|
|||||||
di.override(DocModeProvider, mockDocModeService(editor));
|
di.override(DocModeProvider, mockDocModeService(editor));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// CommentProviderExtension(mockCommentProvider()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,18 @@ import { CommentProviderIdentifier } from '@blocksuite/affine/shared/services';
|
|||||||
import type { BlockStdScope } from '@blocksuite/affine/std';
|
import type { BlockStdScope } from '@blocksuite/affine/std';
|
||||||
import { StdIdentifier } from '@blocksuite/affine/std';
|
import { StdIdentifier } from '@blocksuite/affine/std';
|
||||||
import type { BaseSelection, ExtensionType } from '@blocksuite/affine/store';
|
import type { BaseSelection, ExtensionType } from '@blocksuite/affine/store';
|
||||||
|
import { ImageSelection } from '@blocksuite/affine-shared/selection';
|
||||||
import { type Container } from '@blocksuite/global/di';
|
import { type Container } from '@blocksuite/global/di';
|
||||||
import { BlockSelection, TextSelection } from '@blocksuite/std';
|
import {
|
||||||
|
BlockSelection,
|
||||||
|
SurfaceSelection,
|
||||||
|
TextSelection,
|
||||||
|
} from '@blocksuite/std';
|
||||||
|
import {
|
||||||
|
GfxBlockElementModel,
|
||||||
|
GfxControllerIdentifier,
|
||||||
|
GfxPrimitiveElementModel,
|
||||||
|
} from '@blocksuite/std/gfx';
|
||||||
import type { FrameworkProvider } from '@toeverything/infra';
|
import type { FrameworkProvider } from '@toeverything/infra';
|
||||||
|
|
||||||
import { DocCommentManagerService } from '../../../modules/comment/services/doc-comment-manager';
|
import { DocCommentManagerService } from '../../../modules/comment/services/doc-comment-manager';
|
||||||
@@ -21,6 +31,8 @@ function getPreviewFromSelections(
|
|||||||
|
|
||||||
const previews: string[] = [];
|
const previews: string[] = [];
|
||||||
|
|
||||||
|
const gfx = std.get(GfxControllerIdentifier);
|
||||||
|
|
||||||
for (const selection of selections) {
|
for (const selection of selections) {
|
||||||
if (selection instanceof TextSelection) {
|
if (selection instanceof TextSelection) {
|
||||||
// Extract text from TextSelection
|
// Extract text from TextSelection
|
||||||
@@ -35,9 +47,23 @@ function getPreviewFromSelections(
|
|||||||
const flavour = block.model.flavour.replace('affine:', '');
|
const flavour = block.model.flavour.replace('affine:', '');
|
||||||
previews.push(`<${flavour}>`);
|
previews.push(`<${flavour}>`);
|
||||||
}
|
}
|
||||||
} else if (selection.type === 'image') {
|
} else if (selection instanceof ImageSelection) {
|
||||||
// Return <"Image"> for ImageSelection
|
// Return <"Image"> for ImageSelection
|
||||||
previews.push('<Image>');
|
previews.push('<Image>');
|
||||||
|
} else if (
|
||||||
|
selection instanceof SurfaceSelection &&
|
||||||
|
gfx.surface?.id === selection.blockId
|
||||||
|
) {
|
||||||
|
selection.elements.forEach(elementId => {
|
||||||
|
const model = gfx.getElementById(elementId);
|
||||||
|
if (model instanceof GfxPrimitiveElementModel) {
|
||||||
|
const flavour = model.type.replace('affine:', '');
|
||||||
|
previews.push(`<${flavour}>`);
|
||||||
|
} else if (model instanceof GfxBlockElementModel) {
|
||||||
|
const flavour = model.flavour.replace('affine:', '');
|
||||||
|
previews.push(`<${flavour}>`);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// Skip other types
|
// Skip other types
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { HighlightSelection } from '@blocksuite/affine/shared/selection';
|
|||||||
import {
|
import {
|
||||||
DocModeProvider,
|
DocModeProvider,
|
||||||
findCommentedBlocks,
|
findCommentedBlocks,
|
||||||
|
findCommentedElements,
|
||||||
} from '@blocksuite/affine/shared/services';
|
} from '@blocksuite/affine/shared/services';
|
||||||
import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx';
|
import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx';
|
||||||
import type { InlineEditor } from '@blocksuite/std/inline';
|
import type { InlineEditor } from '@blocksuite/std/inline';
|
||||||
@@ -231,6 +232,12 @@ export class Editor extends Entity {
|
|||||||
if (blockCommentedBlocks.length > 0) {
|
if (blockCommentedBlocks.length > 0) {
|
||||||
finalId = blockCommentedBlocks[0].id;
|
finalId = blockCommentedBlocks[0].id;
|
||||||
finalKey = 'blockIds';
|
finalKey = 'blockIds';
|
||||||
|
} else {
|
||||||
|
const commentedElements = findCommentedElements(std.store, commentId);
|
||||||
|
if (commentedElements.length > 0) {
|
||||||
|
finalId = commentedElements[0].id;
|
||||||
|
finalKey = 'elementIds';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Workaround: clear selection to avoid comment editor flickering
|
// Workaround: clear selection to avoid comment editor flickering
|
||||||
|
|||||||
Reference in New Issue
Block a user