diff --git a/packages/design-system/src/css/style.css b/packages/design-system/src/css/style.css index 1efc86194..1153d4543 100644 --- a/packages/design-system/src/css/style.css +++ b/packages/design-system/src/css/style.css @@ -1328,6 +1328,15 @@ audio.comfy-audio.empty-audio-widget { font-size 0.1s ease; } +/* Performance optimization during canvas interaction */ +.transform-pane--interacting .lg-node * { + transition: none !important; +} + +.transform-pane--interacting .lg-node { + will-change: transform; +} + /* ===================== Mask Editor Styles ===================== */ /* To be migrated to Tailwind later */ #maskEditor_brush { diff --git a/src/renderer/core/layout/__tests__/TransformPane.test.ts b/src/renderer/core/layout/__tests__/TransformPane.test.ts index 4876115b9..64952a629 100644 --- a/src/renderer/core/layout/__tests__/TransformPane.test.ts +++ b/src/renderer/core/layout/__tests__/TransformPane.test.ts @@ -117,6 +117,73 @@ describe('TransformPane', () => { }) }) + describe('canvas event listeners', () => { + it('should add event listeners to canvas on mount', async () => { + const mockCanvas = createMockCanvas() + mount(TransformPane, { + props: { + canvas: mockCanvas + } + }) + + await nextTick() + + expect(mockCanvas.canvas.addEventListener).toHaveBeenCalledWith( + 'wheel', + expect.any(Function), + expect.any(Object) + ) + expect(mockCanvas.canvas.addEventListener).not.toHaveBeenCalledWith( + 'pointerdown', + expect.any(Function), + expect.any(Object) + ) + expect(mockCanvas.canvas.addEventListener).not.toHaveBeenCalledWith( + 'pointerup', + expect.any(Function), + expect.any(Object) + ) + expect(mockCanvas.canvas.addEventListener).not.toHaveBeenCalledWith( + 'pointercancel', + expect.any(Function), + expect.any(Object) + ) + }) + + it('should remove event listeners on unmount', async () => { + const mockCanvas = createMockCanvas() + const wrapper = mount(TransformPane, { + props: { + canvas: mockCanvas + } + }) + + await nextTick() + wrapper.unmount() + + expect(mockCanvas.canvas.removeEventListener).toHaveBeenCalledWith( + 'wheel', + expect.any(Function), + expect.any(Object) + ) + expect(mockCanvas.canvas.removeEventListener).not.toHaveBeenCalledWith( + 'pointerdown', + expect.any(Function), + expect.any(Object) + ) + expect(mockCanvas.canvas.removeEventListener).not.toHaveBeenCalledWith( + 'pointerup', + expect.any(Function), + expect.any(Object) + ) + expect(mockCanvas.canvas.removeEventListener).not.toHaveBeenCalledWith( + 'pointercancel', + expect.any(Function), + expect.any(Object) + ) + }) + }) + describe('interaction state management', () => { it('should apply interacting class during interactions', async () => { const mockCanvas = createMockCanvas() @@ -131,7 +198,9 @@ describe('TransformPane', () => { const transformPane = wrapper.find('[data-testid="transform-pane"]') // Initially should not have interacting class - expect(transformPane.classes()).not.toContain('will-change-transform') + expect(transformPane.classes()).not.toContain( + 'transform-pane--interacting' + ) }) it('should handle pointer events for node delegation', async () => { diff --git a/src/renderer/core/layout/transform/TransformPane.vue b/src/renderer/core/layout/transform/TransformPane.vue index b39f67140..cf542bb89 100644 --- a/src/renderer/core/layout/transform/TransformPane.vue +++ b/src/renderer/core/layout/transform/TransformPane.vue @@ -1,7 +1,12 @@