@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 +2 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +209 -206
- package/dist/unpkg.js +2 -2
- package/package.json +1 -1
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.
|
|
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.
|
|
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,
|
|
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
|
-
|
|
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
|
|
222
|
-
|
|
223
|
-
|
|
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
|
|
210
|
+
return PreserveAspectRatio$1.Contain;
|
|
260
211
|
}
|
|
261
|
-
case
|
|
262
|
-
case 'jpeg':
|
|
212
|
+
case ObjectFit.Cover:
|
|
263
213
|
{
|
|
264
|
-
return
|
|
214
|
+
return PreserveAspectRatio$1.Cover;
|
|
265
215
|
}
|
|
266
|
-
case
|
|
267
|
-
case 'gif':
|
|
268
|
-
case 'webp':
|
|
269
|
-
case 'avif':
|
|
216
|
+
case ObjectFit.Fill:
|
|
270
217
|
{
|
|
271
|
-
return
|
|
218
|
+
return PreserveAspectRatio$1.Initial;
|
|
272
219
|
}
|
|
273
|
-
case
|
|
274
|
-
case 'mpeg':
|
|
275
|
-
case 'wav':
|
|
220
|
+
case ObjectFit.None:
|
|
276
221
|
{
|
|
277
|
-
return
|
|
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
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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
|
-
},
|
|
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
|
-
*/
|
|
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
|
-
|
|
470
|
-
|
|
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
|
-
|
|
495
|
-
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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
|
|
588
|
-
error.status = result.status;
|
|
591
|
+
const error = new Error(result.statusText);
|
|
589
592
|
throw error;
|
|
590
593
|
}
|
|
591
594
|
/**
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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
|
/**
|