/* @flow */ import React from 'react'; import PropTypes from 'prop-types'; import { canUseDOM } from 'exenv'; import { KEYDOWN, KEYPRESS, KEYUP, type KeyConstants } from './constants'; import { type primitiveOrArray } from './types'; import { isInput, matchesKeyboardEvent } from './utils'; type Props = {| +keyValue?: ?primitiveOrArray, +keyCode?: ?primitiveOrArray, +code?: ?primitiveOrArray, +keyEventName: KeyConstants, +onKeyHandle?: (event: KeyboardEvent) => mixed, |}; export default class KeyHandler extends React.Component { static propTypes = { keyValue: PropTypes.oneOfType([ PropTypes.string, PropTypes.arrayOf(PropTypes.string), ]), keyCode: PropTypes.oneOfType([ PropTypes.number, PropTypes.arrayOf(PropTypes.number), ]), code: PropTypes.oneOfType([ PropTypes.string, PropTypes.arrayOf(PropTypes.string), ]), keyEventName: PropTypes.oneOf([KEYDOWN, KEYPRESS, KEYUP]), onKeyHandle: PropTypes.func, }; static defaultProps = { keyEventName: KEYUP, }; shouldComponentUpdate(): boolean { return false; } constructor(props: Props) { super(props); /* eslint-disable no-console */ if (props.keyCode) { console.warn( 'Warning: Deprecated propType: `keyCode` is deprecated in favour of `code` for `KeyHandler`.', ); } if (!props.keyValue && !props.keyCode && !props.code) { console.error( 'Warning: Failed propType: Missing prop `code`, `keyValue` or `keyCode` for `KeyHandler`.', ); } /* eslint-enable */ } componentDidMount(): void { if (!canUseDOM) return; window.document.addEventListener(this.props.keyEventName, this.handleKey); } componentWillUnmount(): void { if (!canUseDOM) return; window.document.removeEventListener( this.props.keyEventName, this.handleKey, ); } render(): null { return null; } handleKey = (event: KeyboardEvent): void => { const { keyValue, keyCode, code, onKeyHandle } = this.props; if (!onKeyHandle) { return; } const { target } = event; if (target instanceof window.HTMLElement && isInput(target)) { return; } if (!matchesKeyboardEvent(event, { keyValue, keyCode, code })) { return; } onKeyHandle(event); }; }