@aarsteinmedia/dotlottie-player 5.0.1 → 5.0.2

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,264 @@ 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
+ /**
636
+ * DotLottie Player Web Component.
637
+ */ class DotLottiePlayer extends PropertyCallbackElement {
312
638
  /**
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';
639
+ * Attributes to observe.
640
+ */ static get observedAttributes() {
641
+ return [
642
+ 'animateOnScroll',
643
+ 'autoplay',
644
+ 'controls',
645
+ 'direction',
646
+ 'hover',
647
+ 'loop',
648
+ 'mode',
649
+ 'speed',
650
+ 'src',
651
+ 'subframe'
652
+ ];
318
653
  }
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);
654
+ static get observedProperties() {
655
+ return [
656
+ 'playerState',
657
+ '_isSettingsOpen',
658
+ '_seeker',
659
+ '_currentAnimation',
660
+ '_animations'
661
+ ];
323
662
  }
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');
663
+ /**
664
+ * Return the styles for the component.
665
+ */ static get styles() {
666
+ return async ()=>{
667
+ const styleSheet = new CSSStyleSheet();
668
+ await styleSheet.replace(css_248z);
669
+ return styleSheet;
670
+ };
333
671
  }
334
- if (!manifest.animations.length) {
335
- throw new Error('No animations listed in manifest');
672
+ /**
673
+ * Whether to trigger next frame with scroll.
674
+ */ set animateOnScroll(value) {
675
+ this.setAttribute('animateOnScroll', Boolean(value).toString());
336
676
  }
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 '';
677
+ get animateOnScroll() {
678
+ const val = this.getAttribute('animateOnScroll');
679
+ return Boolean(val === 'true' || val === '' || val === '1');
357
680
  }
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
- }
681
+ /**
682
+ * Autoplay.
683
+ */ set autoplay(value) {
684
+ this.setAttribute('autoplay', Boolean(value).toString());
370
685
  }
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;
686
+ get autoplay() {
687
+ const val = this.getAttribute('autoplay');
688
+ return Boolean(val === 'true' || val === '' || val === '1');
378
689
  }
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;
690
+ /**
691
+ * Background color.
692
+ */ set background(value) {
693
+ this.setAttribute('background', value);
387
694
  }
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
- }));
695
+ get background() {
696
+ return this.getAttribute('background') || 'transparent';
404
697
  }
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;
698
+ /**
699
+ * Show controls.
700
+ */ set controls(value) {
701
+ this.setAttribute('controls', Boolean(value).toString());
434
702
  }
