lido-player 0.0.2-alpha-98 → 0.0.2-alpha-99

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 (34) hide show
  1. package/dist/cjs/{decode-afeNWInB.js → decode-Bw2Aqe6S.js} +1 -1
  2. package/dist/cjs/{index-Dl8SlqP-.js → index-Bsk4M2Qz.js} +36 -9
  3. package/dist/cjs/{index-DMfHwNdL.js → index-Cmk1eaCV.js} +17 -1
  4. package/dist/cjs/index.cjs.js +2 -2
  5. package/dist/cjs/lido-avatar_22.cjs.entry.js +67 -37
  6. package/dist/cjs/lido-player.cjs.js +2 -2
  7. package/dist/cjs/loader.cjs.js +1 -1
  8. package/dist/collection/collection-manifest.json +1 -1
  9. package/dist/collection/components/trace/lido-trace.js +64 -34
  10. package/dist/collection/utils/utilsHandlers/dragDropHandler.js +16 -0
  11. package/dist/components/index.js +1 -1
  12. package/dist/components/lido-home.js +1 -1
  13. package/dist/components/lido-root.js +1 -1
  14. package/dist/components/lido-trace.js +1 -1
  15. package/dist/components/p-D2I4rurf.js +1 -0
  16. package/dist/components/{p-DsaycW90.js → p-DdjiT37N.js} +1 -1
  17. package/dist/esm/{decode-ChEy8Z68.js → decode-BqPxsId-.js} +1 -1
  18. package/dist/esm/{index-DwX5MikQ.js → index-BNZwxVWj.js} +17 -1
  19. package/dist/esm/{index-C7XdSFIP.js → index-Dfvjtz8r.js} +36 -9
  20. package/dist/esm/index.js +2 -2
  21. package/dist/esm/lido-avatar_22.entry.js +67 -37
  22. package/dist/esm/lido-player.js +3 -3
  23. package/dist/esm/loader.js +2 -2
  24. package/dist/lido-player/index.esm.js +1 -1
  25. package/dist/lido-player/lido-player.esm.js +1 -1
  26. package/dist/lido-player/{p-Cn2i_VLp.js → p-BFlGDCI4.js} +1 -1
  27. package/dist/lido-player/p-CXTdf__z.js +1 -0
  28. package/dist/lido-player/p-Dfvjtz8r.js +2 -0
  29. package/dist/lido-player/{p-a5f04b97.entry.js → p-b28417ad.entry.js} +1 -1
  30. package/dist/types/components/trace/lido-trace.d.ts +1 -1
  31. package/package.json +1 -1
  32. package/dist/components/p-B4Jyt3YL.js +0 -1
  33. package/dist/lido-player/p-C-h69UYH.js +0 -1
  34. package/dist/lido-player/p-C7XdSFIP.js +0 -2
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-DMfHwNdL.js');
3
+ var index = require('./index-Cmk1eaCV.js');
4
4
 
