Last active
May 8, 2018 10:47
-
-
Save TylerK/f85cdde98ed61d4fd31cadf378e4ec62 to your computer and use it in GitHub Desktop.
Click outside higher order component for React written in TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { findDOMNode } from 'react-dom'; | |
type HocWrapper<P> = React.ComponentClass<P> | React.SFC<P>; | |
function withClickOutside<P, S>(Component: HocWrapper<P>): React.ComponentClass<P> { | |
class WrappedComponent extends React.Component<P, S> { | |
private handleClickOutside = e => { | |
const bounds = this.wrappedDomNode.getBoundingClientRect(); | |
const mouseX = e.clientX || e.pageX; | |
const mouseY = e.clientY || e.pageY; | |
const clickedInBounds = | |
mouseX <= bounds.right && | |
mouseX >= bounds.left && | |
mouseY <= bounds.bottom && | |
mouseY >= bounds.top; | |
if (!clickedInBounds && typeof this.wrappedInstance.handleClickOutside === 'function') { | |
this.wrappedInstance.handleClickOutside(e); | |
} | |
}; | |
public static displayName = ''; | |
public wrappedInstance = null; | |
public wrappedDomNode = null; | |
public componentDidMount() { | |
window.addEventListener('click', this.handleClickOutside, true); | |
} | |
public componentWillUnmount() { | |
window.removeEventListener('click', this.handleClickOutside, true); | |
} | |
// Explicitely typing the return here keeps TS from yelling. ¯\_(ツ)_/¯ | |
public render(): JSX.Element { | |
const { ...props } = this.props as any; | |
return ( | |
<Component | |
{...props} | |
ref={el => { | |
this.wrappedInstance = el; | |
this.wrappedDomNode = findDOMNode(el); | |
}} | |
/> | |
); | |
} | |
} | |
const name = WrappedComponent.displayName || WrappedComponent.name; | |
WrappedComponent.displayName = `withClickOutside(${name})`; | |
return WrappedComponent; | |
} | |
export default withClickOutside; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import withClickOutside from './click-outside'; | |
class Widget extends React.Component<any, any> { | |
handleClickOutside = e => { | |
console.log('Clicked outside!'); | |
} | |
handleClick = e => { | |
console.log('Clicked inside!'); | |
} | |
render() { | |
return <button onClick={this.handleClick}>Click Me!</button> | |
} | |
} | |
export default withClickOutside(Widget); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment