react-intersection-observer
Advanced tools
Comparing version 1.0.1 to 1.1.0
201
es/index.js
@@ -1,36 +0,11 @@ | ||
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var _react = require('react'); | ||
var _react2 = _interopRequireDefault(_react); | ||
var _propTypes = require('prop-types'); | ||
var _propTypes2 = _interopRequireDefault(_propTypes); | ||
var _intersection = require('./intersection'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
import React, { Component, createElement } from 'react'; // eslint-disable-line no-unused-vars | ||
import PropTypes from 'prop-types'; | ||
import { observe, unobserve } from './intersection'; | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
const isFunction = func => typeof func === 'function'; | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // eslint-disable-line no-unused-vars | ||
var isFunction = function isFunction(func) { | ||
return typeof func === 'function'; | ||
}; | ||
/** | ||
@@ -45,126 +20,100 @@ * Monitors scroll, and triggers the children function with updated props | ||
*/ | ||
class Observer extends Component { | ||
constructor(...args) { | ||
var _temp; | ||
var Observer = function (_Component) { | ||
_inherits(Observer, _Component); | ||
return _temp = super(...args), this.state = { | ||
inView: false | ||
}, this.node = null, this.handleNode = node => { | ||
if (this.node) unobserve(this.node); | ||
this.node = node; | ||
this.observeNode(); | ||
}, this.handleChange = inView => this.setState({ inView }), _temp; | ||
} | ||
function Observer() { | ||
var _ref; | ||
var _temp, _this, _ret; | ||
_classCallCheck(this, Observer); | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
componentWillUpdate(nextProps, nextState) { | ||
if (!!this.props.onChange && nextState !== this.state) { | ||
this.props.onChange(nextState.inView); | ||
} | ||
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Observer.__proto__ || Object.getPrototypeOf(Observer)).call.apply(_ref, [this].concat(args))), _this), _this.state = { | ||
inView: false | ||
}, _this.node = null, _this.handleNode = function (node) { | ||
if (_this.node) (0, _intersection.unobserve)(_this.node); | ||
_this.node = node; | ||
_this.observeNode(); | ||
}, _this.handleChange = function (inView) { | ||
return _this.setState({ inView: inView }); | ||
}, _temp), _possibleConstructorReturn(_this, _ret); | ||
} | ||
_createClass(Observer, [{ | ||
key: 'componentWillUpdate', | ||
value: function componentWillUpdate(nextProps, nextState) { | ||
if (!!this.props.onChange && nextState !== this.state) { | ||
this.props.onChange(nextState.inView); | ||
} | ||
componentDidUpdate(prevProps, prevState) { | ||
// If a IntersectionObserver option changed, reinit the observer | ||
if (prevProps.rootMargin !== this.props.rootMargin || prevProps.root !== this.props.root || prevProps.threshold !== this.props.threshold) { | ||
unobserve(this.node); | ||
this.observeNode(); | ||
} | ||
}, { | ||
key: 'componentDidUpdate', | ||
value: function componentDidUpdate(prevProps, prevState) { | ||
// If a IntersectionObserver option changed, reinit the observer | ||
if (prevProps.rootMargin !== this.props.rootMargin || prevProps.root !== this.props.root || prevProps.threshold !== this.props.threshold) { | ||
(0, _intersection.unobserve)(this.node); | ||
this.observeNode(); | ||
} | ||
if (prevState.inView !== this.state.inView) { | ||
if (this.state.inView && this.props.triggerOnce) { | ||
(0, _intersection.unobserve)(this.node); | ||
this.node = null; | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'componentWillUnmount', | ||
value: function componentWillUnmount() { | ||
if (this.node) { | ||
(0, _intersection.unobserve)(this.node); | ||
if (prevState.inView !== this.state.inView) { | ||
if (this.state.inView && this.props.triggerOnce) { | ||
unobserve(this.node); | ||
this.node = null; | ||
} | ||
} | ||
}, { | ||
key: 'observeNode', | ||
value: function observeNode() { | ||
if (!this.node) return; | ||
var _props = this.props, | ||
threshold = _props.threshold, | ||
root = _props.root, | ||
rootMargin = _props.rootMargin, | ||
rootId = _props.rootId; | ||
} | ||
(0, _intersection.observe)(this.node, this.handleChange, { | ||
threshold: threshold, | ||
root: root, | ||
rootMargin: rootMargin | ||
}, rootId); | ||
componentWillUnmount() { | ||
if (this.node) { | ||
unobserve(this.node); | ||
this.node = null; | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var _props2 = this.props, | ||
children = _props2.children, | ||
render = _props2.render, | ||
tag = _props2.tag, | ||
triggerOnce = _props2.triggerOnce, | ||
threshold = _props2.threshold, | ||
root = _props2.root, | ||
rootId = _props2.rootId, | ||
rootMargin = _props2.rootMargin, | ||
props = _objectWithoutProperties(_props2, ['children', 'render', 'tag', 'triggerOnce', 'threshold', 'root', 'rootId', 'rootMargin']); | ||
} | ||
var inView = this.state.inView; | ||
observeNode() { | ||
if (!this.node) return; | ||
const { threshold, root, rootMargin, rootId } = this.props; | ||
observe(this.node, this.handleChange, { | ||
threshold, | ||
root, | ||
rootMargin | ||
}, rootId); | ||
} | ||
render() { | ||
const _props = this.props, | ||
{ | ||
children, | ||
render, | ||
tag, | ||
triggerOnce, | ||
threshold, | ||
root, | ||
rootId, | ||
rootMargin | ||
} = _props, | ||
props = _objectWithoutProperties(_props, ['children', 'render', 'tag', 'triggerOnce', 'threshold', 'root', 'rootId', 'rootMargin']); | ||
return (0, _react.createElement)(tag, _extends({}, props, { | ||
ref: this.handleNode | ||
}), | ||
// If render is a function, use it to render content when in view | ||
inView && isFunction(render) ? render() : null, | ||
// If children is a function, render it with the current inView status. | ||
// Otherwise always render children. Assume onChange is being used outside, to control the the state of children. | ||
isFunction(children) ? children(inView) : children); | ||
} | ||
}]); | ||
const { inView } = this.state; | ||
return Observer; | ||
}(_react.Component); | ||
return createElement(tag, _extends({}, props, { | ||
ref: this.handleNode | ||
}), | ||
// If render is a function, use it to render content when in view | ||
inView && isFunction(render) ? render() : null, | ||
// If children is a function, render it with the current inView status. | ||
// Otherwise always render children. Assume onChange is being used outside, to control the the state of children. | ||
isFunction(children) ? children(inView) : children); | ||
} | ||
} | ||
Observer.propTypes = { | ||
/** Element tag to use for the wrapping */ | ||
tag: _propTypes2.default.node, | ||
tag: PropTypes.node, | ||
/** Children should be either a function or a node */ | ||
children: _propTypes2.default.oneOfType([_propTypes2.default.func, _propTypes2.default.node]), | ||
children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), | ||
/** Only trigger the inView callback once */ | ||
triggerOnce: _propTypes2.default.bool, | ||
triggerOnce: PropTypes.bool, | ||
/** Number between 0 and 1 indicating the the percentage that should be visible before triggering. Can also be an array of numbers, to create multiple trigger points. */ | ||
threshold: _propTypes2.default.oneOfType([_propTypes2.default.arrayOf(_propTypes2.default.number), _propTypes2.default.number]), | ||
threshold: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]), | ||
/** The HTMLElement that is used as the viewport for checking visibility of the target. Defaults to the browser viewport if not specified or if null.*/ | ||
root: _propTypes2.default.object, | ||
root: PropTypes.object, | ||
/** Margin around the root. Can have values similar to the CSS margin property, e.g. "10px 20px 30px 40px" (top, right, bottom, left). */ | ||
rootMargin: _propTypes2.default.string, | ||
rootMargin: PropTypes.string, | ||
/** Unique identifier for the root element - This is used to identify the IntersectionObserver instance, so it can be reused. | ||
* If you defined a root element, without adding an id, it will create a new instance for all components. */ | ||
rootId: _propTypes2.default.string, | ||
rootId: PropTypes.string, | ||
/** Call this function whenever the in view state changes */ | ||
onChange: _propTypes2.default.func, | ||
onChange: PropTypes.func, | ||
/** Use render method to only render content when inView */ | ||
render: _propTypes2.default.func | ||
render: PropTypes.func | ||
}; | ||
@@ -176,2 +125,2 @@ Observer.defaultProps = { | ||
}; | ||
exports.default = Observer; | ||
export default Observer; |
@@ -1,12 +0,4 @@ | ||
"use strict"; | ||
const INSTANCE_MAP = new Map(); | ||
const OBSERVER_MAP = new Map(); | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.observe = observe; | ||
exports.unobserve = unobserve; | ||
exports.destroy = destroy; | ||
var INSTANCE_MAP = new Map(); | ||
var OBSERVER_MAP = new Map(); | ||
/** | ||
@@ -22,19 +14,14 @@ * Monitor element, and trigger callback when element becomes visible | ||
*/ | ||
function observe(element, callback) { | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { | ||
threshold: 0 | ||
}; | ||
var rootId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; | ||
var threshold = options.threshold, | ||
root = options.root, | ||
rootMargin = options.rootMargin; | ||
export function observe(element, callback, options = { | ||
threshold: 0 | ||
}, rootId = null) { | ||
const { threshold, root, rootMargin } = options; | ||
if (!element || !callback) return; | ||
var observerId = rootMargin ? threshold + "_" + rootMargin : "" + threshold; | ||
let observerId = rootMargin ? `${threshold}_${rootMargin}` : `${threshold}`; | ||
if (root) { | ||
observerId = rootId ? rootId + "_" + observerId : null; | ||
observerId = rootId ? `${rootId}_${observerId}` : null; | ||
} | ||
var observerInstance = observerId ? OBSERVER_MAP.get(observerId) : null; | ||
let observerInstance = observerId ? OBSERVER_MAP.get(observerId) : null; | ||
if (!observerInstance) { | ||
@@ -45,7 +32,7 @@ observerInstance = new IntersectionObserver(onChange, options); | ||
var instance = { | ||
callback: callback, | ||
const instance = { | ||
callback, | ||
visible: false, | ||
options: options, | ||
observerId: observerId, | ||
options, | ||
observerId, | ||
observer: !observerId ? observerInstance : undefined | ||
@@ -66,12 +53,9 @@ }; | ||
*/ | ||
function unobserve(element) { | ||
export function unobserve(element) { | ||
if (!element) return; | ||
if (INSTANCE_MAP.has(element)) { | ||
var _INSTANCE_MAP$get = INSTANCE_MAP.get(element), | ||
observerId = _INSTANCE_MAP$get.observerId, | ||
observer = _INSTANCE_MAP$get.observer; | ||
const { observerId, observer } = INSTANCE_MAP.get(element); | ||
const observerInstance = observerId ? OBSERVER_MAP.get(observerId) : observer; | ||
var observerInstance = observerId ? OBSERVER_MAP.get(observerId) : observer; | ||
if (observerInstance) { | ||
@@ -82,5 +66,5 @@ observerInstance.unobserve(element); | ||
// Check if we are stilling observing any elements with the same threshold. | ||
var itemsLeft = false; | ||
let itemsLeft = false; | ||
if (observerId) { | ||
INSTANCE_MAP.forEach(function (item, key) { | ||
INSTANCE_MAP.forEach((item, key) => { | ||
if (item && item.observerId === observerId && key !== element) { | ||
@@ -106,4 +90,4 @@ itemsLeft = true; | ||
**/ | ||
function destroy() { | ||
OBSERVER_MAP.forEach(function (observer) { | ||
export function destroy() { | ||
OBSERVER_MAP.forEach(observer => { | ||
observer.disconnect(); | ||
@@ -117,16 +101,13 @@ }); | ||
function onChange(changes) { | ||
changes.forEach(function (intersection) { | ||
changes.forEach(intersection => { | ||
if (INSTANCE_MAP.has(intersection.target)) { | ||
var isIntersecting = intersection.isIntersecting, | ||
intersectionRatio = intersection.intersectionRatio, | ||
target = intersection.target; | ||
const { isIntersecting, intersectionRatio, target } = intersection; | ||
const instance = INSTANCE_MAP.get(target); | ||
const options = instance.options; | ||
var instance = INSTANCE_MAP.get(target); | ||
var options = instance.options; | ||
let inView; | ||
var inView = void 0; | ||
if (Array.isArray(options.threshold)) { | ||
// If threshold is an array, check if any of them intersects. This just triggers the onChange event multiple times. | ||
inView = options.threshold.some(function (threshold) { | ||
inView = options.threshold.some(threshold => { | ||
return instance.visible ? intersectionRatio > threshold : intersectionRatio >= threshold; | ||
@@ -155,6 +136,6 @@ }); | ||
exports.default = { | ||
observe: observe, | ||
unobserve: unobserve, | ||
destroy: destroy | ||
export default { | ||
observe, | ||
unobserve, | ||
destroy | ||
}; |
{ | ||
"name": "react-intersection-observer", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "Monitor if a component is inside the viewport, using IntersectionObserver API", | ||
@@ -42,34 +42,19 @@ "main": "lib/index.js", | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"env", | ||
"react", | ||
"stage-2" | ||
], | ||
"env": { | ||
"es": { | ||
"presets": [ | ||
[ | ||
"env", | ||
{ | ||
"modules": false | ||
} | ||
], | ||
"react", | ||
"stage-2" | ||
] | ||
} | ||
} | ||
}, | ||
"eslintConfig": { | ||
"extends": [ | ||
"insilico", | ||
"prettier", | ||
"prettier/react" | ||
"insilico" | ||
] | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"./.babelrc.js" | ||
] | ||
}, | ||
"jest": { | ||
"testEnvironment": "node", | ||
"snapshotSerializers": [ | ||
"<rootDir>/node_modules/enzyme-to-json/serializer" | ||
"enzyme-to-json/serializer" | ||
], | ||
"setupFiles": [ | ||
"<rootDir>/jest-setup.js" | ||
] | ||
@@ -83,8 +68,8 @@ }, | ||
"devDependencies": { | ||
"@storybook/addon-actions": "^3.1.9", | ||
"@storybook/addon-options": "^3.1.6", | ||
"@storybook/react": "^3.1.9", | ||
"@storybook/addon-actions": "^3.2.11", | ||
"@storybook/addon-options": "^3.2.10", | ||
"@storybook/react": "^3.2.11", | ||
"babel-cli": "^6.24.1", | ||
"babel-core": "^6.25.0", | ||
"babel-jest": "^21.0.0", | ||
"babel-jest": "^21.2.0", | ||
"babel-preset-env": "^1.6.0", | ||
@@ -94,17 +79,17 @@ "babel-preset-react": "^6.24.1", | ||
"concurrently": "3.5.0", | ||
"enzyme": "^2.9.1", | ||
"enzyme-to-json": "^1.5.1", | ||
"eslint": "^4.3.0", | ||
"eslint-config-insilico": "^4.1.1", | ||
"eslint-config-prettier": "^2.3.0", | ||
"enzyme": "^3.0.0", | ||
"enzyme-adapter-react-16": "^1.0.0", | ||
"enzyme-to-json": "^3.0.1", | ||
"eslint": "^4.7.2", | ||
"eslint-config-insilico": "^5.0.0", | ||
"husky": "^0.14.3", | ||
"intersection-observer": "^0.4.0", | ||
"jest": "^21.0.0", | ||
"lint-staged": "^4.0.2", | ||
"prettier": "^1.5.3", | ||
"prop-types": "^15.5.10", | ||
"react": "^15.6.1", | ||
"react-dom": "^15.6.1", | ||
"react-test-renderer": "^15.6.1" | ||
"jest": "^21.2.0", | ||
"lint-staged": "^4.2.3", | ||
"prettier": "^1.7.0", | ||
"prop-types": "^15.6.0", | ||
"react": "^16.0.0", | ||
"react-dom": "^16.0.0", | ||
"react-test-renderer": "^16.0.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15
41569
756