|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- 'use strict';
-
- Object.defineProperty(exports, '__esModule', { value: true });
-
- var react = require('react');
- var reactDom = require('react-dom');
-
- function _inheritsLoose(subClass, superClass) {
- subClass.prototype = Object.create(superClass.prototype);
- subClass.prototype.constructor = subClass;
- subClass.__proto__ = superClass;
- }
-
- function _objectWithoutProperties(source, excluded) {
- if (source == null) return {};
- var target = {};
- var sourceKeys = Object.keys(source);
- var key, i;
-
- for (i = 0; i < sourceKeys.length; i++) {
- key = sourceKeys[i];
- if (excluded.indexOf(key) >= 0) continue;
- target[key] = source[key];
- }
-
- if (Object.getOwnPropertySymbols) {
- var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
-
- for (i = 0; i < sourceSymbolKeys.length; i++) {
- key = sourceSymbolKeys[i];
- if (excluded.indexOf(key) >= 0) continue;
- if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
- target[key] = source[key];
- }
- }
-
- return target;
- }
-
- /**
- * Check whether some DOM node is our Component's node.
- */
- function isNodeFound(current, componentNode, ignoreClass) {
- if (current === componentNode) {
- return true;
- } // SVG <use/> elements do not technically reside in the rendered DOM, so
- // they do not have classList directly, but they offer a link to their
- // corresponding element, which can have classList. This extra check is for
- // that case.
- // See: http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGUseElement
- // Discussion: https://github.com/Pomax/react-onclickoutside/pull/17
-
-
- if (current.correspondingElement) {
- return current.correspondingElement.classList.contains(ignoreClass);
- }
-
- return current.classList.contains(ignoreClass);
- }
- /**
- * Try to find our node in a hierarchy of nodes, returning the document
- * node as highest node if our node is not found in the path up.
- */
-
- function findHighest(current, componentNode, ignoreClass) {
- if (current === componentNode) {
- return true;
- } // 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 (isNodeFound(current, componentNode, ignoreClass)) {
- return true;
- }
-
- current = current.parentNode;
- }
-
- return current;
- }
- /**
- * Check if the browser scrollbar was clicked
- */
-
- function clickedScrollbar(evt) {
- return document.documentElement.clientWidth <= evt.clientX || document.documentElement.clientHeight <= evt.clientY;
- }
-
- // ideally will get replaced with external dep
- // when rafrex/detect-passive-events#4 and rafrex/detect-passive-events#5 get merged in
- var testPassiveEventSupport = function testPassiveEventSupport() {
- if (typeof window === 'undefined' || typeof window.addEventListener !== 'function') {
- return;
- }
-
- var passive = false;
- var options = Object.defineProperty({}, 'passive', {
- get: function get() {
- passive = true;
- }
- });
-
- var noop = function noop() {};
-
- window.addEventListener('testPassiveEventSupport', noop, options);
- window.removeEventListener('testPassiveEventSupport', noop, options);
- return passive;
- };
-
- function autoInc(seed) {
- if (seed === void 0) {
- seed = 0;
- }
-
- return function () {
- return ++seed;
- };
- }
-
- var uid = autoInc();
-
- var passiveEventSupport;
- var handlersMap = {};
- var enabledInstances = {};
- var touchEvents = ['touchstart', 'touchmove'];
- var IGNORE_CLASS_NAME = 'ignore-react-onclickoutside';
- /**
- * 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
- * in order to impart onOutsideClick listening to an
- * arbitrary component. It gets called at the end of the
- * bootstrapping code to yield an instance of the
- * onClickOutsideHOC function defined inside setupHOC().
- */
-
-
- function onClickOutsideHOC(WrappedComponent, config) {
- var _class, _temp;
-
- var componentName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
- return _temp = _class =
- /*#__PURE__*/
- function (_Component) {
- _inheritsLoose(onClickOutside, _Component);
-
- function onClickOutside(props) {
- var _this;
-
- _this = _Component.call(this, props) || this;
-
- _this.__outsideClickHandler = function (event) {
- if (typeof _this.__clickOutsideHandlerProp === 'function') {
- _this.__clickOutsideHandlerProp(event);
-
- return;
- }
-
- var instance = _this.getInstance();
-
- if (typeof instance.props.handleClickOutside === 'function') {
- instance.props.handleClickOutside(event);
- return;
- }
-
- if (typeof instance.handleClickOutside === 'function') {
- instance.handleClickOutside(event);
- return;
- }
-
- throw new Error("WrappedComponent: " + componentName + " lacks a handleClickOutside(event) function for processing outside click events.");
- };
-
- _this.__getComponentNode = function () {
- var instance = _this.getInstance();
-
- if (config && typeof config.setClickOutsideRef === 'function') {
- return config.setClickOutsideRef()(instance);
- }
-
- if (typeof instance.setClickOutsideRef === 'function') {
- return instance.setClickOutsideRef();
- }
-
- return reactDom.findDOMNode(instance);
- };
-
- _this.enableOnClickOutside = function () {
- if (typeof document === 'undefined' || enabledInstances[_this._uid]) {
- return;
- }
-
- if (typeof passiveEventSupport === 'undefined') {
- passiveEventSupport = testPassiveEventSupport();
- }
-
- enabledInstances[_this._uid] = true;
- var events = _this.props.eventTypes;
-
- if (!events.forEach) {
- events = [events];
- }
-
- handlersMap[_this._uid] = function (event) {
- if (_this.componentNode === null) return;
-
- if (_this.props.preventDefault) {
- event.preventDefault();
- }
-
- if (_this.props.stopPropagation) {
- event.stopPropagation();
- }
-
- if (_this.props.excludeScrollbar && clickedScrollbar(event)) return;
- var current = event.target;
-
- if (findHighest(current, _this.componentNode, _this.props.outsideClickIgnoreClass) !== document) {
- return;
- }
-
- _this.__outsideClickHandler(event);
- };
-
- events.forEach(function (eventName) {
- document.addEventListener(eventName, handlersMap[_this._uid], getEventHandlerOptions(_this, eventName));
- });
- };
-
- _this.disableOnClickOutside = function () {
- delete enabledInstances[_this._uid];
- var fn = handlersMap[_this._uid];
-
- if (fn && typeof document !== 'undefined') {
- var events = _this.props.eventTypes;
-
- if (!events.forEach) {
- events = [events];
- }
-
- events.forEach(function (eventName) {
- return document.removeEventListener(eventName, fn, getEventHandlerOptions(_this, eventName));
- });
- delete handlersMap[_this._uid];
- }
- };
-
- _this.getRef = function (ref) {
- return _this.instanceRef = ref;
- };
-
- _this._uid = uid();
- return _this;
- }
- /**
- * Access the WrappedComponent's instance.
- */
-
-
- var _proto = onClickOutside.prototype;
-
- _proto.getInstance = function getInstance() {
- if (!WrappedComponent.prototype.isReactComponent) {
- return this;
- }
-
- var ref = this.instanceRef;
- return ref.getInstance ? ref.getInstance() : ref;
- };
-
- /**
- * Add click listeners to the current document,
- * linked to this component's state.
- */
- _proto.componentDidMount = function componentDidMount() {
- // If we are in an environment without a DOM such
- // as shallow rendering or snapshots then we exit
- // early to prevent any unhandled errors being thrown.
- if (typeof document === 'undefined' || !document.createElement) {
- return;
- }
-
- var instance = this.getInstance();
-
- if (config && typeof config.handleClickOutside === 'function') {
- this.__clickOutsideHandlerProp = config.handleClickOutside(instance);
-
- if (typeof this.__clickOutsideHandlerProp !== 'function') {
- throw new Error("WrappedComponent: " + componentName + " lacks a function for processing outside click events specified by the handleClickOutside config option.");
- }
- }
-
- this.componentNode = this.__getComponentNode(); // return early so we dont initiate onClickOutside
-
- if (this.props.disableOnClickOutside) return;
- this.enableOnClickOutside();
- };
-
- _proto.componentDidUpdate = function componentDidUpdate() {
- this.componentNode = this.__getComponentNode();
- };
- /**
- * Remove all document's event listeners for this component
- */
-
-
- _proto.componentWillUnmount = function componentWillUnmount() {
- this.disableOnClickOutside();
- };
- /**
- * Can be called to explicitly enable event listening
- * for clicks and touches outside of this element.
- */
-
-
- /**
- * Pass-through render
- */
- _proto.render = function render() {
- // eslint-disable-next-line no-unused-vars
- var _props = this.props,
- excludeScrollbar = _props.excludeScrollbar,
- props = _objectWithoutProperties(_props, ["excludeScrollbar"]);
-
- if (WrappedComponent.prototype.isReactComponent) {
- props.ref = this.getRef;
- } else {
- props.wrappedRef = this.getRef;
- }
-
- props.disableOnClickOutside = this.disableOnClickOutside;
- props.enableOnClickOutside = this.enableOnClickOutside;
- return react.createElement(WrappedComponent, props);
- };
-
- return onClickOutside;
- }(react.Component), _class.displayName = "OnClickOutside(" + componentName + ")", _class.defaultProps = {
- eventTypes: ['mousedown', 'touchstart'],
- excludeScrollbar: config && config.excludeScrollbar || false,
- outsideClickIgnoreClass: IGNORE_CLASS_NAME,
- preventDefault: false,
- stopPropagation: false
- }, _class.getClass = function () {
- return WrappedComponent.getClass ? WrappedComponent.getClass() : WrappedComponent;
- }, _temp;
- }
-
- exports.IGNORE_CLASS_NAME = IGNORE_CLASS_NAME;
- exports['default'] = onClickOutsideHOC;
|