mirror of
https://github.com/NanmiCoder/claude-code-haha.git
synced 2026-10-10 20:03:13 +08:00
fix(chat): clear conversation marker at latest
This commit is contained in:
@@ -658,9 +658,9 @@ describe('MessageList nested tool calls', () => {
|
||||
|
||||
const { container } = render(<MessageList />)
|
||||
const scroller = container.querySelector('.chat-scroll-area') as HTMLElement
|
||||
let scrollTop = 0
|
||||
let scrollTop = 2
|
||||
Object.defineProperty(scroller, 'clientHeight', { configurable: true, value: 200 })
|
||||
Object.defineProperty(scroller, 'scrollHeight', { configurable: true, value: 450 })
|
||||
Object.defineProperty(scroller, 'scrollHeight', { configurable: true, value: 600 })
|
||||
Object.defineProperty(scroller, 'scrollTop', {
|
||||
configurable: true,
|
||||
get: () => scrollTop,
|
||||
@@ -673,9 +673,15 @@ describe('MessageList nested tool calls', () => {
|
||||
scrollTop = 250
|
||||
fireEvent.scroll(scroller)
|
||||
expect(screen.getByRole('button', { name: /Turn 2 of 4: Second prompt/ }).getAttribute('aria-current')).toBe('location')
|
||||
|
||||
scrollTop = 400
|
||||
fireEvent.scroll(scroller)
|
||||
expect(screen.getAllByRole('button', { name: /Turn \d of 4/ }).every((marker) => (
|
||||
marker.getAttribute('aria-current') === null
|
||||
))).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps a clicked turn active until the user scrolls again', () => {
|
||||
it('keeps a clicked turn active until user scrolling resumes, then clears it at latest', () => {
|
||||
useChatStore.setState({
|
||||
sessions: {
|
||||
[ACTIVE_TAB]: makeSessionState({
|
||||
@@ -714,6 +720,15 @@ describe('MessageList nested tool calls', () => {
|
||||
scrollTop = 0
|
||||
fireEvent.scroll(scroller)
|
||||
expect(screen.getByRole('button', { name: /Turn 1 of 4: First prompt/ }).getAttribute('aria-current')).toBe('location')
|
||||
|
||||
fireEvent.click(thirdTurn)
|
||||
expect(thirdTurn.getAttribute('aria-current')).toBe('location')
|
||||
fireEvent.wheel(scroller, { deltaY: 100 })
|
||||
scrollTop = 700
|
||||
fireEvent.scroll(scroller)
|
||||
expect(screen.getAllByRole('button', { name: /Turn \d of 4/ }).every((marker) => (
|
||||
marker.getAttribute('aria-current') === null
|
||||
))).toBe(true)
|
||||
})
|
||||
|
||||
it('mounts and highlights a far virtualized message selected from the navigator', async () => {
|
||||
|
||||
@@ -1643,7 +1643,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
const [branchingMessageId, setBranchingMessageId] = useState<string | null>(null)
|
||||
const [rewindingTurnId, setRewindingTurnId] = useState<string | null>(null)
|
||||
const [turnUndoConfirmTargetId, setTurnUndoConfirmTargetId] = useState<string | null>(null)
|
||||
const [showJumpToLatest, setShowJumpToLatest] = useState(false)
|
||||
const [isAwayFromLatest, setIsAwayFromLatest] = useState(false)
|
||||
const [virtualViewport, setVirtualViewport] = useState<VirtualViewport>({
|
||||
scrollTop: SCROLL_BOTTOM_SENTINEL,
|
||||
viewportHeight: VIRTUAL_DEFAULT_VIEWPORT_HEIGHT,
|
||||
@@ -1741,7 +1741,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
wasAtBottom: true,
|
||||
})
|
||||
}
|
||||
setShowJumpToLatest(false)
|
||||
setIsAwayFromLatest(false)
|
||||
// Reset flag after the scroll event(s) from scrollIntoView have fired
|
||||
requestAnimationFrame(() => {
|
||||
const latestContainer = scrollContainerRef.current
|
||||
@@ -1827,7 +1827,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
if (isPermissionLayoutShift) return
|
||||
|
||||
shouldAutoScrollRef.current = isAtBottom
|
||||
setShowJumpToLatest(!isAtBottom)
|
||||
setIsAwayFromLatest(!isAtBottom)
|
||||
|
||||
if (resolvedSessionId) {
|
||||
rememberSessionScroll(resolvedSessionId, container)
|
||||
@@ -1842,7 +1842,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
markUserScrollIntent()
|
||||
if (event.deltaY < 0) {
|
||||
shouldAutoScrollRef.current = false
|
||||
setShowJumpToLatest(true)
|
||||
setIsAwayFromLatest(true)
|
||||
}
|
||||
}, [markUserScrollIntent])
|
||||
|
||||
@@ -1862,7 +1862,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
markUserScrollIntent()
|
||||
if (isUpwardScrollKey) {
|
||||
shouldAutoScrollRef.current = false
|
||||
setShowJumpToLatest(true)
|
||||
setIsAwayFromLatest(true)
|
||||
}
|
||||
}, [markUserScrollIntent])
|
||||
|
||||
@@ -1895,7 +1895,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
scrollTop: snapshot.scrollTop,
|
||||
viewportHeight: container.clientHeight || current.viewportHeight || VIRTUAL_DEFAULT_VIEWPORT_HEIGHT,
|
||||
}))
|
||||
setShowJumpToLatest(true)
|
||||
setIsAwayFromLatest(true)
|
||||
} else if (container) {
|
||||
// Switch to a session we were at the bottom of (or first visit): write
|
||||
// the bottom sentinel without going through scrollToBottom's read path,
|
||||
@@ -1909,7 +1909,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
scrollTop: SCROLL_BOTTOM_SENTINEL,
|
||||
viewportHeight: container.clientHeight || current.viewportHeight || VIRTUAL_DEFAULT_VIEWPORT_HEIGHT,
|
||||
}))
|
||||
setShowJumpToLatest(false)
|
||||
setIsAwayFromLatest(false)
|
||||
if (resolvedSessionId) {
|
||||
sessionScrollSnapshots.set(resolvedSessionId, {
|
||||
scrollTop: container.scrollTop,
|
||||
@@ -1942,7 +1942,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
|
||||
useEffect(() => {
|
||||
if (!shouldAutoScrollRef.current) {
|
||||
setShowJumpToLatest(true)
|
||||
setIsAwayFromLatest(true)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2077,13 +2077,15 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
[measuredItemsVersion, renderItemKeys, renderItemMetrics, renderItems, virtualViewport],
|
||||
)
|
||||
const activeConversationNavigationItemId = useMemo(
|
||||
() => getActiveConversationNavigationItemId(
|
||||
conversationNavigationItems,
|
||||
virtualTranscriptWindow.offsets,
|
||||
virtualViewport.scrollTop,
|
||||
virtualViewport.viewportHeight,
|
||||
),
|
||||
[conversationNavigationItems, virtualTranscriptWindow.offsets, virtualViewport],
|
||||
() => isAwayFromLatest
|
||||
? getActiveConversationNavigationItemId(
|
||||
conversationNavigationItems,
|
||||
virtualTranscriptWindow.offsets,
|
||||
virtualViewport.scrollTop,
|
||||
virtualViewport.viewportHeight,
|
||||
)
|
||||
: null,
|
||||
[conversationNavigationItems, isAwayFromLatest, virtualTranscriptWindow.offsets, virtualViewport],
|
||||
)
|
||||
const visibleConversationNavigationItemId =
|
||||
programmaticNavigationItemId && conversationNavigationItems.some((item) => item.id === programmaticNavigationItemId)
|
||||
@@ -2349,7 +2351,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
const isNearby = Math.abs(container.scrollTop - targetScrollTop) <= viewportHeight * 1.25
|
||||
|
||||
shouldAutoScrollRef.current = false
|
||||
setShowJumpToLatest(true)
|
||||
setIsAwayFromLatest(true)
|
||||
ignoreProgrammaticScrollUntilRef.current = performance.now() + 250
|
||||
ignoreProgrammaticScrollTopRef.current = targetScrollTop
|
||||
|
||||
@@ -2400,7 +2402,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
|
||||
setActiveConversationFindMatch(match)
|
||||
shouldAutoScrollRef.current = false
|
||||
setShowJumpToLatest(true)
|
||||
setIsAwayFromLatest(true)
|
||||
ignoreProgrammaticScrollUntilRef.current = performance.now() + 250
|
||||
ignoreProgrammaticScrollTopRef.current = targetScrollTop
|
||||
setScrollTopWithoutLayoutRead(container, targetScrollTop)
|
||||
@@ -2695,7 +2697,7 @@ export function MessageList({ sessionId, compact = false, mobileLayout = false }
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showJumpToLatest && (
|
||||
{isAwayFromLatest && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
|
||||
Reference in New Issue
Block a user