@gradio/gallery 0.12.1 → 0.13.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/gallery",
3
- "version": "0.12.1",
3
+ "version": "0.13.0-beta.1",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -8,24 +8,36 @@
8
8
  "private": false,
9
9
  "dependencies": {
10
10
  "dequal": "^2.0.2",
11
- "@gradio/atoms": "^0.8.0",
12
- "@gradio/client": "^1.5.1",
13
- "@gradio/icons": "^0.7.1",
14
- "@gradio/image": "^0.15.0",
15
- "@gradio/upload": "^0.12.3",
16
- "@gradio/utils": "^0.6.0",
17
- "@gradio/file": "^0.9.3",
18
- "@gradio/statustracker": "^0.7.5"
11
+ "@gradio/atoms": "^0.8.1-beta.1",
12
+ "@gradio/client": "^1.6.0-beta.1",
13
+ "@gradio/image": "^0.16.0-beta.1",
14
+ "@gradio/statustracker": "^0.8.0-beta.1",
15
+ "@gradio/icons": "^0.8.0-beta.1",
16
+ "@gradio/upload": "^0.12.4-beta.1",
17
+ "@gradio/utils": "^0.7.0-beta.1",
18
+ "@gradio/video": "^0.11.0-beta.1",
19
+ "@gradio/file": "^0.9.4-beta.1"
19
20
  },
20
21
  "devDependencies": {
21
- "@gradio/preview": "^0.11.0"
22
+ "@gradio/preview": "^0.11.1-beta.0"
22
23
  },
23
24
  "main": "./Index.svelte",
24
25
  "main_changeset": true,
25
26
  "exports": {
26
- ".": "./Index.svelte",
27
+ ".": {
28
+ "gradio": "./Index.svelte",
29
+ "svelte": "./dist/Index.svelte",
30
+ "types": "./dist/Index.svelte.d.ts"
31
+ },
27
32
  "./package.json": "./package.json",
28
- "./base": "./shared/Gallery.svelte"
33
+ "./base": {
34
+ "gradio": "./shared/Gallery.svelte",
35
+ "svelte": "./dist/shared/Gallery.svelte",
36
+ "types": "./dist/shared/Gallery.svelte.d.ts"
37
+ }
38
+ },
39
+ "peerDependencies": {
40
+ "svelte": "^4.0.0"
29
41
  },
30
42
  "repository": {
31
43
  "type": "git",
@@ -3,28 +3,30 @@
3
3
  import { ModifyUpload } from "@gradio/upload";
4
4
  import type { SelectData } from "@gradio/utils";
5
5
  import { Image } from "@gradio/image/shared";
6
+ import { Video } from "@gradio/video/shared";
6
7
  import { dequal } from "dequal";
7
8
  import { createEventDispatcher, onMount } from "svelte";
8
9
  import { tick } from "svelte";
10
+ import type { GalleryImage, GalleryVideo } from "../types";
9
11
 
10
12
  import {
11
13
  Download,
12
14
  Image as ImageIcon,
13
15
  Maximize,
14
16
  Minimize,
15
- Clear
17
+ Clear,
18
+ Play
16
19
  } from "@gradio/icons";
17
20
  import { FileData } from "@gradio/client";
18
21
  import { format_gallery_for_sharing } from "./utils";
19
22
  import { IconButton } from "@gradio/atoms";
20
23
  import type { I18nFormatter } from "@gradio/utils";
21
24
 
22
- type GalleryImage = { image: FileData; caption: string | null };
23
- type GalleryData = GalleryImage[];
25
+ type GalleryData = GalleryImage | GalleryVideo;
24
26
 
25
27
  export let show_label = true;
26
28
  export let label: string;
27
- export let value: GalleryData | null = null;
29
+ export let value: GalleryData[] | null = null;
28
30
  export let columns: number | number[] | undefined = [2];
29
31
  export let rows: number | number[] | undefined = undefined;
30
32
  export let height: number | "auto" = "auto";
@@ -54,16 +56,24 @@
54
56
 
55
57
  $: was_reset = value == null || value.length === 0 ? true : was_reset;
56
58
 
57
- let resolved_value: GalleryData | null = null;
59
+ let resolved_value: GalleryData[] | null = null;
60
+
58
61
  $: resolved_value =
59
62
  value == null
60
63
  ? null
61
- : value.map((data) => ({
62
- image: data.image as FileData,
63
- caption: data.caption
64
- }));
65
-
66
- let prev_value: GalleryData | null = value;
64
+ : (value.map((data) => {
65
+ if ("video" in data) {
66
+ return {
67
+ video: data.video as FileData,
68
+ caption: data.caption
69
+ };
70
+ } else if ("image" in data) {
71
+ return { image: data.image as FileData, caption: data.caption };
72
+ }
73
+ return {};
74
+ }) as GalleryData[]);
75
+
76
+ let prev_value: GalleryData[] | null = value;
67
77
  if (selected_index == null && preview && value?.length) {
68
78
  selected_index = 0;
69
79
  }
@@ -201,7 +211,7 @@
201
211
  URL.revokeObjectURL(url);
202
212
  }
