Fix bracketed paste blocking provider form submit (#818)
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
import { expect, test } from 'bun:test'
|
import { expect, test } from 'bun:test'
|
||||||
import { supportsClipboardImageFallback } from './usePasteHandler.ts'
|
import {
|
||||||
|
shouldHandleInputAsPaste,
|
||||||
|
supportsClipboardImageFallback,
|
||||||
|
} from './usePasteHandler.ts'
|
||||||
|
|
||||||
test('supports clipboard image fallback on Windows', () => {
|
test('supports clipboard image fallback on Windows', () => {
|
||||||
expect(supportsClipboardImageFallback('windows')).toBe(true)
|
expect(supportsClipboardImageFallback('windows')).toBe(true)
|
||||||
@@ -20,3 +23,42 @@ test('does not support clipboard image fallback on WSL', () => {
|
|||||||
test('does not support clipboard image fallback on unknown platforms', () => {
|
test('does not support clipboard image fallback on unknown platforms', () => {
|
||||||
expect(supportsClipboardImageFallback('unknown')).toBe(false)
|
expect(supportsClipboardImageFallback('unknown')).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('does not treat a bracketed paste as pending when no paste handlers are provided', () => {
|
||||||
|
expect(
|
||||||
|
shouldHandleInputAsPaste({
|
||||||
|
hasTextPasteHandler: false,
|
||||||
|
hasImagePasteHandler: false,
|
||||||
|
inputLength: 'kimi-k2.5'.length,
|
||||||
|
pastePending: false,
|
||||||
|
hasImageFilePath: false,
|
||||||
|
isFromPaste: true,
|
||||||
|
}),
|
||||||
|
).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('treats bracketed text paste as pending when a text paste handler exists', () => {
|
||||||
|
expect(
|
||||||
|
shouldHandleInputAsPaste({
|
||||||
|
hasTextPasteHandler: true,
|
||||||
|
hasImagePasteHandler: false,
|
||||||
|
inputLength: 'kimi-k2.5'.length,
|
||||||
|
pastePending: false,
|
||||||
|
hasImageFilePath: false,
|
||||||
|
isFromPaste: true,
|
||||||
|
}),
|
||||||
|
).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('treats image path paste as pending when only an image handler exists', () => {
|
||||||
|
expect(
|
||||||
|
shouldHandleInputAsPaste({
|
||||||
|
hasTextPasteHandler: false,
|
||||||
|
hasImagePasteHandler: true,
|
||||||
|
inputLength: 'C:\\Users\\jat\\image.png'.length,
|
||||||
|
pastePending: false,
|
||||||
|
hasImageFilePath: true,
|
||||||
|
isFromPaste: false,
|
||||||
|
}),
|
||||||
|
).toBe(true)
|
||||||
|
})
|
||||||
|
|||||||
@@ -35,6 +35,24 @@ type PasteHandlerProps = {
|
|||||||
) => void
|
) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function shouldHandleInputAsPaste(options: {
|
||||||
|
hasTextPasteHandler: boolean
|
||||||
|
hasImagePasteHandler: boolean
|
||||||
|
inputLength: number
|
||||||
|
pastePending: boolean
|
||||||
|
hasImageFilePath: boolean
|
||||||
|
isFromPaste: boolean
|
||||||
|
}): boolean {
|
||||||
|
return (
|
||||||
|
(options.hasTextPasteHandler &&
|
||||||
|
(options.inputLength > PASTE_THRESHOLD ||
|
||||||
|
options.pastePending ||
|
||||||
|
options.hasImageFilePath ||
|
||||||
|
options.isFromPaste)) ||
|
||||||
|
(options.hasImagePasteHandler && options.hasImageFilePath)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function usePasteHandler({
|
export function usePasteHandler({
|
||||||
onPaste,
|
onPaste,
|
||||||
onInput,
|
onInput,
|
||||||
@@ -236,11 +254,6 @@ export function usePasteHandler({
|
|||||||
// The keypress parser sets isPasted=true for content within bracketed paste.
|
// The keypress parser sets isPasted=true for content within bracketed paste.
|
||||||
const isFromPaste = event.keypress.isPasted
|
const isFromPaste = event.keypress.isPasted
|
||||||
|
|
||||||
// If this is pasted content, set isPasting state for UI feedback
|
|
||||||
if (isFromPaste) {
|
|
||||||
setIsPasting(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle large pastes (>PASTE_THRESHOLD chars)
|
// Handle large pastes (>PASTE_THRESHOLD chars)
|
||||||
// Usually we get one or two input characters at a time. If we
|
// Usually we get one or two input characters at a time. If we
|
||||||
// get more than the threshold, the user has probably pasted.
|
// get more than the threshold, the user has probably pasted.
|
||||||
@@ -268,6 +281,7 @@ export function usePasteHandler({
|
|||||||
canFallbackToClipboardImage &&
|
canFallbackToClipboardImage &&
|
||||||
onImagePaste
|
onImagePaste
|
||||||
) {
|
) {
|
||||||
|
setIsPasting(true)
|
||||||
checkClipboardForImage()
|
checkClipboardForImage()
|
||||||
// Reset isPasting since there's no text content to process
|
// Reset isPasting since there's no text content to process
|
||||||
setIsPasting(false)
|
setIsPasting(false)
|
||||||
@@ -275,14 +289,17 @@ export function usePasteHandler({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if we should handle as paste (from bracketed paste, large input, or continuation)
|
// Check if we should handle as paste (from bracketed paste, large input, or continuation)
|
||||||
const shouldHandleAsPaste =
|
const shouldHandleAsPaste = shouldHandleInputAsPaste({
|
||||||
onPaste &&
|
hasTextPasteHandler: Boolean(onPaste),
|
||||||
(input.length > PASTE_THRESHOLD ||
|
hasImagePasteHandler: Boolean(onImagePaste),
|
||||||
pastePendingRef.current ||
|
inputLength: input.length,
|
||||||
hasImageFilePath ||
|
pastePending: pastePendingRef.current,
|
||||||
isFromPaste)
|
hasImageFilePath,
|
||||||
|
isFromPaste,
|
||||||
|
})
|
||||||
|
|
||||||
if (shouldHandleAsPaste) {
|
if (shouldHandleAsPaste) {
|
||||||
|
setIsPasting(true)
|
||||||
pastePendingRef.current = true
|
pastePendingRef.current = true
|
||||||
setPasteState(({ chunks, timeoutId }) => {
|
setPasteState(({ chunks, timeoutId }) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user