UNPKG

melt

Version:

The next generation of Melt UI. Built for Svelte 5.

58 lines (57 loc) 1.89 kB
import { extract } from "../utils/extract"; import { createDataIds } from "../utils/identifiers"; import { styleAttr } from "../utils/attribute"; import { inBrowser } from "../utils/browser"; import { watch } from "runed"; import { createAttachmentKey } from "svelte/attachments"; 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"); #ak = createAttachmentKey(); #setLoadingStatus(s) { this.#loadingStatus = s; this.#props.onLoadingStatusChange?.(s); } constructor(props = {}) { this.#props = props; } get loadingStatus() { return this.#loadingStatus; } #attach = () => { watch(() => this.src, () => { this.#setLoadingStatus("loading"); }); }; 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.#setLoadingStatus("loaded"); }, this.delayMs); return () => window.clearTimeout(timerId); }, onerror: () => { this.#setLoadingStatus("error"); }, [this.#ak]: this.#attach, }; } get fallback() { return { [identifiers.fallback]: "", style: this.#loadingStatus === "loaded" ? styleAttr({ display: "none" }) : undefined, hidden: this.#loadingStatus === "loaded" ? true : undefined, }; } }