@gradio/upload 0.17.1 → 0.17.2-dev.2

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 CHANGED
@@ -1,5 +1,38 @@
1
1
  # @gradio/upload
2
2
 
3
+ ## 0.17.2-dev.2
4
+
5
+ ### Dependency updates
6
+
7
+ - @gradio/atoms@0.19.0-dev.1
8
+ - @gradio/client@2.0.0-dev.2
9
+
10
+ ## 0.17.2-dev.1
11
+
12
+ ### Dependency updates
13
+
14
+ - @gradio/atoms@0.18.2-dev.0
15
+ - @gradio/utils@0.10.3-dev.0
16
+ - @gradio/icons@0.15.0-dev.0
17
+
18
+ ## 0.17.2-dev.0
19
+
20
+ ### Dependency updates
21
+
22
+ - @gradio/client@2.0.0-dev.1
23
+
24
+ ## 0.17.2-dev.0
25
+
26
+ ### Dependency updates
27
+
28
+ - @gradio/client@2.0.0-dev.0
29
+
30
+ ## 0.17.1
31
+
32
+ ### Dependency updates
33
+
34
+ - @gradio/client@1.19.1
35
+
3
36
  ## 0.17.1
4
37
 
5
38
  ### Fixes
@@ -1,12 +1,21 @@
1
- <script>import { IconButton, IconButtonWrapper } from "@gradio/atoms";
2
- import { Edit, Clear, Undo, Download } from "@gradio/icons";
3
- import { DownloadLink } from "@gradio/atoms";
4
- import { createEventDispatcher } from "svelte";
5
- export let editable = false;
6
- export let undoable = false;
7
- export let download = null;
8
- export let i18n;
9
- const dispatch = createEventDispatcher();
1
+ <script lang="ts">
2
+ import { IconButton, IconButtonWrapper } from "@gradio/atoms";
3
+ import type { I18nFormatter } from "@gradio/utils";
4
+ import { Edit, Clear, Undo, Download } from "@gradio/icons";
5
+ import { DownloadLink } from "@gradio/atoms";
6
+
7
+ import { createEventDispatcher } from "svelte";
8
+
9
+ export let editable = false;
10
+ export let undoable = false;
11
+ export let download: string | null = null;
12
+ export let i18n: I18nFormatter;
13
+
14
+ const dispatch = createEventDispatcher<{
15
+ edit?: never;
16
+ clear?: never;
17
+ undo?: never;
18
+ }>();
10
19
  </script>
11
20
 
12
21
  <IconButtonWrapper>
@@ -1,28 +1,37 @@
1
- import { SvelteComponent } from "svelte";
2
1
  import type { I18nFormatter } from "@gradio/utils";
3
- declare const __propDef: {
4
- props: {
5
- editable?: boolean;
6
- undoable?: boolean;
7
- download?: string | null;
8
- i18n: I18nFormatter;
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
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;
9
12
  };
10
- events: {
11
- edit?: CustomEvent<undefined> | undefined;
12
- clear?: CustomEvent<undefined> | undefined;
13
- undo?: CustomEvent<undefined> | undefined;
14
- } & {
15
- [evt: string]: CustomEvent<any>;
16
- };
17
- slots: {
18
- default: {};
19
- };
20
- exports?: {} | undefined;
21
- bindings?: string | undefined;
22
- };
23
- export type ModifyUploadProps = typeof __propDef.props;
24
- export type ModifyUploadEvents = typeof __propDef.events;
25
- export type ModifyUploadSlots = typeof __propDef.slots;
26
- export default class ModifyUpload extends SvelteComponent<ModifyUploadProps, ModifyUploadEvents, ModifyUploadSlots> {
13
+ z_$$bindings?: Bindings;
27
14
  }
