Skip to content

Instantly share code, notes, and snippets.

@washingtonsoares
Created September 15, 2023 12:17
Show Gist options
  • Save washingtonsoares/e9a3a70f04bf17a69cddd74442112312 to your computer and use it in GitHub Desktop.
Save washingtonsoares/e9a3a70f04bf17a69cddd74442112312 to your computer and use it in GitHub Desktop.
import React, { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { findMatchedKey } from './keyEvents';
let exclusiveHandlers = [];
const KeyboardEventHandler = ({
handleKeys = [],
handleEventType = 'keydown',
handleFocusableElements = false,
onKeyEvent = () => null,
isDisabled = false,
isExclusive = false,
children,
...otherProps
}) => {
const childrenContainer = useRef(null);
useEffect(() => {
const handleKeyboardEvent = (event) => {
if (isDisabled) {
return false;
}
const isEventTypeMatched = handleEventType === event.type;
if (!isEventTypeMatched) {
return false;
}
const exclusiveHandlerInPlace = exclusiveHandlers.length > 0;
const isExcluded = exclusiveHandlerInPlace && exclusiveHandlers[0] !== handleKeyboardEvent;
if (isExcluded) {
return false;
}
const isEligibleEvent = event.target === document.body || handleFocusableElements;
const isChildrenEvent = childrenContainer.current && childrenContainer.current.contains(event.target);
const isValidSource = children ? isChildrenEvent : isEligibleEvent;
if (!isValidSource) {
return false;
}
const matchedKey = findMatchedKey(event, handleKeys);
if (matchedKey) {
onKeyEvent(matchedKey, event);
return true;
}
return false;
};
const registerExclusiveHandler = () => {
deregisterExclusiveHandler();
exclusiveHandlers.unshift(handleKeyboardEvent);
};
const deregisterExclusiveHandler = () => {
if (exclusiveHandlers.includes(handleKeyboardEvent)) {
exclusiveHandlers = exclusiveHandlers.filter(h => h !== handleKeyboardEvent);
}
};
if (typeof document !== 'undefined') {
document.addEventListener('keydown', handleKeyboardEvent, false);
document.addEventListener('keyup', handleKeyboardEvent, false);
document.addEventListener('keypress', handleKeyboardEvent, false);
if (isExclusive && !isDisabled) {
registerExclusiveHandler();
}
}
return () => {
if (typeof document !== 'undefined') {
document.removeEventListener('keydown', handleKeyboardEvent, false);
document.removeEventListener('keyup', handleKeyboardEvent, false);
document.removeEventListener('keypress', handleKeyboardEvent, false);
}
deregisterExclusiveHandler();
};
}, [isDisabled, handleKeys, onKeyEvent, handleEventType, children, handleFocusableElements, isExclusive]);
return children ? (
<span ref={childrenContainer} {...otherProps}>
{children}
</span>
) : null;
};
KeyboardEventHandler.propTypes = {
handleKeys: PropTypes.array,
handleEventType: PropTypes.oneOf(['keydown', 'keyup', 'keypress']),
handleFocusableElements: PropTypes.bool,
onKeyEvent: PropTypes.func,
isDisabled: PropTypes.bool,
isExclusive: PropTypes.bool,
children: PropTypes.any,
};
export default KeyboardEventHandler;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment