mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-07 00:20:07 +00:00
[CodeHealth] Replace temporary TS conversion widget types (#1019)
This commit is contained in:
@@ -73,9 +73,8 @@ import {
|
||||
} from "./types/globalEnums"
|
||||
import { alignNodes, distributeNodes, getBoundaryNodes } from "./utils/arrange"
|
||||
import { findFirstNode, getAllNestedItems } from "./utils/collections"
|
||||
import { toClass } from "./utils/type"
|
||||
import { BaseWidget } from "./widgets/BaseWidget"
|
||||
import { WIDGET_TYPE_MAP } from "./widgets/widgetMap"
|
||||
import { toConcreteWidget } from "./widgets/widgetMap"
|
||||
|
||||
interface IShowSearchOptions {
|
||||
node_to?: LGraphNode | null
|
||||
@@ -2397,9 +2396,8 @@ export class LGraphCanvas {
|
||||
const x = pos[0] - node.pos[0]
|
||||
const y = pos[1] - node.pos[1]
|
||||
|
||||
const WidgetClass = WIDGET_TYPE_MAP[widget.type]
|
||||
if (WidgetClass) {
|
||||
const widgetInstance = toClass(WidgetClass, widget)
|
||||
const widgetInstance = toConcreteWidget(widget)
|
||||
if (widgetInstance) {
|
||||
pointer.onClick = () => widgetInstance.onClick({
|
||||
e,
|
||||
node,
|
||||
|
||||
@@ -20,6 +20,9 @@ export type WhenNullish<T, Result> = T & {} | (T extends null ? Result : T exten
|
||||
/** A type with each of the {@link Properties} made optional. */
|
||||
export type OptionalProps<T, Properties extends keyof T> = Omit<T, Properties> & { [K in Properties]?: T[K] }
|
||||
|
||||
/** A type with each of the {@link Properties} marked as required. */
|
||||
export type RequiredProps<T, Properties extends keyof T> = Omit<T, Properties> & { [K in Properties]-?: T[K] }
|
||||
|
||||
/** Bitwise AND intersection of two types; returns a new, non-union type that includes only properties that exist on both types. */
|
||||
export type SharedIntersection<T1, T2> = {
|
||||
[P in keyof T1 as P extends keyof T2 ? P : never]: T1[P]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { CanvasPointer, LGraphCanvas, LGraphNode } from "../litegraph"
|
||||
import type { CanvasMouseEvent, CanvasPointerEvent } from "./events"
|
||||
|
||||
import { CanvasColour, Point, Size } from "../interfaces"
|
||||
import { CanvasColour, Point, type RequiredProps, Size } from "../interfaces"
|
||||
|
||||
export interface IWidgetOptions<TValue = unknown> extends Record<string, unknown> {
|
||||
export interface IWidgetOptions<TValues = unknown[]> {
|
||||
on?: string
|
||||
off?: string
|
||||
max?: number
|
||||
@@ -27,7 +27,7 @@ export interface IWidgetOptions<TValue = unknown> extends Record<string, unknown
|
||||
/** If `true`, an input socket will not be created for this widget. */
|
||||
socketless?: boolean
|
||||
|
||||
values?: TValue[]
|
||||
values?: TValues
|
||||
callback?: IWidget["callback"]
|
||||
}
|
||||
|
||||
@@ -60,71 +60,61 @@ export type IWidget =
|
||||
| IBooleanWidget
|
||||
| INumericWidget
|
||||
| IStringWidget
|
||||
| IMultilineStringWidget
|
||||
| IComboWidget
|
||||
| ICustomWidget
|
||||
| ISliderWidget
|
||||
| IButtonWidget
|
||||
| IKnobWidget
|
||||
|
||||
export interface IBooleanWidget extends IBaseWidget {
|
||||
export interface IBooleanWidget extends IBaseWidget<boolean, "toggle", IWidgetOptions<boolean>> {
|
||||
type: "toggle"
|
||||
value: boolean
|
||||
}
|
||||
|
||||
/** Any widget that uses a numeric backing */
|
||||
export interface INumericWidget extends IBaseWidget {
|
||||
export interface INumericWidget extends IBaseWidget<number, "number", IWidgetOptions<number>> {
|
||||
type: "number"
|
||||
value: number
|
||||
}
|
||||
|
||||
export interface ISliderWidget extends IBaseWidget {
|
||||
export interface ISliderWidget extends IBaseWidget<number, "slider", IWidgetSliderOptions> {
|
||||
type: "slider"
|
||||
value: number
|
||||
options: IWidgetSliderOptions
|
||||
marker?: number
|
||||
}
|
||||
|
||||
export interface IKnobWidget extends IBaseWidget {
|
||||
export interface IKnobWidget extends IBaseWidget<number, "knob", IWidgetKnobOptions> {
|
||||
type: "knob"
|
||||
value: number
|
||||
options: IWidgetKnobOptions
|
||||
}
|
||||
|
||||
type ComboWidgetValues = string[] | Record<string, string> | ((widget?: IComboWidget, node?: LGraphNode) => string[])
|
||||
|
||||
/** A combo-box widget (dropdown, select, etc) */
|
||||
export interface IComboWidget extends IBaseWidget {
|
||||
export interface IComboWidget extends IBaseWidget<
|
||||
string | number,
|
||||
"combo",
|
||||
RequiredProps<IWidgetOptions<ComboWidgetValues>, "values">
|
||||
> {
|
||||
type: "combo"
|
||||
value: string | number
|
||||
options: IWidgetOptions<string>
|
||||
}
|
||||
|
||||
export type IStringWidgetType = IStringWidget["type"] | IMultilineStringWidget["type"]
|
||||
|
||||
/** A widget with a string value */
|
||||
export interface IStringWidget extends IBaseWidget {
|
||||
export interface IStringWidget extends IBaseWidget<string, "string" | "text", IWidgetOptions<string>> {
|
||||
type: "string" | "text"
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface IButtonWidget extends IBaseWidget {
|
||||
export interface IButtonWidget extends IBaseWidget<undefined, "button", IWidgetOptions<undefined>> {
|
||||
type: "button"
|
||||
value: undefined
|
||||
clicked: boolean
|
||||
}
|
||||
|
||||
/** A widget with a string value and a multiline text input */
|
||||
export interface IMultilineStringWidget<TElement extends HTMLElement = HTMLTextAreaElement> extends
|
||||
IBaseWidget {
|
||||
|
||||
type: "multiline"
|
||||
value: string
|
||||
|
||||
/** HTML textarea element */
|
||||
element?: TElement
|
||||
}
|
||||
|
||||
/** A custom widget - accepts any value and has no built-in special handling */
|
||||
export interface ICustomWidget extends IBaseWidget {
|
||||
export interface ICustomWidget extends IBaseWidget<string | object, "custom", IWidgetOptions<string | object>> {
|
||||
type: "custom"
|
||||
value: string | object
|
||||
}
|
||||
@@ -141,16 +131,16 @@ export type TWidgetValue = IWidget["value"]
|
||||
* The base type for all widgets. Should not be implemented directly.
|
||||
* @see IWidget
|
||||
*/
|
||||
export interface IBaseWidget {
|
||||
export interface IBaseWidget<TValue = unknown, TType = string, TOptions = unknown> {
|
||||
linkedWidgets?: IWidget[]
|
||||
|
||||
name: string
|
||||
options: IWidgetOptions
|
||||
options: TOptions
|
||||
|
||||
label?: string
|
||||
/** Widget type (see {@link TWidgetType}) */
|
||||
type: TWidgetType
|
||||
value?: TWidgetValue
|
||||
type: TType
|
||||
value?: TValue
|
||||
|
||||
/**
|
||||
* Whether the widget value should be serialized on node serialization.
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import type { IWidget } from "@/types/widgets"
|
||||
|
||||
import { BaseWidget, type DrawWidgetOptions, type WidgetEventOptions } from "./BaseWidget"
|
||||
|
||||
/**
|
||||
* Base class for widgets that have increment and decrement buttons.
|
||||
*/
|
||||
export abstract class BaseSteppedWidget extends BaseWidget {
|
||||
export abstract class BaseSteppedWidget<TWidget extends IWidget> extends BaseWidget<TWidget> {
|
||||
/**
|
||||
* Whether the widget can increment its value
|
||||
* @returns `true` if the widget can increment its value, otherwise `false`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { CanvasPointer, LGraphCanvas, LGraphNode, Size } from "@/litegraph"
|
||||
import type { CanvasMouseEvent, CanvasPointerEvent } from "@/types/events"
|
||||
import type { IBaseWidget, IWidget, IWidgetOptions, TWidgetType, TWidgetValue } from "@/types/widgets"
|
||||
import type { IBaseWidget, IWidget } from "@/types/widgets"
|
||||
|
||||
import { drawTextInArea } from "@/draw"
|
||||
import { Rectangle } from "@/infrastructure/Rectangle"
|
||||
@@ -29,7 +29,7 @@ export interface WidgetEventOptions {
|
||||
canvas: LGraphCanvas
|
||||
}
|
||||
|
||||
export abstract class BaseWidget implements IBaseWidget {
|
||||
export abstract class BaseWidget<TWidget extends IWidget = IWidget> implements IBaseWidget {
|
||||
/** From node edge to widget edge */
|
||||
static margin = 15
|
||||
/** From widget edge to tip of arrow button */
|
||||
@@ -43,10 +43,10 @@ export abstract class BaseWidget implements IBaseWidget {
|
||||
|
||||
linkedWidgets?: IWidget[]
|
||||
name: string
|
||||
options: IWidgetOptions<unknown>
|
||||
options: TWidget["options"]
|
||||
label?: string
|
||||
type: TWidgetType
|
||||
value?: TWidgetValue
|
||||
type: TWidget["type"]
|
||||
value: TWidget["value"]
|
||||
y: number = 0
|
||||
last_y?: number
|
||||
width?: number
|
||||
@@ -74,11 +74,12 @@ export abstract class BaseWidget implements IBaseWidget {
|
||||
computeSize?(width?: number): Size
|
||||
onPointerDown?(pointer: CanvasPointer, node: LGraphNode, canvas: LGraphCanvas): boolean
|
||||
|
||||
constructor(widget: IBaseWidget) {
|
||||
constructor(widget: TWidget) {
|
||||
Object.assign(this, widget)
|
||||
this.name = widget.name
|
||||
this.options = widget.options
|
||||
this.type = widget.type
|
||||
this.value = widget.value
|
||||
}
|
||||
|
||||
get outline_color() {
|
||||
@@ -232,7 +233,7 @@ export abstract class BaseWidget implements IBaseWidget {
|
||||
* @param value The value to set
|
||||
* @param options The options for setting the value
|
||||
*/
|
||||
setValue(value: TWidgetValue, { e, node, canvas }: WidgetEventOptions) {
|
||||
setValue(value: TWidget["value"], { e, node, canvas }: WidgetEventOptions) {
|
||||
const oldValue = this.value
|
||||
if (value === this.value) return
|
||||
|
||||
|
||||
@@ -2,16 +2,8 @@ import type { IBooleanWidget } from "@/types/widgets"
|
||||
|
||||
import { BaseWidget, type DrawWidgetOptions, type WidgetEventOptions } from "./BaseWidget"
|
||||
|
||||
export class BooleanWidget extends BaseWidget implements IBooleanWidget {
|
||||
// IBooleanWidget properties
|
||||
declare type: "toggle"
|
||||
declare value: boolean
|
||||
|
||||
constructor(widget: IBooleanWidget) {
|
||||
super(widget)
|
||||
this.type = "toggle"
|
||||
this.value = widget.value
|
||||
}
|
||||
export class BooleanWidget extends BaseWidget<IBooleanWidget> implements IBooleanWidget {
|
||||
override type = "toggle" as const
|
||||
|
||||
override drawWidget(ctx: CanvasRenderingContext2D, {
|
||||
width,
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
import type { IButtonWidget, IWidgetOptions } from "@/types/widgets"
|
||||
import type { IButtonWidget } from "@/types/widgets"
|
||||
|
||||
import { BaseWidget, type DrawWidgetOptions, type WidgetEventOptions } from "./BaseWidget"
|
||||
|
||||
export class ButtonWidget extends BaseWidget implements IButtonWidget {
|
||||
// IButtonWidget properties
|
||||
declare type: "button"
|
||||
declare options: IWidgetOptions<boolean>
|
||||
declare clicked: boolean
|
||||
declare value: undefined
|
||||
export class ButtonWidget extends BaseWidget<IButtonWidget> implements IButtonWidget {
|
||||
override type = "button" as const
|
||||
clicked: boolean
|
||||
|
||||
constructor(widget: IButtonWidget) {
|
||||
super(widget)
|
||||
this.type = "button"
|
||||
this.clicked = widget.clicked ?? false
|
||||
this.clicked ??= false
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { WidgetEventOptions } from "./BaseWidget"
|
||||
import type { LGraphNode } from "@/LGraphNode"
|
||||
import type { IComboWidget, IWidgetOptions } from "@/types/widgets"
|
||||
import type { IComboWidget } from "@/types/widgets"
|
||||
|
||||
import { clamp, LiteGraph } from "@/litegraph"
|
||||
import { warnDeprecated } from "@/utils/feedback"
|
||||
@@ -19,12 +19,8 @@ function toArray(values: Values): string[] {
|
||||
return Array.isArray(values) ? values : Object.keys(values)
|
||||
}
|
||||
|
||||
export class ComboWidget extends BaseSteppedWidget implements IComboWidget {
|
||||
// IComboWidget properties
|
||||
declare type: "combo"
|
||||
declare value: string | number
|
||||
// @ts-expect-error Workaround for Record<string, string> not being typed in IWidgetOptions
|
||||
declare options: Omit<IWidgetOptions<string>, "values"> & { values: Values }
|
||||
export class ComboWidget extends BaseSteppedWidget<IComboWidget> implements IComboWidget {
|
||||
override type = "combo" as const
|
||||
|
||||
override get displayValue() {
|
||||
const { values: rawValues } = this.options
|
||||
@@ -38,12 +34,6 @@ export class ComboWidget extends BaseSteppedWidget implements IComboWidget {
|
||||
return typeof this.value === "number" ? String(this.value) : this.value
|
||||
}
|
||||
|
||||
constructor(widget: IComboWidget) {
|
||||
super(widget)
|
||||
this.type = "combo"
|
||||
this.value = widget.value
|
||||
}
|
||||
|
||||
#getValues(node: LGraphNode): Values {
|
||||
const { values } = this.options
|
||||
if (values == null) throw new Error("[ComboWidget]: values is required")
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
import type { IKnobWidget, IWidgetKnobOptions } from "@/types/widgets"
|
||||
import type { IKnobWidget } from "@/types/widgets"
|
||||
|
||||
import { clamp } from "@/litegraph"
|
||||
import { getWidgetStep } from "@/utils/widget"
|
||||
|
||||
import { BaseWidget, type DrawWidgetOptions, type WidgetEventOptions } from "./BaseWidget"
|
||||
|
||||
export class KnobWidget extends BaseWidget implements IKnobWidget {
|
||||
declare type: "knob"
|
||||
declare value: number
|
||||
declare options: IWidgetKnobOptions
|
||||
|
||||
constructor(widget: IKnobWidget) {
|
||||
super(widget)
|
||||
this.type = "knob"
|
||||
this.value = widget.value
|
||||
this.options = widget.options
|
||||
}
|
||||
export class KnobWidget extends BaseWidget<IKnobWidget> implements IKnobWidget {
|
||||
override type = "knob" as const
|
||||
|
||||
computedHeight?: number
|
||||
/**
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import type { WidgetEventOptions } from "./BaseWidget"
|
||||
import type { INumericWidget, IWidgetOptions } from "@/types/widgets"
|
||||
import type { INumericWidget } from "@/types/widgets"
|
||||
|
||||
import { getWidgetStep } from "@/utils/widget"
|
||||
|
||||
import { BaseSteppedWidget } from "./BaseSteppedWidget"
|
||||
|
||||
export class NumberWidget extends BaseSteppedWidget implements INumericWidget {
|
||||
// INumberWidget properties
|
||||
declare type: "number"
|
||||
declare value: number
|
||||
declare options: IWidgetOptions<number>
|
||||
export class NumberWidget extends BaseSteppedWidget<INumericWidget> implements INumericWidget {
|
||||
override type = "number" as const
|
||||
|
||||
override get displayValue() {
|
||||
return Number(this.value).toFixed(
|
||||
@@ -19,12 +16,6 @@ export class NumberWidget extends BaseSteppedWidget implements INumericWidget {
|
||||
)
|
||||
}
|
||||
|
||||
constructor(widget: INumericWidget) {
|
||||
super(widget)
|
||||
this.type = "number"
|
||||
this.value = widget.value
|
||||
}
|
||||
|
||||
override canIncrement(): boolean {
|
||||
const { max } = this.options
|
||||
return max == null || this.value < max
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
import type { ISliderWidget, IWidgetSliderOptions } from "@/types/widgets"
|
||||
import type { ISliderWidget } from "@/types/widgets"
|
||||
|
||||
import { clamp } from "@/litegraph"
|
||||
|
||||
import { BaseWidget, type DrawWidgetOptions, type WidgetEventOptions } from "./BaseWidget"
|
||||
|
||||
export class SliderWidget extends BaseWidget implements ISliderWidget {
|
||||
// ISliderWidget properties
|
||||
declare type: "slider"
|
||||
declare value: number
|
||||
declare options: IWidgetSliderOptions
|
||||
marker?: number
|
||||
export class SliderWidget extends BaseWidget<ISliderWidget> implements ISliderWidget {
|
||||
override type = "slider" as const
|
||||
|
||||
constructor(widget: ISliderWidget) {
|
||||
super(widget)
|
||||
this.type = "slider"
|
||||
this.value = widget.value
|
||||
this.options = widget.options
|
||||
this.marker = widget.marker
|
||||
}
|
||||
marker?: number
|
||||
|
||||
/**
|
||||
* Draws the widget
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import type { IStringWidget, IWidgetOptions } from "@/types/widgets"
|
||||
import type { IStringWidget } from "@/types/widgets"
|
||||
|
||||
import { BaseWidget, type DrawWidgetOptions, type WidgetEventOptions } from "./BaseWidget"
|
||||
|
||||
export class TextWidget extends BaseWidget implements IStringWidget {
|
||||
// IStringWidget properties
|
||||
declare type: "text" | "string"
|
||||
declare value: string
|
||||
declare options: IWidgetOptions<string>
|
||||
|
||||
export class TextWidget extends BaseWidget<IStringWidget> implements IStringWidget {
|
||||
constructor(widget: IStringWidget) {
|
||||
super(widget)
|
||||
this.type = widget.type ?? "string"
|
||||
this.type ??= "string"
|
||||
this.value = widget.value?.toString() ?? ""
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { IBaseWidget } from "@/types/widgets"
|
||||
import type { IBaseWidget, IWidget } from "@/types/widgets"
|
||||
|
||||
import { BaseWidget } from "./BaseWidget"
|
||||
import { BooleanWidget } from "./BooleanWidget"
|
||||
@@ -9,6 +9,21 @@ import { NumberWidget } from "./NumberWidget"
|
||||
import { SliderWidget } from "./SliderWidget"
|
||||
import { TextWidget } from "./TextWidget"
|
||||
|
||||
export function toConcreteWidget(widget: IWidget): BaseWidget | undefined {
|
||||
if (widget instanceof BaseWidget) return widget
|
||||
|
||||
switch (widget.type) {
|
||||
case "button": return new ButtonWidget(widget)
|
||||
case "toggle": return new BooleanWidget(widget)
|
||||
case "slider": return new SliderWidget(widget)
|
||||
case "knob": return new KnobWidget(widget)
|
||||
case "combo": return new ComboWidget(widget)
|
||||
case "number": return new NumberWidget(widget)
|
||||
case "string": return new TextWidget(widget)
|
||||
case "text": return new TextWidget(widget)
|
||||
}
|
||||
}
|
||||
|
||||
type WidgetConstructor = {
|
||||
new (plain: IBaseWidget): BaseWidget
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user