UNPKG

adwaita-web

Version:

A GTK inspired toolkit designed to build awesome web apps

97 lines (96 loc) 2.7 kB
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 };