Skip to content

Commit 7d36fdd

Browse files
feat: pressing backspace deletes last attachment when textarea is empty (#130)
1 parent 11358e3 commit 7d36fdd

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

packages/elements/__tests__/prompt-input.test.tsx

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,6 +1280,115 @@ describe("PromptInputAttachment", () => {
12801280

12811281
expect(screen.queryByText("test.txt")).not.toBeInTheDocument();
12821282
});
1283+
1284+
it("removes attachment if backspace key is pressed and textarea is empty", async () => {
1285+
const onSubmit = vi.fn();
1286+
const user = userEvent.setup();
1287+
1288+
const file1 = new File(["test1"], "first.txt", { type: "text/plain" });
1289+
const file2 = new File(["test2"], "second.txt", { type: "text/plain" });
1290+
const file3 = new File(["test3"], "third.txt", { type: "text/plain" });
1291+
1292+
const AttachmentConsumer = () => {
1293+
const attachments = usePromptInputAttachments();
1294+
return (
1295+
<>
1296+
<button onClick={() => attachments.add([file1, file2, file3])} type="button">
1297+
Add Files
1298+
</button>
1299+
<PromptInputAttachments>
1300+
{(attachment) => (
1301+
<div key={attachment.id}>{attachment.filename}</div>
1302+
)}
1303+
</PromptInputAttachments>
1304+
</>
1305+
);
1306+
};
1307+
1308+
render(
1309+
<PromptInput onSubmit={onSubmit}>
1310+
<PromptInputBody>
1311+
<AttachmentConsumer />
1312+
<PromptInputTextarea />
1313+
</PromptInputBody>
1314+
</PromptInput>
1315+
);
1316+
1317+
const textarea = screen.getByPlaceholderText(
1318+
"What would you like to know?"
1319+
) as HTMLTextAreaElement;
1320+
1321+
await user.click(screen.getByRole("button", { name: "Add Files" }));
1322+
1323+
expect(screen.getByText("first.txt")).toBeInTheDocument();
1324+
expect(screen.getByText("second.txt")).toBeInTheDocument();
1325+
expect(screen.getByText("third.txt")).toBeInTheDocument();
1326+
1327+
textarea.focus();
1328+
expect(textarea.value).toBe("");
1329+
1330+
await user.keyboard("{Backspace}");
1331+
1332+
expect(screen.getByText("first.txt")).toBeInTheDocument();
1333+
expect(screen.getByText("second.txt")).toBeInTheDocument();
1334+
expect(screen.queryByText("third.txt")).not.toBeInTheDocument();
1335+
1336+
await user.keyboard("{Backspace}");
1337+
1338+
expect(screen.getByText("first.txt")).toBeInTheDocument();
1339+
expect(screen.queryByText("second.txt")).not.toBeInTheDocument();
1340+
1341+
await user.keyboard("{Backspace}");
1342+
1343+
expect(screen.queryByText("first.txt")).not.toBeInTheDocument();
1344+
});
1345+
1346+
it("does not remove attachment when backspace key is pressed and textarea has content", async () => {
1347+
const onSubmit = vi.fn();
1348+
const user = userEvent.setup();
1349+
1350+
const file = new File(["test"], "test.txt", { type: "text/plain" });
1351+
1352+
const AttachmentConsumer = () => {
1353+
const attachments = usePromptInputAttachments();
1354+
return (
1355+
<>
1356+
<button onClick={() => attachments.add([file])} type="button">
1357+
Add File
1358+
</button>
1359+
<PromptInputAttachments>
1360+
{(attachment) => (
1361+
<div key={attachment.id}>{attachment.filename}</div>
1362+
)}
1363+
</PromptInputAttachments>
1364+
</>
1365+
);
1366+
};
1367+
1368+
render(
1369+
<PromptInput onSubmit={onSubmit}>
1370+
<PromptInputBody>
1371+
<AttachmentConsumer />
1372+
<PromptInputTextarea />
1373+
</PromptInputBody>
1374+
</PromptInput>
1375+
);
1376+
1377+
const textarea = screen.getByPlaceholderText(
1378+
"What would you like to know?"
1379+
) as HTMLTextAreaElement;
1380+
1381+
await user.click(screen.getByRole("button", { name: "Add File" }));
1382+
expect(screen.getByText("test.txt")).toBeInTheDocument();
1383+
1384+
await user.type(textarea, "Some text");
1385+
expect(textarea.value).toBe("Some text");
1386+
1387+
await user.keyboard("{Backspace}");
1388+
1389+
expect(screen.getByText("test.txt")).toBeInTheDocument();
1390+
expect(textarea.value).toBe("Some tex");
1391+
});
12831392
});
12841393

12851394
describe("PromptInputActionAddAttachments", () => {

packages/elements/src/prompt-input.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,18 @@ export const PromptInputTextarea = ({
796796
e.preventDefault();
797797
e.currentTarget.form?.requestSubmit();
798798
}
799+
800+
// Remove last attachment when Backspace is pressed and textarea is empty
801+
if (
802+
e.key === "Backspace" &&
803+
e.currentTarget.value === "" &&
804+
attachments.files.length > 0
805+
) {
806+
e.preventDefault();
807+
const lastAttachment =
808+
attachments.files[attachments.files.length - 1];
809+
attachments.remove(lastAttachment.id);
810+
}
799811
};
800812

801813
const handlePaste: ClipboardEventHandler<HTMLTextAreaElement> = (event) => {

0 commit comments

Comments
 (0)