435
- if (!this.controls) {
436
- slot.innerHTML = '';
437
- return;
703
+ get controls() {
704
+ const val = this.getAttribute('controls');
705
+ return Boolean(val === 'true' || val === '' || val === '1');
438
706
  }
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;
707
+ /**
708
+ * Number of times to loop.
709
+ */ set count(value) {
710
+ this.setAttribute('count', value.toString());
443
711
  }
444
- const stop = this.shadow.querySelector('.stop');
445
- if (stop instanceof HTMLButtonElement) {
446
- stop.onclick = this.stop;
712
+ get count() {
713
+ const val = this.getAttribute('count');
714
+ if (val) {
715
+ return Number(val);
716
+ }
717
+ return 0;
447
718
  }
448
- const prev = this.shadow.querySelector('.prev');
449
- if (prev instanceof HTMLButtonElement) {
450
- prev.onclick = this.prev;
719
+ /**
720
+ * Description for screen readers.
721
+ */ set description(value) {
722
+ if (value) {
723
+ this.setAttribute('description', value);
724
+ }
451
725
  }
452
- const next = this.shadow.querySelector('.next');
453
- if (next instanceof HTMLButtonElement) {
454
- next.onclick = this.next;
726
+ get description() {
727
+ return this.getAttribute('description');
455
728
  }
456
- const seeker = this.shadow.querySelector('.seeker');
457
- if (seeker instanceof HTMLInputElement) {
458
- seeker.onchange = this._handleSeekChange;
459
- seeker.onmousedown = this._freeze;
729
+ /**
730
+ * Direction of animation.
731
+ */ set direction(value) {
732
+ this.setAttribute('direction', value.toString());
460
733
  }
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;
734
+ get direction() {
735
+ const val = Number(this.getAttribute('direction'));
736
+ if (val === -1) {
737
+ return val;
473
738
  }
474
- const snapshot = this.shadow.querySelector('.snapshot');
475
- if (snapshot instanceof HTMLButtonElement) {
476
- snapshot.onclick = ()=>this.snapshot(true);
739
+ return 1;
740
+ }
741
+ /**
742
+ * Whether to play on mouseover.
743
+ */ set hover(value) {
744
+ this.setAttribute('hover', value.toString());
745
+ }
746
+ get hover() {
747
+ const val = this.getAttribute('hover');
748
+ return Boolean(val === 'true' || val === '' || val === '1');
749
+ }
750
+ /**
751
+ * Pause between loop intrations, in miliseconds.
752
+ */ set intermission(value) {
753
+ this.setAttribute('intermission', value.toString());
754
+ }
755
+ get intermission() {
756
+ const val = Number(this.getAttribute('intermission'));
757
+ if (!isNaN(val)) {
758
+ return val;
477
759
  }
478
- const toggleSettings = this.shadow.querySelector('.toggleSettings');
479
- if (toggleSettings instanceof HTMLButtonElement) {
480
- toggleSettings.onclick = this._handleSettingsClick;
481
- toggleSettings.onblur = this._handleBlur;
760
+ return 0;
761
+ }
762
+ /**
763
+ * Loop animation.
764
+ */ set loop(value) {
765
+ this.setAttribute('loop', Boolean(value).toString());
766
+ }
767
+ get loop() {
768
+ const val = this.getAttribute('loop');
769
+ return Boolean(val === 'true' || val === '' || val === '1');
770
+ }
771
+ /**
772
+ * Play mode.
773
+ */ set mode(value) {
774
+ this.setAttribute('mode', value.toString());
775
+ }
776
+ get mode() {
777
+ const val = this.getAttribute('mode');
778
+ if (val === PlayMode.Bounce) {
779
+ return val;
482
780
  }
781
+ return PlayMode.Normal;
483
782
  }
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] = [];
783
+ /**
784
+ * Resizing to container.
785
+ */ set objectfit(value) {
786
+ this.setAttribute('objectfit', value);
787
+ }
788
+ get objectfit() {
789
+ const val = this.getAttribute('objectfit');
790
+ if (val && Object.values(ObjectFit).includes(val)) {
791
+ return val;
503
792
  }
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
- }
793
+ return ObjectFit.Contain;
794
+ }
795
+ /**
796
+ * Resizing to container (Deprecated).
797
+ */ set preserveAspectRatio(value) {
798
+ this.setAttribute('preserveAspectRatio', value || PreserveAspectRatio.Contain);
799
+ }
800
+ get preserveAspectRatio() {
801
+ const val = this.getAttribute('preserveAspectRatio');
802
+ if (val && Object.values(PreserveAspectRatio).includes(val)) {
803
+ return val;
526
804
  }
805
+ return null;
527
806
  }
528
- connectedCallback() {
529
- let arr = [];
530
- if (UPDATE_ON_CONNECTED in this && Array.isArray(this[UPDATE_ON_CONNECTED])) {
531
- arr = this[UPDATE_ON_CONNECTED];
807
+ /**
808
+ * Renderer to use: svg, canvas or html.
809
+ */ set renderer(value) {
810
+ this.setAttribute('renderer', value);
811
+ }
812
+ get renderer() {
813
+ const val = this.getAttribute('renderer');
814
+ if (val === RendererType.Canvas || val === RendererType.HTML) {
815
+ return val;
532
816
  }
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
- }
817
+ return RendererType.SVG;
818
+ }
819
+ /**
820
+ * Hide advanced controls.
821
+ */ set simple(value) {
822
+ this.setAttribute('simple', value.toString());
823
+ }
824
+ get simple() {
825
+ const val = this.getAttribute('simple');
826
+ return Boolean(val === 'true' || val === '' || val === '1');
827
+ }
828
+ /**
829
+ * Speed.
830
+ */ set speed(value) {
831
+ this.setAttribute('speed', value.toString());
832
+ }
833
+ get speed() {
834
+ const val = this.getAttribute('speed');
835
+ if (val !== null && !isNaN(Number(val))) {
836
+ return Number(val);
541
837
  }
838
+ return 1;
839
+ }
840
+ /**
841
+ * Source, either path or JSON string.
842
+ */ set src(value) {
843
+ this.setAttribute('src', value || '');
844
+ }
845
+ get src() {
846
+ return this.getAttribute('src');
847
+ }
848
+ /**
849
+ * Subframe.
850
+ */ set subframe(value) {
851
+ this.setAttribute('subframe', Boolean(value).toString());
852
+ }
853
+ get subframe() {
854
+ const val = this.getAttribute('subframe');
855
+ return Boolean(val === 'true' || val === '' || val === '1');
542
856
  }
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
857
  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
858
+ super(), /**
859
+ * Player state.
564
860
  */ 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 = {
861
+ * Animation Container.
862
+ */ this._container = null, this._errorMessage = 'Something went wrong', this._identifier = this.id || createElementID(), /**
863
+ * Whether settings toolbar is open.
864
+ */ this._isSettingsOpen = false, this._playerState = {
579
865
  count: 0,
580
866
  loaded: false,
581
867
  prev: PlayerState.Loading,
582
868
  scrollTimeout: null,
583
869
  scrollY: 0,
584
870
  visible: false
585
- }, /**
586
- * Handle settings click event
871
+ }, this._render = renderPlayer, this._renderControls = renderControls, /**
872
+ * Seeker.
873
+ */ this._seeker = 0, /**
874
+ * This is included in watched properties,
875
+ * so that next-button will show up
876
+ * on load, if controls are visible.
877
+ */ this._animations = [], /**
878
+ * Which animation to show, if several.
879
+ */ this._currentAnimation = 0, this._isBounce = false, this._isDotLottie = false, this._lottieInstance = null, /**
880
+ * Multi-animation settings.
881
+ */ this._multiAnimationSettings = [], /**
882
+ * Handle settings click event.
587
883
  */ this._handleSettingsClick = ({ target })=>{
588
884
  this._toggleSettings();
589
885
  // Because Safari does not add focus on click, we need to add it manually, so the onblur event will fire
@@ -622,55 +918,58 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
622
918
  });
623
919
  }
624
920
  /**
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();
921
+ * Creates a new dotLottie file, by combinig several animations.
922
+ * If set to false the function returns an ArrayBuffer. Defaults to true.
923
+ */ async addAnimation(configs, fileName, shouldDownload = true) {
924
+ // Initialize meta object for animation, with fallbacks for
925
+ // when the method is called indepenently
926
+ const { animations = [], manifest = {
927
+ animations: this.src ? [
928
+ {
929
+ id: this._identifier
930
+ }
931
+ ] : []
932
+ } } = this.src ? await getAnimationData(this.src) : {};
933
+ try {
934
+ if (!manifest) {
935
+ throw new Error('Manifest is not set');
936
+ }
937
+ manifest.generator = '@aarsteinmedia/dotlottie-player';
938
+ const { length } = configs;
939
+ for(let i = 0; i < length; i++){
940
+ const { url } = configs[i], { animations: animationsToAdd } = await getAnimationData(url);
941
+ if (!animationsToAdd) {
942
+ throw new Error('No animation loaded');
943
+ }
944
+ if (manifest.animations.some(({ id })=>id === configs[i].id)) {
945
+ throw new Error('Duplicate id for animation');
946
+ }
947
+ manifest.animations = [
948
+ ...manifest.animations,
949
+ {
950
+ id: configs[i].id
951
+ }
952
+ ];
953
+ animations.push(...animationsToAdd);
954
+ }
955
+ return {
956
+ result: await createDotLottie({
957
+ animations,
958
+ fileName,
959
+ manifest,
960
+ shouldDownload
961
+ }),
962
+ success: true
963
+ };
964
+ } catch (error) {
965
+ return {
966
+ error: handleErrors(error).message,
967
+ success: false
968
+ };
652
969
  }
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
970
  }
672
971
  /**
673
- * Runs when the value of an attribute is changed on the component
972
+ * Runs when the value of an attribute is changed on the component.
674
973
  */ async attributeChangedCallback(name, _oldValue, value) {
675
974
  if (!this._lottieInstance) {
676
975
  return;
@@ -701,7 +1000,8 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
701
1000
  }
702
1001
  if (name === 'direction') {
703
1002
  if (Number(value) === -1) {
704
- return this.setDirection(-1);
1003
+ this.setDirection(-1);
1004
+ return;
705
1005
  }
706
1006
  this.setDirection(1);
707
1007
  }
@@ -715,14 +1015,14 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
715
1015
  this._container.removeEventListener('mouseleave', this._mouseLeave);
716
1016
  }
717
1017
  if (name === 'loop') {
718
- const toggleLoop = this.shadow.querySelector('.toggleLoop');
1018
+ const toggleLoop = this.shadow?.querySelector('.toggleLoop');
719
1019
  if (toggleLoop instanceof HTMLButtonElement) {
720
1020
  toggleLoop.dataset.active = value;
721
1021
  }
722
1022
  this.setLoop(value === '' || Boolean(value));
723
1023
  }
724
1024
  if (name === 'mode') {
725
- const toggleBoomerang = this.shadow.querySelector('.toggleBoomerang');
1025
+ const toggleBoomerang = this.shadow?.querySelector('.toggleBoomerang');
726
1026
  if (toggleBoomerang instanceof HTMLButtonElement) {
727
1027
  toggleBoomerang.dataset.active = (value === PlayMode.Bounce).toString();
728
1028
  }
@@ -741,759 +1041,189 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
741
1041
  this.setSubframe(value === '' || Boolean(value));
742
1042
  }
743
1043
  }
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) {
1044
+ /**
1045
+ * Initialize everything on component first render.
1046
+ */ async connectedCallback() {
1047
+ await super.connectedCallback();
1048
+ await this._render();
755
1049
  if (!this.shadow) {
756
- return;
1050
+ throw new Error('Missing Shadow element');
757
1051
  }
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);
1052
+ this._container = this.shadow.querySelector('.animation');
1053
+ this._renderControls();
1054
+ // Add listener for Visibility API's change event.
1055
+ if (typeof document.hidden !== 'undefined') {
1056
+ document.addEventListener('visibilitychange', this._onVisibilityChange);
1275
1057
  }
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);
1058
+ // Add intersection observer for detecting component being out-of-view.
1059
+ this._addIntersectionObserver();
1060
+ // Setup lottie player
1061
+ await this.load(this.src);
1062
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Rendered));
1282
1063
  }
