@@ -4,6 +4,7 @@ import { act, cleanup as cleanupRender, fireEvent, render, screen } from '@testi
44import { useEditorStore } from '@site/store/store'
55import { RESET_ZOOM } from '@site/canvas/math'
66import {
7+ isCanvasPointerPanActive ,
78 isCanvasSpacePanActive ,
89 panDeltaFromWheel ,
910 setCanvasSpacePanActive ,
@@ -39,6 +40,21 @@ function dispatchWheel(target: Element, props: Record<string, unknown>) {
3940 return event
4041}
4142
43+ function dispatchPointer ( target : Element , type : string , props : Record < string , unknown > ) {
44+ const event = new Event ( type , { bubbles : true , cancelable : true } )
45+ for ( const [ key , value ] of Object . entries ( props ) ) {
46+ Object . defineProperty ( event , key , { configurable : true , value } )
47+ }
48+ target . dispatchEvent ( event )
49+ return event
50+ }
51+
52+ function parseTranslate ( transform : string ) : { x : number ; y : number } {
53+ const match = / ^ t r a n s l a t e \( ( - ? \d + ) p x , ( - ? \d + ) p x \) s c a l e \( 1 \) $ / . exec ( transform )
54+ if ( ! match ) throw new Error ( `Unexpected transform: ${ transform } ` )
55+ return { x : Number ( match [ 1 ] ) , y : Number ( match [ 2 ] ) }
56+ }
57+
4258beforeEach ( ( ) => {
4359 useEditorStore . setState ( {
4460 zoom : RESET_ZOOM ,
@@ -124,6 +140,55 @@ describe('useCanvas wheel pan sync', () => {
124140 expect ( layer . style . transform ) . toContain ( 'scale(1.' )
125141 expect ( layer . style . transform ) . not . toBe ( 'translate(0px, 0px) scale(1)' )
126142 } )
143+
144+ it ( 'pans the canvas with middle-mouse dragging' , async ( ) => {
145+ render ( < TestCanvas /> )
146+
147+ const root = screen . getByTestId ( 'test-canvas-root' )
148+ const layer = screen . getByTestId ( 'test-transform-layer' )
149+
150+ fireEvent . pointerDown ( root , {
151+ pointerId : 1 ,
152+ pointerType : 'mouse' ,
153+ button : 1 ,
154+ buttons : 4 ,
155+ clientX : 100 ,
156+ clientY : 100 ,
157+ } )
158+ fireEvent . pointerMove ( root , {
159+ pointerId : 1 ,
160+ pointerType : 'mouse' ,
161+ button : - 1 ,
162+ buttons : 4 ,
163+ clientX : 130 ,
164+ clientY : 140 ,
165+ } )
166+
167+ await act ( async ( ) => {
168+ await nextAnimationFrame ( )
169+ } )
170+
171+ const translate = parseTranslate ( layer . style . transform )
172+ expect ( translate . x ) . toBeGreaterThan ( 0 )
173+ expect ( translate . y ) . toBeGreaterThan ( 0 )
174+ } )
175+
176+ it ( 'prevents browser defaults when middle-mouse pan starts' , ( ) => {
177+ render ( < TestCanvas /> )
178+
179+ const root = screen . getByTestId ( 'test-canvas-root' )
180+
181+ const pointerDown = dispatchPointer ( root , 'pointerdown' , {
182+ pointerId : 1 ,
183+ pointerType : 'mouse' ,
184+ button : 1 ,
185+ buttons : 4 ,
186+ clientX : 100 ,
187+ clientY : 100 ,
188+ } )
189+
190+ expect ( pointerDown . defaultPrevented ) . toBe ( true )
191+ } )
127192} )
128193
129194describe ( 'canvas mouse pan input policy' , ( ) => {
@@ -144,9 +209,13 @@ describe('canvas mouse pan input policy', () => {
144209 expect ( panDeltaFromWheel ( { shiftKey : false , deltaX : 0 , deltaY : 120 } ) ) . toEqual ( { dx : 0 , dy : - 120 } )
145210 } )
146211
147- it ( 'does not use middle-button dragging as a canvas pan gesture' , ( ) => {
148- expect ( shouldStartCanvasPointerPan ( { button : 1 } , { spaceHeld : false } ) ) . toBe ( false )
149- expect ( shouldStartCanvasPointerPan ( { button : 1 } , { spaceHeld : true } ) ) . toBe ( false )
212+ it ( 'uses middle-button dragging as a canvas pan gesture' , ( ) => {
213+ expect ( shouldStartCanvasPointerPan ( { button : 1 } , { spaceHeld : false } ) ) . toBe ( true )
214+ expect ( shouldStartCanvasPointerPan ( { button : 1 } , { spaceHeld : true } ) ) . toBe ( true )
215+ expect ( shouldStartCanvasPointerPan ( { button : 0 } , { spaceHeld : false } ) ) . toBe ( false )
150216 expect ( shouldStartCanvasPointerPan ( { button : 0 } , { spaceHeld : true } ) ) . toBe ( true )
217+ expect ( isCanvasPointerPanActive ( { buttons : 4 } , { spaceHeld : false } ) ) . toBe ( true )
218+ expect ( isCanvasPointerPanActive ( { buttons : 1 } , { spaceHeld : false } ) ) . toBe ( false )
219+ expect ( isCanvasPointerPanActive ( { buttons : 1 } , { spaceHeld : true } ) ) . toBe ( true )
151220 } )
152221} )
0 commit comments