Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/clever-lizards-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"melt": patch
---

1. change avatar callbacks trigger order to fire before dom updates
2. add test suite for avatar
9 changes: 7 additions & 2 deletions docs/src/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -1717,22 +1717,27 @@
"properties": [
{
"name": "src",
"type": "string",
"type": "string | undefined",
"description": ""
},
{
"name": "delayMs",
"type": "number",
"description": ""
},
{
"name": "id",
"type": "string",
"description": ""
},
{
"name": "loadingStatus",
"type": "ImageLoadingStatus",
"description": ""
},
{
"name": "image",
"type": "{\n readonly \"data-melt-avatar-image\": \"\"\n readonly src: string\n readonly style: `display: ${string}`\n readonly onload: () => (() => void) | undefined\n readonly onerror: () => void\n}",
"type": "{\n readonly \"data-melt-avatar-image\": \"\"\n readonly src: string | undefined\n readonly style: `display: ${string}`\n readonly onload: () => (() => void) | undefined\n readonly onerror: () => void\n}",
"description": ""
},
{
Expand Down
6 changes: 3 additions & 3 deletions packages/melt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"test:headless": "vitest --browser.headless",
"sync": "svelte-kit sync",
"build": "npm run package",
"prepare": "svelte-kit sync || echo ''",
"preview": "vite preview",
"package": "svelte-kit sync && svelte-package && publint",
"prepublishOnly": "npm run package",
Expand All @@ -57,7 +58,6 @@
"@sveltejs/kit": "^2.15.2",
"@sveltejs/package": "^2.3.9",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"jsdom": "^24.1.0",
"publint": "^0.1.9",
"svelte": "5.34.8",
"svelte-check": "^4.1.3",
Expand All @@ -70,8 +70,8 @@
"@floating-ui/dom": "^1.6.13",
"dequal": "^2.0.3",
"focus-trap": "^7.6.5",
"jest-axe": "^9.0.0",
"runed": "^0.23.3"
"runed": "^0.23.3",
"vitest-axe": "1.0.0-pre.3"
},
"publishConfig": {
"access": "public"
Expand Down
38 changes: 27 additions & 11 deletions packages/melt/src/lib/builders/Avatar.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { extract } from "$lib/utils/extract";
import { createDataIds } from "$lib/utils/identifiers";
import { createBuilderMetadata, } from "$lib/utils/identifiers";
import { styleAttr } from "$lib/utils/attribute";
import { inBrowser } from "$lib/utils/browser";
import type { MaybeGetter } from "$lib/types";
import { watch } from "runed";

const identifiers = createDataIds("avatar", ["image", "fallback"]);
const { dataAttrs, createIds } = createBuilderMetadata("avatar", ["image", "fallback"]);

export type ImageLoadingStatus = "loading" | "loaded" | "error";

Expand All @@ -29,27 +29,43 @@ export type AvatarProps = {
};

export class Avatar {
#ids = createIds();
/* Props */
#props!: AvatarProps;
readonly src = $derived(extract(this.#props.src, ""));
readonly src = $derived(extract(this.#props.src, undefined));
readonly delayMs = $derived(extract(this.#props.delayMs, 0));

/* State */
#loadingStatus: ImageLoadingStatus = $state("loading");

constructor(props: AvatarProps = {}) {
$effect(() => {
this.#props.onLoadingStatusChange?.(this.#loadingStatus);
});
// Should be defined at the top before the effects
// when using $effect.pre or $watch.pre
this.#props = props;

watch(
// Run effects before dom updates
// for provide handlers with some execution time
watch.pre(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the $effect to watch.pre over here. It felt to me that onLoadingStatusChange should be running before the dom updates, as it might be contain other reactive updates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like a breaking change but I'm not really sure, need some advice

() => this.#loadingStatus,
() => {
this.#props.onLoadingStatusChange?.(this.#loadingStatus);
}
);

watch.pre(
() => this.src,
() => {
this.#loadingStatus = "loading";
this.#loadingStatus = "loading";
},
{
lazy: true
}
);

this.#props = props;
}

get id() {
return this.#ids.image;
}

get loadingStatus() {
Expand All @@ -58,7 +74,7 @@ export class Avatar {

get image() {
return {
[identifiers.image]: "",
[dataAttrs.image]: "",
src: this.src,
style: styleAttr({ display: this.#loadingStatus === "loaded" ? "block" : "none" }),
onload: () => {
Expand All @@ -76,7 +92,7 @@ export class Avatar {

get fallback() {
return {
[identifiers.fallback]: "",
[dataAttrs.fallback]: "",
style: this.#loadingStatus === "loaded" ? styleAttr({ display: "none" }) : undefined,
hidden: this.#loadingStatus === "loaded" ? true : undefined,
} as const;
Expand Down
Loading
Loading