diff --git a/.changeset/svelte-runes-migration.md b/.changeset/svelte-runes-migration.md
new file mode 100644
index 00000000..da7eb3af
--- /dev/null
+++ b/.changeset/svelte-runes-migration.md
@@ -0,0 +1,5 @@
+---
+"@lottiefiles/dotlottie-svelte": major
+---
+
+Migrate to Svelte 5 runes API and drop Svelte 4 support. The component now uses `$props()`, `$effect()`, and `$state` instead of `export let`, `$:`, and `on:event`. The `svelte` peer dependency is narrowed from `^4.0.0 || ^5.0.0` to `^5.0.0`.
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index 9ae84716..15d157df 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -41,26 +41,34 @@
"lint": "biome check .",
"format": "biome check --write .",
"stats:ts": "tsc -p tsconfig.build.json --extendedDiagnostics",
+ "test": "vitest run --browser.headless",
+ "test:coverage": "vitest run --browser.headless --coverage",
+ "test:watch": "vitest",
"type-check": "tsc --noEmit"
},
"peerDependencies": {
- "svelte": "^4.0.0 || ^5.0.0"
+ "svelte": "^5.0.0"
},
"dependencies": {
"@lottiefiles/dotlottie-web": "workspace:*"
},
"devDependencies": {
- "@sveltejs/adapter-auto": "^3.0.0",
- "@sveltejs/kit": "^2.0.0",
- "@sveltejs/package": "^2.0.0",
- "@sveltejs/vite-plugin-svelte": "^4.0.0",
- "publint": "^0.1.9",
- "svelte": "^5.0.0",
- "svelte-check": "^3.6.0",
+ "@sveltejs/adapter-auto": "^7.0.1",
+ "@sveltejs/kit": "^2.53.4",
+ "@sveltejs/package": "^2.5.7",
+ "@sveltejs/vite-plugin-svelte": "^6.2.4",
+ "@testing-library/user-event": "^14.5.2",
+ "@vitest/browser": "^4.0.18",
+ "@vitest/browser-playwright": "^4.0.18",
+ "@vitest/coverage-istanbul": "^4.0.18",
+ "publint": "^0.3.17",
+ "svelte": "^5.53.6",
+ "svelte-check": "^4.4.4",
"tslib": "^2.4.1",
"typescript": "5.9.3",
- "vite": "^5.0.13",
- "vitest": "^4.0.18"
+ "vite": "^7.3.1",
+ "vitest": "^4.0.18",
+ "vitest-browser-svelte": "^2.0.2"
},
"sideEffects": false,
"publishConfig": {
diff --git a/packages/svelte/setup-file.ts b/packages/svelte/setup-file.ts
new file mode 100644
index 00000000..327dba44
--- /dev/null
+++ b/packages/svelte/setup-file.ts
@@ -0,0 +1,7 @@
+import 'vitest-browser-svelte';
+import { setWasmUrl } from './src/lib/index.js';
+
+// eslint-disable-next-line node/no-unsupported-features/node-builtins
+const wasmUrl = new URL('../web/src/core/dotlottie-player.wasm?url', import.meta.url).href;
+
+setWasmUrl(wasmUrl);
diff --git a/packages/svelte/src/index.test.ts b/packages/svelte/src/index.test.ts
deleted file mode 100644
index aa934263..00000000
--- a/packages/svelte/src/index.test.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { describe, expect, it } from 'vitest';
-
-describe('sum test', () => {
- it('adds 1 + 2 to equal 3', () => {
- expect(1 + 2).toBe(3);
- });
-});
diff --git a/packages/svelte/src/lib/Dotlottie.svelte b/packages/svelte/src/lib/Dotlottie.svelte
index c45e2674..d7024f62 100644
--- a/packages/svelte/src/lib/Dotlottie.svelte
+++ b/packages/svelte/src/lib/Dotlottie.svelte
@@ -1,213 +1,278 @@
diff --git a/packages/svelte/src/routes/+page.svelte b/packages/svelte/src/routes/+page.svelte
index 50917ac7..6b3af4c7 100644
--- a/packages/svelte/src/routes/+page.svelte
+++ b/packages/svelte/src/routes/+page.svelte
@@ -5,37 +5,37 @@ import { DotLottieSvelte, setWasmUrl } from '../lib/index.js';
setWasmUrl(wasmUrl);
-let dotLottie: DotLottie | undefined;
-let isLoaded = false;
-let isPlaying = false;
-let isPaused = false;
-let isStopped = false;
-let isFrozen = false;
-let loop = true;
-let backgroundColor = '#00000000';
-let speed = 1;
-let hasMultipleAnimations = false;
-let src = 'https://lottie.host/b06d1336-2c08-4156-aa6f-96f08ff511e0/4itF1pXb1i.lottie';
-let activeAnimationIdx = 0;
-let animations: string[] = [];
-let themes: string[] = [];
-let activeAnimationId = '';
-let activeThemeId = '';
+let dotLottie: DotLottie | undefined = $state(undefined);
+let isLoaded = $state(false);
+let isPlaying = $state(false);
+let isPaused = $state(false);
+let isStopped = $state(false);
+let isFrozen = $state(false);
+let loop = $state(true);
+let backgroundColor = $state('#00000000');
+let speed = $state(1);
+let hasMultipleAnimations = $state(false);
+let src = $state('https://lottie.host/b06d1336-2c08-4156-aa6f-96f08ff511e0/4itF1pXb1i.lottie');
+let activeAnimationIdx = $state(0);
+let animations: string[] = $state([]);
+let themes: string[] = $state([]);
+let activeAnimationId = $state('');
+let activeThemeId = $state('');
function dotLottieRefCallback(ref: DotLottie) {
dotLottie = ref;
}
const next = () => {
- const animations = dotLottie?.manifest?.animations;
- if (animations?.length) {
- activeAnimationIdx = (activeAnimationIdx + 1) % animations.length;
- const animationId = animations[activeAnimationIdx]?.id || '';
+ const anims = dotLottie?.manifest?.animations;
+ if (anims?.length) {
+ activeAnimationIdx = (activeAnimationIdx + 1) % anims.length;
+ const animationId = anims[activeAnimationIdx]?.id || '';
if (animationId) dotLottie?.loadAnimation(animationId);
}
};
-$: {
+$effect(() => {
if (dotLottie) {
dotLottie.addEventListener('load', () => {
isLoaded = true;
@@ -71,30 +71,30 @@ $: {
isFrozen = false;
});
}
-}
+});
-