@@ -25,10 +25,8 @@ import {
2525 type LocalAgentInfo ,
2626} from './utils/local-agent-registry'
2727
28- import {
29- chatThemes ,
30- createMarkdownPalette ,
31- } from './utils/theme-system'
28+ import { chatThemes , createMarkdownPalette } from './utils/theme-system'
29+ import { createChatScrollAcceleration } from './utils/chat-scroll-accel'
3230import { TextAttributes } from '@opentui/core'
3331
3432import type { ToolName } from '@codebuff/sdk'
@@ -150,7 +148,9 @@ const filterSlashCommands = (
150148
151149 for ( const command of commands ) {
152150 const id = command . id . toLowerCase ( )
153- const aliasList = ( command . aliases ?? [ ] ) . map ( ( alias ) => alias . toLowerCase ( ) )
151+ const aliasList = ( command . aliases ?? [ ] ) . map ( ( alias ) =>
152+ alias . toLowerCase ( ) ,
153+ )
154154
155155 if (
156156 id . startsWith ( normalized ) ||
@@ -162,7 +162,9 @@ const filterSlashCommands = (
162162
163163 for ( const command of commands ) {
164164 const id = command . id . toLowerCase ( )
165- const aliasList = ( command . aliases ?? [ ] ) . map ( ( alias ) => alias . toLowerCase ( ) )
165+ const aliasList = ( command . aliases ?? [ ] ) . map ( ( alias ) =>
166+ alias . toLowerCase ( ) ,
167+ )
166168 const description = command . description . toLowerCase ( )
167169
168170 if (
@@ -271,12 +273,21 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
271273 }
272274 } , [ ] )
273275
274- const { scrollToAgent, scrollboxProps } = useChatScrollbox (
276+ const { scrollToLatest , scrollToAgent, scrollboxProps } = useChatScrollbox (
275277 scrollRef ,
276278 messages ,
277279 agentRefsMap ,
278280 )
279281
282+ const inertialScrollAcceleration = useMemo (
283+ ( ) => createChatScrollAcceleration ( ) ,
284+ [ ] ,
285+ )
286+
287+ const appliedScrollboxProps = inertialScrollAcceleration
288+ ? { ...scrollboxProps , scrollAcceleration : inertialScrollAcceleration }
289+ : scrollboxProps
290+
280291 const localAgents = useMemo ( ( ) => loadLocalAgents ( ) , [ ] )
281292
282293 const slashContext = useMemo (
@@ -334,10 +345,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
334345 } , [ slashContext . active , slashContext . query ] )
335346
336347 useEffect ( ( ) => {
337- if (
338- slashMatches . length > 0 &&
339- slashSelectedIndex >= slashMatches . length
340- ) {
348+ if ( slashMatches . length > 0 && slashSelectedIndex >= slashMatches . length ) {
341349 setSlashSelectedIndex ( slashMatches . length - 1 )
342350 }
343351 if ( slashMatches . length === 0 && slashSelectedIndex !== 0 ) {
@@ -354,10 +362,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
354362 } , [ mentionContext . active , mentionContext . query ] )
355363
356364 useEffect ( ( ) => {
357- if (
358- agentMatches . length > 0 &&
359- agentSelectedIndex >= agentMatches . length
360- ) {
365+ if ( agentMatches . length > 0 && agentSelectedIndex >= agentMatches . length ) {
361366 setAgentSelectedIndex ( agentMatches . length - 1 )
362367 }
363368 if ( agentMatches . length === 0 && agentSelectedIndex !== 0 ) {
@@ -379,9 +384,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
379384 return false
380385 }
381386
382- const hasModifier = Boolean (
383- key . ctrl || key . meta || key . alt || key . option ,
384- )
387+ const hasModifier = Boolean ( key . ctrl || key . meta || key . alt || key . option )
385388
386389 if ( key . name === 'down' && ! hasModifier ) {
387390 setSlashSelectedIndex ( ( prev ) =>
@@ -408,8 +411,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
408411 }
409412
410413 if ( key . name === 'return' && ! key . shift && ! hasModifier ) {
411- const selected =
412- slashMatches [ slashSelectedIndex ] ?? slashMatches [ 0 ]
414+ const selected = slashMatches [ slashSelectedIndex ] ?? slashMatches [ 0 ]
413415 if ( ! selected ) {
414416 return true
415417 }
@@ -432,7 +434,13 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
432434
433435 return false
434436 } ,
435- [ slashContext . active , slashContext . startIndex , slashContext . query , slashMatches , slashSelectedIndex ] ,
437+ [
438+ slashContext . active ,
439+ slashContext . startIndex ,
440+ slashContext . query ,
441+ slashMatches ,
442+ slashSelectedIndex ,
443+ ] ,
436444 )
437445
438446 const handleAgentMenuKey = useCallback (
@@ -449,9 +457,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
449457 return false
450458 }
451459
452- const hasModifier = Boolean (
453- key . ctrl || key . meta || key . alt || key . option ,
454- )
460+ const hasModifier = Boolean ( key . ctrl || key . meta || key . alt || key . option )
455461
456462 if ( key . name === 'down' && ! hasModifier ) {
457463 setAgentSelectedIndex ( ( prev ) =>
@@ -478,8 +484,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
478484 }
479485
480486 if ( key . name === 'return' && ! key . shift && ! hasModifier ) {
481- const selected =
482- agentMatches [ agentSelectedIndex ] ?? agentMatches [ 0 ]
487+ const selected = agentMatches [ agentSelectedIndex ] ?? agentMatches [ 0 ]
483488 if ( ! selected ) {
484489 return true
485490 }
@@ -503,7 +508,13 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
503508
504509 return false
505510 } ,
506- [ mentionContext . active , mentionContext . startIndex , mentionContext . query , agentMatches , agentSelectedIndex ] ,
511+ [
512+ mentionContext . active ,
513+ mentionContext . startIndex ,
514+ mentionContext . query ,
515+ agentMatches ,
516+ agentSelectedIndex ,
517+ ] ,
507518 )
508519
509520 const handleSuggestionMenuKey = useCallback (
@@ -610,6 +621,10 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
610621 }
611622
612623 sendMessage ( trimmed )
624+
625+ setTimeout ( ( ) => {
626+ scrollToLatest ( )
627+ } , 0 )
613628 } , [
614629 inputValue ,
615630 isStreaming ,
@@ -618,6 +633,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
618633 addToQueue ,
619634 streamMessageIdRef ,
620635 isChainInProgressRef ,
636+ scrollToLatest ,
621637 ] )
622638
623639 useKeyboardHandlers ( {
@@ -678,7 +694,7 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
678694 stickyStart = "bottom"
679695 scrollX = { false }
680696 scrollbarOptions = { { visible : false } }
681- { ...scrollboxProps }
697+ { ...appliedScrollboxProps }
682698 style = { {
683699 flexGrow : 1 ,
684700 rootOptions : {
@@ -747,7 +763,8 @@ export const App = ({ initialPrompt }: { initialPrompt?: string } = {}) => {
747763 prefix = "/"
748764 />
749765 ) : null }
750- { ! slashContext . active && mentionContext . active &&
766+ { ! slashContext . active &&
767+ mentionContext . active &&
751768 agentSuggestionItems . length > 0 ? (
752769 < SuggestionMenu
753770 items = { agentSuggestionItems }
0 commit comments