",
22 | "license": "MIT",
23 | "repository": {
24 | "type": "git",
25 | "url": "git+https://github.com/LottieFiles/svelte-lottie-player.git"
26 | },
27 | "homepage": "https://github.com/LottieFiles/svelte-lottie-player",
28 | "bugs": {
29 | "url": "https://github.com/LottieFiles/svelte-lottie-player/issues"
30 | },
31 | "scripts": {
32 | "predev": "node -p \"'export const SVELTE_LOTTIE_PLAYER_VERSION = ' + JSON.stringify(require('./package.json').version) + '; \\n' + 'export const LOTTIE_WEB_VERSION = ' + JSON.stringify(require('./package.json').dependencies['lottie-web']) + ';'\" > src/components/versions.js",
33 | "dev": "rollup -c -w",
34 | "prebuild": "node -p \"'export const SVELTE_LOTTIE_PLAYER_VERSION = ' + JSON.stringify(require('./package.json').version) + '; \\n' + 'export const LOTTIE_WEB_VERSION = ' + JSON.stringify(require('./package.json').dependencies['lottie-web']) + ';'\" > src/components/versions.js",
35 | "build": "rollup -c",
36 | "prepublishOnly": "yarn build",
37 | "lint": "eslint src/",
38 | "lint:fix": "eslint src/ --fix",
39 | "storybook": "start-storybook -p 6006",
40 | "build-storybook": "build-storybook"
41 | },
42 | "devDependencies": {
43 | "@babel/core": "^7.9.6",
44 | "@rollup/plugin-commonjs": "11.1.0",
45 | "@rollup/plugin-node-resolve": "^7.1.3",
46 | "@rollup/plugin-strip": "^1.3.2",
47 | "@storybook/addon-a11y": "^5.3.18",
48 | "@storybook/addon-actions": "^5.3.18",
49 | "@storybook/addon-backgrounds": "^5.3.18",
50 | "@storybook/addon-knobs": "^5.3.18",
51 | "@storybook/addon-links": "^5.3.18",
52 | "@storybook/addon-storysource": "^5.3.18",
53 | "@storybook/addon-viewport": "^5.3.18",
54 | "@storybook/addons": "^5.3.18",
55 | "@storybook/source-loader": "^5.3.18",
56 | "@storybook/svelte": "^5.3.18",
57 | "babel-loader": "^8.1.0",
58 | "eslint": "^6.8.0",
59 | "eslint-plugin-svelte3": "^2.7.3",
60 | "husky": "^4.2.5",
61 | "lint-staged": "^10.2.2",
62 | "npm-run-all": "^4.1.5",
63 | "prettier": "^2.0.5",
64 | "prettier-plugin-svelte": "^0.7.0",
65 | "rollup": "^2.7.6",
66 | "rollup-plugin-svelte": "^6.1.1",
67 | "rollup-plugin-terser": "^5.3.0",
68 | "svelte": "^3.21.0",
69 | "svelte-loader": "^2.13.6"
70 | },
71 | "dependencies": {
72 | "lottie-web": "^5.10.0"
73 | },
74 | "files": [
75 | "src/components",
76 | "dist"
77 | ],
78 | "husky": {
79 | "hooks": {
80 | "pre-commit": "lint-staged"
81 | }
82 | },
83 | "lint-staged": {
84 | "*.{html, css, scss, stylus, js, ts, json, yml, md}": [
85 | "prettier --write"
86 | ],
87 | "*.{js, svelte}": [
88 | "eslint . --fix"
89 | ]
90 | },
91 | "publishConfig": {
92 | "access": "public"
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'avoid',
3 | bracketSpacing: true,
4 | endOfLine: 'lf',
5 | insertPragma: false,
6 | jsxBracketSameLine: false,
7 | printWidth: 120,
8 | proseWrap: 'always',
9 | requirePragma: false,
10 | semi: true,
11 | singleQuote: true,
12 | tabWidth: 2,
13 | trailingComma: 'all',
14 | useTabs: false,
15 | overrides: [
16 | {
17 | files: '*.json',
18 | options: {
19 | tabWidth: 2,
20 | singleQuote: false,
21 | },
22 | },
23 | ],
24 |
25 | // Svelte configs
26 | svelteSortOrder: 'styles-scripts-markup',
27 | svelteStrictMode: true,
28 | svelteBracketNewLine: true,
29 | svelteAllowShorthand: true,
30 | };
31 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import commonjs from '@rollup/plugin-commonjs';
2 | import resolve from '@rollup/plugin-node-resolve';
3 | import strip from '@rollup/plugin-strip';
4 | import svelte from 'rollup-plugin-svelte';
5 | import { terser } from 'rollup-plugin-terser';
6 |
7 | import pkg from './package.json';
8 |
9 | const isProduction = !process.env.ROLLUP_WATCH;
10 | const name = pkg.name
11 | .replace(/^(@\S+\/)?(svelte-)?(\S+)/, '$3')
12 | .replace(/^\w/, m => m.toUpperCase())
13 | .replace(/-\w/g, m => m[1].toUpperCase());
14 |
15 | export default {
16 | input: 'src/components/index.js',
17 | output: [
18 | {
19 | file: pkg.module,
20 | format: 'es',
21 | sourcemap: true,
22 | name,
23 | },
24 | {
25 | file: pkg.main,
26 | format: 'umd',
27 | sourcemap: true,
28 | name,
29 | },
30 | ],
31 | plugins: [
32 | // Strip assert and console.log statements
33 | strip(),
34 |
35 | svelte({
36 | // Enable run-time checks when not in production
37 | dev: !isProduction,
38 | }),
39 |
40 | // If you have external dependencies installed from
41 | // npm, you'll most likely need these plugins. In
42 | // some cases you'll need additional configuration —
43 | // consult the documentation for details:
44 | // https://github.com/rollup/plugins/tree/master/packages/commonjs
45 | resolve({
46 | browser: true,
47 | dedupe: importee => {
48 | return importee === 'svelte' || importee.startsWith('svelte/');
49 | },
50 | }),
51 | commonjs(),
52 |
53 | // In production mode, minify
54 | isProduction && terser(),
55 | ],
56 |
57 | watch: {
58 | clearScreen: true,
59 | },
60 | };
61 |
--------------------------------------------------------------------------------
/src/components/ColorPicker.svelte:
--------------------------------------------------------------------------------
1 |
59 |
60 |
116 |
117 |
118 |
135 |
136 |
137 |
138 | parseColor(e.target.value)} />
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/src/components/Controls.svelte:
--------------------------------------------------------------------------------
1 |
152 |
153 |
227 |
228 |
229 | {#each layout as item}
230 | {#if item === 'playpause'}
231 |
232 | {#if isPlaying}
233 |
234 |
235 |
236 |
237 | {:else}
238 |
239 |
240 |
241 | {/if}
242 |
243 | {:else if item === 'stop'}
244 |
252 | {:else if item === 'progress'}
253 |
268 | {:else if item === 'loop'}
269 |
270 |
271 |
281 |
295 |
296 |
297 | {:else if item === 'background'}
298 |
299 |
300 |
311 |
312 |
313 |
314 |
315 |
316 | {:else if item === 'snapshot'}
317 |
322 |
323 |
324 |
325 |
332 |
333 |
334 |
340 |
341 |
342 |
343 |
Frame {formattedFrame}
344 |
Download SVG
345 |
Download PNG
346 |
Scroll with mousewheel to find exact frame
347 |
348 |
349 |
350 | {:else if item === 'zoom'}
351 |
352 | {#if isZoomed}
353 |
354 |
360 |
361 | {:else}
362 |
363 |
369 |
370 | {/if}
371 |
372 | {:else if item === 'info'}
373 |
374 |
375 |
376 |
377 |
384 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 | {:else if item === 'frame'}
398 |
399 |
408 |
409 | {:else if item === 'nextFrame'}
410 |
411 |
412 |
416 |
417 |
418 |
419 | {:else if item === 'previousFrame'}
420 |
421 |
422 |
423 |
424 |
425 |
426 | {:else if item === 'spacer'}
427 |
428 | {/if}
429 | {/each}
430 |
431 |
--------------------------------------------------------------------------------
/src/components/Info.svelte:
--------------------------------------------------------------------------------
1 |
35 |
36 |
61 |
62 | Info
63 |
64 | {#if version}
65 |
66 | Lottie Version
67 | {version}
68 |
69 | {/if}
70 |
71 | {#if numFrames}
72 |
73 | Frames
74 | {numFrames}
75 |
76 | {/if}
77 |
78 | {#if frameRate}
79 |
80 | Frame Rate
81 | {frameRate}
82 |
83 | {/if}
84 |
85 | {#if numLayers}
86 |
87 | Layers
88 | {numLayers}
89 |
90 | {/if}
91 |
92 | {#if numAssets}
93 |
94 | Assets
95 | {numAssets}
96 |
97 | {/if}
98 |
99 | {#if numFonts}
100 |
101 | Fonts
102 | {numFonts}
103 |
104 | {/if}
105 |
106 | {#if hasMeta}
107 |
108 |
109 | {#if generator}
110 |
111 | Generator
112 | {generator}
113 |
114 | {/if}
115 |
116 | {#if author}
117 |
118 | Author
119 | {author}
120 |
121 | {/if}
122 |
123 | {#if keywords}
124 |
125 | Keywords
126 | {keywords}
127 |
128 | {/if}
129 |
130 | {#if themeColor}
131 |
132 | Theme Color
133 | {themeColor}
134 |
135 | {/if}
136 | {/if}
137 |
--------------------------------------------------------------------------------
/src/components/LottiePlayer.svelte:
--------------------------------------------------------------------------------
1 |
525 |
526 |
556 |
557 |
562 |
567 |
571 | {#if currentState === PlayerState.Error}
572 |
⚠️
573 | {/if}
574 |
575 | {#if controls}
576 |
setBackground(e.detail.color)}
578 | layout={controlsLayout}
579 | {animationData}
580 | {background}
581 | {controls}
582 | {currentState}
583 | {frame}
584 | {freeze}
585 | {instance}
586 | {loop}
587 | {lottie}
588 | {pause}
589 | {play}
590 | {progress}
591 | {seek}
592 | {setDirection}
593 | {setSpeed}
594 | {setLooping}
595 | {snapshot}
596 | {src}
597 | {stop}
598 | {toggleZoom}
599 | {toggleLooping}
600 | {togglePlay}
601 | {totalFrames} />
602 | {/if}
603 |
604 |
605 |
--------------------------------------------------------------------------------
/src/components/Popover.svelte:
--------------------------------------------------------------------------------
1 |
38 |
39 |
81 |
82 |
89 |
90 |
91 |
92 |
103 |
104 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import LottiePlayer from './LottiePlayer.svelte';
2 | import Controls from './Controls.svelte';
3 | import { parseSrc, PlayMode, PlayerEvents, PlayerState } from './utils';
4 |
5 | export {
6 | Controls,
7 | LottiePlayer,
8 | PlayerEvents,
9 | PlayerState,
10 | PlayMode,
11 | parseSrc,
12 | };
13 |
--------------------------------------------------------------------------------
/src/components/store.js:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | export const autoplay = writable();
4 | export const background = writable();
5 | export const controls = writable();
6 | export const loopCount = writable();
7 | export const defaultFrame = writable();
8 | export const direction = writable();
9 | export const hover = writable();
10 | export const loop = writable();
11 | export const mode = writable();
12 | export const speed = writable();
13 | export const state = writable();
14 |
15 | export const instance = writable();
16 | export const animationData = writable();
17 | export const frame = writable();
18 | export const progress = writable();
19 |
--------------------------------------------------------------------------------
/src/components/utils.js:
--------------------------------------------------------------------------------
1 | export const PlayerRender = {
2 | SVG: 'svg',
3 | Canvas: 'canvas'
4 | }
5 |
6 | // Define valid player states
7 | export const PlayerState = {
8 | Loading: 'loading',
9 | Playing: 'playing',
10 | Paused: 'paused',
11 | Stopped: 'stopped',
12 | Frozen: 'frozen',
13 | Error: 'error',
14 | };
15 |
16 | // Define play modes
17 | export const PlayMode = {
18 | Normal: 'normal',
19 | Bounce: 'bounce',
20 | };
21 |
22 | // Define player events
23 | export const PlayerEvents = {
24 | Load: 'load',
25 | Error: 'error',
26 | Ready: 'ready',
27 | Play: 'play',
28 | Pause: 'pause',
29 | Stop: 'stop',
30 | Freeze: 'freeze',
31 | Loop: 'loop',
32 | Complete: 'complete',
33 | Frame: 'frame',
34 | };
35 |
36 | // Define controls layout options
37 | export const ControlsLayoutOptions = [
38 | "previousFrame",
39 | "playpause",
40 | "stop",
41 | "nextFrame",
42 | "progress",
43 | "frame",
44 | "loop",
45 | "spacer",
46 | "background",
47 | "snapshot",
48 | "info",
49 | "zoom"
50 | ];
51 |
52 | /**
53 | * Parse a resource into a JSON object or a URL string
54 | */
55 | export const parseSrc = src => {
56 | if (typeof src === 'object') {
57 | return src;
58 | }
59 |
60 | try {
61 | return JSON.parse(src);
62 | } catch (e) {
63 | // Try construct an absolute URL from the src URL
64 | const srcUrl = new URL(src, window.location.href);
65 |
66 | return srcUrl.toString();
67 | }
68 | };
69 |
70 | /**
71 | * Trigger the download of the given data URI as a file
72 | *
73 | * @param {string} dataUri
74 | * @param {string} name
75 | */
76 | export const triggerDownload = (dataUri, filename) => {
77 | const element = document.createElement('a');
78 | element.href = dataUri;
79 | element.download = filename;
80 | document.body.appendChild(element);
81 |
82 | element.click();
83 |
84 | document.body.removeChild(element);
85 | };
86 |
--------------------------------------------------------------------------------
/src/components/versions.js:
--------------------------------------------------------------------------------
1 | export const SVELTE_LOTTIE_PLAYER_VERSION = "0.3.0";
2 | export const LOTTIE_WEB_VERSION = "^5.10.0";
3 |
--------------------------------------------------------------------------------
/src/stories/LottiePlayer.stories.js:
--------------------------------------------------------------------------------
1 | import { withKnobs, boolean, text, color, number, select } from '@storybook/addon-knobs';
2 |
3 | import LottiePlayer from './Wrapper.svelte';
4 | import { PlayMode, PlayerRender, ControlsLayoutOptions } from '../components/utils';
5 |
6 | export default {
7 | title: 'LottiePlayer',
8 | decorators: [withKnobs],
9 | };
10 |
11 | export const Basic = () => ({
12 | Component: LottiePlayer,
13 | props: {
14 | src: text('Lottie URL/JSON', 'https://assets2.lottiefiles.com/packages/lf20_wxUJzo.json'),
15 | renderer: select('Renderer', PlayerRender),
16 | autoplay: boolean('Auto Play', false),
17 | loop: boolean('Loop', true),
18 | mode: select('Playback mode', PlayMode),
19 | hover: boolean('Play on hover', false),
20 | background: color('Background', '#ffffff'),
21 | defaultFrame: number('Default Frame', 100),
22 | speed: number('Speed', 1),
23 | height: number('Height', ''),
24 | width: number('Width', 500),
25 | controls: boolean('Show Controls', true),
26 | controlsLayout: text('Controls Layout', ControlsLayoutOptions.join(',')),
27 | style: text('Styles', ''),
28 | }
29 | });
30 |
--------------------------------------------------------------------------------
/src/stories/Wrapper.svelte:
--------------------------------------------------------------------------------
1 |
29 |
30 |
37 |
38 | Lottie Player
39 | Load and play lottie animations
40 |
41 |
57 |
58 |
59 | Lorem Ipsum is simply dummy text of the printing and typesetting industry.
60 | Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
61 | when an unknown printer took a galley of type and scrambled it to make a type
62 | specimen book. It has survived not only five centuries, but also the leap into
63 | electronic typesetting, remaining essentially unchanged. It was popularised in
64 | the 1960s with the release of Letraset sheets containing Lorem Ipsum passages,
65 | and more recently with desktop publishing software like Aldus PageMaker
66 | including versions of Lorem Ipsum.
67 |
68 |
--------------------------------------------------------------------------------