Skip to content

Instantly share code, notes, and snippets.

@davidmfoley
Last active June 9, 2017 23:22
Show Gist options
  • Save davidmfoley/43603de2eccfe1255052ea7289f1af22 to your computer and use it in GitHub Desktop.
Save davidmfoley/43603de2eccfe1255052ea7289f1af22 to your computer and use it in GitHub Desktop.
KeyboardNav react component example
// @flow
import React from 'react';
const { Component } = React;
let stack = [];
function addToStack(handler: Function) {
if (stack.length === 0) {
window.addEventListener('keydown', globalKeyHandler);
}
stack = stack.filter(f => f !== handler).concat([handler]);
}
function removeFromStack(handler: Function) {
stack = stack.filter(f => f !== handler);
if (stack.length === 0) {
window.removeEventListener('keydown', globalKeyHandler);
}
}
function globalKeyHandler(e: KeyboardEvent) {
const handler = stack[stack.length - 1];
if (handler) {
handler(e);
}
}
type Props = {
onLeft?: Function,
onRight?: Function,
onEsc?: Function,
onDown?: Function,
onUp?: Function,
}
export default class KeyboardNav extends Component {
props: Props
componentDidMount() {
addToStack(this.onKey);
}
componentWillUnmount() {
removeFromStack(this.onKey);
}
getHandler(keyCode: number): ?Function {
if (keyCode === 27) {
return this.props.onEsc;
}
if (keyCode === 37) {
return this.props.onLeft;
}
if (keyCode === 38) {
return this.props.onUp;
}
if (keyCode === 39) {
return this.props.onRight;
}
if (keyCode === 40) {
return this.props.onDown;
}
}
onKey = (e: KeyboardEvent) => {
const name = ((document.activeElement || {}).nodeName || '').toLowerCase();
if (name === 'textarea' || name === 'input') return;
const handler = this.getHandler(e.keyCode);
if (!handler) return;
e.preventDefault();
e.stopPropagation();
handler();
}
render() {
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment