@aarsteinmedia/dotlottie-player 6.4.10 → 6.5.1

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.
@@ -71,7 +71,7 @@ if (isServer) {
71
71
  }
72
72
  }
73
73
 
74
- 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 & 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 .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 & *::-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";
74
+ var css_248z = "*{box-sizing:border-box}:host{--lottie-player-toolbar-height:35px;--lottie-player-toolbar-background-color:#fff;--lottie-player-toolbar-icon-color:#000;--lottie-player-toolbar-icon-hover-color:#000;--lottie-player-toolbar-icon-active-color:#4285f4;--lottie-player-seeker-track-color:#0003;--lottie-player-seeker-thumb-color:#4285f4;--lottie-player-seeker-display:block;height:100%;width:100%;&:not([hidden]){display:block}.main{display:flex;flex-direction:column;height:100%;margin:0;padding:0;width:100%}.animation{contain:content;display:flex;height:100%;margin:0;padding:0;width:100%;& svg g{will-change:transform}}[data-controls=true] .animation{height:calc(100% - 35px)}.animation-container{position:relative}.popover{animation:fade-in .2s ease-in-out;background-color:var(--lottie-player-toolbar-background-color);border:2px solid var(--lottie-player-toolbar-icon-color);border-radius:5px;bottom:40px;padding:10px 15px;position:absolute;right:5px;&:before{border:7px solid #0000;border-top:7px solid var(--lottie-player-toolbar-icon-color);content:\"\";height:0;margin-right:-7px;pointer-events:none;position:absolute;right:10px;top:100%;width:0}}.error{align-items:center;display:flex;height:100%;justify-content:center;margin:auto;& svg{height:auto;width:100%}}.toolbar{background:var(--lottie-player-toolbar-background-color);border-radius:5px;display:flex;gap:5px;height:35px;margin:0;padding:5px;place-items:center center;&.has-error{opacity:.5;pointer-events:none}& button{fill:var(--lottie-player-toolbar-icon-color);align-items:center;background:none;border:0;color:var(--lottie-player-toolbar-icon-color);cursor:pointer;gap:5px;height:100%;margin:0;opacity:.9;outline:0;padding:0;&:not([hidden]){display:flex}&:hover{opacity:1}&[data-active=true]{fill:var(--lottie-player-toolbar-icon-active-color);opacity:1}&:disabled{opacity:.5}&:focus{outline:0}& svg{pointer-events:none;&>*{fill:inherit}}&.disabled svg{display:none}}}.progress-container{position:relative;width:100%;&.simple{margin-right:12px}}& progress{appearance:none;background-color:var(--lottie-player-seeker-track-color);border:0;border-radius:3px;height:5px;left:0;margin:7.5px 0;outline:none;pointer-events:none;position:absolute;top:0;width:100%;&::-webkit-progress-inner-element{border-radius:3px;overflow:hidden}&::-webkit-slider-runnable-track{background-color:initial}&::-webkit-progress-value{background-color:var(--lottie-player-seeker-thumb-color)}}.seeker{appearance:none;background-color:initial;border:0;border-radius:3px;color:var(--lottie-player-seeker-thumb-color);cursor:pointer;display:var(--lottie-player-seeker-display);height:20px;margin:0;outline:none;padding:7.5px 0;position:relative;width:100%;z-index:1;&::-webkit-slider-runnable-track,&::-webkit-slider-thumb{appearance:none;outline:none}&::-webkit-slider-thumb{background-color:var(--lottie-player-seeker-thumb-color);border:0;border-radius:50%;cursor:pointer;height:15px;transform:scale(0);-webkit-transition:transform .2s ease-in-out;transition:transform .2s ease-in-out;width:15px}&:focus::-webkit-slider-thumb,&:hover::-webkit-slider-thumb{transform:scale(1)}&::-moz-range-progress{background-color:var(--lottie-player-seeker-thumb-color);border-radius:3px;height:5px}&::-moz-range-thumb{background-color:var(--lottie-player-seeker-thumb-color);border:0;border-radius:50%;cursor:pointer;height:15px;transform:scale(0);-moz-transition:transform .2s ease-in-out;transition:transform .2s ease-in-out;width:15px}&:focus::-moz-range-thumb,&:hover::-moz-range-thumb{transform:scale(1)}&::-ms-track{background:#0000;border-color:#0000;color:#0000;cursor:pointer;height:5px;width:100%}&::-ms-fill-upper{background:var(--lottie-player-seeker-track-color);border-radius:3px}&::-ms-fill-lower{background-color:var(--lottie-player-seeker-thumb-color);border-radius:3px}&::-ms-thumb{background:var(--lottie-player-seeker-thumb-color);border:0;border-radius:50%;cursor:pointer;height:15px;transform:scale(0);-ms-transition:transform .2s ease-in-out;transition:transform .2s ease-in-out;width:15px}&:hover::-ms-thumb{transform:scale(1)}&:focus{&::-ms-thumb{transform:scale(1)}&::-ms-fill-lower,&::-ms-fill-upper{background:var(--lottie-player-seeker-track-color)}}}& ::-moz-progress-bar{background-color:var(--lottie-player-seeker-thumb-color)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@media (prefers-color-scheme:dark){:host{--lottie-player-toolbar-background-color:#000;--lottie-player-toolbar-icon-color:#fff;--lottie-player-toolbar-icon-hover-color:#fff;--lottie-player-seeker-track-color:#fff9}}";
75
75
 
76
76
  let dotlottieTools = null, loadPromise = null;
