@aarsteinmedia/dotlottie-player 6.5.7 → 6.6.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.
@@ -1,5 +1,6 @@
1
1
  import { getAnimationData } from '@aarsteinmedia/lottie-web/dotlottie';
2
2
  import { isServer, PreserveAspectRatio, PlayMode, RendererType, createElementID, clamp, PlayerEvent, download, getFilename } from '@aarsteinmedia/lottie-web/utils';
3
+ import { O as ObjectFit, M as MouseOut, P as PlayerState, h as hasIOSupport, r as reducedMotionQuery, a as hasVTSupport, b as hasHover } from './utilities-CC4oA5Yh.js';
3
4
 
4
5
  let modulePromise$1;
5
6
  function loadControlsModule() {
@@ -9,16 +10,16 @@ function loadControlsModule() {
9
10
 
10
11
  let modulePromise = null;
11
12
  function loadErrorModule() {
12
- modulePromise = modulePromise ?? import('./errorScreen-BPvA3AoR.js');
13
+ modulePromise = modulePromise ?? import('./errorScreen-B5U8u-AX.js');
13
14
  return modulePromise;
14
15
  }
15
16
 
16
17
  /**
17
18
  * Credit to: Leonardo Favre https://github.com/leofavre/observed-properties.
18
- */ const updateOnConnected = Symbol('UPDATE_ON_CONNECTED');
19
- if (isServer) {
19
+ */ if (isServer) {
20
20
  // Mock HTMLElement for server-side rendering
21
- global.HTMLElement = // eslint-disable-next-line @typescript-eslint/no-extraneous-class
21
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
22
+ globalThis.HTMLElement ??= // eslint-disable-next-line @typescript-eslint/no-extraneous-class
22
23
  class EmptyHTMLElement {
23
24
  };
24
25
  }
@@ -27,9 +28,6 @@ if (isServer) {
27
28
  */ class PropertyCallbackElement extends HTMLElement {
28
29
  constructor(){
29
30
  super();
30
- if (updateOnConnected in this) {
31
- this[updateOnConnected] = [];
32
- }
33
31
  const { observedProperties } = this.constructor;
34
32
  const { length } = observedProperties;
35
33
  for(let i = 0; i < length; i++){
@@ -46,24 +44,6 @@ if (isServer) {
46
44
  this.propertyChangedCallback(observedProperties[i], oldValue, value);
47
45
  }
48
46
  });
49
- if (typeof initialValue !== 'undefined' && updateOnConnected in this && Array.isArray(this[updateOnConnected])) {
50
- this[updateOnConnected].push(observedProperties[i]);
51
- }
52
- }
53
- }
54
- connectedCallback() {
55
- let arr = [];
56
- if (updateOnConnected in this && Array.isArray(this[updateOnConnected])) {
57
- arr = this[updateOnConnected];
58
- }
59
- const { length } = arr;
60
- for(let i = 0; i < length; i++){
61
- if (!('propertyChangedCallback' in this) || typeof this.propertyChangedCallback !== 'function') {
62
- continue;
63
- }
64
- if (arr[i] ?? '' in this) {
65
- this.propertyChangedCallback(arr[i] ?? '', undefined, this[arr[i]]);
66
- }
67
47
  }
68
48
  }
69
49
  propertyChangedCallback(_name, _oldValue, _value) {
@@ -73,33 +53,6 @@ if (isServer) {
73
53
 
74
54
  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
55
 
76
- var ObjectFit = /*#__PURE__*/ function(ObjectFit) {
77
- ObjectFit["Contain"] = "contain";
78
- ObjectFit["Cover"] = "cover";
79
- ObjectFit["Fill"] = "fill";
80
- ObjectFit["None"] = "none";
81
- ObjectFit["ScaleDown"] = "scale-down";
82
- return ObjectFit;
83
- }({});
84
- var MouseOut = /*#__PURE__*/ function(MouseOut) {
85
- MouseOut["Pause"] = "pause";
86
- MouseOut["Reverse"] = "reverse";
87
- MouseOut["Stop"] = "stop";
88
- MouseOut["Void"] = "void";
89
- return MouseOut;
90
- }({});
91
- var PlayerState = /*#__PURE__*/ function(PlayerState) {
92
- PlayerState["Completed"] = "completed";
93
- PlayerState["Destroyed"] = "destroyed";
94
- PlayerState["Error"] = "error";
95
- PlayerState["Frozen"] = "frozen";
96
- PlayerState["Loading"] = "loading";
97
- PlayerState["Paused"] = "paused";
98
- PlayerState["Playing"] = "playing";
99
- PlayerState["Stopped"] = "stopped";
100
- return PlayerState;
101
- }({});
102
-
103
56
  /**
104
57
  * Get extension from filename, URL or path.
105
58
  */ const aspectRatio = (objectFit)=>{
@@ -126,7 +79,7 @@ var PlayerState = /*#__PURE__*/ function(PlayerState) {
126
79
  return PreserveAspectRatio.Contain;
127
80
  }
128
81
  }
129
- }, handleErrors = (err)=>{
82
+ }, escapeHTML = (str)=>str.replaceAll(/[&<>"']/g, (char)=>`&#${char.charCodeAt(0)};`), handleErrors = (err)=>{
130
83
  const res = {
131
84
  message: 'Unknown error',
132
85
  status: isServer ? 500 : 400
@@ -158,24 +111,22 @@ var PlayerState = /*#__PURE__*/ function(PlayerState) {
158
111
  'h'
159
112
  ];
160
113
  return mandatory.every((field)=>Object.hasOwn(json, field));
161
- }, isTouch = ()=>'ontouchstart' in window, frameOutput = (frame)=>((frame ?? 0) + 1).toString().padStart(3, '0'), parseHTMLBooleans = (val)=>val !== null && [
114
+ }, frameOutput = (frame)=>((frame ?? 0) + 1).toString().padStart(3, '0'), parseHTMLBooleans = (val)=>val !== null && [
162
115
  'true',
163
116
  '',
164
117
  '1'
165
118
  ].includes(val);
166
119
 
167
- const tagName = 'dotlottie-player', hasReducedMotion = !isServer && matchMedia('(prefers-reduced-motion: reduce)').matches, hasIOSupport = !isServer && 'IntersectionObserver' in window, hasVTSupport = !isServer && 'ViewTimeline' in window;
168
-
169
120
  const getStyles = async ()=>{
170
121
  const styleSheet = new CSSStyleSheet();
171
122
  await styleSheet.replace(css_248z);
172
123
  return styleSheet;
173
- };
124
+ }, stylePromise = getStyles();
174
125
  class BaseElement extends PropertyCallbackElement {
175
126
  /**
176
127
  * Return the styles for the component.
177
128
  */ static get styles() {
178
- return getStyles;
129
+ return stylePromise;
179
130
  }
180
131
  /**
181
132
  * Whether to trigger next frame with scroll.
@@ -511,6 +462,7 @@ class ScrollElement extends BaseElement {
511
462
  cancelScrollProbe() {
512
463
  this._scrollProbe?.cancel();
513
464
  this._scrollProbe = undefined;
465
+ this._useGeometricScroll = false;
514
466
  }
515
467
  scrollLoop() {
516
468
  this._playerState.scrollLoopId = requestAnimationFrame(this.scrollLoop);
@@ -540,7 +492,7 @@ class ScrollElement extends BaseElement {
540
492
  this._intersectionObserver = new IntersectionObserver(([{ isIntersecting }])=>{
541
493
  this.isIntersecting = isIntersecting;
542
494
  // Prevent animate on scroll for users with who prefers reduces motion.
543
- if (this.animateOnScroll && !hasReducedMotion) {
495
+ if (this.animateOnScroll && !reducedMotionQuery?.matches) {
544
496
  if (isIntersecting) {
545
497
  this.startScrollLoop();
546
498
  return;
@@ -552,12 +504,15 @@ class ScrollElement extends BaseElement {
552
504
  if (this.playerState === PlayerState.Playing) {
553
505
  this._freeze();
554
506
  }
507
+ if (this._playerState.playTimeout) {
508
+ clearTimeout(this._playerState.playTimeout);
509
+ }
555
510
  return;
556
511
  }
557
- if (!this.playOnVisible && this.playerState === PlayerState.Frozen && !(this.autoplay && hasReducedMotion)) {
512
+ if (!this.playOnVisible && this.playerState === PlayerState.Frozen && !(this.autoplay && reducedMotionQuery?.matches)) {
558
513
  this.play();
559
514
  }
560
- if (!this.playOnVisible || hasReducedMotion) {
515
+ if (!this.playOnVisible || reducedMotionQuery?.matches) {
561
516
  return;
562
517
  }
563
518
  if (this.playerState === PlayerState.Completed && !this.once) {
@@ -592,28 +547,31 @@ class ScrollElement extends BaseElement {
592
547
  if (!this._container) {
593
548
  return null;
594
549
  }
595
- if (!hasVTSupport) {
550
+ if (!hasVTSupport || this._useGeometricScroll) {
596
551
  return this._getGeometricScrollProgress();
597
552
  }
598
- const timeline = new ViewTimeline({
599
- axis: 'block',
600
- subject: this._container
601
- }), canDriveTimeline = this._canDriveTimeline(timeline);
602
- if (!canDriveTimeline) {
603
- this.devLog('[dotlottie-player] animateOnScroll: the player\'s nearest scrolling ancestor cannot ' + 'scroll, so its ViewTimeline would never advance. This is almost always an ancestor ' + 'with `overflow: hidden` — use `overflow: clip` instead. Falling back to viewport ' + 'measurement.');
604
- return this._getGeometricScrollProgress();
553
+ if (!this._scrollProbe) {
554
+ const timeline = new ViewTimeline({
555
+ axis: 'block',
556
+ subject: this._container
557
+ });
558
+ if (!this._canDriveTimeline(timeline)) {
559
+ this._useGeometricScroll = true;
560
+ this.devLog('[dotlottie-player] animateOnScroll: the player\'s nearest scrolling ancestor cannot ' + 'scroll, so its ViewTimeline would never advance. This is almost always an ancestor ' + 'with `overflow: hidden` — use `overflow: clip` instead. Falling back to viewport ' + 'measurement.');
561
+ return this._getGeometricScrollProgress();
562
+ }
563
+ this._scrollProbe ??= this._container.animate({
564
+ '--dotlottie-scroll': [
565
+ 0,
566
+ 1
567
+ ]
568
+ }, {
569
+ fill: 'both',
570
+ rangeEnd: 'cover 100%',
571
+ rangeStart: 'cover 0%',
572
+ timeline
573
+ });
605
574
  }
606
- this._scrollProbe ??= this._container.animate({
607
- '--dotlottie-scroll': [
608
- 0,
609
- 1
610
- ]
611
- }, {
612
- fill: 'both',
613
- rangeEnd: 'cover 100%',
614
- rangeStart: 'cover 0%',
615
- timeline
616
- });
617
575
  return this._scrollProbe.effect?.getComputedTiming().progress ?? null;
618
576
  }
619
577
  _observeIntersectionTarget() {
@@ -626,7 +584,7 @@ class ScrollElement extends BaseElement {
626
584
  this._intersectionObserver.observe(this._container);
627
585
  }
628
586
  constructor(...args){
629
- super(...args), this.isIntersecting = false;
587
+ super(...args), this.isIntersecting = false, this._useGeometricScroll = false;
630
588
  }
631
589
  }
632
590
 
@@ -755,10 +713,26 @@ function handleButtons() {
755
713
  }
756
714
  if (!this.controls) {
757
715
  slot.innerHTML = '';
716
+ this._controlElements = null;
758
717
  return;
759
718
  }
760
719
  const convertLabel = this.isDotLottie ? 'dotLottie animation to JSON format' : 'JSON animation to dotLottie format', convertButtonText = this.isDotLottie ? 'Convert to JSON' : 'Convert to dotLottie';
761
- 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>`;
720
+ 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}" aria-pressed="${this.loop}" tabindex="0" aria-label="Toggle loop">${loopIcon}</button> <button class="toggleBoomerang" data-active="${this.mode === PlayMode.Bounce}" aria-pressed="${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>`;
721
+ const query = (selector, type)=>{
722
+ const el = slot.querySelector(selector);
723
+ return el instanceof type ? el : null;
724
+ }, togglePlay = query('.togglePlay', HTMLButtonElement), stop = query('.stop', HTMLButtonElement), prev = query('.prev', HTMLButtonElement), next = query('.next', HTMLButtonElement), seeker = query('.seeker', HTMLInputElement), progress = query('progress', HTMLProgressElement);
725
+ this._controlElements = togglePlay && stop && prev && next && seeker && progress ? {
726
+ convert: query('.convert', HTMLButtonElement),
727
+ next,
728
+ popover: query('.popover', HTMLDivElement),
729
+ prev,
730
+ progress,
731
+ seeker,
732
+ snapshot: query('.snapshot', HTMLButtonElement),
733
+ stop,
734
+ togglePlay
735
+ } : null;
762
736
  handleButtons.call(this);
763
737
  }
764
738
  function updatePlayPauseButton(togglePlay, state) {
@@ -779,7 +753,13 @@ var controls = /*#__PURE__*/Object.freeze({
779
753
  if (!this.shadow || !this.template) {
780
754
  throw new Error('No Shadow Element or Template');
781
755
  }
782
- let langAttribute = '';
756
+ this.template.innerHTML = /* HTML */ `<div class="animation-container main"><figure class="animation"></figure><slot name="controls"></slot></div>`;
757
+ const fragment = this.template.content.cloneNode(true), container = fragment.querySelector('.animation-container'), figure = fragment.querySelector('figure');
758
+ if (!(container instanceof HTMLDivElement) || !figure) {
759
+ throw new Error('Template is broken');
760
+ }
761
+ container.dataset.controls = String(this.controls);
762
+ figure.style.background = this.background;
783
763
  /**
784
764
  * If player has aria-description, it's safe to assume
785
765
  * language should be the same as `document.documentElement.lang`.
@@ -788,11 +768,12 @@ var controls = /*#__PURE__*/Object.freeze({
788
768
  * With neither controls or description, the lang attribute is
789
769
  * not needed.
790
770
  */ if (this.description || this.controls) {
791
- const lang = this.description ? document.documentElement.lang : 'en';
792
- langAttribute = `lang="${lang}"`;
771
+ container.lang = this.description ? document.documentElement.lang : 'en';
793
772
  }
794
- 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>`;
795
- this.shadow.appendChild(this.template.content.cloneNode(true));
773
+ if (this.description) {
774
+ figure.setAttribute('aria-label', this.description);
775
+ }
776
+ this.shadow.replaceChildren(fragment);
796
777
  }
797
778
 
798
779
  /**
@@ -802,15 +783,15 @@ var controls = /*#__PURE__*/Object.freeze({
802
783
  * Attributes to observe.
803
784
  */ static get observedAttributes() {
804
785
  return [
805
- 'animateOnScroll',
786
+ 'animateonscroll',
806
787
  'autoplay',
807
788
  'controls',
808
789
  'direction',
809
790
  'hover',
810
791
  'loop',
811
792
  'mode',
812
- 'playOnClick',
813
- 'playOnVisible',
793
+ 'playonclick',
794
+ 'playonvisible',
814
795
  'selector',
815
796
  'speed',
816
797
  'src',
@@ -830,11 +811,11 @@ var controls = /*#__PURE__*/Object.freeze({
830
811
  return this._isDotLottie;
831
812
  }
832
813
  constructor(){
833
- super(), this.isLight = false, /**
814
+ super(), this.canConvert = false, this._controlElements = null, /**
834
815
  * Whether settings toolbar is open.
835
816
  */ this._isSettingsOpen = false, /**
836
817
  * Seeker.
837
- */ this._seeker = 0, this._controlsLoadId = 0, this._errorLoadId = 0, this._isBounce = false, this._isDotLottie = false, /**
818
+ */ this._seeker = 0, this._controlsLoadId = 0, this._errorLoadId = 0, this._isBounce = false, this._isDotLottie = false, this._loadId = 0, /**
838
819
  * Multi-animation settings.
839
820
  */ this._multiAnimationSettings = [], this._renderControls = async ()=>{
840
821
  const slot = this.shadow?.querySelector('slot[name=controls]');
@@ -843,6 +824,7 @@ var controls = /*#__PURE__*/Object.freeze({
843
824
  }
844
825
  if (!this.controls) {
845
826
  slot.innerHTML = '';
827
+ this._controlElements = null;
846
828
  return;
847
829
  }
848
830
  const loadId = ++this._controlsLoadId, { renderControls } = await loadControlsModule();
@@ -866,7 +848,6 @@ var controls = /*#__PURE__*/Object.freeze({
866
848
  this._mouseLeave = this._mouseLeave.bind(this);
867
849
  this._onVisibilityChange = this._onVisibilityChange.bind(this);
868
850
  this.scrollLoop = this.scrollLoop.bind(this);
869
- // this.startScrollLoop = this.startScrollLoop.bind(this)
870
851
  this._switchInstance = this._switchInstance.bind(this);
871
852
  this._handleSettingsClick = this._handleSettingsClick.bind(this);
872
853
  this.togglePlay = this.togglePlay.bind(this);
@@ -891,9 +872,9 @@ var controls = /*#__PURE__*/Object.freeze({
891
872
  }
892
873
  this.clearDevLog();
893
874
  switch(name){
894
- case 'animateOnScroll':
875
+ case 'animateonscroll':
895
876
  {
896
- if (value === '' || Boolean(value)) {
877
+ if (parseHTMLBooleans(value)) {
897
878
  this._lottieInstance.autoplay = false;
898
879
  if (this.isIntersecting) {
899
880
  this.startScrollLoop();
@@ -905,10 +886,10 @@ var controls = /*#__PURE__*/Object.freeze({
905
886
  }
906
887
  case 'autoplay':
907
888
  {
908
- if (this.animateOnScroll || this.playOnVisible || hasReducedMotion) {
889
+ if (this.animateOnScroll || this.playOnVisible || reducedMotionQuery?.matches) {
909
890
  return;
910
891
  }
911
- if (value === '' || Boolean(value)) {
892
+ if (parseHTMLBooleans(value)) {
912
893
  this.play();
913
894
  return;
914
895
  }
@@ -931,7 +912,7 @@ var controls = /*#__PURE__*/Object.freeze({
931
912
  }
932
913
  case 'hover':
933
914
  {
934
- if (value === '' || Boolean(value)) {
915
+ if (parseHTMLBooleans(value)) {
935
916
  this._container.addEventListener('mouseenter', this._mouseEnter);
936
917
  this._container.addEventListener('mouseleave', this._mouseLeave);
937
918
  return;
@@ -961,9 +942,9 @@ var controls = /*#__PURE__*/Object.freeze({
961
942
  this._isBounce = value === PlayMode.Bounce;
962
943
  break;
963
944
  }
964
- case 'playOnClick':
945
+ case 'playonclick':
965
946
  {
966
- if (value === '' || Boolean(value)) {
947
+ if (parseHTMLBooleans(value)) {
967
948
  this._lottieInstance.autoplay = false;
968
949
  this._container.addEventListener('click', this._handleClick);
969
950
  return;
@@ -971,9 +952,9 @@ var controls = /*#__PURE__*/Object.freeze({
971
952
  this._container.removeEventListener('click', this._handleClick);
972
953
  break;
973
954
  }
974
- case 'playOnVisible':
955
+ case 'playonvisible':
975
956
  {
976
- if (value === '' || Boolean(value)) {
957
+ if (parseHTMLBooleans(value)) {
977
958
  this._lottieInstance.autoplay = false;
978
959
  }
979
960
  break;
@@ -999,7 +980,7 @@ var controls = /*#__PURE__*/Object.freeze({
999
980
  }
1000
981
  case 'subframe':
1001
982
  {
1002
- this.setSubframe(value === '' || Boolean(value));
983
+ this.setSubframe(parseHTMLBooleans(value));
1003
984
  break;
1004
985
  }
1005
986
  }
@@ -1007,7 +988,7 @@ var controls = /*#__PURE__*/Object.freeze({
1007
988
  /**
1008
989
  * Initialize everything on component first render.
1009
990
  */ connectedCallback() {
1010
- super.connectedCallback();
991
+ // super.connectedCallback()
1011
992
  void (async ()=>{
1012
993
  try {
1013
994
  await this._render();
@@ -1017,10 +998,6 @@ var controls = /*#__PURE__*/Object.freeze({
1017
998
  this._container = this.shadow.querySelector('.animation');
1018
999
  // Setup lottie player
1019
1000
  await this.load(this.src);
1020
- // Add listener for Visibility API's change event.
1021
- if (typeof document.hidden !== 'undefined') {
1022
- document.addEventListener('visibilitychange', this._onVisibilityChange);
1023
- }
1024
1001
  // Add intersection observer for detecting component being out-of-view.
1025
1002
  this._addIntersectionObserver();
1026
1003
  this.dispatchEvent(new CustomEvent(PlayerEvent.Rendered));
@@ -1042,7 +1019,7 @@ var controls = /*#__PURE__*/Object.freeze({
1042
1019
  this.stopScrollLoop();
1043
1020
  this.dispatchEvent(new CustomEvent(PlayerEvent.Destroyed));
1044
1021
  this.remove();
1045
- document.removeEventListener('visibilitychange', this._onVisibilityChange);
1022
+ this._removeEventListeners();
1046
1023
  }
1047
1024
  /**
1048
1025
  * Cleanup on component destroy.
@@ -1055,8 +1032,7 @@ var controls = /*#__PURE__*/Object.freeze({
1055
1032
  if (this._playerState.playTimeout) {
1056
1033
  clearTimeout(this._playerState.playTimeout);
1057
1034
  }
1058
- // Remove the attached Visibility API's change event listener
1059
- document.removeEventListener('visibilitychange', this._onVisibilityChange);
1035
+ this._removeEventListeners();
1060
1036
  // Destroy the animation instance
1061
1037
  this.destroy();
1062
1038
  this.clearDevLog();
@@ -1088,6 +1064,10 @@ var controls = /*#__PURE__*/Object.freeze({
1088
1064
  if (!this.shadowRoot || !src) {
1089
1065
  return;
1090
1066
  }
1067
+ const loadId = ++this._loadId;
1068
+ if (loadId !== this._loadId) {
1069
+ return;
1070
+ }
1091
1071
  this.source = src;
1092
1072
  // Load the resource
1093
1073
  const { animations, isDotLottie, manifest } = await getAnimationData(src);
@@ -1204,39 +1184,38 @@ var controls = /*#__PURE__*/Object.freeze({
1204
1184
  if (!this.shadow) {
1205
1185
  return;
1206
1186
  }
1207
- const togglePlay = this.shadow.querySelector('.togglePlay'), stopButton = this.shadow.querySelector('.stop'), prevButton = this.shadow.querySelector('.prev'), nextButton = 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');
1208
- if (!(togglePlay instanceof HTMLButtonElement) || !(stopButton instanceof HTMLButtonElement) || !(nextButton instanceof HTMLButtonElement) || !(prevButton instanceof HTMLButtonElement) || !(seeker instanceof HTMLInputElement) || !(progress instanceof HTMLProgressElement)) {
1187
+ const elements = this._controlElements;
1188
+ if (!elements) {
1209
1189
  return;
1210
1190
  }
1211
1191
  if (name === 'playerState') {
1212
- updatePlayPauseButton(togglePlay, value);
1213
- stopButton.dataset.active = (value === PlayerState.Stopped).toString();
1192
+ updatePlayPauseButton(elements.togglePlay, value);
1193
+ elements.stop.dataset.active = (value === PlayerState.Stopped).toString();
1214
1194
  }
1215
1195
  if (name === '_seeker' && typeof value === 'number') {
1216
- seeker.value = value.toString();
1217
- seeker.ariaValueNow = value.toString();
1218
- progress.value = value;
1196
+ elements.seeker.value = value.toString();
1197
+ elements.seeker.ariaValueNow = value.toString();
1198
+ elements.progress.value = value;
1219
1199
  }
1220
1200
  if (name === '_animations' && Array.isArray(value) && this._currentAnimation + 1 < value.length) {
1221
- nextButton.hidden = false;
1201
+ elements.next.hidden = false;
1222
1202
  }
1223
1203
  if (name === '_currentAnimation' && typeof value === 'number') {
1224
- nextButton.hidden = value + 1 >= this._animations.length;
1225
- prevButton.hidden = !value;
1204
+ elements.next.hidden = value + 1 >= this._animations.length;
1205
+ elements.prev.hidden = !value;
1226
1206
  }
1227
- if (name === '_isSettingsOpen' && typeof value === 'boolean' && popover instanceof HTMLDivElement && convertButton instanceof HTMLButtonElement && snapshot instanceof HTMLButtonElement) {
1228
- popover.hidden = !value;
1229
- convertButton.hidden = this.isLight;
1230
- snapshot.hidden = this.renderer !== RendererType.SVG;
1207
+ if (name === '_isSettingsOpen' && typeof value === 'boolean' && elements.popover && elements.convert && elements.snapshot) {
1208
+ elements.popover.hidden = !value;
1209
+ elements.convert.hidden = !this.canConvert;
1210
+ elements.snapshot.hidden = this.renderer !== RendererType.SVG;
1231
1211
  }
1232
1212
  }
1233
1213
  /**
1234
1214
  * Reload animation.
1235
1215
  */ async reload() {
1236
- if (!this._lottieInstance || !this.src) {
1216
+ if (!this.src) {
1237
1217
  return;
1238
1218
  }
1239
- this._lottieInstance.destroy();
1240
1219
  await this.load(this.src);
1241
1220
  }
1242
1221
  /**
@@ -1248,14 +1227,21 @@ var controls = /*#__PURE__*/Object.freeze({
1248
1227
  return;
1249
1228
  }
1250
1229
  // Extract frame number from either number or percentage value
1251
- const matches = RegExp(/^(\d+)(%?)$/).exec(value.toString());
1230
+ const str = String(value).trim(), matches = /^([+-]?(?:\d+(?:\.\d*)?|\.\d+))\s*(%?)$/.exec(str);
1252
1231
  if (!matches) {
1253
1232
  return;
1254
1233
  }
1234
+ const { totalFrames } = this._lottieInstance, frame = parseInt(matches[1]), isPercentage = matches[2] === '%';
1255
1235
  // Calculate and set the frame number
1256
- const frame = Math.round(matches[2] === '%' ? this._lottieInstance.totalFrames * Number(matches[1]) / 100 : Number(matches[1]));
1236
+ let percentage;
1237
+ // Check if value is a percentage string
1238
+ if (isPercentage) {
1239
+ percentage = Math.round(totalFrames * frame / 100);
1240
+ } else {
1241
+ percentage = Math.round(frame / totalFrames * 100);
1242
+ }
1257
1243
  // Set seeker to new frame number
1258
- this._seeker = frame;
1244
+ this._seeker = percentage;
1259
1245
  // Send lottie player to the new frame
1260
1246
  if (this.playerState === PlayerState.Playing || this.playerState === PlayerState.Frozen && this._playerState.prev === PlayerState.Playing) {
1261
1247
  this._lottieInstance.goToAndPlay(frame, true);
@@ -1323,7 +1309,7 @@ var controls = /*#__PURE__*/Object.freeze({
1323
1309
  * Snapshot and download the current frame as SVG.
1324
1310
  */ snapshot(shouldDownload = true, name = 'AM Lottie') {
1325
1311
  try {
1326
- if (!this.shadowRoot) {
1312
+ if (!this.shadowRoot || !this._lottieInstance) {
1327
1313
  throw new Error('Unknown error');
1328
1314
  }
1329
1315
  // Get SVG element and serialize markup
@@ -1338,7 +1324,7 @@ var controls = /*#__PURE__*/Object.freeze({
1338
1324
  if (shouldDownload) {
1339
1325
  download(data, {
1340
1326
  mimeType: 'image/svg+xml',
1341
- name: `${getFilename(this.src || name)}-${frameOutput(this._seeker)}.svg`
1327
+ name: `${getFilename(this.src || name)}-${frameOutput(this._seeker * this._lottieInstance.totalFrames / 100)}.svg`
1342
1328
  });
1343
1329
  }
1344
1330
  return data;
@@ -1473,9 +1459,10 @@ var controls = /*#__PURE__*/Object.freeze({
1473
1459
  if (!this.shadow) {
1474
1460
  return;
1475
1461
  }
1462
+ this._controlElements = null;
1476
1463
  renderPlayer.call(this);
1477
1464
  this.shadow.adoptedStyleSheets = [
1478
- await DotLottiePlayerBase.styles()
1465
+ await DotLottiePlayerBase.styles
1479
1466
  ];
1480
1467
  }
1481
1468
  async _showError() {
@@ -1487,6 +1474,7 @@ var controls = /*#__PURE__*/Object.freeze({
1487
1474
  */ controlSlot = this.shadow?.querySelector('slot[name=controls]');
1488
1475
  if (controlSlot) {
1489
1476
  controlSlot.innerHTML = '';
1477
+ this._controlElements = null;
1490
1478
  }
1491
1479
  if (!(figure instanceof HTMLElement)) {
1492
1480
  return;
@@ -1497,9 +1485,6 @@ var controls = /*#__PURE__*/Object.freeze({
1497
1485
  }
1498
1486
  figure.innerHTML = errorScreen(this._errorMessage);
1499
1487
  }
1500
- setOptions(_options) {
1501
- throw new Error('Method not implemented');
1502
- }
1503
1488
  /**
1504
1489
  * Add event listeners.
1505
1490
  */ _addEventListeners() {
@@ -1584,7 +1569,7 @@ var controls = /*#__PURE__*/Object.freeze({
1584
1569
  hasAutoplay = Boolean(currentAnimationSettings.autoplay);
1585
1570
  }
1586
1571
  // Disable autoplay on reduced-motion.
1587
- if (this.animateOnScroll || hasReducedMotion) {
1572
+ if (this.animateOnScroll || reducedMotionQuery?.matches) {
1588
1573
  hasAutoplay = false;
1589
1574
  }
1590
1575
  // Segment
@@ -1617,19 +1602,23 @@ var controls = /*#__PURE__*/Object.freeze({
1617
1602
  this.devLog(error);
1618
1603
  }
1619
1604
  _handleLdScript() {
1620
- const ldScript = this.parentElement?.querySelector('script[type="application/ld+json"]');
1605
+ const ldScript = this.parentElement?.querySelector(':scope > script[type="application/ld+json"]');
1621
1606
  if (!ldScript) {
1622
1607
  return;
1623
1608
  }
1624
- const settings = JSON.parse(ldScript.innerHTML);
1625
- if (settings.selector) {
1626
- this.selector = settings.selector;
1627
- }
1628
- if (settings.segment) {
1629
- this.setSegment(settings.segment);
1630
- }
1631
- if (settings.multiAnimationSettings) {
1632
- this.setMultiAnimationSettings(settings.multiAnimationSettings);
1609
+ try {
1610
+ const settings = JSON.parse(ldScript.innerHTML);
1611
+ if (settings.selector) {
1612
+ this.selector = settings.selector;
1613
+ }
1614
+ if (settings.segment) {
1615
+ this.setSegment(settings.segment);
1616
+ }
1617
+ if (settings.multiAnimationSettings) {
1618
+ this.setMultiAnimationSettings(settings.multiAnimationSettings);
1619
+ }
1620
+ } catch (error) {
1621
+ this.devLog(error);
1633
1622
  }
1634
1623
  }
1635
1624
  _handleSelector(method) {
@@ -1698,7 +1687,7 @@ var controls = /*#__PURE__*/Object.freeze({
1698
1687
  /**
1699
1688
  * Handle MouseEnter.
1700
1689
  */ _mouseEnter() {
1701
- if (!this.hover || !this._lottieInstance || isTouch() || hasReducedMotion) {
1690
+ if (!this.hover || !this._lottieInstance || !hasHover || reducedMotionQuery?.matches) {
1702
1691
  return;
1703
1692
  }
1704
1693
  if (this.mouseout === MouseOut.Reverse) {
@@ -1716,7 +1705,7 @@ var controls = /*#__PURE__*/Object.freeze({
1716
1705
  /**
1717
1706
  * Handle MouseLeave.
1718
1707
  */ _mouseLeave() {
1719
- if (!this.hover || !this._lottieInstance || isTouch() || hasReducedMotion) {
1708
+ if (!this.hover || !this._lottieInstance || !hasHover || reducedMotionQuery?.matches) {
1720
1709
  return;
1721
1710
  }
1722
1711
  switch(this.mouseout){
@@ -1744,7 +1733,7 @@ var controls = /*#__PURE__*/Object.freeze({
1744
1733
  /**
1745
1734
  * Handle visibility change events.
1746
1735
  */ _onVisibilityChange() {
1747
- if (this.autoplay && hasReducedMotion) {
1736
+ if (this.autoplay && reducedMotionQuery?.matches) {
1748
1737
  return;
1749
1738
  }
1750
1739
  if (document.hidden && this.playerState === PlayerState.Playing) {
@@ -1805,6 +1794,10 @@ var controls = /*#__PURE__*/Object.freeze({
1805
1794
  * Toggle event listeners.
1806
1795
  */ _toggleEventListeners(action) {
1807
1796
  const method = action === 'add' ? 'addEventListener' : 'removeEventListener';
1797
+ // Toggle the attached Visibility API's change event listener
1798
+ if (typeof document.hidden !== 'undefined') {
1799
+ document[method]('visibilitychange', this._onVisibilityChange);
1800
+ }
1808
1801
  if (this._lottieInstance) {
1809
1802
  this._lottieInstance[method](PlayerEvent.EnterFrame, this._enterFrame);
1810
1803
  this._lottieInstance[method](PlayerEvent.Complete, this._complete);
@@ -1843,4 +1836,4 @@ var controls = /*#__PURE__*/Object.freeze({
1843
1836
  }
1844
1837
  }
1845
1838
 
1846
- export { DotLottiePlayerBase as D, MouseOut as M, PlayerState as P, loadDotLottieTools as l, tagName as t };
1839
+ export { DotLottiePlayerBase as D, escapeHTML as e, loadDotLottieTools as l };