diff --git a/blocksuite/affine/inlines/comment/src/inline-comment.ts b/blocksuite/affine/inlines/comment/src/inline-comment.ts index 71964f4aa..423dfc211 100644 --- a/blocksuite/affine/inlines/comment/src/inline-comment.ts +++ b/blocksuite/affine/inlines/comment/src/inline-comment.ts @@ -41,6 +41,8 @@ export class InlineComment extends WithDisposable(ShadowlessElement) { }) accessor commentIds!: string[]; + private _index: number = 0; + @consume({ context: stdContext }) private accessor _std!: BlockStdScope; @@ -52,8 +54,8 @@ export class InlineComment extends WithDisposable(ShadowlessElement) { } private readonly _handleClick = () => { - const provider = this._provider; - provider && this.commentIds.forEach(id => provider.highlightComment(id)); + this._provider?.highlightComment(this.commentIds[this._index]); + this._index = (this._index + 1) % this.commentIds.length; }; private readonly _handleHighlight = (id: CommentId | null) => { diff --git a/blocksuite/affine/shared/src/selection/hightlight.ts b/blocksuite/affine/shared/src/selection/hightlight.ts index 1fa3304ec..26800f7f0 100644 --- a/blocksuite/affine/shared/src/selection/hightlight.ts +++ b/blocksuite/affine/shared/src/selection/hightlight.ts @@ -1,8 +1,12 @@ -import { - type ReferenceParams, - ReferenceParamsSchema, -} from '@blocksuite/affine-model'; +import { ReferenceParamsSchema } from '@blocksuite/affine-model'; import { BaseSelection, SelectionExtension } from '@blocksuite/store'; +import z from 'zod'; + +const HighlightSelectionParamsSchema = ReferenceParamsSchema.extend({ + highlight: z.boolean().optional(), +}); + +type HighlightSelectionParams = z.infer; export class HighlightSelection extends BaseSelection { static override group = 'scene'; @@ -15,16 +19,24 @@ export class HighlightSelection extends BaseSelection { readonly mode: 'page' | 'edgeless' = 'page'; - constructor({ mode, blockIds, elementIds }: ReferenceParams) { + readonly highlight: boolean = true; + + constructor({ + mode, + blockIds, + elementIds, + highlight = true, + }: HighlightSelectionParams) { super({ blockId: '[scene-highlight]' }); this.mode = mode ?? 'page'; this.blockIds = blockIds ?? []; this.elementIds = elementIds ?? []; + this.highlight = highlight; } static override fromJSON(json: Record): HighlightSelection { - const result = ReferenceParamsSchema.parse(json); + const result = HighlightSelectionParamsSchema.parse(json); return new HighlightSelection(result); } diff --git a/blocksuite/affine/widgets/scroll-anchoring/src/scroll-anchoring.ts b/blocksuite/affine/widgets/scroll-anchoring/src/scroll-anchoring.ts index 8368894ef..adc6bedc1 100644 --- a/blocksuite/affine/widgets/scroll-anchoring/src/scroll-anchoring.ts +++ b/blocksuite/affine/widgets/scroll-anchoring/src/scroll-anchoring.ts @@ -12,6 +12,7 @@ import { styleMap } from 'lit/directives/style-map.js'; type Anchor = { id: string; mode: DocMode; + highlight: boolean; }; export const AFFINE_SCROLL_ANCHORING_WIDGET = 'affine-scroll-anchoring-widget'; @@ -221,6 +222,7 @@ export class AffineScrollAnchoringWidget extends WidgetComponent { mode, blockIds: [bid], elementIds: [eid], + highlight, } = highlighted; const id = mode === 'page' ? bid : eid || bid; if (!id) return; @@ -228,7 +230,7 @@ export class AffineScrollAnchoringWidget extends WidgetComponent { // Consumes highlight selection this.std.selection.clear(['highlight']); - this.anchor$.value = { mode, id }; + this.anchor$.value = { mode, id, highlight }; this.#listened = true; }) ); @@ -241,7 +243,7 @@ export class AffineScrollAnchoringWidget extends WidgetComponent { override render() { const anchor = this.anchor$.value; - if (!anchor) return nothing; + if (!anchor || !anchor.highlight) return nothing; const { mode, id } = anchor; diff --git a/packages/frontend/core/src/modules/editor/entities/editor.ts b/packages/frontend/core/src/modules/editor/entities/editor.ts index cd0f7856a..feb5eaa21 100644 --- a/packages/frontend/core/src/modules/editor/entities/editor.ts +++ b/packages/frontend/core/src/modules/editor/entities/editor.ts @@ -56,7 +56,7 @@ export class Editor extends Entity { const mode = get(this.mode$); let id = selector?.blockIds?.[0]; let commentId = selector?.commentId; - let key = 'blockIds'; + let key: 'blockIds' | 'elementIds' = 'blockIds'; if (mode === 'edgeless') { const elementId = selector?.elementIds?.[0]; @@ -195,7 +195,7 @@ export class Editor extends Entity { } handleFocusAt(focusAt: { - key: string; + key: 'blockIds' | 'elementIds'; mode: DocMode; id?: string; commentId?: string; @@ -208,6 +208,7 @@ export class Editor extends Entity { let finalId = id; let finalKey = key; + let highlight = true; // If we have commentId but no blockId, find the block from the comment if (commentId && !id && editorContainer.host?.std) { @@ -230,6 +231,9 @@ export class Editor extends Entity { finalKey = 'blockIds'; } } + // Workaround: clear selection to avoid comment editor flickering + selection?.clear(); + highlight = false; } if (mode === this.mode$.value && finalId) { @@ -237,7 +241,8 @@ export class Editor extends Entity { selection?.create(HighlightSelection, { mode, [finalKey]: [finalId], - }), + highlight, + } as const), ]); } }