[Refactor] useStringWidget composable (#2503)

This commit is contained in:
Chenlei Hu
2025-02-10 19:49:00 -05:00
committed by GitHub
parent 46428cbf7d
commit b4c59ffae1
4 changed files with 99 additions and 71 deletions

View File

@@ -0,0 +1,90 @@
import type { IWidget, LGraphNode } from '@comfyorg/litegraph'
import { useSettingStore } from '@/stores/settingStore'
import type { ComfyApp } from '@/types'
import type { InputSpec } from '@/types/apiTypes'
function addMultilineWidget(
node: LGraphNode,
name: string,
opts: { defaultVal: string; placeholder?: string },
app: ComfyApp
) {
const inputEl = document.createElement('textarea')
inputEl.className = 'comfy-multiline-input'
inputEl.value = opts.defaultVal
inputEl.placeholder = opts.placeholder || name
if (app.vueAppReady) {
inputEl.spellcheck = useSettingStore().get(
'Comfy.TextareaWidget.Spellcheck'
)
}
const widget = node.addDOMWidget(name, 'customtext', inputEl, {
getValue(): string {
return inputEl.value
},
setValue(v: string) {
inputEl.value = v
}
})
widget.inputEl = inputEl
inputEl.addEventListener('input', () => {
widget.callback?.(widget.value)
})
inputEl.addEventListener('pointerdown', (event: PointerEvent) => {
if (event.button === 1) {
app.canvas.processMouseDown(event)
}
})
inputEl.addEventListener('pointermove', (event: PointerEvent) => {
if ((event.buttons & 4) === 4) {
app.canvas.processMouseMove(event)
}
})
inputEl.addEventListener('pointerup', (event: PointerEvent) => {
if (event.button === 1) {
app.canvas.processMouseUp(event)
}
})
return { minWidth: 400, minHeight: 200, widget }
}
export const useStringWidget = () => {
const widgetConstructor = (
node: LGraphNode,
inputName: string,
inputData: InputSpec,
app: ComfyApp
) => {
const defaultVal = inputData[1].default || ''
const multiline = !!inputData[1].multiline
let res: { widget: IWidget }
if (multiline) {
res = addMultilineWidget(
node,
inputName,
{ defaultVal, ...inputData[1] },
app
)
} else {
res = {
widget: node.addWidget('text', inputName, defaultVal, () => {}, {})
}
}
if (inputData[1].dynamicPrompts != undefined)
res.widget.dynamicPrompts = inputData[1].dynamicPrompts
return res
}
return widgetConstructor
}

View File

@@ -10,8 +10,7 @@ useExtensionService().registerExtension({
if (node.widgets) {
// Locate dynamic prompt text widgets
// Include any widgets with dynamicPrompts set to true, and customtext
// @ts-expect-error dynamicPrompts is not typed
const widgets = node.widgets.filter((n) => n.dynamicPrompts)
const widgets = node.widgets.filter((w) => w.dynamicPrompts)
for (const widget of widgets) {
// Override the serialization of the value to resolve dynamic prompts for all widgets supporting it in this node
// @ts-expect-error hacky override

View File

@@ -15,6 +15,7 @@ import TiptapStarterKit from '@tiptap/starter-kit'
import { Markdown as TiptapMarkdown } from 'tiptap-markdown'
import { useRemoteWidget } from '@/composables/widgets/useRemoteWidget'
import { useStringWidget } from '@/composables/widgets/useStringWidget'
import { useSettingStore } from '@/stores/settingStore'
import { useToastStore } from '@/stores/toastStore'
import { useWidgetStore } from '@/stores/widgetStore'
@@ -335,52 +336,6 @@ function createIntWidget(
}
}
function addMultilineWidget(node, name: string, opts, app: ComfyApp) {
const inputEl = document.createElement('textarea')
inputEl.className = 'comfy-multiline-input'
inputEl.value = opts.defaultVal
inputEl.placeholder = opts.placeholder || name
if (app.vueAppReady) {
inputEl.spellcheck = useSettingStore().get(
'Comfy.TextareaWidget.Spellcheck'
)
}
const widget = node.addDOMWidget(name, 'customtext', inputEl, {
getValue() {
return inputEl.value
},
setValue(v) {
inputEl.value = v
}
})
widget.inputEl = inputEl
inputEl.addEventListener('input', () => {
widget.callback?.(widget.value)
})
inputEl.addEventListener('pointerdown', (event: PointerEvent) => {
if (event.button === 1) {
app.canvas.processMouseDown(event)
}
})
inputEl.addEventListener('pointermove', (event: PointerEvent) => {
if ((event.buttons & 4) === 4) {
app.canvas.processMouseMove(event)
}
})
inputEl.addEventListener('pointerup', (event: PointerEvent) => {
if (event.button === 1) {
app.canvas.processMouseUp(event)
}
})
return { minWidth: 400, minHeight: 200, widget }
}
function addMarkdownWidget(node, name: string, opts, app: ComfyApp) {
TiptapMarkdown.configure({
html: false,
@@ -528,29 +483,7 @@ export const ComfyWidgets: Record<string, ComfyWidgetConstructor> = {
widget: node.addWidget('toggle', inputName, defaultVal, () => {}, options)
}
},
STRING(node, inputName, inputData: InputSpec, app) {
const defaultVal = inputData[1].default || ''
const multiline = !!inputData[1].multiline
let res
if (multiline) {
res = addMultilineWidget(
node,
inputName,
{ defaultVal, ...inputData[1] },
app
)
} else {
res = {
widget: node.addWidget('text', inputName, defaultVal, () => {}, {})
}
}
if (inputData[1].dynamicPrompts != undefined)
res.widget.dynamicPrompts = inputData[1].dynamicPrompts
return res
},
STRING: useStringWidget(),
MARKDOWN(node, inputName, inputData: InputSpec, app) {
const defaultVal = inputData[1].default || ''

View File

@@ -17,6 +17,12 @@ declare module '@comfyorg/litegraph/dist/types/widgets' {
onRemove?: () => void
beforeQueued?: () => unknown
serializeValue?: (node: LGraphNode, index: number) => Promise<unknown>
/**
* If the widget supports dynamic prompts, this will be set to true.
* See extensions/core/dynamicPrompts.ts
*/
dynamicPrompts?: boolean
}
}