@gradio/upload 0.17.2 → 0.17.4
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 +37 -0
- package/dist/src/ModifyUpload.svelte +24 -17
- package/dist/src/ModifyUpload.svelte.d.ts +8 -31
- package/dist/src/Upload.svelte +84 -62
- package/dist/src/Upload.svelte.d.ts +9 -37
- package/dist/src/UploadProgress.svelte +33 -23
- package/dist/src/UploadProgress.svelte.d.ts +5 -20
- package/package.json +6 -6
- package/src/ModifyUpload.svelte +24 -17
- package/src/Upload.svelte +84 -62
- package/src/UploadProgress.svelte +33 -23
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,41 @@
|
|
|
1
1
|
# @gradio/upload
|
|
2
|
+
|
|
3
|
+
## 0.17.4
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
|
|
7
|
+
- [#12800](https://github.com/gradio-app/gradio/pull/12800) [`7a1c321`](https://github.com/gradio-app/gradio/commit/7a1c321b6546ba05a353488f5133e8262c4a8a39) - Bump svelte/kit for security reasons. Thanks @freddyaboulton!
|
|
8
|
+
- [#12779](https://github.com/gradio-app/gradio/pull/12779) [`ea2d3e9`](https://github.com/gradio-app/gradio/commit/ea2d3e985a8b42d188e551f517c5825c00790628) - Migrate Audio + Upload + Atoms to Svelte 5. Thanks @dawoodkhan82!
|
|
9
|
+
- [#12637](https://github.com/gradio-app/gradio/pull/12637) [`e202750`](https://github.com/gradio-app/gradio/commit/e202750b1deb5d4583c07d7d9d1b86f6b3dfef4b) - Fix bug where UploadProgress initializes with a null upload_id. Thanks @freddyaboulton!
|
|
10
|
+
|
|
11
|
+
### Dependency updates
|
|
12
|
+
|
|
13
|
+
- @gradio/atoms@0.20.1
|
|
14
|
+
- @gradio/utils@0.11.2
|
|
15
|
+
- @gradio/icons@0.15.1
|
|
16
|
+
- @gradio/client@2.0.3
|
|
17
|
+
|
|
18
|
+
## 0.17.3
|
|
19
|
+
|
|
20
|
+
### Dependency updates
|
|
21
|
+
|
|
22
|
+
- @gradio/utils@0.11.1
|
|
23
|
+
- @gradio/client@2.0.2
|
|
24
|
+
|
|
25
|
+
## 0.17.3
|
|
26
|
+
|
|
27
|
+
### Dependency updates
|
|
28
|
+
|
|
29
|
+
- @gradio/atoms@0.20.0
|
|
30
|
+
- @gradio/utils@0.11.0
|
|
31
|
+
- @gradio/client@2.0.1
|
|
32
|
+
|
|
33
|
+
## 0.17.2
|
|
34
|
+
|
|
35
|
+
### Dependency updates
|
|
36
|
+
|
|
37
|
+
- @gradio/utils@0.10.4
|
|
38
|
+
|
|
2
39
|
## 0.17.2
|
|
3
40
|
|
|
4
41
|
### Features
|
|
@@ -4,18 +4,25 @@
|
|
|
4
4
|
import { Edit, Clear, Undo, Download } from "@gradio/icons";
|
|
5
5
|
import { DownloadLink } from "@gradio/atoms";
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
let {
|
|
8
|
+
editable = false,
|
|
9
|
+
undoable = false,
|
|
10
|
+
download = null,
|
|
11
|
+
i18n,
|
|
12
|
+
onedit,
|
|
13
|
+
onclear,
|
|
14
|
+
onundo,
|
|
15
|
+
children
|
|
16
|
+
}: {
|
|
17
|
+
editable?: boolean;
|
|
18
|
+
undoable?: boolean;
|
|
19
|
+
download?: string | null;
|
|
20
|
+
i18n: I18nFormatter;
|
|
21
|
+
onedit?: () => void;
|
|
22
|
+
onclear?: () => void;
|
|
23
|
+
onundo?: () => void;
|
|
24
|
+
children?: import("svelte").Snippet;
|
|
25
|
+
} = $props();
|
|
19
26
|
</script>
|
|
20
27
|
|
|
21
28
|
<IconButtonWrapper>
|
|
@@ -23,7 +30,7 @@
|
|
|
23
30
|
<IconButton
|
|
24
31
|
Icon={Edit}
|
|
25
32
|
label={i18n("common.edit")}
|
|
26
|
-
|
|
33
|
+
onclick={() => onedit?.()}
|
|
27
34
|
/>
|
|
28
35
|
{/if}
|
|
29
36
|
|
|
@@ -31,7 +38,7 @@
|
|
|
31
38
|
<IconButton
|
|
32
39
|
Icon={Undo}
|
|
33
40
|
label={i18n("common.undo")}
|
|
34
|
-
|
|
41
|
+
onclick={() => onundo?.()}
|
|
35
42
|
/>
|
|
36
43
|
{/if}
|
|
37
44
|
|
|
@@ -41,13 +48,13 @@
|
|
|
41
48
|
</DownloadLink>
|
|
42
49
|
{/if}
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
{#if children}{@render children()}{/if}
|
|
45
52
|
|
|
46
53
|
<IconButton
|
|
47
54
|
Icon={Clear}
|
|
48
55
|
label={i18n("common.clear")}
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
onclick={(event) => {
|
|
57
|
+
onclear?.();
|
|
51
58
|
event.stopPropagation();
|
|
52
59
|
}}
|
|
53
60
|
/>
|
|
@@ -1,37 +1,14 @@
|
|
|
1
1
|
import type { I18nFormatter } from "@gradio/utils";
|
|
2
|
-
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
14
|
-
}
|
|
15
|
-
type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
16
|
-
default: any;
|
|
17
|
-
} ? Props extends Record<string, never> ? any : {
|
|
18
|
-
children?: any;
|
|
19
|
-
} : {});
|
|
20
|
-
declare const ModifyUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
|
|
2
|
+
type $$ComponentProps = {
|
|
21
3
|
editable?: boolean;
|
|
22
4
|
undoable?: boolean;
|
|
23
5
|
download?: string | null;
|
|
24
6
|
i18n: I18nFormatter;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
[evt: string]: CustomEvent<any>;
|
|
33
|
-
}, {
|
|
34
|
-
default: {};
|
|
35
|
-
}, {}, string>;
|
|
36
|
-
type ModifyUpload = InstanceType<typeof ModifyUpload>;
|
|
7
|
+
onedit?: () => void;
|
|
8
|
+
onclear?: () => void;
|
|
9
|
+
onundo?: () => void;
|
|
10
|
+
children?: import("svelte").Snippet;
|
|
11
|
+
};
|
|
12
|
+
declare const ModifyUpload: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
13
|
+
type ModifyUpload = ReturnType<typeof ModifyUpload>;
|
|
37
14
|
export default ModifyUpload;
|
package/dist/src/Upload.svelte
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { tick } from "svelte";
|
|
3
3
|
import type { FileData } from "@gradio/client";
|
|
4
4
|
import { prepare_files, type Client } from "@gradio/client";
|
|
5
5
|
import UploadProgress from "./UploadProgress.svelte";
|
|
@@ -7,32 +7,61 @@
|
|
|
7
7
|
|
|
8
8
|
const { drag, open_file_upload: _open_file_upload } = create_drag();
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
let {
|
|
11
|
+
filetype = null,
|
|
12
|
+
dragging = $bindable(false),
|
|
13
|
+
boundedheight = true,
|
|
14
|
+
center = true,
|
|
15
|
+
flex = true,
|
|
16
|
+
file_count = "single",
|
|
17
|
+
disable_click = false,
|
|
18
|
+
root,
|
|
19
|
+
hidden = false,
|
|
20
|
+
format = "file",
|
|
21
|
+
uploading = $bindable(false),
|
|
22
|
+
show_progress = true,
|
|
23
|
+
max_file_size = null,
|
|
24
|
+
upload,
|
|
25
|
+
stream_handler,
|
|
26
|
+
icon_upload = false,
|
|
27
|
+
height = undefined,
|
|
28
|
+
aria_label = undefined,
|
|
29
|
+
upload_promise = $bindable(),
|
|
30
|
+
onload,
|
|
31
|
+
onerror,
|
|
32
|
+
children
|
|
33
|
+
}: {
|
|
34
|
+
filetype?: string | string[] | null;
|
|
35
|
+
dragging?: boolean;
|
|
36
|
+
boundedheight?: boolean;
|
|
37
|
+
center?: boolean;
|
|
38
|
+
flex?: boolean;
|
|
39
|
+
file_count?: "single" | "multiple" | "directory";
|
|
40
|
+
disable_click?: boolean;
|
|
41
|
+
root: string;
|
|
42
|
+
hidden?: boolean;
|
|
43
|
+
format?: "blob" | "file";
|
|
44
|
+
uploading?: boolean;
|
|
45
|
+
show_progress?: boolean;
|
|
46
|
+
max_file_size?: number | null;
|
|
47
|
+
upload: Client["upload"];
|
|
48
|
+
stream_handler: Client["stream"];
|
|
49
|
+
icon_upload?: boolean;
|
|
50
|
+
height?: number | string | undefined;
|
|
51
|
+
aria_label?: string | undefined;
|
|
52
|
+
upload_promise?: Promise<(FileData | null)[]>;
|
|
53
|
+
onload?: (data: FileData | FileData[] | Blob | File) => void;
|
|
54
|
+
onerror?: (error: string) => void;
|
|
55
|
+
children?: import("svelte").Snippet;
|
|
56
|
+
} = $props();
|
|
29
57
|
|
|
30
58
|
export function open_upload(): void {
|
|
31
59
|
_open_file_upload();
|
|
32
60
|
}
|
|
61
|
+
|
|
33
62
|
let upload_id: string = "";
|
|
34
63
|
let file_data: FileData[];
|
|
35
|
-
let accept_file_types: string | null;
|
|
64
|
+
let accept_file_types: string | null = $state(null);
|
|
36
65
|
let use_post_upload_validation: boolean | null = null;
|
|
37
66
|
|
|
38
67
|
const get_ios = (): boolean => {
|
|
@@ -43,9 +72,8 @@
|
|
|
43
72
|
return false;
|
|
44
73
|
};
|
|
45
74
|
|
|
46
|
-
|
|
75
|
+
let ios = get_ios();
|
|
47
76
|
|
|
48
|
-
const dispatch = createEventDispatcher();
|
|
49
77
|
const validFileTypes = ["image", "video", "audio", "text", "file"];
|
|
50
78
|
const process_file_type = (type: string): string => {
|
|
51
79
|
if (ios && type.startsWith(".")) {
|
|
@@ -64,16 +92,18 @@
|
|
|
64
92
|
return "." + type;
|
|
65
93
|
};
|
|
66
94
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
$effect(() => {
|
|
96
|
+
if (filetype == null) {
|
|
97
|
+
accept_file_types = null;
|
|
98
|
+
} else if (typeof filetype === "string") {
|
|
99
|
+
accept_file_types = process_file_type(filetype);
|
|
100
|
+
} else if (ios && filetype.includes("file/*")) {
|
|
101
|
+
accept_file_types = "*";
|
|
102
|
+
} else {
|
|
103
|
+
const processed = filetype.map(process_file_type);
|
|
104
|
+
accept_file_types = processed.join(", ");
|
|
105
|
+
}
|
|
106
|
+
});
|
|
77
107
|
|
|
78
108
|
export function paste_clipboard(): void {
|
|
79
109
|
navigator.clipboard.read().then(async (items) => {
|
|
@@ -97,20 +127,19 @@
|
|
|
97
127
|
_open_file_upload();
|
|
98
128
|
}
|
|
99
129
|
|
|
100
|
-
function handle_upload(
|
|
130
|
+
async function handle_upload(
|
|
101
131
|
file_data: FileData[],
|
|
102
132
|
_upload_id?: string
|
|
103
133
|
): Promise<(FileData | null)[]> {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
upload_id = _upload_id;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
uploading = true;
|
|
134
|
+
if (!_upload_id) {
|
|
135
|
+
upload_id = Math.random().toString(36).substring(2, 15);
|
|
136
|
+
} else {
|
|
137
|
+
upload_id = _upload_id;
|
|
138
|
+
}
|
|
113
139
|
|
|
140
|
+
await tick();
|
|
141
|
+
uploading = true;
|
|
142
|
+
upload_promise = new Promise(async (resolve) => {
|
|
114
143
|
try {
|
|
115
144
|
const _file_data = await upload(
|
|
116
145
|
file_data,
|
|
@@ -118,15 +147,11 @@
|
|
|
118
147
|
upload_id,
|
|
119
148
|
max_file_size ?? Infinity
|
|
120
149
|
);
|
|
121
|
-
|
|
122
|
-
"load",
|
|
123
|
-
file_count === "single" ? _file_data?.[0] : _file_data
|
|
124
|
-
);
|
|
150
|
+
onload?.(file_count === "single" ? _file_data?.[0] : _file_data);
|
|
125
151
|
resolve(_file_data || []);
|
|
126
152
|
uploading = false;
|
|
127
|
-
return _file_data || [];
|
|
128
153
|
} catch (e) {
|
|
129
|
-
|
|
154
|
+
onerror?.((e as Error).message);
|
|
130
155
|
uploading = false;
|
|
131
156
|
resolve([]);
|
|
132
157
|
}
|
|
@@ -186,10 +211,7 @@
|
|
|
186
211
|
if (is_valid_file(file)) {
|
|
187
212
|
return true;
|
|
188
213
|
}
|
|
189
|
-
|
|
190
|
-
"error",
|
|
191
|
-
`Invalid file type: ${file.name}. Only ${filetype} allowed.`
|
|
192
|
-
);
|
|
214
|
+
onerror?.(`Invalid file type: ${file.name}. Only ${filetype} allowed.`);
|
|
193
215
|
return false;
|
|
194
216
|
});
|
|
195
217
|
|
|
@@ -243,17 +265,17 @@
|
|
|
243
265
|
) {
|
|
244
266
|
return true;
|
|
245
267
|
}
|
|
246
|
-
|
|
268
|
+
onerror?.(`Invalid file type only ${filetype} allowed.`);
|
|
247
269
|
return false;
|
|
248
270
|
});
|
|
249
271
|
if (format != "blob") {
|
|
250
272
|
await load_files(files_to_load);
|
|
251
273
|
} else {
|
|
252
274
|
if (file_count === "single") {
|
|
253
|
-
|
|
275
|
+
onload?.(files_to_load[0]);
|
|
254
276
|
return;
|
|
255
277
|
}
|
|
256
|
-
|
|
278
|
+
onload?.(files_to_load);
|
|
257
279
|
}
|
|
258
280
|
}
|
|
259
281
|
|
|
@@ -268,10 +290,10 @@
|
|
|
268
290
|
await load_files(files_to_load);
|
|
269
291
|
} else {
|
|
270
292
|
if (file_count === "single") {
|
|
271
|
-
|
|
293
|
+
onload?.(files_to_load[0]);
|
|
272
294
|
return;
|
|
273
295
|
}
|
|
274
|
-
|
|
296
|
+
onload?.(files_to_load);
|
|
275
297
|
}
|
|
276
298
|
}
|
|
277
299
|
</script>
|
|
@@ -291,10 +313,10 @@
|
|
|
291
313
|
: height
|
|
292
314
|
: "100%"}
|
|
293
315
|
tabindex={hidden ? -1 : 0}
|
|
294
|
-
|
|
316
|
+
onclick={paste_clipboard}
|
|
295
317
|
aria-label={aria_label || "Paste from clipboard"}
|
|
296
318
|
>
|
|
297
|
-
|
|
319
|
+
{#if children}{@render children()}{/if}
|
|
298
320
|
</button>
|
|
299
321
|
{:else if uploading && show_progress}
|
|
300
322
|
{#if !hidden}
|
|
@@ -317,7 +339,7 @@
|
|
|
317
339
|
: "100%"}
|
|
318
340
|
tabindex={hidden ? -1 : 0}
|
|
319
341
|
use:drag={{
|
|
320
|
-
on_drag_change: (
|
|
342
|
+
on_drag_change: (d) => (dragging = d),
|
|
321
343
|
on_files: (files) => load_files_from_upload(files),
|
|
322
344
|
accepted_types: accept_file_types,
|
|
323
345
|
mode: file_count,
|
|
@@ -326,7 +348,7 @@
|
|
|
326
348
|
aria-label={aria_label || "Click to upload or drop files"}
|
|
327
349
|
aria-dropeffect="copy"
|
|
328
350
|
>
|
|
329
|
-
|
|
351
|
+
{#if children}{@render children()}{/if}
|
|
330
352
|
</button>
|
|
331
353
|
{/if}
|
|
332
354
|
|
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
import type { FileData } from "@gradio/client";
|
|
2
2
|
import { type Client } from "@gradio/client";
|
|
3
|
-
|
|
4
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
5
|
-
$$bindings?: Bindings;
|
|
6
|
-
} & Exports;
|
|
7
|
-
(internal: unknown, props: Props & {
|
|
8
|
-
$$events?: Events;
|
|
9
|
-
$$slots?: Slots;
|
|
10
|
-
}): Exports & {
|
|
11
|
-
$set?: any;
|
|
12
|
-
$on?: any;
|
|
13
|
-
};
|
|
14
|
-
z_$$bindings?: Bindings;
|
|
15
|
-
}
|
|
16
|
-
type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
17
|
-
default: any;
|
|
18
|
-
} ? Props extends Record<string, never> ? any : {
|
|
19
|
-
children?: any;
|
|
20
|
-
} : {});
|
|
21
|
-
declare const Upload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
|
|
3
|
+
type $$ComponentProps = {
|
|
22
4
|
filetype?: string | string[] | null;
|
|
23
5
|
dragging?: boolean;
|
|
24
6
|
boundedheight?: boolean;
|
|
@@ -37,27 +19,17 @@ declare const Upload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWit
|
|
|
37
19
|
icon_upload?: boolean;
|
|
38
20
|
height?: number | string | undefined;
|
|
39
21
|
aria_label?: string | undefined;
|
|
40
|
-
upload_promise?: Promise<(FileData | null)[]
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}, {
|
|
47
|
-
default: {};
|
|
48
|
-
}>, {
|
|
49
|
-
load: CustomEvent<any>;
|
|
50
|
-
error: CustomEvent<any>;
|
|
51
|
-
} & {
|
|
52
|
-
[evt: string]: CustomEvent<any>;
|
|
53
|
-
}, {
|
|
54
|
-
default: {};
|
|
55
|
-
}, {
|
|
22
|
+
upload_promise?: Promise<(FileData | null)[]>;
|
|
23
|
+
onload?: (data: FileData | FileData[] | Blob | File) => void;
|
|
24
|
+
onerror?: (error: string) => void;
|
|
25
|
+
children?: import("svelte").Snippet;
|
|
26
|
+
};
|
|
27
|
+
declare const Upload: import("svelte").Component<$$ComponentProps, {
|
|
56
28
|
open_upload: () => void;
|
|
57
29
|
paste_clipboard: () => void;
|
|
58
30
|
open_file_upload: () => void;
|
|
59
31
|
load_files: (files: File[] | Blob[], upload_id?: string) => Promise<(FileData | null)[] | void>;
|
|
60
32
|
load_files_from_drop: (e: DragEvent) => Promise<void>;
|
|
61
|
-
},
|
|
62
|
-
type Upload =
|
|
33
|
+
}, "uploading" | "dragging" | "upload_promise">;
|
|
34
|
+
type Upload = ReturnType<typeof Upload>;
|
|
63
35
|
export default Upload;
|
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { FileData, type Client } from "@gradio/client";
|
|
3
|
-
import { onMount,
|
|
3
|
+
import { onMount, onDestroy } from "svelte";
|
|
4
4
|
|
|
5
5
|
type FileDataWithProgress = FileData & { progress: number };
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
let {
|
|
8
|
+
upload_id,
|
|
9
|
+
root,
|
|
10
|
+
files,
|
|
11
|
+
stream_handler,
|
|
12
|
+
ondone
|
|
13
|
+
}: {
|
|
14
|
+
upload_id: string;
|
|
15
|
+
root: string;
|
|
16
|
+
files: FileData[];
|
|
17
|
+
stream_handler: Client["stream"];
|
|
18
|
+
ondone?: () => void;
|
|
19
|
+
} = $props();
|
|
11
20
|
|
|
12
21
|
let stream: Awaited<ReturnType<Client["stream"]>>;
|
|
13
|
-
let progress = false;
|
|
14
|
-
let current_file_upload
|
|
15
|
-
let file_to_display
|
|
16
|
-
|
|
17
|
-
let files_with_progress
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
let progress = $state(false);
|
|
23
|
+
let current_file_upload = $state<FileDataWithProgress>();
|
|
24
|
+
let file_to_display = $derived(current_file_upload || files_with_progress[0]);
|
|
25
|
+
|
|
26
|
+
let files_with_progress = $state<FileDataWithProgress[]>(
|
|
27
|
+
files.map((file) => {
|
|
28
|
+
return {
|
|
29
|
+
...file,
|
|
30
|
+
progress: 0
|
|
31
|
+
};
|
|
32
|
+
})
|
|
33
|
+
);
|
|
25
34
|
|
|
26
35
|
function handleProgress(filename: string, chunk_size: number): void {
|
|
27
36
|
// Find the corresponding file in the array and update its progress
|
|
@@ -52,22 +61,23 @@
|
|
|
52
61
|
if (_data.msg === "done") {
|
|
53
62
|
// the stream will close itself but is here for clarity; remove .close() in 5.0
|
|
54
63
|
stream?.close();
|
|
55
|
-
|
|
64
|
+
ondone?.();
|
|
56
65
|
} else {
|
|
57
66
|
current_file_upload = _data;
|
|
58
67
|
handleProgress(_data.orig_name, _data.chunk_size);
|
|
59
68
|
}
|
|
60
69
|
};
|
|
61
70
|
});
|
|
71
|
+
|
|
62
72
|
onDestroy(() => {
|
|
63
73
|
// the stream will close itself but is here for clarity; remove .close() in 5.0
|
|
64
74
|
if (stream != null || stream != undefined) stream.close();
|
|
65
75
|
});
|
|
66
76
|
|
|
67
|
-
function calculateTotalProgress(files:
|
|
77
|
+
function calculateTotalProgress(files: FileDataWithProgress[]): number {
|
|
68
78
|
let totalProgress = 0;
|
|
69
79
|
files.forEach((file) => {
|
|
70
|
-
totalProgress += getProgress(file
|
|
80
|
+
totalProgress += getProgress(file);
|
|
71
81
|
});
|
|
72
82
|
|
|
73
83
|
document.documentElement.style.setProperty(
|
|
@@ -78,9 +88,9 @@
|
|
|
78
88
|
return totalProgress / files.length;
|
|
79
89
|
}
|
|
80
90
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
91
|
+
$effect(() => {
|
|
92
|
+
calculateTotalProgress(files_with_progress);
|
|
93
|
+
});
|
|
84
94
|
</script>
|
|
85
95
|
|
|
86
96
|
<div class="wrap" class:progress>
|
|
@@ -1,26 +1,11 @@
|
|
|
1
1
|
import { FileData, type Client } from "@gradio/client";
|
|
2
|
-
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
14
|
-
}
|
|
15
|
-
declare const UploadProgress: $$__sveltets_2_IsomorphicComponent<{
|
|
2
|
+
type $$ComponentProps = {
|
|
16
3
|
upload_id: string;
|
|
17
4
|
root: string;
|
|
18
5
|
files: FileData[];
|
|
19
6
|
stream_handler: Client["stream"];
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}, {}, {}, string>;
|
|
25
|
-
type UploadProgress = InstanceType<typeof UploadProgress>;
|
|
7
|
+
ondone?: () => void;
|
|
8
|
+
};
|
|
9
|
+
declare const UploadProgress: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type UploadProgress = ReturnType<typeof UploadProgress>;
|
|
26
11
|
export default UploadProgress;
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/upload",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.4",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"author": "",
|
|
8
8
|
"license": "ISC",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@gradio/atoms": "^0.
|
|
11
|
-
"@gradio/icons": "^0.15.
|
|
12
|
-
"@gradio/
|
|
13
|
-
"@gradio/
|
|
10
|
+
"@gradio/atoms": "^0.20.1",
|
|
11
|
+
"@gradio/icons": "^0.15.1",
|
|
12
|
+
"@gradio/utils": "^0.11.2",
|
|
13
|
+
"@gradio/client": "^2.0.3"
|
|
14
14
|
},
|
|
15
15
|
"main_changeset": true,
|
|
16
16
|
"exports": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"svelte": "^5.
|
|
24
|
+
"svelte": "^5.48.0"
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
package/src/ModifyUpload.svelte
CHANGED
|
@@ -4,18 +4,25 @@
|
|
|
4
4
|
import { Edit, Clear, Undo, Download } from "@gradio/icons";
|
|
5
5
|
import { DownloadLink } from "@gradio/atoms";
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
let {
|
|
8
|
+
editable = false,
|
|
9
|
+
undoable = false,
|
|
10
|
+
download = null,
|
|
11
|
+
i18n,
|
|
12
|
+
onedit,
|
|
13
|
+
onclear,
|
|
14
|
+
onundo,
|
|
15
|
+
children
|
|
16
|
+
}: {
|
|
17
|
+
editable?: boolean;
|
|
18
|
+
undoable?: boolean;
|
|
19
|
+
download?: string | null;
|
|
20
|
+
i18n: I18nFormatter;
|
|
21
|
+
onedit?: () => void;
|
|
22
|
+
onclear?: () => void;
|
|
23
|
+
onundo?: () => void;
|
|
24
|
+
children?: import("svelte").Snippet;
|
|
25
|
+
} = $props();
|
|
19
26
|
</script>
|
|
20
27
|
|
|
21
28
|
<IconButtonWrapper>
|
|
@@ -23,7 +30,7 @@
|
|
|
23
30
|
<IconButton
|
|
24
31
|
Icon={Edit}
|
|
25
32
|
label={i18n("common.edit")}
|
|
26
|
-
|
|
33
|
+
onclick={() => onedit?.()}
|
|
27
34
|
/>
|
|
28
35
|
{/if}
|
|
29
36
|
|
|
@@ -31,7 +38,7 @@
|
|
|
31
38
|
<IconButton
|
|
32
39
|
Icon={Undo}
|
|
33
40
|
label={i18n("common.undo")}
|
|
34
|
-
|
|
41
|
+
onclick={() => onundo?.()}
|
|
35
42
|
/>
|
|
36
43
|
{/if}
|
|
37
44
|
|
|
@@ -41,13 +48,13 @@
|
|
|
41
48
|
</DownloadLink>
|
|
42
49
|
{/if}
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
{#if children}{@render children()}{/if}
|
|
45
52
|
|
|
46
53
|
<IconButton
|
|
47
54
|
Icon={Clear}
|
|
48
55
|
label={i18n("common.clear")}
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
onclick={(event) => {
|
|
57
|
+
onclear?.();
|
|
51
58
|
event.stopPropagation();
|
|
52
59
|
}}
|
|
53
60
|
/>
|
package/src/Upload.svelte
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { tick } from "svelte";
|
|
3
3
|
import type { FileData } from "@gradio/client";
|
|
4
4
|
import { prepare_files, type Client } from "@gradio/client";
|
|
5
5
|
import UploadProgress from "./UploadProgress.svelte";
|
|
@@ -7,32 +7,61 @@
|
|
|
7
7
|
|
|
8
8
|
const { drag, open_file_upload: _open_file_upload } = create_drag();
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
let {
|
|
11
|
+
filetype = null,
|
|
12
|
+
dragging = $bindable(false),
|
|
13
|
+
boundedheight = true,
|
|
14
|
+
center = true,
|
|
15
|
+
flex = true,
|
|
16
|
+
file_count = "single",
|
|
17
|
+
disable_click = false,
|
|
18
|
+
root,
|
|
19
|
+
hidden = false,
|
|
20
|
+
format = "file",
|
|
21
|
+
uploading = $bindable(false),
|
|
22
|
+
show_progress = true,
|
|
23
|
+
max_file_size = null,
|
|
24
|
+
upload,
|
|
25
|
+
stream_handler,
|
|
26
|
+
icon_upload = false,
|
|
27
|
+
height = undefined,
|
|
28
|
+
aria_label = undefined,
|
|
29
|
+
upload_promise = $bindable(),
|
|
30
|
+
onload,
|
|
31
|
+
onerror,
|
|
32
|
+
children
|
|
33
|
+
}: {
|
|
34
|
+
filetype?: string | string[] | null;
|
|
35
|
+
dragging?: boolean;
|
|
36
|
+
boundedheight?: boolean;
|
|
37
|
+
center?: boolean;
|
|
38
|
+
flex?: boolean;
|
|
39
|
+
file_count?: "single" | "multiple" | "directory";
|
|
40
|
+
disable_click?: boolean;
|
|
41
|
+
root: string;
|
|
42
|
+
hidden?: boolean;
|
|
43
|
+
format?: "blob" | "file";
|
|
44
|
+
uploading?: boolean;
|
|
45
|
+
show_progress?: boolean;
|
|
46
|
+
max_file_size?: number | null;
|
|
47
|
+
upload: Client["upload"];
|
|
48
|
+
stream_handler: Client["stream"];
|
|
49
|
+
icon_upload?: boolean;
|
|
50
|
+
height?: number | string | undefined;
|
|
51
|
+
aria_label?: string | undefined;
|
|
52
|
+
upload_promise?: Promise<(FileData | null)[]>;
|
|
53
|
+
onload?: (data: FileData | FileData[] | Blob | File) => void;
|
|
54
|
+
onerror?: (error: string) => void;
|
|
55
|
+
children?: import("svelte").Snippet;
|
|
56
|
+
} = $props();
|
|
29
57
|
|
|
30
58
|
export function open_upload(): void {
|
|
31
59
|
_open_file_upload();
|
|
32
60
|
}
|
|
61
|
+
|
|
33
62
|
let upload_id: string = "";
|
|
34
63
|
let file_data: FileData[];
|
|
35
|
-
let accept_file_types: string | null;
|
|
64
|
+
let accept_file_types: string | null = $state(null);
|
|
36
65
|
let use_post_upload_validation: boolean | null = null;
|
|
37
66
|
|
|
38
67
|
const get_ios = (): boolean => {
|
|
@@ -43,9 +72,8 @@
|
|
|
43
72
|
return false;
|
|
44
73
|
};
|
|
45
74
|
|
|
46
|
-
|
|
75
|
+
let ios = get_ios();
|
|
47
76
|
|
|
48
|
-
const dispatch = createEventDispatcher();
|
|
49
77
|
const validFileTypes = ["image", "video", "audio", "text", "file"];
|
|
50
78
|
const process_file_type = (type: string): string => {
|
|
51
79
|
if (ios && type.startsWith(".")) {
|
|
@@ -64,16 +92,18 @@
|
|
|
64
92
|
return "." + type;
|
|
65
93
|
};
|
|
66
94
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
$effect(() => {
|
|
96
|
+
if (filetype == null) {
|
|
97
|
+
accept_file_types = null;
|
|
98
|
+
} else if (typeof filetype === "string") {
|
|
99
|
+
accept_file_types = process_file_type(filetype);
|
|
100
|
+
} else if (ios && filetype.includes("file/*")) {
|
|
101
|
+
accept_file_types = "*";
|
|
102
|
+
} else {
|
|
103
|
+
const processed = filetype.map(process_file_type);
|
|
104
|
+
accept_file_types = processed.join(", ");
|
|
105
|
+
}
|
|
106
|
+
});
|
|
77
107
|
|
|
78
108
|
export function paste_clipboard(): void {
|
|
79
109
|
navigator.clipboard.read().then(async (items) => {
|
|
@@ -97,20 +127,19 @@
|
|
|
97
127
|
_open_file_upload();
|
|
98
128
|
}
|
|
99
129
|
|
|
100
|
-
function handle_upload(
|
|
130
|
+
async function handle_upload(
|
|
101
131
|
file_data: FileData[],
|
|
102
132
|
_upload_id?: string
|
|
103
133
|
): Promise<(FileData | null)[]> {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
upload_id = _upload_id;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
uploading = true;
|
|
134
|
+
if (!_upload_id) {
|
|
135
|
+
upload_id = Math.random().toString(36).substring(2, 15);
|
|
136
|
+
} else {
|
|
137
|
+
upload_id = _upload_id;
|
|
138
|
+
}
|
|
113
139
|
|
|
140
|
+
await tick();
|
|
141
|
+
uploading = true;
|
|
142
|
+
upload_promise = new Promise(async (resolve) => {
|
|
114
143
|
try {
|
|
115
144
|
const _file_data = await upload(
|
|
116
145
|
file_data,
|
|
@@ -118,15 +147,11 @@
|
|
|
118
147
|
upload_id,
|
|
119
148
|
max_file_size ?? Infinity
|
|
120
149
|
);
|
|
121
|
-
|
|
122
|
-
"load",
|
|
123
|
-
file_count === "single" ? _file_data?.[0] : _file_data
|
|
124
|
-
);
|
|
150
|
+
onload?.(file_count === "single" ? _file_data?.[0] : _file_data);
|
|
125
151
|
resolve(_file_data || []);
|
|
126
152
|
uploading = false;
|
|
127
|
-
return _file_data || [];
|
|
128
153
|
} catch (e) {
|
|
129
|
-
|
|
154
|
+
onerror?.((e as Error).message);
|
|
130
155
|
uploading = false;
|
|
131
156
|
resolve([]);
|
|
132
157
|
}
|
|
@@ -186,10 +211,7 @@
|
|
|
186
211
|
if (is_valid_file(file)) {
|
|
187
212
|
return true;
|
|
188
213
|
}
|
|
189
|
-
|
|
190
|
-
"error",
|
|
191
|
-
`Invalid file type: ${file.name}. Only ${filetype} allowed.`
|
|
192
|
-
);
|
|
214
|
+
onerror?.(`Invalid file type: ${file.name}. Only ${filetype} allowed.`);
|
|
193
215
|
return false;
|
|
194
216
|
});
|
|
195
217
|
|
|
@@ -243,17 +265,17 @@
|
|
|
243
265
|
) {
|
|
244
266
|
return true;
|
|
245
267
|
}
|
|
246
|
-
|
|
268
|
+
onerror?.(`Invalid file type only ${filetype} allowed.`);
|
|
247
269
|
return false;
|
|
248
270
|
});
|
|
249
271
|
if (format != "blob") {
|
|
250
272
|
await load_files(files_to_load);
|
|
251
273
|
} else {
|
|
252
274
|
if (file_count === "single") {
|
|
253
|
-
|
|
275
|
+
onload?.(files_to_load[0]);
|
|
254
276
|
return;
|
|
255
277
|
}
|
|
256
|
-
|
|
278
|
+
onload?.(files_to_load);
|
|
257
279
|
}
|
|
258
280
|
}
|
|
259
281
|
|
|
@@ -268,10 +290,10 @@
|
|
|
268
290
|
await load_files(files_to_load);
|
|
269
291
|
} else {
|
|
270
292
|
if (file_count === "single") {
|
|
271
|
-
|
|
293
|
+
onload?.(files_to_load[0]);
|
|
272
294
|
return;
|
|
273
295
|
}
|
|
274
|
-
|
|
296
|
+
onload?.(files_to_load);
|
|
275
297
|
}
|
|
276
298
|
}
|
|
277
299
|
</script>
|
|
@@ -291,10 +313,10 @@
|
|
|
291
313
|
: height
|
|
292
314
|
: "100%"}
|
|
293
315
|
tabindex={hidden ? -1 : 0}
|
|
294
|
-
|
|
316
|
+
onclick={paste_clipboard}
|
|
295
317
|
aria-label={aria_label || "Paste from clipboard"}
|
|
296
318
|
>
|
|
297
|
-
|
|
319
|
+
{#if children}{@render children()}{/if}
|
|
298
320
|
</button>
|
|
299
321
|
{:else if uploading && show_progress}
|
|
300
322
|
{#if !hidden}
|
|
@@ -317,7 +339,7 @@
|
|
|
317
339
|
: "100%"}
|
|
318
340
|
tabindex={hidden ? -1 : 0}
|
|
319
341
|
use:drag={{
|
|
320
|
-
on_drag_change: (
|
|
342
|
+
on_drag_change: (d) => (dragging = d),
|
|
321
343
|
on_files: (files) => load_files_from_upload(files),
|
|
322
344
|
accepted_types: accept_file_types,
|
|
323
345
|
mode: file_count,
|
|
@@ -326,7 +348,7 @@
|
|
|
326
348
|
aria-label={aria_label || "Click to upload or drop files"}
|
|
327
349
|
aria-dropeffect="copy"
|
|
328
350
|
>
|
|
329
|
-
|
|
351
|
+
{#if children}{@render children()}{/if}
|
|
330
352
|
</button>
|
|
331
353
|
{/if}
|
|
332
354
|
|
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { FileData, type Client } from "@gradio/client";
|
|
3
|
-
import { onMount,
|
|
3
|
+
import { onMount, onDestroy } from "svelte";
|
|
4
4
|
|
|
5
5
|
type FileDataWithProgress = FileData & { progress: number };
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
let {
|
|
8
|
+
upload_id,
|
|
9
|
+
root,
|
|
10
|
+
files,
|
|
11
|
+
stream_handler,
|
|
12
|
+
ondone
|
|
13
|
+
}: {
|
|
14
|
+
upload_id: string;
|
|
15
|
+
root: string;
|
|
16
|
+
files: FileData[];
|
|
17
|
+
stream_handler: Client["stream"];
|
|
18
|
+
ondone?: () => void;
|
|
19
|
+
} = $props();
|
|
11
20
|
|
|
12
21
|
let stream: Awaited<ReturnType<Client["stream"]>>;
|
|
13
|
-
let progress = false;
|
|
14
|
-
let current_file_upload
|
|
15
|
-
let file_to_display
|
|
16
|
-
|
|
17
|
-
let files_with_progress
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
let progress = $state(false);
|
|
23
|
+
let current_file_upload = $state<FileDataWithProgress>();
|
|
24
|
+
let file_to_display = $derived(current_file_upload || files_with_progress[0]);
|
|
25
|
+
|
|
26
|
+
let files_with_progress = $state<FileDataWithProgress[]>(
|
|
27
|
+
files.map((file) => {
|
|
28
|
+
return {
|
|
29
|
+
...file,
|
|
30
|
+
progress: 0
|
|
31
|
+
};
|
|
32
|
+
})
|
|
33
|
+
);
|
|
25
34
|
|
|
26
35
|
function handleProgress(filename: string, chunk_size: number): void {
|
|
27
36
|
// Find the corresponding file in the array and update its progress
|
|
@@ -52,22 +61,23 @@
|
|
|
52
61
|
if (_data.msg === "done") {
|
|
53
62
|
// the stream will close itself but is here for clarity; remove .close() in 5.0
|
|
54
63
|
stream?.close();
|
|
55
|
-
|
|
64
|
+
ondone?.();
|
|
56
65
|
} else {
|
|
57
66
|
current_file_upload = _data;
|
|
58
67
|
handleProgress(_data.orig_name, _data.chunk_size);
|
|
59
68
|
}
|
|
60
69
|
};
|
|
61
70
|
});
|
|
71
|
+
|
|
62
72
|
onDestroy(() => {
|
|
63
73
|
// the stream will close itself but is here for clarity; remove .close() in 5.0
|
|
64
74
|
if (stream != null || stream != undefined) stream.close();
|
|
65
75
|
});
|
|
66
76
|
|
|
67
|
-
function calculateTotalProgress(files:
|
|
77
|
+
function calculateTotalProgress(files: FileDataWithProgress[]): number {
|
|
68
78
|
let totalProgress = 0;
|
|
69
79
|
files.forEach((file) => {
|
|
70
|
-
totalProgress += getProgress(file
|
|
80
|
+
totalProgress += getProgress(file);
|
|
71
81
|
});
|
|
72
82
|
|
|
73
83
|
document.documentElement.style.setProperty(
|
|
@@ -78,9 +88,9 @@
|
|
|
78
88
|
return totalProgress / files.length;
|
|
79
89
|
}
|
|
80
90
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
91
|
+
$effect(() => {
|
|
92
|
+
calculateTotalProgress(files_with_progress);
|
|
93
|
+
});
|
|
84
94
|
</script>
|
|
85
95
|
|
|
86
96
|
<div class="wrap" class:progress>
|