@@ -331,8 +331,10 @@ const ChatInputInner: React.FC<ChatInputProps> = (props) => {
331331 const handleChatInputSectionRef = useCallback ( ( el : HTMLDivElement | null ) => {
332332 chatInputSectionRef . current = el ;
333333 // Set an initial value once (avoid overriding later transitions).
334+ // Default to "done" so non-workspace variants (or stories that don't rely on this)
335+ // never get stuck waiting for a focus attempt that won't run.
334336 if ( el && ! el . hasAttribute ( "data-autofocus-state" ) ) {
335- el . setAttribute ( "data-autofocus-state" , "pending " ) ;
337+ el . setAttribute ( "data-autofocus-state" , "done " ) ;
336338 }
337339 } , [ ] ) ;
338340
@@ -643,9 +645,31 @@ const ChatInputInner: React.FC<ChatInputProps> = (props) => {
643645 if ( cancelled ) return ;
644646
645647 attempts += 1 ;
646- focusMessageInput ( ) ;
647648
648649 const input = inputRef . current ;
650+ const active = document . activeElement ;
651+
652+ // If something else already took focus (e.g. a modal, command palette, or a user click),
653+ // do not keep fighting it across frames.
654+ if (
655+ active instanceof HTMLElement &&
656+ active !== document . body &&
657+ active !== document . documentElement
658+ ) {
659+ const isWithinChatInput = ! ! chatInputSectionRef . current ?. contains ( active ) ;
660+ const isInput = ! ! input && active === input ;
661+
662+ // If something else already took focus (e.g. a modal, command palette, or a user click),
663+ // do not keep fighting it across frames.
664+ if ( ! isWithinChatInput && ! isInput ) {
665+ setChatInputAutoFocusState ( "done" ) ;
666+ return ;
667+ }
668+ }
669+
670+ // Try focusing; if the input isn't mounted yet, we'll retry on the next frame.
671+ focusMessageInput ( ) ;
672+
649673 const isFocused = ! ! input && document . activeElement === input ;
650674 const isDone = isFocused || attempts >= maxFrames ;
651675
0 commit comments