lido-player 0.0.2-beta-01 → 0.0.2-beta-02

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.
Files changed (36) hide show
  1. package/dist/cjs/{decode-DkmQvXwq.js → decode-BvT284iq.js} +1 -1
  2. package/dist/cjs/{index-DWfpvz_s.js → index-BhikEYm-.js} +93 -8
  3. package/dist/cjs/index.cjs.js +1 -1
  4. package/dist/cjs/lido-avatar_22.cjs.entry.js +59 -18
  5. package/dist/collection/components/home/lido-home.js +47 -7
  6. package/dist/collection/components/slideFill/lido-slide-fill.css +1 -1
  7. package/dist/collection/components/slideFill/lido-slide-fill.js +5 -5
  8. package/dist/collection/components/trace/lido-trace.css +1 -1
  9. package/dist/collection/components/trace/lido-trace.js +3 -2
  10. package/dist/collection/utils/audioPlayer.js +86 -5
  11. package/dist/collection/utils/utilsHandlers/clickHandler.js +5 -1
  12. package/dist/collection/utils/utilsHandlers/dragDropHandler.js +1 -1
  13. package/dist/components/index.js +1 -1
  14. package/dist/components/lido-home.js +1 -1
  15. package/dist/components/lido-root.js +1 -1
  16. package/dist/components/lido-slide-fill.js +1 -1
  17. package/dist/components/lido-trace.js +1 -1
  18. package/dist/components/p-BY1E9s1O.js +1 -0
  19. package/dist/components/p-CYA3cHAL.js +1 -0
  20. package/dist/components/p-yHq43npj.js +1 -0
  21. package/dist/esm/{decode-Czc9ZfbM.js → decode-B2R73LQH.js} +1 -1
  22. package/dist/esm/{index-9UC_Eom9.js → index-C1lqv26k.js} +93 -8
  23. package/dist/esm/index.js +1 -1
  24. package/dist/esm/lido-avatar_22.entry.js +59 -18
  25. package/dist/lido-player/index.esm.js +1 -1
  26. package/dist/lido-player/lido-player.esm.js +1 -1
  27. package/dist/lido-player/{p-C73A1Nfh.js → p-C61UwQXx.js} +1 -1
  28. package/dist/lido-player/p-DLiAHqUu.js +1 -0
  29. package/dist/lido-player/{p-15e1c7db.entry.js → p-b98f209c.entry.js} +1 -1
  30. package/dist/types/components/home/lido-home.d.ts +3 -0
  31. package/dist/types/utils/audioPlayer.d.ts +13 -2
  32. package/package.json +1 -1
  33. package/dist/components/p-CtU7FitD.js +0 -1
  34. package/dist/components/p-Dr5sh_El.js +0 -1
  35. package/dist/components/p-PPkfANfe.js +0 -1
  36. package/dist/lido-player/p-CRp3QJ0s.js +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-DWfpvz_s.js');
3
+ var index = require('./index-BhikEYm-.js');
4
4
 
