mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-05 15:40:10 +00:00
[TS] Widget typing (#3804)
This commit is contained in:
@@ -75,7 +75,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { IWidget, LGraphNode } from '@comfyorg/litegraph'
|
||||
import { LGraphNode } from '@comfyorg/litegraph'
|
||||
import { Tooltip } from 'primevue'
|
||||
import Button from 'primevue/button'
|
||||
|
||||
@@ -101,13 +101,13 @@ const emit = defineEmits<{
|
||||
const resizeNodeMatchOutput = () => {
|
||||
console.log('resizeNodeMatchOutput')
|
||||
|
||||
const outputWidth = node.widgets?.find((w: IWidget) => w.name === 'width')
|
||||
const outputHeight = node.widgets?.find((w: IWidget) => w.name === 'height')
|
||||
const outputWidth = node.widgets?.find((w) => w.name === 'width')
|
||||
const outputHeight = node.widgets?.find((w) => w.name === 'height')
|
||||
|
||||
if (outputWidth && outputHeight && outputHeight.value && outputWidth.value) {
|
||||
const [oldWidth, oldHeight] = node.size
|
||||
|
||||
const scene = node.widgets?.find((w: IWidget) => w.name === 'image')
|
||||
const scene = node.widgets?.find((w) => w.name === 'image')
|
||||
|
||||
const sceneHeight = scene?.computedHeight
|
||||
|
||||
|
||||
@@ -50,7 +50,8 @@ export const useFloatWidget = () => {
|
||||
Math.max(0, -Math.floor(Math.log10(step)))
|
||||
const enableRounding = !settingStore.get('Comfy.DisableFloatRounding')
|
||||
|
||||
const defaultValue = inputSpec.default ?? 0
|
||||
/** Assertion {@link inputSpec.default} */
|
||||
const defaultValue = (inputSpec.default as number | undefined) ?? 0
|
||||
return node.addWidget(
|
||||
widgetType,
|
||||
inputSpec.name,
|
||||
|
||||
@@ -55,7 +55,8 @@ export const useIntWidget = () => {
|
||||
: 'number'
|
||||
|
||||
const step = inputSpec.step ?? 1
|
||||
const defaultValue = inputSpec.default ?? 0
|
||||
/** Assertion {@link inputSpec.default} */
|
||||
const defaultValue = (inputSpec.default as number | undefined) ?? 0
|
||||
const widget = node.addWidget(
|
||||
widgetType,
|
||||
inputSpec.name,
|
||||
|
||||
@@ -36,7 +36,7 @@ const ext = {
|
||||
w.type === 'combo' && w.options.values?.length === values.length
|
||||
)
|
||||
.find((w) =>
|
||||
// @ts-ignore Poorly typed; filter above "should" mitigate exceptions
|
||||
// @ts-expect-error Poorly typed; filter above "should" mitigate exceptions
|
||||
w.options.values?.every((v, i) => v === values[i])
|
||||
)?.value
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { IWidget } from '@comfyorg/litegraph'
|
||||
import { IStringWidget } from '@comfyorg/litegraph/dist/types/widgets'
|
||||
import type { IStringWidget } from '@comfyorg/litegraph/dist/types/widgets'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
import Load3D from '@/components/load3d/Load3D.vue'
|
||||
@@ -116,7 +115,7 @@ useExtensionService().registerExtension({
|
||||
fileInput.onchange = async () => {
|
||||
if (fileInput.files?.length) {
|
||||
const modelWidget = node.widgets?.find(
|
||||
(w: IWidget) => w.name === 'model_file'
|
||||
(w) => w.name === 'model_file'
|
||||
) as IStringWidget
|
||||
|
||||
node.properties['Texture'] = undefined
|
||||
@@ -139,7 +138,7 @@ useExtensionService().registerExtension({
|
||||
|
||||
if (uploadPath && modelWidget) {
|
||||
if (!modelWidget.options?.values?.includes(uploadPath)) {
|
||||
// @ts-ignore Fails due to earlier type-assertion of IStringWidget
|
||||
// @ts-expect-error Fails due to earlier type-assertion of IStringWidget
|
||||
modelWidget.options?.values?.push(uploadPath)
|
||||
}
|
||||
|
||||
@@ -155,9 +154,7 @@ useExtensionService().registerExtension({
|
||||
node.addWidget('button', 'clear', 'clear', () => {
|
||||
useLoad3dService().getLoad3d(node)?.clearModel()
|
||||
|
||||
const modelWidget = node.widgets?.find(
|
||||
(w: IWidget) => w.name === 'model_file'
|
||||
)
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
if (modelWidget) {
|
||||
modelWidget.value = ''
|
||||
|
||||
@@ -203,12 +200,10 @@ useExtensionService().registerExtension({
|
||||
|
||||
const config = new Load3DConfiguration(load3d)
|
||||
|
||||
const modelWidget = node.widgets?.find(
|
||||
(w: IWidget) => w.name === 'model_file'
|
||||
)
|
||||
const width = node.widgets?.find((w: IWidget) => w.name === 'width')
|
||||
const height = node.widgets?.find((w: IWidget) => w.name === 'height')
|
||||
const sceneWidget = node.widgets?.find((w: IWidget) => w.name === 'image')
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
const width = node.widgets?.find((w) => w.name === 'width')
|
||||
const height = node.widgets?.find((w) => w.name === 'height')
|
||||
const sceneWidget = node.widgets?.find((w) => w.name === 'image')
|
||||
|
||||
if (modelWidget && width && height && sceneWidget) {
|
||||
config.configure('input', modelWidget, cameraState, width, height)
|
||||
@@ -276,7 +271,7 @@ useExtensionService().registerExtension({
|
||||
fileInput.onchange = async () => {
|
||||
if (fileInput.files?.length) {
|
||||
const modelWidget = node.widgets?.find(
|
||||
(w: IWidget) => w.name === 'model_file'
|
||||
(w) => w.name === 'model_file'
|
||||
) as IStringWidget
|
||||
|
||||
const uploadPath = await Load3dUtils.uploadFile(
|
||||
@@ -297,7 +292,7 @@ useExtensionService().registerExtension({
|
||||
|
||||
if (uploadPath && modelWidget) {
|
||||
if (!modelWidget.options?.values?.includes(uploadPath)) {
|
||||
// @ts-ignore Fails due to earlier type-assertion of IStringWidget
|
||||
// @ts-expect-error Fails due to earlier type-assertion of IStringWidget
|
||||
modelWidget.options?.values?.push(uploadPath)
|
||||
}
|
||||
|
||||
@@ -313,9 +308,7 @@ useExtensionService().registerExtension({
|
||||
node.addWidget('button', 'clear', 'clear', () => {
|
||||
useLoad3dService().getLoad3d(node)?.clearModel()
|
||||
|
||||
const modelWidget = node.widgets?.find(
|
||||
(w: IWidget) => w.name === 'model_file'
|
||||
)
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
if (modelWidget) {
|
||||
modelWidget.value = ''
|
||||
}
|
||||
@@ -352,18 +345,16 @@ useExtensionService().registerExtension({
|
||||
|
||||
await nextTick()
|
||||
|
||||
const sceneWidget = node.widgets?.find((w: IWidget) => w.name === 'image')
|
||||
const sceneWidget = node.widgets?.find((w) => w.name === 'image')
|
||||
|
||||
const load3d = useLoad3dService().getLoad3d(node) as Load3dAnimation
|
||||
|
||||
const modelWidget = node.widgets?.find(
|
||||
(w: IWidget) => w.name === 'model_file'
|
||||
)
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
|
||||
let cameraState = node.properties['Camera Info']
|
||||
|
||||
const width = node.widgets?.find((w: IWidget) => w.name === 'width')
|
||||
const height = node.widgets?.find((w: IWidget) => w.name === 'height')
|
||||
const width = node.widgets?.find((w) => w.name === 'width')
|
||||
const height = node.widgets?.find((w) => w.name === 'height')
|
||||
|
||||
if (modelWidget && width && height && sceneWidget && load3d) {
|
||||
const config = new Load3DConfiguration(load3d)
|
||||
@@ -479,9 +470,7 @@ useExtensionService().registerExtension({
|
||||
|
||||
let cameraState = message.result[1]
|
||||
|
||||
const modelWidget = node.widgets?.find(
|
||||
(w: IWidget) => w.name === 'model_file'
|
||||
)
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
|
||||
if (load3d && modelWidget) {
|
||||
modelWidget.value = filePath.replaceAll('\\', '/')
|
||||
@@ -555,9 +544,7 @@ useExtensionService().registerExtension({
|
||||
|
||||
const load3d = useLoad3dService().getLoad3d(node)
|
||||
|
||||
const modelWidget = node.widgets?.find(
|
||||
(w: IWidget) => w.name === 'model_file'
|
||||
)
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')
|
||||
if (load3d && modelWidget) {
|
||||
modelWidget.value = filePath.replaceAll('\\', '/')
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ Preview Any - original implement from
|
||||
https://github.com/rgthree/rgthree-comfy/blob/main/py/display_any.py
|
||||
upstream requested in https://github.com/Kosinkadink/rfcs/blob/main/rfcs/0000-corenodes.md#preview-nodes
|
||||
*/
|
||||
import { IWidget } from '@comfyorg/litegraph'
|
||||
|
||||
import { DOMWidget } from '@/scripts/domWidget'
|
||||
import { ComfyWidgets } from '@/scripts/widgets'
|
||||
import { useExtensionService } from '@/services/extensionService'
|
||||
@@ -37,9 +35,7 @@ useExtensionService().registerExtension({
|
||||
? void 0
|
||||
: onExecuted.apply(this, [message])
|
||||
|
||||
const previewWidget = this.widgets?.find(
|
||||
(w: IWidget) => w.name === 'preview'
|
||||
)
|
||||
const previewWidget = this.widgets?.find((w) => w.name === 'preview')
|
||||
|
||||
if (previewWidget) {
|
||||
previewWidget.value = message.text[0]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { IWidget } from '@comfyorg/litegraph'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
import Load3D from '@/components/load3d/Load3D.vue'
|
||||
@@ -61,7 +60,7 @@ useExtensionService().registerExtension({
|
||||
|
||||
const load3d = useLoad3dService().getLoad3d(node)
|
||||
|
||||
const modelWidget = node.widgets?.find((w: IWidget) => w.name === 'image')
|
||||
const modelWidget = node.widgets?.find((w) => w.name === 'image')
|
||||
|
||||
if (load3d && modelWidget) {
|
||||
const filePath = fileInfo['subfolder'] + '/' + fileInfo['filename']
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { IWidget, LGraphNode } from '@comfyorg/litegraph'
|
||||
import type { LGraphNode } from '@comfyorg/litegraph'
|
||||
import type { IStringWidget } from '@comfyorg/litegraph/dist/types/widgets'
|
||||
|
||||
import { useNodeDragAndDrop } from '@/composables/node/useNodeDragAndDrop'
|
||||
@@ -164,11 +164,11 @@ app.registerExtension({
|
||||
// The widget that allows user to select file.
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const audioWidget = node.widgets.find(
|
||||
(w: IWidget) => w.name === 'audio'
|
||||
(w) => w.name === 'audio'
|
||||
) as IStringWidget
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const audioUIWidget = node.widgets.find(
|
||||
(w: IWidget) => w.name === 'audioUI'
|
||||
(w) => w.name === 'audioUI'
|
||||
) as unknown as DOMWidget<HTMLAudioElement, string>
|
||||
|
||||
const onAudioWidgetUpdate = () => {
|
||||
|
||||
@@ -36,7 +36,7 @@ export const zNumericInputOptions = zBaseInputOptions.extend({
|
||||
min: z.number().optional(),
|
||||
max: z.number().optional(),
|
||||
step: z.number().optional(),
|
||||
// Note: Many node authors are using INT/FLOAT to pass list of INT/FLOAT.
|
||||
/** Note: Many node authors are using INT/FLOAT to pass list of INT/FLOAT. */
|
||||
default: z.union([z.number(), z.array(z.number())]).optional(),
|
||||
display: z.enum(['slider', 'number', 'knob']).optional()
|
||||
})
|
||||
|
||||
@@ -78,7 +78,7 @@ export function addValueControlWidget(
|
||||
_values?: unknown,
|
||||
widgetName?: string,
|
||||
inputData?: InputSpec
|
||||
): IWidget {
|
||||
): IComboWidget {
|
||||
let name = inputData?.[1]?.control_after_generate
|
||||
if (typeof name !== 'string') {
|
||||
name = widgetName
|
||||
@@ -102,7 +102,7 @@ export function addValueControlWidgets(
|
||||
defaultValue?: string,
|
||||
options?: Record<string, any>,
|
||||
inputData?: InputSpec
|
||||
): IWidget[] {
|
||||
): [IComboWidget, ...IStringWidget[]] {
|
||||
if (!defaultValue) defaultValue = 'randomize'
|
||||
if (!options) options = {}
|
||||
|
||||
@@ -118,7 +118,6 @@ export function addValueControlWidgets(
|
||||
return name
|
||||
}
|
||||
|
||||
const widgets: IWidget[] = []
|
||||
const valueControl = node.addWidget(
|
||||
'combo',
|
||||
getName('control_after_generate', 'controlAfterGenerateName'),
|
||||
@@ -135,12 +134,12 @@ export function addValueControlWidgets(
|
||||
// @ts-ignore index with symbol
|
||||
valueControl[IS_CONTROL_WIDGET] = true
|
||||
updateControlWidgetLabel(valueControl)
|
||||
widgets.push(valueControl)
|
||||
const widgets: [IComboWidget, ...IStringWidget[]] = [valueControl]
|
||||
|
||||
const isCombo = targetWidget.type === 'combo'
|
||||
let comboFilter: IStringWidget
|
||||
if (isCombo && valueControl.options.values) {
|
||||
// @ts-ignore Combo widget values may be a dictionary or legacy function type
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
valueControl.options.values.push('increment-wrap')
|
||||
}
|
||||
if (isCombo && options.addFilterList !== false) {
|
||||
@@ -184,7 +183,7 @@ export function addValueControlWidgets(
|
||||
const lower = filter.toLocaleLowerCase()
|
||||
check = (item: string) => item.toLocaleLowerCase().includes(lower)
|
||||
}
|
||||
// @ts-ignore Combo widget values may be a dictionary or legacy function type
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
values = values.filter((item: string) => check(item))
|
||||
if (!values.length && targetWidget.options.values?.length) {
|
||||
console.warn(
|
||||
@@ -211,17 +210,17 @@ export function addValueControlWidgets(
|
||||
current_index -= 1
|
||||
break
|
||||
case 'randomize':
|
||||
// @ts-ignore Combo widget values may be a dictionary or legacy function type
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
current_index = Math.floor(Math.random() * current_length)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
current_index = Math.max(0, current_index)
|
||||
// @ts-ignore Combo widget values may be a dictionary or legacy function type
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
current_index = Math.min(current_length - 1, current_index)
|
||||
if (current_index >= 0) {
|
||||
// @ts-ignore Combo widget values may be a dictionary or legacy function type
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
let value = values[current_index]
|
||||
targetWidget.value = value
|
||||
targetWidget.callback?.(value)
|
||||
|
||||
13
src/types/litegraph-augmentation.d.ts
vendored
13
src/types/litegraph-augmentation.d.ts
vendored
@@ -35,10 +35,7 @@ declare module '@comfyorg/litegraph/dist/types/widgets' {
|
||||
onRemove?: () => void
|
||||
beforeQueued?: () => unknown
|
||||
afterQueued?: () => unknown
|
||||
serializeValue?: (
|
||||
node: LGraphNode,
|
||||
index: number
|
||||
) => Promise<unknown> | unknown
|
||||
serializeValue?(node: LGraphNode, index: number): Promise<unknown> | unknown
|
||||
|
||||
/**
|
||||
* Refreshes the widget's value or options from its remote source.
|
||||
@@ -66,6 +63,14 @@ declare module '@comfyorg/litegraph' {
|
||||
new (): T
|
||||
}
|
||||
|
||||
interface TextWidget {
|
||||
dynamicPrompts?: boolean
|
||||
}
|
||||
|
||||
interface BaseWidget {
|
||||
serializeValue?(node: LGraphNode, index: number): Promise<unknown> | unknown
|
||||
}
|
||||
|
||||
interface LGraphNode {
|
||||
constructor: LGraphNodeConstructor
|
||||
|
||||
|
||||
@@ -35,11 +35,9 @@ export function isAudioNode(node: LGraphNode | undefined): boolean {
|
||||
export function addToComboValues(widget: IComboWidget, value: string) {
|
||||
if (!widget.options) widget.options = { values: [] }
|
||||
if (!widget.options.values) widget.options.values = []
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore Combo widget values may be a dictionary or legacy function type
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
if (!widget.options.values.includes(value)) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore Combo widget values may be a dictionary or legacy function type
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
widget.options.values.push(value)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user