@@ -15,7 +15,7 @@ import { AIDroppedFiles } from "./aidroppedfiles";
1515import { AIPanelHeader } from "./aipanelheader" ;
1616import { AIPanelInput , type AIPanelInputRef } from "./aipanelinput" ;
1717import { AIPanelMessages } from "./aipanelmessages" ;
18- import { WaveAIModel } from "./waveai-model" ;
18+ import { WaveAIModel , type DroppedFile } from "./waveai-model" ;
1919
2020interface AIPanelProps {
2121 className ?: string ;
@@ -26,8 +26,7 @@ const AIPanelComponent = memo(({ className, onClose }: AIPanelProps) => {
2626 const [ input , setInput ] = useState ( "" ) ;
2727 const [ isDragOver , setIsDragOver ] = useState ( false ) ;
2828 const [ errorMessage , setErrorMessage ] = useState < string > ( "" ) ;
29- const modelRef = useRef ( new WaveAIModel ( globalStore . get ( atoms . staticTabId ) ) ) ;
30- const model = modelRef . current ;
29+ const model = WaveAIModel . getInstance ( ) ;
3130 const realMessageRef = useRef < AIMessage > ( null ) ;
3231 const inputRef = useRef < AIPanelInputRef > ( null ) ;
3332
@@ -83,14 +82,18 @@ const AIPanelComponent = memo(({ className, onClose }: AIPanelProps) => {
8382 } ;
8483 } , [ ] ) ;
8584
85+ useEffect ( ( ) => {
86+ model . registerInputRef ( inputRef ) ;
87+ } , [ model ] ) ;
88+
8689 const handleSubmit = async ( e : React . FormEvent ) => {
8790 e . preventDefault ( ) ;
8891 if ( ! input . trim ( ) || status !== "ready" ) return ;
8992
9093 // Clear any previous error when submitting
9194 setErrorMessage ( "" ) ;
9295
93- const droppedFiles = globalStore . get ( model . droppedFiles ) ;
96+ const droppedFiles = globalStore . get ( model . droppedFiles ) as DroppedFile [ ] ;
9497
9598 // Prepare AI message parts (for backend)
9699 const aiMessageParts : AIMessagePart [ ] = [ { type : "text" , text : input . trim ( ) } ] ;
@@ -191,10 +194,28 @@ const AIPanelComponent = memo(({ className, onClose }: AIPanelProps) => {
191194 }
192195 } ;
193196
197+ const handleClick = ( e : React . MouseEvent ) => {
198+ // Check if the click target is an interactive element
199+ const target = e . target as HTMLElement ;
200+ const isInteractive = target . closest ( 'button, a, input, textarea, select, [role="button"], [tabindex]' ) ;
201+
202+ if ( isInteractive ) {
203+ return ;
204+ }
205+
206+ // Use setTimeout to avoid interfering with other click actions
207+ setTimeout ( ( ) => {
208+ const selection = window . getSelection ( ) ;
209+ if ( ! selection || selection . toString ( ) . length === 0 ) {
210+ model . focusInput ( ) ;
211+ }
212+ } , 0 ) ;
213+ } ;
214+
194215 return (
195216 < div
196217 className = { cn (
197- "bg-gray-900 border-t border-gray-600 flex flex-col relative" ,
218+ "bg-gray-900 border-t border-gray-600 flex flex-col relative mt-1 " ,
198219 className ,
199220 isDragOver && "bg-gray-800 border-accent"
200221 ) }
@@ -207,6 +228,7 @@ const AIPanelComponent = memo(({ className, onClose }: AIPanelProps) => {
207228 onDragEnter = { handleDragEnter }
208229 onDragLeave = { handleDragLeave }
209230 onDrop = { handleDrop }
231+ onClick = { handleClick }
210232 >
211233 { isDragOver && (
212234 < div className = "absolute inset-0 bg-accent/20 border-2 border-dashed border-accent rounded-lg flex items-center justify-center z-10 p-4" >
0 commit comments