@@ -45,6 +45,11 @@ interface ChatTextAreaProps {
4545 modeShortcutText : string
4646}
4747
48+ interface CursorPositionState {
49+ value : string
50+ afterRender ?: "SET_CURSOR_FIRST_LINE" | "SET_CURSOR_LAST_LINE" | "SET_CURSOR_START"
51+ }
52+
4853const ChatTextArea = forwardRef < HTMLTextAreaElement , ChatTextAreaProps > (
4954 (
5055 {
@@ -158,6 +163,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
158163 const [ historyIndex , setHistoryIndex ] = useState ( - 1 )
159164 const [ tempInput , setTempInput ] = useState ( "" )
160165 const [ promptHistory , setPromptHistory ] = useState < string [ ] > ( [ ] )
166+ const [ inputValueWithCursor , setInputValueWithCursor ] = useState < CursorPositionState > ( { value : inputValue } )
161167
162168 // Initialize prompt history from task history
163169 useEffect ( ( ) => {
@@ -411,17 +417,10 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
411417 setHistoryIndex ( newIndex )
412418 const historicalPrompt = promptHistory [ newIndex ]
413419 setInputValue ( historicalPrompt )
414-
415- // Set cursor to end of first line
416- setTimeout ( ( ) => {
417- if ( textAreaRef . current ) {
418- const firstLineEnd =
419- historicalPrompt . indexOf ( "\n" ) === - 1
420- ? historicalPrompt . length
421- : historicalPrompt . indexOf ( "\n" )
422- textAreaRef . current . setSelectionRange ( firstLineEnd , firstLineEnd )
423- }
424- } , 0 )
420+ setInputValueWithCursor ( {
421+ value : historicalPrompt ,
422+ afterRender : "SET_CURSOR_FIRST_LINE" ,
423+ } )
425424 }
426425 return
427426 }
@@ -435,26 +434,18 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
435434 setHistoryIndex ( newIndex )
436435 const historicalPrompt = promptHistory [ newIndex ]
437436 setInputValue ( historicalPrompt )
438-
439- // Set cursor to start of last line
440- setTimeout ( ( ) => {
441- if ( textAreaRef . current ) {
442- const lines = historicalPrompt . split ( "\n" )
443- const lastLineStart = historicalPrompt . length - lines [ lines . length - 1 ] . length
444- textAreaRef . current . setSelectionRange ( lastLineStart , lastLineStart )
445- }
446- } , 0 )
437+ setInputValueWithCursor ( {
438+ value : historicalPrompt ,
439+ afterRender : "SET_CURSOR_LAST_LINE" ,
440+ } )
447441 } else if ( historyIndex === 0 ) {
448442 // Return to current input
449443 setHistoryIndex ( - 1 )
450444 setInputValue ( tempInput )
451-
452- // Set cursor to start
453- setTimeout ( ( ) => {
454- if ( textAreaRef . current ) {
455- textAreaRef . current . setSelectionRange ( 0 , 0 )
456- }
457- } , 0 )
445+ setInputValueWithCursor ( {
446+ value : tempInput ,
447+ afterRender : "SET_CURSOR_START" ,
448+ } )
458449 }
459450 return
460451 }
@@ -544,6 +535,27 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
544535 }
545536 } , [ inputValue , intendedCursorPosition ] )
546537
538+ // Handle cursor positioning after history navigation
539+ useLayoutEffect ( ( ) => {
540+ if ( ! inputValueWithCursor . afterRender || ! textAreaRef . current ) return
541+
542+ if ( inputValueWithCursor . afterRender === "SET_CURSOR_FIRST_LINE" ) {
543+ const firstLineEnd =
544+ inputValueWithCursor . value . indexOf ( "\n" ) === - 1
545+ ? inputValueWithCursor . value . length
546+ : inputValueWithCursor . value . indexOf ( "\n" )
547+ textAreaRef . current . setSelectionRange ( firstLineEnd , firstLineEnd )
548+ } else if ( inputValueWithCursor . afterRender === "SET_CURSOR_LAST_LINE" ) {
549+ const lines = inputValueWithCursor . value . split ( "\n" )
550+ const lastLineStart = inputValueWithCursor . value . length - lines [ lines . length - 1 ] . length
551+ textAreaRef . current . setSelectionRange ( lastLineStart , lastLineStart )
552+ } else if ( inputValueWithCursor . afterRender === "SET_CURSOR_START" ) {
553+ textAreaRef . current . setSelectionRange ( 0 , 0 )
554+ }
555+
556+ setInputValueWithCursor ( { value : inputValueWithCursor . value } )
557+ } , [ inputValueWithCursor ] )
558+
547559 // Ref to store the search timeout.
548560 const searchTimeoutRef = useRef < NodeJS . Timeout | null > ( null )
549561
0 commit comments