@gradio/imageslider 0.5.0 → 0.7.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 +45 -0
- package/Example.svelte +11 -4
- package/ImageSlider.test.ts +32 -0
- package/Index.svelte +16 -49
- package/dist/Example.svelte +11 -4
- package/dist/Example.svelte.d.ts +4 -18
- package/dist/Index.svelte +16 -49
- package/dist/shared/ClearImage.svelte +2 -3
- package/dist/shared/ClearImage.svelte.d.ts +5 -19
- package/dist/shared/Image.svelte +67 -45
- package/dist/shared/Image.svelte.d.ts +14 -40
- package/dist/shared/ImageEl.svelte +22 -23
- package/dist/shared/ImageEl.svelte.d.ts +7 -22
- package/dist/shared/Slider.svelte +34 -19
- package/dist/shared/Slider.svelte.d.ts +8 -29
- package/dist/shared/SliderPreview.svelte +85 -47
- package/dist/shared/SliderPreview.svelte.d.ts +8 -23
- package/dist/shared/SliderUpload.svelte +43 -20
- package/dist/shared/SliderUpload.svelte.d.ts +11 -49
- package/dist/types.d.ts +1 -1
- package/package.json +7 -7
- package/shared/ClearImage.svelte +2 -3
- package/shared/Image.svelte +67 -45
- package/shared/ImageEl.svelte +22 -23
- package/shared/Slider.svelte +34 -19
- package/shared/SliderPreview.svelte +85 -47
- package/shared/SliderUpload.svelte +43 -20
- package/types.ts +1 -1
|
@@ -1,25 +1,8 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
1
2
|
import type { I18nFormatter } from "@gradio/utils";
|
|
2
3
|
import { type Client } from "@gradio/client";
|
|
3
4
|
import type { FileData } from "@gradio/client";
|
|
4
|
-
|
|
5
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
6
|
-
$$bindings?: Bindings;
|
|
7
|
-
} & Exports;
|
|
8
|
-
(internal: unknown, props: Props & {
|
|
9
|
-
$$events?: Events;
|
|
10
|
-
$$slots?: Slots;
|
|
11
|
-
}): Exports & {
|
|
12
|
-
$set?: any;
|
|
13
|
-
$on?: any;
|
|
14
|
-
};
|
|
15
|
-
z_$$bindings?: Bindings;
|
|
16
|
-
}
|
|
17
|
-
type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
18
|
-
default: any;
|
|
19
|
-
} ? Props extends Record<string, never> ? any : {
|
|
20
|
-
children?: any;
|
|
21
|
-
} : {});
|
|
22
|
-
declare const SliderUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
|
|
5
|
+
type $$ComponentProps = {
|
|
23
6
|
value?: [FileData | null, FileData | null];
|
|
24
7
|
upload: Client["upload"];
|
|
25
8
|
stream_handler: Client["stream"];
|
|
@@ -28,36 +11,15 @@ declare const SliderUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_Pr
|
|
|
28
11
|
i18n: I18nFormatter;
|
|
29
12
|
root: string;
|
|
30
13
|
upload_count?: number;
|
|
31
|
-
dragging
|
|
14
|
+
dragging?: boolean;
|
|
32
15
|
max_height: number;
|
|
33
16
|
max_file_size?: number | null;
|
|
34
|
-
upload_promise?: Promise<any
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
select: CustomEvent<import("@gradio/utils").SelectData>;
|
|
43
|
-
share: CustomEvent<any>;
|
|
44
|
-
} & {
|
|
45
|
-
[evt: string]: CustomEvent<any>;
|
|
46
|
-
}, {
|
|
47
|
-
default: {};
|
|
48
|
-
}, {
|
|
49
|
-
value: [FileData | null, FileData | null];
|
|
50
|
-
upload: Client["upload"];
|
|
51
|
-
stream_handler: Client["stream"];
|
|
52
|
-
label: string;
|
|
53
|
-
show_label: boolean;
|
|
54
|
-
i18n: I18nFormatter;
|
|
55
|
-
root: string;
|
|
56
|
-
upload_count: number;
|
|
57
|
-
dragging: boolean;
|
|
58
|
-
max_height: number;
|
|
59
|
-
max_file_size: number | null;
|
|
60
|
-
upload_promise: Promise<any> | null;
|
|
61
|
-
}, string>;
|
|
62
|
-
type SliderUpload = InstanceType<typeof SliderUpload>;
|
|
17
|
+
upload_promise?: Promise<any>;
|
|
18
|
+
onclear?: () => void;
|
|
19
|
+
ondrag?: (dragging: boolean) => void;
|
|
20
|
+
onupload?: (value: [FileData | null, FileData | null]) => void;
|
|
21
|
+
children?: Snippet;
|
|
22
|
+
};
|
|
23
|
+
declare const SliderUpload: import("svelte").Component<$$ComponentProps, {}, "value" | "dragging" | "upload_promise">;
|
|
24
|
+
type SliderUpload = ReturnType<typeof SliderUpload>;
|
|
63
25
|
export default SliderUpload;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SelectData, ValueData, ShareData, CustomButton } from "@gradio/utils";
|
|
2
|
-
import type { LoadingStatus } from "@gradio/statustracker";
|
|
2
|
+
import type { ILoadingStatus as LoadingStatus } from "@gradio/statustracker";
|
|
3
3
|
import type { FileData } from "@gradio/client";
|
|
4
4
|
export interface ImageSliderEvents {
|
|
5
5
|
input: never;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/imageslider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
"@types/d3-selection": "^3.0.11",
|
|
12
12
|
"d3-drag": "^3.0.0",
|
|
13
13
|
"d3-selection": "^3.0.0",
|
|
14
|
-
"@gradio/
|
|
15
|
-
"@gradio/
|
|
16
|
-
"@gradio/
|
|
17
|
-
"@gradio/
|
|
18
|
-
"@gradio/upload": "^0.
|
|
19
|
-
"@gradio/
|
|
14
|
+
"@gradio/icons": "^0.16.0",
|
|
15
|
+
"@gradio/atoms": "^0.26.0",
|
|
16
|
+
"@gradio/statustracker": "^0.15.1",
|
|
17
|
+
"@gradio/utils": "^0.13.0",
|
|
18
|
+
"@gradio/upload": "^0.18.1",
|
|
19
|
+
"@gradio/client": "^2.3.1"
|
|
20
20
|
},
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
package/shared/ClearImage.svelte
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { createEventDispatcher } from "svelte";
|
|
3
2
|
import { IconButton } from "@gradio/atoms";
|
|
4
3
|
import { Clear } from "@gradio/icons";
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
let { onremove_image }: { onremove_image?: () => void } = $props();
|
|
7
6
|
</script>
|
|
8
7
|
|
|
9
8
|
<div>
|
|
@@ -11,7 +10,7 @@
|
|
|
11
10
|
Icon={Clear}
|
|
12
11
|
label="Remove Image"
|
|
13
12
|
onclick={(event) => {
|
|
14
|
-
|
|
13
|
+
onremove_image?.();
|
|
15
14
|
event.stopPropagation();
|
|
16
15
|
}}
|
|
17
16
|
/>
|
package/shared/Image.svelte
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Slider from "./Slider.svelte";
|
|
3
|
-
import {
|
|
3
|
+
import { tick, type Snippet } from "svelte";
|
|
4
4
|
import { BlockLabel, Empty, IconButton, DownloadLink } from "@gradio/atoms";
|
|
5
5
|
import { Download } from "@gradio/icons";
|
|
6
6
|
import { Image } from "@gradio/icons";
|
|
7
|
-
import { type
|
|
7
|
+
import { type I18nFormatter } from "@gradio/utils";
|
|
8
8
|
import ClearImage from "./ClearImage.svelte";
|
|
9
9
|
import ImageEl from "./ImageEl.svelte";
|
|
10
10
|
|
|
@@ -12,65 +12,87 @@
|
|
|
12
12
|
|
|
13
13
|
import { type FileData, type Client } from "@gradio/client";
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
let {
|
|
16
|
+
value = $bindable<[FileData | null, FileData | null]>([null, null]),
|
|
17
|
+
label = undefined,
|
|
18
|
+
show_label,
|
|
19
|
+
root,
|
|
20
|
+
position = $bindable(0.5),
|
|
21
|
+
upload_count = 2,
|
|
22
|
+
show_download_button = true,
|
|
23
|
+
slider_color,
|
|
24
|
+
upload,
|
|
25
|
+
stream_handler,
|
|
26
|
+
max_file_size = null,
|
|
27
|
+
i18n,
|
|
28
|
+
max_height,
|
|
29
|
+
upload_promise = $bindable(),
|
|
30
|
+
dragging = $bindable(false),
|
|
31
|
+
onclear,
|
|
32
|
+
ondrag,
|
|
33
|
+
onupload,
|
|
34
|
+
children
|
|
35
|
+
}: {
|
|
36
|
+
value?: [FileData | null, FileData | null];
|
|
37
|
+
label?: string;
|
|
38
|
+
show_label: boolean;
|
|
39
|
+
root: string;
|
|
40
|
+
position?: number;
|
|
41
|
+
upload_count?: number;
|
|
42
|
+
show_download_button?: boolean;
|
|
43
|
+
slider_color: string;
|
|
44
|
+
upload: Client["upload"];
|
|
45
|
+
stream_handler: Client["stream"];
|
|
46
|
+
max_file_size?: number | null;
|
|
47
|
+
i18n: I18nFormatter;
|
|
48
|
+
max_height: number;
|
|
49
|
+
upload_promise?: Promise<any>;
|
|
50
|
+
dragging?: boolean;
|
|
51
|
+
onclear?: () => void;
|
|
52
|
+
ondrag?: (dragging: boolean) => void;
|
|
53
|
+
onupload?: (value: [FileData | null, FileData | null]) => void;
|
|
54
|
+
children?: Snippet;
|
|
55
|
+
} = $props();
|
|
16
56
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export let position: number;
|
|
21
|
-
export let upload_count = 2;
|
|
22
|
-
|
|
23
|
-
export let show_download_button = true;
|
|
24
|
-
export let slider_color: string;
|
|
25
|
-
export let upload: Client["upload"];
|
|
26
|
-
export let stream_handler: Client["stream"];
|
|
27
|
-
export let max_file_size: number | null = null;
|
|
28
|
-
export let i18n: I18nFormatter;
|
|
29
|
-
export let max_height: number;
|
|
30
|
-
export let upload_promise: Promise<any> | null = null;
|
|
31
|
-
|
|
32
|
-
let value_: [FileData | null, FileData | null] = value || [null, null];
|
|
57
|
+
let value_ = $state<[FileData | null, FileData | null]>(
|
|
58
|
+
value || [null, null]
|
|
59
|
+
);
|
|
33
60
|
|
|
34
61
|
let img: HTMLImageElement;
|
|
35
|
-
let el_width
|
|
36
|
-
let el_height
|
|
62
|
+
let el_width = $state(0);
|
|
63
|
+
let el_height = $state(0);
|
|
37
64
|
|
|
38
|
-
async function handle_upload(
|
|
65
|
+
async function handle_upload(
|
|
66
|
+
detail: Blob | File | FileData | FileData[],
|
|
67
|
+
n: number
|
|
68
|
+
): Promise<void> {
|
|
69
|
+
const file_data = Array.isArray(detail) ? detail : [detail as FileData];
|
|
39
70
|
const new_value = [value[0], value[1]] as [
|
|
40
71
|
FileData | null,
|
|
41
72
|
FileData | null
|
|
42
73
|
];
|
|
43
|
-
if (
|
|
44
|
-
new_value[n] =
|
|
74
|
+
if (file_data.length > 1) {
|
|
75
|
+
new_value[n] = file_data[0];
|
|
45
76
|
} else {
|
|
46
|
-
new_value[n] =
|
|
77
|
+
new_value[n] = file_data[n];
|
|
47
78
|
}
|
|
48
79
|
value = new_value;
|
|
49
80
|
await tick();
|
|
50
81
|
|
|
51
|
-
|
|
82
|
+
onupload?.(new_value);
|
|
52
83
|
}
|
|
53
84
|
|
|
54
85
|
let old_value = "";
|
|
55
86
|
|
|
56
|
-
|
|
87
|
+
$effect(() => {
|
|
88
|
+
if (JSON.stringify(value) === old_value) return;
|
|
57
89
|
old_value = JSON.stringify(value);
|
|
58
90
|
value_ = value;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const dispatch = createEventDispatcher<{
|
|
62
|
-
change: string | null;
|
|
63
|
-
stream: string | null;
|
|
64
|
-
edit: undefined;
|
|
65
|
-
clear: undefined;
|
|
66
|
-
drag: boolean;
|
|
67
|
-
upload: [FileData | null, FileData | null];
|
|
68
|
-
select: SelectData;
|
|
69
|
-
}>();
|
|
70
|
-
|
|
71
|
-
export let dragging = false;
|
|
91
|
+
});
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
$effect(() => {
|
|
94
|
+
ondrag?.(dragging);
|
|
95
|
+
});
|
|
74
96
|
</script>
|
|
75
97
|
|
|
76
98
|
<BlockLabel {show_label} Icon={Image} label={label || i18n("image.image")} />
|
|
@@ -83,10 +105,10 @@
|
|
|
83
105
|
>
|
|
84
106
|
{#if value?.[0]?.url || value?.[1]?.url}
|
|
85
107
|
<ClearImage
|
|
86
|
-
|
|
108
|
+
onremove_image={() => {
|
|
87
109
|
position = 0.5;
|
|
88
110
|
value = [null, null];
|
|
89
|
-
|
|
111
|
+
onclear?.();
|
|
90
112
|
}}
|
|
91
113
|
/>
|
|
92
114
|
{/if}
|
|
@@ -126,7 +148,7 @@
|
|
|
126
148
|
{stream_handler}
|
|
127
149
|
{max_file_size}
|
|
128
150
|
>
|
|
129
|
-
|
|
151
|
+
{#if children}{@render children()}{/if}
|
|
130
152
|
</Upload>
|
|
131
153
|
</div>
|
|
132
154
|
{:else}
|
|
@@ -152,7 +174,7 @@
|
|
|
152
174
|
{stream_handler}
|
|
153
175
|
{max_file_size}
|
|
154
176
|
>
|
|
155
|
-
|
|
177
|
+
{#if children}{@render children()}{/if}
|
|
156
178
|
</Upload>
|
|
157
179
|
{:else if !value_?.[1] && upload_count === 1}
|
|
158
180
|
<div
|
package/shared/ImageEl.svelte
CHANGED
|
@@ -1,36 +1,35 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { HTMLImgAttributes } from "svelte/elements";
|
|
3
|
-
import {
|
|
4
|
-
interface Props extends HTMLImgAttributes {
|
|
3
|
+
import { onMount, tick } from "svelte";
|
|
4
|
+
interface Props extends Omit<HTMLImgAttributes, "onload"> {
|
|
5
5
|
"data-testid"?: string;
|
|
6
6
|
fixed?: boolean;
|
|
7
7
|
transform?: string;
|
|
8
|
-
img_el?: HTMLImageElement;
|
|
8
|
+
img_el?: HTMLImageElement | null;
|
|
9
9
|
hidden?: boolean;
|
|
10
10
|
variant?: "preview" | "upload";
|
|
11
11
|
max_height?: number;
|
|
12
12
|
fullscreen?: boolean;
|
|
13
|
-
|
|
14
|
-
type $$Props = Props;
|
|
15
|
-
|
|
16
|
-
export let src: HTMLImgAttributes["src"] = undefined;
|
|
17
|
-
export let fullscreen = false;
|
|
18
|
-
|
|
19
|
-
export let fixed = false;
|
|
20
|
-
export let transform = "translate(0px, 0px) scale(1)";
|
|
21
|
-
export let img_el: HTMLImageElement | null = null;
|
|
22
|
-
export let hidden = false;
|
|
23
|
-
export let variant = "upload";
|
|
24
|
-
export let max_height = 500;
|
|
25
|
-
|
|
26
|
-
const dispatch = createEventDispatcher<{
|
|
27
|
-
load: {
|
|
13
|
+
onload?: (size: {
|
|
28
14
|
top: number;
|
|
29
15
|
left: number;
|
|
30
16
|
width: number;
|
|
31
17
|
height: number;
|
|
32
|
-
};
|
|
33
|
-
}
|
|
18
|
+
}) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
src = undefined,
|
|
23
|
+
fullscreen = false,
|
|
24
|
+
fixed = false,
|
|
25
|
+
transform = "translate(0px, 0px) scale(1)",
|
|
26
|
+
img_el = $bindable<HTMLImageElement | null>(),
|
|
27
|
+
hidden = false,
|
|
28
|
+
variant = "upload",
|
|
29
|
+
max_height = 500,
|
|
30
|
+
onload,
|
|
31
|
+
...restProps
|
|
32
|
+
}: Props = $props();
|
|
34
33
|
|
|
35
34
|
function get_image_size(img: HTMLImageElement | null): {
|
|
36
35
|
top: number;
|
|
@@ -70,7 +69,7 @@
|
|
|
70
69
|
const resizer = new ResizeObserver(async (entries) => {
|
|
71
70
|
for (const entry of entries) {
|
|
72
71
|
await tick();
|
|
73
|
-
|
|
72
|
+
onload?.(get_image_size(img_el));
|
|
74
73
|
}
|
|
75
74
|
});
|
|
76
75
|
|
|
@@ -86,7 +85,7 @@
|
|
|
86
85
|
<img
|
|
87
86
|
{src}
|
|
88
87
|
data-testid="imageslider-image"
|
|
89
|
-
{
|
|
88
|
+
{...restProps}
|
|
90
89
|
class:fixed
|
|
91
90
|
style:transform
|
|
92
91
|
bind:this={img_el}
|
|
@@ -96,7 +95,7 @@
|
|
|
96
95
|
style:max-height={max_height && !fullscreen ? `${max_height}px` : null}
|
|
97
96
|
class:fullscreen
|
|
98
97
|
class:small={!fullscreen}
|
|
99
|
-
|
|
98
|
+
onload={() => onload?.(get_image_size(img_el))}
|
|
100
99
|
/>
|
|
101
100
|
|
|
102
101
|
<style>
|
package/shared/Slider.svelte
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { onMount } from "svelte";
|
|
2
|
+
import { onMount, type Snippet } from "svelte";
|
|
3
3
|
import { drag } from "d3-drag";
|
|
4
4
|
import { select } from "d3-selection";
|
|
5
5
|
|
|
@@ -7,22 +7,33 @@
|
|
|
7
7
|
return Math.min(Math.max(value, min), max);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
let {
|
|
11
|
+
position = $bindable(0.5),
|
|
12
|
+
disabled = false,
|
|
13
|
+
slider_color = "var(--border-color-primary)",
|
|
14
|
+
image_size = { top: 0, left: 0, width: 0, height: 0 },
|
|
15
|
+
el = $bindable<HTMLDivElement | undefined>(undefined),
|
|
16
|
+
parent_el = $bindable<HTMLDivElement | undefined>(undefined),
|
|
17
|
+
children
|
|
18
|
+
}: {
|
|
19
|
+
position?: number;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
slider_color?: string;
|
|
22
|
+
image_size?: {
|
|
23
|
+
top: number;
|
|
24
|
+
left: number;
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
};
|
|
28
|
+
el?: HTMLDivElement;
|
|
29
|
+
parent_el?: HTMLDivElement;
|
|
30
|
+
children?: Snippet;
|
|
31
|
+
} = $props();
|
|
12
32
|
|
|
13
|
-
export let slider_color = "var(--border-color-primary)";
|
|
14
|
-
export let image_size: {
|
|
15
|
-
top: number;
|
|
16
|
-
left: number;
|
|
17
|
-
width: number;
|
|
18
|
-
height: number;
|
|
19
|
-
} = { top: 0, left: 0, width: 0, height: 0 };
|
|
20
|
-
export let el: HTMLDivElement | undefined = undefined;
|
|
21
|
-
export let parent_el: HTMLDivElement | undefined = undefined;
|
|
22
33
|
let inner: Element;
|
|
23
|
-
let px = 0;
|
|
24
|
-
let active = false;
|
|
25
|
-
let container_width = 0;
|
|
34
|
+
let px = $state(0);
|
|
35
|
+
let active = $state(false);
|
|
36
|
+
let container_width = $state(0);
|
|
26
37
|
|
|
27
38
|
function set_position(width: number): void {
|
|
28
39
|
container_width = parent_el?.getBoundingClientRect().width || 0;
|
|
@@ -67,8 +78,12 @@
|
|
|
67
78
|
px = clamp(image_size.width * pc + image_size.left, 0, container_width);
|
|
68
79
|
}
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
$effect(() => {
|
|
82
|
+
set_position(image_size.width);
|
|
83
|
+
});
|
|
84
|
+
$effect(() => {
|
|
85
|
+
update_position_from_pc(position);
|
|
86
|
+
});
|
|
72
87
|
|
|
73
88
|
onMount(() => {
|
|
74
89
|
set_position(image_size.width);
|
|
@@ -80,11 +95,11 @@
|
|
|
80
95
|
});
|
|
81
96
|
</script>
|
|
82
97
|
|
|
83
|
-
<svelte:window
|
|
98
|
+
<svelte:window onresize={() => set_position(image_size.width)} />
|
|
84
99
|
|
|
85
100
|
<div class="wrap" role="none" bind:this={parent_el}>
|
|
86
101
|
<div class="content" bind:this={el}>
|
|
87
|
-
|
|
102
|
+
{#if children}{@render children()}{/if}
|
|
88
103
|
</div>
|
|
89
104
|
<div
|
|
90
105
|
class="outer"
|
|
@@ -16,28 +16,49 @@
|
|
|
16
16
|
import { ZoomableImage } from "./zoom";
|
|
17
17
|
import { onMount } from "svelte";
|
|
18
18
|
import { tweened, type Tweened } from "svelte/motion";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
value = $bindable<[null | FileData, null | FileData]>([null, null]),
|
|
22
|
+
label = undefined,
|
|
23
|
+
show_download_button = true,
|
|
24
|
+
show_label,
|
|
25
|
+
i18n,
|
|
26
|
+
position = $bindable(0.5),
|
|
27
|
+
layer_images = true,
|
|
28
|
+
show_single = false,
|
|
29
|
+
slider_color,
|
|
30
|
+
show_fullscreen_button = true,
|
|
31
|
+
fullscreen = $bindable(false),
|
|
32
|
+
buttons = null,
|
|
33
|
+
on_custom_button_click = null,
|
|
34
|
+
el_width = $bindable(0),
|
|
35
|
+
max_height,
|
|
36
|
+
interactive = true,
|
|
37
|
+
onclear,
|
|
38
|
+
onfullscreen
|
|
39
|
+
}: {
|
|
40
|
+
value?: [null | FileData, null | FileData];
|
|
41
|
+
label?: string;
|
|
42
|
+
show_download_button?: boolean;
|
|
43
|
+
show_label: boolean;
|
|
44
|
+
i18n: I18nFormatter;
|
|
45
|
+
position?: number;
|
|
46
|
+
layer_images?: boolean;
|
|
47
|
+
show_single?: boolean;
|
|
48
|
+
slider_color: string;
|
|
49
|
+
show_fullscreen_button?: boolean;
|
|
50
|
+
fullscreen?: boolean;
|
|
51
|
+
buttons?: (string | CustomButtonType)[] | null;
|
|
52
|
+
on_custom_button_click?: ((id: number) => void) | null;
|
|
53
|
+
el_width?: number;
|
|
54
|
+
max_height: number;
|
|
55
|
+
interactive?: boolean;
|
|
56
|
+
onclear?: () => void;
|
|
57
|
+
onfullscreen?: (fullscreen: boolean) => void;
|
|
58
|
+
} = $props();
|
|
59
|
+
|
|
60
|
+
let img = $state<HTMLImageElement>();
|
|
61
|
+
let slider_wrap = $state<HTMLDivElement>();
|
|
41
62
|
let image_container: HTMLDivElement;
|
|
42
63
|
|
|
43
64
|
let transform: Tweened<{ x: number; y: number; z: number }> = tweened(
|
|
@@ -47,18 +68,28 @@
|
|
|
47
68
|
}
|
|
48
69
|
);
|
|
49
70
|
let parent_el: HTMLDivElement;
|
|
71
|
+
let img_width = $state(0);
|
|
72
|
+
let viewport_width = $state(0);
|
|
73
|
+
let image_size = $state<{
|
|
74
|
+
top: number;
|
|
75
|
+
left: number;
|
|
76
|
+
width: number;
|
|
77
|
+
height: number;
|
|
78
|
+
}>({ top: 0, left: 0, width: 0, height: 0 });
|
|
50
79
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
80
|
+
let coords_at_viewport = $derived(
|
|
81
|
+
get_coords_at_viewport(
|
|
82
|
+
position,
|
|
83
|
+
viewport_width,
|
|
84
|
+
image_size.width,
|
|
85
|
+
image_size.left,
|
|
86
|
+
$transform.x,
|
|
87
|
+
$transform.z
|
|
88
|
+
)
|
|
89
|
+
);
|
|
90
|
+
let style = $derived(
|
|
91
|
+
layer_images ? `clip-path: inset(0 0 0 ${coords_at_viewport * 100}%)` : ""
|
|
58
92
|
);
|
|
59
|
-
$: style = layer_images
|
|
60
|
-
? `clip-path: inset(0 0 0 ${coords_at_viewport * 100}%)`
|
|
61
|
-
: "";
|
|
62
93
|
|
|
63
94
|
function get_coords_at_viewport(
|
|
64
95
|
viewport_percent_x: number, // 0-1
|
|
@@ -77,15 +108,12 @@
|
|
|
77
108
|
return percent_position;
|
|
78
109
|
}
|
|
79
110
|
|
|
80
|
-
let img_width = 0;
|
|
81
|
-
let viewport_width = 0;
|
|
82
|
-
|
|
83
111
|
let zoomable_image: ZoomableImage | null = null;
|
|
84
112
|
let observer: ResizeObserver | null = null;
|
|
85
113
|
|
|
86
114
|
function init_image(
|
|
87
|
-
img: HTMLImageElement,
|
|
88
|
-
slider_wrap: HTMLDivElement
|
|
115
|
+
img: HTMLImageElement | undefined,
|
|
116
|
+
slider_wrap: HTMLDivElement | undefined
|
|
89
117
|
): void {
|
|
90
118
|
if (!img || !slider_wrap) return;
|
|
91
119
|
zoomable_image?.destroy();
|
|
@@ -112,7 +140,9 @@
|
|
|
112
140
|
observer.observe(img);
|
|
113
141
|
}
|
|
114
142
|
|
|
115
|
-
|
|
143
|
+
$effect(() => {
|
|
144
|
+
init_image(img, slider_wrap);
|
|
145
|
+
});
|
|
116
146
|
|
|
117
147
|
onMount(() => {
|
|
118
148
|
return () => {
|
|
@@ -123,11 +153,13 @@
|
|
|
123
153
|
|
|
124
154
|
let slider_wrap_parent: HTMLDivElement;
|
|
125
155
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
156
|
+
function handle_image_load(size: {
|
|
157
|
+
top: number;
|
|
158
|
+
left: number;
|
|
159
|
+
width: number;
|
|
160
|
+
height: number;
|
|
161
|
+
}): void {
|
|
162
|
+
image_size = size;
|
|
131
163
|
}
|
|
132
164
|
</script>
|
|
133
165
|
|
|
@@ -144,7 +176,13 @@
|
|
|
144
176
|
onclick={() => zoomable_image?.reset_zoom()}
|
|
145
177
|
/>
|
|
146
178
|
{#if show_fullscreen_button}
|
|
147
|
-
<FullscreenButton
|
|
179
|
+
<FullscreenButton
|
|
180
|
+
{fullscreen}
|
|
181
|
+
onclick={(is_fullscreen) => {
|
|
182
|
+
fullscreen = is_fullscreen;
|
|
183
|
+
onfullscreen?.(is_fullscreen);
|
|
184
|
+
}}
|
|
185
|
+
/>
|
|
148
186
|
{/if}
|
|
149
187
|
|
|
150
188
|
{#if show_download_button}
|
|
@@ -161,7 +199,7 @@
|
|
|
161
199
|
label="Remove Image"
|
|
162
200
|
onclick={(event) => {
|
|
163
201
|
value = [null, null];
|
|
164
|
-
|
|
202
|
+
onclear?.();
|
|
165
203
|
event.stopPropagation();
|
|
166
204
|
}}
|
|
167
205
|
/>
|
|
@@ -189,7 +227,7 @@
|
|
|
189
227
|
transform="translate({$transform.x}px, {$transform.y}px) scale({$transform.z})"
|
|
190
228
|
{fullscreen}
|
|
191
229
|
{max_height}
|
|
192
|
-
|
|
230
|
+
onload={handle_image_load}
|
|
193
231
|
/>
|
|
194
232
|
<ImageEl
|
|
195
233
|
variant="preview"
|
|
@@ -202,7 +240,7 @@
|
|
|
202
240
|
transform="translate({$transform.x}px, {$transform.y}px) scale({$transform.z})"
|
|
203
241
|
{fullscreen}
|
|
204
242
|
{max_height}
|
|
205
|
-
|
|
243
|
+
onload={handle_image_load}
|
|
206
244
|
/>
|
|
207
245
|
</Slider>
|
|
208
246
|
</div>
|