Repository navigation
Conversation
A trackpad swipe or a fling that runs into the end of a native macOS text view stretches the text past it and springs back. `scroll_bounce(true)` does the same for a multi-line input whose text is taller than it, with the spring and rubber-band curve of `ScrollBounce`. The input scrolls itself, so it cannot sit inside that wrapper, which would move its frame and only sees a packet after the input has handled it; the input drives the shared `Physics` instead. Scrolling stays exact: the stretch only moves where the text and gutter are drawn, inside the frame that clips them, and the scrollbar stays put. A finger drags the edge. Momentum or a mouse wheel flick that runs into it throws it instead: its packets measure speed rather than travel, so each adds to the edge's peak, capped, and the spring carries it out and back. `Physics` gains `kick` for that. As with `ScrollBounce`, it is on by default on iOS and Android and off elsewhere; under reduced motion the text stops at its ends without stretching. The Textarea and Editor stories turn it on.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
A trackpad swipe or fling that runs into the end of a native macOS text view stretches the text past it and springs back.
scroll_bounce(true)does the same for a multi-line input whose text is taller than it, using the spring and rubber-band curve ofScrollBounce.The input scrolls itself, so it cannot sit inside
ScrollBounce: that wrapper would move the input's frame along with the text, and it sees a packet only after the input has handled it. The input drives the samePhysicsinstead. Scrolling stays exact: the stretch only moves where the text and gutter are drawn, inside the frame that clips them, and the scrollbar stays put.Physicsgains a crate-privatekickfor that; pulling a 100px wheel step instead would jump the edge in one frame.ScrollBounce, which leaves line-wheel input to its child, it also bounces on a mouse wheel: an input has no child to pass it to, and with a mouse the end of the text is otherwise a dead stop.ScrollBounce, it is on by default on iOS and Android and off elsewhere. Under reduced motion the text stops at its ends without stretching.ScrollBounce's default motion, plus the kick's fixed 0.3px of peak per pixel of travel. There is noScrollBounceMotionsetter on the input yet; one can follow if a host needs to tune it.The Textarea and Editor stories turn it on, and the Textarea and Editor docs (English and Chinese) describe it. It builds on #3484, which keeps the scroll in the input at its end, so a stretch never scrolls the page behind it.
Public API
gpui-base (reached through
TextareaStateandEditorStatein gpui-component)InputBaseState<M: MultiLineMode>::scroll_bounce(self, scroll_bounce: bool) -> Self: whether text taller than the input stretches past its ends and springs back.InputBaseState<M: MultiLineMode>::set_scroll_bounce(&mut self, scroll_bounce: bool, cx: &mut Context<Self>): change it later; turning it off drops any stretch at once.Breaking Changes
On iOS and Android, textareas and editors whose text is taller than them now bounce at their ends by default, as
ScrollBouncedoes there. To keep them still:TextareaState::new(window, cx) + .scroll_bounce(false)How to Test
cargo test -p gpui-base --lib -- overscroll scroll_bouncetest_scroll_bounce_stretches_past_the_end_and_springs_back: a swipe past the end stretches the text, it springs back to 0, and the scroll offset stays exactly at the end.test_scroll_bounce_stays_put_under_reduced_motion: the text still scrolls to its end, and the edge does not stretch.test_scroll_bounce_is_off_by_default_on_the_desktop,test_scroll_bounce_leaves_text_that_fitsandtest_turning_scroll_bounce_off_drops_the_stretchpin the defaults and the setter.overscroll::tests: pulling back unstretches before scrolling the text; a wheel flick throws the edge from where it is, never more than 15px a frame, peaks within 30px, ignores packets once it turns back, and settles; after a pause the next flick throws it again.scroll_bounce::testsstill pass, soScrollBounceis unchanged by sharing its spring.AI-assisted: written with Claude Code and reviewed by me before submission.
Checklist
cargo runfor story tests related to the changes. (Textarea and Editor stories, macOS with a mouse wheel: the text bounces past either end and springs back; the frame, scrollbar and page stay put; nothing moves with Reduce motion on.)