@aarsteinmedia/dotlottie-player 5.2.4 → 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 +8 -0
- package/custom-elements.json +23 -38
- package/dist/index.d.ts +10 -36
- package/dist/index.js +169 -579
- package/dist/unpkg.js +69 -7
- package/package.json +11 -14
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,18 +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
159
|
|
|
99
160
|
/**
|
|
100
161
|
* Render Controls.
|
|
@@ -110,7 +171,7 @@ var PreserveAspectRatio = /*#__PURE__*/ function(PreserveAspectRatio) {
|
|
|
110
171
|
slot.innerHTML = '';
|
|
111
172
|
return;
|
|
112
173
|
}
|
|
113
|
-
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>`;
|
|
114
175
|
const togglePlay = this.shadow.querySelector('.togglePlay');
|
|
115
176
|
if (togglePlay instanceof HTMLButtonElement) {
|
|
116
177
|
togglePlay.onclick = this.togglePlay;
|
|
@@ -141,14 +202,16 @@ var PreserveAspectRatio = /*#__PURE__*/ function(PreserveAspectRatio) {
|
|
|
141
202
|
if (toggleBoomerang instanceof HTMLButtonElement) {
|
|
142
203
|
toggleBoomerang.onclick = this.toggleBoomerang;
|
|
143
204
|
}
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
-
|
|
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
|
+
};
|
|
147
214
|
}
|
|
148
|
-
// const convertJSON = this.shadow.querySelector('.convert-json')
|
|
149
|
-
// if (convertJSON instanceof HTMLButtonElement) {
|
|
150
|
-
// convertJSON.onclick = this.convertJSON as unknown as () => void
|
|
151
|
-
// }
|
|
152
215
|
const snapshot = this.shadow.querySelector('.snapshot');
|
|
153
216
|
if (snapshot instanceof HTMLButtonElement) {
|
|
154
217
|
snapshot.onclick = ()=>this.snapshot(true);
|
|
@@ -161,23 +224,27 @@ var PreserveAspectRatio = /*#__PURE__*/ function(PreserveAspectRatio) {
|
|
|
161
224
|
}
|
|
162
225
|
}
|
|
163
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
|
+
|
|
164
235
|
/**
|
|
165
236
|
* Render Player.
|
|
166
237
|
*/ async function renderPlayer() {
|
|
167
238
|
if (!this.shadow) {
|
|
168
239
|
throw new Error('No Shadow Element');
|
|
169
240
|
}
|
|
170
|
-
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>`;
|
|
171
242
|
this.shadow.adoptedStyleSheets = [
|
|
172
243
|
await DotLottiePlayer.styles()
|
|
173
244
|
];
|
|
174
245
|
this.shadow.appendChild(this.template.content.cloneNode(true));
|
|
175
246
|
}
|
|
176
247
|
|
|
177
|
-
const hasExt = (path)=>{
|
|
178
|
-
const lastDotIndex = path?.split('/').pop()?.lastIndexOf('.');
|
|
179
|
-
return (lastDotIndex ?? 0) > 1 && path && path.length - 1 > (lastDotIndex ?? 0);
|
|
180
|
-
};
|
|
181
248
|
/**
|
|
182
249
|
* Get extension from filename, URL or path.
|
|
183
250
|
*/ const aspectRatio = (objectFit)=>{
|
|
@@ -185,76 +252,25 @@ const hasExt = (path)=>{
|
|
|
185
252
|
case ObjectFit.Contain:
|
|
186
253
|
case ObjectFit.ScaleDown:
|
|
187
254
|
{
|
|
188
|
-
return PreserveAspectRatio
|
|
255
|
+
return PreserveAspectRatio.Contain;
|
|
189
256
|
}
|
|
190
257
|
case ObjectFit.Cover:
|
|
191
258
|
{
|
|
192
|
-
return PreserveAspectRatio
|
|
259
|
+
return PreserveAspectRatio.Cover;
|
|
193
260
|
}
|
|
194
261
|
case ObjectFit.Fill:
|
|
195
262
|
{
|
|
196
|
-
return PreserveAspectRatio
|
|
263
|
+
return PreserveAspectRatio.Initial;
|
|
197
264
|
}
|
|
198
265
|
case ObjectFit.None:
|
|
199
266
|
{
|
|
200
|
-
return PreserveAspectRatio
|
|
267
|
+
return PreserveAspectRatio.None;
|
|
201
268
|
}
|
|
202
269
|
default:
|
|
203
270
|
{
|
|
204
|
-
return PreserveAspectRatio
|
|
271
|
+
return PreserveAspectRatio.Contain;
|
|
205
272
|
}
|
|
206
273
|
}
|
|
207
|
-
}, /**
|
|
208
|
-
* Download file, either SVG or dotLottie.
|
|
209
|
-
*/ download = (data, options)=>{
|
|
210
|
-
const blob = new Blob([
|
|
211
|
-
data
|
|
212
|
-
], {
|
|
213
|
-
type: options?.mimeType
|
|
214
|
-
}), fileName = options?.name || createElementID(), dataURL = URL.createObjectURL(blob), link = document.createElement('a');
|
|
215
|
-
link.href = dataURL;
|
|
216
|
-
link.download = fileName;
|
|
217
|
-
link.hidden = true;
|
|
218
|
-
document.body.appendChild(link);
|
|
219
|
-
link.click();
|
|
220
|
-
setTimeout(()=>{
|
|
221
|
-
link.remove();
|
|
222
|
-
URL.revokeObjectURL(dataURL);
|
|
223
|
-
}, 1000);
|
|
224
|
-
}, getExt = (str)=>{
|
|
225
|
-
if (typeof str !== 'string' || !str || !hasExt(str)) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
return str.split('.').pop()?.toLowerCase();
|
|
229
|
-
}, /**
|
|
230
|
-
* Parse URL to get filename.
|
|
231
|
-
*
|
|
232
|
-
* @param src - The url string.
|
|
233
|
-
* @param keepExt - Whether to include file extension.
|
|
234
|
-
* @returns Filename, in lowercase.
|
|
235
|
-
*/ getFilename = (src, keepExt)=>{
|
|
236
|
-
// Because the regex strips all special characters, we need to extract the file extension, so we can add it later if we need it
|
|
237
|
-
getExt(src);
|
|
238
|
-
return `${src.split('/').pop()?.replace(/\.[^.]*$/, '').replaceAll(/\W+/g, '-')}${''}`;
|
|
239
|
-
}, addExt = (ext, str)=>{
|
|
240
|
-
if (!str) {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
if (getExt(str)) {
|
|
244
|
-
if (getExt(str) === ext) {
|
|
245
|
-
return str;
|
|
246
|
-
}
|
|
247
|
-
return `${getFilename(str)}.${ext}`;
|
|
248
|
-
}
|
|
249
|
-
return `${str}.${ext}`;
|
|
250
|
-
}, parseBase64 = (str)=>str.slice(Math.max(0, str.indexOf(',') + 1)), /**
|
|
251
|
-
* Convert Base64 encoded string to Uint8Array.
|
|
252
|
-
*
|
|
253
|
-
* @param str - Base64 encoded string.
|
|
254
|
-
* @returns UTF-8/Latin-1 binary.
|
|
255
|
-
*/ base64ToU8 = (str)=>strToU8(isServer ? Buffer.from(parseBase64(str), 'base64').toString('binary') : atob(parseBase64(str)), true), getExtFromB64 = (str)=>{
|
|
256
|
-
const mime = str.split(':')[1].split(';')[0], ext = mime.split('/')[1].split('+')[0];
|
|
257
|
-
return ext;
|
|
258
274
|
}, handleErrors = (err)=>{
|
|
259
275
|
const res = {
|
|
260
276
|
message: 'Unknown error',
|
|
@@ -269,360 +285,8 @@ const hasExt = (path)=>{
|
|
|
269
285
|
}
|
|
270
286
|
}
|
|
271
287
|
return res;
|
|
272
|
-
},
|
|
273
|
-
|
|
274
|
-
const getArrayBuffer = async (zippable)=>{
|
|
275
|
-
const arrayBuffer = await new Promise((resolve, reject)=>{
|
|
276
|
-
zip(zippable, {
|
|
277
|
-
level: 9
|
|
278
|
-
}, (err, data)=>{
|
|
279
|
-
if (err) {
|
|
280
|
-
reject(err);
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
if (!(data.buffer instanceof ArrayBuffer)) {
|
|
284
|
-
reject(new Error('Data is not transferable'));
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
resolve(data.buffer);
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
return arrayBuffer;
|
|
291
|
-
}, fileToBase64 = async (url)=>{
|
|
292
|
-
const response = await fetch(url), blob = await response.blob();
|
|
293
|
-
return new Promise((resolve, reject)=>{
|
|
294
|
-
try {
|
|
295
|
-
const reader = new FileReader();
|
|
296
|
-
reader.onload = ()=>{
|
|
297
|
-
if (typeof reader.result === 'string') {
|
|
298
|
-
resolve(reader.result);
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
reject(new Error('Could not create bas64'));
|
|
302
|
-
};
|
|
303
|
-
reader.readAsDataURL(blob);
|
|
304
|
-
} catch (error) {
|
|
305
|
-
reject(error);
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
};
|
|
309
|
-
/**
|
|
310
|
-
* Convert a JSON Lottie to dotLottie or combine several animations and download new dotLottie file in your browser.
|
|
311
|
-
*/ async function createDotLottie({ animations = [], fileName, manifest, shouldDownload = true }) {
|
|
312
|
-
try {
|
|
313
|
-
// Input validation
|
|
314
|
-
if (animations.length === 0 || !manifest) {
|
|
315
|
-
throw new Error(`Missing or malformed required parameter(s):\n ${animations.length > 0 ? '- manifest\n' : ''} ${manifest ? '- animations\n' : ''}`);
|
|
316
|
-
}
|
|
317
|
-
const manifestCompressionLevel = 0, animationCompressionLevel = 9, /**
|
|
318
|
-
* Prepare the dotLottie file.
|
|
319
|
-
*/ name = addExt('lottie', fileName) || `${createElementID()}.lottie`, dotlottie = {
|
|
320
|
-
'manifest.json': [
|
|
321
|
-
strToU8(JSON.stringify(manifest), true),
|
|
322
|
-
{
|
|
323
|
-
level: manifestCompressionLevel
|
|
324
|
-
}
|
|
325
|
-
]
|
|
326
|
-
};
|
|
327
|
-
// Add animations and assets to the dotLottie file
|
|
328
|
-
const { length } = animations;
|
|
329
|
-
for(let i = 0; i < length; i++){
|
|
330
|
-
const { length: jLen } = animations[i].assets;
|
|
331
|
-
// Prepare assets
|
|
332
|
-
for(let j = 0; j < jLen; j++){
|
|
333
|
-
const asset = animations[i].assets[j];
|
|
334
|
-
if (!asset.p || !isImage(asset) && !isAudio(asset)) {
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
const { p: file, u: path } = asset;
|
|
338
|
-
if (!file) {
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
// Original asset.id caused issues with multianimations
|
|
342
|
-
const assetId = createElementID(), isEncoded = file.startsWith('data:'), ext = isEncoded ? getExtFromB64(file) : getExt(file), /**
|
|
343
|
-
* Check if the asset is already base64-encoded. If not, get path, fetch it, and encode it.
|
|
344
|
-
*/ dataURL = isEncoded ? file : await fileToBase64(path ? path.endsWith('/') && `${path}${file}` || `${path}/${file}` : file);
|
|
345
|
-
// Asset is encoded
|
|
346
|
-
// eslint-disable-next-line require-atomic-updates
|
|
347
|
-
animations[i].assets[j].e = 1;
|
|
348
|
-
// eslint-disable-next-line require-atomic-updates
|
|
349
|
-
animations[i].assets[j].p = `${assetId}.${ext}`;
|
|
350
|
-
// Asset is embedded, so path empty string
|
|
351
|
-
// eslint-disable-next-line require-atomic-updates
|
|
352
|
-
animations[i].assets[j].u = '';
|
|
353
|
-
dotlottie[`${isAudio(asset) ? 'audio' : 'images'}/${assetId}.${ext}`] = [
|
|
354
|
-
base64ToU8(dataURL),
|
|
355
|
-
{
|
|
356
|
-
level: animationCompressionLevel
|
|
357
|
-
}
|
|
358
|
-
];
|
|
359
|
-
}
|
|
360
|
-
// Prepare expressions
|
|
361
|
-
const { length: kLen } = animations[i].layers;
|
|
362
|
-
for(let k = 0; k < kLen; k++){
|
|
363
|
-
const { ks: shape } = animations[i].layers[k], props = Object.keys(shape), { length: pLen } = props;
|
|
364
|
-
for(let p = 0; p < pLen; p++){
|
|
365
|
-
const { x: expression } = shape[props[p]];
|
|
366
|
-
if (!expression) {
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
// Base64 Encode to handle compression
|
|
370
|
-
// @ts-expect-error: We have checked this property is set
|
|
371
|
-
animations[i].layers[k].ks[props[p]].x = btoa(expression);
|
|
372
|
-
// Set e (encoded) to 1
|
|
373
|
-
// @ts-expect-error: We have checked this property is set
|
|
374
|
-
animations[i].layers[k].ks[props[p]].e = 1;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
dotlottie[`a/${manifest.animations[i].id}.json`] = [
|
|
378
|
-
strToU8(JSON.stringify(animations[i]), true),
|
|
379
|
-
{
|
|
380
|
-
level: animationCompressionLevel
|
|
381
|
-
}
|
|
382
|
-
];
|
|
383
|
-
}
|
|
384
|
-
const buffer = await getArrayBuffer(dotlottie);
|
|
385
|
-
if (shouldDownload) {
|
|
386
|
-
download(buffer, {
|
|
387
|
-
mimeType: 'application/zip',
|
|
388
|
-
name
|
|
389
|
-
});
|
|
390
|
-
return null;
|
|
391
|
-
}
|
|
392
|
-
return buffer;
|
|
393
|
-
} catch (error) {
|
|
394
|
-
console.error(handleErrors(error).message);
|
|
395
|
-
return null;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
function createJSON({ animation, fileName, shouldDownload }) {
|
|
400
|
-
try {
|
|
401
|
-
if (!animation) {
|
|
402
|
-
throw new Error('createJSON: Missing or malformed required parameter(s):\n - animation\n\'');
|
|
403
|
-
}
|
|
404
|
-
const name = addExt('json', fileName) || `${createElementID()}.json`, jsonString = JSON.stringify(animation);
|
|
405
|
-
if (shouldDownload) {
|
|
406
|
-
download(jsonString, {
|
|
407
|
-
mimeType: 'application/json',
|
|
408
|
-
name
|
|
409
|
-
});
|
|
410
|
-
return null;
|
|
411
|
-
}
|
|
412
|
-
return jsonString;
|
|
413
|
-
} catch (error) {
|
|
414
|
-
console.error(handleErrors(error).message);
|
|
415
|
-
return null;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const getMimeFromExt = (ext)=>{
|
|
420
|
-
switch(ext){
|
|
421
|
-
case 'svg':
|
|
422
|
-
case 'svg+xml':
|
|
423
|
-
{
|
|
424
|
-
return 'image/svg+xml';
|
|
425
|
-
}
|
|
426
|
-
case 'jpg':
|
|
427
|
-
case 'jpeg':
|
|
428
|
-
{
|
|
429
|
-
return 'image/jpeg';
|
|
430
|
-
}
|
|
431
|
-
case 'png':
|
|
432
|
-
case 'gif':
|
|
433
|
-
case 'webp':
|
|
434
|
-
case 'avif':
|
|
435
|
-
{
|
|
436
|
-
return `image/${ext}`;
|
|
437
|
-
}
|
|
438
|
-
case 'mp3':
|
|
439
|
-
case 'mpeg':
|
|
440
|
-
case 'wav':
|
|
441
|
-
{
|
|
442
|
-
return `audio/${ext}`;
|
|
443
|
-
}
|
|
444
|
-
default:
|
|
445
|
-
{
|
|
446
|
-
return '';
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}, isBase64 = (str)=>{
|
|
450
|
-
if (!str) {
|
|
451
|
-
return false;
|
|
452
|
-
}
|
|
453
|
-
const regex = /^(?:[0-9a-z+/]{4})*(?:[0-9a-z+/]{2}==|[0-9a-z+/]{3}=)?$/i;
|
|
454
|
-
return regex.test(parseBase64(str));
|
|
455
|
-
};
|
|
456
|
-
async function resolveAssets(unzipped, assets) {
|
|
457
|
-
if (!Array.isArray(assets)) {
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
const toResolve = [], { length } = assets;
|
|
461
|
-
for(let i = 0; i < length; i++){
|
|
462
|
-
if (!isAudio(assets[i]) && !isImage(assets[i])) {
|
|
463
|
-
continue;
|
|
464
|
-
}
|
|
465
|
-
const type = isImage(assets[i]) ? 'images' : 'audio', u8 = unzipped?.[`${type}/${assets[i].p}`];
|
|
466
|
-
if (!u8) {
|
|
467
|
-
continue;
|
|
468
|
-
}
|
|
469
|
-
toResolve.push(new Promise((resolveAsset)=>{
|
|
470
|
-
let assetB64;
|
|
471
|
-
if (isServer) {
|
|
472
|
-
assetB64 = Buffer.from(u8).toString('base64');
|
|
473
|
-
} else {
|
|
474
|
-
let result = '';
|
|
475
|
-
const { length: jLen } = u8;
|
|
476
|
-
for(let j = 0; j < jLen; j++){
|
|
477
|
-
result += String.fromCharCode(u8[j]);
|
|
478
|
-
}
|
|
479
|
-
assetB64 = btoa(result);
|
|
480
|
-
}
|
|
481
|
-
assets[i].p = assets[i].p?.startsWith('data:') || isBase64(assets[i].p) ? assets[i].p : `data:${getMimeFromExt(getExt(assets[i].p))};base64,${assetB64}`;
|
|
482
|
-
assets[i].e = 1;
|
|
483
|
-
assets[i].u = '';
|
|
484
|
-
resolveAsset();
|
|
485
|
-
}));
|
|
486
|
-
}
|
|
487
|
-
await Promise.all(toResolve);
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
const unzip = async (resp)=>{
|
|
491
|
-
const u8 = new Uint8Array(await resp.arrayBuffer()), unzipped = await new Promise((resolve, reject)=>{
|
|
492
|
-
unzip$1(u8, (err, file)=>{
|
|
493
|
-
if (err) {
|
|
494
|
-
reject(err);
|
|
495
|
-
}
|
|
496
|
-
resolve(file);
|
|
497
|
-
});
|
|
498
|
-
});
|
|
499
|
-
return unzipped;
|
|
500
|
-
}, getManifest = (unzipped)=>{
|
|
501
|
-
const file = strFromU8(unzipped['manifest.json'], false), manifest = JSON.parse(file);
|
|
502
|
-
if (!('animations' in manifest)) {
|
|
503
|
-
throw new Error('Manifest not found');
|
|
504
|
-
}
|
|
505
|
-
if (manifest.animations.length === 0) {
|
|
506
|
-
throw new Error('No animations listed in manifest');
|
|
507
|
-
}
|
|
508
|
-
return manifest;
|
|
509
|
-
}, prepareString = (str)=>str.replaceAll(new RegExp(/"""/, 'g'), '""').replaceAll(/(["'])(.*?)\1/g, (_match, quote, content)=>{
|
|
510
|
-
/**
|
|
511
|
-
* TODO: This caused text layers and expressions to be mangled
|
|
512
|
-
* Consider a more nuanced sanitaiton, if at all.
|
|
513
|
-
*/ // const replacedContent = content.replaceAll(/[^\w\s.#]/g, '')
|
|
514
|
-
return `${quote}${content}${quote}`;
|
|
515
|
-
});
|
|
516
|
-
async function getLottieJSON(resp) {
|
|
517
|
-
const unzipped = await unzip(resp), manifest = getManifest(unzipped), data = [], toResolve = [], { length } = manifest.animations;
|
|
518
|
-
/**
|
|
519
|
-
* Check whether Lottie animations folder is abbreviated.
|
|
520
|
-
*/ let animationsFolder = 'animations';
|
|
521
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
522
|
-
if (unzipped[`a/${manifest.animations[0].id}.json`]) {
|
|
523
|
-
animationsFolder = 'a';
|
|
524
|
-
}
|
|
525
|
-
for(let i = 0; i < length; i++){
|
|
526
|
-
const str = strFromU8(unzipped[`${animationsFolder}/${manifest.animations[i].id}.json`]), lottie = JSON.parse(prepareString(str));
|
|
527
|
-
// Handle Expressions
|
|
528
|
-
const { length: jLen } = lottie.layers;
|
|
529
|
-
for(let j = 0; j < jLen; j++){
|
|
530
|
-
const { ks: shape } = lottie.layers[j], props = Object.keys(shape), { length: pLen } = props;
|
|
531
|
-
for(let p = 0; p < pLen; p++){
|
|
532
|
-
const { e: isEncoded, x: expression } = shape[props[p]];
|
|
533
|
-
if (!expression || !isEncoded) {
|
|
534
|
-
continue;
|
|
535
|
-
}
|
|
536
|
-
// Base64 Decode to handle compression
|
|
537
|
-
// @ts-expect-error
|
|
538
|
-
lottie.layers[j].ks[props[p]].x = atob(expression);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
toResolve.push(resolveAssets(unzipped, lottie.assets));
|
|
542
|
-
data.push(lottie);
|
|
543
|
-
}
|
|
544
|
-
await Promise.all(toResolve);
|
|
545
|
-
return {
|
|
546
|
-
data,
|
|
547
|
-
manifest
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
async function getAnimationData(input) {
|
|
552
|
-
try {
|
|
553
|
-
if (!input || typeof input !== 'string' && typeof input !== 'object') {
|
|
554
|
-
throw new Error('Broken file or invalid file format');
|
|
555
|
-
}
|
|
556
|
-
if (typeof input !== 'string') {
|
|
557
|
-
const animations = Array.isArray(input) ? input : [
|
|
558
|
-
input
|
|
559
|
-
];
|
|
560
|
-
return {
|
|
561
|
-
animations,
|
|
562
|
-
isDotLottie: false,
|
|
563
|
-
manifest: null
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
const result = await fetch(input, {
|
|
567
|
-
headers: {
|
|
568
|
-
'Content-Type': 'application/json; charset=UTF-8'
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
if (!result.ok) {
|
|
572
|
-
const error = new Error(result.statusText);
|
|
573
|
-
throw error;
|
|
574
|
-
}
|
|
575
|
-
/**
|
|
576
|
-
* Check if file is JSON, first by parsing headers for content-type,
|
|
577
|
-
* than by parsing filename, then – if filename has no extension – by
|
|
578
|
-
* cloning the response and parsing response for content.
|
|
579
|
-
*/ let isJSON = true;
|
|
580
|
-
const contentType = result.headers.get('content-type');
|
|
581
|
-
if (contentType === 'application/zip+dotlottie') {
|
|
582
|
-
isJSON = false;
|
|
583
|
-
}
|
|
584
|
-
if (isJSON) {
|
|
585
|
-
const ext = getExt(input);
|
|
586
|
-
if (ext === 'json') {
|
|
587
|
-
const lottie = await result.json();
|
|
588
|
-
return {
|
|
589
|
-
animations: [
|
|
590
|
-
lottie
|
|
591
|
-
],
|
|
592
|
-
isDotLottie: false,
|
|
593
|
-
manifest: null
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
const text = await result.clone().text();
|
|
597
|
-
try {
|
|
598
|
-
const lottie = JSON.parse(text);
|
|
599
|
-
return {
|
|
600
|
-
animations: [
|
|
601
|
-
lottie
|
|
602
|
-
],
|
|
603
|
-
isDotLottie: false,
|
|
604
|
-
manifest: null
|
|
605
|
-
};
|
|
606
|
-
} catch (error) {
|
|
607
|
-
/* empty */ }
|
|
608
|
-
}
|
|
609
|
-
const { data, manifest } = await getLottieJSON(result);
|
|
610
|
-
return {
|
|
611
|
-
animations: data,
|
|
612
|
-
isDotLottie: true,
|
|
613
|
-
manifest
|
|
614
|
-
};
|
|
615
|
-
} catch (error) {
|
|
616
|
-
console.error(handleErrors(error).message);
|
|
617
|
-
return {
|
|
618
|
-
animations: undefined,
|
|
619
|
-
isDotLottie: false,
|
|
620
|
-
manifest: null
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
}
|
|
288
|
+
}, frameOutput = (frame)=>((frame ?? 0) + 1).toString().padStart(3, '0');
|
|
624
289
|
|
|
625
|
-
const generator = '@aarsteinmedia/dotlottie-player';
|
|
626
290
|
/**
|
|
627
291
|
* DotLottie Player Web Component.
|
|
628
292
|
*/ class DotLottiePlayer extends PropertyCallbackElement {
|
|
@@ -750,6 +414,9 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
750
414
|
}
|
|
751
415
|
return 0;
|
|
752
416
|
}
|
|
417
|
+
get isDotLottie() {
|
|
418
|
+
return this._isDotLottie;
|
|
419
|
+
}
|
|
753
420
|
/**
|
|
754
421
|
* Loop animation.
|
|
755
422
|
*/ set loop(value) {
|
|
@@ -846,7 +513,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
846
513
|
return Boolean(val === 'true' || val === '' || val === '1');
|
|
847
514
|
}
|
|
848
515
|
constructor(){
|
|
849
|
-
super(), /**
|
|
516
|
+
super(), this.addAnimation = addAnimation, this.convert = convert, /**
|
|
850
517
|
* Player state.
|
|
851
518
|
*/ this.playerState = PlayerState.Loading, /**
|
|
852
519
|
* Animation Container.
|
|
@@ -894,7 +561,6 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
894
561
|
this.snapshot = this.snapshot.bind(this);
|
|
895
562
|
this.toggleLoop = this.toggleLoop.bind(this);
|
|
896
563
|
this.toggleBoomerang = this.toggleBoomerang.bind(this);
|
|
897
|
-
this.convert = this.convert.bind(this);
|
|
898
564
|
this.destroy = this.destroy.bind(this);
|
|
899
565
|
this.template = document.createElement('template');
|
|
900
566
|
this.shadow = this.attachShadow({
|
|
@@ -902,57 +568,6 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
902
568
|
});
|
|
903
569
|
}
|
|
904
570
|
/**
|
|
905
|
-
* Creates a new dotLottie file, by combinig several animations.
|
|
906
|
-
* If set to false the function returns an ArrayBuffer. Defaults to true.
|
|
907
|
-
*/ async addAnimation(configs, fileName, shouldDownload = true) {
|
|
908
|
-
// Initialize meta object for animation, with fallbacks for
|
|
909
|
-
// when the method is called indepenently
|
|
910
|
-
const { animations = [], manifest = {
|
|
911
|
-
animations: this.src ? [
|
|
912
|
-
{
|
|
913
|
-
id: this._identifier
|
|
914
|
-
}
|
|
915
|
-
] : []
|
|
916
|
-
} } = this.src ? await getAnimationData(this.src) : {};
|
|
917
|
-
try {
|
|
918
|
-
if (!manifest) {
|
|
919
|
-
throw new Error('Manifest is not set');
|
|
920
|
-
}
|
|
921
|
-
manifest.generator = generator;
|
|
922
|
-
const { length } = configs;
|
|
923
|
-
for(let i = 0; i < length; i++){
|
|
924
|
-
const { url } = configs[i], { animations: animationsToAdd } = await getAnimationData(url);
|
|
925
|
-
if (!animationsToAdd) {
|
|
926
|
-
throw new Error('No animation loaded');
|
|
927
|
-
}
|
|
928
|
-
if (manifest.animations.some(({ id })=>id === configs[i].id)) {
|
|
929
|
-
throw new Error('Duplicate id for animation');
|
|
930
|
-
}
|
|
931
|
-
manifest.animations = [
|
|
932
|
-
...manifest.animations,
|
|
933
|
-
{
|
|
934
|
-
id: configs[i].id
|
|
935
|
-
}
|
|
936
|
-
];
|
|
937
|
-
animations.push(...animationsToAdd);
|
|
938
|
-
}
|
|
939
|
-
return {
|
|
940
|
-
result: await createDotLottie({
|
|
941
|
-
animations,
|
|
942
|
-
fileName,
|
|
943
|
-
manifest,
|
|
944
|
-
shouldDownload
|
|
945
|
-
}),
|
|
946
|
-
success: true
|
|
947
|
-
};
|
|
948
|
-
} catch (error) {
|
|
949
|
-
return {
|
|
950
|
-
error: handleErrors(error).message,
|
|
951
|
-
success: false
|
|
952
|
-
};
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
/**
|
|
956
571
|
* Runs when the value of an attribute is changed on the component.
|
|
957
572
|
*/ async attributeChangedCallback(name, _oldValue, value) {
|
|
958
573
|
if (!this._lottieInstance || !this.shadow) {
|
|
@@ -1027,50 +642,29 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1027
642
|
}
|
|
1028
643
|
/**
|
|
1029
644
|
* Initialize everything on component first render.
|
|
1030
|
-
*/
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
}
|
|
1053
|
-
let animations = animationsFromProps;
|
|
1054
|
-
if (!animations) {
|
|
1055
|
-
const animationData = await getAnimationData(src);
|
|
1056
|
-
animations = animationData.animations;
|
|
1057
|
-
}
|
|
1058
|
-
if (typeCheck || this._isDotLottie) {
|
|
1059
|
-
return createJSON({
|
|
1060
|
-
animation: animations?.[0],
|
|
1061
|
-
fileName: `${getFilename(fileName || src || 'converted')}.json`,
|
|
1062
|
-
shouldDownload
|
|
1063
|
-
});
|
|
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));
|
|
1064
667
|
}
|
|
1065
|
-
return createDotLottie({
|
|
1066
|
-
animations,
|
|
1067
|
-
fileName: `${getFilename(fileName || src || 'converted')}.lottie`,
|
|
1068
|
-
manifest: {
|
|
1069
|
-
...manifest ?? this._manifest,
|
|
1070
|
-
generator
|
|
1071
|
-
},
|
|
1072
|
-
shouldDownload
|
|
1073
|
-
});
|
|
1074
668
|
}
|
|
1075
669
|
/**
|
|
1076
670
|
* Destroy animation and element.
|
|
@@ -1121,12 +715,12 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1121
715
|
/**
|
|
1122
716
|
* Initialize Lottie Web player.
|
|
1123
717
|
*/ async load(src) {
|
|
1124
|
-
if (!this.shadowRoot || !src) {
|
|
1125
|
-
return;
|
|
1126
|
-
}
|
|
1127
|
-
this.source = src;
|
|
1128
|
-
// Load the resource
|
|
1129
718
|
try {
|
|
719
|
+
if (!this.shadowRoot || !src) {
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
this.source = src;
|
|
723
|
+
// Load the resource
|
|
1130
724
|
const { animations, isDotLottie, manifest } = await getAnimationData(src);
|
|
1131
725
|
if (!animations || animations.some((animation)=>!this._isLottie(animation))) {
|
|
1132
726
|
throw new Error('Broken or corrupted file');
|
|
@@ -1139,7 +733,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1139
733
|
manifest.animations[0].autoplay = this.autoplay;
|
|
1140
734
|
manifest.animations[0].loop = this.loop;
|
|
1141
735
|
}
|
|
1142
|
-
this._isDotLottie =
|
|
736
|
+
this._isDotLottie = isDotLottie;
|
|
1143
737
|
this._animations = animations;
|
|
1144
738
|
this._manifest = manifest ?? {
|
|
1145
739
|
animations: [
|
|
@@ -1164,30 +758,37 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1164
758
|
...this._getOptions(),
|
|
1165
759
|
animationData: animations[this._currentAnimation]
|
|
1166
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
|
+
}
|
|
1167
787
|
} catch (error) {
|
|
788
|
+
console.error(error);
|
|
1168
789
|
this._errorMessage = handleErrors(error).message;
|
|
1169
790
|
this.playerState = PlayerState.Error;
|
|
1170
791
|
this.dispatchEvent(new CustomEvent(PlayerEvents.Error));
|
|
1171
|
-
return;
|
|
1172
|
-
}
|
|
1173
|
-
this._addEventListeners();
|
|
1174
|
-
const speed = this._multiAnimationSettings[this._currentAnimation]?.speed ?? this.speed, direction = this._multiAnimationSettings[this._currentAnimation]?.direction ?? this.direction;
|
|
1175
|
-
// Set initial playback speed and direction
|
|
1176
|
-
this._lottieInstance.setSpeed(speed);
|
|
1177
|
-
this._lottieInstance.setDirection(direction);
|
|
1178
|
-
this._lottieInstance.setSubframe(Boolean(this.subframe));
|
|
1179
|
-
// Start playing if autoplay is enabled
|
|
1180
|
-
if (this.autoplay || this.animateOnScroll) {
|
|
1181
|
-
if (this.direction === -1) {
|
|
1182
|
-
this.seek('99%');
|
|
1183
|
-
}
|
|
1184
|
-
if (!('IntersectionObserver' in window)) {
|
|
1185
|
-
if (!this.animateOnScroll) {
|
|
1186
|
-
this.play();
|
|
1187
|
-
}
|
|
1188
|
-
this._playerState.visible = true;
|
|
1189
|
-
}
|
|
1190
|
-
this._addIntersectionObserver();
|
|
1191
792
|
}
|
|
1192
793
|
}
|
|
1193
794
|
/**
|
|
@@ -1236,7 +837,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1236
837
|
if (!this.shadow) {
|
|
1237
838
|
return;
|
|
1238
839
|
}
|
|
1239
|
-
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');
|
|
1240
841
|
if (!(togglePlay instanceof HTMLButtonElement) || !(stop instanceof HTMLButtonElement) || !(next instanceof HTMLButtonElement) || !(prev instanceof HTMLButtonElement) || !(seeker instanceof HTMLInputElement) || !(progress instanceof HTMLProgressElement)) {
|
|
1241
842
|
return;
|
|
1242
843
|
}
|
|
@@ -1244,9 +845,9 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1244
845
|
togglePlay.dataset.active = (value === PlayerState.Playing || value === PlayerState.Paused).toString();
|
|
1245
846
|
stop.dataset.active = (value === PlayerState.Stopped).toString();
|
|
1246
847
|
if (value === PlayerState.Playing) {
|
|
1247
|
-
togglePlay.innerHTML =
|
|
848
|
+
togglePlay.innerHTML = pauseIcon;
|
|
1248
849
|
} else {
|
|
1249
|
-
togglePlay.innerHTML =
|
|
850
|
+
togglePlay.innerHTML = playIcon;
|
|
1250
851
|
}
|
|
1251
852
|
}
|
|
1252
853
|
if (name === '_seeker' && typeof value === 'number') {
|
|
@@ -1261,17 +862,10 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1261
862
|
next.hidden = value + 1 >= this._animations.length;
|
|
1262
863
|
prev.hidden = !value;
|
|
1263
864
|
}
|
|
1264
|
-
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) {
|
|
1265
866
|
popover.hidden = !value;
|
|
1266
|
-
|
|
867
|
+
convertButton.hidden = false;
|
|
1267
868
|
snapshot.hidden = this.renderer !== RendererType.SVG;
|
|
1268
|
-
if (this._isDotLottie) {
|
|
1269
|
-
convert.ariaLabel = 'Convert dotLottie to JSON';
|
|
1270
|
-
convert.innerHTML = convert.innerHTML.replace('dotLottie', 'JSON');
|
|
1271
|
-
} else {
|
|
1272
|
-
convert.ariaLabel = 'Convert JSON animation to dotLottie format';
|
|
1273
|
-
convert.innerHTML = convert.innerHTML.replace('JSON', 'dotLottie');
|
|
1274
|
-
}
|
|
1275
869
|
}
|
|
1276
870
|
}
|
|
1277
871
|
/**
|
|
@@ -1335,13 +929,11 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1335
929
|
}
|
|
1336
930
|
/**
|
|
1337
931
|
* Set Multi-animation settings.
|
|
1338
|
-
*
|
|
1339
932
|
*/ setMultiAnimationSettings(settings) {
|
|
1340
933
|
this._multiAnimationSettings = settings;
|
|
1341
934
|
}
|
|
1342
935
|
/**
|
|
1343
936
|
* Set playback segment.
|
|
1344
|
-
*
|
|
1345
937
|
*/ setSegment(segment) {
|
|
1346
938
|
this._segment = segment;
|
|
1347
939
|
}
|
|
@@ -1411,7 +1003,7 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1411
1003
|
/**
|
|
1412
1004
|
* Toggle Boomerang.
|
|
1413
1005
|
*/ toggleBoomerang() {
|
|
1414
|
-
const curr = this._multiAnimationSettings[this._currentAnimation];
|
|
1006
|
+
const curr = this._multiAnimationSettings[this._currentAnimation] ?? {};
|
|
1415
1007
|
if (curr.mode !== undefined) {
|
|
1416
1008
|
if (curr.mode === PlayMode.Normal) {
|
|
1417
1009
|
curr.mode = PlayMode.Bounce;
|
|
@@ -1489,7 +1081,6 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1489
1081
|
}
|
|
1490
1082
|
/**
|
|
1491
1083
|
* Handles click and drag actions on the progress track.
|
|
1492
|
-
*
|
|
1493
1084
|
*/ _handleSeekChange({ target }) {
|
|
1494
1085
|
if (!(target instanceof HTMLInputElement) || !this._lottieInstance || isNaN(Number(target.value))) {
|
|
1495
1086
|
return;
|
|
@@ -1865,11 +1456,10 @@ const generator = '@aarsteinmedia/dotlottie-player';
|
|
|
1865
1456
|
|
|
1866
1457
|
/**
|
|
1867
1458
|
* Expose DotLottiePlayer class as global variable.
|
|
1868
|
-
*
|
|
1869
1459
|
*/ globalThis.dotLottiePlayer = ()=>new DotLottiePlayer();
|
|
1870
1460
|
const tagName = 'dotlottie-player';
|
|
1871
1461
|
if (!isServer) {
|
|
1872
1462
|
customElements.define(tagName, DotLottiePlayer);
|
|
1873
1463
|
}
|
|
1874
1464
|
|
|
1875
|
-
export {
|
|
1465
|
+
export { PlayerState, DotLottiePlayer as default, tagName };
|