Skip to content

Commit c6b48a9

Browse files
brandonkachenclaude
andcommitted
refactor: convert isUserCollapsingRef to callback pattern
Simplifies collapse handling by using a callback function instead of a ref parameter: - Pass callback function to useChatScrollbox instead of ref - Inline collapse logic into handleCollapseToggle - Use setTimeout to reset flag after state update - Remove separate setCollapsedAgentsWithFlag wrapper - Remove useEffect that was watching collapsedAgents changes This is cleaner and more explicit about when the flag is checked. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d0697bb commit c6b48a9

File tree

2 files changed

+31
-34
lines changed

2 files changed

+31
-34
lines changed

cli/src/chat.tsx

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -222,25 +222,13 @@ export const Chat = ({
222222

223223
const isUserCollapsingRef = useRef<boolean>(false)
224224

225-
// Reset the collapse flag after collapse state changes
226-
useEffect(() => {
227-
isUserCollapsingRef.current = false
228-
}, [collapsedAgents])
229-
230-
// Wrapper for setCollapsedAgents that sets the flag to prevent auto-scroll
231-
const setCollapsedAgentsWithFlag = useCallback(
232-
(action: React.SetStateAction<Set<string>>) => {
233-
isUserCollapsingRef.current = true
234-
setCollapsedAgents(action)
235-
},
236-
[setCollapsedAgents],
237-
)
238-
239225
const handleCollapseToggle = useCallback(
240226
(id: string) => {
241227
const wasCollapsed = collapsedAgents.has(id)
242228

243-
setCollapsedAgentsWithFlag((prev) => {
229+
// Set flag to prevent auto-scroll during user-initiated collapse
230+
isUserCollapsingRef.current = true
231+
setCollapsedAgents((prev) => {
244232
const next = new Set(prev)
245233
if (next.has(id)) {
246234
next.delete(id)
@@ -250,6 +238,11 @@ export const Chat = ({
250238
return next
251239
})
252240

241+
// Reset flag after state update completes
242+
setTimeout(() => {
243+
isUserCollapsingRef.current = false
244+
}, 0)
245+
253246
setUserOpenedAgents((prev) => {
254247
const next = new Set(prev)
255248
if (wasCollapsed) {
@@ -260,13 +253,17 @@ export const Chat = ({
260253
return next
261254
})
262255
},
263-
[collapsedAgents, setCollapsedAgentsWithFlag, setUserOpenedAgents],
256+
[collapsedAgents, setCollapsedAgents, setUserOpenedAgents],
264257
)
265258

259+
const isUserCollapsing = useCallback(() => {
260+
return isUserCollapsingRef.current
261+
}, [])
262+
266263
const { scrollToLatest, scrollboxProps, isAtBottom } = useChatScrollbox(
267264
scrollRef,
268265
messages,
269-
isUserCollapsingRef,
266+
isUserCollapsing,
270267
)
271268

272269
const inertialScrollAcceleration = useMemo(
@@ -629,7 +626,7 @@ export const Chat = ({
629626
isWaitingForResponse={isWaitingForResponse}
630627
timerStartTime={timerStartTime}
631628
onCollapseToggle={handleCollapseToggle}
632-
setCollapsedAgents={setCollapsedAgentsWithFlag}
629+
setCollapsedAgents={setCollapsedAgents}
633630
setFocusedAgentId={setFocusedAgentId}
634631
userOpenedAgents={userOpenedAgents}
635632
setUserOpenedAgents={setUserOpenedAgents}
@@ -655,17 +652,10 @@ export const Chat = ({
655652
width: '100%',
656653
}}
657654
>
658-
{/* Left section - queue preview */}
655+
{/* Left section - status indicator */}
659656
<box style={{ flexGrow: 1, flexShrink: 1, flexBasis: 0 }}>
660-
{shouldShowQueuePreview && (
661-
<text style={{ wrapMode: 'none' }}>
662-
<span fg={theme.secondary} bg={theme.inputFocusedBg}>
663-
{` ${formatQueuedPreview(
664-
queuedMessages,
665-
Math.max(30, terminalWidth - 25),
666-
)} `}
667-
</span>
668-
</text>
657+
{hasStatus && (
658+
<text style={{ wrapMode: 'none' }}>{statusIndicatorNode}</text>
669659
)}
670660
</box>
671661

@@ -691,7 +681,7 @@ export const Chat = ({
691681
)}
692682
</box>
693683

694-
{/* Right section - status indicator */}
684+
{/* Right section - queue preview */}
695685
<box
696686
style={{
697687
flexGrow: 1,
@@ -701,8 +691,15 @@ export const Chat = ({
701691
justifyContent: 'flex-end',
702692
}}
703693
>
704-
{hasStatus && (
705-
<text style={{ wrapMode: 'none' }}>{statusIndicatorNode}</text>
694+
{shouldShowQueuePreview && (
695+
<text style={{ wrapMode: 'none' }}>
696+
<span fg={theme.secondary} bg={theme.inputFocusedBg}>
697+
{` ${formatQueuedPreview(
698+
queuedMessages,
699+
Math.max(30, terminalWidth - 25),
700+
)} `}
701+
</span>
702+
</text>
706703
)}
707704
</box>
708705
</box>

cli/src/hooks/use-scroll-management.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const easeOutCubic = (t: number): number => {
99
export const useChatScrollbox = (
1010
scrollRef: React.RefObject<ScrollBoxRenderable | null>,
1111
messages: any[],
12-
isUserCollapsingRef: React.MutableRefObject<boolean>,
12+
isUserCollapsing: () => boolean,
1313
) => {
1414
const autoScrollEnabledRef = useRef<boolean>(true)
1515
const programmaticScrollRef = useRef<boolean>(false)
@@ -112,7 +112,7 @@ export const useChatScrollbox = (
112112
if (scrollbox.scrollTop > maxScroll) {
113113
programmaticScrollRef.current = true
114114
scrollbox.scrollTop = maxScroll
115-
} else if (autoScrollEnabledRef.current && !isUserCollapsingRef.current) {
115+
} else if (autoScrollEnabledRef.current && !isUserCollapsing()) {
116116
programmaticScrollRef.current = true
117117
scrollbox.scrollTop = maxScroll
118118
}
@@ -121,7 +121,7 @@ export const useChatScrollbox = (
121121
return () => clearTimeout(timeoutId)
122122
}
123123
return undefined
124-
}, [messages, scrollToLatest, scrollRef, isUserCollapsingRef])
124+
}, [messages, scrollToLatest, scrollRef, isUserCollapsing])
125125

126126
useEffect(() => {
127127
return () => {

0 commit comments

Comments
 (0)