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