@gradio/multimodaltextbox 0.5.6 → 0.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/Example.svelte +1 -1
- package/Index.svelte +5 -1
- package/MultimodalTextbox.test.ts +1 -2
- package/dist/Example.svelte +96 -0
- package/dist/Example.svelte.d.ts +22 -0
- package/dist/Index.svelte +104 -0
- package/dist/Index.svelte.d.ts +171 -0
- package/dist/shared/MultimodalTextbox.svelte +543 -0
- package/dist/shared/MultimodalTextbox.svelte.d.ts +60 -0
- package/dist/shared/utils.d.ts +8 -0
- package/dist/shared/utils.js +39 -0
- package/package.json +23 -12
- package/shared/MultimodalTextbox.svelte +51 -6
- package/shared/utils.ts +6 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @gradio/multimodaltextbox
|
|
2
2
|
|
|
3
|
+
## 0.6.0-beta.1
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- [#9235](https://github.com/gradio-app/gradio/pull/9235) [`f8b411f`](https://github.com/gradio-app/gradio/commit/f8b411fe282ff0316ed4abebc0a043b044bf4dd9) - Built-in submit and stop buttons in `gr.ChatInterface(multimodal=False)`, adding `submit_btn` and `stop_btn` props to `gr.Textbox()` and `gr.MultimodalText()`. Thanks @whitphx!
|
|
8
|
+
|
|
9
|
+
### Dependency updates
|
|
10
|
+
|
|
11
|
+
- @gradio/video@0.11.0-beta.1
|
|
12
|
+
- @gradio/atoms@0.8.1-beta.1
|
|
13
|
+
- @gradio/icons@0.8.0-beta.1
|
|
14
|
+
- @gradio/statustracker@0.8.0-beta.1
|
|
15
|
+
- @gradio/utils@0.7.0-beta.1
|
|
16
|
+
- @gradio/client@1.6.0-beta.1
|
|
17
|
+
- @gradio/image@0.16.0-beta.1
|
|
18
|
+
- @gradio/upload@0.12.4-beta.1
|
|
19
|
+
|
|
20
|
+
## 0.5.7-beta.0
|
|
21
|
+
|
|
22
|
+
### Fixes
|
|
23
|
+
|
|
24
|
+
- [#9163](https://github.com/gradio-app/gradio/pull/9163) [`2b6cbf2`](https://github.com/gradio-app/gradio/commit/2b6cbf25908e42cf027324e54ef2cc0baad11a91) - fix exports and generate types. Thanks @pngwn!
|
|
25
|
+
|
|
26
|
+
### Dependency updates
|
|
27
|
+
|
|
28
|
+
- @gradio/utils@0.7.0-beta.0
|
|
29
|
+
- @gradio/statustracker@0.8.0-beta.0
|
|
30
|
+
- @gradio/atoms@0.8.1-beta.0
|
|
31
|
+
- @gradio/client@1.6.0-beta.0
|
|
32
|
+
- @gradio/icons@0.8.0-beta.0
|
|
33
|
+
- @gradio/upload@0.12.4-beta.0
|
|
34
|
+
- @gradio/image@0.16.0-beta.0
|
|
35
|
+
- @gradio/video@0.11.0-beta.0
|
|
36
|
+
|
|
3
37
|
## 0.5.6
|
|
4
38
|
|
|
5
39
|
### Features
|
package/Example.svelte
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
{#if file.mime_type && file.mime_type.includes("image")}
|
|
43
43
|
<Image src={file.url} alt="" />
|
|
44
44
|
{:else if file.mime_type && file.mime_type.includes("video")}
|
|
45
|
-
<Video src={file.url} alt="" loop={true} />
|
|
45
|
+
<Video src={file.url} alt="" loop={true} is_stream={false} />
|
|
46
46
|
{:else if file.mime_type && file.mime_type.includes("audio")}
|
|
47
47
|
<audio src={file.url} controls />
|
|
48
48
|
{:else}
|
package/Index.svelte
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
export let gradio: Gradio<{
|
|
17
17
|
change: typeof value;
|
|
18
18
|
submit: never;
|
|
19
|
+
stop: never;
|
|
19
20
|
blur: never;
|
|
20
21
|
select: SelectData;
|
|
21
22
|
input: never;
|
|
@@ -40,7 +41,8 @@
|
|
|
40
41
|
export let container = true;
|
|
41
42
|
export let scale: number | null = null;
|
|
42
43
|
export let min_width: number | undefined = undefined;
|
|
43
|
-
export let submit_btn: string | null = null;
|
|
44
|
+
export let submit_btn: string | boolean | null = null;
|
|
45
|
+
export let stop_btn: string | boolean | null = null;
|
|
44
46
|
export let loading_status: LoadingStatus | undefined = undefined;
|
|
45
47
|
export let value_is_output = false;
|
|
46
48
|
export let rtl = false;
|
|
@@ -88,6 +90,7 @@
|
|
|
88
90
|
max_lines={!max_lines ? lines + 1 : max_lines}
|
|
89
91
|
{placeholder}
|
|
90
92
|
{submit_btn}
|
|
93
|
+
{stop_btn}
|
|
91
94
|
{autofocus}
|
|
92
95
|
{container}
|
|
93
96
|
{autoscroll}
|
|
@@ -96,6 +99,7 @@
|
|
|
96
99
|
on:change={() => gradio.dispatch("change", value)}
|
|
97
100
|
on:input={() => gradio.dispatch("input")}
|
|
98
101
|
on:submit={() => gradio.dispatch("submit")}
|
|
102
|
+
on:stop={() => gradio.dispatch("stop")}
|
|
99
103
|
on:blur={() => gradio.dispatch("blur")}
|
|
100
104
|
on:select={(e) => gradio.dispatch("select", e.detail)}
|
|
101
105
|
on:focus={() => gradio.dispatch("focus")}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { test, describe, assert, afterEach } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
import { cleanup, fireEvent, render, get_text, wait } from "@gradio/tootils";
|
|
2
|
+
import { cleanup, render } from "@self/tootils";
|
|
4
3
|
import event from "@testing-library/user-event";
|
|
5
4
|
|
|
6
5
|
import MultimodalTextbox from "./Index.svelte";
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<script>import { onMount } from "svelte";
|
|
2
|
+
import { Image } from "@gradio/image/shared";
|
|
3
|
+
import { Video } from "@gradio/video/shared";
|
|
4
|
+
export let value = {
|
|
5
|
+
text: "",
|
|
6
|
+
files: []
|
|
7
|
+
};
|
|
8
|
+
export let type;
|
|
9
|
+
export let selected = false;
|
|
10
|
+
let size;
|
|
11
|
+
let el;
|
|
12
|
+
function set_styles(element, el_width) {
|
|
13
|
+
if (!element || !el_width)
|
|
14
|
+
return;
|
|
15
|
+
el.style.setProperty(
|
|
16
|
+
"--local-text-width",
|
|
17
|
+
`${el_width < 150 ? el_width : 200}px`
|
|
18
|
+
);
|
|
19
|
+
el.style.whiteSpace = "unset";
|
|
20
|
+
}
|
|
21
|
+
onMount(() => {
|
|
22
|
+
set_styles(el, size);
|
|
23
|
+
});
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<div
|
|
27
|
+
class="container"
|
|
28
|
+
bind:clientWidth={size}
|
|
29
|
+
bind:this={el}
|
|
30
|
+
class:table={type === "table"}
|
|
31
|
+
class:gallery={type === "gallery"}
|
|
32
|
+
class:selected
|
|
33
|
+
class:border={value}
|
|
34
|
+
>
|
|
35
|
+
<p>{value.text ? value.text : ""}</p>
|
|
36
|
+
{#each value.files as file}
|
|
37
|
+
{#if file.mime_type && file.mime_type.includes("image")}
|
|
38
|
+
<Image src={file.url} alt="" />
|
|
39
|
+
{:else if file.mime_type && file.mime_type.includes("video")}
|
|
40
|
+
<Video src={file.url} alt="" loop={true} is_stream={false} />
|
|
41
|
+
{:else if file.mime_type && file.mime_type.includes("audio")}
|
|
42
|
+
<audio src={file.url} controls />
|
|
43
|
+
{:else}
|
|
44
|
+
{file.orig_name}
|
|
45
|
+
{/if}
|
|
46
|
+
{/each}
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<style>
|
|
50
|
+
.gallery {
|
|
51
|
+
padding: var(--size-1) var(--size-2);
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
gap: 20px;
|
|
55
|
+
overflow-x: auto;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
div {
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
min-width: var(--local-text-width);
|
|
61
|
+
white-space: nowrap;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.container :global(img),
|
|
65
|
+
.container :global(video) {
|
|
66
|
+
object-fit: contain;
|
|
67
|
+
width: 100px;
|
|
68
|
+
height: 100px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.container.selected {
|
|
72
|
+
border-color: var(--border-color-accent);
|
|
73
|
+
}
|
|
74
|
+
.border.table {
|
|
75
|
+
border: 2px solid var(--border-color-primary);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.container.table {
|
|
79
|
+
margin: 0 auto;
|
|
80
|
+
border-radius: var(--radius-lg);
|
|
81
|
+
overflow-x: auto;
|
|
82
|
+
width: max-content;
|
|
83
|
+
height: max-content;
|
|
84
|
+
object-fit: cover;
|
|
85
|
+
padding: var(--size-2);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.container.gallery {
|
|
89
|
+
object-fit: cover;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
div > :global(p) {
|
|
93
|
+
font-size: var(--text-lg);
|
|
94
|
+
white-space: normal;
|
|
95
|
+
}
|
|
96
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { FileData } from "@gradio/client";
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
value?: {
|
|
6
|
+
text: string;
|
|
7
|
+
files: FileData[];
|
|
8
|
+
} | undefined;
|
|
9
|
+
type: "gallery" | "table";
|
|
10
|
+
selected?: boolean | undefined;
|
|
11
|
+
};
|
|
12
|
+
events: {
|
|
13
|
+
[evt: string]: CustomEvent<any>;
|
|
14
|
+
};
|
|
15
|
+
slots: {};
|
|
16
|
+
};
|
|
17
|
+
export type ExampleProps = typeof __propDef.props;
|
|
18
|
+
export type ExampleEvents = typeof __propDef.events;
|
|
19
|
+
export type ExampleSlots = typeof __propDef.slots;
|
|
20
|
+
export default class Example extends SvelteComponent<ExampleProps, ExampleEvents, ExampleSlots> {
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<svelte:options accessors={true} />
|
|
2
|
+
|
|
3
|
+
<script context="module">export { default as BaseMultimodalTextbox } from "./shared/MultimodalTextbox.svelte";
|
|
4
|
+
export { default as BaseExample } from "./Example.svelte";
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script>import MultimodalTextbox from "./shared/MultimodalTextbox.svelte";
|
|
8
|
+
import { Block } from "@gradio/atoms";
|
|
9
|
+
import { StatusTracker } from "@gradio/statustracker";
|
|
10
|
+
export let gradio;
|
|
11
|
+
export let elem_id = "";
|
|
12
|
+
export let elem_classes = [];
|
|
13
|
+
export let visible = true;
|
|
14
|
+
export let value = {
|
|
15
|
+
text: "",
|
|
16
|
+
files: []
|
|
17
|
+
};
|
|
18
|
+
export let file_types = null;
|
|
19
|
+
export let lines;
|
|
20
|
+
export let placeholder = "";
|
|
21
|
+
export let label = "MultimodalTextbox";
|
|
22
|
+
export let info = void 0;
|
|
23
|
+
export let show_label;
|
|
24
|
+
export let max_lines;
|
|
25
|
+
export let container = true;
|
|
26
|
+
export let scale = null;
|
|
27
|
+
export let min_width = void 0;
|
|
28
|
+
export let submit_btn = null;
|
|
29
|
+
export let stop_btn = null;
|
|
30
|
+
export let loading_status = void 0;
|
|
31
|
+
export let value_is_output = false;
|
|
32
|
+
export let rtl = false;
|
|
33
|
+
export let text_align = void 0;
|
|
34
|
+
export let autofocus = false;
|
|
35
|
+
export let autoscroll = true;
|
|
36
|
+
export let interactive;
|
|
37
|
+
export let root;
|
|
38
|
+
export let file_count;
|
|
39
|
+
let dragging;
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<Block
|
|
43
|
+
{visible}
|
|
44
|
+
{elem_id}
|
|
45
|
+
elem_classes={[...elem_classes, "multimodal-textbox"]}
|
|
46
|
+
{scale}
|
|
47
|
+
{min_width}
|
|
48
|
+
allow_overflow={false}
|
|
49
|
+
padding={container}
|
|
50
|
+
border_mode={dragging ? "focus" : "base"}
|
|
51
|
+
>
|
|
52
|
+
{#if loading_status}
|
|
53
|
+
<StatusTracker
|
|
54
|
+
autoscroll={gradio.autoscroll}
|
|
55
|
+
i18n={gradio.i18n}
|
|
56
|
+
{...loading_status}
|
|
57
|
+
on:clear_status={() => gradio.dispatch("clear_status", loading_status)}
|
|
58
|
+
/>
|
|
59
|
+
{/if}
|
|
60
|
+
|
|
61
|
+
<MultimodalTextbox
|
|
62
|
+
bind:value
|
|
63
|
+
bind:value_is_output
|
|
64
|
+
bind:dragging
|
|
65
|
+
{file_types}
|
|
66
|
+
{root}
|
|
67
|
+
{label}
|
|
68
|
+
{info}
|
|
69
|
+
{show_label}
|
|
70
|
+
{lines}
|
|
71
|
+
{rtl}
|
|
72
|
+
{text_align}
|
|
73
|
+
max_lines={!max_lines ? lines + 1 : max_lines}
|
|
74
|
+
{placeholder}
|
|
75
|
+
{submit_btn}
|
|
76
|
+
{stop_btn}
|
|
77
|
+
{autofocus}
|
|
78
|
+
{container}
|
|
79
|
+
{autoscroll}
|
|
80
|
+
{file_count}
|
|
81
|
+
max_file_size={gradio.max_file_size}
|
|
82
|
+
on:change={() => gradio.dispatch("change", value)}
|
|
83
|
+
on:input={() => gradio.dispatch("input")}
|
|
84
|
+
on:submit={() => gradio.dispatch("submit")}
|
|
85
|
+
on:stop={() => gradio.dispatch("stop")}
|
|
86
|
+
on:blur={() => gradio.dispatch("blur")}
|
|
87
|
+
on:select={(e) => gradio.dispatch("select", e.detail)}
|
|
88
|
+
on:focus={() => gradio.dispatch("focus")}
|
|
89
|
+
on:error={({ detail }) => {
|
|
90
|
+
gradio.dispatch("error", detail);
|
|
91
|
+
}}
|
|
92
|
+
disabled={!interactive}
|
|
93
|
+
upload={gradio.client.upload}
|
|
94
|
+
stream_handler={gradio.client.stream}
|
|
95
|
+
/>
|
|
96
|
+
</Block>
|
|
97
|
+
|
|
98
|
+
<style>
|
|
99
|
+
:global(.form .block.multimodal-textbox) {
|
|
100
|
+
box-shadow: var(--block-shadow) !important;
|
|
101
|
+
border-width: var(--block-border-width) !important;
|
|
102
|
+
border-radius: var(--block-radius) !important;
|
|
103
|
+
}
|
|
104
|
+
</style>
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
export { default as BaseMultimodalTextbox } from "./shared/MultimodalTextbox.svelte";
|
|
3
|
+
export { default as BaseExample } from "./Example.svelte";
|
|
4
|
+
import type { Gradio, SelectData } from "@gradio/utils";
|
|
5
|
+
import type { LoadingStatus } from "@gradio/statustracker";
|
|
6
|
+
import type { FileData } from "@gradio/client";
|
|
7
|
+
declare const __propDef: {
|
|
8
|
+
props: {
|
|
9
|
+
gradio: Gradio<{
|
|
10
|
+
change: {
|
|
11
|
+
text: string;
|
|
12
|
+
files: FileData[];
|
|
13
|
+
};
|
|
14
|
+
submit: never;
|
|
15
|
+
stop: never;
|
|
16
|
+
blur: never;
|
|
17
|
+
select: SelectData;
|
|
18
|
+
input: never;
|
|
19
|
+
focus: never;
|
|
20
|
+
error: string;
|
|
21
|
+
clear_status: LoadingStatus;
|
|
22
|
+
}>;
|
|
23
|
+
elem_id?: string | undefined;
|
|
24
|
+
elem_classes?: string[] | undefined;
|
|
25
|
+
visible?: boolean | undefined;
|
|
26
|
+
value?: {
|
|
27
|
+
text: string;
|
|
28
|
+
files: FileData[];
|
|
29
|
+
} | undefined;
|
|
30
|
+
file_types?: (string[] | null) | undefined;
|
|
31
|
+
lines: number;
|
|
32
|
+
placeholder?: string | undefined;
|
|
33
|
+
label?: string | undefined;
|
|
34
|
+
info?: string | undefined;
|
|
35
|
+
show_label: boolean;
|
|
36
|
+
max_lines: number;
|
|
37
|
+
container?: boolean | undefined;
|
|
38
|
+
scale?: (number | null) | undefined;
|
|
39
|
+
min_width?: number | undefined;
|
|
40
|
+
submit_btn?: (string | boolean | null) | undefined;
|
|
41
|
+
stop_btn?: (string | boolean | null) | undefined;
|
|
42
|
+
loading_status?: LoadingStatus | undefined;
|
|
43
|
+
value_is_output?: boolean | undefined;
|
|
44
|
+
rtl?: boolean | undefined;
|
|
45
|
+
text_align?: "left" | "right" | undefined;
|
|
46
|
+
autofocus?: boolean | undefined;
|
|
47
|
+
autoscroll?: boolean | undefined;
|
|
48
|
+
interactive: boolean;
|
|
49
|
+
root: string;
|
|
50
|
+
file_count: "single" | "multiple" | "directory";
|
|
51
|
+
};
|
|
52
|
+
events: {
|
|
53
|
+
[evt: string]: CustomEvent<any>;
|
|
54
|
+
};
|
|
55
|
+
slots: {};
|
|
56
|
+
};
|
|
57
|
+
export type IndexProps = typeof __propDef.props;
|
|
58
|
+
export type IndexEvents = typeof __propDef.events;
|
|
59
|
+
export type IndexSlots = typeof __propDef.slots;
|
|
60
|
+
export default class Index extends SvelteComponent<IndexProps, IndexEvents, IndexSlots> {
|
|
61
|
+
get gradio(): Gradio<{
|
|
62
|
+
change: {
|
|
63
|
+
text: string;
|
|
64
|
+
files: FileData[];
|
|
65
|
+
};
|
|
66
|
+
submit: never;
|
|
67
|
+
stop: never;
|
|
68
|
+
blur: never;
|
|
69
|
+
select: SelectData;
|
|
70
|
+
input: never;
|
|
71
|
+
focus: never;
|
|
72
|
+
error: string;
|
|
73
|
+
clear_status: LoadingStatus;
|
|
74
|
+
}>;
|
|
75
|
+
/**accessor*/
|
|
76
|
+
set gradio(_: Gradio<{
|
|
77
|
+
change: {
|
|
78
|
+
text: string;
|
|
79
|
+
files: FileData[];
|
|
80
|
+
};
|
|
81
|
+
submit: never;
|
|
82
|
+
stop: never;
|
|
83
|
+
blur: never;
|
|
84
|
+
select: SelectData;
|
|
85
|
+
input: never;
|
|
86
|
+
focus: never;
|
|
87
|
+
error: string;
|
|
88
|
+
clear_status: LoadingStatus;
|
|
89
|
+
}>);
|
|
90
|
+
get elem_id(): string | undefined;
|
|
91
|
+
/**accessor*/
|
|
92
|
+
set elem_id(_: string | undefined);
|
|
93
|
+
get elem_classes(): string[] | undefined;
|
|
94
|
+
/**accessor*/
|
|
95
|
+
set elem_classes(_: string[] | undefined);
|
|
96
|
+
get visible(): boolean | undefined;
|
|
97
|
+
/**accessor*/
|
|
98
|
+
set visible(_: boolean | undefined);
|
|
99
|
+
get value(): {
|
|
100
|
+
text: string;
|
|
101
|
+
files: FileData[];
|
|
102
|
+
} | undefined;
|
|
103
|
+
/**accessor*/
|
|
104
|
+
set value(_: {
|
|
105
|
+
text: string;
|
|
106
|
+
files: FileData[];
|
|
107
|
+
} | undefined);
|
|
108
|
+
get file_types(): string[] | null | undefined;
|
|
109
|
+
/**accessor*/
|
|
110
|
+
set file_types(_: string[] | null | undefined);
|
|
111
|
+
get lines(): number;
|
|
112
|
+
/**accessor*/
|
|
113
|
+
set lines(_: number);
|
|
114
|
+
get placeholder(): string | undefined;
|
|
115
|
+
/**accessor*/
|
|
116
|
+
set placeholder(_: string | undefined);
|
|
117
|
+
get label(): string | undefined;
|
|
118
|
+
/**accessor*/
|
|
119
|
+
set label(_: string | undefined);
|
|
120
|
+
get info(): string | undefined;
|
|
121
|
+
/**accessor*/
|
|
122
|
+
set info(_: string | undefined);
|
|
123
|
+
get show_label(): boolean;
|
|
124
|
+
/**accessor*/
|
|
125
|
+
set show_label(_: boolean);
|
|
126
|
+
get max_lines(): number;
|
|
127
|
+
/**accessor*/
|
|
128
|
+
set max_lines(_: number);
|
|
129
|
+
get container(): boolean | undefined;
|
|
130
|
+
/**accessor*/
|
|
131
|
+
set container(_: boolean | undefined);
|
|
132
|
+
get scale(): number | null | undefined;
|
|
133
|
+
/**accessor*/
|
|
134
|
+
set scale(_: number | null | undefined);
|
|
135
|
+
get min_width(): number | undefined;
|
|
136
|
+
/**accessor*/
|
|
137
|
+
set min_width(_: number | undefined);
|
|
138
|
+
get submit_btn(): string | boolean | null | undefined;
|
|
139
|
+
/**accessor*/
|
|
140
|
+
set submit_btn(_: string | boolean | null | undefined);
|
|
141
|
+
get stop_btn(): string | boolean | null | undefined;
|
|
142
|
+
/**accessor*/
|
|
143
|
+
set stop_btn(_: string | boolean | null | undefined);
|
|
144
|
+
get loading_status(): LoadingStatus | undefined;
|
|
145
|
+
/**accessor*/
|
|
146
|
+
set loading_status(_: LoadingStatus | undefined);
|
|
147
|
+
get value_is_output(): boolean | undefined;
|
|
148
|
+
/**accessor*/
|
|
149
|
+
set value_is_output(_: boolean | undefined);
|
|
150
|
+
get rtl(): boolean | undefined;
|
|
151
|
+
/**accessor*/
|
|
152
|
+
set rtl(_: boolean | undefined);
|
|
153
|
+
get text_align(): "left" | "right" | undefined;
|
|
154
|
+
/**accessor*/
|
|
155
|
+
set text_align(_: "left" | "right" | undefined);
|
|
156
|
+
get autofocus(): boolean | undefined;
|
|
157
|
+
/**accessor*/
|
|
158
|
+
set autofocus(_: boolean | undefined);
|
|
159
|
+
get autoscroll(): boolean | undefined;
|
|
160
|
+
/**accessor*/
|
|
161
|
+
set autoscroll(_: boolean | undefined);
|
|
162
|
+
get interactive(): boolean;
|
|
163
|
+
/**accessor*/
|
|
164
|
+
set interactive(_: boolean);
|
|
165
|
+
get root(): string;
|
|
166
|
+
/**accessor*/
|
|
167
|
+
set root(_: string);
|
|
168
|
+
get file_count(): "multiple" | "single" | "directory";
|
|
169
|
+
/**accessor*/
|
|
170
|
+
set file_count(_: "multiple" | "single" | "directory");
|
|
171
|
+
}
|
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
<script>import {
|
|
2
|
+
beforeUpdate,
|
|
3
|
+
afterUpdate,
|
|
4
|
+
createEventDispatcher,
|
|
5
|
+
tick
|
|
6
|
+
} from "svelte";
|
|
7
|
+
import { text_area_resize, resize } from "../shared/utils";
|
|
8
|
+
import { BlockTitle } from "@gradio/atoms";
|
|
9
|
+
import { Upload } from "@gradio/upload";
|
|
10
|
+
import { Image } from "@gradio/image/shared";
|
|
11
|
+
import {
|
|
12
|
+
Clear,
|
|
13
|
+
File,
|
|
14
|
+
Music,
|
|
15
|
+
Paperclip,
|
|
16
|
+
Video,
|
|
17
|
+
Send,
|
|
18
|
+
Square
|
|
19
|
+
} from "@gradio/icons";
|
|
20
|
+
export let value = {
|
|
21
|
+
text: "",
|
|
22
|
+
files: []
|
|
23
|
+
};
|
|
24
|
+
export let value_is_output = false;
|
|
25
|
+
export let lines = 1;
|
|
26
|
+
export let placeholder = "Type here...";
|
|
27
|
+
export let disabled = false;
|
|
28
|
+
export let label;
|
|
29
|
+
export let info = void 0;
|
|
30
|
+
export let show_label = true;
|
|
31
|
+
export let container = true;
|
|
32
|
+
export let max_lines;
|
|
33
|
+
export let submit_btn = null;
|
|
34
|
+
export let stop_btn = null;
|
|
35
|
+
export let rtl = false;
|
|
36
|
+
export let autofocus = false;
|
|
37
|
+
export let text_align = void 0;
|
|
38
|
+
export let autoscroll = true;
|
|
39
|
+
export let root;
|
|
40
|
+
export let file_types = null;
|
|
41
|
+
export let max_file_size = null;
|
|
42
|
+
export let upload;
|
|
43
|
+
export let stream_handler;
|
|
44
|
+
export let file_count = "multiple";
|
|
45
|
+
let upload_component;
|
|
46
|
+
let hidden_upload;
|
|
47
|
+
let el;
|
|
48
|
+
let can_scroll;
|
|
49
|
+
let previous_scroll_top = 0;
|
|
50
|
+
let user_has_scrolled_up = false;
|
|
51
|
+
export let dragging = false;
|
|
52
|
+
let uploading = false;
|
|
53
|
+
let oldValue = value.text;
|
|
54
|
+
$:
|
|
55
|
+
dispatch("drag", dragging);
|
|
56
|
+
let full_container;
|
|
57
|
+
$:
|
|
58
|
+
if (oldValue !== value.text) {
|
|
59
|
+
dispatch("change", value);
|
|
60
|
+
oldValue = value.text;
|
|
61
|
+
}
|
|
62
|
+
let accept_file_types;
|
|
63
|
+
if (file_types == null) {
|
|
64
|
+
accept_file_types = null;
|
|
65
|
+
} else {
|
|
66
|
+
file_types = file_types.map((x) => {
|
|
67
|
+
if (x.startsWith(".")) {
|
|
68
|
+
return x;
|
|
69
|
+
}
|
|
70
|
+
return x + "/*";
|
|
71
|
+
});
|
|
72
|
+
accept_file_types = file_types.join(", ");
|
|
73
|
+
}
|
|
74
|
+
$:
|
|
75
|
+
if (value === null)
|
|
76
|
+
value = { text: "", files: [] };
|
|
77
|
+
$:
|
|
78
|
+
value, el && lines !== max_lines && resize(el, lines, max_lines);
|
|
79
|
+
const dispatch = createEventDispatcher();
|
|
80
|
+
beforeUpdate(() => {
|
|
81
|
+
can_scroll = el && el.offsetHeight + el.scrollTop > el.scrollHeight - 100;
|
|
82
|
+
});
|
|
83
|
+
const scroll = () => {
|
|
84
|
+
if (can_scroll && autoscroll && !user_has_scrolled_up) {
|
|
85
|
+
el.scrollTo(0, el.scrollHeight);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
async function handle_change() {
|
|
89
|
+
dispatch("change", value);
|
|
90
|
+
if (!value_is_output) {
|
|
91
|
+
dispatch("input");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
afterUpdate(() => {
|
|
95
|
+
if (autofocus && el !== null) {
|
|
96
|
+
el.focus();
|
|
97
|
+
}
|
|
98
|
+
if (can_scroll && autoscroll) {
|
|
99
|
+
scroll();
|
|
100
|
+
}
|
|
101
|
+
value_is_output = false;
|
|
102
|
+
});
|
|
103
|
+
function handle_select(event) {
|
|
104
|
+
const target = event.target;
|
|
105
|
+
const text = target.value;
|
|
106
|
+
const index = [
|
|
107
|
+
target.selectionStart,
|
|
108
|
+
target.selectionEnd
|
|
109
|
+
];
|
|
110
|
+
dispatch("select", { value: text.substring(...index), index });
|
|
111
|
+
}
|
|
112
|
+
async function handle_keypress(e) {
|
|
113
|
+
await tick();
|
|
114
|
+
if (e.key === "Enter" && e.shiftKey && lines > 1) {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
dispatch("submit");
|
|
117
|
+
} else if (e.key === "Enter" && !e.shiftKey && lines === 1 && max_lines >= 1) {
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
dispatch("submit");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function handle_scroll(event) {
|
|
123
|
+
const target = event.target;
|
|
124
|
+
const current_scroll_top = target.scrollTop;
|
|
125
|
+
if (current_scroll_top < previous_scroll_top) {
|
|
126
|
+
user_has_scrolled_up = true;
|
|
127
|
+
}
|
|
128
|
+
previous_scroll_top = current_scroll_top;
|
|
129
|
+
const max_scroll_top = target.scrollHeight - target.clientHeight;
|
|
130
|
+
const user_has_scrolled_to_bottom = current_scroll_top >= max_scroll_top;
|
|
131
|
+
if (user_has_scrolled_to_bottom) {
|
|
132
|
+
user_has_scrolled_up = false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function handle_upload({
|
|
136
|
+
detail
|
|
137
|
+
}) {
|
|
138
|
+
handle_change();
|
|
139
|
+
if (Array.isArray(detail)) {
|
|
140
|
+
for (let file of detail) {
|
|
141
|
+
value.files.push(file);
|
|
142
|
+
}
|
|
143
|
+
value = value;
|
|
144
|
+
} else {
|
|
145
|
+
value.files.push(detail);
|
|
146
|
+
value = value;
|
|
147
|
+
}
|
|
148
|
+
await tick();
|
|
149
|
+
dispatch("change", value);
|
|
150
|
+
dispatch("upload", detail);
|
|
151
|
+
}
|
|
152
|
+
function remove_thumbnail(event, index) {
|
|
153
|
+
handle_change();
|
|
154
|
+
event.stopPropagation();
|
|
155
|
+
value.files.splice(index, 1);
|
|
156
|
+
value = value;
|
|
157
|
+
}
|
|
158
|
+
function handle_upload_click() {
|
|
159
|
+
if (hidden_upload) {
|
|
160
|
+
hidden_upload.value = "";
|
|
161
|
+
hidden_upload.click();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function handle_stop() {
|
|
165
|
+
dispatch("stop");
|
|
166
|
+
}
|
|
167
|
+
function handle_submit() {
|
|
168
|
+
dispatch("submit");
|
|
169
|
+
}
|
|
170
|
+
function handle_paste(event) {
|
|
171
|
+
if (!event.clipboardData)
|
|
172
|
+
return;
|
|
173
|
+
const items = event.clipboardData.items;
|
|
174
|
+
for (let index in items) {
|
|
175
|
+
const item = items[index];
|
|
176
|
+
if (item.kind === "file" && item.type.includes("image")) {
|
|
177
|
+
const blob = item.getAsFile();
|
|
178
|
+
if (blob)
|
|
179
|
+
upload_component.load_files([blob]);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function handle_dragenter(event) {
|
|
184
|
+
event.preventDefault();
|
|
185
|
+
dragging = true;
|
|
186
|
+
}
|
|
187
|
+
function handle_dragleave(event) {
|
|
188
|
+
event.preventDefault();
|
|
189
|
+
const rect = full_container.getBoundingClientRect();
|
|
190
|
+
const { clientX, clientY } = event;
|
|
191
|
+
if (clientX <= rect.left || clientX >= rect.right || clientY <= rect.top || clientY >= rect.bottom) {
|
|
192
|
+
dragging = false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function handle_drop(event) {
|
|
196
|
+
event.preventDefault();
|
|
197
|
+
dragging = false;
|
|
198
|
+
if (event.dataTransfer && event.dataTransfer.files) {
|
|
199
|
+
upload_component.load_files(Array.from(event.dataTransfer.files));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
</script>
|
|
203
|
+
|
|
204
|
+
<div
|
|
205
|
+
class="full-container"
|
|
206
|
+
class:dragging
|
|
207
|
+
bind:this={full_container}
|
|
208
|
+
on:dragenter={handle_dragenter}
|
|
209
|
+
on:dragleave={handle_dragleave}
|
|
210
|
+
on:dragover|preventDefault
|
|
211
|
+
on:drop={handle_drop}
|
|
212
|
+
role="group"
|
|
213
|
+
aria-label="Multimedia input field"
|
|
214
|
+
>
|
|
215
|
+
<!-- svelte-ignore a11y-autofocus -->
|
|
216
|
+
<label class:container>
|
|
217
|
+
<BlockTitle {show_label} {info}>{label}</BlockTitle>
|
|
218
|
+
{#if value.files.length > 0 || uploading}
|
|
219
|
+
<div
|
|
220
|
+
class="thumbnails scroll-hide"
|
|
221
|
+
aria-label="Uploaded files"
|
|
222
|
+
data-testid="container_el"
|
|
223
|
+
style="display: {value.files.length > 0 || uploading
|
|
224
|
+
? 'flex'
|
|
225
|
+
: 'none'};"
|
|
226
|
+
>
|
|
227
|
+
{#each value.files as file, index}
|
|
228
|
+
<span role="listitem" aria-label="File thumbnail">
|
|
229
|
+
<button class="thumbnail-item thumbnail-small">
|
|
230
|
+
<button
|
|
231
|
+
class:disabled
|
|
232
|
+
class="delete-button"
|
|
233
|
+
on:click={(event) => remove_thumbnail(event, index)}
|
|
234
|
+
><Clear /></button
|
|
235
|
+
>
|
|
236
|
+
{#if file.mime_type && file.mime_type.includes("image")}
|
|
237
|
+
<Image
|
|
238
|
+
src={file.url}
|
|
239
|
+
title={null}
|
|
240
|
+
alt=""
|
|
241
|
+
loading="lazy"
|
|
242
|
+
class={"thumbnail-image"}
|
|
243
|
+
/>
|
|
244
|
+
{:else if file.mime_type && file.mime_type.includes("audio")}
|
|
245
|
+
<Music />
|
|
246
|
+
{:else if file.mime_type && file.mime_type.includes("video")}
|
|
247
|
+
<Video />
|
|
248
|
+
{:else}
|
|
249
|
+
<File />
|
|
250
|
+
{/if}
|
|
251
|
+
</button>
|
|
252
|
+
</span>
|
|
253
|
+
{/each}
|
|
254
|
+
{#if uploading}
|
|
255
|
+
<div class="loader" role="status" aria-label="Uploading"></div>
|
|
256
|
+
{/if}
|
|
257
|
+
</div>
|
|
258
|
+
{/if}
|
|
259
|
+
<div class="input-container">
|
|
260
|
+
<Upload
|
|
261
|
+
bind:this={upload_component}
|
|
262
|
+
on:load={handle_upload}
|
|
263
|
+
{file_count}
|
|
264
|
+
{root}
|
|
265
|
+
{max_file_size}
|
|
266
|
+
bind:dragging
|
|
267
|
+
bind:uploading
|
|
268
|
+
show_progress={false}
|
|
269
|
+
disable_click={true}
|
|
270
|
+
bind:hidden_upload
|
|
271
|
+
on:error
|
|
272
|
+
hidden={true}
|
|
273
|
+
{upload}
|
|
274
|
+
{stream_handler}
|
|
275
|
+
></Upload>
|
|
276
|
+
<button
|
|
277
|
+
data-testid="upload-button"
|
|
278
|
+
class="upload-button"
|
|
279
|
+
on:click={handle_upload_click}><Paperclip /></button
|
|
280
|
+
>
|
|
281
|
+
<textarea
|
|
282
|
+
data-testid="textbox"
|
|
283
|
+
use:text_area_resize={{
|
|
284
|
+
text: value.text,
|
|
285
|
+
lines: lines,
|
|
286
|
+
max_lines: max_lines
|
|
287
|
+
}}
|
|
288
|
+
class="scroll-hide"
|
|
289
|
+
dir={rtl ? "rtl" : "ltr"}
|
|
290
|
+
bind:value={value.text}
|
|
291
|
+
bind:this={el}
|
|
292
|
+
{placeholder}
|
|
293
|
+
rows={lines}
|
|
294
|
+
{disabled}
|
|
295
|
+
{autofocus}
|
|
296
|
+
on:keypress={handle_keypress}
|
|
297
|
+
on:blur
|
|
298
|
+
on:select={handle_select}
|
|
299
|
+
on:focus
|
|
300
|
+
on:scroll={handle_scroll}
|
|
301
|
+
on:paste={handle_paste}
|
|
302
|
+
style={text_align ? "text-align: " + text_align : ""}
|
|
303
|
+
/>
|
|
304
|
+
{#if submit_btn}
|
|
305
|
+
<button
|
|
306
|
+
class="submit-button"
|
|
307
|
+
class:padded-button={submit_btn !== true}
|
|
308
|
+
on:click={handle_submit}
|
|
309
|
+
>
|
|
310
|
+
{#if submit_btn === true}
|
|
311
|
+
<Send />
|
|
312
|
+
{:else}
|
|
313
|
+
{submit_btn}
|
|
314
|
+
{/if}
|
|
315
|
+
</button>
|
|
316
|
+
{/if}
|
|
317
|
+
{#if stop_btn}
|
|
318
|
+
<button
|
|
319
|
+
class="stop-button"
|
|
320
|
+
class:padded-button={stop_btn !== true}
|
|
321
|
+
on:click={handle_stop}
|
|
322
|
+
>
|
|
323
|
+
{#if stop_btn === true}
|
|
324
|
+
<Square />
|
|
325
|
+
{:else}
|
|
326
|
+
{stop_btn}
|
|
327
|
+
{/if}
|
|
328
|
+
</button>
|
|
329
|
+
{/if}
|
|
330
|
+
</div>
|
|
331
|
+
</label>
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
<style>
|
|
335
|
+
.full-container {
|
|
336
|
+
width: 100%;
|
|
337
|
+
position: relative;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.full-container.dragging::after {
|
|
341
|
+
content: "";
|
|
342
|
+
position: absolute;
|
|
343
|
+
top: 0;
|
|
344
|
+
left: 0;
|
|
345
|
+
right: 0;
|
|
346
|
+
bottom: 0;
|
|
347
|
+
pointer-events: none;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.input-container {
|
|
351
|
+
display: flex;
|
|
352
|
+
position: relative;
|
|
353
|
+
align-items: flex-end;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
textarea {
|
|
357
|
+
flex-grow: 1;
|
|
358
|
+
outline: none !important;
|
|
359
|
+
background: var(--input-background-fill);
|
|
360
|
+
padding: var(--input-padding);
|
|
361
|
+
color: var(--body-text-color);
|
|
362
|
+
font-weight: var(--input-text-weight);
|
|
363
|
+
font-size: var(--input-text-size);
|
|
364
|
+
line-height: var(--line-sm);
|
|
365
|
+
border: none;
|
|
366
|
+
margin-top: 0px;
|
|
367
|
+
margin-bottom: 0px;
|
|
368
|
+
resize: none;
|
|
369
|
+
position: relative;
|
|
370
|
+
z-index: 1;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
textarea:disabled {
|
|
374
|
+
-webkit-opacity: 1;
|
|
375
|
+
opacity: 1;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
textarea::placeholder {
|
|
379
|
+
color: var(--input-placeholder-color);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.upload-button,
|
|
383
|
+
.submit-button,
|
|
384
|
+
.stop-button {
|
|
385
|
+
border: none;
|
|
386
|
+
text-align: center;
|
|
387
|
+
text-decoration: none;
|
|
388
|
+
font-size: 14px;
|
|
389
|
+
cursor: pointer;
|
|
390
|
+
border-radius: 15px;
|
|
391
|
+
min-width: 30px;
|
|
392
|
+
height: 30px;
|
|
393
|
+
flex-shrink: 0;
|
|
394
|
+
display: flex;
|
|
395
|
+
justify-content: center;
|
|
396
|
+
align-items: center;
|
|
397
|
+
margin-bottom: 5px;
|
|
398
|
+
z-index: var(--layer-1);
|
|
399
|
+
}
|
|
400
|
+
.padded-button {
|
|
401
|
+
padding: 0 10px;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.upload-button,
|
|
405
|
+
.submit-button {
|
|
406
|
+
background: var(--button-secondary-background-fill);
|
|
407
|
+
color: var(--button-secondary-text-color);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.upload-button:hover,
|
|
411
|
+
.submit-button:hover {
|
|
412
|
+
background: var(--button-secondary-background-fill-hover);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.upload-button:active,
|
|
416
|
+
.submit-button:active {
|
|
417
|
+
box-shadow: var(--button-shadow-active);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.submit-button :global(svg) {
|
|
421
|
+
height: 22px;
|
|
422
|
+
width: 22px;
|
|
423
|
+
}
|
|
424
|
+
.upload-button :global(svg) {
|
|
425
|
+
height: 17px;
|
|
426
|
+
width: 17px;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.stop-button {
|
|
430
|
+
background: var(--button-cancel-background-fill);
|
|
431
|
+
color: var(--button-cancel-text-color);
|
|
432
|
+
}
|
|
433
|
+
.stop-button:hover {
|
|
434
|
+
background: var(--button-cancel-background-fill-hover);
|
|
435
|
+
color: var(--button-cancel-text-color-hover);
|
|
436
|
+
}
|
|
437
|
+
.stop-button :global(svg) {
|
|
438
|
+
height: 18px;
|
|
439
|
+
width: 18px;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.loader {
|
|
443
|
+
display: flex;
|
|
444
|
+
justify-content: center;
|
|
445
|
+
align-items: center;
|
|
446
|
+
--ring-color: transparent;
|
|
447
|
+
position: relative;
|
|
448
|
+
border: 5px solid #f3f3f3;
|
|
449
|
+
border-top: 5px solid var(--color-accent);
|
|
450
|
+
border-radius: 50%;
|
|
451
|
+
width: 25px;
|
|
452
|
+
height: 25px;
|
|
453
|
+
animation: spin 2s linear infinite;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@keyframes spin {
|
|
457
|
+
0% {
|
|
458
|
+
transform: rotate(0deg);
|
|
459
|
+
}
|
|
460
|
+
100% {
|
|
461
|
+
transform: rotate(360deg);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.thumbnails :global(img) {
|
|
466
|
+
width: var(--size-full);
|
|
467
|
+
height: var(--size-full);
|
|
468
|
+
object-fit: cover;
|
|
469
|
+
border-radius: var(--radius-lg);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.thumbnails {
|
|
473
|
+
display: flex;
|
|
474
|
+
align-items: center;
|
|
475
|
+
gap: var(--spacing-lg);
|
|
476
|
+
overflow-x: scroll;
|
|
477
|
+
padding-top: var(--spacing-sm);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.thumbnail-item {
|
|
481
|
+
display: flex;
|
|
482
|
+
justify-content: center;
|
|
483
|
+
align-items: center;
|
|
484
|
+
--ring-color: transparent;
|
|
485
|
+
position: relative;
|
|
486
|
+
box-shadow:
|
|
487
|
+
0 0 0 2px var(--ring-color),
|
|
488
|
+
var(--shadow-drop);
|
|
489
|
+
border: 1px solid var(--border-color-primary);
|
|
490
|
+
border-radius: var(--radius-lg);
|
|
491
|
+
background: var(--background-fill-secondary);
|
|
492
|
+
aspect-ratio: var(--ratio-square);
|
|
493
|
+
width: var(--size-full);
|
|
494
|
+
height: var(--size-full);
|
|
495
|
+
cursor: default;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.thumbnail-small {
|
|
499
|
+
flex: none;
|
|
500
|
+
transform: scale(0.9);
|
|
501
|
+
transition: 0.075s;
|
|
502
|
+
width: var(--size-12);
|
|
503
|
+
height: var(--size-12);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.thumbnail-item :global(svg) {
|
|
507
|
+
width: 30px;
|
|
508
|
+
height: 30px;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.delete-button {
|
|
512
|
+
display: flex;
|
|
513
|
+
justify-content: center;
|
|
514
|
+
align-items: center;
|
|
515
|
+
position: absolute;
|
|
516
|
+
right: -7px;
|
|
517
|
+
top: -7px;
|
|
518
|
+
color: var(--button-secondary-text-color);
|
|
519
|
+
background: var(--button-secondary-background-fill);
|
|
520
|
+
border: none;
|
|
521
|
+
text-align: center;
|
|
522
|
+
text-decoration: none;
|
|
523
|
+
font-size: 10px;
|
|
524
|
+
cursor: pointer;
|
|
525
|
+
border-radius: 50%;
|
|
526
|
+
width: 20px;
|
|
527
|
+
height: 20px;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.disabled {
|
|
531
|
+
display: none;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.delete-button :global(svg) {
|
|
535
|
+
width: 12px;
|
|
536
|
+
height: 12px;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.delete-button:hover {
|
|
540
|
+
filter: brightness(1.2);
|
|
541
|
+
border: 0.8px solid var(--color-grey-500);
|
|
542
|
+
}
|
|
543
|
+
</style>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { FileData, Client } from "@gradio/client";
|
|
3
|
+
import type { SelectData } from "@gradio/utils";
|
|
4
|
+
declare const __propDef: {
|
|
5
|
+
props: {
|
|
6
|
+
value?: {
|
|
7
|
+
text: string;
|
|
8
|
+
files: FileData[];
|
|
9
|
+
} | undefined;
|
|
10
|
+
value_is_output?: boolean | undefined;
|
|
11
|
+
lines?: number | undefined;
|
|
12
|
+
placeholder?: string | undefined;
|
|
13
|
+
disabled?: boolean | undefined;
|
|
14
|
+
label: string;
|
|
15
|
+
info?: string | undefined;
|
|
16
|
+
show_label?: boolean | undefined;
|
|
17
|
+
container?: boolean | undefined;
|
|
18
|
+
max_lines: number;
|
|
19
|
+
submit_btn?: (string | boolean | null) | undefined;
|
|
20
|
+
stop_btn?: (string | boolean | null) | undefined;
|
|
21
|
+
rtl?: boolean | undefined;
|
|
22
|
+
autofocus?: boolean | undefined;
|
|
23
|
+
text_align?: "left" | "right" | undefined;
|
|
24
|
+
autoscroll?: boolean | undefined;
|
|
25
|
+
root: string;
|
|
26
|
+
file_types?: (string[] | null) | undefined;
|
|
27
|
+
max_file_size?: (number | null) | undefined;
|
|
28
|
+
upload: Client["upload"];
|
|
29
|
+
stream_handler: Client["stream"];
|
|
30
|
+
file_count?: ("single" | "multiple" | "directory") | undefined;
|
|
31
|
+
dragging?: boolean | undefined;
|
|
32
|
+
};
|
|
33
|
+
events: {
|
|
34
|
+
dragover: DragEvent;
|
|
35
|
+
error: CustomEvent<any>;
|
|
36
|
+
blur: CustomEvent<any>;
|
|
37
|
+
focus: CustomEvent<any>;
|
|
38
|
+
change: CustomEvent<{
|
|
39
|
+
text: string;
|
|
40
|
+
files: FileData[];
|
|
41
|
+
}>;
|
|
42
|
+
submit: CustomEvent<undefined>;
|
|
43
|
+
stop: CustomEvent<undefined>;
|
|
44
|
+
select: CustomEvent<SelectData>;
|
|
45
|
+
input: CustomEvent<undefined>;
|
|
46
|
+
drag: CustomEvent<boolean>;
|
|
47
|
+
upload: CustomEvent<FileData | FileData[]>;
|
|
48
|
+
clear: CustomEvent<undefined>;
|
|
49
|
+
load: CustomEvent<FileData | FileData[]>;
|
|
50
|
+
} & {
|
|
51
|
+
[evt: string]: CustomEvent<any>;
|
|
52
|
+
};
|
|
53
|
+
slots: {};
|
|
54
|
+
};
|
|
55
|
+
export type MultimodalTextboxProps = typeof __propDef.props;
|
|
56
|
+
export type MultimodalTextboxEvents = typeof __propDef.events;
|
|
57
|
+
export type MultimodalTextboxSlots = typeof __propDef.slots;
|
|
58
|
+
export default class MultimodalTextbox extends SvelteComponent<MultimodalTextboxProps, MultimodalTextboxEvents, MultimodalTextboxSlots> {
|
|
59
|
+
}
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface Value {
|
|
2
|
+
lines: number;
|
|
3
|
+
max_lines: number;
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function resize(target: HTMLTextAreaElement | HTMLInputElement, lines: number, max_lines: number): Promise<void>;
|
|
7
|
+
export declare function text_area_resize(_el: HTMLTextAreaElement, _value: Value): any | undefined;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { tick } from "svelte";
|
|
2
|
+
export async function resize(target, lines, max_lines) {
|
|
3
|
+
await tick();
|
|
4
|
+
if (lines === max_lines)
|
|
5
|
+
return;
|
|
6
|
+
let max = max_lines === undefined
|
|
7
|
+
? false
|
|
8
|
+
: max_lines === undefined // default
|
|
9
|
+
? 21 * 11
|
|
10
|
+
: 21 * (max_lines + 1);
|
|
11
|
+
let min = 21 * (lines + 1);
|
|
12
|
+
target.style.height = "1px";
|
|
13
|
+
let scroll_height;
|
|
14
|
+
if (max && target.scrollHeight > max) {
|
|
15
|
+
scroll_height = max;
|
|
16
|
+
}
|
|
17
|
+
else if (target.scrollHeight < min) {
|
|
18
|
+
scroll_height = min;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
scroll_height = target.scrollHeight;
|
|
22
|
+
}
|
|
23
|
+
target.style.height = `${scroll_height}px`;
|
|
24
|
+
}
|
|
25
|
+
export function text_area_resize(_el, _value) {
|
|
26
|
+
if (_value.lines === _value.max_lines)
|
|
27
|
+
return;
|
|
28
|
+
_el.style.overflowY = "scroll";
|
|
29
|
+
function handle_input(event) {
|
|
30
|
+
resize(event.target, _value.lines, _value.max_lines);
|
|
31
|
+
}
|
|
32
|
+
_el.addEventListener("input", handle_input);
|
|
33
|
+
if (!_value.text.trim())
|
|
34
|
+
return;
|
|
35
|
+
resize(_el, _value.lines, _value.max_lines);
|
|
36
|
+
return {
|
|
37
|
+
destroy: () => _el.removeEventListener("input", handle_input)
|
|
38
|
+
};
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/multimodaltextbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0-beta.1",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -9,22 +9,33 @@
|
|
|
9
9
|
"main_changeset": true,
|
|
10
10
|
"main": "Index.svelte",
|
|
11
11
|
"exports": {
|
|
12
|
-
".":
|
|
13
|
-
|
|
12
|
+
".": {
|
|
13
|
+
"gradio": "./Index.svelte",
|
|
14
|
+
"svelte": "./dist/Index.svelte",
|
|
15
|
+
"types": "./dist/Index.svelte.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./example": {
|
|
18
|
+
"gradio": "./Example.svelte",
|
|
19
|
+
"svelte": "./dist/Example.svelte",
|
|
20
|
+
"types": "./dist/Example.svelte.d.ts"
|
|
21
|
+
},
|
|
14
22
|
"./package.json": "./package.json"
|
|
15
23
|
},
|
|
16
24
|
"dependencies": {
|
|
17
|
-
"@gradio/atoms": "^0.8.
|
|
18
|
-
"@gradio/icons": "^0.
|
|
19
|
-
"@gradio/statustracker": "^0.
|
|
20
|
-
"@gradio/
|
|
21
|
-
"@gradio/
|
|
22
|
-
"@gradio/image": "^0.
|
|
23
|
-
"@gradio/video": "^0.
|
|
24
|
-
"@gradio/client": "^1.
|
|
25
|
+
"@gradio/atoms": "^0.8.1-beta.1",
|
|
26
|
+
"@gradio/icons": "^0.8.0-beta.1",
|
|
27
|
+
"@gradio/statustracker": "^0.8.0-beta.1",
|
|
28
|
+
"@gradio/utils": "^0.7.0-beta.1",
|
|
29
|
+
"@gradio/upload": "^0.12.4-beta.1",
|
|
30
|
+
"@gradio/image": "^0.16.0-beta.1",
|
|
31
|
+
"@gradio/video": "^0.11.0-beta.1",
|
|
32
|
+
"@gradio/client": "^1.6.0-beta.1"
|
|
25
33
|
},
|
|
26
34
|
"devDependencies": {
|
|
27
|
-
"@gradio/preview": "^0.11.0"
|
|
35
|
+
"@gradio/preview": "^0.11.1-beta.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"svelte": "^4.0.0"
|
|
28
39
|
},
|
|
29
40
|
"repository": {
|
|
30
41
|
"type": "git",
|
|
@@ -10,7 +10,15 @@
|
|
|
10
10
|
import { Upload } from "@gradio/upload";
|
|
11
11
|
import { Image } from "@gradio/image/shared";
|
|
12
12
|
import type { FileData, Client } from "@gradio/client";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
Clear,
|
|
15
|
+
File,
|
|
16
|
+
Music,
|
|
17
|
+
Paperclip,
|
|
18
|
+
Video,
|
|
19
|
+
Send,
|
|
20
|
+
Square
|
|
21
|
+
} from "@gradio/icons";
|
|
14
22
|
import type { SelectData } from "@gradio/utils";
|
|
15
23
|
|
|
16
24
|
export let value: { text: string; files: FileData[] } = {
|
|
@@ -28,6 +36,7 @@
|
|
|
28
36
|
export let container = true;
|
|
29
37
|
export let max_lines: number;
|
|
30
38
|
export let submit_btn: string | boolean | null = null;
|
|
39
|
+
export let stop_btn: string | boolean | null = null;
|
|
31
40
|
export let rtl = false;
|
|
32
41
|
export let autofocus = false;
|
|
33
42
|
export let text_align: "left" | "right" | undefined = undefined;
|
|
@@ -75,6 +84,7 @@
|
|
|
75
84
|
const dispatch = createEventDispatcher<{
|
|
76
85
|
change: typeof value;
|
|
77
86
|
submit: undefined;
|
|
87
|
+
stop: undefined;
|
|
78
88
|
blur: undefined;
|
|
79
89
|
select: SelectData;
|
|
80
90
|
input: undefined;
|
|
@@ -188,7 +198,11 @@
|
|
|
188
198
|
}
|
|
189
199
|
}
|
|
190
200
|
|
|
191
|
-
|
|
201
|
+
function handle_stop(): void {
|
|
202
|
+
dispatch("stop");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function handle_submit(): void {
|
|
192
206
|
dispatch("submit");
|
|
193
207
|
}
|
|
194
208
|
|
|
@@ -341,7 +355,20 @@
|
|
|
341
355
|
{#if submit_btn === true}
|
|
342
356
|
<Send />
|
|
343
357
|
{:else}
|
|
344
|
-
|
|
358
|
+
{submit_btn}
|
|
359
|
+
{/if}
|
|
360
|
+
</button>
|
|
361
|
+
{/if}
|
|
362
|
+
{#if stop_btn}
|
|
363
|
+
<button
|
|
364
|
+
class="stop-button"
|
|
365
|
+
class:padded-button={stop_btn !== true}
|
|
366
|
+
on:click={handle_stop}
|
|
367
|
+
>
|
|
368
|
+
{#if stop_btn === true}
|
|
369
|
+
<Square />
|
|
370
|
+
{:else}
|
|
371
|
+
{stop_btn}
|
|
345
372
|
{/if}
|
|
346
373
|
</button>
|
|
347
374
|
{/if}
|
|
@@ -398,9 +425,8 @@
|
|
|
398
425
|
}
|
|
399
426
|
|
|
400
427
|
.upload-button,
|
|
401
|
-
.submit-button
|
|
402
|
-
|
|
403
|
-
color: var(--button-secondary-text-color);
|
|
428
|
+
.submit-button,
|
|
429
|
+
.stop-button {
|
|
404
430
|
border: none;
|
|
405
431
|
text-align: center;
|
|
406
432
|
text-decoration: none;
|
|
@@ -420,6 +446,12 @@
|
|
|
420
446
|
padding: 0 10px;
|
|
421
447
|
}
|
|
422
448
|
|
|
449
|
+
.upload-button,
|
|
450
|
+
.submit-button {
|
|
451
|
+
background: var(--button-secondary-background-fill);
|
|
452
|
+
color: var(--button-secondary-text-color);
|
|
453
|
+
}
|
|
454
|
+
|
|
423
455
|
.upload-button:hover,
|
|
424
456
|
.submit-button:hover {
|
|
425
457
|
background: var(--button-secondary-background-fill-hover);
|
|
@@ -439,6 +471,19 @@
|
|
|
439
471
|
width: 17px;
|
|
440
472
|
}
|
|
441
473
|
|
|
474
|
+
.stop-button {
|
|
475
|
+
background: var(--button-cancel-background-fill);
|
|
476
|
+
color: var(--button-cancel-text-color);
|
|
477
|
+
}
|
|
478
|
+
.stop-button:hover {
|
|
479
|
+
background: var(--button-cancel-background-fill-hover);
|
|
480
|
+
color: var(--button-cancel-text-color-hover);
|
|
481
|
+
}
|
|
482
|
+
.stop-button :global(svg) {
|
|
483
|
+
height: 18px;
|
|
484
|
+
width: 18px;
|
|
485
|
+
}
|
|
486
|
+
|
|
442
487
|
.loader {
|
|
443
488
|
display: flex;
|
|
444
489
|
justify-content: center;
|
package/shared/utils.ts
CHANGED
|
@@ -42,17 +42,16 @@ export function text_area_resize(
|
|
|
42
42
|
): any | undefined {
|
|
43
43
|
if (_value.lines === _value.max_lines) return;
|
|
44
44
|
_el.style.overflowY = "scroll";
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
|
|
46
|
+
function handle_input(event: Event): void {
|
|
47
|
+
resize(event.target as HTMLTextAreaElement, _value.lines, _value.max_lines);
|
|
48
|
+
}
|
|
49
|
+
_el.addEventListener("input", handle_input);
|
|
48
50
|
|
|
49
51
|
if (!_value.text.trim()) return;
|
|
50
52
|
resize(_el, _value.lines, _value.max_lines);
|
|
51
53
|
|
|
52
54
|
return {
|
|
53
|
-
destroy: () =>
|
|
54
|
-
_el.removeEventListener("input", (e: Event) =>
|
|
55
|
-
resize(e.target as HTMLTextAreaElement, _value.lines, _value.max_lines)
|
|
56
|
-
)
|
|
55
|
+
destroy: () => _el.removeEventListener("input", handle_input)
|
|
57
56
|
};
|
|
58
57
|
}
|