Components / Data
Follow scroll
Markdown crates/ui/src/scroll.rs docs.rs
use ui::scroll;
div().relative()
.child(div().id("log").size_full().overflow_y_scroll().track_scroll(&self.scroll).child(rows))
.child(scroll::follow(&self.scroll, &self.follow))
.child(scroll::scrollbar("log-bar", &self.scroll, &self.bar))The overflow is what tells appended content from a user scroll: if it changed, the content grew and the pin stays as the user set it; if it did not, the user moved it, and being at the end re-pins. Scrolling up releases and scrolling back down re-attaches, with no gesture to hook.
API
// ui::scroll
/// Drop it in beside the scrollbar, over the same container.
pub fn follow(handle: &ScrollHandle, state: &FollowState) -> gpui::AnyElement;
/// Starts pinned — a transcript opens on its newest line.
pub struct FollowState(Rc<Cell<(bool, Pixels)>>);
impl FollowState {
/// Re-pin, from a "jump to bottom" button.
pub fn follow(&self);
// ...
}
/// The predicate, exposed because a jump-to-bottom pill needs the same answer.
/// Content that fits is always at the bottom.
pub fn at_bottom(max_offset: Pixels, offset: Pixels, slack: Pixels) -> bool;The slack matters: a wheel lands on fractional offsets, and without it a view would unpin itself over a rounding error. The correction lands a frame late and converges — once pinned and at the end, nothing is requested.