@clayui/shared
Version:
ClayShared component
122 lines (121 loc) • 4.13 kB
JavaScript
import { useEffect, useState } from "react";
import { isMac } from "./platform";
let currentInteraction = null;
let hasSetupGlobalListeners = false;
let hasEventBeforeFocus = false;
let hasBlurredWindowRecently = false;
const handlers = /* @__PURE__ */ new Set();
function isValidKey(event) {
return !(event.metaKey || !isMac() && event.altKey || event.ctrlKey || event.key === "Control" || event.key === "Shift" || event.key === "Meta");
}
function isVirtualClick(event) {
if (event.mozInputSource === 0 && event.isTrusted) {
return true;
}
return event.detail === 0 && !event.pointerType;
}
function isFocusVisible() {
return currentInteraction !== "pointer";
}
function getInteraction() {
return currentInteraction;
}
function callHandlers(interaction) {
for (const handler of handlers) {
handler(interaction);
}
}
function useInteractionFocus() {
useEffect(() => {
if (hasSetupGlobalListeners) {
return;
}
const onKeyboard = (event) => {
hasEventBeforeFocus = true;
if (isValidKey(event)) {
currentInteraction = "keyboard";
callHandlers(currentInteraction);
}
};
const onClick = (event) => {
if (isVirtualClick(event)) {
hasEventBeforeFocus = true;
currentInteraction = "virtual";
callHandlers(currentInteraction);
}
};
const onFocus = (event) => {
if (event.target === window || event.target === document) {
return;
}
if (!hasEventBeforeFocus && !hasBlurredWindowRecently) {
currentInteraction = "virtual";
callHandlers(currentInteraction);
}
hasEventBeforeFocus = false;
hasBlurredWindowRecently = false;
};
const onBlur = () => {
hasEventBeforeFocus = false;
hasBlurredWindowRecently = true;
};
const onPointer = (event) => {
currentInteraction = "pointer";
if (event.type === "mousedown" || event.type === "pointerdown") {
hasEventBeforeFocus = true;
callHandlers(currentInteraction);
}
};
document.addEventListener("keydown", onKeyboard, true);
document.addEventListener("keyup", onKeyboard, true);
document.addEventListener("click", onClick, true);
window.addEventListener("focus", onFocus, true);
window.addEventListener("blur", onBlur, false);
if (typeof PointerEvent !== "undefined") {
document.addEventListener("pointerdown", onPointer, true);
document.addEventListener("pointermove", onPointer, true);
document.addEventListener("pointerup", onPointer, true);
} else {
document.addEventListener("mousedown", onPointer, true);
document.addEventListener("mousemove", onPointer, true);
document.addEventListener("mouseup", onPointer, true);
}
hasSetupGlobalListeners = true;
return () => {
document.removeEventListener("keydown", onKeyboard, true);
document.removeEventListener("keyup", onKeyboard, true);
document.removeEventListener("click", onClick, true);
window.removeEventListener("focus", onFocus, true);
window.removeEventListener("blur", onBlur, false);
if (typeof PointerEvent !== "undefined") {
document.removeEventListener("pointerdown", onPointer, true);
document.removeEventListener("pointermove", onPointer, true);
document.removeEventListener("pointerup", onPointer, true);
} else {
document.removeEventListener("mousedown", onPointer, true);
document.removeEventListener("mousemove", onPointer, true);
document.removeEventListener("mouseup", onPointer, true);
}
hasSetupGlobalListeners = false;
};
}, []);
return { getInteraction, isFocusVisible };
}
function useFocusVisible() {
useInteractionFocus();
const [interaction, setInteraction] = useState(isFocusVisible());
useEffect(() => {
const handler = (interaction2) => {
setInteraction(interaction2 !== "pointer");
};
handlers.add(handler);
return () => {
handlers.delete(handler);
};
}, []);
return interaction;
}
export {
useFocusVisible,
useInteractionFocus
};