diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 6586ce18629..a050898501e 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -12,6 +12,7 @@ import { forEachNode } from '@/utils/graphTraversalUtil' import { CanvasPointer } from './CanvasPointer' import type { ContextMenu } from './ContextMenu' +import { createCursorCache } from './cursorCache' import { DragAndScale } from './DragAndScale' import type { AnimationOptions } from './DragAndScale' import type { LGraph } from './LGraph' @@ -364,6 +365,8 @@ export class LGraphCanvas implements CustomEventDispatcher this.canvas.dispatchEvent(new CustomEvent(type, { detail })) } + private _setCursor!: ReturnType + private _updateCursorStyle() { if (!this.state.shouldSetCursor) return @@ -386,7 +389,7 @@ export class LGraphCanvas implements CustomEventDispatcher cursor = 'grab' } - this.canvas.style.cursor = cursor + this._setCursor(cursor) } // Whether the canvas was previously being dragged prior to pressing space key. @@ -1911,6 +1914,7 @@ export class LGraphCanvas implements CustomEventDispatcher this.pointer.element = element if (!element) return + this._setCursor = createCursorCache(element) // TODO: classList.add element.className += ' lgraphcanvas' @@ -2970,7 +2974,7 @@ export class LGraphCanvas implements CustomEventDispatcher } // Set appropriate cursor for resize direction - this.canvas.style.cursor = cursors[resizeDirection] + this._setCursor(cursors[resizeDirection]) return } } diff --git a/src/lib/litegraph/src/cursorCache.test.ts b/src/lib/litegraph/src/cursorCache.test.ts new file mode 100644 index 00000000000..c73f97c6036 --- /dev/null +++ b/src/lib/litegraph/src/cursorCache.test.ts @@ -0,0 +1,59 @@ +import { describe, expect, it, vi } from 'vitest' + +import { createCursorCache } from './cursorCache' + +function createMockElement() { + let cursorValue = '' + const setter = vi.fn((value: string) => { + cursorValue = value + }) + + const element = document.createElement('div') + Object.defineProperty(element.style, 'cursor', { + get: () => cursorValue, + set: setter + }) + + return { element, setter } +} + +describe('createCursorCache', () => { + it('should only write to DOM when cursor value changes', () => { + const { element, setter } = createMockElement() + const setCursor = createCursorCache(element) + + setCursor('crosshair') + setCursor('crosshair') + setCursor('crosshair') + + expect(setter).toHaveBeenCalledTimes(1) + expect(setter).toHaveBeenCalledWith('crosshair') + }) + + it('should write to DOM when cursor value differs', () => { + const { element, setter } = createMockElement() + const setCursor = createCursorCache(element) + + setCursor('default') + setCursor('crosshair') + setCursor('grabbing') + + expect(setter).toHaveBeenCalledTimes(3) + expect(setter).toHaveBeenNthCalledWith(1, 'default') + expect(setter).toHaveBeenNthCalledWith(2, 'crosshair') + expect(setter).toHaveBeenNthCalledWith(3, 'grabbing') + }) + + it('should skip repeated values interspersed with changes', () => { + const { element, setter } = createMockElement() + const setCursor = createCursorCache(element) + + setCursor('default') + setCursor('default') + setCursor('grab') + setCursor('grab') + setCursor('default') + + expect(setter).toHaveBeenCalledTimes(3) + }) +}) diff --git a/src/lib/litegraph/src/cursorCache.ts b/src/lib/litegraph/src/cursorCache.ts new file mode 100644 index 00000000000..36bc4ecfde9 --- /dev/null +++ b/src/lib/litegraph/src/cursorCache.ts @@ -0,0 +1,8 @@ +export function createCursorCache(element: HTMLElement) { + let lastCursor = '' + return function setCursor(cursor: string) { + if (cursor === lastCursor) return + lastCursor = cursor + element.style.cursor = cursor + } +}