forked from Pomax/react-onclickoutside
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
68 lines (59 loc) · 1.86 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
const DEFAULT_EVENTS = ['mousedown', 'touchstart']
class OnClickOutside extends Component {
constructor(props) {
super(props)
this.__handler = this.__handler.bind(this)
}
__handler(e) {
if (this.props.onClickOutside) {
let current = e.target
let found = false
const componentNode = ReactDOM.findDOMNode(this)
// If source=local then this event came from "somewhere"
// inside and should be ignored. We could handle this with
// a layered approach, too, but that requires going back to
// thinking in terms of Dom node nesting, running counter
// to React's "you shouldn't care about the DOM" philosophy.
while(current.parentNode) {
if (current === componentNode) {
return
}
current = current.parentNode
}
// If element is in a detached DOM, consider it "not clicked
// outside", as it cannot be known whether it was outside.
if (current !== document) {
return
}
this.props.onClickOutside(e)
}
}
componentDidMount() {
let events = (this.props.outsideEventTypes || DEFAULT_EVENTS)
if (!events.forEach) {
events = [events]
}
events.forEach(eventName => {
document.addEventListener(eventName, this.__handler, false)
})
// store the actual bound events for unbinding later
// in case outsideEventTypes changes
this.__boundEvents = events
}
componentWillUnmount() {
this.__boundEvents.forEach(eventName => {
document.removeEventListener(eventName, this.__handler, false)
})
}
}
OnClickOutside.propTypes = {
onClickOutside: PropTypes.func.isRequired,
outsideEventTypes: PropTypes.oneOfType([
PropTypes.string,
PropTypes.array
]),
}
export default OnClickOutside