Copy action and button
This commit is contained in:
Submodule litegraph updated: a1e9ae1261...93b0ed15b7
@@ -43,6 +43,7 @@
|
|||||||
"@gradio/utils": "workspace:*",
|
"@gradio/utils": "workspace:*",
|
||||||
"@litegraph-ts/core": "workspace:*",
|
"@litegraph-ts/core": "workspace:*",
|
||||||
"@litegraph-ts/nodes-basic": "workspace:*",
|
"@litegraph-ts/nodes-basic": "workspace:*",
|
||||||
|
"@litegraph-ts/nodes-events": "workspace:*",
|
||||||
"@litegraph-ts/tsconfig": "workspace:*",
|
"@litegraph-ts/tsconfig": "workspace:*",
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.1.1",
|
"@sveltejs/vite-plugin-svelte": "^2.1.1",
|
||||||
"@tsconfig/svelte": "^4.0.1",
|
"@tsconfig/svelte": "^4.0.1",
|
||||||
|
|||||||
197
pnpm-lock.yaml
generated
197
pnpm-lock.yaml
generated
@@ -37,6 +37,9 @@ importers:
|
|||||||
'@litegraph-ts/nodes-basic':
|
'@litegraph-ts/nodes-basic':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:litegraph/packages/nodes-basic
|
version: link:litegraph/packages/nodes-basic
|
||||||
|
'@litegraph-ts/nodes-events':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:litegraph/packages/nodes-events
|
||||||
'@litegraph-ts/tsconfig':
|
'@litegraph-ts/tsconfig':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:litegraph/packages/tsconfig
|
version: link:litegraph/packages/tsconfig
|
||||||
@@ -129,7 +132,7 @@ importers:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
vite:
|
vite:
|
||||||
specifier: ^2.9.9
|
specifier: ^2.9.9
|
||||||
version: 2.9.9(sass@1.61.0)
|
version: 2.9.9
|
||||||
|
|
||||||
gradio/js/accordion: {}
|
gradio/js/accordion: {}
|
||||||
|
|
||||||
@@ -694,7 +697,7 @@ importers:
|
|||||||
version: 1.0.0-next.91(@sveltejs/kit@1.15.2)
|
version: 1.0.0-next.91(@sveltejs/kit@1.15.2)
|
||||||
'@sveltejs/kit':
|
'@sveltejs/kit':
|
||||||
specifier: ^1.0.0-next.318
|
specifier: ^1.0.0-next.318
|
||||||
version: 1.15.2(svelte@3.58.0)(vite@4.3.1)
|
version: 1.15.2(svelte@3.58.0)
|
||||||
autoprefixer:
|
autoprefixer:
|
||||||
specifier: ^10.4.2
|
specifier: ^10.4.2
|
||||||
version: 10.4.2(postcss@8.4.21)
|
version: 10.4.2(postcss@8.4.21)
|
||||||
@@ -706,13 +709,13 @@ importers:
|
|||||||
version: 3.1.1
|
version: 3.1.1
|
||||||
svelte-check:
|
svelte-check:
|
||||||
specifier: ^2.2.6
|
specifier: ^2.2.6
|
||||||
version: 2.2.6(postcss-load-config@3.1.1)(postcss@8.4.21)(sass@1.61.0)(svelte@3.58.0)
|
version: 2.2.6(postcss-load-config@3.1.1)(postcss@8.4.21)(svelte@3.58.0)
|
||||||
svelte-preprocess:
|
svelte-preprocess:
|
||||||
specifier: ^4.10.1
|
specifier: ^4.10.1
|
||||||
version: 4.10.1(postcss-load-config@3.1.1)(postcss@8.4.21)(sass@1.61.0)(svelte@3.58.0)(typescript@4.5.4)
|
version: 4.10.1(postcss-load-config@3.1.1)(postcss@8.4.21)(svelte@3.58.0)(typescript@4.5.4)
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.0.12
|
specifier: ^3.0.12
|
||||||
version: 3.3.1(postcss@8.4.21)
|
version: 3.3.1
|
||||||
tslib:
|
tslib:
|
||||||
specifier: ^2.3.1
|
specifier: ^2.3.1
|
||||||
version: 2.3.1
|
version: 2.3.1
|
||||||
@@ -746,7 +749,7 @@ importers:
|
|||||||
version: 5.0.3
|
version: 5.0.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(sass@1.61.0)
|
version: 4.2.1
|
||||||
vite-plugin-checker:
|
vite-plugin-checker:
|
||||||
specifier: ^0.5.6
|
specifier: ^0.5.6
|
||||||
version: 0.5.6(eslint@8.37.0)(typescript@5.0.3)(vite@4.2.1)
|
version: 0.5.6(eslint@8.37.0)(typescript@5.0.3)(vite@4.2.1)
|
||||||
@@ -765,7 +768,23 @@ importers:
|
|||||||
version: 5.0.3
|
version: 5.0.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(sass@1.61.0)
|
version: 4.2.1
|
||||||
|
|
||||||
|
litegraph/packages/nodes-events:
|
||||||
|
dependencies:
|
||||||
|
'@litegraph-ts/core':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../core
|
||||||
|
devDependencies:
|
||||||
|
'@litegraph-ts/tsconfig':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../tsconfig
|
||||||
|
typescript:
|
||||||
|
specifier: ^5.0.3
|
||||||
|
version: 5.0.3
|
||||||
|
vite:
|
||||||
|
specifier: ^4.2.1
|
||||||
|
version: 4.3.1
|
||||||
|
|
||||||
litegraph/packages/tsconfig: {}
|
litegraph/packages/tsconfig: {}
|
||||||
|
|
||||||
@@ -1993,11 +2012,11 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@sveltejs/kit': ^1.0.0-next.587
|
'@sveltejs/kit': ^1.0.0-next.587
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/kit': 1.15.2(svelte@3.58.0)(vite@4.3.1)
|
'@sveltejs/kit': 1.15.2(svelte@3.58.0)
|
||||||
import-meta-resolve: 2.2.2
|
import-meta-resolve: 2.2.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@sveltejs/kit@1.15.2(svelte@3.58.0)(vite@4.3.1):
|
/@sveltejs/kit@1.15.2(svelte@3.58.0):
|
||||||
resolution: {integrity: sha512-rLNxZrjbrlPf8AWW8GAU4L/Vvu17e9v8EYl7pUip7x72lTft7RcxeP3z7tsrHpMSBBxC9o4XdKzFvz1vMZyXZw==}
|
resolution: {integrity: sha512-rLNxZrjbrlPf8AWW8GAU4L/Vvu17e9v8EYl7pUip7x72lTft7RcxeP3z7tsrHpMSBBxC9o4XdKzFvz1vMZyXZw==}
|
||||||
engines: {node: ^16.14 || >=18}
|
engines: {node: ^16.14 || >=18}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -2006,7 +2025,7 @@ packages:
|
|||||||
svelte: ^3.54.0
|
svelte: ^3.54.0
|
||||||
vite: ^4.0.0
|
vite: ^4.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte': 2.1.1(svelte@3.58.0)(vite@4.3.1)
|
'@sveltejs/vite-plugin-svelte': 2.1.1(svelte@3.58.0)
|
||||||
'@types/cookie': 0.5.1
|
'@types/cookie': 0.5.1
|
||||||
cookie: 0.5.0
|
cookie: 0.5.0
|
||||||
devalue: 4.3.0
|
devalue: 4.3.0
|
||||||
@@ -2020,7 +2039,24 @@ packages:
|
|||||||
svelte: 3.58.0
|
svelte: 3.58.0
|
||||||
tiny-glob: 0.2.9
|
tiny-glob: 0.2.9
|
||||||
undici: 5.20.0
|
undici: 5.20.0
|
||||||
vite: 4.3.1(@types/node@18.16.0)(sass@1.61.0)
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@sveltejs/vite-plugin-svelte@2.1.1(svelte@3.58.0):
|
||||||
|
resolution: {integrity: sha512-7YeBDt4us0FiIMNsVXxyaP4Hwyn2/v9x3oqStkHU3ZdIc5O22pGwUwH33wUqYo+7Itdmo8zxJ45Qvfm3H7UUjQ==}
|
||||||
|
engines: {node: ^14.18.0 || >= 16}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^3.54.0
|
||||||
|
vite: ^4.0.0
|
||||||
|
dependencies:
|
||||||
|
debug: 4.3.4
|
||||||
|
deepmerge: 4.3.1
|
||||||
|
kleur: 4.1.5
|
||||||
|
magic-string: 0.30.0
|
||||||
|
svelte: 3.58.0
|
||||||
|
svelte-hmr: 0.15.1(svelte@3.58.0)
|
||||||
|
vitefu: 0.2.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
@@ -2042,6 +2078,7 @@ packages:
|
|||||||
vitefu: 0.2.4(vite@4.3.1)
|
vitefu: 0.2.4(vite@4.3.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@ts-morph/common@0.18.1:
|
/@ts-morph/common@0.18.1:
|
||||||
resolution: {integrity: sha512-RVE+zSRICWRsfrkAw5qCAK+4ZH9kwEFv5h0+/YeHTLieWP7F4wWq4JsKFuNWG+fYh/KF+8rAtgdj5zb2mm+DVA==}
|
resolution: {integrity: sha512-RVE+zSRICWRsfrkAw5qCAK+4ZH9kwEFv5h0+/YeHTLieWP7F4wWq4JsKFuNWG+fYh/KF+8rAtgdj5zb2mm+DVA==}
|
||||||
@@ -4304,7 +4341,7 @@ packages:
|
|||||||
exit: 0.1.2
|
exit: 0.1.2
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
import-local: 3.1.0
|
import-local: 3.1.0
|
||||||
jest-config: 29.5.0(@types/node@18.16.0)
|
jest-config: 29.5.0
|
||||||
jest-util: 29.5.0
|
jest-util: 29.5.0
|
||||||
jest-validate: 29.5.0
|
jest-validate: 29.5.0
|
||||||
prompts: 2.4.2
|
prompts: 2.4.2
|
||||||
@@ -4315,6 +4352,44 @@ packages:
|
|||||||
- ts-node
|
- ts-node
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/jest-config@29.5.0:
|
||||||
|
resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==}
|
||||||
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/node': '*'
|
||||||
|
ts-node: '>=9.0.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/node':
|
||||||
|
optional: true
|
||||||
|
ts-node:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/core': 7.21.4
|
||||||
|
'@jest/test-sequencer': 29.5.0
|
||||||
|
'@jest/types': 29.5.0
|
||||||
|
babel-jest: 29.5.0(@babel/core@7.21.4)
|
||||||
|
chalk: 4.1.2
|
||||||
|
ci-info: 3.8.0
|
||||||
|
deepmerge: 4.3.1
|
||||||
|
glob: 7.2.3
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
jest-circus: 29.5.0
|
||||||
|
jest-environment-node: 29.5.0
|
||||||
|
jest-get-type: 29.4.3
|
||||||
|
jest-regex-util: 29.4.3
|
||||||
|
jest-resolve: 29.5.0
|
||||||
|
jest-runner: 29.5.0
|
||||||
|
jest-util: 29.5.0
|
||||||
|
jest-validate: 29.5.0
|
||||||
|
micromatch: 4.0.5
|
||||||
|
parse-json: 5.2.0
|
||||||
|
pretty-format: 29.5.0
|
||||||
|
slash: 3.0.0
|
||||||
|
strip-json-comments: 3.1.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
/jest-config@29.5.0(@types/node@18.16.0):
|
/jest-config@29.5.0(@types/node@18.16.0):
|
||||||
resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==}
|
resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
@@ -5894,7 +5969,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
/svelte-check@2.2.6(postcss-load-config@3.1.1)(postcss@8.4.21)(sass@1.61.0)(svelte@3.58.0):
|
/svelte-check@2.2.6(postcss-load-config@3.1.1)(postcss@8.4.21)(svelte@3.58.0):
|
||||||
resolution: {integrity: sha512-oJux/afbmcZO+N+ADXB88h6XANLie8Y2rh2qBlhgfkpr2c3t/q/T0w2JWrHqagaDL8zeNwO8a8RVFBkrRox8gg==}
|
resolution: {integrity: sha512-oJux/afbmcZO+N+ADXB88h6XANLie8Y2rh2qBlhgfkpr2c3t/q/T0w2JWrHqagaDL8zeNwO8a8RVFBkrRox8gg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -5908,7 +5983,7 @@ packages:
|
|||||||
sade: 1.8.1
|
sade: 1.8.1
|
||||||
source-map: 0.7.4
|
source-map: 0.7.4
|
||||||
svelte: 3.58.0
|
svelte: 3.58.0
|
||||||
svelte-preprocess: 4.10.1(postcss-load-config@3.1.1)(postcss@8.4.21)(sass@1.61.0)(svelte@3.58.0)(typescript@5.0.3)
|
svelte-preprocess: 4.10.1(postcss-load-config@3.1.1)(postcss@8.4.21)(svelte@3.58.0)(typescript@5.0.3)
|
||||||
typescript: 5.0.3
|
typescript: 5.0.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
@@ -5988,7 +6063,7 @@ packages:
|
|||||||
tiny-glob: 0.2.9
|
tiny-glob: 0.2.9
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/svelte-preprocess@4.10.1(postcss-load-config@3.1.1)(postcss@8.4.21)(sass@1.61.0)(svelte@3.58.0)(typescript@4.5.4):
|
/svelte-preprocess@4.10.1(postcss-load-config@3.1.1)(postcss@8.4.21)(svelte@3.58.0)(typescript@4.5.4):
|
||||||
resolution: {integrity: sha512-NSNloaylf+o9UeyUR2KvpdxrAyMdHl3U7rMnoP06/sG0iwJvlUM4TpMno13RaNqovh4AAoGsx1jeYcIyuGUXMw==}
|
resolution: {integrity: sha512-NSNloaylf+o9UeyUR2KvpdxrAyMdHl3U7rMnoP06/sG0iwJvlUM4TpMno13RaNqovh4AAoGsx1jeYcIyuGUXMw==}
|
||||||
engines: {node: '>= 9.11.2'}
|
engines: {node: '>= 9.11.2'}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
@@ -6035,14 +6110,13 @@ packages:
|
|||||||
magic-string: 0.25.9
|
magic-string: 0.25.9
|
||||||
postcss: 8.4.21
|
postcss: 8.4.21
|
||||||
postcss-load-config: 3.1.1
|
postcss-load-config: 3.1.1
|
||||||
sass: 1.61.0
|
|
||||||
sorcery: 0.10.0
|
sorcery: 0.10.0
|
||||||
strip-indent: 3.0.0
|
strip-indent: 3.0.0
|
||||||
svelte: 3.58.0
|
svelte: 3.58.0
|
||||||
typescript: 4.5.4
|
typescript: 4.5.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/svelte-preprocess@4.10.1(postcss-load-config@3.1.1)(postcss@8.4.21)(sass@1.61.0)(svelte@3.58.0)(typescript@5.0.3):
|
/svelte-preprocess@4.10.1(postcss-load-config@3.1.1)(postcss@8.4.21)(svelte@3.58.0)(typescript@5.0.3):
|
||||||
resolution: {integrity: sha512-NSNloaylf+o9UeyUR2KvpdxrAyMdHl3U7rMnoP06/sG0iwJvlUM4TpMno13RaNqovh4AAoGsx1jeYcIyuGUXMw==}
|
resolution: {integrity: sha512-NSNloaylf+o9UeyUR2KvpdxrAyMdHl3U7rMnoP06/sG0iwJvlUM4TpMno13RaNqovh4AAoGsx1jeYcIyuGUXMw==}
|
||||||
engines: {node: '>= 9.11.2'}
|
engines: {node: '>= 9.11.2'}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
@@ -6089,7 +6163,6 @@ packages:
|
|||||||
magic-string: 0.25.9
|
magic-string: 0.25.9
|
||||||
postcss: 8.4.21
|
postcss: 8.4.21
|
||||||
postcss-load-config: 3.1.1
|
postcss-load-config: 3.1.1
|
||||||
sass: 1.61.0
|
|
||||||
sorcery: 0.10.0
|
sorcery: 0.10.0
|
||||||
strip-indent: 3.0.0
|
strip-indent: 3.0.0
|
||||||
svelte: 3.58.0
|
svelte: 3.58.0
|
||||||
@@ -6232,42 +6305,6 @@ packages:
|
|||||||
sucrase: 3.32.0
|
sucrase: 3.32.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- ts-node
|
- ts-node
|
||||||
dev: false
|
|
||||||
|
|
||||||
/tailwindcss@3.3.1(postcss@8.4.21):
|
|
||||||
resolution: {integrity: sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==}
|
|
||||||
engines: {node: '>=12.13.0'}
|
|
||||||
hasBin: true
|
|
||||||
peerDependencies:
|
|
||||||
postcss: ^8.0.9
|
|
||||||
dependencies:
|
|
||||||
arg: 5.0.2
|
|
||||||
chokidar: 3.5.3
|
|
||||||
color-name: 1.1.4
|
|
||||||
didyoumean: 1.2.2
|
|
||||||
dlv: 1.1.3
|
|
||||||
fast-glob: 3.2.12
|
|
||||||
glob-parent: 6.0.2
|
|
||||||
is-glob: 4.0.3
|
|
||||||
jiti: 1.18.2
|
|
||||||
lilconfig: 2.1.0
|
|
||||||
micromatch: 4.0.5
|
|
||||||
normalize-path: 3.0.0
|
|
||||||
object-hash: 3.0.0
|
|
||||||
picocolors: 1.0.0
|
|
||||||
postcss: 8.4.21
|
|
||||||
postcss-import: 14.1.0(postcss@8.4.21)
|
|
||||||
postcss-js: 4.0.1(postcss@8.4.21)
|
|
||||||
postcss-load-config: 3.1.4(postcss@8.4.21)
|
|
||||||
postcss-nested: 6.0.0(postcss@8.4.21)
|
|
||||||
postcss-selector-parser: 6.0.11
|
|
||||||
postcss-value-parser: 4.2.0
|
|
||||||
quick-lru: 5.1.1
|
|
||||||
resolve: 1.22.2
|
|
||||||
sucrase: 3.32.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- ts-node
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/test-exclude@6.0.0:
|
/test-exclude@6.0.0:
|
||||||
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
|
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
|
||||||
@@ -6969,7 +7006,7 @@ packages:
|
|||||||
strip-ansi: 6.0.1
|
strip-ansi: 6.0.1
|
||||||
tiny-invariant: 1.3.1
|
tiny-invariant: 1.3.1
|
||||||
typescript: 5.0.3
|
typescript: 5.0.3
|
||||||
vite: 4.2.1(sass@1.61.0)
|
vite: 4.2.1
|
||||||
vscode-languageclient: 7.0.0
|
vscode-languageclient: 7.0.0
|
||||||
vscode-languageserver: 7.0.0
|
vscode-languageserver: 7.0.0
|
||||||
vscode-languageserver-textdocument: 1.0.8
|
vscode-languageserver-textdocument: 1.0.8
|
||||||
@@ -6992,7 +7029,7 @@ packages:
|
|||||||
kolorist: 1.8.0
|
kolorist: 1.8.0
|
||||||
magic-string: 0.29.0
|
magic-string: 0.29.0
|
||||||
ts-morph: 17.0.1
|
ts-morph: 17.0.1
|
||||||
vite: 4.2.1(sass@1.61.0)
|
vite: 4.2.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- rollup
|
- rollup
|
||||||
@@ -7026,7 +7063,7 @@ packages:
|
|||||||
- typescript
|
- typescript
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite@2.9.9(sass@1.61.0):
|
/vite@2.9.9:
|
||||||
resolution: {integrity: sha512-ffaam+NgHfbEmfw/Vuh6BHKKlI/XIAhxE5QSS7gFLIngxg171mg1P3a4LSRME0z2ZU1ScxoKzphkipcYwSD5Ew==}
|
resolution: {integrity: sha512-ffaam+NgHfbEmfw/Vuh6BHKKlI/XIAhxE5QSS7gFLIngxg171mg1P3a4LSRME0z2ZU1ScxoKzphkipcYwSD5Ew==}
|
||||||
engines: {node: '>=12.2.0'}
|
engines: {node: '>=12.2.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -7046,12 +7083,11 @@ packages:
|
|||||||
postcss: 8.4.21
|
postcss: 8.4.21
|
||||||
resolve: 1.22.2
|
resolve: 1.22.2
|
||||||
rollup: 2.79.1
|
rollup: 2.79.1
|
||||||
sass: 1.61.0
|
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite@4.2.1(sass@1.61.0):
|
/vite@4.2.1:
|
||||||
resolution: {integrity: sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==}
|
resolution: {integrity: sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -7080,10 +7116,41 @@ packages:
|
|||||||
postcss: 8.4.21
|
postcss: 8.4.21
|
||||||
resolve: 1.22.2
|
resolve: 1.22.2
|
||||||
rollup: 3.21.0
|
rollup: 3.21.0
|
||||||
sass: 1.61.0
|
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
|
|
||||||
|
/vite@4.3.1:
|
||||||
|
resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==}
|
||||||
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@types/node': '>= 14'
|
||||||
|
less: '*'
|
||||||
|
sass: '*'
|
||||||
|
stylus: '*'
|
||||||
|
sugarss: '*'
|
||||||
|
terser: ^5.4.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/node':
|
||||||
|
optional: true
|
||||||
|
less:
|
||||||
|
optional: true
|
||||||
|
sass:
|
||||||
|
optional: true
|
||||||
|
stylus:
|
||||||
|
optional: true
|
||||||
|
sugarss:
|
||||||
|
optional: true
|
||||||
|
terser:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.17.18
|
||||||
|
postcss: 8.4.21
|
||||||
|
rollup: 3.21.0
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/vite@4.3.1(@types/node@18.16.0)(sass@1.61.0):
|
/vite@4.3.1(@types/node@18.16.0)(sass@1.61.0):
|
||||||
resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==}
|
resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
@@ -7150,6 +7217,15 @@ packages:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
|
|
||||||
|
/vitefu@0.2.4:
|
||||||
|
resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==}
|
||||||
|
peerDependencies:
|
||||||
|
vite: ^3.0.0 || ^4.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
vite:
|
||||||
|
optional: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
/vitefu@0.2.4(vite@4.3.1):
|
/vitefu@0.2.4(vite@4.3.1):
|
||||||
resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==}
|
resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -7159,6 +7235,7 @@ packages:
|
|||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 4.3.1(sass@1.61.0)
|
vite: 4.3.1(sass@1.61.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/vitest@0.25.8(sass@1.61.0):
|
/vitest@0.25.8(sass@1.61.0):
|
||||||
resolution: {integrity: sha512-X75TApG2wZTJn299E/TIYevr4E9/nBo1sUtZzn0Ci5oK8qnpZAZyhwg0qCeMSakGIWtc6oRwcQFyFfW14aOFWg==}
|
resolution: {integrity: sha512-X75TApG2wZTJn299E/TIYevr4E9/nBo1sUtZzn0Ci5oK8qnpZAZyhwg0qCeMSakGIWtc6oRwcQFyFfW14aOFWg==}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
packages:
|
packages:
|
||||||
- 'gradio/js/*'
|
- 'gradio/js/*'
|
||||||
- 'gradio/client/js'
|
- 'gradio/client/js'
|
||||||
- 'litegraph/packages/core'
|
- 'litegraph/packages/*'
|
||||||
- 'litegraph/packages/nodes-basic'
|
|
||||||
- 'litegraph/packages/tsconfig'
|
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ComfyApp from "$lib/components/ComfyApp.svelte"
|
import ComfyApp from "$lib/components/ComfyApp.svelte"
|
||||||
|
import { default as ComfyAppState } from "$lib/components/ComfyApp"
|
||||||
import "@litegraph-ts/core/css/litegraph.css";
|
import "@litegraph-ts/core/css/litegraph.css";
|
||||||
import "./scss/global.scss";
|
import "./scss/global.scss";
|
||||||
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
const app = new ComfyAppState();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ComfyApp/>
|
<ComfyApp {app}/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import uiState from "./stores/uiState";
|
|||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
import type ComfyGraphNode from "./nodes/ComfyGraphNode";
|
import type ComfyGraphNode from "./nodes/ComfyGraphNode";
|
||||||
import type IComfyInputSlot from "./IComfyInputSlot";
|
import type IComfyInputSlot from "./IComfyInputSlot";
|
||||||
|
import type { ComfyBackendNode } from "./nodes/ComfyBackendNode";
|
||||||
|
|
||||||
type ComfyGraphEvents = {
|
type ComfyGraphEvents = {
|
||||||
configured: (graph: LGraph) => void
|
configured: (graph: LGraph) => void
|
||||||
@@ -16,6 +17,7 @@ type ComfyGraphEvents = {
|
|||||||
cleared: () => void
|
cleared: () => void
|
||||||
beforeChange: (graph: LGraph, param: any) => void
|
beforeChange: (graph: LGraph, param: any) => void
|
||||||
afterChange: (graph: LGraph, param: any) => void
|
afterChange: (graph: LGraph, param: any) => void
|
||||||
|
afterExecute: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ComfyGraph extends LGraph {
|
export default class ComfyGraph extends LGraph {
|
||||||
@@ -42,6 +44,10 @@ export default class ComfyGraph extends LGraph {
|
|||||||
this.eventBus.emit("afterChange", graph, info);
|
this.eventBus.emit("afterChange", graph, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override onAfterExecute() {
|
||||||
|
this.eventBus.emit("afterExecute");
|
||||||
|
}
|
||||||
|
|
||||||
override onNodeAdded(node: LGraphNode, options: LGraphAddNodeOptions) {
|
override onNodeAdded(node: LGraphNode, options: LGraphAddNodeOptions) {
|
||||||
layoutState.nodeAdded(node)
|
layoutState.nodeAdded(node)
|
||||||
this.graphSync.onNodeAdded(node);
|
this.graphSync.onNodeAdded(node);
|
||||||
@@ -51,7 +57,7 @@ export default class ComfyGraph extends LGraph {
|
|||||||
&& !options.addedByDeserialize // ...and we're not trying to deserialize an existing workflow
|
&& !options.addedByDeserialize // ...and we're not trying to deserialize an existing workflow
|
||||||
&& get(uiState).autoAddUI) {
|
&& get(uiState).autoAddUI) {
|
||||||
console.debug("[ComfyGraph] AutoAdd UI")
|
console.debug("[ComfyGraph] AutoAdd UI")
|
||||||
const comfyNode = node as ComfyGraphNode;
|
const comfyNode = node as ComfyBackendNode;
|
||||||
const widgetNodesAdded = []
|
const widgetNodesAdded = []
|
||||||
for (let index = 0; index < comfyNode.inputs.length; index++) {
|
for (let index = 0; index < comfyNode.inputs.length; index++) {
|
||||||
const input = comfyNode.inputs[index];
|
const input = comfyNode.inputs[index];
|
||||||
@@ -70,7 +76,7 @@ export default class ComfyGraph extends LGraph {
|
|||||||
}
|
}
|
||||||
const dragItems = widgetNodesAdded.map(wn => get(layoutState).allItemsByNode[wn.id]?.dragItem).filter(di => di)
|
const dragItems = widgetNodesAdded.map(wn => get(layoutState).allItemsByNode[wn.id]?.dragItem).filter(di => di)
|
||||||
console.debug("[ComfyGraph] Group new widgets", dragItems)
|
console.debug("[ComfyGraph] Group new widgets", dragItems)
|
||||||
layoutState.groupItems(dragItems, comfyNode.comfyClass)
|
layoutState.groupItems(dragItems, { title: comfyNode.comfyClass })
|
||||||
}
|
}
|
||||||
|
|
||||||
console.debug("Added", node);
|
console.debug("Added", node);
|
||||||
|
|||||||
@@ -143,7 +143,7 @@
|
|||||||
gap: var(--layout-gap);
|
gap: var(--layout-gap);
|
||||||
width: var(--size-full);
|
width: var(--size-full);
|
||||||
|
|
||||||
.v-pane {
|
> :global(.block > .v-pane) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@
|
|||||||
&.vertical {
|
&.vertical {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.v-pane {
|
> :global(.block > .v-pane) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,14 @@
|
|||||||
import ComfyQueue from "./ComfyQueue.svelte";
|
import ComfyQueue from "./ComfyQueue.svelte";
|
||||||
import queueState from "$lib/stores/queueState";
|
import queueState from "$lib/stores/queueState";
|
||||||
|
|
||||||
let app: ComfyApp = undefined;
|
export let app: ComfyApp = undefined;
|
||||||
let imageViewer: ImageViewer;
|
let imageViewer: ImageViewer;
|
||||||
let queue: ComfyQueue = undefined;
|
let queue: ComfyQueue = undefined;
|
||||||
let mainElem: HTMLDivElement;
|
let mainElem: HTMLDivElement;
|
||||||
let uiPane: ComfyUIPane = undefined;
|
let uiPane: ComfyUIPane = undefined;
|
||||||
let containerElem: HTMLDivElement;
|
let containerElem: HTMLDivElement;
|
||||||
let resizeTimeout: NodeJS.Timeout | null;
|
let resizeTimeout: NodeJS.Timeout | null;
|
||||||
|
let hasShownUIHelpToast: boolean = false;
|
||||||
|
|
||||||
let debugLayout: boolean = true;
|
let debugLayout: boolean = true;
|
||||||
|
|
||||||
@@ -44,8 +45,8 @@
|
|||||||
app.queuePrompt(0, 1);
|
app.queuePrompt(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (app) app.lCanvas.allow_dragnodes = !$uiState.nodesLocked;
|
$: if (app?.lCanvas) app.lCanvas.allow_dragnodes = !$uiState.nodesLocked;
|
||||||
$: if (app) app.lCanvas.allow_interaction = !$uiState.graphLocked;
|
$: if (app?.lCanvas) app.lCanvas.allow_interaction = !$uiState.graphLocked;
|
||||||
|
|
||||||
$: if ($uiState.uiEditMode)
|
$: if ($uiState.uiEditMode)
|
||||||
$layoutState.currentSelection = []
|
$layoutState.currentSelection = []
|
||||||
@@ -98,27 +99,26 @@
|
|||||||
app.lCanvas.recenter();
|
app.lCanvas.recenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
$: if ($uiState.uiEditMode !== "disabled" && !hasShownUIHelpToast) {
|
||||||
app = new ComfyApp();
|
hasShownUIHelpToast = true;
|
||||||
|
toast.push("Right-click to open context menu.")
|
||||||
|
}
|
||||||
|
|
||||||
if (debugLayout) {
|
if (debugLayout) {
|
||||||
layoutState.subscribe(s => {
|
layoutState.subscribe(s => {
|
||||||
console.warn("UPDATESTATE", s)
|
console.warn("UPDATESTATE", s)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
app.api.addEventListener("status", (ev: CustomEvent) => {
|
app.api.addEventListener("status", (ev: CustomEvent) => {
|
||||||
queueState.statusUpdated(ev.detail as ComfyAPIStatus);
|
queueState.statusUpdated(ev.detail as ComfyAPIStatus);
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.setup();
|
|
||||||
(window as any).app = app;
|
|
||||||
(window as any).appPane = uiPane;
|
|
||||||
|
|
||||||
refreshView();
|
|
||||||
|
|
||||||
|
$: if (app.rootEl && !imageViewer) {
|
||||||
imageViewer = new ImageViewer(app.rootEl);
|
imageViewer = new ImageViewer(app.rootEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (containerElem) {
|
||||||
let wrappers = containerElem.querySelectorAll<HTMLDivElement>(".pane-wrapper")
|
let wrappers = containerElem.querySelectorAll<HTMLDivElement>(".pane-wrapper")
|
||||||
for (const wrapper of wrappers) {
|
for (const wrapper of wrappers) {
|
||||||
const paneNode = wrapper.parentNode as HTMLElement; // get the node inside the <Pane/>
|
const paneNode = wrapper.parentNode as HTMLElement; // get the node inside the <Pane/>
|
||||||
@@ -126,6 +126,14 @@
|
|||||||
app.resizeCanvas()
|
app.resizeCanvas()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
await app.setup();
|
||||||
|
(window as any).app = app;
|
||||||
|
(window as any).appPane = uiPane;
|
||||||
|
|
||||||
|
refreshView();
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { LiteGraph, LGraph, LGraphCanvas, LGraphNode, type LGraphNodeConstructor, type LGraphNodeExecutable, type SerializedLGraph, type SerializedLGraphGroup, type SerializedLGraphNode, type SerializedLLink, NodeMode, type Vector2 } from "@litegraph-ts/core";
|
import { LiteGraph, LGraph, LGraphCanvas, LGraphNode, type LGraphNodeConstructor, type LGraphNodeExecutable, type SerializedLGraph, type SerializedLGraphGroup, type SerializedLGraphNode, type SerializedLLink, NodeMode, type Vector2, BuiltInSlotType } from "@litegraph-ts/core";
|
||||||
import type { LConnectionKind, INodeSlot } from "@litegraph-ts/core";
|
import type { LConnectionKind, INodeSlot } from "@litegraph-ts/core";
|
||||||
import ComfyAPI from "$lib/api"
|
import ComfyAPI from "$lib/api"
|
||||||
import { ComfyWidgets } from "$lib/widgets"
|
import { ComfyWidgets } from "$lib/widgets"
|
||||||
@@ -9,7 +9,9 @@ import type TypedEmitter from "typed-emitter";
|
|||||||
|
|
||||||
// Import nodes
|
// Import nodes
|
||||||
import "@litegraph-ts/nodes-basic"
|
import "@litegraph-ts/nodes-basic"
|
||||||
|
import "@litegraph-ts/nodes-events"
|
||||||
import * as nodes from "$lib/nodes/index"
|
import * as nodes from "$lib/nodes/index"
|
||||||
|
|
||||||
import ComfyGraphCanvas, { type SerializedGraphCanvasState } from "$lib/ComfyGraphCanvas";
|
import ComfyGraphCanvas, { type SerializedGraphCanvasState } from "$lib/ComfyGraphCanvas";
|
||||||
import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
|
import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
|
||||||
import * as widgets from "$lib/widgets/index"
|
import * as widgets from "$lib/widgets/index"
|
||||||
@@ -20,6 +22,7 @@ import type { SerializedLayoutState } from "$lib/stores/layoutState";
|
|||||||
import layoutState from "$lib/stores/layoutState";
|
import layoutState from "$lib/stores/layoutState";
|
||||||
import { toast } from '@zerodevx/svelte-toast'
|
import { toast } from '@zerodevx/svelte-toast'
|
||||||
import ComfyGraph from "$lib/ComfyGraph";
|
import ComfyGraph from "$lib/ComfyGraph";
|
||||||
|
import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
||||||
|
|
||||||
export const COMFYBOX_SERIAL_VERSION = 1;
|
export const COMFYBOX_SERIAL_VERSION = 1;
|
||||||
|
|
||||||
@@ -61,12 +64,18 @@ export default class ComfyApp {
|
|||||||
|
|
||||||
private queueItems: QueueItem[] = [];
|
private queueItems: QueueItem[] = [];
|
||||||
private processingQueue: boolean = false;
|
private processingQueue: boolean = false;
|
||||||
|
private alreadySetup = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.api = new ComfyAPI();
|
this.api = new ComfyAPI();
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup(): Promise<void> {
|
async setup(): Promise<void> {
|
||||||
|
if (this.alreadySetup) {
|
||||||
|
console.error("Already setup")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.rootEl = document.getElementById("main") as HTMLDivElement;
|
this.rootEl = document.getElementById("main") as HTMLDivElement;
|
||||||
this.canvasEl = document.getElementById("graph-canvas") as HTMLCanvasElement;
|
this.canvasEl = document.getElementById("graph-canvas") as HTMLCanvasElement;
|
||||||
this.lGraph = new ComfyGraph();
|
this.lGraph = new ComfyGraph();
|
||||||
@@ -76,11 +85,7 @@ export default class ComfyApp {
|
|||||||
LiteGraph.release_link_on_empty_shows_menu = true;
|
LiteGraph.release_link_on_empty_shows_menu = true;
|
||||||
LiteGraph.alt_drag_do_clone_nodes = true;
|
LiteGraph.alt_drag_do_clone_nodes = true;
|
||||||
|
|
||||||
this.lGraph.start();
|
|
||||||
|
|
||||||
// await this.#invokeExtensionsAsync("init");
|
// await this.#invokeExtensionsAsync("init");
|
||||||
this.registerNodeTypeOverrides();
|
|
||||||
this.registerWidgetTypeOverrides();
|
|
||||||
await this.registerNodes();
|
await this.registerNodes();
|
||||||
|
|
||||||
// Load previous workflow
|
// Load previous workflow
|
||||||
@@ -109,10 +114,7 @@ export default class ComfyApp {
|
|||||||
this.addPasteHandler();
|
this.addPasteHandler();
|
||||||
this.addKeyboardHandler();
|
this.addKeyboardHandler();
|
||||||
|
|
||||||
// Distinguish frontend/backend connections
|
this.setupColorScheme()
|
||||||
const BACKEND_TYPES = ["CLIP", "CLIP_VISION", "CLIP_VISION_OUTPUT", "CONDITIONING", "CONTROL_NET", "IMAGE", "LATENT", "MASK", "MODEL", "STYLE_MODEL", "VAE"]
|
|
||||||
for (const type of BACKEND_TYPES)
|
|
||||||
LGraphCanvas.link_type_colors[type] = "orange" // yellow
|
|
||||||
|
|
||||||
// await this.#invokeExtensionsAsync("setup");
|
// await this.#invokeExtensionsAsync("setup");
|
||||||
|
|
||||||
@@ -120,6 +122,11 @@ export default class ComfyApp {
|
|||||||
this.resizeCanvas();
|
this.resizeCanvas();
|
||||||
window.addEventListener("resize", this.resizeCanvas.bind(this));
|
window.addEventListener("resize", this.resizeCanvas.bind(this));
|
||||||
|
|
||||||
|
this.lGraph.start();
|
||||||
|
this.lGraph.eventBus.on("afterExecute", () => this.lCanvas.draw(true))
|
||||||
|
|
||||||
|
this.alreadySetup = true;
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,32 +144,14 @@ export default class ComfyApp {
|
|||||||
localStorage.setItem("workflow", json)
|
localStorage.setItem("workflow", json)
|
||||||
}
|
}
|
||||||
|
|
||||||
static node_type_overrides: Record<string, typeof ComfyGraphNode> = {}
|
static node_type_overrides: Record<string, typeof ComfyBackendNode> = {}
|
||||||
static widget_type_overrides: Record<string, typeof SvelteComponentDev> = {}
|
static widget_type_overrides: Record<string, typeof SvelteComponentDev> = {}
|
||||||
|
|
||||||
private registerNodeTypeOverrides() {
|
|
||||||
ComfyApp.node_type_overrides["SaveImage"] = nodes.ComfySaveImageNode;
|
|
||||||
ComfyApp.node_type_overrides["PreviewImage"] = nodes.ComfyPreviewImageNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private registerWidgetTypeOverrides() {
|
|
||||||
ComfyApp.widget_type_overrides["comfy/gallery"] = widgets.ComfyGalleryWidget_Svelte;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async registerNodes() {
|
private async registerNodes() {
|
||||||
const app = this;
|
const app = this;
|
||||||
|
|
||||||
// Load node definitions from the backend
|
// Load node definitions from the backend
|
||||||
const defs = await this.api.getNodeDefs();
|
const defs = await this.api.getNodeDefs();
|
||||||
// await this.#invokeExtensionsAsync("addCustomNodeDefs", defs);
|
|
||||||
|
|
||||||
// Generate list of known widgets
|
|
||||||
const widgets = ComfyWidgets;
|
|
||||||
// const widgets = Object.assign(
|
|
||||||
// {},
|
|
||||||
// ComfyWidgets,
|
|
||||||
// ...(await this.#invokeExtensionsAsync("getCustomWidgets")).filter(Boolean)
|
|
||||||
// );
|
|
||||||
|
|
||||||
// Register a node for each definition
|
// Register a node for each definition
|
||||||
for (const nodeId in defs) {
|
for (const nodeId in defs) {
|
||||||
@@ -171,60 +160,11 @@ export default class ComfyApp {
|
|||||||
const typeOverride = ComfyApp.node_type_overrides[nodeId]
|
const typeOverride = ComfyApp.node_type_overrides[nodeId]
|
||||||
if (typeOverride)
|
if (typeOverride)
|
||||||
console.debug("Attaching custom type to received node:", nodeId, typeOverride)
|
console.debug("Attaching custom type to received node:", nodeId, typeOverride)
|
||||||
const baseClass: typeof LGraphNode = typeOverride || LGraphNode;
|
const baseClass: typeof ComfyBackendNode = typeOverride || ComfyBackendNode;
|
||||||
|
|
||||||
const ctor = class extends baseClass {
|
const ctor = class extends baseClass {
|
||||||
constructor(title?: string) {
|
constructor(title?: string) {
|
||||||
super(title);
|
super(title, nodeId, nodeData);
|
||||||
this.type = nodeId; // XXX: workaround dependency in LGraphNode.addInput()
|
|
||||||
(this as any).comfyClass = nodeId;
|
|
||||||
(this as any).isBackendNode = true;
|
|
||||||
const color = LGraphCanvas.node_colors["yellow"];
|
|
||||||
this.color = color.color
|
|
||||||
this.bgColor = color.bgColor
|
|
||||||
var inputs = nodeData["input"]["required"];
|
|
||||||
if (nodeData["input"]["optional"] != undefined) {
|
|
||||||
inputs = Object.assign({}, nodeData["input"]["required"], nodeData["input"]["optional"])
|
|
||||||
}
|
|
||||||
const config = { minWidth: 1, minHeight: 1 };
|
|
||||||
for (const inputName in inputs) {
|
|
||||||
const inputData = inputs[inputName];
|
|
||||||
const type = inputData[0];
|
|
||||||
|
|
||||||
if (inputData[1]?.forceInput) {
|
|
||||||
this.addInput(inputName, type);
|
|
||||||
} else {
|
|
||||||
if (Array.isArray(type)) {
|
|
||||||
// Enums
|
|
||||||
Object.assign(config, widgets.COMBO(this, inputName, inputData, app) || {});
|
|
||||||
} else if (`${type}:${inputName}` in widgets) {
|
|
||||||
// Support custom widgets by Type:Name
|
|
||||||
Object.assign(config, widgets[`${type}:${inputName}`](this, inputName, inputData, app) || {});
|
|
||||||
} else if (type in widgets) {
|
|
||||||
// Standard type widgets
|
|
||||||
Object.assign(config, widgets[type](this, inputName, inputData, app) || {});
|
|
||||||
} else {
|
|
||||||
// Node connection inputs (backend)
|
|
||||||
this.addInput(inputName, type, { color_off: "orange", color_on: "orange" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const o in nodeData["output"]) {
|
|
||||||
const output = nodeData["output"][o];
|
|
||||||
const outputName = nodeData["output_name"][o] || output;
|
|
||||||
this.addOutput(outputName, output, { color_off: "orange", color_on: "orange" });
|
|
||||||
}
|
|
||||||
|
|
||||||
const s = this.computeSize();
|
|
||||||
s[0] = Math.max(config.minWidth, s[0] * 1.5);
|
|
||||||
s[1] = Math.max(config.minHeight, s[1]);
|
|
||||||
this.size = s;
|
|
||||||
this.serialize_widgets = false;
|
|
||||||
|
|
||||||
// app.#invokeExtensionsAsync("nodeCreated", this);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,15 +175,9 @@ export default class ComfyApp {
|
|||||||
desc: `ComfyNode: ${nodeId}`
|
desc: `ComfyNode: ${nodeId}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.#addNodeContextMenuHandler(node);
|
|
||||||
// this.#addDrawBackgroundHandler(node, app);
|
|
||||||
|
|
||||||
// await this.#invokeExtensionsAsync("beforeRegisterNodeDef", node, nodeData);
|
|
||||||
LiteGraph.registerNodeType(node);
|
LiteGraph.registerNodeType(node);
|
||||||
node.category = nodeData.category;
|
node.category = nodeData.category;
|
||||||
}
|
}
|
||||||
|
|
||||||
// await this.#invokeExtensionsAsync("registerCustomNodes");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private showDropZone() {
|
private showDropZone() {
|
||||||
@@ -363,6 +297,23 @@ export default class ComfyApp {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setupColorScheme() {
|
||||||
|
const setColor = (type: any, color: string) => {
|
||||||
|
this.lCanvas.link_type_colors[type] = color
|
||||||
|
this.lCanvas.default_connection_color_byType[type] = color
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distinguish frontend/backend connections
|
||||||
|
const BACKEND_TYPES = ["CLIP", "CLIP_VISION", "CLIP_VISION_OUTPUT", "CONDITIONING", "CONTROL_NET", "IMAGE", "LATENT", "MASK", "MODEL", "STYLE_MODEL", "VAE"]
|
||||||
|
for (const type of BACKEND_TYPES) {
|
||||||
|
setColor(type, "orange")
|
||||||
|
}
|
||||||
|
|
||||||
|
setColor("OUTPUT", "rebeccapurple")
|
||||||
|
setColor(BuiltInSlotType.EVENT, "lightseagreen")
|
||||||
|
setColor(BuiltInSlotType.ACTION, "lightseagreen")
|
||||||
|
}
|
||||||
|
|
||||||
serialize(): SerializedAppState {
|
serialize(): SerializedAppState {
|
||||||
const graph = this.lGraph;
|
const graph = this.lGraph;
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,10 @@
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
function groupWidgets() {
|
function groupWidgets(horizontal: boolean) {
|
||||||
const items = layoutState.getCurrentSelection()
|
const items = layoutState.getCurrentSelection()
|
||||||
$layoutState.currentSelection = []
|
$layoutState.currentSelection = []
|
||||||
layoutState.groupItems(items)
|
layoutState.groupItems(items, { direction: horizontal ? "horizontal" : "vertical" })
|
||||||
}
|
}
|
||||||
|
|
||||||
let canUngroup = false;
|
let canUngroup = false;
|
||||||
@@ -95,8 +95,12 @@
|
|||||||
<Menu {...menuPos} on:click={closeMenu} on:clickoutside={closeMenu}>
|
<Menu {...menuPos} on:click={closeMenu} on:clickoutside={closeMenu}>
|
||||||
<MenuOption
|
<MenuOption
|
||||||
isDisabled={$layoutState.currentSelection.length === 0}
|
isDisabled={$layoutState.currentSelection.length === 0}
|
||||||
on:click={groupWidgets}
|
on:click={() => groupWidgets(false)}
|
||||||
text="Group" />
|
text="Group" />
|
||||||
|
<MenuOption
|
||||||
|
isDisabled={$layoutState.currentSelection.length === 0}
|
||||||
|
on:click={() => groupWidgets(true)}
|
||||||
|
text="Group Horizontally" />
|
||||||
<MenuOption
|
<MenuOption
|
||||||
isDisabled={!canUngroup}
|
isDisabled={!canUngroup}
|
||||||
on:click={ungroup}
|
on:click={ungroup}
|
||||||
|
|||||||
@@ -56,6 +56,9 @@
|
|||||||
.widget.selected {
|
.widget.selected {
|
||||||
background: var(--color-yellow-200);
|
background: var(--color-yellow-200);
|
||||||
}
|
}
|
||||||
|
.container.selected {
|
||||||
|
background: var(--color-yellow-400);
|
||||||
|
}
|
||||||
|
|
||||||
.is-executing {
|
.is-executing {
|
||||||
border: 3px dashed var(--color-green-600) !important;
|
border: 3px dashed var(--color-green-600) !important;
|
||||||
|
|||||||
53
src/lib/nodes/ComfyActionNodes.ts
Normal file
53
src/lib/nodes/ComfyActionNodes.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { LiteGraph, type ContextMenuItem, type LGraphNode, type Vector2, LConnectionKind, LLink, LGraphCanvas, type SlotType, TitleMode, type SlotLayout, BuiltInSlotType, type ITextWidget } from "@litegraph-ts/core";
|
||||||
|
import ComfyGraphNode from "./ComfyGraphNode";
|
||||||
|
import { Watch } from "@litegraph-ts/nodes-basic";
|
||||||
|
|
||||||
|
export interface ComfyCopyActionProperties extends Record<any, any> {
|
||||||
|
value: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ComfyCopyAction extends ComfyGraphNode {
|
||||||
|
override properties: ComfyCopyActionProperties = {
|
||||||
|
value: null
|
||||||
|
}
|
||||||
|
|
||||||
|
static slotLayout: SlotLayout = {
|
||||||
|
inputs: [
|
||||||
|
{ name: "in", type: "*" },
|
||||||
|
{ name: "copy", type: BuiltInSlotType.ACTION }
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
{ name: "out", type: "*" }
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
displayWidget: ITextWidget;
|
||||||
|
|
||||||
|
constructor(title?: string) {
|
||||||
|
super(title);
|
||||||
|
this.displayWidget = this.addWidget<ITextWidget>(
|
||||||
|
"text",
|
||||||
|
"Value",
|
||||||
|
"",
|
||||||
|
"value"
|
||||||
|
);
|
||||||
|
this.displayWidget.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
override onExecute() {
|
||||||
|
this.setProperty("value", this.getInputData(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
override onAction(action: any, param: any) {
|
||||||
|
this.setProperty("value", this.getInputData(0))
|
||||||
|
this.setOutputData(0, this.properties.value)
|
||||||
|
console.log("setData", this.properties.value)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LiteGraph.registerNodeType({
|
||||||
|
class: ComfyCopyAction,
|
||||||
|
title: "Comfy.CopyAction",
|
||||||
|
desc: "Copies its input to its output when an event is received",
|
||||||
|
type: "actions/copy"
|
||||||
|
})
|
||||||
92
src/lib/nodes/ComfyBackendNode.ts
Normal file
92
src/lib/nodes/ComfyBackendNode.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import LGraphCanvas from "@litegraph-ts/core/src/LGraphCanvas";
|
||||||
|
import ComfyGraphNode from "./ComfyGraphNode";
|
||||||
|
import ComfyWidgets from "$lib/widgets"
|
||||||
|
import type { ComfyWidgetNode } from "./ComfyWidgetNodes";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Base class for any node with configuration sent by the backend.
|
||||||
|
*/
|
||||||
|
export class ComfyBackendNode extends ComfyGraphNode {
|
||||||
|
comfyClass: string;
|
||||||
|
|
||||||
|
constructor(title: string, comfyClass: string, nodeData: any) {
|
||||||
|
super(title)
|
||||||
|
this.type = comfyClass; // XXX: workaround dependency in LGraphNode.addInput()
|
||||||
|
this.comfyClass = comfyClass;
|
||||||
|
this.isBackendNode = true;
|
||||||
|
|
||||||
|
const color = LGraphCanvas.node_colors["yellow"];
|
||||||
|
this.color = color.color
|
||||||
|
this.bgColor = color.bgColor
|
||||||
|
|
||||||
|
this.setup(nodeData)
|
||||||
|
|
||||||
|
// ComfyUI has no obvious way to identify if a node will return outputs back to the frontend based on its properties.
|
||||||
|
// It just returns a hash like { "ui": { "images": results } } internally.
|
||||||
|
// So this will need to be hardcoded for now.
|
||||||
|
if (["PreviewImage", "SaveImage"].indexOf(comfyClass) !== -1) {
|
||||||
|
this.addOutput("output", "OUTPUT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setup(nodeData: any) {
|
||||||
|
var inputs = nodeData["input"]["required"];
|
||||||
|
if (nodeData["input"]["optional"] != undefined) {
|
||||||
|
inputs = Object.assign({}, nodeData["input"]["required"], nodeData["input"]["optional"])
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = { minWidth: 1, minHeight: 1 };
|
||||||
|
for (const inputName in inputs) {
|
||||||
|
const inputData = inputs[inputName];
|
||||||
|
const type = inputData[0];
|
||||||
|
|
||||||
|
if (inputData[1]?.forceInput) {
|
||||||
|
this.addInput(inputName, type);
|
||||||
|
} else {
|
||||||
|
if (Array.isArray(type)) {
|
||||||
|
// Enums
|
||||||
|
Object.assign(config, ComfyWidgets.COMBO(this, inputName, inputData) || {});
|
||||||
|
} else if (`${type}:${inputName}` in ComfyWidgets) {
|
||||||
|
// Support custom ComfyWidgets by Type:Name
|
||||||
|
Object.assign(config, ComfyWidgets[`${type}:${inputName}`](this, inputName, inputData) || {});
|
||||||
|
} else if (type in ComfyWidgets) {
|
||||||
|
// Standard type ComfyWidgets
|
||||||
|
Object.assign(config, ComfyWidgets[type](this, inputName, inputData) || {});
|
||||||
|
} else {
|
||||||
|
// Node connection inputs (backend)
|
||||||
|
this.addInput(inputName, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const o in nodeData["output"]) {
|
||||||
|
const output = nodeData["output"][o];
|
||||||
|
const outputName = nodeData["output_name"][o] || output;
|
||||||
|
this.addOutput(outputName, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
const s = this.computeSize();
|
||||||
|
s[0] = Math.max(config.minWidth, s[0] * 1.5);
|
||||||
|
s[1] = Math.max(config.minHeight, s[1]);
|
||||||
|
this.size = s;
|
||||||
|
this.serialize_widgets = false;
|
||||||
|
|
||||||
|
// app.#invokeExtensionsAsync("nodeCreated", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
override onExecuted(outputData: any) {
|
||||||
|
console.warn("onExecuted outputs", outputData)
|
||||||
|
for (let index = 0; index < this.outputs.length; index++) {
|
||||||
|
const output = this.outputs[index]
|
||||||
|
if (output.type === "OUTPUT") {
|
||||||
|
this.setOutputData(index, outputData)
|
||||||
|
for (const node of this.getOutputNodes(index)) {
|
||||||
|
if ("receiveOutput" in node) {
|
||||||
|
const widgetNode = node as ComfyWidgetNode;
|
||||||
|
widgetNode.receiveOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ import type ComfyWidget from "$lib/components/widgets/ComfyWidget";
|
|||||||
import { LGraph, LGraphNode } from "@litegraph-ts/core";
|
import { LGraph, LGraphNode } from "@litegraph-ts/core";
|
||||||
|
|
||||||
export default class ComfyGraphNode extends LGraphNode {
|
export default class ComfyGraphNode extends LGraphNode {
|
||||||
comfyClass: string | null
|
|
||||||
isBackendNode?: boolean;
|
isBackendNode?: boolean;
|
||||||
|
|
||||||
afterQueued?(): void;
|
afterQueued?(): void;
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
import ComfyGalleryWidget, { type ComfyGalleryEntry } from "$lib/widgets/ComfyGalleryWidget";
|
|
||||||
import ComfyGraphNode from "./ComfyGraphNode";
|
|
||||||
|
|
||||||
export type ComfyImageResult = {
|
|
||||||
filename: string,
|
|
||||||
subfolder: string,
|
|
||||||
type: "output" | "temp"
|
|
||||||
}
|
|
||||||
export type ComfyImageExecOutput = {
|
|
||||||
images: ComfyImageResult[]
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Node with a single extra image output widget
|
|
||||||
*/
|
|
||||||
class ComfyImageNode extends ComfyGraphNode {
|
|
||||||
private _imageResults: Array<ComfyImageResult> = [];
|
|
||||||
private _galleryWidget: ComfyGalleryWidget;
|
|
||||||
|
|
||||||
constructor(title?: any) {
|
|
||||||
super(title)
|
|
||||||
this._galleryWidget = new ComfyGalleryWidget("Images", [], this);
|
|
||||||
this.addCustomWidget(this._galleryWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
override onExecuted(output: ComfyImageExecOutput) {
|
|
||||||
this._imageResults = Array.from(output.images); // TODO append?
|
|
||||||
const galleryItems = this._imageResults.map(r => {
|
|
||||||
// TODO
|
|
||||||
const url = "http://localhost:8188/view?"
|
|
||||||
const params = new URLSearchParams(r)
|
|
||||||
let entry: ComfyGalleryEntry = [url + params, null]
|
|
||||||
return entry
|
|
||||||
});
|
|
||||||
this._galleryWidget.addImages(galleryItems);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ComfySaveImageNode extends ComfyImageNode {
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ComfyPreviewImageNode extends ComfyImageNode {
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
import { LiteGraph, type ContextMenuItem, type LGraphNode, type Vector2, LConnectionKind, LLink, LGraphCanvas, type SlotType, TitleMode, type SlotLayout, LGraph, type INodeInputSlot, type ITextWidget, type INodeOutputSlot, type SerializedLGraphNode } from "@litegraph-ts/core";
|
import { LiteGraph, type ContextMenuItem, type LGraphNode, type Vector2, LConnectionKind, LLink, LGraphCanvas, type SlotType, TitleMode, type SlotLayout, LGraph, type INodeInputSlot, type ITextWidget, type INodeOutputSlot, type SerializedLGraphNode, BuiltInSlotType } from "@litegraph-ts/core";
|
||||||
import ComfyGraphNode from "./ComfyGraphNode";
|
import ComfyGraphNode from "./ComfyGraphNode";
|
||||||
import ComboWidget from "$lib/widgets/ComboWidget.svelte";
|
import ComboWidget from "$lib/widgets/ComboWidget.svelte";
|
||||||
import RangeWidget from "$lib/widgets/RangeWidget.svelte";
|
import RangeWidget from "$lib/widgets/RangeWidget.svelte";
|
||||||
import TextWidget from "$lib/widgets/TextWidget.svelte";
|
import TextWidget from "$lib/widgets/TextWidget.svelte";
|
||||||
|
import GalleryWidget from "$lib/widgets/GalleryWidget.svelte";
|
||||||
|
import ButtonWidget from "$lib/widgets/ButtonWidget.svelte";
|
||||||
import type { SvelteComponentDev } from "svelte/internal";
|
import type { SvelteComponentDev } from "svelte/internal";
|
||||||
import { ComfyWidgets } from "$lib/widgets";
|
|
||||||
import { Watch } from "@litegraph-ts/nodes-basic";
|
import { Watch } from "@litegraph-ts/nodes-basic";
|
||||||
import type IComfyInputSlot from "$lib/IComfyInputSlot";
|
import type IComfyInputSlot from "$lib/IComfyInputSlot";
|
||||||
import { writable, type Unsubscriber, type Writable, get } from "svelte/store";
|
import { writable, type Unsubscriber, type Writable, get } from "svelte/store";
|
||||||
import { clamp } from "$lib/utils"
|
import { clamp } from "$lib/utils"
|
||||||
import layoutState from "$lib/stores/layoutState";
|
import layoutState from "$lib/stores/layoutState";
|
||||||
|
import type { FileData as GradioFileData } from "@gradio/upload";
|
||||||
|
import queueState from "$lib/stores/queueState";
|
||||||
|
|
||||||
export interface ComfyWidgetProperties extends Record<string, any> {
|
export interface ComfyWidgetProperties extends Record<string, any> {
|
||||||
defaultValue: any
|
defaultValue: any
|
||||||
@@ -36,6 +39,10 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
|||||||
override isBackendNode = false;
|
override isBackendNode = false;
|
||||||
override serialize_widgets = true;
|
override serialize_widgets = true;
|
||||||
|
|
||||||
|
outputIndex: number = 0;
|
||||||
|
inputIndex: number = 0;
|
||||||
|
changedIndex: number = 1;
|
||||||
|
|
||||||
displayWidget: ITextWidget;
|
displayWidget: ITextWidget;
|
||||||
|
|
||||||
override size: Vector2 = [60, 40];
|
override size: Vector2 = [60, 40];
|
||||||
@@ -55,24 +62,47 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
|||||||
this.unsubscribe = this.value.subscribe(this.onValueUpdated.bind(this))
|
this.unsubscribe = this.value.subscribe(this.onValueUpdated.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
formatValue(value: any): string {
|
||||||
|
return Watch.toString(value)
|
||||||
|
}
|
||||||
|
|
||||||
private onValueUpdated(value: any) {
|
private onValueUpdated(value: any) {
|
||||||
console.debug("[Widget] valueUpdated", this, value)
|
console.debug("[Widget] valueUpdated", this, value)
|
||||||
this.displayWidget.value = Watch.toString(value)
|
this.displayWidget.value = this.formatValue(value)
|
||||||
|
|
||||||
|
if (this.outputs.length >= this.outputIndex) {
|
||||||
|
this.setOutputData(this.outputIndex, get(this.value))
|
||||||
|
}
|
||||||
|
if (this.outputs.length >= this.changedIndex) {
|
||||||
|
const changedOutput = this.outputs[this.changedIndex]
|
||||||
|
if (changedOutput.type === BuiltInSlotType.EVENT)
|
||||||
|
this.triggerSlot(this.changedIndex, "changed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(value: any) {
|
setValue(value: any) {
|
||||||
this.value.set(value)
|
this.value.set(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract validateValue(value: any): boolean;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Logic to run if this widget can be treated as output (slider, combo, text)
|
||||||
|
*/
|
||||||
override onExecute() {
|
override onExecute() {
|
||||||
// Assumption: we will have one output in the inherited class with the
|
if (this.inputs.length >= this.inputIndex) {
|
||||||
// correct type
|
const data = this.getInputData(this.inputIndex)
|
||||||
this.setOutputData(0, get(this.value))
|
if (data && this.validateValue(data)) { // TODO can "null" be a legitimate value here?
|
||||||
|
this.setValue(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.outputs.length >= this.outputIndex) {
|
||||||
|
this.setOutputData(this.outputIndex, get(this.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const outputLinks = this.getOutputLinks(0)
|
/** Called when a backend node sends a ComfyUI output over a link */
|
||||||
console.debug("[Widget] onExecute", this, outputLinks)
|
receiveOutput() {
|
||||||
|
|
||||||
// TODO send event to linked nodes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onConnectOutput(
|
onConnectOutput(
|
||||||
@@ -93,7 +123,7 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
|||||||
this.setValue(this.properties.defaultValue)
|
this.setValue(this.properties.defaultValue)
|
||||||
|
|
||||||
const widget = layoutState.findLayoutForNode(this.id)
|
const widget = layoutState.findLayoutForNode(this.id)
|
||||||
if (widget) {
|
if (widget && input.name !== "") {
|
||||||
widget.attrs.title = input.name;
|
widget.attrs.title = input.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,8 +194,12 @@ export class ComfySliderNode extends ComfyWidgetNode<number> {
|
|||||||
override svelteComponentType = RangeWidget
|
override svelteComponentType = RangeWidget
|
||||||
|
|
||||||
static slotLayout: SlotLayout = {
|
static slotLayout: SlotLayout = {
|
||||||
outputs: [
|
inputs: [
|
||||||
{ name: "value", type: "number" }
|
{ name: "value", type: "number" }
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
{ name: "value", type: "number" },
|
||||||
|
{ name: "changed", type: BuiltInSlotType.EVENT }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +207,12 @@ export class ComfySliderNode extends ComfyWidgetNode<number> {
|
|||||||
super(name, 0)
|
super(name, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override validateValue(value: any): boolean {
|
||||||
|
return typeof value === "number"
|
||||||
|
&& value >= this.properties.min
|
||||||
|
&& value <= this.properties.max
|
||||||
|
}
|
||||||
|
|
||||||
override clampOneConfig(input: IComfyInputSlot) {
|
override clampOneConfig(input: IComfyInputSlot) {
|
||||||
// this.setProperty("min", clamp(this.properties.min, input.config.min, input.config.max))
|
// this.setProperty("min", clamp(this.properties.min, input.config.min, input.config.max))
|
||||||
// this.setProperty("max", clamp(this.properties.max, input.config.max, input.config.min))
|
// this.setProperty("max", clamp(this.properties.max, input.config.max, input.config.min))
|
||||||
@@ -199,8 +239,12 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static slotLayout: SlotLayout = {
|
static slotLayout: SlotLayout = {
|
||||||
outputs: [
|
inputs: [
|
||||||
{ name: "value", type: "string" }
|
{ name: "value", type: "string" }
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
{ name: "value", type: "string" },
|
||||||
|
{ name: "changed", type: BuiltInSlotType.EVENT }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +280,12 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override validateValue(value: any): boolean {
|
||||||
|
if (typeof value !== "string")
|
||||||
|
return false;
|
||||||
|
return this.properties.values.indexOf(value) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
override clampOneConfig(input: IComfyInputSlot) {
|
override clampOneConfig(input: IComfyInputSlot) {
|
||||||
if (input.config.values.indexOf(this.properties.value) === -1) {
|
if (input.config.values.indexOf(this.properties.value) === -1) {
|
||||||
if (input.config.values.length === 0)
|
if (input.config.values.length === 0)
|
||||||
@@ -264,8 +314,12 @@ export class ComfyTextNode extends ComfyWidgetNode<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static slotLayout: SlotLayout = {
|
static slotLayout: SlotLayout = {
|
||||||
outputs: [
|
inputs: [
|
||||||
{ name: "value", type: "string" }
|
{ name: "value", type: "string" }
|
||||||
|
],
|
||||||
|
outputs: [
|
||||||
|
{ name: "value", type: "string" },
|
||||||
|
{ name: "changed", type: BuiltInSlotType.EVENT }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,6 +328,10 @@ export class ComfyTextNode extends ComfyWidgetNode<string> {
|
|||||||
constructor(name?: string) {
|
constructor(name?: string) {
|
||||||
super(name, "")
|
super(name, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override validateValue(value: any): boolean {
|
||||||
|
return typeof value === "string"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LiteGraph.registerNodeType({
|
LiteGraph.registerNodeType({
|
||||||
@@ -282,3 +340,121 @@ LiteGraph.registerNodeType({
|
|||||||
desc: "Textbox outputting a string value",
|
desc: "Textbox outputting a string value",
|
||||||
type: "ui/text"
|
type: "ui/text"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** Raw output as received from ComfyUI's backend */
|
||||||
|
export type GalleryOutput = {
|
||||||
|
images: GalleryOutputEntry[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Raw output entry as received from ComfyUI's backend */
|
||||||
|
export type GalleryOutputEntry = {
|
||||||
|
filename: string,
|
||||||
|
subfolder: string,
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComfyGalleryProperties extends ComfyWidgetProperties {
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||||
|
override properties: ComfyGalleryProperties = {
|
||||||
|
defaultValue: []
|
||||||
|
}
|
||||||
|
|
||||||
|
static slotLayout: SlotLayout = {
|
||||||
|
inputs: [
|
||||||
|
{ name: "images", type: "OUTPUT" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
override svelteComponentType = GalleryWidget
|
||||||
|
|
||||||
|
constructor(name?: string) {
|
||||||
|
super(name, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
override afterQueued() {
|
||||||
|
let queue = get(queueState)
|
||||||
|
if (!(typeof queue.queueRemaining === "number" && queue.queueRemaining > 1)) {
|
||||||
|
this.setValue([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override formatValue(value: GradioFileData[]): string {
|
||||||
|
return `Images: ${value.length}`
|
||||||
|
}
|
||||||
|
|
||||||
|
override validateValue(value: any): boolean {
|
||||||
|
return Array.isArray(value) && value.every(e => "images" in e)
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveOutput() {
|
||||||
|
const link = this.getInputLink(0)
|
||||||
|
if (link.data && "images" in link.data) {
|
||||||
|
const data = link.data as GalleryOutput
|
||||||
|
console.debug("[ComfyGalleryNode] Received output!", data)
|
||||||
|
|
||||||
|
const galleryItems: GradioFileData[] = data.images.map(r => {
|
||||||
|
// TODO configure backend URL
|
||||||
|
const url = "http://localhost:8188/view?"
|
||||||
|
const params = new URLSearchParams(r)
|
||||||
|
return {
|
||||||
|
name: null,
|
||||||
|
data: url + params
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentValue = get(this.value)
|
||||||
|
this.setValue(currentValue.concat(galleryItems))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LiteGraph.registerNodeType({
|
||||||
|
class: ComfyGalleryNode,
|
||||||
|
title: "UI.Gallery",
|
||||||
|
desc: "Gallery that shows most recent outputs",
|
||||||
|
type: "ui/gallery"
|
||||||
|
})
|
||||||
|
|
||||||
|
export interface ComfyButtonProperties extends ComfyWidgetProperties {
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ComfyButtonNode extends ComfyWidgetNode<boolean> {
|
||||||
|
override properties: ComfyButtonProperties = {
|
||||||
|
defaultValue: false,
|
||||||
|
message: "bang"
|
||||||
|
}
|
||||||
|
|
||||||
|
static slotLayout: SlotLayout = {
|
||||||
|
outputs: [
|
||||||
|
{ name: "event", type: BuiltInSlotType.EVENT },
|
||||||
|
{ name: "isClicked", type: "boolean" },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
override outputIndex = 1;
|
||||||
|
override svelteComponentType = ButtonWidget;
|
||||||
|
|
||||||
|
override validateValue(value: any): boolean {
|
||||||
|
return typeof value === "boolean"
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick() {
|
||||||
|
this.setValue(true)
|
||||||
|
this.triggerSlot(0, this.properties.message);
|
||||||
|
this.setValue(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(name?: string) {
|
||||||
|
super(name, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LiteGraph.registerNodeType({
|
||||||
|
class: ComfyButtonNode,
|
||||||
|
title: "UI.Button",
|
||||||
|
desc: "Button that triggers an event when clicked",
|
||||||
|
type: "ui/button"
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export { default as ComfyReroute } from "./ComfyReroute"
|
export { default as ComfyReroute } from "./ComfyReroute"
|
||||||
export { ComfySaveImageNode, ComfyPreviewImageNode } from "./ComfyImageNodes"
|
|
||||||
export { ComfyWidgetNode, ComfySliderNode, ComfyComboNode, ComfyTextNode } from "./ComfyWidgetNodes"
|
export { ComfyWidgetNode, ComfySliderNode, ComfyComboNode, ComfyTextNode } from "./ComfyWidgetNodes"
|
||||||
|
export { ComfyCopyAction } from "./ComfyActionNodes"
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ const ALL_ATTRIBUTES: AttributesSpecList = [
|
|||||||
export { ALL_ATTRIBUTES };
|
export { ALL_ATTRIBUTES };
|
||||||
|
|
||||||
export type Attributes = {
|
export type Attributes = {
|
||||||
direction: string,
|
direction: "horizontal" | "vertical",
|
||||||
title: string,
|
title: string,
|
||||||
showTitle: boolean,
|
showTitle: boolean,
|
||||||
classes: string
|
classes: string
|
||||||
@@ -95,7 +95,7 @@ type LayoutStateOps = {
|
|||||||
updateChildren: (parent: IDragItem, children: IDragItem[]) => IDragItem[],
|
updateChildren: (parent: IDragItem, children: IDragItem[]) => IDragItem[],
|
||||||
nodeAdded: (node: LGraphNode) => void,
|
nodeAdded: (node: LGraphNode) => void,
|
||||||
nodeRemoved: (node: LGraphNode) => void,
|
nodeRemoved: (node: LGraphNode) => void,
|
||||||
groupItems: (dragItems: IDragItem[], title: string) => ContainerLayout,
|
groupItems: (dragItems: IDragItem[], attrs?: Partial<Attributes>) => ContainerLayout,
|
||||||
ungroup: (container: ContainerLayout) => void,
|
ungroup: (container: ContainerLayout) => void,
|
||||||
getCurrentSelection: () => IDragItem[],
|
getCurrentSelection: () => IDragItem[],
|
||||||
findLayoutForNode: (nodeId: number) => IDragItem | null;
|
findLayoutForNode: (nodeId: number) => IDragItem | null;
|
||||||
@@ -265,7 +265,7 @@ function moveItem(target: IDragItem, to: ContainerLayout, index: number = -1) {
|
|||||||
|
|
||||||
if (entry.parent) {
|
if (entry.parent) {
|
||||||
const parentEntry = state.allItems[entry.parent.id];
|
const parentEntry = state.allItems[entry.parent.id];
|
||||||
const index = parentEntry.children.indexOf(target)
|
const index = parentEntry.children.findIndex(c => c.id === target.id)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
parentEntry.children.splice(index, 1)
|
parentEntry.children.splice(index, 1)
|
||||||
}
|
}
|
||||||
@@ -293,7 +293,7 @@ function getCurrentSelection(): IDragItem[] {
|
|||||||
return state.currentSelection.map(id => state.allItems[id].dragItem)
|
return state.currentSelection.map(id => state.allItems[id].dragItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
function groupItems(dragItems: IDragItem[], title: string = "Group"): ContainerLayout {
|
function groupItems(dragItems: IDragItem[], attrs: Partial<Attributes> = {}): ContainerLayout {
|
||||||
if (dragItems.length === 0)
|
if (dragItems.length === 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -305,17 +305,19 @@ function groupItems(dragItems: IDragItem[], title: string = "Group"): ContainerL
|
|||||||
|
|
||||||
let index = undefined;
|
let index = undefined;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
const indexFound = state.allItems[parent.id].children.indexOf(dragItems[0])
|
const indexFound = state.allItems[parent.id].children.findIndex(c => c.id === dragItems[0].id)
|
||||||
if (indexFound !== -1)
|
if (indexFound !== -1)
|
||||||
index = indexFound
|
index = indexFound
|
||||||
}
|
}
|
||||||
|
|
||||||
const container = addContainer(parent as ContainerLayout, { title }, index)
|
const container = addContainer(parent as ContainerLayout, attrs, index)
|
||||||
|
|
||||||
for (const item of dragItems) {
|
for (const item of dragItems) {
|
||||||
moveItem(item, container)
|
moveItem(item, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.debug("[layoutState] Grouped", container, parent, state.allItems[container.id].children, index)
|
||||||
|
|
||||||
store.set(state)
|
store.set(state)
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
@@ -331,7 +333,7 @@ function ungroup(container: ContainerLayout) {
|
|||||||
|
|
||||||
let index = undefined;
|
let index = undefined;
|
||||||
const parentChildren = state.allItems[parent.id].children;
|
const parentChildren = state.allItems[parent.id].children;
|
||||||
const indexFound = parentChildren.indexOf(container)
|
const indexFound = parentChildren.findIndex(c => c.id === container.id)
|
||||||
if (indexFound !== -1)
|
if (indexFound !== -1)
|
||||||
index = indexFound
|
index = indexFound
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import type { IWidget, LGraphNode } from "@litegraph-js/core";
|
import type { IWidget, LGraphNode } from "@litegraph-js/core";
|
||||||
import type ComfyApp from "$lib/components/ComfyApp";
|
|
||||||
import ComfyValueControlWidget from "./widgets/ComfyValueControlWidget";
|
import ComfyValueControlWidget from "./widgets/ComfyValueControlWidget";
|
||||||
import type { ComfyInputConfig } from "./IComfyInputSlot";
|
import type { ComfyInputConfig } from "./IComfyInputSlot";
|
||||||
import type IComfyInputSlot from "./IComfyInputSlot";
|
import type IComfyInputSlot from "./IComfyInputSlot";
|
||||||
import { BuiltInSlotShape } from "@litegraph-ts/core";
|
import { BuiltInSlotShape } from "@litegraph-ts/core";
|
||||||
import { ComfyComboNode, ComfySliderNode, ComfyTextNode } from "./nodes";
|
import { ComfyComboNode, ComfySliderNode, ComfyTextNode } from "./nodes";
|
||||||
|
|
||||||
type WidgetFactory = (node: LGraphNode, inputName: string, inputData: any, app: ComfyApp) => IComfyInputSlot;
|
type WidgetFactory = (node: LGraphNode, inputName: string, inputData: any) => IComfyInputSlot;
|
||||||
|
|
||||||
function getNumberDefaults(inputData: any, defaultStep: number): ComfyInputConfig {
|
function getNumberDefaults(inputData: any, defaultStep: number): ComfyInputConfig {
|
||||||
let defaultValue = inputData[1]["default"];
|
let defaultValue = inputData[1]["default"];
|
||||||
@@ -38,7 +37,7 @@ const INT: WidgetFactory = (node: LGraphNode, inputName: string, inputData: any)
|
|||||||
return addComfyInput(node, inputName, { type: "number", config, defaultWidgetNode: ComfySliderNode })
|
return addComfyInput(node, inputName, { type: "number", config, defaultWidgetNode: ComfySliderNode })
|
||||||
};
|
};
|
||||||
|
|
||||||
const STRING: WidgetFactory = (node: LGraphNode, inputName: string, inputData: any, app: ComfyApp): IComfyInputSlot => {
|
const STRING: WidgetFactory = (node: LGraphNode, inputName: string, inputData: any): IComfyInputSlot => {
|
||||||
const defaultValue = inputData[1].default || "";
|
const defaultValue = inputData[1].default || "";
|
||||||
const multiline = !!inputData[1].multiline;
|
const multiline = !!inputData[1].multiline;
|
||||||
|
|
||||||
@@ -54,13 +53,13 @@ const COMBO: WidgetFactory = (node: LGraphNode, inputName: string, inputData: an
|
|||||||
return addComfyInput(node, inputName, { type: "string", config: { values: type, defaultValue }, defaultWidgetNode: ComfyComboNode })
|
return addComfyInput(node, inputName, { type: "string", config: { values: type, defaultValue }, defaultWidgetNode: ComfyComboNode })
|
||||||
}
|
}
|
||||||
|
|
||||||
const IMAGEUPLOAD: WidgetFactory = (node: LGraphNode, inputName: string, inputData: any, app): IComfyInputSlot => {
|
const IMAGEUPLOAD: WidgetFactory = (node: LGraphNode, inputName: string, inputData: any): IComfyInputSlot => {
|
||||||
return addComfyInput(node, inputName, { type: "number", config: {} })
|
return addComfyInput(node, inputName, { type: "number", config: {} })
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WidgetRepository = Record<string, WidgetFactory>
|
export type WidgetRepository = Record<string, WidgetFactory>
|
||||||
|
|
||||||
export const ComfyWidgets: WidgetRepository = {
|
const ComfyWidgets: WidgetRepository = {
|
||||||
"INT:seed": INT,
|
"INT:seed": INT,
|
||||||
"INT:noise_seed": INT,
|
"INT:noise_seed": INT,
|
||||||
FLOAT,
|
FLOAT,
|
||||||
@@ -69,3 +68,5 @@ export const ComfyWidgets: WidgetRepository = {
|
|||||||
COMBO,
|
COMBO,
|
||||||
IMAGEUPLOAD,
|
IMAGEUPLOAD,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default ComfyWidgets
|
||||||
|
|||||||
44
src/lib/widgets/ButtonWidget.svelte
Normal file
44
src/lib/widgets/ButtonWidget.svelte
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { ComfyButtonNode } from "$lib/nodes/ComfyWidgetNodes";
|
||||||
|
import type { ComfySliderNode } from "$lib/nodes/index";
|
||||||
|
import { type WidgetLayout } from "$lib/stores/layoutState";
|
||||||
|
import { Button } from "@gradio/button";
|
||||||
|
import { get, type Writable } from "svelte/store";
|
||||||
|
export let widget: WidgetLayout | null = null;
|
||||||
|
let node: ComfyButtonNode | null = null;
|
||||||
|
let nodeValue: Writable<boolean> | null = null;
|
||||||
|
let propsChanged: Writable<boolean> | null = null;
|
||||||
|
|
||||||
|
$: widget && setNodeValue(widget);
|
||||||
|
|
||||||
|
function setNodeValue(widget: WidgetLayout) {
|
||||||
|
if (widget) {
|
||||||
|
node = widget.node as ComfyButtonNode
|
||||||
|
nodeValue = node.value;
|
||||||
|
propsChanged = node.propsChanged;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function onClick(e: MouseEvent) {
|
||||||
|
node.onClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
full_width: "100%"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="wrapper gr-button">
|
||||||
|
{#if node !== null}
|
||||||
|
<Button on:click={onClick} variant="primary" {style}>
|
||||||
|
{widget.attrs.title}
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
padding: 2px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { onMount } from "svelte";
|
|
||||||
import { ImageViewer } from "$lib/ImageViewer";
|
|
||||||
import { Block } from "@gradio/atoms";
|
|
||||||
import { Gallery } from "@gradio/gallery";
|
|
||||||
import type { Styles } from "@gradio/utils";
|
|
||||||
|
|
||||||
export let item: WidgetUIState | null = null;
|
|
||||||
let itemValue: WidgetUIStateStore | null = null; // stores must be declared at top level
|
|
||||||
|
|
||||||
$: if(item) {
|
|
||||||
itemValue = item.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
let style: Styles = {
|
|
||||||
// grid_cols: [2],
|
|
||||||
grid: [3],
|
|
||||||
// object_fit: "cover",
|
|
||||||
}
|
|
||||||
let element: HTMLDivElement;
|
|
||||||
|
|
||||||
function updateForLightbox() {
|
|
||||||
// Wait for gradio gallery to show the large preview image, if no timeout then
|
|
||||||
// the event might fire too early
|
|
||||||
setTimeout(() => {
|
|
||||||
const images = element.querySelectorAll<HTMLImageElement>('div.block div > img')
|
|
||||||
if (images != null) {
|
|
||||||
images.forEach(ImageViewer.instance.setupImageForLightbox.bind(ImageViewer.instance));
|
|
||||||
}
|
|
||||||
ImageViewer.instance.updateOnBackgroundChange();
|
|
||||||
}, 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<div class="wrapper comfy-gallery-widget gr-gallery" bind:this={element}>
|
|
||||||
{#if item && itemValue}
|
|
||||||
<Block variant="solid" padding={false}>
|
|
||||||
<Gallery
|
|
||||||
bind:value={$itemValue}
|
|
||||||
label={item.widget.name}
|
|
||||||
show_label={true}
|
|
||||||
{style}
|
|
||||||
root={""}
|
|
||||||
root_url={""}
|
|
||||||
on:select={updateForLightbox}
|
|
||||||
/>
|
|
||||||
</Block>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.wrapper {
|
|
||||||
padding: 2px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { get } from "svelte/store";
|
|
||||||
import type { WidgetPanelOptions } from "@litegraph-ts/core";
|
|
||||||
import ComfyWidget from "./ComfyWidget";
|
|
||||||
import type { ComfyImageResult } from "$lib/nodes/ComfySaveImageNode";
|
|
||||||
import queueState from "$lib/stores/queueState";
|
|
||||||
|
|
||||||
export type ComfyGalleryEntry = [string, string | null]; // <img> src and alt/title, gradio format
|
|
||||||
|
|
||||||
export interface ComfyGalleryWidgetOptions extends WidgetPanelOptions {
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class ComfyGalleryWidget extends ComfyWidget<ComfyGalleryWidgetOptions, ComfyGalleryEntry[]> {
|
|
||||||
override type = "comfy/gallery";
|
|
||||||
override isVirtual = true;
|
|
||||||
|
|
||||||
addImages(images: ComfyImageResult[]) {
|
|
||||||
this.setValue(this.value.concat(images));
|
|
||||||
}
|
|
||||||
|
|
||||||
override afterQueued() {
|
|
||||||
let queue = get(queueState)
|
|
||||||
if (!(typeof queue.queueRemaining === "number" && queue.queueRemaining > 1)) {
|
|
||||||
this.setValue([])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import type { IEnumWidget, IEnumWidgetOptions, INumberWidget, LGraphNode, WidgetPanelOptions } from "@litegraph-ts/core";
|
|
||||||
import ComfyWidget from "./ComfyWidget";
|
|
||||||
import type { ComfyImageResult } from "$lib/nodes/ComfySaveImageNode";
|
|
||||||
import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
|
|
||||||
|
|
||||||
export interface ComfyValueControlWidgetOptions extends IEnumWidgetOptions {
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class ComfyValueControlWidget extends ComfyWidget<ComfyValueControlWidgetOptions, string> {
|
|
||||||
override type = "combo";
|
|
||||||
targetWidget: INumberWidget;
|
|
||||||
|
|
||||||
constructor(name: string, value: string, node: ComfyGraphNode, targetWidget: INumberWidget) {
|
|
||||||
super(name, value, node)
|
|
||||||
this.targetWidget = targetWidget;
|
|
||||||
this.options = { values: ["fixed", "increment", "decrement", "randomize"], serialize: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
override afterQueued() {
|
|
||||||
var v = this.value;
|
|
||||||
|
|
||||||
let min = this.targetWidget.options.min;
|
|
||||||
let max = this.targetWidget.options.max;
|
|
||||||
// limit to something that javascript can handle
|
|
||||||
max = Math.min(1125899906842624, max);
|
|
||||||
min = Math.max(-1125899906842624, min);
|
|
||||||
let range = (max - min) / (this.targetWidget.options.step);
|
|
||||||
|
|
||||||
//adjust values based on valueControl Behaviour
|
|
||||||
switch (v) {
|
|
||||||
case "fixed":
|
|
||||||
break;
|
|
||||||
case "increment":
|
|
||||||
this.targetWidget.value += this.targetWidget.options.step;
|
|
||||||
break;
|
|
||||||
case "decrement":
|
|
||||||
this.targetWidget.value -= this.targetWidget.options.step;
|
|
||||||
break;
|
|
||||||
case "randomize":
|
|
||||||
this.targetWidget.value = Math.floor(Math.random() * range) * (this.targetWidget.options.step) + min;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/*check if values are over or under their respective
|
|
||||||
* ranges and set them to min or max.*/
|
|
||||||
if (this.targetWidget.value < min)
|
|
||||||
this.targetWidget.value = min;
|
|
||||||
|
|
||||||
if (this.targetWidget.value > max)
|
|
||||||
this.targetWidget.value = max;
|
|
||||||
|
|
||||||
// nodeState.widgetStateChanged(this.node.id, this.targetWidget);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
78
src/lib/widgets/GalleryWidget.svelte
Normal file
78
src/lib/widgets/GalleryWidget.svelte
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { ImageViewer } from "$lib/ImageViewer";
|
||||||
|
import { Block } from "@gradio/atoms";
|
||||||
|
import { Gallery } from "@gradio/gallery";
|
||||||
|
import type { Styles } from "@gradio/utils";
|
||||||
|
import type { WidgetLayout } from "$lib/stores/layoutState";
|
||||||
|
import type { Writable } from "svelte/store";
|
||||||
|
import type { ComfyGalleryNode } from "$lib/nodes/ComfyWidgetNodes";
|
||||||
|
import type { FileData as GradioFileData } from "@gradio/upload";
|
||||||
|
|
||||||
|
export let widget: WidgetLayout | null = null;
|
||||||
|
let node: ComfyGalleryNode | null = null;
|
||||||
|
let nodeValue: Writable<GradioFileData[]> | null = null;
|
||||||
|
let propsChanged: Writable<boolean> | null = null;
|
||||||
|
let option: number | null = null;
|
||||||
|
|
||||||
|
$: widget && setNodeValue(widget);
|
||||||
|
|
||||||
|
function setNodeValue(widget: WidgetLayout) {
|
||||||
|
if (widget) {
|
||||||
|
node = widget.node as ComfyGalleryNode
|
||||||
|
nodeValue = node.value;
|
||||||
|
propsChanged = node.propsChanged;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let style: Styles = {
|
||||||
|
// grid_cols: [2],
|
||||||
|
grid: [3],
|
||||||
|
// object_fit: "cover",
|
||||||
|
}
|
||||||
|
let element: HTMLDivElement;
|
||||||
|
|
||||||
|
function updateForLightbox() {
|
||||||
|
// Wait for gradio gallery to show the large preview image, if no timeout then
|
||||||
|
// the event might fire too early
|
||||||
|
setTimeout(() => {
|
||||||
|
const images = element.querySelectorAll<HTMLImageElement>('div.block div > img')
|
||||||
|
if (images != null) {
|
||||||
|
images.forEach(ImageViewer.instance.setupImageForLightbox.bind(ImageViewer.instance));
|
||||||
|
}
|
||||||
|
ImageViewer.instance.updateOnBackgroundChange();
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<div class="wrapper comfy-gallery-widget gr-gallery" bind:this={element}>
|
||||||
|
{#if widget && node && nodeValue}
|
||||||
|
<Block variant="solid" padding={false}>
|
||||||
|
<div class="padding">
|
||||||
|
<Gallery
|
||||||
|
bind:value={$nodeValue}
|
||||||
|
label={widget.attrs.title}
|
||||||
|
show_label={true}
|
||||||
|
{style}
|
||||||
|
root={""}
|
||||||
|
root_url={""}
|
||||||
|
on:select={updateForLightbox}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Block>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
padding: 2px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.padding {
|
||||||
|
height: 30rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper :global(button.thumbnail-lg) {
|
||||||
|
width: var(--size-32);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user