UNPKG

kinetic-slider

Version:

A WebGL-powered kinetic slider component using PIXI.js

169 lines (166 loc) 6.85 kB
import { useRef, useEffect } from 'react'; // Development environment check const isDevelopment = "production" === 'development'; /** * Hook to handle touch swipe gestures for the slider * Detects left and right swipes on touch devices and triggers navigation */ const useTouchSwipe = ({ sliderRef, onSwipeLeft, onSwipeRight, threshold, thresholdFraction = 0.2, // Default: 20% of screen width minSwipeDistance = 30, // Default minimum swipe distance in pixels resourceManager }) => { // Store touch state in refs to avoid re-renders const touchStateRef = useRef({ touchStartX: 0, touchStartY: 0, touchEndX: 0, touchEndY: 0, swiping: false }); useEffect(() => { // Skip during server-side rendering if (typeof window === 'undefined') return; const slider = sliderRef.current; if (!slider) { return; } /** * Calculate the appropriate swipe threshold based on slider width * @returns The calculated threshold in pixels */ const calculateThreshold = () => { // If explicit threshold is provided, use it if (threshold !== undefined) return threshold; // Calculate based on slider width if available, otherwise use window width const baseWidth = slider.clientWidth || window.innerWidth; const calculatedThreshold = baseWidth * thresholdFraction; // Ensure minimum threshold for small screens return Math.max(calculatedThreshold, minSwipeDistance); }; /** * Handle the start of a touch event * @param e - The touch event */ const handleTouchStart = (e) => { try { // Cast to TouchEvent for type safety const touchEvent = e; if (!touchEvent.touches || touchEvent.touches.length === 0) return; // Store initial touch position touchStateRef.current.touchStartX = touchEvent.touches[0].clientX; touchStateRef.current.touchStartY = touchEvent.touches[0].clientY; touchStateRef.current.swiping = true; if (isDevelopment) ; } catch (error) { } }; /** * Handle touch move events * @param e - The touch event */ const handleTouchMove = (e) => { try { // Cast to TouchEvent for type safety const touchEvent = e; if (!touchStateRef.current.swiping || !touchEvent.touches || touchEvent.touches.length === 0) return; // Update current touch position touchStateRef.current.touchEndX = touchEvent.touches[0].clientX; touchStateRef.current.touchEndY = touchEvent.touches[0].clientY; } catch (error) { } }; /** * Handle the end of a touch event */ const handleTouchEnd = () => { try { if (!touchStateRef.current.swiping) return; // Calculate swipe distance and angle const { touchStartX, touchStartY, touchEndX, touchEndY } = touchStateRef.current; const deltaX = touchEndX - touchStartX; const deltaY = touchEndY - touchStartY; const swipeThreshold = calculateThreshold(); // Calculate absolute distances const absX = Math.abs(deltaX); const absY = Math.abs(deltaY); if (isDevelopment) ; // Only trigger if horizontal distance > vertical distance (to avoid scrolling conflicts) // and if the horizontal distance exceeds the threshold if (absX > absY && absX > swipeThreshold) { // Determine direction and trigger appropriate callback if (deltaX < 0) { if (isDevelopment) ; onSwipeLeft(); } else { if (isDevelopment) ; onSwipeRight(); } } // Reset swiping state touchStateRef.current.swiping = false; } catch (error) { // Reset swiping state even on error touchStateRef.current.swiping = false; } }; /** * Handle touch cancel events */ const handleTouchCancel = () => { try { if (isDevelopment) ; // Reset swiping state touchStateRef.current.swiping = false; } catch (error) { // Reset swiping state even on error touchStateRef.current.swiping = false; } }; // Add event listeners with passive flag for better scrolling performance // Use ResourceManager if available, otherwise add directly if (resourceManager) { resourceManager.addEventListener(slider, "touchstart", handleTouchStart); resourceManager.addEventListener(slider, "touchmove", handleTouchMove); resourceManager.addEventListener(slider, "touchend", handleTouchEnd); resourceManager.addEventListener(slider, "touchcancel", handleTouchCancel); } else { // Use regular event listeners with passive option slider.addEventListener("touchstart", handleTouchStart, { passive: true }); slider.addEventListener("touchmove", handleTouchMove, { passive: true }); slider.addEventListener("touchend", handleTouchEnd); slider.addEventListener("touchcancel", handleTouchCancel); } // Cleanup function return () => { // Remove event listeners if ResourceManager not used if (!resourceManager) { slider.removeEventListener("touchstart", handleTouchStart); slider.removeEventListener("touchmove", handleTouchMove); slider.removeEventListener("touchend", handleTouchEnd); slider.removeEventListener("touchcancel", handleTouchCancel); } // Note: ResourceManager handles event cleanup when disposed }; }, [ sliderRef, onSwipeLeft, onSwipeRight, threshold, thresholdFraction, minSwipeDistance, resourceManager ]); // No return value needed as this hook just sets up the touch handlers }; export { useTouchSwipe as default }; //# sourceMappingURL=useTouchSwipe.js.map