1283
- _enterFrame() {
1284
- if (!this._lottieInstance) {
1064
+ async convert({ animations: animationsFromProps, fileName, manifest, shouldDownload = true, src: srcFromProps, typeCheck }) {
1065
+ const src = srcFromProps || this.src || this.source;
1066
+ if (!src) {
1067
+ throw new Error('No animation to convert');
1068
+ }
1069
+ if (typeCheck || this._isDotLottie) {
1070
+ const animationData = await getAnimationData(src);
1071
+ createJSON({
1072
+ animation: animationData.animations?.[0],
1073
+ fileName: `${getFilename(fileName || src || 'converted')}.json`,
1074
+ shouldDownload
1075
+ });
1285
1076
  return;
1286
1077
  }
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
- }));
1078
+ let animations = animationsFromProps;
1079
+ if (!animations) {
1080
+ const animationData = await getAnimationData(src);
1081
+ animations = animationData.animations;
1082
+ }
1083
+ return createDotLottie({
1084
+ animations,
1085
+ fileName: `${getFilename(fileName || src || 'converted')}.lottie`,
1086
+ manifest: {
1087
+ ...manifest ?? this._manifest,
1088
+ generator: '[[GENERATOR]]'
1089
+ },
1090
+ shouldDownload
1091
+ });
1295
1092
  }
1296
- _complete() {
1093
+ /**
1094
+ * Destroy animation and element.
1095
+ */ destroy() {
1297
1096
  if (!this._lottieInstance) {
1298
1097
  return;
1299
1098
  }
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));
1099
+ this.playerState = PlayerState.Destroyed;
1100
+ this._lottieInstance.destroy();
1101
+ this._lottieInstance = null;
1102
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Destroyed));
1103
+ this.remove();
1104
+ document.removeEventListener('visibilitychange', this._onVisibilityChange);
1329
1105
  }
