mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-08 17:10:07 +00:00
108 lines
2.6 KiB
TypeScript
108 lines
2.6 KiB
TypeScript
import type { LGraphNode } from '@comfyorg/litegraph'
|
|
|
|
import { api } from '@/scripts/api'
|
|
import { useToastStore } from '@/stores/toastStore'
|
|
|
|
import { useNodeDragAndDrop } from './useNodeDragAndDrop'
|
|
import { useNodePaste } from './useNodePaste'
|
|
|
|
const ACCEPTED_IMAGE_TYPES = 'image/jpeg,image/png,image/webp'
|
|
const PASTED_IMAGE_EXPIRY_MS = 2000
|
|
|
|
const createFileInput = () => {
|
|
const fileInput = document.createElement('input')
|
|
fileInput.type = 'file'
|
|
fileInput.accept = ACCEPTED_IMAGE_TYPES
|
|
return fileInput
|
|
}
|
|
|
|
const uploadFile = async (file: File, isPasted: boolean) => {
|
|
const body = new FormData()
|
|
body.append('image', file)
|
|
if (isPasted) body.append('subfolder', 'pasted')
|
|
|
|
const resp = await api.fetchApi('/upload/image', {
|
|
method: 'POST',
|
|
body
|
|
})
|
|
|
|
if (resp.status !== 200) {
|
|
useToastStore().addAlert(resp.status + ' - ' + resp.statusText)
|
|
return
|
|
}
|
|
|
|
const data = await resp.json()
|
|
return data.subfolder ? `${data.subfolder}/${data.name}` : data.name
|
|
}
|
|
|
|
interface ImageUploadOptions {
|
|
fileFilter?: (file: File) => boolean
|
|
onUploadComplete: (paths: string[]) => void
|
|
}
|
|
|
|
export const useNodeImageUpload = (
|
|
node: LGraphNode,
|
|
options: ImageUploadOptions
|
|
) => {
|
|
const { fileFilter = () => true, onUploadComplete } = options
|
|
|
|
const isPastedFile = (file: File): boolean =>
|
|
file.name === 'image.png' &&
|
|
file.lastModified - Date.now() < PASTED_IMAGE_EXPIRY_MS
|
|
|
|
const handleUpload = async (file: File) => {
|
|
try {
|
|
const path = await uploadFile(file, isPastedFile(file))
|
|
if (!path) return
|
|
return path
|
|
} catch (error) {
|
|
useToastStore().addAlert(String(error))
|
|
}
|
|
}
|
|
|
|
// Handle drag & drop
|
|
useNodeDragAndDrop(node, {
|
|
fileFilter,
|
|
onDrop: async (files) => {
|
|
const paths = await Promise.all(files.map(handleUpload))
|
|
const validPaths = paths.filter((p): p is string => !!p)
|
|
if (validPaths.length) {
|
|
onUploadComplete(validPaths)
|
|
}
|
|
return validPaths
|
|
}
|
|
})
|
|
|
|
// Handle paste
|
|
useNodePaste(node, {
|
|
fileFilter,
|
|
onPaste: async (file) => {
|
|
const path = await handleUpload(file)
|
|
if (path) {
|
|
onUploadComplete([path])
|
|
}
|
|
return path
|
|
}
|
|
})
|
|
|
|
// Handle file input
|
|
const fileInput = createFileInput()
|
|
fileInput.onchange = async () => {
|
|
if (fileInput.files?.length) {
|
|
const paths = await Promise.all(
|
|
Array.from(fileInput.files).filter(fileFilter).map(handleUpload)
|
|
)
|
|
const validPaths = paths.filter((p): p is string => !!p)
|
|
if (validPaths.length) {
|
|
onUploadComplete(validPaths)
|
|
}
|
|
}
|
|
}
|
|
document.body.append(fileInput)
|
|
|
|
return {
|
|
fileInput,
|
|
handleUpload
|
|
}
|
|
}
|