refactor litegraph to solve circular dep

This commit is contained in:
snomiao
2025-09-15 08:01:39 +00:00
parent 768e49bfdd
commit 5d082b7f37
30 changed files with 519 additions and 377 deletions

130
scripts/verbatim.mjs Normal file
View File

@@ -0,0 +1,130 @@
#!/usr/bin/env bun
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
// const __dirname = path.dirname(fileURLToPath(import.meta.url));
const __dirname = process.cwd()
// Parse the tsc.log file to get all errors
async function parseErrors(file) {
const logContent = await fs.readFile(file, 'utf-8');
const lines = logContent.split('\n').filter(line => line.includes('error TS1484'));
const errors = [];
for (const line of lines) {
// Match the format: filepath(line,col): error TS1484: 'TypeName' is a type
// Note: Some lines may have a number prefix followed by →
const match = line.match(/(?:\d+→)?(.+?)\((\d+),(\d+)\): error TS1484: '(.+?)' is a type/);
if (match) {
const [, filePath, lineNum, colNum, typeName] = match;
errors.push({
filePath: path.join(__dirname, filePath.trim()),
lineNum: parseInt(lineNum),
colNum: parseInt(colNum),
typeName
});
}
}
return errors;
}
// Group errors by file
function groupByFile(errors) {
const grouped = {};
for (const error of errors) {
if (!grouped[error.filePath]) {
grouped[error.filePath] = [];
}
grouped[error.filePath].push(error);
}
return grouped;
}
// Process a single file
async function processFile(filePath, errors) {
try {
const content = await fs.readFile(filePath, 'utf-8');
const lines = content.split('\n');
// Sort errors by line and column in reverse order to avoid position shifts
errors.sort((a, b) => {
if (a.lineNum !== b.lineNum) {
return b.lineNum - a.lineNum;
}
return b.colNum - a.colNum;
});
// Process each error
for (const error of errors) {
const lineIndex = error.lineNum - 1;
const line = lines[lineIndex];
if (!line) continue;
// Skip if already has 'type' keyword before this position
const beforePos = line.substring(0, error.colNum - 1);
if (beforePos.includes('import type') || beforePos.endsWith('{ type ') || beforePos.endsWith(', type ')) {
continue;
}
// Insert "type " at the exact column position (column is 1-based)
const insertPos = error.colNum - 1;
lines[lineIndex] = line.substring(0, insertPos) + 'type ' + line.substring(insertPos);
}
await fs.writeFile(filePath, lines.join('\n'));
console.log(`✓ Fixed ${errors.length} type imports in ${path.relative(__dirname, filePath)}`);
return true;
} catch (error) {
console.error(`✗ Error processing ${filePath}:`, error.message);
return false;
}
}
// Main function
async function main() {
console.log('🔧 Fixing TypeScript type-only imports...\n');
const logFile = path.join(__dirname, 'tsc.log');
if (!await readFile(logFile).catch(() => null)) {
console.error('Unable to read tsc.log');
console.error('Run this command to generate type errors and rerun this script again:');
console.error('pnpm typecheck > tsc.log');
return;
}
console.log('Parsing tsc.log for type import errors...\n');
const errors = await parseErrors(logFile);
console.log(`Found ${errors.length} type import errors\n`);
const grouped = groupByFile(errors);
const files = Object.keys(grouped);
console.log(`Processing ${files.length} files...\n`);
let successCount = 0;
let failCount = 0;
for (const filePath of files) {
const success = await processFile(filePath, grouped[filePath]);
if (success) {
successCount++;
} else {
failCount++;
}
}
console.log('\n📊 Summary:');
console.log(`✓ Successfully processed: ${successCount} files`);
if (failCount > 0) {
console.log(`✗ Failed to process: ${failCount} files`);
}
console.log('\n✨ Refactoring complete!');
console.log('Run "pnpm typecheck" to verify the fixes.');
}
// Run the script
main().catch(console.error);

View File

@@ -3,7 +3,7 @@ import type {
IContextMenuOptions, IContextMenuOptions,
IContextMenuValue IContextMenuValue
} from './interfaces' } from './interfaces'
import { LiteGraph } from './litegraph' import { LiteGraphSingleton } from './LiteGraphSingleton'
// TODO: Replace this pattern with something more modern. // TODO: Replace this pattern with something more modern.
export interface ContextMenu<TValue = unknown> { export interface ContextMenu<TValue = unknown> {
@@ -182,7 +182,7 @@ export class ContextMenu<TValue = unknown> {
root.style.left = `${left}px` root.style.left = `${left}px`
root.style.top = `${top}px` root.style.top = `${top}px`
if (LiteGraph.context_menu_scaling && options.scale) { if (LiteGraphSingleton.context_menu_scaling && options.scale) {
root.style.transform = `scale(${Math.round(options.scale * 4) * 0.25})` root.style.transform = `scale(${Math.round(options.scale * 4) * 0.25})`
} }
} }
@@ -355,7 +355,7 @@ export class ContextMenu<TValue = unknown> {
) { ) {
ContextMenu.trigger( ContextMenu.trigger(
this.parentMenu.root, this.parentMenu.root,
`${LiteGraph.pointerevents_method}leave`, `${LiteGraphSingleton.pointerevents_method}leave`,
e e
) )
} }

View File

