mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-29 03:44:06 +08:00
fix(ui): preserve auto-scroll pause after wheel up
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/kilo-ui": patch
|
||||
---
|
||||
|
||||
Keep chat auto-scroll detached after a small upward wheel scroll near the latest message.
|
||||
@@ -77,12 +77,12 @@ globalThis.WheelEvent = FakeWheelEvent as unknown as typeof WheelEvent
|
||||
|
||||
const { createAutoScroll } = await import("./create-auto-scroll")
|
||||
|
||||
function setup(options?: { interacted?: () => void }) {
|
||||
function setup(options?: { interacted?: () => void; working?: boolean }) {
|
||||
const el = new FakeElement()
|
||||
const root = createRoot((dispose) => ({
|
||||
dispose,
|
||||
scroll: createAutoScroll({
|
||||
working: () => false,
|
||||
working: () => options?.working ?? false,
|
||||
onUserInteracted: options?.interacted,
|
||||
}),
|
||||
}))
|
||||
@@ -158,15 +158,48 @@ describe("createAutoScroll non-scrollable layouts", () => {
|
||||
ctx.dispose()
|
||||
})
|
||||
|
||||
test("does not pause for an upward wheel on short content", () => {
|
||||
test("does not pause when content overflows after an upward wheel on short content", () => {
|
||||
let interactions = 0
|
||||
const ctx = setup({ interacted: () => interactions++ })
|
||||
const ctx = setup({ interacted: () => interactions++, working: true })
|
||||
const event = new FakeWheelEvent(-20, ctx.el)
|
||||
|
||||
ctx.el.fire("wheel", event as unknown as Event)
|
||||
ctx.el.scrollHeight = 300
|
||||
ctx.resize()
|
||||
|
||||
expect(ctx.scroll.userScrolled()).toBe(false)
|
||||
expect(ctx.el.scrollTop).toBe(300)
|
||||
expect(interactions).toBe(0)
|
||||
ctx.dispose()
|
||||
})
|
||||
|
||||
test("does not pause for an upward wheel at the top", () => {
|
||||
const ctx = setup()
|
||||
ctx.el.scrollHeight = 300
|
||||
const event = new FakeWheelEvent(-5, ctx.el)
|
||||
|
||||
ctx.el.fire("wheel", event as unknown as Event)
|
||||
|
||||
expect(ctx.scroll.userScrolled()).toBe(false)
|
||||
expect(interactions).toBe(0)
|
||||
ctx.dispose()
|
||||
})
|
||||
|
||||
test("does not reattach after an upward wheel within the bottom threshold", () => {
|
||||
const ctx = setup()
|
||||
ctx.el.scrollHeight = 300
|
||||
ctx.el.scrollTop = 195
|
||||
const event = new FakeWheelEvent(-5, ctx.el)
|
||||
|
||||
ctx.el.fire("wheel", event as unknown as Event)
|
||||
ctx.scroll.handleScroll()
|
||||
|
||||
expect(ctx.scroll.userScrolled()).toBe(true)
|
||||
expect(ctx.el.scrollTop).toBe(195)
|
||||
|
||||
ctx.el.scrollTop = 200
|
||||
ctx.scroll.handleScroll()
|
||||
|
||||
expect(ctx.scroll.userScrolled()).toBe(false)
|
||||
ctx.dispose()
|
||||
})
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ export function createAutoScroll(options: AutoScrollOptions) {
|
||||
if (!canScroll(scroll)) return
|
||||
|
||||
if (distance < threshold()) {
|
||||
if (store.userScrolled) setStore("userScrolled", false)
|
||||
if (store.userScrolled && (distance < 2 || !userActivity.isRecent())) setStore("userScrolled", false)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ const isPotentialScrollInput = (event: Event) => {
|
||||
export const createUserActivity = (options: UserActivityOptions) => {
|
||||
let marked = false
|
||||
let time = 0
|
||||
let scroll: HTMLElement | undefined
|
||||
|
||||
// Mark input that may cause the next scroll so layout-driven scroll events
|
||||
// do not get mistaken for the user leaving auto-follow mode.
|
||||
@@ -22,18 +23,21 @@ export const createUserActivity = (options: UserActivityOptions) => {
|
||||
}
|
||||
|
||||
const handleWheel = (event: WheelEvent) => {
|
||||
if (event.deltaY >= 0) return
|
||||
if (event.deltaY >= 0 || !scroll || scroll.scrollTop <= 0) return
|
||||
time = performance.now()
|
||||
options.onWheelUp()
|
||||
}
|
||||
|
||||
return {
|
||||
listen: (el: HTMLElement) => {
|
||||
scroll = el
|
||||
el.addEventListener("wheel", handleWheel, { passive: true, capture: true })
|
||||
el.addEventListener("pointerdown", mark, { passive: true })
|
||||
el.addEventListener("keydown", mark, { passive: true })
|
||||
el.addEventListener("touchstart", mark, { passive: true })
|
||||
|
||||
return () => {
|
||||
if (scroll === el) scroll = undefined
|
||||
el.removeEventListener("wheel", handleWheel, { capture: true })
|
||||
el.removeEventListener("pointerdown", mark)
|
||||
el.removeEventListener("keydown", mark)
|
||||
|
||||
Reference in New Issue
Block a user