@@ -174,9 +174,8 @@ class PaintManager {
174174 document . addEventListener ( 'keydown' , this . handleKeyboard ) ;
175175
176176 // Mouse move for brush cursor
177- this . canvas . addEventListener ( 'mousemove' , this . updateBrushCursor ) ;
178177 this . canvas . addEventListener ( 'mouseenter' , this . updateBrushCursor ) ;
179- this . canvas . addEventListener ( 'mouseleave ' , this . hideBrushCursor ) ;
178+ this . canvas . addEventListener ( 'mousemove ' , this . updateBrushCursor ) ;
180179
181180 // Create brush cursor element
182181 this . createBrushCursor ( ) ;
@@ -218,9 +217,6 @@ class PaintManager {
218217
219218 // Cancel any pending text placement
220219 this . cancelTextPlacement ( ) ;
221-
222- // Update brush cursor visibility
223- this . updateBrushCursorVisibility ( ) ;
224220 }
225221
226222 createBrushCursor ( ) {
@@ -259,54 +255,54 @@ class PaintManager {
259255 this . brushCursor . style . height = size + 'px' ;
260256 }
261257
262- updateBrushCursorVisibility ( ) {
263- if ( ! this . brushCursor ) return ;
264-
265- if ( this . currentTool === 'brush' || this . currentTool === 'eraser' ) {
266- this . brushCursor . style . display = 'block' ;
267- this . canvas . style . cursor = 'none' ;
268- } else {
269- this . brushCursor . style . display = 'none' ;
270- this . canvas . style . cursor = 'default' ;
271- }
272- }
273-
274258 updateBrushCursor ( e ) {
275259 if ( ! this . brushCursor ) return ;
276260
277261 if ( this . currentTool === 'brush' || this . currentTool === 'eraser' ) {
278- this . brushCursor . style . display = 'block' ;
279- this . canvas . style . cursor = 'none' ;
280-
281- // Store the pending position
282- this . pendingCursorX = e . clientX ;
283- this . pendingCursorY = e . clientY ;
284-
285- // Schedule update using requestAnimationFrame for smooth movement
286- if ( ! this . cursorUpdateScheduled ) {
287- this . cursorUpdateScheduled = true ;
288- requestAnimationFrame ( ( ) => {
289- this . brushCursor . style . transform = `translate(${ this . pendingCursorX } px, ${ this . pendingCursorY } px) translate(-50%, -50%)` ;
290- this . cursorUpdateScheduled = false ;
291- } ) ;
292- }
262+ // Check if mouse is within canvas bounds
263+ const rect = this . canvas . getBoundingClientRect ( ) ;
264+ const isInCanvas = e . clientX >= rect . left &&
265+ e . clientX <= rect . right &&
266+ e . clientY >= rect . top &&
267+ e . clientY <= rect . bottom ;
268+
269+ if ( isInCanvas ) {
270+ this . brushCursor . style . display = 'block' ;
271+ this . canvas . style . cursor = 'none' ;
272+
273+ // Store the pending position
274+ this . pendingCursorX = e . clientX ;
275+ this . pendingCursorY = e . clientY ;
276+
277+ // Schedule update using requestAnimationFrame for smooth movement
278+ if ( ! this . cursorUpdateScheduled ) {
279+ this . cursorUpdateScheduled = true ;
280+ requestAnimationFrame ( ( ) => {
281+ this . brushCursor . style . transform = `translate(${ this . pendingCursorX } px, ${ this . pendingCursorY } px) translate(-50%, -50%)` ;
282+ this . cursorUpdateScheduled = false ;
283+ } ) ;
284+ }
293285
294- // Update color to match brush or show white for eraser (only needs to happen once or when tool changes)
295- if ( this . currentTool === 'eraser' ) {
296- if ( this . brushCursor . getAttribute ( 'data-tool' ) !== 'eraser' ) {
297- this . brushCursor . style . border = '2px solid rgba(255, 0, 0, 0.7)' ;
298- this . brushCursor . style . backgroundColor = 'rgba(255, 255, 255, 0.2)' ;
299- this . brushCursor . style . boxShadow = 'none' ;
300- this . brushCursor . setAttribute ( 'data-tool' , 'eraser' ) ;
286+ // Update color to match brush or show white for eraser (only needs to happen once or when tool changes)
287+ if ( this . currentTool === 'eraser' ) {
288+ if ( this . brushCursor . getAttribute ( 'data-tool' ) !== 'eraser' ) {
289+ this . brushCursor . style . border = '2px solid rgba(255, 0, 0, 0.7)' ;
290+ this . brushCursor . style . backgroundColor = 'rgba(255, 255, 255, 0.2)' ;
291+ this . brushCursor . style . boxShadow = 'none' ;
292+ this . brushCursor . setAttribute ( 'data-tool' , 'eraser' ) ;
293+ }
294+ } else {
295+ if ( this . brushCursor . getAttribute ( 'data-tool' ) !== 'brush' ) {
296+ // Use a contrasting border - white with black outline for visibility
297+ this . brushCursor . style . border = '1px solid white' ;
298+ this . brushCursor . style . boxShadow = '0 0 0 1px black, inset 0 0 0 1px black' ;
299+ this . brushCursor . style . backgroundColor = 'transparent' ;
300+ this . brushCursor . setAttribute ( 'data-tool' , 'brush' ) ;
301+ }
301302 }
302303 } else {
303- if ( this . brushCursor . getAttribute ( 'data-tool' ) !== 'brush' ) {
304- // Use a contrasting border - white with black outline for visibility
305- this . brushCursor . style . border = '1px solid white' ;
306- this . brushCursor . style . boxShadow = '0 0 0 1px black, inset 0 0 0 1px black' ;
307- this . brushCursor . style . backgroundColor = 'transparent' ;
308- this . brushCursor . setAttribute ( 'data-tool' , 'brush' ) ;
309- }
304+ // Hide cursor when outside canvas
305+ this . brushCursor . style . display = 'none' ;
310306 }
311307 }
312308 }
@@ -353,6 +349,8 @@ class PaintManager {
353349 this . isDraggingText = false ;
354350 this . lastX = 0 ;
355351 this . lastY = 0 ;
352+
353+ this . hideBrushCursor ( ) ;
356354 }
357355
358356 paint ( e ) {
0 commit comments