fix(ai-toolbar): keep textarea paste on component path

This commit is contained in:
2026-04-22 23:31:46 -04:00
parent b048e34891
commit c37c39a0ba
2 changed files with 20 additions and 0 deletions

View File

@@ -241,6 +241,8 @@ export const AIToolbar = ({
// Mark that the synchronous paste event handled images so keydown // Mark that the synchronous paste event handled images so keydown
// doesn't double-fire // doesn't double-fire
const handlePasteHandled = (e: ClipboardEvent) => { const handlePasteHandled = (e: ClipboardEvent) => {
if (isEditableTarget(e.target)) return;
const images = extractAllImagesFromClipboard(e.clipboardData ?? null); const images = extractAllImagesFromClipboard(e.clipboardData ?? null);
if (images.length > 0) pasteHandledByEvent = true; if (images.length > 0) pasteHandledByEvent = true;
}; };

View File

@@ -376,6 +376,24 @@ describe("AI capture redesign", () => {
expect(onImagesSelect).toHaveBeenCalledTimes(1); expect(onImagesSelect).toHaveBeenCalledTimes(1);
}); });
test("capture-phase document paste ignores textarea targets before reading clipboard data", async () => {
await renderToolbar();
const handleCapturePaste = getDocumentListener(
"paste",
(entry) => entry.options?.capture === true,
);
expect(() =>
handleCapturePaste({
target: { tagName: "TEXTAREA", isContentEditable: false },
get clipboardData() {
throw new Error("editable paste should stay on the component path");
},
} as unknown as Event),
).not.toThrow();
});
test("document paste forwards clipboard images to onImagesSelect only for non-editable targets", async () => { test("document paste forwards clipboard images to onImagesSelect only for non-editable targets", async () => {
const onImagesSelect = mock(); const onImagesSelect = mock();
const image = new File(["image-bytes"], "clipboard.png", { const image = new File(["image-bytes"], "clipboard.png", {