mirror of
https://github.com/gradio-app/gradio.git
synced 2024-12-15 02:11:15 +08:00
Improve pasted text behaviour in Multimodaltextbox
(#10135)
* handle pasted text as file * test * add changeset * remove unneeded test * add max_plain_text_length param --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
parent
7ca36850c9
commit
3e93740f05
6
.changeset/fair-bees-report.md
Normal file
6
.changeset/fair-bees-report.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@gradio/multimodaltextbox": minor
|
||||
"gradio": minor
|
||||
---
|
||||
|
||||
feat:Improve pasted text behaviour in `Multimodaltextbox`
|
@ -86,6 +86,7 @@ class MultimodalTextbox(FormComponent):
|
||||
rtl: bool = False,
|
||||
submit_btn: str | bool | None = True,
|
||||
stop_btn: str | bool | None = False,
|
||||
max_plain_text_length: int = 1000,
|
||||
):
|
||||
"""
|
||||
Parameters:
|
||||
@ -115,6 +116,7 @@ class MultimodalTextbox(FormComponent):
|
||||
autoscroll: If True, will automatically scroll to the bottom of the textbox when the value changes, unless the user scrolls up. If False, will not scroll to the bottom of the textbox when the value changes.
|
||||
submit_btn: If False, will not show a submit button. If a string, will use that string as the submit button text.
|
||||
stop_btn: If True, will show a stop button (useful for streaming demos). If a string, will use that string as the stop button text.
|
||||
max_plain_text_length: Maximum length of plain text in the textbox. If the text exceeds this length, the text will be pasted as a file. Default is 1000.
|
||||
"""
|
||||
self.file_types = file_types
|
||||
self.file_count = file_count
|
||||
@ -129,6 +131,7 @@ class MultimodalTextbox(FormComponent):
|
||||
self.stop_btn = stop_btn
|
||||
self.autofocus = autofocus
|
||||
self.autoscroll = autoscroll
|
||||
self.max_plain_text_length = max_plain_text_length
|
||||
|
||||
super().__init__(
|
||||
label=label,
|
||||
|
@ -52,6 +52,7 @@
|
||||
export let interactive: boolean;
|
||||
export let root: string;
|
||||
export let file_count: "single" | "multiple" | "directory";
|
||||
export let max_plain_text_length: number;
|
||||
|
||||
let dragging: boolean;
|
||||
</script>
|
||||
@ -109,5 +110,6 @@
|
||||
disabled={!interactive}
|
||||
upload={(...args) => gradio.client.upload(...args)}
|
||||
stream_handler={(...args) => gradio.client.stream(...args)}
|
||||
{max_plain_text_length}
|
||||
/>
|
||||
</Block>
|
||||
|
@ -47,6 +47,7 @@
|
||||
export let upload: Client["upload"];
|
||||
export let stream_handler: Client["stream"];
|
||||
export let file_count: "single" | "multiple" | "directory" = "multiple";
|
||||
export let max_plain_text_length = 1000;
|
||||
|
||||
let upload_component: Upload;
|
||||
let hidden_upload: HTMLInputElement;
|
||||
@ -194,9 +195,23 @@
|
||||
dispatch("submit");
|
||||
}
|
||||
|
||||
function handle_paste(event: ClipboardEvent): void {
|
||||
async function handle_paste(event: ClipboardEvent): Promise<void> {
|
||||
if (!event.clipboardData) return;
|
||||
const items = event.clipboardData.items;
|
||||
const text = event.clipboardData.getData("text");
|
||||
|
||||
if (text && text.length > max_plain_text_length) {
|
||||
event.preventDefault();
|
||||
const file = new window.File([text], "pasted_text.txt", {
|
||||
type: "text/plain",
|
||||
lastModified: Date.now()
|
||||
});
|
||||
if (upload_component) {
|
||||
upload_component.load_files([file]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (let index in items) {
|
||||
const item = items[index];
|
||||
if (item.kind === "file" && item.type.includes("image")) {
|
||||
|
@ -266,4 +266,33 @@ for (const msg_format of ["tuples", "messages"]) {
|
||||
|
||||
await expect(page.locator(".thumbnail-image")).toHaveCount(2);
|
||||
});
|
||||
|
||||
test(`message format ${msg_format} - pasting large text should create a file upload`, async ({
|
||||
page
|
||||
}) => {
|
||||
if (msg_format === "tuples") {
|
||||
await go_to_testcase(page, "tuples");
|
||||
}
|
||||
const textbox = await page.getByTestId("textbox");
|
||||
const largeText = "x".repeat(2000);
|
||||
|
||||
await textbox.focus();
|
||||
await page.evaluate((text) => {
|
||||
const dataTransfer = new DataTransfer();
|
||||
const clipboardData = new ClipboardEvent("paste", {
|
||||
clipboardData: dataTransfer,
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
dataTransfer.setData("text/plain", text);
|
||||
document.activeElement?.dispatchEvent(clipboardData);
|
||||
}, largeText);
|
||||
|
||||
await expect(page.locator(".thumbnail-item")).toBeVisible();
|
||||
const fileIcon = await page.locator(".thumbnail-item").first();
|
||||
await expect(fileIcon).toBeVisible();
|
||||
|
||||
const textboxValue = await textbox.inputValue();
|
||||
await expect(textboxValue).toBe("");
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user