A local-first note taking app

Restore scroll and cursor when returning to a tab master

Switching tabs threw away where you were. `DocumentSlotView` keys `DocumentPane` by document id and only the active tab's slot is rendered, so every tab switch unmounts CodeMirror and rebuilds it from scratch — landing you back at the top of the document with the cursor at position 0. Each tab now keeps an `EditorViewSnapshot` (cursor + scroll). The editor reports one as it tears down and consumes one when it is built. The capture is a *layout* effect cleanup, which matters more than it looks: `scrollSnapshot()` reads `scrollDOM.scrollTop`, and React runs passive (`useEffect`) cleanups for a deleted subtree only after its DOM nodes are detached. A detached element reports `scrollTop` 0, so capturing there records "top of document" every time and the feature silently does nothing. Layout cleanups run during the mutation phase, while the node is still attached and still scrolled. Restoration happens at construction rather than by dispatching after mount: `EditorViewConfig.scrollTo` accepts the effect from `view.scrollSnapshot()`, so the position is right before the first paint and the editor never visibly jumps from the top. The snapshot is document-anchored, not a pixel offset, so it survives content arriving late. The restored selection is clamped to the document length, because a synced vault's document can still be empty at mount and an out-of-range selection throws. The capture closure binds the tab id at render time. That is load-bearing and easy to get wrong: when the active tab changes, the outgoing editor is unmounted without ever being re-rendered, so its teardown must report against the tab being LEFT rather than the one arriving. `TileTab.view` is in-memory only — it holds a live CodeMirror object. `serializeLayout` already picks fields explicitly, so it cannot reach localStorage; a test pins that, since a future field could otherwise leak silently. Scroll position is therefore not restored across app restarts, which is a reasonable follow-up rather than part of this. Undo history is still lost on a tab switch — restoring it means serialising `historyField`, which is deliberately out of scope here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>