Files
ComfyUI_frontend/src/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue
Terry Jia f6d39dbfc8 fix: stop pointer/mouse event propagation in vueNodes widget containers (#7953)
## Summary
Prevents custom widget drag interactions from triggering node drag in
vueNodes mode. Custom plugins like KJNodes Points Editor use their own
drag handlers which were bubbling up to the node container.

## Screenshots (if applicable)
before



https://github.com/user-attachments/assets/bc4c3095-d454-45f6-a4ec-60178e8f47df


after


https://github.com/user-attachments/assets/a32a5591-120e-4842-a0e0-3dd972127376

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7953-fix-stop-pointer-mouse-event-propagation-in-vueNodes-widget-containers-2e56d73d3650810398f2c582a91d767b)
by [Unito](https://www.unito.io)
2026-01-11 20:34:22 -05:00

114 lines
3.9 KiB
Vue

<script setup lang="ts">
import { useResizeObserver } from '@vueuse/core'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useChainCallback } from '@/composables/functional/useChainCallback'
import { CanvasPointer } from '@/lib/litegraph/src/CanvasPointer'
import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas'
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { augmentToCanvasPointerEvent } from '@/renderer/extensions/vueNodes/utils/eventUtils'
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
const props = defineProps<{
widget: SimplifiedWidget<void>
}>()
const canvasEl = ref()
const containerHeight = ref(20)
const canvas: LGraphCanvas = useCanvasStore().canvas as LGraphCanvas
let node: LGraphNode | undefined
let widgetInstance: IBaseWidget | undefined
let pointer: CanvasPointer | undefined
const scaleFactor = 2
onMounted(() => {
node =
canvas?.graph?.getNodeById(
canvasEl.value.parentElement.attributes['node-id'].value
) ?? undefined
if (!node) return
widgetInstance = node.widgets?.find((w) => w.name === props.widget.name)
if (!widgetInstance) return
canvasEl.value.width *= scaleFactor
if (!widgetInstance.triggerDraw)
widgetInstance.callback = useChainCallback(
widgetInstance.callback,
function (this: IBaseWidget) {
this?.triggerDraw?.()
}
)
widgetInstance.triggerDraw = draw
useResizeObserver(canvasEl.value.parentElement, draw)
watch(() => useColorPaletteStore().activePaletteId, draw)
pointer = new CanvasPointer(canvasEl.value)
})
onBeforeUnmount(() => {
if (widgetInstance) widgetInstance.triggerDraw = () => {}
})
function draw() {
if (!widgetInstance || !node) return
const width = canvasEl.value.parentElement.clientWidth
// Priority: computedHeight (from litegraph) > computeLayoutSize > computeSize
let height = 20
if (widgetInstance.computedHeight) {
height = widgetInstance.computedHeight
} else if (widgetInstance.computeLayoutSize) {
height = widgetInstance.computeLayoutSize(node).minHeight
} else if (widgetInstance.computeSize) {
height = widgetInstance.computeSize(width)[1]
}
containerHeight.value = height
// Set node.canvasHeight for legacy widgets that use it (e.g., Impact Pack)
// @ts-expect-error canvasHeight is a custom property used by some extensions
node.canvasHeight = height
widgetInstance.y = 0
canvasEl.value.height = (height + 2) * scaleFactor
canvasEl.value.width = width * scaleFactor
const ctx = canvasEl.value?.getContext('2d')
if (!ctx) return
ctx.scale(scaleFactor, scaleFactor)
widgetInstance.draw?.(ctx, node, width, 1, height)
}
//See LGraphCanvas.processWidgetClick
function handleDown(e: PointerEvent) {
if (!node || !widgetInstance || !pointer) return
augmentToCanvasPointerEvent(e, node, canvas)
pointer.down(e)
if (widgetInstance.mouse)
pointer.onDrag = (e) =>
widgetInstance!.mouse?.(e, [e.offsetX, e.offsetY], node!)
//NOTE: a mouseUp event is already registed under pointer.finally
canvas.processWidgetClick(e, node, widgetInstance, pointer)
}
function handleUp(e: PointerEvent) {
if (!pointer || !node) return
augmentToCanvasPointerEvent(e, node, canvas)
e.click_time = e.timeStamp - (pointer?.eDown?.timeStamp ?? 0)
pointer.up(e)
}
function handleMove(e: PointerEvent) {
if (!pointer || !node) return
augmentToCanvasPointerEvent(e, node, canvas)
pointer.move(e)
}
</script>
<template>
<div
class="relative mx-[-12px] min-w-0 basis-0"
:style="{ minHeight: `${containerHeight}px` }"
>
<canvas
ref="canvasEl"
class="absolute w-full cursor-crosshair"
@pointerdown.stop="handleDown"
@pointerup.stop="handleUp"
@pointermove.stop="handleMove"
/>
</div>
</template>