Last active
June 28, 2024 11:13
-
-
Save manix84/87be4f154216df05d8cf70704f38d480 to your computer and use it in GitHub Desktop.
A React Hook for guessing if you're left or not. This is useful for navigation menus appearing near your thumb on mobile devices.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
This code is licensed under the terms of the MIT license | |
*/ | |
import { useEffect, useState } from "react"; | |
const MINIMUM_VERTICAL_MOVEMENT_PX = 100; | |
const MINIMUM_HORIZONTAL_MOVEMENT_PX = 10; | |
const STORED_GUESSES = 11; // More than half in one direction will cause a switch | |
export const useIsLeftHanded = (): Boolean => { | |
const [isLeftHanded, setIsLeftHanded] = useState<Boolean>(false); | |
const [previousGuesses, setPreviousGuesses] = useState<Boolean[]>(() => | |
new Array(STORED_GUESSES).fill(false) | |
); | |
const [startPoint, setStartPoint] = useState<Number[]>([0, 0]); | |
const [endPoint, setEndPoint] = useState<Number[]>([0, 0]); | |
const getAverageGuess = () => | |
Boolean( | |
Math.round( | |
previousGuesses.reduce((a, b) => Number(a) + Number(b), 0) / | |
previousGuesses.length | |
) | |
); | |
const addNewGuess = (newGuess: Boolean) => | |
setPreviousGuesses((prev) => { | |
const newGuesses = prev; | |
newGuesses.shift(); | |
newGuesses.push(newGuess); | |
return newGuesses; | |
}); | |
const getStartPoint = (ev: TouchEvent) => { | |
setStartPoint([ | |
Number(ev.changedTouches?.[0]?.clientX), | |
Number(ev.changedTouches?.[0]?.clientY), | |
]); | |
}; | |
const getEndPoint = (ev: TouchEvent) => { | |
setEndPoint([ | |
Number(ev.changedTouches?.[0]?.clientX), | |
Number(ev.changedTouches?.[0]?.clientY), | |
]); | |
}; | |
useEffect(() => { | |
addEventListener("touchstart", getStartPoint); | |
addEventListener("touchend", getEndPoint); | |
return () => { | |
removeEventListener("touchstart", getStartPoint); | |
removeEventListener("touchend", getEndPoint); | |
}; | |
}, []); | |
useEffect(() => { | |
const verticalDistanceTravelled = | |
Number(endPoint[1]) - Number(startPoint[1]); | |
const horizontalDistanceTravelled = | |
Number(endPoint[0]) - Number(startPoint[0]); | |
if (verticalDistanceTravelled > Math.abs(MINIMUM_VERTICAL_MOVEMENT_PX)) { | |
// Down | |
addNewGuess( | |
horizontalDistanceTravelled > Math.abs(MINIMUM_HORIZONTAL_MOVEMENT_PX) | |
); | |
} else if ( | |
verticalDistanceTravelled < -Math.abs(MINIMUM_VERTICAL_MOVEMENT_PX) | |
) { | |
// Up | |
addNewGuess( | |
horizontalDistanceTravelled < -Math.abs(MINIMUM_HORIZONTAL_MOVEMENT_PX) | |
); | |
} | |
}, [startPoint, endPoint]); | |
useEffect( | |
() => setIsLeftHanded(getAverageGuess()), | |
[previousGuesses, startPoint, endPoint] | |
); | |
return isLeftHanded; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment