Has User Scrolled?

I want to scroll to the end ( EditorView.scrollIntoView(tr.state.doc.length, { x: 'start', y: 'end' }) ) when appending to the document, but only if the User hasn’t scrolled somewhere else.

Is there a way to tell in the state/view if the User has scrolled?

Based on my understanding, it seems like maybe I’ll need to do a domEventHandler extension watching scroll ( EditorView.domEventHandlers({ scroll(event, view) { ... }) ) and update a Facet, but I’m hoping there’s something I missed. Some kind of property in the view.

Additionally, is there a way to know if the user is scrolled to the bottom? Not sure how to use the available properties to detect what’s truly visible in the viewport, or if I should use native JS methods on view.scrollDOM.

The view itself doesn’t track this. Easiest way to do it would be a view plugin that keeps a flag for this and registers its own scroll handler.

Thanks, marijn. That’s the route I started going down. Works decently well.

function isElementScrolledToBottom(el, wiggleRoom = 10) {
  return el.scrollHeight - el.scrollTop <= el.clientHeight + wiggleRoom;
}

export const scrollViewPlugin = ViewPlugin.fromClass(
  class {
    scrolledToBottom = true;
    programmaticScroll = false;

    update(update) {
      if (update.docChanged) {
        for (let tr of update.transactions) {
          for (let e of tr.effects) {
            if ( e.is( myCustomEffect ) && this.scrolledToBottom) {
                // Add flag that this was a programmatic scroll.
                this.programmaticScroll = true;
                // Delay by an animation frame to ensure DOM is ready
                requestAnimationFrame(() => {
                  // Scroll to the bottom of the console.
                  const el = update.view.scrollDOM;
                  el.scrollTop = el.scrollHeight;
                });
              }
            }
          }
        }
      }
    }
  },
  {
    eventHandlers: {
      scroll: function (e, view) {
        // Ignore programmatic scroll events.
        if (this.programmaticScroll) {
          this.programmaticScroll = false;
          return;
        }
        this.scrolledToBottom = isElementScrolledToBottom(view.scrollDOM);
      }
    }
  }
);