Skip to content

Commit 740cdde

Browse files
committed
add Lottie
1 parent 5042d78 commit 740cdde

7 files changed

Lines changed: 130 additions & 3 deletions

File tree

package-lock.json

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"type": "module",
2222
"exports": {
2323
".": {
24-
"development": "./src/lib/index.js",
24+
"development": "./src/lib/index.js",
2525
"types": "./dist/index.d.ts",
2626
"svelte": "./dist/index.js"
2727
}
@@ -43,6 +43,7 @@
4343
"svelte"
4444
],
4545
"dependencies": {
46-
"@asamuzakjp/css-color": "^4.1.0"
46+
"@asamuzakjp/css-color": "^4.1.0",
47+
"lottie-web": "^5.13.0"
4748
}
4849
}

src/lib/Lottie.svelte

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<script>
2+
// NOTE: for some reason we have to do this ugly mess for typings
3+
import * as _lottie from 'lottie-web';
4+
/** @type {import("lottie-web").LottiePlayer} */
5+
const lottie = _lottie.default;
6+
7+
/**
8+
* @callback AnimationCallback
9+
* @param {import("lottie-web").AnimationItem} animation
10+
* @returns {void}
11+
*/
12+
/**
13+
* @typedef {Object} Properties
14+
* @property {string?} src Lottie src to display
15+
* @property {boolean?} autoplay
16+
* @property {number|boolean?} loop
17+
* @property {number?} speed
18+
* @property {import("lottie-web").AnimationSegment?} initialSegment
19+
* @property {AnimationCallback} animationRef Get a reference to the Lottie AnimationItem.
20+
*/
21+
/** @type {Properties} */
22+
const props = $props();
23+
24+
let container;
25+
let loaded = $state(false);
26+
$effect(() => {
27+
const animation = lottie.loadAnimation({
28+
container: container,
29+
renderer: 'svg',
30+
31+
path: props.src,
32+
autoplay: props.autoplay,
33+
loop: props.loop,
34+
speed: props.speed,
35+
initialSegment: props.initialSegment,
36+
});
37+
if (typeof props.speed === "number") animation.setSpeed(props.speed);
38+
animation.addEventListener("error", () => {
39+
loaded = false;
40+
});
41+
animation.addEventListener("DOMLoaded", () => {
42+
loaded = true;
43+
});
44+
45+
if (props.animationRef) props.animationRef(animation);
46+
return () => animation.destroy();
47+
});
48+
</script>
49+
50+
<div
51+
{...props}
52+
class="lottie"
53+
data-penguinmodsvelteui-lottie="true"
54+
bind:this={container}
55+
>
56+
{#if !loaded}
57+
<div
58+
class="lottie-placeholder"
59+
data-penguinmodsvelteui-lottie-placeholder="true"
60+
>
61+
{@render props.children?.()}
62+
</div>
63+
{/if}
64+
</div>
65+
66+
<style>
67+
.lottie {
68+
position: relative;
69+
}
70+
.lottie-placeholder {
71+
position: absolute;
72+
}
73+
</style>

src/lib/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import Category from "./Category.svelte";
44
import SwappableHolder from "./SwappableHolder.svelte";
55
import UserDisplay from "./UserDisplay.svelte";
66
import Project from "./Project.svelte";
7+
import Lottie from "./Lottie.svelte";
78

89
export {
910
Button,
1011
Category,
1112
SwappableHolder,
1213
UserDisplay,
1314
Project,
15+
Lottie,
1416
};

src/routes/lottie/+page.svelte

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<script>
2+
import * as PenguinModSvelteUI from "$lib/index.js";
3+
import testLottie1 from "./lottie1.json";
4+
import testLottie2 from "./lottie2.json";
5+
6+
const testLottieURI1 = `data:application/json;,${encodeURIComponent(JSON.stringify(testLottie1))}`;
7+
const testLottieURI2 = `data:application/json;,${encodeURIComponent(JSON.stringify(testLottie2))}`;
8+
9+
// svelte-ignore non_reactive_update
10+
/** @type {import("lottie-web").AnimationItem} */
11+
let controlTestLottie;
12+
let controlTestLottieSrc = $state(testLottieURI1);
13+
</script>
14+
15+
<h1>Lottie</h1>
16+
<PenguinModSvelteUI.Lottie src={testLottieURI1}>
17+
<p>Loading</p>
18+
</PenguinModSvelteUI.Lottie>
19+
<PenguinModSvelteUI.Lottie src={testLottieURI1} autoplay>
20+
<p>Loading</p>
21+
</PenguinModSvelteUI.Lottie>
22+
<PenguinModSvelteUI.Lottie src={testLottieURI1} autoplay speed={8}>
23+
<p>Loading</p>
24+
</PenguinModSvelteUI.Lottie>
25+
<PenguinModSvelteUI.Lottie src={testLottieURI1} autoplay loop>
26+
<p>Loading</p>
27+
</PenguinModSvelteUI.Lottie>
28+
<PenguinModSvelteUI.Lottie src={testLottieURI1} autoplay loop={false}>
29+
<p>Loading</p>
30+
</PenguinModSvelteUI.Lottie>
31+
<hr>
32+
<PenguinModSvelteUI.Lottie src={"about:blank"}>
33+
<p>this will not render</p>
34+
</PenguinModSvelteUI.Lottie>
35+
<hr>
36+
<PenguinModSvelteUI.Lottie src={controlTestLottieSrc} animationRef={(animation) => { controlTestLottie = animation; }}>
37+
<p>Controllable</p>
38+
</PenguinModSvelteUI.Lottie>
39+
<button onclick={() => { controlTestLottieSrc = controlTestLottieSrc === testLottieURI1 ? testLottieURI2 : testLottieURI1; }}>Swap SRC</button>
40+
<button onclick={() => controlTestLottie.play()}>Play</button>
41+
<button onclick={() => controlTestLottie.pause()}>Pause</button>
42+
<button onclick={() => controlTestLottie.stop()}>Stop</button>

src/routes/lottie/lottie1.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

src/routes/lottie/lottie2.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)