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
			| 
											3 years ago
										 | (function(g,f){typeof exports==='object'&&typeof module!=='undefined'?f(exports,require('react'),require('react-dom')):typeof define==='function'&&define.amd?define(['exports','react','react-dom'],f):(g=typeof globalThis!=='undefined'?globalThis:g||self,f(g.onClickOutside={},g.React,g.ReactDOM));}(this,(function(exports, react, reactDom){'use strict';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;Object.defineProperty(exports,'__esModule',{value:true});}))); |