Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3524,14 +3524,12 @@ export class PresentationEditor extends EventEmitter {
this.emit('paginationUpdate', payload);

// Emit fresh comment positions after layout completes.
// This ensures positions are always in sync with the current document and layout.
// Always emit — even when empty — so the store can clear stale positions
// (e.g. when undo removes the last tracked-change mark).
const allowViewingCommentPositions = this.#layoutOptions.emitCommentPositionsInViewing === true;
if (this.#documentMode !== 'viewing' || allowViewingCommentPositions) {
const commentPositions = this.#collectCommentPositions();
const positionKeys = Object.keys(commentPositions);
if (positionKeys.length > 0) {
this.emit('commentPositions', { positions: commentPositions });
}
this.emit('commentPositions', { positions: commentPositions });
}

this.#selectionSync.requestRender({ immediate: true });
Expand Down
9 changes: 5 additions & 4 deletions packages/superdoc/src/stores/comments-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -876,11 +876,12 @@ export const useCommentsStore = defineStore('comments', () => {
const comments = getGroupedComments.value?.parentComments
.filter((c) => !c.resolvedTime)
.filter((c) => {
const keys = Object.keys(editorCommentPositions.value);
const isPdfComment = c.selection?.source !== 'super-editor';
if (isPdfComment) return true;
// Non-editor comments (e.g. PDF) are always shown.
// Editor-backed comments (including tracked changes, which have no
// selection.source) must have a live position in the document.
if (!isEditorBackedComment(c)) return true;
const commentKey = c.commentId || c.importedId;
return keys.includes(commentKey);
return commentKey in editorCommentPositions.value;
});
return comments;
});
Expand Down
19 changes: 19 additions & 0 deletions packages/superdoc/src/stores/comments-store.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -946,5 +946,24 @@ describe('comments-store', () => {
const floating = store.getFloatingComments;
expect(floating).toEqual([]);
});

it('excludes unresolved tracked change when positions are cleared (regression: SD-2071)', () => {
store.commentsList = [
{ commentId: 'tc-1', trackedChange: true, resolvedTime: null, createdTime: 1, selection: {} },
];
// Undo removed the mark — positions are now empty
store.editorCommentPositions = {};

const floating = store.getFloatingComments;
expect(floating).toEqual([]);
});

it('keeps PDF comments visible when editor positions are empty (SD-2071)', () => {
store.commentsList = [{ commentId: 'pdf-1', createdTime: 1, selection: { source: 'pdf', selectionBounds: {} } }];
store.editorCommentPositions = {};

const floating = store.getFloatingComments;
expect(floating.map((c) => c.commentId)).toEqual(['pdf-1']);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ test('thread with 2+ replies collapses and expands on click', async ({ superdoc
});
await superdoc.waitForStable();

// Wait for dialog to lose active state before re-activating — Firefox needs
// this gap so the component fully unmounts its expanded state.
const activeDialog = superdoc.page.locator('.comment-placeholder .comments-dialog.is-active');
await expect(activeDialog).toHaveCount(0, { timeout: 5_000 });

// Activate the comment dialog
const dialog = await activateCommentDialog(superdoc, 'collapse');

Expand Down
Loading