33import { useEditorEngine } from '@/components/store/editor' ;
44import { EditorAttributes } from '@onlook/constants' ;
55import { EditorMode } from '@onlook/models' ;
6+ import { throttle } from 'lodash' ;
67import { observer } from 'mobx-react-lite' ;
78import { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
89import { Frames } from './frames' ;
@@ -35,7 +36,7 @@ export const Canvas = observer(() => {
3536 return ;
3637 }
3738
38- // Start drag selection only in design mode and when not holding middle mouse button
39+ // Start drag selection only in design mode and left mouse button
3940 if ( editorEngine . state . editorMode === EditorMode . DESIGN && event . button === 0 ) {
4041 const rect = containerRef . current . getBoundingClientRect ( ) ;
4142 const x = event . clientX - rect . left ;
@@ -50,21 +51,25 @@ export const Canvas = observer(() => {
5051 editorEngine . clearUI ( ) ;
5152 editorEngine . frames . deselectAll ( ) ;
5253 }
53- } else {
54+ } else if ( event . button === 0 ) {
55+ // Only clear UI for left clicks that don't start drag selection
5456 editorEngine . clearUI ( ) ;
5557 }
5658 } ;
5759
58- const handleCanvasMouseMove = ( event : React . MouseEvent < HTMLDivElement > ) => {
59- if ( ! isDragSelecting || ! containerRef . current ) {
60- return ;
61- }
62-
63- const rect = containerRef . current . getBoundingClientRect ( ) ;
64- const x = event . clientX - rect . left ;
65- const y = event . clientY - rect . top ;
66- setDragSelectEnd ( { x, y } ) ;
67- } ;
60+ const handleCanvasMouseMove = useCallback (
61+ throttle ( ( event : React . MouseEvent < HTMLDivElement > ) => {
62+ if ( ! isDragSelecting || ! containerRef . current ) {
63+ return ;
64+ }
65+
66+ const rect = containerRef . current . getBoundingClientRect ( ) ;
67+ const x = event . clientX - rect . left ;
68+ const y = event . clientY - rect . top ;
69+ setDragSelectEnd ( { x, y } ) ;
70+ } , 16 ) , // ~60fps
71+ [ isDragSelecting ]
72+ ) ;
6873
6974 const handleCanvasMouseUp = ( event : React . MouseEvent < HTMLDivElement > ) => {
7075 if ( ! isDragSelecting ) {
@@ -239,9 +244,10 @@ export const Canvas = observer(() => {
239244 div . removeEventListener ( 'wheel' , handleWheel ) ;
240245 div . removeEventListener ( 'mousedown' , middleMouseButtonDown ) ;
241246 div . removeEventListener ( 'mouseup' , middleMouseButtonUp ) ;
247+ handleCanvasMouseMove . cancel ?.( ) ; // Clean up throttled function
242248 } ;
243249 }
244- } , [ handleWheel , middleMouseButtonDown , middleMouseButtonUp ] ) ;
250+ } , [ handleWheel , middleMouseButtonDown , middleMouseButtonUp , handleCanvasMouseMove ] ) ;
245251
246252 return (
247253 < HotkeysArea >
@@ -251,7 +257,12 @@ export const Canvas = observer(() => {
251257 onMouseDown = { handleCanvasMouseDown }
252258 onMouseMove = { handleCanvasMouseMove }
253259 onMouseUp = { handleCanvasMouseUp }
254- onMouseLeave = { handleCanvasMouseUp }
260+ onMouseLeave = { ( e ) => {
261+ // Only terminate drag if no mouse button is pressed
262+ if ( e . buttons === 0 ) {
263+ handleCanvasMouseUp ( e ) ;
264+ }
265+ } }
255266 >
256267 < div id = { EditorAttributes . CANVAS_CONTAINER_ID } style = { transformStyle } >
257268 < Frames />
0 commit comments