@aarsteinmedia/dotlottie-player 5.1.9 → 5.1.10

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/CHANGELOG.md CHANGED
@@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  Changelog was only added since [3.2.3], so it's not exhaustive. [Please report any missing noteable changes to us](https://github.com/aarsteinmedia/dotlottie-player/issues), and we'll add them promptly.
9
9
 
10
- ## [5.1.9] - 05-06-2025
10
+ ## [5.1.10] - 05-06-2025
11
11
 
12
12
  ### Changed
13
13
 
@@ -252,7 +252,7 @@ Changelog was only added since [3.2.3], so it's not exhaustive. [Please report a
252
252
  - Removed dependencies
253
253
  - `@lit`
254
254
 
255
- [5.1.9]: https://www.npmjs.com/package/@aarsteinmedia/dotlottie-player/v/5.1.9
255
+ [5.1.10]: https://www.npmjs.com/package/@aarsteinmedia/dotlottie-player/v/5.1.10
256
256
  [5.1.4]: https://www.npmjs.com/package/@aarsteinmedia/dotlottie-player/v/5.1.4
257
257
  [5.1.3]: https://www.npmjs.com/package/@aarsteinmedia/dotlottie-player/v/5.1.3
258
258
  [5.1.0]: https://www.npmjs.com/package/@aarsteinmedia/dotlottie-player/v/5.1.0
package/dist/index.d.ts CHANGED
@@ -59,6 +59,10 @@ declare abstract class PropertyCallbackElement extends HTMLElement {
59
59
  propertyChangedCallback(_name: string, _oldValue: unknown, _value: unknown): void;
60
60
  }
61
61
 
