adwaita-web
Version:
A GTK inspired toolkit designed to build awesome web apps
97 lines (96 loc) • 2.7 kB
JavaScript
import * as React from "react";
import * as ReactDOM from "react-dom";
let hadKeyboardEvent = true;
let hadFocusVisibleRecently = false;
let hadFocusVisibleRecentlyTimeout = null;
const inputTypesWhitelist = {
text: true,
search: true,
url: true,
tel: true,
email: true,
password: true,
number: true,
date: true,
month: true,
week: true,
time: true,
datetime: true,
"datetime-local": true
};
function focusTriggersKeyboardModality(node) {
const { type, tagName } = node;
if (tagName === "INPUT" && type && inputTypesWhitelist[type] && !node.readOnly) {
return true;
}
if (tagName === "TEXTAREA" && !node.readOnly) {
return true;
}
if (node.isContentEditable) {
return true;
}
return false;
}
function handleKeyDown(event) {
if (event.metaKey || event.altKey || event.ctrlKey) {
return;
}
hadKeyboardEvent = true;
}
function handlePointerDown() {
hadKeyboardEvent = false;
}
function handleVisibilityChange() {
if (this.visibilityState === "hidden") {
if (hadFocusVisibleRecently) {
hadKeyboardEvent = true;
}
}
}
function prepare(doc) {
doc.addEventListener("keydown", handleKeyDown, true);
doc.addEventListener("mousedown", handlePointerDown, true);
doc.addEventListener("pointerdown", handlePointerDown, true);
doc.addEventListener("touchstart", handlePointerDown, true);
doc.addEventListener("visibilitychange", handleVisibilityChange, true);
}
function teardown(doc) {
doc.removeEventListener("keydown", handleKeyDown, true);
doc.removeEventListener("mousedown", handlePointerDown, true);
doc.removeEventListener("pointerdown", handlePointerDown, true);
doc.removeEventListener("touchstart", handlePointerDown, true);
doc.removeEventListener("visibilitychange", handleVisibilityChange, true);
}
function isFocusVisible(event) {
const { currentTarget } = event;
try {
return currentTarget.matches(":focus-visible");
} catch (error) {
}
return hadKeyboardEvent || focusTriggersKeyboardModality(currentTarget);
}
function handleBlurVisible() {
hadFocusVisibleRecently = true;
if (hadFocusVisibleRecentlyTimeout) {
window.clearTimeout(hadFocusVisibleRecentlyTimeout);
}
hadFocusVisibleRecentlyTimeout = window.setTimeout(() => {
hadFocusVisibleRecently = false;
}, 100);
}
function useIsFocusVisible() {
const ref = React.useCallback((instance) => {
const node = ReactDOM.findDOMNode(instance);
if (node != null) {
prepare(node.ownerDocument);
}
}, []);
if (true) {
React.useDebugValue(isFocusVisible);
}
return { isFocusVisible, onBlurVisible: handleBlurVisible, ref };
}
export {
useIsFocusVisible as default,
teardown
};