28
- export {};
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<{
21
+ editable?: boolean;
22
+ undoable?: boolean;
23
+ download?: string | null;
24
+ i18n: I18nFormatter;
25
+ }, {
26
+ default: {};
27
+ }>, {
28
+ edit?: CustomEvent<undefined> | undefined;
29
+ clear?: CustomEvent<undefined> | undefined;
30
+ undo?: CustomEvent<undefined> | undefined;
31
+ } & {
32
+ [evt: string]: CustomEvent<any>;
33
+ }, {
34
+ default: {};
35
+ }, {}, string>;
36
+ type ModifyUpload = InstanceType<typeof ModifyUpload>;
37
+ export default ModifyUpload;
@@ -1,209 +1,279 @@
1
- <script>import { createEventDispatcher, tick, getContext } from "svelte";
2
- import { prepare_files } from "@gradio/client";
3
- import UploadProgress from "./UploadProgress.svelte";
4
- import { create_drag } from "./utils";
5
- const { drag, open_file_upload: _open_file_upload } = create_drag();
6
- export let filetype = null;
7
- export let dragging = false;
8
- export let boundedheight = true;
9
- export let center = true;
10
- export let flex = true;
11
- export let file_count = "single";
12
- export let disable_click = false;
13
- export let root;
14
- export let hidden = false;
15
- export let format = "file";
16
- export let uploading = false;
17
- export let show_progress = true;
18
- export let max_file_size = null;
19
- export let upload;
20
- export let stream_handler;
21
- export let icon_upload = false;
22
- export let height = void 0;
23
- export let aria_label = void 0;
24
- export function open_upload() {
25
- _open_file_upload();
26
- }
27
- let upload_id;
28
- let file_data;
29
- let accept_file_types;
30
- let use_post_upload_validation = null;
31
- const get_ios = () => {
32
- if (typeof navigator !== "undefined") {
33
- const userAgent = navigator.userAgent.toLowerCase();
34
- return userAgent.indexOf("iphone") > -1 || userAgent.indexOf("ipad") > -1;
35
- }
36
- return false;
37
- };
38
- $: ios = get_ios();
39
- const dispatch = createEventDispatcher();
40
- const validFileTypes = ["image", "video", "audio", "text", "file"];
41
- const process_file_type = (type) => {
42
- if (ios && type.startsWith(".")) {
43
- use_post_upload_validation = true;
44
- return type;
45
- }
46
- if (ios && type.includes("file/*")) {
47
- return "*";
48
- }
49
- if (type.startsWith(".") || type.endsWith("/*")) {
50
- return type;
51
- }
52
- if (validFileTypes.includes(type)) {
53
- return type + "/*";
54
- }
55
- return "." + type;
56
- };
57
- $: if (filetype == null) {
58
- accept_file_types = null;
59
- } else if (typeof filetype === "string") {
60
- accept_file_types = process_file_type(filetype);
61
- } else if (ios && filetype.includes("file/*")) {
62
- accept_file_types = "*";
63
- } else {
64
- filetype = filetype.map(process_file_type);
65
- accept_file_types = filetype.join(", ");
66
- }
67
- export function paste_clipboard() {
68
- navigator.clipboard.read().then(async (items) => {
69
- for (let i = 0; i < items.length; i++) {
70
- const type = items[i].types.find((t) => t.startsWith("image/"));
71
- if (type) {
72
- items[i].getType(type).then(async (blob) => {
73
- const file = new File(
74
- [blob],
75
- `clipboard.${type.replace("image/", "")}`
76
- );
77
- await load_files([file]);
78
- });
79
- break;
80
- }
81
- }
82
- });
83
- }
84
- export function open_file_upload() {
85
- _open_file_upload();
86
- }
87
- async function handle_upload(file_data2, upload_id2) {
88
- await tick();
89
- if (!upload_id2) {
90
- upload_id2 = Math.random().toString(36).substring(2, 15);
91
- }
92
- uploading = true;
93
- try {
94
- const _file_data = await upload(
95
- file_data2,
96
- root,
97
- upload_id2,
98
- max_file_size ?? Infinity
99
- );
100
- dispatch("load", file_count === "single" ? _file_data?.[0] : _file_data);
101
- uploading = false;
102
- return _file_data || [];
103
- } catch (e) {
104
- dispatch("error", e.message);
105
- uploading = false;
106
- return [];
107
- }
108
- }
109
- function is_valid_mimetype(file_accept, uploaded_file_extension, uploaded_file_type) {
110
- if (!file_accept || file_accept === "*" || file_accept === "file/*" || Array.isArray(file_accept) && file_accept.some((accept) => accept === "*" || accept === "file/*")) {
111
- return true;
112
- }
113
- let acceptArray;
114
- if (typeof file_accept === "string") {
115
- acceptArray = file_accept.split(",").map((s) => s.trim());
116
- } else if (Array.isArray(file_accept)) {
117
- acceptArray = file_accept;
118
- } else {
119
- return false;
120
- }
121
- return acceptArray.includes(uploaded_file_extension) || acceptArray.some((type) => {
122
- const [category] = type.split("/").map((s) => s.trim());
123
- return type.endsWith("/*") && uploaded_file_type.startsWith(category + "/");
124
- });
125
- }
126
- export async function load_files(files, upload_id2) {
127
- if (!files.length) {
128
- return;
129
- }
130
- let _files = files.map(
131
- (f) => new File([f], f instanceof File ? f.name : "file", { type: f.type })
132
- );
133
- if (ios && use_post_upload_validation) {
134
- _files = _files.filter((file) => {
135
- if (is_valid_file(file)) {
136
- return true;
137
- }
138
- dispatch(
139
- "error",
140
- `Invalid file type: ${file.name}. Only ${filetype} allowed.`
141
- );
142
- return false;
143
- });
144
- if (_files.length === 0) {
145
- return [];
146
- }
147
- }
148
- file_data = await prepare_files(_files);
149
- return await handle_upload(file_data, upload_id2);
150
- }
151
- function is_valid_file(file) {
152
- if (!filetype) return true;
153
- const allowed_types = Array.isArray(filetype) ? filetype : [filetype];
154
- return allowed_types.some((type) => {
155
- const processed_type = process_file_type(type);
156
- if (processed_type.startsWith(".")) {
157
- return file.name.toLowerCase().endsWith(processed_type.toLowerCase());
158
- }
159
- if (processed_type === "*") {
160
- return true;
161
- }
162
- if (processed_type.endsWith("/*")) {
163
- const [category] = processed_type.split("/");
164
- return file.type.startsWith(category + "/");
165
- }
166
- return file.type === processed_type;
167
- });
168
- }
169
- async function load_files_from_upload(files) {
170
- const files_to_load = files.filter((file) => {
171
- const file_extension = "." + file.name.toLowerCase().split(".").pop();
172
- if (file_extension && is_valid_mimetype(accept_file_types, file_extension, file.type)) {
173
- return true;
174
- }
175
- if (file_extension && Array.isArray(filetype) ? filetype.includes(file_extension) : file_extension === filetype) {
176
- return true;
177
- }
178
- dispatch("error", `Invalid file type only ${filetype} allowed.`);
179
- return false;
180
- });
181
- if (format != "blob") {
182
- await load_files(files_to_load);
183
- } else {
184
- if (file_count === "single") {
185
- dispatch("load", files_to_load[0]);
186
- return;
187
- }
188
- dispatch("load", files_to_load);
189
- }
190
- }
191
- export async function load_files_from_drop(e) {
192
- dragging = false;
193
- if (!e.dataTransfer?.files) return;
194
- const files_to_load = Array.from(e.dataTransfer.files).filter(
195
- is_valid_file
196
- );
197
- if (format != "blob") {
198
- await load_files(files_to_load);
199
- } else {
200
- if (file_count === "single") {
201
- dispatch("load", files_to_load[0]);
202
- return;
203
- }
204
- dispatch("load", files_to_load);
205
- }
206
- }
1
+ <script lang="ts">
2
+ import { createEventDispatcher, tick, getContext } from "svelte";
3
+ import type { FileData } from "@gradio/client";
4
+ import { prepare_files, type Client } from "@gradio/client";
5
+ import UploadProgress from "./UploadProgress.svelte";
6
+ import { create_drag } from "./utils";
7
+
8
+ const { drag, open_file_upload: _open_file_upload } = create_drag();
9
+
10
+ export let filetype: string | string[] | null = null;
11
+ export let dragging = false;
12
+ export let boundedheight = true;
13
+ export let center = true;
14
+ export let flex = true;
15
+ export let file_count: "single" | "multiple" | "directory" = "single";
16
+ export let disable_click = false;
17
+ export let root: string;
18
+ export let hidden = false;
19
+ export let format: "blob" | "file" = "file";
20
+ export let uploading = false;
21
+ export let show_progress = true;
22
+ export let max_file_size: number | null = null;
23
+ export let upload: Client["upload"];
24
+ export let stream_handler: Client["stream"];
25
+ export let icon_upload = false;
26
+ export let height: number | string | undefined = undefined;
27
+ export let aria_label: string | undefined = undefined;
28
+ export let upload_promise: Promise<(FileData | null)[]> | null = null;
29
+
30
+ export function open_upload(): void {
31
+ _open_file_upload();
32
+ }
33
+ let upload_id: string = "";
34
+ let file_data: FileData[];
35
+ let accept_file_types: string | null;
36
+ let use_post_upload_validation: boolean | null = null;
37
+
38
+ const get_ios = (): boolean => {
39
+ if (typeof navigator !== "undefined") {
40
+ const userAgent = navigator.userAgent.toLowerCase();
41
+ return userAgent.indexOf("iphone") > -1 || userAgent.indexOf("ipad") > -1;
42
+ }
43
+ return false;
44
+ };
45
+
46
+ $: ios = get_ios();
47
+
48
+ const dispatch = createEventDispatcher();
49
+ const validFileTypes = ["image", "video", "audio", "text", "file"];
50
+ const process_file_type = (type: string): string => {
51
+ if (ios && type.startsWith(".")) {
52
+ use_post_upload_validation = true;
53
+ return type;
54
+ }
55
+ if (ios && type.includes("file/*")) {
56
+ return "*";
57
+ }
58
+ if (type.startsWith(".") || type.endsWith("/*")) {
59
+ return type;
60
+ }
61
+ if (validFileTypes.includes(type)) {
62
+ return type + "/*";
63
+ }
64
+ return "." + type;
65
+ };
66
+
67
+ $: if (filetype == null) {
68
+ accept_file_types = null;
69
+ } else if (typeof filetype === "string") {
70
+ accept_file_types = process_file_type(filetype);
71
+ } else if (ios && filetype.includes("file/*")) {
72
+ accept_file_types = "*";
73
+ } else {
74
+ filetype = filetype.map(process_file_type);
75
+ accept_file_types = filetype.join(", ");
76
+ }
77
+
78
+ export function paste_clipboard(): void {
79
+ navigator.clipboard.read().then(async (items) => {
80
+ for (let i = 0; i < items.length; i++) {
81
+ const type = items[i].types.find((t) => t.startsWith("image/"));
82
+ if (type) {
83
+ items[i].getType(type).then(async (blob) => {
84
+ const file = new File(
85
+ [blob],
86
+ `clipboard.${type.replace("image/", "")}`
87
+ );
88
+ await load_files([file]);
89
+ });
90
+ break;
91
+ }
92
+ }
93
+ });
94
+ }
95
+
96
+ export function open_file_upload(): void {
97
+ _open_file_upload();
98
+ }
99
+
100
+ function handle_upload(
101
+ file_data: FileData[],
102
+ _upload_id?: string
103
+ ): Promise<(FileData | null)[]> {
104
+ upload_promise = new Promise(async (resolve, rej) => {
105
+ await tick();
106
+ if (!_upload_id) {
107
+ upload_id = Math.random().toString(36).substring(2, 15);
108
+ } else {
109
+ upload_id = _upload_id;
110
+ }
111
+
112
+ uploading = true;
113
+
114
+ try {
115
+ const _file_data = await upload(
116
+ file_data,
117
+ root,
118
+ upload_id,
119
+ max_file_size ?? Infinity
120
+ );
121
+ dispatch(
122
+ "load",
123
+ file_count === "single" ? _file_data?.[0] : _file_data
124
+ );
125
+ resolve(_file_data || []);
126
+ uploading = false;
127
+ return _file_data || [];
128
+ } catch (e) {
129
+ dispatch("error", (e as Error).message);
130
+ uploading = false;
131
+ resolve([]);
132
+ }
133
+ });
134
+
135
+ return upload_promise;
136
+ }
137
+
138
+ function is_valid_mimetype(
139
+ file_accept: string | string[] | null,
140
+ uploaded_file_extension: string,
141
+ uploaded_file_type: string
142
+ ): boolean {
143
+ if (
144
+ !file_accept ||
145
+ file_accept === "*" ||
146
+ file_accept === "file/*" ||
147
+ (Array.isArray(file_accept) &&
148
+ file_accept.some((accept) => accept === "*" || accept === "file/*"))
149
+ ) {
150
+ return true;
151
+ }
152
+ let acceptArray: string[];
153
+ if (typeof file_accept === "string") {
154
+ acceptArray = file_accept.split(",").map((s) => s.trim());
155
+ } else if (Array.isArray(file_accept)) {
156
+ acceptArray = file_accept;
157
+ } else {
158
+ return false;
159
+ }
160
+
161
+ return (
162
+ acceptArray.includes(uploaded_file_extension) ||
163
+ acceptArray.some((type) => {
164
+ const [category] = type.split("/").map((s) => s.trim());
165
+ return (
166
+ type.endsWith("/*") && uploaded_file_type.startsWith(category + "/")
167
+ );
168
+ })
169
+ );
170
+ }
171
+
172
+ export async function load_files(
173
+ files: File[] | Blob[],
174
+ upload_id?: string
175
+ ): Promise<(FileData | null)[] | void> {
176
+ if (!files.length) {
177
+ return;
178
+ }
179
+ let _files: File[] = files.map(
180
+ (f) =>
181
+ new File([f], f instanceof File ? f.name : "file", { type: f.type })
182
+ );
183
+
184
+ if (ios && use_post_upload_validation) {
185
+ _files = _files.filter((file) => {
186
+ if (is_valid_file(file)) {
187
+ return true;
188
+ }
189
+ dispatch(
190
+ "error",
191
+ `Invalid file type: ${file.name}. Only ${filetype} allowed.`
192
+ );
193
+ return false;
194
+ });
195
+
196
+ if (_files.length === 0) {
197
+ return [];
198
+ }
199
+ }
200
+
201
+ file_data = await prepare_files(_files);
202
+ return await handle_upload(file_data, upload_id);
203
+ }
204
+
205
+ function is_valid_file(file: File): boolean {
206
+ if (!filetype) return true;
207
+
208
+ const allowed_types = Array.isArray(filetype) ? filetype : [filetype];
209
+
210
+ return allowed_types.some((type) => {
211
+ const processed_type = process_file_type(type);
212
+
213
+ if (processed_type.startsWith(".")) {
214
+ return file.name.toLowerCase().endsWith(processed_type.toLowerCase());
215
+ }
216
+
217
+ if (processed_type === "*") {
218
+ return true;
219
+ }
220
+
221
+ if (processed_type.endsWith("/*")) {
222
+ const [category] = processed_type.split("/");
223
+ return file.type.startsWith(category + "/");
224
+ }
225
+
226
+ return file.type === processed_type;
227
+ });
228
+ }
229
+
230
+ async function load_files_from_upload(files: File[]): Promise<void> {
231
+ const files_to_load = files.filter((file) => {
232
+ const file_extension = "." + file.name.toLowerCase().split(".").pop();
233
+ if (
234
+ file_extension &&
235
+ is_valid_mimetype(accept_file_types, file_extension, file.type)
236
+ ) {
237
+ return true;
238
+ }
239
+ if (
240
+ file_extension && Array.isArray(filetype)
241
+ ? filetype.includes(file_extension)
242
+ : file_extension === filetype
243
+ ) {
244
+ return true;
245
+ }
246
+ dispatch("error", `Invalid file type only ${filetype} allowed.`);
247
+ return false;
248
+ });
249
+ if (format != "blob") {
250
+ await load_files(files_to_load);
251
+ } else {
252
+ if (file_count === "single") {
253
+ dispatch("load", files_to_load[0]);
254
+ return;
255
+ }
256
+ dispatch("load", files_to_load);
257
+ }
258
+ }
259
+
260
+ export async function load_files_from_drop(e: DragEvent): Promise<void> {
261
+ dragging = false;
262
+ if (!e.dataTransfer?.files) return;
263
+ const files_to_load = Array.from(e.dataTransfer.files).filter(
264
+ is_valid_file
265
+ );
266
+
267
+ if (format != "blob") {
268
+ await load_files(files_to_load);
269
+ } else {
270
+ if (file_count === "single") {
271
+ dispatch("load", files_to_load[0]);
272
+ return;
273
+ }
274
+ dispatch("load", files_to_load);
275
+ }
276
+ }
207
277
  </script>
