You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							356 lines
						
					
					
						
							11 KiB
						
					
					
				
			
		
		
	
	
							356 lines
						
					
					
						
							11 KiB
						
					
					
				| 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var react=require('react'),reactDom=require('react-dom');function _inheritsLoose(subClass, superClass) {
 | |
|   subClass.prototype = Object.create(superClass.prototype);
 | |
|   subClass.prototype.constructor = subClass;
 | |
| 
 | |
|   _setPrototypeOf(subClass, superClass);
 | |
| }
 | |
| 
 | |
| function _setPrototypeOf(o, p) {
 | |
|   _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
 | |
|     o.__proto__ = p;
 | |
|     return o;
 | |
|   };
 | |
| 
 | |
|   return _setPrototypeOf(o, p);
 | |
| }
 | |
| 
 | |
| function _objectWithoutPropertiesLoose(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];
 | |
|   }
 | |
| 
 | |
|   return target;
 | |
| }
 | |
| 
 | |
| function _assertThisInitialized(self) {
 | |
|   if (self === void 0) {
 | |
|     throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
 | |
|   }
 | |
| 
 | |
|   return self;
 | |
| }/**
 | |
|  * 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.
 | |
|   // Also cover shadowRoot node by checking current.host
 | |
| 
 | |
| 
 | |
|   while (current.parentNode || current.host) {
 | |
|     // Only check normal node without shadowRoot
 | |
|     if (current.parentNode && isNodeFound(current, componentNode, ignoreClass)) {
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     current = current.parentNode || current.host;
 | |
|   }
 | |
| 
 | |
|   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.composed && event.composedPath && event.composedPath().shift() || 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(_assertThisInitialized(_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(_assertThisInitialized(_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 && !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 _this$props = this.props;
 | |
|           _this$props.excludeScrollbar;
 | |
|           var props = _objectWithoutPropertiesLoose(_this$props, ["excludeScrollbar"]);
 | |
| 
 | |
|       if (WrappedComponent.prototype && 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; |