5
5
  function _mergeNamespaces(n, m) {
6
6
  m.forEach(function (e) {
@@ -25,7 +25,7 @@ const globalScripts = () => {};
25
25
  const globalStyles = "@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Baloo+2:wght@400..800&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Baloo+Bhai+2:wght@400..800&display=swap'); body{overflow:hidden;background-position:center;background-size:cover;background-repeat:no-repeat;height:100vh}*{user-select:none}.lido-disable-check-button{pointer-events:none;background-color:#9393935c !important;color:white}.lido-element-selected{border:2px solid;background-color:#ffdf7d !important}.diagonal-target,.diagonal-drop *{transform:scale(0.8) !important;opacity:1 !important}.cloned-element{display:flex !important;position:absolute !important;filter:grayscale(100%);pointer-events:none}.removeShadow{box-shadow:0px 0px 0px 0px #ff8900 !important}.highlight-element{border:2px solid white;box-shadow:rgb(243, 77, 8) 0px 0px 40px !important}.drop-element.empty{border:4px dashed #f34d08 !important}.drop-element.filled{border:'none' !important}.drag-element{box-shadow:0px 15px 11px rgba(43, 0, 0, 0.3) !important}.drag-element.dropped{box-shadow:none !important}.click-element{background-color:var(--btn-bg-color, rgba(255, 172, 76, 1)) !important;box-shadow:var(--btn-shadow-px) var(--btn-shadow-color, rgba(225, 121, 76, 1)) !important;cursor:pointer;transition:box-shadow 0.1s ease-out, transform 0.2s ease-out;}.click-element:active{box-shadow:0px 0px 0px var(--btn-shadow-color, rgba(225, 121, 76, 1)) !important;transform:translateY(var(--btn-active));}.click-element:focus{outline:2px solid dodgerblue;outline-offset:3px}.after-drop-popup-container{width:200%;height:200%;background-color:rgba(0, 0, 0, 0.8);position:absolute;display:flex;flex-direction:row-reverse;align-items:center;justify-content:center !important;gap:80px}.after-drop-popup-drag-element{scale:1.5;border-radius:8px;transform:none !important;position:unset !important}.after-drop-popup-drop-element{scale:1.5;border:unset;border-radius:8px;transform:none !important;position:unset !important}@keyframes zoomFadeIn{0%{transform:scale(0.6);opacity:0}100%{transform:scale(1);opacity:1}}.zoom-fade-in{animation:zoomFadeIn 0.8s ease-out forwards}@keyframes zoomFadeOut{0%{transform:scale(1);opacity:1}100%{transform:scale(0.6);opacity:0}}.zoom-fade-out{animation:zoomFadeOut 0.8s ease-in forwards}.slide-numbers{width:70px;height:70px;border:1px solid #f57139;background-color:white;font-weight:500;color:#f57139;font-size:44px;border-radius:40px;display:flex;align-items:center;justify-content:center;font-family:'Baloo Bhai 2', serif}.slide-numbers-bottom{position:absolute;display:flex;justify-content:space-around;align-items:center;bottom:-25px;width:100%;height:50px}.slide-numbers-left{position:absolute;display:flex;flex-direction:column;justify-content:space-around;height:100%;width:50px;left:-25px;bottom:0px}.lido-speak-icon{width:56px;height:56px;position:absolute;top:-25px;right:-25px;z-index:10;background-image:url(\"https://aeakbcdznktpsbrfsgys.supabase.co/storage/v1/object/public/template-assets/template/audioIcon.png\");background-color:white;border:4px solid #F34D08;border-radius:16px;box-shadow:0px 4px 0px 0px #F34D08;background-size:contain;background-repeat:no-repeat;cursor:pointer}.lido-speak-icon:active{transform:translateY(8px);box-shadow:0px 0px 0px 0px !important}.lido-strong-shake{animation:strongShake 0.3s ease}.lido-scaled-shake{animation:scaledShake 0.6s ease-in-out}.lido-horizontal-shake{animation:horizontalShake 0.6s ease-in-out;border-radius:20px}.lido-vertical-shake{animation:verticalShake 0.6s ease-in-out;border-radius:20px}.lido-diagonal-shake{animation:diagonalShake 0.5s ease-in-out;border-radius:20px;will-change:transform}.lido-glow{animation:glowPulse 1s infinite alternate;transition:opacity 0.5s ease-in-out}.lido-box-highlight{animation:topToPlace 0.3s linear}.lido-display-hiddenvalue{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:80px;font-weight:1000;color:brown;-webkit-text-stroke:2px white;font-family:'Baloo Bhai 2', sans-serif;pointer-events:none}.lido-image-colorize{position:relative;display:inline-block}.lido-image-colorize::after{content:'';position:absolute;inset:0;background:var(--tint-color);mix-blend-mode:multiply;opacity:0.8;pointer-events:none;mask-image:var(--mask-url);mask-size:cover;mask-repeat:no-repeat;mask-position:center}.lido-tts-highlight-overlay{position:fixed;pointer-events:none;z-index:9999;background:linear-gradient(\r\n 180deg,\r\n rgba(255, 235, 59, 0.95),\r\n rgba(255, 214, 0, 0.95)\r\n );border-radius:6px;box-shadow:0 2px 6px rgba(0, 0, 0, 0.18),\r\n inset 0 -1px 0 rgba(255, 255, 255, 0.25);transition:left 55ms linear,\r\n top 55ms linear,\r\n width 55ms ease-out,\r\n height 55ms ease-out,\r\n opacity 80ms ease-out;opacity:0.95;will-change:transform, width, height}";
26
26
 
27
27
  /*
28
- Stencil Client Platform v4.43.3 | MIT Licensed | https://stenciljs.com
28
+ Stencil Client Platform v4.43.4 | MIT Licensed | https://stenciljs.com
29
29
  */
30
30
 
31
31
 
@@ -599,6 +599,31 @@ var newVNode = (tag, text) => {
599
599
  var Host = {};
600
600
  var isHost = (node) => node && node.$tag$ === Host;
601
601
 
602
+ // src/runtime/normalize-watchers.ts
603
+ var normalizeWatchers = (raw) => {
604
+ if (!raw) return void 0;
605
+ const keys = Object.keys(raw);
606
+ if (keys.length === 0) return void 0;
607
+ let hasLegacy = false;
608
+ for (const propName of keys) {
609
+ if (hasLegacy) break;
610
+ for (const h2 of raw[propName]) {
611
+ if (typeof h2 === "string") {
612
+ hasLegacy = true;
613
+ break;
614
+ }
615
+ }
616
+ }
617
+ if (!hasLegacy) return raw;
618
+ const out = {};
619
+ for (const propName of keys) {
620
+ out[propName] = raw[propName].map(
621
+ (h2) => typeof h2 === "string" ? { [h2]: 0 } : h2
622
+ );
623
+ }
624
+ return out;
625
+ };
626
+
602
627
  // src/runtime/parse-property-value.ts
603
628
  var parsePropertyValue = (propValue, propType, isFormAssociated) => {
604
629
  if (propValue != null && !isComplexType(propValue)) {
@@ -1582,7 +1607,7 @@ var proxyComponent = (Cstr, cmpMeta, flags) => {
1582
1607
  if (cmpMeta.$members$ || BUILD.propChangeCallback) {
1583
1608
  {
1584
1609
  if (Cstr.watchers && !cmpMeta.$watchers$) {
1585
- cmpMeta.$watchers$ = Cstr.watchers;
1610
+ cmpMeta.$watchers$ = normalizeWatchers(Cstr.watchers);
1586
1611
  }
1587
1612
  if (Cstr.deserializers && !cmpMeta.$deserializers$) {
1588
1613
  cmpMeta.$deserializers$ = Cstr.deserializers;
@@ -1708,11 +1733,13 @@ var proxyComponent = (Cstr, cmpMeta, flags) => {
1708
1733
  return;
1709
1734
  }
1710
1735
  const propFlags = members.find(([m]) => m === propName);
1711
- if (propFlags && propFlags[1][0] & 4 /* Boolean */) {
1736
+ const isBooleanTarget = propFlags && propFlags[1][0] & 4 /* Boolean */;
1737
+ const isSpuriousBooleanRemoval = isBooleanTarget && newValue === null && this[propName] === void 0;
1738
+ if (isBooleanTarget) {
1712
1739
  newValue = newValue === null || newValue === "false" ? false : true;
1713
1740
  }
1714
1741
  const propDesc = Object.getOwnPropertyDescriptor(prototype, propName);
1715
- if (newValue != this[propName] && (!propDesc.get || !!propDesc.set)) {
1742
+ if (!isSpuriousBooleanRemoval && newValue != this[propName] && (!propDesc.get || !!propDesc.set)) {
1716
1743
  this[propName] = newValue;
1717
1744
  }
1718
1745
  });
@@ -1757,7 +1784,7 @@ var initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId) => {
1757
1784
  }
1758
1785
  if (!Cstr.isProxied) {
1759
1786
  {
1760
- cmpMeta.$watchers$ = Cstr.watchers;
1787
+ cmpMeta.$watchers$ = normalizeWatchers(Cstr.watchers);
1761
1788
  cmpMeta.$serializers$ = Cstr.serializers;
1762
1789
  cmpMeta.$deserializers$ = Cstr.deserializers;
1763
1790
  }
@@ -1930,7 +1957,7 @@ var bootstrapLazy = (lazyBundles, options = {}) => {
1930
1957
  let hasSlotRelocation = false;
1931
1958
  lazyBundles.map((lazyBundle) => {
1932
1959
  lazyBundle[1].map((compactMeta) => {
1933
- var _a2, _b, _c;
1960
+ var _a2, _b;
1934
1961
  const cmpMeta = {
1935
1962
  $flags$: compactMeta[0],
1936
1963
  $tagName$: compactMeta[1],
@@ -1947,9 +1974,9 @@ var bootstrapLazy = (lazyBundles, options = {}) => {
1947
1974
  cmpMeta.$attrsToReflect$ = [];
1948
1975
  }
1949
1976
  {
1950
- cmpMeta.$watchers$ = (_a2 = compactMeta[4]) != null ? _a2 : {};
1951
- cmpMeta.$serializers$ = (_b = compactMeta[5]) != null ? _b : {};
1952
- cmpMeta.$deserializers$ = (_c = compactMeta[6]) != null ? _c : {};
1977
+ cmpMeta.$watchers$ = normalizeWatchers(compactMeta[4]);
1978
+ cmpMeta.$serializers$ = (_a2 = compactMeta[5]) != null ? _a2 : {};
1979
+ cmpMeta.$deserializers$ = (_b = compactMeta[6]) != null ? _b : {};
1953
1980
  }
1954
1981
  const tagName = transformTag(cmpMeta.$tagName$);
1955
1982
  const HostElement = class extends HTMLElement {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index$1 = require('./index-Dl8SlqP-.js');
3
+ var index$1 = require('./index-Bsk4M2Qz.js');
4
4
 
5
5
  const DragMapKey = 'lidoDragMap';
6
6
  const SelectedValuesKey = 'lidoSelectedValues';
@@ -567,6 +567,8 @@ function enableDraggingWithScaling(element) {
567
567
  handleResetDragElement(element, mostOverlappedElement, dropHasDrag, null, dragSelectedData);
568
568
  return;
569
569
  }
570
+ element.style.pointerEvents = 'none'; // Disable pointer events on drag element to prevent interference during drop handling
571
+ mostOverlappedElement.style.pointerEvents = 'none';
570
572
  onElementDropComplete(element, mostOverlappedElement);
571
573
  if (templateId === "blender" && element && mostOverlappedElement) {
572
574
  const allElements = document.querySelectorAll(`*`);
@@ -576,6 +578,11 @@ function enableDraggingWithScaling(element) {
576
578
  mostOverlappedElement.classList.add("highlight-element");
577
579
  }
578
580
  executeActions("this.updateCountBlender='true'", container);
581
+ setTimeout(() => {
582
+ element.style.pointerEvents = '';
583
+ mostOverlappedElement.style.pointerEvents = '';
584
+ }, 1000);
585
+ // element.style.pointerEvents = ''; // Re-enable pointer events on drag element after drop handling
579
586
  if (((_b = element.getAttribute('dropAttr')) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === DropMode.Diagonal) {
580
587
  if (mostOverlappedElement) {
581
588
  if (element) {
@@ -1053,6 +1060,7 @@ async function onClickDropOrDragElement(element, type) {
1053
1060
  // Remove the highlight class from elements matching the selector
1054
1061
  const highlightedElements = document.querySelectorAll(`[type='${type}']`);
1055
1062
  highlightedElements.forEach(el => {
1063
+ el.style.pointerEvents = ''; // Re-enable pointer events
1056
1064
  removeHighlight(el);
1057
1065
  });
1058
1066
  // Dynamically create the highlight class if it doesn't exist
@@ -1071,17 +1079,22 @@ async function onClickDropOrDragElement(element, type) {
1071
1079
  document.head.appendChild(style);
1072
1080
  }
1073
1081
  element === null || element === void 0 ? void 0 : element.classList.add('highlight-element');
1082
+ element.style.pointerEvents = "none";
1074
1083
  element.ariaPressed = 'true';
1075
1084
  const selectedDropElement = type === 'drop' ? element : document.querySelector("[type='drop'].highlight-element");
1076
1085
  const selectedDragElement = type === 'drag' ? element : document.querySelector("[type='drag'].highlight-element");
1077
1086
  if (!selectedDropElement || element.classList.contains("dropped")) {
1078
1087
  console.log("hello");
1079
1088
  onClickDragElement(element);
1089
+ element.style.pointerEvents = ""; // Re-enable pointer events if it was a drag element
1080
1090
  return;
1081
1091
  }
1082
1092
  if (element.classList.contains("drop-element"))
1083
1093
  return;
1084
1094
  if (selectedDropElement && selectedDragElement) {
1095
+ selectedDropElement.style.pointerEvents = 'none'; // Disable pointer events on drop element during animation
1096
+ selectedDragElement.style.pointerEvents = 'none'; // Disable pointer events on drag element during animation
1097
+ console.log("drop called!!!");
1085
1098
  if (selectedDragElement.getAttribute('drop-to'))
1086
1099
  return;
1087
1100
  // Add a transition for a smooth, slower movement
@@ -1108,10 +1121,13 @@ async function onClickDropOrDragElement(element, type) {
1108
1121
  }
1109
1122
  // await new Promise(resolve => setTimeout(resolve, 500));
1110
1123
  await onElementDropComplete(selectedDragElement, selectedDropElement);
1124
+ selectedDragElement.style.pointerEvents = ''; // Re-enable pointer events on drag element after animation
1125
+ selectedDropElement.style.pointerEvents = ''; // Re-enable pointer events on drop element after animation
1111
1126
  // ensure count update for click-to-drop flow
1112
1127
  await executeActions("this.updateCountBlender='true'", container);
1113
1128
  // await new Promise(resolve => setTimeout(resolve, 500));
1114
1129
  // selectedDragElement.style.transform = 'translate(0px, 0px)';
1130
+ // selectedDropElement.style.pointerEvents = '';
1115
1131
  }
1116
1132
  }
1117
1133
  const dragToDropMap = new Map();
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-DMfHwNdL.js');
4
- require('./index-Dl8SlqP-.js');
3
+ var index = require('./index-Cmk1eaCV.js');
4
+ require('./index-Bsk4M2Qz.js');
5
5
 
6
6
 
7
7
 
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-Dl8SlqP-.js');
4
- var index$1 = require('./index-DMfHwNdL.js');
3
+ var index = require('./index-Bsk4M2Qz.js');
4
+ var index$1 = require('./index-Cmk1eaCV.js');
5
5
 
6
6
  var rive$1 = {exports: {}};
7
7
 
@@ -12874,7 +12874,7 @@ const LidoHome = class {
12874
12874
  }
12875
12875
  // Pure-JS fallback (no wasm asset required)
12876
12876
  try {
12877
- const brotliDecodeModule = await Promise.resolve().then(function () { return require('./decode-afeNWInB.js'); }).then(function (n) { return n.decode; });
12877
+ const brotliDecodeModule = await Promise.resolve().then(function () { return require('./decode-Bw2Aqe6S.js'); }).then(function (n) { return n.decode; });
12878
12878
  const brotliDecompressBuffer = brotliDecodeModule.BrotliDecompressBuffer || ((_a = brotliDecodeModule.default) === null || _a === void 0 ? void 0 : _a.BrotliDecompressBuffer);
12879
12879
  if (typeof brotliDecompressBuffer !== 'function') {
12880
12880
  throw new Error('BrotliDecompressBuffer function not found in brotli/dec/decode');
@@ -18308,6 +18308,7 @@ const LidoTrace = class {
18308
18308
  state.isDragging = true;
18309
18309
  state.activePointerId = evt.pointerId;
18310
18310
  state.circle.setPointerCapture(evt.pointerId);
18311
+ state.lastPointerPos = pointerPos;
18311
18312
  }
18312
18313
  this.hideFingerHint(); // ← NEW
18313
18314
  this.resetIdleTimer(state); // ← NEW
@@ -18329,6 +18330,7 @@ const LidoTrace = class {
18329
18330
  if (evt.pointerId === state.activePointerId) {
18330
18331
  state.isDragging = false;
18331
18332
  state.activePointerId = null;
18333
+ state.lastPointerPos = null;
18332
18334
  this.hideFingerHint(); // ← NEW
18333
18335
  this.resetIdleTimer(state); // ← NEW
18334
18336
  }
@@ -18356,10 +18358,12 @@ const LidoTrace = class {
18356
18358
  };
18357
18359
  // Only update if pointer moved a minimum distance (to reduce unnecessary updates)
18358
18360
  const MOVE_THRESHOLD = 1; // px
18361
+ let pointerMoveDistanceSquared = Infinity;
18359
18362
  if (state.lastPointerPos) {
18360
18363
  const dx = pointerPos.x - state.lastPointerPos.x;
18361
18364
  const dy = pointerPos.y - state.lastPointerPos.y;
18362
- if (dx * dx + dy * dy < MOVE_THRESHOLD * MOVE_THRESHOLD) {
18365
+ pointerMoveDistanceSquared = dx * dx + dy * dy;
18366
+ if (pointerMoveDistanceSquared < MOVE_THRESHOLD * MOVE_THRESHOLD) {
18363
18367
  return;
18364
18368
  }
18365
18369
  }
@@ -18382,14 +18386,15 @@ const LidoTrace = class {
18382
18386
  if (distanceSquared > proximitySquared) {
18383
18387
  return; // Skip any further actions
18384
18388
  }
18385
- const closestPoint = this.getClosestPointOnPath(currentPath, pointerPos);
18389
+ const isFreeTraceMode = state.mode === index$1.TraceMode.FreeTrace || state.mode === index$1.TraceMode.BlindFreeTrace;
18390
+ const closestPoint = this.getClosestPointOnPath(currentPath, pointerPos, isFreeTraceMode ? undefined : state.lastLength);
18386
18391
  // Ensure drawing happens only within proximity threshold
18387
18392
  const distanceToPathSquared = this.getDistanceSquared(pointerPos, closestPoint);
18388
18393
  if (distanceToPathSquared > proximitySquared) {
18389
18394
  return; // Skip drawing if too far from the path
18390
18395
  }
18391
18396
  // For free trace mode and blind free trace mode, allow free drawing only if within the reduced proximity threshold
18392
- if (state.mode === index$1.TraceMode.FreeTrace || state.mode === index$1.TraceMode.BlindFreeTrace) {
18397
+ if (isFreeTraceMode) {
18393
18398
  // Throttle: Only update every 2nd event (for reducing excessive dom updates)
18394
18399
  this.freeTraceUpdateCounter = (this.freeTraceUpdateCounter || 0) + 1;
18395
18400
  if (this.freeTraceUpdateCounter % 2 !== 0) {
@@ -18463,12 +18468,34 @@ const LidoTrace = class {
18463
18468
  return; // Exit early since we're in free trace or blind free trace mode
18464
18469
  }
18465
18470
  // In normal modes, allow movement and drawing only within the general proximity threshold
18466
- if (state.isDragging && closestPoint.length >= state.lastLength) {
18467
- state.lastLength = closestPoint.length;
18471
+ const BACKWARD_TOLERANCE = 20; // allow slight backward movement
18472
+ const MAX_FORWARD_JUMP = 80; // prevent jumping to wrong segment
18473
+ const RECOVERY_FORWARD_JUMP = Math.min(320, Math.max(160, state.totalPathLength * 0.45)); // recover on long strokes without skipping short paths
18474
+ const RECOVERY_END_BUFFER = Math.min(60, Math.max(24, state.totalPathLength * 0.12)); // don't let recovery auto-finish the last part
18475
+ const RECOVERY_POINTER_MOVE_THRESHOLD = 8; // only recover after a meaningful drag, not during slow tracing
18476
+ let guidedClosestPoint = closestPoint;
18477
+ let isValidProgress = guidedClosestPoint.length >= state.lastLength - BACKWARD_TOLERANCE &&
18478
+ guidedClosestPoint.length - state.lastLength <= MAX_FORWARD_JUMP;
18479
+ if (!isValidProgress) {
18480
+ const recoveryPoint = this.getClosestPointOnPath(currentPath, pointerPos);
18481
+ const recoveryDistanceSquared = this.getDistanceSquared(pointerPos, recoveryPoint);
18482
+ const canRecover = pointerMoveDistanceSquared >= RECOVERY_POINTER_MOVE_THRESHOLD * RECOVERY_POINTER_MOVE_THRESHOLD &&
18483
+ recoveryDistanceSquared <= proximitySquared &&
18484
+ recoveryPoint.length >= state.lastLength - BACKWARD_TOLERANCE &&
18485
+ recoveryPoint.length - state.lastLength <= RECOVERY_FORWARD_JUMP &&
18486
+ recoveryPoint.length < state.totalPathLength - RECOVERY_END_BUFFER;
18487
+ if (canRecover) {
18488
+ guidedClosestPoint = recoveryPoint;
18489
+ isValidProgress = true;
18490
+ }
18491
+ }
18492
+ if (state.isDragging && isValidProgress) {
18493
+ state.lastLength = Math.max(state.lastLength, guidedClosestPoint.length);
18494
+ state.lastPointerPos = pointerPos;
18468
18495
  // Only update the circle if it moved enough
18469
- if (Math.abs(closestPoint.x - circlePos.x) > MOVE_THRESHOLD || Math.abs(closestPoint.y - circlePos.y) > MOVE_THRESHOLD) {
18470
- state.circle.setAttribute('cx', closestPoint.x.toString());
18471
- state.circle.setAttribute('cy', closestPoint.y.toString());
18496
+ if (Math.abs(guidedClosestPoint.x - circlePos.x) > MOVE_THRESHOLD || Math.abs(guidedClosestPoint.y - circlePos.y) > MOVE_THRESHOLD) {
18497
+ state.circle.setAttribute('cx', guidedClosestPoint.x.toString());
18498
+ state.circle.setAttribute('cy', guidedClosestPoint.y.toString());
18472
18499
  }
18473
18500
  // Only re-append if not already children list
18474
18501
  const childNodes = (_d = state.svg) === null || _d === void 0 ? void 0 : _d.childNodes;
@@ -18617,36 +18644,39 @@ const LidoTrace = class {
18617
18644
  return dx * dx + dy * dy;
18618
18645
  }
18619
18646
  // Find the closest point on the given path to the specified point using two-pass sampling (optimized)
18620
- getClosestPointOnPath(pathNode, point) {
18647
+ getClosestPointOnPath(pathNode, point, lastLength) {
18621
18648
  const pathLength = pathNode.getTotalLength();
18622
18649
  let closestPoint = { x: 0, y: 0, length: 0 };
18623
18650
  let minDistanceSquared = Infinity;
18624
- // Optimized: Increase coarse steps for better performance
18625
- const coarseStep = 40; // was 20
18626
- let coarseClosestPoint = { length: 0 };
18627
- let coarseMinDistanceSquared = Infinity;
18628
- for (let i = 0; i <= pathLength; i += coarseStep) {
18629
- const pointOnPath = pathNode.getPointAtLength(i);
18630
- const distanceSquared = this.getDistanceSquared(point, pointOnPath);
18631
- if (distanceSquared < coarseMinDistanceSquared) {
18632
- coarseMinDistanceSquared = distanceSquared;
18633
- coarseClosestPoint = {
18634
- x: pointOnPath.x,
18635
- y: pointOnPath.y,
18636
- length: i,
18637
- };
18651
+ const coarseStep = 40;
18652
+ const fineStep = 6;
18653
+ // dynamic search window (prevents jump)
18654
+ const SEARCH_WINDOW = 150;
18655
+ let searchStart = 0;
18656
+ let searchEnd = pathLength;
18657
+ // If lastLength exists → restrict search (smooth tracing)
18658
+ if (lastLength !== undefined) {
18659
+ searchStart = Math.max(0, lastLength - SEARCH_WINDOW);
18660
+ searchEnd = Math.min(pathLength, lastLength + SEARCH_WINDOW);
18661
+ }
18662
+ let coarseClosest = { length: searchStart };
18663
+ for (let i = searchStart; i <= searchEnd; i += coarseStep) {
18664
+ const pt = pathNode.getPointAtLength(i);
18665
+ const dist = this.getDistanceSquared(point, pt);
18666
+ if (dist < minDistanceSquared) {
18667
+ minDistanceSquared = dist;
18668
+ coarseClosest = { x: pt.x, y: pt.y, length: i };
18638
18669
  }
18639
18670
  }
18640
- // Second pass: fine sampling around coarseClosestPoint
18641
- const fineStep = 6; // was 2
18642
- const searchStart = Math.max(coarseClosestPoint.length - coarseStep, 0);
18643
- const searchEnd = Math.min(coarseClosestPoint.length + coarseStep, pathLength);
18644
- for (let i = searchStart; i <= searchEnd; i += fineStep) {
18645
- const pointOnPath = pathNode.getPointAtLength(i);
18646
- const distanceSquared = this.getDistanceSquared(point, pointOnPath);
18647
- if (distanceSquared < minDistanceSquared) {
18648
- minDistanceSquared = distanceSquared;
18649
- closestPoint = { x: pointOnPath.x, y: pointOnPath.y, length: i };
18671
+ const fineStart = Math.max(0, coarseClosest.length - coarseStep);
18672
+ const fineEnd = Math.min(pathLength, coarseClosest.length + coarseStep);
18673
+ minDistanceSquared = Infinity;
18674
+ for (let i = fineStart; i <= fineEnd; i += fineStep) {
18675
+ const pt = pathNode.getPointAtLength(i);
18676
+ const dist = this.getDistanceSquared(point, pt);
18677
+ if (dist < minDistanceSquared) {
18678
+ minDistanceSquared = dist;
18679
+ closestPoint = { x: pt.x, y: pt.y, length: i };
18650
18680
  }
18651
18681
  }
18652
18682
  return closestPoint;
@@ -18809,7 +18839,7 @@ const LidoTrace = class {
18809
18839
  };
18810
18840
  }
18811
18841
  render() {
18812
- return (index.h(index.Host, { key: '3f7da73f3c075a90ea0ce27022ed06a60c814fb4', 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: '209d9faf31cf0ec234ee2fd34521eec8bbbf8ac4', style: this.style, id: "lido-svgContainer" })));
18842
+ return (index.h(index.Host, { key: '11c018f8ea98db4d389b54a5965cbcc8760d9a8b', 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: '75a794c24a2fa4817b85c831bc57051003ce2fa2', style: this.style, id: "lido-svgContainer" })));
18813
18843
  }
18814
18844
  static get assetsDirs() { return ["svg", "images"]; }
18815
18845
  get el() { return index.getElement(this); }
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-Dl8SlqP-.js');
3
+ var index = require('./index-Bsk4M2Qz.js');
4
4
 
5
5
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
6
6
  /*
7
- Stencil Client Patch Browser v4.43.3 | MIT Licensed | https://stenciljs.com
7
+ Stencil Client Patch Browser v4.43.4 | MIT Licensed | https://stenciljs.com
8
8
  */
9
9
 
10
10
  var patchBrowser = () => {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-Dl8SlqP-.js');
3
+ var index = require('./index-Bsk4M2Qz.js');
4
4
 
5
5
  const defineCustomElements = async (win, options) => {
6
6
  if (typeof window === 'undefined') return undefined;
@@ -26,7 +26,7 @@
26
26
  "mixins": [],
27
27
  "compiler": {
28
28
  "name": "@stencil/core",
29
- "version": "4.43.3",
29
+ "version": "4.43.4",
30
30
  "typescriptVersion": "5.8.3"
31
31
  },
32
32
  "collections": [],
@@ -433,6 +433,7 @@ export class LidoTrace {
433
433
  state.isDragging = true;
434
434
  state.activePointerId = evt.pointerId;
435
435
  state.circle.setPointerCapture(evt.pointerId);
436
+ state.lastPointerPos = pointerPos;
436
437
  }
437
438
  this.hideFingerHint(); // ← NEW
438
439
  this.resetIdleTimer(state); // ← NEW
@@ -454,6 +455,7 @@ export class LidoTrace {
454
455
  if (evt.pointerId === state.activePointerId) {
455
456
  state.isDragging = false;
456
457
  state.activePointerId = null;
458
+ state.lastPointerPos = null;
457
459
  this.hideFingerHint(); // ← NEW
458
460
  this.resetIdleTimer(state); // ← NEW
459
461
  }
@@ -481,10 +483,12 @@ export class LidoTrace {
481
483
  };
482
484
  // Only update if pointer moved a minimum distance (to reduce unnecessary updates)
483
485
  const MOVE_THRESHOLD = 1; // px
486
+ let pointerMoveDistanceSquared = Infinity;
484
487
  if (state.lastPointerPos) {
485
488
  const dx = pointerPos.x - state.lastPointerPos.x;
486
489
  const dy = pointerPos.y - state.lastPointerPos.y;
487
- if (dx * dx + dy * dy < MOVE_THRESHOLD * MOVE_THRESHOLD) {
490
+ pointerMoveDistanceSquared = dx * dx + dy * dy;
491
+ if (pointerMoveDistanceSquared < MOVE_THRESHOLD * MOVE_THRESHOLD) {
488
492
  return;
489
493
  }
490
494
  }
@@ -507,14 +511,15 @@ export class LidoTrace {
507
511
  if (distanceSquared > proximitySquared) {
508
512
  return; // Skip any further actions
509
513
  }
510
- const closestPoint = this.getClosestPointOnPath(currentPath, pointerPos);
514
+ const isFreeTraceMode = state.mode === TraceMode.FreeTrace || state.mode === TraceMode.BlindFreeTrace;
515
+ const closestPoint = this.getClosestPointOnPath(currentPath, pointerPos, isFreeTraceMode ? undefined : state.lastLength);
511
516
  // Ensure drawing happens only within proximity threshold
512
517
  const distanceToPathSquared = this.getDistanceSquared(pointerPos, closestPoint);
513
518
  if (distanceToPathSquared > proximitySquared) {
514
519
  return; // Skip drawing if too far from the path
515
520
  }
516
521
  // For free trace mode and blind free trace mode, allow free drawing only if within the reduced proximity threshold
517
- if (state.mode === TraceMode.FreeTrace || state.mode === TraceMode.BlindFreeTrace) {
522
+ if (isFreeTraceMode) {
518
523
  // Throttle: Only update every 2nd event (for reducing excessive dom updates)
519
524
  this.freeTraceUpdateCounter = (this.freeTraceUpdateCounter || 0) + 1;
520
525
  if (this.freeTraceUpdateCounter % 2 !== 0) {
@@ -588,12 +593,34 @@ export class LidoTrace {
588
593
  return; // Exit early since we're in free trace or blind free trace mode
589
594
  }
590
595
  // In normal modes, allow movement and drawing only within the general proximity threshold
591
- if (state.isDragging && closestPoint.length >= state.lastLength) {
592
- state.lastLength = closestPoint.length;
596
+ const BACKWARD_TOLERANCE = 20; // allow slight backward movement
597
+ const MAX_FORWARD_JUMP = 80; // prevent jumping to wrong segment
598
+ const RECOVERY_FORWARD_JUMP = Math.min(320, Math.max(160, state.totalPathLength * 0.45)); // recover on long strokes without skipping short paths
599
+ const RECOVERY_END_BUFFER = Math.min(60, Math.max(24, state.totalPathLength * 0.12)); // don't let recovery auto-finish the last part
600
+ const RECOVERY_POINTER_MOVE_THRESHOLD = 8; // only recover after a meaningful drag, not during slow tracing
601
+ let guidedClosestPoint = closestPoint;
602
+ let isValidProgress = guidedClosestPoint.length >= state.lastLength - BACKWARD_TOLERANCE &&
603
+ guidedClosestPoint.length - state.lastLength <= MAX_FORWARD_JUMP;
604
+ if (!isValidProgress) {
605
+ const recoveryPoint = this.getClosestPointOnPath(currentPath, pointerPos);
606
+ const recoveryDistanceSquared = this.getDistanceSquared(pointerPos, recoveryPoint);
607
+ const canRecover = pointerMoveDistanceSquared >= RECOVERY_POINTER_MOVE_THRESHOLD * RECOVERY_POINTER_MOVE_THRESHOLD &&
608
+ recoveryDistanceSquared <= proximitySquared &&
609
+ recoveryPoint.length >= state.lastLength - BACKWARD_TOLERANCE &&
610
+ recoveryPoint.length - state.lastLength <= RECOVERY_FORWARD_JUMP &&
611
+ recoveryPoint.length < state.totalPathLength - RECOVERY_END_BUFFER;
612
+ if (canRecover) {
613
+ guidedClosestPoint = recoveryPoint;
614
+ isValidProgress = true;
615
+ }
616
+ }
617
+ if (state.isDragging && isValidProgress) {
618
+ state.lastLength = Math.max(state.lastLength, guidedClosestPoint.length);
619
+ state.lastPointerPos = pointerPos;
593
620
  // Only update the circle if it moved enough
594
- if (Math.abs(closestPoint.x - circlePos.x) > MOVE_THRESHOLD || Math.abs(closestPoint.y - circlePos.y) > MOVE_THRESHOLD) {
595
- state.circle.setAttribute('cx', closestPoint.x.toString());
596
- state.circle.setAttribute('cy', closestPoint.y.toString());
621
+ if (Math.abs(guidedClosestPoint.x - circlePos.x) > MOVE_THRESHOLD || Math.abs(guidedClosestPoint.y - circlePos.y) > MOVE_THRESHOLD) {
622
+ state.circle.setAttribute('cx', guidedClosestPoint.x.toString());
623
+ state.circle.setAttribute('cy', guidedClosestPoint.y.toString());
597
624
  }
598
625
  // Only re-append if not already children list
599
626
  const childNodes = (_d = state.svg) === null || _d === void 0 ? void 0 : _d.childNodes;
@@ -742,36 +769,39 @@ export class LidoTrace {
742
769
  return dx * dx + dy * dy;
743
770
  }
744
771
  // Find the closest point on the given path to the specified point using two-pass sampling (optimized)
745
- getClosestPointOnPath(pathNode, point) {
772
+ getClosestPointOnPath(pathNode, point, lastLength) {
746
773
  const pathLength = pathNode.getTotalLength();
747
774
  let closestPoint = { x: 0, y: 0, length: 0 };
748
775
  let minDistanceSquared = Infinity;
749
- // Optimized: Increase coarse steps for better performance
750
- const coarseStep = 40; // was 20
751
- let coarseClosestPoint = { x: 0, y: 0, length: 0 };
752
- let coarseMinDistanceSquared = Infinity;
753
- for (let i = 0; i <= pathLength; i += coarseStep) {
754
- const pointOnPath = pathNode.getPointAtLength(i);
755
- const distanceSquared = this.getDistanceSquared(point, pointOnPath);
756
- if (distanceSquared < coarseMinDistanceSquared) {
757
- coarseMinDistanceSquared = distanceSquared;
758
- coarseClosestPoint = {
759
- x: pointOnPath.x,
760
- y: pointOnPath.y,
761
- length: i,
762
- };
776
+ const coarseStep = 40;
777
+ const fineStep = 6;
778
+ // dynamic search window (prevents jump)
779
+ const SEARCH_WINDOW = 150;
780
+ let searchStart = 0;
781
+ let searchEnd = pathLength;
782
+ // If lastLength exists → restrict search (smooth tracing)
783
+ if (lastLength !== undefined) {
784
+ searchStart = Math.max(0, lastLength - SEARCH_WINDOW);
785
+ searchEnd = Math.min(pathLength, lastLength + SEARCH_WINDOW);
786
+ }
787
+ let coarseClosest = { x: 0, y: 0, length: searchStart };
788
+ for (let i = searchStart; i <= searchEnd; i += coarseStep) {
789
+ const pt = pathNode.getPointAtLength(i);
790
+ const dist = this.getDistanceSquared(point, pt);
791
+ if (dist < minDistanceSquared) {
792
+ minDistanceSquared = dist;
793
+ coarseClosest = { x: pt.x, y: pt.y, length: i };
763
794
  }
764
795
  }
765
- // Second pass: fine sampling around coarseClosestPoint
766
- const fineStep = 6; // was 2
767
- const searchStart = Math.max(coarseClosestPoint.length - coarseStep, 0);
768
- const searchEnd = Math.min(coarseClosestPoint.length + coarseStep, pathLength);
769
- for (let i = searchStart; i <= searchEnd; i += fineStep) {
770
- const pointOnPath = pathNode.getPointAtLength(i);
771
- const distanceSquared = this.getDistanceSquared(point, pointOnPath);
772
- if (distanceSquared < minDistanceSquared) {
773
- minDistanceSquared = distanceSquared;
774
- closestPoint = { x: pointOnPath.x, y: pointOnPath.y, length: i };
796
+ const fineStart = Math.max(0, coarseClosest.length - coarseStep);
797
+ const fineEnd = Math.min(pathLength, coarseClosest.length + coarseStep);
798
+ minDistanceSquared = Infinity;
799
+ for (let i = fineStart; i <= fineEnd; i += fineStep) {
800
+ const pt = pathNode.getPointAtLength(i);
801
+ const dist = this.getDistanceSquared(point, pt);
802
+ if (dist < minDistanceSquared) {
803
+ minDistanceSquared = dist;
804
+ closestPoint = { x: pt.x, y: pt.y, length: i };
775
805
  }
776
806
  }
777
807
  return closestPoint;
@@ -934,7 +964,7 @@ export class LidoTrace {
934
964
  };
935
965
  }
936
966
  render() {
937
- return (h(Host, { key: '3f7da73f3c075a90ea0ce27022ed06a60c814fb4', 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: '209d9faf31cf0ec234ee2fd34521eec8bbbf8ac4', style: this.style, id: "lido-svgContainer" })));
967
+ return (h(Host, { key: '11c018f8ea98db4d389b54a5965cbcc8760d9a8b', 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: '75a794c24a2fa4817b85c831bc57051003ce2fa2', style: this.style, id: "lido-svgContainer" })));
938
968
  }
939
969
  static get is() { return "lido-trace"; }
940
970
  static get originalStyleUrls() {