mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
fix: space bar panning over Vue nodes in standard nav mode
Bridge LGraphCanvas.read_only to Vue reactivity via onReadOnlyChanged callback so the existing CSS pointer-events-auto/none toggle on LGraphNode.vue and NodeWidgets.vue re-evaluates when space key toggles panning mode. Events then fall through to the LiteGraph canvas naturally — no per-handler forwarding or force flags needed. Fixes #7806 Amp-Thread-ID: https://ampcode.com/threads/T-019c796c-e83c-769d-85f4-20a349994bad
This commit is contained in:
@@ -401,8 +401,11 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
|
||||
set read_only(value: boolean) {
|
||||
this.state.readOnly = value
|
||||
this._updateCursorStyle()
|
||||
this.onReadOnlyChanged?.(value)
|
||||
}
|
||||
|
||||
onReadOnlyChanged?: (readOnly: boolean) => void
|
||||
|
||||
get isDragging(): boolean {
|
||||
return this.state.draggingItems
|
||||
}
|
||||
|
||||
81
src/renderer/core/canvas/canvasStore.test.ts
Normal file
81
src/renderer/core/canvas/canvasStore.test.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
import type { LGraphCanvas } from '@/lib/litegraph/src/litegraph'
|
||||
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||
|
||||
vi.mock('@/scripts/app', () => ({
|
||||
app: { canvas: null }
|
||||
}))
|
||||
|
||||
vi.mock('@vueuse/core', async (importOriginal) => {
|
||||
const actual = await importOriginal()
|
||||
return {
|
||||
...(actual as Record<string, unknown>),
|
||||
useEventListener: vi.fn()
|
||||
}
|
||||
})
|
||||
|
||||
function createMockCanvas(
|
||||
readOnly = false
|
||||
): LGraphCanvas & { onReadOnlyChanged?: (v: boolean) => void } {
|
||||
return {
|
||||
read_only: readOnly,
|
||||
canvas: document.createElement('canvas'),
|
||||
onReadOnlyChanged: undefined
|
||||
} as unknown as LGraphCanvas & {
|
||||
onReadOnlyChanged?: (v: boolean) => void
|
||||
}
|
||||
}
|
||||
|
||||
describe('useCanvasStore', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('isReadOnly', () => {
|
||||
it('syncs initial read_only value when canvas is set', async () => {
|
||||
const store = useCanvasStore()
|
||||
const mockCanvas = createMockCanvas(true)
|
||||
|
||||
store.canvas = mockCanvas as unknown as LGraphCanvas
|
||||
await nextTick()
|
||||
|
||||
expect(store.isReadOnly).toBe(true)
|
||||
})
|
||||
|
||||
it('updates isReadOnly when onReadOnlyChanged callback fires', async () => {
|
||||
const store = useCanvasStore()
|
||||
const mockCanvas = createMockCanvas(false)
|
||||
|
||||
store.canvas = mockCanvas as unknown as LGraphCanvas
|
||||
await nextTick()
|
||||
|
||||
expect(store.isReadOnly).toBe(false)
|
||||
|
||||
// Simulate space key press → LGraphCanvas sets read_only = true
|
||||
mockCanvas.onReadOnlyChanged?.(true)
|
||||
|
||||
expect(store.isReadOnly).toBe(true)
|
||||
|
||||
// Simulate space key release
|
||||
mockCanvas.onReadOnlyChanged?.(false)
|
||||
|
||||
expect(store.isReadOnly).toBe(false)
|
||||
})
|
||||
|
||||
it('registers onReadOnlyChanged callback on the canvas', async () => {
|
||||
const store = useCanvasStore()
|
||||
const mockCanvas = createMockCanvas(false)
|
||||
|
||||
store.canvas = mockCanvas as unknown as LGraphCanvas
|
||||
await nextTick()
|
||||
|
||||
expect(mockCanvas.onReadOnlyChanged).toBeDefined()
|
||||
expect(typeof mockCanvas.onReadOnlyChanged).toBe('function')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -41,6 +41,7 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||
const appScalePercentage = ref(100)
|
||||
|
||||
const linearMode = ref(false)
|
||||
const isReadOnly = ref(false)
|
||||
|
||||
// Set up scale synchronization when canvas is available
|
||||
let originalOnChanged: ((scale: number, offset: Point) => void) | undefined =
|
||||
@@ -115,6 +116,11 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||
whenever(
|
||||
() => canvas.value,
|
||||
(newCanvas) => {
|
||||
isReadOnly.value = newCanvas.read_only
|
||||
newCanvas.onReadOnlyChanged = (value: boolean) => {
|
||||
isReadOnly.value = value
|
||||
}
|
||||
|
||||
useEventListener(
|
||||
newCanvas.canvas,
|
||||
'litegraph:set-graph',
|
||||
@@ -141,6 +147,7 @@ export const useCanvasStore = defineStore('canvas', () => {
|
||||
rerouteSelected,
|
||||
appScalePercentage,
|
||||
linearMode,
|
||||
isReadOnly,
|
||||
updateSelectedItems,
|
||||
getCanvas,
|
||||
setAppZoomFromPercentage,
|
||||
|
||||
@@ -12,7 +12,8 @@ vi.mock('@/renderer/core/canvas/canvasStore', () => {
|
||||
return {
|
||||
useCanvasStore: vi.fn(() => ({
|
||||
getCanvas,
|
||||
setCursorStyle
|
||||
setCursorStyle,
|
||||
isReadOnly: false
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -23,7 +23,7 @@ export function useCanvasInteractions() {
|
||||
* Returns false when canvas is in read-only/panning mode (e.g., space key held for panning).
|
||||
*/
|
||||
const shouldHandleNodePointerEvents = computed(
|
||||
() => !(canvasStore.canvas?.read_only ?? false)
|
||||
() => !canvasStore.isReadOnly
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user