Skip to content

Commit c3568d2

Browse files
authored
fix(comments): reduce sidebar jitter when clicking comments (SD-2034) (#2250)
* fix(comments): reduce sidebar jitter when clicking comments (SD-2034) Clicking a comment near the bottom of the sidebar caused the scrollbar to flash because totalHeight oscillated during collision avoidance recalculation and height remeasurements. Three fixes: - Add CSS transition on section-wrapper min-height so height changes are smooth instead of causing abrupt scrollbar appearance/disappearance - Increase ESTIMATED_HEIGHT from 80 to 110 to better match actual comment card sizes, reducing visual overlap before measurement - Fix scroll-to-comment: increase delay from 100ms to 400ms so the comment-placeholder CSS transition (300ms) completes before checking visibility, and use rect.bottom instead of rect.top for the lower bound check * fix(comments): handle tall cards in scroll-to-comment visibility check When a comment card is taller than the viewport, the rect.bottom check always fails, causing scrollIntoView to fire on every click. Fall back to checking only rect.top for cards that exceed the available height.
1 parent d74f18d commit c3568d2

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

packages/superdoc/src/components/CommentsLayer/FloatingComments.vue

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { useCommentsStore } from '@superdoc/stores/comments-store';
1010
import { useSuperdocStore } from '@superdoc/stores/superdoc-store';
1111
import CommentDialog from '@superdoc/components/CommentsLayer/CommentDialog.vue';
1212
13-
const ESTIMATED_HEIGHT = 80;
13+
const ESTIMATED_HEIGHT = 110;
1414
const OBSERVER_MARGIN = 600;
1515
1616
// Layout algorithm: positions comments in a single column with collision avoidance.
@@ -323,18 +323,23 @@ watch(activeComment, () => {
323323
if (!key) return;
324324
325325
nextTick(() => {
326+
// 400ms: wait for .comment-placeholder CSS transition (300ms) + buffer
326327
scrollTimer = setTimeout(() => {
327328
const el = placeholderRefs.value[key];
328329
if (!el) return;
329330
330331
const rect = el.getBoundingClientRect();
331332
const margin = 80;
332-
const isVisible = rect.top >= margin && rect.top <= window.innerHeight - margin;
333+
const availableHeight = window.innerHeight - 2 * margin;
334+
const isVisible =
335+
rect.height > availableHeight
336+
? rect.top >= margin
337+
: rect.top >= margin && rect.bottom <= window.innerHeight - margin;
333338
334339
if (!isVisible) {
335340
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
336341
}
337-
}, 100);
342+
}, 400);
338343
});
339344
});
340345
@@ -499,5 +504,7 @@ onBeforeUnmount(() => {
499504
display: flex;
500505
align-items: flex-start;
501506
justify-content: flex-start;
507+
/* SD-2034: smooth min-height changes to prevent scrollbar flash */
508+
transition: min-height 0.5s ease-out;
502509
}
503510
</style>

0 commit comments

Comments
 (0)