react-intersection-observer
Advanced tools
Comparing version 1.2.1 to 1.2.2-0
module.exports = { | ||
presets: [ | ||
[ | ||
'env', | ||
process.env.BABEL_ENV === 'es' | ||
? { | ||
modules: false, | ||
} | ||
: {}, | ||
], | ||
'react', | ||
'stage-2', | ||
], | ||
presets: ['env', 'react', 'stage-2'], | ||
} |
@@ -13,11 +13,7 @@ 'use strict'; | ||
var _react2 = _interopRequireDefault(_react); | ||
var React = _interopRequireWildcard(_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 _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | ||
@@ -30,9 +26,4 @@ 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 _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 | ||
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; } | ||
var isFunction = function isFunction(func) { | ||
return typeof func === 'function'; | ||
}; | ||
/** | ||
@@ -47,6 +38,5 @@ * Monitors scroll, and triggers the children function with updated props | ||
*/ | ||
var Observer = function (_React$Component) { | ||
_inherits(Observer, _React$Component); | ||
var Observer = function (_Component) { | ||
_inherits(Observer, _Component); | ||
function Observer() { | ||
@@ -138,10 +128,10 @@ var _ref; | ||
return (0, _react.createElement)(tag, _extends({}, props, { | ||
return 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); | ||
inView && typeof render === 'function' ? 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. | ||
typeof children === 'function' ? children(inView) : children); | ||
} | ||
@@ -151,25 +141,4 @@ }]); | ||
return Observer; | ||
}(_react.Component); | ||
}(React.Component); | ||
Observer.propTypes = { | ||
/** Element tag to use for the wrapping */ | ||
tag: _propTypes2.default.node, | ||
/** Children should be either a function or a node */ | ||
children: _propTypes2.default.oneOfType([_propTypes2.default.func, _propTypes2.default.node]), | ||
/** Only trigger the inView callback once */ | ||
triggerOnce: _propTypes2.default.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]), | ||
/** 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, | ||
/** 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, | ||
/** 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, | ||
/** Call this function whenever the in view state changes */ | ||
onChange: _propTypes2.default.func, | ||
/** Use render method to only render content when inView */ | ||
render: _propTypes2.default.func | ||
}; | ||
Observer.defaultProps = { | ||
@@ -176,0 +145,0 @@ tag: 'div', |
@@ -26,9 +26,9 @@ "use strict"; | ||
}; | ||
var rootId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; | ||
var threshold = options.threshold, | ||
root = options.root, | ||
var rootId = arguments[3]; | ||
var root = options.root, | ||
rootMargin = options.rootMargin; | ||
var threshold = options.threshold || 0; | ||
if (!element || !callback) return; | ||
var observerId = rootMargin ? threshold + "_" + rootMargin : "" + threshold; | ||
var observerId = rootMargin ? threshold.toString() + "_" + rootMargin : "" + threshold.toString(); | ||
@@ -67,11 +67,12 @@ if (root) { | ||
if (!element) return; | ||
var instance = INSTANCE_MAP.get(element); | ||
if (INSTANCE_MAP.has(element)) { | ||
var _INSTANCE_MAP$get = INSTANCE_MAP.get(element), | ||
observerId = _INSTANCE_MAP$get.observerId, | ||
observer = _INSTANCE_MAP$get.observer; | ||
if (instance) { | ||
var _observerId = instance.observerId, | ||
_observer = instance.observer; | ||
var observerInstance = observerId ? OBSERVER_MAP.get(observerId) : observer; | ||
var observerInstance = _observerId ? OBSERVER_MAP.get(_observerId) : _observer; | ||
if (observerInstance) { | ||
// $FlowFixMe - the interface in bom.js is wrong. Spec should accept the element. | ||
observerInstance.unobserve(element); | ||
@@ -82,5 +83,5 @@ } | ||
var itemsLeft = false; | ||
if (observerId) { | ||
if (_observerId) { | ||
INSTANCE_MAP.forEach(function (item, key) { | ||
if (item && item.observerId === observerId && key !== element) { | ||
if (item && item.observerId === _observerId && key !== element) { | ||
itemsLeft = true; | ||
@@ -94,3 +95,3 @@ } | ||
observerInstance.disconnect(); | ||
OBSERVER_MAP.delete(observerId); | ||
OBSERVER_MAP.delete(_observerId); | ||
} | ||
@@ -117,20 +118,20 @@ | ||
changes.forEach(function (intersection) { | ||
if (INSTANCE_MAP.has(intersection.target)) { | ||
var isIntersecting = intersection.isIntersecting, | ||
intersectionRatio = intersection.intersectionRatio, | ||
target = intersection.target; | ||
var isIntersecting = intersection.isIntersecting, | ||
intersectionRatio = intersection.intersectionRatio, | ||
target = intersection.target; | ||
var instance = INSTANCE_MAP.get(target); | ||
var options = instance.options; | ||
var instance = INSTANCE_MAP.get(target); | ||
if (instance) { | ||
var _options = instance.options; | ||
var inView = void 0; | ||
var _inView = false; | ||
if (Array.isArray(options.threshold)) { | ||
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(function (threshold) { | ||
return instance.visible ? intersectionRatio > threshold : intersectionRatio >= threshold; | ||
}); | ||
} else { | ||
} else if (_options.threshold !== undefined) { | ||
// Trigger on 0 ratio only when not visible. This is fallback for browsers without isIntersecting support | ||
inView = instance.visible ? intersectionRatio > options.threshold : intersectionRatio >= options.threshold; | ||
_inView = instance.visible ? intersectionRatio > _options.threshold : intersectionRatio >= _options.threshold; | ||
} | ||
@@ -141,10 +142,10 @@ | ||
// Otherwise it reports a threshold of 0 | ||
inView = inView && isIntersecting; | ||
_inView = _inView && isIntersecting; | ||
} | ||
// Update the visible value on the instance | ||
instance.visible = inView; | ||
instance.visible = _inView; | ||
if (instance.callback) { | ||
instance.callback(inView); | ||
instance.callback(_inView); | ||
} | ||
@@ -151,0 +152,0 @@ } |
{ | ||
"name": "react-intersection-observer", | ||
"version": "1.2.1", | ||
"version": "1.2.2-0", | ||
"description": "Monitor if a component is inside the viewport, using IntersectionObserver API", | ||
"main": "lib/index.js", | ||
"module": "es/index.js", | ||
"jsnext:main": "es/index.js", | ||
"author": "Daniel Schmidt", | ||
@@ -22,9 +20,9 @@ "repository": { | ||
"scripts": { | ||
"build": "rm -rf lib && npm run build:lib && npm run build:es", | ||
"build:es": "BABEL_ENV=es babel src --out-dir es --ignore __*,*.story.js,*.test.js", | ||
"build": "rm -rf lib es && npm run build:lib && npm run build:flow", | ||
"build:lib": "babel src --out-dir lib --ignore __*,*.story.js,*.test.js", | ||
"build:storybook": "build-storybook --output-dir example", | ||
"build:flow": "flow-copy-source -v src lib", | ||
"dev": "concurrently -k -r 'jest --watch' 'npm run storybook'", | ||
"lint": "eslint {src,stories,tests}/. ", | ||
"precommit": "lint-staged", | ||
"precommit": "flow && lint-staged", | ||
"postcommit": "git reset", | ||
@@ -62,5 +60,3 @@ "prepublish": "npm run build", | ||
}, | ||
"dependencies": { | ||
"prop-types": "^15.6.0" | ||
}, | ||
"dependencies": {}, | ||
"peerDependencies": { | ||
@@ -85,2 +81,4 @@ "react": "^15.0.0 || ^16.0.0 || ^17.0.0" | ||
"eslint-config-insilico": "^5.0.1", | ||
"flow-bin": "^0.57.3", | ||
"flow-copy-source": "^1.2.1", | ||
"husky": "^0.14.3", | ||
@@ -87,0 +85,0 @@ "intersection-observer": "^0.4.0", |
@@ -1,7 +0,31 @@ | ||
import React, { Component, createElement } from 'react' // eslint-disable-line no-unused-vars | ||
import PropTypes from 'prop-types' | ||
// @flow | ||
import * as React from 'react' | ||
import { observe, unobserve } from './intersection' | ||
const isFunction = func => typeof func === 'function' | ||
type Props = { | ||
/** Element tag to use for the wrapping */ | ||
tag: string, | ||
/** Only trigger the inView callback once */ | ||
triggerOnce: boolean, | ||
/** Children should be either a function or a node */ | ||
children?: ((inView: boolean) => React.Node) | React.Node, | ||
/** 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?: number | Array<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?: HTMLElement, | ||
/** Margin around the root. Can have values similar to the CSS margin property, e.g. "10px 20px 30px 40px" (top, right, bottom, left). */ | ||
rootMargin?: 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?: string, | ||
/** Call this function whenever the in view state changes */ | ||
onChange?: (inView: boolean) => void, | ||
/** Use render method to only render content when inView */ | ||
render?: () => React.Node, | ||
} | ||
type State = { | ||
inView: boolean, | ||
} | ||
/** | ||
@@ -16,28 +40,3 @@ * Monitors scroll, and triggers the children function with updated props | ||
*/ | ||
class Observer extends Component { | ||
static propTypes = { | ||
/** Element tag to use for the wrapping */ | ||
tag: PropTypes.node, | ||
/** Children should be either a function or a node */ | ||
children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), | ||
/** Only trigger the inView callback once */ | ||
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: 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: 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: 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: PropTypes.string, | ||
/** Call this function whenever the in view state changes */ | ||
onChange: PropTypes.func, | ||
/** Use render method to only render content when inView */ | ||
render: PropTypes.func, | ||
} | ||
class Observer extends React.Component<Props, State> { | ||
static defaultProps = { | ||
@@ -53,3 +52,3 @@ tag: 'div', | ||
componentWillUpdate(nextProps, nextState) { | ||
componentWillUpdate(nextProps: Props, nextState: State) { | ||
if (!!this.props.onChange && nextState !== this.state) { | ||
@@ -60,3 +59,3 @@ this.props.onChange(nextState.inView) | ||
componentDidUpdate(prevProps, prevState) { | ||
componentDidUpdate(prevProps: Props, prevState: State) { | ||
// If a IntersectionObserver option changed, reinit the observer | ||
@@ -87,3 +86,3 @@ if ( | ||
node = null | ||
node: ?HTMLElement = null | ||
@@ -105,3 +104,3 @@ observeNode() { | ||
handleNode = node => { | ||
handleNode = (node: ?HTMLElement) => { | ||
if (this.node) unobserve(this.node) | ||
@@ -112,3 +111,3 @@ this.node = node | ||
handleChange = inView => this.setState({ inView }) | ||
handleChange = (inView: boolean) => this.setState({ inView }) | ||
@@ -130,3 +129,3 @@ render() { | ||
return createElement( | ||
return React.createElement( | ||
tag, | ||
@@ -138,6 +137,6 @@ { | ||
// 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, | ||
inView && typeof render === 'function' ? 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. | ||
typeof children === 'function' ? children(inView) : children, | ||
) | ||
@@ -144,0 +143,0 @@ } |
@@ -1,4 +0,15 @@ | ||
const INSTANCE_MAP = new Map() | ||
const OBSERVER_MAP = new Map() | ||
// @flow | ||
type Callback = (inView: boolean) => void | ||
type Instance = { | ||
callback: Callback, | ||
visible: boolean, | ||
options: IntersectionObserverOptions, | ||
observerId: ?string, | ||
observer: ?IntersectionObserver, | ||
} | ||
const INSTANCE_MAP: Map<HTMLElement, Instance> = new Map() | ||
const OBSERVER_MAP: Map<?string, IntersectionObserver> = new Map() | ||
/** | ||
@@ -15,12 +26,15 @@ * Monitor element, and trigger callback when element becomes visible | ||
export function observe( | ||
element, | ||
callback, | ||
options = { | ||
element: HTMLElement, | ||
callback: Callback, | ||
options: IntersectionObserverOptions = { | ||
threshold: 0, | ||
}, | ||
rootId = null, | ||
rootId?: string, | ||
) { | ||
const { threshold, root, rootMargin } = options | ||
const { root, rootMargin } = options | ||
const threshold = options.threshold || 0 | ||
if (!element || !callback) return | ||
let observerId = rootMargin ? `${threshold}_${rootMargin}` : `${threshold}` | ||
let observerId = rootMargin | ||
? `${threshold.toString()}_${rootMargin}` | ||
: `${threshold.toString()}` | ||
@@ -37,3 +51,3 @@ if (root) { | ||
const instance = { | ||
const instance: Instance = { | ||
callback, | ||
@@ -58,7 +72,8 @@ visible: false, | ||
*/ | ||
export function unobserve(element) { | ||
export function unobserve(element: ?HTMLElement) { | ||
if (!element) return | ||
const instance = INSTANCE_MAP.get(element) | ||
if (INSTANCE_MAP.has(element)) { | ||
const { observerId, observer } = INSTANCE_MAP.get(element) | ||
if (instance) { | ||
const { observerId, observer } = instance | ||
const observerInstance = observerId | ||
@@ -69,2 +84,3 @@ ? OBSERVER_MAP.get(observerId) | ||
if (observerInstance) { | ||
// $FlowFixMe - the interface in bom.js is wrong. Spec should accept the element. | ||
observerInstance.unobserve(element) | ||
@@ -108,8 +124,8 @@ } | ||
changes.forEach(intersection => { | ||
if (INSTANCE_MAP.has(intersection.target)) { | ||
const { isIntersecting, intersectionRatio, target } = intersection | ||
const instance = INSTANCE_MAP.get(target) | ||
const { isIntersecting, intersectionRatio, target } = intersection | ||
const instance = INSTANCE_MAP.get(target) | ||
if (instance) { | ||
const options = instance.options | ||
let inView | ||
let inView = false | ||
@@ -123,3 +139,3 @@ if (Array.isArray(options.threshold)) { | ||
}) | ||
} else { | ||
} else if (options.threshold !== undefined) { | ||
// Trigger on 0 ratio only when not visible. This is fallback for browsers without isIntersecting support | ||
@@ -126,0 +142,0 @@ inView = instance.visible |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
1
15
40135
25
512
2
- Removedprop-types@^15.6.0
- Removedprop-types@15.8.1(transitive)
- Removedreact-is@16.13.1(transitive)