UNPKG

react-visibility-sensor

Version:

Sensor component for React that notifies you when it goes in or out of the window viewport.

595 lines (489 loc) 22.7 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("react"), require("react-dom")); else if(typeof define === 'function' && define.amd) define(["React", "ReactDOM"], factory); else if(typeof exports === 'object') exports["react-visibility-sensor"] = factory(require("react"), require("react-dom")); else root["react-visibility-sensor"] = factory(root["React"], root["ReactDOM"]); })(this, function(__WEBPACK_EXTERNAL_MODULE__1__, __WEBPACK_EXTERNAL_MODULE__2__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 4); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ if (false) { var throwOnDirectAccess, ReactIs; } else { // By explicitly using `prop-types` you are opting into new production behavior. // http://fb.me/prop-types-in-prod module.exports = __webpack_require__(5)(); } /***/ }), /* 1 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__1__; /***/ }), /* 2 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__2__; /***/ }), /* 3 */ /***/ (function(module, exports) { // Tell whether the rect is visible, given an offset // // return: boolean module.exports = function (offset, rect, containmentRect) { var offsetDir = offset.direction; var offsetVal = offset.value; // Rules for checking different kind of offsets. In example if the element is // 90px below viewport and offsetTop is 100, it is considered visible. switch (offsetDir) { case 'top': return containmentRect.top + offsetVal < rect.top && containmentRect.bottom > rect.bottom && containmentRect.left < rect.left && containmentRect.right > rect.right; case 'left': return containmentRect.left + offsetVal < rect.left && containmentRect.bottom > rect.bottom && containmentRect.top < rect.top && containmentRect.right > rect.right; case 'bottom': return containmentRect.bottom - offsetVal > rect.bottom && containmentRect.left < rect.left && containmentRect.right > rect.right && containmentRect.top < rect.top; case 'right': return containmentRect.right - offsetVal > rect.right && containmentRect.left < rect.left && containmentRect.top < rect.top && containmentRect.bottom > rect.bottom; } }; /***/ }), /* 4 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return VisibilitySensor; }); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2); /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var prop_types__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(0); /* harmony import */ var prop_types__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(prop_types__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _lib_is_visible_with_offset__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3); /* harmony import */ var _lib_is_visible_with_offset__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_lib_is_visible_with_offset__WEBPACK_IMPORTED_MODULE_3__); function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function normalizeRect(rect) { if (rect.width === undefined) { rect.width = rect.right - rect.left; } if (rect.height === undefined) { rect.height = rect.bottom - rect.top; } return rect; } var VisibilitySensor = /*#__PURE__*/ function (_React$Component) { _inherits(VisibilitySensor, _React$Component); function VisibilitySensor(props) { var _this; _classCallCheck(this, VisibilitySensor); _this = _possibleConstructorReturn(this, _getPrototypeOf(VisibilitySensor).call(this, props)); _defineProperty(_assertThisInitialized(_this), "getContainer", function () { return _this.props.containment || window; }); _defineProperty(_assertThisInitialized(_this), "addEventListener", function (target, event, delay, throttle) { if (!_this.debounceCheck) { _this.debounceCheck = {}; } var timeout; var func; var later = function later() { timeout = null; _this.check(); }; if (throttle > -1) { func = function func() { if (!timeout) { timeout = setTimeout(later, throttle || 0); } }; } else { func = function func() { clearTimeout(timeout); timeout = setTimeout(later, delay || 0); }; } var info = { target: target, fn: func, getLastTimeout: function getLastTimeout() { return timeout; } }; target.addEventListener(event, info.fn); _this.debounceCheck[event] = info; }); _defineProperty(_assertThisInitialized(_this), "startWatching", function () { if (_this.debounceCheck || _this.interval) { return; } if (_this.props.intervalCheck) { _this.interval = setInterval(_this.check, _this.props.intervalDelay); } if (_this.props.scrollCheck) { _this.addEventListener(_this.getContainer(), "scroll", _this.props.scrollDelay, _this.props.scrollThrottle); } if (_this.props.resizeCheck) { _this.addEventListener(window, "resize", _this.props.resizeDelay, _this.props.resizeThrottle); } // if dont need delayed call, check on load ( before the first interval fires ) !_this.props.delayedCall && _this.check(); }); _defineProperty(_assertThisInitialized(_this), "stopWatching", function () { if (_this.debounceCheck) { // clean up event listeners and their debounce callers for (var debounceEvent in _this.debounceCheck) { if (_this.debounceCheck.hasOwnProperty(debounceEvent)) { var debounceInfo = _this.debounceCheck[debounceEvent]; clearTimeout(debounceInfo.getLastTimeout()); debounceInfo.target.removeEventListener(debounceEvent, debounceInfo.fn); _this.debounceCheck[debounceEvent] = null; } } } _this.debounceCheck = null; if (_this.interval) { _this.interval = clearInterval(_this.interval); } }); _defineProperty(_assertThisInitialized(_this), "check", function () { var el = _this.node; var rect; var containmentRect; // if the component has rendered to null, dont update visibility if (!el) { return _this.state; } rect = normalizeRect(_this.roundRectDown(el.getBoundingClientRect())); if (_this.props.containment) { var containmentDOMRect = _this.props.containment.getBoundingClientRect(); containmentRect = { top: containmentDOMRect.top, left: containmentDOMRect.left, bottom: containmentDOMRect.bottom, right: containmentDOMRect.right }; } else { containmentRect = { top: 0, left: 0, bottom: window.innerHeight || document.documentElement.clientHeight, right: window.innerWidth || document.documentElement.clientWidth }; } // Check if visibility is wanted via offset? var offset = _this.props.offset || {}; var hasValidOffset = _typeof(offset) === "object"; if (hasValidOffset) { containmentRect.top += offset.top || 0; containmentRect.left += offset.left || 0; containmentRect.bottom -= offset.bottom || 0; containmentRect.right -= offset.right || 0; } var visibilityRect = { top: rect.top >= containmentRect.top, left: rect.left >= containmentRect.left, bottom: rect.bottom <= containmentRect.bottom, right: rect.right <= containmentRect.right }; // https://github.com/joshwnj/react-visibility-sensor/pull/114 var hasSize = rect.height > 0 && rect.width > 0; var isVisible = hasSize && visibilityRect.top && visibilityRect.left && visibilityRect.bottom && visibilityRect.right; // check for partial visibility if (hasSize && _this.props.partialVisibility) { var partialVisible = rect.top <= containmentRect.bottom && rect.bottom >= containmentRect.top && rect.left <= containmentRect.right && rect.right >= containmentRect.left; // account for partial visibility on a single edge if (typeof _this.props.partialVisibility === "string") { partialVisible = visibilityRect[_this.props.partialVisibility]; } // if we have minimum top visibility set by props, lets check, if it meets the passed value // so if for instance element is at least 200px in viewport, then show it. isVisible = _this.props.minTopValue ? partialVisible && rect.top <= containmentRect.bottom - _this.props.minTopValue : partialVisible; } // Deprecated options for calculating offset. if (typeof offset.direction === "string" && typeof offset.value === "number") { console.warn("[notice] offset.direction and offset.value have been deprecated. They still work for now, but will be removed in next major version. Please upgrade to the new syntax: { %s: %d }", offset.direction, offset.value); isVisible = _lib_is_visible_with_offset__WEBPACK_IMPORTED_MODULE_3___default()(offset, rect, containmentRect); } var state = _this.state; // notify the parent when the value changes if (_this.state.isVisible !== isVisible) { state = { isVisible: isVisible, visibilityRect: visibilityRect }; _this.setState(state); if (_this.props.onChange) _this.props.onChange(isVisible); } return state; }); _this.state = { isVisible: null, visibilityRect: {} }; return _this; } _createClass(VisibilitySensor, [{ key: "componentDidMount", value: function componentDidMount() { this.node = react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.findDOMNode(this); if (this.props.active) { this.startWatching(); } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.stopWatching(); } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { // re-register node in componentDidUpdate if children diffs [#103] this.node = react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.findDOMNode(this); if (this.props.active && !prevProps.active) { this.setState({ isVisible: null, visibilityRect: {} }); this.startWatching(); } else if (!this.props.active) { this.stopWatching(); } } }, { key: "roundRectDown", value: function roundRectDown(rect) { return { top: Math.floor(rect.top), left: Math.floor(rect.left), bottom: Math.floor(rect.bottom), right: Math.floor(rect.right) }; } /** * Check if the element is within the visible viewport */ }, { key: "render", value: function render() { if (this.props.children instanceof Function) { return this.props.children({ isVisible: this.state.isVisible, visibilityRect: this.state.visibilityRect }); } return react__WEBPACK_IMPORTED_MODULE_0___default.a.Children.only(this.props.children); } }]); return VisibilitySensor; }(react__WEBPACK_IMPORTED_MODULE_0___default.a.Component); _defineProperty(VisibilitySensor, "defaultProps", { active: true, partialVisibility: false, minTopValue: 0, scrollCheck: false, scrollDelay: 250, scrollThrottle: -1, resizeCheck: false, resizeDelay: 250, resizeThrottle: -1, intervalCheck: true, intervalDelay: 100, delayedCall: false, offset: {}, containment: null, children: react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", null) }); _defineProperty(VisibilitySensor, "propTypes", { onChange: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.func, active: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.bool, partialVisibility: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.bool, prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.oneOf(["top", "right", "bottom", "left"])]), delayedCall: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.bool, offset: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.shape({ top: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number, left: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number, bottom: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number, right: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number }), // deprecated offset property prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.shape({ direction: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.oneOf(["top", "right", "bottom", "left"]), value: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number })]), scrollCheck: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.bool, scrollDelay: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number, scrollThrottle: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number, resizeCheck: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.bool, resizeDelay: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number, resizeThrottle: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number, intervalCheck: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.bool, intervalDelay: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number, containment: typeof window !== "undefined" ? prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.instanceOf(window.Element) : prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.any, children: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.element, prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.func]), minTopValue: prop_types__WEBPACK_IMPORTED_MODULE_2___default.a.number }); /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var ReactPropTypesSecret = __webpack_require__(6); function emptyFunction() {} function emptyFunctionWithReset() {} emptyFunctionWithReset.resetWarningCache = emptyFunction; module.exports = function() { function shim(props, propName, componentName, location, propFullName, secret) { if (secret === ReactPropTypesSecret) { // It is still safe when called from React. return; } var err = new Error( 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + 'Use PropTypes.checkPropTypes() to call them. ' + 'Read more at http://fb.me/use-check-prop-types' ); err.name = 'Invariant Violation'; throw err; }; shim.isRequired = shim; function getShim() { return shim; }; // Important! // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. var ReactPropTypes = { array: shim, bool: shim, func: shim, number: shim, object: shim, string: shim, symbol: shim, any: shim, arrayOf: getShim, element: shim, elementType: shim, instanceOf: getShim, node: shim, objectOf: getShim, oneOf: getShim, oneOfType: getShim, shape: getShim, exact: getShim, checkPropTypes: emptyFunctionWithReset, resetWarningCache: emptyFunction }; ReactPropTypes.PropTypes = ReactPropTypes; return ReactPropTypes; }; /***/ }), /* 6 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; module.exports = ReactPropTypesSecret; /***/ }) /******/ ]); });