@bevry/hooks
Version:
Aggregation of react hooks that we use. Such as useInterval, useMetaKey.
97 lines (96 loc) • 4.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useEscapeKey = exports.useKeyPress = exports.useMetaKey = exports.useKey = exports.useInterval = void 0;
const react_1 = require("react");
/**
* After X milliseconds, trigger a state change.
*
* Use cases for this are:
*
* 1. Refresh your component every second. For example: `useInterval(1000)`
* 2. Refresh your component when the first piece of data inside it expires. For example: `useInterval([milkExpires, breadExpires])`
*
* @param interval The desired interval specified in milliseconds. If an array, then the smallest non-negative number is used. If the interval is negative, then it is discarded, as it is considered no longer relevant.
* @param threshold If the interval is valid and below the threshold, then round up to the threshold. For example: `useInterval(300, 1000)` will set the interval to `1000`, and `useInterval(-300, 1000)` still correctly discards the interval. Example use case: A threshold of `1000` would be used to prevent `useInterval(1)` from causing a thousand state changes within a single second, as such, you should set the threshold to the milliseconds that a state change is visually unnecessary.
*
* @returns An aimless value to cause state to change, it currently represents the number of fulfilled interval completions.
*/
function useInterval(interval, threshold = 0) {
// make the state reflect the iterations
const [iterations, setIterations] = (0, react_1.useState)(0);
// timers are side effects
(0, react_1.useEffect)(function () {
if (Array.isArray(interval)) {
// don't emit unexpected behaviour if nothing was provided
if (interval.length === 0)
return;
// fetch the smallest valid value
interval = interval.filter((ms) => ms >= 0).sort()[0];
}
// if the value is negative, no need for an interval
if (interval < 0)
return;
// if the value is below the threshold, then set it to the threshold
if (interval < threshold)
interval = threshold;
// create the timer
const timer = setTimeout(() => {
// bump the interation state
setIterations(iterations + 1);
}, interval);
// cleanup the timer
return () => clearTimeout(timer);
});
// return the interations
return iterations;
}
exports.useInterval = useInterval;
/**
* Create an effect for the keydown and keyup events.
* @param callback The callback that is fired when a key is pressed
*/
function useKey(callback) {
(0, react_1.useEffect)(function () {
document.addEventListener('keydown', callback);
document.addEventListener('keyup', callback);
return function () {
document.removeEventListener('keydown', callback);
document.removeEventListener('keyup', callback);
};
});
}
exports.useKey = useKey;
/**
* Create a state that reflects the status of meta keys.
* @param callback The callback that is fired when the state of a meta key changes.
*/
function useMetaKey(callback) {
useKey(function (e) {
callback(e.shiftKey || e.metaKey || e.altKey || e.ctrlKey);
});
}
exports.useMetaKey = useMetaKey;
/**
* Create an effect for when a key is pressed.
* @param callback The callback that is fired when a key is pressed.
*/
function useKeyPress(callback) {
(0, react_1.useEffect)(function () {
document.addEventListener('keypress', callback);
return function () {
document.removeEventListener('keypress', callback);
};
});
}
exports.useKeyPress = useKeyPress;
/**
* Create an effect for when the escape key is pressed.
* @param callback The callback that is fired when the escape key is pressed.
*/
function useEscapeKey(callback) {
useKeyPress(function (e) {
if (e.keyCode === 27)
callback(e);
});
}
exports.useEscapeKey = useEscapeKey;