melt
Version:
The next generation of Melt UI. Built for Svelte 5.
52 lines (51 loc) • 1.72 kB
JavaScript
import { extract } from "../utils/extract";
import { createDataIds } from "../utils/identifiers";
import { styleAttr } from "../utils/attribute";
import { inBrowser } from "../utils/browser";
import { watch } from "runed";
const identifiers = createDataIds("avatar", ["image", "fallback"]);
export class Avatar {
/* Props */
#props;
src = $derived(extract(this.#props.src, ""));
delayMs = $derived(extract(this.#props.delayMs, 0));
/* State */
#loadingStatus = $state("loading");
constructor(props = {}) {
$effect(() => {
this.#props.onLoadingStatusChange?.(this.#loadingStatus);
});
watch(() => this.src, () => {
this.#loadingStatus = "loading";
});
this.#props = props;
}
get loadingStatus() {
return this.#loadingStatus;
}
get image() {
return {
[identifiers.image]: "",
src: this.src,
style: styleAttr({ display: this.#loadingStatus === "loaded" ? "block" : "none" }),
onload: () => {
if (!inBrowser())
return;
const timerId = window.setTimeout(() => {
this.#loadingStatus = "loaded";
}, this.delayMs);
return () => window.clearTimeout(timerId);
},
onerror: () => {
this.#loadingStatus = "error";
},
};
}
get fallback() {
return {
[identifiers.fallback]: "",
style: this.#loadingStatus === "loaded" ? styleAttr({ display: "none" }) : undefined,
hidden: this.#loadingStatus === "loaded" ? true : undefined,
};
}
}