mirror of
https://github.com/immich-app/immich.git
synced 2026-07-28 14:47:30 -07:00
80 lines
1.7 KiB
Svelte
80 lines
1.7 KiB
Svelte
<script lang="ts">
|
|
import { isFirefox } from '$lib/utils/asset-utils';
|
|
import { cancelImageUrl } from '$lib/utils/sw-messaging';
|
|
import { onDestroy, untrack } from 'svelte';
|
|
import type { HTMLImgAttributes } from 'svelte/elements';
|
|
|
|
type Props = Omit<HTMLImgAttributes, 'onload' | 'onerror'> & {
|
|
src: string | undefined;
|
|
onStart?: () => void;
|
|
onLoad?: () => void;
|
|
onError?: (error: Error) => void;
|
|
ref?: HTMLImageElement;
|
|
};
|
|
|
|
let { src, onStart, onLoad, onError, ref = $bindable(), ...rest }: Props = $props();
|
|
|
|
let capturedSource: string | undefined = $state();
|
|
let loaded = $state(false);
|
|
let destroyed = false;
|
|
|
|
$effect(() => {
|
|
if (src === undefined || capturedSource !== undefined) {
|
|
return;
|
|
}
|
|
|
|
capturedSource = src;
|
|
untrack(() => {
|
|
onStart?.();
|
|
});
|
|
});
|
|
|
|
onDestroy(() => {
|
|
destroyed = true;
|
|
if (capturedSource !== undefined) {
|
|
cancelImageUrl(capturedSource);
|
|
}
|
|
});
|
|
|
|
const completeLoad = () => {
|
|
if (destroyed) {
|
|
return;
|
|
}
|
|
loaded = true;
|
|
onLoad?.();
|
|
};
|
|
|
|
const handleLoad = () => {
|
|
if (destroyed || !src) {
|
|
return;
|
|
}
|
|
|
|
if (isFirefox && ref) {
|
|
ref.decode().then(completeLoad).catch(completeLoad);
|
|
return;
|
|
}
|
|
|
|
completeLoad();
|
|
};
|
|
|
|
const handleError = () => {
|
|
if (destroyed || !src) {
|
|
return;
|
|
}
|
|
onError?.(new Error(`Failed to load image: ${src}`));
|
|
};
|
|
</script>
|
|
|
|
{#if capturedSource}
|
|
{#key capturedSource}
|
|
<img
|
|
bind:this={ref}
|
|
src={capturedSource}
|
|
{...rest}
|
|
style:visibility={isFirefox && !loaded ? 'hidden' : undefined}
|
|
onload={handleLoad}
|
|
onerror={handleError}
|
|
/>
|
|
{/key}
|
|
{/if}
|