@aarsteinmedia/dotlottie-player 5.0.1 → 5.0.3

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/index.js CHANGED
@@ -1,13 +1,72 @@
1
+ import { isServer as isServer$1, createElementID, PreserveAspectRatio as PreserveAspectRatio$1 } from '@aarsteinmedia/lottie-web/utils';
2
+ import Lottie from 'lottie-web';
1
3
  import { strToU8, strFromU8, zip, unzip as unzip$1 } from 'fflate';
2
- import { createElementID } from '@aarsteinmedia/lottie-web/utils';
3
- import * as Lottie from 'lottie-web/build/player/lottie.js';
4
+
5
+ /**
6
+ * Credit to: Leonardo Favre https://github.com/leofavre/observed-properties.
7
+ */ const updateOnConnected = Symbol('UPDATE_ON_CONNECTED');
8
+ if (isServer$1()) {
9
+ // Mock HTMLElement for server-side rendering
10
+ global.HTMLElement = // eslint-disable-next-line @typescript-eslint/no-extraneous-class
11
+ class EmptyHTMLElement {
12
+ };
13
+ }
14
+ /**
15
+ * HTMLElement enhanced to track property changes.
16
+ */ class PropertyCallbackElement extends HTMLElement {
17
+ constructor(){
18
+ super();
19
+ if (updateOnConnected in this) {
20
+ this[updateOnConnected] = [];
21
+ }
22
+ const { observedProperties = [] } = this.constructor;
23
+ const { length } = observedProperties;
24
+ for(let i = 0; i < length; i++){
25
+ const initialValue = this[observedProperties[i]], cachedValue = Symbol(observedProperties[i]);
26
+ this[cachedValue] = initialValue;
27
+ Object.defineProperty(this, observedProperties[i], {
28
+ get () {
29
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
30
+ return this[cachedValue];
31
+ },
32
+ set (value) {
33
+ const oldValue = this[cachedValue];
34
+ this[cachedValue] = value;
35
+ this.propertyChangedCallback(observedProperties[i], oldValue, value);
36
+ }
37
+ });
38
+ if (typeof initialValue !== 'undefined' && updateOnConnected in this && Array.isArray(this[updateOnConnected])) {
39
+ this[updateOnConnected].push(observedProperties[i]);
40
+ }
41
+ }
42
+ }
43
+ // eslint-disable-next-line @typescript-eslint/require-await
44
+ async connectedCallback() {
45
+ let arr = [];
46
+ if (updateOnConnected in this && Array.isArray(this[updateOnConnected])) {
47
+ arr = this[updateOnConnected];
48
+ }
49
+ const { length } = arr;
50
+ for(let i = 0; i < length; i++){
51
+ if (!('propertyChangedCallback' in this) || typeof this.propertyChangedCallback !== 'function') {
52
+ continue;
53
+ }
54
+ if (arr[i] in this) {
55
+ this.propertyChangedCallback(arr[i], undefined, this[arr[i]]);
56
+ }
57
+ }
58
+ }
59
+ propertyChangedCallback(_name, _oldValue, _value) {
60
+ throw new Error(`${this.constructor.name}: Method propertyChangedCallback is not implemented`);
61
+ }
62
+ }
4
63
 
5
64
  var ObjectFit = /*#__PURE__*/ function(ObjectFit) {
6
65
  ObjectFit["Contain"] = "contain";
7
66
  ObjectFit["Cover"] = "cover";
8
67
  ObjectFit["Fill"] = "fill";
9
- ObjectFit["ScaleDown"] = "scale-down";
10
68
  ObjectFit["None"] = "none";
69
+ ObjectFit["ScaleDown"] = "scale-down";
11
70
  return ObjectFit;
12
71
  }({});