@@ -34,7 +34,8 @@ import type {
Positionable, Positionable,
Size Size
} from './interfaces' } from './interfaces'
import { LiteGraph, SubgraphNode } from './litegraph' import { SubgraphNode } from './litegraph'
import { LiteGraphSingleton } from './LiteGraphSingleton'
import { import {
alignOutsideContainer, alignOutsideContainer,
alignToContainer, alignToContainer,
@@ -274,7 +275,7 @@ export class LGraph
* @param o data from previous serialization [optional] * @param o data from previous serialization [optional]
*/ */
constructor(o?: ISerialisedGraph | SerialisableGraph) { constructor(o?: ISerialisedGraph | SerialisableGraph) {
if (LiteGraph.debug) console.log('Graph created') if (LiteGraphSingleton.debug) console.log('Graph created')
/** @see MapProxyHandler */ /** @see MapProxyHandler */
const links = this._links const links = this._links
@@ -424,7 +425,7 @@ export class LGraph
this.sendEventToAllNodes('onStart') this.sendEventToAllNodes('onStart')
// launch // launch
this.starttime = LiteGraph.getTime() this.starttime = LiteGraphSingleton.getTime()
this.last_update_time = this.starttime this.last_update_time = this.starttime
interval ||= 0 interval ||= 0
@@ -486,7 +487,7 @@ export class LGraph
runStep(num: number, do_not_catch_errors: boolean, limit?: number): void { runStep(num: number, do_not_catch_errors: boolean, limit?: number): void {
num = num || 1 num = num || 1
const start = LiteGraph.getTime() const start = LiteGraphSingleton.getTime()
this.globaltime = 0.001 * (start - this.starttime) this.globaltime = 0.001 * (start - this.starttime)
const nodes = this._nodes_executable || this._nodes const nodes = this._nodes_executable || this._nodes
@@ -530,14 +531,14 @@ export class LGraph
this.errors_in_execution = false this.errors_in_execution = false
} catch (error) { } catch (error) {
this.errors_in_execution = true this.errors_in_execution = true
if (LiteGraph.throw_errors) throw error if (LiteGraphSingleton.throw_errors) throw error
if (LiteGraph.debug) console.log('Error during execution:', error) if (LiteGraphSingleton.debug) console.log('Error during execution:', error)
this.stop() this.stop()
} }
} }
const now = LiteGraph.getTime() const now = LiteGraphSingleton.getTime()
let elapsed = now - start let elapsed = now - start
if (elapsed == 0) elapsed = 1 if (elapsed == 0) elapsed = 1
@@ -662,7 +663,7 @@ export class LGraph
L.push(M[i]) L.push(M[i])
} }
if (L.length != this._nodes.length && LiteGraph.debug) if (L.length != this._nodes.length && LiteGraphSingleton.debug)
console.warn('something went wrong, nodes missing') console.warn('something went wrong, nodes missing')
/** Ensure type is set */ /** Ensure type is set */
@@ -718,16 +719,16 @@ export class LGraph
if (!column) continue if (!column) continue
let max_size = 100 let max_size = 100
let y = margin + LiteGraph.NODE_TITLE_HEIGHT let y = margin + LiteGraphSingleton.NODE_TITLE_HEIGHT
for (const node of column) { for (const node of column) {
node.pos[0] = layout == LiteGraph.VERTICAL_LAYOUT ? y : x node.pos[0] = layout == LiteGraphSingleton.VERTICAL_LAYOUT ? y : x
node.pos[1] = layout == LiteGraph.VERTICAL_LAYOUT ? x : y node.pos[1] = layout == LiteGraphSingleton.VERTICAL_LAYOUT ? x : y
const max_size_index = layout == LiteGraph.VERTICAL_LAYOUT ? 1 : 0 const max_size_index = layout == LiteGraphSingleton.VERTICAL_LAYOUT ? 1 : 0
if (node.size[max_size_index] > max_size) { if (node.size[max_size_index] > max_size) {
max_size = node.size[max_size_index] max_size = node.size[max_size_index]
} }
const node_size_index = layout == LiteGraph.VERTICAL_LAYOUT ? 0 : 1 const node_size_index = layout == LiteGraphSingleton.VERTICAL_LAYOUT ? 0 : 1
y += node.size[node_size_index] + margin + LiteGraph.NODE_TITLE_HEIGHT y += node.size[node_size_index] + margin + LiteGraphSingleton.NODE_TITLE_HEIGHT
} }
x += max_size + margin x += max_size + margin
} }
@@ -831,7 +832,7 @@ export class LGraph
const { state } = this const { state } = this
// Ensure created items are snapped // Ensure created items are snapped
if (LiteGraph.alwaysSnapToGrid) { if (LiteGraphSingleton.alwaysSnapToGrid) {
const snapTo = this.getSnapToGridSize() const snapTo = this.getSnapToGridSize()
if (snapTo) node.snapToGrid(snapTo) if (snapTo) node.snapToGrid(snapTo)
} }
@@ -856,16 +857,16 @@ export class LGraph
console.warn( console.warn(
'LiteGraph: there is already a node with this ID, changing it' 'LiteGraph: there is already a node with this ID, changing it'
) )
node.id = LiteGraph.use_uuids ? LiteGraph.uuidv4() : ++state.lastNodeId node.id = LiteGraphSingleton.use_uuids ? LiteGraphSingleton.uuidv4() : ++state.lastNodeId
} }
if (this._nodes.length >= LiteGraph.MAX_NUMBER_OF_NODES) { if (this._nodes.length >= LiteGraphSingleton.MAX_NUMBER_OF_NODES) {
throw 'LiteGraph: max number of nodes in a graph reached' throw 'LiteGraph: max number of nodes in a graph reached'
} }
// give him an id // give him an id
if (LiteGraph.use_uuids) { if (LiteGraphSingleton.use_uuids) {
if (node.id == null || node.id == -1) node.id = LiteGraph.uuidv4() if (node.id == null || node.id == -1) node.id = LiteGraphSingleton.uuidv4()
} else { } else {
if (node.id == null || node.id == -1) { if (node.id == null || node.id == -1) {
node.id = ++state.lastNodeId node.id = ++state.lastNodeId
@@ -1128,9 +1129,9 @@ export class LGraph
/** /**
* Snaps the provided items to a grid. * Snaps the provided items to a grid.
* *
* Item positions are reounded to the nearest multiple of {@link LiteGraph.CANVAS_GRID_SIZE}. * Item positions are reounded to the nearest multiple of {@link LiteGraphSingleton.CANVAS_GRID_SIZE}.
* *
* When {@link LiteGraph.alwaysSnapToGrid} is enabled * When {@link LiteGraphSingleton.alwaysSnapToGrid} is enabled
* and the grid size is falsy, a default of 1 is used. * and the grid size is falsy, a default of 1 is used.
* @param items The items to be snapped to the grid * @param items The items to be snapped to the grid
* @todo Currently only snaps nodes. * @todo Currently only snaps nodes.
@@ -1150,9 +1151,9 @@ export class LGraph
*/ */
getSnapToGridSize(): number { getSnapToGridSize(): number {
// Default to 1 when always snapping // Default to 1 when always snapping
return LiteGraph.alwaysSnapToGrid return LiteGraphSingleton.alwaysSnapToGrid
? LiteGraph.CANVAS_GRID_SIZE || 1 ? LiteGraphSingleton.CANVAS_GRID_SIZE || 1
: LiteGraph.CANVAS_GRID_SIZE : LiteGraphSingleton.CANVAS_GRID_SIZE
} }
/** /**
@@ -1164,11 +1165,11 @@ export class LGraph
checkNodeTypes() { checkNodeTypes() {
const { _nodes } = this const { _nodes } = this
for (const [i, node] of _nodes.entries()) { for (const [i, node] of _nodes.entries()) {
const ctor = LiteGraph.registered_node_types[node.type] const ctor = LiteGraphSingleton.registered_node_types[node.type]
if (node.constructor == ctor) continue if (node.constructor == ctor) continue
console.log('node being replaced by newer version:', node.type) console.log('node being replaced by newer version:', node.type)
const newnode = LiteGraph.createNode(node.type) const newnode = LiteGraphSingleton.createNode(node.type)
if (!newnode) continue if (!newnode) continue
_nodes[i] = newnode _nodes[i] = newnode
newnode.configure(node.serialize()) newnode.configure(node.serialize())
@@ -1229,7 +1230,7 @@ export class LGraph
/* Called when something visually changed (not the graph!) */ /* Called when something visually changed (not the graph!) */
change(): void { change(): void {
if (LiteGraph.debug) { if (LiteGraphSingleton.debug) {
console.log('Graph changed') console.log('Graph changed')
} }
this.canvasAction((c) => c.setDirty(true, true)) this.canvasAction((c) => c.setDirty(true, true))
@@ -1579,7 +1580,7 @@ export class LGraph
}) })
// Create subgraph node object // Create subgraph node object
const subgraphNode = LiteGraph.createNode(subgraph.id, subgraph.name, { const subgraphNode = LiteGraphSingleton.createNode(subgraph.id, subgraph.name, {
outputs: structuredClone(outputs) outputs: structuredClone(outputs)
}) })
if (!subgraphNode) throw new Error('Failed to create subgraph node') if (!subgraphNode) throw new Error('Failed to create subgraph node')
@@ -1598,7 +1599,7 @@ export class LGraph
) )
//Correct for title height. It's included in bounding box, but not _posSize //Correct for title height. It's included in bounding box, but not _posSize
subgraphNode.pos[1] += LiteGraph.NODE_TITLE_HEIGHT / 2 subgraphNode.pos[1] += LiteGraphSingleton.NODE_TITLE_HEIGHT / 2
// Add the subgraph node to the graph // Add the subgraph node to the graph
this.add(subgraphNode) this.add(subgraphNode)
@@ -1719,7 +1720,7 @@ export class LGraph
const movedNodes = multiClone(subgraphNode.subgraph.nodes) const movedNodes = multiClone(subgraphNode.subgraph.nodes)
const nodeIdMap = new Map<NodeId, NodeId>() const nodeIdMap = new Map<NodeId, NodeId>()
for (const n_info of movedNodes) { for (const n_info of movedNodes) {
const node = LiteGraph.createNode(String(n_info.type), n_info.title) const node = LiteGraphSingleton.createNode(String(n_info.type), n_info.title)
if (!node) { if (!node) {
throw new Error('Node not found') throw new Error('Node not found')
} }
@@ -2027,7 +2028,7 @@ export class LGraph
definitions, definitions,
config, config,
extra, extra,
version: LiteGraph.VERSION version: LiteGraphSingleton.VERSION
} }
} }
@@ -2052,7 +2053,7 @@ export class LGraph
const { id, revision, config, state } = this const { id, revision, config, state } = this
const nodeList = const nodeList =
!LiteGraph.use_uuids && options?.sortNodes !LiteGraphSingleton.use_uuids && options?.sortNodes
? // @ts-expect-error If LiteGraph.use_uuids is false, ids are numbers. ? // @ts-expect-error If LiteGraph.use_uuids is false, ids are numbers.
[...this._nodes].sort((a, b) => a.id - b.id) [...this._nodes].sort((a, b) => a.id - b.id)
: this._nodes : this._nodes
@@ -2072,7 +2073,7 @@ export class LGraph
// Save scale and offset // Save scale and offset
const extra = { ...this.extra } const extra = { ...this.extra }
if (LiteGraph.saveViewportWithGraph) extra.ds = this.#getDragAndScale() if (LiteGraphSingleton.saveViewportWithGraph) extra.ds = this.#getDragAndScale()
if (!extra.ds) delete extra.ds if (!extra.ds) delete extra.ds
const data: ReturnType<typeof this.asSerialisable> = { const data: ReturnType<typeof this.asSerialisable> = {
@@ -2230,9 +2231,9 @@ export class LGraph
if (nodesData) { if (nodesData) {
for (const n_info of nodesData) { for (const n_info of nodesData) {
// stored info // stored info
let node = LiteGraph.createNode(String(n_info.type), n_info.title) let node = LiteGraphSingleton.createNode(String(n_info.type), n_info.title)
if (!node) { if (!node) {
if (LiteGraph.debug) if (LiteGraphSingleton.debug)
console.log('Node not found or has errors:', n_info.type) console.log('Node not found or has errors:', n_info.type)
// in case of error we create a replacement node to avoid losing info // in case of error we create a replacement node to avoid losing info
@@ -2284,7 +2285,7 @@ export class LGraph
if (groupData) { if (groupData) {
for (const data of groupData) { for (const data of groupData) {
// TODO: Search/remove these global object refs // TODO: Search/remove these global object refs
const group = new LiteGraph.LGraphGroup() const group = new LiteGraphSingleton.LGraphGroup()
group.configure(data) group.configure(data)
this.add(group) this.add(group)
} }

View File

@@ -52,7 +52,8 @@ import type {
Rect, Rect,
Size Size
} from './interfaces' } from './interfaces'
import { LiteGraph, Rectangle, SubgraphNode, createUuidv4 } from './litegraph' import { Rectangle, SubgraphNode, createUuidv4 } from './litegraph'
import { LiteGraphSingleton } from './LiteGraphSingleton'
import { import {
containsRect, containsRect,
createBounds, createBounds,
@@ -409,12 +410,12 @@ export class LGraphCanvas
* @deprecated Use {@link LGraphNode.titleFontStyle} instead. * @deprecated Use {@link LGraphNode.titleFontStyle} instead.
*/ */
get title_text_font(): string { get title_text_font(): string {
return `${LiteGraph.NODE_TEXT_SIZE}px ${LiteGraph.NODE_FONT}` return `${LiteGraphSingleton.NODE_TEXT_SIZE}px ${LiteGraphSingleton.NODE_FONT}`
} }
// #endregion Legacy accessors // #endregion Legacy accessors
get inner_text_font(): string { get inner_text_font(): string {
return `normal ${LiteGraph.NODE_SUBTEXT_SIZE}px ${LiteGraph.NODE_FONT}` return `normal ${LiteGraphSingleton.NODE_SUBTEXT_SIZE}px ${LiteGraphSingleton.NODE_FONT}`
} }
#maximumFrameGap = 0 #maximumFrameGap = 0
@@ -433,14 +434,14 @@ export class LGraphCanvas
* @deprecated Use {@link LiteGraphGlobal.ROUND_RADIUS} instead. * @deprecated Use {@link LiteGraphGlobal.ROUND_RADIUS} instead.
*/ */
get round_radius() { get round_radius() {
return LiteGraph.ROUND_RADIUS return LiteGraphSingleton.ROUND_RADIUS
} }
/** /**
* @deprecated Use {@link LiteGraphGlobal.ROUND_RADIUS} instead. * @deprecated Use {@link LiteGraphGlobal.ROUND_RADIUS} instead.
*/ */
set round_radius(value: number) { set round_radius(value: number) {
LiteGraph.ROUND_RADIUS = value LiteGraphSingleton.ROUND_RADIUS = value
} }
// Cached LOD threshold values for performance // Cached LOD threshold values for performance
@@ -459,7 +460,7 @@ export class LGraphCanvas
return return
} }
const baseFontSize = LiteGraph.NODE_TEXT_SIZE // 14px const baseFontSize = LiteGraphSingleton.NODE_TEXT_SIZE // 14px
const dprAdjustment = Math.sqrt(window.devicePixelRatio || 1) //Using sqrt here because higher DPR monitors do not linearily scale the readability of the font, instead they increase the font by some heurisitc, and to approximate we use sqrt to say bascially a DPR of 2 increases the readibility by 40%, 3 by 70% const dprAdjustment = Math.sqrt(window.devicePixelRatio || 1) //Using sqrt here because higher DPR monitors do not linearily scale the readability of the font, instead they increase the font by some heurisitc, and to approximate we use sqrt to say bascially a DPR of 2 increases the readibility by 40%, 3 by 70%
// Calculate the zoom level where text becomes unreadable // Calculate the zoom level where text becomes unreadable
@@ -788,7 +789,7 @@ export class LGraphCanvas
// No longer in use // No longer in use
// add menu when releasing link in empty space // add menu when releasing link in empty space
if (LiteGraph.release_link_on_empty_shows_menu) { if (LiteGraphSingleton.release_link_on_empty_shows_menu) {
const linkReleaseContext = const linkReleaseContext =
this.linkConnector.state.connectingTo === 'input' this.linkConnector.state.connectingTo === 'input'
? { ? {
@@ -835,8 +836,8 @@ export class LGraphCanvas
// in range (1.01, 2.5). Less than 1 will invert the zoom direction // in range (1.01, 2.5). Less than 1 will invert the zoom direction
this.zoom_speed = 1.1 this.zoom_speed = 1.1
this.node_title_color = LiteGraph.NODE_TITLE_COLOR this.node_title_color = LiteGraphSingleton.NODE_TITLE_COLOR
this.default_link_color = LiteGraph.LINK_COLOR this.default_link_color = LiteGraphSingleton.LINK_COLOR
this.default_connection_color = { this.default_connection_color = {
input_off: '#778', input_off: '#778',
input_on: '#7F7', input_on: '#7F7',
@@ -959,7 +960,7 @@ export class LGraphCanvas
): void { ): void {
const canvas = LGraphCanvas.active_canvas const canvas = LGraphCanvas.active_canvas
const group = new LiteGraph.LGraphGroup() const group = new LiteGraphSingleton.LGraphGroup()
group.pos = canvas.convertEventToCanvasOffset(mouse_event) group.pos = canvas.convertEventToCanvasOffset(mouse_event)
if (!canvas.graph) throw new NullGraphError() if (!canvas.graph) throw new NullGraphError()
canvas.graph.add(group) canvas.graph.add(group)
@@ -1009,7 +1010,7 @@ export class LGraphCanvas
prev_menu: ContextMenu<string>, prev_menu: ContextMenu<string>,
node: LGraphNode node: LGraphNode
): void { ): void {
new LiteGraph.ContextMenu(['Top', 'Bottom', 'Left', 'Right'], { new LiteGraphSingleton.ContextMenu(['Top', 'Bottom', 'Left', 'Right'], {
event, event,
callback: inner_clicked, callback: inner_clicked,
parentMenu: prev_menu parentMenu: prev_menu
@@ -1033,7 +1034,7 @@ export class LGraphCanvas
event: MouseEvent, event: MouseEvent,
prev_menu: ContextMenu<string> prev_menu: ContextMenu<string>
): void { ): void {
new LiteGraph.ContextMenu(['Top', 'Bottom', 'Left', 'Right'], { new LiteGraphSingleton.ContextMenu(['Top', 'Bottom', 'Left', 'Right'], {
event, event,
callback: inner_clicked, callback: inner_clicked,
parentMenu: prev_menu parentMenu: prev_menu
@@ -1056,7 +1057,7 @@ export class LGraphCanvas
event: MouseEvent, event: MouseEvent,
prev_menu: ContextMenu<string> prev_menu: ContextMenu<string>
): void { ): void {
new LiteGraph.ContextMenu(['Vertically', 'Horizontally'], { new LiteGraphSingleton.ContextMenu(['Vertically', 'Horizontally'], {
event, event,
callback: inner_clicked, callback: inner_clicked,
parentMenu: prev_menu parentMenu: prev_menu
@@ -1104,7 +1105,7 @@ export class LGraphCanvas
): void { ): void {
if (!graph) return if (!graph) return
const categories = LiteGraph.getNodeTypesCategories( const categories = LiteGraphSingleton.getNodeTypesCategories(
canvas.filter || graph.filter canvas.filter || graph.filter
).filter((category) => category.startsWith(base_category)) ).filter((category) => category.startsWith(base_category))
const entries: AddNodeMenu[] = [] const entries: AddNodeMenu[] = []
@@ -1147,7 +1148,7 @@ export class LGraphCanvas
} }
} }
const nodes = LiteGraph.getNodeTypesInCategory( const nodes = LiteGraphSingleton.getNodeTypesInCategory(
base_category.slice(0, -1), base_category.slice(0, -1),
canvas.filter || graph.filter canvas.filter || graph.filter
) )
@@ -1171,7 +1172,7 @@ export class LGraphCanvas
const first_event = contextMenu.getFirstEvent() const first_event = contextMenu.getFirstEvent()
canvas.graph.beforeChange() canvas.graph.beforeChange()
const node = LiteGraph.createNode(value.value) const node = LiteGraphSingleton.createNode(value.value)
if (node) { if (node) {
if (!first_event) if (!first_event)
throw new TypeError( throw new TypeError(
@@ -1191,7 +1192,7 @@ export class LGraphCanvas
entries.push(entry) entries.push(entry)
} }
new LiteGraph.ContextMenu( new LiteGraphSingleton.ContextMenu(
entries, entries,
{ event: e, parentMenu: prev_menu }, { event: e, parentMenu: prev_menu },
// @ts-expect-error - extra parameter // @ts-expect-error - extra parameter
@@ -1220,12 +1221,12 @@ export class LGraphCanvas
let entries: (IContextMenuValue<INodeSlotContextItem> | null)[] = [] let entries: (IContextMenuValue<INodeSlotContextItem> | null)[] = []
if ( if (
LiteGraph.do_add_triggers_slots && LiteGraphSingleton.do_add_triggers_slots &&
node.findOutputSlot('onExecuted') == -1 node.findOutputSlot('onExecuted') == -1
) { ) {
entries.push({ entries.push({
content: 'On Executed', content: 'On Executed',
value: ['onExecuted', LiteGraph.EVENT, { nameLocked: true }], value: ['onExecuted', LiteGraphSingleton.EVENT, { nameLocked: true }],
className: 'event' className: 'event'
}) })
} }
@@ -1235,7 +1236,7 @@ export class LGraphCanvas
if (!entries.length) return if (!entries.length) return
new LiteGraph.ContextMenu<INodeSlotContextItem>(entries, { new LiteGraphSingleton.ContextMenu<INodeSlotContextItem>(entries, {
event: e, event: e,
callback: inner_clicked, callback: inner_clicked,
parentMenu: prev_menu, parentMenu: prev_menu,
@@ -1263,7 +1264,7 @@ export class LGraphCanvas
for (const i in value) { for (const i in value) {
entries.push({ content: i, value: value[i] }) entries.push({ content: i, value: value[i] })
} }
new LiteGraph.ContextMenu(entries, { new LiteGraphSingleton.ContextMenu(entries, {
event: e, event: e,
callback: inner_clicked, callback: inner_clicked,
parentMenu: prev_menu, parentMenu: prev_menu,
@@ -1322,7 +1323,7 @@ export class LGraphCanvas
return return
} }
new LiteGraph.ContextMenu<string>( new LiteGraphSingleton.ContextMenu<string>(
entries, entries,
{ {
event: e, event: e,
@@ -1465,18 +1466,18 @@ export class LGraphCanvas
let dialogCloseTimer: number let dialogCloseTimer: number
dialog.addEventListener('mouseleave', function () { dialog.addEventListener('mouseleave', function () {
if (LiteGraph.dialog_close_on_mouse_leave) { if (LiteGraphSingleton.dialog_close_on_mouse_leave) {
if (!dialog.is_modified && LiteGraph.dialog_close_on_mouse_leave) { if (!dialog.is_modified && LiteGraphSingleton.dialog_close_on_mouse_leave) {
// @ts-expect-error - setTimeout type // @ts-expect-error - setTimeout type
dialogCloseTimer = setTimeout( dialogCloseTimer = setTimeout(
dialog.close, dialog.close,
LiteGraph.dialog_close_on_mouse_leave_delay LiteGraphSingleton.dialog_close_on_mouse_leave_delay
) )
} }
} }
}) })
dialog.addEventListener('mouseenter', function () { dialog.addEventListener('mouseenter', function () {
if (LiteGraph.dialog_close_on_mouse_leave) { if (LiteGraphSingleton.dialog_close_on_mouse_leave) {
if (dialogCloseTimer) clearTimeout(dialogCloseTimer) if (dialogCloseTimer) clearTimeout(dialogCloseTimer)
} }
}) })
@@ -1596,7 +1597,7 @@ export class LGraphCanvas
menu: ContextMenu, menu: ContextMenu,
node: LGraphNode node: LGraphNode
): boolean { ): boolean {
new LiteGraph.ContextMenu(LiteGraph.NODE_MODES, { new LiteGraphSingleton.ContextMenu(LiteGraphSingleton.NODE_MODES, {
event: e, event: e,
callback: inner_clicked, callback: inner_clicked,
parentMenu: menu, parentMenu: menu,
@@ -1606,9 +1607,9 @@ export class LGraphCanvas
function inner_clicked(v: string) { function inner_clicked(v: string) {
if (!node) return if (!node) return
const kV = Object.values(LiteGraph.NODE_MODES).indexOf(v) const kV = Object.values(LiteGraphSingleton.NODE_MODES).indexOf(v)
const fApplyMultiNode = function (node: LGraphNode) { const fApplyMultiNode = function (node: LGraphNode) {
if (kV !== -1 && LiteGraph.NODE_MODES[kV]) { if (kV !== -1 && LiteGraphSingleton.NODE_MODES[kV]) {
node.changeMode(kV) node.changeMode(kV)
} else { } else {
console.warn(`unexpected mode: ${v}`) console.warn(`unexpected mode: ${v}`)
@@ -1664,7 +1665,7 @@ export class LGraphCanvas
} }
values.push(value) values.push(value)
} }
new LiteGraph.ContextMenu<string | null>(values, { new LiteGraphSingleton.ContextMenu<string | null>(values, {
event: e, event: e,
callback: inner_clicked, callback: inner_clicked,
parentMenu: menu, parentMenu: menu,
@@ -1698,17 +1699,17 @@ export class LGraphCanvas
static onMenuNodeShapes( static onMenuNodeShapes(
// @ts-expect-error - unused parameter // @ts-expect-error - unused parameter
value: IContextMenuValue<(typeof LiteGraph.VALID_SHAPES)[number]>, value: IContextMenuValue<(typeof LiteGraphSingleton.VALID_SHAPES)[number]>,
// @ts-expect-error - unused parameter // @ts-expect-error - unused parameter
options: IContextMenuOptions<(typeof LiteGraph.VALID_SHAPES)[number]>, options: IContextMenuOptions<(typeof LiteGraphSingleton.VALID_SHAPES)[number]>,
e: MouseEvent, e: MouseEvent,
menu?: ContextMenu<(typeof LiteGraph.VALID_SHAPES)[number]>, menu?: ContextMenu<(typeof LiteGraphSingleton.VALID_SHAPES)[number]>,
node?: LGraphNode node?: LGraphNode
): boolean { ): boolean {
if (!node) throw 'no node passed' if (!node) throw 'no node passed'
new LiteGraph.ContextMenu<(typeof LiteGraph.VALID_SHAPES)[number]>( new LiteGraphSingleton.ContextMenu<(typeof LiteGraphSingleton.VALID_SHAPES)[number]>(
LiteGraph.VALID_SHAPES, LiteGraphSingleton.VALID_SHAPES,
{ {
event: e, event: e,
callback: inner_clicked, callback: inner_clicked,
@@ -1717,7 +1718,7 @@ export class LGraphCanvas
} }
) )
function inner_clicked(v: (typeof LiteGraph.VALID_SHAPES)[number]) { function inner_clicked(v: (typeof LiteGraphSingleton.VALID_SHAPES)[number]) {
if (!node) return if (!node) return
if (!node.graph) throw new NullGraphError() if (!node.graph) throw new NullGraphError()
@@ -2099,7 +2100,7 @@ export class LGraphCanvas
if (this.#maximumFrameGap > 0) { if (this.#maximumFrameGap > 0) {
// Manual FPS limit // Manual FPS limit
const gap = const gap =
this.#maximumFrameGap - (LiteGraph.getTime() - this.last_draw_time) this.#maximumFrameGap - (LiteGraphSingleton.getTime() - this.last_draw_time)
setTimeout(renderFrame.bind(this), Math.max(1, gap)) setTimeout(renderFrame.bind(this), Math.max(1, gap))
} else { } else {
// FPS limited by refresh rate // FPS limited by refresh rate
@@ -2170,7 +2171,7 @@ export class LGraphCanvas
// Hover transitions // Hover transitions
// TODO: Implement single lerp ease factor for current progress on hover in/out. // TODO: Implement single lerp ease factor for current progress on hover in/out.
// In drawNode, multiply by ease factor and differential value (e.g. bg alpha +0.5). // In drawNode, multiply by ease factor and differential value (e.g. bg alpha +0.5).
otherNode.lostFocusAt = LiteGraph.getTime() otherNode.lostFocusAt = LiteGraphSingleton.getTime()
this.node_over?.onMouseLeave?.(e) this.node_over?.onMouseLeave?.(e)
this.node_over = undefined this.node_over = undefined
@@ -2223,7 +2224,7 @@ export class LGraphCanvas
this.canvas.focus() this.canvas.focus()
LiteGraph.closeAllContextMenus(ref_window) LiteGraphSingleton.closeAllContextMenus(ref_window)
if (this.onMouse?.(e) == true) return if (this.onMouse?.(e) == true) return
@@ -2294,7 +2295,7 @@ export class LGraphCanvas
} }
this.last_mouse = [x, y] this.last_mouse = [x, y]
this.last_mouseclick = LiteGraph.getTime() this.last_mouseclick = LiteGraphSingleton.getTime()
this.last_mouse_dragging = true this.last_mouse_dragging = true
graph.change() graph.change()
@@ -2348,7 +2349,7 @@ export class LGraphCanvas
if ( if (
ctrlOrMeta && ctrlOrMeta &&
!e.altKey && !e.altKey &&
LiteGraph.canvasNavigationMode === 'legacy' LiteGraphSingleton.canvasNavigationMode === 'legacy'
) { ) {
this.#setupNodeSelectionDrag(e, pointer, node) this.#setupNodeSelectionDrag(e, pointer, node)
@@ -2363,7 +2364,7 @@ export class LGraphCanvas
// clone node ALT dragging // clone node ALT dragging
if ( if (
LiteGraph.alt_drag_do_clone_nodes && LiteGraphSingleton.alt_drag_do_clone_nodes &&
e.altKey && e.altKey &&
!e.ctrlKey && !e.ctrlKey &&
node && node &&
@@ -2383,7 +2384,7 @@ export class LGraphCanvas
if (node_data?.type != null) { if (node_data?.type != null) {
// Ensure the cloned node is configured against the correct type (especially for SubgraphNodes) // Ensure the cloned node is configured against the correct type (especially for SubgraphNodes)
node_data.type = newType node_data.type = newType
const cloned = LiteGraph.createNode(newType) const cloned = LiteGraphSingleton.createNode(newType)
if (cloned) { if (cloned) {
cloned.configure(node_data) cloned.configure(node_data)
cloned.pos[0] += 5 cloned.pos[0] += 5
@@ -2566,7 +2567,7 @@ export class LGraphCanvas
} }
pointer.finally = () => (this.resizingGroup = null) pointer.finally = () => (this.resizingGroup = null)
} else { } else {
const f = group.font_size || LiteGraph.DEFAULT_GROUP_FONT_SIZE const f = group.font_size || LiteGraphSingleton.DEFAULT_GROUP_FONT_SIZE
const headerHeight = f * 1.4 const headerHeight = f * 1.4
if ( if (
isInRectangle( isInRectangle(
@@ -2617,7 +2618,7 @@ export class LGraphCanvas
this.allow_dragcanvas this.allow_dragcanvas
) { ) {
// allow dragging canvas if canvas is not in standard, or read-only (pan mode in standard) // allow dragging canvas if canvas is not in standard, or read-only (pan mode in standard)
if (LiteGraph.canvasNavigationMode !== 'standard' || this.read_only) { if (LiteGraphSingleton.canvasNavigationMode !== 'standard' || this.read_only) {
pointer.onClick = () => this.processSelect(null, e) pointer.onClick = () => this.processSelect(null, e)
pointer.finally = () => (this.dragging_canvas = false) pointer.finally = () => (this.dragging_canvas = false)
this.dragging_canvas = true this.dragging_canvas = true
@@ -2714,11 +2715,11 @@ export class LGraphCanvas
linkConnector.dragNewFromOutput(graph, node, output) linkConnector.dragNewFromOutput(graph, node, output)
this.#linkConnectorDrop() this.#linkConnectorDrop()
if (LiteGraph.shift_click_do_break_link_from) { if (LiteGraphSingleton.shift_click_do_break_link_from) {
if (e.shiftKey) { if (e.shiftKey) {
node.disconnectOutput(i) node.disconnectOutput(i)
} }
} else if (LiteGraph.ctrl_alt_click_do_break_link) { } else if (LiteGraphSingleton.ctrl_alt_click_do_break_link) {
if (ctrlOrMeta && e.altKey && !e.shiftKey) { if (ctrlOrMeta && e.altKey && !e.shiftKey) {
node.disconnectOutput(i) node.disconnectOutput(i)
} }
@@ -2747,13 +2748,13 @@ export class LGraphCanvas
pointer.onClick = () => node.onInputClick?.(i, e) pointer.onClick = () => node.onInputClick?.(i, e)
const shouldBreakLink = const shouldBreakLink =
LiteGraph.ctrl_alt_click_do_break_link && LiteGraphSingleton.ctrl_alt_click_do_break_link &&
ctrlOrMeta && ctrlOrMeta &&
e.altKey && e.altKey &&
!e.shiftKey !e.shiftKey
if (input.link !== null || input._floatingLinks?.size) { if (input.link !== null || input._floatingLinks?.size) {
// Existing link // Existing link
if (shouldBreakLink || LiteGraph.click_do_break_link_to) { if (shouldBreakLink || LiteGraphSingleton.click_do_break_link_to) {
node.disconnectInput(i, true) node.disconnectInput(i, true)
} else if (e.shiftKey || this.allow_reconnect_links) { } else if (e.shiftKey || this.allow_reconnect_links) {
linkConnector.moveInputLink(graph, input) linkConnector.moveInputLink(graph, input)
@@ -3028,7 +3029,7 @@ export class LGraphCanvas
const { pointer } = this const { pointer } = this
if ( if (
LiteGraph.middle_click_slot_add_default_node && LiteGraphSingleton.middle_click_slot_add_default_node &&
node && node &&
this.allow_interaction && this.allow_interaction &&
!this.read_only && !this.read_only &&
@@ -3323,7 +3324,7 @@ export class LGraphCanvas
} else if ( } else if (
inputId != -1 && inputId != -1 &&
node.inputs[inputId] && node.inputs[inputId] &&
LiteGraph.isValidConnection( LiteGraphSingleton.isValidConnection(
firstLink.fromSlot.type, firstLink.fromSlot.type,
node.inputs[inputId].type node.inputs[inputId].type
) )
@@ -3350,7 +3351,7 @@ export class LGraphCanvas
if ( if (
outputId != -1 && outputId != -1 &&
node.outputs[outputId] && node.outputs[outputId] &&
LiteGraph.isValidConnection( LiteGraphSingleton.isValidConnection(
firstLink.fromSlot.type, firstLink.fromSlot.type,
node.outputs[outputId].type node.outputs[outputId].type
) )
@@ -3503,7 +3504,7 @@ export class LGraphCanvas
*/ */
#processDraggedItems(e: CanvasPointerEvent): void { #processDraggedItems(e: CanvasPointerEvent): void {
const { graph } = this const { graph } = this
if (e.shiftKey || LiteGraph.alwaysSnapToGrid) if (e.shiftKey || LiteGraphSingleton.alwaysSnapToGrid)
graph?.snapToGrid(this.selectedItems) graph?.snapToGrid(this.selectedItems)
this.dirty_canvas = true this.dirty_canvas = true
@@ -3527,7 +3528,7 @@ export class LGraphCanvas
this.adjustMouseEvent(e) this.adjustMouseEvent(e)
const now = LiteGraph.getTime() const now = LiteGraphSingleton.getTime()
e.click_time = now - this.last_mouseclick e.click_time = now - this.last_mouseclick
/** The mouseup event occurred near the mousedown event. */ /** The mouseup event occurred near the mousedown event. */
@@ -3629,7 +3630,7 @@ export class LGraphCanvas
e.ctrlKey || (e.metaKey && navigator.platform.includes('Mac')) e.ctrlKey || (e.metaKey && navigator.platform.includes('Mac'))
const isZoomModifier = isCtrlOrMacMeta && !e.altKey && !e.shiftKey const isZoomModifier = isCtrlOrMacMeta && !e.altKey && !e.shiftKey
if (isZoomModifier || LiteGraph.canvasNavigationMode === 'legacy') { if (isZoomModifier || LiteGraphSingleton.canvasNavigationMode === 'legacy') {
// Legacy mode or standard mode with ctrl - use wheel for zoom // Legacy mode or standard mode with ctrl - use wheel for zoom
if (isTrackpad) { if (isTrackpad) {
// Trackpad gesture - use smooth scaling // Trackpad gesture - use smooth scaling
@@ -3870,7 +3871,7 @@ export class LGraphCanvas
// if ctrl + shift + v is off, return when isConnectUnselected is true (shift is pressed) to maintain old behavior // if ctrl + shift + v is off, return when isConnectUnselected is true (shift is pressed) to maintain old behavior
if ( if (
!LiteGraph.ctrl_shift_v_paste_connect_unselected_outputs && !LiteGraphSingleton.ctrl_shift_v_paste_connect_unselected_outputs &&
connectInputs connectInputs
) )
return return
@@ -3952,7 +3953,7 @@ export class LGraphCanvas
// Nodes // Nodes
for (const info of parsed.nodes) { for (const info of parsed.nodes) {
const node = info.type == null ? null : LiteGraph.createNode(info.type) const node = info.type == null ? null : LiteGraphSingleton.createNode(info.type)
if (!node) { if (!node) {
// failedNodes.push(info) // failedNodes.push(info)
continue continue
@@ -3995,7 +3996,7 @@ export class LGraphCanvas
// If it wasn't copied, use the original graph value // If it wasn't copied, use the original graph value
if ( if (
connectInputs && connectInputs &&
LiteGraph.ctrl_shift_v_paste_connect_unselected_outputs LiteGraphSingleton.ctrl_shift_v_paste_connect_unselected_outputs
) { ) {
outNode ??= graph.getNodeById(info.origin_id) outNode ??= graph.getNodeById(info.origin_id)
afterRerouteId ??= info.parentId afterRerouteId ??= info.parentId
@@ -4560,7 +4561,7 @@ export class LGraphCanvas
return return
// fps counting // fps counting
const now = LiteGraph.getTime() const now = LiteGraphSingleton.getTime()
this.render_time = (now - this.last_draw_time) * 0.001 this.render_time = (now - this.last_draw_time) * 0.001
this.last_draw_time = now this.last_draw_time = now
@@ -4625,7 +4626,7 @@ export class LGraphCanvas
// TODO: Set snapping value when changed instead of once per frame // TODO: Set snapping value when changed instead of once per frame
this.#snapToGrid = this.#snapToGrid =
this.#shiftDown || LiteGraph.alwaysSnapToGrid this.#shiftDown || LiteGraphSingleton.alwaysSnapToGrid
? this.graph?.getSnapToGridSize() ? this.graph?.getSnapToGridSize()
: undefined : undefined
@@ -4718,9 +4719,9 @@ export class LGraphCanvas
const connType = fromSlot.type const connType = fromSlot.type
const colour = const colour =
connType === LiteGraph.EVENT connType === LiteGraphSingleton.EVENT
? LiteGraph.EVENT_LINK_COLOR ? LiteGraphSingleton.EVENT_LINK_COLOR
: LiteGraph.CONNECTING_LINK_COLOR : LiteGraphSingleton.CONNECTING_LINK_COLOR
// the connection being dragged by the mouse // the connection being dragged by the mouse
if (this.linkRenderer) { if (this.linkRenderer) {
@@ -4746,7 +4747,7 @@ export class LGraphCanvas
ctx.fillStyle = colour ctx.fillStyle = colour
ctx.beginPath() ctx.beginPath()
if (connType === LiteGraph.EVENT || connShape === RenderShape.BOX) { if (connType === LiteGraphSingleton.EVENT || connShape === RenderShape.BOX) {
ctx.rect(pos[0] - 6 + 0.5, pos[1] - 5 + 0.5, 14, 10) ctx.rect(pos[0] - 6 + 0.5, pos[1] - 5 + 0.5, 14, 10)
ctx.rect( ctx.rect(
highlightPos[0] - 6 + 0.5, highlightPos[0] - 6 + 0.5,
@@ -4836,7 +4837,7 @@ export class LGraphCanvas
/** Get the target snap / highlight point in graph space */ /** Get the target snap / highlight point in graph space */
#getHighlightPosition(): ReadOnlyPoint { #getHighlightPosition(): ReadOnlyPoint {
return LiteGraph.snaps_for_comfy return LiteGraphSingleton.snaps_for_comfy
? this.linkConnector.state.snapLinksPos ?? ? this.linkConnector.state.snapLinksPos ??
this._highlight_pos ?? this._highlight_pos ??
this.graph_mouse this.graph_mouse
@@ -4872,7 +4873,7 @@ export class LGraphCanvas
const { linkConnector } = this const { linkConnector } = this
const { overReroute, overWidget } = linkConnector const { overReroute, overWidget } = linkConnector
if ( if (
!LiteGraph.snap_highlights_node || !LiteGraphSingleton.snap_highlights_node ||
!linkConnector.isConnecting || !linkConnector.isConnecting ||
linkConnectorSnap linkConnectorSnap
) )
@@ -4889,7 +4890,7 @@ export class LGraphCanvas
const area = node.boundingRect const area = node.boundingRect
const gap = 3 const gap = 3
const radius = LiteGraph.ROUND_RADIUS + gap const radius = LiteGraphSingleton.ROUND_RADIUS + gap
const x = area[0] - gap const x = area[0] - gap
const y = area[1] - gap const y = area[1] - gap
@@ -4937,7 +4938,7 @@ export class LGraphCanvas
const { const {
pos: [nodeX, nodeY] pos: [nodeX, nodeY]
} = node } = node
const height = LiteGraph.NODE_WIDGET_HEIGHT const height = LiteGraphSingleton.NODE_WIDGET_HEIGHT
if ( if (
overWidget.type.startsWith('custom') && overWidget.type.startsWith('custom') &&
computedHeight != null && computedHeight != null &&
@@ -4981,7 +4982,7 @@ export class LGraphCanvas
ctx.save() ctx.save()
ctx.translate(x, y) ctx.translate(x, y)
ctx.font = `10px ${LiteGraph.DEFAULT_FONT}` ctx.font = `10px ${LiteGraphSingleton.DEFAULT_FONT}`
ctx.fillStyle = '#888' ctx.fillStyle = '#888'
ctx.textAlign = 'left' ctx.textAlign = 'left'
if (this.graph) { if (this.graph) {
@@ -5160,7 +5161,7 @@ export class LGraphCanvas
// When Vue nodes mode is enabled, LiteGraph should not draw node chrome or widgets. // When Vue nodes mode is enabled, LiteGraph should not draw node chrome or widgets.
// We still need to keep slot metrics and layout in sync for hit-testing and links. // We still need to keep slot metrics and layout in sync for hit-testing and links.
// Interaction system changes coming later, chances are vue nodes mode will be mostly broken on land // Interaction system changes coming later, chances are vue nodes mode will be mostly broken on land
if (LiteGraph.vueNodesMode) { if (LiteGraphSingleton.vueNodesMode) {
// Prepare concrete slots and compute layout measures without rendering visuals. // Prepare concrete slots and compute layout measures without rendering visuals.
node._setConcreteSlots() node._setConcreteSlots()
if (!node.collapsed) { if (!node.collapsed) {
@@ -5177,7 +5178,7 @@ export class LGraphCanvas
ctx.globalAlpha = editor_alpha ctx.globalAlpha = editor_alpha
if (this.render_shadows && !low_quality) { if (this.render_shadows && !low_quality) {
ctx.shadowColor = LiteGraph.DEFAULT_SHADOW_COLOR ctx.shadowColor = LiteGraphSingleton.DEFAULT_SHADOW_COLOR
ctx.shadowOffsetX = 2 * this.ds.scale ctx.shadowOffsetX = 2 * this.ds.scale
ctx.shadowOffsetY = 2 * this.ds.scale ctx.shadowOffsetY = 2 * this.ds.scale
ctx.shadowBlur = 3 * this.ds.scale ctx.shadowBlur = 3 * this.ds.scale
@@ -5217,7 +5218,7 @@ export class LGraphCanvas
// Render title buttons (if not collapsed) // Render title buttons (if not collapsed)
if (node.title_buttons && !node.flags.collapsed) { if (node.title_buttons && !node.flags.collapsed) {
const title_height = LiteGraph.NODE_TITLE_HEIGHT const title_height = LiteGraphSingleton.NODE_TITLE_HEIGHT
let current_x = size[0] // Start flush with right edge let current_x = size[0] // Start flush with right edge
for (let i = 0; i < node.title_buttons.length; i++) { for (let i = 0; i < node.title_buttons.length; i++) {
@@ -5244,7 +5245,7 @@ export class LGraphCanvas
ctx.shadowColor = 'transparent' ctx.shadowColor = 'transparent'
// TODO: Legacy behaviour: onDrawForeground received ctx in this state // TODO: Legacy behaviour: onDrawForeground received ctx in this state
ctx.strokeStyle = LiteGraph.NODE_BOX_OUTLINE_COLOR ctx.strokeStyle = LiteGraphSingleton.NODE_BOX_OUTLINE_COLOR
// Draw Foreground // Draw Foreground
node.onDrawForeground?.(ctx, this, this.canvas) node.onDrawForeground?.(ctx, this, this.canvas)
@@ -5372,7 +5373,7 @@ export class LGraphCanvas
ctx.strokeStyle = fgcolor ctx.strokeStyle = fgcolor
ctx.fillStyle = bgcolor ctx.fillStyle = bgcolor
const title_height = LiteGraph.NODE_TITLE_HEIGHT const title_height = LiteGraphSingleton.NODE_TITLE_HEIGHT
const { low_quality } = this const { low_quality } = this
const { collapsed } = node.flags const { collapsed } = node.flags
@@ -5404,8 +5405,8 @@ export class LGraphCanvas
area[2], area[2],
area[3], area[3],
shape == RenderShape.CARD shape == RenderShape.CARD
? [LiteGraph.ROUND_RADIUS, LiteGraph.ROUND_RADIUS, 0, 0] ? [LiteGraphSingleton.ROUND_RADIUS, LiteGraphSingleton.ROUND_RADIUS, 0, 0]
: [LiteGraph.ROUND_RADIUS] : [LiteGraphSingleton.ROUND_RADIUS]
) )
} else if (shape == RenderShape.CIRCLE) { } else if (shape == RenderShape.CIRCLE) {
ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5, 0, Math.PI * 2) ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5, 0, Math.PI * 2)
@@ -5533,7 +5534,7 @@ export class LGraphCanvas
const visibleReroutes: Reroute[] = [] const visibleReroutes: Reroute[] = []
const now = LiteGraph.getTime() const now = LiteGraphSingleton.getTime()
const { visible_area } = this const { visible_area } = this
LGraphCanvas.#margin_area[0] = visible_area[0] - 20 LGraphCanvas.#margin_area[0] = visible_area[0] - 20
LGraphCanvas.#margin_area[1] = visible_area[1] - 20 LGraphCanvas.#margin_area[1] = visible_area[1] - 20
@@ -5560,7 +5561,7 @@ export class LGraphCanvas
const link = graph._links.get(link_id) const link = graph._links.get(link_id)
if (!link) continue if (!link) continue
const endPos: Point = LiteGraph.vueNodesMode // TODO: still use LG get pos if vue nodes is off until stable const endPos: Point = LiteGraphSingleton.vueNodesMode // TODO: still use LG get pos if vue nodes is off until stable
? getSlotPosition(node, i, true) ? getSlotPosition(node, i, true)
: node.getInputPos(i) : node.getInputPos(i)
@@ -5572,7 +5573,7 @@ export class LGraphCanvas
const startPos: Point = const startPos: Point =
outputId === -1 outputId === -1
? [start_node.pos[0] + 10, start_node.pos[1] + 10] ? [start_node.pos[0] + 10, start_node.pos[1] + 10]
: LiteGraph.vueNodesMode // TODO: still use LG get pos if vue nodes is off until stable : LiteGraphSingleton.vueNodesMode // TODO: still use LG get pos if vue nodes is off until stable
? getSlotPosition(start_node, outputId, false) ? getSlotPosition(start_node, outputId, false)
: start_node.getOutputPos(outputId) : start_node.getOutputPos(outputId)
@@ -5992,23 +5993,23 @@ export class LGraphCanvas
for (const node of visible_nodes) { for (const node of visible_nodes) {
ctx.fillStyle = 'black' ctx.fillStyle = 'black'
ctx.fillRect( ctx.fillRect(
node.pos[0] - LiteGraph.NODE_TITLE_HEIGHT, node.pos[0] - LiteGraphSingleton.NODE_TITLE_HEIGHT,
node.pos[1] - LiteGraph.NODE_TITLE_HEIGHT, node.pos[1] - LiteGraphSingleton.NODE_TITLE_HEIGHT,
LiteGraph.NODE_TITLE_HEIGHT, LiteGraphSingleton.NODE_TITLE_HEIGHT,
LiteGraph.NODE_TITLE_HEIGHT LiteGraphSingleton.NODE_TITLE_HEIGHT
) )
if (node.order == 0) { if (node.order == 0) {
ctx.strokeRect( ctx.strokeRect(
node.pos[0] - LiteGraph.NODE_TITLE_HEIGHT + 0.5, node.pos[0] - LiteGraphSingleton.NODE_TITLE_HEIGHT + 0.5,
node.pos[1] - LiteGraph.NODE_TITLE_HEIGHT + 0.5, node.pos[1] - LiteGraphSingleton.NODE_TITLE_HEIGHT + 0.5,
LiteGraph.NODE_TITLE_HEIGHT, LiteGraphSingleton.NODE_TITLE_HEIGHT,
LiteGraph.NODE_TITLE_HEIGHT LiteGraphSingleton.NODE_TITLE_HEIGHT
) )
} }
ctx.fillStyle = '#FFF' ctx.fillStyle = '#FFF'
ctx.fillText( ctx.fillText(
toString(node.order), toString(node.order),
node.pos[0] + LiteGraph.NODE_TITLE_HEIGHT * -0.5, node.pos[0] + LiteGraphSingleton.NODE_TITLE_HEIGHT * -0.5,
node.pos[1] - 6 node.pos[1] - 6
) )
} }
@@ -6107,7 +6108,7 @@ export class LGraphCanvas
const { origin_id, origin_slot } = segment const { origin_id, origin_slot } = segment
if (origin_id == null || origin_slot == null) { if (origin_id == null || origin_slot == null) {
new LiteGraph.ContextMenu<string>(['Link has no origin'], { new LiteGraphSingleton.ContextMenu<string>(['Link has no origin'], {
event: e, event: e,
title title
}) })
@@ -6119,7 +6120,7 @@ export class LGraphCanvas
const options = ['Add Node', 'Add Reroute', null, 'Delete', null] const options = ['Add Node', 'Add Reroute', null, 'Delete', null]
const menu = new LiteGraph.ContextMenu<string>(options, { const menu = new LiteGraphSingleton.ContextMenu<string>(options, {
event: e, event: e,
title, title,
callback: inner_clicked.bind(this) callback: inner_clicked.bind(this)
@@ -6282,10 +6283,10 @@ export class LGraphCanvas
} }
// check for defaults nodes for this slottype // check for defaults nodes for this slottype
const fromSlotType = slotX.type == LiteGraph.EVENT ? '_event_' : slotX.type const fromSlotType = slotX.type == LiteGraphSingleton.EVENT ? '_event_' : slotX.type
const slotTypesDefault = isFrom const slotTypesDefault = isFrom
? LiteGraph.slot_types_default_out ? LiteGraphSingleton.slot_types_default_out
: LiteGraph.slot_types_default_in : LiteGraphSingleton.slot_types_default_in
if (slotTypesDefault?.[fromSlotType]) { if (slotTypesDefault?.[fromSlotType]) {
// TODO: Remove "any" kludge // TODO: Remove "any" kludge
let nodeNewType: any = false let nodeNewType: any = false
@@ -6314,7 +6315,7 @@ export class LGraphCanvas
} }
// that.graph.beforeChange(); // that.graph.beforeChange();
const newNode = LiteGraph.createNode(nodeNewType) const newNode = LiteGraphSingleton.createNode(nodeNewType)
if (newNode) { if (newNode) {
// if is object pass options // if is object pass options
if (nodeNewOpts) { if (nodeNewOpts) {
@@ -6493,10 +6494,10 @@ export class LGraphCanvas
} }
// get defaults nodes for this slottype // get defaults nodes for this slottype
const fromSlotType = slotX.type == LiteGraph.EVENT ? '_event_' : slotX.type const fromSlotType = slotX.type == LiteGraphSingleton.EVENT ? '_event_' : slotX.type
const slotTypesDefault = isFrom const slotTypesDefault = isFrom
? LiteGraph.slot_types_default_out ? LiteGraphSingleton.slot_types_default_out
: LiteGraph.slot_types_default_in : LiteGraphSingleton.slot_types_default_in
if (slotTypesDefault?.[fromSlotType]) { if (slotTypesDefault?.[fromSlotType]) {
if (typeof slotTypesDefault[fromSlotType] == 'object') { if (typeof slotTypesDefault[fromSlotType] == 'object') {
for (const typeX in slotTypesDefault[fromSlotType]) { for (const typeX in slotTypesDefault[fromSlotType]) {
@@ -6508,7 +6509,7 @@ export class LGraphCanvas
} }
// build menu // build menu
const menu = new LiteGraph.ContextMenu<string>(options, { const menu = new LiteGraphSingleton.ContextMenu<string>(options, {
event: opts.e, event: opts.e,
extra: slotX, extra: slotX,
title: title:
@@ -6657,20 +6658,20 @@ export class LGraphCanvas
let dialogCloseTimer: number let dialogCloseTimer: number
let prevent_timeout = 0 let prevent_timeout = 0
LiteGraph.pointerListenerAdd(dialog, 'leave', function () { LiteGraphSingleton.pointerListenerAdd(dialog, 'leave', function () {
if (prevent_timeout) return if (prevent_timeout) return
if (LiteGraph.dialog_close_on_mouse_leave) { if (LiteGraphSingleton.dialog_close_on_mouse_leave) {
if (!dialog.is_modified && LiteGraph.dialog_close_on_mouse_leave) { if (!dialog.is_modified && LiteGraphSingleton.dialog_close_on_mouse_leave) {
// @ts-expect-error - setTimeout type // @ts-expect-error - setTimeout type
dialogCloseTimer = setTimeout( dialogCloseTimer = setTimeout(
dialog.close, dialog.close,
LiteGraph.dialog_close_on_mouse_leave_delay LiteGraphSingleton.dialog_close_on_mouse_leave_delay
) )
} }
} }
}) })
LiteGraph.pointerListenerAdd(dialog, 'enter', function () { LiteGraphSingleton.pointerListenerAdd(dialog, 'enter', function () {
if (LiteGraph.dialog_close_on_mouse_leave && dialogCloseTimer) if (LiteGraphSingleton.dialog_close_on_mouse_leave && dialogCloseTimer)
clearTimeout(dialogCloseTimer) clearTimeout(dialogCloseTimer)
}) })
const selInDia = dialog.querySelectorAll('select') const selInDia = dialog.querySelectorAll('select')
@@ -6779,7 +6780,7 @@ export class LGraphCanvas
node_to: null, node_to: null,
// TODO check for registered_slot_[in/out]_types not empty // TODO check for registered_slot_[in/out]_types not empty
// this will be checked for functionality enabled : filter on slot type, in and out // this will be checked for functionality enabled : filter on slot type, in and out
do_type_filter: LiteGraph.search_filter_enabled, do_type_filter: LiteGraphSingleton.search_filter_enabled,
// these are default: pass to set initially set values // these are default: pass to set initially set values
// @ts-expect-error Property missing from interface definition // @ts-expect-error Property missing from interface definition
@@ -6788,9 +6789,9 @@ export class LGraphCanvas
type_filter_out: false, type_filter_out: false,
show_general_if_none_on_typefilter: true, show_general_if_none_on_typefilter: true,
show_general_after_typefiltered: true, show_general_after_typefiltered: true,
hide_on_mouse_leave: LiteGraph.search_hide_on_mouse_leave, hide_on_mouse_leave: LiteGraphSingleton.search_hide_on_mouse_leave,
show_all_if_empty: true, show_all_if_empty: true,
show_all_on_open: LiteGraph.search_show_all_on_open show_all_on_open: LiteGraphSingleton.search_show_all_on_open
} }
Object.assign(options, searchOptions) Object.assign(options, searchOptions)
@@ -6851,7 +6852,7 @@ export class LGraphCanvas
// FIXME: Remove "any" kludge // FIXME: Remove "any" kludge
let prevent_timeout: any = false let prevent_timeout: any = false
let timeout_close: number | null = null let timeout_close: number | null = null
LiteGraph.pointerListenerAdd(dialog, 'enter', function () { LiteGraphSingleton.pointerListenerAdd(dialog, 'enter', function () {
if (timeout_close) { if (timeout_close) {
clearTimeout(timeout_close) clearTimeout(timeout_close)
timeout_close = null timeout_close = null
@@ -6946,12 +6947,12 @@ export class LGraphCanvas
// if should filter on type, load and fill selected and choose elements if passed // if should filter on type, load and fill selected and choose elements if passed
if (options.do_type_filter) { if (options.do_type_filter) {
if (selIn) { if (selIn) {
const aSlots = LiteGraph.slot_types_in const aSlots = LiteGraphSingleton.slot_types_in
const nSlots = aSlots.length const nSlots = aSlots.length
if ( if (
options.type_filter_in == LiteGraph.EVENT || options.type_filter_in == LiteGraphSingleton.EVENT ||
options.type_filter_in == LiteGraph.ACTION options.type_filter_in == LiteGraphSingleton.ACTION
) { ) {
options.type_filter_in = '_event_' options.type_filter_in = '_event_'
} }
@@ -6974,11 +6975,11 @@ export class LGraphCanvas
}) })
} }
if (selOut) { if (selOut) {
const aSlots = LiteGraph.slot_types_out const aSlots = LiteGraphSingleton.slot_types_out
if ( if (
options.type_filter_out == LiteGraph.EVENT || options.type_filter_out == LiteGraphSingleton.EVENT ||
options.type_filter_out == LiteGraph.ACTION options.type_filter_out == LiteGraphSingleton.ACTION
) { ) {
options.type_filter_out = '_event_' options.type_filter_out = '_event_'
} }
@@ -7037,7 +7038,7 @@ export class LGraphCanvas
if (!graphcanvas.graph) throw new NullGraphError() if (!graphcanvas.graph) throw new NullGraphError()
graphcanvas.graph.beforeChange() graphcanvas.graph.beforeChange()
const node = LiteGraph.createNode(name) const node = LiteGraphSingleton.createNode(name)
if (node) { if (node) {
node.pos = graphcanvas.convertEventToCanvasOffset(safeEvent) node.pos = graphcanvas.convertEventToCanvasOffset(safeEvent)
graphcanvas.graph.add(node, false) graphcanvas.graph.add(node, false)
@@ -7190,7 +7191,7 @@ export class LGraphCanvas
sOut = that.search_box.querySelector('.slot_out_type_filter') sOut = that.search_box.querySelector('.slot_out_type_filter')
} }
const keys = Object.keys(LiteGraph.registered_node_types) const keys = Object.keys(LiteGraphSingleton.registered_node_types)
const filtered = keys.filter((x) => inner_test_filter(x)) const filtered = keys.filter((x) => inner_test_filter(x))
for (const item of filtered) { for (const item of filtered) {
@@ -7210,7 +7211,7 @@ export class LGraphCanvas
// FIXME: Undeclared variable again // FIXME: Undeclared variable again
// @ts-expect-error Variable declared without type annotation // @ts-expect-error Variable declared without type annotation
filtered_extra = [] filtered_extra = []
for (const i in LiteGraph.registered_node_types) { for (const i in LiteGraphSingleton.registered_node_types) {
if ( if (
inner_test_filter(i, { inner_test_filter(i, {
inTypeOverride: sIn && sIn.value ? '*' : false, inTypeOverride: sIn && sIn.value ? '*' : false,
@@ -7240,7 +7241,7 @@ export class LGraphCanvas
) { ) {
// @ts-expect-error Variable declared without type annotation // @ts-expect-error Variable declared without type annotation
filtered_extra = [] filtered_extra = []
for (const i in LiteGraph.registered_node_types) { for (const i in LiteGraphSingleton.registered_node_types) {
if (inner_test_filter(i, { skipFilter: true })) if (inner_test_filter(i, { skipFilter: true }))
// @ts-expect-error Variable declared without type annotation // @ts-expect-error Variable declared without type annotation
filtered_extra.push(i) filtered_extra.push(i)
@@ -7271,7 +7272,7 @@ export class LGraphCanvas
outTypeOverride: false outTypeOverride: false
} }
const opts = Object.assign(optsDef, optsIn) const opts = Object.assign(optsDef, optsIn)
const ctor = LiteGraph.registered_node_types[type] const ctor = LiteGraphSingleton.registered_node_types[type]
if (filter && ctor.filter != filter) return false if (filter && ctor.filter != filter) return false
if ( if (
(!options.show_all_if_empty || str) && (!options.show_all_if_empty || str) &&
@@ -7288,18 +7289,18 @@ export class LGraphCanvas
let sV = let sV =
opts.inTypeOverride !== false ? opts.inTypeOverride : sIn.value opts.inTypeOverride !== false ? opts.inTypeOverride : sIn.value
// type is stored // type is stored
if (sIn && sV && LiteGraph.registered_slot_in_types[sV]?.nodes) { if (sIn && sV && LiteGraphSingleton.registered_slot_in_types[sV]?.nodes) {
const doesInc = const doesInc =
LiteGraph.registered_slot_in_types[sV].nodes.includes(sType) LiteGraphSingleton.registered_slot_in_types[sV].nodes.includes(sType)
if (doesInc === false) return false if (doesInc === false) return false
} }
sV = sOut.value sV = sOut.value
if (opts.outTypeOverride !== false) sV = opts.outTypeOverride if (opts.outTypeOverride !== false) sV = opts.outTypeOverride
// type is stored // type is stored
if (sOut && sV && LiteGraph.registered_slot_out_types[sV]?.nodes) { if (sOut && sV && LiteGraphSingleton.registered_slot_out_types[sV]?.nodes) {
const doesInc = const doesInc =
LiteGraph.registered_slot_out_types[sV].nodes.includes(sType) LiteGraphSingleton.registered_slot_out_types[sV].nodes.includes(sType)
if (doesInc === false) return false if (doesInc === false) return false
} }
} }
@@ -7311,7 +7312,7 @@ export class LGraphCanvas
const help = document.createElement('div') const help = document.createElement('div')
first ||= type first ||= type
const nodeType = LiteGraph.registered_node_types[type] const nodeType = LiteGraphSingleton.registered_node_types[type]
if (nodeType?.title) { if (nodeType?.title) {
help.textContent = nodeType?.title help.textContent = nodeType?.title
const typeEl = document.createElement('span') const typeEl = document.createElement('span')
@@ -7545,16 +7546,16 @@ export class LGraphCanvas
dialog.addEventListener('mouseleave', function () { dialog.addEventListener('mouseleave', function () {
if (prevent_timeout) return if (prevent_timeout) return
if (!dialog.is_modified && LiteGraph.dialog_close_on_mouse_leave) { if (!dialog.is_modified && LiteGraphSingleton.dialog_close_on_mouse_leave) {
// @ts-expect-error - setTimeout type // @ts-expect-error - setTimeout type
dialogCloseTimer = setTimeout( dialogCloseTimer = setTimeout(
dialog.close, dialog.close,
LiteGraph.dialog_close_on_mouse_leave_delay LiteGraphSingleton.dialog_close_on_mouse_leave_delay
) )
} }
}) })
dialog.addEventListener('mouseenter', function () { dialog.addEventListener('mouseenter', function () {
if (options.closeOnLeave || LiteGraph.dialog_close_on_mouse_leave) { if (options.closeOnLeave || LiteGraphSingleton.dialog_close_on_mouse_leave) {
if (dialogCloseTimer) clearTimeout(dialogCloseTimer) if (dialogCloseTimer) clearTimeout(dialogCloseTimer)
} }
}) })
@@ -7757,7 +7758,7 @@ export class LGraphCanvas
innerChange(propname, v) innerChange(propname, v)
return false return false
} }
new LiteGraph.ContextMenu( new LiteGraphSingleton.ContextMenu(
values, values,
{ {
event, event,
@@ -7840,8 +7841,8 @@ export class LGraphCanvas
if (typeof value !== 'string') if (typeof value !== 'string')
throw new TypeError('Attempting to set mode to non-string value.') throw new TypeError('Attempting to set mode to non-string value.')
const kV = Object.values(LiteGraph.NODE_MODES).indexOf(value) const kV = Object.values(LiteGraphSingleton.NODE_MODES).indexOf(value)
if (kV !== -1 && LiteGraph.NODE_MODES[kV]) { if (kV !== -1 && LiteGraphSingleton.NODE_MODES[kV]) {
node.changeMode(kV) node.changeMode(kV)
} else { } else {
console.warn(`unexpected mode: ${value}`) console.warn(`unexpected mode: ${value}`)
@@ -7872,12 +7873,12 @@ export class LGraphCanvas
panel.addWidget('string', 'Title', node.title, {}, fUpdate) panel.addWidget('string', 'Title', node.title, {}, fUpdate)
const mode = const mode =
node.mode == null ? undefined : LiteGraph.NODE_MODES[node.mode] node.mode == null ? undefined : LiteGraphSingleton.NODE_MODES[node.mode]
panel.addWidget( panel.addWidget(
'combo', 'combo',
'Mode', 'Mode',
mode, mode,
{ values: LiteGraph.NODE_MODES }, { values: LiteGraphSingleton.NODE_MODES },
fUpdate fUpdate
) )
@@ -8025,7 +8026,7 @@ export class LGraphCanvas
| IContextMenuValue<string | null> | IContextMenuValue<string | null>
| IContextMenuValue<INodeSlotContextItem> | IContextMenuValue<INodeSlotContextItem>
| IContextMenuValue<unknown, LGraphNode> | IContextMenuValue<unknown, LGraphNode>
| IContextMenuValue<(typeof LiteGraph.VALID_SHAPES)[number]> | IContextMenuValue<(typeof LiteGraphSingleton.VALID_SHAPES)[number]>
| null | null
)[] )[]
if (node.getMenuOptions) { if (node.getMenuOptions) {
@@ -8247,10 +8248,10 @@ export class LGraphCanvas
} }
// @ts-expect-error Slot type can be number and has number checks // @ts-expect-error Slot type can be number and has number checks
options.title = (slot.input ? slot.input.type : slot.output.type) || '*' options.title = (slot.input ? slot.input.type : slot.output.type) || '*'
if (slot.input && slot.input.type == LiteGraph.ACTION) if (slot.input && slot.input.type == LiteGraphSingleton.ACTION)
options.title = 'Action' options.title = 'Action'
if (slot.output && slot.output.type == LiteGraph.EVENT) if (slot.output && slot.output.type == LiteGraphSingleton.EVENT)
options.title = 'Event' options.title = 'Event'
} else { } else {
// on node // on node
@@ -8312,7 +8313,7 @@ export class LGraphCanvas
if (!menu_info) return if (!menu_info) return
// @ts-expect-error Remove param ref_window - unused // @ts-expect-error Remove param ref_window - unused
new LiteGraph.ContextMenu(menu_info, options, ref_window) new LiteGraphSingleton.ContextMenu(menu_info, options, ref_window)
const createDialog = (options: IDialogOptions) => const createDialog = (options: IDialogOptions) =>
this.createDialog( this.createDialog(

View File

@@ -13,7 +13,7 @@ import type {
Positionable, Positionable,
Size Size
} from './interfaces' } from './interfaces'
import { LiteGraph } from './litegraph' import { LiteGraphSingleton } from './LiteGraphSingleton'
import { import {
containsCentre, containsCentre,
containsRect, containsRect,
@@ -39,7 +39,7 @@ export class LGraphGroup implements Positionable, IPinnable, IColorable {
color?: string color?: string
title: string title: string
font?: string font?: string
font_size: number = LiteGraph.DEFAULT_GROUP_FONT || 24 font_size: number = LiteGraphSingleton.DEFAULT_GROUP_FONT || 24
_bounding: Float32Array = new Float32Array([ _bounding: Float32Array = new Float32Array([
10, 10,
10, 10,
@@ -170,7 +170,7 @@ export class LGraphGroup implements Positionable, IPinnable, IColorable {
*/ */
draw(graphCanvas: LGraphCanvas, ctx: CanvasRenderingContext2D): void { draw(graphCanvas: LGraphCanvas, ctx: CanvasRenderingContext2D): void {
const { padding, resizeLength, defaultColour } = LGraphGroup const { padding, resizeLength, defaultColour } = LGraphGroup
const font_size = this.font_size || LiteGraph.DEFAULT_GROUP_FONT_SIZE const font_size = this.font_size || LiteGraphSingleton.DEFAULT_GROUP_FONT_SIZE
const [x, y] = this._pos const [x, y] = this._pos
const [width, height] = this._size const [width, height] = this._size
@@ -201,7 +201,7 @@ export class LGraphGroup implements Positionable, IPinnable, IColorable {
ctx.fill() ctx.fill()
// Title // Title
ctx.font = `${font_size}px ${LiteGraph.GROUP_FONT}` ctx.font = `${font_size}px ${LiteGraphSingleton.GROUP_FONT}`
ctx.textAlign = 'left' ctx.textAlign = 'left'
ctx.fillText( ctx.fillText(
this.title + (this.pinned ? '📌' : ''), this.title + (this.pinned ? '📌' : ''),
@@ -209,7 +209,7 @@ export class LGraphGroup implements Positionable, IPinnable, IColorable {
y + font_size y + font_size
) )
if (LiteGraph.highlight_selected_group && this.selected) { if (LiteGraphSingleton.highlight_selected_group && this.selected) {
strokeShape(ctx, this._bounding, { strokeShape(ctx, this._bounding, {
title_height: this.titleHeight, title_height: this.titleHeight,
padding padding

View File

@@ -44,10 +44,10 @@ import type {
} from './interfaces' } from './interfaces'
import { import {
type LGraphNodeConstructor, type LGraphNodeConstructor,
LiteGraph,
type Subgraph, type Subgraph,
type SubgraphNode type SubgraphNode
} from './litegraph' } from './litegraph'
import { LiteGraphSingleton } from './LiteGraphSingleton'
import { import {
createBounds, createBounds,
isInRect, isInRect,
@@ -244,11 +244,11 @@ export class LGraphNode
* The font style used to render the node's title text. * The font style used to render the node's title text.
*/ */
get titleFontStyle(): string { get titleFontStyle(): string {
return `${LiteGraph.NODE_TEXT_SIZE}px ${LiteGraph.NODE_FONT}` return `${LiteGraphSingleton.NODE_TEXT_SIZE}px ${LiteGraphSingleton.NODE_FONT}`
} }
get innerFontStyle(): string { get innerFontStyle(): string {
return `normal ${LiteGraph.NODE_SUBTEXT_SIZE}px ${LiteGraph.NODE_FONT}` return `normal ${LiteGraphSingleton.NODE_SUBTEXT_SIZE}px ${LiteGraphSingleton.NODE_FONT}`
} }
get displayType(): string { get displayType(): string {
@@ -303,13 +303,13 @@ export class LGraphNode
/** The fg color used to render the node. */ /** The fg color used to render the node. */
get renderingColor(): string { get renderingColor(): string {
return this.color || this.constructor.color || LiteGraph.NODE_DEFAULT_COLOR return this.color || this.constructor.color || LiteGraphSingleton.NODE_DEFAULT_COLOR
} }
/** The bg color used to render the node. */ /** The bg color used to render the node. */
get renderingBgColor(): string { get renderingBgColor(): string {
return ( return (
this.bgcolor || this.constructor.bgcolor || LiteGraph.NODE_DEFAULT_BGCOLOR this.bgcolor || this.constructor.bgcolor || LiteGraphSingleton.NODE_DEFAULT_BGCOLOR
) )
} }
@@ -317,17 +317,17 @@ export class LGraphNode
get renderingBoxColor(): string { get renderingBoxColor(): string {
if (this.boxcolor) return this.boxcolor if (this.boxcolor) return this.boxcolor
if (LiteGraph.node_box_coloured_when_on) { if (LiteGraphSingleton.node_box_coloured_when_on) {
if (this.action_triggered) return '#FFF' if (this.action_triggered) return '#FFF'
if (this.execute_triggered) return '#AAA' if (this.execute_triggered) return '#AAA'
} }
if (LiteGraph.node_box_coloured_by_mode) { if (LiteGraphSingleton.node_box_coloured_by_mode) {
const modeColour = const modeColour =
LiteGraph.NODE_MODES_COLORS[this.mode ?? LGraphEventMode.ALWAYS] LiteGraphSingleton.NODE_MODES_COLORS[this.mode ?? LGraphEventMode.ALWAYS]
if (modeColour) return modeColour if (modeColour) return modeColour
} }
return LiteGraph.NODE_DEFAULT_BOXCOLOR return LiteGraphSingleton.NODE_DEFAULT_BOXCOLOR
} }
/** @inheritdoc {@link IColorable.setColorOption} */ /** @inheritdoc {@link IColorable.setColorOption} */
@@ -507,7 +507,7 @@ export class LGraphNode
* The shape of the node used for rendering. @see {@link RenderShape} * The shape of the node used for rendering. @see {@link RenderShape}
*/ */
get renderingShape(): RenderShape { get renderingShape(): RenderShape {
return this._shape || this.constructor.shape || LiteGraph.NODE_DEFAULT_SHAPE return this._shape || this.constructor.shape || LiteGraphSingleton.NODE_DEFAULT_SHAPE
} }
public get is_selected(): boolean | undefined { public get is_selected(): boolean | undefined {
@@ -720,7 +720,7 @@ export class LGraphNode
return { return {
padding: 12, padding: 12,
lineWidth: 10, lineWidth: 10,
color: LiteGraph.NODE_ERROR_COLOUR color: LiteGraphSingleton.NODE_ERROR_COLOUR
} }
} }
} }
@@ -734,10 +734,10 @@ export class LGraphNode
} }
constructor(title: string, type?: string) { constructor(title: string, type?: string) {
this.id = LiteGraph.use_uuids ? LiteGraph.uuidv4() : -1 this.id = LiteGraphSingleton.use_uuids ? LiteGraphSingleton.uuidv4() : -1
this.title = title || 'Unnamed' this.title = title || 'Unnamed'
this.type = type ?? '' this.type = type ?? ''
this.size = [LiteGraph.NODE_WIDTH, 60] this.size = [LiteGraphSingleton.NODE_WIDTH, 60]
this.pos = [10, 10] this.pos = [10, 10]
this.strokeStyles = { this.strokeStyles = {
error: this.#getErrorStrokeStyle, error: this.#getErrorStrokeStyle,
@@ -778,7 +778,7 @@ export class LGraphNode
this[j]?.configure(info[j]) this[j]?.configure(info[j])
} else { } else {
// @ts-expect-error #594 // @ts-expect-error #594
this[j] = LiteGraph.cloneObject(info[j], this[j]) this[j] = LiteGraphSingleton.cloneObject(info[j], this[j])
} }
} else { } else {
// value // value
@@ -863,7 +863,7 @@ export class LGraphNode
type: this.type, type: this.type,
pos: [this.pos[0], this.pos[1]], pos: [this.pos[0], this.pos[1]],
size: [this.size[0], this.size[1]], size: [this.size[0], this.size[1]],
flags: LiteGraph.cloneObject(this.flags), flags: LiteGraphSingleton.cloneObject(this.flags),
order: this.order, order: this.order,
mode: this.mode, mode: this.mode,
showAdvanced: this.showAdvanced showAdvanced: this.showAdvanced
@@ -881,7 +881,7 @@ export class LGraphNode
if (this.title && this.title != this.constructor.title) o.title = this.title if (this.title && this.title != this.constructor.title) o.title = this.title
if (this.properties) o.properties = LiteGraph.cloneObject(this.properties) if (this.properties) o.properties = LiteGraphSingleton.cloneObject(this.properties)
const { widgets } = this const { widgets } = this
if (widgets && this.serialize_widgets) { if (widgets && this.serialize_widgets) {
@@ -911,11 +911,11 @@ export class LGraphNode
/* Creates a clone of this node */ /* Creates a clone of this node */
clone(): LGraphNode | null { clone(): LGraphNode | null {
if (this.type == null) return null if (this.type == null) return null
const node = LiteGraph.createNode(this.type) const node = LiteGraphSingleton.createNode(this.type)
if (!node) return null if (!node) return null
// we clone it because serialize returns shared containers // we clone it because serialize returns shared containers
const data = LiteGraph.cloneObject(this.serialize()) const data = LiteGraphSingleton.cloneObject(this.serialize())
const { inputs, outputs } = data const { inputs, outputs } = data
// remove links // remove links
@@ -934,7 +934,7 @@ export class LGraphNode
// @ts-expect-error Exceptional case: id is removed so that the graph can assign a new one on add. // @ts-expect-error Exceptional case: id is removed so that the graph can assign a new one on add.
delete data.id delete data.id
if (LiteGraph.use_uuids) data.id = LiteGraph.uuidv4() if (LiteGraphSingleton.use_uuids) data.id = LiteGraphSingleton.uuidv4()
node.configure(data) node.configure(data)
@@ -1255,7 +1255,7 @@ export class LGraphNode
addOnTriggerInput(): number { addOnTriggerInput(): number {
const trigS = this.findInputSlot('onTrigger') const trigS = this.findInputSlot('onTrigger')
if (trigS == -1) { if (trigS == -1) {
this.addInput('onTrigger', LiteGraph.EVENT, { this.addInput('onTrigger', LiteGraphSingleton.EVENT, {
nameLocked: true nameLocked: true
}) })
return this.findInputSlot('onTrigger') return this.findInputSlot('onTrigger')
@@ -1266,7 +1266,7 @@ export class LGraphNode
addOnExecutedOutput(): number { addOnExecutedOutput(): number {
const trigS = this.findOutputSlot('onExecuted') const trigS = this.findOutputSlot('onExecuted')
if (trigS == -1) { if (trigS == -1) {
this.addOutput('onExecuted', LiteGraph.ACTION, { this.addOutput('onExecuted', LiteGraphSingleton.ACTION, {
nameLocked: true nameLocked: true
}) })
return this.findOutputSlot('onExecuted') return this.findOutputSlot('onExecuted')
@@ -1298,7 +1298,7 @@ export class LGraphNode
break break
// @ts-expect-error Not impl. // @ts-expect-error Not impl.
case LiteGraph.ON_REQUEST: case LiteGraphSingleton.ON_REQUEST:
break break
default: default:
@@ -1385,12 +1385,12 @@ export class LGraphNode
return return
} }
if (this.graph) this.graph._last_trigger_time = LiteGraph.getTime() if (this.graph) this.graph._last_trigger_time = LiteGraphSingleton.getTime()
for (const [i, output] of outputs.entries()) { for (const [i, output] of outputs.entries()) {
if ( if (
!output || !output ||
output.type !== LiteGraph.EVENT || output.type !== LiteGraphSingleton.EVENT ||
(action && output.name != action) (action && output.name != action)
) { ) {
continue continue
@@ -1430,7 +1430,7 @@ export class LGraphNode
if (!links || !links.length) return if (!links || !links.length) return
if (!this.graph) throw new NullGraphError() if (!this.graph) throw new NullGraphError()
this.graph._last_trigger_time = LiteGraph.getTime() this.graph._last_trigger_time = LiteGraphSingleton.getTime()
// for every link attached here // for every link attached here
for (const id of links) { for (const id of links) {
@@ -1441,7 +1441,7 @@ export class LGraphNode
// not connected // not connected
if (!link_info) continue if (!link_info) continue
link_info._last_time = LiteGraph.getTime() link_info._last_time = LiteGraphSingleton.getTime()
const node = this.graph.getNodeById(link_info.target_id) const node = this.graph.getNodeById(link_info.target_id)
// node not found? // node not found?
if (!node) continue if (!node) continue
@@ -1551,8 +1551,8 @@ export class LGraphNode
this.outputs.push(output) this.outputs.push(output)
this.onOutputAdded?.(output) this.onOutputAdded?.(output)
if (LiteGraph.auto_load_slot_types) if (LiteGraphSingleton.auto_load_slot_types)
LiteGraph.registerNodeAndSlotType(this, type, true) LiteGraphSingleton.registerNodeAndSlotType(this, type, true)
this.expandToFitContent() this.expandToFitContent()
this.setDirtyCanvas(true, true) this.setDirtyCanvas(true, true)
@@ -1609,7 +1609,7 @@ export class LGraphNode
this.expandToFitContent() this.expandToFitContent()
this.onInputAdded?.(input) this.onInputAdded?.(input)
LiteGraph.registerNodeAndSlotType(this, type) LiteGraphSingleton.registerNodeAndSlotType(this, type)
this.setDirtyCanvas(true, true) this.setDirtyCanvas(true, true)
return input return input
@@ -1656,9 +1656,9 @@ export class LGraphNode
const size = out || new Float32Array([0, 0]) const size = out || new Float32Array([0, 0])
rows = Math.max(rows, 1) rows = Math.max(rows, 1)
// although it should be graphcanvas.inner_text_font size // although it should be graphcanvas.inner_text_font size
const font_size = LiteGraph.NODE_TEXT_SIZE const font_size = LiteGraphSingleton.NODE_TEXT_SIZE
const padLeft = LiteGraph.NODE_TITLE_HEIGHT const padLeft = LiteGraphSingleton.NODE_TITLE_HEIGHT
const padRight = padLeft * 0.33 const padRight = padLeft * 0.33
const title_width = const title_width =
padLeft + compute_text_size(this.title, this.titleFontStyle) + padRight padLeft + compute_text_size(this.title, this.titleFontStyle) + padRight
@@ -1689,13 +1689,13 @@ export class LGraphNode
} }
} }
const minWidth = LiteGraph.NODE_WIDTH * (widgets?.length ? 1.5 : 1) const minWidth = LiteGraphSingleton.NODE_WIDTH * (widgets?.length ? 1.5 : 1)
// Text + slot width + centre padding // Text + slot width + centre padding
const centrePadding = input_width && output_width ? 5 : 0 const centrePadding = input_width && output_width ? 5 : 0
const slotsWidth = const slotsWidth =
input_width + input_width +
output_width + output_width +
2 * LiteGraph.NODE_SLOT_HEIGHT + 2 * LiteGraphSingleton.NODE_SLOT_HEIGHT +
centrePadding centrePadding
// Total distance from edge of node to the inner edge of the widget 'previous' arrow button // Total distance from edge of node to the inner edge of the widget 'previous' arrow button
@@ -1706,7 +1706,7 @@ export class LGraphNode
size[0] = Math.max(slotsWidth, widgetWidth, title_width, minWidth) size[0] = Math.max(slotsWidth, widgetWidth, title_width, minWidth)
size[1] = size[1] =
(this.constructor.slot_start_y || 0) + rows * LiteGraph.NODE_SLOT_HEIGHT (this.constructor.slot_start_y || 0) + rows * LiteGraphSingleton.NODE_SLOT_HEIGHT
// Get widget height & expand size if necessary // Get widget height & expand size if necessary
let widgets_height = 0 let widgets_height = 0
@@ -1725,7 +1725,7 @@ export class LGraphNode
widget_height += minHeight widget_height += minHeight
} else { } else {
widget_height += LiteGraph.NODE_WIDGET_HEIGHT widget_height += LiteGraphSingleton.NODE_WIDGET_HEIGHT
} }
widgets_height += widget_height + 4 widgets_height += widget_height + 4
} }
@@ -1758,7 +1758,7 @@ export class LGraphNode
inResizeCorner(canvasX: number, canvasY: number): boolean { inResizeCorner(canvasX: number, canvasY: number): boolean {
const rows = this.outputs ? this.outputs.length : 1 const rows = this.outputs ? this.outputs.length : 1
const outputs_offset = const outputs_offset =
(this.constructor.slot_start_y || 0) + rows * LiteGraph.NODE_SLOT_HEIGHT (this.constructor.slot_start_y || 0) + rows * LiteGraphSingleton.NODE_SLOT_HEIGHT
return isInRectangle( return isInRectangle(
canvasX, canvasX,
canvasY, canvasY,
@@ -1959,7 +1959,7 @@ export class LGraphNode
// If Vue nodes mode is enabled, skip LiteGraph's direct position update // If Vue nodes mode is enabled, skip LiteGraph's direct position update
// The layout store will handle the movement and sync back to LiteGraph // The layout store will handle the movement and sync back to LiteGraph
if (LiteGraph.vueNodesMode) { if (LiteGraphSingleton.vueNodesMode) {
// Vue nodes handle their own dragging through the layout store // Vue nodes handle their own dragging through the layout store
// This prevents the snap-back issue from conflicting position updates // This prevents the snap-back issue from conflicting position updates
return return
@@ -1983,7 +1983,7 @@ export class LGraphNode
const renderTitle = const renderTitle =
titleMode != TitleMode.TRANSPARENT_TITLE && titleMode != TitleMode.TRANSPARENT_TITLE &&
titleMode != TitleMode.NO_TITLE titleMode != TitleMode.NO_TITLE
const titleHeight = renderTitle ? LiteGraph.NODE_TITLE_HEIGHT : 0 const titleHeight = renderTitle ? LiteGraphSingleton.NODE_TITLE_HEIGHT : 0
out[0] = this.pos[0] out[0] = this.pos[0]
out[1] = this.pos[1] + -titleHeight out[1] = this.pos[1] + -titleHeight
@@ -1995,10 +1995,10 @@ export class LGraphNode
this._collapsed_width = Math.min( this._collapsed_width = Math.min(
this.size[0], this.size[0],
ctx.measureText(this.getTitle() ?? '').width + ctx.measureText(this.getTitle() ?? '').width +
LiteGraph.NODE_TITLE_HEIGHT * 2 LiteGraphSingleton.NODE_TITLE_HEIGHT * 2
) )
out[2] = this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH out[2] = this._collapsed_width || LiteGraphSingleton.NODE_COLLAPSED_WIDTH
out[3] = LiteGraph.NODE_TITLE_HEIGHT out[3] = LiteGraphSingleton.NODE_TITLE_HEIGHT
} }
} }
@@ -2055,7 +2055,7 @@ export class LGraphNode
* @returns true if the x,y point is in the collapse button area, otherwise false * @returns true if the x,y point is in the collapse button area, otherwise false
*/ */
isPointInCollapse(x: number, y: number): boolean { isPointInCollapse(x: number, y: number): boolean {
const squareLength = LiteGraph.NODE_TITLE_HEIGHT const squareLength = LiteGraphSingleton.NODE_TITLE_HEIGHT
return isInRectangle( return isInRectangle(
x, x,
y, y,
@@ -2158,7 +2158,7 @@ export class LGraphNode
const h = const h =
widget.computedHeight ?? widget.computedHeight ??
widget.computeSize?.(nodeWidth)[1] ?? widget.computeSize?.(nodeWidth)[1] ??
LiteGraph.NODE_WIDGET_HEIGHT LiteGraphSingleton.NODE_WIDGET_HEIGHT
const maybeDOMWidget = widget as { margin?: number } const maybeDOMWidget = widget as { margin?: number }
const mtop = maybeDOMWidget.margin ?? -2 const mtop = maybeDOMWidget.margin ?? -2
@@ -2439,10 +2439,10 @@ export class LGraphNode
for (const sourceType of sourceTypes) { for (const sourceType of sourceTypes) {
// TODO: Remove _event_ entirely. // TODO: Remove _event_ entirely.
const source = sourceType == '_event_' ? LiteGraph.EVENT : sourceType const source = sourceType == '_event_' ? LiteGraphSingleton.EVENT : sourceType
for (const destType of destTypes) { for (const destType of destTypes) {
const dest = destType == '_event_' ? LiteGraph.EVENT : destType const dest = destType == '_event_' ? LiteGraphSingleton.EVENT : destType
if (source == dest || source === '*' || dest === '*') { if (source == dest || source === '*' || dest === '*') {
if (preferFreeSlot && (slot.links?.length || slot.link != null)) { if (preferFreeSlot && (slot.links?.length || slot.link != null)) {
@@ -2502,9 +2502,9 @@ export class LGraphNode
if (slot >= 0 && slot !== null) return slot if (slot >= 0 && slot !== null) return slot
// TODO: Remove or reimpl. events. WILL CREATE THE onTrigger IN SLOT // TODO: Remove or reimpl. events. WILL CREATE THE onTrigger IN SLOT
if (opts.createEventInCase && slotType == LiteGraph.EVENT) { if (opts.createEventInCase && slotType == LiteGraphSingleton.EVENT) {
if (findInputs) return -1 if (findInputs) return -1
if (LiteGraph.do_add_triggers_slots) return node.addOnExecutedOutput() if (LiteGraphSingleton.do_add_triggers_slots) return node.addOnExecutedOutput()
} }
// connect to the first general output slot if not found a specific type and // connect to the first general output slot if not found a specific type and
@@ -2517,7 +2517,7 @@ export class LGraphNode
opts.wildcardToTyped && opts.wildcardToTyped &&
(slotType == 0 || slotType == '*' || slotType == '') (slotType == 0 || slotType == '*' || slotType == '')
) { ) {
const opt = { typesNotAccepted: [LiteGraph.EVENT] } const opt = { typesNotAccepted: [LiteGraphSingleton.EVENT] }
const nonEventSlot = findInputs const nonEventSlot = findInputs
? node.findInputSlotFree(opt) ? node.findInputSlotFree(opt)
: node.findOutputSlotFree(opt) : node.findOutputSlotFree(opt)
@@ -2637,7 +2637,7 @@ export class LGraphNode
) { ) {
return ( return (
this.id !== node.id && this.id !== node.id &&
LiteGraph.isValidConnection(fromSlot.type, toSlot.type) LiteGraphSingleton.isValidConnection(fromSlot.type, toSlot.type)
) )
} }
@@ -2671,12 +2671,12 @@ export class LGraphNode
if (typeof slot === 'string') { if (typeof slot === 'string') {
slot = this.findOutputSlot(slot) slot = this.findOutputSlot(slot)
if (slot == -1) { if (slot == -1) {
if (LiteGraph.debug) if (LiteGraphSingleton.debug)
console.log(`Connect: Error, no slot of name ${slot}`) console.log(`Connect: Error, no slot of name ${slot}`)
return null return null
} }
} else if (!outputs || slot >= outputs.length) { } else if (!outputs || slot >= outputs.length) {
if (LiteGraph.debug) console.log('Connect: Error, slot number not found') if (LiteGraphSingleton.debug) console.log('Connect: Error, slot number not found')
return null return null
} }
@@ -2695,13 +2695,13 @@ export class LGraphNode
if (typeof target_slot === 'string') { if (typeof target_slot === 'string') {
targetIndex = target_node.findInputSlot(target_slot) targetIndex = target_node.findInputSlot(target_slot)
if (targetIndex == -1) { if (targetIndex == -1) {
if (LiteGraph.debug) if (LiteGraphSingleton.debug)
console.log(`Connect: Error, no slot of name ${targetIndex}`) console.log(`Connect: Error, no slot of name ${targetIndex}`)
return null return null
} }
} else if (target_slot === LiteGraph.EVENT) { } else if (target_slot === LiteGraphSingleton.EVENT) {
// TODO: Events // TODO: Events
if (LiteGraph.do_add_triggers_slots) { if (LiteGraphSingleton.do_add_triggers_slots) {
target_node.changeMode(LGraphEventMode.ON_TRIGGER) target_node.changeMode(LGraphEventMode.ON_TRIGGER)
targetIndex = target_node.findInputSlot('onTrigger') targetIndex = target_node.findInputSlot('onTrigger')
} else { } else {
@@ -2728,7 +2728,7 @@ export class LGraphNode
!target_node.inputs || !target_node.inputs ||
targetIndex >= target_node.inputs.length targetIndex >= target_node.inputs.length
) { ) {
if (LiteGraph.debug) console.log('Connect: Error, slot number not found') if (LiteGraphSingleton.debug) console.log('Connect: Error, slot number not found')
return null return null
} }
@@ -2739,8 +2739,8 @@ export class LGraphNode
if (output.links?.length) { if (output.links?.length) {
if ( if (
output.type === LiteGraph.EVENT && output.type === LiteGraphSingleton.EVENT &&
!LiteGraph.allow_multi_output_for_events !LiteGraphSingleton.allow_multi_output_for_events
) { ) {
graph.beforeChange() graph.beforeChange()
// @ts-expect-error Unused param // @ts-expect-error Unused param
@@ -2783,7 +2783,7 @@ export class LGraphNode
} }
// check targetSlot and check connection types // check targetSlot and check connection types
if (!LiteGraph.isValidConnection(output.type, input.type)) { if (!LiteGraphSingleton.isValidConnection(output.type, input.type)) {
this.setDirtyCanvas(false, true) this.setDirtyCanvas(false, true)
return null return null
} }
@@ -2954,12 +2954,12 @@ export class LGraphNode
if (typeof slot === 'string') { if (typeof slot === 'string') {
slot = this.findOutputSlot(slot) slot = this.findOutputSlot(slot)
if (slot == -1) { if (slot == -1) {
if (LiteGraph.debug) if (LiteGraphSingleton.debug)
console.log(`Connect: Error, no slot of name ${slot}`) console.log(`Connect: Error, no slot of name ${slot}`)
return false return false
} }
} else if (!this.outputs || slot >= this.outputs.length) { } else if (!this.outputs || slot >= this.outputs.length) {
if (LiteGraph.debug) console.log('Connect: Error, slot number not found') if (LiteGraphSingleton.debug) console.log('Connect: Error, slot number not found')
return false return false
} }
@@ -3074,12 +3074,12 @@ export class LGraphNode
if (typeof slot === 'string') { if (typeof slot === 'string') {
slot = this.findInputSlot(slot) slot = this.findInputSlot(slot)
if (slot == -1) { if (slot == -1) {
if (LiteGraph.debug) if (LiteGraphSingleton.debug)
console.log(`Connect: Error, no slot of name ${slot}`) console.log(`Connect: Error, no slot of name ${slot}`)
return false return false
} }
} else if (!this.inputs || slot >= this.inputs.length) { } else if (!this.inputs || slot >= this.inputs.length) {
if (LiteGraph.debug) { if (LiteGraphSingleton.debug) {
console.log('Connect: Error, slot number not found') console.log('Connect: Error, slot number not found')
} }
return false return false
@@ -3183,16 +3183,16 @@ export class LGraphNode
} = this } = this
if (this.flags.collapsed) { if (this.flags.collapsed) {
const w = this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH const w = this._collapsed_width || LiteGraphSingleton.NODE_COLLAPSED_WIDTH
out[0] = is_input ? nodeX : nodeX + w out[0] = is_input ? nodeX : nodeX + w
out[1] = nodeY - LiteGraph.NODE_TITLE_HEIGHT * 0.5 out[1] = nodeY - LiteGraphSingleton.NODE_TITLE_HEIGHT * 0.5
return out return out
} }
// weird feature that never got finished // weird feature that never got finished
if (is_input && slot_number == -1) { if (is_input && slot_number == -1) {
out[0] = nodeX + LiteGraph.NODE_TITLE_HEIGHT * 0.5 out[0] = nodeX + LiteGraphSingleton.NODE_TITLE_HEIGHT * 0.5
out[1] = nodeY + LiteGraph.NODE_TITLE_HEIGHT * 0.5 out[1] = nodeY + LiteGraphSingleton.NODE_TITLE_HEIGHT * 0.5
return out return out
} }
@@ -3211,7 +3211,7 @@ export class LGraphNode
} }
// default vertical slots // default vertical slots
const offset = LiteGraph.NODE_SLOT_HEIGHT * 0.5 const offset = LiteGraphSingleton.NODE_SLOT_HEIGHT * 0.5
const slotIndex = is_input const slotIndex = is_input
? this.#defaultVerticalInputs.indexOf(this.inputs[slot_number]) ? this.#defaultVerticalInputs.indexOf(this.inputs[slot_number])
: this.#defaultVerticalOutputs.indexOf(this.outputs[slot_number]) : this.#defaultVerticalOutputs.indexOf(this.outputs[slot_number])
@@ -3219,7 +3219,7 @@ export class LGraphNode
out[0] = is_input ? nodeX + offset : nodeX + this.size[0] + 1 - offset out[0] = is_input ? nodeX + offset : nodeX + this.size[0] + 1 - offset
out[1] = out[1] =
nodeY + nodeY +
(slotIndex + 0.7) * LiteGraph.NODE_SLOT_HEIGHT + (slotIndex + 0.7) * LiteGraphSingleton.NODE_SLOT_HEIGHT +
(this.constructor.slot_start_y || 0) (this.constructor.slot_start_y || 0)
return out return out
} }
@@ -3297,7 +3297,7 @@ export class LGraphNode
/** @see {@link snapToGrid} */ /** @see {@link snapToGrid} */
alignToGrid(): void { alignToGrid(): void {
this.snapToGrid(LiteGraph.CANVAS_GRID_SIZE) this.snapToGrid(LiteGraphSingleton.CANVAS_GRID_SIZE)
} }
/* Console output */ /* Console output */
@@ -3321,7 +3321,7 @@ export class LGraphNode
} }
const img: AsyncImageElement = new Image() const img: AsyncImageElement = new Image()
img.src = LiteGraph.node_images_path + url img.src = LiteGraphSingleton.node_images_path + url
img.ready = false img.ready = false
const dirty = () => this.setDirtyCanvas(true) const dirty = () => this.setDirtyCanvas(true)
@@ -3416,7 +3416,7 @@ export class LGraphNode
get width() { get width() {
return this.collapsed return this.collapsed
? this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH ? this._collapsed_width || LiteGraphSingleton.NODE_COLLAPSED_WIDTH
: this.size[0] : this.size[0]
} }
@@ -3424,7 +3424,7 @@ export class LGraphNode
* Returns the height of the node, including the title bar. * Returns the height of the node, including the title bar.
*/ */
get height() { get height() {
return LiteGraph.NODE_TITLE_HEIGHT + this.bodyHeight return LiteGraphSingleton.NODE_TITLE_HEIGHT + this.bodyHeight
} }
/** /**
@@ -3447,7 +3447,7 @@ export class LGraphNode
(acc, badge) => acc + badge.getWidth(ctx) + gap, (acc, badge) => acc + badge.getWidth(ctx) + gap,
0 0
) )
const y = -(LiteGraph.NODE_TITLE_HEIGHT + gap) const y = -(LiteGraphSingleton.NODE_TITLE_HEIGHT + gap)
for (const badge of badgeInstances) { for (const badge of badgeInstances) {
badge.draw(ctx, currentX, y - badge.height) badge.draw(ctx, currentX, y - badge.height)
@@ -3462,7 +3462,7 @@ export class LGraphNode
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,
{ {
scale, scale,
title_height = LiteGraph.NODE_TITLE_HEIGHT, title_height = LiteGraphSingleton.NODE_TITLE_HEIGHT,
low_quality = false low_quality = false
}: DrawTitleOptions }: DrawTitleOptions
): void { ): void {
@@ -3480,7 +3480,7 @@ export class LGraphNode
} }
if (this.collapsed) { if (this.collapsed) {
ctx.shadowColor = LiteGraph.DEFAULT_SHADOW_COLOR ctx.shadowColor = LiteGraphSingleton.DEFAULT_SHADOW_COLOR
} }
ctx.fillStyle = this.constructor.title_color || fgcolor ctx.fillStyle = this.constructor.title_color || fgcolor
@@ -3495,8 +3495,8 @@ export class LGraphNode
size[0], size[0],
title_height, title_height,
this.collapsed this.collapsed
? [LiteGraph.ROUND_RADIUS] ? [LiteGraphSingleton.ROUND_RADIUS]
: [LiteGraph.ROUND_RADIUS, LiteGraph.ROUND_RADIUS, 0, 0] : [LiteGraphSingleton.ROUND_RADIUS, LiteGraphSingleton.ROUND_RADIUS, 0, 0]
) )
} }
ctx.fill() ctx.fill()
@@ -3513,7 +3513,7 @@ export class LGraphNode
{ {
scale, scale,
low_quality = false, low_quality = false,
title_height = LiteGraph.NODE_TITLE_HEIGHT, title_height = LiteGraphSingleton.NODE_TITLE_HEIGHT,
box_size = 10 box_size = 10
}: DrawTitleBoxOptions }: DrawTitleBoxOptions
): void { ): void {
@@ -3589,7 +3589,7 @@ export class LGraphNode
scale, scale,
default_title_color, default_title_color,
low_quality = false, low_quality = false,
title_height = LiteGraph.NODE_TITLE_HEIGHT title_height = LiteGraphSingleton.NODE_TITLE_HEIGHT
}: DrawTitleTextOptions }: DrawTitleTextOptions
): void { ): void {
const size = this.renderingSize const size = this.renderingSize
@@ -3617,7 +3617,7 @@ export class LGraphNode
const title = String(rawTitle) + (this.pinned ? '📌' : '') const title = String(rawTitle) + (this.pinned ? '📌' : '')
if (title) { if (title) {
if (selected) { if (selected) {
ctx.fillStyle = LiteGraph.NODE_SELECTED_TITLE_COLOR ctx.fillStyle = LiteGraphSingleton.NODE_SELECTED_TITLE_COLOR
} else { } else {
ctx.fillStyle = this.constructor.title_text_color || default_title_color ctx.fillStyle = this.constructor.title_text_color || default_title_color
} }
@@ -3656,7 +3656,7 @@ export class LGraphNode
ctx.fillText( ctx.fillText(
displayTitle, displayTitle,
title_height, title_height,
LiteGraph.NODE_TITLE_TEXT_Y - title_height LiteGraphSingleton.NODE_TITLE_TEXT_Y - title_height
) )
} }
} }
@@ -3689,7 +3689,7 @@ export class LGraphNode
if (input.link == null) continue if (input.link == null) continue
const output = outputs[index] const output = outputs[index]
if (!output || !LiteGraph.isValidConnection(input.type, output.type)) if (!output || !LiteGraphSingleton.isValidConnection(input.type, output.type))
continue continue
const inLink = _links.get(input.link) const inLink = _links.get(input.link)
@@ -3713,7 +3713,7 @@ export class LGraphNode
if (!inNode) continue if (!inNode) continue
for (const output of outputs) { for (const output of outputs) {
if (!LiteGraph.isValidConnection(input.type, output.type)) continue if (!LiteGraphSingleton.isValidConnection(input.type, output.type)) continue
bypassAllLinks(output, inNode, inLink, graph) bypassAllLinks(output, inNode, inLink, graph)
break break
@@ -3764,7 +3764,7 @@ export class LGraphNode
const nodeWidth = this.size[0] const nodeWidth = this.size[0]
const { widgets } = this const { widgets } = this
const H = LiteGraph.NODE_WIDGET_HEIGHT const H = LiteGraphSingleton.NODE_WIDGET_HEIGHT
const showText = !lowQuality const showText = !lowQuality
ctx.save() ctx.save()
ctx.globalAlpha = editorAlpha ctx.globalAlpha = editorAlpha
@@ -3774,8 +3774,8 @@ export class LGraphNode
const { y } = widget const { y } = widget
const outlineColour = widget.advanced const outlineColour = widget.advanced
? LiteGraph.WIDGET_ADVANCED_OUTLINE_COLOR ? LiteGraphSingleton.WIDGET_ADVANCED_OUTLINE_COLOR
: LiteGraph.WIDGET_OUTLINE_COLOR : LiteGraphSingleton.WIDGET_OUTLINE_COLOR
widget.last_y = y widget.last_y = y
// Disable widget if it is disabled or if the value is passed from socket connection. // Disable widget if it is disabled or if the value is passed from socket connection.
@@ -3833,12 +3833,12 @@ export class LGraphNode
? this.getInputPos(slotIndex) ? this.getInputPos(slotIndex)
: this.getOutputPos(slotIndex) : this.getOutputPos(slotIndex)
slot.boundingRect[0] = pos[0] - LiteGraph.NODE_SLOT_HEIGHT * 0.5 slot.boundingRect[0] = pos[0] - LiteGraphSingleton.NODE_SLOT_HEIGHT * 0.5
slot.boundingRect[1] = pos[1] - LiteGraph.NODE_SLOT_HEIGHT * 0.5 slot.boundingRect[1] = pos[1] - LiteGraphSingleton.NODE_SLOT_HEIGHT * 0.5
slot.boundingRect[2] = slot.isWidgetInputSlot slot.boundingRect[2] = slot.isWidgetInputSlot
? BaseWidget.margin ? BaseWidget.margin
: LiteGraph.NODE_SLOT_HEIGHT : LiteGraphSingleton.NODE_SLOT_HEIGHT
slot.boundingRect[3] = LiteGraph.NODE_SLOT_HEIGHT slot.boundingRect[3] = LiteGraphSingleton.NODE_SLOT_HEIGHT
} }
#measureSlots(): ReadOnlyRect | null { #measureSlots(): ReadOnlyRect | null {
@@ -3973,7 +3973,7 @@ export class LGraphNode
w w
}) })
} else { } else {
const height = LiteGraph.NODE_WIDGET_HEIGHT + 4 const height = LiteGraphSingleton.NODE_WIDGET_HEIGHT + 4
w.computedHeight = height w.computedHeight = height
fixedWidgetHeight += height fixedWidgetHeight += height
} }
@@ -4036,13 +4036,13 @@ export class LGraphNode
// Only set custom pos if not using Vue positioning // Only set custom pos if not using Vue positioning
// Vue positioning calculates widget slot positions dynamically // Vue positioning calculates widget slot positions dynamically
if (!LiteGraph.vueNodesMode) { if (!LiteGraphSingleton.vueNodesMode) {
for (const widget of this.widgets) { for (const widget of this.widgets) {
const slot = slotByWidgetName.get(widget.name) const slot = slotByWidgetName.get(widget.name)
if (!slot) continue if (!slot) continue
const actualSlot = this.#concreteInputs[slot.index] const actualSlot = this.#concreteInputs[slot.index]
const offset = LiteGraph.NODE_SLOT_HEIGHT * 0.5 const offset = LiteGraphSingleton.NODE_SLOT_HEIGHT * 0.5
actualSlot.pos = [offset, widget.y + offset] actualSlot.pos = [offset, widget.y + offset]
this.#measureSlot(actualSlot, slot.index, true) this.#measureSlot(actualSlot, slot.index, true)
} }

View File

@@ -0,0 +1,4 @@
import { LiteGraphGlobal } from './LiteGraphGlobal';
export const LiteGraphSingleton = new LiteGraphGlobal();

View File

@@ -1,6 +1,6 @@
import type { Rectangle } from './infrastructure/Rectangle' import type { Rectangle } from './infrastructure/Rectangle'
import type { CanvasColour, Rect } from './interfaces' import type { CanvasColour, Rect } from './interfaces'
import { LiteGraph } from './litegraph' import { LiteGraphSingleton } from './LiteGraphSingleton'
import { RenderShape, TitleMode } from './types/globalEnums' import { RenderShape, TitleMode } from './types/globalEnums'
const ELLIPSIS = '\u2026' const ELLIPSIS = '\u2026'
@@ -80,12 +80,12 @@ export function strokeShape(
}: IDrawBoundingOptions = {} }: IDrawBoundingOptions = {}
): void { ): void {
// These param defaults are not compile-time static, and must be re-evaluated at runtime // These param defaults are not compile-time static, and must be re-evaluated at runtime
round_radius ??= LiteGraph.ROUND_RADIUS round_radius ??= LiteGraphSingleton.ROUND_RADIUS
color ??= LiteGraph.NODE_BOX_OUTLINE_COLOR color ??= LiteGraphSingleton.NODE_BOX_OUTLINE_COLOR
// Adjust area if title is transparent // Adjust area if title is transparent
if (title_mode === TitleMode.TRANSPARENT_TITLE) { if (title_mode === TitleMode.TRANSPARENT_TITLE) {
const height = title_height ?? LiteGraph.NODE_TITLE_HEIGHT const height = title_height ?? LiteGraphSingleton.NODE_TITLE_HEIGHT
area[1] -= height area[1] -= height
area[3] += height area[3] += height
} }

View File

@@ -1,6 +1,6 @@
import type { ContextMenu } from './ContextMenu' import type { ContextMenu } from './ContextMenu'
import type { LGraphNode } from './LGraphNode' import type { LGraphNode } from './LGraphNode'
import { LiteGraphGlobal } from './LiteGraphGlobal' import { LiteGraphSingleton } from './LiteGraphSingleton'
import type { ConnectingLink, Point } from './interfaces' import type { ConnectingLink, Point } from './interfaces'
import type { IContextMenuOptions, Size } from './interfaces' import type { IContextMenuOptions, Size } from './interfaces'
import { loadPolyfills } from './polyfills' import { loadPolyfills } from './polyfills'
@@ -10,7 +10,7 @@ import type { RenderShape, TitleMode } from './types/globalEnums'
// Must remain above LiteGraphGlobal (circular dependency due to abstract factory behaviour in `configure`) // Must remain above LiteGraphGlobal (circular dependency due to abstract factory behaviour in `configure`)
export { Subgraph } from './subgraph/Subgraph' export { Subgraph } from './subgraph/Subgraph'
export const LiteGraph = new LiteGraphGlobal() export const LiteGraph = LiteGraphSingleton
// Load legacy polyfills // Load legacy polyfills
loadPolyfills() loadPolyfills()

View File

@@ -7,7 +7,7 @@ import type {
OptionalProps, OptionalProps,
ReadOnlyPoint ReadOnlyPoint
} from '@/lib/litegraph/src/interfaces' } from '@/lib/litegraph/src/interfaces'
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../LiteGraphSingleton'
import { type IDrawOptions, NodeSlot } from '@/lib/litegraph/src/node/NodeSlot' import { type IDrawOptions, NodeSlot } from '@/lib/litegraph/src/node/NodeSlot'
import type { SubgraphInput } from '@/lib/litegraph/src/subgraph/SubgraphInput' import type { SubgraphInput } from '@/lib/litegraph/src/subgraph/SubgraphInput'
import type { SubgraphOutput } from '@/lib/litegraph/src/subgraph/SubgraphOutput' import type { SubgraphOutput } from '@/lib/litegraph/src/subgraph/SubgraphOutput'
@@ -33,7 +33,7 @@ export class NodeInputSlot extends NodeSlot implements INodeInputSlot {
} }
get collapsedPos(): ReadOnlyPoint { get collapsedPos(): ReadOnlyPoint {
return [0, LiteGraph.NODE_TITLE_HEIGHT * -0.5] return [0, LiteGraphSingleton.NODE_TITLE_HEIGHT * -0.5]
} }
constructor( constructor(
@@ -52,11 +52,11 @@ export class NodeInputSlot extends NodeSlot implements INodeInputSlot {
fromSlot: INodeInputSlot | INodeOutputSlot | SubgraphInput | SubgraphOutput fromSlot: INodeInputSlot | INodeOutputSlot | SubgraphInput | SubgraphOutput
): boolean { ): boolean {
if ('links' in fromSlot) { if ('links' in fromSlot) {
return LiteGraph.isValidConnection(fromSlot.type, this.type) return LiteGraphSingleton.isValidConnection(fromSlot.type, this.type)
} }
if (isSubgraphInput(fromSlot)) { if (isSubgraphInput(fromSlot)) {
return LiteGraph.isValidConnection(fromSlot.type, this.type) return LiteGraphSingleton.isValidConnection(fromSlot.type, this.type)
} }
return false return false

View File

@@ -7,7 +7,7 @@ import type {
OptionalProps, OptionalProps,
ReadOnlyPoint ReadOnlyPoint
} from '@/lib/litegraph/src/interfaces' } from '@/lib/litegraph/src/interfaces'
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../LiteGraphSingleton'
import { type IDrawOptions, NodeSlot } from '@/lib/litegraph/src/node/NodeSlot' import { type IDrawOptions, NodeSlot } from '@/lib/litegraph/src/node/NodeSlot'
import type { SubgraphInput } from '@/lib/litegraph/src/subgraph/SubgraphInput' import type { SubgraphInput } from '@/lib/litegraph/src/subgraph/SubgraphInput'
import type { SubgraphOutput } from '@/lib/litegraph/src/subgraph/SubgraphOutput' import type { SubgraphOutput } from '@/lib/litegraph/src/subgraph/SubgraphOutput'
@@ -26,8 +26,8 @@ export class NodeOutputSlot extends NodeSlot implements INodeOutputSlot {
get collapsedPos(): ReadOnlyPoint { get collapsedPos(): ReadOnlyPoint {
return [ return [
this.#node._collapsed_width ?? LiteGraph.NODE_COLLAPSED_WIDTH, this.#node._collapsed_width ?? LiteGraphSingleton.NODE_COLLAPSED_WIDTH,
LiteGraph.NODE_TITLE_HEIGHT * -0.5 LiteGraphSingleton.NODE_TITLE_HEIGHT * -0.5
] ]
} }
@@ -46,11 +46,11 @@ export class NodeOutputSlot extends NodeSlot implements INodeOutputSlot {
fromSlot: INodeInputSlot | INodeOutputSlot | SubgraphInput | SubgraphOutput fromSlot: INodeInputSlot | INodeOutputSlot | SubgraphInput | SubgraphOutput
): boolean { ): boolean {
if ('link' in fromSlot) { if ('link' in fromSlot) {
return LiteGraph.isValidConnection(this.type, fromSlot.type) return LiteGraphSingleton.isValidConnection(this.type, fromSlot.type)
} }
if (isSubgraphOutput(fromSlot)) { if (isSubgraphOutput(fromSlot)) {
return LiteGraph.isValidConnection(this.type, fromSlot.type) return LiteGraphSingleton.isValidConnection(this.type, fromSlot.type)
} }
return false return false

View File

@@ -11,7 +11,8 @@ import type {
Point, Point,
ReadOnlyPoint ReadOnlyPoint
} from '@/lib/litegraph/src/interfaces' } from '@/lib/litegraph/src/interfaces'
import { LiteGraph, Rectangle } from '@/lib/litegraph/src/litegraph' import { Rectangle } from '@/lib/litegraph/src/litegraph'
import { LiteGraphSingleton } from '../LiteGraphSingleton'
import { getCentre } from '@/lib/litegraph/src/measure' import { getCentre } from '@/lib/litegraph/src/measure'
import type { SubgraphInput } from '@/lib/litegraph/src/subgraph/SubgraphInput' import type { SubgraphInput } from '@/lib/litegraph/src/subgraph/SubgraphInput'
import type { SubgraphOutput } from '@/lib/litegraph/src/subgraph/SubgraphOutput' import type { SubgraphOutput } from '@/lib/litegraph/src/subgraph/SubgraphOutput'
@@ -61,9 +62,9 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot {
get highlightColor(): CanvasColour { get highlightColor(): CanvasColour {
return ( return (
LiteGraph.NODE_TEXT_HIGHLIGHT_COLOR ?? LiteGraphSingleton.NODE_TEXT_HIGHLIGHT_COLOR ??
LiteGraph.NODE_SELECTED_TITLE_COLOR ?? LiteGraphSingleton.NODE_SELECTED_TITLE_COLOR ??
LiteGraph.NODE_TEXT_COLOR LiteGraphSingleton.NODE_TEXT_COLOR
) )
} }
@@ -123,7 +124,7 @@ export abstract class NodeSlot extends SlotBase implements INodeSlot {
const labelColor = highlight const labelColor = highlight
? this.highlightColor ? this.highlightColor
: LiteGraph.NODE_TEXT_COLOR : LiteGraphSingleton.NODE_TEXT_COLOR
const pos = this.#centreOffset const pos = this.#centreOffset
const slot_type = this.type const slot_type = this.type

View File

@@ -9,7 +9,8 @@ import type {
CallbackReturn, CallbackReturn,
ISlotType ISlotType
} from '@/lib/litegraph/src/interfaces' } from '@/lib/litegraph/src/interfaces'
import { LGraphEventMode, LiteGraph } from '@/lib/litegraph/src/litegraph' import { LGraphEventMode } from '@/lib/litegraph/src/litegraph'
import { LiteGraphSingleton } from '../LiteGraphSingleton'
import { Subgraph } from './Subgraph' import { Subgraph } from './Subgraph'
import type { SubgraphNode } from './SubgraphNode' import type { SubgraphNode } from './SubgraphNode'
@@ -346,8 +347,8 @@ export class ExecutableNodeDTO implements ExecutableLGraphNode {
// Prefer input with the same slot ID // Prefer input with the same slot ID
if ( if (
oppositeInput && oppositeInput &&
LiteGraph.isValidConnection(oppositeInput.type, outputType) && LiteGraphSingleton.isValidConnection(oppositeInput.type, outputType) &&
LiteGraph.isValidConnection(oppositeInput.type, type) LiteGraphSingleton.isValidConnection(oppositeInput.type, type)
) { ) {
return slot return slot
} }
@@ -359,8 +360,8 @@ export class ExecutableNodeDTO implements ExecutableLGraphNode {
// Find first matching slot - prefer exact type // Find first matching slot - prefer exact type
return inputs.findIndex( return inputs.findIndex(
(input) => (input) =>
LiteGraph.isValidConnection(input.type, outputType) && LiteGraphSingleton.isValidConnection(input.type, outputType) &&
LiteGraph.isValidConnection(input.type, type) LiteGraphSingleton.isValidConnection(input.type, type)
) )
} }

View File

@@ -13,9 +13,8 @@ import {
type CanvasColour, type CanvasColour,
type CanvasPointer, type CanvasPointer,
type CanvasPointerEvent, type CanvasPointerEvent,
type IContextMenuValue, type IContextMenuValue} from '@/lib/litegraph/src/litegraph'
LiteGraph import { LiteGraphSingleton } from '../LiteGraphSingleton'
} from '@/lib/litegraph/src/litegraph'
import { snapPoint } from '@/lib/litegraph/src/measure' import { snapPoint } from '@/lib/litegraph/src/measure'
import { CanvasItem } from '@/lib/litegraph/src/types/globalEnums' import { CanvasItem } from '@/lib/litegraph/src/types/globalEnums'
import type { import type {
@@ -194,7 +193,7 @@ export abstract class SubgraphIONodeBase<
const options: (IContextMenuValue | null)[] = this.#getSlotMenuOptions(slot) const options: (IContextMenuValue | null)[] = this.#getSlotMenuOptions(slot)
if (!(options.length > 0)) return if (!(options.length > 0)) return
new LiteGraph.ContextMenu(options, { new LiteGraphSingleton.ContextMenu(options, {
event: event as any, event: event as any,
title: slot.name || 'Subgraph Output', title: slot.name || 'Subgraph Output',
callback: (item: IContextMenuValue) => { callback: (item: IContextMenuValue) => {

View File

@@ -9,7 +9,7 @@ import type {
Point, Point,
ReadOnlyRect ReadOnlyRect
} from '@/lib/litegraph/src/interfaces' } from '@/lib/litegraph/src/interfaces'
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../LiteGraphSingleton'
import { NodeSlotType } from '@/lib/litegraph/src/types/globalEnums' import { NodeSlotType } from '@/lib/litegraph/src/types/globalEnums'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets' import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
@@ -237,12 +237,12 @@ export class SubgraphInput extends SubgraphSlot {
if (isNodeSlot(fromSlot)) { if (isNodeSlot(fromSlot)) {
return ( return (
'link' in fromSlot && 'link' in fromSlot &&
LiteGraph.isValidConnection(this.type, fromSlot.type) LiteGraphSingleton.isValidConnection(this.type, fromSlot.type)
) )
} }
if (isSubgraphOutput(fromSlot)) { if (isSubgraphOutput(fromSlot)) {
return LiteGraph.isValidConnection(this.type, fromSlot.type) return LiteGraphSingleton.isValidConnection(this.type, fromSlot.type)
} }
return false return false

View File

@@ -9,7 +9,7 @@ import type {
Point, Point,
ReadOnlyRect ReadOnlyRect
} from '@/lib/litegraph/src/interfaces' } from '@/lib/litegraph/src/interfaces'
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../LiteGraphSingleton'
import { NodeSlotType } from '@/lib/litegraph/src/types/globalEnums' import { NodeSlotType } from '@/lib/litegraph/src/types/globalEnums'
import type { SubgraphInput } from './SubgraphInput' import type { SubgraphInput } from './SubgraphInput'
@@ -39,7 +39,7 @@ export class SubgraphOutput extends SubgraphSlot {
const { subgraph } = this.parent const { subgraph } = this.parent
// Validate type compatibility // Validate type compatibility
if (!LiteGraph.isValidConnection(slot.type, this.type)) return if (!LiteGraphSingleton.isValidConnection(slot.type, this.type)) return
// Allow nodes to block connection // Allow nodes to block connection
const outputIndex = node.outputs.indexOf(slot) const outputIndex = node.outputs.indexOf(slot)
@@ -143,12 +143,12 @@ export class SubgraphOutput extends SubgraphSlot {
if (isNodeSlot(fromSlot)) { if (isNodeSlot(fromSlot)) {
return ( return (
'links' in fromSlot && 'links' in fromSlot &&
LiteGraph.isValidConnection(fromSlot.type, this.type) LiteGraphSingleton.isValidConnection(fromSlot.type, this.type)
) )
} }
if (isSubgraphInput(fromSlot)) { if (isSubgraphInput(fromSlot)) {
return LiteGraph.isValidConnection(fromSlot.type, this.type) return LiteGraphSingleton.isValidConnection(fromSlot.type, this.type)
} }
return false return false

View File

@@ -14,7 +14,7 @@ import type {
ReadOnlyRect, ReadOnlyRect,
ReadOnlySize ReadOnlySize
} from '@/lib/litegraph/src/interfaces' } from '@/lib/litegraph/src/interfaces'
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../LiteGraphSingleton'
import { SlotBase } from '@/lib/litegraph/src/node/SlotBase' import { SlotBase } from '@/lib/litegraph/src/node/SlotBase'
import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events' import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events'
import type { import type {
@@ -42,7 +42,7 @@ export abstract class SubgraphSlot
implements SubgraphIO, Hoverable, Serialisable<SubgraphIO> implements SubgraphIO, Hoverable, Serialisable<SubgraphIO>
{ {
static get defaultHeight() { static get defaultHeight() {
return LiteGraph.NODE_SLOT_HEIGHT return LiteGraphSingleton.NODE_SLOT_HEIGHT
} }
readonly #pos: Point = new Float32Array(2) readonly #pos: Point = new Float32Array(2)
@@ -228,7 +228,7 @@ export abstract class SubgraphSlot
if (this.displayName) { if (this.displayName) {
const [labelX, labelY] = this.labelPos const [labelX, labelY] = this.labelPos
// Also apply highlight logic to text color // Also apply highlight logic to text color
ctx.fillStyle = highlight ? 'white' : LiteGraph.NODE_TEXT_COLOR || '#AAA' ctx.fillStyle = highlight ? 'white' : LiteGraphSingleton.NODE_TEXT_COLOR || '#AAA'
ctx.fillText(this.displayName, labelX, labelY) ctx.fillText(this.displayName, labelX, labelY)
} }

View File

@@ -12,7 +12,8 @@ import type {
INodeOutputSlot, INodeOutputSlot,
Positionable Positionable
} from '@/lib/litegraph/src/interfaces' } from '@/lib/litegraph/src/interfaces'
import { LiteGraph, createUuidv4 } from '@/lib/litegraph/src/litegraph' import { createUuidv4 } from '@/lib/litegraph/src/litegraph'
import { LiteGraphSingleton } from '../LiteGraphSingleton'
import { nextUniqueName } from '@/lib/litegraph/src/strings' import { nextUniqueName } from '@/lib/litegraph/src/strings'
import type { import type {
ISerialisedNode, ISerialisedNode,
@@ -217,14 +218,14 @@ export function multiClone(nodes: Iterable<LGraphNode>): ISerialisedNode[] {
// Selectively clone - keep IDs & links // Selectively clone - keep IDs & links
for (const node of nodes) { for (const node of nodes) {
const newNode = LiteGraph.createNode(node.type) const newNode = LiteGraphSingleton.createNode(node.type)
if (!newNode) { if (!newNode) {
console.warn('Failed to create node', node.type) console.warn('Failed to create node', node.type)
continue continue
} }
// Must be cloned; litegraph "serialize" is mostly shallow clone // Must be cloned; litegraph "serialize" is mostly shallow clone
const data = LiteGraph.cloneObject(node.serialize()) const data = LiteGraphSingleton.cloneObject(node.serialize())
newNode.configure(data) newNode.configure(data)
clonedNodes.push(newNode.serialize()) clonedNodes.push(newNode.serialize())

View File

@@ -15,7 +15,7 @@ import type {
Point, Point,
Size Size
} from '../interfaces' } from '../interfaces'
import type { LiteGraph } from '../litegraph' import type { LiteGraphSingleton } from '../LiteGraphSingleton'
import type { TWidgetValue } from '../types/widgets' import type { TWidgetValue } from '../types/widgets'
import type { RenderShape } from './globalEnums' import type { RenderShape } from './globalEnums'
@@ -124,7 +124,7 @@ export interface ISerialisedGraph extends BaseExportedGraph {
links: SerialisedLLinkArray[] links: SerialisedLLinkArray[]
floatingLinks?: SerialisableLLink[] floatingLinks?: SerialisableLLink[]
groups: ISerialisedGroup[] groups: ISerialisedGroup[]
version: typeof LiteGraph.VERSION version: typeof LiteGraphSingleton.VERSION
extra?: LGraphExtra extra?: LGraphExtra
} }

View File

@@ -1,4 +1,4 @@
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../LiteGraphSingleton'
/** Guard against unbound allocation. */ /** Guard against unbound allocation. */
const UNIQUE_MESSAGE_LIMIT = 10_000 const UNIQUE_MESSAGE_LIMIT = 10_000
@@ -11,7 +11,7 @@ const sentWarnings: Set<string> = new Set()
* @param source A reference object to include alongside the message, e.g. `this`. * @param source A reference object to include alongside the message, e.g. `this`.
*/ */
export function warnDeprecated(message: string, source?: object): void { export function warnDeprecated(message: string, source?: object): void {
if (!LiteGraph.alwaysRepeatWarnings) { if (!LiteGraphSingleton.alwaysRepeatWarnings) {
// Do not repeat // Do not repeat
if (sentWarnings.has(message)) return if (sentWarnings.has(message)) return
@@ -21,7 +21,7 @@ export function warnDeprecated(message: string, source?: object): void {
sentWarnings.add(message) sentWarnings.add(message)
} }
for (const callback of LiteGraph.onDeprecationWarning) { for (const callback of LiteGraphSingleton.onDeprecationWarning) {
callback(message, source) callback(message, source)
} }
} }

View File

@@ -7,7 +7,7 @@ import type {
LGraphNode, LGraphNode,
Size Size
} from '@/lib/litegraph/src/litegraph' } from '@/lib/litegraph/src/litegraph'
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../LiteGraphSingleton'
import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events' import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets' import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
@@ -147,28 +147,28 @@ export abstract class BaseWidget<TWidget extends IBaseWidget = IBaseWidget>
get outline_color() { get outline_color() {
return this.advanced return this.advanced
? LiteGraph.WIDGET_ADVANCED_OUTLINE_COLOR ? LiteGraphSingleton.WIDGET_ADVANCED_OUTLINE_COLOR
: LiteGraph.WIDGET_OUTLINE_COLOR : LiteGraphSingleton.WIDGET_OUTLINE_COLOR
} }
get background_color() { get background_color() {
return LiteGraph.WIDGET_BGCOLOR return LiteGraphSingleton.WIDGET_BGCOLOR
} }
get height() { get height() {
return LiteGraph.NODE_WIDGET_HEIGHT return LiteGraphSingleton.NODE_WIDGET_HEIGHT
} }
get text_color() { get text_color() {
return LiteGraph.WIDGET_TEXT_COLOR return LiteGraphSingleton.WIDGET_TEXT_COLOR
} }
get secondary_text_color() { get secondary_text_color() {
return LiteGraph.WIDGET_SECONDARY_TEXT_COLOR return LiteGraphSingleton.WIDGET_SECONDARY_TEXT_COLOR
} }
get disabledTextColor() { get disabledTextColor() {
return LiteGraph.WIDGET_DISABLED_TEXT_COLOR return LiteGraphSingleton.WIDGET_DISABLED_TEXT_COLOR
} }
get displayName() { get displayName() {
@@ -255,7 +255,7 @@ export abstract class BaseWidget<TWidget extends IBaseWidget = IBaseWidget>
if (requiredWidth <= totalWidth) { if (requiredWidth <= totalWidth) {
// Draw label & value normally // Draw label & value normally
drawTextInArea({ ctx, text: displayName, area, align: 'left' }) drawTextInArea({ ctx, text: displayName, area, align: 'left' })
} else if (LiteGraph.truncateWidgetTextEvenly) { } else if (LiteGraphSingleton.truncateWidgetTextEvenly) {
// Label + value will not fit - scale evenly to fit // Label + value will not fit - scale evenly to fit
const scale = (totalWidth - gap) / (requiredWidth - gap) const scale = (totalWidth - gap) / (requiredWidth - gap)
area.width = labelWidth * scale area.width = labelWidth * scale
@@ -265,7 +265,7 @@ export abstract class BaseWidget<TWidget extends IBaseWidget = IBaseWidget>
// Move the area to the right to render the value // Move the area to the right to render the value
area.right = x + totalWidth area.right = x + totalWidth
area.setWidthRightAnchored(valueWidth * scale) area.setWidthRightAnchored(valueWidth * scale)
} else if (LiteGraph.truncateWidgetValuesFirst) { } else if (LiteGraphSingleton.truncateWidgetValuesFirst) {
// Label + value will not fit - use legacy scaling of value first // Label + value will not fit - use legacy scaling of value first
const cappedLabelWidth = Math.min(labelWidth, totalWidth) const cappedLabelWidth = Math.min(labelWidth, totalWidth)

View File

@@ -1,7 +1,7 @@
import { clamp } from 'es-toolkit/compat' import { clamp } from 'es-toolkit/compat'
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode' import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../LiteGraphSingleton'
import type { import type {
IComboWidget, IComboWidget,
IStringComboWidget IStringComboWidget
@@ -133,7 +133,7 @@ export class ComboWidget
// Handle center click - show dropdown menu // Handle center click - show dropdown menu
const text_values = values != values_list ? Object.values(values) : values const text_values = values != values_list ? Object.values(values) : values
new LiteGraph.ContextMenu(text_values, { new LiteGraphSingleton.ContextMenu(text_values, {
scale: Math.max(1, canvas.ds.scale), scale: Math.max(1, canvas.ds.scale),
event: e, event: e,
className: 'dark', className: 'dark',

View File

@@ -1,5 +1,5 @@
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode' import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../LiteGraphSingleton'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets' import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
import { BaseWidget, type DrawWidgetOptions } from './BaseWidget' import { BaseWidget, type DrawWidgetOptions } from './BaseWidget'
@@ -27,7 +27,7 @@ export class LegacyWidget<TWidget extends IBaseWidget = IBaseWidget>
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,
options: DrawWidgetOptions options: DrawWidgetOptions
) { ) {
const H = LiteGraph.NODE_WIDGET_HEIGHT const H = LiteGraphSingleton.NODE_WIDGET_HEIGHT
this.draw?.(ctx, this.node, options.width, this.y, H, !!options.showText) this.draw?.(ctx, this.node, options.width, this.y, H, !!options.showText)
} }

View File

@@ -1,6 +1,7 @@
import { describe } from 'vitest' import { describe } from 'vitest'
import { LGraph, LiteGraph } from '@/lib/litegraph/src/litegraph' import { LGraph } from '@/lib/litegraph/src/litegraph'
import { LiteGraphSingleton } from '../src/LiteGraphSingleton'
import { test } from './testExtensions' import { test } from './testExtensions'
@@ -17,8 +18,8 @@ describe('LGraph', () => {
const directImport = await import('@/lib/litegraph/src/LGraph') const directImport = await import('@/lib/litegraph/src/LGraph')
const entryPointImport = await import('@/lib/litegraph/src/litegraph') const entryPointImport = await import('@/lib/litegraph/src/litegraph')
expect(LiteGraph.LGraph).toBe(directImport.LGraph) expect(LiteGraphSingleton.LGraph).toBe(directImport.LGraph)
expect(LiteGraph.LGraph).toBe(entryPointImport.LGraph) expect(LiteGraphSingleton.LGraph).toBe(entryPointImport.LGraph)
}) })
test('populates optional values', ({ expect, minimalSerialisableGraph }) => { test('populates optional values', ({ expect, minimalSerialisableGraph }) => {
@@ -139,6 +140,6 @@ describe('Legacy LGraph Compatibility Layer', () => {
}) })
test('is correctly assigned to LiteGraph', ({ expect }) => { test('is correctly assigned to LiteGraph', ({ expect }) => {
expect(LiteGraph.LGraph).toBe(LGraph) expect(LiteGraphSingleton.LGraph).toBe(LGraph)
}) })
}) })

View File

@@ -1,7 +1,8 @@
import { beforeEach, describe, expect, it, vi } from 'vitest' import { beforeEach, describe, expect, it, vi } from 'vitest'
import { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas' import { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas'
import { LGraphNode, LiteGraph } from '@/lib/litegraph/src/litegraph' import { LGraphNode } from '@/lib/litegraph/src/litegraph'
import { LiteGraphSingleton } from '../src/LiteGraphSingleton'
describe('LGraphCanvas Title Button Rendering', () => { describe('LGraphCanvas Title Button Rendering', () => {
let canvas: LGraphCanvas let canvas: LGraphCanvas
@@ -115,7 +116,7 @@ describe('LGraphCanvas Title Button Rendering', () => {
// Check draw positions (right-aligned from node width) // Check draw positions (right-aligned from node width)
// First button (rightmost): 200 - 5 = 195, then subtract width // First button (rightmost): 200 - 5 = 195, then subtract width
// Second button: first button position - 5 - button width // Second button: first button position - 5 - button width
const titleHeight = LiteGraph.NODE_TITLE_HEIGHT const titleHeight = LiteGraphSingleton.NODE_TITLE_HEIGHT
const buttonY = -titleHeight + (titleHeight - 20) / 2 // Centered const buttonY = -titleHeight + (titleHeight - 20) / 2 // Centered
expect(draw1).toHaveBeenCalledWith(ctx, 180, buttonY) // 200 - 20 expect(draw1).toHaveBeenCalledWith(ctx, 180, buttonY) // 200 - 20
expect(draw2).toHaveBeenCalledWith(ctx, 153, buttonY) // 180 - 2 - 25 expect(draw2).toHaveBeenCalledWith(ctx, 153, buttonY) // 180 - 2 - 25
@@ -180,7 +181,7 @@ describe('LGraphCanvas Title Button Rendering', () => {
canvas.drawNode(node, ctx) canvas.drawNode(node, ctx)
const titleHeight = LiteGraph.NODE_TITLE_HEIGHT const titleHeight = LiteGraphSingleton.NODE_TITLE_HEIGHT
// Check positions are correctly spaced (right to left) // Check positions are correctly spaced (right to left)
// Starting position: 200 // Starting position: 200
@@ -209,7 +210,7 @@ describe('LGraphCanvas Title Button Rendering', () => {
// Buttons should still be rendered in low quality mode // Buttons should still be rendered in low quality mode
const buttonY = const buttonY =
-LiteGraph.NODE_TITLE_HEIGHT + (LiteGraph.NODE_TITLE_HEIGHT - 20) / 2 -LiteGraphSingleton.NODE_TITLE_HEIGHT + (LiteGraphSingleton.NODE_TITLE_HEIGHT - 20) / 2
expect(drawSpy).toHaveBeenCalledWith(ctx, 180, buttonY) expect(drawSpy).toHaveBeenCalledWith(ctx, 180, buttonY)
}) })
@@ -236,7 +237,7 @@ describe('LGraphCanvas Title Button Rendering', () => {
canvas.drawNode(node, ctx) canvas.drawNode(node, ctx)
const titleHeight = LiteGraph.NODE_TITLE_HEIGHT const titleHeight = LiteGraphSingleton.NODE_TITLE_HEIGHT
// Small button (rightmost): 200 - 15 = 185 // Small button (rightmost): 200 - 15 = 185
const buttonY = -titleHeight + (titleHeight - 20) / 2 const buttonY = -titleHeight + (titleHeight - 20) / 2
@@ -263,7 +264,7 @@ describe('LGraphCanvas Title Button Rendering', () => {
canvas.drawNode(node, ctx) canvas.drawNode(node, ctx)
const titleHeight = LiteGraph.NODE_TITLE_HEIGHT const titleHeight = LiteGraphSingleton.NODE_TITLE_HEIGHT
// Should use new width: 300 - 20 = 280 // Should use new width: 300 - 20 = 280
const buttonY = -titleHeight + (titleHeight - 20) / 2 const buttonY = -titleHeight + (titleHeight - 20) / 2
expect(drawSpy).toHaveBeenCalledWith(ctx, 280, buttonY) expect(drawSpy).toHaveBeenCalledWith(ctx, 280, buttonY)

View File

@@ -1,6 +1,7 @@
import { beforeEach, describe, expect } from 'vitest' import { beforeEach, describe, expect } from 'vitest'
import { LGraphNode, LiteGraph } from '@/lib/litegraph/src/litegraph' import { LGraphNode } from '@/lib/litegraph/src/litegraph'
import { LiteGraphSingleton } from '../src/LiteGraphSingleton'
import { test } from './testExtensions' import { test } from './testExtensions'
@@ -9,7 +10,7 @@ describe('LGraphNode resize functionality', () => {
beforeEach(() => { beforeEach(() => {
// Set up LiteGraph constants needed for measure // Set up LiteGraph constants needed for measure
LiteGraph.NODE_TITLE_HEIGHT = 20 LiteGraphSingleton.NODE_TITLE_HEIGHT = 20
node = new LGraphNode('Test Node') node = new LGraphNode('Test Node')
node.pos = [100, 100] node.pos = [100, 100]

View File

@@ -1,7 +1,8 @@
import { afterEach, beforeEach, describe, expect, vi } from 'vitest' import { afterEach, beforeEach, describe, expect, vi } from 'vitest'
import type { INodeInputSlot, Point } from '@/lib/litegraph/src/interfaces' import type { INodeInputSlot, Point } from '@/lib/litegraph/src/interfaces'
import { LGraphNode, LiteGraph } from '@/lib/litegraph/src/litegraph' import { LGraphNode } from '@/lib/litegraph/src/litegraph'
import { LiteGraphSingleton } from '../src/LiteGraphSingleton'
import { LGraph } from '@/lib/litegraph/src/litegraph' import { LGraph } from '@/lib/litegraph/src/litegraph'
import { NodeInputSlot } from '@/lib/litegraph/src/node/NodeInputSlot' import { NodeInputSlot } from '@/lib/litegraph/src/node/NodeInputSlot'
import { NodeOutputSlot } from '@/lib/litegraph/src/node/NodeOutputSlot' import { NodeOutputSlot } from '@/lib/litegraph/src/node/NodeOutputSlot'
@@ -28,14 +29,14 @@ function getMockISerialisedNode(
describe('LGraphNode', () => { describe('LGraphNode', () => {
let node: LGraphNode let node: LGraphNode
let origLiteGraph: typeof LiteGraph let origLiteGraph: typeof LiteGraphSingleton
beforeEach(() => { beforeEach(() => {
origLiteGraph = Object.assign({}, LiteGraph) origLiteGraph = Object.assign({}, LiteGraphSingleton)
// @ts-expect-error TODO: Fix after merge - Classes property not in type // @ts-expect-error TODO: Fix after merge - Classes property not in type
delete origLiteGraph.Classes delete origLiteGraph.Classes
Object.assign(LiteGraph, { Object.assign(LiteGraphSingleton, {
NODE_TITLE_HEIGHT: 20, NODE_TITLE_HEIGHT: 20,
NODE_SLOT_HEIGHT: 15, NODE_SLOT_HEIGHT: 15,
NODE_TEXT_SIZE: 14, NODE_TEXT_SIZE: 14,
@@ -52,7 +53,7 @@ describe('LGraphNode', () => {
}) })
afterEach(() => { afterEach(() => {
Object.assign(LiteGraph, origLiteGraph) Object.assign(LiteGraphSingleton, origLiteGraph)
}) })
test('should serialize position/size correctly', () => { test('should serialize position/size correctly', () => {
@@ -460,8 +461,8 @@ describe('LGraphNode', () => {
node.addOutput('output2', 'number') node.addOutput('output2', 'number')
// Calculate expected positions // Calculate expected positions
const slotOffset = LiteGraph.NODE_SLOT_HEIGHT * 0.5 const slotOffset = LiteGraphSingleton.NODE_SLOT_HEIGHT * 0.5
const slotSpacing = LiteGraph.NODE_SLOT_HEIGHT const slotSpacing = LiteGraphSingleton.NODE_SLOT_HEIGHT
const nodeWidth = node.size[0] const nodeWidth = node.size[0]
// Test input positions // Test input positions
@@ -496,8 +497,8 @@ describe('LGraphNode', () => {
node.addInput('default-input1', 'number') node.addInput('default-input1', 'number')
node.addInput('default-input2', 'number') node.addInput('default-input2', 'number')
const slotOffset = LiteGraph.NODE_SLOT_HEIGHT * 0.5 const slotOffset = LiteGraphSingleton.NODE_SLOT_HEIGHT * 0.5
const slotSpacing = LiteGraph.NODE_SLOT_HEIGHT const slotSpacing = LiteGraphSingleton.NODE_SLOT_HEIGHT
// Test: default positioned slots should be consecutive, ignoring absolute positioned ones // Test: default positioned slots should be consecutive, ignoring absolute positioned ones
expect(node.getInputPos(1)).toEqual([ expect(node.getInputPos(1)).toEqual([
@@ -576,7 +577,7 @@ describe('LGraphNode', () => {
}) })
test('should return position based on title height when collapsed', () => { test('should return position based on title height when collapsed', () => {
node.flags.collapsed = true node.flags.collapsed = true
const expectedPos: Point = [100, 200 - LiteGraph.NODE_TITLE_HEIGHT * 0.5] const expectedPos: Point = [100, 200 - LiteGraphSingleton.NODE_TITLE_HEIGHT * 0.5]
expect(node.getInputSlotPos(inputSlot)).toEqual(expectedPos) expect(node.getInputSlotPos(inputSlot)).toEqual(expectedPos)
}) })
@@ -600,12 +601,12 @@ describe('LGraphNode', () => {
const slotIndex = 0 const slotIndex = 0
const nodeOffsetY = (node.constructor as any).slot_start_y || 0 const nodeOffsetY = (node.constructor as any).slot_start_y || 0
const expectedY = const expectedY =
200 + (slotIndex + 0.7) * LiteGraph.NODE_SLOT_HEIGHT + nodeOffsetY 200 + (slotIndex + 0.7) * LiteGraphSingleton.NODE_SLOT_HEIGHT + nodeOffsetY
const expectedX = 100 + LiteGraph.NODE_SLOT_HEIGHT * 0.5 const expectedX = 100 + LiteGraphSingleton.NODE_SLOT_HEIGHT * 0.5
expect(node.getInputSlotPos(inputSlot)).toEqual([expectedX, expectedY]) expect(node.getInputSlotPos(inputSlot)).toEqual([expectedX, expectedY])
const slotIndex2 = 1 const slotIndex2 = 1
const expectedY2 = const expectedY2 =
200 + (slotIndex2 + 0.7) * LiteGraph.NODE_SLOT_HEIGHT + nodeOffsetY 200 + (slotIndex2 + 0.7) * LiteGraphSingleton.NODE_SLOT_HEIGHT + nodeOffsetY
expect(node.getInputSlotPos(inputSlot2)).toEqual([expectedX, expectedY2]) expect(node.getInputSlotPos(inputSlot2)).toEqual([expectedX, expectedY2])
}) })
@@ -616,8 +617,8 @@ describe('LGraphNode', () => {
const slotIndex = 0 const slotIndex = 0
const nodeOffsetY = 25 const nodeOffsetY = 25
const expectedY = const expectedY =
200 + (slotIndex + 0.7) * LiteGraph.NODE_SLOT_HEIGHT + nodeOffsetY 200 + (slotIndex + 0.7) * LiteGraphSingleton.NODE_SLOT_HEIGHT + nodeOffsetY
const expectedX = 100 + LiteGraph.NODE_SLOT_HEIGHT * 0.5 const expectedX = 100 + LiteGraphSingleton.NODE_SLOT_HEIGHT * 0.5
expect(node.getInputSlotPos(inputSlot)).toEqual([expectedX, expectedY]) expect(node.getInputSlotPos(inputSlot)).toEqual([expectedX, expectedY])
delete (node.constructor as any).slot_start_y delete (node.constructor as any).slot_start_y
}) })
@@ -650,8 +651,8 @@ describe('LGraphNode', () => {
const slotIndex = 0 const slotIndex = 0
const nodeOffsetY = (node.constructor as any).slot_start_y || 0 const nodeOffsetY = (node.constructor as any).slot_start_y || 0
const expectedDefaultY = const expectedDefaultY =
200 + (slotIndex + 0.7) * LiteGraph.NODE_SLOT_HEIGHT + nodeOffsetY 200 + (slotIndex + 0.7) * LiteGraphSingleton.NODE_SLOT_HEIGHT + nodeOffsetY
const expectedDefaultX = 100 + LiteGraph.NODE_SLOT_HEIGHT * 0.5 const expectedDefaultX = 100 + LiteGraphSingleton.NODE_SLOT_HEIGHT * 0.5
expect(node.getInputPos(0)).toEqual([expectedDefaultX, expectedDefaultY]) expect(node.getInputPos(0)).toEqual([expectedDefaultX, expectedDefaultY])
spy.mockRestore() spy.mockRestore()
}) })
@@ -660,7 +661,7 @@ describe('LGraphNode', () => {
describe('removeInput/removeOutput on copied nodes', () => { describe('removeInput/removeOutput on copied nodes', () => {
beforeEach(() => { beforeEach(() => {
// Register a test node type so clone() can work // Register a test node type so clone() can work
LiteGraph.registerNodeType('TestNode', LGraphNode) LiteGraphSingleton.registerNodeType('TestNode', LGraphNode)
}) })
test('should NOT throw error when calling removeInput on a copied node without graph', () => { test('should NOT throw error when calling removeInput on a copied node without graph', () => {

View File

@@ -2,14 +2,15 @@ import { clamp } from 'es-toolkit/compat'
import { beforeEach, describe, expect, vi } from 'vitest' import { beforeEach, describe, expect, vi } from 'vitest'
import { LiteGraphGlobal } from '@/lib/litegraph/src/LiteGraphGlobal' import { LiteGraphGlobal } from '@/lib/litegraph/src/LiteGraphGlobal'
import { LGraphCanvas, LiteGraph } from '@/lib/litegraph/src/litegraph' import { LGraphCanvas } from '@/lib/litegraph/src/litegraph'
import { LiteGraphSingleton } from '../src/LiteGraphSingleton'
import { test } from './testExtensions' import { test } from './testExtensions'
describe('Litegraph module', () => { describe('Litegraph module', () => {
test('contains a global export', ({ expect }) => { test('contains a global export', ({ expect }) => {
expect(LiteGraph).toBeInstanceOf(LiteGraphGlobal) expect(LiteGraphSingleton).toBeInstanceOf(LiteGraphGlobal)
expect(LiteGraph.LGraphCanvas).toBe(LGraphCanvas) expect(LiteGraphSingleton.LGraphCanvas).toBe(LGraphCanvas)
}) })
test('has the same structure', ({ expect }) => { test('has the same structure', ({ expect }) => {
@@ -36,8 +37,8 @@ describe('Import order dependency', () => {
const directImport = await import('@/lib/litegraph/src/LGraph') const directImport = await import('@/lib/litegraph/src/LGraph')
// Sanity check that imports were cleared. // Sanity check that imports were cleared.
expect(Object.is(LiteGraph, entryPointImport.LiteGraph)).toBe(false) expect(Object.is(LiteGraphSingleton, entryPointImport.LiteGraphSingleton)).toBe(false)
expect(Object.is(LiteGraph.LGraph, directImport.LGraph)).toBe(false) expect(Object.is(LiteGraphSingleton.LGraph, directImport.LGraph)).toBe(false)
} }
await expect(importNormally()).resolves.toBeUndefined() await expect(importNormally()).resolves.toBeUndefined()

View File

@@ -4,9 +4,8 @@ import type { ISlotType } from '@/lib/litegraph/src/litegraph'
import { import {
LGraph, LGraph,
LGraphGroup, LGraphGroup,
LGraphNode, LGraphNode} from '@/lib/litegraph/src/litegraph'
LiteGraph import { LiteGraphSingleton } from '../../src/LiteGraphSingleton'
} from '@/lib/litegraph/src/litegraph'
import { import {
createTestSubgraph, createTestSubgraph,
@@ -20,7 +19,7 @@ function createNode(
title?: string title?: string
) { ) {
const type = JSON.stringify({ inputs, outputs }) const type = JSON.stringify({ inputs, outputs })
if (!LiteGraph.registered_node_types[type]) { if (!LiteGraphSingleton.registered_node_types[type]) {
class testnode extends LGraphNode { class testnode extends LGraphNode {
constructor(title: string) { constructor(title: string) {
super(title) super(title)
@@ -31,9 +30,9 @@ function createNode(
this.addOutput('output_' + o_count++, output) this.addOutput('output_' + o_count++, output)
} }
} }
LiteGraph.registered_node_types[type] = testnode LiteGraphSingleton.registered_node_types[type] = testnode
} }
const node = LiteGraph.createNode(type, title) const node = LiteGraphSingleton.createNode(type, title)
if (!node) { if (!node) {
throw new Error('Failed to create node') throw new Error('Failed to create node')
} }

View File

@@ -1,7 +1,7 @@
import { test as baseTest } from 'vitest' import { test as baseTest } from 'vitest'
import { LGraph } from '@/lib/litegraph/src/LGraph' import { LGraph } from '@/lib/litegraph/src/LGraph'
import { LiteGraph } from '@/lib/litegraph/src/litegraph' import { LiteGraphSingleton } from '../src/LiteGraphSingleton'
import type { import type {
ISerialisedGraph, ISerialisedGraph,
@@ -74,7 +74,7 @@ export const dirtyTest = test.extend<DirtyFixtures>({
// Register node types // Register node types
for (const node of basicSerialisableGraph.nodes) { for (const node of basicSerialisableGraph.nodes) {
LiteGraph.registerNodeType(node.type!, LiteGraph.LGraphNode) LiteGraphSingleton.registerNodeType(node.type!, LiteGraphSingleton.LGraphNode)
} }
await use(structuredClone(basicSerialisableGraph)) await use(structuredClone(basicSerialisableGraph))