Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
306ae55
Remove type text from slot
benceruleanlu Jul 21, 2025
fe1b61d
Format slots LR
benceruleanlu Jul 21, 2025
b7144ea
Deduplicate slots/widgets
benceruleanlu Jul 21, 2025
a5e2b45
Remove node body padding
benceruleanlu Jul 24, 2025
3748cf4
Add slots
benceruleanlu Jul 24, 2025
d0f70bc
Make node body gap consistent
benceruleanlu Jul 24, 2025
b0c35bc
Add slots UI
benceruleanlu Jul 24, 2025
7190b78
Strict height
benceruleanlu Jul 24, 2025
e72d29c
Add larger hitbox
benceruleanlu Jul 24, 2025
ac8af8b
nit
benceruleanlu Jul 24, 2025
d02d7aa
Update constant name
benceruleanlu Jul 24, 2025
b35a621
Add feature flag sync
benceruleanlu Jul 24, 2025
d8e5a5c
Temp tsc silencer
benceruleanlu Jul 24, 2025
a29f65c
Add event forwarding
benceruleanlu Jul 24, 2025
4d8a1cf
Hide "No Widgets" text
benceruleanlu Jul 25, 2025
a94a1fc
pr-1.5 to widgets
benceruleanlu Jul 25, 2025
4ee0a39
Fix slot visibility on widgets
benceruleanlu Jul 25, 2025
f959de7
nit
benceruleanlu Jul 25, 2025
8541800
Rename to vueNodesMode
benceruleanlu Jul 25, 2025
a099d9b
Disable DOM widgets in vue nodes mode
benceruleanlu Jul 25, 2025
9ebc97a
Merge to feature flag
benceruleanlu Jul 25, 2025
f2260d3
Add node header boilerplate test
benceruleanlu Jul 25, 2025
bf89129
feat: Add escape key support to EditableText component
benceruleanlu Jul 25, 2025
94f4479
Add test fixtures
benceruleanlu Jul 26, 2025
e44c6ae
Add data-testid to vue node header
benceruleanlu Jul 26, 2025
38292bb
Add vue node header tests
benceruleanlu Jul 26, 2025
692c77d
Fix handles node collapsing test
benceruleanlu Jul 26, 2025
b3d8182
Fix MARKDOWN => TEXTAREA test
benceruleanlu Jul 28, 2025
cd84802
Comment out misleading test expectation
benceruleanlu Jul 28, 2025
432bc4e
Squashed 'src/lib/litegraph/' content from commit f0f8e9e66
benceruleanlu Jul 28, 2025
14571ba
Merge commit '432bc4eea4ac3daaff0fda20b8ce875324b90f41' as 'src/lib/l…
benceruleanlu Jul 28, 2025
b732ed7
Add TypeScript path mapping for local litegraph subtree
benceruleanlu Jul 28, 2025
12c10cc
Remove @comfyorg/litegraph npm dependency
benceruleanlu Jul 28, 2025
86e7a14
Exclude litegraph from ESLint
benceruleanlu Jul 28, 2025
38acfbe
Remove litegraph-specific config files
benceruleanlu Jul 28, 2025
dc80e48
Configure litegraph as TypeScript composite project
benceruleanlu Jul 29, 2025
ba8f186
Revert "Add TypeScript path mapping for local litegraph subtree"
benceruleanlu Jul 29, 2025
44d80e0
Fix TypeScript errors in Rectangle.ts
benceruleanlu Jul 29, 2025
d6025b5
Fix imports
benceruleanlu Jul 29, 2025
11174de
Remove unused eslint
benceruleanlu Jul 29, 2025
cb5e8de
Remove duplicated/unused packages
benceruleanlu Jul 29, 2025
1e307e8
Fix pre-commit hook to use vue-tsc --build
benceruleanlu Jul 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add event forwarding
  • Loading branch information
benceruleanlu committed Jul 24, 2025
commit a29f65c0be03c5d781d8663ef9f85fc28808e9f8
25 changes: 16 additions & 9 deletions src/components/graph/vueNodes/NodeSlots.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@

<script setup lang="ts">
import type { INodeSlot, LGraphNode } from '@comfyorg/litegraph'
import { computed, onErrorCaptured, ref } from 'vue'
import { computed, onErrorCaptured, onUnmounted, ref } from 'vue'

