fix(vueNodes): sync node size changes from extensions to Vue components (#7993)

## Summary
When extensions like KJNodes call node.setSize(), the Vue component now
properly updates its CSS variables to reflect the new size.

## Changes:
- LGraphNode pos/size setters now always sync to layoutStore with Canvas
source
- LGraphNode.vue listens to layoutStore changes and updates CSS
variables
- Fixed height calculation to account for NODE_TITLE_HEIGHT difference
- Removed _syncToLayoutStore flag (simplified - layoutStore ignores
non-existent nodes)
- Use setPos() helper method instead of direct pos[0]/pos[1] assignment

## Screenshots (if applicable)
before

https://github.com/user-attachments/assets/236a173a-e41d-485b-8c63-5c28ef1c69bf


after

https://github.com/user-attachments/assets/5fc3f7e4-35c7-40e1-81ac-38a35ee0ac1b

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7993-fix-vueNodes-sync-node-size-changes-from-extensions-to-Vue-components-2e76d73d3650815799c5f2d9d8c7dcbf)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Terry Jia
2026-02-12 05:38:18 -05:00
committed by GitHub
parent c0c81dba49
commit 6cf0357b3e
6 changed files with 104 additions and 74 deletions

View File

@@ -199,6 +199,7 @@ import {
nextTick,
onErrorCaptured,
onMounted,
onUnmounted,
ref,
watch
} from 'vue'
@@ -223,6 +224,7 @@ import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
import NodeBadges from '@/renderer/extensions/vueNodes/components/NodeBadges.vue'
import { LayoutSource } from '@/renderer/core/layout/types'
import SlotConnectionDot from '@/renderer/extensions/vueNodes/components/SlotConnectionDot.vue'
import { useNodeEventHandlers } from '@/renderer/extensions/vueNodes/composables/useNodeEventHandlers'
import { useNodePointerInteractions } from '@/renderer/extensions/vueNodes/composables/useNodePointerInteractions'
@@ -362,15 +364,8 @@ const handleContextMenu = (event: MouseEvent) => {
showNodeOptions(event)
}
onMounted(() => {
initSizeStyles()
})
/**
* Set initial DOM size from layout store, but respect intrinsic content minimum.
* Important: nodes can mount in a collapsed state, and the collapse watcher won't
* run initially. Match the collapsed runtime behavior by writing to the correct
* CSS variables on mount.
* Set initial DOM size from layout store.
*/
function initSizeStyles() {
const el = nodeContainerRef.value
@@ -378,14 +373,51 @@ function initSizeStyles() {
if (!el) return
const suffix = isCollapsed.value ? '-x' : ''
const fullHeight = height + LiteGraph.NODE_TITLE_HEIGHT
el.style.setProperty(`--node-width${suffix}`, `${width}px`)
el.style.setProperty(
`--node-height${suffix}`,
`${height + LiteGraph.NODE_TITLE_HEIGHT}px`
)
el.style.setProperty(`--node-height${suffix}`, `${fullHeight}px`)
}
/**
* Handle external size changes (e.g., from extensions calling node.setSize()).
* Updates CSS variables when layoutStore changes from Canvas/External source.
*/
function handleLayoutChange(change: {
source: LayoutSource
nodeIds: string[]
}) {
// Only handle Canvas or External source (extensions calling setSize)
if (
change.source !== LayoutSource.Canvas &&
change.source !== LayoutSource.External
)
return
if (!change.nodeIds.includes(nodeData.id)) return
if (layoutStore.isResizingVueNodes.value) return
if (isCollapsed.value) return
const el = nodeContainerRef.value
if (!el) return
const newSize = size.value
const fullHeight = newSize.height + LiteGraph.NODE_TITLE_HEIGHT
el.style.setProperty('--node-width', `${newSize.width}px`)
el.style.setProperty('--node-height', `${fullHeight}px`)
}
let unsubscribeLayoutChange: (() => void) | null = null
onMounted(() => {
initSizeStyles()
unsubscribeLayoutChange = layoutStore.onChange(handleLayoutChange)
})
onUnmounted(() => {
unsubscribeLayoutChange?.()
})
const baseResizeHandleClasses =
'absolute h-5 w-5 opacity-0 pointer-events-auto focus-visible:outline focus-visible:outline-2 focus-visible:outline-white/40'