Refine mobile nav swipe gesture logic
Browse filesImproves swipe gesture handling by using the final movement direction for slow drags instead of a fixed position threshold. Adds tracking of the last touch X position to better determine user intent when ending a drag.
src/lib/components/MobileNav.svelte
CHANGED
|
@@ -72,10 +72,10 @@
|
|
| 72 |
// Swipe gesture support for opening/closing the nav with live feedback
|
| 73 |
// Thresholds from vaul drawer library
|
| 74 |
const VELOCITY_THRESHOLD = 0.4; // px/ms - if exceeded, snap in swipe direction
|
| 75 |
-
const CLOSE_THRESHOLD = 0.25; // 25% position threshold
|
| 76 |
const DIRECTION_LOCK_THRESHOLD = 10; // px - movement needed to lock direction
|
| 77 |
|
| 78 |
let touchstart: Touch | null = null;
|
|
|
|
| 79 |
let dragStartTime: number = 0;
|
| 80 |
let isDragging = $state(false);
|
| 81 |
let dragOffset = $state(-100); // percentage: -100 (closed) to 0 (open)
|
|
@@ -164,6 +164,8 @@
|
|
| 164 |
} else {
|
| 165 |
dragOffset = Math.max(-100, Math.min(0, -100 + (deltaX / drawerWidth) * 100));
|
| 166 |
}
|
|
|
|
|
|
|
| 167 |
}
|
| 168 |
|
| 169 |
function onTouchEnd(e: TouchEvent) {
|
|
@@ -179,12 +181,13 @@
|
|
| 179 |
const distMoved = touch.clientX - touchstart.clientX;
|
| 180 |
const velocity = Math.abs(distMoved) / timeTaken;
|
| 181 |
|
| 182 |
-
// Determine snap direction based on velocity first, then
|
| 183 |
if (velocity > VELOCITY_THRESHOLD) {
|
| 184 |
isOpen = distMoved > 0;
|
| 185 |
} else {
|
| 186 |
-
|
| 187 |
-
|
|
|
|
| 188 |
}
|
| 189 |
|
| 190 |
resetDragState();
|
|
@@ -201,6 +204,7 @@
|
|
| 201 |
isDragging = false;
|
| 202 |
potentialDrag = false;
|
| 203 |
touchstart = null;
|
|
|
|
| 204 |
directionLock = null;
|
| 205 |
}
|
| 206 |
|
|
|
|
| 72 |
// Swipe gesture support for opening/closing the nav with live feedback
|
| 73 |
// Thresholds from vaul drawer library
|
| 74 |
const VELOCITY_THRESHOLD = 0.4; // px/ms - if exceeded, snap in swipe direction
|
|
|
|
| 75 |
const DIRECTION_LOCK_THRESHOLD = 10; // px - movement needed to lock direction
|
| 76 |
|
| 77 |
let touchstart: Touch | null = null;
|
| 78 |
+
let lastTouchX: number | null = null;
|
| 79 |
let dragStartTime: number = 0;
|
| 80 |
let isDragging = $state(false);
|
| 81 |
let dragOffset = $state(-100); // percentage: -100 (closed) to 0 (open)
|
|
|
|
| 164 |
} else {
|
| 165 |
dragOffset = Math.max(-100, Math.min(0, -100 + (deltaX / drawerWidth) * 100));
|
| 166 |
}
|
| 167 |
+
|
| 168 |
+
lastTouchX = touch.clientX;
|
| 169 |
}
|
| 170 |
|
| 171 |
function onTouchEnd(e: TouchEvent) {
|
|
|
|
| 181 |
const distMoved = touch.clientX - touchstart.clientX;
|
| 182 |
const velocity = Math.abs(distMoved) / timeTaken;
|
| 183 |
|
| 184 |
+
// Determine snap direction based on velocity first, then final movement direction
|
| 185 |
if (velocity > VELOCITY_THRESHOLD) {
|
| 186 |
isOpen = distMoved > 0;
|
| 187 |
} else {
|
| 188 |
+
// For slow drags, use the final movement direction (allows "change of mind")
|
| 189 |
+
const finalDirection = lastTouchX !== null ? touch.clientX - lastTouchX : distMoved;
|
| 190 |
+
isOpen = finalDirection > 0;
|
| 191 |
}
|
| 192 |
|
| 193 |
resetDragState();
|
|
|
|
| 204 |
isDragging = false;
|
| 205 |
potentialDrag = false;
|
| 206 |
touchstart = null;
|
| 207 |
+
lastTouchX = null;
|
| 208 |
directionLock = null;
|
| 209 |
}
|
| 210 |
|