203
213
 
204
- $: selected_image =
214
+ $: selected_media =
205
215
  selected_index != null && resolved_value != null
206
216
  ? resolved_value[selected_index]
207
217
  : null;
@@ -230,7 +240,7 @@
230
240
  <Empty unpadded_box={true} size="large"><ImageIcon /></Empty>
231
241
  {:else}
232
242
  <div class="gallery-container" bind:this={gallery_container}>
233
- {#if selected_image && allow_preview}
243
+ {#if selected_media && allow_preview}
234
244
  <button
235
245
  on:keydown={on_keydown}
236
246
  class="preview"
@@ -242,7 +252,10 @@
242
252
  Icon={Download}
243
253
  label={i18n("common.download")}
244
254
  on:click={() => {
245
- const image = selected_image?.image;
255
+ const image =
256
+ "image" in selected_media
257
+ ? selected_media?.image
258
+ : selected_media?.video;
246
259
  if (image == null) {
247
260
  return;
248
261
  }
@@ -281,25 +294,40 @@
281
294
  {/if}
282
295
  </div>
283
296
  <button
284
- class="image-button"
285
- on:click={(event) => handle_preview_click(event)}
286
- style="height: calc(100% - {selected_image.caption
297
+ class="media-button"
298
+ on:click={"image" in selected_media
299
+ ? (event) => handle_preview_click(event)
300
+ : null}
301
+ style="height: calc(100% - {selected_media.caption
287
302
  ? '80px'
288
303
  : '60px'})"
289
304
  aria-label="detailed view of selected image"
290
305
  >
291
- <Image
292
- data-testid="detailed-image"
293
- src={selected_image.image.url}
294
- alt={selected_image.caption || ""}
295
- title={selected_image.caption || null}
296
- class={selected_image.caption && "with-caption"}
297
- loading="lazy"
298
- />
306
+ {#if "image" in selected_media}
307
+ <Image
308
+ data-testid="detailed-image"
309
+ src={selected_media.image.url}
310
+ alt={selected_media.caption || ""}
311
+ title={selected_media.caption || null}
312
+ class={selected_media.caption && "with-caption"}
313
+ loading="lazy"
314
+ />
315
+ {:else}
316
+ <Video
317
+ src={selected_media.video.url}
318
+ data-testid={"detailed-video"}
319
+ alt={selected_media.caption || ""}
320
+ loading="lazy"
321
+ loop={false}
322
+ is_stream={false}
323
+ muted={false}
324
+ controls={true}
325
+ />
326
+ {/if}
299
327
  </button>
300
- {#if selected_image?.caption}
328
+ {#if selected_media?.caption}
301
329
  <caption class="caption">
302
- {selected_image.caption}
330
+ {selected_media.caption}
303
331
  </caption>
304
332
  {/if}
305
333
  <div
@@ -307,7 +335,7 @@
307
335
  class="thumbnails scroll-hide"
308
336
  data-testid="container_el"
309
337
  >
310
- {#each resolved_value as image, i}
338
+ {#each resolved_value as media, i}
311
339
  <button
312
340
  bind:this={el[i]}
313
341
  on:click={() => (selected_index = i)}
@@ -318,13 +346,26 @@
318
346
  " of " +
319
347
  resolved_value.length}
320
348
  >
321
- <Image
322
- src={image.image.url}
323
- title={image.caption || null}
324
- data-testid={"thumbnail " + (i + 1)}
325
- alt=""
326
- loading="lazy"
327
- />
349
+ {#if "image" in media}
350
+ <Image
351
+ src={media.image.url}
352
+ title={media.caption || null}
353
+ data-testid={"thumbnail " + (i + 1)}
354
+ alt=""
355
+ loading="lazy"
356
+ />
357
+ {:else}
358
+ <Play />
359
+ <Video
360
+ src={media.video.url}
361
+ title={media.caption || null}
362
+ is_stream={false}
363
+ data-testid={"thumbnail " + (i + 1)}
364
+ alt=""
365
+ loading="lazy"
366
+ loop={false}
367
+ />
368
+ {/if}
328
369
  </button>
329
370
  {/each}
330
371
  </div>
@@ -347,7 +388,7 @@
347
388
  <ModifyUpload
348
389
  {i18n}
349
390
  absolute={false}
350
- on:clear={() => (value = null)}
391
+ on:clear={() => (value = [])}
351
392
  />
352
393
  </div>
353
394
  {/if}
@@ -369,13 +410,26 @@
369
410
  on:click={() => (selected_index = i)}
370
411
  aria-label={"Thumbnail " + (i + 1) + " of " + resolved_value.length}
371
412
  >
372
- <Image
373
- alt={entry.caption || ""}
374
- src={typeof entry.image === "string"
375
- ? entry.image
376
- : entry.image.url}
377
- loading="lazy"
378
- />
413
+ {#if "image" in entry}
414
+ <Image
415
+ alt={entry.caption || ""}
416
+ src={typeof entry.image === "string"
417
+ ? entry.image
418
+ : entry.image.url}
419
+ loading="lazy"
420
+ />
421
+ {:else}
422
+ <Play />
423
+ <Video
424
+ src={entry.video.url}
425
+ title={entry.caption || null}
426
+ is_stream={false}
427
+ data-testid={"thumbnail " + (i + 1)}
428
+ alt=""
429
+ loading="lazy"
430
+ loop={false}
431
+ />
432
+ {/if}
379
433
  {#if entry.caption}
380
434
  <div class="caption-label">
381
435
  {entry.caption}
@@ -440,12 +494,13 @@
440
494
  }
441
495
  }
442
496
 
443
- .image-button {
497
+ .media-button {
444
498
  height: calc(100% - 60px);
445
499
  width: 100%;
446
500
  display: flex;
447
501
  }
448
- .image-button :global(img) {
502
+ .media-button :global(img),
503
+ .media-button :global(video) {
449
504
  width: var(--size-full);
450
505
  height: var(--size-full);
451
506
  object-fit: contain;
@@ -455,6 +510,14 @@
455
510
  width: var(--size-full);
456
511
  height: var(--size-full);
457
512
  }
513
+ .thumbnails :global(svg) {
514
+ position: absolute;
515
+ top: var(--size-2);
516
+ left: var(--size-2);
517
+ width: 50%;
518
+ height: 50%;
519
+ opacity: 50%;
520
+ }
458
521
  .preview :global(img.with-caption) {
459
522
  height: var(--size-full);
460
523
  }
@@ -516,6 +579,23 @@
516
579
  border-color: var(--color-accent);
517
580
  }
518
581
 
582
+ .thumbnail-item :global(svg) {
583
+ position: absolute;
584
+ top: 50%;
585
+ left: 50%;
586
+ width: 50%;
587
+ height: 50%;
588
+ opacity: 50%;
589
+ transform: translate(-50%, -50%);
590
+ }
591
+
592
+ .thumbnail-item :global(video) {
593
+ width: var(--size-full);
594
+ height: var(--size-full);
595
+ overflow: hidden;
596
+ object-fit: cover;
597
+ }
598
+
519
599
  .thumbnail-small {
520
600
  flex: none;
521
601
  transform: scale(0.9);
@@ -523,7 +603,6 @@
523
603
  width: var(--size-9);
524
604
  height: var(--size-9);
525
605
  }
526
-
527
606
  .thumbnail-small.selected {
528
607
  --ring-color: var(--color-accent);
529
608
  transform: scale(1);
package/types.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { FileData } from "@gradio/client";
2
+
3
+ export interface GalleryImage {
4
+ image: FileData;
5
+ caption: string | null;
6
+ }
7
+
8
+ export interface GalleryVideo {
9
+ video: FileData;
10
+ caption: string | null;
11
+ }