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
JavaScript
(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;
/***/ })
/******/ ]);
});