208
278
 
209
279
  {#if filetype === "clipboard"}
@@ -1,52 +1,63 @@
1
- import { SvelteComponent } from "svelte";
2
1
  import type { FileData } from "@gradio/client";
3
2
  import { type Client } from "@gradio/client";
4
- declare const __propDef: {
5
- props: {
6
- filetype?: string | string[] | null;
7
- dragging?: boolean;
8
- boundedheight?: boolean;
9
- center?: boolean;
10
- flex?: boolean;
11
- file_count?: "single" | "multiple" | "directory";
12
- disable_click?: boolean;
13
- root: string;
14
- hidden?: boolean;
15
- format?: "blob" | "file";
16
- uploading?: boolean;
17
- show_progress?: boolean;
18
- max_file_size?: number | null;
19
- upload: Client["upload"];
20
- stream_handler: Client["stream"];
21
- icon_upload?: boolean;
22
- height?: number | string | undefined;
23
- aria_label?: string | undefined;
24
- open_upload?: () => void;
25
- paste_clipboard?: () => void;
26
- open_file_upload?: () => void;
27
- load_files?: (files: File[] | Blob[], upload_id?: string) => Promise<(FileData | null)[] | void>;
28
- load_files_from_drop?: (e: DragEvent) => Promise<void>;
3
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
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;
29
13
  };
30
- events: {
31
- load: CustomEvent<any>;
32
- error: CustomEvent<any>;
33
- } & {
34
- [evt: string]: CustomEvent<any>;
35
- };
36
- slots: {
37
- default: {};
38
- };
39
- exports?: {} | undefined;
40
- bindings?: string | undefined;
41
- };
42
- export type UploadProps = typeof __propDef.props;
43
- export type UploadEvents = typeof __propDef.events;
44
- export type UploadSlots = typeof __propDef.slots;
45
- export default class Upload extends SvelteComponent<UploadProps, UploadEvents, UploadSlots> {
46
- get open_upload(): () => void;
47
- get paste_clipboard(): () => void;
48
- get open_file_upload(): () => void;
49
- get load_files(): (files: File[] | Blob[], upload_id?: string) => Promise<(FileData | null)[] | void>;
50
- get load_files_from_drop(): (e: DragEvent) => Promise<void>;
14
+ z_$$bindings?: Bindings;
51
15
  }
52
- export {};
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<{
22
+ filetype?: string | string[] | null;
23
+ dragging?: boolean;
24
+ boundedheight?: boolean;
25
+ center?: boolean;
26
+ flex?: boolean;
27
+ file_count?: "single" | "multiple" | "directory";
28
+ disable_click?: boolean;
29
+ root: string;
30
+ hidden?: boolean;
31
+ format?: "blob" | "file";
32
+ uploading?: boolean;
33
+ show_progress?: boolean;
34
+ max_file_size?: number | null;
35
+ upload: Client["upload"];
36
+ stream_handler: Client["stream"];
37
+ icon_upload?: boolean;
38
+ height?: number | string | undefined;
39
+ aria_label?: string | undefined;
40
+ upload_promise?: Promise<(FileData | null)[]> | null;
41
+ open_upload?: () => void;
42
+ paste_clipboard?: () => void;
43
+ open_file_upload?: () => void;
44
+ load_files?: (files: File[] | Blob[], upload_id?: string) => Promise<(FileData | null)[] | void>;
45
+ load_files_from_drop?: (e: DragEvent) => Promise<void>;
46
+ }, {
47
+ default: {};
48
+ }>, {
49
+ load: CustomEvent<any>;
50
+ error: CustomEvent<any>;
51
+ } & {
52
+ [evt: string]: CustomEvent<any>;
53
+ }, {
54
+ default: {};
55
+ }, {
56
+ open_upload: () => void;
57
+ paste_clipboard: () => void;
58
+ open_file_upload: () => void;
59
+ load_files: (files: File[] | Blob[], upload_id?: string) => Promise<(FileData | null)[] | void>;
60
+ load_files_from_drop: (e: DragEvent) => Promise<void>;
61
+ }, string>;
62
+ type Upload = InstanceType<typeof Upload>;
63
+ export default Upload;
@@ -1,66 +1,86 @@
1
- <script>import { FileData } from "@gradio/client";
2
- import { onMount, createEventDispatcher, onDestroy } from "svelte";
3
- export let upload_id;
4
- export let root;
5
- export let files;
6
- export let stream_handler;
7
- let stream;
8
- let progress = false;
9
- let current_file_upload;
10
- let file_to_display;
11
- let files_with_progress = files.map((file) => {
12
- return {
13
- ...file,
14
- progress: 0
15
- };
16
- });
17
- const dispatch = createEventDispatcher();
18
- function handleProgress(filename, chunk_size) {
19
- files_with_progress = files_with_progress.map((file) => {
20
- if (file.orig_name === filename) {
21
- file.progress += chunk_size;
22
- }
23
- return file;
24
- });
25
- }
26
- function getProgress(file) {
27
- return file.progress * 100 / (file.size || 0) || 0;
28
- }
29
- onMount(async () => {
30
- stream = await stream_handler(
31
- new URL(`${root}/gradio_api/upload_progress?upload_id=${upload_id}`)
32
- );
33
- if (stream == null) {
34
- throw new Error("Event source is not defined");
35
- }
36
- stream.onmessage = async function(event) {
37
- const _data = JSON.parse(event.data);
38
- if (!progress) progress = true;
39
- if (_data.msg === "done") {
40
- stream?.close();
41
- dispatch("done");
42
- } else {
43
- current_file_upload = _data;
44
- handleProgress(_data.orig_name, _data.chunk_size);
45
- }
46
- };
47
- });
48
- onDestroy(() => {
49
- if (stream != null || stream != void 0) stream.close();
50
- });
51
- function calculateTotalProgress(files2) {
52
- let totalProgress = 0;
53
- files2.forEach((file) => {
54
- totalProgress += getProgress(file);
55
- });
56
- document.documentElement.style.setProperty(
57
- "--upload-progress-width",
58
- (totalProgress / files2.length).toFixed(2) + "%"
59
- );
60
- return totalProgress / files2.length;
61
- }
62
- $: calculateTotalProgress(files_with_progress);
63
- $: file_to_display = current_file_upload || files_with_progress[0];
1
+ <script lang="ts">
2
+ import { FileData, type Client } from "@gradio/client";
3
+ import { onMount, createEventDispatcher, onDestroy } from "svelte";
4
+
5
+ type FileDataWithProgress = FileData & { progress: number };
6
+
7
+ export let upload_id: string;
8
+ export let root: string;
9
+ export let files: FileData[];
10
+ export let stream_handler: Client["stream"];
11
+
12
+ let stream: Awaited<ReturnType<Client["stream"]>>;
13
+ let progress = false;
14
+ let current_file_upload: FileDataWithProgress;
15
+ let file_to_display: FileDataWithProgress;
16
+
17
+ let files_with_progress: FileDataWithProgress[] = files.map((file) => {
18
+ return {
19
+ ...file,
20
+ progress: 0
21
+ };
22
+ });
23
+
24
+ const dispatch = createEventDispatcher();
25
+
26
+ function handleProgress(filename: string, chunk_size: number): void {
27
+ // Find the corresponding file in the array and update its progress
28
+ files_with_progress = files_with_progress.map((file) => {
29
+ if (file.orig_name === filename) {
30
+ file.progress += chunk_size;
31
+ }
32
+ return file;
33
+ });
34
+ }
35
+
36
+ function getProgress(file: FileDataWithProgress): number {
37
+ return (file.progress * 100) / (file.size || 0) || 0;
38
+ }
39
+
40
+ onMount(async () => {
41
+ stream = await stream_handler(
42
+ new URL(`${root}/gradio_api/upload_progress?upload_id=${upload_id}`)
43
+ );
44
+
45
+ if (stream == null) {
46
+ throw new Error("Event source is not defined");
47
+ }
48
+ // Event listener for progress updates
49
+ stream.onmessage = async function (event) {
50
+ const _data = JSON.parse(event.data);
51
+ if (!progress) progress = true;
52
+ if (_data.msg === "done") {
53
+ // the stream will close itself but is here for clarity; remove .close() in 5.0
54
+ stream?.close();
55
+ dispatch("done");
56
+ } else {
57
+ current_file_upload = _data;
58
+ handleProgress(_data.orig_name, _data.chunk_size);
59
+ }
60
+ };
61
+ });
62
+ onDestroy(() => {
63
+ // the stream will close itself but is here for clarity; remove .close() in 5.0
64
+ if (stream != null || stream != undefined) stream.close();
65
+ });
66
+
67
+ function calculateTotalProgress(files: FileData[]): number {
68
+ let totalProgress = 0;
69
+ files.forEach((file) => {
70
+ totalProgress += getProgress(file as FileDataWithProgress);
71
+ });
72
+
73
+ document.documentElement.style.setProperty(
74
+ "--upload-progress-width",
75
+ (totalProgress / files.length).toFixed(2) + "%"
76
+ );
77
+
78
+ return totalProgress / files.length;
79
+ }
80
+
81
+ $: calculateTotalProgress(files_with_progress);
82
+
83
+ $: file_to_display = current_file_upload || files_with_progress[0];
64
84
  </script>
65
85
 
66
86
  <div class="wrap" class:progress>
@@ -154,7 +174,8 @@ $: file_to_display = current_file_upload || files_with_progress[0];
154
174
  width: 14px;
155
175
  height: 14px;
156
176
  border-radius: 50%;
157
- background: radial-gradient(
177
+ background:
178
+ radial-gradient(
158
179
  closest-side,
159
180
  var(--block-background-fill) 64%,
160
181
  transparent 53% 100%
@@ -1,24 +1,26 @@
1
- import { SvelteComponent } from "svelte";
2
1
  import { FileData, type Client } from "@gradio/client";
3
- declare const __propDef: {
4
- props: {
5
- upload_id: string;
6
- root: string;
7
- files: FileData[];
8
- stream_handler: Client["stream"];
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
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;
9
12
  };
10
- events: {
11
- done: CustomEvent<any>;
12
- } & {
13
- [evt: string]: CustomEvent<any>;
14
- };
15
- slots: {};
16
- exports?: {} | undefined;
17
- bindings?: string | undefined;
18
- };
19
- export type UploadProgressProps = typeof __propDef.props;
20
- export type UploadProgressEvents = typeof __propDef.events;
21
- export type UploadProgressSlots = typeof __propDef.slots;
22
- export default class UploadProgress extends SvelteComponent<UploadProgressProps, UploadProgressEvents, UploadProgressSlots> {
13
+ z_$$bindings?: Bindings;
23
14
  }
24
- export {};
15
+ declare const UploadProgress: $$__sveltets_2_IsomorphicComponent<{
16
+ upload_id: string;
17
+ root: string;
18
+ files: FileData[];
19
+ stream_handler: Client["stream"];
20
+ }, {
21
+ done: CustomEvent<any>;
22
+ } & {
23
+ [evt: string]: CustomEvent<any>;
24
+ }, {}, {}, string>;
25
+ type UploadProgress = InstanceType<typeof UploadProgress>;
26
+ export default UploadProgress;
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@gradio/upload",
3
- "version": "0.17.1",
3
+ "version": "0.17.2-dev.2",
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.18.1",
11
- "@gradio/client": "^1.19.0",
12
- "@gradio/utils": "^0.10.2",
13
- "@gradio/icons": "^0.14.0"
10
+ "@gradio/atoms": "^0.19.0-dev.1",
11
+ "@gradio/client": "^2.0.0-dev.2",
12
+ "@gradio/icons": "^0.15.0-dev.0",
13
+ "@gradio/utils": "^0.10.3-dev.0"
14
14
  },
15
15
  "main_changeset": true,
16
16
  "exports": {
@@ -21,7 +21,7 @@
21
21
  }
22
22
  },
23
23
  "peerDependencies": {
24
- "svelte": "^4.0.0"
24
+ "svelte": "^5.43.4"
25
25
  },
26
26
  "repository": {
27
27
  "type": "git",
package/src/Upload.svelte CHANGED
@@ -25,10 +25,12 @@
25
25
  export let icon_upload = false;
26
26
  export let height: number | string | undefined = undefined;
27
27
  export let aria_label: string | undefined = undefined;
28
+ export let upload_promise: Promise<(FileData | null)[]> | null = null;
29
+
28
30
  export function open_upload(): void {
29
31
  _open_file_upload();
30
32
  }
31
- let upload_id: string;
33
+ let upload_id: string = "";
32
34
  let file_data: FileData[];
33
35
  let accept_file_types: string | null;
34
36
  let use_post_upload_validation: boolean | null = null;
@@ -95,30 +97,42 @@
95
97
  _open_file_upload();
96
98
  }
97
99
 
98
- async function handle_upload(
100
+ function handle_upload(
99
101
  file_data: FileData[],
100
- upload_id?: string
102
+ _upload_id?: string
101
103
  ): Promise<(FileData | null)[]> {
102
- await tick();
103
- if (!upload_id) {
104
- upload_id = Math.random().toString(36).substring(2, 15);
105
- }
106
- uploading = true;
107
- try {
108
- const _file_data = await upload(
109
- file_data,
110
- root,
111
- upload_id,
112
- max_file_size ?? Infinity
113
- );
114
- dispatch("load", file_count === "single" ? _file_data?.[0] : _file_data);
115
- uploading = false;
116
- return _file_data || [];
117
- } catch (e) {
118
- dispatch("error", (e as Error).message);
119
- uploading = false;
120
- return [];
121
- }
104
+ upload_promise = new Promise(async (resolve, rej) => {
105
+ await tick();
106
+ if (!_upload_id) {
107
+ upload_id = Math.random().toString(36).substring(2, 15);
108
+ } else {
109
+ upload_id = _upload_id;
110
+ }
111
+
112
+ uploading = true;
113
+
114
+ try {
115
+ const _file_data = await upload(
116
+ file_data,
117
+ root,
118
+ upload_id,
119
+ max_file_size ?? Infinity
120
+ );
121
+ dispatch(
122
+ "load",
123
+ file_count === "single" ? _file_data?.[0] : _file_data
124
+ );
125
+ resolve(_file_data || []);
126
+ uploading = false;
127
+ return _file_data || [];
128
+ } catch (e) {
129
+ dispatch("error", (e as Error).message);
130
+ uploading = false;
131
+ resolve([]);
132
+ }
133
+ });
134
+
135
+ return upload_promise;
122
136
  }
123
137
 
124
138
  function is_valid_mimetype(
@@ -232,7 +246,6 @@
232
246
  dispatch("error", `Invalid file type only ${filetype} allowed.`);
233
247
  return false;
234
248
  });
235
-
236
249
  if (format != "blob") {
237
250
  await load_files(files_to_load);
238
251
  } else {
@@ -174,7 +174,8 @@
174
174
  width: 14px;
175
175
  height: 14px;
176
176
  border-radius: 50%;
177
- background: radial-gradient(
177
+ background:
178
+ radial-gradient(
178
179
  closest-side,
179
180
  var(--block-background-fill) 64%,
180
181
  transparent 53% 100%