react-onclickoutside
Advanced tools
Comparing version 6.7.0 to 6.7.1
@@ -131,2 +131,18 @@ (function (global, factory) { | ||
/** | ||
* Options for addEventHandler and removeEventHandler | ||
*/ | ||
function getEventHandlerOptions(instance, eventName) { | ||
var handlerOptions = null; | ||
var isTouchEvent = touchEvents.indexOf(eventName) !== -1; | ||
if (isTouchEvent && passiveEventSupport) { | ||
handlerOptions = { | ||
passive: !instance.props.preventDefault | ||
}; | ||
} | ||
return handlerOptions; | ||
} | ||
/** | ||
* This function generates the HOC function that you'll use | ||
@@ -139,2 +155,3 @@ * in order to impart onOutsideClick listening to an | ||
function onClickOutsideHOC(WrappedComponent, config) { | ||
@@ -214,12 +231,3 @@ var _class, _temp; | ||
events.forEach(function (eventName) { | ||
var handlerOptions = null; | ||
var isTouchEvent = touchEvents.indexOf(eventName) !== -1; | ||
if (isTouchEvent && passiveEventSupport) { | ||
handlerOptions = { | ||
passive: !_this.props.preventDefault | ||
}; | ||
} | ||
document.addEventListener(eventName, handlersMap[_this._uid], handlerOptions); | ||
document.addEventListener(eventName, handlersMap[_this._uid], getEventHandlerOptions(_this, eventName)); | ||
}); | ||
@@ -240,3 +248,3 @@ }; | ||
events.forEach(function (eventName) { | ||
return document.removeEventListener(eventName, fn); | ||
return document.removeEventListener(eventName, fn, getEventHandlerOptions(_this, eventName)); | ||
}); | ||
@@ -243,0 +251,0 @@ delete handlersMap[_this._uid]; |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react"),require("react-dom")):"function"==typeof define&&define.amd?define(["exports","react","react-dom"],t):t(e.onClickOutside={},e.React,e.ReactDOM)}(this,function(e,t,n){"use strict";var o,i=function(){if("undefined"!=typeof window&&"function"==typeof window.addEventListener){var e=!1,t=Object.defineProperty({},"passive",{get:function(){e=!0}}),n=function(){};return window.addEventListener("testPassiveEventSupport",n,t),window.removeEventListener("testPassiveEventSupport",n,t),e}},r=function(e){return void 0===e&&(e=0),function(){return++e}}(),c={},s={},u=["touchstart","touchmove"],d="ignore-react-onclickoutside";e.IGNORE_CLASS_NAME=d,e.default=function(e,a){var l,p;return p=l=function(d){function l(e){var t;return t=d.call(this,e)||this,t.__outsideClickHandler=function(e){if("function"!=typeof t.__clickOutsideHandlerProp){var n=t.getInstance();if("function"!=typeof n.props.handleClickOutside){if("function"!=typeof n.handleClickOutside)throw Error("WrappedComponent lacks a handleClickOutside(event) function for processing outside click events.");n.handleClickOutside(e)}else n.props.handleClickOutside(e)}else t.__clickOutsideHandlerProp(e)},t.enableOnClickOutside=function(){if("undefined"!=typeof document&&!s[t._uid]){void 0===o&&(o=i()),s[t._uid]=!0;var e=t.props.eventTypes;e.forEach||(e=[e]),c[t._uid]=function(e){t.props.disableOnClickOutside||null===t.componentNode||(t.props.preventDefault&&e.preventDefault(),t.props.stopPropagation&&e.stopPropagation(),t.props.excludeScrollbar&&function(e){return document.documentElement.clientWidth<=e.clientX||document.documentElement.clientHeight<=e.clientY}(e))||function(e,t,n){if(e===t)return!0;for(;e.parentNode;){if(function(e,t,n){return e===t||(e.correspondingElement?e.correspondingElement.classList.contains(n):e.classList.contains(n))}(e,t,n))return!0;e=e.parentNode}return e}(e.target,t.componentNode,t.props.outsideClickIgnoreClass)===document&&t.__outsideClickHandler(e)},e.forEach(function(e){var n=null;-1!==u.indexOf(e)&&o&&(n={passive:!t.props.preventDefault}),document.addEventListener(e,c[t._uid],n)})}},t.disableOnClickOutside=function(){delete s[t._uid];var e=c[t._uid];if(e&&"undefined"!=typeof document){var n=t.props.eventTypes;n.forEach||(n=[n]),n.forEach(function(t){return document.removeEventListener(t,e)}),delete c[t._uid]}},t.getRef=function(e){return t.instanceRef=e},t._uid=r(),t}!function(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}(l,d);var p=l.prototype;return p.getInstance=function(){if(!e.prototype.isReactComponent)return this;var t=this.instanceRef;return t.getInstance?t.getInstance():t},p.componentDidMount=function(){if("undefined"!=typeof document&&document.createElement){var e=this.getInstance();if(a&&"function"==typeof a.handleClickOutside&&(this.__clickOutsideHandlerProp=a.handleClickOutside(e),"function"!=typeof this.__clickOutsideHandlerProp))throw Error("WrappedComponent lacks a function for processing outside click events specified by the handleClickOutside config option.");this.componentNode=n.findDOMNode(this.getInstance()),this.enableOnClickOutside()}},p.componentDidUpdate=function(){this.componentNode=n.findDOMNode(this.getInstance())},p.componentWillUnmount=function(){this.disableOnClickOutside()},p.render=function(){var n=this.props,o=function(e,t){if(null==e)return{};var n,o,i={},r=Object.keys(e);for(o=0;r.length>o;o++)0>t.indexOf(n=r[o])&&(i[n]=e[n]);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(o=0;c.length>o;o++)0>t.indexOf(n=c[o])&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}(n,["excludeScrollbar"]);return e.prototype.isReactComponent?o.ref=this.getRef:o.wrappedRef=this.getRef,o.disableOnClickOutside=this.disableOnClickOutside,o.enableOnClickOutside=this.enableOnClickOutside,t.createElement(e,o)},l}(t.Component),l.displayName="OnClickOutside("+(e.displayName||e.name||"Component")+")",l.defaultProps={eventTypes:["mousedown","touchstart"],excludeScrollbar:a&&a.excludeScrollbar||!1,outsideClickIgnoreClass:d,preventDefault:!1,stopPropagation:!1},l.getClass=function(){return e.getClass?e.getClass():e},p},Object.defineProperty(e,"__esModule",{value:!0})}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react"),require("react-dom")):"function"==typeof define&&define.amd?define(["exports","react","react-dom"],t):t(e.onClickOutside={},e.React,e.ReactDOM)}(this,function(e,t,n){"use strict";var o=function(){if("undefined"!=typeof window&&"function"==typeof window.addEventListener){var e=!1,t=Object.defineProperty({},"passive",{get:function(){e=!0}}),n=function(){};return window.addEventListener("testPassiveEventSupport",n,t),window.removeEventListener("testPassiveEventSupport",n,t),e}};var i,r,c=(void 0===i&&(i=0),function(){return++i}),s={},d={},u=["touchstart","touchmove"],a="ignore-react-onclickoutside";function l(e,t){var n=null;return-1!==u.indexOf(t)&&r&&(n={passive:!e.props.preventDefault}),n}e.IGNORE_CLASS_NAME=a,e.default=function(e,i){var u,p;return p=u=function(u){var a,p;function f(e){var t;return(t=u.call(this,e)||this).__outsideClickHandler=function(e){if("function"!=typeof t.__clickOutsideHandlerProp){var n=t.getInstance();if("function"!=typeof n.props.handleClickOutside){if("function"!=typeof n.handleClickOutside)throw Error("WrappedComponent lacks a handleClickOutside(event) function for processing outside click events.");n.handleClickOutside(e)}else n.props.handleClickOutside(e)}else t.__clickOutsideHandlerProp(e)},t.enableOnClickOutside=function(){if("undefined"!=typeof document&&!d[t._uid]){void 0===r&&(r=o()),d[t._uid]=!0;var e=t.props.eventTypes;e.forEach||(e=[e]),s[t._uid]=function(e){var n;t.props.disableOnClickOutside||null!==t.componentNode&&(t.props.preventDefault&&e.preventDefault(),t.props.stopPropagation&&e.stopPropagation(),(!t.props.excludeScrollbar||(n=e,document.documentElement.clientWidth>n.clientX&&document.documentElement.clientHeight>n.clientY))&&function(e,t,n){if(e===t)return!0;for(;e.parentNode;){if(i=n,(o=e)===t||(o.correspondingElement?o.correspondingElement.classList.contains(i):o.classList.contains(i)))return!0;e=e.parentNode}var o,i;return e}(e.target,t.componentNode,t.props.outsideClickIgnoreClass)===document&&t.__outsideClickHandler(e))},e.forEach(function(e){document.addEventListener(e,s[t._uid],l(t,e))})}},t.disableOnClickOutside=function(){delete d[t._uid];var e=s[t._uid];if(e&&"undefined"!=typeof document){var n=t.props.eventTypes;n.forEach||(n=[n]),n.forEach(function(n){return document.removeEventListener(n,e,l(t,n))}),delete s[t._uid]}},t.getRef=function(e){return t.instanceRef=e},t._uid=c(),t}(a=f).prototype=Object.create((p=u).prototype),a.prototype.constructor=a,a.__proto__=p;var O=f.prototype;return O.getInstance=function(){if(!e.prototype.isReactComponent)return this;var t=this.instanceRef;return t.getInstance?t.getInstance():t},O.componentDidMount=function(){if("undefined"!=typeof document&&document.createElement){var e=this.getInstance();if(i&&"function"==typeof i.handleClickOutside&&(this.__clickOutsideHandlerProp=i.handleClickOutside(e),"function"!=typeof this.__clickOutsideHandlerProp))throw Error("WrappedComponent lacks a function for processing outside click events specified by the handleClickOutside config option.");this.componentNode=n.findDOMNode(this.getInstance()),this.enableOnClickOutside()}},O.componentDidUpdate=function(){this.componentNode=n.findDOMNode(this.getInstance())},O.componentWillUnmount=function(){this.disableOnClickOutside()},O.render=function(){var n=this.props,o=function(e,t){if(null==e)return{};var n,o,i={},r=Object.keys(e);for(o=0;r.length>o;o++)0>t.indexOf(n=r[o])&&(i[n]=e[n]);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(o=0;c.length>o;o++)0>t.indexOf(n=c[o])&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}(n,["excludeScrollbar"]);return e.prototype.isReactComponent?o.ref=this.getRef:o.wrappedRef=this.getRef,o.disableOnClickOutside=this.disableOnClickOutside,o.enableOnClickOutside=this.enableOnClickOutside,t.createElement(e,o)},f}(t.Component),u.displayName="OnClickOutside("+(e.displayName||e.name||"Component")+")",u.defaultProps={eventTypes:["mousedown","touchstart"],excludeScrollbar:i&&i.excludeScrollbar||!1,outsideClickIgnoreClass:a,preventDefault:!1,stopPropagation:!1},u.getClass=function(){return e.getClass?e.getClass():e},p},Object.defineProperty(e,"__esModule",{value:!0})}); |
{ | ||
"name": "react-onclickoutside", | ||
"version": "6.7.0", | ||
"version": "6.7.1", | ||
"description": "An onClickOutside wrapper for React components", | ||
"main": "lib/index.js", | ||
"module": "es/index.js", | ||
"jsnext:main": "es/index.js", | ||
"main": "dist/react-onclickoutside.cjs.js", | ||
"module": "dist/react-onclickoutside.es.js", | ||
"jsnext:main": "dist/react-onclickoutside.es.js", | ||
"files": [ | ||
"es", | ||
"lib", | ||
"dist" | ||
@@ -34,12 +32,8 @@ ], | ||
"scripts": { | ||
"clean": "rimraf es lib dist", | ||
"clean": "rimraf dist", | ||
"prebuild": "npm run clean", | ||
"build": "run-p build:**", | ||
"build:es": "cross-env BABEL_ENV=es rollup -c -i src/index.js -o es/index.js", | ||
"build:cjs": "cross-env BABEL_ENV=cjs rollup -c -i src/index.js -o lib/index.js", | ||
"build:umd": "cross-env BABEL_ENV=es NODE_ENV=development rollup -c rollup.umd.config.js -i src/index.js -o dist/react-onclickoutside.js", | ||
"build:umd:min": "cross-env BABEL_ENV=es NODE_ENV=production rollup -c rollup.umd.config.js -i src/index.js -o dist/react-onclickoutside.min.js", | ||
"build": "rollup -c", | ||
"lint": "eslint src/*.js ./test", | ||
"test": "run-s test:**", | ||
"test:basic": "run-s lint build:cjs", | ||
"test:basic": "run-s lint build", | ||
"test:karma": "karma start test/karma.conf.js --single-run", | ||
@@ -63,6 +57,5 @@ "test:nodom": "mocha test/no-dom-test.js", | ||
"babel-loader": "8.0.0-beta.0", | ||
"chai": "^3.5.0", | ||
"cross-env": "^5.0.0", | ||
"eslint": "^3.4.0", | ||
"husky": "^0.13.3", | ||
"chai": "^4.1.2", | ||
"eslint": "^4.12.0", | ||
"husky": "^0.14.3", | ||
"karma": "^1.4.0", | ||
@@ -72,6 +65,6 @@ "karma-chai": "^0.1.0", | ||
"karma-mocha": "^1.3.0", | ||
"karma-spec-reporter": "0.0.26", | ||
"karma-webpack": "^2.0.2", | ||
"lint-staged": "^3.4.2", | ||
"mocha": "^3.2.0", | ||
"karma-spec-reporter": "0.0.31", | ||
"karma-webpack": "^2.0.6", | ||
"lint-staged": "^5.0.0", | ||
"mocha": "^4.0.1", | ||
"npm-run-all": "^4.0.2", | ||
@@ -84,4 +77,4 @@ "prettier": "^1.8.2", | ||
"rimraf": "^2.6.2", | ||
"rollup": "^0.51.3", | ||
"rollup-plugin-babel": "^4.0.0-beta.0", | ||
"rollup": "^0.52.0", | ||
"rollup-plugin-babel": "4.0.0-beta.0", | ||
"rollup-plugin-uglify": "^2.0.1", | ||
@@ -88,0 +81,0 @@ "webpack": "^3.8.1" |
244
README.md
@@ -7,22 +7,31 @@ [![npm version](https://img.shields.io/npm/v/react-onclickoutside.svg)](https://www.npmjs.com/package/react-onclickoutside) | ||
This is a React Higher Order Component (HOC) that you can use with your own React components if you want to have them listen for clicks that occur somewhere in the document, outside of the element itself (for instance, if you need to hide a menu when people click anywhere else on your page). | ||
This is a React Higher Order Component (HOC) that you can use with your own | ||
React components if you want to have them listen for clicks that occur somewhere | ||
in the document, outside of the element itself (for instance, if you need to | ||
hide a menu when people click anywhere else on your page). | ||
Note that this HOC relies on the `.classList` property, which is supported by all modern browsers, but not by deprecated and obsolete browsers like IE (noting that Microsoft Edge is not Microsoft Internet Explorer. Edge does not have any problems with the `classList` property for SVG elements). If your code relies on classList in any way, you want to use a polyfill like [dom4](https://github.com/WebReflection/dom4). | ||
Note that this HOC relies on the `.classList` property, which is supported by | ||
all modern browsers, but not by deprecated and obsolete browsers like IE (noting | ||
that Microsoft Edge is not Microsoft Internet Explorer. Edge does not have any | ||
problems with the `classList` property for SVG elements). If your code relies on | ||
classList in any way, you want to use a polyfill like | ||
[dom4](https://github.com/WebReflection/dom4). | ||
This HOC supports stateless components as of v5.7.0, and switched to using transpiled es6 classes rather than `createClass` as of v6. | ||
This HOC supports stateless components as of v5.7.0, and switched to using | ||
transpiled es6 classes rather than `createClass` as of v6. | ||
## Sections covered in this README | ||
- [Installation](#installation) | ||
- [Regulate which events to listen for](#regulate-which-events-to-listen-for) | ||
- [Regulate whether or not to listen for outside clicks](#regulate-whether-or-not-to-listen-for-outside-clicks) | ||
- [Regulate whether or not to listen to scrollbar clicks](#regulate-whether-or-not-to-listen-to-scrollbar-clicks) | ||
- [Regulating `evt.preventDefault()` and `evt.stopPropagation()`](#regulating-evtpreventdefault-and-evtstoppropagation) | ||
- [Marking elements as "skip over this one" during the event loop](#marking-elements-as-skip-over-this-one-during-the-event-loop) | ||
- [Older React code: "What happened to the Mixin??"](#older-react-code-what-happened-to-the-mixin) | ||
* [Installation](#installation) | ||
* [Regulate which events to listen for](#regulate-which-events-to-listen-for) | ||
* [Regulate whether or not to listen for outside clicks](#regulate-whether-or-not-to-listen-for-outside-clicks) | ||
* [Regulate whether or not to listen to scrollbar clicks](#regulate-whether-or-not-to-listen-to-scrollbar-clicks) | ||
* [Regulating `evt.preventDefault()` and `evt.stopPropagation()`](#regulating-evtpreventdefault-and-evtstoppropagation) | ||
* [Marking elements as "skip over this one" during the event loop](#marking-elements-as-skip-over-this-one-during-the-event-loop) | ||
* [Older React code: "What happened to the Mixin??"](#older-react-code-what-happened-to-the-mixin) | ||
* [But how can I access my component? It has an API that I rely on!](#but-how-can-i-access-my-component-it-has-an-api-that-i-rely-on) | ||
- [Which version do I need for which version of React?](#which-version-do-i-need-for-which-version-of-react) | ||
* [Which version do I need for which version of React?](#which-version-do-i-need-for-which-version-of-react) | ||
* [Support-wise, only the latest version will receive updates and bug fixes.](#support-wise-only-the-latest-version-will-receive-updates-and-bug-fixes) | ||
- [IE does not support classList for SVG elements!](#ie-does-not-support-classlist-for-svg-elements) | ||
- [I can't find what I need in the README](#i-cant-find-what-i-need-in-the-readme) | ||
* [IE does not support classList for SVG elements!](#ie-does-not-support-classlist-for-svg-elements) | ||
* [I can't find what I need in the README](#i-cant-find-what-i-need-in-the-readme) | ||
@@ -37,8 +46,9 @@ ## Installation | ||
(or `--save-dev` depending on your needs). You then use it in your components as: | ||
(or `--save-dev` depending on your needs). You then use it in your components | ||
as: | ||
```js | ||
// ES6 Class and Module Syntax | ||
import React, { Component } from 'react' | ||
import onClickOutside from 'react-onclickoutside' | ||
import React, { Component } from "react"; | ||
import onClickOutside from "react-onclickoutside"; | ||
@@ -48,6 +58,6 @@ class MyComponent extends Component { | ||
// ..handling code goes here... | ||
} | ||
}; | ||
} | ||
export default onClickOutside(MyComponent) | ||
export default onClickOutside(MyComponent); | ||
``` | ||
@@ -60,30 +70,36 @@ | ||
// .default is needed because library is bundled as ES6 module | ||
var onClickOutside = require('react-onclickoutside').default; | ||
var createReactClass = require('create-react-class'); | ||
var onClickOutside = require("react-onclickoutside").default; | ||
var createReactClass = require("create-react-class"); | ||
// create a new component, wrapped by this onclickoutside HOC: | ||
var MyComponent = onClickOutside(createReactClass({ | ||
..., | ||
handleClickOutside: function(evt) { | ||
// ...handling code goes here... | ||
}, | ||
... | ||
})); | ||
var MyComponent = onClickOutside( | ||
createReactClass({ | ||
// ..., | ||
handleClickOutside: function(evt) { | ||
// ...handling code goes here... | ||
} | ||
// ... | ||
}) | ||
); | ||
``` | ||
Note that if you try to wrap a React component class without a `handleClickOutside(evt)` handler like this, the HOC will throw an error. In order to use a custom event handler, you can specify the function to be used by the HOC as second parameter | ||
(this can be useful in environments like TypeScript, where the fact that the wrapped component does not implement the handler can be flagged at compile-time): | ||
Note that if you try to wrap a React component class without a | ||
`handleClickOutside(evt)` handler like this, the HOC will throw an error. In | ||
order to use a custom event handler, you can specify the function to be used by | ||
the HOC as second parameter (this can be useful in environments like TypeScript, | ||
where the fact that the wrapped component does not implement the handler can be | ||
flagged at compile-time): | ||
```js | ||
// load the HOC: | ||
import React, { Component } from 'react' | ||
import onClickOutside from 'react-onclickoutside' | ||
import React, { Component } from "react"; | ||
import onClickOutside from "react-onclickoutside"; | ||
// create a new component, wrapped below by onClickOutside HOC: | ||
class MyComponent extends Component { | ||
... | ||
// ... | ||
myClickOutsideHandler(evt) { | ||
// ...handling code goes here... | ||
} | ||
... | ||
// ... | ||
} | ||
@@ -94,11 +110,16 @@ var clickOutsideConfig = { | ||
} | ||
} | ||
}; | ||
var EnhancedComponent = onClickOutside(MyComponent, clickOutsideConfig); | ||
``` | ||
Note that if you try to wrap a React component with a custom handler that the component does not implement, the HOC will throw an error at run-time. | ||
Note that if you try to wrap a React component with a custom handler that the | ||
component does not implement, the HOC will throw an error at run-time. | ||
## Regulate which events to listen for | ||
By default, "outside clicks" are based on both `mousedown` and `touchstart` events; if that is what you need, then you do not need to specify anything special. However, if you need different events, you can specify these using the `eventTypes` property. If you just need one event, you can pass in the event name as plain string: | ||
By default, "outside clicks" are based on both `mousedown` and `touchstart` | ||
events; if that is what you need, then you do not need to specify anything | ||
special. However, if you need different events, you can specify these using the | ||
`eventTypes` property. If you just need one event, you can pass in the event | ||
name as plain string: | ||
@@ -109,3 +130,4 @@ ```js | ||
For multiple events, you can pass in the array of event names you need to listen for: | ||
For multiple events, you can pass in the array of event names you need to listen | ||
for: | ||
@@ -118,19 +140,25 @@ ```js | ||
Wrapped components have two functions that can be used to explicitly listen for, or do nothing with, outside clicks | ||
Wrapped components have two functions that can be used to explicitly listen for, | ||
or do nothing with, outside clicks | ||
- `enableOnClickOutside()` - Enables outside click listening by setting up the event listening bindings. | ||
- `disableOnClickOutside()` - Disables outside click listening by explicitly removing the event listening bindings. | ||
* `enableOnClickOutside()` - Enables outside click listening by setting up the | ||
event listening bindings. | ||
* `disableOnClickOutside()` - Disables outside click listening by explicitly | ||
removing the event listening bindings. | ||
In addition, you can create a component that uses this HOC 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`: | ||
In addition, you can create a component that uses this HOC 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`: | ||
```js | ||
import React, { Component } from 'react' | ||
import onClickOutside from 'react-onclickoutside' | ||
import React, { Component } from "react"; | ||
import onClickOutside from "react-onclickoutside"; | ||
class MyComponent extends Component { | ||
... | ||
// ... | ||
handleClickOutside(evt) { | ||
// ... | ||
} | ||
... | ||
// ... | ||
} | ||
@@ -141,3 +169,3 @@ var EnhancedComponent = onClickOutside(MyComponent); | ||
render(evt) { | ||
return <EnhancedComponent disableOnClickOutside={true} /> | ||
return <EnhancedComponent disableOnClickOutside={true} />; | ||
} | ||
@@ -147,14 +175,21 @@ } | ||
Using `disableOnClickOutside()` or `enableOnClickOutside()` within `componentDidMount` or `componentWillMount` is considered an anti-pattern, and does not have consistent behaviour when using the mixin and HOC/ES7 Decorator. Favour setting the `disableOnClickOutside` property on the component. | ||
Using `disableOnClickOutside()` or `enableOnClickOutside()` within | ||
`componentDidMount` or `componentWillMount` is considered an anti-pattern, and | ||
does not have consistent behaviour when using the mixin and HOC/ES7 Decorator. | ||
Favour setting the `disableOnClickOutside` property on the component. | ||
## Regulate whether or not to listen to scrollbar clicks | ||
By default this HOC will listen for "clicks inside the document", which may include clicks that occur on the scrollbar. Quite often clicking on the scrollbar *should* close whatever is open but in case your project invalidates that assumption you can use the `excludeScrollbar` property to explicitly tell the HOC that clicks on the scrollbar should be ignored: | ||
By default this HOC will listen for "clicks inside the document", which may | ||
include clicks that occur on the scrollbar. Quite often clicking on the | ||
scrollbar _should_ close whatever is open but in case your project invalidates | ||
that assumption you can use the `excludeScrollbar` property to explicitly tell | ||
the HOC that clicks on the scrollbar should be ignored: | ||
```js | ||
import React, { Component } from 'react' | ||
import onClickOutside from 'react-onclickoutside' | ||
import React, { Component } from "react"; | ||
import onClickOutside from "react-onclickoutside"; | ||
class MyComponent extends Component { | ||
... | ||
// ... | ||
} | ||
@@ -165,3 +200,3 @@ var EnhancedComponent = onClickOutside(MyComponent); | ||
render(evt) { | ||
return <EnhancedComponent excludeScrollbar={true} /> | ||
return <EnhancedComponent excludeScrollbar={true} />; | ||
} | ||
@@ -171,14 +206,15 @@ } | ||
Alternatively, you can specify this behavior as default for all instances of your component passing a configuration object as second parameter: | ||
Alternatively, you can specify this behavior as default for all instances of | ||
your component passing a configuration object as second parameter: | ||
```js | ||
import React, { Component } from 'react' | ||
import onClickOutside from 'react-onclickoutside' | ||
import React, { Component } from "react"; | ||
import onClickOutside from "react-onclickoutside"; | ||
class MyComponent extends Component { | ||
... | ||
// ... | ||
} | ||
var clickOutsideConfig = { | ||
excludeScrollbar: true | ||
} | ||
}; | ||
var EnhancedComponent = onClickOutside(MyComponent, clickOutsideConfig); | ||
@@ -189,19 +225,34 @@ ``` | ||
Technically this HOC lets you pass in `preventDefault={true/false}` and `stopPropagation={true/false}` to regulate what happens to the event when it hits your `handleClickOutside(evt)` function, but beware: `stopPropagation` may not do what you expect it to do. | ||
Technically this HOC lets you pass in `preventDefault={true/false}` and | ||
`stopPropagation={true/false}` to regulate what happens to the event when it | ||
hits your `handleClickOutside(evt)` function, but beware: `stopPropagation` may | ||
not do what you expect it to do. | ||
Each component adds new event listeners to the document, which may or may not cause as many event triggers as there are event listening bindings. In the test file found in `./test/browser/index.html`, the coded uses `stopPropagation={true}` but sibling events still make it to "parents". | ||
Each component adds new event listeners to the document, which may or may not | ||
cause as many event triggers as there are event listening bindings. In the test | ||
file found in `./test/browser/index.html`, the coded uses | ||
`stopPropagation={true}` but sibling events still make it to "parents". | ||
## Marking elements as "skip over this one" during the event loop | ||
If you want the HOC to ignore certain elements, you can tell the HOC which CSS class name it should use for this purposes. If you want explicit control over the class name, use `outsideClickIgnoreClass={some string}` as component property, or if you don't, the default string used is `ignore-react-onclickoutside`. | ||
If you want the HOC to ignore certain elements, you can tell the HOC which CSS | ||
class name it should use for this purposes. If you want explicit control over | ||
the class name, use `outsideClickIgnoreClass={some string}` as component | ||
property, or if you don't, the default string used is | ||
`ignore-react-onclickoutside`. | ||
## Older React code: "What happened to the Mixin??" | ||
Due to ES2015/ES6 `class` syntax making mixins essentially impossible, and the fact that HOC wrapping works perfectly fine in ES5 and older versions of React, as of this package's version 5.0.0 no Mixin is offered anymore. | ||
Due to ES2015/ES6 `class` syntax making mixins essentially impossible, and the | ||
fact that HOC wrapping works perfectly fine in ES5 and older versions of React, | ||
as of this package's version 5.0.0 no Mixin is offered anymore. | ||
If you *absolutely* need a mixin... you really don't. | ||
If you _absolutely_ need a mixin... you really don't. | ||
### But how can I access my component? It has an API that I rely on! | ||
No, I get that. I constantly have that problem myself, so while there is no universal agreement on how to do that, this HOC offers a `getInstance()` function that you can call for a reference to the component you wrapped, so that you can call its API without headaches: | ||
No, I get that. I constantly have that problem myself, so while there is no | ||
universal agreement on how to do that, this HOC offers a `getInstance()` | ||
function that you can call for a reference to the component you wrapped, so that | ||
you can call its API without headaches: | ||
@@ -213,3 +264,3 @@ ```js | ||
class MyComponent extends Component { | ||
... | ||
// ... | ||
handleClickOutside(evt) { | ||
@@ -246,3 +297,8 @@ // ... | ||
Note that there is also a `getClass()` function, to get the original Class that was passed into the HOC wrapper, but if you find yourself needing this you're probably doing something wrong: you really want to define your classes as real, require'able etc. units, and then write wrapped components separately, so that you can always access the original class's `statics` etc. properties without needing to extract them out of a HOC. | ||
Note that there is also a `getClass()` function, to get the original Class that | ||
was passed into the HOC wrapper, but if you find yourself needing this you're | ||
probably doing something wrong: you really want to define your classes as real, | ||
require'able etc. units, and then write wrapped components separately, so that | ||
you can always access the original class's `statics` etc. properties without | ||
needing to extract them out of a HOC. | ||
@@ -253,21 +309,43 @@ ## Which version do I need for which version of React? | ||
If you use **React 0.14**, use **v2.5 through v4.9**, as these specifically use `react-DOM` for the necessary DOM event bindings. | ||
If you use **React 0.14**, use **v2.5 through v4.9**, as these specifically use | ||
`react-DOM` for the necessary DOM event bindings. | ||
If you use **React 15**, you can use **v4.x, which offers both a mixin and HOC, or use v5.x, which is HOC-only**. | ||
If you use **React 15**, you can use **v4.x, which offers both a mixin and HOC, | ||
or use v5.x, which is HOC-only**. | ||
If you use **React 15.5**, you can use **v5.11.x**, which relies on `createClass` as supplied by `create-react-class` rather than `React.createClass`. | ||
If you use **React 15.5**, you can use **v5.11.x**, which relies on | ||
`createClass` as supplied by `create-react-class` rather than | ||
`React.createClass`. | ||
If you use **React 16** or 15.5 in preparation of 16, use v6.x, which uses pure class notation. | ||
If you use **React 16** or 15.5 in preparation of 16, use v6.x, which uses pure | ||
class notation. | ||
### Support-wise, only the latest version will receive updates and bug fixes. | ||
I do not believe in perpetual support for outdated libraries, so if you find one of the older versions is not playing nice with an even older React: you know what to do, and it's not "keep using that old version of React". | ||
I do not believe in perpetual support for outdated libraries, so if you find one | ||
of the older versions is not playing nice with an even older React: you know | ||
what to do, and it's not "keep using that old version of React". | ||
## IE does not support classList for SVG elements! | ||
This is true, but also an edge-case problem that only exists for older versions of IE (including IE11), and should be addressed by you, rather than by thousands of individual libraries that assume browsers have proper HTML API implementations (IE Edge has proper `classList` support even for SVG). | ||
This is true, but also an edge-case problem that only exists for older versions | ||
of IE (including IE11), and should be addressed by you, rather than by thousands | ||
of individual libraries that assume browsers have proper HTML API | ||
implementations (IE Edge has proper `classList` support even for SVG). | ||
If you need this to work, you can add a shim for `classList` to your page(s), loaded before you load your React code, and you'll have instantly fixed *every* library that you might remotely rely on that makes use of the `classList` property. You can find several shims quite easily, a good one to start with is the [dom4](https://github.com/WebReflection/dom4) shim, which adds all manner of good DOM4 properties to "not quite at DOM4 yet" browser implementations. | ||
If you need this to work, you can add a shim for `classList` to your page(s), | ||
loaded before you load your React code, and you'll have instantly fixed _every_ | ||
library that you might remotely rely on that makes use of the `classList` | ||
property. You can find several shims quite easily, a good one to start with is | ||
the [dom4](https://github.com/WebReflection/dom4) shim, which adds all manner of | ||
good DOM4 properties to "not quite at DOM4 yet" browser implementations. | ||
Eventually this problem will stop being one, but in the mean time *you* are responsible for making *your* site work by shimming everything that needs shimming for IE. As such, **if you file a PR to fix classList-and-SVG issues specifically for this library, your PR will be closed and I will politely point you to this README.md section**. I will not accept PRs to fix this issue. You already have the power to fix it, and I expect you to take responsibility as a fellow developer to shim what you need instead of getting obsolete quirks supported by libraries whose job isn't to support obsolete quirks. | ||
Eventually this problem will stop being one, but in the mean time _you_ are | ||
responsible for making _your_ site work by shimming everything that needs | ||
shimming for IE. As such, **if you file a PR to fix classList-and-SVG issues | ||
specifically for this library, your PR will be closed and I will politely point | ||
you to this README.md section**. I will not accept PRs to fix this issue. You | ||
already have the power to fix it, and I expect you to take responsibility as a | ||
fellow developer to shim what you need instead of getting obsolete quirks | ||
supported by libraries whose job isn't to support obsolete quirks. | ||
@@ -277,12 +355,12 @@ To work around the issue you can use this simple shim: | ||
```js | ||
if (!('classList' in SVGElement.prototype)) { | ||
Object.defineProperty(SVGElement.prototype, 'classList', { | ||
if (!("classList" in SVGElement.prototype)) { | ||
Object.defineProperty(SVGElement.prototype, "classList", { | ||
get() { | ||
return { | ||
contains: className => { | ||
return this.className.baseVal.split(' ').indexOf(className) !== -1 | ||
}, | ||
} | ||
}, | ||
}) | ||
return this.className.baseVal.split(" ").indexOf(className) !== -1; | ||
} | ||
}; | ||
} | ||
}); | ||
} | ||
@@ -293,2 +371,6 @@ ``` | ||
If you've read the whole thing and you still can't find what you were looking for, then the README is missing important information that should be added in. Please [file an issue](issues) with a request for additional documentation, describing what you were hoping to find in enough detail that it can be used to write up the information you needed. | ||
If you've read the whole thing and you still can't find what you were looking | ||
for, then the README is missing important information that should be added in. | ||
Please [file an issue](issues) with a request for additional documentation, | ||
describing what you were hoping to find in enough detail that it can be used to | ||
write up the information you needed. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
52173
29
846
360
1