Skip to content

Commit d18dab0

Browse files
committed
fix(marko-virtual): hold chat-pretext pin through in-flight prepends, harden scroll-settle waits.
1 parent 815f91b commit d18dab0

3 files changed

Lines changed: 21 additions & 9 deletions

File tree

examples/marko/chat-pretext/src/routes/+page.marko

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,14 @@ static function messageHeight(message: Message, viewportWidth: number) {
193193
atEnd = statusEl.scrollHeight - statusEl.scrollTop - statusEl.clientHeight <= AT_END_PX
194194
}
195195
// Converge an in-flight "Latest": re-issue the jump while content growth keeps
196-
// moving the end away (see pinPending above). Terminates as soon as the end
197-
// holds through one virtualizer update.
196+
// moving the end away (see pinPending above). Disarms once the end holds AND no
197+
// history load is in flight — a prepend armed before the click can land after
198+
// the end was first reached, and disarming early would leave that late growth
199+
// with no corrective jump.
198200
if (state.pinPending) {
199-
if (atEnd) {
201+
if (atEnd && !loadingHistory) {
200202
state.pinPending = false
201-
} else {
203+
} else if (!atEnd) {
202204
v.scrollToEnd()
203205
}
204206
}

packages/marko-virtual/e2e/app/e2e/chat-pretext.spec.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,21 @@ async function scrollTop(page: Page): Promise<number> {
5757
// virtualizer is still measuring the rows that came into view, and a measured size
5858
// above the viewport makes core compensate the offset. A baseline captured mid-settle
5959
// makes the "this action did NOT move the view" assertion race. Same helper as
60-
// chat.spec.ts; the two pages share this shape.
60+
// chat.spec.ts; the two pages share this shape. Requires several consecutive stable
61+
// samples: a single unchanged pair can straddle a pause between two compensation
62+
// steps under load, reading as settled mid-drift.
6163
async function waitForScrollSettled(page: Page) {
6264
let previous = Number.NaN
65+
let stableSamples = 0
6366
await expect
6467
.poll(
6568
async () => {
6669
const current = await scrollTop(page)
67-
const settled = current === previous
70+
const stable =
71+
!Number.isNaN(previous) && Math.abs(current - previous) <= 0.5
72+
stableSamples = stable ? stableSamples + 1 : 0
6873
previous = current
69-
return settled
74+
return stableSamples >= 3
7075
},
7176
{ timeout: 5000, intervals: [100, 100, 100, 150, 150, 200] },
7277
)

packages/marko-virtual/e2e/app/e2e/chat.spec.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,20 @@ async function scrollTop(page: Page): Promise<number> {
5858
// the viewport makes core compensate the offset — so a baseline captured immediately
5959
// after the jump can still drift by ~100px on its own. Tests that assert "this
6060
// action did NOT move the view" need a quiescent baseline, or they race the settle.
61+
// Requires several consecutive stable samples: a single unchanged pair can straddle
62+
// a pause between two compensation steps under load, reading as settled mid-drift.
6163
async function waitForScrollSettled(page: Page) {
6264
let previous = Number.NaN
65+
let stableSamples = 0
6366
await expect
6467
.poll(
6568
async () => {
6669
const current = await scrollTop(page)
67-
const settled = current === previous
70+
const stable =
71+
!Number.isNaN(previous) && Math.abs(current - previous) <= 0.5
72+
stableSamples = stable ? stableSamples + 1 : 0
6873
previous = current
69-
return settled
74+
return stableSamples >= 3
7075
},
7176
{ timeout: 5000, intervals: [100, 100, 100, 150, 150, 200] },
7277
)

0 commit comments

Comments
 (0)