@gradio/multimodaltextbox 0.8.0 → 0.9.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 +33 -0
- package/Index.svelte +60 -2
- package/MultimodalTextbox.stories.svelte +10 -0
- package/MultimodalTextbox.test.ts +19 -0
- package/dist/Index.svelte +49 -2
- package/dist/Index.svelte.d.ts +23 -4
- package/dist/shared/MultimodalTextbox.svelte +187 -120
- package/dist/shared/MultimodalTextbox.svelte.d.ts +9 -1
- package/package.json +9 -9
- package/shared/MultimodalTextbox.svelte +193 -122
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @gradio/multimodaltextbox
|
|
2
2
|
|
|
3
|
+
## 0.9.1
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
|
|
7
|
+
- [#10322](https://github.com/gradio-app/gradio/pull/10322) [`d2691e7`](https://github.com/gradio-app/gradio/commit/d2691e7436f722781ee61db43ce3f2d5ccc3e253) - Quick Fix: Multimodal microphone audio not clearing. Thanks @dawoodkhan82!
|
|
8
|
+
|
|
9
|
+
### Dependency updates
|
|
10
|
+
|
|
11
|
+
- @gradio/video@0.13.1
|
|
12
|
+
- @gradio/atoms@0.13.1
|
|
13
|
+
- @gradio/statustracker@0.10.1
|
|
14
|
+
- @gradio/client@1.10.0
|
|
15
|
+
- @gradio/icons@0.10.0
|
|
16
|
+
- @gradio/upload@0.14.5
|
|
17
|
+
- @gradio/image@0.20.1
|
|
18
|
+
|
|
19
|
+
## 0.9.0
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
- [#10186](https://github.com/gradio-app/gradio/pull/10186) [`9b17032`](https://github.com/gradio-app/gradio/commit/9b17032a6564c8bda4ab1749989a9797c670919c) - Add Microphone Input to MultimodalTextbox. Thanks @dawoodkhan82!
|
|
24
|
+
|
|
25
|
+
### Dependency updates
|
|
26
|
+
|
|
27
|
+
- @gradio/atoms@0.13.0
|
|
28
|
+
- @gradio/utils@0.10.0
|
|
29
|
+
- @gradio/upload@0.14.4
|
|
30
|
+
- @gradio/client@1.9.0
|
|
31
|
+
- @gradio/icons@0.9.0
|
|
32
|
+
- @gradio/statustracker@0.10.0
|
|
33
|
+
- @gradio/image@0.20.0
|
|
34
|
+
- @gradio/video@0.13.0
|
|
35
|
+
|
|
3
36
|
## 0.8.0
|
|
4
37
|
|
|
5
38
|
### Features
|
package/Index.svelte
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
import { StatusTracker } from "@gradio/statustracker";
|
|
13
13
|
import type { LoadingStatus } from "@gradio/statustracker";
|
|
14
14
|
import type { FileData } from "@gradio/client";
|
|
15
|
+
import { onMount } from "svelte";
|
|
16
|
+
import type { WaveformOptions } from "../audio/shared/types";
|
|
15
17
|
|
|
16
18
|
export let gradio: Gradio<{
|
|
17
19
|
change: typeof value;
|
|
@@ -23,6 +25,11 @@
|
|
|
23
25
|
focus: never;
|
|
24
26
|
error: string;
|
|
25
27
|
clear_status: LoadingStatus;
|
|
28
|
+
start_recording: never;
|
|
29
|
+
pause_recording: never;
|
|
30
|
+
stop_recording: never;
|
|
31
|
+
upload: FileData[] | FileData;
|
|
32
|
+
clear: undefined;
|
|
26
33
|
}>;
|
|
27
34
|
export let elem_id = "";
|
|
28
35
|
export let elem_classes: string[] = [];
|
|
@@ -38,7 +45,6 @@
|
|
|
38
45
|
export let info: string | undefined = undefined;
|
|
39
46
|
export let show_label: boolean;
|
|
40
47
|
export let max_lines: number;
|
|
41
|
-
export let container = true;
|
|
42
48
|
export let scale: number | null = null;
|
|
43
49
|
export let min_width: number | undefined = undefined;
|
|
44
50
|
export let submit_btn: string | boolean | null = null;
|
|
@@ -53,8 +59,52 @@
|
|
|
53
59
|
export let root: string;
|
|
54
60
|
export let file_count: "single" | "multiple" | "directory";
|
|
55
61
|
export let max_plain_text_length: number;
|
|
62
|
+
export let sources: ["microphone" | "upload"] = ["upload"];
|
|
63
|
+
export let waveform_options: WaveformOptions = {};
|
|
56
64
|
|
|
57
65
|
let dragging: boolean;
|
|
66
|
+
let active_source: "microphone" | null = null;
|
|
67
|
+
let waveform_settings: Record<string, any>;
|
|
68
|
+
let color_accent = "darkorange";
|
|
69
|
+
|
|
70
|
+
onMount(() => {
|
|
71
|
+
color_accent = getComputedStyle(document?.documentElement).getPropertyValue(
|
|
72
|
+
"--color-accent"
|
|
73
|
+
);
|
|
74
|
+
set_trim_region_colour();
|
|
75
|
+
waveform_settings.waveColor = waveform_options.waveform_color || "#9ca3af";
|
|
76
|
+
waveform_settings.progressColor =
|
|
77
|
+
waveform_options.waveform_progress_color || color_accent;
|
|
78
|
+
waveform_settings.mediaControls = waveform_options.show_controls;
|
|
79
|
+
waveform_settings.sampleRate = waveform_options.sample_rate || 44100;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
$: waveform_settings = {
|
|
83
|
+
height: 50,
|
|
84
|
+
|
|
85
|
+
barWidth: 2,
|
|
86
|
+
barGap: 3,
|
|
87
|
+
cursorWidth: 2,
|
|
88
|
+
cursorColor: "#ddd5e9",
|
|
89
|
+
autoplay: false,
|
|
90
|
+
barRadius: 10,
|
|
91
|
+
dragToSeek: true,
|
|
92
|
+
normalize: true,
|
|
93
|
+
minPxPerSec: 20
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const trim_region_settings = {
|
|
97
|
+
color: waveform_options.trim_region_color,
|
|
98
|
+
drag: true,
|
|
99
|
+
resize: true
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
function set_trim_region_colour(): void {
|
|
103
|
+
document.documentElement.style.setProperty(
|
|
104
|
+
"--trim-region-color",
|
|
105
|
+
trim_region_settings.color || color_accent
|
|
106
|
+
);
|
|
107
|
+
}
|
|
58
108
|
</script>
|
|
59
109
|
|
|
60
110
|
<Block
|
|
@@ -80,6 +130,7 @@
|
|
|
80
130
|
bind:value
|
|
81
131
|
bind:value_is_output
|
|
82
132
|
bind:dragging
|
|
133
|
+
bind:active_source
|
|
83
134
|
{file_types}
|
|
84
135
|
{root}
|
|
85
136
|
{label}
|
|
@@ -88,14 +139,16 @@
|
|
|
88
139
|
{lines}
|
|
89
140
|
{rtl}
|
|
90
141
|
{text_align}
|
|
142
|
+
{waveform_settings}
|
|
143
|
+
i18n={gradio.i18n}
|
|
91
144
|
max_lines={!max_lines ? lines + 1 : max_lines}
|
|
92
145
|
{placeholder}
|
|
93
146
|
{submit_btn}
|
|
94
147
|
{stop_btn}
|
|
95
148
|
{autofocus}
|
|
96
|
-
{container}
|
|
97
149
|
{autoscroll}
|
|
98
150
|
{file_count}
|
|
151
|
+
{sources}
|
|
99
152
|
max_file_size={gradio.max_file_size}
|
|
100
153
|
on:change={() => gradio.dispatch("change", value)}
|
|
101
154
|
on:input={() => gradio.dispatch("input")}
|
|
@@ -107,6 +160,11 @@
|
|
|
107
160
|
on:error={({ detail }) => {
|
|
108
161
|
gradio.dispatch("error", detail);
|
|
109
162
|
}}
|
|
163
|
+
on:start_recording={() => gradio.dispatch("start_recording")}
|
|
164
|
+
on:pause_recording={() => gradio.dispatch("pause_recording")}
|
|
165
|
+
on:stop_recording={() => gradio.dispatch("stop_recording")}
|
|
166
|
+
on:upload={(e) => gradio.dispatch("upload", e.detail)}
|
|
167
|
+
on:clear={() => gradio.dispatch("clear")}
|
|
110
168
|
disabled={!interactive}
|
|
111
169
|
upload={(...args) => gradio.client.upload(...args)}
|
|
112
170
|
stream_handler={(...args) => gradio.client.stream(...args)}
|
|
@@ -42,6 +42,12 @@
|
|
|
42
42
|
description: "Whether to render right-to-left",
|
|
43
43
|
control: { type: "boolean" },
|
|
44
44
|
defaultValue: false
|
|
45
|
+
},
|
|
46
|
+
sources: {
|
|
47
|
+
options: ["upload", "microphone"],
|
|
48
|
+
description: "The sources to enable",
|
|
49
|
+
control: { type: "select" },
|
|
50
|
+
defaultValue: ["upload", "microphone"]
|
|
45
51
|
}
|
|
46
52
|
}}
|
|
47
53
|
/>
|
|
@@ -87,3 +93,7 @@
|
|
|
87
93
|
}
|
|
88
94
|
}}
|
|
89
95
|
/>
|
|
96
|
+
<Story
|
|
97
|
+
name="MultimodalTextbox with microphone input"
|
|
98
|
+
args={{ sources: ["microphone"] }}
|
|
99
|
+
/>
|
|
@@ -65,4 +65,23 @@ describe("MultimodalTextbox", () => {
|
|
|
65
65
|
assert.equal(mock.calls[8][0].detail.data.text, "hi some text");
|
|
66
66
|
assert.equal(mock.calls[8][0].detail.data.files.length, 0);
|
|
67
67
|
});
|
|
68
|
+
|
|
69
|
+
test("submitting should clear mic_audio", async () => {
|
|
70
|
+
const { component } = await render(MultimodalTextbox, {
|
|
71
|
+
show_label: true,
|
|
72
|
+
max_lines: 10,
|
|
73
|
+
loading_status,
|
|
74
|
+
lines: 1,
|
|
75
|
+
value: { text: "", files: [] },
|
|
76
|
+
label: "MultimodalTextbox",
|
|
77
|
+
interactive: true,
|
|
78
|
+
root: "",
|
|
79
|
+
sources: ["microphone"]
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
component.$set({ mic_audio: { url: "test.mp3", mime_type: "audio/mp3" } });
|
|
83
|
+
component.$set({ active_source: "microphone" });
|
|
84
|
+
await component.$$.ctx[component.$$.props["handle_submit"]];
|
|
85
|
+
assert.equal(component.mic_audio, null);
|
|
86
|
+
});
|
|
68
87
|
});
|
package/dist/Index.svelte
CHANGED
|
@@ -7,6 +7,7 @@ export { default as BaseExample } from "./Example.svelte";
|
|
|
7
7
|
<script>import MultimodalTextbox from "./shared/MultimodalTextbox.svelte";
|
|
8
8
|
import { Block } from "@gradio/atoms";
|
|
9
9
|
import { StatusTracker } from "@gradio/statustracker";
|
|
10
|
+
import { onMount } from "svelte";
|
|
10
11
|
export let gradio;
|
|
11
12
|
export let elem_id = "";
|
|
12
13
|
export let elem_classes = [];
|
|
@@ -22,7 +23,6 @@ export let label = "MultimodalTextbox";
|
|
|
22
23
|
export let info = void 0;
|
|
23
24
|
export let show_label;
|
|
24
25
|
export let max_lines;
|
|
25
|
-
export let container = true;
|
|
26
26
|
export let scale = null;
|
|
27
27
|
export let min_width = void 0;
|
|
28
28
|
export let submit_btn = null;
|
|
@@ -37,7 +37,46 @@ export let interactive;
|
|
|
37
37
|
export let root;
|
|
38
38
|
export let file_count;
|
|
39
39
|
export let max_plain_text_length;
|
|
40
|
+
export let sources = ["upload"];
|
|
41
|
+
export let waveform_options = {};
|
|
40
42
|
let dragging;
|
|
43
|
+
let active_source = null;
|
|
44
|
+
let waveform_settings;
|
|
45
|
+
let color_accent = "darkorange";
|
|
46
|
+
onMount(() => {
|
|
47
|
+
color_accent = getComputedStyle(document?.documentElement).getPropertyValue(
|
|
48
|
+
"--color-accent"
|
|
49
|
+
);
|
|
50
|
+
set_trim_region_colour();
|
|
51
|
+
waveform_settings.waveColor = waveform_options.waveform_color || "#9ca3af";
|
|
52
|
+
waveform_settings.progressColor = waveform_options.waveform_progress_color || color_accent;
|
|
53
|
+
waveform_settings.mediaControls = waveform_options.show_controls;
|
|
54
|
+
waveform_settings.sampleRate = waveform_options.sample_rate || 44100;
|
|
55
|
+
});
|
|
56
|
+
$:
|
|
57
|
+
waveform_settings = {
|
|
58
|
+
height: 50,
|
|
59
|
+
barWidth: 2,
|
|
60
|
+
barGap: 3,
|
|
61
|
+
cursorWidth: 2,
|
|
62
|
+
cursorColor: "#ddd5e9",
|
|
63
|
+
autoplay: false,
|
|
64
|
+
barRadius: 10,
|
|
65
|
+
dragToSeek: true,
|
|
66
|
+
normalize: true,
|
|
67
|
+
minPxPerSec: 20
|
|
68
|
+
};
|
|
69
|
+
const trim_region_settings = {
|
|
70
|
+
color: waveform_options.trim_region_color,
|
|
71
|
+
drag: true,
|
|
72
|
+
resize: true
|
|
73
|
+
};
|
|
74
|
+
function set_trim_region_colour() {
|
|
75
|
+
document.documentElement.style.setProperty(
|
|
76
|
+
"--trim-region-color",
|
|
77
|
+
trim_region_settings.color || color_accent
|
|
78
|
+
);
|
|
79
|
+
}
|
|
41
80
|
</script>
|
|
42
81
|
|
|
43
82
|
<Block
|
|
@@ -63,6 +102,7 @@ let dragging;
|
|
|
63
102
|
bind:value
|
|
64
103
|
bind:value_is_output
|
|
65
104
|
bind:dragging
|
|
105
|
+
bind:active_source
|
|
66
106
|
{file_types}
|
|
67
107
|
{root}
|
|
68
108
|
{label}
|
|
@@ -71,14 +111,16 @@ let dragging;
|
|
|
71
111
|
{lines}
|
|
72
112
|
{rtl}
|
|
73
113
|
{text_align}
|
|
114
|
+
{waveform_settings}
|
|
115
|
+
i18n={gradio.i18n}
|
|
74
116
|
max_lines={!max_lines ? lines + 1 : max_lines}
|
|
75
117
|
{placeholder}
|
|
76
118
|
{submit_btn}
|
|
77
119
|
{stop_btn}
|
|
78
120
|
{autofocus}
|
|
79
|
-
{container}
|
|
80
121
|
{autoscroll}
|
|
81
122
|
{file_count}
|
|
123
|
+
{sources}
|
|
82
124
|
max_file_size={gradio.max_file_size}
|
|
83
125
|
on:change={() => gradio.dispatch("change", value)}
|
|
84
126
|
on:input={() => gradio.dispatch("input")}
|
|
@@ -90,6 +132,11 @@ let dragging;
|
|
|
90
132
|
on:error={({ detail }) => {
|
|
91
133
|
gradio.dispatch("error", detail);
|
|
92
134
|
}}
|
|
135
|
+
on:start_recording={() => gradio.dispatch("start_recording")}
|
|
136
|
+
on:pause_recording={() => gradio.dispatch("pause_recording")}
|
|
137
|
+
on:stop_recording={() => gradio.dispatch("stop_recording")}
|
|
138
|
+
on:upload={(e) => gradio.dispatch("upload", e.detail)}
|
|
139
|
+
on:clear={() => gradio.dispatch("clear")}
|
|
93
140
|
disabled={!interactive}
|
|
94
141
|
upload={(...args) => gradio.client.upload(...args)}
|
|
95
142
|
stream_handler={(...args) => gradio.client.stream(...args)}
|
package/dist/Index.svelte.d.ts
CHANGED
|
@@ -19,6 +19,11 @@ declare const __propDef: {
|
|
|
19
19
|
focus: never;
|
|
20
20
|
error: string;
|
|
21
21
|
clear_status: LoadingStatus;
|
|
22
|
+
start_recording: never;
|
|
23
|
+
pause_recording: never;
|
|
24
|
+
stop_recording: never;
|
|
25
|
+
upload: FileData[] | FileData;
|
|
26
|
+
clear: undefined;
|
|
22
27
|
}>;
|
|
23
28
|
elem_id?: string | undefined;
|
|
24
29
|
elem_classes?: string[] | undefined;
|
|
@@ -34,7 +39,6 @@ declare const __propDef: {
|
|
|
34
39
|
info?: string | undefined;
|
|
35
40
|
show_label: boolean;
|
|
36
41
|
max_lines: number;
|
|
37
|
-
container?: boolean | undefined;
|
|
38
42
|
scale?: (number | null) | undefined;
|
|
39
43
|
min_width?: number | undefined;
|
|
40
44
|
submit_btn?: (string | boolean | null) | undefined;
|
|
@@ -49,6 +53,8 @@ declare const __propDef: {
|
|
|
49
53
|
root: string;
|
|
50
54
|
file_count: "single" | "multiple" | "directory";
|
|
51
55
|
max_plain_text_length: number;
|
|
56
|
+
sources?: ["microphone" | "upload"] | undefined;
|
|
57
|
+
waveform_options?: any;
|
|
52
58
|
};
|
|
53
59
|
events: {
|
|
54
60
|
[evt: string]: CustomEvent<any>;
|
|
@@ -72,6 +78,11 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
|
|
|
72
78
|
focus: never;
|
|
73
79
|
error: string;
|
|
74
80
|
clear_status: LoadingStatus;
|
|
81
|
+
start_recording: never;
|
|
82
|
+
pause_recording: never;
|
|
83
|
+
stop_recording: never;
|
|
84
|
+
upload: FileData[] | FileData;
|
|
85
|
+
clear: undefined;
|
|
75
86
|
}>;
|
|
76
87
|
/**accessor*/
|
|
77
88
|
set gradio(_: Gradio<{
|
|
@@ -87,6 +98,11 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
|
|
|
87
98
|
focus: never;
|
|
88
99
|
error: string;
|
|
89
100
|
clear_status: LoadingStatus;
|
|
101
|
+
start_recording: never;
|
|
102
|
+
pause_recording: never;
|
|
103
|
+
stop_recording: never;
|
|
104
|
+
upload: FileData[] | FileData;
|
|
105
|
+
clear: undefined;
|
|
90
106
|
}>);
|
|
91
107
|
get elem_id(): string | undefined;
|
|
92
108
|
/**accessor*/
|
|
@@ -127,9 +143,6 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
|
|
|
127
143
|
get max_lines(): number;
|
|
128
144
|
/**accessor*/
|
|
129
145
|
set max_lines(_: number);
|
|
130
|
-
get container(): boolean | undefined;
|
|
131
|
-
/**accessor*/
|
|
132
|
-
set container(_: boolean | undefined);
|
|
133
146
|
get scale(): number | null | undefined;
|
|
134
147
|
/**accessor*/
|
|
135
148
|
set scale(_: number | null | undefined);
|
|
@@ -172,4 +185,10 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
|
|
|
172
185
|
get max_plain_text_length(): number;
|
|
173
186
|
/**accessor*/
|
|
174
187
|
set max_plain_text_length(_: number);
|
|
188
|
+
get sources(): ["upload" | "microphone"] | undefined;
|
|
189
|
+
/**accessor*/
|
|
190
|
+
set sources(_: ["upload" | "microphone"] | undefined);
|
|
191
|
+
get waveform_options(): any;
|
|
192
|
+
/**accessor*/
|
|
193
|
+
set waveform_options(_: any);
|
|
175
194
|
}
|
|
@@ -16,20 +16,22 @@ import {
|
|
|
16
16
|
Paperclip,
|
|
17
17
|
Video,
|
|
18
18
|
Send,
|
|
19
|
-
Square
|
|
19
|
+
Square,
|
|
20
|
+
Microphone
|
|
20
21
|
} from "@gradio/icons";
|
|
22
|
+
import InteractiveAudio from "../../audio/interactive/InteractiveAudio.svelte";
|
|
21
23
|
export let value = {
|
|
22
24
|
text: "",
|
|
23
25
|
files: []
|
|
24
26
|
};
|
|
25
27
|
export let value_is_output = false;
|
|
26
28
|
export let lines = 1;
|
|
29
|
+
export let i18n;
|
|
27
30
|
export let placeholder = "Type here...";
|
|
28
31
|
export let disabled = false;
|
|
29
32
|
export let label;
|
|
30
33
|
export let info = void 0;
|
|
31
34
|
export let show_label = true;
|
|
32
|
-
export let container = true;
|
|
33
35
|
export let max_lines;
|
|
34
36
|
export let submit_btn = null;
|
|
35
37
|
export let stop_btn = null;
|
|
@@ -44,6 +46,10 @@ export let upload;
|
|
|
44
46
|
export let stream_handler;
|
|
45
47
|
export let file_count = "multiple";
|
|
46
48
|
export let max_plain_text_length = 1e3;
|
|
49
|
+
export let waveform_settings;
|
|
50
|
+
export let waveform_options = {};
|
|
51
|
+
export let sources = ["upload"];
|
|
52
|
+
export let active_source = null;
|
|
47
53
|
let upload_component;
|
|
48
54
|
let hidden_upload;
|
|
49
55
|
let el;
|
|
@@ -53,8 +59,10 @@ let user_has_scrolled_up = false;
|
|
|
53
59
|
export let dragging = false;
|
|
54
60
|
let uploading = false;
|
|
55
61
|
let oldValue = value.text;
|
|
62
|
+
let recording = false;
|
|
56
63
|
$:
|
|
57
64
|
dispatch("drag", dragging);
|
|
65
|
+
let mic_audio = null;
|
|
58
66
|
let full_container;
|
|
59
67
|
$:
|
|
60
68
|
if (oldValue !== value.text) {
|
|
@@ -109,6 +117,12 @@ async function handle_keypress(e) {
|
|
|
109
117
|
} else if (e.key === "Enter" && !e.shiftKey && lines === 1 && max_lines >= 1) {
|
|
110
118
|
e.preventDefault();
|
|
111
119
|
dispatch("submit");
|
|
120
|
+
active_source = null;
|
|
121
|
+
if (mic_audio) {
|
|
122
|
+
value.files.push(mic_audio);
|
|
123
|
+
value = value;
|
|
124
|
+
mic_audio = null;
|
|
125
|
+
}
|
|
112
126
|
}
|
|
113
127
|
}
|
|
114
128
|
function handle_scroll(event) {
|
|
@@ -158,6 +172,12 @@ function handle_stop() {
|
|
|
158
172
|
}
|
|
159
173
|
function handle_submit() {
|
|
160
174
|
dispatch("submit");
|
|
175
|
+
active_source = null;
|
|
176
|
+
if (mic_audio) {
|
|
177
|
+
value.files.push(mic_audio);
|
|
178
|
+
value = value;
|
|
179
|
+
mic_audio = null;
|
|
180
|
+
}
|
|
161
181
|
}
|
|
162
182
|
async function handle_paste(event) {
|
|
163
183
|
if (!event.clipboardData)
|
|
@@ -238,127 +258,167 @@ function handle_drop(event) {
|
|
|
238
258
|
role="group"
|
|
239
259
|
aria-label="Multimedia input field"
|
|
240
260
|
>
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
<
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
261
|
+
<BlockTitle {root} {show_label} {info}>{label}</BlockTitle>
|
|
262
|
+
{#if value.files.length > 0 || uploading}
|
|
263
|
+
<div
|
|
264
|
+
class="thumbnails scroll-hide"
|
|
265
|
+
aria-label="Uploaded files"
|
|
266
|
+
data-testid="container_el"
|
|
267
|
+
style="display: {value.files.length > 0 || uploading ? 'flex' : 'none'};"
|
|
268
|
+
>
|
|
269
|
+
{#each value.files as file, index}
|
|
270
|
+
<span role="listitem" aria-label="File thumbnail">
|
|
271
|
+
<button class="thumbnail-item thumbnail-small">
|
|
272
|
+
<button
|
|
273
|
+
class:disabled
|
|
274
|
+
class="delete-button"
|
|
275
|
+
on:click={(event) => remove_thumbnail(event, index)}
|
|
276
|
+
><Clear /></button
|
|
277
|
+
>
|
|
278
|
+
{#if file.mime_type && file.mime_type.includes("image")}
|
|
279
|
+
<Image
|
|
280
|
+
src={file.url}
|
|
281
|
+
title={null}
|
|
282
|
+
alt=""
|
|
283
|
+
loading="lazy"
|
|
284
|
+
class={"thumbnail-image"}
|
|
285
|
+
/>
|
|
286
|
+
{:else if file.mime_type && file.mime_type.includes("audio")}
|
|
287
|
+
<Music />
|
|
288
|
+
{:else if file.mime_type && file.mime_type.includes("video")}
|
|
289
|
+
<Video />
|
|
290
|
+
{:else}
|
|
291
|
+
<File />
|
|
292
|
+
{/if}
|
|
293
|
+
</button>
|
|
294
|
+
</span>
|
|
295
|
+
{/each}
|
|
296
|
+
{#if uploading}
|
|
297
|
+
<div class="loader" role="status" aria-label="Uploading"></div>
|
|
298
|
+
{/if}
|
|
299
|
+
</div>
|
|
300
|
+
{/if}
|
|
301
|
+
{#if sources && sources.includes("microphone") && active_source === "microphone"}
|
|
302
|
+
<InteractiveAudio
|
|
303
|
+
on:change={({ detail }) => {
|
|
304
|
+
if (detail !== null) {
|
|
305
|
+
mic_audio = detail;
|
|
306
|
+
}
|
|
307
|
+
}}
|
|
308
|
+
on:clear={() => {
|
|
309
|
+
active_source = null;
|
|
310
|
+
}}
|
|
311
|
+
on:start_recording={() => dispatch("start_recording")}
|
|
312
|
+
on:pause_recording={() => dispatch("pause_recording")}
|
|
313
|
+
on:stop_recording={() => dispatch("stop_recording")}
|
|
314
|
+
sources={["microphone"]}
|
|
315
|
+
class_name="compact-audio"
|
|
316
|
+
{recording}
|
|
317
|
+
{waveform_settings}
|
|
318
|
+
{waveform_options}
|
|
319
|
+
{i18n}
|
|
320
|
+
{active_source}
|
|
321
|
+
{upload}
|
|
322
|
+
{stream_handler}
|
|
323
|
+
stream_every={1}
|
|
324
|
+
editable={true}
|
|
325
|
+
{label}
|
|
326
|
+
{root}
|
|
327
|
+
loop={false}
|
|
328
|
+
show_label={false}
|
|
329
|
+
show_download_button={false}
|
|
330
|
+
dragging={false}
|
|
331
|
+
/>
|
|
332
|
+
{/if}
|
|
333
|
+
<div class="input-container">
|
|
334
|
+
{#if sources && sources.includes("upload") && !disabled && !(file_count === "single" && value.files.length > 0)}
|
|
335
|
+
<Upload
|
|
336
|
+
bind:this={upload_component}
|
|
337
|
+
on:load={handle_upload}
|
|
338
|
+
{file_count}
|
|
339
|
+
filetype={file_types}
|
|
340
|
+
{root}
|
|
341
|
+
{max_file_size}
|
|
342
|
+
bind:dragging
|
|
343
|
+
bind:uploading
|
|
344
|
+
show_progress={false}
|
|
345
|
+
disable_click={true}
|
|
346
|
+
bind:hidden_upload
|
|
347
|
+
on:error
|
|
348
|
+
hidden={true}
|
|
349
|
+
{upload}
|
|
350
|
+
{stream_handler}
|
|
351
|
+
/>
|
|
352
|
+
<button
|
|
353
|
+
data-testid="upload-button"
|
|
354
|
+
class="upload-button"
|
|
355
|
+
on:click={handle_upload_click}><Paperclip /></button
|
|
252
356
|
>
|
|
253
|
-
{#each value.files as file, index}
|
|
254
|
-
<span role="listitem" aria-label="File thumbnail">
|
|
255
|
-
<button class="thumbnail-item thumbnail-small">
|
|
256
|
-
<button
|
|
257
|
-
class:disabled
|
|
258
|
-
class="delete-button"
|
|
259
|
-
on:click={(event) => remove_thumbnail(event, index)}
|
|
260
|
-
><Clear /></button
|
|
261
|
-
>
|
|
262
|
-
{#if file.mime_type && file.mime_type.includes("image")}
|
|
263
|
-
<Image
|
|
264
|
-
src={file.url}
|
|
265
|
-
title={null}
|
|
266
|
-
alt=""
|
|
267
|
-
loading="lazy"
|
|
268
|
-
class={"thumbnail-image"}
|
|
269
|
-
/>
|
|
270
|
-
{:else if file.mime_type && file.mime_type.includes("audio")}
|
|
271
|
-
<Music />
|
|
272
|
-
{:else if file.mime_type && file.mime_type.includes("video")}
|
|
273
|
-
<Video />
|
|
274
|
-
{:else}
|
|
275
|
-
<File />
|
|
276
|
-
{/if}
|
|
277
|
-
</button>
|
|
278
|
-
</span>
|
|
279
|
-
{/each}
|
|
280
|
-
{#if uploading}
|
|
281
|
-
<div class="loader" role="status" aria-label="Uploading"></div>
|
|
282
|
-
{/if}
|
|
283
|
-
</div>
|
|
284
357
|
{/if}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
{root}
|
|
293
|
-
{max_file_size}
|
|
294
|
-
bind:dragging
|
|
295
|
-
bind:uploading
|
|
296
|
-
show_progress={false}
|
|
297
|
-
disable_click={true}
|
|
298
|
-
bind:hidden_upload
|
|
299
|
-
on:error
|
|
300
|
-
hidden={true}
|
|
301
|
-
{upload}
|
|
302
|
-
{stream_handler}
|
|
303
|
-
></Upload>
|
|
304
|
-
<button
|
|
305
|
-
data-testid="upload-button"
|
|
306
|
-
class="upload-button"
|
|
307
|
-
on:click={handle_upload_click}><Paperclip /></button
|
|
308
|
-
>
|
|
309
|
-
{/if}
|
|
310
|
-
<textarea
|
|
311
|
-
data-testid="textbox"
|
|
312
|
-
use:text_area_resize={{
|
|
313
|
-
text: value.text,
|
|
314
|
-
lines: lines,
|
|
315
|
-
max_lines: max_lines
|
|
358
|
+
{#if sources && sources.includes("microphone")}
|
|
359
|
+
<button
|
|
360
|
+
data-testid="microphone-button"
|
|
361
|
+
class="microphone-button"
|
|
362
|
+
class:recording
|
|
363
|
+
on:click={() => {
|
|
364
|
+
active_source = active_source !== "microphone" ? "microphone" : null;
|
|
316
365
|
}}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
{
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
{
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
366
|
+
>
|
|
367
|
+
<Microphone />
|
|
368
|
+
</button>
|
|
369
|
+
{/if}
|
|
370
|
+
<!-- svelte-ignore a11y-autofocus -->
|
|
371
|
+
<textarea
|
|
372
|
+
data-testid="textbox"
|
|
373
|
+
use:text_area_resize={{
|
|
374
|
+
text: value.text,
|
|
375
|
+
lines: lines,
|
|
376
|
+
max_lines: max_lines
|
|
377
|
+
}}
|
|
378
|
+
class="scroll-hide"
|
|
379
|
+
class:no-label={!show_label}
|
|
380
|
+
dir={rtl ? "rtl" : "ltr"}
|
|
381
|
+
bind:value={value.text}
|
|
382
|
+
bind:this={el}
|
|
383
|
+
{placeholder}
|
|
384
|
+
rows={lines}
|
|
385
|
+
{disabled}
|
|
386
|
+
{autofocus}
|
|
387
|
+
on:keypress={handle_keypress}
|
|
388
|
+
on:blur
|
|
389
|
+
on:select={handle_select}
|
|
390
|
+
on:focus
|
|
391
|
+
on:scroll={handle_scroll}
|
|
392
|
+
on:paste={handle_paste}
|
|
393
|
+
style={text_align ? "text-align: " + text_align : ""}
|
|
394
|
+
/>
|
|
395
|
+
{#if submit_btn}
|
|
396
|
+
<button
|
|
397
|
+
class="submit-button"
|
|
398
|
+
class:padded-button={submit_btn !== true}
|
|
399
|
+
on:click={handle_submit}
|
|
400
|
+
>
|
|
401
|
+
{#if submit_btn === true}
|
|
402
|
+
<Send />
|
|
403
|
+
{:else}
|
|
404
|
+
{submit_btn}
|
|
405
|
+
{/if}
|
|
406
|
+
</button>
|
|
407
|
+
{/if}
|
|
408
|
+
{#if stop_btn}
|
|
409
|
+
<button
|
|
410
|
+
class="stop-button"
|
|
411
|
+
class:padded-button={stop_btn !== true}
|
|
412
|
+
on:click={handle_stop}
|
|
413
|
+
>
|
|
414
|
+
{#if stop_btn === true}
|
|
415
|
+
<Square fill={"none"} stroke_width={2.5} />
|
|
416
|
+
{:else}
|
|
417
|
+
{stop_btn}
|
|
418
|
+
{/if}
|
|
419
|
+
</button>
|
|
420
|
+
{/if}
|
|
421
|
+
</div>
|
|
362
422
|
</div>
|
|
363
423
|
|
|
364
424
|
<style>
|
|
@@ -420,6 +480,7 @@ function handle_drop(event) {
|
|
|
420
480
|
color: var(--input-placeholder-color);
|
|
421
481
|
}
|
|
422
482
|
|
|
483
|
+
.microphone-button,
|
|
423
484
|
.upload-button,
|
|
424
485
|
.submit-button,
|
|
425
486
|
.stop-button {
|
|
@@ -436,29 +497,34 @@ function handle_drop(event) {
|
|
|
436
497
|
justify-content: center;
|
|
437
498
|
align-items: center;
|
|
438
499
|
z-index: var(--layer-1);
|
|
500
|
+
margin-left: var(--spacing-sm);
|
|
439
501
|
}
|
|
440
502
|
.padded-button {
|
|
441
503
|
padding: 0 10px;
|
|
442
504
|
}
|
|
443
505
|
|
|
506
|
+
.microphone-button,
|
|
444
507
|
.stop-button,
|
|
445
508
|
.upload-button,
|
|
446
509
|
.submit-button {
|
|
447
510
|
background: var(--button-secondary-background-fill);
|
|
448
511
|
}
|
|
449
512
|
|
|
513
|
+
.microphone-button:hover,
|
|
450
514
|
.stop-button:hover,
|
|
451
515
|
.upload-button:hover,
|
|
452
516
|
.submit-button:hover {
|
|
453
517
|
background: var(--button-secondary-background-fill-hover);
|
|
454
518
|
}
|
|
455
519
|
|
|
520
|
+
.microphone-button:disabled,
|
|
456
521
|
.stop-button:disabled,
|
|
457
522
|
.upload-button:disabled,
|
|
458
523
|
.submit-button:disabled {
|
|
459
524
|
background: var(--button-secondary-background-fill);
|
|
460
525
|
cursor: initial;
|
|
461
526
|
}
|
|
527
|
+
.microphone-button:active,
|
|
462
528
|
.stop-button:active,
|
|
463
529
|
.upload-button:active,
|
|
464
530
|
.submit-button:active {
|
|
@@ -469,6 +535,7 @@ function handle_drop(event) {
|
|
|
469
535
|
height: 22px;
|
|
470
536
|
width: 22px;
|
|
471
537
|
}
|
|
538
|
+
.microphone-button :global(svg),
|
|
472
539
|
.upload-button :global(svg) {
|
|
473
540
|
height: 17px;
|
|
474
541
|
width: 17px;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { I18nFormatter } from "js/core/src/gradio_helper";
|
|
2
3
|
import type { FileData, Client } from "@gradio/client";
|
|
3
4
|
import type { SelectData } from "@gradio/utils";
|
|
4
5
|
declare const __propDef: {
|
|
@@ -9,12 +10,12 @@ declare const __propDef: {
|
|
|
9
10
|
} | undefined;
|
|
10
11
|
value_is_output?: boolean | undefined;
|
|
11
12
|
lines?: number | undefined;
|
|
13
|
+
i18n: I18nFormatter;
|
|
12
14
|
placeholder?: string | undefined;
|
|
13
15
|
disabled?: boolean | undefined;
|
|
14
16
|
label: string;
|
|
15
17
|
info?: string | undefined;
|
|
16
18
|
show_label?: boolean | undefined;
|
|
17
|
-
container?: boolean | undefined;
|
|
18
19
|
max_lines: number;
|
|
19
20
|
submit_btn?: (string | boolean | null) | undefined;
|
|
20
21
|
stop_btn?: (string | boolean | null) | undefined;
|
|
@@ -29,6 +30,10 @@ declare const __propDef: {
|
|
|
29
30
|
stream_handler: Client["stream"];
|
|
30
31
|
file_count?: ("single" | "multiple" | "directory") | undefined;
|
|
31
32
|
max_plain_text_length?: number | undefined;
|
|
33
|
+
waveform_settings: Record<string, any>;
|
|
34
|
+
waveform_options?: any;
|
|
35
|
+
sources?: ["microphone" | "upload"] | undefined;
|
|
36
|
+
active_source?: ("microphone" | null) | undefined;
|
|
32
37
|
dragging?: boolean | undefined;
|
|
33
38
|
};
|
|
34
39
|
events: {
|
|
@@ -48,6 +53,9 @@ declare const __propDef: {
|
|
|
48
53
|
upload: CustomEvent<any>;
|
|
49
54
|
clear: CustomEvent<undefined>;
|
|
50
55
|
load: CustomEvent<any>;
|
|
56
|
+
start_recording: CustomEvent<undefined>;
|
|
57
|
+
pause_recording: CustomEvent<undefined>;
|
|
58
|
+
stop_recording: CustomEvent<undefined>;
|
|
51
59
|
} & {
|
|
52
60
|
[evt: string]: CustomEvent<any>;
|
|
53
61
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/multimodaltextbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
"./package.json": "./package.json"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@gradio/atoms": "^0.
|
|
26
|
-
"@gradio/statustracker": "^0.
|
|
27
|
-
"@gradio/
|
|
28
|
-
"@gradio/upload": "^0.14.
|
|
29
|
-
"@gradio/
|
|
30
|
-
"@gradio/image": "^0.
|
|
31
|
-
"@gradio/
|
|
32
|
-
"@gradio/client": "^1.
|
|
25
|
+
"@gradio/atoms": "^0.13.1",
|
|
26
|
+
"@gradio/statustracker": "^0.10.1",
|
|
27
|
+
"@gradio/icons": "^0.10.0",
|
|
28
|
+
"@gradio/upload": "^0.14.5",
|
|
29
|
+
"@gradio/utils": "^0.10.0",
|
|
30
|
+
"@gradio/image": "^0.20.1",
|
|
31
|
+
"@gradio/video": "^0.13.1",
|
|
32
|
+
"@gradio/client": "^1.10.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@gradio/preview": "^0.13.0"
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
import { BlockTitle } from "@gradio/atoms";
|
|
11
11
|
import { Upload } from "@gradio/upload";
|
|
12
12
|
import { Image } from "@gradio/image/shared";
|
|
13
|
+
import type { I18nFormatter } from "js/core/src/gradio_helper";
|
|
13
14
|
import type { FileData, Client } from "@gradio/client";
|
|
15
|
+
import type { WaveformOptions } from "../../audio/shared/types";
|
|
14
16
|
import {
|
|
15
17
|
Clear,
|
|
16
18
|
File,
|
|
@@ -18,9 +20,11 @@
|
|
|
18
20
|
Paperclip,
|
|
19
21
|
Video,
|
|
20
22
|
Send,
|
|
21
|
-
Square
|
|
23
|
+
Square,
|
|
24
|
+
Microphone
|
|
22
25
|
} from "@gradio/icons";
|
|
23
26
|
import type { SelectData } from "@gradio/utils";
|
|
27
|
+
import InteractiveAudio from "../../audio/interactive/InteractiveAudio.svelte";
|
|
24
28
|
|
|
25
29
|
export let value: { text: string; files: FileData[] } = {
|
|
26
30
|
text: "",
|
|
@@ -29,12 +33,12 @@
|
|
|
29
33
|
|
|
30
34
|
export let value_is_output = false;
|
|
31
35
|
export let lines = 1;
|
|
36
|
+
export let i18n: I18nFormatter;
|
|
32
37
|
export let placeholder = "Type here...";
|
|
33
38
|
export let disabled = false;
|
|
34
39
|
export let label: string;
|
|
35
40
|
export let info: string | undefined = undefined;
|
|
36
41
|
export let show_label = true;
|
|
37
|
-
export let container = true;
|
|
38
42
|
export let max_lines: number;
|
|
39
43
|
export let submit_btn: string | boolean | null = null;
|
|
40
44
|
export let stop_btn: string | boolean | null = null;
|
|
@@ -49,7 +53,10 @@
|
|
|
49
53
|
export let stream_handler: Client["stream"];
|
|
50
54
|
export let file_count: "single" | "multiple" | "directory" = "multiple";
|
|
51
55
|
export let max_plain_text_length = 1000;
|
|
52
|
-
|
|
56
|
+
export let waveform_settings: Record<string, any>;
|
|
57
|
+
export let waveform_options: WaveformOptions = {};
|
|
58
|
+
export let sources: ["microphone" | "upload"] = ["upload"];
|
|
59
|
+
export let active_source: "microphone" | null = null;
|
|
53
60
|
let upload_component: Upload;
|
|
54
61
|
let hidden_upload: HTMLInputElement;
|
|
55
62
|
let el: HTMLTextAreaElement | HTMLInputElement;
|
|
@@ -59,7 +66,9 @@
|
|
|
59
66
|
export let dragging = false;
|
|
60
67
|
let uploading = false;
|
|
61
68
|
let oldValue = value.text;
|
|
69
|
+
let recording = false;
|
|
62
70
|
$: dispatch("drag", dragging);
|
|
71
|
+
let mic_audio: FileData | null = null;
|
|
63
72
|
|
|
64
73
|
let full_container: HTMLDivElement;
|
|
65
74
|
|
|
@@ -84,6 +93,9 @@
|
|
|
84
93
|
clear: undefined;
|
|
85
94
|
load: FileData[] | FileData;
|
|
86
95
|
error: string;
|
|
96
|
+
start_recording: undefined;
|
|
97
|
+
pause_recording: undefined;
|
|
98
|
+
stop_recording: undefined;
|
|
87
99
|
}>();
|
|
88
100
|
|
|
89
101
|
beforeUpdate(() => {
|
|
@@ -141,6 +153,12 @@
|
|
|
141
153
|
) {
|
|
142
154
|
e.preventDefault();
|
|
143
155
|
dispatch("submit");
|
|
156
|
+
active_source = null;
|
|
157
|
+
if (mic_audio) {
|
|
158
|
+
value.files.push(mic_audio);
|
|
159
|
+
value = value;
|
|
160
|
+
mic_audio = null;
|
|
161
|
+
}
|
|
144
162
|
}
|
|
145
163
|
}
|
|
146
164
|
|
|
@@ -161,7 +179,7 @@
|
|
|
161
179
|
|
|
162
180
|
async function handle_upload({
|
|
163
181
|
detail
|
|
164
|
-
}: CustomEvent<FileData
|
|
182
|
+
}: CustomEvent<FileData>): Promise<void> {
|
|
165
183
|
handle_change();
|
|
166
184
|
if (Array.isArray(detail)) {
|
|
167
185
|
for (let file of detail) {
|
|
@@ -197,6 +215,12 @@
|
|
|
197
215
|
|
|
198
216
|
function handle_submit(): void {
|
|
199
217
|
dispatch("submit");
|
|
218
|
+
active_source = null;
|
|
219
|
+
if (mic_audio) {
|
|
220
|
+
value.files.push(mic_audio);
|
|
221
|
+
value = value;
|
|
222
|
+
mic_audio = null;
|
|
223
|
+
}
|
|
200
224
|
}
|
|
201
225
|
|
|
202
226
|
async function handle_paste(event: ClipboardEvent): Promise<void> {
|
|
@@ -289,127 +313,167 @@
|
|
|
289
313
|
role="group"
|
|
290
314
|
aria-label="Multimedia input field"
|
|
291
315
|
>
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
<
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
316
|
+
<BlockTitle {root} {show_label} {info}>{label}</BlockTitle>
|
|
317
|
+
{#if value.files.length > 0 || uploading}
|
|
318
|
+
<div
|
|
319
|
+
class="thumbnails scroll-hide"
|
|
320
|
+
aria-label="Uploaded files"
|
|
321
|
+
data-testid="container_el"
|
|
322
|
+
style="display: {value.files.length > 0 || uploading ? 'flex' : 'none'};"
|
|
323
|
+
>
|
|
324
|
+
{#each value.files as file, index}
|
|
325
|
+
<span role="listitem" aria-label="File thumbnail">
|
|
326
|
+
<button class="thumbnail-item thumbnail-small">
|
|
327
|
+
<button
|
|
328
|
+
class:disabled
|
|
329
|
+
class="delete-button"
|
|
330
|
+
on:click={(event) => remove_thumbnail(event, index)}
|
|
331
|
+
><Clear /></button
|
|
332
|
+
>
|
|
333
|
+
{#if file.mime_type && file.mime_type.includes("image")}
|
|
334
|
+
<Image
|
|
335
|
+
src={file.url}
|
|
336
|
+
title={null}
|
|
337
|
+
alt=""
|
|
338
|
+
loading="lazy"
|
|
339
|
+
class={"thumbnail-image"}
|
|
340
|
+
/>
|
|
341
|
+
{:else if file.mime_type && file.mime_type.includes("audio")}
|
|
342
|
+
<Music />
|
|
343
|
+
{:else if file.mime_type && file.mime_type.includes("video")}
|
|
344
|
+
<Video />
|
|
345
|
+
{:else}
|
|
346
|
+
<File />
|
|
347
|
+
{/if}
|
|
348
|
+
</button>
|
|
349
|
+
</span>
|
|
350
|
+
{/each}
|
|
351
|
+
{#if uploading}
|
|
352
|
+
<div class="loader" role="status" aria-label="Uploading"></div>
|
|
353
|
+
{/if}
|
|
354
|
+
</div>
|
|
355
|
+
{/if}
|
|
356
|
+
{#if sources && sources.includes("microphone") && active_source === "microphone"}
|
|
357
|
+
<InteractiveAudio
|
|
358
|
+
on:change={({ detail }) => {
|
|
359
|
+
if (detail !== null) {
|
|
360
|
+
mic_audio = detail;
|
|
361
|
+
}
|
|
362
|
+
}}
|
|
363
|
+
on:clear={() => {
|
|
364
|
+
active_source = null;
|
|
365
|
+
}}
|
|
366
|
+
on:start_recording={() => dispatch("start_recording")}
|
|
367
|
+
on:pause_recording={() => dispatch("pause_recording")}
|
|
368
|
+
on:stop_recording={() => dispatch("stop_recording")}
|
|
369
|
+
sources={["microphone"]}
|
|
370
|
+
class_name="compact-audio"
|
|
371
|
+
{recording}
|
|
372
|
+
{waveform_settings}
|
|
373
|
+
{waveform_options}
|
|
374
|
+
{i18n}
|
|
375
|
+
{active_source}
|
|
376
|
+
{upload}
|
|
377
|
+
{stream_handler}
|
|
378
|
+
stream_every={1}
|
|
379
|
+
editable={true}
|
|
380
|
+
{label}
|
|
381
|
+
{root}
|
|
382
|
+
loop={false}
|
|
383
|
+
show_label={false}
|
|
384
|
+
show_download_button={false}
|
|
385
|
+
dragging={false}
|
|
386
|
+
/>
|
|
387
|
+
{/if}
|
|
388
|
+
<div class="input-container">
|
|
389
|
+
{#if sources && sources.includes("upload") && !disabled && !(file_count === "single" && value.files.length > 0)}
|
|
390
|
+
<Upload
|
|
391
|
+
bind:this={upload_component}
|
|
392
|
+
on:load={handle_upload}
|
|
393
|
+
{file_count}
|
|
394
|
+
filetype={file_types}
|
|
395
|
+
{root}
|
|
396
|
+
{max_file_size}
|
|
397
|
+
bind:dragging
|
|
398
|
+
bind:uploading
|
|
399
|
+
show_progress={false}
|
|
400
|
+
disable_click={true}
|
|
401
|
+
bind:hidden_upload
|
|
402
|
+
on:error
|
|
403
|
+
hidden={true}
|
|
404
|
+
{upload}
|
|
405
|
+
{stream_handler}
|
|
406
|
+
/>
|
|
407
|
+
<button
|
|
408
|
+
data-testid="upload-button"
|
|
409
|
+
class="upload-button"
|
|
410
|
+
on:click={handle_upload_click}><Paperclip /></button
|
|
303
411
|
>
|
|
304
|
-
{#each value.files as file, index}
|
|
305
|
-
<span role="listitem" aria-label="File thumbnail">
|
|
306
|
-
<button class="thumbnail-item thumbnail-small">
|
|
307
|
-
<button
|
|
308
|
-
class:disabled
|
|
309
|
-
class="delete-button"
|
|
310
|
-
on:click={(event) => remove_thumbnail(event, index)}
|
|
311
|
-
><Clear /></button
|
|
312
|
-
>
|
|
313
|
-
{#if file.mime_type && file.mime_type.includes("image")}
|
|
314
|
-
<Image
|
|
315
|
-
src={file.url}
|
|
316
|
-
title={null}
|
|
317
|
-
alt=""
|
|
318
|
-
loading="lazy"
|
|
319
|
-
class={"thumbnail-image"}
|
|
320
|
-
/>
|
|
321
|
-
{:else if file.mime_type && file.mime_type.includes("audio")}
|
|
322
|
-
<Music />
|
|
323
|
-
{:else if file.mime_type && file.mime_type.includes("video")}
|
|
324
|
-
<Video />
|
|
325
|
-
{:else}
|
|
326
|
-
<File />
|
|
327
|
-
{/if}
|
|
328
|
-
</button>
|
|
329
|
-
</span>
|
|
330
|
-
{/each}
|
|
331
|
-
{#if uploading}
|
|
332
|
-
<div class="loader" role="status" aria-label="Uploading"></div>
|
|
333
|
-
{/if}
|
|
334
|
-
</div>
|
|
335
412
|
{/if}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
{root}
|
|
344
|
-
{max_file_size}
|
|
345
|
-
bind:dragging
|
|
346
|
-
bind:uploading
|
|
347
|
-
show_progress={false}
|
|
348
|
-
disable_click={true}
|
|
349
|
-
bind:hidden_upload
|
|
350
|
-
on:error
|
|
351
|
-
hidden={true}
|
|
352
|
-
{upload}
|
|
353
|
-
{stream_handler}
|
|
354
|
-
></Upload>
|
|
355
|
-
<button
|
|
356
|
-
data-testid="upload-button"
|
|
357
|
-
class="upload-button"
|
|
358
|
-
on:click={handle_upload_click}><Paperclip /></button
|
|
359
|
-
>
|
|
360
|
-
{/if}
|
|
361
|
-
<textarea
|
|
362
|
-
data-testid="textbox"
|
|
363
|
-
use:text_area_resize={{
|
|
364
|
-
text: value.text,
|
|
365
|
-
lines: lines,
|
|
366
|
-
max_lines: max_lines
|
|
413
|
+
{#if sources && sources.includes("microphone")}
|
|
414
|
+
<button
|
|
415
|
+
data-testid="microphone-button"
|
|
416
|
+
class="microphone-button"
|
|
417
|
+
class:recording
|
|
418
|
+
on:click={() => {
|
|
419
|
+
active_source = active_source !== "microphone" ? "microphone" : null;
|
|
367
420
|
}}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
{
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
{
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
421
|
+
>
|
|
422
|
+
<Microphone />
|
|
423
|
+
</button>
|
|
424
|
+
{/if}
|
|
425
|
+
<!-- svelte-ignore a11y-autofocus -->
|
|
426
|
+
<textarea
|
|
427
|
+
data-testid="textbox"
|
|
428
|
+
use:text_area_resize={{
|
|
429
|
+
text: value.text,
|
|
430
|
+
lines: lines,
|
|
431
|
+
max_lines: max_lines
|
|
432
|
+
}}
|
|
433
|
+
class="scroll-hide"
|
|
434
|
+
class:no-label={!show_label}
|
|
435
|
+
dir={rtl ? "rtl" : "ltr"}
|
|
436
|
+
bind:value={value.text}
|
|
437
|
+
bind:this={el}
|
|
438
|
+
{placeholder}
|
|
439
|
+
rows={lines}
|
|
440
|
+
{disabled}
|
|
441
|
+
{autofocus}
|
|
442
|
+
on:keypress={handle_keypress}
|
|
443
|
+
on:blur
|
|
444
|
+
on:select={handle_select}
|
|
445
|
+
on:focus
|
|
446
|
+
on:scroll={handle_scroll}
|
|
447
|
+
on:paste={handle_paste}
|
|
448
|
+
style={text_align ? "text-align: " + text_align : ""}
|
|
449
|
+
/>
|
|
450
|
+
{#if submit_btn}
|
|
451
|
+
<button
|
|
452
|
+
class="submit-button"
|
|
453
|
+
class:padded-button={submit_btn !== true}
|
|
454
|
+
on:click={handle_submit}
|
|
455
|
+
>
|
|
456
|
+
{#if submit_btn === true}
|
|
457
|
+
<Send />
|
|
458
|
+
{:else}
|
|
459
|
+
{submit_btn}
|
|
460
|
+
{/if}
|
|
461
|
+
</button>
|
|
462
|
+
{/if}
|
|
463
|
+
{#if stop_btn}
|
|
464
|
+
<button
|
|
465
|
+
class="stop-button"
|
|
466
|
+
class:padded-button={stop_btn !== true}
|
|
467
|
+
on:click={handle_stop}
|
|
468
|
+
>
|
|
469
|
+
{#if stop_btn === true}
|
|
470
|
+
<Square fill={"none"} stroke_width={2.5} />
|
|
471
|
+
{:else}
|
|
472
|
+
{stop_btn}
|
|
473
|
+
{/if}
|
|
474
|
+
</button>
|
|
475
|
+
{/if}
|
|
476
|
+
</div>
|
|
413
477
|
</div>
|
|
414
478
|
|
|
415
479
|
<style>
|
|
@@ -471,6 +535,7 @@
|
|
|
471
535
|
color: var(--input-placeholder-color);
|
|
472
536
|
}
|
|
473
537
|
|
|
538
|
+
.microphone-button,
|
|
474
539
|
.upload-button,
|
|
475
540
|
.submit-button,
|
|
476
541
|
.stop-button {
|
|
@@ -487,29 +552,34 @@
|
|
|
487
552
|
justify-content: center;
|
|
488
553
|
align-items: center;
|
|
489
554
|
z-index: var(--layer-1);
|
|
555
|
+
margin-left: var(--spacing-sm);
|
|
490
556
|
}
|
|
491
557
|
.padded-button {
|
|
492
558
|
padding: 0 10px;
|
|
493
559
|
}
|
|
494
560
|
|
|
561
|
+
.microphone-button,
|
|
495
562
|
.stop-button,
|
|
496
563
|
.upload-button,
|
|
497
564
|
.submit-button {
|
|
498
565
|
background: var(--button-secondary-background-fill);
|
|
499
566
|
}
|
|
500
567
|
|
|
568
|
+
.microphone-button:hover,
|
|
501
569
|
.stop-button:hover,
|
|
502
570
|
.upload-button:hover,
|
|
503
571
|
.submit-button:hover {
|
|
504
572
|
background: var(--button-secondary-background-fill-hover);
|
|
505
573
|
}
|
|
506
574
|
|
|
575
|
+
.microphone-button:disabled,
|
|
507
576
|
.stop-button:disabled,
|
|
508
577
|
.upload-button:disabled,
|
|
509
578
|
.submit-button:disabled {
|
|
510
579
|
background: var(--button-secondary-background-fill);
|
|
511
580
|
cursor: initial;
|
|
512
581
|
}
|
|
582
|
+
.microphone-button:active,
|
|
513
583
|
.stop-button:active,
|
|
514
584
|
.upload-button:active,
|
|
515
585
|
.submit-button:active {
|
|
@@ -520,6 +590,7 @@
|
|
|
520
590
|
height: 22px;
|
|
521
591
|
width: 22px;
|
|
522
592
|
}
|
|
593
|
+
.microphone-button :global(svg),
|
|
523
594
|
.upload-button :global(svg) {
|
|
524
595
|
height: 17px;
|
|
525
596
|
width: 17px;
|