62
+ declare function renderControls(this: DotLottiePlayer): void;
63
+
64
+ declare function renderPlayer(this: DotLottiePlayer): Promise<void>;
65
+
62
66
  declare enum PlayerState {
63
67
  Completed = "completed",
64
68
  Destroyed = "destroyed",
@@ -101,10 +105,6 @@ declare enum RendererType {
101
105
  SVG = "svg"
102
106
  }
103
107
 
104
- declare function renderControls(this: DotLottiePlayer): void;
105
-
106
- declare function renderPlayer(this: DotLottiePlayer): Promise<void>;
107
-
108
108
  declare class DotLottiePlayer extends PropertyCallbackElement {
109
109
  static get observedAttributes(): string[];
110
110
  static get observedProperties(): string[];
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isServer, createElementID, PreserveAspectRatio as PreserveAspectRatio$1 } from '@aarsteinmedia/lottie-web/utils';
2
2
  import Lottie from '@aarsteinmedia/lottie-web';
3
- import { strToU8, strFromU8, zip, unzip as unzip$1 } from 'fflate';
3
+ import { strToU8, zip, strFromU8, unzip as unzip$1 } from 'fflate';
4
4
 
5
5
  /**
6
6
  * Credit to: Leonardo Favre https://github.com/leofavre/observed-properties.
@@ -61,6 +61,8 @@ if (isServer()) {
61
61
  }
62
62
  }
63
63
 
64
+ 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";
65
+
64
66
  var ObjectFit = /*#__PURE__*/ function(ObjectFit) {
65
67
  ObjectFit["Contain"] = "contain";
66
68
  ObjectFit["Cover"] = "cover";
@@ -116,8 +118,6 @@ var RendererType = /*#__PURE__*/ function(RendererType) {
116
118
  return RendererType;
117
119
  }({});
118
120
 
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
121
  /**
122
122
  * Render Controls.
123
123
  */ function renderControls() {
@@ -196,186 +196,39 @@ var css_248z = "* {\n box-sizing: border-box;\n}\n\n:host {\n --lottie-player-
196
196
  this.shadow.appendChild(this.template.content.cloneNode(true));
197
197
  }
198
198
 
199
- class CustomError extends Error {
200
- }
201
- /**
202
- * Methods used locally and exported.
203
- */ const getManifest = (unzipped)=>{
204
- const file = strFromU8(unzipped['manifest.json'], false), manifest = JSON.parse(file);
205
- if (!('animations' in manifest)) {
206
- throw new Error('Manifest not found');
207
- }
208
- if (manifest.animations.length === 0) {
209
- throw new Error('No animations listed in manifest');
210
- }
211
- return manifest;
212
- };
213
- /**
214
- * Methods used only locally.
215
- */ const hasExt = (path)=>{
199
+ const hasExt = (path)=>{
216
200
  const lastDotIndex = path?.split('/').pop()?.lastIndexOf('.');
217
201
  return (lastDotIndex ?? 0) > 1 && path && path.length - 1 > (lastDotIndex ?? 0);
218
202
  };
219
203
  /**
220
204
  * Get extension from filename, URL or path.
221
- */ const getExt = (str)=>{
222
- if (typeof str !== 'string' || !str || !hasExt(str)) {
223
- return;
224
- }
225
- return str.split('.').pop()?.toLowerCase();
226
- };
227
- const unzip = async (resp)=>{
228
- const u8 = new Uint8Array(await resp.arrayBuffer()), unzipped = await new Promise((resolve, reject)=>{
229
- unzip$1(u8, (err, file)=>{
230
- if (err) {
231
- reject(err);
232
- }
233
- resolve(file);
234
- });
235
- });
236
- return unzipped;
237
- }, getArrayBuffer = async (zippable)=>{
238
- const arrayBuffer = await new Promise((resolve, reject)=>{
239
- zip(zippable, {
240
- level: 9
241
- }, (err, data)=>{
242
- if (err) {
243
- reject(err);
244
- return;
245
- }
246
- if (!(data.buffer instanceof ArrayBuffer)) {
247
- reject(new Error('Data is not transferable'));
248
- return;
249
- }
250
- resolve(data.buffer);
251
- });
252
- });
253
- return arrayBuffer;
254
- }, getMimeFromExt = (ext)=>{
255
- switch(ext){
256
- case 'svg':
257
- case 'svg+xml':
205
+ */ const aspectRatio = (objectFit)=>{
206
+ switch(objectFit){
207
+ case ObjectFit.Contain:
208
+ case ObjectFit.ScaleDown:
258
209
  {
259
- return 'image/svg+xml';
210
+ return PreserveAspectRatio$1.Contain;
260
211
  }
261
- case 'jpg':
262
- case 'jpeg':
212
+ case ObjectFit.Cover:
263
213
  {
264
- return 'image/jpeg';
214
+ return PreserveAspectRatio$1.Cover;
265
215
  }
266
- case 'png':
267
- case 'gif':
268
- case 'webp':
269
- case 'avif':
216
+ case ObjectFit.Fill:
270
217
  {
271
- return `image/${ext}`;
218
+ return PreserveAspectRatio$1.Initial;
272
219
  }
273
- case 'mp3':
274
- case 'mpeg':
275
- case 'wav':
220
+ case ObjectFit.None:
276
221
  {
277
- return `audio/${ext}`;
222
+ return PreserveAspectRatio$1.None;
278
223
  }
279
224
  default:
280
225
  {
281
- return '';
282
- }
283
- }
284
- }, 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)=>{
285
- if (!str) {
286
- return false;
287
- }
288
- const regex = /^(?:[0-9a-z+/]{4})*(?:[0-9a-z+/]{2}==|[0-9a-z+/]{3}=)?$/i;
289
- return regex.test(parseBase64(str));
290
- }, resolveAssets = async (unzipped, assets)=>{
291
- if (!Array.isArray(assets)) {
292
- return;
293
- }
294
- const toResolve = [], { length } = assets;
295
- for(let i = 0; i < length; i++){
296
- if (!isAudio(assets[i]) && !isImage(assets[i])) {
297
- continue;
298
- }
299
- const type = isImage(assets[i]) ? 'images' : 'audio', u8 = unzipped?.[`${type}/${assets[i].p}`];
300
- if (!u8) {
301
- continue;
302
- }
303
- toResolve.push(new Promise((resolveAsset)=>{
304
- let assetB64;
305
- if (isServer()) {
306
- assetB64 = Buffer.from(u8).toString('base64');
307
- } else {
308
- let result = '';
309
- const { length: jLen } = u8;
310
- for(let j = 0; j < jLen; j++){
311
- result += String.fromCharCode(u8[j]);
312
- }
313
- assetB64 = btoa(result);
314
- }
315
- assets[i].p = assets[i].p?.startsWith('data:') || isBase64(assets[i].p) ? assets[i].p : `data:${getMimeFromExt(getExt(assets[i].p))};base64,${assetB64}`;
316
- assets[i].e = 1;
317
- assets[i].u = '';
318
- resolveAsset();
319
- }));
320
- }
321
- await Promise.all(toResolve);
322
- }, prepareString = (str)=>str.replaceAll(new RegExp(/"""/, 'g'), '""').replaceAll(/(["'])(.*?)\1/g, (_match, quote, content)=>{
323
- const replacedContent = content.replaceAll(/[^\w\s.#]/g, '');
324
- return `${quote}${replacedContent}${quote}`;
325
- }), fileToBase64 = async (url)=>{
326
- const response = await fetch(url), blob = await response.blob();
327
- return new Promise((resolve, reject)=>{
328
- try {
329
- const reader = new FileReader();
330
- reader.onload = ()=>{
331
- if (typeof reader.result === 'string') {
332
- resolve(reader.result);
333
- return;
334
- }
335
- reject(new Error('Could not create bas64'));
336
- };
337
- reader.readAsDataURL(blob);
338
- } catch (error) {
339
- reject(error);
340
- }
341
- });
342
- }, getLottieJSON = async (resp)=>{
343
- const unzipped = await unzip(resp), manifest = getManifest(unzipped), data = [], toResolve = [], { length } = manifest.animations;
344
- /**
345
- * Check whether Lottie animations folder is abbreviated.
346
- */ let animationsFolder = 'animations';
347
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
348
- if (unzipped[`a/${manifest.animations[0].id}.json`]) {
349
- animationsFolder = 'a';
350
- }
351
- for(let i = 0; i < length; i++){
352
- const str = strFromU8(unzipped[`${animationsFolder}/${manifest.animations[i].id}.json`]), lottie = JSON.parse(prepareString(str));
353
- // Handle Expressions
354
- const { length: jLen } = lottie.layers;
355
- for(let j = 0; j < jLen; j++){
356
- const { ks: shape } = lottie.layers[j], props = Object.keys(shape), { length: pLen } = props;
357
- for(let p = 0; p < pLen; p++){
358
- const { e: isEncoded, x: expression } = shape[props[p]];
359
- if (!expression || !isEncoded) {
360
- continue;
361
- }
362
- // Base64 Decode to handle compression
363
- // @ts-expect-error
364
- lottie.layers[j].ks[props[p]].x = atob(expression);
226
+ return PreserveAspectRatio$1.Contain;
365
227
  }
366
- }
367
- toResolve.push(resolveAssets(unzipped, lottie.assets));
368
- data.push(lottie);
369
228
  }
370
- await Promise.all(toResolve);
371
- return {
372
- data,
373
- manifest
374
- };
375
- };
376
- /**
377
- * Download file, either SVG or dotLottie.
378
- */ const download = (data, options)=>{
229
+ }, /**
230
+ * Download file, either SVG or dotLottie.
231
+ */ download = (data, options)=>{
379
232
  const blob = new Blob([
380
233
  data
381
234
  ], {
@@ -390,6 +243,11 @@ const unzip = async (resp)=>{
390
243
  link.remove();
391
244
  URL.revokeObjectURL(dataURL);
392
245
  }, 1000);
246
+ }, getExt = (str)=>{
247
+ if (typeof str !== 'string' || !str || !hasExt(str)) {
248
+ return;
249
+ }
250
+ return str.split('.').pop()?.toLowerCase();
393
251
  }, /**
394
252
  * Parse URL to get filename.
395
253
  *
@@ -411,31 +269,7 @@ const unzip = async (resp)=>{
411
269
  return `${getFilename(str)}.${ext}`;
412
270
  }
413
271
  return `${str}.${ext}`;
414
- }, aspectRatio = (objectFit)=>{
415
- switch(objectFit){
416
- case ObjectFit.Contain:
417
- case ObjectFit.ScaleDown:
418
- {
419
- return PreserveAspectRatio$1.Contain;
420
- }
421
- case ObjectFit.Cover:
422
- {
423
- return PreserveAspectRatio$1.Cover;
424
- }
425
- case ObjectFit.Fill:
426
- {
427
- return PreserveAspectRatio$1.Initial;
428
- }
429
- case ObjectFit.None:
430
- {
431
- return PreserveAspectRatio$1.None;
432
- }
433
- default:
434
- {
435
- return PreserveAspectRatio$1.Contain;
436
- }
437
- }
438
- }, /**
272
+ }, parseBase64 = (str)=>str.slice(Math.max(0, str.indexOf(',') + 1)), /**
439
273
  * Convert Base64 encoded string to Uint8Array.
440
274
  *
441
275
  * @param str - Base64 encoded string.
@@ -457,17 +291,54 @@ const unzip = async (resp)=>{
457
291
  }
458
292
  }
459
293
  return res;
460
- }, /**
294
+ }, 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, frameOutput = (frame)=>((frame ?? 0) + 1).toString().padStart(3, '0');
295
+
296
+ const getArrayBuffer = async (zippable)=>{
297
+ const arrayBuffer = await new Promise((resolve, reject)=>{
298
+ zip(zippable, {
299
+ level: 9
300
+ }, (err, data)=>{
301
+ if (err) {
302
+ reject(err);
303
+ return;
304
+ }
305
+ if (!(data.buffer instanceof ArrayBuffer)) {
306
+ reject(new Error('Data is not transferable'));
307
+ return;
308
+ }
309
+ resolve(data.buffer);
310
+ });
311
+ });
312
+ return arrayBuffer;
313
+ }, fileToBase64 = async (url)=>{
314
+ const response = await fetch(url), blob = await response.blob();
315
+ return new Promise((resolve, reject)=>{
316
+ try {
317
+ const reader = new FileReader();
318
+ reader.onload = ()=>{
319
+ if (typeof reader.result === 'string') {
320
+ resolve(reader.result);
321
+ return;
322
+ }
323
+ reject(new Error('Could not create bas64'));
324
+ };
325
+ reader.readAsDataURL(blob);
326
+ } catch (error) {
327
+ reject(error);
328
+ }
329
+ });
330
+ };
331
+ /**
461
332
  * Convert a JSON Lottie to dotLottie or combine several animations and download new dotLottie file in your browser.
462
- */ createDotLottie = async ({ animations = [], fileName, manifest, shouldDownload = true })=>{
333
+ */ async function createDotLottie({ animations = [], fileName, manifest, shouldDownload = true }) {
463
334
  try {
464
335
  // Input validation
465
336
  if (animations.length === 0 || !manifest) {
466
337
  throw new Error(`Missing or malformed required parameter(s):\n ${animations.length > 0 ? '- manifest\n' : ''} ${manifest ? '- animations\n' : ''}`);
467
338
  }
468
339
  const manifestCompressionLevel = 0, animationCompressionLevel = 9, /**
469
- * Prepare the dotLottie file.
470
- */ name = addExt('lottie', fileName) || `${createElementID()}.lottie`, dotlottie = {
340
+ * Prepare the dotLottie file.
341
+ */ name = addExt('lottie', fileName) || `${createElementID()}.lottie`, dotlottie = {
471
342
  'manifest.json': [
472
343
  strToU8(JSON.stringify(manifest), true),
473
344
  {
@@ -491,8 +362,8 @@ const unzip = async (resp)=>{
491
362
  }
492
363
  // Original asset.id caused issues with multianimations
493
364
  const assetId = createElementID(), isEncoded = file.startsWith('data:'), ext = isEncoded ? getExtFromB64(file) : getExt(file), /**
494
- * Check if the asset is already base64-encoded. If not, get path, fetch it, and encode it.
495
- */ dataURL = isEncoded ? file : await fileToBase64(path ? path.endsWith('/') && `${path}${file}` || `${path}/${file}` : file);
365
+ * Check if the asset is already base64-encoded. If not, get path, fetch it, and encode it.
366
+ */ dataURL = isEncoded ? file : await fileToBase64(path ? path.endsWith('/') && `${path}${file}` || `${path}/${file}` : file);
496
367
  // Asset is encoded
497
368
  // eslint-disable-next-line require-atomic-updates
498
369
  animations[i].assets[j].e = 1;
@@ -545,7 +416,9 @@ const unzip = async (resp)=>{
545
416
  console.error(handleErrors(error).message);
546
417
  return null;
547
418
  }
548
- }, createJSON = ({ animation, fileName, shouldDownload })=>{
419
+ }
420
+
421
+ function createJSON({ animation, fileName, shouldDownload }) {
549
422
  try {
550
423
  if (!animation) {
551
424
  throw new Error('createJSON: Missing or malformed required parameter(s):\n - animation\n\'');
@@ -563,7 +436,138 @@ const unzip = async (resp)=>{
563
436
  console.error(handleErrors(error).message);
564
437
  return null;
565
438
  }
566
- }, frameOutput = (frame)=>((frame ?? 0) + 1).toString().padStart(3, '0'), getAnimationData = async (input)=>{
439
+ }
440
+
441
+ const getMimeFromExt = (ext)=>{
442
+ switch(ext){
443
+ case 'svg':
444
+ case 'svg+xml':
445
+ {
446
+ return 'image/svg+xml';
447
+ }
448
+ case 'jpg':
449
+ case 'jpeg':
450
+ {
451
+ return 'image/jpeg';
452
+ }
453
+ case 'png':
454
+ case 'gif':
455
+ case 'webp':
456
+ case 'avif':
457
+ {
458
+ return `image/${ext}`;
459
+ }
460
+ case 'mp3':
461
+ case 'mpeg':
462
+ case 'wav':
463
+ {
464
+ return `audio/${ext}`;
465
+ }
466
+ default:
467
+ {
468
+ return '';
469
+ }
470
+ }
471
+ }, isBase64 = (str)=>{
472
+ if (!str) {
473
+ return false;
474
+ }
475
+ const regex = /^(?:[0-9a-z+/]{4})*(?:[0-9a-z+/]{2}==|[0-9a-z+/]{3}=)?$/i;
476
+ return regex.test(parseBase64(str));
477
+ };
478
+ async function resolveAssets(unzipped, assets) {
479
+ if (!Array.isArray(assets)) {
480
+ return;
481
+ }
482
+ const toResolve = [], { length } = assets;
483
+ for(let i = 0; i < length; i++){
484
+ if (!isAudio(assets[i]) && !isImage(assets[i])) {
485
+ continue;
486
+ }
487
+ const type = isImage(assets[i]) ? 'images' : 'audio', u8 = unzipped?.[`${type}/${assets[i].p}`];
488
+ if (!u8) {
489
+ continue;
490
+ }
491
+ toResolve.push(new Promise((resolveAsset)=>{
492
+ let assetB64;
493
+ if (isServer()) {
494
+ assetB64 = Buffer.from(u8).toString('base64');
495
+ } else {
496
+ let result = '';
497
+ const { length: jLen } = u8;
498
+ for(let j = 0; j < jLen; j++){
499
+ result += String.fromCharCode(u8[j]);
500
+ }
501
+ assetB64 = btoa(result);
502
+ }
503
+ assets[i].p = assets[i].p?.startsWith('data:') || isBase64(assets[i].p) ? assets[i].p : `data:${getMimeFromExt(getExt(assets[i].p))};base64,${assetB64}`;
504
+ assets[i].e = 1;
505
+ assets[i].u = '';
506
+ resolveAsset();
507
+ }));
508
+ }
509
+ await Promise.all(toResolve);
510
+ }
511
+
512
+ const unzip = async (resp)=>{
513
+ const u8 = new Uint8Array(await resp.arrayBuffer()), unzipped = await new Promise((resolve, reject)=>{
514
+ unzip$1(u8, (err, file)=>{
515
+ if (err) {
516
+ reject(err);
517
+ }
518
+ resolve(file);
519
+ });
520
+ });
521
+ return unzipped;
522
+ }, getManifest = (unzipped)=>{
523
+ const file = strFromU8(unzipped['manifest.json'], false), manifest = JSON.parse(file);
524
+ if (!('animations' in manifest)) {
525
+ throw new Error('Manifest not found');
526
+ }
527
+ if (manifest.animations.length === 0) {
528
+ throw new Error('No animations listed in manifest');
529
+ }
530
+ return manifest;
531
+ }, prepareString = (str)=>str.replaceAll(new RegExp(/"""/, 'g'), '""').replaceAll(/(["'])(.*?)\1/g, (_match, quote, content)=>{
532
+ const replacedContent = content.replaceAll(/[^\w\s.#]/g, '');
533
+ return `${quote}${replacedContent}${quote}`;
534
+ });
535
+ async function getLottieJSON(resp) {
536
+ const unzipped = await unzip(resp), manifest = getManifest(unzipped), data = [], toResolve = [], { length } = manifest.animations;
537
+ /**
538
+ * Check whether Lottie animations folder is abbreviated.
539
+ */ let animationsFolder = 'animations';
540
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
541
+ if (unzipped[`a/${manifest.animations[0].id}.json`]) {
542
+ animationsFolder = 'a';
543
+ }
544
+ for(let i = 0; i < length; i++){
545
+ const str = strFromU8(unzipped[`${animationsFolder}/${manifest.animations[i].id}.json`]), lottie = JSON.parse(prepareString(str));
546
+ // Handle Expressions
547
+ const { length: jLen } = lottie.layers;
548
+ for(let j = 0; j < jLen; j++){
549
+ const { ks: shape } = lottie.layers[j], props = Object.keys(shape), { length: pLen } = props;
550
+ for(let p = 0; p < pLen; p++){
551
+ const { e: isEncoded, x: expression } = shape[props[p]];
552
+ if (!expression || !isEncoded) {
553
+ continue;
554
+ }
555
+ // Base64 Decode to handle compression
556
+ // @ts-expect-error
557
+ lottie.layers[j].ks[props[p]].x = atob(expression);
558
+ }
559
+ }
560
+ toResolve.push(resolveAssets(unzipped, lottie.assets));
561
+ data.push(lottie);
562
+ }
563
+ await Promise.all(toResolve);
564
+ return {
565
+ data,
566
+ manifest
567
+ };
568
+ }
569
+
570
+ async function getAnimationData(input) {
567
571
  try {
568
572
  if (!input || typeof input !== 'string' && typeof input !== 'object') {
569
573
  throw new Error('Broken file or invalid file format');
@@ -584,15 +588,14 @@ const unzip = async (resp)=>{
584
588
  }
585
589
  });
586
590
  if (!result.ok) {
587
- const error = new CustomError(result.statusText);
588
- error.status = result.status;
591
+ const error = new Error(result.statusText);
589
592
  throw error;
590
593
  }
591
594
  /**
592
- * Check if file is JSON, first by parsing headers for content-type,
593
- * than by parsing filename, then – if filename has no extension – by
594
- * cloning the response and parsing response for content.
595
- */ let isJSON = true;
595
+ * Check if file is JSON, first by parsing headers for content-type,
596
+ * than by parsing filename, then – if filename has no extension – by
597
+ * cloning the response and parsing response for content.
598
+ */ let isJSON = true;
596
599
  const contentType = result.headers.get('content-type');
597
600
  if (contentType === 'application/zip+dotlottie') {
598
601
  isJSON = false;
@@ -636,7 +639,7 @@ const unzip = async (resp)=>{
636
639
  manifest: null
637
640
  };
638
641
  }
639
- };
642
+ }
640
643
 
641
644
  const generator = '@aarsteinmedia/dotlottie-player';
642
645
  /**