Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
eca48a8
[docs] Add Vue node system architecture and implementation plans
christian-byrne Jun 25, 2025
0ec98e3
[feat] Add slot type color definitions
christian-byrne Jun 25, 2025
a041f40
[feat] Implement Vue-based node rendering components
christian-byrne Jun 25, 2025
065e292
[feat] Add TransformPane for Vue node coordinate synchronization
christian-byrne Jun 30, 2025
992d79b
[feat] Vue node lifecycle management implementation
christian-byrne Jul 2, 2025
3dc7686
[feat] Add widget renderer composable
christian-byrne Jul 2, 2025
95c291d
[fix] Fix WidgetSelect component for combo widgets
christian-byrne Jul 2, 2025
6bbd285
[feat] Update NodeWidgets to use safe widget data
christian-byrne Jul 2, 2025
39603dd
[feat] Update Vue node components with proper typing
christian-byrne Jul 2, 2025
04e9a79
[feat] Update GraphCanvas with VueNodeData typing
christian-byrne Jul 2, 2025
222a52d
[feat] Add feature flags and utility updates
christian-byrne Jul 2, 2025
124db59
[feat] Implement callback-driven widget updates
christian-byrne Jul 3, 2025
cd3296f
[feat] Add viewport debug overlay for TransformPane
christian-byrne Jul 3, 2025
122170f
[fix] Fix widget value synchronization between Vue and LiteGraph
christian-byrne Jul 4, 2025
0de3b8a
[feat] Add QuadTree spatial data structure for node indexing
christian-byrne Jul 4, 2025
a23d8be
[feat] Add Vue-based node rendering system with widget support
christian-byrne Jul 5, 2025
c3023e4
[fix] Remove FPS tracking to prevent memory leaks
christian-byrne Jul 5, 2025
cdd940e
[fix] Add proper cleanup for nodeManager to prevent memory leaks
christian-byrne Jul 5, 2025
95ab702
[test] Add test helper utilities for Vue node system testing
christian-byrne Jul 5, 2025
a58a354
[test] Add comprehensive tests for transform and spatial composables
christian-byrne Jul 5, 2025
32ddf72
[test] Add TransformPane component tests
christian-byrne Jul 5, 2025
c246326
[test] Add performance tests for transform operations
christian-byrne Jul 5, 2025
71c3c72
[feat] Implement LOD (Level of Detail) system for Vue nodes
christian-byrne Jul 5, 2025
290906e
[refactor] Improve type safety across Vue node widget system
christian-byrne Jul 5, 2025
5cb9ba1
[feat] Add CSS LOD classes for Vue node rendering optimization
christian-byrne Jul 5, 2025
d6315a1
[feat] Add debug type definitions for spatial indexing system
christian-byrne Jul 5, 2025
7d7dc09
[perf] Optimize TransformPane interaction tracking for better perform…
christian-byrne Jul 5, 2025
d29ce21
[refactor] Remove unused variables in GraphCanvas to fix TypeScript w…
christian-byrne Jul 5, 2025
57b09da
[test] Add missing useWidgetValue import in test file
christian-byrne Jul 5, 2025
18854d7
[cleanup] Remove temporary documentation and planning files
christian-byrne Jul 5, 2025
555e806
[perf] Optimize widget rendering performance
christian-byrne Jul 6, 2025
9a93764
[refactor] Extract canvas transform sync to dedicated composables
christian-byrne Jul 6, 2025
4304bb3
[test] Relocate and update test files
christian-byrne Jul 6, 2025
30728c1
[cleanup] Remove unused viewport culling settings and variables
christian-byrne Jul 6, 2025
32c8d0c
[refactor] Move QuadTreeBenchmark to test directory
christian-byrne Jul 6, 2025
1098d3b
[feat] Enhanced LOD system with component-driven approach (#4371)
christian-byrne Jul 7, 2025
108e54c
[perf] Global CSS optimizations for LOD system (#4379)
christian-byrne Jul 8, 2025
c6422da
Vue Node Body (#4387)
benceruleanlu Aug 6, 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
[refactor] Improve type safety across Vue node widget system
- Create WidgetValue union type for all valid widget values
- Replace 'any' types with proper generic constraints in SimplifiedWidget
- Add runtime validation for widget values in useGraphNodeManager
- Update WidgetSelect to use constrained generics instead of any
- Fix type assertions with proper validation functions
- Ensure SafeWidgetData uses WidgetValue type consistently

This eliminates most 'any' usage while maintaining runtime safety through validation.
  • Loading branch information
christian-byrne committed Jul 5, 2025
commit 290906e7ccac4cf4830ca70b799fbecf4ea717bf
4 changes: 2 additions & 2 deletions src/components/graph/vueNodes/NodeWidgets.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import type {
import { LODLevel } from '@/composables/graph/useLOD'
import { useWidgetRenderer } from '@/composables/graph/useWidgetRenderer'
import { useErrorHandling } from '@/composables/useErrorHandling'
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
import type { SimplifiedWidget, WidgetValue } from '@/types/simplifiedWidget'

interface NodeWidgetsProps {
node?: LGraphNode
Expand Down Expand Up @@ -106,7 +106,7 @@ const getVueComponent = (widget: SafeWidgetData) => {
return component || WidgetInputText // Fallback to text input
}

const getWidgetValue = (widget: SafeWidgetData): unknown => {
const getWidgetValue = (widget: SafeWidgetData): WidgetValue => {
return widget.value
}

Expand Down
6 changes: 3 additions & 3 deletions src/components/graph/vueWidgets/WidgetSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ import {
} from '@/utils/widgetPropFilter'

const props = defineProps<{
widget: SimplifiedWidget<any>
modelValue: any
widget: SimplifiedWidget<string | number | undefined>
modelValue: string | number | undefined
readonly?: boolean
}>()

const emit = defineEmits<{
'update:modelValue': [value: any]
'update:modelValue': [value: string | number | undefined]
}>()

// Use the composable for consistent widget value handling
Expand Down
59 changes: 52 additions & 7 deletions src/composables/graph/useGraphNodeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import type { LGraph, LGraphNode } from '@comfyorg/litegraph'
import { nextTick, reactive, readonly } from 'vue'

import type { WidgetValue } from '@/types/simplifiedWidget'
import type { SpatialIndexDebugInfo } from '@/types/spatialIndex'

import { type Bounds, QuadTree } from '../../utils/spatial/QuadTree'

export interface NodeState {
Expand All @@ -18,7 +21,7 @@ export interface NodeMetadata {
lastRenderTime: number
cachedBounds: DOMRect | null
lodLevel: 'high' | 'medium' | 'low'
spatialIndex?: any
spatialIndex?: QuadTree<string>
}

export interface PerformanceMetrics {
Expand All @@ -35,7 +38,7 @@ export interface PerformanceMetrics {
export interface SafeWidgetData {
name: string
type: string
value: unknown
value: WidgetValue
options?: Record<string, unknown>
callback?: ((value: unknown) => void) | undefined
}
Expand Down Expand Up @@ -87,7 +90,7 @@ export interface GraphNodeManager {
spatialMetrics: SpatialMetrics

// Debug
getSpatialIndexDebugInfo(): any | null
getSpatialIndexDebugInfo(): SpatialIndexDebugInfo | null
}

export const useGraphNodeManager = (graph: LGraph): GraphNodeManager => {
Expand Down Expand Up @@ -182,7 +185,7 @@ export const useGraphNodeManager = (graph: LGraph): GraphNodeManager => {
return {
name: widget.name || 'unknown',
type: widget.type || 'text',
value: undefined,
value: undefined, // Already a valid WidgetValue
options: undefined,
callback: undefined
}
Expand All @@ -207,6 +210,33 @@ export const useGraphNodeManager = (graph: LGraph): GraphNodeManager => {
return nodeRefs.get(id)
}

/**
* Validates that a value is a valid WidgetValue type
*/
const validateWidgetValue = (value: unknown): WidgetValue => {
if (value === null || value === undefined || value === void 0) {
return undefined
}
if (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'boolean'
) {
return value
}
if (typeof value === 'object') {
// Check if it's a File array
if (Array.isArray(value) && value.every((item) => item instanceof File)) {
return value as File[]
}
// Otherwise it's a generic object
return value as object
}
// If none of the above, return undefined
console.warn(`Invalid widget value type: ${typeof value}`, value)
return undefined
}

/**
* Updates Vue state when widget values change
*/
Expand All @@ -220,7 +250,7 @@ export const useGraphNodeManager = (graph: LGraph): GraphNodeManager => {
if (!currentData?.widgets) return

const updatedWidgets = currentData.widgets.map((w) =>
w.name === widgetName ? { ...w, value: value } : w
w.name === widgetName ? { ...w, value: validateWidgetValue(value) } : w
)
vueNodeData.set(nodeId, {
...currentData,
Expand All @@ -236,13 +266,25 @@ export const useGraphNodeManager = (graph: LGraph): GraphNodeManager => {
* Creates a wrapped callback for a widget that maintains LiteGraph/Vue sync
*/
const createWrappedWidgetCallback = (
widget: any,
widget: { value?: unknown; name: string }, // LiteGraph widget with minimal typing
originalCallback: ((value: unknown) => void) | undefined,
nodeId: string
) => {
return (value: unknown) => {
// 1. Update the widget value in LiteGraph (critical for LiteGraph state)
widget.value = value as string | number | boolean | object | undefined
// Validate that the value is of an acceptable type
if (
value !== null &&
value !== undefined &&
typeof value !== 'string' &&
typeof value !== 'number' &&
typeof value !== 'boolean' &&
typeof value !== 'object'
) {
console.warn(`Invalid widget value type: ${typeof value}`)
return
}
widget.value = value

// 2. Call the original callback if it exists
if (originalCallback) {
Expand Down Expand Up @@ -362,6 +404,9 @@ export const useGraphNodeManager = (graph: LGraph): GraphNodeManager => {
// Store non-reactive reference
nodeRefs.set(id, node)

// Set up widget callbacks BEFORE extracting data (critical order)
setupNodeWidgetCallbacks(node)

// Extract and store safe data for Vue
vueNodeData.set(id, extractVueNodeData(node))

Expand Down
14 changes: 10 additions & 4 deletions src/composables/graph/useWidgetValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
*/
import { type Ref, ref, watch } from 'vue'

import type { SimplifiedWidget } from '@/types/simplifiedWidget'
import type { SimplifiedWidget, WidgetValue } from '@/types/simplifiedWidget'

export interface UseWidgetValueOptions<T, U = T> {
export interface UseWidgetValueOptions<
T extends WidgetValue = WidgetValue,
U = T
> {
/** The widget configuration from LiteGraph */
widget: SimplifiedWidget<T>
/** The current value from parent component */
Expand All @@ -19,7 +22,10 @@ export interface UseWidgetValueOptions<T, U = T> {
transform?: (value: U) => T
}

export interface UseWidgetValueReturn<T, U = T> {
export interface UseWidgetValueReturn<
T extends WidgetValue = WidgetValue,
U = T
> {
/** Local value for immediate UI updates */
localValue: Ref<T>
/** Handler for user interactions */
Expand All @@ -38,7 +44,7 @@ export interface UseWidgetValueReturn<T, U = T> {
* })
* ```
*/
export function useWidgetValue<T, U = T>({
export function useWidgetValue<T extends WidgetValue = WidgetValue, U = T>({
widget,
modelValue,
defaultValue,
Expand Down
16 changes: 15 additions & 1 deletion src/types/simplifiedWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,21 @@
* Removes all DOM manipulation and positioning concerns
*/

export interface SimplifiedWidget<T = any, O = Record<string, any>> {
/** Valid types for widget values */
export type WidgetValue =
| string
| number
| boolean
| object
| undefined
| null
| void
| File[]

export interface SimplifiedWidget<
T extends WidgetValue = WidgetValue,
O = Record<string, any>
> {
/** Display name of the widget */
name: string

Expand Down