mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-18 13:23:33 +08:00
fix(desktop): respect manual scroll during thinking (#727)
Keep programmatic scroll suppression limited to scroll events that still match the requested auto-scroll target. This lets user scrollbar movement take over while active thinking content is growing. Tested: cd desktop && bun run test -- --run src/components/chat/MessageList.test.tsx Tested: bun run check:desktop Confidence: high Scope-risk: narrow
This commit is contained in:
parent
4b6c855eda
commit
3e6fe7d6bb
@ -2557,6 +2557,83 @@ describe('MessageList nested tool calls', () => {
|
||||
expect(screen.queryByRole('button', { name: 'Latest' })).toBeNull()
|
||||
})
|
||||
|
||||
it('lets the user drag away from active thinking output before the programmatic scroll settles', async () => {
|
||||
let resizeCallback: ResizeObserverCallback | null = null
|
||||
class TestResizeObserver {
|
||||
observe = vi.fn()
|
||||
unobserve = vi.fn()
|
||||
disconnect = vi.fn()
|
||||
|
||||
constructor(callback: ResizeObserverCallback) {
|
||||
resizeCallback = callback
|
||||
}
|
||||
}
|
||||
vi.stubGlobal('ResizeObserver', TestResizeObserver)
|
||||
|
||||
useChatStore.setState({
|
||||
sessions: {
|
||||
[ACTIVE_TAB]: makeSessionState({
|
||||
chatState: 'thinking',
|
||||
activeThinkingId: 'thinking-1',
|
||||
messages: [
|
||||
{
|
||||
id: 'user-1',
|
||||
type: 'user_text',
|
||||
content: '分析一下这段代码',
|
||||
timestamp: 1,
|
||||
},
|
||||
{
|
||||
id: 'thinking-1',
|
||||
type: 'thinking',
|
||||
content: '正在阅读代码路径',
|
||||
timestamp: 2,
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
const { container } = render(<MessageList />)
|
||||
const scroller = container.querySelector('.overflow-y-auto') as HTMLDivElement
|
||||
let scrollTop = 600
|
||||
let scrollHeight = 1000
|
||||
Object.defineProperty(scroller, 'scrollHeight', {
|
||||
configurable: true,
|
||||
get: () => scrollHeight,
|
||||
})
|
||||
Object.defineProperty(scroller, 'clientHeight', { configurable: true, value: 400 })
|
||||
Object.defineProperty(scroller, 'scrollTop', {
|
||||
configurable: true,
|
||||
get: () => scrollTop,
|
||||
set: (value) => {
|
||||
scrollTop = value
|
||||
},
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(resizeCallback).not.toBeNull()
|
||||
})
|
||||
|
||||
act(() => {
|
||||
resizeCallback?.([{
|
||||
contentRect: { height: 600 },
|
||||
} as ResizeObserverEntry], {} as ResizeObserver)
|
||||
})
|
||||
|
||||
scrollTop = 200
|
||||
fireEvent.scroll(scroller)
|
||||
expect(screen.getByRole('button', { name: 'Latest' })).toBeTruthy()
|
||||
|
||||
scrollHeight = 1200
|
||||
act(() => {
|
||||
resizeCallback?.([{
|
||||
contentRect: { height: 760 },
|
||||
} as ResizeObserverEntry], {} as ResizeObserver)
|
||||
})
|
||||
|
||||
expect(scrollTop).toBe(200)
|
||||
})
|
||||
|
||||
it('ignores one-pixel content resize jitter while pinned to active thinking output', async () => {
|
||||
let resizeCallback: ResizeObserverCallback | null = null
|
||||
class TestResizeObserver {
|
||||
|
||||
@ -1506,11 +1506,16 @@ export function MessageList({ sessionId, compact = false }: MessageListProps = {
|
||||
// prevent the jump-to-latest button from flickering during auto-scroll.
|
||||
const container = scrollContainerRef.current
|
||||
if (!container) return
|
||||
const shouldIgnoreRecentProgrammaticScroll =
|
||||
performance.now() < ignoreProgrammaticScrollUntilRef.current &&
|
||||
const matchesProgrammaticScrollTop =
|
||||
ignoreProgrammaticScrollTopRef.current !== null &&
|
||||
Math.abs(container.scrollTop - ignoreProgrammaticScrollTopRef.current) < 1
|
||||
if (isProgrammaticScrollingRef.current || shouldIgnoreRecentProgrammaticScroll) {
|
||||
const shouldIgnoreRecentProgrammaticScroll =
|
||||
matchesProgrammaticScrollTop &&
|
||||
(
|
||||
isProgrammaticScrollingRef.current ||
|
||||
performance.now() < ignoreProgrammaticScrollUntilRef.current
|
||||
)
|
||||
if (shouldIgnoreRecentProgrammaticScroll) {
|
||||
syncVirtualViewportFromContainer(container)
|
||||
return
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user