@@ -5,9 +5,30 @@ import type { SessionStore } from "../../../../store/session-store.svelte.js";
55
66const listenMock = vi . fn ( ) ;
77const invokeMock = vi . fn ( ) ;
8+ let zoomLevel = 0.8 ;
89
910let AgentInputState : typeof import ( "../agent-input-state.svelte.js" ) . AgentInputState ;
1011
12+ interface DragPositionEvent {
13+ payload : {
14+ paths : string [ ] ;
15+ position : {
16+ x : number ;
17+ y : number ;
18+ } ;
19+ } ;
20+ }
21+
22+ function requireDragOverHandler (
23+ handler : ( ( event : DragPositionEvent ) => void ) | null
24+ ) : ( event : DragPositionEvent ) => void {
25+ if ( handler === null ) {
26+ throw new Error ( "Expected tauri://drag-over listener to register" ) ;
27+ }
28+
29+ return handler ;
30+ }
31+
1132function createPendingPromise < T > ( ) {
1233 let resolveValue : ( ( value : T ) => void ) | null = null ;
1334 const promise = new Promise < T > ( ( resolve ) => {
@@ -34,13 +55,19 @@ describe("AgentInputState drag-drop listener lifecycle", () => {
3455 beforeEach ( async ( ) => {
3556 listenMock . mockReset ( ) ;
3657 invokeMock . mockReset ( ) ;
58+ zoomLevel = 0.8 ;
3759
3860 mock . module ( "@tauri-apps/api/core" , ( ) => ( {
3961 invoke : invokeMock ,
4062 } ) ) ;
4163 mock . module ( "@tauri-apps/api/event" , ( ) => ( {
4264 listen : listenMock ,
4365 } ) ) ;
66+ mock . module ( "$lib/services/zoom.svelte.js" , ( ) => ( {
67+ getZoomService : ( ) => ( {
68+ zoomLevel,
69+ } ) ,
70+ } ) ) ;
4471
4572 ( { AgentInputState } = await import ( "../agent-input-state.svelte.js" ) ) ;
4673 } ) ;
@@ -77,4 +104,90 @@ describe("AgentInputState drag-drop listener lifecycle", () => {
77104 expect ( unlistenDrop ) . toHaveBeenCalledTimes ( 1 ) ;
78105 expect ( unlistenLeave ) . toHaveBeenCalledTimes ( 1 ) ;
79106 } ) ;
80- } ) ;
107+
108+ it ( "does not highlight the composer for native drag positions outside its zoomed bounds" , async ( ) => {
109+ let dragOverHandler : ( ( event : DragPositionEvent ) => void ) | null = null ;
110+
111+ listenMock . mockImplementation ( ( eventName : string , handler : ( ( event : DragPositionEvent ) => void ) | ( ( ) => void ) ) => {
112+ if ( eventName === "tauri://drag-over" ) {
113+ dragOverHandler = handler as ( event : DragPositionEvent ) => void ;
114+ }
115+
116+ return Promise . resolve ( ( ) => { } ) ;
117+ } ) ;
118+
119+ const state = new AgentInputState ( { } as SessionStore , { } as PanelStore ) ;
120+ state . containerRef = {
121+ getBoundingClientRect : ( ) => ( {
122+ x : 100 ,
123+ y : 100 ,
124+ width : 100 ,
125+ height : 100 ,
126+ top : 100 ,
127+ right : 200 ,
128+ bottom : 200 ,
129+ left : 100 ,
130+ toJSON : ( ) => ( { } ) ,
131+ } ) ,
132+ } as HTMLElement ;
133+
134+ state . initialize ( ) ;
135+ await flushAsync ( ) ;
136+
137+ expect ( dragOverHandler ) . not . toBeNull ( ) ;
138+ const registeredDragOverHandler = requireDragOverHandler ( dragOverHandler ) ;
139+
140+ registeredDragOverHandler ( {
141+ payload : {
142+ paths : [ "/tmp/image.png" ] ,
143+ position : { x : 170 , y : 120 } ,
144+ } ,
145+ } ) ;
146+
147+ expect ( state . isDragActive ) . toBe ( true ) ;
148+ expect ( state . isDragHovering ) . toBe ( false ) ;
149+ } ) ;
150+
151+ it ( "does not highlight the composer for native drag positions just outside its bounds" , async ( ) => {
152+ let dragOverHandler : ( ( event : DragPositionEvent ) => void ) | null = null ;
153+ zoomLevel = 1 ;
154+
155+ listenMock . mockImplementation ( ( eventName : string , handler : ( ( event : DragPositionEvent ) => void ) | ( ( ) => void ) ) => {
156+ if ( eventName === "tauri://drag-over" ) {
157+ dragOverHandler = handler as ( event : DragPositionEvent ) => void ;
158+ }
159+
160+ return Promise . resolve ( ( ) => { } ) ;
161+ } ) ;
162+
163+ const state = new AgentInputState ( { } as SessionStore , { } as PanelStore ) ;
164+ state . containerRef = {
165+ getBoundingClientRect : ( ) => ( {
166+ x : 100 ,
167+ y : 100 ,
168+ width : 100 ,
169+ height : 100 ,
170+ top : 100 ,
171+ right : 200 ,
172+ bottom : 200 ,
173+ left : 100 ,
174+ toJSON : ( ) => ( { } ) ,
175+ } ) ,
176+ } as HTMLElement ;
177+
178+ state . initialize ( ) ;
179+ await flushAsync ( ) ;
180+
181+ expect ( dragOverHandler ) . not . toBeNull ( ) ;
182+ const registeredDragOverHandler = requireDragOverHandler ( dragOverHandler ) ;
183+
184+ registeredDragOverHandler ( {
185+ payload : {
186+ paths : [ "/tmp/image.png" ] ,
187+ position : { x : 201 , y : 120 } ,
188+ } ,
189+ } ) ;
190+
191+ expect ( state . isDragHovering ) . toBe ( false ) ;
192+ } ) ;
193+ } ) ;
0 commit comments