1330
- _handleWindowBlur({ type }) {
1331
- if (this.playerState === PlayerState.Playing && type === 'blur') {
1332
- this._freeze();
1106
+ /**
1107
+ * Cleanup on component destroy.
1108
+ */ disconnectedCallback() {
1109
+ // Remove intersection observer for detecting component being out-of-view
1110
+ if (this._intersectionObserver) {
1111
+ this._intersectionObserver.disconnect();
1112
+ this._intersectionObserver = undefined;
1333
1113
  }
1334
- if (this.playerState === PlayerState.Frozen && type === 'focus') {
1335
- this.play();
1114
+ // Destroy the animation instance
1115
+ if (this._lottieInstance) {
1116
+ this._lottieInstance.destroy();
1336
1117
  }
1118
+ // Remove the attached Visibility API's change event listener
1119
+ document.removeEventListener('visibilitychange', this._onVisibilityChange);
1337
1120
  }
1338
1121
  /**
1339
- * Handle MouseEnter
1340
- */ _mouseEnter() {
1341
- if (this.hover && this.playerState !== PlayerState.Playing) {
1342
- this.play();
1343
- }
1122
+ * Returns the lottie-web instance used in the component.
1123
+ */ getLottie() {
1124
+ return this._lottieInstance;
1344
1125
  }
1345
1126
  /**
1346
- * Handle MouseLeave
1347
- */ _mouseLeave() {
1348
- if (this.hover && this.playerState === PlayerState.Playing) {
1349
- this.stop();
1350
- }
1127
+ * Get Lottie Manifest.
1128
+ */ getManifest() {
1129
+ return this._manifest;
1351
1130
  }
1352
1131
  /**
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
- }
1132
+ * Get Multi-animation settings.
1133
+ *
1134
+ */ getMultiAnimationSettings() {
1135
+ return this._multiAnimationSettings;
1362
1136
  }
1363
1137
  /**
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
- }
1138
+ * Get playback segment.
1139
+ *
1140
+ */ getSegment() {
1141
+ return this._segment;
1390
1142
  }
1391
1143
  /**
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))) {
1144
+ * Initialize Lottie Web player.
1145
+ */ async load(src) {
1146
+ if (!this.shadowRoot || !src) {
1396
1147
  return;
1397
1148
  }
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) : {};
1149
+ this.source = src;
1150
+ // Load the resource
1429
1151
  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,
1152
+ const { animations, isDotLottie, manifest } = await getAnimationData(src);
1153
+ if (!animations || animations.some((animation)=>!this._isLottie(animation))) {
1154
+ throw new Error('Broken or corrupted file');
1155
+ }
1156
+ this._isBounce = this.mode === PlayMode.Bounce;
1157
+ if (this._multiAnimationSettings.length > 0 && this._multiAnimationSettings[this._currentAnimation]?.mode) {
1158
+ this._isBounce = this._multiAnimationSettings[this._currentAnimation].mode === PlayMode.Bounce;
1159
+ }
1160
+ this._isDotLottie = Boolean(isDotLottie);
1161
+ this._animations = animations;
1162
+ this._manifest = manifest ?? {
1163
+ animations: [
1444
1164
  {
1445
- id: configs[i].id
1165
+ autoplay: !this.animateOnScroll && this.autoplay,
1166
+ direction: this.direction,
1167
+ id: createElementID(),
1168
+ loop: this.loop,
1169
+ mode: this.mode,
1170
+ speed: this.speed
1446
1171
  }
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
1172
+ ]
1464
1173
  };
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) {
1174
+ // Clear previous animation, if any
1175
+ if (this._lottieInstance) {
1176
+ this._lottieInstance.destroy();
1177
+ }
1178
+ this.playerState = PlayerState.Stopped;
1179
+ if (!this.animateOnScroll && (this.autoplay || this._multiAnimationSettings[this._currentAnimation]?.autoplay)) {
1180
+ this.playerState = PlayerState.Playing;
1181
+ }
1182
+ // Initialize lottie player and load animation
1183
+ // @ts-expect-error TODO:
1184
+ this._lottieInstance = Lottie.loadAnimation({
1185
+ ...this._getOptions(),
1186
+ animationData: animations[this._currentAnimation]
1187
+ });
1188
+ } catch (error) {
1189
+ this._errorMessage = handleErrors(error).message;
1190
+ this.playerState = PlayerState.Error;
1191
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1476
1192
  return;
1477
1193
  }
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;
1194
+ this._addEventListeners();
1195
+ const speed = this._multiAnimationSettings[this._currentAnimation]?.speed ?? this.speed, direction = this._multiAnimationSettings[this._currentAnimation]?.direction ?? this.direction;
1196
+ // Set initial playback speed and direction
1197
+ this._lottieInstance.setSpeed(speed);
1198
+ this._lottieInstance.setDirection(direction);
1199
+ this._lottieInstance.setSubframe(Boolean(this.subframe));
1200
+ // Start playing if autoplay is enabled
1201
+ if (this.autoplay || this.animateOnScroll) {
1202
+ if (this.direction === -1) {
1203
+ this.seek('99%');
1204
+ }
1205
+ if (!('IntersectionObserver' in window)) {
1206
+ if (!this.animateOnScroll) {
1207
+ this.play();
1208
+ }
1209
+ this._playerState.visible = true;
1210
+ }
1211
+ this._addIntersectionObserver();
1486
1212
  }
1487
1213
  }
1488
1214
  /**
1489
- * Pause
1215
+ * Skip to next animation.
1216
+ */ next() {
1217
+ this._currentAnimation++;
1218
+ this._switchInstance();
1219
+ }
1220
+ /**
1221
+ * Pause.
1490
1222
  */ pause() {
1491
1223
  if (!this._lottieInstance) {
1492
1224
  return;
1493
1225
  }
1494
- if (this.playerState) {
1495
- this._playerState.prev = this.playerState;
1496
- }
1226
+ this._playerState.prev = this.playerState;
1497
1227
  try {
1498
1228
  this._lottieInstance.pause();
1499
1229
  this.dispatchEvent(new CustomEvent(PlayerEvents.Pause));
@@ -1502,44 +1232,88 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
1502
1232
  }
1503
1233
  }
1504
1234
  /**
1505
- * Stop
1506
- */ stop() {
1235
+ * Play.
1236
+ */ play() {
1507
1237
  if (!this._lottieInstance) {
1508
1238
  return;
1509
1239
  }
1510
- if (this.playerState) {
1511
- this._playerState.prev = this.playerState;
1512
- }
1513
- this._playerState.count = 0;
1240
+ this._playerState.prev = this.playerState;
1514
1241
  try {
1515
- this._lottieInstance.stop();
1516
- this.dispatchEvent(new CustomEvent(PlayerEvents.Stop));
1242
+ this._lottieInstance.play();
1243
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Play));
1517
1244
  } finally{
1518
- this.playerState = PlayerState.Stopped;
1245
+ this.playerState = PlayerState.Playing;
1519
1246
  }
1520
1247
  }
1521
1248
  /**
1522
- * Destroy animation and element
1523
- */ destroy() {
1524
- if (!this._lottieInstance) {
1249
+ * Skip to previous animation.
1250
+ */ prev() {
1251
+ this._currentAnimation--;
1252
+ this._switchInstance(true);
1253
+ }
1254
+ /**
1255
+ * Name: string, oldValue: string, newValue: string.
1256
+ */ propertyChangedCallback(name, _oldValue, value) {
1257
+ if (!this.shadow) {
1258
+ return;
1259
+ }
1260
+ 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');
1261
+ if (!(togglePlay instanceof HTMLButtonElement) || !(stop instanceof HTMLButtonElement) || !(next instanceof HTMLButtonElement) || !(prev instanceof HTMLButtonElement) || !(seeker instanceof HTMLInputElement) || !(progress instanceof HTMLProgressElement)) {
1262
+ return;
1263
+ }
1264
+ if (name === 'playerState') {
1265
+ togglePlay.dataset.active = (value === PlayerState.Playing || value === PlayerState.Paused).toString();
1266
+ stop.dataset.active = (value === PlayerState.Stopped).toString();
1267
+ if (value === PlayerState.Playing) {
1268
+ 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>`;
1269
+ } else {
1270
+ 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>`;
1271
+ }
1272
+ }
1273
+ if (name === '_seeker' && typeof value === 'number') {
1274
+ seeker.value = value.toString();
1275
+ seeker.ariaValueNow = value.toString();
1276
+ progress.value = value;
1277
+ }
1278
+ if (name === '_animations' && Array.isArray(value) && this._currentAnimation + 1 < value.length) {
1279
+ next.hidden = false;
1280
+ }
1281
+ if (name === '_currentAnimation' && typeof value === 'number') {
1282
+ if (value + 1 >= this._animations.length) {
1283
+ next.hidden = true;
1284
+ } else {
1285
+ next.hidden = false;
1286
+ }
1287
+ if (value) {
1288
+ prev.hidden = false;
1289
+ } else {
1290
+ prev.hidden = true;
1291
+ }
1292
+ }
1293
+ if (name === '_isSettingsOpen' && typeof value === 'boolean' && popover instanceof HTMLDivElement && convert instanceof HTMLButtonElement) {
1294
+ popover.hidden = !value;
1295
+ convert.hidden = this._isDotLottie;
1296
+ }
1297
+ }
1298
+ /**
1299
+ * Reload animation.
1300
+ */ async reload() {
1301
+ if (!this._lottieInstance || !this.src) {
1525
1302
  return;
1526
1303
  }
1527
- this.playerState = PlayerState.Destroyed;
1528
1304
  this._lottieInstance.destroy();
1529
- this._lottieInstance = null;
1530
- this.dispatchEvent(new CustomEvent(PlayerEvents.Destroyed));
1531
- this.remove();
1532
- document.removeEventListener('visibilitychange', this._onVisibilityChange);
1305
+ await this.load(this.src);
1533
1306
  }
1534
1307
  /**
1535
- * Seek to a given frame
1536
- * @param { number | string } value Frame to seek to
1308
+ * Seek to a given frame.
1309
+ *
1310
+ * @param value - Frame to seek to.
1537
1311
  */ seek(value) {
1538
1312
  if (!this._lottieInstance) {
1539
1313
  return;
1540
1314
  }
1541
1315
  // Extract frame number from either number or percentage value
1542
- const matches = value.toString().match(/^([0-9]+)(%?)$/);
1316
+ const matches = value.toString().match(/^(\d+)(%?)$/);
1543
1317
  if (!matches) {
1544
1318
  return;
1545
1319
  }
@@ -1557,7 +1331,63 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
1557
1331
  this._lottieInstance.pause();
1558
1332
  }
1559
1333
  /**
1560
- * Snapshot and download the current frame as SVG
1334
+ * Dynamically set count for loops.
1335
+ */ setCount(value) {
1336
+ this.count = value;
1337
+ }
1338
+ /**
1339
+ * Animation play direction.
1340
+ *
1341
+ * @param value - Animation direction.
1342
+ */ setDirection(value) {
1343
+ if (!this._lottieInstance) {
1344
+ return;
1345
+ }
1346
+ this._lottieInstance.setDirection(value);
1347
+ }
1348
+ /**
1349
+ * Set loop.
1350
+ *
1351
+ */ setLoop(value) {
1352
+ if (!this._lottieInstance) {
1353
+ return;
1354
+ }
1355
+ this._lottieInstance.setLoop(value);
1356
+ }
1357
+ /**
1358
+ * Set Multi-animation settings.
1359
+ *
1360
+ */ setMultiAnimationSettings(settings) {
1361
+ this._multiAnimationSettings = settings;
1362
+ }
1363
+ /**
1364
+ * Set playback segment.
1365
+ *
1366
+ */ setSegment(segment) {
1367
+ this._segment = segment;
1368
+ }
1369
+ /**
1370
+ * Set animation playback speed.
1371
+ *
1372
+ * @param value - Playback speed.
1373
+ */ setSpeed(value = 1) {
1374
+ if (!this._lottieInstance) {
1375
+ return;
1376
+ }
1377
+ this._lottieInstance.setSpeed(value);
1378
+ }
1379
+ /**
1380
+ * Toggles subframe, for more smooth animations.
1381
+ *
1382
+ * @param value - Whether animation uses subframe.
1383
+ */ setSubframe(value) {
1384
+ if (!this._lottieInstance) {
1385
+ return;
1386
+ }
1387
+ this._lottieInstance.setSubframe(value);
1388
+ }
1389
+ /**
1390
+ * Snapshot and download the current frame as SVG.
1561
1391
  */ snapshot(shouldDownload = true, name = 'AM Lottie') {
1562
1392
  try {
1563
1393
  if (!this.shadowRoot) {
@@ -1579,144 +1409,388 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
1579
1409
  });
1580
1410
  }
1581
1411
  return data;
1582
- } catch (err) {
1583
- console.error(err);
1412
+ } catch (error) {
1413
+ console.error(error);
1584
1414
  return null;
1585
1415
  }
1586
1416
  }
1587
- /**
1588
- * Toggles subframe, for more smooth animations
1589
- * @param { boolean } value Whether animation uses subframe
1590
- */ setSubframe(value) {
1417
+ /**
1418
+ * Stop.
1419
+ */ stop() {
1420
+ if (!this._lottieInstance) {
1421
+ return;
1422
+ }
1423
+ this._playerState.prev = this.playerState;
1424
+ this._playerState.count = 0;
1425
+ try {
1426
+ this._lottieInstance.stop();
1427
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Stop));
1428
+ } finally{
1429
+ this.playerState = PlayerState.Stopped;
1430
+ }
1431
+ }
1432
+ /**
1433
+ * Toggle Boomerang.
1434
+ */ toggleBoomerang() {
1435
+ const curr = this._multiAnimationSettings[this._currentAnimation];
1436
+ if (curr.mode !== undefined) {
1437
+ if (curr.mode === PlayMode.Normal) {
1438
+ curr.mode = PlayMode.Bounce;
1439
+ this._isBounce = true;
1440
+ return;
1441
+ }
1442
+ curr.mode = PlayMode.Normal;
1443
+ this._isBounce = false;
1444
+ return;
1445
+ }
1446
+ if (this.mode === PlayMode.Normal) {
1447
+ this.mode = PlayMode.Bounce;
1448
+ this._isBounce = true;
1449
+ return;
1450
+ }
1451
+ this.mode = PlayMode.Normal;
1452
+ this._isBounce = false;
1453
+ }
1454
+ /**
1455
+ * Toggle loop.
1456
+ */ toggleLoop() {
1457
+ const hasLoop = !this.loop;
1458
+ this.loop = hasLoop;
1459
+ this.setLoop(hasLoop);
1460
+ }
1461
+ /**
1462
+ * Toggle playing state.
1463
+ */ togglePlay() {
1464
+ if (!this._lottieInstance) {
1465
+ return;
1466
+ }
1467
+ const { currentFrame, playDirection, totalFrames } = this._lottieInstance;
1468
+ if (this.playerState === PlayerState.Playing) {
1469
+ this.pause();
1470
+ return;
1471
+ }
1472
+ if (this.playerState !== PlayerState.Completed) {
1473
+ this.play();
1474
+ return;
1475
+ }
1476
+ this.playerState = PlayerState.Playing;
1477
+ if (this._isBounce) {
1478
+ this.setDirection(playDirection * -1);
1479
+ this._lottieInstance.goToAndPlay(currentFrame, true);
1480
+ return;
1481
+ }
1482
+ if (playDirection === -1) {
1483
+ this._lottieInstance.goToAndPlay(totalFrames, true);
1484
+ return;
1485
+ }
1486
+ this._lottieInstance.goToAndPlay(0, true);
1487
+ }
1488
+ /**
1489
+ * Freeze animation.
1490
+ * This internal state pauses animation and is used to differentiate between
1491
+ * user requested pauses and component instigated pauses.
1492
+ */ _freeze() {
1493
+ if (!this._lottieInstance) {
1494
+ return;
1495
+ }
1496
+ this._playerState.prev = this.playerState;
1497
+ try {
1498
+ this._lottieInstance.pause();
1499
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Freeze));
1500
+ } finally{
1501
+ this.playerState = PlayerState.Frozen;
1502
+ }
1503
+ }
1504
+ /**
1505
+ * Handle blur.
1506
+ */ _handleBlur() {
1507
+ setTimeout(()=>{
1508
+ this._toggleSettings(false);
1509
+ }, 200);
1510
+ }
1511
+ /**
1512
+ * Handles click and drag actions on the progress track.
1513
+ *
1514
+ */ _handleSeekChange({ target }) {
1515
+ if (!(target instanceof HTMLInputElement) || !this._lottieInstance || isNaN(Number(target.value))) {
1516
+ return;
1517
+ }
1518
+ this.seek(Math.round(Number(target.value) / 100 * this._lottieInstance.totalFrames));
1519
+ }
1520
+ /**
1521
+ * Add event listeners.
1522
+ */ _addEventListeners() {
1523
+ this._toggleEventListeners('add');
1524
+ }
1525
+ /**
1526
+ * Add IntersectionObserver.
1527
+ */ _addIntersectionObserver() {
1528
+ if (!this._container || this._intersectionObserver || !('IntersectionObserver' in window)) {
1529
+ return;
1530
+ }
1531
+ this._intersectionObserver = new IntersectionObserver((entries)=>{
1532
+ const { length } = entries;
1533
+ for(let i = 0; i < length; i++){
1534
+ if (!entries[i].isIntersecting || document.hidden) {
1535
+ if (this.playerState === PlayerState.Playing) {
1536
+ this._freeze();
1537
+ }
1538
+ this._playerState.visible = false;
1539
+ continue;
1540
+ }
1541
+ if (!this.animateOnScroll && this.playerState === PlayerState.Frozen) {
1542
+ this.play();
1543
+ }
1544
+ if (!this._playerState.scrollY) {
1545
+ this._playerState.scrollY = scrollY;
1546
+ }
1547
+ this._playerState.visible = true;
1548
+ }
1549
+ });
1550
+ this._intersectionObserver.observe(this._container);
1551
+ }
1552
+ _complete() {
1553
+ if (!this._lottieInstance) {
1554
+ return;
1555
+ }
1556
+ if (this._animations.length > 1) {
1557
+ if (this._multiAnimationSettings[this._currentAnimation + 1]?.autoplay) {
1558
+ this.next();
1559
+ return;
1560
+ }
1561
+ if (this.loop && this._currentAnimation === this._animations.length - 1) {
1562
+ this._currentAnimation = 0;
1563
+ this._switchInstance();
1564
+ return;
1565
+ }
1566
+ }
1567
+ const { currentFrame, totalFrames } = this._lottieInstance;
1568
+ this._seeker = Math.round(currentFrame / totalFrames * 100);
1569
+ this.playerState = PlayerState.Completed;
1570
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Complete, {
1571
+ detail: {
1572
+ frame: currentFrame,
1573
+ seeker: this._seeker
1574
+ }
1575
+ }));
1576
+ }
1577
+ _dataFailed() {
1578
+ this.playerState = PlayerState.Error;
1579
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1580
+ }
1581
+ _dataReady() {
1582
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Load));
1583
+ }
1584
+ _DOMLoaded() {
1585
+ this._playerState.loaded = true;
1586
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Ready));
1587
+ }
1588
+ _enterFrame() {
1591
1589
  if (!this._lottieInstance) {
1592
1590
  return;
1593
1591
  }
1594
- this._lottieInstance.setSubframe(value);
1595
- }
1596
- /**
1597
- * Dynamically set count for loops
1598
- */ setCount(value) {
1599
- this.count = value;
1592
+ const { currentFrame, totalFrames } = this._lottieInstance;
1593
+ this._seeker = Math.round(currentFrame / totalFrames * 100);
1594
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Frame, {
1595
+ detail: {
1596
+ frame: currentFrame,
1597
+ seeker: this._seeker
1598
+ }
1599
+ }));
1600
1600
  }
