@gradio/gallery 0.17.7 → 0.18.0
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 +36 -0
- package/Gallery.stories.svelte +0 -180
- package/Gallery.test.ts +22 -7
- package/Index.svelte +7 -5
- package/dist/Index.svelte +7 -5
- package/dist/shared/Gallery.svelte +18 -19
- package/dist/shared/utils.d.ts +2 -2
- package/dist/shared/utils.js +2 -2
- package/dist/types.d.ts +3 -2
- package/package.json +9 -9
- package/shared/Gallery.svelte +18 -19
- package/shared/utils.ts +6 -4
- package/types.ts +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @gradio/gallery
|
|
2
2
|
|
|
3
|
+
## 0.18.0
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- [#13526](https://github.com/gradio-app/gradio/pull/13526) [`53cb4ca`](https://github.com/gradio-app/gradio/commit/53cb4cae1ec3521e9170d12867253516413ba37a) - Run `pnpm lint` and `pnpm ts:check` on CI. Thanks @abidlabs!
|
|
8
|
+
|
|
9
|
+
### Dependency updates
|
|
10
|
+
|
|
11
|
+
- @gradio/atoms@0.25.0
|
|
12
|
+
- @gradio/statustracker@0.15.0
|
|
13
|
+
- @gradio/utils@0.13.0
|
|
14
|
+
- @gradio/client@2.3.0
|
|
15
|
+
- @gradio/upload@0.18.0
|
|
16
|
+
- @gradio/image@0.27.0
|
|
17
|
+
- @gradio/file@0.15.0
|
|
18
|
+
- @gradio/video@0.21.0
|
|
19
|
+
|
|
20
|
+
## 0.17.8
|
|
21
|
+
|
|
22
|
+
### Dependency updates
|
|
23
|
+
|
|
24
|
+
- @gradio/client@2.2.2
|
|
25
|
+
|
|
26
|
+
## 0.17.8
|
|
27
|
+
|
|
28
|
+
### Dependency updates
|
|
29
|
+
|
|
30
|
+
- @gradio/client@2.2.1
|
|
31
|
+
- @gradio/upload@0.17.10
|
|
32
|
+
|
|
33
|
+
## 0.17.8
|
|
34
|
+
|
|
35
|
+
### Fixes
|
|
36
|
+
|
|
37
|
+
- [#13335](https://github.com/gradio-app/gradio/pull/13335) [`953efe0`](https://github.com/gradio-app/gradio/commit/953efe06fa6d0742a9dd899b846d45fbc6ea3ccf) - Prevent Gallery Select Event From Triggering When Value Updated Programmatically. Thanks @freddyaboulton!
|
|
38
|
+
|
|
3
39
|
## 0.17.7
|
|
4
40
|
|
|
5
41
|
### Dependency updates
|
package/Gallery.stories.svelte
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
3
|
import Gallery from "./Index.svelte";
|
|
4
4
|
import { allModes } from "../storybook/modes";
|
|
5
|
-
import { within } from "@testing-library/dom";
|
|
6
|
-
import { userEvent } from "storybook/test";
|
|
7
5
|
import { wrapProps } from "../storybook/wrapProps";
|
|
8
6
|
|
|
9
7
|
const cheetah = "/cheetah.jpg";
|
|
@@ -157,15 +155,6 @@
|
|
|
157
155
|
buttons: ["fullscreen", "download", "share"],
|
|
158
156
|
sources: ["upload"]
|
|
159
157
|
}}
|
|
160
|
-
play={async ({ canvasElement }) => {
|
|
161
|
-
const canvas = within(canvasElement);
|
|
162
|
-
const image = await canvas.findByLabelText("Thumbnail 1 of 8");
|
|
163
|
-
await userEvent.click(image);
|
|
164
|
-
const expand_btn = await canvas.findByRole("button", {
|
|
165
|
-
name: "Fullscreen"
|
|
166
|
-
});
|
|
167
|
-
await userEvent.click(expand_btn);
|
|
168
|
-
}}
|
|
169
158
|
>
|
|
170
159
|
{#snippet template(args)}
|
|
171
160
|
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
@@ -186,37 +175,6 @@
|
|
|
186
175
|
{/snippet}
|
|
187
176
|
</Story>
|
|
188
177
|
|
|
189
|
-
<Story
|
|
190
|
-
name="Gallery with rows=3 and columns=3"
|
|
191
|
-
args={{
|
|
192
|
-
label: "My Cheetah Gallery",
|
|
193
|
-
show_label: true,
|
|
194
|
-
rows: 3,
|
|
195
|
-
columns: 3,
|
|
196
|
-
buttons: [],
|
|
197
|
-
sources: ["upload"]
|
|
198
|
-
}}
|
|
199
|
-
>
|
|
200
|
-
{#snippet template(args)}
|
|
201
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
202
|
-
{/snippet}
|
|
203
|
-
</Story>
|
|
204
|
-
|
|
205
|
-
<Story
|
|
206
|
-
name="Gallery with columns=4"
|
|
207
|
-
args={{
|
|
208
|
-
label: "My Cheetah Gallery",
|
|
209
|
-
show_label: true,
|
|
210
|
-
columns: 4,
|
|
211
|
-
buttons: [],
|
|
212
|
-
sources: ["upload"]
|
|
213
|
-
}}
|
|
214
|
-
>
|
|
215
|
-
{#snippet template(args)}
|
|
216
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
217
|
-
{/snippet}
|
|
218
|
-
</Story>
|
|
219
|
-
|
|
220
178
|
<Story
|
|
221
179
|
name="Gallery with height=600"
|
|
222
180
|
args={{
|
|
@@ -231,21 +189,6 @@
|
|
|
231
189
|
{/snippet}
|
|
232
190
|
</Story>
|
|
233
191
|
|
|
234
|
-
<Story
|
|
235
|
-
name="Gallery with allow_preview=false"
|
|
236
|
-
args={{
|
|
237
|
-
label: "My Cheetah Gallery",
|
|
238
|
-
show_label: true,
|
|
239
|
-
allow_preview: false,
|
|
240
|
-
buttons: [],
|
|
241
|
-
sources: ["upload"]
|
|
242
|
-
}}
|
|
243
|
-
>
|
|
244
|
-
{#snippet template(args)}
|
|
245
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
246
|
-
{/snippet}
|
|
247
|
-
</Story>
|
|
248
|
-
|
|
249
192
|
<Story
|
|
250
193
|
name="Gallery with preview"
|
|
251
194
|
args={{
|
|
@@ -261,36 +204,6 @@
|
|
|
261
204
|
{/snippet}
|
|
262
205
|
</Story>
|
|
263
206
|
|
|
264
|
-
<Story
|
|
265
|
-
name="Gallery with object_fit=scale-down"
|
|
266
|
-
args={{
|
|
267
|
-
label: "My Cheetah Gallery",
|
|
268
|
-
show_label: true,
|
|
269
|
-
object_fit: "scale-down",
|
|
270
|
-
buttons: [],
|
|
271
|
-
sources: ["upload"]
|
|
272
|
-
}}
|
|
273
|
-
>
|
|
274
|
-
{#snippet template(args)}
|
|
275
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
276
|
-
{/snippet}
|
|
277
|
-
</Story>
|
|
278
|
-
|
|
279
|
-
<Story
|
|
280
|
-
name="Gallery with object_fit=contain"
|
|
281
|
-
args={{
|
|
282
|
-
label: "My Cheetah Gallery",
|
|
283
|
-
show_label: true,
|
|
284
|
-
object_fit: "contain",
|
|
285
|
-
buttons: [],
|
|
286
|
-
sources: ["upload"]
|
|
287
|
-
}}
|
|
288
|
-
>
|
|
289
|
-
{#snippet template(args)}
|
|
290
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
291
|
-
{/snippet}
|
|
292
|
-
</Story>
|
|
293
|
-
|
|
294
207
|
<Story
|
|
295
208
|
name="Gallery with object_fit=cover"
|
|
296
209
|
args={{
|
|
@@ -306,21 +219,6 @@
|
|
|
306
219
|
{/snippet}
|
|
307
220
|
</Story>
|
|
308
221
|
|
|
309
|
-
<Story
|
|
310
|
-
name="Gallery with object_fit=none"
|
|
311
|
-
args={{
|
|
312
|
-
label: "My Cheetah Gallery",
|
|
313
|
-
show_label: true,
|
|
314
|
-
object_fit: "none",
|
|
315
|
-
buttons: [],
|
|
316
|
-
sources: ["upload"]
|
|
317
|
-
}}
|
|
318
|
-
>
|
|
319
|
-
{#snippet template(args)}
|
|
320
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
321
|
-
{/snippet}
|
|
322
|
-
</Story>
|
|
323
|
-
|
|
324
222
|
<Story
|
|
325
223
|
name="Gallery with object_fit=fill"
|
|
326
224
|
args={{
|
|
@@ -336,69 +234,6 @@
|
|
|
336
234
|
{/snippet}
|
|
337
235
|
</Story>
|
|
338
236
|
|
|
339
|
-
<Story
|
|
340
|
-
name="Gallery with share button"
|
|
341
|
-
args={{
|
|
342
|
-
label: "My Cheetah Gallery",
|
|
343
|
-
show_label: true,
|
|
344
|
-
buttons: ["share"],
|
|
345
|
-
sources: ["upload"]
|
|
346
|
-
}}
|
|
347
|
-
>
|
|
348
|
-
{#snippet template(args)}
|
|
349
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
350
|
-
{/snippet}
|
|
351
|
-
</Story>
|
|
352
|
-
|
|
353
|
-
<Story
|
|
354
|
-
name="Gallery with overflow of images"
|
|
355
|
-
args={{
|
|
356
|
-
label: "My Cheetah Gallery",
|
|
357
|
-
show_label: true,
|
|
358
|
-
rows: 2,
|
|
359
|
-
columns: 2,
|
|
360
|
-
height: 400,
|
|
361
|
-
buttons: [],
|
|
362
|
-
sources: ["upload"]
|
|
363
|
-
}}
|
|
364
|
-
>
|
|
365
|
-
{#snippet template(args)}
|
|
366
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
367
|
-
{/snippet}
|
|
368
|
-
</Story>
|
|
369
|
-
|
|
370
|
-
<Story
|
|
371
|
-
name="Gallery with overflow of images and short height"
|
|
372
|
-
args={{
|
|
373
|
-
label: "My Cheetah Gallery",
|
|
374
|
-
show_label: true,
|
|
375
|
-
rows: 2,
|
|
376
|
-
columns: 2,
|
|
377
|
-
height: 200,
|
|
378
|
-
buttons: [],
|
|
379
|
-
sources: ["upload"]
|
|
380
|
-
}}
|
|
381
|
-
>
|
|
382
|
-
{#snippet template(args)}
|
|
383
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
384
|
-
{/snippet}
|
|
385
|
-
</Story>
|
|
386
|
-
|
|
387
|
-
<Story
|
|
388
|
-
name="Gallery with download button"
|
|
389
|
-
args={{
|
|
390
|
-
label: "My Cheetah Gallery",
|
|
391
|
-
rows: 2,
|
|
392
|
-
height: 400,
|
|
393
|
-
buttons: ["download"],
|
|
394
|
-
sources: ["upload"]
|
|
395
|
-
}}
|
|
396
|
-
>
|
|
397
|
-
{#snippet template(args)}
|
|
398
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
399
|
-
{/snippet}
|
|
400
|
-
</Story>
|
|
401
|
-
|
|
402
237
|
<Story
|
|
403
238
|
name="Gallery with fit_columns false"
|
|
404
239
|
args={{
|
|
@@ -413,18 +248,3 @@
|
|
|
413
248
|
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
414
249
|
{/snippet}
|
|
415
250
|
</Story>
|
|
416
|
-
|
|
417
|
-
<Story
|
|
418
|
-
name="Gallery with fit_columns true"
|
|
419
|
-
args={{
|
|
420
|
-
label: "My Cheetah Gallery",
|
|
421
|
-
columns: 10,
|
|
422
|
-
buttons: ["download"],
|
|
423
|
-
fit_columns: true,
|
|
424
|
-
sources: ["upload"]
|
|
425
|
-
}}
|
|
426
|
-
>
|
|
427
|
-
{#snippet template(args)}
|
|
428
|
-
<Gallery {...wrapProps({ value: galleryValue, ...args })} />
|
|
429
|
-
{/snippet}
|
|
430
|
-
</Story>
|
package/Gallery.test.ts
CHANGED
|
@@ -627,7 +627,7 @@ describe("Events: select", () => {
|
|
|
627
627
|
expect(select).toHaveBeenCalledWith(expect.objectContaining({ index: 1 }));
|
|
628
628
|
});
|
|
629
629
|
|
|
630
|
-
test("select: fired when selected_index changes via set_data", async () => {
|
|
630
|
+
test("select: not fired when selected_index changes via set_data", async () => {
|
|
631
631
|
const { listen, set_data } = await render(Gallery, {
|
|
632
632
|
...default_props,
|
|
633
633
|
preview: true,
|
|
@@ -639,8 +639,25 @@ describe("Events: select", () => {
|
|
|
639
639
|
|
|
640
640
|
await set_data({ selected_index: 2 });
|
|
641
641
|
|
|
642
|
-
expect(select).toHaveBeenCalled();
|
|
643
|
-
|
|
642
|
+
expect(select).not.toHaveBeenCalled();
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
test("select: not fired when value and selected_index update together via set_data", async () => {
|
|
646
|
+
const { listen, set_data } = await render(Gallery, {
|
|
647
|
+
...default_props,
|
|
648
|
+
preview: true,
|
|
649
|
+
selected_index: 0,
|
|
650
|
+
value: [img("a"), img("b")]
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
const select = listen("select");
|
|
654
|
+
|
|
655
|
+
await set_data({
|
|
656
|
+
value: [img("a"), img("b"), img("c")],
|
|
657
|
+
selected_index: 2
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
expect(select).not.toHaveBeenCalled();
|
|
644
661
|
});
|
|
645
662
|
});
|
|
646
663
|
|
|
@@ -976,7 +993,7 @@ describe("Regression: #13170 — selected_index points to newly appended image",
|
|
|
976
993
|
expect(preview_img.src).toBe("https://example.com/img3.png");
|
|
977
994
|
});
|
|
978
995
|
|
|
979
|
-
test("selected_index pointing to newly appended item
|
|
996
|
+
test("selected_index pointing to newly appended item does not dispatch select", async () => {
|
|
980
997
|
const initial_value = [img("a"), img("b")];
|
|
981
998
|
|
|
982
999
|
const { set_data, listen } = await render(Gallery, {
|
|
@@ -993,9 +1010,7 @@ describe("Regression: #13170 — selected_index points to newly appended image",
|
|
|
993
1010
|
selected_index: 2
|
|
994
1011
|
});
|
|
995
1012
|
|
|
996
|
-
expect(select).toHaveBeenCalled();
|
|
997
|
-
const last_call = select.mock.calls[select.mock.calls.length - 1][0];
|
|
998
|
-
expect(last_call.index).toBe(2);
|
|
1013
|
+
expect(select).not.toHaveBeenCalled();
|
|
999
1014
|
});
|
|
1000
1015
|
|
|
1001
1016
|
test("rapidly appending images with selected_index tracking last always shows the latest", async () => {
|
package/Index.svelte
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const props = $props();
|
|
33
|
-
const gradio = new GalleryGradio
|
|
33
|
+
const gradio = new GalleryGradio(props, {
|
|
34
34
|
selected_index: null,
|
|
35
35
|
file_types: ["image", "video"]
|
|
36
36
|
});
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
gradio.dispatch("upload", gradio.props.value);
|
|
193
193
|
gradio.dispatch("change", gradio.props.value);
|
|
194
194
|
}}
|
|
195
|
-
onerror={(
|
|
195
|
+
onerror={(detail) => {
|
|
196
196
|
gradio.shared.loading_status = gradio.shared.loading_status || {};
|
|
197
197
|
gradio.shared.loading_status.status = "error";
|
|
198
198
|
gradio.dispatch("error", detail);
|
|
@@ -206,6 +206,7 @@
|
|
|
206
206
|
root={gradio.shared.root}
|
|
207
207
|
value={null}
|
|
208
208
|
on:capture={async (e) => {
|
|
209
|
+
if (!(e.detail instanceof Blob)) return;
|
|
209
210
|
const f = await handle_save(
|
|
210
211
|
e.detail,
|
|
211
212
|
(f) => gradio.shared.client.upload(f, gradio.shared.root),
|
|
@@ -231,7 +232,8 @@
|
|
|
231
232
|
root={gradio.shared.root}
|
|
232
233
|
value={null}
|
|
233
234
|
on:capture={async (e) => {
|
|
234
|
-
|
|
235
|
+
if (!e.detail) return;
|
|
236
|
+
const f = { ...(e.detail as FileData) };
|
|
235
237
|
f.mime_type = "video/webm";
|
|
236
238
|
const processed_files = await process_upload_files([f]);
|
|
237
239
|
gradio.props.value?.push(...processed_files);
|
|
@@ -254,7 +256,7 @@
|
|
|
254
256
|
{sources}
|
|
255
257
|
bind:active_source
|
|
256
258
|
handle_clear={() => gradio.dispatch("clear")}
|
|
257
|
-
handle_select={handle_select_source}
|
|
259
|
+
handle_select={(source) => handle_select_source(source as any)}
|
|
258
260
|
/>
|
|
259
261
|
{/if}
|
|
260
262
|
{:else}
|
|
@@ -282,7 +284,7 @@
|
|
|
282
284
|
gradio.dispatch("change", gradio.props.value);
|
|
283
285
|
}}
|
|
284
286
|
{sources}
|
|
285
|
-
{onsource_change}
|
|
287
|
+
onsource_change={(source) => onsource_change(source as any)}
|
|
286
288
|
label={gradio.shared.label}
|
|
287
289
|
show_label={gradio.shared.show_label}
|
|
288
290
|
columns={gradio.props.columns}
|
package/dist/Index.svelte
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const props = $props();
|
|
33
|
-
const gradio = new GalleryGradio
|
|
33
|
+
const gradio = new GalleryGradio(props, {
|
|
34
34
|
selected_index: null,
|
|
35
35
|
file_types: ["image", "video"]
|
|
36
36
|
});
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
gradio.dispatch("upload", gradio.props.value);
|
|
193
193
|
gradio.dispatch("change", gradio.props.value);
|
|
194
194
|
}}
|
|
195
|
-
onerror={(
|
|
195
|
+
onerror={(detail) => {
|
|
196
196
|
gradio.shared.loading_status = gradio.shared.loading_status || {};
|
|
197
197
|
gradio.shared.loading_status.status = "error";
|
|
198
198
|
gradio.dispatch("error", detail);
|
|
@@ -206,6 +206,7 @@
|
|
|
206
206
|
root={gradio.shared.root}
|
|
207
207
|
value={null}
|
|
208
208
|
on:capture={async (e) => {
|
|
209
|
+
if (!(e.detail instanceof Blob)) return;
|
|
209
210
|
const f = await handle_save(
|
|
210
211
|
e.detail,
|
|
211
212
|
(f) => gradio.shared.client.upload(f, gradio.shared.root),
|
|
@@ -231,7 +232,8 @@
|
|
|
231
232
|
root={gradio.shared.root}
|
|
232
233
|
value={null}
|
|
233
234
|
on:capture={async (e) => {
|
|
234
|
-
|
|
235
|
+
if (!e.detail) return;
|
|
236
|
+
const f = { ...(e.detail as FileData) };
|
|
235
237
|
f.mime_type = "video/webm";
|
|
236
238
|
const processed_files = await process_upload_files([f]);
|
|
237
239
|
gradio.props.value?.push(...processed_files);
|
|
@@ -254,7 +256,7 @@
|
|
|
254
256
|
{sources}
|
|
255
257
|
bind:active_source
|
|
256
258
|
handle_clear={() => gradio.dispatch("clear")}
|
|
257
|
-
handle_select={handle_select_source}
|
|
259
|
+
handle_select={(source) => handle_select_source(source as any)}
|
|
258
260
|
/>
|
|
259
261
|
{/if}
|
|
260
262
|
{:else}
|
|
@@ -282,7 +284,7 @@
|
|
|
282
284
|
gradio.dispatch("change", gradio.props.value);
|
|
283
285
|
}}
|
|
284
286
|
{sources}
|
|
285
|
-
{onsource_change}
|
|
287
|
+
onsource_change={(source) => onsource_change(source as any)}
|
|
286
288
|
label={gradio.shared.label}
|
|
287
289
|
show_label={gradio.shared.show_label}
|
|
288
290
|
columns={gradio.props.columns}
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
} = $props();
|
|
113
113
|
|
|
114
114
|
let upload_promise: Promise<any> | null = null;
|
|
115
|
-
let mode
|
|
115
|
+
let mode = $state<"normal" | "minimal">("normal");
|
|
116
116
|
let display_icon_button_wrapper_top_corner = false;
|
|
117
117
|
let is_full_screen = false;
|
|
118
118
|
let image_container: HTMLElement;
|
|
@@ -160,7 +160,6 @@
|
|
|
160
160
|
if (selected_index == null && preview && value?.length) {
|
|
161
161
|
selected_index = 0;
|
|
162
162
|
}
|
|
163
|
-
let old_selected_index: number | null = $state(selected_index);
|
|
164
163
|
|
|
165
164
|
$effect(() => {
|
|
166
165
|
if (!dequal(prev_value, value)) {
|
|
@@ -195,6 +194,15 @@
|
|
|
195
194
|
() => ((selected_index ?? 0) + 1) % (resolved_value?.length ?? 0)
|
|
196
195
|
);
|
|
197
196
|
|
|
197
|
+
function dispatch_select(index: number): void {
|
|
198
|
+
if (resolved_value !== null) {
|
|
199
|
+
onselect({
|
|
200
|
+
index,
|
|
201
|
+
value: resolved_value?.[index]
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
198
206
|
function handle_preview_click(event: MouseEvent): void {
|
|
199
207
|
const element = event.target as HTMLElement;
|
|
200
208
|
const x = event.offsetX;
|
|
@@ -206,6 +214,7 @@
|
|
|
206
214
|
} else {
|
|
207
215
|
selected_index = next;
|
|
208
216
|
}
|
|
217
|
+
dispatch_select(selected_index);
|
|
209
218
|
}
|
|
210
219
|
|
|
211
220
|
function on_keydown(e: KeyboardEvent): void {
|
|
@@ -218,32 +227,18 @@
|
|
|
218
227
|
case "ArrowLeft":
|
|
219
228
|
e.preventDefault();
|
|
220
229
|
selected_index = previous;
|
|
230
|
+
dispatch_select(selected_index);
|
|
221
231
|
break;
|
|
222
232
|
case "ArrowRight":
|
|
223
233
|
e.preventDefault();
|
|
224
234
|
selected_index = next;
|
|
235
|
+
dispatch_select(selected_index);
|
|
225
236
|
break;
|
|
226
237
|
default:
|
|
227
238
|
break;
|
|
228
239
|
}
|
|
229
240
|
}
|
|
230
241
|
|
|
231
|
-
$effect(() => {
|
|
232
|
-
// Only trigger the effect if the selected_index has actually changed
|
|
233
|
-
if (selected_index !== old_selected_index) {
|
|
234
|
-
old_selected_index = selected_index;
|
|
235
|
-
|
|
236
|
-
// Ensure we have a valid selection and data to work with
|
|
237
|
-
if (selected_index !== null && resolved_value !== null) {
|
|
238
|
-
// Notify the parent component or listener about the updated selection
|
|
239
|
-
onselect({
|
|
240
|
-
index: selected_index,
|
|
241
|
-
value: resolved_value?.[selected_index]
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
|
|
247
242
|
$effect(() => {
|
|
248
243
|
if (allow_preview && container_element) {
|
|
249
244
|
scroll_to_img(selected_index);
|
|
@@ -495,7 +490,10 @@
|
|
|
495
490
|
{#each resolved_value as media, i}
|
|
496
491
|
<button
|
|
497
492
|
bind:this={el[i]}
|
|
498
|
-
on:click={() =>
|
|
493
|
+
on:click={() => {
|
|
494
|
+
selected_index = i;
|
|
495
|
+
dispatch_select(i);
|
|
496
|
+
}}
|
|
499
497
|
class="thumbnail-item thumbnail-small"
|
|
500
498
|
class:selected={selected_index === i && mode !== "minimal"}
|
|
501
499
|
aria-label={"Thumbnail " +
|
|
@@ -616,6 +614,7 @@
|
|
|
616
614
|
onpreview_open();
|
|
617
615
|
}
|
|
618
616
|
selected_index = i;
|
|
617
|
+
dispatch_select(i);
|
|
619
618
|
}}
|
|
620
619
|
aria-label={"Thumbnail " +
|
|
621
620
|
(i + 1) +
|
package/dist/shared/utils.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { FileData
|
|
1
|
+
import { FileData } from "@gradio/client";
|
|
2
2
|
export declare function format_gallery_for_sharing(value: [FileData, string | null][] | null): Promise<string>;
|
|
3
|
-
export declare function handle_save(img_blob: Blob, upload:
|
|
3
|
+
export declare function handle_save(img_blob: Blob, upload: (files: FileData[]) => Promise<(FileData | null)[] | null>, filename?: string): Promise<FileData[]>;
|
package/dist/shared/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { uploadToHuggingFace } from "@gradio/utils";
|
|
2
|
-
import { FileData
|
|
2
|
+
import { FileData } from "@gradio/client";
|
|
3
3
|
export async function format_gallery_for_sharing(value) {
|
|
4
4
|
if (!value)
|
|
5
5
|
return "";
|
|
@@ -25,5 +25,5 @@ export async function handle_save(img_blob, upload, filename = "uploaded_file")
|
|
|
25
25
|
is_stream: false
|
|
26
26
|
})
|
|
27
27
|
];
|
|
28
|
-
return (await upload(
|
|
28
|
+
return ((await upload(files)) ?? []).filter((file) => file !== null);
|
|
29
29
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { FileData
|
|
2
|
-
import type { CustomButton } from "@gradio/utils";
|
|
1
|
+
import type { FileData } from "@gradio/client";
|
|
2
|
+
import type { CustomButton, SelectData } from "@gradio/utils";
|
|
3
3
|
export interface GalleryImage {
|
|
4
4
|
image: FileData;
|
|
5
5
|
caption: string | null;
|
|
@@ -34,6 +34,7 @@ export interface GalleryEvents {
|
|
|
34
34
|
};
|
|
35
35
|
preview_open: never;
|
|
36
36
|
preview_close: never;
|
|
37
|
+
clear: never;
|
|
37
38
|
clear_status: any;
|
|
38
39
|
share: any;
|
|
39
40
|
error: any;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/gallery",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
"private": false,
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"dequal": "^2.0.3",
|
|
11
|
-
"@gradio/atoms": "^0.
|
|
12
|
-
"@gradio/
|
|
11
|
+
"@gradio/atoms": "^0.25.0",
|
|
12
|
+
"@gradio/file": "^0.15.0",
|
|
13
13
|
"@gradio/icons": "^0.15.1",
|
|
14
|
-
"@gradio/
|
|
15
|
-
"@gradio/
|
|
16
|
-
"@gradio/
|
|
17
|
-
"@gradio/
|
|
18
|
-
"@gradio/
|
|
19
|
-
"@gradio/
|
|
14
|
+
"@gradio/client": "^2.3.0",
|
|
15
|
+
"@gradio/image": "^0.27.0",
|
|
16
|
+
"@gradio/statustracker": "^0.15.0",
|
|
17
|
+
"@gradio/utils": "^0.13.0",
|
|
18
|
+
"@gradio/upload": "^0.18.0",
|
|
19
|
+
"@gradio/video": "^0.21.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@gradio/preview": "^0.16.2"
|
package/shared/Gallery.svelte
CHANGED
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
} = $props();
|
|
113
113
|
|
|
114
114
|
let upload_promise: Promise<any> | null = null;
|
|
115
|
-
let mode
|
|
115
|
+
let mode = $state<"normal" | "minimal">("normal");
|
|
116
116
|
let display_icon_button_wrapper_top_corner = false;
|
|
117
117
|
let is_full_screen = false;
|
|
118
118
|
let image_container: HTMLElement;
|
|
@@ -160,7 +160,6 @@
|
|
|
160
160
|
if (selected_index == null && preview && value?.length) {
|
|
161
161
|
selected_index = 0;
|
|
162
162
|
}
|
|
163
|
-
let old_selected_index: number | null = $state(selected_index);
|
|
164
163
|
|
|
165
164
|
$effect(() => {
|
|
166
165
|
if (!dequal(prev_value, value)) {
|
|
@@ -195,6 +194,15 @@
|
|
|
195
194
|
() => ((selected_index ?? 0) + 1) % (resolved_value?.length ?? 0)
|
|
196
195
|
);
|
|
197
196
|
|
|
197
|
+
function dispatch_select(index: number): void {
|
|
198
|
+
if (resolved_value !== null) {
|
|
199
|
+
onselect({
|
|
200
|
+
index,
|
|
201
|
+
value: resolved_value?.[index]
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
198
206
|
function handle_preview_click(event: MouseEvent): void {
|
|
199
207
|
const element = event.target as HTMLElement;
|
|
200
208
|
const x = event.offsetX;
|
|
@@ -206,6 +214,7 @@
|
|
|
206
214
|
} else {
|
|
207
215
|
selected_index = next;
|
|
208
216
|
}
|
|
217
|
+
dispatch_select(selected_index);
|
|
209
218
|
}
|
|
210
219
|
|
|
211
220
|
function on_keydown(e: KeyboardEvent): void {
|
|
@@ -218,32 +227,18 @@
|
|
|
218
227
|
case "ArrowLeft":
|
|
219
228
|
e.preventDefault();
|
|
220
229
|
selected_index = previous;
|
|
230
|
+
dispatch_select(selected_index);
|
|
221
231
|
break;
|
|
222
232
|
case "ArrowRight":
|
|
223
233
|
e.preventDefault();
|
|
224
234
|
selected_index = next;
|
|
235
|
+
dispatch_select(selected_index);
|
|
225
236
|
break;
|
|
226
237
|
default:
|
|
227
238
|
break;
|
|
228
239
|
}
|
|
229
240
|
}
|
|
230
241
|
|
|
231
|
-
$effect(() => {
|
|
232
|
-
// Only trigger the effect if the selected_index has actually changed
|
|
233
|
-
if (selected_index !== old_selected_index) {
|
|
234
|
-
old_selected_index = selected_index;
|
|
235
|
-
|
|
236
|
-
// Ensure we have a valid selection and data to work with
|
|
237
|
-
if (selected_index !== null && resolved_value !== null) {
|
|
238
|
-
// Notify the parent component or listener about the updated selection
|
|
239
|
-
onselect({
|
|
240
|
-
index: selected_index,
|
|
241
|
-
value: resolved_value?.[selected_index]
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
|
|
247
242
|
$effect(() => {
|
|
248
243
|
if (allow_preview && container_element) {
|
|
249
244
|
scroll_to_img(selected_index);
|
|
@@ -495,7 +490,10 @@
|
|
|
495
490
|
{#each resolved_value as media, i}
|
|
496
491
|
<button
|
|
497
492
|
bind:this={el[i]}
|
|
498
|
-
on:click={() =>
|
|
493
|
+
on:click={() => {
|
|
494
|
+
selected_index = i;
|
|
495
|
+
dispatch_select(i);
|
|
496
|
+
}}
|
|
499
497
|
class="thumbnail-item thumbnail-small"
|
|
500
498
|
class:selected={selected_index === i && mode !== "minimal"}
|
|
501
499
|
aria-label={"Thumbnail " +
|
|
@@ -616,6 +614,7 @@
|
|
|
616
614
|
onpreview_open();
|
|
617
615
|
}
|
|
618
616
|
selected_index = i;
|
|
617
|
+
dispatch_select(i);
|
|
619
618
|
}}
|
|
620
619
|
aria-label={"Thumbnail " +
|
|
621
620
|
(i + 1) +
|
package/shared/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { uploadToHuggingFace } from "@gradio/utils";
|
|
2
|
-
import { FileData
|
|
2
|
+
import { FileData } from "@gradio/client";
|
|
3
3
|
|
|
4
4
|
export async function format_gallery_for_sharing(
|
|
5
5
|
value: [FileData, string | null][] | null
|
|
@@ -19,8 +19,8 @@ export async function format_gallery_for_sharing(
|
|
|
19
19
|
|
|
20
20
|
export async function handle_save(
|
|
21
21
|
img_blob: Blob,
|
|
22
|
-
upload:
|
|
23
|
-
filename
|
|
22
|
+
upload: (files: FileData[]) => Promise<(FileData | null)[] | null>,
|
|
23
|
+
filename = "uploaded_file"
|
|
24
24
|
): Promise<FileData[]> {
|
|
25
25
|
const ext = img_blob.type.split("/")[1] || "png";
|
|
26
26
|
const f_ = new File([img_blob], `${filename}.${ext}`);
|
|
@@ -34,5 +34,7 @@ export async function handle_save(
|
|
|
34
34
|
is_stream: false
|
|
35
35
|
})
|
|
36
36
|
];
|
|
37
|
-
return (await upload(
|
|
37
|
+
return ((await upload(files)) ?? []).filter(
|
|
38
|
+
(file): file is FileData => file !== null
|
|
39
|
+
);
|
|
38
40
|
}
|
package/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { FileData
|
|
2
|
-
import type { CustomButton } from "@gradio/utils";
|
|
1
|
+
import type { FileData } from "@gradio/client";
|
|
2
|
+
import type { CustomButton, SelectData } from "@gradio/utils";
|
|
3
3
|
|
|
4
4
|
export interface GalleryImage {
|
|
5
5
|
image: FileData;
|
|
@@ -36,6 +36,7 @@ export interface GalleryEvents {
|
|
|
36
36
|
delete: { file: FileData; index: number };
|
|
37
37
|
preview_open: never;
|
|
38
38
|
preview_close: never;
|
|
39
|
+
clear: never;
|
|
39
40
|
clear_status: any;
|
|
40
41
|
share: any;
|
|
41
42
|
error: any;
|