Skip to content

v0.4.3

Choose a tag to compare

@olibaron olibaron released this 10 Sep 19:05
· 3 commits to main since this release

Fixed

Block toolbars no longer cost work on every scroll frame. Every code, diagram, and table toolbar registered its own capturing window scroll listener and requested an animation frame per scroll event. Each frame measured its block with getBoundingClientRect and called classList.add or classList.remove — for every block on the page, on screen or not, whether or not the state changed. DOMTokenList add and remove rewrite the class attribute even when the token is already in the requested state, so each block produced a layout read and a mutation record per frame. A host scrolling a 64k px transcript measured ~600 mutation records and ~2,000 rect reads per second from toolbars alone; afterwards the same scroll measured 9 mutation records per second.

watchStickyHeader replaces the per-block listeners:

  • one shared IntersectionObserver tracks which blocks are on screen; an off-screen block cannot span the toolbar band, so it is cleared and never measured;
  • one capturing scroll/resize listener is attached only while some block is on screen;
  • each pass reads every on-screen block before writing any class, so a frame lays out once;
  • the scroll class is toggled only when the stuck state flips.

Without IntersectionObserver, every block counts as on screen (the previous behaviour, without the redundant writes).

Compatibility

No API change. The toolbar's scroll class keeps its meaning and thresholds; onViewportScroll stays exported. Patch release.