1601
1601
  /**
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;
1602
+ * Get options from props.
1603
+ *
1604
+ */ _getOptions() {
1605
+ if (!this._container) {
1606
+ throw new Error('Container not rendered');
1608
1607
  }
1609
- if (this.playerState) {
1610
- this._playerState.prev = this.playerState;
1608
+ const preserveAspectRatio = this.preserveAspectRatio ?? aspectRatio(this.objectfit), currentAnimationSettings = this._multiAnimationSettings.length > 0 ? this._multiAnimationSettings[this._currentAnimation] : undefined, currentAnimationManifest = this._manifest?.animations[this._currentAnimation];
1609
+ // Loop
1610
+ let hasLoop = Boolean(this.loop);
1611
+ if (currentAnimationManifest?.loop !== undefined) {
1612
+ hasLoop = Boolean(currentAnimationManifest.loop);
1611
1613
  }
1612
- try {
1613
- this._lottieInstance.pause();
1614
- this.dispatchEvent(new CustomEvent(PlayerEvents.Freeze));
1615
- } finally{
1616
- this.playerState = PlayerState.Frozen;
1614
+ if (currentAnimationSettings?.loop !== undefined) {
1615
+ hasLoop = Boolean(currentAnimationSettings.loop);
1617
1616
  }
1618
- }
1619
- /**
1620
- * Reload animation
1621
- */ async reload() {
1622
- if (!this._lottieInstance || !this.src) {
1623
- return;
1617
+ // Autoplay
1618
+ let hasAutoplay = Boolean(this.autoplay);
1619
+ if (currentAnimationManifest?.autoplay !== undefined) {
1620
+ hasAutoplay = Boolean(currentAnimationManifest.autoplay);
1624
1621
  }
1625
- this._lottieInstance.destroy();
1626
- await this.load(this.src);
1622
+ if (currentAnimationSettings?.autoplay !== undefined) {
1623
+ hasAutoplay = Boolean(currentAnimationSettings.autoplay);
1624
+ }
1625
+ if (this.animateOnScroll) {
1626
+ hasAutoplay = false;
1627
+ }
1628
+ // Segment
1629
+ let initialSegment = this._segment;
1630
+ if (this._segment?.every((val)=>val > 0)) {
1631
+ initialSegment = [
1632
+ this._segment[0] - 1,
1633
+ this._segment[1] - 1
1634
+ ];
1635
+ }
1636
+ if (this._segment?.some((val)=>val < 0)) {
1637
+ initialSegment = undefined;
1638
+ }
1639
+ const options = {
1640
+ autoplay: hasAutoplay,
1641
+ container: this._container,
1642
+ initialSegment,
1643
+ loop: hasLoop,
1644
+ renderer: this.renderer,
1645
+ rendererSettings: {
1646
+ imagePreserveAspectRatio: preserveAspectRatio
1647
+ }
1648
+ };
1649
+ switch(this.renderer){
1650
+ case RendererType.SVG:
1651
+ {
1652
+ options.rendererSettings = {
1653
+ ...options.rendererSettings,
1654
+ hideOnTransparent: true,
1655
+ preserveAspectRatio,
1656
+ progressiveLoad: true
1657
+ };
1658
+ break;
1659
+ }
1660
+ case RendererType.Canvas:
1661
+ {
1662
+ options.rendererSettings = {
1663
+ ...options.rendererSettings,
1664
+ // @ts-expect-error TODO:
1665
+ clearCanvas: true,
1666
+ preserveAspectRatio,
1667
+ progressiveLoad: true
1668
+ };
1669
+ break;
1670
+ }
1671
+ case RendererType.HTML:
1672
+ {
1673
+ options.rendererSettings = {
1674
+ ...options.rendererSettings,
1675
+ hideOnTransparent: true
1676
+ };
1677
+ }
1678
+ }
1679
+ return options;
1627
1680
  }
1628
1681
  /**
1629
- * Set animation playback speed
1630
- * @param { number } value Playback speed
1631
- */ setSpeed(value = 1) {
1632
- if (!this._lottieInstance) {
1682
+ * Handle scroll.
1683
+ */ _handleScroll() {
1684
+ if (!this.animateOnScroll || !this._lottieInstance) {
1633
1685
  return;
1634
1686
  }
1635
- this._lottieInstance.setSpeed(value);
1636
- }
1637
- /**
1638
- * Animation play direction
1639
- * @param { AnimationDirection } value Animation direction
1640
- */ setDirection(value) {
1641
- if (!this._lottieInstance) {
1687
+ if (isServer()) {
1688
+ console.warn('DotLottie: Scroll animations might not work properly in a Server Side Rendering context. Try to wrap this in a client component.');
1642
1689
  return;
1643
1690
  }
1644
- this._lottieInstance.setDirection(value);
1691
+ if (this._playerState.visible) {
1692
+ if (this._playerState.scrollTimeout) {
1693
+ clearTimeout(this._playerState.scrollTimeout);
1694
+ }
1695
+ this._playerState.scrollTimeout = setTimeout(()=>{
1696
+ this.playerState = PlayerState.Paused;
1697
+ }, 400);
1698
+ 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;
1699
+ requestAnimationFrame(()=>{
1700
+ if (roundedScroll < (this._lottieInstance?.totalFrames ?? 0)) {
1701
+ this.playerState = PlayerState.Playing;
1702
+ this._lottieInstance?.goToAndStop(roundedScroll, true);
1703
+ } else {
1704
+ this.playerState = PlayerState.Paused;
1705
+ }
1706
+ });
1707
+ }
1645
1708
  }
1646
- /**
1647
- * Set loop
1648
- * @param { boolean } value
1649
- */ setLoop(value) {
1650
- if (!this._lottieInstance) {
1651
- return;
1709
+ _handleWindowBlur({ type }) {
1710
+ if (this.playerState === PlayerState.Playing && type === 'blur') {
1711
+ this._freeze();
1712
+ }
1713
+ if (this.playerState === PlayerState.Frozen && type === 'focus') {
1714
+ this.play();
1652
1715
  }
1653
- this._lottieInstance.setLoop(value);
1654
1716
  }
1655
- /**
1656
- * Toggle playing state
1657
- */ togglePlay() {
1717
+ _isLottie(json) {
1718
+ const mandatory = [
1719
+ 'v',
1720
+ 'ip',
1721
+ 'op',
1722
+ 'layers',
1723
+ 'fr',
1724
+ 'w',
1725
+ 'h'
1726
+ ];
1727
+ return mandatory.every((field)=>Object.hasOwn(json, field));
1728
+ }
1729
+ _loopComplete() {
1658
1730
  if (!this._lottieInstance) {
1659
1731
  return;
1660
1732
  }
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();
1733
+ const { playDirection, // firstFrame,
1734
+ totalFrames } = this._lottieInstance, inPoint = this._segment ? this._segment[0] : 0, outPoint = this._segment ? this._segment[0] : totalFrames;
1735
+ if (this.count) {
1736
+ if (this._isBounce) {
1737
+ this._playerState.count += 0.5;
1738
+ } else {
1739
+ this._playerState.count += 1;
1740
+ }
1741
+ if (this._playerState.count >= this.count) {
1742
+ this.setLoop(false);
1743
+ this.playerState = PlayerState.Completed;
1744
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Complete));
1745
+ return;
1746
+ }
1667
1747
  }
1668
- this.playerState = PlayerState.Playing;
1748
+ this.dispatchEvent(new CustomEvent(PlayerEvents.Loop));
1669
1749
  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);
1750
+ this._lottieInstance.goToAndStop(playDirection === -1 ? inPoint : outPoint * 0.99, true);
1751
+ this._lottieInstance.setDirection(playDirection * -1);
1752
+ return setTimeout(()=>{
1753
+ if (!this.animateOnScroll) {
1754
+ this._lottieInstance?.play();
1755
+ }
1756
+ }, this.intermission);
1675
1757
  }
1676
- return this._lottieInstance.goToAndPlay(0, true);
1758
+ this._lottieInstance.goToAndStop(playDirection === -1 ? outPoint * 0.99 : inPoint, true);
1759
+ return setTimeout(()=>{
1760
+ if (!this.animateOnScroll) {
1761
+ this._lottieInstance?.play();
1762
+ }
1763
+ }, this.intermission);
1677
1764
  }
1678
1765
  /**
1679
- * Toggle loop
1680
- */ toggleLoop() {
1681
- const val = !this.loop;
1682
- this.loop = val;
1683
- this.setLoop(val);
1766
+ * Handle MouseEnter.
1767
+ */ _mouseEnter() {
1768
+ if (this.hover && this.playerState !== PlayerState.Playing) {
1769
+ this.play();
1770
+ }
1684
1771
  }
1685
1772
  /**
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;
1773
+ * Handle MouseLeave.
1774
+ */ _mouseLeave() {
1775
+ if (this.hover && this.playerState === PlayerState.Playing) {
1776
+ this.stop();
1703
1777
  }
1704
- this.mode = PlayMode.Normal;
1705
- this._isBounce = false;
1706
1778
  }
1707
1779
  /**
1708
- * Toggle show Settings
1709
- */ _toggleSettings(flag) {
1710
- if (flag === undefined) {
1711
- this._isSettingsOpen = !this._isSettingsOpen;
1780
+ * Handle visibility change events.
1781
+ */ _onVisibilityChange() {
1782
+ if (document.hidden && this.playerState === PlayerState.Playing) {
1783
+ this._freeze();
1712
1784
  return;
1713
1785
  }
1714
- this._isSettingsOpen = flag;
1786
+ if (this.playerState === PlayerState.Frozen) {
1787
+ this.play();
1788
+ }
1715
1789
  }
1716
1790
  /**
1717
- * Handle blur
1718
- */ _handleBlur() {
1719
- setTimeout(()=>this._toggleSettings(false), 200);
1791
+ * Remove event listeners.
1792
+ */ _removeEventListeners() {
1793
+ this._toggleEventListeners('remove');
1720
1794
  }
1721
1795
  _switchInstance(isPrevious = false) {
1722
1796
  // Bail early if there is not animation to play
@@ -1730,82 +1804,85 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
1730
1804
  }
1731
1805
  // Re-initialize lottie player
1732
1806
  // @ts-expect-error TODO:
1733
- this._lottieInstance = Lottie.default.loadAnimation({
1807
+ this._lottieInstance = Lottie.loadAnimation({
1734
1808
  ...this._getOptions(),
1735
1809
  animationData: this._animations[this._currentAnimation]
1736
1810
  });
1737
1811
  // Check play mode for current animation
1738
- if (this._multiAnimationSettings?.[this._currentAnimation]?.mode) {
1812
+ if (this._multiAnimationSettings[this._currentAnimation]?.mode) {
1739
1813
  this._isBounce = this._multiAnimationSettings[this._currentAnimation].mode === PlayMode.Bounce;
1740
1814
  }
1741
1815
  // Remove event listeners to new Lottie instance, and add new
1742
1816
  this._removeEventListeners();
1743
1817
  this._addEventListeners();
1744
1818
  this.dispatchEvent(new CustomEvent(isPrevious ? PlayerEvents.Previous : PlayerEvents.Next));
1745
- if (this._multiAnimationSettings?.[this._currentAnimation]?.autoplay ?? this.autoplay) {
1819
+ if (this._multiAnimationSettings[this._currentAnimation]?.autoplay ?? this.autoplay) {
1746
1820
  if (this.animateOnScroll) {
1747
- this._lottieInstance?.goToAndStop(0, true);
1821
+ this._lottieInstance.goToAndStop(0, true);
1748
1822
  this.playerState = PlayerState.Paused;
1749
1823
  return;
1750
1824
  }
1751
- this._lottieInstance?.goToAndPlay(0, true);
1825
+ this._lottieInstance.goToAndPlay(0, true);
1752
1826
  this.playerState = PlayerState.Playing;
1753
1827
  return;
1754
1828
  }
1755
- this._lottieInstance?.goToAndStop(0, true);
1829
+ this._lottieInstance.goToAndStop(0, true);
1756
1830
  this.playerState = PlayerState.Stopped;
1757
- } catch (err) {
1758
- this._errorMessage = handleErrors(err).message;
1831
+ } catch (error) {
1832
+ this._errorMessage = handleErrors(error).message;
1759
1833
  this.playerState = PlayerState.Error;
1760
1834
  this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
1761
1835
  }
1762
1836
  }
1763
1837
  /**
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
- });
1838
+ * Toggle event listeners.
1839
+ */ _toggleEventListeners(action) {
1840
+ const method = action === 'add' ? 'addEventListener' : 'removeEventListener';
1841
+ if (this._lottieInstance) {
1842
+ this._lottieInstance[method]('enterFrame', this._enterFrame);
1843
+ this._lottieInstance[method]('complete', this._complete);
1844
+ this._lottieInstance[method]('loopComplete', this._loopComplete);
1845
+ this._lottieInstance[method]('DOMLoaded', this._DOMLoaded);
1846
+ this._lottieInstance[method]('data_ready', this._dataReady);
1847
+ this._lottieInstance[method]('data_failed', this._dataFailed);
1782
1848
  }
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
1849
+ if (this._container && this.hover) {
1850
+ this._container[method]('mouseenter', this._mouseEnter);
1851
+ this._container[method]('mouseleave', this._mouseLeave);
1852
+ }
1853
+ window[method]('focus', this._handleWindowBlur, {
1854
+ capture: false,
1855
+ passive: true
1856
+ });
1857
+ window[method]('blur', this._handleWindowBlur, {
1858
+ capture: false,
1859
+ passive: true
1791
1860
  });
1861
+ if (this.animateOnScroll) {
1862
+ window[method]('scroll', this._handleScroll, {
1863
+ capture: true,
1864
+ passive: true
1865
+ });
1866
+ }
1792
1867
  }
1793
1868
  /**
1794
- * Return the styles for the component
1795
- */ static get styles() {
1796
- const styleSheet = new CSSStyleSheet();
1797
- styleSheet.replace(css_248z);
1798
- return styleSheet;
1869
+ * Toggle show Settings.
1870
+ */ _toggleSettings(flag) {
1871
+ if (flag === undefined) {
1872
+ this._isSettingsOpen = !this._isSettingsOpen;
1873
+ return;
1874
+ }
1875
+ this._isSettingsOpen = flag;
1799
1876
  }
1800
1877
  }
1801
1878
 
1802
1879
  /**
1803
- * Expose DotLottiePlayer class as global variable
1804
- * @returns { DotLottiePlayer }
1880
+ * Expose DotLottiePlayer class as global variable.
1881
+ *
1805
1882
  */ globalThis.dotLottiePlayer = ()=>new DotLottiePlayer();
1806
1883
  const tagName = 'dotlottie-player';
1807
1884
  if (!isServer()) {
1808
- customElements.define('dotlottie-player', DotLottiePlayer);
1885
+ customElements.define(tagName, DotLottiePlayer);
1809
1886
  }
1810
1887
 
1811
1888
  export { PlayMode, PlayerEvents, PlayerState, DotLottiePlayer as default, tagName };