Replies: 2 comments 1 reply
|
I built a minimal page carrying the exact CSS from The escape route you describe is real, and the codebase already documents it. .input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
resize: none;
/* Never a scroller of its own: it is as tall as the draft, so it has no
scrollable overflow to hold an offset that could differ from the glyphs'.
The browser still reveals the caret — the scroll-into-view walks up to
.scroll and moves both layers together. */
overflow: hidden;That last sentence is the load-bearing assumption. It holds only while So Where the hypothesis is wrong: sticky isn't the trigger. I ran the seat as The other one worth killing early: making Two things did work in the repro, in both engines, at every draft length, with the resulting selection byte-identical: moving the seat out of const host = document.querySelector('[data-conversation-scroll]')
const ta = host.querySelector('[data-composer-seat] textarea')
ta.addEventListener('pointerdown', () => {
const pinned = host.scrollTop
let live = true
const tick = () => {
if (!live) return
if (host.scrollTop !== pinned) host.scrollTop = pinned
requestAnimationFrame(tick)
}
requestAnimationFrame(tick)
addEventListener('pointerup', () => { live = false; host.scrollTop = pinned }, { once: true })
})A That's also the cheap test that tells you whether you're looking at 1 bug or 2. Paste the guard, then try both gestures. If dragging goes quiet and typing still creeps, the typing half is app-driven and the engine autoscroll isn't it. For the typing half I couldn't get native typing to move the host at all, at empty, 5, 6, 30 and 40-line drafts and at start offsets of 50, 200, 2000 and 4200, in either engine, controlled-value re-assignment included. The one thing that did creep per keystroke was an unqualified Second thing queued up behind this, whichever gesture causes it. const movedByReader = Math.abs(el.scrollTop - Math.min(observedTopRef.current, floor)) > 0.5That's deliberate and documented in Nothing on master addresses it as of the 2026-08-21 push. The newest InputBar commits are For a regression test, |
|
That narrows it usefully, and it means my
.scroll {
max-height: var(--dsh-composer-text-max-height);
overflow-y: auto;
}With a short draft Which makes the comment at It walks up to
Meanwhile the same pin works on the key path, and it doesn't need the rAF loop since that's one reveal per key rather than a drag: ta.addEventListener('keydown', () => {
const pinned = host.scrollTop
requestAnimationFrame(() => { host.scrollTop = pinned })
}) |
Uh oh!
There was an error while loading. Please reload this page.
Description
In a conversation with enough history to scroll, when the user scrolls up to view older messages and then types or drags to select text inside the composer textarea, the chat transcript automatically scrolls down incrementally with every typed or selected character until it reaches the very bottom.
Steps to Reproduce
data-conversation-scroll) scrolls down step-by-step, eventually jumping all the way to the bottom.Environment
0.1.1-rc.2Preliminary Analysis (Hypothesis only, for maintainer reference)
Note: This is a preliminary deduction based on inspecting the frontend layout and has not been verified with a full code patch.
.wSkVaW_composerSeat) is nested inside the conversation scrolling container (.wSkVaW_scrollBodywithdata-conversation-scroll) using CSSposition: sticky; bottom: 0.<textarea>(.uV2eYG_input), the browser text/selection engine native selection tracking (ScrollRectToVisible/ autoscroll) appears to evaluate the selection coordinates against the ancestor scroll container normal layout flow, propagating unintended downward scroll increments to the parentscrollBody.Expected Behavior
Typing or selecting text in the composer should not affect the scroll position of the conversation transcript when inspecting history.
All reactions