| 689 | // Swipe a library row left to reveal its Delete button (iOS-style). Wired |
| 690 | // imperatively after each render. |
| 691 | function wireSwipe() { |
| 692 | app.querySelectorAll(".track-wrap .track").forEach((row) => { |
| 693 | const id = row.dataset.id; |
| 694 | let x0 = 0, y0 = 0, active = false, horizontal = false; |
| 695 | const base = () => (state.swipedTrackId === id ? -84 : 0); |
| 696 | |
| 697 | row.addEventListener("pointerdown", (e) => { |
| 698 | x0 = e.clientX; y0 = e.clientY; active = true; horizontal = false; |
| 699 | row.style.transition = "none"; |
| 700 | }); |
| 701 | row.addEventListener("pointermove", (e) => { |
| 702 | if (!active) return; |
| 703 | const dx = e.clientX - x0; |
| 704 | const dy = e.clientY - y0; |
| 705 | if (!horizontal && Math.abs(dx) > 8 && Math.abs(dx) > Math.abs(dy)) horizontal = true; |
| 706 | if (horizontal) { |
| 707 | e.preventDefault(); |
| 708 | const tx = Math.max(-84, Math.min(0, base() + dx)); |
| 709 | row.style.transform = `translateX(${tx}px)`; |
| 710 | } |
| 711 | }); |
| 712 | const end = (e) => { |
| 713 | if (!active) return; |
| 714 | active = false; |
| 715 | if (!horizontal) { row.style.transition = ""; row.style.transform = ""; return; } |
| 716 | suppressClick = true; |
| 717 | setTimeout(() => { suppressClick = false; }, 60); |
| 718 | const dx = e.clientX - x0; |
| 719 | const open = dx < -40 ? true : dx > 40 ? false : state.swipedTrackId === id; |
| 720 | // Animate to the snap position by toggling the class (no DOM rebuild, so |
| 721 | // it transitions smoothly from wherever the finger let go). |
| 722 | closeOtherSwipes(row.closest(".track-wrap")); |
| 723 | row.style.transition = "transform 0.22s cubic-bezier(0.22,1,0.36,1)"; |
| 724 | row.closest(".track-wrap").classList.toggle("swiped", open); |
| 725 | row.style.transform = ""; |
| 726 | state.swipedTrackId = open ? id : null; |
| 727 | }; |
| 728 | row.addEventListener("pointerup", end); |
| 729 | row.addEventListener("pointercancel", end); |
| 730 | }); |
| 731 | } |
| 732 | |
| 733 | // Smoothly close any revealed row (optionally except `keep`), without a full |
| 734 | // re-render so the close animates. |