@aarsteinmedia/dotlottie-player 4.0.13 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js DELETED
@@ -1,1777 +0,0 @@
1
- import { strToU8, strFromU8, zip, unzip as unzip$1 } from 'fflate';
2
- import * as Lottie from 'lottie-web/build/player/lottie.js';
3
-
4
- var ObjectFit = /*#__PURE__*/ function(ObjectFit) {
5
- ObjectFit["Contain"] = "contain";
6
- ObjectFit["Cover"] = "cover";
7
- ObjectFit["Fill"] = "fill";
8
- ObjectFit["ScaleDown"] = "scale-down";
9
- ObjectFit["None"] = "none";
10
- return ObjectFit;
11
- }({});
12
- var PlayerState = /*#__PURE__*/ function(PlayerState) {
13
- PlayerState["Completed"] = "completed";
14
- PlayerState["Destroyed"] = "destroyed";
15
- PlayerState["Error"] = "error";
16
- PlayerState["Frozen"] = "frozen";
17
- PlayerState["Loading"] = "loading";
18
- PlayerState["Paused"] = "paused";
19
- PlayerState["Playing"] = "playing";
20
- PlayerState["Stopped"] = "stopped";
21
- return PlayerState;
22
- }({});
23
- var PlayMode = /*#__PURE__*/ function(PlayMode) {
24
- PlayMode["Bounce"] = "bounce";
25
- PlayMode["Normal"] = "normal";
26
- return PlayMode;
27
- }({});
28
- var PlayerEvents = /*#__PURE__*/ function(PlayerEvents) {
29
- PlayerEvents["Complete"] = "complete";
30
- PlayerEvents["Destroyed"] = "destroyed";
31
- PlayerEvents["Error"] = "error";
32
- PlayerEvents["Frame"] = "frame";
33
- PlayerEvents["Freeze"] = "freeze";
34
- PlayerEvents["Load"] = "load";
35
- PlayerEvents["Loop"] = "loop";
36
- PlayerEvents["Next"] = "next";
37
- PlayerEvents["Pause"] = "pause";
38
- PlayerEvents["Play"] = "play";
39
- PlayerEvents["Previous"] = "previous";
40
- PlayerEvents["Ready"] = "ready";
41
- PlayerEvents["Rendered"] = "rendered";
42
- PlayerEvents["Stop"] = "stop";
43
- return PlayerEvents;
44
- }({});
45
- var PreserveAspectRatio = /*#__PURE__*/ function(PreserveAspectRatio) {
46
- PreserveAspectRatio["Contain"] = "xMidYMid meet";
47
- PreserveAspectRatio["Cover"] = "xMidYMid slice";
48
- PreserveAspectRatio["None"] = "xMinYMin slice";
49
- PreserveAspectRatio["Initial"] = "none";
50
- return PreserveAspectRatio;
51
- }({});
52
-
53
- class CustomError extends Error {
54
- }
55
- const addExt = (ext, str)=>{
56
- if (!str) {
57
- return;
58
- }
59
- if (getExt(str)) {
60
- if (getExt(str) === ext) {
61
- return str;
62
- }
63
- return `${getFilename(str)}.${ext}`;
64
- }
65
- return `${str}.${ext}`;
66
- }, aspectRatio = (objectFit)=>{
67
- switch(objectFit){
68
- case ObjectFit.Contain:
69
- case ObjectFit.ScaleDown:
70
- return 'xMidYMid meet';
71
- case ObjectFit.Cover:
72
- return 'xMidYMid slice';
73
- case ObjectFit.Fill:
74
- return 'none';
75
- case ObjectFit.None:
76
- return 'xMinYMin slice';
77
- default:
78
- return 'xMidYMid meet';
79
- }
80
- }, /**
81
- * Convert Base64 encoded string to Uint8Array
82
- * @param { string } str Base64 encoded string
83
- * @returns { Uint8Array } UTF-8/Latin-1 binary
84
- */ base64ToU8 = (str)=>strToU8(isServer() ? Buffer.from(parseBase64(str), 'base64').toString('binary') : atob(parseBase64(str)), true), /**
85
- * Convert a JSON Lottie to dotLottie or combine several animations and download new dotLottie file in your browser.
86
- */ createDotLottie = async ({ animations, fileName, manifest, shouldDownload = true })=>{
87
- try {
88
- // Input validation
89
- if (!animations?.length || !manifest) {
90
- throw new Error(`Missing or malformed required parameter(s):\n ${animations?.length ? '- manifest\n' : ''} ${manifest ? '- animations\n' : ''}`);
91
- }
92
- const manifestCompressionLevel = 0, animationCompressionLevel = 9, // Prepare the dotLottie file
93
- name = addExt('lottie', fileName) || `${useId()}.lottie`, dotlottie = {
94
- 'manifest.json': [
95
- strToU8(JSON.stringify(manifest), true),
96
- {
97
- level: manifestCompressionLevel
98
- }
99
- ]
100
- };
101
- // Add animations and assets to the dotLottie file
102
- for (const [i, animation] of animations.entries()){
103
- for (const asset of animation.assets ?? []){
104
- if (!asset.p || !isImage(asset) && !isAudio(asset)) {
105
- continue;
106
- }
107
- const { p: file, u: path } = asset, // Original asset.id caused issues with multianimations
108
- assetId = useId('asset'), isEncoded = file.startsWith('data:'), ext = isEncoded ? getExtFromB64(file) : getExt(file), // Check if the asset is already base64-encoded. If not, get path, fetch it, and encode it
109
- dataURL = isEncoded ? file : await fileToBase64(path ? path.endsWith('/') && `${path}${file}` || `${path}/${file}` : file);
110
- asset.p = `${assetId}.${ext}`;
111
- // Asset is embedded, so path empty string
112
- asset.u = '';
113
- // Asset is encoded
114
- asset.e = 1;
115
- dotlottie[`${isAudio(asset) ? 'audio' : 'images'}/${assetId}.${ext}`] = [
116
- base64ToU8(dataURL),
117
- {
118
- level: animationCompressionLevel
119
- }
120
- ];
121
- }
122
- dotlottie[`animations/${manifest.animations[i].id}.json`] = [
123
- strToU8(JSON.stringify(animation), true),
124
- {
125
- level: animationCompressionLevel
126
- }
127
- ];
128
- }
129
- const buffer = await getArrayBuffer(dotlottie);
130
- return shouldDownload ? download(buffer, {
131
- mimeType: 'application/zip',
132
- name
133
- }) : buffer;
134
- } catch (err) {
135
- console.error(`❌ ${handleErrors(err).message}`);
136
- }
137
- }, createJSON = ({ animation, fileName, shouldDownload })=>{
138
- try {
139
- if (!animation) {
140
- throw new Error("Missing or malformed required parameter(s):\n - animation\n'");
141
- }
142
- const name = addExt('json', fileName) || `${useId()}.json`, jsonString = JSON.stringify(animation);
143
- return shouldDownload ? download(jsonString, {
144
- mimeType: 'application/json',
145
- name
146
- }) : jsonString;
147
- } catch (err) {
148
- console.error(`❌ ${handleErrors(err).message}`);
149
- }
150
- }, /**
151
- * Download file, either SVG or dotLottie.
152
- * @param { string } data The data to be downloaded
153
- * @param { string } name Don't include file extension in the filename
154
- */ download = (data, options)=>{
155
- const blob = new Blob([
156
- data
157
- ], {
158
- type: options?.mimeType
159
- }), fileName = options?.name || useId(), dataURL = URL.createObjectURL(blob), link = document.createElement('a');
160
- link.href = dataURL;
161
- link.download = fileName;
162
- link.hidden = true;
163
- document.body.appendChild(link);
164
- link.click();
165
- setTimeout(()=>{
166
- link.remove();
167
- URL.revokeObjectURL(dataURL);
168
- }, 1000);
169
- }, fileToBase64 = async (url)=>{
170
- const response = await fetch(url), blob = await response.blob();
171
- return new Promise((resolve, reject)=>{
172
- try {
173
- const reader = new FileReader();
174
- reader.onload = ()=>{
175
- if (typeof reader.result === 'string') {
176
- resolve(reader.result);
177
- return;
178
- }
179
- reject();
180
- };
181
- reader.readAsDataURL(blob);
182
- } catch (e) {
183
- reject(e);
184
- }
185
- });
186
- }, frameOutput = (frame)=>((frame ?? 0) + 1).toString().padStart(3, '0'), getAnimationData = async (input)=>{
187
- try {
188
- if (!input || typeof input !== 'string' && typeof input !== 'object') {
189
- throw new Error('Broken file or invalid file format');
190
- }
191
- if (typeof input !== 'string') {
192
- const animations = Array.isArray(input) ? input : [
193
- input
194
- ];
195
- return {
196
- animations,
197
- isDotLottie: false,
198
- manifest: undefined
199
- };
200
- }
201
- const result = await fetch(input, {
202
- headers: {
203
- 'Content-Type': 'application/json; charset=UTF-8'
204
- }
205
- });
206
- if (!result.ok) {
207
- const error = new CustomError(result.statusText);
208
- error.status = result.status;
209
- throw error;
210
- }
211
- /**
212
- * Check if file is JSON, first by parsing file name for extension,
213
- * then – if filename has no extension – by cloning the response
214
- * and parsing it for content.
215
- */ const ext = getExt(input);
216
- if (ext === 'json' || !ext) {
217
- if (ext) {
218
- const lottie = await result.json();
219
- return {
220
- animations: [
221
- lottie
222
- ],
223
- isDotLottie: false,
224
- manifest: undefined
225
- };
226
- }
227
- const text = await result.clone().text();
228
- try {
229
- const lottie = JSON.parse(text);
230
- return {
231
- animations: [
232
- lottie
233
- ],
234
- isDotLottie: false,
235
- manifest: undefined
236
- };
237
- } catch (_e) {
238
- /* empty */ }
239
- }
240
- const { data, manifest } = await getLottieJSON(result);
241
- return {
242
- animations: data,
243
- isDotLottie: true,
244
- manifest
245
- };
246
- } catch (err) {
247
- console.error(`❌ ${handleErrors(err).message}`);
248
- return {
249
- animations: undefined,
250
- isDotLottie: false,
251
- manifest: undefined
252
- };
253
- }
254
- }, getArrayBuffer = async (zippable)=>{
255
- const arrayBuffer = await new Promise((resolve, reject)=>{
256
- zip(zippable, {
257
- level: 9
258
- }, (err, data)=>{
259
- if (err) {
260
- reject(err);
261
- return;
262
- }
263
- if (!(data.buffer instanceof ArrayBuffer)) {
264
- reject('Data is not transferable');
265
- return;
266
- }
267
- resolve(data.buffer);
268
- });
269
- });
270
- return arrayBuffer;
271
- }, /**
272
- * Get extension from filename, URL or path
273
- * @param { string } str Filename, URL or path
274
- */ getExt = (str)=>{
275
- if (typeof str !== 'string' || !str || !hasExt(str)) {
276
- return;
277
- }
278
- return str.split('.').pop()?.toLowerCase();
279
- }, getExtFromB64 = (str)=>{
280
- const mime = str.split(':')[1].split(';')[0], ext = mime.split('/')[1].split('+')[0];
281
- return ext;
282
- }, /**
283
- * Parse URL to get filename
284
- * @param { string } src The url string
285
- * @param { boolean } keepExt Whether to include file extension
286
- * @returns { string } Filename, in lowercase
287
- */ getFilename = (src, keepExt)=>{
288
- // Because the regex strips all special characters, we need to extract the file extension, so we can add it later if we need it
289
- getExt(src);
290
- return `${src.split('/').pop()?.replace(/\.[^.]*$/, '').replace(/\W+/g, '-')}${''}` // .toLowerCase()
291
- ;
292
- }, getLottieJSON = async (resp)=>{
293
- const unzipped = await unzip(resp), manifest = getManifest(unzipped), data = [], toResolve = [];
294
- for (const { id } of manifest.animations){
295
- const str = strFromU8(unzipped[`animations/${id}.json`]), lottie = JSON.parse(prepareString(str));
296
- toResolve.push(resolveAssets(unzipped, lottie.assets));
297
- data.push(lottie);
298
- }
299
- await Promise.all(toResolve);
300
- return {
301
- data,
302
- manifest
303
- };
304
- }, getManifest = (unzipped)=>{
305
- const file = strFromU8(unzipped['manifest.json'], false), manifest = JSON.parse(file);
306
- if (!('animations' in manifest)) {
307
- throw new Error('Manifest not found');
308
- }
309
- if (!manifest.animations.length) {
310
- throw new Error('No animations listed in manifest');
311
- }
312
- return manifest;
313
- }, getMimeFromExt = (ext)=>{
314
- switch(ext){
315
- case 'svg':
316
- case 'svg+xml':
317
- return 'image/svg+xml';
318
- case 'jpg':
319
- case 'jpeg':
320
- return 'image/jpeg';
321
- case 'png':
322
- case 'gif':
323
- case 'webp':
324
- case 'avif':
325
- return `image/${ext}`;
326
- case 'mp3':
327
- case 'mpeg':
328
- case 'wav':
329
- return `audio/${ext}`;
330
- default:
331
- return '';
332
- }
333
- }, handleErrors = (err)=>{
334
- const res = {
335
- message: 'Unknown error',
336
- status: isServer() ? 500 : 400
337
- };
338
- if (err && typeof err === 'object') {
339
- if ('message' in err && typeof err.message === 'string') {
340
- res.message = err.message;
341
- }
342
- if ('status' in err) {
343
- res.status = Number(err.status);
344
- }
345
- }
346
- return res;
347
- }, hasExt = (path)=>{
348
- const lastDotIndex = path?.split('/').pop()?.lastIndexOf('.');
349
- return (lastDotIndex ?? 0) > 1 && path && path.length - 1 > (lastDotIndex ?? 0);
350
- }, isAudio = (asset)=>!('h' in asset) && !('w' in asset) && 'p' in asset && 'e' in asset && 'u' in asset && 'id' in asset, isBase64 = (str)=>{
351
- if (!str) {
352
- return false;
353
- }
354
- const regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
355
- return regex.test(parseBase64(str));
356
- }, isImage = (asset)=>'w' in asset && 'h' in asset && !('xt' in asset) && 'p' in asset, isServer = ()=>!(typeof window !== 'undefined' && window.document), parseBase64 = (str)=>str.substring(str.indexOf(',') + 1), prepareString = (str)=>str.replace(new RegExp(/"""/, 'g'), '""').replace(/(["'])(.*?)\1/g, (_match, quote, content)=>{
357
- const replacedContent = content.replace(/[^\w\s\d.#]/g, '');
358
- return `${quote}${replacedContent}${quote}`;
359
- }), resolveAssets = async (unzipped, assets)=>{
360
- if (!Array.isArray(assets)) {
361
- return;
362
- }
363
- const toResolve = [];
364
- for (const asset of assets){
365
- if (!isAudio(asset) && !isImage(asset)) {
366
- continue;
367
- }
368
- const type = isImage(asset) ? 'images' : 'audio', u8 = unzipped?.[`${type}/${asset.p}`];
369
- if (!u8) {
370
- continue;
371
- }
372
- toResolve.push(new Promise((resolveAsset)=>{
373
- const assetB64 = isServer() ? Buffer.from(u8).toString('base64') : btoa(u8.reduce((dat, byte)=>`${dat}${String.fromCharCode(byte)}`, ''));
374
- asset.p = asset.p?.startsWith('data:') || isBase64(asset.p) ? asset.p : `data:${getMimeFromExt(getExt(asset.p))};base64,${assetB64}`;
375
- asset.e = 1;
376
- asset.u = '';
377
- resolveAsset();
378
- }));
379
- }
380
- await Promise.all(toResolve);
381
- }, unzip = async (resp)=>{
382
- const u8 = new Uint8Array(await resp.arrayBuffer()), unzipped = await new Promise((resolve, reject)=>{
383
- unzip$1(u8, /* { filter }, */ (err, file)=>{
384
- if (err) {
385
- reject(err);
386
- }
387
- resolve(file);
388
- });
389
- });
390
- return unzipped;
391
- }, useId = (prefix)=>{
392
- const s4 = ()=>((1 + Math.random()) * 0x10000 | 0).toString(16).substring(1);
393
- return `${prefix ?? `:${s4()}`}_${s4()}`;
394
- };
395
-
396
- /**
397
- * Render Player
398
- */ function renderPlayer() {
399
- this.template.innerHTML = /* HTML */ `<div class="animation-container main" data-controls="${this.controls ?? false}" lang="${this.description ? document?.documentElement?.lang : 'en'}" aria-label="${this.description ?? 'Lottie animation'}" data-loaded="${this._playerState.loaded}"><figure class="animation" style="background:${this.background}">${this.playerState === PlayerState.Error ? /* HTML */ `<div class="error"><svg preserveAspectRatio="xMidYMid slice" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="1920" height="1080" viewBox="0 0 1920 1080"><path fill="#fff" d="M0 0h1920v1080H0z"/><path fill="#3a6d8b" d="M1190.2 531 1007 212.4c-22-38.2-77.2-38-98.8.5L729.5 531.3c-21.3 37.9 6.1 84.6 49.5 84.6l361.9.3c43.7 0 71.1-47.3 49.3-85.2zM937.3 288.7c.2-7.5 3.3-23.9 23.2-23.9 16.3 0 23 16.1 23 23.5 0 55.3-10.7 197.2-12.2 214.5-.1 1-.9 1.7-1.9 1.7h-18.3c-1 0-1.8-.7-1.9-1.7-1.4-17.5-13.4-162.9-11.9-214.1zm24.2 283.8c-13.1 0-23.7-10.6-23.7-23.7s10.6-23.7 23.7-23.7 23.7 10.6 23.7 23.7-10.6 23.7-23.7 23.7zM722.1 644h112.6v34.4h-70.4V698h58.8v31.7h-58.8v22.6h72.4v36.2H722.1V644zm162 57.1h.6c8.3-12.9 18.2-17.8 31.3-17.8 3 0 5.1.4 6.3 1v32.6h-.8c-22.4-3.8-35.6 6.3-35.6 29.5v42.3h-38.2V685.5h36.4v15.6zm78.9 0h.6c8.3-12.9 18.2-17.8 31.3-17.8 3 0 5.1.4 6.3 1v32.6h-.8c-22.4-3.8-35.6 6.3-35.6 29.5v42.3h-38.2V685.5H963v15.6zm39.5 36.2c0-31.3 22.2-54.8 56.6-54.8 34.4 0 56.2 23.5 56.2 54.8s-21.8 54.6-56.2 54.6c-34.4-.1-56.6-23.3-56.6-54.6zm74 0c0-17.4-6.1-29.1-17.8-29.1-11.7 0-17.4 11.7-17.4 29.1 0 17.4 5.7 29.1 17.4 29.1s17.8-11.8 17.8-29.1zm83.1-36.2h.6c8.3-12.9 18.2-17.8 31.3-17.8 3 0 5.1.4 6.3 1v32.6h-.8c-22.4-3.8-35.6 6.3-35.6 29.5v42.3h-38.2V685.5h36.4v15.6z"/><path fill="none" d="M718.9 807.7h645v285.4h-645z"/><text fill="#3a6d8b" style="text-align:center;position:absolute;left:100%;font-size:47px;font-family:system-ui,-apple-system,BlinkMacSystemFont,'.SFNSText-Regular',sans-serif" x="50%" y="848.017" text-anchor="middle">${this._errorMessage}</text></svg></div>` : ''}</figure><slot name="controls"></slot></div>`;
400
- this.shadow.adoptedStyleSheets = [
401
- DotLottiePlayer.styles
402
- ];
403
- this.shadow.appendChild(this.template.content.cloneNode(true));
404
- }
405
-
406
- /**
407
- * Render Controls
408
- */ function renderControls() {
409
- const slot = this.shadow.querySelector('slot[name=controls]');
410
- if (!slot) {
411
- return;
412
- }
413
- if (!this.controls) {
414
- slot.innerHTML = '';
415
- return;
416
- }
417
- slot.innerHTML = /* HTML */ `<div class="lottie-controls toolbar ${this.playerState === PlayerState.Error ? 'has-error' : ''}" aria-label="Lottie Animation controls"><button class="togglePlay" data-active="false" aria-label="Toggle Play/Pause"><svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M8.016 5.016L18.985 12 8.016 18.984V5.015z"/></svg></button> <button class="stop" data-active="true" aria-label="Stop"><svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M6 6h12v12H6V6z"/></svg></button> <button class="prev" aria-label="Previous animation" hidden><svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M17.9 18.2 8.1 12l9.8-6.2v12.4zm-10.3 0H6.1V5.8h1.5v12.4z"/></svg></button> <button class="next" aria-label="Next animation" hidden><svg width="24" height="24" aria-hidden="true" focusable="false"><path d="m6.1 5.8 9.8 6.2-9.8 6.2V5.8zM16.4 5.8h1.5v12.4h-1.5z"/></svg></button><form class="progress-container${this.simple ? ' simple' : ''}"><input class="seeker" type="range" min="0" max="100" step="1" value="${this._seeker.toString()}" aria-valuemin="0" aria-valuemax="100" role="slider" aria-valuenow="${this._seeker.toString()}" tabindex="0" aria-label="Slider for search"><progress max="100" value="${this._seeker}"></progress></form>${this.simple ? '' : /* HTML */ `<button class="toggleLoop" data-active="${this.loop}" tabindex="0" aria-label="Toggle loop"><svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M17.016 17.016v-4.031h1.969v6h-12v3l-3.984-3.984 3.984-3.984v3h10.031zM6.984 6.984v4.031H5.015v-6h12v-3l3.984 3.984-3.984 3.984v-3H6.984z"/></svg></button> <button class="toggleBoomerang" data-active="${this.mode === PlayMode.Bounce}" aria-label="Toggle boomerang" tabindex="0"><svg width="24" height="24" aria-hidden="true" focusable="false"><path d="m11.8 13.2-.3.3c-.5.5-1.1 1.1-1.7 1.5-.5.4-1 .6-1.5.8-.5.2-1.1.3-1.6.3s-1-.1-1.5-.3c-.6-.2-1-.5-1.4-1-.5-.6-.8-1.2-.9-1.9-.2-.9-.1-1.8.3-2.6.3-.7.8-1.2 1.3-1.6.3-.2.6-.4 1-.5.2-.2.5-.2.8-.3.3 0 .7-.1 1 0 .3 0 .6.1.9.2.9.3 1.7.9 2.4 1.5.4.4.8.7 1.1 1.1l.1.1.4-.4c.6-.6 1.2-1.2 1.9-1.6.5-.3 1-.6 1.5-.7.4-.1.7-.2 1-.2h.9c1 .1 1.9.5 2.6 1.4.4.5.7 1.1.8 1.8.2.9.1 1.7-.2 2.5-.4.9-1 1.5-1.8 2-.4.2-.7.4-1.1.4-.4.1-.8.1-1.2.1-.5 0-.9-.1-1.3-.3-.8-.3-1.5-.9-2.1-1.5-.4-.4-.8-.7-1.1-1.1h-.3zm-1.1-1.1c-.1-.1-.1-.1 0 0-.3-.3-.6-.6-.8-.9-.5-.5-1-.9-1.6-1.2-.4-.3-.8-.4-1.3-.4-.4 0-.8 0-1.1.2-.5.2-.9.6-1.1 1-.2.3-.3.7-.3 1.1 0 .3 0 .6.1.9.1.5.4.9.8 1.2.5.4 1.1.5 1.7.5.5 0 1-.2 1.5-.5.6-.4 1.1-.8 1.6-1.3.1-.3.3-.5.5-.6zM13 12c.5.5 1 1 1.5 1.4.5.5 1.1.9 1.9 1 .4.1.8 0 1.2-.1.3-.1.6-.3.9-.5.4-.4.7-.9.8-1.4.1-.5 0-.9-.1-1.4-.3-.8-.8-1.2-1.7-1.4-.4-.1-.8-.1-1.2 0-.5.1-1 .4-1.4.7-.5.4-1 .8-1.4 1.2-.2.2-.4.3-.5.5z"/></svg></button> <button class="toggleSettings" aria-label="Settings" aria-haspopup="true" aria-expanded="${!!this._isSettingsOpen}" aria-controls="${this._identifier}-settings"><svg width="24" height="24" aria-hidden="true" focusable="false"><circle cx="12" cy="5.4" r="2.5"/><circle cx="12" cy="12" r="2.5"/><circle cx="12" cy="18.6" r="2.5"/></svg></button><div id="${this._identifier}-settings" class="popover" hidden><button class="convert" aria-label="Convert JSON animation to dotLottie format" hidden><svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M17.016 17.016v-4.031h1.969v6h-12v3l-3.984-3.984 3.984-3.984v3h10.031zM6.984 6.984v4.031H5.015v-6h12v-3l3.984 3.984-3.984 3.984v-3H6.984z"/></svg> Convert to dotLottie</button> <button class="snapshot" aria-label="Download still image"><svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M16.8 10.8 12 15.6l-4.8-4.8h3V3.6h3.6v7.2h3zM12 15.6H3v4.8h18v-4.8h-9zm7.8 2.4h-2.4v-1.2h2.4V18z"/></svg> Download still image</button></div>`}</div>`;
418
- const togglePlay = this.shadow.querySelector('.togglePlay');
419
- if (togglePlay instanceof HTMLButtonElement) {
420
- togglePlay.onclick = this.togglePlay;
421
- }
422
- const stop = this.shadow.querySelector('.stop');
423
- if (stop instanceof HTMLButtonElement) {
424
- stop.onclick = this.stop;
425
- }
426
- const prev = this.shadow.querySelector('.prev');
427
- if (prev instanceof HTMLButtonElement) {
428
- prev.onclick = this.prev;
429
- }
430
- const next = this.shadow.querySelector('.next');
431
- if (next instanceof HTMLButtonElement) {
432
- next.onclick = this.next;
433
- }
434
- const seeker = this.shadow.querySelector('.seeker');
435
- if (seeker instanceof HTMLInputElement) {
436
- seeker.onchange = this._handleSeekChange;
437
- seeker.onmousedown = this._freeze;
438
- }
439
- if (!this.simple) {
440
- const toggleLoop = this.shadow.querySelector('.toggleLoop');
441
- if (toggleLoop instanceof HTMLButtonElement) {
442
- toggleLoop.onclick = this.toggleLoop;
443
- }
444
- const toggleBoomerang = this.shadow.querySelector('.toggleBoomerang');
445
- if (toggleBoomerang instanceof HTMLButtonElement) {
446
- toggleBoomerang.onclick = this.toggleBoomerang;
447
- }
448
- const convert = this.shadow.querySelector('.convert');
449
- if (convert instanceof HTMLButtonElement) {
450
- convert.onclick = this.convert;
451
- }
452
- const snapshot = this.shadow.querySelector('.snapshot');
453
- if (snapshot instanceof HTMLButtonElement) {
454
- snapshot.onclick = ()=>this.snapshot(true);
455
- }
456
- const toggleSettings = this.shadow.querySelector('.toggleSettings');
457
- if (toggleSettings instanceof HTMLButtonElement) {
458
- toggleSettings.onclick = this._handleSettingsClick;
459
- toggleSettings.onblur = this._handleBlur;
460
- }
461
- }
462
- }
463
-
464
- /**
465
- * Credit to:
466
- * @author Leonardo Favre <https://github.com/leofavre/observed-properties>
467
- * @description Enhanced HTML element with reactive state handlers
468
- */ /* eslint-disable @typescript-eslint/ban-ts-comment */ const UPDATE_ON_CONNECTED = Symbol('UPDATE_ON_CONNECTED');
469
- if (isServer()) {
470
- // Mock HTMLElement for server-side rendering
471
- // @ts-ignore
472
- global.HTMLElement = class EmptyHTMLElement {
473
- };
474
- }
475
- /**
476
- * HTMLElement enhanced to track property changes
477
- */ class EnhancedElement extends HTMLElement {
478
- constructor(){
479
- super();
480
- // @ts-ignore
481
- const { observedProperties = [] } = this.constructor;
482
- if (UPDATE_ON_CONNECTED in this) {
483
- this[UPDATE_ON_CONNECTED] = [];
484
- }
485
- if ('propertyChangedCallback' in this && typeof this.propertyChangedCallback === 'function') {
486
- for (const propName of observedProperties){
487
- const initialValue = this[propName], CACHED_VALUE = Symbol(propName);
488
- // @ts-ignore
489
- this[CACHED_VALUE] = initialValue;
490
- Object.defineProperty(this, propName, {
491
- get () {
492
- return this[CACHED_VALUE];
493
- },
494
- set (value) {
495
- const oldValue = this[CACHED_VALUE];
496
- this[CACHED_VALUE] = value;
497
- this.propertyChangedCallback(propName, oldValue, value);
498
- }
499
- });
500
- if (typeof initialValue !== 'undefined') {
501
- if (UPDATE_ON_CONNECTED in this && Array.isArray(this[UPDATE_ON_CONNECTED])) {
502
- this[UPDATE_ON_CONNECTED].push(propName);
503
- }
504
- }
505
- }
506
- }
507
- }
508
- connectedCallback() {
509
- let arr = [];
510
- if (UPDATE_ON_CONNECTED in this && Array.isArray(this[UPDATE_ON_CONNECTED])) {
511
- arr = this[UPDATE_ON_CONNECTED];
512
- }
513
- for (const propName of arr){
514
- if (!('propertyChangedCallback' in this) || typeof this.propertyChangedCallback !== 'function') {
515
- continue;
516
- }
517
- if (propName in this) {
518
- this.propertyChangedCallback(propName, undefined, this[propName]);
519
- }
520
- }
521
- }
522
- }
523
-
524
- var name="@aarsteinmedia/dotlottie-player";var pkg = {name:name};
525
-
526
- var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-toolbar-height: 35px;\n --lottie-player-toolbar-background-color: #FFF;\n --lottie-player-toolbar-icon-color: #000;\n --lottie-player-toolbar-icon-hover-color: #000;\n --lottie-player-toolbar-icon-active-color: #4285f4;\n --lottie-player-seeker-track-color: rgb(0 0 0 / 20%);\n --lottie-player-seeker-thumb-color: #4285f4;\n --lottie-player-seeker-display: block;\n\n width: 100%;\n height: 100%;\n\n &:not([hidden]) {\n display: block;\n }\n\n .main {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n margin: 0;\n padding: 0;\n }\n\n .animation {\n width: 100%;\n height: 100%;\n display: flex;\n margin: 0;\n padding: 0;\n }\n\n [data-controls=\"true\"] .animation {\n height: calc(100% - 35px);\n }\n\n .animation-container {\n position: relative;\n }\n\n .popover {\n position: absolute;\n right: 5px;\n bottom: 40px;\n background-color: var(--lottie-player-toolbar-background-color);\n border-radius: 5px;\n padding: 10px 15px;\n border: solid 2px var(--lottie-player-toolbar-icon-color);\n animation: fade-in .2s ease-in-out;\n\n &::before {\n content: \"\";\n right: 10px;\n border: 7px solid transparent;\n margin-right: -7px;\n height: 0;\n width: 0;\n position: absolute;\n pointer-events: none;\n top: 100%;\n border-top-color: var(--lottie-player-toolbar-icon-color);\n }\n }\n\n .error {\n display: flex;\n margin: auto;\n justify-content: center;\n height: 100%;\n align-items: center;\n\n & svg {\n width: 100%;\n height: auto;\n }\n }\n\n .toolbar {\n display: flex;\n place-items: center center;\n background: var(--lottie-player-toolbar-background-color);\n margin: 0;\n height: 35px;\n padding: 5px;\n border-radius: 5px;\n gap: 5px;\n\n &.has-error {\n pointer-events: none;\n opacity: .5;\n }\n\n & button {\n cursor: pointer;\n fill: var(--lottie-player-toolbar-icon-color);\n color: var(--lottie-player-toolbar-icon-color);\n background: none;\n border: 0;\n padding: 0;\n outline: 0;\n height: 100%;\n margin: 0;\n align-items: center;\n gap: 5px;\n opacity: .9;\n\n &:not([hidden]) {\n display: flex;\n }\n\n &:hover {\n opacity: 1;\n }\n\n &[data-active=\"true\"] {\n opacity: 1;\n fill: var(--lottie-player-toolbar-icon-active-color);\n }\n\n &:disabled {\n opacity: .5;\n }\n\n &:focus {\n outline: 0;\n }\n\n & svg {\n pointer-events: none;\n\n >* {\n fill: inherit;\n }\n }\n\n &.disabled svg {\n display: none;\n }\n }\n }\n\n .progress-container {\n position: relative;\n width: 100%;\n\n &.simple {\n margin-right: 12px;\n }\n }\n\n .seeker {\n appearance: none;\n outline: none;\n width: 100%;\n height: 20px;\n border-radius: 3px;\n border: 0;\n cursor: pointer;\n background-color: transparent;\n\n display: var(--lottie-player-seeker-display);\n color: var(--lottie-player-seeker-thumb-color);\n margin: 0;\n padding: 7.5px 0;\n position: relative;\n z-index: 1;\n\n &::-webkit-slider-runnable-track,\n &::-webkit-slider-thumb {\n appearance: none;\n outline: none;\n }\n\n &::-webkit-slider-thumb {\n height: 15px;\n width: 15px;\n border-radius: 50%;\n border: 0;\n background-color: var(--lottie-player-seeker-thumb-color);\n cursor: pointer;\n -webkit-transition: transform .2s ease-in-out;\n transition: transform .2s ease-in-out;\n transform: scale(0);\n }\n\n &:hover::-webkit-slider-thumb,\n &:focus::-webkit-slider-thumb {\n transform: scale(1);\n }\n\n &::-moz-range-progress {\n background-color: var(--lottie-player-seeker-thumb-color);\n height: 5px;\n border-radius: 3px;\n }\n\n &::-moz-range-thumb {\n height: 15px;\n width: 15px;\n border-radius: 50%;\n background-color: var(--lottie-player-seeker-thumb-color);\n border: 0;\n cursor: pointer;\n -moz-transition: transform .2s ease-in-out;\n transition: transform .2s ease-in-out;\n transform: scale(0);\n }\n\n &:hover::-moz-range-thumb,\n &:focus::-moz-range-thumb {\n transform: scale(1);\n }\n\n &::-ms-track {\n width: 100%;\n height: 5px;\n cursor: pointer;\n background: transparent;\n border-color: transparent;\n color: transparent;\n }\n\n &::-ms-fill-upper {\n background: var(--lottie-player-seeker-track-color);\n border-radius: 3px;\n }\n\n &::-ms-fill-lower {\n background-color: var(--lottie-player-seeker-thumb-color);\n border-radius: 3px;\n }\n\n &::-ms-thumb {\n border: 0;\n height: 15px;\n width: 15px;\n border-radius: 50%;\n background: var(--lottie-player-seeker-thumb-color);\n cursor: pointer;\n -ms-transition: transform .2s ease-in-out;\n transition: transform .2s ease-in-out;\n transform: scale(0);\n }\n\n &:hover::-ms-thumb {\n transform: scale(1);\n }\n\n &:focus {\n &::-ms-thumb {\n transform: scale(1);\n }\n\n &::-ms-fill-lower,\n &::-ms-fill-upper {\n background: var(--lottie-player-seeker-track-color);\n }\n }\n }\n\n & progress {\n appearance: none;\n outline: none;\n position: absolute;\n width: 100%;\n height: 5px;\n border-radius: 3px;\n border: 0;\n top: 0;\n left: 0;\n margin: 7.5px 0;\n background-color: var(--lottie-player-seeker-track-color);\n pointer-events: none;\n\n &::-webkit-progress-inner-element {\n border-radius: 3px;\n overflow: hidden;\n }\n\n &::-webkit-slider-runnable-track {\n background-color: transparent;\n }\n\n &::-webkit-progress-value {\n background-color: var(--lottie-player-seeker-thumb-color);\n }\n }\n\n ::-moz-progress-bar {\n background-color: var(--lottie-player-seeker-thumb-color);\n }\n\n}\n\n@keyframes fade-in {\n 0% {\n opacity: 0;\n }\n\n 100% {\n opacity: 1;\n }\n}\n\n@media (prefers-color-scheme: dark) {\n :host {\n --lottie-player-toolbar-background-color: #000;\n --lottie-player-toolbar-icon-color: #FFF;\n --lottie-player-toolbar-icon-hover-color: #FFF;\n --lottie-player-seeker-track-color: rgb(255 255 255 / 60%);\n }\n}\n";
527
-
528
- /**
529
- * dotLottie Player Web Component
530
- * @export
531
- * @class DotLottiePlayer
532
- * @extends { EnhancedElement }
533
- * @description Web Component for playing Lottie animations in your web app.
534
- */ class DotLottiePlayer extends EnhancedElement {
535
- constructor(){
536
- super(), this._renderControls = renderControls, this._render = renderPlayer, /**
537
- * Multi-animation settings
538
- */ this._multiAnimationSettings = [], /**
539
- * Animation Container
540
- */ this._container = null, /**
541
- * @state
542
- * Player state
543
- */ this.playerState = PlayerState.Loading, /**
544
- * @state
545
- * Whether settings toolbar is open
546
- */ this._isSettingsOpen = false, /**
547
- * @state
548
- * Seeker
549
- */ this._seeker = 0, /**
550
- * @state
551
- * Which animation to show, if several
552
- */ this._currentAnimation = 0, this._lottieInstance = null, this._identifier = this.id || useId('dotlottie'), this._errorMessage = 'Something went wrong', this._isBounce = false, this._isDotLottie = false, this._playerState = {
553
- count: 0,
554
- loaded: false,
555
- prev: PlayerState.Loading,
556
- scrollTimeout: null,
557
- scrollY: 0,
558
- visible: false
559
- }, /**
560
- * Handle settings click event
561
- */ this._handleSettingsClick = ({ target })=>{
562
- this._toggleSettings();
563
- // Because Safari does not add focus on click, we need to add it manually, so the onblur event will fire
564
- if (target instanceof HTMLElement) {
565
- target.focus();
566
- }
567
- };
568
- this._complete = this._complete.bind(this);
569
- this._dataFailed = this._dataFailed.bind(this);
570
- this._dataReady = this._dataReady.bind(this);
571
- this._DOMLoaded = this._DOMLoaded.bind(this);
572
- this._enterFrame = this._enterFrame.bind(this);
573
- this._freeze = this._freeze.bind(this);
574
- this._handleBlur = this._handleBlur.bind(this);
575
- this._handleScroll = this._handleScroll.bind(this);
576
- this._handleSeekChange = this._handleSeekChange.bind(this);
577
- this._handleWindowBlur = this._handleWindowBlur.bind(this);
578
- this._loopComplete = this._loopComplete.bind(this);
579
- this._mouseEnter = this._mouseEnter.bind(this);
580
- this._mouseLeave = this._mouseLeave.bind(this);
581
- this._onVisibilityChange = this._onVisibilityChange.bind(this);
582
- this._switchInstance = this._switchInstance.bind(this);
583
- this.togglePlay = this.togglePlay.bind(this);
584
- this.stop = this.stop.bind(this);
585
- this.prev = this.prev.bind(this);
586
- this.next = this.next.bind(this);
587
- this._renderControls = this._renderControls.bind(this);
588
- this.snapshot = this.snapshot.bind(this);
589
- this.toggleLoop = this.toggleLoop.bind(this);
590
- this.toggleBoomerang = this.toggleBoomerang.bind(this);
591
- this.convert = this.convert.bind(this);
592
- this.destroy = this.destroy.bind(this);
593
- this.template = document.createElement('template');
594
- this.shadow = this.attachShadow({
595
- mode: 'open'
596
- });
597
- }
598
- /**
599
- * Initialize everything on component first render
600
- */ async connectedCallback() {
601
- super.connectedCallback();
602
- this._render();
603
- this._container = this.shadow.querySelector('.animation');
604
- this._renderControls();
605
- // Add listener for Visibility API's change event.
606
- if (typeof document.hidden !== 'undefined') {
607
- document.addEventListener('visibilitychange', this._onVisibilityChange);
608
- }
609
- // Add intersection observer for detecting component being out-of-view.
610
- this._addIntersectionObserver();
611
- // Setup lottie player
612
- await this.load(this.src);
613
- this.dispatchEvent(new CustomEvent(PlayerEvents.Rendered));
614
- }
615
- /**
616
- * Cleanup on component destroy
617
- */ disconnectedCallback() {
618
- // Remove intersection observer for detecting component being out-of-view
619
- if (this._intersectionObserver) {
620
- this._intersectionObserver.disconnect();
621
- this._intersectionObserver = undefined;
622
- }
623
- // Destroy the animation instance
624
- if (this._lottieInstance) {
625
- this._lottieInstance.destroy();
626
- }
627
- // Remove the attached Visibility API's change event listener
628
- document.removeEventListener('visibilitychange', this._onVisibilityChange);
629
- }
630
- /**
631
- * Attributes to observe
632
- */ static get observedAttributes() {
633
- return [
634
- 'animateOnScroll',
635
- 'autoplay',
636
- 'controls',
637
- 'direction',
638
- 'hover',
639
- 'loop',
640
- 'mode',
641
- 'speed',
642
- 'src',
643
- 'subframe'
644
- ];
645
- }
646
- /**
647
- * Runs when the value of an attribute is changed on the component
648
- */ async attributeChangedCallback(name, _oldValue, value) {
649
- if (!this._lottieInstance) {
650
- return;
651
- }
652
- if (name === 'animateOnScroll') {
653
- if (value === '' || Boolean(value)) {
654
- this._lottieInstance.autoplay = false;
655
- addEventListener('scroll', this._handleScroll, {
656
- capture: true,
657
- passive: true
658
- });
659
- return;
660
- }
661
- removeEventListener('scroll', this._handleScroll, true);
662
- }
663
- if (name === 'autoplay') {
664
- if (this.animateOnScroll) {
665
- return;
666
- }
667
- if (value === '' || Boolean(value)) {
668
- this.play();
669
- return;
670
- }
671
- this.stop();
672
- }
673
- if (name === 'controls') {
674
- this._renderControls();
675
- }
676
- if (name === 'direction') {
677
- if (Number(value) === -1) {
678
- return this.setDirection(-1);
679
- }
680
- this.setDirection(1);
681
- }
682
- if (name === 'hover' && this._container) {
683
- if (value === '' || Boolean(value)) {
684
- this._container.addEventListener('mouseenter', this._mouseEnter);
685
- this._container.addEventListener('mouseleave', this._mouseLeave);
686
- return;
687
- }
688
- this._container.removeEventListener('mouseenter', this._mouseEnter);
689
- this._container.removeEventListener('mouseleave', this._mouseLeave);
690
- }
691
- if (name === 'loop') {
692
- const toggleLoop = this.shadow.querySelector('.toggleLoop');
693
- if (toggleLoop instanceof HTMLButtonElement) {
694
- toggleLoop.dataset.active = value;
695
- }
696
- this.setLoop(value === '' || Boolean(value));
697
- }
698
- if (name === 'mode') {
699
- const toggleBoomerang = this.shadow.querySelector('.toggleBoomerang');
700
- if (toggleBoomerang instanceof HTMLButtonElement) {
701
- toggleBoomerang.dataset.active = (value === PlayMode.Bounce).toString();
702
- }
703
- this._isBounce = value === PlayMode.Bounce;
704
- }
705
- if (name === 'speed') {
706
- const val = Number(value);
707
- if (val && !isNaN(val)) {
708
- this.setSpeed(val);
709
- }
710
- }
711
- if (name === 'src') {
712
- await this.load(value);
713
- }
714
- if (name === 'subframe') {
715
- this.setSubframe(value === '' || Boolean(value));
716
- }
717
- }
718
- static get observedProperties() {
719
- return [
720
- 'playerState',
721
- '_isSettingsOpen',
722
- '_seeker',
723
- '_currentAnimation',
724
- '_animations'
725
- ];
726
- }
727
- // name: string, oldValue: string, newValue: string
728
- propertyChangedCallback(name, _oldValue, value) {
729
- if (!this.shadow) {
730
- return;
731
- }
732
- const togglePlay = this.shadow.querySelector('.togglePlay'), stop = this.shadow.querySelector('.stop'), prev = this.shadow.querySelector('.prev'), next = this.shadow.querySelector('.next'), seeker = this.shadow.querySelector('.seeker'), progress = this.shadow.querySelector('progress'), popover = this.shadow.querySelector('.popover'), convert = this.shadow.querySelector('.convert');
733
- if (!(togglePlay instanceof HTMLButtonElement) || !(stop instanceof HTMLButtonElement) || !(next instanceof HTMLButtonElement) || !(prev instanceof HTMLButtonElement) || !(seeker instanceof HTMLInputElement) || !(progress instanceof HTMLProgressElement)) {
734
- return;
735
- }
736
- if (name === 'playerState') {
737
- togglePlay.dataset.active = (value === PlayerState.Playing || value === PlayerState.Paused).toString();
738
- stop.dataset.active = (value === PlayerState.Stopped).toString();
739
- if (value === PlayerState.Playing) {
740
- togglePlay.innerHTML = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M14.016 5.016H18v13.969h-3.984V5.016zM6 18.984V5.015h3.984v13.969H6z"/></svg>`;
741
- } else {
742
- togglePlay.innerHTML = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M8.016 5.016L18.985 12 8.016 18.984V5.015z"/></svg>`;
743
- }
744
- }
745
- if (name === '_seeker' && typeof value === 'number') {
746
- seeker.value = value.toString();
747
- seeker.ariaValueNow = value.toString();
748
- progress.value = value;
749
- }
750
- if (name === '_animations' && Array.isArray(value)) {
751
- if (this._currentAnimation + 1 < value.length) {
752
- next.hidden = false;
753
- }
754
- }
755
- if (name === '_currentAnimation' && typeof value === 'number') {
756
- if (value + 1 >= this._animations.length) {
757
- next.hidden = true;
758
- } else {
759
- next.hidden = false;
760
- }
761
- if (value) {
762
- prev.hidden = false;
763
- } else {
764
- prev.hidden = true;
765
- }
766
- }
767
- if (name === '_isSettingsOpen' && typeof value === 'boolean' && popover instanceof HTMLDivElement && convert instanceof HTMLButtonElement) {
768
- popover.hidden = !value;
769
- convert.hidden = this._isDotLottie;
770
- }
771
- }
772
- /**
773
- * Whether to trigger next frame with scroll
774
- */ set animateOnScroll(value) {
775
- this.setAttribute('animateOnScroll', (!!value).toString());
776
- }
777
- get animateOnScroll() {
778
- const val = this.getAttribute('animateOnScroll');
779
- if (val === 'true' || val === '' || val === '1') {
780
- return true;
781
- }
782
- return false;
783
- }
784
- /**
785
- * Autoplay
786
- */ set autoplay(value) {
787
- this.setAttribute('autoplay', (!!value).toString());
788
- }
789
- get autoplay() {
790
- const val = this.getAttribute('autoplay');
791
- if (val === 'true' || val === '' || val === '1') {
792
- return true;
793
- }
794
- return false;
795
- }
796
- /**
797
- * Background color
798
- */ set background(value) {
799
- this.setAttribute('background', value);
800
- }
801
- get background() {
802
- return this.getAttribute('background') || 'transparent';
803
- }
804
- /**
805
- * Show controls
806
- */ set controls(value) {
807
- this.setAttribute('controls', (!!value).toString());
808
- }
809
- get controls() {
810
- const val = this.getAttribute('controls');
811
- if (val === 'true' || val === '' || val === '1') {
812
- return true;
813
- }
814
- return false;
815
- }
816
- /**
817
- * Number of times to loop
818
- */ set count(value) {
819
- this.setAttribute('count', value.toString());
820
- }
821
- get count() {
822
- const val = this.getAttribute('count');
823
- if (val) {
824
- return Number(val);
825
- }
826
- return 0;
827
- }
828
- /**
829
- * Description for screen readers
830
- */ set description(value) {
831
- if (value) {
832
- this.setAttribute('description', value);
833
- }
834
- }
835
- get description() {
836
- return this.getAttribute('description');
837
- }
838
- /**
839
- * Direction of animation
840
- */ set direction(value) {
841
- this.setAttribute('direction', value.toString());
842
- }
843
- get direction() {
844
- const val = Number(this.getAttribute('direction'));
845
- if (val === -1) {
846
- return val;
847
- }
848
- return 1;
849
- }
850
- /**
851
- * Whether to play on mouseover
852
- */ set hover(value) {
853
- this.setAttribute('hover', value.toString());
854
- }
855
- get hover() {
856
- const val = this.getAttribute('hover');
857
- if (val === 'true' || val === '' || val === '1') {
858
- return true;
859
- }
860
- return false;
861
- }
862
- /**
863
- * Pause between loop intrations, in miliseconds
864
- */ set intermission(value) {
865
- this.setAttribute('intermission', value.toString());
866
- }
867
- get intermission() {
868
- const val = Number(this.getAttribute('intermission'));
869
- if (!isNaN(val)) {
870
- return val;
871
- }
872
- return 0;
873
- }
874
- /**
875
- * Loop animation
876
- */ set loop(value) {
877
- this.setAttribute('loop', (!!value).toString());
878
- }
879
- get loop() {
880
- const val = this.getAttribute('loop');
881
- if (val === 'true' || val === '' || val === '1') {
882
- return true;
883
- }
884
- return false;
885
- }
886
- /**
887
- * Play mode
888
- */ set mode(value) {
889
- this.setAttribute('mode', value.toString());
890
- }
891
- get mode() {
892
- const val = this.getAttribute('mode');
893
- if (val === PlayMode.Bounce) {
894
- return val;
895
- }
896
- return PlayMode.Normal;
897
- }
898
- /**
899
- * Resizing to container
900
- */ set objectfit(value) {
901
- this.setAttribute('objectfit', value);
902
- }
903
- get objectfit() {
904
- const val = this.getAttribute('objectfit');
905
- if (val && Object.values(ObjectFit).includes(val)) {
906
- return val;
907
- }
908
- return ObjectFit.Contain;
909
- }
910
- /**
911
- * Resizing to container (Deprecated)
912
- */ set preserveAspectRatio(value) {
913
- this.setAttribute('preserveAspectRatio', value || PreserveAspectRatio.Contain);
914
- }
915
- get preserveAspectRatio() {
916
- const val = this.getAttribute('preserveAspectRatio');
917
- if (val && Object.values(PreserveAspectRatio).includes(val)) {
918
- return val;
919
- }
920
- return null;
921
- }
922
- /**
923
- * Renderer to use: svg, canvas or html
924
- */ set renderer(value) {
925
- this.setAttribute('renderer', value);
926
- }
927
- get renderer() {
928
- const val = this.getAttribute('renderer');
929
- if (val === 'canvas' || val === 'html') {
930
- return val;
931
- }
932
- return 'svg';
933
- }
934
- /**
935
- * Hide advanced controls
936
- */ set simple(value) {
937
- this.setAttribute('simple', value.toString());
938
- }
939
- get simple() {
940
- const val = this.getAttribute('simple');
941
- if (val === 'true' || val === '' || val === '1') {
942
- return true;
943
- }
944
- return false;
945
- }
946
- /**
947
- * Speed
948
- */ set speed(value) {
949
- this.setAttribute('speed', value?.toString());
950
- }
951
- get speed() {
952
- const val = this.getAttribute('speed');
953
- if (val !== null && !isNaN(Number(val))) {
954
- return Number(val);
955
- }
956
- return 1;
957
- }
958
- /**
959
- * Source, either path or JSON string
960
- */ set src(value) {
961
- this.setAttribute('src', value || '');
962
- }
963
- get src() {
964
- return this.getAttribute('src');
965
- }
966
- /**
967
- * Subframe
968
- */ set subframe(value) {
969
- this.setAttribute('subframe', (!!value).toString());
970
- }
971
- get subframe() {
972
- const val = this.getAttribute('subframe');
973
- if (val === 'true' || val === '' || val === '1') {
974
- return true;
975
- }
976
- return false;
977
- }
978
- /**
979
- * Get Multi-animation settings
980
- * @returns { AnimationSettings[] }
981
- */ getMultiAnimationSettings() {
982
- return this._multiAnimationSettings;
983
- }
984
- /**
985
- * Set Multi-animation settings
986
- * @param { AnimationSettings[] } settings
987
- */ setMultiAnimationSettings(settings) {
988
- this._multiAnimationSettings = settings;
989
- }
990
- /**
991
- * Set playback segment
992
- * @param { AnimationSegment } settings
993
- */ setSegment(segment) {
994
- this._segment = segment;
995
- }
996
- /**
997
- * Get playback segment
998
- * @returns { AnimationSegment }
999
- */ getSegment() {
1000
- return this._segment;
1001
- }
1002
- /**
1003
- * Get options from props
1004
- * @returns { AnimationConfig }
1005
- */ _getOptions() {
1006
- if (!this._container) {
1007
- throw new Error('Container not rendered');
1008
- }
1009
- const preserveAspectRatio = this.preserveAspectRatio ?? (this.objectfit && aspectRatio(this.objectfit)), currentAnimationSettings = this._multiAnimationSettings?.length ? this._multiAnimationSettings?.[this._currentAnimation] : undefined, currentAnimationManifest = this._manifest.animations?.[this._currentAnimation];
1010
- // Loop
1011
- let loop = !!this.loop;
1012
- if (currentAnimationManifest.loop !== undefined && this.loop === undefined) {
1013
- loop = !!currentAnimationManifest.loop;
1014
- }
1015
- if (currentAnimationSettings?.loop !== undefined) {
1016
- loop = !!currentAnimationSettings.loop;
1017
- }
1018
- // Autoplay
1019
- let autoplay = !!this.autoplay;
1020
- if (currentAnimationManifest.autoplay !== undefined && this.autoplay === undefined) {
1021
- autoplay = !!currentAnimationManifest.autoplay;
1022
- }
1023
- if (currentAnimationSettings?.autoplay !== undefined) {
1024
- autoplay = !!currentAnimationSettings.autoplay;
1025
- }
1026
- if (this.animateOnScroll) {
1027
- autoplay = false;
1028
- }
1029
- // Segment
1030
- let initialSegment = this._segment;
1031
- if (this._segment?.every((val)=>val > 0)) {
1032
- initialSegment = [
1033
- this._segment[0] - 1,
1034
- this._segment[1] - 1
1035
- ];
1036
- }
1037
- if (this._segment?.some((val)=>val < 0)) {
1038
- initialSegment = undefined;
1039
- }
1040
- const options = {
1041
- autoplay,
1042
- container: this._container,
1043
- initialSegment,
1044
- loop,
1045
- renderer: this.renderer,
1046
- rendererSettings: {
1047
- imagePreserveAspectRatio: preserveAspectRatio
1048
- }
1049
- };
1050
- switch(this.renderer){
1051
- case 'svg':
1052
- options.rendererSettings = {
1053
- ...options.rendererSettings,
1054
- hideOnTransparent: true,
1055
- preserveAspectRatio,
1056
- progressiveLoad: true
1057
- };
1058
- break;
1059
- case 'canvas':
1060
- options.rendererSettings = {
1061
- ...options.rendererSettings,
1062
- clearCanvas: true,
1063
- preserveAspectRatio,
1064
- progressiveLoad: true
1065
- };
1066
- break;
1067
- case 'html':
1068
- options.rendererSettings = {
1069
- ...options.rendererSettings,
1070
- hideOnTransparent: true
1071
- };
1072
- }
1073
- return options;
1074
- }
1075
- /**
1076
- * Add IntersectionObserver
1077
- */ _addIntersectionObserver() {
1078
- if (!this._container || this._intersectionObserver || !('IntersectionObserver' in window)) {
1079
- return;
1080
- }
1081
- this._intersectionObserver = new IntersectionObserver((entries)=>{
1082
- for (const entry of entries){
1083
- if (!entry.isIntersecting || document.hidden) {
1084
- if (this.playerState === PlayerState.Playing) {
1085
- this._freeze();
1086
- }
1087
- this._playerState.visible = false;
1088
- continue;
1089
- }
1090
- if (!this.animateOnScroll && this.playerState === PlayerState.Frozen) {
1091
- this.play();
1092
- }
1093
- if (!this._playerState.scrollY) {
1094
- this._playerState.scrollY = scrollY;
1095
- }
1096
- this._playerState.visible = true;
1097
- }
1098
- });
1099
- this._intersectionObserver.observe(this._container);
1100
- }
1101
- /**
1102
- * Initialize Lottie Web player
1103
- */ async load(src) {
1104
- if (!this.shadowRoot || !src) {
1105
- return;
1106
- }
1107
- // Load the resource
1108
- try {
1109
- const { animations, isDotLottie, manifest } = await getAnimationData(src);
1110
- if (!animations || animations.some((animation)=>!this._isLottie(animation))) {
1111
- throw new Error('Broken or corrupted file');
1112
- }
1113
- this._isBounce = this.mode === PlayMode.Bounce;
1114
- if (this._multiAnimationSettings?.length) {
1115
- if (this._multiAnimationSettings[this._currentAnimation]?.mode) {
1116
- this._isBounce = this._multiAnimationSettings[this._currentAnimation].mode === PlayMode.Bounce;
1117
- }
1118
- }
1119
- this._isDotLottie = !!isDotLottie;
1120
- this._animations = animations;
1121
- this._manifest = manifest ?? {
1122
- animations: [
1123
- {
1124
- autoplay: !this.animateOnScroll && this.autoplay,
1125
- direction: this.direction,
1126
- id: useId(),
1127
- loop: this.loop,
1128
- mode: this.mode,
1129
- speed: this.speed
1130
- }
1131
- ]
1132
- };
1133
- // Clear previous animation, if any
1134
- if (this._lottieInstance) {
1135
- this._lottieInstance.destroy();
1136
- }
1137
- this.playerState = PlayerState.Stopped;
1138
- if (!this.animateOnScroll && (this.autoplay || this._multiAnimationSettings?.[this._currentAnimation]?.autoplay)) {
1139
- this.playerState = PlayerState.Playing;
1140
- }
1141
- // Initialize lottie player and load animation
1142
- this._lottieInstance = Lottie.default.loadAnimation({
1143
- ...this._getOptions(),
1144
- animationData: animations[this._currentAnimation]
1145
- });
1146
- } catch (err) {
1147
- this._errorMessage = handleErrors(err).message;
1148
- this.playerState = PlayerState.Error;
1149
- this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1150
- return;
1151
- }
1152
- this._addEventListeners();
1153
- const speed = this._multiAnimationSettings?.[this._currentAnimation]?.speed ?? this.speed ?? this._manifest.animations[this._currentAnimation].speed, direction = this._multiAnimationSettings?.[this._currentAnimation]?.direction ?? this.direction ?? this._manifest.animations[this._currentAnimation].direction ?? 1;
1154
- // Set initial playback speed and direction
1155
- this._lottieInstance.setSpeed(speed);
1156
- this._lottieInstance.setDirection(direction);
1157
- this._lottieInstance.setSubframe(!!this.subframe);
1158
- // Start playing if autoplay is enabled
1159
- if (this.autoplay || this.animateOnScroll) {
1160
- if (this.direction === -1) {
1161
- this.seek('99%');
1162
- }
1163
- if (!('IntersectionObserver' in window)) {
1164
- if (!this.animateOnScroll) {
1165
- this.play();
1166
- }
1167
- this._playerState.visible = true;
1168
- }
1169
- this._addIntersectionObserver();
1170
- }
1171
- }
1172
- /**
1173
- * Get Lottie Manifest
1174
- */ getManifest() {
1175
- return this._manifest;
1176
- }
1177
- /**
1178
- * Toggle event listeners
1179
- */ _toggleEventListeners(action) {
1180
- const method = action === 'add' ? 'addEventListener' : 'removeEventListener';
1181
- if (this._lottieInstance) {
1182
- this._lottieInstance[method]('enterFrame', this._enterFrame);
1183
- this._lottieInstance[method]('complete', this._complete);
1184
- this._lottieInstance[method]('loopComplete', this._loopComplete);
1185
- this._lottieInstance[method]('DOMLoaded', this._DOMLoaded);
1186
- this._lottieInstance[method]('data_ready', this._dataReady);
1187
- this._lottieInstance[method]('data_failed', this._dataFailed);
1188
- }
1189
- if (this._container && this.hover) {
1190
- this._container[method]('mouseenter', this._mouseEnter);
1191
- this._container[method]('mouseleave', this._mouseLeave);
1192
- }
1193
- window[method]('focus', this._handleWindowBlur, {
1194
- capture: false,
1195
- passive: true
1196
- });
1197
- window[method]('blur', this._handleWindowBlur, {
1198
- capture: false,
1199
- passive: true
1200
- });
1201
- if (this.animateOnScroll) {
1202
- window[method]('scroll', this._handleScroll, {
1203
- capture: true,
1204
- passive: true
1205
- });
1206
- }
1207
- }
1208
- /**
1209
- * Add event listeners
1210
- */ _addEventListeners() {
1211
- this._toggleEventListeners('add');
1212
- }
1213
- /**
1214
- * Remove event listeners
1215
- */ _removeEventListeners() {
1216
- this._toggleEventListeners('remove');
1217
- }
1218
- _loopComplete() {
1219
- if (!this._lottieInstance) {
1220
- return;
1221
- }
1222
- const { playDirection, // firstFrame,
1223
- totalFrames } = this._lottieInstance, inPoint = this._segment ? this._segment[0] : 0, outPoint = this._segment ? this._segment[0] : totalFrames;
1224
- if (this.count) {
1225
- if (this._isBounce) {
1226
- this._playerState.count += 0.5;
1227
- } else {
1228
- this._playerState.count += 1;
1229
- }
1230
- if (this._playerState.count >= this.count) {
1231
- this.setLoop(false);
1232
- this.playerState = PlayerState.Completed;
1233
- this.dispatchEvent(new CustomEvent(PlayerEvents.Complete));
1234
- return;
1235
- }
1236
- }
1237
- this.dispatchEvent(new CustomEvent(PlayerEvents.Loop));
1238
- if (this._isBounce) {
1239
- this._lottieInstance.goToAndStop(playDirection === -1 ? inPoint : outPoint * 0.99, true);
1240
- this._lottieInstance.setDirection(playDirection * -1);
1241
- return setTimeout(()=>{
1242
- if (!this.animateOnScroll) {
1243
- this._lottieInstance?.play();
1244
- }
1245
- }, this.intermission);
1246
- }
1247
- this._lottieInstance.goToAndStop(playDirection === -1 ? outPoint * 0.99 : inPoint, true);
1248
- return setTimeout(()=>{
1249
- if (!this.animateOnScroll) {
1250
- this._lottieInstance?.play();
1251
- }
1252
- }, this.intermission);
1253
- }
1254
- _enterFrame() {
1255
- if (!this._lottieInstance) {
1256
- return;
1257
- }
1258
- const { currentFrame, totalFrames } = this._lottieInstance;
1259
- this._seeker = Math.round(currentFrame / totalFrames * 100);
1260
- this.dispatchEvent(new CustomEvent(PlayerEvents.Frame, {
1261
- detail: {
1262
- frame: currentFrame,
1263
- seeker: this._seeker
1264
- }
1265
- }));
1266
- }
1267
- _complete() {
1268
- if (!this._lottieInstance) {
1269
- return;
1270
- }
1271
- if (this._animations.length > 1) {
1272
- if (this._multiAnimationSettings?.[this._currentAnimation + 1]?.autoplay) {
1273
- return this.next();
1274
- }
1275
- if (this.loop && this._currentAnimation === this._animations.length - 1) {
1276
- this._currentAnimation = 0;
1277
- return this._switchInstance();
1278
- }
1279
- }
1280
- const { currentFrame, totalFrames } = this._lottieInstance;
1281
- this._seeker = Math.round(currentFrame / totalFrames * 100);
1282
- this.playerState = PlayerState.Completed;
1283
- this.dispatchEvent(new CustomEvent(PlayerEvents.Complete, {
1284
- detail: {
1285
- frame: currentFrame,
1286
- seeker: this._seeker
1287
- }
1288
- }));
1289
- }
1290
- _DOMLoaded() {
1291
- this._playerState.loaded = true;
1292
- this.dispatchEvent(new CustomEvent(PlayerEvents.Ready));
1293
- }
1294
- _dataReady() {
1295
- this.dispatchEvent(new CustomEvent(PlayerEvents.Load));
1296
- }
1297
- _dataFailed() {
1298
- this.playerState = PlayerState.Error;
1299
- this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1300
- }
1301
- _handleWindowBlur({ type }) {
1302
- if (this.playerState === PlayerState.Playing && type === 'blur') {
1303
- this._freeze();
1304
- }
1305
- if (this.playerState === PlayerState.Frozen && type === 'focus') {
1306
- this.play();
1307
- }
1308
- }
1309
- /**
1310
- * Handle MouseEnter
1311
- */ _mouseEnter() {
1312
- if (this.hover && this.playerState !== PlayerState.Playing) {
1313
- this.play();
1314
- }
1315
- }
1316
- /**
1317
- * Handle MouseLeave
1318
- */ _mouseLeave() {
1319
- if (this.hover && this.playerState === PlayerState.Playing) {
1320
- this.stop();
1321
- }
1322
- }
1323
- /**
1324
- * Handle visibility change events
1325
- */ _onVisibilityChange() {
1326
- if (document.hidden && this.playerState === PlayerState.Playing) {
1327
- this._freeze();
1328
- return;
1329
- }
1330
- if (this.playerState === PlayerState.Frozen) {
1331
- this.play();
1332
- }
1333
- }
1334
- /**
1335
- * Handle scroll
1336
- */ _handleScroll() {
1337
- if (!this.animateOnScroll || !this._lottieInstance) {
1338
- return;
1339
- }
1340
- if (isServer()) {
1341
- console.warn('DotLottie: Scroll animations might not work properly in a Server Side Rendering context. Try to wrap this in a client component.');
1342
- return;
1343
- }
1344
- if (this._playerState.visible) {
1345
- if (this._playerState.scrollTimeout) {
1346
- clearTimeout(this._playerState.scrollTimeout);
1347
- }
1348
- this._playerState.scrollTimeout = setTimeout(()=>{
1349
- this.playerState = PlayerState.Paused;
1350
- }, 400);
1351
- const adjustedScroll = scrollY > this._playerState.scrollY ? scrollY - this._playerState.scrollY : this._playerState.scrollY - scrollY, clampedScroll = Math.min(Math.max(adjustedScroll / 3, 1), this._lottieInstance.totalFrames * 3), roundedScroll = clampedScroll / 3;
1352
- requestAnimationFrame(()=>{
1353
- if (roundedScroll < (this._lottieInstance?.totalFrames ?? 0)) {
1354
- this.playerState = PlayerState.Playing;
1355
- this._lottieInstance?.goToAndStop(roundedScroll, true);
1356
- } else {
1357
- this.playerState = PlayerState.Paused;
1358
- }
1359
- });
1360
- }
1361
- }
1362
- /**
1363
- * Handles click and drag actions on the progress track
1364
- * @param { Event & { HTMLInputElement } } event
1365
- */ _handleSeekChange({ target }) {
1366
- if (!(target instanceof HTMLInputElement) || !this._lottieInstance || isNaN(Number(target.value))) {
1367
- return;
1368
- }
1369
- this.seek(Math.round(Number(target.value) / 100 * this._lottieInstance.totalFrames));
1370
- }
1371
- _isLottie(json) {
1372
- const mandatory = [
1373
- 'v',
1374
- 'ip',
1375
- 'op',
1376
- 'layers',
1377
- 'fr',
1378
- 'w',
1379
- 'h'
1380
- ];
1381
- return mandatory.every((field)=>Object.prototype.hasOwnProperty.call(json, field));
1382
- }
1383
- /**
1384
- * Creates a new dotLottie file, by combinig several animations
1385
- * @param { [ AnimationConfig ] } configs
1386
- * @param { string } fileName
1387
- * @param { boolean } shouldDownload Whether to trigger a download in the browser.
1388
- * If set to false the function returns an ArrayBuffer. Defaults to true.
1389
- *
1390
- */ async addAnimation(configs, fileName, shouldDownload = true) {
1391
- // Initialize meta object for animation, with fallbacks for
1392
- // when the method is called indepenently
1393
- const { animations = [], manifest = {
1394
- animations: this.src ? [
1395
- {
1396
- id: this._identifier
1397
- }
1398
- ] : []
1399
- } } = this.src ? await getAnimationData(this.src) : {};
1400
- try {
1401
- manifest.generator = pkg.name;
1402
- for (const config of configs){
1403
- const { url } = config, { animations: animationsToAdd } = await getAnimationData(url);
1404
- if (!animationsToAdd) {
1405
- throw new Error('No animation loaded');
1406
- }
1407
- if (manifest.animations.some(({ id })=>id === config.id)) {
1408
- throw new Error('Duplicate id for animation');
1409
- }
1410
- manifest.animations = [
1411
- ...manifest.animations,
1412
- {
1413
- id: config.id
1414
- }
1415
- ];
1416
- animations?.push(...animationsToAdd);
1417
- }
1418
- return {
1419
- result: await createDotLottie({
1420
- animations,
1421
- fileName,
1422
- manifest,
1423
- shouldDownload
1424
- }),
1425
- success: true
1426
- };
1427
- } catch (err) {
1428
- return {
1429
- error: handleErrors(err).message,
1430
- success: false
1431
- };
1432
- }
1433
- }
1434
- /**
1435
- * Returns the lottie-web instance used in the component
1436
- */ getLottie() {
1437
- return this._lottieInstance;
1438
- }
1439
- /**
1440
- * Play
1441
- */ async play() {
1442
- if (!this._lottieInstance) {
1443
- return;
1444
- }
1445
- if (this.playerState) {
1446
- this._playerState.prev = this.playerState;
1447
- }
1448
- try {
1449
- this._lottieInstance.play();
1450
- this.dispatchEvent(new CustomEvent(PlayerEvents.Play));
1451
- } finally{
1452
- this.playerState = PlayerState.Playing;
1453
- }
1454
- }
1455
- /**
1456
- * Pause
1457
- */ pause() {
1458
- if (!this._lottieInstance) {
1459
- return;
1460
- }
1461
- if (this.playerState) {
1462
- this._playerState.prev = this.playerState;
1463
- }
1464
- try {
1465
- this._lottieInstance.pause();
1466
- this.dispatchEvent(new CustomEvent(PlayerEvents.Pause));
1467
- } finally{
1468
- this.playerState = PlayerState.Paused;
1469
- }
1470
- }
1471
- /**
1472
- * Stop
1473
- */ stop() {
1474
- if (!this._lottieInstance) {
1475
- return;
1476
- }
1477
- if (this.playerState) {
1478
- this._playerState.prev = this.playerState;
1479
- }
1480
- this._playerState.count = 0;
1481
- try {
1482
- this._lottieInstance.stop();
1483
- this.dispatchEvent(new CustomEvent(PlayerEvents.Stop));
1484
- } finally{
1485
- this.playerState = PlayerState.Stopped;
1486
- }
1487
- }
1488
- /**
1489
- * Destroy animation and element
1490
- */ destroy() {
1491
- if (!this._lottieInstance) {
1492
- return;
1493
- }
1494
- this.playerState = PlayerState.Destroyed;
1495
- this._lottieInstance.destroy();
1496
- this._lottieInstance = null;
1497
- this.dispatchEvent(new CustomEvent(PlayerEvents.Destroyed));
1498
- this.remove();
1499
- document.removeEventListener('visibilitychange', this._onVisibilityChange);
1500
- }
1501
- /**
1502
- * Seek to a given frame
1503
- * @param { number | string } value Frame to seek to
1504
- */ seek(value) {
1505
- if (!this._lottieInstance) {
1506
- return;
1507
- }
1508
- // Extract frame number from either number or percentage value
1509
- const matches = value.toString().match(/^([0-9]+)(%?)$/);
1510
- if (!matches) {
1511
- return;
1512
- }
1513
- // Calculate and set the frame number
1514
- const frame = Math.round(matches[2] === '%' ? this._lottieInstance.totalFrames * Number(matches[1]) / 100 : Number(matches[1]));
1515
- // Set seeker to new frame number
1516
- this._seeker = frame;
1517
- // Send lottie player to the new frame
1518
- if (this.playerState === PlayerState.Playing || this.playerState === PlayerState.Frozen && this._playerState.prev === PlayerState.Playing) {
1519
- this._lottieInstance.goToAndPlay(frame, true);
1520
- this.playerState = PlayerState.Playing;
1521
- return;
1522
- }
1523
- this._lottieInstance.goToAndStop(frame, true);
1524
- this._lottieInstance.pause();
1525
- }
1526
- /**
1527
- * Snapshot and download the current frame as SVG
1528
- */ snapshot(shouldDownload = true, name = 'AM Lottie') {
1529
- try {
1530
- if (!this.shadowRoot) {
1531
- throw new Error('Unknown error');
1532
- }
1533
- // Get SVG element and serialize markup
1534
- const svgElement = this.shadowRoot.querySelector('.animation svg');
1535
- if (!svgElement) {
1536
- throw new Error('Could not retrieve animation from DOM');
1537
- }
1538
- const data = svgElement instanceof Node ? new XMLSerializer().serializeToString(svgElement) : null;
1539
- if (!data) {
1540
- throw new Error('Could not serialize SVG element');
1541
- }
1542
- if (shouldDownload) {
1543
- download(data, {
1544
- mimeType: 'image/svg+xml',
1545
- name: `${getFilename(this.src || name)}-${frameOutput(this._seeker)}.svg`
1546
- });
1547
- }
1548
- return data;
1549
- } catch (err) {
1550
- console.error(err);
1551
- return null;
1552
- }
1553
- }
1554
- /**
1555
- * Toggles subframe, for more smooth animations
1556
- * @param { boolean } value Whether animation uses subframe
1557
- */ setSubframe(value) {
1558
- if (!this._lottieInstance) {
1559
- return;
1560
- }
1561
- this._lottieInstance.setSubframe(value);
1562
- }
1563
- /**
1564
- * Dynamically set count for loops
1565
- */ setCount(value) {
1566
- this.count = value;
1567
- }
1568
- /**
1569
- * Freeze animation.
1570
- * This internal state pauses animation and is used to differentiate between
1571
- * user requested pauses and component instigated pauses.
1572
- */ _freeze() {
1573
- if (!this._lottieInstance) {
1574
- return;
1575
- }
1576
- if (this.playerState) {
1577
- this._playerState.prev = this.playerState;
1578
- }
1579
- try {
1580
- this._lottieInstance.pause();
1581
- this.dispatchEvent(new CustomEvent(PlayerEvents.Freeze));
1582
- } finally{
1583
- this.playerState = PlayerState.Frozen;
1584
- }
1585
- }
1586
- /**
1587
- * Reload animation
1588
- */ async reload() {
1589
- if (!this._lottieInstance || !this.src) {
1590
- return;
1591
- }
1592
- this._lottieInstance.destroy();
1593
- await this.load(this.src);
1594
- }
1595
- /**
1596
- * Set animation playback speed
1597
- * @param { number } value Playback speed
1598
- */ setSpeed(value = 1) {
1599
- if (!this._lottieInstance) {
1600
- return;
1601
- }
1602
- this._lottieInstance.setSpeed(value);
1603
- }
1604
- /**
1605
- * Animation play direction
1606
- * @param { AnimationDirection } value Animation direction
1607
- */ setDirection(value) {
1608
- if (!this._lottieInstance) {
1609
- return;
1610
- }
1611
- this._lottieInstance.setDirection(value);
1612
- }
1613
- /**
1614
- * Set loop
1615
- * @param { boolean } value
1616
- */ setLoop(value) {
1617
- if (!this._lottieInstance) {
1618
- return;
1619
- }
1620
- this._lottieInstance.setLoop(value);
1621
- }
1622
- /**
1623
- * Toggle playing state
1624
- */ togglePlay() {
1625
- if (!this._lottieInstance) {
1626
- return;
1627
- }
1628
- const { currentFrame, playDirection, totalFrames } = this._lottieInstance;
1629
- if (this.playerState === PlayerState.Playing) {
1630
- return this.pause();
1631
- }
1632
- if (this.playerState !== PlayerState.Completed) {
1633
- return this.play();
1634
- }
1635
- this.playerState = PlayerState.Playing;
1636
- if (this._isBounce) {
1637
- this.setDirection(playDirection * -1);
1638
- return this._lottieInstance.goToAndPlay(currentFrame, true);
1639
- }
1640
- if (playDirection === -1) {
1641
- return this._lottieInstance.goToAndPlay(totalFrames, true);
1642
- }
1643
- return this._lottieInstance.goToAndPlay(0, true);
1644
- }
1645
- /**
1646
- * Toggle loop
1647
- */ toggleLoop() {
1648
- const val = !this.loop;
1649
- this.loop = val;
1650
- this.setLoop(val);
1651
- }
1652
- /**
1653
- * Toggle Boomerang
1654
- */ toggleBoomerang() {
1655
- const curr = this._multiAnimationSettings?.[this._currentAnimation];
1656
- if (curr?.mode !== undefined) {
1657
- if (curr.mode === PlayMode.Normal) {
1658
- curr.mode = PlayMode.Bounce;
1659
- this._isBounce = true;
1660
- return;
1661
- }
1662
- curr.mode = PlayMode.Normal;
1663
- this._isBounce = false;
1664
- return;
1665
- }
1666
- if (this.mode === PlayMode.Normal) {
1667
- this.mode = PlayMode.Bounce;
1668
- this._isBounce = true;
1669
- return;
1670
- }
1671
- this.mode = PlayMode.Normal;
1672
- this._isBounce = false;
1673
- }
1674
- /**
1675
- * Toggle show Settings
1676
- */ _toggleSettings(flag) {
1677
- if (flag === undefined) {
1678
- this._isSettingsOpen = !this._isSettingsOpen;
1679
- return;
1680
- }
1681
- this._isSettingsOpen = flag;
1682
- }
1683
- /**
1684
- * Handle blur
1685
- */ _handleBlur() {
1686
- setTimeout(()=>this._toggleSettings(false), 200);
1687
- }
1688
- _switchInstance(isPrevious = false) {
1689
- // Bail early if there is not animation to play
1690
- if (!this._animations[this._currentAnimation]) {
1691
- return;
1692
- }
1693
- try {
1694
- // Clear previous animation
1695
- if (this._lottieInstance) {
1696
- this._lottieInstance.destroy();
1697
- }
1698
- // Re-initialize lottie player
1699
- this._lottieInstance = Lottie.default.loadAnimation({
1700
- ...this._getOptions(),
1701
- animationData: this._animations[this._currentAnimation]
1702
- });
1703
- // Check play mode for current animation
1704
- if (this._multiAnimationSettings?.[this._currentAnimation]?.mode) {
1705
- this._isBounce = this._multiAnimationSettings[this._currentAnimation].mode === PlayMode.Bounce;
1706
- }
1707
- // Remove event listeners to new Lottie instance, and add new
1708
- this._removeEventListeners();
1709
- this._addEventListeners();
1710
- this.dispatchEvent(new CustomEvent(isPrevious ? PlayerEvents.Previous : PlayerEvents.Next));
1711
- if (this._multiAnimationSettings?.[this._currentAnimation]?.autoplay ?? this.autoplay) {
1712
- if (this.animateOnScroll) {
1713
- this._lottieInstance?.goToAndStop(0, true);
1714
- this.playerState = PlayerState.Paused;
1715
- return;
1716
- }
1717
- this._lottieInstance?.goToAndPlay(0, true);
1718
- this.playerState = PlayerState.Playing;
1719
- return;
1720
- }
1721
- this._lottieInstance?.goToAndStop(0, true);
1722
- this.playerState = PlayerState.Stopped;
1723
- } catch (err) {
1724
- this._errorMessage = handleErrors(err).message;
1725
- this.playerState = PlayerState.Error;
1726
- this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1727
- }
1728
- }
1729
- /**
1730
- * Skip to next animation
1731
- */ next() {
1732
- this._currentAnimation++;
1733
- this._switchInstance();
1734
- }
1735
- /**
1736
- * Skip to previous animation
1737
- */ prev() {
1738
- this._currentAnimation--;
1739
- this._switchInstance(true);
1740
- }
1741
- async convert({ animations, fileName, manifest, shouldDownload = true, src, typeCheck }) {
1742
- if (typeCheck || this._isDotLottie) {
1743
- return createJSON({
1744
- animation: (await getAnimationData(src || this.src))?.animations?.[0],
1745
- fileName: `${getFilename(fileName || this.src || 'converted')}.json`,
1746
- shouldDownload
1747
- });
1748
- }
1749
- return createDotLottie({
1750
- animations: animations || (await getAnimationData(this.src))?.animations,
1751
- fileName: `${getFilename(fileName || this.src || 'converted')}.lottie`,
1752
- manifest: {
1753
- ...manifest || this._manifest,
1754
- generator: pkg.name
1755
- },
1756
- shouldDownload
1757
- });
1758
- }
1759
- /**
1760
- * Return the styles for the component
1761
- */ static get styles() {
1762
- const styleSheet = new CSSStyleSheet();
1763
- styleSheet.replace(css_248z);
1764
- return styleSheet;
1765
- }
1766
- }
1767
-
1768
- /**
1769
- * Expose DotLottiePlayer class as global variable
1770
- * @returns { DotLottiePlayer }
1771
- */ globalThis.dotLottiePlayer = ()=>new DotLottiePlayer();
1772
- const tagName = 'dotlottie-player';
1773
- if (!isServer()) {
1774
- customElements.define('dotlottie-player', DotLottiePlayer);
1775
- }
1776
-
1777
- export { PlayMode, PlayerEvents, PlayerState, DotLottiePlayer as default, tagName };