77
77
  function loadDotLottieTools() {
@@ -92,87 +92,25 @@ function loadDotLottieTools() {
92
92
  return loadPromise;
93
93
  }
94
94
 
95
- const boomerangIcon = /* HTML */ `
96
- <svg width="24" height="24" aria-hidden="true" focusable="false">
97
- <path
98
- 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"
99
- />
100
- </svg>
101
- `;
95
+ const boomerangIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="m11.8 13.2-.3.3c-.5.5-1.1 1.1-1.7 1.5-.5.4-1 .6-1.5.8-.5.2-1.1.3-1.6.3s-1-.1-1.5-.3c-.6-.2-1-.5-1.4-1-.5-.6-.8-1.2-.9-1.9-.2-.9-.1-1.8.3-2.6.3-.7.8-1.2 1.3-1.6.3-.2.6-.4 1-.5.2-.2.5-.2.8-.3.3 0 .7-.1 1 0 .3 0 .6.1.9.2.9.3 1.7.9 2.4 1.5.4.4.8.7 1.1 1.1l.1.1.4-.4c.6-.6 1.2-1.2 1.9-1.6.5-.3 1-.6 1.5-.7.4-.1.7-.2 1-.2h.9c1 .1 1.9.5 2.6 1.4.4.5.7 1.1.8 1.8.2.9.1 1.7-.2 2.5-.4.9-1 1.5-1.8 2-.4.2-.7.4-1.1.4-.4.1-.8.1-1.2.1-.5 0-.9-.1-1.3-.3-.8-.3-1.5-.9-2.1-1.5-.4-.4-.8-.7-1.1-1.1h-.3zm-1.1-1.1c-.1-.1-.1-.1 0 0-.3-.3-.6-.6-.8-.9-.5-.5-1-.9-1.6-1.2-.4-.3-.8-.4-1.3-.4-.4 0-.8 0-1.1.2-.5.2-.9.6-1.1 1-.2.3-.3.7-.3 1.1 0 .3 0 .6.1.9.1.5.4.9.8 1.2.5.4 1.1.5 1.7.5.5 0 1-.2 1.5-.5.6-.4 1.1-.8 1.6-1.3.1-.3.3-.5.5-.6zM13 12c.5.5 1 1 1.5 1.4.5.5 1.1.9 1.9 1 .4.1.8 0 1.2-.1.3-.1.6-.3.9-.5.4-.4.7-.9.8-1.4.1-.5 0-.9-.1-1.4-.3-.8-.8-1.2-1.7-1.4-.4-.1-.8-.1-1.2 0-.5.1-1 .4-1.4.7-.5.4-1 .8-1.4 1.2-.2.2-.4.3-.5.5z"/></svg>`;
102
96
 
103
- const convertIcon = /* HTML */ `
104
- <svg
105
- width="24"
106
- height="24"
107
- aria-hidden="true"
108
- focusable="false"
109
- >
110
- <path
111
- 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"
112
- />
113
- </svg>
114
- `;
97
+ const convertIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M17.016 17.016v-4.031h1.969v6h-12v3l-3.984-3.984 3.984-3.984v3h10.031zM6.984 6.984v4.031H5.015v-6h12v-3l3.984 3.984-3.984 3.984v-3H6.984z"/></svg>`;
115
98
 
116
- const downloadIcon = /* HTML */ `
117
- <svg
118
- width="24"
119
- height="24"
120
- aria-hidden="true"
121
- focusable="false"
122
- >
123
- <path
124
- 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"
125
- />
126
- </svg>
127
- `;
99
+ const downloadIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M16.8 10.8 12 15.6l-4.8-4.8h3V3.6h3.6v7.2h3zM12 15.6H3v4.8h18v-4.8h-9zm7.8 2.4h-2.4v-1.2h2.4V18z"/></svg>`;
128
100
 
129
- const loopIcon = /* HTML */ `
130
- <svg width="24" height="24" aria-hidden="true" focusable="false">
131
- <path
132
- 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"
133
- />
134
- </svg>
135
- `;
101
+ const loopIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M17.016 17.016v-4.031h1.969v6h-12v3l-3.984-3.984 3.984-3.984v3h10.031zM6.984 6.984v4.031H5.015v-6h12v-3l3.984 3.984-3.984 3.984v-3H6.984z"/></svg>`;
136
102
 
137
- const nextIcon = /* HTML */ `
138
- <svg width="24" height="24" aria-hidden="true" focusable="false">
139
- <path d="m6.1 5.8 9.8 6.2-9.8 6.2V5.8zM16.4 5.8h1.5v12.4h-1.5z" />
140
- </svg>
141
- `;
103
+ const nextIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="m6.1 5.8 9.8 6.2-9.8 6.2V5.8zM16.4 5.8h1.5v12.4h-1.5z"/></svg>`;
142
104
 
143
- const pauseIcon = /* HTML */ `
144
- <svg width="24" height="24" aria-hidden="true" focusable="false">
145
- <path
146
- d="M14.016 5.016H18v13.969h-3.984V5.016zM6 18.984V5.015h3.984v13.969H6z"
147
- />
148
- </svg>
149
- `;
105
+ const pauseIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M14.016 5.016H18v13.969h-3.984V5.016zM6 18.984V5.015h3.984v13.969H6z"/></svg>`;
150
106
 
151
- const playIcon = /* HTML */ `
152
- <svg width="24" height="24" aria-hidden="true" focusable="false">
153
- <path d="M8.016 5.016L18.985 12 8.016 18.984V5.015z" />
154
- </svg>
155
- `;
107
+ const playIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M8.016 5.016L18.985 12 8.016 18.984V5.015z"/></svg>`;
156
108
 
157
- const prevIcon = /* HTML */ `
158
- <svg width="24" height="24" aria-hidden="true" focusable="false">
159
- <path d="M17.9 18.2 8.1 12l9.8-6.2v12.4zm-10.3 0H6.1V5.8h1.5v12.4z" />
160
- </svg>
161
- `;
109
+ const prevIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M17.9 18.2 8.1 12l9.8-6.2v12.4zm-10.3 0H6.1V5.8h1.5v12.4z"/></svg>`;
162
110
 
163
- const settingsIcon = /* HTML */ `
164
- <svg width="24" height="24" aria-hidden="true" focusable="false">
165
- <circle cx="12" cy="5.4" r="2.5" />
166
- <circle cx="12" cy="12" r="2.5" />
167
- <circle cx="12" cy="18.6" r="2.5" />
168
- </svg>
169
- `;
111
+ const settingsIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><circle cx="12" cy="5.4" r="2.5"/><circle cx="12" cy="12" r="2.5"/><circle cx="12" cy="18.6" r="2.5"/></svg>`;
170
112
 
171
- const stopIcon = /* HTML */ `
172
- <svg width="24" height="24" aria-hidden="true" focusable="false">
173
- <path d="M6 6h12v12H6V6z" />
174
- </svg>
175
- `;
113
+ const stopIcon = /* HTML */ `<svg width="24" height="24" aria-hidden="true" focusable="false"><path d="M6 6h12v12H6V6z"/></svg>`;
176
114
 
177
115
  var ObjectFit = /*#__PURE__*/ function(ObjectFit) {
178
116
  ObjectFit["Contain"] = "contain";
@@ -200,23 +138,49 @@ var PlayerState = /*#__PURE__*/ function(PlayerState) {
200
138
  PlayerState["Stopped"] = "stopped";
201
139
  return PlayerState;
202
140
  }({});
203
- const tagName = 'dotlottie-player';
204
141
 
205
- /**
206
- * Render Controls.
207
- */ function renderControls() {
142
+ function advancedButtons() {
208
143
  if (!this.shadow) {
209
- throw new Error('No Shadow Element');
210
- }
211
- const slot = this.shadow.querySelector('slot[name=controls]');
212
- if (!slot) {
213
144
  return;
214
145
  }
215
- if (!this.controls) {
216
- slot.innerHTML = '';
146
+ const toggleLoop = this.shadow.querySelector('.toggleLoop');
147
+ if (toggleLoop instanceof HTMLButtonElement) {
148
+ toggleLoop.onclick = this.toggleLoop;
149
+ }
150
+ const toggleBoomerang = this.shadow.querySelector('.toggleBoomerang');
151
+ if (toggleBoomerang instanceof HTMLButtonElement) {
152
+ toggleBoomerang.onclick = this.toggleBoomerang;
153
+ }
154
+ const convertButton = this.shadow.querySelector('.convert');
155
+ if (convertButton instanceof HTMLButtonElement) {
156
+ convertButton.onclick = async ()=>{
157
+ convertButton.disabled = true;
158
+ try {
159
+ const { convert } = await loadDotLottieTools();
160
+ await convert({
161
+ isDotLottie: this.isDotLottie,
162
+ manifest: this.getManifest(),
163
+ src: this.src || this.source
164
+ });
165
+ } finally{
166
+ convertButton.disabled = false;
167
+ }
168
+ };
169
+ }
170
+ const snapshot = this.shadow.querySelector('.snapshot');
171
+ if (snapshot instanceof HTMLButtonElement) {
172
+ snapshot.onclick = ()=>this.snapshot(true);
173
+ }
174
+ const toggleSettings = this.shadow.querySelector('.toggleSettings');
175
+ if (toggleSettings instanceof HTMLButtonElement) {
176
+ toggleSettings.onclick = this._handleSettingsClick;
177
+ toggleSettings.onblur = this._handleBlur;
178
+ }
179
+ }
180
+ function handleButtons() {
181
+ if (!this.shadow) {
217
182
  return;
218
183
  }
219
- 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="false">${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="${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" aria-label="Convert ${this.isDotLottie ? 'dotLottie animation to JSON format' : '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>`;
220
184
  const togglePlay = this.shadow.querySelector('.togglePlay');
221
185
  if (togglePlay instanceof HTMLButtonElement) {
222
186
  togglePlay.onclick = this.togglePlay;
@@ -244,41 +208,28 @@ const tagName = 'dotlottie-player';
244
208
  seeker.onchange = this._handleSeekChange;
245
209
  seeker.onmousedown = this._freeze;
246
210
  }
247
- if (!this.simple) {
248
- const toggleLoop = this.shadow.querySelector('.toggleLoop');
249
- if (toggleLoop instanceof HTMLButtonElement) {
250
- toggleLoop.onclick = this.toggleLoop;
251
- }
252
- const toggleBoomerang = this.shadow.querySelector('.toggleBoomerang');
253
- if (toggleBoomerang instanceof HTMLButtonElement) {
254
- toggleBoomerang.onclick = this.toggleBoomerang;
255
- }
256
- const convertButton = this.shadow.querySelector('.convert');
257
- if (convertButton instanceof HTMLButtonElement) {
258
- convertButton.onclick = async ()=>{
259
- convertButton.disabled = true;
260
- try {
261
- const { convert } = await loadDotLottieTools();
262
- await convert({
263
- isDotLottie: this.isDotLottie,
264
- manifest: this.getManifest(),
265
- src: this.src || this.source
266
- });
267
- } finally{
268
- convertButton.disabled = false;
269
- }
270
- };
271
- }
272
- const snapshot = this.shadow.querySelector('.snapshot');
273
- if (snapshot instanceof HTMLButtonElement) {
274
- snapshot.onclick = ()=>this.snapshot(true);
275
- }
276
- const toggleSettings = this.shadow.querySelector('.toggleSettings');
277
- if (toggleSettings instanceof HTMLButtonElement) {
278
- toggleSettings.onclick = this._handleSettingsClick;
279
- toggleSettings.onblur = this._handleBlur;
280
- }
211
+ if (this.simple) {
212
+ return;
213
+ }
214
+ advancedButtons.call(this);
215
+ }
216
+ /**
217
+ * Render Controls.
218
+ */ function renderControls() {
219
+ if (!this.shadow) {
220
+ throw new Error('No Shadow Element');
221
+ }
222
+ const slot = this.shadow.querySelector('slot[name=controls]');
223
+ if (!slot) {
224
+ return;
225
+ }
226
+ if (!this.controls) {
227
+ slot.innerHTML = '';
228
+ return;
281
229
  }
230
+ const convertLabel = this.isDotLottie ? 'dotLottie animation to JSON format' : 'JSON animation to dotLottie format', convertButtonText = this.isDotLottie ? 'Convert to JSON' : 'Convert to dotLottie';
231
+ 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="false">${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="${this._isSettingsOpen}" aria-controls="${this._identifier}-settings">${settingsIcon}</button><div id="${this._identifier}-settings" class="popover" hidden><button class="convert" aria-label="Convert ${convertLabel}" hidden>${convertIcon} ${convertButtonText}</button> <button class="snapshot" aria-label="Download still image">${downloadIcon} Download still image</button></div>`}</div>`;
232
+ handleButtons.call(this);
282
233
  }
283
234
  function updatePlayPauseButton(togglePlay, state) {
284
235
  const isActive = state === PlayerState.Playing || state === PlayerState.Paused;
@@ -310,9 +261,7 @@ var controls = /*#__PURE__*/Object.freeze({
310
261
  const lang = this.description ? document.documentElement.lang : 'en';
311
262
  langAttribute = `lang="${lang}"`;
312
263
  }
313
- this.template.innerHTML = /* HTML */ `<div class="animation-container main" data-controls="${this.controls ?? false}" ${langAttribute}><figure class="animation" style="background:${this.background}" ${this.description ? /* HTML */ `
314
- aria-label="${this.description}"
315
- ` : ''}></figure><slot name="controls"></slot></div>`;
264
+ this.template.innerHTML = /* HTML */ `<div class="animation-container main" data-controls="${this.controls ?? false}" ${langAttribute}><figure class="animation" style="background:${this.background}" ${this.description ? `aria-label="${this.description}"` : ''}></figure><slot name="controls"></slot></div>`;
316
265
  this.shadow.adoptedStyleSheets = [
317
266
  await DotLottiePlayerBase.styles()
318
267
  ];
@@ -383,6 +332,8 @@ var controls = /*#__PURE__*/Object.freeze({
383
332
  '1'
384
333
  ].includes(val);
385
334
 
335
+ const tagName = 'dotlottie-player', hasReducedMotion = !isServer && matchMedia('(prefers-reduced-motion: reduce)').matches, hasIOSupport = !isServer && 'IntersectionObserver' in window, hasVTSupport = !isServer && 'ViewTimeline' in window;
336
+
386
337
  const notImplemented = 'Method is not implemented', getStyles = async ()=>{
387
338
  const styleSheet = new CSSStyleSheet();
388
339
  await styleSheet.replace(css_248z);
@@ -713,15 +664,14 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
713
664
  * Player state.
714
665
  */ this.playerState = PlayerState.Loading, /**
715
666
  * Animation Container.
716
- */ this._container = null, this._DOMRect = null, this._errorMessage = 'Something went wrong', this._identifier = this.id || createElementID(), /**
667
+ */ this._container = null, this._errorMessage = 'Something went wrong', this._identifier = this.id || createElementID(), /**
717
668
  * Whether settings toolbar is open.
718
669
  */ this._isSettingsOpen = false, this._playerState = {
719
670
  count: 0,
671
+ frame: 0,
720
672
  loaded: false,
721
- prev: PlayerState.Loading,
722
- scrollTimeout: null,
723
- scrollY: 0,
724
- visible: false
673
+ playTimeout: null,
674
+ prev: PlayerState.Loading
725
675
  }, this._render = renderPlayer, /**
726
676
  * Seeker.
727
677
  */ this._seeker = 0, /**
@@ -730,7 +680,7 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
730
680
  * on load, if controls are visible.
731
681
  */ this._animations = [], this._controlsLoadId = 0, /**
732
682
  * Which animation to show, if several.
733
- */ this._currentAnimation = 0, this._errorLoadId = 0, this._isBounce = false, this._isDotLottie = false, this._lottieInstance = null, /**
683
+ */ this._currentAnimation = 0, this._errorLoadId = 0, this._isBounce = false, this._isDotLottie = false, this._isIntersecting = false, this._lottieInstance = null, /**
734
684
  * Multi-animation settings.
735
685
  */ this._multiAnimationSettings = [], this._renderControls = async ()=>{
736
686
  const slot = this.shadow?.querySelector('slot[name=controls]');
@@ -755,13 +705,13 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
755
705
  this._freeze = this._freeze.bind(this);
756
706
  this._handleBlur = this._handleBlur.bind(this);
757
707
  this._handleClick = this._handleClick.bind(this);
758
- this._handleScroll = this._handleScroll.bind(this);
759
708
  this._handleSeekChange = this._handleSeekChange.bind(this);
760
709
  this._handleWindowBlur = this._handleWindowBlur.bind(this);
761
710
  this._loopComplete = this._loopComplete.bind(this);
762
711
  this._mouseEnter = this._mouseEnter.bind(this);
763
712
  this._mouseLeave = this._mouseLeave.bind(this);
764
713
  this._onVisibilityChange = this._onVisibilityChange.bind(this);
714
+ this._scrollLoop = this._scrollLoop.bind(this);
765
715
  this._switchInstance = this._switchInstance.bind(this);
766
716
  this._handleSettingsClick = this._handleSettingsClick.bind(this);
767
717
  this.togglePlay = this.togglePlay.bind(this);
@@ -782,7 +732,8 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
782
732
  }
783
733
  /**
784
734
  * Runs when the value of an attribute is changed on the component.
785
- */ async attributeChangedCallback(name, _oldValue, value) {
735
+ */ // eslint-disable-next-line sonarjs/cognitive-complexity
736
+ async attributeChangedCallback(name, _oldValue, value) {
786
737
  if (!this._lottieInstance || !this.shadow || !this._container) {
787
738
  return;
788
739
  }
@@ -791,18 +742,17 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
791
742
  {
792
743
  if (value === '' || Boolean(value)) {
793
744
  this._lottieInstance.autoplay = false;
794
- addEventListener('scroll', this._handleScroll, {
795
- capture: true,
796
- passive: true
797
- });
745
+ if (this._isIntersecting) {
746
+ this._startScrollLoop();
747
+ }
798
748
  return;
799
749
  }
800
- removeEventListener('scroll', this._handleScroll, true);
750
+ this._stopScrollLoop();
801
751
  break;
802
752
  }
803
753
  case 'autoplay':
804
754
  {
805
- if (this.animateOnScroll || this.playOnVisible) {
755
+ if (this.animateOnScroll || this.playOnVisible || hasReducedMotion) {
806
756
  return;
807
757
  }
808
758
  if (value === '' || Boolean(value)) {
@@ -905,8 +855,8 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
905
855
  * Initialize everything on component first render.
906
856
  */ connectedCallback() {
907
857
  super.connectedCallback();
908
- try {
909
- void (async ()=>{
858
+ void (async ()=>{
859
+ try {
910
860
  await this._render();
911
861
  if (!this.shadow) {
912
862
  throw new Error('Missing Shadow element');
@@ -918,16 +868,13 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
918
868
  if (typeof document.hidden !== 'undefined') {
919
869
  document.addEventListener('visibilitychange', this._onVisibilityChange);
920
870
  }
921
- if (this._container) {
922
- this._DOMRect = this._container.getBoundingClientRect();
923
- }
924
871
  // Add intersection observer for detecting component being out-of-view.
925
872
  this._addIntersectionObserver();
926
873
  this.dispatchEvent(new CustomEvent(PlayerEvent.Rendered));
927
- })();
928
- } catch (error) {
929
- void this._handleError(error);
930
- }
874
+ } catch (error) {
875
+ void this._handleError(error);
876
+ }
877
+ })();
931
878
  }
932
879
  convert(_params) {
933
880
  throw new Error(notImplemented);
@@ -938,9 +885,11 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
938
885
  if (!this._lottieInstance?.destroy) {
939
886
  return;
940
887
  }
888
+ this._cancelScrollProbe();
941
889
  this.playerState = PlayerState.Destroyed;
942
890
  this._lottieInstance.destroy();
943
891
  this._lottieInstance = null;
892
+ this._stopScrollLoop();
944
893
  this.dispatchEvent(new CustomEvent(PlayerEvent.Destroyed));
945
894
  this.remove();
946
895
  document.removeEventListener('visibilitychange', this._onVisibilityChange);
@@ -949,9 +898,14 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
949
898
  * Cleanup on component destroy.
950
899
  */ disconnectedCallback() {
951
900
  // Remove intersection observer for detecting component being out-of-view
952
- if (this._intersectionObserver) {
953
- this._intersectionObserver.disconnect();
954
- this._intersectionObserver = undefined;
901
+ this._intersectionObserver?.disconnect();
902
+ this._intersectionObserver = undefined;
903
+ this._cancelScrollProbe();
904
+ if (this._playerState.scrollLoopId) {
905
+ cancelAnimationFrame(this._playerState.scrollLoopId);
906
+ }
907
+ if (this._playerState.playTimeout) {
908
+ clearTimeout(this._playerState.playTimeout);
955
909
  }
956
910
  // Remove the attached Visibility API's change event listener
957
911
  document.removeEventListener('visibilitychange', this._onVisibilityChange);
@@ -991,19 +945,7 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
991
945
  if (!animations?.every(isLottie)) {
992
946
  throw new Error('Broken or corrupted file');
993
947
  }
994
- const ldScript = this.parentElement?.querySelector('script[type="application/ld+json"]');
995
- if (ldScript) {
996
- const settings = JSON.parse(ldScript.innerHTML);
997
- if (settings.selector) {
998
- this.selector = settings.selector;
999
- }
1000
- if (settings.segment) {
1001
- this.setSegment(settings.segment);
1002
- }
1003
- if (settings.multiAnimationSettings) {
1004
- this.setMultiAnimationSettings(settings.multiAnimationSettings);
1005
- }
1006
- }
948
+ this._handleLdScript();
1007
949
  this._isBounce = this.mode === PlayMode.Bounce;
1008
950
  if (this._multiAnimationSettings.length > 0 && this._multiAnimationSettings[this._currentAnimation]?.mode) {
1009
951
  this._isBounce = this._multiAnimationSettings[this._currentAnimation]?.mode === PlayMode.Bounce;
@@ -1046,6 +988,10 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1046
988
  this._lottieInstance.setSpeed(speed);
1047
989
  this._lottieInstance.setDirection(direction);
1048
990
  this._lottieInstance.setSubframe(Boolean(this.subframe));
991
+ // Set progress on load if AnimateOnScroll
992
+ if (this.animateOnScroll) {
993
+ this._applyScrollProgress();
994
+ }
1049
995
  // Start playing if autoplay is enabled
1050
996
  if ((this.autoplay || this.animateOnScroll || this.playOnVisible) && this.direction === -1) {
1051
997
  this.seek('99%');
@@ -1156,7 +1102,7 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1156
1102
  return;
1157
1103
  }
1158
1104
  // Extract frame number from either number or percentage value
1159
- const matches = value.toString().match(/^(\d+)(%?)$/);
1105
+ const matches = RegExp(/^(\d+)(%?)$/).exec(value.toString());
1160
1106
  if (!matches) {
1161
1107
  return;
1162
1108
  }
@@ -1345,9 +1291,12 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1345
1291
  /**
1346
1292
  * Handle blur.
1347
1293
  */ _handleBlur() {
1348
- setTimeout(()=>{
1294
+ const blurTimeout = setTimeout(()=>{
1349
1295
  this._toggleSettings(false);
1350
1296
  }, 200);
1297
+ if (!this._isSettingsOpen) {
1298
+ clearTimeout(blurTimeout);
1299
+ }
1351
1300
  }
1352
1301
  /**
1353
1302
  * Handle click.
@@ -1404,54 +1353,65 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1404
1353
  /**
1405
1354
  * Add IntersectionObserver.
1406
1355
  */ _addIntersectionObserver() {
1407
- if (!this._container || this._intersectionObserver) {
1356
+ if (!this._container || this._intersectionObserver || !hasIOSupport) {
1408
1357
  return;
1409
1358
  }
1410
- if (!('IntersectionObserver' in window)) {
1411
- this._intersectionObserverFallback();
1412
- removeEventListener('scroll', this._intersectionObserverFallback, true);
1413
- addEventListener('scroll', this._intersectionObserverFallback, {
1414
- capture: true,
1415
- passive: true
1416
- });
1417
- return;
1418
- }
1419
- this._intersectionObserver = new IntersectionObserver((entries)=>{
1420
- const { length } = entries;
1421
- for(let i = 0; i < length; i++){
1422
- if (!entries[i]?.isIntersecting || document.hidden) {
1423
- if (this.playerState === PlayerState.Playing) {
1424
- this._freeze();
1425
- }
1426
- this._playerState.visible = false;
1427
- continue;
1428
- }
1429
- if (!this.animateOnScroll && !this.playOnVisible && this.playerState === PlayerState.Frozen) {
1430
- this.play();
1431
- }
1432
- if (this.playOnVisible) {
1433
- if (this.playerState === PlayerState.Completed && !this.once) {
1434
- this.playerState = PlayerState.Playing;
1435
- this._lottieInstance?.goToAndPlay(this.direction === 1 ? 0 : this._lottieInstance.totalFrames);
1436
- } else {
1437
- setTimeout(()=>{
1438
- this.play();
1439
- }, this.delay);
1440
- }
1359
+ this._intersectionObserver = new IntersectionObserver(([{ isIntersecting }])=>{
1360
+ this._isIntersecting = isIntersecting;
1361
+ // Prevent animate on scroll for users with who prefers reduces motion.
1362
+ if (this.animateOnScroll && !hasReducedMotion) {
1363
+ if (isIntersecting) {
1364
+ this._startScrollLoop();
1365
+ } else {
1366
+ this._stopScrollLoop();
1441
1367
  }
1442
- /**
1443
- * If the player is a ways down the page, we need to account for this by
1444
- * setting _playerState.scrollY to the current scroll position. However, we
1445
- * also need to check that the player hasn't been scrolled past, so we check
1446
- * boundingClientRect as well.
1447
- */ if (!this._playerState.scrollY && (entries[i]?.boundingClientRect.y || 0) > 0) {
1448
- this._playerState.scrollY = scrollY;
1368
+ return;
1369
+ }
1370
+ if (!isIntersecting || document.hidden) {
1371
+ if (this.playerState === PlayerState.Playing) {
1372
+ this._freeze();
1449
1373
  }
1450
- this._playerState.visible = true;
1374
+ return;
1375
+ }
1376
+ if (!this.playOnVisible && this.playerState === PlayerState.Frozen) {
1377
+ this.play();
1378
+ }
1379
+ if (!this.playOnVisible || hasReducedMotion) {
1380
+ return;
1381
+ }
1382
+ if (this.playerState === PlayerState.Completed && !this.once) {
1383
+ this.playerState = PlayerState.Playing;
1384
+ this._lottieInstance?.goToAndPlay(this.direction === 1 ? 0 : this._lottieInstance.totalFrames);
1385
+ return;
1386
+ }
1387
+ this._playerState.playTimeout = setTimeout(()=>{
1388
+ this.play();
1389
+ }, this.delay);
1390
+ if (this.playerState === PlayerState.Playing) {
1391
+ clearTimeout(this._playerState.playTimeout);
1451
1392
  }
1452
1393
  });
1453
1394
  this._intersectionObserver.observe(this._container);
1454
1395
  }
1396
+ _applyScrollProgress() {
1397
+ if (!this.animateOnScroll || !this._lottieInstance) {
1398
+ return;
1399
+ }
1400
+ const progress = this._getScrollProgress();
1401
+ if (progress === null) {
1402
+ return;
1403
+ }
1404
+ const { totalFrames } = this._lottieInstance, frame = progress * (totalFrames - 1), epsilon = this.subframe ? 0.1 : 0.5;
1405
+ if (Math.abs(frame - this._playerState.frame) < epsilon) {
1406
+ return;
1407
+ }
1408
+ this._playerState.frame = frame;
1409
+ this._lottieInstance.goToAndStop(frame, true);
1410
+ }
1411
+ _cancelScrollProbe() {
1412
+ this._scrollProbe?.cancel();
1413
+ this._scrollProbe = undefined;
1414
+ }
1455
1415
  _clearPrevious() {
1456
1416
  this._lottieInstance?.destroy();
1457
1417
  const figure = this.shadow?.querySelector('.animation');
@@ -1530,7 +1490,8 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1530
1490
  if (currentAnimationSettings?.autoplay !== undefined) {
1531
1491
  hasAutoplay = Boolean(currentAnimationSettings.autoplay);
1532
1492
  }
1533
- if (this.animateOnScroll) {
1493
+ // Disable autoplay on reduced-motion.
1494
+ if (this.animateOnScroll || hasReducedMotion) {
1534
1495
  hasAutoplay = false;
1535
1496
  }
1536
1497
  // Segment
@@ -1553,6 +1514,30 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1553
1514
  rendererType: this.renderer
1554
1515
  });
1555
1516
  }
1517
+ _getScrollProgress() {
1518
+ if (!this._container) {
1519
+ return null;
1520
+ }
1521
+ if (hasVTSupport) {
1522
+ this._scrollProbe ??= this._container.animate({
1523
+ '--dotlottie-scroll': [
1524
+ 0,
1525
+ 1
1526
+ ]
1527
+ }, {
1528
+ fill: 'both',
1529
+ rangeEnd: 'cover 100%',
1530
+ rangeStart: 'cover 0%',
1531
+ timeline: new ViewTimeline({
1532
+ axis: 'block',
1533
+ subject: this._container
1534
+ })
1535
+ });
1536
+ return this._scrollProbe.effect?.getComputedTiming().progress ?? null;
1537
+ }
1538
+ const { height, top } = this._container.getBoundingClientRect(), viewport = visualViewport?.height ?? innerHeight;
1539
+ return clamp((viewport - top) / (viewport + height), 0, 1);
1540
+ }
1556
1541
  async _handleError(error) {
1557
1542
  this.playerState = PlayerState.Error;
1558
1543
  if (!this.quiet) {
@@ -1562,44 +1547,37 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1562
1547
  this.dispatchEvent(new CustomEvent(PlayerEvent.Error));
1563
1548
  console.error(error);
1564
1549
  }
1565
- /**
1566
- * Handle scroll.
1567
- */ _handleScroll() {
1568
- if (!this.animateOnScroll || !this._DOMRect || !this._lottieInstance) {
1550
+ _handleLdScript() {
1551
+ const ldScript = this.parentElement?.querySelector('script[type="application/ld+json"]');
1552
+ if (!ldScript) {
1569
1553
  return;
1570
1554
  }
1571
- if (isServer) {
1572
- console.warn('DotLottie: Scroll animations might not work properly in a Server Side Rendering context. Try to wrap this in a client component.');
1573
- return;
1555
+ const settings = JSON.parse(ldScript.innerHTML);
1556
+ if (settings.selector) {
1557
+ this.selector = settings.selector;
1558
+ }
1559
+ if (settings.segment) {
1560
+ this.setSegment(settings.segment);
1561
+ }
1562
+ if (settings.multiAnimationSettings) {
1563
+ this.setMultiAnimationSettings(settings.multiAnimationSettings);
1574
1564
  }
1575
- if (!this._playerState.visible) {
1565
+ }
1566
+ _handleSelector(method) {
1567
+ if (!this.selector) {
1576
1568
  return;
1577
1569
  }
1578
- if (this._playerState.scrollTimeout) {
1579
- clearTimeout(this._playerState.scrollTimeout);
1580
- }
1581
- this._playerState.scrollTimeout = setTimeout(()=>{
1582
- this.playerState = PlayerState.Paused;
1583
- }, 400);
1584
- const { totalFrames } = this._lottieInstance;
1585
- let scrollPosition = scrollY - this._playerState.scrollY;
1586
- if (scrollY <= this._playerState.scrollY) {
1587
- scrollPosition = this._playerState.scrollY - scrollY;
1588
- }
1589
- const { bottom, height, top } = this._DOMRect;
1590
- let offset = height - bottom;
1591
- if (top >= innerHeight) {
1592
- offset = height;
1593
- }
1594
- const scrollProgress = scrollPosition / (innerHeight + offset), currentFrame = clamp(scrollProgress * (totalFrames - 1), 0, totalFrames);
1595
- requestAnimationFrame(()=>{
1596
- if (currentFrame >= totalFrames) {
1597
- this.playerState = PlayerState.Paused;
1598
- return;
1570
+ const selector = document.getElementById(this.selector);
1571
+ if (selector) {
1572
+ if (this.hover) {
1573
+ selector[method]('mouseenter', this._mouseEnter);
1574
+ selector[method]('mouseleave', this._mouseLeave);
1575
+ } else {
1576
+ selector[method]('click', this._handleClick);
1599
1577
  }
1600
- this.playerState = PlayerState.Playing;
1601
- this._lottieInstance?.goToAndStop(currentFrame, true);
1602
- });
1578
+ } else {
1579
+ this.selector = null;
1580
+ }
1603
1581
  }
1604
1582
  _handleWindowBlur({ type }) {
1605
1583
  if (this.dontFreezeOnBlur) {
@@ -1612,20 +1590,6 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1612
1590
  this.play();
1613
1591
  }
1614
1592
  }
1615
- _intersectionObserverFallback() {
1616
- if (!this._container) {
1617
- return;
1618
- }
1619
- const { bottom, left, right, top } = this._container.getBoundingClientRect();
1620
- this._playerState.visible = top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
1621
- if (this.autoplay || this.playOnVisible || this.playerState === PlayerState.Playing || this.playerState === PlayerState.Frozen) {
1622
- if (this._playerState.visible) {
1623
- this.play();
1624
- } else {
1625
- this._freeze();
1626
- }
1627
- }
1628
- }
1629
1593
  _loopComplete() {
1630
1594
  if (!this._lottieInstance) {
1631
1595
  return;
@@ -1665,7 +1629,7 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1665
1629
  /**
1666
1630
  * Handle MouseEnter.
1667
1631
  */ _mouseEnter() {
1668
- if (!this.hover || !this._lottieInstance || isTouch()) {
1632
+ if (!this.hover || !this._lottieInstance || isTouch() || hasReducedMotion) {
1669
1633
  return;
1670
1634
  }
1671
1635
  if (this.mouseout === MouseOut.Reverse) {
@@ -1683,7 +1647,7 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1683
1647
  /**
1684
1648
  * Handle MouseLeave.
1685
1649
  */ _mouseLeave() {
1686
- if (!this.hover || !this._lottieInstance || isTouch()) {
1650
+ if (!this.hover || !this._lottieInstance || isTouch() || hasReducedMotion) {
1687
1651
  return;
1688
1652
  }
1689
1653
  switch(this.mouseout){
@@ -1698,10 +1662,6 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1698
1662
  }
1699
1663
  case MouseOut.Reverse:
1700
1664
  {
1701
- // const { direction = 1 } =
1702
- // this._multiAnimationSettings.length > 0 ?
1703
- // this._multiAnimationSettings[this._currentAnimation + 1] ?? { direction: 1 } : this,
1704
- // newDirection = direction * -1 as AnimationDirection
1705
1665
  this._lottieInstance.setDirection(-1);
1706
1666
  this.play();
1707
1667
  break;
@@ -1728,6 +1688,25 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1728
1688
  */ _removeEventListeners() {
1729
1689
  this._toggleEventListeners('remove');
1730
1690
  }
1691
+ _scrollLoop() {
1692
+ this._playerState.scrollLoopId = requestAnimationFrame(this._scrollLoop);
1693
+ this._applyScrollProgress();
1694
+ }
1695
+ _startScrollLoop() {
1696
+ if (isServer) {
1697
+ console.warn('DotLottie: Scroll animations will not work in a Server Side Rendering context. Try to wrap this in a client component.');
1698
+ return;
1699
+ }
1700
+ this._playerState.scrollLoopId ??= requestAnimationFrame(this._scrollLoop);
1701
+ }
1702
+ _stopScrollLoop() {
1703
+ if (this._playerState.scrollLoopId === undefined) {
1704
+ return;
1705
+ }
1706
+ cancelAnimationFrame(this._playerState.scrollLoopId);
1707
+ this._playerState.scrollLoopId = undefined;
1708
+ this._applyScrollProgress();
1709
+ }
1731
1710
  _switchInstance(isPrevious = false) {
1732
1711
  // Bail early if there is not animation to play
1733
1712
  if (!this._animations[this._currentAnimation]) {
@@ -1735,9 +1714,8 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1735
1714
  }
1736
1715
  try {
1737
1716
  // Clear previous animation
1738
- if (this._lottieInstance) {
1739
- this._lottieInstance.destroy();
1740
- }
1717
+ this._lottieInstance?.destroy();
1718
+ this._cancelScrollProbe();
1741
1719
  // Re-initialize lottie player
1742
1720
  this._lottieInstance = this.loadAnimation({
1743
1721
  ...this._getOptions(),
@@ -1753,7 +1731,8 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1753
1731
  this.dispatchEvent(new CustomEvent(isPrevious ? PlayerEvent.Previous : PlayerEvent.Next));
1754
1732
  if (this._multiAnimationSettings[this._currentAnimation]?.autoplay ?? this.autoplay) {
1755
1733
  if (this.animateOnScroll) {
1756
- this._lottieInstance.goToAndStop(0, true);
1734
+ // Get instant scroll position
1735
+ this._applyScrollProgress();
1757
1736
  this.playerState = PlayerState.Paused;
1758
1737
  return;
1759
1738
  }
@@ -1781,19 +1760,7 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1781
1760
  this._lottieInstance[method](PlayerEvent.DataReady, this._dataReady);
1782
1761
  this._lottieInstance[method](PlayerEvent.DataFailed, this._dataFailed);
1783
1762
  }
1784
- if (this.selector) {
1785
- const selector = document.getElementById(this.selector);
1786
- if (selector) {
1787
- if (this.hover) {
1788
- selector[method]('mouseenter', this._mouseEnter);
1789
- selector[method]('mouseleave', this._mouseLeave);
1790
- } else {
1791
- selector[method]('click', this._handleClick);
1792
- }
1793
- } else {
1794
- this.selector = null;
1795
- }
1796
- }
1763
+ this._handleSelector(method);
1797
1764
  if (this._container && !this.selector) {
1798
1765
  if (this.hover) {
1799
1766
  this._container[method]('mouseenter', this._mouseEnter);
@@ -1811,12 +1778,6 @@ const notImplemented = 'Method is not implemented', getStyles = async ()=>{
1811
1778
  capture: false,
1812
1779
  passive: true
1813
1780
  });
1814
- if (this.animateOnScroll) {
1815
- window[method]('scroll', this._handleScroll, {
1816
- capture: true,
1817
- passive: true
1818
- });
1819
- }
1820
1781
  }
1821
1782
  /**
1822
1783
  * Toggle show Settings.