[backport core/1.32] Feat: Alt+Drag to clone - Vue Nodes (#6860)

Backport of #6789 to `core/1.32`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6860-backport-core-1-32-Feat-Alt-Drag-to-clone-Vue-Nodes-2b46d73d365081e0ac21c1dc61189a7c)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Comfy Org PR Bot
2025-11-24 05:24:14 +09:00
committed by GitHub
parent 0507d333fe
commit b66a181879
22 changed files with 574 additions and 1568 deletions

View File

@@ -1,6 +1,7 @@
import { beforeEach, describe, expect, it } from 'vitest'
import { useTransformState } from '@/renderer/core/layout/transform/useTransformState'
import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas'
// Create a mock canvas context for transform testing
function createMockCanvasContext() {
@@ -27,10 +28,12 @@ function createMockCanvasContext() {
}
describe('useTransformState', () => {
let transformState: ReturnType<typeof useTransformState>
const transformState = useTransformState()
beforeEach(() => {
transformState = useTransformState()
transformState.syncWithCanvas({
ds: { offset: [0, 0] }
} as unknown as LGraphCanvas)
})
describe('initial state', () => {
@@ -179,8 +182,8 @@ describe('useTransformState', () => {
it('should calculate correct screen bounds for a node', () => {
const { getNodeScreenBounds } = transformState
const nodePos = [10, 20]
const nodeSize = [200, 100]
const nodePos: [number, number] = [10, 20]
const nodeSize: [number, number] = [200, 100]
const bounds = getNodeScreenBounds(nodePos, nodeSize)
// Top-left: canvasToScreen(10, 20) = (220, 140)
@@ -206,8 +209,8 @@ describe('useTransformState', () => {
it('should return true for nodes inside viewport', () => {
const { isNodeInViewport } = transformState
const nodePos = [100, 100]
const nodeSize = [200, 100]
const nodePos: [number, number] = [100, 100]
const nodeSize: [number, number] = [200, 100]
expect(isNodeInViewport(nodePos, nodeSize, viewport)).toBe(true)
})
@@ -232,8 +235,8 @@ describe('useTransformState', () => {
const { isNodeInViewport } = transformState
// Node slightly outside but within margin
const nodePos = [-50, -50]
const nodeSize = [100, 100]
const nodePos: [number, number] = [-50, -50]
const nodeSize: [number, number] = [100, 100]
expect(isNodeInViewport(nodePos, nodeSize, viewport, 0.2)).toBe(true)
})
@@ -242,8 +245,8 @@ describe('useTransformState', () => {
const { isNodeInViewport } = transformState
// Node is in viewport but too small
const nodePos = [100, 100]
const nodeSize = [3, 3] // Less than 4 pixels
const nodePos: [number, number] = [100, 100]
const nodeSize: [number, number] = [3, 3] // Less than 4 pixels
expect(isNodeInViewport(nodePos, nodeSize, viewport)).toBe(false)
})