fix: handle copy image from browser in linux

This commit is contained in:
Faisal Amir 2025-08-26 21:37:32 +07:00
parent b915f1f674
commit b93f77a9f5

View File

@ -381,13 +381,53 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => {
} }
const clipboardItems = e.clipboardData?.items const clipboardItems = e.clipboardData?.items
let hasProcessedImage = false
// Linux fallback: Use modern Clipboard API if clipboardData.items is unavailable // Try clipboardData.items first (traditional method)
if ( if (clipboardItems && clipboardItems.length > 0) {
!clipboardItems && const imageItems = Array.from(clipboardItems).filter((item) =>
navigator.clipboard && item.type.startsWith('image/')
'read' in navigator.clipboard )
) {
if (imageItems.length > 0) {
e.preventDefault()
const files: File[] = []
let processedCount = 0
imageItems.forEach((item) => {
const file = item.getAsFile()
if (file) {
files.push(file)
}
processedCount++
// When all items are processed, handle the valid files
if (processedCount === imageItems.length) {
if (files.length > 0) {
const syntheticEvent = {
target: {
files: files,
},
} as unknown as React.ChangeEvent<HTMLInputElement>
handleFileChange(syntheticEvent)
hasProcessedImage = true
}
}
})
// If we found image items but couldn't get files, fall through to modern API
if (processedCount === imageItems.length && !hasProcessedImage) {
// Continue to modern clipboard API fallback below
} else {
return // Successfully processed with traditional method
}
}
}
// Modern Clipboard API fallback (for Linux, images copied from web, etc.)
if (navigator.clipboard && 'read' in navigator.clipboard) {
e.preventDefault() e.preventDefault()
try { try {
@ -402,10 +442,11 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => {
for (const type of imageTypes) { for (const type of imageTypes) {
try { try {
const blob = await item.getType(type) const blob = await item.getType(type)
// Convert blob to File // Convert blob to File with better naming
const extension = type.split('/')[1] || 'png'
const file = new File( const file = new File(
[blob], [blob],
`pasted-image.${type.split('/')[1]}`, `pasted-image-${Date.now()}.${extension}`,
{ type } { type }
) )
files.push(file) files.push(file)
@ -423,47 +464,16 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => {
} as unknown as React.ChangeEvent<HTMLInputElement> } as unknown as React.ChangeEvent<HTMLInputElement>
handleFileChange(syntheticEvent) handleFileChange(syntheticEvent)
return
} }
return
} catch (error) { } catch (error) {
console.error('Error reading clipboard contents:', error) console.error('Clipboard API access failed:', error)
return
} }
} }
// Original logic for browsers with working clipboardData.items // If we reach here, no image was found or processed
if (!clipboardItems) { if (!hasProcessedImage) {
return console.log('No image data found in clipboard or clipboard access failed')
}
const imageItems = Array.from(clipboardItems).filter((item) =>
item.type.startsWith('image/')
)
if (imageItems.length > 0) {
e.preventDefault()
const files: File[] = []
let processedCount = 0
imageItems.forEach((item) => {
const file = item.getAsFile()
if (file) {
files.push(file)
}
processedCount++
// When all items are processed, handle the valid files
if (processedCount === imageItems.length && files.length > 0) {
const syntheticEvent = {
target: {
files: files,
},
} as unknown as React.ChangeEvent<HTMLInputElement>
handleFileChange(syntheticEvent)
}
})
} }
} }