Skip to content

Instantly share code, notes, and snippets.

@manix84
Last active June 28, 2024 11:13
Show Gist options
  • Save manix84/87be4f154216df05d8cf70704f38d480 to your computer and use it in GitHub Desktop.
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 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