@gradio/gallery 0.12.0 → 0.12.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,39 @@
1
1
  # @gradio/gallery
2
2
 
3
+ ## 0.12.2
4
+
5
+ ### Fixes
6
+
7
+ - [#9163](https://github.com/gradio-app/gradio/pull/9163) [`2b6cbf2`](https://github.com/gradio-app/gradio/commit/2b6cbf25908e42cf027324e54ef2cc0baad11a91) - fix exports and generate types. Thanks @pngwn!
8
+
9
+ ### Dependency updates
10
+
11
+ - @gradio/utils@0.6.1
12
+ - @gradio/statustracker@0.7.6
13
+ - @gradio/atoms@0.8.1
14
+ - @gradio/icons@0.7.2
15
+ - @gradio/client@1.5.2
16
+ - @gradio/upload@0.12.4
17
+ - @gradio/image@0.15.1
18
+ - @gradio/file@0.9.4
19
+
20
+ ## 0.12.1
21
+
22
+ ### Features
23
+
24
+ - [#9118](https://github.com/gradio-app/gradio/pull/9118) [`e1c404d`](https://github.com/gradio-app/gradio/commit/e1c404da1143fb52b659d03e028bdba1badf443d) - setup npm-previews of all packages. Thanks @pngwn!
25
+
26
+ ### Dependency updates
27
+
28
+ - @gradio/utils@0.6.0
29
+ - @gradio/upload@0.12.3
30
+ - @gradio/atoms@0.8.0
31
+ - @gradio/client@1.5.1
32
+ - @gradio/statustracker@0.7.5
33
+ - @gradio/icons@0.7.1
34
+ - @gradio/image@0.15.0
35
+ - @gradio/file@0.9.3
36
+
3
37
  ## 0.12.0
4
38
 
5
39
  ### Features
package/Gallery.test.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { test, describe, assert, afterEach, vi } from "vitest";
2
- import { cleanup, render } from "@gradio/tootils";
3
- import { setupi18n } from "../app/src/i18n";
2
+ import { cleanup, render } from "@self/tootils";
3
+ import { setupi18n } from "../core/src/i18n";
4
4
 
5
5
  import Gallery from "./Index.svelte";
6
6
  import type { LoadingStatus } from "@gradio/statustracker";
@@ -0,0 +1,105 @@
1
+ <script context="module">export { default as BaseGallery } from "./shared/Gallery.svelte";
2
+ </script>
3
+
4
+ <script>import { Block, UploadText } from "@gradio/atoms";
5
+ import Gallery from "./shared/Gallery.svelte";
6
+ import { StatusTracker } from "@gradio/statustracker";
7
+ import { createEventDispatcher } from "svelte";
8
+ import { BaseFileUpload } from "@gradio/file";
9
+ export let loading_status;
10
+ export let show_label;
11
+ export let label;
12
+ export let root;
13
+ export let elem_id = "";
14
+ export let elem_classes = [];
15
+ export let visible = true;
16
+ export let value = null;
17
+ export let container = true;
18
+ export let scale = null;
19
+ export let min_width = void 0;
20
+ export let columns = [2];
21
+ export let rows = void 0;
22
+ export let height = "auto";
23
+ export let preview;
24
+ export let allow_preview = true;
25
+ export let selected_index = null;
26
+ export let object_fit = "cover";
27
+ export let show_share_button = false;
28
+ export let interactive;
29
+ export let show_download_button = false;
30
+ export let gradio;
31
+ export let show_fullscreen_button = true;
32
+ const dispatch = createEventDispatcher();
33
+ $:
34
+ no_value = Array.isArray(value) ? value.length === 0 : !value;
35
+ $:
36
+ selected_index, dispatch("prop_change", { selected_index });
37
+ </script>
38
+
39
+ <Block
40
+ {visible}
41
+ variant="solid"
42
+ padding={false}
43
+ {elem_id}
44
+ {elem_classes}
45
+ {container}
46
+ {scale}
47
+ {min_width}
48
+ allow_overflow={false}
49
+ height={typeof height === "number" ? height : undefined}
50
+ >
51
+ <StatusTracker
52
+ autoscroll={gradio.autoscroll}
53
+ i18n={gradio.i18n}
54
+ {...loading_status}
55
+ on:clear_status={() => gradio.dispatch("clear_status", loading_status)}
56
+ />
57
+ {#if interactive && no_value}
58
+ <BaseFileUpload
59
+ value={null}
60
+ {root}
61
+ {label}
62
+ max_file_size={gradio.max_file_size}
63
+ file_count={"multiple"}
64
+ file_types={["image"]}
65
+ i18n={gradio.i18n}
66
+ upload={gradio.client.upload}
67
+ stream_handler={gradio.client.stream}
68
+ on:upload={(e) => {
69
+ const files = Array.isArray(e.detail) ? e.detail : [e.detail];
70
+ value = files.map((x) => ({ image: x, caption: null }));
71
+ gradio.dispatch("upload", value);
72
+ }}
73
+ on:error={({ detail }) => {
74
+ loading_status = loading_status || {};
75
+ loading_status.status = "error";
76
+ gradio.dispatch("error", detail);
77
+ }}
78
+ >
79
+ <UploadText i18n={gradio.i18n} type="gallery" />
80
+ </BaseFileUpload>
81
+ {:else}
82
+ <Gallery
83
+ on:change={() => gradio.dispatch("change", value)}
84
+ on:select={(e) => gradio.dispatch("select", e.detail)}
85
+ on:share={(e) => gradio.dispatch("share", e.detail)}
86
+ on:error={(e) => gradio.dispatch("error", e.detail)}
87
+ {label}
88
+ {show_label}
89
+ {columns}
90
+ {rows}
91
+ {height}
92
+ {preview}
93
+ {object_fit}
94
+ {interactive}
95
+ {allow_preview}
96
+ bind:selected_index
97
+ bind:value
98
+ {show_share_button}
99
+ {show_download_button}
100
+ i18n={gradio.i18n}
101
+ _fetch={gradio.client.fetch}
102
+ {show_fullscreen_button}
103
+ />
104
+ {/if}
105
+ </Block>
@@ -0,0 +1,60 @@
1
+ import { SvelteComponent } from "svelte";
2
+ export { default as BaseGallery } from "./shared/Gallery.svelte";
3
+ import type { Gradio, ShareData, SelectData } from "@gradio/utils";
4
+ import type { LoadingStatus } from "@gradio/statustracker";
5
+ import type { FileData } from "@gradio/client";
6
+ declare const __propDef: {
7
+ props: {
8
+ loading_status: LoadingStatus;
9
+ show_label: boolean;
10
+ label: string;
11
+ root: string;
12
+ elem_id?: string | undefined;
13
+ elem_classes?: string[] | undefined;
14
+ visible?: boolean | undefined;
15
+ value?: ({
16
+ image: FileData;
17
+ caption: string | null;
18
+ }[] | null) | undefined;
19
+ container?: boolean | undefined;
20
+ scale?: (number | null) | undefined;
21
+ min_width?: number | undefined;
22
+ columns?: number | number[] | undefined;
23
+ rows?: number | number[] | undefined;
24
+ height?: (number | "auto") | undefined;
25
+ preview: boolean;
26
+ allow_preview?: boolean | undefined;
27
+ selected_index?: (number | null) | undefined;
28
+ object_fit?: ("contain" | "cover" | "fill" | "none" | "scale-down") | undefined;
29
+ show_share_button?: boolean | undefined;
30
+ interactive: boolean;
31
+ show_download_button?: boolean | undefined;
32
+ gradio: Gradio<{
33
+ change: {
34
+ image: FileData;
35
+ caption: string | null;
36
+ }[] | null;
37
+ upload: {
38
+ image: FileData;
39
+ caption: string | null;
40
+ }[] | null;
41
+ select: SelectData;
42
+ share: ShareData;
43
+ error: string;
44
+ prop_change: Record<string, any>;
45
+ clear_status: LoadingStatus;
46
+ }>;
47
+ show_fullscreen_button?: boolean | undefined;
48
+ };
49
+ events: {
50
+ prop_change: CustomEvent<any>;
51
+ } & {
52
+ [evt: string]: CustomEvent<any>;
53
+ };
54
+ slots: {};
55
+ };
56
+ export type IndexProps = typeof __propDef.props;
57
+ export type IndexEvents = typeof __propDef.events;
58
+ export type IndexSlots = typeof __propDef.slots;
59
+ export default class Index extends SvelteComponent<IndexProps, IndexEvents, IndexSlots> {
60
+ }
@@ -0,0 +1,546 @@
1
+ <script>import { BlockLabel, Empty, ShareButton } from "@gradio/atoms";
2
+ import { ModifyUpload } from "@gradio/upload";
3
+ import { Image } from "@gradio/image/shared";
4
+ import { dequal } from "dequal";
5
+ import { createEventDispatcher, onMount } from "svelte";
6
+ import { tick } from "svelte";
7
+ import {
8
+ Download,
9
+ Image as ImageIcon,
10
+ Maximize,
11
+ Minimize,
12
+ Clear
13
+ } from "@gradio/icons";
14
+ import { FileData } from "@gradio/client";
15
+ import { format_gallery_for_sharing } from "./utils";
16
+ import { IconButton } from "@gradio/atoms";
17
+ export let show_label = true;
18
+ export let label;
19
+ export let value = null;
20
+ export let columns = [2];
21
+ export let rows = void 0;
22
+ export let height = "auto";
23
+ export let preview;
24
+ export let allow_preview = true;
25
+ export let object_fit = "cover";
26
+ export let show_share_button = false;
27
+ export let show_download_button = false;
28
+ export let i18n;
29
+ export let selected_index = null;
30
+ export let interactive;
31
+ export let _fetch;
32
+ export let mode = "normal";
33
+ export let show_fullscreen_button = true;
34
+ let is_full_screen = false;
35
+ let gallery_container;
36
+ const dispatch = createEventDispatcher();
37
+ let was_reset = true;
38
+ $:
39
+ was_reset = value == null || value.length === 0 ? true : was_reset;
40
+ let resolved_value = null;
41
+ $:
42
+ resolved_value = value == null ? null : value.map((data) => ({
43
+ image: data.image,
44
+ caption: data.caption
45
+ }));
46
+ let prev_value = value;
47
+ if (selected_index == null && preview && value?.length) {
48
+ selected_index = 0;
49
+ }
50
+ let old_selected_index = selected_index;
51
+ $:
52
+ if (!dequal(prev_value, value)) {
53
+ if (was_reset) {
54
+ selected_index = preview && value?.length ? 0 : null;
55
+ was_reset = false;
56
+ } else {
57
+ selected_index = selected_index != null && value != null && selected_index < value.length ? selected_index : null;
58
+ }
59
+ dispatch("change");
60
+ prev_value = value;
61
+ }
62
+ $:
63
+ previous = ((selected_index ?? 0) + (resolved_value?.length ?? 0) - 1) % (resolved_value?.length ?? 0);
64
+ $:
65
+ next = ((selected_index ?? 0) + 1) % (resolved_value?.length ?? 0);
66
+ function handle_preview_click(event) {
67
+ const element = event.target;
68
+ const x = event.offsetX;
69
+ const width = element.offsetWidth;
70
+ const centerX = width / 2;
71
+ if (x < centerX) {
72
+ selected_index = previous;
73
+ } else {
74
+ selected_index = next;
75
+ }
76
+ }
77
+ function on_keydown(e) {
78
+ switch (e.code) {
79
+ case "Escape":
80
+ e.preventDefault();
81
+ selected_index = null;
82
+ break;
83
+ case "ArrowLeft":
84
+ e.preventDefault();
85
+ selected_index = previous;
86
+ break;
87
+ case "ArrowRight":
88
+ e.preventDefault();
89
+ selected_index = next;
90
+ break;
91
+ default:
92
+ break;
93
+ }
94
+ }
95
+ $: {
96
+ if (selected_index !== old_selected_index) {
97
+ old_selected_index = selected_index;
98
+ if (selected_index !== null) {
99
+ dispatch("select", {
100
+ index: selected_index,
101
+ value: resolved_value?.[selected_index]
102
+ });
103
+ }
104
+ }
105
+ }
106
+ $:
107
+ if (allow_preview) {
108
+ scroll_to_img(selected_index);
109
+ }
110
+ let el = [];
111
+ let container_element;
112
+ async function scroll_to_img(index) {
113
+ if (typeof index !== "number")
114
+ return;
115
+ await tick();
116
+ if (el[index] === void 0)
117
+ return;
118
+ el[index]?.focus();
119
+ const { left: container_left, width: container_width } = container_element.getBoundingClientRect();
120
+ const { left, width } = el[index].getBoundingClientRect();
121
+ const relative_left = left - container_left;
122
+ const pos = relative_left + width / 2 - container_width / 2 + container_element.scrollLeft;
123
+ if (container_element && typeof container_element.scrollTo === "function") {
124
+ container_element.scrollTo({
125
+ left: pos < 0 ? 0 : pos,
126
+ behavior: "smooth"
127
+ });
128
+ }
129
+ }
130
+ let window_height = 0;
131
+ async function download(file_url, name) {
132
+ let response;
133
+ try {
134
+ response = await _fetch(file_url);
135
+ } catch (error) {
136
+ if (error instanceof TypeError) {
137
+ window.open(file_url, "_blank", "noreferrer");
138
+ return;
139
+ }
140
+ throw error;
141
+ }
142
+ const blob = await response.blob();
143
+ const url = URL.createObjectURL(blob);
144
+ const link = document.createElement("a");
145
+ link.href = url;
146
+ link.download = name;
147
+ link.click();
148
+ URL.revokeObjectURL(url);
149
+ }
150
+ $:
151
+ selected_image = selected_index != null && resolved_value != null ? resolved_value[selected_index] : null;
152
+ onMount(() => {
153
+ document.addEventListener("fullscreenchange", () => {
154
+ is_full_screen = !!document.fullscreenElement;
155
+ });
156
+ });
157
+ const toggle_full_screen = async () => {
158
+ if (!is_full_screen) {
159
+ await gallery_container.requestFullscreen();
160
+ } else {
161
+ await document.exitFullscreen();
162
+ }
163
+ };
164
+ </script>
165
+
166
+ <svelte:window bind:innerHeight={window_height} />
167
+
168
+ {#if show_label}
169
+ <BlockLabel {show_label} Icon={ImageIcon} label={label || "Gallery"} />
170
+ {/if}
171
+ {#if value == null || resolved_value == null || resolved_value.length === 0}
172
+ <Empty unpadded_box={true} size="large"><ImageIcon /></Empty>
173
+ {:else}
174
+ <div class="gallery-container" bind:this={gallery_container}>
175
+ {#if selected_image && allow_preview}
176
+ <button
177
+ on:keydown={on_keydown}
178
+ class="preview"
179
+ class:minimal={mode === "minimal"}
180
+ >
181
+ <div class="icon-buttons">
182
+ {#if show_download_button}
183
+ <IconButton
184
+ Icon={Download}
185
+ label={i18n("common.download")}
186
+ on:click={() => {
187
+ const image = selected_image?.image;
188
+ if (image == null) {
189
+ return;
190
+ }
191
+ const { url, orig_name } = image;
192
+ if (url) {
193
+ download(url, orig_name ?? "image");
194
+ }
195
+ }}
196
+ />
197
+ {/if}
198
+
199
+ {#if show_fullscreen_button && !is_full_screen}
200
+ <IconButton
201
+ Icon={is_full_screen ? Minimize : Maximize}
202
+ label={is_full_screen
203
+ ? "Exit full screen"
204
+ : "View in full screen"}
205
+ on:click={toggle_full_screen}
206
+ />
207
+ {/if}
208
+
209
+ {#if show_fullscreen_button && is_full_screen}
210
+ <IconButton
211
+ Icon={Minimize}
212
+ label="Exit full screen"
213
+ on:click={toggle_full_screen}
214
+ />
215
+ {/if}
216
+
217
+ {#if !is_full_screen}
218
+ <IconButton
219
+ Icon={Clear}
220
+ label="Close"
221
+ on:click={() => (selected_index = null)}
222
+ />
223
+ {/if}
224
+ </div>
225
+ <button
226
+ class="image-button"
227
+ on:click={(event) => handle_preview_click(event)}
228
+ style="height: calc(100% - {selected_image.caption
229
+ ? '80px'
230
+ : '60px'})"
231
+ aria-label="detailed view of selected image"
232
+ >
233
+ <Image
234
+ data-testid="detailed-image"
235
+ src={selected_image.image.url}
236
+ alt={selected_image.caption || ""}
237
+ title={selected_image.caption || null}
238
+ class={selected_image.caption && "with-caption"}
239
+ loading="lazy"
240
+ />
241
+ </button>
242
+ {#if selected_image?.caption}
243
+ <caption class="caption">
244
+ {selected_image.caption}
245
+ </caption>
246
+ {/if}
247
+ <div
248
+ bind:this={container_element}
249
+ class="thumbnails scroll-hide"
250
+ data-testid="container_el"
251
+ >
252
+ {#each resolved_value as image, i}
253
+ <button
254
+ bind:this={el[i]}
255
+ on:click={() => (selected_index = i)}
256
+ class="thumbnail-item thumbnail-small"
257
+ class:selected={selected_index === i && mode !== "minimal"}
258
+ aria-label={"Thumbnail " +
259
+ (i + 1) +
260
+ " of " +
261
+ resolved_value.length}
262
+ >
263
+ <Image
264
+ src={image.image.url}
265
+ title={image.caption || null}
266
+ data-testid={"thumbnail " + (i + 1)}
267
+ alt=""
268
+ loading="lazy"
269
+ />
270
+ </button>
271
+ {/each}
272
+ </div>
273
+ </button>
274
+ {/if}
275
+
276
+ <div
277
+ class="grid-wrap"
278
+ class:minimal={mode === "minimal"}
279
+ class:fixed-height={mode !== "minimal" && (!height || height == "auto")}
280
+ class:hidden={is_full_screen}
281
+ >
282
+ <div
283
+ class="grid-container"
284
+ style="--grid-cols:{columns}; --grid-rows:{rows}; --object-fit: {object_fit}; height: {height};"
285
+ class:pt-6={show_label}
286
+ >
287
+ {#if interactive}
288
+ <div class="icon-button">
289
+ <ModifyUpload
290
+ {i18n}
291
+ absolute={false}
292
+ on:clear={() => (value = null)}
293
+ />
294
+ </div>
295
+ {/if}
296
+ {#if show_share_button}
297
+ <div class="icon-button">
298
+ <ShareButton
299
+ {i18n}
300
+ on:share
301
+ on:error
302
+ value={resolved_value}
303
+ formatter={format_gallery_for_sharing}
304
+ />
305
+ </div>
306
+ {/if}
307
+ {#each resolved_value as entry, i}
308
+ <button
309
+ class="thumbnail-item thumbnail-lg"
310
+ class:selected={selected_index === i}
311
+ on:click={() => (selected_index = i)}
312
+ aria-label={"Thumbnail " + (i + 1) + " of " + resolved_value.length}
313
+ >
314
+ <Image
315
+ alt={entry.caption || ""}
316
+ src={typeof entry.image === "string"
317
+ ? entry.image
318
+ : entry.image.url}
319
+ loading="lazy"
320
+ />
321
+ {#if entry.caption}
322
+ <div class="caption-label">
323
+ {entry.caption}
324
+ </div>
325
+ {/if}
326
+ </button>
327
+ {/each}
328
+ </div>
329
+ </div>
330
+ </div>
331
+ {/if}
332
+
333
+ <style>
334
+ .image-container {
335
+ height: 100%;
336
+ position: relative;
337
+ }
338
+ .image-container :global(img),
339
+ button {
340
+ width: var(--size-full);
341
+ height: var(--size-full);
342
+ object-fit: contain;
343
+ display: block;
344
+ border-radius: var(--radius-lg);
345
+ }
346
+
347
+ .preview {
348
+ display: flex;
349
+ position: absolute;
350
+ flex-direction: column;
351
+ z-index: var(--layer-2);
352
+ border-radius: calc(var(--block-radius) - var(--block-border-width));
353
+ -webkit-backdrop-filter: blur(8px);
354
+ backdrop-filter: blur(8px);
355
+ width: var(--size-full);
356
+ height: var(--size-full);
357
+ }
358
+
359
+ .preview.minimal {
360
+ width: fit-content;
361
+ height: fit-content;
362
+ }
363
+
364
+ .preview::before {
365
+ content: "";
366
+ position: absolute;
367
+ z-index: var(--layer-below);
368
+ background: var(--background-fill-primary);
369
+ opacity: 0.9;
370
+ width: var(--size-full);
371
+ height: var(--size-full);
372
+ }
373
+
374
+ .fixed-height {
375
+ min-height: var(--size-80);
376
+ max-height: 55vh;
377
+ }
378
+
379
+ @media (--screen-xl) {
380
+ .fixed-height {
381
+ min-height: 450px;
382
+ }
383
+ }
384
+
385
+ .image-button {
386
+ height: calc(100% - 60px);
387
+ width: 100%;
388
+ display: flex;
389
+ }
390
+ .image-button :global(img) {
391
+ width: var(--size-full);
392
+ height: var(--size-full);
393
+ object-fit: contain;
394
+ }
395
+ .thumbnails :global(img) {
396
+ object-fit: cover;
397
+ width: var(--size-full);
398
+ height: var(--size-full);
399
+ }
400
+ .preview :global(img.with-caption) {
401
+ height: var(--size-full);
402
+ }
403
+
404
+ .preview.minimal :global(img.with-caption) {
405
+ height: auto;
406
+ }
407
+
408
+ .selectable {
409
+ cursor: crosshair;
410
+ }
411
+
412
+ .caption {
413
+ padding: var(--size-2) var(--size-3);
414
+ overflow: hidden;
415
+ color: var(--block-label-text-color);
416
+ font-weight: var(--weight-semibold);
417
+ text-align: center;
418
+ text-overflow: ellipsis;
419
+ white-space: nowrap;
420
+ align-self: center;
421
+ }
422
+
423
+ .thumbnails {
424
+ display: flex;
425
+ position: absolute;
426
+ bottom: 0;
427
+ justify-content: center;
428
+ align-items: center;
429
+ gap: var(--spacing-lg);
430
+ width: var(--size-full);
431
+ height: var(--size-14);
432
+ overflow-x: scroll;
433
+ }
434
+
435
+ .thumbnail-item {
436
+ --ring-color: transparent;
437
+ position: relative;
438
+ box-shadow:
439
+ inset 0 0 0 1px var(--ring-color),
440
+ var(--shadow-drop);
441
+ border: 1px solid var(--border-color-primary);
442
+ border-radius: var(--button-small-radius);
443
+ background: var(--background-fill-secondary);
444
+ aspect-ratio: var(--ratio-square);
445
+ width: var(--size-full);
446
+ height: var(--size-full);
447
+ overflow: clip;
448
+ }
449
+
450
+ .thumbnail-item:hover {
451
+ --ring-color: var(--color-accent);
452
+ border-color: var(--color-accent);
453
+ filter: brightness(1.1);
454
+ }
455
+
456
+ .thumbnail-item.selected {
457
+ --ring-color: var(--color-accent);
458
+ border-color: var(--color-accent);
459
+ }
460
+
461
+ .thumbnail-small {
462
+ flex: none;
463
+ transform: scale(0.9);
464
+ transition: 0.075s;
465
+ width: var(--size-9);
466
+ height: var(--size-9);
467
+ }
468
+
469
+ .thumbnail-small.selected {
470
+ --ring-color: var(--color-accent);
471
+ transform: scale(1);
472
+ border-color: var(--color-accent);
473
+ }
474
+
475
+ .thumbnail-small > img {
476
+ width: var(--size-full);
477
+ height: var(--size-full);
478
+ overflow: hidden;
479
+ object-fit: var(--object-fit);
480
+ }
481
+
482
+ .grid-wrap {
483
+ position: relative;
484
+ padding: var(--size-2);
485
+ height: var(--size-full);
486
+ overflow-y: scroll;
487
+ }
488
+
489
+ .grid-container {
490
+ display: grid;
491
+ position: relative;
492
+ grid-template-rows: repeat(var(--grid-rows), minmax(100px, 1fr));
493
+ grid-template-columns: repeat(var(--grid-cols), minmax(100px, 1fr));
494
+ grid-auto-rows: minmax(100px, 1fr);
495
+ gap: var(--spacing-lg);
496
+ }
497
+
498
+ .thumbnail-lg > :global(img) {
499
+ width: var(--size-full);
500
+ height: var(--size-full);
501
+ overflow: hidden;
502
+ object-fit: var(--object-fit);
503
+ }
504
+
505
+ .thumbnail-lg:hover .caption-label {
506
+ opacity: 0.5;
507
+ }
508
+
509
+ .caption-label {
510
+ position: absolute;
511
+ right: var(--block-label-margin);
512
+ bottom: var(--block-label-margin);
513
+ z-index: var(--layer-1);
514
+ border-top: 1px solid var(--border-color-primary);
515
+ border-left: 1px solid var(--border-color-primary);
516
+ border-radius: var(--block-label-radius);
517
+ background: var(--background-fill-secondary);
518
+ padding: var(--block-label-padding);
519
+ max-width: 80%;
520
+ overflow: hidden;
521
+ font-size: var(--block-label-text-size);
522
+ text-align: left;
523
+ text-overflow: ellipsis;
524
+ white-space: nowrap;
525
+ }
526
+
527
+ .icon-button {
528
+ position: absolute;
529
+ top: 0px;
530
+ right: 0px;
531
+ z-index: var(--layer-1);
532
+ }
533
+
534
+ .icon-buttons {
535
+ display: flex;
536
+ position: absolute;
537
+ right: 0;
538
+ gap: var(--size-1);
539
+ z-index: 1;
540
+ margin: var(--size-1);
541
+ }
542
+
543
+ .grid-wrap.minimal {
544
+ padding: 0;
545
+ }
546
+ </style>
@@ -0,0 +1,43 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { SelectData } from "@gradio/utils";
3
+ import { FileData } from "@gradio/client";
4
+ import type { I18nFormatter } from "@gradio/utils";
5
+ declare const __propDef: {
6
+ props: {
7
+ show_label?: boolean | undefined;
8
+ label: string;
9
+ value?: ({
10
+ image: FileData;
11
+ caption: string | null;
12
+ }[] | null) | undefined;
13
+ columns?: number | number[] | undefined;
14
+ rows?: number | number[] | undefined;
15
+ height?: (number | "auto") | undefined;
16
+ preview: boolean;
17
+ allow_preview?: boolean | undefined;
18
+ object_fit?: ("contain" | "cover" | "fill" | "none" | "scale-down") | undefined;
19
+ show_share_button?: boolean | undefined;
20
+ show_download_button?: boolean | undefined;
21
+ i18n: I18nFormatter;
22
+ selected_index?: (number | null) | undefined;
23
+ interactive: boolean;
24
+ _fetch: typeof fetch;
25
+ mode?: ("normal" | "minimal") | undefined;
26
+ show_fullscreen_button?: boolean | undefined;
27
+ };
28
+ events: {
29
+ share: CustomEvent<import("@gradio/utils").ShareData>;
30
+ error: CustomEvent<string>;
31
+ change: CustomEvent<undefined>;
32
+ select: CustomEvent<SelectData>;
33
+ } & {
34
+ [evt: string]: CustomEvent<any>;
35
+ };
36
+ slots: {};
37
+ };
38
+ export type GalleryProps = typeof __propDef.props;
39
+ export type GalleryEvents = typeof __propDef.events;
40
+ export type GallerySlots = typeof __propDef.slots;
41
+ export default class Gallery extends SvelteComponent<GalleryProps, GalleryEvents, GallerySlots> {
42
+ }
43
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { FileData } from "@gradio/client";
2
+ export declare function format_gallery_for_sharing(value: [FileData, string | null][] | null): Promise<string>;
@@ -0,0 +1,13 @@
1
+ import { uploadToHuggingFace } from "@gradio/utils";
2
+ export async function format_gallery_for_sharing(value) {
3
+ if (!value)
4
+ return "";
5
+ let urls = await Promise.all(value.map(async ([image, _]) => {
6
+ if (image === null || !image.url)
7
+ return "";
8
+ return await uploadToHuggingFace(image.url, "url");
9
+ }));
10
+ return `<div style="display: flex; flex-wrap: wrap; gap: 16px">${urls
11
+ .map((url) => `<img src="${url}" style="height: 400px" />`)
12
+ .join("")}</div>`;
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/gallery",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -8,23 +8,39 @@
8
8
  "private": false,
9
9
  "dependencies": {
10
10
  "dequal": "^2.0.2",
11
- "@gradio/atoms": "^0.7.9",
12
- "@gradio/client": "^1.5.0",
13
- "@gradio/image": "^0.14.0",
14
- "@gradio/icons": "^0.7.0",
15
- "@gradio/statustracker": "^0.7.4",
16
- "@gradio/utils": "^0.5.2",
17
- "@gradio/upload": "^0.12.2",
18
- "@gradio/file": "^0.9.2"
11
+ "@gradio/atoms": "^0.8.1",
12
+ "@gradio/icons": "^0.7.2",
13
+ "@gradio/image": "^0.15.1",
14
+ "@gradio/statustracker": "^0.7.6",
15
+ "@gradio/client": "^1.5.2",
16
+ "@gradio/utils": "^0.6.1",
17
+ "@gradio/file": "^0.9.4",
18
+ "@gradio/upload": "^0.12.4"
19
19
  },
20
20
  "devDependencies": {
21
- "@gradio/preview": "^0.10.2"
21
+ "@gradio/preview": "^0.11.1"
22
22
  },
23
23
  "main": "./Index.svelte",
24
24
  "main_changeset": true,
25
25
  "exports": {
26
- ".": "./Index.svelte",
26
+ ".": {
27
+ "gradio": "./Index.svelte",
28
+ "svelte": "./dist/Index.svelte",
29
+ "types": "./dist/Index.svelte.d.ts"
30
+ },
27
31
  "./package.json": "./package.json",
28
- "./base": "./shared/Gallery.svelte"
32
+ "./base": {
33
+ "gradio": "./shared/Gallery.svelte",
34
+ "svelte": "./dist/shared/Gallery.svelte",
35
+ "types": "./dist/shared/Gallery.svelte.d.ts"
36
+ }
37
+ },
38
+ "peerDependencies": {
39
+ "svelte": "^4.0.0"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/gradio-app/gradio.git",
44
+ "directory": "js/gallery"
29
45
  }
30
46
  }