13
72
  var PlayerState = /*#__PURE__*/ function(PlayerState) {
@@ -46,20 +105,298 @@ var PlayerEvents = /*#__PURE__*/ function(PlayerEvents) {
46
105
  var PreserveAspectRatio = /*#__PURE__*/ function(PreserveAspectRatio) {
47
106
  PreserveAspectRatio["Contain"] = "xMidYMid meet";
48
107
  PreserveAspectRatio["Cover"] = "xMidYMid slice";
49
- PreserveAspectRatio["None"] = "xMinYMin slice";
50
108
  PreserveAspectRatio["Initial"] = "none";
109
+ PreserveAspectRatio["None"] = "xMinYMin slice";
51
110
  return PreserveAspectRatio;
52
111
  }({});
53
112
  var RendererType = /*#__PURE__*/ function(RendererType) {
54
- RendererType["SVG"] = "svg";
55
- RendererType["HTML"] = "html";
56
113
  RendererType["Canvas"] = "canvas";
114
+ RendererType["HTML"] = "html";
115
+ RendererType["SVG"] = "svg";
57
116
  return RendererType;
58
117
  }({});
59
118
 
119
+ 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 0.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: 0.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: 0.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: 0.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 0.2s ease-in-out;\n transition: transform 0.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 0.2s ease-in-out;\n transition: transform 0.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 0.2s ease-in-out;\n transition: transform 0.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@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";
120
+
121
+ /**
122
+ * Render Controls.
123
+ */ function renderControls() {
124
+ if (!this.shadow) {
125
+ throw new Error('No Shadow Element');
126
+ }
127
+ const slot = this.shadow.querySelector('slot[name=controls]');
128
+ if (!slot) {
129
+ return;
130
+ }
131
+ if (!this.controls) {
132
+ slot.innerHTML = '';
133
+ return;
134
+ }
135
+ 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="${Boolean(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>`;
136
+ const togglePlay = this.shadow.querySelector('.togglePlay');
137
+ if (togglePlay instanceof HTMLButtonElement) {
138
+ togglePlay.onclick = this.togglePlay;
139
+ }
140
+ const stop = this.shadow.querySelector('.stop');
141
+ if (stop instanceof HTMLButtonElement) {
142
+ stop.onclick = this.stop;
143
+ }
144
+ const prev = this.shadow.querySelector('.prev');
145
+ if (prev instanceof HTMLButtonElement) {
146
+ prev.onclick = this.prev;
147
+ }
148
+ const next = this.shadow.querySelector('.next');
149
+ if (next instanceof HTMLButtonElement) {
150
+ next.onclick = this.next;
151
+ }
152
+ const seeker = this.shadow.querySelector('.seeker');
153
+ if (seeker instanceof HTMLInputElement) {
154
+ seeker.onchange = this._handleSeekChange;
155
+ seeker.onmousedown = this._freeze;
156
+ }
157
+ if (!this.simple) {
158
+ const toggleLoop = this.shadow.querySelector('.toggleLoop');
159
+ if (toggleLoop instanceof HTMLButtonElement) {
160
+ toggleLoop.onclick = this.toggleLoop;
161
+ }
162
+ const toggleBoomerang = this.shadow.querySelector('.toggleBoomerang');
163
+ if (toggleBoomerang instanceof HTMLButtonElement) {
164
+ toggleBoomerang.onclick = this.toggleBoomerang;
165
+ }
166
+ const convert = this.shadow.querySelector('.convert');
167
+ if (convert instanceof HTMLButtonElement) {
168
+ convert.onclick = this.convert;
169
+ }
170
+ const snapshot = this.shadow.querySelector('.snapshot');
171
+ if (snapshot instanceof HTMLButtonElement) {
172
+ snapshot.onclick = ()=>this.snapshot(true);
173
+ }
174
+ const toggleSettings = this.shadow.querySelector('.toggleSettings');
175
+ if (toggleSettings instanceof HTMLButtonElement) {
176
+ toggleSettings.onclick = this._handleSettingsClick;
177
+ toggleSettings.onblur = this._handleBlur;
178
+ }
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Render Player.
184
+ */ async function renderPlayer() {
185
+ if (!this.shadow) {
186
+ throw new Error('No Shadow Element');
187
+ }
188
+ 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>`;
189
+ this.shadow.adoptedStyleSheets = [
190
+ await DotLottiePlayer.styles()
191
+ ];
192
+ this.shadow.appendChild(this.template.content.cloneNode(true));
193
+ }
194
+
60
195
  class CustomError extends Error {
61
196
  }
62
- const addExt = (ext, str)=>{
197
+ /**
198
+ * Methods used locally and exported.
199
+ */ const getManifest = (unzipped)=>{
200
+ const file = strFromU8(unzipped['manifest.json'], false), manifest = JSON.parse(file);
201
+ if (!('animations' in manifest)) {
202
+ throw new Error('Manifest not found');
203
+ }
204
+ if (manifest.animations.length === 0) {
205
+ throw new Error('No animations listed in manifest');
206
+ }
207
+ return manifest;
208
+ }, isServer = ()=>!(typeof window !== 'undefined' && window.document);
209
+ /**
210
+ * Methods used only locally.
211
+ */ const hasExt = (path)=>{
212
+ const lastDotIndex = path?.split('/').pop()?.lastIndexOf('.');
213
+ return (lastDotIndex ?? 0) > 1 && path && path.length - 1 > (lastDotIndex ?? 0);
214
+ };
215
+ /**
216
+ * Get extension from filename, URL or path.
217
+ */ const getExt = (str)=>{
218
+ if (typeof str !== 'string' || !str || !hasExt(str)) {
219
+ return;
220
+ }
221
+ return str.split('.').pop()?.toLowerCase();
222
+ };
223
+ const unzip = async (resp)=>{
224
+ const u8 = new Uint8Array(await resp.arrayBuffer()), unzipped = await new Promise((resolve, reject)=>{
225
+ unzip$1(u8, (err, file)=>{
226
+ if (err) {
227
+ reject(err);
228
+ }
229
+ resolve(file);
230
+ });
231
+ });
232
+ return unzipped;
233
+ }, getArrayBuffer = async (zippable)=>{
234
+ const arrayBuffer = await new Promise((resolve, reject)=>{
235
+ zip(zippable, {
236
+ level: 9
237
+ }, (err, data)=>{
238
+ if (err) {
239
+ reject(err);
240
+ return;
241
+ }
242
+ if (!(data.buffer instanceof ArrayBuffer)) {
243
+ reject(new Error('Data is not transferable'));
244
+ return;
245
+ }
246
+ resolve(data.buffer);
247
+ });
248
+ });
249
+ return arrayBuffer;
250
+ }, getMimeFromExt = (ext)=>{
251
+ switch(ext){
252
+ case 'svg':
253
+ case 'svg+xml':
254
+ {
255
+ return 'image/svg+xml';
256
+ }
257
+ case 'jpg':
258
+ case 'jpeg':
259
+ {
260
+ return 'image/jpeg';
261
+ }
262
+ case 'png':
263
+ case 'gif':
264
+ case 'webp':
265
+ case 'avif':
266
+ {
267
+ return `image/${ext}`;
268
+ }
269
+ case 'mp3':
270
+ case 'mpeg':
271
+ case 'wav':
272
+ {
273
+ return `audio/${ext}`;
274
+ }
275
+ default:
276
+ {
277
+ return '';
278
+ }
279
+ }
280
+ }, isAudio = (asset)=>!('h' in asset) && !('w' in asset) && 'p' in asset && 'e' in asset && 'u' in asset && 'id' in asset, isImage = (asset)=>'w' in asset && 'h' in asset && !('xt' in asset) && 'p' in asset, parseBase64 = (str)=>str.slice(Math.max(0, str.indexOf(',') + 1)), isBase64 = (str)=>{
281
+ if (!str) {
282
+ return false;
283
+ }
284
+ const regex = /^(?:[0-9a-z+/]{4})*(?:[0-9a-z+/]{2}==|[0-9a-z+/]{3}=)?$/i;
285
+ return regex.test(parseBase64(str));
286
+ }, resolveAssets = async (unzipped, assets)=>{
287
+ if (!Array.isArray(assets)) {
288
+ return;
289
+ }
290
+ const toResolve = [], { length } = assets;
291
+ for(let i = 0; i < length; i++){
292
+ if (!isAudio(assets[i]) && !isImage(assets[i])) {
293
+ continue;
294
+ }
295
+ const type = isImage(assets[i]) ? 'images' : 'audio', u8 = unzipped?.[`${type}/${assets[i].p}`];
296
+ if (!u8) {
297
+ continue;
298
+ }
299
+ toResolve.push(new Promise((resolveAsset)=>{
300
+ let assetB64;
301
+ if (isServer()) {
302
+ assetB64 = Buffer.from(u8).toString('base64');
303
+ } else {
304
+ let result = '';
305
+ const { length: jLen } = u8;
306
+ for(let j = 0; j < jLen; j++){
307
+ result += String.fromCharCode(u8[j]);
308
+ }
309
+ assetB64 = btoa(result);
310
+ }
311
+ assets[i].p = assets[i].p?.startsWith('data:') || isBase64(assets[i].p) ? assets[i].p : `data:${getMimeFromExt(getExt(assets[i].p))};base64,${assetB64}`;
312
+ assets[i].e = 1;
313
+ assets[i].u = '';
314
+ resolveAsset();
315
+ }));
316
+ }
317
+ await Promise.all(toResolve);
318
+ }, prepareString = (str)=>str.replaceAll(new RegExp(/"""/, 'g'), '""').replaceAll(/(["'])(.*?)\1/g, (_match, quote, content)=>{
319
+ const replacedContent = content.replaceAll(/[^\w\s.#]/g, '');
320
+ return `${quote}${replacedContent}${quote}`;
321
+ }), fileToBase64 = async (url)=>{
322
+ const response = await fetch(url), blob = await response.blob();
323
+ return new Promise((resolve, reject)=>{
324
+ try {
325
+ const reader = new FileReader();
326
+ reader.onload = ()=>{
327
+ if (typeof reader.result === 'string') {
328
+ resolve(reader.result);
329
+ return;
330
+ }
331
+ reject(new Error('Could not create bas64'));
332
+ };
333
+ reader.readAsDataURL(blob);
334
+ } catch (error) {
335
+ reject(error);
336
+ }
337
+ });
338
+ }, getLottieJSON = async (resp)=>{
339
+ const unzipped = await unzip(resp), manifest = getManifest(unzipped), data = [], toResolve = [], { length } = manifest.animations;
340
+ /**
341
+ * Check whether Lottie animations folder is abbreviated.
342
+ */ let animationsFolder = 'animations';
343
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
344
+ if (unzipped[`a/${manifest.animations[0].id}.json`]) {
345
+ animationsFolder = 'a';
346
+ }
347
+ for(let i = 0; i < length; i++){
348
+ const str = strFromU8(unzipped[`${animationsFolder}/${manifest.animations[i].id}.json`]), lottie = JSON.parse(prepareString(str));
349
+ // Handle Expressions
350
+ const { length: jLen } = lottie.layers;
351
+ for(let j = 0; j < jLen; j++){
352
+ const { ks: shape } = lottie.layers[j], props = Object.keys(shape), { length: pLen } = props;
353
+ for(let p = 0; p < pLen; p++){
354
+ const { e: isEncoded, x: expression } = shape[props[p]];
355
+ if (!expression || !isEncoded) {
356
+ continue;
357
+ }
358
+ // Base64 Decode to handle compression
359
+ // @ts-expect-error
360
+ lottie.layers[j].ks[props[p]].x = atob(expression);
361
+ }
362
+ }
363
+ toResolve.push(resolveAssets(unzipped, lottie.assets));
364
+ data.push(lottie);
365
+ }
366
+ await Promise.all(toResolve);
367
+ return {
368
+ data,
369
+ manifest
370
+ };
371
+ };
372
+ /**
373
+ * Download file, either SVG or dotLottie.
374
+ */ const download = (data, options)=>{
375
+ const blob = new Blob([
376
+ data
377
+ ], {
378
+ type: options?.mimeType
379
+ }), fileName = options?.name || createElementID(), dataURL = URL.createObjectURL(blob), link = document.createElement('a');
380
+ link.href = dataURL;
381
+ link.download = fileName;
382
+ link.hidden = true;
383
+ document.body.appendChild(link);
384
+ link.click();
385
+ setTimeout(()=>{
386
+ link.remove();
387
+ URL.revokeObjectURL(dataURL);
388
+ }, 1000);
389
+ }, /**
390
+ * Parse URL to get filename.
391
+ *
392
+ * @param src - The url string.
393
+ * @param keepExt - Whether to include file extension.
394
+ * @returns Filename, in lowercase.
395
+ */ getFilename = (src, keepExt)=>{
396
+ // Because the regex strips all special characters, we need to extract the file extension, so we can add it later if we need it
397
+ getExt(src);
398
+ return `${src.split('/').pop()?.replace(/\.[^.]*$/, '').replaceAll(/\W+/g, '-')}${''}`;
399
+ }, addExt = (ext, str)=>{
63
400
  if (!str) {
64
401
  return;
65
402
  }
@@ -74,30 +411,59 @@ const addExt = (ext, str)=>{
74
411
  switch(objectFit){
75
412
  case ObjectFit.Contain:
76
413
  case ObjectFit.ScaleDown:
77
- return 'xMidYMid meet';
414
+ {
415
+ return PreserveAspectRatio$1.Contain;
416
+ }
78
417
  case ObjectFit.Cover:
79
- return 'xMidYMid slice';
418
+ {
419
+ return PreserveAspectRatio$1.Cover;
420
+ }
80
421
  case ObjectFit.Fill:
81
- return 'none';
422
+ {
423
+ return PreserveAspectRatio$1.Initial;
424
+ }
82
425
  case ObjectFit.None:
83
- return 'xMinYMin slice';
426
+ {
427
+ return PreserveAspectRatio$1.None;
428
+ }
84
429
  default:
85
- return 'xMidYMid meet';
430
+ {
431
+ return PreserveAspectRatio$1.Contain;
432
+ }
86
433
  }
87
434
  }, /**
88
- * Convert Base64 encoded string to Uint8Array
89
- * @param { string } str Base64 encoded string
90
- * @returns { Uint8Array } UTF-8/Latin-1 binary
91
- */ base64ToU8 = (str)=>strToU8(isServer() ? Buffer.from(parseBase64(str), 'base64').toString('binary') : atob(parseBase64(str)), true), /**
92
- * Convert a JSON Lottie to dotLottie or combine several animations and download new dotLottie file in your browser.
435
+ * Convert Base64 encoded string to Uint8Array.
436
+ *
437
+ * @param str - Base64 encoded string.
438
+ * @returns UTF-8/Latin-1 binary.
439
+ */ base64ToU8 = (str)=>strToU8(isServer() ? Buffer.from(parseBase64(str), 'base64').toString('binary') : atob(parseBase64(str)), true), getExtFromB64 = (str)=>{
440
+ const mime = str.split(':')[1].split(';')[0], ext = mime.split('/')[1].split('+')[0];
441
+ return ext;
442
+ }, handleErrors = (err)=>{
443
+ const res = {
444
+ message: 'Unknown error',
445
+ status: isServer() ? 500 : 400
446
+ };
447
+ if (err && typeof err === 'object') {
448
+ if ('message' in err && typeof err.message === 'string') {
449
+ res.message = err.message;
450
+ }
451
+ if ('status' in err) {
452
+ res.status = Number(err.status);
453
+ }
454
+ }
455
+ return res;
456
+ }, /**
457
+ * Convert a JSON Lottie to dotLottie or combine several animations and download new dotLottie file in your browser.
93
458
  */ createDotLottie = async ({ animations = [], fileName, manifest, shouldDownload = true })=>{
94
459
  try {
95
460
  // Input validation
96
- if (!animations.length || !manifest) {
97
- throw new Error(`Missing or malformed required parameter(s):\n ${animations.length ? '- manifest\n' : ''} ${manifest ? '- animations\n' : ''}`);
461
+ if (animations.length === 0 || !manifest) {
462
+ throw new Error(`Missing or malformed required parameter(s):\n ${animations.length > 0 ? '- manifest\n' : ''} ${manifest ? '- animations\n' : ''}`);
98
463
  }
99
- const manifestCompressionLevel = 0, animationCompressionLevel = 9, // Prepare the dotLottie file
100
- name = addExt('lottie', fileName) || `${createElementID()}.lottie`, dotlottie = {
464
+ const manifestCompressionLevel = 0, animationCompressionLevel = 9, /**
465
+ * Prepare the dotLottie file.
466
+ */ name = addExt('lottie', fileName) || `${createElementID()}.lottie`, dotlottie = {
101
467
  'manifest.json': [
102
468
  strToU8(JSON.stringify(manifest), true),
103
469
  {
@@ -109,30 +475,53 @@ const addExt = (ext, str)=>{
109
475
  const { length } = animations;
110
476
  for(let i = 0; i < length; i++){
111
477
  const { length: jLen } = animations[i].assets;
478
+ // Prepare assets
112
479
  for(let j = 0; j < jLen; j++){
113
- if (!animations[i].assets[j].p || !isImage(animations[i].assets[j]) && !isAudio(animations[i].assets[j])) {
480
+ const asset = animations[i].assets[j];
481
+ if (!asset.p || !isImage(asset) && !isAudio(asset)) {
114
482
  continue;
115
483
  }
116
- const { p: file, u: path } = animations[i].assets[j];
484
+ const { p: file, u: path } = asset;
117
485
  if (!file) {
118
486
  continue;
119
487
  }
120
488
  // Original asset.id caused issues with multianimations
121
- const assetId = createElementID(), 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
122
- dataURL = isEncoded ? file : await fileToBase64(path ? path.endsWith('/') && `${path}${file}` || `${path}/${file}` : file);
489
+ const assetId = createElementID(), isEncoded = file.startsWith('data:'), ext = isEncoded ? getExtFromB64(file) : getExt(file), /**
490
+ * Check if the asset is already base64-encoded. If not, get path, fetch it, and encode it.
491
+ */ dataURL = isEncoded ? file : await fileToBase64(path ? path.endsWith('/') && `${path}${file}` || `${path}/${file}` : file);
492
+ // Asset is encoded
493
+ // eslint-disable-next-line require-atomic-updates
494
+ animations[i].assets[j].e = 1;
495
+ // eslint-disable-next-line require-atomic-updates
123
496
  animations[i].assets[j].p = `${assetId}.${ext}`;
124
497
  // Asset is embedded, so path empty string
498
+ // eslint-disable-next-line require-atomic-updates
125
499
  animations[i].assets[j].u = '';
126
- // Asset is encoded
127
- animations[i].assets[j].e = 1;
128
- dotlottie[`${isAudio(animations[i].assets[j]) ? 'audio' : 'images'}/${assetId}.${ext}`] = [
500
+ dotlottie[`${isAudio(asset) ? 'audio' : 'images'}/${assetId}.${ext}`] = [
129
501
  base64ToU8(dataURL),
130
502
  {
131
503
  level: animationCompressionLevel
132
504
  }
133
505
  ];
134
506
  }
135
- dotlottie[`animations/${manifest.animations[i].id}.json`] = [
507
+ // Prepare expressions
508
+ const { length: kLen } = animations[i].layers;
509
+ for(let k = 0; k < kLen; k++){
510
+ const { ks: shape } = animations[i].layers[k], props = Object.keys(shape), { length: pLen } = props;
511
+ for(let p = 0; p < pLen; p++){
512
+ const { x: expression } = shape[props[p]];
513
+ if (!expression) {
514
+ continue;
515
+ }
516
+ // Base64 Encode to handle compression
517
+ // @ts-expect-error: We have checked this property is set
518
+ animations[i].layers[k].ks[props[p]].x = btoa(expression);
519
+ // Set e (encoded) to 1
520
+ // @ts-expect-error: We have checked this property is set
521
+ animations[i].layers[k].ks[props[p]].e = 1;
522
+ }
523
+ }
524
+ dotlottie[`a/${manifest.animations[i].id}.json`] = [
136
525
  strToU8(JSON.stringify(animations[i]), true),
137
526
  {
138
527
  level: animationCompressionLevel
@@ -140,62 +529,34 @@ const addExt = (ext, str)=>{
140
529
  ];
141
530
  }
142
531
  const buffer = await getArrayBuffer(dotlottie);
143
- return shouldDownload ? download(buffer, {
144
- mimeType: 'application/zip',
145
- name
146
- }) : buffer;
147
- } catch (err) {
148
- console.error(`❌ ${handleErrors(err).message}`);
532
+ if (shouldDownload) {
533
+ download(buffer, {
534
+ mimeType: 'application/zip',
535
+ name
536
+ });
537
+ return null;
538
+ }
539
+ return buffer;
540
+ } catch (error) {
541
+ console.error(`❌ ${handleErrors(error).message}`);
542
+ return null;
149
543
  }
150
544
  }, createJSON = ({ animation, fileName, shouldDownload })=>{
151
545
  try {
152
546
  if (!animation) {
153
- throw new Error("createJSON: Missing or malformed required parameter(s):\n - animation\n'");
547
+ throw new Error('createJSON: Missing or malformed required parameter(s):\n - animation\n\'');
154
548
  }
155
549
  const name = addExt('json', fileName) || `${createElementID()}.json`, jsonString = JSON.stringify(animation);
156
- return shouldDownload ? download(jsonString, {
157
- mimeType: 'application/json',
158
- name
159
- }) : jsonString;
160
- } catch (err) {
161
- console.error(`❌ ${handleErrors(err).message}`);
162
- }
163
- }, /**
164
- * Download file, either SVG or dotLottie.
165
- * @param { string } data The data to be downloaded
166
- * @param { string } name Don't include file extension in the filename
167
- */ download = (data, options)=>{
168
- const blob = new Blob([
169
- data
170
- ], {
171
- type: options?.mimeType
172
- }), fileName = options?.name || createElementID(), dataURL = URL.createObjectURL(blob), link = document.createElement('a');
173
- link.href = dataURL;
174
- link.download = fileName;
175
- link.hidden = true;
176
- document.body.appendChild(link);
177
- link.click();
178
- setTimeout(()=>{
179
- link.remove();
180
- URL.revokeObjectURL(dataURL);
181
- }, 1000);
182
- }, fileToBase64 = async (url)=>{
183
- const response = await fetch(url), blob = await response.blob();
184
- return new Promise((resolve, reject)=>{
185
- try {
186
- const reader = new FileReader();
187
- reader.onload = ()=>{
188
- if (typeof reader.result === 'string') {
189
- resolve(reader.result);
190
- return;
191
- }
192
- reject();
193
- };
194
- reader.readAsDataURL(blob);
195
- } catch (e) {
196
- reject(e);
550
+ if (shouldDownload) {
551
+ download(jsonString, {
552
+ mimeType: 'application/json',
553
+ name
554
+ });
197
555
  }
198
- });
556
+ return;
557
+ } catch (error) {
558
+ console.error(`❌ ${handleErrors(error).message}`);
559
+ }
199
560
  }, frameOutput = (frame)=>((frame ?? 0) + 1).toString().padStart(3, '0'), getAnimationData = async (input)=>{
200
561
  try {
201
562
  if (!input || typeof input !== 'string' && typeof input !== 'object') {
@@ -261,329 +622,265 @@ const addExt = (ext, str)=>{
261
622
  isDotLottie: true,
262
623
  manifest
263
624
  };
264
- } catch (err) {
265
- console.error(`❌ ${handleErrors(err).message}`);
625
+ } catch (error) {
626
+ console.error(`❌ ${handleErrors(error).message}`);
266
627
  return {
267
628
  animations: undefined,
268
629
  isDotLottie: false,
269
630
  manifest: null
270
631
  };
271
632
  }
272
- }, getArrayBuffer = async (zippable)=>{
273
- const arrayBuffer = await new Promise((resolve, reject)=>{
274
- zip(zippable, {
275
- level: 9
276
- }, (err, data)=>{
277
- if (err) {
278
- reject(err);
279
- return;
280
- }
281
- if (!(data.buffer instanceof ArrayBuffer)) {
282
- reject('Data is not transferable');
283
- return;
284
- }
285
- resolve(data.buffer);
286
- });
287
- });
288
- return arrayBuffer;
289
- }, /**
290
- * Get extension from filename, URL or path
291
- * @param { string } str Filename, URL or path
292
- */ getExt = (str)=>{
293
- if (typeof str !== 'string' || !str || !hasExt(str)) {
294
- return;
295
- }
296
- return str.split('.').pop()?.toLowerCase();
297
- }, getExtFromB64 = (str)=>{
298
- const mime = str.split(':')[1].split(';')[0], ext = mime.split('/')[1].split('+')[0];
299
- return ext;
300
- }, /**
301
- * Parse URL to get filename
302
- * @param { string } src The url string
303
- * @param { boolean } keepExt Whether to include file extension
304
- * @returns { string } Filename, in lowercase
305
- */ getFilename = (src, keepExt)=>{
306
- // Because the regex strips all special characters, we need to extract the file extension, so we can add it later if we need it
307
- getExt(src);
308
- return `${src.split('/').pop()?.replace(/\.[^.]*$/, '').replace(/\W+/g, '-')}${''}` // .toLowerCase()
309
- ;
310
- }, getLottieJSON = async (resp)=>{
311
- const unzipped = await unzip(resp), manifest = getManifest(unzipped), data = [], toResolve = [], { length } = manifest.animations;
633
+ };
634
+
635
+ const generator = '@aarsteinmedia/dotlottie-player';
636
+ /**
637
+ * DotLottie Player Web Component.
638
+ */ class DotLottiePlayer extends PropertyCallbackElement {
312
639
  /**
313
- * Check whether Lottie animations folder is abbreviated.
314
- */ let animationsFolder = 'animations';
315
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
316
- if (unzipped[`a/${manifest.animations[0].id}.json`]) {
317
- animationsFolder = 'a';
640
+ * Attributes to observe.
641
+ */ static get observedAttributes() {
642
+ return [
643
+ 'animateOnScroll',
644
+ 'autoplay',
645
+ 'controls',
646
+ 'direction',
647
+ 'hover',
648
+ 'loop',
649
+ 'mode',
650
+ 'speed',
651
+ 'src',
652
+ 'subframe'
653
+ ];
318
654
  }
319
- for(let i = 0; i < length; i++){
320
- const str = strFromU8(unzipped[`${animationsFolder}/${manifest.animations[i].id}.json`]), lottie = JSON.parse(prepareString(str));
321
- toResolve.push(resolveAssets(unzipped, lottie.assets));
322
- data.push(lottie);
655
+ static get observedProperties() {
656
+ return [
657
+ 'playerState',
658
+ '_isSettingsOpen',
659
+ '_seeker',
660
+ '_currentAnimation',
661
+ '_animations'
662
+ ];
323
663
  }
324
- await Promise.all(toResolve);
325
- return {
326
- data,
327
- manifest
328
- };
329
- }, getManifest = (unzipped)=>{
330
- const file = strFromU8(unzipped['manifest.json'], false), manifest = JSON.parse(file);
331
- if (!('animations' in manifest)) {
332
- throw new Error('Manifest not found');
664
+ /**
665
+ * Return the styles for the component.
666
+ */ static get styles() {
667
+ return async ()=>{
668
+ const styleSheet = new CSSStyleSheet();
669
+ await styleSheet.replace(css_248z);
670
+ return styleSheet;
671
+ };
333
672
  }
334
- if (!manifest.animations.length) {
335
- throw new Error('No animations listed in manifest');
673
+ /**
674
+ * Whether to trigger next frame with scroll.
675
+ */ set animateOnScroll(value) {
676
+ this.setAttribute('animateOnScroll', Boolean(value).toString());
336
677
  }
337
- return manifest;
338
- }, getMimeFromExt = (ext)=>{
339
- switch(ext){
340
- case 'svg':
341
- case 'svg+xml':
342
- return 'image/svg+xml';
343
- case 'jpg':
344
- case 'jpeg':
345
- return 'image/jpeg';
346
- case 'png':
347
- case 'gif':
348
- case 'webp':
349
- case 'avif':
350
- return `image/${ext}`;
351
- case 'mp3':
352
- case 'mpeg':
353
- case 'wav':
354
- return `audio/${ext}`;
355
- default:
356
- return '';
678
+ get animateOnScroll() {
679
+ const val = this.getAttribute('animateOnScroll');
680
+ return Boolean(val === 'true' || val === '' || val === '1');
357
681
  }
358
- }, handleErrors = (err)=>{
359
- const res = {
360
- message: 'Unknown error',
361
- status: isServer() ? 500 : 400
362
- };
363
- if (err && typeof err === 'object') {
364
- if ('message' in err && typeof err.message === 'string') {
365
- res.message = err.message;
366
- }
367
- if ('status' in err) {
368
- res.status = Number(err.status);
369
- }
682
+ /**
683
+ * Autoplay.
684
+ */ set autoplay(value) {
685
+ this.setAttribute('autoplay', Boolean(value).toString());
370
686
  }
371
- return res;
372
- }, hasExt = (path)=>{
373
- const lastDotIndex = path?.split('/').pop()?.lastIndexOf('.');
374
- return (lastDotIndex ?? 0) > 1 && path && path.length - 1 > (lastDotIndex ?? 0);
375
- }, isAudio = (asset)=>!('h' in asset) && !('w' in asset) && 'p' in asset && 'e' in asset && 'u' in asset && 'id' in asset, isBase64 = (str)=>{
376
- if (!str) {
377
- return false;
687
+ get autoplay() {
688
+ const val = this.getAttribute('autoplay');
689
+ return Boolean(val === 'true' || val === '' || val === '1');
378
690
  }
379
- const regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
380
- return regex.test(parseBase64(str));
381
- }, 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)=>{
382
- const replacedContent = content.replace(/[^\w\s\d.#]/g, '');
383
- return `${quote}${replacedContent}${quote}`;
384
- }), resolveAssets = async (unzipped, assets)=>{
385
- if (!Array.isArray(assets)) {
386
- return;
691
+ /**
692
+ * Background color.
693
+ */ set background(value) {
694
+ this.setAttribute('background', value);
387
695
  }
388
- const toResolve = [], { length } = assets;
389
- for(let i = 0; i < length; i++){
390
- if (!isAudio(assets[i]) && !isImage(assets[i])) {
391
- continue;
392
- }
393
- const type = isImage(assets[i]) ? 'images' : 'audio', u8 = unzipped?.[`${type}/${assets[i].p}`];
394
- if (!u8) {
395
- continue;
396
- }
397
- toResolve.push(new Promise((resolveAsset)=>{
398
- const assetB64 = isServer() ? Buffer.from(u8).toString('base64') : btoa(u8.reduce((dat, byte)=>`${dat}${String.fromCharCode(byte)}`, ''));
399
- assets[i].p = assets[i].p?.startsWith('data:') || isBase64(assets[i].p) ? assets[i].p : `data:${getMimeFromExt(getExt(assets[i].p))};base64,${assetB64}`;
400
- assets[i].e = 1;
401
- assets[i].u = '';
402
- resolveAsset();
403
- }));
696
+ get background() {
697
+ return this.getAttribute('background') || 'transparent';
404
698
  }
405
- await Promise.all(toResolve);
406
- }, unzip = async (resp)=>{
407
- const u8 = new Uint8Array(await resp.arrayBuffer()), unzipped = await new Promise((resolve, reject)=>{
408
- unzip$1(u8, /* { filter }, */ (err, file)=>{
409
- if (err) {
410
- reject(err);
411
- }
412
- resolve(file);
413
- });
414
- });
415
- return unzipped;
416
- };
417
-
418
- /**
419
- * Render Player
420
- */ function renderPlayer() {
421
- 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>`;
422
- this.shadow.adoptedStyleSheets = [
423
- DotLottiePlayer.styles
424
- ];
425
- this.shadow.appendChild(this.template.content.cloneNode(true));
426
- }
427
-
428
- /**
429
- * Render Controls
430
- */ function renderControls() {
431
- const slot = this.shadow.querySelector('slot[name=controls]');
432
- if (!slot) {
433
- return;
699
+ /**
700
+ * Show controls.
701
+ */ set controls(value) {
702
+ this.setAttribute('controls', Boolean(value).toString());
434
703
  }
435
- if (!this.controls) {
436
- slot.innerHTML = '';
437
- return;
704
+ get controls() {
705
+ const val = this.getAttribute('controls');
706
+ return Boolean(val === 'true' || val === '' || val === '1');
438
707
  }
439
- 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>`;
440
- const togglePlay = this.shadow.querySelector('.togglePlay');
441
- if (togglePlay instanceof HTMLButtonElement) {
442
- togglePlay.onclick = this.togglePlay;
708
+ /**
709
+ * Number of times to loop.
710
+ */ set count(value) {
711
+ this.setAttribute('count', value.toString());
443
712
  }
444
- const stop = this.shadow.querySelector('.stop');
445
- if (stop instanceof HTMLButtonElement) {
446
- stop.onclick = this.stop;
713
+ get count() {
714
+ const val = this.getAttribute('count');
715
+ if (val) {
716
+ return Number(val);
717
+ }
718
+ return 0;
447
719
  }
448
- const prev = this.shadow.querySelector('.prev');
449
- if (prev instanceof HTMLButtonElement) {
450
- prev.onclick = this.prev;
720
+ /**
721
+ * Description for screen readers.
722
+ */ set description(value) {
723
+ if (value) {
724
+ this.setAttribute('description', value);
725
+ }
451
726
  }
452
- const next = this.shadow.querySelector('.next');
453
- if (next instanceof HTMLButtonElement) {
454
- next.onclick = this.next;
727
+ get description() {
728
+ return this.getAttribute('description');
455
729
  }
456
- const seeker = this.shadow.querySelector('.seeker');
457
- if (seeker instanceof HTMLInputElement) {
458
- seeker.onchange = this._handleSeekChange;
459
- seeker.onmousedown = this._freeze;
730
+ /**
731
+ * Direction of animation.
732
+ */ set direction(value) {
733
+ this.setAttribute('direction', value.toString());
460
734
  }
461
- if (!this.simple) {
462
- const toggleLoop = this.shadow.querySelector('.toggleLoop');
463
- if (toggleLoop instanceof HTMLButtonElement) {
464
- toggleLoop.onclick = this.toggleLoop;
465
- }
466
- const toggleBoomerang = this.shadow.querySelector('.toggleBoomerang');
467
- if (toggleBoomerang instanceof HTMLButtonElement) {
468
- toggleBoomerang.onclick = this.toggleBoomerang;
469
- }
470
- const convert = this.shadow.querySelector('.convert');
471
- if (convert instanceof HTMLButtonElement) {
472
- convert.onclick = this.convert;
735
+ get direction() {
736
+ const val = Number(this.getAttribute('direction'));
737
+ if (val === -1) {
738
+ return val;
473
739
  }
474
- const snapshot = this.shadow.querySelector('.snapshot');
475
- if (snapshot instanceof HTMLButtonElement) {
476
- snapshot.onclick = ()=>this.snapshot(true);
740
+ return 1;
741
+ }
742
+ /**
743
+ * Whether to play on mouseover.
744
+ */ set hover(value) {
745
+ this.setAttribute('hover', value.toString());
746
+ }
747
+ get hover() {
748
+ const val = this.getAttribute('hover');
749
+ return Boolean(val === 'true' || val === '' || val === '1');
750
+ }
751
+ /**
752
+ * Pause between loop intrations, in miliseconds.
753
+ */ set intermission(value) {
754
+ this.setAttribute('intermission', value.toString());
755
+ }
756
+ get intermission() {
757
+ const val = Number(this.getAttribute('intermission'));
758
+ if (!isNaN(val)) {
759
+ return val;
477
760
  }
478
- const toggleSettings = this.shadow.querySelector('.toggleSettings');
479
- if (toggleSettings instanceof HTMLButtonElement) {
480
- toggleSettings.onclick = this._handleSettingsClick;
481
- toggleSettings.onblur = this._handleBlur;
761
+ return 0;
762
+ }
763
+ /**
764
+ * Loop animation.
765
+ */ set loop(value) {
766
+ this.setAttribute('loop', Boolean(value).toString());
767
+ }
768
+ get loop() {
769
+ const val = this.getAttribute('loop');
770
+ return Boolean(val === 'true' || val === '' || val === '1');
771
+ }
772
+ /**
773
+ * Play mode.
774
+ */ set mode(value) {
775
+ this.setAttribute('mode', value.toString());
776
+ }
777
+ get mode() {
778
+ const val = this.getAttribute('mode');
779
+ if (val === PlayMode.Bounce) {
780
+ return val;
482
781
  }
782
+ return PlayMode.Normal;
483
783
  }
484
- }
485
-
486
- /**
487
- * Credit to:
488
- * @author Leonardo Favre <https://github.com/leofavre/observed-properties>
489
- */ const UPDATE_ON_CONNECTED = Symbol('UPDATE_ON_CONNECTED');
490
- if (isServer()) {
491
- // Mock HTMLElement for server-side rendering
492
- global.HTMLElement = class EmptyHTMLElement {
493
- };
494
- }
495
- /**
496
- * HTMLElement enhanced to track property changes
497
- */ class PropertyCallbackElement extends HTMLElement {
498
- constructor(){
499
- super();
500
- const { observedProperties = [] } = this.constructor;
501
- if (UPDATE_ON_CONNECTED in this) {
502
- this[UPDATE_ON_CONNECTED] = [];
784
+ /**
785
+ * Resizing to container.
786
+ */ set objectfit(value) {
787
+ this.setAttribute('objectfit', value);
788
+ }
789
+ get objectfit() {
790
+ const val = this.getAttribute('objectfit');
791
+ if (val && Object.values(ObjectFit).includes(val)) {
792
+ return val;
503
793
  }
504
- if ('propertyChangedCallback' in this && typeof this.propertyChangedCallback === 'function') {
505
- const { length } = observedProperties;
506
- for(let i = 0; i < length; i++){
507
- const initialValue = this[observedProperties[i]], CACHED_VALUE = Symbol(observedProperties[i]);
508
- // @ts-expect-error: ingore
509
- this[CACHED_VALUE] = initialValue;
510
- Object.defineProperty(this, observedProperties[i], {
511
- get () {
512
- return this[CACHED_VALUE];
513
- },
514
- set (value) {
515
- const oldValue = this[CACHED_VALUE];
516
- this[CACHED_VALUE] = value;
517
- this.propertyChangedCallback(observedProperties[i], oldValue, value);
518
- }
519
- });
520
- if (typeof initialValue !== 'undefined') {
521
- if (UPDATE_ON_CONNECTED in this && Array.isArray(this[UPDATE_ON_CONNECTED])) {
522
- this[UPDATE_ON_CONNECTED].push(observedProperties[i]);
523
- }
524
- }
525
- }
794
+ return ObjectFit.Contain;
795
+ }
796
+ /**
797
+ * Resizing to container (Deprecated).
798
+ */ set preserveAspectRatio(value) {
799
+ this.setAttribute('preserveAspectRatio', value || PreserveAspectRatio.Contain);
800
+ }
801
+ get preserveAspectRatio() {
802
+ const val = this.getAttribute('preserveAspectRatio');
803
+ if (val && Object.values(PreserveAspectRatio).includes(val)) {
804
+ return val;
526
805
  }
806
+ return null;
527
807
  }
528
- connectedCallback() {
529
- let arr = [];
530
- if (UPDATE_ON_CONNECTED in this && Array.isArray(this[UPDATE_ON_CONNECTED])) {
531
- arr = this[UPDATE_ON_CONNECTED];
808
+ /**
809
+ * Renderer to use: svg, canvas or html.
810
+ */ set renderer(value) {
811
+ this.setAttribute('renderer', value);
812
+ }
813
+ get renderer() {
814
+ const val = this.getAttribute('renderer');
815
+ if (val === RendererType.Canvas || val === RendererType.HTML) {
816
+ return val;
532
817
  }
533
- const { length } = arr;
534
- for(let i = 0; i < length; i++){
535
- if (!('propertyChangedCallback' in this) || typeof this.propertyChangedCallback !== 'function') {
536
- continue;
537
- }
538
- if (arr[i] in this) {
539
- this.propertyChangedCallback(arr[i], undefined, this[arr[i]]);
540
- }
818
+ return RendererType.SVG;
819
+ }
820
+ /**
821
+ * Hide advanced controls.
822
+ */ set simple(value) {
823
+ this.setAttribute('simple', value.toString());
824
+ }
825
+ get simple() {
826
+ const val = this.getAttribute('simple');
827
+ return Boolean(val === 'true' || val === '' || val === '1');
828
+ }
829
+ /**
830
+ * Speed.
831
+ */ set speed(value) {
832
+ this.setAttribute('speed', value.toString());
833
+ }
834
+ get speed() {
835
+ const val = this.getAttribute('speed');
836
+ if (val !== null && !isNaN(Number(val))) {
837
+ return Number(val);
541
838
  }
839
+ return 1;
840
+ }
841
+ /**
842
+ * Source, either path or JSON string.
843
+ */ set src(value) {
844
+ this.setAttribute('src', value || '');
845
+ }
846
+ get src() {
847
+ return this.getAttribute('src');
848
+ }
849
+ /**
850
+ * Subframe.
851
+ */ set subframe(value) {
852
+ this.setAttribute('subframe', Boolean(value).toString());
853
+ }
854
+ get subframe() {
855
+ const val = this.getAttribute('subframe');
856
+ return Boolean(val === 'true' || val === '' || val === '1');
542
857
  }
543
- }
544
-
545
- var name="@aarsteinmedia/dotlottie-player";var version="5.0.1";var description="Web Component for playing Lottie animations in your web app. Previously @johanaarstein/dotlottie-player";var exports={".":{"import":"./dist/index.js",node:"./dist/index.js",types:"./dist/index.d.ts"}};var main="./dist/index.js";var unpkg="./dist/unpkg/index.js";var module="./dist/index.js";var types="./dist/index.d.ts";var type="module";var homepage="https://www.aarstein.media/en/dotlottie-player";var repository={url:"git+https://github.com/aarsteinmedia/dotlottie-player.git",type:"git"};var bugs="https://github.com/aarsteinmedia/dotlottie-player/issues";var author={name:"Johan Martin Aarstein",email:"johan@aarstein.media",url:"https://www.aarstein.media",organization:"Aarstein Media"};var contributors=[{name:"Anthony Colpron",email:"anthonycolpron@gmail.com",url:"https://github.com/anthony-colpron"}];var license="GPL-2.0-or-later";var scripts={test:"wtr",prebuild:"rimraf ./dist",build:"rollup -c","prebuild:types":"rimraf ./types","build:types":"tsc -p ./tsconfig.prod.json && tsc-alias","build:cem":"npx cem analyze --config cem.config.js",prod:"pnpm build:types && pnpm build && pnpm build:cem",dev:"rollup -c -w --environment NODE_ENV:development","lint:js":"eslint","lint:js:fix":"eslint --fix","lint:css":"npx stylelint **/*.css","lint:css:fix":"npx stylelint **/*.css --fix"};var dependencies={"@aarsteinmedia/lottie-web":"^0.2.21",fflate:"^0.8.2","lottie-web":"^5.13.0"};var peerDependencies={"@types/react":">= 16.0.0"};var devDependencies={"@custom-elements-manifest/analyzer":"^0.10.4","@eslint/compat":"^1.2.9","@eslint/js":"^9.27.0","@esm-bundle/chai":"4.3.4-fix.0","@open-wc/testing":"^4.0.0","@rollup/plugin-commonjs":"^28.0.3","@rollup/plugin-json":"^6.1.0","@rollup/plugin-node-resolve":"^16.0.1","@rollup/plugin-typescript":"^12.1.2","@swc/core":"^1.11.29","@types/mocha":"^10.0.10","@types/node":"^22.15.21","@types/path-browserify":"^1.0.3","@types/react":"^19.1.5","@web/dev-server-esbuild":"^1.0.4","@web/dev-server-import-maps":"^0.2.1","@web/dev-server-rollup":"^0.6.4","@web/test-runner":"^0.20.2","@web/test-runner-playwright":"^0.11.0",autoprefixer:"^10.4.21",esbuild:"^0.25.4",eslint:"^9.27.0","eslint-config-prettier":"^10.1.5","eslint-import-resolver-typescript":"^4.3.5","eslint-plugin-import":"^2.31.0","eslint-plugin-jsdoc":"^50.6.17","eslint-plugin-perfectionist":"^4.13.0","eslint-plugin-prettier":"^5.4.0",globals:"^16.1.0","postcss-flexbugs-fixes":"^5.0.2",prettier:"^3.5.3",react:"^19.1.0",rimraf:"^6.0.1",rollup:"^4.41.0","rollup-plugin-dts":"^6.2.1","rollup-plugin-html-literals":"^1.1.8","rollup-plugin-livereload":"^2.0.5","rollup-plugin-postcss":"^4.0.2","rollup-plugin-serve":"^3.0.0","rollup-plugin-summary":"^3.0.1","rollup-plugin-swc3":"^0.12.1","rollup-plugin-typescript-paths":"^1.5.0",stylelint:"^16.19.1","stylelint-config-recommended":"^16.0.0","tsc-alias":"^1.8.16",tslib:"^2.8.1",typescript:"^5.8.3","typescript-eslint":"^8.32.1"};var pnpm={onlyBuiltDependencies:["@parcel/watcher","@swc/core","esbuild","unrs-resolver"]};var browserslist={production:[">0.3%","not dead","not op_mini all"],development:["last 1 chrome version","last 1 firefox version","last 1 safari version"]};var customElements$1="custom-elements.json";var files=["CHANGELOG.md","custom-elements.json","dist","README.md"];var keywords=["lottie","dotlottie","animation","web component","svg","vector","player"];var publishConfig={access:"public"};var engines={node:">= 12.17.0"};var funding={type:"paypal",url:"https://www.paypal.com/donate/?hosted_button_id=E7C7DMN8KSQ6A"};var pkg = {name:name,version:version,description:description,exports:exports,main:main,unpkg:unpkg,module:module,types:types,type:type,homepage:homepage,repository:repository,bugs:bugs,author:author,contributors:contributors,license:license,scripts:scripts,dependencies:dependencies,peerDependencies:peerDependencies,devDependencies:devDependencies,pnpm:pnpm,browserslist:browserslist,customElements:customElements$1,files:files,keywords:keywords,publishConfig:publishConfig,engines:engines,funding:funding};
546
-
547
- 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 0.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: 0.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: 0.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: 0.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 0.2s ease-in-out;\n transition: transform 0.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 0.2s ease-in-out;\n transition: transform 0.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 0.2s ease-in-out;\n transition: transform 0.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@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";
548
-
549
- /**
550
- * dotLottie Player Web Component
551
- * @export
552
- * @class DotLottiePlayer
553
- * @extends { EnhancedElement }
554
- * @description Web Component for playing Lottie animations in your web app.
555
- */ class DotLottiePlayer extends PropertyCallbackElement {
556
858
  constructor(){
557
- super(), this._renderControls = renderControls, this._render = renderPlayer, /**
558
- * Multi-animation settings
559
- */ this._multiAnimationSettings = [], /**
560
- * Animation Container
561
- */ this._container = null, /**
562
- * @state
563
- * Player state
859
+ super(), /**
860
+ * Player state.
564
861
  */ this.playerState = PlayerState.Loading, /**
565
- * @state
566
- * Whether settings toolbar is open
567
- */ this._isSettingsOpen = false, /**
568
- * @state
569
- * Seeker
570
- */ this._seeker = 0, /**
571
- * @state
572
- * Which animation to show, if several
573
- */ this._currentAnimation = 0, /**
574
- * @state
575
- * This is included in watched properties,
576
- * so that next-button will show up
577
- * on load, if controls are visible
578
- */ this._animations = [], this._lottieInstance = null, this._identifier = this.id || createElementID(), this._errorMessage = 'Something went wrong', this._isBounce = false, this._isDotLottie = false, this._playerState = {
862
+ * Animation Container.
863
+ */ this._container = null, this._errorMessage = 'Something went wrong', this._identifier = this.id || createElementID(), /**
864
+ * Whether settings toolbar is open.
865
+ */ this._isSettingsOpen = false, this._playerState = {
579
866
  count: 0,
580
867
  loaded: false,
581
868
  prev: PlayerState.Loading,
582
869
  scrollTimeout: null,
583
870
  scrollY: 0,
584
871
  visible: false
585
- }, /**
586
- * Handle settings click event
872
+ }, this._render = renderPlayer, this._renderControls = renderControls, /**
873
+ * Seeker.
874
+ */ this._seeker = 0, /**
875
+ * This is included in watched properties,
876
+ * so that next-button will show up
877
+ * on load, if controls are visible.
878
+ */ this._animations = [], /**
879
+ * Which animation to show, if several.
880
+ */ this._currentAnimation = 0, this._isBounce = false, this._isDotLottie = false, this._lottieInstance = null, /**
881
+ * Multi-animation settings.
882
+ */ this._multiAnimationSettings = [], /**
883
+ * Handle settings click event.
587
884
  */ this._handleSettingsClick = ({ target })=>{
588
885
  this._toggleSettings();
589
886
  // Because Safari does not add focus on click, we need to add it manually, so the onblur event will fire
@@ -622,55 +919,58 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
622
919
  });
623
920
  }
624
921
  /**
625
- * Initialize everything on component first render
626
- */ async connectedCallback() {
627
- super.connectedCallback();
628
- this._render();
629
- this._container = this.shadow.querySelector('.animation');
630
- this._renderControls();
631
- // Add listener for Visibility API's change event.
632
- if (typeof document.hidden !== 'undefined') {
633
- document.addEventListener('visibilitychange', this._onVisibilityChange);
634
- }
635
- // Add intersection observer for detecting component being out-of-view.
636
- this._addIntersectionObserver();
637
- // Setup lottie player
638
- await this.load(this.src);
639
- this.dispatchEvent(new CustomEvent(PlayerEvents.Rendered));
640
- }
641
- /**
642
- * Cleanup on component destroy
643
- */ disconnectedCallback() {
644
- // Remove intersection observer for detecting component being out-of-view
645
- if (this._intersectionObserver) {
646
- this._intersectionObserver.disconnect();
647
- this._intersectionObserver = undefined;
648
- }
649
- // Destroy the animation instance
650
- if (this._lottieInstance) {
651
- this._lottieInstance.destroy();
922
+ * Creates a new dotLottie file, by combinig several animations.
923
+ * If set to false the function returns an ArrayBuffer. Defaults to true.
924
+ */ async addAnimation(configs, fileName, shouldDownload = true) {
925
+ // Initialize meta object for animation, with fallbacks for
926
+ // when the method is called indepenently
927
+ const { animations = [], manifest = {
928
+ animations: this.src ? [
929
+ {
930
+ id: this._identifier
931
+ }
932
+ ] : []
933
+ } } = this.src ? await getAnimationData(this.src) : {};
934
+ try {
935
+ if (!manifest) {
936
+ throw new Error('Manifest is not set');
937
+ }
938
+ manifest.generator = generator;
939
+ const { length } = configs;
940
+ for(let i = 0; i < length; i++){
941
+ const { url } = configs[i], { animations: animationsToAdd } = await getAnimationData(url);
942
+ if (!animationsToAdd) {
943
+ throw new Error('No animation loaded');
944
+ }
945
+ if (manifest.animations.some(({ id })=>id === configs[i].id)) {
946
+ throw new Error('Duplicate id for animation');
947
+ }
948
+ manifest.animations = [
949
+ ...manifest.animations,
950
+ {
951
+ id: configs[i].id
952
+ }
953
+ ];
954
+ animations.push(...animationsToAdd);
955
+ }
956
+ return {
957
+ result: await createDotLottie({
958
+ animations,
959
+ fileName,
960
+ manifest,
961
+ shouldDownload
962
+ }),
963
+ success: true
964
+ };
965
+ } catch (error) {
966
+ return {
967
+ error: handleErrors(error).message,
968
+ success: false
969
+ };
652
970
  }
653
- // Remove the attached Visibility API's change event listener
654
- document.removeEventListener('visibilitychange', this._onVisibilityChange);
655
- }
656
- /**
657
- * Attributes to observe
658
- */ static get observedAttributes() {
659
- return [
660
- 'animateOnScroll',
661
- 'autoplay',
662
- 'controls',
663
- 'direction',
664
- 'hover',
665
- 'loop',
666
- 'mode',
667
- 'speed',
668
- 'src',
669
- 'subframe'
670
- ];
671
971
  }
672
972
  /**
673
- * Runs when the value of an attribute is changed on the component
973
+ * Runs when the value of an attribute is changed on the component.
674
974
  */ async attributeChangedCallback(name, _oldValue, value) {
675
975
  if (!this._lottieInstance) {
676
976
  return;
@@ -701,7 +1001,8 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
701
1001
  }
702
1002
  if (name === 'direction') {
703
1003
  if (Number(value) === -1) {
704
- return this.setDirection(-1);
1004
+ this.setDirection(-1);
1005
+ return;
705
1006
  }
706
1007
  this.setDirection(1);
707
1008
  }
@@ -715,14 +1016,14 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
715
1016
  this._container.removeEventListener('mouseleave', this._mouseLeave);
716
1017
  }
717
1018
  if (name === 'loop') {
718
- const toggleLoop = this.shadow.querySelector('.toggleLoop');
1019
+ const toggleLoop = this.shadow?.querySelector('.toggleLoop');
719
1020
  if (toggleLoop instanceof HTMLButtonElement) {
720
1021
  toggleLoop.dataset.active = value;
721
1022
  }
722
1023
  this.setLoop(value === '' || Boolean(value));
723
1024
  }
724
1025
  if (name === 'mode') {
725
- const toggleBoomerang = this.shadow.querySelector('.toggleBoomerang');
1026
+ const toggleBoomerang = this.shadow?.querySelector('.toggleBoomerang');
726
1027
  if (toggleBoomerang instanceof HTMLButtonElement) {
727
1028
  toggleBoomerang.dataset.active = (value === PlayMode.Bounce).toString();
728
1029
  }
@@ -741,759 +1042,189 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
741
1042
  this.setSubframe(value === '' || Boolean(value));
742
1043
  }
743
1044
  }
744
- static get observedProperties() {
745
- return [
746
- 'playerState',
747
- '_isSettingsOpen',
748
- '_seeker',
749
- '_currentAnimation',
750
- '_animations'
751
- ];
752
- }
753
- // name: string, oldValue: string, newValue: string
754
- propertyChangedCallback(name, _oldValue, value) {
1045
+ /**
1046
+ * Initialize everything on component first render.
1047
+ */ async connectedCallback() {
1048
+ await super.connectedCallback();
1049
+ await this._render();
755
1050
  if (!this.shadow) {
756
- return;
1051
+ throw new Error('Missing Shadow element');
757
1052
  }
758
- 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');
759
- if (!(togglePlay instanceof HTMLButtonElement) || !(stop instanceof HTMLButtonElement) || !(next instanceof HTMLButtonElement) || !(prev instanceof HTMLButtonElement) || !(seeker instanceof HTMLInputElement) || !(progress instanceof HTMLProgressElement)) {
760
- return;
761
- }
762
- if (name === 'playerState') {
763
- togglePlay.dataset.active = (value === PlayerState.Playing || value === PlayerState.Paused).toString();
764
- stop.dataset.active = (value === PlayerState.Stopped).toString();
765
- if (value === PlayerState.Playing) {
766
- 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>`;
767
- } else {
768
- 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>`;
769
- }
770
- }
771
- if (name === '_seeker' && typeof value === 'number') {
772
- seeker.value = value.toString();
773
- seeker.ariaValueNow = value.toString();
774
- progress.value = value;
775
- }
776
- if (name === '_animations' && Array.isArray(value)) {
777
- if (this._currentAnimation + 1 < value.length) {
778
- next.hidden = false;
779
- }
780
- }
781
- if (name === '_currentAnimation' && typeof value === 'number') {
782
- if (value + 1 >= this._animations.length) {
783
- next.hidden = true;
784
- } else {
785
- next.hidden = false;
786
- }
787
- if (value) {
788
- prev.hidden = false;
789
- } else {
790
- prev.hidden = true;
791
- }
792
- }
793
- if (name === '_isSettingsOpen' && typeof value === 'boolean' && popover instanceof HTMLDivElement && convert instanceof HTMLButtonElement) {
794
- popover.hidden = !value;
795
- convert.hidden = this._isDotLottie;
796
- }
797
- }
798
- /**
799
- * Whether to trigger next frame with scroll
800
- */ set animateOnScroll(value) {
801
- this.setAttribute('animateOnScroll', (!!value).toString());
802
- }
803
- get animateOnScroll() {
804
- const val = this.getAttribute('animateOnScroll');
805
- if (val === 'true' || val === '' || val === '1') {
806
- return true;
807
- }
808
- return false;
809
- }
810
- /**
811
- * Autoplay
812
- */ set autoplay(value) {
813
- this.setAttribute('autoplay', (!!value).toString());
814
- }
815
- get autoplay() {
816
- const val = this.getAttribute('autoplay');
817
- if (val === 'true' || val === '' || val === '1') {
818
- return true;
819
- }
820
- return false;
821
- }
822
- /**
823
- * Background color
824
- */ set background(value) {
825
- this.setAttribute('background', value);
826
- }
827
- get background() {
828
- return this.getAttribute('background') || 'transparent';
829
- }
830
- /**
831
- * Show controls
832
- */ set controls(value) {
833
- this.setAttribute('controls', (!!value).toString());
834
- }
835
- get controls() {
836
- const val = this.getAttribute('controls');
837
- if (val === 'true' || val === '' || val === '1') {
838
- return true;
839
- }
840
- return false;
841
- }
842
- /**
843
- * Number of times to loop
844
- */ set count(value) {
845
- this.setAttribute('count', value.toString());
846
- }
847
- get count() {
848
- const val = this.getAttribute('count');
849
- if (val) {
850
- return Number(val);
851
- }
852
- return 0;
853
- }
854
- /**
855
- * Description for screen readers
856
- */ set description(value) {
857
- if (value) {
858
- this.setAttribute('description', value);
859
- }
860
- }
861
- get description() {
862
- return this.getAttribute('description');
863
- }
864
- /**
865
- * Direction of animation
866
- */ set direction(value) {
867
- this.setAttribute('direction', value.toString());
868
- }
869
- get direction() {
870
- const val = Number(this.getAttribute('direction'));
871
- if (val === -1) {
872
- return val;
873
- }
874
- return 1;
875
- }
876
- /**
877
- * Whether to play on mouseover
878
- */ set hover(value) {
879
- this.setAttribute('hover', value.toString());
880
- }
881
- get hover() {
882
- const val = this.getAttribute('hover');
883
- if (val === 'true' || val === '' || val === '1') {
884
- return true;
885
- }
886
- return false;
887
- }
888
- /**
889
- * Pause between loop intrations, in miliseconds
890
- */ set intermission(value) {
891
- this.setAttribute('intermission', value.toString());
892
- }
893
- get intermission() {
894
- const val = Number(this.getAttribute('intermission'));
895
- if (!isNaN(val)) {
896
- return val;
897
- }
898
- return 0;
899
- }
900
- /**
901
- * Loop animation
902
- */ set loop(value) {
903
- this.setAttribute('loop', (!!value).toString());
904
- }
905
- get loop() {
906
- const val = this.getAttribute('loop');
907
- if (val === 'true' || val === '' || val === '1') {
908
- return true;
909
- }
910
- return false;
911
- }
912
- /**
913
- * Play mode
914
- */ set mode(value) {
915
- this.setAttribute('mode', value.toString());
916
- }
917
- get mode() {
918
- const val = this.getAttribute('mode');
919
- if (val === PlayMode.Bounce) {
920
- return val;
921
- }
922
- return PlayMode.Normal;
923
- }
924
- /**
925
- * Resizing to container
926
- */ set objectfit(value) {
927
- this.setAttribute('objectfit', value);
928
- }
929
- get objectfit() {
930
- const val = this.getAttribute('objectfit');
931
- if (val && Object.values(ObjectFit).includes(val)) {
932
- return val;
933
- }
934
- return ObjectFit.Contain;
935
- }
936
- /**
937
- * Resizing to container (Deprecated)
938
- */ set preserveAspectRatio(value) {
939
- this.setAttribute('preserveAspectRatio', value || PreserveAspectRatio.Contain);
940
- }
941
- get preserveAspectRatio() {
942
- const val = this.getAttribute('preserveAspectRatio');
943
- if (val && Object.values(PreserveAspectRatio).includes(val)) {
944
- return val;
945
- }
946
- return null;
947
- }
948
- /**
949
- * Renderer to use: svg, canvas or html
950
- */ set renderer(value) {
951
- this.setAttribute('renderer', value);
952
- }
953
- get renderer() {
954
- const val = this.getAttribute('renderer');
955
- if (val === RendererType.Canvas || val === RendererType.HTML) {
956
- return val;
957
- }
958
- return RendererType.SVG;
959
- }
960
- /**
961
- * Hide advanced controls
962
- */ set simple(value) {
963
- this.setAttribute('simple', value.toString());
964
- }
965
- get simple() {
966
- const val = this.getAttribute('simple');
967
- if (val === 'true' || val === '' || val === '1') {
968
- return true;
969
- }
970
- return false;
971
- }
972
- /**
973
- * Speed
974
- */ set speed(value) {
975
- this.setAttribute('speed', value?.toString());
976
- }
977
- get speed() {
978
- const val = this.getAttribute('speed');
979
- if (val !== null && !isNaN(Number(val))) {
980
- return Number(val);
981
- }
982
- return 1;
983
- }
984
- /**
985
- * Source, either path or JSON string
986
- */ set src(value) {
987
- this.setAttribute('src', value || '');
988
- }
989
- get src() {
990
- return this.getAttribute('src');
991
- }
992
- /**
993
- * Subframe
994
- */ set subframe(value) {
995
- this.setAttribute('subframe', (!!value).toString());
996
- }
997
- get subframe() {
998
- const val = this.getAttribute('subframe');
999
- if (val === 'true' || val === '' || val === '1') {
1000
- return true;
1001
- }
1002
- return false;
1003
- }
1004
- /**
1005
- * Get Multi-animation settings
1006
- * @returns { AnimationSettings[] }
1007
- */ getMultiAnimationSettings() {
1008
- return this._multiAnimationSettings;
1009
- }
1010
- /**
1011
- * Set Multi-animation settings
1012
- * @param { AnimationSettings[] } settings
1013
- */ setMultiAnimationSettings(settings) {
1014
- this._multiAnimationSettings = settings;
1015
- }
1016
- /**
1017
- * Set playback segment
1018
- * @param { Vector2 } segment
1019
- */ setSegment(segment) {
1020
- this._segment = segment;
1021
- }
1022
- /**
1023
- * Get playback segment
1024
- * @returns { Vector2 }
1025
- */ getSegment() {
1026
- return this._segment;
1027
- }
1028
- /**
1029
- * Get options from props
1030
- * @returns { AnimationConfig }
1031
- */ _getOptions() {
1032
- if (!this._container) {
1033
- throw new Error('Container not rendered');
1034
- }
1035
- const preserveAspectRatio = this.preserveAspectRatio ?? (this.objectfit && aspectRatio(this.objectfit)), currentAnimationSettings = this._multiAnimationSettings?.length ? this._multiAnimationSettings?.[this._currentAnimation] : undefined, currentAnimationManifest = this._manifest?.animations[this._currentAnimation];
1036
- // Loop
1037
- let loop = !!this.loop;
1038
- if (currentAnimationManifest?.loop !== undefined && this.loop === undefined) {
1039
- loop = !!currentAnimationManifest.loop;
1040
- }
1041
- if (currentAnimationSettings?.loop !== undefined) {
1042
- loop = !!currentAnimationSettings.loop;
1043
- }
1044
- // Autoplay
1045
- let autoplay = !!this.autoplay;
1046
- if (currentAnimationManifest?.autoplay !== undefined && this.autoplay === undefined) {
1047
- autoplay = !!currentAnimationManifest.autoplay;
1048
- }
1049
- if (currentAnimationSettings?.autoplay !== undefined) {
1050
- autoplay = !!currentAnimationSettings.autoplay;
1051
- }
1052
- if (this.animateOnScroll) {
1053
- autoplay = false;
1054
- }
1055
- // Segment
1056
- let initialSegment = this._segment;
1057
- if (this._segment?.every((val)=>val > 0)) {
1058
- initialSegment = [
1059
- this._segment[0] - 1,
1060
- this._segment[1] - 1
1061
- ];
1062
- }
1063
- if (this._segment?.some((val)=>val < 0)) {
1064
- initialSegment = undefined;
1065
- }
1066
- const options = {
1067
- autoplay,
1068
- container: this._container,
1069
- initialSegment,
1070
- loop,
1071
- renderer: this.renderer,
1072
- rendererSettings: {
1073
- imagePreserveAspectRatio: preserveAspectRatio
1074
- }
1075
- };
1076
- switch(this.renderer){
1077
- case 'svg':
1078
- options.rendererSettings = {
1079
- ...options.rendererSettings,
1080
- hideOnTransparent: true,
1081
- preserveAspectRatio,
1082
- progressiveLoad: true
1083
- };
1084
- break;
1085
- case 'canvas':
1086
- options.rendererSettings = {
1087
- ...options.rendererSettings,
1088
- clearCanvas: true,
1089
- // @ts-expect-error TODO:
1090
- preserveAspectRatio,
1091
- progressiveLoad: true
1092
- };
1093
- break;
1094
- case 'html':
1095
- options.rendererSettings = {
1096
- ...options.rendererSettings,
1097
- hideOnTransparent: true
1098
- };
1099
- }
1100
- return options;
1101
- }
1102
- /**
1103
- * Add IntersectionObserver
1104
- */ _addIntersectionObserver() {
1105
- if (!this._container || this._intersectionObserver || !('IntersectionObserver' in window)) {
1106
- return;
1107
- }
1108
- this._intersectionObserver = new IntersectionObserver((entries)=>{
1109
- const { length } = entries;
1110
- for(let i = 0; i < length; i++){
1111
- if (!entries[i].isIntersecting || document.hidden) {
1112
- if (this.playerState === PlayerState.Playing) {
1113
- this._freeze();
1114
- }
1115
- this._playerState.visible = false;
1116
- continue;
1117
- }
1118
- if (!this.animateOnScroll && this.playerState === PlayerState.Frozen) {
1119
- this.play();
1120
- }
1121
- if (!this._playerState.scrollY) {
1122
- this._playerState.scrollY = scrollY;
1123
- }
1124
- this._playerState.visible = true;
1125
- }
1126
- });
1127
- this._intersectionObserver.observe(this._container);
1128
- }
1129
- /**
1130
- * Initialize Lottie Web player
1131
- */ async load(src) {
1132
- if (!this.shadowRoot || !src) {
1133
- return;
1134
- }
1135
- // Load the resource
1136
- try {
1137
- const { animations, isDotLottie, manifest } = await getAnimationData(src);
1138
- if (!animations || animations.some((animation)=>!this._isLottie(animation))) {
1139
- throw new Error('Broken or corrupted file');
1140
- }
1141
- this._isBounce = this.mode === PlayMode.Bounce;
1142
- if (this._multiAnimationSettings?.length) {
1143
- if (this._multiAnimationSettings[this._currentAnimation]?.mode) {
1144
- this._isBounce = this._multiAnimationSettings[this._currentAnimation].mode === PlayMode.Bounce;
1145
- }
1146
- }
1147
- this._isDotLottie = !!isDotLottie;
1148
- this._animations = animations;
1149
- this._manifest = manifest ?? {
1150
- animations: [
1151
- {
1152
- autoplay: !this.animateOnScroll && this.autoplay,
1153
- direction: this.direction,
1154
- id: createElementID(),
1155
- loop: this.loop,
1156
- mode: this.mode,
1157
- speed: this.speed
1158
- }
1159
- ]
1160
- };
1161
- // Clear previous animation, if any
1162
- if (this._lottieInstance) {
1163
- this._lottieInstance.destroy();
1164
- }
1165
- this.playerState = PlayerState.Stopped;
1166
- if (!this.animateOnScroll && (this.autoplay || this._multiAnimationSettings?.[this._currentAnimation]?.autoplay)) {
1167
- this.playerState = PlayerState.Playing;
1168
- }
1169
- // Initialize lottie player and load animation
1170
- // @ts-expect-error TODO:
1171
- this._lottieInstance = Lottie.default.loadAnimation({
1172
- ...this._getOptions(),
1173
- animationData: animations[this._currentAnimation]
1174
- });
1175
- } catch (err) {
1176
- this._errorMessage = handleErrors(err).message;
1177
- this.playerState = PlayerState.Error;
1178
- this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1179
- return;
1180
- }
1181
- this._addEventListeners();
1182
- 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;
1183
- // Set initial playback speed and direction
1184
- this._lottieInstance.setSpeed(speed);
1185
- this._lottieInstance.setDirection(direction);
1186
- this._lottieInstance.setSubframe(!!this.subframe);
1187
- // Start playing if autoplay is enabled
1188
- if (this.autoplay || this.animateOnScroll) {
1189
- if (this.direction === -1) {
1190
- this.seek('99%');
1191
- }
1192
- if (!('IntersectionObserver' in window)) {
1193
- if (!this.animateOnScroll) {
1194
- this.play();
1195
- }
1196
- this._playerState.visible = true;
1197
- }
1198
- this._addIntersectionObserver();
1199
- }
1200
- }
1201
- /**
1202
- * Get Lottie Manifest
1203
- */ getManifest() {
1204
- return this._manifest;
1205
- }
1206
- /**
1207
- * Toggle event listeners
1208
- */ _toggleEventListeners(action) {
1209
- const method = action === 'add' ? 'addEventListener' : 'removeEventListener';
1210
- if (this._lottieInstance) {
1211
- this._lottieInstance[method]('enterFrame', this._enterFrame);
1212
- this._lottieInstance[method]('complete', this._complete);
1213
- this._lottieInstance[method]('loopComplete', this._loopComplete);
1214
- this._lottieInstance[method]('DOMLoaded', this._DOMLoaded);
1215
- this._lottieInstance[method]('data_ready', this._dataReady);
1216
- this._lottieInstance[method]('data_failed', this._dataFailed);
1217
- }
1218
- if (this._container && this.hover) {
1219
- this._container[method]('mouseenter', this._mouseEnter);
1220
- this._container[method]('mouseleave', this._mouseLeave);
1221
- }
1222
- window[method]('focus', this._handleWindowBlur, {
1223
- capture: false,
1224
- passive: true
1225
- });
1226
- window[method]('blur', this._handleWindowBlur, {
1227
- capture: false,
1228
- passive: true
1229
- });
1230
- if (this.animateOnScroll) {
1231
- window[method]('scroll', this._handleScroll, {
1232
- capture: true,
1233
- passive: true
1234
- });
1235
- }
1236
- }
1237
- /**
1238
- * Add event listeners
1239
- */ _addEventListeners() {
1240
- this._toggleEventListeners('add');
1241
- }
1242
- /**
1243
- * Remove event listeners
1244
- */ _removeEventListeners() {
1245
- this._toggleEventListeners('remove');
1246
- }
1247
- _loopComplete() {
1248
- if (!this._lottieInstance) {
1249
- return;
1250
- }
1251
- const { playDirection, // firstFrame,
1252
- totalFrames } = this._lottieInstance, inPoint = this._segment ? this._segment[0] : 0, outPoint = this._segment ? this._segment[0] : totalFrames;
1253
- if (this.count) {
1254
- if (this._isBounce) {
1255
- this._playerState.count += 0.5;
1256
- } else {
1257
- this._playerState.count += 1;
1258
- }
1259
- if (this._playerState.count >= this.count) {
1260
- this.setLoop(false);
1261
- this.playerState = PlayerState.Completed;
1262
- this.dispatchEvent(new CustomEvent(PlayerEvents.Complete));
1263
- return;
1264
- }
1265
- }
1266
- this.dispatchEvent(new CustomEvent(PlayerEvents.Loop));
1267
- if (this._isBounce) {
1268
- this._lottieInstance.goToAndStop(playDirection === -1 ? inPoint : outPoint * 0.99, true);
1269
- this._lottieInstance.setDirection(playDirection * -1);
1270
- return setTimeout(()=>{
1271
- if (!this.animateOnScroll) {
1272
- this._lottieInstance?.play();
1273
- }
1274
- }, this.intermission);
1053
+ this._container = this.shadow.querySelector('.animation');
1054
+ this._renderControls();
1055
+ // Add listener for Visibility API's change event.
1056
+ if (typeof document.hidden !== 'undefined') {
1057
+ document.addEventListener('visibilitychange', this._onVisibilityChange);
1275
1058
  }
1276
- this._lottieInstance.goToAndStop(playDirection === -1 ? outPoint * 0.99 : inPoint, true);
1277
- return setTimeout(()=>{
1278
- if (!this.animateOnScroll) {
1279
- this._lottieInstance?.play();
1280
- }
1281
- }, this.intermission);
1059
+ // Add intersection observer for detecting component being out-of-view.
1060
+ this._addIntersectionObserver();
1061
+ // Setup lottie player
1062
+ await this.load(this.src);
1063
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Rendered));
1282
1064
  }
1283
- _enterFrame() {
1284
- if (!this._lottieInstance) {
1065
+ async convert({ animations: animationsFromProps, fileName, manifest, shouldDownload = true, src: srcFromProps, typeCheck }) {
1066
+ const src = srcFromProps || this.src || this.source;
1067
+ if (!src) {
1068
+ throw new Error('No animation to convert');
1069
+ }
1070
+ if (typeCheck || this._isDotLottie) {
1071
+ const animationData = await getAnimationData(src);
1072
+ createJSON({
1073
+ animation: animationData.animations?.[0],
1074
+ fileName: `${getFilename(fileName || src || 'converted')}.json`,
1075
+ shouldDownload
1076
+ });
1285
1077
  return;
1286
1078
  }
1287
- const { currentFrame, totalFrames } = this._lottieInstance;
1288
- this._seeker = Math.round(currentFrame / totalFrames * 100);
1289
- this.dispatchEvent(new CustomEvent(PlayerEvents.Frame, {
1290
- detail: {
1291
- frame: currentFrame,
1292
- seeker: this._seeker
1293
- }
1294
- }));
1079
+ let animations = animationsFromProps;
1080
+ if (!animations) {
1081
+ const animationData = await getAnimationData(src);
1082
+ animations = animationData.animations;
1083
+ }
1084
+ return createDotLottie({
1085
+ animations,
1086
+ fileName: `${getFilename(fileName || src || 'converted')}.lottie`,
1087
+ manifest: {
1088
+ ...manifest ?? this._manifest,
1089
+ generator
1090
+ },
1091
+ shouldDownload
1092
+ });
1295
1093
  }
1296
- _complete() {
1094
+ /**
1095
+ * Destroy animation and element.
1096
+ */ destroy() {
1297
1097
  if (!this._lottieInstance) {
1298
1098
  return;
1299
1099
  }
1300
- if (this._animations.length > 1) {
1301
- if (this._multiAnimationSettings?.[this._currentAnimation + 1]?.autoplay) {
1302
- return this.next();
1303
- }
1304
- if (this.loop && this._currentAnimation === this._animations.length - 1) {
1305
- this._currentAnimation = 0;
1306
- return this._switchInstance();
1307
- }
1308
- }
1309
- const { currentFrame, totalFrames } = this._lottieInstance;
1310
- this._seeker = Math.round(currentFrame / totalFrames * 100);
1311
- this.playerState = PlayerState.Completed;
1312
- this.dispatchEvent(new CustomEvent(PlayerEvents.Complete, {
1313
- detail: {
1314
- frame: currentFrame,
1315
- seeker: this._seeker
1316
- }
1317
- }));
1318
- }
1319
- _DOMLoaded() {
1320
- this._playerState.loaded = true;
1321
- this.dispatchEvent(new CustomEvent(PlayerEvents.Ready));
1322
- }
1323
- _dataReady() {
1324
- this.dispatchEvent(new CustomEvent(PlayerEvents.Load));
1325
- }
1326
- _dataFailed() {
1327
- this.playerState = PlayerState.Error;
1328
- this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1100
+ this.playerState = PlayerState.Destroyed;
1101
+ this._lottieInstance.destroy();
1102
+ this._lottieInstance = null;
1103
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Destroyed));
1104
+ this.remove();
1105
+ document.removeEventListener('visibilitychange', this._onVisibilityChange);
1329
1106
  }
1330
- _handleWindowBlur({ type }) {
1331
- if (this.playerState === PlayerState.Playing && type === 'blur') {
1332
- this._freeze();
1107
+ /**
1108
+ * Cleanup on component destroy.
1109
+ */ disconnectedCallback() {
1110
+ // Remove intersection observer for detecting component being out-of-view
1111
+ if (this._intersectionObserver) {
1112
+ this._intersectionObserver.disconnect();
1113
+ this._intersectionObserver = undefined;
1333
1114
  }
1334
- if (this.playerState === PlayerState.Frozen && type === 'focus') {
1335
- this.play();
1115
+ // Destroy the animation instance
1116
+ if (this._lottieInstance) {
1117
+ this._lottieInstance.destroy();
1336
1118
  }
1119
+ // Remove the attached Visibility API's change event listener
1120
+ document.removeEventListener('visibilitychange', this._onVisibilityChange);
1337
1121
  }
1338
1122
  /**
1339
- * Handle MouseEnter
1340
- */ _mouseEnter() {
1341
- if (this.hover && this.playerState !== PlayerState.Playing) {
1342
- this.play();
1343
- }
1123
+ * Returns the lottie-web instance used in the component.
1124
+ */ getLottie() {
1125
+ return this._lottieInstance;
1344
1126
  }
1345
1127
  /**
1346
- * Handle MouseLeave
1347
- */ _mouseLeave() {
1348
- if (this.hover && this.playerState === PlayerState.Playing) {
1349
- this.stop();
1350
- }
1128
+ * Get Lottie Manifest.
1129
+ */ getManifest() {
1130
+ return this._manifest;
1351
1131
  }
1352
1132
  /**
1353
- * Handle visibility change events
1354
- */ _onVisibilityChange() {
1355
- if (document.hidden && this.playerState === PlayerState.Playing) {
1356
- this._freeze();
1357
- return;
1358
- }
1359
- if (this.playerState === PlayerState.Frozen) {
1360
- this.play();
1361
- }
1133
+ * Get Multi-animation settings.
1134
+ *
1135
+ */ getMultiAnimationSettings() {
1136
+ return this._multiAnimationSettings;
1362
1137
  }
1363
1138
  /**
1364
- * Handle scroll
1365
- */ _handleScroll() {
1366
- if (!this.animateOnScroll || !this._lottieInstance) {
1367
- return;
1368
- }
1369
- if (isServer()) {
1370
- console.warn('DotLottie: Scroll animations might not work properly in a Server Side Rendering context. Try to wrap this in a client component.');
1371
- return;
1372
- }
1373
- if (this._playerState.visible) {
1374
- if (this._playerState.scrollTimeout) {
1375
- clearTimeout(this._playerState.scrollTimeout);
1376
- }
1377
- this._playerState.scrollTimeout = setTimeout(()=>{
1378
- this.playerState = PlayerState.Paused;
1379
- }, 400);
1380
- 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;
1381
- requestAnimationFrame(()=>{
1382
- if (roundedScroll < (this._lottieInstance?.totalFrames ?? 0)) {
1383
- this.playerState = PlayerState.Playing;
1384
- this._lottieInstance?.goToAndStop(roundedScroll, true);
1385
- } else {
1386
- this.playerState = PlayerState.Paused;
1387
- }
1388
- });
1389
- }
1139
+ * Get playback segment.
1140
+ *
1141
+ */ getSegment() {
1142
+ return this._segment;
1390
1143
  }
1391
1144
  /**
1392
- * Handles click and drag actions on the progress track
1393
- * @param { Event & { HTMLInputElement } } event
1394
- */ _handleSeekChange({ target }) {
1395
- if (!(target instanceof HTMLInputElement) || !this._lottieInstance || isNaN(Number(target.value))) {
1145
+ * Initialize Lottie Web player.
1146
+ */ async load(src) {
1147
+ if (!this.shadowRoot || !src) {
1396
1148
  return;
1397
1149
  }
1398
- this.seek(Math.round(Number(target.value) / 100 * this._lottieInstance.totalFrames));
1399
- }
1400
- _isLottie(json) {
1401
- const mandatory = [
1402
- 'v',
1403
- 'ip',
1404
- 'op',
1405
- 'layers',
1406
- 'fr',
1407
- 'w',
1408
- 'h'
1409
- ];
1410
- return mandatory.every((field)=>Object.prototype.hasOwnProperty.call(json, field));
1411
- }
1412
- /**
1413
- * Creates a new dotLottie file, by combinig several animations
1414
- * @param { [ AnimationConfig ] } configs
1415
- * @param { string } fileName
1416
- * @param { boolean } shouldDownload Whether to trigger a download in the browser.
1417
- * If set to false the function returns an ArrayBuffer. Defaults to true.
1418
- *
1419
- */ async addAnimation(configs, fileName, shouldDownload = true) {
1420
- // Initialize meta object for animation, with fallbacks for
1421
- // when the method is called indepenently
1422
- const { animations = [], manifest = {
1423
- animations: this.src ? [
1424
- {
1425
- id: this._identifier
1426
- }
1427
- ] : []
1428
- } } = this.src ? await getAnimationData(this.src) : {};
1150
+ this.source = src;
1151
+ // Load the resource
1429
1152
  try {
1430
- // @ts-expect-error TODO:
1431
- manifest.generator = pkg.name;
1432
- const { length } = configs;
1433
- for(let i = 0; i < length; i++){
1434
- const { url } = configs[i], { animations: animationsToAdd } = await getAnimationData(url);
1435
- if (!animationsToAdd) {
1436
- throw new Error('No animation loaded');
1437
- }
1438
- if (manifest?.animations.some(({ id })=>id === configs[i].id)) {
1439
- throw new Error('Duplicate id for animation');
1440
- }
1441
- // @ts-expect-error TODO:
1442
- manifest.animations = [
1443
- ...manifest.animations,
1153
+ const { animations, isDotLottie, manifest } = await getAnimationData(src);
1154
+ if (!animations || animations.some((animation)=>!this._isLottie(animation))) {
1155
+ throw new Error('Broken or corrupted file');
1156
+ }
1157
+ this._isBounce = this.mode === PlayMode.Bounce;
1158
+ if (this._multiAnimationSettings.length > 0 && this._multiAnimationSettings[this._currentAnimation]?.mode) {
1159
+ this._isBounce = this._multiAnimationSettings[this._currentAnimation].mode === PlayMode.Bounce;
1160
+ }
1161
+ this._isDotLottie = Boolean(isDotLottie);
1162
+ this._animations = animations;
1163
+ this._manifest = manifest ?? {
1164
+ animations: [
1444
1165
  {
1445
- id: configs[i].id
1166
+ autoplay: !this.animateOnScroll && this.autoplay,
1167
+ direction: this.direction,
1168
+ id: createElementID(),
1169
+ loop: this.loop,
1170
+ mode: this.mode,
1171
+ speed: this.speed
1446
1172
  }
1447
- ];
1448
- animations.push(...animationsToAdd);
1449
- }
1450
- return {
1451
- result: await createDotLottie({
1452
- animations,
1453
- fileName,
1454
- // @ts-expect-error TODO:
1455
- manifest,
1456
- shouldDownload
1457
- }),
1458
- success: true
1459
- };
1460
- } catch (err) {
1461
- return {
1462
- error: handleErrors(err).message,
1463
- success: false
1173
+ ]
1464
1174
  };
1465
- }
1466
- }
1467
- /**
1468
- * Returns the lottie-web instance used in the component
1469
- */ getLottie() {
1470
- return this._lottieInstance;
1471
- }
1472
- /**
1473
- * Play
1474
- */ async play() {
1475
- if (!this._lottieInstance) {
1175
+ // Clear previous animation, if any
1176
+ if (this._lottieInstance) {
1177
+ this._lottieInstance.destroy();
1178
+ }
1179
+ this.playerState = PlayerState.Stopped;
1180
+ if (!this.animateOnScroll && (this.autoplay || this._multiAnimationSettings[this._currentAnimation]?.autoplay)) {
1181
+ this.playerState = PlayerState.Playing;
1182
+ }
1183
+ // Initialize lottie player and load animation
1184
+ // @ts-expect-error TODO:
1185
+ this._lottieInstance = Lottie.loadAnimation({
1186
+ ...this._getOptions(),
1187
+ animationData: animations[this._currentAnimation]
1188
+ });
1189
+ } catch (error) {
1190
+ this._errorMessage = handleErrors(error).message;
1191
+ this.playerState = PlayerState.Error;
1192
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1476
1193
  return;
1477
1194
  }
1478
- if (this.playerState) {
1479
- this._playerState.prev = this.playerState;
1480
- }
1481
- try {
1482
- this._lottieInstance.play();
1483
- this.dispatchEvent(new CustomEvent(PlayerEvents.Play));
1484
- } finally{
1485
- this.playerState = PlayerState.Playing;
1195
+ this._addEventListeners();
1196
+ const speed = this._multiAnimationSettings[this._currentAnimation]?.speed ?? this.speed, direction = this._multiAnimationSettings[this._currentAnimation]?.direction ?? this.direction;
1197
+ // Set initial playback speed and direction
1198
+ this._lottieInstance.setSpeed(speed);
1199
+ this._lottieInstance.setDirection(direction);
1200
+ this._lottieInstance.setSubframe(Boolean(this.subframe));
1201
+ // Start playing if autoplay is enabled
1202
+ if (this.autoplay || this.animateOnScroll) {
1203
+ if (this.direction === -1) {
1204
+ this.seek('99%');
1205
+ }
1206
+ if (!('IntersectionObserver' in window)) {
1207
+ if (!this.animateOnScroll) {
1208
+ this.play();
1209
+ }
1210
+ this._playerState.visible = true;
1211
+ }
1212
+ this._addIntersectionObserver();
1486
1213
  }
1487
1214
  }
1488
1215
  /**
1489
- * Pause
1216
+ * Skip to next animation.
1217
+ */ next() {
1218
+ this._currentAnimation++;
1219
+ this._switchInstance();
1220
+ }
1221
+ /**
1222
+ * Pause.
1490
1223
  */ pause() {
1491
1224
  if (!this._lottieInstance) {
1492
1225
  return;
1493
1226
  }
1494
- if (this.playerState) {
1495
- this._playerState.prev = this.playerState;
1496
- }
1227
+ this._playerState.prev = this.playerState;
1497
1228
  try {
1498
1229
  this._lottieInstance.pause();
1499
1230
  this.dispatchEvent(new CustomEvent(PlayerEvents.Pause));
@@ -1502,44 +1233,88 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
1502
1233
  }
1503
1234
  }
1504
1235
  /**
1505
- * Stop
1506
- */ stop() {
1236
+ * Play.
1237
+ */ play() {
1507
1238
  if (!this._lottieInstance) {
1508
1239
  return;
1509
1240
  }
1510
- if (this.playerState) {
1511
- this._playerState.prev = this.playerState;
1512
- }
1513
- this._playerState.count = 0;
1241
+ this._playerState.prev = this.playerState;
1514
1242
  try {
1515
- this._lottieInstance.stop();
1516
- this.dispatchEvent(new CustomEvent(PlayerEvents.Stop));
1243
+ this._lottieInstance.play();
1244
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Play));
1517
1245
  } finally{
1518
- this.playerState = PlayerState.Stopped;
1246
+ this.playerState = PlayerState.Playing;
1519
1247
  }
1520
1248
  }
1521
1249
  /**
1522
- * Destroy animation and element
1523
- */ destroy() {
1524
- if (!this._lottieInstance) {
1250
+ * Skip to previous animation.
1251
+ */ prev() {
1252
+ this._currentAnimation--;
1253
+ this._switchInstance(true);
1254
+ }
1255
+ /**
1256
+ * Name: string, oldValue: string, newValue: string.
1257
+ */ propertyChangedCallback(name, _oldValue, value) {
1258
+ if (!this.shadow) {
1259
+ return;
1260
+ }
1261
+ 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');
1262
+ if (!(togglePlay instanceof HTMLButtonElement) || !(stop instanceof HTMLButtonElement) || !(next instanceof HTMLButtonElement) || !(prev instanceof HTMLButtonElement) || !(seeker instanceof HTMLInputElement) || !(progress instanceof HTMLProgressElement)) {
1263
+ return;
1264
+ }
1265
+ if (name === 'playerState') {
1266
+ togglePlay.dataset.active = (value === PlayerState.Playing || value === PlayerState.Paused).toString();
1267
+ stop.dataset.active = (value === PlayerState.Stopped).toString();
1268
+ if (value === PlayerState.Playing) {
1269
+ 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>`;
1270
+ } else {
1271
+ 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>`;
1272
+ }
1273
+ }
1274
+ if (name === '_seeker' && typeof value === 'number') {
1275
+ seeker.value = value.toString();
1276
+ seeker.ariaValueNow = value.toString();
1277
+ progress.value = value;
1278
+ }
1279
+ if (name === '_animations' && Array.isArray(value) && this._currentAnimation + 1 < value.length) {
1280
+ next.hidden = false;
1281
+ }
1282
+ if (name === '_currentAnimation' && typeof value === 'number') {
1283
+ if (value + 1 >= this._animations.length) {
1284
+ next.hidden = true;
1285
+ } else {
1286
+ next.hidden = false;
1287
+ }
1288
+ if (value) {
1289
+ prev.hidden = false;
1290
+ } else {
1291
+ prev.hidden = true;
1292
+ }
1293
+ }
1294
+ if (name === '_isSettingsOpen' && typeof value === 'boolean' && popover instanceof HTMLDivElement && convert instanceof HTMLButtonElement) {
1295
+ popover.hidden = !value;
1296
+ convert.hidden = this._isDotLottie;
1297
+ }
1298
+ }
1299
+ /**
1300
+ * Reload animation.
1301
+ */ async reload() {
1302
+ if (!this._lottieInstance || !this.src) {
1525
1303
  return;
1526
1304
  }
1527
- this.playerState = PlayerState.Destroyed;
1528
1305
  this._lottieInstance.destroy();
1529
- this._lottieInstance = null;
1530
- this.dispatchEvent(new CustomEvent(PlayerEvents.Destroyed));
1531
- this.remove();
1532
- document.removeEventListener('visibilitychange', this._onVisibilityChange);
1306
+ await this.load(this.src);
1533
1307
  }
1534
1308
  /**
1535
- * Seek to a given frame
1536
- * @param { number | string } value Frame to seek to
1309
+ * Seek to a given frame.
1310
+ *
1311
+ * @param value - Frame to seek to.
1537
1312
  */ seek(value) {
1538
1313
  if (!this._lottieInstance) {
1539
1314
  return;
1540
1315
  }
1541
1316
  // Extract frame number from either number or percentage value
1542
- const matches = value.toString().match(/^([0-9]+)(%?)$/);
1317
+ const matches = value.toString().match(/^(\d+)(%?)$/);
1543
1318
  if (!matches) {
1544
1319
  return;
1545
1320
  }
@@ -1557,7 +1332,63 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
1557
1332
  this._lottieInstance.pause();
1558
1333
  }
1559
1334
  /**
1560
- * Snapshot and download the current frame as SVG
1335
+ * Dynamically set count for loops.
1336
+ */ setCount(value) {
1337
+ this.count = value;
1338
+ }
1339
+ /**
1340
+ * Animation play direction.
1341
+ *
1342
+ * @param value - Animation direction.
1343
+ */ setDirection(value) {
1344
+ if (!this._lottieInstance) {
1345
+ return;
1346
+ }
1347
+ this._lottieInstance.setDirection(value);
1348
+ }
1349
+ /**
1350
+ * Set loop.
1351
+ *
1352
+ */ setLoop(value) {
1353
+ if (!this._lottieInstance) {
1354
+ return;
1355
+ }
1356
+ this._lottieInstance.setLoop(value);
1357
+ }
1358
+ /**
1359
+ * Set Multi-animation settings.
1360
+ *
1361
+ */ setMultiAnimationSettings(settings) {
1362
+ this._multiAnimationSettings = settings;
1363
+ }
1364
+ /**
1365
+ * Set playback segment.
1366
+ *
1367
+ */ setSegment(segment) {
1368
+ this._segment = segment;
1369
+ }
1370
+ /**
1371
+ * Set animation playback speed.
1372
+ *
1373
+ * @param value - Playback speed.
1374
+ */ setSpeed(value = 1) {
1375
+ if (!this._lottieInstance) {
1376
+ return;
1377
+ }
1378
+ this._lottieInstance.setSpeed(value);
1379
+ }
1380
+ /**
1381
+ * Toggles subframe, for more smooth animations.
1382
+ *
1383
+ * @param value - Whether animation uses subframe.
1384
+ */ setSubframe(value) {
1385
+ if (!this._lottieInstance) {
1386
+ return;
1387
+ }
1388
+ this._lottieInstance.setSubframe(value);
1389
+ }
1390
+ /**
1391
+ * Snapshot and download the current frame as SVG.
1561
1392
  */ snapshot(shouldDownload = true, name = 'AM Lottie') {
1562
1393
  try {
1563
1394
  if (!this.shadowRoot) {
@@ -1579,144 +1410,388 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
1579
1410
  });
1580
1411
  }
1581
1412
  return data;
1582
- } catch (err) {
1583
- console.error(err);
1413
+ } catch (error) {
1414
+ console.error(error);
1584
1415
  return null;
1585
1416
  }
1586
1417
  }
1587
- /**
1588
- * Toggles subframe, for more smooth animations
1589
- * @param { boolean } value Whether animation uses subframe
1590
- */ setSubframe(value) {
1418
+ /**
1419
+ * Stop.
1420
+ */ stop() {
1421
+ if (!this._lottieInstance) {
1422
+ return;
1423
+ }
1424
+ this._playerState.prev = this.playerState;
1425
+ this._playerState.count = 0;
1426
+ try {
1427
+ this._lottieInstance.stop();
1428
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Stop));
1429
+ } finally{
1430
+ this.playerState = PlayerState.Stopped;
1431
+ }
1432
+ }
1433
+ /**
1434
+ * Toggle Boomerang.
1435
+ */ toggleBoomerang() {
1436
+ const curr = this._multiAnimationSettings[this._currentAnimation];
1437
+ if (curr.mode !== undefined) {
1438
+ if (curr.mode === PlayMode.Normal) {
1439
+ curr.mode = PlayMode.Bounce;
1440
+ this._isBounce = true;
1441
+ return;
1442
+ }
1443
+ curr.mode = PlayMode.Normal;
1444
+ this._isBounce = false;
1445
+ return;
1446
+ }
1447
+ if (this.mode === PlayMode.Normal) {
1448
+ this.mode = PlayMode.Bounce;
1449
+ this._isBounce = true;
1450
+ return;
1451
+ }
1452
+ this.mode = PlayMode.Normal;
1453
+ this._isBounce = false;
1454
+ }
1455
+ /**
1456
+ * Toggle loop.
1457
+ */ toggleLoop() {
1458
+ const hasLoop = !this.loop;
1459
+ this.loop = hasLoop;
1460
+ this.setLoop(hasLoop);
1461
+ }
1462
+ /**
1463
+ * Toggle playing state.
1464
+ */ togglePlay() {
1465
+ if (!this._lottieInstance) {
1466
+ return;
1467
+ }
1468
+ const { currentFrame, playDirection, totalFrames } = this._lottieInstance;
1469
+ if (this.playerState === PlayerState.Playing) {
1470
+ this.pause();
1471
+ return;
1472
+ }
1473
+ if (this.playerState !== PlayerState.Completed) {
1474
+ this.play();
1475
+ return;
1476
+ }
1477
+ this.playerState = PlayerState.Playing;
1478
+ if (this._isBounce) {
1479
+ this.setDirection(playDirection * -1);
1480
+ this._lottieInstance.goToAndPlay(currentFrame, true);
1481
+ return;
1482
+ }
1483
+ if (playDirection === -1) {
1484
+ this._lottieInstance.goToAndPlay(totalFrames, true);
1485
+ return;
1486
+ }
1487
+ this._lottieInstance.goToAndPlay(0, true);
1488
+ }
1489
+ /**
1490
+ * Freeze animation.
1491
+ * This internal state pauses animation and is used to differentiate between
1492
+ * user requested pauses and component instigated pauses.
1493
+ */ _freeze() {
1494
+ if (!this._lottieInstance) {
1495
+ return;
1496
+ }
1497
+ this._playerState.prev = this.playerState;
1498
+ try {
1499
+ this._lottieInstance.pause();
1500
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Freeze));
1501
+ } finally{
1502
+ this.playerState = PlayerState.Frozen;
1503
+ }
1504
+ }
1505
+ /**
1506
+ * Handle blur.
1507
+ */ _handleBlur() {
1508
+ setTimeout(()=>{
1509
+ this._toggleSettings(false);
1510
+ }, 200);
1511
+ }
1512
+ /**
1513
+ * Handles click and drag actions on the progress track.
1514
+ *
1515
+ */ _handleSeekChange({ target }) {
1516
+ if (!(target instanceof HTMLInputElement) || !this._lottieInstance || isNaN(Number(target.value))) {
1517
+ return;
1518
+ }
1519
+ this.seek(Math.round(Number(target.value) / 100 * this._lottieInstance.totalFrames));
1520
+ }
1521
+ /**
1522
+ * Add event listeners.
1523
+ */ _addEventListeners() {
1524
+ this._toggleEventListeners('add');
1525
+ }
1526
+ /**
1527
+ * Add IntersectionObserver.
1528
+ */ _addIntersectionObserver() {
1529
+ if (!this._container || this._intersectionObserver || !('IntersectionObserver' in window)) {
1530
+ return;
1531
+ }
1532
+ this._intersectionObserver = new IntersectionObserver((entries)=>{
1533
+ const { length } = entries;
1534
+ for(let i = 0; i < length; i++){
1535
+ if (!entries[i].isIntersecting || document.hidden) {
1536
+ if (this.playerState === PlayerState.Playing) {
1537
+ this._freeze();
1538
+ }
1539
+ this._playerState.visible = false;
1540
+ continue;
1541
+ }
1542
+ if (!this.animateOnScroll && this.playerState === PlayerState.Frozen) {
1543
+ this.play();
1544
+ }
1545
+ if (!this._playerState.scrollY) {
1546
+ this._playerState.scrollY = scrollY;
1547
+ }
1548
+ this._playerState.visible = true;
1549
+ }
1550
+ });
1551
+ this._intersectionObserver.observe(this._container);
1552
+ }
1553
+ _complete() {
1554
+ if (!this._lottieInstance) {
1555
+ return;
1556
+ }
1557
+ if (this._animations.length > 1) {
1558
+ if (this._multiAnimationSettings[this._currentAnimation + 1]?.autoplay) {
1559
+ this.next();
1560
+ return;
1561
+ }
1562
+ if (this.loop && this._currentAnimation === this._animations.length - 1) {
1563
+ this._currentAnimation = 0;
1564
+ this._switchInstance();
1565
+ return;
1566
+ }
1567
+ }
1568
+ const { currentFrame, totalFrames } = this._lottieInstance;
1569
+ this._seeker = Math.round(currentFrame / totalFrames * 100);
1570
+ this.playerState = PlayerState.Completed;
1571
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Complete, {
1572
+ detail: {
1573
+ frame: currentFrame,
1574
+ seeker: this._seeker
1575
+ }
1576
+ }));
1577
+ }
1578
+ _dataFailed() {
1579
+ this.playerState = PlayerState.Error;
1580
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1581
+ }
1582
+ _dataReady() {
1583
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Load));
1584
+ }
1585
+ _DOMLoaded() {
1586
+ this._playerState.loaded = true;
1587
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Ready));
1588
+ }
1589
+ _enterFrame() {
1591
1590
  if (!this._lottieInstance) {
1592
1591
  return;
1593
1592
  }
1594
- this._lottieInstance.setSubframe(value);
1595
- }
1596
- /**
1597
- * Dynamically set count for loops
1598
- */ setCount(value) {
1599
- this.count = value;
1593
+ const { currentFrame, totalFrames } = this._lottieInstance;
1594
+ this._seeker = Math.round(currentFrame / totalFrames * 100);
1595
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Frame, {
1596
+ detail: {
1597
+ frame: currentFrame,
1598
+ seeker: this._seeker
1599
+ }
1600
+ }));
1600
1601
  }
1601
1602
  /**
1602
- * Freeze animation.
1603
- * This internal state pauses animation and is used to differentiate between
1604
- * user requested pauses and component instigated pauses.
1605
- */ _freeze() {
1606
- if (!this._lottieInstance) {
1607
- return;
1603
+ * Get options from props.
1604
+ *
1605
+ */ _getOptions() {
1606
+ if (!this._container) {
1607
+ throw new Error('Container not rendered');
1608
1608
  }
1609
- if (this.playerState) {
1610
- this._playerState.prev = this.playerState;
1609
+ const preserveAspectRatio = this.preserveAspectRatio ?? aspectRatio(this.objectfit), currentAnimationSettings = this._multiAnimationSettings.length > 0 ? this._multiAnimationSettings[this._currentAnimation] : undefined, currentAnimationManifest = this._manifest?.animations[this._currentAnimation];
1610
+ // Loop
1611
+ let hasLoop = Boolean(this.loop);
1612
+ if (currentAnimationManifest?.loop !== undefined) {
1613
+ hasLoop = Boolean(currentAnimationManifest.loop);
1611
1614
  }
1612
- try {
1613
- this._lottieInstance.pause();
1614
- this.dispatchEvent(new CustomEvent(PlayerEvents.Freeze));
1615
- } finally{
1616
- this.playerState = PlayerState.Frozen;
1615
+ if (currentAnimationSettings?.loop !== undefined) {
1616
+ hasLoop = Boolean(currentAnimationSettings.loop);
1617
1617
  }
1618
- }
1619
- /**
1620
- * Reload animation
1621
- */ async reload() {
1622
- if (!this._lottieInstance || !this.src) {
1623
- return;
1618
+ // Autoplay
1619
+ let hasAutoplay = Boolean(this.autoplay);
1620
+ if (currentAnimationManifest?.autoplay !== undefined) {
1621
+ hasAutoplay = Boolean(currentAnimationManifest.autoplay);
1624
1622
  }
1625
- this._lottieInstance.destroy();
1626
- await this.load(this.src);
1623
+ if (currentAnimationSettings?.autoplay !== undefined) {
1624
+ hasAutoplay = Boolean(currentAnimationSettings.autoplay);
1625
+ }
1626
+ if (this.animateOnScroll) {
1627
+ hasAutoplay = false;
1628
+ }
1629
+ // Segment
1630
+ let initialSegment = this._segment;
1631
+ if (this._segment?.every((val)=>val > 0)) {
1632
+ initialSegment = [
1633
+ this._segment[0] - 1,
1634
+ this._segment[1] - 1
1635
+ ];
1636
+ }
1637
+ if (this._segment?.some((val)=>val < 0)) {
1638
+ initialSegment = undefined;
1639
+ }
1640
+ const options = {
1641
+ autoplay: hasAutoplay,
1642
+ container: this._container,
1643
+ initialSegment,
1644
+ loop: hasLoop,
1645
+ renderer: this.renderer,
1646
+ rendererSettings: {
1647
+ imagePreserveAspectRatio: preserveAspectRatio
1648
+ }
1649
+ };
1650
+ switch(this.renderer){
1651
+ case RendererType.SVG:
1652
+ {
1653
+ options.rendererSettings = {
1654
+ ...options.rendererSettings,
1655
+ hideOnTransparent: true,
1656
+ preserveAspectRatio,
1657
+ progressiveLoad: true
1658
+ };
1659
+ break;
1660
+ }
1661
+ case RendererType.Canvas:
1662
+ {
1663
+ options.rendererSettings = {
1664
+ ...options.rendererSettings,
1665
+ // @ts-expect-error TODO:
1666
+ clearCanvas: true,
1667
+ preserveAspectRatio,
1668
+ progressiveLoad: true
1669
+ };
1670
+ break;
1671
+ }
1672
+ case RendererType.HTML:
1673
+ {
1674
+ options.rendererSettings = {
1675
+ ...options.rendererSettings,
1676
+ hideOnTransparent: true
1677
+ };
1678
+ }
1679
+ }
1680
+ return options;
1627
1681
  }
1628
1682
  /**
1629
- * Set animation playback speed
1630
- * @param { number } value Playback speed
1631
- */ setSpeed(value = 1) {
1632
- if (!this._lottieInstance) {
1683
+ * Handle scroll.
1684
+ */ _handleScroll() {
1685
+ if (!this.animateOnScroll || !this._lottieInstance) {
1633
1686
  return;
1634
1687
  }
1635
- this._lottieInstance.setSpeed(value);
1636
- }
1637
- /**
1638
- * Animation play direction
1639
- * @param { AnimationDirection } value Animation direction
1640
- */ setDirection(value) {
1641
- if (!this._lottieInstance) {
1688
+ if (isServer()) {
1689
+ console.warn('DotLottie: Scroll animations might not work properly in a Server Side Rendering context. Try to wrap this in a client component.');
1642
1690
  return;
1643
1691
  }
1644
- this._lottieInstance.setDirection(value);
1692
+ if (this._playerState.visible) {
1693
+ if (this._playerState.scrollTimeout) {
1694
+ clearTimeout(this._playerState.scrollTimeout);
1695
+ }
1696
+ this._playerState.scrollTimeout = setTimeout(()=>{
1697
+ this.playerState = PlayerState.Paused;
1698
+ }, 400);
1699
+ 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;
1700
+ requestAnimationFrame(()=>{
1701
+ if (roundedScroll < (this._lottieInstance?.totalFrames ?? 0)) {
1702
+ this.playerState = PlayerState.Playing;
1703
+ this._lottieInstance?.goToAndStop(roundedScroll, true);
1704
+ } else {
1705
+ this.playerState = PlayerState.Paused;
1706
+ }
1707
+ });
1708
+ }
1645
1709
  }
1646
- /**
1647
- * Set loop
1648
- * @param { boolean } value
1649
- */ setLoop(value) {
1650
- if (!this._lottieInstance) {
1651
- return;
1710
+ _handleWindowBlur({ type }) {
1711
+ if (this.playerState === PlayerState.Playing && type === 'blur') {
1712
+ this._freeze();
1713
+ }
1714
+ if (this.playerState === PlayerState.Frozen && type === 'focus') {
1715
+ this.play();
1652
1716
  }
1653
- this._lottieInstance.setLoop(value);
1654
1717
  }
1655
- /**
1656
- * Toggle playing state
1657
- */ togglePlay() {
1718
+ _isLottie(json) {
1719
+ const mandatory = [
1720
+ 'v',
1721
+ 'ip',
1722
+ 'op',
1723
+ 'layers',
1724
+ 'fr',
1725
+ 'w',
1726
+ 'h'
1727
+ ];
1728
+ return mandatory.every((field)=>Object.hasOwn(json, field));
1729
+ }
1730
+ _loopComplete() {
1658
1731
  if (!this._lottieInstance) {
1659
1732
  return;
1660
1733
  }
1661
- const { currentFrame, playDirection, totalFrames } = this._lottieInstance;
1662
- if (this.playerState === PlayerState.Playing) {
1663
- return this.pause();
1664
- }
1665
- if (this.playerState !== PlayerState.Completed) {
1666
- return this.play();
1734
+ const { playDirection, // firstFrame,
1735
+ totalFrames } = this._lottieInstance, inPoint = this._segment ? this._segment[0] : 0, outPoint = this._segment ? this._segment[0] : totalFrames;
1736
+ if (this.count) {
1737
+ if (this._isBounce) {
1738
+ this._playerState.count += 0.5;
1739
+ } else {
1740
+ this._playerState.count += 1;
1741
+ }
1742
+ if (this._playerState.count >= this.count) {
1743
+ this.setLoop(false);
1744
+ this.playerState = PlayerState.Completed;
1745
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Complete));
1746
+ return;
1747
+ }
1667
1748
  }
1668
- this.playerState = PlayerState.Playing;
1749
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Loop));
1669
1750
  if (this._isBounce) {
1670
- this.setDirection(playDirection * -1);
1671
- return this._lottieInstance.goToAndPlay(currentFrame, true);
1672
- }
1673
- if (playDirection === -1) {
1674
- return this._lottieInstance.goToAndPlay(totalFrames, true);
1751
+ this._lottieInstance.goToAndStop(playDirection === -1 ? inPoint : outPoint * 0.99, true);
1752
+ this._lottieInstance.setDirection(playDirection * -1);
1753
+ return setTimeout(()=>{
1754
+ if (!this.animateOnScroll) {
1755
+ this._lottieInstance?.play();
1756
+ }
1757
+ }, this.intermission);
1675
1758
  }
1676
- return this._lottieInstance.goToAndPlay(0, true);
1759
+ this._lottieInstance.goToAndStop(playDirection === -1 ? outPoint * 0.99 : inPoint, true);
1760
+ return setTimeout(()=>{
1761
+ if (!this.animateOnScroll) {
1762
+ this._lottieInstance?.play();
1763
+ }
1764
+ }, this.intermission);
1677
1765
  }
1678
1766
  /**
1679
- * Toggle loop
1680
- */ toggleLoop() {
1681
- const val = !this.loop;
1682
- this.loop = val;
1683
- this.setLoop(val);
1767
+ * Handle MouseEnter.
1768
+ */ _mouseEnter() {
1769
+ if (this.hover && this.playerState !== PlayerState.Playing) {
1770
+ this.play();
1771
+ }
1684
1772
  }
1685
1773
  /**
1686
- * Toggle Boomerang
1687
- */ toggleBoomerang() {
1688
- const curr = this._multiAnimationSettings?.[this._currentAnimation];
1689
- if (curr?.mode !== undefined) {
1690
- if (curr.mode === PlayMode.Normal) {
1691
- curr.mode = PlayMode.Bounce;
1692
- this._isBounce = true;
1693
- return;
1694
- }
1695
- curr.mode = PlayMode.Normal;
1696
- this._isBounce = false;
1697
- return;
1698
- }
1699
- if (this.mode === PlayMode.Normal) {
1700
- this.mode = PlayMode.Bounce;
1701
- this._isBounce = true;
1702
- return;
1774
+ * Handle MouseLeave.
1775
+ */ _mouseLeave() {
1776
+ if (this.hover && this.playerState === PlayerState.Playing) {
1777
+ this.stop();
1703
1778
  }
1704
- this.mode = PlayMode.Normal;
1705
- this._isBounce = false;
1706
1779
  }
1707
1780
  /**
1708
- * Toggle show Settings
1709
- */ _toggleSettings(flag) {
1710
- if (flag === undefined) {
1711
- this._isSettingsOpen = !this._isSettingsOpen;
1781
+ * Handle visibility change events.
1782
+ */ _onVisibilityChange() {
1783
+ if (document.hidden && this.playerState === PlayerState.Playing) {
1784
+ this._freeze();
1712
1785
  return;
1713
1786
  }
1714
- this._isSettingsOpen = flag;
1787
+ if (this.playerState === PlayerState.Frozen) {
1788
+ this.play();
1789
+ }
1715
1790
  }
1716
1791
  /**
1717
- * Handle blur
1718
- */ _handleBlur() {
1719
- setTimeout(()=>this._toggleSettings(false), 200);
1792
+ * Remove event listeners.
1793
+ */ _removeEventListeners() {
1794
+ this._toggleEventListeners('remove');
1720
1795
  }
1721
1796
  _switchInstance(isPrevious = false) {
1722
1797
  // Bail early if there is not animation to play
@@ -1730,82 +1805,85 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
1730
1805
  }
1731
1806
  // Re-initialize lottie player
1732
1807
  // @ts-expect-error TODO:
1733
- this._lottieInstance = Lottie.default.loadAnimation({
1808
+ this._lottieInstance = Lottie.loadAnimation({
1734
1809
  ...this._getOptions(),
1735
1810
  animationData: this._animations[this._currentAnimation]
1736
1811
  });
1737
1812
  // Check play mode for current animation
1738
- if (this._multiAnimationSettings?.[this._currentAnimation]?.mode) {
1813
+ if (this._multiAnimationSettings[this._currentAnimation]?.mode) {
1739
1814
  this._isBounce = this._multiAnimationSettings[this._currentAnimation].mode === PlayMode.Bounce;
1740
1815
  }
1741
1816
  // Remove event listeners to new Lottie instance, and add new
1742
1817
  this._removeEventListeners();
1743
1818
  this._addEventListeners();
1744
1819
  this.dispatchEvent(new CustomEvent(isPrevious ? PlayerEvents.Previous : PlayerEvents.Next));
1745
- if (this._multiAnimationSettings?.[this._currentAnimation]?.autoplay ?? this.autoplay) {
1820
+ if (this._multiAnimationSettings[this._currentAnimation]?.autoplay ?? this.autoplay) {
1746
1821
  if (this.animateOnScroll) {
1747
- this._lottieInstance?.goToAndStop(0, true);
1822
+ this._lottieInstance.goToAndStop(0, true);
1748
1823
  this.playerState = PlayerState.Paused;
1749
1824
  return;
1750
1825
  }
1751
- this._lottieInstance?.goToAndPlay(0, true);
1826
+ this._lottieInstance.goToAndPlay(0, true);
1752
1827
  this.playerState = PlayerState.Playing;
1753
1828
  return;
1754
1829
  }
1755
- this._lottieInstance?.goToAndStop(0, true);
1830
+ this._lottieInstance.goToAndStop(0, true);
1756
1831
  this.playerState = PlayerState.Stopped;
1757
- } catch (err) {
1758
- this._errorMessage = handleErrors(err).message;
1832
+ } catch (error) {
1833
+ this._errorMessage = handleErrors(error).message;
1759
1834
  this.playerState = PlayerState.Error;
1760
1835
  this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1761
1836
  }
1762
1837
  }
1763
1838
  /**
1764
- * Skip to next animation
1765
- */ next() {
1766
- this._currentAnimation++;
1767
- this._switchInstance();
1768
- }
1769
- /**
1770
- * Skip to previous animation
1771
- */ prev() {
1772
- this._currentAnimation--;
1773
- this._switchInstance(true);
1774
- }
1775
- async convert({ animations, fileName, manifest, shouldDownload = true, src, typeCheck }) {
1776
- if (typeCheck || this._isDotLottie) {
1777
- return createJSON({
1778
- animation: (await getAnimationData(src || this.src))?.animations?.[0],
1779
- fileName: `${getFilename(fileName || this.src || 'converted')}.json`,
1780
- shouldDownload
1781
- });
1839
+ * Toggle event listeners.
1840
+ */ _toggleEventListeners(action) {
1841
+ const method = action === 'add' ? 'addEventListener' : 'removeEventListener';
1842
+ if (this._lottieInstance) {
1843
+ this._lottieInstance[method]('enterFrame', this._enterFrame);
1844
+ this._lottieInstance[method]('complete', this._complete);
1845
+ this._lottieInstance[method]('loopComplete', this._loopComplete);
1846
+ this._lottieInstance[method]('DOMLoaded', this._DOMLoaded);
1847
+ this._lottieInstance[method]('data_ready', this._dataReady);
1848
+ this._lottieInstance[method]('data_failed', this._dataFailed);
1782
1849
  }
1783
- return createDotLottie({
1784
- animations: animations || (await getAnimationData(this.src)).animations,
1785
- fileName: `${getFilename(fileName || this.src || 'converted')}.lottie`,
1786
- manifest: {
1787
- ...manifest || this._manifest,
1788
- generator: pkg.name
1789
- },
1790
- shouldDownload
1850
+ if (this._container && this.hover) {
1851
+ this._container[method]('mouseenter', this._mouseEnter);
1852
+ this._container[method]('mouseleave', this._mouseLeave);
1853
+ }
1854
+ window[method]('focus', this._handleWindowBlur, {
1855
+ capture: false,
1856
+ passive: true
1857
+ });
1858
+ window[method]('blur', this._handleWindowBlur, {
1859
+ capture: false,
1860
+ passive: true
1791
1861
  });
1862
+ if (this.animateOnScroll) {
1863
+ window[method]('scroll', this._handleScroll, {
1864
+ capture: true,
1865
+ passive: true
1866
+ });
1867
+ }
1792
1868
  }
1793
1869
  /**
1794
- * Return the styles for the component
1795
- */ static get styles() {
1796
- const styleSheet = new CSSStyleSheet();
1797
- styleSheet.replace(css_248z);
1798
- return styleSheet;
1870
+ * Toggle show Settings.
1871
+ */ _toggleSettings(flag) {
1872
+ if (flag === undefined) {
1873
+ this._isSettingsOpen = !this._isSettingsOpen;
1874
+ return;
1875
+ }
1876
+ this._isSettingsOpen = flag;
1799
1877
  }
1800
1878
  }
1801
1879
 
1802
1880
  /**
1803
- * Expose DotLottiePlayer class as global variable
1804
- * @returns { DotLottiePlayer }
1881
+ * Expose DotLottiePlayer class as global variable.
1882
+ *
1805
1883
  */ globalThis.dotLottiePlayer = ()=>new DotLottiePlayer();
1806
1884
  const tagName = 'dotlottie-player';
1807
1885
  if (!isServer()) {
1808
- customElements.define('dotlottie-player', DotLottiePlayer);
1886
+ customElements.define(tagName, DotLottiePlayer);
1809
1887
  }
1810
1888
 
1811
1889
  export { PlayMode, PlayerEvents, PlayerState, DotLottiePlayer as default, tagName };