import { useEventForwarding } from '@/composables/graph/useEventForwarding'
import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
import type { LODLevel } from '@/composables/graph/useLOD'
import { useErrorHandling } from '@/composables/useErrorHandling'
Expand Down Expand Up @@ -103,20 +104,26 @@ const getActualInputIndex = (
return actualIndex !== -1 ? actualIndex : filteredIndex
}

// Set up event forwarding for slot interactions
const { handleSlotPointerDown, cleanup } = useEventForwarding()

// Handle input slot click
const handleInputSlotClick = (index: number, event: PointerEvent) => {
// TODO: Click handling will be implemented by passing events through to LiteGraph
// LiteGraph will have slots rendered in the same location and will handle the connection logic
console.log('Input slot clicked:', index, event)
const handleInputSlotClick = (_index: number, event: PointerEvent) => {
// Forward the event to LiteGraph for native slot handling
handleSlotPointerDown(event)
}

// Handle output slot click
const handleOutputSlotClick = (index: number, event: PointerEvent) => {
// TODO: Click handling will be implemented by passing events through to LiteGraph
// LiteGraph will have slots rendered in the same location and will handle the connection logic
console.log('Output slot clicked:', index, event)
const handleOutputSlotClick = (_index: number, event: PointerEvent) => {
// Forward the event to LiteGraph for native slot handling
handleSlotPointerDown(event)
}

// Clean up event listeners on unmount
onUnmounted(() => {
cleanup()
})

// Error boundary implementation
const renderError = ref<string | null>(null)
const { toastErrorHandler } = useErrorHandling()
Expand Down
21 changes: 20 additions & 1 deletion src/components/graph/vueNodes/NodeWidgets.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
:index="index"
:readonly="readonly"
:dot-only="true"
@slot-click="handleWidgetSlotClick($event, widget)"
/>
</div>
<!-- Widget Component -->
Expand All @@ -36,11 +37,12 @@

<script setup lang="ts">
import type { LGraphNode } from '@comfyorg/litegraph'
import { computed, onErrorCaptured, ref } from 'vue'
import { computed, onErrorCaptured, onUnmounted, ref } from 'vue'

// Import widget components directly
import WidgetInputText from '@/components/graph/vueWidgets/WidgetInputText.vue'
import { widgetTypeToComponent } from '@/components/graph/vueWidgets/widgetRegistry'
import { useEventForwarding } from '@/composables/graph/useEventForwarding'
import type {
SafeWidgetData,
VueNodeData
Expand All @@ -64,6 +66,9 @@ interface NodeWidgetsProps {

const props = defineProps<NodeWidgetsProps>()

// Set up event forwarding for slot interactions
const { handleSlotPointerDown, cleanup } = useEventForwarding()

// Use widget renderer composable
const { getWidgetComponent, shouldRenderAsVue } = useWidgetRenderer()

Expand Down Expand Up @@ -142,4 +147,18 @@ const processedWidgets = computed((): ProcessedWidget[] => {

return result
})

// Handle widget slot click
const handleWidgetSlotClick = (
event: PointerEvent,
_widget: ProcessedWidget
) => {
// Forward the event to LiteGraph for native slot handling
handleSlotPointerDown(event)
}

// Clean up event listeners on unmount
onUnmounted(() => {
cleanup()
})
</script>
186 changes: 186 additions & 0 deletions src/composables/graph/useEventForwarding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import type { LGraphCanvas } from '@comfyorg/litegraph'

import { useCanvasStore } from '@/stores/graphStore'

export function useEventForwarding() {
const canvasStore = useCanvasStore()

// Track active drag operation
let isDragging = false
let dragCleanup: (() => void) | null = null
// Store last known position for escape key handling
const lastPointerPosition = { x: 0, y: 0 }

function createSyntheticPointerEvent(
originalEvent: PointerEvent,
eventType: string
): PointerEvent {
// Only copy properties that LiteGraph actually uses
return new PointerEvent(eventType, {
bubbles: true,
cancelable: true,
view: window,
// Position properties
clientX: originalEvent.clientX,
clientY: originalEvent.clientY,
// Modifier keys
ctrlKey: originalEvent.ctrlKey,
shiftKey: originalEvent.shiftKey,
altKey: originalEvent.altKey,
metaKey: originalEvent.metaKey,
// Button state
button: originalEvent.button,
buttons: originalEvent.buttons,
// Pointer tracking
pointerId: originalEvent.pointerId,
isPrimary: originalEvent.isPrimary,
pointerType: originalEvent.pointerType
})
}

function forwardPointerEvent(
originalEvent: PointerEvent,
eventType: 'down' | 'move' | 'up'
) {
const canvas: LGraphCanvas | null = canvasStore.getCanvas()
if (!canvas) {
console.warn('No canvas available for event forwarding')
return
}

// Prevent original event from bubbling to canvas
originalEvent.stopPropagation()
originalEvent.preventDefault()

// Create synthetic event
const syntheticEvent = createSyntheticPointerEvent(
originalEvent,
`pointer${eventType}`
)

// Create a mutable copy of the event for LiteGraph to modify
const mutableEvent = syntheticEvent as PointerEvent & {
canvasX?: number
canvasY?: number
deltaX?: number
deltaY?: number
safeOffsetX?: number
safeOffsetY?: number
}

// Let LiteGraph adjust coordinates to graph space
// Using 'as any' to bypass TypeScript assertion limitations
;(canvas.adjustMouseEvent as any)(mutableEvent)

// Forward to appropriate handler
switch (eventType) {
case 'down':
canvas.processMouseDown(mutableEvent)
break
case 'move':
canvas.processMouseMove(mutableEvent)
break
case 'up':
canvas.processMouseUp(mutableEvent)
break
}
}

// Pre-create event handlers to avoid recreating on each pointerdown
const handlePointerMove = (e: PointerEvent) => {
if (!isDragging) return
// Update last known position
lastPointerPosition.x = e.clientX
lastPointerPosition.y = e.clientY
forwardPointerEvent(e, 'move')
}

const handlePointerUp = (e: PointerEvent) => {
if (!isDragging) return

isDragging = false
forwardPointerEvent(e, 'up')

// Clean up listeners
if (dragCleanup) {
dragCleanup()
dragCleanup = null
}
}

const handleKeyDown = (e: KeyboardEvent) => {
// Handle escape key to cancel drag
if (e.key === 'Escape' && isDragging) {
isDragging = false

// Create minimal synthetic cancel event
const cancelEvent = new PointerEvent('pointerup', {
bubbles: true,
cancelable: true,
view: window,
// Use last known position from the current drag operation
clientX: lastPointerPosition.x,
clientY: lastPointerPosition.y,
button: 0,
buttons: 0
})

const canvas: LGraphCanvas | null = canvasStore.getCanvas()
if (canvas) {
const mutableCancelEvent = cancelEvent as PointerEvent & {
canvasX?: number
canvasY?: number
deltaX?: number
deltaY?: number
safeOffsetX?: number
safeOffsetY?: number
}
;(canvas.adjustMouseEvent as any)(mutableCancelEvent)
canvas.processMouseUp(mutableCancelEvent)
}

// Clean up
if (dragCleanup) {
dragCleanup()
dragCleanup = null
}
}
}

function handleSlotPointerDown(originalEvent: PointerEvent) {
// Forward the initial pointer down
forwardPointerEvent(originalEvent, 'down')

// Set up drag handling
isDragging = true
// Initialize last known position
lastPointerPosition.x = originalEvent.clientX
lastPointerPosition.y = originalEvent.clientY

// Add global listeners for drag handling
document.addEventListener('pointermove', handlePointerMove, true)
document.addEventListener('pointerup', handlePointerUp, true)
document.addEventListener('keydown', handleKeyDown, true)

// Store cleanup function
dragCleanup = () => {
document.removeEventListener('pointermove', handlePointerMove, true)
document.removeEventListener('pointerup', handlePointerUp, true)
document.removeEventListener('keydown', handleKeyDown, true)
}
}

// Cleanup on unmount
function cleanup() {
isDragging = false
if (dragCleanup) {
dragCleanup()
dragCleanup = null
}
}

return {
handleSlotPointerDown,
cleanup
}
}