@gradio/file 0.14.0 → 0.14.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/file
2
2
 
3
+ ## 0.14.2
4
+
5
+ ### Dependency updates
6
+
7
+ - @gradio/atoms@0.21.0
8
+ - @gradio/client@2.0.4
9
+ - @gradio/statustracker@0.12.3
10
+ - @gradio/upload@0.17.5
11
+
12
+ ## 0.14.1
13
+
14
+ ### Fixes
15
+
16
+ - [#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!
17
+ - [#12698](https://github.com/gradio-app/gradio/pull/12698) [`db86165`](https://github.com/gradio-app/gradio/commit/db86165535386991701ea89b2083ef5e60cd23e8) - Migrates gr.File. Thanks @aliabid94!
18
+ - [#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!
19
+
20
+ ### Dependency updates
21
+
22
+ - @gradio/statustracker@0.12.2
23
+ - @gradio/atoms@0.20.1
24
+ - @gradio/utils@0.11.2
25
+ - @gradio/icons@0.15.1
26
+ - @gradio/upload@0.17.4
27
+ - @gradio/client@2.0.3
28
+
29
+ ## 0.14.0
30
+
31
+ ### Dependency updates
32
+
33
+ - @gradio/utils@0.11.1
34
+ - @gradio/client@2.0.2
35
+
3
36
  ## 0.14.0
4
37
 
5
38
  ### Features
package/Example.svelte CHANGED
@@ -1,9 +1,15 @@
1
1
  <script lang="ts">
2
2
  import type { FileData } from "@gradio/client";
3
3
 
4
- export let value: FileData | null;
5
- export let type: "gallery" | "table";
6
- export let selected = false;
4
+ let {
5
+ value,
6
+ type,
7
+ selected = false
8
+ }: {
9
+ value: FileData | null;
10
+ type: "gallery" | "table";
11
+ selected: boolean;
12
+ } = $props();
7
13
  </script>
8
14
 
9
15
  <div
@@ -1,64 +1,67 @@
1
- <script>
2
- import { Meta, Template, Story } from "@storybook/addon-svelte-csf";
1
+ <script module>
2
+ import { defineMeta } from "@storybook/addon-svelte-csf";
3
3
  import File from "./Index.svelte";
4
- </script>
4
+ import { wrapProps } from "../storybook/wrapProps";
5
+
6
+ const cheetah = "/cheetah.jpg";
7
+ const bus = "/bus.png";
5
8
 
6
- <Meta
7
- title="Components/File"
8
- component={File}
9
- argTypes={{
10
- value: {
11
- control: "text",
12
- description: "The URL or filepath (or list of URLs or filepaths)",
13
- name: "value",
14
- value: []
9
+ const { Story } = defineMeta({
10
+ title: "Components/File",
11
+ component: File,
12
+ argTypes: {
13
+ value: {
14
+ control: "text",
15
+ description: "The URL or filepath (or list of URLs or filepaths)",
16
+ name: "value",
17
+ value: []
18
+ }
15
19
  }
16
- }}
17
- />
20
+ });
21
+ </script>
18
22
 
19
- <Template let:args>
20
- <File {...args} />
21
- </Template>
23
+ {#snippet template(args)}
24
+ <File {...wrapProps(args)} />
25
+ {/snippet}
22
26
 
23
27
  <Story
24
28
  name="Single File"
25
29
  args={{
26
30
  value: [
27
31
  {
28
- path: "cheetah.jpg",
32
+ path: cheetah,
29
33
  orig_name: "cheetah.jpg",
30
- url: "https://gradio-builds.s3.amazonaws.com/demo-files/ghepardo-primo-piano.jpg",
34
+ url: cheetah,
31
35
  size: 10000
32
36
  }
33
37
  ]
34
38
  }}
39
+ {template}
35
40
  />
36
41
  <Story
37
42
  name="Multiple files, with height set to 150px and reordering enabled"
38
43
  args={{
39
44
  value: [
40
45
  {
41
- path: "cheetah.jpg",
42
- orig_name: "cheetah.jpgz",
43
- url: "https://raw.githubusercontent.com/gradio-app/gradio/main/test/test_files/bus.png",
46
+ path: bus,
47
+ orig_name: "bus.png",
48
+ url: bus,
44
49
  size: 10000
45
50
  },
46
51
  {
47
- path: "cheetah.jpgs",
52
+ path: cheetah,
48
53
  orig_name: "cheetah.jpg",
49
- url: "https://gradio-builds.s3.amazonaws.com/demo-files/ghepardo-primo-piano.jpg",
54
+ url: cheetah,
50
55
  size: 10000
51
56
  }
52
57
  ],
53
58
  height: 150,
54
59
  allow_reordering: true
55
60
  }}
61
+ {template}
56
62
  />
57
63
  <Story
58
64
  name="File upload with height set to 400px"
59
- args={{
60
- interactive: true,
61
- value: null,
62
- height: 400
63
- }}
65
+ args={{ interactive: true, value: null, height: 400 }}
66
+ {template}
64
67
  />
@@ -1,12 +1,14 @@
1
- <script context="module">
2
- import { Template, Story } from "@storybook/addon-svelte-csf";
3
- import { format } from "svelte-i18n";
4
- import FileUpload from "./shared/FileUpload.svelte";
5
- import { get } from "svelte/store";
1
+ <script module>
2
+ import { defineMeta } from "@storybook/addon-svelte-csf";
3
+ import File from "./Index.svelte";
4
+ import { wrapProps } from "../storybook/wrapProps";
6
5
 
7
- export const meta = {
6
+ const cheetah = "/cheetah.jpg";
7
+ const lion = "/lion.jpg";
8
+
9
+ const { Story } = defineMeta({
8
10
  title: "Components/FileUpload",
9
- component: FileUpload,
11
+ component: File,
10
12
  argTypes: {
11
13
  value: {
12
14
  control: "text",
@@ -22,43 +24,53 @@
22
24
  value: "single"
23
25
  }
24
26
  }
25
- };
27
+ });
26
28
  </script>
27
29
 
28
- <Template let:args>
29
- <FileUpload {...args} i18n={get(format)} />
30
- </Template>
30
+ {#snippet template(args)}
31
+ <File {...wrapProps(args)} />
32
+ {/snippet}
31
33
 
32
34
  <Story
33
35
  name="Single File"
34
36
  args={{
35
37
  value: [
36
38
  {
37
- path: "cheetah.jpg",
39
+ path: cheetah,
38
40
  orig_name: "cheetah.jpg",
39
- url: "https://gradio-builds.s3.amazonaws.com/demo-files/ghepardo-primo-piano.jpg",
41
+ url: cheetah,
40
42
  size: 10000
41
43
  }
42
44
  ],
43
- file_count: "single"
45
+ file_count: "single",
46
+ interactive: true
44
47
  }}
48
+ {template}
45
49
  />
46
50
  <Story
47
51
  name="Multiple files"
48
52
  args={{
49
- value: Array(2).fill({
50
- path: "cheetah.jpg",
51
- orig_name: "cheetah.jpg",
52
- url: "https://gradio-builds.s3.amazonaws.com/demo-files/ghepardo-primo-piano.jpg",
53
- size: 10000
54
- }),
55
- file_count: "multiple"
53
+ value: [
54
+ {
55
+ path: cheetah,
56
+ orig_name: "cheetah.jpg",
57
+ url: cheetah,
58
+ size: 10000
59
+ },
60
+ {
61
+ path: lion,
62
+ orig_name: "lion.jpg",
63
+ url: lion,
64
+ size: 10000
65
+ }
66
+ ],
67
+ file_count: "multiple",
68
+ interactive: true
56
69
  }}
70
+ {template}
57
71
  />
58
72
  <Story
59
73
  name="No value"
60
- args={{
61
- value: null,
62
- file_count: "multiple"
63
- }}
74
+ args={{ value: null, file_count: "multiple", interactive: true }}
75
+ {template}
64
76
  />
package/Index.svelte CHANGED
@@ -13,11 +13,12 @@
13
13
  import FileUpload from "./shared/FileUpload.svelte";
14
14
  import { Block, UploadText } from "@gradio/atoms";
15
15
  import type { FileEvents, FileProps } from "./types";
16
+ import type { SelectData } from "@gradio/utils";
16
17
  import { StatusTracker } from "@gradio/statustracker";
17
18
  import { tick } from "svelte";
18
19
 
19
20
  const props = $props();
20
- let upload_promise = $state<Promise<any>>();
21
+ let upload_promise = $state<Promise<any> | null>(null);
21
22
 
22
23
  let dragging = $state(false);
23
24
  let pending_upload = $state(false);
@@ -94,7 +95,7 @@
94
95
  file_count={gradio.props.file_count}
95
96
  file_types={gradio.props.file_types}
96
97
  selectable={gradio.props._selectable}
97
- height={gradio.props.height}
98
+ height={gradio.props.height ?? undefined}
98
99
  root={gradio.shared.root}
99
100
  allow_reordering={gradio.props.allow_reordering}
100
101
  max_file_size={gradio.shared.max_file_size}
@@ -102,19 +103,19 @@
102
103
  on_custom_button_click={(id) => {
103
104
  gradio.dispatch("custom_button_click", { id });
104
105
  }}
105
- on:change={({ detail }) => {
106
+ onchange={(detail) => {
106
107
  gradio.props.value = detail;
107
108
  }}
108
- on:drag={({ detail }) => (dragging = detail)}
109
- on:clear={() => gradio.dispatch("clear")}
110
- on:select={({ detail }) => gradio.dispatch("select", detail)}
111
- on:upload={() => gradio.dispatch("upload")}
112
- on:error={({ detail }) => {
109
+ ondrag={(detail) => (dragging = detail)}
110
+ onclear={() => gradio.dispatch("clear")}
111
+ onselect={(detail: SelectData) => gradio.dispatch("select", detail)}
112
+ onupload={() => gradio.dispatch("upload")}
113
+ onerror={(error) => {
113
114
  gradio.shared.loading_status = gradio.shared.loading_status || {};
114
115
  gradio.shared.loading_status.status = "error";
115
- gradio.dispatch("error", detail);
116
+ gradio.dispatch("error", error);
116
117
  }}
117
- on:delete={({ detail }) => {
118
+ ondelete={(detail) => {
118
119
  gradio.dispatch("delete", detail);
119
120
  }}
120
121
  i18n={gradio.i18n}
@@ -1,9 +1,15 @@
1
1
  <script lang="ts">
2
2
  import type { FileData } from "@gradio/client";
3
3
 
4
- export let value: FileData | null;
5
- export let type: "gallery" | "table";
6
- export let selected = false;
4
+ let {
5
+ value,
6
+ type,
7
+ selected = false
8
+ }: {
9
+ value: FileData | null;
10
+ type: "gallery" | "table";
11
+ selected: boolean;
12
+ } = $props();
7
13
  </script>
8
14
 
9
15
  <div
@@ -1,23 +1,9 @@
1
1
  import type { FileData } from "@gradio/client";
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;
12
- };
13
- z_$$bindings?: Bindings;
14
- }
15
- declare const Example: $$__sveltets_2_IsomorphicComponent<{
2
+ type $$ComponentProps = {
16
3
  value: FileData | null;
17
4
  type: "gallery" | "table";
18
- selected?: boolean;
19
- }, {
20
- [evt: string]: CustomEvent<any>;
21
- }, {}, {}, string>;
22
- type Example = InstanceType<typeof Example>;
5
+ selected: boolean;
6
+ };
7
+ declare const Example: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type Example = ReturnType<typeof Example>;
23
9
  export default Example;
package/dist/Index.svelte CHANGED
@@ -13,11 +13,12 @@
13
13
  import FileUpload from "./shared/FileUpload.svelte";
14
14
  import { Block, UploadText } from "@gradio/atoms";
15
15
  import type { FileEvents, FileProps } from "./types";
16
+ import type { SelectData } from "@gradio/utils";
16
17
  import { StatusTracker } from "@gradio/statustracker";
17
18
  import { tick } from "svelte";
18
19
 
19
20
  const props = $props();
20
- let upload_promise = $state<Promise<any>>();
21
+ let upload_promise = $state<Promise<any> | null>(null);
21
22
 
22
23
  let dragging = $state(false);
23
24
  let pending_upload = $state(false);
@@ -94,7 +95,7 @@
94
95
  file_count={gradio.props.file_count}
95
96
  file_types={gradio.props.file_types}
96
97
  selectable={gradio.props._selectable}
97
- height={gradio.props.height}
98
+ height={gradio.props.height ?? undefined}
98
99
  root={gradio.shared.root}
99
100
  allow_reordering={gradio.props.allow_reordering}
100
101
  max_file_size={gradio.shared.max_file_size}
@@ -102,19 +103,19 @@
102
103
  on_custom_button_click={(id) => {
103
104
  gradio.dispatch("custom_button_click", { id });
104
105
  }}
105
- on:change={({ detail }) => {
106
+ onchange={(detail) => {
106
107
  gradio.props.value = detail;
107
108
  }}
108
- on:drag={({ detail }) => (dragging = detail)}
109
- on:clear={() => gradio.dispatch("clear")}
110
- on:select={({ detail }) => gradio.dispatch("select", detail)}
111
- on:upload={() => gradio.dispatch("upload")}
112
- on:error={({ detail }) => {
109
+ ondrag={(detail) => (dragging = detail)}
110
+ onclear={() => gradio.dispatch("clear")}
111
+ onselect={(detail: SelectData) => gradio.dispatch("select", detail)}
112
+ onupload={() => gradio.dispatch("upload")}
113
+ onerror={(error) => {
113
114
  gradio.shared.loading_status = gradio.shared.loading_status || {};
114
115
  gradio.shared.loading_status.status = "error";
115
- gradio.dispatch("error", detail);
116
+ gradio.dispatch("error", error);
116
117
  }}
117
- on:delete={({ detail }) => {
118
+ ondelete={(detail) => {
118
119
  gradio.dispatch("delete", detail);
119
120
  }}
120
121
  i18n={gradio.i18n}
@@ -1,24 +1,33 @@
1
1
  <script lang="ts">
2
2
  import type { FileData } from "@gradio/client";
3
3
  import { prettyBytes } from "./utils";
4
- import { createEventDispatcher } from "svelte";
5
4
  import type { I18nFormatter, SelectData } from "@gradio/utils";
6
5
  import { DownloadLink } from "@gradio/atoms";
7
6
 
8
- const dispatch = createEventDispatcher<{
9
- select: SelectData;
10
- change: FileData[] | FileData;
11
- delete: FileData;
12
- download: FileData;
13
- }>();
14
- export let value: FileData | FileData[];
15
- export let selectable = false;
16
- export let height: number | string | undefined = undefined;
17
- export let i18n: I18nFormatter;
18
- export let allow_reordering = false;
19
-
20
- let dragging_index: number | null = null;
21
- let drop_target_index: number | null = null;
7
+ let {
8
+ value,
9
+ selectable = false,
10
+ height = undefined,
11
+ i18n,
12
+ allow_reordering = false,
13
+ onselect,
14
+ onchange,
15
+ ondelete,
16
+ ondownload
17
+ }: {
18
+ value: FileData | FileData[];
19
+ selectable?: boolean;
20
+ height?: number | string | undefined;
21
+ i18n: I18nFormatter;
22
+ allow_reordering?: boolean;
23
+ onselect?: (event_data: SelectData) => void;
24
+ onchange?: (event_data: FileData[] | FileData) => void;
25
+ ondelete?: (event_data: FileData) => void;
26
+ ondownload?: (event_data: FileData) => void;
27
+ } = $props();
28
+
29
+ let dragging_index: number | null = $state(null);
30
+ let drop_target_index: number | null = $state(null);
22
31
 
23
32
  function handle_drag_start(event: DragEvent, index: number): void {
24
33
  dragging_index = index;
@@ -68,7 +77,7 @@
68
77
  );
69
78
 
70
79
  const new_value = Array.isArray(value) ? files : files[0];
71
- dispatch("change", new_value);
80
+ onchange?.(new_value);
72
81
 
73
82
  dragging_index = null;
74
83
  drop_target_index = null;
@@ -82,14 +91,18 @@
82
91
  return [filename.slice(0, last_dot), filename.slice(last_dot)];
83
92
  }
84
93
 
85
- $: normalized_files = (Array.isArray(value) ? value : [value]).map((file) => {
86
- const [filename_stem, filename_ext] = split_filename(file.orig_name ?? "");
87
- return {
88
- ...file,
89
- filename_stem,
90
- filename_ext
91
- };
92
- });
94
+ let normalized_files = $derived(
95
+ (Array.isArray(value) ? value : [value]).map((file) => {
96
+ const [filename_stem, filename_ext] = split_filename(
97
+ file.orig_name ?? ""
98
+ );
99
+ return {
100
+ ...file,
101
+ filename_stem,
102
+ filename_ext
103
+ };
104
+ })
105
+ );
93
106
 
94
107
  function handle_row_click(
95
108
  event: MouseEvent & { currentTarget: HTMLTableRowElement },
@@ -103,20 +116,21 @@
103
116
  event.composedPath().includes(tr.firstElementChild)); // Or if the click is on the name column
104
117
 
105
118
  if (should_select) {
106
- dispatch("select", { value: normalized_files[index].orig_name, index });
119
+ onselect?.({ value: normalized_files[index].orig_name, index });
107
120
  }
108
121
  }
109
122
 
110
123
  function remove_file(index: number): void {
111
- const removed = normalized_files.splice(index, 1);
112
- normalized_files = [...normalized_files];
113
- value = normalized_files;
114
- dispatch("delete", removed[0]);
115
- dispatch("change", normalized_files);
124
+ const files = Array.isArray(value) ? [...value] : [value];
125
+ const removed = files.splice(index, 1);
126
+ const new_value = Array.isArray(value) ? files : files[0];
127
+ value = new_value;
128
+ ondelete?.(removed[0]);
129
+ onchange?.(new_value);
116
130
  }
117
131
 
118
132
  function handle_download(file: FileData): void {
119
- dispatch("download", file);
133
+ ondownload?.(file);
120
134
  }
121
135
 
122
136
  const is_browser = typeof window !== "undefined";
@@ -147,14 +161,14 @@
147
161
  ? "after"
148
162
  : "before"}
149
163
  draggable={allow_reordering && normalized_files.length > 1}
150
- on:click={(event) => {
164
+ onclick={(event) => {
151
165
  handle_row_click(event, i);
152
166
  }}
153
- on:dragstart={(event) => handle_drag_start(event, i)}
154
- on:dragenter|preventDefault
155
- on:dragover={(event) => handle_drag_over(event, i)}
156
- on:drop={(event) => handle_drop(event, i)}
157
- on:dragend={handle_drag_end}
167
+ ondragstart={(event) => handle_drag_start(event, i)}
168
+ ondragenter={(event) => event.preventDefault()}
169
+ ondragover={(event) => handle_drag_over(event, i)}
170
+ ondrop={(event) => handle_drop(event, i)}
171
+ ondragend={handle_drag_end}
158
172
  >
159
173
  <td class="filename" aria-label={file.orig_name}>
160
174
  {#if allow_reordering && normalized_files.length > 1}
@@ -187,10 +201,10 @@
187
201
  <button
188
202
  class="label-clear-button"
189
203
  aria-label="Remove this file"
190
- on:click={() => {
204
+ onclick={() => {
191
205
  remove_file(i);
192
206
  }}
193
- on:keydown={(event) => {
207
+ onkeydown={(event) => {
194
208
  if (event.key === "Enter") {
195
209
  remove_file(i);
196
210
  }
@@ -1,32 +1,16 @@
1
1
  import type { FileData } from "@gradio/client";
2
2
  import type { I18nFormatter, SelectData } from "@gradio/utils";
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;
13
- };
14
- z_$$bindings?: Bindings;
15
- }
16
- declare const FilePreview: $$__sveltets_2_IsomorphicComponent<{
3
+ type $$ComponentProps = {
17
4
  value: FileData | FileData[];
18
5
  selectable?: boolean;
19
6
  height?: number | string | undefined;
20
7
  i18n: I18nFormatter;
21
8
  allow_reordering?: boolean;
22
- }, {
23
- dragenter: DragEvent;
24
- select: CustomEvent<SelectData>;
25
- change: CustomEvent<FileData | FileData[]>;
26
- delete: CustomEvent<FileData>;
27
- download: CustomEvent<FileData>;
28
- } & {
29
- [evt: string]: CustomEvent<any>;
30
- }, {}, {}, string>;
31
- type FilePreview = InstanceType<typeof FilePreview>;
9
+ onselect?: (event_data: SelectData) => void;
10
+ onchange?: (event_data: FileData[] | FileData) => void;
11
+ ondelete?: (event_data: FileData) => void;
12
+ ondownload?: (event_data: FileData) => void;
13
+ };
14
+ declare const FilePreview: import("svelte").Component<$$ComponentProps, {}, "">;
15
+ type FilePreview = ReturnType<typeof FilePreview>;
32
16
  export default FilePreview;
@@ -1,36 +1,67 @@
1
1
  <script lang="ts">
2
- import { createEventDispatcher, tick } from "svelte";
2
+ import { tick } from "svelte";
3
3
  import { Upload, ModifyUpload } from "@gradio/upload";
4
4
  import type { FileData, Client } from "@gradio/client";
5
5
  import { BlockLabel, IconButtonWrapper, IconButton } from "@gradio/atoms";
6
6
  import { File, Clear, Upload as UploadIcon } from "@gradio/icons";
7
7
 
8
8
  import FilePreview from "./FilePreview.svelte";
9
- import type { I18nFormatter } from "@gradio/utils";
9
+ import type { I18nFormatter, SelectData } from "@gradio/utils";
10
10
  import type { CustomButton as CustomButtonType } from "@gradio/utils";
11
11
 
12
- export let value: null | FileData | FileData[];
12
+ let {
13
+ value = $bindable<null | FileData | FileData[]>(),
14
+ label,
15
+ show_label = true,
16
+ file_count = "single",
17
+ file_types = null,
18
+ selectable = false,
19
+ root,
20
+ height = undefined,
21
+ i18n,
22
+ max_file_size = null,
23
+ upload,
24
+ stream_handler,
25
+ uploading = $bindable(false),
26
+ allow_reordering = false,
27
+ upload_promise = $bindable<Promise<(FileData | null)[]> | null>(),
28
+ buttons = null,
29
+ on_custom_button_click = null,
30
+ onchange,
31
+ onclear,
32
+ ondrag,
33
+ onupload,
34
+ onerror,
35
+ ondelete,
36
+ onselect
37
+ }: {
38
+ value: null | FileData | FileData[];
39
+ label: string;
40
+ show_label?: boolean;
41
+ file_count: "single" | "multiple" | "directory";
42
+ file_types: string[] | null;
43
+ selectable?: boolean;
44
+ root: string;
45
+ height?: number | undefined;
46
+ i18n: I18nFormatter;
47
+ max_file_size: number | null;
48
+ upload: Client["upload"];
49
+ stream_handler: Client["stream"];
50
+ uploading?: boolean;
51
+ allow_reordering?: boolean;
52
+ upload_promise?: Promise<(FileData | null)[]> | null;
53
+ buttons?: (string | CustomButtonType)[] | null;
54
+ on_custom_button_click?: ((id: number) => void) | null;
55
+ onchange?: (event_data: FileData[] | FileData | null) => void;
56
+ onclear?: () => void;
57
+ ondrag?: (dragging: boolean) => void;
58
+ onupload?: (event_data: FileData[] | FileData) => void;
59
+ onerror?: (error: string) => void;
60
+ ondelete?: (event_data: FileData) => void;
61
+ onselect?: (event_data: SelectData) => void;
62
+ } = $props();
13
63
 
14
- export let label: string;
15
- export let show_label = true;
16
- export let file_count: "single" | "multiple" | "directory" = "single";
17
- export let file_types: string[] | null = null;
18
- export let selectable = false;
19
- export let root: string;
20
- export let height: number | undefined = undefined;
21
- export let i18n: I18nFormatter;
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 uploading = false;
26
- export let allow_reordering = false;
27
- export let upload_promise: Promise<(FileData | null)[]> | null = null;
28
- export let buttons: (string | CustomButtonType)[] | null = null;
29
- export let on_custom_button_click: ((id: number) => void) | null = null;
30
-
31
- async function handle_upload({
32
- detail
33
- }: CustomEvent<FileData | FileData[]>): Promise<void> {
64
+ async function handle_upload(detail: FileData | FileData[]): Promise<void> {
34
65
  if (Array.isArray(value)) {
35
66
  value = [...value, ...(Array.isArray(detail) ? detail : [detail])];
36
67
  } else if (value) {
@@ -39,27 +70,17 @@
39
70
  value = detail;
40
71
  }
41
72
  await tick();
42
- dispatch("change", value);
43
- dispatch("upload", detail);
73
+ onchange?.(value);
74
+ onupload?.(value);
44
75
  }
45
76
 
46
77
  function handle_clear(): void {
47
78
  value = null;
48
- dispatch("change", null);
49
- dispatch("clear");
79
+ onchange?.(null);
80
+ onclear?.();
50
81
  }
51
82
 
52
- const dispatch = createEventDispatcher<{
53
- change: FileData[] | FileData | null;
54
- clear: undefined;
55
- drag: boolean;
56
- upload: FileData[] | FileData;
57
- load: FileData[] | FileData;
58
- error: string;
59
- }>();
60
-
61
- let dragging = false;
62
- $: dispatch("drag", dragging);
83
+ let dragging = $state(false);
63
84
  </script>
64
85
 
65
86
  {#if show_label && buttons && buttons.length > 0}
@@ -74,14 +95,14 @@
74
95
  <Upload
75
96
  bind:upload_promise
76
97
  icon_upload={true}
77
- on:load={handle_upload}
98
+ onload={handle_upload}
78
99
  filetype={file_types}
79
100
  {file_count}
80
101
  {max_file_size}
81
102
  {root}
82
103
  bind:dragging
83
104
  bind:uploading
84
- on:error
105
+ {onerror}
85
106
  {stream_handler}
86
107
  {upload}
87
108
  />
@@ -90,8 +111,7 @@
90
111
  <IconButton
91
112
  Icon={Clear}
92
113
  label={i18n("common.clear")}
93
- on:click={(event) => {
94
- dispatch("clear");
114
+ onclick={(event) => {
95
115
  event.stopPropagation();
96
116
  handle_clear();
97
117
  }}
@@ -100,25 +120,25 @@
100
120
 
101
121
  <FilePreview
102
122
  {i18n}
103
- on:select
123
+ {onselect}
104
124
  {selectable}
105
125
  {value}
106
126
  {height}
107
- on:change
108
- on:delete
127
+ {onchange}
128
+ {ondelete}
109
129
  {allow_reordering}
110
130
  />
111
131
  {:else}
112
132
  <Upload
113
133
  bind:upload_promise
114
- on:load={handle_upload}
134
+ onload={handle_upload}
115
135
  filetype={file_types}
116
136
  {file_count}
117
137
  {max_file_size}
118
138
  {root}
119
139
  bind:dragging
120
140
  bind:uploading
121
- on:error
141
+ {onerror}
122
142
  {stream_handler}
123
143
  {upload}
124
144
  {height}
@@ -1,6 +1,32 @@
1
1
  import type { FileData, Client } from "@gradio/client";
2
- import type { I18nFormatter } from "@gradio/utils";
2
+ import type { I18nFormatter, SelectData } from "@gradio/utils";
3
3
  import type { CustomButton as CustomButtonType } from "@gradio/utils";
4
+ type $$ComponentProps = {
5
+ value: null | FileData | FileData[];
6
+ label: string;
7
+ show_label?: boolean;
8
+ file_count: "single" | "multiple" | "directory";
9
+ file_types: string[] | null;
10
+ selectable?: boolean;
11
+ root: string;
12
+ height?: number | undefined;
13
+ i18n: I18nFormatter;
14
+ max_file_size: number | null;
15
+ upload: Client["upload"];
16
+ stream_handler: Client["stream"];
17
+ uploading?: boolean;
18
+ allow_reordering?: boolean;
19
+ upload_promise?: Promise<(FileData | null)[]> | null;
20
+ buttons?: (string | CustomButtonType)[] | null;
21
+ on_custom_button_click?: ((id: number) => void) | null;
22
+ onchange?: (event_data: FileData[] | FileData | null) => void;
23
+ onclear?: () => void;
24
+ ondrag?: (dragging: boolean) => void;
25
+ onupload?: (event_data: FileData[] | FileData) => void;
26
+ onerror?: (error: string) => void;
27
+ ondelete?: (event_data: FileData) => void;
28
+ onselect?: (event_data: SelectData) => void;
29
+ };
4
30
  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> {
5
31
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
6
32
  $$bindings?: Bindings;
@@ -19,39 +45,12 @@ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
19
45
  } ? Props extends Record<string, never> ? any : {
20
46
  children?: any;
21
47
  } : {});
22
- declare const FileUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
23
- value: null | FileData | FileData[];
24
- label: string;
25
- show_label?: boolean;
26
- file_count?: "single" | "multiple" | "directory";
27
- file_types?: string[] | null;
28
- selectable?: boolean;
29
- root: string;
30
- height?: number | undefined;
31
- i18n: I18nFormatter;
32
- max_file_size?: number | null;
33
- upload: Client["upload"];
34
- stream_handler: Client["stream"];
35
- uploading?: boolean;
36
- allow_reordering?: boolean;
37
- upload_promise?: Promise<(FileData | null)[]> | null;
38
- buttons?: (string | CustomButtonType)[] | null;
39
- on_custom_button_click?: ((id: number) => void) | null;
40
- }, {
48
+ declare const FileUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<$$ComponentProps, {
41
49
  default: {};
42
50
  }>, {
43
- error: CustomEvent<any>;
44
- select: CustomEvent<import("@gradio/utils").SelectData>;
45
- change: CustomEvent<any>;
46
- delete: CustomEvent<FileData>;
47
- clear: CustomEvent<undefined>;
48
- drag: CustomEvent<boolean>;
49
- upload: CustomEvent<FileData | FileData[]>;
50
- load: CustomEvent<FileData | FileData[]>;
51
- } & {
52
51
  [evt: string]: CustomEvent<any>;
53
52
  }, {
54
53
  default: {};
55
- }, {}, string>;
54
+ }, {}, "value" | "uploading" | "upload_promise">;
56
55
  type FileUpload = InstanceType<typeof FileUpload>;
57
56
  export default FileUpload;
package/dist/types.d.ts CHANGED
@@ -19,7 +19,7 @@ export interface FileEvents {
19
19
  clear: void;
20
20
  select: SelectData | null;
21
21
  change: FileData | FileData[] | null;
22
- delete: void;
22
+ delete: FileData;
23
23
  custom_button_click: {
24
24
  id: number;
25
25
  };
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@gradio/file",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
7
7
  "license": "ISC",
8
8
  "private": false,
9
9
  "dependencies": {
10
- "@gradio/atoms": "^0.20.0",
11
- "@gradio/client": "^2.0.1",
12
- "@gradio/statustracker": "^0.12.1",
13
- "@gradio/icons": "^0.15.0",
14
- "@gradio/upload": "^0.17.3",
15
- "@gradio/utils": "^0.11.0"
10
+ "@gradio/atoms": "^0.21.0",
11
+ "@gradio/icons": "^0.15.1",
12
+ "@gradio/client": "^2.0.4",
13
+ "@gradio/statustracker": "^0.12.3",
14
+ "@gradio/utils": "^0.11.2",
15
+ "@gradio/upload": "^0.17.5"
16
16
  },
17
17
  "devDependencies": {
18
- "@gradio/preview": "^0.15.1"
18
+ "@gradio/preview": "^0.15.2"
19
19
  },
20
20
  "main": "./Index.svelte",
21
21
  "main_changeset": true,
@@ -33,7 +33,7 @@
33
33
  "./package.json": "./package.json"
34
34
  },
35
35
  "peerDependencies": {
36
- "svelte": "^5.43.4"
36
+ "svelte": "^5.48.0"
37
37
  },
38
38
  "repository": {
39
39
  "type": "git",
@@ -1,24 +1,33 @@
1
1
  <script lang="ts">
2
2
  import type { FileData } from "@gradio/client";
3
3
  import { prettyBytes } from "./utils";
4
- import { createEventDispatcher } from "svelte";
5
4
  import type { I18nFormatter, SelectData } from "@gradio/utils";
6
5
  import { DownloadLink } from "@gradio/atoms";
7
6
 
8
- const dispatch = createEventDispatcher<{
9
- select: SelectData;
10
- change: FileData[] | FileData;
11
- delete: FileData;
12
- download: FileData;
13
- }>();
14
- export let value: FileData | FileData[];
15
- export let selectable = false;
16
- export let height: number | string | undefined = undefined;
17
- export let i18n: I18nFormatter;
18
- export let allow_reordering = false;
19
-
20
- let dragging_index: number | null = null;
21
- let drop_target_index: number | null = null;
7
+ let {
8
+ value,
9
+ selectable = false,
10
+ height = undefined,
11
+ i18n,
12
+ allow_reordering = false,
13
+ onselect,
14
+ onchange,
15
+ ondelete,
16
+ ondownload
17
+ }: {
18
+ value: FileData | FileData[];
19
+ selectable?: boolean;
20
+ height?: number | string | undefined;
21
+ i18n: I18nFormatter;
22
+ allow_reordering?: boolean;
23
+ onselect?: (event_data: SelectData) => void;
24
+ onchange?: (event_data: FileData[] | FileData) => void;
25
+ ondelete?: (event_data: FileData) => void;
26
+ ondownload?: (event_data: FileData) => void;
27
+ } = $props();
28
+
29
+ let dragging_index: number | null = $state(null);
30
+ let drop_target_index: number | null = $state(null);
22
31
 
23
32
  function handle_drag_start(event: DragEvent, index: number): void {
24
33
  dragging_index = index;
@@ -68,7 +77,7 @@
68
77
  );
69
78
 
70
79
  const new_value = Array.isArray(value) ? files : files[0];
71
- dispatch("change", new_value);
80
+ onchange?.(new_value);
72
81
 
73
82
  dragging_index = null;
74
83
  drop_target_index = null;
@@ -82,14 +91,18 @@
82
91
  return [filename.slice(0, last_dot), filename.slice(last_dot)];
83
92
  }
84
93
 
85
- $: normalized_files = (Array.isArray(value) ? value : [value]).map((file) => {
86
- const [filename_stem, filename_ext] = split_filename(file.orig_name ?? "");
87
- return {
88
- ...file,
89
- filename_stem,
90
- filename_ext
91
- };
92
- });
94
+ let normalized_files = $derived(
95
+ (Array.isArray(value) ? value : [value]).map((file) => {
96
+ const [filename_stem, filename_ext] = split_filename(
97
+ file.orig_name ?? ""
98
+ );
99
+ return {
100
+ ...file,
101
+ filename_stem,
102
+ filename_ext
103
+ };
104
+ })
105
+ );
93
106
 
94
107
  function handle_row_click(
95
108
  event: MouseEvent & { currentTarget: HTMLTableRowElement },
@@ -103,20 +116,21 @@
103
116
  event.composedPath().includes(tr.firstElementChild)); // Or if the click is on the name column
104
117
 
105
118
  if (should_select) {
106
- dispatch("select", { value: normalized_files[index].orig_name, index });
119
+ onselect?.({ value: normalized_files[index].orig_name, index });
107
120
  }
108
121
  }
109
122
 
110
123
  function remove_file(index: number): void {
111
- const removed = normalized_files.splice(index, 1);
112
- normalized_files = [...normalized_files];
113
- value = normalized_files;
114
- dispatch("delete", removed[0]);
115
- dispatch("change", normalized_files);
124
+ const files = Array.isArray(value) ? [...value] : [value];
125
+ const removed = files.splice(index, 1);
126
+ const new_value = Array.isArray(value) ? files : files[0];
127
+ value = new_value;
128
+ ondelete?.(removed[0]);
129
+ onchange?.(new_value);
116
130
  }
117
131
 
118
132
  function handle_download(file: FileData): void {
119
- dispatch("download", file);
133
+ ondownload?.(file);
120
134
  }
121
135
 
122
136
  const is_browser = typeof window !== "undefined";
@@ -147,14 +161,14 @@
147
161
  ? "after"
148
162
  : "before"}
149
163
  draggable={allow_reordering && normalized_files.length > 1}
150
- on:click={(event) => {
164
+ onclick={(event) => {
151
165
  handle_row_click(event, i);
152
166
  }}
153
- on:dragstart={(event) => handle_drag_start(event, i)}
154
- on:dragenter|preventDefault
155
- on:dragover={(event) => handle_drag_over(event, i)}
156
- on:drop={(event) => handle_drop(event, i)}
157
- on:dragend={handle_drag_end}
167
+ ondragstart={(event) => handle_drag_start(event, i)}
168
+ ondragenter={(event) => event.preventDefault()}
169
+ ondragover={(event) => handle_drag_over(event, i)}
170
+ ondrop={(event) => handle_drop(event, i)}
171
+ ondragend={handle_drag_end}
158
172
  >
159
173
  <td class="filename" aria-label={file.orig_name}>
160
174
  {#if allow_reordering && normalized_files.length > 1}
@@ -187,10 +201,10 @@
187
201
  <button
188
202
  class="label-clear-button"
189
203
  aria-label="Remove this file"
190
- on:click={() => {
204
+ onclick={() => {
191
205
  remove_file(i);
192
206
  }}
193
- on:keydown={(event) => {
207
+ onkeydown={(event) => {
194
208
  if (event.key === "Enter") {
195
209
  remove_file(i);
196
210
  }
@@ -1,36 +1,67 @@
1
1
  <script lang="ts">
2
- import { createEventDispatcher, tick } from "svelte";
2
+ import { tick } from "svelte";
3
3
  import { Upload, ModifyUpload } from "@gradio/upload";
4
4
  import type { FileData, Client } from "@gradio/client";
5
5
  import { BlockLabel, IconButtonWrapper, IconButton } from "@gradio/atoms";
6
6
  import { File, Clear, Upload as UploadIcon } from "@gradio/icons";
7
7
 
8
8
  import FilePreview from "./FilePreview.svelte";
9
- import type { I18nFormatter } from "@gradio/utils";
9
+ import type { I18nFormatter, SelectData } from "@gradio/utils";
10
10
  import type { CustomButton as CustomButtonType } from "@gradio/utils";
11
11
 
12
- export let value: null | FileData | FileData[];
12
+ let {
13
+ value = $bindable<null | FileData | FileData[]>(),
14
+ label,
15
+ show_label = true,
16
+ file_count = "single",
17
+ file_types = null,
18
+ selectable = false,
19
+ root,
20
+ height = undefined,
21
+ i18n,
22
+ max_file_size = null,
23
+ upload,
24
+ stream_handler,
25
+ uploading = $bindable(false),
26
+ allow_reordering = false,
27
+ upload_promise = $bindable<Promise<(FileData | null)[]> | null>(),
28
+ buttons = null,
29
+ on_custom_button_click = null,
30
+ onchange,
31
+ onclear,
32
+ ondrag,
33
+ onupload,
34
+ onerror,
35
+ ondelete,
36
+ onselect
37
+ }: {
38
+ value: null | FileData | FileData[];
39
+ label: string;
40
+ show_label?: boolean;
41
+ file_count: "single" | "multiple" | "directory";
42
+ file_types: string[] | null;
43
+ selectable?: boolean;
44
+ root: string;
45
+ height?: number | undefined;
46
+ i18n: I18nFormatter;
47
+ max_file_size: number | null;
48
+ upload: Client["upload"];
49
+ stream_handler: Client["stream"];
50
+ uploading?: boolean;
51
+ allow_reordering?: boolean;
52
+ upload_promise?: Promise<(FileData | null)[]> | null;
53
+ buttons?: (string | CustomButtonType)[] | null;
54
+ on_custom_button_click?: ((id: number) => void) | null;
55
+ onchange?: (event_data: FileData[] | FileData | null) => void;
56
+ onclear?: () => void;
57
+ ondrag?: (dragging: boolean) => void;
58
+ onupload?: (event_data: FileData[] | FileData) => void;
59
+ onerror?: (error: string) => void;
60
+ ondelete?: (event_data: FileData) => void;
61
+ onselect?: (event_data: SelectData) => void;
62
+ } = $props();
13
63
 
14
- export let label: string;
15
- export let show_label = true;
16
- export let file_count: "single" | "multiple" | "directory" = "single";
17
- export let file_types: string[] | null = null;
18
- export let selectable = false;
19
- export let root: string;
20
- export let height: number | undefined = undefined;
21
- export let i18n: I18nFormatter;
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 uploading = false;
26
- export let allow_reordering = false;
27
- export let upload_promise: Promise<(FileData | null)[]> | null = null;
28
- export let buttons: (string | CustomButtonType)[] | null = null;
29
- export let on_custom_button_click: ((id: number) => void) | null = null;
30
-
31
- async function handle_upload({
32
- detail
33
- }: CustomEvent<FileData | FileData[]>): Promise<void> {
64
+ async function handle_upload(detail: FileData | FileData[]): Promise<void> {
34
65
  if (Array.isArray(value)) {
35
66
  value = [...value, ...(Array.isArray(detail) ? detail : [detail])];
36
67
  } else if (value) {
@@ -39,27 +70,17 @@
39
70
  value = detail;
40
71
  }
41
72
  await tick();
42
- dispatch("change", value);
43
- dispatch("upload", detail);
73
+ onchange?.(value);
74
+ onupload?.(value);
44
75
  }
45
76
 
46
77
  function handle_clear(): void {
47
78
  value = null;
48
- dispatch("change", null);
49
- dispatch("clear");
79
+ onchange?.(null);
80
+ onclear?.();
50
81
  }
51
82
 
52
- const dispatch = createEventDispatcher<{
53
- change: FileData[] | FileData | null;
54
- clear: undefined;
55
- drag: boolean;
56
- upload: FileData[] | FileData;
57
- load: FileData[] | FileData;
58
- error: string;
59
- }>();
60
-
61
- let dragging = false;
62
- $: dispatch("drag", dragging);
83
+ let dragging = $state(false);
63
84
  </script>
64
85
 
65
86
  {#if show_label && buttons && buttons.length > 0}
@@ -74,14 +95,14 @@
74
95
  <Upload
75
96
  bind:upload_promise
76
97
  icon_upload={true}
77
- on:load={handle_upload}
98
+ onload={handle_upload}
78
99
  filetype={file_types}
79
100
  {file_count}
80
101
  {max_file_size}
81
102
  {root}
82
103
  bind:dragging
83
104
  bind:uploading
84
- on:error
105
+ {onerror}
85
106
  {stream_handler}
86
107
  {upload}
87
108
  />
@@ -90,8 +111,7 @@
90
111
  <IconButton
91
112
  Icon={Clear}
92
113
  label={i18n("common.clear")}
93
- on:click={(event) => {
94
- dispatch("clear");
114
+ onclick={(event) => {
95
115
  event.stopPropagation();
96
116
  handle_clear();
97
117
  }}
@@ -100,25 +120,25 @@
100
120
 
101
121
  <FilePreview
102
122
  {i18n}
103
- on:select
123
+ {onselect}
104
124
  {selectable}
105
125
  {value}
106
126
  {height}
107
- on:change
108
- on:delete
127
+ {onchange}
128
+ {ondelete}
109
129
  {allow_reordering}
110
130
  />
111
131
  {:else}
112
132
  <Upload
113
133
  bind:upload_promise
114
- on:load={handle_upload}
134
+ onload={handle_upload}
115
135
  filetype={file_types}
116
136
  {file_count}
117
137
  {max_file_size}
118
138
  {root}
119
139
  bind:dragging
120
140
  bind:uploading
121
- on:error
141
+ {onerror}
122
142
  {stream_handler}
123
143
  {upload}
124
144
  {height}
package/types.ts CHANGED
@@ -21,6 +21,6 @@ export interface FileEvents {
21
21
  clear: void;
22
22
  select: SelectData | null;
23
23
  change: FileData | FileData[] | null;
24
- delete: void;
24
+ delete: FileData;
25
25
  custom_button_click: { id: number };
26
26
  }