@aarsteinmedia/dotlottie-player 5.2.3 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -2
- package/custom-elements.json +33 -42
- package/dist/index.d.ts +11 -41
- package/dist/index.js +180 -596
- package/dist/unpkg.js +69 -7
- package/package.json +14 -17
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { isServer,
|
|
2
|
-
export { PlayerEvents } from '@aarsteinmedia/lottie-web/utils';
|
|
1
|
+
import { isServer, PlayMode, PreserveAspectRatio, namespaceSVG, RendererType, createElementID, PlayerEvents, download, getFilename } from '@aarsteinmedia/lottie-web/utils';
|
|
2
|
+
export { PlayMode, PlayerEvents } from '@aarsteinmedia/lottie-web/utils';
|
|
3
3
|
import Lottie from '@aarsteinmedia/lottie-web';
|
|
4
|
-
import {
|
|
4
|
+
import { convert, addAnimation, getAnimationData } from '@aarsteinmedia/lottie-web/dotlottie';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Credit to: Leonardo Favre https://github.com/leofavre/observed-properties.
|
|
@@ -41,8 +41,7 @@ if (isServer) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
async connectedCallback() {
|
|
44
|
+
connectedCallback() {
|
|
46
45
|
let arr = [];
|
|
47
46
|
if (updateOnConnected in this && Array.isArray(this[updateOnConnected])) {
|
|
48
47
|
arr = this[updateOnConnected];
|
|
@@ -64,6 +63,80 @@ if (isServer) {
|
|
|
64
63
|
|
|
65
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";
|
|
66
65
|
|
|
66
|
+
const boomerangIcon = /* HTML */ `
|
|
67
|
+
<svg width="24" height="24" aria-hidden="true" focusable="false">
|
|
68
|
+
<path
|
|
69
|
+
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"
|
|
70
|
+
/>
|
|
71
|
+
</svg>
|
|
72
|
+
`;
|
|
73
|
+
|
|
74
|
+
const convertIcon = /* HTML */ `
|
|
75
|
+
<svg
|
|
76
|
+
width="24"
|
|
77
|
+
height="24"
|
|
78
|
+
aria-hidden="true"
|
|
79
|
+
focusable="false"
|
|
80
|
+
>
|
|
81
|
+
<path
|
|
82
|
+
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"
|
|
83
|
+
/>
|
|
84
|
+
</svg>
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
const downloadIcon = /* HTML */ `
|
|
88
|
+
<svg
|
|
89
|
+
width="24"
|
|
90
|
+
height="24"
|
|
91
|
+
aria-hidden="true"
|
|
92
|
+
focusable="false"
|
|
93
|
+
>
|
|
94
|
+
<path
|
|
95
|
+
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"
|
|
96
|
+
/>
|
|
97
|
+
</svg>
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
const loopIcon = /* HTML */ `
|
|
101
|
+
<svg width="24" height="24" aria-hidden="true" focusable="false">
|
|
102
|
+
<path
|
|
103
|
+
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"
|
|
104
|
+
/>
|
|
105
|
+
</svg>
|
|
106
|
+
`;
|
|
107
|
+
|
|
108
|
+
const nextIcon = /* HTML */ `
|
|
109
|
+
<svg width="24" height="24" aria-hidden="true" focusable="false">
|
|
110
|
+
<path d="m6.1 5.8 9.8 6.2-9.8 6.2V5.8zM16.4 5.8h1.5v12.4h-1.5z" />
|
|
111
|
+
</svg>
|
|
112
|
+
`;
|
|
113
|
+
|
|
114
|
+
const playIcon = /* HTML */ `
|
|
115
|
+
<svg width="24" height="24" aria-hidden="true" focusable="false">
|
|
116
|
+
<path d="M8.016 5.016L18.985 12 8.016 18.984V5.015z" />
|
|
117
|
+
</svg>
|
|
118
|
+
`;
|
|
119
|
+
|
|
120
|
+
const prevIcon = /* HTML */ `
|
|
121
|
+
<svg width="24" height="24" aria-hidden="true" focusable="false">
|
|
122
|
+
<path d="M17.9 18.2 8.1 12l9.8-6.2v12.4zm-10.3 0H6.1V5.8h1.5v12.4z" />
|
|
123
|
+
</svg>
|
|
124
|
+
`;
|
|
125
|
+
|
|
126
|
+
const settingsIcon = /* HTML */ `
|
|
127
|
+
<svg width="24" height="24" aria-hidden="true" focusable="false">
|
|
128
|
+
<circle cx="12" cy="5.4" r="2.5" />
|
|
129
|
+
<circle cx="12" cy="12" r="2.5" />
|
|
130
|
+
<circle cx="12" cy="18.6" r="2.5" />
|
|
131
|
+
</svg>
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
const stopIcon = /* HTML */ `
|
|
135
|
+
<svg width="24" height="24" aria-hidden="true" focusable="false">
|
|
136
|
+
<path d="M6 6h12v12H6V6z" />
|
|
137
|
+
</svg>
|
|
138
|
+
`;
|
|
139
|
+
|
|
67
140
|
var ObjectFit = /*#__PURE__*/ function(ObjectFit) {
|
|
68
141
|
ObjectFit["Contain"] = "contain";
|
|
69
142
|
ObjectFit["Cover"] = "cover";
|
|
@@ -83,24 +156,6 @@ var PlayerState = /*#__PURE__*/ function(PlayerState) {
|
|
|
83
156
|
PlayerState["Stopped"] = "stopped";
|
|
84
157
|
return PlayerState;
|
|
85
158
|
}({});
|
|
86
|
-
var PlayMode = /*#__PURE__*/ function(PlayMode) {
|
|
87
|
-
PlayMode["Bounce"] = "bounce";
|
|
88
|
-
PlayMode["Normal"] = "normal";
|
|
89
|
-
return PlayMode;
|
|
90
|
-
}({});
|
|
91
|
-
var PreserveAspectRatio = /*#__PURE__*/ function(PreserveAspectRatio) {
|
|
92
|
-
PreserveAspectRatio["Contain"] = "xMidYMid meet";
|
|
93
|
-
PreserveAspectRatio["Cover"] = "xMidYMid slice";
|
|
94
|
-
PreserveAspectRatio["Initial"] = "none";
|
|
95
|
-
PreserveAspectRatio["None"] = "xMinYMin slice";
|
|
96
|
-
return PreserveAspectRatio;
|
|
97
|
-
}({});
|
|
98
|
-
var RendererType = /*#__PURE__*/ function(RendererType) {
|
|
99
|
-
RendererType["Canvas"] = "canvas";
|
|
100
|
-
RendererType["HTML"] = "html";
|
|
101
|
-
RendererType["SVG"] = "svg";
|
|
102
|
-
return RendererType;
|
|
103
|
-
}({});
|
|
104
159
|
|
|
105
160
|
/**
|
|
106
161
|
* Render Controls.
|
|
@@ -116,7 +171,7 @@ var RendererType = /*#__PURE__*/ function(RendererType) {
|
|
|
116
171
|
slot.innerHTML = '';
|
|
117
172
|
return;
|
|
118
173
|
}
|
|
119
|
-
slot.innerHTML = /* HTML */ `<div class="lottie-controls toolbar ${this.playerState === PlayerState.Error ? 'has-error' : ''}" aria-label="Lottie Animation controls"><button class="togglePlay" data-active="
|
|
174
|
+
slot.innerHTML = /* HTML */ `<div class="lottie-controls toolbar ${this.playerState === PlayerState.Error ? 'has-error' : ''}" aria-label="Lottie Animation controls"><button class="togglePlay" data-active="${this.autoplay}" aria-label="Toggle Play/Pause">${playIcon}</button> <button class="stop" data-active="${!this.autoplay}" aria-label="Stop">${stopIcon}</button> <button class="prev" aria-label="Previous animation" hidden>${prevIcon}</button> <button class="next" aria-label="Next animation" hidden>${nextIcon}</button><form class="progress-container${this.simple ? ' simple' : ''}"><input type="range" class="seeker" min="0" max="100" step="1" value="${this._seeker.toString()}" aria-valuemin="0" aria-valuemax="100" 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">${loopIcon}</button> <button class="toggleBoomerang" data-active="${this.mode === PlayMode.Bounce}" aria-label="Toggle boomerang" tabindex="0">${boomerangIcon}</button> <button class="toggleSettings" aria-label="Settings" aria-haspopup="true" aria-expanded="${Boolean(this._isSettingsOpen)}" aria-controls="${this._identifier}-settings">${settingsIcon}</button><div id="${this._identifier}-settings" class="popover" hidden><button class="convert" aria-label="Convert JSON animation to dotLottie format" hidden>${convertIcon} ${this.isDotLottie ? 'Convert to JSON' : 'Convert to dotLottie'}</button> <button class="snapshot" aria-label="Download still image">${downloadIcon} Download still image</button></div>`}</div>`;
|
|
120
175
|
const togglePlay = this.shadow.querySelector('.togglePlay');
|
|
121
176
|
if (togglePlay instanceof HTMLButtonElement) {
|
|
122
177
|
togglePlay.onclick = this.togglePlay;
|
|
@@ -147,14 +202,16 @@ var RendererType = /*#__PURE__*/ function(RendererType) {
|
|
|
147
202
|
if (toggleBoomerang instanceof HTMLButtonElement) {
|
|
148
203
|
toggleBoomerang.onclick = this.toggleBoomerang;
|
|
149
204
|
}
|
|
150
|
-
const
|
|
151
|
-
if (
|
|
152
|
-
|
|
205
|
+
const convertButton = this.shadow.querySelector('.convert');
|
|
206
|
+
if (convertButton instanceof HTMLButtonElement) {
|
|
207
|
+
convertButton.onclick = ()=>{
|
|
208
|
+
void convert({
|
|
209
|
+
isDotLottie: this.isDotLottie,
|
|
210
|
+
manifest: this.getManifest(),
|
|
211
|
+
src: this.src || this.source
|
|
212
|
+
});
|
|
213
|
+
};
|
|
153
214
|
}
|
|
154
|
-
// const convertJSON = this.shadow.querySelector('.convert-json')
|
|
155
|
-
// if (convertJSON instanceof HTMLButtonElement) {
|
|
156
|
-
// convertJSON.onclick = this.convertJSON as unknown as () => void
|
|
157
|
-
// }
|
|
158
215
|
const snapshot = this.shadow.querySelector('.snapshot');
|
|
159
216
|
if (snapshot instanceof HTMLButtonElement) {
|
|
160
217
|
snapshot.onclick = ()=>this.snapshot(true);
|
|
@@ -167,23 +224,27 @@ var RendererType = /*#__PURE__*/ function(RendererType) {
|
|
|
167
224
|
}
|
|
168
225
|
}
|
|
169
226
|
|
|
227
|
+
const pauseIcon = /* HTML */ `
|
|
228
|
+
<svg width="24" height="24" aria-hidden="true" focusable="false">
|
|
229
|
+
<path
|
|
230
|
+
d="M14.016 5.016H18v13.969h-3.984V5.016zM6 18.984V5.015h3.984v13.969H6z"
|
|
231
|
+
/>
|
|
232
|
+
</svg>
|
|
233
|
+
`;
|
|
234
|
+
|
|
170
235
|
/**
|
|
171
236
|
* Render Player.
|
|
172
237
|
*/ async function renderPlayer() {
|
|
173
238
|
if (!this.shadow) {
|
|
174
239
|
throw new Error('No Shadow Element');
|
|
175
240
|
}
|
|
176
|
-
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="
|
|
241
|
+
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="${PreserveAspectRatio.Cover}" xmlns="${namespaceSVG}" width="1920" height="1080" viewBox="0 0 1920 1080" style="white-space:preserve"><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>`;
|
|
177
242
|
this.shadow.adoptedStyleSheets = [
|
|
178
243
|
await DotLottiePlayer.styles()
|
|
179
244
|
];
|
|
180
245
|
this.shadow.appendChild(this.template.content.cloneNode(true));
|
|
181
246
|
}
|
|
182
247
|
|
|
183
|
-
const hasExt = (path)=>{
|
|
184
|
-
const lastDotIndex = path?.split('/').pop()?.lastIndexOf('.');
|
|
185
|
-
return (lastDotIndex ?? 0) > 1 && path && path.length - 1 > (lastDotIndex ?? 0);
|
|
186
|
-
};
|
|
187
248
|
/**
|
|
188
249
|
* Get extension from filename, URL or path.
|
|
189
250
|
*/ const aspectRatio = (objectFit)=>{
|
|
@@ -191,76 +252,25 @@ const hasExt = (path)=>{
|
|
|
191
252
|
case ObjectFit.Contain:
|
|
192
253
|
case ObjectFit.ScaleDown:
|
|
193
254
|
{
|
|
194
|
-
return PreserveAspectRatio
|
|
255
|
+
return PreserveAspectRatio.Contain;
|
|
195
256
|
}
|
|
196
257
|
case ObjectFit.Cover:
|
|
197
258
|
{
|
|
198
|
-
return PreserveAspectRatio
|
|
259
|
+
return PreserveAspectRatio.Cover;
|
|
199
260
|
}
|
|
200
261
|
case ObjectFit.Fill:
|
|
201
262
|
{
|
|
202
|
-
return PreserveAspectRatio
|
|
263
|
+
return PreserveAspectRatio.Initial;
|
|
203
264
|
}
|
|
204
265
|
case ObjectFit.None:
|
|
205
266
|
{
|
|
206
|
-
return PreserveAspectRatio
|
|
267
|
+
return PreserveAspectRatio.None;
|
|
207
268
|
}
|
|
208
269
|
default:
|
|
209
270
|
{
|
|
210
|
-
return PreserveAspectRatio
|
|
271
|
+
return PreserveAspectRatio.Contain;
|
|
211
272
|
}
|
|
212
273
|
}
|
|
213
|
-
}, /**
|
|
214
|
-
* Download file, either SVG or dotLottie.
|
|
215
|
-
*/ download = (data, options)=>{
|
|
216
|
-
const blob = new Blob([
|
|
217
|
-
data
|
|
218
|
-
], {
|
|
219
|
-
type: options?.mimeType
|
|
220
|
-
}), fileName = options?.name || createElementID(), dataURL = URL.createObjectURL(blob), link = document.createElement('a');
|
|
221
|
-
link.href = dataURL;
|
|
222
|
-
link.download = fileName;
|
|
223
|
-
link.hidden = true;
|
|
224
|
-
document.body.appendChild(link);
|
|
225
|
-
link.click();
|
|
226
|
-
setTimeout(()=>{
|
|
227
|
-
link.remove();
|
|
228
|
-
URL.revokeObjectURL(dataURL);
|
|
229
|
-
}, 1000);
|
|
230
|
-
}, getExt = (str)=>{
|
|
231
|
-
if (typeof str !== 'string' || !str || !hasExt(str)) {
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
return str.split('.').pop()?.toLowerCase();
|
|
235
|
-
}, /**
|
|
236
|
-
* Parse URL to get filename.
|
|
237
|
-
*
|
|
238
|
-
* @param src - The url string.
|
|
239
|
-
* @param keepExt - Whether to include file extension.
|
|
240
|
-
* @returns Filename, in lowercase.
|
|
241
|
-
*/ getFilename = (src, keepExt)=>{
|
|
242
|
-
// Because the regex strips all special characters, we need to extract the file extension, so we can add it later if we need it
|
|
243
|
-
getExt(src);
|
|
244
|
-
return `${src.split('/').pop()?.replace(/\.[^.]*$/, '').replaceAll(/\W+/g, '-')}${''}`;
|
|
245
|
-
}, addExt = (ext, str)=>{
|
|
246
|
-
if (!str) {
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
if (getExt(str)) {
|
|
250
|
-
if (getExt(str) === ext) {
|
|
251
|
-
return str;
|
|
252
|
-
}
|
|
253
|
-
return `${getFilename(str)}.${ext}`;
|
|
254
|
-
}
|
|
255
|
-
return `${str}.${ext}`;
|
|
256
|
-
}, parseBase64 = (str)=>str.slice(Math.max(0, str.indexOf(',') + 1)), /**
|
|
257
|
-
* Convert Base64 encoded string to Uint8Array.
|
|
258
|
-
*
|
|
259
|
-
* @param str - Base64 encoded string.
|
|
260
|
-
* @returns UTF-8/Latin-1 binary.
|
|
261
|
-
*/ base64ToU8 = (str)=>strToU8(isServer ? Buffer.from(parseBase64(str), 'base64').toString('binary') : atob(parseBase64(str)), true), getExtFromB64 = (str)=>{
|
|
262
|
-
const mime = str.split(':')[1].split(';')[0], ext = mime.split('/')[1].split('+')[0];
|
|
263
|
-
return ext;
|
|
264
274
|
}, handleErrors = (err)=>{
|
|
265
275
|
const res = {
|
|
266
276
|
message: 'Unknown error',
|
|
@@ -275,360 +285,8 @@ const hasExt = (path)=>{
|
|
|
275
285
|
}
|
|
276
286
|
}
|
|
277
287
|
return res;
|
|
278
|
-
},
|
|
279
|
-
|
|
280
|
-
const getArrayBuffer = async (zippable)=>{
|
|
281
|
-
const arrayBuffer = await new Promise((resolve, reject)=>{
|
|
282
|
-
zip(zippable, {
|
|
283
|
-
level: 9
|
|
284
|
-
}, (err, data)=>{
|
|
285
|
-
if (err) {
|
|
286
|
-
reject(err);
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
if (!(data.buffer instanceof ArrayBuffer)) {
|
|
290
|
-
reject(new Error('Data is not transferable'));
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
resolve(data.buffer);
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
return arrayBuffer;
|
|
297
|
-
}, fileToBase64 = async (url)=>{
|
|
298
|
-
const response = await fetch(url), blob = await response.blob();
|
|
299
|
-
return new Promise((resolve, reject)=>{
|
|
300
|
-
try {
|
|
301
|
-
const reader = new FileReader();
|
|
302
|
-
reader.onload = ()=>{
|
|
303
|
-
if (typeof reader.result === 'string') {
|
|
304
|
-
resolve(reader.result);
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
reject(new Error('Could not create bas64'));
|
|
308
|
-
};
|
|
309
|
-
reader.readAsDataURL(blob);
|
|
310
|
-
} catch (error) {
|
|
311
|
-
reject(error);
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
};
|
|
315
|
-
/**
|
|
316
|
-
* Convert a JSON Lottie to dotLottie or combine several animations and download new dotLottie file in your browser.
|
|
317
|
-
*/ async function createDotLottie({ animations = [], fileName, manifest, shouldDownload = true }) {
|
|
318
|
-
try {
|
|
319
|
-
// Input validation
|
|
320
|
-
if (animations.length === 0 || !manifest) {
|
|
321
|
-
throw new Error(`Missing or malformed required parameter(s):\n ${animations.length > 0 ? '- manifest\n' : ''} ${manifest ? '- animations\n' : ''}`);
|
|
322
|
-
}
|
|
323
|
-
const manifestCompressionLevel = 0, animationCompressionLevel = 9, /**
|
|
324
|
-
* Prepare the dotLottie file.
|
|
325
|
-
*/ name = addExt('lottie', fileName) || `${createElementID()}.lottie`, dotlottie = {
|
|
326
|
-
'manifest.json': [
|
|
327
|
-
strToU8(JSON.stringify(manifest), true),
|
|
328
|
-
{
|
|
329
|
-
level: manifestCompressionLevel
|
|
330
|
-
}
|
|
331
|
-
]
|
|
332
|
-
};
|
|
333
|
-
// Add animations and assets to the dotLottie file
|
|
334
|
-
const { length } = animations;
|
|
335
|
-
for(let i = 0; i < length; i++){
|
|
336
|
-
const { length: jLen } = animations[i].assets;
|
|
337
|
-
// Prepare assets
|
|
338
|
-
for(let j = 0; j < jLen; j++){
|
|
339
|
-
const asset = animations[i].assets[j];
|
|
340
|
-
if (!asset.p || !isImage(asset) && !isAudio(asset)) {
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
const { p: file, u: path } = asset;
|
|
344
|
-
if (!file) {
|
|
345
|
-
continue;
|
|
346
|
-
}
|
|
347
|
-
// Original asset.id caused issues with multianimations
|
|
348
|
-
const assetId = createElementID(), isEncoded = file.startsWith('data:'), ext = isEncoded ? getExtFromB64(file) : getExt(file), /**
|
|
349
|
-
* Check if the asset is already base64-encoded. If not, get path, fetch it, and encode it.
|
|
350
|
-
*/ dataURL = isEncoded ? file : await fileToBase64(path ? path.endsWith('/') && `${path}${file}` || `${path}/${file}` : file);
|
|
351
|
-
// Asset is encoded
|
|
352
|
-
// eslint-disable-next-line require-atomic-updates
|
|
353
|
-
animations[i].assets[j].e = 1;
|
|
354
|
-
// eslint-disable-next-line require-atomic-updates
|
|
355
|
-
animations[i].assets[j].p = `${assetId}.${ext}`;
|
|
356
|
-
// Asset is embedded, so path empty string
|
|
357
|
-
// eslint-disable-next-line require-atomic-updates
|
|
358
|
-
animations[i].assets[j].u = '';
|
|
359
|
-
dotlottie[`${isAudio(asset) ? 'audio' : 'images'}/${assetId}.${ext}`] = [
|
|
360
|
-
base64ToU8(dataURL),
|
|
361
|
-
{
|
|
362
|
-
level: animationCompressionLevel
|
|
363
|
-
}
|
|
364
|
-
];
|
|
365
|
-
}
|
|
366
|
-
// Prepare expressions
|
|
367
|
-
const { length: kLen } = animations[i].layers;
|
|
368
|
-
for(let k = 0; k < kLen; k++){
|
|
369
|
-
const { ks: shape } = animations[i].layers[k], props = Object.keys(shape), { length: pLen } = props;
|
|
370
|
-
for(let p = 0; p < pLen; p++){
|
|
371
|
-
const { x: expression } = shape[props[p]];
|
|
372
|
-
if (!expression) {
|
|
373
|
-
continue;
|
|
374
|
-
}
|
|
375
|
-
// Base64 Encode to handle compression
|
|
376
|
-
// @ts-expect-error: We have checked this property is set
|
|
377
|
-
animations[i].layers[k].ks[props[p]].x = btoa(expression);
|
|
378
|
-
// Set e (encoded) to 1
|
|
379
|
-
// @ts-expect-error: We have checked this property is set
|
|
380
|
-
animations[i].layers[k].ks[props[p]].e = 1;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
dotlottie[`a/${manifest.animations[i].id}.json`] = [
|
|
384
|
-
strToU8(JSON.stringify(animations[i]), true),
|
|
385
|
-
{
|
|
386
|
-
level: animationCompressionLevel
|
|
387
|
-
}
|
|
388
|
-
];
|
|
389
|
-
}
|
|
390
|
-
const buffer = await getArrayBuffer(dotlottie);
|
|
391
|
-
if (shouldDownload) {
|
|
392
|
-
download(buffer, {
|
|
393
|
-
mimeType: 'application/zip',
|
|
394
|
-
name
|
|
395
|
-
});
|
|
396
|
-
return null;
|
|
397
|
-
}
|
|
398
|
-
return buffer;
|
|
399
|
-
} catch (error) {
|
|
400
|
-
console.error(handleErrors(error).message);
|
|
401
|
-
return null;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
function createJSON({ animation, fileName, shouldDownload }) {
|
|
406
|
-
try {
|
|
407
|
-
if (!animation) {
|
|
408
|
-
throw new Error('createJSON: Missing or malformed required parameter(s):\n - animation\n\'');
|
|
409
|
-
}
|
|
410
|
-
const name = addExt('json', fileName) || `${createElementID()}.json`, jsonString = JSON.stringify(animation);
|
|
411
|
-
if (shouldDownload) {
|
|
412
|
-
download(jsonString, {
|
|
413
|
-
mimeType: 'application/json',
|
|
414
|
-
name
|
|
415
|
-
});
|
|
416
|
-
return null;
|
|
417
|
-
}
|
|
418
|
-
return jsonString;
|
|
419
|
-
} catch (error) {
|
|
420
|
-
console.error(handleErrors(error).message);
|
|
421
|
-
return null;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const getMimeFromExt = (ext)=>{
|
|
426
|
-
switch(ext){
|
|
427
|
-
case 'svg':
|
|
428
|
-
case 'svg+xml':
|
|
429
|
-
{
|
|
430
|
-
return 'image/svg+xml';
|
|
431
|
-
}
|
|
432
|
-
case 'jpg':
|
|
433
|
-
case 'jpeg':
|
|
434
|
-
{
|
|
435
|
-
return 'image/jpeg';
|
|
436
|
-
}
|
|
437
|
-
case 'png':
|
|
438
|
-
case 'gif':
|
|
439
|
-
case 'webp':
|
|
440
|
-
case 'avif':
|
|
441
|
-
{
|
|
442
|
-
return `image/${ext}`;
|
|
443
|
-
}
|
|
444
|
-
case 'mp3':
|
|
445
|
-
case 'mpeg':
|
|
446
|
-
case 'wav':
|
|
447
|
-
{
|
|
448
|
-
return `audio/${ext}`;
|
|
449
|
-
}
|
|
450
|
-
default:
|
|
451
|
-
{
|
|
452
|
-
return '';
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}, isBase64 = (str)=>{
|
|
456
|
-
if (!str) {
|
|
457
|
-
return false;
|
|
458
|
-
}
|
|
459
|
-
const regex = /^(?:[0-9a-z+/]{4})*(?:[0-9a-z+/]{2}==|[0-9a-z+/]{3}=)?$/i;
|
|
460
|
-
return regex.test(parseBase64(str));
|
|
461
|
-
};
|
|
462
|
-
async function resolveAssets(unzipped, assets) {
|
|
463
|
-
if (!Array.isArray(assets)) {
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
const toResolve = [], { length } = assets;
|
|
467
|
-
for(let i = 0; i < length; i++){
|
|
468
|
-
if (!isAudio(assets[i]) && !isImage(assets[i])) {
|
|
469
|
-
continue;
|
|
470
|
-
}
|
|
471
|
-
const type = isImage(assets[i]) ? 'images' : 'audio', u8 = unzipped?.[`${type}/${assets[i].p}`];
|
|
472
|
-
if (!u8) {
|
|
473
|
-
continue;
|
|
474
|
-
}
|
|
475
|
-
toResolve.push(new Promise((resolveAsset)=>{
|
|
476
|
-
let assetB64;
|
|
477
|
-
if (isServer) {
|
|
478
|
-
assetB64 = Buffer.from(u8).toString('base64');
|
|
479
|
-
} else {
|
|
480
|
-
let result = '';
|
|
481
|
-
const { length: jLen } = u8;
|
|
482
|
-
for(let j = 0; j < jLen; j++){
|
|
483
|
-
result += String.fromCharCode(u8[j]);
|
|
484
|
-
}
|
|
485
|
-
assetB64 = btoa(result);
|
|
486
|
-
}
|
|
487
|
-
assets[i].p = assets[i].p?.startsWith('data:') || isBase64(assets[i].p) ? assets[i].p : `data:${getMimeFromExt(getExt(assets[i].p))};base64,${assetB64}`;
|
|
488
|
-
assets[i].e = 1;
|
|
489
|
-
assets[i].u = '';
|
|
490
|
-
resolveAsset();
|
|
491
|
-
}));
|
|
492
|
-
}
|
|
493
|
-
await Promise.all(toResolve);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
const unzip = async (resp)=>{
|
|
497
|
-
const u8 = new Uint8Array(await resp.arrayBuffer()), unzipped = await new Promise((resolve, reject)=>{
|
|
498
|
-
unzip$1(u8, (err, file)=>{
|
|
499
|
-
if (err) {
|
|
500
|
-
reject(err);
|
|
501
|
-
}
|
|
502
|
-
resolve(file);
|
|
503
|
-
});
|
|
504
|
-
});
|
|
505
|
-
return unzipped;
|
|
506
|
-
}, getManifest = (unzipped)=>{
|
|
507
|
-
const file = strFromU8(unzipped['manifest.json'], false), manifest = JSON.parse(file);
|
|
508
|
-
if (!('animations' in manifest)) {
|
|
509
|
-
throw new Error('Manifest not found');
|
|
510
|
-
}
|
|
511
|
-
if (manifest.animations.length === 0) {
|
|
512
|
-
throw new Error('No animations listed in manifest');
|
|
513
|
-
}
|
|
514
|
-
return manifest;
|
|
515
|
-
}, prepareString = (str)=>str.replaceAll(new RegExp(/"""/, 'g'), '""').replaceAll(/(["'])(.*?)\1/g, (_match, quote, content)=>{
|
|
516
|
-
/**
|
|
517
|
-
* TODO: This caused text layers and expressions to be mangled
|
|
518
|
-
* Consider a more nuanced sanitaiton, if at all.
|
|
519
|
-
*/ // const replacedContent = content.replaceAll(/[^\w\s.#]/g, '')
|
|
520
|
-
return `${quote}${content}${quote}`;
|
|
521
|
-
});
|
|
522
|
-
async function getLottieJSON(resp) {
|
|
523
|
-
const unzipped = await unzip(resp), manifest = getManifest(unzipped), data = [], toResolve = [], { length } = manifest.animations;
|
|
524
|
-
/**
|
|
525
|
-
* Check whether Lottie animations folder is abbreviated.
|
|
526
|
-
*/ let animationsFolder = 'animations';
|
|
527
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
528
|
-
if (unzipped[`a/${manifest.animations[0].id}.json`]) {
|
|
529
|
-
animationsFolder = 'a';
|
|
530
|
-
}
|
|
531
|
-
for(let i = 0; i < length; i++){
|
|
532
|
-
const str = strFromU8(unzipped[`${animationsFolder}/${manifest.animations[i].id}.json`]), lottie = JSON.parse(prepareString(str));
|
|
533
|
-
// Handle Expressions
|
|
534
|
-
const { length: jLen } = lottie.layers;
|
|
535
|
-
for(let j = 0; j < jLen; j++){
|
|
536
|
-
const { ks: shape } = lottie.layers[j], props = Object.keys(shape), { length: pLen } = props;
|
|
537
|
-
for(let p = 0; p < pLen; p++){
|
|
538
|
-
const { e: isEncoded, x: expression } = shape[props[p]];
|
|
539
|
-
if (!expression || !isEncoded) {
|
|
540
|
-
continue;
|
|
541
|
-
}
|
|
542
|
-
// Base64 Decode to handle compression
|
|
543
|
-
// @ts-expect-error
|
|
544
|
-
lottie.layers[j].ks[props[p]].x = atob(expression);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
toResolve.push(resolveAssets(unzipped, lottie.assets));
|
|
548
|
-
data.push(lottie);
|
|
549
|
-
}
|
|
550
|
-
await Promise.all(toResolve);
|
|
551
|
-
return {
|
|
552
|
-
data,
|
|
553
|
-
manifest
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
async function getAnimationData(input) {
|
|
558
|
-
try {
|
|
559
|
-
if (!input || typeof input !== 'string' && typeof input !== 'object') {
|
|
560
|
-
throw new Error('Broken file or invalid file format');
|
|
561
|
-
}
|
|
562
|
-
if (typeof input !== 'string') {
|
|
563
|
-
const animations = Array.isArray(input) ? input : [
|
|
564
|
-
input
|
|
565
|
-
];
|
|
566
|
-
return {
|
|
567
|
-
animations,
|
|
568
|
-
isDotLottie: false,
|
|
569
|
-
manifest: null
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
const result = await fetch(input, {
|
|
573
|
-
headers: {
|
|
574
|
-
'Content-Type': 'application/json; charset=UTF-8'
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
|
-
if (!result.ok) {
|
|
578
|
-
const error = new Error(result.statusText);
|
|
579
|
-
throw error;
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* Check if file is JSON, first by parsing headers for content-type,
|
|
583
|
-
* than by parsing filename, then – if filename has no extension – by
|
|
584
|
-
* cloning the response and parsing response for content.
|
|
585
|
-
*/ let isJSON = true;
|
|
586
|
-
const contentType = result.headers.get('content-type');
|
|
587
|
-
if (contentType === 'application/zip+dotlottie') {
|
|
588
|
-
isJSON = false;
|
|
589
|
-
}
|
|
590
|
-
if (isJSON) {
|
|
591
|
-
const ext = getExt(input);
|
|
592
|
-
if (ext === 'json') {
|
|
593
|
-
const lottie = await result.json();
|
|
594
|
-
return {
|
|
595
|
-
animations: [
|
|
596
|
-
lottie
|
|
597
|
-
],
|
|
598
|
-
isDotLottie: false,
|
|
599
|
-
manifest: null
|
|
600
|
-
};
|
|
601
|
-
}
|
|
602
|
-
const text = await result.clone().text();
|
|
603
|
-
try {
|
|
604
|
-
const lottie = JSON.parse(text);
|
|
605
|
-
return {
|
|
606
|
-
animations: [
|
|
607
|
-
lottie
|
|
608
|
-
],
|
|
609
|
-
isDotLottie: false,
|
|
610
|
-
manifest: null
|
|
611
|
-
};
|
|
612
|
-
} catch (error) {
|
|
613
|
-
/* empty */ }
|
|
614
|
-
}
|
|
615
|
-
const { data, manifest } = await getLottieJSON(result);
|
|
616
|
-
return {
|
|
617
|
-
animations: data,
|
|
618
|
-
isDotLottie: true,
|
|
619
|
-
manifest
|
|
620
|
-
};
|
|
621
|
-
} catch (error) {
|
|
622
|
-
console.error(handleErrors(error).message);
|
|
623
|
-
return {
|
|
624
|
-
animations: undefined,
|
|
625
|
-
isDotLottie: false,
|
|
626
|
-
manifest: null
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
}
|
|
288
|
+
}, frameOutput = (frame)=>((frame ?? 0) + 1).toString().padStart(3, '0');
|
|
630
289
|
|
|
631
|
-
const generator = '@aarsteinmedia/dotlottie-player';
|
|
632
290
|
/**
|
|
633
291
|
* DotLottie Player Web Component.
|
|
634
292
|
*/ class DotLottiePlayer extends PropertyCallbackElement {
|
|
@@ -756,6 +414,9 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
756
414
|
}
|
|
757
415
|
return 0;
|
|
758
416
|
}
|
|
417
|
+
get isDotLottie() {
|
|
418
|
+
return this._isDotLottie;
|
|
419
|
+
}
|
|
759
420
|
/**
|
|
760
421
|
* Loop animation.
|
|
761
422
|
*/ set loop(value) {
|
|
@@ -852,7 +513,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
852
513
|
return Boolean(val === 'true' || val === '' || val === '1');
|
|
853
514
|
}
|
|
854
515
|
constructor(){
|
|
855
|
-
super(), /**
|
|
516
|
+
super(), this.addAnimation = addAnimation, this.convert = convert, /**
|
|
856
517
|
* Player state.
|
|
857
518
|
*/ this.playerState = PlayerState.Loading, /**
|
|
858
519
|
* Animation Container.
|
|
@@ -875,15 +536,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
875
536
|
* Which animation to show, if several.
|
|
876
537
|
*/ this._currentAnimation = 0, this._isBounce = false, this._isDotLottie = false, this._lottieInstance = null, /**
|
|
877
538
|
* Multi-animation settings.
|
|
878
|
-
*/ this._multiAnimationSettings = []
|
|
879
|
-
* Handle settings click event.
|
|
880
|
-
*/ this._handleSettingsClick = ({ target })=>{
|
|
881
|
-
this._toggleSettings();
|
|
882
|
-
// Because Safari does not add focus on click, we need to add it manually, so the onblur event will fire
|
|
883
|
-
if (target instanceof HTMLElement) {
|
|
884
|
-
target.focus();
|
|
885
|
-
}
|
|
886
|
-
};
|
|
539
|
+
*/ this._multiAnimationSettings = [];
|
|
887
540
|
this._complete = this._complete.bind(this);
|
|
888
541
|
this._dataFailed = this._dataFailed.bind(this);
|
|
889
542
|
this._dataReady = this._dataReady.bind(this);
|
|
@@ -899,6 +552,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
899
552
|
this._mouseLeave = this._mouseLeave.bind(this);
|
|
900
553
|
this._onVisibilityChange = this._onVisibilityChange.bind(this);
|
|
901
554
|
this._switchInstance = this._switchInstance.bind(this);
|
|
555
|
+
this._handleSettingsClick = this._handleSettingsClick.bind(this);
|
|
902
556
|
this.togglePlay = this.togglePlay.bind(this);
|
|
903
557
|
this.stop = this.stop.bind(this);
|
|
904
558
|
this.prev = this.prev.bind(this);
|
|
@@ -907,7 +561,6 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
907
561
|
this.snapshot = this.snapshot.bind(this);
|
|
908
562
|
this.toggleLoop = this.toggleLoop.bind(this);
|
|
909
563
|
this.toggleBoomerang = this.toggleBoomerang.bind(this);
|
|
910
|
-
this.convert = this.convert.bind(this);
|
|
911
564
|
this.destroy = this.destroy.bind(this);
|
|
912
565
|
this.template = document.createElement('template');
|
|
913
566
|
this.shadow = this.attachShadow({
|
|
@@ -915,57 +568,6 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
915
568
|
});
|
|
916
569
|
}
|
|
917
570
|
/**
|
|
918
|
-
* Creates a new dotLottie file, by combinig several animations.
|
|
919
|
-
* If set to false the function returns an ArrayBuffer. Defaults to true.
|
|
920
|
-
*/ async addAnimation(configs, fileName, shouldDownload = true) {
|
|
921
|
-
// Initialize meta object for animation, with fallbacks for
|
|
922
|
-
// when the method is called indepenently
|
|
923
|
-
const { animations = [], manifest = {
|
|
924
|
-
animations: this.src ? [
|
|
925
|
-
{
|
|
926
|
-
id: this._identifier
|
|
927
|
-
}
|
|
928
|
-
] : []
|
|
929
|
-
} } = this.src ? await getAnimationData(this.src) : {};
|
|
930
|
-
try {
|
|
931
|
-
if (!manifest) {
|
|
932
|
-
throw new Error('Manifest is not set');
|
|
933
|
-
}
|
|
934
|
-
manifest.generator = generator;
|
|
935
|
-
const { length } = configs;
|
|
936
|
-
for(let i = 0; i < length; i++){
|
|
937
|
-
const { url } = configs[i], { animations: animationsToAdd } = await getAnimationData(url);
|
|
938
|
-
if (!animationsToAdd) {
|
|
939
|
-
throw new Error('No animation loaded');
|
|
940
|
-
}
|
|
941
|
-
if (manifest.animations.some(({ id })=>id === configs[i].id)) {
|
|
942
|
-
throw new Error('Duplicate id for animation');
|
|
943
|
-
}
|
|
944
|
-
manifest.animations = [
|
|
945
|
-
...manifest.animations,
|
|
946
|
-
{
|
|
947
|
-
id: configs[i].id
|
|
948
|
-
}
|
|
949
|
-
];
|
|
950
|
-
animations.push(...animationsToAdd);
|
|
951
|
-
}
|
|
952
|
-
return {
|
|
953
|
-
result: await createDotLottie({
|
|
954
|
-
animations,
|
|
955
|
-
fileName,
|
|
956
|
-
manifest,
|
|
957
|
-
shouldDownload
|
|
958
|
-
}),
|
|
959
|
-
success: true
|
|
960
|
-
};
|
|
961
|
-
} catch (error) {
|
|
962
|
-
return {
|
|
963
|
-
error: handleErrors(error).message,
|
|
964
|
-
success: false
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
/**
|
|
969
571
|
* Runs when the value of an attribute is changed on the component.
|
|
970
572
|
*/ async attributeChangedCallback(name, _oldValue, value) {
|
|
971
573
|
if (!this._lottieInstance || !this.shadow) {
|
|
@@ -1040,50 +642,29 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1040
642
|
}
|
|
1041
643
|
/**
|
|
1042
644
|
* Initialize everything on component first render.
|
|
1043
|
-
*/
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
}
|
|
1066
|
-
let animations = animationsFromProps;
|
|
1067
|
-
if (!animations) {
|
|
1068
|
-
const animationData = await getAnimationData(src);
|
|
1069
|
-
animations = animationData.animations;
|
|
1070
|
-
}
|
|
1071
|
-
if (typeCheck || this._isDotLottie) {
|
|
1072
|
-
return createJSON({
|
|
1073
|
-
animation: animations?.[0],
|
|
1074
|
-
fileName: `${getFilename(fileName || src || 'converted')}.json`,
|
|
1075
|
-
shouldDownload
|
|
1076
|
-
});
|
|
645
|
+
*/ connectedCallback() {
|
|
646
|
+
super.connectedCallback();
|
|
647
|
+
try {
|
|
648
|
+
void (async ()=>{
|
|
649
|
+
await this._render();
|
|
650
|
+
if (!this.shadow) {
|
|
651
|
+
throw new Error('Missing Shadow element');
|
|
652
|
+
}
|
|
653
|
+
this._container = this.shadow.querySelector('.animation');
|
|
654
|
+
// Add listener for Visibility API's change event.
|
|
655
|
+
if (typeof document.hidden !== 'undefined') {
|
|
656
|
+
document.addEventListener('visibilitychange', this._onVisibilityChange);
|
|
657
|
+
}
|
|
658
|
+
// Add intersection observer for detecting component being out-of-view.
|
|
659
|
+
this._addIntersectionObserver();
|
|
660
|
+
// Setup lottie player
|
|
661
|
+
await this.load(this.src);
|
|
662
|
+
this.dispatchEvent(new CustomEvent(PlayerEvents.Rendered));
|
|
663
|
+
})();
|
|
664
|
+
} catch (error) {
|
|
665
|
+
console.error(error);
|
|
666
|
+
this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
|
|
1077
667
|
}
|
|
1078
|
-
return createDotLottie({
|
|
1079
|
-
animations,
|
|
1080
|
-
fileName: `${getFilename(fileName || src || 'converted')}.lottie`,
|
|
1081
|
-
manifest: {
|
|
1082
|
-
...manifest ?? this._manifest,
|
|
1083
|
-
generator
|
|
1084
|
-
},
|
|
1085
|
-
shouldDownload
|
|
1086
|
-
});
|
|
1087
668
|
}
|
|
1088
669
|
/**
|
|
1089
670
|
* Destroy animation and element.
|
|
@@ -1123,25 +704,23 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1123
704
|
}
|
|
1124
705
|
/**
|
|
1125
706
|
* Get Multi-animation settings.
|
|
1126
|
-
*
|
|
1127
707
|
*/ getMultiAnimationSettings() {
|
|
1128
708
|
return this._multiAnimationSettings;
|
|
1129
709
|
}
|
|
1130
710
|
/**
|
|
1131
711
|
* Get playback segment.
|
|
1132
|
-
*
|
|
1133
712
|
*/ getSegment() {
|
|
1134
713
|
return this._segment;
|
|
1135
714
|
}
|
|
1136
715
|
/**
|
|
1137
716
|
* Initialize Lottie Web player.
|
|
1138
717
|
*/ async load(src) {
|
|
1139
|
-
if (!this.shadowRoot || !src) {
|
|
1140
|
-
return;
|
|
1141
|
-
}
|
|
1142
|
-
this.source = src;
|
|
1143
|
-
// Load the resource
|
|
1144
718
|
try {
|
|
719
|
+
if (!this.shadowRoot || !src) {
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
this.source = src;
|
|
723
|
+
// Load the resource
|
|
1145
724
|
const { animations, isDotLottie, manifest } = await getAnimationData(src);
|
|
1146
725
|
if (!animations || animations.some((animation)=>!this._isLottie(animation))) {
|
|
1147
726
|
throw new Error('Broken or corrupted file');
|
|
@@ -1154,7 +733,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1154
733
|
manifest.animations[0].autoplay = this.autoplay;
|
|
1155
734
|
manifest.animations[0].loop = this.loop;
|
|
1156
735
|
}
|
|
1157
|
-
this._isDotLottie =
|
|
736
|
+
this._isDotLottie = isDotLottie;
|
|
1158
737
|
this._animations = animations;
|
|
1159
738
|
this._manifest = manifest ?? {
|
|
1160
739
|
animations: [
|
|
@@ -1179,30 +758,37 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1179
758
|
...this._getOptions(),
|
|
1180
759
|
animationData: animations[this._currentAnimation]
|
|
1181
760
|
});
|
|
761
|
+
this._addEventListeners();
|
|
762
|
+
const speed = this._multiAnimationSettings[this._currentAnimation]?.speed ?? this.speed, direction = this._multiAnimationSettings[this._currentAnimation]?.direction ?? this.direction;
|
|
763
|
+
// Set initial playback speed and direction
|
|
764
|
+
this._lottieInstance.setSpeed(speed);
|
|
765
|
+
this._lottieInstance.setDirection(direction);
|
|
766
|
+
this._lottieInstance.setSubframe(Boolean(this.subframe));
|
|
767
|
+
// Start playing if autoplay is enabled
|
|
768
|
+
if (this.autoplay || this.animateOnScroll) {
|
|
769
|
+
if (this.direction === -1) {
|
|
770
|
+
this.seek('99%');
|
|
771
|
+
}
|
|
772
|
+
if (!('IntersectionObserver' in window)) {
|
|
773
|
+
if (!this.animateOnScroll) {
|
|
774
|
+
this.play();
|
|
775
|
+
}
|
|
776
|
+
this._playerState.visible = true;
|
|
777
|
+
}
|
|
778
|
+
this._addIntersectionObserver();
|
|
779
|
+
}
|
|
780
|
+
this._renderControls();
|
|
781
|
+
if (this.autoplay) {
|
|
782
|
+
const togglePlay = this.shadow?.querySelector('.togglePlay');
|
|
783
|
+
if (togglePlay) {
|
|
784
|
+
togglePlay.innerHTML = pauseIcon;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
1182
787
|
} catch (error) {
|
|
788
|
+
console.error(error);
|
|
1183
789
|
this._errorMessage = handleErrors(error).message;
|
|
1184
790
|
this.playerState = PlayerState.Error;
|
|
1185
791
|
this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
|
|
1186
|
-
return;
|
|
1187
|
-
}
|
|
1188
|
-
this._addEventListeners();
|
|
1189
|
-
const speed = this._multiAnimationSettings[this._currentAnimation]?.speed ?? this.speed, direction = this._multiAnimationSettings[this._currentAnimation]?.direction ?? this.direction;
|
|
1190
|
-
// Set initial playback speed and direction
|
|
1191
|
-
this._lottieInstance.setSpeed(speed);
|
|
1192
|
-
this._lottieInstance.setDirection(direction);
|
|
1193
|
-
this._lottieInstance.setSubframe(Boolean(this.subframe));
|
|
1194
|
-
// Start playing if autoplay is enabled
|
|
1195
|
-
if (this.autoplay || this.animateOnScroll) {
|
|
1196
|
-
if (this.direction === -1) {
|
|
1197
|
-
this.seek('99%');
|
|
1198
|
-
}
|
|
1199
|
-
if (!('IntersectionObserver' in window)) {
|
|
1200
|
-
if (!this.animateOnScroll) {
|
|
1201
|
-
this.play();
|
|
1202
|
-
}
|
|
1203
|
-
this._playerState.visible = true;
|
|
1204
|
-
}
|
|
1205
|
-
this._addIntersectionObserver();
|
|
1206
792
|
}
|
|
1207
793
|
}
|
|
1208
794
|
/**
|
|
@@ -1251,7 +837,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1251
837
|
if (!this.shadow) {
|
|
1252
838
|
return;
|
|
1253
839
|
}
|
|
1254
|
-
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'),
|
|
840
|
+
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'), convertButton = this.shadow.querySelector('.convert'), snapshot = this.shadow.querySelector('.snapshot');
|
|
1255
841
|
if (!(togglePlay instanceof HTMLButtonElement) || !(stop instanceof HTMLButtonElement) || !(next instanceof HTMLButtonElement) || !(prev instanceof HTMLButtonElement) || !(seeker instanceof HTMLInputElement) || !(progress instanceof HTMLProgressElement)) {
|
|
1256
842
|
return;
|
|
1257
843
|
}
|
|
@@ -1259,9 +845,9 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1259
845
|
togglePlay.dataset.active = (value === PlayerState.Playing || value === PlayerState.Paused).toString();
|
|
1260
846
|
stop.dataset.active = (value === PlayerState.Stopped).toString();
|
|
1261
847
|
if (value === PlayerState.Playing) {
|
|
1262
|
-
togglePlay.innerHTML =
|
|
848
|
+
togglePlay.innerHTML = pauseIcon;
|
|
1263
849
|
} else {
|
|
1264
|
-
togglePlay.innerHTML =
|
|
850
|
+
togglePlay.innerHTML = playIcon;
|
|
1265
851
|
}
|
|
1266
852
|
}
|
|
1267
853
|
if (name === '_seeker' && typeof value === 'number') {
|
|
@@ -1276,17 +862,10 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1276
862
|
next.hidden = value + 1 >= this._animations.length;
|
|
1277
863
|
prev.hidden = !value;
|
|
1278
864
|
}
|
|
1279
|
-
if (name === '_isSettingsOpen' && typeof value === 'boolean' && popover instanceof HTMLDivElement &&
|
|
865
|
+
if (name === '_isSettingsOpen' && typeof value === 'boolean' && popover instanceof HTMLDivElement && convertButton instanceof HTMLButtonElement && snapshot instanceof HTMLButtonElement) {
|
|
1280
866
|
popover.hidden = !value;
|
|
1281
|
-
|
|
867
|
+
convertButton.hidden = false;
|
|
1282
868
|
snapshot.hidden = this.renderer !== RendererType.SVG;
|
|
1283
|
-
if (this._isDotLottie) {
|
|
1284
|
-
convert.ariaLabel = 'Convert dotLottie to JSON';
|
|
1285
|
-
convert.innerHTML = convert.innerHTML.replace('dotLottie', 'JSON');
|
|
1286
|
-
} else {
|
|
1287
|
-
convert.ariaLabel = 'Convert JSON animation to dotLottie format';
|
|
1288
|
-
convert.innerHTML = convert.innerHTML.replace('JSON', 'dotLottie');
|
|
1289
|
-
}
|
|
1290
869
|
}
|
|
1291
870
|
}
|
|
1292
871
|
/**
|
|
@@ -1350,13 +929,11 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1350
929
|
}
|
|
1351
930
|
/**
|
|
1352
931
|
* Set Multi-animation settings.
|
|
1353
|
-
*
|
|
1354
932
|
*/ setMultiAnimationSettings(settings) {
|
|
1355
933
|
this._multiAnimationSettings = settings;
|
|
1356
934
|
}
|
|
1357
935
|
/**
|
|
1358
936
|
* Set playback segment.
|
|
1359
|
-
*
|
|
1360
937
|
*/ setSegment(segment) {
|
|
1361
938
|
this._segment = segment;
|
|
1362
939
|
}
|
|
@@ -1426,7 +1003,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1426
1003
|
/**
|
|
1427
1004
|
* Toggle Boomerang.
|
|
1428
1005
|
*/ toggleBoomerang() {
|
|
1429
|
-
const curr = this._multiAnimationSettings[this._currentAnimation];
|
|
1006
|
+
const curr = this._multiAnimationSettings[this._currentAnimation] ?? {};
|
|
1430
1007
|
if (curr.mode !== undefined) {
|
|
1431
1008
|
if (curr.mode === PlayMode.Normal) {
|
|
1432
1009
|
curr.mode = PlayMode.Bounce;
|
|
@@ -1504,7 +1081,6 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1504
1081
|
}
|
|
1505
1082
|
/**
|
|
1506
1083
|
* Handles click and drag actions on the progress track.
|
|
1507
|
-
*
|
|
1508
1084
|
*/ _handleSeekChange({ target }) {
|
|
1509
1085
|
if (!(target instanceof HTMLInputElement) || !this._lottieInstance || isNaN(Number(target.value))) {
|
|
1510
1086
|
return;
|
|
@@ -1512,6 +1088,15 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1512
1088
|
this.seek(Math.round(Number(target.value) / 100 * this._lottieInstance.totalFrames));
|
|
1513
1089
|
}
|
|
1514
1090
|
/**
|
|
1091
|
+
* Handle settings click event.
|
|
1092
|
+
*/ _handleSettingsClick({ target }) {
|
|
1093
|
+
this._toggleSettings();
|
|
1094
|
+
// Because Safari does not add focus on click, we need to add it manually, so the onblur event will fire
|
|
1095
|
+
if (target instanceof HTMLElement) {
|
|
1096
|
+
target.focus();
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1515
1100
|
* Add event listeners.
|
|
1516
1101
|
*/ _addEventListeners() {
|
|
1517
1102
|
this._toggleEventListeners('add');
|
|
@@ -1871,11 +1456,10 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1871
1456
|
|
|
1872
1457
|
/**
|
|
1873
1458
|
* Expose DotLottiePlayer class as global variable.
|
|
1874
|
-
*
|
|
1875
1459
|
*/ globalThis.dotLottiePlayer = ()=>new DotLottiePlayer();
|
|
1876
1460
|
const tagName = 'dotlottie-player';
|
|
1877
1461
|
if (!isServer) {
|
|
1878
1462
|
customElements.define(tagName, DotLottiePlayer);
|
|
1879
1463
|
}
|
|
1880
1464
|
|
|
1881
|
-
export {
|
|
1465
|
+
export { PlayerState, DotLottiePlayer as default, tagName };
|