Skip to content

fix: render embedded Task List rows from the visible part of the note - #2425

Open
asmbatati wants to merge 1 commit into
callumalpass:mainfrom
asmbatati:fix/virtual-scroller-embedded-viewport
Open

asmbatati wants to merge 1 commit into
callumalpass:mainfrom
asmbatati:fix/virtual-scroller-embedded-viewport

Conversation

@asmbatati

Copy link
Copy Markdown

Bug

A Task List view with 100 or more rows, embedded in a note (![[tasks.base#View]]), renders only its first rows. The rest stay blank while the note is scrolled, and appear only after scrolling with the mouse over the list itself. Seen on 4.14.0 and current main, Obsidian 1.15.0, Windows 11, Live Preview, with the embed inside a callout and inside a multi-column callout.

Cause

VirtualScroller takes the nearest ancestor whose computed overflow-y is auto or scroll as the list's scroll container. In an embedded Base that is Obsidian's .bases-view, which gets overflow-x: auto in notes, so its overflow-y computes to auto as well. That element is not height-bounded: it grows with its content, and the note's .cm-scroller scrolls it. So the scroller sized its window from that element, rendered the first rows, and redrew only on scroll events from .bases-view itself, never from the note.

Measured in the affected embed (227 rows), the ancestor chain was: .bases-view (auto) → .bases-embed (hidden) → .callout-content (auto) → .callout (hidden) → .callout-content (auto, display: contents, 0×0 rect) → .callout → .cm-embed-block → .cm-scroller (auto, the real scroller).

Fix

In VirtualScroller:

  • The visible range is the part of the container that is on screen: the viewport, clipped by every ancestor whose overflow-y clips. Elements with display: contents have no box and are skipped; the multi-column callout's content is one, with a 0×0 rect and a computed overflow-y: auto.
  • A capturing scroll listener on the document (scroll events do not bubble) and a resize listener redraw it, so scrolling the note updates the rows.
  • The container reserves the list's full height (min-height, the spacer's height), since the spacer is absolutely positioned and gives an unbounded ancestor no height.
  • The height estimate is not sampled while the container has no width (the embed measured about 658 px per row before layout), and afterwards follows the average of the measured rows, since unrendered rows now size the page.
  • A container with no layout (not attached, hidden, jsdom) keeps the old scrollTop path.

Tests

  • Four unit tests in tests/unit/utils/VirtualScroller.test.ts for an embedded list scrolled by its note: the first window, a note scroll, a display: contents ancestor, and the reserved height. Three failed on main before the change; the display: contents one fails without that check.
  • npm run lint:ts for the file, tsc --noEmit and npm run build pass. Six unit suites fail on this machine (Windows) with and without the change: the same suites, unrelated.
  • Checked by hand: the same commit applied to 4.14.0 and installed in a real vault. The embedded list fills the screen on first load and keeps rendering as the note scrolls. I did not write a Playwright spec.

🤖 Generated with Claude Code

A Task List with 100 or more rows renders through VirtualScroller, which
took the nearest ancestor with overflow auto or scroll as the list's
scroll container. In a Base embedded in a note that is Obsidian's
.bases-view: it sets overflow-x: auto there, so overflow-y computes to
auto too, yet the element grows with its content and the note scrolls
it. The scroller measured that element, rendered the rows of its first
window, and redrew only when the list itself was scrolled; scrolling
the note did nothing.

The visible range is now the part of the container that is on screen:
the viewport clipped by every ancestor that clips (skipping elements
with display: contents, which have no box, such as a multi-column
callout's content). A capturing scroll listener on the document and a
resize listener redraw it. The container reserves the list's full
height, so the note can scroll to rows not rendered yet, and the height
estimate is skipped while the container has no width and then follows
the measured rows. Containers with no layout keep the old scrollTop
path.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant