fix: Exclude nested tables from sticky scrollbar

Share the nested-table check between the sticky header and sticky
scrollbar via a memoized isNestedTable() helper, so a nested table that
overflows horizontally no longer shows a viewport-pinned floating
scrollbar from the constructor tick or update().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Moor
2026-06-02 08:49:03 -04:00
parent dc3484120c
commit e331be0572
+25 -5
View File
@@ -148,6 +148,8 @@ export class TableView extends ProsemirrorTableView {
private syncingScroll = false; private syncingScroll = false;
private nestedTable: boolean | null = null;
private scrollHandler: ((event: Event) => void) | null = null; private scrollHandler: ((event: Event) => void) | null = null;
private resizeHandler: (() => void) | null = null; private resizeHandler: (() => void) | null = null;
@@ -168,7 +170,7 @@ export class TableView extends ProsemirrorTableView {
// Defer setup to ensure DOM is fully rendered // Defer setup to ensure DOM is fully rendered
setTimeout(() => { setTimeout(() => {
// Skip sticky behavior for nested tables // Skip sticky behavior for nested tables
if (this.dom.closest(`table .${EditorStyleHelper.table}`)) { if (this.isNestedTable()) {
return; return;
} }
@@ -298,11 +300,13 @@ export class TableView extends ProsemirrorTableView {
const viewportHeight = const viewportHeight =
window.innerHeight || document.documentElement.clientHeight; window.innerHeight || document.documentElement.clientHeight;
// Only show the floating scrollbar when the browser renders persistent // Only show the floating scrollbar when this is not a nested table, the
// scrollbars (otherwise the table can be scrolled by gesture and a floating // browser renders persistent scrollbars (otherwise the table can be
// bar would look out of place), the table overflows horizontally, is within // scrolled by gesture and a floating bar would look out of place), the
// view, and its real scrollbar sits below the bottom of the viewport. // table overflows horizontally, is within view, and its real scrollbar sits
// below the bottom of the viewport.
const shouldShow = const shouldShow =
!this.isNestedTable() &&
hasVisibleScrollbars() && hasVisibleScrollbars() &&
overflows && overflows &&
rect.top < viewportHeight && rect.top < viewportHeight &&
@@ -340,6 +344,22 @@ export class TableView extends ProsemirrorTableView {
} }
} }
/**
* Returns whether this table is nested within another table. Nested tables
* are excluded from sticky header and sticky scrollbar behavior. The result
* is memoized once the DOM is connected, as nesting is structural and stable.
*
* @returns whether the table is nested within another table.
*/
private isNestedTable(): boolean {
if (this.nestedTable === null && isBrowser && this.dom.isConnected) {
this.nestedTable = !!this.dom.closest(
`table .${EditorStyleHelper.table}`
);
}
return this.nestedTable ?? false;
}
/** /**
* Gets the current header offset from the CSS variable. * Gets the current header offset from the CSS variable.
* *