diff --git a/browser_tests/fixtures/ComfyPage.ts b/browser_tests/fixtures/ComfyPage.ts index 376cf3239..bf1a219e6 100644 --- a/browser_tests/fixtures/ComfyPage.ts +++ b/browser_tests/fixtures/ComfyPage.ts @@ -557,7 +557,7 @@ export class ComfyPage { async dragAndDrop(source: Position, target: Position) { await this.page.mouse.move(source.x, source.y) await this.page.mouse.down() - await this.page.mouse.move(target.x, target.y) + await this.page.mouse.move(target.x, target.y, { steps: 100 }) await this.page.mouse.up() await this.nextFrame() } diff --git a/browser_tests/tests/interaction.spec.ts-snapshots/dragged-node1-chromium-linux.png b/browser_tests/tests/interaction.spec.ts-snapshots/dragged-node1-chromium-linux.png index a3d7a8443..d59e9707a 100644 Binary files a/browser_tests/tests/interaction.spec.ts-snapshots/dragged-node1-chromium-linux.png and b/browser_tests/tests/interaction.spec.ts-snapshots/dragged-node1-chromium-linux.png differ diff --git a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-moved-chromium-linux.png b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-moved-chromium-linux.png index 700e9d2c5..7b75a5a3e 100644 Binary files a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-moved-chromium-linux.png and b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-moved-chromium-linux.png differ diff --git a/src/composables/graph/useGraphNodeManager.ts b/src/composables/graph/useGraphNodeManager.ts index 815d987cd..23edf6ea6 100644 --- a/src/composables/graph/useGraphNodeManager.ts +++ b/src/composables/graph/useGraphNodeManager.ts @@ -13,6 +13,7 @@ import type { import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets' import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMutations' import { LayoutSource } from '@/renderer/core/layout/types' +import type { NodeId } from '@/renderer/core/layout/types' import type { InputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2' import { isDOMWidget } from '@/scripts/domWidget' import { useNodeDefStore } from '@/stores/nodeDefStore' @@ -46,7 +47,7 @@ export interface SafeWidgetData { } export interface VueNodeData { - id: string + id: NodeId title: string type: string mode: number diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 70359197e..fb21e72b5 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -1771,18 +1771,19 @@ export class LGraphCanvas } static onMenuNodeClone( - // @ts-expect-error - unused parameter - value: IContextMenuValue, - // @ts-expect-error - unused parameter - options: IContextMenuOptions, - // @ts-expect-error - unused parameter - e: MouseEvent, - // @ts-expect-error - unused parameter - menu: ContextMenu, + _value: IContextMenuValue, + _options: IContextMenuOptions, + _e: MouseEvent, + _menu: ContextMenu, node: LGraphNode ): void { const canvas = LGraphCanvas.active_canvas - const nodes = canvas.selectedItems.size ? canvas.selectedItems : [node] + const nodes = canvas.selectedItems.size ? [...canvas.selectedItems] : [node] + if (nodes.length) LGraphCanvas.cloneNodes(nodes) + } + + static cloneNodes(nodes: Positionable[]) { + const canvas = LGraphCanvas.active_canvas // Find top-left-most boundary let offsetX = Infinity @@ -1792,11 +1793,11 @@ export class LGraphCanvas throw new TypeError( 'Invalid node encountered on clone. `pos` was null.' ) - if (item.pos[0] < offsetX) offsetX = item.pos[0] - if (item.pos[1] < offsetY) offsetY = item.pos[1] + offsetX = Math.min(offsetX, item.pos[0]) + offsetY = Math.min(offsetY, item.pos[1]) } - canvas._deserializeItems(canvas._serializeItems(nodes), { + return canvas._deserializeItems(canvas._serializeItems(nodes), { position: [offsetX + 5, offsetY + 5] }) } diff --git a/src/renderer/core/layout/injectionKeys.ts b/src/renderer/core/layout/injectionKeys.ts deleted file mode 100644 index 8970e55f8..000000000 --- a/src/renderer/core/layout/injectionKeys.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { InjectionKey } from 'vue' - -import type { useTransformState } from '@/renderer/core/layout/transform/useTransformState' - -/** - * Lightweight, injectable transform state used by layout-aware components. - * - * Consumers use this interface to convert coordinates between LiteGraph's - * canvas space and the DOM's screen space, access the current pan/zoom - * (camera), and perform basic viewport culling checks. - * - * Coordinate mapping: - * - screen = (canvas + offset) * scale - * - canvas = screen / scale - offset - * - * The full implementation and additional helpers live in - * `useTransformState()`. This interface deliberately exposes only the - * minimal surface needed outside that composable. - * - * @example - * const state = inject(TransformStateKey)! - * const screen = state.canvasToScreen({ x: 100, y: 50 }) - */ -export interface TransformState - extends Pick< - ReturnType, - 'screenToCanvas' | 'canvasToScreen' | 'camera' | 'isNodeInViewport' - > {} - -export const TransformStateKey: InjectionKey = - Symbol('transformState') diff --git a/src/renderer/core/layout/transform/TransformPane.vue b/src/renderer/core/layout/transform/TransformPane.vue index 9675248a7..e1287e599 100644 --- a/src/renderer/core/layout/transform/TransformPane.vue +++ b/src/renderer/core/layout/transform/TransformPane.vue @@ -17,10 +17,9 @@