Skip to content

Commit c3ccde4

Browse files
committed
ES6 class support via the HOC/ES7 decorator pattern.
1 parent bd23c01 commit c3ccde4

File tree

2 files changed

+138
-4
lines changed

2 files changed

+138
-4
lines changed

README.md

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ npm install react-onclickoutside --save
1818

1919
(or `--save-dev` depending on your needs). You then use it in your components as:
2020

21-
```
21+
```javascript
2222
var Component = React.createClass({
2323
mixins: [
2424
require('react-onclickoutside')
@@ -39,13 +39,13 @@ bower install react-onclickoutside
3939

4040
and then include it as script via:
4141

42-
```
42+
```html
4343
<script src="bower_components/react-onclickoutside/index.js"></script>
4444
```
4545

4646
Then use it as:
4747

48-
```
48+
```javascript
4949
var Component = React.createClass({
5050
mixins: [
5151
OnClickOutside
@@ -66,7 +66,7 @@ When using this mixin, a component has two functions that can be used to explici
6666

6767
In addition, you can create a component that uses this mixin such that it has the code set up and ready to go, but not listening for outside click events until you explicitly issue its `enableOnClickOutside()`, by passing in a properly called `disableOnClickOutside`:
6868

69-
```
69+
```javascript
7070
var Component = React.createClass({
7171
mixins: [ ... ],
7272
handleClickOutside: function(evt) {
@@ -85,4 +85,41 @@ var Container = React.createClass({
8585

8686
If you want the mixin to ignore certain elements, then add the class `ignore-react-onclickoutside` to that element and the callback won't be invoked when the click happens inside elements with that class.
8787

88+
## ES6/2015 class support via HOC / ES7 decorators
89+
90+
Since mixins can't be used with ES6/2015 class React components a
91+
[Higher-Order Component (HOC)](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750)
92+
and [ES7 decorator](https://github.com/wycats/javascript-decorators) are bundled with the mixin:
93+
94+
```javascript
95+
import listensToClickOutside from 'react-onclickoutside/decorator';
96+
97+
class Component extends React.Component {
98+
handleClickOutside = (event) => {
99+
// ...
100+
}
101+
}
102+
103+
export default listensToClickOutside(Component);
104+
105+
// OR
106+
107+
import listensToClickOutside from 'react-onclickoutside/decorator';
108+
109+
@listensToClickOutside()
110+
class Component extends React.Component {
111+
handleClickOutside = (event) => {
112+
// ...
113+
}
114+
}
115+
116+
export default Component;
117+
```
118+
119+
One difference when using the HOC/decorator compared to the mixin is that the `enableOnClickOutside()`
120+
and `disableOnClickOutside()` methods are not available as class methods, but rather on the `props`;
121+
so instead of `this.enableOnClickOutside()` you would call `this.props.enableOnClickOutside()`.
122+
123+
In every other respect the the mixin and HOC/decorator provides the same functionality.
124+
88125
For bugs and enhancements hit up https://github.com/Pomax/react-onclickoutside/issues

decorator.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
var React = require('react');
2+
var objectAssign = require('react/lib/Object.assign');
3+
var OnClickOutsideMixin = require('react-onclickoutside');
4+
5+
6+
function addClickOutsideListener(Component) {
7+
8+
return React.createClass({
9+
10+
displayName: (Component.displayName || Component.name) + 'ClickOutside',
11+
12+
mixins: [OnClickOutsideMixin],
13+
14+
handleClickOutside: function(event) {
15+
if (this.refs.inner.handleClickOutside) {
16+
this.refs.inner.handleClickOutside(event);
17+
}
18+
else if (this.props.onClickOutside) {
19+
this.props.onClickOutside(event);
20+
}
21+
},
22+
23+
render: function render() {
24+
return React.createElement(Component, objectAssign({
25+
enableOnClickOutside: this.enableOnClickOutside,
26+
disableOnClickOutside: this.disableOnClickOutside,
27+
ref: 'inner'
28+
}, this.props));
29+
}
30+
});
31+
}
32+
33+
34+
/**
35+
* @function listensToClickOutside
36+
*
37+
* A higher-order component for ES6 React classes to use the `handleClickOutside` event handler:
38+
*
39+
* import listensToClickOutside from 'react-onclickoutside/decorator';
40+
*
41+
* class Es6Component extends React.Component {
42+
* handleClickOutside = (event) => {
43+
* // ...handling code goes here...
44+
* }
45+
* }
46+
*
47+
* export default listensToClickOutside(Es6Component);
48+
*
49+
* Alternatively you can pass the handler down from the parent on an `onClickOutside` prop:
50+
*
51+
* class Child extends React.Component {
52+
* // No event handler here, if provided this handler takes precedence and the one passed down
53+
* // is not called automatically. If it should be, call it on the props from the child handler.
54+
* }
55+
*
56+
* Child = listenToClickOutside(Child);
57+
*
58+
*
59+
* class Parent extends React.Component {
60+
* handleClickOutside = (event) => {
61+
* // ...handling code goes here...
62+
* }
63+
*
64+
* render() {
65+
* return (
66+
* <Child onClickOutside={this.handleClickOutside}/>
67+
* );
68+
* }
69+
* }
70+
*
71+
* The [ES7 Decorator Pattern](https://github.com/wycats/javascript-decorators) is also supported
72+
* using the same import:
73+
*
74+
* import listensToClickOutside from 'react-onclickoutside/decorator';
75+
*
76+
* @listensToClickOutside()
77+
* class Es6Component extends React.Component {
78+
* handleClickOutside = (event) => {
79+
* // ...handling code goes here...
80+
* }
81+
* }
82+
*
83+
* @param {React.Component} [Component] The component outside of which to listen to clicks.
84+
* @returns {React.Component} or {Function} if using the decorator pattern.
85+
*/
86+
function listensToClickOutside(Component) {
87+
// support decorator pattern
88+
if (!Component) {
89+
return function listensToClickOutsideDecorator(ComponentToDecorate) {
90+
return addClickOutsideListener(ComponentToDecorate);
91+
};
92+
}
93+
94+
return addClickOutsideListener(Component);
95+
}
96+
97+
module.exports = listensToClickOutside;

0 commit comments

Comments
 (0)