@@ -18,7 +18,7 @@ function ExplorerPanel({isVisible = false}: ExplorerPanelProps) {
1818
1919 const [ inputValue , setInputValue ] = useState ( '' ) ;
2020 const [ focusedBlockIndex , setFocusedBlockIndex ] = useState ( - 1 ) ; // -1 means input is focused
21- const [ showSlashCommands , setShowSlashCommands ] = useState ( false ) ;
21+ const [ isSlashCommandsVisible , setIsSlashCommandsVisible ] = useState ( false ) ;
2222 const [ isMinimized , setIsMinimized ] = useState ( false ) ; // state for slide-down
2323 const textareaRef = useRef < HTMLTextAreaElement > ( null ) ;
2424 const scrollContainerRef = useRef < HTMLDivElement > ( null ) ;
@@ -27,6 +27,7 @@ function ExplorerPanel({isVisible = false}: ExplorerPanelProps) {
2727 Map < number , ( key : 'Enter' | 'ArrowUp' | 'ArrowDown' ) => boolean >
2828 > ( new Map ( ) ) ;
2929 const panelRef = useRef < HTMLDivElement > ( null ) ;
30+ const hoveredBlockIndex = useRef < number > ( - 1 ) ;
3031
3132 // Custom hooks
3233 const { panelSize, handleMaxSize, handleMedSize} = usePanelSizing ( ) ;
@@ -112,6 +113,32 @@ function ExplorerPanel({isVisible = false}: ExplorerPanelProps) {
112113 blockRefs . current = blockRefs . current . slice ( 0 , blocks . length ) ;
113114 } , [ blocks ] ) ;
114115
116+ // Auto-focus input when user starts typing while a block is focused
117+ useEffect ( ( ) => {
118+ if ( ! isVisible ) {
119+ return undefined ;
120+ }
121+
122+ const handleKeyDown = ( e : KeyboardEvent ) => {
123+ if ( focusedBlockIndex !== - 1 ) {
124+ const isPrintableChar =
125+ e . key . length === 1 && ! e . ctrlKey && ! e . metaKey && ! e . altKey ;
126+
127+ if ( isPrintableChar ) {
128+ e . preventDefault ( ) ;
129+ setFocusedBlockIndex ( - 1 ) ;
130+ textareaRef . current ?. focus ( ) ;
131+ setInputValue ( prev => prev + e . key ) ;
132+ }
133+ }
134+ } ;
135+
136+ document . addEventListener ( 'keydown' , handleKeyDown ) ;
137+ return ( ) => {
138+ document . removeEventListener ( 'keydown' , handleKeyDown ) ;
139+ } ;
140+ } , [ isVisible , focusedBlockIndex ] ) ;
141+
115142 const handleKeyDown = ( e : React . KeyboardEvent < HTMLTextAreaElement > ) => {
116143 if ( e . key === 'Escape' && isPolling && ! interruptRequested ) {
117144 e . preventDefault ( ) ;
@@ -139,10 +166,6 @@ function ExplorerPanel({isVisible = false}: ExplorerPanelProps) {
139166 textareaRef . current ?. focus ( ) ;
140167 }
141168
142- // Check if we should show slash commands
143- const shouldShow = value . startsWith ( '/' ) && ! value . includes ( ' ' ) && value . length > 1 ;
144- setShowSlashCommands ( shouldShow ) ;
145-
146169 // Auto-resize textarea
147170 const textarea = e . target ;
148171 textarea . style . height = 'auto' ;
@@ -155,6 +178,7 @@ function ExplorerPanel({isVisible = false}: ExplorerPanelProps) {
155178 } ;
156179
157180 const handleInputClick = ( ) => {
181+ hoveredBlockIndex . current = - 1 ;
158182 setFocusedBlockIndex ( - 1 ) ;
159183 textareaRef . current ?. focus ( ) ;
160184 setIsMinimized ( false ) ;
@@ -168,20 +192,15 @@ function ExplorerPanel({isVisible = false}: ExplorerPanelProps) {
168192 // Execute the command
169193 command . handler ( ) ;
170194
171- // Clear input and hide slash commands
195+ // Clear input
172196 setInputValue ( '' ) ;
173- setShowSlashCommands ( false ) ;
174197
175198 // Reset textarea height
176199 if ( textareaRef . current ) {
177200 textareaRef . current . style . height = 'auto' ;
178201 }
179202 } ;
180203
181- const handleSlashCommandsClose = ( ) => {
182- setShowSlashCommands ( false ) ;
183- } ;
184-
185204 const panelContent = (
186205 < PanelContainers
187206 ref = { panelRef }
@@ -206,7 +225,23 @@ function ExplorerPanel({isVisible = false}: ExplorerPanelProps) {
206225 isFocused = { focusedBlockIndex === index }
207226 isPolling = { isPolling }
208227 onClick = { ( ) => handleBlockClick ( index ) }
209- onMouseEnter = { ( ) => setFocusedBlockIndex ( index ) }
228+ onMouseEnter = { ( ) => {
229+ // Don't change focus while slash commands menu is open or if already on this block
230+ if ( isSlashCommandsVisible || hoveredBlockIndex . current === index ) {
231+ return ;
232+ }
233+
234+ hoveredBlockIndex . current = index ;
235+ setFocusedBlockIndex ( index ) ;
236+ if ( document . activeElement === textareaRef . current ) {
237+ textareaRef . current ?. blur ( ) ;
238+ }
239+ } }
240+ onMouseLeave = { ( ) => {
241+ if ( hoveredBlockIndex . current === index ) {
242+ hoveredBlockIndex . current = - 1 ;
243+ }
244+ } }
210245 onDelete = { ( ) => deleteFromIndex ( index ) }
211246 onNavigate = { ( ) => setIsMinimized ( true ) }
212247 onRegisterEnterHandler = { handler => {
@@ -220,14 +255,13 @@ function ExplorerPanel({isVisible = false}: ExplorerPanelProps) {
220255 ref = { textareaRef }
221256 inputValue = { inputValue }
222257 focusedBlockIndex = { focusedBlockIndex }
223- showSlashCommands = { showSlashCommands }
224258 isPolling = { isPolling }
225259 interruptRequested = { interruptRequested }
226260 onInputChange = { handleInputChange }
227261 onKeyDown = { handleKeyDown }
228262 onInputClick = { handleInputClick }
229263 onCommandSelect = { handleCommandSelect }
230- onSlashCommandsClose = { handleSlashCommandsClose }
264+ onSlashCommandsVisibilityChange = { setIsSlashCommandsVisible }
231265 onMaxSize = { handleMaxSize }
232266 onMedSize = { handleMedSize }
233267 onClear = { startNewSession }
0 commit comments