mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 19:21:54 +00:00
[TS] Improve types and (#1043)
This commit is contained in:
@@ -1477,11 +1477,12 @@ export class LGraph implements LinkNetwork, BaseLGraph, Serialisable<Serialisabl
|
|||||||
|
|
||||||
// State
|
// State
|
||||||
if (data.state) {
|
if (data.state) {
|
||||||
const { state: { lastGroupId, lastLinkId, lastNodeId, lastRerouteId } } = data
|
const { lastGroupId, lastLinkId, lastNodeId, lastRerouteId } = data.state
|
||||||
if (lastGroupId != null) this.state.lastGroupId = lastGroupId
|
const { state } = this
|
||||||
if (lastLinkId != null) this.state.lastLinkId = lastLinkId
|
if (lastGroupId != null) state.lastGroupId = lastGroupId
|
||||||
if (lastNodeId != null) this.state.lastNodeId = lastNodeId
|
if (lastLinkId != null) state.lastLinkId = lastLinkId
|
||||||
if (lastRerouteId != null) this.state.lastRerouteId = lastRerouteId
|
if (lastNodeId != null) state.lastNodeId = lastNodeId
|
||||||
|
if (lastRerouteId != null) state.lastRerouteId = lastRerouteId
|
||||||
}
|
}
|
||||||
|
|
||||||
// Links
|
// Links
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { ContextMenu } from "./ContextMenu"
|
import type { ContextMenu } from "./ContextMenu"
|
||||||
|
import type { LGraphCanvasEventMap } from "./infrastructure/LGraphCanvasEventMap"
|
||||||
import type {
|
import type {
|
||||||
CanvasColour,
|
CanvasColour,
|
||||||
ColorOption,
|
ColorOption,
|
||||||
@@ -27,7 +28,6 @@ import type {
|
|||||||
} from "./interfaces"
|
} from "./interfaces"
|
||||||
import type { LGraph } from "./LGraph"
|
import type { LGraph } from "./LGraph"
|
||||||
import type {
|
import type {
|
||||||
CanvasEventDetail,
|
|
||||||
CanvasMouseEvent,
|
CanvasMouseEvent,
|
||||||
CanvasPointerEvent,
|
CanvasPointerEvent,
|
||||||
CanvasPointerExtensions,
|
CanvasPointerExtensions,
|
||||||
@@ -3151,7 +3151,7 @@ export class LGraphCanvas {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
emitEvent(detail: CanvasEventDetail): void {
|
emitEvent(detail: LGraphCanvasEventMap["litegraph:canvas"]): void {
|
||||||
this.canvas.dispatchEvent(
|
this.canvas.dispatchEvent(
|
||||||
new CustomEvent("litegraph:canvas", {
|
new CustomEvent("litegraph:canvas", {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
|
|||||||
@@ -1421,13 +1421,15 @@ export class LGraphNode implements Positionable, IPinnable, IColorable {
|
|||||||
* @param type string defining the output type ("vec3","number",...)
|
* @param type string defining the output type ("vec3","number",...)
|
||||||
* @param extra_info this can be used to have special properties of an output (label, special color, position, etc)
|
* @param extra_info this can be used to have special properties of an output (label, special color, position, etc)
|
||||||
*/
|
*/
|
||||||
addOutput(
|
addOutput<TProperties extends Partial<INodeOutputSlot>>(
|
||||||
name: string,
|
name: string,
|
||||||
type: ISlotType,
|
type: ISlotType,
|
||||||
extra_info?: Partial<INodeOutputSlot>,
|
extra_info?: TProperties,
|
||||||
): INodeOutputSlot {
|
): INodeOutputSlot & TProperties {
|
||||||
const output = new NodeOutputSlot({ name, type, links: null }, this)
|
const output = Object.assign(
|
||||||
if (extra_info) Object.assign(output, extra_info)
|
new NodeOutputSlot({ name, type, links: null }, this),
|
||||||
|
extra_info,
|
||||||
|
)
|
||||||
|
|
||||||
this.outputs ||= []
|
this.outputs ||= []
|
||||||
this.outputs.push(output)
|
this.outputs.push(output)
|
||||||
@@ -1470,10 +1472,13 @@ export class LGraphNode implements Positionable, IPinnable, IColorable {
|
|||||||
* @param type string defining the input type ("vec3","number",...), it its a generic one use 0
|
* @param type string defining the input type ("vec3","number",...), it its a generic one use 0
|
||||||
* @param extra_info this can be used to have special properties of an input (label, color, position, etc)
|
* @param extra_info this can be used to have special properties of an input (label, color, position, etc)
|
||||||
*/
|
*/
|
||||||
addInput(name: string, type: ISlotType, extra_info?: Partial<INodeInputSlot>): INodeInputSlot {
|
addInput<TProperties extends Partial<INodeInputSlot>>(name: string, type: ISlotType, extra_info?: TProperties): INodeInputSlot & TProperties {
|
||||||
type = type || 0
|
type ||= 0
|
||||||
const input = new NodeInputSlot({ name: name, type: type, link: null }, this)
|
|
||||||
if (extra_info) Object.assign(input, extra_info)
|
const input = Object.assign(
|
||||||
|
new NodeInputSlot({ name, type, link: null }, this),
|
||||||
|
extra_info,
|
||||||
|
)
|
||||||
|
|
||||||
this.inputs ||= []
|
this.inputs ||= []
|
||||||
this.inputs.push(input)
|
this.inputs.push(input)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export type SerialisedLLinkArray = [
|
|||||||
type: ISlotType,
|
type: ISlotType,
|
||||||
]
|
]
|
||||||
|
|
||||||
interface ResolvedConnection {
|
export interface ResolvedConnection {
|
||||||
inputNode: LGraphNode | undefined
|
inputNode: LGraphNode | undefined
|
||||||
outputNode: LGraphNode | undefined
|
outputNode: LGraphNode | undefined
|
||||||
input: INodeInputSlot | undefined
|
input: INodeInputSlot | undefined
|
||||||
|
|||||||
@@ -1,21 +1,84 @@
|
|||||||
/** {@link Omit} all properties that evaluate to `never`. */
|
import type { NeverNever, PickNevers } from "@/types/utility"
|
||||||
type NeverNever<T> = {
|
|
||||||
[K in keyof T as T[K] extends never ? never : K]: T[K]
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@link Pick} only properties that evaluate to `never`. */
|
|
||||||
type PickNevers<T> = {
|
|
||||||
[K in keyof T as T[K] extends never ? K : never]: T[K]
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListeners<T> = {
|
type EventListeners<T> = {
|
||||||
readonly [K in keyof T]: ((this: EventTarget, ev: CustomEvent<T[K]>) => any) | EventListenerObject | null
|
readonly [K in keyof T]: ((this: EventTarget, ev: CustomEvent<T[K]>) => any) | EventListenerObject | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has strongly-typed overrides of {@link EventTarget.addEventListener} and {@link EventTarget.removeEventListener}.
|
||||||
|
*/
|
||||||
|
export interface ICustomEventTarget<
|
||||||
|
EventMap extends Record<Keys, unknown>,
|
||||||
|
Keys extends keyof EventMap & string = keyof EventMap & string,
|
||||||
|
> {
|
||||||
|
addEventListener<K extends Keys>(
|
||||||
|
type: K,
|
||||||
|
listener: EventListeners<EventMap>[K],
|
||||||
|
options?: boolean | AddEventListenerOptions,
|
||||||
|
): void
|
||||||
|
|
||||||
|
removeEventListener<K extends Keys>(
|
||||||
|
type: K,
|
||||||
|
listener: EventListeners<EventMap>[K],
|
||||||
|
options?: boolean | EventListenerOptions,
|
||||||
|
): void
|
||||||
|
|
||||||
|
/** @deprecated Use {@link dispatch}. */
|
||||||
|
dispatchEvent(event: never): boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capable of dispatching strongly-typed events via {@link dispatch}.
|
||||||
|
* Overloads are used to ensure detail param is correctly optional.
|
||||||
|
*/
|
||||||
|
export interface CustomEventDispatcher<
|
||||||
|
EventMap extends Record<Keys, unknown>,
|
||||||
|
Keys extends keyof EventMap & string = keyof EventMap & string,
|
||||||
|
> {
|
||||||
|
dispatch<T extends keyof NeverNever<EventMap>>(type: T, detail: EventMap[T]): boolean
|
||||||
|
dispatch<T extends keyof PickNevers<EventMap>>(type: T): boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A strongly-typed, custom {@link EventTarget} that can dispatch and listen for events.
|
||||||
|
*
|
||||||
|
* 1. Define an event map
|
||||||
|
* ```ts
|
||||||
|
* export interface CustomEventMap {
|
||||||
|
* "my-event": { message: string }
|
||||||
|
* "simple-event": never
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* 2. Create an event emitter
|
||||||
|
* ```ts
|
||||||
|
* // By subclassing
|
||||||
|
* class MyClass extends CustomEventTarget<CustomEventMap> {
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // Or simply create an instance:
|
||||||
|
* const events = new CustomEventTarget<CustomEventMap>()
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* 3. Dispatch events
|
||||||
|
* ```ts
|
||||||
|
* // Extended class
|
||||||
|
* const myClass = new MyClass()
|
||||||
|
* myClass.dispatch("my-event", { message: "Hello, world!" })
|
||||||
|
* myClass.dispatch("simple-event")
|
||||||
|
*
|
||||||
|
* // Instance
|
||||||
|
* const events = new CustomEventTarget<CustomEventMap>()
|
||||||
|
* events.dispatch("my-event", { message: "Hello, world!" })
|
||||||
|
* events.dispatch("simple-event")
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export class CustomEventTarget<
|
export class CustomEventTarget<
|
||||||
EventMap extends Record<Keys, unknown>,
|
EventMap extends Record<Keys, unknown>,
|
||||||
Keys extends keyof EventMap & string = keyof EventMap & string,
|
Keys extends keyof EventMap & string = keyof EventMap & string,
|
||||||
> extends EventTarget {
|
>
|
||||||
|
extends EventTarget implements ICustomEventTarget<EventMap, Keys> {
|
||||||
/**
|
/**
|
||||||
* Type-safe event dispatching.
|
* Type-safe event dispatching.
|
||||||
* @see {@link EventTarget.dispatchEvent}
|
* @see {@link EventTarget.dispatchEvent}
|
||||||
|
|||||||
28
src/infrastructure/LGraphCanvasEventMap.ts
Normal file
28
src/infrastructure/LGraphCanvasEventMap.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import type { ConnectingLink } from "@/interfaces"
|
||||||
|
import type { LGraphGroup } from "@/LGraphGroup"
|
||||||
|
import type { LGraphNode } from "@/LGraphNode"
|
||||||
|
import type { CanvasPointerEvent } from "@/types/events"
|
||||||
|
|
||||||
|
export interface LGraphCanvasEventMap {
|
||||||
|
"litegraph:canvas":
|
||||||
|
| { subType: "before-change" | "after-change" }
|
||||||
|
| {
|
||||||
|
subType: "empty-release"
|
||||||
|
originalEvent?: CanvasPointerEvent
|
||||||
|
linkReleaseContext?: { links: ConnectingLink[] }
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
subType: "group-double-click"
|
||||||
|
originalEvent?: CanvasPointerEvent
|
||||||
|
group: LGraphGroup
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
subType: "empty-double-click"
|
||||||
|
originalEvent?: CanvasPointerEvent
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
subType: "node-double-click"
|
||||||
|
originalEvent?: CanvasPointerEvent
|
||||||
|
node: LGraphNode
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -417,3 +417,23 @@ export interface DefaultConnectionColors {
|
|||||||
getConnectedColor(type: ISlotType): CanvasColour
|
getConnectedColor(type: ISlotType): CanvasColour
|
||||||
getDisconnectedColor(type: ISlotType): CanvasColour
|
getDisconnectedColor(type: ISlotType): CanvasColour
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Shorthand for {@link Parameters} of optional callbacks.
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const { onClick } = CustomClass.prototype
|
||||||
|
* CustomClass.prototype.onClick = function (...args: CallbackParams<typeof onClick>) {
|
||||||
|
* const r = onClick?.apply(this, args)
|
||||||
|
* // ...
|
||||||
|
* return r
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export type CallbackParams<T extends ((...args: any) => any) | undefined> =
|
||||||
|
Parameters<Exclude<T, undefined>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorthand for {@link ReturnType} of optional callbacks.
|
||||||
|
* @see {@link CallbackParams}
|
||||||
|
*/
|
||||||
|
export type CallbackReturn<T extends ((...args: any) => any) | undefined> = ReturnType<Exclude<T, undefined>>
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ export interface LGraphNodeConstructor<T extends LGraphNode = LGraphNode> {
|
|||||||
title_color?: string
|
title_color?: string
|
||||||
title_text_color?: string
|
title_text_color?: string
|
||||||
keepAllLinksOnBypass: boolean
|
keepAllLinksOnBypass: boolean
|
||||||
nodeData: any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// End backwards compat
|
// End backwards compat
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
import type { LGraphGroup } from "../LGraphGroup"
|
import type { LGraphGroup } from "../LGraphGroup"
|
||||||
import type { LGraphNode } from "../LGraphNode"
|
import type { LGraphNode } from "../LGraphNode"
|
||||||
import type { ConnectingLink, LinkReleaseContextExtended } from "../litegraph"
|
import type { LinkReleaseContextExtended } from "../litegraph"
|
||||||
import type { IWidget } from "./widgets"
|
|
||||||
|
|
||||||
/** For Canvas*Event - adds graph space co-ordinates (property names are shipped) */
|
/** For Canvas*Event - adds graph space co-ordinates (property names are shipped) */
|
||||||
export interface ICanvasPosition {
|
export interface ICanvasPosition {
|
||||||
@@ -57,12 +56,9 @@ export interface CanvasDragEvent extends
|
|||||||
|
|
||||||
export type CanvasEventDetail =
|
export type CanvasEventDetail =
|
||||||
| GenericEventDetail
|
| GenericEventDetail
|
||||||
| DragggingCanvasEventDetail
|
|
||||||
| ReadOnlyEventDetail
|
|
||||||
| GroupDoubleClickEventDetail
|
| GroupDoubleClickEventDetail
|
||||||
| NodeDoubleClickEventDetail
|
| NodeDoubleClickEventDetail
|
||||||
| EmptyDoubleClickEventDetail
|
| EmptyDoubleClickEventDetail
|
||||||
| ConnectingWidgetLinkEventDetail
|
|
||||||
| EmptyReleaseEventDetail
|
| EmptyReleaseEventDetail
|
||||||
|
|
||||||
export interface GenericEventDetail {
|
export interface GenericEventDetail {
|
||||||
@@ -78,13 +74,6 @@ export interface EmptyReleaseEventDetail extends OriginalEvent {
|
|||||||
linkReleaseContext: LinkReleaseContextExtended
|
linkReleaseContext: LinkReleaseContextExtended
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConnectingWidgetLinkEventDetail {
|
|
||||||
subType: "connectingWidgetLink"
|
|
||||||
link: ConnectingLink
|
|
||||||
node: LGraphNode
|
|
||||||
widget: IWidget
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmptyDoubleClickEventDetail extends OriginalEvent {
|
export interface EmptyDoubleClickEventDetail extends OriginalEvent {
|
||||||
subType: "empty-double-click"
|
subType: "empty-double-click"
|
||||||
}
|
}
|
||||||
@@ -98,13 +87,3 @@ export interface NodeDoubleClickEventDetail extends OriginalEvent {
|
|||||||
subType: "node-double-click"
|
subType: "node-double-click"
|
||||||
node: LGraphNode
|
node: LGraphNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DragggingCanvasEventDetail {
|
|
||||||
subType: "dragging-canvas"
|
|
||||||
draggingCanvas: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReadOnlyEventDetail {
|
|
||||||
subType: "read-only"
|
|
||||||
readOnly: boolean
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export interface BaseExportedGraph {
|
|||||||
/** Unique graph ID. Automatically generated if not provided. */
|
/** Unique graph ID. Automatically generated if not provided. */
|
||||||
id: UUID
|
id: UUID
|
||||||
revision: number
|
revision: number
|
||||||
config: LGraphConfig
|
config?: LGraphConfig
|
||||||
/** Details of the appearance and location of subgraphs shown in this graph. Similar to */
|
/** Details of the appearance and location of subgraphs shown in this graph. Similar to */
|
||||||
subgraphs?: ExportedSubgraphInstance[]
|
subgraphs?: ExportedSubgraphInstance[]
|
||||||
/** Definitions of re-usable objects that are referenced elsewhere in this exported graph. */
|
/** Definitions of re-usable objects that are referenced elsewhere in this exported graph. */
|
||||||
@@ -161,7 +161,7 @@ export interface ISerialisedGroup {
|
|||||||
title: string
|
title: string
|
||||||
bounding: number[]
|
bounding: number[]
|
||||||
color?: string
|
color?: string
|
||||||
font_size: number
|
font_size?: number
|
||||||
flags?: IGraphGroupFlags
|
flags?: IGraphGroupFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
src/types/utility.ts
Normal file
13
src/types/utility.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* General-purpose, TypeScript utility types.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** {@link Pick} only properties that evaluate to `never`. */
|
||||||
|
export type PickNevers<T> = {
|
||||||
|
[K in keyof T as T[K] extends never ? K : never]: T[K]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@link Omit} all properties that evaluate to `never`. */
|
||||||
|
export type NeverNever<T> = {
|
||||||
|
[K in keyof T as T[K] extends never ? never : K]: T[K]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user