5
5
  function _mergeNamespaces(n, m) {
6
6
  m.forEach(function (e) {
@@ -1062,7 +1062,7 @@ function handleDropElement(element) {
1062
1062
  }
1063
1063
  async function onClickDropOrDragElement(element, type) {
1064
1064
  const container = document.getElementById(LidoContainer);
1065
- if (container.getAttribute('canplay') === 'false')
1065
+ if (container.getAttribute('canplay') === 'false' || container.getAttribute("game-completed") === "true")
1066
1066
  return;
1067
1067
  // Remove the highlight class from elements matching the selector
1068
1068
  const highlightedElements = document.querySelectorAll(`[type='${type}']`);
@@ -1364,21 +1364,39 @@ function highlightElement() {
1364
1364
 
1365
1365
  class AudioPlayer {
1366
1366
  constructor() {
1367
+ this.currentTargetElement = null;
1368
+ this.pendingReplayElement = null;
1367
1369
  this.highlightOverlay = null;
1368
1370
  this.wordRects = [];
1369
1371
  this.activeWordIndex = -1;
1370
1372
  this.highlightRAF = null;
1371
1373
  this.endPromiseResolve = null;
1372
- this.handleUserClick = () => {
1374
+ this.visibilityWaitResolvers = [];
1375
+ this.isVisibilityChangeRegistered = false;
1376
+ this.handleUserClick = (event) => {
1373
1377
  const container = document.getElementById(LidoContainer);
1378
+ if (container && (event === null || event === void 0 ? void 0 : event.target) === container)
1379
+ return;
1374
1380
  if ((container === null || container === void 0 ? void 0 : container.getAttribute('game-completed')) === 'true')
1375
1381
  return;
1376
1382
  this.stop();
1377
1383
  };
1384
+ this.handleVisibilityChange = async () => {
1385
+ if (this.isWindowVisible()) {
1386
+ this.resolveVisibilityWaiters();
1387
+ return;
1388
+ }
1389
+ if (!this.currentTargetElement) {
1390
+ return;
1391
+ }
1392
+ this.pendingReplayElement = this.currentTargetElement;
1393
+ await this.stop(true);
1394
+ };
1378
1395
  this.audioElement = document.createElement('audio');
1379
1396
  this.audioElement.id = 'audio';
1380
1397
  document.body.appendChild(this.audioElement);
1381
1398
  this.registerGlobalStopEvents();
1399
+ this.registerVisibilityEvents();
1382
1400
  }
1383
1401
  static getI() {
1384
1402
  if (!AudioPlayer.instance) {
@@ -1386,7 +1404,12 @@ class AudioPlayer {
1386
1404
  }
1387
1405
  return AudioPlayer.instance;
1388
1406
  }
1389
- stop() {
1407
+ static destroyI() {
1408
+ if (AudioPlayer.instance) {
1409
+ AudioPlayer.instance.destroy();
1410
+ }
1411
+ }
1412
+ stop(preserveReplay = false) {
1390
1413
  const container = document.getElementById(LidoContainer);
1391
1414
  if (container && container.getAttribute('highlight-word-by-word') === 'true') {
1392
1415
  // stop any highlight loop
@@ -1402,6 +1425,10 @@ class AudioPlayer {
1402
1425
  this.endPromiseResolve = null;
1403
1426
  resolve();
1404
1427
  }
1428
+ if (!preserveReplay) {
1429
+ this.pendingReplayElement = null;
1430
+ }
1431
+ this.currentTargetElement = null;
1405
1432
  this.audioElement.pause();
1406
1433
  this.audioElement.currentTime = 0;
1407
1434
  this.audioElement.src = '';
@@ -1416,12 +1443,38 @@ class AudioPlayer {
1416
1443
  pauseElement.style.visibility = 'hidden';
1417
1444
  }
1418
1445
  }
1446
+ isWindowVisible() {
1447
+ return document.visibilityState === 'visible' && !document.hidden;
1448
+ }
1449
+ waitUntilWindowIsVisible() {
1450
+ if (this.isWindowVisible()) {
1451
+ return Promise.resolve();
1452
+ }
1453
+ this.registerVisibilityEvents();
1454
+ return new Promise(resolve => {
1455
+ this.visibilityWaitResolvers.push(resolve);
1456
+ });
1457
+ }
1458
+ resolveVisibilityWaiters() {
1459
+ const resolvers = this.visibilityWaitResolvers.splice(0);
1460
+ resolvers.forEach(resolve => resolve());
1461
+ }
1419
1462
  getLidoTextElement(el) {
1420
1463
  if (el.tagName.toLowerCase() === 'lido-text')
1421
1464
  return el;
1422
1465
  return el.closest('lido-text');
1423
1466
  }
1424
1467
  async play(targetElement) {
1468
+ this.registerVisibilityEvents();
1469
+ if (!this.isWindowVisible()) {
1470
+ this.pendingReplayElement = targetElement;
1471
+ await this.stop(true);
1472
+ await this.waitUntilWindowIsVisible();
1473
+ if (this.pendingReplayElement !== targetElement) {
1474
+ return;
1475
+ }
1476
+ this.pendingReplayElement = null;
1477
+ }
1425
1478
  // Stop any currently playing audio first if target element has audio given
1426
1479
  try {
1427
1480
  await AudioPlayer.getI().stop();
@@ -1449,6 +1502,7 @@ class AudioPlayer {
1449
1502
  this.stopOverlayHighlightLoop(); // stop any highlight loop;
1450
1503
  targetElement = textElement;
1451
1504
  }
1505
+ this.currentTargetElement = targetElement;
1452
1506
  // then play the target element audio.
1453
1507
  let audioUrl = targetElement.getAttribute('audio') || '';
1454
1508
  // If no direct audio attribute, check childrens for audio
@@ -1465,7 +1519,7 @@ class AudioPlayer {
1465
1519
  if (audioUrl) {
1466
1520
  audioUrl = convertUrlToRelative(audioUrl);
1467
1521
  this.audioElement.src = audioUrl;
1468
- console.log('🚀 Playing audio:', this.audioElement.src);
1522
+ // console.log('🚀 Playing audio:', this.audioElement.src);
1469
1523
  try {
1470
1524
  // setDraggingDisabled(true);
1471
1525
  const language = container.getAttribute('Lang') || 'en';
@@ -1529,10 +1583,10 @@ class AudioPlayer {
1529
1583
  else if (targetElement.textContent) {
1530
1584
  try {
1531
1585
  highlightSpeakingElement(targetElement);
1532
- window.addEventListener('click', this.handleUserClick, true);
1586
+ // window.addEventListener('click', this.handleUserClick, true);
1533
1587
  await speakText(targetElement.textContent, targetElement);
1534
- const highlightedElements = document.querySelectorAll('.speaking-highlight');
1535
- highlightedElements.forEach(element => stopHighlightForSpeakingElement(element));
1588
+ document.querySelectorAll('.speaking-highlight');
1589
+ // highlightedElements.forEach(element => stopHighlightForSpeakingElement(element as HTMLElement));
1536
1590
  }
1537
1591
  catch (error) {
1538
1592
  console.log('🎧 TTS Error:', error);
@@ -1541,6 +1595,17 @@ class AudioPlayer {
1541
1595
  setDraggingDisabled(false);
1542
1596
  }
1543
1597
  }
1598
+ const shouldReplayFromStart = this.pendingReplayElement === targetElement;
1599
+ if (shouldReplayFromStart) {
1600
+ await this.waitUntilWindowIsVisible();
1601
+ if (this.pendingReplayElement === targetElement) {
1602
+ this.pendingReplayElement = null;
1603
+ return this.play(targetElement);
1604
+ }
1605
+ }
1606
+ if (this.currentTargetElement === targetElement) {
1607
+ this.currentTargetElement = null;
1608
+ }
1544
1609
  }
1545
1610
  // GLOBAL STOP EVENTS (container change, activity change…)
1546
1611
  registerGlobalStopEvents() {
@@ -1552,10 +1617,26 @@ class AudioPlayer {
1552
1617
  window.addEventListener(key, () => this.stop());
1553
1618
  });
1554
1619
  }
1620
+ registerVisibilityEvents() {
1621
+ if (this.isVisibilityChangeRegistered) {
1622
+ return;
1623
+ }
1624
+ document.addEventListener('visibilitychange', this.handleVisibilityChange);
1625
+ this.isVisibilityChangeRegistered = true;
1626
+ }
1627
+ unregisterVisibilityEvents() {
1628
+ if (!this.isVisibilityChangeRegistered) {
1629
+ return;
1630
+ }
1631
+ document.removeEventListener('visibilitychange', this.handleVisibilityChange);
1632
+ this.isVisibilityChangeRegistered = false;
1633
+ this.resolveVisibilityWaiters();
1634
+ }
1555
1635
  // DESTROY (for hot-reload)
1556
1636
  destroy() {
1557
1637
  console.log("AudioPlayer destroyed (hot-reload safe)");
1558
1638
  this.stop();
1639
+ this.unregisterVisibilityEvents();
1559
1640
  // Remove DOM element
1560
1641
  if (this.audioElement.parentNode) {
1561
1642
  this.audioElement.parentNode.removeChild(this.audioElement);
@@ -3660,6 +3741,8 @@ function addClickListenerForClickType(element) {
3660
3741
  }
3661
3742
  const onClick = async () => {
3662
3743
  var _a;
3744
+ if (element === container)
3745
+ return;
3663
3746
  if (container.getAttribute("game-completed") === "true")
3664
3747
  return;
3665
3748
  const lido_buttons = element.getAttribute('id');
@@ -3751,7 +3834,9 @@ function addClickListenerForClickType(element) {
3751
3834
  container.setAttribute(SelectedValuesKey, JSON.stringify(sortedValues));
3752
3835
  const isCorrect = objective.includes(element['value']);
3753
3836
  dispatchClickEvent(element, isCorrect);
3754
- AudioPlayer.getI().stop();
3837
+ if (hasValidAudio) {
3838
+ AudioPlayer.getI().stop();
3839
+ }
3755
3840
  if (isCorrect) {
3756
3841
  const onCorrect = element.getAttribute('onCorrect');
3757
3842
  await executeActions(onCorrect, element);
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-DWfpvz_s.js');
3
+ var index = require('./index-BhikEYm-.js');
4
4
  require('./index-Bsk4M2Qz.js');
5
5
 
6
6
 
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var index = require('./index-Bsk4M2Qz.js');
4
- var index$1 = require('./index-DWfpvz_s.js');
4
+ var index$1 = require('./index-BhikEYm-.js');
5
5
 
6
6
  var rive$1 = {exports: {}};
7
7
 
@@ -12738,13 +12738,19 @@ const LidoHome = class {
12738
12738
  }, 100);
12739
12739
  };
12740
12740
  this.btnpopupRunId = 0;
12741
- this.handleWindowTouch = () => {
12742
- void this.cancelBtnpopupRun();
12741
+ this.activeBtnpopupRunId = null;
12742
+ this.shouldStopActiveBtnpopupAudio = true;
12743
+ this.handleWindowTouch = (event) => {
12744
+ if (this.activeBtnpopupRunId === null)
12745
+ return;
12746
+ void this.cancelBtnpopupRun(this.hasAudioOnInteractionTarget(event.target));
12743
12747
  };
12744
12748
  this.handleWindowPointer = (event) => {
12745
12749
  if (event.pointerType !== 'touch')
12746
12750
  return;
12747
- void this.cancelBtnpopupRun();
12751
+ if (this.activeBtnpopupRunId === null)
12752
+ return;
12753
+ void this.cancelBtnpopupRun(this.hasAudioOnInteractionTarget(event.target));
12748
12754
  };
12749
12755
  this.popUpClick = (comment) => {
12750
12756
  const alertElement = this.el.querySelector('.lido-alert-popup');
@@ -12880,7 +12886,7 @@ const LidoHome = class {
12880
12886
  }
12881
12887
  // Pure-JS fallback (no wasm asset required)
12882
12888
  try {
12883
- const brotliDecodeModule = await Promise.resolve().then(function () { return require('./decode-DkmQvXwq.js'); }).then(function (n) { return n.decode; });
12889
+ const brotliDecodeModule = await Promise.resolve().then(function () { return require('./decode-BvT284iq.js'); }).then(function (n) { return n.decode; });
12884
12890
  const brotliDecompressBuffer = brotliDecodeModule.BrotliDecompressBuffer || ((_a = brotliDecodeModule.default) === null || _a === void 0 ? void 0 : _a.BrotliDecompressBuffer);
12885
12891
  if (typeof brotliDecompressBuffer !== 'function') {
12886
12892
  throw new Error('BrotliDecompressBuffer function not found in brotli/dec/decode');
@@ -12973,6 +12979,7 @@ const LidoHome = class {
12973
12979
  * Lifecycle method that cleans up event listeners when the component is removed from the DOM.
12974
12980
  */
12975
12981
  disconnectedCallback() {
12982
+ index$1.AudioPlayer.destroyI();
12976
12983
  window.removeEventListener(index$1.NextContainerKey, () => {
12977
12984
  this.NextContainerKey();
12978
12985
  });
@@ -13173,7 +13180,9 @@ const LidoHome = class {
13173
13180
  await index$1.AudioPlayer.getI().play(htmlel);
13174
13181
  }
13175
13182
  if (index$1.getCancelBtnPopup() || isStale()) {
13176
- await index$1.AudioPlayer.getI().stop();
13183
+ if (this.shouldStopActiveBtnpopupAudio) {
13184
+ await index$1.AudioPlayer.getI().stop();
13185
+ }
13177
13186
  break;
13178
13187
  }
13179
13188
  await new Promise(resolve => setTimeout(resolve, 300));
@@ -13199,10 +13208,31 @@ const LidoHome = class {
13199
13208
  console.log('Not yet filled ');
13200
13209
  }
13201
13210
  }
13202
- async cancelBtnpopupRun() {
13211
+ hasAudioOnInteractionTarget(target) {
13212
+ const element = target;
13213
+ if (!element)
13214
+ return false;
13215
+ const hasValidAudio = (candidate) => {
13216
+ if (!(candidate instanceof HTMLElement))
13217
+ return false;
13218
+ const audioAttr = candidate.getAttribute('audio');
13219
+ return !!audioAttr && audioAttr.trim().length > 0;
13220
+ };
13221
+ if (hasValidAudio(element))
13222
+ return true;
13223
+ if (hasValidAudio(element.closest('[audio]')))
13224
+ return true;
13225
+ if (hasValidAudio(element.querySelector('[audio]')))
13226
+ return true;
13227
+ return false;
13228
+ }
13229
+ async cancelBtnpopupRun(shouldStopAudio = true) {
13203
13230
  this.btnpopupRunId++;
13231
+ this.shouldStopActiveBtnpopupAudio = shouldStopAudio;
13204
13232
  index$1.setCancelBtnPopup(true);
13205
- await index$1.AudioPlayer.getI().stop();
13233
+ if (shouldStopAudio) {
13234
+ await index$1.AudioPlayer.getI().stop();
13235
+ }
13206
13236
  }
13207
13237
  async handleBtnpopupClick() {
13208
13238
  // Invalidate any in-flight run and stop audio immediately.
@@ -13210,7 +13240,17 @@ const LidoHome = class {
13210
13240
  // Start fresh run.
13211
13241
  const nextRunId = this.btnpopupRunId;
13212
13242
  index$1.setCancelBtnPopup(false);
13213
- await this.btnpopup(nextRunId);
13243
+ this.activeBtnpopupRunId = nextRunId;
13244
+ this.shouldStopActiveBtnpopupAudio = true;
13245
+ try {
13246
+ await this.btnpopup(nextRunId);
13247
+ }
13248
+ finally {
13249
+ if (this.activeBtnpopupRunId === nextRunId) {
13250
+ this.activeBtnpopupRunId = null;
13251
+ }
13252
+ this.shouldStopActiveBtnpopupAudio = true;
13253
+ }
13214
13254
  }
13215
13255
  scaleNavbarContainer() {
13216
13256
  setTimeout(() => {
@@ -17379,7 +17419,7 @@ const LidoShape = class {
17379
17419
  };
17380
17420
  LidoShape.style = lidoShapeCss();
17381
17421
 
17382
- const lidoSlideFillCss = () => `.svg-element,svg{width:100%;height:100%}`;
17422
+ const lidoSlideFillCss = () => `.lido-svg-element,.lido-slide-svg{width:100%;height:100%}`;
17383
17423
 
17384
17424
  const LidoSlideFill = class {
17385
17425
  constructor(hostRef) {
@@ -17471,8 +17511,8 @@ const LidoSlideFill = class {
17471
17511
  <use xlink:href="#glassPath" />
17472
17512
  </clipPath>
17473
17513
  `;
17474
- svgText = svgText.replace(/<svg([^>]*)>/, `<svg$1>
17475
- ${clipPathDef}
17514
+ svgText = svgText.replace(/<svg([^>]*)>/, `<svg class="lido-slide-svg"$1>
17515
+ ${clipPathDef}
17476
17516
  `);
17477
17517
  svgText = svgText.replace(/<rect([^>]*)\/?>/, `<rect id="fillArea" $1 clip-path="url(#clipGlass)" />`);
17478
17518
  this.svgContent = svgText;
@@ -17507,7 +17547,7 @@ const LidoSlideFill = class {
17507
17547
  }
17508
17548
  updateFill() {
17509
17549
  var _a;
17510
- const svgEl = (_a = this.el.querySelector('.svg-element')) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
17550
+ const svgEl = (_a = this.el.querySelector('.lido-svg-element')) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
17511
17551
  if (!svgEl)
17512
17552
  return;
17513
17553
  const rect = svgEl.querySelector('#fillArea');
@@ -17561,7 +17601,7 @@ const LidoSlideFill = class {
17561
17601
  }
17562
17602
  addRulerNumbers() {
17563
17603
  var _a;
17564
- const svgEl = (_a = this.el.querySelector('.svg-element')) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
17604
+ const svgEl = (_a = this.el.querySelector('.lido-svg-element')) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
17565
17605
  if (!svgEl)
17566
17606
  return;
17567
17607
  const rulerPath = svgEl.querySelector('#rulerPath');
@@ -17597,7 +17637,7 @@ const LidoSlideFill = class {
17597
17637
  }
17598
17638
  }
17599
17639
  render() {
17600
- return (index.h(index.Host, { key: '9addda03d3a509cb0b23e88c59ad22c64dcd0044', id: this.id, class: "lido-slide-fill", src: this.src, fill: this.fill, fillDirection: this.fillDirection, slider: this.slider, style: this.style, min: this.min, max: this.max, division: this.division, numberType: this.numberType, onEntry: this.onEntry, type: this.type, "disable-speak": this.disableSpeak }, index.h("div", { key: 'e0d62ba6795bf0ac28e9e6b7dee5df04c2015ed5', innerHTML: this.svgContent, class: "svg-element" })));
17640
+ return (index.h(index.Host, { key: 'b9d026d02c325b4f1bc4d78a9ab1035a4da582f4', id: this.id, class: "lido-slide-fill", src: this.src, fill: this.fill, fillDirection: this.fillDirection, slider: this.slider, style: this.style, min: this.min, max: this.max, division: this.division, numberType: this.numberType, onEntry: this.onEntry, type: this.type, "disable-speak": this.disableSpeak }, index.h("div", { key: '53f70e11440aad0f60736a87489b488a81177c1a', innerHTML: this.svgContent, class: "lido-svg-element" })));
17601
17641
  }
17602
17642
  get el() { return index.getElement(this); }
17603
17643
  static get watchers() { return {
@@ -17882,7 +17922,7 @@ const LidoText = class {
17882
17922
  };
17883
17923
  LidoText.style = lidoTextCss();
17884
17924
 
17885
- const lidoTraceCss = () => `:host{display:block;position:relative}#lido-svgContainer{display:flex;justify-content:center;align-items:center;overflow:hidden}svg{width:100%;height:100%;touch-action:none}#lido-draggableCircle{cursor:pointer;fill:#CF1565;transition:fill 0.2s, r 0.2s}.lido-blindTracing{stroke:none !important}.lido-blindFreeTrace{stroke:none !important}.lido-hovered{cursor:grab;fill:darkred}#lido-controls{position:fixed;bottom:0;left:0;right:0;display:flex;justify-content:space-between;padding:10px;background-color:#f0f0f0;border-top:1px solid #ccc}button{padding:10px;font-size:16px}@media (max-width: 600px){button{padding:8px;font-size:14px}}.lido-trace-path-green{}.lido-flow-indicator{stroke:blue;stroke-width:2;stroke-dasharray:6, 6;fill:none}.lido-trace{height:700px;width:700px;z-index:1;justify-items:center;align-content:center}.trace-animate{animation:trace-bounce 0.5s}@keyframes trace-bounce{0%{transform:scale(1)}30%{transform:scale(1.05)}60%{transform:scale(0.95)}100%{transform:scale(1)}}`;
17925
+ const lidoTraceCss = () => `:host{display:block;position:relative}#lido-svgContainer{display:flex;justify-content:center;align-items:center;overflow:hidden}.lido-trace-svg{width:100%;height:100%;touch-action:none}#lido-draggableCircle{cursor:pointer;fill:#CF1565;transition:fill 0.2s, r 0.2s}.lido-blindTracing{stroke:none !important}.lido-blindFreeTrace{stroke:none !important}.lido-hovered{cursor:grab;fill:darkred}#lido-controls{position:fixed;bottom:0;left:0;right:0;display:flex;justify-content:space-between;padding:10px;background-color:#f0f0f0;border-top:1px solid #ccc}button{padding:10px;font-size:16px}@media (max-width: 600px){button{padding:8px;font-size:14px}}.lido-trace-path-green{}.lido-flow-indicator{stroke:blue;stroke-width:2;stroke-dasharray:6, 6;fill:none}.lido-trace{height:700px;width:700px;z-index:1;justify-items:center;align-content:center}.trace-animate{animation:trace-bounce 0.5s}@keyframes trace-bounce{0%{transform:scale(1)}30%{transform:scale(1.05)}60%{transform:scale(0.95)}100%{transform:scale(1)}}`;
17886
17926
 
17887
17927
  const LidoTrace = class {
17888
17928
  constructor(hostRef) {
@@ -18013,7 +18053,7 @@ const LidoTrace = class {
18013
18053
  circle: null,
18014
18054
  paths: [],
18015
18055
  svg: null,
18016
- proximityThreshold: 375, // Increased general proximity threshold (was 100)
18056
+ proximityThreshold: 60, // Increased general proximity threshold (was 100)
18017
18057
  freeTraceProximityThreshold: 350, // Increased proximity for free trace (was 50)
18018
18058
  rafId: null,
18019
18059
  pointerMoveEvent: null,
@@ -18154,6 +18194,7 @@ const LidoTrace = class {
18154
18194
  svgContainer.innerHTML = svgText;
18155
18195
  // After inserting, get the SVG element
18156
18196
  const svgElement = svgContainer.querySelector('svg');
18197
+ svgElement.classList.add('lido-trace-svg');
18157
18198
  // Remove the width and height attributes from the SVG element
18158
18199
  svgElement.removeAttribute('width');
18159
18200
  svgElement.removeAttribute('height');
@@ -18860,7 +18901,7 @@ const LidoTrace = class {
18860
18901
  };
18861
18902
  }
18862
18903
  render() {
18863
- return (index.h(index.Host, { key: '47a5947638a6a6c84cd294d6b3d8062a36553fc1', class: "lido-trace", id: this.id, audio: this.audio, onCorrect: this.onCorrect, onInCorrect: this.onInCorrect, style: this.style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, tabindex: this.tabIndex, "disable-speak": this.disableSpeak }, index.h("div", { key: '13e10f42f4747405ebe8c9ef5826f386a1e894e9', style: this.style, id: "lido-svgContainer" })));
18904
+ return (index.h(index.Host, { key: 'ad97a2d2c254f734133d045536f0401cc8b9d757', class: "lido-trace", id: this.id, audio: this.audio, onCorrect: this.onCorrect, onInCorrect: this.onInCorrect, style: this.style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, tabindex: this.tabIndex, "disable-speak": this.disableSpeak }, index.h("div", { key: '49c77a05b424e8443ec5af28de1ca8bc2be190c2', style: this.style, id: "lido-svgContainer" })));
18864
18905
  }
18865
18906
  static get assetsDirs() { return ["svg", "images"]; }
18866
18907
  get el() { return index.getElement(this); }
@@ -149,13 +149,19 @@ export class LidoHome {
149
149
  }, 100);
150
150
  };
151
151
  this.btnpopupRunId = 0;
152
- this.handleWindowTouch = () => {
153
- void this.cancelBtnpopupRun();
152
+ this.activeBtnpopupRunId = null;
153
+ this.shouldStopActiveBtnpopupAudio = true;
154
+ this.handleWindowTouch = (event) => {
155
+ if (this.activeBtnpopupRunId === null)
156
+ return;
157
+ void this.cancelBtnpopupRun(this.hasAudioOnInteractionTarget(event.target));
154
158
  };
155
159
  this.handleWindowPointer = (event) => {
156
160
  if (event.pointerType !== 'touch')
157
161
  return;
158
- void this.cancelBtnpopupRun();
162
+ if (this.activeBtnpopupRunId === null)
163
+ return;
164
+ void this.cancelBtnpopupRun(this.hasAudioOnInteractionTarget(event.target));
159
165
  };
160
166
  this.popUpClick = (comment) => {
161
167
  const alertElement = this.el.querySelector('.lido-alert-popup');
@@ -384,6 +390,7 @@ export class LidoHome {
384
390
  * Lifecycle method that cleans up event listeners when the component is removed from the DOM.
385
391
  */
386
392
  disconnectedCallback() {
393
+ AudioPlayer.destroyI();
387
394
  window.removeEventListener(NextContainerKey, () => {
388
395
  this.NextContainerKey();
389
396
  });
@@ -584,7 +591,9 @@ export class LidoHome {
584
591
  await AudioPlayer.getI().play(htmlel);
585
592
  }
586
593
  if (getCancelBtnPopup() || isStale()) {
587
- await AudioPlayer.getI().stop();
594
+ if (this.shouldStopActiveBtnpopupAudio) {
595
+ await AudioPlayer.getI().stop();
596
+ }
588
597
  break;
589
598
  }
590
599
  await new Promise(resolve => setTimeout(resolve, 300));
@@ -610,10 +619,31 @@ export class LidoHome {
610
619
  console.log('Not yet filled ');
611
620
  }
612
621
  }
613
- async cancelBtnpopupRun() {
622
+ hasAudioOnInteractionTarget(target) {
623
+ const element = target;
624
+ if (!element)
625
+ return false;
626
+ const hasValidAudio = (candidate) => {
627
+ if (!(candidate instanceof HTMLElement))
628
+ return false;
629
+ const audioAttr = candidate.getAttribute('audio');
630
+ return !!audioAttr && audioAttr.trim().length > 0;
631
+ };
632
+ if (hasValidAudio(element))
633
+ return true;
634
+ if (hasValidAudio(element.closest('[audio]')))
635
+ return true;
636
+ if (hasValidAudio(element.querySelector('[audio]')))
637
+ return true;
638
+ return false;
639
+ }
640
+ async cancelBtnpopupRun(shouldStopAudio = true) {
614
641
  this.btnpopupRunId++;
642
+ this.shouldStopActiveBtnpopupAudio = shouldStopAudio;
615
643
  setCancelBtnPopup(true);
616
- await AudioPlayer.getI().stop();
644
+ if (shouldStopAudio) {
645
+ await AudioPlayer.getI().stop();
646
+ }
617
647
  }
618
648
  async handleBtnpopupClick() {
619
649
  // Invalidate any in-flight run and stop audio immediately.
@@ -621,7 +651,17 @@ export class LidoHome {
621
651
  // Start fresh run.
622
652
  const nextRunId = this.btnpopupRunId;
623
653
  setCancelBtnPopup(false);
624
- await this.btnpopup(nextRunId);
654
+ this.activeBtnpopupRunId = nextRunId;
655
+ this.shouldStopActiveBtnpopupAudio = true;
656
+ try {
657
+ await this.btnpopup(nextRunId);
658
+ }
659
+ finally {
660
+ if (this.activeBtnpopupRunId === nextRunId) {
661
+ this.activeBtnpopupRunId = null;
662
+ }
663
+ this.shouldStopActiveBtnpopupAudio = true;
664
+ }
625
665
  }
626
666
  scaleNavbarContainer() {
627
667
  setTimeout(() => {
@@ -1,4 +1,4 @@
1
- .svg-element, svg {
1
+ .lido-svg-element, .lido-slide-svg {
2
2
  width: 100%;
3
3
  height: 100%;
4
4
  }
@@ -90,8 +90,8 @@ export class LidoSlideFill {
90
90
  <use xlink:href="#glassPath" />
91
91
  </clipPath>
92
92
  `;
93
- svgText = svgText.replace(/<svg([^>]*)>/, `<svg$1>
94
- ${clipPathDef}
93
+ svgText = svgText.replace(/<svg([^>]*)>/, `<svg class="lido-slide-svg"$1>
94
+ ${clipPathDef}
95
95
  `);
96
96
  svgText = svgText.replace(/<rect([^>]*)\/?>/, `<rect id="fillArea" $1 clip-path="url(#clipGlass)" />`);
97
97
  this.svgContent = svgText;
@@ -126,7 +126,7 @@ export class LidoSlideFill {
126
126
  }
127
127
  updateFill() {
128
128
  var _a;
129
- const svgEl = (_a = this.el.querySelector('.svg-element')) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
129
+ const svgEl = (_a = this.el.querySelector('.lido-svg-element')) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
130
130
  if (!svgEl)
131
131
  return;
132
132
  const rect = svgEl.querySelector('#fillArea');
@@ -180,7 +180,7 @@ export class LidoSlideFill {
180
180
  }
181
181
  addRulerNumbers() {
182
182
  var _a;
183
- const svgEl = (_a = this.el.querySelector('.svg-element')) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
183
+ const svgEl = (_a = this.el.querySelector('.lido-svg-element')) === null || _a === void 0 ? void 0 : _a.querySelector('svg');
184
184
  if (!svgEl)
185
185
  return;
186
186
  const rulerPath = svgEl.querySelector('#rulerPath');
@@ -216,7 +216,7 @@ export class LidoSlideFill {
216
216
  }
217
217
  }
218
218
  render() {
219
- return (h(Host, { key: '9addda03d3a509cb0b23e88c59ad22c64dcd0044', id: this.id, class: "lido-slide-fill", src: this.src, fill: this.fill, fillDirection: this.fillDirection, slider: this.slider, style: this.style, min: this.min, max: this.max, division: this.division, numberType: this.numberType, onEntry: this.onEntry, type: this.type, "disable-speak": this.disableSpeak }, h("div", { key: 'e0d62ba6795bf0ac28e9e6b7dee5df04c2015ed5', innerHTML: this.svgContent, class: "svg-element" })));
219
+ return (h(Host, { key: 'b9d026d02c325b4f1bc4d78a9ab1035a4da582f4', id: this.id, class: "lido-slide-fill", src: this.src, fill: this.fill, fillDirection: this.fillDirection, slider: this.slider, style: this.style, min: this.min, max: this.max, division: this.division, numberType: this.numberType, onEntry: this.onEntry, type: this.type, "disable-speak": this.disableSpeak }, h("div", { key: '53f70e11440aad0f60736a87489b488a81177c1a', innerHTML: this.svgContent, class: "lido-svg-element" })));
220
220
  }
221
221
  static get is() { return "lido-slide-fill"; }
222
222
  static get originalStyleUrls() {
@@ -15,7 +15,7 @@
15
15
  overflow: hidden;
16
16
  }
17
17
 
18
- svg {
18
+ .lido-trace-svg {
19
19
  width: 100%;
20
20
  height: 100%;
21
21
  /* max-height: calc(100vh - 50px); */
@@ -130,7 +130,7 @@ export class LidoTrace {
130
130
  circle: null,
131
131
  paths: [],
132
132
  svg: null,
133
- proximityThreshold: 375, // Increased general proximity threshold (was 100)
133
+ proximityThreshold: 60, // Increased general proximity threshold (was 100)
134
134
  freeTraceProximityThreshold: 350, // Increased proximity for free trace (was 50)
135
135
  rafId: null,
136
136
  pointerMoveEvent: null,
@@ -271,6 +271,7 @@ export class LidoTrace {
271
271
  svgContainer.innerHTML = svgText;
272
272
  // After inserting, get the SVG element
273
273
  const svgElement = svgContainer.querySelector('svg');
274
+ svgElement.classList.add('lido-trace-svg');
274
275
  // Remove the width and height attributes from the SVG element
275
276
  svgElement.removeAttribute('width');
276
277
  svgElement.removeAttribute('height');
@@ -977,7 +978,7 @@ export class LidoTrace {
977
978
  };
978
979
  }
979
980
  render() {
980
- return (h(Host, { key: '47a5947638a6a6c84cd294d6b3d8062a36553fc1', class: "lido-trace", id: this.id, audio: this.audio, onCorrect: this.onCorrect, onInCorrect: this.onInCorrect, style: this.style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, tabindex: this.tabIndex, "disable-speak": this.disableSpeak }, h("div", { key: '13e10f42f4747405ebe8c9ef5826f386a1e894e9', style: this.style, id: "lido-svgContainer" })));
981
+ return (h(Host, { key: 'ad97a2d2c254f734133d045536f0401cc8b9d757', class: "lido-trace", id: this.id, audio: this.audio, onCorrect: this.onCorrect, onInCorrect: this.onInCorrect, style: this.style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, tabindex: this.tabIndex, "disable-speak": this.disableSpeak }, h("div", { key: '49c77a05b424e8443ec5af28de1ca8bc2be190c2', style: this.style, id: "lido-svgContainer" })));
981
982
  }
982
983
  static get is() { return "lido-trace"; }
983
984
  static get originalStyleUrls() {