@react-md/utils
Version:
General utils for react-md.
118 lines • 4.84 kB
JavaScript
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
import { useRef, useState } from "react";
import { useIsomorphicLayoutEffect } from "../useIsomorphicLayoutEffect";
/**
* @internal
*/
var TOUCH_TIMEOUT = 1200;
/**
* This hook helps determine the current interaction mode by attaching the
* required event listeners to the window. The `mode` will always be defaulted
* to `mouse` at first since it has the least possibilities of causing errors
* with styles since the mouse-only styles are normally just `:hover` effects.
*
* ## Switching between modes:
*
* ### While in `mouse` mode:
*
* - any `keydown` event will switch to `keyboard` mode
* - this does have the side effect of meta keys also causing the switch over,
* but it feels fine since it helps show the current focus in the document
* as well
* - any `touchstart` event will switch to `touch` mode
*
* ### While in `keyboard` mode:
*
* - any `mousedown` event will switch to `mouse` mode
* - it is perfectly okay to move the mouse while in keyboard mode, but still
* want to keep the keyboard styles until the user actually starts clicking
* - any `touchstart` event will switch to `touch` mode
*
* ### While in `touch` mode:
*
* - any `mousemove` event will switch to `mouse` mode, but **only** if there
* hasn't been a `contextmenu` event within the last `1.2s`
* - you can really only switch back to `mouse` mode if you are using the
* devtools to emulate devices OR using a touch-desktop. I don't know how
* common this really is though.
* - touching the screen will always fire a `mousemove` event (which is why
* the `:hover` styles are normally with `rmd-utils-mouse-only`) and even
* after the `contextmenu` event. Normally want to go back to `mouse` mode
* when the mouse re-enters the `window`
*
* Note: It's currently impossible to switch from `touch` to `keyboard`
* immediately. You'd first need to switch to `mouse` and then to `keyboard`. I
* don't really know of any use-cases other than the weird touch-desktop stuff
* and I have no experience using them.
*
* @internal
*/
export function useInteractionMode() {
var _a = __read(useState("mouse"), 2), mode = _a[0], setMode = _a[1];
var lastTouchTime = useRef(0);
var isTouchContextMenu = useRef(false);
useIsomorphicLayoutEffect(function () {
var enableMouseMode = function () { return setMode("mouse"); };
var enableKeyboardMode = function () { return setMode("keyboard"); };
var handleTouchStart = function () {
lastTouchTime.current = Date.now();
isTouchContextMenu.current = false;
setMode("touch");
};
var handleMouseMove = function () {
if (isTouchContextMenu.current ||
Date.now() - lastTouchTime.current < TOUCH_TIMEOUT) {
isTouchContextMenu.current = false;
return;
}
enableMouseMode();
};
var handleContextMenu = function () {
isTouchContextMenu.current = true;
};
var className = "rmd-utils--".concat(mode);
document.body.classList.add(className);
window.addEventListener("touchstart", handleTouchStart, true);
if (mode === "mouse") {
window.addEventListener("keydown", enableKeyboardMode, true);
}
else if (mode === "keyboard") {
window.addEventListener("mousedown", enableMouseMode, true);
}
else {
window.addEventListener("mousemove", handleMouseMove, true);
window.addEventListener("contextmenu", handleContextMenu, true);
}
return function () {
document.body.classList.remove(className);
window.removeEventListener("touchstart", handleTouchStart, true);
if (mode === "mouse") {
window.removeEventListener("keydown", enableKeyboardMode, true);
}
else if (mode === "keyboard") {
window.removeEventListener("mousedown", enableMouseMode, true);
}
else {
window.removeEventListener("mousemove", handleMouseMove, true);
window.removeEventListener("contextmenu", handleContextMenu, true);
}
};
}, [mode]);
return mode;
}
//# sourceMappingURL=useInteractionMode.js.map